Compare commits
13
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dd174a6099 | ||
|
|
a06b35c70d | ||
|
|
06451407ce | ||
|
|
59029a0035 | ||
|
|
cac4999e9f | ||
|
|
403db7ad3f | ||
|
|
ef499b6d47 | ||
|
|
9f9a6a45dd | ||
|
|
1f1da901ea | ||
|
|
f65aafe96b | ||
|
|
a79b816117 | ||
|
|
d37ed7e07c | ||
|
|
d825ac06dd |
@@ -19,7 +19,12 @@ runs:
|
||||
shell: bash
|
||||
run: git fetch origin main --depth=1
|
||||
- name: Get last successful commit
|
||||
if: env.NX_BASE == ''
|
||||
uses: nrwl/nx-set-shas@v4
|
||||
- name: Fallback to origin/main if no base found
|
||||
if: env.NX_BASE == ''
|
||||
shell: bash
|
||||
run: echo "NX_BASE=$(git rev-parse origin/main)" >> $GITHUB_ENV
|
||||
- name: Run affected command
|
||||
shell: bash
|
||||
env:
|
||||
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
needs: changed-files-check
|
||||
if: needs.changed-files-check.outputs.any_changed == 'true'
|
||||
timeout-minutes: 10
|
||||
runs-on: ubuntu-latest-8-cores
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
name: CI Front and E2E
|
||||
name: CI Front
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
merge_group:
|
||||
|
||||
permissions:
|
||||
@@ -19,6 +18,7 @@ env:
|
||||
|
||||
jobs:
|
||||
changed-files-check:
|
||||
if: github.event_name != 'merge_group'
|
||||
uses: ./.github/workflows/changed-files.yaml
|
||||
with:
|
||||
files: |
|
||||
@@ -29,15 +29,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'
|
||||
@@ -74,7 +65,7 @@ jobs:
|
||||
key: ${{ env.STORYBOOK_BUILD_CACHE_KEY_FOR_SAVE_ACTION }}
|
||||
front-sb-test:
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-latest-8-cores
|
||||
runs-on: ubuntu-latest-4-cores
|
||||
needs: front-sb-build
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -160,32 +151,6 @@ jobs:
|
||||
# npx nyc merge coverage-artifacts ${{ env.PATH_TO_COVERAGE }}/coverage-storybook.json
|
||||
# - name: Checking coverage
|
||||
# run: npx nx storybook:coverage twenty-front --checkCoverage=true --configuration=${{ matrix.storybook_scope }}
|
||||
front-chromatic-deployment:
|
||||
timeout-minutes: 30
|
||||
if: false
|
||||
needs: front-sb-build
|
||||
runs-on: ubuntu-latest-8-cores
|
||||
env:
|
||||
REACT_APP_SERVER_BASE_URL: http://127.0.0.1:3000
|
||||
CHROMATIC_PROJECT_TOKEN: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 10
|
||||
- name: Install dependencies
|
||||
uses: ./.github/actions/yarn-install
|
||||
- name: Restore storybook build cache
|
||||
uses: ./.github/actions/restore-cache
|
||||
with:
|
||||
key: ${{ env.STORYBOOK_BUILD_CACHE_KEY_FOR_RESTORE_ACTION }}
|
||||
- name: Front / Write .env
|
||||
run: |
|
||||
cd packages/twenty-front
|
||||
touch .env
|
||||
echo "" >> .env
|
||||
echo "REACT_APP_SERVER_BASE_URL=$REACT_APP_SERVER_BASE_URL" >> .env
|
||||
- name: Publish to Chromatic
|
||||
run: npx nx run twenty-front:chromatic:ci
|
||||
front-task:
|
||||
needs: changed-files-check
|
||||
if: needs.changed-files-check.outputs.any_changed == 'true'
|
||||
@@ -257,117 +222,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 +239,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
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
name: CI Merge Queue
|
||||
|
||||
on:
|
||||
merge_group:
|
||||
|
||||
pull_request:
|
||||
types: [labeled, synchronize, opened, reopened]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event_name == 'merge_group' && github.event.merge_group.base_ref || 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: Restore Nx build cache
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
key: v4-e2e-build-${{ github.ref_name }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
v4-e2e-build-${{ github.ref_name }}-
|
||||
v4-e2e-build-main-
|
||||
path: |
|
||||
.nx
|
||||
node_modules/.cache
|
||||
packages/*/node_modules/.cache
|
||||
|
||||
- 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: Save Nx build cache
|
||||
if: always()
|
||||
uses: actions/cache/save@v4
|
||||
with:
|
||||
key: v4-e2e-build-${{ github.ref_name }}-${{ github.sha }}
|
||||
path: |
|
||||
.nx
|
||||
node_modules/.cache
|
||||
packages/*/node_modules/.cache
|
||||
|
||||
- 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
|
||||
@@ -1,9 +1,8 @@
|
||||
name: CI SDK
|
||||
|
||||
on:
|
||||
merge_group:
|
||||
|
||||
pull_request:
|
||||
merge_group:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -14,10 +13,12 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
changed-files-check:
|
||||
if: github.event_name != 'merge_group'
|
||||
uses: ./.github/workflows/changed-files.yaml
|
||||
with:
|
||||
files: |
|
||||
packages/twenty-sdk/**
|
||||
packages/twenty-server/**
|
||||
!packages/twenty-sdk/package.json
|
||||
sdk-test:
|
||||
needs: changed-files-check
|
||||
@@ -50,7 +51,7 @@ jobs:
|
||||
tasks: ${{ matrix.task }}
|
||||
sdk-e2e-test:
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-latest-8-cores
|
||||
runs-on: ubuntu-latest-4-cores
|
||||
needs: [changed-files-check, sdk-test]
|
||||
if: needs.changed-files-check.outputs.any_changed == 'true'
|
||||
services:
|
||||
|
||||
@@ -2,7 +2,6 @@ name: CI Server
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
merge_group:
|
||||
|
||||
permissions:
|
||||
@@ -17,6 +16,7 @@ env:
|
||||
|
||||
jobs:
|
||||
changed-files-check:
|
||||
if: github.event_name != 'merge_group'
|
||||
uses: ./.github/workflows/changed-files.yaml
|
||||
with:
|
||||
files: |
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
needs: changed-files-check
|
||||
if: needs.changed-files-check.outputs.any_changed == 'true'
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-latest-8-cores
|
||||
runs-on: ubuntu-latest-4-cores
|
||||
steps:
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
@@ -60,7 +60,7 @@ jobs:
|
||||
needs: changed-files-check
|
||||
if: needs.changed-files-check.outputs.any_changed == 'true'
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-latest-8-cores
|
||||
runs-on: ubuntu-latest-4-cores
|
||||
steps:
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
@@ -79,7 +79,7 @@ jobs:
|
||||
server-validation:
|
||||
needs: server-build
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-latest-8-cores
|
||||
runs-on: ubuntu-latest-4-cores
|
||||
services:
|
||||
postgres:
|
||||
image: twentycrm/twenty-postgres-spilo
|
||||
@@ -179,7 +179,7 @@ jobs:
|
||||
server-test:
|
||||
needs: server-build
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-latest-8-cores
|
||||
runs-on: ubuntu-latest-4-cores
|
||||
steps:
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
@@ -201,7 +201,7 @@ jobs:
|
||||
|
||||
server-integration-test:
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-latest-8-cores
|
||||
runs-on: ubuntu-latest-4-cores
|
||||
needs: server-build
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
name: CI Shared
|
||||
|
||||
on:
|
||||
merge_group:
|
||||
|
||||
pull_request:
|
||||
merge_group:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -14,6 +13,7 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
changed-files-check:
|
||||
if: github.event_name != 'merge_group'
|
||||
uses: ./.github/workflows/changed-files.yaml
|
||||
with:
|
||||
files: |
|
||||
|
||||
@@ -4,9 +4,8 @@ permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
merge_group:
|
||||
|
||||
pull_request:
|
||||
merge_group:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
@@ -14,6 +13,7 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
changed-files-check:
|
||||
if: github.event_name != 'merge_group'
|
||||
uses: ./.github/workflows/changed-files.yaml
|
||||
with:
|
||||
files: |
|
||||
|
||||
@@ -4,9 +4,8 @@ permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
merge_group:
|
||||
|
||||
pull_request:
|
||||
merge_group:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
@@ -14,6 +13,7 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
changed-files-check:
|
||||
if: github.event_name != 'merge_group'
|
||||
uses: ./.github/workflows/changed-files.yaml
|
||||
with:
|
||||
files: |
|
||||
|
||||
@@ -3,8 +3,6 @@ name: CI Zapier
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
merge_group:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
@@ -28,7 +26,7 @@ jobs:
|
||||
needs: changed-files-check
|
||||
if: needs.changed-files-check.outputs.any_changed == 'true'
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-latest-8-cores
|
||||
runs-on: ubuntu-latest-4-cores
|
||||
services:
|
||||
postgres:
|
||||
image: twentycrm/twenty-postgres-spilo
|
||||
|
||||
@@ -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)"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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": "^_"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
dist
|
||||
@@ -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,10 @@ 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 |
|
||||
| `-m, --minimal` | Creates only core files (`application-config.ts` and `default-role.ts`) |
|
||||
|
||||
```bash
|
||||
# Default: all examples included
|
||||
@@ -76,24 +77,12 @@ npx create-twenty-app@latest my-app
|
||||
|
||||
# Minimal: only core files
|
||||
npx create-twenty-app@latest my-app -m
|
||||
|
||||
# Interactive: choose which examples to include
|
||||
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`)
|
||||
- **Example front component** — a React UI component (`front-components/hello-world.tsx`)
|
||||
- **Example view** — a saved view for the example object (`views/example-view.ts`)
|
||||
- **Example navigation menu item** — a sidebar link (`navigation-menu-items/example-navigation-menu-item.ts`)
|
||||
- **Example skill** — an AI agent skill definition (`skills/example-skill.ts`)
|
||||
- **Integration test** — a vitest integration test verifying app installation (`__tests__/app-install.integration-test.ts`)
|
||||
|
||||
## 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 +91,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 +102,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 +135,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)
|
||||
|
||||
@@ -18,10 +18,6 @@ const program = new Command(packageJson.name)
|
||||
'-m, --minimal',
|
||||
'Create only core entities (application-config and default-role)',
|
||||
)
|
||||
.option(
|
||||
'-i, --interactive',
|
||||
'Interactively choose which entity examples to include',
|
||||
)
|
||||
.helpOption('-h, --help', 'Display this help message.')
|
||||
.action(
|
||||
async (
|
||||
@@ -29,19 +25,14 @@ const program = new Command(packageJson.name)
|
||||
options?: {
|
||||
exhaustive?: boolean;
|
||||
minimal?: boolean;
|
||||
interactive?: boolean;
|
||||
},
|
||||
) => {
|
||||
const modeFlags = [
|
||||
options?.exhaustive,
|
||||
options?.minimal,
|
||||
options?.interactive,
|
||||
].filter(Boolean);
|
||||
const modeFlags = [options?.exhaustive, options?.minimal].filter(Boolean);
|
||||
|
||||
if (modeFlags.length > 1) {
|
||||
console.error(
|
||||
chalk.red(
|
||||
'Error: --exhaustive, --minimal, and --interactive are mutually exclusive.',
|
||||
'Error: --exhaustive and --minimal are mutually exclusive.',
|
||||
),
|
||||
);
|
||||
process.exit(1);
|
||||
@@ -56,11 +47,7 @@ const program = new Command(packageJson.name)
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const mode: ScaffoldingMode = options?.minimal
|
||||
? 'minimal'
|
||||
: options?.interactive
|
||||
? 'interactive'
|
||||
: 'exhaustive';
|
||||
const mode: ScaffoldingMode = options?.minimal ? 'minimal' : 'exhaustive';
|
||||
|
||||
await new CreateAppCommand().execute(directory, mode);
|
||||
},
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ export class CreateAppCommand {
|
||||
const { appName, appDisplayName, appDirectory, appDescription } =
|
||||
await this.getAppInfos(directory);
|
||||
|
||||
const exampleOptions = await this.resolveExampleOptions(mode);
|
||||
const exampleOptions = this.resolveExampleOptions(mode);
|
||||
|
||||
await this.validateDirectory(appDirectory);
|
||||
|
||||
@@ -103,9 +103,7 @@ export class CreateAppCommand {
|
||||
return { appName, appDisplayName, appDirectory, appDescription };
|
||||
}
|
||||
|
||||
private async resolveExampleOptions(
|
||||
mode: ScaffoldingMode,
|
||||
): Promise<ExampleOptions> {
|
||||
private resolveExampleOptions(mode: ScaffoldingMode): ExampleOptions {
|
||||
if (mode === 'minimal') {
|
||||
return {
|
||||
includeExampleObject: false,
|
||||
@@ -119,94 +117,15 @@ export class CreateAppCommand {
|
||||
};
|
||||
}
|
||||
|
||||
if (mode === 'exhaustive') {
|
||||
return {
|
||||
includeExampleObject: true,
|
||||
includeExampleField: true,
|
||||
includeExampleLogicFunction: true,
|
||||
includeExampleFrontComponent: true,
|
||||
includeExampleView: true,
|
||||
includeExampleNavigationMenuItem: true,
|
||||
includeExampleSkill: true,
|
||||
includeExampleIntegrationTest: true,
|
||||
};
|
||||
}
|
||||
|
||||
const { selectedExamples } = await inquirer.prompt([
|
||||
{
|
||||
type: 'checkbox',
|
||||
name: 'selectedExamples',
|
||||
message: 'Select which example files to include:',
|
||||
choices: [
|
||||
{
|
||||
name: 'Example object (custom object definition)',
|
||||
value: 'object',
|
||||
checked: true,
|
||||
},
|
||||
{
|
||||
name: 'Example field (custom field on the example object)',
|
||||
value: 'field',
|
||||
checked: true,
|
||||
},
|
||||
{
|
||||
name: 'Example logic function (server-side handler)',
|
||||
value: 'logicFunction',
|
||||
checked: true,
|
||||
},
|
||||
{
|
||||
name: 'Example front component (React UI component)',
|
||||
value: 'frontComponent',
|
||||
checked: true,
|
||||
},
|
||||
{
|
||||
name: 'Example view (saved view for the example object)',
|
||||
value: 'view',
|
||||
checked: true,
|
||||
},
|
||||
{
|
||||
name: 'Example navigation menu item (sidebar link)',
|
||||
value: 'navigationMenuItem',
|
||||
checked: true,
|
||||
},
|
||||
{
|
||||
name: 'Example skill (AI agent skill definition)',
|
||||
value: 'skill',
|
||||
checked: true,
|
||||
},
|
||||
{
|
||||
name: 'Integration test (vitest test verifying app installation)',
|
||||
value: 'integrationTest',
|
||||
checked: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
const includeField = selectedExamples.includes('field');
|
||||
const includeView = selectedExamples.includes('view');
|
||||
const includeExampleIntegrationTest =
|
||||
selectedExamples.includes('integrationTest');
|
||||
const includeObject =
|
||||
selectedExamples.includes('object') || includeField || includeView;
|
||||
|
||||
if ((includeField || includeView) && !selectedExamples.includes('object')) {
|
||||
console.log(
|
||||
chalk.yellow(
|
||||
'Note: Example object auto-included because example field/view depends on it.',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
includeExampleObject: includeObject,
|
||||
includeExampleField: includeField,
|
||||
includeExampleLogicFunction: selectedExamples.includes('logicFunction'),
|
||||
includeExampleFrontComponent: selectedExamples.includes('frontComponent'),
|
||||
includeExampleView: includeView,
|
||||
includeExampleNavigationMenuItem:
|
||||
selectedExamples.includes('navigationMenuItem'),
|
||||
includeExampleSkill: selectedExamples.includes('skill'),
|
||||
includeExampleIntegrationTest,
|
||||
includeExampleObject: true,
|
||||
includeExampleField: true,
|
||||
includeExampleLogicFunction: true,
|
||||
includeExampleFrontComponent: true,
|
||||
includeExampleView: true,
|
||||
includeExampleNavigationMenuItem: true,
|
||||
includeExampleSkill: true,
|
||||
includeExampleIntegrationTest: true,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export type ScaffoldingMode = 'exhaustive' | 'minimal' | 'interactive';
|
||||
export type ScaffoldingMode = 'exhaustive' | 'minimal';
|
||||
|
||||
export type ExampleOptions = {
|
||||
includeExampleObject: boolean;
|
||||
|
||||
@@ -673,15 +673,24 @@ describe('copyBaseApplicationProject', () => {
|
||||
|
||||
const content = await fs.readFile(viewPath, 'utf8');
|
||||
|
||||
expect(content).toContain("import { defineView } from 'twenty-sdk'");
|
||||
expect(content).toContain(
|
||||
"import { EXAMPLE_OBJECT_UNIVERSAL_IDENTIFIER } from 'src/objects/example-object'",
|
||||
"import { defineView, ViewKey } from 'twenty-sdk'",
|
||||
);
|
||||
expect(content).toContain(
|
||||
"import { EXAMPLE_OBJECT_UNIVERSAL_IDENTIFIER, NAME_FIELD_UNIVERSAL_IDENTIFIER } from 'src/objects/example-object'",
|
||||
);
|
||||
expect(content).toContain('export default defineView({');
|
||||
expect(content).toContain(
|
||||
'objectUniversalIdentifier: EXAMPLE_OBJECT_UNIVERSAL_IDENTIFIER',
|
||||
);
|
||||
expect(content).toContain("name: 'example-view'");
|
||||
expect(content).toContain("name: 'All example items'");
|
||||
expect(content).toContain('fields: [');
|
||||
expect(content).toContain(
|
||||
'fieldMetadataUniversalIdentifier: NAME_FIELD_UNIVERSAL_IDENTIFIER',
|
||||
);
|
||||
expect(content).toContain('isVisible: true');
|
||||
expect(content).toContain('key: ViewKey.INDEX');
|
||||
expect(content).toContain('size: 200');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -712,6 +721,7 @@ describe('copyBaseApplicationProject', () => {
|
||||
expect(content).toContain('export default defineNavigationMenuItem({');
|
||||
expect(content).toContain("name: 'example-navigation-menu-item'");
|
||||
expect(content).toContain("icon: 'IconList'");
|
||||
expect(content).toContain("color: 'blue'");
|
||||
expect(content).toContain('position: 0');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -431,16 +431,29 @@ const createExampleView = async ({
|
||||
fileName: string;
|
||||
}) => {
|
||||
const universalIdentifier = v4();
|
||||
const viewFieldUniversalIdentifier = v4();
|
||||
|
||||
const content = `import { defineView } from 'twenty-sdk';
|
||||
import { EXAMPLE_OBJECT_UNIVERSAL_IDENTIFIER } from 'src/objects/example-object';
|
||||
const content = `import { defineView, ViewKey } from 'twenty-sdk';
|
||||
import { EXAMPLE_OBJECT_UNIVERSAL_IDENTIFIER, NAME_FIELD_UNIVERSAL_IDENTIFIER } from 'src/objects/example-object';
|
||||
|
||||
export const EXAMPLE_VIEW_UNIVERSAL_IDENTIFIER = '${universalIdentifier}';
|
||||
|
||||
export default defineView({
|
||||
universalIdentifier: '${universalIdentifier}',
|
||||
name: 'example-view',
|
||||
universalIdentifier: EXAMPLE_VIEW_UNIVERSAL_IDENTIFIER,
|
||||
name: 'All example items',
|
||||
objectUniversalIdentifier: EXAMPLE_OBJECT_UNIVERSAL_IDENTIFIER,
|
||||
icon: 'IconList',
|
||||
key: ViewKey.INDEX,
|
||||
position: 0,
|
||||
fields: [
|
||||
{
|
||||
universalIdentifier: '${viewFieldUniversalIdentifier}',
|
||||
fieldMetadataUniversalIdentifier: NAME_FIELD_UNIVERSAL_IDENTIFIER,
|
||||
position: 0,
|
||||
isVisible: true,
|
||||
size: 200,
|
||||
},
|
||||
],
|
||||
});
|
||||
`;
|
||||
|
||||
@@ -460,18 +473,15 @@ const createExampleNavigationMenuItem = async ({
|
||||
const universalIdentifier = v4();
|
||||
|
||||
const content = `import { defineNavigationMenuItem } from 'twenty-sdk';
|
||||
import { EXAMPLE_VIEW_UNIVERSAL_IDENTIFIER } from 'src/views/example-view';
|
||||
|
||||
export default defineNavigationMenuItem({
|
||||
universalIdentifier: '${universalIdentifier}',
|
||||
name: 'example-navigation-menu-item',
|
||||
icon: 'IconList',
|
||||
color: 'blue',
|
||||
position: 0,
|
||||
// Link to a view:
|
||||
// viewUniversalIdentifier: '...',
|
||||
// Or link to an object:
|
||||
// targetObjectUniversalIdentifier: '...',
|
||||
// Or link to an external URL:
|
||||
// link: 'https://example.com',
|
||||
viewUniversalIdentifier: EXAMPLE_VIEW_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
`;
|
||||
|
||||
|
||||
@@ -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"]
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ cd my-twenty-app
|
||||
yarn twenty app:dev
|
||||
```
|
||||
|
||||
The scaffolder supports three modes for controlling which example files are included:
|
||||
The scaffolder supports two modes for controlling which example files are included:
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Default (exhaustive): all examples (object, field, logic function, front component, view, navigation menu item, skill)
|
||||
@@ -43,9 +43,6 @@ npx create-twenty-app@latest my-app
|
||||
|
||||
# Minimal: only core files (application-config.ts and default-role.ts)
|
||||
npx create-twenty-app@latest my-app --minimal
|
||||
|
||||
# Interactive: select which examples to include
|
||||
npx create-twenty-app@latest my-app --interactive
|
||||
```
|
||||
|
||||
From here you can:
|
||||
@@ -121,7 +118,7 @@ my-twenty-app/
|
||||
└── example-skill.ts # Example AI agent skill definition
|
||||
```
|
||||
|
||||
With `--minimal`, only the core files are created (`application-config.ts`, `roles/default-role.ts`, `logic-functions/pre-install.ts`, and `logic-functions/post-install.ts`). With `--interactive`, you choose which example files to include.
|
||||
With `--minimal`, only the core files are created (`application-config.ts`, `roles/default-role.ts`, `logic-functions/pre-install.ts`, and `logic-functions/post-install.ts`).
|
||||
|
||||
At a high level:
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ cd my-twenty-app
|
||||
yarn twenty app:dev
|
||||
```
|
||||
|
||||
يدعم المُنشئ ثلاثة أوضاع للتحكم في ملفات الأمثلة التي سيتم تضمينها:
|
||||
يدعم المُنشئ وضعين للتحكم في ملفات الأمثلة التي سيتم تضمينها:
|
||||
|
||||
```bash filename="Terminal"
|
||||
# الافتراضي (شامل): جميع الأمثلة (كائن، حقل، دالة منطقية، مكوّن الواجهة الأمامية، عرض، عنصر قائمة التنقل، مهارة)
|
||||
@@ -44,9 +44,6 @@ npx create-twenty-app@latest my-app
|
||||
|
||||
# الأدنى: الملفات الأساسية فقط (application-config.ts و default-role.ts)
|
||||
npx create-twenty-app@latest my-app --minimal
|
||||
|
||||
# التفاعلي: اختر الأمثلة التي تريد تضمينها
|
||||
npx create-twenty-app@latest my-app --interactive
|
||||
```
|
||||
|
||||
من هنا يمكنك:
|
||||
@@ -122,7 +119,7 @@ my-twenty-app/
|
||||
└── example-skill.ts # تعريف مهارة لوكيل الذكاء الاصطناعي — مثال},{
|
||||
```
|
||||
|
||||
مع `--minimal`، سيتم إنشاء الملفات الأساسية فقط (`application-config.ts`، `roles/default-role.ts`، `logic-functions/pre-install.ts`، و`logic-functions/post-install.ts`). مع `--interactive`، تختار ملفات الأمثلة التي تريد تضمينها.
|
||||
مع `--minimal`، سيتم إنشاء الملفات الأساسية فقط (`application-config.ts`، `roles/default-role.ts`، `logic-functions/pre-install.ts`، و`logic-functions/post-install.ts`).
|
||||
|
||||
بشكل عام:
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ cd my-twenty-app
|
||||
yarn twenty app:dev
|
||||
```
|
||||
|
||||
Nástroj pro generování kostry podporuje tři režimy pro řízení toho, které ukázkové soubory jsou zahrnuty:
|
||||
Nástroj pro generování kostry podporuje dva režimy pro řízení toho, které ukázkové soubory jsou zahrnuty:
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Výchozí (úplný): všechny příklady (objekt, pole, logická funkce, front-endová komponenta, zobrazení, položka navigační nabídky, dovednost)
|
||||
@@ -44,9 +44,6 @@ npx create-twenty-app@latest my-app
|
||||
|
||||
# Minimální: pouze základní soubory (application-config.ts a default-role.ts)
|
||||
npx create-twenty-app@latest my-app --minimal
|
||||
|
||||
# Interaktivní: vyberte, které příklady zahrnout
|
||||
npx create-twenty-app@latest my-app --interactive
|
||||
```
|
||||
|
||||
Odtud můžete:
|
||||
@@ -122,7 +119,7 @@ my-twenty-app/
|
||||
└── example-skill.ts # Ukázková definice dovednosti agenta AI
|
||||
```
|
||||
|
||||
S volbou `--minimal` se vytvoří pouze základní soubory (`application-config.ts`, `roles/default-role.ts`, `logic-functions/pre-install.ts` a `logic-functions/post-install.ts`). S volbou `--interactive` si vyberete, které ukázkové soubory chcete zahrnout.
|
||||
S volbou `--minimal` se vytvoří pouze základní soubory (`application-config.ts`, `roles/default-role.ts`, `logic-functions/pre-install.ts` a `logic-functions/post-install.ts`).
|
||||
|
||||
V kostce:
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ cd my-twenty-app
|
||||
yarn twenty app:dev
|
||||
```
|
||||
|
||||
Das Scaffolding-Tool unterstützt drei Modi, um zu steuern, welche Beispieldateien enthalten sind:
|
||||
Das Scaffolding-Tool unterstützt zwei Modi, um zu steuern, welche Beispieldateien enthalten sind:
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Standard (umfassend): alle Beispiele (Objekt, Feld, Logikfunktion, Frontend-Komponente, View, Navigationsmenüeintrag, Skill)
|
||||
@@ -44,9 +44,6 @@ npx create-twenty-app@latest my-app
|
||||
|
||||
# Minimal: nur Kerndateien (application-config.ts und default-role.ts)
|
||||
npx create-twenty-app@latest my-app --minimal
|
||||
|
||||
# Interaktiv: wähle aus, welche Beispiele enthalten sein sollen
|
||||
npx create-twenty-app@latest my-app --interactive
|
||||
```
|
||||
|
||||
Von hier aus können Sie:
|
||||
@@ -122,7 +119,7 @@ my-twenty-app/
|
||||
└── example-skill.ts # Example AI agent skill definition
|
||||
```
|
||||
|
||||
Mit `--minimal` werden nur die Kerndateien erstellt (`application-config.ts`, `roles/default-role.ts`, `logic-functions/pre-install.ts` und `logic-functions/post-install.ts`). Mit `--interactive` wählst du aus, welche Beispieldateien enthalten sein sollen.
|
||||
Mit `--minimal` werden nur die Kerndateien erstellt (`application-config.ts`, `roles/default-role.ts`, `logic-functions/pre-install.ts` und `logic-functions/post-install.ts`).
|
||||
|
||||
Auf hoher Ebene:
|
||||
|
||||
|
||||
@@ -36,17 +36,14 @@ cd my-twenty-app
|
||||
yarn twenty app:dev
|
||||
```
|
||||
|
||||
Lo strumento di scaffolding supporta tre modalità per controllare quali file di esempio vengono inclusi:
|
||||
Lo strumento di scaffolding supporta due modalità per controllare quali file di esempio vengono inclusi:
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Default (exhaustive): all examples (object, field, logic function, front component, view, navigation menu item, skill)
|
||||
# Predefinita (esaustiva): tutti gli esempi (oggetto, campo, funzione logica, componente front-end, vista, voce del menu di navigazione, skill)
|
||||
npx create-twenty-app@latest my-app
|
||||
|
||||
# Minimal: only core files (application-config.ts and default-role.ts)
|
||||
# Minimale: solo i file principali (application-config.ts e default-role.ts)
|
||||
npx create-twenty-app@latest my-app --minimal
|
||||
|
||||
# Interactive: select which examples to include
|
||||
npx create-twenty-app@latest my-app --interactive
|
||||
```
|
||||
|
||||
Da qui puoi:
|
||||
@@ -122,7 +119,7 @@ my-twenty-app/
|
||||
└── example-skill.ts # Example AI agent skill definition
|
||||
```
|
||||
|
||||
Con `--minimal`, vengono creati solo i file principali (`application-config.ts`, `roles/default-role.ts`, `logic-functions/pre-install.ts` e `logic-functions/post-install.ts`). Con `--interactive`, scegli quali file di esempio includere.
|
||||
Con `--minimal`, vengono creati solo i file principali (`application-config.ts`, `roles/default-role.ts`, `logic-functions/pre-install.ts` e `logic-functions/post-install.ts`).
|
||||
|
||||
A livello generale:
|
||||
|
||||
|
||||
@@ -36,17 +36,14 @@ cd my-twenty-app
|
||||
yarn twenty app:dev
|
||||
```
|
||||
|
||||
O gerador de estrutura oferece suporte a três modos para controlar quais arquivos de exemplo são incluídos:
|
||||
The scaffolder supports two modes for controlling which example files are included:
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Padrão (exhaustivo): todos os exemplos (objeto, campo, função de lógica, componente de front-end, visualização, item do menu de navegação, habilidade)
|
||||
# Default (exhaustive): all examples (object, field, logic function, front component, view, navigation menu item, skill)
|
||||
npx create-twenty-app@latest my-app
|
||||
|
||||
# Mínimo: apenas arquivos principais (application-config.ts e default-role.ts)
|
||||
# Minimal: only core files (application-config.ts and default-role.ts)
|
||||
npx create-twenty-app@latest my-app --minimal
|
||||
|
||||
# Interativo: selecione quais exemplos incluir
|
||||
npx create-twenty-app@latest my-app --interactive
|
||||
```
|
||||
|
||||
A partir daqui você pode:
|
||||
@@ -122,7 +119,7 @@ my-twenty-app/
|
||||
└── example-skill.ts # Exemplo de definição de habilidade de agente de IA
|
||||
```
|
||||
|
||||
With `--minimal`, only the core files are created (`application-config.ts`, `roles/default-role.ts`, `logic-functions/pre-install.ts`, and `logic-functions/post-install.ts`). Com `--interactive`, você escolhe quais arquivos de exemplo incluir.
|
||||
With `--minimal`, only the core files are created (`application-config.ts`, `roles/default-role.ts`, `logic-functions/pre-install.ts`, and `logic-functions/post-install.ts`).
|
||||
|
||||
Em alto nível:
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ cd my-twenty-app
|
||||
yarn twenty app:dev
|
||||
```
|
||||
|
||||
Generatorul de schelet acceptă trei moduri pentru a controla ce fișiere de exemplu sunt incluse:
|
||||
Generatorul de schelet acceptă două moduri pentru a controla ce fișiere de exemplu sunt incluse:
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Implicit (exhaustiv): toate exemplele (obiect, câmp, funcție logică, componentă de interfață, vizualizare, element de meniu de navigare, abilitate)
|
||||
@@ -44,9 +44,6 @@ npx create-twenty-app@latest my-app
|
||||
|
||||
# Minimal: doar fișierele de bază (application-config.ts și default-role.ts)
|
||||
npx create-twenty-app@latest my-app --minimal
|
||||
|
||||
# Interactiv: selectezi ce exemple să incluzi
|
||||
npx create-twenty-app@latest my-app --interactive
|
||||
```
|
||||
|
||||
De aici puteți:
|
||||
@@ -122,7 +119,7 @@ my-twenty-app/
|
||||
└── example-skill.ts # Example AI agent skill definition
|
||||
```
|
||||
|
||||
Cu `--minimal`, sunt create doar fișierele de bază (`application-config.ts`, `roles/default-role.ts`, `logic-functions/pre-install.ts` și `logic-functions/post-install.ts`). Cu `--interactive`, alegi ce fișiere de exemplu să incluzi.
|
||||
Cu `--minimal`, sunt create doar fișierele de bază (`application-config.ts`, `roles/default-role.ts`, `logic-functions/pre-install.ts` și `logic-functions/post-install.ts`).
|
||||
|
||||
Pe scurt:
|
||||
|
||||
|
||||
@@ -36,17 +36,14 @@ cd my-twenty-app
|
||||
yarn twenty app:dev
|
||||
```
|
||||
|
||||
Генератор каркаса поддерживает три режима для управления тем, какие примерные файлы включаются:
|
||||
The scaffolder supports two modes for controlling which example files are included:
|
||||
|
||||
```bash filename="Terminal"
|
||||
# По умолчанию (полный набор): все примеры (объект, поле, логическая функция, фронтенд-компонент, представление, пункт меню навигации, навык)
|
||||
# Default (exhaustive): all examples (object, field, logic function, front component, view, navigation menu item, skill)
|
||||
npx create-twenty-app@latest my-app
|
||||
|
||||
# Минимальный: только основные файлы (application-config.ts и default-role.ts)
|
||||
# Minimal: only core files (application-config.ts and default-role.ts)
|
||||
npx create-twenty-app@latest my-app --minimal
|
||||
|
||||
# Интерактивный: выбрать, какие примеры включить
|
||||
npx create-twenty-app@latest my-app --interactive
|
||||
```
|
||||
|
||||
Отсюда вы можете:
|
||||
@@ -122,7 +119,7 @@ my-twenty-app/
|
||||
└── example-skill.ts # Example AI agent skill definition
|
||||
```
|
||||
|
||||
С `--minimal` создаются только основные файлы (`application-config.ts`, `roles/default-role.ts`, `logic-functions/pre-install.ts` и `logic-functions/post-install.ts`). С `--interactive` вы выбираете, какие примерные файлы включить.
|
||||
С `--minimal` создаются только основные файлы (`application-config.ts`, `roles/default-role.ts`, `logic-functions/pre-install.ts` и `logic-functions/post-install.ts`).
|
||||
|
||||
В общих чертах:
|
||||
|
||||
|
||||
@@ -36,17 +36,14 @@ cd my-twenty-app
|
||||
yarn twenty app:dev
|
||||
```
|
||||
|
||||
İskelet oluşturucu, hangi örnek dosyaların dahil edileceğini kontrol etmek için üç modu destekler:
|
||||
The scaffolder supports two modes for controlling which example files are included:
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Varsayılan (kapsamlı): tüm örnekler (nesne, alan, mantık fonksiyonu, ön bileşen, görünüm, gezinme menüsü öğesi, yetenek)
|
||||
# Default (exhaustive): all examples (object, field, logic function, front component, view, navigation menu item, skill)
|
||||
npx create-twenty-app@latest my-app
|
||||
|
||||
# Minimal: yalnızca çekirdek dosyalar (application-config.ts ve default-role.ts)
|
||||
# Minimal: only core files (application-config.ts and default-role.ts)
|
||||
npx create-twenty-app@latest my-app --minimal
|
||||
|
||||
# Etkileşimli: dahil edilecek örnekleri seçin
|
||||
npx create-twenty-app@latest my-app --interactive
|
||||
```
|
||||
|
||||
Buradan şunları yapabilirsiniz:
|
||||
@@ -122,7 +119,7 @@ my-twenty-app/
|
||||
└── example-skill.ts # Örnek yapay zekâ ajanı yetenek tanımı
|
||||
```
|
||||
|
||||
`--minimal` ile yalnızca çekirdek dosyalar oluşturulur (`application-config.ts`, `roles/default-role.ts`, `logic-functions/pre-install.ts` ve `logic-functions/post-install.ts`). `--interactive` ile hangi örnek dosyaların dahil edileceğini siz seçersiniz.
|
||||
`--minimal` ile yalnızca çekirdek dosyalar oluşturulur (`application-config.ts`, `roles/default-role.ts`, `logic-functions/pre-install.ts` ve `logic-functions/post-install.ts`).
|
||||
|
||||
Genel hatlarıyla:
|
||||
|
||||
|
||||
@@ -36,17 +36,14 @@ cd my-twenty-app
|
||||
yarn twenty app:dev
|
||||
```
|
||||
|
||||
The scaffolder supports three modes for controlling which example files are included:
|
||||
The scaffolder supports two modes for controlling which example files are included:
|
||||
|
||||
```bash filename="Terminal"
|
||||
# 默认(完整):所有示例(对象、字段、逻辑函数、前端组件、视图、导航菜单项、技能)
|
||||
# Default (exhaustive): all examples (object, field, logic function, front component, view, navigation menu item, skill)
|
||||
npx create-twenty-app@latest my-app
|
||||
|
||||
# 最小化:仅核心文件(application-config.ts 和 default-role.ts)
|
||||
# Minimal: only core files (application-config.ts and default-role.ts)
|
||||
npx create-twenty-app@latest my-app --minimal
|
||||
|
||||
# 交互式:选择要包含的示例
|
||||
npx create-twenty-app@latest my-app --interactive
|
||||
```
|
||||
|
||||
从这里您可以:
|
||||
@@ -122,7 +119,7 @@ my-twenty-app/
|
||||
└── example-skill.ts # Example AI agent skill definition
|
||||
```
|
||||
|
||||
使用 `--minimal` 时,只会创建核心文件(`application-config.ts`、`roles/default-role.ts`、`logic-functions/pre-install.ts` 和 `logic-functions/post-install.ts`)。 With `--interactive`, you choose which example files to include.
|
||||
使用 `--minimal` 时,只会创建核心文件(`application-config.ts`、`roles/default-role.ts`、`logic-functions/pre-install.ts` 和 `logic-functions/post-install.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)
|
||||
}
|
||||
@@ -106,7 +106,7 @@ export class LoginPage {
|
||||
}
|
||||
|
||||
async typeEmail(email: string) {
|
||||
await this.emailField.fill(email, { timeout: 10000 });
|
||||
await this.emailField.fill(email, { timeout: 30000 });
|
||||
}
|
||||
|
||||
async typePassword(email: string) {
|
||||
|
||||
@@ -9,18 +9,18 @@ const test = base.extend<{ loginPage: LoginPage }>({
|
||||
});
|
||||
|
||||
const loginAndSelectWorkspace = async (loginPage: LoginPage, page: any) => {
|
||||
await page.waitForLoadState('networkidle');
|
||||
await page.waitForLoadState('domcontentloaded');
|
||||
await loginPage.clickLoginWithEmailIfVisible();
|
||||
await loginPage.typeEmail(process.env.DEFAULT_LOGIN!);
|
||||
await loginPage.clickContinueButton();
|
||||
await loginPage.typePassword(process.env.DEFAULT_PASSWORD!);
|
||||
await page.waitForLoadState('networkidle');
|
||||
await page.waitForLoadState('domcontentloaded');
|
||||
await loginPage.clickSignInButton();
|
||||
await page.waitForLoadState('networkidle');
|
||||
await page.waitForLoadState('domcontentloaded');
|
||||
|
||||
const workspaceButton = page.getByText('Apple', { exact: true });
|
||||
|
||||
await workspaceButton.waitFor({ state: 'visible', timeout: 15000 }).catch(
|
||||
await workspaceButton.waitFor({ state: 'visible', timeout: 30000 }).catch(
|
||||
() => {
|
||||
// Single workspace mode — no workspace selection
|
||||
},
|
||||
@@ -34,7 +34,7 @@ const loginAndSelectWorkspace = async (loginPage: LoginPage, page: any) => {
|
||||
() =>
|
||||
!window.location.href.includes('verify') &&
|
||||
!window.location.href.includes('welcome'),
|
||||
{ timeout: 15000 },
|
||||
{ timeout: 30000 },
|
||||
);
|
||||
};
|
||||
|
||||
@@ -82,13 +82,13 @@ test.describe('Return-to-path after login', () => {
|
||||
page,
|
||||
loginPage,
|
||||
}) => {
|
||||
const targetPath =
|
||||
'/authorize?clientId=test-client-id&redirectUrl=https%3A%2F%2Fexample.com%2Fcallback';
|
||||
const targetPath = '/settings/accounts';
|
||||
const targetPathWithParams = `${targetPath}?tab=emails&filter=unread`;
|
||||
|
||||
await test.step(
|
||||
'Navigate to path with query params while logged out',
|
||||
async () => {
|
||||
await page.goto(targetPath);
|
||||
await page.goto(targetPathWithParams);
|
||||
await page.waitForURL('**/welcome');
|
||||
await page.waitForLoadState('domcontentloaded');
|
||||
},
|
||||
@@ -101,14 +101,15 @@ test.describe('Return-to-path after login', () => {
|
||||
await test.step(
|
||||
'Verify redirected to original path with query params',
|
||||
async () => {
|
||||
await page.waitForURL('**/authorize**', { timeout: 15000 });
|
||||
await page.waitForURL(`**${targetPath}**`, {
|
||||
timeout: 30000,
|
||||
waitUntil: 'commit',
|
||||
});
|
||||
const url = new URL(page.url());
|
||||
|
||||
expect(url.pathname).toBe('/authorize');
|
||||
expect(url.searchParams.get('clientId')).toBe('test-client-id');
|
||||
expect(url.searchParams.get('redirectUrl')).toBe(
|
||||
'https://example.com/callback',
|
||||
);
|
||||
expect(url.pathname).toBe(targetPath);
|
||||
expect(url.searchParams.get('tab')).toBe('emails');
|
||||
expect(url.searchParams.get('filter')).toBe('unread');
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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"]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
src/locales/generated
|
||||
@@ -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
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
@@ -13,9 +13,5 @@
|
||||
"src/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.tsx",
|
||||
"vite.config.ts"
|
||||
]
|
||||
"include": ["src/**/*.ts", "src/**/*.tsx", "vite.config.ts"]
|
||||
}
|
||||
|
||||
@@ -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"]
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@
|
||||
"twenty/effect-components": "error",
|
||||
"twenty/no-hardcoded-colors": "error",
|
||||
"twenty/matching-state-variable": "error",
|
||||
"twenty/sort-css-properties-alphabetically": "off",
|
||||
"twenty/sort-css-properties-alphabetically": "error",
|
||||
"twenty/styled-components-prefixed-with-styled": "error",
|
||||
"twenty/no-state-useref": "error",
|
||||
"twenty/component-props-naming": "error",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
src/generated
|
||||
src/generated-metadata
|
||||
src/locales/generated
|
||||
src/testing/mock-data/generated
|
||||
@@ -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 --relative --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 --relative --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)"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -35,12 +35,12 @@ const StyledSkeletonContainer = styled.div`
|
||||
`;
|
||||
|
||||
const StyledSkeletonTitleContainer = styled.div`
|
||||
align-items: flex-start;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
height: 32px;
|
||||
justify-content: center;
|
||||
|
||||
max-width: 196px;
|
||||
min-width: 196px;
|
||||
|
||||
+1
-1
@@ -10,8 +10,8 @@ const StyledSkeletonContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
min-width: 196px;
|
||||
max-width: 196px;
|
||||
min-width: 196px;
|
||||
`;
|
||||
|
||||
export const MainNavigationDrawerItemsSkeletonLoader = ({
|
||||
|
||||
@@ -44,11 +44,11 @@ const StyledRightPanelContainer = styled.div`
|
||||
`;
|
||||
|
||||
const StyledRightPanelFlexContainer = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
height: 32px;
|
||||
justify-content: flex-end;
|
||||
margin-bottom: 12px;
|
||||
`;
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ import { ThemeContext, themeCssVariables } from 'twenty-ui/theme-constants';
|
||||
const StyledSidePanelContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
padding: ${themeCssVariables.spacing[4]};
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
const StyledSkeletonLoader = () => {
|
||||
|
||||
@@ -16,9 +16,9 @@ const StyledContainer = styled.div`
|
||||
gap: 12px;
|
||||
height: 100dvh;
|
||||
min-width: ${NAVIGATION_DRAWER_CONSTRAINTS.default}px;
|
||||
width: 100%;
|
||||
padding: 12px 8px 12px 8px;
|
||||
overflow: hidden;
|
||||
padding: 12px 8px 12px 8px;
|
||||
width: 100%;
|
||||
|
||||
@media (max-width: ${MOBILE_VIEWPORT}px) {
|
||||
width: 100%;
|
||||
|
||||
@@ -4157,6 +4157,12 @@ msgstr "Verstek landkode"
|
||||
msgid "Default palette"
|
||||
msgstr "Verstekpalet"
|
||||
|
||||
#. js-lingui-id: U/uGBk
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationUngroupedEditor.tsx
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx
|
||||
msgid "Default position/visibility for fields created in the future"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: v41VX6
|
||||
#: src/pages/settings/members/SettingsWorkspaceMembers.tsx
|
||||
#: src/modules/workspace/components/WorkspaceInviteTeam.tsx
|
||||
@@ -8951,6 +8957,12 @@ msgstr "Nuwe E-posdomein"
|
||||
msgid "New Field"
|
||||
msgstr "Nuwe Veld"
|
||||
|
||||
#. js-lingui-id: DNUCGO
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationUngroupedEditor.tsx
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx
|
||||
msgid "New fields"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: 96G6Re
|
||||
#: src/modules/side-panel/pages/navigation-menu-item/hooks/useAddFolderToNavigationMenu.ts
|
||||
#: src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemMainMenu.tsx
|
||||
|
||||
@@ -4157,6 +4157,12 @@ msgstr "رمز البلد الافتراضي"
|
||||
msgid "Default palette"
|
||||
msgstr "لوحة الألوان الافتراضية"
|
||||
|
||||
#. js-lingui-id: U/uGBk
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationUngroupedEditor.tsx
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx
|
||||
msgid "Default position/visibility for fields created in the future"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: v41VX6
|
||||
#: src/pages/settings/members/SettingsWorkspaceMembers.tsx
|
||||
#: src/modules/workspace/components/WorkspaceInviteTeam.tsx
|
||||
@@ -8951,6 +8957,12 @@ msgstr "نطاق بريد إلكتروني جديد"
|
||||
msgid "New Field"
|
||||
msgstr "حقل جديد"
|
||||
|
||||
#. js-lingui-id: DNUCGO
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationUngroupedEditor.tsx
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx
|
||||
msgid "New fields"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: 96G6Re
|
||||
#: src/modules/side-panel/pages/navigation-menu-item/hooks/useAddFolderToNavigationMenu.ts
|
||||
#: src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemMainMenu.tsx
|
||||
|
||||
@@ -4157,6 +4157,12 @@ msgstr "Codi de país predeterminat"
|
||||
msgid "Default palette"
|
||||
msgstr "Paleta predeterminada"
|
||||
|
||||
#. js-lingui-id: U/uGBk
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationUngroupedEditor.tsx
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx
|
||||
msgid "Default position/visibility for fields created in the future"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: v41VX6
|
||||
#: src/pages/settings/members/SettingsWorkspaceMembers.tsx
|
||||
#: src/modules/workspace/components/WorkspaceInviteTeam.tsx
|
||||
@@ -8951,6 +8957,12 @@ msgstr "Nou domini de correu"
|
||||
msgid "New Field"
|
||||
msgstr "Nou camp"
|
||||
|
||||
#. js-lingui-id: DNUCGO
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationUngroupedEditor.tsx
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx
|
||||
msgid "New fields"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: 96G6Re
|
||||
#: src/modules/side-panel/pages/navigation-menu-item/hooks/useAddFolderToNavigationMenu.ts
|
||||
#: src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemMainMenu.tsx
|
||||
|
||||
@@ -4157,6 +4157,12 @@ msgstr "Výchozí číselný kód země"
|
||||
msgid "Default palette"
|
||||
msgstr "Výchozí paleta"
|
||||
|
||||
#. js-lingui-id: U/uGBk
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationUngroupedEditor.tsx
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx
|
||||
msgid "Default position/visibility for fields created in the future"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: v41VX6
|
||||
#: src/pages/settings/members/SettingsWorkspaceMembers.tsx
|
||||
#: src/modules/workspace/components/WorkspaceInviteTeam.tsx
|
||||
@@ -8951,6 +8957,12 @@ msgstr "Nová e-mailová doména"
|
||||
msgid "New Field"
|
||||
msgstr "Nové pole"
|
||||
|
||||
#. js-lingui-id: DNUCGO
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationUngroupedEditor.tsx
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx
|
||||
msgid "New fields"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: 96G6Re
|
||||
#: src/modules/side-panel/pages/navigation-menu-item/hooks/useAddFolderToNavigationMenu.ts
|
||||
#: src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemMainMenu.tsx
|
||||
|
||||
@@ -4157,6 +4157,12 @@ msgstr "Standardlandekode"
|
||||
msgid "Default palette"
|
||||
msgstr "Standardfarvepalet"
|
||||
|
||||
#. js-lingui-id: U/uGBk
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationUngroupedEditor.tsx
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx
|
||||
msgid "Default position/visibility for fields created in the future"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: v41VX6
|
||||
#: src/pages/settings/members/SettingsWorkspaceMembers.tsx
|
||||
#: src/modules/workspace/components/WorkspaceInviteTeam.tsx
|
||||
@@ -8951,6 +8957,12 @@ msgstr "Nyt e-mail-domæne"
|
||||
msgid "New Field"
|
||||
msgstr "Nyt felt"
|
||||
|
||||
#. js-lingui-id: DNUCGO
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationUngroupedEditor.tsx
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx
|
||||
msgid "New fields"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: 96G6Re
|
||||
#: src/modules/side-panel/pages/navigation-menu-item/hooks/useAddFolderToNavigationMenu.ts
|
||||
#: src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemMainMenu.tsx
|
||||
|
||||
@@ -4157,6 +4157,12 @@ msgstr "Standard-Ländercode"
|
||||
msgid "Default palette"
|
||||
msgstr "Standardpalette"
|
||||
|
||||
#. js-lingui-id: U/uGBk
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationUngroupedEditor.tsx
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx
|
||||
msgid "Default position/visibility for fields created in the future"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: v41VX6
|
||||
#: src/pages/settings/members/SettingsWorkspaceMembers.tsx
|
||||
#: src/modules/workspace/components/WorkspaceInviteTeam.tsx
|
||||
@@ -8951,6 +8957,12 @@ msgstr "Neue E-Mail-Domäne"
|
||||
msgid "New Field"
|
||||
msgstr "Neues Feld"
|
||||
|
||||
#. js-lingui-id: DNUCGO
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationUngroupedEditor.tsx
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx
|
||||
msgid "New fields"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: 96G6Re
|
||||
#: src/modules/side-panel/pages/navigation-menu-item/hooks/useAddFolderToNavigationMenu.ts
|
||||
#: src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemMainMenu.tsx
|
||||
|
||||
@@ -4157,6 +4157,12 @@ msgstr "Προεπιλεγμένος Κωδικός Χώρας"
|
||||
msgid "Default palette"
|
||||
msgstr "Προεπιλεγμένη παλέτα"
|
||||
|
||||
#. js-lingui-id: U/uGBk
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationUngroupedEditor.tsx
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx
|
||||
msgid "Default position/visibility for fields created in the future"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: v41VX6
|
||||
#: src/pages/settings/members/SettingsWorkspaceMembers.tsx
|
||||
#: src/modules/workspace/components/WorkspaceInviteTeam.tsx
|
||||
@@ -8951,6 +8957,12 @@ msgstr "Νέα Περιοχή Email"
|
||||
msgid "New Field"
|
||||
msgstr "Νέο Πεδίο"
|
||||
|
||||
#. js-lingui-id: DNUCGO
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationUngroupedEditor.tsx
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx
|
||||
msgid "New fields"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: 96G6Re
|
||||
#: src/modules/side-panel/pages/navigation-menu-item/hooks/useAddFolderToNavigationMenu.ts
|
||||
#: src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemMainMenu.tsx
|
||||
|
||||
@@ -4152,6 +4152,12 @@ msgstr "Default Country Code"
|
||||
msgid "Default palette"
|
||||
msgstr "Default palette"
|
||||
|
||||
#. js-lingui-id: U/uGBk
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationUngroupedEditor.tsx
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx
|
||||
msgid "Default position/visibility for fields created in the future"
|
||||
msgstr "Default position/visibility for fields created in the future"
|
||||
|
||||
#. js-lingui-id: v41VX6
|
||||
#: src/pages/settings/members/SettingsWorkspaceMembers.tsx
|
||||
#: src/modules/workspace/components/WorkspaceInviteTeam.tsx
|
||||
@@ -8946,6 +8952,12 @@ msgstr "New Emailing Domain"
|
||||
msgid "New Field"
|
||||
msgstr "New Field"
|
||||
|
||||
#. js-lingui-id: DNUCGO
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationUngroupedEditor.tsx
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx
|
||||
msgid "New fields"
|
||||
msgstr "New fields"
|
||||
|
||||
#. js-lingui-id: 96G6Re
|
||||
#: src/modules/side-panel/pages/navigation-menu-item/hooks/useAddFolderToNavigationMenu.ts
|
||||
#: src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemMainMenu.tsx
|
||||
|
||||
@@ -4157,6 +4157,12 @@ msgstr "Código de país predeterminado"
|
||||
msgid "Default palette"
|
||||
msgstr "Paleta predeterminada"
|
||||
|
||||
#. js-lingui-id: U/uGBk
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationUngroupedEditor.tsx
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx
|
||||
msgid "Default position/visibility for fields created in the future"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: v41VX6
|
||||
#: src/pages/settings/members/SettingsWorkspaceMembers.tsx
|
||||
#: src/modules/workspace/components/WorkspaceInviteTeam.tsx
|
||||
@@ -8951,6 +8957,12 @@ msgstr "Nuevo dominio de correo electrónico"
|
||||
msgid "New Field"
|
||||
msgstr "Nuevo Campo"
|
||||
|
||||
#. js-lingui-id: DNUCGO
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationUngroupedEditor.tsx
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx
|
||||
msgid "New fields"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: 96G6Re
|
||||
#: src/modules/side-panel/pages/navigation-menu-item/hooks/useAddFolderToNavigationMenu.ts
|
||||
#: src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemMainMenu.tsx
|
||||
|
||||
@@ -4157,6 +4157,12 @@ msgstr "Oletusmaakoodi"
|
||||
msgid "Default palette"
|
||||
msgstr "Oletuspaletti"
|
||||
|
||||
#. js-lingui-id: U/uGBk
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationUngroupedEditor.tsx
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx
|
||||
msgid "Default position/visibility for fields created in the future"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: v41VX6
|
||||
#: src/pages/settings/members/SettingsWorkspaceMembers.tsx
|
||||
#: src/modules/workspace/components/WorkspaceInviteTeam.tsx
|
||||
@@ -8951,6 +8957,12 @@ msgstr "Uusi sähköpostitoimialue"
|
||||
msgid "New Field"
|
||||
msgstr "Uusi kenttä"
|
||||
|
||||
#. js-lingui-id: DNUCGO
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationUngroupedEditor.tsx
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx
|
||||
msgid "New fields"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: 96G6Re
|
||||
#: src/modules/side-panel/pages/navigation-menu-item/hooks/useAddFolderToNavigationMenu.ts
|
||||
#: src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemMainMenu.tsx
|
||||
|
||||
@@ -4157,6 +4157,12 @@ msgstr "Code du pays par défaut"
|
||||
msgid "Default palette"
|
||||
msgstr "Palette par défaut"
|
||||
|
||||
#. js-lingui-id: U/uGBk
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationUngroupedEditor.tsx
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx
|
||||
msgid "Default position/visibility for fields created in the future"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: v41VX6
|
||||
#: src/pages/settings/members/SettingsWorkspaceMembers.tsx
|
||||
#: src/modules/workspace/components/WorkspaceInviteTeam.tsx
|
||||
@@ -8951,6 +8957,12 @@ msgstr "Nouveau domaine d'envoi d'e-mail"
|
||||
msgid "New Field"
|
||||
msgstr "Nouveau champ"
|
||||
|
||||
#. js-lingui-id: DNUCGO
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationUngroupedEditor.tsx
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx
|
||||
msgid "New fields"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: 96G6Re
|
||||
#: src/modules/side-panel/pages/navigation-menu-item/hooks/useAddFolderToNavigationMenu.ts
|
||||
#: src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemMainMenu.tsx
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -4157,6 +4157,12 @@ msgstr "קוד מדינה ברירת מחדל"
|
||||
msgid "Default palette"
|
||||
msgstr "פלטת ברירת המחדל"
|
||||
|
||||
#. js-lingui-id: U/uGBk
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationUngroupedEditor.tsx
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx
|
||||
msgid "Default position/visibility for fields created in the future"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: v41VX6
|
||||
#: src/pages/settings/members/SettingsWorkspaceMembers.tsx
|
||||
#: src/modules/workspace/components/WorkspaceInviteTeam.tsx
|
||||
@@ -8951,6 +8957,12 @@ msgstr "<span dir=\"rtl\">דומיין חדש לשליחת מיילים</span>"
|
||||
msgid "New Field"
|
||||
msgstr "שדה חדש"
|
||||
|
||||
#. js-lingui-id: DNUCGO
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationUngroupedEditor.tsx
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx
|
||||
msgid "New fields"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: 96G6Re
|
||||
#: src/modules/side-panel/pages/navigation-menu-item/hooks/useAddFolderToNavigationMenu.ts
|
||||
#: src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemMainMenu.tsx
|
||||
|
||||
@@ -4157,6 +4157,12 @@ msgstr "Alapértelmezett országkód"
|
||||
msgid "Default palette"
|
||||
msgstr "Alapértelmezett paletta"
|
||||
|
||||
#. js-lingui-id: U/uGBk
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationUngroupedEditor.tsx
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx
|
||||
msgid "Default position/visibility for fields created in the future"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: v41VX6
|
||||
#: src/pages/settings/members/SettingsWorkspaceMembers.tsx
|
||||
#: src/modules/workspace/components/WorkspaceInviteTeam.tsx
|
||||
@@ -8951,6 +8957,12 @@ msgstr "Új Emailküldési Tartomány"
|
||||
msgid "New Field"
|
||||
msgstr "Új mező"
|
||||
|
||||
#. js-lingui-id: DNUCGO
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationUngroupedEditor.tsx
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx
|
||||
msgid "New fields"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: 96G6Re
|
||||
#: src/modules/side-panel/pages/navigation-menu-item/hooks/useAddFolderToNavigationMenu.ts
|
||||
#: src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemMainMenu.tsx
|
||||
|
||||
@@ -4157,6 +4157,12 @@ msgstr "Prefisso internazionale predefinito"
|
||||
msgid "Default palette"
|
||||
msgstr "Tavolozza predefinita"
|
||||
|
||||
#. js-lingui-id: U/uGBk
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationUngroupedEditor.tsx
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx
|
||||
msgid "Default position/visibility for fields created in the future"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: v41VX6
|
||||
#: src/pages/settings/members/SettingsWorkspaceMembers.tsx
|
||||
#: src/modules/workspace/components/WorkspaceInviteTeam.tsx
|
||||
@@ -8951,6 +8957,12 @@ msgstr "Nuovo dominio di email"
|
||||
msgid "New Field"
|
||||
msgstr "Nuovo Campo"
|
||||
|
||||
#. js-lingui-id: DNUCGO
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationUngroupedEditor.tsx
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx
|
||||
msgid "New fields"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: 96G6Re
|
||||
#: src/modules/side-panel/pages/navigation-menu-item/hooks/useAddFolderToNavigationMenu.ts
|
||||
#: src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemMainMenu.tsx
|
||||
|
||||
@@ -4157,6 +4157,12 @@ msgstr "デフォルトの国コード"
|
||||
msgid "Default palette"
|
||||
msgstr "デフォルトのパレット"
|
||||
|
||||
#. js-lingui-id: U/uGBk
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationUngroupedEditor.tsx
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx
|
||||
msgid "Default position/visibility for fields created in the future"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: v41VX6
|
||||
#: src/pages/settings/members/SettingsWorkspaceMembers.tsx
|
||||
#: src/modules/workspace/components/WorkspaceInviteTeam.tsx
|
||||
@@ -8951,6 +8957,12 @@ msgstr "新しいメール送信ドメイン"
|
||||
msgid "New Field"
|
||||
msgstr "新規フィールド"
|
||||
|
||||
#. js-lingui-id: DNUCGO
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationUngroupedEditor.tsx
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx
|
||||
msgid "New fields"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: 96G6Re
|
||||
#: src/modules/side-panel/pages/navigation-menu-item/hooks/useAddFolderToNavigationMenu.ts
|
||||
#: src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemMainMenu.tsx
|
||||
|
||||
@@ -4157,6 +4157,12 @@ msgstr "기본 국가 코드"
|
||||
msgid "Default palette"
|
||||
msgstr "기본 팔레트"
|
||||
|
||||
#. js-lingui-id: U/uGBk
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationUngroupedEditor.tsx
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx
|
||||
msgid "Default position/visibility for fields created in the future"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: v41VX6
|
||||
#: src/pages/settings/members/SettingsWorkspaceMembers.tsx
|
||||
#: src/modules/workspace/components/WorkspaceInviteTeam.tsx
|
||||
@@ -8951,6 +8957,12 @@ msgstr "새 이메일 도메인"
|
||||
msgid "New Field"
|
||||
msgstr "새 필드"
|
||||
|
||||
#. js-lingui-id: DNUCGO
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationUngroupedEditor.tsx
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx
|
||||
msgid "New fields"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: 96G6Re
|
||||
#: src/modules/side-panel/pages/navigation-menu-item/hooks/useAddFolderToNavigationMenu.ts
|
||||
#: src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemMainMenu.tsx
|
||||
|
||||
@@ -4157,6 +4157,12 @@ msgstr "Standaard landcode"
|
||||
msgid "Default palette"
|
||||
msgstr "Standaardpalet"
|
||||
|
||||
#. js-lingui-id: U/uGBk
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationUngroupedEditor.tsx
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx
|
||||
msgid "Default position/visibility for fields created in the future"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: v41VX6
|
||||
#: src/pages/settings/members/SettingsWorkspaceMembers.tsx
|
||||
#: src/modules/workspace/components/WorkspaceInviteTeam.tsx
|
||||
@@ -8951,6 +8957,12 @@ msgstr "Nieuw e-maildomein"
|
||||
msgid "New Field"
|
||||
msgstr "Nieuw veld"
|
||||
|
||||
#. js-lingui-id: DNUCGO
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationUngroupedEditor.tsx
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx
|
||||
msgid "New fields"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: 96G6Re
|
||||
#: src/modules/side-panel/pages/navigation-menu-item/hooks/useAddFolderToNavigationMenu.ts
|
||||
#: src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemMainMenu.tsx
|
||||
|
||||
@@ -4157,6 +4157,12 @@ msgstr "Standardlandkode"
|
||||
msgid "Default palette"
|
||||
msgstr "Standardpalett"
|
||||
|
||||
#. js-lingui-id: U/uGBk
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationUngroupedEditor.tsx
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx
|
||||
msgid "Default position/visibility for fields created in the future"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: v41VX6
|
||||
#: src/pages/settings/members/SettingsWorkspaceMembers.tsx
|
||||
#: src/modules/workspace/components/WorkspaceInviteTeam.tsx
|
||||
@@ -8951,6 +8957,12 @@ msgstr "Nytt e-postdomene"
|
||||
msgid "New Field"
|
||||
msgstr "Nytt felt"
|
||||
|
||||
#. js-lingui-id: DNUCGO
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationUngroupedEditor.tsx
|
||||
#: src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx
|
||||
msgid "New fields"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: 96G6Re
|
||||
#: src/modules/side-panel/pages/navigation-menu-item/hooks/useAddFolderToNavigationMenu.ts
|
||||
#: src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemMainMenu.tsx
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user