snapshot of https://github.com/twentyhq/twenty.git (main, 2026-09-17; blobs > 131072B omitted)
Some checks failed
App Prod-Parity E2E Dispatch / dispatch (push) Failing after 10s
CD Storybook UI / build (push) Failing after 3m25s
CD Storybook UI / dispatch (push) Has been skipped
CD deploy main / website-changed-files (push) Successful in 18m8s
CI Agent Skills / changed-files-check (push) Successful in 18m9s
CI Create App E2E minimal / changed-files-check (push) Successful in 24s
CI Create App / changed-files-check (push) Successful in 26s
CI Docs / changed-files-check (push) Successful in 26s
CI Emails / changed-files-check (push) Successful in 28s
CI Example App Hello World / changed-files-check (push) Successful in 23s
CI Front / changed-files-check (push) Has been skipped
CI Example App Postcard / changed-files-check (push) Successful in 27s
CI UI / changed-files-check (push) Has been skipped
CI Utils Test / changed-files-check (push) Successful in 45s
CI Twenty Apps / discover (push) Successful in 1m3s
CD deploy main / deploy-main (push) Failing after 3s
CI Agent Skills / agent-skills-validate (push) Has been skipped
CI Create App / create-app-test (lint) (push) Has been skipped
CI Emails / emails-test (push) Has been skipped
CI Front / front-task (lingui:compile) (push) Has been skipped
CI Front / front-task (lint) (push) Has been skipped
CI Example App Postcard / example-app-postcard (push) Has been skipped
CI UI / ui-task (lint) (push) Has been skipped
CI UI / ui-task (pack-size) (push) Has been skipped
CI UI / ui-task (size) (push) Has been skipped
CI UI / ui-task (test) (push) Has been skipped
CI UI / ui-task (typecheck) (push) Has been skipped
CI Utils Test / utils-test (push) Has been skipped
CI Twenty Apps / ${{ matrix.app.name }} (push) Has been skipped
CI Emails / ci-emails-status-check (push) Successful in 2s
CI Example App Hello World / ci-example-app-hello-world-status-check (push) Successful in 2s
CI Example App Postcard / ci-example-app-postcard-status-check (push) Successful in 3s
CI UI / ui-sb-test (push) Has been skipped
CI Utils Test / ci-utils-test-status-check (push) Successful in 2s
CI Twenty Apps / ci-twenty-apps-status-check (push) Successful in 2s
CI UI / ci-ui-status-check (push) Successful in 2s
CI Desktop / desktop (push) Failing after 1m8s
Push docs to Crowdin / Push documentation to Crowdin (push) Failing after 55s
Push translations to Crowdin / Extract and upload translations (push) Failing after 5s
Push website translations to Crowdin / Extract and upload website translations (push) Failing after 5s
CI Create App / create-app-test (test) (push) Has been skipped
CI Create App / create-app-test (typecheck) (push) Has been skipped
CI Docs / docs-lint (push) Has been skipped
CI Example App Hello World / example-app-hello-world (push) Has been skipped
CI Front / front-task (lingui:extract) (push) Has been skipped
CI Front / front-task (test) (push) Has been skipped
CI Front / front-task (typecheck) (push) Has been skipped
CI UI / ui-sb-build (push) Failing after 1m32s
CI Twenty Apps / ${{ matrix.app.name }} (${{ matrix.server-source }}) (push) Has been skipped
CI Agent Skills / agent-skills-publish (push) Has been skipped
CI Create App / ci-create-app-status-check (push) Successful in 2s
CI Agent Skills / agent-skills-remote-source (push) Has been skipped
CI Create App E2E minimal / create-app-e2e-minimal (push) Has been cancelled
CI E2E Main / e2e-test (push) Has been cancelled
CI Front / front-sb-build (push) Has been cancelled
CI Front / front-build (push) Has been cancelled
CI Create App E2E minimal / ci-create-app-e2e-minimal-status-check (push) Has been cancelled
CI E2E Main / ci-e2e-main-status-check (push) Has been cancelled
CI E2E Main / notify-main-ci-failure (push) Has been cancelled
CI E2E Main / qa-scout-comment (push) Has been cancelled
CI Front / front-sb-test (push) Has been cancelled
CI Front / front-sb-screenshots (push) Has been cancelled
CI Front / ci-front-status-check (push) Has been cancelled
DPA Sub-Processor Sync / sync-subprocessors (push) Failing after 3s
AI Catalog Sync / sync-catalog (push) Failing after 2s

This commit is contained in:
upstream-mirror
2026-09-17 23:28:13 +05:00
commit e7da97194a
32688 changed files with 4208681 additions and 0 deletions

View File

@@ -0,0 +1,19 @@
{
"$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"
}
}

View File

@@ -0,0 +1,3 @@
# Function Execute Test App
Fixture app used to exercise logic-function execution in SDK tests.

View File

@@ -0,0 +1,11 @@
import { defineApplication } from 'twenty-sdk/define';
import { DEFAULT_ROLE_UNIVERSAL_IDENTIFIER } from './my.role';
export default defineApplication({
universalIdentifier: '01e065d6-1b48-4107-86d8-b06f87420a4f',
displayName: 'Function Execute Test App',
description: 'A minimal app for testing function:execute',
icon: 'IconFunction',
defaultRoleUniversalIdentifier: DEFAULT_ROLE_UNIVERSAL_IDENTIFIER,
});

View File

@@ -0,0 +1,18 @@
import { defineRole } from 'twenty-sdk/define';
export const DEFAULT_ROLE_UNIVERSAL_IDENTIFIER =
'9f992b6c-17e9-4381-bab5-b6150b574304';
export default defineRole({
universalIdentifier: DEFAULT_ROLE_UNIVERSAL_IDENTIFIER,
label: 'Default role',
description: 'Default role for function execute test app',
canReadAllObjectRecords: true,
canUpdateAllObjectRecords: false,
canSoftDeleteAllObjectRecords: false,
canDestroyAllObjectRecords: false,
canUpdateAllSettings: false,
canBeAssignedToAgents: false,
canBeAssignedToUsers: true,
canBeAssignedToApiKeys: false,
});

View File

@@ -0,0 +1,29 @@
{
"name": "function-execute-app",
"version": "0.1.0",
"license": "MIT",
"engines": {
"node": "^24.5.0",
"npm": "please-use-yarn",
"yarn": ">=4.0.2"
},
"packageManager": "yarn@4.9.2",
"scripts": {
"dev": "twenty dev",
"exec": "twenty dev:fn-exec",
"uninstall": "twenty app:uninstall",
"lint": "oxlint -c .oxlintrc.json .",
"lint:fix": "oxlint --fix -c .oxlintrc.json ."
},
"dependencies": {
"twenty-sdk": "latest",
"twenty-client-sdk": "latest"
},
"devDependencies": {
"typescript": "^5.9.3",
"@types/node": "^24.7.2",
"@types/react": "^19.0.2",
"react": "^19.0.2",
"oxlint": "^0.16.0"
}
}

View File

@@ -0,0 +1,24 @@
import { defineLogicFunction } from 'twenty-sdk/define';
export const ADD_NUMBERS_UNIVERSAL_IDENTIFIER =
'f9e5589c-e951-4d99-85db-0a305ab53502';
const addNumbersHandler = (payload: { a: number; b: number }) => {
const result = payload.a + payload.b;
console.log(`Adding ${payload.a} + ${payload.b} = ${result}`);
return result;
};
export default defineLogicFunction({
universalIdentifier: ADD_NUMBERS_UNIVERSAL_IDENTIFIER,
name: 'add-numbers',
timeoutSeconds: 5,
handler: addNumbersHandler,
httpRouteTriggerSettings: {
path: '/add-numbers',
httpMethod: 'GET',
isAuthRequired: false,
},
});

View File

@@ -0,0 +1,17 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"jsx": "react-jsx",
"baseUrl": ".",
"paths": {
"src/*": ["./src/*"]
}
},
"include": ["**/*"],
"exclude": ["node_modules", "dist", ".twenty"]
}

View File

@@ -0,0 +1,19 @@
{
"$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"
}
}

View File

