From f740bac98847e4ea60d1432480aa9cdce57ed142 Mon Sep 17 00:00:00 2001 From: Abdul Rahman <81605929+abdulrahmancodes@users.noreply.github.com> Date: Sat, 8 Nov 2025 15:54:07 +0530 Subject: [PATCH] add documentation i18n workflows for Crowdin (#15538) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Félix Malfait Co-authored-by: Félix Malfait --- .github/workflows/ci-docs.yaml | 47 ++ .github/workflows/docs-i18n-pull.yaml | 106 +++ .github/workflows/docs-i18n-push.yaml | 42 ++ .github/workflows/i18n-pull.yaml | 4 +- crowdin.yml | 27 +- eslint.config.mjs | 21 + package.json | 1 + packages/twenty-docs/docs.json | 639 ++++++++++++------ packages/twenty-docs/eslint.config.mjs | 10 +- .../user-guide/data-model/data-model-faq.mdx | 15 +- .../getting-started/getting-around-twenty.mdx | 4 +- .../getting-started/import-export-data.mdx | 28 +- .../fr/user-guide/settings/settings-faq.mdx | 14 +- .../workflows/workflow-troubleshooting.mdx | 4 +- packages/twenty-docs/snippets/vimeo-embed.mdx | 20 + .../user-guide/collaboration/notes.mdx | 22 +- .../user-guide/collaboration/tasks.mdx | 60 +- .../user-guide/crm-essentials/pipeline.mdx | 41 +- .../crm-essentials/view-management.mdx | 98 +-- .../data-model/creating-records.mdx | 41 +- .../user-guide/data-model/data-model-faq.mdx | 2 +- .../user-guide/data-model/fields.mdx | 22 +- .../user-guide/data-model/objects.mdx | 41 +- .../getting-started/create-workspace.mdx | 22 +- .../getting-started/import-export-data.mdx | 22 +- .../integrations-api/api-webhooks.mdx | 45 +- .../user-guide/views/kanban-views.mdx | 41 +- .../user-guide/views/views-sort-filter.mdx | 98 +-- tools/eslint-rules/index.ts | 5 + .../rules/mdx-component-newlines.ts | 97 +++ yarn.lock | 388 ++++++++++- 31 files changed, 1302 insertions(+), 725 deletions(-) create mode 100644 .github/workflows/ci-docs.yaml create mode 100644 .github/workflows/docs-i18n-pull.yaml create mode 100644 .github/workflows/docs-i18n-push.yaml create mode 100644 packages/twenty-docs/snippets/vimeo-embed.mdx create mode 100644 tools/eslint-rules/rules/mdx-component-newlines.ts diff --git a/.github/workflows/ci-docs.yaml b/.github/workflows/ci-docs.yaml new file mode 100644 index 00000000000..72996b8c280 --- /dev/null +++ b/.github/workflows/ci-docs.yaml @@ -0,0 +1,47 @@ +name: CI Docs + +on: + push: + branches: + - main + + pull_request: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + +jobs: + changed-files-check: + uses: ./.github/workflows/changed-files.yaml + with: + files: | + package.json + packages/twenty-docs/** + eslint.config.mjs + + docs-lint: + needs: changed-files-check + if: needs.changed-files-check.outputs.any_changed == 'true' + timeout-minutes: 10 + runs-on: ubuntu-latest + steps: + - name: Cancel Previous Runs + uses: styfle/cancel-workflow-action@0.11.0 + with: + access_token: ${{ github.token }} + + - name: Fetch local actions + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Install dependencies + uses: ./.github/workflows/actions/yarn-install + + - name: Docs / Lint English MDX files + run: npx eslint "packages/twenty-docs/{developers,user-guide,twenty-ui,getting-started,snippets}/**/*.mdx" --max-warnings 0 + diff --git a/.github/workflows/docs-i18n-pull.yaml b/.github/workflows/docs-i18n-pull.yaml new file mode 100644 index 00000000000..56cd88cfbbd --- /dev/null +++ b/.github/workflows/docs-i18n-pull.yaml @@ -0,0 +1,106 @@ +name: 'Pull docs translations from Crowdin' + +permissions: + contents: write + pull-requests: write + +on: + schedule: + - cron: '0 */2 * * *' # Every two hours + workflow_dispatch: + inputs: + force_pull: + description: 'Force pull translations regardless of status' + required: false + type: boolean + default: false + workflow_call: + inputs: + force_pull: + description: 'Force pull translations regardless of status' + required: false + type: boolean + default: false + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + +jobs: + pull_docs_translations: + name: Pull docs translations + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + token: ${{ github.token }} + ref: main + + - name: Setup i18n branch + run: | + git fetch origin i18n || true + git checkout -B i18n origin/i18n || git checkout -b i18n + + - name: Configure git + run: | + git config --global user.name 'github-actions' + git config --global user.email 'github-actions@twenty.com' + + - name: Stash any changes before pulling translations + run: | + git add . + git stash || true + + - name: Pull translated docs from Crowdin + if: inputs.force_pull == true || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' + uses: crowdin/github-action@v2 + with: + upload_sources: false + upload_translations: false + download_translations: true + download_language: fr + source: 'packages/twenty-docs/**/*.mdx' + translation: 'packages/twenty-docs/%two_letters_code%/**/%original_file_name%' + export_only_approved: false + localization_branch_name: i18n + base_url: 'https://twenty.api.crowdin.com' + skip_untranslated_files: true + push_translations: false + create_pull_request: false + skip_ref_checkout: true + dryrun_action: false + env: + GITHUB_TOKEN: ${{ github.token }} + CROWDIN_PROJECT_ID: '1' + CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} + + - name: Fix file permissions + run: sudo chown -R runner:docker . || true + + - name: Check for changes and commit + id: check_changes + run: | + git add . + if ! git diff --staged --quiet --exit-code; then + git commit -m "chore: update docs translations from Crowdin" + echo "changes_detected=true" >> $GITHUB_OUTPUT + else + echo "changes_detected=false" >> $GITHUB_OUTPUT + fi + + - name: Push changes + if: steps.check_changes.outputs.changes_detected == 'true' + run: git push origin HEAD:i18n + + - name: Create pull request + if: steps.check_changes.outputs.changes_detected == 'true' + run: | + if git diff --name-only origin/main..HEAD | grep -q .; then + gh pr create -B main -H i18n --title 'i18n - docs translations' --body 'Created by Github action' || true + else + echo "No file differences between branches, skipping PR creation" + fi + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + diff --git a/.github/workflows/docs-i18n-push.yaml b/.github/workflows/docs-i18n-push.yaml new file mode 100644 index 00000000000..359fc996bac --- /dev/null +++ b/.github/workflows/docs-i18n-push.yaml @@ -0,0 +1,42 @@ +name: 'Push docs to Crowdin' + +permissions: + contents: write + +on: + workflow_dispatch: + workflow_call: + push: + branches: ['main'] + paths: + - 'packages/twenty-docs/**/*.mdx' + - '!packages/twenty-docs/fr/**' + - 'crowdin.yml' + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + +jobs: + push_docs: + name: Push documentation to Crowdin + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + token: ${{ github.token }} + ref: main + + - name: Upload docs to Crowdin + uses: crowdin/github-action@v2 + with: + upload_sources: true + upload_translations: false + download_translations: false + localization_branch_name: i18n + base_url: 'https://twenty.api.crowdin.com' + env: + CROWDIN_PROJECT_ID: 1 + CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} + diff --git a/.github/workflows/i18n-pull.yaml b/.github/workflows/i18n-pull.yaml index d565ccb5b18..6e4f36c5afb 100644 --- a/.github/workflows/i18n-pull.yaml +++ b/.github/workflows/i18n-pull.yaml @@ -91,7 +91,7 @@ jobs: GITHUB_TOKEN: ${{ github.token }} CROWDIN_PROJECT_ID: '1' CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} - + # As the files are extracted from a Docker container, they belong to root:root # We need to fix this before the next steps - name: Fix file permissions @@ -103,7 +103,7 @@ jobs: # if: inputs.force_pull || steps.compile_translations_strict.outcome == 'failure' run: | npx nx run twenty-server:lingui:compile - npx nx run twenty-emails:lingui:compile + npx nx run twenty-emails:lingui:compile npx nx run twenty-front:lingui:compile git status git config --global user.name 'github-actions' diff --git a/crowdin.yml b/crowdin.yml index 47e97dc8faf..1d75a670766 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -27,5 +27,30 @@ files: [ # e.g. "/resources/%two_letters_code%/%original_file_name%" # "translation": "%original_path%/%locale%.po", + }, + { + # + # MDX documentation files - user-guide + # Using md type to preserve JSX component structure + # This prevents Crowdin from reformatting , , etc. + # + "source": "packages/twenty-docs/user-guide/**/*.mdx", + "translation": "packages/twenty-docs/%two_letters_code%/user-guide/**/%original_file_name%", + }, + { + # + # MDX documentation files - developers + # Using md type to preserve JSX component structure + # + "source": "packages/twenty-docs/developers/**/*.mdx", + "translation": "packages/twenty-docs/%two_letters_code%/developers/**/%original_file_name%", + }, + { + # + # MDX documentation files - twenty-ui + # Using md type to preserve JSX component structure + # + "source": "packages/twenty-docs/twenty-ui/**/*.mdx", + "translation": "packages/twenty-docs/%two_letters_code%/twenty-ui/**/%original_file_name%", } -] \ No newline at end of file +] diff --git a/eslint.config.mjs b/eslint.config.mjs index ef7a65920cb..9a94eeee305 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -4,6 +4,7 @@ import typescriptEslint from '@typescript-eslint/eslint-plugin'; import typescriptParser from '@typescript-eslint/parser'; import importPlugin from 'eslint-plugin-import'; import linguiPlugin from 'eslint-plugin-lingui'; +import * as mdxPlugin from 'eslint-plugin-mdx'; import preferArrowPlugin from 'eslint-plugin-prefer-arrow'; import prettierPlugin from 'eslint-plugin-prettier'; import unicornPlugin from 'eslint-plugin-unicorn'; @@ -191,4 +192,24 @@ export default [ parser: jsoncParser, }, }, + + // MDX files + { + ...mdxPlugin.flat, + plugins: { + ...mdxPlugin.flat.plugins, + '@nx': nxPlugin, + }, + }, + mdxPlugin.flatCodeBlocks, + { + files: ['**/*.mdx'], + rules: { + 'no-unused-vars': 'off', + 'unused-imports/no-unused-imports': 'off', + 'unused-imports/no-unused-vars': 'off', + // Enforce JSX tags on separate lines to prevent Crowdin translation issues + '@nx/workspace-mdx-component-newlines': 'error', + }, + }, ]; diff --git a/package.json b/package.json index 39819f30d00..59424214950 100644 --- a/package.json +++ b/package.json @@ -158,6 +158,7 @@ "eslint-plugin-import": "^2.31.0", "eslint-plugin-jsx-a11y": "^6.10.2", "eslint-plugin-lingui": "^0.9.0", + "eslint-plugin-mdx": "^3.6.2", "eslint-plugin-prefer-arrow": "^1.2.3", "eslint-plugin-prettier": "^5.1.2", "eslint-plugin-project-structure": "^3.9.1", diff --git a/packages/twenty-docs/docs.json b/packages/twenty-docs/docs.json index f8f64d97efa..a533c012cd6 100644 --- a/packages/twenty-docs/docs.json +++ b/packages/twenty-docs/docs.json @@ -26,225 +26,472 @@ "eyebrows": "breadcrumbs" }, "navigation": { - "tabs": [ + "languages": [ { - "tab": "User Guide", - "groups": [ + "language": "en", + "tabs": [ { - "group": "Getting Started", - "icon": "rocket", - "pages": [ - "user-guide/introduction", - "user-guide/getting-started/what-is-twenty", - "user-guide/getting-started/create-workspace", - "user-guide/getting-started/getting-around-twenty", - "user-guide/getting-started/configure-your-workspace", - "user-guide/getting-started/implementation-services", - "user-guide/getting-started/migrating-from-other-crms", - "user-guide/getting-started/import-export-data" - ] - }, - { - "group": "Data Model", - "icon": "database", - "pages": [ - "user-guide/data-model/customize-your-data-model", - "user-guide/data-model/objects", - "user-guide/data-model/fields", - "user-guide/data-model/creating-records", - "user-guide/data-model/relation-fields", - "user-guide/data-model/data-model-faq" - ] - }, - { - "group": "CRM Essentials", - "icon": "users", - "pages": [ - "user-guide/crm-essentials/contact-and-account-management", - "user-guide/crm-essentials/pipeline", - "user-guide/crm-essentials/view-management", - "user-guide/crm-essentials/sales-use-cases" - ] - }, - { - "group": "Views", - "icon": "table", - "pages": [ - "user-guide/views/kanban-views", - "user-guide/views/views-sort-filter" - ] - }, - { - "group": "Workflows", - "icon": "bolt", - "pages": [ - "user-guide/workflows/getting-started-workflows", - "user-guide/workflows/workflow-features", - "user-guide/workflows/internal-automations", - "user-guide/workflows/external-tool-integration", - "user-guide/workflows/workflow-troubleshooting", - "user-guide/workflows/workflow-credits", - "user-guide/workflows/professional-services" - ] - }, - { - "group": "Collaboration", - "icon": "envelope", - "pages": [ - "user-guide/collaboration/emails-and-calendars", - "user-guide/collaboration/notes", - "user-guide/collaboration/tasks" - ] - }, - { - "group": "Integrations & API", - "icon": "plug", - "pages": [ - "user-guide/integrations-api/apis-overview", - "user-guide/integrations-api/api-webhooks", - "user-guide/integrations-api/integrations" - ] - }, - { - "group": "Reporting", - "icon": "chart-bar", - "pages": ["user-guide/reporting/reporting-overview"] - }, - { - "group": "Settings", - "icon": "gear", - "pages": [ - "user-guide/settings/profile-settings", - "user-guide/settings/experience-settings", - "user-guide/settings/email-calendar-setup", - "user-guide/settings/workspace-settings", - "user-guide/settings/member-management", - "user-guide/settings/permissions", - "user-guide/settings/domains-settings", - "user-guide/settings/releases-settings", - "user-guide/settings/settings-faq" - ] - }, - { - "group": "Pricing", - "icon": "credit-card", - "pages": ["user-guide/pricing/billing-and-pricing-faq"] - }, - { - "group": "Resources", - "icon": "book-open", - "pages": [ - "user-guide/resources/glossary", - "user-guide/resources/github" - ] - } - ] - }, - { - "tab": "Developers", - "groups": [ - { - "group": "Developers" - }, - { - "group": "Getting Started", - "icon": "rocket", - "pages": [ - "developers/introduction", - "developers/local-setup", + "tab": "User Guide", + "groups": [ { - "group": "Self-Hosting", + "group": "Getting Started", + "icon": "rocket", "pages": [ - "developers/self-hosting/docker-compose", - "developers/self-hosting/setup", - "developers/self-hosting/upgrade-guide", - "developers/self-hosting/cloud-providers", - "developers/self-hosting/troubleshooting" + "user-guide/introduction", + "user-guide/getting-started/what-is-twenty", + "user-guide/getting-started/create-workspace", + "user-guide/getting-started/getting-around-twenty", + "user-guide/getting-started/configure-your-workspace", + "user-guide/getting-started/implementation-services", + "user-guide/getting-started/migrating-from-other-crms", + "user-guide/getting-started/import-export-data" ] }, { - "group": "API and Webhooks", + "group": "Data Model", + "icon": "database", "pages": [ - "developers/api-and-webhooks/api", - "developers/api-and-webhooks/webhooks" + "user-guide/data-model/customize-your-data-model", + "user-guide/data-model/objects", + "user-guide/data-model/fields", + "user-guide/data-model/creating-records", + "user-guide/data-model/relation-fields", + "user-guide/data-model/data-model-faq" + ] + }, + { + "group": "CRM Essentials", + "icon": "users", + "pages": [ + "user-guide/crm-essentials/contact-and-account-management", + "user-guide/crm-essentials/pipeline", + "user-guide/crm-essentials/view-management", + "user-guide/crm-essentials/sales-use-cases" + ] + }, + { + "group": "Views", + "icon": "table", + "pages": [ + "user-guide/views/kanban-views", + "user-guide/views/views-sort-filter" + ] + }, + { + "group": "Workflows", + "icon": "bolt", + "pages": [ + "user-guide/workflows/getting-started-workflows", + "user-guide/workflows/workflow-features", + "user-guide/workflows/internal-automations", + "user-guide/workflows/external-tool-integration", + "user-guide/workflows/workflow-troubleshooting", + "user-guide/workflows/workflow-credits", + "user-guide/workflows/professional-services" + ] + }, + { + "group": "Collaboration", + "icon": "envelope", + "pages": [ + "user-guide/collaboration/emails-and-calendars", + "user-guide/collaboration/notes", + "user-guide/collaboration/tasks" + ] + }, + { + "group": "Integrations & API", + "icon": "plug", + "pages": [ + "user-guide/integrations-api/apis-overview", + "user-guide/integrations-api/api-webhooks", + "user-guide/integrations-api/integrations" + ] + }, + { + "group": "Reporting", + "icon": "chart-bar", + "pages": [ + "user-guide/reporting/reporting-overview" + ] + }, + { + "group": "Settings", + "icon": "gear", + "pages": [ + "user-guide/settings/profile-settings", + "user-guide/settings/experience-settings", + "user-guide/settings/email-calendar-setup", + "user-guide/settings/workspace-settings", + "user-guide/settings/member-management", + "user-guide/settings/permissions", + "user-guide/settings/domains-settings", + "user-guide/settings/releases-settings", + "user-guide/settings/settings-faq" + ] + }, + { + "group": "Pricing", + "icon": "credit-card", + "pages": [ + "user-guide/pricing/billing-and-pricing-faq" + ] + }, + { + "group": "Resources", + "icon": "book-open", + "pages": [ + "user-guide/resources/glossary", + "user-guide/resources/github" ] } ] }, { - "group": "Contributing", - "icon": "code-branch", - "pages": [ - "developers/bug-and-requests", + "tab": "Developers", + "groups": [ { - "group": "Frontend Development", + "group": "Developers" + }, + { + "group": "Getting Started", + "icon": "rocket", "pages": [ - "developers/frontend-development/storybook", + "developers/introduction", + "developers/local-setup", { - "group": "Twenty UI", + "group": "Self-Hosting", "pages": [ - "twenty-ui/introduction", - { - "group": "Display", - "pages": [ - "twenty-ui/display/checkmark", - "twenty-ui/display/chip", - "twenty-ui/display/icons", - "twenty-ui/display/soon-pill", - "twenty-ui/display/tag", - "twenty-ui/display/app-tooltip" - ] - }, - { - "group": "Feedback", - "pages": ["twenty-ui/progress-bar"] - }, - { - "group": "Input", - "pages": [ - "twenty-ui/input/buttons", - "twenty-ui/input/color-scheme", - "twenty-ui/input/text", - "twenty-ui/input/checkbox", - "twenty-ui/input/icon-picker", - "twenty-ui/input/image-input", - "twenty-ui/input/radio", - "twenty-ui/input/select", - "twenty-ui/input/toggle", - "twenty-ui/input/block-editor" - ] - }, - { - "group": "Navigation", - "pages": [ - "twenty-ui/navigation", - "twenty-ui/navigation/breadcrumb", - "twenty-ui/navigation/links", - "twenty-ui/navigation/menu-item", - "twenty-ui/navigation/navigation-bar", - "twenty-ui/navigation/step-bar" - ] - } + "developers/self-hosting/docker-compose", + "developers/self-hosting/setup", + "developers/self-hosting/upgrade-guide", + "developers/self-hosting/cloud-providers", + "developers/self-hosting/troubleshooting" ] }, - "developers/frontend-development/frontend-commands", - "developers/frontend-development/work-with-figma", - "developers/frontend-development/best-practices-front", - "developers/frontend-development/style-guide", - "developers/frontend-development/folder-architecture-front", - "developers/frontend-development/hotkeys" + { + "group": "API and Webhooks", + "pages": [ + "developers/api-and-webhooks/api", + "developers/api-and-webhooks/webhooks" + ] + } ] }, { - "group": "Backend Development", + "group": "Contributing", + "icon": "code-branch", "pages": [ - "developers/backend-development/server-commands", - "developers/backend-development/feature-flags", - "developers/backend-development/folder-architecture-server", - "developers/backend-development/zapier", - "developers/backend-development/best-practices-server", - "developers/backend-development/custom-objects", - "developers/backend-development/queue" + "developers/bug-and-requests", + { + "group": "Frontend Development", + "pages": [ + "developers/frontend-development/storybook", + { + "group": "Twenty UI", + "pages": [ + "twenty-ui/introduction", + { + "group": "Display", + "pages": [ + "twenty-ui/display/checkmark", + "twenty-ui/display/chip", + "twenty-ui/display/icons", + "twenty-ui/display/soon-pill", + "twenty-ui/display/tag", + "twenty-ui/display/app-tooltip" + ] + }, + { + "group": "Feedback", + "pages": [ + "twenty-ui/progress-bar" + ] + }, + { + "group": "Input", + "pages": [ + "twenty-ui/input/buttons", + "twenty-ui/input/color-scheme", + "twenty-ui/input/text", + "twenty-ui/input/checkbox", + "twenty-ui/input/icon-picker", + "twenty-ui/input/image-input", + "twenty-ui/input/radio", + "twenty-ui/input/select", + "twenty-ui/input/toggle", + "twenty-ui/input/block-editor" + ] + }, + { + "group": "Navigation", + "pages": [ + "twenty-ui/navigation", + "twenty-ui/navigation/breadcrumb", + "twenty-ui/navigation/links", + "twenty-ui/navigation/menu-item", + "twenty-ui/navigation/navigation-bar", + "twenty-ui/navigation/step-bar" + ] + } + ] + }, + "developers/frontend-development/frontend-commands", + "developers/frontend-development/work-with-figma", + "developers/frontend-development/best-practices-front", + "developers/frontend-development/style-guide", + "developers/frontend-development/folder-architecture-front", + "developers/frontend-development/hotkeys" + ] + }, + { + "group": "Backend Development", + "pages": [ + "developers/backend-development/server-commands", + "developers/backend-development/feature-flags", + "developers/backend-development/folder-architecture-server", + "developers/backend-development/zapier", + "developers/backend-development/best-practices-server", + "developers/backend-development/custom-objects", + "developers/backend-development/queue" + ] + } + ] + } + ] + } + ] + }, + { + "language": "fr", + "tabs": [ + { + "tab": "User Guide", + "groups": [ + { + "group": "Getting Started", + "icon": "rocket", + "pages": [ + "fr/user-guide/introduction", + "fr/user-guide/getting-started/what-is-twenty", + "fr/user-guide/getting-started/create-workspace", + "fr/user-guide/getting-started/getting-around-twenty", + "fr/user-guide/getting-started/configure-your-workspace", + "fr/user-guide/getting-started/implementation-services", + "fr/user-guide/getting-started/migrating-from-other-crms", + "fr/user-guide/getting-started/import-export-data" + ] + }, + { + "group": "Data Model", + "icon": "database", + "pages": [ + "fr/user-guide/data-model/customize-your-data-model", + "fr/user-guide/data-model/objects", + "fr/user-guide/data-model/fields", + "fr/user-guide/data-model/creating-records", + "fr/user-guide/data-model/relation-fields", + "fr/user-guide/data-model/data-model-faq" + ] + }, + { + "group": "CRM Essentials", + "icon": "users", + "pages": [ + "fr/user-guide/crm-essentials/contact-and-account-management", + "fr/user-guide/crm-essentials/pipeline", + "fr/user-guide/crm-essentials/view-management", + "fr/user-guide/crm-essentials/sales-use-cases" + ] + }, + { + "group": "Views", + "icon": "table", + "pages": [ + "fr/user-guide/views/kanban-views", + "fr/user-guide/views/views-sort-filter" + ] + }, + { + "group": "Workflows", + "icon": "bolt", + "pages": [ + "fr/user-guide/workflows/getting-started-workflows", + "fr/user-guide/workflows/workflow-features", + "fr/user-guide/workflows/internal-automations", + "fr/user-guide/workflows/external-tool-integration", + "fr/user-guide/workflows/workflow-troubleshooting", + "fr/user-guide/workflows/workflow-credits", + "fr/user-guide/workflows/professional-services" + ] + }, + { + "group": "Collaboration", + "icon": "envelope", + "pages": [ + "fr/user-guide/collaboration/emails-and-calendars", + "fr/user-guide/collaboration/notes", + "fr/user-guide/collaboration/tasks" + ] + }, + { + "group": "Integrations & API", + "icon": "plug", + "pages": [ + "fr/user-guide/integrations-api/apis-overview", + "fr/user-guide/integrations-api/api-webhooks", + "fr/user-guide/integrations-api/integrations" + ] + }, + { + "group": "Reporting", + "icon": "chart-bar", + "pages": [ + "fr/user-guide/reporting/reporting-overview" + ] + }, + { + "group": "Settings", + "icon": "gear", + "pages": [ + "fr/user-guide/settings/profile-settings", + "fr/user-guide/settings/experience-settings", + "fr/user-guide/settings/email-calendar-setup", + "fr/user-guide/settings/workspace-settings", + "fr/user-guide/settings/member-management", + "fr/user-guide/settings/permissions", + "fr/user-guide/settings/domains-settings", + "fr/user-guide/settings/releases-settings", + "fr/user-guide/settings/settings-faq" + ] + }, + { + "group": "Pricing", + "icon": "credit-card", + "pages": [ + "fr/user-guide/pricing/billing-and-pricing-faq" + ] + }, + { + "group": "Resources", + "icon": "book-open", + "pages": [ + "fr/user-guide/resources/glossary", + "fr/user-guide/resources/github" + ] + } + ] + }, + { + "tab": "Developers", + "groups": [ + { + "group": "Developers", + "pages": [] + }, + { + "group": "Getting Started", + "icon": "rocket", + "pages": [ + "fr/developers/introduction", + "fr/developers/local-setup", + { + "group": "Self-Hosting", + "pages": [ + "fr/developers/self-hosting/docker-compose", + "fr/developers/self-hosting/setup", + "fr/developers/self-hosting/upgrade-guide", + "fr/developers/self-hosting/cloud-providers", + "fr/developers/self-hosting/troubleshooting" + ] + }, + { + "group": "API and Webhooks", + "pages": [ + "fr/developers/api-and-webhooks/api", + "fr/developers/api-and-webhooks/webhooks" + ] + } + ] + }, + { + "group": "Contributing", + "icon": "code-branch", + "pages": [ + "fr/developers/bug-and-requests", + { + "group": "Frontend Development", + "pages": [ + "fr/developers/frontend-development/storybook", + { + "group": "Twenty UI", + "pages": [ + "fr/twenty-ui/introduction", + { + "group": "Display", + "pages": [ + "fr/twenty-ui/display/checkmark", + "fr/twenty-ui/display/chip", + "fr/twenty-ui/display/icons", + "fr/twenty-ui/display/soon-pill", + "fr/twenty-ui/display/tag", + "fr/twenty-ui/display/app-tooltip" + ] + }, + { + "group": "Feedback", + "pages": [ + "fr/twenty-ui/progress-bar" + ] + }, + { + "group": "Input", + "pages": [ + "fr/twenty-ui/input/buttons", + "fr/twenty-ui/input/color-scheme", + "fr/twenty-ui/input/text", + "fr/twenty-ui/input/checkbox", + "fr/twenty-ui/input/icon-picker", + "fr/twenty-ui/input/image-input", + "fr/twenty-ui/input/radio", + "fr/twenty-ui/input/select", + "fr/twenty-ui/input/toggle", + "fr/twenty-ui/input/block-editor" + ] + }, + { + "group": "Navigation", + "pages": [ + "fr/twenty-ui/navigation", + "fr/twenty-ui/navigation/breadcrumb", + "fr/twenty-ui/navigation/links", + "fr/twenty-ui/navigation/menu-item", + "fr/twenty-ui/navigation/navigation-bar", + "fr/twenty-ui/navigation/step-bar" + ] + } + ] + }, + "fr/developers/frontend-development/frontend-commands", + "fr/developers/frontend-development/work-with-figma", + "fr/developers/frontend-development/best-practices-front", + "fr/developers/frontend-development/style-guide", + "fr/developers/frontend-development/folder-architecture-front", + "fr/developers/frontend-development/hotkeys" + ] + }, + { + "group": "Backend Development", + "pages": [ + "fr/developers/backend-development/server-commands", + "fr/developers/backend-development/feature-flags", + "fr/developers/backend-development/folder-architecture-server", + "fr/developers/backend-development/zapier", + "fr/developers/backend-development/best-practices-server", + "fr/developers/backend-development/custom-objects", + "fr/developers/backend-development/queue" + ] + } ] } ] diff --git a/packages/twenty-docs/eslint.config.mjs b/packages/twenty-docs/eslint.config.mjs index d771eb98535..d5b5dbda515 100644 --- a/packages/twenty-docs/eslint.config.mjs +++ b/packages/twenty-docs/eslint.config.mjs @@ -1,12 +1,4 @@ import baseConfig from '../../eslint.config.mjs'; -export default [ - ...baseConfig, - { - files: ['**/*.mdx'], - rules: { - // MDX-specific rules if needed - }, - }, -]; +export default [...baseConfig]; diff --git a/packages/twenty-docs/fr/user-guide/data-model/data-model-faq.mdx b/packages/twenty-docs/fr/user-guide/data-model/data-model-faq.mdx index 538e628f094..57ea33d297a 100644 --- a/packages/twenty-docs/fr/user-guide/data-model/data-model-faq.mdx +++ b/packages/twenty-docs/fr/user-guide/data-model/data-model-faq.mdx @@ -20,7 +20,9 @@ Pas encore. L'ordre des objets dans la navigation est actuellement fixe, mais ce Tous les objets actifs apparaissent dans la navigation. Vous pouvez désactiver les objets dont vous n'avez pas besoin sous **Paramètres → Modèle de données**. -Vous pouvez désactiver les objets standard, mais vous ne pouvez pas les supprimer définitivement. + +Vous pouvez désactiver les objets standard, mais vous ne pouvez pas les supprimer définitivement. + ## Capacités des champs @@ -43,7 +45,8 @@ Notre API GraphQL utilise les deux formes pour différentes opérations : - `createPerson` (singulier) pour les actions sur un seul enregistrement - `createPeople` (pluriel) pour les opérations en masse -Cela crée des limitations lorsque les formes singulier et pluriel sont identiques, mais cela améliore l'expérience développeur. +Cela crée des limitations lorsque les formes singulier et pluriel sont identiques, mais cela améliore l'expérience développeur. + Certains noms de champs comme `Type` ou `Application` sont réservés à l'usage du système. Choisissez des noms alternatifs comme `Catégorie` ou `Classification`. @@ -69,13 +72,17 @@ Le réagencement des champs sera disponible avec les mises en page personnalisé ## Accès et Permissions -Vous pouvez accéder à votre modèle de données sous **Paramètres → Modèle de données**. + +Vous pouvez accéder à votre modèle de données sous **Paramètres → Modèle de données**. + Contactez votre administrateur d'espace de travail. L'accès au modèle de données est généralement limité aux administrateurs uniquement. -Vous pouvez créer autant d'objets et de champs personnalisés que vous le souhaitez - le prix ne changera pas. + +Vous pouvez créer autant d'objets et de champs personnalisés que vous le souhaitez - le prix ne changera pas. + ## Besoin de plus d'aide ? diff --git a/packages/twenty-docs/fr/user-guide/getting-started/getting-around-twenty.mdx b/packages/twenty-docs/fr/user-guide/getting-started/getting-around-twenty.mdx index 0565007abbe..7228b851f05 100644 --- a/packages/twenty-docs/fr/user-guide/getting-started/getting-around-twenty.mdx +++ b/packages/twenty-docs/fr/user-guide/getting-started/getting-around-twenty.mdx @@ -25,7 +25,9 @@ Vous pouvez **voir, modifier, supprimer des enregistrements** à partir de là a - Utilisez la **barre de recherche** (appuyez sur `/` pour y accéder instantanément) - Ouvrir la section **Paramètres** -Veuillez noter que notre documentation API est accessible sous la section Paramètres et non dans le guide de l'utilisateur. + +Veuillez noter que notre documentation API est accessible sous la section Paramètres et non dans le guide de l'utilisateur. + - Ayez un accès direct à vos **vues favorites**. Les favoris sont uniques pour chaque utilisateur. - Alternez entre différents objets - **Créez des automatisations** en utilisant des workflows diff --git a/packages/twenty-docs/fr/user-guide/getting-started/import-export-data.mdx b/packages/twenty-docs/fr/user-guide/getting-started/import-export-data.mdx index c8b9809f8a0..217e91000a8 100644 --- a/packages/twenty-docs/fr/user-guide/getting-started/import-export-data.mdx +++ b/packages/twenty-docs/fr/user-guide/getting-started/import-export-data.mdx @@ -35,10 +35,10 @@ Voici quelques éléments à vérifier avant de charger votre fichier. - Exemple : Vous souhaitez attacher une personne à une entreprise. Ajoutez une colonne dans le fichier contenant tous les enregistrements `Personnes` qui contient l'`id` de l'entreprise — ou son `domaine`. Vous pourrez mapper ce champ lors du téléversement. **Note importante :** -- Les relations entre les objets dans Twenty sont "Un à Plusieurs". Cela signifie que chaque enregistrement de l'objet A peut être attaché à plusieurs enregistrements de l'objet B. Mais chaque enregistrement de l'objet B peut appartenir à un seul enregistrement de l'objet A. +- Les relations entre les objets dans Twenty sont "Un à Plusieurs". Cela signifie que chaque enregistrement de l'objet A peut être attaché à plusieurs enregistrements de l'objet B. Mais chaque enregistrement de l'objet B peut appartenir à un seul enregistrement de l'objet A. _Par exemple, une entreprise peut être attachée à plusieurs personnes. Et une personne ne peut appartenir qu'à une seule entreprise._ -- Pour téléverser des relations via la fonction d'importation, vous devez fournir l'`id` (ou tout autre champ unique) de l'objet attaché dans le fichier contenant les enregistrements du "côté Multiples" de la relation. +- Pour téléverser des relations via la fonction d'importation, vous devez fournir l'`id` (ou tout autre champ unique) de l'objet attaché dans le fichier contenant les enregistrements du "côté Multiples" de la relation. _Par exemple, vous fournissez l'`id` ou le `domaine` de l'entreprise lors du téléversement d'enregistrements de personnes. Vous ne fournissez pas l'`id` (ou `email`) des personnes lors du téléversement du fichier des entreprises._ @@ -60,27 +60,31 @@ _Par exemple, vous fournissez l'`id` ou le `domaine` de l'entreprise lors du té ### FAQ Importation -
Je vois des problèmes de doublons lors du téléversement de mon fichier, que dois-je faire? +
+Je vois des problèmes de doublons lors du téléversement de mon fichier, que dois-je faire? Veuillez vous référer à la section **Préparer votre csv** ci-dessus dans cet article, elle contient des instructions sur ce qui sera considéré comme un doublon.
-
Puis-je importer des relations entre objets? +
+Puis-je importer des relations entre objets? Oui, veuillez vous référer à la section **Préparer votre csv** ci-dessus dans cet article, elle contient une section sur l'importation des relations.
-
Puis-je mettre à jour des enregistrements existants en utilisant la fonction d'importation? +
+Puis-je mettre à jour des enregistrements existants en utilisant la fonction d'importation? Oui, vous pouvez mettre à jour des enregistrements existants en utilisant la fonction d'importation. Assurez-vous de fournir l'id (ou tout autre champ unique) lors du re-téléversement de vos enregistrements.
-
Puis-je migrer l'`id` de mon (mes) autre(s) outil(s)? +
+Puis-je migrer l'`id` de mon (mes) autre(s) outil(s)? -Oui. Vous devez créer un champ que vous définissez comme unique dans votre modèle de données qui contiendra l'`id` de votre (vos) autre(s) outil(s). Veuillez noter que le nom `id` est protégé car il est utilisé pour l'ID Twenty. +Oui. Vous devez créer un champ que vous définissez comme unique dans votre modèle de données qui contiendra l'`id` de votre (vos) autre(s) outil(s). Veuillez noter que le nom `id` est protégé car il est utilisé pour l'ID Twenty. Si vous souhaitez créer des relations entre objets à l'aide de ce champ, consultez la section **Préparer votre csv** ci-dessus dans cet article. Elle contient une section sur l'importation des relations.
@@ -97,17 +101,17 @@ Pour exporter des données à partir d'un objet : 5. Sélectionnez l'emplacement d'enregistrement pour les données CSV. Notez que l'exportation peut prendre du temps avec un grand nombre d'enregistrements.
- -
- + ## Viewing Notes diff --git a/packages/twenty-docs/user-guide/collaboration/tasks.mdx b/packages/twenty-docs/user-guide/collaboration/tasks.mdx index f4b3b57fd71..0a40094c81a 100644 --- a/packages/twenty-docs/user-guide/collaboration/tasks.mdx +++ b/packages/twenty-docs/user-guide/collaboration/tasks.mdx @@ -4,6 +4,9 @@ info: Understand how to effectively manage tasks in Twenty. image: /images/user-guide/tasks/tasks_header.png sectionInfo: Discover how to leverage Notes and Tasks to better collaborate with your team. --- + +import { VimeoEmbed } from '/snippets/vimeo-embed.mdx'; + Header @@ -60,24 +63,7 @@ Creating tasks in Twenty is seamless. You can either: - Use the search function by pressing `cmd/ctrl + k`, then select 'Create task' from the list of quick actions. - Go to a `Record page` and press `+` at the top right of the page, or go to the Task tab and press the `Add Task` button. -
- -
- + ### Adding Task Content @@ -92,24 +78,7 @@ The **Tasks** page displays all your tasks across your workspace. Here you can: You can also see tasks for a given Record on its `Record page`. -
- -
- + ## Editing Tasks @@ -129,24 +98,7 @@ To mark a task as complete: This procedure will help keep an updated record of your accomplishments. -
- -
- + ## Delete a task diff --git a/packages/twenty-docs/user-guide/crm-essentials/pipeline.mdx b/packages/twenty-docs/user-guide/crm-essentials/pipeline.mdx index f7faba78c1c..cbbeb835c6b 100644 --- a/packages/twenty-docs/user-guide/crm-essentials/pipeline.mdx +++ b/packages/twenty-docs/user-guide/crm-essentials/pipeline.mdx @@ -4,6 +4,9 @@ info: "Track and manage your sales opportunities through customizable pipeline s image: /images/user-guide/kanban-views/kanban.png sectionInfo: "Essential CRM features for managing leads, sales, and customers" --- + +import { VimeoEmbed } from '/snippets/vimeo-embed.mdx'; + Header @@ -22,24 +25,7 @@ Kanban views visually map out your pipeline, where each column represents a stag You can move each opportunity between stages as it progresses through your sales process by dragging and dropping. Hold your click on a card and move it to the next stage. -
- -
- + ### Customizing your pipeline stages @@ -49,24 +35,7 @@ You can tailor your pipeline to suit your specific sales process. Stages represe To add a stage, access the Select Field Settings by navigating to Settings → Data Model, selecting your object, and then the field your Kanban board depends on. -
- -
- + #### Removing stages diff --git a/packages/twenty-docs/user-guide/crm-essentials/view-management.mdx b/packages/twenty-docs/user-guide/crm-essentials/view-management.mdx index 7b89cf0ee2d..5b0f35d7ba1 100644 --- a/packages/twenty-docs/user-guide/crm-essentials/view-management.mdx +++ b/packages/twenty-docs/user-guide/crm-essentials/view-management.mdx @@ -4,6 +4,9 @@ info: "Create and customize views to organize your data with filters, sorting, a image: /images/user-guide/table-views/table.png sectionInfo: "Essential CRM features for managing leads, sales, and customers" --- + +import { VimeoEmbed } from '/snippets/vimeo-embed.mdx'; + Header @@ -25,24 +28,7 @@ Organizes your records by grouping them based on a select field. For example, yo ### Kanban Layout A visual board where each column represents a stage and each record appears as a card. This layout is ideal for managing pipelines and workflows where records move through different stages. For more details on using Kanban views for pipeline management, see our [Pipeline](/user-guide/crm-essentials/pipeline) article. -
- -
- + ## Creating New Views @@ -61,47 +47,13 @@ Important: You need to first select the List layout and then add a Group By. You - For Kanban views, select which select field to use as column headers -
- -
- + ### Creating Views from Existing Filters When you modify the sorting and filtering of an existing view, a `Save as new view` button appears. This lets you create a new view based on your current customizations. -
- -
- + ## Making Views Actionable @@ -126,48 +78,14 @@ All layouts support the same customization options: sorting, filtering, and fiel You can apply filters to show only the records that match your criteria. Click `Filter` in the toolbar, select a field, choose your condition, and set the value. You can add multiple filters for advanced filtering based on several conditions. -
- -
- + ### Sorting Your Records Control the order of your records by clicking on any column header to sort by that field. Click again to reverse the sort order. You can apply multiple sorts for complex organization. -
- -
- + ### Managing Fields and Columns diff --git a/packages/twenty-docs/user-guide/data-model/creating-records.mdx b/packages/twenty-docs/user-guide/data-model/creating-records.mdx index cfc8a5b2634..6438242d453 100644 --- a/packages/twenty-docs/user-guide/data-model/creating-records.mdx +++ b/packages/twenty-docs/user-guide/data-model/creating-records.mdx @@ -4,6 +4,9 @@ info: "Learn how to customize and navigate Table Views." image: /images/user-guide/table-views/table.png sectionInfo: Discover how to use standard and custom objects in your workspace. --- + +import { VimeoEmbed } from '/snippets/vimeo-embed.mdx'; + Header @@ -18,24 +21,7 @@ Add records as needed, without limits. To add a record, you can either click on Enter the record name then press `Enter` to save. To edit a record name, click on its name on its detail page. -
- -
- + ## Delete record @@ -45,24 +31,7 @@ Enter the record name then press `Enter` to save. To edit a record name, click o **Record Page:** Tap the `⋮` icon in the top right corner, then select delete. -
- -
- + ## Add a Custom Field diff --git a/packages/twenty-docs/user-guide/data-model/data-model-faq.mdx b/packages/twenty-docs/user-guide/data-model/data-model-faq.mdx index c4e204b72d2..5d65143c1f7 100644 --- a/packages/twenty-docs/user-guide/data-model/data-model-faq.mdx +++ b/packages/twenty-docs/user-guide/data-model/data-model-faq.mdx @@ -1,6 +1,6 @@ --- title: Data Model FAQ -info: Frequently asked questions about data model configuration, limitations, and upcoming features. +info: "Frequently asked questions about data model configuration, limitations, and upcoming features." image: /images/user-guide/what-is-twenty/faq.png sectionInfo: Flexible data model designed to support your unique business processes --- diff --git a/packages/twenty-docs/user-guide/data-model/fields.mdx b/packages/twenty-docs/user-guide/data-model/fields.mdx index 51a8e3264b0..1c228ba8071 100644 --- a/packages/twenty-docs/user-guide/data-model/fields.mdx +++ b/packages/twenty-docs/user-guide/data-model/fields.mdx @@ -4,6 +4,9 @@ info: "Understand the role of fields and how to handle them." image: /images/user-guide/fields/field.png sectionInfo: Flexible data model designed to support your unique business processes --- + +import { VimeoEmbed } from '/snippets/vimeo-embed.mdx'; + Header @@ -42,24 +45,7 @@ To add a custom field to any object, follow these steps: Your newly created field is now available within the application's fields. To display it on a specific view, click on the options menu, then select `Fields`. -
- -
- + **Quick way:** Click the **+** button at the top right of any object table, then select `Customize fields`. This takes you directly to the Data Model settings. diff --git a/packages/twenty-docs/user-guide/data-model/objects.mdx b/packages/twenty-docs/user-guide/data-model/objects.mdx index f0a0093a568..3d6fb40c39b 100644 --- a/packages/twenty-docs/user-guide/data-model/objects.mdx +++ b/packages/twenty-docs/user-guide/data-model/objects.mdx @@ -4,6 +4,9 @@ info: "Learn about standard objects and how to create custom ones for your busin image: /images/user-guide/objects/objects_orange.png sectionInfo: Flexible data model designed to support your unique business processes --- + +import { VimeoEmbed } from '/snippets/vimeo-embed.mdx'; + Header @@ -40,24 +43,7 @@ To create a new custom object: 2. Under Workspace, go to Data model. Here you'll be able to see an overview of all your existing Standard and Custom objects (both active and disabled). -
- -
- + 3. Click on `+ New object` at the top. Enter the name (both singular and plural), choose an icon, and add a description for your custom object and hit Save (at the top right). Using Listing as an example of custom object, the singular would be "listing" and the plural would be "listings" along with a description like "Listings that hosts created to showcase their property." @@ -65,24 +51,7 @@ To create a new custom object: The singular and plural names must be different. This is required for our GraphQL API to work properly. -
- -
- + 4. Once you create your custom object, you'll be able to manage it. You can edit the name, icon and description, view the different fields, and add more fields. diff --git a/packages/twenty-docs/user-guide/getting-started/create-workspace.mdx b/packages/twenty-docs/user-guide/getting-started/create-workspace.mdx index 7886ec0cc08..d62774888de 100644 --- a/packages/twenty-docs/user-guide/getting-started/create-workspace.mdx +++ b/packages/twenty-docs/user-guide/getting-started/create-workspace.mdx @@ -4,6 +4,9 @@ info: "Follow a step-by-step guide on how to register on Twenty, choose a subscr image: /images/user-guide/create-workspace/workspace-cover.png sectionInfo: Discover Twenty, an open-source CRM. --- + +import { VimeoEmbed } from '/snippets/vimeo-embed.mdx'; + Header @@ -15,24 +18,7 @@ sectionInfo: Discover Twenty, an open-source CRM. - **Continue with Microsoft** for Microsoft account registration. - Or, **Continue With Email** for email registration. -
- -
- + ## Step 2: Choosing a Trial Period Choose between two trial periods: diff --git a/packages/twenty-docs/user-guide/getting-started/import-export-data.mdx b/packages/twenty-docs/user-guide/getting-started/import-export-data.mdx index 627fcd36452..eaacfb6209c 100644 --- a/packages/twenty-docs/user-guide/getting-started/import-export-data.mdx +++ b/packages/twenty-docs/user-guide/getting-started/import-export-data.mdx @@ -4,6 +4,9 @@ info: "Learn how to import and export data." image: /images/user-guide/import-export-data/cloud.png sectionInfo: Discover Twenty, an open-source CRM. --- + +import { VimeoEmbed } from '/snippets/vimeo-embed.mdx'; + Header @@ -95,23 +98,6 @@ To export data from an object: 4. Click on `Export view`. 5. Select the save location for the CSV data. Note that exporting may take time with a large record count. -
- -
- + diff --git a/packages/twenty-docs/user-guide/integrations-api/api-webhooks.mdx b/packages/twenty-docs/user-guide/integrations-api/api-webhooks.mdx index 049f7df593c..745bbc78341 100644 --- a/packages/twenty-docs/user-guide/integrations-api/api-webhooks.mdx +++ b/packages/twenty-docs/user-guide/integrations-api/api-webhooks.mdx @@ -4,13 +4,16 @@ info: "Create and manage API keys for authentication and set up webhooks for rea image: /images/user-guide/api/api.png sectionInfo: Learn how to connect Twenty to your other tools. --- + +import { VimeoEmbed } from '/snippets/vimeo-embed.mdx'; + Header ## API Keys -API keys allow automated access to your CRM data, synchronize data with other systems, and create custom integrations or solutions. +API keys allow automated access to your CRM data, synchronize data with other systems, and create custom integrations or solutions. ### Create an API Key @@ -22,29 +25,12 @@ API keys allow automated access to your CRM data, synchronize data with other sy 4. Click **Save** to generate your API key 5. **Important**: Copy and store your API key immediately, it's only shown once -Once created, your API key provides access to your custom API documentation and playground where you can test endpoints with your actual data model. +Once created, your API key provides access to your custom API documentation and playground where you can test endpoints with your actual data model. Since your API key gives access to sensitive information, you shouldn't share it with services you don't fully trust. If leaked, someone can use it maliciously. If your API key's security is compromised, immediately disable it and generate a new one. -
- -
- + ### Manage API Keys @@ -77,24 +63,7 @@ Webhooks are ideal for integrating with external systems, while Workflows suppor Your webhook will immediately start receiving real-time notifications about changes to your CRM data. -
- -
- + ### Manage Webhooks diff --git a/packages/twenty-docs/user-guide/views/kanban-views.mdx b/packages/twenty-docs/user-guide/views/kanban-views.mdx index 14677a1a979..619170a11ca 100644 --- a/packages/twenty-docs/user-guide/views/kanban-views.mdx +++ b/packages/twenty-docs/user-guide/views/kanban-views.mdx @@ -4,6 +4,9 @@ info: "Learn how to customize and navigate Kanban Views." image: /images/user-guide/kanban-views/kanban.png sectionInfo: Discover how to use standard and custom objects in your workspace. --- + +import { VimeoEmbed } from '/snippets/vimeo-embed.mdx'; + Header @@ -16,24 +19,7 @@ Kanban views visually map out process flows, where each column stands for a dist You can move each card between stages as it goes through your workflow by dragging and dropping. To proceed, hold your click on a card and move it to the next stage. -
- -
- + ## Add and delete stages @@ -43,24 +29,7 @@ You can tailor your workflow to suit your needs using stages, which represent a To add a stage, access the Select field settings by navigating to Settings > Data Model, selecting your object, and then the field your Kanban board depends on. -
- -
- + ### Remove Stages diff --git a/packages/twenty-docs/user-guide/views/views-sort-filter.mdx b/packages/twenty-docs/user-guide/views/views-sort-filter.mdx index 6d8e1847064..68d8a7d690f 100644 --- a/packages/twenty-docs/user-guide/views/views-sort-filter.mdx +++ b/packages/twenty-docs/user-guide/views/views-sort-filter.mdx @@ -4,6 +4,9 @@ info: "Find out how to create, manage and delete Object Views." image: /images/user-guide/views/filter.png sectionInfo: Discover how to use standard and custom objects in your workspace. --- + +import { VimeoEmbed } from '/snippets/vimeo-embed.mdx'; + Header @@ -37,47 +40,13 @@ There are two ways to create a new view. Either directly from the `View Switcher The newly created view opens automatically. -
- -
- + #### From Sorting and Filtering When you change the `Sorting` and `Filtering` of an existing view, a `Save as new view` button will appear at the right edge of the `View Bar`. This will open the New View menu mentioned above, allowing you to create a new view out of an existing one. -
- -
- + ### Editing and Deleting a View @@ -88,24 +57,7 @@ To Edit or Delete a view: Upon clicking on edit, you can change the icon and the name of the view or delete the view completely. -
- -
- + ## Navigating Between Views @@ -124,48 +76,14 @@ To filter a view: - Add more filters with `+ Add filter` or remove them with **X**. -
- -
- + ### Sorting a View Order your fields data in ascending or descending order: - Select **Sort**, choose a field, and define the sort order you desire. - You can apply and arrange several sorts as needed. -
- -
- + ### Field display diff --git a/tools/eslint-rules/index.ts b/tools/eslint-rules/index.ts index b28a2350c37..b1bd6178f19 100644 --- a/tools/eslint-rules/index.ts +++ b/tools/eslint-rules/index.ts @@ -26,6 +26,10 @@ import { rule as maxConstsPerFile, RULE_NAME as maxConstsPerFileName, } from './rules/max-consts-per-file'; +import { + rule as mdxComponentNewlines, + RULE_NAME as mdxComponentNewlinesName, +} from './rules/mdx-component-newlines'; import { rule as noHardcodedColors, RULE_NAME as noHardcodedColorsName, @@ -103,5 +107,6 @@ module.exports = { [injectWorkspaceRepositoryName]: injectWorkspaceRepository, [restApiMethodsShouldBeGuardedName]: restApiMethodsShouldBeGuarded, [graphqlResolversShouldBeGuardedName]: graphqlResolversShouldBeGuarded, + [mdxComponentNewlinesName]: mdxComponentNewlines, }, }; diff --git a/tools/eslint-rules/rules/mdx-component-newlines.ts b/tools/eslint-rules/rules/mdx-component-newlines.ts new file mode 100644 index 00000000000..f061b74b2ea --- /dev/null +++ b/tools/eslint-rules/rules/mdx-component-newlines.ts @@ -0,0 +1,97 @@ +import type { TSESTree } from '@typescript-eslint/utils'; +import type { Rule } from 'eslint'; + +export const RULE_NAME = 'mdx-component-newlines'; + +export const rule: Rule.RuleModule = { + meta: { + type: 'layout', + docs: { + description: + 'Enforce JSX/HTML component tags are on separate lines in MDX files to prevent Crowdin translation issues', + recommended: true, + }, + fixable: 'whitespace', + messages: { + tagOnSameLine: + 'JSX/HTML tag should be on its own line. This prevents Crowdin from merging tags with content during translation.', + }, + schema: [], + }, + + create: (context) => { + const sourceCode = context.sourceCode || context.getSourceCode(); + + return { + // Check JSX opening tags that have content on the same line + JSXOpeningElement: (node: TSESTree.JSXOpeningElement) => { + const tokenAfter = sourceCode.getTokenAfter(node as any); + + if (!tokenAfter) { + return; + } + + // Check if there's content on the same line after the opening tag + if (node.loc.end.line === tokenAfter.loc.start.line) { + // Allow if it's a closing tag immediately after (self-closing pattern) + const nextNode = (sourceCode as any).getNodeByRangeIndex?.( + tokenAfter.range[0], + ); + if (nextNode?.type === 'JSXClosingElement') { + return; + } + + // Check if it's actual content (not whitespace) + const textBetween = sourceCode.text.slice( + node.range[1], + tokenAfter.range[0], + ); + if (textBetween.trim() === '') { + return; // Only whitespace, that's fine + } + + context.report({ + node: node as any, + messageId: 'tagOnSameLine', + fix: (fixer) => fixer.insertTextAfter(node as any, '\n'), + }); + } + }, + + // Check JSX closing tags that have content on the same line before them + JSXClosingElement: (node: TSESTree.JSXClosingElement) => { + const tokenBefore = sourceCode.getTokenBefore(node as any); + + if (!tokenBefore) { + return; + } + + // Check if there's content on the same line before the closing tag + if (node.loc.start.line === tokenBefore.loc.end.line) { + // Check if it's actual content (not whitespace or opening tag) + const prevNode = (sourceCode as any).getNodeByRangeIndex?.( + tokenBefore.range[0], + ); + if (prevNode?.type === 'JSXOpeningElement') { + return; // This is handled by the opening tag check + } + + const textBetween = sourceCode.text.slice( + tokenBefore.range[1], + node.range[0], + ); + + // If there's any non-whitespace content before the closing tag on same line + if (textBetween.trim() !== '' || tokenBefore.type === 'Punctuator') { + context.report({ + node: node as any, + messageId: 'tagOnSameLine', + fix: (fixer) => fixer.insertTextBefore(node as any, '\n'), + }); + } + } + }, + }; + }, +}; + diff --git a/yarn.lock b/yarn.lock index 80c4f5460a9..8b0da0d3170 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2577,7 +2577,7 @@ __metadata: languageName: node linkType: hard -"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.16.7, @babel/code-frame@npm:^7.24.7, @babel/code-frame@npm:^7.27.1": +"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.16.7, @babel/code-frame@npm:^7.21.4, @babel/code-frame@npm:^7.24.7, @babel/code-frame@npm:^7.27.1": version: 7.27.1 resolution: "@babel/code-frame@npm:7.27.1" dependencies: @@ -12185,6 +12185,22 @@ __metadata: languageName: node linkType: hard +"@npmcli/config@npm:^8.0.0": + version: 8.3.4 + resolution: "@npmcli/config@npm:8.3.4" + dependencies: + "@npmcli/map-workspaces": "npm:^3.0.2" + "@npmcli/package-json": "npm:^5.1.1" + ci-info: "npm:^4.0.0" + ini: "npm:^4.1.2" + nopt: "npm:^7.2.1" + proc-log: "npm:^4.2.0" + semver: "npm:^7.3.5" + walk-up-path: "npm:^3.0.1" + checksum: 10c0/f44af54bd2cdb32b132a861863bfe7936599a4706490136082585ab71e37ef47f201f8d2013b9902b3ff30cc8264f5da70f834c80f0a29953b52a28da20f5ea7 + languageName: node + linkType: hard + "@npmcli/fs@npm:^1.0.0": version: 1.1.1 resolution: "@npmcli/fs@npm:1.1.1" @@ -12246,6 +12262,23 @@ __metadata: languageName: node linkType: hard +"@npmcli/git@npm:^5.0.0": + version: 5.0.8 + resolution: "@npmcli/git@npm:5.0.8" + dependencies: + "@npmcli/promise-spawn": "npm:^7.0.0" + ini: "npm:^4.1.3" + lru-cache: "npm:^10.0.1" + npm-pick-manifest: "npm:^9.0.0" + proc-log: "npm:^4.0.0" + promise-inflight: "npm:^1.0.1" + promise-retry: "npm:^2.0.1" + semver: "npm:^7.3.5" + which: "npm:^4.0.0" + checksum: 10c0/892441c968404950809c7b515a93b78167ea1db2252f259f390feae22a2c5477f3e1629e105e19a084c05afc56e585bf3f13c2f13b54a06bfd6786f0c8429532 + languageName: node + linkType: hard + "@npmcli/installed-package-contents@npm:^1.0.6, @npmcli/installed-package-contents@npm:^1.0.7": version: 1.0.7 resolution: "@npmcli/installed-package-contents@npm:1.0.7" @@ -12282,6 +12315,18 @@ __metadata: languageName: node linkType: hard +"@npmcli/map-workspaces@npm:^3.0.2": + version: 3.0.6 + resolution: "@npmcli/map-workspaces@npm:3.0.6" + dependencies: + "@npmcli/name-from-folder": "npm:^2.0.0" + glob: "npm:^10.2.2" + minimatch: "npm:^9.0.0" + read-package-json-fast: "npm:^3.0.0" + checksum: 10c0/6bfcf8ca05ab9ddc2bd19c0fd91e9982f03cc6e67b0c03f04ba4d2f29b7d83f96e759c0f8f1f4b6dbe3182272483643a0d1269788352edd0c883d6fbfa2f3f14 + languageName: node + linkType: hard + "@npmcli/metavuln-calculator@npm:^1.1.0": version: 1.1.1 resolution: "@npmcli/metavuln-calculator@npm:1.1.1" @@ -12320,6 +12365,13 @@ __metadata: languageName: node linkType: hard +"@npmcli/name-from-folder@npm:^2.0.0": + version: 2.0.0 + resolution: "@npmcli/name-from-folder@npm:2.0.0" + checksum: 10c0/1aa551771d98ab366d4cb06b33efd3bb62b609942f6d9c3bb667c10e5bb39a223d3e330022bc980a44402133e702ae67603862099ac8254dad11f90e77409827 + languageName: node + linkType: hard + "@npmcli/node-gyp@npm:^1.0.1, @npmcli/node-gyp@npm:^1.0.2": version: 1.0.3 resolution: "@npmcli/node-gyp@npm:1.0.3" @@ -12343,6 +12395,21 @@ __metadata: languageName: node linkType: hard +"@npmcli/package-json@npm:^5.1.1": + version: 5.2.1 + resolution: "@npmcli/package-json@npm:5.2.1" + dependencies: + "@npmcli/git": "npm:^5.0.0" + glob: "npm:^10.2.2" + hosted-git-info: "npm:^7.0.0" + json-parse-even-better-errors: "npm:^3.0.0" + normalize-package-data: "npm:^6.0.0" + proc-log: "npm:^4.0.0" + semver: "npm:^7.5.3" + checksum: 10c0/b852e31e3121a0afe5fa20bbf4faa701a59dbc9d9dd7141f7fd57b8e919ce22c1285dcdfea490851fe410fa0f7bc9c397cafba0d268aaa53420a12d7c561dde1 + languageName: node + linkType: hard + "@npmcli/promise-spawn@npm:^1.2.0, @npmcli/promise-spawn@npm:^1.3.2": version: 1.3.2 resolution: "@npmcli/promise-spawn@npm:1.3.2" @@ -12361,6 +12428,15 @@ __metadata: languageName: node linkType: hard +"@npmcli/promise-spawn@npm:^7.0.0": + version: 7.0.2 + resolution: "@npmcli/promise-spawn@npm:7.0.2" + dependencies: + which: "npm:^4.0.0" + checksum: 10c0/8f2af5bc2c1b1ccfb9bcd91da8873ab4723616d8bd5af877c0daa40b1e2cbfa4afb79e052611284179cae918c945a1b99ae1c565d78a355bec1a461011e89f71 + languageName: node + linkType: hard + "@npmcli/run-script@npm:^1.8.2": version: 1.8.6 resolution: "@npmcli/run-script@npm:1.8.6" @@ -23375,6 +23451,15 @@ __metadata: languageName: node linkType: hard +"@types/concat-stream@npm:^2.0.0": + version: 2.0.3 + resolution: "@types/concat-stream@npm:2.0.3" + dependencies: + "@types/node": "npm:*" + checksum: 10c0/dd8bdf8061d275f30dc602e04c63ebc001d3a260e722c867916667a45f90fd22da62a2de0919a35f35969b84a14cb94c69d15bdb2c8a518ce8abf3a0e1a16e5d + languageName: node + linkType: hard + "@types/connect@npm:*, @types/connect@npm:3.4.38": version: 3.4.38 resolution: "@types/connect@npm:3.4.38" @@ -23858,6 +23943,13 @@ __metadata: languageName: node linkType: hard +"@types/is-empty@npm:^1.0.0": + version: 1.2.3 + resolution: "@types/is-empty@npm:1.2.3" + checksum: 10c0/2ca9af27ce93cc0abe277178a69803e641d755152bf4fc415e1789451ff62f6e39cf15dbdc111d490171d757669937ad4789c7395af55f5e7d261f6bfe416974 + languageName: node + linkType: hard + "@types/is-hotkey@npm:^0.1.1": version: 0.1.10 resolution: "@types/is-hotkey@npm:0.1.10" @@ -24457,6 +24549,15 @@ __metadata: languageName: node linkType: hard +"@types/node@npm:^22.0.0": + version: 22.19.0 + resolution: "@types/node@npm:22.19.0" + dependencies: + undici-types: "npm:~6.21.0" + checksum: 10c0/66b98fcd38efb4ae58c628d61fed2b8f17c830eb665d8bceabc4174cae1dd81b8e4caac4c70d7dc929f9f76a3dc46cb21f480e904d0b898297bd12c0a2d1571a + languageName: node + linkType: hard + "@types/node@npm:^22.5.5, @types/node@npm:^22.7.5": version: 22.18.1 resolution: "@types/node@npm:22.18.1" @@ -24830,6 +24931,13 @@ __metadata: languageName: node linkType: hard +"@types/supports-color@npm:^8.0.0": + version: 8.1.3 + resolution: "@types/supports-color@npm:8.1.3" + checksum: 10c0/03aa3616b403f3deaeb774df6d3a3969845b0c9f449814a83c2c53eb6818f5f9b571ba205330b0ebe8e46f41fd550f581a34b4310b13f0e0448694cfff37ddbf + languageName: node + linkType: hard + "@types/tedious@npm:^4.0.14": version: 4.0.14 resolution: "@types/tedious@npm:4.0.14" @@ -31204,6 +31312,18 @@ __metadata: languageName: node linkType: hard +"concat-stream@npm:^2.0.0": + version: 2.0.0 + resolution: "concat-stream@npm:2.0.0" + dependencies: + buffer-from: "npm:^1.0.0" + inherits: "npm:^2.0.3" + readable-stream: "npm:^3.0.2" + typedarray: "npm:^0.0.6" + checksum: 10c0/29565dd9198fe1d8cf57f6cc71527dbc6ad67e12e4ac9401feb389c53042b2dceedf47034cbe702dfc4fd8df3ae7e6bfeeebe732cc4fa2674e484c13f04c219a + languageName: node + linkType: hard + "concurrently@npm:^8.2.2": version: 8.2.2 resolution: "concurrently@npm:8.2.2" @@ -33525,6 +33645,13 @@ __metadata: languageName: node linkType: hard +"emoji-regex@npm:^10.2.1": + version: 10.6.0 + resolution: "emoji-regex@npm:10.6.0" + checksum: 10c0/1e4aa097bb007301c3b4b1913879ae27327fdc48e93eeefefe3b87e495eb33c5af155300be951b4349ff6ac084f4403dc9eff970acba7c1c572d89396a9a32d7 + languageName: node + linkType: hard + "emoji-regex@npm:^10.3.0": version: 10.4.0 resolution: "emoji-regex@npm:10.4.0" @@ -33693,6 +33820,15 @@ __metadata: languageName: node linkType: hard +"error-ex@npm:^1.3.2": + version: 1.3.4 + resolution: "error-ex@npm:1.3.4" + dependencies: + is-arrayish: "npm:^0.2.1" + checksum: 10c0/b9e34ff4778b8f3b31a8377e1c654456f4c41aeaa3d10a1138c3b7635d8b7b2e03eb2475d46d8ae055c1f180a1063e100bffabf64ea7e7388b37735df5328664 + languageName: node + linkType: hard + "error@npm:^10.4.0": version: 10.4.0 resolution: "error@npm:10.4.0" @@ -34702,6 +34838,33 @@ __metadata: languageName: node linkType: hard +"eslint-mdx@npm:^3.6.2": + version: 3.6.2 + resolution: "eslint-mdx@npm:3.6.2" + dependencies: + acorn: "npm:^8.15.0" + acorn-jsx: "npm:^5.3.2" + espree: "npm:^9.6.1 || ^10.4.0" + estree-util-visit: "npm:^2.0.0" + remark-mdx: "npm:^3.1.0" + remark-parse: "npm:^11.0.0" + remark-stringify: "npm:^11.0.0" + synckit: "npm:^0.11.8" + unified: "npm:^11.0.5" + unified-engine: "npm:^11.2.2" + unist-util-visit: "npm:^5.0.0" + uvu: "npm:^0.5.6" + vfile: "npm:^6.0.3" + peerDependencies: + eslint: ">=8.0.0" + remark-lint-file-extension: "*" + peerDependenciesMeta: + remark-lint-file-extension: + optional: true + checksum: 10c0/07238395e932f5caf47a0301fc61f350a24c57e4bf923601f3e767f02d5f7ac18d708dd59819bcc1af54f16e5e6cc6aabb37a08614faade2a5e3fc317e802424 + languageName: node + linkType: hard + "eslint-module-utils@npm:^2.12.1, eslint-module-utils@npm:^2.7.4": version: 2.12.1 resolution: "eslint-module-utils@npm:2.12.1" @@ -34780,6 +34943,26 @@ __metadata: languageName: node linkType: hard +"eslint-plugin-mdx@npm:^3.6.2": + version: 3.6.2 + resolution: "eslint-plugin-mdx@npm:3.6.2" + dependencies: + eslint-mdx: "npm:^3.6.2" + mdast-util-from-markdown: "npm:^2.0.2" + mdast-util-mdx: "npm:^3.0.0" + micromark-extension-mdxjs: "npm:^3.0.0" + remark-mdx: "npm:^3.1.0" + remark-parse: "npm:^11.0.0" + remark-stringify: "npm:^11.0.0" + synckit: "npm:^0.11.8" + unified: "npm:^11.0.5" + vfile: "npm:^6.0.3" + peerDependencies: + eslint: ">=8.0.0" + checksum: 10c0/16be144348fc6fe66d8a2d7d0f739084991aea5f79c3c4b4b20232ead0e826a5e26806b0fcdbfcda4cef325369a6ad1630bdb1d66a3b3dce9d5c0f765e110ee5 + languageName: node + linkType: hard + "eslint-plugin-prefer-arrow@npm:^1.2.3": version: 1.2.3 resolution: "eslint-plugin-prefer-arrow@npm:1.2.3" @@ -35044,7 +35227,7 @@ __metadata: languageName: node linkType: hard -"espree@npm:^10.0.1, espree@npm:^10.4.0": +"espree@npm:^10.0.1, espree@npm:^10.4.0, espree@npm:^9.6.1 || ^10.4.0": version: 10.4.0 resolution: "espree@npm:10.4.0" dependencies: @@ -38883,6 +39066,13 @@ __metadata: languageName: node linkType: hard +"ignore@npm:^6.0.0": + version: 6.0.2 + resolution: "ignore@npm:6.0.2" + checksum: 10c0/9a38feac1861906a78ba0f03e8ef3cd6b0526dce2a1a84e1009324b557763afeb9c3ebcc04666b21f7bbf71adda45e76781bb9e2eaa0903d45dcaded634454f5 + languageName: node + linkType: hard + "ignore@npm:^7.0.0": version: 7.0.5 resolution: "ignore@npm:7.0.5" @@ -39018,6 +39208,13 @@ __metadata: languageName: node linkType: hard +"import-meta-resolve@npm:^4.0.0": + version: 4.2.0 + resolution: "import-meta-resolve@npm:4.2.0" + checksum: 10c0/3ee8aeecb61d19b49d2703987f977e9d1c7d4ba47db615a570eaa02fe414f40dfa63f7b953e842cbe8470d26df6371332bfcf21b2fd92b0112f9fea80dde2c4c + languageName: node + linkType: hard + "imurmurhash@npm:^0.1.4": version: 0.1.4 resolution: "imurmurhash@npm:0.1.4" @@ -39091,6 +39288,13 @@ __metadata: languageName: node linkType: hard +"ini@npm:^4.1.2, ini@npm:^4.1.3": + version: 4.1.3 + resolution: "ini@npm:4.1.3" + checksum: 10c0/0d27eff094d5f3899dd7c00d0c04ea733ca03a8eb6f9406ce15daac1a81de022cb417d6eaff7e4342451ffa663389c565ffc68d6825eaf686bf003280b945764 + languageName: node + linkType: hard + "ini@npm:^5.0.0": version: 5.0.0 resolution: "ini@npm:5.0.0" @@ -39662,6 +39866,13 @@ __metadata: languageName: node linkType: hard +"is-empty@npm:^1.0.0": + version: 1.2.0 + resolution: "is-empty@npm:1.2.0" + checksum: 10c0/f0dd6534716f2749586c35f1dcf37a0a5ac31e91d629ae2652b36c7f72c0ce71f0b68f082a6eed95b1af6f84ba31cd757c2343b19507878ed1e532a3383ebaaa + languageName: node + linkType: hard + "is-extendable@npm:^0.1.0": version: 0.1.1 resolution: "is-extendable@npm:0.1.1" @@ -42428,6 +42639,13 @@ __metadata: languageName: node linkType: hard +"lines-and-columns@npm:^2.0.3": + version: 2.0.4 + resolution: "lines-and-columns@npm:2.0.4" + checksum: 10c0/4db28bf065cd7ad897c0700f22d3d0d7c5ed6777e138861c601c496d545340df3fc19e18bd04ff8d95a246a245eb55685b82ca2f8c2ca53a008e9c5316250379 + languageName: node + linkType: hard + "linkify-it@npm:5.0.0, linkify-it@npm:^5.0.0": version: 5.0.0 resolution: "linkify-it@npm:5.0.0" @@ -42465,6 +42683,16 @@ __metadata: languageName: node linkType: hard +"load-plugin@npm:^6.0.0": + version: 6.0.3 + resolution: "load-plugin@npm:6.0.3" + dependencies: + "@npmcli/config": "npm:^8.0.0" + import-meta-resolve: "npm:^4.0.0" + checksum: 10c0/cbbd4e18472a0ed543b6d60e867a1e2aae385205fcaa76d300ab5a72697e057422cd1e6ff2ba19755c55a86b3d53e53b81a814c757be720895ba525d05f75797 + languageName: node + linkType: hard + "load-yaml-file@npm:^0.2.0": version: 0.2.0 resolution: "load-yaml-file@npm:0.2.0" @@ -46364,7 +46592,7 @@ __metadata: languageName: node linkType: hard -"nopt@npm:^7.0.0": +"nopt@npm:^7.0.0, nopt@npm:^7.2.1": version: 7.2.1 resolution: "nopt@npm:7.2.1" dependencies: @@ -46399,6 +46627,17 @@ __metadata: languageName: node linkType: hard +"normalize-package-data@npm:^6.0.0": + version: 6.0.2 + resolution: "normalize-package-data@npm:6.0.2" + dependencies: + hosted-git-info: "npm:^7.0.0" + semver: "npm:^7.3.5" + validate-npm-package-license: "npm:^3.0.4" + checksum: 10c0/7e32174e7f5575ede6d3d449593247183880122b4967d4ae6edb28cea5769ca025defda54fc91ec0e3c972fdb5ab11f9284606ba278826171b264cb16a9311ef + languageName: node + linkType: hard + "normalize-path@npm:3.0.0, normalize-path@npm:^3.0.0, normalize-path@npm:~3.0.0": version: 3.0.0 resolution: "normalize-path@npm:3.0.0" @@ -46519,6 +46758,18 @@ __metadata: languageName: node linkType: hard +"npm-package-arg@npm:^11.0.0": + version: 11.0.3 + resolution: "npm-package-arg@npm:11.0.3" + dependencies: + hosted-git-info: "npm:^7.0.0" + proc-log: "npm:^4.0.0" + semver: "npm:^7.3.5" + validate-npm-package-name: "npm:^5.0.0" + checksum: 10c0/e18333485e05c3a8774f4b5701ef74f4799533e650b70a68ca8dd697666c9a8d46932cb765fc593edce299521033bd4025a40323d5240cea8a393c784c0c285a + languageName: node + linkType: hard + "npm-package-arg@npm:^8.0.0, npm-package-arg@npm:^8.0.1, npm-package-arg@npm:^8.1.2, npm-package-arg@npm:^8.1.5": version: 8.1.5 resolution: "npm-package-arg@npm:8.1.5" @@ -46577,6 +46828,18 @@ __metadata: languageName: node linkType: hard +"npm-pick-manifest@npm:^9.0.0": + version: 9.1.0 + resolution: "npm-pick-manifest@npm:9.1.0" + dependencies: + npm-install-checks: "npm:^6.0.0" + npm-normalize-package-bin: "npm:^3.0.0" + npm-package-arg: "npm:^11.0.0" + semver: "npm:^7.3.5" + checksum: 10c0/8765f4199755b381323da2bff2202b4b15b59f59dba0d1be3f2f793b591321cd19e1b5a686ef48d9753a6bd4868550da632541a45dfb61809d55664222d73e44 + languageName: node + linkType: hard + "npm-registry-fetch@npm:^11.0.0": version: 11.0.0 resolution: "npm-registry-fetch@npm:11.0.0" @@ -47687,6 +47950,19 @@ __metadata: languageName: node linkType: hard +"parse-json@npm:^7.0.0": + version: 7.1.1 + resolution: "parse-json@npm:7.1.1" + dependencies: + "@babel/code-frame": "npm:^7.21.4" + error-ex: "npm:^1.3.2" + json-parse-even-better-errors: "npm:^3.0.0" + lines-and-columns: "npm:^2.0.3" + type-fest: "npm:^3.8.0" + checksum: 10c0/a85ebc7430af7763fa52eb456d7efd35c35be5b06f04d8d80c37d0d33312ac6cdff12647acb9c95448dcc8b907dfafa81fb126e094aa132b0abc2a71b9df51d5 + languageName: node + linkType: hard + "parse-latin@npm:^7.0.0": version: 7.0.0 resolution: "parse-latin@npm:7.0.0" @@ -48868,7 +49144,7 @@ __metadata: languageName: node linkType: hard -"proc-log@npm:^4.1.0, proc-log@npm:^4.2.0": +"proc-log@npm:^4.0.0, proc-log@npm:^4.1.0, proc-log@npm:^4.2.0": version: 4.2.0 resolution: "proc-log@npm:4.2.0" checksum: 10c0/17db4757c2a5c44c1e545170e6c70a26f7de58feb985091fb1763f5081cab3d01b181fb2dd240c9f4a4255a1d9227d163d5771b7e69c9e49a561692db865efb9 @@ -50381,7 +50657,7 @@ __metadata: languageName: node linkType: hard -"readable-stream@npm:3, readable-stream@npm:^3.0.6, readable-stream@npm:^3.1.1, readable-stream@npm:^3.4.0, readable-stream@npm:^3.5.0, readable-stream@npm:^3.6.0": +"readable-stream@npm:3, readable-stream@npm:^3.0.2, readable-stream@npm:^3.0.6, readable-stream@npm:^3.1.1, readable-stream@npm:^3.4.0, readable-stream@npm:^3.5.0, readable-stream@npm:^3.6.0": version: 3.6.2 resolution: "readable-stream@npm:3.6.2" dependencies: @@ -53652,6 +53928,17 @@ __metadata: languageName: node linkType: hard +"string-width@npm:^6.0.0": + version: 6.1.0 + resolution: "string-width@npm:6.1.0" + dependencies: + eastasianwidth: "npm:^0.2.0" + emoji-regex: "npm:^10.2.1" + strip-ansi: "npm:^7.0.1" + checksum: 10c0/7b2991ea7c946a43042070787b85af454079116dfd6d853aab4ff8a6d4ac717cdc18656cfee15b7a7a78286669202a4a56385728f0740cb1e15001c71807b361 + languageName: node + linkType: hard + "string-width@npm:^7.0.0, string-width@npm:^7.2.0": version: 7.2.0 resolution: "string-width@npm:7.2.0" @@ -54185,6 +54472,13 @@ __metadata: languageName: node linkType: hard +"supports-color@npm:^9.0.0": + version: 9.4.0 + resolution: "supports-color@npm:9.4.0" + checksum: 10c0/6c24e6b2b64c6a60e5248490cfa50de5924da32cf09ae357ad8ebbf305cc5d2717ba705a9d4cb397d80bbf39417e8fdc8d7a0ce18bd0041bf7b5b456229164e4 + languageName: node + linkType: hard + "supports-hyperlinks@npm:^1.0.1": version: 1.0.1 resolution: "supports-hyperlinks@npm:1.0.1" @@ -55972,6 +56266,7 @@ __metadata: eslint-plugin-import: "npm:^2.31.0" eslint-plugin-jsx-a11y: "npm:^6.10.2" eslint-plugin-lingui: "npm:^0.9.0" + eslint-plugin-mdx: "npm:^3.6.2" eslint-plugin-prefer-arrow: "npm:^1.2.3" eslint-plugin-prettier: "npm:^5.1.2" eslint-plugin-project-structure: "npm:^3.9.1" @@ -56569,6 +56864,35 @@ __metadata: languageName: node linkType: hard +"unified-engine@npm:^11.2.2": + version: 11.2.2 + resolution: "unified-engine@npm:11.2.2" + dependencies: + "@types/concat-stream": "npm:^2.0.0" + "@types/debug": "npm:^4.0.0" + "@types/is-empty": "npm:^1.0.0" + "@types/node": "npm:^22.0.0" + "@types/unist": "npm:^3.0.0" + concat-stream: "npm:^2.0.0" + debug: "npm:^4.0.0" + extend: "npm:^3.0.0" + glob: "npm:^10.0.0" + ignore: "npm:^6.0.0" + is-empty: "npm:^1.0.0" + is-plain-obj: "npm:^4.0.0" + load-plugin: "npm:^6.0.0" + parse-json: "npm:^7.0.0" + trough: "npm:^2.0.0" + unist-util-inspect: "npm:^8.0.0" + vfile: "npm:^6.0.0" + vfile-message: "npm:^4.0.0" + vfile-reporter: "npm:^8.0.0" + vfile-statistics: "npm:^3.0.0" + yaml: "npm:^2.0.0" + checksum: 10c0/daac3b2bf18fb79a052129958e104bddfb8241ef5ea51696a214864906a61a375c4d95b42958b7ed300ebaa028172f1e8b6515f1664a0fa765eb11ca06b891ee + languageName: node + linkType: hard + "unified@npm:^10.0.0": version: 10.1.2 resolution: "unified@npm:10.1.2" @@ -56697,6 +57021,15 @@ __metadata: languageName: node linkType: hard +"unist-util-inspect@npm:^8.0.0": + version: 8.1.0 + resolution: "unist-util-inspect@npm:8.1.0" + dependencies: + "@types/unist": "npm:^3.0.0" + checksum: 10c0/d3dff256ffd77a1e8dd583be89070dc1ab124d424794fcc1105a38c2f0bb0538afc686e592699807c7d9fa612821961033fe38e26c11ba0bb51d19e8ae7c4119 + languageName: node + linkType: hard + "unist-util-is@npm:^5.0.0": version: 5.2.1 resolution: "unist-util-is@npm:5.2.1" @@ -57392,7 +57725,7 @@ __metadata: languageName: node linkType: hard -"uvu@npm:^0.5.0": +"uvu@npm:^0.5.0, uvu@npm:^0.5.6": version: 0.5.6 resolution: "uvu@npm:0.5.6" dependencies: @@ -57540,6 +57873,42 @@ __metadata: languageName: node linkType: hard +"vfile-reporter@npm:^8.0.0": + version: 8.1.1 + resolution: "vfile-reporter@npm:8.1.1" + dependencies: + "@types/supports-color": "npm:^8.0.0" + string-width: "npm:^6.0.0" + supports-color: "npm:^9.0.0" + unist-util-stringify-position: "npm:^4.0.0" + vfile: "npm:^6.0.0" + vfile-message: "npm:^4.0.0" + vfile-sort: "npm:^4.0.0" + vfile-statistics: "npm:^3.0.0" + checksum: 10c0/5da85c67e4a26762d64d65d0aac5ef339a413cc051470d970eea7352f07afd24577d42780c3af93c109177078df1bbbdbcc3e82adcc34e1bb96d2665f3f0c2a1 + languageName: node + linkType: hard + +"vfile-sort@npm:^4.0.0": + version: 4.0.0 + resolution: "vfile-sort@npm:4.0.0" + dependencies: + vfile: "npm:^6.0.0" + vfile-message: "npm:^4.0.0" + checksum: 10c0/fe1a4cbe24d03b81a7e7486be107eb029ac2631a3575e55a3f1d25cf54bcf2d60b3f76694dedf8a2f60793877e1d192234157cdfd50d1a0d18b9a4c1487cdf65 + languageName: node + linkType: hard + +"vfile-statistics@npm:^3.0.0": + version: 3.0.0 + resolution: "vfile-statistics@npm:3.0.0" + dependencies: + vfile: "npm:^6.0.0" + vfile-message: "npm:^4.0.0" + checksum: 10c0/3de51670329701e2cff75d979564087578844444d9b9d8619a2fdd2a904bc970bf4d05b58e7cee71e0f6f34087f1f7f2ea85cdfa5bf58f572c777432c156bd8f + languageName: node + linkType: hard + "vfile@npm:^5.0.0, vfile@npm:^5.3.0": version: 5.3.7 resolution: "vfile@npm:5.3.7" @@ -57936,6 +58305,13 @@ __metadata: languageName: node linkType: hard +"walk-up-path@npm:^3.0.1": + version: 3.0.1 + resolution: "walk-up-path@npm:3.0.1" + checksum: 10c0/3184738e0cf33698dd58b0ee4418285b9c811e58698f52c1f025435a85c25cbc5a63fee599f1a79cb29ca7ef09a44ec9417b16bfd906b1a37c305f7aa20ee5bc + languageName: node + linkType: hard + "walker@npm:^1.0.8": version: 1.0.8 resolution: "walker@npm:1.0.8"