Compare commits
21
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9ea9ff569f | ||
|
|
2df52785ba | ||
|
|
23aa859502 | ||
|
|
773245fa65 | ||
|
|
0f8ee5714f | ||
|
|
7f4f2e932c | ||
|
|
0d05788547 | ||
|
|
837a946b5f | ||
|
|
cb0b71dbdc | ||
|
|
546ab0a036 | ||
|
|
89eeb34ca7 | ||
|
|
ee8004922e | ||
|
|
18b9cc5281 | ||
|
|
284ebeb12d | ||
|
|
fa903c6971 | ||
|
|
e294d74e07 | ||
|
|
59f2b1c724 | ||
|
|
4aca4d1143 | ||
|
|
1553ff2857 | ||
|
|
9441e0456c | ||
|
|
7999cd3dde |
@@ -105,7 +105,7 @@ jobs:
|
||||
create-twenty-app --version
|
||||
mkdir -p /tmp/e2e-test-workspace
|
||||
cd /tmp/e2e-test-workspace
|
||||
create-twenty-app test-app --display-name "Test scaffolded app" --description "E2E test scaffolded app" --skip-local-instance
|
||||
create-twenty-app test-app --display-name "Test scaffolded app" --description "E2E test scaffolded app" --skip-local-instance --yes
|
||||
|
||||
- name: Install scaffolded app dependencies
|
||||
run: |
|
||||
|
||||
@@ -20,15 +20,7 @@ jobs:
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.CI_PRIVILEGED_DISPATCH_TOKEN }}
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
||||
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
|
||||
PR_AUTHOR_ASSOCIATION: ${{ github.event.pull_request.author_association }}
|
||||
REPO: ${{ github.repository }}
|
||||
run: |
|
||||
gh api repos/twentyhq/ci-privileged/dispatches \
|
||||
-f event_type=pr-review \
|
||||
-f "client_payload[pr_number]=$PR_NUMBER" \
|
||||
-f "client_payload[pr_head_sha]=$PR_HEAD_SHA" \
|
||||
-f "client_payload[pr_author]=$PR_AUTHOR" \
|
||||
-f "client_payload[pr_author_association]=$PR_AUTHOR_ASSOCIATION" \
|
||||
-f "client_payload[repo]=$REPO"
|
||||
-f "client_payload[pr_number]=$PR_NUMBER"
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
Twenty gives technical teams the building blocks for a custom CRM that meets complex business needs and quickly adapts as the business evolves. Twenty is the CRM you build, ship, and version like the rest of your stack.
|
||||
|
||||
<a href="https://twenty.com/why-twenty"><img src="./packages/twenty-website-new/public/images/readme/star-icon.svg" width="14" height="14"/> Learn more about why we built Twenty</a>
|
||||
<a href="https://twenty.com/resources/why-twenty"><img src="./packages/twenty-website-new/public/images/readme/star-icon.svg" width="14" height="14"/> Learn more about why we built Twenty</a>
|
||||
|
||||
<br />
|
||||
|
||||
|
||||
@@ -60,7 +60,6 @@
|
||||
"packages/twenty-sdk",
|
||||
"packages/twenty-front-component-renderer",
|
||||
"packages/twenty-client-sdk",
|
||||
"packages/twenty-apps",
|
||||
"packages/twenty-cli",
|
||||
"packages/create-twenty-app",
|
||||
"packages/twenty-oxlint-rules",
|
||||
|
||||
@@ -4,12 +4,10 @@ import {
|
||||
APP_DESCRIPTION,
|
||||
APP_DISPLAY_NAME,
|
||||
APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
DEFAULT_ROLE_UNIVERSAL_IDENTIFIER,
|
||||
} from 'src/constants/universal-identifiers';
|
||||
|
||||
export default defineApplication({
|
||||
universalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
displayName: APP_DISPLAY_NAME,
|
||||
description: APP_DESCRIPTION,
|
||||
defaultRoleUniversalIdentifier: DEFAULT_ROLE_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { defineRole } from 'twenty-sdk/define';
|
||||
import { defineApplicationRole } from 'twenty-sdk/define';
|
||||
|
||||
import {
|
||||
APP_DISPLAY_NAME,
|
||||
DEFAULT_ROLE_UNIVERSAL_IDENTIFIER,
|
||||
} from 'src/constants/universal-identifiers';
|
||||
|
||||
export default defineRole({
|
||||
export default defineApplicationRole({
|
||||
universalIdentifier: DEFAULT_ROLE_UNIVERSAL_IDENTIFIER,
|
||||
label: `${APP_DISPLAY_NAME} default function role`,
|
||||
description: `${APP_DISPLAY_NAME} default function role`,
|
||||
|
||||
@@ -16,7 +16,6 @@ import {
|
||||
containerExists,
|
||||
detectLocalServer,
|
||||
serverStart,
|
||||
type ServerStartResult,
|
||||
} from 'twenty-sdk/cli';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
@@ -33,6 +32,8 @@ type CreateAppOptions = {
|
||||
};
|
||||
|
||||
export class CreateAppCommand {
|
||||
private static TOTAL_STEPS = 4;
|
||||
|
||||
async execute(options: CreateAppOptions = {}): Promise<void> {
|
||||
const { appName, appDisplayName, appDirectory, appDescription } =
|
||||
await this.getAppInfos(options);
|
||||
@@ -40,9 +41,26 @@ export class CreateAppCommand {
|
||||
try {
|
||||
await this.validateDirectory(appDirectory);
|
||||
|
||||
this.logCreationInfo({ appDirectory, appName });
|
||||
const confirmed = await this.promptScaffoldConfirmation({
|
||||
appName,
|
||||
appDisplayName,
|
||||
appDescription,
|
||||
appDirectory,
|
||||
autoConfirm: options.yes,
|
||||
});
|
||||
|
||||
if (!confirmed) {
|
||||
console.log(chalk.gray('\nScaffolding cancelled.'));
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
console.log('');
|
||||
|
||||
this.logStep(1, 'Creating project directory');
|
||||
await fs.ensureDir(appDirectory);
|
||||
this.logDetail(appDirectory);
|
||||
|
||||
this.logStep(2, 'Scaffolding project files');
|
||||
|
||||
if (options.example) {
|
||||
const exampleSucceeded = await this.tryDownloadExample(
|
||||
@@ -56,6 +74,7 @@ export class CreateAppCommand {
|
||||
appDisplayName,
|
||||
appDescription,
|
||||
appDirectory,
|
||||
onProgress: (message) => this.logDetail(message),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
@@ -64,33 +83,59 @@ export class CreateAppCommand {
|
||||
appDisplayName,
|
||||
appDescription,
|
||||
appDirectory,
|
||||
onProgress: (message) => this.logDetail(message),
|
||||
});
|
||||
}
|
||||
|
||||
await install(appDirectory);
|
||||
this.logStep(3, 'Installing dependencies');
|
||||
await install(appDirectory, (message) => this.logDetail(message));
|
||||
|
||||
await tryGitInit(appDirectory);
|
||||
this.logStep(4, 'Initializing Git repository');
|
||||
const gitInitialized = await tryGitInit(appDirectory);
|
||||
|
||||
let serverResult: ServerStartResult | undefined;
|
||||
if (gitInitialized) {
|
||||
this.logDetail('Initialized on branch main');
|
||||
this.logDetail('Created initial commit');
|
||||
} else {
|
||||
this.logDetail(
|
||||
'Skipped (Git unavailable, initialization failed, or already in a repository)',
|
||||
);
|
||||
}
|
||||
|
||||
console.log('');
|
||||
|
||||
let hasLocalServer = false;
|
||||
let authSucceeded = false;
|
||||
|
||||
if (!options.skipLocalInstance) {
|
||||
const shouldStartServer = await this.shouldStartServer(options.yes);
|
||||
const existingServerUrl = await detectLocalServer();
|
||||
|
||||
if (shouldStartServer) {
|
||||
const startResult = await serverStart({
|
||||
onProgress: (message: string) => console.log(chalk.gray(message)),
|
||||
});
|
||||
if (existingServerUrl) {
|
||||
hasLocalServer = true;
|
||||
authSucceeded = await this.promptConnectToLocal(existingServerUrl);
|
||||
} else {
|
||||
const shouldStart = await this.shouldStartServer(options.yes);
|
||||
|
||||
if (startResult.success) {
|
||||
serverResult = startResult.data;
|
||||
await this.promptConnectToLocal(serverResult.url);
|
||||
if (shouldStart) {
|
||||
const startResult = await serverStart({
|
||||
onProgress: (message: string) => console.log(chalk.gray(message)),
|
||||
});
|
||||
|
||||
if (startResult.success) {
|
||||
hasLocalServer = true;
|
||||
authSucceeded = await this.promptConnectToLocal(
|
||||
startResult.data.url,
|
||||
);
|
||||
} else {
|
||||
console.log(chalk.yellow(`\n${startResult.error.message}`));
|
||||
}
|
||||
} else {
|
||||
console.log(chalk.yellow(`\n${startResult.error.message}`));
|
||||
this.logServerSkipped();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.logSuccess(appDirectory, serverResult);
|
||||
this.logSuccess(appDirectory, hasLocalServer, authSucceeded);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
chalk.red('\nCreate application failed:'),
|
||||
@@ -213,25 +258,80 @@ export class CreateAppCommand {
|
||||
}
|
||||
}
|
||||
|
||||
private logCreationInfo({
|
||||
appDirectory,
|
||||
private async promptScaffoldConfirmation({
|
||||
appName,
|
||||
appDisplayName,
|
||||
appDescription,
|
||||
appDirectory,
|
||||
autoConfirm,
|
||||
}: {
|
||||
appDirectory: string;
|
||||
appName: string;
|
||||
}): void {
|
||||
appDisplayName: string;
|
||||
appDescription: string;
|
||||
appDirectory: string;
|
||||
autoConfirm?: boolean;
|
||||
}): Promise<boolean> {
|
||||
console.log(chalk.blue('\nCreating Twenty Application\n'));
|
||||
console.log(chalk.white(` Name: ${appName}`));
|
||||
console.log(chalk.white(` Display name: ${appDisplayName}`));
|
||||
|
||||
if (appDescription) {
|
||||
console.log(chalk.white(` Description: ${appDescription}`));
|
||||
}
|
||||
|
||||
console.log(chalk.white(` Directory: ${appDirectory}`));
|
||||
|
||||
console.log(chalk.white('\nThe following steps will be performed:\n'));
|
||||
console.log(chalk.gray(' 1. Create project directory'));
|
||||
console.log(
|
||||
chalk.blue('\n', 'Creating Twenty Application\n'),
|
||||
chalk.gray(`- Directory: ${appDirectory}\n`, `- Name: ${appName}\n`),
|
||||
chalk.gray(
|
||||
' 2. Scaffold project files from base template\n' +
|
||||
' - Copy template files\n' +
|
||||
' - Configure dotfiles (.gitignore, .github)\n' +
|
||||
' - Generate unique application identifiers\n' +
|
||||
' - Update package.json with app name and SDK versions',
|
||||
),
|
||||
);
|
||||
console.log(chalk.gray(' 3. Install dependencies (yarn)'));
|
||||
console.log(
|
||||
chalk.gray(' 4. Initialize Git repository with initial commit'),
|
||||
);
|
||||
console.log('');
|
||||
|
||||
if (autoConfirm) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const { proceed } = await inquirer.prompt([
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'proceed',
|
||||
message: 'Proceed?',
|
||||
default: true,
|
||||
},
|
||||
]);
|
||||
|
||||
return proceed;
|
||||
}
|
||||
|
||||
private logStep(step: number, title: string): void {
|
||||
console.log(
|
||||
chalk.blue(`\n[${step}/${CreateAppCommand.TOTAL_STEPS}]`) +
|
||||
chalk.white(` ${title}...`),
|
||||
);
|
||||
}
|
||||
|
||||
private async shouldStartServer(autoConfirm?: boolean): Promise<boolean> {
|
||||
const existingServerUrl = await detectLocalServer();
|
||||
private logDetail(message: string): void {
|
||||
console.log(chalk.gray(` → ${message}`));
|
||||
}
|
||||
|
||||
if (existingServerUrl) {
|
||||
return true;
|
||||
}
|
||||
private async shouldStartServer(autoConfirm?: boolean): Promise<boolean> {
|
||||
console.log(
|
||||
chalk.white(
|
||||
'\n A local Twenty instance is required for app development.\n' +
|
||||
' It provides the API and schema your application connects to.\n',
|
||||
),
|
||||
);
|
||||
|
||||
if (checkDockerRunning() && containerExists()) {
|
||||
if (autoConfirm) {
|
||||
@@ -268,12 +368,31 @@ export class CreateAppCommand {
|
||||
return startDocker;
|
||||
}
|
||||
|
||||
private async promptConnectToLocal(serverUrl: string): Promise<void> {
|
||||
private logServerSkipped(): void {
|
||||
console.log(
|
||||
chalk.gray(
|
||||
'\n To start a Twenty instance later:\n' +
|
||||
' yarn twenty server start\n\n' +
|
||||
' To connect to a remote instance instead:\n' +
|
||||
' yarn twenty remote add\n',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
private async promptConnectToLocal(serverUrl: string): Promise<boolean> {
|
||||
console.log(
|
||||
chalk.white(
|
||||
'\n Authentication links your app to a Twenty instance so you can\n' +
|
||||
' sync custom objects, fields, and roles during development.\n' +
|
||||
' This will open a browser window to complete the OAuth flow.\n',
|
||||
),
|
||||
);
|
||||
|
||||
const { shouldAuthenticate } = await inquirer.prompt([
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'shouldAuthenticate',
|
||||
message: `Would you like to authenticate to the local Twenty instance (${serverUrl})?`,
|
||||
message: `Authenticate to the local Twenty instance (${serverUrl})?`,
|
||||
default: true,
|
||||
},
|
||||
]);
|
||||
@@ -281,13 +400,22 @@ export class CreateAppCommand {
|
||||
if (!shouldAuthenticate) {
|
||||
console.log(
|
||||
chalk.gray(
|
||||
'Authentication skipped. Run `yarn twenty remote add --local` manually.',
|
||||
'\n Authentication skipped. To authenticate later:\n' +
|
||||
` yarn twenty remote add --local\n`,
|
||||
),
|
||||
);
|
||||
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
await inquirer.prompt([
|
||||
{
|
||||
type: 'input',
|
||||
name: 'confirm',
|
||||
message: 'Press Enter to open the browser for authentication...',
|
||||
},
|
||||
]);
|
||||
|
||||
try {
|
||||
const result = await authLoginOAuth({
|
||||
apiUrl: serverUrl,
|
||||
@@ -298,12 +426,16 @@ export class CreateAppCommand {
|
||||
const configService = new ConfigService();
|
||||
|
||||
await configService.setDefaultRemote('local');
|
||||
|
||||
return true;
|
||||
} else {
|
||||
console.log(
|
||||
chalk.yellow(
|
||||
'Authentication failed. Run `yarn twenty remote add --local` manually.',
|
||||
),
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
} catch {
|
||||
console.log(
|
||||
@@ -311,28 +443,44 @@ export class CreateAppCommand {
|
||||
'Authentication failed. Run `yarn twenty remote add` manually.',
|
||||
),
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private logSuccess(
|
||||
appDirectory: string,
|
||||
serverResult?: ServerStartResult,
|
||||
hasLocalServer: boolean,
|
||||
authSucceeded: boolean,
|
||||
): void {
|
||||
const dirName = basename(appDirectory);
|
||||
|
||||
console.log(chalk.blue('\nApplication created. Next steps:'));
|
||||
console.log(chalk.gray(`- cd ${dirName}`));
|
||||
console.log(chalk.green('\n✔ Application created successfully!\n'));
|
||||
console.log(chalk.white(' Next steps:\n'));
|
||||
|
||||
if (!serverResult) {
|
||||
console.log(
|
||||
chalk.gray(
|
||||
'- yarn twenty remote add # Authenticate with Twenty',
|
||||
),
|
||||
);
|
||||
let stepNumber = 1;
|
||||
|
||||
console.log(chalk.white(` ${stepNumber}. Navigate to your project`));
|
||||
console.log(chalk.cyan(` cd ${dirName}\n`));
|
||||
stepNumber++;
|
||||
|
||||
if (!authSucceeded) {
|
||||
const remoteCommand = hasLocalServer
|
||||
? 'yarn twenty remote add --local'
|
||||
: 'yarn twenty remote add';
|
||||
|
||||
console.log(chalk.white(` ${stepNumber}. Connect to a Twenty instance`));
|
||||
console.log(chalk.cyan(` ${remoteCommand}\n`));
|
||||
stepNumber++;
|
||||
}
|
||||
|
||||
console.log(chalk.white(` ${stepNumber}. Start developing`));
|
||||
console.log(chalk.cyan(' yarn twenty dev\n'));
|
||||
|
||||
console.log(
|
||||
chalk.gray('- yarn twenty dev # Start dev mode'),
|
||||
chalk.gray(
|
||||
' Documentation: https://docs.twenty.com/developers/extend/capabilities/apps',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ import { join } from 'path';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import createTwentyAppPackageJson from 'package.json';
|
||||
import chalk from 'chalk';
|
||||
|
||||
const SRC_FOLDER = 'src';
|
||||
|
||||
@@ -12,27 +11,33 @@ export const copyBaseApplicationProject = async ({
|
||||
appDisplayName,
|
||||
appDescription,
|
||||
appDirectory,
|
||||
onProgress,
|
||||
}: {
|
||||
appName: string;
|
||||
appDisplayName: string;
|
||||
appDescription: string;
|
||||
appDirectory: string;
|
||||
onProgress?: (message: string) => void;
|
||||
}) => {
|
||||
console.log(chalk.gray('Generating application project...'));
|
||||
onProgress?.('Copying base template');
|
||||
await fs.copy(join(__dirname, './constants/template'), appDirectory);
|
||||
|
||||
onProgress?.('Configuring dotfiles (.gitignore, .github)');
|
||||
await renameDotfiles({ appDirectory });
|
||||
|
||||
onProgress?.('Mirroring AGENTS.md to CLAUDE.md');
|
||||
await mirrorAgentsToClaude({ appDirectory });
|
||||
|
||||
await addEmptyPublicDirectory({ appDirectory });
|
||||
|
||||
onProgress?.('Generating unique application identifiers');
|
||||
await generateUniversalIdentifiers({
|
||||
appDisplayName,
|
||||
appDescription,
|
||||
appDirectory,
|
||||
});
|
||||
|
||||
onProgress?.('Updating package.json');
|
||||
await updatePackageJson({ appName, appDirectory });
|
||||
};
|
||||
|
||||
|
||||
@@ -4,14 +4,18 @@ import { exec } from 'child_process';
|
||||
|
||||
const execPromise = promisify(exec);
|
||||
|
||||
export const install = async (root: string) => {
|
||||
console.log(chalk.gray('Installing yarn dependencies...'));
|
||||
export const install = async (
|
||||
root: string,
|
||||
onProgress?: (message: string) => void,
|
||||
) => {
|
||||
onProgress?.('Enabling corepack');
|
||||
try {
|
||||
await execPromise('corepack enable', { cwd: root });
|
||||
} catch (error: any) {
|
||||
console.warn(chalk.yellow('corepack enabled failed:'), error.stderr);
|
||||
console.warn(chalk.yellow('corepack enable failed:'), error.stderr);
|
||||
}
|
||||
|
||||
onProgress?.('Running yarn install');
|
||||
try {
|
||||
await execPromise('yarn install', { cwd: root });
|
||||
} catch (error: any) {
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
## Base documentation
|
||||
|
||||
- Documentation: https://docs.twenty.com/developers/extend/apps/getting-started
|
||||
- Rich app example: https://github.com/twentyhq/twenty/tree/main/packages/twenty-apps/examples/postcard
|
||||
|
||||
## UUID requirement
|
||||
|
||||
- All generated UUIDs must be valid UUID v4.
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
- Creating an object without an index view associated. Unless this is a technical object, user will need to visualize it.
|
||||
- Creating a view without a navigationMenuItem associated. This will make the view available on the left sidebar.
|
||||
- Creating a front-end component that has a scroll instead of being responsive to its fixed widget height and width, unless it is specifically meant to be used in a canvas tab.
|
||||
@@ -0,0 +1,14 @@
|
||||
## Base documentation
|
||||
|
||||
- Documentation: https://docs.twenty.com/developers/extend/apps/getting-started
|
||||
- Rich app example: https://github.com/twentyhq/twenty/tree/main/packages/twenty-apps/examples/postcard
|
||||
|
||||
## UUID requirement
|
||||
|
||||
- All generated UUIDs must be valid UUID v4.
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
- Creating an object without an index view associated. Unless this is a technical object, user will need to visualize it.
|
||||
- Creating a view without a navigationMenuItem associated. This will make the view available on the left sidebar.
|
||||
- Creating a front-end component that has a scroll instead of being responsive to its fixed widget height and width, unless it is specifically meant to be used in a canvas tab.
|
||||
@@ -0,0 +1,14 @@
|
||||
## Base documentation
|
||||
|
||||
- Documentation: https://docs.twenty.com/developers/extend/apps/getting-started
|
||||
- Rich app example: https://github.com/twentyhq/twenty/tree/main/packages/twenty-apps/examples/postcard
|
||||
|
||||
## UUID requirement
|
||||
|
||||
- All generated UUIDs must be valid UUID v4.
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
- Creating an object without an index view associated. Unless this is a technical object, user will need to visualize it.
|
||||
- Creating a view without a navigationMenuItem associated. This will make the view available on the left sidebar.
|
||||
- Creating a front-end component that has a scroll instead of being responsive to its fixed widget height and width, unless it is specifically meant to be used in a canvas tab.
|
||||
@@ -20,7 +20,7 @@
|
||||
"test:watch": "vitest --config vitest.unit.config.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"twenty-sdk": "2.1.0"
|
||||
"twenty-sdk": "2.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^24.7.2",
|
||||
|
||||
+31
@@ -31,4 +31,35 @@ export default defineLogicFunction({
|
||||
required: ['teamId', 'title'],
|
||||
},
|
||||
},
|
||||
workflowActionTriggerSettings: {
|
||||
label: 'Create Linear Issue',
|
||||
inputSchema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
teamId: { type: 'string' },
|
||||
title: { type: 'string' },
|
||||
description: { type: 'string' },
|
||||
},
|
||||
},
|
||||
],
|
||||
outputSchema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
success: { type: 'boolean' },
|
||||
issue: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string' },
|
||||
identifier: { type: 'string' },
|
||||
title: { type: 'string' },
|
||||
url: { type: 'string' },
|
||||
},
|
||||
},
|
||||
error: { type: 'string' },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1 +0,0 @@
|
||||
{"tags": ["scope:apps"]}
|
||||
@@ -13,7 +13,6 @@ Every app must have exactly one `defineApplication` call. It declares:
|
||||
|
||||
```ts src/application-config.ts
|
||||
import { defineApplication } from 'twenty-sdk/define';
|
||||
import { DEFAULT_ROLE_UNIVERSAL_IDENTIFIER } from 'src/roles/default-role';
|
||||
|
||||
export default defineApplication({
|
||||
universalIdentifier: '39783023-bcac-41e3-b0d2-ff1944d8465d',
|
||||
@@ -27,19 +26,19 @@ export default defineApplication({
|
||||
isSecret: false,
|
||||
},
|
||||
},
|
||||
defaultRoleUniversalIdentifier: DEFAULT_ROLE_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
```
|
||||
|
||||
Notes:
|
||||
- `universalIdentifier` fields are deterministic IDs you own. Generate them once and keep them stable across syncs.
|
||||
- `applicationVariables` become environment variables for your functions and front components (e.g., `DEFAULT_RECIPIENT_NAME` is available as `process.env.DEFAULT_RECIPIENT_NAME`).
|
||||
- `defaultRoleUniversalIdentifier` must reference a role defined with [`defineRole()`](/developers/extend/apps/config/roles).
|
||||
- The default role is detected automatically from the role file marked with [`defineApplicationRole()`](/developers/extend/apps/config/roles) — you do not need to reference it from `defineApplication()`.
|
||||
- Pre-install and post-install functions are detected automatically during the manifest build — you do not need to reference them in `defineApplication()`.
|
||||
- Passing `defaultRoleUniversalIdentifier` explicitly is still supported for backward compatibility, but is deprecated in favor of `defineApplicationRole()`.
|
||||
|
||||
## Default function role
|
||||
|
||||
The `defaultRoleUniversalIdentifier` controls what the app's logic functions and front components can access:
|
||||
The role declared with [`defineApplicationRole()`](/developers/extend/apps/config/roles) controls what the app's logic functions and front components can access:
|
||||
|
||||
- The runtime token injected as `TWENTY_APP_ACCESS_TOKEN` is derived from this role.
|
||||
- The typed API client is restricted to the permissions granted to that role.
|
||||
|
||||
@@ -4,7 +4,7 @@ description: Declare what objects and fields your app's logic functions and fron
|
||||
icon: "shield-halved"
|
||||
---
|
||||
|
||||
A **role** is a permission set: which objects an app can read or write, which fields it can see, and which platform-level capabilities it can use. Every app's logic functions and front components inherit the permissions of the role declared as `defaultRoleUniversalIdentifier` in [`defineApplication`](/developers/extend/apps/config/application).
|
||||
A **role** is a permission set: which objects an app can read or write, which fields it can see, and which platform-level capabilities it can use. Every app's logic functions and front components inherit the permissions of the role marked with `defineApplicationRole()` (see [The default function role](#the-default-function-role) below).
|
||||
|
||||
```ts src/roles/restricted-company-role.ts
|
||||
import {
|
||||
@@ -51,15 +51,15 @@ export default defineRole({
|
||||
|
||||
## The default function role
|
||||
|
||||
When you scaffold a new app, the CLI creates a default role file:
|
||||
When you scaffold a new app, the CLI creates a default role file declared with `defineApplicationRole()`:
|
||||
|
||||
```ts src/roles/default-role.ts
|
||||
import { defineRole, PermissionFlag } from 'twenty-sdk/define';
|
||||
import { defineApplicationRole, PermissionFlag } from 'twenty-sdk/define';
|
||||
|
||||
export const DEFAULT_ROLE_UNIVERSAL_IDENTIFIER =
|
||||
'b648f87b-1d26-4961-b974-0908fd991061';
|
||||
|
||||
export default defineRole({
|
||||
export default defineApplicationRole({
|
||||
universalIdentifier: DEFAULT_ROLE_UNIVERSAL_IDENTIFIER,
|
||||
label: 'Default function role',
|
||||
description: 'Default role for function Twenty client',
|
||||
@@ -77,10 +77,12 @@ export default defineRole({
|
||||
});
|
||||
```
|
||||
|
||||
This role's `universalIdentifier` is referenced from `application-config.ts` as `defaultRoleUniversalIdentifier`:
|
||||
`defineApplicationRole()` is a thin wrapper around `defineRole()` that flags **the** role used as your application's default at install time. Validation is identical to `defineRole`, but the build pipeline auto-wires its `universalIdentifier` into the application manifest's `defaultRoleUniversalIdentifier` — so you do not need to reference it from [`defineApplication`](/developers/extend/apps/config/application) yourself.
|
||||
|
||||
- **`*.role.ts`** declares what the role can do.
|
||||
- **`application-config.ts`** points to that role so your functions inherit its permissions.
|
||||
Notes:
|
||||
- Exactly **one** `defineApplicationRole(...)` is allowed per app — the manifest build will fail if it finds more than one.
|
||||
- Use `defineRole()` (not `defineApplicationRole()`) for any **additional** roles your app ships.
|
||||
- Setting `defaultRoleUniversalIdentifier` explicitly on `defineApplication()` is still supported for backward compatibility, but is deprecated in favor of `defineApplicationRole()`.
|
||||
|
||||
## Best practices
|
||||
|
||||
|
||||
@@ -52,7 +52,6 @@ export default defineApplication({
|
||||
universalIdentifier: '...',
|
||||
displayName: 'Linear',
|
||||
description: 'Connect Linear to Twenty.',
|
||||
defaultRoleUniversalIdentifier: '...',
|
||||
// OAuth client credentials live on the app registration (one OAuth app per
|
||||
// Twenty server, configured by the admin) — not per-workspace. Declare them
|
||||
// as serverVariables so the admin can fill them in once for all installs.
|
||||
|
||||
@@ -372,5 +372,5 @@ Key points:
|
||||
- `TWENTY_API_URL` — Base URL of the Twenty API
|
||||
- `TWENTY_APP_ACCESS_TOKEN` — Short-lived key scoped to your application's default function role
|
||||
|
||||
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`.
|
||||
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 declared with `defineApplicationRole()` (or referenced via `defaultRoleUniversalIdentifier` in `application-config.ts`).
|
||||
</Note>
|
||||
|
||||
@@ -187,7 +187,6 @@ export default defineApplication({
|
||||
universalIdentifier: '...',
|
||||
displayName: 'My App',
|
||||
description: 'A great app',
|
||||
defaultRoleUniversalIdentifier: DEFAULT_ROLE_UNIVERSAL_IDENTIFIER,
|
||||
logoUrl: 'public/logo.png',
|
||||
screenshots: [
|
||||
'public/screenshot-1.png',
|
||||
|
||||
@@ -4293,7 +4293,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Data",
|
||||
"group": "Dados",
|
||||
"pages": [
|
||||
"l/pt/developers/extend/apps/data/overview",
|
||||
"l/pt/developers/extend/apps/data/objects",
|
||||
|
||||
@@ -13,7 +13,6 @@ Jede App muss genau einen Aufruf von `defineApplication` haben. Dieser deklarier
|
||||
|
||||
```ts src/application-config.ts
|
||||
import { defineApplication } from 'twenty-sdk/define';
|
||||
import { DEFAULT_ROLE_UNIVERSAL_IDENTIFIER } from 'src/roles/default-role';
|
||||
|
||||
export default defineApplication({
|
||||
universalIdentifier: '39783023-bcac-41e3-b0d2-ff1944d8465d',
|
||||
@@ -27,7 +26,6 @@ export default defineApplication({
|
||||
isSecret: false,
|
||||
},
|
||||
},
|
||||
defaultRoleUniversalIdentifier: DEFAULT_ROLE_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
```
|
||||
|
||||
@@ -35,12 +33,13 @@ Notizen:
|
||||
|
||||
* `universalIdentifier`-Felder sind deterministische IDs, die Ihnen gehören. Erzeugen Sie sie einmal und halten Sie sie über Synchronisierungen hinweg stabil.
|
||||
* `applicationVariables` werden zu Umgebungsvariablen für Ihre Funktionen und Frontend-Komponenten (z. B. ist `DEFAULT_RECIPIENT_NAME` als `process.env.DEFAULT_RECIPIENT_NAME` verfügbar).
|
||||
* `defaultRoleUniversalIdentifier` muss auf eine mit [`defineRole()`](/l/de/developers/extend/apps/config/roles) definierte Rolle verweisen.
|
||||
* Die Standardrolle wird automatisch aus der Rollen-Datei erkannt, die mit [`defineApplicationRole()`](/l/de/developers/extend/apps/config/roles) markiert ist – Sie müssen sie nicht aus `defineApplication()` referenzieren.
|
||||
* Pre- und Post-Installationsfunktionen werden während des Manifest-Builds automatisch erkannt — Sie müssen sie in `defineApplication()` nicht referenzieren.
|
||||
* Die explizite Übergabe von `defaultRoleUniversalIdentifier` wird für die Abwärtskompatibilität weiterhin unterstützt, ist jedoch zugunsten von `defineApplicationRole()` veraltet.
|
||||
|
||||
## Standard-Funktionsrolle
|
||||
|
||||
Der `defaultRoleUniversalIdentifier` steuert, worauf die Logikfunktionen und Frontend-Komponenten der App zugreifen können:
|
||||
Die mit [`defineApplicationRole()`](/l/de/developers/extend/apps/config/roles) deklarierte Rolle steuert, worauf die Logikfunktionen und Frontend-Komponenten der App zugreifen können:
|
||||
|
||||
* Das zur Laufzeit als `TWENTY_APP_ACCESS_TOKEN` injizierte Token wird aus dieser Rolle abgeleitet.
|
||||
* Der typisierte API-Client ist auf die dieser Rolle gewährten Berechtigungen beschränkt.
|
||||
|
||||
@@ -20,9 +20,9 @@ Jede App darf **höchstens eine Pre-Install-Funktion** und **höchstens eine Pos
|
||||
```
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="definePostInstallLogicFunction" description="Wird ausgeführt, nachdem die Workspace-Metadatenmigration angewendet wurde">
|
||||
<Accordion title="definePostInstallLogicFunction" description="Wird ausgeführt, nachdem die Metadatenmigration des Arbeitsbereichs angewendet wurde">
|
||||
|
||||
Eine Post-Install-Funktion wird automatisch ausgeführt, sobald Ihre App die Installation in einem Workspace abgeschlossen hat. Der Server führt sie **nach** der Synchronisierung der Metadaten der App und der Generierung des SDK-Clients aus, sodass der Arbeitsbereich vollständig einsatzbereit ist und das neue Schema bereitsteht. Typische Anwendungsfälle umfassen das Befüllen von Standarddaten, das Erstellen anfänglicher Datensätze, das Konfigurieren von Arbeitsbereichseinstellungen oder das Bereitstellen von Ressourcen bei Diensten von Drittanbietern.
|
||||
Eine Post-Install-Funktion wird automatisch ausgeführt, sobald Ihre App die Installation in einem Arbeitsbereich abgeschlossen hat. Der Server führt sie **nach** der Synchronisierung der Metadaten der App und der Generierung des SDK-Clients aus, sodass der Arbeitsbereich vollständig einsatzbereit ist und das neue Schema bereitsteht. Typische Anwendungsfälle umfassen das Befüllen von Standarddaten, das Erstellen anfänglicher Datensätze, das Konfigurieren von Arbeitsbereichseinstellungen oder das Bereitstellen von Ressourcen bei Diensten von Drittanbietern.
|
||||
|
||||
```ts src/logic-functions/post-install.ts
|
||||
import { definePostInstallLogicFunction, type InstallPayload } from 'twenty-sdk/define';
|
||||
@@ -60,12 +60,12 @@ Hauptpunkte:
|
||||
* Pro Anwendung ist nur eine Post-Installationsfunktion zulässig. Der Manifest-Build schlägt fehl, wenn mehr als eine erkannt wird.
|
||||
* Die `universalIdentifier`, `shouldRunOnVersionUpgrade` und `shouldRunSynchronously` der Funktion werden während des Builds automatisch dem Anwendungsmanifest unter dem Feld `postInstallLogicFunction` hinzugefügt – Sie müssen sie in [`defineApplication()`](/l/de/developers/extend/apps/config/application) nicht referenzieren.
|
||||
* Das standardmäßige Timeout ist auf 300 Sekunden (5 Minuten) festgelegt, um längere Einrichtungsvorgänge wie Daten-Seeding zu ermöglichen.
|
||||
* **Nicht im Dev-Modus ausgeführt**: Wenn eine App lokal registriert ist (über `yarn twenty dev`), überspringt der Server den Installationsablauf vollständig und synchronisiert Dateien direkt über den CLI-Watcher — daher läuft Post-Install im Dev-Modus nie, unabhängig von `shouldRunSynchronously`. Verwenden Sie `yarn twenty exec --postInstall`, um es manuell gegen einen laufenden Workspace auszulösen.
|
||||
* **Nicht im Dev-Modus ausgeführt**: Wenn eine App lokal registriert ist (über `yarn twenty dev`), überspringt der Server den Installationsablauf vollständig und synchronisiert Dateien direkt über den CLI-Watcher — daher läuft Post-Install im Dev-Modus nie, unabhängig von `shouldRunSynchronously`. Verwenden Sie `yarn twenty exec --postInstall`, um es manuell gegen einen laufenden Arbeitsbereich auszulösen.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="definePreInstallLogicFunction" description="Wird ausgeführt, bevor die Workspace-Metadatenmigration angewendet wird">
|
||||
<Accordion title="definePreInstallLogicFunction" description="Wird ausgeführt, bevor die Metadatenmigration des Arbeitsbereichs angewendet wird">
|
||||
|
||||
Eine Pre-Install-Funktion wird automatisch während der Installation ausgeführt, **bevor die Workspace-Metadatenmigration angewendet wird**. Sie hat die gleiche Payload-Struktur wie Post-Install (`InstallPayload`), ist aber früher im Installationsablauf positioniert, sodass sie Zustände vorbereiten kann, von denen die bevorstehende Migration abhängt — typische Anwendungsfälle sind das Sichern von Daten, die Validierung der Kompatibilität mit dem neuen Schema oder das Archivieren von Datensätzen, die umstrukturiert oder entfernt werden sollen.
|
||||
Eine Pre-Install-Funktion wird automatisch während der Installation ausgeführt, **bevor die Metadatenmigration des Arbeitsbereichs angewendet wird**. Sie hat die gleiche Payload-Struktur wie Post-Install (`InstallPayload`), ist aber früher im Installationsablauf positioniert, sodass sie Zustände vorbereiten kann, von denen die bevorstehende Migration abhängt — typische Anwendungsfälle sind das Sichern von Daten, die Validierung der Kompatibilität mit dem neuen Schema oder das Archivieren von Datensätzen, die umstrukturiert oder entfernt werden sollen.
|
||||
|
||||
```ts src/logic-functions/pre-install.ts
|
||||
import { definePreInstallLogicFunction, type InstallPayload } from 'twenty-sdk/define';
|
||||
@@ -93,8 +93,8 @@ yarn twenty exec --preInstall
|
||||
Hauptpunkte:
|
||||
* Pre-Install-Funktionen verwenden `definePreInstallLogicFunction()` — dieselbe spezialisierte Konfiguration wie bei Post-Install, nur an einen anderen Lifecycle-Slot gebunden.
|
||||
* Sowohl Pre- als auch Post-Install-Handler erhalten denselben `InstallPayload`-Typ: `{ previousVersion?: string; newVersion: string }`. Importieren Sie ihn einmal und verwenden Sie ihn für beide Hooks wieder.
|
||||
* **Wann der Hook ausgeführt wird**: positioniert direkt vor der Metadatenmigration des Workspaces (`synchronizeFromManifest`). Vor der Ausführung führt der Server einen rein additiven "pared-down sync" durch, der die Pre-Install-Funktion der **neuen** Version in den Workspace-Metadaten registriert — sonst wird nichts angefasst — und führt sie dann aus. Da dieser Sync nur additiv ist, sind die Objekte, Felder und Daten der vorherigen Version noch intakt, wenn Ihr Handler läuft: Sie können den Zustand vor der Migration gefahrlos lesen und sichern.
|
||||
* **Ausführungsmodell**: Pre-Install wird **synchron** ausgeführt und **blockiert die Installation**. Wenn der Handler einen Fehler wirft, wird die Installation abgebrochen, bevor Schemaänderungen angewendet werden — der Workspace verbleibt in der vorherigen Version in einem konsistenten Zustand. Das ist beabsichtigt: Pre-Install ist Ihre letzte Chance, ein riskantes Upgrade abzulehnen.
|
||||
* **Wann der Hook ausgeführt wird**: positioniert direkt vor der Metadatenmigration des Arbeitsbereichs (`synchronizeFromManifest`). Vor der Ausführung führt der Server einen rein additiven "pared-down sync" durch, der die Pre-Install-Funktion der **neuen** Version in den Metadaten des Arbeitsbereichs registriert — sonst wird nichts angefasst — und führt sie dann aus. Da dieser Sync nur additiv ist, sind die Objekte, Felder und Daten der vorherigen Version noch intakt, wenn Ihr Handler läuft: Sie können den Zustand vor der Migration gefahrlos lesen und sichern.
|
||||
* **Ausführungsmodell**: Pre-Install wird **synchron** ausgeführt und **blockiert die Installation**. Wenn der Handler einen Fehler wirft, wird die Installation abgebrochen, bevor Schemaänderungen angewendet werden — der Arbeitsbereich verbleibt in der vorherigen Version in einem konsistenten Zustand. Das ist beabsichtigt: Pre-Install ist Ihre letzte Chance, ein riskantes Upgrade abzulehnen.
|
||||
* Wie bei Post-Install ist pro Anwendung nur eine Pre-Installationsfunktion zulässig. Sie wird während des Builds automatisch dem Anwendungsmanifest unter `preInstallLogicFunction` hinzugefügt.
|
||||
* **Nicht im Dev-Modus ausgeführt**: wie bei Post-Install — der Installationsablauf wird für lokal registrierte Apps vollständig übersprungen, daher läuft Pre-Install unter `yarn twenty dev` nie. Verwenden Sie `yarn twenty exec --preInstall`, um es manuell auszulösen.
|
||||
|
||||
@@ -190,7 +190,7 @@ export default definePreInstallLogicFunction({
|
||||
|
||||
| Sie möchten ... | Verwenden |
|
||||
| ------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
|
||||
| Standarddaten befüllen, den Workspace konfigurieren, externe Ressourcen registrieren | `post-install` |
|
||||
| Standarddaten befüllen, den Arbeitsbereich konfigurieren, externe Ressourcen registrieren | `post-install` |
|
||||
| Lang laufendes Seeding oder Drittanbieteraufrufe ausführen, die die Installationsantwort nicht blockieren sollten | `post-install` (Standard — `shouldRunSynchronously: false`, mit Worker-Wiederholungen) |
|
||||
| Schnelle Einrichtung ausführen, auf die sich der Aufrufer unmittelbar nach der Rückkehr des Installationsaufrufs verlassen wird | `post-install` mit `shouldRunSynchronously: true` |
|
||||
| Daten lesen oder sichern, die bei der bevorstehenden Migration verloren gingen | `pre-install` |
|
||||
|
||||
@@ -29,7 +29,7 @@ Die **Konfigurationsebene** einer Twenty-App beschreibt die App *für die Plattf
|
||||
## In diesem Abschnitt
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Anwendungskonfiguration" icon="rocket" href="/l/de/developers/extend/apps/config/application">
|
||||
<Card title="App-Konfiguration" icon="rocket" href="/l/de/developers/extend/apps/config/application">
|
||||
`defineApplication` – Identität, Standardrolle, Variablen, Marketplace-Metadaten.
|
||||
</Card>
|
||||
<Card title="Rollen & Berechtigungen" icon="shield-halved" href="/l/de/developers/extend/apps/config/roles">
|
||||
@@ -42,8 +42,8 @@ Die **Konfigurationsebene** einer Twenty-App beschreibt die App *für die Plattf
|
||||
|
||||
## Wie die Bausteine zusammenhängen
|
||||
|
||||
* **Application** ist der Einstiegspunkt. Jede App hat genau einen `defineApplication()`-Aufruf, und dieser verweist auf eine **Role** als Standard.
|
||||
* Die **Role** steuert, was die Logikfunktionen und Front-Komponenten der App lesen und schreiben können. Folgen Sie dem Prinzip der geringsten Privilegien: Gewähren Sie nur die Berechtigungen, die Ihr Code tatsächlich benötigt.
|
||||
* **Application** ist der Einstiegspunkt. Jede App hat genau einen `defineApplication()`-Aufruf, und dieser verweist auf eine **Rolle** als Standard.
|
||||
* Die **Rolle** steuert, was die Logikfunktionen und Frontend-Komponenten der App lesen und schreiben können. Folgen Sie dem Prinzip der geringsten Privilegien: Gewähren Sie nur die Berechtigungen, die Ihr Code tatsächlich benötigt.
|
||||
* **Install Hooks** laufen während der Installation oder Aktualisierung – Pre-Install vor der Metadatenmigration (so kann ein riskantes Upgrade abgelehnt werden), Post-Install nach der Migration (so können Standarddaten gegen das neue Schema befüllt werden).
|
||||
|
||||
<Note>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Öffentliche Assets
|
||||
description: Liefere statische Dateien – Bilder, Symbole, Schriftarten – zusammen mit deiner App über den Ordner public/.
|
||||
description: Liefern Sie statische Dateien — Bilder, Icons, Schriftarten — zusammen mit Ihrer App über den Ordner public/ aus.
|
||||
icon: folder-open
|
||||
---
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
---
|
||||
title: Rollen & Berechtigungen
|
||||
description: Legen Sie fest, welche Objekte und Felder die Logikfunktionen und Front-Komponenten Ihrer App lesen und schreiben können.
|
||||
description: Legen Sie fest, welche Objekte und Felder die Logikfunktionen und Frontend-Komponenten Ihrer App lesen und schreiben können.
|
||||
icon: shield-halved
|
||||
---
|
||||
|
||||
Eine **Rolle** ist ein Berechtigungssatz: welche Objekte eine App lesen oder schreiben kann, welche Felder sie sehen kann und welche plattformbezogenen Funktionen sie nutzen kann. Alle Logikfunktionen und Front-Komponenten einer App erben die Berechtigungen der Rolle, die in `defineApplication` als `defaultRoleUniversalIdentifier` deklariert ist ([`defineApplication`](/l/de/developers/extend/apps/config/application)).
|
||||
Eine **Rolle** ist ein Berechtigungssatz: welche Objekte eine App lesen oder schreiben kann, welche Felder sie sehen kann und welche plattformbezogenen Funktionen sie nutzen kann. Alle Logikfunktionen und Frontend-Komponenten einer App erben die Berechtigungen der Rolle, die mit `defineApplicationRole()` markiert ist (siehe [Die Standardfunktionsrolle](#the-default-function-role) unten).
|
||||
|
||||
```ts src/roles/restricted-company-role.ts
|
||||
import {
|
||||
@@ -51,15 +51,15 @@ export default defineRole({
|
||||
|
||||
## Die Standard-Funktionsrolle
|
||||
|
||||
Wenn Sie eine neue App erzeugen, erstellt die CLI eine Standard-Rolldatei:
|
||||
Wenn Sie eine neue App erzeugen, erstellt die CLI eine Datei für die Standardrolle, die mit `defineApplicationRole()` deklariert ist:
|
||||
|
||||
```ts src/roles/default-role.ts
|
||||
import { defineRole, PermissionFlag } from 'twenty-sdk/define';
|
||||
import { defineApplicationRole, PermissionFlag } from 'twenty-sdk/define';
|
||||
|
||||
export const DEFAULT_ROLE_UNIVERSAL_IDENTIFIER =
|
||||
'b648f87b-1d26-4961-b974-0908fd991061';
|
||||
|
||||
export default defineRole({
|
||||
export default defineApplicationRole({
|
||||
universalIdentifier: DEFAULT_ROLE_UNIVERSAL_IDENTIFIER,
|
||||
label: 'Default function role',
|
||||
description: 'Default role for function Twenty client',
|
||||
@@ -77,10 +77,13 @@ export default defineRole({
|
||||
});
|
||||
```
|
||||
|
||||
Der `universalIdentifier` dieser Rolle wird in `application-config.ts` als `defaultRoleUniversalIdentifier` referenziert:
|
||||
`defineApplicationRole()` ist ein dünner Wrapper um `defineRole()`, der **die** Rolle kennzeichnet, die zum Installationszeitpunkt als Standardrolle Ihrer Anwendung verwendet wird. Die Validierung ist identisch zu `defineRole`, aber die Build-Pipeline verdrahtet deren `universalIdentifier` automatisch in das `defaultRoleUniversalIdentifier` des Anwendungsmanifests – sodass Sie es nicht selbst aus [`defineApplication`](/l/de/developers/extend/apps/config/application) referenzieren müssen.
|
||||
|
||||
* **`*.role.ts`** deklariert, was die Rolle darf.
|
||||
* **`application-config.ts`** verweist auf diese Rolle, sodass Ihre Funktionen deren Berechtigungen erben.
|
||||
Notizen:
|
||||
|
||||
* Genau **eine** `defineApplicationRole(...)` ist pro App zulässig – der Manifest-Build schlägt fehl, wenn mehr als eine gefunden wird.
|
||||
* Verwenden Sie `defineRole()` (nicht `defineApplicationRole()`) für alle **zusätzlichen** Rollen, die Ihre App mitliefert.
|
||||
* Das explizite Setzen von `defaultRoleUniversalIdentifier` in `defineApplication()` wird für die Abwärtskompatibilität weiterhin unterstützt, ist aber zugunsten von `defineApplicationRole()` veraltet.
|
||||
|
||||
## Beste Praktiken
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Objekte
|
||||
description: Deklariere neue Record-Typen – benutzerdefinierte Tabellen mit eigenen Feldern – mit defineObject.
|
||||
icon: tabelle
|
||||
description: Deklarieren Sie neue Datensatztypen — benutzerdefinierte Tabellen mit eigenen Feldern — mit defineObject.
|
||||
icon: table
|
||||
---
|
||||
|
||||
Benutzerdefinierte **Objekte** sind neue Datensatztypen, die Ihre App zu einem Arbeitsbereich hinzufügt – Postkarte, Rechnung, Abonnement, alles, was spezifisch für Ihre Domäne ist. Jedes Objekt deklariert sein Schema (Felder, Relationen, Standardwerte) und einen stabilen universellen Bezeichner, der über Synchronisierungen und Deployments hinweg bestehen bleibt.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Beziehungen
|
||||
description: Objekte mit bidirektionalen MANY_TO_ONE- / ONE_TO_MANY-Relationen verbinden.
|
||||
description: Objekte mit bidirektionalen MANY_TO_ONE-/ONE_TO_MANY-Relationen verbinden.
|
||||
icon: diagram-project
|
||||
---
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Konzepte
|
||||
description: Funktionsweise von Twenty-Apps – Entity-Modell, Sandboxing und der Installations-Lebenszyklus.
|
||||
description: Wie Twenty-Apps funktionieren – Entitätenmodell, Sandboxing und Installationslebenszyklus.
|
||||
icon: sitemap
|
||||
---
|
||||
|
||||
@@ -34,22 +34,22 @@ your-app/
|
||||
|
||||
## Entitätstypen
|
||||
|
||||
| Entität | Zweck | Dokumentation |
|
||||
| -------------------------- | ---------------------------------------------------------- | ------------------------------------------------------------------------------- |
|
||||
| **Anwendung** | App-Identität, Standardrolle, Variablen | [Application Config](/l/de/developers/extend/apps/config/application) |
|
||||
| **Rolle** | Berechtigungssätze für Objekte und Felder | [Roles & Permissions](/l/de/developers/extend/apps/config/roles) |
|
||||
| **Objekt** | Benutzerdefinierte Datensatztypen mit Feldern | [Objekte](/l/de/developers/extend/apps/data/objects) |
|
||||
| **Feld** | Felder zu Objekten aus anderen Apps hinzufügen | [Extending Objects](/l/de/developers/extend/apps/data/extending-objects) |
|
||||
| **Beziehung** | Bidirektionale Verknüpfungen zwischen Objekten | [Beziehungen](/l/de/developers/extend/apps/data/relations) |
|
||||
| **Logikfunktion** | Serverseitiges TypeScript mit Triggern | [Logikfunktionen](/l/de/developers/extend/apps/logic/logic-functions) |
|
||||
| **Skill** | Wiederverwendbare Anweisungen für KI-Agenten | [Skills & Agenten](/l/de/developers/extend/apps/logic/skills-and-agents) |
|
||||
| **Agent** | KI-Assistenten mit benutzerdefinierten Prompts | [Skills & Agenten](/l/de/developers/extend/apps/logic/skills-and-agents) |
|
||||
| **Verbindungsanbieter** | OAuth-Zugangsdaten für Drittanbieter-APIs | [Connections](/l/de/developers/extend/apps/logic/connections) |
|
||||
| **Ansicht** | Vorkonfigurierte Listenansichten für Datensätze | [Ansichten](/l/de/developers/extend/apps/layout/views) |
|
||||
| **Navigationsmenüeintrag** | Benutzerdefinierte Seitenleisten-Einträge | [Navigationsmenüeinträge](/l/de/developers/extend/apps/layout/navigation-menu-items) |
|
||||
| **Seitenlayout** | Tabs und Widgets auf der Detailseite eines Datensatzes | [Seiten-Layouts](/l/de/developers/extend/apps/layout/page-layouts) |
|
||||
| **Frontend-Komponente** | Gedisplayte React-UI in einer Sandbox innerhalb von Twenty | [Frontend-Komponenten](/l/de/developers/extend/apps/layout/front-components) |
|
||||
| **Befehlsmenü-Eintrag** | Schnellaktionen und Cmd+K-Einträge | [Befehlsmenü-Einträge](/l/de/developers/extend/apps/layout/command-menu-items) |
|
||||
| Entität | Zweck | Dokumentation |
|
||||
| -------------------------- | ------------------------------------------------------ | ------------------------------------------------------------------------------- |
|
||||
| **Anwendung** | App-Identität, Standardrolle, Variablen | [Anwendungskonfiguration](/l/de/developers/extend/apps/config/application) |
|
||||
| **Rolle** | Berechtigungssätze für Objekte und Felder | [Rollen & Berechtigungen](/l/de/developers/extend/apps/config/roles) |
|
||||
| **Objekt** | Benutzerdefinierte Datensatztypen mit Feldern | [Objekte](/l/de/developers/extend/apps/data/objects) |
|
||||
| **Feld** | Felder zu Objekten aus anderen Apps hinzufügen | [Objekte erweitern](/l/de/developers/extend/apps/data/extending-objects) |
|
||||
| **Beziehung** | Bidirektionale Verknüpfungen zwischen Objekten | [Beziehungen](/l/de/developers/extend/apps/data/relations) |
|
||||
| **Logikfunktion** | Serverseitiges TypeScript mit Triggern | [Logikfunktionen](/l/de/developers/extend/apps/logic/logic-functions) |
|
||||
| **Skill** | Wiederverwendbare Anweisungen für KI-Agenten | [Skills & Agenten](/l/de/developers/extend/apps/logic/skills-and-agents) |
|
||||
| **Agent** | KI-Assistenten mit benutzerdefinierten Prompts | [Skills & Agenten](/l/de/developers/extend/apps/logic/skills-and-agents) |
|
||||
| **Verbindungsanbieter** | OAuth-Zugangsdaten für Drittanbieter-APIs | [Verbindungen](/l/de/developers/extend/apps/logic/connections) |
|
||||
| **Ansicht** | Vorkonfigurierte Listenansichten für Datensätze | [Ansichten](/l/de/developers/extend/apps/layout/views) |
|
||||
| **Navigationsmenüeintrag** | Benutzerdefinierte Seitenleisten-Einträge | [Navigationsmenüeinträge](/l/de/developers/extend/apps/layout/navigation-menu-items) |
|
||||
| **Seitenlayout** | Tabs und Widgets auf der Detailseite eines Datensatzes | [Seiten-Layouts](/l/de/developers/extend/apps/layout/page-layouts) |
|
||||
| **Frontend-Komponente** | Isolierte React-UI innerhalb von Twenty | [Frontend-Komponenten](/l/de/developers/extend/apps/layout/front-components) |
|
||||
| **Befehlsmenü-Eintrag** | Schnellaktionen und Cmd+K-Einträge | [Befehlsmenü-Einträge](/l/de/developers/extend/apps/layout/command-menu-items) |
|
||||
|
||||
## Sandboxing
|
||||
|
||||
@@ -90,10 +90,10 @@ your-app/
|
||||
Objekte, Felder und bidirektionale Relationen.
|
||||
</Card>
|
||||
<Card title="Logik" icon="bolt" href="/l/de/developers/extend/apps/logic/overview">
|
||||
Logikfunktionen, Skills, Agents und OAuth-Verbindungen.
|
||||
Logikfunktionen, Skills, Agenten und OAuth-Verbindungen.
|
||||
</Card>
|
||||
<Card title="Layout" icon="table-columns" href="/l/de/developers/extend/apps/layout/overview">
|
||||
Ansichten, Navigation, Seiten-Layouts, Front-Komponenten.
|
||||
Ansichten, Navigation, Seiten-Layouts, Frontend-Komponenten.
|
||||
</Card>
|
||||
<Card title="Operationen" icon="rocket" href="/l/de/developers/extend/apps/operations/overview">
|
||||
CLI, Tests, Remotes, CI und das Veröffentlichen Ihrer App.
|
||||
|
||||
@@ -131,7 +131,7 @@ yarn twenty dev --once
|
||||
Beide Modi benötigen einen Server im Entwicklungsmodus und eine authentifizierte Remote-Verbindung.
|
||||
|
||||
<Warning>
|
||||
Der Dev-Modus ist nur auf Twenty-Instanzen verfügbar, die im Entwicklungsmodus laufen (`NODE_ENV=development`). Produktionsinstanzen lehnen Dev-Sync-Anfragen ab — verwenden Sie `yarn twenty deploy`, um auf Produktionsserver bereitzustellen. Siehe [Veröffentlichung](/l/de/developers/extend/apps/operations/publishing).
|
||||
Der Dev-Modus ist nur auf Twenty-Instanzen verfügbar, die im Entwicklungsmodus laufen (`NODE_ENV=development`). Produktionsinstanzen lehnen Dev-Sync-Anfragen ab — verwenden Sie `yarn twenty deploy`, um auf Produktionsserver bereitzustellen. Siehe [Apps veröffentlichen](/l/de/developers/extend/apps/operations/publishing).
|
||||
</Warning>
|
||||
|
||||
---
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Gerüst erstellen
|
||||
description: Generiere Entitätsdateien interaktiv mit yarn twenty add – Objekte, Felder, Ansichten, Logikfunktionen und mehr.
|
||||
title: Scaffolding
|
||||
description: Generieren Sie Entitätsdateien interaktiv mit yarn twenty add — Objekte, Felder, Ansichten, Logikfunktionen und mehr.
|
||||
icon: wand-magic-sparkles
|
||||
---
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
---
|
||||
title: Befehlsmenü-Einträge
|
||||
description: Stelle Front-Komponenten als Schnellaktionen und Einträge im Befehlsmenü (Cmd+K) mit defineCommandMenuItem bereit.
|
||||
description: Stellen Sie Front-Komponenten als Schnellaktionen und Einträge im Befehlsmenü (Cmd+K) mit defineCommandMenuItem bereit.
|
||||
icon: Terminal
|
||||
---
|
||||
|
||||
Ein **Befehlsmenü-Eintrag** ist die Brücke zwischen dem Benutzer und einer [Front-Komponente](/l/de/developers/extend/apps/layout/front-components). Er registriert die Komponente im Twenty-Befehlsmenü (Cmd+K) und optional als angeheftete Schnellaktions-Schaltfläche in der oberen rechten Ecke der Seite.
|
||||
Ein **Befehlsmenü-Eintrag** ist die Brücke zwischen dem Benutzer und einer [Front-Komponente](/l/de/developers/extend/apps/layout/front-components). Er registriert die Komponente im Twenty-Befehlsmenü (Cmd+K) und zeigt sie optional als angeheftete Schnellaktionsschaltfläche oben rechts auf der Seite an.
|
||||
|
||||
```ts src/command-menu-items/open-dashboard.command-menu-item.ts
|
||||
import { defineCommandMenuItem } from 'twenty-sdk/define';
|
||||
@@ -36,7 +36,7 @@ export default defineCommandMenuItem({
|
||||
|
||||
## Headless-Befehle
|
||||
|
||||
Ein Befehlsmenü-Eintrag, der mit einer [Headless-Front-Komponente](/l/de/developers/extend/apps/layout/front-components#headless-vs-non-headless) gekoppelt ist, ist die idiomatische Art, eine One-Click-Aktion bereitzustellen – Code ausführen, navigieren oder bestätigen und ausführen. Die Seite „Front Components" behandelt die [SDK Command-Komponenten](/l/de/developers/extend/apps/layout/front-components#sdk-command-components) (`Command`, `CommandLink`, `CommandModal`, `CommandOpenSidePanelPage`), die das Action-and-Unmount-Muster handhaben.
|
||||
Ein Befehlsmenü-Eintrag, der mit einer [Headless-Front-Komponente](/l/de/developers/extend/apps/layout/front-components#headless-vs-non-headless) gekoppelt ist, ist die idiomatische Art, eine One-Click-Aktion bereitzustellen – Code ausführen, navigieren oder bestätigen und ausführen. Die Seite „Front Components“ behandelt die [SDK Command-Komponenten](/l/de/developers/extend/apps/layout/front-components#sdk-command-components) (`Command`, `CommandLink`, `CommandModal`, `CommandOpenSidePanelPage`), die das Action-and-Unmount-Muster handhaben.
|
||||
|
||||
Ein typischer Ablauf:
|
||||
|
||||
@@ -107,24 +107,24 @@ export default defineCommandMenuItem({
|
||||
|
||||
Diese repräsentieren den aktuellen Zustand der Seite:
|
||||
|
||||
| Variable | Typ | Beschreibung |
|
||||
| ------------------------------ | -------------- | --------------------------------------------------------------- |
|
||||
| `pageType` | `Zeichenkette` | Aktueller Seitentyp (z. B. 'RecordIndexPage', 'RecordShowPage') |
|
||||
| `isInSidePanel` | `boolean` | Ob die Komponente in einem Seitenpanel gerendert wird |
|
||||
| `numberOfSelectedRecords` | `number` | Anzahl der aktuell ausgewählten Datensätze |
|
||||
| `isSelectAll` | `boolean` | Ob „Alle auswählen“ aktiv ist |
|
||||
| `selectedRecords` | `array` | Die ausgewählten Datensatzobjekte |
|
||||
| `favoriteRecordIds` | `array` | IDs der favorisierten Datensätze |
|
||||
| `objectPermissions` | `object` | Berechtigungen für den aktuellen Objekttyp |
|
||||
| `targetObjectReadPermissions` | `object` | Leseberechtigungen für das Zielobjekt |
|
||||
| `targetObjectWritePermissions` | `object` | Schreibberechtigungen für das Zielobjekt |
|
||||
| `featureFlags` | `object` | Aktive Feature-Flags |
|
||||
| `objectMetadataItem` | `object` | Metadaten des aktuellen Objekttyps |
|
||||
| `hasAnySoftDeleteFilterOnView` | `boolean` | Ob die aktuelle Ansicht einen Soft-Delete-Filter hat |
|
||||
| Variable | Typ | Beschreibung |
|
||||
| ------------------------------ | --------- | --------------------------------------------------------------- |
|
||||
| `pageType` | `string` | Aktueller Seitentyp (z. B. 'RecordIndexPage', 'RecordShowPage') |
|
||||
| `isInSidePanel` | `boolean` | Ob die Komponente in einem Seitenpanel gerendert wird |
|
||||
| `numberOfSelectedRecords` | `number` | Anzahl der aktuell ausgewählten Datensätze |
|
||||
| `isSelectAll` | `boolean` | Ob „Alle auswählen“ aktiv ist |
|
||||
| `selectedRecords` | `array` | Die ausgewählten Datensatzobjekte |
|
||||
| `favoriteRecordIds` | `array` | IDs der favorisierten Datensätze |
|
||||
| `objectPermissions` | `object` | Berechtigungen für den aktuellen Objekttyp |
|
||||
| `targetObjectReadPermissions` | `object` | Leseberechtigungen für das Zielobjekt |
|
||||
| `targetObjectWritePermissions` | `object` | Schreibberechtigungen für das Zielobjekt |
|
||||
| `featureFlags` | `object` | Aktive Feature-Flags |
|
||||
| `objectMetadataItem` | `object` | Metadaten des aktuellen Objekttyps |
|
||||
| `hasAnySoftDeleteFilterOnView` | `boolean` | Ob die aktuelle Ansicht einen Soft-Delete-Filter hat |
|
||||
|
||||
### Operatoren
|
||||
|
||||
Kombiniere Variablen zu booleschen Ausdrücken:
|
||||
Kombinieren Sie Variablen zu booleschen Ausdrücken:
|
||||
|
||||
| Operator | Beschreibung |
|
||||
| ----------------------------------- | ------------------------------------------------------------------------------------------- |
|
||||
|
||||
@@ -234,9 +234,9 @@ Verfügbare Hooks:
|
||||
| Hook | Gibt zurück | Beschreibung |
|
||||
| --------------------------------------------- | -------------------- | --------------------------------------------------------------------------- |
|
||||
| `useUserId()` | `string` oder `null` | Die ID des aktuellen Benutzers |
|
||||
| `useSelectedRecordIds()` | `Zeichenkette[]` | Alle ausgewählten Datensatz-IDs (leeres Array, wenn keine ausgewählt sind) |
|
||||
| `useSelectedRecordIds()` | `string[]` | Alle ausgewählten Datensatz-IDs (leeres Array, wenn keine ausgewählt sind) |
|
||||
| `useRecordId()` | `string` oder `null` | **Veraltet.** Verwenden Sie stattdessen `useSelectedRecordIds()` |
|
||||
| `useFrontComponentId()` | `Zeichenkette` | Die ID dieser Komponenteninstanz |
|
||||
| `useFrontComponentId()` | `string` | Die ID dieser Komponenteninstanz |
|
||||
| `useFrontComponentExecutionContext(selector)` | variiert | Zugriff auf den vollständigen Ausführungskontext mit einer Selektorfunktion |
|
||||
|
||||
## Host-Kommunikations-API
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Übersicht
|
||||
description: Binden Sie Ihre App in das UI von Twenty ein – Seitleisten-Einträge, gespeicherte Ansichten, Registerkarten auf Datensatzseiten und isolierte React-Komponenten.
|
||||
description: Binden Sie Ihre App in das UI von Twenty ein – Seitenleisten-Einträge, gespeicherte Ansichten, Registerkarten auf Datensatzseiten und isolierte React-Komponenten.
|
||||
icon: table-columns
|
||||
---
|
||||
|
||||
@@ -26,11 +26,11 @@ Die **Layout-Ebene** einer Twenty-App umfasst alles, was der Benutzer sieht: wo
|
||||
## In diesem Abschnitt
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Ansichten" icon="Liste" href="/l/de/developers/extend/apps/layout/views">
|
||||
<Card title="Ansichten" icon="list" href="/l/de/developers/extend/apps/layout/views">
|
||||
`defineView` — gespeicherte Listen-Konfigurationen: sichtbare Spalten, Filter, Gruppen.
|
||||
</Card>
|
||||
<Card title="Navigationselemente im Menü" icon="Balken" href="/l/de/developers/extend/apps/layout/navigation-menu-items">
|
||||
`defineNavigationMenuItem` — Seitleisten-Einträge, die auf Ansichten oder externe URLs verweisen.
|
||||
<Card title="Navigationsmenüeinträge" icon="bars" href="/l/de/developers/extend/apps/layout/navigation-menu-items">
|
||||
`defineNavigationMenuItem` — Seitenleisten-Einträge, die auf Ansichten oder externe URLs verweisen.
|
||||
</Card>
|
||||
<Card title="Seitenlayouts" icon="table-columns" href="/l/de/developers/extend/apps/layout/page-layouts">
|
||||
`definePageLayout` und `definePageLayoutTab` — Registerkarten und Widgets auf der Detailseite eines Datensatzes.
|
||||
@@ -38,8 +38,8 @@ Die **Layout-Ebene** einer Twenty-App umfasst alles, was der Benutzer sieht: wo
|
||||
<Card title="Frontend-Komponenten" icon="window-maximize" href="/l/de/developers/extend/apps/layout/front-components">
|
||||
`defineFrontComponent` — isolierte React-Komponenten, die innerhalb von Twenty gerendert werden.
|
||||
</Card>
|
||||
<Card title="Befehlsmenüeinträge" icon="Terminal" href="/l/de/developers/extend/apps/layout/command-menu-items">
|
||||
`defineCommandMenuItem` — Front-Komponenten als Cmd+K-Einträge und Schnellaktionen registrieren.
|
||||
<Card title="Befehlsmenü-Einträge" icon="terminal" href="/l/de/developers/extend/apps/layout/command-menu-items">
|
||||
`defineCommandMenuItem` — Frontend-Komponenten als Cmd+K-Einträge und Schnellaktionen registrieren.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -53,4 +53,4 @@ Die **Layout-Ebene** einer Twenty-App umfasst alles, was der Benutzer sieht: wo
|
||||
| **Innerhalb eines der oben genannten Bereiche** | Ein benutzerdefiniertes React-Widget – Schaltflächen, Formulare, Dashboards, Integrationen | `defineFrontComponent` |
|
||||
| **Befehlsmenü (Cmd+K)** | Eine angeheftete Schnellaktion oder ein versteckter Befehl | `defineCommandMenuItem` |
|
||||
|
||||
Front-Komponenten laufen in einem isolierten Web Worker unter Verwendung von Remote DOM – sie werden *nativ* auf der Seite gerendert (nicht in einem iframe), können aber die Hostseite oder das DOM nicht direkt erreichen. Die Kommunikation mit Twenty erfolgt über eine Message-Passing-Host-API.
|
||||
Frontend-Komponenten laufen in einem isolierten Web Worker unter Verwendung von Remote DOM – sie werden nativ auf der Seite gerendert (nicht in einem iframe), können aber die Hostseite oder das DOM nicht direkt erreichen. Die Kommunikation mit Twenty erfolgt über eine Message-Passing-Host-API.
|
||||
|
||||
@@ -40,4 +40,4 @@ export default defineView({
|
||||
|
||||
## Wie Ansichten in der UI angezeigt werden
|
||||
|
||||
Eine Ansicht für sich ist aus der Seitenleiste nicht erreichbar. Damit sie dort erscheint, verknüpfen Sie sie mit einem [Navigationsmenüeintrag](/l/de/developers/extend/apps/layout/navigation-menu-items) des Typs `VIEW`, der auf die `universalIdentifier` der Ansicht zeigt. Das ist das kanonische Muster: Jedes benutzerdefinierte Objekt liefert typischerweise eine Standardansicht plus einen Eintrag in der Seitenleiste, der sie öffnet.
|
||||
Eine Ansicht für sich ist aus der Seitenleiste nicht erreichbar. Damit sie dort erscheint, verknüpfen Sie sie mit einem [Navigationsmenüeintrag](/l/de/developers/extend/apps/layout/navigation-menu-items) des Typs `VIEW`, der auf den `universalIdentifier` der Ansicht zeigt. Das ist das kanonische Muster: Jedes benutzerdefinierte Objekt liefert typischerweise eine Standardansicht plus einen Eintrag in der Seitenleiste, der sie öffnet.
|
||||
|
||||
@@ -52,7 +52,6 @@ export default defineApplication({
|
||||
universalIdentifier: '...',
|
||||
displayName: 'Linear',
|
||||
description: 'Connect Linear to Twenty.',
|
||||
defaultRoleUniversalIdentifier: '...',
|
||||
// OAuth client credentials live on the app registration (one OAuth app per
|
||||
// Twenty server, configured by the admin) — not per-workspace. Declare them
|
||||
// as serverVariables so the admin can fill them in once for all installs.
|
||||
@@ -137,15 +136,15 @@ export const createLinearIssueHandler = async (input: {
|
||||
|
||||
Jede Verbindung hat:
|
||||
|
||||
| Feld | Beschreibung |
|
||||
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `id` | Eindeutige Zeilen-ID; an `getConnection(id)` übergeben, um eine einzelne Verbindung erneut abzurufen |
|
||||
| `sichtbarkeit` | `'user'` (privat für ein Mitglied des Arbeitsbereichs) oder `'workspace'` (mit allen Mitgliedern geteilt) |
|
||||
| `geltungsbereiche` | Vom Upstream-Anbieter gewährte OAuth-Berechtigungen (unabhängig von `visibility` — diese sind nicht miteinander verknüpft) |
|
||||
| `userWorkspaceId` | Die userWorkspace-ID des Eigentümers — nützlich, um "die Verbindung des anfragenden Benutzers" in HTTP-Routen-Triggern auszuwählen |
|
||||
| `accessToken` | Frisches OAuth-Zugriffstoken (wird bei Ablauf automatisch erneuert) |
|
||||
| `name` / `handle` | Anzeigename der Verbindung (automatisch beim OAuth-Callback abgeleitet, vom Benutzer umbenennbar) |
|
||||
| `authFailedAt` | Gesetzt, wenn die jüngste Aktualisierung fehlgeschlagen ist; der Benutzer muss die Verbindung erneut herstellen |
|
||||
| Feld | Beschreibung |
|
||||
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `id` | Eindeutige Zeilen-ID; an `getConnection(id)` übergeben, um eine einzelne Verbindung erneut abzurufen |
|
||||
| `visibility` | `'user'` (privat für ein Mitglied des Arbeitsbereichs) oder `'workspace'` (mit allen Mitgliedern geteilt) |
|
||||
| `scopes` | Vom Upstream-Anbieter gewährte OAuth-Berechtigungen (unabhängig von `visibility` — diese sind nicht miteinander verknüpft) |
|
||||
| `userWorkspaceId` | Die userWorkspace-ID des Eigentümers — nützlich, um "die Verbindung des anfragenden Benutzers" in HTTP-Routen-Triggern auszuwählen |
|
||||
| `accessToken` | Frisches OAuth-Zugriffstoken (wird bei Ablauf automatisch erneuert) |
|
||||
| `name` / `handle` | Anzeigename der Verbindung (automatisch beim OAuth-Callback abgeleitet, vom Benutzer umbenennbar) |
|
||||
| `authFailedAt` | Gesetzt, wenn die jüngste Aktualisierung fehlgeschlagen ist; der Benutzer muss die Verbindung erneut herstellen |
|
||||
|
||||
Hauptpunkte:
|
||||
|
||||
|
||||
@@ -370,5 +370,5 @@ Hauptpunkte:
|
||||
* `TWENTY_API_URL` — Basis-URL der Twenty-API
|
||||
* `TWENTY_APP_ACCESS_TOKEN` — Kurzlebiger Schlüssel, der auf die Standard-Funktionsrolle Ihrer Anwendung begrenzt ist
|
||||
|
||||
Sie müssen diese **nicht** an die Clients übergeben — sie lesen automatisch aus `process.env`. Die Berechtigungen des API-Schlüssels werden durch die Rolle bestimmt, auf die in `defaultRoleUniversalIdentifier` in Ihrer `application-config.ts` verwiesen wird.
|
||||
Sie müssen diese **nicht** an die Clients übergeben — sie lesen automatisch aus `process.env`. Die Berechtigungen des API-Schlüssels werden durch die Rolle bestimmt, die mit `defineApplicationRole()` deklariert wird (oder über `defaultRoleUniversalIdentifier` in `application-config.ts` referenziert wird).
|
||||
</Note>
|
||||
|
||||
@@ -28,11 +28,11 @@ Die **Logikschicht** einer Twenty-App ist der Code, der *ausgeführt wird* – s
|
||||
<Card title="Logikfunktionen" icon="bolt" href="/l/de/developers/extend/apps/logic/logic-functions">
|
||||
Der zentrale Baustein – Auslösertypen, Payloads und der typisierte API-Client.
|
||||
</Card>
|
||||
<Card title="Fähigkeiten & Agenten" icon="robot" href="/l/de/developers/extend/apps/logic/skills-and-agents">
|
||||
Wiederverwendbare KI-Agenten-Anweisungen und Assistenten mit benutzerdefinierten System-Prompts.
|
||||
<Card title="Skills & Agenten" icon="robot" href="/l/de/developers/extend/apps/logic/skills-and-agents">
|
||||
Wiederverwendbare Anweisungen für KI-Agenten und Assistenten mit benutzerdefinierten System-Prompts.
|
||||
</Card>
|
||||
<Card title="Verbindungen" icon="plug" href="/l/de/developers/extend/apps/logic/connections">
|
||||
OAuth-Anmeldedaten, die Ihre App für Dienste von Drittanbietern hält – Linear, GitHub, Slack und mehr.
|
||||
OAuth-Anmeldedaten, die Ihre App für Dienste von Drittanbietern verwaltet – Linear, GitHub, Slack und mehr.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -40,16 +40,16 @@ Die **Logikschicht** einer Twenty-App ist der Code, der *ausgeführt wird* – s
|
||||
|
||||
Eine Logikfunktion wählt einen oder mehrere Auslöser – jeder Eintrag unten ist ein eigenes Feld auf `defineLogicFunction()`:
|
||||
|
||||
| Auslöser | Wann sie ausgeführt wird | Einstellung |
|
||||
| --------------------- | -------------------------------------------------------------------- | ------------------------------- |
|
||||
| **HTTP-Route** | Eine Anfrage trifft auf Ihren `/s/\<path>`-Endpunkt | `httpRouteTriggerSettings` |
|
||||
| **Cron** | Ein CRON-Ausdruck stimmt überein | `cronTriggerSettings` |
|
||||
| **Datenbankereignis** | Ein Workspace-Datensatz wird erstellt, aktualisiert oder gelöscht | `databaseEventTriggerSettings` |
|
||||
| **KI-Tool** | Eine Twenty-KI-Funktion entscheidet sich, Ihre Funktion aufzurufen | `toolTriggerSettings` |
|
||||
| **Workflow-Aktion** | Ein Workflow-Schritt ruft Ihre Funktion auf | `workflowActionTriggerSettings` |
|
||||
| Auslöser | Wann sie ausgeführt wird | Einstellung |
|
||||
| --------------------- | ------------------------------------------------------------------ | ------------------------------- |
|
||||
| **HTTP-Route** | Eine Anfrage erreicht Ihren `/s/\<path>`-Endpunkt | `httpRouteTriggerSettings` |
|
||||
| **Cron** | Ein CRON-Ausdruck trifft zu | `cronTriggerSettings` |
|
||||
| **Datenbankereignis** | Ein Workspace-Datensatz wird erstellt, aktualisiert oder gelöscht | `databaseEventTriggerSettings` |
|
||||
| **KI-Tool** | Eine Twenty-KI-Funktion entscheidet sich, Ihre Funktion aufzurufen | `toolTriggerSettings` |
|
||||
| **Workflow-Aktion** | Ein Workflow-Schritt ruft Ihre Funktion auf | `workflowActionTriggerSettings` |
|
||||
|
||||
Funktionen werden in isolierten Node.js-Prozessen sandboxed ausgeführt und greifen über einen typisierten API-Client, der auf die in [`defineApplication()`](/l/de/developers/extend/apps/config/application) deklarierte Rolle beschränkt ist, auf den Workspace zu.
|
||||
Funktionen werden in isolierten Node.js-Prozessen in einer Sandbox ausgeführt und greifen über einen typisierten API-Client, der auf die in [`defineApplication()`](/l/de/developers/extend/apps/config/application) deklarierte Rolle beschränkt ist, auf den Workspace zu.
|
||||
|
||||
<Note>
|
||||
**Installations-Hooks zur Installationszeit** – Code, der vor oder nach der Installation ausgeführt wird – teilen sich diese Laufzeitumgebung, verwenden jedoch ihre eigenen define-Funktionen und befinden sich unter [Config → Install Hooks](/l/de/developers/extend/apps/config/install-hooks).
|
||||
**Installations-Hooks** – Code, der vor oder nach der Installation ausgeführt wird – teilen sich diese Laufzeitumgebung, verwenden jedoch eigene Define-Funktionen und befinden sich unter [Config → Install Hooks](/l/de/developers/extend/apps/config/install-hooks).
|
||||
</Note>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
---
|
||||
title: Fähigkeiten & Agenten
|
||||
title: Skills & Agenten
|
||||
description: Definieren Sie KI-Skills und Agenten für Ihre App.
|
||||
icon: robot
|
||||
---
|
||||
|
||||
<Warning>
|
||||
Fähigkeiten und Agenten befinden sich derzeit in der Alpha-Phase. Die Funktion ist funktionsfähig, entwickelt sich jedoch noch weiter.
|
||||
Skills und Agenten befinden sich derzeit in der Alpha-Phase. Die Funktion ist funktionsfähig, entwickelt sich jedoch noch weiter.
|
||||
</Warning>
|
||||
|
||||
Apps können KI-Funktionen definieren, die im Arbeitsbereich verfügbar sind — wiederverwendbare Skill-Anweisungen und Agenten mit benutzerdefinierten System-Prompts.
|
||||
|
||||
@@ -4,7 +4,7 @@ description: Erstellen, testen und ausliefern Sie Ihre App – CLI-Befehle, Inte
|
||||
icon: rocket
|
||||
---
|
||||
|
||||
Die **Operationsschicht** umfasst alles, was Sie *mit* Ihrer App tun, anstatt *in* ihr: das Ausführen von CLI-Befehlen, das Starten von Integrationstests gegen einen realen Twenty-Server, das Konfigurieren von CI und das Ausliefern von Releases – entweder als Tarball, der auf einem einzelnen Server bereitgestellt wird, oder als npm-Paket, das im Marketplace gelistet ist.
|
||||
Die **Operationsschicht** umfasst alles, was Sie *an* Ihrer App tun, statt *mit* ihr: das Ausführen von CLI-Befehlen, das Durchführen von Integrationstests gegen einen realen Twenty-Server, das Konfigurieren von CI und das Ausliefern von Releases – entweder als Tarball, der auf einem einzelnen Server bereitgestellt wird, oder als npm-Paket, das im Marketplace gelistet ist.
|
||||
|
||||
```text
|
||||
develop ─▶ test ─▶ build ─▶ deploy / publish
|
||||
@@ -17,13 +17,13 @@ Die **Operationsschicht** umfasst alles, was Sie *mit* Ihrer App tun, anstatt *i
|
||||
## In diesem Abschnitt
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="CLI" icon="Terminal" href="/l/de/developers/extend/apps/operations/cli">
|
||||
<Card title="CLI" icon="terminal" href="/l/de/developers/extend/apps/operations/cli">
|
||||
`yarn twenty`-Referenz – exec, logs, uninstall, remotes.
|
||||
</Card>
|
||||
<Card title="Tests" icon="flask" href="/l/de/developers/extend/apps/operations/testing">
|
||||
Vitest-Setup, Integrationstests, Typprüfung, CI-Workflow.
|
||||
</Card>
|
||||
<Card title="Veröffentlichen" icon="hochladen" href="/l/de/developers/extend/apps/operations/publishing">
|
||||
Build, Tarball bereitstellen, auf npm veröffentlichen, installieren.
|
||||
<Card title="Veröffentlichen" icon="upload" href="/l/de/developers/extend/apps/operations/publishing">
|
||||
Build erstellen, Tarball bereitstellen, auf npm veröffentlichen, installieren.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -187,7 +187,6 @@ export default defineApplication({
|
||||
universalIdentifier: '...',
|
||||
displayName: 'My App',
|
||||
description: 'A great app',
|
||||
defaultRoleUniversalIdentifier: DEFAULT_ROLE_UNIVERSAL_IDENTIFIER,
|
||||
logoUrl: 'public/logo.png',
|
||||
screenshots: [
|
||||
'public/screenshot-1.png',
|
||||
|
||||
@@ -144,7 +144,7 @@ Der Subpfad `twenty-sdk/cli` exportiert Funktionen, die Sie direkt aus Testcode
|
||||
|
||||
| Funktion | Beschreibung |
|
||||
| -------------- | ----------------------------------------------------- |
|
||||
| `appBuild` | Die App bauen und optional ein Tarball packen |
|
||||
| `appBuild` | Die App bauen und optional ein Tarball erstellen |
|
||||
| `appDeploy` | Ein Tarball auf den Server hochladen |
|
||||
| `appInstall` | Die App im aktiven Arbeitsbereich installieren |
|
||||
| `appUninstall` | Die App aus dem aktiven Arbeitsbereich deinstallieren |
|
||||
|
||||
@@ -13,7 +13,6 @@ Todo app deve ter exatamente uma chamada a `defineApplication`. Ela declara:
|
||||
|
||||
```ts src/application-config.ts
|
||||
import { defineApplication } from 'twenty-sdk/define';
|
||||
import { DEFAULT_ROLE_UNIVERSAL_IDENTIFIER } from 'src/roles/default-role';
|
||||
|
||||
export default defineApplication({
|
||||
universalIdentifier: '39783023-bcac-41e3-b0d2-ff1944d8465d',
|
||||
@@ -27,7 +26,6 @@ export default defineApplication({
|
||||
isSecret: false,
|
||||
},
|
||||
},
|
||||
defaultRoleUniversalIdentifier: DEFAULT_ROLE_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
```
|
||||
|
||||
@@ -35,12 +33,13 @@ Notas:
|
||||
|
||||
* Os campos `universalIdentifier` são IDs determinísticos que você controla. Gere-os uma vez e mantenha-os estáveis entre sincronizações.
|
||||
* `applicationVariables` tornam-se variáveis de ambiente para suas funções e componentes de front-end (por exemplo, `DEFAULT_RECIPIENT_NAME` fica disponível como `process.env.DEFAULT_RECIPIENT_NAME`).
|
||||
* `defaultRoleUniversalIdentifier` deve fazer referência a um papel definido com [`defineRole()`](/l/pt/developers/extend/apps/config/roles).
|
||||
* O papel padrão é detectado automaticamente a partir do arquivo de definição de papel marcado com [`defineApplicationRole()`](/l/pt/developers/extend/apps/config/roles) — você não precisa referenciá-lo em `defineApplication()`.
|
||||
* As funções de pré-instalação e pós-instalação são detectadas automaticamente durante a construção do manifesto — você não precisa referenciá-las em `defineApplication()`.
|
||||
* Passar `defaultRoleUniversalIdentifier` explicitamente ainda é compatível para retrocompatibilidade, mas foi preterido em favor de `defineApplicationRole()`.
|
||||
|
||||
## Papel de função padrão
|
||||
|
||||
O `defaultRoleUniversalIdentifier` controla ao que as funções de lógica e os componentes de front-end do app podem acessar:
|
||||
O papel declarado com [`defineApplicationRole()`](/l/pt/developers/extend/apps/config/roles) controla o que as funções de lógica e os componentes de front-end do aplicativo podem acessar:
|
||||
|
||||
* O token em tempo de execução injetado como `TWENTY_APP_ACCESS_TOKEN` é derivado desse papel.
|
||||
* O cliente de API tipado é restrito às permissões concedidas a esse papel.
|
||||
|
||||
@@ -6,7 +6,7 @@ icon: wrench
|
||||
|
||||
Hooks de instalação são funções de lógica especiais que são executadas durante o ciclo de vida de instalação ou atualização. Elas compartilham o mesmo runtime de handler que as [logic functions](/l/pt/developers/extend/apps/logic/logic-functions) normais e recebem um `InstallPayload`, mas são declaradas com suas próprias funções de definição — `definePostInstallLogicFunction()` e `definePreInstallLogicFunction()` — e ficam fora do modelo de gatilhos normal (HTTP, cron, eventos de banco de dados).
|
||||
|
||||
Cada aplicativo pode definir **no máximo uma pré-instalação** e **no máximo uma pós-instalação**. A geração do manifesto apresentará erro se mais de uma de cada for detectada.
|
||||
Cada aplicativo pode definir no máximo uma função de pré-instalação e no máximo uma função de pós-instalação. A geração do manifesto apresentará erro se mais de uma de cada for detectada.
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
|
||||
@@ -26,7 +26,7 @@ A **camada de configuração** de uma aplicação Twenty é o que descreve a apl
|
||||
└──────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Nesta seção
|
||||
## Nesta secção
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Configuração da aplicação" icon="rocket" href="/l/pt/developers/extend/apps/config/application">
|
||||
@@ -36,15 +36,15 @@ A **camada de configuração** de uma aplicação Twenty é o que descreve a apl
|
||||
`defineRole` — declara o que as funções de lógica da sua aplicação podem ler e escrever.
|
||||
</Card>
|
||||
<Card title="Hooks de instalação" icon="wrench" href="/l/pt/developers/extend/apps/config/install-hooks">
|
||||
`definePreInstallLogicFunction` e `definePostInstallLogicFunction` — fazem cópias de segurança dos dados, pré-preenchem valores padrão, validam atualizações.
|
||||
`definePreInstallLogicFunction` e `definePostInstallLogicFunction` — criam cópias de segurança dos dados, inicializam valores predefinidos, validam atualizações.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Como as peças se relacionam
|
||||
|
||||
* A **Aplicação** é o ponto de entrada. Cada aplicação tem exatamente uma chamada `defineApplication()`, e esta aponta para uma **Função** como predefinida.
|
||||
* A **Função** controla o que as funções de lógica e os componentes de interface da aplicação podem ler e escrever. Siga o princípio do menor privilégio: conceda apenas as permissões de que o seu código realmente necessita.
|
||||
* Os **Hooks de instalação** são executados durante a instalação ou atualização — o pré-instalação antes da migração de metadados (para que possa recusar uma atualização arriscada) e o pós-instalação depois da migração (para que possa pré-preencher dados padrão com base no novo esquema).
|
||||
* A **Função** controla o que as funções de lógica e os componentes de front-end da aplicação podem ler e escrever. Siga o princípio do menor privilégio: conceda apenas as permissões de que o seu código realmente necessita.
|
||||
* Os **Hooks de instalação** são executados durante a instalação ou atualização — a pré-instalação antes da migração de metadados (para que possa recusar uma atualização arriscada) e a pós-instalação após a migração (para que possa inicializar dados predefinidos com base no novo esquema).
|
||||
|
||||
<Note>
|
||||
Os hooks de instalação partilham o ambiente de execução de [função de lógica](/l/pt/developers/extend/apps/logic/logic-functions) — a mesma assinatura de handler, as mesmas variáveis de ambiente, o mesmo cliente de API tipado — mas são declarados com as suas próprias funções "define" e vivem fora do modelo de disparo normal (HTTP, cron, eventos de base de dados).
|
||||
|
||||
@@ -4,7 +4,7 @@ description: Declare quais objetos e campos as funções de lógica e os compone
|
||||
icon: shield-halved
|
||||
---
|
||||
|
||||
Um **papel** é um conjunto de permissões: quais objetos um app pode ler ou gravar, quais campos ele pode ver e quais recursos em nível de plataforma ele pode usar. Todas as funções de lógica e os componentes de front-end do app herdam as permissões do papel declarado como `defaultRoleUniversalIdentifier` em [`defineApplication`](/l/pt/developers/extend/apps/config/application).
|
||||
Um **papel** é um conjunto de permissões: quais objetos um app pode ler ou gravar, quais campos ele pode ver e quais recursos em nível de plataforma ele pode usar. Todas as funções de lógica e os componentes de front-end de cada app herdam as permissões do papel marcado com `defineApplicationRole()` (consulte [O papel padrão da função](#the-default-function-role) abaixo).
|
||||
|
||||
```ts src/roles/restricted-company-role.ts
|
||||
import {
|
||||
@@ -51,15 +51,15 @@ export default defineRole({
|
||||
|
||||
## Papel de função padrão
|
||||
|
||||
Ao criar um novo app com o scaffold, a CLI cria um arquivo de papel padrão:
|
||||
Ao criar um novo app com o scaffold, a CLI cria um arquivo de papel padrão declarado com `defineApplicationRole()`:
|
||||
|
||||
```ts src/roles/default-role.ts
|
||||
import { defineRole, PermissionFlag } from 'twenty-sdk/define';
|
||||
import { defineApplicationRole, PermissionFlag } from 'twenty-sdk/define';
|
||||
|
||||
export const DEFAULT_ROLE_UNIVERSAL_IDENTIFIER =
|
||||
'b648f87b-1d26-4961-b974-0908fd991061';
|
||||
|
||||
export default defineRole({
|
||||
export default defineApplicationRole({
|
||||
universalIdentifier: DEFAULT_ROLE_UNIVERSAL_IDENTIFIER,
|
||||
label: 'Default function role',
|
||||
description: 'Default role for function Twenty client',
|
||||
@@ -77,10 +77,13 @@ export default defineRole({
|
||||
});
|
||||
```
|
||||
|
||||
O `universalIdentifier` desse papel é referenciado em `application-config.ts` como `defaultRoleUniversalIdentifier`:
|
||||
`defineApplicationRole()` é um wrapper leve em torno de `defineRole()` que sinaliza **o** papel usado como padrão do seu app no momento da instalação. A validação é idêntica à de `defineRole`, mas o pipeline de build conecta automaticamente seu `universalIdentifier` ao `defaultRoleUniversalIdentifier` do manifesto do app — assim, você não precisa referenciá-lo em [`defineApplication`](/l/pt/developers/extend/apps/config/application).
|
||||
|
||||
* **`*.role.ts`** declara o que o papel pode fazer.
|
||||
* **`application-config.ts`** aponta para esse papel para que suas funções herdem suas permissões.
|
||||
Notas:
|
||||
|
||||
* Exatamente **um** `defineApplicationRole(...)` é permitido por app — o build do manifesto falhará se encontrar mais de um.
|
||||
* Use `defineRole()` (não `defineApplicationRole()`) para quaisquer papéis **adicionais** que o seu app forneça.
|
||||
* Definir `defaultRoleUniversalIdentifier` explicitamente em `defineApplication()` ainda é compatível para retrocompatibilidade, mas foi preterido em favor de `defineApplicationRole()`.
|
||||
|
||||
## Melhores Práticas
|
||||
|
||||
|
||||
@@ -39,11 +39,11 @@ A **camada de dados** de um app Twenty é o conjunto de dados que seu app *adici
|
||||
|
||||
## Entidades em resumo
|
||||
|
||||
| Entidade | Finalidade | Definido com |
|
||||
| ----------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------- |
|
||||
| **Objeto** | Um novo tipo de registro personalizado (por exemplo, PostCard, Invoice) com seus próprios campos | `defineObject()` |
|
||||
| **Campo** | Uma coluna em um objeto. Campos independentes podem estender objetos que você não criou (por exemplo, adicionar `loyaltyTier` a Company) | `defineField()` |
|
||||
| **Relação** | Um vínculo bidirecional entre dois objetos — ambos os lados declarados como campos | `defineField()` com `FieldType.RELATION` |
|
||||
| Entidade | Finalidade | Definido com |
|
||||
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------- |
|
||||
| **Objeto** | Um novo tipo de registro personalizado (por exemplo, PostCard, Invoice) com seus próprios campos | `defineObject()` |
|
||||
| **Campo** | Uma coluna em um objeto. Campos independentes podem estender objetos que você não criou (por exemplo, adicionar `loyaltyTier` ao objeto Company) | `defineField()` |
|
||||
| **Relação** | Um vínculo bidirecional entre dois objetos — ambos os lados declarados como campos | `defineField()` com `FieldType.RELATION` |
|
||||
|
||||
O SDK detecta esses elementos por meio de análise de AST em tempo de build, então a organização dos arquivos fica a seu critério — a convenção é `src/objects/` e `src/fields/`. UUIDs `universalIdentifier` estáveis conectam tudo em implantações diferentes.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Conceitos
|
||||
description: Como os apps Twenty funcionam — modelo de entidade, sandboxing e ciclo de vida da instalação.
|
||||
description: Como as aplicações Twenty funcionam — modelo de entidade, sandboxing e ciclo de vida da instalação.
|
||||
icon: sitemap
|
||||
---
|
||||
|
||||
@@ -34,22 +34,22 @@ your-app/
|
||||
|
||||
## Tipos de entidade
|
||||
|
||||
| Entidade | Finalidade | Documentação |
|
||||
| ----------------------------- | --------------------------------------------------- | ----------------------------------------------------------------------------- |
|
||||
| **Aplicação** | Identidade da aplicação, função padrão, variáveis | [Application Config](/l/pt/developers/extend/apps/config/application) |
|
||||
| **Papel** | Conjuntos de permissões para objetos e campos | [Roles & Permissions](/l/pt/developers/extend/apps/config/roles) |
|
||||
| **Objeto** | Tipos de registro personalizados com campos | [Objects](/l/pt/developers/extend/apps/data/objects) |
|
||||
| **Campo** | Adicionar campos a objetos de outros apps | [Extending Objects](/l/pt/developers/extend/apps/data/extending-objects) |
|
||||
| **Relação** | Links bidirecionais entre objetos | [Relations](/l/pt/developers/extend/apps/data/relations) |
|
||||
| **Função lógica** | TypeScript no lado do servidor com gatilhos | [Funções lógicas](/l/pt/developers/extend/apps/logic/logic-functions) |
|
||||
| **Habilidade** | Instruções reutilizáveis para agentes de IA | [Habilidades e Agentes](/l/pt/developers/extend/apps/logic/skills-and-agents) |
|
||||
| **Agente** | Assistentes de IA com prompts personalizados | [Habilidades e Agentes](/l/pt/developers/extend/apps/logic/skills-and-agents) |
|
||||
| **Provedor de conexão** | Credenciais OAuth para APIs de terceiros | [Connections](/l/pt/developers/extend/apps/logic/connections) |
|
||||
| **Vista** | Vistas de lista de registros pré-configuradas | [Views](/l/pt/developers/extend/apps/layout/views) |
|
||||
| **Item do menu de navegação** | Entradas personalizadas na barra lateral | [Navigation Menu Items](/l/pt/developers/extend/apps/layout/navigation-menu-items) |
|
||||
| **Layout da Página** | Abas e widgets na página de detalhes de um registro | [Page Layouts](/l/pt/developers/extend/apps/layout/page-layouts) |
|
||||
| **Componente de front-end** | UI React em sandbox dentro do Twenty | [Componentes de front-end](/l/pt/developers/extend/apps/layout/front-components) |
|
||||
| **Item do menu de comandos** | Ações rápidas e entradas Cmd+K | [Command Menu Items](/l/pt/developers/extend/apps/layout/command-menu-items) |
|
||||
| Entidade | Finalidade | Documentação |
|
||||
| ----------------------------- | --------------------------------------------------- | ---------------------------------------------------------------------------------- |
|
||||
| **Aplicação** | Identidade da aplicação, função padrão, variáveis | [Configuração da aplicação](/l/pt/developers/extend/apps/config/application) |
|
||||
| **Papel** | Conjuntos de permissões para objetos e campos | [Papéis e permissões](/l/pt/developers/extend/apps/config/roles) |
|
||||
| **Objeto** | Tipos de registro personalizados com campos | [Objetos](/l/pt/developers/extend/apps/data/objects) |
|
||||
| **Campo** | Adicionar campos a objetos de outros apps | [Extensão de objetos](/l/pt/developers/extend/apps/data/extending-objects) |
|
||||
| **Relação** | Links bidirecionais entre objetos | [Relações](/l/pt/developers/extend/apps/data/relations) |
|
||||
| **Função lógica** | TypeScript no lado do servidor com gatilhos | [Funções lógicas](/l/pt/developers/extend/apps/logic/logic-functions) |
|
||||
| **Habilidade** | Instruções reutilizáveis para agentes de IA | [Habilidades e Agentes](/l/pt/developers/extend/apps/logic/skills-and-agents) |
|
||||
| **Agente** | Assistentes de IA com prompts personalizados | [Habilidades e Agentes](/l/pt/developers/extend/apps/logic/skills-and-agents) |
|
||||
| **Provedor de conexão** | Credenciais OAuth para APIs de terceiros | [Conexões](/l/pt/developers/extend/apps/logic/connections) |
|
||||
| **Vista** | Vistas de lista de registros pré-configuradas | [Vistas](/l/pt/developers/extend/apps/layout/views) |
|
||||
| **Item do menu de navegação** | Entradas personalizadas na barra lateral | [Itens do menu de navegação](/l/pt/developers/extend/apps/layout/navigation-menu-items) |
|
||||
| **Layout da Página** | Abas e widgets na página de detalhes de um registro | [Layouts de página](/l/pt/developers/extend/apps/layout/page-layouts) |
|
||||
| **Componente de front-end** | UI React em sandbox dentro do Twenty | [Componentes de front-end](/l/pt/developers/extend/apps/layout/front-components) |
|
||||
| **Item do menu de comandos** | Ações rápidas e entradas Cmd+K | [Itens do menu de comandos](/l/pt/developers/extend/apps/layout/command-menu-items) |
|
||||
|
||||
## Sandboxing
|
||||
|
||||
@@ -78,7 +78,7 @@ your-app/
|
||||
|
||||
* **`yarn twenty dev`** — observa seus arquivos-fonte e sincroniza ao vivo as alterações com um servidor Twenty conectado. O cliente de API tipado é regenerado automaticamente quando o esquema muda.
|
||||
* **`yarn twenty build`** — compila TypeScript, empacota funções de lógica e componentes de front-end com o esbuild e produz um manifesto.
|
||||
* **Hooks de pré/pós-instalação** — funções opcionais que são executadas durante a instalação. Veja [Install Hooks](/l/pt/developers/extend/apps/config/install-hooks) para detalhes.
|
||||
* **Hooks de pré/pós-instalação** — funções opcionais que são executadas durante a instalação. Veja [Hooks de instalação](/l/pt/developers/extend/apps/config/install-hooks) para detalhes.
|
||||
|
||||
## Próximos passos
|
||||
|
||||
@@ -86,16 +86,16 @@ your-app/
|
||||
<Card title="Configuração" icon="screwdriver-wrench" href="/l/pt/developers/extend/apps/config/overview">
|
||||
Identidade da aplicação, função padrão e hooks de instalação.
|
||||
</Card>
|
||||
<Card title="Data" icon="database" href="/l/pt/developers/extend/apps/data/overview">
|
||||
<Card title="Dados" icon="database" href="/l/pt/developers/extend/apps/data/overview">
|
||||
Objetos, campos e relações bidirecionais.
|
||||
</Card>
|
||||
<Card title="Lógica" icon="bolt" href="/l/pt/developers/extend/apps/logic/overview">
|
||||
Funções de lógica, skills, agentes e conexões OAuth.
|
||||
Funções lógicas, habilidades, agentes e conexões OAuth.
|
||||
</Card>
|
||||
<Card title="Layout" icon="table-columns" href="/l/pt/developers/extend/apps/layout/overview">
|
||||
Views, navegação, layouts de página, componentes de front.
|
||||
Vistas, navegação, layouts de página, componentes de front-end.
|
||||
</Card>
|
||||
<Card title="Operações" icon="rocket" href="/l/pt/developers/extend/apps/operations/overview">
|
||||
CLI, testes, remotes, CI e publicação do seu app.
|
||||
CLI, testes, remotos, CI e publicação do seu aplicativo.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Servidor Local
|
||||
description: Gerencie o servidor Twenty Docker local — inicie, pare, atualize, instância de teste em paralelo e configuração manual do SDK.
|
||||
description: Gerencie o servidor Docker local do Twenty — iniciar, parar, atualizar, executar uma instância de teste paralela e configurar manualmente o SDK.
|
||||
icon: server
|
||||
---
|
||||
|
||||
@@ -11,13 +11,13 @@ Use `yarn twenty server` para controlar o contêiner Twenty local:
|
||||
| Comando | O que faz |
|
||||
| -------------------------------------- | ------------------------------------------------ |
|
||||
| `yarn twenty server start` | Inicia o servidor (baixa a imagem se necessário) |
|
||||
| `yarn twenty server start --port 3030` | Iniciar em uma porta personalizada |
|
||||
| `yarn twenty server start --port 3030` | Inicia em uma porta personalizada |
|
||||
| `yarn twenty server stop` | Interrompe o servidor (preserva os dados) |
|
||||
| `yarn twenty server status` | Mostra a URL, a versão e as credenciais de login |
|
||||
| `yarn twenty server logs` | Transmite os logs do servidor |
|
||||
| `yarn twenty server reset` | Apaga os dados e começa do zero |
|
||||
| `yarn twenty server upgrade` | Baixa a imagem mais recente `twenty-app-dev` |
|
||||
| `yarn twenty server upgrade 2.2.0` | Atualizar para uma versão específica |
|
||||
| `yarn twenty server upgrade 2.2.0` | Atualiza para uma versão específica |
|
||||
|
||||
Os dados são persistidos entre reinicializações em dois volumes do Docker (`twenty-app-dev-data` para PostgreSQL, `twenty-app-dev-storage` para arquivos). Use `reset` para apagar tudo.
|
||||
|
||||
@@ -39,17 +39,17 @@ Passe `--test` para qualquer comando de `server` para gerenciar uma segunda inst
|
||||
| Comando | O que faz |
|
||||
| ----------------------------------- | ------------------------------------------------ |
|
||||
| `yarn twenty server start --test` | Inicia a instância de teste (padrão: porta 2021) |
|
||||
| `yarn twenty server stop --test` | Parar |
|
||||
| `yarn twenty server status --test` | Mostrar seu status |
|
||||
| `yarn twenty server logs --test` | Transmitir seus logs |
|
||||
| `yarn twenty server reset --test` | Apagar seus dados |
|
||||
| `yarn twenty server upgrade --test` | Atualizar sua imagem |
|
||||
| `yarn twenty server stop --test` | Para |
|
||||
| `yarn twenty server status --test` | Mostra seu status |
|
||||
| `yarn twenty server logs --test` | Transmite seus logs |
|
||||
| `yarn twenty server reset --test` | Apaga seus dados |
|
||||
| `yarn twenty server upgrade --test` | Atualiza sua imagem |
|
||||
|
||||
A instância de teste tem seu próprio contêiner (`twenty-app-dev-test`), volumes (`twenty-app-dev-test-data`, `twenty-app-dev-test-storage`) e configuração — ela é executada junto com sua instância principal sem conflitos. Combine `--test` com `--port` para substituir 2021.
|
||||
|
||||
## Configuração manual (sem o gerador)
|
||||
|
||||
Ignore a ferramenta de scaffolding se você estiver adicionando o SDK a um projeto existente:
|
||||
Ignore o gerador se você estiver adicionando o SDK a um projeto existente:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn add twenty-sdk twenty-client-sdk
|
||||
|
||||
@@ -173,12 +173,12 @@ Referência completa: [Conceitos](/l/pt/developers/extend/apps/getting-started/c
|
||||
Objetos, campos e relações bidirecionais.
|
||||
</Card>
|
||||
<Card title="Lógica" icon="bolt" href="/l/pt/developers/extend/apps/logic/overview">
|
||||
Funções de lógica, skills, agents e conexões OAuth.
|
||||
Funções lógicas, habilidades, agentes e conexões OAuth.
|
||||
</Card>
|
||||
<Card title="Layout" icon="table-columns" href="/l/pt/developers/extend/apps/layout/overview">
|
||||
Views, navegação, layouts de página, front components.
|
||||
Exibições, navegação, layouts de página, componentes de front-end.
|
||||
</Card>
|
||||
<Card title="Operações" icon="rocket" href="/l/pt/developers/extend/apps/operations/overview">
|
||||
CLI, testes, remotes, CI e publicação do seu aplicativo.
|
||||
CLI, testes, remotos, CI e publicação do seu aplicativo.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Itens do menu de comandos
|
||||
description: Apresente front components como ações rápidas e entradas do menu de comandos (Cmd+K) com `defineCommandMenuItem`.
|
||||
description: Exponha componentes de front-end como ações rápidas e entradas do menu de comandos (Cmd+K) com `defineCommandMenuItem`.
|
||||
icon: terminal
|
||||
---
|
||||
|
||||
@@ -36,7 +36,7 @@ export default defineCommandMenuItem({
|
||||
|
||||
## Comandos sem interface
|
||||
|
||||
Um item de menu de comando emparelhado com um [headless front component](/l/pt/developers/extend/apps/layout/front-components#headless-vs-non-headless) é a forma idiomática de disponibilizar uma ação de um clique — executar código, navegar ou confirmar e executar. A página de Front Components aborda os [SDK Command components](/l/pt/developers/extend/apps/layout/front-components#sdk-command-components) (`Command`, `CommandLink`, `CommandModal`, `CommandOpenSidePanelPage`) que lidam com o padrão de ação e desmontagem.
|
||||
Um item do menu de comandos emparelhado com um [componente de front-end sem interface](/l/pt/developers/extend/apps/layout/front-components#headless-vs-non-headless) é a forma idiomática de disponibilizar uma ação de um clique — executar código, navegar ou confirmar e executar. A página de Front Components aborda os [SDK Command components](/l/pt/developers/extend/apps/layout/front-components#sdk-command-components) (`Command`, `CommandLink`, `CommandModal`, `CommandOpenSidePanelPage`) que lidam com o padrão de ação e desmontagem.
|
||||
|
||||
Um fluxo típico:
|
||||
|
||||
|
||||
@@ -11,16 +11,16 @@ Componentes de front-end são componentes React que renderizam diretamente dentr
|
||||
Os componentes de front-end podem ser renderizados em dois locais dentro do Twenty:
|
||||
|
||||
* **Painel lateral** — Componentes de front-end não headless abrem no painel lateral direito. Este é o comportamento padrão quando um componente de front-end é acionado pelo menu de comandos.
|
||||
* **Widgets (painéis e páginas de registro)** — Componentes de front-end podem ser incorporados como widgets dentro de [page layouts](/l/pt/developers/extend/apps/layout/page-layouts). Ao configurar um painel ou o layout de uma página de registro, os usuários podem adicionar um widget de componente de front-end.
|
||||
* **Widgets (painéis e páginas de registro)** — Componentes de front-end podem ser incorporados como widgets dentro de [layouts de página](/l/pt/developers/extend/apps/layout/page-layouts). Ao configurar um painel ou o layout de uma página de registro, os usuários podem adicionar um widget de componente de front-end.
|
||||
|
||||
Um front component por si só não é acessível pela interface — é preciso *exibi-lo*. As duas maneiras de fazer isso são:
|
||||
Um componente de front-end por si só não é acessível pela UI — é preciso *exibi-lo*. As duas maneiras de fazer isso são:
|
||||
|
||||
* **Associe-o a um [command menu item](/l/pt/developers/extend/apps/layout/command-menu-items)** — registra-o no menu de comandos (Cmd+K) e, opcionalmente, como uma ação rápida fixada.
|
||||
* **Incorpore-o como um widget em um [page layout](/l/pt/developers/extend/apps/layout/page-layouts)** — posiciona-o na página de detalhes de um registro ou em um painel.
|
||||
* **Associe-o a um [item do menu de comandos](/l/pt/developers/extend/apps/layout/command-menu-items)** — registra-o no menu de comandos (Cmd+K) e, opcionalmente, como uma ação rápida fixada.
|
||||
* **Incorpore-o como um widget em um [layout de página](/l/pt/developers/extend/apps/layout/page-layouts)** — posiciona-o na página de detalhes de um registro ou em um painel.
|
||||
|
||||
## Exemplo básico
|
||||
|
||||
A maneira mais rápida de ver um front component em ação é associá-lo a um [`defineCommandMenuItem`](/l/pt/developers/extend/apps/layout/command-menu-items), para que ele apareça como um botão de ação rápida no canto superior direito da página:
|
||||
A maneira mais rápida de ver um componente de front-end em ação é associá-lo a um [`defineCommandMenuItem`](/l/pt/developers/extend/apps/layout/command-menu-items), para que ele apareça como um botão de ação rápida no canto superior direito da página:
|
||||
|
||||
```tsx src/front-components/hello-world.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk/define';
|
||||
@@ -76,7 +76,7 @@ Clique nele para renderizar o componente inline.
|
||||
|
||||
## Colocando um componente de front-end em uma página
|
||||
|
||||
Além de comandos, você pode incorporar um componente de front-end diretamente em uma página de registro adicionando-o como um widget em um **layout de página**. Veja [Page Layouts](/l/pt/developers/extend/apps/layout/page-layouts) para mais detalhes.
|
||||
Além de comandos, você pode incorporar um componente de front-end diretamente em uma página de registro adicionando-o como um widget em um **layout de página**. Veja [Layouts de página](/l/pt/developers/extend/apps/layout/page-layouts) para detalhes.
|
||||
|
||||
## Headless vs não headless
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ A **camada de layout** de um app do Twenty é tudo o que o usuário vê: onde o
|
||||
## Nesta seção
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Visualizações" icon="lista" href="/l/pt/developers/extend/apps/layout/views">
|
||||
<Card title="Visualizações" icon="list" href="/l/pt/developers/extend/apps/layout/views">
|
||||
`defineView` — configurações salvas de lista: colunas visíveis, filtros, grupos.
|
||||
</Card>
|
||||
<Card title="Itens do menu de navegação" icon="bars" href="/l/pt/developers/extend/apps/layout/navigation-menu-items">
|
||||
@@ -39,18 +39,18 @@ A **camada de layout** de um app do Twenty é tudo o que o usuário vê: onde o
|
||||
`defineFrontComponent` — componentes React em sandbox que são renderizados dentro do Twenty.
|
||||
</Card>
|
||||
<Card title="Itens do menu de comandos" icon="terminal" href="/l/pt/developers/extend/apps/layout/command-menu-items">
|
||||
`defineCommandMenuItem` — registra front components como entradas Cmd+K e ações rápidas.
|
||||
`defineCommandMenuItem` — registra componentes de front-end como entradas no Cmd+K e ações rápidas.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Onde o app aparece
|
||||
|
||||
| Superfície | O que controla | Entidade |
|
||||
| ------------------------------------------- | --------------------------------------------------------------------------------------------- | ----------------------------------------- |
|
||||
| **Barra lateral** | Uma entrada personalizada que aponta para uma visualização salva ou URL externa | `defineNavigationMenuItem` |
|
||||
| **Lista de registros** | Uma configuração salva para uma lista de um objeto — colunas visíveis, ordem, filtros, grupos | `defineView` |
|
||||
| **Página de detalhes do registro** | As abas e widgets em uma página de registro (do seu próprio objeto ou de um padrão) | `definePageLayout`, `definePageLayoutTab` |
|
||||
| **Dentro de qualquer uma das opções acima** | Um widget React personalizado — botões, formulários, dashboards, integrações | `defineFrontComponent` |
|
||||
| **Menu de comandos (Cmd+K)** | Uma ação rápida fixada ou comando oculto | `defineCommandMenuItem` |
|
||||
| Superfície | O que controla | Entidade |
|
||||
| ------------------------------------------- | ------------------------------------------------------------------------------------------ | ----------------------------------------- |
|
||||
| **Barra lateral** | Uma entrada personalizada que aponta para uma visualização salva ou URL externa | `defineNavigationMenuItem` |
|
||||
| **Lista de registros** | Uma configuração salva para um objeto — colunas visíveis, ordem, filtros, grupos | `defineView` |
|
||||
| **Página de detalhes do registro** | As abas e widgets em uma página de registro (do seu próprio objeto ou de um objeto padrão) | `definePageLayout`, `definePageLayoutTab` |
|
||||
| **Dentro de qualquer uma das opções acima** | Um widget React personalizado — botões, formulários, dashboards, integrações | `defineFrontComponent` |
|
||||
| **Menu de comandos (Cmd+K)** | Uma ação rápida fixada ou comando oculto | `defineCommandMenuItem` |
|
||||
|
||||
Os front components são executados dentro de um Web Worker isolado usando Remote DOM — eles são renderizados *nativamente* na página (não dentro de um iframe), mas não podem acessar diretamente a página host ou o DOM. A comunicação com o Twenty acontece por meio de uma API de host com passagem de mensagens.
|
||||
Os componentes de front-end são executados dentro de um Web Worker isolado usando Remote DOM — eles são renderizados *nativamente* na página (não dentro de um iframe), mas não podem acessar diretamente a página host ou o DOM. A comunicação com o Twenty acontece por meio de uma API de host com passagem de mensagens.
|
||||
|
||||
@@ -4,7 +4,7 @@ description: Personalize páginas de detalhes de registros — abas, widgets e o
|
||||
icon: table-columns
|
||||
---
|
||||
|
||||
Um **page layout** controla como a página de detalhes de um registro é organizada: quais abas aparecem e quais widgets elas contêm. Use `definePageLayout()` para declarar um layout para um objeto que você possui ou `definePageLayoutTab()` para adicionar uma única aba a um layout que já existe (seu ou um padrão da Twenty).
|
||||
Um **layout de página** controla como a página de detalhes de um registro é organizada: quais abas aparecem e quais widgets elas contêm. Use `definePageLayout()` para declarar um layout para um objeto que você possui ou `definePageLayoutTab()` para adicionar uma única aba a um layout que já existe (seu ou um padrão da Twenty).
|
||||
|
||||
| Caso de uso | Entidade |
|
||||
| ------------------------------------------------------------------------------ | --------------------- |
|
||||
@@ -96,7 +96,7 @@ export default definePageLayoutTab({
|
||||
|
||||
### Pontos-chave
|
||||
|
||||
* `pageLayoutUniversalIdentifier` é **obrigatório** e deve apontar para um page layout que já exista no momento da instalação — seja um layout padrão da Twenty ou um definido pelo seu próprio aplicativo. Referências entre apps para layouts pertencentes a outro aplicativo instalado não são compatíveis atualmente. Quando o layout pai estiver ausente, a instalação falha com um erro de validação claro.
|
||||
* `widgets` têm escopo apenas para esta aba — eles referenciam [front components](/l/pt/developers/extend/apps/layout/front-components), views etc., exatamente como widgets definidos inline em `definePageLayout`.
|
||||
* `pageLayoutUniversalIdentifier` é **obrigatório** e deve apontar para um layout de página que já exista no momento da instalação — seja um layout padrão da Twenty ou um definido pelo seu próprio aplicativo. Referências entre aplicativos para layouts pertencentes a outro aplicativo instalado não são compatíveis atualmente. Quando o layout pai estiver ausente, a instalação falha com um erro de validação claro.
|
||||
* `widgets` têm escopo apenas para esta aba — eles referenciam [front components](/l/pt/developers/extend/apps/layout/front-components), visualizações etc., exatamente como widgets definidos inline em `definePageLayout`.
|
||||
* `position` controla a ordenação em relação às abas existentes no layout de destino. Escolha um valor que posicione sua aba onde você deseja em relação às abas nativas.
|
||||
* Use isto em vez de `definePageLayout` quando você quiser apenas adicionar a um layout existente. Use `definePageLayout` quando você possuir todo o layout.
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
---
|
||||
title: Visualizações
|
||||
description: Envie visualizações salvas pré-configuradas — ordem das colunas, filtros, grupos — para objetos no seu app.
|
||||
description: Distribua visualizações salvas e pré-configuradas — ordem das colunas, filtros, grupos — para objetos no seu app.
|
||||
icon: list
|
||||
---
|
||||
|
||||
Uma **visualização** é uma configuração salva de como os registros de um objeto são exibidos: quais campos aparecem, sua ordem, se estão visíveis e quaisquer filtros ou grupos aplicados. Use `defineView()` para enviar visualizações pré-configuradas com o seu app — normalmente uma visualização de índice padrão para cada objeto personalizado que você cria.
|
||||
Uma **visualização** é uma configuração salva de como os registros de um objeto são exibidos: quais campos aparecem, sua ordem, se estão visíveis e quaisquer filtros ou grupos aplicados. Use `defineView()` para distribuir visualizações pré-configuradas com seu app — normalmente uma visualização de índice padrão para cada objeto personalizado que você cria.
|
||||
|
||||
```ts src/views/example-view.ts
|
||||
import { defineView, ViewKey } from 'twenty-sdk/define';
|
||||
@@ -40,4 +40,4 @@ export default defineView({
|
||||
|
||||
## Como as visualizações aparecem na UI
|
||||
|
||||
Uma visualização por si só não é acessível a partir da barra lateral. Para fazê-la aparecer lá, associe-a a um [item de menu de navegação](/l/pt/developers/extend/apps/layout/navigation-menu-items) do tipo `VIEW` que aponte para o `universalIdentifier` da visualização. Esse é o padrão canônico: cada objeto personalizado normalmente envia uma visualização padrão + uma entrada na barra lateral que a abre.
|
||||
Uma visualização por si só não é acessível a partir da barra lateral. Para fazê-la aparecer lá, associe-a a um [item de menu de navegação](/l/pt/developers/extend/apps/layout/navigation-menu-items) do tipo `VIEW` que aponte para o `universalIdentifier` da visualização. Esse é o padrão canônico: cada objeto personalizado normalmente inclui uma visualização padrão + uma entrada na barra lateral que a abre.
|
||||
|
||||
@@ -52,7 +52,6 @@ export default defineApplication({
|
||||
universalIdentifier: '...',
|
||||
displayName: 'Linear',
|
||||
description: 'Connect Linear to Twenty.',
|
||||
defaultRoleUniversalIdentifier: '...',
|
||||
// OAuth client credentials live on the app registration (one OAuth app per
|
||||
// Twenty server, configured by the admin) — not per-workspace. Declare them
|
||||
// as serverVariables so the admin can fill them in once for all installs.
|
||||
|
||||
@@ -370,5 +370,5 @@ Pontos-chave:
|
||||
* `TWENTY_API_URL` — URL base da API do Twenty
|
||||
* `TWENTY_APP_ACCESS_TOKEN` — Chave de curta duração com escopo para o papel de função padrão do seu aplicativo
|
||||
|
||||
Você **não** precisa passá-las para os clientes — eles leem de `process.env` automaticamente. As permissões da chave de API são determinadas pelo papel referenciado em `defaultRoleUniversalIdentifier` no seu `application-config.ts`.
|
||||
Você **não** precisa passá-las para os clientes — eles leem de `process.env` automaticamente. As permissões da chave de API são determinadas pelo papel declarado com `defineApplicationRole()` (ou referenciado via `defaultRoleUniversalIdentifier` em `application-config.ts`).
|
||||
</Note>
|
||||
|
||||
@@ -4,7 +4,7 @@ description: TypeScript do lado do servidor que é executado dentro do Twenty
|
||||
icon: bolt
|
||||
---
|
||||
|
||||
A **camada de lógica** de um app Twenty é o código que *é executado* — manipuladores TypeScript do lado do servidor reagindo a solicitações HTTP, agendamentos cron e alterações de registros; habilidades e agentes de IA que vivem dentro do workspace; e conexões OAuth que permitem que suas funções ajam em nome de um usuário em serviços de terceiros.
|
||||
A **camada de lógica** de um app do Twenty é o código que *é executado* — manipuladores TypeScript do lado do servidor que reagem a solicitações HTTP, agendamentos CRON e alterações de registros; habilidades e agentes de IA que vivem dentro do workspace; e conexões OAuth que permitem que suas funções ajam em nome de um usuário em serviços de terceiros.
|
||||
|
||||
```text
|
||||
┌─ HTTP route ──┐
|
||||
@@ -48,7 +48,7 @@ Uma função de lógica escolhe um ou mais gatilhos — cada entrada abaixo é u
|
||||
| **Ferramenta de IA** | Um recurso de IA do Twenty decide chamar sua função | `toolTriggerSettings` |
|
||||
| **Ação de fluxo de trabalho** | Uma etapa de fluxo de trabalho invoca sua função | `workflowActionTriggerSettings` |
|
||||
|
||||
As funções são executadas em sandbox em processos Node.js isolados e acessam o workspace por meio de um cliente de API tipado com escopo para a função declarada em [`defineApplication()`](/l/pt/developers/extend/apps/config/application).
|
||||
As funções são executadas em sandbox, em processos Node.js isolados, e acessam o workspace por meio de um cliente de API tipado, com escopo definido pelo papel declarado em [`defineApplication()`](/l/pt/developers/extend/apps/config/application).
|
||||
|
||||
<Note>
|
||||
**Ganchos de instalação** — código que é executado antes ou depois da instalação — compartilham esse runtime, mas usam suas próprias funções define e ficam em [Config → Install Hooks](/l/pt/developers/extend/apps/config/install-hooks).
|
||||
|
||||
@@ -14,11 +14,11 @@ A **camada de operações** é tudo o que você faz *para* o seu app em vez de *
|
||||
dev build yarn twenty publish (npm → marketplace)
|
||||
```
|
||||
|
||||
## Nesta seção
|
||||
## Nesta secção
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="CLI" icon="terminal" href="/l/pt/developers/extend/apps/operations/cli">
|
||||
`yarn twenty` reference — exec, logs, uninstall, remotes.
|
||||
Referência do `yarn twenty` — exec, logs, uninstall, remotes.
|
||||
</Card>
|
||||
<Card title="Testes" icon="flask" href="/l/pt/developers/extend/apps/operations/testing">
|
||||
Configuração do Vitest, testes de integração, verificação de tipos, fluxo de trabalho de CI.
|
||||
|
||||
@@ -50,7 +50,7 @@ yarn twenty deploy
|
||||
### Compartilhando um aplicativo implantado
|
||||
|
||||
<Warning>
|
||||
Compartilhar aplicativos privados (tarball) entre espaços de trabalho é um recurso do plano **Enterprise**. A guia **Distribution** exibirá um aviso de atualização em vez dos controles de compartilhamento até que seu espaço de trabalho tenha uma chave Enterprise válida. Vá para [Configurações > Painel de Administração > Enterprise](/settings/admin-panel#enterprise) para ativá-lo.
|
||||
Compartilhar aplicativos privados (tarball) entre espaços de trabalho é um recurso do plano **Enterprise**. A guia **Distribuição** exibirá um aviso de atualização em vez dos controles de compartilhamento até que seu espaço de trabalho tenha uma chave Enterprise válida. Vá para [Configurações > Painel de Administração > Enterprise](/settings/admin-panel#enterprise) para ativá-lo.
|
||||
</Warning>
|
||||
|
||||
Aplicativos em tarball não são listados no marketplace público, então outros espaços de trabalho no mesmo servidor não os descobrirão ao navegar. Assim que o seu espaço de trabalho estiver no plano Enterprise, você pode compartilhar um app implantado desta forma:
|
||||
@@ -107,7 +107,7 @@ O valor é um [intervalo semver](https://github.com/npm/node-semver#ranges) padr
|
||||
* Se o servidor não tiver `APP_VERSION` configurado, a verificação será ignorada.
|
||||
|
||||
<Note>
|
||||
O servidor realiza a verificação definitiva — ele valida `engines.twenty` tanto no upload do tarball quanto na instalação no workspace. Se você implantar um tarball fora de banda ou instalar a partir do marketplace, o servidor ainda impõe a compatibilidade.
|
||||
O servidor realiza a verificação definitiva — ele valida `engines.twenty` tanto no upload do tarball quanto na instalação no espaço de trabalho. Se você implantar um tarball fora de banda ou instalar a partir do marketplace, o servidor ainda impõe a compatibilidade.
|
||||
</Note>
|
||||
|
||||
## CI/CD automatizado (fluxos de trabalho pré-configurados)
|
||||
@@ -140,7 +140,7 @@ Faz o deploy do seu app para um servidor Twenty configurado a cada push para `ma
|
||||
|
||||
1. Faz checkout do head do PR (para PRs rotulados) ou do commit enviado.
|
||||
2. Executa `twentyhq/twenty/.github/actions/deploy-twenty-app@main` — o equivalente em CI de `yarn twenty deploy`.
|
||||
3. Executa `twentyhq/twenty/.github/actions/install-twenty-app@main` para que a versão recém-implantada seja instalada no workspace de destino.
|
||||
3. Executa `twentyhq/twenty/.github/actions/install-twenty-app@main` para que a versão recém-implantada seja instalada no espaço de trabalho de destino.
|
||||
|
||||
**Configuração obrigatória:**
|
||||
|
||||
@@ -187,7 +187,6 @@ export default defineApplication({
|
||||
universalIdentifier: '...',
|
||||
displayName: 'My App',
|
||||
description: 'A great app',
|
||||
defaultRoleUniversalIdentifier: DEFAULT_ROLE_UNIVERSAL_IDENTIFIER,
|
||||
logoUrl: 'public/logo.png',
|
||||
screenshots: [
|
||||
'public/screenshot-1.png',
|
||||
|
||||
@@ -164,7 +164,7 @@
|
||||
"label": "Configuração"
|
||||
},
|
||||
"appsData": {
|
||||
"label": "Data"
|
||||
"label": "Dados"
|
||||
},
|
||||
"appsLogic": {
|
||||
"label": "Lógica"
|
||||
|
||||
@@ -13,7 +13,6 @@ Fiecare aplicație trebuie să aibă exact un apel `defineApplication`. Acesta d
|
||||
|
||||
```ts src/application-config.ts
|
||||
import { defineApplication } from 'twenty-sdk/define';
|
||||
import { DEFAULT_ROLE_UNIVERSAL_IDENTIFIER } from 'src/roles/default-role';
|
||||
|
||||
export default defineApplication({
|
||||
universalIdentifier: '39783023-bcac-41e3-b0d2-ff1944d8465d',
|
||||
@@ -27,7 +26,6 @@ export default defineApplication({
|
||||
isSecret: false,
|
||||
},
|
||||
},
|
||||
defaultRoleUniversalIdentifier: DEFAULT_ROLE_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
```
|
||||
|
||||
@@ -35,12 +33,13 @@ Notițe:
|
||||
|
||||
* Câmpurile `universalIdentifier` sunt ID-uri deterministe pe care le dețineți. Generați-le o singură dată și mențineți-le stabile între sincronizări.
|
||||
* `applicationVariables` devin variabile de mediu pentru funcțiile și componentele front-end (de exemplu, `DEFAULT_RECIPIENT_NAME` este disponibil ca `process.env.DEFAULT_RECIPIENT_NAME`).
|
||||
* `defaultRoleUniversalIdentifier` trebuie să facă referire la un rol definit cu [`defineRole()`](/l/ro/developers/extend/apps/config/roles).
|
||||
* Rolul implicit este detectat automat din fișierul de rol marcat cu [`defineApplicationRole()`](/l/ro/developers/extend/apps/config/roles) — nu este necesar să faci referire la el în `defineApplication()`.
|
||||
* Funcțiile de pre-instalare și post-instalare sunt detectate automat în timpul construirii manifestului — nu trebuie să le referiți în `defineApplication()`.
|
||||
* Transmiterea explicită a `defaultRoleUniversalIdentifier` este în continuare acceptată pentru compatibilitate retroactivă, dar este considerată învechită în favoarea `defineApplicationRole()`.
|
||||
|
||||
## Rol implicit pentru funcții
|
||||
|
||||
`defaultRoleUniversalIdentifier` controlează la ce pot avea acces funcțiile logice și componentele front-end ale aplicației:
|
||||
Rolul declarat cu [`defineApplicationRole()`](/l/ro/developers/extend/apps/config/roles) controlează la ce pot avea acces funcțiile logice și componentele de interfață ale aplicației:
|
||||
|
||||
* Tokenul de runtime injectat ca `TWENTY_APP_ACCESS_TOKEN` este derivat din acest rol.
|
||||
* Clientul API tipizat este restricționat la permisiunile acordate acelui rol.
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
---
|
||||
title: Instalare hooks
|
||||
title: Hook-uri de instalare
|
||||
description: Rulați logică înainte sau după instalare — pentru a popula cu date inițiale, a face copii de rezervă ale înregistrărilor, a valida actualizarea.
|
||||
icon: wrench
|
||||
---
|
||||
|
||||
Install hooks sunt funcții logice speciale care rulează în timpul ciclului de viață al instalării sau actualizării. Acestea folosesc același runtime de handler ca și [funcțiile logice](/l/ro/developers/extend/apps/logic/logic-functions) obișnuite și primesc un `InstallPayload`, dar sunt declarate cu propriile lor funcții de definire — `definePostInstallLogicFunction()` și `definePreInstallLogicFunction()` — și există în afara modelului obișnuit de declanșatori (HTTP, cron, evenimente de bază de date).
|
||||
Hook-urile de instalare sunt funcții logice speciale care rulează în timpul ciclului de viață al instalării sau actualizării. Acestea folosesc același runtime de handler ca și [funcțiile logice](/l/ro/developers/extend/apps/logic/logic-functions) obișnuite și primesc un `InstallPayload`, dar sunt declarate cu propriile lor funcții de definire — `definePostInstallLogicFunction()` și `definePreInstallLogicFunction()` — și există în afara modelului obișnuit de declanșatori (HTTP, cron, evenimente de bază de date).
|
||||
|
||||
Fiecare aplicație poate defini **cel mult o funcție de pre-instalare** și **cel mult o funcție de post-instalare**. Construirea manifestului va genera o eroare dacă este detectată mai mult de una dintre oricare dintre ele.
|
||||
Fiecare aplicație poate defini **cel mult o funcție de pre-instalare** și **cel mult o funcție de post-instalare**. Construirea manifestului va genera o eroare dacă se detectează mai mult de una din oricare dintre ele.
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
@@ -58,7 +58,7 @@ Puncte cheie:
|
||||
* Asigurați-vă că handlerul dvs. este idempotent. În modul asincron, coada poate reîncerca de până la trei ori; în oricare mod, hook-ul poate rula din nou la actualizări când `shouldRunOnVersionUpgrade: true`.
|
||||
* Variabilele de mediu `APPLICATION_ID`, `APP_ACCESS_TOKEN` și `API_URL` sunt disponibile în interiorul handlerului (la fel ca în orice altă funcție logică), astfel încât puteți apela API-ul Twenty cu un token de acces al aplicației limitat la aplicația dvs.
|
||||
* 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.
|
||||
* `universalIdentifier`, `shouldRunOnVersionUpgrade` și `shouldRunSynchronously` ale funcției sunt atașate automat la manifestul aplicației în câmpul `postInstallLogicFunction` în timpul build-ului — nu este nevoie să le referi în [`defineApplication()`](/l/ro/developers/extend/apps/config/application).
|
||||
* `universalIdentifier`, `shouldRunOnVersionUpgrade` și `shouldRunSynchronously` ale funcției sunt atașate automat la manifestul aplicației în câmpul `postInstallLogicFunction` în timpul build-ului — nu este nevoie să le referiți în [`defineApplication()`](/l/ro/developers/extend/apps/config/application).
|
||||
* 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.
|
||||
* **Nu se execută în modul dev**: când o aplicație este înregistrată local (prin `yarn twenty dev`), serverul sare complet peste fluxul de instalare și sincronizează fișierele direct prin watcher-ul CLI — astfel încât post-install nu rulează niciodată în modul dev, indiferent de `shouldRunSynchronously`. Folosiți `yarn twenty exec --postInstall` pentru a-l declanșa manual într-un workspace care rulează.
|
||||
|
||||
@@ -99,7 +99,7 @@ Puncte cheie:
|
||||
* **Nu se execută în modul dev**: la fel ca post-install — fluxul de instalare este sărit complet pentru aplicațiile înregistrate local, astfel încât pre-install nu rulează niciodată sub `yarn twenty dev`. Folosiți `yarn twenty exec --preInstall` pentru a-l declanșa manual.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="Pre-install vs post-install: când să folosești fiecare" description="Alegerea hook-ului de instalare potrivit">
|
||||
<Accordion title="Pre-install vs post-install: când să folosiți fiecare" description="Alegerea hook-ului de instalare potrivit">
|
||||
|
||||
Ambele hook-uri fac parte din același flux de instalare și primesc același `InstallPayload`. Diferența constă în **momentul** în care rulează în raport cu migrarea metadatelor workspace-ului, iar asta schimbă ce date pot atinge în siguranță.
|
||||
|
||||
@@ -109,7 +109,7 @@ Pre-install este întotdeauna **sincron** (blochează instalarea și o poate în
|
||||
|
||||
* Popularea datelor implicite (crearea înregistrărilor inițiale, a vizualizărilor implicite, a conținutului demo) pentru obiectele și câmpurile adăugate recent.
|
||||
* Înregistrarea webhook-urilor la servicii terțe, acum că aplicația are acreditările sale.
|
||||
* Apelarea propriului tău API pentru a finaliza configurarea care depinde de metadatele sincronizate.
|
||||
* Apelarea propriului dvs. API pentru a finaliza configurarea care depinde de metadatele sincronizate.
|
||||
* Logică idempotentă de tipul "asigurați-vă că acest lucru există" care ar trebui să reconcilieze starea la fiecare actualizare — combină cu `shouldRunOnVersionUpgrade: true`.
|
||||
|
||||
Exemplu — populează o înregistrare `PostCard` implicită după instalare:
|
||||
@@ -139,9 +139,9 @@ export default definePostInstallLogicFunction({
|
||||
|
||||
**Folosiți `pre-install` atunci când o migrare altfel ar distruge sau ar corupe datele existente.** Deoarece pre-install rulează pe schema *anterioară* și eșecul său anulează actualizarea, acesta este locul potrivit pentru orice este riscant:
|
||||
|
||||
* **Crearea unui backup al datelor care urmează să fie eliminate sau restructurate** — de exemplu, elimini un câmp în v2 și trebuie să-i copiezi valorile într-un alt câmp sau să le exporți în stocare înainte de rularea migrării.
|
||||
* **Arhivarea înregistrărilor pe care o nouă constrângere le-ar invalida** — de exemplu, un câmp devine `NOT NULL` și trebuie mai întâi să ștergi sau să corectezi rândurile cu valori nule.
|
||||
* **Validarea compatibilității și refuzarea actualizării dacă datele curente nu pot fi migrate fără probleme** — aruncă din handler și instalarea se oprește fără ca modificări să fie aplicate. Aceasta este mai sigur decât să descoperi incompatibilitatea în mijlocul migrării.
|
||||
* **Crearea unui backup al datelor care urmează să fie eliminate sau restructurate** — de exemplu, eliminați un câmp în v2 și trebuie să-i copiați valorile într-un alt câmp sau să le exportați în stocare înainte de rularea migrării.
|
||||
* **Arhivarea înregistrărilor pe care o nouă constrângere le-ar invalida** — de exemplu, un câmp devine `NOT NULL` și trebuie mai întâi să ștergeți sau să corectați rândurile cu valori nule.
|
||||
* **Validarea compatibilității și refuzarea actualizării dacă datele curente nu pot fi migrate fără probleme** — aruncați din handler și instalarea se oprește fără ca modificări să fie aplicate. Aceasta este mai sigur decât să descoperi incompatibilitatea în mijlocul migrării.
|
||||
* **Redenumirea sau schimbarea cheilor datelor** înaintea unei modificări de schemă care ar pierde asocierile.
|
||||
|
||||
Exemplu — arhivează înregistrări înainte de o migrare distructivă:
|
||||
@@ -188,13 +188,13 @@ export default definePreInstallLogicFunction({
|
||||
|
||||
**Regulă practică:**
|
||||
|
||||
| Vrei să... | Folosiți |
|
||||
| Doriți să... | Folosiți |
|
||||
| ------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ |
|
||||
| Populați date implicite, configurați workspace-ul, înregistrați resurse externe | `post-install` |
|
||||
| Rulați populări de durată sau apeluri către terți care nu ar trebui să blocheze răspunsul la instalare | `post-install` (implicit — `shouldRunSynchronously: false`, cu reîncercări ale workerului) |
|
||||
| Rulați o configurare rapidă de care apelantul va depinde imediat după ce apelul de instalare revine | `post-install` cu `shouldRunSynchronously: true` |
|
||||
| Citești sau faci backup datelor pe care migrarea iminentă le-ar pierde | `pre-install` |
|
||||
| Respingeți o actualizare care ar corupe datele existente | `pre-install` (aruncă din handler) |
|
||||
| Citiți sau faceți backup datelor pe care migrarea iminentă le-ar pierde | `pre-install` |
|
||||
| Respingeți o actualizare care ar corupe datele existente | `pre-install` (aruncați din handler) |
|
||||
| Rulați o reconciliere la fiecare actualizare | `post-install` cu `shouldRunOnVersionUpgrade: true` |
|
||||
| Faceți o configurare unică doar la prima instalare | `post-install` cu `shouldRunOnVersionUpgrade: false` (implicit) |
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ description: Configurează însăși aplicația — identitatea ei, permisiunile
|
||||
icon: screwdriver-wrench
|
||||
---
|
||||
|
||||
**Stratul de configurare** al unei aplicații Twenty este cel care descrie aplicația *platformei* — identitatea ei, permisiunile pe care le deține și codul care rulează în timpul instalării sau actualizării. Aceste declarații nu adaugă noi structuri de date sau comportamente la rulare; ele îi spun lui Twenty *cine este aplicația* și *cum să fie configurată*.
|
||||
**Stratul de configurare** al unei aplicații Twenty este cel care descrie aplicația *pentru platformă* — identitatea ei, permisiunile pe care le deține și codul care rulează în timpul instalării sau actualizării. Aceste declarații nu adaugă noi structuri de date sau comportamente la rulare; ele îi spun lui Twenty *cine este aplicația* și *cum să fie configurată*.
|
||||
|
||||
```text
|
||||
┌────────────────────────────────────────────────────────┐
|
||||
@@ -29,11 +29,11 @@ icon: screwdriver-wrench
|
||||
## În această secțiune
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Configurare aplicație" icon="rocket" href="/l/ro/developers/extend/apps/config/application">
|
||||
<Card title="Configurația aplicației" icon="rocket" href="/l/ro/developers/extend/apps/config/application">
|
||||
`defineApplication` — identitate, rol implicit, variabile, metadate pentru marketplace.
|
||||
</Card>
|
||||
<Card title="Roluri și permisiuni" icon="shield-halved" href="/l/ro/developers/extend/apps/config/roles">
|
||||
`defineRole` — declară ce pot citi și scrie funcțiile logice ale aplicației tale.
|
||||
`defineRole` — declară ce pot citi și scrie funcțiile de logică ale aplicației dvs.
|
||||
</Card>
|
||||
<Card title="Hook-uri de instalare" icon="wrench" href="/l/ro/developers/extend/apps/config/install-hooks">
|
||||
`definePreInstallLogicFunction` și `definePostInstallLogicFunction` — fac backup la date, introduc valori implicite, validează actualizările.
|
||||
@@ -43,9 +43,9 @@ icon: screwdriver-wrench
|
||||
## Cum se leagă componentele între ele
|
||||
|
||||
* **Aplicația** este punctul de intrare. Fiecare aplicație are exact un apel `defineApplication()`, iar acesta indică un singur **Rol** ca implicit.
|
||||
* **Rolul** controlează ce pot citi și scrie funcțiile logice și componentele de interfață ale aplicației. Urmează principiul celui mai mic privilegiu: acordă doar permisiunile de care codul tău are cu adevărat nevoie.
|
||||
* **Rolul** controlează ce pot citi și scrie funcțiile de logică și componentele front-end ale aplicației. Respectați principiul celui mai mic privilegiu: acordați doar permisiunile de care codul dvs. are cu adevărat nevoie.
|
||||
* **Hook-urile de instalare** rulează în timpul instalării sau actualizării — pre-install înainte de migrarea metadatelor (astfel încât să poată refuza o actualizare riscantă), post-install după migrare (astfel încât să poată introduce date implicite în noua schemă).
|
||||
|
||||
<Note>
|
||||
Hook-urile de instalare împart același runtime cu [funcțiile logice](/l/ro/developers/extend/apps/logic/logic-functions) — aceeași semnătură a handler-ului, aceleași variabile de mediu, același client API tipizat — dar sunt declarate cu propriile lor funcții `define` și există în afara modelului obișnuit de declanșare (HTTP, cron, evenimente de bază de date).
|
||||
Hook-urile de instalare împart același runtime cu [funcțiile de logică](/l/ro/developers/extend/apps/logic/logic-functions) — aceeași semnătură a handlerului, aceleași variabile de mediu, același client API tipizat — dar sunt declarate cu propriile lor funcții `define` și există în afara modelului obișnuit de declanșare (HTTP, cron, evenimente de bază de date).
|
||||
</Note>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Resurse publice
|
||||
description: Livrați fișiere statice — imagini, icoane, fonturi — împreună cu aplicația dvs. prin folderul public/.
|
||||
description: Livrați fișiere statice — imagini, pictograme, fonturi — împreună cu aplicația dvs. prin folderul public/.
|
||||
icon: folder-open
|
||||
---
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
---
|
||||
title: Roluri și permisiuni
|
||||
description: Declarați ce obiecte și câmpuri pot citi și scrie funcțiile de logică și componentele front ale aplicației dvs.
|
||||
description: Declarați ce obiecte și câmpuri pot citi și scrie funcțiile de logică și componentele front-end ale aplicației dvs.
|
||||
icon: shield-halved
|
||||
---
|
||||
|
||||
Un **rol** este un set de permisiuni: ce obiecte poate citi sau scrie o aplicație, ce câmpuri poate vedea și ce capabilități la nivel de platformă poate folosi. Toate funcțiile de logică și componentele front ale unei aplicații moștenesc permisiunile rolului declarat ca `defaultRoleUniversalIdentifier` în [`defineApplication`](/l/ro/developers/extend/apps/config/application).
|
||||
Un **rol** este un set de permisiuni: ce obiecte poate citi sau scrie o aplicație, ce câmpuri poate vedea și ce capabilități la nivel de platformă poate folosi. Funcțiile de logică și componentele front-end ale fiecărei aplicații moștenesc permisiunile rolului marcat cu `defineApplicationRole()` (consultați [Rolul implicit pentru funcții](#the-default-function-role) mai jos).
|
||||
|
||||
```ts src/roles/restricted-company-role.ts
|
||||
import {
|
||||
@@ -51,15 +51,15 @@ export default defineRole({
|
||||
|
||||
## Rolul implicit pentru funcții
|
||||
|
||||
Când generați o aplicație nouă, CLI creează un fișier de rol implicit:
|
||||
Când generați o aplicație nouă, CLI creează un fișier de rol implicit declarat cu `defineApplicationRole()`:
|
||||
|
||||
```ts src/roles/default-role.ts
|
||||
import { defineRole, PermissionFlag } from 'twenty-sdk/define';
|
||||
import { defineApplicationRole, PermissionFlag } from 'twenty-sdk/define';
|
||||
|
||||
export const DEFAULT_ROLE_UNIVERSAL_IDENTIFIER =
|
||||
'b648f87b-1d26-4961-b974-0908fd991061';
|
||||
|
||||
export default defineRole({
|
||||
export default defineApplicationRole({
|
||||
universalIdentifier: DEFAULT_ROLE_UNIVERSAL_IDENTIFIER,
|
||||
label: 'Default function role',
|
||||
description: 'Default role for function Twenty client',
|
||||
@@ -77,10 +77,13 @@ export default defineRole({
|
||||
});
|
||||
```
|
||||
|
||||
`universalIdentifier` al acestui rol este referențiat din `application-config.ts` ca `defaultRoleUniversalIdentifier`:
|
||||
`defineApplicationRole()` este un wrapper subțire în jurul `defineRole()` care marchează rolul utilizat ca implicit pentru aplicația dvs. în momentul instalării. Validarea este identică cu `defineRole`, dar pipeline-ul de build conectează automat `universalIdentifier` în `defaultRoleUniversalIdentifier` din manifestul aplicației — astfel încât nu trebuie să îl referiți manual din [`defineApplication`](/l/ro/developers/extend/apps/config/application).
|
||||
|
||||
* **`*.role.ts`** declară ce poate face rolul.
|
||||
* **`application-config.ts`** indică acel rol, astfel încât funcțiile moștenesc permisiunile lui.
|
||||
Notițe:
|
||||
|
||||
* Exact **un** `defineApplicationRole(...)` este permis per aplicație — build-ul manifestului va eșua dacă găsește mai mult de unul.
|
||||
* Utilizați `defineRole()` (nu `defineApplicationRole()`) pentru orice roluri **suplimentare** cu care este livrată aplicația.
|
||||
* Setarea explicită a `defaultRoleUniversalIdentifier` în `defineApplication()` este în continuare acceptată pentru compatibilitate retroactivă, dar este considerată învechită în favoarea `defineApplicationRole()`.
|
||||
|
||||
## Cele mai bune practici
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ export default defineObject({
|
||||
|
||||
* `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.
|
||||
* Tabloul `fields` este opțional — puteți defini obiecte fără câmpuri personalizate.
|
||||
* Câmpurile inline definite aici **nu** au nevoie de `objectUniversalIdentifier` — este moștenit de la obiectul părinte. Folosiți [`defineField()`](/l/ro/developers/extend/apps/data/extending-objects) pentru a adăuga câmpuri la obiecte care nu vă aparțin.
|
||||
* Puteți genera obiecte noi cu `yarn twenty add object`, care vă ghidează prin denumire, câmpuri și relații. Consultați [Arhitectură → Generarea entităților](/l/ro/developers/extend/apps/getting-started/scaffolding).
|
||||
|
||||
@@ -90,4 +90,4 @@ export default defineObject({
|
||||
|
||||
* **Conectați acest obiect la altele** — consultați [Relații](/l/ro/developers/extend/apps/data/relations) pentru modelul de relație bidirecțională.
|
||||
* **Adăugați câmpuri la obiecte din alte aplicații** — consultați [Extinderea obiectelor](/l/ro/developers/extend/apps/data/extending-objects) pentru `defineField()`.
|
||||
* **Afișați acest obiect în interfața utilizator** — consultați [Vizualizări](/l/ro/developers/extend/apps/layout/views) și [Elemente de meniu de navigare](/l/ro/developers/extend/apps/layout/navigation-menu-items) pentru a-l plasa în bara laterală.
|
||||
* **Afișați acest obiect în interfața utilizatorului** — consultați [Vizualizări](/l/ro/developers/extend/apps/layout/views) și [Elemente de meniu de navigare](/l/ro/developers/extend/apps/layout/navigation-menu-items) pentru a-l plasa în bara laterală.
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Structura proiectului
|
||||
description: Ce se află într-o aplicație Twenty generată cu scaffold — fișiere, foldere și ce face fiecare.
|
||||
description: Ce conține o aplicație Twenty generată — fișiere, foldere și ce face fiecare.
|
||||
icon: folder-tree
|
||||
---
|
||||
|
||||
@@ -32,7 +32,7 @@ my-twenty-app/
|
||||
| `src/application-config.ts` | **Necesar.** Fișierul principal de configurare pentru aplicație. |
|
||||
| `src/default-role.ts` | Rol implicit care controlează la ce pot avea acces funcțiile logice. |
|
||||
| `src/constants/universal-identifiers.ts` | UUID-uri generate automat și metadate (nume afișat, descriere). |
|
||||
| `src/__tests__/` | Teste de integrare (configurare + test exemplu). |
|
||||
| `src/__tests__/` | Teste de integrare (configurare + test de exemplu). |
|
||||
| `public/` | Resurse statice (imagini, fonturi) servite împreună cu aplicația. |
|
||||
|
||||
<Note>
|
||||
|
||||
@@ -144,7 +144,7 @@ Folosiți `--example` pentru a începe cu un proiect mai complet (obiecte person
|
||||
npx create-twenty-app@latest my-twenty-app --example postcard
|
||||
```
|
||||
|
||||
Exemplele se află în [twenty-apps/examples](https://github.com/twentyhq/twenty/tree/main/packages/twenty-apps/examples). Puteți, de asemenea, să creați scheletul entităților individuale într-un proiect existent cu `yarn twenty add` — vedeți [Scaffolding](/l/ro/developers/extend/apps/getting-started/scaffolding).
|
||||
Exemplele se află în [twenty-apps/examples](https://github.com/twentyhq/twenty/tree/main/packages/twenty-apps/examples). Puteți, de asemenea, să creați scheletul entităților individuale într-un proiect existent cu `yarn twenty add` — vedeți [Crearea scheletului](/l/ro/developers/extend/apps/getting-started/scaffolding).
|
||||
|
||||
---
|
||||
|
||||
@@ -176,7 +176,7 @@ Referință completă: [Concepte](/l/ro/developers/extend/apps/getting-started/c
|
||||
Funcții logice, abilități, agenți și conexiuni OAuth.
|
||||
</Card>
|
||||
<Card title="Aspect" icon="table-columns" href="/l/ro/developers/extend/apps/layout/overview">
|
||||
Vizualizări, navigare, machete de pagină, componente front-end.
|
||||
Vizualizări, navigare, layouturi de pagină, componente front-end.
|
||||
</Card>
|
||||
<Card title="Operațiuni" icon="rocket" href="/l/ro/developers/extend/apps/operations/overview">
|
||||
CLI, testare, remote-uri, CI și publicarea aplicației.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
title: Generare schelet (Scaffolding)
|
||||
title: Generare automată
|
||||
description: Generați fișiere de entități în mod interactiv cu yarn twenty add — obiecte, câmpuri, vizualizări, funcții logice și altele.
|
||||
icon: wand-magic-sparkles
|
||||
---
|
||||
|
||||
@@ -13,14 +13,14 @@ Componentele front-end pot fi afișate în două locații în cadrul Twenty:
|
||||
* **Panou lateral** — Componentele front-end care nu sunt headless se deschid în panoul lateral din dreapta. Acesta este comportamentul implicit atunci când o componentă front-end este declanșată din meniul de comenzi.
|
||||
* **Widgeturi (tablouri de bord și pagini de înregistrare)** — Componentele frontale pot fi încorporate ca widgeturi în [machetele de pagină](/l/ro/developers/extend/apps/layout/page-layouts). La configurarea unui tablou de bord sau a machetei unei pagini de înregistrare, utilizatorii pot adăuga un widget de componentă front-end.
|
||||
|
||||
Un front component de unul singur nu este accesibil din interfața utilizator — trebuie să îl *expui*. Cele două moduri de a face asta sunt:
|
||||
O componentă frontală, de una singură, nu este accesibilă din interfața utilizatorului — trebuie să o *expui*. Cele două moduri de a face asta sunt:
|
||||
|
||||
* **Asociază-l cu un [element de meniu de comenzi](/l/ro/developers/extend/apps/layout/command-menu-items)** — îl înregistrează în meniul de comenzi (Cmd+K) și, opțional, ca acțiune rapidă fixată.
|
||||
* **Încorporează-l ca widget într-o [machetă de pagină](/l/ro/developers/extend/apps/layout/page-layouts)** — îl plasează pe pagina de detalii a unei înregistrări sau pe un tablou de bord.
|
||||
|
||||
## Exemplu de bază
|
||||
|
||||
Cel mai rapid mod de a vedea un front component în acțiune este să îl asociezi cu un [`defineCommandMenuItem`](/l/ro/developers/extend/apps/layout/command-menu-items), astfel încât să apară ca un buton de acțiune rapidă în colțul din dreapta sus al paginii:
|
||||
Cel mai rapid mod de a vedea o componentă frontală în acțiune este să o asociezi cu un [`defineCommandMenuItem`](/l/ro/developers/extend/apps/layout/command-menu-items), astfel încât să apară ca un buton de acțiune rapidă în colțul din dreapta sus al paginii:
|
||||
|
||||
```tsx src/front-components/hello-world.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk/define';
|
||||
|
||||
@@ -26,10 +26,10 @@ icon: table-columns
|
||||
## În această secțiune
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Vizualizări" icon="listă" href="/l/ro/developers/extend/apps/layout/views">
|
||||
`defineView` — configurații salvate de liste: coloane vizibile, filtre, grupuri.
|
||||
<Card title="Vizualizări" icon="list" href="/l/ro/developers/extend/apps/layout/views">
|
||||
`defineView` — configurații salvate pentru liste: coloane vizibile, filtre, grupuri.
|
||||
</Card>
|
||||
<Card title="Elemente din meniul de navigare" icon="bars" href="/l/ro/developers/extend/apps/layout/navigation-menu-items">
|
||||
<Card title="Elemente de meniu de navigare" icon="bars" href="/l/ro/developers/extend/apps/layout/navigation-menu-items">
|
||||
`defineNavigationMenuItem` — intrări în bara laterală care trimit către vizualizări sau URL-uri externe.
|
||||
</Card>
|
||||
<Card title="Layouturi de pagină" icon="table-columns" href="/l/ro/developers/extend/apps/layout/page-layouts">
|
||||
@@ -39,7 +39,7 @@ icon: table-columns
|
||||
`defineFrontComponent` — componente React izolate care rulează în interiorul Twenty.
|
||||
</Card>
|
||||
<Card title="Elemente din meniul de comenzi" icon="terminal" href="/l/ro/developers/extend/apps/layout/command-menu-items">
|
||||
`defineCommandMenuItem` — înregistrează componente front ca intrări Cmd+K și acțiuni rapide.
|
||||
`defineCommandMenuItem` — înregistrează componente front-end ca intrări Cmd+K și acțiuni rapide.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -49,7 +49,7 @@ icon: table-columns
|
||||
| -------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | ----------------------------------------- |
|
||||
| **Bară laterală** | O intrare personalizată care face legătura către o vizualizare salvată sau un URL extern | `defineNavigationMenuItem` |
|
||||
| **Listă de înregistrări** | O configurație salvată pentru un obiect — coloane vizibile, ordine, filtre, grupuri | `defineView` |
|
||||
| **Pagină de detalii a înregistrării** | Filele și widgeturile de pe o pagină de înregistrare (ale propriului tău obiect sau ale unuia standard) | `definePageLayout`, `definePageLayoutTab` |
|
||||
| **Pagină de detalii a unei înregistrări** | Filele și widgeturile de pe o pagină de înregistrare (ale propriului tău obiect sau ale unuia standard) | `definePageLayout`, `definePageLayoutTab` |
|
||||
| **În interiorul oricăreia dintre cele de mai sus** | Un widget React personalizat — butoane, formulare, dashboarduri, integrări | `defineFrontComponent` |
|
||||
| **Meniul de comenzi (Cmd+K)** | O acțiune rapidă fixată sau o comandă ascunsă | `defineCommandMenuItem` |
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
---
|
||||
title: Vizualizări
|
||||
description: Livrați vizualizări salvate preconfigurate — ordinea coloanelor, filtre, grupări — pentru obiectele din aplicația dvs.
|
||||
description: Livrați vizualizări salvate preconfigurate — ordinea coloanelor, filtre, grupuri — pentru obiectele din aplicația dvs.
|
||||
icon: listă
|
||||
---
|
||||
|
||||
O **vizualizare** este o configurație salvată pentru modul în care sunt afișate înregistrările unui obiect: ce câmpuri apar, ordinea lor, dacă sunt vizibile și ce filtre sau grupări sunt aplicate. Folosiți `defineView()` pentru a livra vizualizări preconfigurate împreună cu aplicația dvs. — de obicei o vizualizare index implicită pentru fiecare obiect personalizat pe care îl creați.
|
||||
O **vizualizare** este o configurație salvată pentru modul în care sunt afișate înregistrările unui obiect: ce câmpuri apar, ordinea lor, dacă sunt vizibile și ce filtre sau grupuri sunt aplicate. Folosiți `defineView()` pentru a livra vizualizări preconfigurate împreună cu aplicația dvs. — de obicei o vizualizare index implicită pentru fiecare obiect personalizat pe care îl creați.
|
||||
|
||||
```ts src/views/example-view.ts
|
||||
import { defineView, ViewKey } from 'twenty-sdk/define';
|
||||
@@ -38,6 +38,6 @@ export default defineView({
|
||||
* Puteți declara, de asemenea, `filters`, `filterGroups`, `groups` și `fieldGroups` pentru configurații avansate.
|
||||
* `position` controlează ordonarea atunci când există mai multe vizualizări pentru același obiect.
|
||||
|
||||
## Cum apar vizualizările în interfața utilizator
|
||||
## Cum apar vizualizările în interfața utilizatorului
|
||||
|
||||
O vizualizare, de una singură, nu este accesibilă din bara laterală. Pentru a o face să apară acolo, asociați-o cu un [element de meniu de navigare](/l/ro/developers/extend/apps/layout/navigation-menu-items) de tip `VIEW` care indică către `universalIdentifier` al vizualizării. Acesta este modelul canonic: fiecare obiect personalizat livrează, de obicei, o vizualizare implicită + o intrare în bara laterală care o deschide.
|
||||
|
||||
@@ -52,7 +52,6 @@ export default defineApplication({
|
||||
universalIdentifier: '...',
|
||||
displayName: 'Linear',
|
||||
description: 'Connect Linear to Twenty.',
|
||||
defaultRoleUniversalIdentifier: '...',
|
||||
// OAuth client credentials live on the app registration (one OAuth app per
|
||||
// Twenty server, configured by the admin) — not per-workspace. Declare them
|
||||
// as serverVariables so the admin can fill them in once for all installs.
|
||||
|
||||
@@ -371,5 +371,5 @@ Puncte cheie:
|
||||
* `TWENTY_API_URL` — URL-ul de bază al API-ului Twenty
|
||||
* `TWENTY_APP_ACCESS_TOKEN` — Cheie cu durată scurtă, limitată la rolul implicit de funcție al aplicației
|
||||
|
||||
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`.
|
||||
Nu trebuie să le transmiteți clienților — aceștia citesc automat din `process.env`. Permisiunile cheii API sunt determinate de rolul declarat cu `defineApplicationRole()` (sau referențiat prin `defaultRoleUniversalIdentifier` în `application-config.ts`).
|
||||
</Note>
|
||||
|
||||
@@ -40,13 +40,13 @@ icon: bolt
|
||||
|
||||
O funcție de logică alege unul sau mai multe declanșatoare — fiecare intrare de mai jos este un câmp separat pe `defineLogicFunction()`:
|
||||
|
||||
| Declanșator | Când rulează | Setare |
|
||||
| -------------------------- | ----------------------------------------------------------------- | ------------------------------- |
|
||||
| **Rută HTTP** | O cerere ajunge la endpointul tău `/s/\<path>` | `httpRouteTriggerSettings` |
|
||||
| **Cron** | Se potrivește o expresie CRON | `cronTriggerSettings` |
|
||||
| **Eveniment baza de date** | O înregistrare din workspace este creată, actualizată sau ștearsă | `databaseEventTriggerSettings` |
|
||||
| **Instrument IA** | O funcționalitate Twenty IA decide să apeleze funcția ta | `toolTriggerSettings` |
|
||||
| **Acțiune Workflow** | Un pas din workflow îți invocă funcția | `workflowActionTriggerSettings` |
|
||||
| Declanșator | Când rulează | Setare |
|
||||
| ----------------------------- | ----------------------------------------------------------------- | ------------------------------- |
|
||||
| **Rută HTTP** | O cerere ajunge la endpointul tău `/s/\<path>` | `httpRouteTriggerSettings` |
|
||||
| **Cron** | O expresie CRON se potrivește | `cronTriggerSettings` |
|
||||
| **Eveniment de bază de date** | O înregistrare din workspace este creată, actualizată sau ștearsă | `databaseEventTriggerSettings` |
|
||||
| **Instrument IA** | O funcționalitate IA din Twenty decide să apeleze funcția ta | `toolTriggerSettings` |
|
||||
| **Acțiune Workflow** | Un pas din workflow îți invocă funcția | `workflowActionTriggerSettings` |
|
||||
|
||||
Funcțiile rulează în sandbox, în procese Node.js izolate și accesează workspace-ul printr-un client API cu tipuri, limitat la rolul declarat în [`defineApplication()`](/l/ro/developers/extend/apps/config/application).
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ icon: robot
|
||||
---
|
||||
|
||||
<Warning>
|
||||
Aptitudinile și agenții sunt în prezent în testare alfa. Caracteristica funcționează, dar este încă în dezvoltare.
|
||||
Abilitățile și agenții sunt în prezent în stadiu alfa. Caracteristica funcționează, dar este încă în dezvoltare.
|
||||
</Warning>
|
||||
|
||||
Aplicațiile pot defini capabilități AI care există în interiorul spațiului de lucru — instrucțiuni reutilizabile pentru abilități și agenți cu prompturi de sistem personalizate.
|
||||
@@ -61,7 +61,7 @@ Puncte cheie:
|
||||
* `name` este un șir identificator unic pentru agent (se recomandă kebab-case).
|
||||
* `label` este numele de afișare din interfața cu utilizatorul (UI).
|
||||
* `prompt` conține promptul de sistem — acesta este textul de instrucțiuni care definește comportamentul agentului.
|
||||
* `description` (opțional) oferă context suplimentar despre scopul agentului.
|
||||
* `description` (opțional) oferă context despre ce face agentul.
|
||||
* `icon` (opțional) setează pictograma afișată în UI.
|
||||
* `modelId` (opțional) suprascrie modelul AI implicit utilizat de agent.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: CLI
|
||||
description: comenzi `yarn twenty` pentru executarea funcțiilor, transmiterea fluxurilor de jurnale, gestionarea instalărilor de aplicații și schimbarea remote-urilor.
|
||||
description: comenzi `yarn twenty` pentru executarea funcțiilor, transmiterea în flux a jurnalelor, gestionarea instalărilor de aplicații și comutarea între remote-uri.
|
||||
icon: terminal
|
||||
---
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ description: Construiește, testează și livrează aplicația ta — comenzi CL
|
||||
icon: rocket
|
||||
---
|
||||
|
||||
**Stratul de operațiuni** este tot ceea ce faci *asupra* aplicației tale, mai degrabă decât *cu* ea: rularea de comenzi CLI, executarea de teste de integrare împotriva unui server Twenty real, configurarea CI și livrarea de versiuni — fie ca un tarball distribuit pe un singur server, fie ca un pachet npm listat în marketplace.
|
||||
**Stratul de operațiuni** este tot ceea ce faci *asupra* aplicației tale, mai degrabă decât *cu* ea: invocarea comenzilor CLI, rularea testelor de integrare pe un server Twenty real, configurarea CI și livrarea versiunilor — fie ca un tarball implementat pe un singur server, fie ca un pachet npm listat în marketplace.
|
||||
|
||||
```text
|
||||
develop ─▶ test ─▶ build ─▶ deploy / publish
|
||||
@@ -18,12 +18,12 @@ icon: rocket
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="CLI" icon="terminal" href="/l/ro/developers/extend/apps/operations/cli">
|
||||
`yarn twenty` reference — exec, logs, uninstall, remotes.
|
||||
Referință pentru `yarn twenty` — exec, logs, uninstall, remotes.
|
||||
</Card>
|
||||
<Card title="Testare" icon="flask" href="/l/ro/developers/extend/apps/operations/testing">
|
||||
Configurare Vitest, teste de integrare, verificare de tipuri, workflow CI.
|
||||
Configurare Vitest, teste de integrare, verificare a tipurilor, flux de lucru CI.
|
||||
</Card>
|
||||
<Card title="Publicare" icon="încarcă" href="/l/ro/developers/extend/apps/operations/publishing">
|
||||
Construire, deploy al unui tarball, publicare pe npm, instalare.
|
||||
<Card title="Publicare" icon="upload" href="/l/ro/developers/extend/apps/operations/publishing">
|
||||
Construire, implementare a unui tarball, publicare pe npm, instalare.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -187,7 +187,6 @@ export default defineApplication({
|
||||
universalIdentifier: '...',
|
||||
displayName: 'My App',
|
||||
description: 'A great app',
|
||||
defaultRoleUniversalIdentifier: DEFAULT_ROLE_UNIVERSAL_IDENTIFIER,
|
||||
logoUrl: 'public/logo.png',
|
||||
screenshots: [
|
||||
'public/screenshot-1.png',
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
---
|
||||
title: Конфигурация приложения
|
||||
description: Объявите идентификацию вашего приложения, роль по умолчанию, переменные и метаданные маркетплейса с помощью defineApplication.
|
||||
description: Определите идентификацию вашего приложения, роль по умолчанию, переменные и метаданные маркетплейса с помощью defineApplication.
|
||||
icon: rocket
|
||||
---
|
||||
|
||||
В каждом приложении должен быть ровно один вызов `defineApplication`. Он объявляет:
|
||||
|
||||
* **Идентификация** — универсальный идентификатор, отображаемое имя, описание.
|
||||
* **Разрешения** — под какой ролью выполняются его логические функции и фронтенд-компоненты.
|
||||
* **Разрешения** — от имени какой роли выполняются его логические функции и фронтенд-компоненты.
|
||||
* **Переменные** *(необязательно)* — пары ключ–значение, доступные вашему коду как переменные окружения.
|
||||
* **Хуки предустановки / постустановки** *(необязательно)* — см. [Логические функции](/l/ru/developers/extend/apps/logic/logic-functions).
|
||||
|
||||
```ts src/application-config.ts
|
||||
import { defineApplication } from 'twenty-sdk/define';
|
||||
import { DEFAULT_ROLE_UNIVERSAL_IDENTIFIER } from 'src/roles/default-role';
|
||||
|
||||
export default defineApplication({
|
||||
universalIdentifier: '39783023-bcac-41e3-b0d2-ff1944d8465d',
|
||||
@@ -27,7 +26,6 @@ export default defineApplication({
|
||||
isSecret: false,
|
||||
},
|
||||
},
|
||||
defaultRoleUniversalIdentifier: DEFAULT_ROLE_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
```
|
||||
|
||||
@@ -35,12 +33,13 @@ export default defineApplication({
|
||||
|
||||
* Поля `universalIdentifier` — это детерминированные идентификаторы, которые принадлежат вам. Сгенерируйте их один раз и сохраняйте неизменными между синхронизациями.
|
||||
* `applicationVariables` становятся переменными окружения для ваших функций и фронтенд-компонентов (например, `DEFAULT_RECIPIENT_NAME` доступна как `process.env.DEFAULT_RECIPIENT_NAME`).
|
||||
* `defaultRoleUniversalIdentifier` должен ссылаться на роль, определённую с помощью [`defineRole()`](/l/ru/developers/extend/apps/config/roles).
|
||||
* Роль по умолчанию автоматически определяется из файла роли, помеченного с помощью [`defineApplicationRole()`](/l/ru/developers/extend/apps/config/roles) — вам не нужно ссылаться на неё из `defineApplication()`.
|
||||
* Предустановочные и постустановочные функции обнаруживаются автоматически во время сборки манифеста — вам не нужно указывать их в `defineApplication()`.
|
||||
* Явная передача `defaultRoleUniversalIdentifier` по-прежнему поддерживается для обратной совместимости, но считается устаревшей и вместо неё рекомендуется использовать `defineApplicationRole()`.
|
||||
|
||||
## Роль функции по умолчанию
|
||||
|
||||
`defaultRoleUniversalIdentifier` определяет, к чему могут получать доступ логические функции и фронтенд-компоненты приложения:
|
||||
Роль, объявленная с помощью [`defineApplicationRole()`](/l/ru/developers/extend/apps/config/roles), определяет, к чему могут получать доступ логические функции и фронтенд‑компоненты приложения:
|
||||
|
||||
* Токен времени выполнения, подставляемый как `TWENTY_APP_ACCESS_TOKEN`, формируется из этой роли.
|
||||
* Типизированный клиент API ограничен правами, предоставленными этой роли.
|
||||
|
||||
@@ -6,7 +6,7 @@ icon: wrench
|
||||
|
||||
Установочные хуки — это специальные логические функции, которые выполняются во время установки или обновления. Они используют то же окружение выполнения обработчика, что и обычные [logic functions](/l/ru/developers/extend/apps/logic/logic-functions) и получают `InstallPayload`, но объявляются с помощью собственных функций определения — `definePostInstallLogicFunction()` и `definePreInstallLogicFunction()` — и существуют вне обычной модели триггеров (HTTP, cron, события базы данных).
|
||||
|
||||
Каждое приложение может определить **не более одной pre-install** и **не более одной post-install** функции. Сборка манифеста завершится ошибкой, если будет обнаружено более одной функции любого из этих типов.
|
||||
Каждое приложение может определить **не более одной функции pre-install** и **не более одной функции post-install**. Сборка манифеста завершится ошибкой, если будет обнаружено более одной функции любого из этих типов.
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
|
||||
@@ -35,17 +35,17 @@ icon: screwdriver-wrench
|
||||
<Card title="Роли и разрешения" icon="shield-halved" href="/l/ru/developers/extend/apps/config/roles">
|
||||
`defineRole` — определите, что логические функции вашего приложения могут читать и записывать.
|
||||
</Card>
|
||||
<Card title="Хуки установки" icon="wrench" href="/l/ru/developers/extend/apps/config/install-hooks">
|
||||
<Card title="Установочные хуки" icon="wrench" href="/l/ru/developers/extend/apps/config/install-hooks">
|
||||
`definePreInstallLogicFunction` и `definePostInstallLogicFunction` — создавайте резервные копии данных, заполняйте значения по умолчанию, проверяйте обновления.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Связь между частями
|
||||
|
||||
* **Приложение** — это точка входа. У каждого приложения есть ровно один вызов `defineApplication()`, и он указывает на одну **роль** как роль по умолчанию.
|
||||
* **Приложение** — это точка входа. У каждого приложения есть ровно один вызов `defineApplication()`, и он указывает на одну **роль** по умолчанию.
|
||||
* **Роль** управляет тем, что логические функции и фронтенд‑компоненты приложения могут читать и записывать. Следуйте принципу наименьших привилегий: выдавайте только те разрешения, которые вашему коду действительно нужны.
|
||||
* **Хуки установки** запускаются при установке или обновлении — предустановочный до миграции метаданных (чтобы можно было отклонить рискованное обновление), постустановочный после миграции (чтобы можно было заполнить данные по умолчанию в соответствии с новой схемой).
|
||||
* **Установочные хуки** запускаются при установке или обновлении — предустановочный до миграции метаданных (чтобы можно было отклонить рискованное обновление), постустановочный после миграции (чтобы можно было заполнить данные по умолчанию в соответствии с новой схемой).
|
||||
|
||||
<Note>
|
||||
Хуки установки используют то же окружение выполнения, что и [логическая функция](/l/ru/developers/extend/apps/logic/logic-functions) — тот же формат обработчика, те же переменные окружения, тот же типизированный клиент API, — но объявляются через собственные функции `define` и находятся вне обычной модели триггеров (HTTP, cron, события базы данных).
|
||||
Установочные хуки используют то же окружение выполнения, что и [логическая функция](/l/ru/developers/extend/apps/logic/logic-functions) — тот же формат обработчика, те же переменные окружения, тот же типизированный клиент API, — но объявляются через собственные функции `define` и находятся вне обычной модели триггеров (HTTP, cron, события базы данных).
|
||||
</Note>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Публичные ресурсы
|
||||
description: Отправляйте статические файлы — изображения, иконки, шрифты — вместе с вашим приложением через папку public/.
|
||||
description: Поставляйте статические файлы — изображения, значки, шрифты — вместе с приложением через папку `public/`.
|
||||
icon: folder-open
|
||||
---
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
---
|
||||
title: Роли и разрешения
|
||||
description: Укажите, к каким объектам и полям логические функции и фронтенд‑компоненты вашего приложения могут выполнять чтение и запись.
|
||||
description: Укажите, к каким объектам и полям функции логики и фронтенд‑компоненты вашего приложения имеют доступ на чтение и запись.
|
||||
icon: shield-halved
|
||||
---
|
||||
|
||||
**Роль** — это набор разрешений: какие объекты приложение может читать или изменять, какие поля оно может видеть и какие возможности платформенного уровня оно может использовать. Все логические функции и фронтенд‑компоненты каждого приложения наследуют разрешения роли, объявленной как `defaultRoleUniversalIdentifier` в [`defineApplication`](/l/ru/developers/extend/apps/config/application).
|
||||
**Роль** — это набор разрешений: какие объекты приложение может читать или изменять, какие поля оно может видеть и какие возможности платформенного уровня оно может использовать. Функции логики и фронтенд‑компоненты каждого приложения наследуют разрешения роли, помеченной с помощью `defineApplicationRole()` (см. раздел [Роль функции по умолчанию](#the-default-function-role) ниже).
|
||||
|
||||
```ts src/roles/restricted-company-role.ts
|
||||
import {
|
||||
@@ -51,15 +51,15 @@ export default defineRole({
|
||||
|
||||
## Роль функции по умолчанию
|
||||
|
||||
Когда вы генерируете новое приложение, CLI создаёт файл роли по умолчанию:
|
||||
Когда вы создаёте новое приложение с помощью шаблона, CLI создаёт файл роли по умолчанию, объявленный с помощью `defineApplicationRole()`:
|
||||
|
||||
```ts src/roles/default-role.ts
|
||||
import { defineRole, PermissionFlag } from 'twenty-sdk/define';
|
||||
import { defineApplicationRole, PermissionFlag } from 'twenty-sdk/define';
|
||||
|
||||
export const DEFAULT_ROLE_UNIVERSAL_IDENTIFIER =
|
||||
'b648f87b-1d26-4961-b974-0908fd991061';
|
||||
|
||||
export default defineRole({
|
||||
export default defineApplicationRole({
|
||||
universalIdentifier: DEFAULT_ROLE_UNIVERSAL_IDENTIFIER,
|
||||
label: 'Default function role',
|
||||
description: 'Default role for function Twenty client',
|
||||
@@ -77,10 +77,13 @@ export default defineRole({
|
||||
});
|
||||
```
|
||||
|
||||
Значение `universalIdentifier` этой роли указывается в `application-config.ts` как `defaultRoleUniversalIdentifier`:
|
||||
`defineApplicationRole()` — это тонкая обёртка вокруг `defineRole()`, которая помечает **ту** роль, которая используется как роль приложения по умолчанию во время установки. Проверка идентична `defineRole`, но конвейер сборки автоматически подключает его `universalIdentifier` к полю `defaultRoleUniversalIdentifier` манифеста приложения — поэтому вам не нужно ссылаться на него из [`defineApplication`](/l/ru/developers/extend/apps/config/application) самостоятельно.
|
||||
|
||||
* **`*.role.ts`** определяет, что может делать роль.
|
||||
* **`application-config.ts`** указывает на эту роль, чтобы ваши функции наследовали её права.
|
||||
Заметки:
|
||||
|
||||
* Допускается ровно **один** вызов `defineApplicationRole(...)` на приложение — сборка манифеста завершится с ошибкой, если будет найдено более одного.
|
||||
* Используйте `defineRole()` (а не `defineApplicationRole()`) для любых **дополнительных** ролей, которые ставятся вместе с вашим приложением.
|
||||
* Явная установка `defaultRoleUniversalIdentifier` в `defineApplication()` всё ещё поддерживается для обратной совместимости, но считается устаревшей по сравнению с `defineApplicationRole()`.
|
||||
|
||||
## Лучшие практики
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ description: Объявляйте новые типы записей — пол
|
||||
icon: таблица
|
||||
---
|
||||
|
||||
Пользовательские **объекты** — это новые типы записей, которые ваше приложение добавляет в рабочее пространство — открытка, счёт-фактура, подписка, что‑то специфичное для вашей предметной области. Каждый объект объявляет свою схему (поля, связи, значения по умолчанию) и стабильный универсальный идентификатор, который сохраняется между синхронизациями и деплоями.
|
||||
Пользовательские **объекты** — это новые типы записей, которые ваше приложение добавляет в рабочее пространство — открытка, счёт-фактура, подписка, что‑то специфичное для вашей предметной области. Каждый объект объявляет свою схему (поля, связи, значения по умолчанию) и стабильный универсальный идентификатор, который сохраняется между синхронизациями и развёртываниями.
|
||||
|
||||
```ts src/objects/post-card.object.ts
|
||||
import { defineObject, FieldType } from 'twenty-sdk/define';
|
||||
@@ -89,5 +89,5 @@ export default defineObject({
|
||||
## Что дальше
|
||||
|
||||
* **Свяжите этот объект с другими** — см. [Relations](/l/ru/developers/extend/apps/data/relations) для двунаправленного шаблона связей.
|
||||
* **Добавляйте поля к объектам из других приложений** — см. [Extending Objects](/l/ru/developers/extend/apps/data/extending-objects) по `defineField()`.
|
||||
* **Добавляйте поля к объектам из других приложений** — см. [Extending Objects](/l/ru/developers/extend/apps/data/extending-objects) о `defineField()`.
|
||||
* **Отобразите этот объект в интерфейсе** — см. [Views](/l/ru/developers/extend/apps/layout/views) и [Navigation Menu Items](/l/ru/developers/extend/apps/layout/navigation-menu-items), чтобы поместить его в боковую панель.
|
||||
|
||||
@@ -37,13 +37,13 @@ icon: database
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Сущности одним взглядом
|
||||
## Сущности вкратце
|
||||
|
||||
| Сущность | Назначение | Определяется с помощью |
|
||||
| ---------- | ------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- |
|
||||
| **Объект** | Новый пользовательский тип записей (например, PostCard, Invoice) с собственными полями | `defineObject()` |
|
||||
| **Поле** | Столбец в объекте. Отдельные поля могут расширять объекты, которые вы не создавали (например, добавить `loyaltyTier` к Company) | `defineField()` |
|
||||
| **Связь** | Двусторонняя связь между двумя объектами — обе стороны объявлены как поля | `defineField()` с `FieldType.RELATION` |
|
||||
| Сущность | Назначение | Определяется с помощью |
|
||||
| ---------- | --------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- |
|
||||
| **Объект** | Новый пользовательский тип записей (например, PostCard, Invoice) с собственными полями | `defineObject()` |
|
||||
| **Поле** | Столбец в объекте. Отдельные поля могут расширять объекты, которые вы не создавали (например, добавьте `loyaltyTier` к объекту Company) | `defineField()` |
|
||||
| **Связь** | Двусторонняя связь между двумя объектами — обе стороны объявлены как поля | `defineField()` с `FieldType.RELATION` |
|
||||
|
||||
SDK обнаруживает их с помощью анализа AST во время сборки, поэтому организация файлов остается на ваше усмотрение — по соглашению используются `src/objects/` и `src/fields/`. Стабильные UUID `universalIdentifier` связывают все воедино между развертываниями.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Концепции
|
||||
description: Как работают приложения Twenty — модель сущностей, песочницы и жизненный цикл установки.
|
||||
title: Понятия
|
||||
description: Как работают приложения Twenty — модель сущностей, изоляция в песочнице и жизненный цикл установки.
|
||||
icon: sitemap
|
||||
---
|
||||
|
||||
@@ -37,14 +37,14 @@ your-app/
|
||||
| Сущность | Назначение | Документация |
|
||||
| ------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------- |
|
||||
| **Приложение** | Идентификация приложения, роль по умолчанию, переменные | [Конфигурация приложения](/l/ru/developers/extend/apps/config/application) |
|
||||
| **Роль** | Наборы прав для объектов и полей | [Роли и права доступа](/l/ru/developers/extend/apps/config/roles) |
|
||||
| **Роль** | Наборы прав для объектов и полей | [Роли и разрешения](/l/ru/developers/extend/apps/config/roles) |
|
||||
| **Объект** | Пользовательские типы записей с полями | [Объекты](/l/ru/developers/extend/apps/data/objects) |
|
||||
| **Поле** | Добавляйте поля к объектам из других приложений | [Расширение объектов](/l/ru/developers/extend/apps/data/extending-objects) |
|
||||
| **Связь** | Двунаправленные связи между объектами | [Связи](/l/ru/developers/extend/apps/data/relations) |
|
||||
| **Логическая функция** | Серверный TypeScript с триггерами | [Логические функции](/l/ru/developers/extend/apps/logic/logic-functions) |
|
||||
| **Навык** | Повторно используемые инструкции для ИИ-агента | [Навыки и агенты](/l/ru/developers/extend/apps/logic/skills-and-agents) |
|
||||
| **Агент** | ИИ-агенты с пользовательскими промптами | [Навыки и агенты](/l/ru/developers/extend/apps/logic/skills-and-agents) |
|
||||
| **Провайдер подключения** | OAuth-учетные данные для сторонних API | [Подключения](/l/ru/developers/extend/apps/logic/connections) |
|
||||
| **Провайдер подключения** | Учётные данные OAuth для сторонних API | [Подключения](/l/ru/developers/extend/apps/logic/connections) |
|
||||
| **Представление** | Преднастроенные представления списков записей | [Представления](/l/ru/developers/extend/apps/layout/views) |
|
||||
| **Пункт меню навигации** | Пользовательские элементы боковой панели | [Элементы меню навигации](/l/ru/developers/extend/apps/layout/navigation-menu-items) |
|
||||
| **Макет страницы** | Вкладки и виджеты на странице сведений о записи | [Макеты страниц](/l/ru/developers/extend/apps/layout/page-layouts) |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Локальный сервер
|
||||
description: Управление локальным сервером Twenty Docker — запуск, остановка, обновление, параллельный тестовый экземпляр и ручная настройка SDK.
|
||||
description: Управление локальным Docker-сервером Twenty — запуск, остановка, обновление, параллельный тестовый экземпляр и ручная настройка SDK.
|
||||
icon: server
|
||||
---
|
||||
|
||||
@@ -23,7 +23,7 @@ icon: server
|
||||
|
||||
## Обновление образа сервера
|
||||
|
||||
`yarn twenty server upgrade` скачивает последний образ, сравнивает дайджесты и пересоздаёт контейнер только если действительно что-то изменилось. Ваши тома данных сохраняются — заменяется только контейнер. Если был скачан новый образ и контейнер работал, при обновлении автоматически запускается новый контейнер; затем выполните `yarn twenty server start`, чтобы дождаться его готовности.
|
||||
`yarn twenty server upgrade` скачивает последний образ, сравнивает дайджесты и пересоздаёт контейнер только если действительно что-то изменилось. Тома сохраняются — заменяется только контейнер. Если был скачан новый образ и контейнер работал, при обновлении автоматически запускается новый контейнер; затем выполните `yarn twenty server start`, чтобы дождаться его готовности.
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server upgrade # Latest
|
||||
@@ -47,7 +47,7 @@ yarn twenty server upgrade 2.2.0 # Specific version
|
||||
|
||||
Тестовый экземпляр запускается в собственном контейнере Docker (`twenty-app-dev-test`) с выделенными томами (`twenty-app-dev-test-data`, `twenty-app-dev-test-storage`) и собственной конфигурацией, поэтому он может работать параллельно с вашим основным экземпляром без конфликтов. Совместите `--test` с `--port`, чтобы переопределить значение по умолчанию (2021).
|
||||
|
||||
## Ручная настройка (без генератора)
|
||||
## Ручная настройка (без генератора каркаса)
|
||||
|
||||
Пропустите генератор каркаса, если вы добавляете SDK в существующий проект:
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ yarn twenty dev --once
|
||||
npx create-twenty-app@latest my-twenty-app --example postcard
|
||||
```
|
||||
|
||||
Примеры берутся из каталога [twenty-apps/examples](https://github.com/twentyhq/twenty/tree/main/packages/twenty-apps/examples) на GitHub. Вы также можете сгенерировать каркас отдельных сущностей в существующем проекте с помощью `yarn twenty add` — см. [Scaffolding](/l/ru/developers/extend/apps/getting-started/scaffolding).
|
||||
Примеры берутся из каталога [twenty-apps/examples](https://github.com/twentyhq/twenty/tree/main/packages/twenty-apps/examples) на GitHub. Вы также можете сгенерировать каркас отдельных сущностей в существующем проекте с помощью `yarn twenty add` — см. [Создание каркаса](/l/ru/developers/extend/apps/getting-started/scaffolding).
|
||||
|
||||
---
|
||||
|
||||
@@ -161,24 +161,24 @@ npx create-twenty-app@latest my-twenty-app --example postcard
|
||||
| **Представления и навигация** | Предварительно настроенные представления списков и элементы бокового меню |
|
||||
| **Макеты страниц** | Пользовательские страницы сведений о записи с вкладками и виджетами |
|
||||
|
||||
Полная справка: [Concepts](/l/ru/developers/extend/apps/getting-started/concepts).
|
||||
Полная справка: [Концепции](/l/ru/developers/extend/apps/getting-started/concepts).
|
||||
|
||||
## Следующие шаги
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Конфигурация" icon="screwdriver-wrench" href="/l/ru/developers/extend/apps/config/overview">
|
||||
Идентификация приложения, роль по умолчанию, хуки установки, публичные ассеты.
|
||||
Идентификация приложения, роль по умолчанию, хуки установки, публичные ресурсы.
|
||||
</Card>
|
||||
<Card title="Данные" icon="database" href="/l/ru/developers/extend/apps/data/overview">
|
||||
Объекты, поля и двунаправленные связи.
|
||||
</Card>
|
||||
<Card title="Логика" icon="bolt" href="/l/ru/developers/extend/apps/logic/overview">
|
||||
Логические функции, скиллы, агенты и OAuth-подключения.
|
||||
Логические функции, навыки, агенты и OAuth-подключения.
|
||||
</Card>
|
||||
<Card title="Макет" icon="table-columns" href="/l/ru/developers/extend/apps/layout/overview">
|
||||
Представления, навигация, макеты страниц, фронтовые компоненты.
|
||||
Представления, навигация, макеты страниц, фронтенд-компоненты.
|
||||
</Card>
|
||||
<Card title="Операции" icon="rocket" href="/l/ru/developers/extend/apps/operations/overview">
|
||||
CLI, тестирование, ремоуты, CI и публикация вашего приложения.
|
||||
CLI, тестирование, удалённые серверы, CI и публикация вашего приложения.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
---
|
||||
title: Элементы меню команд
|
||||
description: Выводите front-компоненты как быстрые действия и элементы командного меню (Cmd+K) с помощью `defineCommandMenuItem`.
|
||||
description: Отображайте фронтенд-компоненты как быстрые действия и элементы командного меню (Cmd+K) с помощью `defineCommandMenuItem`.
|
||||
icon: terminal
|
||||
---
|
||||
|
||||
**Элемент командного меню** — это мост между пользователем и [front-компонентом](/l/ru/developers/extend/apps/layout/front-components). Он регистрирует компонент в командном меню Twenty (Cmd+K) и, при необходимости, как закреплённую кнопку быстрого действия в правом верхнем углу страницы.
|
||||
**Элемент командного меню** — это мост между пользователем и [фронтенд-компонентом](/l/ru/developers/extend/apps/layout/front-components). Он регистрирует компонент в командном меню Twenty (Cmd+K) и, при необходимости, как закреплённую кнопку быстрого действия в правом верхнем углу страницы.
|
||||
|
||||
```ts src/command-menu-items/open-dashboard.command-menu-item.ts
|
||||
import { defineCommandMenuItem } from 'twenty-sdk/define';
|
||||
@@ -36,9 +36,9 @@ export default defineCommandMenuItem({
|
||||
|
||||
## Команды без интерфейса
|
||||
|
||||
Элемент командного меню в паре с [front-компонентом без интерфейса](/l/ru/developers/extend/apps/layout/front-components#headless-vs-non-headless) — идиоматичный способ предоставить действие в один клик: выполнить код, перейти по навигации или подтвердить и выполнить действие. Страница Front Components описывает [SDK Command components](/l/ru/developers/extend/apps/layout/front-components#sdk-command-components) (`Command`, `CommandLink`, `CommandModal`, `CommandOpenSidePanelPage`), которые реализуют шаблон «действие и размонтирование».
|
||||
Элемент командного меню в паре с [фронтенд-компонентом без интерфейса](/l/ru/developers/extend/apps/layout/front-components#headless-vs-non-headless) — идиоматичный способ предоставить действие в один клик: выполнить код, перейти или подтвердить и выполнить. Страница Front Components описывает [SDK Command components](/l/ru/developers/extend/apps/layout/front-components#sdk-command-components) (`Command`, `CommandLink`, `CommandModal`, `CommandOpenSidePanelPage`), которые реализуют шаблон «действие и размонтирование».
|
||||
|
||||
Типичный поток:
|
||||
Типичный сценарий:
|
||||
|
||||
```tsx src/front-components/run-action.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk/define';
|
||||
|
||||
@@ -26,10 +26,10 @@ icon: table-columns
|
||||
## В этом разделе
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Представления" icon="список" href="/l/ru/developers/extend/apps/layout/views">
|
||||
<Card title="Представления" icon="list" href="/l/ru/developers/extend/apps/layout/views">
|
||||
`defineView` — сохранённые конфигурации списков: видимые столбцы, фильтры, группы.
|
||||
</Card>
|
||||
<Card title="Элементы меню навигации" icon="меню" href="/l/ru/developers/extend/apps/layout/navigation-menu-items">
|
||||
<Card title="Элементы меню навигации" icon="bars" href="/l/ru/developers/extend/apps/layout/navigation-menu-items">
|
||||
`defineNavigationMenuItem` — элементы боковой панели, ссылающиеся на представления или внешние URL.
|
||||
</Card>
|
||||
<Card title="Макеты страниц" icon="table-columns" href="/l/ru/developers/extend/apps/layout/page-layouts">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Макеты страниц
|
||||
description: Настраивайте страницы деталей записей — вкладки, виджеты и места, где отображаются front components, — с помощью `definePageLayout` и `definePageLayoutTab`.
|
||||
description: Настраивайте страницы деталей записей — вкладки, виджеты и места, где отображаются фронтенд-компоненты, — с помощью `definePageLayout` и `definePageLayoutTab`.
|
||||
icon: table-columns
|
||||
---
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
---
|
||||
title: Представления
|
||||
description: Поставляйте предварительно настроенные сохранённые представления — порядок столбцов, фильтры, группы — для объектов в вашем приложении.
|
||||
icon: список
|
||||
icon: list
|
||||
---
|
||||
|
||||
**Представление** — это сохранённая конфигурация того, как отображаются записи объекта: какие поля появляются, их порядок, видимость, а также применённые фильтры и группы. Используйте `defineView()` для поставки предварительно настроенных представлений вместе с вашим приложением — обычно это представление индекса по умолчанию для каждого создаваемого вами пользовательского объекта.
|
||||
**Представление** — это сохранённая конфигурация того, как отображаются записи объекта: какие поля появляются, их порядок, видимость, а также применённые фильтры и группы. Используйте `defineView()` для поставки предварительно настроенных представлений вместе с вашим приложением — обычно это представление списка по умолчанию для каждого создаваемого вами пользовательского объекта.
|
||||
|
||||
```ts src/views/example-view.ts
|
||||
import { defineView, ViewKey } from 'twenty-sdk/define';
|
||||
@@ -35,7 +35,7 @@ export default defineView({
|
||||
* `objectUniversalIdentifier` указывает, к какому объекту применяется это представление. Это может быть пользовательский объект, который вы определили, или стандартный объект Twenty.
|
||||
* `key` определяет тип представления — `ViewKey.INDEX` — это основное представление списка для объекта.
|
||||
* `fields` управляет тем, какие столбцы отображаются и в каком порядке. Каждое поле ссылается на `fieldMetadataUniversalIdentifier`.
|
||||
* Также вы можете объявить `filters`, `filterGroups`, `groups` и `fieldGroups` для продвинутых конфигураций.
|
||||
* Также вы можете определить `filters`, `filterGroups`, `groups` и `fieldGroups` для более продвинутых конфигураций.
|
||||
* `position` управляет порядком, когда для одного и того же объекта существует несколько представлений.
|
||||
|
||||
## Как представления отображаются в интерфейсе
|
||||
|
||||
@@ -52,7 +52,6 @@ export default defineApplication({
|
||||
universalIdentifier: '...',
|
||||
displayName: 'Linear',
|
||||
description: 'Connect Linear to Twenty.',
|
||||
defaultRoleUniversalIdentifier: '...',
|
||||
// OAuth client credentials live on the app registration (one OAuth app per
|
||||
// Twenty server, configured by the admin) — not per-workspace. Declare them
|
||||
// as serverVariables so the admin can fill them in once for all installs.
|
||||
|
||||
@@ -370,5 +370,5 @@ console.log(uploadedFile);
|
||||
* `TWENTY_API_URL` — базовый URL API Twenty
|
||||
* `TWENTY_APP_ACCESS_TOKEN` — краткоживущий ключ, ограниченный ролью функции по умолчанию вашего приложения
|
||||
|
||||
Вам не нужно передавать их клиентам — они автоматически читаются из `process.env`. Права ключа API определяются ролью, указанной в `defaultRoleUniversalIdentifier` в вашем `application-config.ts`.
|
||||
Вам не нужно передавать их клиентам — они автоматически читаются из `process.env`. Права ключа API определяются ролью, объявленной с помощью `defineApplicationRole()` (или указанной через `defaultRoleUniversalIdentifier` в `application-config.ts`).
|
||||
</Note>
|
||||
|
||||
@@ -4,7 +4,7 @@ description: Серверный TypeScript, который выполняетс
|
||||
icon: bolt
|
||||
---
|
||||
|
||||
**Логический слой** приложения Twenty — это код, который *выполняется*: серверные обработчики TypeScript, реагирующие на HTTP-запросы, расписания cron и изменения записей; AI-навыки и агенты, работающие внутри рабочего пространства; а также OAuth-подключения, позволяющие вашим функциям действовать от имени пользователя в сторонних сервисах.
|
||||
**Логический слой** приложения Twenty — это код, который *выполняется*: серверные обработчики TypeScript, реагирующие на HTTP-запросы, расписания cron и изменения записей; навыки ИИ и агенты, работающие внутри рабочего пространства; а также OAuth-подключения, позволяющие вашим функциям действовать от имени пользователя в сторонних сервисах.
|
||||
|
||||
```text
|
||||
┌─ HTTP route ──┐
|
||||
@@ -29,24 +29,24 @@ icon: bolt
|
||||
Основной строительный блок — типы триггеров, полезные данные (payloads) и типизированный клиент API.
|
||||
</Card>
|
||||
<Card title="Навыки и агенты" icon="robot" href="/l/ru/developers/extend/apps/logic/skills-and-agents">
|
||||
Повторно используемые инструкции AI-агента и ассистенты с пользовательскими системными подсказками.
|
||||
Повторно используемые инструкции агента ИИ и ассистенты с пользовательскими системными подсказками.
|
||||
</Card>
|
||||
<Card title="Подключения" icon="plug" href="/l/ru/developers/extend/apps/logic/connections">
|
||||
OAuth-учетные данные, которые ваше приложение хранит для сторонних сервисов — Linear, GitHub, Slack и других.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Типы триггеров одним взглядом
|
||||
## Типы триггеров вкратце
|
||||
|
||||
Логическая функция выбирает один или несколько триггеров — каждая запись ниже — это отдельное поле в `defineLogicFunction()`:
|
||||
|
||||
| Триггер | Когда запускается | Настройка |
|
||||
| ------------------------------ | ------------------------------------------------------------------- | ------------------------------- |
|
||||
| **HTTP-маршрут** | Запрос попадает на ваш конечный пункт `/s/\<path>` | `httpRouteTriggerSettings` |
|
||||
| **Cron** | Срабатывает выражение CRON | `cronTriggerSettings` |
|
||||
| **Событие базы данных** | Запись рабочего пространства создается, обновляется или удаляется | `databaseEventTriggerSettings` |
|
||||
| **Инструмент ИИ** | Функция Twenty AI решает вызвать вашу функцию | `toolTriggerSettings` |
|
||||
| **Действие рабочего процесса** | Шаг рабочего процесса вызывает вашу функцию | `workflowActionTriggerSettings` |
|
||||
| Триггер | Когда запускается | Настройка |
|
||||
| ------------------------------ | -------------------------------------------------------------------- | ------------------------------- |
|
||||
| **HTTP-маршрут** | Запрос попадает на вашу конечную точку `/s/\<path>` | `httpRouteTriggerSettings` |
|
||||
| **Cron** | Срабатывает выражение CRON | `cronTriggerSettings` |
|
||||
| **Событие базы данных** | Запись рабочего пространства создается, обновляется или удаляется | `databaseEventTriggerSettings` |
|
||||
| **Инструмент ИИ** | Возможность Twenty AI решает вызвать вашу функцию | `toolTriggerSettings` |
|
||||
| **Действие рабочего процесса** | Шаг рабочего процесса вызывает вашу функцию | `workflowActionTriggerSettings` |
|
||||
|
||||
Функции выполняются в изолированных процессах Node.js в песочнице и получают доступ к рабочему пространству через типизированный клиент API с областью действия, ограниченной ролью, объявленной в [`defineApplication()`](/l/ru/developers/extend/apps/config/application).
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: CLI
|
||||
description: Команды `yarn twenty` для выполнения функций, потоковой передачи логов, управления установками приложений и переключения удалённых репозиториев.
|
||||
description: Команды `yarn twenty` для выполнения функций, потоковой передачи логов, управления установками приложений и переключения удалённых серверов.
|
||||
icon: terminal
|
||||
---
|
||||
|
||||
@@ -56,7 +56,7 @@ yarn twenty uninstall --yes
|
||||
|
||||
## Управление удалёнными серверами
|
||||
|
||||
**Remote** — это сервер Twenty, к которому подключается ваше приложение. Во время настройки скэффолдер автоматически создаст его для вас. Вы можете в любой момент добавлять новые удалённые серверы или переключаться между ними.
|
||||
**Remote** — это сервер Twenty, к которому подключается ваше приложение. Во время настройки скаффолдер автоматически создаст его для вас. Вы можете в любой момент добавлять новые удалённые серверы или переключаться между ними.
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Add a new remote (opens a browser for OAuth login)
|
||||
|
||||
@@ -4,7 +4,7 @@ description: Собирайте, тестируйте и поставляйте
|
||||
icon: rocket
|
||||
---
|
||||
|
||||
**Операционный уровень** — это все, что вы делаете *с* вашим приложением, а не *внутри* него: выполнение команд CLI, запуск интеграционных тестов против реального сервера Twenty, настройка CI и поставка релизов — либо в виде tarball, разворачиваемого на одном сервере, либо как пакет npm, публикуемый в маркетплейсе.
|
||||
**Операционный уровень** — это все, что вы делаете *над* своим приложением, а не *с ним*: выполнение команд CLI, запуск интеграционных тестов на реальном сервере Twenty, настройка CI и поставка релизов — либо в виде tar-архива, разворачиваемого на одном сервере, либо как пакет npm, размещенный в маркетплейсе.
|
||||
|
||||
```text
|
||||
develop ─▶ test ─▶ build ─▶ deploy / publish
|
||||
@@ -18,12 +18,12 @@ icon: rocket
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="CLI" icon="terminal" href="/l/ru/developers/extend/apps/operations/cli">
|
||||
`yarn twenty` reference — exec, logs, uninstall, remotes.
|
||||
Справочник по `yarn twenty` — exec, logs, uninstall, remotes.
|
||||
</Card>
|
||||
<Card title="Тестирование" icon="flask" href="/l/ru/developers/extend/apps/operations/testing">
|
||||
Настройка Vitest, интеграционные тесты, проверка типов, рабочий процесс CI.
|
||||
</Card>
|
||||
<Card title="Публикация" icon="загрузить" href="/l/ru/developers/extend/apps/operations/publishing">
|
||||
<Card title="Публикация" icon="upload" href="/l/ru/developers/extend/apps/operations/publishing">
|
||||
Сборка, развертывание tarball, публикация в npm, установка.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user