@@ -0,0 +1,9 @@
import { defineApplication } from 'twenty-sdk/define';
export default defineApplication({
universalIdentifier: 'invalid-app-0000-0000-0000-000000000001',
displayName: 'Invalid App',
description: 'An app with duplicate IDs for testing validation',
icon: 'IconAlertTriangle',
defaultRoleUniversalIdentifier: 'e1e2e3e4-e5e6-4000-8000-000000000002',
});

View File

@@ -0,0 +1,27 @@
{
"name": "invalid-app",
"version": "0.1.0",
"license": "MIT",
"engines": {
"node": "^24.5.0",
"npm": "please-use-yarn",
"yarn": ">=4.0.2"
},
"packageManager": "yarn@4.9.2",
"scripts": {
"twenty": "twenty",
"lint": "oxlint -c .oxlintrc.json .",
"lint:fix": "oxlint --fix -c .oxlintrc.json ."
},
"dependencies": {
"twenty-sdk": "latest",
"twenty-client-sdk": "latest"
},
"devDependencies": {
"typescript": "^5.9.3",
"@types/node": "^24.7.2",
"@types/react": "^19.0.2",
"react": "^19.0.2",
"oxlint": "^0.16.0"
}
}

View File

@@ -0,0 +1,23 @@
import { defineObject, FieldType } from 'twenty-sdk/define';
const DUPLICATE_ID = 'duplicate-id-0000-0000-000000000001';
export default defineObject({
universalIdentifier: DUPLICATE_ID,
nameSingular: 'firstObject',
namePlural: 'firstObjects',
labelSingular: 'First object',
labelPlural: 'First objects',
description: 'First object with duplicate ID',
icon: 'IconBox',
labelIdentifierFieldMetadataUniversalIdentifier:
'first-field-0000-0000-000000000001',
fields: [
{
universalIdentifier: 'first-field-0000-0000-000000000001',
type: FieldType.TEXT,
label: 'Name',
name: 'name',
},
],
});

View File

@@ -0,0 +1,23 @@
import { defineObject, FieldType } from 'twenty-sdk/define';
const DUPLICATE_ID = 'duplicate-id-0000-0000-000000000001';
export default defineObject({
universalIdentifier: DUPLICATE_ID,
nameSingular: 'secondObject',
namePlural: 'secondObjects',
labelSingular: 'Second object',
labelPlural: 'Second objects',
description: 'Second object with duplicate ID',
icon: 'IconBox',
labelIdentifierFieldMetadataUniversalIdentifier:
'second-field-0000-0000-000000000001',
fields: [
{
universalIdentifier: 'second-field-0000-0000-000000000001',
type: FieldType.TEXT,
label: 'Title',
name: 'title',
},
],
});

View File

@@ -0,0 +1,17 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"jsx": "react-jsx",
"baseUrl": ".",
"paths": {
"src/*": ["./src/*"]
}
},
"include": ["**/*"],
"exclude": ["node_modules", "dist", ".twenty"]
}

View File

@@ -0,0 +1,6 @@
# This file is generated by running "yarn install" inside your project.
# Manual changes might be lost - proceed with caution!
__metadata:
version: 8
cacheKey: 10c0

View File

@@ -0,0 +1,19 @@
{
"$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"
}
}

View File

@@ -0,0 +1,8 @@
import { defineApplication } from 'twenty-sdk/define';
export default defineApplication({
universalIdentifier: 'e1e2e3e4-e5e6-4000-8000-000000000001',
displayName: 'Root App',
description: 'An app with all entities at root level',
defaultRoleUniversalIdentifier: 'e1e2e3e4-e5e6-4000-8000-000000000002',
});

View File

@@ -0,0 +1 @@
declare module '*.css';

View File

@@ -0,0 +1,18 @@
import { defineFrontComponent } from 'twenty-sdk/define';
import 'twenty-ui/style.css';
export const MyComponent = () => {
return (
<div style={{ padding: '10px' }}>
<h2>My Component</h2>
</div>
);
};
export default defineFrontComponent({
universalIdentifier: 'e1e2e3e4-e5e6-4000-8000-000000000020',
name: 'my-component',
description: 'A root-level front component',
component: MyComponent,
});

View File

@@ -0,0 +1,17 @@
import { defineLogicFunction } from 'twenty-sdk/define';
const myHandler = () => {
return 'my-function-result';
};
export default defineLogicFunction({
universalIdentifier: 'e1e2e3e4-e5e6-4000-8000-000000000010',
name: 'my-function',
timeoutSeconds: 5,
handler: myHandler,
httpRouteTriggerSettings: {
path: '/my-function',
httpMethod: 'GET',
isAuthRequired: false,
},
});

View File

@@ -0,0 +1,21 @@
import { FieldType, defineObject } from 'twenty-sdk/define';
export default defineObject({
universalIdentifier: 'e1e2e3e4-e5e6-4000-8000-000000000030',
nameSingular: 'myNote',
namePlural: 'myNotes',
labelSingular: 'My note',
labelPlural: 'My notes',
description: 'A simple root-level object',
icon: 'IconNote',
labelIdentifierFieldMetadataUniversalIdentifier:
'e1e2e3e4-e5e6-4000-8000-000000000031',
fields: [
{
universalIdentifier: 'e1e2e3e4-e5e6-4000-8000-000000000031',
type: FieldType.TEXT,
label: 'Title',
name: 'title',
},
],
});

View File

@@ -0,0 +1,15 @@
import { defineRole } from 'twenty-sdk/define';
export default defineRole({
universalIdentifier: 'e1e2e3e4-e5e6-4000-8000-000000000040',
label: 'My role',
description: 'A simple root-level role',
canReadAllObjectRecords: true,
canUpdateAllObjectRecords: false,
canSoftDeleteAllObjectRecords: false,
canDestroyAllObjectRecords: false,
canUpdateAllSettings: false,
canBeAssignedToAgents: false,
canBeAssignedToUsers: true,
canBeAssignedToApiKeys: false,
});

View File

@@ -0,0 +1,28 @@
{
"name": "minimal-app",
"version": "0.1.0",
"license": "MIT",
"engines": {
"node": "^24.5.0",
"npm": "please-use-yarn",
"yarn": ">=4.0.2"
},
"packageManager": "yarn@4.9.2",
"scripts": {
"twenty": "twenty",
"lint": "oxlint -c .oxlintrc.json .",
"lint:fix": "oxlint --fix -c .oxlintrc.json ."
},
"dependencies": {
"twenty-sdk": "latest",
"twenty-client-sdk": "latest",
"twenty-ui": "latest"
},
"devDependencies": {
"typescript": "^5.9.3",
"@types/node": "^24.7.2",
"@types/react": "^19.0.2",
"react": "^19.0.2",
"oxlint": "^0.16.0"
}
}

View File

@@ -0,0 +1,17 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"jsx": "react-jsx",
"baseUrl": ".",
"paths": {
"src/*": ["./src/*"]
}
},
"include": ["**/*"],
"exclude": ["node_modules", "dist", ".twenty"]
}

View File

@@ -0,0 +1,6 @@
# This file is generated by running "yarn install" inside your project.
# Manual changes might be lost - proceed with caution!
__metadata:
version: 8
cacheKey: 10c0

View File

@@ -0,0 +1 @@
generated

View File

@@ -0,0 +1,19 @@
{
"$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"
}
}

View File

