Compare commits
33
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
48b2b7b0ff | ||
|
|
94d5348595 | ||
|
|
86423104f7 | ||
|
|
e4a073be56 | ||
|
|
ef66d6b337 | ||
|
|
bcca5d0002 | ||
|
|
e0630b8653 | ||
|
|
61a27984e8 | ||
|
|
fd21d0c6ca | ||
|
|
8d539f0e49 | ||
|
|
a6cecdbd49 | ||
|
|
383935d0d9 | ||
|
|
37908114fc | ||
|
|
369ae2862f | ||
|
|
5bde41ebbb | ||
|
|
8fa3962e1c | ||
|
|
ca00e8dece | ||
|
|
2263e14394 | ||
|
|
ecf8161d0e | ||
|
|
3d1c53ec9d | ||
|
|
2a5aab0c44 | ||
|
|
8985dfbc5d | ||
|
|
40abe1e6d0 | ||
|
|
6c128a35dd | ||
|
|
c0086646fd | ||
|
|
08b041633a | ||
|
|
2fccd29ec6 | ||
|
|
30bdc24bf8 | ||
|
|
d2cf05f4f4 | ||
|
|
696a202bb9 | ||
|
|
b8374f5531 | ||
|
|
1109b89cd7 | ||
|
|
107914b437 |
@@ -86,6 +86,8 @@ jobs:
|
||||
run: |
|
||||
echo "Attempting to merge main into current branch..."
|
||||
|
||||
git config user.email "ci@twenty.com"
|
||||
git config user.name "CI"
|
||||
git fetch origin main
|
||||
|
||||
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
||||
@@ -99,8 +101,8 @@ jobs:
|
||||
echo "❌ Merge failed due to conflicts"
|
||||
echo "⚠️ Falling back to comparing current branch against main without merge"
|
||||
|
||||
# Abort the failed merge
|
||||
git merge --abort
|
||||
# Abort the failed merge (may not exist if merge never started)
|
||||
git merge --abort 2>/dev/null || true
|
||||
|
||||
echo "merged=false" >> $GITHUB_OUTPUT
|
||||
echo "BRANCH_STATE=conflicts" >> $GITHUB_ENV
|
||||
@@ -402,6 +404,23 @@ jobs:
|
||||
# Clean up temp directory
|
||||
rm -rf /tmp/current-branch-files
|
||||
|
||||
- name: Validate downloaded schema files
|
||||
id: validate-schemas
|
||||
run: |
|
||||
valid=true
|
||||
|
||||
for file in main-schema-introspection.json current-schema-introspection.json \
|
||||
main-metadata-schema-introspection.json current-metadata-schema-introspection.json \
|
||||
main-rest-api.json current-rest-api.json \
|
||||
main-rest-metadata-api.json current-rest-metadata-api.json; do
|
||||
if [ ! -f "$file" ] || ! jq empty "$file" 2>/dev/null; then
|
||||
echo "::warning::Invalid or missing schema file: $file"
|
||||
valid=false
|
||||
fi
|
||||
done
|
||||
|
||||
echo "valid=$valid" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
@@ -414,6 +433,7 @@ jobs:
|
||||
echo "Using OpenAPITools/openapi-diff via Docker"
|
||||
|
||||
- name: Generate GraphQL Schema Diff Reports
|
||||
if: steps.validate-schemas.outputs.valid == 'true'
|
||||
run: |
|
||||
echo "=== INSTALLING GRAPHQL INSPECTOR CLI ==="
|
||||
npm install -g @graphql-inspector/cli
|
||||
@@ -424,7 +444,6 @@ jobs:
|
||||
echo "Checking GraphQL schema for changes..."
|
||||
if graphql-inspector diff main-schema-introspection.json current-schema-introspection.json >/dev/null 2>&1; then
|
||||
echo "✅ No changes in GraphQL schema"
|
||||
# Don't create a diff file for no changes
|
||||
else
|
||||
echo "⚠️ Changes detected in GraphQL schema, generating report..."
|
||||
echo "# GraphQL Schema Changes" > graphql-schema-diff.md
|
||||
@@ -442,7 +461,6 @@ jobs:
|
||||
echo "Checking GraphQL metadata schema for changes..."
|
||||
if graphql-inspector diff main-metadata-schema-introspection.json current-metadata-schema-introspection.json >/dev/null 2>&1; then
|
||||
echo "✅ No changes in GraphQL metadata schema"
|
||||
# Don't create a diff file for no changes
|
||||
else
|
||||
echo "⚠️ Changes detected in GraphQL metadata schema, generating report..."
|
||||
echo "# GraphQL Metadata Schema Changes" > graphql-metadata-diff.md
|
||||
@@ -461,6 +479,7 @@ jobs:
|
||||
ls -la *-diff.md 2>/dev/null || echo "No diff files generated (no changes detected)"
|
||||
|
||||
- name: Check REST API Breaking Changes
|
||||
if: steps.validate-schemas.outputs.valid == 'true'
|
||||
run: |
|
||||
echo "=== CHECKING REST API FOR BREAKING CHANGES ==="
|
||||
|
||||
@@ -529,6 +548,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Check REST Metadata API Breaking Changes
|
||||
if: steps.validate-schemas.outputs.valid == 'true'
|
||||
run: |
|
||||
echo "=== CHECKING REST METADATA API FOR BREAKING CHANGES ==="
|
||||
|
||||
|
||||
@@ -188,7 +188,7 @@ jobs:
|
||||
cd /tmp/e2e-test-workspace/test-app
|
||||
EXEC_OUTPUT=$(npx --no-install twenty exec --functionName create-hello-world-company)
|
||||
echo "$EXEC_OUTPUT"
|
||||
echo "$EXEC_OUTPUT" | grep -q "Created company"
|
||||
echo "$EXEC_OUTPUT" | grep -q 'Created company.*Hello World.*with id'
|
||||
|
||||
- name: Run scaffolded app integration test
|
||||
env:
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
name: CI Front Component Renderer
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
merge_group:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
||||
|
||||
jobs:
|
||||
changed-files-check:
|
||||
if: github.event_name != 'merge_group'
|
||||
uses: ./.github/workflows/changed-files.yaml
|
||||
with:
|
||||
files: |
|
||||
package.json
|
||||
yarn.lock
|
||||
packages/twenty-front-component-renderer/**
|
||||
packages/twenty-sdk/**
|
||||
packages/twenty-shared/**
|
||||
!packages/twenty-sdk/package.json
|
||||
renderer-task:
|
||||
needs: changed-files-check
|
||||
if: needs.changed-files-check.outputs.any_changed == 'true'
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
task: [build, typecheck, lint]
|
||||
steps:
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/cancel-workflow-action@0.11.0
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 10
|
||||
- name: Install dependencies
|
||||
uses: ./.github/actions/yarn-install
|
||||
- name: Run ${{ matrix.task }}
|
||||
run: npx nx ${{ matrix.task }} twenty-front-component-renderer
|
||||
renderer-sb-build:
|
||||
needs: changed-files-check
|
||||
if: needs.changed-files-check.outputs.any_changed == 'true'
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/cancel-workflow-action@0.11.0
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 10
|
||||
- name: Install dependencies
|
||||
uses: ./.github/actions/yarn-install
|
||||
- name: Build storybook
|
||||
run: npx nx storybook:build twenty-front-component-renderer
|
||||
- name: Upload storybook build
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: storybook-twenty-front-component-renderer
|
||||
path: packages/twenty-front-component-renderer/storybook-static
|
||||
retention-days: 1
|
||||
renderer-sb-test:
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-latest
|
||||
needs: renderer-sb-build
|
||||
env:
|
||||
STORYBOOK_URL: http://localhost:6008
|
||||
steps:
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 10
|
||||
- name: Install dependencies
|
||||
uses: ./.github/actions/yarn-install
|
||||
- name: Build dependencies
|
||||
run: npx nx build twenty-sdk
|
||||
- name: Download storybook build
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: storybook-twenty-front-component-renderer
|
||||
path: packages/twenty-front-component-renderer/storybook-static
|
||||
- name: Install Playwright
|
||||
run: |
|
||||
cd packages/twenty-front-component-renderer
|
||||
npx playwright install
|
||||
- name: Serve storybook & run tests
|
||||
run: |
|
||||
npx http-server packages/twenty-front-component-renderer/storybook-static --port 6008 --silent &
|
||||
timeout 30 bash -c 'until curl -sf http://localhost:6008 > /dev/null 2>&1; do sleep 1; done'
|
||||
npx nx storybook:test twenty-front-component-renderer
|
||||
ci-front-component-renderer-status-check:
|
||||
if: always() && !cancelled()
|
||||
timeout-minutes: 5
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
[
|
||||
changed-files-check,
|
||||
renderer-task,
|
||||
renderer-sb-build,
|
||||
renderer-sb-test,
|
||||
]
|
||||
steps:
|
||||
- name: Fail job if any needs failed
|
||||
if: contains(needs.*.result, 'failure')
|
||||
run: exit 1
|
||||
@@ -25,6 +25,7 @@ jobs:
|
||||
package.json
|
||||
yarn.lock
|
||||
packages/twenty-front/**
|
||||
packages/twenty-front-component-renderer/**
|
||||
packages/twenty-ui/**
|
||||
packages/twenty-shared/**
|
||||
packages/twenty-sdk/**
|
||||
@@ -93,7 +94,7 @@ jobs:
|
||||
run: |
|
||||
npx nx build twenty-shared
|
||||
npx nx build twenty-ui
|
||||
npx nx build twenty-sdk
|
||||
npx nx build twenty-front-component-renderer
|
||||
- name: Download storybook build
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
|
||||
@@ -27,7 +27,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
task: [lint, typecheck, test:unit, storybook:build, storybook:test, test:integration]
|
||||
task: [lint, typecheck, test:unit, test:integration]
|
||||
steps:
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/cancel-workflow-action@0.11.0
|
||||
@@ -41,9 +41,6 @@ jobs:
|
||||
uses: ./.github/actions/yarn-install
|
||||
- name: Build
|
||||
run: npx nx build twenty-sdk
|
||||
- name: Install Playwright
|
||||
if: contains(matrix.task, 'storybook')
|
||||
run: npx playwright install chromium
|
||||
- name: Run ${{ matrix.task }} task
|
||||
uses: ./.github/actions/nx-affected
|
||||
with:
|
||||
|
||||
@@ -208,6 +208,7 @@
|
||||
"packages/twenty-e2e-testing",
|
||||
"packages/twenty-shared",
|
||||
"packages/twenty-sdk",
|
||||
"packages/twenty-front-component-renderer",
|
||||
"packages/twenty-client-sdk",
|
||||
"packages/twenty-apps",
|
||||
"packages/twenty-cli",
|
||||
|
||||
@@ -110,7 +110,7 @@ npx create-twenty-app@latest my-app -m
|
||||
|
||||
## Local server
|
||||
|
||||
The scaffolder can start a local Twenty dev server for you (all-in-one Docker image with PostgreSQL, Redis, server, and worker). You can also manage it manually:
|
||||
The scaffolder can start a local Twenty dev server for you (all-in-one Docker image with PostgreSQL, Redis, server, and worker on port 2020). These commands only apply to the Docker-based dev server — they do not manage a Twenty instance started from source (e.g. `npx nx start twenty-server` on port 3000). You can also manage it manually:
|
||||
|
||||
```bash
|
||||
yarn twenty server start # Start (pulls image if needed)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "create-twenty-app",
|
||||
"version": "0.8.0-canary.6",
|
||||
"version": "0.8.0-canary.7",
|
||||
"description": "Command-line interface to create Twenty application",
|
||||
"main": "dist/cli.cjs",
|
||||
"bin": "dist/cli.cjs",
|
||||
|
||||
@@ -10,6 +10,7 @@ import * as path from 'path';
|
||||
import { basename } from 'path';
|
||||
import {
|
||||
authLoginOAuth,
|
||||
detectLocalServer,
|
||||
serverStart,
|
||||
type ServerStartResult,
|
||||
} from 'twenty-sdk/cli';
|
||||
@@ -62,15 +63,19 @@ export class CreateAppCommand {
|
||||
let serverResult: ServerStartResult | undefined;
|
||||
|
||||
if (!options.skipLocalInstance) {
|
||||
const startResult = await serverStart({
|
||||
onProgress: (message: string) => console.log(chalk.gray(message)),
|
||||
});
|
||||
const shouldStartServer = await this.shouldStartServer();
|
||||
|
||||
if (startResult.success) {
|
||||
serverResult = startResult.data;
|
||||
await this.connectToLocal(serverResult.url);
|
||||
} else {
|
||||
console.log(chalk.yellow(`\n${startResult.error.message}`));
|
||||
if (shouldStartServer) {
|
||||
const startResult = await serverStart({
|
||||
onProgress: (message: string) => console.log(chalk.gray(message)),
|
||||
});
|
||||
|
||||
if (startResult.success) {
|
||||
serverResult = startResult.data;
|
||||
await this.promptConnectToLocal(serverResult.url);
|
||||
} else {
|
||||
console.log(chalk.yellow(`\n${startResult.error.message}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,7 +206,46 @@ export class CreateAppCommand {
|
||||
);
|
||||
}
|
||||
|
||||
private async connectToLocal(serverUrl: string): Promise<void> {
|
||||
private async shouldStartServer(): Promise<boolean> {
|
||||
const existingServerUrl = await detectLocalServer();
|
||||
|
||||
if (existingServerUrl) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const { startDocker } = await inquirer.prompt([
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'startDocker',
|
||||
message:
|
||||
'No running Twenty instance found. Would you like to start one using Docker?',
|
||||
default: true,
|
||||
},
|
||||
]);
|
||||
|
||||
return startDocker;
|
||||
}
|
||||
|
||||
private async promptConnectToLocal(serverUrl: string): Promise<void> {
|
||||
const { shouldAuthenticate } = await inquirer.prompt([
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'shouldAuthenticate',
|
||||
message: `Would you like to authenticate to the local Twenty instance (${serverUrl})?`,
|
||||
default: true,
|
||||
},
|
||||
]);
|
||||
|
||||
if (!shouldAuthenticate) {
|
||||
console.log(
|
||||
chalk.gray(
|
||||
'Authentication skipped. Run `yarn twenty remote add` manually.',
|
||||
),
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await authLoginOAuth({
|
||||
apiUrl: serverUrl,
|
||||
@@ -211,14 +255,14 @@ export class CreateAppCommand {
|
||||
if (!result.success) {
|
||||
console.log(
|
||||
chalk.yellow(
|
||||
'Authentication skipped. Run `yarn twenty remote add` manually.',
|
||||
'Authentication failed. Run `yarn twenty remote add` manually.',
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch {
|
||||
console.log(
|
||||
chalk.yellow(
|
||||
'Authentication skipped. Run `yarn twenty remote add` manually.',
|
||||
'Authentication failed. Run `yarn twenty remote add` manually.',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -425,8 +425,12 @@ const handler = async (): Promise<{ message: string }> => {
|
||||
},
|
||||
});
|
||||
|
||||
if (!createCompany?.id || !createCompany?.name) {
|
||||
throw new Error('Failed to create company: missing id or name in response');
|
||||
}
|
||||
|
||||
return {
|
||||
message: \`Created company "\${createCompany?.name}" with id \${createCompany?.id}\`,
|
||||
message: \`Created company "\${createCompany.name}" with id \${createCompany.id}\`,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
"@types/react": "^18.2.0",
|
||||
"oxlint": "^0.16.0",
|
||||
"react": "^18.2.0",
|
||||
"twenty-client-sdk": "portal:../../twenty-client-sdk",
|
||||
"twenty-sdk": "portal:../../twenty-sdk",
|
||||
"twenty-client-sdk": "0.8.0-canary.5",
|
||||
"twenty-sdk": "0.8.0-canary.5",
|
||||
"typescript": "^5.9.3",
|
||||
"vite-tsconfig-paths": "^4.2.1",
|
||||
"vitest": "^3.1.1"
|
||||
|
||||
@@ -16,8 +16,12 @@ const handler = async (): Promise<{ message: string }> => {
|
||||
},
|
||||
});
|
||||
|
||||
if (!createCompany?.id || !createCompany?.name) {
|
||||
throw new Error('Failed to create company: missing id or name in response');
|
||||
}
|
||||
|
||||
return {
|
||||
message: `Created company "${createCompany?.name}" with id ${createCompany?.id}`,
|
||||
message: `Created company "${createCompany.name}" with id ${createCompany.id}`,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -5,13 +5,13 @@ __metadata:
|
||||
version: 8
|
||||
cacheKey: 10c0
|
||||
|
||||
"@alcalzone/ansi-tokenize@npm:^0.1.3":
|
||||
version: 0.1.3
|
||||
resolution: "@alcalzone/ansi-tokenize@npm:0.1.3"
|
||||
"@alcalzone/ansi-tokenize@npm:^0.2.4":
|
||||
version: 0.2.5
|
||||
resolution: "@alcalzone/ansi-tokenize@npm:0.2.5"
|
||||
dependencies:
|
||||
ansi-styles: "npm:^6.2.1"
|
||||
is-fullwidth-code-point: "npm:^4.0.0"
|
||||
checksum: 10c0/b88c5708271bb64ce132fc80dac8d5b87fc1699bf3abfdf10ecae40dbb56ab82460818f5746ecdd9870a00be9854e039d5cb3a121b808d0ff6f5bc7d0146cb38
|
||||
is-fullwidth-code-point: "npm:^5.0.0"
|
||||
checksum: 10c0/dd8622288426b5b7dbf8b68d51d4b930cea591d0e3b9dbc3f523131464d78ac922c165fcb7ba5307f133d35dbcaa0e6648a1c3fb6a0dc2725546d6f867b70af4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -2655,7 +2655,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ansi-escapes@npm:^7.0.0":
|
||||
"ansi-escapes@npm:^7.3.0":
|
||||
version: 7.3.0
|
||||
resolution: "ansi-escapes@npm:7.3.0"
|
||||
dependencies:
|
||||
@@ -2717,7 +2717,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ansi-styles@npm:^6.0.0, ansi-styles@npm:^6.2.1":
|
||||
"ansi-styles@npm:^6.2.1, ansi-styles@npm:^6.2.3":
|
||||
version: 6.2.3
|
||||
resolution: "ansi-styles@npm:6.2.3"
|
||||
checksum: 10c0/23b8a4ce14e18fb854693b95351e286b771d23d8844057ed2e7d083cd3e708376c3323707ec6a24365f7d7eda3ca00327fe04092e29e551499ec4c8b7bfac868
|
||||
@@ -2948,7 +2948,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"chalk@npm:^5.3.0":
|
||||
"chalk@npm:^5.3.0, chalk@npm:^5.6.0":
|
||||
version: 5.6.2
|
||||
resolution: "chalk@npm:5.6.2"
|
||||
checksum: 10c0/99a4b0f0e7991796b1e7e3f52dceb9137cae2a9dfc8fc0784a550dc4c558e15ab32ed70b14b21b52beb2679b4892b41a0aa44249bcb996f01e125d58477c6976
|
||||
@@ -3020,13 +3020,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"cli-truncate@npm:^4.0.0":
|
||||
version: 4.0.0
|
||||
resolution: "cli-truncate@npm:4.0.0"
|
||||
"cli-truncate@npm:^5.1.1":
|
||||
version: 5.2.0
|
||||
resolution: "cli-truncate@npm:5.2.0"
|
||||
dependencies:
|
||||
slice-ansi: "npm:^5.0.0"
|
||||
string-width: "npm:^7.0.0"
|
||||
checksum: 10c0/d7f0b73e3d9b88cb496e6c086df7410b541b56a43d18ade6a573c9c18bd001b1c3fba1ad578f741a4218fdc794d042385f8ac02c25e1c295a2d8b9f3cb86eb4c
|
||||
slice-ansi: "npm:^8.0.0"
|
||||
string-width: "npm:^8.2.0"
|
||||
checksum: 10c0/0d4ec94702ca85b64522ac93633837fb5ea7db17b79b1322a60f6045e6ae2b8cd7bd4c1d19ac7d1f9e10e3bbda1112e172e439b68c02b785ee00da8d6a5c5471
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -3306,7 +3306,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"es-toolkit@npm:^1.22.0":
|
||||
"es-toolkit@npm:^1.39.10":
|
||||
version: 1.45.1
|
||||
resolution: "es-toolkit@npm:1.45.1"
|
||||
dependenciesMeta:
|
||||
@@ -3727,7 +3727,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"get-east-asian-width@npm:^1.0.0, get-east-asian-width@npm:^1.3.1":
|
||||
"get-east-asian-width@npm:^1.0.0, get-east-asian-width@npm:^1.3.1, get-east-asian-width@npm:^1.5.0":
|
||||
version: 1.5.0
|
||||
resolution: "get-east-asian-width@npm:1.5.0"
|
||||
checksum: 10c0/bff8bbc8d81790b9477f7aa55b1806b9f082a8dc1359fff7bd8b96939622c86b729685afc2bfeb22def1fc6ef1e5228e4d87dd4e6da60bc43a5edfb03c4ee167
|
||||
@@ -3906,8 +3906,8 @@ __metadata:
|
||||
"@types/react": "npm:^18.2.0"
|
||||
oxlint: "npm:^0.16.0"
|
||||
react: "npm:^18.2.0"
|
||||
twenty-client-sdk: "portal:../../twenty-client-sdk"
|
||||
twenty-sdk: "portal:../../twenty-sdk"
|
||||
twenty-client-sdk: "npm:0.8.0-canary.5"
|
||||
twenty-sdk: "npm:0.8.0-canary.5"
|
||||
typescript: "npm:^5.9.3"
|
||||
vite-tsconfig-paths: "npm:^4.2.1"
|
||||
vitest: "npm:^3.1.1"
|
||||
@@ -4030,44 +4030,45 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ink@npm:^5.1.1":
|
||||
version: 5.2.1
|
||||
resolution: "ink@npm:5.2.1"
|
||||
"ink@npm:^6.8.0":
|
||||
version: 6.8.0
|
||||
resolution: "ink@npm:6.8.0"
|
||||
dependencies:
|
||||
"@alcalzone/ansi-tokenize": "npm:^0.1.3"
|
||||
ansi-escapes: "npm:^7.0.0"
|
||||
"@alcalzone/ansi-tokenize": "npm:^0.2.4"
|
||||
ansi-escapes: "npm:^7.3.0"
|
||||
ansi-styles: "npm:^6.2.1"
|
||||
auto-bind: "npm:^5.0.1"
|
||||
chalk: "npm:^5.3.0"
|
||||
chalk: "npm:^5.6.0"
|
||||
cli-boxes: "npm:^3.0.0"
|
||||
cli-cursor: "npm:^4.0.0"
|
||||
cli-truncate: "npm:^4.0.0"
|
||||
cli-truncate: "npm:^5.1.1"
|
||||
code-excerpt: "npm:^4.0.0"
|
||||
es-toolkit: "npm:^1.22.0"
|
||||
es-toolkit: "npm:^1.39.10"
|
||||
indent-string: "npm:^5.0.0"
|
||||
is-in-ci: "npm:^1.0.0"
|
||||
is-in-ci: "npm:^2.0.0"
|
||||
patch-console: "npm:^2.0.0"
|
||||
react-reconciler: "npm:^0.29.0"
|
||||
scheduler: "npm:^0.23.0"
|
||||
react-reconciler: "npm:^0.33.0"
|
||||
scheduler: "npm:^0.27.0"
|
||||
signal-exit: "npm:^3.0.7"
|
||||
slice-ansi: "npm:^7.1.0"
|
||||
slice-ansi: "npm:^8.0.0"
|
||||
stack-utils: "npm:^2.0.6"
|
||||
string-width: "npm:^7.2.0"
|
||||
type-fest: "npm:^4.27.0"
|
||||
widest-line: "npm:^5.0.0"
|
||||
string-width: "npm:^8.1.1"
|
||||
terminal-size: "npm:^4.0.1"
|
||||
type-fest: "npm:^5.4.1"
|
||||
widest-line: "npm:^6.0.0"
|
||||
wrap-ansi: "npm:^9.0.0"
|
||||
ws: "npm:^8.18.0"
|
||||
yoga-layout: "npm:~3.2.1"
|
||||
peerDependencies:
|
||||
"@types/react": ">=18.0.0"
|
||||
react: ">=18.0.0"
|
||||
react-devtools-core: ^4.19.1
|
||||
"@types/react": ">=19.0.0"
|
||||
react: ">=19.0.0"
|
||||
react-devtools-core: ">=6.1.2"
|
||||
peerDependenciesMeta:
|
||||
"@types/react":
|
||||
optional: true
|
||||
react-devtools-core:
|
||||
optional: true
|
||||
checksum: 10c0/0e2607712783353fbe99438ca4220db3d5874c7ae1a07e2b232f7539489b13a9db929b3046eedeccf318a3ffa222a572287dbe2307c848b8e7f6ec4bba39e550
|
||||
checksum: 10c0/50500e547fdf6a1f1d836d6befbd4770e3ab649ef0be1884500a6da411fb68a90e22dd7dcc9c404911d30e9f87506b3b9d8e997c6c6ceac85ee054b4dadefaff
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -4140,14 +4141,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"is-fullwidth-code-point@npm:^4.0.0":
|
||||
version: 4.0.0
|
||||
resolution: "is-fullwidth-code-point@npm:4.0.0"
|
||||
checksum: 10c0/df2a717e813567db0f659c306d61f2f804d480752526886954a2a3e2246c7745fd07a52b5fecf2b68caf0a6c79dcdace6166fdf29cc76ed9975cc334f0a018b8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"is-fullwidth-code-point@npm:^5.0.0":
|
||||
"is-fullwidth-code-point@npm:^5.0.0, is-fullwidth-code-point@npm:^5.1.0":
|
||||
version: 5.1.0
|
||||
resolution: "is-fullwidth-code-point@npm:5.1.0"
|
||||
dependencies:
|
||||
@@ -4165,12 +4159,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"is-in-ci@npm:^1.0.0":
|
||||
version: 1.0.0
|
||||
resolution: "is-in-ci@npm:1.0.0"
|
||||
"is-in-ci@npm:^2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "is-in-ci@npm:2.0.0"
|
||||
bin:
|
||||
is-in-ci: cli.js
|
||||
checksum: 10c0/98f9cec4c35aece4cf731abf35ebf28359a9b0324fac810da05b842515d9ccb33b8999c1d9a679f0362e1a4df3292065c38d7f86327b1387fa667bc0150f4898
|
||||
checksum: 10c0/1e1d1056939a681e8206035de5ad84e0404556eaa7622bb55f0f1868b9788bff3df427bc0b1ed5a172623154a90fcb1e759a230817cd73d09435543ae3c71feb
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -5014,15 +5008,14 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-dom@npm:^18.2.0":
|
||||
version: 18.3.1
|
||||
resolution: "react-dom@npm:18.3.1"
|
||||
"react-dom@npm:^19.0.0":
|
||||
version: 19.2.4
|
||||
resolution: "react-dom@npm:19.2.4"
|
||||
dependencies:
|
||||
loose-envify: "npm:^1.1.0"
|
||||
scheduler: "npm:^0.23.2"
|
||||
scheduler: "npm:^0.27.0"
|
||||
peerDependencies:
|
||||
react: ^18.3.1
|
||||
checksum: 10c0/a752496c1941f958f2e8ac56239172296fcddce1365ce45222d04a1947e0cc5547df3e8447f855a81d6d39f008d7c32eab43db3712077f09e3f67c4874973e85
|
||||
react: ^19.2.4
|
||||
checksum: 10c0/f0c63f1794dedb154136d4d0f59af00b41907f4859571c155940296808f4b94bf9c0c20633db75b5b2112ec13d8d7dd4f9bf57362ed48782f317b11d05a44f35
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -5033,15 +5026,14 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-reconciler@npm:^0.29.0":
|
||||
version: 0.29.2
|
||||
resolution: "react-reconciler@npm:0.29.2"
|
||||
"react-reconciler@npm:^0.33.0":
|
||||
version: 0.33.0
|
||||
resolution: "react-reconciler@npm:0.33.0"
|
||||
dependencies:
|
||||
loose-envify: "npm:^1.1.0"
|
||||
scheduler: "npm:^0.23.2"
|
||||
scheduler: "npm:^0.27.0"
|
||||
peerDependencies:
|
||||
react: ^18.3.1
|
||||
checksum: 10c0/94f48ddc348a974256cf13c859f5a94efdb0cd72e04c51b1a4d5c72a8b960ccd35df2196057ee6a4cbcb26145e12b01e3f9ba3b183fddb901414db36a07cbf43
|
||||
react: ^19.2.0
|
||||
checksum: 10c0/3f7b27ea8d0ff4c8bf0e402a285e1af9b7d0e6f4c1a70a28f4384938bc1130bc82a90a31df0b79ef5e380e2e55e2598bd90b4dbf802b1203d735ba0355817d3a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -5054,6 +5046,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react@npm:^19.0.0":
|
||||
version: 19.2.4
|
||||
resolution: "react@npm:19.2.4"
|
||||
checksum: 10c0/cd2c9ff67a720799cc3b38a516009986f7fc4cb8d3e15716c6211cf098d1357ee3e348ab05ad0600042bbb0fd888530ba92e329198c92eafa0994f5213396596
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"readdirp@npm:^4.0.1":
|
||||
version: 4.1.2
|
||||
resolution: "readdirp@npm:4.1.2"
|
||||
@@ -5298,12 +5297,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"scheduler@npm:^0.23.0, scheduler@npm:^0.23.2":
|
||||
version: 0.23.2
|
||||
resolution: "scheduler@npm:0.23.2"
|
||||
dependencies:
|
||||
loose-envify: "npm:^1.1.0"
|
||||
checksum: 10c0/26383305e249651d4c58e6705d5f8425f153211aef95f15161c151f7b8de885f24751b377e4a0b3dd42cce09aad3f87a61dab7636859c0d89b7daf1a1e2a5c78
|
||||
"scheduler@npm:^0.27.0":
|
||||
version: 0.27.0
|
||||
resolution: "scheduler@npm:0.27.0"
|
||||
checksum: 10c0/4f03048cb05a3c8fddc45813052251eca00688f413a3cee236d984a161da28db28ba71bd11e7a3dd02f7af84ab28d39fb311431d3b3772fed557945beb00c452
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -5406,23 +5403,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"slice-ansi@npm:^5.0.0":
|
||||
version: 5.0.0
|
||||
resolution: "slice-ansi@npm:5.0.0"
|
||||
"slice-ansi@npm:^8.0.0":
|
||||
version: 8.0.0
|
||||
resolution: "slice-ansi@npm:8.0.0"
|
||||
dependencies:
|
||||
ansi-styles: "npm:^6.0.0"
|
||||
is-fullwidth-code-point: "npm:^4.0.0"
|
||||
checksum: 10c0/2d4d40b2a9d5cf4e8caae3f698fe24ae31a4d778701724f578e984dcb485ec8c49f0c04dab59c401821e80fcdfe89cace9c66693b0244e40ec485d72e543914f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"slice-ansi@npm:^7.1.0":
|
||||
version: 7.1.2
|
||||
resolution: "slice-ansi@npm:7.1.2"
|
||||
dependencies:
|
||||
ansi-styles: "npm:^6.2.1"
|
||||
is-fullwidth-code-point: "npm:^5.0.0"
|
||||
checksum: 10c0/36742f2eb0c03e2e81a38ed14d13a64f7b732fe38c3faf96cce0599788a345011e840db35f1430ca606ea3f8db2abeb92a8d25c2753a819e3babaa10c2e289a2
|
||||
ansi-styles: "npm:^6.2.3"
|
||||
is-fullwidth-code-point: "npm:^5.1.0"
|
||||
checksum: 10c0/0ce4aa91febb7cea4a00c2c27bb820fa53b6d2862ce0f80f7120134719f7914fc416b0ed966cf35250a3169e152916392f35917a2d7cad0fcc5d8b841010fa9a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -5532,7 +5519,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"string-width@npm:^7.0.0, string-width@npm:^7.2.0":
|
||||
"string-width@npm:^7.0.0":
|
||||
version: 7.2.0
|
||||
resolution: "string-width@npm:7.2.0"
|
||||
dependencies:
|
||||
@@ -5543,6 +5530,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"string-width@npm:^8.1.0, string-width@npm:^8.1.1, string-width@npm:^8.2.0":
|
||||
version: 8.2.0
|
||||
resolution: "string-width@npm:8.2.0"
|
||||
dependencies:
|
||||
get-east-asian-width: "npm:^1.5.0"
|
||||
strip-ansi: "npm:^7.1.2"
|
||||
checksum: 10c0/d8915428b43519b0f494da6590dbe4491857d8a12e40250e50fc01fbb616ffd8400a436bbe25712255ee129511fe0414c49d3b6b9627e2bc3a33dcec1d2eda02
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"strip-ansi@npm:^3.0.0, strip-ansi@npm:^3.0.1":
|
||||
version: 3.0.1
|
||||
resolution: "strip-ansi@npm:3.0.1"
|
||||
@@ -5570,7 +5567,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"strip-ansi@npm:^7.1.0":
|
||||
"strip-ansi@npm:^7.1.0, strip-ansi@npm:^7.1.2":
|
||||
version: 7.2.0
|
||||
resolution: "strip-ansi@npm:7.2.0"
|
||||
dependencies:
|
||||
@@ -5640,6 +5637,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tagged-tag@npm:^1.0.0":
|
||||
version: 1.0.0
|
||||
resolution: "tagged-tag@npm:1.0.0"
|
||||
checksum: 10c0/91d25c9ffb86a91f20522cefb2cbec9b64caa1febe27ad0df52f08993ff60888022d771e868e6416cf2e72dab68449d2139e8709ba009b74c6c7ecd4000048d1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tar@npm:^7.5.4":
|
||||
version: 7.5.11
|
||||
resolution: "tar@npm:7.5.11"
|
||||
@@ -5653,6 +5657,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"terminal-size@npm:^4.0.1":
|
||||
version: 4.0.1
|
||||
resolution: "terminal-size@npm:4.0.1"
|
||||
checksum: 10c0/89afd9d816dd9dbfe4499da9aeea70491bbde4ff4592226a9c8ac71074a7580afead6a78e95ecc35f6d42e09087b55ffcb1019302cd55e0cc957b6ce5c4847e8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tinybench@npm:^2.9.0":
|
||||
version: 2.9.0
|
||||
resolution: "tinybench@npm:2.9.0"
|
||||
@@ -5751,20 +5762,21 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"twenty-client-sdk@portal:../../twenty-client-sdk::locator=hello-world%40workspace%3A.":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "twenty-client-sdk@portal:../../twenty-client-sdk::locator=hello-world%40workspace%3A."
|
||||
"twenty-client-sdk@npm:0.8.0-canary.5":
|
||||
version: 0.8.0-canary.5
|
||||
resolution: "twenty-client-sdk@npm:0.8.0-canary.5"
|
||||
dependencies:
|
||||
"@genql/cli": "npm:^3.0.3"
|
||||
"@genql/runtime": "npm:^2.10.0"
|
||||
esbuild: "npm:^0.25.0"
|
||||
graphql: "npm:^16.8.1"
|
||||
checksum: 10c0/754b92b732c8e03c9779f6557324710afe4c07f7e6efbe766bd8ff3b6dd8a00c0d9f3fecce2098d68ef9556cafa722b2189e490473e420fdb9cf30c56beb3619
|
||||
languageName: node
|
||||
linkType: soft
|
||||
linkType: hard
|
||||
|
||||
"twenty-sdk@portal:../../twenty-sdk::locator=hello-world%40workspace%3A.":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "twenty-sdk@portal:../../twenty-sdk::locator=hello-world%40workspace%3A."
|
||||
"twenty-sdk@npm:0.8.0-canary.5":
|
||||
version: 0.8.0-canary.5
|
||||
resolution: "twenty-sdk@npm:0.8.0-canary.5"
|
||||
dependencies:
|
||||
"@chakra-ui/react": "npm:^3.33.0"
|
||||
"@emotion/react": "npm:^11.14.0"
|
||||
@@ -5782,13 +5794,14 @@ __metadata:
|
||||
esbuild: "npm:^0.25.0"
|
||||
graphql: "npm:^16.8.1"
|
||||
graphql-sse: "npm:^2.5.4"
|
||||
ink: "npm:^5.1.1"
|
||||
ink: "npm:^6.8.0"
|
||||
inquirer: "npm:^10.0.0"
|
||||
jsonc-parser: "npm:^3.2.0"
|
||||
preact: "npm:^10.28.3"
|
||||
react: "npm:^18.2.0"
|
||||
react-dom: "npm:^18.2.0"
|
||||
react: "npm:^19.0.0"
|
||||
react-dom: "npm:^19.0.0"
|
||||
tinyglobby: "npm:^0.2.15"
|
||||
twenty-client-sdk: "npm:0.8.0-canary.5"
|
||||
typescript: "npm:^5.9.2"
|
||||
uuid: "npm:^13.0.0"
|
||||
vite: "npm:^7.0.0"
|
||||
@@ -5796,8 +5809,9 @@ __metadata:
|
||||
zod: "npm:^4.1.11"
|
||||
bin:
|
||||
twenty: dist/cli.cjs
|
||||
checksum: 10c0/47d0970c88f59c092e8eca34dca38bf88d9d52678997349068ca8a8e5cebed2ea71dbd4e8b7299f40b99b5419d4cecd53b31f821b65959267e8d97eb91d2ddde
|
||||
languageName: node
|
||||
linkType: soft
|
||||
linkType: hard
|
||||
|
||||
"type-fest@npm:^0.21.3":
|
||||
version: 0.21.3
|
||||
@@ -5806,10 +5820,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"type-fest@npm:^4.27.0":
|
||||
version: 4.41.0
|
||||
resolution: "type-fest@npm:4.41.0"
|
||||
checksum: 10c0/f5ca697797ed5e88d33ac8f1fec21921839871f808dc59345c9cf67345bfb958ce41bd821165dbf3ae591cedec2bf6fe8882098dfdd8dc54320b859711a2c1e4
|
||||
"type-fest@npm:^5.4.1":
|
||||
version: 5.5.0
|
||||
resolution: "type-fest@npm:5.5.0"
|
||||
dependencies:
|
||||
tagged-tag: "npm:^1.0.0"
|
||||
checksum: 10c0/60bf79a8df45abf99490e3204eceb5cf7f915413f8a69fb578c75cab37ddcb7d29ee21f185f0e1617323ac0b2a441e001b8dc691e220d0b087e9c29ea205538c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -6123,12 +6139,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"widest-line@npm:^5.0.0":
|
||||
version: 5.0.0
|
||||
resolution: "widest-line@npm:5.0.0"
|
||||
"widest-line@npm:^6.0.0":
|
||||
version: 6.0.0
|
||||
resolution: "widest-line@npm:6.0.0"
|
||||
dependencies:
|
||||
string-width: "npm:^7.0.0"
|
||||
checksum: 10c0/6bd6cca8cda502ef50e05353fd25de0df8c704ffc43ada7e0a9cf9a5d4f4e12520485d80e0b77cec8a21f6c3909042fcf732aa9281e5dbb98cc9384a138b2578
|
||||
string-width: "npm:^8.1.0"
|
||||
checksum: 10c0/735f1fdcd97fe765a07bb8b5e73c020bed8e53ab34e83ce0ef01693ba3c914d9e7977fe5f5facf0d0b670297a82dd5e376d3efa0896860dfcdaf7cd6924c0fb7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "twenty-client-sdk",
|
||||
"version": "0.8.0-canary.6",
|
||||
"version": "0.8.0-canary.7",
|
||||
"sideEffects": false,
|
||||
"license": "AGPL-3.0",
|
||||
"scripts": {
|
||||
|
||||
@@ -1726,8 +1726,6 @@ enum FeatureFlagKey {
|
||||
IS_EMAILING_DOMAIN_ENABLED
|
||||
IS_JUNCTION_RELATIONS_ENABLED
|
||||
IS_COMMAND_MENU_ITEM_ENABLED
|
||||
IS_NAVIGATION_MENU_ITEM_ENABLED
|
||||
IS_NAVIGATION_MENU_ITEM_EDITING_ENABLED
|
||||
IS_DRAFT_EMAIL_ENABLED
|
||||
IS_USAGE_ANALYTICS_ENABLED
|
||||
IS_RICH_TEXT_V1_MIGRATED
|
||||
|
||||
@@ -1422,7 +1422,7 @@ export interface PublicFeatureFlag {
|
||||
__typename: 'PublicFeatureFlag'
|
||||
}
|
||||
|
||||
export type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_AI_ENABLED' | 'IS_MARKETPLACE_ENABLED' | 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' | 'IS_PUBLIC_DOMAIN_ENABLED' | 'IS_EMAILING_DOMAIN_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_COMMAND_MENU_ITEM_ENABLED' | 'IS_NAVIGATION_MENU_ITEM_ENABLED' | 'IS_NAVIGATION_MENU_ITEM_EDITING_ENABLED' | 'IS_DRAFT_EMAIL_ENABLED' | 'IS_USAGE_ANALYTICS_ENABLED' | 'IS_RICH_TEXT_V1_MIGRATED' | 'IS_DIRECT_GRAPHQL_EXECUTION_ENABLED' | 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' | 'IS_CONNECTED_ACCOUNT_MIGRATED' | 'IS_GRAPHQL_QUERY_TIMING_ENABLED' | 'IS_RECORD_TABLE_WIDGET_ENABLED' | 'IS_DATASOURCE_MIGRATED'
|
||||
export type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_AI_ENABLED' | 'IS_MARKETPLACE_ENABLED' | 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' | 'IS_PUBLIC_DOMAIN_ENABLED' | 'IS_EMAILING_DOMAIN_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_COMMAND_MENU_ITEM_ENABLED' | 'IS_DRAFT_EMAIL_ENABLED' | 'IS_USAGE_ANALYTICS_ENABLED' | 'IS_RICH_TEXT_V1_MIGRATED' | 'IS_DIRECT_GRAPHQL_EXECUTION_ENABLED' | 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' | 'IS_CONNECTED_ACCOUNT_MIGRATED' | 'IS_GRAPHQL_QUERY_TIMING_ENABLED' | 'IS_RECORD_TABLE_WIDGET_ENABLED' | 'IS_DATASOURCE_MIGRATED'
|
||||
|
||||
export interface ClientConfig {
|
||||
appVersion?: Scalars['String']
|
||||
@@ -8953,8 +8953,6 @@ export const enumFeatureFlagKey = {
|
||||
IS_EMAILING_DOMAIN_ENABLED: 'IS_EMAILING_DOMAIN_ENABLED' as const,
|
||||
IS_JUNCTION_RELATIONS_ENABLED: 'IS_JUNCTION_RELATIONS_ENABLED' as const,
|
||||
IS_COMMAND_MENU_ITEM_ENABLED: 'IS_COMMAND_MENU_ITEM_ENABLED' as const,
|
||||
IS_NAVIGATION_MENU_ITEM_ENABLED: 'IS_NAVIGATION_MENU_ITEM_ENABLED' as const,
|
||||
IS_NAVIGATION_MENU_ITEM_EDITING_ENABLED: 'IS_NAVIGATION_MENU_ITEM_EDITING_ENABLED' as const,
|
||||
IS_DRAFT_EMAIL_ENABLED: 'IS_DRAFT_EMAIL_ENABLED' as const,
|
||||
IS_USAGE_ANALYTICS_ENABLED: 'IS_USAGE_ANALYTICS_ENABLED' as const,
|
||||
IS_RICH_TEXT_V1_MIGRATED: 'IS_RICH_TEXT_V1_MIGRATED' as const,
|
||||
|
||||
@@ -16,6 +16,7 @@ COPY ./packages/twenty-server/patches /app/packages/twenty-server/patches
|
||||
COPY ./packages/twenty-ui/package.json /app/packages/twenty-ui/
|
||||
COPY ./packages/twenty-shared/package.json /app/packages/twenty-shared/
|
||||
COPY ./packages/twenty-front/package.json /app/packages/twenty-front/
|
||||
COPY ./packages/twenty-front-component-renderer/package.json /app/packages/twenty-front-component-renderer/
|
||||
COPY ./packages/twenty-sdk/package.json /app/packages/twenty-sdk/
|
||||
COPY ./packages/twenty-client-sdk/package.json /app/packages/twenty-client-sdk/
|
||||
|
||||
@@ -51,6 +52,7 @@ FROM common-deps AS twenty-front-build
|
||||
ARG REACT_APP_SERVER_BASE_URL
|
||||
|
||||
COPY ./packages/twenty-front /app/packages/twenty-front
|
||||
COPY ./packages/twenty-front-component-renderer /app/packages/twenty-front-component-renderer
|
||||
COPY ./packages/twenty-ui /app/packages/twenty-ui
|
||||
COPY ./packages/twenty-shared /app/packages/twenty-shared
|
||||
COPY ./packages/twenty-sdk /app/packages/twenty-sdk
|
||||
|
||||
@@ -362,7 +362,7 @@ If you plan to [publish your app](/developers/extend/apps/publishing), these opt
|
||||
| `category` | App category for marketplace filtering |
|
||||
| `logoUrl` | Path to your app logo (relative to `./assets/`) |
|
||||
| `screenshots` | Array of screenshot paths (relative to `./assets/`) |
|
||||
| `aboutDescription` | Longer markdown description for the "About" tab |
|
||||
| `aboutDescription` | Longer markdown description for the "About" tab. If omitted, the marketplace uses the package's `README.md` from npm |
|
||||
| `websiteUrl` | Link to your website |
|
||||
| `termsUrl` | Link to terms of service |
|
||||
| `emailSupport` | Support email address |
|
||||
|
||||
@@ -9,17 +9,18 @@ Apps are currently in alpha testing. The feature is functional but still evolvin
|
||||
|
||||
Apps let you extend Twenty with custom objects, fields, logic functions, AI skills, and UI components — all managed as code.
|
||||
|
||||
**What you can do today:**
|
||||
- Define custom objects and fields as code (managed data model)
|
||||
- Build logic functions with custom triggers (HTTP routes, cron, database events)
|
||||
- Define skills for AI agents
|
||||
- Build front components that render inside Twenty's UI
|
||||
- Deploy the same app across multiple workspaces
|
||||
**What you can build:**
|
||||
- Custom objects, fields, views, and navigation items to shape your data model
|
||||
- Logic functions triggered by HTTP routes, cron schedules, or database events
|
||||
- Front components that render directly inside Twenty's UI
|
||||
- Skills that extend Twenty's AI agents
|
||||
- Deploy an app across multiple workspaces
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Node.js 24+ and Yarn 4
|
||||
- Docker (for the local Twenty dev server)
|
||||
- Node.js 24+
|
||||
- Yarn 4
|
||||
- Docker (or a running local Twenty instance)
|
||||
|
||||
## Getting Started
|
||||
|
||||
@@ -28,21 +29,9 @@ Create a new app using the official scaffolder, then authenticate and start deve
|
||||
```bash filename="Terminal"
|
||||
# Scaffold a new app (includes all examples by default)
|
||||
npx create-twenty-app@latest my-twenty-app
|
||||
cd my-twenty-app
|
||||
|
||||
# Start dev mode: automatically syncs local changes to your workspace
|
||||
yarn twenty 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, agent)
|
||||
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
|
||||
```
|
||||
> Use `--minimal` option to scaffold a minimal installation
|
||||
|
||||
From here you can:
|
||||
|
||||
|
||||
@@ -102,6 +102,10 @@ yarn twenty catalog-sync -r production
|
||||
|
||||
The metadata shown in the marketplace comes from your `defineApplication()` call in your app source code — fields like `displayName`, `description`, `author`, `category`, `logoUrl`, `screenshots`, `aboutDescription`, `websiteUrl`, and `termsUrl`.
|
||||
|
||||
<Note>
|
||||
If your app does not define an `aboutDescription` in `defineApplication()`, the marketplace will automatically use your package's `README.md` from npm as the about page content. This means you can maintain a single README for both npm and the Twenty marketplace. If you want a different description in the marketplace, explicitly set `aboutDescription`.
|
||||
</Note>
|
||||
|
||||
### CI publishing
|
||||
|
||||
The scaffolded project includes a GitHub Actions workflow that publishes on every release:
|
||||
|
||||
@@ -37,7 +37,7 @@ yarn twenty dev
|
||||
|
||||
### Local Server Management
|
||||
|
||||
The SDK includes commands to manage a local Twenty dev server (all-in-one Docker image with PostgreSQL, Redis, server, and worker):
|
||||
The SDK includes commands to manage a local Twenty dev server (all-in-one Docker image with PostgreSQL, Redis, server, and worker on port 2020). These commands only apply to the Docker-based dev server — they do not manage a Twenty instance started from source (e.g. `npx nx start twenty-server` on port 3000):
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Start the local server (pulls the image if needed)
|
||||
|
||||
@@ -358,17 +358,17 @@ export default defineApplication({
|
||||
|
||||
إذا كنت تخطط لـ [نشر تطبيقك](/l/ar/developers/extend/apps/publishing)، فإن هذه الحقول الاختيارية تتحكّم في كيفية ظهور تطبيقك في السوق:
|
||||
|
||||
| الحقل | الوصف |
|
||||
| ------------------ | ---------------------------------------------------- |
|
||||
| `author` | اسم المؤلف أو الشركة |
|
||||
| `category` | فئة التطبيق لتصفية سوق التطبيقات |
|
||||
| `logoUrl` | المسار إلى شعار تطبيقك (نسبيًا إلى `./assets/`) |
|
||||
| `screenshots` | مصفوفة لمسارات لقطات الشاشة (نسبيًا إلى `./assets/`) |
|
||||
| `aboutDescription` | وصف ماركداون أطول لعلامة التبويب "حول" |
|
||||
| `websiteUrl` | رابط إلى موقعك الإلكتروني |
|
||||
| `termsUrl` | رابط إلى شروط الخدمة |
|
||||
| `emailSupport` | عنوان البريد الإلكتروني للدعم |
|
||||
| `issueReportUrl` | رابط إلى متتبّع المشاكل |
|
||||
| الحقل | الوصف |
|
||||
| ------------------ | ------------------------------------------------------------------------------------------------------------ |
|
||||
| `author` | اسم المؤلف أو الشركة |
|
||||
| `category` | فئة التطبيق لتصفية سوق التطبيقات |
|
||||
| `logoUrl` | المسار إلى شعار تطبيقك (نسبيًا إلى `./assets/`) |
|
||||
| `screenshots` | مصفوفة لمسارات لقطات الشاشة (نسبيًا إلى `./assets/`) |
|
||||
| `aboutDescription` | وصف ماركداون أطول لعلامة التبويب "حول". إذا لم يتم تضمينه، يستخدم السوق ملف `README.md` الخاص بالحزمة من npm |
|
||||
| `websiteUrl` | رابط إلى موقعك الإلكتروني |
|
||||
| `termsUrl` | رابط إلى شروط الخدمة |
|
||||
| `emailSupport` | عنوان البريد الإلكتروني للدعم |
|
||||
| `issueReportUrl` | رابط إلى متتبّع المشاكل |
|
||||
|
||||
#### الأدوار والصلاحيات
|
||||
|
||||
|
||||
@@ -9,18 +9,19 @@ description: أنشئ أول تطبيق Twenty خلال دقائق.
|
||||
|
||||
تتيح لك التطبيقات توسيع Twenty باستخدام كائنات وحقول ووظائف منطقية ومهارات ذكاء اصطناعي ومكونات واجهة مستخدم مخصصة — جميعها تُدار ككود.
|
||||
|
||||
**ما الذي يمكنك فعله اليوم:**
|
||||
**ما الذي يمكنك بناؤه:**
|
||||
|
||||
* عرِّف كائنات وحقولًا مخصصة على شكل كود (نموذج بيانات مُدار)
|
||||
* أنشئ وظائف منطقية مع مشغلات مخصصة (مسارات HTTP، cron، أحداث قاعدة البيانات)
|
||||
* حدد المهارات لوكلاء الذكاء الاصطناعي
|
||||
* أنشئ مكونات واجهية تُعرَض داخل واجهة مستخدم Twenty
|
||||
* انشر التطبيق نفسه عبر مساحات عمل متعددة
|
||||
* كائنات مخصّصة، وحقول، وطرق عرض، وعناصر تنقّل لتشكيل نموذج بياناتك
|
||||
* دوال منطقية يتم تشغيلها عبر مسارات HTTP، وجداول cron، أو أحداث قاعدة البيانات
|
||||
* مكوّنات واجهة أمامية تُعرَض مباشرة داخل واجهة مستخدم Twenty
|
||||
* مهارات توسّع قدرات وكلاء الذكاء الاصطناعي في Twenty
|
||||
* انشر تطبيقاً عبر مساحات عمل متعددة
|
||||
|
||||
## المتطلبات الأساسية
|
||||
|
||||
* Node.js 24+ وYarn 4
|
||||
* Docker (لخادم تطوير Twenty المحلي)
|
||||
* Node.js 24+
|
||||
* Yarn 4
|
||||
* Docker (أو مثيل Twenty محلي قيد التشغيل)
|
||||
|
||||
## البدء
|
||||
|
||||
@@ -29,21 +30,9 @@ description: أنشئ أول تطبيق Twenty خلال دقائق.
|
||||
```bash filename="Terminal"
|
||||
# Scaffold a new app (includes all examples by default)
|
||||
npx create-twenty-app@latest my-twenty-app
|
||||
cd my-twenty-app
|
||||
|
||||
# Start dev mode: automatically syncs local changes to your workspace
|
||||
yarn twenty dev
|
||||
```
|
||||
|
||||
يدعم المُهيئ وضعين للتحكم في ملفات الأمثلة التي سيتم تضمينها:
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Default (exhaustive): all examples (object, field, logic function, front component, view, navigation menu item, skill, agent)
|
||||
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
|
||||
```
|
||||
> استخدم الخيار `--minimal` لتهيئة تثبيت مصغّر
|
||||
|
||||
من هنا يمكنك:
|
||||
|
||||
@@ -123,7 +112,7 @@ my-twenty-app/
|
||||
بشكل عام:
|
||||
|
||||
* **package.json**: يصرّح باسم التطبيق والإصدار والمحرّكات (Node 24+، Yarn 4)، ويضيف `twenty-sdk` بالإضافة إلى نص برمجي `twenty` يفوِّض إلى `twenty` CLI المحلي. شغِّل `yarn twenty help` لعرض جميع الأوامر المتاحة.
|
||||
* **.gitignore**: Ignores common artifacts such as `node_modules`, `.yarn`, `.twenty/`, `dist/`, `build/`, coverage folders, log files, and `.env*` files.
|
||||
* **.gitignore**: يتجاهل العناصر الشائعة مثل `node_modules` و`.yarn` و`.twenty/` و`dist/` و`build/` ومجلدات التغطية وملفات السجلات وملفات `.env*`.
|
||||
* **yarn.lock**، **.yarnrc.yml**، **.yarn/**: تقوم بقفل وتكوين حزمة أدوات Yarn 4 المستخدمة في المشروع.
|
||||
* **.nvmrc**: يثبّت إصدار Node.js المتوقع للمشروع.
|
||||
* **.oxlintrc.json** و **tsconfig.json**: يقدّمان إعدادات الفحص والتهيئة لـ TypeScript لمصادر TypeScript في تطبيقك.
|
||||
@@ -167,8 +156,8 @@ export default defineObject({
|
||||
|
||||
ستضيف الأوامر اللاحقة مزيدًا من الملفات والمجلدات:
|
||||
|
||||
* `yarn twenty dev` will auto-generate the typed `CoreApiClient` (for workspace data via `/graphql`) into `node_modules/twenty-client-sdk/`. The `MetadataApiClient` (for workspace configuration and file uploads via `/metadata`) ships pre-built and is available immediately. Import them from `twenty-client-sdk/core` and `twenty-client-sdk/metadata` respectively.
|
||||
* `yarn twenty add` will add entity definition files under `src/` for your custom objects, functions, front components, roles, skills, and more.
|
||||
* `yarn twenty dev` سيولّد تلقائياً `CoreApiClient` مضبوط الأنواع (لبيانات مساحة العمل عبر `/graphql`) داخل `node_modules/twenty-client-sdk/`. `MetadataApiClient` (لتهيئة مساحة العمل ورفع الملفات عبر `/metadata`) يأتي مُبنًى مسبقاً ومتاحاً على الفور. استوردْهما من `twenty-client-sdk/core` و`twenty-client-sdk/metadata` على الترتيب.
|
||||
* `yarn twenty add` سيضيف ملفات تعريف الكيانات ضمن `src/` لكائناتك المخصّصة، والوظائف، ومكوّنات الواجهة الأمامية، والأدوار، والمهارات، وغير ذلك.
|
||||
|
||||
## المصادقة
|
||||
|
||||
|
||||
@@ -24,9 +24,9 @@ description: وزّع تطبيق Twenty الخاص بك على سوق Twenty أ
|
||||
yarn twenty build
|
||||
```
|
||||
|
||||
يتم حفظ المخرجات في `.twenty/output/`. This directory contains everything needed for distribution: compiled code, assets, the manifest, and a copy of your `package.json`.
|
||||
يتم حفظ المخرجات في `.twenty/output/`. يحتوي هذا الدليل على كل ما يلزم للتوزيع: الكود المُجمَّع، والأصول، وملف manifest، ونسخة من `package.json` الخاص بك.
|
||||
|
||||
To also create a `.tgz` tarball (used by the deploy command internally, or for manual distribution):
|
||||
لإنشاء حزمة tarball بصيغة `.tgz` أيضًا (تُستخدم داخليًا بواسطة أمر النشر، أو للتوزيع اليدوي):
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty build --tarball
|
||||
@@ -39,11 +39,11 @@ yarn twenty build --tarball
|
||||
### المتطلبات
|
||||
|
||||
* حساب على [npm](https://www.npmjs.com)
|
||||
* The `twenty-app` keyword **must** be listed in your `package.json` `keywords` array
|
||||
* الكلمة المفتاحية `twenty-app` **يجب** أن تُدرج في مصفوفة `keywords` في `package.json` الخاص بك
|
||||
|
||||
### Adding the required keyword
|
||||
### إضافة الكلمة المفتاحية المطلوبة
|
||||
|
||||
The Twenty marketplace discovers apps by searching the npm registry for packages with the `twenty-app` keyword. Add it to your `package.json`:
|
||||
يعثر سوق Twenty على التطبيقات من خلال البحث في سجل npm عن الحزم التي تحتوي على الكلمة المفتاحية `twenty-app`. أضِفها إلى `package.json` الخاص بك:
|
||||
|
||||
```json filename="package.json"
|
||||
{
|
||||
@@ -55,52 +55,56 @@ The Twenty marketplace discovers apps by searching the npm registry for packages
|
||||
```
|
||||
|
||||
<Note>
|
||||
The marketplace searches for `keywords:twenty-app` on the npm registry. Without this keyword, your package won't appear in the marketplace even if it has the `twenty-app-` name prefix.
|
||||
يبحث السوق عن `keywords:twenty-app` في سجل npm. من دون هذه الكلمة المفتاحية، لن تظهر حزمتك في السوق حتى وإن كانت تحمل بادئة الاسم `twenty-app-`.
|
||||
</Note>
|
||||
|
||||
### الخطوات
|
||||
|
||||
1. **Build your app:**
|
||||
1. **بناء تطبيقك:**
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty build
|
||||
```
|
||||
|
||||
2. **Publish to npm:**
|
||||
2. **النشر على npm:**
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty publish
|
||||
```
|
||||
|
||||
This runs `npm publish` from the `.twenty/output/` directory.
|
||||
هذا يُشغِّل `npm publish` من دليل `.twenty/output/`.
|
||||
|
||||
To publish under a specific dist-tag (e.g., `beta` or `next`):
|
||||
للنشر تحت dist-tag معيّن (مثلًا: `beta` أو `next`):
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty publish --tag beta
|
||||
```
|
||||
|
||||
### How marketplace discovery works
|
||||
### كيف تعمل آلية الاكتشاف في السوق
|
||||
|
||||
The Twenty server syncs its marketplace catalog from the npm registry **every hour**:
|
||||
يقوم خادم Twenty بمزامنة كتالوج السوق من سجل npm **كل ساعة**:
|
||||
|
||||
1. It searches for all npm packages with the `keywords:twenty-app` keyword
|
||||
2. For each package, it fetches the `manifest.json` from the npm CDN
|
||||
3. The app's metadata (name, description, author, logo, screenshots, category) is extracted from the manifest and displayed in the marketplace
|
||||
1. يبحث عن جميع حزم npm التي تحتوي على الكلمة المفتاحية `keywords:twenty-app`
|
||||
2. ولكل حزمة، يجلب ملف `manifest.json` من شبكة CDN الخاصة بـ npm
|
||||
3. يتم استخراج بيانات التعريف الخاصة بالتطبيق (الاسم، الوصف، المؤلف، الشعار، لقطات الشاشة، الفئة) من ملف manifest وعرضها في السوق
|
||||
|
||||
After publishing, your app can take up to one hour to appear in the marketplace. To trigger the sync immediately instead of waiting for the next hourly run:
|
||||
بعد النشر، قد يستغرق ظهور تطبيقك في السوق ما يصل إلى ساعة واحدة. لتشغيل المزامنة فورًا بدلًا من انتظار التشغيل التالي كل ساعة:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty catalog-sync
|
||||
```
|
||||
|
||||
To target a specific remote:
|
||||
لاستهداف remote معيّن:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty catalog-sync -r production
|
||||
```
|
||||
|
||||
The metadata shown in the marketplace comes from your `defineApplication()` call in your app source code — fields like `displayName`, `description`, `author`, `category`, `logoUrl`, `screenshots`, `aboutDescription`, `websiteUrl`, and `termsUrl`.
|
||||
تأتي بيانات التعريف المعروضة في السوق من استدعائك لـ `defineApplication()` في الشيفرة المصدرية لتطبيقك — حقول مثل `displayName` و`description` و`author` و`category` و`logoUrl` و`screenshots` و`aboutDescription` و`websiteUrl` و`termsUrl`.
|
||||
|
||||
<Note>
|
||||
إذا لم يحدد تطبيقك `aboutDescription` في `defineApplication()`، فسيستخدم السوق تلقائيًا ملف `README.md` الخاص بحزمتك من npm كمحتوى لصفحة حول. هذا يعني أنه يمكنك الاحتفاظ بملف README واحد لكل من npm وسوق Twenty. إذا كنت تريد وصفًا مختلفًا في السوق، فقم بتعيين `aboutDescription` بشكل صريح.
|
||||
</Note>
|
||||
|
||||
### النشر عبر CI
|
||||
|
||||
@@ -133,39 +137,39 @@ jobs:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
```
|
||||
|
||||
For other CI systems (GitLab CI, CircleCI, etc.), the same three commands apply: `yarn install`, `yarn twenty build`, then `npm publish` from `.twenty/output`.
|
||||
بالنسبة لأنظمة CI الأخرى (GitLab CI، وCircleCI، إلخ)، تنطبق الأوامر الثلاثة نفسها: `yarn install`، ثم `yarn twenty build`، ثم `npm publish` من `.twenty/output`.
|
||||
|
||||
<Tip>
|
||||
**npm provenance** اختياري ولكنه موصى به. يضيف النشر باستخدام `--provenance` شارة ثقة إلى إدراجك على npm، مما يتيح للمستخدمين التحقق من أن الحزمة تم بناؤها من التزام محدد ضمن خط أنابيب CI عام. راجع [وثائق npm provenance](https://docs.npmjs.com/generating-provenance-statements) للحصول على تعليمات الإعداد.
|
||||
</Tip>
|
||||
|
||||
## Deploying to a server (tarball)
|
||||
## النشر إلى خادم (tarball)
|
||||
|
||||
For apps you don't want publicly available — proprietary tools, enterprise-only integrations, or experimental builds — you can deploy a tarball directly to a Twenty server.
|
||||
بالنسبة للتطبيقات التي لا تريد إتاحتها للعامة — مثل الأدوات المملوكة، أو عمليات التكامل الخاصة بالمؤسسات فقط، أو الإصدارات التجريبية — يمكنك نشر tarball مباشرةً إلى خادم Twenty.
|
||||
|
||||
### المتطلبات الأساسية
|
||||
|
||||
Before deploying, you need a configured remote pointing to the target server. Remotes store the server URL and authentication credentials locally in `~/.twenty/config.json`.
|
||||
قبل النشر، تحتاج إلى remote مُعدّ يشير إلى خادم الهدف. تُخزّن remotes عنوان URL للخادم وبيانات اعتماد المصادقة محليًا في `~/.twenty/config.json`.
|
||||
|
||||
Add a remote:
|
||||
أضِف remote:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty remote add --url https://your-twenty-server.com --as production
|
||||
```
|
||||
|
||||
For a local development server:
|
||||
لخادم تطوير محلي:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty remote add --local --as local
|
||||
```
|
||||
|
||||
You can also authenticate with an API key for non-interactive environments:
|
||||
يمكنك أيضًا إجراء المصادقة باستخدام مفتاح API للبيئات غير التفاعلية:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty remote add --url https://your-twenty-server.com --token <api-key> --as production
|
||||
```
|
||||
|
||||
Manage your remotes:
|
||||
إدارة remotes الخاصة بك:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty remote list # List all configured remotes
|
||||
@@ -174,76 +178,76 @@ yarn twenty remote status # Show active remote and auth status
|
||||
yarn twenty remote remove old # Remove a remote
|
||||
```
|
||||
|
||||
### Deploying
|
||||
### النشر
|
||||
|
||||
Build and upload your app to the server in one step:
|
||||
بناء تطبيقك ورفعه إلى الخادم في خطوة واحدة:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty deploy
|
||||
```
|
||||
|
||||
This builds the app with `--tarball`, then uploads the tarball to the default remote via a GraphQL multipart upload.
|
||||
يُنشئ هذا التطبيق باستخدام `--tarball`، ثم يرفع ملف tarball إلى الـ remote الافتراضي عبر رفع متعدد الأجزاء لـ GraphQL.
|
||||
|
||||
To deploy to a specific remote:
|
||||
لنشره إلى remote معيّن:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty deploy -r production
|
||||
```
|
||||
|
||||
### Sharing a deployed app
|
||||
### مشاركة تطبيق منشور
|
||||
|
||||
Tarball apps are not listed in the public marketplace, so other workspaces on the same server won't discover them by browsing. To share a deployed app:
|
||||
تطبيقات tarball لا تُدرَج في السوق العامة، لذا لن تكتشفها مساحات العمل الأخرى على الخادم نفسه عبر الاستعراض. لمشاركة تطبيق منشور:
|
||||
|
||||
1. Go to **Settings > Applications > Registrations** and open your app
|
||||
2. In the **Distribution** tab, click **Copy share link**
|
||||
3. Share this link with users on other workspaces — it takes them directly to the app's install page
|
||||
1. اذهب إلى **الإعدادات > التطبيقات > التسجيلات** وافتح تطبيقك
|
||||
2. في علامة التبويب **التوزيع**، انقر **نسخ رابط المشاركة**
|
||||
3. شارك هذا الرابط مع المستخدمين في مساحات عمل أخرى — سيأخذهم مباشرةً إلى صفحة تثبيت التطبيق
|
||||
|
||||
The share link uses the server's base URL (without any workspace subdomain) so it works for any workspace on the server.
|
||||
يستخدم رابط المشاركة عنوان URL الأساسي للخادم (من دون أي نطاق فرعي لمساحة عمل)، لذا يعمل مع أي مساحة عمل على الخادم.
|
||||
|
||||
### إدارة الإصدارات
|
||||
|
||||
لطرح تحديث:
|
||||
|
||||
1. ارفع قيمة الحقل `version` في ملف `package.json`
|
||||
2. Run `yarn twenty deploy` (or `yarn twenty deploy -r production`)
|
||||
3. Workspaces that have the app installed will see the upgrade available in their settings
|
||||
2. شغّل `yarn twenty deploy` (أو `yarn twenty deploy -r production`)
|
||||
3. سترى مساحات العمل التي ثبّتت التطبيق الترقية متاحة في إعداداتها
|
||||
|
||||
## Installing apps
|
||||
## تثبيت التطبيقات
|
||||
|
||||
Once an app is published (npm) or deployed (tarball), workspaces install it through the UI:
|
||||
بعد نشر التطبيق (npm) أو نشره إلى الخادم (tarball)، تقوم مساحات العمل بتثبيته عبر واجهة المستخدم:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty install
|
||||
```
|
||||
|
||||
Or from the **Settings > Applications** page in the Twenty UI, where both marketplace and tarball-deployed apps can be browsed and installed.
|
||||
أو من صفحة **الإعدادات > التطبيقات** في واجهة Twenty، حيث يمكن استعراض التطبيقات من السوق ومن النشر عبر tarball وتثبيتها.
|
||||
|
||||
## App distribution categories
|
||||
## فئات توزيع التطبيقات
|
||||
|
||||
تُنظِّم Twenty التطبيقات في ثلاث فئات استنادًا إلى طريقة توزيعها:
|
||||
|
||||
| الفئة | كيف يعمل | مرئي في سوق Twenty؟ |
|
||||
| ---------------------- | -------------------------------------------------------------------------------------------------------- | ------------------- |
|
||||
| **التطوير** | تطبيقات وضع التطوير المحلي التي تعمل عبر `yarn twenty dev`. تُستخدم للبناء والاختبار. | لا |
|
||||
| **Published (npm)** | Apps published to npm with the `twenty-app` keyword. مدرجة في سوق Twenty لتتمكن أي مساحة عمل من تثبيتها. | نعم |
|
||||
| **Internal (tarball)** | تطبيقات منشورة عبر tarball إلى خادم محدد. Available only to workspaces on that server via a share link. | لا |
|
||||
| الفئة | كيف يعمل | مرئي في سوق Twenty؟ |
|
||||
| ------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------- |
|
||||
| **التطوير** | تطبيقات وضع التطوير المحلي التي تعمل عبر `yarn twenty dev`. تُستخدم للبناء والاختبار. | لا |
|
||||
| **منشور (npm)** | تطبيقات منشورة على npm تحتوي على الكلمة المفتاحية `twenty-app`. مدرجة في سوق Twenty لتتمكن أي مساحة عمل من تثبيتها. | نعم |
|
||||
| **داخلي (tarball)** | تطبيقات منشورة عبر tarball إلى خادم محدد. متاحة فقط لمساحات العمل على ذلك الخادم عبر رابط مشاركة. | لا |
|
||||
|
||||
<Tip>
|
||||
ابدأ في وضع **التطوير** أثناء بناء تطبيقك. عندما يصبح جاهزًا، اختر **منشور** (npm) للتوزيع الواسع أو **داخلي** (tarball) للنشر الخاص.
|
||||
</Tip>
|
||||
|
||||
## CLI reference
|
||||
## مرجع CLI
|
||||
|
||||
| أمر | الوصف | Key flags |
|
||||
| --------------------------- | ---------------------------------------------- | --------------------------------------------------- |
|
||||
| `yarn twenty build` | Compile app and generate manifest | `--tarball` — also create a `.tgz` package |
|
||||
| `yarn twenty publish` | Build and publish to npm | `--tag <tag>` — npm dist-tag (e.g., `beta`, `next`) |
|
||||
| `yarn twenty deploy` | Build and upload tarball to a server | `-r, --remote <name>` — target remote |
|
||||
| `yarn twenty catalog-sync` | Trigger marketplace catalog sync on the server | `-r, --remote <name>` — target remote |
|
||||
| `yarn twenty install` | Install a deployed app on a workspace | `-r, --remote <name>` — target remote |
|
||||
| `yarn twenty dev` | Watch and sync local changes | Uses default remote |
|
||||
| `yarn twenty remote add` | Add a server connection | `--url`, `--token`, `--as`, `--local`, `--port` |
|
||||
| `yarn twenty remote list` | List configured remotes | — |
|
||||
| `yarn twenty remote switch` | Set default remote | — |
|
||||
| `yarn twenty remote status` | Show connection status | — |
|
||||
| `yarn twenty remote remove` | Remove a remote | — |
|
||||
| أمر | الوصف | الأعلام الرئيسية |
|
||||
| --------------------------- | ------------------------------------ | ----------------------------------------------------- |
|
||||
| `yarn twenty build` | تجميع التطبيق وإنشاء manifest | `--tarball` — يقوم أيضًا بإنشاء حزمة `.tgz` |
|
||||
| `yarn twenty publish` | بناء التطبيق ونشره إلى npm | `--tag <tag>` — وسم توزيع npm (مثلًا: `beta`، `next`) |
|
||||
| `yarn twenty deploy` | بناء ورفع tarball إلى خادم | `-r, --remote <name>` — الـ remote المستهدف |
|
||||
| `yarn twenty catalog-sync` | تشغيل مزامنة كتالوج السوق على الخادم | `-r, --remote <name>` — الـ remote المستهدف |
|
||||
| `yarn twenty install` | تثبيت تطبيق منشور على مساحة عمل | `-r, --remote <name>` — الـ remote المستهدف |
|
||||
| `yarn twenty dev` | مراقبة ومزامنة التغييرات المحلية | يستخدم الـ remote الافتراضي |
|
||||
| `yarn twenty remote add` | إضافة اتصال بخادم | `--url`, `--token`, `--as`, `--local`, `--port` |
|
||||
| `yarn twenty remote list` | عرض الـ remotes المُكوَّنة | — |
|
||||
| `yarn twenty remote switch` | تعيين الـ remote الافتراضي | — |
|
||||
| `yarn twenty remote status` | عرض حالة الاتصال | — |
|
||||
| `yarn twenty remote remove` | إزالة remote | — |
|
||||
|
||||
@@ -38,7 +38,7 @@ yarn twenty dev
|
||||
|
||||
### إدارة الخادم المحلي
|
||||
|
||||
يتضمن SDK أوامر لإدارة خادم تطوير Twenty محلي (صورة Docker متكاملة تتضمن PostgreSQL وRedis والخادم والعامل):
|
||||
يتضمن SDK أوامر لإدارة خادم تطوير Twenty محلي (صورة Docker متكاملة تتضمن PostgreSQL وRedis والخادم والعامل على المنفذ 2020). تنطبق هذه الأوامر فقط على خادم التطوير المستند إلى Docker — ولا تُدير مثيل Twenty المُشغَّل من المصدر (مثل `npx nx start twenty-server` على المنفذ 3000):
|
||||
|
||||
```bash filename="Terminal"
|
||||
# ابدأ الخادم المحلي (يسحب الصورة إذا لزم الأمر)
|
||||
|
||||
@@ -358,17 +358,17 @@ Poznámky:
|
||||
|
||||
Pokud plánujete [zveřejnit svou aplikaci](/l/cs/developers/extend/apps/publishing), tato volitelná pole určují, jak se vaše aplikace zobrazuje na Marketplace:
|
||||
|
||||
| Pole | Popis |
|
||||
| ------------------ | -------------------------------------------------------- |
|
||||
| `author` | Jméno autora nebo název společnosti |
|
||||
| `category` | Kategorie aplikace pro filtrování na Marketplace |
|
||||
| `logoUrl` | Cesta k logu vaší aplikace (relativně k `./assets/`) |
|
||||
| `screenshots` | Pole cest ke snímkům obrazovky (relativně k `./assets/`) |
|
||||
| `aboutDescription` | Delší popis v Markdownu pro kartu "O aplikaci" |
|
||||
| `websiteUrl` | Odkaz na váš web |
|
||||
| `termsUrl` | Odkaz na Podmínky služby |
|
||||
| `emailSupport` | E-mailová adresa podpory |
|
||||
| `issueReportUrl` | Odkaz na nástroj pro sledování problémů |
|
||||
| Pole | Popis |
|
||||
| ------------------ | ------------------------------------------------------------------------------------------------------------- |
|
||||
| `author` | Jméno autora nebo název společnosti |
|
||||
| `category` | Kategorie aplikace pro filtrování na Marketplace |
|
||||
| `logoUrl` | Cesta k logu vaší aplikace (relativně k `./assets/`) |
|
||||
| `screenshots` | Pole cest ke snímkům obrazovky (relativně k `./assets/`) |
|
||||
| `aboutDescription` | Delší popis v Markdownu pro kartu "O aplikaci". Pokud je vynecháno, tržiště použije `README.md` balíčku z npm |
|
||||
| `websiteUrl` | Odkaz na váš web |
|
||||
| `termsUrl` | Odkaz na Podmínky služby |
|
||||
| `emailSupport` | E-mailová adresa podpory |
|
||||
| `issueReportUrl` | Odkaz na nástroj pro sledování problémů |
|
||||
|
||||
#### Role a oprávnění
|
||||
|
||||
|
||||
@@ -9,18 +9,19 @@ Aplikace jsou aktuálně v alfa testování. Tato funkce je funkční, ale stál
|
||||
|
||||
Aplikace vám umožňují rozšířit Twenty o vlastní objekty, pole, logické funkce, AI schopnosti a komponenty uživatelského rozhraní — vše je spravováno jako kód.
|
||||
|
||||
**Co můžete dělat už dnes:**
|
||||
**Co můžete vytvořit:**
|
||||
|
||||
* Definujte vlastní objekty a pole jako kód (spravovaný datový model)
|
||||
* Vytvářejte logické funkce s vlastními spouštěči (HTTP routy, cron, databázové události)
|
||||
* Definujte dovednosti agentů AI
|
||||
* Vytvářejte frontendové komponenty, které se vykreslují uvnitř uživatelského rozhraní Twenty
|
||||
* Nasazujte stejnou aplikaci do více pracovních prostorů
|
||||
* Vlastní objekty, pole, zobrazení a položky navigace pro utváření vašeho datového modelu
|
||||
* Logické funkce spouštěné trasami HTTP, plánovačem cron nebo událostmi databáze
|
||||
* Frontendové komponenty, které se vykreslují přímo uvnitř uživatelského rozhraní Twenty
|
||||
* Dovednosti, které rozšiřují možnosti AI agentů Twenty
|
||||
* Nasazení aplikace napříč více pracovními prostory
|
||||
|
||||
## Předpoklady
|
||||
|
||||
* Node.js 24+ a Yarn 4
|
||||
* Docker (pro místní vývojový server Twenty)
|
||||
* Node.js 24+
|
||||
* Yarn 4
|
||||
* Docker (nebo běžící lokální instance Twenty)
|
||||
|
||||
## Začínáme
|
||||
|
||||
@@ -29,21 +30,9 @@ Vytvořte novou aplikaci pomocí oficiálního scaffolderu, poté se ověřte a
|
||||
```bash filename="Terminal"
|
||||
# Scaffold a new app (includes all examples by default)
|
||||
npx create-twenty-app@latest my-twenty-app
|
||||
cd my-twenty-app
|
||||
|
||||
# Start dev mode: automatically syncs local changes to your workspace
|
||||
yarn twenty dev
|
||||
```
|
||||
|
||||
Nástroj pro generování kostry podporuje dva režimy pro řízení toho, které ukázkové soubory jsou zahrnuty:
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Default (exhaustive): all examples (object, field, logic function, front component, view, navigation menu item, skill, agent)
|
||||
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
|
||||
```
|
||||
> Použijte volbu `--minimal` k vygenerování minimální instalace
|
||||
|
||||
Odtud můžete:
|
||||
|
||||
@@ -123,7 +112,7 @@ S volbou `--minimal` se vytvoří pouze základní soubory (`application-config.
|
||||
V kostce:
|
||||
|
||||
* **package.json**: Deklaruje název aplikace, verzi, engines (Node 24+, Yarn 4) a přidává `twenty-sdk` plus skript `twenty`, který deleguje na lokální `twenty` CLI. Spusťte `yarn twenty help` pro výpis všech dostupných příkazů.
|
||||
* **.gitignore**: Ignores common artifacts such as `node_modules`, `.yarn`, `.twenty/`, `dist/`, `build/`, coverage folders, log files, and `.env*` files.
|
||||
* **.gitignore**: Ignoruje běžné artefakty jako `node_modules`, `.yarn`, `.twenty/`, `dist/`, `build/`, složky s coverage, soubory s logy a soubory `.env*`.
|
||||
* **yarn.lock**, **.yarnrc.yml**, **.yarn/**: Zamykají a konfigurují nástrojový řetězec Yarn 4 používaný projektem.
|
||||
* **.nvmrc**: Fixuje verzi Node.js požadovanou projektem.
|
||||
* **.oxlintrc.json** a **tsconfig.json**: Poskytují lintování a konfiguraci TypeScriptu pro zdrojové soubory vaší aplikace v TypeScriptu.
|
||||
@@ -167,8 +156,8 @@ export default defineObject({
|
||||
|
||||
Pozdější příkazy přidají další soubory a složky:
|
||||
|
||||
* `yarn twenty dev` will auto-generate the typed `CoreApiClient` (for workspace data via `/graphql`) into `node_modules/twenty-client-sdk/`. The `MetadataApiClient` (for workspace configuration and file uploads via `/metadata`) ships pre-built and is available immediately. Import them from `twenty-client-sdk/core` and `twenty-client-sdk/metadata` respectively.
|
||||
* `yarn twenty add` will add entity definition files under `src/` for your custom objects, functions, front components, roles, skills, and more.
|
||||
* `yarn twenty dev` automaticky vygeneruje typovaný `CoreApiClient` (pro data pracovního prostoru přes `/graphql`) do `node_modules/twenty-client-sdk/`. `MetadataApiClient` (pro konfiguraci pracovního prostoru a nahrávání souborů přes `/metadata`) je dodáván předpřipravený a je okamžitě k dispozici. Importujte je z `twenty-client-sdk/core` a `twenty-client-sdk/metadata` v uvedeném pořadí.
|
||||
* `yarn twenty add` přidá soubory s definicemi entit do `src/` pro vaše vlastní objekty, funkce, frontové komponenty, role, dovednosti a další.
|
||||
|
||||
## Ověření
|
||||
|
||||
|
||||
@@ -24,9 +24,9 @@ Příkaz `build` zkompiluje vaše zdrojové soubory TypeScriptu, transpiluje log
|
||||
yarn twenty build
|
||||
```
|
||||
|
||||
Výstup se zapisuje do `.twenty/output/`. This directory contains everything needed for distribution: compiled code, assets, the manifest, and a copy of your `package.json`.
|
||||
Výstup se zapisuje do `.twenty/output/`. Tento adresář obsahuje vše potřebné pro distribuci: zkompilovaný kód, statické soubory, manifest a kopii souboru `package.json`.
|
||||
|
||||
To also create a `.tgz` tarball (used by the deploy command internally, or for manual distribution):
|
||||
Chcete-li také vytvořit tarball `.tgz` (používaný interně příkazem deploy nebo pro ruční distribuci):
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty build --tarball
|
||||
@@ -39,11 +39,11 @@ Publikování na npm zajistí, že bude vaše aplikace dohledatelná v Marketpla
|
||||
### Požadavky
|
||||
|
||||
* Účet na [npm](https://www.npmjs.com)
|
||||
* The `twenty-app` keyword **must** be listed in your `package.json` `keywords` array
|
||||
* Klíčové slovo `twenty-app` **musí** být uvedeno v poli `keywords` vašeho `package.json`
|
||||
|
||||
### Adding the required keyword
|
||||
### Přidání požadovaného klíčového slova
|
||||
|
||||
The Twenty marketplace discovers apps by searching the npm registry for packages with the `twenty-app` keyword. Add it to your `package.json`:
|
||||
Tržiště Twenty objevuje aplikace hledáním balíčků v registru npm s klíčovým slovem `twenty-app`. Přidejte jej do svého `package.json`:
|
||||
|
||||
```json filename="package.json"
|
||||
{
|
||||
@@ -55,52 +55,56 @@ The Twenty marketplace discovers apps by searching the npm registry for packages
|
||||
```
|
||||
|
||||
<Note>
|
||||
The marketplace searches for `keywords:twenty-app` on the npm registry. Without this keyword, your package won't appear in the marketplace even if it has the `twenty-app-` name prefix.
|
||||
Tržiště vyhledává v registru npm výraz `keywords:twenty-app`. Bez tohoto klíčového slova se váš balíček v tržišti neobjeví, i když má jmennou předponu `twenty-app-`.
|
||||
</Note>
|
||||
|
||||
### Postup
|
||||
|
||||
1. **Build your app:**
|
||||
1. **Sestavení vaší aplikace:**
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty build
|
||||
```
|
||||
|
||||
2. **Publish to npm:**
|
||||
2. **Publikování na npm:**
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty publish
|
||||
```
|
||||
|
||||
This runs `npm publish` from the `.twenty/output/` directory.
|
||||
Tímto se spustí `npm publish` z adresáře `.twenty/output/`.
|
||||
|
||||
To publish under a specific dist-tag (e.g., `beta` or `next`):
|
||||
Chcete-li publikovat pod konkrétním dist-tagem (např. `beta` nebo `next`):
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty publish --tag beta
|
||||
```
|
||||
|
||||
### How marketplace discovery works
|
||||
### Jak funguje objevování v tržišti
|
||||
|
||||
The Twenty server syncs its marketplace catalog from the npm registry **every hour**:
|
||||
Server Twenty synchronizuje svůj katalog tržiště z registru npm **každou hodinu**:
|
||||
|
||||
1. It searches for all npm packages with the `keywords:twenty-app` keyword
|
||||
2. For each package, it fetches the `manifest.json` from the npm CDN
|
||||
3. The app's metadata (name, description, author, logo, screenshots, category) is extracted from the manifest and displayed in the marketplace
|
||||
1. Vyhledá všechny balíčky na npm s klíčovým slovem `keywords:twenty-app`
|
||||
2. Pro každý balíček stáhne `manifest.json` z CDN npm
|
||||
3. Metadata aplikace (název, popis, autor, logo, snímky obrazovky, kategorie) se získají z manifestu a zobrazí se v tržišti
|
||||
|
||||
After publishing, your app can take up to one hour to appear in the marketplace. To trigger the sync immediately instead of waiting for the next hourly run:
|
||||
Po publikování se vaše aplikace může v tržišti objevit až za jednu hodinu. Chcete-li spustit synchronizaci okamžitě místo čekání na další hodinové spuštění:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty catalog-sync
|
||||
```
|
||||
|
||||
To target a specific remote:
|
||||
Chcete-li zacílit na konkrétní vzdálený cíl:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty catalog-sync -r production
|
||||
```
|
||||
|
||||
The metadata shown in the marketplace comes from your `defineApplication()` call in your app source code — fields like `displayName`, `description`, `author`, `category`, `logoUrl`, `screenshots`, `aboutDescription`, `websiteUrl`, and `termsUrl`.
|
||||
Metadata zobrazená v tržišti pocházejí z volání `defineApplication()` ve zdrojovém kódu vaší aplikace — z polí jako `displayName`, `description`, `author`, `category`, `logoUrl`, `screenshots`, `aboutDescription`, `websiteUrl` a `termsUrl`.
|
||||
|
||||
<Note>
|
||||
Pokud vaše aplikace nedefinuje `aboutDescription` v `defineApplication()`, tržiště automaticky použije soubor `README.md` vašeho balíčku z npm jako obsah stránky O aplikaci. To znamená, že můžete spravovat jediný soubor README jak pro npm, tak pro tržiště Twenty. Pokud chcete v tržišti jiný popis, explicitně nastavte `aboutDescription`.
|
||||
</Note>
|
||||
|
||||
### Publikování pomocí CI
|
||||
|
||||
@@ -133,39 +137,39 @@ jobs:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
```
|
||||
|
||||
For other CI systems (GitLab CI, CircleCI, etc.), the same three commands apply: `yarn install`, `yarn twenty build`, then `npm publish` from `.twenty/output`.
|
||||
Pro jiné systémy CI (GitLab CI, CircleCI atd.) platí stejné tři příkazy: `yarn install`, `yarn twenty build` a poté `npm publish` z `.twenty/output`.
|
||||
|
||||
<Tip>
|
||||
**npm provenance** je volitelné, ale doporučené. Publikování s `--provenance` přidá k vašemu záznamu na npm odznak důvěryhodnosti a umožní uživatelům ověřit, že balíček byl sestaven z konkrétního commitu ve veřejné CI pipeline. Pokyny k nastavení najdete v [dokumentaci k npm provenance](https://docs.npmjs.com/generating-provenance-statements).
|
||||
</Tip>
|
||||
|
||||
## Deploying to a server (tarball)
|
||||
## Nasazení na server (tarball)
|
||||
|
||||
For apps you don't want publicly available — proprietary tools, enterprise-only integrations, or experimental builds — you can deploy a tarball directly to a Twenty server.
|
||||
U aplikací, které nechcete zpřístupnit veřejně — proprietární nástroje, integrace pouze pro enterprise nebo experimentální buildy — můžete nasadit tarball přímo na server Twenty.
|
||||
|
||||
### Předpoklady
|
||||
|
||||
Before deploying, you need a configured remote pointing to the target server. Remotes store the server URL and authentication credentials locally in `~/.twenty/config.json`.
|
||||
Před nasazením potřebujete nakonfigurovaný vzdálený cíl směřující na cílový server. Vzdálené cíle ukládají adresu URL serveru a přihlašovací údaje lokálně v `~/.twenty/config.json`.
|
||||
|
||||
Add a remote:
|
||||
Přidat vzdálený cíl:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty remote add --url https://your-twenty-server.com --as production
|
||||
```
|
||||
|
||||
For a local development server:
|
||||
Pro lokální vývojový server:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty remote add --local --as local
|
||||
```
|
||||
|
||||
You can also authenticate with an API key for non-interactive environments:
|
||||
Pro neinteraktivní prostředí se můžete ověřit také pomocí klíče API:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty remote add --url https://your-twenty-server.com --token <api-key> --as production
|
||||
```
|
||||
|
||||
Manage your remotes:
|
||||
Spravujte své vzdálené servery:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty remote list # List all configured remotes
|
||||
@@ -174,76 +178,76 @@ yarn twenty remote status # Show active remote and auth status
|
||||
yarn twenty remote remove old # Remove a remote
|
||||
```
|
||||
|
||||
### Deploying
|
||||
### Nasazení
|
||||
|
||||
Build and upload your app to the server in one step:
|
||||
Sestavte a nahrajte svou aplikaci na server v jednom kroku:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty deploy
|
||||
```
|
||||
|
||||
This builds the app with `--tarball`, then uploads the tarball to the default remote via a GraphQL multipart upload.
|
||||
Tímto se aplikace sestaví s `--tarball` a poté se tarball nahraje na výchozí vzdálený server prostřednictvím vícedílného (multipart) nahrávání GraphQL.
|
||||
|
||||
To deploy to a specific remote:
|
||||
Chcete-li nasadit na konkrétní vzdálený server:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty deploy -r production
|
||||
```
|
||||
|
||||
### Sharing a deployed app
|
||||
### Sdílení nasazené aplikace
|
||||
|
||||
Tarball apps are not listed in the public marketplace, so other workspaces on the same server won't discover them by browsing. To share a deployed app:
|
||||
Aplikace ve formě tarball nejsou uvedeny ve veřejném tržišti, takže je ostatní pracovní prostory na tomtéž serveru procházením neobjeví. Chcete-li sdílet nasazenou aplikaci:
|
||||
|
||||
1. Go to **Settings > Applications > Registrations** and open your app
|
||||
2. In the **Distribution** tab, click **Copy share link**
|
||||
3. Share this link with users on other workspaces — it takes them directly to the app's install page
|
||||
1. Přejděte do **Nastavení > Aplikace > Registrace** a otevřete svou aplikaci
|
||||
2. Na kartě **Distribuce** klikněte na **Zkopírovat odkaz ke sdílení**
|
||||
3. Sdílejte tento odkaz s uživateli v jiných pracovních prostorech — zavede je přímo na instalační stránku aplikace
|
||||
|
||||
The share link uses the server's base URL (without any workspace subdomain) so it works for any workspace on the server.
|
||||
Odkaz ke sdílení používá základní adresu URL serveru (bez jakékoli subdomény pracovního prostoru), takže funguje pro libovolný pracovní prostor na serveru.
|
||||
|
||||
### Správa verzí
|
||||
|
||||
Chcete-li vydat aktualizaci:
|
||||
|
||||
1. Zvyšte hodnotu pole `version` v souboru `package.json`
|
||||
2. Run `yarn twenty deploy` (or `yarn twenty deploy -r production`)
|
||||
3. Workspaces that have the app installed will see the upgrade available in their settings
|
||||
2. Spusťte `yarn twenty deploy` (nebo `yarn twenty deploy -r production`)
|
||||
3. Pracovní prostory, které mají aplikaci nainstalovanou, uvidí dostupnou aktualizaci ve svém nastavení
|
||||
|
||||
## Installing apps
|
||||
## Instalace aplikací
|
||||
|
||||
Once an app is published (npm) or deployed (tarball), workspaces install it through the UI:
|
||||
Jakmile je aplikace publikována (npm) nebo nasazena (tarball), pracovní prostory ji instalují prostřednictvím uživatelského rozhraní:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty install
|
||||
```
|
||||
|
||||
Or from the **Settings > Applications** page in the Twenty UI, where both marketplace and tarball-deployed apps can be browsed and installed.
|
||||
Nebo ze stránky **Nastavení > Aplikace** v rozhraní Twenty, kde lze procházet a instalovat jak aplikace z tržiště, tak aplikace nasazené jako tarball.
|
||||
|
||||
## App distribution categories
|
||||
## Kategorie distribuce aplikací
|
||||
|
||||
Twenty organizuje aplikace do tří kategorií podle způsobu distribuce:
|
||||
|
||||
| Kategorie | Jak to funguje | Viditelné v Marketplace? |
|
||||
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ------------------------ |
|
||||
| **Vývoj** | Aplikace v místním vývojářském režimu spuštěné přes `yarn twenty dev`. Slouží k sestavování a testování. | Ne |
|
||||
| **Published (npm)** | Apps published to npm with the `twenty-app` keyword. Uvedeny v Marketplace, aby je mohl kterýkoli pracovní prostor nainstalovat. | Ano |
|
||||
| **Internal (tarball)** | Aplikace nasazené pomocí tarballu na konkrétní server. Available only to workspaces on that server via a share link. | Ne |
|
||||
| Kategorie | Jak to funguje | Viditelné v Marketplace? |
|
||||
| --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------ |
|
||||
| **Vývoj** | Aplikace v místním vývojářském režimu spuštěné přes `yarn twenty dev`. Slouží k sestavování a testování. | Ne |
|
||||
| **Publikováno (npm)** | Aplikace publikované na npm s klíčovým slovem `twenty-app`. Uvedeny v Marketplace, aby je mohl kterýkoli pracovní prostor nainstalovat. | Ano |
|
||||
| **Interní (tarball)** | Aplikace nasazené pomocí tarballu na konkrétní server. Dostupné pouze pro pracovní prostory na tomto serveru prostřednictvím odkazu ke sdílení. | Ne |
|
||||
|
||||
<Tip>
|
||||
Začněte v režimu **Development** při sestavování své aplikace. Až bude připravena, zvolte **Published** (npm) pro širokou distribuci nebo **Internal** (tarball) pro soukromé nasazení.
|
||||
</Tip>
|
||||
|
||||
## CLI reference
|
||||
## Reference CLI
|
||||
|
||||
| Příkaz | Popis | Key flags |
|
||||
| --------------------------- | ---------------------------------------------- | --------------------------------------------------- |
|
||||
| `yarn twenty build` | Compile app and generate manifest | `--tarball` — also create a `.tgz` package |
|
||||
| `yarn twenty publish` | Build and publish to npm | `--tag <tag>` — npm dist-tag (e.g., `beta`, `next`) |
|
||||
| `yarn twenty deploy` | Build and upload tarball to a server | `-r, --remote <name>` — target remote |
|
||||
| `yarn twenty catalog-sync` | Trigger marketplace catalog sync on the server | `-r, --remote <name>` — target remote |
|
||||
| `yarn twenty install` | Install a deployed app on a workspace | `-r, --remote <name>` — target remote |
|
||||
| `yarn twenty dev` | Watch and sync local changes | Uses default remote |
|
||||
| `yarn twenty remote add` | Add a server connection | `--url`, `--token`, `--as`, `--local`, `--port` |
|
||||
| `yarn twenty remote list` | List configured remotes | — |
|
||||
| `yarn twenty remote switch` | Set default remote | — |
|
||||
| `yarn twenty remote status` | Show connection status | — |
|
||||
| `yarn twenty remote remove` | Remove a remote | — |
|
||||
| Příkaz | Popis | Klíčové přepínače |
|
||||
| --------------------------- | ----------------------------------------------------- | --------------------------------------------------- |
|
||||
| `yarn twenty build` | Sestaví aplikaci a vygeneruje manifest | `--tarball` — také vytvoří balíček `.tgz` |
|
||||
| `yarn twenty publish` | Sestaví a publikuje na npm | `--tag <tag>` — npm dist-tag (např. `beta`, `next`) |
|
||||
| `yarn twenty deploy` | Sestaví a nahraje tarball na server | `-r, --remote <name>` — cílový vzdálený repozitář |
|
||||
| `yarn twenty catalog-sync` | Spustí synchronizaci katalogu tržiště na serveru | `-r, --remote <name>` — cílový vzdálený repozitář |
|
||||
| `yarn twenty install` | Nainstaluje nasazenou aplikaci do pracovního prostoru | `-r, --remote <name>` — cílový vzdálený server |
|
||||
| `yarn twenty dev` | Sleduje a synchronizuje lokální změny | Používá výchozí vzdálený server |
|
||||
| `yarn twenty remote add` | Přidá připojení k serveru | `--url`, `--token`, `--as`, `--local`, `--port` |
|
||||
| `yarn twenty remote list` | Vypíše nakonfigurované vzdálené servery | — |
|
||||
| `yarn twenty remote switch` | Nastaví výchozí vzdálený server | — |
|
||||
| `yarn twenty remote status` | Zobrazí stav připojení | — |
|
||||
| `yarn twenty remote remove` | Odebere vzdálený server | — |
|
||||
|
||||
@@ -38,7 +38,7 @@ yarn twenty dev
|
||||
|
||||
### Správa místního serveru
|
||||
|
||||
SDK obsahuje příkazy ke správě místního vývojového serveru Twenty (all-in-one obraz Dockeru s PostgreSQL, Redisem, serverem a workerem):
|
||||
SDK obsahuje příkazy ke správě místního vývojového serveru Twenty (all-in-one obraz Dockeru s PostgreSQL, Redisem, serverem a workerem na portu 2020). Tyto příkazy se vztahují pouze na vývojový server založený na Dockeru — nespravují instanci Twenty spuštěnou ze zdrojového kódu (např. `npx nx start twenty-server` na portu 3000):
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Spusťte místní server (v případě potřeby stáhne obraz)
|
||||
|
||||
@@ -358,17 +358,17 @@ Notizen:
|
||||
|
||||
Wenn Sie planen, [Ihre App zu veröffentlichen](/l/de/developers/extend/apps/publishing), steuern diese optionalen Felder, wie Ihre App im Marktplatz erscheint:
|
||||
|
||||
| Feld | Beschreibung |
|
||||
| ------------------ | ---------------------------------------------------- |
|
||||
| `author` | Name des Autors oder des Unternehmens |
|
||||
| `category` | App-Kategorie für die Filterung im Marktplatz |
|
||||
| `logoUrl` | Pfad zu Ihrem App-Logo (relativ zu `./assets/`) |
|
||||
| `screenshots` | Array von Screenshot-Pfaden (relativ zu `./assets/`) |
|
||||
| `aboutDescription` | Längere Markdown-Beschreibung für den Tab "Info" |
|
||||
| `websiteUrl` | Link zu Ihrer Website |
|
||||
| `termsUrl` | Link zu den Nutzungsbedingungen |
|
||||
| `emailSupport` | Support-E-Mail-Adresse |
|
||||
| `issueReportUrl` | Link zum Issue-Tracker |
|
||||
| Feld | Beschreibung |
|
||||
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `author` | Name des Autors oder des Unternehmens |
|
||||
| `category` | App-Kategorie für die Filterung im Marktplatz |
|
||||
| `logoUrl` | Pfad zu Ihrem App-Logo (relativ zu `./assets/`) |
|
||||
| `screenshots` | Array von Screenshot-Pfaden (relativ zu `./assets/`) |
|
||||
| `aboutDescription` | Längere Markdown-Beschreibung für den Tab "Info". Wenn weggelassen, verwendet der Marketplace die `README.md` des Pakets von npm |
|
||||
| `websiteUrl` | Link zu Ihrer Website |
|
||||
| `termsUrl` | Link zu den Nutzungsbedingungen |
|
||||
| `emailSupport` | Support-E-Mail-Adresse |
|
||||
| `issueReportUrl` | Link zum Issue-Tracker |
|
||||
|
||||
#### Rollen und Berechtigungen
|
||||
|
||||
|
||||
@@ -9,18 +9,19 @@ Apps befinden sich derzeit in der Alpha-Testphase. Die Funktion ist funktionsfä
|
||||
|
||||
Apps ermöglichen es Ihnen, Twenty mit benutzerdefinierten Objekten, Feldern, Logikfunktionen, KI-Fähigkeiten und UI-Komponenten zu erweitern — alles als Code verwaltet.
|
||||
|
||||
**Was Sie heute tun können:**
|
||||
**Was Sie erstellen können:**
|
||||
|
||||
* Benutzerdefinierte Objekte und Felder als Code definieren (verwaltetes Datenmodell)
|
||||
* Erstellen Sie Logikfunktionen mit benutzerdefinierten Triggern (HTTP-Routen, cron, Datenbankereignisse)
|
||||
* Fähigkeiten für KI-Agenten definieren
|
||||
* Erstellen Sie Frontend-Komponenten, die in der Twenty-UI gerendert werden
|
||||
* Dieselbe App in mehreren Workspaces bereitstellen
|
||||
* Benutzerdefinierte Objekte, Felder, Ansichten und Navigationselemente, um Ihr Datenmodell zu gestalten
|
||||
* Logikfunktionen, die durch HTTP-Routen, Cron-Zeitpläne oder Datenbankereignisse ausgelöst werden
|
||||
* Frontend-Komponenten, die direkt innerhalb der Twenty-UI gerendert werden
|
||||
* Skills, die die KI-Agenten von Twenty erweitern
|
||||
* Eine App in mehreren Workspaces bereitstellen
|
||||
|
||||
## Voraussetzungen
|
||||
|
||||
* Node.js 24+ und Yarn 4
|
||||
* Docker (für den lokalen Twenty-Dev-Server)
|
||||
* Node.js 24+
|
||||
* Yarn 4
|
||||
* Docker (oder eine lokal laufende Twenty-Instanz)
|
||||
|
||||
## Erste Schritte
|
||||
|
||||
@@ -29,21 +30,9 @@ Erstellen Sie mit dem offiziellen Scaffolder eine neue App, authentifizieren Sie
|
||||
```bash filename="Terminal"
|
||||
# Scaffold a new app (includes all examples by default)
|
||||
npx create-twenty-app@latest my-twenty-app
|
||||
cd my-twenty-app
|
||||
|
||||
# Start dev mode: automatically syncs local changes to your workspace
|
||||
yarn twenty dev
|
||||
```
|
||||
|
||||
Das Scaffolding-Tool unterstützt zwei Modi, um zu steuern, welche Beispieldateien enthalten sind:
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Default (exhaustive): all examples (object, field, logic function, front component, view, navigation menu item, skill, agent)
|
||||
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
|
||||
```
|
||||
> Verwenden Sie die Option `--minimal`, um eine minimale Installation zu erstellen
|
||||
|
||||
Von hier aus können Sie:
|
||||
|
||||
@@ -123,7 +112,7 @@ Mit `--minimal` werden nur die Kerndateien erstellt (`application-config.ts`, `r
|
||||
Auf hoher Ebene:
|
||||
|
||||
* **package.json**: Deklariert den App-Namen, die Version und die Engines (Node 24+, Yarn 4) und fügt `twenty-sdk` sowie ein `twenty`-Skript hinzu, das an die lokale `twenty`-CLI delegiert. Führen Sie `yarn twenty help` aus, um alle verfügbaren Befehle aufzulisten.
|
||||
* **.gitignore**: Ignores common artifacts such as `node_modules`, `.yarn`, `.twenty/`, `dist/`, `build/`, coverage folders, log files, and `.env*` files.
|
||||
* **.gitignore**: Ignoriert übliche Artefakte wie `node_modules`, `.yarn`, `.twenty/`, `dist/`, `build/`, Coverage-Ordner, Logdateien und `.env*`-Dateien.
|
||||
* **yarn.lock**, **.yarnrc.yml**, **.yarn/**: Fixieren und konfigurieren die vom Projekt verwendete Yarn-4-Toolchain.
|
||||
* **.nvmrc**: Legt die vom Projekt erwartete Node.js-Version fest.
|
||||
* **.oxlintrc.json** und **tsconfig.json**: Stellen Linting und TypeScript-Konfiguration für die TypeScript-Quellen Ihrer App bereit.
|
||||
@@ -167,8 +156,8 @@ export default defineObject({
|
||||
|
||||
Spätere Befehle fügen weitere Dateien und Ordner hinzu:
|
||||
|
||||
* `yarn twenty dev` will auto-generate the typed `CoreApiClient` (for workspace data via `/graphql`) into `node_modules/twenty-client-sdk/`. The `MetadataApiClient` (for workspace configuration and file uploads via `/metadata`) ships pre-built and is available immediately. Import them from `twenty-client-sdk/core` and `twenty-client-sdk/metadata` respectively.
|
||||
* `yarn twenty add` will add entity definition files under `src/` for your custom objects, functions, front components, roles, skills, and more.
|
||||
* `yarn twenty dev` generiert den typisierten `CoreApiClient` (für Arbeitsbereichsdaten über `/graphql`) automatisch in `node_modules/twenty-client-sdk/`. Der `MetadataApiClient` (für Arbeitsbereichskonfiguration und Datei-Uploads über `/metadata`) wird vorkompiliert ausgeliefert und ist sofort verfügbar. Importieren Sie sie jeweils aus `twenty-client-sdk/core` und `twenty-client-sdk/metadata`.
|
||||
* `yarn twenty add` fügt unter `src/` Entitätsdefinitionsdateien für Ihre benutzerdefinierten Objekte, Funktionen, Frontend-Komponenten, Rollen, Skills und mehr hinzu.
|
||||
|
||||
## Authentifizierung
|
||||
|
||||
|
||||
@@ -24,9 +24,9 @@ Der Befehl `build` kompiliert Ihre TypeScript-Quelltexte, transpiliert Logikfunk
|
||||
yarn twenty build
|
||||
```
|
||||
|
||||
Die Ausgabe wird in `.twenty/output/` geschrieben. This directory contains everything needed for distribution: compiled code, assets, the manifest, and a copy of your `package.json`.
|
||||
Die Ausgabe wird in `.twenty/output/` geschrieben. Dieses Verzeichnis enthält alles, was für die Verteilung benötigt wird: kompilierter Code, Assets, das Manifest und eine Kopie Ihrer `package.json`.
|
||||
|
||||
To also create a `.tgz` tarball (used by the deploy command internally, or for manual distribution):
|
||||
Um zusätzlich ein `.tgz`-Tarball zu erstellen (wird intern vom Deploy-Befehl verwendet oder für die manuelle Verteilung):
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty build --tarball
|
||||
@@ -39,11 +39,11 @@ Die Veröffentlichung auf npm macht Ihre App im Twenty-Marktplatz auffindbar. Je
|
||||
### Anforderungen
|
||||
|
||||
* Ein [npm](https://www.npmjs.com)-Konto
|
||||
* The `twenty-app` keyword **must** be listed in your `package.json` `keywords` array
|
||||
* Das Schlüsselwort `twenty-app` **muss** in Ihrem `package.json`-`keywords`-Array aufgeführt sein
|
||||
|
||||
### Adding the required keyword
|
||||
### Das erforderliche Schlüsselwort hinzufügen
|
||||
|
||||
The Twenty marketplace discovers apps by searching the npm registry for packages with the `twenty-app` keyword. Add it to your `package.json`:
|
||||
Der Twenty-Marktplatz entdeckt Apps, indem er die npm-Registry nach Paketen mit dem Schlüsselwort `twenty-app` durchsucht. Fügen Sie es zu Ihrer `package.json` hinzu:
|
||||
|
||||
```json filename="package.json"
|
||||
{
|
||||
@@ -55,52 +55,56 @@ The Twenty marketplace discovers apps by searching the npm registry for packages
|
||||
```
|
||||
|
||||
<Note>
|
||||
The marketplace searches for `keywords:twenty-app` on the npm registry. Without this keyword, your package won't appear in the marketplace even if it has the `twenty-app-` name prefix.
|
||||
Der Marktplatz sucht in der npm-Registry nach `keywords:twenty-app`. Ohne dieses Schlüsselwort erscheint Ihr Paket nicht im Marktplatz, selbst wenn es das Namenspräfix `twenty-app-` hat.
|
||||
</Note>
|
||||
|
||||
### Schritte
|
||||
|
||||
1. **Build your app:**
|
||||
1. **Erstellen Ihrer App:**
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty build
|
||||
```
|
||||
|
||||
2. **Publish to npm:**
|
||||
2. **Auf npm veröffentlichen:**
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty publish
|
||||
```
|
||||
|
||||
This runs `npm publish` from the `.twenty/output/` directory.
|
||||
Dies führt `npm publish` aus dem Verzeichnis `.twenty/output/` aus.
|
||||
|
||||
To publish under a specific dist-tag (e.g., `beta` or `next`):
|
||||
Um unter einem bestimmten dist-tag zu veröffentlichen (z. B. `beta` oder `next`):
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty publish --tag beta
|
||||
```
|
||||
|
||||
### How marketplace discovery works
|
||||
### So funktioniert die Marktplatz-Erkennung
|
||||
|
||||
The Twenty server syncs its marketplace catalog from the npm registry **every hour**:
|
||||
Der Twenty-Server synchronisiert seinen Marktplatzkatalog **stündlich** mit der npm-Registry:
|
||||
|
||||
1. It searches for all npm packages with the `keywords:twenty-app` keyword
|
||||
2. For each package, it fetches the `manifest.json` from the npm CDN
|
||||
3. The app's metadata (name, description, author, logo, screenshots, category) is extracted from the manifest and displayed in the marketplace
|
||||
1. Er sucht nach allen npm-Paketen mit dem Schlüsselwort `keywords:twenty-app`
|
||||
2. Für jedes Paket ruft er die `manifest.json` vom npm-CDN ab
|
||||
3. Die Metadaten der App (Name, Beschreibung, Autor, Logo, Screenshots, Kategorie) werden aus dem Manifest extrahiert und im Marktplatz angezeigt
|
||||
|
||||
After publishing, your app can take up to one hour to appear in the marketplace. To trigger the sync immediately instead of waiting for the next hourly run:
|
||||
Nach der Veröffentlichung kann es bis zu einer Stunde dauern, bis Ihre App im Marktplatz erscheint. Um die Synchronisierung sofort auszulösen, statt auf den nächsten stündlichen Lauf zu warten:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty catalog-sync
|
||||
```
|
||||
|
||||
To target a specific remote:
|
||||
Um ein bestimmtes Remote anzusteuern:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty catalog-sync -r production
|
||||
```
|
||||
|
||||
The metadata shown in the marketplace comes from your `defineApplication()` call in your app source code — fields like `displayName`, `description`, `author`, `category`, `logoUrl`, `screenshots`, `aboutDescription`, `websiteUrl`, and `termsUrl`.
|
||||
Die im Marktplatz angezeigten Metadaten stammen aus Ihrem `defineApplication()`-Aufruf im Quellcode Ihrer App — Felder wie `displayName`, `description`, `author`, `category`, `logoUrl`, `screenshots`, `aboutDescription`, `websiteUrl` und `termsUrl`.
|
||||
|
||||
<Note>
|
||||
Wenn deine App keine `aboutDescription` in `defineApplication()` definiert, verwendet der Marktplatz automatisch die `README.md` deines Pakets von npm als Inhalt der Über-uns-Seite. Das bedeutet, dass du eine einzige README sowohl für npm als auch für den Twenty-Marktplatz pflegen kannst. Wenn du im Marktplatz eine andere Beschreibung möchtest, setze `aboutDescription` explizit.
|
||||
</Note>
|
||||
|
||||
### CI-Veröffentlichung
|
||||
|
||||
@@ -133,39 +137,39 @@ jobs:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
```
|
||||
|
||||
For other CI systems (GitLab CI, CircleCI, etc.), the same three commands apply: `yarn install`, `yarn twenty build`, then `npm publish` from `.twenty/output`.
|
||||
Für andere CI-Systeme (GitLab CI, CircleCI usw.) gelten die gleichen drei Befehle: `yarn install`, `yarn twenty build` und anschließend `npm publish` aus `.twenty/output`.
|
||||
|
||||
<Tip>
|
||||
**npm-Provenance** ist optional, wird jedoch empfohlen. Das Veröffentlichen mit `--provenance` fügt Ihrem npm-Eintrag ein Vertrauensabzeichen hinzu, sodass Nutzer überprüfen können, dass das Paket aus einem bestimmten Commit in einer öffentlichen CI-Pipeline gebaut wurde. Siehe die [npm-Provenance-Dokumentation](https://docs.npmjs.com/generating-provenance-statements) für Einrichtungshinweise.
|
||||
</Tip>
|
||||
|
||||
## Deploying to a server (tarball)
|
||||
## Bereitstellung auf einem Server (Tarball)
|
||||
|
||||
For apps you don't want publicly available — proprietary tools, enterprise-only integrations, or experimental builds — you can deploy a tarball directly to a Twenty server.
|
||||
Für Apps, die Sie nicht öffentlich verfügbar machen möchten — proprietäre Tools, ausschließlich für Unternehmen bestimmte Integrationen oder experimentelle Builds — können Sie einen Tarball direkt auf einem Twenty-Server bereitstellen.
|
||||
|
||||
### Voraussetzungen
|
||||
|
||||
Before deploying, you need a configured remote pointing to the target server. Remotes store the server URL and authentication credentials locally in `~/.twenty/config.json`.
|
||||
Bevor Sie bereitstellen, benötigen Sie ein konfiguriertes Remote, das auf den Zielserver zeigt. Remotes speichern die Server-URL und Anmeldeinformationen lokal in `~/.twenty/config.json`.
|
||||
|
||||
Add a remote:
|
||||
Ein Remote hinzufügen:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty remote add --url https://your-twenty-server.com --as production
|
||||
```
|
||||
|
||||
For a local development server:
|
||||
Für einen lokalen Entwicklungsserver:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty remote add --local --as local
|
||||
```
|
||||
|
||||
You can also authenticate with an API key for non-interactive environments:
|
||||
Sie können sich in nicht interaktiven Umgebungen auch mit einem API-Schlüssel authentifizieren:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty remote add --url https://your-twenty-server.com --token <api-key> --as production
|
||||
```
|
||||
|
||||
Manage your remotes:
|
||||
Ihre Remotes verwalten:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty remote list # List all configured remotes
|
||||
@@ -174,76 +178,76 @@ yarn twenty remote status # Show active remote and auth status
|
||||
yarn twenty remote remove old # Remove a remote
|
||||
```
|
||||
|
||||
### Deploying
|
||||
### Bereitstellen
|
||||
|
||||
Build and upload your app to the server in one step:
|
||||
Bauen und laden Sie Ihre App in einem Schritt auf den Server hoch:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty deploy
|
||||
```
|
||||
|
||||
This builds the app with `--tarball`, then uploads the tarball to the default remote via a GraphQL multipart upload.
|
||||
Dies baut die App mit `--tarball` und lädt anschließend den Tarball per GraphQL-Multipart-Upload auf das Standard-Remote hoch.
|
||||
|
||||
To deploy to a specific remote:
|
||||
Um auf ein bestimmtes Remote bereitzustellen:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty deploy -r production
|
||||
```
|
||||
|
||||
### Sharing a deployed app
|
||||
### Eine bereitgestellte App freigeben
|
||||
|
||||
Tarball apps are not listed in the public marketplace, so other workspaces on the same server won't discover them by browsing. To share a deployed app:
|
||||
Tarball-Apps werden nicht im öffentlichen Marktplatz gelistet, daher entdecken andere Arbeitsbereiche auf demselben Server sie nicht durch Stöbern. So geben Sie eine bereitgestellte App frei:
|
||||
|
||||
1. Go to **Settings > Applications > Registrations** and open your app
|
||||
2. In the **Distribution** tab, click **Copy share link**
|
||||
3. Share this link with users on other workspaces — it takes them directly to the app's install page
|
||||
1. Gehen Sie zu **Einstellungen > Anwendungen > Registrierungen** und öffnen Sie Ihre App
|
||||
2. Klicken Sie im Tab **Distribution** auf **Freigabelink kopieren**
|
||||
3. Teilen Sie diesen Link mit Nutzern in anderen Arbeitsbereichen — er führt sie direkt zur Installationsseite der App
|
||||
|
||||
The share link uses the server's base URL (without any workspace subdomain) so it works for any workspace on the server.
|
||||
Der Freigabelink verwendet die Basis-URL des Servers (ohne Workspace-Subdomain), sodass er für jeden Arbeitsbereich auf dem Server funktioniert.
|
||||
|
||||
### Versionsverwaltung
|
||||
|
||||
So veröffentlichen Sie ein Update:
|
||||
|
||||
1. Erhöhen Sie das Feld `version` in Ihrer `package.json`
|
||||
2. Run `yarn twenty deploy` (or `yarn twenty deploy -r production`)
|
||||
3. Workspaces that have the app installed will see the upgrade available in their settings
|
||||
2. Führen Sie `yarn twenty deploy` aus (oder `yarn twenty deploy -r production`)
|
||||
3. Arbeitsbereiche, die die App installiert haben, sehen in ihren Einstellungen, dass ein Upgrade verfügbar ist.
|
||||
|
||||
## Installing apps
|
||||
## Apps installieren
|
||||
|
||||
Once an app is published (npm) or deployed (tarball), workspaces install it through the UI:
|
||||
Sobald eine App veröffentlicht (npm) oder bereitgestellt (Tarball) wurde, installieren Arbeitsbereiche sie über die Benutzeroberfläche:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty install
|
||||
```
|
||||
|
||||
Or from the **Settings > Applications** page in the Twenty UI, where both marketplace and tarball-deployed apps can be browsed and installed.
|
||||
Oder über die Seite **Einstellungen > Anwendungen** in der Twenty-Oberfläche, wo sowohl Marktplatz- als auch per Tarball bereitgestellte Apps durchsucht und installiert werden können.
|
||||
|
||||
## App distribution categories
|
||||
## Kategorien der App-Verteilung
|
||||
|
||||
Twenty organisiert Apps in drei Kategorien, basierend auf ihrer Vertriebsart:
|
||||
|
||||
| Kategorie | Wie es funktioniert | Im Marktplatz sichtbar? |
|
||||
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | ----------------------- |
|
||||
| **Entwicklung** | Lokale Apps im Entwicklungsmodus, die über `yarn twenty dev` ausgeführt werden. Zum Erstellen und Testen verwendet. | Nein |
|
||||
| **Published (npm)** | Apps published to npm with the `twenty-app` keyword. Im Marktplatz gelistet, damit jeder Arbeitsbereich sie installieren kann. | Ja |
|
||||
| **Internal (tarball)** | Apps, die per Tarball auf einen bestimmten Server bereitgestellt werden. Available only to workspaces on that server via a share link. | Nein |
|
||||
| Kategorie | Wie es funktioniert | Im Marktplatz sichtbar? |
|
||||
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------- |
|
||||
| **Entwicklung** | Lokale Apps im Entwicklungsmodus, die über `yarn twenty dev` ausgeführt werden. Zum Erstellen und Testen verwendet. | Nein |
|
||||
| **Veröffentlicht (npm)** | Auf npm veröffentlichte Apps mit dem Schlüsselwort `twenty-app`. Im Marktplatz gelistet, damit jeder Arbeitsbereich sie installieren kann. | Ja |
|
||||
| **Intern (Tarball)** | Apps, die per Tarball auf einen bestimmten Server bereitgestellt werden. Nur für Arbeitsbereiche auf diesem Server per Freigabelink verfügbar. | Nein |
|
||||
|
||||
<Tip>
|
||||
Beginnen Sie im **Entwicklungsmodus**, während Sie Ihre App erstellen. Wenn sie bereit ist, wählen Sie **Veröffentlicht** (npm) für die breite Verteilung oder **Intern** (Tarball) für die private Bereitstellung.
|
||||
</Tip>
|
||||
|
||||
## CLI reference
|
||||
## CLI-Referenz
|
||||
|
||||
| Befehl | Beschreibung | Key flags |
|
||||
| --------------------------- | ---------------------------------------------- | --------------------------------------------------- |
|
||||
| `yarn twenty build` | Compile app and generate manifest | `--tarball` — also create a `.tgz` package |
|
||||
| `yarn twenty publish` | Build and publish to npm | `--tag <tag>` — npm dist-tag (e.g., `beta`, `next`) |
|
||||
| `yarn twenty deploy` | Build and upload tarball to a server | `-r, --remote <name>` — target remote |
|
||||
| `yarn twenty catalog-sync` | Trigger marketplace catalog sync on the server | `-r, --remote <name>` — target remote |
|
||||
| `yarn twenty install` | Install a deployed app on a workspace | `-r, --remote <name>` — target remote |
|
||||
| `yarn twenty dev` | Watch and sync local changes | Uses default remote |
|
||||
| `yarn twenty remote add` | Add a server connection | `--url`, `--token`, `--as`, `--local`, `--port` |
|
||||
| `yarn twenty remote list` | List configured remotes | — |
|
||||
| `yarn twenty remote switch` | Set default remote | — |
|
||||
| `yarn twenty remote status` | Show connection status | — |
|
||||
| `yarn twenty remote remove` | Remove a remote | — |
|
||||
| Befehl | Beschreibung | Wichtige Flags |
|
||||
| --------------------------- | --------------------------------------------------------------- | --------------------------------------------------- |
|
||||
| `yarn twenty build` | App kompilieren und Manifest erzeugen | `--tarball` — zusätzlich ein `.tgz`-Paket erstellen |
|
||||
| `yarn twenty publish` | Bauen und auf npm veröffentlichen | `--tag <tag>` — npm-dist-tag (z. B. `beta`, `next`) |
|
||||
| `yarn twenty deploy` | Tarball bauen und auf einen Server hochladen | `-r, --remote <name>` — Ziel-Remote |
|
||||
| `yarn twenty catalog-sync` | Synchronisierung des Marktplatzkatalogs auf dem Server auslösen | `-r, --remote <name>` — Ziel-Remote |
|
||||
| `yarn twenty install` | Eine bereitgestellte App in einem Arbeitsbereich installieren | `-r, --remote <name>` — Ziel-Remote |
|
||||
| `yarn twenty dev` | Lokale Änderungen beobachten und synchronisieren | Verwendet das Standard-Remote |
|
||||
| `yarn twenty remote add` | Eine Serververbindung hinzufügen | `--url`, `--token`, `--as`, `--local`, `--port` |
|
||||
| `yarn twenty remote list` | Konfigurierte Remotes auflisten | — |
|
||||
| `yarn twenty remote switch` | Standard-Remote festlegen | — |
|
||||
| `yarn twenty remote status` | Verbindungsstatus anzeigen | — |
|
||||
| `yarn twenty remote remove` | Ein Remote entfernen | — |
|
||||
|
||||
@@ -38,7 +38,7 @@ yarn twenty dev
|
||||
|
||||
### Lokale Serververwaltung
|
||||
|
||||
Das SDK enthält Befehle zur Verwaltung eines lokalen Twenty-Dev-Servers (All-in-One-Docker-Image mit PostgreSQL, Redis, Server und Worker):
|
||||
Das SDK enthält Befehle zur Verwaltung eines lokalen Twenty-Dev-Servers (All-in-One-Docker-Image mit PostgreSQL, Redis, Server und Worker auf Port 2020). Diese Befehle gelten nur für den Docker-basierten Dev-Server — sie verwalten keine aus dem Quellcode gestartete Twenty-Instanz (z. B. `npx nx start twenty-server` auf Port 3000):
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Den lokalen Server starten (lädt das Image bei Bedarf herunter)
|
||||
|
||||
@@ -15,21 +15,21 @@ Il pacchetto twenty-sdk fornisce blocchi tipizzati e funzioni helper da usare ne
|
||||
|
||||
L'SDK fornisce funzioni helper per definire le entità della tua app. Come descritto in [Rilevamento delle entità](/l/it/developers/extend/apps/getting-started#entity-detection), devi usare `export default define<Entity>({...})` affinché le tue entità vengano rilevate:
|
||||
|
||||
| Funzione | Scopo |
|
||||
| -------------------------------- | ----------------------------------------------------------------------------------- |
|
||||
| `defineApplication` | Configura i metadati dell'applicazione (obbligatorio, uno per app) |
|
||||
| `defineObject` | Definisci oggetti personalizzati con campi |
|
||||
| `defineField` | Extend existing objects with additional fields or define standalone relation fields |
|
||||
| `defineLogicFunction` | Definisci funzioni logiche con handler |
|
||||
| `definePreInstallLogicFunction` | Definisci una funzione logica di pre-installazione (una per app) |
|
||||
| `definePostInstallLogicFunction` | Definisci una funzione logica di post-installazione (una per app) |
|
||||
| `defineFrontComponent` | Definisci componenti front-end per un'interfaccia utente personalizzata |
|
||||
| `defineRole` | Configura i permessi dei ruoli e l'accesso agli oggetti |
|
||||
| `defineView` | Definisci viste salvate per gli oggetti |
|
||||
| `defineNavigationMenuItem` | Definisci i link di navigazione della barra laterale |
|
||||
| `defineSkill` | Definisci le competenze dell'agente IA |
|
||||
| `defineAgent` | Define AI agents |
|
||||
| `definePageLayout` | Define custom page layouts |
|
||||
| Funzione | Scopo |
|
||||
| -------------------------------- | ----------------------------------------------------------------------------------------------- |
|
||||
| `defineApplication` | Configura i metadati dell'applicazione (obbligatorio, uno per app) |
|
||||
| `defineObject` | Definisci oggetti personalizzati con campi |
|
||||
| `defineField` | Estendi gli oggetti esistenti con campi aggiuntivi oppure definisci campi di relazione autonomi |
|
||||
| `defineLogicFunction` | Definisci funzioni logiche con handler |
|
||||
| `definePreInstallLogicFunction` | Definisci una funzione logica di pre-installazione (una per app) |
|
||||
| `definePostInstallLogicFunction` | Definisci una funzione logica di post-installazione (una per app) |
|
||||
| `defineFrontComponent` | Definisci componenti front-end per un'interfaccia utente personalizzata |
|
||||
| `defineRole` | Configura i permessi dei ruoli e l'accesso agli oggetti |
|
||||
| `defineView` | Definisci viste salvate per gli oggetti |
|
||||
| `defineNavigationMenuItem` | Definisci i link di navigazione della barra laterale |
|
||||
| `defineSkill` | Definisci le competenze dell'agente IA |
|
||||
| `defineAgent` | Definisci gli agenti IA |
|
||||
| `definePageLayout` | Definisci layout di pagina personalizzati |
|
||||
|
||||
Queste funzioni convalidano la configurazione in fase di build e offrono il completamento automatico nell'IDE e la sicurezza dei tipi.
|
||||
|
||||
@@ -112,7 +112,7 @@ Punti chiave:
|
||||
* Il `universalIdentifier` deve essere univoco e stabile tra i deployment.
|
||||
* Ogni campo richiede un `name`, `type`, `label` e il proprio `universalIdentifier` stabile.
|
||||
* L'array `fields` è facoltativo: puoi definire oggetti senza campi personalizzati.
|
||||
* You can scaffold new objects using `yarn twenty add`, which guides you through naming, fields, and relationships.
|
||||
* Puoi generare nuovi oggetti con `yarn twenty add`, che ti guida nella denominazione, nei campi e nelle relazioni.
|
||||
|
||||
<Note>
|
||||
**I campi base vengono creati automaticamente.** Quando definisci un oggetto personalizzato, Twenty aggiunge automaticamente i campi standard
|
||||
@@ -124,7 +124,7 @@ ma non è consigliato.
|
||||
|
||||
### Definire campi sugli oggetti esistenti
|
||||
|
||||
Use `defineField()` to add fields to objects you don't own — such as standard Twenty objects (Person, Company, etc.) or objects from other apps. Unlike inline fields in `defineObject()`, standalone fields require an `objectUniversalIdentifier` to specify which object they extend:
|
||||
Usa `defineField()` per aggiungere campi a oggetti che non possiedi — come gli oggetti standard di Twenty (Person, Company, ecc.) o oggetti di altre app. A differenza dei campi inline in `defineObject()`, i campi autonomi richiedono un `objectUniversalIdentifier` per specificare quale oggetto estendono:
|
||||
|
||||
```typescript
|
||||
// src/fields/company-loyalty-tier.field.ts
|
||||
@@ -147,35 +147,35 @@ export default defineField({
|
||||
|
||||
Punti chiave:
|
||||
|
||||
* `objectUniversalIdentifier` identifies the target object. For standard objects, use `STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS` exported from `twenty-sdk`.
|
||||
* When defining fields inline in `defineObject()`, you do **not** need `objectUniversalIdentifier` — it's inherited from the parent object.
|
||||
* `defineField()` is the only way to add fields to objects you didn't create with `defineObject()`.
|
||||
* `objectUniversalIdentifier` identifica l'oggetto di destinazione. Per gli oggetti standard, usa `STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS` esportati da `twenty-sdk`.
|
||||
* Quando definisci campi inline in `defineObject()`, **non** hai bisogno di `objectUniversalIdentifier` — viene ereditato dall'oggetto padre.
|
||||
* `defineField()` è l'unico modo per aggiungere campi a oggetti che non hai creato con `defineObject()`.
|
||||
|
||||
### Relazioni
|
||||
|
||||
Relations connect objects together. In Twenty, relations are always **bidirectional** — you define both sides, and each side references the other.
|
||||
Le relazioni collegano gli oggetti tra loro. In Twenty, le relazioni sono sempre **bidirezionali** — definisci entrambi i lati e ciascun lato fa riferimento all'altro.
|
||||
|
||||
There are two relation types:
|
||||
Esistono due tipi di relazione:
|
||||
|
||||
| Tipo di relazione | Descrizione | Has foreign key? |
|
||||
| ----------------- | ------------------------------------------------------------- | ---------------------- |
|
||||
| `MANY_TO_ONE` | Many records of this object point to one record of the target | Yes (`joinColumnName`) |
|
||||
| `ONE_TO_MANY` | One record of this object has many records of the target | No (inverse side) |
|
||||
| Tipo di relazione | Descrizione | Ha una chiave esterna? |
|
||||
| ----------------- | --------------------------------------------------------------------- | ---------------------- |
|
||||
| `MANY_TO_ONE` | Molti record di questo oggetto puntano a un record della destinazione | Sì (`joinColumnName`) |
|
||||
| `ONE_TO_MANY` | Un record di questo oggetto ha molti record della destinazione | No (lato inverso) |
|
||||
|
||||
#### How relations work
|
||||
#### Come funzionano le relazioni
|
||||
|
||||
Every relation requires **two fields** that reference each other:
|
||||
Ogni relazione richiede **due campi** che fanno riferimento l'uno all'altro:
|
||||
|
||||
1. The **MANY_TO_ONE** side — lives on the object that holds the foreign key
|
||||
2. The **ONE_TO_MANY** side — lives on the object that owns the collection
|
||||
1. Il lato **MANY_TO_ONE** — risiede sull'oggetto che detiene la chiave esterna
|
||||
2. Il lato **ONE_TO_MANY** — risiede sull'oggetto che possiede la collezione
|
||||
|
||||
Both fields use `FieldType.RELATION` and cross-reference each other via `relationTargetFieldMetadataUniversalIdentifier`.
|
||||
Entrambi i campi usano `FieldType.RELATION` e si riferiscono reciprocamente tramite `relationTargetFieldMetadataUniversalIdentifier`.
|
||||
|
||||
#### Example: Post Card has many Recipients
|
||||
#### Esempio: Post Card ha molti destinatari
|
||||
|
||||
Suppose a `PostCard` can be sent to many `PostCardRecipient` records. Each recipient belongs to exactly one post card.
|
||||
Supponiamo che un `PostCard` possa essere inviato a molti record `PostCardRecipient`. Ogni destinatario appartiene esattamente a una sola cartolina.
|
||||
|
||||
**Step 1: Define the ONE_TO_MANY side on PostCard** (the "one" side):
|
||||
**Passaggio 1: definisci il lato ONE_TO_MANY su PostCard** (il lato "uno"):
|
||||
|
||||
```typescript
|
||||
// src/fields/post-card-recipients-on-post-card.field.ts
|
||||
@@ -203,7 +203,7 @@ export default defineField({
|
||||
});
|
||||
```
|
||||
|
||||
**Step 2: Define the MANY_TO_ONE side on PostCardRecipient** (the "many" side — holds the foreign key):
|
||||
**Passaggio 2: definisci il lato MANY_TO_ONE su PostCardRecipient** (il lato "molti" — contiene la chiave esterna):
|
||||
|
||||
```typescript
|
||||
// src/fields/post-card-on-post-card-recipient.field.ts
|
||||
@@ -234,12 +234,12 @@ export default defineField({
|
||||
```
|
||||
|
||||
<Note>
|
||||
**Circular imports:** Both relation fields reference each other's `universalIdentifier`. To avoid circular import issues, export your field IDs as named constants from each file, and import them in the other file. The build system resolves these at compile time.
|
||||
**Importazioni circolari:** Entrambi i campi di relazione fanno riferimento all'`universalIdentifier` dell'altro. Per evitare problemi di importazioni circolari, esporta gli ID dei campi come costanti denominate da ciascun file e importale nell'altro file. Il sistema di build le risolve in fase di compilazione.
|
||||
</Note>
|
||||
|
||||
#### Relating to standard objects
|
||||
#### Relazioni con gli oggetti standard
|
||||
|
||||
To create a relation with a built-in Twenty object (Person, Company, etc.), use `STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS`:
|
||||
Per creare una relazione con un oggetto Twenty integrato (Person, Company, ecc.), usa `STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS`:
|
||||
|
||||
```typescript
|
||||
// src/fields/person-on-self-hosting-user.field.ts
|
||||
@@ -274,20 +274,20 @@ export default defineField({
|
||||
});
|
||||
```
|
||||
|
||||
#### Relation field properties
|
||||
#### Proprietà dei campi di relazione
|
||||
|
||||
| Proprietà | Obbligatorio | Descrizione |
|
||||
| ------------------------------------------------- | ---------------- | ----------------------------------------------------------------------------------------------------- |
|
||||
| `tipo` | Sì | Must be `FieldType.RELATION` |
|
||||
| `relationTargetObjectMetadataUniversalIdentifier` | Sì | The `universalIdentifier` of the target object |
|
||||
| `relationTargetFieldMetadataUniversalIdentifier` | Sì | The `universalIdentifier` of the matching field on the target object |
|
||||
| `universalSettings.relationType` | Sì | `RelationType.MANY_TO_ONE` or `RelationType.ONE_TO_MANY` |
|
||||
| `universalSettings.onDelete` | MANY_TO_ONE only | What happens when the referenced record is deleted: `CASCADE`, `SET_NULL`, `RESTRICT`, or `NO_ACTION` |
|
||||
| `universalSettings.joinColumnName` | MANY_TO_ONE only | Database column name for the foreign key (e.g., `postCardId`) |
|
||||
| Proprietà | Obbligatorio | Descrizione |
|
||||
| ------------------------------------------------- | ---------------- | ---------------------------------------------------------------------------------------------------------- |
|
||||
| `tipo` | Sì | Deve essere `FieldType.RELATION` |
|
||||
| `relationTargetObjectMetadataUniversalIdentifier` | Sì | L'`universalIdentifier` dell'oggetto di destinazione |
|
||||
| `relationTargetFieldMetadataUniversalIdentifier` | Sì | L'`universalIdentifier` del campo corrispondente sull'oggetto di destinazione |
|
||||
| `universalSettings.relationType` | Sì | `RelationType.MANY_TO_ONE` or `RelationType.ONE_TO_MANY` |
|
||||
| `universalSettings.onDelete` | Solo MANY_TO_ONE | Cosa accade quando il record referenziato viene eliminato: `CASCADE`, `SET_NULL`, `RESTRICT` o `NO_ACTION` |
|
||||
| `universalSettings.joinColumnName` | Solo MANY_TO_ONE | Nome della colonna del database per la chiave esterna (ad es., `postCardId`) |
|
||||
|
||||
#### Inline relation fields in defineObject
|
||||
#### Campi di relazione inline in defineObject
|
||||
|
||||
You can also define relation fields directly inside `defineObject()`. In that case, omit `objectUniversalIdentifier` — it's inherited from the parent object:
|
||||
Puoi anche definire i campi di relazione direttamente all'interno di `defineObject()`. In tal caso, ometti `objectUniversalIdentifier` — viene ereditato dall'oggetto padre:
|
||||
|
||||
```typescript
|
||||
export default defineObject({
|
||||
@@ -354,21 +354,21 @@ Note:
|
||||
* `defaultRoleUniversalIdentifier` deve corrispondere al file del ruolo (vedi sotto).
|
||||
* Le funzioni di pre-installazione e post-installazione vengono rilevate automaticamente durante la build del manifesto. Vedi [Funzioni di pre-installazione](#pre-install-functions) e [Funzioni di post-installazione](#post-install-functions).
|
||||
|
||||
#### Marketplace metadata
|
||||
#### Metadati del marketplace
|
||||
|
||||
If you plan to [publish your app](/l/it/developers/extend/apps/publishing), these optional fields control how your app appears in the marketplace:
|
||||
Se prevedi di [pubblicare la tua app](/l/it/developers/extend/apps/publishing), questi campi opzionali controllano come la tua app appare nel marketplace:
|
||||
|
||||
| Campo | Descrizione |
|
||||
| ------------------ | --------------------------------------------------- |
|
||||
| `autore` | Author or company name |
|
||||
| `categoria` | App category for marketplace filtering |
|
||||
| `logoUrl` | Path to your app logo (relative to `./assets/`) |
|
||||
| `screenshots` | Array of screenshot paths (relative to `./assets/`) |
|
||||
| `aboutDescription` | Longer markdown description for the "About" tab |
|
||||
| `websiteUrl` | Link to your website |
|
||||
| `termsUrl` | Link to terms of service |
|
||||
| `emailSupport` | Support email address |
|
||||
| `issueReportUrl` | Link to issue tracker |
|
||||
| Campo | Descrizione |
|
||||
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `autore` | Nome dell'autore o dell'azienda |
|
||||
| `categoria` | Categoria dell'app per il filtraggio nel marketplace |
|
||||
| `logoUrl` | Percorso del logo della tua app (relativo a `./assets/`) |
|
||||
| `screenshots` | Array di percorsi degli screenshot (relativi a `./assets/`) |
|
||||
| `aboutDescription` | Descrizione markdown più lunga per la scheda "Informazioni". Se omesso, il marketplace utilizza il `README.md` del pacchetto da npm |
|
||||
| `websiteUrl` | Link al tuo sito web |
|
||||
| `termsUrl` | Link ai Termini di servizio |
|
||||
| `emailSupport` | Indirizzo email di supporto |
|
||||
| `issueReportUrl` | Link al sistema di tracciamento dei problemi |
|
||||
|
||||
#### Ruoli e permessi
|
||||
|
||||
@@ -376,7 +376,7 @@ Le applicazioni possono definire ruoli che incapsulano i permessi sugli oggetti
|
||||
|
||||
* La chiave API di runtime iniettata come `TWENTY_API_KEY` è derivata da questo ruolo funzione predefinito.
|
||||
* Il client tipizzato sarà limitato ai permessi concessi a quel ruolo.
|
||||
* Follow least-privilege: create a dedicated role with only the permissions your functions need, then reference its universal identifier.
|
||||
* Segui il principio del privilegio minimo: crea un ruolo dedicato con solo i permessi necessari alle tue funzioni, quindi fai riferimento al suo identificatore universale.
|
||||
|
||||
##### Ruolo funzione predefinito (*.role.ts)
|
||||
|
||||
@@ -429,7 +429,7 @@ L'`universalIdentifier` di questo ruolo viene quindi referenziato in `applicatio
|
||||
|
||||
Note:
|
||||
|
||||
* Start from the scaffolded role, then progressively restrict it following least-privilege.
|
||||
* Parti dal ruolo generato dallo scaffolder, quindi restringilo progressivamente seguendo il principio del privilegio minimo.
|
||||
* Sostituisci `objectPermissions` e `fieldPermissions` con gli oggetti/campi di cui le tue funzioni hanno bisogno.
|
||||
* `permissionFlags` controllano l'accesso alle funzionalità a livello di piattaforma. Mantienili al minimo; aggiungi solo ciò che ti serve.
|
||||
* Vedi un esempio funzionante nell'app Hello World: [`packages/twenty-apps/hello-world/src/roles/function-role.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-apps/hello-world/src/roles/function-role.ts).
|
||||
@@ -543,7 +543,7 @@ Punti chiave:
|
||||
* È consentita una sola funzione di pre-installazione per applicazione. La build del manifesto genererà un errore se ne viene rilevata più di una.
|
||||
* L'`universalIdentifier` della funzione viene impostato automaticamente come `preInstallLogicFunctionUniversalIdentifier` nel manifesto dell'applicazione durante la build — non è necessario farvi riferimento in `defineApplication()`.
|
||||
* Il timeout predefinito è impostato a 300 secondi (5 minuti) per consentire attività di preparazione più lunghe.
|
||||
* Pre-install functions do not need triggers — they are invoked by the platform before installation or manually via `exec --preInstall`.
|
||||
* Le funzioni di pre-installazione non necessitano di trigger — vengono invocate dalla piattaforma prima dell'installazione o manualmente tramite `exec --preInstall`.
|
||||
|
||||
### Funzioni post-installazione
|
||||
|
||||
@@ -581,7 +581,7 @@ Punti chiave:
|
||||
* È consentita una sola funzione di post-installazione per applicazione. La build del manifesto genererà un errore se ne viene rilevata più di una.
|
||||
* L'`universalIdentifier` della funzione viene impostato automaticamente come `postInstallLogicFunctionUniversalIdentifier` nel manifesto dell'applicazione durante la build — non è necessario farvi riferimento in `defineApplication()`.
|
||||
* Il timeout predefinito è impostato a 300 secondi (5 minuti) per consentire attività di configurazione più lunghe, come il popolamento dei dati.
|
||||
* Post-install functions do not need triggers — they are invoked by the platform during installation or manually via `exec --postInstall`.
|
||||
* Le funzioni di post-installazione non necessitano di trigger — vengono invocate dalla piattaforma durante l'installazione o manualmente tramite `exec --postInstall`.
|
||||
|
||||
### Payload del trigger di route
|
||||
|
||||
@@ -625,15 +625,15 @@ const handler = async (event: RoutePayload) => {
|
||||
|
||||
Il tipo `RoutePayload` ha la seguente struttura:
|
||||
|
||||
| Proprietà | Tipo | Descrizione |
|
||||
| ---------------------------- | ------------------------------------- | ---------------------------------------------------------------------------------------- |
|
||||
| `headers` | `Record<string, string \| undefined>` | Intestazioni HTTP (solo quelle elencate in `forwardedRequestHeaders`) |
|
||||
| `queryStringParameters` | `Record<string, string \| undefined>` | Parametri della query string (valori multipli uniti da virgole) |
|
||||
| `pathParameters` | `Record<string, string \| undefined>` | Path parameters extracted from the route pattern (e.g., `/users/:id` -> `{ id: '123' }`) |
|
||||
| `body` | `object \| null` | Corpo della richiesta analizzato (JSON) |
|
||||
| `isBase64Encoded` | `boolean` | Indica se il corpo è codificato in base64 |
|
||||
| `requestContext.http.method` | `string` | Metodo HTTP (GET, POST, PUT, PATCH, DELETE) |
|
||||
| `requestContext.http.path` | `string` | Percorso della richiesta non elaborato |
|
||||
| Proprietà | Tipo | Descrizione |
|
||||
| ---------------------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------ |
|
||||
| `headers` | `Record<string, string \| undefined>` | Intestazioni HTTP (solo quelle elencate in `forwardedRequestHeaders`) |
|
||||
| `queryStringParameters` | `Record<string, string \| undefined>` | Parametri della query string (valori multipli uniti da virgole) |
|
||||
| `pathParameters` | `Record<string, string \| undefined>` | Parametri di percorso estratti dal pattern della route (ad es., `/users/:id` -> `{ id: '123' }`) |
|
||||
| `body` | `object \| null` | Corpo della richiesta analizzato (JSON) |
|
||||
| `isBase64Encoded` | `boolean` | Indica se il corpo è codificato in base64 |
|
||||
| `requestContext.http.method` | `string` | Metodo HTTP (GET, POST, PUT, PATCH, DELETE) |
|
||||
| `requestContext.http.path` | `string` | Percorso della richiesta non elaborato |
|
||||
|
||||
### Inoltro delle intestazioni HTTP
|
||||
|
||||
@@ -675,7 +675,7 @@ const handler = async (event: RoutePayload) => {
|
||||
|
||||
Puoi creare nuove funzioni in due modi:
|
||||
|
||||
* **Scaffolded**: Run `yarn twenty add` and choose the option to add a new logic function. Questo genera un file iniziale con un handler e una configurazione.
|
||||
* **Generata dallo scaffolder**: Esegui `yarn twenty add` e scegli l'opzione per aggiungere una nuova funzione logica. Questo genera un file iniziale con un handler e una configurazione.
|
||||
* **Manuale**: Crea un nuovo file `*.logic-function.ts` e usa `defineLogicFunction()`, seguendo lo stesso schema.
|
||||
|
||||
### Contrassegnare una funzione logica come strumento
|
||||
@@ -776,7 +776,7 @@ Punti chiave:
|
||||
|
||||
Puoi creare nuovi componenti front-end in due modi:
|
||||
|
||||
* **Scaffolded**: Run `yarn twenty add` and choose the option to add a new front component.
|
||||
* **Generata dallo scaffolder**: Esegui `yarn twenty add` e scegli l'opzione per aggiungere un nuovo componente front-end.
|
||||
* **Manuale**: Crea un nuovo file `.tsx` e usa `defineFrontComponent()`, seguendo lo stesso schema.
|
||||
|
||||
### Abilità
|
||||
@@ -811,21 +811,21 @@ Punti chiave:
|
||||
|
||||
Puoi creare nuove skill in due modi:
|
||||
|
||||
* **Scaffolded**: Run `yarn twenty add` and choose the option to add a new skill.
|
||||
* **Generata dallo scaffolder**: Esegui `yarn twenty add` e scegli l'opzione per aggiungere una nuova skill.
|
||||
* **Manuale**: Crea un nuovo file e usa `defineSkill()`, seguendo lo stesso schema.
|
||||
|
||||
### Typed API clients (`twenty-client-sdk`)
|
||||
### Client API tipizzati (`twenty-client-sdk`)
|
||||
|
||||
The `twenty-client-sdk` package provides two typed GraphQL clients for interacting with the Twenty API from your logic functions and front components:
|
||||
Il pacchetto `twenty-client-sdk` fornisce due client GraphQL tipizzati per interagire con l'API di Twenty dalle tue funzioni logiche e dai componenti front-end:
|
||||
|
||||
| Client | Importa | Endpoint | Generated? |
|
||||
| ------------------- | ---------------------------- | ---------------------------------------------- | ---------------------- |
|
||||
| `CoreApiClient` | `twenty-client-sdk/core` | `/graphql` — workspace data (records, objects) | Yes, at dev/build time |
|
||||
| `MetadataApiClient` | `twenty-client-sdk/metadata` | `/metadata` — workspace config, file uploads | No, ships pre-built |
|
||||
| Client | Importa | Endpoint | Generato? |
|
||||
| ------------------- | ---------------------------- | ------------------------------------------------------------------------ | -------------------------- |
|
||||
| `CoreApiClient` | `twenty-client-sdk/core` | `/graphql` — dati dello spazio di lavoro (record, oggetti) | Sì, in fase di dev/build |
|
||||
| `MetadataApiClient` | `twenty-client-sdk/metadata` | `/metadata` — configurazione dello spazio di lavoro, caricamenti di file | No, fornito pronto all'uso |
|
||||
|
||||
#### CoreApiClient
|
||||
|
||||
`CoreApiClient` is the main client for querying and mutating workspace data. It is **generated from your workspace schema** during `yarn twenty dev` or `yarn twenty build`, so it's fully typed to match your objects and fields.
|
||||
`CoreApiClient` è il client principale per interrogare e modificare i dati dello spazio di lavoro. Viene **generato dallo schema del tuo spazio di lavoro** durante `yarn twenty dev` o `yarn twenty build`, quindi è completamente tipizzato per corrispondere ai tuoi oggetti e campi.
|
||||
|
||||
```typescript
|
||||
import { CoreApiClient } from 'twenty-client-sdk/core';
|
||||
@@ -859,15 +859,15 @@ const { createCompany } = await client.mutation({
|
||||
});
|
||||
```
|
||||
|
||||
The client uses a selection-set syntax: pass `true` to include a field, use `__args` for arguments, and nest objects for relations. You get full autocompletion and type checking based on your workspace schema.
|
||||
Il client utilizza una sintassi a selection-set: passa `true` per includere un campo, usa `__args` per gli argomenti e annida oggetti per le relazioni. Ottieni completamento automatico e controllo dei tipi completi basati sullo schema del tuo spazio di lavoro.
|
||||
|
||||
<Note>
|
||||
**CoreApiClient is generated at dev/build time.** If you try to use it without running `yarn twenty dev` or `yarn twenty build` first, it throws an error. The generation happens automatically — the CLI introspects your workspace's GraphQL schema, generates a typed client using `@genql/cli`, writes the generated sources to `node_modules/twenty-client-sdk/dist/core/generated/`, and replaces the stubs in `node_modules/twenty-client-sdk/dist/core.mjs` and `node_modules/twenty-client-sdk/dist/core.cjs`.
|
||||
**CoreApiClient viene generato in fase di dev/build.** Se provi a usarlo senza eseguire prima `yarn twenty dev` o `yarn twenty build`, genererà un errore. La generazione avviene automaticamente — la CLI esegue l'introspezione dello schema GraphQL del tuo spazio di lavoro, genera un client tipizzato usando `@genql/cli`, scrive le sorgenti generate in `node_modules/twenty-client-sdk/dist/core/generated/` e sostituisce gli stub in `node_modules/twenty-client-sdk/dist/core.mjs` e `node_modules/twenty-client-sdk/dist/core.cjs`.
|
||||
</Note>
|
||||
|
||||
#### Using CoreSchema for type annotations
|
||||
#### Utilizzo di CoreSchema per le annotazioni di tipo
|
||||
|
||||
`CoreSchema` provides TypeScript types matching your workspace objects, useful for typing component state or function parameters:
|
||||
`CoreSchema` fornisce tipi TypeScript corrispondenti agli oggetti del tuo spazio di lavoro, utili per tipizzare lo stato dei componenti o i parametri delle funzioni:
|
||||
|
||||
```typescript
|
||||
import { CoreApiClient, CoreSchema } from 'twenty-client-sdk/core';
|
||||
@@ -890,7 +890,7 @@ setCompany(result.company);
|
||||
|
||||
#### MetadataApiClient
|
||||
|
||||
`MetadataApiClient` ships pre-built with the SDK (no generation required). It queries the `/metadata` endpoint for workspace configuration, applications, and file uploads:
|
||||
`MetadataApiClient` è fornito pronto all'uso con l'SDK (nessuna generazione richiesta). Interroga l'endpoint `/metadata` per la configurazione dello spazio di lavoro, le applicazioni e i caricamenti di file:
|
||||
|
||||
```typescript
|
||||
import { MetadataApiClient } from 'twenty-client-sdk/metadata';
|
||||
@@ -912,18 +912,18 @@ const { findManyApplications } = await metadataClient.query({
|
||||
});
|
||||
```
|
||||
|
||||
#### Runtime credentials
|
||||
#### Credenziali di runtime
|
||||
|
||||
When your code runs on Twenty (logic functions or front components), the platform injects credentials as environment variables:
|
||||
Quando il tuo codice viene eseguito su Twenty (funzioni logiche o componenti front-end), la piattaforma inietta le credenziali come variabili d'ambiente:
|
||||
|
||||
* `TWENTY_API_URL` — Base URL of the Twenty API
|
||||
* `TWENTY_API_KEY` — Short-lived key scoped to your application's default function role
|
||||
* `TWENTY_API_URL` — URL di base dell'API di Twenty
|
||||
* `TWENTY_API_KEY` — Chiave a breve durata con ambito al ruolo funzione predefinito della tua applicazione
|
||||
|
||||
You do **not** need to pass these to the clients — they read from `process.env` automatically. The API key's permissions are determined by the role referenced in `defaultRoleUniversalIdentifier` in your `application-config.ts`.
|
||||
Non è **necessario** passarle ai client — vengono lette automaticamente da `process.env`. I permessi della chiave API sono determinati dal ruolo referenziato in `defaultRoleUniversalIdentifier` nel tuo `application-config.ts`.
|
||||
|
||||
#### Caricamento dei file
|
||||
|
||||
`MetadataApiClient` includes an `uploadFile` method for attaching files to file-type fields. It implements the [GraphQL multipart request specification](https://github.com/jaydenseric/graphql-multipart-request-spec):
|
||||
`MetadataApiClient` include un metodo `uploadFile` per allegare file ai campi di tipo file. Implementa la [specifica delle richieste GraphQL multipart](https://github.com/jaydenseric/graphql-multipart-request-spec):
|
||||
|
||||
```typescript
|
||||
import { MetadataApiClient } from 'twenty-client-sdk/metadata';
|
||||
@@ -953,7 +953,7 @@ console.log(uploadedFile);
|
||||
|
||||
Punti chiave:
|
||||
|
||||
* Uses the field's `universalIdentifier` (not its workspace-specific ID), so your upload code works across any workspace where your app is installed.
|
||||
* Usa l'`universalIdentifier` del campo (non il suo ID specifico dello spazio di lavoro), quindi il tuo codice di upload funziona in qualsiasi spazio di lavoro in cui la tua app è installata.
|
||||
* L'`url` restituito è un URL firmato che puoi usare per accedere al file caricato.
|
||||
|
||||
### Esempio Hello World
|
||||
|
||||
@@ -9,18 +9,19 @@ Le app sono attualmente in fase alfa. La funzionalità è funzionante ma ancora
|
||||
|
||||
Le app ti permettono di estendere Twenty con oggetti, campi, funzioni logiche, competenze IA e componenti UI personalizzati — il tutto gestito come codice.
|
||||
|
||||
**Cosa puoi fare oggi:**
|
||||
**Cosa puoi creare:**
|
||||
|
||||
* Definisci oggetti e campi personalizzati come codice (modello dati gestito)
|
||||
* Crea funzioni logiche con trigger personalizzati (route HTTP, cron, eventi del database)
|
||||
* Definisci le abilità per gli agenti IA
|
||||
* Crea componenti front-end che vengono renderizzati all'interno della UI di Twenty
|
||||
* Distribuisci la stessa app su più spazi di lavoro
|
||||
* Oggetti, campi, viste ed elementi di navigazione personalizzati per definire il tuo modello di dati
|
||||
* Funzioni logiche attivate da route HTTP, pianificazioni cron o eventi del database
|
||||
* Componenti front-end che vengono renderizzati direttamente all'interno della UI di Twenty
|
||||
* Abilità che estendono gli agenti IA di Twenty
|
||||
* Distribuisci un'app su più spazi di lavoro
|
||||
|
||||
## Prerequisiti
|
||||
|
||||
* Node.js 24+ e Yarn 4
|
||||
* Docker (per il server di sviluppo locale di Twenty)
|
||||
* Node.js 24+
|
||||
* Yarn 4
|
||||
* Docker (o un'istanza locale di Twenty in esecuzione)
|
||||
|
||||
## Per iniziare
|
||||
|
||||
@@ -29,21 +30,9 @@ Crea una nuova app utilizzando lo scaffolder ufficiale, quindi autenticati e ini
|
||||
```bash filename="Terminal"
|
||||
# Scaffold a new app (includes all examples by default)
|
||||
npx create-twenty-app@latest my-twenty-app
|
||||
cd my-twenty-app
|
||||
|
||||
# Start dev mode: automatically syncs local changes to your workspace
|
||||
yarn twenty dev
|
||||
```
|
||||
|
||||
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, agent)
|
||||
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
|
||||
```
|
||||
> Usa l'opzione `--minimal` per creare un'installazione minima
|
||||
|
||||
Da qui puoi:
|
||||
|
||||
@@ -123,7 +112,7 @@ Con `--minimal`, vengono creati solo i file principali (`application-config.ts`,
|
||||
A livello generale:
|
||||
|
||||
* **package.json**: Dichiara il nome dell'app, la versione, i motori (Node 24+, Yarn 4) e aggiunge `twenty-sdk` più uno script `twenty` che delega alla CLI locale `twenty`. Esegui `yarn twenty help` per elencare tutti i comandi disponibili.
|
||||
* **.gitignore**: Ignores common artifacts such as `node_modules`, `.yarn`, `.twenty/`, `dist/`, `build/`, coverage folders, log files, and `.env*` files.
|
||||
* **.gitignore**: Ignora i file generati comuni come `node_modules`, `.yarn`, `.twenty/`, `dist/`, `build/`, cartelle di coverage, file di log e file `.env*`.
|
||||
* **yarn.lock**, **.yarnrc.yml**, **.yarn/**: Bloccano e configurano la toolchain Yarn 4 utilizzata dal progetto.
|
||||
* **.nvmrc**: Fissa la versione di Node.js prevista dal progetto.
|
||||
* **.oxlintrc.json** e **tsconfig.json**: Forniscono linting e configurazione TypeScript per i sorgenti TypeScript della tua app.
|
||||
@@ -167,8 +156,8 @@ export default defineObject({
|
||||
|
||||
Comandi successivi aggiungeranno altri file e cartelle:
|
||||
|
||||
* `yarn twenty dev` will auto-generate the typed `CoreApiClient` (for workspace data via `/graphql`) into `node_modules/twenty-client-sdk/`. The `MetadataApiClient` (for workspace configuration and file uploads via `/metadata`) ships pre-built and is available immediately. Import them from `twenty-client-sdk/core` and `twenty-client-sdk/metadata` respectively.
|
||||
* `yarn twenty add` will add entity definition files under `src/` for your custom objects, functions, front components, roles, skills, and more.
|
||||
* `yarn twenty dev` genererà automaticamente il `CoreApiClient` tipizzato (per i dati dell'area di lavoro via `/graphql`) in `node_modules/twenty-client-sdk/`. Il `MetadataApiClient` (per la configurazione dell'area di lavoro e il caricamento di file via `/metadata`) è fornito precompilato ed è disponibile immediatamente. Importali da `twenty-client-sdk/core` e `twenty-client-sdk/metadata` rispettivamente.
|
||||
* `yarn twenty add` aggiungerà file di definizione delle entità sotto `src/` per i tuoi oggetti personalizzati, funzioni, componenti front-end, ruoli, competenze e altro ancora.
|
||||
|
||||
## Autenticazione
|
||||
|
||||
|
||||
@@ -24,9 +24,9 @@ Il comando `build` compila i tuoi sorgenti TypeScript, transpila le funzioni di
|
||||
yarn twenty build
|
||||
```
|
||||
|
||||
L'output viene scritto in `.twenty/output/`. This directory contains everything needed for distribution: compiled code, assets, the manifest, and a copy of your `package.json`.
|
||||
L'output viene scritto in `.twenty/output/`. Questa directory contiene tutto il necessario per la distribuzione: codice compilato, risorse, il manifest e una copia del tuo `package.json`.
|
||||
|
||||
To also create a `.tgz` tarball (used by the deploy command internally, or for manual distribution):
|
||||
Per creare anche un tarball `.tgz` (usato internamente dal comando di deploy o per la distribuzione manuale):
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty build --tarball
|
||||
@@ -39,11 +39,11 @@ La pubblicazione su npm rende la tua app scopribile nel marketplace di Twenty. Q
|
||||
### Requisiti
|
||||
|
||||
* Un account [npm](https://www.npmjs.com)
|
||||
* The `twenty-app` keyword **must** be listed in your `package.json` `keywords` array
|
||||
* La parola chiave `twenty-app` **deve** essere elencata nell'array `keywords` del tuo `package.json`
|
||||
|
||||
### Adding the required keyword
|
||||
### Aggiunta della parola chiave richiesta
|
||||
|
||||
The Twenty marketplace discovers apps by searching the npm registry for packages with the `twenty-app` keyword. Add it to your `package.json`:
|
||||
Il marketplace di Twenty individua le app cercando nel registro npm i pacchetti con la parola chiave `twenty-app`. Aggiungila al tuo `package.json`:
|
||||
|
||||
```json filename="package.json"
|
||||
{
|
||||
@@ -55,52 +55,56 @@ The Twenty marketplace discovers apps by searching the npm registry for packages
|
||||
```
|
||||
|
||||
<Note>
|
||||
The marketplace searches for `keywords:twenty-app` on the npm registry. Without this keyword, your package won't appear in the marketplace even if it has the `twenty-app-` name prefix.
|
||||
Il marketplace cerca `keywords:twenty-app` sul registro npm. Senza questa parola chiave, il tuo pacchetto non apparirà nel marketplace anche se ha il prefisso nel nome `twenty-app-`.
|
||||
</Note>
|
||||
|
||||
### Passaggi
|
||||
|
||||
1. **Build your app:**
|
||||
1. **Compila la tua app:**
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty build
|
||||
```
|
||||
|
||||
2. **Publish to npm:**
|
||||
2. **Pubblica su npm:**
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty publish
|
||||
```
|
||||
|
||||
This runs `npm publish` from the `.twenty/output/` directory.
|
||||
Questo esegue `npm publish` dalla directory `.twenty/output/`.
|
||||
|
||||
To publish under a specific dist-tag (e.g., `beta` or `next`):
|
||||
Per pubblicare con un dist-tag specifico (ad es. `beta` o `next`):
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty publish --tag beta
|
||||
```
|
||||
|
||||
### How marketplace discovery works
|
||||
### Come funziona l'individuazione nel marketplace
|
||||
|
||||
The Twenty server syncs its marketplace catalog from the npm registry **every hour**:
|
||||
Il server Twenty sincronizza il proprio catalogo del marketplace dal registro npm **ogni ora**:
|
||||
|
||||
1. It searches for all npm packages with the `keywords:twenty-app` keyword
|
||||
2. For each package, it fetches the `manifest.json` from the npm CDN
|
||||
3. The app's metadata (name, description, author, logo, screenshots, category) is extracted from the manifest and displayed in the marketplace
|
||||
1. Cerca tutti i pacchetti npm con `keywords:twenty-app`
|
||||
2. Per ogni pacchetto, recupera il `manifest.json` dalla CDN di npm
|
||||
3. I metadati dell'app (nome, descrizione, autore, logo, screenshot, categoria) vengono estratti dal manifest e visualizzati nel marketplace
|
||||
|
||||
After publishing, your app can take up to one hour to appear in the marketplace. To trigger the sync immediately instead of waiting for the next hourly run:
|
||||
Dopo la pubblicazione, la tua app può impiegare fino a un'ora per apparire nel marketplace. Per attivare subito la sincronizzazione invece di attendere la prossima esecuzione oraria:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty catalog-sync
|
||||
```
|
||||
|
||||
To target a specific remote:
|
||||
Per puntare a un remote specifico:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty catalog-sync -r production
|
||||
```
|
||||
|
||||
The metadata shown in the marketplace comes from your `defineApplication()` call in your app source code — fields like `displayName`, `description`, `author`, `category`, `logoUrl`, `screenshots`, `aboutDescription`, `websiteUrl`, and `termsUrl`.
|
||||
I metadati mostrati nel marketplace provengono dalla chiamata a `defineApplication()` nel codice sorgente della tua app — campi come `displayName`, `description`, `author`, `category`, `logoUrl`, `screenshots`, `aboutDescription`, `websiteUrl` e `termsUrl`.
|
||||
|
||||
<Note>
|
||||
Se la tua app non definisce un `aboutDescription` in `defineApplication()`, il marketplace userà automaticamente il `README.md` del tuo pacchetto su npm come contenuto della pagina Informazioni. Questo significa che puoi mantenere un unico README sia per npm sia per il marketplace di Twenty. Se desideri una descrizione diversa nel marketplace, imposta esplicitamente `aboutDescription`.
|
||||
</Note>
|
||||
|
||||
### Pubblicazione con CI
|
||||
|
||||
@@ -133,39 +137,39 @@ jobs:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
```
|
||||
|
||||
For other CI systems (GitLab CI, CircleCI, etc.), the same three commands apply: `yarn install`, `yarn twenty build`, then `npm publish` from `.twenty/output`.
|
||||
Per altri sistemi CI (GitLab CI, CircleCI, ecc.), si applicano gli stessi tre comandi: `yarn install`, `yarn twenty build`, quindi `npm publish` da `.twenty/output`.
|
||||
|
||||
<Tip>
|
||||
**npm provenance** è opzionale ma consigliata. La pubblicazione con `--provenance` aggiunge un badge di attendibilità alla tua scheda npm, consentendo agli utenti di verificare che il pacchetto sia stato creato a partire da uno specifico commit in una pipeline CI pubblica. Consulta la [documentazione su npm provenance](https://docs.npmjs.com/generating-provenance-statements) per le istruzioni di configurazione.
|
||||
</Tip>
|
||||
|
||||
## Deploying to a server (tarball)
|
||||
## Distribuzione su un server (tarball)
|
||||
|
||||
For apps you don't want publicly available — proprietary tools, enterprise-only integrations, or experimental builds — you can deploy a tarball directly to a Twenty server.
|
||||
Per le app che non vuoi rendere pubbliche — strumenti proprietari, integrazioni solo aziendali o build sperimentali — puoi distribuire un tarball direttamente su un server Twenty.
|
||||
|
||||
### Prerequisiti
|
||||
|
||||
Before deploying, you need a configured remote pointing to the target server. Remotes store the server URL and authentication credentials locally in `~/.twenty/config.json`.
|
||||
Prima della distribuzione, ti serve un remote configurato che punti al server di destinazione. I remote memorizzano localmente l'URL del server e le credenziali di autenticazione in `~/.twenty/config.json`.
|
||||
|
||||
Add a remote:
|
||||
Aggiungi un remote:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty remote add --url https://your-twenty-server.com --as production
|
||||
```
|
||||
|
||||
For a local development server:
|
||||
Per un server di sviluppo locale:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty remote add --local --as local
|
||||
```
|
||||
|
||||
You can also authenticate with an API key for non-interactive environments:
|
||||
Puoi anche autenticarti con una chiave API per ambienti non interattivi:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty remote add --url https://your-twenty-server.com --token <api-key> --as production
|
||||
```
|
||||
|
||||
Manage your remotes:
|
||||
Gestisci i tuoi remote:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty remote list # List all configured remotes
|
||||
@@ -174,76 +178,76 @@ yarn twenty remote status # Show active remote and auth status
|
||||
yarn twenty remote remove old # Remove a remote
|
||||
```
|
||||
|
||||
### Deploying
|
||||
### Distribuzione
|
||||
|
||||
Build and upload your app to the server in one step:
|
||||
Compila e carica la tua app sul server in un solo passaggio:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty deploy
|
||||
```
|
||||
|
||||
This builds the app with `--tarball`, then uploads the tarball to the default remote via a GraphQL multipart upload.
|
||||
Questo compila l'app con `--tarball`, quindi carica il tarball sul remote predefinito tramite un upload multipart GraphQL.
|
||||
|
||||
To deploy to a specific remote:
|
||||
Per distribuire su un remote specifico:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty deploy -r production
|
||||
```
|
||||
|
||||
### Sharing a deployed app
|
||||
### Condivisione di un'app distribuita
|
||||
|
||||
Tarball apps are not listed in the public marketplace, so other workspaces on the same server won't discover them by browsing. To share a deployed app:
|
||||
Le app in formato tarball non sono elencate nel marketplace pubblico, quindi altri spazi di lavoro sullo stesso server non le troveranno navigando. Per condividere un'app distribuita:
|
||||
|
||||
1. Go to **Settings > Applications > Registrations** and open your app
|
||||
2. In the **Distribution** tab, click **Copy share link**
|
||||
3. Share this link with users on other workspaces — it takes them directly to the app's install page
|
||||
1. Vai su **Impostazioni > Applicazioni > Registrazioni** e apri la tua app
|
||||
2. Nella scheda **Distribuzione**, fai clic su **Copia link di condivisione**
|
||||
3. Condividi questo link con utenti su altri spazi di lavoro — li porterà direttamente alla pagina di installazione dell'app
|
||||
|
||||
The share link uses the server's base URL (without any workspace subdomain) so it works for any workspace on the server.
|
||||
Il link di condivisione utilizza l'URL di base del server (senza alcun sottodominio dello spazio di lavoro) così funziona per qualsiasi spazio di lavoro sul server.
|
||||
|
||||
### Gestione delle versioni
|
||||
|
||||
Per rilasciare un aggiornamento:
|
||||
|
||||
1. Incrementa il campo `version` nel tuo `package.json`
|
||||
2. Run `yarn twenty deploy` (or `yarn twenty deploy -r production`)
|
||||
3. Workspaces that have the app installed will see the upgrade available in their settings
|
||||
2. Esegui `yarn twenty deploy` (oppure `yarn twenty deploy -r production`)
|
||||
3. Gli spazi di lavoro che hanno l'app installata vedranno l'aggiornamento disponibile nelle proprie impostazioni
|
||||
|
||||
## Installing apps
|
||||
## Installazione delle app
|
||||
|
||||
Once an app is published (npm) or deployed (tarball), workspaces install it through the UI:
|
||||
Una volta che un'app è stata pubblicata (npm) o distribuita (tarball), gli spazi di lavoro la installano tramite l'interfaccia utente:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty install
|
||||
```
|
||||
|
||||
Or from the **Settings > Applications** page in the Twenty UI, where both marketplace and tarball-deployed apps can be browsed and installed.
|
||||
Oppure dalla pagina **Impostazioni > Applicazioni** nell'interfaccia di Twenty, dove è possibile sfogliare e installare sia le app del marketplace sia quelle distribuite tramite tarball.
|
||||
|
||||
## App distribution categories
|
||||
## Categorie di distribuzione delle app
|
||||
|
||||
Twenty organizza le app in tre categorie in base a come vengono distribuite:
|
||||
|
||||
| Categoria | Come funziona | Visibile nel marketplace? |
|
||||
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ------------------------- |
|
||||
| **Sviluppo** | App in modalità di sviluppo locale eseguite tramite `yarn twenty dev`. Usate per la compilazione e i test. | No |
|
||||
| **Published (npm)** | Apps published to npm with the `twenty-app` keyword. Elencate nel marketplace per l'installazione da parte di qualsiasi spazio di lavoro. | Sì |
|
||||
| **Internal (tarball)** | App distribuite tramite tarball su un server specifico. Available only to workspaces on that server via a share link. | No |
|
||||
| Categoria | Come funziona | Visibile nel marketplace? |
|
||||
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------- |
|
||||
| **Sviluppo** | App in modalità di sviluppo locale eseguite tramite `yarn twenty dev`. Usate per la compilazione e i test. | No |
|
||||
| **Pubblicate (npm)** | App pubblicate su npm con la parola chiave `twenty-app`. Elencate nel marketplace per l'installazione da parte di qualsiasi spazio di lavoro. | Sì |
|
||||
| **Interne (tarball)** | App distribuite tramite tarball su un server specifico. Disponibili solo per gli spazi di lavoro su quel server tramite un link di condivisione. | No |
|
||||
|
||||
<Tip>
|
||||
Inizia in modalità **Sviluppo** mentre crei la tua app. Quando è pronta, scegli **Pubblicata** (npm) per un'ampia distribuzione oppure **Interna** (tarball) per una distribuzione privata.
|
||||
</Tip>
|
||||
|
||||
## CLI reference
|
||||
## Riferimento CLI
|
||||
|
||||
| Comando | Descrizione | Key flags |
|
||||
| --------------------------- | ---------------------------------------------- | --------------------------------------------------- |
|
||||
| `yarn twenty build` | Compile app and generate manifest | `--tarball` — also create a `.tgz` package |
|
||||
| `yarn twenty publish` | Build and publish to npm | `--tag <tag>` — npm dist-tag (e.g., `beta`, `next`) |
|
||||
| `yarn twenty deploy` | Build and upload tarball to a server | `-r, --remote <name>` — target remote |
|
||||
| `yarn twenty catalog-sync` | Trigger marketplace catalog sync on the server | `-r, --remote <name>` — target remote |
|
||||
| `yarn twenty install` | Install a deployed app on a workspace | `-r, --remote <name>` — target remote |
|
||||
| `yarn twenty dev` | Watch and sync local changes | Uses default remote |
|
||||
| `yarn twenty remote add` | Add a server connection | `--url`, `--token`, `--as`, `--local`, `--port` |
|
||||
| `yarn twenty remote list` | List configured remotes | — |
|
||||
| `yarn twenty remote switch` | Set default remote | — |
|
||||
| `yarn twenty remote status` | Show connection status | — |
|
||||
| `yarn twenty remote remove` | Remove a remote | — |
|
||||
| Comando | Descrizione | Flag principali |
|
||||
| --------------------------- | ------------------------------------------------------------------ | ---------------------------------------------------- |
|
||||
| `yarn twenty build` | Compila l'app e genera il manifest | `--tarball` — crea anche un pacchetto `.tgz` |
|
||||
| `yarn twenty publish` | Compila e pubblica su npm | `--tag <tag>` — dist-tag npm (ad es. `beta`, `next`) |
|
||||
| `yarn twenty deploy` | Compila e carica un tarball su un server | `-r, --remote <name>` — remote di destinazione |
|
||||
| `yarn twenty catalog-sync` | Attiva la sincronizzazione del catalogo del marketplace sul server | `-r, --remote <name>` — remote di destinazione |
|
||||
| `yarn twenty install` | Installa un'app distribuita su uno spazio di lavoro | `-r, --remote <name>` — remote di destinazione |
|
||||
| `yarn twenty dev` | Osserva e sincronizza le modifiche locali | Usa il remote predefinito |
|
||||
| `yarn twenty remote add` | Aggiungi una connessione al server | `--url`, `--token`, `--as`, `--local`, `--port` |
|
||||
| `yarn twenty remote list` | Elenca i remote configurati | — |
|
||||
| `yarn twenty remote switch` | Imposta il remote predefinito | — |
|
||||
| `yarn twenty remote status` | Mostra lo stato della connessione | — |
|
||||
| `yarn twenty remote remove` | Rimuovi un remote | — |
|
||||
|
||||
@@ -38,7 +38,7 @@ yarn twenty dev
|
||||
|
||||
### Gestione del server locale
|
||||
|
||||
L'SDK include comandi per gestire un server di sviluppo locale di Twenty (immagine Docker all-in-one con PostgreSQL, Redis, server e worker):
|
||||
L'SDK include comandi per gestire un server di sviluppo locale di Twenty (immagine Docker all-in-one con PostgreSQL, Redis, server e worker sulla porta 2020). Questi comandi si applicano solo al server di sviluppo basato su Docker — non gestiscono un'istanza di Twenty avviata dal sorgente (ad es. `npx nx start twenty-server` sulla porta 3000):
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Avvia il server locale (scarica l'immagine se necessario)
|
||||
|
||||
@@ -15,21 +15,21 @@ Biblioteca twenty-sdk oferă blocuri de bază tipizate și funcții ajutătoare
|
||||
|
||||
SDK-ul oferă funcții ajutătoare pentru definirea entităților aplicației. După cum este descris în [Detectarea entităților](/l/ro/developers/extend/apps/getting-started#entity-detection), trebuie să folosiți `export default define<Entity>({...})` pentru ca entitățile să fie detectate:
|
||||
|
||||
| Funcție | Scop |
|
||||
| -------------------------------- | ----------------------------------------------------------------------------------- |
|
||||
| `defineApplication` | Configurați metadatele aplicației (obligatoriu, una per aplicație) |
|
||||
| `defineObject` | Definiți obiecte personalizate cu câmpuri |
|
||||
| `defineField` | Extend existing objects with additional fields or define standalone relation fields |
|
||||
| `defineLogicFunction` | Definiți funcții de logică cu handleri |
|
||||
| `definePreInstallLogicFunction` | Definește o funcție logică de pre-instalare (una per aplicație) |
|
||||
| `definePostInstallLogicFunction` | Definește o funcție logică post-instalare (una per aplicație) |
|
||||
| `defineFrontComponent` | Definiți componente Front pentru interfața de utilizator personalizată |
|
||||
| `defineRole` | Configurați permisiunile rolurilor și accesul la obiecte |
|
||||
| `defineView` | Definește vizualizări salvate pentru obiecte |
|
||||
| `defineNavigationMenuItem` | Definește linkuri de navigare în bara laterală |
|
||||
| `defineSkill` | Definiți abilități pentru agentul AI |
|
||||
| `defineAgent` | Define AI agents |
|
||||
| `definePageLayout` | Define custom page layouts |
|
||||
| Funcție | Scop |
|
||||
| -------------------------------- | -------------------------------------------------------------------------------------------------- |
|
||||
| `defineApplication` | Configurați metadatele aplicației (obligatoriu, una per aplicație) |
|
||||
| `defineObject` | Definiți obiecte personalizate cu câmpuri |
|
||||
| `defineField` | Extindeți obiectele existente cu câmpuri suplimentare sau definiți câmpuri de relație independente |
|
||||
| `defineLogicFunction` | Definiți funcții de logică cu handleri |
|
||||
| `definePreInstallLogicFunction` | Definește o funcție logică de pre-instalare (una per aplicație) |
|
||||
| `definePostInstallLogicFunction` | Definește o funcție logică post-instalare (una per aplicație) |
|
||||
| `defineFrontComponent` | Definiți componente Front pentru interfața de utilizator personalizată |
|
||||
| `defineRole` | Configurați permisiunile rolurilor și accesul la obiecte |
|
||||
| `defineView` | Definește vizualizări salvate pentru obiecte |
|
||||
| `defineNavigationMenuItem` | Definește linkuri de navigare în bara laterală |
|
||||
| `defineSkill` | Definiți abilități pentru agentul AI |
|
||||
| `defineAgent` | Definiți agenți AI |
|
||||
| `definePageLayout` | Definiți machete de pagină personalizate |
|
||||
|
||||
Aceste funcții validează configurația în timpul build-ului și oferă completare automată în IDE și siguranța tipurilor.
|
||||
|
||||
@@ -112,7 +112,7 @@ Puncte cheie:
|
||||
* `universalIdentifier` trebuie să fie unic și stabil între implementări.
|
||||
* Fiecare câmp necesită un `name`, un `type`, un `label` și propriul `universalIdentifier` stabil.
|
||||
* Matricea `fields` este opțională — puteți defini obiecte fără câmpuri personalizate.
|
||||
* You can scaffold new objects using `yarn twenty add`, which guides you through naming, fields, and relationships.
|
||||
* Puteți genera obiecte noi folosind `yarn twenty add`, care vă ghidează prin denumire, câmpuri și relații.
|
||||
|
||||
<Note>
|
||||
**Câmpurile de bază sunt create automat.** Când definiți un obiect personalizat, Twenty adaugă automat câmpuri standard
|
||||
@@ -124,7 +124,7 @@ dar acest lucru nu este recomandat.
|
||||
|
||||
### Definirea câmpurilor pe obiecte existente
|
||||
|
||||
Use `defineField()` to add fields to objects you don't own — such as standard Twenty objects (Person, Company, etc.) or objects from other apps. Unlike inline fields in `defineObject()`, standalone fields require an `objectUniversalIdentifier` to specify which object they extend:
|
||||
Utilizați `defineField()` pentru a adăuga câmpuri la obiecte pe care nu le dețineți — cum ar fi obiectele standard Twenty (Person, Company etc.). sau obiecte din alte aplicații. Spre deosebire de câmpurile inline din `defineObject()`, câmpurile independente necesită un `objectUniversalIdentifier` pentru a specifica obiectul pe care îl extind:
|
||||
|
||||
```typescript
|
||||
// src/fields/company-loyalty-tier.field.ts
|
||||
@@ -147,35 +147,35 @@ export default defineField({
|
||||
|
||||
Puncte cheie:
|
||||
|
||||
* `objectUniversalIdentifier` identifies the target object. For standard objects, use `STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS` exported from `twenty-sdk`.
|
||||
* When defining fields inline in `defineObject()`, you do **not** need `objectUniversalIdentifier` — it's inherited from the parent object.
|
||||
* `defineField()` is the only way to add fields to objects you didn't create with `defineObject()`.
|
||||
* `objectUniversalIdentifier` identifică obiectul țintă. Pentru obiectele standard, utilizați `STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS` exportați din `twenty-sdk`.
|
||||
* Atunci când definiți câmpuri inline în `defineObject()`, nu aveți nevoie de `objectUniversalIdentifier` — este moștenit de la obiectul părinte.
|
||||
* `defineField()` este singura modalitate de a adăuga câmpuri la obiecte pe care nu le-ați creat cu `defineObject()`.
|
||||
|
||||
### Relații
|
||||
|
||||
Relations connect objects together. In Twenty, relations are always **bidirectional** — you define both sides, and each side references the other.
|
||||
Relațiile conectează obiectele între ele. În Twenty, relațiile sunt întotdeauna bidirecționale — definiți ambele părți, iar fiecare parte o referențiază pe cealaltă.
|
||||
|
||||
There are two relation types:
|
||||
Există două tipuri de relații:
|
||||
|
||||
| Tip relație | Descriere | Has foreign key? |
|
||||
| ------------- | ------------------------------------------------------------- | ---------------------- |
|
||||
| `MANY_TO_ONE` | Many records of this object point to one record of the target | Yes (`joinColumnName`) |
|
||||
| `ONE_TO_MANY` | One record of this object has many records of the target | No (inverse side) |
|
||||
| Tip relație | Descriere | Are cheie străină? |
|
||||
| ------------- | ---------------------------------------------------------------------------------- | --------------------- |
|
||||
| `MANY_TO_ONE` | Multe înregistrări ale acestui obiect indică către o singură înregistrare a țintei | Da (`joinColumnName`) |
|
||||
| `ONE_TO_MANY` | O înregistrare a acestui obiect are multe înregistrări ale țintei | Nu (partea inversă) |
|
||||
|
||||
#### How relations work
|
||||
#### Cum funcționează relațiile
|
||||
|
||||
Every relation requires **two fields** that reference each other:
|
||||
Fiecare relație necesită **două câmpuri** care se referențiază reciproc:
|
||||
|
||||
1. The **MANY_TO_ONE** side — lives on the object that holds the foreign key
|
||||
2. The **ONE_TO_MANY** side — lives on the object that owns the collection
|
||||
1. Partea **MANY_TO_ONE** — se află pe obiectul care deține cheia străină
|
||||
2. Partea **ONE_TO_MANY** — se află pe obiectul care deține colecția
|
||||
|
||||
Both fields use `FieldType.RELATION` and cross-reference each other via `relationTargetFieldMetadataUniversalIdentifier`.
|
||||
Ambele câmpuri folosesc `FieldType.RELATION` și se referențiază încrucișat prin `relationTargetFieldMetadataUniversalIdentifier`.
|
||||
|
||||
#### Example: Post Card has many Recipients
|
||||
#### Exemplu: Post Card are mulți destinatari
|
||||
|
||||
Suppose a `PostCard` can be sent to many `PostCardRecipient` records. Each recipient belongs to exactly one post card.
|
||||
Presupuneți că un `PostCard` poate fi trimis către multe înregistrări `PostCardRecipient`. Fiecare destinatar aparține exact unui Post Card.
|
||||
|
||||
**Step 1: Define the ONE_TO_MANY side on PostCard** (the "one" side):
|
||||
**Pasul 1: Definiți partea ONE_TO_MANY pe PostCard** (partea "one"):
|
||||
|
||||
```typescript
|
||||
// src/fields/post-card-recipients-on-post-card.field.ts
|
||||
@@ -203,7 +203,7 @@ export default defineField({
|
||||
});
|
||||
```
|
||||
|
||||
**Step 2: Define the MANY_TO_ONE side on PostCardRecipient** (the "many" side — holds the foreign key):
|
||||
**Pasul 2: Definiți partea MANY_TO_ONE pe PostCardRecipient** (partea "many" — deține cheia străină):
|
||||
|
||||
```typescript
|
||||
// src/fields/post-card-on-post-card-recipient.field.ts
|
||||
@@ -234,12 +234,12 @@ export default defineField({
|
||||
```
|
||||
|
||||
<Note>
|
||||
**Circular imports:** Both relation fields reference each other's `universalIdentifier`. To avoid circular import issues, export your field IDs as named constants from each file, and import them in the other file. The build system resolves these at compile time.
|
||||
**Importuri circulare:** Ambele câmpuri de relație se referă unul la celălalt prin `universalIdentifier`. Pentru a evita problemele de import circular, exportați ID-urile câmpurilor ca constante denumite din fiecare fișier și importați-le în celălalt fișier. Sistemul de build le rezolvă în timpul compilării.
|
||||
</Note>
|
||||
|
||||
#### Relating to standard objects
|
||||
#### Relaționarea cu obiectele standard
|
||||
|
||||
To create a relation with a built-in Twenty object (Person, Company, etc.), use `STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS`:
|
||||
Pentru a crea o relație cu un obiect Twenty încorporat (Person, Company etc.), utilizați `STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS`:
|
||||
|
||||
```typescript
|
||||
// src/fields/person-on-self-hosting-user.field.ts
|
||||
@@ -274,20 +274,20 @@ export default defineField({
|
||||
});
|
||||
```
|
||||
|
||||
#### Relation field properties
|
||||
#### Proprietăți ale câmpului de relație
|
||||
|
||||
| Proprietate | Obligatoriu | Descriere |
|
||||
| ------------------------------------------------- | ---------------- | ----------------------------------------------------------------------------------------------------- |
|
||||
| `tip` | Da | Must be `FieldType.RELATION` |
|
||||
| `relationTargetObjectMetadataUniversalIdentifier` | Da | The `universalIdentifier` of the target object |
|
||||
| `relationTargetFieldMetadataUniversalIdentifier` | Da | The `universalIdentifier` of the matching field on the target object |
|
||||
| `universalSettings.relationType` | Da | `RelationType.MANY_TO_ONE` or `RelationType.ONE_TO_MANY` |
|
||||
| `universalSettings.onDelete` | MANY_TO_ONE only | What happens when the referenced record is deleted: `CASCADE`, `SET_NULL`, `RESTRICT`, or `NO_ACTION` |
|
||||
| `universalSettings.joinColumnName` | MANY_TO_ONE only | Database column name for the foreign key (e.g., `postCardId`) |
|
||||
| Proprietate | Obligatoriu | Descriere |
|
||||
| ------------------------------------------------- | ---------------- | --------------------------------------------------------------------------------------------------------------------- |
|
||||
| `tip` | Da | Trebuie să fie `FieldType.RELATION` |
|
||||
| `relationTargetObjectMetadataUniversalIdentifier` | Da | `universalIdentifier` al obiectului țintă |
|
||||
| `relationTargetFieldMetadataUniversalIdentifier` | Da | `universalIdentifier` al câmpului corespunzător de pe obiectul țintă |
|
||||
| `universalSettings.relationType` | Da | `RelationType.MANY_TO_ONE` sau `RelationType.ONE_TO_MANY` |
|
||||
| `universalSettings.onDelete` | Doar MANY_TO_ONE | Ce se întâmplă atunci când înregistrarea referențiată este ștearsă: `CASCADE`, `SET_NULL`, `RESTRICT` sau `NO_ACTION` |
|
||||
| `universalSettings.joinColumnName` | Doar MANY_TO_ONE | Numele coloanei din baza de date pentru cheia străină (de ex., `postCardId`) |
|
||||
|
||||
#### Inline relation fields in defineObject
|
||||
#### Câmpuri de relație inline în defineObject
|
||||
|
||||
You can also define relation fields directly inside `defineObject()`. In that case, omit `objectUniversalIdentifier` — it's inherited from the parent object:
|
||||
Puteți defini, de asemenea, câmpuri de relație direct în `defineObject()`. În acest caz, omiteți `objectUniversalIdentifier` — este moștenit de la obiectul părinte:
|
||||
|
||||
```typescript
|
||||
export default defineObject({
|
||||
@@ -354,21 +354,21 @@ Notițe:
|
||||
* `defaultRoleUniversalIdentifier` trebuie să corespundă fișierului de rol (vedeți mai jos).
|
||||
* Funcțiile de pre-instalare și post-instalare sunt detectate automat în timpul construirii manifestului. Vezi [Funcții de pre-instalare](#pre-install-functions) și [Funcții post-instalare](#post-install-functions).
|
||||
|
||||
#### Marketplace metadata
|
||||
#### Metadate pentru marketplace
|
||||
|
||||
If you plan to [publish your app](/l/ro/developers/extend/apps/publishing), these optional fields control how your app appears in the marketplace:
|
||||
Dacă intenționați să [publicați aplicația](/l/ro/developers/extend/apps/publishing), aceste câmpuri opționale controlează modul în care aplicația apare în marketplace:
|
||||
|
||||
| Câmp | Descriere |
|
||||
| ------------------ | --------------------------------------------------- |
|
||||
| `autor` | Author or company name |
|
||||
| `categorie` | App category for marketplace filtering |
|
||||
| `logoUrl` | Path to your app logo (relative to `./assets/`) |
|
||||
| `screenshots` | Array of screenshot paths (relative to `./assets/`) |
|
||||
| `aboutDescription` | Longer markdown description for the "About" tab |
|
||||
| `websiteUrl` | Link to your website |
|
||||
| `termsUrl` | Link to terms of service |
|
||||
| `emailSupport` | Support email address |
|
||||
| `issueReportUrl` | Link to issue tracker |
|
||||
| Câmp | Descriere |
|
||||
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `autor` | Numele autorului sau al companiei |
|
||||
| `categorie` | Categoria aplicației pentru filtrarea în marketplace |
|
||||
| `logoUrl` | Calea către logo-ul aplicației (relativă la `./assets/`) |
|
||||
| `screenshots` | Listă de căi către capturi de ecran (relative la `./assets/`) |
|
||||
| `aboutDescription` | Descriere markdown mai lungă pentru fila "About". Dacă este omis, marketplace-ul folosește `README.md` al pachetului de pe npm |
|
||||
| `websiteUrl` | Link către site-ul dvs. |
|
||||
| `termsUrl` | Link către termenii de serviciu |
|
||||
| `emailSupport` | Adresă de e-mail pentru suport |
|
||||
| `issueReportUrl` | Link către sistemul de urmărire a problemelor |
|
||||
|
||||
#### Roluri și permisiuni
|
||||
|
||||
@@ -376,7 +376,7 @@ Aplicațiile pot defini roluri care încapsulează permisiuni asupra obiectelor
|
||||
|
||||
* Cheia API de runtime injectată ca `TWENTY_API_KEY` este derivată din acest rol implicit pentru funcții.
|
||||
* Clientul tipizat va fi restricționat la permisiunile acordate acelui rol.
|
||||
* Follow least-privilege: create a dedicated role with only the permissions your functions need, then reference its universal identifier.
|
||||
* Respectați principiul celui mai mic privilegiu: creați un rol dedicat doar cu permisiunile de care au nevoie funcțiile, apoi referiți identificatorul său universal.
|
||||
|
||||
##### Rol implicit pentru funcții (*.role.ts)
|
||||
|
||||
@@ -429,7 +429,7 @@ export default defineRole({
|
||||
|
||||
Notițe:
|
||||
|
||||
* Start from the scaffolded role, then progressively restrict it following least-privilege.
|
||||
* Porniți de la rolul generat, apoi restrângeți-l progresiv urmând principiul celui mai mic privilegiu.
|
||||
* Înlocuiți `objectPermissions` și `fieldPermissions` cu obiectele/câmpurile de care au nevoie funcțiile.
|
||||
* `permissionFlags` controlează accesul la capabilități la nivelul platformei. Mențineți-le la minimum; adăugați doar ceea ce aveți nevoie.
|
||||
* Vedeți un exemplu funcțional în aplicația Hello World: [`packages/twenty-apps/hello-world/src/roles/function-role.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-apps/hello-world/src/roles/function-role.ts).
|
||||
@@ -543,7 +543,7 @@ Puncte cheie:
|
||||
* Este permisă o singură funcție de pre-instalare per aplicație. Construirea manifestului va genera o eroare dacă este detectată mai mult de una.
|
||||
* Proprietatea `universalIdentifier` a funcției este setată automat ca `preInstallLogicFunctionUniversalIdentifier` în manifestul aplicației în timpul build-ului — nu este nevoie să o referi în `defineApplication()`.
|
||||
* Timpul de expirare implicit este setat la 300 de secunde (5 minute) pentru a permite sarcini de pregătire mai lungi.
|
||||
* Pre-install functions do not need triggers — they are invoked by the platform before installation or manually via `exec --preInstall`.
|
||||
* Funcțiile de pre-instalare nu au nevoie de declanșatoare — sunt invocate de platformă înainte de instalare sau manual prin `exec --preInstall`.
|
||||
|
||||
### Funcții post-instalare
|
||||
|
||||
@@ -581,7 +581,7 @@ Puncte cheie:
|
||||
* Este permisă o singură funcție de post-instalare per aplicație. Construirea manifestului va genera o eroare dacă este detectată mai mult de una.
|
||||
* Proprietatea `universalIdentifier` a funcției este setată automat ca `postInstallLogicFunctionUniversalIdentifier` în manifestul aplicației în timpul build-ului — nu este nevoie să o referi în `defineApplication()`.
|
||||
* Timpul de expirare implicit este setat la 300 de secunde (5 minute) pentru a permite sarcini de configurare mai lungi, cum ar fi popularea datelor.
|
||||
* Post-install functions do not need triggers — they are invoked by the platform during installation or manually via `exec --postInstall`.
|
||||
* Funcțiile post-instalare nu au nevoie de declanșatoare — sunt invocate de platformă în timpul instalării sau manual prin `exec --postInstall`.
|
||||
|
||||
### Payload-ul declanșatorului de rută
|
||||
|
||||
@@ -625,15 +625,15 @@ const handler = async (event: RoutePayload) => {
|
||||
|
||||
Tipul `RoutePayload` are următoarea structură:
|
||||
|
||||
| Proprietate | Tip | Descriere |
|
||||
| ---------------------------- | ------------------------------------- | ---------------------------------------------------------------------------------------- |
|
||||
| `headers` | `Record<string, string \| undefined>` | Anteturi HTTP (doar cele listate în `forwardedRequestHeaders`) |
|
||||
| `queryStringParameters` | `Record<string, string \| undefined>` | Parametri query string (valorile multiple unite cu virgule) |
|
||||
| `pathParameters` | `Record<string, string \| undefined>` | Path parameters extracted from the route pattern (e.g., `/users/:id` -> `{ id: '123' }`) |
|
||||
| `body` | `object \| null` | Corpul cererii analizat (JSON) |
|
||||
| `isBase64Encoded` | `boolean` | Indică dacă corpul este codificat în base64 |
|
||||
| `requestContext.http.method` | `string` | Metoda HTTP (GET, POST, PUT, PATCH, DELETE) |
|
||||
| `requestContext.http.path` | `string` | Calea brută a cererii |
|
||||
| Proprietate | Tip | Descriere |
|
||||
| ---------------------------- | ------------------------------------- | ------------------------------------------------------------------------------------- |
|
||||
| `headers` | `Record<string, string \| undefined>` | Anteturi HTTP (doar cele listate în `forwardedRequestHeaders`) |
|
||||
| `queryStringParameters` | `Record<string, string \| undefined>` | Parametri query string (valorile multiple unite cu virgule) |
|
||||
| `pathParameters` | `Record<string, string \| undefined>` | Parametri de cale extrași din modelul rutei (de ex., `/users/:id` -> `{ id: '123' }`) |
|
||||
| `body` | `object \| null` | Corpul cererii analizat (JSON) |
|
||||
| `isBase64Encoded` | `boolean` | Indică dacă corpul este codificat în base64 |
|
||||
| `requestContext.http.method` | `string` | Metoda HTTP (GET, POST, PUT, PATCH, DELETE) |
|
||||
| `requestContext.http.path` | `string` | Calea brută a cererii |
|
||||
|
||||
### Transmiterea anteturilor HTTP
|
||||
|
||||
@@ -675,7 +675,7 @@ const handler = async (event: RoutePayload) => {
|
||||
|
||||
Puteți crea funcții noi în două moduri:
|
||||
|
||||
* **Scaffolded**: Run `yarn twenty add` and choose the option to add a new logic function. Aceasta generează un fișier inițial cu un handler și o configurație.
|
||||
* **Generat**: Rulați `yarn twenty add` și alegeți opțiunea de a adăuga o funcție de logică nouă. Aceasta generează un fișier inițial cu un handler și o configurație.
|
||||
* **Manual**: Creați un fișier nou `*.logic-function.ts` și folosiți `defineLogicFunction()`, urmând același model.
|
||||
|
||||
### Marcarea unei funcții logice drept instrument
|
||||
@@ -776,7 +776,7 @@ Puncte cheie:
|
||||
|
||||
Puteți crea componente Front noi în două moduri:
|
||||
|
||||
* **Scaffolded**: Run `yarn twenty add` and choose the option to add a new front component.
|
||||
* **Generat**: Rulați `yarn twenty add` și alegeți opțiunea de a adăuga o componentă Front nouă.
|
||||
* **Manual**: Creați un fișier nou `.tsx` și folosiți `defineFrontComponent()`, urmând același model.
|
||||
|
||||
### Abilități
|
||||
@@ -811,21 +811,21 @@ Puncte cheie:
|
||||
|
||||
Puteți crea abilități noi în două moduri:
|
||||
|
||||
* **Scaffolded**: Run `yarn twenty add` and choose the option to add a new skill.
|
||||
* **Generat**: Rulați `yarn twenty add` și alegeți opțiunea de a adăuga o abilitate nouă.
|
||||
* **Manual**: Creați un fișier nou și folosiți `defineSkill()`, urmând același model.
|
||||
|
||||
### Typed API clients (`twenty-client-sdk`)
|
||||
### Clienți API tipați (`twenty-client-sdk`)
|
||||
|
||||
The `twenty-client-sdk` package provides two typed GraphQL clients for interacting with the Twenty API from your logic functions and front components:
|
||||
Pachetul `twenty-client-sdk` oferă doi clienți GraphQL tipați pentru a interacționa cu API-ul Twenty din funcțiile de logică și componentele Front:
|
||||
|
||||
| Client | Importați | Endpoint | Generated? |
|
||||
| ------------------- | ---------------------------- | ---------------------------------------------- | ---------------------- |
|
||||
| `CoreApiClient` | `twenty-client-sdk/core` | `/graphql` — workspace data (records, objects) | Yes, at dev/build time |
|
||||
| `MetadataApiClient` | `twenty-client-sdk/metadata` | `/metadata` — workspace config, file uploads | No, ships pre-built |
|
||||
| Client | Importați | Endpoint | Generat? |
|
||||
| ------------------- | ---------------------------- | ------------------------------------------------------------------- | ---------------------------- |
|
||||
| `CoreApiClient` | `twenty-client-sdk/core` | `/graphql` — date ale spațiului de lucru (înregistrări, obiecte) | Da, în timpul dev/build |
|
||||
| `MetadataApiClient` | `twenty-client-sdk/metadata` | `/metadata` — configurarea spațiului de lucru, încărcări de fișiere | Nu, este livrat preconstruit |
|
||||
|
||||
#### CoreApiClient
|
||||
|
||||
`CoreApiClient` is the main client for querying and mutating workspace data. It is **generated from your workspace schema** during `yarn twenty dev` or `yarn twenty build`, so it's fully typed to match your objects and fields.
|
||||
`CoreApiClient` este clientul principal pentru interogarea și modificarea datelor din spațiul de lucru. Este generat din schema spațiului dvs. de lucru în timpul `yarn twenty dev` sau `yarn twenty build`, astfel încât este complet tipat pentru a corespunde obiectelor și câmpurilor dvs.
|
||||
|
||||
```typescript
|
||||
import { CoreApiClient } from 'twenty-client-sdk/core';
|
||||
@@ -859,15 +859,15 @@ const { createCompany } = await client.mutation({
|
||||
});
|
||||
```
|
||||
|
||||
The client uses a selection-set syntax: pass `true` to include a field, use `__args` for arguments, and nest objects for relations. You get full autocompletion and type checking based on your workspace schema.
|
||||
Clientul folosește o sintaxă de tip selection-set: transmiteți `true` pentru a include un câmp, folosiți `__args` pentru argumente și imbricați obiecte pentru relații. Obțineți autocompletare și verificare a tipurilor complete, pe baza schemei spațiului dvs. de lucru.
|
||||
|
||||
<Note>
|
||||
**CoreApiClient is generated at dev/build time.** If you try to use it without running `yarn twenty dev` or `yarn twenty build` first, it throws an error. The generation happens automatically — the CLI introspects your workspace's GraphQL schema, generates a typed client using `@genql/cli`, writes the generated sources to `node_modules/twenty-client-sdk/dist/core/generated/`, and replaces the stubs in `node_modules/twenty-client-sdk/dist/core.mjs` and `node_modules/twenty-client-sdk/dist/core.cjs`.
|
||||
**CoreApiClient este generat în timpul dev/build.** Dacă încercați să îl utilizați fără a rula mai întâi `yarn twenty dev` sau `yarn twenty build`, va arunca o eroare. Generarea are loc automat — CLI-ul introspectează schema GraphQL a spațiului dvs. de lucru, generează un client tipat folosind `@genql/cli`, scrie sursele generate în `node_modules/twenty-client-sdk/dist/core/generated/` și înlocuiește stubs-urile din `node_modules/twenty-client-sdk/dist/core.mjs` și `node_modules/twenty-client-sdk/dist/core.cjs`.
|
||||
</Note>
|
||||
|
||||
#### Using CoreSchema for type annotations
|
||||
#### Folosirea CoreSchema pentru adnotări de tip
|
||||
|
||||
`CoreSchema` provides TypeScript types matching your workspace objects, useful for typing component state or function parameters:
|
||||
`CoreSchema` oferă tipuri TypeScript care se potrivesc obiectelor din spațiul dvs. de lucru, utile pentru tiparea stării componentelor sau a parametrilor funcțiilor:
|
||||
|
||||
```typescript
|
||||
import { CoreApiClient, CoreSchema } from 'twenty-client-sdk/core';
|
||||
@@ -890,7 +890,7 @@ setCompany(result.company);
|
||||
|
||||
#### MetadataApiClient
|
||||
|
||||
`MetadataApiClient` ships pre-built with the SDK (no generation required). It queries the `/metadata` endpoint for workspace configuration, applications, and file uploads:
|
||||
`MetadataApiClient` este livrat preconstruit împreună cu SDK-ul (nu este necesară generarea). Interoghează endpointul `/metadata` pentru configurarea spațiului de lucru, aplicații și încărcări de fișiere:
|
||||
|
||||
```typescript
|
||||
import { MetadataApiClient } from 'twenty-client-sdk/metadata';
|
||||
@@ -912,18 +912,18 @@ const { findManyApplications } = await metadataClient.query({
|
||||
});
|
||||
```
|
||||
|
||||
#### Runtime credentials
|
||||
#### Acreditări la rulare
|
||||
|
||||
When your code runs on Twenty (logic functions or front components), the platform injects credentials as environment variables:
|
||||
Când codul dvs. rulează pe Twenty (funcții de logică sau componente Front), platforma injectează acreditările ca variabile de mediu:
|
||||
|
||||
* `TWENTY_API_URL` — Base URL of the Twenty API
|
||||
* `TWENTY_API_KEY` — Short-lived key scoped to your application's default function role
|
||||
* `TWENTY_API_URL` — URL-ul de bază al API-ului Twenty
|
||||
* `TWENTY_API_KEY` — Cheie cu durată scurtă, limitată la rolul implicit de funcție al aplicației
|
||||
|
||||
You do **not** need to pass these to the clients — they read from `process.env` automatically. The API key's permissions are determined by the role referenced in `defaultRoleUniversalIdentifier` in your `application-config.ts`.
|
||||
Nu trebuie să le transmiteți clienților — aceștia citesc automat din `process.env`. Permisiunile cheii API sunt determinate de rolul referențiat în `defaultRoleUniversalIdentifier` din `application-config.ts`.
|
||||
|
||||
#### Încărcarea fișierelor
|
||||
|
||||
`MetadataApiClient` includes an `uploadFile` method for attaching files to file-type fields. It implements the [GraphQL multipart request specification](https://github.com/jaydenseric/graphql-multipart-request-spec):
|
||||
`MetadataApiClient` include o metodă `uploadFile` pentru atașarea fișierelor la câmpuri de tip fișier. Implementează [specificația pentru cereri GraphQL multipart](https://github.com/jaydenseric/graphql-multipart-request-spec):
|
||||
|
||||
```typescript
|
||||
import { MetadataApiClient } from 'twenty-client-sdk/metadata';
|
||||
@@ -953,7 +953,7 @@ console.log(uploadedFile);
|
||||
|
||||
Puncte cheie:
|
||||
|
||||
* Uses the field's `universalIdentifier` (not its workspace-specific ID), so your upload code works across any workspace where your app is installed.
|
||||
* Folosește `universalIdentifier` al câmpului (nu ID-ul specific spațiului de lucru), astfel încât codul dvs. de încărcare funcționează în orice spațiu de lucru în care aplicația dvs. este instalată.
|
||||
* `url` returnat este un URL semnat pe care îl poți folosi pentru a accesa fișierul încărcat.
|
||||
|
||||
### Exemplu Hello World
|
||||
|
||||
@@ -9,18 +9,19 @@ Aplicațiile sunt în prezent în testare alfa. Caracteristica funcționează, d
|
||||
|
||||
Aplicațiile vă permit să extindeți Twenty cu obiecte personalizate, câmpuri, funcții logice, abilități IA și componente UI — toate gestionate ca cod.
|
||||
|
||||
**Ce puteți face astăzi:**
|
||||
**Ce puteți construi:**
|
||||
|
||||
* Definiți obiecte și câmpuri personalizate sub formă de cod (model de date gestionat)
|
||||
* Construiți funcții logice cu declanșatoare personalizate (rute HTTP, cron, evenimente ale bazei de date)
|
||||
* Definiți abilități pentru agenți de IA
|
||||
* Construiți componente front-end care se afișează în interfața Twenty
|
||||
* Implementați aceeași aplicație în mai multe spații de lucru
|
||||
* Obiecte, câmpuri, vizualizări și elemente de navigare personalizate pentru a defini modelul dumneavoastră de date
|
||||
* Funcții logice declanșate de rute HTTP, programări cron sau evenimente din baza de date
|
||||
* Componente front-end care se afișează direct în interfața Twenty
|
||||
* Abilități care extind capabilitățile agenților AI ai Twenty
|
||||
* Implementați o aplicație în mai multe spații de lucru
|
||||
|
||||
## Cerințe
|
||||
|
||||
* Node.js 24+ și Yarn 4
|
||||
* Docker (pentru serverul local de dezvoltare Twenty)
|
||||
* Node.js 24+
|
||||
* Yarn 4
|
||||
* Docker (sau o instanță Twenty locală în execuție)
|
||||
|
||||
## Începeți
|
||||
|
||||
@@ -29,21 +30,9 @@ Creați o aplicație nouă folosind generatorul oficial, apoi autentificați-vă
|
||||
```bash filename="Terminal"
|
||||
# Scaffold a new app (includes all examples by default)
|
||||
npx create-twenty-app@latest my-twenty-app
|
||||
cd my-twenty-app
|
||||
|
||||
# Start dev mode: automatically syncs local changes to your workspace
|
||||
yarn twenty dev
|
||||
```
|
||||
|
||||
Generatorul de schelet acceptă două moduri pentru a controla ce fișiere de exemplu sunt incluse:
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Default (exhaustive): all examples (object, field, logic function, front component, view, navigation menu item, skill, agent)
|
||||
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
|
||||
```
|
||||
> Folosiți opțiunea `--minimal` pentru a genera o instalare minimă
|
||||
|
||||
De aici puteți:
|
||||
|
||||
@@ -123,7 +112,7 @@ Cu `--minimal`, sunt create doar fișierele de bază (`application-config.ts`, `
|
||||
Pe scurt:
|
||||
|
||||
* **package.json**: Declară numele aplicației, versiunea, motoarele (Node 24+, Yarn 4) și adaugă `twenty-sdk` plus un script `twenty` care deleagă către CLI-ul local `twenty`. Rulați `yarn twenty help` pentru a lista toate comenzile disponibile.
|
||||
* **.gitignore**: Ignores common artifacts such as `node_modules`, `.yarn`, `.twenty/`, `dist/`, `build/`, coverage folders, log files, and `.env*` files.
|
||||
* **.gitignore**: Ignoră artefacte comune precum `node_modules`, `.yarn`, `.twenty/`, `dist/`, `build/`, foldere de coverage, fișiere jurnal și fișiere `.env*`.
|
||||
* **yarn.lock**, **.yarnrc.yml**, **.yarn/**: Blochează și configurează lanțul de instrumente Yarn 4 folosit de proiect.
|
||||
* **.nvmrc**: Fixează versiunea Node.js așteptată de proiect.
|
||||
* **.oxlintrc.json** și **tsconfig.json**: Oferă linting și configurație TypeScript pentru fișierele TypeScript ale aplicației.
|
||||
@@ -167,8 +156,8 @@ export default defineObject({
|
||||
|
||||
Comenzile ulterioare vor adăuga mai multe fișiere și foldere:
|
||||
|
||||
* `yarn twenty dev` will auto-generate the typed `CoreApiClient` (for workspace data via `/graphql`) into `node_modules/twenty-client-sdk/`. The `MetadataApiClient` (for workspace configuration and file uploads via `/metadata`) ships pre-built and is available immediately. Import them from `twenty-client-sdk/core` and `twenty-client-sdk/metadata` respectively.
|
||||
* `yarn twenty add` will add entity definition files under `src/` for your custom objects, functions, front components, roles, skills, and more.
|
||||
* `yarn twenty dev` va genera automat `CoreApiClient` tipizat (pentru datele spațiului de lucru prin `/graphql`) în `node_modules/twenty-client-sdk/`. `MetadataApiClient` (pentru configurarea spațiului de lucru și încărcarea fișierelor prin `/metadata`) este livrat preconstruit și este disponibil imediat. Importați-le din `twenty-client-sdk/core` și `twenty-client-sdk/metadata`, respectiv.
|
||||
* `yarn twenty add` va adăuga fișiere de definire a entităților în `src/` pentru obiectele personalizate, funcțiile, componentele front-end, rolurile, abilitățile și altele.
|
||||
|
||||
## Autentificare
|
||||
|
||||
|
||||
@@ -24,9 +24,9 @@ Comanda `build` compilează sursele TypeScript, transpilează funcțiile de logi
|
||||
yarn twenty build
|
||||
```
|
||||
|
||||
Rezultatul este scris în `.twenty/output/`. This directory contains everything needed for distribution: compiled code, assets, the manifest, and a copy of your `package.json`.
|
||||
Rezultatul este scris în `.twenty/output/`. Acest director conține tot ce este necesar pentru distribuție: cod compilat, resurse, manifestul și o copie a fișierului tău `package.json`.
|
||||
|
||||
To also create a `.tgz` tarball (used by the deploy command internally, or for manual distribution):
|
||||
Pentru a crea și un pachet `.tgz` (folosit intern de comanda de implementare sau pentru distribuire manuală):
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty build --tarball
|
||||
@@ -39,11 +39,11 @@ Publicarea pe npm face ca aplicația ta să poată fi descoperită în marketpla
|
||||
### Cerințe
|
||||
|
||||
* Un cont [npm](https://www.npmjs.com)
|
||||
* The `twenty-app` keyword **must** be listed in your `package.json` `keywords` array
|
||||
* Cuvântul cheie `twenty-app` trebuie să fie listat în array-ul `keywords` din `package.json`-ul tău
|
||||
|
||||
### Adding the required keyword
|
||||
### Adăugarea cuvântului cheie necesar
|
||||
|
||||
The Twenty marketplace discovers apps by searching the npm registry for packages with the `twenty-app` keyword. Add it to your `package.json`:
|
||||
Marketplace-ul Twenty descoperă aplicații căutând în registrul npm pachete cu cuvântul cheie `twenty-app`. Adaugă-l în `package.json`-ul tău:
|
||||
|
||||
```json filename="package.json"
|
||||
{
|
||||
@@ -55,52 +55,56 @@ The Twenty marketplace discovers apps by searching the npm registry for packages
|
||||
```
|
||||
|
||||
<Note>
|
||||
The marketplace searches for `keywords:twenty-app` on the npm registry. Without this keyword, your package won't appear in the marketplace even if it has the `twenty-app-` name prefix.
|
||||
Marketplace-ul caută `keywords:twenty-app` în registrul npm. Fără acest cuvânt cheie, pachetul tău nu va apărea în marketplace chiar dacă are prefixul de nume `twenty-app-`.
|
||||
</Note>
|
||||
|
||||
### Pași
|
||||
|
||||
1. **Build your app:**
|
||||
1. **Construiește-ți aplicația:**
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty build
|
||||
```
|
||||
|
||||
2. **Publish to npm:**
|
||||
2. **Publică pe npm:**
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty publish
|
||||
```
|
||||
|
||||
This runs `npm publish` from the `.twenty/output/` directory.
|
||||
Aceasta rulează `npm publish` din directorul `.twenty/output/`.
|
||||
|
||||
To publish under a specific dist-tag (e.g., `beta` or `next`):
|
||||
Pentru a publica sub un dist-tag specific (de ex., `beta` sau `next`):
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty publish --tag beta
|
||||
```
|
||||
|
||||
### How marketplace discovery works
|
||||
### Cum funcționează descoperirea în marketplace
|
||||
|
||||
The Twenty server syncs its marketplace catalog from the npm registry **every hour**:
|
||||
Serverul Twenty sincronizează catalogul marketplace-ului din registrul npm la fiecare oră:
|
||||
|
||||
1. It searches for all npm packages with the `keywords:twenty-app` keyword
|
||||
2. For each package, it fetches the `manifest.json` from the npm CDN
|
||||
3. The app's metadata (name, description, author, logo, screenshots, category) is extracted from the manifest and displayed in the marketplace
|
||||
1. Caută toate pachetele npm cu cuvântul cheie `keywords:twenty-app`
|
||||
2. Pentru fiecare pachet, preia `manifest.json` din CDN-ul npm
|
||||
3. Metadatele aplicației (nume, descriere, autor, logo, capturi de ecran, categorie) sunt extrase din manifest și afișate în marketplace
|
||||
|
||||
After publishing, your app can take up to one hour to appear in the marketplace. To trigger the sync immediately instead of waiting for the next hourly run:
|
||||
După publicare, poate dura până la o oră ca aplicația ta să apară în marketplace. Pentru a declanșa sincronizarea imediat, în loc să aștepți următoarea rulare orară:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty catalog-sync
|
||||
```
|
||||
|
||||
To target a specific remote:
|
||||
Pentru a viza un remote specific:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty catalog-sync -r production
|
||||
```
|
||||
|
||||
The metadata shown in the marketplace comes from your `defineApplication()` call in your app source code — fields like `displayName`, `description`, `author`, `category`, `logoUrl`, `screenshots`, `aboutDescription`, `websiteUrl`, and `termsUrl`.
|
||||
Metadatele afișate în marketplace provin din apelul tău `defineApplication()` din codul sursă al aplicației — câmpuri precum `displayName`, `description`, `author`, `category`, `logoUrl`, `screenshots`, `aboutDescription`, `websiteUrl` și `termsUrl`.
|
||||
|
||||
<Note>
|
||||
Dacă aplicația ta nu definește un `aboutDescription` în `defineApplication()`, piața va folosi automat fișierul `README.md` al pachetului tău de pe npm drept conținut pentru pagina Despre. Acest lucru înseamnă că poți menține un singur README atât pentru npm, cât și pentru piața Twenty. Dacă vrei o descriere diferită în piață, setează explicit `aboutDescription`.
|
||||
</Note>
|
||||
|
||||
### Publicare CI
|
||||
|
||||
@@ -133,39 +137,39 @@ jobs:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
```
|
||||
|
||||
For other CI systems (GitLab CI, CircleCI, etc.), the same three commands apply: `yarn install`, `yarn twenty build`, then `npm publish` from `.twenty/output`.
|
||||
Pentru alte sisteme CI (GitLab CI, CircleCI etc.), se aplică aceleași trei comenzi: `yarn install`, `yarn twenty build`, apoi `npm publish` din `.twenty/output`.
|
||||
|
||||
<Tip>
|
||||
**npm provenance** este opțională, dar recomandată. Publicarea cu `--provenance` adaugă un badge de încredere la listarea ta în npm, permițând utilizatorilor să verifice că pachetul a fost construit dintr-un commit specific într-un pipeline CI public. Vezi [documentația npm provenance](https://docs.npmjs.com/generating-provenance-statements) pentru instrucțiuni de configurare.
|
||||
</Tip>
|
||||
|
||||
## Deploying to a server (tarball)
|
||||
## Implementare pe un server (tarball)
|
||||
|
||||
For apps you don't want publicly available — proprietary tools, enterprise-only integrations, or experimental builds — you can deploy a tarball directly to a Twenty server.
|
||||
Pentru aplicațiile pe care nu le dorești disponibile public — instrumente proprietare, integrări doar pentru enterprise sau build-uri experimentale — poți implementa un tarball direct pe un server Twenty.
|
||||
|
||||
### Cerințe
|
||||
|
||||
Before deploying, you need a configured remote pointing to the target server. Remotes store the server URL and authentication credentials locally in `~/.twenty/config.json`.
|
||||
Înainte de implementare, ai nevoie de un remote configurat care să indice serverul țintă. Remote-urile stochează local URL-ul serverului și credențialele de autentificare în `~/.twenty/config.json`.
|
||||
|
||||
Add a remote:
|
||||
Adaugă un remote:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty remote add --url https://your-twenty-server.com --as production
|
||||
```
|
||||
|
||||
For a local development server:
|
||||
Pentru un server de dezvoltare local:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty remote add --local --as local
|
||||
```
|
||||
|
||||
You can also authenticate with an API key for non-interactive environments:
|
||||
Te poți autentifica și cu o cheie API pentru medii neinteractive:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty remote add --url https://your-twenty-server.com --token <api-key> --as production
|
||||
```
|
||||
|
||||
Manage your remotes:
|
||||
Gestionează-ți remote-urile:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty remote list # List all configured remotes
|
||||
@@ -174,76 +178,76 @@ yarn twenty remote status # Show active remote and auth status
|
||||
yarn twenty remote remove old # Remove a remote
|
||||
```
|
||||
|
||||
### Deploying
|
||||
### Implementare
|
||||
|
||||
Build and upload your app to the server in one step:
|
||||
Construiește și încarcă aplicația ta pe server într-un singur pas:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty deploy
|
||||
```
|
||||
|
||||
This builds the app with `--tarball`, then uploads the tarball to the default remote via a GraphQL multipart upload.
|
||||
Aceasta construiește aplicația cu `--tarball`, apoi încarcă tarball-ul către remote-ul implicit printr-o încărcare multipart GraphQL.
|
||||
|
||||
To deploy to a specific remote:
|
||||
Pentru a implementa către un remote specific:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty deploy -r production
|
||||
```
|
||||
|
||||
### Sharing a deployed app
|
||||
### Partajarea unei aplicații implementate
|
||||
|
||||
Tarball apps are not listed in the public marketplace, so other workspaces on the same server won't discover them by browsing. To share a deployed app:
|
||||
Aplicațiile tarball nu sunt listate în marketplace-ul public, astfel încât alte spații de lucru de pe același server nu le vor descoperi prin navigare. Pentru a partaja o aplicație implementată:
|
||||
|
||||
1. Go to **Settings > Applications > Registrations** and open your app
|
||||
2. In the **Distribution** tab, click **Copy share link**
|
||||
3. Share this link with users on other workspaces — it takes them directly to the app's install page
|
||||
1. Mergi la **Setări > Aplicații > Înregistrări** și deschide aplicația ta
|
||||
2. În fila **Distribuție**, fă clic pe **Copiază linkul de partajare**
|
||||
3. Partajează acest link cu utilizatori din alte spații de lucru — îi duce direct la pagina de instalare a aplicației
|
||||
|
||||
The share link uses the server's base URL (without any workspace subdomain) so it works for any workspace on the server.
|
||||
Linkul de partajare folosește URL-ul de bază al serverului (fără niciun subdomeniu de spațiu de lucru), astfel încât funcționează pentru orice spațiu de lucru de pe server.
|
||||
|
||||
### Gestionarea versiunilor
|
||||
|
||||
Pentru a lansa o actualizare:
|
||||
|
||||
1. Actualizează câmpul `version` din `package.json`
|
||||
2. Run `yarn twenty deploy` (or `yarn twenty deploy -r production`)
|
||||
3. Workspaces that have the app installed will see the upgrade available in their settings
|
||||
2. Rulează `yarn twenty deploy` (sau `yarn twenty deploy -r production`)
|
||||
3. Spațiile de lucru care au aplicația instalată vor vedea actualizarea disponibilă în setările lor
|
||||
|
||||
## Installing apps
|
||||
## Instalarea aplicațiilor
|
||||
|
||||
Once an app is published (npm) or deployed (tarball), workspaces install it through the UI:
|
||||
După ce o aplicație este publicată (npm) sau implementată (tarball), spațiile de lucru o instalează prin interfața utilizatorului (UI):
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty install
|
||||
```
|
||||
|
||||
Or from the **Settings > Applications** page in the Twenty UI, where both marketplace and tarball-deployed apps can be browsed and installed.
|
||||
Sau din pagina **Setări > Aplicații** din Twenty UI, unde pot fi navigate și instalate atât aplicațiile din marketplace, cât și cele implementate prin tarball.
|
||||
|
||||
## App distribution categories
|
||||
## Categorii de distribuție a aplicațiilor
|
||||
|
||||
Twenty organizează aplicațiile în trei categorii, în funcție de modul în care sunt distribuite:
|
||||
|
||||
| Categorie | Cum funcționează | Vizibilă în marketplace? |
|
||||
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ------------------------ |
|
||||
| **Dezvoltare** | Aplicații în modul de dezvoltare local, rulate prin `yarn twenty dev`. Folosite pentru construire și testare. | Nu |
|
||||
| **Published (npm)** | Apps published to npm with the `twenty-app` keyword. Listate în marketplace pentru ca orice spațiu de lucru să le poată instala. | Da |
|
||||
| **Internal (tarball)** | Aplicații implementate prin tarball pe un server specific. Available only to workspaces on that server via a share link. | Nu |
|
||||
| Categorie | Cum funcționează | Vizibilă în marketplace? |
|
||||
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------ |
|
||||
| **Dezvoltare** | Aplicații în modul de dezvoltare local, rulate prin `yarn twenty dev`. Folosite pentru construire și testare. | Nu |
|
||||
| **Publicat (npm)** | Aplicații publicate pe npm cu cuvântul cheie `twenty-app`. Listate în marketplace pentru ca orice spațiu de lucru să le poată instala. | Da |
|
||||
| **Intern (tarball)** | Aplicații implementate prin tarball pe un server specific. Disponibile doar pentru spațiile de lucru de pe acel server printr-un link de partajare. | Nu |
|
||||
|
||||
<Tip>
|
||||
Pornește în modul **Dezvoltare** în timp ce îți construiești aplicația. Când este gata, alege **Publicat** (npm) pentru distribuire largă sau **Intern** (tarball) pentru implementare privată.
|
||||
</Tip>
|
||||
|
||||
## CLI reference
|
||||
## Referință CLI
|
||||
|
||||
| Comandă | Descriere | Key flags |
|
||||
| --------------------------- | ---------------------------------------------- | --------------------------------------------------- |
|
||||
| `yarn twenty build` | Compile app and generate manifest | `--tarball` — also create a `.tgz` package |
|
||||
| `yarn twenty publish` | Build and publish to npm | `--tag <tag>` — npm dist-tag (e.g., `beta`, `next`) |
|
||||
| `yarn twenty deploy` | Build and upload tarball to a server | `-r, --remote <name>` — target remote |
|
||||
| `yarn twenty catalog-sync` | Trigger marketplace catalog sync on the server | `-r, --remote <name>` — target remote |
|
||||
| `yarn twenty install` | Install a deployed app on a workspace | `-r, --remote <name>` — target remote |
|
||||
| `yarn twenty dev` | Watch and sync local changes | Uses default remote |
|
||||
| `yarn twenty remote add` | Add a server connection | `--url`, `--token`, `--as`, `--local`, `--port` |
|
||||
| `yarn twenty remote list` | List configured remotes | — |
|
||||
| `yarn twenty remote switch` | Set default remote | — |
|
||||
| `yarn twenty remote status` | Show connection status | — |
|
||||
| `yarn twenty remote remove` | Remove a remote | — |
|
||||
| Comandă | Descriere | Opțiuni cheie |
|
||||
| --------------------------- | ---------------------------------------------------------------- | ----------------------------------------------------- |
|
||||
| `yarn twenty build` | Compilează aplicația și generează manifestul | `--tarball` — creează și un pachet `.tgz` |
|
||||
| `yarn twenty publish` | Construiește și publică pe npm | `--tag <tag>` — dist-tag npm (de ex., `beta`, `next`) |
|
||||
| `yarn twenty deploy` | Construiește și încarcă un tarball pe un server | `-r, --remote <name>` — remote țintă |
|
||||
| `yarn twenty catalog-sync` | Declanșează sincronizarea catalogului marketplace-ului pe server | `-r, --remote <name>` — remote țintă |
|
||||
| `yarn twenty install` | Instalează o aplicație implementată pe un spațiu de lucru | `-r, --remote <name>` — remote țintă |
|
||||
| `yarn twenty dev` | Monitorizează și sincronizează modificările locale | Folosește remote-ul implicit |
|
||||
| `yarn twenty remote add` | Adaugă o conexiune la server | `--url`, `--token`, `--as`, `--local`, `--port` |
|
||||
| `yarn twenty remote list` | Listează remote-urile configurate | — |
|
||||
| `yarn twenty remote switch` | Setează remote-ul implicit | — |
|
||||
| `yarn twenty remote status` | Afișează starea conexiunii | — |
|
||||
| `yarn twenty remote remove` | Elimină un remote | — |
|
||||
|
||||
@@ -38,7 +38,7 @@ yarn twenty dev
|
||||
|
||||
### Gestionarea serverului local
|
||||
|
||||
SDK-ul include comenzi pentru a gestiona un server local de dezvoltare Twenty (imagine Docker all-in-one cu PostgreSQL, Redis, server și worker):
|
||||
SDK-ul include comenzi pentru a gestiona un server local de dezvoltare Twenty (imagine Docker all-in-one cu PostgreSQL, Redis, server și worker pe portul 2020). Aceste comenzi se aplică doar serverului de dezvoltare bazat pe Docker — nu gestionează o instanță Twenty pornită din sursă (de exemplu, `npx nx start twenty-server` pe portul 3000):
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Pornește serverul local (descarcă imaginea dacă este necesar)
|
||||
|
||||
@@ -15,21 +15,21 @@ description: Определяйте объекты, функции логики,
|
||||
|
||||
SDK предоставляет вспомогательные функции для определения сущностей вашего приложения. Как описано в [Обнаружение сущностей](/l/ru/developers/extend/apps/getting-started#entity-detection), вы должны использовать `export default define<Entity>({...})`, чтобы ваши сущности были обнаружены:
|
||||
|
||||
| Функция | Назначение |
|
||||
| -------------------------------- | ----------------------------------------------------------------------------------- |
|
||||
| `defineApplication` | Настройка метаданных приложения (обязательно, по одному на приложение) |
|
||||
| `defineObject` | Определяет пользовательские объекты с полями |
|
||||
| `defineField` | Extend existing objects with additional fields or define standalone relation fields |
|
||||
| `defineLogicFunction` | Определение логических функций с обработчиками |
|
||||
| `definePreInstallLogicFunction` | Определяет предустановочную логическую функцию (по одной на приложение) |
|
||||
| `definePostInstallLogicFunction` | Определяет послеустановочную логическую функцию (по одной на приложение) |
|
||||
| `defineFrontComponent` | Определение фронт-компонентов для настраиваемого интерфейса |
|
||||
| `defineRole` | Настраивает права роли и доступ к объектам |
|
||||
| `defineView` | Определяйте сохранённые представления для объектов |
|
||||
| `defineNavigationMenuItem` | Определяйте ссылки боковой панели навигации |
|
||||
| `defineSkill` | Определение навыков агента ИИ |
|
||||
| `defineAgent` | Define AI agents |
|
||||
| `definePageLayout` | Define custom page layouts |
|
||||
| Функция | Назначение |
|
||||
| -------------------------------- | ----------------------------------------------------------------------------------------------- |
|
||||
| `defineApplication` | Настройка метаданных приложения (обязательно, по одному на приложение) |
|
||||
| `defineObject` | Определяет пользовательские объекты с полями |
|
||||
| `defineField` | Расширяйте существующие объекты дополнительными полями или определяйте отдельные поля отношений |
|
||||
| `defineLogicFunction` | Определение логических функций с обработчиками |
|
||||
| `definePreInstallLogicFunction` | Определяет предустановочную логическую функцию (по одной на приложение) |
|
||||
| `definePostInstallLogicFunction` | Определяет послеустановочную логическую функцию (по одной на приложение) |
|
||||
| `defineFrontComponent` | Определение фронт-компонентов для настраиваемого интерфейса |
|
||||
| `defineRole` | Настраивает права роли и доступ к объектам |
|
||||
| `defineView` | Определяйте сохранённые представления для объектов |
|
||||
| `defineNavigationMenuItem` | Определяйте ссылки боковой панели навигации |
|
||||
| `defineSkill` | Определение навыков агента ИИ |
|
||||
| `defineAgent` | Определяйте агентов ИИ |
|
||||
| `definePageLayout` | Определяйте пользовательские макеты страниц |
|
||||
|
||||
Эти функции проверяют вашу конфигурацию на этапе сборки и обеспечивают автодополнение в IDE и безопасность типов.
|
||||
|
||||
@@ -112,7 +112,7 @@ export default defineObject({
|
||||
* `universalIdentifier` должен быть уникальным и стабильным между развёртываниями.
|
||||
* Каждому полю требуются `name`, `type`, `label` и собственный стабильный `universalIdentifier`.
|
||||
* Массив `fields` необязателен — вы можете определять объекты без пользовательских полей.
|
||||
* You can scaffold new objects using `yarn twenty add`, which guides you through naming, fields, and relationships.
|
||||
* Вы можете сгенерировать новые объекты с помощью `yarn twenty add`, который проведёт вас через выбор именования, полей и связей.
|
||||
|
||||
<Note>
|
||||
**Базовые поля создаются автоматически.** Когда вы определяете пользовательский объект, Twenty автоматически добавляет стандартные поля,
|
||||
@@ -124,7 +124,7 @@ export default defineObject({
|
||||
|
||||
### Определение полей для существующих объектов
|
||||
|
||||
Use `defineField()` to add fields to objects you don't own — such as standard Twenty objects (Person, Company, etc.) or objects from other apps. Unlike inline fields in `defineObject()`, standalone fields require an `objectUniversalIdentifier` to specify which object they extend:
|
||||
Используйте `defineField()` для добавления полей к объектам, которые вам не принадлежат — например, к стандартным объектам Twenty (Person, Company и т. д.). или к объектам из других приложений. В отличие от встроенных полей в `defineObject()`, отдельные поля требуют `objectUniversalIdentifier`, чтобы указать, какой объект они расширяют:
|
||||
|
||||
```typescript
|
||||
// src/fields/company-loyalty-tier.field.ts
|
||||
@@ -147,35 +147,35 @@ export default defineField({
|
||||
|
||||
Основные моменты:
|
||||
|
||||
* `objectUniversalIdentifier` identifies the target object. For standard objects, use `STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS` exported from `twenty-sdk`.
|
||||
* When defining fields inline in `defineObject()`, you do **not** need `objectUniversalIdentifier` — it's inherited from the parent object.
|
||||
* `defineField()` is the only way to add fields to objects you didn't create with `defineObject()`.
|
||||
* `objectUniversalIdentifier` определяет целевой объект. Для стандартных объектов используйте `STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS`, экспортируемые из `twenty-sdk`.
|
||||
* При определении полей непосредственно в `defineObject()` вам не нужен `objectUniversalIdentifier` — он наследуется от родительского объекта.
|
||||
* `defineField()` — единственный способ добавить поля к объектам, которые вы не создавали с помощью `defineObject()`.
|
||||
|
||||
### Связи
|
||||
|
||||
Relations connect objects together. In Twenty, relations are always **bidirectional** — you define both sides, and each side references the other.
|
||||
Отношения связывают объекты между собой. В Twenty отношения всегда двунаправленные — вы определяете обе стороны, и каждая сторона ссылается на другую.
|
||||
|
||||
There are two relation types:
|
||||
Существуют два типа отношений:
|
||||
|
||||
| Тип отношения | Описание | Has foreign key? |
|
||||
| ------------- | ------------------------------------------------------------- | ---------------------- |
|
||||
| `MANY_TO_ONE` | Many records of this object point to one record of the target | Yes (`joinColumnName`) |
|
||||
| `ONE_TO_MANY` | One record of this object has many records of the target | No (inverse side) |
|
||||
| Тип отношения | Описание | Есть внешний ключ? |
|
||||
| ------------- | --------------------------------------------------------------------- | ---------------------- |
|
||||
| `MANY_TO_ONE` | Многие записи этого объекта указывают на одну запись целевого объекта | Да (`joinColumnName`) |
|
||||
| `ONE_TO_MANY` | Одна запись этого объекта имеет много записей целевого объекта | Нет (обратная сторона) |
|
||||
|
||||
#### How relations work
|
||||
#### Как работают отношения
|
||||
|
||||
Every relation requires **two fields** that reference each other:
|
||||
Каждое отношение требует **двух полей**, которые ссылаются друг на друга:
|
||||
|
||||
1. The **MANY_TO_ONE** side — lives on the object that holds the foreign key
|
||||
2. The **ONE_TO_MANY** side — lives on the object that owns the collection
|
||||
1. Сторона **MANY_TO_ONE** — находится в объекте, который содержит внешний ключ
|
||||
2. Сторона **ONE_TO_MANY** — находится в объекте, которому принадлежит коллекция
|
||||
|
||||
Both fields use `FieldType.RELATION` and cross-reference each other via `relationTargetFieldMetadataUniversalIdentifier`.
|
||||
Оба поля используют `FieldType.RELATION` и ссылаются друг на друга через `relationTargetFieldMetadataUniversalIdentifier`.
|
||||
|
||||
#### Example: Post Card has many Recipients
|
||||
#### Пример: Почтовая открытка имеет много получателей
|
||||
|
||||
Suppose a `PostCard` can be sent to many `PostCardRecipient` records. Each recipient belongs to exactly one post card.
|
||||
Предположим, `PostCard` может быть отправлен множству записей `PostCardRecipient`. Каждый получатель относится ровно к одной открытке.
|
||||
|
||||
**Step 1: Define the ONE_TO_MANY side on PostCard** (the "one" side):
|
||||
**Шаг 1: Определите сторону ONE_TO_MANY на PostCard** (сторона "one"):
|
||||
|
||||
```typescript
|
||||
// src/fields/post-card-recipients-on-post-card.field.ts
|
||||
@@ -203,7 +203,7 @@ export default defineField({
|
||||
});
|
||||
```
|
||||
|
||||
**Step 2: Define the MANY_TO_ONE side on PostCardRecipient** (the "many" side — holds the foreign key):
|
||||
**Шаг 2: Определите сторону MANY_TO_ONE на PostCardRecipient** (сторона "many" — содержит внешний ключ):
|
||||
|
||||
```typescript
|
||||
// src/fields/post-card-on-post-card-recipient.field.ts
|
||||
@@ -234,12 +234,12 @@ export default defineField({
|
||||
```
|
||||
|
||||
<Note>
|
||||
**Circular imports:** Both relation fields reference each other's `universalIdentifier`. To avoid circular import issues, export your field IDs as named constants from each file, and import them in the other file. The build system resolves these at compile time.
|
||||
**Циклические импорты:** Оба поля отношений ссылаются на `universalIdentifier` друг друга. Чтобы избежать проблем с циклическими импортами, экспортируйте идентификаторы полей как именованные константы из каждого файла и импортируйте их в другом файле. Система сборки разрешает это на этапе компиляции.
|
||||
</Note>
|
||||
|
||||
#### Relating to standard objects
|
||||
#### Связывание со стандартными объектами
|
||||
|
||||
To create a relation with a built-in Twenty object (Person, Company, etc.), use `STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS`:
|
||||
Чтобы создать отношение со встроенным объектом Twenty (Person, Company и т. д.), используйте `STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS`:
|
||||
|
||||
```typescript
|
||||
// src/fields/person-on-self-hosting-user.field.ts
|
||||
@@ -274,20 +274,20 @@ export default defineField({
|
||||
});
|
||||
```
|
||||
|
||||
#### Relation field properties
|
||||
#### Свойства поля отношения
|
||||
|
||||
| Свойство | Обязательно | Описание |
|
||||
| ------------------------------------------------- | ---------------- | ----------------------------------------------------------------------------------------------------- |
|
||||
| `type` | Да | Must be `FieldType.RELATION` |
|
||||
| `relationTargetObjectMetadataUniversalIdentifier` | Да | The `universalIdentifier` of the target object |
|
||||
| `relationTargetFieldMetadataUniversalIdentifier` | Да | The `universalIdentifier` of the matching field on the target object |
|
||||
| `universalSettings.relationType` | Да | `RelationType.MANY_TO_ONE` or `RelationType.ONE_TO_MANY` |
|
||||
| `universalSettings.onDelete` | MANY_TO_ONE only | What happens when the referenced record is deleted: `CASCADE`, `SET_NULL`, `RESTRICT`, or `NO_ACTION` |
|
||||
| `universalSettings.joinColumnName` | MANY_TO_ONE only | Database column name for the foreign key (e.g., `postCardId`) |
|
||||
| Свойство | Обязательно | Описание |
|
||||
| ------------------------------------------------- | ---------------------- | ----------------------------------------------------------------------------------------------- |
|
||||
| `type` | Да | Должно быть `FieldType.RELATION` |
|
||||
| `relationTargetObjectMetadataUniversalIdentifier` | Да | `universalIdentifier` целевого объекта |
|
||||
| `relationTargetFieldMetadataUniversalIdentifier` | Да | `universalIdentifier` соответствующего поля на целевом объекте |
|
||||
| `universalSettings.relationType` | Да | `RelationType.MANY_TO_ONE` или `RelationType.ONE_TO_MANY` |
|
||||
| `universalSettings.onDelete` | Только для MANY_TO_ONE | Что происходит при удалении связанной записи: `CASCADE`, `SET_NULL`, `RESTRICT` или `NO_ACTION` |
|
||||
| `universalSettings.joinColumnName` | Только для MANY_TO_ONE | Имя столбца базы данных для внешнего ключа (например, `postCardId`) |
|
||||
|
||||
#### Inline relation fields in defineObject
|
||||
#### Встроенные поля отношений в defineObject
|
||||
|
||||
You can also define relation fields directly inside `defineObject()`. In that case, omit `objectUniversalIdentifier` — it's inherited from the parent object:
|
||||
Вы также можете определять поля отношений непосредственно внутри `defineObject()`. В этом случае опустите `objectUniversalIdentifier` — он наследуется от родительского объекта:
|
||||
|
||||
```typescript
|
||||
export default defineObject({
|
||||
@@ -354,21 +354,21 @@ export default defineApplication({
|
||||
* `defaultRoleUniversalIdentifier` должен соответствовать файлу роли (см. ниже).
|
||||
* Предустановочные и послеустановочные функции автоматически обнаруживаются во время сборки манифеста. См. [Предустановочные функции](#pre-install-functions) и [Послеустановочные функции](#post-install-functions).
|
||||
|
||||
#### Marketplace metadata
|
||||
#### Метаданные маркетплейса
|
||||
|
||||
If you plan to [publish your app](/l/ru/developers/extend/apps/publishing), these optional fields control how your app appears in the marketplace:
|
||||
Если вы планируете [опубликовать приложение](/l/ru/developers/extend/apps/publishing), эти необязательные поля определяют, как ваше приложение отображается в маркетплейсе:
|
||||
|
||||
| Поле | Описание |
|
||||
| ------------------ | --------------------------------------------------- |
|
||||
| `author` | Author or company name |
|
||||
| `category` | App category for marketplace filtering |
|
||||
| `logoUrl` | Path to your app logo (relative to `./assets/`) |
|
||||
| `screenshots` | Array of screenshot paths (relative to `./assets/`) |
|
||||
| `aboutDescription` | Longer markdown description for the "About" tab |
|
||||
| `websiteUrl` | Link to your website |
|
||||
| `termsUrl` | Link to terms of service |
|
||||
| `emailSupport` | Support email address |
|
||||
| `issueReportUrl` | Link to issue tracker |
|
||||
| Поле | Описание |
|
||||
| ------------------ | ------------------------------------------------------------------------------------------------------------------- |
|
||||
| `author` | Имя автора или название компании |
|
||||
| `category` | Категория приложения для фильтрации в маркетплейсе |
|
||||
| `logoUrl` | Путь к логотипу вашего приложения (относительно `./assets/`) |
|
||||
| `screenshots` | Массив путей к скриншотам (относительно `./assets/`) |
|
||||
| `aboutDescription` | Расширенное описание в Markdown для вкладки "About". Если опущено, маркетплейс использует `README.md` пакета из npm |
|
||||
| `websiteUrl` | Ссылка на ваш сайт |
|
||||
| `termsUrl` | Ссылка на условия предоставления услуг |
|
||||
| `emailSupport` | Адрес электронной почты поддержки |
|
||||
| `issueReportUrl` | Ссылка на систему отслеживания проблем |
|
||||
|
||||
#### Роли и разрешения
|
||||
|
||||
@@ -376,7 +376,7 @@ If you plan to [publish your app](/l/ru/developers/extend/apps/publishing), thes
|
||||
|
||||
* Ключ API во время выполнения, подставляемый как `TWENTY_API_KEY`, получается из этой роли функции по умолчанию.
|
||||
* Типизированный клиент будет ограничен правами, предоставленными этой ролью.
|
||||
* Follow least-privilege: create a dedicated role with only the permissions your functions need, then reference its universal identifier.
|
||||
* Следуйте принципу наименьших привилегий: создайте отдельную роль только с теми правами, которые нужны вашим функциям, и укажите её универсальный идентификатор.
|
||||
|
||||
##### Роль функции по умолчанию (*.role.ts)
|
||||
|
||||
@@ -429,7 +429,7 @@ export default defineRole({
|
||||
|
||||
Заметки:
|
||||
|
||||
* Start from the scaffolded role, then progressively restrict it following least-privilege.
|
||||
* Начните со сгенерированной роли, затем постепенно ограничивайте её, следуя принципу наименьших привилегий.
|
||||
* Замените `objectPermissions` и `fieldPermissions` на объекты/поля, которые нужны вашим функциям.
|
||||
* `permissionFlags` управляют доступом к возможностям на уровне платформы. Держите их минимальными; добавляйте только то, что нужно.
|
||||
* См. рабочий пример в приложении Hello World: [`packages/twenty-apps/hello-world/src/roles/function-role.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-apps/hello-world/src/roles/function-role.ts).
|
||||
@@ -543,7 +543,7 @@ yarn twenty exec --preInstall
|
||||
* Для каждого приложения допускается только одна предустановочная функция. Сборка манифеста завершится ошибкой, если будет обнаружено более одной такой функции.
|
||||
* Параметр `universalIdentifier` функции автоматически устанавливается как `preInstallLogicFunctionUniversalIdentifier` в манифесте приложения во время сборки — вам не нужно ссылаться на него в `defineApplication()`.
|
||||
* Тайм-аут по умолчанию установлен на 300 секунд (5 минут), чтобы обеспечить выполнение более длительных задач подготовки.
|
||||
* Pre-install functions do not need triggers — they are invoked by the platform before installation or manually via `exec --preInstall`.
|
||||
* Предустановочным функциям не нужны триггеры — платформа вызывает их перед установкой или вручную через `exec --preInstall`.
|
||||
|
||||
### Послеустановочные функции
|
||||
|
||||
@@ -581,7 +581,7 @@ yarn twenty exec --postInstall
|
||||
* Для каждого приложения допускается только одна послеустановочная функция. Сборка манифеста завершится ошибкой, если будет обнаружено более одной такой функции.
|
||||
* Параметр `universalIdentifier` функции автоматически устанавливается как `postInstallLogicFunctionUniversalIdentifier` в манифесте приложения во время сборки — вам не нужно ссылаться на него в `defineApplication()`.
|
||||
* Тайм-аут по умолчанию установлен на 300 секунд (5 минут), чтобы позволить выполнять более длительные задачи настройки, такие как инициализация данных.
|
||||
* Post-install functions do not need triggers — they are invoked by the platform during installation or manually via `exec --postInstall`.
|
||||
* Постустановочным функциям не нужны триггеры — платформа вызывает их во время установки или вручную через `exec --postInstall`.
|
||||
|
||||
### Полезная нагрузка триггера маршрута
|
||||
|
||||
@@ -625,15 +625,15 @@ const handler = async (event: RoutePayload) => {
|
||||
|
||||
Тип `RoutePayload` имеет следующую структуру:
|
||||
|
||||
| Свойство | Тип | Описание |
|
||||
| ---------------------------- | ------------------------------------- | ---------------------------------------------------------------------------------------- |
|
||||
| `headers` | `Record<string, string \| undefined>` | HTTP-заголовки (только перечисленные в `forwardedRequestHeaders`) |
|
||||
| `queryStringParameters` | `Record<string, string \| undefined>` | Параметры строки запроса (несколько значений объединяются запятыми) |
|
||||
| `pathParameters` | `Record<string, string \| undefined>` | Path parameters extracted from the route pattern (e.g., `/users/:id` -> `{ id: '123' }`) |
|
||||
| `body` | `object \| null` | Разобранное тело запроса (JSON) |
|
||||
| `isBase64Encoded` | `логический тип` | Является ли тело закодированным в base64 |
|
||||
| `requestContext.http.method` | `строка` | Метод HTTP (GET, POST, PUT, PATCH, DELETE) |
|
||||
| `requestContext.http.path` | `строка` | Необработанный путь запроса |
|
||||
| Свойство | Тип | Описание |
|
||||
| ---------------------------- | ------------------------------------- | ------------------------------------------------------------------------------------------- |
|
||||
| `headers` | `Record<string, string \| undefined>` | HTTP-заголовки (только перечисленные в `forwardedRequestHeaders`) |
|
||||
| `queryStringParameters` | `Record<string, string \| undefined>` | Параметры строки запроса (несколько значений объединяются запятыми) |
|
||||
| `pathParameters` | `Record<string, string \| undefined>` | Параметры пути, извлечённые из шаблона маршрута (например, `/users/:id` -> `{ id: '123' }`) |
|
||||
| `body` | `object \| null` | Разобранное тело запроса (JSON) |
|
||||
| `isBase64Encoded` | `логический тип` | Является ли тело закодированным в base64 |
|
||||
| `requestContext.http.method` | `строка` | Метод HTTP (GET, POST, PUT, PATCH, DELETE) |
|
||||
| `requestContext.http.path` | `строка` | Необработанный путь запроса |
|
||||
|
||||
### Проброс HTTP-заголовков
|
||||
|
||||
@@ -675,7 +675,7 @@ const handler = async (event: RoutePayload) => {
|
||||
|
||||
Вы можете создать новые функции двумя способами:
|
||||
|
||||
* **Scaffolded**: Run `yarn twenty add` and choose the option to add a new logic function. Это создаёт стартовый файл с обработчиком и конфигурацией.
|
||||
* **Сгенерировано**: Запустите `yarn twenty add` и выберите опцию добавления новой логической функции. Это создаёт стартовый файл с обработчиком и конфигурацией.
|
||||
* **Вручную**: Создайте новый файл `*.logic-function.ts` и используйте `defineLogicFunction()`, следуя тому же шаблону.
|
||||
|
||||
### Пометка логической функции как инструмента
|
||||
@@ -776,7 +776,7 @@ export default defineFrontComponent({
|
||||
|
||||
Вы можете создать новые фронт-компоненты двумя способами:
|
||||
|
||||
* **Scaffolded**: Run `yarn twenty add` and choose the option to add a new front component.
|
||||
* **Сгенерировано**: Запустите `yarn twenty add` и выберите опцию добавления нового фронт-компонента.
|
||||
* **Вручную**: Создайте новый файл `.tsx` и используйте `defineFrontComponent()`, следуя тому же шаблону.
|
||||
|
||||
### Навыки
|
||||
@@ -811,21 +811,21 @@ export default defineSkill({
|
||||
|
||||
Вы можете создать новые навыки двумя способами:
|
||||
|
||||
* **Scaffolded**: Run `yarn twenty add` and choose the option to add a new skill.
|
||||
* **Сгенерировано**: Запустите `yarn twenty add` и выберите опцию добавления нового навыка.
|
||||
* **Вручную**: Создайте новый файл и используйте `defineSkill()`, следуя тому же шаблону.
|
||||
|
||||
### Typed API clients (`twenty-client-sdk`)
|
||||
### Типизированные клиенты API (`twenty-client-sdk`)
|
||||
|
||||
The `twenty-client-sdk` package provides two typed GraphQL clients for interacting with the Twenty API from your logic functions and front components:
|
||||
Пакет `twenty-client-sdk` предоставляет два типизированных клиента GraphQL для взаимодействия с API Twenty из ваших логических функций и фронт-компонентов:
|
||||
|
||||
| Клиент | Импорт | Endpoint | Generated? |
|
||||
| ------------------- | ---------------------------- | ---------------------------------------------- | ---------------------- |
|
||||
| `CoreApiClient` | `twenty-client-sdk/core` | `/graphql` — workspace data (records, objects) | Yes, at dev/build time |
|
||||
| `MetadataApiClient` | `twenty-client-sdk/metadata` | `/metadata` — workspace config, file uploads | No, ships pre-built |
|
||||
| Клиент | Импорт | Конечная точка | Генерируется? |
|
||||
| ------------------- | ---------------------------- | ----------------------------------------------------------------- | -------------------------------- |
|
||||
| `CoreApiClient` | `twenty-client-sdk/core` | `/graphql` — данные рабочего пространства (записи, объекты) | Да, на этапе dev/build |
|
||||
| `MetadataApiClient` | `twenty-client-sdk/metadata` | `/metadata` — конфигурация рабочего пространства, загрузка файлов | Нет, поставляется в готовом виде |
|
||||
|
||||
#### CoreApiClient
|
||||
|
||||
`CoreApiClient` is the main client for querying and mutating workspace data. It is **generated from your workspace schema** during `yarn twenty dev` or `yarn twenty build`, so it's fully typed to match your objects and fields.
|
||||
`CoreApiClient` — основной клиент для запросов и изменений данных рабочего пространства. Он генерируется из схемы вашего рабочего пространства во время `yarn twenty dev` или `yarn twenty build`, поэтому он полностью типизирован в соответствии с вашими объектами и полями.
|
||||
|
||||
```typescript
|
||||
import { CoreApiClient } from 'twenty-client-sdk/core';
|
||||
@@ -859,15 +859,15 @@ const { createCompany } = await client.mutation({
|
||||
});
|
||||
```
|
||||
|
||||
The client uses a selection-set syntax: pass `true` to include a field, use `__args` for arguments, and nest objects for relations. You get full autocompletion and type checking based on your workspace schema.
|
||||
Клиент использует синтаксис selection-set: передайте `true`, чтобы включить поле, используйте `__args` для аргументов и вкладывайте объекты для отношений. Вы получаете полное автодополнение и проверку типов на основе схемы вашего рабочего пространства.
|
||||
|
||||
<Note>
|
||||
**CoreApiClient is generated at dev/build time.** If you try to use it without running `yarn twenty dev` or `yarn twenty build` first, it throws an error. The generation happens automatically — the CLI introspects your workspace's GraphQL schema, generates a typed client using `@genql/cli`, writes the generated sources to `node_modules/twenty-client-sdk/dist/core/generated/`, and replaces the stubs in `node_modules/twenty-client-sdk/dist/core.mjs` and `node_modules/twenty-client-sdk/dist/core.cjs`.
|
||||
**CoreApiClient генерируется на этапе dev/build.** Если вы попытаетесь использовать его, не запустив сначала `yarn twenty dev` или `yarn twenty build`, он выбросит ошибку. Генерация происходит автоматически — CLI анализирует GraphQL-схему вашего рабочего пространства, генерирует типизированный клиент с помощью `@genql/cli`, записывает сгенерированные исходники в `node_modules/twenty-client-sdk/dist/core/generated/` и заменяет заглушки в `node_modules/twenty-client-sdk/dist/core.mjs` и `node_modules/twenty-client-sdk/dist/core.cjs`.
|
||||
</Note>
|
||||
|
||||
#### Using CoreSchema for type annotations
|
||||
#### Использование CoreSchema для аннотаций типов
|
||||
|
||||
`CoreSchema` provides TypeScript types matching your workspace objects, useful for typing component state or function parameters:
|
||||
`CoreSchema` предоставляет типы TypeScript, соответствующие объектам вашего рабочего пространства, что полезно для типизации состояния компонентов или параметров функций:
|
||||
|
||||
```typescript
|
||||
import { CoreApiClient, CoreSchema } from 'twenty-client-sdk/core';
|
||||
@@ -890,7 +890,7 @@ setCompany(result.company);
|
||||
|
||||
#### MetadataApiClient
|
||||
|
||||
`MetadataApiClient` ships pre-built with the SDK (no generation required). It queries the `/metadata` endpoint for workspace configuration, applications, and file uploads:
|
||||
`MetadataApiClient` поставляется в готовом виде вместе с SDK (генерация не требуется). Он выполняет запросы к эндпоинту `/metadata` для получения конфигурации рабочего пространства, приложений и загрузки файлов:
|
||||
|
||||
```typescript
|
||||
import { MetadataApiClient } from 'twenty-client-sdk/metadata';
|
||||
@@ -912,18 +912,18 @@ const { findManyApplications } = await metadataClient.query({
|
||||
});
|
||||
```
|
||||
|
||||
#### Runtime credentials
|
||||
#### Учётные данные времени выполнения
|
||||
|
||||
When your code runs on Twenty (logic functions or front components), the platform injects credentials as environment variables:
|
||||
Когда ваш код выполняется на Twenty (логические функции или фронт-компоненты), платформа предоставляет учётные данные в виде переменных окружения:
|
||||
|
||||
* `TWENTY_API_URL` — Base URL of the Twenty API
|
||||
* `TWENTY_API_KEY` — Short-lived key scoped to your application's default function role
|
||||
* `TWENTY_API_URL` — базовый URL API Twenty
|
||||
* `TWENTY_API_KEY` — краткоживущий ключ, ограниченный ролью функции по умолчанию вашего приложения
|
||||
|
||||
You do **not** need to pass these to the clients — they read from `process.env` automatically. The API key's permissions are determined by the role referenced in `defaultRoleUniversalIdentifier` in your `application-config.ts`.
|
||||
Вам не нужно передавать их клиентам — они автоматически читаются из `process.env`. Права ключа API определяются ролью, указанной в `defaultRoleUniversalIdentifier` в вашем `application-config.ts`.
|
||||
|
||||
#### Загрузка файлов
|
||||
|
||||
`MetadataApiClient` includes an `uploadFile` method for attaching files to file-type fields. It implements the [GraphQL multipart request specification](https://github.com/jaydenseric/graphql-multipart-request-spec):
|
||||
`MetadataApiClient` включает метод `uploadFile` для прикрепления файлов к полям типа файла. Он реализует [спецификацию многочастных запросов GraphQL](https://github.com/jaydenseric/graphql-multipart-request-spec):
|
||||
|
||||
```typescript
|
||||
import { MetadataApiClient } from 'twenty-client-sdk/metadata';
|
||||
@@ -953,7 +953,7 @@ console.log(uploadedFile);
|
||||
|
||||
Основные моменты:
|
||||
|
||||
* Uses the field's `universalIdentifier` (not its workspace-specific ID), so your upload code works across any workspace where your app is installed.
|
||||
* Он использует `universalIdentifier` поля (а не его идентификатор, специфичный для рабочего пространства), поэтому ваш код загрузки будет работать в любом рабочем пространстве, где установлено ваше приложение.
|
||||
* Возвращаемый `url` — это подписанный URL, который можно использовать для доступа к загруженному файлу.
|
||||
|
||||
### Пример Hello World
|
||||
|
||||
@@ -9,18 +9,19 @@ description: Создайте своё первое приложение Twenty
|
||||
|
||||
Приложения позволяют расширять Twenty с помощью пользовательских объектов, полей, логических функций, навыков ИИ и UI-компонентов — всё это управляется как код.
|
||||
|
||||
**Что вы можете делать уже сегодня:**
|
||||
**Что вы можете создать:**
|
||||
|
||||
* Определяйте пользовательские объекты и поля в виде кода (управляемая модель данных)
|
||||
* Создавайте логические функции с пользовательскими триггерами (HTTP-маршруты, cron, события базы данных)
|
||||
* Определяйте навыки для ИИ-агентов
|
||||
* Создавайте фронтенд-компоненты, которые отображаются внутри интерфейса Twenty
|
||||
* Развёртывайте одно и то же приложение в нескольких рабочих пространствах
|
||||
* Пользовательские объекты, поля, представления и элементы навигации для формирования вашей модели данных
|
||||
* Логические функции, запускаемые маршрутами HTTP, расписаниями cron или событиями базы данных
|
||||
* Фронтенд-компоненты, которые непосредственно отображаются внутри интерфейса Twenty
|
||||
* Навыки, расширяющие возможности ИИ-агентов Twenty
|
||||
* Разверните приложение в нескольких рабочих пространствах
|
||||
|
||||
## Требования
|
||||
|
||||
* Node.js 24+ и Yarn 4
|
||||
* Docker (для локального сервера разработки Twenty)
|
||||
* Node.js 24+
|
||||
* Yarn 4
|
||||
* Docker (или запущенный локальный экземпляр Twenty)
|
||||
|
||||
## Начало работы
|
||||
|
||||
@@ -29,21 +30,9 @@ description: Создайте своё первое приложение Twenty
|
||||
```bash filename="Terminal"
|
||||
# Scaffold a new app (includes all examples by default)
|
||||
npx create-twenty-app@latest my-twenty-app
|
||||
cd my-twenty-app
|
||||
|
||||
# Start dev mode: automatically syncs local changes to your workspace
|
||||
yarn twenty dev
|
||||
```
|
||||
|
||||
Генератор каркаса поддерживает два режима для управления тем, какие файлы-примеры включаются:
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Default (exhaustive): all examples (object, field, logic function, front component, view, navigation menu item, skill, agent)
|
||||
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
|
||||
```
|
||||
> Используйте параметр `--minimal`, чтобы создать минимальную установку
|
||||
|
||||
Отсюда вы можете:
|
||||
|
||||
@@ -123,7 +112,7 @@ my-twenty-app/
|
||||
В общих чертах:
|
||||
|
||||
* **package.json**: Объявляет имя приложения, версию, движки (Node 24+, Yarn 4) и добавляет `twenty-sdk`, а также скрипт `twenty`, который делегирует выполнение локальному CLI `twenty`. Выполните `yarn twenty help`, чтобы вывести список всех доступных команд.
|
||||
* **.gitignore**: Ignores common artifacts such as `node_modules`, `.yarn`, `.twenty/`, `dist/`, `build/`, coverage folders, log files, and `.env*` files.
|
||||
* **.gitignore**: Игнорирует распространённые артефакты, такие как `node_modules`, `.yarn`, `.twenty/`, `dist/`, `build/`, каталоги coverage, файлы журналов и файлы `.env*`.
|
||||
* **yarn.lock**, **.yarnrc.yml**, **.yarn/**: Фиксируют и настраивают используемый в проекте инструментарий Yarn 4.
|
||||
* **.nvmrc**: Фиксирует версию Node.js, ожидаемую проектом.
|
||||
* **.oxlintrc.json** и **tsconfig.json**: Обеспечивают линтинг и конфигурацию TypeScript для исходников вашего приложения на TypeScript.
|
||||
@@ -167,8 +156,8 @@ export default defineObject({
|
||||
|
||||
Позднее команды добавят больше файлов и папок:
|
||||
|
||||
* `yarn twenty dev` will auto-generate the typed `CoreApiClient` (for workspace data via `/graphql`) into `node_modules/twenty-client-sdk/`. The `MetadataApiClient` (for workspace configuration and file uploads via `/metadata`) ships pre-built and is available immediately. Import them from `twenty-client-sdk/core` and `twenty-client-sdk/metadata` respectively.
|
||||
* `yarn twenty add` will add entity definition files under `src/` for your custom objects, functions, front components, roles, skills, and more.
|
||||
* `yarn twenty dev` автоматически сгенерирует типизированный `CoreApiClient` (для данных рабочего пространства через `/graphql`) в `node_modules/twenty-client-sdk/`. `MetadataApiClient` (для конфигурации рабочего пространства и загрузки файлов через `/metadata`) поставляется в предсобранном виде и доступен сразу. Импортируйте их из `twenty-client-sdk/core` и `twenty-client-sdk/metadata` соответственно.
|
||||
* `yarn twenty add` добавит файлы определений сущностей в `src/` для ваших пользовательских объектов, функций, фронтенд-компонентов, ролей, навыков и многого другого.
|
||||
|
||||
## Аутентификация
|
||||
|
||||
|
||||
@@ -24,9 +24,9 @@ description: Распространяйте своё приложение Twenty
|
||||
yarn twenty build
|
||||
```
|
||||
|
||||
Выходные данные записываются в `.twenty/output/`. This directory contains everything needed for distribution: compiled code, assets, the manifest, and a copy of your `package.json`.
|
||||
Выходные данные записываются в `.twenty/output/`. Этот каталог содержит всё необходимое для распространения: скомпилированный код, ресурсы, манифест и копию вашего `package.json`.
|
||||
|
||||
To also create a `.tgz` tarball (used by the deploy command internally, or for manual distribution):
|
||||
Чтобы также создать tarball `.tgz` (который внутренне используется командой deploy или для ручного распространения):
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty build --tarball
|
||||
@@ -39,11 +39,11 @@ yarn twenty build --tarball
|
||||
### Требования
|
||||
|
||||
* Учётная запись [npm](https://www.npmjs.com)
|
||||
* The `twenty-app` keyword **must** be listed in your `package.json` `keywords` array
|
||||
* Ключевое слово `twenty-app` **обязательно** должно быть указано в массиве `keywords` вашего `package.json`
|
||||
|
||||
### Adding the required keyword
|
||||
### Добавление обязательного ключевого слова
|
||||
|
||||
The Twenty marketplace discovers apps by searching the npm registry for packages with the `twenty-app` keyword. Add it to your `package.json`:
|
||||
Маркетплейс Twenty находит приложения, ища в реестре npm пакеты с ключевым словом `twenty-app`. Добавьте его в ваш `package.json`:
|
||||
|
||||
```json filename="package.json"
|
||||
{
|
||||
@@ -55,52 +55,56 @@ The Twenty marketplace discovers apps by searching the npm registry for packages
|
||||
```
|
||||
|
||||
<Note>
|
||||
The marketplace searches for `keywords:twenty-app` on the npm registry. Without this keyword, your package won't appear in the marketplace even if it has the `twenty-app-` name prefix.
|
||||
Маркетплейс ищет в реестре npm по `keywords:twenty-app`. Без этого ключевого слова ваш пакет не появится в маркетплейсе, даже если в его имени есть префикс `twenty-app-`.
|
||||
</Note>
|
||||
|
||||
### Шаги
|
||||
|
||||
1. **Build your app:**
|
||||
1. **Сборка вашего приложения:**
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty build
|
||||
```
|
||||
|
||||
2. **Publish to npm:**
|
||||
2. **Публикация в npm:**
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty publish
|
||||
```
|
||||
|
||||
This runs `npm publish` from the `.twenty/output/` directory.
|
||||
Это выполняет `npm publish` из каталога `.twenty/output/`.
|
||||
|
||||
To publish under a specific dist-tag (e.g., `beta` or `next`):
|
||||
Чтобы опубликовать с определённым dist-tag (например, `beta` или `next`):
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty publish --tag beta
|
||||
```
|
||||
|
||||
### How marketplace discovery works
|
||||
### Как работает обнаружение приложений в маркетплейсе
|
||||
|
||||
The Twenty server syncs its marketplace catalog from the npm registry **every hour**:
|
||||
Сервер Twenty синхронизирует каталог маркетплейса из реестра npm **каждый час**:
|
||||
|
||||
1. It searches for all npm packages with the `keywords:twenty-app` keyword
|
||||
2. For each package, it fetches the `manifest.json` from the npm CDN
|
||||
3. The app's metadata (name, description, author, logo, screenshots, category) is extracted from the manifest and displayed in the marketplace
|
||||
1. Он ищет все пакеты npm с ключевым словом `keywords:twenty-app`
|
||||
2. Для каждого пакета он извлекает `manifest.json` с CDN npm
|
||||
3. Метаданные приложения (name, description, author, logo, screenshots, category) извлекаются из манифеста и отображаются в маркетплейсе
|
||||
|
||||
After publishing, your app can take up to one hour to appear in the marketplace. To trigger the sync immediately instead of waiting for the next hourly run:
|
||||
После публикации может пройти до одного часа, прежде чем ваше приложение появится в маркетплейсе. Чтобы запустить синхронизацию немедленно, не дожидаясь следующего почасового запуска:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty catalog-sync
|
||||
```
|
||||
|
||||
To target a specific remote:
|
||||
Чтобы указать конкретный remote:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty catalog-sync -r production
|
||||
```
|
||||
|
||||
The metadata shown in the marketplace comes from your `defineApplication()` call in your app source code — fields like `displayName`, `description`, `author`, `category`, `logoUrl`, `screenshots`, `aboutDescription`, `websiteUrl`, and `termsUrl`.
|
||||
Метаданные, отображаемые в маркетплейсе, берутся из вызова `defineApplication()` в исходном коде вашего приложения — из таких полей, как `displayName`, `description`, `author`, `category`, `logoUrl`, `screenshots`, `aboutDescription`, `websiteUrl` и `termsUrl`.
|
||||
|
||||
<Note>
|
||||
Если ваше приложение не определяет `aboutDescription` в `defineApplication()`, маркетплейс автоматически использует `README.md` вашего пакета из npm в качестве содержимого страницы «О приложении». Это означает, что вы можете поддерживать единый README как для npm, так и для маркетплейса Twenty. Если вы хотите другое описание в маркетплейсе, явно задайте `aboutDescription`.
|
||||
</Note>
|
||||
|
||||
### Публикация через CI
|
||||
|
||||
@@ -133,39 +137,39 @@ jobs:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
```
|
||||
|
||||
For other CI systems (GitLab CI, CircleCI, etc.), the same three commands apply: `yarn install`, `yarn twenty build`, then `npm publish` from `.twenty/output`.
|
||||
Для других CI-систем (GitLab CI, CircleCI и др.) применимы те же три команды: `yarn install`, `yarn twenty build`, затем `npm publish` из `.twenty/output`.
|
||||
|
||||
<Tip>
|
||||
**npm provenance** — опционально, но рекомендуется. Публикация с флагом `--provenance` добавляет к вашему пакету в npm значок доверия, позволяя пользователям проверить, что пакет был собран из конкретного коммита в общедоступном конвейере CI. См. инструкции по настройке в [документации по npm provenance](https://docs.npmjs.com/generating-provenance-statements).
|
||||
</Tip>
|
||||
|
||||
## Deploying to a server (tarball)
|
||||
## Развертывание на сервер (tarball)
|
||||
|
||||
For apps you don't want publicly available — proprietary tools, enterprise-only integrations, or experimental builds — you can deploy a tarball directly to a Twenty server.
|
||||
Для приложений, которые вы не хотите делать общедоступными — собственные инструменты, интеграции только для предприятий или экспериментальные сборки — вы можете развернуть tarball напрямую на сервер Twenty.
|
||||
|
||||
### Требования
|
||||
|
||||
Before deploying, you need a configured remote pointing to the target server. Remotes store the server URL and authentication credentials locally in `~/.twenty/config.json`.
|
||||
Перед развертыванием вам нужен настроенный remote, указывающий на целевой сервер. Remotes локально хранят URL сервера и учётные данные аутентификации в `~/.twenty/config.json`.
|
||||
|
||||
Add a remote:
|
||||
Добавьте remote:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty remote add --url https://your-twenty-server.com --as production
|
||||
```
|
||||
|
||||
For a local development server:
|
||||
Для локального сервера разработки:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty remote add --local --as local
|
||||
```
|
||||
|
||||
You can also authenticate with an API key for non-interactive environments:
|
||||
Вы также можете аутентифицироваться с помощью API-ключа в неинтерактивных средах:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty remote add --url https://your-twenty-server.com --token <api-key> --as production
|
||||
```
|
||||
|
||||
Manage your remotes:
|
||||
Управляйте remotes:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty remote list # List all configured remotes
|
||||
@@ -174,76 +178,76 @@ yarn twenty remote status # Show active remote and auth status
|
||||
yarn twenty remote remove old # Remove a remote
|
||||
```
|
||||
|
||||
### Deploying
|
||||
### Развертывание
|
||||
|
||||
Build and upload your app to the server in one step:
|
||||
Соберите и загрузите ваше приложение на сервер в одном шаге:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty deploy
|
||||
```
|
||||
|
||||
This builds the app with `--tarball`, then uploads the tarball to the default remote via a GraphQL multipart upload.
|
||||
Это собирает приложение с флагом `--tarball`, затем загружает tarball на remote по умолчанию через GraphQL multipart upload.
|
||||
|
||||
To deploy to a specific remote:
|
||||
Чтобы развернуть на конкретный remote:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty deploy -r production
|
||||
```
|
||||
|
||||
### Sharing a deployed app
|
||||
### Общий доступ к развернутому приложению
|
||||
|
||||
Tarball apps are not listed in the public marketplace, so other workspaces on the same server won't discover them by browsing. To share a deployed app:
|
||||
Приложения в формате tarball не отображаются в публичном маркетплейсе, поэтому другие рабочие пространства на том же сервере не найдут их при просмотре. Чтобы поделиться развернутым приложением:
|
||||
|
||||
1. Go to **Settings > Applications > Registrations** and open your app
|
||||
2. In the **Distribution** tab, click **Copy share link**
|
||||
3. Share this link with users on other workspaces — it takes them directly to the app's install page
|
||||
1. Перейдите в **Настройки > Приложения > Регистрации** и откройте ваше приложение
|
||||
2. На вкладке **Распространение** нажмите **Копировать ссылку для общего доступа**
|
||||
3. Поделитесь этой ссылкой с пользователями в других рабочих пространствах — она ведёт их прямо на страницу установки приложения
|
||||
|
||||
The share link uses the server's base URL (without any workspace subdomain) so it works for any workspace on the server.
|
||||
Ссылка общего доступа использует базовый URL сервера (без какого-либо поддомена рабочего пространства), поэтому она работает для любого рабочего пространства на сервере.
|
||||
|
||||
### Управление версиями
|
||||
|
||||
Чтобы выпустить обновление:
|
||||
|
||||
1. Обновите значение поля `version` в файле `package.json`
|
||||
2. Run `yarn twenty deploy` (or `yarn twenty deploy -r production`)
|
||||
3. Workspaces that have the app installed will see the upgrade available in their settings
|
||||
2. Выполните `yarn twenty deploy` (или `yarn twenty deploy -r production`)
|
||||
3. Рабочие пространства, в которых установлено приложение, увидят доступное обновление в своих настройках
|
||||
|
||||
## Installing apps
|
||||
## Установка приложений
|
||||
|
||||
Once an app is published (npm) or deployed (tarball), workspaces install it through the UI:
|
||||
После публикации приложения (npm) или его развертывания (tarball) рабочие пространства устанавливают его через интерфейс:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty install
|
||||
```
|
||||
|
||||
Or from the **Settings > Applications** page in the Twenty UI, where both marketplace and tarball-deployed apps can be browsed and installed.
|
||||
Или со страницы **Настройки > Приложения** в интерфейсе Twenty, где можно просматривать и устанавливать как приложения из маркетплейса, так и развернутые через tarball.
|
||||
|
||||
## App distribution categories
|
||||
## Категории распространения приложений
|
||||
|
||||
Twenty группирует приложения в три категории в зависимости от способа их распространения:
|
||||
|
||||
| Категория | Как это работает | Отображается в маркетплейсе? |
|
||||
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- |
|
||||
| **Разработка** | Локальные приложения в режиме разработки, запущенные через `yarn twenty dev`. Используются для сборки и тестирования. | Нет |
|
||||
| **Published (npm)** | Apps published to npm with the `twenty-app` keyword. Отображаются в маркетплейсе, доступные для установки любому рабочему пространству. | Да |
|
||||
| **Internal (tarball)** | Приложения, развернутые через tarball на конкретном сервере. Available only to workspaces on that server via a share link. | Нет |
|
||||
| Категория | Как это работает | Отображается в маркетплейсе? |
|
||||
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- |
|
||||
| **Разработка** | Локальные приложения в режиме разработки, запущенные через `yarn twenty dev`. Используются для сборки и тестирования. | Нет |
|
||||
| **Опубликовано (npm)** | Приложения, опубликованные в npm с ключевым словом `twenty-app`. Отображаются в маркетплейсе, доступные для установки любому рабочему пространству. | Да |
|
||||
| **Внутренние (tarball)** | Приложения, развернутые через tarball на конкретном сервере. Доступны только рабочим пространствам на этом сервере по ссылке общего доступа. | Нет |
|
||||
|
||||
<Tip>
|
||||
Начните в режиме **Разработка** во время создания приложения. Когда будет готово, выберите **Опубликовано** (npm) для широкого распространения или **Внутренний** (tarball) для приватного развертывания.
|
||||
</Tip>
|
||||
|
||||
## CLI reference
|
||||
## Справочник по CLI
|
||||
|
||||
| Команда | Описание | Key flags |
|
||||
| --------------------------- | ---------------------------------------------- | --------------------------------------------------- |
|
||||
| `yarn twenty build` | Compile app and generate manifest | `--tarball` — also create a `.tgz` package |
|
||||
| `yarn twenty publish` | Build and publish to npm | `--tag <tag>` — npm dist-tag (e.g., `beta`, `next`) |
|
||||
| `yarn twenty deploy` | Build and upload tarball to a server | `-r, --remote <name>` — target remote |
|
||||
| `yarn twenty catalog-sync` | Trigger marketplace catalog sync on the server | `-r, --remote <name>` — target remote |
|
||||
| `yarn twenty install` | Install a deployed app on a workspace | `-r, --remote <name>` — target remote |
|
||||
| `yarn twenty dev` | Watch and sync local changes | Uses default remote |
|
||||
| `yarn twenty remote add` | Add a server connection | `--url`, `--token`, `--as`, `--local`, `--port` |
|
||||
| `yarn twenty remote list` | List configured remotes | — |
|
||||
| `yarn twenty remote switch` | Set default remote | — |
|
||||
| `yarn twenty remote status` | Show connection status | — |
|
||||
| `yarn twenty remote remove` | Remove a remote | — |
|
||||
| Команда | Описание | Основные флаги |
|
||||
| --------------------------- | -------------------------------------------------------- | ------------------------------------------------------- |
|
||||
| `yarn twenty build` | Скомпилировать приложение и сгенерировать манифест | `--tarball` — также создать пакет `.tgz` |
|
||||
| `yarn twenty publish` | Собрать и опубликовать в npm | `--tag <tag>` — dist-tag npm (например, `beta`, `next`) |
|
||||
| `yarn twenty deploy` | Собрать и загрузить tarball на сервер | `-r, --remote <name>` — целевой удалённый репозиторий |
|
||||
| `yarn twenty catalog-sync` | Запустить на сервере синхронизацию каталога маркетплейса | `-r, --remote <name>` — целевой удалённый репозиторий |
|
||||
| `yarn twenty install` | Установить развернутое приложение в рабочем пространстве | `-r, --remote <name>` — целевой remote |
|
||||
| `yarn twenty dev` | Отслеживать и синхронизировать локальные изменения | Использует remote по умолчанию |
|
||||
| `yarn twenty remote add` | Добавить подключение к серверу | `--url`, `--token`, `--as`, `--local`, `--port` |
|
||||
| `yarn twenty remote list` | Показать настроенные remotes | — |
|
||||
| `yarn twenty remote switch` | Установить remote по умолчанию | — |
|
||||
| `yarn twenty remote status` | Показать статус подключения | — |
|
||||
| `yarn twenty remote remove` | Удалить remote | — |
|
||||
|
||||
@@ -38,7 +38,7 @@ yarn twenty dev
|
||||
|
||||
### Управление локальным сервером
|
||||
|
||||
SDK включает команды для управления локальным сервером разработки Twenty (универсальный образ Docker с PostgreSQL, Redis, сервером и воркером):
|
||||
SDK включает команды для управления локальным сервером разработки Twenty (универсальный образ Docker с PostgreSQL, Redis, сервером и воркером на порту 2020). Эти команды применимы только к серверу разработки на базе Docker — они не управляют экземпляром Twenty, запущенным из исходного кода (например, `npx nx start twenty-server` на порту 3000):
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Запустить локальный сервер (при необходимости будет загружен образ)
|
||||
|
||||
@@ -15,21 +15,21 @@ twenty-sdk, uygulamanız içinde kullandığınız türlendirilmiş yapı taşla
|
||||
|
||||
SDK, uygulama varlıklarınızı tanımlamak için yardımcı fonksiyonlar sağlar. [Varlık algılama](/l/tr/developers/extend/apps/getting-started#entity-detection) bölümünde açıklandığı gibi, varlıklarınızın algılanması için `export default define<Entity>({...})` kullanmalısınız:
|
||||
|
||||
| Fonksiyon | Amaç |
|
||||
| -------------------------------- | ----------------------------------------------------------------------------------- |
|
||||
| `defineApplication` | Uygulama meta verilerini yapılandırın (zorunlu, uygulama başına bir adet) |
|
||||
| `defineObject` | Alanlara sahip özel nesneler tanımlayın |
|
||||
| `defineField` | Extend existing objects with additional fields or define standalone relation fields |
|
||||
| `defineLogicFunction` | İşleyicilerle mantık fonksiyonları tanımlayın |
|
||||
| `definePreInstallLogicFunction` | Bir kurulum öncesi mantık işlevi tanımlayın (uygulama başına bir adet) |
|
||||
| `definePostInstallLogicFunction` | Bir kurulum sonrası mantık işlevi tanımlayın (uygulama başına bir adet) |
|
||||
| `defineFrontComponent` | Özel kullanıcı arayüzü için ön uç bileşenlerini tanımlayın |
|
||||
| `defineRole` | Rol izinlerini ve nesne erişimini yapılandırın |
|
||||
| `defineView` | Nesneler için kaydedilmiş görünümler tanımlayın |
|
||||
| `defineNavigationMenuItem` | Kenar çubuğu gezinme bağlantılarını tanımlayın |
|
||||
| `defineSkill` | Yapay zekâ ajanı yeteneklerini tanımlayın |
|
||||
| `defineAgent` | Define AI agents |
|
||||
| `definePageLayout` | Define custom page layouts |
|
||||
| Fonksiyon | Amaç |
|
||||
| -------------------------------- | ---------------------------------------------------------------------------------- |
|
||||
| `defineApplication` | Uygulama meta verilerini yapılandırın (zorunlu, uygulama başına bir adet) |
|
||||
| `defineObject` | Alanlara sahip özel nesneler tanımlayın |
|
||||
| `defineField` | Mevcut nesneleri ek alanlarla genişletin veya bağımsız ilişki alanları tanımlayın. |
|
||||
| `defineLogicFunction` | İşleyicilerle mantık fonksiyonları tanımlayın |
|
||||
| `definePreInstallLogicFunction` | Bir kurulum öncesi mantık işlevi tanımlayın (uygulama başına bir adet) |
|
||||
| `definePostInstallLogicFunction` | Bir kurulum sonrası mantık işlevi tanımlayın (uygulama başına bir adet) |
|
||||
| `defineFrontComponent` | Özel kullanıcı arayüzü için ön uç bileşenlerini tanımlayın |
|
||||
| `defineRole` | Rol izinlerini ve nesne erişimini yapılandırın |
|
||||
| `defineView` | Nesneler için kaydedilmiş görünümler tanımlayın |
|
||||
| `defineNavigationMenuItem` | Kenar çubuğu gezinme bağlantılarını tanımlayın |
|
||||
| `defineSkill` | Yapay zekâ ajanı yeteneklerini tanımlayın |
|
||||
| `defineAgent` | Yapay zekâ ajanlarını tanımlayın. |
|
||||
| `definePageLayout` | Özel sayfa düzenlerini tanımlayın. |
|
||||
|
||||
Bu fonksiyonlar, derleme zamanında yapılandırmanızı doğrular ve IDE otomatik tamamlama ile tür güvenliği sağlar.
|
||||
|
||||
@@ -112,7 +112,7 @@ export default defineObject({
|
||||
* `universalIdentifier` dağıtımlar arasında benzersiz ve kararlı olmalıdır.
|
||||
* Her alan bir `name`, `type`, `label` ve kendi kararlı `universalIdentifier` değerini gerektirir.
|
||||
* `fields` dizisi isteğe bağlıdır — özel alanlar olmadan da nesneler tanımlayabilirsiniz.
|
||||
* You can scaffold new objects using `yarn twenty add`, which guides you through naming, fields, and relationships.
|
||||
* `yarn twenty add` kullanarak, adlandırma, alanlar ve ilişkiler konusunda sizi yönlendirerek yeni nesneler oluşturabilirsiniz.
|
||||
|
||||
<Note>
|
||||
**Temel alanlar otomatik olarak oluşturulur.** Özel bir nesne tanımladığınızda Twenty, standart alanları otomatik olarak ekler
|
||||
@@ -124,7 +124,7 @@ ancak bu önerilmez.
|
||||
|
||||
### Mevcut nesneler üzerinde alanları tanımlama
|
||||
|
||||
Use `defineField()` to add fields to objects you don't own — such as standard Twenty objects (Person, Company, etc.) or objects from other apps. Unlike inline fields in `defineObject()`, standalone fields require an `objectUniversalIdentifier` to specify which object they extend:
|
||||
Sahibi olmadığınız nesnelere alan eklemek için `defineField()` kullanın — standart Twenty nesneleri (Person, Company, vb.) gibi. veya diğer uygulamalardaki nesneler. `defineObject()` içindeki satır içi alanların aksine, bağımsız alanlar hangi nesneyi genişlettiklerini belirtmek için bir `objectUniversalIdentifier` gerektirir:
|
||||
|
||||
```typescript
|
||||
// src/fields/company-loyalty-tier.field.ts
|
||||
@@ -147,35 +147,35 @@ export default defineField({
|
||||
|
||||
Önemli noktalar:
|
||||
|
||||
* `objectUniversalIdentifier` identifies the target object. For standard objects, use `STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS` exported from `twenty-sdk`.
|
||||
* When defining fields inline in `defineObject()`, you do **not** need `objectUniversalIdentifier` — it's inherited from the parent object.
|
||||
* `defineField()` is the only way to add fields to objects you didn't create with `defineObject()`.
|
||||
* `objectUniversalIdentifier` hedef nesneyi tanımlar. Standart nesneler için, `twenty-sdk`'den dışa aktarılan `STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS`'ı kullanın.
|
||||
* Alanları `defineObject()` içinde satır içi tanımlarken, `objectUniversalIdentifier`'a ihtiyacınız yoktur — üst nesneden devralınır.
|
||||
* `defineField()`, `defineObject()` ile oluşturmadığınız nesnelere alan eklemenin tek yoludur.
|
||||
|
||||
### İlişkiler
|
||||
|
||||
Relations connect objects together. In Twenty, relations are always **bidirectional** — you define both sides, and each side references the other.
|
||||
İlişkiler nesneleri birbirine bağlar. Twenty'de ilişkiler her zaman **çift yönlüdür** — her iki tarafı da tanımlarsınız ve her taraf diğerine başvurur.
|
||||
|
||||
There are two relation types:
|
||||
İki ilişki türü vardır:
|
||||
|
||||
| İlişki türü | Açıklama | Has foreign key? |
|
||||
| ------------- | ------------------------------------------------------------- | ---------------------- |
|
||||
| `MANY_TO_ONE` | Many records of this object point to one record of the target | Yes (`joinColumnName`) |
|
||||
| `ONE_TO_MANY` | One record of this object has many records of the target | No (inverse side) |
|
||||
| İlişki türü | Açıklama | Yabancı anahtar var mı? |
|
||||
| ------------- | --------------------------------------------------------- | ----------------------- |
|
||||
| `MANY_TO_ONE` | Bu nesnenin birçok kaydı, hedefin bir kaydını işaret eder | Evet (`joinColumnName`) |
|
||||
| `ONE_TO_MANY` | Bu nesnenin bir kaydı, hedefin birçok kaydına sahiptir | Hayır (ters taraf) |
|
||||
|
||||
#### How relations work
|
||||
#### İlişkiler nasıl çalışır
|
||||
|
||||
Every relation requires **two fields** that reference each other:
|
||||
Her ilişki, birbirine referans veren iki alan gerektirir:
|
||||
|
||||
1. The **MANY_TO_ONE** side — lives on the object that holds the foreign key
|
||||
2. The **ONE_TO_MANY** side — lives on the object that owns the collection
|
||||
1. **MANY_TO_ONE** tarafı — yabancı anahtarı tutan nesne üzerinde bulunur
|
||||
2. **ONE_TO_MANY** tarafı — koleksiyona sahip olan nesne üzerinde bulunur
|
||||
|
||||
Both fields use `FieldType.RELATION` and cross-reference each other via `relationTargetFieldMetadataUniversalIdentifier`.
|
||||
Her iki alan da `FieldType.RELATION` kullanır ve `relationTargetFieldMetadataUniversalIdentifier` aracılığıyla birbirine karşılıklı referans verir.
|
||||
|
||||
#### Example: Post Card has many Recipients
|
||||
#### Örnek: Posta Kartı'nın birçok Alıcısı vardır
|
||||
|
||||
Suppose a `PostCard` can be sent to many `PostCardRecipient` records. Each recipient belongs to exactly one post card.
|
||||
Bir `PostCard`'ın birçok `PostCardRecipient` kaydına gönderilebildiğini varsayalım. Her alıcı tam olarak bir posta kartına aittir.
|
||||
|
||||
**Step 1: Define the ONE_TO_MANY side on PostCard** (the "one" side):
|
||||
**Adım 1: PostCard üzerinde ONE_TO_MANY tarafını tanımlayın** ("bir" taraf):
|
||||
|
||||
```typescript
|
||||
// src/fields/post-card-recipients-on-post-card.field.ts
|
||||
@@ -203,7 +203,7 @@ export default defineField({
|
||||
});
|
||||
```
|
||||
|
||||
**Step 2: Define the MANY_TO_ONE side on PostCardRecipient** (the "many" side — holds the foreign key):
|
||||
**Adım 2: PostCardRecipient üzerinde MANY_TO_ONE tarafını tanımlayın** ("çok" taraf — yabancı anahtarı tutar):
|
||||
|
||||
```typescript
|
||||
// src/fields/post-card-on-post-card-recipient.field.ts
|
||||
@@ -234,12 +234,12 @@ export default defineField({
|
||||
```
|
||||
|
||||
<Note>
|
||||
**Circular imports:** Both relation fields reference each other's `universalIdentifier`. To avoid circular import issues, export your field IDs as named constants from each file, and import them in the other file. The build system resolves these at compile time.
|
||||
**Döngüsel içe aktarmalar:** Her iki ilişki alanı da birbirlerinin `universalIdentifier` değerine referans verir. Döngüsel içe aktarma sorunlarından kaçınmak için, alan kimliklerinizi her dosyadan adlandırılmış sabitler olarak dışa aktarın ve diğer dosyada içe aktarın. Derleme sistemi bunları derleme zamanında çözer.
|
||||
</Note>
|
||||
|
||||
#### Relating to standard objects
|
||||
#### Standart nesnelerle ilişkilendirme
|
||||
|
||||
To create a relation with a built-in Twenty object (Person, Company, etc.), use `STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS`:
|
||||
Yerleşik bir Twenty nesnesiyle (Person, Company, vb.) ilişki oluşturmak için `STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS` kullanın:
|
||||
|
||||
```typescript
|
||||
// src/fields/person-on-self-hosting-user.field.ts
|
||||
@@ -274,20 +274,20 @@ export default defineField({
|
||||
});
|
||||
```
|
||||
|
||||
#### Relation field properties
|
||||
#### İlişki alanı özellikleri
|
||||
|
||||
| Özellik | Zorunlu | Açıklama |
|
||||
| ------------------------------------------------- | ---------------- | ----------------------------------------------------------------------------------------------------- |
|
||||
| `type` | Evet | Must be `FieldType.RELATION` |
|
||||
| `relationTargetObjectMetadataUniversalIdentifier` | Evet | The `universalIdentifier` of the target object |
|
||||
| `relationTargetFieldMetadataUniversalIdentifier` | Evet | The `universalIdentifier` of the matching field on the target object |
|
||||
| `universalSettings.relationType` | Evet | `RelationType.MANY_TO_ONE` or `RelationType.ONE_TO_MANY` |
|
||||
| `universalSettings.onDelete` | MANY_TO_ONE only | What happens when the referenced record is deleted: `CASCADE`, `SET_NULL`, `RESTRICT`, or `NO_ACTION` |
|
||||
| `universalSettings.joinColumnName` | MANY_TO_ONE only | Database column name for the foreign key (e.g., `postCardId`) |
|
||||
| Özellik | Zorunlu | Açıklama |
|
||||
| ------------------------------------------------- | -------------------- | -------------------------------------------------------------------------------------------- |
|
||||
| `type` | Evet | `FieldType.RELATION` olmalıdır |
|
||||
| `relationTargetObjectMetadataUniversalIdentifier` | Evet | Hedef nesnenin `universalIdentifier` değeri |
|
||||
| `relationTargetFieldMetadataUniversalIdentifier` | Evet | Hedef nesnedeki eşleşen alanın `universalIdentifier` değeri |
|
||||
| `universalSettings.relationType` | Evet | `RelationType.MANY_TO_ONE` veya `RelationType.ONE_TO_MANY` |
|
||||
| `universalSettings.onDelete` | Yalnızca MANY_TO_ONE | Başvurulan kayıt silindiğinde ne olacağı: `CASCADE`, `SET_NULL`, `RESTRICT` veya `NO_ACTION` |
|
||||
| `universalSettings.joinColumnName` | Yalnızca MANY_TO_ONE | Yabancı anahtar için veritabanı sütun adı (örn. `postCardId`) |
|
||||
|
||||
#### Inline relation fields in defineObject
|
||||
#### defineObject içinde satır içi ilişki alanları
|
||||
|
||||
You can also define relation fields directly inside `defineObject()`. In that case, omit `objectUniversalIdentifier` — it's inherited from the parent object:
|
||||
İlişki alanlarını doğrudan `defineObject()` içinde de tanımlayabilirsiniz. Bu durumda, `objectUniversalIdentifier`'ı atlayın — üst nesneden devralınır:
|
||||
|
||||
```typescript
|
||||
export default defineObject({
|
||||
@@ -354,21 +354,21 @@ Notlar:
|
||||
* `defaultRoleUniversalIdentifier`, rol dosyasıyla eşleşmelidir (aşağıya bakın).
|
||||
* Kurulum öncesi ve kurulum sonrası işlevler, manifest oluşturma sırasında otomatik olarak algılanır. Bkz. [Kurulum öncesi işlevler](#pre-install-functions) ve [Kurulum sonrası işlevler](#post-install-functions).
|
||||
|
||||
#### Marketplace metadata
|
||||
#### Pazaryeri meta verileri
|
||||
|
||||
If you plan to [publish your app](/l/tr/developers/extend/apps/publishing), these optional fields control how your app appears in the marketplace:
|
||||
Eğer [uygulamanızı yayımlamayı](/l/tr/developers/extend/apps/publishing) planlıyorsanız, bu isteğe bağlı alanlar uygulamanızın pazaryerinde nasıl görüneceğini kontrol eder:
|
||||
|
||||
| Alan | Açıklama |
|
||||
| ------------------ | --------------------------------------------------- |
|
||||
| `author` | Author or company name |
|
||||
| `category` | App category for marketplace filtering |
|
||||
| `logoUrl` | Path to your app logo (relative to `./assets/`) |
|
||||
| `screenshots` | Array of screenshot paths (relative to `./assets/`) |
|
||||
| `aboutDescription` | Longer markdown description for the "About" tab |
|
||||
| `websiteUrl` | Link to your website |
|
||||
| `termsUrl` | Link to terms of service |
|
||||
| `emailSupport` | Support email address |
|
||||
| `issueReportUrl` | Link to issue tracker |
|
||||
| Alan | Açıklama |
|
||||
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `author` | Yazar veya şirket adı |
|
||||
| `category` | Pazaryerinde filtreleme için uygulama kategorisi |
|
||||
| `logoUrl` | Uygulama logonuzun yolu (`./assets/` dizinine göre) |
|
||||
| `screenshots` | Ekran görüntüsü yollarının dizisi (`./assets/` dizinine göre) |
|
||||
| `aboutDescription` | "Hakkında" sekmesi için daha uzun bir markdown açıklaması. Belirtilmezse, pazaryeri npm'deki paketin `README.md` dosyasını kullanır |
|
||||
| `websiteUrl` | Web sitenize bağlantı |
|
||||
| `termsUrl` | Hizmet Koşulları'na bağlantı |
|
||||
| `emailSupport` | Destek e-posta adresi |
|
||||
| `issueReportUrl` | Sorun izleyicisine bağlantı |
|
||||
|
||||
#### Roller ve izinler
|
||||
|
||||
@@ -376,7 +376,7 @@ Uygulamalar, çalışma alanınızdaki nesneler ve eylemler üzerindeki izinleri
|
||||
|
||||
* `TWENTY_API_KEY` olarak enjekte edilen çalışma zamanı API anahtarı bu varsayılan fonksiyon rolünden türetilir.
|
||||
* Türlendirilmiş istemci, o role tanınan izinlerle sınırlandırılır.
|
||||
* Follow least-privilege: create a dedicated role with only the permissions your functions need, then reference its universal identifier.
|
||||
* En az ayrıcalık ilkesini izleyin: Yalnızca fonksiyonlarınızın ihtiyaç duyduğu izinlere sahip özel bir rol oluşturun ve ardından evrensel tanımlayıcısına referans verin.
|
||||
|
||||
##### Varsayılan fonksiyon rolü (*.role.ts)
|
||||
|
||||
@@ -429,7 +429,7 @@ Bu rolün `universalIdentifier` değeri daha sonra `application-config.ts` için
|
||||
|
||||
Notlar:
|
||||
|
||||
* Start from the scaffolded role, then progressively restrict it following least-privilege.
|
||||
* Oluşturulan rolden başlayın ve en az ayrıcalık ilkesini izleyerek bunu aşamalı olarak kısıtlayın.
|
||||
* `objectPermissions` ve `fieldPermissions` değerlerini, fonksiyonlarınızın ihtiyaç duyduğu nesneler/alanlarla değiştirin.
|
||||
* `permissionFlags`, platform düzeyindeki yeteneklere erişimi kontrol eder. Minimumda tutun; yalnızca ihtiyacınız olanları ekleyin.
|
||||
* Çalışan bir örneği Hello World uygulamasında görün: [`packages/twenty-apps/hello-world/src/roles/function-role.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-apps/hello-world/src/roles/function-role.ts).
|
||||
@@ -543,7 +543,7 @@ yarn twenty exec --preInstall
|
||||
* Uygulama başına yalnızca bir kurulum öncesi işlevine izin verilir. Birden fazla tespit edilirse manifest oluşturma hataya düşer.
|
||||
* İşlevin `universalIdentifier` değeri, oluşturma sırasında uygulama manifestinde otomatik olarak `preInstallLogicFunctionUniversalIdentifier` olarak ayarlanır — `defineApplication()` içinde buna atıfta bulunmanıza gerek yoktur.
|
||||
* Varsayılan zaman aşımı, daha uzun hazırlık görevlerine izin vermek için 300 saniye (5 dakika) olarak ayarlanmıştır.
|
||||
* Pre-install functions do not need triggers — they are invoked by the platform before installation or manually via `exec --preInstall`.
|
||||
* Kurulum öncesi işlevlerin tetikleyicilere ihtiyacı yoktur — kurulumdan önce platform tarafından veya `exec --preInstall` aracılığıyla manuel olarak çağrılırlar.
|
||||
|
||||
### Kurulum sonrası işlevler
|
||||
|
||||
@@ -581,7 +581,7 @@ yarn twenty exec --postInstall
|
||||
* Uygulama başına yalnızca bir kurulum sonrası işlevine izin verilir. Birden fazla tespit edilirse manifest oluşturma hataya düşer.
|
||||
* İşlevin `universalIdentifier` değeri, oluşturma sırasında uygulama manifestinde otomatik olarak `postInstallLogicFunctionUniversalIdentifier` olarak ayarlanır — `defineApplication()` içinde buna atıfta bulunmanıza gerek yoktur.
|
||||
* Varsayılan zaman aşımı, veri tohumlama gibi daha uzun kurulum görevlerine izin vermek için 300 saniye (5 dakika) olarak ayarlanmıştır.
|
||||
* Post-install functions do not need triggers — they are invoked by the platform during installation or manually via `exec --postInstall`.
|
||||
* Kurulum sonrası işlevlerin tetikleyicilere ihtiyacı yoktur — kurulum sırasında platform tarafından veya `exec --postInstall` aracılığıyla manuel olarak çağrılırlar.
|
||||
|
||||
### Rota tetikleyicisi yükü
|
||||
|
||||
@@ -625,15 +625,15 @@ const handler = async (event: RoutePayload) => {
|
||||
|
||||
`RoutePayload` türünün yapısı şu şekildedir:
|
||||
|
||||
| Özellik | Tür | Açıklama |
|
||||
| ---------------------------- | ------------------------------------- | ---------------------------------------------------------------------------------------- |
|
||||
| `headers` | `Record<string, string \| undefined>` | HTTP başlıkları (`forwardedRequestHeaders` içinde listelenenlerle sınırlı) |
|
||||
| `queryStringParameters` | `Record<string, string \| undefined>` | Sorgu dizesi parametreleri (birden çok değer virgülle birleştirilir) |
|
||||
| `pathParameters` | `Record<string, string \| undefined>` | Path parameters extracted from the route pattern (e.g., `/users/:id` -> `{ id: '123' }`) |
|
||||
| `body` | `object \| null` | Ayrıştırılmış istek gövdesi (JSON) |
|
||||
| `isBase64Encoded` | `boolean` | Gövdenin base64 ile kodlanıp kodlanmadığı |
|
||||
| `requestContext.http.method` | `string` | HTTP yöntemi (GET, POST, PUT, PATCH, DELETE) |
|
||||
| `requestContext.http.path` | `string` | Ham istek yolu |
|
||||
| Özellik | Tür | Açıklama |
|
||||
| ---------------------------- | ------------------------------------- | ----------------------------------------------------------------------------------- |
|
||||
| `headers` | `Record<string, string \| undefined>` | HTTP başlıkları (`forwardedRequestHeaders` içinde listelenenlerle sınırlı) |
|
||||
| `queryStringParameters` | `Record<string, string \| undefined>` | Sorgu dizesi parametreleri (birden çok değer virgülle birleştirilir) |
|
||||
| `pathParameters` | `Record<string, string \| undefined>` | Rota deseninden çıkarılan yol parametreleri (örn., `/users/:id` -> `{ id: '123' }`) |
|
||||
| `body` | `object \| null` | Ayrıştırılmış istek gövdesi (JSON) |
|
||||
| `isBase64Encoded` | `boolean` | Gövdenin base64 ile kodlanıp kodlanmadığı |
|
||||
| `requestContext.http.method` | `string` | HTTP yöntemi (GET, POST, PUT, PATCH, DELETE) |
|
||||
| `requestContext.http.path` | `string` | Ham istek yolu |
|
||||
|
||||
### HTTP başlıklarını iletme
|
||||
|
||||
@@ -675,7 +675,7 @@ const handler = async (event: RoutePayload) => {
|
||||
|
||||
Yeni fonksiyonları iki şekilde oluşturabilirsiniz:
|
||||
|
||||
* **Scaffolded**: Run `yarn twenty add` and choose the option to add a new logic function. Bu, bir işleyici ve yapılandırma içeren bir başlangıç dosyası oluşturur.
|
||||
* **Şablondan**: `yarn twenty add` çalıştırın ve yeni bir mantık fonksiyonu ekleme seçeneğini seçin. Bu, bir işleyici ve yapılandırma içeren bir başlangıç dosyası oluşturur.
|
||||
* **Manuel**: Yeni bir `*.logic-function.ts` dosyası oluşturun ve aynı deseni izleyerek `defineLogicFunction()` kullanın.
|
||||
|
||||
### Bir mantık işlevini araç olarak işaretleme
|
||||
@@ -776,7 +776,7 @@ export default defineFrontComponent({
|
||||
|
||||
Yeni ön uç bileşenlerini iki şekilde oluşturabilirsiniz:
|
||||
|
||||
* **Scaffolded**: Run `yarn twenty add` and choose the option to add a new front component.
|
||||
* **Şablondan**: `yarn twenty add` çalıştırın ve yeni bir ön uç bileşeni ekleme seçeneğini seçin.
|
||||
* **Manuel**: Aynı deseni izleyerek yeni bir `.tsx` dosyası oluşturun ve `defineFrontComponent()` kullanın.
|
||||
|
||||
### Beceriler
|
||||
@@ -811,21 +811,21 @@ export default defineSkill({
|
||||
|
||||
Yeni yetenekleri iki şekilde oluşturabilirsiniz:
|
||||
|
||||
* **Scaffolded**: Run `yarn twenty add` and choose the option to add a new skill.
|
||||
* **Şablondan**: `yarn twenty add` çalıştırın ve yeni bir yetenek ekleme seçeneğini seçin.
|
||||
* **Manuel**: Yeni bir dosya oluşturun ve aynı deseni izleyerek `defineSkill()` kullanın.
|
||||
|
||||
### Typed API clients (`twenty-client-sdk`)
|
||||
### Tipli API istemcileri (`twenty-client-sdk`)
|
||||
|
||||
The `twenty-client-sdk` package provides two typed GraphQL clients for interacting with the Twenty API from your logic functions and front components:
|
||||
`twenty-client-sdk` paketi, mantık fonksiyonlarınızdan ve ön uç bileşenlerinizden Twenty API ile etkileşim kurmak için iki tipli GraphQL istemcisi sağlar:
|
||||
|
||||
| İstemci | İçe Aktar | Endpoint | Generated? |
|
||||
| ------------------- | ---------------------------- | ---------------------------------------------- | ---------------------- |
|
||||
| `CoreApiClient` | `twenty-client-sdk/core` | `/graphql` — workspace data (records, objects) | Yes, at dev/build time |
|
||||
| `MetadataApiClient` | `twenty-client-sdk/metadata` | `/metadata` — workspace config, file uploads | No, ships pre-built |
|
||||
| İstemci | İçe Aktar | Uç nokta | Oluşturuldu mu? |
|
||||
| ------------------- | ---------------------------- | ------------------------------------------------------------- | --------------------------------------- |
|
||||
| `CoreApiClient` | `twenty-client-sdk/core` | `/graphql` — çalışma alanı verileri (kayıtlar, nesneler) | Evet, geliştirme/derleme zamanında |
|
||||
| `MetadataApiClient` | `twenty-client-sdk/metadata` | `/metadata` — çalışma alanı yapılandırması, dosya yüklemeleri | Hayır, önceden hazırlanmış olarak gelir |
|
||||
|
||||
#### CoreApiClient
|
||||
|
||||
`CoreApiClient` is the main client for querying and mutating workspace data. It is **generated from your workspace schema** during `yarn twenty dev` or `yarn twenty build`, so it's fully typed to match your objects and fields.
|
||||
`CoreApiClient`, çalışma alanı verilerini sorgulamak ve değiştirmek için ana istemcidir. `yarn twenty dev` veya `yarn twenty build` sırasında çalışma alanı şemanızdan oluşturulur; bu nedenle nesnelerinize ve alanlarınıza uyacak şekilde tamamen tiplendirilmiştir.
|
||||
|
||||
```typescript
|
||||
import { CoreApiClient } from 'twenty-client-sdk/core';
|
||||
@@ -859,15 +859,15 @@ const { createCompany } = await client.mutation({
|
||||
});
|
||||
```
|
||||
|
||||
The client uses a selection-set syntax: pass `true` to include a field, use `__args` for arguments, and nest objects for relations. You get full autocompletion and type checking based on your workspace schema.
|
||||
İstemci bir seçim kümesi sözdizimi kullanır: Bir alanı dahil etmek için `true` geçin, bağımsız değişkenler için `__args` kullanın ve ilişkiler için nesneleri iç içe yerleştirin. Çalışma alanı şemanıza göre tam otomatik tamamlama ve tip denetimi elde edersiniz.
|
||||
|
||||
<Note>
|
||||
**CoreApiClient is generated at dev/build time.** If you try to use it without running `yarn twenty dev` or `yarn twenty build` first, it throws an error. The generation happens automatically — the CLI introspects your workspace's GraphQL schema, generates a typed client using `@genql/cli`, writes the generated sources to `node_modules/twenty-client-sdk/dist/core/generated/`, and replaces the stubs in `node_modules/twenty-client-sdk/dist/core.mjs` and `node_modules/twenty-client-sdk/dist/core.cjs`.
|
||||
**CoreApiClient geliştirme/derleme zamanında oluşturulur.** Bunu önce `yarn twenty dev` veya `yarn twenty build` çalıştırmadan kullanmaya çalışırsanız, hata verir. Oluşturma otomatik olarak gerçekleşir — CLI, çalışma alanınızın GraphQL şemasını inceler, `@genql/cli` kullanarak tipli bir istemci üretir, üretilen kaynakları `node_modules/twenty-client-sdk/dist/core/generated/` dizinine yazar ve `node_modules/twenty-client-sdk/dist/core.mjs` ile `node_modules/twenty-client-sdk/dist/core.cjs` içindeki taslakları değiştirir.
|
||||
</Note>
|
||||
|
||||
#### Using CoreSchema for type annotations
|
||||
#### Tür açıklamaları için CoreSchema'yı kullanma
|
||||
|
||||
`CoreSchema` provides TypeScript types matching your workspace objects, useful for typing component state or function parameters:
|
||||
`CoreSchema`, çalışma alanı nesnelerinize uyan TypeScript türleri sağlar; bileşen durumunu veya işlev parametrelerini tiplemek için kullanışlıdır:
|
||||
|
||||
```typescript
|
||||
import { CoreApiClient, CoreSchema } from 'twenty-client-sdk/core';
|
||||
@@ -890,7 +890,7 @@ setCompany(result.company);
|
||||
|
||||
#### MetadataApiClient
|
||||
|
||||
`MetadataApiClient` ships pre-built with the SDK (no generation required). It queries the `/metadata` endpoint for workspace configuration, applications, and file uploads:
|
||||
`MetadataApiClient`, SDK ile birlikte önceden hazırlanmış olarak gelir (oluşturma gerektirmez). Çalışma alanı yapılandırması, uygulamalar ve dosya yüklemeleri için `/metadata` uç noktasını sorgular:
|
||||
|
||||
```typescript
|
||||
import { MetadataApiClient } from 'twenty-client-sdk/metadata';
|
||||
@@ -912,18 +912,18 @@ const { findManyApplications } = await metadataClient.query({
|
||||
});
|
||||
```
|
||||
|
||||
#### Runtime credentials
|
||||
#### Çalışma zamanı kimlik bilgileri
|
||||
|
||||
When your code runs on Twenty (logic functions or front components), the platform injects credentials as environment variables:
|
||||
Kodunuz Twenty üzerinde çalıştığında (mantık işlevleri veya ön uç bileşenleri), platform kimlik bilgilerini ortam değişkenleri olarak enjekte eder:
|
||||
|
||||
* `TWENTY_API_URL` — Base URL of the Twenty API
|
||||
* `TWENTY_API_KEY` — Short-lived key scoped to your application's default function role
|
||||
* `TWENTY_API_URL` — Twenty API'nin temel URL'si
|
||||
* `TWENTY_API_KEY` — Uygulamanızın varsayılan fonksiyon rolü kapsamına sahip kısa ömürlü anahtar
|
||||
|
||||
You do **not** need to pass these to the clients — they read from `process.env` automatically. The API key's permissions are determined by the role referenced in `defaultRoleUniversalIdentifier` in your `application-config.ts`.
|
||||
Bunları istemcilere iletmeniz gerekmez — otomatik olarak `process.env`'den okurlar. API anahtarının izinleri, `application-config.ts` içinde `defaultRoleUniversalIdentifier` ile referans verilen role göre belirlenir.
|
||||
|
||||
#### Dosya yükleme
|
||||
|
||||
`MetadataApiClient` includes an `uploadFile` method for attaching files to file-type fields. It implements the [GraphQL multipart request specification](https://github.com/jaydenseric/graphql-multipart-request-spec):
|
||||
`MetadataApiClient`, dosya türü alanlara dosya eklemek için bir `uploadFile` yöntemi içerir. [GraphQL çok parçalı istek spesifikasyonunu](https://github.com/jaydenseric/graphql-multipart-request-spec) uygular:
|
||||
|
||||
```typescript
|
||||
import { MetadataApiClient } from 'twenty-client-sdk/metadata';
|
||||
@@ -953,7 +953,7 @@ console.log(uploadedFile);
|
||||
|
||||
Önemli noktalar:
|
||||
|
||||
* Uses the field's `universalIdentifier` (not its workspace-specific ID), so your upload code works across any workspace where your app is installed.
|
||||
* Alan için `universalIdentifier` kullanır (çalışma alanına özgü kimliği değil), böylece yükleme kodunuz uygulamanızın yüklü olduğu herhangi bir çalışma alanında çalışır.
|
||||
* Döndürülen `url`, yüklenen dosyaya erişmek için kullanabileceğiniz imzalı bir URL'dir.
|
||||
|
||||
### Hello World örneği
|
||||
|
||||
@@ -9,18 +9,19 @@ Uygulamalar şu anda alfa testinde. Özellik işlevsel ancak hâlâ gelişmekte.
|
||||
|
||||
Uygulamalar, Twenty'yi özel nesneler, alanlar, mantık işlevleri, Yapay Zeka yetenekleri ve UI bileşenleriyle genişletmenizi sağlar — tümü kod olarak yönetilir.
|
||||
|
||||
**Bugün Yapabilecekleriniz:**
|
||||
**Oluşturabilecekleriniz:**
|
||||
|
||||
* Özel nesneleri ve alanları kod olarak tanımlayın (yönetilen veri modeli)
|
||||
* Özel tetikleyicilerle mantık işlevleri oluşturun (HTTP routes, cron, database events)
|
||||
* Yapay zekâ ajanları için becerileri tanımlayın
|
||||
* Twenty'nin UI'si içinde görüntülenen ön bileşenler oluşturun
|
||||
* Aynı uygulamayı birden çok çalışma alanına dağıtın
|
||||
* Veri modelinizi şekillendirmek için özel nesneler, alanlar, görünümler ve gezinti öğeleri
|
||||
* HTTP rotaları, cron zamanlamaları veya veritabanı olayları tarafından tetiklenen mantık işlevleri
|
||||
* Twenty'nin UI'si içinde doğrudan görüntülenen ön uç bileşenleri
|
||||
* Twenty'nin yapay zeka ajanlarını genişleten beceriler
|
||||
* Bir uygulamayı birden çok çalışma alanına dağıtın
|
||||
|
||||
## Ön Gereksinimler
|
||||
|
||||
* Node.js 24+ ve Yarn 4
|
||||
* Docker (yerel Twenty geliştirme sunucusu için)
|
||||
* Node.js 24+
|
||||
* Yarn 4
|
||||
* Docker (veya çalışan yerel bir Twenty örneği)
|
||||
|
||||
## Başlarken
|
||||
|
||||
@@ -29,21 +30,9 @@ Resmi iskelet oluşturucu aracını kullanarak yeni bir uygulama oluşturun, ard
|
||||
```bash filename="Terminal"
|
||||
# Scaffold a new app (includes all examples by default)
|
||||
npx create-twenty-app@latest my-twenty-app
|
||||
cd my-twenty-app
|
||||
|
||||
# Start dev mode: automatically syncs local changes to your workspace
|
||||
yarn twenty dev
|
||||
```
|
||||
|
||||
İskelet oluşturucu, hangi örnek dosyaların dahil edileceğini kontrol etmek için iki modu destekler:
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Default (exhaustive): all examples (object, field, logic function, front component, view, navigation menu item, skill, agent)
|
||||
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
|
||||
```
|
||||
> Minimal bir kurulum iskeleti oluşturmak için `--minimal` seçeneğini kullanın
|
||||
|
||||
Buradan şunları yapabilirsiniz:
|
||||
|
||||
@@ -123,7 +112,7 @@ my-twenty-app/
|
||||
Genel hatlarıyla:
|
||||
|
||||
* **package.json**: Uygulama adını, sürümünü, motorları (Node 24+, Yarn 4) bildirir ve `twenty-sdk` ile yerel `twenty` CLI'sine yetki devreden bir `twenty` betiği ekler. Tüm mevcut komutları listelemek için `yarn twenty help` komutunu çalıştırın.
|
||||
* **.gitignore**: Ignores common artifacts such as `node_modules`, `.yarn`, `.twenty/`, `dist/`, `build/`, coverage folders, log files, and `.env*` files.
|
||||
* **.gitignore**: `node_modules`, `.yarn`, `.twenty/`, `dist/`, `build/`, kapsam klasörleri, günlük dosyaları ve `.env*` dosyaları gibi yaygın artifaktları yok sayar.
|
||||
* **yarn.lock**, **.yarnrc.yml**, **.yarn/**: Proje tarafından kullanılan Yarn 4 araç zincirini kilitler ve yapılandırır.
|
||||
* **.nvmrc**: Projenin beklediği Node.js sürümünü sabitler.
|
||||
* **.oxlintrc.json** ve **tsconfig.json**: Uygulamanızın TypeScript kaynakları için linting ve TypeScript yapılandırması sağlar.
|
||||
@@ -167,8 +156,8 @@ export default defineObject({
|
||||
|
||||
İlerideki komutlar daha fazla dosya ve klasör ekleyecektir:
|
||||
|
||||
* `yarn twenty dev` will auto-generate the typed `CoreApiClient` (for workspace data via `/graphql`) into `node_modules/twenty-client-sdk/`. The `MetadataApiClient` (for workspace configuration and file uploads via `/metadata`) ships pre-built and is available immediately. Import them from `twenty-client-sdk/core` and `twenty-client-sdk/metadata` respectively.
|
||||
* `yarn twenty add` will add entity definition files under `src/` for your custom objects, functions, front components, roles, skills, and more.
|
||||
* `yarn twenty dev`, türlendirilmiş `CoreApiClient`'i (çalışma alanı verileri için `/graphql` aracılığıyla) `node_modules/twenty-client-sdk/` içine otomatik olarak oluşturur. `MetadataApiClient` (çalışma alanı yapılandırması ve dosya yüklemeleri için `/metadata` aracılığıyla) önceden derlenmiş olarak gelir ve hemen kullanılabilir. Bunları sırasıyla `twenty-client-sdk/core` ve `twenty-client-sdk/metadata` içinden içe aktarın.
|
||||
* `yarn twenty add`, özel nesneleriniz, fonksiyonlarınız, ön bileşenleriniz, rolleriniz, yetenekleriniz ve daha fazlası için `src/` altında varlık tanım dosyaları ekler.
|
||||
|
||||
## Kimlik Doğrulama
|
||||
|
||||
|
||||
@@ -24,9 +24,9 @@ Her iki yol da aynı **build** adımından başlar.
|
||||
yarn twenty build
|
||||
```
|
||||
|
||||
Çıktı `.twenty/output/` dizinine yazılır. This directory contains everything needed for distribution: compiled code, assets, the manifest, and a copy of your `package.json`.
|
||||
Çıktı `.twenty/output/` dizinine yazılır. Bu dizin, dağıtım için gereken her şeyi içerir: derlenmiş kod, varlıklar, manifest ve `package.json` dosyanızın bir kopyası.
|
||||
|
||||
To also create a `.tgz` tarball (used by the deploy command internally, or for manual distribution):
|
||||
Ayrıca bir `.tgz` tarball oluşturmak için (deploy komutu tarafından dahili olarak kullanılır veya el ile dağıtım için):
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty build --tarball
|
||||
@@ -39,11 +39,11 @@ npm’ye yayımlamak, uygulamanızın Twenty pazaryerinde keşfedilebilir olmas
|
||||
### Gereksinimler
|
||||
|
||||
* Bir [npm](https://www.npmjs.com) hesabı
|
||||
* The `twenty-app` keyword **must** be listed in your `package.json` `keywords` array
|
||||
* `twenty-app` anahtar kelimesi `package.json` dosyanızdaki `keywords` dizisinde **mutlaka** listelenmelidir
|
||||
|
||||
### Adding the required keyword
|
||||
### Gerekli anahtar kelimeyi ekleme
|
||||
|
||||
The Twenty marketplace discovers apps by searching the npm registry for packages with the `twenty-app` keyword. Add it to your `package.json`:
|
||||
Twenty pazar yeri, npm kayıt defterinde `twenty-app` anahtar kelimesine sahip paketleri arayarak uygulamaları keşfeder. Bunu `package.json` dosyanıza ekleyin:
|
||||
|
||||
```json filename="package.json"
|
||||
{
|
||||
@@ -55,52 +55,56 @@ The Twenty marketplace discovers apps by searching the npm registry for packages
|
||||
```
|
||||
|
||||
<Note>
|
||||
The marketplace searches for `keywords:twenty-app` on the npm registry. Without this keyword, your package won't appear in the marketplace even if it has the `twenty-app-` name prefix.
|
||||
Pazar yeri, npm kayıt defterinde `keywords:twenty-app` araması yapar. Bu anahtar kelime olmadan, adında `twenty-app-` öneki bulunsa bile paketiniz pazar yerinde görünmez.
|
||||
</Note>
|
||||
|
||||
### Adımlar
|
||||
|
||||
1. **Build your app:**
|
||||
1. **Uygulamanızı derleyin:**
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty build
|
||||
```
|
||||
|
||||
2. **Publish to npm:**
|
||||
2. **npm’ye yayımlayın:**
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty publish
|
||||
```
|
||||
|
||||
This runs `npm publish` from the `.twenty/output/` directory.
|
||||
Bu, `.twenty/output/` dizininden `npm publish` komutunu çalıştırır.
|
||||
|
||||
To publish under a specific dist-tag (e.g., `beta` or `next`):
|
||||
Belirli bir dist-tag altında yayımlamak için (ör. `beta` veya `next`):
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty publish --tag beta
|
||||
```
|
||||
|
||||
### How marketplace discovery works
|
||||
### Pazar yerinde keşif nasıl çalışır
|
||||
|
||||
The Twenty server syncs its marketplace catalog from the npm registry **every hour**:
|
||||
Twenty sunucusu pazar yeri kataloğunu npm kayıt defterinden **her saat** eşitler:
|
||||
|
||||
1. It searches for all npm packages with the `keywords:twenty-app` keyword
|
||||
2. For each package, it fetches the `manifest.json` from the npm CDN
|
||||
3. The app's metadata (name, description, author, logo, screenshots, category) is extracted from the manifest and displayed in the marketplace
|
||||
1. `keywords:twenty-app` anahtar kelimesine sahip tüm npm paketlerini arar
|
||||
2. Her paket için `manifest.json` dosyasını npm CDN’inden getirir
|
||||
3. Uygulamanın meta verileri (ad, açıklama, yazar, logo, ekran görüntüleri, kategori) manifest dosyasından çıkarılır ve pazar yerinde görüntülenir
|
||||
|
||||
After publishing, your app can take up to one hour to appear in the marketplace. To trigger the sync immediately instead of waiting for the next hourly run:
|
||||
Yayımladıktan sonra, uygulamanızın pazar yerinde görünmesi bir saate kadar sürebilir. Bir sonraki saatlik çalışmayı beklemek yerine eşitlemeyi hemen tetiklemek için:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty catalog-sync
|
||||
```
|
||||
|
||||
To target a specific remote:
|
||||
Belirli bir remote’u hedeflemek için:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty catalog-sync -r production
|
||||
```
|
||||
|
||||
The metadata shown in the marketplace comes from your `defineApplication()` call in your app source code — fields like `displayName`, `description`, `author`, `category`, `logoUrl`, `screenshots`, `aboutDescription`, `websiteUrl`, and `termsUrl`.
|
||||
Pazar yerinde gösterilen meta veriler, uygulamanızın kaynak kodundaki `defineApplication()` çağrısından gelir — `displayName`, `description`, `author`, `category`, `logoUrl`, `screenshots`, `aboutDescription`, `websiteUrl` ve `termsUrl` gibi alanlar.
|
||||
|
||||
<Note>
|
||||
Uygulamanız `defineApplication()` içinde bir `aboutDescription` tanımlamıyorsa, pazaryeri, hakkında sayfasının içeriği olarak paketinizin npm'deki `README.md` dosyasını otomatik olarak kullanır. Bu, hem npm hem de Twenty pazaryeri için tek bir README dosyası kullanabileceğiniz anlamına gelir. Pazaryerinde farklı bir açıklama istiyorsanız, `aboutDescription` değerini açıkça ayarlayın.
|
||||
</Note>
|
||||
|
||||
### CI üzerinden yayımlama
|
||||
|
||||
@@ -133,39 +137,39 @@ jobs:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
```
|
||||
|
||||
For other CI systems (GitLab CI, CircleCI, etc.), the same three commands apply: `yarn install`, `yarn twenty build`, then `npm publish` from `.twenty/output`.
|
||||
Diğer CI sistemleri (GitLab CI, CircleCI, vb.) için de aynı üç komut geçerlidir: `yarn install`, `yarn twenty build` ve ardından `.twenty/output` dizininden `npm publish`.
|
||||
|
||||
<Tip>
|
||||
**npm provenance** isteğe bağlıdır ancak önerilir. `--provenance` ile yayımlamak, npm listenize bir güven rozeti ekler ve kullanıcıların paketin herkese açık bir CI ardışık düzenindeki belirli bir commit’ten oluşturulduğunu doğrulamasını sağlar. Kurulum talimatları için [npm provenance belgelerine](https://docs.npmjs.com/generating-provenance-statements) bakın.
|
||||
</Tip>
|
||||
|
||||
## Deploying to a server (tarball)
|
||||
## Sunucuya dağıtım (tarball)
|
||||
|
||||
For apps you don't want publicly available — proprietary tools, enterprise-only integrations, or experimental builds — you can deploy a tarball directly to a Twenty server.
|
||||
Genel kullanıma açık olmasını istemediğiniz uygulamalar — sahipli araçlar, yalnızca kurumsal entegrasyonlar veya deneysel derlemeler — için bir tarball’ı doğrudan bir Twenty sunucusuna dağıtabilirsiniz.
|
||||
|
||||
### Ön Gereksinimler
|
||||
|
||||
Before deploying, you need a configured remote pointing to the target server. Remotes store the server URL and authentication credentials locally in `~/.twenty/config.json`.
|
||||
Dağıtmadan önce, hedef sunucuyu işaret eden yapılandırılmış bir remote’a ihtiyacınız vardır. Remote’lar sunucu URL’sini ve kimlik doğrulama bilgilerini yerel olarak `~/.twenty/config.json` içinde saklar.
|
||||
|
||||
Add a remote:
|
||||
Bir remote ekleyin:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty remote add --url https://your-twenty-server.com --as production
|
||||
```
|
||||
|
||||
For a local development server:
|
||||
Yerel bir geliştirme sunucusu için:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty remote add --local --as local
|
||||
```
|
||||
|
||||
You can also authenticate with an API key for non-interactive environments:
|
||||
Etkileşimli olmayan ortamlar için bir API anahtarıyla da kimlik doğrulayabilirsiniz:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty remote add --url https://your-twenty-server.com --token <api-key> --as production
|
||||
```
|
||||
|
||||
Manage your remotes:
|
||||
Remote’larınızı yönetin:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty remote list # List all configured remotes
|
||||
@@ -174,76 +178,76 @@ yarn twenty remote status # Show active remote and auth status
|
||||
yarn twenty remote remove old # Remove a remote
|
||||
```
|
||||
|
||||
### Deploying
|
||||
### Dağıtım
|
||||
|
||||
Build and upload your app to the server in one step:
|
||||
Uygulamanızı tek adımda derleyip sunucuya yükleyin:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty deploy
|
||||
```
|
||||
|
||||
This builds the app with `--tarball`, then uploads the tarball to the default remote via a GraphQL multipart upload.
|
||||
Bu, uygulamayı `--tarball` ile derler ve ardından tarball’ı varsayılan remote’a GraphQL çok parçalı yükleme ile yükler.
|
||||
|
||||
To deploy to a specific remote:
|
||||
Belirli bir remote’a dağıtmak için:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty deploy -r production
|
||||
```
|
||||
|
||||
### Sharing a deployed app
|
||||
### Dağıtılmış bir uygulamayı paylaşma
|
||||
|
||||
Tarball apps are not listed in the public marketplace, so other workspaces on the same server won't discover them by browsing. To share a deployed app:
|
||||
Tarball uygulamaları genel pazar yerinde listelenmez; bu nedenle aynı sunucudaki diğer çalışma alanları gezinerek onları keşfedemez. Dağıtılmış bir uygulamayı paylaşmak için:
|
||||
|
||||
1. Go to **Settings > Applications > Registrations** and open your app
|
||||
2. In the **Distribution** tab, click **Copy share link**
|
||||
3. Share this link with users on other workspaces — it takes them directly to the app's install page
|
||||
1. **Ayarlar > Uygulamalar > Kayıtlar** bölümüne gidin ve uygulamanızı açın
|
||||
2. **Dağıtım** sekmesinde, **Paylaşım bağlantısını kopyala**’ya tıklayın
|
||||
3. Bu bağlantıyı diğer çalışma alanlarındaki kullanıcılarla paylaşın — onları doğrudan uygulamanın yükleme sayfasına götürür
|
||||
|
||||
The share link uses the server's base URL (without any workspace subdomain) so it works for any workspace on the server.
|
||||
Paylaşım bağlantısı, sunucunun temel URL’sini (herhangi bir çalışma alanı alt alan adı olmadan) kullanır; böylece sunucudaki herhangi bir çalışma alanı için çalışır.
|
||||
|
||||
### Sürüm yönetimi
|
||||
|
||||
Bir güncelleme yayımlamak için:
|
||||
|
||||
1. `package.json` içindeki `version` alanını artırın
|
||||
2. Run `yarn twenty deploy` (or `yarn twenty deploy -r production`)
|
||||
3. Workspaces that have the app installed will see the upgrade available in their settings
|
||||
2. `yarn twenty deploy` (veya `yarn twenty deploy -r production`) komutunu çalıştırın
|
||||
3. Uygulamayı kurmuş olan çalışma alanları, ayarlarında mevcut güncellemeyi görecektir
|
||||
|
||||
## Installing apps
|
||||
## Uygulamaları yükleme
|
||||
|
||||
Once an app is published (npm) or deployed (tarball), workspaces install it through the UI:
|
||||
Bir uygulama yayımlandığında (npm) veya dağıtıldığında (tarball), çalışma alanları onu kullanıcı arayüzü (UI) aracılığıyla yükler:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty install
|
||||
```
|
||||
|
||||
Or from the **Settings > Applications** page in the Twenty UI, where both marketplace and tarball-deployed apps can be browsed and installed.
|
||||
Veya Twenty kullanıcı arayüzündeki **Ayarlar > Uygulamalar** sayfasından; burada hem pazar yerindeki hem de tarball ile dağıtılmış uygulamalar görüntülenip yüklenebilir.
|
||||
|
||||
## App distribution categories
|
||||
## Uygulama dağıtım kategorileri
|
||||
|
||||
Twenty, uygulamaları nasıl dağıtıldıklarına göre üç kategoriye ayırır:
|
||||
|
||||
| Kategori | Nasıl Çalışır | Pazaryerinde görünür mü? |
|
||||
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ------------------------ |
|
||||
| **Geliştirme** | `yarn twenty dev` ile çalışan yerel geliştirme modu uygulamaları. Derleme ve test için kullanılır. | Hayır |
|
||||
| **Published (npm)** | Apps published to npm with the `twenty-app` keyword. Herhangi bir çalışma alanının yükleyebilmesi için pazaryerinde listelenir. | Evet |
|
||||
| **Internal (tarball)** | Bir tarball aracılığıyla belirli bir sunucuya dağıtılan uygulamalar. Available only to workspaces on that server via a share link. | Hayır |
|
||||
| Kategori | Nasıl Çalışır | Pazaryerinde görünür mü? |
|
||||
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------ |
|
||||
| **Geliştirme** | `yarn twenty dev` ile çalışan yerel geliştirme modu uygulamaları. Derleme ve test için kullanılır. | Hayır |
|
||||
| **Yayımlanmış (npm)** | `twenty-app` anahtar kelimesiyle npm’ye yayımlanan uygulamalar. Herhangi bir çalışma alanının yükleyebilmesi için pazaryerinde listelenir. | Evet |
|
||||
| **Dahili (tarball)** | Bir tarball aracılığıyla belirli bir sunucuya dağıtılan uygulamalar. Yalnızca o sunucudaki çalışma alanları için bir paylaşım bağlantısı aracılığıyla kullanılabilir. | Hayır |
|
||||
|
||||
<Tip>
|
||||
Uygulamanızı geliştirirken **Geliştirme** modunda başlayın. Hazır olduğunda, geniş dağıtım için **Yayımlanmış** (npm) ya da özel dağıtım için **Dahili** (tarball) seçeneğini tercih edin.
|
||||
</Tip>
|
||||
|
||||
## CLI reference
|
||||
## CLI başvurusu
|
||||
|
||||
| Komut | Açıklama | Key flags |
|
||||
| --------------------------- | ---------------------------------------------- | --------------------------------------------------- |
|
||||
| `yarn twenty build` | Compile app and generate manifest | `--tarball` — also create a `.tgz` package |
|
||||
| `yarn twenty publish` | Build and publish to npm | `--tag <tag>` — npm dist-tag (e.g., `beta`, `next`) |
|
||||
| `yarn twenty deploy` | Build and upload tarball to a server | `-r, --remote <name>` — target remote |
|
||||
| `yarn twenty catalog-sync` | Trigger marketplace catalog sync on the server | `-r, --remote <name>` — target remote |
|
||||
| `yarn twenty install` | Install a deployed app on a workspace | `-r, --remote <name>` — target remote |
|
||||
| `yarn twenty dev` | Watch and sync local changes | Uses default remote |
|
||||
| `yarn twenty remote add` | Add a server connection | `--url`, `--token`, `--as`, `--local`, `--port` |
|
||||
| `yarn twenty remote list` | List configured remotes | — |
|
||||
| `yarn twenty remote switch` | Set default remote | — |
|
||||
| `yarn twenty remote status` | Show connection status | — |
|
||||
| `yarn twenty remote remove` | Remove a remote | — |
|
||||
| Komut | Açıklama | Temel bayraklar |
|
||||
| --------------------------- | --------------------------------------------------- | -------------------------------------------------- |
|
||||
| `yarn twenty build` | Uygulamayı derleyin ve manifest oluşturun | `--tarball` — ayrıca bir `.tgz` paket oluşturur |
|
||||
| `yarn twenty publish` | Derleyin ve npm’ye yayımlayın | `--tag <tag>` — npm dist-tag (örn. `beta`, `next`) |
|
||||
| `yarn twenty deploy` | Derleyin ve tarball’ı bir sunucuya yükleyin | `-r, --remote <name>` — hedef remote |
|
||||
| `yarn twenty catalog-sync` | Sunucuda pazar yeri katalog eşitlemesini tetikleyin | `-r, --remote <name>` — hedef remote |
|
||||
| `yarn twenty install` | Dağıtılmış bir uygulamayı bir çalışma alanına kurun | `-r, --remote <name>` — hedef remote |
|
||||
| `yarn twenty dev` | Yerel değişiklikleri izleyin ve eşitleyin | Varsayılan remote’u kullanır |
|
||||
| `yarn twenty remote add` | Bir sunucu bağlantısı ekleyin | `--url`, `--token`, `--as`, `--local`, `--port` |
|
||||
| `yarn twenty remote list` | Yapılandırılmış remote’ları listeleyin | — |
|
||||
| `yarn twenty remote switch` | Varsayılan remote’u ayarlayın | — |
|
||||
| `yarn twenty remote status` | Bağlantı durumunu gösterin | — |
|
||||
| `yarn twenty remote remove` | Bir remote’u kaldırın | — |
|
||||
|
||||
@@ -38,7 +38,7 @@ yarn twenty dev
|
||||
|
||||
### Yerel Sunucu Yönetimi
|
||||
|
||||
SDK, yerel bir Twenty geliştirme sunucusunu yönetmek için komutlar içerir (PostgreSQL, Redis, sunucu ve worker içeren hepsi bir arada Docker imajı):
|
||||
SDK, yerel bir Twenty geliştirme sunucusunu yönetmek için komutlar içerir (PostgreSQL, Redis, sunucu ve worker içeren hepsi bir arada Docker imajı, 2020 numaralı portta). Bu komutlar yalnızca Docker tabanlı geliştirme sunucusu için geçerlidir — kaynak koddan başlatılan bir Twenty örneğini yönetmezler (örn. 3000 numaralı portta `npx nx start twenty-server`):
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Yerel sunucuyu başlatın (gerekirse imajı indirir)
|
||||
|
||||
@@ -358,17 +358,17 @@ export default defineApplication({
|
||||
|
||||
如果你计划[发布你的应用](/l/zh/developers/extend/apps/publishing),这些可选字段将控制你的应用在应用市场中的展示:
|
||||
|
||||
| 字段 | 描述 |
|
||||
| ------------------ | -------------------------- |
|
||||
| `作者` | 作者或公司名称 |
|
||||
| `类别` | 用于应用市场筛选的应用类别 |
|
||||
| `logoUrl` | 你的应用徽标的路径(相对于 `./assets/`) |
|
||||
| `screenshots` | 屏幕截图路径数组(相对于 `./assets/`) |
|
||||
| `aboutDescription` | 用于“关于”选项卡的更长 Markdown 描述 |
|
||||
| `websiteUrl` | 你的网站链接 |
|
||||
| `termsUrl` | 服务条款链接 |
|
||||
| `emailSupport` | 支持电子邮件地址 |
|
||||
| `issueReportUrl` | 问题跟踪器链接 |
|
||||
| 字段 | 描述 |
|
||||
| ------------------ | -------------------------------------------------------------- |
|
||||
| `作者` | 作者或公司名称 |
|
||||
| `类别` | 用于应用市场筛选的应用类别 |
|
||||
| `logoUrl` | 你的应用徽标的路径(相对于 `./assets/`) |
|
||||
| `screenshots` | 屏幕截图路径数组(相对于 `./assets/`) |
|
||||
| `aboutDescription` | 用于“关于”选项卡的更长的 Markdown 描述。 如果省略,市场将使用该软件包在 npm 上的 `README.md`。 |
|
||||
| `websiteUrl` | 你的网站链接 |
|
||||
| `termsUrl` | 服务条款链接 |
|
||||
| `emailSupport` | 支持电子邮件地址 |
|
||||
| `issueReportUrl` | 问题跟踪器链接 |
|
||||
|
||||
#### 角色和权限
|
||||
|
||||
|
||||
@@ -9,18 +9,19 @@ description: 几分钟内创建你的第一个 Twenty 应用。
|
||||
|
||||
应用可通过自定义对象、字段、逻辑函数、AI 技能和 UI 组件来扩展 Twenty——全部以代码进行管理。
|
||||
|
||||
**你现在可以做什么:**
|
||||
**你可以构建的内容:**
|
||||
|
||||
* 以代码定义自定义对象和字段(受管理的数据模型)
|
||||
* 使用自定义触发器(HTTP 路由、cron、数据库事件)构建逻辑函数
|
||||
* 为 AI 智能体定义技能
|
||||
* 构建在 Twenty 的 UI 中渲染的前端组件
|
||||
* 自定义对象、字段、视图和导航项,以塑造你的数据模型
|
||||
* 由 HTTP 路由、cron 调度或数据库事件触发的逻辑函数
|
||||
* 在 Twenty 的 UI 中直接渲染的前端组件
|
||||
* 用于扩展 Twenty 的 AI 代理的技能
|
||||
* 将同一个应用部署到多个工作空间
|
||||
|
||||
## 先决条件
|
||||
|
||||
* Node.js 24+ 和 Yarn 4
|
||||
* Docker (用于本地 Twenty 开发服务器)
|
||||
* Node.js 24+
|
||||
* Yarn 4
|
||||
* Docker (或正在运行的本地 Twenty 实例)
|
||||
|
||||
## 开始使用
|
||||
|
||||
@@ -29,21 +30,9 @@ description: 几分钟内创建你的第一个 Twenty 应用。
|
||||
```bash filename="Terminal"
|
||||
# Scaffold a new app (includes all examples by default)
|
||||
npx create-twenty-app@latest my-twenty-app
|
||||
cd my-twenty-app
|
||||
|
||||
# Start dev mode: automatically syncs local changes to your workspace
|
||||
yarn twenty dev
|
||||
```
|
||||
|
||||
脚手架工具支持两种模式,用于控制包含哪些示例文件:
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Default (exhaustive): all examples (object, field, logic function, front component, view, navigation menu item, skill, agent)
|
||||
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
|
||||
```
|
||||
> 使用 `--minimal` 选项生成最简安装脚手架
|
||||
|
||||
从这里您可以:
|
||||
|
||||
@@ -123,7 +112,7 @@ my-twenty-app/
|
||||
总体来说:
|
||||
|
||||
* **package.json**:声明应用名称、版本、引擎(Node 24+、Yarn 4),并添加 `twenty-sdk` 以及一个 `twenty` 脚本,该脚本会委托给本地的 `twenty` CLI。 运行 `yarn twenty help` 以列出所有可用命令。
|
||||
* **.gitignore**: Ignores common artifacts such as `node_modules`, `.yarn`, `.twenty/`, `dist/`, `build/`, coverage folders, log files, and `.env*` files.
|
||||
* **.gitignore**:忽略常见产物,如 `node_modules`、`.yarn`、`.twenty/`、`dist/`、`build/`、覆盖率文件夹、日志文件以及 `.env*` 文件。
|
||||
* **yarn.lock**、**.yarnrc.yml**、**.yarn/**:锁定并配置项目使用的 Yarn 4 工具链。
|
||||
* **.nvmrc**:固定项目期望的 Node.js 版本。
|
||||
* **.oxlintrc.json** 和 **tsconfig.json**:为应用的 TypeScript 源码提供 Lint 与 TypeScript 配置。
|
||||
@@ -167,8 +156,8 @@ export default defineObject({
|
||||
|
||||
后续命令将添加更多文件和文件夹:
|
||||
|
||||
* `yarn twenty dev` will auto-generate the typed `CoreApiClient` (for workspace data via `/graphql`) into `node_modules/twenty-client-sdk/`. The `MetadataApiClient` (for workspace configuration and file uploads via `/metadata`) ships pre-built and is available immediately. Import them from `twenty-client-sdk/core` and `twenty-client-sdk/metadata` respectively.
|
||||
* `yarn twenty add` will add entity definition files under `src/` for your custom objects, functions, front components, roles, skills, and more.
|
||||
* `yarn twenty dev` 会自动生成类型化的 `CoreApiClient`(通过 `/graphql` 获取工作区数据),并写入 `node_modules/twenty-client-sdk/`。 `MetadataApiClient`(通过 `/metadata` 处理工作区配置和文件上传)为预构建版本,可立即使用。 分别从 `twenty-client-sdk/core` 和 `twenty-client-sdk/metadata` 导入它们。
|
||||
* `yarn twenty add` 会在 `src/` 下为你的自定义对象、函数、前端组件、角色、技能等添加实体定义文件。
|
||||
|
||||
## 身份验证
|
||||
|
||||
|
||||
@@ -24,9 +24,9 @@ description: 将你的 Twenty 应用分发到应用市场,或进行内部部
|
||||
yarn twenty build
|
||||
```
|
||||
|
||||
输出将写入 `.twenty/output/`。 This directory contains everything needed for distribution: compiled code, assets, the manifest, and a copy of your `package.json`.
|
||||
输出将写入 `.twenty/output/`。 此目录包含分发所需的一切:已编译的代码、资源、清单,以及你的 `package.json` 副本。
|
||||
|
||||
To also create a `.tgz` tarball (used by the deploy command internally, or for manual distribution):
|
||||
要同时创建一个 `.tgz` 压缩包(由部署命令在内部使用,或用于手动分发):
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty build --tarball
|
||||
@@ -39,11 +39,11 @@ yarn twenty build --tarball
|
||||
### 要求
|
||||
|
||||
* 一个 [npm](https://www.npmjs.com) 账户
|
||||
* The `twenty-app` keyword **must** be listed in your `package.json` `keywords` array
|
||||
* 在你的 `package.json` 的 `keywords` 数组中**必须**包含 `twenty-app` 关键字
|
||||
|
||||
### Adding the required keyword
|
||||
### 添加所需关键字
|
||||
|
||||
The Twenty marketplace discovers apps by searching the npm registry for packages with the `twenty-app` keyword. Add it to your `package.json`:
|
||||
Twenty 市场通过在 npm 注册表中搜索带有 `twenty-app` 关键字的包来发现应用。 将其添加到你的 `package.json`:
|
||||
|
||||
```json filename="package.json"
|
||||
{
|
||||
@@ -55,56 +55,60 @@ The Twenty marketplace discovers apps by searching the npm registry for packages
|
||||
```
|
||||
|
||||
<Note>
|
||||
The marketplace searches for `keywords:twenty-app` on the npm registry. Without this keyword, your package won't appear in the marketplace even if it has the `twenty-app-` name prefix.
|
||||
该市场会在 npm 注册表中搜索 `keywords:twenty-app`。 没有此关键字,即使包名带有 `twenty-app-` 前缀,你的包也不会出现在市场中。
|
||||
</Note>
|
||||
|
||||
### 步骤
|
||||
|
||||
1. **Build your app:**
|
||||
1. **构建你的应用:**
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty build
|
||||
```
|
||||
|
||||
2. **Publish to npm:**
|
||||
2. **发布到 npm:**
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty publish
|
||||
```
|
||||
|
||||
This runs `npm publish` from the `.twenty/output/` directory.
|
||||
这会在 `.twenty/output/` 目录下运行 `npm publish`。
|
||||
|
||||
To publish under a specific dist-tag (e.g., `beta` or `next`):
|
||||
要在特定的 dist-tag(例如 `beta` 或 `next`)下发布:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty publish --tag beta
|
||||
```
|
||||
|
||||
### How marketplace discovery works
|
||||
### 应用市场的发现机制如何运作
|
||||
|
||||
The Twenty server syncs its marketplace catalog from the npm registry **every hour**:
|
||||
Twenty 服务器会**每小时**从 npm 注册表同步其市场目录:
|
||||
|
||||
1. It searches for all npm packages with the `keywords:twenty-app` keyword
|
||||
2. For each package, it fetches the `manifest.json` from the npm CDN
|
||||
3. The app's metadata (name, description, author, logo, screenshots, category) is extracted from the manifest and displayed in the marketplace
|
||||
1. 它会搜索所有带有 `keywords:twenty-app` 关键字的 npm 包
|
||||
2. 对于每个包,它会从 npm CDN 获取 `manifest.json`
|
||||
3. 应用的元数据(名称、描述、作者、徽标、屏幕截图、类别)将从清单中提取,并显示在市场中
|
||||
|
||||
After publishing, your app can take up to one hour to appear in the marketplace. To trigger the sync immediately instead of waiting for the next hourly run:
|
||||
发布后,你的应用最多可能需要一小时才会出现在市场中。 要立即触发同步,而无需等待下一次每小时同步:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty catalog-sync
|
||||
```
|
||||
|
||||
To target a specific remote:
|
||||
要指定特定的远程:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty catalog-sync -r production
|
||||
```
|
||||
|
||||
The metadata shown in the marketplace comes from your `defineApplication()` call in your app source code — fields like `displayName`, `description`, `author`, `category`, `logoUrl`, `screenshots`, `aboutDescription`, `websiteUrl`, and `termsUrl`.
|
||||
市场中显示的元数据来自你在应用源代码中调用的 `defineApplication()` —— 诸如 `displayName`、`description`、`author`、`category`、`logoUrl`、`screenshots`、`aboutDescription`、`websiteUrl` 和 `termsUrl` 等字段。
|
||||
|
||||
<Note>
|
||||
如果您的应用未在 `defineApplication()` 中定义 `aboutDescription`,市场将自动使用 npm 上您的软件包的 `README.md` 作为关于页面内容。 这意味着您可以为 npm 和 Twenty 市场维护同一个 README。 如果您希望在市场中使用不同的描述,请显式设置 `aboutDescription`。
|
||||
</Note>
|
||||
|
||||
### CI 发布
|
||||
|
||||
The scaffolded project includes a GitHub Actions workflow that publishes on every release:
|
||||
脚手架项目包含一个 GitHub Actions 工作流,会在每次发版时自动发布:
|
||||
|
||||
```yaml filename=".github/workflows/publish.yml"
|
||||
name: Publish
|
||||
@@ -133,39 +137,39 @@ jobs:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
```
|
||||
|
||||
For other CI systems (GitLab CI, CircleCI, etc.), the same three commands apply: `yarn install`, `yarn twenty build`, then `npm publish` from `.twenty/output`.
|
||||
对于其他 CI 系统(GitLab CI、CircleCI 等),同样适用以下三条命令:`yarn install`、`yarn twenty build`,然后在 `.twenty/output` 目录下执行 `npm publish`。
|
||||
|
||||
<Tip>
|
||||
**npm provenance** 可选,但建议启用。 使用 `--provenance` 发布会在你的 npm 列表中添加可信徽章,使用户可以验证该包是由公共 CI 流水线中的特定提交构建的。 有关设置说明,请参见 [npm provenance 文档](https://docs.npmjs.com/generating-provenance-statements)。
|
||||
</Tip>
|
||||
|
||||
## Deploying to a server (tarball)
|
||||
## 部署到服务器(tar 包)
|
||||
|
||||
For apps you don't want publicly available — proprietary tools, enterprise-only integrations, or experimental builds — you can deploy a tarball directly to a Twenty server.
|
||||
对于你不希望公开的应用(专有工具、仅供企业使用的集成或实验性构建),你可以将 tar 包直接部署到某台 Twenty 服务器。
|
||||
|
||||
### 先决条件
|
||||
|
||||
Before deploying, you need a configured remote pointing to the target server. Remotes store the server URL and authentication credentials locally in `~/.twenty/config.json`.
|
||||
在部署之前,你需要配置一个指向目标服务器的远程。 远程会将服务器 URL 和身份验证凭据本地存储在 `~/.twenty/config.json` 中。
|
||||
|
||||
Add a remote:
|
||||
添加远程:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty remote add --url https://your-twenty-server.com --as production
|
||||
```
|
||||
|
||||
For a local development server:
|
||||
对于本地开发服务器:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty remote add --local --as local
|
||||
```
|
||||
|
||||
You can also authenticate with an API key for non-interactive environments:
|
||||
对于非交互式环境,你也可以使用 API 密钥进行身份验证:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty remote add --url https://your-twenty-server.com --token <api-key> --as production
|
||||
```
|
||||
|
||||
Manage your remotes:
|
||||
管理你的远程:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty remote list # List all configured remotes
|
||||
@@ -174,76 +178,76 @@ yarn twenty remote status # Show active remote and auth status
|
||||
yarn twenty remote remove old # Remove a remote
|
||||
```
|
||||
|
||||
### Deploying
|
||||
### 部署
|
||||
|
||||
Build and upload your app to the server in one step:
|
||||
一步构建并将你的应用上传到服务器:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty deploy
|
||||
```
|
||||
|
||||
This builds the app with `--tarball`, then uploads the tarball to the default remote via a GraphQL multipart upload.
|
||||
这会使用 `--tarball` 构建应用,然后通过 GraphQL 多部分上传将该 tar 包上传到默认远程。
|
||||
|
||||
To deploy to a specific remote:
|
||||
部署到特定远程:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty deploy -r production
|
||||
```
|
||||
|
||||
### Sharing a deployed app
|
||||
### 共享已部署的应用
|
||||
|
||||
Tarball apps are not listed in the public marketplace, so other workspaces on the same server won't discover them by browsing. To share a deployed app:
|
||||
通过 tar 包分发的应用不会出现在公共市场中,因此同一服务器上的其他工作区无法通过浏览发现它们。 要共享已部署的应用:
|
||||
|
||||
1. Go to **Settings > Applications > Registrations** and open your app
|
||||
2. In the **Distribution** tab, click **Copy share link**
|
||||
3. Share this link with users on other workspaces — it takes them directly to the app's install page
|
||||
1. 前往 **Settings > Applications > Registrations** 并打开你的应用
|
||||
2. 在 **Distribution** 选项卡中,点击 **Copy share link**
|
||||
3. 将此链接分享给其他工作区的用户 — 它会将他们直接带到该应用的安装页面
|
||||
|
||||
The share link uses the server's base URL (without any workspace subdomain) so it works for any workspace on the server.
|
||||
该分享链接使用服务器的基础 URL(不包含任何工作区子域),因此适用于该服务器上的任意工作区。
|
||||
|
||||
### 版本管理
|
||||
|
||||
要发布更新:
|
||||
|
||||
1. 更新 `package.json` 中的 `version` 字段
|
||||
2. Run `yarn twenty deploy` (or `yarn twenty deploy -r production`)
|
||||
3. Workspaces that have the app installed will see the upgrade available in their settings
|
||||
2. 运行 `yarn twenty deploy`(或 `yarn twenty deploy -r production`)
|
||||
3. 已安装该应用的工作区会在其设置中看到可用的升级
|
||||
|
||||
## Installing apps
|
||||
## 安装应用
|
||||
|
||||
Once an app is published (npm) or deployed (tarball), workspaces install it through the UI:
|
||||
一旦应用已发布(npm)或已部署(tar 包),各工作区即可通过 UI 进行安装:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty install
|
||||
```
|
||||
|
||||
Or from the **Settings > Applications** page in the Twenty UI, where both marketplace and tarball-deployed apps can be browsed and installed.
|
||||
或者在 Twenty UI 的 **Settings > Applications** 页面中浏览并安装来自市场或通过 tar 包部署的应用。
|
||||
|
||||
## App distribution categories
|
||||
## 应用分发类别
|
||||
|
||||
Twenty 会根据分发方式将应用归为三类:
|
||||
|
||||
| 类别 | 工作原理 | 在应用市场中可见? |
|
||||
| ---------------------- | ---------------------------------------------------------------------------------- | --------- |
|
||||
| **开发** | 通过 `yarn twenty dev` 运行的本地开发模式应用。 用于构建和测试。 | 否 |
|
||||
| **Published (npm)** | Apps published to npm with the `twenty-app` keyword. 在应用市场上架,供任何工作区安装。 | 是 |
|
||||
| **Internal (tarball)** | 通过 tar 包部署到特定服务器的应用。 Available only to workspaces on that server via a share link. | 否 |
|
||||
| 类别 | 工作原理 | 在应用市场中可见? |
|
||||
| ------------- | -------------------------------------------------- | --------- |
|
||||
| **开发** | 通过 `yarn twenty dev` 运行的本地开发模式应用。 用于构建和测试。 | 否 |
|
||||
| **已发布(npm)** | 发布到 npm 且包含 `twenty-app` 关键字的应用。 在应用市场上架,供任何工作区安装。 | 是 |
|
||||
| **内部(tar 包)** | 通过 tar 包部署到特定服务器的应用。 仅通过分享链接对该服务器上的工作区可用。 | 否 |
|
||||
|
||||
<Tip>
|
||||
在构建你的应用时,从**开发**模式开始。 准备就绪后,选择用于广泛分发的**已发布**(npm),或用于私有部署的**内部**(tar 包)。
|
||||
</Tip>
|
||||
|
||||
## CLI reference
|
||||
## CLI 参考
|
||||
|
||||
| 命令 | 描述 | Key flags |
|
||||
| --------------------------- | ---------------------------------------------- | --------------------------------------------------- |
|
||||
| `yarn twenty build` | Compile app and generate manifest | `--tarball` — also create a `.tgz` package |
|
||||
| `yarn twenty publish` | Build and publish to npm | `--tag <tag>` — npm dist-tag (e.g., `beta`, `next`) |
|
||||
| `yarn twenty deploy` | Build and upload tarball to a server | `-r, --remote <name>` — target remote |
|
||||
| `yarn twenty catalog-sync` | Trigger marketplace catalog sync on the server | `-r, --remote <name>` — target remote |
|
||||
| `yarn twenty install` | Install a deployed app on a workspace | `-r, --remote <name>` — target remote |
|
||||
| `yarn twenty dev` | Watch and sync local changes | Uses default remote |
|
||||
| `yarn twenty remote add` | Add a server connection | `--url`, `--token`, `--as`, `--local`, `--port` |
|
||||
| `yarn twenty remote list` | List configured remotes | — |
|
||||
| `yarn twenty remote switch` | Set default remote | — |
|
||||
| `yarn twenty remote status` | Show connection status | — |
|
||||
| `yarn twenty remote remove` | Remove a remote | — |
|
||||
| 命令 | 描述 | 关键选项 |
|
||||
| --------------------------- | ---------------- | ------------------------------------------- |
|
||||
| `yarn twenty build` | 编译应用并生成清单 | `--tarball` — 同时创建一个 `.tgz` 包 |
|
||||
| `yarn twenty publish` | 构建并发布到 npm | `--tag <tag>` — npm 分发标签(例如 `beta`、`next`) |
|
||||
| `yarn twenty deploy` | 构建并将 tar 包上传到服务器 | `-r, --remote <name>` — 目标远程 |
|
||||
| `yarn twenty catalog-sync` | 在服务器上触发市场目录同步 | `-r, --remote <name>` — 目标远程 |
|
||||
| `yarn twenty install` | 在某个工作区安装已部署的应用 | `-r, --remote <name>` — 目标远程 |
|
||||
| `yarn twenty dev` | 监听并同步本地更改 | 使用默认远程 |
|
||||
| `yarn twenty remote add` | 添加服务器连接 | `--url`,`--token`,`--as`,`--local`,`--port` |
|
||||
| `yarn twenty remote list` | 列出已配置的远程 | — |
|
||||
| `yarn twenty remote switch` | 设置默认远程 | — |
|
||||
| `yarn twenty remote status` | 显示连接状态 | — |
|
||||
| `yarn twenty remote remove` | 移除远程 | — |
|
||||
|
||||
@@ -38,7 +38,7 @@ yarn twenty dev
|
||||
|
||||
### 本地服务器管理
|
||||
|
||||
该 SDK 包含用于管理本地 Twenty 开发服务器的命令(该服务器是一体化 Docker 镜像,内含 PostgreSQL、Redis、服务器和工作进程):
|
||||
该 SDK 包含用于管理本地 Twenty 开发服务器的命令(该服务器是一体化 Docker 镜像,内含 PostgreSQL、Redis、服务器和工作进程,监听 2020 端口)。 这些命令仅适用于基于 Docker 的开发服务器——它们不会管理从源代码启动的 Twenty 实例(例如通过 `npx nx start twenty-server` 启动的实例,运行在 3000 端口):
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Start the local server (pulls the image if needed)
|
||||
|
||||
@@ -24,7 +24,7 @@ test('Create Industry Select Field', async ({ page }) => {
|
||||
|
||||
test('Create Kanban View from Industry Select Field', async ({ page }) => {
|
||||
await page.getByRole('link', { name: 'Opportunities' }).click();
|
||||
await page.getByRole('button', { name: 'All Opportunities ·' }).click();
|
||||
await page.getByRole('button', { name: /All Opportunities/ }).click();
|
||||
await page.getByText('Add view').click();
|
||||
await page.getByRole('textbox').press('ControlOrMeta+a');
|
||||
await page.getByRole('textbox').fill('By industry');
|
||||
@@ -32,12 +32,11 @@ test('Create Kanban View from Industry Select Field', async ({ page }) => {
|
||||
await page.getByText('Kanban').click();
|
||||
await page.locator('[aria-controls="view-picker-kanban-field-options"]').click();
|
||||
await page.getByRole('option', { name: 'Industry' }).click();
|
||||
// Use exact: true to ensure we only click the button with the label "Create"
|
||||
await page.getByRole('button', { name: 'Create new view' }).click();
|
||||
await expect(page.getByText('Food')).toBeVisible();
|
||||
await expect(page.getByText('Food')).toBeVisible({ timeout: 30000 });
|
||||
await expect(page.getByText('Tech')).toBeVisible();
|
||||
await expect(page.getByText('Travel')).toBeVisible();
|
||||
await expect(page.getByText('No value')).toBeVisible();
|
||||
await expect(page.getByText('No Value')).toBeVisible();
|
||||
const byIndustryElements = await page.locator('text=By industry').all();
|
||||
expect(byIndustryElements.length).toBeGreaterThanOrEqual(1);
|
||||
for (const element of byIndustryElements) {
|
||||
@@ -50,6 +49,6 @@ test('Create Kanban View from Industry Select Field', async ({ page }) => {
|
||||
return req.url().includes('/metadata') &&
|
||||
req.method() === 'POST';
|
||||
})]);
|
||||
await expect(page.getByText('No value')).not.toBeVisible();
|
||||
await expect(page.getByText('No Value')).not.toBeVisible();
|
||||
});
|
||||
})
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
node_modules
|
||||
storybook-static
|
||||
src/__stories__/example-sources-built
|
||||
src/__stories__/example-sources-built-preact
|
||||
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
||||
"plugins": ["react", "typescript", "import", "unicorn"],
|
||||
"categories": {
|
||||
"correctness": "off"
|
||||
},
|
||||
"ignorePatterns": ["node_modules", "dist"],
|
||||
"rules": {
|
||||
"func-style": ["error", "declaration", { "allowArrowFunctions": true }],
|
||||
"no-console": "off",
|
||||
"no-control-regex": "off",
|
||||
"no-debugger": "error",
|
||||
"no-duplicate-imports": "error",
|
||||
"no-undef": "off",
|
||||
"no-unused-vars": "off",
|
||||
"no-redeclare": "off",
|
||||
"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/explicit-function-return-type": "off",
|
||||
"typescript/explicit-module-boundary-types": "off",
|
||||
"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": "^_"
|
||||
}
|
||||
],
|
||||
"react/no-unescaped-entities": "off",
|
||||
"react/prop-types": "off",
|
||||
"react/jsx-key": "off",
|
||||
"react/display-name": "off",
|
||||
"react/jsx-uses-react": "off",
|
||||
"react/react-in-jsx-scope": "off",
|
||||
"react/jsx-no-useless-fragment": "off",
|
||||
"react/jsx-props-no-spreading": ["error", { "explicitSpread": "ignore" }],
|
||||
"react-hooks/rules-of-hooks": "error",
|
||||
"react-hooks/exhaustive-deps": "warn"
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -8,10 +8,10 @@ const dirname =
|
||||
? __dirname
|
||||
: path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
const sdkRoot = path.resolve(dirname, '..');
|
||||
const packageRoot = path.resolve(dirname, '..');
|
||||
|
||||
const config: StorybookConfig = {
|
||||
stories: ['../src/front-component-renderer/**/*.stories.@(js|jsx|ts|tsx)'],
|
||||
stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],
|
||||
|
||||
addons: ['@storybook/addon-vitest'],
|
||||
|
||||
@@ -23,11 +23,11 @@ const config: StorybookConfig = {
|
||||
|
||||
staticDirs: [
|
||||
{
|
||||
from: '../src/front-component-renderer/__stories__/example-sources-built',
|
||||
from: '../src/__stories__/example-sources-built',
|
||||
to: '/built',
|
||||
},
|
||||
{
|
||||
from: '../src/front-component-renderer/__stories__/example-sources-built-preact',
|
||||
from: '../src/__stories__/example-sources-built-preact',
|
||||
to: '/built-preact',
|
||||
},
|
||||
],
|
||||
@@ -57,7 +57,7 @@ const config: StorybookConfig = {
|
||||
},
|
||||
plugins: [
|
||||
...(viteConfig.plugins ?? []),
|
||||
tsconfigPaths({ root: sdkRoot }),
|
||||
tsconfigPaths({ root: packageRoot }),
|
||||
],
|
||||
optimizeDeps: {
|
||||
...viteConfig.optimizeDeps,
|
||||
@@ -0,0 +1,58 @@
|
||||
{
|
||||
"name": "twenty-front-component-renderer",
|
||||
"version": "0.8.0-canary.5",
|
||||
"private": true,
|
||||
"main": "dist/index.cjs",
|
||||
"module": "dist/index.mjs",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
"dist",
|
||||
"package.json"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "npx rimraf dist && npx vite build"
|
||||
},
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.mjs",
|
||||
"require": "./dist/index.cjs"
|
||||
}
|
||||
},
|
||||
"license": "AGPL-3.0",
|
||||
"dependencies": {
|
||||
"@quilted/threads": "^4.0.1",
|
||||
"@remote-dom/core": "^1.10.1",
|
||||
"@remote-dom/react": "^1.2.2",
|
||||
"@sniptt/guards": "^0.2.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"zod": "^4.1.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@chakra-ui/react": "^3.33.0",
|
||||
"@emotion/react": "^11.14.0",
|
||||
"@emotion/styled": "^11.14.0",
|
||||
"@mui/material": "^7.3.8",
|
||||
"@storybook/addon-vitest": "^10.2.13",
|
||||
"@storybook/react-vite": "^10.2.13",
|
||||
"@types/node": "^24.0.0",
|
||||
"@types/react": "^19.0.0",
|
||||
"@types/react-dom": "^19.0.0",
|
||||
"@vitest/browser-playwright": "^4.0.18",
|
||||
"playwright": "^1.56.1",
|
||||
"storybook": "^10.2.13",
|
||||
"styled-components": "^6.1.0",
|
||||
"ts-morph": "^25.0.0",
|
||||
"tsx": "^4.7.0",
|
||||
"twenty-sdk": "workspace:*",
|
||||
"twenty-shared": "workspace:*",
|
||||
"twenty-ui": "workspace:*",
|
||||
"vite-plugin-dts": "^4.5.4",
|
||||
"vite-tsconfig-paths": "^4.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^24.5.0",
|
||||
"yarn": "^4.0.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
{
|
||||
"name": "twenty-front-component-renderer",
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "packages/twenty-front-component-renderer/src",
|
||||
"projectType": "library",
|
||||
"tags": ["scope:frontend"],
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "nx:run-commands",
|
||||
"cache": true,
|
||||
"inputs": ["production", "^production"],
|
||||
"dependsOn": ["^build"],
|
||||
"outputs": ["{projectRoot}/dist"],
|
||||
"options": {
|
||||
"cwd": "{projectRoot}",
|
||||
"commands": [
|
||||
"npx rimraf dist && npx vite build -c vite.config.ts",
|
||||
"tsgo -p tsconfig.lib.json --declaration --emitDeclarationOnly --noEmit false --outDir dist --rootDir src && npx tsc-alias -p tsconfig.lib.json --outDir dist"
|
||||
],
|
||||
"parallel": false
|
||||
}
|
||||
},
|
||||
"typecheck": {},
|
||||
"lint": {},
|
||||
"generate-remote-dom-elements": {
|
||||
"executor": "nx:run-commands",
|
||||
"cache": true,
|
||||
"dependsOn": ["^build"],
|
||||
"inputs": [
|
||||
"{projectRoot}/scripts/remote-dom/**/*",
|
||||
"{projectRoot}/src/constants/**/*",
|
||||
"{workspaceRoot}/packages/twenty-ui/src/**/index.ts",
|
||||
"{workspaceRoot}/packages/twenty-ui/src/**/*.tsx"
|
||||
],
|
||||
"outputs": [
|
||||
"{projectRoot}/src/host/generated/*",
|
||||
"{projectRoot}/src/remote/generated/*"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "packages/twenty-front-component-renderer",
|
||||
"command": "tsx -r tsconfig-paths/register scripts/remote-dom/generate-remote-dom-elements.ts"
|
||||
},
|
||||
"configurations": {
|
||||
"verbose": {
|
||||
"command": "tsx -r tsconfig-paths/register scripts/remote-dom/generate-remote-dom-elements.ts --verbose"
|
||||
}
|
||||
}
|
||||
},
|
||||
"storybook:prebuild": {
|
||||
"executor": "nx:run-commands",
|
||||
"cache": true,
|
||||
"dependsOn": [
|
||||
"generate-remote-dom-elements",
|
||||
{
|
||||
"target": "build:sdk",
|
||||
"projects": "twenty-sdk"
|
||||
},
|
||||
{
|
||||
"target": "build:individual",
|
||||
"projects": "twenty-ui"
|
||||
},
|
||||
{
|
||||
"target": "build:individual",
|
||||
"projects": "twenty-shared"
|
||||
}
|
||||
],
|
||||
"inputs": [
|
||||
"{projectRoot}/scripts/front-component-stories/**/*",
|
||||
"{projectRoot}/src/__stories__/example-sources/*",
|
||||
"{workspaceRoot}/packages/twenty-sdk/src/cli/utilities/build/**/*"
|
||||
],
|
||||
"outputs": ["{projectRoot}/src/__stories__/example-sources-built/*"],
|
||||
"options": {
|
||||
"command": "tsx {projectRoot}/scripts/front-component-stories/build-source-examples.ts"
|
||||
}
|
||||
},
|
||||
"storybook:build": {
|
||||
"dependsOn": ["storybook:prebuild"],
|
||||
"configurations": {
|
||||
"test": {}
|
||||
}
|
||||
},
|
||||
"storybook:serve:dev": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"port": 6008
|
||||
}
|
||||
},
|
||||
"storybook:serve:static": {
|
||||
"options": {
|
||||
"buildTarget": "twenty-front-component-renderer:storybook:build",
|
||||
"port": 6008
|
||||
},
|
||||
"configurations": {
|
||||
"test": {}
|
||||
}
|
||||
},
|
||||
"storybook:test": {
|
||||
"dependsOn": ["storybook:prebuild"],
|
||||
"options": {
|
||||
"command": "vitest run --coverage --config vitest.storybook.config.ts --shard={args.shard}"
|
||||
}
|
||||
},
|
||||
"storybook:test:no-coverage": {
|
||||
"dependsOn": ["storybook:prebuild"],
|
||||
"options": {
|
||||
"command": "vitest run --config vitest.storybook.config.ts --shard={args.shard}"
|
||||
}
|
||||
},
|
||||
"storybook:coverage": {}
|
||||
}
|
||||
}
|
||||
+8
-5
@@ -3,20 +3,20 @@ import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
import { getFrontComponentBuildPlugins } from '../../src/cli/utilities/build/common/front-component-build/utils/get-front-component-build-plugins';
|
||||
import { getFrontComponentBuildPlugins } from 'twenty-sdk/front-component-renderer/build';
|
||||
|
||||
const dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const exampleSourcesDir = path.resolve(
|
||||
dirname,
|
||||
'../../src/front-component-renderer/__stories__/example-sources',
|
||||
'../../src/__stories__/example-sources',
|
||||
);
|
||||
const exampleSourcesBuiltDir = path.resolve(
|
||||
dirname,
|
||||
'../../src/front-component-renderer/__stories__/example-sources-built',
|
||||
'../../src/__stories__/example-sources-built',
|
||||
);
|
||||
const exampleSourcesBuiltPreactDir = path.resolve(
|
||||
dirname,
|
||||
'../../src/front-component-renderer/__stories__/example-sources-built-preact',
|
||||
'../../src/__stories__/example-sources-built-preact',
|
||||
);
|
||||
|
||||
const rootNodeModules = path.resolve(dirname, '../../../../node_modules');
|
||||
@@ -26,7 +26,10 @@ const twentyUiIndividualIndex = path.resolve(
|
||||
'../../../twenty-ui/dist/individual/individual-entry.js',
|
||||
);
|
||||
|
||||
const sdkIndividualIndex = path.resolve(dirname, '../../dist/sdk/index.js');
|
||||
const sdkIndividualIndex = path.resolve(
|
||||
dirname,
|
||||
'../../../twenty-sdk/dist/sdk/index.js',
|
||||
);
|
||||
|
||||
const twentySharedIndividualDir = path.resolve(
|
||||
dirname,
|
||||
+6
-12
@@ -4,9 +4,9 @@ import * as path from 'path';
|
||||
import { IndentationText, Project, QuoteKind } from 'ts-morph';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
import { ALLOWED_HTML_ELEMENTS } from '../../src/sdk/front-component-api/constants/AllowedHtmlElements';
|
||||
import { COMMON_HTML_EVENTS } from '../../src/sdk/front-component-api/constants/CommonHtmlEvents';
|
||||
import { HTML_COMMON_PROPERTIES } from '../../src/sdk/front-component-api/constants/HtmlCommonProperties';
|
||||
import { ALLOWED_HTML_ELEMENTS } from '../../src/constants/AllowedHtmlElements';
|
||||
import { COMMON_HTML_EVENTS } from '../../src/constants/CommonHtmlEvents';
|
||||
import { HTML_COMMON_PROPERTIES } from '../../src/constants/HtmlCommonProperties';
|
||||
|
||||
import {
|
||||
type ComponentSchema,
|
||||
@@ -19,15 +19,9 @@ import {
|
||||
|
||||
const SCRIPT_DIR = path.dirname(fileURLToPath(import.meta.url));
|
||||
const PACKAGE_PATH = path.resolve(SCRIPT_DIR, '../..');
|
||||
const FRONT_COMPONENT_PATH = path.join(
|
||||
PACKAGE_PATH,
|
||||
'src/front-component-renderer',
|
||||
);
|
||||
const HOST_GENERATED_DIR = path.join(FRONT_COMPONENT_PATH, 'host/generated');
|
||||
const REMOTE_GENERATED_DIR = path.join(
|
||||
FRONT_COMPONENT_PATH,
|
||||
'remote/generated',
|
||||
);
|
||||
const SRC_PATH = path.join(PACKAGE_PATH, 'src');
|
||||
const HOST_GENERATED_DIR = path.join(SRC_PATH, 'host/generated');
|
||||
const REMOTE_GENERATED_DIR = path.join(SRC_PATH, 'remote/generated');
|
||||
|
||||
const extractHtmlTag = (tag: string): string => tag.slice(5);
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import type { Project, SourceFile } from 'ts-morph';
|
||||
|
||||
import { EVENT_TO_REACT } from '../../../src/sdk/front-component-api/constants/EventToReact';
|
||||
import { EVENT_TO_REACT } from '../../../src/constants/EventToReact';
|
||||
import { type ComponentSchema } from './schemas';
|
||||
import { addExportedConst } from './utils';
|
||||
|
||||
+1
-2
@@ -336,8 +336,7 @@ export const generateRemoteElements = (
|
||||
});
|
||||
|
||||
sourceFile.addImportDeclaration({
|
||||
moduleSpecifier:
|
||||
'../../../sdk/front-component-api/constants/SerializedEventData',
|
||||
moduleSpecifier: '@/constants/SerializedEventData',
|
||||
namedImports: [{ name: 'SerializedEventData', isTypeOnly: true }],
|
||||
});
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { type PropertySchema } from '@/front-component-renderer/types/PropertySchema';
|
||||
import { type PropertySchema } from './PropertySchema';
|
||||
|
||||
export const HTML_COMMON_PROPERTIES: Record<string, PropertySchema> = {
|
||||
id: { type: 'string', optional: true },
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
import {
|
||||
type CloseSidePanelFunction,
|
||||
type EnqueueSnackbarFunction,
|
||||
type NavigateFunction,
|
||||
type OpenCommandConfirmationModalFunction,
|
||||
type OpenSidePanelPageFunction,
|
||||
type RequestAccessTokenRefreshFunction,
|
||||
type UnmountFrontComponentFunction,
|
||||
type UpdateProgressFunction,
|
||||
} from 'twenty-sdk';
|
||||
|
||||
import { FRONT_COMPONENT_HOST_COMMUNICATION_API_KEY } from 'twenty-sdk/front-component-renderer';
|
||||
|
||||
type FrontComponentHostCommunicationApiStore = {
|
||||
navigate?: NavigateFunction;
|
||||
requestAccessTokenRefresh?: RequestAccessTokenRefreshFunction;
|
||||
openSidePanelPage?: OpenSidePanelPageFunction;
|
||||
openCommandConfirmationModal?: OpenCommandConfirmationModalFunction;
|
||||
unmountFrontComponent?: UnmountFrontComponentFunction;
|
||||
enqueueSnackbar?: EnqueueSnackbarFunction;
|
||||
closeSidePanel?: CloseSidePanelFunction;
|
||||
updateProgress?: UpdateProgressFunction;
|
||||
};
|
||||
|
||||
(globalThis as Record<string, unknown>)[
|
||||
FRONT_COMPONENT_HOST_COMMUNICATION_API_KEY
|
||||
] ??= {};
|
||||
|
||||
export const frontComponentHostCommunicationApi: FrontComponentHostCommunicationApiStore =
|
||||
(globalThis as Record<string, unknown>)[
|
||||
FRONT_COMPONENT_HOST_COMMUNICATION_API_KEY
|
||||
] as FrontComponentHostCommunicationApiStore;
|
||||
+7
-7
@@ -1,10 +1,10 @@
|
||||
import { FrontComponentErrorEffect } from '@/front-component-renderer/remote/components/FrontComponentErrorEffect';
|
||||
import { FrontComponentHostCommunicationApiEffect } from '@/front-component-renderer/remote/components/FrontComponentHostCommunicationApiEffect';
|
||||
import { FrontComponentUpdateContextEffect } from '@/front-component-renderer/remote/components/FrontComponentUpdateContextEffect';
|
||||
import { type FrontComponentHostCommunicationApi } from '@/front-component-renderer/types/FrontComponentHostCommunicationApi';
|
||||
import { type SdkClientUrls } from '@/front-component-renderer/types/HostToWorkerRenderContext';
|
||||
import { type WorkerExports } from '@/front-component-renderer/types/WorkerExports';
|
||||
import { type FrontComponentExecutionContext } from '@/sdk/front-component-api';
|
||||
import { FrontComponentErrorEffect } from '@/remote/components/FrontComponentErrorEffect';
|
||||
import { FrontComponentHostCommunicationApiEffect } from '@/remote/components/FrontComponentHostCommunicationApiEffect';
|
||||
import { FrontComponentUpdateContextEffect } from '@/remote/components/FrontComponentUpdateContextEffect';
|
||||
import { type FrontComponentHostCommunicationApi } from '@/types/FrontComponentHostCommunicationApi';
|
||||
import { type SdkClientUrls } from '@/types/HostToWorkerRenderContext';
|
||||
import { type WorkerExports } from '@/types/WorkerExports';
|
||||
import { type FrontComponentExecutionContext } from 'twenty-sdk';
|
||||
import { type ThreadWebWorker } from '@quilted/threads';
|
||||
import {
|
||||
type RemoteReceiver,
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
|
||||
import { EVENT_TO_REACT } from '@/sdk/front-component-api/constants/EventToReact';
|
||||
import { type SerializedEventData } from '@/sdk/front-component-api/constants/SerializedEventData';
|
||||
import { EVENT_TO_REACT } from '@/constants/EventToReact';
|
||||
import { type SerializedEventData } from '@/constants/SerializedEventData';
|
||||
|
||||
const INTERNAL_PROPS = new Set(['element', 'receiver', 'components']);
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
export { FrontComponentRenderer } from './host/components/FrontComponentRenderer';
|
||||
export { componentRegistry } from './host/generated/host-component-registry';
|
||||
export { FrontComponentErrorEffect } from './remote/components/FrontComponentErrorEffect';
|
||||
export { FrontComponentHostCommunicationApiEffect } from './remote/components/FrontComponentHostCommunicationApiEffect';
|
||||
export { FrontComponentUpdateContextEffect } from './remote/components/FrontComponentUpdateContextEffect';
|
||||
export { FrontComponentWorkerEffect } from './remote/components/FrontComponentWorkerEffect';
|
||||
export {
|
||||
HtmlA,
|
||||
HtmlArticle,
|
||||
HtmlAside,
|
||||
HtmlBlockquote,
|
||||
HtmlBr,
|
||||
HtmlButton,
|
||||
HtmlCode,
|
||||
HtmlDiv,
|
||||
HtmlEm,
|
||||
HtmlFooter,
|
||||
HtmlForm,
|
||||
HtmlH1,
|
||||
HtmlH2,
|
||||
HtmlH3,
|
||||
HtmlH4,
|
||||
HtmlH5,
|
||||
HtmlH6,
|
||||
HtmlHeader,
|
||||
HtmlHr,
|
||||
HtmlIframe,
|
||||
HtmlAudio,
|
||||
HtmlImg,
|
||||
HtmlSource,
|
||||
HtmlVideo,
|
||||
HtmlInput,
|
||||
HtmlLabel,
|
||||
HtmlLi,
|
||||
HtmlMain,
|
||||
HtmlNav,
|
||||
HtmlOl,
|
||||
HtmlOption,
|
||||
HtmlP,
|
||||
HtmlPre,
|
||||
HtmlSection,
|
||||
HtmlSelect,
|
||||
HtmlSmall,
|
||||
HtmlSpan,
|
||||
HtmlStrong,
|
||||
HtmlTable,
|
||||
HtmlTbody,
|
||||
HtmlTd,
|
||||
HtmlTextarea,
|
||||
HtmlTfoot,
|
||||
HtmlTh,
|
||||
HtmlThead,
|
||||
HtmlTr,
|
||||
HtmlUl,
|
||||
} from './remote/generated/remote-components';
|
||||
export {
|
||||
HtmlAElement,
|
||||
HtmlArticleElement,
|
||||
HtmlAsideElement,
|
||||
HtmlBlockquoteElement,
|
||||
HtmlBrElement,
|
||||
HtmlButtonElement,
|
||||
HtmlCodeElement,
|
||||
HtmlDivElement,
|
||||
HtmlEmElement,
|
||||
HtmlFooterElement,
|
||||
HtmlFormElement,
|
||||
HtmlH1Element,
|
||||
HtmlH2Element,
|
||||
HtmlH3Element,
|
||||
HtmlH4Element,
|
||||
HtmlH5Element,
|
||||
HtmlH6Element,
|
||||
HtmlHeaderElement,
|
||||
HtmlHrElement,
|
||||
HtmlIframeElement,
|
||||
HtmlAudioElement,
|
||||
HtmlImgElement,
|
||||
HtmlSourceElement,
|
||||
HtmlVideoElement,
|
||||
HtmlInputElement,
|
||||
HtmlLabelElement,
|
||||
HtmlLiElement,
|
||||
HtmlMainElement,
|
||||
HtmlNavElement,
|
||||
HtmlOlElement,
|
||||
HtmlOptionElement,
|
||||
HtmlPElement,
|
||||
HtmlPreElement,
|
||||
HtmlSectionElement,
|
||||
HtmlSelectElement,
|
||||
HtmlSmallElement,
|
||||
HtmlSpanElement,
|
||||
HtmlStrongElement,
|
||||
HtmlTableElement,
|
||||
HtmlTbodyElement,
|
||||
HtmlTdElement,
|
||||
HtmlTextareaElement,
|
||||
HtmlTfootElement,
|
||||
HtmlTheadElement,
|
||||
HtmlThElement,
|
||||
HtmlTrElement,
|
||||
HtmlUlElement,
|
||||
RemoteFragmentElement,
|
||||
RemoteRootElement,
|
||||
} from './remote/generated/remote-elements';
|
||||
export type {
|
||||
HtmlAProperties,
|
||||
HtmlButtonProperties,
|
||||
HtmlCommonEvents,
|
||||
HtmlCommonProperties,
|
||||
HtmlFormProperties,
|
||||
HtmlIframeProperties,
|
||||
HtmlAudioProperties,
|
||||
HtmlImgProperties,
|
||||
HtmlSourceProperties,
|
||||
HtmlVideoProperties,
|
||||
HtmlInputProperties,
|
||||
HtmlLabelProperties,
|
||||
HtmlOptionProperties,
|
||||
HtmlSelectProperties,
|
||||
HtmlTdProperties,
|
||||
HtmlTextareaProperties,
|
||||
HtmlThProperties,
|
||||
} from './remote/generated/remote-elements';
|
||||
export { createRemoteWorker } from './remote/worker/utils/createRemoteWorker';
|
||||
export { installStyleBridge } from './polyfills/installStyleBridge';
|
||||
export { exposeGlobals } from './remote/utils/exposeGlobals';
|
||||
export type { FrontComponentExecutionContext } from 'twenty-sdk';
|
||||
export type { FrontComponentHostCommunicationApi } from './types/FrontComponentHostCommunicationApi';
|
||||
export type {
|
||||
HostToWorkerRenderContext,
|
||||
SdkClientUrls,
|
||||
} from './types/HostToWorkerRenderContext';
|
||||
export type { PropertySchema } from './constants/PropertySchema';
|
||||
export type { WorkerExports } from './types/WorkerExports';
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user