Compare commits
51
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
09daccc3f9 | ||
|
|
484037c179 | ||
|
|
a5982b644c | ||
|
|
4054ede5bb | ||
|
|
af4765effe | ||
|
|
a941f6fe01 | ||
|
|
fc53f18a9f | ||
|
|
ddaba26abe | ||
|
|
42975a4168 | ||
|
|
dbc033b29b | ||
|
|
72f857fc10 | ||
|
|
a47e1e0e5e | ||
|
|
0d5617d446 | ||
|
|
61683d8bda | ||
|
|
ab705b14d7 | ||
|
|
90537b3b88 | ||
|
|
a754a95d38 | ||
|
|
8dd0aa46e3 | ||
|
|
91b2390ee8 | ||
|
|
b36345a699 | ||
|
|
34d9fcaba1 | ||
|
|
8edc76d3d0 | ||
|
|
7fa136f305 | ||
|
|
04eb913551 | ||
|
|
6dd1e8a471 | ||
|
|
d81756f2e8 | ||
|
|
49b9660420 | ||
|
|
2a9fef2341 | ||
|
|
0dc8426727 | ||
|
|
e16977f97b | ||
|
|
8bc21ec434 | ||
|
|
915ce37d20 | ||
|
|
0cc2194399 | ||
|
|
70a3b25680 | ||
|
|
6a9509ec01 | ||
|
|
fcd2d586ee | ||
|
|
695a374efd | ||
|
|
dea1f89904 | ||
|
|
59b993bdb3 | ||
|
|
e0b4c9918b | ||
|
|
aec2e01662 | ||
|
|
aecfe699f4 | ||
|
|
068fc9363d | ||
|
|
99a5a038bc | ||
|
|
3d90b3882b | ||
|
|
643ec121a7 | ||
|
|
27fd124c2e | ||
|
|
bbc55193f5 | ||
|
|
ac653182b2 | ||
|
|
a159a68e2c | ||
|
|
38d9eacff8 |
@@ -109,7 +109,7 @@ jobs:
|
||||
create-twenty-app --version
|
||||
mkdir -p /tmp/e2e-test-workspace
|
||||
cd /tmp/e2e-test-workspace
|
||||
create-twenty-app test-app --example hello-world --display-name "Test hello-world app" --description "E2E test hello-world app" --skip-local-instance
|
||||
create-twenty-app test-app --example hello-world --display-name "Test hello-world app" --description "E2E test hello-world app" --api-url http://localhost:3000
|
||||
|
||||
- name: Install scaffolded app dependencies
|
||||
run: |
|
||||
|
||||
@@ -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 --yes
|
||||
create-twenty-app test-app --display-name "Test scaffolded app" --description "E2E test scaffolded app" --api-url http://localhost:3000
|
||||
|
||||
- name: Install scaffolded app dependencies
|
||||
run: |
|
||||
|
||||
@@ -107,7 +107,7 @@ jobs:
|
||||
create-twenty-app --version
|
||||
mkdir -p /tmp/e2e-test-workspace
|
||||
cd /tmp/e2e-test-workspace
|
||||
create-twenty-app test-app --example postcard --display-name "Test postcard app" --description "E2E test postcard app" --skip-local-instance
|
||||
create-twenty-app test-app --example postcard --display-name "Test postcard app" --description "E2E test postcard app" --api-url http://localhost:3000
|
||||
|
||||
- name: Install scaffolded app dependencies
|
||||
run: |
|
||||
|
||||
@@ -51,6 +51,7 @@ jobs:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
issues: write
|
||||
id-token: write
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16
|
||||
@@ -123,6 +124,7 @@ jobs:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
issues: write
|
||||
id-token: write
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16
|
||||
|
||||
Vendored
+40
@@ -43,6 +43,46 @@
|
||||
{
|
||||
"name": "packages/twenty-e2e-testing",
|
||||
"path": "../packages/twenty-e2e-testing"
|
||||
},
|
||||
{
|
||||
"name": "packages/twenty-docs",
|
||||
"path": "../packages/twenty-docs"
|
||||
},
|
||||
{
|
||||
"name": "packages/create-twenty-app",
|
||||
"path": "../packages/create-twenty-app"
|
||||
},
|
||||
{
|
||||
"name": "packages/twenty-apps",
|
||||
"path": "../packages/twenty-apps"
|
||||
},
|
||||
{
|
||||
"name": "packages/twenty-claude-skills",
|
||||
"path": "../packages/twenty-claude-skills"
|
||||
},
|
||||
{
|
||||
"name": "packages/twenty-cli",
|
||||
"path": "../packages/twenty-cli"
|
||||
},
|
||||
{
|
||||
"name": "packages/twenty-client-sdk",
|
||||
"path": "../packages/twenty-client-sdk"
|
||||
},
|
||||
{
|
||||
"name": "packages/twenty-companion",
|
||||
"path": "../packages/twenty-companion"
|
||||
},
|
||||
{
|
||||
"name": "packages/twenty-front-component-renderer",
|
||||
"path": "../packages/twenty-front-component-renderer"
|
||||
},
|
||||
{
|
||||
"name": "packages/twenty-sdk",
|
||||
"path": "../packages/twenty-sdk"
|
||||
},
|
||||
{
|
||||
"name": "packages/twenty-website-new",
|
||||
"path": "../packages/twenty-website-new"
|
||||
}
|
||||
],
|
||||
"settings": {
|
||||
|
||||
+3
-1
@@ -4,8 +4,10 @@ enableHardenedMode: true
|
||||
|
||||
enableInlineHunks: true
|
||||
|
||||
enableScripts: false
|
||||
|
||||
nodeLinker: node-modules
|
||||
|
||||
npmMinimalAgeGate: "3d"
|
||||
npmMinimalAgeGate: 3d
|
||||
|
||||
yarnPath: .yarn/releases/yarn-4.13.0.cjs
|
||||
|
||||
@@ -25,18 +25,19 @@ yarn twenty dev
|
||||
The scaffolder will:
|
||||
|
||||
1. Create a new project with TypeScript, linting, tests, and a preconfigured `twenty` CLI
|
||||
2. Optionally start a local Twenty server (Docker)
|
||||
3. Open the browser for OAuth authentication
|
||||
2. Start a local Twenty server via Docker (pulls the latest image automatically)
|
||||
3. Authenticate with the development API key
|
||||
|
||||
## Options
|
||||
|
||||
| Flag | Description |
|
||||
| ------------------------------ | --------------------------------------- |
|
||||
| `--example <name>` | Initialize from an example |
|
||||
| `--name <name>` | Set the app name (skips the prompt) |
|
||||
| `--display-name <displayName>` | Set the display name (skips the prompt) |
|
||||
| `--description <description>` | Set the description (skips the prompt) |
|
||||
| `--skip-local-instance` | Skip the local server setup prompt |
|
||||
| Flag | Description |
|
||||
| ---------------------------------- | --------------------------------------------------------------------- |
|
||||
| `--example <name>` | Initialize from an example |
|
||||
| `--name <name>` | Set the app name |
|
||||
| `--display-name <displayName>` | Set the display name |
|
||||
| `--description <description>` | Set the description |
|
||||
| `--api-url <url>` | Twenty instance URL (default: `http://localhost:2020`) |
|
||||
| `--authentication-method <method>` | `oauth` or `apiKey` (default: `apiKey` for local, `oauth` for remote) |
|
||||
|
||||
By default (no flags), a minimal app is generated with core files and an integration test. Use `--example` to start from a richer example:
|
||||
|
||||
@@ -57,7 +58,7 @@ Full documentation is available at **[docs.twenty.com/developers/extend/apps](ht
|
||||
## Troubleshooting
|
||||
|
||||
- Server not starting: check Docker is running (`docker info`), then try `yarn twenty server logs`.
|
||||
- Auth not working: make sure you are logged in to Twenty in the browser, then run `yarn twenty remote add`.
|
||||
- Auth not working: run `yarn twenty remote add --local` to re-authenticate.
|
||||
- Types not generated: ensure `yarn twenty dev` is running — it auto-generates the typed client.
|
||||
|
||||
## Contributing
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "create-twenty-app",
|
||||
"version": "2.4.0",
|
||||
"version": "2.4.2",
|
||||
"description": "Command-line interface to create Twenty application",
|
||||
"main": "dist/cli.cjs",
|
||||
"bin": "dist/cli.cjs",
|
||||
@@ -32,7 +32,6 @@
|
||||
"chalk": "^5.3.0",
|
||||
"commander": "^12.0.0",
|
||||
"fs-extra": "^11.2.0",
|
||||
"inquirer": "^10.0.0",
|
||||
"lodash.camelcase": "^4.3.0",
|
||||
"lodash.kebabcase": "^4.1.1",
|
||||
"lodash.startcase": "^4.4.0",
|
||||
@@ -43,7 +42,6 @@
|
||||
"@swc/core": "^1.15.11",
|
||||
"@swc/jest": "^0.2.39",
|
||||
"@types/fs-extra": "^11.0.0",
|
||||
"@types/inquirer": "^9.0.0",
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/lodash.camelcase": "^4.3.7",
|
||||
"@types/lodash.kebabcase": "^4.1.7",
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
#!/usr/bin/env node
|
||||
import chalk from 'chalk';
|
||||
import { Command, CommanderError } from 'commander';
|
||||
import { CreateAppCommand } from '@/create-app.command';
|
||||
import {
|
||||
type AuthenticationMethod,
|
||||
CreateAppCommand,
|
||||
} from '@/create-app.command';
|
||||
import packageJson from '../package.json';
|
||||
|
||||
const program = new Command(packageJson.name)
|
||||
@@ -13,20 +16,17 @@ const program = new Command(packageJson.name)
|
||||
)
|
||||
.argument('[directory]')
|
||||
.option('--example <name>', 'Initialize from an example')
|
||||
.option('-n, --name <name>', 'Application name (skips prompt)')
|
||||
.option('-n, --name <name>', 'Application name')
|
||||
.option('-d, --display-name <displayName>', 'Application display name')
|
||||
.option('--description <description>', 'Application description')
|
||||
.option(
|
||||
'-d, --display-name <displayName>',
|
||||
'Application display name (skips prompt)',
|
||||
'--api-url <apiUrl>',
|
||||
'Twenty instance URL (default: http://localhost:2020)',
|
||||
)
|
||||
.option(
|
||||
'--description <description>',
|
||||
'Application description (skips prompt)',
|
||||
'--authentication-method <method>',
|
||||
'Authentication method: oauth or apiKey (default: apiKey for local, oauth for remote)',
|
||||
)
|
||||
.option(
|
||||
'--skip-local-instance',
|
||||
'Skip the local Twenty instance setup prompt',
|
||||
)
|
||||
.option('-y, --yes', 'Auto-confirm prompts (e.g. start existing container)')
|
||||
.helpOption('-h, --help', 'Display this help message.')
|
||||
.action(
|
||||
async (
|
||||
@@ -36,8 +36,8 @@ const program = new Command(packageJson.name)
|
||||
name?: string;
|
||||
displayName?: string;
|
||||
description?: string;
|
||||
skipLocalInstance?: boolean;
|
||||
yes?: boolean;
|
||||
apiUrl?: string;
|
||||
authenticationMethod?: AuthenticationMethod;
|
||||
},
|
||||
) => {
|
||||
if (directory && !/^[a-z0-9-]+$/.test(directory)) {
|
||||
@@ -54,14 +54,26 @@ const program = new Command(packageJson.name)
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (
|
||||
options?.authenticationMethod &&
|
||||
!['oauth', 'apiKey'].includes(options.authenticationMethod)
|
||||
) {
|
||||
console.error(
|
||||
chalk.red(
|
||||
'Error: --authentication-method must be "oauth" or "apiKey".',
|
||||
),
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
await new CreateAppCommand().execute({
|
||||
directory,
|
||||
example: options?.example,
|
||||
name: options?.name,
|
||||
displayName: options?.displayName,
|
||||
description: options?.description,
|
||||
skipLocalInstance: options?.skipLocalInstance,
|
||||
yes: options?.yes,
|
||||
apiUrl: options?.apiUrl,
|
||||
authenticationMethod: options?.authenticationMethod,
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -2,8 +2,19 @@ This is a [Twenty](https://twenty.com) application bootstrapped with [`create-tw
|
||||
|
||||
## Getting Started
|
||||
|
||||
This app was scaffolded with a local Twenty server running at [http://localhost:2020](http://localhost:2020).
|
||||
|
||||
Login with the default development credentials: `[email protected]` / `[email protected]`.
|
||||
|
||||
Run `yarn twenty help` to list all available commands.
|
||||
|
||||
## Useful Commands
|
||||
|
||||
- `yarn twenty dev` - Start the development server and sync your app
|
||||
- `yarn twenty server status` - Check the local Twenty server status
|
||||
- `yarn twenty server start` - Start the local Twenty server
|
||||
- `yarn test` - Run integration tests
|
||||
|
||||
## Learn More
|
||||
|
||||
- [Twenty Apps documentation](https://docs.twenty.com/developers/extend/apps/getting-started/quick-start)
|
||||
|
||||
@@ -11,7 +11,7 @@ permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
TWENTY_DEPLOY_URL: http://localhost:3000
|
||||
TWENTY_DEPLOY_URL: http://localhost:2020
|
||||
|
||||
concurrency:
|
||||
group: cd-${{ github.ref }}
|
||||
|
||||
@@ -5,21 +5,29 @@ import { install } from '@/utils/install';
|
||||
import { tryGitInit } from '@/utils/try-git-init';
|
||||
import chalk from 'chalk';
|
||||
import * as fs from 'fs-extra';
|
||||
import inquirer from 'inquirer';
|
||||
import kebabCase from 'lodash.kebabcase';
|
||||
import * as path from 'path';
|
||||
import { basename } from 'path';
|
||||
import { spawn } from 'node:child_process';
|
||||
import {
|
||||
authLogin,
|
||||
authLoginOAuth,
|
||||
checkDockerRunning,
|
||||
ConfigService,
|
||||
containerExists,
|
||||
detectLocalServer,
|
||||
DEV_API_KEY,
|
||||
DEV_API_URL,
|
||||
serverStart,
|
||||
} from 'twenty-sdk/cli';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import {
|
||||
getDockerInstallInstructions,
|
||||
isDockerInstalled,
|
||||
} from '@/utils/docker-install';
|
||||
|
||||
const CURRENT_EXECUTION_DIRECTORY = process.env.INIT_CWD || process.cwd();
|
||||
const IMAGE = 'twentycrm/twenty-app-dev:latest';
|
||||
|
||||
export type AuthenticationMethod = 'oauth' | 'apiKey';
|
||||
|
||||
type CreateAppOptions = {
|
||||
directory?: string;
|
||||
@@ -27,40 +35,62 @@ type CreateAppOptions = {
|
||||
name?: string;
|
||||
displayName?: string;
|
||||
description?: string;
|
||||
skipLocalInstance?: boolean;
|
||||
yes?: boolean;
|
||||
apiUrl?: string;
|
||||
authenticationMethod?: AuthenticationMethod;
|
||||
};
|
||||
|
||||
export class CreateAppCommand {
|
||||
private static TOTAL_STEPS = 4;
|
||||
private stepCounter = 0;
|
||||
private totalSteps = 0;
|
||||
|
||||
async execute(options: CreateAppOptions = {}): Promise<void> {
|
||||
const { appName, appDisplayName, appDirectory, appDescription } =
|
||||
await this.getAppInfos(options);
|
||||
this.getAppInfos(options);
|
||||
|
||||
const apiUrl = options.apiUrl ?? DEV_API_URL;
|
||||
|
||||
const skipLocalInstance = apiUrl !== DEV_API_URL;
|
||||
|
||||
if (!skipLocalInstance && !isDockerInstalled()) {
|
||||
console.log(chalk.yellow('\n' + getDockerInstallInstructions() + '\n'));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (skipLocalInstance && options.authenticationMethod === 'apiKey') {
|
||||
console.log(
|
||||
chalk.yellow(
|
||||
'API key authentication is only supported on a local Docker instance. Ignoring and switching to OAuth authentication.',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
const authenticationMethod = skipLocalInstance
|
||||
? 'oauth'
|
||||
: (options.authenticationMethod ?? 'apiKey');
|
||||
|
||||
try {
|
||||
await this.validateDirectory(appDirectory);
|
||||
|
||||
const confirmed = await this.promptScaffoldConfirmation({
|
||||
appName,
|
||||
appDisplayName,
|
||||
appDescription,
|
||||
appDirectory,
|
||||
autoConfirm: options.yes,
|
||||
this.totalSteps = this.computeTotalSteps({
|
||||
skipLocalInstance,
|
||||
});
|
||||
|
||||
if (!confirmed) {
|
||||
console.log(chalk.gray('\nScaffolding cancelled.'));
|
||||
process.exit(0);
|
||||
}
|
||||
this.stepCounter = 0;
|
||||
|
||||
console.log('');
|
||||
const dockerPullPromise =
|
||||
!skipLocalInstance && checkDockerRunning()
|
||||
? this.pullImageInBackground()
|
||||
: Promise.resolve(false);
|
||||
|
||||
this.logPlan({ appName, appDisplayName, appDescription, appDirectory });
|
||||
|
||||
this.logNextStep('Creating project directory');
|
||||
|
||||
this.logStep(1, 'Creating project directory');
|
||||
await fs.ensureDir(appDirectory);
|
||||
|
||||
this.logDetail(appDirectory);
|
||||
|
||||
this.logStep(2, 'Scaffolding project files');
|
||||
this.logNextStep('Scaffolding project files');
|
||||
|
||||
if (options.example) {
|
||||
const exampleSucceeded = await this.tryDownloadExample(
|
||||
@@ -87,10 +117,12 @@ export class CreateAppCommand {
|
||||
});
|
||||
}
|
||||
|
||||
this.logStep(3, 'Installing dependencies');
|
||||
this.logNextStep('Installing dependencies');
|
||||
|
||||
await install(appDirectory, (message) => this.logDetail(message));
|
||||
|
||||
this.logStep(4, 'Initializing Git repository');
|
||||
this.logNextStep('Initializing Git repository');
|
||||
|
||||
const gitInitialized = await tryGitInit(appDirectory);
|
||||
|
||||
if (gitInitialized) {
|
||||
@@ -104,38 +136,29 @@ export class CreateAppCommand {
|
||||
|
||||
console.log('');
|
||||
|
||||
let hasLocalServer = false;
|
||||
let authSucceeded = false;
|
||||
let resolvedApiUrl = apiUrl;
|
||||
let serverReady = skipLocalInstance;
|
||||
|
||||
if (!options.skipLocalInstance) {
|
||||
const existingServerUrl = await detectLocalServer();
|
||||
if (!skipLocalInstance) {
|
||||
this.logNextStep('Starting Twenty server');
|
||||
const serverResult = await this.ensureDockerServer(dockerPullPromise);
|
||||
|
||||
if (existingServerUrl) {
|
||||
hasLocalServer = true;
|
||||
authSucceeded = await this.promptConnectToLocal(existingServerUrl);
|
||||
} else {
|
||||
const shouldStart = await this.shouldStartServer(options.yes);
|
||||
|
||||
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 {
|
||||
this.logServerSkipped();
|
||||
}
|
||||
if (isDefined(serverResult.url)) {
|
||||
resolvedApiUrl = serverResult.url;
|
||||
serverReady = true;
|
||||
}
|
||||
}
|
||||
|
||||
this.logSuccess(appDirectory, hasLocalServer, authSucceeded);
|
||||
if (serverReady && authenticationMethod === 'oauth') {
|
||||
this.logNextStep('Authenticating via OAuth');
|
||||
authSucceeded = await this.authenticateWithOAuth(resolvedApiUrl);
|
||||
} else if (serverReady && authenticationMethod === 'apiKey') {
|
||||
this.logNextStep('Authenticating via API key');
|
||||
authSucceeded = await this.authenticateWithDevKey(resolvedApiUrl);
|
||||
}
|
||||
|
||||
this.logSuccess(appDirectory, resolvedApiUrl, authSucceeded);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
chalk.red('\nCreate application failed:'),
|
||||
@@ -145,66 +168,42 @@ export class CreateAppCommand {
|
||||
}
|
||||
}
|
||||
|
||||
private async getAppInfos(options: CreateAppOptions): Promise<{
|
||||
private computeTotalSteps({
|
||||
skipLocalInstance,
|
||||
}: {
|
||||
skipLocalInstance: boolean;
|
||||
}): number {
|
||||
let steps = 4; // directory, scaffold, install, git
|
||||
|
||||
if (!skipLocalInstance) {
|
||||
steps += 1; // start server
|
||||
}
|
||||
|
||||
steps += 1; // authenticate (oauth or apiKey)
|
||||
|
||||
return steps;
|
||||
}
|
||||
|
||||
private getAppInfos(options: CreateAppOptions): {
|
||||
appName: string;
|
||||
appDisplayName: string;
|
||||
appDescription: string;
|
||||
appDirectory: string;
|
||||
}> {
|
||||
const { directory } = options;
|
||||
|
||||
const hasName = isDefined(options.name) || isDefined(directory);
|
||||
const hasDisplayName = isDefined(options.displayName);
|
||||
const hasDescription = isDefined(options.description);
|
||||
const hasExample = isDefined(options.example);
|
||||
|
||||
const { name, displayName, description } = await inquirer.prompt([
|
||||
{
|
||||
type: 'input',
|
||||
name: 'name',
|
||||
message: 'Application name:',
|
||||
when: () => !hasName && !hasExample,
|
||||
default: 'my-twenty-app',
|
||||
validate: (input) => {
|
||||
if (input.length === 0) return 'Application name is required';
|
||||
return true;
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
name: 'displayName',
|
||||
message: 'Application display name:',
|
||||
when: () => !hasDisplayName && !hasExample,
|
||||
default: (answers: { name?: string }) => {
|
||||
return convertToLabel(
|
||||
answers?.name ?? options.name ?? directory ?? '',
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
name: 'description',
|
||||
message: 'Application description (optional):',
|
||||
when: () => !hasDescription && !hasExample,
|
||||
default: '',
|
||||
},
|
||||
]);
|
||||
|
||||
} {
|
||||
const appName = (
|
||||
options.name ??
|
||||
name ??
|
||||
directory ??
|
||||
options.directory ??
|
||||
options.example ??
|
||||
'my-twenty-app'
|
||||
).trim();
|
||||
|
||||
const appDisplayName =
|
||||
(options.displayName ?? displayName)?.trim() || convertToLabel(appName);
|
||||
options.displayName?.trim() || convertToLabel(appName);
|
||||
|
||||
const appDescription = (options.description ?? description ?? '').trim();
|
||||
const appDescription = (options.description ?? '').trim();
|
||||
|
||||
const appDirectory = directory
|
||||
? path.join(CURRENT_EXECUTION_DIRECTORY, directory)
|
||||
const appDirectory = options.directory
|
||||
? path.join(CURRENT_EXECUTION_DIRECTORY, options.directory)
|
||||
: path.join(CURRENT_EXECUTION_DIRECTORY, kebabCase(appName));
|
||||
|
||||
return { appName, appDisplayName, appDirectory, appDescription };
|
||||
@@ -232,45 +231,30 @@ export class CreateAppCommand {
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error(
|
||||
chalk.red(
|
||||
console.log(
|
||||
chalk.yellow(
|
||||
`\n${error instanceof Error ? error.message : 'Failed to download example.'}`,
|
||||
),
|
||||
);
|
||||
this.logDetail('Falling back to default template...');
|
||||
|
||||
const { useTemplate } = await inquirer.prompt([
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'useTemplate',
|
||||
message: 'Would you like to create a default template app instead?',
|
||||
default: true,
|
||||
},
|
||||
]);
|
||||
|
||||
if (!useTemplate) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Clean up any partial files from the failed download
|
||||
await fs.emptyDir(appDirectory);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private async promptScaffoldConfirmation({
|
||||
private logPlan({
|
||||
appName,
|
||||
appDisplayName,
|
||||
appDescription,
|
||||
appDirectory,
|
||||
autoConfirm,
|
||||
}: {
|
||||
appName: string;
|
||||
appDisplayName: string;
|
||||
appDescription: string;
|
||||
appDirectory: string;
|
||||
autoConfirm?: boolean;
|
||||
}): Promise<boolean> {
|
||||
}): void {
|
||||
console.log(chalk.blue('\nCreating Twenty Application\n'));
|
||||
console.log(chalk.white(` Name: ${appName}`));
|
||||
console.log(chalk.white(` Display name: ${appDisplayName}`));
|
||||
@@ -280,43 +264,13 @@ export class CreateAppCommand {
|
||||
}
|
||||
|
||||
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.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 {
|
||||
private logNextStep(title: string): void {
|
||||
this.stepCounter++;
|
||||
console.log(
|
||||
chalk.blue(`\n[${step}/${CreateAppCommand.TOTAL_STEPS}]`) +
|
||||
chalk.blue(`\n[${this.stepCounter}/${this.totalSteps}]`) +
|
||||
chalk.white(` ${title}...`),
|
||||
);
|
||||
}
|
||||
@@ -325,100 +279,57 @@ export class CreateAppCommand {
|
||||
console.log(chalk.gray(` → ${message}`));
|
||||
}
|
||||
|
||||
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',
|
||||
),
|
||||
);
|
||||
private pullImageInBackground(): Promise<boolean> {
|
||||
return new Promise((resolve) => {
|
||||
const child = spawn('docker', ['pull', IMAGE], { stdio: 'ignore' });
|
||||
|
||||
if (checkDockerRunning() && containerExists()) {
|
||||
if (autoConfirm) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const { startExisting } = await inquirer.prompt([
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'startExisting',
|
||||
message:
|
||||
'An existing Twenty server container was found. Would you like to start it?',
|
||||
default: true,
|
||||
},
|
||||
]);
|
||||
|
||||
return startExisting;
|
||||
}
|
||||
|
||||
if (autoConfirm) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const { startDocker } = await inquirer.prompt([
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'startDocker',
|
||||
message:
|
||||
'No running Twenty instance found. Would you like to start one using Docker?',
|
||||
default: true,
|
||||
},
|
||||
]);
|
||||
|
||||
return startDocker;
|
||||
child.on('close', (code) => resolve(code === 0));
|
||||
child.on('error', () => resolve(false));
|
||||
});
|
||||
}
|
||||
|
||||
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: `Authenticate to the local Twenty instance (${serverUrl})?`,
|
||||
default: true,
|
||||
},
|
||||
]);
|
||||
|
||||
if (!shouldAuthenticate) {
|
||||
private async ensureDockerServer(
|
||||
dockerPullPromise: Promise<boolean>,
|
||||
): Promise<{ url?: string }> {
|
||||
if (!checkDockerRunning()) {
|
||||
console.log(
|
||||
chalk.gray(
|
||||
'\n Authentication skipped. To authenticate later:\n' +
|
||||
` yarn twenty remote add --local\n`,
|
||||
chalk.yellow(
|
||||
'\n Docker is installed but not running.\n' +
|
||||
' Please start Docker and run this command again.\n',
|
||||
),
|
||||
);
|
||||
|
||||
return false;
|
||||
return {};
|
||||
}
|
||||
|
||||
await inquirer.prompt([
|
||||
{
|
||||
type: 'input',
|
||||
name: 'confirm',
|
||||
message: 'Press Enter to open the browser for authentication...',
|
||||
},
|
||||
]);
|
||||
this.logDetail('Ensuring latest Twenty server image...');
|
||||
|
||||
const pullSucceeded = await dockerPullPromise;
|
||||
|
||||
if (!pullSucceeded) {
|
||||
this.logDetail(
|
||||
'Image pull failed, continuing with cached image if available...',
|
||||
);
|
||||
}
|
||||
|
||||
const startResult = await serverStart({
|
||||
onProgress: (message: string) => this.logDetail(message),
|
||||
});
|
||||
|
||||
if (startResult.success) {
|
||||
return { url: startResult.data.url };
|
||||
}
|
||||
|
||||
console.log(chalk.yellow(`\n ${startResult.error.message}`));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
private async authenticateWithDevKey(apiUrl: string): Promise<boolean> {
|
||||
try {
|
||||
const result = await authLoginOAuth({
|
||||
apiUrl: serverUrl,
|
||||
const result = await authLogin({
|
||||
apiKey: DEV_API_KEY,
|
||||
apiUrl,
|
||||
remote: 'local',
|
||||
});
|
||||
|
||||
@@ -426,21 +337,68 @@ export class CreateAppCommand {
|
||||
const configService = new ConfigService();
|
||||
|
||||
await configService.setDefaultRemote('local');
|
||||
this.logDetail('Authenticated as [email protected] (development API key)');
|
||||
|
||||
return true;
|
||||
} else {
|
||||
console.log(
|
||||
chalk.yellow(
|
||||
'Authentication failed. Run `yarn twenty remote add --local` manually.',
|
||||
),
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log(
|
||||
chalk.yellow(
|
||||
' Authentication failed. Run `yarn twenty remote add --local` manually.',
|
||||
),
|
||||
);
|
||||
|
||||
return false;
|
||||
} catch {
|
||||
console.log(
|
||||
chalk.yellow(
|
||||
'Authentication failed. Run `yarn twenty remote add` manually.',
|
||||
' Authentication failed. Run `yarn twenty remote add --local` manually.',
|
||||
),
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private deriveRemoteName(url: string): string {
|
||||
try {
|
||||
return new URL(url).hostname.replace(/\./g, '-');
|
||||
} catch {
|
||||
return 'remote';
|
||||
}
|
||||
}
|
||||
|
||||
private async authenticateWithOAuth(apiUrl: string): Promise<boolean> {
|
||||
try {
|
||||
const remoteName = this.deriveRemoteName(apiUrl);
|
||||
|
||||
ConfigService.setActiveRemote(remoteName);
|
||||
|
||||
this.logDetail('Opening browser for OAuth...');
|
||||
|
||||
const result = await authLoginOAuth({ apiUrl });
|
||||
|
||||
if (result.success) {
|
||||
const configService = new ConfigService();
|
||||
|
||||
await configService.setDefaultRemote(remoteName);
|
||||
this.logDetail(`Authenticated via OAuth to ${apiUrl}`);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
console.log(
|
||||
chalk.yellow(
|
||||
` OAuth failed: ${result.error.message}\n` +
|
||||
` Run \`yarn twenty remote add --api-url ${apiUrl}\` manually.`,
|
||||
),
|
||||
);
|
||||
|
||||
return false;
|
||||
} catch {
|
||||
console.log(
|
||||
chalk.yellow(
|
||||
` Authentication failed. Run \`yarn twenty remote add --api-url ${apiUrl}\` manually.`,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -450,12 +408,13 @@ export class CreateAppCommand {
|
||||
|
||||
private logSuccess(
|
||||
appDirectory: string,
|
||||
hasLocalServer: boolean,
|
||||
apiUrl: string,
|
||||
authSucceeded: boolean,
|
||||
): void {
|
||||
const dirName = basename(appDirectory);
|
||||
|
||||
console.log(chalk.green('\n✔ Application created successfully!\n'));
|
||||
|
||||
console.log(chalk.white(' Next steps:\n'));
|
||||
|
||||
let stepNumber = 1;
|
||||
@@ -465,17 +424,21 @@ export class CreateAppCommand {
|
||||
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`));
|
||||
console.log(
|
||||
chalk.cyan(
|
||||
' yarn twenty remote add --api-url <your-instance-url>\n',
|
||||
),
|
||||
);
|
||||
stepNumber++;
|
||||
}
|
||||
|
||||
console.log(chalk.white(` ${stepNumber}. Start developing`));
|
||||
console.log(chalk.cyan(' yarn twenty dev\n'));
|
||||
stepNumber++;
|
||||
|
||||
console.log(chalk.white(` ${stepNumber}. Open your twenty instance`));
|
||||
console.log(chalk.cyan(` ${apiUrl}\n`));
|
||||
|
||||
console.log(
|
||||
chalk.gray(
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import { execSync } from 'node:child_process';
|
||||
|
||||
const DOCKER_DOWNLOAD_URLS: Record<string, string> = {
|
||||
darwin: 'https://docs.docker.com/desktop/setup/install/mac-install/',
|
||||
win32: 'https://docs.docker.com/desktop/setup/install/windows-install/',
|
||||
linux: 'https://docs.docker.com/engine/install/',
|
||||
};
|
||||
|
||||
export const isDockerInstalled = (): boolean => {
|
||||
try {
|
||||
execSync('docker --version', { stdio: 'ignore' });
|
||||
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export const getDockerInstallInstructions = (): string => {
|
||||
const url =
|
||||
DOCKER_DOWNLOAD_URLS[process.platform] ?? DOCKER_DOWNLOAD_URLS.linux;
|
||||
|
||||
return [
|
||||
' Docker is required but not installed.',
|
||||
'',
|
||||
` Install Docker: ${url}`,
|
||||
'',
|
||||
' Then run this command again.',
|
||||
'',
|
||||
' Alternatively, connect to an existing Twenty instance:',
|
||||
' npx create-twenty-app@latest my-twenty-app --api-url <your-instance-url>',
|
||||
].join('\n');
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
||||
"plugins": ["typescript"],
|
||||
"categories": {
|
||||
"correctness": "off"
|
||||
},
|
||||
"ignorePatterns": ["node_modules", "dist"],
|
||||
"rules": {
|
||||
"no-unused-vars": "off",
|
||||
"typescript/no-unused-vars": [
|
||||
"warn",
|
||||
{
|
||||
"argsIgnorePattern": "^_"
|
||||
}
|
||||
],
|
||||
"typescript/no-explicit-any": "off"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
# Discord for Twenty
|
||||
|
||||
Connect Discord to your Twenty workflows. Post messages, edit them, react,
|
||||
delete, and browse channels — all from the workflow builder or the AI chat.
|
||||
|
||||
## What you can do
|
||||
|
||||
Once installed and the admin has provided the bot token, five tools become
|
||||
available in workflows and the AI chat:
|
||||
|
||||
- **Send Discord message** — *"post 'New deal closed 🎉' to #general"*. As a
|
||||
workflow step: provide `channelId` + `messageText`. Optional
|
||||
`replyToMessageId` turns it into a reply to a previous message.
|
||||
- **Update Discord message** — edit a message the bot already sent. Useful
|
||||
for status messages that change as a workflow progresses.
|
||||
- **Delete Discord message** — remove a bot message (for example after a
|
||||
mistake or when a workflow is cancelled).
|
||||
- **Add Discord reaction** — react with a unicode emoji (`👍`, `✅`, `🎉`)
|
||||
or a custom server emoji (`partyparrot:643452342342342342`). Great for
|
||||
signalling status at a glance.
|
||||
- **List Discord channels** — discovers the text-postable channels in a
|
||||
Discord server, useful as the first step in a workflow that picks a
|
||||
channel dynamically. **Leave `guildId` blank if your bot is in only one
|
||||
server — it auto-picks.** If the bot is in multiple servers, the error
|
||||
response lists each server's name and ID so you can copy the right one.
|
||||
|
||||
## Installing
|
||||
|
||||
1. Open **Settings → Applications** in your Twenty workspace.
|
||||
2. Find **Discord** in the available apps and click **Install**.
|
||||
3. Use any of the tools above in a workflow step or via the AI chat.
|
||||
|
||||
> **Heads up:** if you see *"Discord is not configured"* on the first run,
|
||||
> your Twenty admin needs to follow the [Self-hosting setup](#self-hosting-setup-admin-only)
|
||||
> section below — they need to create a Discord application and provide the
|
||||
> bot token before the tools work.
|
||||
|
||||
## Finding channel and message IDs
|
||||
|
||||
Discord IDs are long numeric strings (e.g. `1234567890123456789`). To copy
|
||||
them from the Discord client:
|
||||
|
||||
1. **Enable Developer Mode** once: **User Settings → Advanced → Developer
|
||||
Mode** (toggle on). Discord then shows extra "Copy ID" options on
|
||||
right-click.
|
||||
2. **Channel ID** — right-click any channel → *Copy Channel ID*.
|
||||
3. **Message ID** — right-click any message → *Copy Message ID*.
|
||||
4. **Server (guild) ID** — right-click the server icon → *Copy Server ID*.
|
||||
Only needed for `discord-list-channels` when your bot is in multiple
|
||||
servers (otherwise leave it blank for auto-pick).
|
||||
|
||||
> **Tip:** when chaining steps, pass `messageId` from a previous *Send
|
||||
> Discord message* step directly into a follow-up *Update / Delete / Add
|
||||
> Reaction* step. No copy/paste needed.
|
||||
|
||||
## Limitations
|
||||
|
||||
What this connector intentionally does **not** support in v1:
|
||||
|
||||
- **Direct messages to users.** Discord's DM API needs a different identity
|
||||
flow.
|
||||
- **Threads.** Replying inside a thread or starting a new one isn't exposed.
|
||||
- **Webhooks.** Uses the bot REST API only.
|
||||
- **Slash commands / interactions.** The bot doesn't register or respond to
|
||||
`/commands`.
|
||||
- **Per-workspace identity.** All Twenty workspaces in the same Twenty
|
||||
deployment share the same Discord bot — see
|
||||
[Why bot token instead of OAuth?](#why-bot-token-instead-of-oauth) below.
|
||||
- **2000-character message limit.** Discord rejects longer payloads with
|
||||
HTTP 400.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Symptom | Likely cause | Fix |
|
||||
|---|---|---|
|
||||
| `Discord is not configured` | `DISCORD_BOT_TOKEN` not set | Admin: paste the bot token in Settings → Applications → Discord → **Settings tab** |
|
||||
| `401 Unauthorized` | Token wrong, copied with whitespace, or rotated | Reset the token in the Discord Developer Portal and re-paste |
|
||||
| `Missing Access (50001)` | Bot wasn't invited to that server | Re-run the OAuth invite URL for that server (see admin setup) |
|
||||
| `Missing Permissions (50013)` | Bot is in the server but lacks Send / Manage / React permissions | In Discord: server settings → roles → grant the bot's role the missing permission |
|
||||
| `Unknown Channel (10003)` | `channelId` is wrong, or bot can't see that channel | Verify the ID; check the bot has *View Channel* permission |
|
||||
| `Unknown Message (10008)` | `messageId` is wrong, or message was deleted | Verify the ID is from a still-existing message |
|
||||
| `Cannot edit a message authored by another user (50005)` | Trying to update / delete a message the bot didn't send | The bot can only edit its own messages; it can delete others' messages only with the *Manage Messages* permission |
|
||||
| `Bot is in N Discord servers — please specify which one` (from list-channels) | Bot is in multiple servers and `guildId` was left blank | Copy the server ID from the error message and paste it into the `guildId` field |
|
||||
| `Discord API responded with 429` | Hit Discord's rate limit | Reduce workflow concurrency; this connector doesn't yet auto-retry |
|
||||
|
||||
---
|
||||
|
||||
## Self-hosting setup (admin-only)
|
||||
|
||||
This section is for Twenty server admins. If you're on Twenty Cloud, skip
|
||||
this — the bot credentials are already configured.
|
||||
|
||||
### 1. Create a Discord application
|
||||
|
||||
1. Visit https://discord.com/developers/applications and click
|
||||
**New Application**.
|
||||
2. Name it (e.g. *"Twenty Bot"*) and create. Use a dedicated app — don't
|
||||
reuse one configured for other bots.
|
||||
3. Sidebar → **Bot** tab → **Reset Token** → copy the token immediately
|
||||
(it's only shown once; if you lose it, reset again).
|
||||
4. *Recommended:* toggle **Public Bot** OFF so randoms can't invite the
|
||||
bot to their servers.
|
||||
|
||||
### 2. Generate the invite URL and add the bot to your server(s)
|
||||
|
||||
1. In the Discord Developer Portal: sidebar → **OAuth2** → **URL Generator**.
|
||||
2. **Scopes**: tick `bot`.
|
||||
3. **Bot Permissions**: tick `Send Messages`, `Manage Messages`,
|
||||
`Add Reactions`, `Read Message History`.
|
||||
4. Copy the generated URL.
|
||||
5. Open the URL in your browser, pick the Discord server, authorize.
|
||||
Repeat for each server you want workflows to post in.
|
||||
|
||||
### 3. Wire the bot token into Twenty
|
||||
|
||||
1. In Twenty: **Settings → Applications → Discord → Settings tab**
|
||||
(gear icon).
|
||||
2. Paste the bot token into the `DISCORD_BOT_TOKEN` row. Saves on blur.
|
||||
|
||||
Workspace users can now use the Discord workflow tools immediately — no
|
||||
further per-user configuration needed (which is unique vs Linear / Slack
|
||||
where each user connects their own account).
|
||||
|
||||
---
|
||||
|
||||
## Why bot token instead of OAuth?
|
||||
|
||||
Slack and Linear use OAuth-per-workspace
|
||||
(`defineConnectionProvider({ type: 'oauth' })`) so each Twenty workspace
|
||||
stores its own access token. Discord works differently:
|
||||
|
||||
- Discord's `bot` scope **does** have an OAuth flow, but the `access_token`
|
||||
it returns is a *user* bearer token — useless for bot actions like posting
|
||||
messages. To actually send messages as the bot you need the static
|
||||
**bot token** from the Developer Portal.
|
||||
- That bot token is global to the Discord application (and therefore to
|
||||
the Twenty deployment). Discord deprecated per-install bot tokens years
|
||||
ago.
|
||||
- Webhooks are a separate auth model but only support posting — no edit,
|
||||
delete, or reactions — so they don't cover Slack/Linear parity.
|
||||
|
||||
The result: this connector skips `defineConnectionProvider` entirely and
|
||||
reads `DISCORD_BOT_TOKEN` from an `applicationVariable` set once at
|
||||
deployment scope. See
|
||||
[Discord's OAuth2 docs](https://discord.com/developers/docs/topics/oauth2#bot-users)
|
||||
for the underlying reason bot users authenticate via static tokens.
|
||||
|
||||
---
|
||||
|
||||
## Developers only
|
||||
|
||||
If you're working on this app rather than installing the published version:
|
||||
|
||||
```bash
|
||||
cd packages/twenty-apps/internal/twenty-discord
|
||||
|
||||
# Day-to-day development (publish + install + watch in one):
|
||||
yarn twenty dev
|
||||
|
||||
# Run unit tests:
|
||||
yarn test
|
||||
|
||||
# Lint:
|
||||
yarn lint
|
||||
```
|
||||
|
||||
`twenty dev` is recommended for iteration — it publishes to your local
|
||||
Twenty server, installs the app, and watches for changes in one command.
|
||||
|
||||
The Discord REST API (v10) is called directly via `fetch` — no `discord.js`
|
||||
or other SDK dependency. See
|
||||
`src/logic-functions/utils/discord-api-request.ts` for the auth and
|
||||
error-handling wrapper that all handlers go through.
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "twenty-discord",
|
||||
"version": "0.1.0",
|
||||
"description": "Discord workflow connector for Twenty",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^24.5.0",
|
||||
"npm": "please-use-yarn",
|
||||
"yarn": ">=4.0.2"
|
||||
},
|
||||
"keywords": [
|
||||
"twenty-app"
|
||||
],
|
||||
"packageManager": "[email protected]",
|
||||
"scripts": {
|
||||
"twenty": "twenty",
|
||||
"lint": "oxlint -c .oxlintrc.json .",
|
||||
"lint:fix": "oxlint --fix -c .oxlintrc.json .",
|
||||
"test": "vitest run",
|
||||
"test:watch": "vitest"
|
||||
},
|
||||
"dependencies": {
|
||||
"twenty-sdk": "2.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^24.7.2",
|
||||
"oxlint": "^0.16.0",
|
||||
"typescript": "^5.9.3",
|
||||
"vitest": "^3.1.1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="64"
|
||||
height="64"
|
||||
viewBox="0 0 127 127"
|
||||
fill="none"
|
||||
role="img"
|
||||
>
|
||||
<title>Discord</title>
|
||||
<path
|
||||
fill="#5865F2"
|
||||
d="M107.7 26.4A104.6 104.6 0 0 0 81.6 18a0.4 0.4 0 0 0-0.4 0.2 73 73 0 0 0-3.2 6.6 96.6 96.6 0 0 0-29 0A66.8 66.8 0 0 0 45.6 18.2a0.4 0.4 0 0 0-0.4-0.2 104.2 104.2 0 0 0-26.1 8.4 0.4 0.4 0 0 0-0.2 0.2C2.3 51.4-2.2 75.7 0 99.7a0.4 0.4 0 0 0 0.2 0.3 105.2 105.2 0 0 0 31.6 16 0.4 0.4 0 0 0 0.5-0.1 75.6 75.6 0 0 0 6.5-10.6 0.4 0.4 0 0 0-0.2-0.5 69.4 69.4 0 0 1-9.9-4.7 0.4 0.4 0 0 1 0-0.7 54.6 54.6 0 0 0 2-1.6 0.4 0.4 0 0 1 0.4-0.1 75 75 0 0 0 63.9 0 0.4 0.4 0 0 1 0.4 0.1c0.6 0.6 1.3 1.1 2 1.6a0.4 0.4 0 0 1 0 0.7 65.2 65.2 0 0 1-9.9 4.7 0.4 0.4 0 0 0-0.2 0.5 84.8 84.8 0 0 0 6.5 10.6 0.4 0.4 0 0 0 0.5 0.1 104.8 104.8 0 0 0 31.6-16 0.4 0.4 0 0 0 0.2-0.3c2.7-27.8-4.5-51.9-18.9-73.1a0.4 0.4 0 0 0-0.2-0.2zM42.5 85a12.3 12.3 0 0 1-11.5-12.9c0-7.1 5-12.9 11.5-12.9 6.6 0 11.7 5.8 11.6 12.9 0 7-5.1 12.9-11.6 12.9zm42.8 0a12.3 12.3 0 0 1-11.5-12.9c0-7.1 5-12.9 11.5-12.9 6.6 0 11.6 5.8 11.5 12.9 0 7-5 12.9-11.5 12.9z"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,30 @@
|
||||
import { defineApplication } from 'twenty-sdk/define';
|
||||
|
||||
import {
|
||||
APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
DISCORD_BOT_TOKEN_VARIABLE_UNIVERSAL_IDENTIFIER,
|
||||
} from 'src/constants/universal-identifiers';
|
||||
|
||||
export default defineApplication({
|
||||
universalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
displayName: 'Twenty Discord',
|
||||
description:
|
||||
'Connect Discord to Twenty. Workflow steps post, update, and delete bot messages and add reactions using a Discord bot token shared across the deployment.',
|
||||
logoUrl: 'public/twenty-discord.svg',
|
||||
author: 'Twenty',
|
||||
category: 'Communication',
|
||||
aboutDescription:
|
||||
'Official Discord connector for Twenty CRM. Create a Discord application at https://discord.com/developers/applications, copy its bot token into the DISCORD_BOT_TOKEN application variable, then invite the bot to each server you want workflows to post in. Use workflow actions to post, update, or delete bot messages and add reactions.',
|
||||
websiteUrl: 'https://docs.twenty.com/developers/extend/apps/getting-started',
|
||||
termsUrl: 'https://www.twenty.com/terms',
|
||||
emailSupport: '[email protected]',
|
||||
issueReportUrl: 'https://github.com/twentyhq/twenty/issues',
|
||||
applicationVariables: {
|
||||
DISCORD_BOT_TOKEN: {
|
||||
universalIdentifier: DISCORD_BOT_TOKEN_VARIABLE_UNIVERSAL_IDENTIFIER,
|
||||
description:
|
||||
'Bot token from your Discord application (Developer Portal → Bot tab → Reset Token). Used with the `Bot` auth prefix to call the Discord REST API. The same token authenticates the bot across every guild it has been invited to.',
|
||||
isSecret: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
import { defineCommandMenuItem } from 'twenty-sdk/define';
|
||||
|
||||
import {
|
||||
SEND_DISCORD_MESSAGE_COMMAND_UNIVERSAL_IDENTIFIER,
|
||||
SEND_MESSAGE_FORM_FRONT_COMPONENT_UNIVERSAL_IDENTIFIER,
|
||||
} from 'src/constants/universal-identifiers';
|
||||
|
||||
export default defineCommandMenuItem({
|
||||
universalIdentifier: SEND_DISCORD_MESSAGE_COMMAND_UNIVERSAL_IDENTIFIER,
|
||||
label: 'Send Discord message',
|
||||
shortLabel: 'Discord message',
|
||||
icon: 'IconBrandDiscord',
|
||||
isPinned: false,
|
||||
availabilityType: 'GLOBAL',
|
||||
frontComponentUniversalIdentifier:
|
||||
SEND_MESSAGE_FORM_FRONT_COMPONENT_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
+670
@@ -0,0 +1,670 @@
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { defineFrontComponent } from 'twenty-sdk/define';
|
||||
import {
|
||||
closeSidePanel,
|
||||
enqueueSnackbar,
|
||||
unmountFrontComponent,
|
||||
} from 'twenty-sdk/front-component';
|
||||
|
||||
import { SEND_MESSAGE_FORM_FRONT_COMPONENT_UNIVERSAL_IDENTIFIER } from 'src/constants/universal-identifiers';
|
||||
|
||||
type DiscordGuild = {
|
||||
id: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
type DiscordChannel = {
|
||||
id: string;
|
||||
name: string;
|
||||
type: number;
|
||||
parentId: string | null;
|
||||
position: number;
|
||||
};
|
||||
|
||||
const DISCORD_MESSAGE_MAX_LENGTH = 2000;
|
||||
|
||||
// The front component sandbox dispatches events with a non-standard shape.
|
||||
// Values may live on e.detail.value, e.value, or e.target.value.
|
||||
const readSerializedValue = (
|
||||
e: React.SyntheticEvent<HTMLElement>,
|
||||
): string | undefined => {
|
||||
const obj = e as {
|
||||
detail?: { value?: string };
|
||||
value?: string;
|
||||
target?: { value?: string };
|
||||
};
|
||||
|
||||
if (typeof obj.detail?.value === 'string') return obj.detail.value;
|
||||
if (typeof obj.value === 'string') return obj.value;
|
||||
if (typeof obj.target?.value === 'string') return obj.target.value;
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
||||
const onValueChange =
|
||||
(fn: (value: string) => void) => (e: React.SyntheticEvent<HTMLElement>) => {
|
||||
const v = readSerializedValue(e);
|
||||
|
||||
if (typeof v === 'string') fn(v);
|
||||
};
|
||||
|
||||
const callAppRoute = async (
|
||||
path: string,
|
||||
method: 'GET' | 'POST',
|
||||
body?: Record<string, unknown>,
|
||||
) => {
|
||||
const apiBaseUrl = process.env.TWENTY_API_URL;
|
||||
const token =
|
||||
process.env.TWENTY_APP_ACCESS_TOKEN ?? process.env.TWENTY_API_KEY;
|
||||
|
||||
if (!apiBaseUrl || !token) {
|
||||
throw new Error('API configuration missing');
|
||||
}
|
||||
|
||||
const response = await fetch(`${apiBaseUrl}/s${path}`, {
|
||||
method,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
...(body ? { body: JSON.stringify(body) } : {}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const text = await response.text().catch(() => '');
|
||||
|
||||
throw new Error(
|
||||
`Request failed (${response.status}): ${text.slice(0, 200)}`,
|
||||
);
|
||||
}
|
||||
|
||||
return response.json();
|
||||
};
|
||||
|
||||
const COLOR = {
|
||||
bg: '#f1f1f1',
|
||||
card: '#ffffff',
|
||||
surface: '#fcfcfc',
|
||||
border: '#ebebeb',
|
||||
borderStrong: '#d6d6d6',
|
||||
text: '#333333',
|
||||
textSecondary: '#666666',
|
||||
textTertiary: '#999999',
|
||||
placeholder: '#cccccc',
|
||||
accent: '#5865f2',
|
||||
error: '#e05252',
|
||||
};
|
||||
|
||||
const INLINE_SELECT: React.CSSProperties = {
|
||||
appearance: 'none',
|
||||
WebkitAppearance: 'none' as const,
|
||||
border: 'none',
|
||||
background: 'transparent',
|
||||
color: 'inherit',
|
||||
font: 'inherit',
|
||||
cursor: 'pointer',
|
||||
outline: 'none',
|
||||
padding: 0,
|
||||
};
|
||||
|
||||
const STYLES = {
|
||||
outer: {
|
||||
fontFamily: 'Inter, system-ui, -apple-system, sans-serif',
|
||||
fontSize: '13px',
|
||||
backgroundColor: COLOR.bg,
|
||||
padding: '12px',
|
||||
height: '100%',
|
||||
boxSizing: 'border-box' as const,
|
||||
},
|
||||
container: {
|
||||
backgroundColor: COLOR.card,
|
||||
borderRadius: '8px',
|
||||
border: `1px solid ${COLOR.border}`,
|
||||
display: 'flex',
|
||||
flexDirection: 'column' as const,
|
||||
height: '100%',
|
||||
boxSizing: 'border-box' as const,
|
||||
color: COLOR.text,
|
||||
},
|
||||
topBar: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
padding: '8px 12px',
|
||||
borderBottom: `1px solid ${COLOR.border}`,
|
||||
flexShrink: 0,
|
||||
},
|
||||
guildSelect: {
|
||||
appearance: 'none' as const,
|
||||
WebkitAppearance: 'none' as const,
|
||||
background: COLOR.surface,
|
||||
border: `1px solid ${COLOR.border}`,
|
||||
borderRadius: '6px',
|
||||
padding: '3px 8px',
|
||||
color: COLOR.text,
|
||||
fontSize: '12px',
|
||||
fontFamily: 'inherit',
|
||||
cursor: 'pointer',
|
||||
outline: 'none',
|
||||
},
|
||||
channelPicker: {
|
||||
flexShrink: 0,
|
||||
padding: '12px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '6px',
|
||||
borderBottom: `1px solid ${COLOR.border}`,
|
||||
},
|
||||
channelChip: {
|
||||
appearance: 'none' as const,
|
||||
WebkitAppearance: 'none' as const,
|
||||
background: 'transparent',
|
||||
border: `1px solid ${COLOR.border}`,
|
||||
borderRadius: '20px',
|
||||
padding: '3px 9px',
|
||||
color: COLOR.textSecondary,
|
||||
fontSize: '12px',
|
||||
fontFamily: 'inherit',
|
||||
cursor: 'pointer',
|
||||
outline: 'none',
|
||||
display: 'inline-flex' as const,
|
||||
alignItems: 'center',
|
||||
gap: '4px',
|
||||
whiteSpace: 'nowrap' as const,
|
||||
lineHeight: '16px',
|
||||
},
|
||||
chipIcon: {
|
||||
fontSize: '12px',
|
||||
lineHeight: 1,
|
||||
flexShrink: 0,
|
||||
color: COLOR.textTertiary,
|
||||
},
|
||||
optionsLoadingIndicator: {
|
||||
marginLeft: 'auto',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
},
|
||||
spinner: {
|
||||
width: '14px',
|
||||
height: '14px',
|
||||
border: `2px solid ${COLOR.border}`,
|
||||
borderTopColor: COLOR.textSecondary,
|
||||
borderRadius: '50%',
|
||||
animation: 'spin 0.6s linear infinite',
|
||||
},
|
||||
body: {
|
||||
flex: 1,
|
||||
display: 'flex',
|
||||
flexDirection: 'column' as const,
|
||||
padding: '24px',
|
||||
overflow: 'auto',
|
||||
minHeight: 0,
|
||||
gap: '6px',
|
||||
},
|
||||
messageInput: {
|
||||
background: 'transparent',
|
||||
border: 'none',
|
||||
outline: 'none',
|
||||
color: COLOR.text,
|
||||
fontSize: '14px',
|
||||
fontFamily: 'inherit',
|
||||
width: '100%',
|
||||
padding: 0,
|
||||
resize: 'none' as const,
|
||||
flex: 1,
|
||||
minHeight: '120px',
|
||||
},
|
||||
charCount: {
|
||||
fontSize: '11px',
|
||||
textAlign: 'right' as const,
|
||||
color: COLOR.textTertiary,
|
||||
flexShrink: 0,
|
||||
},
|
||||
charCountOverLimit: {
|
||||
color: COLOR.error,
|
||||
},
|
||||
actionBar: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-end',
|
||||
gap: '6px',
|
||||
padding: '6px 12px',
|
||||
borderTop: `1px solid ${COLOR.border}`,
|
||||
flexShrink: 0,
|
||||
},
|
||||
cancelButton: {
|
||||
background: 'transparent',
|
||||
border: 'none',
|
||||
color: COLOR.textSecondary,
|
||||
fontSize: '12px',
|
||||
fontFamily: 'inherit',
|
||||
cursor: 'pointer',
|
||||
padding: '5px 10px',
|
||||
borderRadius: '6px',
|
||||
},
|
||||
sendButton: {
|
||||
background: COLOR.accent,
|
||||
border: 'none',
|
||||
color: '#ffffff',
|
||||
fontSize: '12px',
|
||||
fontWeight: 500,
|
||||
fontFamily: 'inherit',
|
||||
cursor: 'pointer',
|
||||
padding: '5px 14px',
|
||||
borderRadius: '6px',
|
||||
},
|
||||
sendButtonDisabled: {
|
||||
background: COLOR.borderStrong,
|
||||
color: COLOR.textTertiary,
|
||||
cursor: 'not-allowed',
|
||||
},
|
||||
successOuter: {
|
||||
fontFamily: 'Inter, system-ui, -apple-system, sans-serif',
|
||||
backgroundColor: COLOR.bg,
|
||||
padding: '12px',
|
||||
height: '100%',
|
||||
boxSizing: 'border-box' as const,
|
||||
},
|
||||
successContainer: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '10px',
|
||||
padding: '10px 14px',
|
||||
boxSizing: 'border-box' as const,
|
||||
backgroundColor: COLOR.card,
|
||||
borderRadius: '8px',
|
||||
border: `1px solid ${COLOR.border}`,
|
||||
color: COLOR.text,
|
||||
},
|
||||
successCheck: {
|
||||
width: '20px',
|
||||
height: '20px',
|
||||
borderRadius: '50%',
|
||||
backgroundColor: '#2ea043',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
fontSize: '11px',
|
||||
color: '#fff',
|
||||
flexShrink: 0,
|
||||
},
|
||||
successText: {
|
||||
color: COLOR.text,
|
||||
fontWeight: 500,
|
||||
fontSize: '13px',
|
||||
flex: 1,
|
||||
overflow: 'hidden' as const,
|
||||
textOverflow: 'ellipsis' as const,
|
||||
whiteSpace: 'nowrap' as const,
|
||||
},
|
||||
closeButton: {
|
||||
background: 'transparent',
|
||||
border: `1px solid ${COLOR.border}`,
|
||||
color: COLOR.textSecondary,
|
||||
fontSize: '12px',
|
||||
fontFamily: 'inherit',
|
||||
cursor: 'pointer',
|
||||
padding: '5px 14px',
|
||||
borderRadius: '6px',
|
||||
flexShrink: 0,
|
||||
},
|
||||
loadingOuter: {
|
||||
fontFamily: 'Inter, system-ui, -apple-system, sans-serif',
|
||||
backgroundColor: COLOR.bg,
|
||||
padding: '12px',
|
||||
height: '100%',
|
||||
boxSizing: 'border-box' as const,
|
||||
},
|
||||
loadingContainer: {
|
||||
color: COLOR.textSecondary,
|
||||
fontSize: '13px',
|
||||
textAlign: 'center' as const,
|
||||
backgroundColor: COLOR.card,
|
||||
borderRadius: '8px',
|
||||
border: `1px solid ${COLOR.border}`,
|
||||
padding: '24px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
errorOuter: {
|
||||
fontFamily: 'Inter, system-ui, -apple-system, sans-serif',
|
||||
backgroundColor: COLOR.bg,
|
||||
padding: '12px',
|
||||
height: '100%',
|
||||
boxSizing: 'border-box' as const,
|
||||
},
|
||||
errorContainer: {
|
||||
backgroundColor: COLOR.card,
|
||||
borderRadius: '8px',
|
||||
border: `1px solid ${COLOR.border}`,
|
||||
padding: '24px',
|
||||
display: 'flex',
|
||||
flexDirection: 'column' as const,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: '10px',
|
||||
},
|
||||
errorText: {
|
||||
color: COLOR.error,
|
||||
fontSize: '12px',
|
||||
textAlign: 'center' as const,
|
||||
},
|
||||
retryButton: {
|
||||
background: COLOR.surface,
|
||||
border: `1px solid ${COLOR.border}`,
|
||||
color: COLOR.text,
|
||||
fontSize: '12px',
|
||||
fontFamily: 'inherit',
|
||||
cursor: 'pointer',
|
||||
padding: '5px 12px',
|
||||
borderRadius: '6px',
|
||||
},
|
||||
};
|
||||
|
||||
const SendMessageForm = () => {
|
||||
const [guilds, setGuilds] = useState<DiscordGuild[]>([]);
|
||||
const [guildsLoading, setGuildsLoading] = useState(true);
|
||||
const [guildsError, setGuildsError] = useState<string | null>(null);
|
||||
|
||||
const [channels, setChannels] = useState<DiscordChannel[]>([]);
|
||||
const [channelsLoading, setChannelsLoading] = useState(false);
|
||||
|
||||
const [selectedGuildId, setSelectedGuildId] = useState('');
|
||||
const [selectedChannelId, setSelectedChannelId] = useState('');
|
||||
const [messageText, setMessageText] = useState('');
|
||||
|
||||
const [sending, setSending] = useState(false);
|
||||
const [sentChannelName, setSentChannelName] = useState<string | null>(null);
|
||||
const [closing, setClosing] = useState(false);
|
||||
|
||||
const fetchChannels = useCallback(async (guildId: string) => {
|
||||
if (!guildId) {
|
||||
setChannels([]);
|
||||
setSelectedChannelId('');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
setChannelsLoading(true);
|
||||
|
||||
try {
|
||||
const result = await callAppRoute(
|
||||
`/discord/channels?guildId=${encodeURIComponent(guildId)}`,
|
||||
'GET',
|
||||
);
|
||||
|
||||
if (!result.success) {
|
||||
setChannels([]);
|
||||
await enqueueSnackbar({
|
||||
message: result.error ?? 'Failed to load channels',
|
||||
variant: 'error',
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
setChannels(result.channels ?? []);
|
||||
} catch (error) {
|
||||
setChannels([]);
|
||||
await enqueueSnackbar({
|
||||
message:
|
||||
error instanceof Error ? error.message : 'Failed to load channels',
|
||||
variant: 'error',
|
||||
});
|
||||
} finally {
|
||||
setChannelsLoading(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleGuildChange = useCallback(
|
||||
(newGuildId: string) => {
|
||||
setSelectedGuildId(newGuildId);
|
||||
setSelectedChannelId('');
|
||||
fetchChannels(newGuildId);
|
||||
},
|
||||
[fetchChannels],
|
||||
);
|
||||
|
||||
const fetchGuilds = useCallback(async () => {
|
||||
try {
|
||||
setGuildsError(null);
|
||||
const result = await callAppRoute('/discord/guilds', 'GET');
|
||||
|
||||
if (!result.success) {
|
||||
setGuildsError(result.error ?? 'Failed to load Discord servers');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const fetchedGuilds: DiscordGuild[] = result.guilds ?? [];
|
||||
|
||||
setGuilds(fetchedGuilds);
|
||||
|
||||
// Auto-select when the bot is in exactly one server to skip a needless step.
|
||||
if (fetchedGuilds.length === 1) {
|
||||
setSelectedGuildId(fetchedGuilds[0].id);
|
||||
fetchChannels(fetchedGuilds[0].id);
|
||||
}
|
||||
} catch (error) {
|
||||
setGuildsError(
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: 'Failed to load Discord servers',
|
||||
);
|
||||
} finally {
|
||||
setGuildsLoading(false);
|
||||
}
|
||||
}, [fetchChannels]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchGuilds();
|
||||
}, [fetchGuilds]);
|
||||
|
||||
const handleSubmit = async () => {
|
||||
const trimmedMessage = (messageText ?? '').trim();
|
||||
|
||||
if (
|
||||
!selectedGuildId ||
|
||||
!selectedChannelId ||
|
||||
trimmedMessage.length === 0 ||
|
||||
trimmedMessage.length > DISCORD_MESSAGE_MAX_LENGTH
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
setSending(true);
|
||||
|
||||
try {
|
||||
const result = await callAppRoute('/discord/messages', 'POST', {
|
||||
channelId: selectedChannelId,
|
||||
messageText: trimmedMessage,
|
||||
});
|
||||
|
||||
if (!result.success) {
|
||||
await enqueueSnackbar({
|
||||
message: result.error ?? 'Failed to send message',
|
||||
variant: 'error',
|
||||
});
|
||||
setSending(false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const channelName =
|
||||
channels.find((channel) => channel.id === selectedChannelId)?.name ??
|
||||
'channel';
|
||||
|
||||
setSentChannelName(channelName);
|
||||
await enqueueSnackbar({
|
||||
message: `Message sent to #${channelName}`,
|
||||
variant: 'success',
|
||||
});
|
||||
} catch (error) {
|
||||
await enqueueSnackbar({
|
||||
message:
|
||||
error instanceof Error ? error.message : 'Failed to send message',
|
||||
variant: 'error',
|
||||
});
|
||||
setSending(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
setClosing(true);
|
||||
unmountFrontComponent();
|
||||
closeSidePanel();
|
||||
};
|
||||
|
||||
if (closing) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (sentChannelName) {
|
||||
return (
|
||||
<div style={STYLES.successOuter}>
|
||||
<div style={STYLES.successContainer}>
|
||||
<div style={STYLES.successCheck}>{'✓'}</div>
|
||||
<span style={STYLES.successText}>
|
||||
Message sent to #{sentChannelName}
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
style={STYLES.closeButton}
|
||||
onClick={handleCancel}
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (guildsLoading) {
|
||||
return (
|
||||
<div style={STYLES.loadingOuter}>
|
||||
<div style={STYLES.loadingContainer}>Loading...</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (guildsError) {
|
||||
return (
|
||||
<div style={STYLES.errorOuter}>
|
||||
<div style={STYLES.errorContainer}>
|
||||
<p style={STYLES.errorText}>{guildsError}</p>
|
||||
<button
|
||||
type="button"
|
||||
style={STYLES.retryButton}
|
||||
onClick={fetchGuilds}
|
||||
>
|
||||
Retry
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const trimmedLength = (messageText ?? '').trim().length;
|
||||
const isOverLimit = (messageText ?? '').length > DISCORD_MESSAGE_MAX_LENGTH;
|
||||
const canSubmit =
|
||||
!!selectedGuildId &&
|
||||
!!selectedChannelId &&
|
||||
trimmedLength > 0 &&
|
||||
!isOverLimit &&
|
||||
!sending;
|
||||
|
||||
return (
|
||||
<div style={STYLES.outer}>
|
||||
<style>{'@keyframes spin{to{transform:rotate(360deg)}}'}</style>
|
||||
<div style={STYLES.container}>
|
||||
<div style={STYLES.topBar}>
|
||||
<select
|
||||
value={selectedGuildId}
|
||||
onChange={onValueChange(handleGuildChange)}
|
||||
style={STYLES.guildSelect}
|
||||
>
|
||||
<option value="">Select server...</option>
|
||||
{guilds.map((guild) => (
|
||||
<option key={guild.id} value={guild.id}>
|
||||
{guild.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
{channelsLoading && (
|
||||
<div style={STYLES.optionsLoadingIndicator}>
|
||||
<div style={STYLES.spinner} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div style={STYLES.channelPicker}>
|
||||
<label style={STYLES.channelChip}>
|
||||
<span style={STYLES.chipIcon}>{'#'}</span>
|
||||
<select
|
||||
value={selectedChannelId}
|
||||
onChange={onValueChange(setSelectedChannelId)}
|
||||
style={INLINE_SELECT}
|
||||
disabled={!selectedGuildId || channelsLoading}
|
||||
>
|
||||
<option value="">
|
||||
{channels.length === 0 ? 'No channels' : 'Select channel'}
|
||||
</option>
|
||||
{channels.map((channel) => (
|
||||
<option key={channel.id} value={channel.id}>
|
||||
{channel.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div style={STYLES.body}>
|
||||
<textarea
|
||||
value={messageText}
|
||||
onInput={onValueChange(setMessageText)}
|
||||
onChange={onValueChange(setMessageText)}
|
||||
style={STYLES.messageInput}
|
||||
placeholder="Type a message..."
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
...STYLES.charCount,
|
||||
...(isOverLimit ? STYLES.charCountOverLimit : {}),
|
||||
}}
|
||||
>
|
||||
{(messageText ?? '').length} / {DISCORD_MESSAGE_MAX_LENGTH}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={STYLES.actionBar}>
|
||||
<button
|
||||
type="button"
|
||||
style={STYLES.cancelButton}
|
||||
onClick={handleCancel}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
style={{
|
||||
...STYLES.sendButton,
|
||||
...(!canSubmit ? STYLES.sendButtonDisabled : {}),
|
||||
}}
|
||||
disabled={!canSubmit}
|
||||
onClick={handleSubmit}
|
||||
>
|
||||
{sending ? 'Sending...' : 'Send'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: SEND_MESSAGE_FORM_FRONT_COMPONENT_UNIVERSAL_IDENTIFIER,
|
||||
name: 'send-discord-message-form',
|
||||
description:
|
||||
'Form to send a message to a Discord channel: pick the server, pick the channel, type the message, send.',
|
||||
component: SendMessageForm,
|
||||
});
|
||||
@@ -0,0 +1,41 @@
|
||||
export const APPLICATION_UNIVERSAL_IDENTIFIER =
|
||||
'9b1b7628-ac98-4e44-8e1e-91b401378a5f';
|
||||
|
||||
export const DEFAULT_ROLE_UNIVERSAL_IDENTIFIER =
|
||||
'6aa50eb2-e8c2-470f-8c4d-09debbf6e051';
|
||||
|
||||
export const DISCORD_BOT_TOKEN_VARIABLE_UNIVERSAL_IDENTIFIER =
|
||||
'ac986a3b-19a5-4cee-a87a-2f8d3885ad84';
|
||||
|
||||
export const DISCORD_POST_MESSAGE_UNIVERSAL_IDENTIFIER =
|
||||
'6c03d456-c1fa-4acc-9928-d97ced0925fe';
|
||||
|
||||
export const DISCORD_UPDATE_MESSAGE_UNIVERSAL_IDENTIFIER =
|
||||
'b37285d9-cb11-4fe5-963d-0434780122ba';
|
||||
|
||||
export const DISCORD_DELETE_MESSAGE_UNIVERSAL_IDENTIFIER =
|
||||
'a2efc27c-eae0-4713-b327-bdb1aaeff95f';
|
||||
|
||||
export const DISCORD_ADD_REACTION_UNIVERSAL_IDENTIFIER =
|
||||
'32c77c8a-ebd0-4308-aa1b-d21bb94422ac';
|
||||
|
||||
export const DISCORD_LIST_CHANNELS_UNIVERSAL_IDENTIFIER =
|
||||
'ef2296f6-1b48-4edd-81ac-cafa4fe73f99';
|
||||
|
||||
export const DISCORD_LIST_CHANNELS_ROUTE_UNIVERSAL_IDENTIFIER =
|
||||
'550cd993-af6e-46ae-b697-f838f34cfe39';
|
||||
|
||||
export const DISCORD_LIST_GUILDS_UNIVERSAL_IDENTIFIER =
|
||||
'0aaaca4f-3156-4b7c-a9f5-ee6a2e17cbf1';
|
||||
|
||||
export const DISCORD_LIST_GUILDS_ROUTE_UNIVERSAL_IDENTIFIER =
|
||||
'3cfa36d9-3c04-495c-bc09-f8019ad85dce';
|
||||
|
||||
export const DISCORD_POST_MESSAGE_ROUTE_UNIVERSAL_IDENTIFIER =
|
||||
'eda60c95-450b-4a86-b5a0-6b85f488ae81';
|
||||
|
||||
export const SEND_MESSAGE_FORM_FRONT_COMPONENT_UNIVERSAL_IDENTIFIER =
|
||||
'ee8d8efa-2f9d-4d2c-b759-bb3cafc7797d';
|
||||
|
||||
export const SEND_DISCORD_MESSAGE_COMMAND_UNIVERSAL_IDENTIFIER =
|
||||
'8c80b9d8-2f18-4b6c-8933-30d170790685';
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
import { defineLogicFunction } from 'twenty-sdk/define';
|
||||
import { jsonSchemaToInputSchema } from 'twenty-shared/logic-function';
|
||||
|
||||
import { DISCORD_ADD_REACTION_UNIVERSAL_IDENTIFIER } from 'src/constants/universal-identifiers';
|
||||
import { discordAddReactionHandler } from 'src/logic-functions/handlers/discord-add-reaction-handler';
|
||||
import { discordAddReactionInputSchema } from './schemas/discord-add-reaction-input.schema';
|
||||
|
||||
export default defineLogicFunction({
|
||||
universalIdentifier: DISCORD_ADD_REACTION_UNIVERSAL_IDENTIFIER,
|
||||
name: 'discord-add-reaction',
|
||||
description:
|
||||
'Add an emoji reaction to a Discord message (for example a checkmark ✅) so the channel can see status at a glance.',
|
||||
timeoutSeconds: 30,
|
||||
toolTriggerSettings: {
|
||||
inputSchema: discordAddReactionInputSchema,
|
||||
},
|
||||
workflowActionTriggerSettings: {
|
||||
label: 'Add Discord Reaction',
|
||||
icon: 'IconBrandDiscord',
|
||||
inputSchema: jsonSchemaToInputSchema(discordAddReactionInputSchema),
|
||||
outputSchema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
success: { type: 'boolean' },
|
||||
message: { type: 'string' },
|
||||
error: { type: 'string' },
|
||||
messageId: { type: 'string' },
|
||||
channelId: { type: 'string' },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
handler: discordAddReactionHandler,
|
||||
});
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
import { defineLogicFunction } from 'twenty-sdk/define';
|
||||
import { jsonSchemaToInputSchema } from 'twenty-shared/logic-function';
|
||||
|
||||
import { DISCORD_DELETE_MESSAGE_UNIVERSAL_IDENTIFIER } from 'src/constants/universal-identifiers';
|
||||
import { discordDeleteMessageHandler } from 'src/logic-functions/handlers/discord-delete-message-handler';
|
||||
import { discordDeleteMessageInputSchema } from './schemas/discord-delete-message-input.schema';
|
||||
|
||||
export default defineLogicFunction({
|
||||
universalIdentifier: DISCORD_DELETE_MESSAGE_UNIVERSAL_IDENTIFIER,
|
||||
name: 'discord-delete-message',
|
||||
description:
|
||||
'Remove a Discord message this bot sent (for example after a mistake or when a workflow is cancelled).',
|
||||
timeoutSeconds: 30,
|
||||
toolTriggerSettings: {
|
||||
inputSchema: discordDeleteMessageInputSchema,
|
||||
},
|
||||
workflowActionTriggerSettings: {
|
||||
label: 'Delete Discord Message',
|
||||
icon: 'IconBrandDiscord',
|
||||
inputSchema: jsonSchemaToInputSchema(discordDeleteMessageInputSchema),
|
||||
outputSchema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
success: { type: 'boolean' },
|
||||
message: { type: 'string' },
|
||||
error: { type: 'string' },
|
||||
messageId: { type: 'string' },
|
||||
channelId: { type: 'string' },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
handler: discordDeleteMessageHandler,
|
||||
});
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
import type { RoutePayload } from 'twenty-sdk/define';
|
||||
import { defineLogicFunction } from 'twenty-sdk/define';
|
||||
|
||||
import { DISCORD_LIST_CHANNELS_ROUTE_UNIVERSAL_IDENTIFIER } from 'src/constants/universal-identifiers';
|
||||
import { discordListChannelsHandler } from 'src/logic-functions/handlers/discord-list-channels-handler';
|
||||
|
||||
const handler = async (event: RoutePayload) => {
|
||||
const params = event.queryStringParameters ?? {};
|
||||
const guildId =
|
||||
typeof params.guildId === 'string' && params.guildId.length > 0
|
||||
? params.guildId
|
||||
: undefined;
|
||||
|
||||
return discordListChannelsHandler({ guildId });
|
||||
};
|
||||
|
||||
export default defineLogicFunction({
|
||||
universalIdentifier: DISCORD_LIST_CHANNELS_ROUTE_UNIVERSAL_IDENTIFIER,
|
||||
name: 'discord-list-channels-route',
|
||||
timeoutSeconds: 30,
|
||||
handler,
|
||||
httpRouteTriggerSettings: {
|
||||
path: '/discord/channels',
|
||||
httpMethod: 'GET',
|
||||
isAuthRequired: true,
|
||||
},
|
||||
});
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
import { defineLogicFunction } from 'twenty-sdk/define';
|
||||
import { jsonSchemaToInputSchema } from 'twenty-shared/logic-function';
|
||||
|
||||
import { DISCORD_LIST_CHANNELS_UNIVERSAL_IDENTIFIER } from 'src/constants/universal-identifiers';
|
||||
import { discordListChannelsHandler } from 'src/logic-functions/handlers/discord-list-channels-handler';
|
||||
import { discordListChannelsInputSchema } from './schemas/discord-list-channels-input.schema';
|
||||
|
||||
export default defineLogicFunction({
|
||||
universalIdentifier: DISCORD_LIST_CHANNELS_UNIVERSAL_IDENTIFIER,
|
||||
name: 'discord-list-channels',
|
||||
description:
|
||||
'List the text-postable channels (types `GUILD_TEXT` and `GUILD_ANNOUNCEMENT`) in a Discord server, sorted by Discord position. Each entry exposes `id`, `name`, `type`, `parentId` (category), and `position`. Pass the server (guild) ID to scope the listing; if omitted and the bot is in exactly one server, that server is auto-selected. If the bot is in multiple servers, the error response lists each server name and ID for explicit selection. Voice channels, threads, forums, and categories are excluded.',
|
||||
timeoutSeconds: 30,
|
||||
toolTriggerSettings: {
|
||||
inputSchema: discordListChannelsInputSchema,
|
||||
},
|
||||
workflowActionTriggerSettings: {
|
||||
label: 'List Discord Channels',
|
||||
icon: 'IconBrandDiscord',
|
||||
inputSchema: jsonSchemaToInputSchema(discordListChannelsInputSchema),
|
||||
outputSchema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
success: { type: 'boolean' },
|
||||
channels: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string' },
|
||||
name: { type: 'string' },
|
||||
type: { type: 'number' },
|
||||
parentId: { type: 'string' },
|
||||
position: { type: 'number' },
|
||||
},
|
||||
},
|
||||
},
|
||||
count: { type: 'number' },
|
||||
error: { type: 'string' },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
handler: discordListChannelsHandler,
|
||||
});
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
import { defineLogicFunction } from 'twenty-sdk/define';
|
||||
import type { RoutePayload } from 'twenty-sdk/define';
|
||||
|
||||
import { DISCORD_LIST_GUILDS_ROUTE_UNIVERSAL_IDENTIFIER } from 'src/constants/universal-identifiers';
|
||||
import { discordListGuildsHandler } from 'src/logic-functions/handlers/discord-list-guilds-handler';
|
||||
|
||||
const handler = async (_event: RoutePayload) => {
|
||||
return discordListGuildsHandler();
|
||||
};
|
||||
|
||||
export default defineLogicFunction({
|
||||
universalIdentifier: DISCORD_LIST_GUILDS_ROUTE_UNIVERSAL_IDENTIFIER,
|
||||
name: 'discord-list-guilds-route',
|
||||
timeoutSeconds: 30,
|
||||
handler,
|
||||
httpRouteTriggerSettings: {
|
||||
path: '/discord/guilds',
|
||||
httpMethod: 'GET',
|
||||
isAuthRequired: true,
|
||||
},
|
||||
});
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
import { defineLogicFunction } from 'twenty-sdk/define';
|
||||
import { jsonSchemaToInputSchema } from 'twenty-shared/logic-function';
|
||||
|
||||
import { DISCORD_LIST_GUILDS_UNIVERSAL_IDENTIFIER } from 'src/constants/universal-identifiers';
|
||||
import { discordListGuildsHandler } from 'src/logic-functions/handlers/discord-list-guilds-handler';
|
||||
import { discordListGuildsInputSchema } from './schemas/discord-list-guilds-input.schema';
|
||||
|
||||
export default defineLogicFunction({
|
||||
universalIdentifier: DISCORD_LIST_GUILDS_UNIVERSAL_IDENTIFIER,
|
||||
name: 'discord-list-guilds',
|
||||
description:
|
||||
'List the Discord servers (guilds) the bot has been invited to. Each entry exposes `id` and `name`. Use this to discover which servers the bot can post in, then pass the chosen server ID to `discord-list-channels` or other server-scoped actions.',
|
||||
timeoutSeconds: 30,
|
||||
toolTriggerSettings: {
|
||||
inputSchema: discordListGuildsInputSchema,
|
||||
},
|
||||
workflowActionTriggerSettings: {
|
||||
label: 'List Discord Servers',
|
||||
icon: 'IconBrandDiscord',
|
||||
inputSchema: jsonSchemaToInputSchema(discordListGuildsInputSchema),
|
||||
outputSchema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
success: { type: 'boolean' },
|
||||
guilds: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string' },
|
||||
name: { type: 'string' },
|
||||
},
|
||||
},
|
||||
},
|
||||
count: { type: 'number' },
|
||||
error: { type: 'string' },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
handler: discordListGuildsHandler,
|
||||
});
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import type { RoutePayload } from 'twenty-sdk/define';
|
||||
import { defineLogicFunction } from 'twenty-sdk/define';
|
||||
|
||||
import { DISCORD_POST_MESSAGE_ROUTE_UNIVERSAL_IDENTIFIER } from 'src/constants/universal-identifiers';
|
||||
import { discordPostMessageHandler } from 'src/logic-functions/handlers/discord-post-message-handler';
|
||||
|
||||
const handler = async (event: RoutePayload) => {
|
||||
const body = event.body as Record<string, unknown> | null;
|
||||
const rawChannelId = body?.channelId;
|
||||
const rawMessageText = body?.messageText;
|
||||
|
||||
if (typeof rawChannelId !== 'string' || typeof rawMessageText !== 'string') {
|
||||
return {
|
||||
success: false,
|
||||
message: 'Failed to post Discord message',
|
||||
error: '`channelId` and `messageText` must be strings.',
|
||||
};
|
||||
}
|
||||
|
||||
const channelId = rawChannelId.trim();
|
||||
const messageText = rawMessageText.trim();
|
||||
|
||||
if (!isNonEmptyString(channelId) || !isNonEmptyString(messageText)) {
|
||||
return {
|
||||
success: false,
|
||||
message: 'Failed to post Discord message',
|
||||
error: '`channelId` and `messageText` are required.',
|
||||
};
|
||||
}
|
||||
|
||||
return discordPostMessageHandler({ channelId, messageText });
|
||||
};
|
||||
|
||||
export default defineLogicFunction({
|
||||
universalIdentifier: DISCORD_POST_MESSAGE_ROUTE_UNIVERSAL_IDENTIFIER,
|
||||
name: 'discord-post-message-route',
|
||||
timeoutSeconds: 30,
|
||||
handler,
|
||||
httpRouteTriggerSettings: {
|
||||
path: '/discord/messages',
|
||||
httpMethod: 'POST',
|
||||
isAuthRequired: true,
|
||||
},
|
||||
});
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
import { defineLogicFunction } from 'twenty-sdk/define';
|
||||
import { jsonSchemaToInputSchema } from 'twenty-shared/logic-function';
|
||||
|
||||
import { DISCORD_POST_MESSAGE_UNIVERSAL_IDENTIFIER } from 'src/constants/universal-identifiers';
|
||||
import { discordPostMessageHandler } from 'src/logic-functions/handlers/discord-post-message-handler';
|
||||
import { discordPostMessageInputSchema } from './schemas/discord-post-message-input.schema';
|
||||
|
||||
export default defineLogicFunction({
|
||||
universalIdentifier: DISCORD_POST_MESSAGE_UNIVERSAL_IDENTIFIER,
|
||||
name: 'discord-post-message',
|
||||
description:
|
||||
'Send a message to a Discord channel as the bot. Optionally reply to an existing message using its message ID from a previous step.',
|
||||
timeoutSeconds: 30,
|
||||
toolTriggerSettings: {
|
||||
inputSchema: discordPostMessageInputSchema,
|
||||
},
|
||||
workflowActionTriggerSettings: {
|
||||
label: 'Send Discord Message',
|
||||
icon: 'IconBrandDiscord',
|
||||
inputSchema: jsonSchemaToInputSchema(discordPostMessageInputSchema),
|
||||
outputSchema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
success: { type: 'boolean' },
|
||||
message: { type: 'string' },
|
||||
error: { type: 'string' },
|
||||
messageId: { type: 'string' },
|
||||
channelId: { type: 'string' },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
handler: discordPostMessageHandler,
|
||||
});
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
import { defineLogicFunction } from 'twenty-sdk/define';
|
||||
import { jsonSchemaToInputSchema } from 'twenty-shared/logic-function';
|
||||
|
||||
import { DISCORD_UPDATE_MESSAGE_UNIVERSAL_IDENTIFIER } from 'src/constants/universal-identifiers';
|
||||
import { discordUpdateMessageHandler } from 'src/logic-functions/handlers/discord-update-message-handler';
|
||||
import { discordUpdateMessageInputSchema } from './schemas/discord-update-message-input.schema';
|
||||
|
||||
export default defineLogicFunction({
|
||||
universalIdentifier: DISCORD_UPDATE_MESSAGE_UNIVERSAL_IDENTIFIER,
|
||||
name: 'discord-update-message',
|
||||
description:
|
||||
'Change the text of a Discord message this bot already sent. You need the channel ID and the message ID from when it was posted.',
|
||||
timeoutSeconds: 30,
|
||||
toolTriggerSettings: {
|
||||
inputSchema: discordUpdateMessageInputSchema,
|
||||
},
|
||||
workflowActionTriggerSettings: {
|
||||
label: 'Update Discord Message',
|
||||
icon: 'IconBrandDiscord',
|
||||
inputSchema: jsonSchemaToInputSchema(discordUpdateMessageInputSchema),
|
||||
outputSchema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
success: { type: 'boolean' },
|
||||
message: { type: 'string' },
|
||||
error: { type: 'string' },
|
||||
messageId: { type: 'string' },
|
||||
channelId: { type: 'string' },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
handler: discordUpdateMessageHandler,
|
||||
});
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
import { type DiscordAddReactionInput } from 'src/logic-functions/types/discord-add-reaction-input.type';
|
||||
import { type DiscordToolResult } from 'src/logic-functions/types/discord-tool-result.type';
|
||||
import { buildDiscordFailureResult } from 'src/logic-functions/utils/build-discord-failure-result';
|
||||
import { discordApiRequest } from 'src/logic-functions/utils/discord-api-request';
|
||||
import { getDiscordBotToken } from 'src/logic-functions/utils/get-discord-bot-token';
|
||||
|
||||
export const discordAddReactionHandler = async (
|
||||
parameters: DiscordAddReactionInput,
|
||||
): Promise<DiscordToolResult> => {
|
||||
const tokenResult = getDiscordBotToken();
|
||||
|
||||
if (!tokenResult.success) {
|
||||
return {
|
||||
success: false,
|
||||
message: 'Discord is not configured',
|
||||
error: tokenResult.error,
|
||||
};
|
||||
}
|
||||
|
||||
const channelId = parameters.channelId.trim();
|
||||
const messageId = parameters.messageId.trim();
|
||||
const emoji = parameters.emoji.trim();
|
||||
|
||||
const encodedChannelId = encodeURIComponent(channelId);
|
||||
const encodedMessageId = encodeURIComponent(messageId);
|
||||
const encodedEmoji = encodeURIComponent(emoji);
|
||||
|
||||
try {
|
||||
const result = await discordApiRequest({
|
||||
botToken: tokenResult.botToken,
|
||||
method: 'PUT',
|
||||
path: `/channels/${encodedChannelId}/messages/${encodedMessageId}/reactions/${encodedEmoji}/@me`,
|
||||
});
|
||||
|
||||
if (!result.ok) {
|
||||
return {
|
||||
success: false,
|
||||
message: 'Failed to add Discord reaction',
|
||||
error: result.errorMessage,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: `Reaction "${emoji}" added to the message.`,
|
||||
messageId,
|
||||
channelId,
|
||||
};
|
||||
} catch (error) {
|
||||
return buildDiscordFailureResult('Failed to add Discord reaction', error);
|
||||
}
|
||||
};
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
import { type DiscordDeleteMessageInput } from 'src/logic-functions/types/discord-delete-message-input.type';
|
||||
import { type DiscordToolResult } from 'src/logic-functions/types/discord-tool-result.type';
|
||||
import { buildDiscordFailureResult } from 'src/logic-functions/utils/build-discord-failure-result';
|
||||
import { discordApiRequest } from 'src/logic-functions/utils/discord-api-request';
|
||||
import { getDiscordBotToken } from 'src/logic-functions/utils/get-discord-bot-token';
|
||||
|
||||
export const discordDeleteMessageHandler = async (
|
||||
parameters: DiscordDeleteMessageInput,
|
||||
): Promise<DiscordToolResult> => {
|
||||
const tokenResult = getDiscordBotToken();
|
||||
|
||||
if (!tokenResult.success) {
|
||||
return {
|
||||
success: false,
|
||||
message: 'Discord is not configured',
|
||||
error: tokenResult.error,
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await discordApiRequest({
|
||||
botToken: tokenResult.botToken,
|
||||
method: 'DELETE',
|
||||
path: `/channels/${encodeURIComponent(
|
||||
parameters.channelId,
|
||||
)}/messages/${encodeURIComponent(parameters.messageId)}`,
|
||||
});
|
||||
|
||||
if (!result.ok) {
|
||||
return {
|
||||
success: false,
|
||||
message: 'Failed to delete Discord message',
|
||||
error: result.errorMessage,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: 'Discord message deleted.',
|
||||
messageId: parameters.messageId,
|
||||
channelId: parameters.channelId,
|
||||
};
|
||||
} catch (error) {
|
||||
return buildDiscordFailureResult('Failed to delete Discord message', error);
|
||||
}
|
||||
};
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { type DiscordListChannelsInput } from 'src/logic-functions/types/discord-list-channels-input.type';
|
||||
import {
|
||||
type DiscordListChannelsResult,
|
||||
type DiscordListChannelsResultChannel,
|
||||
} from 'src/logic-functions/types/discord-list-channels-output.type';
|
||||
import { discordApiRequest } from 'src/logic-functions/utils/discord-api-request';
|
||||
import { fetchDiscordGuilds } from 'src/logic-functions/utils/fetch-discord-guilds';
|
||||
import { getDiscordBotToken } from 'src/logic-functions/utils/get-discord-bot-token';
|
||||
|
||||
const GUILD_TEXT_CHANNEL_TYPE = 0;
|
||||
const GUILD_ANNOUNCEMENT_CHANNEL_TYPE = 5;
|
||||
|
||||
const POSTABLE_CHANNEL_TYPES = new Set<number>([
|
||||
GUILD_TEXT_CHANNEL_TYPE,
|
||||
GUILD_ANNOUNCEMENT_CHANNEL_TYPE,
|
||||
]);
|
||||
|
||||
type DiscordChannelResponse = {
|
||||
id: string;
|
||||
name: string | null;
|
||||
type: number;
|
||||
parent_id: string | null;
|
||||
position: number;
|
||||
};
|
||||
|
||||
const buildFailureResult = (error: string): DiscordListChannelsResult => ({
|
||||
success: false,
|
||||
channels: [],
|
||||
count: 0,
|
||||
error,
|
||||
});
|
||||
|
||||
const resolveGuildId = async ({
|
||||
botToken,
|
||||
providedGuildId,
|
||||
}: {
|
||||
botToken: string;
|
||||
providedGuildId: string | undefined;
|
||||
}): Promise<{ ok: true; guildId: string } | { ok: false; error: string }> => {
|
||||
const trimmed = providedGuildId?.trim();
|
||||
|
||||
if (isDefined(trimmed) && trimmed.length > 0) {
|
||||
return { ok: true, guildId: trimmed };
|
||||
}
|
||||
|
||||
const guildsResult = await fetchDiscordGuilds(botToken);
|
||||
|
||||
if (!guildsResult.ok) {
|
||||
return { ok: false, error: guildsResult.errorMessage };
|
||||
}
|
||||
|
||||
const guilds = guildsResult.data;
|
||||
|
||||
if (guilds.length === 0) {
|
||||
return {
|
||||
ok: false,
|
||||
error:
|
||||
'Bot has not been invited to any Discord server yet. Use the OAuth2 → URL Generator in the Discord Developer Portal (scope `bot`) to invite it to a server, then retry.',
|
||||
};
|
||||
}
|
||||
|
||||
if (guilds.length > 1) {
|
||||
const guildList = guilds
|
||||
.map((guild) => `"${guild.name}" (${guild.id})`)
|
||||
.join(', ');
|
||||
|
||||
return {
|
||||
ok: false,
|
||||
error: `Bot is in ${guilds.length} Discord servers — please specify which one via the guildId input. Available: ${guildList}.`,
|
||||
};
|
||||
}
|
||||
|
||||
return { ok: true, guildId: guilds[0].id };
|
||||
};
|
||||
|
||||
export const discordListChannelsHandler = async (
|
||||
parameters: DiscordListChannelsInput,
|
||||
): Promise<DiscordListChannelsResult> => {
|
||||
const tokenResult = getDiscordBotToken();
|
||||
|
||||
if (!tokenResult.success) {
|
||||
return buildFailureResult(tokenResult.error);
|
||||
}
|
||||
|
||||
const guildIdResult = await resolveGuildId({
|
||||
botToken: tokenResult.botToken,
|
||||
providedGuildId: parameters.guildId,
|
||||
});
|
||||
|
||||
if (!guildIdResult.ok) {
|
||||
return buildFailureResult(guildIdResult.error);
|
||||
}
|
||||
|
||||
const result = await discordApiRequest<DiscordChannelResponse[]>({
|
||||
botToken: tokenResult.botToken,
|
||||
method: 'GET',
|
||||
path: `/guilds/${encodeURIComponent(guildIdResult.guildId)}/channels`,
|
||||
});
|
||||
|
||||
if (!result.ok) {
|
||||
return buildFailureResult(result.errorMessage);
|
||||
}
|
||||
|
||||
const channels: DiscordListChannelsResultChannel[] = result.data
|
||||
.filter(
|
||||
(channel) =>
|
||||
POSTABLE_CHANNEL_TYPES.has(channel.type) && isDefined(channel.name),
|
||||
)
|
||||
.map((channel) => ({
|
||||
id: channel.id,
|
||||
name: channel.name as string,
|
||||
type: channel.type,
|
||||
parentId: channel.parent_id,
|
||||
position: channel.position,
|
||||
}))
|
||||
.sort((a, b) => a.position - b.position);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
channels,
|
||||
count: channels.length,
|
||||
};
|
||||
};
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
import { type DiscordListGuildsResult } from 'src/logic-functions/types/discord-list-guilds-output.type';
|
||||
import { fetchDiscordGuilds } from 'src/logic-functions/utils/fetch-discord-guilds';
|
||||
import { getDiscordBotToken } from 'src/logic-functions/utils/get-discord-bot-token';
|
||||
|
||||
const buildFailureResult = (error: string): DiscordListGuildsResult => ({
|
||||
success: false,
|
||||
guilds: [],
|
||||
count: 0,
|
||||
error,
|
||||
});
|
||||
|
||||
export const discordListGuildsHandler =
|
||||
async (): Promise<DiscordListGuildsResult> => {
|
||||
const tokenResult = getDiscordBotToken();
|
||||
|
||||
if (!tokenResult.success) {
|
||||
return buildFailureResult(tokenResult.error);
|
||||
}
|
||||
|
||||
const result = await fetchDiscordGuilds(tokenResult.botToken);
|
||||
|
||||
if (!result.ok) {
|
||||
return buildFailureResult(result.errorMessage);
|
||||
}
|
||||
|
||||
const guilds = result.data.map((guild) => ({
|
||||
id: guild.id,
|
||||
name: guild.name,
|
||||
}));
|
||||
|
||||
return {
|
||||
success: true,
|
||||
guilds,
|
||||
count: guilds.length,
|
||||
};
|
||||
};
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { type DiscordPostMessageInput } from 'src/logic-functions/types/discord-post-message-input.type';
|
||||
import { type DiscordToolResult } from 'src/logic-functions/types/discord-tool-result.type';
|
||||
import { buildDiscordFailureResult } from 'src/logic-functions/utils/build-discord-failure-result';
|
||||
import { discordApiRequest } from 'src/logic-functions/utils/discord-api-request';
|
||||
import { getDiscordBotToken } from 'src/logic-functions/utils/get-discord-bot-token';
|
||||
|
||||
type DiscordMessageResponse = {
|
||||
id: string;
|
||||
channel_id: string;
|
||||
};
|
||||
|
||||
export const discordPostMessageHandler = async (
|
||||
parameters: DiscordPostMessageInput,
|
||||
): Promise<DiscordToolResult> => {
|
||||
const tokenResult = getDiscordBotToken();
|
||||
|
||||
if (!tokenResult.success) {
|
||||
return {
|
||||
success: false,
|
||||
message: 'Discord is not configured',
|
||||
error: tokenResult.error,
|
||||
};
|
||||
}
|
||||
|
||||
const replyToMessageId = parameters.replyToMessageId?.trim();
|
||||
const body: Record<string, unknown> = {
|
||||
content: parameters.messageText,
|
||||
};
|
||||
|
||||
if (isDefined(replyToMessageId) && replyToMessageId.length > 0) {
|
||||
body.message_reference = { message_id: replyToMessageId };
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await discordApiRequest<DiscordMessageResponse>({
|
||||
botToken: tokenResult.botToken,
|
||||
method: 'POST',
|
||||
path: `/channels/${encodeURIComponent(parameters.channelId)}/messages`,
|
||||
body,
|
||||
});
|
||||
|
||||
if (!result.ok) {
|
||||
return {
|
||||
success: false,
|
||||
message: 'Failed to post Discord message',
|
||||
error: result.errorMessage,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: `Message posted to Discord (id=${result.data.id}).`,
|
||||
messageId: result.data.id,
|
||||
channelId: result.data.channel_id,
|
||||
};
|
||||
} catch (error) {
|
||||
return buildDiscordFailureResult('Failed to post Discord message', error);
|
||||
}
|
||||
};
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
import { type DiscordToolResult } from 'src/logic-functions/types/discord-tool-result.type';
|
||||
import { type DiscordUpdateMessageInput } from 'src/logic-functions/types/discord-update-message-input.type';
|
||||
import { buildDiscordFailureResult } from 'src/logic-functions/utils/build-discord-failure-result';
|
||||
import { discordApiRequest } from 'src/logic-functions/utils/discord-api-request';
|
||||
import { getDiscordBotToken } from 'src/logic-functions/utils/get-discord-bot-token';
|
||||
|
||||
type DiscordMessageResponse = {
|
||||
id: string;
|
||||
channel_id: string;
|
||||
};
|
||||
|
||||
export const discordUpdateMessageHandler = async (
|
||||
parameters: DiscordUpdateMessageInput,
|
||||
): Promise<DiscordToolResult> => {
|
||||
const tokenResult = getDiscordBotToken();
|
||||
|
||||
if (!tokenResult.success) {
|
||||
return {
|
||||
success: false,
|
||||
message: 'Discord is not configured',
|
||||
error: tokenResult.error,
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await discordApiRequest<DiscordMessageResponse>({
|
||||
botToken: tokenResult.botToken,
|
||||
method: 'PATCH',
|
||||
path: `/channels/${encodeURIComponent(
|
||||
parameters.channelId,
|
||||
)}/messages/${encodeURIComponent(parameters.messageId)}`,
|
||||
body: { content: parameters.newMessageText },
|
||||
});
|
||||
|
||||
if (!result.ok) {
|
||||
return {
|
||||
success: false,
|
||||
message: 'Failed to update Discord message',
|
||||
error: result.errorMessage,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: 'Discord message updated.',
|
||||
messageId: result.data.id,
|
||||
channelId: result.data.channel_id,
|
||||
};
|
||||
} catch (error) {
|
||||
return buildDiscordFailureResult('Failed to update Discord message', error);
|
||||
}
|
||||
};
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
import { type InputJsonSchema } from 'twenty-sdk/logic-function';
|
||||
|
||||
export const discordAddReactionInputSchema: InputJsonSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
channelId: {
|
||||
type: 'string',
|
||||
label: 'Discord channel ID',
|
||||
description: 'Channel where the message lives (Discord channel ID).',
|
||||
},
|
||||
messageId: {
|
||||
type: 'string',
|
||||
label: 'Message ID',
|
||||
description:
|
||||
'The message to react to: its **message ID** (same value as `messageId` returned when the bot posted it, or right-click the message → "Copy Message ID").',
|
||||
},
|
||||
emoji: {
|
||||
type: 'string',
|
||||
label: 'Emoji',
|
||||
description:
|
||||
'Emoji to add. For a standard unicode emoji, paste the emoji directly (e.g. `👍`, `✅`, `🎉`). For a custom server emoji, use the format `name:id` (e.g. `partyparrot:643452342342342342`). The bot must have **Add Reactions** permission in the channel.',
|
||||
},
|
||||
},
|
||||
required: ['channelId', 'messageId', 'emoji'],
|
||||
additionalProperties: false,
|
||||
};
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
import { type InputJsonSchema } from 'twenty-sdk/logic-function';
|
||||
|
||||
export const discordDeleteMessageInputSchema: InputJsonSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
channelId: {
|
||||
type: 'string',
|
||||
label: 'Discord channel ID',
|
||||
description: 'Channel that contains the message (Discord channel ID).',
|
||||
},
|
||||
messageId: {
|
||||
type: 'string',
|
||||
label: 'Message ID',
|
||||
description:
|
||||
'Which message to remove: its **message ID** (same value as `messageId` returned when the bot posted it). The bot can delete its own messages without extra permissions; deleting others\' messages requires the **Manage Messages** permission.',
|
||||
},
|
||||
},
|
||||
required: ['channelId', 'messageId'],
|
||||
additionalProperties: false,
|
||||
};
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
import { type InputJsonSchema } from 'twenty-sdk/logic-function';
|
||||
|
||||
export const discordListChannelsInputSchema: InputJsonSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
guildId: {
|
||||
type: 'string',
|
||||
label: 'Discord server (guild) ID',
|
||||
description:
|
||||
'Optional. The Discord server ID to list channels for (a long number like `1234567890123456789`). In Discord with Developer Mode on: right-click the server icon → "Copy Server ID". If omitted and the bot is in exactly one server, that server is used automatically; if the bot is in multiple servers, the error response lists each server name and ID so you can pick one.',
|
||||
},
|
||||
},
|
||||
required: [],
|
||||
additionalProperties: false,
|
||||
};
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
import { type InputJsonSchema } from 'twenty-sdk/logic-function';
|
||||
|
||||
export const discordListGuildsInputSchema: InputJsonSchema = {
|
||||
type: 'object',
|
||||
properties: {},
|
||||
required: [],
|
||||
additionalProperties: false,
|
||||
};
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
import { type InputJsonSchema } from 'twenty-sdk/logic-function';
|
||||
|
||||
export const discordPostMessageInputSchema: InputJsonSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
channelId: {
|
||||
type: 'string',
|
||||
label: 'Discord channel ID',
|
||||
description:
|
||||
'Where to post: the Discord channel ID (a long number like `1234567890123456789`). In Discord with Developer Mode on: right-click the channel → "Copy Channel ID". The bot must be a member of the server and have permission to send messages in this channel.',
|
||||
},
|
||||
messageText: {
|
||||
type: 'string',
|
||||
label: 'Message',
|
||||
multiline: true,
|
||||
description:
|
||||
'The message text. Supports Discord-flavoured markdown (**bold**, *italics*, ```code blocks```, lists, links). Max 2000 characters — Discord rejects longer payloads.',
|
||||
},
|
||||
replyToMessageId: {
|
||||
type: 'string',
|
||||
label: 'Reply to message ID',
|
||||
description:
|
||||
'Optional. To reply to an existing message, paste its ID (from a previous step\'s `messageId` output, or right-click the message → "Copy Message ID"). Leave empty for a normal new message.',
|
||||
},
|
||||
},
|
||||
required: ['channelId', 'messageText'],
|
||||
additionalProperties: false,
|
||||
};
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
import { type InputJsonSchema } from 'twenty-sdk/logic-function';
|
||||
|
||||
export const discordUpdateMessageInputSchema: InputJsonSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
channelId: {
|
||||
type: 'string',
|
||||
label: 'Discord channel ID',
|
||||
description: 'Channel that contains the message (Discord channel ID).',
|
||||
},
|
||||
messageId: {
|
||||
type: 'string',
|
||||
label: 'Message ID',
|
||||
description:
|
||||
'Which message to edit: its **message ID** (same value as `messageId` returned when the bot posted the message). You can only edit messages this bot sent.',
|
||||
},
|
||||
newMessageText: {
|
||||
type: 'string',
|
||||
label: 'New message',
|
||||
multiline: true,
|
||||
description:
|
||||
'Replacement text shown in Discord instead of the old content. Supports Discord-flavoured markdown. Max 2000 characters.',
|
||||
},
|
||||
},
|
||||
required: ['channelId', 'messageId', 'newMessageText'],
|
||||
additionalProperties: false,
|
||||
};
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
export type DiscordAddReactionInput = {
|
||||
channelId: string;
|
||||
messageId: string;
|
||||
emoji: string;
|
||||
};
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
export type DiscordDeleteMessageInput = {
|
||||
channelId: string;
|
||||
messageId: string;
|
||||
};
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
export type DiscordListChannelsInput = {
|
||||
guildId?: string;
|
||||
};
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
export type DiscordListChannelsResultChannel = {
|
||||
id: string;
|
||||
name: string;
|
||||
type: number;
|
||||
parentId: string | null;
|
||||
position: number;
|
||||
};
|
||||
|
||||
export type DiscordListChannelsResult = {
|
||||
success: boolean;
|
||||
channels: DiscordListChannelsResultChannel[];
|
||||
count: number;
|
||||
error?: string;
|
||||
};
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
export type DiscordListGuildsResultGuild = {
|
||||
id: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
export type DiscordListGuildsResult = {
|
||||
success: boolean;
|
||||
guilds: DiscordListGuildsResultGuild[];
|
||||
count: number;
|
||||
error?: string;
|
||||
};
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
export type DiscordPostMessageInput = {
|
||||
channelId: string;
|
||||
messageText: string;
|
||||
replyToMessageId?: string;
|
||||
};
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
export type DiscordToolResult = {
|
||||
success: boolean;
|
||||
message: string;
|
||||
error?: string;
|
||||
messageId?: string;
|
||||
channelId?: string;
|
||||
};
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
export type DiscordUpdateMessageInput = {
|
||||
channelId: string;
|
||||
messageId: string;
|
||||
newMessageText: string;
|
||||
};
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import { type DiscordToolResult } from 'src/logic-functions/types/discord-tool-result.type';
|
||||
|
||||
export const buildDiscordFailureResult = (
|
||||
message: string,
|
||||
error: unknown,
|
||||
): DiscordToolResult => ({
|
||||
success: false,
|
||||
message,
|
||||
error: error instanceof Error ? error.message : 'Discord request failed',
|
||||
});
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
const DISCORD_API_BASE_URL = 'https://discord.com/api/v10';
|
||||
|
||||
type DiscordApiSuccess<TData> = {
|
||||
ok: true;
|
||||
status: number;
|
||||
data: TData;
|
||||
};
|
||||
|
||||
type DiscordApiFailure = {
|
||||
ok: false;
|
||||
status: number;
|
||||
errorMessage: string;
|
||||
};
|
||||
|
||||
export type DiscordApiResult<TData> =
|
||||
| DiscordApiSuccess<TData>
|
||||
| DiscordApiFailure;
|
||||
|
||||
type DiscordErrorBody = {
|
||||
code?: number;
|
||||
message?: string;
|
||||
};
|
||||
|
||||
type DiscordApiRequestParams = {
|
||||
botToken: string;
|
||||
path: string;
|
||||
method: 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE';
|
||||
body?: unknown;
|
||||
};
|
||||
|
||||
export const discordApiRequest = async <TData = unknown>({
|
||||
botToken,
|
||||
path,
|
||||
method,
|
||||
body,
|
||||
}: DiscordApiRequestParams): Promise<DiscordApiResult<TData>> => {
|
||||
const url = `${DISCORD_API_BASE_URL}${path}`;
|
||||
const hasBody = isDefined(body);
|
||||
|
||||
let response: Response;
|
||||
|
||||
try {
|
||||
response = await fetch(url, {
|
||||
method,
|
||||
headers: {
|
||||
Authorization: `Bot ${botToken}`,
|
||||
...(hasBody ? { 'Content-Type': 'application/json' } : {}),
|
||||
},
|
||||
...(hasBody ? { body: JSON.stringify(body) } : {}),
|
||||
});
|
||||
} catch (error) {
|
||||
return {
|
||||
ok: false,
|
||||
status: 0,
|
||||
errorMessage: `Discord API request failed: ${(error as Error).message}`,
|
||||
};
|
||||
}
|
||||
|
||||
if (response.status === 204) {
|
||||
return { ok: true, status: 204, data: undefined as TData };
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
const errorMessage = await extractDiscordErrorMessage(response);
|
||||
|
||||
return {
|
||||
ok: false,
|
||||
status: response.status,
|
||||
errorMessage,
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const data = (await response.json()) as TData;
|
||||
|
||||
return { ok: true, status: response.status, data };
|
||||
} catch (error) {
|
||||
return {
|
||||
ok: false,
|
||||
status: response.status,
|
||||
errorMessage: `Discord API returned a non-JSON response: ${
|
||||
(error as Error).message
|
||||
}`,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const extractDiscordErrorMessage = async (
|
||||
response: Response,
|
||||
): Promise<string> => {
|
||||
const fallback = `Discord API responded with ${response.status}`;
|
||||
|
||||
try {
|
||||
const errorBody = (await response.json()) as DiscordErrorBody;
|
||||
|
||||
if (isDefined(errorBody.message)) {
|
||||
return isDefined(errorBody.code)
|
||||
? `${errorBody.message} (Discord error code ${errorBody.code})`
|
||||
: errorBody.message;
|
||||
}
|
||||
|
||||
return fallback;
|
||||
} catch {
|
||||
return fallback;
|
||||
}
|
||||
};
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
import {
|
||||
discordApiRequest,
|
||||
type DiscordApiResult,
|
||||
} from 'src/logic-functions/utils/discord-api-request';
|
||||
|
||||
export type DiscordGuildResponse = {
|
||||
id: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
export const fetchDiscordGuilds = (
|
||||
botToken: string,
|
||||
): Promise<DiscordApiResult<DiscordGuildResponse[]>> =>
|
||||
discordApiRequest<DiscordGuildResponse[]>({
|
||||
botToken,
|
||||
method: 'GET',
|
||||
path: '/users/@me/guilds',
|
||||
});
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const DISCORD_BOT_TOKEN_ENV_VAR = 'DISCORD_BOT_TOKEN';
|
||||
|
||||
export const getDiscordBotToken = ():
|
||||
| { success: true; botToken: string }
|
||||
| { success: false; error: string } => {
|
||||
const botToken = process.env[DISCORD_BOT_TOKEN_ENV_VAR];
|
||||
|
||||
if (!isDefined(botToken) || botToken.length === 0) {
|
||||
return {
|
||||
success: false,
|
||||
error:
|
||||
'Discord is not configured. Open the Twenty Discord app settings and set the DISCORD_BOT_TOKEN application variable (Developer Portal → Bot tab → Reset Token).',
|
||||
};
|
||||
}
|
||||
|
||||
return { success: true, botToken };
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
import { defineApplicationRole } from 'twenty-sdk/define';
|
||||
|
||||
import { DEFAULT_ROLE_UNIVERSAL_IDENTIFIER } from 'src/constants/universal-identifiers';
|
||||
|
||||
export default defineApplicationRole({
|
||||
universalIdentifier: DEFAULT_ROLE_UNIVERSAL_IDENTIFIER,
|
||||
label: 'Twenty Discord tools role',
|
||||
description:
|
||||
'No CRM data access — tools only forward requests to Discord using the configured bot token.',
|
||||
canReadAllObjectRecords: false,
|
||||
canUpdateAllObjectRecords: false,
|
||||
canSoftDeleteAllObjectRecords: false,
|
||||
canDestroyAllObjectRecords: false,
|
||||
canUpdateAllSettings: false,
|
||||
canBeAssignedToAgents: false,
|
||||
canBeAssignedToUsers: false,
|
||||
canBeAssignedToApiKeys: false,
|
||||
objectPermissions: [],
|
||||
fieldPermissions: [],
|
||||
permissionFlags: [],
|
||||
});
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"compileOnSave": false,
|
||||
"compilerOptions": {
|
||||
"sourceMap": true,
|
||||
"declaration": true,
|
||||
"outDir": "./dist",
|
||||
"rootDir": ".",
|
||||
"jsx": "react-jsx",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"importHelpers": true,
|
||||
"allowUnreachableCode": false,
|
||||
"strict": true,
|
||||
"alwaysStrict": true,
|
||||
"noImplicitAny": true,
|
||||
"strictBindCallApply": false,
|
||||
"target": "es2020",
|
||||
"module": "esnext",
|
||||
"lib": ["es2020", "dom"],
|
||||
"skipLibCheck": true,
|
||||
"skipDefaultLibCheck": true,
|
||||
"resolveJsonModule": true,
|
||||
"paths": {
|
||||
"src/*": ["./src/*"],
|
||||
"~/*": ["./*"]
|
||||
}
|
||||
},
|
||||
"exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import { defineConfig } from 'vitest/config';
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
include: ['src/**/*.test.ts'],
|
||||
},
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "twenty-client-sdk",
|
||||
"version": "2.4.0",
|
||||
"version": "2.4.2",
|
||||
"sideEffects": false,
|
||||
"license": "AGPL-3.0",
|
||||
"scripts": {
|
||||
|
||||
@@ -323,6 +323,7 @@ type FrontComponent {
|
||||
isHeadless: Boolean!
|
||||
usesSdkClient: Boolean!
|
||||
applicationTokenPair: ApplicationTokenPair
|
||||
applicationVariables: JSON
|
||||
}
|
||||
|
||||
type CommandMenuItem {
|
||||
@@ -812,6 +813,7 @@ type ViewSort {
|
||||
id: UUID!
|
||||
fieldMetadataId: UUID!
|
||||
direction: ViewSortDirection!
|
||||
subFieldName: String
|
||||
viewId: UUID!
|
||||
workspaceId: UUID!
|
||||
createdAt: DateTime!
|
||||
@@ -1486,7 +1488,6 @@ enum BillingUsageType {
|
||||
enum BillingProductKey {
|
||||
BASE_PRODUCT
|
||||
RESOURCE_CREDIT
|
||||
WORKFLOW_NODE_EXECUTION
|
||||
}
|
||||
|
||||
type BillingPriceLicensed {
|
||||
@@ -1580,7 +1581,7 @@ type BillingEndTrialPeriod {
|
||||
billingPortalUrl: String
|
||||
}
|
||||
|
||||
type BillingMeteredProductUsage {
|
||||
type BillingResourceCreditUsage {
|
||||
productKey: BillingProductKey!
|
||||
periodStart: DateTime!
|
||||
periodEnd: DateTime!
|
||||
@@ -1749,13 +1750,11 @@ enum FeatureFlagKey {
|
||||
IS_UNIQUE_INDEXES_ENABLED
|
||||
IS_JSON_FILTER_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_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED
|
||||
IS_BILLING_V2_ENABLED
|
||||
IS_REST_METADATA_API_NEW_FORMAT_DIRECT
|
||||
}
|
||||
|
||||
type WorkspaceUrls {
|
||||
@@ -2444,13 +2443,6 @@ type ImapSmtpCaldavConnectionSuccess {
|
||||
connectedAccountId: String!
|
||||
}
|
||||
|
||||
type PostgresCredentials {
|
||||
id: UUID!
|
||||
user: String!
|
||||
password: String!
|
||||
workspaceId: UUID!
|
||||
}
|
||||
|
||||
type ToolIndexEntry {
|
||||
name: String!
|
||||
description: String!
|
||||
@@ -2961,7 +2953,7 @@ type Query {
|
||||
enterpriseSubscriptionStatus: EnterpriseSubscriptionStatusDTO
|
||||
billingPortalSession(returnUrlPath: String): BillingSession!
|
||||
listPlans: [BillingPlan!]!
|
||||
getMeteredProductsUsage: [BillingMeteredProductUsage!]!
|
||||
getResourceCreditUsage: [BillingResourceCreditUsage!]!
|
||||
findWorkspaceInvitations: [WorkspaceInvitation!]!
|
||||
getApprovedAccessDomains: [ApprovedAccessDomain!]!
|
||||
getPageLayoutTabs(pageLayoutId: String!): [PageLayoutTab!]!
|
||||
@@ -3063,7 +3055,6 @@ type Query {
|
||||
getAutoCompleteAddress(address: String!, token: String!, country: String, isFieldCity: Boolean): [AutocompleteResult!]!
|
||||
getAddressDetails(placeId: String!, token: String!): PlaceDetailsResult!
|
||||
getUsageAnalytics(input: UsageAnalyticsInput): UsageAnalytics!
|
||||
getPostgresCredentials: PostgresCredentials
|
||||
findManyPublicDomains: [PublicDomain!]!
|
||||
getEmailingDomains: [EmailingDomain!]!
|
||||
findManyMarketplaceApps: [MarketplaceApp!]!
|
||||
@@ -3201,9 +3192,9 @@ type Mutation {
|
||||
switchBillingPlan: BillingUpdate!
|
||||
cancelSwitchBillingPlan: BillingUpdate!
|
||||
cancelSwitchBillingInterval: BillingUpdate!
|
||||
setMeteredSubscriptionPrice(priceId: String!): BillingUpdate!
|
||||
setResourceCreditSubscriptionPrice(priceId: String!): BillingUpdate!
|
||||
endSubscriptionTrialPeriod: BillingEndTrialPeriod!
|
||||
cancelSwitchMeteredPrice: BillingUpdate!
|
||||
cancelSwitchResourceCreditPrice: BillingUpdate!
|
||||
deleteWorkspaceInvitation(appTokenId: String!): String!
|
||||
resendWorkspaceInvitation(appTokenId: String!): SendInvitations!
|
||||
sendInvitations(emails: [String!]!, roleId: UUID): SendInvitations!
|
||||
@@ -3335,8 +3326,6 @@ type Mutation {
|
||||
startChannelSync(connectedAccountId: UUID!): ChannelSyncSuccess!
|
||||
saveImapSmtpCaldavAccount(accountOwnerId: UUID!, handle: String!, connectionParameters: EmailAccountConnectionParameters!, id: UUID): ImapSmtpCaldavConnectionSuccess!
|
||||
updateLabPublicFeatureFlag(input: UpdateLabPublicFeatureFlagInput!): FeatureFlag!
|
||||
enablePostgresProxy: PostgresCredentials!
|
||||
disablePostgresProxy: PostgresCredentials!
|
||||
createPublicDomain(domain: String!, applicationId: String): PublicDomain!
|
||||
updatePublicDomain(domain: String!, applicationId: String): PublicDomain!
|
||||
deletePublicDomain(domain: String!): Boolean!
|
||||
@@ -3552,6 +3541,7 @@ input CreateViewSortInput {
|
||||
id: UUID
|
||||
fieldMetadataId: UUID!
|
||||
direction: ViewSortDirection = ASC
|
||||
subFieldName: String
|
||||
viewId: UUID!
|
||||
}
|
||||
|
||||
@@ -3565,6 +3555,7 @@ input UpdateViewSortInput {
|
||||
|
||||
input UpdateViewSortInputUpdates {
|
||||
direction: ViewSortDirection
|
||||
subFieldName: String
|
||||
}
|
||||
|
||||
input DeleteViewSortInput {
|
||||
|
||||
@@ -276,6 +276,7 @@ export interface FrontComponent {
|
||||
isHeadless: Scalars['Boolean']
|
||||
usesSdkClient: Scalars['Boolean']
|
||||
applicationTokenPair?: ApplicationTokenPair
|
||||
applicationVariables?: Scalars['JSON']
|
||||
__typename: 'FrontComponent'
|
||||
}
|
||||
|
||||
@@ -549,6 +550,7 @@ export interface ViewSort {
|
||||
id: Scalars['UUID']
|
||||
fieldMetadataId: Scalars['UUID']
|
||||
direction: ViewSortDirection
|
||||
subFieldName?: Scalars['String']
|
||||
viewId: Scalars['UUID']
|
||||
workspaceId: Scalars['UUID']
|
||||
createdAt: Scalars['DateTime']
|
||||
@@ -1146,7 +1148,7 @@ export type BillingUsageType = 'METERED' | 'LICENSED'
|
||||
|
||||
|
||||
/** The different billing products available */
|
||||
export type BillingProductKey = 'BASE_PRODUCT' | 'RESOURCE_CREDIT' | 'WORKFLOW_NODE_EXECUTION'
|
||||
export type BillingProductKey = 'BASE_PRODUCT' | 'RESOURCE_CREDIT'
|
||||
|
||||
export interface BillingPriceLicensed {
|
||||
recurringInterval: SubscriptionInterval
|
||||
@@ -1232,7 +1234,7 @@ export interface BillingEndTrialPeriod {
|
||||
__typename: 'BillingEndTrialPeriod'
|
||||
}
|
||||
|
||||
export interface BillingMeteredProductUsage {
|
||||
export interface BillingResourceCreditUsage {
|
||||
productKey: BillingProductKey
|
||||
periodStart: Scalars['DateTime']
|
||||
periodEnd: Scalars['DateTime']
|
||||
@@ -1241,7 +1243,7 @@ export interface BillingMeteredProductUsage {
|
||||
rolloverCredits: Scalars['Float']
|
||||
totalGrantedCredits: Scalars['Float']
|
||||
unitPriceCents: Scalars['Float']
|
||||
__typename: 'BillingMeteredProductUsage'
|
||||
__typename: 'BillingResourceCreditUsage'
|
||||
}
|
||||
|
||||
export interface BillingPlan {
|
||||
@@ -1389,7 +1391,7 @@ export interface FeatureFlag {
|
||||
__typename: 'FeatureFlag'
|
||||
}
|
||||
|
||||
export type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_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_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' | 'IS_BILLING_V2_ENABLED'
|
||||
export type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_MARKETPLACE_SETTING_TAB_VISIBLE' | 'IS_PUBLIC_DOMAIN_ENABLED' | 'IS_EMAILING_DOMAIN_ENABLED' | 'IS_EMAIL_GROUP_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_REST_METADATA_API_NEW_FORMAT_DIRECT'
|
||||
|
||||
export interface WorkspaceUrls {
|
||||
customUrl?: Scalars['String']
|
||||
@@ -2122,14 +2124,6 @@ export interface ImapSmtpCaldavConnectionSuccess {
|
||||
__typename: 'ImapSmtpCaldavConnectionSuccess'
|
||||
}
|
||||
|
||||
export interface PostgresCredentials {
|
||||
id: Scalars['UUID']
|
||||
user: Scalars['String']
|
||||
password: Scalars['String']
|
||||
workspaceId: Scalars['UUID']
|
||||
__typename: 'PostgresCredentials'
|
||||
}
|
||||
|
||||
export interface ToolIndexEntry {
|
||||
name: Scalars['String']
|
||||
description: Scalars['String']
|
||||
@@ -2588,7 +2582,7 @@ export interface Query {
|
||||
enterpriseSubscriptionStatus?: EnterpriseSubscriptionStatusDTO
|
||||
billingPortalSession: BillingSession
|
||||
listPlans: BillingPlan[]
|
||||
getMeteredProductsUsage: BillingMeteredProductUsage[]
|
||||
getResourceCreditUsage: BillingResourceCreditUsage[]
|
||||
findWorkspaceInvitations: WorkspaceInvitation[]
|
||||
getApprovedAccessDomains: ApprovedAccessDomain[]
|
||||
getPageLayoutTabs: PageLayoutTab[]
|
||||
@@ -2663,7 +2657,6 @@ export interface Query {
|
||||
getAutoCompleteAddress: AutocompleteResult[]
|
||||
getAddressDetails: PlaceDetailsResult
|
||||
getUsageAnalytics: UsageAnalytics
|
||||
getPostgresCredentials?: PostgresCredentials
|
||||
findManyPublicDomains: PublicDomain[]
|
||||
getEmailingDomains: EmailingDomain[]
|
||||
findManyMarketplaceApps: MarketplaceApp[]
|
||||
@@ -2734,9 +2727,9 @@ export interface Mutation {
|
||||
switchBillingPlan: BillingUpdate
|
||||
cancelSwitchBillingPlan: BillingUpdate
|
||||
cancelSwitchBillingInterval: BillingUpdate
|
||||
setMeteredSubscriptionPrice: BillingUpdate
|
||||
setResourceCreditSubscriptionPrice: BillingUpdate
|
||||
endSubscriptionTrialPeriod: BillingEndTrialPeriod
|
||||
cancelSwitchMeteredPrice: BillingUpdate
|
||||
cancelSwitchResourceCreditPrice: BillingUpdate
|
||||
deleteWorkspaceInvitation: Scalars['String']
|
||||
resendWorkspaceInvitation: SendInvitations
|
||||
sendInvitations: SendInvitations
|
||||
@@ -2868,8 +2861,6 @@ export interface Mutation {
|
||||
startChannelSync: ChannelSyncSuccess
|
||||
saveImapSmtpCaldavAccount: ImapSmtpCaldavConnectionSuccess
|
||||
updateLabPublicFeatureFlag: FeatureFlag
|
||||
enablePostgresProxy: PostgresCredentials
|
||||
disablePostgresProxy: PostgresCredentials
|
||||
createPublicDomain: PublicDomain
|
||||
updatePublicDomain: PublicDomain
|
||||
deletePublicDomain: Scalars['Boolean']
|
||||
@@ -3173,6 +3164,7 @@ export interface FrontComponentGenqlSelection{
|
||||
isHeadless?: boolean | number
|
||||
usesSdkClient?: boolean | number
|
||||
applicationTokenPair?: ApplicationTokenPairGenqlSelection
|
||||
applicationVariables?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
@@ -3486,6 +3478,7 @@ export interface ViewSortGenqlSelection{
|
||||
id?: boolean | number
|
||||
fieldMetadataId?: boolean | number
|
||||
direction?: boolean | number
|
||||
subFieldName?: boolean | number
|
||||
viewId?: boolean | number
|
||||
workspaceId?: boolean | number
|
||||
createdAt?: boolean | number
|
||||
@@ -4192,7 +4185,7 @@ export interface BillingEndTrialPeriodGenqlSelection{
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface BillingMeteredProductUsageGenqlSelection{
|
||||
export interface BillingResourceCreditUsageGenqlSelection{
|
||||
productKey?: boolean | number
|
||||
periodStart?: boolean | number
|
||||
periodEnd?: boolean | number
|
||||
@@ -5154,15 +5147,6 @@ export interface ImapSmtpCaldavConnectionSuccessGenqlSelection{
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface PostgresCredentialsGenqlSelection{
|
||||
id?: boolean | number
|
||||
user?: boolean | number
|
||||
password?: boolean | number
|
||||
workspaceId?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface ToolIndexEntryGenqlSelection{
|
||||
name?: boolean | number
|
||||
description?: boolean | number
|
||||
@@ -5633,7 +5617,7 @@ export interface QueryGenqlSelection{
|
||||
enterpriseSubscriptionStatus?: EnterpriseSubscriptionStatusDTOGenqlSelection
|
||||
billingPortalSession?: (BillingSessionGenqlSelection & { __args?: {returnUrlPath?: (Scalars['String'] | null)} })
|
||||
listPlans?: BillingPlanGenqlSelection
|
||||
getMeteredProductsUsage?: BillingMeteredProductUsageGenqlSelection
|
||||
getResourceCreditUsage?: BillingResourceCreditUsageGenqlSelection
|
||||
findWorkspaceInvitations?: WorkspaceInvitationGenqlSelection
|
||||
getApprovedAccessDomains?: ApprovedAccessDomainGenqlSelection
|
||||
getPageLayoutTabs?: (PageLayoutTabGenqlSelection & { __args: {pageLayoutId: Scalars['String']} })
|
||||
@@ -5726,7 +5710,6 @@ export interface QueryGenqlSelection{
|
||||
getAutoCompleteAddress?: (AutocompleteResultGenqlSelection & { __args: {address: Scalars['String'], token: Scalars['String'], country?: (Scalars['String'] | null), isFieldCity?: (Scalars['Boolean'] | null)} })
|
||||
getAddressDetails?: (PlaceDetailsResultGenqlSelection & { __args: {placeId: Scalars['String'], token: Scalars['String']} })
|
||||
getUsageAnalytics?: (UsageAnalyticsGenqlSelection & { __args?: {input?: (UsageAnalyticsInput | null)} })
|
||||
getPostgresCredentials?: PostgresCredentialsGenqlSelection
|
||||
findManyPublicDomains?: PublicDomainGenqlSelection
|
||||
getEmailingDomains?: EmailingDomainGenqlSelection
|
||||
findManyMarketplaceApps?: MarketplaceAppGenqlSelection
|
||||
@@ -5818,9 +5801,9 @@ export interface MutationGenqlSelection{
|
||||
switchBillingPlan?: BillingUpdateGenqlSelection
|
||||
cancelSwitchBillingPlan?: BillingUpdateGenqlSelection
|
||||
cancelSwitchBillingInterval?: BillingUpdateGenqlSelection
|
||||
setMeteredSubscriptionPrice?: (BillingUpdateGenqlSelection & { __args: {priceId: Scalars['String']} })
|
||||
setResourceCreditSubscriptionPrice?: (BillingUpdateGenqlSelection & { __args: {priceId: Scalars['String']} })
|
||||
endSubscriptionTrialPeriod?: BillingEndTrialPeriodGenqlSelection
|
||||
cancelSwitchMeteredPrice?: BillingUpdateGenqlSelection
|
||||
cancelSwitchResourceCreditPrice?: BillingUpdateGenqlSelection
|
||||
deleteWorkspaceInvitation?: { __args: {appTokenId: Scalars['String']} }
|
||||
resendWorkspaceInvitation?: (SendInvitationsGenqlSelection & { __args: {appTokenId: Scalars['String']} })
|
||||
sendInvitations?: (SendInvitationsGenqlSelection & { __args: {emails: Scalars['String'][], roleId?: (Scalars['UUID'] | null)} })
|
||||
@@ -5952,8 +5935,6 @@ export interface MutationGenqlSelection{
|
||||
startChannelSync?: (ChannelSyncSuccessGenqlSelection & { __args: {connectedAccountId: Scalars['UUID']} })
|
||||
saveImapSmtpCaldavAccount?: (ImapSmtpCaldavConnectionSuccessGenqlSelection & { __args: {accountOwnerId: Scalars['UUID'], handle: Scalars['String'], connectionParameters: EmailAccountConnectionParameters, id?: (Scalars['UUID'] | null)} })
|
||||
updateLabPublicFeatureFlag?: (FeatureFlagGenqlSelection & { __args: {input: UpdateLabPublicFeatureFlagInput} })
|
||||
enablePostgresProxy?: PostgresCredentialsGenqlSelection
|
||||
disablePostgresProxy?: PostgresCredentialsGenqlSelection
|
||||
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']} }
|
||||
@@ -6038,7 +6019,7 @@ export interface UpsertViewWidgetViewFilterGroupInput {id?: (Scalars['UUID'] | n
|
||||
|
||||
export interface UpsertViewWidgetViewSortInput {id?: (Scalars['UUID'] | null),fieldMetadataId: Scalars['UUID'],direction?: (ViewSortDirection | null)}
|
||||
|
||||
export interface CreateViewSortInput {id?: (Scalars['UUID'] | null),fieldMetadataId: Scalars['UUID'],direction?: (ViewSortDirection | null),viewId: Scalars['UUID']}
|
||||
export interface CreateViewSortInput {id?: (Scalars['UUID'] | null),fieldMetadataId: Scalars['UUID'],direction?: (ViewSortDirection | null),subFieldName?: (Scalars['String'] | null),viewId: Scalars['UUID']}
|
||||
|
||||
export interface UpdateViewSortInput {
|
||||
/** The id of the view sort to update */
|
||||
@@ -6046,7 +6027,7 @@ id: Scalars['UUID'],
|
||||
/** The view sort to update */
|
||||
update: UpdateViewSortInputUpdates}
|
||||
|
||||
export interface UpdateViewSortInputUpdates {direction?: (ViewSortDirection | null)}
|
||||
export interface UpdateViewSortInputUpdates {direction?: (ViewSortDirection | null),subFieldName?: (Scalars['String'] | null)}
|
||||
|
||||
export interface DeleteViewSortInput {
|
||||
/** The id of the view sort to delete. */
|
||||
@@ -7107,10 +7088,10 @@ export interface LogicFunctionLogsInput {applicationId?: (Scalars['UUID'] | null
|
||||
|
||||
|
||||
|
||||
const BillingMeteredProductUsage_possibleTypes: string[] = ['BillingMeteredProductUsage']
|
||||
export const isBillingMeteredProductUsage = (obj?: { __typename?: any } | null): obj is BillingMeteredProductUsage => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isBillingMeteredProductUsage"')
|
||||
return BillingMeteredProductUsage_possibleTypes.includes(obj.__typename)
|
||||
const BillingResourceCreditUsage_possibleTypes: string[] = ['BillingResourceCreditUsage']
|
||||
export const isBillingResourceCreditUsage = (obj?: { __typename?: any } | null): obj is BillingResourceCreditUsage => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isBillingResourceCreditUsage"')
|
||||
return BillingResourceCreditUsage_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
@@ -7971,14 +7952,6 @@ export interface LogicFunctionLogsInput {applicationId?: (Scalars['UUID'] | null
|
||||
|
||||
|
||||
|
||||
const PostgresCredentials_possibleTypes: string[] = ['PostgresCredentials']
|
||||
export const isPostgresCredentials = (obj?: { __typename?: any } | null): obj is PostgresCredentials => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isPostgresCredentials"')
|
||||
return PostgresCredentials_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const ToolIndexEntry_possibleTypes: string[] = ['ToolIndexEntry']
|
||||
export const isToolIndexEntry = (obj?: { __typename?: any } | null): obj is ToolIndexEntry => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isToolIndexEntry"')
|
||||
@@ -8705,8 +8678,7 @@ export const enumBillingUsageType = {
|
||||
|
||||
export const enumBillingProductKey = {
|
||||
BASE_PRODUCT: 'BASE_PRODUCT' as const,
|
||||
RESOURCE_CREDIT: 'RESOURCE_CREDIT' as const,
|
||||
WORKFLOW_NODE_EXECUTION: 'WORKFLOW_NODE_EXECUTION' as const
|
||||
RESOURCE_CREDIT: 'RESOURCE_CREDIT' as const
|
||||
}
|
||||
|
||||
export const enumSubscriptionInterval = {
|
||||
@@ -8759,13 +8731,11 @@ export const enumFeatureFlagKey = {
|
||||
IS_UNIQUE_INDEXES_ENABLED: 'IS_UNIQUE_INDEXES_ENABLED' as const,
|
||||
IS_JSON_FILTER_ENABLED: 'IS_JSON_FILTER_ENABLED' as const,
|
||||
IS_MARKETPLACE_SETTING_TAB_VISIBLE: 'IS_MARKETPLACE_SETTING_TAB_VISIBLE' as const,
|
||||
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_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED: 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' as const,
|
||||
IS_BILLING_V2_ENABLED: 'IS_BILLING_V2_ENABLED' as const
|
||||
IS_REST_METADATA_API_NEW_FORMAT_DIRECT: 'IS_REST_METADATA_API_NEW_FORMAT_DIRECT' as const
|
||||
}
|
||||
|
||||
export const enumIdentityProviderType = {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -31,7 +31,7 @@ export default defineApplication({
|
||||
|
||||
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`).
|
||||
- `applicationVariables` become environment variables for your functions and front components. In logic functions (server-side), they are available as `process.env.VARIABLE_NAME`. In front components, use `getApplicationVariable('VARIABLE_NAME')` from `twenty-sdk/front-component`. Variables marked with `isSecret: true` are only injected into logic functions. Front components receive only non-secret variables.
|
||||
- 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()`.
|
||||
|
||||
@@ -87,7 +87,7 @@ cd my-twenty-app
|
||||
yarn twenty dev
|
||||
```
|
||||
|
||||
This watches `src/`, rebuilds on every change, and syncs the result to the server. Edit a file, save, and within a second the server reflects the change. You'll see a live status panel in your terminal.
|
||||
This watches `src/`, rebuilds on every change, and syncs the result to the server. Edit a file, save, and within a few seconds the server reflects the change. You'll see a live status panel in your terminal.
|
||||
|
||||
For more detailed output (build logs, sync requests, error traces), add `--verbose`.
|
||||
|
||||
@@ -128,11 +128,15 @@ yarn twenty dev --once
|
||||
| `yarn twenty dev` | Watches and re-syncs on every change. Runs until you stop it. | Interactive local development. |
|
||||
| `yarn twenty dev --once` | Single build + sync, exits `0` on success, `1` on failure. | CI, pre-commit hooks, AI agents, scripted workflows. |
|
||||
|
||||
Both modes need a server in development mode and an authenticated remote.
|
||||
Both modes need an authenticated remote.
|
||||
|
||||
<Warning>
|
||||
Dev mode is only available on Twenty instances running in development (`NODE_ENV=development`). Production instances reject dev sync requests — use `yarn twenty deploy` to deploy to production servers. See [Publishing](/developers/extend/apps/operations/publishing).
|
||||
</Warning>
|
||||
### Dev mode options
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--once` | Build and sync once, then exit. |
|
||||
| `--debounceMs <ms>` | Set the file-change debounce delay in milliseconds (default: `2000`). |
|
||||
| `--verbose` / `--debug` | Show detailed build logs, sync requests, and error traces. |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -239,6 +239,38 @@ Available hooks:
|
||||
| `useFrontComponentId()` | `string` | This component instance's ID |
|
||||
| `useFrontComponentExecutionContext(selector)` | varies | Access the full execution context with a selector function |
|
||||
|
||||
## Application variables
|
||||
|
||||
Application variables defined in [`defineApplication()`](/developers/extend/apps/config/application) with `isSecret: false` are available inside front components via the `getApplicationVariable` utility:
|
||||
|
||||
```tsx src/front-components/greeting.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk/define';
|
||||
import { getApplicationVariable } from 'twenty-sdk/front-component';
|
||||
|
||||
const Greeting = () => {
|
||||
const recipientName = getApplicationVariable('DEFAULT_RECIPIENT_NAME') ?? 'World';
|
||||
|
||||
return <p>Hello, {recipientName}!</p>;
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: '...',
|
||||
name: 'greeting',
|
||||
component: Greeting,
|
||||
});
|
||||
```
|
||||
|
||||
<Warning>
|
||||
Secret variables (`isSecret: true`) are **not** exposed to front components. They are only available in [logic functions](/developers/extend/apps/logic/logic-functions), which run server-side. This prevents sensitive values like API keys from being sent to the browser.
|
||||
</Warning>
|
||||
|
||||
The following system variables are always available via `process.env`:
|
||||
|
||||
| Variable | Description |
|
||||
|----------|-------------|
|
||||
| `TWENTY_API_URL` | Base URL of the Twenty API |
|
||||
| `TWENTY_APP_ACCESS_TOKEN` | Short-lived token scoped to your app's role |
|
||||
|
||||
## Host communication API
|
||||
|
||||
Front components can trigger navigation, modals, and notifications using functions from `twenty-sdk`:
|
||||
|
||||
@@ -32,7 +32,7 @@ export default defineApplication({
|
||||
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).
|
||||
* `applicationVariables` werden zu Umgebungsvariablen für Ihre Funktionen und Frontend-Komponenten. In Logikfunktionen (serverseitig) sind sie als `process.env.VARIABLE_NAME` verfügbar. In Frontend-Komponenten verwenden Sie `getApplicationVariable('VARIABLE_NAME')` aus `twenty-sdk/front-component`. Variablen, die mit `isSecret: true` gekennzeichnet sind, werden nur in Logikfunktionen injiziert. Frontend-Komponenten erhalten nur nicht-geheime Variablen.
|
||||
* 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.
|
||||
|
||||
@@ -87,7 +87,7 @@ cd my-twenty-app
|
||||
yarn twenty dev
|
||||
```
|
||||
|
||||
Dies überwacht `src/`, baut bei jeder Änderung neu und synchronisiert das Ergebnis mit dem Server. Bearbeiten Sie eine Datei, speichern Sie, und innerhalb einer Sekunde spiegelt der Server die Änderung wider. Sie sehen eine Live-Statusanzeige in Ihrem Terminal.
|
||||
Dies überwacht `src/`, baut bei jeder Änderung neu und synchronisiert das Ergebnis mit dem Server. Bearbeiten Sie eine Datei, speichern Sie, und innerhalb weniger Sekunden spiegelt der Server die Änderung wider. Sie sehen eine Live-Statusanzeige in Ihrem Terminal.
|
||||
|
||||
Für ausführlichere Ausgaben (Build-Protokolle, Sync-Anfragen, Fehlerspuren) fügen Sie `--verbose` hinzu.
|
||||
|
||||
@@ -128,11 +128,15 @@ yarn twenty dev --once
|
||||
| `yarn twenty dev` | Überwacht und synchronisiert bei jeder Änderung erneut. Läuft, bis Sie es stoppen. | Interaktive lokale Entwicklung. |
|
||||
| `yarn twenty dev --once` | Einmaliger Build + Sync, beendet sich mit `0` bei Erfolg, mit `1` bei Fehler. | CI, Pre-Commit-Hooks, KI-Agenten, skriptgesteuerte Workflows. |
|
||||
|
||||
Beide Modi benötigen einen Server im Entwicklungsmodus und eine authentifizierte Remote-Verbindung.
|
||||
Beide Modi benötigen ein authentifiziertes Remote-Repository.
|
||||
|
||||
<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 [Apps veröffentlichen](/l/de/developers/extend/apps/operations/publishing).
|
||||
</Warning>
|
||||
### Dev-Modus-Optionen
|
||||
|
||||
| Flag | Beschreibung |
|
||||
| ------------------------------------- | ----------------------------------------------------------------------------------- |
|
||||
| `--once` | Einmal erstellen und synchronisieren, dann beenden. |
|
||||
| `--debounceMs \<ms>` | Legt die Entprellzeit für Dateiänderungen in Millisekunden fest (Standard: `2000`). |
|
||||
| `--verbose` / `--debug` | Zeigt ausführliche Build-Protokolle, Sync-Anfragen und Fehler-Traces an. |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -239,6 +239,38 @@ Verfügbare Hooks:
|
||||
| `useFrontComponentId()` | `string` | Die ID dieser Komponenteninstanz |
|
||||
| `useFrontComponentExecutionContext(selector)` | variiert | Zugriff auf den vollständigen Ausführungskontext mit einer Selektorfunktion |
|
||||
|
||||
## Anwendungsvariablen
|
||||
|
||||
In [`defineApplication()`](/l/de/developers/extend/apps/config/application) mit `isSecret: false` definierte Anwendungsvariablen sind in Front-Komponenten über das Hilfsprogramm `getApplicationVariable` verfügbar:
|
||||
|
||||
```tsx src/front-components/greeting.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk/define';
|
||||
import { getApplicationVariable } from 'twenty-sdk/front-component';
|
||||
|
||||
const Greeting = () => {
|
||||
const recipientName = getApplicationVariable('DEFAULT_RECIPIENT_NAME') ?? 'World';
|
||||
|
||||
return <p>Hello, {recipientName}!</p>;
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: '...',
|
||||
name: 'greeting',
|
||||
component: Greeting,
|
||||
});
|
||||
```
|
||||
|
||||
<Warning>
|
||||
Geheime Variablen (`isSecret: true`) werden **nicht** in Front-Komponenten offengelegt. Sie sind nur in [Logikfunktionen](/l/de/developers/extend/apps/logic/logic-functions) verfügbar, die serverseitig ausgeführt werden. Dadurch wird verhindert, dass sensible Werte wie API-Schlüssel an den Browser gesendet werden.
|
||||
</Warning>
|
||||
|
||||
Die folgenden Systemvariablen sind immer über `process.env` verfügbar:
|
||||
|
||||
| Variable | Beschreibung |
|
||||
| ------------------------- | ------------------------------------------------------------- |
|
||||
| `TWENTY_API_URL` | Basis-URL der Twenty API |
|
||||
| `TWENTY_APP_ACCESS_TOKEN` | Kurzlebiges Token mit dem Geltungsbereich der Rolle Ihrer App |
|
||||
|
||||
## Host-Kommunikations-API
|
||||
|
||||
Front-Komponenten können Navigation, Modals und Benachrichtigungen mittels Funktionen aus `twenty-sdk` auslösen:
|
||||
|
||||
@@ -32,7 +32,7 @@ export default defineApplication({
|
||||
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`).
|
||||
* `applicationVariables` tornam-se variáveis de ambiente para suas funções e componentes de front-end. Em funções lógicas (no lado do servidor), elas ficam disponíveis como `process.env.VARIABLE_NAME`. Em componentes de front-end, use `getApplicationVariable('VARIABLE_NAME')` de `twenty-sdk/front-component`. Variáveis marcadas com `isSecret: true` são injetadas apenas em funções lógicas. Componentes de front-end recebem apenas variáveis não secretas.
|
||||
* 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()`.
|
||||
|
||||
@@ -87,7 +87,7 @@ cd my-twenty-app
|
||||
yarn twenty dev
|
||||
```
|
||||
|
||||
Isso monitora `src/`, recompila a cada alteração e sincroniza o resultado com o servidor. Edite um arquivo, salve e, em um segundo, o servidor refletirá a alteração. Você verá um painel de status em tempo real no seu terminal.
|
||||
Isso monitora `src/`, recompila a cada alteração e sincroniza o resultado com o servidor. Edite um arquivo, salve e, em alguns segundos, o servidor refletirá a alteração. Você verá um painel de status em tempo real no seu terminal.
|
||||
|
||||
Para uma saída mais detalhada (logs de build, solicitações de sincronização, rastros de erro), adicione `--verbose`.
|
||||
|
||||
@@ -128,11 +128,15 @@ yarn twenty dev --once
|
||||
| `yarn twenty dev` | Monitora e ressincroniza a cada alteração. Fica em execução até você interrompê-lo. | Desenvolvimento local interativo. |
|
||||
| `yarn twenty dev --once` | Executa uma única compilação + sincronização e, em seguida, encerra com o código `0` em caso de sucesso ou `1` em caso de falha. | Scripts, CI, hooks de pre-commit, agentes de IA e fluxos de trabalho com script. |
|
||||
|
||||
Ambos os modos precisam de um servidor em modo de desenvolvimento e de um remoto autenticado.
|
||||
Ambos os modos precisam de um remoto autenticado.
|
||||
|
||||
<Warning>
|
||||
O modo de desenvolvimento só está disponível em instâncias do Twenty em modo de desenvolvimento (`NODE_ENV=development`). Instâncias de produção rejeitam solicitações de sincronização de desenvolvimento — use `yarn twenty deploy` para implantar em servidores de produção. Veja [Publicação](/l/pt/developers/extend/apps/operations/publishing).
|
||||
</Warning>
|
||||
### Opções do modo de desenvolvimento
|
||||
|
||||
| Opção | Descrição |
|
||||
| ------------------------------------- | ------------------------------------------------------------------------------------------------- |
|
||||
| `--once` | Compila e sincroniza uma vez e, em seguida, sai. |
|
||||
| `--debounceMs \<ms>` | Define o atraso de debounce para alterações de arquivo em milissegundos (padrão: `2000`). |
|
||||
| `--verbose` / `--debug` | Mostra registros detalhados de compilação, solicitações de sincronização e rastreamentos de erro. |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -239,6 +239,38 @@ Hooks disponíveis:
|
||||
| `useFrontComponentId()` | `string` | O ID desta instância do componente |
|
||||
| `useFrontComponentExecutionContext(selector)` | varia | Acesse o contexto de execução completo com uma função seletora |
|
||||
|
||||
## Variáveis de aplicação
|
||||
|
||||
Variáveis de aplicação definidas em [`defineApplication()`](/l/pt/developers/extend/apps/config/application) com `isSecret: false` estão disponíveis nos componentes de front por meio do utilitário `getApplicationVariable`:
|
||||
|
||||
```tsx src/front-components/greeting.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk/define';
|
||||
import { getApplicationVariable } from 'twenty-sdk/front-component';
|
||||
|
||||
const Greeting = () => {
|
||||
const recipientName = getApplicationVariable('DEFAULT_RECIPIENT_NAME') ?? 'World';
|
||||
|
||||
return <p>Hello, {recipientName}!</p>;
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: '...',
|
||||
name: 'greeting',
|
||||
component: Greeting,
|
||||
});
|
||||
```
|
||||
|
||||
<Warning>
|
||||
Variáveis secretas (`isSecret: true`) **não** são expostas aos componentes de front. Elas estão disponíveis apenas em [funções de lógica](/l/pt/developers/extend/apps/logic/logic-functions), que são executadas no lado do servidor. Isso impede que valores sigilosos, como chaves de API, sejam enviados para o navegador.
|
||||
</Warning>
|
||||
|
||||
As seguintes variáveis de sistema estão sempre disponíveis via `process.env`:
|
||||
|
||||
| Variável | Descrição |
|
||||
| ------------------------- | ------------------------------------------------------------- |
|
||||
| `TWENTY_API_URL` | URL base da API da Twenty |
|
||||
| `TWENTY_APP_ACCESS_TOKEN` | Token de curta duração limitado ao escopo do papel do seu app |
|
||||
|
||||
## API de comunicação do host
|
||||
|
||||
Componentes de front-end podem acionar navegação, modais e notificações usando funções de `twenty-sdk`:
|
||||
|
||||
@@ -32,7 +32,7 @@ export default defineApplication({
|
||||
Notițe:
|
||||
|
||||
* Câmpurile `universalIdentifier` sunt ID-uri deterministe pe care le dețineți. Generați-le o singură dată și mențineți-le stabile între sincronizări.
|
||||
* `applicationVariables` devin variabile de mediu pentru funcțiile și componentele front-end (de exemplu, `DEFAULT_RECIPIENT_NAME` este disponibil ca `process.env.DEFAULT_RECIPIENT_NAME`).
|
||||
* `applicationVariables` devin variabile de mediu pentru funcțiile și componentele front-end. În funcțiile de logică (server-side), acestea sunt disponibile ca `process.env.VARIABLE_NAME`. În componentele front-end, folosește `getApplicationVariable('VARIABLE_NAME')` din `twenty-sdk/front-component`. Variabilele marcate cu `isSecret: true` sunt injectate doar în funcțiile de logică. Componentele front-end primesc doar variabile non-secrete.
|
||||
* Rolul implicit este detectat automat din fișierul de rol marcat cu [`defineApplicationRole()`](/l/ro/developers/extend/apps/config/roles) — nu este necesar să faci referire la el în `defineApplication()`.
|
||||
* Funcțiile de pre-instalare și post-instalare sunt detectate automat în timpul construirii manifestului — nu trebuie să le referiți în `defineApplication()`.
|
||||
* Transmiterea explicită a `defaultRoleUniversalIdentifier` este în continuare acceptată pentru compatibilitate retroactivă, dar este considerată învechită în favoarea `defineApplicationRole()`.
|
||||
|
||||
@@ -87,7 +87,7 @@ cd my-twenty-app
|
||||
yarn twenty dev
|
||||
```
|
||||
|
||||
Aceasta monitorizează `src/`, reconstruiește la fiecare modificare și sincronizează rezultatul pe server. Editați un fișier, salvați, iar în decurs de o secundă serverul reflectă modificarea. Veți vedea în terminal un panou de stare în timp real.
|
||||
Aceasta monitorizează `src/`, reconstruiește la fiecare modificare și sincronizează rezultatul pe server. Editați un fișier, salvați, iar în câteva secunde serverul reflectă modificarea. Veți vedea în terminal un panou de stare în timp real.
|
||||
|
||||
Pentru o ieșire mai detaliată (jurnale de build, cereri de sincronizare, urme ale erorilor), adăugați `--verbose`.
|
||||
|
||||
@@ -128,11 +128,15 @@ yarn twenty dev --once
|
||||
| `yarn twenty dev` | Monitorizează și resincronizează la fiecare modificare. Rulează până când îl opriți. | Dezvoltare locală interactivă. |
|
||||
| `yarn twenty dev --once` | Un singur build + sync, iese cu `0` la succes, `1` la eșec. | CI, hook-uri pre-commit, agenți AI, fluxuri de lucru scriptate. |
|
||||
|
||||
Ambele moduri necesită un server în modul de dezvoltare și un remote autentificat.
|
||||
Ambele moduri necesită o conexiune la distanță autentificată.
|
||||
|
||||
<Warning>
|
||||
Modul de dezvoltare este disponibil doar pe instanțele Twenty care rulează în modul development (`NODE_ENV=development`). Instanțele de producție resping cererile de sincronizare din modul de dezvoltare — folosiți `yarn twenty deploy` pentru a implementa pe serverele de producție. Consultați [Publicarea](/l/ro/developers/extend/apps/operations/publishing).
|
||||
</Warning>
|
||||
### Opțiuni pentru modul de dezvoltare
|
||||
|
||||
| Opțiune | Descriere |
|
||||
| ------------------------------------- | ------------------------------------------------------------------------------------------------ |
|
||||
| `--once` | Construiește și sincronizează o singură dată, apoi iese. |
|
||||
| `--debounceMs \<ms>` | Setează întârzierea de debounce pentru modificarea fișierului în milisecunde (implicit: `2000`). |
|
||||
| `--verbose` / `--debug` | Afișează jurnale detaliate de construire, cereri de sincronizare și urme ale erorilor. |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -239,6 +239,38 @@ Hook-uri disponibile:
|
||||
| `useFrontComponentId()` | `string` | ID-ul acestei instanțe de componentă |
|
||||
| `useFrontComponentExecutionContext(selector)` | variază | Accesați întregul context de execuție cu o funcție selector |
|
||||
|
||||
## Variabile de aplicație
|
||||
|
||||
Variabilele de aplicație definite în [`defineApplication()`](/l/ro/developers/extend/apps/config/application) cu `isSecret: false` sunt disponibile în componentele de interfață prin utilitarul `getApplicationVariable`:
|
||||
|
||||
```tsx src/front-components/greeting.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk/define';
|
||||
import { getApplicationVariable } from 'twenty-sdk/front-component';
|
||||
|
||||
const Greeting = () => {
|
||||
const recipientName = getApplicationVariable('DEFAULT_RECIPIENT_NAME') ?? 'World';
|
||||
|
||||
return <p>Hello, {recipientName}!</p>;
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: '...',
|
||||
name: 'greeting',
|
||||
component: Greeting,
|
||||
});
|
||||
```
|
||||
|
||||
<Warning>
|
||||
Variabilele secrete (`isSecret: true`) **nu** sunt expuse componentelor de interfață. Acestea sunt disponibile doar în [funcțiile logice](/l/ro/developers/extend/apps/logic/logic-functions), care rulează pe server. Acest lucru împiedică trimiterea către browser a valorilor sensibile, cum ar fi cheile API.
|
||||
</Warning>
|
||||
|
||||
Următoarele variabile de sistem sunt întotdeauna disponibile prin `process.env`:
|
||||
|
||||
| Variabilă | Descriere |
|
||||
| ------------------------- | -------------------------------------------------------- |
|
||||
| `TWENTY_API_URL` | URL de bază al API-ului Twenty |
|
||||
| `TWENTY_APP_ACCESS_TOKEN` | Token cu durată scurtă, limitat la rolul aplicației dvs. |
|
||||
|
||||
## API-ul de comunicare cu gazda
|
||||
|
||||
Componentele front-end pot declanșa navigare, ferestre modale și notificări folosind funcții din `twenty-sdk`:
|
||||
|
||||
@@ -32,7 +32,7 @@ export default defineApplication({
|
||||
Заметки:
|
||||
|
||||
* Поля `universalIdentifier` — это детерминированные идентификаторы, которые принадлежат вам. Сгенерируйте их один раз и сохраняйте неизменными между синхронизациями.
|
||||
* `applicationVariables` становятся переменными окружения для ваших функций и фронтенд-компонентов (например, `DEFAULT_RECIPIENT_NAME` доступна как `process.env.DEFAULT_RECIPIENT_NAME`).
|
||||
* `applicationVariables` становятся переменными окружения для ваших функций и фронтенд-компонентов. В логических функциях (на стороне сервера) они доступны как `process.env.VARIABLE_NAME`. Во фронтенд-компонентах используйте `getApplicationVariable('VARIABLE_NAME')` из `twenty-sdk/front-component`. Переменные, помеченные как `isSecret: true`, внедряются только в логические функции. Фронтенд-компоненты получают только несекретные переменные.
|
||||
* Роль по умолчанию автоматически определяется из файла роли, помеченного с помощью [`defineApplicationRole()`](/l/ru/developers/extend/apps/config/roles) — вам не нужно ссылаться на неё из `defineApplication()`.
|
||||
* Предустановочные и постустановочные функции обнаруживаются автоматически во время сборки манифеста — вам не нужно указывать их в `defineApplication()`.
|
||||
* Явная передача `defaultRoleUniversalIdentifier` по-прежнему поддерживается для обратной совместимости, но считается устаревшей и вместо неё рекомендуется использовать `defineApplicationRole()`.
|
||||
|
||||
@@ -87,7 +87,7 @@ cd my-twenty-app
|
||||
yarn twenty dev
|
||||
```
|
||||
|
||||
Эта команда отслеживает `src/`, пересобирает при каждом изменении и синхронизирует результат с сервером. Отредактируйте файл, сохраните — и через секунду сервер отразит изменения. В терминале появится панель текущего статуса.
|
||||
Эта команда отслеживает `src/`, пересобирает при каждом изменении и синхронизирует результат с сервером. Отредактируйте файл, сохраните — и через несколько секунд сервер отразит изменения. В терминале появится панель текущего статуса.
|
||||
|
||||
Для более подробного вывода (журналы сборки, запросы синхронизации, трассировки ошибок) добавьте `--verbose`.
|
||||
|
||||
@@ -128,11 +128,15 @@ yarn twenty dev --once
|
||||
| `yarn twenty dev` | Отслеживает и повторно синхронизирует при каждом изменении. Продолжает работать, пока вы его не остановите. | Интерактивная локальная разработка. |
|
||||
| `yarn twenty dev --once` | Одна сборка и синхронизация, завершает работу с кодом `0` при успехе и `1` при ошибке. | CI, хуки pre-commit, AI-агенты, скриптовые рабочие процессы. |
|
||||
|
||||
Оба режима требуют сервер в режиме разработки и аутентифицированный удалённый сервер.
|
||||
Оба режима требуют аутентифицированного удалённого репозитория.
|
||||
|
||||
<Warning>
|
||||
Режим разработки доступен только на экземплярах Twenty, запущенных в режиме разработки (`NODE_ENV=development`). Экземпляры в продакшене отклоняют запросы синхронизации из режима разработки — используйте `yarn twenty deploy` для развёртывания на производственные серверы. См. [Публикация](/l/ru/developers/extend/apps/operations/publishing).
|
||||
</Warning>
|
||||
### Параметры режима разработки
|
||||
|
||||
| Флаг | Описание |
|
||||
| ------------------------------------- | ------------------------------------------------------------------------------------- |
|
||||
| `--once` | Выполнить сборку и синхронизацию один раз, затем завершить работу. |
|
||||
| `--debounceMs \<ms>` | Установить задержку дебаунса изменений файлов в миллисекундах (по умолчанию: `2000`). |
|
||||
| `--verbose` / `--debug` | Показывать подробные журналы сборки, запросы синхронизации и трассировки ошибок. |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -239,6 +239,38 @@ export default defineFrontComponent({
|
||||
| `useFrontComponentId()` | `string` | ID этого экземпляра компонента |
|
||||
| `useFrontComponentExecutionContext(selector)` | различается | Доступ к полному контексту выполнения с помощью функции-селектора |
|
||||
|
||||
## Переменные приложения
|
||||
|
||||
Переменные приложения, определенные в [`defineApplication()`](/l/ru/developers/extend/apps/config/application) с `isSecret: false`, доступны внутри фронтенд-компонентов через утилиту `getApplicationVariable`:
|
||||
|
||||
```tsx src/front-components/greeting.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk/define';
|
||||
import { getApplicationVariable } from 'twenty-sdk/front-component';
|
||||
|
||||
const Greeting = () => {
|
||||
const recipientName = getApplicationVariable('DEFAULT_RECIPIENT_NAME') ?? 'World';
|
||||
|
||||
return <p>Hello, {recipientName}!</p>;
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: '...',
|
||||
name: 'greeting',
|
||||
component: Greeting,
|
||||
});
|
||||
```
|
||||
|
||||
<Warning>
|
||||
Секретные переменные (`isSecret: true`) **не** доступны фронтенд-компонентам. Они доступны только в [логических функциях](/l/ru/developers/extend/apps/logic/logic-functions), которые выполняются на стороне сервера. Это предотвращает отправку в браузер конфиденциальных значений, таких как ключи API.
|
||||
</Warning>
|
||||
|
||||
Следующие системные переменные всегда доступны через `process.env`:
|
||||
|
||||
| Переменная | Описание |
|
||||
| ------------------------- | ----------------------------------------------------------------------------- |
|
||||
| `TWENTY_API_URL` | Базовый URL API Twenty |
|
||||
| `TWENTY_APP_ACCESS_TOKEN` | Краткоживущий токен с областью действия, ограниченной ролью вашего приложения |
|
||||
|
||||
## API взаимодействия с хостом
|
||||
|
||||
Компоненты фронтенда могут вызывать навигацию, модальные окна и уведомления с помощью функций из `twenty-sdk`:
|
||||
|
||||
@@ -32,7 +32,7 @@ export default defineApplication({
|
||||
Notlar:
|
||||
|
||||
* `universalIdentifier` alanları, size ait deterministik kimliklerdir. Bunları bir kez oluşturun ve senkronizasyonlar boyunca kararlı tutun.
|
||||
* `applicationVariables`, fonksiyonlarınız ve ön uç bileşenleriniz için ortam değişkenlerine dönüşür (örn. `DEFAULT_RECIPIENT_NAME`, `process.env.DEFAULT_RECIPIENT_NAME` olarak kullanılabilir).
|
||||
* `applicationVariables`, fonksiyonlarınız ve ön bileşenleriniz için ortam değişkenlerine dönüşür. Mantık fonksiyonlarında (sunucu tarafında), `process.env.VARIABLE_NAME` olarak kullanılabilirler. Ön bileşenlerde, `twenty-sdk/front-component` içindeki `getApplicationVariable('VARIABLE_NAME')` fonksiyonunu kullanın. `isSecret: true` ile işaretlenen değişkenler yalnızca mantık fonksiyonlarına enjekte edilir. Ön bileşenler yalnızca gizli olmayan değişkenleri alır.
|
||||
* Varsayılan rol, [`defineApplicationRole()`](/l/tr/developers/extend/apps/config/roles) ile işaretlenmiş rol dosyasından otomatik olarak algılanır — onu `defineApplication()` içinden belirtmenize gerek yoktur.
|
||||
* Kurulum öncesi ve kurulum sonrası fonksiyonlar manifest derlemesi sırasında otomatik olarak algılanır — bunlara `defineApplication()` içinde referans vermeniz gerekmez.
|
||||
* Geriye dönük uyumluluk için `defaultRoleUniversalIdentifier` değerini açıkça geçmek hâlâ desteklenmektedir, ancak `defineApplicationRole()` lehine kullanımdan kaldırılmıştır.
|
||||
|
||||
@@ -87,7 +87,7 @@ cd my-twenty-app
|
||||
yarn twenty dev
|
||||
```
|
||||
|
||||
Bu, `src/` dizinini izler, her değişiklikte yeniden oluşturur ve sonucu sunucuya eşitler. Bir dosyayı düzenleyin, kaydedin; bir saniye içinde sunucu değişikliği yansıtır. Terminalinizde canlı bir durum paneli göreceksiniz.
|
||||
Bu, `src/` dizinini izler, her değişiklikte yeniden oluşturur ve sonucu sunucuya eşitler. Bir dosyayı düzenleyin, kaydedin ve birkaç saniye içinde sunucu değişikliği yansıtır. Terminalinizde canlı bir durum paneli göreceksiniz.
|
||||
|
||||
Daha ayrıntılı çıktı (derleme günlükleri, eşitleme istekleri, hata izleri) için `--verbose` ekleyin.
|
||||
|
||||
@@ -128,11 +128,15 @@ yarn twenty dev --once
|
||||
| `yarn twenty dev` | Her değişiklikte izler ve yeniden eşitler. Siz durdurana kadar çalışır. | Etkileşimli yerel geliştirme. |
|
||||
| `yarn twenty dev --once` | Tek derleme + eşitleme; başarıda `0`, başarısızlıkta `1` ile çıkar. | CI, pre-commit kancaları, AI ajanları, betiklenmiş iş akışları. |
|
||||
|
||||
Her iki mod da geliştirme modunda bir sunucuya ve kimliği doğrulanmış bir uzak uca ihtiyaç duyar.
|
||||
Her iki kipin de kimliği doğrulanmış bir uzak sunucuya ihtiyaç duyar.
|
||||
|
||||
<Warning>
|
||||
Geliştirme modu yalnızca geliştirme ortamında (`NODE_ENV=development`) çalışan Twenty örneklerinde kullanılabilir. Üretim örnekleri, geliştirme eşitleme isteklerini reddeder — üretim sunucularına dağıtmak için `yarn twenty deploy` kullanın. Bkz. [Yayımlama](/l/tr/developers/extend/apps/operations/publishing).
|
||||
</Warning>
|
||||
### Geliştirme kipi seçenekleri
|
||||
|
||||
| Bayrak | Açıklama |
|
||||
| ------------------------------------- | ------------------------------------------------------------------------------------------ |
|
||||
| `--once` | Bir kez derleyip eşitleyin, ardından çıkın. |
|
||||
| `--debounceMs \<ms>` | Dosya değişikliği geciktirme süresini milisaniye cinsinden ayarlayın (varsayılan: `2000`). |
|
||||
| `--verbose` / `--debug` | Ayrıntılı derleme günlüklerini, eşitleme isteklerini ve hata izlerini gösterin. |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -239,6 +239,38 @@ Kullanılabilir hook'lar:
|
||||
| `useFrontComponentId()` | `string` | Bu bileşen örneğinin ID'si |
|
||||
| `useFrontComponentExecutionContext(selector)` | değişir | Bir seçici işlevle tam yürütme bağlamına erişin |
|
||||
|
||||
## Uygulama değişkenleri
|
||||
|
||||
`isSecret: false` ile [`defineApplication()`](/l/tr/developers/extend/apps/config/application) içinde tanımlanan uygulama değişkenleri, `getApplicationVariable` yardımcı işlevi aracılığıyla ön uç bileşenleri içinde kullanılabilir:
|
||||
|
||||
```tsx src/front-components/greeting.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk/define';
|
||||
import { getApplicationVariable } from 'twenty-sdk/front-component';
|
||||
|
||||
const Greeting = () => {
|
||||
const recipientName = getApplicationVariable('DEFAULT_RECIPIENT_NAME') ?? 'World';
|
||||
|
||||
return <p>Hello, {recipientName}!</p>;
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: '...',
|
||||
name: 'greeting',
|
||||
component: Greeting,
|
||||
});
|
||||
```
|
||||
|
||||
<Warning>
|
||||
Gizli değişkenler (`isSecret: true`) ön uç bileşenlere açıklanmaz. Bunlar yalnızca sunucu tarafında çalışan [mantık işlevlerinde](/l/tr/developers/extend/apps/logic/logic-functions) kullanılabilir. Bu, API anahtarları gibi hassas değerlerin tarayıcıya gönderilmesini engeller.
|
||||
</Warning>
|
||||
|
||||
Aşağıdaki sistem değişkenleri her zaman `process.env` aracılığıyla kullanılabilir:
|
||||
|
||||
| Değişken | Açıklama |
|
||||
| ------------------------- | --------------------------------------------------------- |
|
||||
| `TWENTY_API_URL` | Twenty API'nin temel URL'si |
|
||||
| `TWENTY_APP_ACCESS_TOKEN` | Uygulamanızın rolüyle sınırlanan kısa ömürlü bir belirteç |
|
||||
|
||||
## Host iletişim API'si
|
||||
|
||||
Ön uç bileşenleri, `twenty-sdk`'deki işlevleri kullanarak gezinmeyi, modalları ve bildirimleri tetikleyebilir:
|
||||
|
||||
@@ -32,7 +32,7 @@ export default defineApplication({
|
||||
备注:
|
||||
|
||||
* `universalIdentifier` 字段是你拥有的确定性 ID。 只需生成一次,并在多次同步过程中保持稳定不变。
|
||||
* `applicationVariables` 会变成你的函数和前端组件可用的环境变量(例如,`DEFAULT_RECIPIENT_NAME` 可作为 `process.env.DEFAULT_RECIPIENT_NAME` 使用)。
|
||||
* `applicationVariables` 会变成你的函数和前端组件可用的环境变量。 在逻辑函数(服务端)中,可以通过 `process.env.VARIABLE_NAME` 使用它们。 在前端组件中,使用 `twenty-sdk/front-component` 中的 `getApplicationVariable('VARIABLE_NAME')`。 标记为 `isSecret: true` 的变量只会注入到逻辑函数中。 前端组件只会接收非机密变量。
|
||||
* 默认角色会根据使用 [`defineApplicationRole()`](/l/zh/developers/extend/apps/config/roles) 标记的角色文件自动检测——你不需要在 `defineApplication()` 中引用它。
|
||||
* 在构建清单时会自动检测安装前/安装后函数——无需在 `defineApplication()` 中引用它们。
|
||||
* 显式传递 `defaultRoleUniversalIdentifier` 仍然受支持以保持向后兼容性,但已弃用,推荐改用 `defineApplicationRole()`。
|
||||
|
||||
@@ -87,7 +87,7 @@ cd my-twenty-app
|
||||
yarn twenty dev
|
||||
```
|
||||
|
||||
它会监视 `src/`,在每次更改时重新构建,并将结果同步到服务器。 编辑文件、保存,服务器会在一秒内反映出更改。 你会在终端中看到一个实时状态面板。
|
||||
它会监视 `src/`,在每次更改时重新构建,并将结果同步到服务器。 编辑文件、保存,服务器会在几秒内反映出更改。 你会在终端中看到一个实时状态面板。
|
||||
|
||||
如需更详细的输出(构建日志、同步请求、错误跟踪),请添加 `--verbose`。
|
||||
|
||||
@@ -128,11 +128,15 @@ yarn twenty dev --once
|
||||
| `yarn twenty dev` | 监视并在每次更改时重新同步。 持续运行,直到你将其停止。 | 交互式本地开发。 |
|
||||
| `yarn twenty dev --once` | 单次构建与同步,成功时以 `0` 退出,失败时以 `1` 退出。 | CI、pre-commit 钩子、AI 智能体、脚本化工作流。 |
|
||||
|
||||
两种模式都需要处于开发模式的服务器和已认证的远程。
|
||||
两种模式都需要经过身份验证的远程仓库。
|
||||
|
||||
<Warning>
|
||||
开发模式仅适用于以开发模式运行的 Twenty 实例(`NODE_ENV=development`)。 生产实例会拒绝开发同步请求——请使用 `yarn twenty deploy` 部署到生产服务器。 参见[发布](/l/zh/developers/extend/apps/operations/publishing)。
|
||||
</Warning>
|
||||
### 开发模式选项
|
||||
|
||||
| 标志 | 描述 |
|
||||
| ------------------------------------- | ------------------------------ |
|
||||
| `--once` | 仅构建并同步一次,然后退出。 |
|
||||
| `--debounceMs \<ms>` | 以毫秒为单位设置文件更改的防抖延迟(默认值:`2000`)。 |
|
||||
| `--verbose` / `--debug` | 显示详细的构建日志、同步请求和错误跟踪。 |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -239,6 +239,38 @@ export default defineFrontComponent({
|
||||
| `useFrontComponentId()` | `string` | 此组件实例的 ID |
|
||||
| `useFrontComponentExecutionContext(selector)` | 因情况而异 | 使用选择器函数访问完整的执行上下文 |
|
||||
|
||||
## 应用程序变量
|
||||
|
||||
在 [`defineApplication()`](/l/zh/developers/extend/apps/config/application) 中定义、且 `isSecret: false` 的应用程序变量,可以通过 `getApplicationVariable` 实用工具在前端组件中使用:
|
||||
|
||||
```tsx src/front-components/greeting.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk/define';
|
||||
import { getApplicationVariable } from 'twenty-sdk/front-component';
|
||||
|
||||
const Greeting = () => {
|
||||
const recipientName = getApplicationVariable('DEFAULT_RECIPIENT_NAME') ?? 'World';
|
||||
|
||||
return <p>Hello, {recipientName}!</p>;
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: '...',
|
||||
name: 'greeting',
|
||||
component: Greeting,
|
||||
});
|
||||
```
|
||||
|
||||
<Warning>
|
||||
机密变量(`isSecret: true`)**不会**暴露给前端组件。 它们仅在服务器端运行的 [逻辑函数](/l/zh/developers/extend/apps/logic/logic-functions) 中可用。 这可以防止诸如 API 密钥之类的敏感值被发送到浏览器。
|
||||
</Warning>
|
||||
|
||||
以下系统变量始终可以通过 `process.env` 获取:
|
||||
|
||||
| 变量 | 描述 |
|
||||
| ------------------------- | ------------------ |
|
||||
| `TWENTY_API_URL` | Twenty API 的基础 URL |
|
||||
| `TWENTY_APP_ACCESS_TOKEN` | 限定在你的应用角色范围内的短期令牌 |
|
||||
|
||||
## 宿主通信 API
|
||||
|
||||
前端组件可以使用来自 `twenty-sdk` 的函数触发导航、模态框和通知:
|
||||
|
||||
+4
@@ -23,6 +23,7 @@ type FrontComponentContentProps = {
|
||||
applicationAccessToken?: string;
|
||||
apiUrl?: string;
|
||||
sdkClientUrls?: SdkClientUrls;
|
||||
applicationVariables?: Record<string, string>;
|
||||
executionContext: FrontComponentExecutionContext;
|
||||
frontComponentHostCommunicationApi: FrontComponentHostCommunicationApi;
|
||||
onError: (error?: Error) => void;
|
||||
@@ -34,6 +35,7 @@ export const FrontComponentRenderer = ({
|
||||
applicationAccessToken,
|
||||
apiUrl,
|
||||
sdkClientUrls,
|
||||
applicationVariables,
|
||||
executionContext,
|
||||
frontComponentHostCommunicationApi,
|
||||
onError,
|
||||
@@ -55,6 +57,7 @@ export const FrontComponentRenderer = ({
|
||||
applicationAccessToken={applicationAccessToken}
|
||||
apiUrl={apiUrl}
|
||||
sdkClientUrls={sdkClientUrls}
|
||||
applicationVariables={applicationVariables}
|
||||
frontComponentId={executionContext.frontComponentId}
|
||||
setReceiver={setReceiver}
|
||||
setThread={setThread}
|
||||
@@ -69,6 +72,7 @@ export const FrontComponentRenderer = ({
|
||||
applicationAccessToken,
|
||||
apiUrl,
|
||||
sdkClientUrls,
|
||||
applicationVariables,
|
||||
executionContext.frontComponentId,
|
||||
]);
|
||||
|
||||
|
||||
+4
@@ -36,6 +36,7 @@ type FrontComponentWorkerEffectProps = {
|
||||
applicationAccessToken?: string;
|
||||
apiUrl?: string;
|
||||
sdkClientUrls?: SdkClientUrls;
|
||||
applicationVariables?: Record<string, string>;
|
||||
frontComponentId: string;
|
||||
setReceiver: React.Dispatch<React.SetStateAction<RemoteReceiver | null>>;
|
||||
setThread: React.Dispatch<
|
||||
@@ -52,6 +53,7 @@ export const FrontComponentWorkerEffect = ({
|
||||
applicationAccessToken,
|
||||
apiUrl,
|
||||
sdkClientUrls,
|
||||
applicationVariables,
|
||||
frontComponentId,
|
||||
setReceiver,
|
||||
setThread,
|
||||
@@ -121,6 +123,7 @@ export const FrontComponentWorkerEffect = ({
|
||||
applicationAccessToken,
|
||||
apiUrl,
|
||||
sdkClientUrls,
|
||||
applicationVariables,
|
||||
})
|
||||
.catch((error: Error) => {
|
||||
setError(error);
|
||||
@@ -143,6 +146,7 @@ export const FrontComponentWorkerEffect = ({
|
||||
applicationAccessToken,
|
||||
apiUrl,
|
||||
sdkClientUrls,
|
||||
applicationVariables,
|
||||
frontComponentId,
|
||||
setError,
|
||||
setReceiver,
|
||||
|
||||
@@ -91,6 +91,13 @@ const render: WorkerExports['render'] = async (
|
||||
document.body.append(root);
|
||||
installStyleBridge(root);
|
||||
|
||||
if (isDefined(renderContext.applicationVariables)) {
|
||||
setWorkerEnv({
|
||||
applicationVariables: JSON.stringify(renderContext.applicationVariables),
|
||||
});
|
||||
}
|
||||
|
||||
// System variables are set after application variables so they cannot be overridden
|
||||
if (isDefined(renderContext.apiUrl)) {
|
||||
setWorkerEnv({
|
||||
TWENTY_API_URL: renderContext.apiUrl,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const setWorkerEnv = (environmentVariables: Record<string, string>) => {
|
||||
export const setWorkerEnv = (variables: Record<string, string>) => {
|
||||
const globalObject = globalThis as Record<string, unknown>;
|
||||
const processObject =
|
||||
(globalObject['process'] as Record<string, unknown> | undefined) ?? {};
|
||||
@@ -7,7 +7,7 @@ export const setWorkerEnv = (environmentVariables: Record<string, string>) => {
|
||||
|
||||
processObject['env'] = {
|
||||
...processEnvironment,
|
||||
...environmentVariables,
|
||||
...variables,
|
||||
};
|
||||
|
||||
globalObject['process'] = processObject;
|
||||
|
||||
@@ -8,4 +8,5 @@ export type HostToWorkerRenderContext = {
|
||||
applicationAccessToken?: string;
|
||||
apiUrl?: string;
|
||||
sdkClientUrls?: SdkClientUrls;
|
||||
applicationVariables?: Record<string, string>;
|
||||
};
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 134 KiB |
@@ -270,15 +270,13 @@ export type FeatureFlag = {
|
||||
};
|
||||
|
||||
export enum FeatureFlagKey {
|
||||
IS_BILLING_V2_ENABLED = 'IS_BILLING_V2_ENABLED',
|
||||
IS_EMAILING_DOMAIN_ENABLED = 'IS_EMAILING_DOMAIN_ENABLED',
|
||||
IS_EMAIL_GROUP_ENABLED = 'IS_EMAIL_GROUP_ENABLED',
|
||||
IS_JSON_FILTER_ENABLED = 'IS_JSON_FILTER_ENABLED',
|
||||
IS_JUNCTION_RELATIONS_ENABLED = 'IS_JUNCTION_RELATIONS_ENABLED',
|
||||
IS_MARKETPLACE_SETTING_TAB_VISIBLE = 'IS_MARKETPLACE_SETTING_TAB_VISIBLE',
|
||||
IS_PUBLIC_DOMAIN_ENABLED = 'IS_PUBLIC_DOMAIN_ENABLED',
|
||||
IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED = 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED',
|
||||
IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED = 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED',
|
||||
IS_REST_METADATA_API_NEW_FORMAT_DIRECT = 'IS_REST_METADATA_API_NEW_FORMAT_DIRECT',
|
||||
IS_UNIQUE_INDEXES_ENABLED = 'IS_UNIQUE_INDEXES_ENABLED'
|
||||
}
|
||||
|
||||
@@ -294,6 +292,7 @@ export type InstanceAndAllWorkspacesUpgradeStatus = {
|
||||
__typename?: 'InstanceAndAllWorkspacesUpgradeStatus';
|
||||
computedAt: Scalars['DateTime'];
|
||||
instanceUpgradeStatus: InstanceUpgradeStatus;
|
||||
upToDateWorkspaceCount: Scalars['Int'];
|
||||
workspacesBehind: Array<WorkspaceUpgradeRef>;
|
||||
workspacesFailed: Array<WorkspaceUpgradeRef>;
|
||||
};
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -236,10 +236,10 @@ msgstr "{agentLabel} Agentrol"
|
||||
msgid "{aggregateLabel} of {fieldLabel}"
|
||||
msgstr "{aggregateLabel} van {fieldLabel}"
|
||||
|
||||
#. js-lingui-id: LTvJAf
|
||||
#. js-lingui-id: ZZZxmp
|
||||
#: src/pages/auth/Authorize.tsx
|
||||
msgid "{appName} wants to access your account"
|
||||
msgstr "{appName} wil toegang tot jou rekening hê"
|
||||
msgid "{appName} would like to:"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: y9covz
|
||||
#: src/pages/settings/admin-panel/SettingsAdminWorkspacesStatus.tsx
|
||||
@@ -266,11 +266,6 @@ msgstr "{contextStoreNumberOfSelectedRecords} geselekteer"
|
||||
msgid "{count, plural, one {E.g. {0}{1} for {count} decimal} other {E.g. {2}{3} for {count} decimals}}"
|
||||
msgstr "{count, plural, one {Byv. {0}{1} vir {count} desimaal} other {Byv. {2}{3} vir {count} desimale}}"
|
||||
|
||||
#. js-lingui-id: aTq2js
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "{credits} Credits - ${price}"
|
||||
msgstr "{credits} Krediete - ${price}"
|
||||
|
||||
#. js-lingui-id: q8RNNe
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
msgid "{credits} Credits - ${priceDisplay}"
|
||||
@@ -808,10 +803,10 @@ msgstr ""
|
||||
msgid "Access Key ID"
|
||||
msgstr "Toegangsleutel-ID"
|
||||
|
||||
#. js-lingui-id: o0Ci6l
|
||||
#. js-lingui-id: CrjDqe
|
||||
#: src/pages/auth/Authorize.tsx
|
||||
msgid "Access workspace data"
|
||||
msgstr "Toegang tot werkruimtedata"
|
||||
msgid "Access your workspace data"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: c2UA7k
|
||||
#: src/pages/settings/ai/components/SettingsAiMCP.tsx
|
||||
@@ -1326,6 +1321,7 @@ msgstr "By swartlys gevoeg"
|
||||
#: src/modules/ui/field/input/components/AddressInput.tsx
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Address 1"
|
||||
msgstr "Adres 1"
|
||||
|
||||
@@ -1333,6 +1329,7 @@ msgstr "Adres 1"
|
||||
#: src/modules/ui/field/input/components/AddressInput.tsx
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Address 2"
|
||||
msgstr "Adres 2"
|
||||
|
||||
@@ -2332,6 +2329,7 @@ msgstr "oplopend"
|
||||
|
||||
#. js-lingui-id: nYD/Cq
|
||||
#: src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsSorts.tsx
|
||||
#: src/modules/views/editable-chip/components/EditableSortChip.tsx
|
||||
#: src/modules/side-panel/pages/page-layout/components/record-table-settings/RecordTableSettingsSorts.tsx
|
||||
#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
|
||||
#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
|
||||
@@ -3044,16 +3042,6 @@ msgstr "Kanselleer intervalwisseling"
|
||||
msgid "Cancel interval switching?"
|
||||
msgstr "Kanselleer intervalwisseling?"
|
||||
|
||||
#. js-lingui-id: /Dmw1h
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Cancel metered tier switching"
|
||||
msgstr "Kanselleer gemeterde vlakwisseling"
|
||||
|
||||
#. js-lingui-id: Q/chGD
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Cancel metered tier switching?"
|
||||
msgstr "Kanselleer gemeterde vlakwisseling?"
|
||||
|
||||
#. js-lingui-id: rRK/Lf
|
||||
#: src/pages/settings/enterprise/SettingsEnterprise.tsx
|
||||
#: src/modules/settings/billing/components/SettingsBillingContent.tsx
|
||||
@@ -3367,6 +3355,7 @@ msgstr "Kies jou Proeflopie"
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "City"
|
||||
msgstr "Stad"
|
||||
|
||||
@@ -3795,11 +3784,6 @@ msgstr "Opgestel"
|
||||
msgid "Confirm"
|
||||
msgstr "Bevestig"
|
||||
|
||||
#. js-lingui-id: qmnX/6
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Confirm changing your current credit plan."
|
||||
msgstr "Bevestig dat jy jou huidige kredietplan verander."
|
||||
|
||||
#. js-lingui-id: q2rgqr
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
msgid "Confirm changing your current resource credit allocation."
|
||||
@@ -3812,7 +3796,6 @@ msgstr "Bevestig verwydering van {roleName} rol? Dit kan nie ongedaan gemaak wor
|
||||
|
||||
#. js-lingui-id: kZkFSm
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Confirm downgrade"
|
||||
msgstr "Bevestig verlaagde gradering"
|
||||
|
||||
@@ -3823,10 +3806,14 @@ msgstr "Bevestig rolopdatering"
|
||||
|
||||
#. js-lingui-id: DDbn3x
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Confirm upgrade"
|
||||
msgstr "Bevestig opgradering"
|
||||
|
||||
#. js-lingui-id: LOM1MR
|
||||
#: src/pages/auth/Authorize.tsx
|
||||
msgid "Connect {appName} to your account"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: mFiwDA
|
||||
#: src/pages/settings/applications/components/SettingsApplicationConnectScopePickerModal.tsx
|
||||
msgid "Connect {providerDisplayName}"
|
||||
@@ -4128,7 +4115,6 @@ msgid "Core Objects"
|
||||
msgstr "Kernobjekte"
|
||||
|
||||
#. js-lingui-id: I99Miw
|
||||
#: src/modules/settings/billing/components/SettingsBillingCreditsSection.tsx
|
||||
#: src/modules/ai/components/internal/AiChatContextUsageButton.tsx
|
||||
msgid "Cost"
|
||||
msgstr "Koste"
|
||||
@@ -4138,11 +4124,6 @@ msgstr "Koste"
|
||||
msgid "Cost per 1M tokens"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: HUPoL8
|
||||
#: src/modules/settings/billing/components/SettingsBillingCreditsSection.tsx
|
||||
msgid "Cost per Extra Credits"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: 3X5ngu
|
||||
#: src/pages/settings/admin-panel/SettingsAdminNewAiModel.tsx
|
||||
msgid "Cost per million tokens (USD)"
|
||||
@@ -4225,6 +4206,7 @@ msgstr "Tel unieke waardes"
|
||||
#: src/modules/ui/field/input/components/AddressInput.tsx
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Country"
|
||||
msgstr "Land"
|
||||
|
||||
@@ -4425,11 +4407,6 @@ msgstr "Kredietverbruik oor tyd."
|
||||
msgid "Credit pack switching has been cancelled."
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: Efny36
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Credit Plan"
|
||||
msgstr "Kredietkaart Plan"
|
||||
|
||||
#. js-lingui-id: qtEx+T
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
msgid "Credit plan upgraded."
|
||||
@@ -5331,6 +5308,7 @@ msgstr "aflopend"
|
||||
|
||||
#. js-lingui-id: Cko536
|
||||
#: src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsSorts.tsx
|
||||
#: src/modules/views/editable-chip/components/EditableSortChip.tsx
|
||||
#: src/modules/side-panel/pages/page-layout/components/record-table-settings/RecordTableSettingsSorts.tsx
|
||||
#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
|
||||
#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
|
||||
@@ -5560,8 +5538,6 @@ msgstr ""
|
||||
#. js-lingui-id: LE8J+K
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Downgrade"
|
||||
msgstr "Verlaagde gradering"
|
||||
|
||||
@@ -6560,11 +6536,6 @@ msgstr ""
|
||||
msgid "Error while cancelling interval switching."
|
||||
msgstr "Fout tydens die kansellasie van intervalwisseling."
|
||||
|
||||
#. js-lingui-id: a1gs9Y
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Error while cancelling metered tier switching."
|
||||
msgstr "Fout tydens die kansellasie van gemeterde vlakwisseling."
|
||||
|
||||
#. js-lingui-id: FS6DQK
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Error while cancelling plan switching."
|
||||
@@ -6888,11 +6859,6 @@ msgstr ""
|
||||
msgid "Expression"
|
||||
msgstr "Uitdrukking"
|
||||
|
||||
#. js-lingui-id: uE7S0L
|
||||
#: src/modules/settings/billing/components/SettingsBillingCreditsSection.tsx
|
||||
msgid "Extra Credits Used"
|
||||
msgstr "Ekstra Krediete Gebruik"
|
||||
|
||||
#. js-lingui-id: 7Bj3x9
|
||||
#: src/pages/settings/emailing-domains/utils/getEmailingDomainStatusText.ts
|
||||
#: src/pages/settings/admin-panel/SettingsAdminInstanceStatus.tsx
|
||||
@@ -7111,11 +7077,6 @@ msgstr ""
|
||||
msgid "Failed to update model selection mode"
|
||||
msgstr "Kon nie modelkeusemodus opdateer nie"
|
||||
|
||||
#. js-lingui-id: HnBqPY
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Failed to update price."
|
||||
msgstr "Kon nie prys opdateer nie."
|
||||
|
||||
#. js-lingui-id: J7vly7
|
||||
#: src/modules/object-record/record-update-multiple/components/UpdateMultipleRecordsContainer.tsx
|
||||
msgid "Failed to update records. Please try again."
|
||||
@@ -7483,6 +7444,11 @@ msgstr "Eerste 2 reëls"
|
||||
msgid "First 5 lines"
|
||||
msgstr "Eerste 5 reëls"
|
||||
|
||||
#. js-lingui-id: V1EGGU
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "First name"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: kODvZJ
|
||||
#: src/pages/onboarding/CreateProfile.tsx
|
||||
#: src/modules/settings/security/components/SettingsSecurityEditableProfileFields.tsx
|
||||
@@ -9062,6 +9028,7 @@ msgstr "Laaste boodskap {lastMessageSentAtFormatted}"
|
||||
|
||||
#. js-lingui-id: 1ZaQUH
|
||||
#: src/modules/settings/members/components/MemberNameFields.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Last name"
|
||||
msgstr ""
|
||||
|
||||
@@ -9122,6 +9089,11 @@ msgstr "Nuutste datum"
|
||||
msgid "Latest version"
|
||||
msgstr "Nuutste weergawe"
|
||||
|
||||
#. js-lingui-id: Q7hYLw
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Latitude"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: ZEP8tT
|
||||
#: src/modules/settings/playground/components/PlaygroundSetupForm.tsx
|
||||
msgid "Launch"
|
||||
@@ -9499,6 +9471,11 @@ msgstr "Teken uit"
|
||||
msgid "Logs"
|
||||
msgstr "Logboeke"
|
||||
|
||||
#. js-lingui-id: FJBbw5
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Longitude"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: tL2lBI
|
||||
#: src/modules/workflow/workflow-diagram/utils/generateNodesAndEdgesForIteratorNode.ts
|
||||
msgid "loop"
|
||||
@@ -9810,11 +9787,6 @@ msgstr "Metadata"
|
||||
msgid "Metadata file generation failed"
|
||||
msgstr "Metadataleêr generasie het misluk"
|
||||
|
||||
#. js-lingui-id: onCJJ6
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Metered tier switching has been cancelled."
|
||||
msgstr "Gemeterde vlakwisseling is gekanselleer."
|
||||
|
||||
#. js-lingui-id: fiPesM
|
||||
#: src/modules/settings/logic-functions/components/triggers/SettingsLogicFunctionHttpTriggerSection.tsx
|
||||
msgid "Method"
|
||||
@@ -11169,7 +11141,6 @@ msgstr "Aantal desimale"
|
||||
|
||||
#. js-lingui-id: tYOaY8
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Number of new credits allocated every {recurringInterval}"
|
||||
msgstr "Aantal nuwe krediete toegeken elke {recurringInterval}"
|
||||
|
||||
@@ -12046,7 +12017,6 @@ msgstr "Kies asseblief ten minste een bestemmingsobjek vir hierdie verhouding."
|
||||
|
||||
#. js-lingui-id: 8YnlGz
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Please start your subscription first"
|
||||
msgstr "Begin asseblief eers met jou inskrywing"
|
||||
|
||||
@@ -12125,6 +12095,7 @@ msgstr ""
|
||||
|
||||
#. js-lingui-id: OKJUcC
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Postcode"
|
||||
msgstr "Poskode"
|
||||
|
||||
@@ -12175,11 +12146,6 @@ msgstr "Vorige"
|
||||
msgid "Previous 7 days"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: jmc+FY
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Price updated."
|
||||
msgstr "Prys opdateer."
|
||||
|
||||
#. js-lingui-id: aHCEmh
|
||||
#: src/pages/settings/admin-panel/SettingsAdminNewAiModel.tsx
|
||||
msgid "Pricing"
|
||||
@@ -14569,6 +14535,7 @@ msgstr "Verifikasiestelsel begin"
|
||||
#: src/modules/settings/admin-panel/health-status/components/SettingsAdminQueueJobsTable.tsx
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "State"
|
||||
msgstr "Staat"
|
||||
|
||||
@@ -16316,8 +16283,6 @@ msgstr "Opdaterings"
|
||||
#: src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelSection.tsx
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
msgid "Upgrade"
|
||||
@@ -16362,9 +16327,9 @@ msgstr ""
|
||||
msgid "Upgrade to {latestAvailableVersion}"
|
||||
msgstr "Opgradeer na {latestAvailableVersion}"
|
||||
|
||||
#. js-lingui-id: tLOGrv
|
||||
#. js-lingui-id: Kutw4+
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
msgid "Upgrade to {nextTierCredits} credits for ${nextTierPrice}/{nextTierInterval}."
|
||||
msgid "Upgrade to {nextResourceCreditsAmount} credits for ${nextResourceCreditPrice}/{nextTierInterval}."
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: ggd+Ee
|
||||
@@ -17545,11 +17510,6 @@ msgstr ""
|
||||
msgid "You have scheduled a credit pack change. Do you want to cancel it?"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: M2lYgq
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "You have scheduled a metered tier change. Do you want to cancel it?"
|
||||
msgstr "Jy het 'n geskeduleerde gemeterde vlakverandering. Wil jy dit kanselleer?"
|
||||
|
||||
#. js-lingui-id: z8eKS7
|
||||
#: src/modules/settings/billing/hooks/useBillingWording.ts
|
||||
msgid "you will be charged ${enterprisePrice} per user per month"
|
||||
@@ -17587,11 +17547,11 @@ msgid ""
|
||||
"Reach to our support team to upgrade."
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: UUaKVD
|
||||
#. js-lingui-id: /fksQo
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
msgid ""
|
||||
"You've hit your usage limit. \n"
|
||||
"Upgrade to {nextTierCredits} credits for ${nextTierPrice}/{nextTierInterval}."
|
||||
"Upgrade to {nextResourceCreditsAmount} credits for ${nextResourceCreditPrice}/{nextTierInterval}."
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: yZ0wRS
|
||||
|
||||
@@ -236,10 +236,10 @@ msgstr "دور الوكيل {agentLabel}"
|
||||
msgid "{aggregateLabel} of {fieldLabel}"
|
||||
msgstr "{aggregateLabel} من {fieldLabel}"
|
||||
|
||||
#. js-lingui-id: LTvJAf
|
||||
#. js-lingui-id: ZZZxmp
|
||||
#: src/pages/auth/Authorize.tsx
|
||||
msgid "{appName} wants to access your account"
|
||||
msgstr "{appName} يريد الوصول إلى حسابك"
|
||||
msgid "{appName} would like to:"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: y9covz
|
||||
#: src/pages/settings/admin-panel/SettingsAdminWorkspacesStatus.tsx
|
||||
@@ -266,11 +266,6 @@ msgstr "{contextStoreNumberOfSelectedRecords} مُختار"
|
||||
msgid "{count, plural, one {E.g. {0}{1} for {count} decimal} other {E.g. {2}{3} for {count} decimals}}"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: aTq2js
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "{credits} Credits - ${price}"
|
||||
msgstr "{credits, plural, zero {لا اعتمادات} one {اعتماد واحد} two {اعتمادان} few {# اعتمادات} many {# اعتمادًا} other {# اعتماد}} - ${price}"
|
||||
|
||||
#. js-lingui-id: q8RNNe
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
msgid "{credits} Credits - ${priceDisplay}"
|
||||
@@ -808,10 +803,10 @@ msgstr ""
|
||||
msgid "Access Key ID"
|
||||
msgstr "معرّف مفتاح الوصول"
|
||||
|
||||
#. js-lingui-id: o0Ci6l
|
||||
#. js-lingui-id: CrjDqe
|
||||
#: src/pages/auth/Authorize.tsx
|
||||
msgid "Access workspace data"
|
||||
msgstr "الوصول إلى بيانات مساحة العمل"
|
||||
msgid "Access your workspace data"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: c2UA7k
|
||||
#: src/pages/settings/ai/components/SettingsAiMCP.tsx
|
||||
@@ -1326,6 +1321,7 @@ msgstr "أضيف إلى القائمة السوداء"
|
||||
#: src/modules/ui/field/input/components/AddressInput.tsx
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Address 1"
|
||||
msgstr "العنوان 1"
|
||||
|
||||
@@ -1333,6 +1329,7 @@ msgstr "العنوان 1"
|
||||
#: src/modules/ui/field/input/components/AddressInput.tsx
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Address 2"
|
||||
msgstr "العنوان 2"
|
||||
|
||||
@@ -2332,6 +2329,7 @@ msgstr "تصاعدي"
|
||||
|
||||
#. js-lingui-id: nYD/Cq
|
||||
#: src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsSorts.tsx
|
||||
#: src/modules/views/editable-chip/components/EditableSortChip.tsx
|
||||
#: src/modules/side-panel/pages/page-layout/components/record-table-settings/RecordTableSettingsSorts.tsx
|
||||
#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
|
||||
#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
|
||||
@@ -3044,16 +3042,6 @@ msgstr "إلغاء تبديل الفاصل الزمني"
|
||||
msgid "Cancel interval switching?"
|
||||
msgstr "إلغاء تبديل الفاصل الزمني؟"
|
||||
|
||||
#. js-lingui-id: /Dmw1h
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Cancel metered tier switching"
|
||||
msgstr "إلغاء تبديل الطبقة المقاسة"
|
||||
|
||||
#. js-lingui-id: Q/chGD
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Cancel metered tier switching?"
|
||||
msgstr "إلغاء تبديل الطبقة المقاسة؟"
|
||||
|
||||
#. js-lingui-id: rRK/Lf
|
||||
#: src/pages/settings/enterprise/SettingsEnterprise.tsx
|
||||
#: src/modules/settings/billing/components/SettingsBillingContent.tsx
|
||||
@@ -3367,6 +3355,7 @@ msgstr "اختر تجربتك"
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "City"
|
||||
msgstr "المدينة"
|
||||
|
||||
@@ -3795,11 +3784,6 @@ msgstr "تم الإعداد"
|
||||
msgid "Confirm"
|
||||
msgstr "تأكيد"
|
||||
|
||||
#. js-lingui-id: qmnX/6
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Confirm changing your current credit plan."
|
||||
msgstr "تأكيد تغيير خطة الائتمان الحالية الخاصة بك."
|
||||
|
||||
#. js-lingui-id: q2rgqr
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
msgid "Confirm changing your current resource credit allocation."
|
||||
@@ -3812,7 +3796,6 @@ msgstr "تأكيد حذف دور {roleName}؟ لا يمكن التراجع عن
|
||||
|
||||
#. js-lingui-id: kZkFSm
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Confirm downgrade"
|
||||
msgstr "تأكيد الترقية"
|
||||
|
||||
@@ -3823,10 +3806,14 @@ msgstr "تأكيد تحديث الدور"
|
||||
|
||||
#. js-lingui-id: DDbn3x
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Confirm upgrade"
|
||||
msgstr "تأكيد التحديث"
|
||||
|
||||
#. js-lingui-id: LOM1MR
|
||||
#: src/pages/auth/Authorize.tsx
|
||||
msgid "Connect {appName} to your account"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: mFiwDA
|
||||
#: src/pages/settings/applications/components/SettingsApplicationConnectScopePickerModal.tsx
|
||||
msgid "Connect {providerDisplayName}"
|
||||
@@ -4128,7 +4115,6 @@ msgid "Core Objects"
|
||||
msgstr "الكائنات الأساسية"
|
||||
|
||||
#. js-lingui-id: I99Miw
|
||||
#: src/modules/settings/billing/components/SettingsBillingCreditsSection.tsx
|
||||
#: src/modules/ai/components/internal/AiChatContextUsageButton.tsx
|
||||
msgid "Cost"
|
||||
msgstr "التكلفة"
|
||||
@@ -4138,11 +4124,6 @@ msgstr "التكلفة"
|
||||
msgid "Cost per 1M tokens"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: HUPoL8
|
||||
#: src/modules/settings/billing/components/SettingsBillingCreditsSection.tsx
|
||||
msgid "Cost per Extra Credits"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: 3X5ngu
|
||||
#: src/pages/settings/admin-panel/SettingsAdminNewAiModel.tsx
|
||||
msgid "Cost per million tokens (USD)"
|
||||
@@ -4225,6 +4206,7 @@ msgstr "عدّ القيم الفريدة"
|
||||
#: src/modules/ui/field/input/components/AddressInput.tsx
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Country"
|
||||
msgstr "البلد"
|
||||
|
||||
@@ -4425,11 +4407,6 @@ msgstr "استهلاك الرصيد بمرور الوقت."
|
||||
msgid "Credit pack switching has been cancelled."
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: Efny36
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Credit Plan"
|
||||
msgstr "خطة الرصيد"
|
||||
|
||||
#. js-lingui-id: qtEx+T
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
msgid "Credit plan upgraded."
|
||||
@@ -5331,6 +5308,7 @@ msgstr "تنازلي"
|
||||
|
||||
#. js-lingui-id: Cko536
|
||||
#: src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsSorts.tsx
|
||||
#: src/modules/views/editable-chip/components/EditableSortChip.tsx
|
||||
#: src/modules/side-panel/pages/page-layout/components/record-table-settings/RecordTableSettingsSorts.tsx
|
||||
#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
|
||||
#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
|
||||
@@ -5560,8 +5538,6 @@ msgstr ""
|
||||
#. js-lingui-id: LE8J+K
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Downgrade"
|
||||
msgstr "خفض المستوى"
|
||||
|
||||
@@ -6560,11 +6536,6 @@ msgstr ""
|
||||
msgid "Error while cancelling interval switching."
|
||||
msgstr "خطأ أثناء إلغاء تبديل الفاصل الزمني."
|
||||
|
||||
#. js-lingui-id: a1gs9Y
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Error while cancelling metered tier switching."
|
||||
msgstr "خطأ أثناء إلغاء تبديل الطبقة المقاسة."
|
||||
|
||||
#. js-lingui-id: FS6DQK
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Error while cancelling plan switching."
|
||||
@@ -6888,11 +6859,6 @@ msgstr ""
|
||||
msgid "Expression"
|
||||
msgstr "تعبير"
|
||||
|
||||
#. js-lingui-id: uE7S0L
|
||||
#: src/modules/settings/billing/components/SettingsBillingCreditsSection.tsx
|
||||
msgid "Extra Credits Used"
|
||||
msgstr "الإعتمادات الإضافية المستخدمة"
|
||||
|
||||
#. js-lingui-id: 7Bj3x9
|
||||
#: src/pages/settings/emailing-domains/utils/getEmailingDomainStatusText.ts
|
||||
#: src/pages/settings/admin-panel/SettingsAdminInstanceStatus.tsx
|
||||
@@ -7111,11 +7077,6 @@ msgstr ""
|
||||
msgid "Failed to update model selection mode"
|
||||
msgstr "فشل في تحديث وضع اختيار النموذج"
|
||||
|
||||
#. js-lingui-id: HnBqPY
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Failed to update price."
|
||||
msgstr "فشل في تحديث السعر."
|
||||
|
||||
#. js-lingui-id: J7vly7
|
||||
#: src/modules/object-record/record-update-multiple/components/UpdateMultipleRecordsContainer.tsx
|
||||
msgid "Failed to update records. Please try again."
|
||||
@@ -7483,6 +7444,11 @@ msgstr "أول خطين ٢"
|
||||
msgid "First 5 lines"
|
||||
msgstr "أول 5 خطوط"
|
||||
|
||||
#. js-lingui-id: V1EGGU
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "First name"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: kODvZJ
|
||||
#: src/pages/onboarding/CreateProfile.tsx
|
||||
#: src/modules/settings/security/components/SettingsSecurityEditableProfileFields.tsx
|
||||
@@ -9062,6 +9028,7 @@ msgstr "آخر رسالة {lastMessageSentAtFormatted}"
|
||||
|
||||
#. js-lingui-id: 1ZaQUH
|
||||
#: src/modules/settings/members/components/MemberNameFields.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Last name"
|
||||
msgstr ""
|
||||
|
||||
@@ -9122,6 +9089,11 @@ msgstr "تاريخ الأحدث"
|
||||
msgid "Latest version"
|
||||
msgstr "أحدث إصدار"
|
||||
|
||||
#. js-lingui-id: Q7hYLw
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Latitude"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: ZEP8tT
|
||||
#: src/modules/settings/playground/components/PlaygroundSetupForm.tsx
|
||||
msgid "Launch"
|
||||
@@ -9499,6 +9471,11 @@ msgstr "تسجيل الخروج"
|
||||
msgid "Logs"
|
||||
msgstr "السجلات"
|
||||
|
||||
#. js-lingui-id: FJBbw5
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Longitude"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: tL2lBI
|
||||
#: src/modules/workflow/workflow-diagram/utils/generateNodesAndEdgesForIteratorNode.ts
|
||||
msgid "loop"
|
||||
@@ -9810,11 +9787,6 @@ msgstr "البيانات الوصفية"
|
||||
msgid "Metadata file generation failed"
|
||||
msgstr "فشل في توليد ملف البيانات الوصفية"
|
||||
|
||||
#. js-lingui-id: onCJJ6
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Metered tier switching has been cancelled."
|
||||
msgstr "تم إلغاء تبديل الطبقة المقاسة."
|
||||
|
||||
#. js-lingui-id: fiPesM
|
||||
#: src/modules/settings/logic-functions/components/triggers/SettingsLogicFunctionHttpTriggerSection.tsx
|
||||
msgid "Method"
|
||||
@@ -11169,7 +11141,6 @@ msgstr "عدد الكسور العشرية"
|
||||
|
||||
#. js-lingui-id: tYOaY8
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Number of new credits allocated every {recurringInterval}"
|
||||
msgstr "عدد الاعتمادات الجديدة المخصصة كل {recurringInterval}"
|
||||
|
||||
@@ -12046,7 +12017,6 @@ msgstr "يُرجى اختيار كائن وجهة واحد على الأقل ل
|
||||
|
||||
#. js-lingui-id: 8YnlGz
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Please start your subscription first"
|
||||
msgstr "يرجى بدء اشتراكك أولاً"
|
||||
|
||||
@@ -12125,6 +12095,7 @@ msgstr ""
|
||||
|
||||
#. js-lingui-id: OKJUcC
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Postcode"
|
||||
msgstr "الرمز البريدي"
|
||||
|
||||
@@ -12175,11 +12146,6 @@ msgstr "السابق"
|
||||
msgid "Previous 7 days"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: jmc+FY
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Price updated."
|
||||
msgstr "تم تحديث السعر."
|
||||
|
||||
#. js-lingui-id: aHCEmh
|
||||
#: src/pages/settings/admin-panel/SettingsAdminNewAiModel.tsx
|
||||
msgid "Pricing"
|
||||
@@ -14569,6 +14535,7 @@ msgstr "تم بدء عملية التحقق"
|
||||
#: src/modules/settings/admin-panel/health-status/components/SettingsAdminQueueJobsTable.tsx
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "State"
|
||||
msgstr "الولاية"
|
||||
|
||||
@@ -16316,8 +16283,6 @@ msgstr "التحديثات"
|
||||
#: src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelSection.tsx
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
msgid "Upgrade"
|
||||
@@ -16362,9 +16327,9 @@ msgstr ""
|
||||
msgid "Upgrade to {latestAvailableVersion}"
|
||||
msgstr "الترقية إلى {latestAvailableVersion}"
|
||||
|
||||
#. js-lingui-id: tLOGrv
|
||||
#. js-lingui-id: Kutw4+
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
msgid "Upgrade to {nextTierCredits} credits for ${nextTierPrice}/{nextTierInterval}."
|
||||
msgid "Upgrade to {nextResourceCreditsAmount} credits for ${nextResourceCreditPrice}/{nextTierInterval}."
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: ggd+Ee
|
||||
@@ -17543,11 +17508,6 @@ msgstr ""
|
||||
msgid "You have scheduled a credit pack change. Do you want to cancel it?"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: M2lYgq
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "You have scheduled a metered tier change. Do you want to cancel it?"
|
||||
msgstr "لقد قمت بجدولة تغيير الطبقة المقاسة. هل تريد إلغاؤه؟"
|
||||
|
||||
#. js-lingui-id: z8eKS7
|
||||
#: src/modules/settings/billing/hooks/useBillingWording.ts
|
||||
msgid "you will be charged ${enterprisePrice} per user per month"
|
||||
@@ -17585,11 +17545,11 @@ msgid ""
|
||||
"Reach to our support team to upgrade."
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: UUaKVD
|
||||
#. js-lingui-id: /fksQo
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
msgid ""
|
||||
"You've hit your usage limit. \n"
|
||||
"Upgrade to {nextTierCredits} credits for ${nextTierPrice}/{nextTierInterval}."
|
||||
"Upgrade to {nextResourceCreditsAmount} credits for ${nextResourceCreditPrice}/{nextTierInterval}."
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: yZ0wRS
|
||||
|
||||
@@ -236,10 +236,10 @@ msgstr "Rol d'agent {agentLabel}"
|
||||
msgid "{aggregateLabel} of {fieldLabel}"
|
||||
msgstr "{aggregateLabel} de {fieldLabel}"
|
||||
|
||||
#. js-lingui-id: LTvJAf
|
||||
#. js-lingui-id: ZZZxmp
|
||||
#: src/pages/auth/Authorize.tsx
|
||||
msgid "{appName} wants to access your account"
|
||||
msgstr "{appName} vol accedir al teu compte"
|
||||
msgid "{appName} would like to:"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: y9covz
|
||||
#: src/pages/settings/admin-panel/SettingsAdminWorkspacesStatus.tsx
|
||||
@@ -266,11 +266,6 @@ msgstr "{contextStoreNumberOfSelectedRecords} seleccionats"
|
||||
msgid "{count, plural, one {E.g. {0}{1} for {count} decimal} other {E.g. {2}{3} for {count} decimals}}"
|
||||
msgstr "{count, plural, one {Ex. {0}{1} per {count} decimal} other {Ex. {2}{3} per {count} decimals}}"
|
||||
|
||||
#. js-lingui-id: aTq2js
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "{credits} Credits - ${price}"
|
||||
msgstr "{credits} crèdits - ${price}"
|
||||
|
||||
#. js-lingui-id: q8RNNe
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
msgid "{credits} Credits - ${priceDisplay}"
|
||||
@@ -808,10 +803,10 @@ msgstr ""
|
||||
msgid "Access Key ID"
|
||||
msgstr "ID de la clau d'accés"
|
||||
|
||||
#. js-lingui-id: o0Ci6l
|
||||
#. js-lingui-id: CrjDqe
|
||||
#: src/pages/auth/Authorize.tsx
|
||||
msgid "Access workspace data"
|
||||
msgstr "Accedir a les dades de l'espai de treball"
|
||||
msgid "Access your workspace data"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: c2UA7k
|
||||
#: src/pages/settings/ai/components/SettingsAiMCP.tsx
|
||||
@@ -1326,6 +1321,7 @@ msgstr "Afegit a la llista de bloqueig"
|
||||
#: src/modules/ui/field/input/components/AddressInput.tsx
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Address 1"
|
||||
msgstr "Adreça 1"
|
||||
|
||||
@@ -1333,6 +1329,7 @@ msgstr "Adreça 1"
|
||||
#: src/modules/ui/field/input/components/AddressInput.tsx
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Address 2"
|
||||
msgstr "Adreça 2"
|
||||
|
||||
@@ -2332,6 +2329,7 @@ msgstr "ascendent"
|
||||
|
||||
#. js-lingui-id: nYD/Cq
|
||||
#: src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsSorts.tsx
|
||||
#: src/modules/views/editable-chip/components/EditableSortChip.tsx
|
||||
#: src/modules/side-panel/pages/page-layout/components/record-table-settings/RecordTableSettingsSorts.tsx
|
||||
#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
|
||||
#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
|
||||
@@ -3044,16 +3042,6 @@ msgstr "Cancel·lar el canvi d'interval"
|
||||
msgid "Cancel interval switching?"
|
||||
msgstr "Cancel·lar el canvi d'interval?"
|
||||
|
||||
#. js-lingui-id: /Dmw1h
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Cancel metered tier switching"
|
||||
msgstr "Cancel·lar el canvi de nivell mesurat"
|
||||
|
||||
#. js-lingui-id: Q/chGD
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Cancel metered tier switching?"
|
||||
msgstr "Cancel·lar el canvi de nivell mesurat?"
|
||||
|
||||
#. js-lingui-id: rRK/Lf
|
||||
#: src/pages/settings/enterprise/SettingsEnterprise.tsx
|
||||
#: src/modules/settings/billing/components/SettingsBillingContent.tsx
|
||||
@@ -3367,6 +3355,7 @@ msgstr "Trieu la vostra prova"
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "City"
|
||||
msgstr "Ciutat"
|
||||
|
||||
@@ -3795,11 +3784,6 @@ msgstr "Configurat"
|
||||
msgid "Confirm"
|
||||
msgstr "Confirmar"
|
||||
|
||||
#. js-lingui-id: qmnX/6
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Confirm changing your current credit plan."
|
||||
msgstr "Confirma el canvi del teu pla de crèdit actual."
|
||||
|
||||
#. js-lingui-id: q2rgqr
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
msgid "Confirm changing your current resource credit allocation."
|
||||
@@ -3812,7 +3796,6 @@ msgstr "Confirmeu la supressió del rol {roleName}? Aquesta acció no es pot des
|
||||
|
||||
#. js-lingui-id: kZkFSm
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Confirm downgrade"
|
||||
msgstr "Confirmar la reducció"
|
||||
|
||||
@@ -3823,10 +3806,14 @@ msgstr "Confirmeu l'actualització del rol"
|
||||
|
||||
#. js-lingui-id: DDbn3x
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Confirm upgrade"
|
||||
msgstr "Confirmar la millora"
|
||||
|
||||
#. js-lingui-id: LOM1MR
|
||||
#: src/pages/auth/Authorize.tsx
|
||||
msgid "Connect {appName} to your account"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: mFiwDA
|
||||
#: src/pages/settings/applications/components/SettingsApplicationConnectScopePickerModal.tsx
|
||||
msgid "Connect {providerDisplayName}"
|
||||
@@ -4128,7 +4115,6 @@ msgid "Core Objects"
|
||||
msgstr "Objectes principals"
|
||||
|
||||
#. js-lingui-id: I99Miw
|
||||
#: src/modules/settings/billing/components/SettingsBillingCreditsSection.tsx
|
||||
#: src/modules/ai/components/internal/AiChatContextUsageButton.tsx
|
||||
msgid "Cost"
|
||||
msgstr "Cost"
|
||||
@@ -4138,11 +4124,6 @@ msgstr "Cost"
|
||||
msgid "Cost per 1M tokens"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: HUPoL8
|
||||
#: src/modules/settings/billing/components/SettingsBillingCreditsSection.tsx
|
||||
msgid "Cost per Extra Credits"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: 3X5ngu
|
||||
#: src/pages/settings/admin-panel/SettingsAdminNewAiModel.tsx
|
||||
msgid "Cost per million tokens (USD)"
|
||||
@@ -4225,6 +4206,7 @@ msgstr "Compta valors únics"
|
||||
#: src/modules/ui/field/input/components/AddressInput.tsx
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Country"
|
||||
msgstr "País"
|
||||
|
||||
@@ -4425,11 +4407,6 @@ msgstr "Consum de crèdits al llarg del temps."
|
||||
msgid "Credit pack switching has been cancelled."
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: Efny36
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Credit Plan"
|
||||
msgstr "Pla de crèdit"
|
||||
|
||||
#. js-lingui-id: qtEx+T
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
msgid "Credit plan upgraded."
|
||||
@@ -5331,6 +5308,7 @@ msgstr "descendent"
|
||||
|
||||
#. js-lingui-id: Cko536
|
||||
#: src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsSorts.tsx
|
||||
#: src/modules/views/editable-chip/components/EditableSortChip.tsx
|
||||
#: src/modules/side-panel/pages/page-layout/components/record-table-settings/RecordTableSettingsSorts.tsx
|
||||
#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
|
||||
#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
|
||||
@@ -5560,8 +5538,6 @@ msgstr ""
|
||||
#. js-lingui-id: LE8J+K
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Downgrade"
|
||||
msgstr "Baixar de categoria"
|
||||
|
||||
@@ -6560,11 +6536,6 @@ msgstr ""
|
||||
msgid "Error while cancelling interval switching."
|
||||
msgstr "Error en cancel·lar el canvi d'interval."
|
||||
|
||||
#. js-lingui-id: a1gs9Y
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Error while cancelling metered tier switching."
|
||||
msgstr "Error en cancel·lar el canvi de nivell mesurat."
|
||||
|
||||
#. js-lingui-id: FS6DQK
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Error while cancelling plan switching."
|
||||
@@ -6888,11 +6859,6 @@ msgstr ""
|
||||
msgid "Expression"
|
||||
msgstr "Expressió"
|
||||
|
||||
#. js-lingui-id: uE7S0L
|
||||
#: src/modules/settings/billing/components/SettingsBillingCreditsSection.tsx
|
||||
msgid "Extra Credits Used"
|
||||
msgstr "Crèdits extres utilitzats"
|
||||
|
||||
#. js-lingui-id: 7Bj3x9
|
||||
#: src/pages/settings/emailing-domains/utils/getEmailingDomainStatusText.ts
|
||||
#: src/pages/settings/admin-panel/SettingsAdminInstanceStatus.tsx
|
||||
@@ -7111,11 +7077,6 @@ msgstr ""
|
||||
msgid "Failed to update model selection mode"
|
||||
msgstr "No s'ha pogut actualitzar el mode de selecció de models"
|
||||
|
||||
#. js-lingui-id: HnBqPY
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Failed to update price."
|
||||
msgstr "Ha fallat l'actualització del preu."
|
||||
|
||||
#. js-lingui-id: J7vly7
|
||||
#: src/modules/object-record/record-update-multiple/components/UpdateMultipleRecordsContainer.tsx
|
||||
msgid "Failed to update records. Please try again."
|
||||
@@ -7483,6 +7444,11 @@ msgstr "Primeres 2 línies"
|
||||
msgid "First 5 lines"
|
||||
msgstr "Primeres 5 línies"
|
||||
|
||||
#. js-lingui-id: V1EGGU
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "First name"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: kODvZJ
|
||||
#: src/pages/onboarding/CreateProfile.tsx
|
||||
#: src/modules/settings/security/components/SettingsSecurityEditableProfileFields.tsx
|
||||
@@ -9062,6 +9028,7 @@ msgstr "Últim missatge {lastMessageSentAtFormatted}"
|
||||
|
||||
#. js-lingui-id: 1ZaQUH
|
||||
#: src/modules/settings/members/components/MemberNameFields.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Last name"
|
||||
msgstr ""
|
||||
|
||||
@@ -9122,6 +9089,11 @@ msgstr "Data més recent"
|
||||
msgid "Latest version"
|
||||
msgstr "Última versió"
|
||||
|
||||
#. js-lingui-id: Q7hYLw
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Latitude"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: ZEP8tT
|
||||
#: src/modules/settings/playground/components/PlaygroundSetupForm.tsx
|
||||
msgid "Launch"
|
||||
@@ -9499,6 +9471,11 @@ msgstr "Tancar sessió"
|
||||
msgid "Logs"
|
||||
msgstr "Registres"
|
||||
|
||||
#. js-lingui-id: FJBbw5
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Longitude"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: tL2lBI
|
||||
#: src/modules/workflow/workflow-diagram/utils/generateNodesAndEdgesForIteratorNode.ts
|
||||
msgid "loop"
|
||||
@@ -9810,11 +9787,6 @@ msgstr "Metadades"
|
||||
msgid "Metadata file generation failed"
|
||||
msgstr "Error en la generació del fitxer de metadades"
|
||||
|
||||
#. js-lingui-id: onCJJ6
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Metered tier switching has been cancelled."
|
||||
msgstr "El canvi de nivell mesurat ha estat cancel·lat."
|
||||
|
||||
#. js-lingui-id: fiPesM
|
||||
#: src/modules/settings/logic-functions/components/triggers/SettingsLogicFunctionHttpTriggerSection.tsx
|
||||
msgid "Method"
|
||||
@@ -11169,7 +11141,6 @@ msgstr "Número de decimals"
|
||||
|
||||
#. js-lingui-id: tYOaY8
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Number of new credits allocated every {recurringInterval}"
|
||||
msgstr "Nombre de crèdits nous assignats cada {recurringInterval}"
|
||||
|
||||
@@ -12046,7 +12017,6 @@ msgstr "Si us plau, seleccioneu com a mínim un objecte de destinació per a aqu
|
||||
|
||||
#. js-lingui-id: 8YnlGz
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Please start your subscription first"
|
||||
msgstr "Si us plau, inicieu la vostra subscripció primer"
|
||||
|
||||
@@ -12125,6 +12095,7 @@ msgstr ""
|
||||
|
||||
#. js-lingui-id: OKJUcC
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Postcode"
|
||||
msgstr "Codi postal"
|
||||
|
||||
@@ -12175,11 +12146,6 @@ msgstr "Anterior"
|
||||
msgid "Previous 7 days"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: jmc+FY
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Price updated."
|
||||
msgstr "Preu actualitzat."
|
||||
|
||||
#. js-lingui-id: aHCEmh
|
||||
#: src/pages/settings/admin-panel/SettingsAdminNewAiModel.tsx
|
||||
msgid "Pricing"
|
||||
@@ -14569,6 +14535,7 @@ msgstr "S'ha iniciat el procés de verificació"
|
||||
#: src/modules/settings/admin-panel/health-status/components/SettingsAdminQueueJobsTable.tsx
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "State"
|
||||
msgstr "Estat"
|
||||
|
||||
@@ -16316,8 +16283,6 @@ msgstr "Actualitzacions"
|
||||
#: src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelSection.tsx
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
msgid "Upgrade"
|
||||
@@ -16362,9 +16327,9 @@ msgstr ""
|
||||
msgid "Upgrade to {latestAvailableVersion}"
|
||||
msgstr "Actualitza a {latestAvailableVersion}"
|
||||
|
||||
#. js-lingui-id: tLOGrv
|
||||
#. js-lingui-id: Kutw4+
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
msgid "Upgrade to {nextTierCredits} credits for ${nextTierPrice}/{nextTierInterval}."
|
||||
msgid "Upgrade to {nextResourceCreditsAmount} credits for ${nextResourceCreditPrice}/{nextTierInterval}."
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: ggd+Ee
|
||||
@@ -17545,11 +17510,6 @@ msgstr ""
|
||||
msgid "You have scheduled a credit pack change. Do you want to cancel it?"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: M2lYgq
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "You have scheduled a metered tier change. Do you want to cancel it?"
|
||||
msgstr "Has programat un canvi de nivell mesurat. Vols cancel·lar-lo?"
|
||||
|
||||
#. js-lingui-id: z8eKS7
|
||||
#: src/modules/settings/billing/hooks/useBillingWording.ts
|
||||
msgid "you will be charged ${enterprisePrice} per user per month"
|
||||
@@ -17587,11 +17547,11 @@ msgid ""
|
||||
"Reach to our support team to upgrade."
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: UUaKVD
|
||||
#. js-lingui-id: /fksQo
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
msgid ""
|
||||
"You've hit your usage limit. \n"
|
||||
"Upgrade to {nextTierCredits} credits for ${nextTierPrice}/{nextTierInterval}."
|
||||
"Upgrade to {nextResourceCreditsAmount} credits for ${nextResourceCreditPrice}/{nextTierInterval}."
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: yZ0wRS
|
||||
|
||||
@@ -236,10 +236,10 @@ msgstr "Role agenta {agentLabel}"
|
||||
msgid "{aggregateLabel} of {fieldLabel}"
|
||||
msgstr "{aggregateLabel} z {fieldLabel}"
|
||||
|
||||
#. js-lingui-id: LTvJAf
|
||||
#. js-lingui-id: ZZZxmp
|
||||
#: src/pages/auth/Authorize.tsx
|
||||
msgid "{appName} wants to access your account"
|
||||
msgstr "{appName} chce získat přístup k vašemu účtu"
|
||||
msgid "{appName} would like to:"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: y9covz
|
||||
#: src/pages/settings/admin-panel/SettingsAdminWorkspacesStatus.tsx
|
||||
@@ -266,11 +266,6 @@ msgstr "{contextStoreNumberOfSelectedRecords} vybrané"
|
||||
msgid "{count, plural, one {E.g. {0}{1} for {count} decimal} other {E.g. {2}{3} for {count} decimals}}"
|
||||
msgstr "{count, plural, one {Např. {0}{1} pro {count} desetinné místo} few {Např. {2}{3} pro {count} desetinná místa} many {Např. {2}{3} pro {count} desetinných míst} other {Např. {2}{3} pro {count} desetinných míst}}"
|
||||
|
||||
#. js-lingui-id: aTq2js
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "{credits} Credits - ${price}"
|
||||
msgstr "{credits} kreditů - ${price}"
|
||||
|
||||
#. js-lingui-id: q8RNNe
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
msgid "{credits} Credits - ${priceDisplay}"
|
||||
@@ -808,10 +803,10 @@ msgstr ""
|
||||
msgid "Access Key ID"
|
||||
msgstr "ID přístupového klíče"
|
||||
|
||||
#. js-lingui-id: o0Ci6l
|
||||
#. js-lingui-id: CrjDqe
|
||||
#: src/pages/auth/Authorize.tsx
|
||||
msgid "Access workspace data"
|
||||
msgstr "Přístup k datům pracovního prostoru"
|
||||
msgid "Access your workspace data"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: c2UA7k
|
||||
#: src/pages/settings/ai/components/SettingsAiMCP.tsx
|
||||
@@ -1326,6 +1321,7 @@ msgstr "Přidáno do blokovaného seznamu"
|
||||
#: src/modules/ui/field/input/components/AddressInput.tsx
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Address 1"
|
||||
msgstr "Adresa 1"
|
||||
|
||||
@@ -1333,6 +1329,7 @@ msgstr "Adresa 1"
|
||||
#: src/modules/ui/field/input/components/AddressInput.tsx
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Address 2"
|
||||
msgstr "Adresa 2"
|
||||
|
||||
@@ -2332,6 +2329,7 @@ msgstr "vzestupně"
|
||||
|
||||
#. js-lingui-id: nYD/Cq
|
||||
#: src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsSorts.tsx
|
||||
#: src/modules/views/editable-chip/components/EditableSortChip.tsx
|
||||
#: src/modules/side-panel/pages/page-layout/components/record-table-settings/RecordTableSettingsSorts.tsx
|
||||
#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
|
||||
#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
|
||||
@@ -3044,16 +3042,6 @@ msgstr "Zrušit změnu intervalu"
|
||||
msgid "Cancel interval switching?"
|
||||
msgstr "Zrušit změnu intervalu?"
|
||||
|
||||
#. js-lingui-id: /Dmw1h
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Cancel metered tier switching"
|
||||
msgstr "Zrušit přepínání úrovně s měřením"
|
||||
|
||||
#. js-lingui-id: Q/chGD
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Cancel metered tier switching?"
|
||||
msgstr "Zrušit přepínání úrovně s měřením?"
|
||||
|
||||
#. js-lingui-id: rRK/Lf
|
||||
#: src/pages/settings/enterprise/SettingsEnterprise.tsx
|
||||
#: src/modules/settings/billing/components/SettingsBillingContent.tsx
|
||||
@@ -3367,6 +3355,7 @@ msgstr "Vyberte si Trial"
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "City"
|
||||
msgstr "Město"
|
||||
|
||||
@@ -3795,11 +3784,6 @@ msgstr "Nakonfigurováno"
|
||||
msgid "Confirm"
|
||||
msgstr "Potvrdit"
|
||||
|
||||
#. js-lingui-id: qmnX/6
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Confirm changing your current credit plan."
|
||||
msgstr "Potvrďte změnu svého aktuálního úvěrového plánu."
|
||||
|
||||
#. js-lingui-id: q2rgqr
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
msgid "Confirm changing your current resource credit allocation."
|
||||
@@ -3812,7 +3796,6 @@ msgstr "Opravdu chcete smazat roli {roleName}? Toto akci nelze vrátit zpět. V
|
||||
|
||||
#. js-lingui-id: kZkFSm
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Confirm downgrade"
|
||||
msgstr "Potvrďte zhoršení plánu"
|
||||
|
||||
@@ -3823,10 +3806,14 @@ msgstr "Potvrdit aktualizaci role"
|
||||
|
||||
#. js-lingui-id: DDbn3x
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Confirm upgrade"
|
||||
msgstr "Potvrďte upgrade"
|
||||
|
||||
#. js-lingui-id: LOM1MR
|
||||
#: src/pages/auth/Authorize.tsx
|
||||
msgid "Connect {appName} to your account"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: mFiwDA
|
||||
#: src/pages/settings/applications/components/SettingsApplicationConnectScopePickerModal.tsx
|
||||
msgid "Connect {providerDisplayName}"
|
||||
@@ -4128,7 +4115,6 @@ msgid "Core Objects"
|
||||
msgstr "Základní objekty"
|
||||
|
||||
#. js-lingui-id: I99Miw
|
||||
#: src/modules/settings/billing/components/SettingsBillingCreditsSection.tsx
|
||||
#: src/modules/ai/components/internal/AiChatContextUsageButton.tsx
|
||||
msgid "Cost"
|
||||
msgstr "Cena"
|
||||
@@ -4138,11 +4124,6 @@ msgstr "Cena"
|
||||
msgid "Cost per 1M tokens"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: HUPoL8
|
||||
#: src/modules/settings/billing/components/SettingsBillingCreditsSection.tsx
|
||||
msgid "Cost per Extra Credits"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: 3X5ngu
|
||||
#: src/pages/settings/admin-panel/SettingsAdminNewAiModel.tsx
|
||||
msgid "Cost per million tokens (USD)"
|
||||
@@ -4225,6 +4206,7 @@ msgstr "Počet unikátních hodnot"
|
||||
#: src/modules/ui/field/input/components/AddressInput.tsx
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Country"
|
||||
msgstr "Země"
|
||||
|
||||
@@ -4425,11 +4407,6 @@ msgstr "Spotřeba kreditů v čase."
|
||||
msgid "Credit pack switching has been cancelled."
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: Efny36
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Credit Plan"
|
||||
msgstr "Kreditní plán"
|
||||
|
||||
#. js-lingui-id: qtEx+T
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
msgid "Credit plan upgraded."
|
||||
@@ -5331,6 +5308,7 @@ msgstr "sestupně"
|
||||
|
||||
#. js-lingui-id: Cko536
|
||||
#: src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsSorts.tsx
|
||||
#: src/modules/views/editable-chip/components/EditableSortChip.tsx
|
||||
#: src/modules/side-panel/pages/page-layout/components/record-table-settings/RecordTableSettingsSorts.tsx
|
||||
#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
|
||||
#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
|
||||
@@ -5560,8 +5538,6 @@ msgstr ""
|
||||
#. js-lingui-id: LE8J+K
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Downgrade"
|
||||
msgstr "Snížení úrovně"
|
||||
|
||||
@@ -6560,11 +6536,6 @@ msgstr ""
|
||||
msgid "Error while cancelling interval switching."
|
||||
msgstr "Chyba při rušení změny intervalu."
|
||||
|
||||
#. js-lingui-id: a1gs9Y
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Error while cancelling metered tier switching."
|
||||
msgstr "Chyba při ukončení přepínání úrovně s měřením."
|
||||
|
||||
#. js-lingui-id: FS6DQK
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Error while cancelling plan switching."
|
||||
@@ -6888,11 +6859,6 @@ msgstr ""
|
||||
msgid "Expression"
|
||||
msgstr "Výraz"
|
||||
|
||||
#. js-lingui-id: uE7S0L
|
||||
#: src/modules/settings/billing/components/SettingsBillingCreditsSection.tsx
|
||||
msgid "Extra Credits Used"
|
||||
msgstr "Použité extra kredity"
|
||||
|
||||
#. js-lingui-id: 7Bj3x9
|
||||
#: src/pages/settings/emailing-domains/utils/getEmailingDomainStatusText.ts
|
||||
#: src/pages/settings/admin-panel/SettingsAdminInstanceStatus.tsx
|
||||
@@ -7111,11 +7077,6 @@ msgstr ""
|
||||
msgid "Failed to update model selection mode"
|
||||
msgstr "Nepodařilo se aktualizovat režim výběru modelu"
|
||||
|
||||
#. js-lingui-id: HnBqPY
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Failed to update price."
|
||||
msgstr "Nepodařilo se aktualizovat cenu."
|
||||
|
||||
#. js-lingui-id: J7vly7
|
||||
#: src/modules/object-record/record-update-multiple/components/UpdateMultipleRecordsContainer.tsx
|
||||
msgid "Failed to update records. Please try again."
|
||||
@@ -7483,6 +7444,11 @@ msgstr "První 2 řádky"
|
||||
msgid "First 5 lines"
|
||||
msgstr "Prvních 5 řádků"
|
||||
|
||||
#. js-lingui-id: V1EGGU
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "First name"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: kODvZJ
|
||||
#: src/pages/onboarding/CreateProfile.tsx
|
||||
#: src/modules/settings/security/components/SettingsSecurityEditableProfileFields.tsx
|
||||
@@ -9062,6 +9028,7 @@ msgstr "Poslední zpráva {lastMessageSentAtFormatted}"
|
||||
|
||||
#. js-lingui-id: 1ZaQUH
|
||||
#: src/modules/settings/members/components/MemberNameFields.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Last name"
|
||||
msgstr ""
|
||||
|
||||
@@ -9122,6 +9089,11 @@ msgstr "Nejnovější datum"
|
||||
msgid "Latest version"
|
||||
msgstr "Nejnovější verze"
|
||||
|
||||
#. js-lingui-id: Q7hYLw
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Latitude"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: ZEP8tT
|
||||
#: src/modules/settings/playground/components/PlaygroundSetupForm.tsx
|
||||
msgid "Launch"
|
||||
@@ -9499,6 +9471,11 @@ msgstr "Odhlásit"
|
||||
msgid "Logs"
|
||||
msgstr "Protokoly"
|
||||
|
||||
#. js-lingui-id: FJBbw5
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Longitude"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: tL2lBI
|
||||
#: src/modules/workflow/workflow-diagram/utils/generateNodesAndEdgesForIteratorNode.ts
|
||||
msgid "loop"
|
||||
@@ -9810,11 +9787,6 @@ msgstr "Metadata"
|
||||
msgid "Metadata file generation failed"
|
||||
msgstr "Generování souboru metadat selhalo"
|
||||
|
||||
#. js-lingui-id: onCJJ6
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Metered tier switching has been cancelled."
|
||||
msgstr "Přepínání úrovně s měřením bylo zrušeno."
|
||||
|
||||
#. js-lingui-id: fiPesM
|
||||
#: src/modules/settings/logic-functions/components/triggers/SettingsLogicFunctionHttpTriggerSection.tsx
|
||||
msgid "Method"
|
||||
@@ -11169,7 +11141,6 @@ msgstr "Počet desetinných míst"
|
||||
|
||||
#. js-lingui-id: tYOaY8
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Number of new credits allocated every {recurringInterval}"
|
||||
msgstr "Počet nových kreditů přidělených každé {recurringInterval}"
|
||||
|
||||
@@ -12046,7 +12017,6 @@ msgstr "Vyberte prosím alespoň jeden cílový objekt pro tento vztah."
|
||||
|
||||
#. js-lingui-id: 8YnlGz
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Please start your subscription first"
|
||||
msgstr "Nejprve prosím zahajte své předplatné."
|
||||
|
||||
@@ -12125,6 +12095,7 @@ msgstr ""
|
||||
|
||||
#. js-lingui-id: OKJUcC
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Postcode"
|
||||
msgstr "PSČ"
|
||||
|
||||
@@ -12175,11 +12146,6 @@ msgstr "Předchozí"
|
||||
msgid "Previous 7 days"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: jmc+FY
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Price updated."
|
||||
msgstr "Cena byla aktualizována."
|
||||
|
||||
#. js-lingui-id: aHCEmh
|
||||
#: src/pages/settings/admin-panel/SettingsAdminNewAiModel.tsx
|
||||
msgid "Pricing"
|
||||
@@ -14569,6 +14535,7 @@ msgstr "Zahájen proces ověřování"
|
||||
#: src/modules/settings/admin-panel/health-status/components/SettingsAdminQueueJobsTable.tsx
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "State"
|
||||
msgstr "Stav"
|
||||
|
||||
@@ -16316,8 +16283,6 @@ msgstr "Aktualizace"
|
||||
#: src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelSection.tsx
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
msgid "Upgrade"
|
||||
@@ -16362,9 +16327,9 @@ msgstr ""
|
||||
msgid "Upgrade to {latestAvailableVersion}"
|
||||
msgstr "Aktualizovat na {latestAvailableVersion}"
|
||||
|
||||
#. js-lingui-id: tLOGrv
|
||||
#. js-lingui-id: Kutw4+
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
msgid "Upgrade to {nextTierCredits} credits for ${nextTierPrice}/{nextTierInterval}."
|
||||
msgid "Upgrade to {nextResourceCreditsAmount} credits for ${nextResourceCreditPrice}/{nextTierInterval}."
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: ggd+Ee
|
||||
@@ -17545,11 +17510,6 @@ msgstr ""
|
||||
msgid "You have scheduled a credit pack change. Do you want to cancel it?"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: M2lYgq
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "You have scheduled a metered tier change. Do you want to cancel it?"
|
||||
msgstr "Naplánovali jste změnu úrovně s měřením. Chcete ji zrušit?"
|
||||
|
||||
#. js-lingui-id: z8eKS7
|
||||
#: src/modules/settings/billing/hooks/useBillingWording.ts
|
||||
msgid "you will be charged ${enterprisePrice} per user per month"
|
||||
@@ -17587,11 +17547,11 @@ msgid ""
|
||||
"Reach to our support team to upgrade."
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: UUaKVD
|
||||
#. js-lingui-id: /fksQo
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
msgid ""
|
||||
"You've hit your usage limit. \n"
|
||||
"Upgrade to {nextTierCredits} credits for ${nextTierPrice}/{nextTierInterval}."
|
||||
"Upgrade to {nextResourceCreditsAmount} credits for ${nextResourceCreditPrice}/{nextTierInterval}."
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: yZ0wRS
|
||||
|
||||
@@ -236,10 +236,10 @@ msgstr "{agentLabel} Agentrolle"
|
||||
msgid "{aggregateLabel} of {fieldLabel}"
|
||||
msgstr "{aggregateLabel} af {fieldLabel}"
|
||||
|
||||
#. js-lingui-id: LTvJAf
|
||||
#. js-lingui-id: ZZZxmp
|
||||
#: src/pages/auth/Authorize.tsx
|
||||
msgid "{appName} wants to access your account"
|
||||
msgstr "{appName} ønsker at få adgang til din konto"
|
||||
msgid "{appName} would like to:"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: y9covz
|
||||
#: src/pages/settings/admin-panel/SettingsAdminWorkspacesStatus.tsx
|
||||
@@ -266,11 +266,6 @@ msgstr "{contextStoreNumberOfSelectedRecords} valgt"
|
||||
msgid "{count, plural, one {E.g. {0}{1} for {count} decimal} other {E.g. {2}{3} for {count} decimals}}"
|
||||
msgstr "{count, plural, one {Fx. {0}{1} for {count} decimal} other {Fx. {2}{3} for {count} decimaler}}"
|
||||
|
||||
#. js-lingui-id: aTq2js
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "{credits} Credits - ${price}"
|
||||
msgstr "{credits} kreditter - ${price}"
|
||||
|
||||
#. js-lingui-id: q8RNNe
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
msgid "{credits} Credits - ${priceDisplay}"
|
||||
@@ -808,10 +803,10 @@ msgstr ""
|
||||
msgid "Access Key ID"
|
||||
msgstr "Access Key ID"
|
||||
|
||||
#. js-lingui-id: o0Ci6l
|
||||
#. js-lingui-id: CrjDqe
|
||||
#: src/pages/auth/Authorize.tsx
|
||||
msgid "Access workspace data"
|
||||
msgstr "Få adgang til data i arbejdsområdet"
|
||||
msgid "Access your workspace data"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: c2UA7k
|
||||
#: src/pages/settings/ai/components/SettingsAiMCP.tsx
|
||||
@@ -1326,6 +1321,7 @@ msgstr "Tilføjet til blokeringsliste"
|
||||
#: src/modules/ui/field/input/components/AddressInput.tsx
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Address 1"
|
||||
msgstr "Adresse 1"
|
||||
|
||||
@@ -1333,6 +1329,7 @@ msgstr "Adresse 1"
|
||||
#: src/modules/ui/field/input/components/AddressInput.tsx
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Address 2"
|
||||
msgstr "Adresse 2"
|
||||
|
||||
@@ -2332,6 +2329,7 @@ msgstr "stigende"
|
||||
|
||||
#. js-lingui-id: nYD/Cq
|
||||
#: src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsSorts.tsx
|
||||
#: src/modules/views/editable-chip/components/EditableSortChip.tsx
|
||||
#: src/modules/side-panel/pages/page-layout/components/record-table-settings/RecordTableSettingsSorts.tsx
|
||||
#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
|
||||
#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
|
||||
@@ -3044,16 +3042,6 @@ msgstr "Annuller intervalskift"
|
||||
msgid "Cancel interval switching?"
|
||||
msgstr "Annuller intervalskift?"
|
||||
|
||||
#. js-lingui-id: /Dmw1h
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Cancel metered tier switching"
|
||||
msgstr "Annuller skift til målt niveau"
|
||||
|
||||
#. js-lingui-id: Q/chGD
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Cancel metered tier switching?"
|
||||
msgstr "Annuller skift til målt niveau?"
|
||||
|
||||
#. js-lingui-id: rRK/Lf
|
||||
#: src/pages/settings/enterprise/SettingsEnterprise.tsx
|
||||
#: src/modules/settings/billing/components/SettingsBillingContent.tsx
|
||||
@@ -3367,6 +3355,7 @@ msgstr "Vælg din prøveperiode"
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "City"
|
||||
msgstr "By"
|
||||
|
||||
@@ -3795,11 +3784,6 @@ msgstr "Konfigureret"
|
||||
msgid "Confirm"
|
||||
msgstr "Bekræft"
|
||||
|
||||
#. js-lingui-id: qmnX/6
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Confirm changing your current credit plan."
|
||||
msgstr "Bekræft ændring af din nuværende kreditplan."
|
||||
|
||||
#. js-lingui-id: q2rgqr
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
msgid "Confirm changing your current resource credit allocation."
|
||||
@@ -3812,7 +3796,6 @@ msgstr "Bekræft sletning af {roleName} rolle? Dette kan ikke fortrydes. Alle me
|
||||
|
||||
#. js-lingui-id: kZkFSm
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Confirm downgrade"
|
||||
msgstr "Bekræft nedgradering"
|
||||
|
||||
@@ -3823,10 +3806,14 @@ msgstr "Bekræft rolleændring"
|
||||
|
||||
#. js-lingui-id: DDbn3x
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Confirm upgrade"
|
||||
msgstr "Bekræft opgradering"
|
||||
|
||||
#. js-lingui-id: LOM1MR
|
||||
#: src/pages/auth/Authorize.tsx
|
||||
msgid "Connect {appName} to your account"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: mFiwDA
|
||||
#: src/pages/settings/applications/components/SettingsApplicationConnectScopePickerModal.tsx
|
||||
msgid "Connect {providerDisplayName}"
|
||||
@@ -4128,7 +4115,6 @@ msgid "Core Objects"
|
||||
msgstr "Kerneobjekter"
|
||||
|
||||
#. js-lingui-id: I99Miw
|
||||
#: src/modules/settings/billing/components/SettingsBillingCreditsSection.tsx
|
||||
#: src/modules/ai/components/internal/AiChatContextUsageButton.tsx
|
||||
msgid "Cost"
|
||||
msgstr "Omkostninger"
|
||||
@@ -4138,11 +4124,6 @@ msgstr "Omkostninger"
|
||||
msgid "Cost per 1M tokens"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: HUPoL8
|
||||
#: src/modules/settings/billing/components/SettingsBillingCreditsSection.tsx
|
||||
msgid "Cost per Extra Credits"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: 3X5ngu
|
||||
#: src/pages/settings/admin-panel/SettingsAdminNewAiModel.tsx
|
||||
msgid "Cost per million tokens (USD)"
|
||||
@@ -4225,6 +4206,7 @@ msgstr "Tæl unikke værdier"
|
||||
#: src/modules/ui/field/input/components/AddressInput.tsx
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Country"
|
||||
msgstr "Land"
|
||||
|
||||
@@ -4425,11 +4407,6 @@ msgstr "Kreditforbrug over tid."
|
||||
msgid "Credit pack switching has been cancelled."
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: Efny36
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Credit Plan"
|
||||
msgstr "Kreditplan"
|
||||
|
||||
#. js-lingui-id: qtEx+T
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
msgid "Credit plan upgraded."
|
||||
@@ -5331,6 +5308,7 @@ msgstr "faldende"
|
||||
|
||||
#. js-lingui-id: Cko536
|
||||
#: src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsSorts.tsx
|
||||
#: src/modules/views/editable-chip/components/EditableSortChip.tsx
|
||||
#: src/modules/side-panel/pages/page-layout/components/record-table-settings/RecordTableSettingsSorts.tsx
|
||||
#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
|
||||
#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
|
||||
@@ -5560,8 +5538,6 @@ msgstr ""
|
||||
#. js-lingui-id: LE8J+K
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Downgrade"
|
||||
msgstr "Nedgrader"
|
||||
|
||||
@@ -6560,11 +6536,6 @@ msgstr ""
|
||||
msgid "Error while cancelling interval switching."
|
||||
msgstr "Fejl ved annullering af intervalskift."
|
||||
|
||||
#. js-lingui-id: a1gs9Y
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Error while cancelling metered tier switching."
|
||||
msgstr "Fejl ved annullering af skift til målt niveau."
|
||||
|
||||
#. js-lingui-id: FS6DQK
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Error while cancelling plan switching."
|
||||
@@ -6888,11 +6859,6 @@ msgstr ""
|
||||
msgid "Expression"
|
||||
msgstr "Udtryk"
|
||||
|
||||
#. js-lingui-id: uE7S0L
|
||||
#: src/modules/settings/billing/components/SettingsBillingCreditsSection.tsx
|
||||
msgid "Extra Credits Used"
|
||||
msgstr "Ekstra kreditter forbrugt"
|
||||
|
||||
#. js-lingui-id: 7Bj3x9
|
||||
#: src/pages/settings/emailing-domains/utils/getEmailingDomainStatusText.ts
|
||||
#: src/pages/settings/admin-panel/SettingsAdminInstanceStatus.tsx
|
||||
@@ -7111,11 +7077,6 @@ msgstr ""
|
||||
msgid "Failed to update model selection mode"
|
||||
msgstr "Kunne ikke opdatere tilstand for modelvalg"
|
||||
|
||||
#. js-lingui-id: HnBqPY
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Failed to update price."
|
||||
msgstr "Kunne ikke opdatere pris."
|
||||
|
||||
#. js-lingui-id: J7vly7
|
||||
#: src/modules/object-record/record-update-multiple/components/UpdateMultipleRecordsContainer.tsx
|
||||
msgid "Failed to update records. Please try again."
|
||||
@@ -7483,6 +7444,11 @@ msgstr "Første 2 linjer"
|
||||
msgid "First 5 lines"
|
||||
msgstr "Første 5 linjer"
|
||||
|
||||
#. js-lingui-id: V1EGGU
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "First name"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: kODvZJ
|
||||
#: src/pages/onboarding/CreateProfile.tsx
|
||||
#: src/modules/settings/security/components/SettingsSecurityEditableProfileFields.tsx
|
||||
@@ -9062,6 +9028,7 @@ msgstr "Sidste besked {lastMessageSentAtFormatted}"
|
||||
|
||||
#. js-lingui-id: 1ZaQUH
|
||||
#: src/modules/settings/members/components/MemberNameFields.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Last name"
|
||||
msgstr ""
|
||||
|
||||
@@ -9122,6 +9089,11 @@ msgstr "Seneste dato"
|
||||
msgid "Latest version"
|
||||
msgstr "Seneste version"
|
||||
|
||||
#. js-lingui-id: Q7hYLw
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Latitude"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: ZEP8tT
|
||||
#: src/modules/settings/playground/components/PlaygroundSetupForm.tsx
|
||||
msgid "Launch"
|
||||
@@ -9499,6 +9471,11 @@ msgstr "Logud"
|
||||
msgid "Logs"
|
||||
msgstr "Logfiler"
|
||||
|
||||
#. js-lingui-id: FJBbw5
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Longitude"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: tL2lBI
|
||||
#: src/modules/workflow/workflow-diagram/utils/generateNodesAndEdgesForIteratorNode.ts
|
||||
msgid "loop"
|
||||
@@ -9810,11 +9787,6 @@ msgstr "Metadata"
|
||||
msgid "Metadata file generation failed"
|
||||
msgstr "Generering af metadatafil mislykkedes"
|
||||
|
||||
#. js-lingui-id: onCJJ6
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Metered tier switching has been cancelled."
|
||||
msgstr "Skift til målt niveau er blevet annulleret."
|
||||
|
||||
#. js-lingui-id: fiPesM
|
||||
#: src/modules/settings/logic-functions/components/triggers/SettingsLogicFunctionHttpTriggerSection.tsx
|
||||
msgid "Method"
|
||||
@@ -11169,7 +11141,6 @@ msgstr "Antal decimaler"
|
||||
|
||||
#. js-lingui-id: tYOaY8
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Number of new credits allocated every {recurringInterval}"
|
||||
msgstr "Antal nye tildelte kreditter hver {recurringInterval}"
|
||||
|
||||
@@ -12046,7 +12017,6 @@ msgstr "Vælg mindst én destinationsobjekt til denne relation."
|
||||
|
||||
#. js-lingui-id: 8YnlGz
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Please start your subscription first"
|
||||
msgstr "Start venligst dit abonnement først"
|
||||
|
||||
@@ -12125,6 +12095,7 @@ msgstr ""
|
||||
|
||||
#. js-lingui-id: OKJUcC
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Postcode"
|
||||
msgstr "Postnummer"
|
||||
|
||||
@@ -12175,11 +12146,6 @@ msgstr "Forrige"
|
||||
msgid "Previous 7 days"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: jmc+FY
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Price updated."
|
||||
msgstr "Pris opdateret."
|
||||
|
||||
#. js-lingui-id: aHCEmh
|
||||
#: src/pages/settings/admin-panel/SettingsAdminNewAiModel.tsx
|
||||
msgid "Pricing"
|
||||
@@ -14569,6 +14535,7 @@ msgstr "Verifikationsprocessen er startet"
|
||||
#: src/modules/settings/admin-panel/health-status/components/SettingsAdminQueueJobsTable.tsx
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "State"
|
||||
msgstr "Tilstand"
|
||||
|
||||
@@ -16318,8 +16285,6 @@ msgstr "Opdateringer"
|
||||
#: src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelSection.tsx
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
msgid "Upgrade"
|
||||
@@ -16364,9 +16329,9 @@ msgstr ""
|
||||
msgid "Upgrade to {latestAvailableVersion}"
|
||||
msgstr "Opgrader til {latestAvailableVersion}"
|
||||
|
||||
#. js-lingui-id: tLOGrv
|
||||
#. js-lingui-id: Kutw4+
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
msgid "Upgrade to {nextTierCredits} credits for ${nextTierPrice}/{nextTierInterval}."
|
||||
msgid "Upgrade to {nextResourceCreditsAmount} credits for ${nextResourceCreditPrice}/{nextTierInterval}."
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: ggd+Ee
|
||||
@@ -17547,11 +17512,6 @@ msgstr ""
|
||||
msgid "You have scheduled a credit pack change. Do you want to cancel it?"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: M2lYgq
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "You have scheduled a metered tier change. Do you want to cancel it?"
|
||||
msgstr "Du har planlagt et skift til målt niveau. Vil du annullere det?"
|
||||
|
||||
#. js-lingui-id: z8eKS7
|
||||
#: src/modules/settings/billing/hooks/useBillingWording.ts
|
||||
msgid "you will be charged ${enterprisePrice} per user per month"
|
||||
@@ -17589,11 +17549,11 @@ msgid ""
|
||||
"Reach to our support team to upgrade."
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: UUaKVD
|
||||
#. js-lingui-id: /fksQo
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
msgid ""
|
||||
"You've hit your usage limit. \n"
|
||||
"Upgrade to {nextTierCredits} credits for ${nextTierPrice}/{nextTierInterval}."
|
||||
"Upgrade to {nextResourceCreditsAmount} credits for ${nextResourceCreditPrice}/{nextTierInterval}."
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: yZ0wRS
|
||||
|
||||
@@ -236,10 +236,10 @@ msgstr "{agentLabel}-Agentenrolle"
|
||||
msgid "{aggregateLabel} of {fieldLabel}"
|
||||
msgstr "{aggregateLabel} von {fieldLabel}"
|
||||
|
||||
#. js-lingui-id: LTvJAf
|
||||
#. js-lingui-id: ZZZxmp
|
||||
#: src/pages/auth/Authorize.tsx
|
||||
msgid "{appName} wants to access your account"
|
||||
msgstr "{appName} möchte auf Ihr Konto zugreifen"
|
||||
msgid "{appName} would like to:"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: y9covz
|
||||
#: src/pages/settings/admin-panel/SettingsAdminWorkspacesStatus.tsx
|
||||
@@ -266,11 +266,6 @@ msgstr "{contextStoreNumberOfSelectedRecords} ausgewählt"
|
||||
msgid "{count, plural, one {E.g. {0}{1} for {count} decimal} other {E.g. {2}{3} for {count} decimals}}"
|
||||
msgstr "{count, plural, one {z.B. {0}{1} für {count} Dezimalstelle} other {z.B. {2}{3} für {count} Dezimalstellen}}"
|
||||
|
||||
#. js-lingui-id: aTq2js
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "{credits} Credits - ${price}"
|
||||
msgstr "{credits} Credits - ${price}"
|
||||
|
||||
#. js-lingui-id: q8RNNe
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
msgid "{credits} Credits - ${priceDisplay}"
|
||||
@@ -808,10 +803,10 @@ msgstr ""
|
||||
msgid "Access Key ID"
|
||||
msgstr "Zugriffsschlüssel-ID"
|
||||
|
||||
#. js-lingui-id: o0Ci6l
|
||||
#. js-lingui-id: CrjDqe
|
||||
#: src/pages/auth/Authorize.tsx
|
||||
msgid "Access workspace data"
|
||||
msgstr "Auf Arbeitsbereichsdaten zugreifen"
|
||||
msgid "Access your workspace data"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: c2UA7k
|
||||
#: src/pages/settings/ai/components/SettingsAiMCP.tsx
|
||||
@@ -1326,6 +1321,7 @@ msgstr "Zur Blockliste hinzugefügt"
|
||||
#: src/modules/ui/field/input/components/AddressInput.tsx
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Address 1"
|
||||
msgstr "Adresse 1"
|
||||
|
||||
@@ -1333,6 +1329,7 @@ msgstr "Adresse 1"
|
||||
#: src/modules/ui/field/input/components/AddressInput.tsx
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Address 2"
|
||||
msgstr "Adresse 2"
|
||||
|
||||
@@ -2332,6 +2329,7 @@ msgstr "aufsteigend"
|
||||
|
||||
#. js-lingui-id: nYD/Cq
|
||||
#: src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsSorts.tsx
|
||||
#: src/modules/views/editable-chip/components/EditableSortChip.tsx
|
||||
#: src/modules/side-panel/pages/page-layout/components/record-table-settings/RecordTableSettingsSorts.tsx
|
||||
#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
|
||||
#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
|
||||
@@ -3044,16 +3042,6 @@ msgstr "Intervallwechsel abbrechen"
|
||||
msgid "Cancel interval switching?"
|
||||
msgstr "Intervallwechsel abbrechen?"
|
||||
|
||||
#. js-lingui-id: /Dmw1h
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Cancel metered tier switching"
|
||||
msgstr "Zählertarifwechsel abbrechen"
|
||||
|
||||
#. js-lingui-id: Q/chGD
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Cancel metered tier switching?"
|
||||
msgstr "Zählertarifwechsel abbrechen?"
|
||||
|
||||
#. js-lingui-id: rRK/Lf
|
||||
#: src/pages/settings/enterprise/SettingsEnterprise.tsx
|
||||
#: src/modules/settings/billing/components/SettingsBillingContent.tsx
|
||||
@@ -3367,6 +3355,7 @@ msgstr "Wählen Sie Ihre Testphase"
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "City"
|
||||
msgstr "Stadt"
|
||||
|
||||
@@ -3795,11 +3784,6 @@ msgstr "Konfiguriert"
|
||||
msgid "Confirm"
|
||||
msgstr "Bestätigen"
|
||||
|
||||
#. js-lingui-id: qmnX/6
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Confirm changing your current credit plan."
|
||||
msgstr "Bestätigen Sie die Änderung Ihres aktuellen Guthabenplans."
|
||||
|
||||
#. js-lingui-id: q2rgqr
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
msgid "Confirm changing your current resource credit allocation."
|
||||
@@ -3812,7 +3796,6 @@ msgstr "Löschung der Rolle {roleName} bestätigen? Dies kann nicht rückgängig
|
||||
|
||||
#. js-lingui-id: kZkFSm
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Confirm downgrade"
|
||||
msgstr "Herabstufung bestätigen"
|
||||
|
||||
@@ -3823,10 +3806,14 @@ msgstr "Rollenaktualisierung bestätigen"
|
||||
|
||||
#. js-lingui-id: DDbn3x
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Confirm upgrade"
|
||||
msgstr "Upgrade bestätigen"
|
||||
|
||||
#. js-lingui-id: LOM1MR
|
||||
#: src/pages/auth/Authorize.tsx
|
||||
msgid "Connect {appName} to your account"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: mFiwDA
|
||||
#: src/pages/settings/applications/components/SettingsApplicationConnectScopePickerModal.tsx
|
||||
msgid "Connect {providerDisplayName}"
|
||||
@@ -4128,7 +4115,6 @@ msgid "Core Objects"
|
||||
msgstr "Kernobjekte"
|
||||
|
||||
#. js-lingui-id: I99Miw
|
||||
#: src/modules/settings/billing/components/SettingsBillingCreditsSection.tsx
|
||||
#: src/modules/ai/components/internal/AiChatContextUsageButton.tsx
|
||||
msgid "Cost"
|
||||
msgstr "Kosten"
|
||||
@@ -4138,11 +4124,6 @@ msgstr "Kosten"
|
||||
msgid "Cost per 1M tokens"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: HUPoL8
|
||||
#: src/modules/settings/billing/components/SettingsBillingCreditsSection.tsx
|
||||
msgid "Cost per Extra Credits"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: 3X5ngu
|
||||
#: src/pages/settings/admin-panel/SettingsAdminNewAiModel.tsx
|
||||
msgid "Cost per million tokens (USD)"
|
||||
@@ -4225,6 +4206,7 @@ msgstr "Eindeutige Werte zählen"
|
||||
#: src/modules/ui/field/input/components/AddressInput.tsx
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Country"
|
||||
msgstr "Land"
|
||||
|
||||
@@ -4425,11 +4407,6 @@ msgstr "Guthabenverbrauch im Zeitverlauf."
|
||||
msgid "Credit pack switching has been cancelled."
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: Efny36
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Credit Plan"
|
||||
msgstr "Guthabenplan"
|
||||
|
||||
#. js-lingui-id: qtEx+T
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
msgid "Credit plan upgraded."
|
||||
@@ -5331,6 +5308,7 @@ msgstr "absteigend"
|
||||
|
||||
#. js-lingui-id: Cko536
|
||||
#: src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsSorts.tsx
|
||||
#: src/modules/views/editable-chip/components/EditableSortChip.tsx
|
||||
#: src/modules/side-panel/pages/page-layout/components/record-table-settings/RecordTableSettingsSorts.tsx
|
||||
#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
|
||||
#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
|
||||
@@ -5560,8 +5538,6 @@ msgstr ""
|
||||
#. js-lingui-id: LE8J+K
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Downgrade"
|
||||
msgstr "Herabstufen"
|
||||
|
||||
@@ -6560,11 +6536,6 @@ msgstr ""
|
||||
msgid "Error while cancelling interval switching."
|
||||
msgstr "Fehler beim Abbrechen des Intervallswechsels."
|
||||
|
||||
#. js-lingui-id: a1gs9Y
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Error while cancelling metered tier switching."
|
||||
msgstr "Fehler beim Abbrechen des Zählertarifwechsels."
|
||||
|
||||
#. js-lingui-id: FS6DQK
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Error while cancelling plan switching."
|
||||
@@ -6888,11 +6859,6 @@ msgstr ""
|
||||
msgid "Expression"
|
||||
msgstr "Ausdruck"
|
||||
|
||||
#. js-lingui-id: uE7S0L
|
||||
#: src/modules/settings/billing/components/SettingsBillingCreditsSection.tsx
|
||||
msgid "Extra Credits Used"
|
||||
msgstr "Verwendete zusätzliche Credits"
|
||||
|
||||
#. js-lingui-id: 7Bj3x9
|
||||
#: src/pages/settings/emailing-domains/utils/getEmailingDomainStatusText.ts
|
||||
#: src/pages/settings/admin-panel/SettingsAdminInstanceStatus.tsx
|
||||
@@ -7111,11 +7077,6 @@ msgstr ""
|
||||
msgid "Failed to update model selection mode"
|
||||
msgstr "Fehler beim Aktualisieren des Modellauswahlmodus"
|
||||
|
||||
#. js-lingui-id: HnBqPY
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Failed to update price."
|
||||
msgstr "Fehler beim Aktualisieren des Preises."
|
||||
|
||||
#. js-lingui-id: J7vly7
|
||||
#: src/modules/object-record/record-update-multiple/components/UpdateMultipleRecordsContainer.tsx
|
||||
msgid "Failed to update records. Please try again."
|
||||
@@ -7483,6 +7444,11 @@ msgstr "Ersten 2 Zeilen"
|
||||
msgid "First 5 lines"
|
||||
msgstr "Ersten 5 Zeilen"
|
||||
|
||||
#. js-lingui-id: V1EGGU
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "First name"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: kODvZJ
|
||||
#: src/pages/onboarding/CreateProfile.tsx
|
||||
#: src/modules/settings/security/components/SettingsSecurityEditableProfileFields.tsx
|
||||
@@ -9062,6 +9028,7 @@ msgstr "Letzte Nachricht {lastMessageSentAtFormatted}"
|
||||
|
||||
#. js-lingui-id: 1ZaQUH
|
||||
#: src/modules/settings/members/components/MemberNameFields.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Last name"
|
||||
msgstr ""
|
||||
|
||||
@@ -9122,6 +9089,11 @@ msgstr "Neuester Termin"
|
||||
msgid "Latest version"
|
||||
msgstr "Neueste Version"
|
||||
|
||||
#. js-lingui-id: Q7hYLw
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Latitude"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: ZEP8tT
|
||||
#: src/modules/settings/playground/components/PlaygroundSetupForm.tsx
|
||||
msgid "Launch"
|
||||
@@ -9499,6 +9471,11 @@ msgstr "Abmelden"
|
||||
msgid "Logs"
|
||||
msgstr "Protokolle"
|
||||
|
||||
#. js-lingui-id: FJBbw5
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Longitude"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: tL2lBI
|
||||
#: src/modules/workflow/workflow-diagram/utils/generateNodesAndEdgesForIteratorNode.ts
|
||||
msgid "loop"
|
||||
@@ -9810,11 +9787,6 @@ msgstr "Metadaten"
|
||||
msgid "Metadata file generation failed"
|
||||
msgstr "Generierung der Metadatendatei fehlgeschlagen"
|
||||
|
||||
#. js-lingui-id: onCJJ6
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Metered tier switching has been cancelled."
|
||||
msgstr "Der Zählertarifwechsel wurde abgebrochen."
|
||||
|
||||
#. js-lingui-id: fiPesM
|
||||
#: src/modules/settings/logic-functions/components/triggers/SettingsLogicFunctionHttpTriggerSection.tsx
|
||||
msgid "Method"
|
||||
@@ -11169,7 +11141,6 @@ msgstr "Anzahl der Dezimalstellen"
|
||||
|
||||
#. js-lingui-id: tYOaY8
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Number of new credits allocated every {recurringInterval}"
|
||||
msgstr "Anzahl der neuen zugewiesenen Guthaben alle {recurringInterval}"
|
||||
|
||||
@@ -12046,7 +12017,6 @@ msgstr "Bitte wählen Sie mindestens ein Zielobjekt für diese Beziehung aus."
|
||||
|
||||
#. js-lingui-id: 8YnlGz
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Please start your subscription first"
|
||||
msgstr "Bitte starten Sie zuerst Ihr Abonnement"
|
||||
|
||||
@@ -12125,6 +12095,7 @@ msgstr ""
|
||||
|
||||
#. js-lingui-id: OKJUcC
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Postcode"
|
||||
msgstr "Postleitzahl"
|
||||
|
||||
@@ -12175,11 +12146,6 @@ msgstr "Vorherige"
|
||||
msgid "Previous 7 days"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: jmc+FY
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Price updated."
|
||||
msgstr "Preis aktualisiert."
|
||||
|
||||
#. js-lingui-id: aHCEmh
|
||||
#: src/pages/settings/admin-panel/SettingsAdminNewAiModel.tsx
|
||||
msgid "Pricing"
|
||||
@@ -14569,6 +14535,7 @@ msgstr "Verifizierungsprozess gestartet"
|
||||
#: src/modules/settings/admin-panel/health-status/components/SettingsAdminQueueJobsTable.tsx
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "State"
|
||||
msgstr "Zustand"
|
||||
|
||||
@@ -16316,8 +16283,6 @@ msgstr "Aktualisierungen"
|
||||
#: src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelSection.tsx
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
msgid "Upgrade"
|
||||
@@ -16362,9 +16327,9 @@ msgstr ""
|
||||
msgid "Upgrade to {latestAvailableVersion}"
|
||||
msgstr "Auf {latestAvailableVersion} aktualisieren"
|
||||
|
||||
#. js-lingui-id: tLOGrv
|
||||
#. js-lingui-id: Kutw4+
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
msgid "Upgrade to {nextTierCredits} credits for ${nextTierPrice}/{nextTierInterval}."
|
||||
msgid "Upgrade to {nextResourceCreditsAmount} credits for ${nextResourceCreditPrice}/{nextTierInterval}."
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: ggd+Ee
|
||||
@@ -17545,11 +17510,6 @@ msgstr ""
|
||||
msgid "You have scheduled a credit pack change. Do you want to cancel it?"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: M2lYgq
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "You have scheduled a metered tier change. Do you want to cancel it?"
|
||||
msgstr "Sie haben eine Änderung des Zählertarifs geplant. Möchten Sie diese abbrechen?"
|
||||
|
||||
#. js-lingui-id: z8eKS7
|
||||
#: src/modules/settings/billing/hooks/useBillingWording.ts
|
||||
msgid "you will be charged ${enterprisePrice} per user per month"
|
||||
@@ -17587,11 +17547,11 @@ msgid ""
|
||||
"Reach to our support team to upgrade."
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: UUaKVD
|
||||
#. js-lingui-id: /fksQo
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
msgid ""
|
||||
"You've hit your usage limit. \n"
|
||||
"Upgrade to {nextTierCredits} credits for ${nextTierPrice}/{nextTierInterval}."
|
||||
"Upgrade to {nextResourceCreditsAmount} credits for ${nextResourceCreditPrice}/{nextTierInterval}."
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: yZ0wRS
|
||||
|
||||
@@ -236,10 +236,10 @@ msgstr "{agentLabel} Ρόλος Πράκτορα"
|
||||
msgid "{aggregateLabel} of {fieldLabel}"
|
||||
msgstr "{aggregateLabel} του {fieldLabel}"
|
||||
|
||||
#. js-lingui-id: LTvJAf
|
||||
#. js-lingui-id: ZZZxmp
|
||||
#: src/pages/auth/Authorize.tsx
|
||||
msgid "{appName} wants to access your account"
|
||||
msgstr "Το {appName} θέλει να αποκτήσει πρόσβαση στον λογαριασμό σας"
|
||||
msgid "{appName} would like to:"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: y9covz
|
||||
#: src/pages/settings/admin-panel/SettingsAdminWorkspacesStatus.tsx
|
||||
@@ -266,11 +266,6 @@ msgstr "{contextStoreNumberOfSelectedRecords} επιλεγμένα"
|
||||
msgid "{count, plural, one {E.g. {0}{1} for {count} decimal} other {E.g. {2}{3} for {count} decimals}}"
|
||||
msgstr "{count, plural, one {Π.χ. {0}{1} για {count} δεκαδικό} other {Π.χ. {2}{3} για {count} δεκαδικά}}"
|
||||
|
||||
#. js-lingui-id: aTq2js
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "{credits} Credits - ${price}"
|
||||
msgstr "{credits} Πιστώσεις - ${price}"
|
||||
|
||||
#. js-lingui-id: q8RNNe
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
msgid "{credits} Credits - ${priceDisplay}"
|
||||
@@ -808,10 +803,10 @@ msgstr ""
|
||||
msgid "Access Key ID"
|
||||
msgstr "Access Key ID"
|
||||
|
||||
#. js-lingui-id: o0Ci6l
|
||||
#. js-lingui-id: CrjDqe
|
||||
#: src/pages/auth/Authorize.tsx
|
||||
msgid "Access workspace data"
|
||||
msgstr "Πρόσβαση στα δεδομένα του χώρου εργασίας"
|
||||
msgid "Access your workspace data"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: c2UA7k
|
||||
#: src/pages/settings/ai/components/SettingsAiMCP.tsx
|
||||
@@ -1326,6 +1321,7 @@ msgstr "Προστέθηκε στη λίστα αποκλεισμού"
|
||||
#: src/modules/ui/field/input/components/AddressInput.tsx
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Address 1"
|
||||
msgstr "Διεύθυνση 1"
|
||||
|
||||
@@ -1333,6 +1329,7 @@ msgstr "Διεύθυνση 1"
|
||||
#: src/modules/ui/field/input/components/AddressInput.tsx
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Address 2"
|
||||
msgstr "Διεύθυνση 2"
|
||||
|
||||
@@ -2332,6 +2329,7 @@ msgstr "αύξουσα"
|
||||
|
||||
#. js-lingui-id: nYD/Cq
|
||||
#: src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsSorts.tsx
|
||||
#: src/modules/views/editable-chip/components/EditableSortChip.tsx
|
||||
#: src/modules/side-panel/pages/page-layout/components/record-table-settings/RecordTableSettingsSorts.tsx
|
||||
#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
|
||||
#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
|
||||
@@ -3044,16 +3042,6 @@ msgstr "Ακύρωση αλλαγής περιόδου"
|
||||
msgid "Cancel interval switching?"
|
||||
msgstr "Ακύρωση αλλαγής περιόδου;"
|
||||
|
||||
#. js-lingui-id: /Dmw1h
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Cancel metered tier switching"
|
||||
msgstr "Ακύρωση αλλαγής τιμολογιακής βαθμίδας"
|
||||
|
||||
#. js-lingui-id: Q/chGD
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Cancel metered tier switching?"
|
||||
msgstr "Ακύρωση αλλαγής τιμολογιακής βαθμίδας;"
|
||||
|
||||
#. js-lingui-id: rRK/Lf
|
||||
#: src/pages/settings/enterprise/SettingsEnterprise.tsx
|
||||
#: src/modules/settings/billing/components/SettingsBillingContent.tsx
|
||||
@@ -3367,6 +3355,7 @@ msgstr "Επιλέξτε τη Δοκιμή σας"
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "City"
|
||||
msgstr "Πόλη"
|
||||
|
||||
@@ -3795,11 +3784,6 @@ msgstr "Ρυθμισμένο"
|
||||
msgid "Confirm"
|
||||
msgstr "Επιβεβαίωση"
|
||||
|
||||
#. js-lingui-id: qmnX/6
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Confirm changing your current credit plan."
|
||||
msgstr "Επιβεβαίωση αλλαγής του τρέχοντος πλάνου πιστώσεων."
|
||||
|
||||
#. js-lingui-id: q2rgqr
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
msgid "Confirm changing your current resource credit allocation."
|
||||
@@ -3812,7 +3796,6 @@ msgstr "Επιβεβαιώστε την διαγραφή του ρόλου {role
|
||||
|
||||
#. js-lingui-id: kZkFSm
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Confirm downgrade"
|
||||
msgstr "Επιβεβαίωση υποβάθμισης"
|
||||
|
||||
@@ -3823,10 +3806,14 @@ msgstr "Επιβεβαίωση ενημέρωσης ρόλου"
|
||||
|
||||
#. js-lingui-id: DDbn3x
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Confirm upgrade"
|
||||
msgstr "Επιβεβαίωση αναβάθμισης"
|
||||
|
||||
#. js-lingui-id: LOM1MR
|
||||
#: src/pages/auth/Authorize.tsx
|
||||
msgid "Connect {appName} to your account"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: mFiwDA
|
||||
#: src/pages/settings/applications/components/SettingsApplicationConnectScopePickerModal.tsx
|
||||
msgid "Connect {providerDisplayName}"
|
||||
@@ -4128,7 +4115,6 @@ msgid "Core Objects"
|
||||
msgstr "Κύρια Αντικείμενα"
|
||||
|
||||
#. js-lingui-id: I99Miw
|
||||
#: src/modules/settings/billing/components/SettingsBillingCreditsSection.tsx
|
||||
#: src/modules/ai/components/internal/AiChatContextUsageButton.tsx
|
||||
msgid "Cost"
|
||||
msgstr "Κόστος"
|
||||
@@ -4138,11 +4124,6 @@ msgstr "Κόστος"
|
||||
msgid "Cost per 1M tokens"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: HUPoL8
|
||||
#: src/modules/settings/billing/components/SettingsBillingCreditsSection.tsx
|
||||
msgid "Cost per Extra Credits"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: 3X5ngu
|
||||
#: src/pages/settings/admin-panel/SettingsAdminNewAiModel.tsx
|
||||
msgid "Cost per million tokens (USD)"
|
||||
@@ -4225,6 +4206,7 @@ msgstr "Καταμέτρηση μοναδικών τιμών"
|
||||
#: src/modules/ui/field/input/components/AddressInput.tsx
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Country"
|
||||
msgstr "Χώρα"
|
||||
|
||||
@@ -4425,11 +4407,6 @@ msgstr "Κατανάλωση πιστώσεων με την πάροδο του
|
||||
msgid "Credit pack switching has been cancelled."
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: Efny36
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Credit Plan"
|
||||
msgstr "Πρόγραμμα Πιστώσεων"
|
||||
|
||||
#. js-lingui-id: qtEx+T
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
msgid "Credit plan upgraded."
|
||||
@@ -5331,6 +5308,7 @@ msgstr "φθίνουσα"
|
||||
|
||||
#. js-lingui-id: Cko536
|
||||
#: src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsSorts.tsx
|
||||
#: src/modules/views/editable-chip/components/EditableSortChip.tsx
|
||||
#: src/modules/side-panel/pages/page-layout/components/record-table-settings/RecordTableSettingsSorts.tsx
|
||||
#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
|
||||
#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
|
||||
@@ -5560,8 +5538,6 @@ msgstr ""
|
||||
#. js-lingui-id: LE8J+K
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Downgrade"
|
||||
msgstr "Υποβάθμιση"
|
||||
|
||||
@@ -6560,11 +6536,6 @@ msgstr ""
|
||||
msgid "Error while cancelling interval switching."
|
||||
msgstr "Σφάλμα κατά την ακύρωση αλλαγής περιόδου."
|
||||
|
||||
#. js-lingui-id: a1gs9Y
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Error while cancelling metered tier switching."
|
||||
msgstr "Σφάλμα κατά την ακύρωση αλλαγής τιμολογιακής βαθμίδας."
|
||||
|
||||
#. js-lingui-id: FS6DQK
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Error while cancelling plan switching."
|
||||
@@ -6888,11 +6859,6 @@ msgstr ""
|
||||
msgid "Expression"
|
||||
msgstr "Έκφραση"
|
||||
|
||||
#. js-lingui-id: uE7S0L
|
||||
#: src/modules/settings/billing/components/SettingsBillingCreditsSection.tsx
|
||||
msgid "Extra Credits Used"
|
||||
msgstr "Πρόσθετες μονάδες χρησιμοποιήθηκαν"
|
||||
|
||||
#. js-lingui-id: 7Bj3x9
|
||||
#: src/pages/settings/emailing-domains/utils/getEmailingDomainStatusText.ts
|
||||
#: src/pages/settings/admin-panel/SettingsAdminInstanceStatus.tsx
|
||||
@@ -7111,11 +7077,6 @@ msgstr ""
|
||||
msgid "Failed to update model selection mode"
|
||||
msgstr "Αποτυχία ενημέρωσης λειτουργίας επιλογής μοντέλου"
|
||||
|
||||
#. js-lingui-id: HnBqPY
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Failed to update price."
|
||||
msgstr "Αποτυχία ενημέρωσης τιμής."
|
||||
|
||||
#. js-lingui-id: J7vly7
|
||||
#: src/modules/object-record/record-update-multiple/components/UpdateMultipleRecordsContainer.tsx
|
||||
msgid "Failed to update records. Please try again."
|
||||
@@ -7483,6 +7444,11 @@ msgstr "Πρώτες 2 γραμμές"
|
||||
msgid "First 5 lines"
|
||||
msgstr "Πρώτες 5 γραμμές"
|
||||
|
||||
#. js-lingui-id: V1EGGU
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "First name"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: kODvZJ
|
||||
#: src/pages/onboarding/CreateProfile.tsx
|
||||
#: src/modules/settings/security/components/SettingsSecurityEditableProfileFields.tsx
|
||||
@@ -9062,6 +9028,7 @@ msgstr "Τελευταίο μήνυμα {lastMessageSentAtFormatted}"
|
||||
|
||||
#. js-lingui-id: 1ZaQUH
|
||||
#: src/modules/settings/members/components/MemberNameFields.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Last name"
|
||||
msgstr ""
|
||||
|
||||
@@ -9122,6 +9089,11 @@ msgstr "Τελευταία ημερομηνία"
|
||||
msgid "Latest version"
|
||||
msgstr "Τελευταία έκδοση"
|
||||
|
||||
#. js-lingui-id: Q7hYLw
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Latitude"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: ZEP8tT
|
||||
#: src/modules/settings/playground/components/PlaygroundSetupForm.tsx
|
||||
msgid "Launch"
|
||||
@@ -9499,6 +9471,11 @@ msgstr "Αποσύνδεση"
|
||||
msgid "Logs"
|
||||
msgstr "Καταγραφές"
|
||||
|
||||
#. js-lingui-id: FJBbw5
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Longitude"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: tL2lBI
|
||||
#: src/modules/workflow/workflow-diagram/utils/generateNodesAndEdgesForIteratorNode.ts
|
||||
msgid "loop"
|
||||
@@ -9810,11 +9787,6 @@ msgstr "Μεταδεδομένα"
|
||||
msgid "Metadata file generation failed"
|
||||
msgstr "Αποτυχία δημιουργίας αρχείου μεταδεδομένων"
|
||||
|
||||
#. js-lingui-id: onCJJ6
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Metered tier switching has been cancelled."
|
||||
msgstr "Η αλλαγή βαθμίδας ακυρώθηκε."
|
||||
|
||||
#. js-lingui-id: fiPesM
|
||||
#: src/modules/settings/logic-functions/components/triggers/SettingsLogicFunctionHttpTriggerSection.tsx
|
||||
msgid "Method"
|
||||
@@ -11169,7 +11141,6 @@ msgstr "Αριθμός δεκαδικών"
|
||||
|
||||
#. js-lingui-id: tYOaY8
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Number of new credits allocated every {recurringInterval}"
|
||||
msgstr "Αριθμός νέων πιστώσεων που διατίθενται κάθε {recurringInterval}"
|
||||
|
||||
@@ -12046,7 +12017,6 @@ msgstr "Παρακαλώ επιλέξτε τουλάχιστον ένα αντι
|
||||
|
||||
#. js-lingui-id: 8YnlGz
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Please start your subscription first"
|
||||
msgstr "Παρακαλώ ξεκινήστε πρώτα τη συνδρομή σας"
|
||||
|
||||
@@ -12125,6 +12095,7 @@ msgstr ""
|
||||
|
||||
#. js-lingui-id: OKJUcC
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Postcode"
|
||||
msgstr "Ταχυδρομικός Κωδικός"
|
||||
|
||||
@@ -12175,11 +12146,6 @@ msgstr "Προηγούμενο"
|
||||
msgid "Previous 7 days"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: jmc+FY
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Price updated."
|
||||
msgstr "Η τιμή ενημερώθηκε."
|
||||
|
||||
#. js-lingui-id: aHCEmh
|
||||
#: src/pages/settings/admin-panel/SettingsAdminNewAiModel.tsx
|
||||
msgid "Pricing"
|
||||
@@ -14571,6 +14537,7 @@ msgstr "Ξεκίνησε η διαδικασία επαλήθευσης"
|
||||
#: src/modules/settings/admin-panel/health-status/components/SettingsAdminQueueJobsTable.tsx
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "State"
|
||||
msgstr "Κατάσταση"
|
||||
|
||||
@@ -16320,8 +16287,6 @@ msgstr "Ενημερώσεις"
|
||||
#: src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelSection.tsx
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
msgid "Upgrade"
|
||||
@@ -16366,9 +16331,9 @@ msgstr ""
|
||||
msgid "Upgrade to {latestAvailableVersion}"
|
||||
msgstr "Αναβάθμιση σε {latestAvailableVersion}"
|
||||
|
||||
#. js-lingui-id: tLOGrv
|
||||
#. js-lingui-id: Kutw4+
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
msgid "Upgrade to {nextTierCredits} credits for ${nextTierPrice}/{nextTierInterval}."
|
||||
msgid "Upgrade to {nextResourceCreditsAmount} credits for ${nextResourceCreditPrice}/{nextTierInterval}."
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: ggd+Ee
|
||||
@@ -17549,11 +17514,6 @@ msgstr ""
|
||||
msgid "You have scheduled a credit pack change. Do you want to cancel it?"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: M2lYgq
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "You have scheduled a metered tier change. Do you want to cancel it?"
|
||||
msgstr "Έχετε προγραμματίσει αλλαγή βαθμίδας. Θέλετε να την ακυρώσετε;"
|
||||
|
||||
#. js-lingui-id: z8eKS7
|
||||
#: src/modules/settings/billing/hooks/useBillingWording.ts
|
||||
msgid "you will be charged ${enterprisePrice} per user per month"
|
||||
@@ -17591,11 +17551,11 @@ msgid ""
|
||||
"Reach to our support team to upgrade."
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: UUaKVD
|
||||
#. js-lingui-id: /fksQo
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
msgid ""
|
||||
"You've hit your usage limit. \n"
|
||||
"Upgrade to {nextTierCredits} credits for ${nextTierPrice}/{nextTierInterval}."
|
||||
"Upgrade to {nextResourceCreditsAmount} credits for ${nextResourceCreditPrice}/{nextTierInterval}."
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: yZ0wRS
|
||||
|
||||
@@ -231,10 +231,10 @@ msgstr "{agentLabel} Agent Role"
|
||||
msgid "{aggregateLabel} of {fieldLabel}"
|
||||
msgstr "{aggregateLabel} of {fieldLabel}"
|
||||
|
||||
#. js-lingui-id: LTvJAf
|
||||
#. js-lingui-id: ZZZxmp
|
||||
#: src/pages/auth/Authorize.tsx
|
||||
msgid "{appName} wants to access your account"
|
||||
msgstr "{appName} wants to access your account"
|
||||
msgid "{appName} would like to:"
|
||||
msgstr "{appName} would like to:"
|
||||
|
||||
#. js-lingui-id: y9covz
|
||||
#: src/pages/settings/admin-panel/SettingsAdminWorkspacesStatus.tsx
|
||||
@@ -261,11 +261,6 @@ msgstr "{contextStoreNumberOfSelectedRecords} selected"
|
||||
msgid "{count, plural, one {E.g. {0}{1} for {count} decimal} other {E.g. {2}{3} for {count} decimals}}"
|
||||
msgstr "{count, plural, one {E.g. {0}{1} for {count} decimal} other {E.g. {2}{3} for {count} decimals}}"
|
||||
|
||||
#. js-lingui-id: aTq2js
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "{credits} Credits - ${price}"
|
||||
msgstr "{credits} Credits - ${price}"
|
||||
|
||||
#. js-lingui-id: q8RNNe
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
msgid "{credits} Credits - ${priceDisplay}"
|
||||
@@ -803,10 +798,10 @@ msgstr "Access"
|
||||
msgid "Access Key ID"
|
||||
msgstr "Access Key ID"
|
||||
|
||||
#. js-lingui-id: o0Ci6l
|
||||
#. js-lingui-id: CrjDqe
|
||||
#: src/pages/auth/Authorize.tsx
|
||||
msgid "Access workspace data"
|
||||
msgstr "Access workspace data"
|
||||
msgid "Access your workspace data"
|
||||
msgstr "Access your workspace data"
|
||||
|
||||
#. js-lingui-id: c2UA7k
|
||||
#: src/pages/settings/ai/components/SettingsAiMCP.tsx
|
||||
@@ -1321,6 +1316,7 @@ msgstr "Added to blocklist"
|
||||
#: src/modules/ui/field/input/components/AddressInput.tsx
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Address 1"
|
||||
msgstr "Address 1"
|
||||
|
||||
@@ -1328,6 +1324,7 @@ msgstr "Address 1"
|
||||
#: src/modules/ui/field/input/components/AddressInput.tsx
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Address 2"
|
||||
msgstr "Address 2"
|
||||
|
||||
@@ -2327,6 +2324,7 @@ msgstr "ascending"
|
||||
|
||||
#. js-lingui-id: nYD/Cq
|
||||
#: src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsSorts.tsx
|
||||
#: src/modules/views/editable-chip/components/EditableSortChip.tsx
|
||||
#: src/modules/side-panel/pages/page-layout/components/record-table-settings/RecordTableSettingsSorts.tsx
|
||||
#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
|
||||
#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
|
||||
@@ -3039,16 +3037,6 @@ msgstr "Cancel interval switching"
|
||||
msgid "Cancel interval switching?"
|
||||
msgstr "Cancel interval switching?"
|
||||
|
||||
#. js-lingui-id: /Dmw1h
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Cancel metered tier switching"
|
||||
msgstr "Cancel metered tier switching"
|
||||
|
||||
#. js-lingui-id: Q/chGD
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Cancel metered tier switching?"
|
||||
msgstr "Cancel metered tier switching?"
|
||||
|
||||
#. js-lingui-id: rRK/Lf
|
||||
#: src/pages/settings/enterprise/SettingsEnterprise.tsx
|
||||
#: src/modules/settings/billing/components/SettingsBillingContent.tsx
|
||||
@@ -3362,6 +3350,7 @@ msgstr "Choose your Trial"
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "City"
|
||||
msgstr "City"
|
||||
|
||||
@@ -3790,11 +3779,6 @@ msgstr "Configured"
|
||||
msgid "Confirm"
|
||||
msgstr "Confirm"
|
||||
|
||||
#. js-lingui-id: qmnX/6
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Confirm changing your current credit plan."
|
||||
msgstr "Confirm changing your current credit plan."
|
||||
|
||||
#. js-lingui-id: q2rgqr
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
msgid "Confirm changing your current resource credit allocation."
|
||||
@@ -3807,7 +3791,6 @@ msgstr "Confirm deletion of {roleName} role? This cannot be undone. All members
|
||||
|
||||
#. js-lingui-id: kZkFSm
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Confirm downgrade"
|
||||
msgstr "Confirm downgrade"
|
||||
|
||||
@@ -3818,10 +3801,14 @@ msgstr "Confirm role update"
|
||||
|
||||
#. js-lingui-id: DDbn3x
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Confirm upgrade"
|
||||
msgstr "Confirm upgrade"
|
||||
|
||||
#. js-lingui-id: LOM1MR
|
||||
#: src/pages/auth/Authorize.tsx
|
||||
msgid "Connect {appName} to your account"
|
||||
msgstr "Connect {appName} to your account"
|
||||
|
||||
#. js-lingui-id: mFiwDA
|
||||
#: src/pages/settings/applications/components/SettingsApplicationConnectScopePickerModal.tsx
|
||||
msgid "Connect {providerDisplayName}"
|
||||
@@ -4123,7 +4110,6 @@ msgid "Core Objects"
|
||||
msgstr "Core Objects"
|
||||
|
||||
#. js-lingui-id: I99Miw
|
||||
#: src/modules/settings/billing/components/SettingsBillingCreditsSection.tsx
|
||||
#: src/modules/ai/components/internal/AiChatContextUsageButton.tsx
|
||||
msgid "Cost"
|
||||
msgstr "Cost"
|
||||
@@ -4133,11 +4119,6 @@ msgstr "Cost"
|
||||
msgid "Cost per 1M tokens"
|
||||
msgstr "Cost per 1M tokens"
|
||||
|
||||
#. js-lingui-id: HUPoL8
|
||||
#: src/modules/settings/billing/components/SettingsBillingCreditsSection.tsx
|
||||
msgid "Cost per Extra Credits"
|
||||
msgstr "Cost per Extra Credits"
|
||||
|
||||
#. js-lingui-id: 3X5ngu
|
||||
#: src/pages/settings/admin-panel/SettingsAdminNewAiModel.tsx
|
||||
msgid "Cost per million tokens (USD)"
|
||||
@@ -4220,6 +4201,7 @@ msgstr "Count unique values"
|
||||
#: src/modules/ui/field/input/components/AddressInput.tsx
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Country"
|
||||
msgstr "Country"
|
||||
|
||||
@@ -4420,11 +4402,6 @@ msgstr "Credit consumption over time."
|
||||
msgid "Credit pack switching has been cancelled."
|
||||
msgstr "Credit pack switching has been cancelled."
|
||||
|
||||
#. js-lingui-id: Efny36
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Credit Plan"
|
||||
msgstr "Credit Plan"
|
||||
|
||||
#. js-lingui-id: qtEx+T
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
msgid "Credit plan upgraded."
|
||||
@@ -5326,6 +5303,7 @@ msgstr "descending"
|
||||
|
||||
#. js-lingui-id: Cko536
|
||||
#: src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsSorts.tsx
|
||||
#: src/modules/views/editable-chip/components/EditableSortChip.tsx
|
||||
#: src/modules/side-panel/pages/page-layout/components/record-table-settings/RecordTableSettingsSorts.tsx
|
||||
#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
|
||||
#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
|
||||
@@ -5555,8 +5533,6 @@ msgstr "Dots and comma"
|
||||
#. js-lingui-id: LE8J+K
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Downgrade"
|
||||
msgstr "Downgrade"
|
||||
|
||||
@@ -6555,11 +6531,6 @@ msgstr "Error while cancelling credit pack switching."
|
||||
msgid "Error while cancelling interval switching."
|
||||
msgstr "Error while cancelling interval switching."
|
||||
|
||||
#. js-lingui-id: a1gs9Y
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Error while cancelling metered tier switching."
|
||||
msgstr "Error while cancelling metered tier switching."
|
||||
|
||||
#. js-lingui-id: FS6DQK
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Error while cancelling plan switching."
|
||||
@@ -6883,11 +6854,6 @@ msgstr "Exposes the function as a tool that AI agents can call"
|
||||
msgid "Expression"
|
||||
msgstr "Expression"
|
||||
|
||||
#. js-lingui-id: uE7S0L
|
||||
#: src/modules/settings/billing/components/SettingsBillingCreditsSection.tsx
|
||||
msgid "Extra Credits Used"
|
||||
msgstr "Extra Credits Used"
|
||||
|
||||
#. js-lingui-id: 7Bj3x9
|
||||
#: src/pages/settings/emailing-domains/utils/getEmailingDomainStatusText.ts
|
||||
#: src/pages/settings/admin-panel/SettingsAdminInstanceStatus.tsx
|
||||
@@ -7106,11 +7072,6 @@ msgstr "Failed to update model recommendations"
|
||||
msgid "Failed to update model selection mode"
|
||||
msgstr "Failed to update model selection mode"
|
||||
|
||||
#. js-lingui-id: HnBqPY
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Failed to update price."
|
||||
msgstr "Failed to update price."
|
||||
|
||||
#. js-lingui-id: J7vly7
|
||||
#: src/modules/object-record/record-update-multiple/components/UpdateMultipleRecordsContainer.tsx
|
||||
msgid "Failed to update records. Please try again."
|
||||
@@ -7478,6 +7439,11 @@ msgstr "First 2 lines"
|
||||
msgid "First 5 lines"
|
||||
msgstr "First 5 lines"
|
||||
|
||||
#. js-lingui-id: V1EGGU
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "First name"
|
||||
msgstr "First name"
|
||||
|
||||
#. js-lingui-id: kODvZJ
|
||||
#: src/pages/onboarding/CreateProfile.tsx
|
||||
#: src/modules/settings/security/components/SettingsSecurityEditableProfileFields.tsx
|
||||
@@ -9080,6 +9046,7 @@ msgstr "Last message {lastMessageSentAtFormatted}"
|
||||
|
||||
#. js-lingui-id: 1ZaQUH
|
||||
#: src/modules/settings/members/components/MemberNameFields.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Last name"
|
||||
msgstr "Last name"
|
||||
|
||||
@@ -9140,6 +9107,11 @@ msgstr "Latest date"
|
||||
msgid "Latest version"
|
||||
msgstr "Latest version"
|
||||
|
||||
#. js-lingui-id: Q7hYLw
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Latitude"
|
||||
msgstr "Latitude"
|
||||
|
||||
#. js-lingui-id: ZEP8tT
|
||||
#: src/modules/settings/playground/components/PlaygroundSetupForm.tsx
|
||||
msgid "Launch"
|
||||
@@ -9517,6 +9489,11 @@ msgstr "Logout"
|
||||
msgid "Logs"
|
||||
msgstr "Logs"
|
||||
|
||||
#. js-lingui-id: FJBbw5
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Longitude"
|
||||
msgstr "Longitude"
|
||||
|
||||
#. js-lingui-id: tL2lBI
|
||||
#: src/modules/workflow/workflow-diagram/utils/generateNodesAndEdgesForIteratorNode.ts
|
||||
msgid "loop"
|
||||
@@ -9828,11 +9805,6 @@ msgstr "Metadata"
|
||||
msgid "Metadata file generation failed"
|
||||
msgstr "Metadata file generation failed"
|
||||
|
||||
#. js-lingui-id: onCJJ6
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Metered tier switching has been cancelled."
|
||||
msgstr "Metered tier switching has been cancelled."
|
||||
|
||||
#. js-lingui-id: fiPesM
|
||||
#: src/modules/settings/logic-functions/components/triggers/SettingsLogicFunctionHttpTriggerSection.tsx
|
||||
msgid "Method"
|
||||
@@ -11187,7 +11159,6 @@ msgstr "Number of decimals"
|
||||
|
||||
#. js-lingui-id: tYOaY8
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Number of new credits allocated every {recurringInterval}"
|
||||
msgstr "Number of new credits allocated every {recurringInterval}"
|
||||
|
||||
@@ -12064,7 +12035,6 @@ msgstr "Please select at least one destination object for this relation."
|
||||
|
||||
#. js-lingui-id: 8YnlGz
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Please start your subscription first"
|
||||
msgstr "Please start your subscription first"
|
||||
|
||||
@@ -12143,6 +12113,7 @@ msgstr "Post-install"
|
||||
|
||||
#. js-lingui-id: OKJUcC
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Postcode"
|
||||
msgstr "Postcode"
|
||||
|
||||
@@ -12193,11 +12164,6 @@ msgstr "Previous"
|
||||
msgid "Previous 7 days"
|
||||
msgstr "Previous 7 days"
|
||||
|
||||
#. js-lingui-id: jmc+FY
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Price updated."
|
||||
msgstr "Price updated."
|
||||
|
||||
#. js-lingui-id: aHCEmh
|
||||
#: src/pages/settings/admin-panel/SettingsAdminNewAiModel.tsx
|
||||
msgid "Pricing"
|
||||
@@ -14587,6 +14553,7 @@ msgstr "Started verification process"
|
||||
#: src/modules/settings/admin-panel/health-status/components/SettingsAdminQueueJobsTable.tsx
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "State"
|
||||
msgstr "State"
|
||||
|
||||
@@ -16366,8 +16333,6 @@ msgstr "Updates"
|
||||
#: src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelSection.tsx
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
msgid "Upgrade"
|
||||
@@ -16412,10 +16377,10 @@ msgstr "Upgrade status refreshed"
|
||||
msgid "Upgrade to {latestAvailableVersion}"
|
||||
msgstr "Upgrade to {latestAvailableVersion}"
|
||||
|
||||
#. js-lingui-id: tLOGrv
|
||||
#. js-lingui-id: Kutw4+
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
msgid "Upgrade to {nextTierCredits} credits for ${nextTierPrice}/{nextTierInterval}."
|
||||
msgstr "Upgrade to {nextTierCredits} credits for ${nextTierPrice}/{nextTierInterval}."
|
||||
msgid "Upgrade to {nextResourceCreditsAmount} credits for ${nextResourceCreditPrice}/{nextTierInterval}."
|
||||
msgstr "Upgrade to {nextResourceCreditsAmount} credits for ${nextResourceCreditPrice}/{nextTierInterval}."
|
||||
|
||||
#. js-lingui-id: ggd+Ee
|
||||
#: src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelSection.tsx
|
||||
@@ -17595,11 +17560,6 @@ msgstr "You don't have access to this object."
|
||||
msgid "You have scheduled a credit pack change. Do you want to cancel it?"
|
||||
msgstr "You have scheduled a credit pack change. Do you want to cancel it?"
|
||||
|
||||
#. js-lingui-id: M2lYgq
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "You have scheduled a metered tier change. Do you want to cancel it?"
|
||||
msgstr "You have scheduled a metered tier change. Do you want to cancel it?"
|
||||
|
||||
#. js-lingui-id: z8eKS7
|
||||
#: src/modules/settings/billing/hooks/useBillingWording.ts
|
||||
msgid "you will be charged ${enterprisePrice} per user per month"
|
||||
@@ -17639,14 +17599,14 @@ msgstr ""
|
||||
"You've hit your usage limit. \n"
|
||||
"Reach to our support team to upgrade."
|
||||
|
||||
#. js-lingui-id: UUaKVD
|
||||
#. js-lingui-id: /fksQo
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
msgid ""
|
||||
"You've hit your usage limit. \n"
|
||||
"Upgrade to {nextTierCredits} credits for ${nextTierPrice}/{nextTierInterval}."
|
||||
"Upgrade to {nextResourceCreditsAmount} credits for ${nextResourceCreditPrice}/{nextTierInterval}."
|
||||
msgstr ""
|
||||
"You've hit your usage limit. \n"
|
||||
"Upgrade to {nextTierCredits} credits for ${nextTierPrice}/{nextTierInterval}."
|
||||
"Upgrade to {nextResourceCreditsAmount} credits for ${nextResourceCreditPrice}/{nextTierInterval}."
|
||||
|
||||
#. js-lingui-id: yZ0wRS
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
|
||||
@@ -236,10 +236,10 @@ msgstr "Rol de agente de {agentLabel}"
|
||||
msgid "{aggregateLabel} of {fieldLabel}"
|
||||
msgstr "{aggregateLabel} de {fieldLabel}"
|
||||
|
||||
#. js-lingui-id: LTvJAf
|
||||
#. js-lingui-id: ZZZxmp
|
||||
#: src/pages/auth/Authorize.tsx
|
||||
msgid "{appName} wants to access your account"
|
||||
msgstr "{appName} quiere acceder a tu cuenta"
|
||||
msgid "{appName} would like to:"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: y9covz
|
||||
#: src/pages/settings/admin-panel/SettingsAdminWorkspacesStatus.tsx
|
||||
@@ -266,11 +266,6 @@ msgstr "{contextStoreNumberOfSelectedRecords} seleccionados"
|
||||
msgid "{count, plural, one {E.g. {0}{1} for {count} decimal} other {E.g. {2}{3} for {count} decimals}}"
|
||||
msgstr "{count, plural, one {Ej. {0}{1} para {count} decimal} other {Ej. {2}{3} para {count} decimales}}"
|
||||
|
||||
#. js-lingui-id: aTq2js
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "{credits} Credits - ${price}"
|
||||
msgstr "{credits} créditos - ${price}"
|
||||
|
||||
#. js-lingui-id: q8RNNe
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
msgid "{credits} Credits - ${priceDisplay}"
|
||||
@@ -808,10 +803,10 @@ msgstr ""
|
||||
msgid "Access Key ID"
|
||||
msgstr "ID de clave de acceso"
|
||||
|
||||
#. js-lingui-id: o0Ci6l
|
||||
#. js-lingui-id: CrjDqe
|
||||
#: src/pages/auth/Authorize.tsx
|
||||
msgid "Access workspace data"
|
||||
msgstr "Acceder a los datos del espacio de trabajo"
|
||||
msgid "Access your workspace data"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: c2UA7k
|
||||
#: src/pages/settings/ai/components/SettingsAiMCP.tsx
|
||||
@@ -1326,6 +1321,7 @@ msgstr "Añadido a la lista de bloqueo"
|
||||
#: src/modules/ui/field/input/components/AddressInput.tsx
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Address 1"
|
||||
msgstr "Dirección 1"
|
||||
|
||||
@@ -1333,6 +1329,7 @@ msgstr "Dirección 1"
|
||||
#: src/modules/ui/field/input/components/AddressInput.tsx
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Address 2"
|
||||
msgstr "Dirección 2"
|
||||
|
||||
@@ -2332,6 +2329,7 @@ msgstr "ascendente"
|
||||
|
||||
#. js-lingui-id: nYD/Cq
|
||||
#: src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsSorts.tsx
|
||||
#: src/modules/views/editable-chip/components/EditableSortChip.tsx
|
||||
#: src/modules/side-panel/pages/page-layout/components/record-table-settings/RecordTableSettingsSorts.tsx
|
||||
#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
|
||||
#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
|
||||
@@ -3044,16 +3042,6 @@ msgstr "Cancelar cambio de intervalo"
|
||||
msgid "Cancel interval switching?"
|
||||
msgstr "¿Cancelar cambio de intervalo?"
|
||||
|
||||
#. js-lingui-id: /Dmw1h
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Cancel metered tier switching"
|
||||
msgstr "Cancelar cambio de nivel medido"
|
||||
|
||||
#. js-lingui-id: Q/chGD
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Cancel metered tier switching?"
|
||||
msgstr "¿Cancelar cambio de nivel medido?"
|
||||
|
||||
#. js-lingui-id: rRK/Lf
|
||||
#: src/pages/settings/enterprise/SettingsEnterprise.tsx
|
||||
#: src/modules/settings/billing/components/SettingsBillingContent.tsx
|
||||
@@ -3367,6 +3355,7 @@ msgstr "Elija su prueba"
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "City"
|
||||
msgstr "Ciudad"
|
||||
|
||||
@@ -3795,11 +3784,6 @@ msgstr "Configurado"
|
||||
msgid "Confirm"
|
||||
msgstr "Confirmar"
|
||||
|
||||
#. js-lingui-id: qmnX/6
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Confirm changing your current credit plan."
|
||||
msgstr "Confirmar el cambio de tu plan de crédito actual."
|
||||
|
||||
#. js-lingui-id: q2rgqr
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
msgid "Confirm changing your current resource credit allocation."
|
||||
@@ -3812,7 +3796,6 @@ msgstr "¿Confirmar eliminación del rol {roleName}? Esto no se puede deshacer.
|
||||
|
||||
#. js-lingui-id: kZkFSm
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Confirm downgrade"
|
||||
msgstr "Confirmar degradación"
|
||||
|
||||
@@ -3823,10 +3806,14 @@ msgstr "Confirmar la actualización del rol"
|
||||
|
||||
#. js-lingui-id: DDbn3x
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Confirm upgrade"
|
||||
msgstr "Confirmar actualización"
|
||||
|
||||
#. js-lingui-id: LOM1MR
|
||||
#: src/pages/auth/Authorize.tsx
|
||||
msgid "Connect {appName} to your account"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: mFiwDA
|
||||
#: src/pages/settings/applications/components/SettingsApplicationConnectScopePickerModal.tsx
|
||||
msgid "Connect {providerDisplayName}"
|
||||
@@ -4128,7 +4115,6 @@ msgid "Core Objects"
|
||||
msgstr "Objetos principales"
|
||||
|
||||
#. js-lingui-id: I99Miw
|
||||
#: src/modules/settings/billing/components/SettingsBillingCreditsSection.tsx
|
||||
#: src/modules/ai/components/internal/AiChatContextUsageButton.tsx
|
||||
msgid "Cost"
|
||||
msgstr "Costo"
|
||||
@@ -4138,11 +4124,6 @@ msgstr "Costo"
|
||||
msgid "Cost per 1M tokens"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: HUPoL8
|
||||
#: src/modules/settings/billing/components/SettingsBillingCreditsSection.tsx
|
||||
msgid "Cost per Extra Credits"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: 3X5ngu
|
||||
#: src/pages/settings/admin-panel/SettingsAdminNewAiModel.tsx
|
||||
msgid "Cost per million tokens (USD)"
|
||||
@@ -4225,6 +4206,7 @@ msgstr "Contar valores únicos"
|
||||
#: src/modules/ui/field/input/components/AddressInput.tsx
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Country"
|
||||
msgstr "País"
|
||||
|
||||
@@ -4425,11 +4407,6 @@ msgstr "Consumo de créditos a lo largo del tiempo."
|
||||
msgid "Credit pack switching has been cancelled."
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: Efny36
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Credit Plan"
|
||||
msgstr "Plan de Crédito"
|
||||
|
||||
#. js-lingui-id: qtEx+T
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
msgid "Credit plan upgraded."
|
||||
@@ -5331,6 +5308,7 @@ msgstr "descendente"
|
||||
|
||||
#. js-lingui-id: Cko536
|
||||
#: src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsSorts.tsx
|
||||
#: src/modules/views/editable-chip/components/EditableSortChip.tsx
|
||||
#: src/modules/side-panel/pages/page-layout/components/record-table-settings/RecordTableSettingsSorts.tsx
|
||||
#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
|
||||
#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
|
||||
@@ -5560,8 +5538,6 @@ msgstr ""
|
||||
#. js-lingui-id: LE8J+K
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Downgrade"
|
||||
msgstr "Degradar"
|
||||
|
||||
@@ -6560,11 +6536,6 @@ msgstr ""
|
||||
msgid "Error while cancelling interval switching."
|
||||
msgstr "Error al cancelar el cambio de intervalo."
|
||||
|
||||
#. js-lingui-id: a1gs9Y
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Error while cancelling metered tier switching."
|
||||
msgstr "Error al cancelar el cambio de nivel medido."
|
||||
|
||||
#. js-lingui-id: FS6DQK
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Error while cancelling plan switching."
|
||||
@@ -6888,11 +6859,6 @@ msgstr ""
|
||||
msgid "Expression"
|
||||
msgstr "Expresión"
|
||||
|
||||
#. js-lingui-id: uE7S0L
|
||||
#: src/modules/settings/billing/components/SettingsBillingCreditsSection.tsx
|
||||
msgid "Extra Credits Used"
|
||||
msgstr "Créditos Extra Usados"
|
||||
|
||||
#. js-lingui-id: 7Bj3x9
|
||||
#: src/pages/settings/emailing-domains/utils/getEmailingDomainStatusText.ts
|
||||
#: src/pages/settings/admin-panel/SettingsAdminInstanceStatus.tsx
|
||||
@@ -7111,11 +7077,6 @@ msgstr ""
|
||||
msgid "Failed to update model selection mode"
|
||||
msgstr "Error al actualizar el modo de selección de modelos"
|
||||
|
||||
#. js-lingui-id: HnBqPY
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Failed to update price."
|
||||
msgstr "Error al actualizar el precio."
|
||||
|
||||
#. js-lingui-id: J7vly7
|
||||
#: src/modules/object-record/record-update-multiple/components/UpdateMultipleRecordsContainer.tsx
|
||||
msgid "Failed to update records. Please try again."
|
||||
@@ -7483,6 +7444,11 @@ msgstr "Primeras 2 líneas"
|
||||
msgid "First 5 lines"
|
||||
msgstr "Primeras 5 líneas"
|
||||
|
||||
#. js-lingui-id: V1EGGU
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "First name"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: kODvZJ
|
||||
#: src/pages/onboarding/CreateProfile.tsx
|
||||
#: src/modules/settings/security/components/SettingsSecurityEditableProfileFields.tsx
|
||||
@@ -9062,6 +9028,7 @@ msgstr "Último mensaje {lastMessageSentAtFormatted}"
|
||||
|
||||
#. js-lingui-id: 1ZaQUH
|
||||
#: src/modules/settings/members/components/MemberNameFields.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Last name"
|
||||
msgstr ""
|
||||
|
||||
@@ -9122,6 +9089,11 @@ msgstr "Última fecha"
|
||||
msgid "Latest version"
|
||||
msgstr "Última versión"
|
||||
|
||||
#. js-lingui-id: Q7hYLw
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Latitude"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: ZEP8tT
|
||||
#: src/modules/settings/playground/components/PlaygroundSetupForm.tsx
|
||||
msgid "Launch"
|
||||
@@ -9499,6 +9471,11 @@ msgstr "Cerrar sesión"
|
||||
msgid "Logs"
|
||||
msgstr "Registros"
|
||||
|
||||
#. js-lingui-id: FJBbw5
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Longitude"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: tL2lBI
|
||||
#: src/modules/workflow/workflow-diagram/utils/generateNodesAndEdgesForIteratorNode.ts
|
||||
msgid "loop"
|
||||
@@ -9810,11 +9787,6 @@ msgstr "Metadatos"
|
||||
msgid "Metadata file generation failed"
|
||||
msgstr "Fallo en la generación del archivo de metadatos"
|
||||
|
||||
#. js-lingui-id: onCJJ6
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "Metered tier switching has been cancelled."
|
||||
msgstr "El cambio de nivel medido ha sido cancelado."
|
||||
|
||||
#. js-lingui-id: fiPesM
|
||||
#: src/modules/settings/logic-functions/components/triggers/SettingsLogicFunctionHttpTriggerSection.tsx
|
||||
msgid "Method"
|
||||
@@ -11169,7 +11141,6 @@ msgstr "Número de decimales"
|
||||
|
||||
#. js-lingui-id: tYOaY8
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Number of new credits allocated every {recurringInterval}"
|
||||
msgstr "Cantidad de nuevos créditos asignados cada {recurringInterval}"
|
||||
|
||||
@@ -12046,7 +12017,6 @@ msgstr "Por favor, seleccione al menos un objeto de destino para esta relación.
|
||||
|
||||
#. js-lingui-id: 8YnlGz
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Please start your subscription first"
|
||||
msgstr "Por favor, inicia tu suscripción primero"
|
||||
|
||||
@@ -12125,6 +12095,7 @@ msgstr ""
|
||||
|
||||
#. js-lingui-id: OKJUcC
|
||||
#: src/modules/settings/data-model/fields/forms/address/constants/DefaultSelectionAddressWithMessages.ts
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "Postcode"
|
||||
msgstr "Código postal"
|
||||
|
||||
@@ -12175,11 +12146,6 @@ msgstr "Anterior"
|
||||
msgid "Previous 7 days"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: jmc+FY
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
msgid "Price updated."
|
||||
msgstr "Precio actualizado."
|
||||
|
||||
#. js-lingui-id: aHCEmh
|
||||
#: src/pages/settings/admin-panel/SettingsAdminNewAiModel.tsx
|
||||
msgid "Pricing"
|
||||
@@ -14569,6 +14535,7 @@ msgstr "Proceso de verificación iniciado"
|
||||
#: src/modules/settings/admin-panel/health-status/components/SettingsAdminQueueJobsTable.tsx
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-record/record-field/ui/form-types/components/FormAddressFieldInput.tsx
|
||||
#: src/modules/object-metadata/hooks/useSortSubFieldChoicesForField.ts
|
||||
msgid "State"
|
||||
msgstr "Estado"
|
||||
|
||||
@@ -16318,8 +16285,6 @@ msgstr "Actualizaciones"
|
||||
#: src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelSection.tsx
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/ResourceCreditPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
#: src/modules/settings/billing/components/internal/MeteredPriceSelector.tsx
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
msgid "Upgrade"
|
||||
@@ -16364,9 +16329,9 @@ msgstr ""
|
||||
msgid "Upgrade to {latestAvailableVersion}"
|
||||
msgstr "Actualizar a {latestAvailableVersion}"
|
||||
|
||||
#. js-lingui-id: tLOGrv
|
||||
#. js-lingui-id: Kutw4+
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
msgid "Upgrade to {nextTierCredits} credits for ${nextTierPrice}/{nextTierInterval}."
|
||||
msgid "Upgrade to {nextResourceCreditsAmount} credits for ${nextResourceCreditPrice}/{nextTierInterval}."
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: ggd+Ee
|
||||
@@ -17547,11 +17512,6 @@ msgstr ""
|
||||
msgid "You have scheduled a credit pack change. Do you want to cancel it?"
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: M2lYgq
|
||||
#: src/modules/settings/billing/components/SettingsBillingSubscriptionInfo.tsx
|
||||
msgid "You have scheduled a metered tier change. Do you want to cancel it?"
|
||||
msgstr "Has programado un cambio de nivel medido. ¿Quieres cancelarlo?"
|
||||
|
||||
#. js-lingui-id: z8eKS7
|
||||
#: src/modules/settings/billing/hooks/useBillingWording.ts
|
||||
msgid "you will be charged ${enterprisePrice} per user per month"
|
||||
@@ -17589,11 +17549,11 @@ msgid ""
|
||||
"Reach to our support team to upgrade."
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: UUaKVD
|
||||
#. js-lingui-id: /fksQo
|
||||
#: src/modules/ai/components/AIChatNoMoreBillingCreditsBanner.tsx
|
||||
msgid ""
|
||||
"You've hit your usage limit. \n"
|
||||
"Upgrade to {nextTierCredits} credits for ${nextTierPrice}/{nextTierInterval}."
|
||||
"Upgrade to {nextResourceCreditsAmount} credits for ${nextResourceCreditPrice}/{nextTierInterval}."
|
||||
msgstr ""
|
||||
|
||||
#. js-lingui-id: yZ0wRS
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user