@@ -0,0 +1,175 @@
import { defineApplication, FieldType } from 'twenty-sdk/define';
import { DEFAULT_ROLE_UNIVERSAL_IDENTIFIER } from './src/roles/default-function.role';
export default defineApplication({
universalIdentifier: '4ec0391d-18d5-411c-b2f3-266ddc1c3ef7',
displayName: 'Rich App',
description: 'A simple rich app',
applicationVariables: {
DEFAULT_RECIPIENT_NAME: {
universalIdentifier: '19e94e59-d4fe-4251-8981-b96d0a9f74de',
description: 'Default recipient name for postcards',
value: 'Alex Karp',
isSecret: false,
},
GREETING_TEXT: {
universalIdentifier: 'ad19edc5-4cc5-4003-a996-aef53a5c8de0',
description: 'Free text shown on the postcard',
type: FieldType.TEXT,
value: 'Hello from Rich App',
},
ENABLE_TRACKING: {
universalIdentifier: 'b9c58bb2-58c3-4c6c-9877-498ea6c03fde',
description: 'Toggle delivery tracking',
type: FieldType.BOOLEAN,
value: true,
},
MAX_POSTCARDS: {
universalIdentifier: '5f4497e4-9030-4085-85eb-2c48b8d53713',
description: 'Maximum postcards per batch',
type: FieldType.NUMBER,
value: 10,
},
DISCOUNT_RATE: {
universalIdentifier: 'd32f810f-06bb-4d29-b0ee-1dc4228f7cb8',
description: 'Bulk discount rate applied at checkout',
type: FieldType.NUMERIC,
value: 2.5,
},
CAMPAIGN_START_DATE: {
universalIdentifier: '5aa4fcec-e8a3-4bc1-9c7f-762e1f9dfb40',
description: 'Date the campaign starts',
type: FieldType.DATE,
value: '2026-01-01',
},
CAMPAIGN_START_AT: {
universalIdentifier: '273d0cfd-d6ab-4148-8816-c4a5d4b1d600',
description: 'Exact moment the campaign starts',
type: FieldType.DATE_TIME,
value: '2026-01-01T09:00:00.000Z',
},
DEFAULT_REGION: {
universalIdentifier: '76c5c321-b6b6-46eb-b4fc-f9f04bb04227',
description: 'Default shipping region',
type: FieldType.SELECT,
options: [
{ label: 'Europe', value: 'eu' },
{ label: 'United States', value: 'us' },
{ label: 'Asia-Pacific', value: 'apac' },
],
value: 'eu',
},
ENABLED_CHANNELS: {
universalIdentifier: '706a2b08-8284-4715-8bc0-922a99cb26af',
description: 'Channels the app is allowed to use',
type: FieldType.MULTI_SELECT,
options: [
{ label: 'Email', value: 'email' },
{ label: 'SMS', value: 'sms' },
{ label: 'Postcard', value: 'postcard' },
],
value: ['email', 'postcard'],
},
ALLOWED_TAGS: {
universalIdentifier: 'c1c8a4c9-9130-4ab8-8dce-18d2b50879ed',
description: 'Free-form tags applied to recipients',
type: FieldType.ARRAY,
value: ['vip', 'returning'],
},
PROVIDER_CONFIG: {
universalIdentifier: '183d5285-c70c-4f29-96e0-c68659fbe5ae',
description: 'Raw JSON configuration for the printing provider',
type: FieldType.RAW_JSON,
value: { retries: 3, timeoutMs: 5000 },
},
WELCOME_MESSAGE: {
universalIdentifier: '25a66ff5-8458-498e-9e7e-33ea458a6f3c',
description: 'Rich text welcome message',
type: FieldType.RICH_TEXT,
value: { blocknote: null, markdown: 'Welcome to **Rich App**!' },
},
},
serverVariables: {
POSTCARD_API_KEY: {
description: 'API key for the postcard printing service',
isSecret: true,
isRequired: true,
},
POSTCARD_SENDER_NAME: {
description: 'Default sender name on postcards',
isSecret: false,
isRequired: false,
},
POSTCARD_DELIVERY_SPEED: {
description: 'Delivery speed requested from the provider',
type: FieldType.SELECT,
options: [
{ label: 'Standard', value: 'standard' },
{ label: 'Express', value: 'express' },
],
isSecret: false,
isRequired: true,
},
POSTCARD_DAILY_LIMIT: {
description: 'Maximum postcards the provider will accept per day',
type: FieldType.NUMBER,
isSecret: false,
isRequired: false,
},
POSTCARD_UNIT_PRICE: {
description: 'Price charged by the provider per postcard',
type: FieldType.NUMERIC,
isSecret: false,
isRequired: false,
},
POSTCARD_SANDBOX_MODE: {
description: 'Send postcards through the provider sandbox instead of production',
type: FieldType.BOOLEAN,
isSecret: false,
isRequired: false,
},
POSTCARD_CONTRACT_START_DATE: {
description: 'Date the provider contract starts',
type: FieldType.DATE,
isSecret: false,
isRequired: false,
},
POSTCARD_CONTRACT_RENEWAL_AT: {
description: 'Exact moment the provider contract renews',
type: FieldType.DATE_TIME,
isSecret: false,
isRequired: false,
},
POSTCARD_ENABLED_REGIONS: {
description: 'Regions the provider is allowed to ship to',
type: FieldType.MULTI_SELECT,
options: [
{ label: 'Europe', value: 'eu' },
{ label: 'United States', value: 'us' },
{ label: 'Asia-Pacific', value: 'apac' },
],
isSecret: false,
isRequired: false,
},
POSTCARD_WEBHOOK_EVENTS: {
description: 'Provider webhook events the app subscribes to',
type: FieldType.ARRAY,
isSecret: false,
isRequired: false,
},
POSTCARD_PROVIDER_CONFIG: {
description: 'Raw JSON configuration for the printing provider',
type: FieldType.RAW_JSON,
isSecret: false,
isRequired: false,
},
POSTCARD_INVOICE_NOTE: {
description: 'Rich text note appended to provider invoices',
type: FieldType.RICH_TEXT,
isSecret: false,
isRequired: false,
},
},
defaultRoleUniversalIdentifier: DEFAULT_ROLE_UNIVERSAL_IDENTIFIER,
});

View File

