Compare commits
35
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a630874c35 | ||
|
|
9dc8333908 | ||
|
|
8909badc59 | ||
|
|
c81019965d | ||
|
|
58dd5d3561 | ||
|
|
c611a7ac20 | ||
|
|
50a4fe5040 | ||
|
|
34b927ff23 | ||
|
|
086830f81b | ||
|
|
a962cdc34f | ||
|
|
a15bf1e608 | ||
|
|
524e5d8cf7 | ||
|
|
2e5ccd9b86 | ||
|
|
459c64f642 | ||
|
|
3420d63b7a | ||
|
|
4da8878697 | ||
|
|
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"
|
||||
|
||||
@@ -6,14 +6,14 @@
|
||||
|
||||
<h2 align="center" >The #1 Open-Source CRM</h2>
|
||||
|
||||
<p align="center"><a href="https://twenty.com"><img src="./packages/twenty-website-new/public/images/readme/globe-icon.svg" width="12" height="12"/> Website</a> · <a href="https://docs.twenty.com"><img src="./packages/twenty-website-new/public/images/readme/book-icon.svg" width="12" height="12"/> Documentation</a> · <a href="https://github.com/orgs/twentyhq/projects/1"><img src="./packages/twenty-website-new/public/images/readme/map-icon.svg" width="12" height="12"/> Roadmap </a> · <a href="https://discord.gg/cx5n4Jzs57"><img src="./packages/twenty-website-new/public/images/readme/discord-icon.svg" width="12" height="12"/> Discord</a> · <a href="https://www.figma.com/file/xt8O9mFeLl46C5InWwoMrN/Twenty"><img src="./packages/twenty-website-new/public/images/readme/figma-icon.png" width="12" height="12"/> Figma</a></p>
|
||||
<p align="center"><a href="https://twenty.com"><img src="./packages/twenty-website-new/public/images/readme/globe-icon.svg" width="12" height="12"/> Website</a> · <a href="https://docs.twenty.com"><img src="./packages/twenty-website-new/public/images/readme/book-icon.svg" width="12" height="12"/> Documentation</a> · <a href="https://github.com/orgs/twentyhq/projects/1"><img src="./packages/twenty-website-new/public/images/readme/map-icon.svg" width="12" height="12"/> Roadmap </a> · <a href="https://discord.gg/cx5n4Jzs57"><img src="./packages/twenty-website-new/public/images/readme/discord-icon.svg" width="12" height="12"/> Discord</a> · <a href="https://www.figma.com/file/xt8O9mFeLl46C5InWwoMrN/Twenty"><img src="./packages/twenty-website-new/public/images/readme/figma-icon.webp" width="12" height="12"/> Figma</a></p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://www.twenty.com">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="./packages/twenty-website-new/public/images/readme/github-cover-dark.png" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="./packages/twenty-website-new/public/images/readme/github-cover-light.png" />
|
||||
<img src="./packages/twenty-website-new/public/images/readme/github-cover-light.png" alt="Twenty banner" />
|
||||
<source media="(prefers-color-scheme: dark)" srcset="./packages/twenty-website-new/public/images/readme/github-cover-dark.webp" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="./packages/twenty-website-new/public/images/readme/github-cover-light.webp" />
|
||||
<img src="./packages/twenty-website-new/public/images/readme/github-cover-light.webp" alt="Twenty banner" />
|
||||
</picture>
|
||||
</a>
|
||||
</p>
|
||||
@@ -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 />
|
||||
|
||||
@@ -85,17 +85,17 @@ Want to go deeper? Read the <a href="https://docs.twenty.com/user-guide/introduc
|
||||
<tr>
|
||||
<td width="50%">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="./packages/twenty-website-new/public/images/readme/v2-build-apps-dark.png" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="./packages/twenty-website-new/public/images/readme/v2-build-apps-light.png" />
|
||||
<img src="./packages/twenty-website-new/public/images/readme/v2-build-apps-light.png" alt="Create your apps" />
|
||||
<source media="(prefers-color-scheme: dark)" srcset="./packages/twenty-website-new/public/images/readme/v2-build-apps-dark.webp" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="./packages/twenty-website-new/public/images/readme/v2-build-apps-light.webp" />
|
||||
<img src="./packages/twenty-website-new/public/images/readme/v2-build-apps-light.webp" alt="Create your apps" />
|
||||
</picture>
|
||||
<p align="center"><a href="https://docs.twenty.com/developers/extend/apps/getting-started"><img src="./packages/twenty-website-new/public/images/readme/code-icon.svg" width="16" height="16"/> Learn more about apps in doc</a></p>
|
||||
</td>
|
||||
<td width="50%">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="./packages/twenty-website-new/public/images/readme/v2-version-control-dark.png" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="./packages/twenty-website-new/public/images/readme/v2-version-control-light.png" />
|
||||
<img src="./packages/twenty-website-new/public/images/readme/v2-version-control-light.png" alt="Stay on top with version control" />
|
||||
<source media="(prefers-color-scheme: dark)" srcset="./packages/twenty-website-new/public/images/readme/v2-version-control-dark.webp" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="./packages/twenty-website-new/public/images/readme/v2-version-control-light.webp" />
|
||||
<img src="./packages/twenty-website-new/public/images/readme/v2-version-control-light.webp" alt="Stay on top with version control" />
|
||||
</picture>
|
||||
<p align="center"><a href="https://docs.twenty.com/developers/extend/apps/publishing"><img src="./packages/twenty-website-new/public/images/readme/monitor-icon.svg" width="16" height="16"/> Learn more about version control in doc</a></p>
|
||||
</td>
|
||||
@@ -103,17 +103,17 @@ Want to go deeper? Read the <a href="https://docs.twenty.com/user-guide/introduc
|
||||
<tr>
|
||||
<td width="50%">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="./packages/twenty-website-new/public/images/readme/v2-all-tools-dark.png" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="./packages/twenty-website-new/public/images/readme/v2-all-tools-light.png" />
|
||||
<img src="./packages/twenty-website-new/public/images/readme/v2-all-tools-light.png" alt="All the tools you need to build anything" />
|
||||
<source media="(prefers-color-scheme: dark)" srcset="./packages/twenty-website-new/public/images/readme/v2-all-tools-dark.webp" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="./packages/twenty-website-new/public/images/readme/v2-all-tools-light.webp" />
|
||||
<img src="./packages/twenty-website-new/public/images/readme/v2-all-tools-light.webp" alt="All the tools you need to build anything" />
|
||||
</picture>
|
||||
<p align="center"><a href="https://docs.twenty.com/developers/extend/apps/building"><img src="./packages/twenty-website-new/public/images/readme/rocket-icon.svg" width="16" height="16"/> Learn more about primitives in doc</a></p>
|
||||
</td>
|
||||
<td width="50%">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="./packages/twenty-website-new/public/images/readme/v2-tools-dark.png" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="./packages/twenty-website-new/public/images/readme/v2-tools-light.png" />
|
||||
<img src="./packages/twenty-website-new/public/images/readme/v2-tools-light.png" alt="Customize your layouts" />
|
||||
<source media="(prefers-color-scheme: dark)" srcset="./packages/twenty-website-new/public/images/readme/v2-tools-dark.webp" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="./packages/twenty-website-new/public/images/readme/v2-tools-light.webp" />
|
||||
<img src="./packages/twenty-website-new/public/images/readme/v2-tools-light.webp" alt="Customize your layouts" />
|
||||
</picture>
|
||||
<p align="center"><a href="https://docs.twenty.com/user-guide/layout/overview"><img src="./packages/twenty-website-new/public/images/readme/planner-icon.svg" width="16" height="16"/> Learn more about layouts in doc</a></p>
|
||||
</td>
|
||||
@@ -121,17 +121,17 @@ Want to go deeper? Read the <a href="https://docs.twenty.com/user-guide/introduc
|
||||
<tr>
|
||||
<td width="50%">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="./packages/twenty-website-new/public/images/readme/v2-ai-agents-dark.png" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="./packages/twenty-website-new/public/images/readme/v2-ai-agents-light.png" />
|
||||
<img src="./packages/twenty-website-new/public/images/readme/v2-ai-agents-light.png" alt="AI agents and chats" />
|
||||
<source media="(prefers-color-scheme: dark)" srcset="./packages/twenty-website-new/public/images/readme/v2-ai-agents-dark.webp" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="./packages/twenty-website-new/public/images/readme/v2-ai-agents-light.webp" />
|
||||
<img src="./packages/twenty-website-new/public/images/readme/v2-ai-agents-light.webp" alt="AI agents and chats" />
|
||||
</picture>
|
||||
<p align="center"><a href="https://docs.twenty.com/user-guide/ai/overview"><img src="./packages/twenty-website-new/public/images/readme/message-icon.svg" width="16" height="16"/> Learn more about AI in doc</a></p>
|
||||
</td>
|
||||
<td width="50%">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="./packages/twenty-website-new/public/images/readme/v2-crm-tools-dark.png" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="./packages/twenty-website-new/public/images/readme/v2-crm-tools-light.png" />
|
||||
<img src="./packages/twenty-website-new/public/images/readme/v2-crm-tools-light.png" alt="Plus all the tools of a good CRM" />
|
||||
<source media="(prefers-color-scheme: dark)" srcset="./packages/twenty-website-new/public/images/readme/v2-crm-tools-dark.webp" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="./packages/twenty-website-new/public/images/readme/v2-crm-tools-light.webp" />
|
||||
<img src="./packages/twenty-website-new/public/images/readme/v2-crm-tools-light.webp" alt="Plus all the tools of a good CRM" />
|
||||
</picture>
|
||||
<p align="center"><a href="https://docs.twenty.com/user-guide/introduction"><img src="./packages/twenty-website-new/public/images/readme/star-icon.svg" width="16" height="16"/> Learn more about CRM features in doc</a></p>
|
||||
</td>
|
||||
@@ -152,13 +152,13 @@ Want to go deeper? Read the <a href="https://docs.twenty.com/user-guide/introduc
|
||||
# Thanks
|
||||
|
||||
<p align="center">
|
||||
<a href="https://www.chromatic.com/"><img src="./packages/twenty-website-new/public/images/readme/chromatic.png" height="28" alt="Chromatic" /></a>
|
||||
<a href="https://www.chromatic.com/"><img src="./packages/twenty-website-new/public/images/readme/chromatic.webp" height="28" alt="Chromatic" /></a>
|
||||
|
||||
<a href="https://greptile.com"><img src="./packages/twenty-website-new/public/images/readme/greptile.png" height="28" alt="Greptile" /></a>
|
||||
<a href="https://greptile.com"><img src="./packages/twenty-website-new/public/images/readme/greptile.webp" height="28" alt="Greptile" /></a>
|
||||
|
||||
<a href="https://sentry.io/"><img src="./packages/twenty-website-new/public/images/readme/sentry.png" height="28" alt="Sentry" /></a>
|
||||
<a href="https://sentry.io/"><img src="./packages/twenty-website-new/public/images/readme/sentry.webp" height="28" alt="Sentry" /></a>
|
||||
|
||||
<a href="https://crowdin.com/"><img src="./packages/twenty-website-new/public/images/readme/crowdin.png" height="28" alt="Crowdin" /></a>
|
||||
<a href="https://crowdin.com/"><img src="./packages/twenty-website-new/public/images/readme/crowdin.webp" height="28" alt="Crowdin" /></a>
|
||||
</p>
|
||||
|
||||
Thanks to these amazing services that we use and recommend for UI testing (Chromatic), code review (Greptile), catching bugs (Sentry) and translating (Crowdin).
|
||||
|
||||
@@ -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"]}
|
||||
@@ -1752,6 +1752,7 @@ enum FeatureFlagKey {
|
||||
IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED
|
||||
IS_PUBLIC_DOMAIN_ENABLED
|
||||
IS_EMAILING_DOMAIN_ENABLED
|
||||
IS_EMAIL_GROUP_ENABLED
|
||||
IS_JUNCTION_RELATIONS_ENABLED
|
||||
IS_CONNECTED_ACCOUNT_MIGRATED
|
||||
IS_RICH_TEXT_V1_MIGRATED
|
||||
@@ -1926,6 +1927,7 @@ type ClientConfig {
|
||||
isGoogleCalendarEnabled: Boolean!
|
||||
isConfigVariablesInDbEnabled: Boolean!
|
||||
isImapSmtpCaldavEnabled: Boolean!
|
||||
isEmailGroupEnabled: Boolean!
|
||||
allowRequestsToTwentyIcons: Boolean!
|
||||
calendarBookingPageId: String
|
||||
isCloudflareIntegrationEnabled: Boolean!
|
||||
@@ -2354,6 +2356,7 @@ type PublicDomain {
|
||||
id: UUID!
|
||||
domain: String!
|
||||
isValidated: Boolean!
|
||||
applicationId: UUID
|
||||
createdAt: DateTime!
|
||||
}
|
||||
|
||||
@@ -2777,6 +2780,7 @@ type MessageChannel {
|
||||
connectedAccountId: UUID!
|
||||
createdAt: DateTime!
|
||||
updatedAt: DateTime!
|
||||
connectedAccount: ConnectedAccountPublicDTO
|
||||
}
|
||||
|
||||
enum MessageChannelVisibility {
|
||||
@@ -2788,6 +2792,7 @@ enum MessageChannelVisibility {
|
||||
enum MessageChannelType {
|
||||
EMAIL
|
||||
SMS
|
||||
EMAIL_GROUP
|
||||
}
|
||||
|
||||
enum MessageChannelContactAutoCreationPolicy {
|
||||
@@ -2826,6 +2831,11 @@ enum MessageChannelSyncStage {
|
||||
FAILED
|
||||
}
|
||||
|
||||
type CreateEmailGroupChannelOutput {
|
||||
messageChannel: MessageChannel!
|
||||
forwardingAddress: String!
|
||||
}
|
||||
|
||||
type MessageFolder {
|
||||
id: UUID!
|
||||
name: String
|
||||
@@ -3243,6 +3253,8 @@ type Mutation {
|
||||
updateMessageFolder(input: UpdateMessageFolderInput!): MessageFolder!
|
||||
updateMessageFolders(input: UpdateMessageFoldersInput!): [MessageFolder!]!
|
||||
updateMessageChannel(input: UpdateMessageChannelInput!): MessageChannel!
|
||||
createEmailGroupChannel(input: CreateEmailGroupChannelInput!): CreateEmailGroupChannelOutput!
|
||||
deleteEmailGroupChannel(id: UUID!): MessageChannel!
|
||||
deleteConnectedAccount(id: UUID!): ConnectedAccountDTO!
|
||||
updateCalendarChannel(input: UpdateCalendarChannelInput!): CalendarChannel!
|
||||
createWebhook(input: CreateWebhookInput!): Webhook!
|
||||
@@ -3316,7 +3328,8 @@ type Mutation {
|
||||
updateLabPublicFeatureFlag(input: UpdateLabPublicFeatureFlagInput!): FeatureFlag!
|
||||
enablePostgresProxy: PostgresCredentials!
|
||||
disablePostgresProxy: PostgresCredentials!
|
||||
createPublicDomain(domain: String!): PublicDomain!
|
||||
createPublicDomain(domain: String!, applicationId: String): PublicDomain!
|
||||
updatePublicDomain(domain: String!, applicationId: String): PublicDomain!
|
||||
deletePublicDomain(domain: String!): Boolean!
|
||||
checkPublicDomainValidRecords(domain: String!): DomainValidRecords
|
||||
createEmailingDomain(domain: String!, driver: EmailingDomainDriver!): EmailingDomain!
|
||||
@@ -4171,6 +4184,10 @@ input UpdateMessageChannelInputUpdates {
|
||||
excludeGroupEmails: Boolean
|
||||
}
|
||||
|
||||
input CreateEmailGroupChannelInput {
|
||||
handle: String!
|
||||
}
|
||||
|
||||
input UpdateCalendarChannelInput {
|
||||
id: UUID!
|
||||
update: UpdateCalendarChannelInputUpdates!
|
||||
|
||||
@@ -1388,7 +1388,7 @@ export interface FeatureFlag {
|
||||
__typename: 'FeatureFlag'
|
||||
}
|
||||
|
||||
export type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_COMMAND_MENU_ITEM_ENABLED' | 'IS_MARKETPLACE_SETTING_TAB_VISIBLE' | 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' | 'IS_PUBLIC_DOMAIN_ENABLED' | 'IS_EMAILING_DOMAIN_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_CONNECTED_ACCOUNT_MIGRATED' | 'IS_RICH_TEXT_V1_MIGRATED' | 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' | 'IS_DATASOURCE_MIGRATED' | 'IS_BILLING_V2_ENABLED'
|
||||
export type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_COMMAND_MENU_ITEM_ENABLED' | 'IS_MARKETPLACE_SETTING_TAB_VISIBLE' | 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' | 'IS_PUBLIC_DOMAIN_ENABLED' | 'IS_EMAILING_DOMAIN_ENABLED' | 'IS_EMAIL_GROUP_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_CONNECTED_ACCOUNT_MIGRATED' | 'IS_RICH_TEXT_V1_MIGRATED' | 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' | 'IS_DATASOURCE_MIGRATED' | 'IS_BILLING_V2_ENABLED'
|
||||
|
||||
export interface WorkspaceUrls {
|
||||
customUrl?: Scalars['String']
|
||||
@@ -1554,6 +1554,7 @@ export interface ClientConfig {
|
||||
isGoogleCalendarEnabled: Scalars['Boolean']
|
||||
isConfigVariablesInDbEnabled: Scalars['Boolean']
|
||||
isImapSmtpCaldavEnabled: Scalars['Boolean']
|
||||
isEmailGroupEnabled: Scalars['Boolean']
|
||||
allowRequestsToTwentyIcons: Scalars['Boolean']
|
||||
calendarBookingPageId?: Scalars['String']
|
||||
isCloudflareIntegrationEnabled: Scalars['Boolean']
|
||||
@@ -2025,6 +2026,7 @@ export interface PublicDomain {
|
||||
id: Scalars['UUID']
|
||||
domain: Scalars['String']
|
||||
isValidated: Scalars['Boolean']
|
||||
applicationId?: Scalars['UUID']
|
||||
createdAt: Scalars['DateTime']
|
||||
__typename: 'PublicDomain'
|
||||
}
|
||||
@@ -2459,12 +2461,13 @@ export interface MessageChannel {
|
||||
connectedAccountId: Scalars['UUID']
|
||||
createdAt: Scalars['DateTime']
|
||||
updatedAt: Scalars['DateTime']
|
||||
connectedAccount?: ConnectedAccountPublicDTO
|
||||
__typename: 'MessageChannel'
|
||||
}
|
||||
|
||||
export type MessageChannelVisibility = 'METADATA' | 'SUBJECT' | 'SHARE_EVERYTHING'
|
||||
|
||||
export type MessageChannelType = 'EMAIL' | 'SMS'
|
||||
export type MessageChannelType = 'EMAIL' | 'SMS' | 'EMAIL_GROUP'
|
||||
|
||||
export type MessageChannelContactAutoCreationPolicy = 'SENT_AND_RECEIVED' | 'SENT' | 'NONE'
|
||||
|
||||
@@ -2476,6 +2479,12 @@ export type MessageChannelSyncStatus = 'NOT_SYNCED' | 'ONGOING' | 'ACTIVE' | 'FA
|
||||
|
||||
export type MessageChannelSyncStage = 'PENDING_CONFIGURATION' | 'MESSAGE_LIST_FETCH_PENDING' | 'MESSAGE_LIST_FETCH_SCHEDULED' | 'MESSAGE_LIST_FETCH_ONGOING' | 'MESSAGES_IMPORT_PENDING' | 'MESSAGES_IMPORT_SCHEDULED' | 'MESSAGES_IMPORT_ONGOING' | 'FAILED'
|
||||
|
||||
export interface CreateEmailGroupChannelOutput {
|
||||
messageChannel: MessageChannel
|
||||
forwardingAddress: Scalars['String']
|
||||
__typename: 'CreateEmailGroupChannelOutput'
|
||||
}
|
||||
|
||||
export interface MessageFolder {
|
||||
id: Scalars['UUID']
|
||||
name?: Scalars['String']
|
||||
@@ -2772,6 +2781,8 @@ export interface Mutation {
|
||||
updateMessageFolder: MessageFolder
|
||||
updateMessageFolders: MessageFolder[]
|
||||
updateMessageChannel: MessageChannel
|
||||
createEmailGroupChannel: CreateEmailGroupChannelOutput
|
||||
deleteEmailGroupChannel: MessageChannel
|
||||
deleteConnectedAccount: ConnectedAccountDTO
|
||||
updateCalendarChannel: CalendarChannel
|
||||
createWebhook: Webhook
|
||||
@@ -2846,6 +2857,7 @@ export interface Mutation {
|
||||
enablePostgresProxy: PostgresCredentials
|
||||
disablePostgresProxy: PostgresCredentials
|
||||
createPublicDomain: PublicDomain
|
||||
updatePublicDomain: PublicDomain
|
||||
deletePublicDomain: Scalars['Boolean']
|
||||
checkPublicDomainValidRecords?: DomainValidRecords
|
||||
createEmailingDomain: EmailingDomain
|
||||
@@ -4495,6 +4507,7 @@ export interface ClientConfigGenqlSelection{
|
||||
isGoogleCalendarEnabled?: boolean | number
|
||||
isConfigVariablesInDbEnabled?: boolean | number
|
||||
isImapSmtpCaldavEnabled?: boolean | number
|
||||
isEmailGroupEnabled?: boolean | number
|
||||
allowRequestsToTwentyIcons?: boolean | number
|
||||
calendarBookingPageId?: boolean | number
|
||||
isCloudflareIntegrationEnabled?: boolean | number
|
||||
@@ -5024,6 +5037,7 @@ export interface PublicDomainGenqlSelection{
|
||||
id?: boolean | number
|
||||
domain?: boolean | number
|
||||
isValidated?: boolean | number
|
||||
applicationId?: boolean | number
|
||||
createdAt?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
@@ -5487,6 +5501,14 @@ export interface MessageChannelGenqlSelection{
|
||||
connectedAccountId?: boolean | number
|
||||
createdAt?: boolean | number
|
||||
updatedAt?: boolean | number
|
||||
connectedAccount?: ConnectedAccountPublicDTOGenqlSelection
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface CreateEmailGroupChannelOutputGenqlSelection{
|
||||
messageChannel?: MessageChannelGenqlSelection
|
||||
forwardingAddress?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
@@ -5828,6 +5850,8 @@ export interface MutationGenqlSelection{
|
||||
updateMessageFolder?: (MessageFolderGenqlSelection & { __args: {input: UpdateMessageFolderInput} })
|
||||
updateMessageFolders?: (MessageFolderGenqlSelection & { __args: {input: UpdateMessageFoldersInput} })
|
||||
updateMessageChannel?: (MessageChannelGenqlSelection & { __args: {input: UpdateMessageChannelInput} })
|
||||
createEmailGroupChannel?: (CreateEmailGroupChannelOutputGenqlSelection & { __args: {input: CreateEmailGroupChannelInput} })
|
||||
deleteEmailGroupChannel?: (MessageChannelGenqlSelection & { __args: {id: Scalars['UUID']} })
|
||||
deleteConnectedAccount?: (ConnectedAccountDTOGenqlSelection & { __args: {id: Scalars['UUID']} })
|
||||
updateCalendarChannel?: (CalendarChannelGenqlSelection & { __args: {input: UpdateCalendarChannelInput} })
|
||||
createWebhook?: (WebhookGenqlSelection & { __args: {input: CreateWebhookInput} })
|
||||
@@ -5901,7 +5925,8 @@ export interface MutationGenqlSelection{
|
||||
updateLabPublicFeatureFlag?: (FeatureFlagGenqlSelection & { __args: {input: UpdateLabPublicFeatureFlagInput} })
|
||||
enablePostgresProxy?: PostgresCredentialsGenqlSelection
|
||||
disablePostgresProxy?: PostgresCredentialsGenqlSelection
|
||||
createPublicDomain?: (PublicDomainGenqlSelection & { __args: {domain: Scalars['String']} })
|
||||
createPublicDomain?: (PublicDomainGenqlSelection & { __args: {domain: Scalars['String'], applicationId?: (Scalars['String'] | null)} })
|
||||
updatePublicDomain?: (PublicDomainGenqlSelection & { __args: {domain: Scalars['String'], applicationId?: (Scalars['String'] | null)} })
|
||||
deletePublicDomain?: { __args: {domain: Scalars['String']} }
|
||||
checkPublicDomainValidRecords?: (DomainValidRecordsGenqlSelection & { __args: {domain: Scalars['String']} })
|
||||
createEmailingDomain?: (EmailingDomainGenqlSelection & { __args: {domain: Scalars['String'], driver: EmailingDomainDriver} })
|
||||
@@ -6206,6 +6231,8 @@ export interface UpdateMessageChannelInput {id: Scalars['UUID'],update: UpdateMe
|
||||
|
||||
export interface UpdateMessageChannelInputUpdates {visibility?: (MessageChannelVisibility | null),isContactAutoCreationEnabled?: (Scalars['Boolean'] | null),contactAutoCreationPolicy?: (MessageChannelContactAutoCreationPolicy | null),messageFolderImportPolicy?: (MessageFolderImportPolicy | null),isSyncEnabled?: (Scalars['Boolean'] | null),excludeNonProfessionalEmails?: (Scalars['Boolean'] | null),excludeGroupEmails?: (Scalars['Boolean'] | null)}
|
||||
|
||||
export interface CreateEmailGroupChannelInput {handle: Scalars['String']}
|
||||
|
||||
export interface UpdateCalendarChannelInput {id: Scalars['UUID'],update: UpdateCalendarChannelInputUpdates}
|
||||
|
||||
export interface UpdateCalendarChannelInputUpdates {visibility?: (CalendarChannelVisibility | null),isContactAutoCreationEnabled?: (Scalars['Boolean'] | null),contactAutoCreationPolicy?: (CalendarChannelContactAutoCreationPolicy | null),isSyncEnabled?: (Scalars['Boolean'] | null)}
|
||||
@@ -8163,6 +8190,14 @@ export interface LogicFunctionLogsInput {applicationId?: (Scalars['UUID'] | null
|
||||
|
||||
|
||||
|
||||
const CreateEmailGroupChannelOutput_possibleTypes: string[] = ['CreateEmailGroupChannelOutput']
|
||||
export const isCreateEmailGroupChannelOutput = (obj?: { __typename?: any } | null): obj is CreateEmailGroupChannelOutput => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isCreateEmailGroupChannelOutput"')
|
||||
return CreateEmailGroupChannelOutput_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const MessageFolder_possibleTypes: string[] = ['MessageFolder']
|
||||
export const isMessageFolder = (obj?: { __typename?: any } | null): obj is MessageFolder => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isMessageFolder"')
|
||||
@@ -8691,6 +8726,7 @@ export const enumFeatureFlagKey = {
|
||||
IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED: 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' as const,
|
||||
IS_PUBLIC_DOMAIN_ENABLED: 'IS_PUBLIC_DOMAIN_ENABLED' as const,
|
||||
IS_EMAILING_DOMAIN_ENABLED: 'IS_EMAILING_DOMAIN_ENABLED' as const,
|
||||
IS_EMAIL_GROUP_ENABLED: 'IS_EMAIL_GROUP_ENABLED' as const,
|
||||
IS_JUNCTION_RELATIONS_ENABLED: 'IS_JUNCTION_RELATIONS_ENABLED' as const,
|
||||
IS_CONNECTED_ACCOUNT_MIGRATED: 'IS_CONNECTED_ACCOUNT_MIGRATED' as const,
|
||||
IS_RICH_TEXT_V1_MIGRATED: 'IS_RICH_TEXT_V1_MIGRATED' as const,
|
||||
@@ -8790,7 +8826,8 @@ export const enumMessageChannelVisibility = {
|
||||
|
||||
export const enumMessageChannelType = {
|
||||
EMAIL: 'EMAIL' as const,
|
||||
SMS: 'SMS' as const
|
||||
SMS: 'SMS' as const,
|
||||
EMAIL_GROUP: 'EMAIL_GROUP' as const
|
||||
}
|
||||
|
||||
export const enumMessageChannelContactAutoCreationPolicy = {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -37,7 +37,7 @@ Both are available as REST and GraphQL. GraphQL adds batch upserts and the abili
|
||||
Authorization: Bearer YOUR_API_KEY
|
||||
```
|
||||
|
||||
Create an API key in **Settings → API & Webhooks → + Create key**. Copy it immediately — it's shown once. Keys can be scoped to a specific role under **Settings → Roles → Assignment tab** to limit what they can access.
|
||||
Create an API key in **Settings → API & Webhooks → + Create key**. Copy it immediately — it's shown once. Keys can be scoped to a specific role under **Settings → Members → Roles → Assignment tab** to limit what they can access.
|
||||
|
||||
<VimeoEmbed videoId="928786722" title="Creating API key" />
|
||||
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -83,7 +83,7 @@ Your API key grants access to sensitive data. Don't share it with untrusted serv
|
||||
|
||||
For better security, assign a specific role to limit access:
|
||||
|
||||
1. Go to **Settings → Roles**
|
||||
1. Go to **Settings → Members → Roles**
|
||||
2. Click on the role to assign
|
||||
3. Open the **Assignment** tab
|
||||
4. Under **API Keys**, click **+ Assign to API key**
|
||||
|
||||
@@ -4293,7 +4293,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Data",
|
||||
"group": "Dados",
|
||||
"pages": [
|
||||
"l/pt/developers/extend/apps/data/overview",
|
||||
"l/pt/developers/extend/apps/data/objects",
|
||||
|
||||
@@ -37,7 +37,7 @@ Beide sind als REST und GraphQL verfügbar. GraphQL bietet Batch-Upserts und die
|
||||
Authorization: Bearer YOUR_API_KEY
|
||||
```
|
||||
|
||||
Erstellen Sie einen API-Schlüssel unter **Settings > APIs & Webhooks > + Create key**. Kopieren Sie ihn sofort — er wird nur einmal angezeigt. Schlüssel können unter **Settings > Roles > Assignment tab** auf eine bestimmte Rolle beschränkt werden, um ihren Zugriff einzuschränken.
|
||||
Erstellen Sie einen API-Schlüssel unter **Settings > APIs & Webhooks > + Create key**. Kopieren Sie ihn sofort — er wird nur einmal angezeigt. Schlüssel können unter **Settings → Members → Roles → Assignment tab** auf eine bestimmte Rolle beschränkt werden, um ihren Zugriff einzuschränken.
|
||||
|
||||
<VimeoEmbed videoId="928786722" title="API-Schlüssel erstellen" />
|
||||
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -88,7 +88,7 @@ Ihr API-Schlüssel gewährt Zugriff auf sensible Daten. Teilen Sie ihn nicht mit
|
||||
|
||||
Für mehr Sicherheit weisen Sie eine spezifische Rolle zu, um den Zugriff zu beschränken:
|
||||
|
||||
1. Gehen Sie zu **Einstellungen → Rollen**
|
||||
1. Gehen Sie zu **Einstellungen → Mitglieder → Rollen**
|
||||
2. Klicken Sie auf die Rolle, die Sie zuweisen möchten
|
||||
3. Öffnen Sie den Tab **Zuweisungen**
|
||||
4. Unter **API-Schlüssel** auf **+ API-Schlüssel zuweisen** klicken
|
||||
|
||||
@@ -9,7 +9,7 @@ KI-Agenten respektieren Ihre bestehende Berechtigungsstruktur. Dies ist besonder
|
||||
|
||||
## Weisen Sie einem KI-Agenten eine Rolle zu
|
||||
|
||||
1. Gehen Sie zu **Einstellungen → Rollen**
|
||||
1. Gehen Sie zu **Einstellungen → Mitglieder → Rollen**
|
||||
2. Klicken Sie auf die Rolle, die Sie zuweisen möchten
|
||||
3. Öffnen Sie den Tab **Zuweisungen**
|
||||
4. Unter **KI-Agenten** klicken Sie auf **+ KI-Agent zuweisen**
|
||||
|
||||
@@ -17,7 +17,7 @@ description: Häufig gestellte Fragen zu KI-Funktionen in Twenty.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Haben KI-Agenten Zugriff auf alle meine Daten?">
|
||||
KI-Agenten werden über das Berechtigungssystem verwaltet. Sie können KI-Agenten unter **Einstellungen → Rollen** bestimmte Rollen zuweisen und haben damit volle Kontrolle darüber, auf welche Daten sie zugreifen können und welche Aktionen sie ausführen dürfen.
|
||||
KI-Agenten werden über das Berechtigungssystem verwaltet. Sie können KI-Agenten unter **Einstellungen → Mitglieder → Rollen** bestimmte Rollen zuweisen und haben damit volle Kontrolle darüber, auf welche Daten sie zugreifen können und welche Aktionen sie ausführen dürfen.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Wie funktionieren KI-Credits?">
|
||||
|
||||
@@ -48,7 +48,7 @@ Erweitern Sie Ihre Workflows mit KI-gestützten Aktionen und autonomen Agenten.
|
||||
|
||||
KI-Agenten werden über das bestehende Berechtigungssystem verwaltet:
|
||||
|
||||
1. Gehen Sie zu **Einstellungen → Rollen**
|
||||
1. Gehen Sie zu **Einstellungen → Mitglieder → Rollen**
|
||||
2. Konfigurieren Sie, auf welche Daten jeder KI-Agent zugreifen kann
|
||||
3. Legen Sie Lese-/Schreibberechtigungen pro Objekt fest
|
||||
|
||||
|
||||
+1
-1
@@ -214,7 +214,7 @@ Schließen Sie nach dem Import der Daten die Konfiguration Ihres Arbeitsbereichs
|
||||
|
||||
### Rollen und Berechtigungen konfigurieren
|
||||
|
||||
* Richten Sie Rollen unter **Einstellungen → Rollen** ein
|
||||
* Richten Sie Rollen unter **Einstellungen → Mitglieder → Rollen** ein
|
||||
* Weisen Sie Benutzer den entsprechenden Rollen zu
|
||||
|
||||
### E-Mail und Kalender verbinden
|
||||
|
||||
+1
-1
@@ -127,7 +127,7 @@ Erstellen Sie nach dem Import der Daten manuell neu:
|
||||
|
||||
### Rollen und Berechtigungen
|
||||
|
||||
* Konfigurieren Sie Rollen in **Einstellungen → Rollen**
|
||||
* Richten Sie Rollen unter **Einstellungen → Mitglieder → Rollen** ein
|
||||
* Weisen Sie Benutzer den entsprechenden Rollen zu
|
||||
|
||||
### Integrationen
|
||||
|
||||
+7
-7
@@ -13,7 +13,7 @@ Das Berechtigungssystem von Twenty ermöglicht es Ihnen, den Zugriff auf drei Ha
|
||||
|
||||
Um eine neue Rolle zu erstellen:
|
||||
|
||||
1. Gehen Sie zu **Einstellungen → Rollen**
|
||||
1. Gehen Sie zu **Einstellungen → Mitglieder → Rollen**
|
||||
2. Unter **Alle Rollen** klicken Sie auf **+ Rolle erstellen**
|
||||
3. Geben Sie einen Rollennamen ein
|
||||
4. Im Standard-Tab **Berechtigungen** [Berechtigungen konfigurieren](#customize-permissions)
|
||||
@@ -23,7 +23,7 @@ Um eine neue Rolle zu erstellen:
|
||||
|
||||
Um eine Rolle zu löschen:
|
||||
|
||||
1. Gehen Sie zu **Einstellungen → Rollen**
|
||||
1. Gehen Sie zu **Einstellungen → Mitglieder → Rollen**
|
||||
2. Klicken Sie auf die Rolle, die Sie entfernen möchten
|
||||
3. Öffnen Sie den Tab **Einstellungen** und klicken Sie auf **Rolle löschen**
|
||||
4. Klicken Sie im Modal auf **Bestätigen**
|
||||
@@ -36,13 +36,13 @@ Wenn eine Rolle gelöscht wird, wird jedes ihr zugewiesene Mitglied des Arbeitsb
|
||||
|
||||
### Aktuelle Zuweisungen anzeigen
|
||||
|
||||
* Gehen Sie zu **Einstellungen → Rollen**
|
||||
* Gehen Sie zu **Einstellungen → Mitglieder → Rollen**
|
||||
* Sehen Sie alle Rollen und wie viele Mitglieder jeweils zugewiesen sind
|
||||
* Anzeigen, welche Mitglieder welche Rollen haben
|
||||
|
||||
### Weisen Sie einem Mitglied eine Rolle zu
|
||||
|
||||
1. Gehen Sie zu **Einstellungen → Rollen**
|
||||
1. Gehen Sie zu **Einstellungen → Mitglieder → Rollen**
|
||||
2. Klicken Sie auf die Rolle, die Sie zuweisen möchten
|
||||
3. Öffnen Sie den Tab **Zuweisungen**
|
||||
4. Klicken Sie auf **+ Mitglied zuweisen**
|
||||
@@ -51,7 +51,7 @@ Wenn eine Rolle gelöscht wird, wird jedes ihr zugewiesene Mitglied des Arbeitsb
|
||||
|
||||
### Standardrolle festlegen
|
||||
|
||||
1. Gehen Sie zu **Einstellungen → Rollen**
|
||||
1. Gehen Sie zu **Einstellungen → Mitglieder → Rollen**
|
||||
2. Suchen Sie im Abschnitt **Optionen** nach **Standardrolle**
|
||||
3. Wählen Sie aus, welche Rolle neue Mitglieder automatisch erhalten sollen
|
||||
4. Neue Arbeitsbereichsmitglieder werden beim Beitritt dieser Rolle zugewiesen
|
||||
@@ -168,7 +168,7 @@ Neben Mitgliedern des Arbeitsbereichs können Rollen auch **API-Schlüsseln** un
|
||||
|
||||
### Einem API-Schlüssel eine Rolle zuweisen
|
||||
|
||||
1. Gehen Sie zu **Einstellungen → Rollen**
|
||||
1. Gehen Sie zu **Einstellungen → Mitglieder → Rollen**
|
||||
2. Klicken Sie auf die Rolle, die Sie zuweisen möchten
|
||||
3. Öffnen Sie den Tab **Zuweisungen**
|
||||
4. Unter **API-Schlüssel** auf **+ API-Schlüssel zuweisen** klicken
|
||||
@@ -183,7 +183,7 @@ API-Schlüssel ohne zugewiesene Rolle verwenden Standardberechtigungen. Weisen S
|
||||
|
||||
### Einem KI-Agenten eine Rolle zuweisen
|
||||
|
||||
1. Gehen Sie zu **Einstellungen → Rollen**
|
||||
1. Gehen Sie zu **Einstellungen → Mitglieder → Rollen**
|
||||
2. Klicken Sie auf die Rolle, die Sie zuweisen möchten
|
||||
3. Öffnen Sie den Tab **Zuweisungen**
|
||||
4. Unter **KI-Agenten** auf **+ KI-Agenten zuweisen** klicken
|
||||
|
||||
@@ -19,7 +19,7 @@ Jedes Mitglied des Arbeitsbereichs, dem diese Rolle zugewiesen ist, wird automat
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Wie lege ich eine Standardrolle für neue Mitglieder fest?">
|
||||
Gehen Sie zu **Einstellungen → Rollen**, suchen Sie die Option **Standardrolle** und wählen Sie aus, welche Rolle neue Mitglieder beim Beitritt automatisch erhalten sollen.
|
||||
Gehen Sie zu **Einstellungen → Mitglieder → Rollen**, suchen Sie die Option **Standardrolle** und wählen Sie aus, welche Rolle neue Mitglieder beim Beitritt automatisch erhalten sollen.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Kann ich einem Benutzer mehrere Rollen zuweisen?">
|
||||
@@ -64,7 +64,7 @@ Berechtigungen auf Zeilenebene werden bis Q1 2026 im Tarif **Organization** verf
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Wie mache ich ein Feld für bestimmte Benutzer schreibgeschützt?">
|
||||
1. Gehen Sie zu **Einstellungen → Rollen**
|
||||
1. Gehen Sie zu **Einstellungen → Mitglieder → Rollen**
|
||||
2. Wählen Sie die Rolle aus
|
||||
3. Navigieren Sie zu dem Objekt, das das Feld enthält
|
||||
4. Setzen Sie die Feldberechtigung auf **Feld anzeigen** (ohne Feld bearbeiten)
|
||||
|
||||
@@ -3,10 +3,12 @@ title: Domäneneinstellungen
|
||||
description: Konfigurieren Sie die Arbeitsbereichsdomäne, genehmigte Zugriffsdomänen und öffentliche Domänen.
|
||||
---
|
||||
|
||||
Konfigurieren Sie die Domäneneinstellungen unter **Einstellungen → Domänen**.
|
||||
Domain-Einstellungen befinden sich an drei Stellen, abhängig davon, was Sie konfigurieren.
|
||||
|
||||
## Arbeitsbereichsdomäne
|
||||
|
||||
Konfigurieren Sie dies unter **Einstellungen → Allgemein → Arbeitsbereichs-Domain**.
|
||||
|
||||
Bearbeiten Sie den Namen Ihrer Subdomäne oder legen Sie eine benutzerdefinierte Domäne für Ihren Arbeitsbereich fest.
|
||||
|
||||
### Domäne anpassen
|
||||
@@ -19,6 +21,8 @@ Für benutzerdefinierte Domänen müssen Sie die DNS-Einstellungen bei Ihrem Dom
|
||||
|
||||
## Genehmigte Domänen
|
||||
|
||||
Konfigurieren Sie dies unter **Einstellungen → Mitglieder → Zugriff**.
|
||||
|
||||
Jede Person mit einer E-Mail-Adresse in diesen Domänen darf sich automatisch für diesen Arbeitsbereich registrieren.
|
||||
|
||||
### Genehmigte Zugriffsdomäne hinzufügen
|
||||
@@ -35,13 +39,16 @@ Dies ist nützlich, um Ihrem gesamten Team die Selbstregistrierung zu ermöglich
|
||||
|
||||
## Öffentliche Domains
|
||||
|
||||
Stellen Sie eine vollständige und sichere Hosting-Umgebung auf diesen Domains bereit.
|
||||
Konfigurieren Sie dies unter **Einstellungen → Apps → Entwickler**.
|
||||
|
||||
Stellen Sie eine vollständige und sichere Hosting-Umgebung auf diesen Domains bereit. Eine öffentliche Domain kann an eine bestimmte App gebunden werden – wenn sie gebunden ist, sind unter dieser Domain nur die HTTP-gerouteten Logikfunktionen dieser App erreichbar. Lassen Sie die Bindung leer, um alle HTTP-Routen des Arbeitsbereichs bereitzustellen.
|
||||
|
||||
### Öffentliche Domäne hinzufügen
|
||||
|
||||
1. Klicken Sie auf **Öffentliche Domäne hinzufügen**
|
||||
2. Geben Sie die Domäne ein, die Sie verwenden möchten
|
||||
3. Konfigurieren Sie die DNS-Einstellungen gemäß Anleitung
|
||||
4. Überprüfen Sie die Domäne
|
||||
3. Optional an eine App binden
|
||||
4. Konfigurieren Sie die DNS-Einstellungen gemäß Anleitung
|
||||
5. Überprüfen Sie die Domäne
|
||||
|
||||
SSL-Zertifikate werden für öffentliche Domänen automatisch bereitgestellt.
|
||||
|
||||
@@ -77,7 +77,7 @@ Verwalten Sie Einladungen, die noch nicht angenommen wurden:
|
||||
|
||||
Erlauben Sie Teammitgliedern, basierend auf ihrer E-Mail-Domäne automatisch beizutreten:
|
||||
|
||||
1. Gehen Sie zu **Einstellungen → Domänen**
|
||||
1. Gehen Sie zu **Einstellungen → Mitglieder → Zugriff**
|
||||
2. Fügen Sie die Domäne Ihres Unternehmens hinzu (z. B. `yourcompany.com`)
|
||||
3. Jede Person mit dieser E-Mail-Domäne kann ohne Einladung beitreten
|
||||
|
||||
|
||||
@@ -137,7 +137,7 @@ Ja, Sie können mehrere E-Mail-Konten verbinden. Gehen Sie zu **Einstellungen
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Kann ich meine Arbeitsbereichsdomäne anpassen?">
|
||||
Ja! Gehen Sie zu **Einstellungen → Domänen** und klicken Sie auf **Domäne anpassen**. Sie haben zwei Optionen:
|
||||
Ja! Gehen Sie zu **Einstellungen → Allgemein → Workspace-Domäne** und klicken Sie auf **Domäne anpassen**. Sie haben zwei Optionen:
|
||||
|
||||
* **Subdomain**: Verwenden Sie eine Twenty-Subdomain wie `yourcompany.twenty.com`
|
||||
* **Benutzerdefinierte Domäne**: Verwenden Sie Ihre eigene Domäne wie `crm.yourcompany.com` (erfordert DNS-Konfiguration)
|
||||
@@ -146,7 +146,7 @@ Eine Subdomain ist schnell eingerichtet, während eine benutzerdefinierte Domän
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Wie funktionieren genehmigte Zugriffsdomänen?">
|
||||
Sie können genehmigte Zugriffsdomänen konfigurieren, damit Teammitglieder mit Firmen-E-Mail-Adressen Ihrem Arbeitsbereich automatisch beitreten können. Gehen Sie zu **Einstellungen → Domänen** und fügen Sie Ihre Firmendomäne hinzu (z. B. `yourcompany.com`).
|
||||
Sie können genehmigte Zugriffsdomänen konfigurieren, damit Teammitglieder mit Firmen-E-Mail-Adressen Ihrem Arbeitsbereich automatisch beitreten können. Gehen Sie zu **Einstellungen → Mitglieder → Zugriff** und fügen Sie Ihre Firmendomäne hinzu (z. B. `yourcompany.com`).
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ Fügen Sie Ihrem Arbeitsbereich Teammitglieder hinzu:
|
||||
4. Weisen Sie geeignete Rollen zu
|
||||
|
||||
<Note>
|
||||
Bevor Sie Ihr Team einladen, überprüfen Sie die Standardrolle unter **Einstellungen → Rollen**. Neuen Mitgliedern wird diese Rolle beim Beitritt automatisch zugewiesen.
|
||||
Bevor Sie Ihr Team einladen, überprüfen Sie die Standardrolle unter **Einstellungen → Mitglieder → Rollen**. Neuen Mitgliedern wird diese Rolle beim Beitritt automatisch zugewiesen.
|
||||
</Note>
|
||||
|
||||
## Checkliste für Arbeitsbereichseinstellungen
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ Sie benötigen zwei benutzerdefinierte Felder am Objekt „Opportunities“.
|
||||
|
||||
Wenn Benutzer diese berechneten Felder nicht manuell bearbeiten sollen:
|
||||
|
||||
1. Gehen Sie zu **Einstellungen → Rollen**
|
||||
1. Gehen Sie zu **Einstellungen → Mitglieder → Rollen**
|
||||
2. Wählen Sie die zu konfigurierende Rolle aus
|
||||
3. Suchen Sie das Objekt „Opportunities“
|
||||
4. Setzen Sie die Felder **Probability** und **Expected Amount** auf schreibgeschützt
|
||||
|
||||
+1
-1
@@ -61,7 +61,7 @@ Sie benötigen keine "Days in"-Felder für Closed Won und Closed Lost, da dies f
|
||||
|
||||
Wenn Benutzer diese berechneten Felder nicht manuell bearbeiten sollen:
|
||||
|
||||
1. Gehen Sie zu **Einstellungen → Rollen**
|
||||
1. Gehen Sie zu **Einstellungen → Mitglieder → Rollen**
|
||||
2. Rolle zum Konfigurieren auswählen
|
||||
3. Suchen Sie das Objekt Opportunities
|
||||
4. Setzen Sie die Felder "Last Entered" und "Days in" auf schreibgeschützt
|
||||
|
||||
@@ -307,5 +307,5 @@ AI Agent actions consume workflow credits based on the AI model used. See [Workf
|
||||
</Note>
|
||||
|
||||
<Note>
|
||||
AI agents respect role-based permissions. You can assign specific roles to agents under **Settings → Roles** to control what data they can access. See [Permissions](/l/de/user-guide/permissions-access/capabilities/permissions) for details.
|
||||
AI agents respect role-based permissions. Sie können Agenten unter **Einstellungen → Mitglieder → Rollen** bestimmte Rollen zuweisen, um zu steuern, auf welche Daten sie zugreifen können. See [Permissions](/l/de/user-guide/permissions-access/capabilities/permissions) for details.
|
||||
</Note>
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ description: Häufig gestellte Fragen zu Workflows in Twenty.
|
||||
<Accordion title="Warum kann ich einen Workflow nicht aktivieren?">
|
||||
Dies ist wahrscheinlich ein Berechtigungsproblem. Sie benötigen Zugriff auf Workflows, um sie zu erstellen und zu aktivieren.
|
||||
|
||||
**Lösung**: Wenden Sie sich an Ihren Workspace-Administrator, damit er Ihnen unter **Einstellungen → Rollen** Zugriff auf Workflows gewährt.
|
||||
**Lösung**: Wenden Sie sich an Ihren Workspace-Administrator, damit er Ihnen unter **Einstellungen → Mitglieder → Rollen** Zugriff auf Workflows gewährt.
|
||||
|
||||
Wenn Sie den Bereich Workflows in Ihrer Seitenleiste überhaupt nicht sehen, bestätigt dies ein Berechtigungsproblem.
|
||||
</Accordion>
|
||||
|
||||
@@ -37,7 +37,7 @@ Ambas estão disponíveis como REST e GraphQL. GraphQL adiciona upserts em lote
|
||||
Authorization: Bearer YOUR_API_KEY
|
||||
```
|
||||
|
||||
Crie uma chave de API em **Settings → API & Webhooks → + Create key**. Copie-a imediatamente — ela é exibida apenas uma vez. As chaves podem ter escopo para uma função específica em **Settings → Roles → Assignment tab** para limitar o que podem acessar.
|
||||
Crie uma chave de API em **Settings → API & Webhooks → + Create key**. Copie-a imediatamente — ela é exibida apenas uma vez. As chaves podem ser limitadas a uma função específica em **Settings → Members → Roles → Assignment tab** para restringir o que podem acessar.
|
||||
|
||||
<VimeoEmbed videoId="928786722" title="Criando chave de API" />
|
||||
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -88,7 +88,7 @@ Sua chave de API concede acesso a dados confidenciais. Não a compartilhe com se
|
||||
|
||||
Para maior segurança, atribua uma função específica para limitar o acesso:
|
||||
|
||||
1. Vá para **Configurações → Funções**
|
||||
1. Vá para **Configurações → Membros → Funções**
|
||||
2. Clique na função que deseja atribuir
|
||||
3. Abra a aba de **Atribuição**
|
||||
4. Em **Chaves de API**, clique em **+ Atribuir à chave de API**
|
||||
|
||||
@@ -164,7 +164,7 @@
|
||||
"label": "Configuração"
|
||||
},
|
||||
"appsData": {
|
||||
"label": "Data"
|
||||
"label": "Dados"
|
||||
},
|
||||
"appsLogic": {
|
||||
"label": "Lógica"
|
||||
|
||||
@@ -9,7 +9,7 @@ Os agentes de IA respeitam sua estrutura de permissões existente. Isso é parti
|
||||
|
||||
## Atribuir uma Função a um Agente de IA
|
||||
|
||||
1. Vá para **Configurações → Funções**
|
||||
1. Vá para **Configurações → Membros → Funções**
|
||||
2. Clique na função que deseja atribuir
|
||||
3. Abra a aba de **Atribuição**
|
||||
4. Em **Agentes de IA**, clique em **+ Atribuir ao agente de IA**
|
||||
|
||||
@@ -17,7 +17,7 @@ description: Perguntas frequentes sobre recursos de IA na Twenty.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Os agentes de IA terão acesso a todos os meus dados?">
|
||||
Os agentes de IA funcionarão de acordo com o sistema de permissões. Você pode atribuir funções específicas aos agentes de IA em **Configurações → Funções**, dando a você controle total sobre quais dados eles podem acessar e quais ações podem executar.
|
||||
Os agentes de IA funcionarão de acordo com o sistema de permissões. Você pode atribuir funções específicas aos agentes de IA em **Configurações → Membros → Funções**, dando a você controle total sobre quais dados eles podem acessar e quais ações podem executar.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Como os créditos de IA vão funcionar?">
|
||||
|
||||
@@ -48,7 +48,7 @@ Amplie seus fluxos de trabalho com ações com IA e agentes autônomos.
|
||||
|
||||
Os agentes de IA serão gerenciados pelo sistema de permissões existente:
|
||||
|
||||
1. Vá para **Configurações → Funções**
|
||||
1. Vá para **Configurações → Membros → Funções**
|
||||
2. Configure quais dados cada agente de IA pode acessar
|
||||
3. Defina permissões de leitura/gravação por objeto
|
||||
|
||||
|
||||
+1
-1
@@ -214,7 +214,7 @@ Após importar os dados, complete a configuração do seu espaço de trabalho:
|
||||
|
||||
### Configure funções e permissões
|
||||
|
||||
* Configure as funções em **Definições → Funções**
|
||||
* Configure as funções em **Definições → Membros → Funções**
|
||||
* Atribua os utilizadores às funções apropriadas
|
||||
|
||||
### Ligue o e-mail e o calendário
|
||||
|
||||
+1
-1
@@ -127,7 +127,7 @@ Depois de importar os dados, recrie manualmente:
|
||||
|
||||
### Funções e Permissões
|
||||
|
||||
* Configure as funções em **Configurações → Funções**
|
||||
* Configure as funções em **Definições → Membros → Funções**
|
||||
* Atribua os utilizadores às funções apropriadas
|
||||
|
||||
### Integrações
|
||||
|
||||
+7
-7
@@ -13,7 +13,7 @@ O sistema de permissões do Twenty permite que você controle o acesso a três
|
||||
|
||||
Para criar uma nova função:
|
||||
|
||||
1. Vá para **Configurações → Funções**
|
||||
1. Vá para **Configurações → Membros → Funções**
|
||||
2. Em **Todas as Funções**, clique em **+ Criar Função**
|
||||
3. Digite um nome para a função
|
||||
4. Na aba padrão **Permissões**, [configure as permissões](#customize-permissions)
|
||||
@@ -23,7 +23,7 @@ Para criar uma nova função:
|
||||
|
||||
Para excluir uma função:
|
||||
|
||||
1. Vá para **Configurações → Funções**
|
||||
1. Vá para **Configurações → Membros → Funções**
|
||||
2. Clique na função que deseja remover
|
||||
3. Abra a aba de **Configurações** e clique em **Excluir Função**
|
||||
4. Clique em **Confirmar** no modal
|
||||
@@ -36,13 +36,13 @@ Se uma função for excluída, qualquer membro do espaço de trabalho atribuído
|
||||
|
||||
### Visualizar Atribuições Atuais
|
||||
|
||||
* Vá para **Configurações → Funções**
|
||||
* Vá para **Configurações → Membros → Funções**
|
||||
* Veja todas as funções e quantos membros estão atribuídos a cada uma
|
||||
* Veja quais membros têm quais funções
|
||||
|
||||
### Atribuir uma Função a um Membro
|
||||
|
||||
1. Vá para **Configurações → Funções**
|
||||
1. Vá para **Configurações → Membros → Funções**
|
||||
2. Clique na função que deseja atribuir
|
||||
3. Abra a aba de **Atribuição**
|
||||
4. Clique em **+ Atribuir a membro**
|
||||
@@ -51,7 +51,7 @@ Se uma função for excluída, qualquer membro do espaço de trabalho atribuído
|
||||
|
||||
### Definir Função Padrão
|
||||
|
||||
1. Vá para **Configurações → Funções**
|
||||
1. Vá para **Configurações → Membros → Funções**
|
||||
2. Na seção **Opções**, encontre **Função Padrão**
|
||||
3. Selecione qual função novos membros devem receber automaticamente
|
||||
4. Novos membros do espaço de trabalho serão atribuídos a essa função ao ingressar
|
||||
@@ -168,7 +168,7 @@ Além dos membros do espaço de trabalho, funções também podem ser atribuída
|
||||
|
||||
### Atribuir uma função a uma chave de API
|
||||
|
||||
1. Vá para **Configurações → Funções**
|
||||
1. Vá para **Configurações → Membros → Funções**
|
||||
2. Clique na função que deseja atribuir
|
||||
3. Abra a aba de **Atribuição**
|
||||
4. Em **Chaves de API**, clique em **+ Atribuir à chave de API**
|
||||
@@ -183,7 +183,7 @@ Chaves de API sem uma função atribuída usam permissões padrão. Para maior s
|
||||
|
||||
### Atribuir uma função a um agente de IA
|
||||
|
||||
1. Vá para **Configurações → Funções**
|
||||
1. Vá para **Configurações → Membros → Funções**
|
||||
2. Clique na função que deseja atribuir
|
||||
3. Abra a aba de **Atribuição**
|
||||
4. Em **Agentes de IA**, clique em **+ Atribuir ao agente de IA**
|
||||
|
||||
@@ -19,7 +19,7 @@ Qualquer membro do espaço de trabalho atribuído a essa função será automati
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Como defino uma função padrão para novos membros?">
|
||||
Vá para **Configurações → Funções**, encontre a opção **Função Padrão** e selecione qual função os novos membros devem receber automaticamente ao entrar.
|
||||
Vá para **Configurações → Membros → Funções**, encontre a opção **Função Padrão** e selecione qual função os novos membros devem receber automaticamente ao entrar.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Posso atribuir várias funções a um único usuário?">
|
||||
@@ -64,7 +64,7 @@ As permissões em nível de linha estarão disponíveis no plano **Organization*
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Como deixar um campo somente leitura para determinados usuários?">
|
||||
1. Vá para **Configurações → Funções**
|
||||
1. Vá para **Configurações → Membros → Funções**
|
||||
2. Selecione a função
|
||||
3. Navegue até o objeto que contém o campo
|
||||
4. Defina a permissão do campo como **Ver campo** (sem Editar campo)
|
||||
|
||||
@@ -3,10 +3,12 @@ title: Configurações de Domínio
|
||||
description: Configure o domínio do espaço de trabalho, os domínios de acesso aprovados e os domínios públicos.
|
||||
---
|
||||
|
||||
Configure as configurações de domínio em **Configurações → Domínios**.
|
||||
As configurações de domínio ficam em três lugares, dependendo do que você está configurando.
|
||||
|
||||
## Domínio do espaço de trabalho
|
||||
|
||||
Configure em **Configurações → Geral → Domínio do workspace**.
|
||||
|
||||
Edite o nome do seu subdomínio ou defina um domínio personalizado para o seu espaço de trabalho.
|
||||
|
||||
### Personalizar domínio
|
||||
@@ -19,6 +21,8 @@ Para domínios personalizados, você precisará configurar as configurações de
|
||||
|
||||
## Domínios Aprovados
|
||||
|
||||
Configure em **Configurações → Membros → Acesso**.
|
||||
|
||||
Qualquer pessoa com um endereço de e-mail nesses domínios pode inscrever-se neste espaço de trabalho automaticamente.
|
||||
|
||||
### Adicionar Domínio de Acesso Aprovado
|
||||
@@ -35,13 +39,16 @@ Isso é útil para permitir que toda a sua equipe se registre por conta própria
|
||||
|
||||
## Domínios Públicos
|
||||
|
||||
Provisionar um ambiente de hospedagem completo e seguro nestes domínios.
|
||||
Configure em **Configurações → Aplicativos → Desenvolvedor**.
|
||||
|
||||
Provisionar um ambiente de hospedagem completo e seguro nestes domínios. Um domínio público pode ser vinculado a um app específico — quando vinculado, somente as funções de lógica roteadas por HTTP desse app ficam acessíveis no domínio. Deixe a vinculação vazia para expor todas as rotas HTTP do workspace.
|
||||
|
||||
### Adicionar Domínio Público
|
||||
|
||||
1. Clique em **Adicionar Domínio Público**
|
||||
2. Insira o domínio que você deseja usar
|
||||
3. Configure as configurações de DNS conforme as instruções
|
||||
4. Verifique o domínio
|
||||
3. Opcionalmente vincule-o a um app
|
||||
4. Configure as configurações de DNS conforme as instruções
|
||||
5. Verifique o domínio
|
||||
|
||||
Os certificados SSL são provisionados automaticamente para domínios públicos.
|
||||
|
||||
@@ -77,7 +77,7 @@ Gerencie convites que ainda não foram aceitos:
|
||||
|
||||
Permita que membros da equipe ingressem automaticamente com base no domínio de e-mail:
|
||||
|
||||
1. Vá para **Configurações → Domínios**
|
||||
1. Vá para **Configurações → Membros → Acesso**
|
||||
2. Adicione o domínio da sua empresa (por exemplo, `yourcompany.com`)
|
||||
3. Qualquer pessoa com esse domínio de e-mail pode ingressar sem convite
|
||||
|
||||
|
||||
@@ -137,7 +137,7 @@ Sim, você pode conectar várias contas de e-mail. Vá para **Configurações
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Posso personalizar o domínio do meu espaço de trabalho?">
|
||||
Sim! Vá para **Configurações → Domínios** e clique em **Personalizar domínio**. Você tem duas opções:
|
||||
Sim! Vá para **Configurações → Geral → Domínio do espaço de trabalho** e clique em **Personalizar domínio**. Você tem duas opções:
|
||||
|
||||
* **Subdomínio**: Use um subdomínio do Twenty como `yourcompany.twenty.com`
|
||||
* **Domínio personalizado**: Use seu próprio domínio, como `crm.yourcompany.com` (requer configuração de DNS)
|
||||
@@ -146,7 +146,7 @@ Um subdomínio é rápido de configurar, enquanto um domínio personalizado ofer
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Como funcionam os domínios de acesso aprovados?">
|
||||
Você pode configurar domínios de acesso aprovados para que membros da equipe com endereços de e-mail da empresa possam ingressar automaticamente no seu espaço de trabalho. Vá para **Configurações → Domínios** e adicione o domínio da sua empresa (por exemplo, `yourcompany.com`).
|
||||
Você pode configurar domínios de acesso aprovados para que membros da equipe com endereços de e-mail da empresa possam ingressar automaticamente no seu espaço de trabalho. Vá para **Configurações → Membros → Acesso** e adicione o domínio da sua empresa (por exemplo, `yourcompany.com`).
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ Adicione membros da equipa ao seu espaço de trabalho:
|
||||
4. Atribua funções apropriadas
|
||||
|
||||
<Note>
|
||||
Antes de convidar a sua equipa, verifique a função padrão em **Configurações → Funções**. Novos membros recebem automaticamente essa função ao entrar.
|
||||
Antes de convidar a sua equipa, verifique a função padrão em **Configurações → Membros → Funções**. Novos membros recebem automaticamente essa função ao entrar.
|
||||
</Note>
|
||||
|
||||
## Lista de Verificação das Configurações do Espaço de Trabalho
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ Você precisa de dois campos personalizados no objeto Oportunidades.
|
||||
|
||||
Se você não quiser que os usuários editem manualmente esses campos calculados:
|
||||
|
||||
1. Vá para **Configurações → Funções**
|
||||
1. Vá para **Configurações → Membros → Funções**
|
||||
2. Selecione a função a configurar
|
||||
3. Encontre o objeto Oportunidades
|
||||
4. Defina os campos **Probability** e **Expected Amount** como somente leitura
|
||||
|
||||
+1
-1
@@ -61,7 +61,7 @@ Você não precisa de campos "Dias em" para Fechado Ganho e Fechado Perdido, poi
|
||||
|
||||
Se você não quiser que os usuários editem manualmente esses campos calculados:
|
||||
|
||||
1. Vá para **Configurações → Funções**
|
||||
1. Vá para **Configurações → Membros → Funções**
|
||||
2. Selecione a função a configurar
|
||||
3. Encontre o objeto Oportunidades
|
||||
4. Defina os campos "Última entrada" e "Dias em" como somente leitura
|
||||
|
||||
@@ -307,5 +307,5 @@ As ações do Agente de IA consomem créditos de fluxo de trabalho com base no m
|
||||
</Note>
|
||||
|
||||
<Note>
|
||||
Os agentes de IA respeitam permissões baseadas em funções. Você pode atribuir funções específicas aos agentes em **Configurações → Funções** para controlar a quais dados eles podem acessar. Veja [Permissões](/l/pt/user-guide/permissions-access/capabilities/permissions) para obter detalhes.
|
||||
Os agentes de IA respeitam permissões baseadas em funções. Você pode atribuir funções específicas aos agentes em **Configurações → Membros → Funções** para controlar a quais dados eles podem acessar. Veja [Permissões](/l/pt/user-guide/permissions-access/capabilities/permissions) para obter detalhes.
|
||||
</Note>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user