diff --git a/.github/workflows/ci-front.yaml b/.github/workflows/ci-front.yaml index d2a949c47b5..6fcae868395 100644 --- a/.github/workflows/ci-front.yaml +++ b/.github/workflows/ci-front.yaml @@ -1,10 +1,8 @@ -name: CI Front and E2E +name: CI Front on: pull_request: - merge_group: - permissions: contents: read @@ -29,15 +27,6 @@ jobs: packages/twenty-shared/** packages/twenty-sdk/** !packages/twenty-sdk/package.json - changed-files-check-e2e: - uses: ./.github/workflows/changed-files.yaml - with: - files: | - packages/** - !packages/create-twenty-app/package.json - !packages/twenty-sdk/package.json - playwright.config.ts - .github/workflows/ci-front.yaml front-sb-build: needs: changed-files-check if: needs.changed-files-check.outputs.any_changed == 'true' @@ -257,117 +246,6 @@ jobs: # name: frontend-build # path: packages/twenty-front/build # retention-days: 1 - e2e-test: - runs-on: ubuntu-latest - needs: [changed-files-check-e2e, front-build] - if: | - always() && - needs.changed-files-check-e2e.outputs.any_changed == 'true' && - (needs.front-build.result == 'success' || needs.front-build.result == 'skipped') && - (github.event_name == 'push' || github.event_name == 'merge_group' || (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'run-e2e'))) - timeout-minutes: 30 - env: - NODE_OPTIONS: "--max-old-space-size=10240" - services: - postgres: - image: twentycrm/twenty-postgres-spilo - env: - PGUSER_SUPERUSER: postgres - PGPASSWORD_SUPERUSER: postgres - ALLOW_NOSSL: "true" - SPILO_PROVIDER: "local" - ports: - - 5432:5432 - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 - redis: - image: redis - ports: - - 6379:6379 - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 10 - - uses: actions/setup-node@v4 - with: - node-version: lts/* - - - name: Check system resources - run: | - echo "Available memory:" - free -h - echo "Available disk space:" - df -h - echo "CPU info:" - lscpu - - - name: Install dependencies - uses: ./.github/actions/yarn-install - - - name: Build twenty-shared - run: npx nx build twenty-shared - - - name: Install Playwright Browsers - run: npx nx setup twenty-e2e-testing - - - name: Setup environment files - run: | - cp packages/twenty-front/.env.example packages/twenty-front/.env - npx nx reset:env:e2e-testing-server twenty-server - - # - name: Download frontend build artifact - # if: needs.front-build.result == 'success' - # uses: actions/download-artifact@v4 - # with: - # name: frontend-build - # path: packages/twenty-front/build - - # - name: Build frontend (if not available from front-build) - # if: needs.front-build.result == 'skipped' - # run: NODE_ENV=production NODE_OPTIONS="--max-old-space-size=10240" npx nx build twenty-front - - - name: Build frontend - run: NODE_ENV=production NODE_OPTIONS="--max-old-space-size=10240" npx nx build twenty-front - - - name: Build server - run: npx nx build twenty-server - - - name: Create and setup database - run: | - PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d postgres -c 'CREATE DATABASE "default";' - PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d postgres -c 'CREATE DATABASE "test";' - npx nx run twenty-server:database:reset - - - name: Start server - run: | - npx nx start twenty-server & - echo "Waiting for server to be ready..." - timeout 60 bash -c 'until curl -s http://localhost:3000/health; do sleep 2; done' - - - name: Start frontend - run: | - npm_config_yes=true npx serve -s packages/twenty-front/build -l 3001 & - echo "Waiting for frontend to be ready..." - timeout 60 bash -c 'until curl -s http://localhost:3001; do sleep 2; done' - - - name: Start worker - run: | - npx nx run twenty-server:worker & - echo "Worker started" - - - name: Run Playwright tests - run: npx nx test twenty-e2e-testing - - # - uses: actions/upload-artifact@v4 - # if: always() - # with: - # name: playwright-report - # path: packages/twenty-e2e-testing/run_results/ - # retention-days: 30 - ci-front-status-check: if: always() && !cancelled() timeout-minutes: 5 @@ -385,12 +263,3 @@ jobs: - name: Fail job if any needs failed if: contains(needs.*.result, 'failure') run: exit 1 - ci-e2e-status-check: - if: always() && !cancelled() - timeout-minutes: 5 - runs-on: ubuntu-latest - needs: [changed-files-check-e2e, e2e-test] - steps: - - name: Fail job if any needs failed - if: contains(needs.*.result, 'failure') - run: exit 1 diff --git a/.github/workflows/ci-merge-queue.yaml b/.github/workflows/ci-merge-queue.yaml new file mode 100644 index 00000000000..00ddb3e5434 --- /dev/null +++ b/.github/workflows/ci-merge-queue.yaml @@ -0,0 +1,118 @@ +name: CI Merge Queue + +on: + merge_group: + + pull_request: + types: [labeled, synchronize, opened, reopened] + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + e2e-test: + if: > + github.event_name == 'merge_group' || + (github.event_name == 'pull_request' && + contains(github.event.pull_request.labels.*.name, 'run-merge-queue')) + runs-on: ubuntu-latest-8-cores + timeout-minutes: 30 + env: + NODE_OPTIONS: "--max-old-space-size=10240" + services: + postgres: + image: twentycrm/twenty-postgres-spilo + env: + PGUSER_SUPERUSER: postgres + PGPASSWORD_SUPERUSER: postgres + ALLOW_NOSSL: "true" + SPILO_PROVIDER: "local" + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + redis: + image: redis + ports: + - 6379:6379 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 10 + + - uses: actions/setup-node@v4 + with: + node-version: lts/* + + - name: Install dependencies + uses: ./.github/actions/yarn-install + + - name: Build twenty-shared + run: npx nx build twenty-shared + + - name: Install Playwright Browsers + run: npx nx setup twenty-e2e-testing + + - name: Setup environment files + run: | + cp packages/twenty-front/.env.example packages/twenty-front/.env + npx nx reset:env:e2e-testing-server twenty-server + + - name: Build frontend + run: NODE_ENV=production npx nx build twenty-front + + - name: Build server + run: npx nx build twenty-server + + - name: Create and setup database + run: | + PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d postgres -c 'CREATE DATABASE "default";' + PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d postgres -c 'CREATE DATABASE "test";' + npx nx run twenty-server:database:reset + + - name: Start server + run: | + npx nx start twenty-server & + echo "Waiting for server to be ready..." + timeout 60 bash -c 'until curl -s http://localhost:3000/health; do sleep 2; done' + + - name: Start frontend + run: | + npm_config_yes=true npx serve -s packages/twenty-front/build -l 3001 & + echo "Waiting for frontend to be ready..." + timeout 60 bash -c 'until curl -s http://localhost:3001; do sleep 2; done' + + - name: Start worker + run: | + npx nx run twenty-server:worker & + echo "Worker started" + + - name: Run Playwright tests + run: npx nx test twenty-e2e-testing + + - name: Upload Playwright results + if: always() + uses: actions/upload-artifact@v4 + with: + name: playwright-results + path: | + packages/twenty-e2e-testing/run_results/ + packages/twenty-e2e-testing/test-results/ + retention-days: 7 + + ci-merge-queue-status-check: + if: always() && !cancelled() + timeout-minutes: 5 + runs-on: ubuntu-latest + needs: [e2e-test] + steps: + - name: Fail job if any needs failed + if: contains(needs.*.result, 'failure') + run: exit 1 diff --git a/.github/workflows/ci-sdk.yaml b/.github/workflows/ci-sdk.yaml index 8dbe21580c4..d8a1cc7acd1 100644 --- a/.github/workflows/ci-sdk.yaml +++ b/.github/workflows/ci-sdk.yaml @@ -1,8 +1,6 @@ name: CI SDK on: - merge_group: - pull_request: permissions: diff --git a/.github/workflows/ci-server.yaml b/.github/workflows/ci-server.yaml index 179e8a89f8a..e88ea91085c 100644 --- a/.github/workflows/ci-server.yaml +++ b/.github/workflows/ci-server.yaml @@ -3,8 +3,6 @@ name: CI Server on: pull_request: - merge_group: - permissions: contents: read diff --git a/.github/workflows/ci-shared.yaml b/.github/workflows/ci-shared.yaml index 7ce6143fa5c..313fc937467 100644 --- a/.github/workflows/ci-shared.yaml +++ b/.github/workflows/ci-shared.yaml @@ -1,8 +1,6 @@ name: CI Shared on: - merge_group: - pull_request: permissions: diff --git a/.github/workflows/ci-test-docker-compose.yaml b/.github/workflows/ci-test-docker-compose.yaml index 419d440beea..1b4309b9393 100644 --- a/.github/workflows/ci-test-docker-compose.yaml +++ b/.github/workflows/ci-test-docker-compose.yaml @@ -4,8 +4,6 @@ permissions: contents: read on: - merge_group: - pull_request: concurrency: diff --git a/.github/workflows/ci-website.yaml b/.github/workflows/ci-website.yaml index 28740a9aac4..712f97ded27 100644 --- a/.github/workflows/ci-website.yaml +++ b/.github/workflows/ci-website.yaml @@ -4,8 +4,6 @@ permissions: contents: read on: - merge_group: - pull_request: concurrency: diff --git a/.github/workflows/ci-zapier.yaml b/.github/workflows/ci-zapier.yaml index 7e9517a8d1c..05c2004a34c 100644 --- a/.github/workflows/ci-zapier.yaml +++ b/.github/workflows/ci-zapier.yaml @@ -3,8 +3,6 @@ name: CI Zapier on: pull_request: - merge_group: - permissions: contents: read diff --git a/nx.json b/nx.json index 130305732b9..9a501358839 100644 --- a/nx.json +++ b/nx.json @@ -44,12 +44,12 @@ "cache": true, "options": { "cwd": "{projectRoot}", - "command": "npx oxlint -c .oxlintrc.json ." + "command": "npx oxlint -c .oxlintrc.json . && (prettier . --check --cache --cache-location ../../.cache/prettier/{projectRoot} --cache-strategy metadata || (echo 'ERROR: Prettier formatting check failed! Fix with: npx nx lint --configuration=fix' && false))" }, "configurations": { "ci": {}, "fix": { - "command": "npx oxlint --fix -c .oxlintrc.json ." + "command": "npx oxlint --fix -c .oxlintrc.json . && prettier . --write --cache --cache-location ../../.cache/prettier/{projectRoot} --cache-strategy metadata" } }, "dependsOn": ["^build", "twenty-oxlint-rules:build"] @@ -58,12 +58,12 @@ "executor": "nx:run-commands", "cache": false, "options": { - "command": "FILES=$(git diff --name-only --diff-filter=d main -- {projectRoot}/ | grep -E '{args.pattern}'); [ -z \"$FILES\" ] && echo 'No changed files.' || npx oxlint -c {projectRoot}/.oxlintrc.json $FILES", + "command": "FILES=$(git diff --name-only --diff-filter=d main -- {projectRoot}/ | grep -E '{args.pattern}'); [ -z \"$FILES\" ] && echo 'No changed files.' || (npx oxlint -c {projectRoot}/.oxlintrc.json $FILES && (prettier --check $FILES || (echo 'ERROR: Prettier formatting check failed! Fix with: npx nx lint:diff-with-main --configuration=fix' && false)))", "pattern": "\\.(ts|tsx|js|jsx)$" }, "configurations": { "fix": { - "command": "FILES=$(git diff --name-only --diff-filter=d main -- {projectRoot}/ | grep -E '{args.pattern}'); [ -z \"$FILES\" ] && echo 'No changed files.' || npx oxlint --fix -c {projectRoot}/.oxlintrc.json $FILES" + "command": "FILES=$(git diff --name-only --diff-filter=d main -- {projectRoot}/ | grep -E '{args.pattern}'); [ -z \"$FILES\" ] && echo 'No changed files.' || (npx oxlint --fix -c {projectRoot}/.oxlintrc.json $FILES && prettier --write $FILES)" } } }, diff --git a/packages/create-twenty-app/.oxlintrc.json b/packages/create-twenty-app/.oxlintrc.json index bdd923728ac..9ca5cc67d45 100644 --- a/packages/create-twenty-app/.oxlintrc.json +++ b/packages/create-twenty-app/.oxlintrc.json @@ -17,22 +17,31 @@ "import/no-duplicates": "error", "typescript/no-redeclare": "error", "typescript/ban-ts-comment": "error", - "typescript/consistent-type-imports": ["error", { - "prefer": "type-imports", - "fixStyle": "inline-type-imports" - }], + "typescript/consistent-type-imports": [ + "error", + { + "prefer": "type-imports", + "fixStyle": "inline-type-imports" + } + ], "typescript/explicit-function-return-type": "off", "typescript/explicit-module-boundary-types": "off", - "typescript/no-empty-object-type": ["error", { - "allowInterfaces": "with-single-extends" - }], + "typescript/no-empty-object-type": [ + "error", + { + "allowInterfaces": "with-single-extends" + } + ], "typescript/no-empty-function": "off", "typescript/no-explicit-any": "off", - "typescript/no-unused-vars": ["warn", { - "vars": "all", - "varsIgnorePattern": "^_", - "args": "after-used", - "argsIgnorePattern": "^_" - }] + "typescript/no-unused-vars": [ + "warn", + { + "vars": "all", + "varsIgnorePattern": "^_", + "args": "after-used", + "argsIgnorePattern": "^_" + } + ] } } diff --git a/packages/create-twenty-app/.prettierignore b/packages/create-twenty-app/.prettierignore new file mode 100644 index 00000000000..1521c8b7652 --- /dev/null +++ b/packages/create-twenty-app/.prettierignore @@ -0,0 +1 @@ +dist diff --git a/packages/create-twenty-app/README.md b/packages/create-twenty-app/README.md index dc41dc2e347..23ee234b50a 100644 --- a/packages/create-twenty-app/README.md +++ b/packages/create-twenty-app/README.md @@ -19,9 +19,11 @@ Create Twenty App is the official scaffolding CLI for building apps on top of [T - Strong TypeScript support and typed client generation ## Documentation + See Twenty application documentation https://docs.twenty.com/developers/extend/capabilities/apps ## Prerequisites + - Node.js 24+ (recommended) and Yarn 4 - A Twenty workspace and an API key (create one at https://app.twenty.com/settings/api-webhooks) @@ -64,11 +66,11 @@ yarn twenty app:uninstall Control which example files are included when creating a new app: -| Flag | Behavior | -|------|----------| -| `-e, --exhaustive` | **(default)** Creates all example files without prompting | -| `-m, --minimal` | Creates only core files (`application-config.ts` and `default-role.ts`) | -| `-i, --interactive` | Prompts you to select which examples to include | +| Flag | Behavior | +| ------------------- | ----------------------------------------------------------------------- | +| `-e, --exhaustive` | **(default)** Creates all example files without prompting | +| `-m, --minimal` | Creates only core files (`application-config.ts` and `default-role.ts`) | +| `-i, --interactive` | Prompts you to select which examples to include | ```bash # Default: all examples included @@ -82,6 +84,7 @@ npx create-twenty-app@latest my-app -i ``` In interactive mode, you can pick from: + - **Example object** — a custom CRM object definition (`objects/example-object.ts`) - **Example field** — a custom field on the example object (`fields/example-field.ts`) - **Example logic function** — a server-side handler with HTTP trigger (`logic-functions/hello-world.ts`) @@ -94,6 +97,7 @@ In interactive mode, you can pick from: ## What gets scaffolded **Core files (always created):** + - `application-config.ts` — Application metadata configuration - `roles/default-role.ts` — Default role for logic functions - `logic-functions/pre-install.ts` — Pre-install logic function (runs before app installation) @@ -102,6 +106,7 @@ In interactive mode, you can pick from: - A prewired `twenty` script that delegates to the `twenty` CLI from twenty-sdk **Example files (controlled by scaffolding mode):** + - `objects/example-object.ts` — Example custom object with a text field - `fields/example-field.ts` — Example standalone field extending the example object - `logic-functions/hello-world.ts` — Example logic function with HTTP trigger @@ -112,14 +117,15 @@ In interactive mode, you can pick from: - `__tests__/app-install.integration-test.ts` — Integration test that builds, installs, and verifies the app (includes `vitest.config.ts`, `tsconfig.spec.json`, and a setup file) ## Next steps + - Run `yarn twenty help` to see all available commands. - Use `yarn twenty auth:login` to authenticate with your Twenty workspace. - Explore the generated project and add your first entity with `yarn twenty entity:add` (logic functions, front components, objects, roles, views, navigation menu items, skills). - Use `yarn twenty app:dev` while you iterate — it watches, builds, and syncs changes to your workspace in real time. - Two typed API clients are auto‑generated by `yarn twenty app:dev` and stored in `node_modules/twenty-sdk/generated`: `CoreApiClient` (for workspace data via `/graphql`) and `MetadataApiClient` (for workspace configuration and file uploads via `/metadata`). - ## Publish your application + Applications are currently stored in `twenty/packages/twenty-apps`. You can share your application with all Twenty users: @@ -144,9 +150,11 @@ git push Our team reviews contributions for quality, security, and reusability before merging. ## Troubleshooting + - Auth prompts not appearing: run `yarn twenty auth:login` again and verify the API key permissions. - Types not generated: ensure `yarn twenty app:dev` is running — it auto‑generates the typed client. ## Contributing + - See our [GitHub](https://github.com/twentyhq/twenty) - Join our [Discord](https://discord.gg/cx5n4Jzs57) diff --git a/packages/create-twenty-app/src/constants/base-application/.oxlintrc.json b/packages/create-twenty-app/src/constants/base-application/.oxlintrc.json index d2a673cd1ad..87c62c51832 100644 --- a/packages/create-twenty-app/src/constants/base-application/.oxlintrc.json +++ b/packages/create-twenty-app/src/constants/base-application/.oxlintrc.json @@ -8,9 +8,12 @@ "rules": { "no-unused-vars": "off", - "typescript/no-unused-vars": ["warn", { - "argsIgnorePattern": "^_" - }], + "typescript/no-unused-vars": [ + "warn", + { + "argsIgnorePattern": "^_" + } + ], "typescript/no-explicit-any": "off" } } diff --git a/packages/create-twenty-app/src/constants/base-application/LLMS.md b/packages/create-twenty-app/src/constants/base-application/LLMS.md index 38afd91745d..e4c582d1f3c 100644 --- a/packages/create-twenty-app/src/constants/base-application/LLMS.md +++ b/packages/create-twenty-app/src/constants/base-application/LLMS.md @@ -4,6 +4,7 @@ - Rich app example: https://github.com/twentyhq/twenty/tree/main/packages/twenty-sdk/src/cli/__tests__/apps/rich-app ## UUID requirement + - All generated UUIDs must be valid UUID v4. ## Common Pitfalls diff --git a/packages/create-twenty-app/src/constants/base-application/tsconfig.json b/packages/create-twenty-app/src/constants/base-application/tsconfig.json index 6ee3fc81e13..de962867325 100644 --- a/packages/create-twenty-app/src/constants/base-application/tsconfig.json +++ b/packages/create-twenty-app/src/constants/base-application/tsconfig.json @@ -27,5 +27,11 @@ "~/*": ["./*"] } }, - "exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts", "**/*.integration-test.ts"] + "exclude": [ + "node_modules", + "dist", + "**/*.test.ts", + "**/*.spec.ts", + "**/*.integration-test.ts" + ] } diff --git a/packages/create-twenty-app/tsconfig.json b/packages/create-twenty-app/tsconfig.json index c7efa26bf77..fc85ffd6d61 100644 --- a/packages/create-twenty-app/tsconfig.json +++ b/packages/create-twenty-app/tsconfig.json @@ -24,7 +24,5 @@ "vite.config.ts", "jest.config.mjs" ], - "exclude": [ - "src/constants/base-application/vitest.config.ts" - ] + "exclude": ["src/constants/base-application/vitest.config.ts"] } diff --git a/packages/twenty-e2e-testing/lib/pom/loginPage.ts b/packages/twenty-e2e-testing/lib/pom/loginPage.ts index 9d5f8551226..ccd1ab22efc 100644 --- a/packages/twenty-e2e-testing/lib/pom/loginPage.ts +++ b/packages/twenty-e2e-testing/lib/pom/loginPage.ts @@ -87,7 +87,7 @@ export class LoginPage { async clickLoginWithEmailIfVisible() { try { - await this.loginWithEmailButton.click(); + await this.loginWithEmailButton.click({ timeout: 3000 }); } catch { // Button not found - email field might already be visible (SSO-only or different auth flow) } diff --git a/packages/twenty-e2e-testing/tests/authentication/signup_invite_email.spec.ts b/packages/twenty-e2e-testing/tests/authentication/signup_invite_email.spec.ts index 92f228880d9..884fd556a50 100644 --- a/packages/twenty-e2e-testing/tests/authentication/signup_invite_email.spec.ts +++ b/packages/twenty-e2e-testing/tests/authentication/signup_invite_email.spec.ts @@ -34,7 +34,7 @@ test('Sign up with invite link via email', async ({ }); await test.step('Create new account', async () => { - await loginPage.clickLoginWithEmail(); + await loginPage.clickLoginWithEmailIfVisible(); await loginPage.typeEmail(email); await loginPage.clickContinueButton(); await loginPage.typePassword(process.env.DEFAULT_PASSWORD); diff --git a/packages/twenty-e2e-testing/tests/workflow-creation.spec.ts b/packages/twenty-e2e-testing/tests/workflow-creation.spec.ts index 76cd993c0ae..9b88250e403 100644 --- a/packages/twenty-e2e-testing/tests/workflow-creation.spec.ts +++ b/packages/twenty-e2e-testing/tests/workflow-creation.spec.ts @@ -34,10 +34,7 @@ test('Create workflow', async ({ page }) => { const recordName = page.getByTestId('top-bar-title').getByPlaceholder('Name'); await expect(recordName).toBeVisible(); - await recordName.click(); - - const nameInput = page.getByTestId('top-bar-title').getByRole('textbox'); - await nameInput.fill(NEW_WORKFLOW_NAME); + await recordName.fill(NEW_WORKFLOW_NAME); const workflowDiagramContainer = page.locator('.react-flow__renderer'); await workflowDiagramContainer.click(); diff --git a/packages/twenty-emails/.oxlintrc.json b/packages/twenty-emails/.oxlintrc.json index ef6ce29bcc8..9eb4a5b1847 100644 --- a/packages/twenty-emails/.oxlintrc.json +++ b/packages/twenty-emails/.oxlintrc.json @@ -5,12 +5,13 @@ "categories": { "correctness": "off" }, - "ignorePatterns": [ - "node_modules" - ], + "ignorePatterns": ["node_modules"], "rules": { "func-style": ["error", "declaration", { "allowArrowFunctions": true }], - "no-console": ["warn", { "allow": ["group", "groupCollapsed", "groupEnd"] }], + "no-console": [ + "warn", + { "allow": ["group", "groupCollapsed", "groupEnd"] } + ], "no-control-regex": "off", "no-debugger": "error", "no-duplicate-imports": "error", @@ -34,31 +35,43 @@ "typescript/no-redeclare": "error", "typescript/ban-ts-comment": "error", - "typescript/consistent-type-imports": ["error", { - "prefer": "type-imports", - "fixStyle": "inline-type-imports" - }], + "typescript/consistent-type-imports": [ + "error", + { + "prefer": "type-imports", + "fixStyle": "inline-type-imports" + } + ], "typescript/explicit-function-return-type": "off", "typescript/explicit-module-boundary-types": "off", - "typescript/no-empty-object-type": ["error", { - "allowInterfaces": "with-single-extends" - }], + "typescript/no-empty-object-type": [ + "error", + { + "allowInterfaces": "with-single-extends" + } + ], "typescript/no-empty-function": "off", "typescript/no-explicit-any": "off", - "typescript/no-unused-vars": ["warn", { - "vars": "all", - "varsIgnorePattern": "^_", - "args": "after-used", - "argsIgnorePattern": "^_" - }], + "typescript/no-unused-vars": [ + "warn", + { + "vars": "all", + "varsIgnorePattern": "^_", + "args": "after-used", + "argsIgnorePattern": "^_" + } + ], - "twenty/enforce-module-boundaries": ["error", { - "depConstraints": [ - { - "sourceTag": "scope:backend", - "onlyDependOnLibsWithTags": ["scope:shared", "scope:backend"] - } - ] - }] + "twenty/enforce-module-boundaries": [ + "error", + { + "depConstraints": [ + { + "sourceTag": "scope:backend", + "onlyDependOnLibsWithTags": ["scope:shared", "scope:backend"] + } + ] + } + ] } } diff --git a/packages/twenty-emails/.prettierignore b/packages/twenty-emails/.prettierignore new file mode 100644 index 00000000000..23c4124138d --- /dev/null +++ b/packages/twenty-emails/.prettierignore @@ -0,0 +1 @@ +src/locales/generated diff --git a/packages/twenty-emails/.swcrc b/packages/twenty-emails/.swcrc index 7027d91372e..9d14a2f1380 100644 --- a/packages/twenty-emails/.swcrc +++ b/packages/twenty-emails/.swcrc @@ -5,12 +5,12 @@ "plugins": [ [ "@lingui/swc-plugin", - { - "runtimeModules": { - "i18n": ["@lingui/core", "i18n"], - "trans": ["@lingui/react", "Trans"] - }, - "stripNonEssentialFields": false + { + "runtimeModules": { + "i18n": ["@lingui/core", "i18n"], + "trans": ["@lingui/react", "Trans"] + }, + "stripNonEssentialFields": false } ] ] diff --git a/packages/twenty-emails/tsconfig.json b/packages/twenty-emails/tsconfig.json index 03000a6d4fb..62058d28fe4 100644 --- a/packages/twenty-emails/tsconfig.json +++ b/packages/twenty-emails/tsconfig.json @@ -13,9 +13,5 @@ "src/*": ["./src/*"] } }, - "include": [ - "src/**/*.ts", - "src/**/*.tsx", - "vite.config.ts" - ] + "include": ["src/**/*.ts", "src/**/*.tsx", "vite.config.ts"] } diff --git a/packages/twenty-emails/tsconfig.lib.json b/packages/twenty-emails/tsconfig.lib.json index 9921075dc60..b4cd3b134ee 100644 --- a/packages/twenty-emails/tsconfig.lib.json +++ b/packages/twenty-emails/tsconfig.lib.json @@ -7,10 +7,5 @@ "types": ["node", "@nx/react/typings/image.d.ts", "vite/client"] }, "include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"], - "exclude": [ - "**/*.spec.ts", - "**/*.test.ts", - "**/*.spec.tsx", - "**/*.test.tsx" - ] + "exclude": ["**/*.spec.ts", "**/*.test.ts", "**/*.spec.tsx", "**/*.test.tsx"] } diff --git a/packages/twenty-front/.prettierignore b/packages/twenty-front/.prettierignore index 3cd786f417b..ef2c8ca903b 100644 --- a/packages/twenty-front/.prettierignore +++ b/packages/twenty-front/.prettierignore @@ -1,3 +1,4 @@ src/generated src/generated-metadata +src/locales/generated src/testing/mock-data/generated \ No newline at end of file diff --git a/packages/twenty-front/project.json b/packages/twenty-front/project.json index 70cacd59bd0..e48030ff4f5 100644 --- a/packages/twenty-front/project.json +++ b/packages/twenty-front/project.json @@ -77,11 +77,11 @@ ], "options": { "cwd": "{projectRoot}", - "command": "npx oxlint --type-aware -c .oxlintrc.json src/" + "command": "npx oxlint --type-aware -c .oxlintrc.json src/ && (prettier src/ --check --cache --cache-location ../../.cache/prettier/{projectRoot} --cache-strategy metadata || (echo 'ERROR: Prettier formatting check failed! Fix with: npx nx lint twenty-front --configuration=fix' && false))" }, "configurations": { "fix": { - "command": "npx oxlint --type-aware --fix -c .oxlintrc.json src/" + "command": "npx oxlint --type-aware --fix -c .oxlintrc.json src/ && prettier src/ --write --cache --cache-location ../../.cache/prettier/{projectRoot} --cache-strategy metadata" } } }, @@ -89,11 +89,11 @@ "executor": "nx:run-commands", "options": { "cwd": "{projectRoot}", - "command": "FILES=$(git diff --name-only --diff-filter=d main...HEAD -- src/ | grep -E '\\.(ts|tsx)$'); [ -z \"$FILES\" ] && echo 'No changed files.' || npx oxlint --type-aware -c .oxlintrc.json $FILES" + "command": "FILES=$(git diff --name-only --diff-filter=d main...HEAD -- src/ | grep -E '\\.(ts|tsx)$'); [ -z \"$FILES\" ] && echo 'No changed files.' || (npx oxlint --type-aware -c .oxlintrc.json $FILES && (prettier --check $FILES || (echo 'ERROR: Prettier formatting check failed! Fix with: npx nx lint:diff-with-main twenty-front --configuration=fix' && false)))" }, "configurations": { "fix": { - "command": "FILES=$(git diff --name-only --diff-filter=d main...HEAD -- src/ | grep -E '\\.(ts|tsx)$'); [ -z \"$FILES\" ] && echo 'No changed files.' || npx oxlint --type-aware --fix -c .oxlintrc.json $FILES" + "command": "FILES=$(git diff --name-only --diff-filter=d main...HEAD -- src/ | grep -E '\\.(ts|tsx)$'); [ -z \"$FILES\" ] && echo 'No changed files.' || (npx oxlint --type-aware --fix -c .oxlintrc.json $FILES && prettier --write $FILES)" } } }, diff --git a/packages/twenty-front/src/modules/activities/timeline-activities/components/TimelineCard.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/components/TimelineCard.tsx index 5ea608e841d..37e866e7a31 100644 --- a/packages/twenty-front/src/modules/activities/timeline-activities/components/TimelineCard.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/components/TimelineCard.tsx @@ -51,8 +51,7 @@ export const TimelineCard = () => { const { timelineActivities, loading, fetchMoreRecords } = useTimelineActivities(targetRecord); - const isTimelineActivitiesEmpty = - timelineActivities.length === 0; + const isTimelineActivitiesEmpty = timelineActivities.length === 0; if (loading === true) { return ; diff --git a/packages/twenty-front/src/modules/activities/utils/getActivityTargetObjectRecords.ts b/packages/twenty-front/src/modules/activities/utils/getActivityTargetObjectRecords.ts index 75485ce35b2..98d2f001a08 100644 --- a/packages/twenty-front/src/modules/activities/utils/getActivityTargetObjectRecords.ts +++ b/packages/twenty-front/src/modules/activities/utils/getActivityTargetObjectRecords.ts @@ -31,11 +31,9 @@ export const getActivityTargetObjectRecords = ({ const targets = activityTargets ? activityTargets - : 'noteTargets' in activityRecord && - isDefined(activityRecord.noteTargets) + : 'noteTargets' in activityRecord && isDefined(activityRecord.noteTargets) ? activityRecord.noteTargets - : 'taskTargets' in activityRecord && - isDefined(activityRecord.taskTargets) + : 'taskTargets' in activityRecord && isDefined(activityRecord.taskTargets) ? activityRecord.taskTargets : []; diff --git a/packages/twenty-front/src/modules/ai/components/RoutingStatusDisplay.tsx b/packages/twenty-front/src/modules/ai/components/RoutingStatusDisplay.tsx index a422717f4c0..5bb1734062a 100644 --- a/packages/twenty-front/src/modules/ai/components/RoutingStatusDisplay.tsx +++ b/packages/twenty-front/src/modules/ai/components/RoutingStatusDisplay.tsx @@ -66,7 +66,8 @@ export const RoutingStatusDisplay = ({ const [isExpanded, setIsExpanded] = useState(false); const isLoading = data.state === 'loading'; const isDebugMode = process.env.IS_DEBUG_MODE === 'true'; - const isExpandable = isDebugMode && data.state === 'routed' && isDefined(data.debug); + const isExpandable = + isDebugMode && data.state === 'routed' && isDefined(data.debug); if (data.state === 'error') { return null; diff --git a/packages/twenty-front/src/modules/app/hooks/useCreateAppRouter.tsx b/packages/twenty-front/src/modules/app/hooks/useCreateAppRouter.tsx index e10da34e831..9f77653333a 100644 --- a/packages/twenty-front/src/modules/app/hooks/useCreateAppRouter.tsx +++ b/packages/twenty-front/src/modules/app/hooks/useCreateAppRouter.tsx @@ -117,56 +117,108 @@ export const useCreateAppRouter = ( } /> } + element={ + + + + } /> } + element={ + + + + } /> } + element={ + + + + } /> } + element={ + + + + } /> } + element={ + + + + } /> } + element={ + + + + } /> } + element={ + + + + } /> } + element={ + + + + } /> } + element={ + + + + } /> } + element={ + + + + } /> } + element={ + + + + } /> >} /> } + element={ + + + + } /> } + element={ + + + + } /> } + element={ + + + + } /> }> } + element={ + + + + } /> , diff --git a/packages/twenty-front/src/modules/billing/components/internal/MeteredPriceSelector.tsx b/packages/twenty-front/src/modules/billing/components/internal/MeteredPriceSelector.tsx index a0f04e565e7..6baf4a75ccd 100644 --- a/packages/twenty-front/src/modules/billing/components/internal/MeteredPriceSelector.tsx +++ b/packages/twenty-front/src/modules/billing/components/internal/MeteredPriceSelector.tsx @@ -97,7 +97,12 @@ export const MeteredPriceSelector = ({ selectedPriceId !== currentMeteredPrice?.stripePriceId; const isUpgrade = () => { - if (!isChanged || !isDefined(selectedPrice) || !isDefined(currentMeteredPrice)) return false; + if ( + !isChanged || + !isDefined(selectedPrice) || + !isDefined(currentMeteredPrice) + ) + return false; return ( (selectedPrice.tiers as BillingPriceTiers)[0].flatAmount > (currentMeteredPrice.tiers as BillingPriceTiers)[0].flatAmount diff --git a/packages/twenty-front/src/modules/favorites/favorite-folder-picker/components/FavoriteFolderPickerEffect.tsx b/packages/twenty-front/src/modules/favorites/favorite-folder-picker/components/FavoriteFolderPickerEffect.tsx index 3c243b717b7..88688ead3ac 100644 --- a/packages/twenty-front/src/modules/favorites/favorite-folder-picker/components/FavoriteFolderPickerEffect.tsx +++ b/packages/twenty-front/src/modules/favorites/favorite-folder-picker/components/FavoriteFolderPickerEffect.tsx @@ -72,7 +72,7 @@ export const FavoriteFolderPickerEffect = ({ .filter( (favorite) => favorite.recordId === targetId && - isDefined(favorite.forWorkspaceMemberId), + isDefined(favorite.forWorkspaceMemberId), ) .map((favorite) => favorite.favoriteFolderId ?? 'no-folder'); setFavoriteFolderPickerChecked(checkedFolderIds); diff --git a/packages/twenty-front/src/modules/mention/hooks/useMentionSearch.ts b/packages/twenty-front/src/modules/mention/hooks/useMentionSearch.ts index 35fef69b6ce..9b54038cd82 100644 --- a/packages/twenty-front/src/modules/mention/hooks/useMentionSearch.ts +++ b/packages/twenty-front/src/modules/mention/hooks/useMentionSearch.ts @@ -50,8 +50,7 @@ export const useMentionSearch = () => { }, }); - const searchRecords = - data?.search.edges.map((edge) => edge.node) ?? []; + const searchRecords = data?.search.edges.map((edge) => edge.node) ?? []; return searchRecords.map((searchRecord) => ({ recordId: searchRecord.recordId, diff --git a/packages/twenty-front/src/modules/object-record/hooks/useFindOneRecord.ts b/packages/twenty-front/src/modules/object-record/hooks/useFindOneRecord.ts index 6bffed369f9..a37554b6a06 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useFindOneRecord.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useFindOneRecord.ts @@ -56,7 +56,11 @@ export const useFindOneRecord = ({ const { data, loading, error, refetch } = useQuery<{ [nameSingular: string]: RecordGqlNode; }>(findOneRecordQuery, { - skip: !isDefined(objectMetadataItem) || !objectRecordId || skip || !hasReadPermission, + skip: + !isDefined(objectMetadataItem) || + !objectRecordId || + skip || + !hasReadPermission, variables: { objectRecordId }, client: apolloCoreClient, onCompleted: (data) => { diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableVirtualizedInitialDataLoadEffect.tsx b/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableVirtualizedInitialDataLoadEffect.tsx index 0fd817c64b7..8762406ac22 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableVirtualizedInitialDataLoadEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableVirtualizedInitialDataLoadEffect.tsx @@ -93,8 +93,7 @@ export const RecordTableVirtualizedInitialDataLoadEffect = () => { JSON.stringify(lastContextStoreVirtualizedVisibleRecordFields) !== JSON.stringify(visibleRecordFields) ) { - const lastFields = - lastContextStoreVirtualizedVisibleRecordFields ?? []; + const lastFields = lastContextStoreVirtualizedVisibleRecordFields ?? []; const currentFields = visibleRecordFields ?? []; setLastContextStoreVirtualizedVisibleRecordFields(visibleRecordFields); diff --git a/packages/twenty-front/src/modules/settings/components/SettingsOptions/SettingsOptionCardContentButton.tsx b/packages/twenty-front/src/modules/settings/components/SettingsOptions/SettingsOptionCardContentButton.tsx index 8320d83a228..ab7baa95506 100644 --- a/packages/twenty-front/src/modules/settings/components/SettingsOptions/SettingsOptionCardContentButton.tsx +++ b/packages/twenty-front/src/modules/settings/components/SettingsOptions/SettingsOptionCardContentButton.tsx @@ -48,7 +48,9 @@ export const SettingsOptionCardContentButton = ({ )} - {isDefined(Button) && {Button}} + {isDefined(Button) && ( + {Button} + )} ); }; diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelPermissionMeValueSelect.tsx b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelPermissionMeValueSelect.tsx index 6d4639f14d2..100e3c92152 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelPermissionMeValueSelect.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelPermissionMeValueSelect.tsx @@ -110,7 +110,9 @@ export const SettingsRolePermissionsObjectLevelRecordLevelPermissionMeValueSelec } } - const compatibleWorkspaceMemberFields = !isDefined(workspaceMemberMetadataItem) + const compatibleWorkspaceMemberFields = !isDefined( + workspaceMemberMetadataItem, + ) ? [] : workspaceMemberMetadataItem.fields.filter((field) => { if ( diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/SubMatchingSelectInput.tsx b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/SubMatchingSelectInput.tsx index d41b36c872e..82ff952671a 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/SubMatchingSelectInput.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/SubMatchingSelectInput.tsx @@ -28,14 +28,12 @@ export const SubMatchingSelectInput = ({ const optionsToSelect = useMemo(() => { const searchTerm = normalizeSearchText(searchFilter); - return ( - options.filter((option) => { - return ( - option.value !== selectedOption?.value && - normalizeSearchText(option.label).includes(searchTerm) - ); - }) - ); + return options.filter((option) => { + return ( + option.value !== selectedOption?.value && + normalizeSearchText(option.label).includes(searchTerm) + ); + }); }, [options, searchFilter, selectedOption?.value]); const optionsInDropDown = useMemo( diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/ValidationStep/ValidationStep.tsx b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/ValidationStep/ValidationStep.tsx index 14c72a902e3..a4be5481002 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/ValidationStep/ValidationStep.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/ValidationStep/ValidationStep.tsx @@ -206,11 +206,11 @@ export const ValidationStep = ({ if (filterByErrors) { return data.filter((value) => { if (isDefined(value?.__errors)) { - return ( - (Object.values(value.__errors)?.filter( - (err) => err.level === 'error', - ).length ?? 0) > 0 - ); + return ( + (Object.values(value.__errors)?.filter( + (err) => err.level === 'error', + ).length ?? 0) > 0 + ); } return false; }); diff --git a/packages/twenty-front/src/modules/ui/input/components/SelectInput.tsx b/packages/twenty-front/src/modules/ui/input/components/SelectInput.tsx index 419ac32e0d7..982bc3d8238 100644 --- a/packages/twenty-front/src/modules/ui/input/components/SelectInput.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/SelectInput.tsx @@ -58,14 +58,12 @@ export const SelectInput = ({ const optionsToSelect = useMemo(() => { const searchTerm = normalizeSearchText(searchFilter); - return ( - options.filter((option) => { - return ( - option.value !== selectedOption?.value && - normalizeSearchText(option.label).includes(searchTerm) - ); - }) - ); + return options.filter((option) => { + return ( + option.value !== selectedOption?.value && + normalizeSearchText(option.label).includes(searchTerm) + ); + }); }, [options, searchFilter, selectedOption?.value]); const optionsInDropDown = useMemo( diff --git a/packages/twenty-front/src/modules/ui/theme/hooks/useSystemColorScheme.ts b/packages/twenty-front/src/modules/ui/theme/hooks/useSystemColorScheme.ts index 115c1a6d7ae..26420a8e711 100644 --- a/packages/twenty-front/src/modules/ui/theme/hooks/useSystemColorScheme.ts +++ b/packages/twenty-front/src/modules/ui/theme/hooks/useSystemColorScheme.ts @@ -10,7 +10,9 @@ export const useSystemColorScheme = (): ColorScheme => { ); const [preferredColorScheme, setPreferredColorScheme] = useState( - isUndefinedOrNull(window.matchMedia) || !mediaQuery.matches ? 'Light' : 'Dark', + isUndefinedOrNull(window.matchMedia) || !mediaQuery.matches + ? 'Light' + : 'Dark', ); useEffect(() => { diff --git a/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerOptionDropdown.tsx b/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerOptionDropdown.tsx index 613a83a2202..d50a9e07ed8 100644 --- a/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerOptionDropdown.tsx +++ b/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerOptionDropdown.tsx @@ -83,7 +83,7 @@ export const ViewPickerOptionDropdown = ({ : favorites.some( (favorite) => favorite.recordId === view.id && - isDefined(favorite.forWorkspaceMemberId), + isDefined(favorite.forWorkspaceMemberId), ); const handleDelete = () => { diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/components/WorkflowStepFilterValueInput.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/components/WorkflowStepFilterValueInput.tsx index 8a3c1835298..0b721f278ab 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/components/WorkflowStepFilterValueInput.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/components/WorkflowStepFilterValueInput.tsx @@ -116,7 +116,8 @@ export const WorkflowStepFilterValueInput = ({ const isDisabled = !stepFilter.operand; const operandHasNoInput = - (isDefined(stepFilter) && !configurableViewFilterOperands.has(stepFilter.operand)) ?? + (isDefined(stepFilter) && + !configurableViewFilterOperands.has(stepFilter.operand)) ?? true; const { diff --git a/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerDatabaseEventForm.tsx b/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerDatabaseEventForm.tsx index 3db99dc0366..619ca8155fb 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerDatabaseEventForm.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerDatabaseEventForm.tsx @@ -144,7 +144,11 @@ export const WorkflowEditTriggerDatabaseEventForm = ({ ...trigger, settings: { ...trigger.settings, - fields: isDefined(fields) ? (Array.isArray(fields) ? fields : [fields]) : null, + fields: isDefined(fields) + ? Array.isArray(fields) + ? fields + : [fields] + : null, }, }); }; diff --git a/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerManual.tsx b/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerManual.tsx index 678e1440733..1f052b00a83 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerManual.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerManual.tsx @@ -121,7 +121,10 @@ export const WorkflowEditTriggerManual = ({ options={availableMetadata} disabled={triggerOptions.readonly} onChange={(objectNameSingular) => { - if (triggerOptions.readonly === true || !isDefined(availability)) { + if ( + triggerOptions.readonly === true || + !isDefined(availability) + ) { return; } diff --git a/packages/twenty-front/src/pages/settings/data-model/hooks/useMapFieldMetadataItemToSettingsObjectDetailTableItem.ts b/packages/twenty-front/src/pages/settings/data-model/hooks/useMapFieldMetadataItemToSettingsObjectDetailTableItem.ts index b7f2d3f2f7d..9070e46bc55 100644 --- a/packages/twenty-front/src/pages/settings/data-model/hooks/useMapFieldMetadataItemToSettingsObjectDetailTableItem.ts +++ b/packages/twenty-front/src/pages/settings/data-model/hooks/useMapFieldMetadataItemToSettingsObjectDetailTableItem.ts @@ -39,8 +39,8 @@ export const useMapFieldMetadataItemToSettingsObjectDetailTableItem = ( fieldMetadataItem, fieldType: fieldType ?? '', dataType: - (isDefined(relationObjectMetadataItem?.labelPlural) || - isFieldTypeSupportedInSettings(fieldMetadataType)) + isDefined(relationObjectMetadataItem?.labelPlural) || + isFieldTypeSupportedInSettings(fieldMetadataType) ? getSettingsFieldTypeConfig(fieldMetadataType as SettingsFieldType) ?.label : '', diff --git a/packages/twenty-oxlint-rules/package.json b/packages/twenty-oxlint-rules/package.json new file mode 100644 index 00000000000..c8e3d09b32c --- /dev/null +++ b/packages/twenty-oxlint-rules/package.json @@ -0,0 +1,5 @@ +{ + "name": "twenty-oxlint-rules", + "private": true, + "type": "module" +} diff --git a/packages/twenty-oxlint-rules/tsconfig.json b/packages/twenty-oxlint-rules/tsconfig.json index 86e13f251b8..3d093777814 100644 --- a/packages/twenty-oxlint-rules/tsconfig.json +++ b/packages/twenty-oxlint-rules/tsconfig.json @@ -3,8 +3,8 @@ "compilerOptions": { "outDir": "../../.cache/tsc", "esModuleInterop": true, - "moduleResolution": "node16", - "module": "node16", + "moduleResolution": "bundler", + "module": "esnext", "types": ["node"] }, "include": ["**/*.ts"] diff --git a/packages/twenty-sdk/.oxlintrc.json b/packages/twenty-sdk/.oxlintrc.json index b4b75f81974..a1d10264b45 100644 --- a/packages/twenty-sdk/.oxlintrc.json +++ b/packages/twenty-sdk/.oxlintrc.json @@ -17,23 +17,32 @@ "import/no-duplicates": "error", "typescript/no-redeclare": "error", "typescript/ban-ts-comment": "error", - "typescript/consistent-type-imports": ["error", { - "prefer": "type-imports", - "fixStyle": "inline-type-imports" - }], + "typescript/consistent-type-imports": [ + "error", + { + "prefer": "type-imports", + "fixStyle": "inline-type-imports" + } + ], "typescript/explicit-function-return-type": "off", "typescript/explicit-module-boundary-types": "off", - "typescript/no-empty-object-type": ["error", { - "allowInterfaces": "with-single-extends" - }], + "typescript/no-empty-object-type": [ + "error", + { + "allowInterfaces": "with-single-extends" + } + ], "typescript/no-empty-function": "off", "typescript/no-explicit-any": "off", - "typescript/no-unused-vars": ["warn", { - "vars": "all", - "varsIgnorePattern": "^_", - "args": "after-used", - "argsIgnorePattern": "^_" - }], + "typescript/no-unused-vars": [ + "warn", + { + "vars": "all", + "varsIgnorePattern": "^_", + "args": "after-used", + "argsIgnorePattern": "^_" + } + ], "react/no-unescaped-entities": "off", "react/prop-types": "off", "react/jsx-key": "off", diff --git a/packages/twenty-sdk/.prettierignore b/packages/twenty-sdk/.prettierignore new file mode 100644 index 00000000000..e3d13709bb2 --- /dev/null +++ b/packages/twenty-sdk/.prettierignore @@ -0,0 +1,3 @@ +dist +storybook-static +coverage diff --git a/packages/twenty-sdk/.storybook/main.ts b/packages/twenty-sdk/.storybook/main.ts index 321be7b79bb..c16a82b1fad 100644 --- a/packages/twenty-sdk/.storybook/main.ts +++ b/packages/twenty-sdk/.storybook/main.ts @@ -11,9 +11,7 @@ const dirname = const sdkRoot = path.resolve(dirname, '..'); const config: StorybookConfig = { - stories: [ - '../src/front-component-renderer/**/*.stories.@(js|jsx|ts|tsx)', - ], + stories: ['../src/front-component-renderer/**/*.stories.@(js|jsx|ts|tsx)'], addons: ['@storybook/addon-vitest'], diff --git a/packages/twenty-sdk/README.md b/packages/twenty-sdk/README.md index c6fffb93b46..c3a21291b95 100644 --- a/packages/twenty-sdk/README.md +++ b/packages/twenty-sdk/README.md @@ -19,9 +19,11 @@ A CLI and SDK to develop, build, and publish applications that extend [Twenty CR - Works great with the scaffolder: [create-twenty-app](https://www.npmjs.com/package/create-twenty-app) ## Documentation + See Twenty application documentation https://docs.twenty.com/developers/extend/capabilities/apps ## Prerequisites + - Node.js 24+ (recommended) and Yarn 4 - A Twenty workspace and an API key. Generate one at https://app.twenty.com/settings/api-webhooks @@ -73,6 +75,7 @@ In a scaffolded project (via `create-twenty-app`), use `yarn twenty ` i Authenticate the CLI against your Twenty workspace. - `twenty auth:login` — Authenticate with Twenty. + - Options: - `--api-key `: API key for authentication. - `--api-url `: Twenty API URL (defaults to your current profile's value or `http://localhost:3000`). @@ -83,6 +86,7 @@ Authenticate the CLI against your Twenty workspace. - `twenty auth:status` — Print the current authentication status (API URL, masked API key, validity). - `twenty auth:list` — List all configured workspaces. + - Behavior: Displays all available workspaces with their authentication status and API URLs. Shows which workspace is the current default. - `twenty auth:switch [workspace]` — Switch the default workspace for authentication. @@ -123,6 +127,7 @@ twenty auth:switch production Application development commands. - `twenty app:dev [appPath]` — Start development mode: watch and sync local application changes. + - Behavior: Builds your application (functions and front components), computes the manifest, syncs everything to your workspace, then watches the directory for changes and re-syncs automatically. Displays an interactive UI showing build and sync status in real time. Press Ctrl+C to stop. - `twenty app:typecheck [appPath]` — Run TypeScript type checking on the application (runs `tsc --noEmit`). Exits with code 1 if type errors are found. @@ -149,6 +154,7 @@ Application development commands. ### Function - `twenty function:logs [appPath]` — Stream application function logs. + - Options: - `-u, --functionUniversalIdentifier `: Only show logs for a specific function universal ID. - `-n, --functionName `: Only show logs for a specific function name. @@ -249,8 +255,8 @@ Notes: - `twenty auth:switch` sets the `defaultWorkspace` field, which is used when `--workspace` is not specified. - `twenty auth:list` shows all configured workspaces and their authentication status. - ## Troubleshooting + - Auth errors: run `twenty auth:login` again and ensure the API key has the required permissions. - Typings out of date: restart `twenty app:dev` to refresh the client and types. - Not seeing changes in dev: make sure dev mode is running (`twenty app:dev`). @@ -301,5 +307,6 @@ node packages/twenty-sdk/dist/cli.cjs ``` ### Resources + - See our [GitHub](https://github.com/twentyhq/twenty) - Join our [Discord](https://discord.gg/cx5n4Jzs57) diff --git a/packages/twenty-sdk/project.json b/packages/twenty-sdk/project.json index 1caeef57080..2411587f196 100644 --- a/packages/twenty-sdk/project.json +++ b/packages/twenty-sdk/project.json @@ -3,24 +3,14 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "packages/twenty-sdk/src", "projectType": "library", - "tags": [ - "scope:sdk", - "scope:shared" - ], + "tags": ["scope:sdk"], "targets": { "build": { "executor": "nx:run-commands", "cache": true, - "inputs": [ - "production", - "^production" - ], - "dependsOn": [ - "^build" - ], - "outputs": [ - "{projectRoot}/dist" - ], + "inputs": ["production", "^production"], + "dependsOn": ["^build"], + "outputs": ["{projectRoot}/dist"], "options": { "cwd": "{projectRoot}", "commands": [ @@ -32,9 +22,7 @@ }, "dev": { "executor": "nx:run-commands", - "dependsOn": [ - "^build" - ], + "dependsOn": ["^build"], "options": { "cwd": "packages/twenty-sdk", "command": "npx rimraf dist && npx vite build -c vite.config.node.ts && npx vite build -c vite.config.browser.ts && npx vite build -c vite.config.sdk.ts && tsgo -p tsconfig.lib.json --declaration --emitDeclarationOnly --noEmit false --outDir dist --rootDir src && npx tsc-alias -p tsconfig.lib.json --outDir dist && npx vite build -c vite.config.node.ts --watch & npx vite build -c vite.config.browser.ts --watch & npx vite build -c vite.config.sdk.ts --watch" @@ -42,9 +30,7 @@ }, "start": { "executor": "nx:run-commands", - "dependsOn": [ - "build" - ], + "dependsOn": ["build"], "options": { "cwd": "packages/twenty-sdk", "command": "node dist/cli.cjs" @@ -54,9 +40,7 @@ "lint": {}, "test": { "executor": "@nx/vitest:test", - "outputs": [ - "{workspaceRoot}/coverage/{projectRoot}" - ], + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], "options": { "config": "{projectRoot}/vitest.config.ts" }, @@ -103,15 +87,9 @@ "build:sdk": { "executor": "nx:run-commands", "cache": true, - "dependsOn": [ - "^build" - ], - "inputs": [ - "{projectRoot}/src/sdk/**/*" - ], - "outputs": [ - "{projectRoot}/dist/sdk" - ], + "dependsOn": ["^build"], + "inputs": ["{projectRoot}/src/sdk/**/*"], + "outputs": ["{projectRoot}/dist/sdk"], "options": { "cwd": "{projectRoot}", "command": "npx vite build -c vite.config.sdk.ts" @@ -120,9 +98,7 @@ "generate-remote-dom-elements": { "executor": "nx:run-commands", "cache": true, - "dependsOn": [ - "^build" - ], + "dependsOn": ["^build"], "inputs": [ "{projectRoot}/scripts/remote-dom/**/*", "{projectRoot}/src/sdk/front-component-api/**/*", @@ -171,9 +147,7 @@ } }, "storybook:build": { - "dependsOn": [ - "storybook:prebuild" - ], + "dependsOn": ["storybook:prebuild"], "configurations": { "test": {} } @@ -194,17 +168,13 @@ } }, "storybook:test": { - "dependsOn": [ - "storybook:prebuild" - ], + "dependsOn": ["storybook:prebuild"], "options": { "command": "vitest run --coverage --config vitest.storybook.config.ts --shard={args.shard}" } }, "storybook:test:no-coverage": { - "dependsOn": [ - "storybook:prebuild" - ], + "dependsOn": ["storybook:prebuild"], "options": { "command": "vitest run --config vitest.storybook.config.ts --shard={args.shard}" } diff --git a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/src/utils/card-display.component.tsx b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/src/utils/card-display.component.tsx index de1d427f6a5..1a7be225faf 100644 --- a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/src/utils/card-display.component.tsx +++ b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/src/utils/card-display.component.tsx @@ -6,7 +6,9 @@ export const CardDisplay = ({ content: string; }) => { return ( - + {title} {content} diff --git a/packages/twenty-sdk/src/cli/utilities/dev/ui/components/dev-ui-application-panel.tsx b/packages/twenty-sdk/src/cli/utilities/dev/ui/components/dev-ui-application-panel.tsx index 4f89e82239a..026664d0f2c 100644 --- a/packages/twenty-sdk/src/cli/utilities/dev/ui/components/dev-ui-application-panel.tsx +++ b/packages/twenty-sdk/src/cli/utilities/dev/ui/components/dev-ui-application-panel.tsx @@ -114,11 +114,7 @@ export const DevUiApplicationPanel = ({ const entities = groupedEntities.get(type) ?? []; return ( - + ); })} diff --git a/packages/twenty-sdk/src/cli/utilities/dev/ui/components/dev-ui-entity-section.tsx b/packages/twenty-sdk/src/cli/utilities/dev/ui/components/dev-ui-entity-section.tsx index 56e23cc36cd..4ad94ad8b47 100644 --- a/packages/twenty-sdk/src/cli/utilities/dev/ui/components/dev-ui-entity-section.tsx +++ b/packages/twenty-sdk/src/cli/utilities/dev/ui/components/dev-ui-entity-section.tsx @@ -1,6 +1,4 @@ -import { - type OrchestratorStateEntityInfo, -} from '@/cli/utilities/dev/orchestrator/dev-mode-orchestrator-state'; +import { type OrchestratorStateEntityInfo } from '@/cli/utilities/dev/orchestrator/dev-mode-orchestrator-state'; import { type DevUiStatus, DEV_UI_STATUS_CONFIG, @@ -37,9 +35,7 @@ export const DevUiEntityRow = ({ return ( - + {entity.name} {entity.path !== entity.name && ( ({shortenPath(entity.path)}) diff --git a/packages/twenty-sdk/src/front-component-renderer/__stories__/BundleSizes.stories.tsx b/packages/twenty-sdk/src/front-component-renderer/__stories__/BundleSizes.stories.tsx index 4bfc8a0adbe..c58e6a5568b 100644 --- a/packages/twenty-sdk/src/front-component-renderer/__stories__/BundleSizes.stories.tsx +++ b/packages/twenty-sdk/src/front-component-renderer/__stories__/BundleSizes.stories.tsx @@ -74,10 +74,8 @@ const BundleSizesTable = () => { {entries.map((entry) => { - const reactWidth = - (entry.reactBytes / maxBytes) * BAR_MAX_WIDTH; - const preactWidth = - (entry.preactBytes / maxBytes) * BAR_MAX_WIDTH; + const reactWidth = (entry.reactBytes / maxBytes) * BAR_MAX_WIDTH; + const preactWidth = (entry.preactBytes / maxBytes) * BAR_MAX_WIDTH; const saving = entry.reactBytes > 0 ? ( @@ -102,7 +100,9 @@ const BundleSizesTable = () => { {formatLabel(entry.name)} - + { > Increment - setCount(0)} - > + setCount(0)}> Reset diff --git a/packages/twenty-sdk/src/front-component-renderer/__stories__/example-sources/sdk-context-example.front-component.tsx b/packages/twenty-sdk/src/front-component-renderer/__stories__/example-sources/sdk-context-example.front-component.tsx index 70fbbd076bb..694ccd61482 100644 --- a/packages/twenty-sdk/src/front-component-renderer/__stories__/example-sources/sdk-context-example.front-component.tsx +++ b/packages/twenty-sdk/src/front-component-renderer/__stories__/example-sources/sdk-context-example.front-component.tsx @@ -37,9 +37,7 @@ const SdkContextComponent = () => { const userId = useUserId(); - const fullContext = useFrontComponentExecutionContext( - (context) => context, - ); + const fullContext = useFrontComponentExecutionContext((context) => context); return ( @@ -78,9 +76,7 @@ const SdkContextComponent = () => { - + setRenderCount((previous) => previous + 1)} diff --git a/packages/twenty-sdk/vitest.config.ts b/packages/twenty-sdk/vitest.config.ts index ec2117b65a2..f139de1949d 100644 --- a/packages/twenty-sdk/vitest.config.ts +++ b/packages/twenty-sdk/vitest.config.ts @@ -13,14 +13,18 @@ export default defineConfig({ environment: 'node', include: [ 'src/**/__tests__/**/*.{test,spec}.{ts,tsx}', - 'src/**/__integration__/**/*.{test,spec}.{ts,tsx}', 'src/**/*.{test,spec}.{ts,tsx}', ], - exclude: ['**/node_modules/**', '**/.git/**', '**/__e2e__/**'], + exclude: [ + '**/node_modules/**', + '**/.git/**', + '**/__e2e__/**', + '**/__integration__/**', + ], coverage: { provider: 'v8', include: ['src/**/*.{ts,tsx}'], - exclude: ['src/**/*.d.ts', 'src/cli/cli.ts'], + exclude: ['src/**/*.d.ts', 'src/cli/cli.ts', 'src/**/__stories__/**'], thresholds: { statements: 1, lines: 1, diff --git a/packages/twenty-server/project.json b/packages/twenty-server/project.json index 73d47dfa25b..f4a5fc74e43 100644 --- a/packages/twenty-server/project.json +++ b/packages/twenty-server/project.json @@ -162,12 +162,12 @@ ], "options": { "cwd": "{projectRoot}", - "command": "npx oxlint --type-aware -c .oxlintrc.json src/" + "command": "npx oxlint --type-aware -c .oxlintrc.json src/ && (prettier src/ --check --cache --cache-location ../../.cache/prettier/{projectRoot} --cache-strategy metadata || (echo 'ERROR: Prettier formatting check failed! Fix with: npx nx lint twenty-server --configuration=fix' && false))" }, "configurations": { "ci": {}, "fix": { - "command": "npx oxlint --type-aware --fix -c .oxlintrc.json src/" + "command": "npx oxlint --type-aware --fix -c .oxlintrc.json src/ && prettier src/ --write --cache --cache-location ../../.cache/prettier/{projectRoot} --cache-strategy metadata" } } }, diff --git a/packages/twenty-server/src/engine/core-modules/audit/README.md b/packages/twenty-server/src/engine/core-modules/audit/README.md index 64f22973ecc..da64e829e78 100644 --- a/packages/twenty-server/src/engine/core-modules/audit/README.md +++ b/packages/twenty-server/src/engine/core-modules/audit/README.md @@ -30,14 +30,14 @@ export class MyService { // Track a workspace event auditService.insertWorkspaceEvent(CUSTOM_DOMAIN_ACTIVATED_EVENT, {}); - + // Track an object event auditService.createObjectEvent(OBJECT_RECORD_CREATED_EVENT, { recordId: 'record-id', objectMetadataId: 'object-metadata-id', // other properties }); - + // Track a pageview auditService.createPageviewEvent('page-name', { href: '/path', @@ -82,12 +82,14 @@ Then update the `events.type.ts` file: ```typescript // src/engine/core-modules/analytics/types/events.type.ts -import { MY_EVENT, MyEventTrackEvent } from '../utils/events/track/my-feature/my-event'; +import { + MY_EVENT, + MyEventTrackEvent, +} from '../utils/events/track/my-feature/my-event'; // Add to the union type -export type TrackEventName = - | typeof MY_EVENT - // ... other event names; +export type TrackEventName = typeof MY_EVENT; +// ... other event names; // Add to the TrackEvents interface export interface TrackEvents { @@ -96,9 +98,8 @@ export interface TrackEvents { } // The TrackEventProperties type will automatically use the new event -export type TrackEventProperties = T extends keyof TrackEvents - ? TrackEvents[T]['properties'] - : object; +export type TrackEventProperties = + T extends keyof TrackEvents ? TrackEvents[T]['properties'] : object; ``` ## API @@ -136,9 +137,8 @@ export interface TrackEvents { } // Use the mapping to extract properties for each event type -export type TrackEventProperties = T extends keyof TrackEvents - ? TrackEvents[T]['properties'] - : object; +export type TrackEventProperties = + T extends keyof TrackEvents ? TrackEvents[T]['properties'] : object; ``` This approach makes it easier to add new events without having to modify a complex nested conditional type. diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-resource/constants/seed-project/src/index.mjs b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-resource/constants/seed-project/src/index.mjs index bd89c19f6c4..e86f51739b3 100644 --- a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-resource/constants/seed-project/src/index.mjs +++ b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-resource/constants/seed-project/src/index.mjs @@ -3,6 +3,4 @@ var main = async (params) => { const message = `Hello, input: ${a} and ${b}`; return { message }; }; -export { - main -}; +export { main }; diff --git a/packages/twenty-shared/.oxlintrc.json b/packages/twenty-shared/.oxlintrc.json index 871691c06a1..b7a1c3cebf0 100644 --- a/packages/twenty-shared/.oxlintrc.json +++ b/packages/twenty-shared/.oxlintrc.json @@ -8,7 +8,10 @@ "ignorePatterns": ["node_modules", "dist"], "rules": { "func-style": ["error", "declaration", { "allowArrowFunctions": true }], - "no-console": ["warn", { "allow": ["group", "groupCollapsed", "groupEnd"] }], + "no-console": [ + "warn", + { "allow": ["group", "groupCollapsed", "groupEnd"] } + ], "no-control-regex": "off", "no-debugger": "error", "no-duplicate-imports": "error", @@ -18,28 +21,43 @@ "import/no-duplicates": "error", "typescript/no-redeclare": "error", "typescript/ban-ts-comment": "error", - "typescript/consistent-type-imports": ["error", { - "prefer": "type-imports", - "fixStyle": "inline-type-imports" - }], + "typescript/consistent-type-imports": [ + "error", + { + "prefer": "type-imports", + "fixStyle": "inline-type-imports" + } + ], "typescript/explicit-function-return-type": "off", "typescript/explicit-module-boundary-types": "off", - "typescript/no-empty-object-type": ["error", { - "allowInterfaces": "with-single-extends" - }], + "typescript/no-empty-object-type": [ + "error", + { + "allowInterfaces": "with-single-extends" + } + ], "typescript/no-empty-function": "off", "typescript/no-explicit-any": "off", - "typescript/no-unused-vars": ["warn", { - "vars": "all", - "varsIgnorePattern": "^_", - "args": "after-used", - "argsIgnorePattern": "^_" - }], - "twenty/enforce-module-boundaries": ["error", { - "depConstraints": [ - { "sourceTag": "scope:shared", "onlyDependOnLibsWithTags": ["scope:shared"] } - ] - }] + "typescript/no-unused-vars": [ + "warn", + { + "vars": "all", + "varsIgnorePattern": "^_", + "args": "after-used", + "argsIgnorePattern": "^_" + } + ], + "twenty/enforce-module-boundaries": [ + "error", + { + "depConstraints": [ + { + "sourceTag": "scope:shared", + "onlyDependOnLibsWithTags": ["scope:shared"] + } + ] + } + ] }, "overrides": [ { diff --git a/packages/twenty-shared/project.json b/packages/twenty-shared/project.json index 8f13e07a10e..8d7cbf53bfe 100644 --- a/packages/twenty-shared/project.json +++ b/packages/twenty-shared/project.json @@ -3,21 +3,13 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "packages/twenty-shared/src", "projectType": "library", - "tags": [ - "scope:shared" - ], + "tags": ["scope:shared"], "targets": { "build": { "executor": "nx:run-commands", "cache": true, - "inputs": [ - "production", - "^production" - ], - "dependsOn": [ - "generateBarrels", - "^build" - ], + "inputs": ["production", "^production"], + "dependsOn": ["generateBarrels", "^build"], "outputs": [ "{projectRoot}/dist", "{projectRoot}/ai/package.json", @@ -59,16 +51,9 @@ "build:individual": { "executor": "nx:run-commands", "cache": true, - "dependsOn": [ - "build" - ], - "inputs": [ - "production", - "^production" - ], - "outputs": [ - "{projectRoot}/dist/individual" - ], + "dependsOn": ["build"], + "inputs": ["production", "^production"], + "outputs": ["{projectRoot}/dist/individual"], "options": { "cwd": "{projectRoot}", "command": "npx vite build -c vite.config.individual.ts" @@ -77,34 +62,17 @@ "generateBarrels": { "executor": "nx:run-commands", "cache": true, - "inputs": [ - "production", - "{projectRoot}/scripts/generateBarrels.ts" - ], + "inputs": ["production", "{projectRoot}/scripts/generateBarrels.ts"], "outputs": [ "{projectRoot}/src/index.ts", "{projectRoot}/src/*/index.ts", "{projectRoot}/package.json" ], - "options": { - "command": "tsx {projectRoot}/scripts/generateBarrels.ts" - } + "options": { "command": "tsx {projectRoot}/scripts/generateBarrels.ts" } }, "typecheck": {}, "test": {}, - "lint": { - "options": {}, - "configurations": { - "fix": {} - } - }, - "fmt": { - "options": { - "files": "src" - }, - "configurations": { - "fix": {} - } - } + "lint": { "options": {}, "configurations": { "fix": {} } }, + "fmt": { "options": { "files": "src" }, "configurations": { "fix": {} } } } } diff --git a/packages/twenty-shared/scripts/generateBarrels.ts b/packages/twenty-shared/scripts/generateBarrels.ts index 36a504146ab..1f2ce155e0d 100644 --- a/packages/twenty-shared/scripts/generateBarrels.ts +++ b/packages/twenty-shared/scripts/generateBarrels.ts @@ -151,7 +151,10 @@ type WriteInJsonFileArgs = { }; const updateJsonFile = ({ content, file }: WriteInJsonFileArgs) => { const updatedJsonFile = JSON.stringify(content); - const formattedContent = prettierFormat(updatedJsonFile, 'json-stringify'); + const formattedContent = prettier.format(updatedJsonFile, { + ...prettierConfiguration, + filepath: file, + }); fs.writeFileSync(file, formattedContent, 'utf-8'); }; diff --git a/packages/twenty-shared/src/individual-entry.ts b/packages/twenty-shared/src/individual-entry.ts index bbb0efaca30..d2217191fe8 100644 --- a/packages/twenty-shared/src/individual-entry.ts +++ b/packages/twenty-shared/src/individual-entry.ts @@ -9,4 +9,3 @@ export * from './types'; export * from './utils'; export * from './workflow'; export * from './workspace'; - diff --git a/packages/twenty-shared/tsconfig.json b/packages/twenty-shared/tsconfig.json index ede1d80d548..fffeed0c92b 100644 --- a/packages/twenty-shared/tsconfig.json +++ b/packages/twenty-shared/tsconfig.json @@ -21,7 +21,5 @@ "jest.config.mjs", "vite.config.*.ts" ], - "exclude": [ - "src/individual-entry.ts" - ] + "exclude": ["src/individual-entry.ts"] } diff --git a/packages/twenty-ui/.oxlintrc.json b/packages/twenty-ui/.oxlintrc.json index 1397c633294..3279ce3aa2b 100644 --- a/packages/twenty-ui/.oxlintrc.json +++ b/packages/twenty-ui/.oxlintrc.json @@ -5,13 +5,13 @@ "categories": { "correctness": "off" }, - "ignorePatterns": [ - "node_modules", - "generated" - ], + "ignorePatterns": ["node_modules", "generated"], "rules": { "func-style": ["error", "declaration", { "allowArrowFunctions": true }], - "no-console": ["warn", { "allow": ["group", "groupCollapsed", "groupEnd"] }], + "no-console": [ + "warn", + { "allow": ["group", "groupCollapsed", "groupEnd"] } + ], "no-control-regex": "off", "no-debugger": "error", "no-duplicate-imports": "error", @@ -35,31 +35,43 @@ "typescript/no-redeclare": "error", "typescript/ban-ts-comment": "error", - "typescript/consistent-type-imports": ["error", { - "prefer": "type-imports", - "fixStyle": "inline-type-imports" - }], + "typescript/consistent-type-imports": [ + "error", + { + "prefer": "type-imports", + "fixStyle": "inline-type-imports" + } + ], "typescript/explicit-function-return-type": "off", "typescript/explicit-module-boundary-types": "off", - "typescript/no-empty-object-type": ["error", { - "allowInterfaces": "with-single-extends" - }], + "typescript/no-empty-object-type": [ + "error", + { + "allowInterfaces": "with-single-extends" + } + ], "typescript/no-empty-function": "off", "typescript/no-explicit-any": "off", - "typescript/no-unused-vars": ["warn", { - "vars": "all", - "varsIgnorePattern": "^_", - "args": "after-used", - "argsIgnorePattern": "^_" - }], + "typescript/no-unused-vars": [ + "warn", + { + "vars": "all", + "varsIgnorePattern": "^_", + "args": "after-used", + "argsIgnorePattern": "^_" + } + ], - "twenty/enforce-module-boundaries": ["error", { - "depConstraints": [ - { - "sourceTag": "scope:shared", - "onlyDependOnLibsWithTags": ["scope:shared"] - } - ] - }] + "twenty/enforce-module-boundaries": [ + "error", + { + "depConstraints": [ + { + "sourceTag": "scope:shared", + "onlyDependOnLibsWithTags": ["scope:shared"] + } + ] + } + ] } } diff --git a/packages/twenty-ui/.prettierignore b/packages/twenty-ui/.prettierignore new file mode 100644 index 00000000000..e3d13709bb2 --- /dev/null +++ b/packages/twenty-ui/.prettierignore @@ -0,0 +1,3 @@ +dist +storybook-static +coverage diff --git a/packages/twenty-ui/.storybook/main.ts b/packages/twenty-ui/.storybook/main.ts index a4b9db14e98..6a3eeb7351c 100644 --- a/packages/twenty-ui/.storybook/main.ts +++ b/packages/twenty-ui/.storybook/main.ts @@ -43,8 +43,7 @@ const config: StorybookConfig = { ...viteConfig.resolve, alias: { ...(viteConfig.resolve?.alias ?? {}), - '@tabler/icons-react': - '@tabler/icons-react/dist/esm/icons/index.mjs', + '@tabler/icons-react': '@tabler/icons-react/dist/esm/icons/index.mjs', }, }, }; diff --git a/packages/twenty-ui/.storybook/manager-head.html b/packages/twenty-ui/.storybook/manager-head.html index 0be4849fca4..6c642f18305 100644 --- a/packages/twenty-ui/.storybook/manager-head.html +++ b/packages/twenty-ui/.storybook/manager-head.html @@ -1,5 +1,5 @@ \ No newline at end of file + [data-is-storybook='true'] { + background-color: transparent !important; + } + diff --git a/packages/twenty-ui/.storybook/preview-head.html b/packages/twenty-ui/.storybook/preview-head.html index f6ee81b23de..534a4fb9bee 100644 --- a/packages/twenty-ui/.storybook/preview-head.html +++ b/packages/twenty-ui/.storybook/preview-head.html @@ -6,29 +6,29 @@ \ No newline at end of file + *::-webkit-scrollbar-thumb { + background-color: transparent; + border-radius: 2px; + } + diff --git a/packages/twenty-ui/project.json b/packages/twenty-ui/project.json index 779c75f750b..1775723c615 100644 --- a/packages/twenty-ui/project.json +++ b/packages/twenty-ui/project.json @@ -3,15 +3,10 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "packages/twenty-ui/src", "projectType": "library", - "tags": [ - "scope:shared" - ], + "tags": ["scope:shared"], "targets": { "build": { - "dependsOn": [ - "^build", - "generateBarrels" - ], + "dependsOn": ["^build", "generateBarrels"], "outputs": [ "{projectRoot}/dist", "{projectRoot}/accessibility/package.json", @@ -44,16 +39,10 @@ }, "generateThemeConstants": { "executor": "nx:run-commands", - "dependsOn": [ - "build" - ], + "dependsOn": ["build"], "cache": true, - "inputs": [ - "{projectRoot}/scripts/generateThemeConstants.ts" - ], - "outputs": [ - "{projectRoot}/src/theme-constants/generated" - ], + "inputs": ["{projectRoot}/scripts/generateThemeConstants.ts"], + "outputs": ["{projectRoot}/src/theme-constants/generated"], "options": { "command": "tsx {projectRoot}/scripts/generateThemeConstants.ts" } @@ -61,31 +50,19 @@ "generateBarrels": { "executor": "nx:run-commands", "cache": true, - "inputs": [ - "production", - "{projectRoot}/scripts/generateBarrels.ts" - ], + "inputs": ["production", "{projectRoot}/scripts/generateBarrels.ts"], "outputs": [ "{projectRoot}/src/**/*/index.ts", "{projectRoot}/package.json" ], - "options": { - "command": "tsx {projectRoot}/scripts/generateBarrels.ts" - } + "options": { "command": "tsx {projectRoot}/scripts/generateBarrels.ts" } }, "build:individual": { "executor": "nx:run-commands", "cache": true, - "dependsOn": [ - "build" - ], - "inputs": [ - "production", - "^production" - ], - "outputs": [ - "{projectRoot}/dist/individual" - ], + "dependsOn": ["build"], + "inputs": ["production", "^production"], + "outputs": ["{projectRoot}/dist/individual"], "options": { "cwd": "{projectRoot}", "command": "npx vite build -c vite.config.individual.ts" @@ -93,39 +70,17 @@ }, "clean": { "executor": "nx:run-commands", - "options": { - "command": "rimraf {projectRoot}/dist" - } + "options": { "command": "rimraf {projectRoot}/dist" } }, "lint": {}, - "fmt": { - "options": { - "files": "src" - }, - "configurations": { - "fix": {} - } - }, + "fmt": { "options": { "files": "src" }, "configurations": { "fix": {} } }, "test": {}, "typecheck": {}, - "storybook:build": { - "configurations": { - "test": {} - } - }, - "storybook:serve:dev": { - "options": { - "port": 6007 - } - }, + "storybook:build": { "configurations": { "test": {} } }, + "storybook:serve:dev": { "options": { "port": 6007 } }, "storybook:serve:static": { - "options": { - "buildTarget": "twenty-ui:storybook:build", - "port": 6007 - }, - "configurations": { - "test": {} - } + "options": { "buildTarget": "twenty-ui:storybook:build", "port": 6007 }, + "configurations": { "test": {} } }, "storybook:test": {}, "storybook:test:no-coverage": {}, diff --git a/packages/twenty-ui/scripts/generateBarrels.ts b/packages/twenty-ui/scripts/generateBarrels.ts index 75ca5e652c0..ba6f271412e 100644 --- a/packages/twenty-ui/scripts/generateBarrels.ts +++ b/packages/twenty-ui/scripts/generateBarrels.ts @@ -151,7 +151,10 @@ type WriteInJsonFileArgs = { }; const updateJsonFile = ({ content, file }: WriteInJsonFileArgs) => { const updatedJsonFile = JSON.stringify(content); - const formattedContent = prettierFormat(updatedJsonFile, 'json-stringify'); + const formattedContent = prettier.format(updatedJsonFile, { + ...prettierConfiguration, + filepath: file, + }); fs.writeFileSync(file, formattedContent, 'utf-8'); }; diff --git a/packages/twenty-ui/src/theme-constants/theme-dark.css b/packages/twenty-ui/src/theme-constants/theme-dark.css index 2aa8a026caa..5162b078c8a 100644 --- a/packages/twenty-ui/src/theme-constants/theme-dark.css +++ b/packages/twenty-ui/src/theme-constants/theme-dark.css @@ -110,8 +110,16 @@ --t-background-overlay-primary: #000000b8; --t-background-overlay-secondary: #0000005c; --t-background-overlay-tertiary: #0000005c; - --t-background-radial-gradient: radial-gradient(50% 62.62% at 50% 0%, color(display-p3 0.506 0.506 0.506) 0%, color(display-p3 0.482 0.482 0.482) 100%); - --t-background-radial-gradient-hover: radial-gradient(76.32% 95.59% at 50% 0%, color(display-p3 0.482 0.482 0.482) 0%, color(display-p3 0.702 0.702 0.702) 100%); + --t-background-radial-gradient: radial-gradient( + 50% 62.62% at 50% 0%, + color(display-p3 0.506 0.506 0.506) 0%, + color(display-p3 0.482 0.482 0.482) 100% + ); + --t-background-radial-gradient-hover: radial-gradient( + 76.32% 95.59% at 50% 0%, + color(display-p3 0.482 0.482 0.482) 0%, + color(display-p3 0.702 0.702 0.702) 100% + ); --t-background-primary-inverted: color(display-p3 0.922 0.922 0.922); --t-background-primary-inverted-hover: color(display-p3 0.702 0.702 0.702); --t-blur-light: blur(6px) saturate(200%) contrast(100%) brightness(130%); @@ -132,11 +140,14 @@ --t-border-radius-xxl: 40px; --t-border-radius-pill: 999px; --t-border-radius-rounded: 100%; - --t-box-shadow-color: rgba(0,0,0,0.6); - --t-box-shadow-light: 0px 2px 4px 0px rgba(0,0,0,0.04), 0px 0px 4px 0px rgba(0,0,0,0.08); - --t-box-shadow-strong: 2px 4px 16px 0px rgba(0,0,0,0.16), 0px 2px 4px 0px rgba(0,0,0,0.08); - --t-box-shadow-underline: 0px 1px 0px 0px rgba(0,0,0,0.32); - --t-box-shadow-super-heavy: 2px 4px 16px 0px rgba(0,0,0,0.12), 0px 2px 4px 0px rgba(0,0,0,0.04); + --t-box-shadow-color: rgba(0, 0, 0, 0.6); + --t-box-shadow-light: 0px 2px 4px 0px rgba(0, 0, 0, 0.04), + 0px 0px 4px 0px rgba(0, 0, 0, 0.08); + --t-box-shadow-strong: 2px 4px 16px 0px rgba(0, 0, 0, 0.16), + 0px 2px 4px 0px rgba(0, 0, 0, 0.08); + --t-box-shadow-underline: 0px 1px 0px 0px rgba(0, 0, 0, 0.32); + --t-box-shadow-super-heavy: 2px 4px 16px 0px rgba(0, 0, 0, 0.12), + 0px 2px 4px 0px rgba(0, 0, 0, 0.04); --t-font-color-primary: color(display-p3 0.922 0.922 0.922); --t-font-color-secondary: color(display-p3 0.702 0.702 0.702); --t-font-color-tertiary: color(display-p3 0.506 0.506 0.506); diff --git a/packages/twenty-ui/src/theme-constants/theme-light.css b/packages/twenty-ui/src/theme-constants/theme-light.css index 471f5e326bf..a5c319899de 100644 --- a/packages/twenty-ui/src/theme-constants/theme-light.css +++ b/packages/twenty-ui/src/theme-constants/theme-light.css @@ -110,8 +110,16 @@ --t-background-overlay-primary: color(display-p3 0 0 0 / 0.722); --t-background-overlay-secondary: color(display-p3 0 0 0 / 0.361); --t-background-overlay-tertiary: color(display-p3 0 0 0 / 0.071); - --t-background-radial-gradient: radial-gradient(50% 62.62% at 50% 0%, color(display-p3 0.6 0.6 0.6) 0%, color(display-p3 0.514 0.514 0.514) 100%); - --t-background-radial-gradient-hover: radial-gradient(76.32% 95.59% at 50% 0%, color(display-p3 0.514 0.514 0.514) 0%, color(display-p3 0.4 0.4 0.4) 100%); + --t-background-radial-gradient: radial-gradient( + 50% 62.62% at 50% 0%, + color(display-p3 0.6 0.6 0.6) 0%, + color(display-p3 0.514 0.514 0.514) 100% + ); + --t-background-radial-gradient-hover: radial-gradient( + 76.32% 95.59% at 50% 0%, + color(display-p3 0.514 0.514 0.514) 0%, + color(display-p3 0.4 0.4 0.4) 100% + ); --t-background-primary-inverted: color(display-p3 0.2 0.2 0.2); --t-background-primary-inverted-hover: color(display-p3 0.4 0.4 0.4); --t-blur-light: blur(6px) saturate(200%) contrast(50%) brightness(130%); @@ -133,10 +141,14 @@ --t-border-radius-pill: 999px; --t-border-radius-rounded: 100%; --t-box-shadow-color: color(display-p3 0 0 0 / 0.039); - --t-box-shadow-light: 0px 2px 4px 0px color(display-p3 0 0 0 / 0.039), 0px 0px 4px 0px color(display-p3 0 0 0 / 0.078); - --t-box-shadow-strong: 2px 4px 16px 0px color(display-p3 0 0 0 / 0.161), 0px 2px 4px 0px color(display-p3 0 0 0 / 0.078); + --t-box-shadow-light: 0px 2px 4px 0px color(display-p3 0 0 0 / 0.039), + 0px 0px 4px 0px color(display-p3 0 0 0 / 0.078); + --t-box-shadow-strong: 2px 4px 16px 0px color(display-p3 0 0 0 / 0.161), + 0px 2px 4px 0px color(display-p3 0 0 0 / 0.078); --t-box-shadow-underline: 0px 1px 0px 0px color(display-p3 0 0 0 / 0.361); - --t-box-shadow-super-heavy: 0px 0px 8px 0px color(display-p3 0 0 0 / 0.161), 0px 8px 64px -16px color(display-p3 0 0 0 / 0.478), 0px 24px 56px -16px color(display-p3 0 0 0 / 0.078); + --t-box-shadow-super-heavy: 0px 0px 8px 0px color(display-p3 0 0 0 / 0.161), + 0px 8px 64px -16px color(display-p3 0 0 0 / 0.478), + 0px 24px 56px -16px color(display-p3 0 0 0 / 0.078); --t-font-color-primary: color(display-p3 0.2 0.2 0.2); --t-font-color-secondary: color(display-p3 0.4 0.4 0.4); --t-font-color-tertiary: color(display-p3 0.6 0.6 0.6); diff --git a/packages/twenty-ui/vite.config.ts b/packages/twenty-ui/vite.config.ts index 2a0fb882118..0eafce38afb 100644 --- a/packages/twenty-ui/vite.config.ts +++ b/packages/twenty-ui/vite.config.ts @@ -63,8 +63,7 @@ export default defineConfig(({ command }) => { alias: { '@ui/': path.resolve(__dirname, 'src') + '/', '@assets/': path.resolve(__dirname, 'src/assets') + '/', - '@tabler/icons-react': - '@tabler/icons-react/dist/esm/icons/index.mjs', + '@tabler/icons-react': '@tabler/icons-react/dist/esm/icons/index.mjs', }, }, css: { diff --git a/packages/twenty-zapier/.oxlintrc.json b/packages/twenty-zapier/.oxlintrc.json index b4b75f81974..a1d10264b45 100644 --- a/packages/twenty-zapier/.oxlintrc.json +++ b/packages/twenty-zapier/.oxlintrc.json @@ -17,23 +17,32 @@ "import/no-duplicates": "error", "typescript/no-redeclare": "error", "typescript/ban-ts-comment": "error", - "typescript/consistent-type-imports": ["error", { - "prefer": "type-imports", - "fixStyle": "inline-type-imports" - }], + "typescript/consistent-type-imports": [ + "error", + { + "prefer": "type-imports", + "fixStyle": "inline-type-imports" + } + ], "typescript/explicit-function-return-type": "off", "typescript/explicit-module-boundary-types": "off", - "typescript/no-empty-object-type": ["error", { - "allowInterfaces": "with-single-extends" - }], + "typescript/no-empty-object-type": [ + "error", + { + "allowInterfaces": "with-single-extends" + } + ], "typescript/no-empty-function": "off", "typescript/no-explicit-any": "off", - "typescript/no-unused-vars": ["warn", { - "vars": "all", - "varsIgnorePattern": "^_", - "args": "after-used", - "argsIgnorePattern": "^_" - }], + "typescript/no-unused-vars": [ + "warn", + { + "vars": "all", + "varsIgnorePattern": "^_", + "args": "after-used", + "argsIgnorePattern": "^_" + } + ], "react/no-unescaped-entities": "off", "react/prop-types": "off", "react/jsx-key": "off", diff --git a/packages/twenty-zapier/CHANGELOG.md b/packages/twenty-zapier/CHANGELOG.md index 7a953398de5..d7f5e12c84a 100644 --- a/packages/twenty-zapier/CHANGELOG.md +++ b/packages/twenty-zapier/CHANGELOG.md @@ -1,16 +1,21 @@ ## 2.2.0 -* Fix authentication issue + +- Fix authentication issue ## 2.1.1 -* Add changelog + +- Add changelog ## 2.1.0 -* Fix some authentication issues -* Remove position from input fields -* Fix required boolean fields that should not be + +- Fix some authentication issues +- Remove position from input fields +- Fix required boolean fields that should not be ## 2.0.0 -* First release + +- First release ## 1.0.0 + Initial release to public. diff --git a/packages/twenty-zapier/project.json b/packages/twenty-zapier/project.json index f5f178245da..b0edda76245 100644 --- a/packages/twenty-zapier/project.json +++ b/packages/twenty-zapier/project.json @@ -23,9 +23,7 @@ "executor": "nx:run-commands", "options": { "cwd": "{projectRoot}", - "commands": [ - "NODE_ENV=test jest --testTimeout 10000" - ] + "commands": ["NODE_ENV=test jest --testTimeout 10000"] } }, "lint": {}, diff --git a/yarn.lock b/yarn.lock index ed665f04bbf..2d779f2be27 100644 --- a/yarn.lock +++ b/yarn.lock @@ -55779,6 +55779,12 @@ __metadata: languageName: unknown linkType: soft +"twenty-oxlint-rules@workspace:packages/twenty-oxlint-rules": + version: 0.0.0-use.local + resolution: "twenty-oxlint-rules@workspace:packages/twenty-oxlint-rules" + languageName: unknown + linkType: soft + "twenty-sdk@workspace:*, twenty-sdk@workspace:packages/twenty-sdk": version: 0.0.0-use.local resolution: "twenty-sdk@workspace:packages/twenty-sdk"
{content}