@@ -0,0 +1,27 @@
{
"name": "rich-app",
"version": "0.1.0",
"license": "MIT",
"engines": {
"node": "^24.5.0",
"npm": "please-use-yarn",
"yarn": ">=4.0.2"
},
"packageManager": "yarn@4.9.2",
"scripts": {
"twenty": "twenty",
"lint": "oxlint -c .oxlintrc.json .",
"lint:fix": "oxlint --fix -c .oxlintrc.json ."
},
"dependencies": {
"twenty-sdk": "latest",
"twenty-client-sdk": "latest"
},
"devDependencies": {
"typescript": "^5.9.3",
"@types/node": "^24.7.2",
"@types/react": "^19.0.2",
"react": "^19.0.2",
"oxlint": "^0.16.0"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 570 B

View File

@@ -0,0 +1,9 @@
import { defineFrontComponent } from 'twenty-sdk/define';
import { CardDisplay } from '../utils/card-display.component';
export default defineFrontComponent({
universalIdentifier: '88c15ae2-5f87-4a6b-b48f-1974bbe62eb7',
name: 'card-component',
description: 'A component using an external component file',
component: CardDisplay,
});

View File

@@ -0,0 +1,19 @@
import { defineFrontComponent } from 'twenty-sdk/define';
import { DEFAULT_NAME, formatGreeting } from '../utils/greeting.util';
const GreetingComponent = () => {
const message = formatGreeting(DEFAULT_NAME);
return (
<div style={{ padding: '20px', textAlign: 'center' }}>
<h1>{message}</h1>
</div>
);
};
export default defineFrontComponent({
universalIdentifier: '370ae182-743f-4ecb-b625-7ac48e21f0e5',
name: 'greeting-component',
description: 'A component that uses greeting utility',
component: GreetingComponent,
});

View File

@@ -0,0 +1,16 @@
import { defineFrontComponent } from 'twenty-sdk/define';
export const TestComponent = () => {
return (
<div style={{ padding: '20px' }}>
<h1>Test Component</h1>
</div>
);
};
export default defineFrontComponent({
universalIdentifier: 'f1234567-abcd-4000-8000-000000000001',
name: 'test-component',
description: 'A test front component',
component: TestComponent,
});

View File

@@ -0,0 +1,14 @@
import { defineField, FieldType, STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS } from 'twenty-sdk/define';
// Field on existing company object
export default defineField({
universalIdentifier: 'f922fdb8-10a9-4f11-a1d0-992a779f6dff',
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
type: FieldType.BOOLEAN,
name: 'canReceivePostcards',
label: 'Can Receive Postcards',
description: 'Whether the company can receive postcards',
icon: 'IconMailbox',
defaultValue: false,
});

View File

@@ -0,0 +1,40 @@
import { defineField, FieldType } from 'twenty-sdk/define';
import { POST_CARD_UNIVERSAL_IDENTIFIER } from '../objects/post-card.object';
export default defineField({
objectUniversalIdentifier: POST_CARD_UNIVERSAL_IDENTIFIER,
universalIdentifier: 'b602dbd9-e511-49ce-b6d3-b697218dc69c',
type: FieldType.SELECT,
name: 'category',
label: 'Category',
description: 'Post card category',
options: [
{
id: 'cd751c81-787d-4581-bc51-efe43f0050a7',
value: 'PERSONAL',
label: 'Personal',
color: 'blue',
position: 0,
},
{
id: 'eec437ca-5beb-41a9-a826-c9a5eca2eef4',
value: 'BUSINESS',
label: 'Business',
color: 'green',
position: 1,
},
{
id: 'a5baa37d-1047-4972-b6b8-7faae0e3eac1',
value: 'PROMOTIONAL',
label: 'Promotional',
color: 'orange',
position: 2,
},
{
value: 'OTHER',
label: 'Other',
color: 'gray',
position: 3,
},
],
});

View File

@@ -0,0 +1,11 @@
import { defineField, FieldType } from 'twenty-sdk/define';
import { POST_CARD_UNIVERSAL_IDENTIFIER } from '../objects/post-card.object';
export default defineField({
objectUniversalIdentifier: POST_CARD_UNIVERSAL_IDENTIFIER,
universalIdentifier: '7b57bd63-5a4c-46ca-9d52-42c8f02d1df6',
type: FieldType.NUMBER,
name: 'priority',
label: 'Priority',
description: 'Priority level for the post card (1-10)',
});

View File

@@ -0,0 +1,24 @@
import {
POST_CARD_ON_POST_CARD_RECIPIENT_ID,
POST_CARD_RECIPIENTS_ON_POST_CARD_ID,
} from './post-card-recipients-on-post-card.field';
import { POST_CARD_RECIPIENT_UNIVERSAL_IDENTIFIER } from '../objects/post-card-recipient.object';
import { defineField, FieldType, OnDeleteAction, RelationType } from 'twenty-sdk/define';
import { POST_CARD_UNIVERSAL_IDENTIFIER } from '../objects/post-card.object';
export default defineField({
universalIdentifier: POST_CARD_ON_POST_CARD_RECIPIENT_ID,
objectUniversalIdentifier: POST_CARD_RECIPIENT_UNIVERSAL_IDENTIFIER,
type: FieldType.RELATION,
name: 'postCard',
label: 'Post Card',
relationTargetObjectMetadataUniversalIdentifier:
POST_CARD_UNIVERSAL_IDENTIFIER,
relationTargetFieldMetadataUniversalIdentifier:
POST_CARD_RECIPIENTS_ON_POST_CARD_ID,
universalSettings: {
relationType: RelationType.MANY_TO_ONE,
onDelete: OnDeleteAction.CASCADE,
joinColumnName: 'postCardId',
},
});

View File

@@ -0,0 +1,25 @@
import { POST_CARD_RECIPIENT_UNIVERSAL_IDENTIFIER } from '../objects/post-card-recipient.object';
import { defineField, FieldType, RelationType } from 'twenty-sdk/define';
import { POST_CARD_UNIVERSAL_IDENTIFIER } from '../objects/post-card.object';
import { RECIPIENT_ON_POST_CARD_RECIPIENT_ID } from './post-card-recipients-on-recipient.field';
export const POST_CARD_RECIPIENTS_ON_POST_CARD_ID =
'a1a2b3c4-0001-4a7b-8c9d-0e1f2a3b4c5d';
export const POST_CARD_ON_POST_CARD_RECIPIENT_ID =
'a1a2b3c4-0002-4a7b-8c9d-0e1f2a3b4c5d';
export default defineField({
universalIdentifier: POST_CARD_RECIPIENTS_ON_POST_CARD_ID,
objectUniversalIdentifier: POST_CARD_UNIVERSAL_IDENTIFIER,
type: FieldType.RELATION,
name: 'postCardRecipients',
label: 'Post Card Recipients',
relationTargetObjectMetadataUniversalIdentifier:
POST_CARD_RECIPIENT_UNIVERSAL_IDENTIFIER,
relationTargetFieldMetadataUniversalIdentifier:
POST_CARD_ON_POST_CARD_RECIPIENT_ID,
universalSettings: {
relationType: RelationType.ONE_TO_MANY,
junctionTargetFieldUniversalIdentifier: RECIPIENT_ON_POST_CARD_RECIPIENT_ID,
},
});

View File

@@ -0,0 +1,23 @@
import { defineField, FieldType, RelationType } from 'twenty-sdk/define';
import { RECIPIENT_UNIVERSAL_IDENTIFIER } from '../objects/recipient.object';
import { POST_CARD_RECIPIENT_UNIVERSAL_IDENTIFIER } from '../objects/post-card-recipient.object';
export const POST_CARD_RECIPIENTS_ON_RECIPIENT_ID =
'a1a2b3c4-0003-4a7b-8c9d-0e1f2a3b4c5d';
export const RECIPIENT_ON_POST_CARD_RECIPIENT_ID =
'a1a2b3c4-0004-4a7b-8c9d-0e1f2a3b4c5d';
export default defineField({
universalIdentifier: POST_CARD_RECIPIENTS_ON_RECIPIENT_ID,
objectUniversalIdentifier: RECIPIENT_UNIVERSAL_IDENTIFIER,
type: FieldType.RELATION,
name: 'postCardRecipients',
label: 'Post Card Recipients',
relationTargetObjectMetadataUniversalIdentifier:
POST_CARD_RECIPIENT_UNIVERSAL_IDENTIFIER,
relationTargetFieldMetadataUniversalIdentifier:
RECIPIENT_ON_POST_CARD_RECIPIENT_ID,
universalSettings: {
relationType: RelationType.ONE_TO_MANY,
},
});

View File

@@ -0,0 +1,24 @@
import { defineField, FieldType, RelationType, OnDeleteAction } from 'twenty-sdk/define';
import { RECIPIENT_UNIVERSAL_IDENTIFIER } from '../objects/recipient.object';
import { POST_CARD_RECIPIENT_UNIVERSAL_IDENTIFIER } from '../objects/post-card-recipient.object';
import {
POST_CARD_RECIPIENTS_ON_RECIPIENT_ID,
RECIPIENT_ON_POST_CARD_RECIPIENT_ID,
} from './post-card-recipients-on-recipient.field';
export default defineField({
universalIdentifier: RECIPIENT_ON_POST_CARD_RECIPIENT_ID,
objectUniversalIdentifier: POST_CARD_RECIPIENT_UNIVERSAL_IDENTIFIER,
type: FieldType.RELATION,
name: 'recipient',
label: 'Recipient',
relationTargetObjectMetadataUniversalIdentifier:
RECIPIENT_UNIVERSAL_IDENTIFIER,
relationTargetFieldMetadataUniversalIdentifier:
POST_CARD_RECIPIENTS_ON_RECIPIENT_ID,
universalSettings: {
relationType: RelationType.MANY_TO_ONE,
onDelete: OnDeleteAction.CASCADE,
joinColumnName: 'recipientId',
},
});

View File

@@ -0,0 +1,17 @@
import { defineIndex } from 'twenty-sdk/define';
import {
POST_CARD_UNIVERSAL_IDENTIFIER,
STATUS_FIELD_UNIVERSAL_IDENTIFIER,
} from '../objects/post-card.object';
export default defineIndex({
universalIdentifier: 'b6e9d2a1-5a4c-46ca-9d52-42c8f02d1ff0',
objectUniversalIdentifier: POST_CARD_UNIVERSAL_IDENTIFIER,
fields: [
{
universalIdentifier: 'b6e9d2a1-5a4c-46ca-9d52-42c8f02d1ff1',
fieldUniversalIdentifier: STATUS_FIELD_UNIVERSAL_IDENTIFIER,
},
],
});

View File

@@ -0,0 +1,23 @@
import { defineLogicFunction, type TwentyRecord } from 'twenty-sdk/define';
const handler = async (params: {
companyId: TwentyRecord<'20202020-b374-4779-a561-80086cb2e17f'>;
postCardIds: TwentyRecord<'54b589ca-eeed-4950-a176-358418b85c05'>[];
}) => {
return {
companyId: params.companyId,
postCardCount: params.postCardIds.length,
};
};
export default defineLogicFunction({
universalIdentifier: 'a1b2c3d4-ac10-4a7b-8c9d-0e1f2a3b4c5d',
name: 'enrich-post-cards',
description: 'Enrich post cards of a company',
timeoutSeconds: 5,
handler,
workflowActionTriggerSettings: {
label: 'Enrich Post Cards',
icon: 'IconMail',
},
});

View File

@@ -0,0 +1,18 @@
import { defineLogicFunction } from 'twenty-sdk/define';
import { DEFAULT_NAME, formatGreeting } from '../utils/greeting.util';
const greetingHandler = () => {
return formatGreeting(DEFAULT_NAME);
};
export default defineLogicFunction({
universalIdentifier: '9d412d9e-2caf-487c-8b66-d1585883dd4e',
name: 'greeting-function',
timeoutSeconds: 5,
handler: greetingHandler,
httpRouteTriggerSettings: {
path: '/greet',
httpMethod: 'GET',
isAuthRequired: false,
},
});

View File

@@ -0,0 +1,22 @@
import { defineLogicFunction } from 'twenty-sdk/define';
const handler = async (params: { recipientName: string }) => {
return { found: true, name: params.recipientName };
};
export default defineLogicFunction({
universalIdentifier: 'a1b2c3d4-1001-4a7b-8c9d-0e1f2a3b4c5d',
name: 'lookup-recipient',
description: 'Look up a recipient by name to find their details',
timeoutSeconds: 5,
handler,
toolTriggerSettings: {
inputSchema: {
type: 'object',
properties: {
recipientName: { type: 'string' },
},
required: ['recipientName'],
},
},
});

View File

@@ -0,0 +1,32 @@
import {
defineLogicFunction,
type DatabaseEventPayload,
type ObjectRecordCreateEvent,
} from 'twenty-sdk/define';
import { createTimelineActivity } from 'twenty-sdk/logic-function';
import { POST_CARD_UNIVERSAL_IDENTIFIER } from '../objects/post-card.object';
const handler = async (
payload: DatabaseEventPayload<ObjectRecordCreateEvent<{ id: string }>>,
) => {
await createTimelineActivity({
timelineActivityTypeUniversalIdentifier:
'f4fa646c-6e11-4d8f-a6be-c3b7a2fc7500',
targetObjectUniversalIdentifier: POST_CARD_UNIVERSAL_IDENTIFIER,
targetRecordId: payload.properties.after.id,
});
return { processed: true };
};
export default defineLogicFunction({
universalIdentifier: 'a1b2c3d4-db01-4a7b-8c9d-0e1f2a3b4c5d',
name: 'on-post-card-created',
description: 'Triggered when a new post card is created',
timeoutSeconds: 5,
handler,
databaseEventTriggerSettings: {
eventName: 'postCard.created',
},
});

View File

@@ -0,0 +1,12 @@
import { defineLogicFunction } from 'twenty-sdk/define';
import { testFunction2 } from '../utils/test-function-2.util';
export default defineLogicFunction({
universalIdentifier: 'eb3ffc98-88ec-45d4-9b4a-56833b219ccb',
name: 'test-function-2',
timeoutSeconds: 2,
handler: testFunction2,
cronTriggerSettings: {
pattern: '0 0 1 1 *',
},
});

View File

@@ -0,0 +1,19 @@
import { defineLogicFunction } from 'twenty-sdk/define';
import { formatFarewell } from '../utils/greeting.util';
const handler = () => {
return formatFarewell('test');
};
export default defineLogicFunction({
universalIdentifier: 'e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf',
name: 'test-function',
timeoutSeconds: 2,
handler,
httpRouteTriggerSettings: {
path: '/post-card/create',
httpMethod: 'GET',
isAuthRequired: false,
forwardedRequestHeaders: ['signature'],
},
});

View File

@@ -0,0 +1,10 @@
import { defineNavigationMenuItem } from 'twenty-sdk/define';
import { NavigationMenuItemType } from 'twenty-shared/types';
import { POST_CARD_RECIPIENT_UNIVERSAL_IDENTIFIER } from '../objects/post-card-recipient.object';
export default defineNavigationMenuItem({
universalIdentifier: 'c1a2b3c4-0003-4a7b-8c9d-0e1f2a3b4c5d',
position: 2,
type: NavigationMenuItemType.OBJECT,
targetObjectUniversalIdentifier: POST_CARD_RECIPIENT_UNIVERSAL_IDENTIFIER,
});

View File

@@ -0,0 +1,10 @@
import { defineNavigationMenuItem } from 'twenty-sdk/define';
import { NavigationMenuItemType } from 'twenty-shared/types';
import { POST_CARD_UNIVERSAL_IDENTIFIER } from '../objects/post-card.object';
export default defineNavigationMenuItem({
universalIdentifier: 'e8031eca-d6ea-4a4b-b828-38227dba896a',
position: 0,
type: NavigationMenuItemType.OBJECT,
targetObjectUniversalIdentifier: POST_CARD_UNIVERSAL_IDENTIFIER,
});

View File

@@ -0,0 +1,10 @@
import { defineNavigationMenuItem } from 'twenty-sdk/define';
import { NavigationMenuItemType } from 'twenty-shared/types';
import { RECIPIENT_UNIVERSAL_IDENTIFIER } from '../objects/recipient.object';
export default defineNavigationMenuItem({
universalIdentifier: 'c1a2b3c4-0002-4a7b-8c9d-0e1f2a3b4c5d',
position: 1,
type: NavigationMenuItemType.OBJECT,
targetObjectUniversalIdentifier: RECIPIENT_UNIVERSAL_IDENTIFIER,
});

View File

@@ -0,0 +1,28 @@
import { defineObject, FieldType } from 'twenty-sdk/define';
export const POST_CARD_RECIPIENT_UNIVERSAL_IDENTIFIER =
'e1a2b3c4-5e6f-4a7b-8c9d-0e1f2a3b4c5e';
export const SENT_AT_FIELD_UNIVERSAL_IDENTIFIER =
'e2a2b3c4-5e6f-4a7b-8c9d-0e1f2a3b4c5e';
export default defineObject({
universalIdentifier: POST_CARD_RECIPIENT_UNIVERSAL_IDENTIFIER,
nameSingular: 'postCardRecipient',
namePlural: 'postCardRecipients',
labelSingular: 'Post Card Recipient',
labelPlural: 'Post Card Recipients',
description: 'Junction object linking post cards to their recipients',
icon: 'IconLink',
fields: [
{
universalIdentifier: SENT_AT_FIELD_UNIVERSAL_IDENTIFIER,
type: FieldType.DATE_TIME,
label: 'Sent at',
name: 'sentAt',
icon: 'IconClock',
isNullable: true,
defaultValue: null,
},
],
});

View File

@@ -0,0 +1,111 @@
import { defineObject, FieldType } from 'twenty-sdk/define';
enum PostCardStatus {
DRAFT = 'DRAFT',
SENT = 'SENT',
DELIVERED = 'DELIVERED',
RETURNED = 'RETURNED',
LOST = 'LOST',
}
export const POST_CARD_UNIVERSAL_IDENTIFIER =
'54b589ca-eeed-4950-a176-358418b85c05';
export const CONTENT_FIELD_UNIVERSAL_IDENTIFIER =
'58a0a314-d7ea-4865-9850-7fb84e72f30b';
export const STATUS_FIELD_UNIVERSAL_IDENTIFIER =
'87b675b8-dd8c-4448-b4ca-20e5a2234a1e';
export const DELIVERED_AT_FIELD_UNIVERSAL_IDENTIFIER =
'e06abe72-5b44-4e7f-93be-afc185a3c433';
export default defineObject({
universalIdentifier: POST_CARD_UNIVERSAL_IDENTIFIER,
nameSingular: 'postCard',
namePlural: 'postCards',
labelSingular: 'Post card',
labelPlural: 'Post cards',
description: 'A post card object',
icon: 'IconMail',
labelIdentifierFieldMetadataUniversalIdentifier:
CONTENT_FIELD_UNIVERSAL_IDENTIFIER,
fields: [
{
universalIdentifier: CONTENT_FIELD_UNIVERSAL_IDENTIFIER,
type: FieldType.TEXT,
label: 'Content',
description: "Postcard's content",
icon: 'IconAbc',
name: 'content',
},
{
universalIdentifier: 'c6aa31f3-da76-4ac6-889f-475e226009ac',
type: FieldType.FULL_NAME,
label: 'Recipient name',
icon: 'IconUser',
name: 'recipientName',
},
{
universalIdentifier: '95045777-a0ad-49ec-98f9-22f9fc0c8266',
type: FieldType.ADDRESS,
label: 'Recipient address',
icon: 'IconHome',
name: 'recipientAddress',
},
{
universalIdentifier: STATUS_FIELD_UNIVERSAL_IDENTIFIER,
type: FieldType.SELECT,
label: 'Status',
icon: 'IconSend',
defaultValue: `'${PostCardStatus.DRAFT}'`,
options: [
{
id: '1b008e19-1e59-4a07-b187-65a20e547c4e',
value: PostCardStatus.DRAFT,
label: 'Draft',
position: 0,
color: 'gray',
},
{
id: '452b9d40-889c-4342-9697-98319394db04',
value: PostCardStatus.SENT,
label: 'Sent',
position: 1,
color: 'orange',
},
{
id: 'c2ed0b8c-a3ed-4383-aef9-e0441267bcfe',
value: PostCardStatus.DELIVERED,
label: 'Delivered',
position: 2,
color: 'green',
},
{
id: 'c57a5e08-7ef7-49b8-87e6-32d720d22802',
value: PostCardStatus.RETURNED,
label: 'Returned',
position: 3,
color: 'orange',
},
{
// No id — exercises addMissingFieldOptionIds in the object branch
value: PostCardStatus.LOST,
label: 'Lost',
position: 4,
color: 'red',
},
],
name: 'status',
},
{
universalIdentifier: DELIVERED_AT_FIELD_UNIVERSAL_IDENTIFIER,
type: FieldType.DATE_TIME,
label: 'Delivered at',
icon: 'IconCheck',
isNullable: true,
defaultValue: null,
name: 'deliveredAt',
},
],
});

View File

@@ -0,0 +1,36 @@
import { defineObject, FieldType } from 'twenty-sdk/define';
export const RECIPIENT_UNIVERSAL_IDENTIFIER =
'd1a2b3c4-5e6f-4a7b-8c9d-0e1f2a3b4c5d';
export const RECIPIENT_EMAIL_FIELD_UNIVERSAL_IDENTIFIER =
'd2a2b3c4-5e6f-4a7b-8c9d-0e1f2a3b4c5d';
export const RECIPIENT_ADDRESS_FIELD_UNIVERSAL_IDENTIFIER =
'd3a2b3c4-5e6f-4a7b-8c9d-0e1f2a3b4c5d';
export default defineObject({
universalIdentifier: RECIPIENT_UNIVERSAL_IDENTIFIER,
nameSingular: 'recipient',
namePlural: 'recipients',
labelSingular: 'Recipient',
labelPlural: 'Recipients',
description: 'A person or organization that receives post cards',
icon: 'IconUser',
fields: [
{
universalIdentifier: RECIPIENT_EMAIL_FIELD_UNIVERSAL_IDENTIFIER,
type: FieldType.EMAILS,
label: 'Email',
name: 'email',
icon: 'IconMail',
},
{
universalIdentifier: RECIPIENT_ADDRESS_FIELD_UNIVERSAL_IDENTIFIER,
type: FieldType.ADDRESS,
label: 'Mailing Address',
name: 'mailingAddress',
icon: 'IconHome',
},
],
});

View File

@@ -0,0 +1,41 @@
import {
AggregateOperations,
definePageLayoutTab,
PageLayoutTabLayoutMode,
} from 'twenty-sdk/define';
import { POST_CARD_UNIVERSAL_IDENTIFIER } from '../objects/post-card.object';
export default definePageLayoutTab({
universalIdentifier: 'b0b1b2b3-b4b5-4000-8000-000000000010',
pageLayoutUniversalIdentifier: 'b0b1b2b3-b4b5-4000-8000-000000000020',
title: 'Extra Tab',
position: 1000,
icon: 'IconLayout',
layoutMode: PageLayoutTabLayoutMode.VERTICAL_LIST,
widgets: [
{
universalIdentifier: 'b0b1b2b3-b4b5-4000-8000-000000000012',
title: 'Total Priority',
type: 'GRAPH',
objectUniversalIdentifier: POST_CARD_UNIVERSAL_IDENTIFIER,
configuration: {
configurationType: 'AGGREGATE_CHART',
aggregateFieldMetadataUniversalIdentifier:
'7b57bd63-5a4c-46ca-9d52-42c8f02d1df6',
aggregateOperation: AggregateOperations.SUM,
},
},
{
universalIdentifier: 'b0b1b2b3-b4b5-4000-8000-000000000011',
title: 'Extra Widget',
type: 'FRONT_COMPONENT',
heightBehavior: 'TAB_VIEWPORT',
configuration: {
configurationType: 'FRONT_COMPONENT',
frontComponentUniversalIdentifier:
'370ae182-743f-4ecb-b625-7ac48e21f0e5',
},
},
],
});

View File

@@ -0,0 +1,19 @@
import {
definePageLayoutWidget,
PageLayoutTabLayoutMode,
STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
export default definePageLayoutWidget({
universalIdentifier: 'b0b1b2b3-b4b5-4000-8000-000000000013',
pageLayoutTabUniversalIdentifier:
STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.companyRecordPage.tabs.home
.universalIdentifier,
title: 'Extra Home Widget',
type: 'FRONT_COMPONENT',
position: { layoutMode: PageLayoutTabLayoutMode.VERTICAL_LIST, index: 1000 },
configuration: {
configurationType: 'FRONT_COMPONENT',
frontComponentUniversalIdentifier: '370ae182-743f-4ecb-b625-7ac48e21f0e5',
},
});

View File

@@ -0,0 +1,49 @@
import { SystemPermissionFlag, defineRole } from 'twenty-sdk/define';
import { STANDARD_OBJECTS } from 'twenty-shared/metadata';
import {
CONTENT_FIELD_UNIVERSAL_IDENTIFIER,
POST_CARD_UNIVERSAL_IDENTIFIER,
} from '../objects/post-card.object';
export const DEFAULT_ROLE_UNIVERSAL_IDENTIFIER =
'b648f87b-1d26-4961-b974-0908fd991061';
export default defineRole({
universalIdentifier: DEFAULT_ROLE_UNIVERSAL_IDENTIFIER,
label: 'Default function role',
description: 'Default role for function Twenty client',
canReadAllObjectRecords: false,
canUpdateAllObjectRecords: false,
canSoftDeleteAllObjectRecords: false,
canDestroyAllObjectRecords: false,
canUpdateAllSettings: false,
canBeAssignedToAgents: false,
canBeAssignedToUsers: false,
canBeAssignedToApiKeys: false,
objectPermissions: [
{
objectUniversalIdentifier: POST_CARD_UNIVERSAL_IDENTIFIER,
canReadObjectRecords: true,
canUpdateObjectRecords: true,
canSoftDeleteObjectRecords: false,
canDestroyObjectRecords: false,
},
{
objectUniversalIdentifier:
STANDARD_OBJECTS.timelineActivity.universalIdentifier,
canReadObjectRecords: true,
canUpdateObjectRecords: true,
canSoftDeleteObjectRecords: false,
canDestroyObjectRecords: false,
},
],
fieldPermissions: [
{
objectUniversalIdentifier: POST_CARD_UNIVERSAL_IDENTIFIER,
fieldUniversalIdentifier: CONTENT_FIELD_UNIVERSAL_IDENTIFIER,
canReadFieldValue: false,
canUpdateFieldValue: false,
},
],
permissionFlagUniversalIdentifiers: [SystemPermissionFlag.APPLICATIONS],
});

View File

@@ -0,0 +1,16 @@
import { defineFrontComponent } from 'twenty-sdk/define';
export const RootComponent = () => {
return (
<div style={{ padding: '10px' }}>
<h2>Root Component</h2>
</div>
);
};
export default defineFrontComponent({
universalIdentifier: 'a0a1a2a3-a4a5-4000-8000-000000000001',
name: 'root-component',
description: 'A root-level front component',
component: RootComponent,
});

View File

@@ -0,0 +1,17 @@
import { defineLogicFunction } from 'twenty-sdk/define';
const rootHandler = () => {
return 'root-function-result';
};
export default defineLogicFunction({
universalIdentifier: 'f0f1f2f3-f4f5-4000-8000-000000000001',
name: 'root-function',
timeoutSeconds: 5,
handler: rootHandler,
httpRouteTriggerSettings: {
path: '/root',
httpMethod: 'GET',
isAuthRequired: false,
},
});

View File

@@ -0,0 +1,27 @@
import { defineObject, FieldType } from 'twenty-sdk/define';
export default defineObject({
universalIdentifier: 'b0b1b2b3-b4b5-4000-8000-000000000001',
nameSingular: 'rootNote',
namePlural: 'rootNotes',
labelSingular: 'Root note',
labelPlural: 'Root notes',
description: 'A simple root-level object',
icon: 'IconNote',
labelIdentifierFieldMetadataUniversalIdentifier:
'b0b1b2b3-b4b5-4000-8000-000000000002',
fields: [
{
universalIdentifier: 'b0b1b2b3-b4b5-4000-8000-000000000002',
type: FieldType.TEXT,
label: 'Title',
name: 'title',
},
{
universalIdentifier: 'b0b1b2b3-b4b5-4000-8000-000000000003',
type: FieldType.TEXT,
label: 'Body',
name: 'body',
},
],
});

View File

@@ -0,0 +1,15 @@
import { defineRole } from 'twenty-sdk/define';
export default defineRole({
universalIdentifier: 'c0c1c2c3-c4c5-4000-8000-000000000001',
label: 'Root role',
description: 'A simple root-level role',
canReadAllObjectRecords: true,
canUpdateAllObjectRecords: false,
canSoftDeleteAllObjectRecords: false,
canDestroyAllObjectRecords: false,
canUpdateAllSettings: false,
canBeAssignedToAgents: false,
canBeAssignedToUsers: true,
canBeAssignedToApiKeys: false,
});

View File

@@ -0,0 +1,9 @@
import { defineTimelineActivityType } from 'twenty-sdk/define';
export default defineTimelineActivityType({
universalIdentifier: 'f4fa646c-6e11-4d8f-a6be-c3b7a2fc7500',
name: 'postCardCreated',
label: 'created a post card',
icon: 'IconMail',
frontComponentUniversalIdentifier: '88c15ae2-5f87-4a6b-b48f-1974bbe62eb7',
});

View File

@@ -0,0 +1,19 @@
import { defineTimelineActivityType } from 'twenty-sdk/define';
import { POST_CARD_RECIPIENTS_ON_POST_CARD_ID } from '../fields/post-card-recipients-on-post-card.field';
import { POST_CARD_UNIVERSAL_IDENTIFIER } from '../objects/post-card.object';
export default defineTimelineActivityType({
universalIdentifier: 'f4fa646c-6e11-4d8f-a6be-c3b7a2fc7501',
name: 'postCardLinked',
label: 'received a post card',
icon: 'IconMail',
emit: {
on: 'linked',
objectUniversalIdentifier: POST_CARD_UNIVERSAL_IDENTIFIER,
through: {
relationFieldUniversalIdentifier: POST_CARD_RECIPIENTS_ON_POST_CARD_ID,
},
},
frontComponentUniversalIdentifier: '88c15ae2-5f87-4a6b-b48f-1974bbe62eb7',
});

View File

@@ -0,0 +1,16 @@
export const CardDisplay = ({
title,
content,
}: {
title: string;
content: string;
}) => {
return (
<div
style={{ border: '1px solid #ccc', padding: '16px', borderRadius: '8px' }}
>
<h3>{title}</h3>
<p>{content}</p>
</div>
);
};

View File

@@ -0,0 +1,9 @@
export const DEFAULT_NAME = 'World';
export const formatGreeting = (name: string): string => {
return `Hello, ${name}!`;
};
export const formatFarewell = (name: string): string => {
return `Goodbye, ${name}!`;
};

View File

@@ -0,0 +1,3 @@
export const testFunction2 = () => {
return 'test-function-2-result';
};

View File

@@ -0,0 +1,10 @@
import { defineViewField } from 'twenty-sdk/define';
import { ALL_POST_CARDS_VIEW_ID } from '../views/all-post-cards.view';
export default defineViewField({
fieldMetadataUniversalIdentifier: '7b57bd63-5a4c-46ca-9d52-42c8f02d1df6',
position: 5,
universalIdentifier: 'cd582d11-ea21-4dc3-b9c1-0298ce3b6b54',
viewUniversalIdentifier: ALL_POST_CARDS_VIEW_ID,
isVisible: true,
});

View File

@@ -0,0 +1,31 @@
import { defineView } from 'twenty-sdk/define';
import { ViewType } from 'twenty-shared/types';
import {
POST_CARD_RECIPIENT_UNIVERSAL_IDENTIFIER,
SENT_AT_FIELD_UNIVERSAL_IDENTIFIER,
} from '../objects/post-card-recipient.object';
export const ALL_POST_CARD_RECIPIENTS_VIEW_ID =
'b1a2b3c4-0003-4a7b-8c9d-0e1f2a3b4c5d';
export const POST_CARD_RECIPIENT_SENT_AT_FIELD_UNIVERSAL_IDENTIFIER =
'fd959c6f-3465-4a3a-b7ad-3f4004fffc9a';
export default defineView({
universalIdentifier: ALL_POST_CARD_RECIPIENTS_VIEW_ID,
name: 'All Post Card Recipients',
objectUniversalIdentifier: POST_CARD_RECIPIENT_UNIVERSAL_IDENTIFIER,
type: ViewType.TABLE,
icon: 'IconLink',
position: 2,
fields: [
{
universalIdentifier:
POST_CARD_RECIPIENT_SENT_AT_FIELD_UNIVERSAL_IDENTIFIER,
fieldMetadataUniversalIdentifier: SENT_AT_FIELD_UNIVERSAL_IDENTIFIER,
position: 0,
isVisible: true,
size: 200,
},
],
});

View File

@@ -0,0 +1,34 @@
import { defineView } from 'twenty-sdk/define';
import {
CONTENT_FIELD_UNIVERSAL_IDENTIFIER,
POST_CARD_UNIVERSAL_IDENTIFIER,
STATUS_FIELD_UNIVERSAL_IDENTIFIER,
} from '../objects/post-card.object';
import { ViewType } from 'twenty-shared/types';
export const ALL_POST_CARDS_VIEW_ID = 'b1a2b3c4-0001-4a7b-8c9d-0e1f2a3b4c5d';
export default defineView({
universalIdentifier: ALL_POST_CARDS_VIEW_ID,
name: 'All Post Cards',
objectUniversalIdentifier: POST_CARD_UNIVERSAL_IDENTIFIER,
type: ViewType.TABLE,
icon: 'IconMail',
position: 0,
fields: [
{
universalIdentifier: 'bf1a2b3c-0001-4a7b-8c9d-0e1f2a3b4c5d',
fieldMetadataUniversalIdentifier: CONTENT_FIELD_UNIVERSAL_IDENTIFIER,
position: 0,
isVisible: true,
size: 200,
},
{
universalIdentifier: 'bf1a2b3c-0002-4a7b-8c9d-0e1f2a3b4c5d',
fieldMetadataUniversalIdentifier: STATUS_FIELD_UNIVERSAL_IDENTIFIER,
position: 1,
isVisible: true,
size: 150,
},
],
});

View File

@@ -0,0 +1,36 @@
import { defineView } from 'twenty-sdk/define';
import { ViewType } from 'twenty-shared/types';
import {
RECIPIENT_ADDRESS_FIELD_UNIVERSAL_IDENTIFIER,
RECIPIENT_EMAIL_FIELD_UNIVERSAL_IDENTIFIER,
RECIPIENT_UNIVERSAL_IDENTIFIER,
} from '../objects/recipient.object';
export const ALL_RECIPIENTS_VIEW_ID = 'b1a2b3c4-0002-4a7b-8c9d-0e1f2a3b4c5d';
export default defineView({
universalIdentifier: ALL_RECIPIENTS_VIEW_ID,
name: 'All Recipients',
objectUniversalIdentifier: RECIPIENT_UNIVERSAL_IDENTIFIER,
type: ViewType.TABLE,
icon: 'IconUser',
position: 1,
fields: [
{
universalIdentifier: 'bf1a2b3c-0003-4a7b-8c9d-0e1f2a3b4c5d',
fieldMetadataUniversalIdentifier:
RECIPIENT_EMAIL_FIELD_UNIVERSAL_IDENTIFIER,
position: 0,
isVisible: true,
size: 200,
},
{
universalIdentifier: 'bf1a2b3c-0004-4a7b-8c9d-0e1f2a3b4c5d',
fieldMetadataUniversalIdentifier:
RECIPIENT_ADDRESS_FIELD_UNIVERSAL_IDENTIFIER,
position: 1,
isVisible: true,
size: 150,
},
],
});

View File

@@ -0,0 +1,32 @@
import { defineView } from 'twenty-sdk/define';
import { ViewCalendarLayout, ViewType } from 'twenty-shared/types';
import {
CONTENT_FIELD_UNIVERSAL_IDENTIFIER,
DELIVERED_AT_FIELD_UNIVERSAL_IDENTIFIER,
POST_CARD_UNIVERSAL_IDENTIFIER,
} from '../objects/post-card.object';
export const POST_CARDS_BY_DELIVERY_DATE_VIEW_ID =
'b1a2b3c4-0005-4a7b-8c9d-0e1f2a3b4c5d';
export default defineView({
universalIdentifier: POST_CARDS_BY_DELIVERY_DATE_VIEW_ID,
name: 'By Delivery Date',
objectUniversalIdentifier: POST_CARD_UNIVERSAL_IDENTIFIER,
type: ViewType.CALENDAR,
icon: 'IconCalendarEvent',
position: 2,
calendarLayout: ViewCalendarLayout.MONTH,
calendarFieldMetadataUniversalIdentifier:
DELIVERED_AT_FIELD_UNIVERSAL_IDENTIFIER,
fields: [
{
universalIdentifier: 'bf1a2b3c-0006-4a7b-8c9d-0e1f2a3b4c5d',
fieldMetadataUniversalIdentifier: CONTENT_FIELD_UNIVERSAL_IDENTIFIER,
position: 0,
isVisible: true,
size: 200,
},
],
});

View File

@@ -0,0 +1,63 @@
import { defineView } from 'twenty-sdk/define';
import { ViewType } from 'twenty-shared/types';
import {
CONTENT_FIELD_UNIVERSAL_IDENTIFIER,
POST_CARD_UNIVERSAL_IDENTIFIER,
STATUS_FIELD_UNIVERSAL_IDENTIFIER,
} from '../objects/post-card.object';
export const POST_CARDS_BY_STATUS_VIEW_ID =
'b1a2b3c4-0004-4a7b-8c9d-0e1f2a3b4c5d';
export default defineView({
universalIdentifier: POST_CARDS_BY_STATUS_VIEW_ID,
name: 'By Status',
objectUniversalIdentifier: POST_CARD_UNIVERSAL_IDENTIFIER,
type: ViewType.KANBAN,
icon: 'IconLayoutKanban',
position: 1,
mainGroupByFieldMetadataUniversalIdentifier:
STATUS_FIELD_UNIVERSAL_IDENTIFIER,
fields: [
{
universalIdentifier: 'bf1a2b3c-0005-4a7b-8c9d-0e1f2a3b4c5d',
fieldMetadataUniversalIdentifier: CONTENT_FIELD_UNIVERSAL_IDENTIFIER,
position: 0,
isVisible: true,
size: 200,
},
],
groups: [
{
universalIdentifier: 'e9ed34f1-3c3d-41b1-869b-00aae0033d9c',
fieldValue: 'DRAFT',
position: 0,
isVisible: true,
},
{
universalIdentifier: '19b1a3c1-53f0-4d32-b072-d645dac98e38',
fieldValue: 'SENT',
position: 1,
isVisible: true,
},
{
universalIdentifier: 'f545cb5a-370d-423f-9b4e-278a9a465bdf',
fieldValue: 'DELIVERED',
position: 2,
isVisible: true,
},
{
universalIdentifier: '5d4c6d5f-af53-4cd0-a843-df38915561b2',
fieldValue: 'RETURNED',
position: 3,
isVisible: true,
},
{
universalIdentifier: '5ebbd7dc-9939-4594-b2a0-519269b4531f',
fieldValue: 'LOST',
position: 4,
isVisible: true,
},
],
});

View File

@@ -0,0 +1,17 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"jsx": "react-jsx",
"baseUrl": ".",
"paths": {
"src/*": ["./src/*"]
}
},
"include": ["**/*"],
"exclude": ["node_modules", "dist", ".twenty"]
}

View File

@@ -0,0 +1,6 @@
# This file is generated by running "yarn install" inside your project.
# Manual changes might be lost - proceed with caution!
__metadata:
version: 8
cacheKey: 10c0

View File

@@ -0,0 +1,3 @@
generated
.twenty
node_modules

View File

@@ -0,0 +1,19 @@
{
"$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"
}
}

View File

@@ -0,0 +1,8 @@
import { defineApplication } from 'twenty-sdk/define';
export default defineApplication({
universalIdentifier: 'e1e2e3e4-e5e6-4000-8000-000000000101',
displayName: 'Shared Dependencies App',
description: 'An app sharing dependencies across its front components',
defaultRoleUniversalIdentifier: 'e1e2e3e4-e5e6-4000-8000-000000000102',
});

View File

@@ -0,0 +1,15 @@
import { defineRole } from 'twenty-sdk/define';
export default defineRole({
universalIdentifier: 'e1e2e3e4-e5e6-4000-8000-000000000102',
label: 'Shared dependencies app role',
description: 'The default role of the shared dependencies app',
canReadAllObjectRecords: true,
canUpdateAllObjectRecords: false,
canSoftDeleteAllObjectRecords: false,
canDestroyAllObjectRecords: false,
canUpdateAllSettings: false,
canBeAssignedToAgents: false,
canBeAssignedToUsers: true,
canBeAssignedToApiKeys: false,
});

View File

@@ -0,0 +1,29 @@
{
"name": "shared-dependencies-app",
"version": "0.1.0",
"license": "MIT",
"engines": {
"node": "^24.5.0",
"npm": "please-use-yarn",
"yarn": ">=4.0.2"
},
"packageManager": "yarn@4.9.2",
"frontComponentSharedDependencies": ["react", "react-dom/client"],
"scripts": {
"twenty": "twenty",
"lint": "oxlint -c .oxlintrc.json .",
"lint:fix": "oxlint --fix -c .oxlintrc.json ."
},
"dependencies": {
"twenty-sdk": "latest",
"twenty-client-sdk": "latest"
},
"devDependencies": {
"typescript": "^5.9.3",
"@types/node": "^24.7.2",
"@types/react": "^19.0.2",
"react": "^19.2.7",
"react-dom": "^19.2.7",
"oxlint": "^0.16.0"
}
}

View File

@@ -0,0 +1,20 @@
import { useState } from 'react';
import { defineFrontComponent } from 'twenty-sdk/define';
export const Counter = () => {
const [count, setCount] = useState(0);
return (
<div>
<span>{count}</span>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
};
export default defineFrontComponent({
universalIdentifier: 'e1e2e3e4-e5e6-4000-8000-000000000103',
name: 'counter',
description: 'A component relying on the shared react',
component: Counter,
});

View File

@@ -0,0 +1,17 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"jsx": "react-jsx",
"baseUrl": ".",
"paths": {
"src/*": ["./src/*"]
}
},
"include": ["**/*"],
"exclude": ["node_modules", "dist", ".twenty"]
}

View File

@@ -0,0 +1,6 @@
# This file is generated by running "yarn install" inside your project.
# Manual changes might be lost - proceed with caution!
__metadata:
version: 8
cacheKey: 10c0