Compare commits
104 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 57fd9fe2b6 | |||
| 46a7c7595f | |||
| 0def017060 | |||
| 6dfb1af261 | |||
| f438658b6b | |||
| 5f0096c464 | |||
| 6ac797a69c | |||
| 3d6bcc3102 | |||
| 75df1f3997 | |||
| d6b3527552 | |||
| 989b45db15 | |||
| d86e827563 | |||
| 6ad6fcce0f | |||
| ad47b2972c | |||
| ba493e5a23 | |||
| 627b488556 | |||
| b9e5ff2065 | |||
| 381ca32055 | |||
| 6029847491 | |||
| 66afd5a1de | |||
| da5e1152bb | |||
| b338a7a1d2 | |||
| 6e00a122c6 | |||
| 4dff30f676 | |||
| 71c377484e | |||
| 26906951b3 | |||
| 51202d5a32 | |||
| f4380f89a8 | |||
| e430e4ea0a | |||
| b027e4bdb1 | |||
| fc90b4ba8b | |||
| 88b77cb699 | |||
| 0ed2e9d82d | |||
| 643cfe9b13 | |||
| bc1b7f6fdf | |||
| 57118a868f | |||
| 93f848fd2f | |||
| 667cb95730 | |||
| 4e5d47168c | |||
| 10c0bed462 | |||
| 08b1c5738d | |||
| c2df39405c | |||
| 3e2c50c6cf | |||
| f67db8d8b2 | |||
| 3cd2458fdf | |||
| 13f09d8946 | |||
| 961745e9ba | |||
| 41832c8d82 | |||
| 3041ed3b6e | |||
| 6d550611d2 | |||
| 3c97d9648b | |||
| 3afdabb93e | |||
| 25b0e0d091 | |||
| a43e5c3fb3 | |||
| 996cdaf3ff | |||
| 1d84695fb0 | |||
| 64e0b76d00 | |||
| 8a74ea8829 | |||
| f4ead89956 | |||
| 865ca697ca | |||
| ebfaca5b3d | |||
| 9b54200d8c | |||
| bd6811d060 | |||
| b32249877a | |||
| 6fb6ef4e7a | |||
| bb4e28904f | |||
| c3d1af89ae | |||
| e6221c5f0e | |||
| 6566a918af | |||
| 6ea637d6c5 | |||
| 531410f64a | |||
| 182960051f | |||
| 7d9f9605a2 | |||
| 7065441972 | |||
| 6e2cf4cbc0 | |||
| de7daaa81a | |||
| c0cbe67bcd | |||
| c5606212f2 | |||
| 0702e72e3f | |||
| 0503aa7982 | |||
| f98c5d0609 | |||
| 4797d2f270 | |||
| c8b9dace72 | |||
| fbae66de8a | |||
| 46e7f23df1 | |||
| 6f3541fd7c | |||
| 863f3f29a2 | |||
| 9264480824 | |||
| 5ff8c3b219 | |||
| ff28547a36 | |||
| dde6df7a26 | |||
| 92b0e07617 | |||
| 951ead5a1e | |||
| e79f43813b | |||
| 73ab5de46c | |||
| 986b9dcb3d | |||
| ae7db23bdd | |||
| 2f358a1775 | |||
| fc3004b2f6 | |||
| 086b79e5b9 | |||
| 8cb88cabee | |||
| ac89d2ff56 | |||
| 423faa6153 | |||
| a051490ec9 |
@@ -80,10 +80,20 @@ jobs:
|
||||
with:
|
||||
name: storybook-twenty-front-component-renderer
|
||||
path: packages/twenty-front-component-renderer/storybook-static
|
||||
- name: Resolve Playwright version
|
||||
id: playwright-version
|
||||
run: echo "version=$(node -p "require('@playwright/test/package.json').version")" >> "$GITHUB_OUTPUT"
|
||||
- name: Cache Playwright browsers
|
||||
id: playwright-cache
|
||||
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
||||
with:
|
||||
path: ~/.cache/ms-playwright
|
||||
key: v4-playwright-browsers-${{ runner.os }}-${{ steps.playwright-version.outputs.version }}
|
||||
- name: Install Playwright
|
||||
if: steps.playwright-cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
cd packages/twenty-front-component-renderer
|
||||
npx playwright install
|
||||
npx playwright install chromium
|
||||
- name: Serve storybook & run tests
|
||||
run: |
|
||||
npx http-server packages/twenty-front-component-renderer/storybook-static --port 6008 --silent &
|
||||
|
||||
@@ -96,10 +96,20 @@ jobs:
|
||||
with:
|
||||
name: storybook-static
|
||||
path: packages/twenty-front/storybook-static
|
||||
- name: Resolve Playwright version
|
||||
id: playwright-version
|
||||
run: echo "version=$(node -p "require('@playwright/test/package.json').version")" >> "$GITHUB_OUTPUT"
|
||||
- name: Cache Playwright browsers
|
||||
id: playwright-cache
|
||||
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
||||
with:
|
||||
path: ~/.cache/ms-playwright
|
||||
key: v4-playwright-browsers-${{ runner.os }}-${{ steps.playwright-version.outputs.version }}
|
||||
- name: Install Playwright
|
||||
if: steps.playwright-cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
cd packages/twenty-front
|
||||
npx playwright install
|
||||
npx playwright install chromium
|
||||
- name: Front / Write .env
|
||||
run: npx nx reset:env twenty-front
|
||||
- name: Serve storybook & run tests
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 173 KiB |
+1
-1
@@ -28,7 +28,7 @@
|
||||
"resolutions": {
|
||||
"graphql": "16.8.1",
|
||||
"type-fest": "4.10.1",
|
||||
"typescript": "5.9.2",
|
||||
"typescript": "5.9.3",
|
||||
"nodemailer": "8.0.4",
|
||||
"graphql-redis-subscriptions/ioredis": "^5.6.0",
|
||||
"@lingui/core": "5.1.2",
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
"jest": "29.7.0",
|
||||
"jest-environment-node": "^29.4.1",
|
||||
"twenty-shared": "workspace:*",
|
||||
"typescript": "^5.9.2",
|
||||
"typescript": "^5.9.3",
|
||||
"vite": "^7.0.0",
|
||||
"vite-plugin-dts": "^4.5.4",
|
||||
"vite-tsconfig-paths": "^4.2.1"
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
"@typescript/native-preview": "^7.0.0-dev.20260116.1",
|
||||
"tsc-alias": "^1.8.16",
|
||||
"twenty-shared": "workspace:*",
|
||||
"typescript": "^5.9.2",
|
||||
"typescript": "^5.9.3",
|
||||
"vite": "^7.0.0",
|
||||
"vite-plugin-dts": "^4.5.4",
|
||||
"vite-tsconfig-paths": "^4.2.1",
|
||||
|
||||
@@ -1100,7 +1100,7 @@ type PageLayoutWidgetCanvasPosition {
|
||||
layoutMode: PageLayoutTabLayoutMode!
|
||||
}
|
||||
|
||||
union WidgetConfiguration = AggregateChartConfiguration | StandaloneRichTextConfiguration | PieChartConfiguration | LineChartConfiguration | IframeConfiguration | GaugeChartConfiguration | BarChartConfiguration | CalendarConfiguration | FrontComponentConfiguration | EmailsConfiguration | EmailThreadConfiguration | FieldConfiguration | FieldRichTextConfiguration | FieldsConfiguration | FilesConfiguration | NotesConfiguration | TasksConfiguration | TimelineConfiguration | ViewConfiguration | RecordTableConfiguration | WorkflowConfiguration | WorkflowRunConfiguration | WorkflowVersionConfiguration
|
||||
union WidgetConfiguration = AggregateChartConfiguration | StandaloneRichTextConfiguration | PieChartConfiguration | LineChartConfiguration | IframeConfiguration | BarChartConfiguration | CalendarConfiguration | FrontComponentConfiguration | EmailsConfiguration | EmailThreadConfiguration | FieldConfiguration | FieldRichTextConfiguration | FieldsConfiguration | FilesConfiguration | NotesConfiguration | TasksConfiguration | TimelineConfiguration | ViewConfiguration | RecordTableConfiguration | WorkflowConfiguration | WorkflowRunConfiguration | WorkflowVersionConfiguration
|
||||
|
||||
type AggregateChartConfiguration {
|
||||
configurationType: WidgetConfigurationType!
|
||||
@@ -1120,7 +1120,6 @@ type AggregateChartConfiguration {
|
||||
|
||||
enum WidgetConfigurationType {
|
||||
AGGREGATE_CHART
|
||||
GAUGE_CHART
|
||||
PIE_CHART
|
||||
BAR_CHART
|
||||
LINE_CHART
|
||||
@@ -1239,18 +1238,6 @@ type IframeConfiguration {
|
||||
url: String
|
||||
}
|
||||
|
||||
type GaugeChartConfiguration {
|
||||
configurationType: WidgetConfigurationType!
|
||||
aggregateFieldMetadataId: UUID!
|
||||
aggregateOperation: AggregateOperations!
|
||||
displayDataLabel: Boolean
|
||||
color: String
|
||||
description: String
|
||||
filter: JSON
|
||||
timezone: String
|
||||
firstDayOfTheWeek: Int
|
||||
}
|
||||
|
||||
type BarChartConfiguration {
|
||||
configurationType: WidgetConfigurationType!
|
||||
aggregateFieldMetadataId: UUID!
|
||||
@@ -1315,6 +1302,7 @@ type FieldConfiguration {
|
||||
configurationType: WidgetConfigurationType!
|
||||
fieldMetadataId: String!
|
||||
fieldDisplayMode: FieldDisplayMode!
|
||||
viewId: String
|
||||
}
|
||||
|
||||
"""Display mode for field configuration widgets"""
|
||||
@@ -1323,6 +1311,7 @@ enum FieldDisplayMode {
|
||||
EDITOR
|
||||
FIELD
|
||||
VIEW
|
||||
TABLE
|
||||
}
|
||||
|
||||
type FieldRichTextConfiguration {
|
||||
@@ -1444,6 +1433,39 @@ type Analytics {
|
||||
success: Boolean!
|
||||
}
|
||||
|
||||
type VerificationRecord {
|
||||
type: String!
|
||||
key: String!
|
||||
value: String!
|
||||
priority: Float
|
||||
}
|
||||
|
||||
type EmailingDomain {
|
||||
id: UUID!
|
||||
createdAt: DateTime!
|
||||
updatedAt: DateTime!
|
||||
domain: String!
|
||||
driver: EmailingDomainDriver!
|
||||
status: EmailingDomainStatus!
|
||||
verificationRecords: [VerificationRecord!]
|
||||
verifiedAt: DateTime
|
||||
}
|
||||
|
||||
enum EmailingDomainDriver {
|
||||
AWS_SES
|
||||
}
|
||||
|
||||
enum EmailingDomainStatus {
|
||||
PENDING
|
||||
VERIFIED
|
||||
FAILED
|
||||
TEMPORARY_FAILURE
|
||||
}
|
||||
|
||||
type SendEmailViaDomainOutput {
|
||||
messageId: String!
|
||||
}
|
||||
|
||||
type ApprovedAccessDomain {
|
||||
id: UUID!
|
||||
domain: String!
|
||||
@@ -1754,10 +1776,10 @@ enum FeatureFlagKey {
|
||||
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
|
||||
IS_SETTINGS_DISCOVERY_HERO_ENABLED
|
||||
}
|
||||
|
||||
type WorkspaceUrls {
|
||||
@@ -2371,35 +2393,6 @@ type PublicDomain {
|
||||
createdAt: DateTime!
|
||||
}
|
||||
|
||||
type VerificationRecord {
|
||||
type: String!
|
||||
key: String!
|
||||
value: String!
|
||||
priority: Float
|
||||
}
|
||||
|
||||
type EmailingDomain {
|
||||
id: UUID!
|
||||
createdAt: DateTime!
|
||||
updatedAt: DateTime!
|
||||
domain: String!
|
||||
driver: EmailingDomainDriver!
|
||||
status: EmailingDomainStatus!
|
||||
verificationRecords: [VerificationRecord!]
|
||||
verifiedAt: DateTime
|
||||
}
|
||||
|
||||
enum EmailingDomainDriver {
|
||||
AWS_SES
|
||||
}
|
||||
|
||||
enum EmailingDomainStatus {
|
||||
PENDING
|
||||
VERIFIED
|
||||
FAILED
|
||||
TEMPORARY_FAILURE
|
||||
}
|
||||
|
||||
type AutocompleteResult {
|
||||
text: String!
|
||||
placeId: String!
|
||||
@@ -2707,6 +2700,12 @@ type AgentTurn {
|
||||
createdAt: DateTime!
|
||||
}
|
||||
|
||||
type WorkspaceAiStats {
|
||||
conversationsCount: Int!
|
||||
skillsCount: Int!
|
||||
toolsCount: Int!
|
||||
}
|
||||
|
||||
type CalendarChannel {
|
||||
id: UUID!
|
||||
handle: String!
|
||||
@@ -2944,6 +2943,7 @@ type Query {
|
||||
getPageLayoutTab(id: String!): PageLayoutTab!
|
||||
getPageLayouts(objectMetadataId: String, pageLayoutType: PageLayoutType): [PageLayout!]!
|
||||
getPageLayout(id: String!): PageLayout
|
||||
getEmailingDomains: [EmailingDomain!]!
|
||||
applicationConnectionProviders(applicationId: UUID!): [ApplicationConnectionProvider!]!
|
||||
getPageLayoutWidgets(pageLayoutTabId: String!): [PageLayoutWidget!]!
|
||||
getPageLayoutWidget(id: String!): PageLayoutWidget!
|
||||
@@ -3003,6 +3003,7 @@ type Query {
|
||||
myConnectedAccounts: [ConnectedAccountPublicDTO!]!
|
||||
myCalendarChannels(connectedAccountId: UUID): [CalendarChannel!]!
|
||||
minimalMetadata: MinimalMetadata!
|
||||
findWorkspaceAiStats: WorkspaceAiStats!
|
||||
chatThreads: [AgentChatThread!]!
|
||||
chatThread(id: UUID!): AgentChatThread!
|
||||
chatMessages(threadId: UUID!): [AgentMessage!]!
|
||||
@@ -3038,7 +3039,6 @@ type Query {
|
||||
getAddressDetails(placeId: String!, token: String!): PlaceDetailsResult!
|
||||
getUsageAnalytics(input: UsageAnalyticsInput): UsageAnalytics!
|
||||
findManyPublicDomains: [PublicDomain!]!
|
||||
getEmailingDomains: [EmailingDomain!]!
|
||||
findManyMarketplaceApps: [MarketplaceApp!]!
|
||||
findMarketplaceAppDetail(universalIdentifier: String!): MarketplaceAppDetail!
|
||||
}
|
||||
@@ -3193,6 +3193,10 @@ type Mutation {
|
||||
resetPageLayoutToDefault(id: String!): PageLayout!
|
||||
resetPageLayoutWidgetToDefault(id: String!): PageLayoutWidget!
|
||||
resetPageLayoutTabToDefault(id: String!): PageLayoutTab!
|
||||
createEmailingDomain(domain: String!, driver: EmailingDomainDriver!): EmailingDomain!
|
||||
deleteEmailingDomain(id: String!): Boolean!
|
||||
verifyEmailingDomain(id: String!): EmailingDomain!
|
||||
sendEmailViaEmailingDomain(input: SendEmailViaDomainInput!): SendEmailViaDomainOutput!
|
||||
updateOneApplicationVariable(key: String!, value: String!, applicationId: UUID!): Boolean!
|
||||
createPageLayoutWidget(input: CreatePageLayoutWidgetInput!): PageLayoutWidget!
|
||||
updatePageLayoutWidget(id: String!, input: UpdatePageLayoutWidgetInput!): PageLayoutWidget!
|
||||
@@ -3273,6 +3277,7 @@ type Mutation {
|
||||
authorizeApp(clientId: String!, codeChallenge: String, redirectUrl: String!, state: String, scope: String): AuthorizeApp!
|
||||
renewToken(appToken: String!): AuthTokens!
|
||||
generateApiKeyToken(apiKeyId: UUID!, expiresAt: String!): ApiKeyToken!
|
||||
generatePlaygroundToken: AuthToken!
|
||||
emailPasswordResetLink(email: String!, workspaceId: UUID): EmailPasswordResetLink!
|
||||
updatePasswordViaResetToken(passwordResetToken: String!, newPassword: String!): InvalidatePassword!
|
||||
createApplicationRegistration(input: CreateApplicationRegistrationInput!): CreateApplicationRegistration!
|
||||
@@ -3313,9 +3318,6 @@ type Mutation {
|
||||
updatePublicDomain(domain: String!, applicationId: String): PublicDomain!
|
||||
deletePublicDomain(domain: String!): Boolean!
|
||||
checkPublicDomainValidRecords(domain: String!): DomainValidRecords
|
||||
createEmailingDomain(domain: String!, driver: EmailingDomainDriver!): EmailingDomain!
|
||||
deleteEmailingDomain(id: String!): Boolean!
|
||||
verifyEmailingDomain(id: String!): EmailingDomain!
|
||||
createOneAppToken(input: CreateOneAppTokenInput!): AppToken!
|
||||
installMarketplaceApp(universalIdentifier: String!, version: String): Boolean! @deprecated(reason: "Use installApplication instead")
|
||||
installApplication(universalIdentifier: String!, version: String): Application!
|
||||
@@ -3759,6 +3761,18 @@ input GridPositionInput {
|
||||
columnSpan: Float!
|
||||
}
|
||||
|
||||
input SendEmailViaDomainInput {
|
||||
emailingDomainId: String!
|
||||
to: [String!]!
|
||||
cc: [String!]
|
||||
bcc: [String!]
|
||||
subject: String!
|
||||
text: String!
|
||||
html: String
|
||||
from: String!
|
||||
replyTo: [String!]
|
||||
}
|
||||
|
||||
input CreatePageLayoutWidgetInput {
|
||||
pageLayoutTabId: UUID!
|
||||
title: String!
|
||||
|
||||
@@ -790,7 +790,7 @@ export interface PageLayoutWidgetCanvasPosition {
|
||||
__typename: 'PageLayoutWidgetCanvasPosition'
|
||||
}
|
||||
|
||||
export type WidgetConfiguration = (AggregateChartConfiguration | StandaloneRichTextConfiguration | PieChartConfiguration | LineChartConfiguration | IframeConfiguration | GaugeChartConfiguration | BarChartConfiguration | CalendarConfiguration | FrontComponentConfiguration | EmailsConfiguration | EmailThreadConfiguration | FieldConfiguration | FieldRichTextConfiguration | FieldsConfiguration | FilesConfiguration | NotesConfiguration | TasksConfiguration | TimelineConfiguration | ViewConfiguration | RecordTableConfiguration | WorkflowConfiguration | WorkflowRunConfiguration | WorkflowVersionConfiguration) & { __isUnion?: true }
|
||||
export type WidgetConfiguration = (AggregateChartConfiguration | StandaloneRichTextConfiguration | PieChartConfiguration | LineChartConfiguration | IframeConfiguration | BarChartConfiguration | CalendarConfiguration | FrontComponentConfiguration | EmailsConfiguration | EmailThreadConfiguration | FieldConfiguration | FieldRichTextConfiguration | FieldsConfiguration | FilesConfiguration | NotesConfiguration | TasksConfiguration | TimelineConfiguration | ViewConfiguration | RecordTableConfiguration | WorkflowConfiguration | WorkflowRunConfiguration | WorkflowVersionConfiguration) & { __isUnion?: true }
|
||||
|
||||
export interface AggregateChartConfiguration {
|
||||
configurationType: WidgetConfigurationType
|
||||
@@ -809,7 +809,7 @@ export interface AggregateChartConfiguration {
|
||||
__typename: 'AggregateChartConfiguration'
|
||||
}
|
||||
|
||||
export type WidgetConfigurationType = 'AGGREGATE_CHART' | 'GAUGE_CHART' | 'PIE_CHART' | 'BAR_CHART' | 'LINE_CHART' | 'IFRAME' | 'STANDALONE_RICH_TEXT' | 'VIEW' | 'FIELD' | 'FIELDS' | 'TIMELINE' | 'TASKS' | 'NOTES' | 'FILES' | 'EMAILS' | 'CALENDAR' | 'FIELD_RICH_TEXT' | 'WORKFLOW' | 'WORKFLOW_VERSION' | 'WORKFLOW_RUN' | 'FRONT_COMPONENT' | 'RECORD_TABLE' | 'EMAIL_THREAD'
|
||||
export type WidgetConfigurationType = 'AGGREGATE_CHART' | 'PIE_CHART' | 'BAR_CHART' | 'LINE_CHART' | 'IFRAME' | 'STANDALONE_RICH_TEXT' | 'VIEW' | 'FIELD' | 'FIELDS' | 'TIMELINE' | 'TASKS' | 'NOTES' | 'FILES' | 'EMAILS' | 'CALENDAR' | 'FIELD_RICH_TEXT' | 'WORKFLOW' | 'WORKFLOW_VERSION' | 'WORKFLOW_RUN' | 'FRONT_COMPONENT' | 'RECORD_TABLE' | 'EMAIL_THREAD'
|
||||
|
||||
export interface StandaloneRichTextConfiguration {
|
||||
configurationType: WidgetConfigurationType
|
||||
@@ -888,19 +888,6 @@ export interface IframeConfiguration {
|
||||
__typename: 'IframeConfiguration'
|
||||
}
|
||||
|
||||
export interface GaugeChartConfiguration {
|
||||
configurationType: WidgetConfigurationType
|
||||
aggregateFieldMetadataId: Scalars['UUID']
|
||||
aggregateOperation: AggregateOperations
|
||||
displayDataLabel?: Scalars['Boolean']
|
||||
color?: Scalars['String']
|
||||
description?: Scalars['String']
|
||||
filter?: Scalars['JSON']
|
||||
timezone?: Scalars['String']
|
||||
firstDayOfTheWeek?: Scalars['Int']
|
||||
__typename: 'GaugeChartConfiguration'
|
||||
}
|
||||
|
||||
export interface BarChartConfiguration {
|
||||
configurationType: WidgetConfigurationType
|
||||
aggregateFieldMetadataId: Scalars['UUID']
|
||||
@@ -966,12 +953,13 @@ export interface FieldConfiguration {
|
||||
configurationType: WidgetConfigurationType
|
||||
fieldMetadataId: Scalars['String']
|
||||
fieldDisplayMode: FieldDisplayMode
|
||||
viewId?: Scalars['String']
|
||||
__typename: 'FieldConfiguration'
|
||||
}
|
||||
|
||||
|
||||
/** Display mode for field configuration widgets */
|
||||
export type FieldDisplayMode = 'CARD' | 'EDITOR' | 'FIELD' | 'VIEW'
|
||||
export type FieldDisplayMode = 'CARD' | 'EDITOR' | 'FIELD' | 'VIEW' | 'TABLE'
|
||||
|
||||
export interface FieldRichTextConfiguration {
|
||||
configurationType: WidgetConfigurationType
|
||||
@@ -1106,6 +1094,35 @@ export interface Analytics {
|
||||
__typename: 'Analytics'
|
||||
}
|
||||
|
||||
export interface VerificationRecord {
|
||||
type: Scalars['String']
|
||||
key: Scalars['String']
|
||||
value: Scalars['String']
|
||||
priority?: Scalars['Float']
|
||||
__typename: 'VerificationRecord'
|
||||
}
|
||||
|
||||
export interface EmailingDomain {
|
||||
id: Scalars['UUID']
|
||||
createdAt: Scalars['DateTime']
|
||||
updatedAt: Scalars['DateTime']
|
||||
domain: Scalars['String']
|
||||
driver: EmailingDomainDriver
|
||||
status: EmailingDomainStatus
|
||||
verificationRecords?: VerificationRecord[]
|
||||
verifiedAt?: Scalars['DateTime']
|
||||
__typename: 'EmailingDomain'
|
||||
}
|
||||
|
||||
export type EmailingDomainDriver = 'AWS_SES'
|
||||
|
||||
export type EmailingDomainStatus = 'PENDING' | 'VERIFIED' | 'FAILED' | 'TEMPORARY_FAILURE'
|
||||
|
||||
export interface SendEmailViaDomainOutput {
|
||||
messageId: Scalars['String']
|
||||
__typename: 'SendEmailViaDomainOutput'
|
||||
}
|
||||
|
||||
export interface ApprovedAccessDomain {
|
||||
id: Scalars['UUID']
|
||||
domain: Scalars['String']
|
||||
@@ -1394,7 +1411,7 @@ export interface FeatureFlag {
|
||||
__typename: 'FeatureFlag'
|
||||
}
|
||||
|
||||
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 type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_MARKETPLACE_SETTING_TAB_VISIBLE' | 'IS_PUBLIC_DOMAIN_ENABLED' | 'IS_EMAIL_GROUP_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_REST_METADATA_API_NEW_FORMAT_DIRECT' | 'IS_SETTINGS_DISCOVERY_HERO_ENABLED'
|
||||
|
||||
export interface WorkspaceUrls {
|
||||
customUrl?: Scalars['String']
|
||||
@@ -2050,30 +2067,6 @@ export interface PublicDomain {
|
||||
__typename: 'PublicDomain'
|
||||
}
|
||||
|
||||
export interface VerificationRecord {
|
||||
type: Scalars['String']
|
||||
key: Scalars['String']
|
||||
value: Scalars['String']
|
||||
priority?: Scalars['Float']
|
||||
__typename: 'VerificationRecord'
|
||||
}
|
||||
|
||||
export interface EmailingDomain {
|
||||
id: Scalars['UUID']
|
||||
createdAt: Scalars['DateTime']
|
||||
updatedAt: Scalars['DateTime']
|
||||
domain: Scalars['String']
|
||||
driver: EmailingDomainDriver
|
||||
status: EmailingDomainStatus
|
||||
verificationRecords?: VerificationRecord[]
|
||||
verifiedAt?: Scalars['DateTime']
|
||||
__typename: 'EmailingDomain'
|
||||
}
|
||||
|
||||
export type EmailingDomainDriver = 'AWS_SES'
|
||||
|
||||
export type EmailingDomainStatus = 'PENDING' | 'VERIFIED' | 'FAILED' | 'TEMPORARY_FAILURE'
|
||||
|
||||
export interface AutocompleteResult {
|
||||
text: Scalars['String']
|
||||
placeId: Scalars['String']
|
||||
@@ -2417,6 +2410,13 @@ export interface AgentTurn {
|
||||
__typename: 'AgentTurn'
|
||||
}
|
||||
|
||||
export interface WorkspaceAiStats {
|
||||
conversationsCount: Scalars['Int']
|
||||
skillsCount: Scalars['Int']
|
||||
toolsCount: Scalars['Int']
|
||||
__typename: 'WorkspaceAiStats'
|
||||
}
|
||||
|
||||
export interface CalendarChannel {
|
||||
id: Scalars['UUID']
|
||||
handle: Scalars['String']
|
||||
@@ -2571,6 +2571,7 @@ export interface Query {
|
||||
getPageLayoutTab: PageLayoutTab
|
||||
getPageLayouts: PageLayout[]
|
||||
getPageLayout?: PageLayout
|
||||
getEmailingDomains: EmailingDomain[]
|
||||
applicationConnectionProviders: ApplicationConnectionProvider[]
|
||||
getPageLayoutWidgets: PageLayoutWidget[]
|
||||
getPageLayoutWidget: PageLayoutWidget
|
||||
@@ -2603,6 +2604,7 @@ export interface Query {
|
||||
myConnectedAccounts: ConnectedAccountPublicDTO[]
|
||||
myCalendarChannels: CalendarChannel[]
|
||||
minimalMetadata: MinimalMetadata
|
||||
findWorkspaceAiStats: WorkspaceAiStats
|
||||
chatThreads: AgentChatThread[]
|
||||
chatThread: AgentChatThread
|
||||
chatMessages: AgentMessage[]
|
||||
@@ -2638,7 +2640,6 @@ export interface Query {
|
||||
getAddressDetails: PlaceDetailsResult
|
||||
getUsageAnalytics: UsageAnalytics
|
||||
findManyPublicDomains: PublicDomain[]
|
||||
getEmailingDomains: EmailingDomain[]
|
||||
findManyMarketplaceApps: MarketplaceApp[]
|
||||
findMarketplaceAppDetail: MarketplaceAppDetail
|
||||
__typename: 'Query'
|
||||
@@ -2726,6 +2727,10 @@ export interface Mutation {
|
||||
resetPageLayoutToDefault: PageLayout
|
||||
resetPageLayoutWidgetToDefault: PageLayoutWidget
|
||||
resetPageLayoutTabToDefault: PageLayoutTab
|
||||
createEmailingDomain: EmailingDomain
|
||||
deleteEmailingDomain: Scalars['Boolean']
|
||||
verifyEmailingDomain: EmailingDomain
|
||||
sendEmailViaEmailingDomain: SendEmailViaDomainOutput
|
||||
updateOneApplicationVariable: Scalars['Boolean']
|
||||
createPageLayoutWidget: PageLayoutWidget
|
||||
updatePageLayoutWidget: PageLayoutWidget
|
||||
@@ -2806,6 +2811,7 @@ export interface Mutation {
|
||||
authorizeApp: AuthorizeApp
|
||||
renewToken: AuthTokens
|
||||
generateApiKeyToken: ApiKeyToken
|
||||
generatePlaygroundToken: AuthToken
|
||||
emailPasswordResetLink: EmailPasswordResetLink
|
||||
updatePasswordViaResetToken: InvalidatePassword
|
||||
createApplicationRegistration: CreateApplicationRegistration
|
||||
@@ -2846,9 +2852,6 @@ export interface Mutation {
|
||||
updatePublicDomain: PublicDomain
|
||||
deletePublicDomain: Scalars['Boolean']
|
||||
checkPublicDomainValidRecords?: DomainValidRecords
|
||||
createEmailingDomain: EmailingDomain
|
||||
deleteEmailingDomain: Scalars['Boolean']
|
||||
verifyEmailingDomain: EmailingDomain
|
||||
createOneAppToken: AppToken
|
||||
/** @deprecated Use installApplication instead */
|
||||
installMarketplaceApp: Scalars['Boolean']
|
||||
@@ -3703,7 +3706,6 @@ export interface WidgetConfigurationGenqlSelection{
|
||||
on_PieChartConfiguration?:PieChartConfigurationGenqlSelection,
|
||||
on_LineChartConfiguration?:LineChartConfigurationGenqlSelection,
|
||||
on_IframeConfiguration?:IframeConfigurationGenqlSelection,
|
||||
on_GaugeChartConfiguration?:GaugeChartConfigurationGenqlSelection,
|
||||
on_BarChartConfiguration?:BarChartConfigurationGenqlSelection,
|
||||
on_CalendarConfiguration?:CalendarConfigurationGenqlSelection,
|
||||
on_FrontComponentConfiguration?:FrontComponentConfigurationGenqlSelection,
|
||||
@@ -3811,20 +3813,6 @@ export interface IframeConfigurationGenqlSelection{
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface GaugeChartConfigurationGenqlSelection{
|
||||
configurationType?: boolean | number
|
||||
aggregateFieldMetadataId?: boolean | number
|
||||
aggregateOperation?: boolean | number
|
||||
displayDataLabel?: boolean | number
|
||||
color?: boolean | number
|
||||
description?: boolean | number
|
||||
filter?: boolean | number
|
||||
timezone?: boolean | number
|
||||
firstDayOfTheWeek?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface BarChartConfigurationGenqlSelection{
|
||||
configurationType?: boolean | number
|
||||
aggregateFieldMetadataId?: boolean | number
|
||||
@@ -3887,6 +3875,7 @@ export interface FieldConfigurationGenqlSelection{
|
||||
configurationType?: boolean | number
|
||||
fieldMetadataId?: boolean | number
|
||||
fieldDisplayMode?: boolean | number
|
||||
viewId?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
@@ -4040,6 +4029,34 @@ export interface AnalyticsGenqlSelection{
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface VerificationRecordGenqlSelection{
|
||||
type?: boolean | number
|
||||
key?: boolean | number
|
||||
value?: boolean | number
|
||||
priority?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface EmailingDomainGenqlSelection{
|
||||
id?: boolean | number
|
||||
createdAt?: boolean | number
|
||||
updatedAt?: boolean | number
|
||||
domain?: boolean | number
|
||||
driver?: boolean | number
|
||||
status?: boolean | number
|
||||
verificationRecords?: VerificationRecordGenqlSelection
|
||||
verifiedAt?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface SendEmailViaDomainOutputGenqlSelection{
|
||||
messageId?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface ApprovedAccessDomainGenqlSelection{
|
||||
id?: boolean | number
|
||||
domain?: boolean | number
|
||||
@@ -5051,28 +5068,6 @@ export interface PublicDomainGenqlSelection{
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface VerificationRecordGenqlSelection{
|
||||
type?: boolean | number
|
||||
key?: boolean | number
|
||||
value?: boolean | number
|
||||
priority?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface EmailingDomainGenqlSelection{
|
||||
id?: boolean | number
|
||||
createdAt?: boolean | number
|
||||
updatedAt?: boolean | number
|
||||
domain?: boolean | number
|
||||
driver?: boolean | number
|
||||
status?: boolean | number
|
||||
verificationRecords?: VerificationRecordGenqlSelection
|
||||
verifiedAt?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface AutocompleteResultGenqlSelection{
|
||||
text?: boolean | number
|
||||
placeId?: boolean | number
|
||||
@@ -5452,6 +5447,14 @@ export interface AgentTurnGenqlSelection{
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface WorkspaceAiStatsGenqlSelection{
|
||||
conversationsCount?: boolean | number
|
||||
skillsCount?: boolean | number
|
||||
toolsCount?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface CalendarChannelGenqlSelection{
|
||||
id?: boolean | number
|
||||
handle?: boolean | number
|
||||
@@ -5588,6 +5591,7 @@ export interface QueryGenqlSelection{
|
||||
getPageLayoutTab?: (PageLayoutTabGenqlSelection & { __args: {id: Scalars['String']} })
|
||||
getPageLayouts?: (PageLayoutGenqlSelection & { __args?: {objectMetadataId?: (Scalars['String'] | null), pageLayoutType?: (PageLayoutType | null)} })
|
||||
getPageLayout?: (PageLayoutGenqlSelection & { __args: {id: Scalars['String']} })
|
||||
getEmailingDomains?: EmailingDomainGenqlSelection
|
||||
applicationConnectionProviders?: (ApplicationConnectionProviderGenqlSelection & { __args: {applicationId: Scalars['UUID']} })
|
||||
getPageLayoutWidgets?: (PageLayoutWidgetGenqlSelection & { __args: {pageLayoutTabId: Scalars['String']} })
|
||||
getPageLayoutWidget?: (PageLayoutWidgetGenqlSelection & { __args: {id: Scalars['String']} })
|
||||
@@ -5638,6 +5642,7 @@ export interface QueryGenqlSelection{
|
||||
myConnectedAccounts?: ConnectedAccountPublicDTOGenqlSelection
|
||||
myCalendarChannels?: (CalendarChannelGenqlSelection & { __args?: {connectedAccountId?: (Scalars['UUID'] | null)} })
|
||||
minimalMetadata?: MinimalMetadataGenqlSelection
|
||||
findWorkspaceAiStats?: WorkspaceAiStatsGenqlSelection
|
||||
chatThreads?: AgentChatThreadGenqlSelection
|
||||
chatThread?: (AgentChatThreadGenqlSelection & { __args: {id: Scalars['UUID']} })
|
||||
chatMessages?: (AgentMessageGenqlSelection & { __args: {threadId: Scalars['UUID']} })
|
||||
@@ -5673,7 +5678,6 @@ export interface QueryGenqlSelection{
|
||||
getAddressDetails?: (PlaceDetailsResultGenqlSelection & { __args: {placeId: Scalars['String'], token: Scalars['String']} })
|
||||
getUsageAnalytics?: (UsageAnalyticsGenqlSelection & { __args?: {input?: (UsageAnalyticsInput | null)} })
|
||||
findManyPublicDomains?: PublicDomainGenqlSelection
|
||||
getEmailingDomains?: EmailingDomainGenqlSelection
|
||||
findManyMarketplaceApps?: MarketplaceAppGenqlSelection
|
||||
findMarketplaceAppDetail?: (MarketplaceAppDetailGenqlSelection & { __args: {universalIdentifier: Scalars['String']} })
|
||||
__typename?: boolean | number
|
||||
@@ -5782,6 +5786,10 @@ export interface MutationGenqlSelection{
|
||||
resetPageLayoutToDefault?: (PageLayoutGenqlSelection & { __args: {id: Scalars['String']} })
|
||||
resetPageLayoutWidgetToDefault?: (PageLayoutWidgetGenqlSelection & { __args: {id: Scalars['String']} })
|
||||
resetPageLayoutTabToDefault?: (PageLayoutTabGenqlSelection & { __args: {id: Scalars['String']} })
|
||||
createEmailingDomain?: (EmailingDomainGenqlSelection & { __args: {domain: Scalars['String'], driver: EmailingDomainDriver} })
|
||||
deleteEmailingDomain?: { __args: {id: Scalars['String']} }
|
||||
verifyEmailingDomain?: (EmailingDomainGenqlSelection & { __args: {id: Scalars['String']} })
|
||||
sendEmailViaEmailingDomain?: (SendEmailViaDomainOutputGenqlSelection & { __args: {input: SendEmailViaDomainInput} })
|
||||
updateOneApplicationVariable?: { __args: {key: Scalars['String'], value: Scalars['String'], applicationId: Scalars['UUID']} }
|
||||
createPageLayoutWidget?: (PageLayoutWidgetGenqlSelection & { __args: {input: CreatePageLayoutWidgetInput} })
|
||||
updatePageLayoutWidget?: (PageLayoutWidgetGenqlSelection & { __args: {id: Scalars['String'], input: UpdatePageLayoutWidgetInput} })
|
||||
@@ -5862,6 +5870,7 @@ export interface MutationGenqlSelection{
|
||||
authorizeApp?: (AuthorizeAppGenqlSelection & { __args: {clientId: Scalars['String'], codeChallenge?: (Scalars['String'] | null), redirectUrl: Scalars['String'], state?: (Scalars['String'] | null), scope?: (Scalars['String'] | null)} })
|
||||
renewToken?: (AuthTokensGenqlSelection & { __args: {appToken: Scalars['String']} })
|
||||
generateApiKeyToken?: (ApiKeyTokenGenqlSelection & { __args: {apiKeyId: Scalars['UUID'], expiresAt: Scalars['String']} })
|
||||
generatePlaygroundToken?: AuthTokenGenqlSelection
|
||||
emailPasswordResetLink?: (EmailPasswordResetLinkGenqlSelection & { __args: {email: Scalars['String'], workspaceId?: (Scalars['UUID'] | null)} })
|
||||
updatePasswordViaResetToken?: (InvalidatePasswordGenqlSelection & { __args: {passwordResetToken: Scalars['String'], newPassword: Scalars['String']} })
|
||||
createApplicationRegistration?: (CreateApplicationRegistrationGenqlSelection & { __args: {input: CreateApplicationRegistrationInput} })
|
||||
@@ -5902,9 +5911,6 @@ export interface MutationGenqlSelection{
|
||||
updatePublicDomain?: (PublicDomainGenqlSelection & { __args: {domain: Scalars['String'], applicationId?: (Scalars['String'] | null)} })
|
||||
deletePublicDomain?: { __args: {domain: Scalars['String']} }
|
||||
checkPublicDomainValidRecords?: (DomainValidRecordsGenqlSelection & { __args: {domain: Scalars['String']} })
|
||||
createEmailingDomain?: (EmailingDomainGenqlSelection & { __args: {domain: Scalars['String'], driver: EmailingDomainDriver} })
|
||||
deleteEmailingDomain?: { __args: {id: Scalars['String']} }
|
||||
verifyEmailingDomain?: (EmailingDomainGenqlSelection & { __args: {id: Scalars['String']} })
|
||||
createOneAppToken?: (AppTokenGenqlSelection & { __args: {input: CreateOneAppTokenInput} })
|
||||
/** @deprecated Use installApplication instead */
|
||||
installMarketplaceApp?: { __args: {universalIdentifier: Scalars['String'], version?: (Scalars['String'] | null)} }
|
||||
@@ -6082,6 +6088,8 @@ export interface UpdatePageLayoutWidgetWithIdInput {id: Scalars['UUID'],pageLayo
|
||||
|
||||
export interface GridPositionInput {row: Scalars['Float'],column: Scalars['Float'],rowSpan: Scalars['Float'],columnSpan: Scalars['Float']}
|
||||
|
||||
export interface SendEmailViaDomainInput {emailingDomainId: Scalars['String'],to: Scalars['String'][],cc?: (Scalars['String'][] | null),bcc?: (Scalars['String'][] | null),subject: Scalars['String'],text: Scalars['String'],html?: (Scalars['String'] | null),from: Scalars['String'],replyTo?: (Scalars['String'][] | null)}
|
||||
|
||||
export interface CreatePageLayoutWidgetInput {pageLayoutTabId: Scalars['UUID'],title: Scalars['String'],type: WidgetType,objectMetadataId?: (Scalars['UUID'] | null),gridPosition: GridPositionInput,position?: (Scalars['JSON'] | null),configuration: Scalars['JSON']}
|
||||
|
||||
export interface UpdatePageLayoutWidgetInput {pageLayoutTabId?: (Scalars['UUID'] | null),title?: (Scalars['String'] | null),type?: (WidgetType | null),objectMetadataId?: (Scalars['UUID'] | null),gridPosition?: (GridPositionInput | null),position?: (Scalars['JSON'] | null),configuration?: (Scalars['JSON'] | null),conditionalDisplay?: (Scalars['JSON'] | null),conditionalAvailabilityExpression?: (Scalars['String'] | null)}
|
||||
@@ -6707,7 +6715,7 @@ export interface LogicFunctionLogsInput {applicationId?: (Scalars['UUID'] | null
|
||||
|
||||
|
||||
|
||||
const WidgetConfiguration_possibleTypes: string[] = ['AggregateChartConfiguration','StandaloneRichTextConfiguration','PieChartConfiguration','LineChartConfiguration','IframeConfiguration','GaugeChartConfiguration','BarChartConfiguration','CalendarConfiguration','FrontComponentConfiguration','EmailsConfiguration','EmailThreadConfiguration','FieldConfiguration','FieldRichTextConfiguration','FieldsConfiguration','FilesConfiguration','NotesConfiguration','TasksConfiguration','TimelineConfiguration','ViewConfiguration','RecordTableConfiguration','WorkflowConfiguration','WorkflowRunConfiguration','WorkflowVersionConfiguration']
|
||||
const WidgetConfiguration_possibleTypes: string[] = ['AggregateChartConfiguration','StandaloneRichTextConfiguration','PieChartConfiguration','LineChartConfiguration','IframeConfiguration','BarChartConfiguration','CalendarConfiguration','FrontComponentConfiguration','EmailsConfiguration','EmailThreadConfiguration','FieldConfiguration','FieldRichTextConfiguration','FieldsConfiguration','FilesConfiguration','NotesConfiguration','TasksConfiguration','TimelineConfiguration','ViewConfiguration','RecordTableConfiguration','WorkflowConfiguration','WorkflowRunConfiguration','WorkflowVersionConfiguration']
|
||||
export const isWidgetConfiguration = (obj?: { __typename?: any } | null): obj is WidgetConfiguration => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isWidgetConfiguration"')
|
||||
return WidgetConfiguration_possibleTypes.includes(obj.__typename)
|
||||
@@ -6755,14 +6763,6 @@ export interface LogicFunctionLogsInput {applicationId?: (Scalars['UUID'] | null
|
||||
|
||||
|
||||
|
||||
const GaugeChartConfiguration_possibleTypes: string[] = ['GaugeChartConfiguration']
|
||||
export const isGaugeChartConfiguration = (obj?: { __typename?: any } | null): obj is GaugeChartConfiguration => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isGaugeChartConfiguration"')
|
||||
return GaugeChartConfiguration_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const BarChartConfiguration_possibleTypes: string[] = ['BarChartConfiguration']
|
||||
export const isBarChartConfiguration = (obj?: { __typename?: any } | null): obj is BarChartConfiguration => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isBarChartConfiguration"')
|
||||
@@ -6955,6 +6955,30 @@ export interface LogicFunctionLogsInput {applicationId?: (Scalars['UUID'] | null
|
||||
|
||||
|
||||
|
||||
const VerificationRecord_possibleTypes: string[] = ['VerificationRecord']
|
||||
export const isVerificationRecord = (obj?: { __typename?: any } | null): obj is VerificationRecord => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isVerificationRecord"')
|
||||
return VerificationRecord_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const EmailingDomain_possibleTypes: string[] = ['EmailingDomain']
|
||||
export const isEmailingDomain = (obj?: { __typename?: any } | null): obj is EmailingDomain => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isEmailingDomain"')
|
||||
return EmailingDomain_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const SendEmailViaDomainOutput_possibleTypes: string[] = ['SendEmailViaDomainOutput']
|
||||
export const isSendEmailViaDomainOutput = (obj?: { __typename?: any } | null): obj is SendEmailViaDomainOutput => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isSendEmailViaDomainOutput"')
|
||||
return SendEmailViaDomainOutput_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const ApprovedAccessDomain_possibleTypes: string[] = ['ApprovedAccessDomain']
|
||||
export const isApprovedAccessDomain = (obj?: { __typename?: any } | null): obj is ApprovedAccessDomain => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isApprovedAccessDomain"')
|
||||
@@ -7859,22 +7883,6 @@ export interface LogicFunctionLogsInput {applicationId?: (Scalars['UUID'] | null
|
||||
|
||||
|
||||
|
||||
const VerificationRecord_possibleTypes: string[] = ['VerificationRecord']
|
||||
export const isVerificationRecord = (obj?: { __typename?: any } | null): obj is VerificationRecord => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isVerificationRecord"')
|
||||
return VerificationRecord_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const EmailingDomain_possibleTypes: string[] = ['EmailingDomain']
|
||||
export const isEmailingDomain = (obj?: { __typename?: any } | null): obj is EmailingDomain => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isEmailingDomain"')
|
||||
return EmailingDomain_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const AutocompleteResult_possibleTypes: string[] = ['AutocompleteResult']
|
||||
export const isAutocompleteResult = (obj?: { __typename?: any } | null): obj is AutocompleteResult => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isAutocompleteResult"')
|
||||
@@ -8163,6 +8171,14 @@ export interface LogicFunctionLogsInput {applicationId?: (Scalars['UUID'] | null
|
||||
|
||||
|
||||
|
||||
const WorkspaceAiStats_possibleTypes: string[] = ['WorkspaceAiStats']
|
||||
export const isWorkspaceAiStats = (obj?: { __typename?: any } | null): obj is WorkspaceAiStats => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isWorkspaceAiStats"')
|
||||
return WorkspaceAiStats_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const CalendarChannel_possibleTypes: string[] = ['CalendarChannel']
|
||||
export const isCalendarChannel = (obj?: { __typename?: any } | null): obj is CalendarChannel => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isCalendarChannel"')
|
||||
@@ -8560,7 +8576,6 @@ export const enumPageLayoutTabLayoutMode = {
|
||||
|
||||
export const enumWidgetConfigurationType = {
|
||||
AGGREGATE_CHART: 'AGGREGATE_CHART' as const,
|
||||
GAUGE_CHART: 'GAUGE_CHART' as const,
|
||||
PIE_CHART: 'PIE_CHART' as const,
|
||||
BAR_CHART: 'BAR_CHART' as const,
|
||||
LINE_CHART: 'LINE_CHART' as const,
|
||||
@@ -8627,7 +8642,8 @@ export const enumFieldDisplayMode = {
|
||||
CARD: 'CARD' as const,
|
||||
EDITOR: 'EDITOR' as const,
|
||||
FIELD: 'FIELD' as const,
|
||||
VIEW: 'VIEW' as const
|
||||
VIEW: 'VIEW' as const,
|
||||
TABLE: 'TABLE' as const
|
||||
}
|
||||
|
||||
export const enumPageLayoutType = {
|
||||
@@ -8637,6 +8653,17 @@ export const enumPageLayoutType = {
|
||||
STANDALONE_PAGE: 'STANDALONE_PAGE' as const
|
||||
}
|
||||
|
||||
export const enumEmailingDomainDriver = {
|
||||
AWS_SES: 'AWS_SES' as const
|
||||
}
|
||||
|
||||
export const enumEmailingDomainStatus = {
|
||||
PENDING: 'PENDING' as const,
|
||||
VERIFIED: 'VERIFIED' as const,
|
||||
FAILED: 'FAILED' as const,
|
||||
TEMPORARY_FAILURE: 'TEMPORARY_FAILURE' as const
|
||||
}
|
||||
|
||||
export const enumBillingPlanKey = {
|
||||
PRO: 'PRO' as const,
|
||||
ENTERPRISE: 'ENTERPRISE' as const
|
||||
@@ -8703,10 +8730,10 @@ export const enumFeatureFlagKey = {
|
||||
IS_JSON_FILTER_ENABLED: 'IS_JSON_FILTER_ENABLED' as const,
|
||||
IS_MARKETPLACE_SETTING_TAB_VISIBLE: 'IS_MARKETPLACE_SETTING_TAB_VISIBLE' 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_REST_METADATA_API_NEW_FORMAT_DIRECT: 'IS_REST_METADATA_API_NEW_FORMAT_DIRECT' as const
|
||||
IS_REST_METADATA_API_NEW_FORMAT_DIRECT: 'IS_REST_METADATA_API_NEW_FORMAT_DIRECT' as const,
|
||||
IS_SETTINGS_DISCOVERY_HERO_ENABLED: 'IS_SETTINGS_DISCOVERY_HERO_ENABLED' as const
|
||||
}
|
||||
|
||||
export const enumIdentityProviderType = {
|
||||
@@ -8750,17 +8777,6 @@ export const enumBillingEntitlementKey = {
|
||||
AUDIT_LOGS: 'AUDIT_LOGS' as const
|
||||
}
|
||||
|
||||
export const enumEmailingDomainDriver = {
|
||||
AWS_SES: 'AWS_SES' as const
|
||||
}
|
||||
|
||||
export const enumEmailingDomainStatus = {
|
||||
PENDING: 'PENDING' as const,
|
||||
VERIFIED: 'VERIFIED' as const,
|
||||
FAILED: 'FAILED' as const,
|
||||
TEMPORARY_FAILURE: 'TEMPORARY_FAILURE' as const
|
||||
}
|
||||
|
||||
export const enumCalendarChannelSyncStatus = {
|
||||
NOT_SYNCED: 'NOT_SYNCED' as const,
|
||||
ONGOING: 'ONGOING' as const,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -40,6 +40,7 @@ export default defineField({
|
||||
- When defining fields **inline inside `defineObject()`**, you do **not** need `objectUniversalIdentifier` — it's inherited from the parent object.
|
||||
- `defineField()` is the only way to add fields to objects you didn't create with `defineObject()`.
|
||||
- File location is up to you. The convention is `src/fields/<name>.field.ts`, but the SDK detects fields anywhere in `src/`.
|
||||
- To add a tab to a standard page layout (e.g. the Task or Company detail page), use [`definePageLayoutTab`](/developers/extend/apps/layout/page-layouts#definepagelayouttab) with `STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS` from `twenty-sdk/define`.
|
||||
|
||||
## Adding a relation to an existing object
|
||||
|
||||
|
||||
@@ -103,6 +103,10 @@ export default defineCommandMenuItem({
|
||||
});
|
||||
```
|
||||
|
||||
<Note>
|
||||
`RECORD_SELECTION` already implies a non-empty selection — use `numberOfSelectedRecords` only for specific counts (e.g. `>= 2`).
|
||||
</Note>
|
||||
|
||||
### Context variables
|
||||
|
||||
These represent the current state of the page:
|
||||
|
||||
@@ -196,6 +196,94 @@ export default defineFrontComponent({
|
||||
});
|
||||
```
|
||||
|
||||
## Calling a logic function
|
||||
|
||||
Front components run browser-side in a sandboxed Web Worker, while [logic functions](/developers/extend/apps/logic/logic-functions) run server-side. There is no direct in-process call between the two — instead, a front component reaches a logic function over HTTP.
|
||||
|
||||
A logic function declared with `httpRouteTriggerSettings` is exposed under the `/s/` endpoint at `${TWENTY_API_URL}/s<path>`. Your front component calls that route with `fetch`, authenticating with the `TWENTY_APP_ACCESS_TOKEN` that Twenty injects into the worker.
|
||||
|
||||
A small reusable helper keeps the call sites clean:
|
||||
|
||||
```ts src/shared/call-app-route.ts
|
||||
export async function callAppRoute(
|
||||
path: string,
|
||||
body: Record<string, unknown>,
|
||||
): Promise<unknown> {
|
||||
const apiUrl = process.env.TWENTY_API_URL ?? '';
|
||||
const token = process.env.TWENTY_APP_ACCESS_TOKEN;
|
||||
|
||||
const res = await fetch(`${apiUrl}/s${path}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error(`Logic function failed (${res.status})`);
|
||||
}
|
||||
|
||||
return res.json();
|
||||
}
|
||||
```
|
||||
|
||||
A headless front component can run the call on mount via the `Command` component, then unmount automatically:
|
||||
|
||||
```tsx src/front-components/sync-prs.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk/define';
|
||||
import { Command } from 'twenty-sdk/command';
|
||||
import { callAppRoute } from 'src/shared/call-app-route';
|
||||
|
||||
const SyncPrs = () => {
|
||||
const execute = async () => {
|
||||
await callAppRoute('/github/fetch-prs', {
|
||||
owner: 'twentyhq',
|
||||
repo: 'twenty',
|
||||
});
|
||||
};
|
||||
|
||||
return <Command execute={execute} />;
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: '...',
|
||||
name: 'sync-prs',
|
||||
description: 'Triggers the fetch-prs logic function',
|
||||
isHeadless: true,
|
||||
component: SyncPrs,
|
||||
});
|
||||
```
|
||||
|
||||
The `path` passed to `callAppRoute` must match the logic function's `httpRouteTriggerSettings.path` (the `/s` prefix is added by the helper):
|
||||
|
||||
```ts src/logic-functions/fetch-prs.logic-function.ts
|
||||
import { defineLogicFunction } from 'twenty-sdk/define';
|
||||
import type { RoutePayload } from 'twenty-sdk/logic-function';
|
||||
|
||||
const handler = async (event: RoutePayload) => {
|
||||
const { owner, repo } = (event.body ?? {}) as { owner: string; repo: string };
|
||||
// ...fetch from GitHub and persist records...
|
||||
return { ok: true };
|
||||
};
|
||||
|
||||
export default defineLogicFunction({
|
||||
universalIdentifier: '...',
|
||||
name: 'fetch-prs',
|
||||
handler,
|
||||
httpRouteTriggerSettings: {
|
||||
path: '/github/fetch-prs',
|
||||
httpMethod: 'POST',
|
||||
isAuthRequired: true,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
<Note>
|
||||
`TWENTY_API_URL` and `TWENTY_APP_ACCESS_TOKEN` are injected automatically — see [Application variables](#application-variables). Because secret application variables are never exposed to front components, keep API keys and other sensitive logic in the logic function, not in the front component.
|
||||
</Note>
|
||||
|
||||
## Accessing runtime context
|
||||
|
||||
Inside your component, use SDK hooks to access the current user, record, and component instance:
|
||||
|
||||
@@ -65,16 +65,15 @@ Use this when you only want to **add** a tab to an existing layout — for examp
|
||||
import {
|
||||
definePageLayoutTab,
|
||||
PageLayoutTabLayoutMode,
|
||||
STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS,
|
||||
} from 'twenty-sdk/define';
|
||||
import { HELLO_WORLD_FRONT_COMPONENT_UNIVERSAL_IDENTIFIER } from '../front-components/hello-world';
|
||||
|
||||
const COMPANY_RECORD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIER =
|
||||
'20202020-ab01-4001-8001-c0aba11c0100';
|
||||
|
||||
export default definePageLayoutTab({
|
||||
universalIdentifier: 'b1b2b3b4-b5b6-4000-8000-000000000001',
|
||||
pageLayoutUniversalIdentifier:
|
||||
COMPANY_RECORD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIER,
|
||||
STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.companyRecordPage
|
||||
.universalIdentifier,
|
||||
title: 'Hello World',
|
||||
position: 1000,
|
||||
icon: 'IconWorld',
|
||||
@@ -97,6 +96,34 @@ export default definePageLayoutTab({
|
||||
### Key points
|
||||
|
||||
- `pageLayoutUniversalIdentifier` is **required** and must point to a page layout that already exists at install time — either a standard Twenty layout or one defined by your own app. Cross-app references to layouts owned by another installed app are not supported today. When the parent layout is missing, installation fails with a clear validation error.
|
||||
- For standard Twenty layouts, import identifiers from `twenty-sdk/define`:
|
||||
|
||||
```ts
|
||||
import { STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS } from 'twenty-sdk/define';
|
||||
|
||||
// STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.companyRecordPage.universalIdentifier
|
||||
// STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.personRecordPage.universalIdentifier
|
||||
// STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.taskRecordPage.universalIdentifier
|
||||
// STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.opportunityRecordPage.universalIdentifier
|
||||
// STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.noteRecordPage.universalIdentifier
|
||||
// …
|
||||
```
|
||||
|
||||
Each layout entry also exposes its `tabs` and their `widgets`, so you can reference any level:
|
||||
|
||||
```ts
|
||||
STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.taskRecordPage.tabs.home.universalIdentifier
|
||||
STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.taskRecordPage.tabs.home.widgets.fields.universalIdentifier
|
||||
```
|
||||
|
||||
A short alias `STANDARD_PAGE_LAYOUT` is also available:
|
||||
|
||||
```ts
|
||||
import { STANDARD_PAGE_LAYOUT } from 'twenty-sdk/define';
|
||||
|
||||
STANDARD_PAGE_LAYOUT.companyRecordPage.universalIdentifier;
|
||||
```
|
||||
|
||||
- `widgets` are scoped to this tab only — they reference [front components](/developers/extend/apps/layout/front-components), views, etc. exactly like widgets defined inline in `definePageLayout`.
|
||||
- `position` controls ordering against existing tabs on the targeted layout. Pick a value that places your tab where you want it relative to built-in tabs.
|
||||
- Use this instead of `definePageLayout` when you only want to add to an existing layout. Use `definePageLayout` when you own the entire layout.
|
||||
|
||||
@@ -53,6 +53,10 @@ export default defineLogicFunction({
|
||||
Available trigger types:
|
||||
- **httpRoute**: Exposes your function on an HTTP path and method **under the `/s/` endpoint**:
|
||||
> e.g. `path: '/post-card/create'` is callable at `https://your-twenty-server.com/s/post-card/create`
|
||||
|
||||
<Note>
|
||||
To invoke a route-triggered logic function from a (headless) front component, see [Calling a logic function](/developers/extend/apps/layout/front-components#calling-a-logic-function).
|
||||
</Note>
|
||||
- **cron**: Runs your function on a schedule using a CRON expression.
|
||||
- **databaseEvent**: Runs on workspace object lifecycle events. When the event operation is `updated`, specific fields to listen to can be specified in the `updatedFields` array. If left undefined or empty, any update will trigger the function.
|
||||
> e.g. `person.updated`, `*.created`, `company.*`
|
||||
|
||||
@@ -43,6 +43,8 @@ export default defineField({
|
||||
|
||||
* Der Speicherort der Datei liegt bei Ihnen. Die Konvention ist `src/fields/\<name>.field.ts`, aber das SDK erkennt Felder überall in `src/`.
|
||||
|
||||
* Um eine Registerkarte zu einem Standard-Seitenlayout hinzuzufügen (z. B. der Aufgaben- oder Unternehmensdetailseite), verwenden Sie [`definePageLayoutTab`](/l/de/developers/extend/apps/layout/page-layouts#definepagelayouttab) mit `STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS` aus `twenty-sdk/define`.
|
||||
|
||||
## Hinzufügen einer Relation zu einem bestehenden Objekt
|
||||
|
||||
Um ein Relationsfeld hinzuzufügen (z. B. zur Verknüpfung Ihres benutzerdefinierten Objekts mit einer Standard-`Person`), verwenden Sie `defineField()` mit `FieldType.RELATION`. Das Muster ist dasselbe wie bei Inline-Relationen, jedoch mit explizit gesetztem `objectUniversalIdentifier`. Siehe [Relations](/l/de/developers/extend/apps/data/relations) für das bidirektionale Muster.
|
||||
|
||||
@@ -103,6 +103,10 @@ export default defineCommandMenuItem({
|
||||
});
|
||||
```
|
||||
|
||||
<Note>
|
||||
`RECORD_SELECTION` impliziert bereits eine nichtleere Auswahl — verwende `numberOfSelectedRecords` nur für bestimmte Zählwerte (z. B. `>= 2`).
|
||||
</Note>
|
||||
|
||||
### Kontextvariablen
|
||||
|
||||
Diese repräsentieren den aktuellen Zustand der Seite:
|
||||
|
||||
@@ -196,6 +196,94 @@ export default defineFrontComponent({
|
||||
});
|
||||
```
|
||||
|
||||
## Aufrufen einer Logikfunktion
|
||||
|
||||
Front-Komponenten laufen browserseitig in einem isolierten Web Worker, während [Logikfunktionen](/l/de/developers/extend/apps/logic/logic-functions) serverseitig ausgeführt werden. Es gibt keinen direkten In-Process-Aufruf zwischen beiden – stattdessen ruft eine Front-Komponente eine Logikfunktion über HTTP auf.
|
||||
|
||||
Eine mit `httpRouteTriggerSettings` deklarierte Logikfunktion wird unter dem `/s/`-Endpunkt unter `${TWENTY_API_URL}/s\<path>` bereitgestellt. Ihre Front-Komponente ruft diese Route mit `fetch` auf und authentifiziert sich dabei mit dem `TWENTY_APP_ACCESS_TOKEN`, das Twenty in den Worker injiziert.
|
||||
|
||||
Ein kleiner wiederverwendbarer Helper hält die Aufrufstellen übersichtlich:
|
||||
|
||||
```ts src/shared/call-app-route.ts
|
||||
export async function callAppRoute(
|
||||
path: string,
|
||||
body: Record<string, unknown>,
|
||||
): Promise<unknown> {
|
||||
const apiUrl = process.env.TWENTY_API_URL ?? '';
|
||||
const token = process.env.TWENTY_APP_ACCESS_TOKEN;
|
||||
|
||||
const res = await fetch(`${apiUrl}/s${path}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error(`Logic function failed (${res.status})`);
|
||||
}
|
||||
|
||||
return res.json();
|
||||
}
|
||||
```
|
||||
|
||||
Eine headless Front-Komponente kann den Aufruf beim Mounten über die `Command`-Komponente ausführen und sich anschließend automatisch unmounten:
|
||||
|
||||
```tsx src/front-components/sync-prs.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk/define';
|
||||
import { Command } from 'twenty-sdk/command';
|
||||
import { callAppRoute } from 'src/shared/call-app-route';
|
||||
|
||||
const SyncPrs = () => {
|
||||
const execute = async () => {
|
||||
await callAppRoute('/github/fetch-prs', {
|
||||
owner: 'twentyhq',
|
||||
repo: 'twenty',
|
||||
});
|
||||
};
|
||||
|
||||
return <Command execute={execute} />;
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: '...',
|
||||
name: 'sync-prs',
|
||||
description: 'Triggers the fetch-prs logic function',
|
||||
isHeadless: true,
|
||||
component: SyncPrs,
|
||||
});
|
||||
```
|
||||
|
||||
Der an `callAppRoute` übergebene `path` muss dem `httpRouteTriggerSettings.path` der Logikfunktion entsprechen (das `/s`-Präfix wird vom Helper hinzugefügt):
|
||||
|
||||
```ts src/logic-functions/fetch-prs.logic-function.ts
|
||||
import { defineLogicFunction } from 'twenty-sdk/define';
|
||||
import type { RoutePayload } from 'twenty-sdk/logic-function';
|
||||
|
||||
const handler = async (event: RoutePayload) => {
|
||||
const { owner, repo } = (event.body ?? {}) as { owner: string; repo: string };
|
||||
// ...fetch from GitHub and persist records...
|
||||
return { ok: true };
|
||||
};
|
||||
|
||||
export default defineLogicFunction({
|
||||
universalIdentifier: '...',
|
||||
name: 'fetch-prs',
|
||||
handler,
|
||||
httpRouteTriggerSettings: {
|
||||
path: '/github/fetch-prs',
|
||||
httpMethod: 'POST',
|
||||
isAuthRequired: true,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
<Note>
|
||||
`TWENTY_API_URL` und `TWENTY_APP_ACCESS_TOKEN` werden automatisch injiziert – siehe [Anwendungsvariablen](#application-variables). Da geheime Anwendungsvariablen niemals in Front-Komponenten offengelegt werden, sollten API-Schlüssel und andere sensible Logik in der Logikfunktion verbleiben und nicht in der Front-Komponente.
|
||||
</Note>
|
||||
|
||||
## Zugriff auf den Laufzeitkontext
|
||||
|
||||
Verwenden Sie innerhalb Ihrer Komponente SDK-Hooks, um auf den aktuellen Benutzer, den Datensatz und die Komponenteninstanz zuzugreifen:
|
||||
|
||||
@@ -65,16 +65,15 @@ Verwenden Sie dies, wenn Sie nur einen Tab zu einem vorhandenen Layout **hinzuf
|
||||
import {
|
||||
definePageLayoutTab,
|
||||
PageLayoutTabLayoutMode,
|
||||
STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS,
|
||||
} from 'twenty-sdk/define';
|
||||
import { HELLO_WORLD_FRONT_COMPONENT_UNIVERSAL_IDENTIFIER } from '../front-components/hello-world';
|
||||
|
||||
const COMPANY_RECORD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIER =
|
||||
'20202020-ab01-4001-8001-c0aba11c0100';
|
||||
|
||||
export default definePageLayoutTab({
|
||||
universalIdentifier: 'b1b2b3b4-b5b6-4000-8000-000000000001',
|
||||
pageLayoutUniversalIdentifier:
|
||||
COMPANY_RECORD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIER,
|
||||
STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.companyRecordPage
|
||||
.universalIdentifier,
|
||||
title: 'Hello World',
|
||||
position: 1000,
|
||||
icon: 'IconWorld',
|
||||
@@ -97,6 +96,37 @@ export default definePageLayoutTab({
|
||||
### Hauptpunkte
|
||||
|
||||
* `pageLayoutUniversalIdentifier` ist **erforderlich** und muss auf ein Seitenlayout verweisen, das zum Installationszeitpunkt bereits existiert – entweder ein standardmäßiges Twenty-Layout oder eines, das von Ihrer eigenen App definiert wurde. App-übergreifende Verweise auf Layouts, die einer anderen installierten App gehören, werden derzeit nicht unterstützt. Wenn das übergeordnete Layout fehlt, schlägt die Installation mit einem eindeutigen Validierungsfehler fehl.
|
||||
|
||||
* Für Standard-Twenty-Layouts importieren Sie die Bezeichner aus `twenty-sdk/define`:
|
||||
|
||||
```ts
|
||||
import { STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS } from 'twenty-sdk/define';
|
||||
|
||||
// STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.companyRecordPage.universalIdentifier
|
||||
// STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.personRecordPage.universalIdentifier
|
||||
// STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.taskRecordPage.universalIdentifier
|
||||
// STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.opportunityRecordPage.universalIdentifier
|
||||
// STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.noteRecordPage.universalIdentifier
|
||||
// …
|
||||
```
|
||||
|
||||
Jeder Layout-Eintrag stellt außerdem seine `tabs` und deren `widgets` zur Verfügung, sodass Sie auf jede Ebene verweisen können:
|
||||
|
||||
```ts
|
||||
STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.taskRecordPage.tabs.home.universalIdentifier
|
||||
STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.taskRecordPage.tabs.home.widgets.fields.universalIdentifier
|
||||
```
|
||||
|
||||
Eine kurze Alias-Variable `STANDARD_PAGE_LAYOUT` ist ebenfalls verfügbar:
|
||||
|
||||
```ts
|
||||
import { STANDARD_PAGE_LAYOUT } from 'twenty-sdk/define';
|
||||
|
||||
STANDARD_PAGE_LAYOUT.companyRecordPage.universalIdentifier;
|
||||
```
|
||||
|
||||
* `widgets` sind ausschließlich auf diesen Tab beschränkt – sie verweisen auf [Frontend-Komponenten](/l/de/developers/extend/apps/layout/front-components), Ansichten usw., genau wie Widgets, die inline in `definePageLayout` definiert sind.
|
||||
|
||||
* `position` steuert die Reihenfolge im Zielseitenlayout relativ zu den vorhandenen Registerkarten. Wählen Sie einen Wert, der Ihre Registerkarte relativ zu integrierten Registerkarten an die gewünschte Position bringt.
|
||||
|
||||
* Verwenden Sie dies anstelle von `definePageLayout`, wenn Sie einem vorhandenen Layout nur etwas hinzufügen möchten. Verwenden Sie `definePageLayout`, wenn Sie das gesamte Layout besitzen.
|
||||
|
||||
@@ -53,6 +53,10 @@ export default defineLogicFunction({
|
||||
Verfügbare Trigger-Typen:
|
||||
* **httpRoute**: Stellt Ihre Funktion unter einem HTTP-Pfad und einer Methode **unter dem Endpunkt `/s/`** bereit:
|
||||
> z. B. `path: '/post-card/create'` ist unter `https://your-twenty-server.com/s/post-card/create` aufrufbar
|
||||
|
||||
<Note>
|
||||
Um eine routenausgelöste Logikfunktion von einer (headless) Front-Komponente aus aufzurufen, siehe [Aufrufen einer Logikfunktion](/l/de/developers/extend/apps/layout/front-components#calling-a-logic-function).
|
||||
</Note>
|
||||
* **cron**: Führt Ihre Funktion nach Zeitplan mithilfe eines CRON-Ausdrucks aus.
|
||||
* **databaseEvent**: Wird bei Lebenszyklusereignissen von Workspace-Objekten ausgeführt. Wenn die Ereignisoperation `updated` ist, können bestimmte zu überwachende Felder im Array `updatedFields` angegeben werden. Wenn das Array undefiniert oder leer ist, löst jede Aktualisierung die Funktion aus.
|
||||
> z. B. `person.updated`, `*.created`, `company.*`
|
||||
|
||||
@@ -43,6 +43,8 @@ export default defineField({
|
||||
|
||||
* A localização do arquivo fica a seu critério. A convenção é `src/fields/\<name>.field.ts`, mas o SDK detecta campos em qualquer lugar dentro de `src/`.
|
||||
|
||||
* Para adicionar uma aba a um layout de página padrão (por exemplo, a página de detalhes de Task ou Company), use [`definePageLayoutTab`](/l/pt/developers/extend/apps/layout/page-layouts#definepagelayouttab) com `STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS` de `twenty-sdk/define`.
|
||||
|
||||
## Adicionando uma relação a um objeto existente
|
||||
|
||||
Para adicionar um campo de relação (por exemplo, vinculando seu objeto personalizado a um `Person` padrão), use `defineField()` com `FieldType.RELATION`. O padrão é o mesmo que para relações inline, mas com `objectUniversalIdentifier` definido explicitamente. Veja [Relações](/l/pt/developers/extend/apps/data/relations) para o padrão bidirecional.
|
||||
|
||||
@@ -103,6 +103,10 @@ export default defineCommandMenuItem({
|
||||
});
|
||||
```
|
||||
|
||||
<Note>
|
||||
`RECORD_SELECTION` já implica uma seleção não vazia — use `numberOfSelectedRecords` apenas para contagens específicas (por exemplo, `>= 2`).
|
||||
</Note>
|
||||
|
||||
### Variáveis de contexto
|
||||
|
||||
Elas representam o estado atual da página:
|
||||
|
||||
@@ -196,6 +196,94 @@ export default defineFrontComponent({
|
||||
});
|
||||
```
|
||||
|
||||
## Chamando uma função lógica
|
||||
|
||||
Os componentes de front são executados no navegador em um Web Worker isolado, enquanto as [funções lógicas](/l/pt/developers/extend/apps/logic/logic-functions) são executadas no servidor. Não há chamada direta no mesmo processo entre os dois — em vez disso, um componente de front acessa uma função lógica via HTTP.
|
||||
|
||||
Uma função lógica declarada com `httpRouteTriggerSettings` é exposta sob o endpoint `/s/` em `${TWENTY_API_URL}/s\<path>`. Seu componente de front chama essa rota com `fetch`, autenticando com o `TWENTY_APP_ACCESS_TOKEN` que Twenty injeta no worker.
|
||||
|
||||
Um pequeno helper reutilizável mantém os locais de chamada limpos:
|
||||
|
||||
```ts src/shared/call-app-route.ts
|
||||
export async function callAppRoute(
|
||||
path: string,
|
||||
body: Record<string, unknown>,
|
||||
): Promise<unknown> {
|
||||
const apiUrl = process.env.TWENTY_API_URL ?? '';
|
||||
const token = process.env.TWENTY_APP_ACCESS_TOKEN;
|
||||
|
||||
const res = await fetch(`${apiUrl}/s${path}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error(`Logic function failed (${res.status})`);
|
||||
}
|
||||
|
||||
return res.json();
|
||||
}
|
||||
```
|
||||
|
||||
Um componente de front headless pode executar a chamada ao montar via o componente `Command` e, em seguida, desmontar automaticamente:
|
||||
|
||||
```tsx src/front-components/sync-prs.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk/define';
|
||||
import { Command } from 'twenty-sdk/command';
|
||||
import { callAppRoute } from 'src/shared/call-app-route';
|
||||
|
||||
const SyncPrs = () => {
|
||||
const execute = async () => {
|
||||
await callAppRoute('/github/fetch-prs', {
|
||||
owner: 'twentyhq',
|
||||
repo: 'twenty',
|
||||
});
|
||||
};
|
||||
|
||||
return <Command execute={execute} />;
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: '...',
|
||||
name: 'sync-prs',
|
||||
description: 'Triggers the fetch-prs logic function',
|
||||
isHeadless: true,
|
||||
component: SyncPrs,
|
||||
});
|
||||
```
|
||||
|
||||
O `path` passado para `callAppRoute` deve corresponder ao `httpRouteTriggerSettings.path` da função lógica (o prefixo `/s` é adicionado pelo helper):
|
||||
|
||||
```ts src/logic-functions/fetch-prs.logic-function.ts
|
||||
import { defineLogicFunction } from 'twenty-sdk/define';
|
||||
import type { RoutePayload } from 'twenty-sdk/logic-function';
|
||||
|
||||
const handler = async (event: RoutePayload) => {
|
||||
const { owner, repo } = (event.body ?? {}) as { owner: string; repo: string };
|
||||
// ...fetch from GitHub and persist records...
|
||||
return { ok: true };
|
||||
};
|
||||
|
||||
export default defineLogicFunction({
|
||||
universalIdentifier: '...',
|
||||
name: 'fetch-prs',
|
||||
handler,
|
||||
httpRouteTriggerSettings: {
|
||||
path: '/github/fetch-prs',
|
||||
httpMethod: 'POST',
|
||||
isAuthRequired: true,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
<Note>
|
||||
`TWENTY_API_URL` e `TWENTY_APP_ACCESS_TOKEN` são injetados automaticamente — consulte [Variáveis de aplicação](#application-variables). Como as variáveis de aplicação secretas nunca são expostas aos componentes de front, mantenha as chaves de API e outra lógica sensível na função lógica, não no componente de front.
|
||||
</Note>
|
||||
|
||||
## Acessando o contexto de execução
|
||||
|
||||
Dentro do seu componente, use hooks do SDK para acessar o usuário atual, o registro e a instância do componente:
|
||||
|
||||
@@ -65,16 +65,15 @@ Use isto quando você quiser apenas **adicionar** uma aba a um layout existente
|
||||
import {
|
||||
definePageLayoutTab,
|
||||
PageLayoutTabLayoutMode,
|
||||
STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS,
|
||||
} from 'twenty-sdk/define';
|
||||
import { HELLO_WORLD_FRONT_COMPONENT_UNIVERSAL_IDENTIFIER } from '../front-components/hello-world';
|
||||
|
||||
const COMPANY_RECORD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIER =
|
||||
'20202020-ab01-4001-8001-c0aba11c0100';
|
||||
|
||||
export default definePageLayoutTab({
|
||||
universalIdentifier: 'b1b2b3b4-b5b6-4000-8000-000000000001',
|
||||
pageLayoutUniversalIdentifier:
|
||||
COMPANY_RECORD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIER,
|
||||
STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.companyRecordPage
|
||||
.universalIdentifier,
|
||||
title: 'Hello World',
|
||||
position: 1000,
|
||||
icon: 'IconWorld',
|
||||
@@ -97,6 +96,37 @@ export default definePageLayoutTab({
|
||||
### Pontos-chave
|
||||
|
||||
* `pageLayoutUniversalIdentifier` é **obrigatório** e deve apontar para um layout de página que já exista no momento da instalação — seja um layout padrão da Twenty ou um definido pelo seu próprio aplicativo. Referências entre aplicativos para layouts pertencentes a outro aplicativo instalado não são compatíveis atualmente. Quando o layout pai estiver ausente, a instalação falha com um erro de validação claro.
|
||||
|
||||
* Para layouts padrão do Twenty, importe identificadores de `twenty-sdk/define`:
|
||||
|
||||
```ts
|
||||
import { STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS } from 'twenty-sdk/define';
|
||||
|
||||
// STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.companyRecordPage.universalIdentifier
|
||||
// STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.personRecordPage.universalIdentifier
|
||||
// STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.taskRecordPage.universalIdentifier
|
||||
// STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.opportunityRecordPage.universalIdentifier
|
||||
// STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.noteRecordPage.universalIdentifier
|
||||
// …
|
||||
```
|
||||
|
||||
Cada entrada de layout também expõe suas `tabs` e seus `widgets`, para que você possa fazer referência a qualquer nível:
|
||||
|
||||
```ts
|
||||
STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.taskRecordPage.tabs.home.universalIdentifier
|
||||
STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.taskRecordPage.tabs.home.widgets.fields.universalIdentifier
|
||||
```
|
||||
|
||||
Um alias abreviado `STANDARD_PAGE_LAYOUT` também está disponível:
|
||||
|
||||
```ts
|
||||
import { STANDARD_PAGE_LAYOUT } from 'twenty-sdk/define';
|
||||
|
||||
STANDARD_PAGE_LAYOUT.companyRecordPage.universalIdentifier;
|
||||
```
|
||||
|
||||
* `widgets` têm escopo apenas para esta aba — eles referenciam [front components](/l/pt/developers/extend/apps/layout/front-components), visualizações etc., exatamente como widgets definidos inline em `definePageLayout`.
|
||||
|
||||
* `position` controla a ordenação em relação às abas existentes no layout de destino. Escolha um valor que posicione sua aba onde você deseja em relação às abas nativas.
|
||||
|
||||
* Use isto em vez de `definePageLayout` quando você quiser apenas adicionar a um layout existente. Use `definePageLayout` quando você possuir todo o layout.
|
||||
|
||||
@@ -53,6 +53,10 @@ export default defineLogicFunction({
|
||||
Tipos de gatilho disponíveis:
|
||||
* **httpRoute**: Expõe sua função em um caminho e método HTTP **no endpoint `/s/`**:
|
||||
> por exemplo, `path: '/post-card/create'` é acessível em `https://your-twenty-server.com/s/post-card/create`
|
||||
|
||||
<Note>
|
||||
Para invocar uma função de lógica acionada por rota a partir de um componente de front-end (headless), consulte [Chamando uma função de lógica](/l/pt/developers/extend/apps/layout/front-components#calling-a-logic-function).
|
||||
</Note>
|
||||
* **cron**: Executa sua função em um agendamento usando uma expressão CRON.
|
||||
* **databaseEvent**: Executa em eventos do ciclo de vida de objetos do espaço de trabalho. Quando a operação do evento é `updated`, campos específicos a serem observados podem ser especificados no array `updatedFields`. Se deixar indefinido ou vazio, qualquer atualização acionará a função.
|
||||
> por exemplo, `person.updated`, `*.created`, `company.*`
|
||||
|
||||
@@ -43,6 +43,8 @@ export default defineField({
|
||||
|
||||
* Locația fișierului depinde de dumneavoastră. Convenția este `src/fields/\<name>.field.ts`, dar SDK-ul detectează câmpuri oriunde în `src/`.
|
||||
|
||||
* Pentru a adăuga o filă într-un layout standard de pagină (de ex. pagina de detalii pentru Task sau Company), folosește [`definePageLayoutTab`](/l/ro/developers/extend/apps/layout/page-layouts#definepagelayouttab) cu `STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS` din `twenty-sdk/define`.
|
||||
|
||||
## Adăugarea unei relații la un obiect existent
|
||||
|
||||
Pentru a adăuga un câmp de tip relație (de ex. pentru a lega obiectul personalizat de un `Person` standard), folosiți `defineField()` cu `FieldType.RELATION`. Modelul este același ca pentru relațiile inline, dar cu `objectUniversalIdentifier` setat explicit. Consultați [Relații](/l/ro/developers/extend/apps/data/relations) pentru modelul bidirecțional.
|
||||
|
||||
@@ -103,6 +103,10 @@ export default defineCommandMenuItem({
|
||||
});
|
||||
```
|
||||
|
||||
<Note>
|
||||
`RECORD_SELECTION` implică deja o selecție care nu este goală — folosește `numberOfSelectedRecords` doar pentru valori specifice (de ex. `>= 2`).
|
||||
</Note>
|
||||
|
||||
### Variabile de context
|
||||
|
||||
Acestea reprezintă starea curentă a paginii:
|
||||
|
||||
@@ -196,6 +196,94 @@ export default defineFrontComponent({
|
||||
});
|
||||
```
|
||||
|
||||
## Apelarea unei funcții logice
|
||||
|
||||
Componentele de front rulează în browser într-un Web Worker izolat, în timp ce [funcțiile logice](/l/ro/developers/extend/apps/logic/logic-functions) rulează pe server. Nu există un apel direct în același proces între cele două — în schimb, o componentă de front apelează o funcție logică prin HTTP.
|
||||
|
||||
O funcție logică declarată cu `httpRouteTriggerSettings` este expusă sub endpoint-ul `/s/` la `${TWENTY_API_URL}/s\<path>`. Componenta ta de front apelează acea rută cu `fetch`, autentificându-se cu `TWENTY_APP_ACCESS_TOKEN` pe care Twenty îl injectează în worker.
|
||||
|
||||
Un mic utilitar reutilizabil menține locurile de apel curate:
|
||||
|
||||
```ts src/shared/call-app-route.ts
|
||||
export async function callAppRoute(
|
||||
path: string,
|
||||
body: Record<string, unknown>,
|
||||
): Promise<unknown> {
|
||||
const apiUrl = process.env.TWENTY_API_URL ?? '';
|
||||
const token = process.env.TWENTY_APP_ACCESS_TOKEN;
|
||||
|
||||
const res = await fetch(`${apiUrl}/s${path}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error(`Logic function failed (${res.status})`);
|
||||
}
|
||||
|
||||
return res.json();
|
||||
}
|
||||
```
|
||||
|
||||
O componentă de front headless poate efectua apelul la montare prin componenta `Command`, apoi se demontează automat:
|
||||
|
||||
```tsx src/front-components/sync-prs.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk/define';
|
||||
import { Command } from 'twenty-sdk/command';
|
||||
import { callAppRoute } from 'src/shared/call-app-route';
|
||||
|
||||
const SyncPrs = () => {
|
||||
const execute = async () => {
|
||||
await callAppRoute('/github/fetch-prs', {
|
||||
owner: 'twentyhq',
|
||||
repo: 'twenty',
|
||||
});
|
||||
};
|
||||
|
||||
return <Command execute={execute} />;
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: '...',
|
||||
name: 'sync-prs',
|
||||
description: 'Triggers the fetch-prs logic function',
|
||||
isHeadless: true,
|
||||
component: SyncPrs,
|
||||
});
|
||||
```
|
||||
|
||||
`path` transmis către `callAppRoute` trebuie să corespundă cu `httpRouteTriggerSettings.path` al funcției logice (prefixul `/s` este adăugat de utilitar):
|
||||
|
||||
```ts src/logic-functions/fetch-prs.logic-function.ts
|
||||
import { defineLogicFunction } from 'twenty-sdk/define';
|
||||
import type { RoutePayload } from 'twenty-sdk/logic-function';
|
||||
|
||||
const handler = async (event: RoutePayload) => {
|
||||
const { owner, repo } = (event.body ?? {}) as { owner: string; repo: string };
|
||||
// ...fetch from GitHub and persist records...
|
||||
return { ok: true };
|
||||
};
|
||||
|
||||
export default defineLogicFunction({
|
||||
universalIdentifier: '...',
|
||||
name: 'fetch-prs',
|
||||
handler,
|
||||
httpRouteTriggerSettings: {
|
||||
path: '/github/fetch-prs',
|
||||
httpMethod: 'POST',
|
||||
isAuthRequired: true,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
<Note>
|
||||
`TWENTY_API_URL` și `TWENTY_APP_ACCESS_TOKEN` sunt injectate automat — vezi [Application variables](#application-variables). Deoarece variabilele de aplicație secrete nu sunt niciodată expuse componentelor de front, păstrează cheile API și altă logică sensibilă în funcția logică, nu în componenta de front.
|
||||
</Note>
|
||||
|
||||
## Accesarea contextului de rulare
|
||||
|
||||
În interiorul componentei, folosiți hook-urile SDK pentru a accesa utilizatorul curent, înregistrarea curentă și instanța componentei:
|
||||
|
||||
@@ -65,16 +65,15 @@ Folosește aceasta atunci când vrei doar să **adaugi** o filă la un layout ex
|
||||
import {
|
||||
definePageLayoutTab,
|
||||
PageLayoutTabLayoutMode,
|
||||
STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS,
|
||||
} from 'twenty-sdk/define';
|
||||
import { HELLO_WORLD_FRONT_COMPONENT_UNIVERSAL_IDENTIFIER } from '../front-components/hello-world';
|
||||
|
||||
const COMPANY_RECORD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIER =
|
||||
'20202020-ab01-4001-8001-c0aba11c0100';
|
||||
|
||||
export default definePageLayoutTab({
|
||||
universalIdentifier: 'b1b2b3b4-b5b6-4000-8000-000000000001',
|
||||
pageLayoutUniversalIdentifier:
|
||||
COMPANY_RECORD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIER,
|
||||
STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.companyRecordPage
|
||||
.universalIdentifier,
|
||||
title: 'Hello World',
|
||||
position: 1000,
|
||||
icon: 'IconWorld',
|
||||
@@ -97,6 +96,37 @@ export default definePageLayoutTab({
|
||||
### Puncte cheie
|
||||
|
||||
* `pageLayoutUniversalIdentifier` este **obligatoriu** și trebuie să indice către un layout de pagină care există deja la momentul instalării — fie un layout standard Twenty, fie unul definit de propria ta aplicație. Referințele cross-app către layouturi deținute de o altă aplicație instalată nu sunt acceptate în prezent. Când lipsește layoutul părinte, instalarea eșuează cu o eroare clară de validare.
|
||||
|
||||
* Pentru layout-urile standard Twenty, importați identificatorii din `twenty-sdk/define`:
|
||||
|
||||
```ts
|
||||
import { STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS } from 'twenty-sdk/define';
|
||||
|
||||
// STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.companyRecordPage.universalIdentifier
|
||||
// STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.personRecordPage.universalIdentifier
|
||||
// STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.taskRecordPage.universalIdentifier
|
||||
// STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.opportunityRecordPage.universalIdentifier
|
||||
// STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.noteRecordPage.universalIdentifier
|
||||
// …
|
||||
```
|
||||
|
||||
Fiecare intrare de layout își expune, de asemenea, `tabs` și `widgets`, astfel încât puteți face referire la orice nivel:
|
||||
|
||||
```ts
|
||||
STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.taskRecordPage.tabs.home.universalIdentifier
|
||||
STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.taskRecordPage.tabs.home.widgets.fields.universalIdentifier
|
||||
```
|
||||
|
||||
Este disponibil și un alias scurt `STANDARD_PAGE_LAYOUT`:
|
||||
|
||||
```ts
|
||||
import { STANDARD_PAGE_LAYOUT } from 'twenty-sdk/define';
|
||||
|
||||
STANDARD_PAGE_LAYOUT.companyRecordPage.universalIdentifier;
|
||||
```
|
||||
|
||||
* `widgets` sunt limitate doar la această filă — fac referire la [front components](/l/ro/developers/extend/apps/layout/front-components), vizualizări etc., exact ca widgeturile definite inline în `definePageLayout`.
|
||||
|
||||
* `position` controlează ordonarea în raport cu filele existente din layoutul țintă. Alege o valoare care să plaseze fila ta acolo unde dorești, relativ la filele predefinite.
|
||||
|
||||
* Folosește aceasta în loc de `definePageLayout` atunci când vrei doar să adaugi la un layout existent. Folosește `definePageLayout` atunci când deții întregul layout.
|
||||
|
||||
@@ -53,6 +53,10 @@ export default defineLogicFunction({
|
||||
Tipuri de declanșatoare disponibile:
|
||||
* **httpRoute**: Expune funcția pe o cale și metodă HTTP **sub endpoint-ul `/s/`**:
|
||||
> de ex. `path: '/post-card/create'` este apelabil la `https://your-twenty-server.com/s/post-card/create`
|
||||
|
||||
<Note>
|
||||
Pentru a apela o funcție logică declanșată de o rută dintr-o componentă front-end (headless), consultă [Apelarea unei funcții logice](/l/ro/developers/extend/apps/layout/front-components#calling-a-logic-function).
|
||||
</Note>
|
||||
* **cron**: Rulează funcția pe un program folosind o expresie CRON.
|
||||
* **databaseEvent**: Rulează la evenimentele ciclului de viață ale obiectelor din spațiul de lucru. Când operațiunea evenimentului este `updated`, câmpurile specifice de urmărit pot fi specificate în array-ul `updatedFields`. Dacă este lăsat nedefinit sau gol, orice actualizare va declanșa funcția.
|
||||
> de ex. `person.updated`, `*.created`, `company.*`
|
||||
|
||||
@@ -43,6 +43,8 @@ export default defineField({
|
||||
|
||||
* Расположение файла зависит от вас. Принятое соглашение — `src/fields/\<name>.field.ts`, но SDK обнаруживает поля в любом месте внутри `src/`.
|
||||
|
||||
* Чтобы добавить вкладку в стандартную компоновку страницы (например, на страницу сведений о задаче или компании), используйте [`definePageLayoutTab`](/l/ru/developers/extend/apps/layout/page-layouts#definepagelayouttab) с `STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS` из `twenty-sdk/define`.
|
||||
|
||||
## Добавление связи к существующему объекту
|
||||
|
||||
Чтобы добавить поле связи (например, связать ваш пользовательский объект со стандартным `Person`), используйте `defineField()` с `FieldType.RELATION`. Шаблон тот же, что и для встроенных связей, но с явным указанием `objectUniversalIdentifier`. Смотрите раздел [Relations](/l/ru/developers/extend/apps/data/relations) для двунаправленного шаблона.
|
||||
|
||||
@@ -103,6 +103,10 @@ export default defineCommandMenuItem({
|
||||
});
|
||||
```
|
||||
|
||||
<Note>
|
||||
`RECORD_SELECTION` уже подразумевает, что есть выбранные записи — используйте `numberOfSelectedRecords` только для конкретных количеств (например, `>= 2`).
|
||||
</Note>
|
||||
|
||||
### Переменные контекста
|
||||
|
||||
Они представляют текущее состояние страницы:
|
||||
|
||||
@@ -196,6 +196,94 @@ export default defineFrontComponent({
|
||||
});
|
||||
```
|
||||
|
||||
## Вызов логической функции
|
||||
|
||||
Front-компоненты выполняются в браузере в изолированном Web Worker, в то время как [логические функции](/l/ru/developers/extend/apps/logic/logic-functions) выполняются на стороне сервера. Между ними нет прямого внутрипроцессного вызова — вместо этого front-компонент обращается к логической функции по HTTP.
|
||||
|
||||
Логическая функция, объявленная с `httpRouteTriggerSettings`, доступна по эндпоинту `/s/` по адресу `${TWENTY_API_URL}/s\<path>`. Ваш front-компонент вызывает этот маршрут с помощью `fetch`, аутентифицируясь с использованием `TWENTY_APP_ACCESS_TOKEN`, который Twenty внедряет в worker.
|
||||
|
||||
Небольшой переиспользуемый хелпер делает места вызова чище:
|
||||
|
||||
```ts src/shared/call-app-route.ts
|
||||
export async function callAppRoute(
|
||||
path: string,
|
||||
body: Record<string, unknown>,
|
||||
): Promise<unknown> {
|
||||
const apiUrl = process.env.TWENTY_API_URL ?? '';
|
||||
const token = process.env.TWENTY_APP_ACCESS_TOKEN;
|
||||
|
||||
const res = await fetch(`${apiUrl}/s${path}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error(`Logic function failed (${res.status})`);
|
||||
}
|
||||
|
||||
return res.json();
|
||||
}
|
||||
```
|
||||
|
||||
Безголовый front-компонент может выполнить вызов при монтировании через компонент `Command`, а затем автоматически размонтироваться:
|
||||
|
||||
```tsx src/front-components/sync-prs.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk/define';
|
||||
import { Command } from 'twenty-sdk/command';
|
||||
import { callAppRoute } from 'src/shared/call-app-route';
|
||||
|
||||
const SyncPrs = () => {
|
||||
const execute = async () => {
|
||||
await callAppRoute('/github/fetch-prs', {
|
||||
owner: 'twentyhq',
|
||||
repo: 'twenty',
|
||||
});
|
||||
};
|
||||
|
||||
return <Command execute={execute} />;
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: '...',
|
||||
name: 'sync-prs',
|
||||
description: 'Triggers the fetch-prs logic function',
|
||||
isHeadless: true,
|
||||
component: SyncPrs,
|
||||
});
|
||||
```
|
||||
|
||||
`path`, переданный в `callAppRoute`, должен совпадать с `httpRouteTriggerSettings.path` логической функции (префикс `/s` добавляется хелпером):
|
||||
|
||||
```ts src/logic-functions/fetch-prs.logic-function.ts
|
||||
import { defineLogicFunction } from 'twenty-sdk/define';
|
||||
import type { RoutePayload } from 'twenty-sdk/logic-function';
|
||||
|
||||
const handler = async (event: RoutePayload) => {
|
||||
const { owner, repo } = (event.body ?? {}) as { owner: string; repo: string };
|
||||
// ...fetch from GitHub and persist records...
|
||||
return { ok: true };
|
||||
};
|
||||
|
||||
export default defineLogicFunction({
|
||||
universalIdentifier: '...',
|
||||
name: 'fetch-prs',
|
||||
handler,
|
||||
httpRouteTriggerSettings: {
|
||||
path: '/github/fetch-prs',
|
||||
httpMethod: 'POST',
|
||||
isAuthRequired: true,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
<Note>
|
||||
`TWENTY_API_URL` и `TWENTY_APP_ACCESS_TOKEN` внедряются автоматически — см. [переменные приложения](#application-variables). Поскольку секретные переменные приложения никогда не раскрываются front-компонентам, храните ключи API и другую конфиденциальную логику в логической функции, а не во front-компоненте.
|
||||
</Note>
|
||||
|
||||
## Доступ к контексту времени выполнения
|
||||
|
||||
Внутри вашего компонента используйте хуки SDK для доступа к текущему пользователю, записи и экземпляру компонента:
|
||||
|
||||
@@ -65,16 +65,15 @@ export default definePageLayout({
|
||||
import {
|
||||
definePageLayoutTab,
|
||||
PageLayoutTabLayoutMode,
|
||||
STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS,
|
||||
} from 'twenty-sdk/define';
|
||||
import { HELLO_WORLD_FRONT_COMPONENT_UNIVERSAL_IDENTIFIER } from '../front-components/hello-world';
|
||||
|
||||
const COMPANY_RECORD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIER =
|
||||
'20202020-ab01-4001-8001-c0aba11c0100';
|
||||
|
||||
export default definePageLayoutTab({
|
||||
universalIdentifier: 'b1b2b3b4-b5b6-4000-8000-000000000001',
|
||||
pageLayoutUniversalIdentifier:
|
||||
COMPANY_RECORD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIER,
|
||||
STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.companyRecordPage
|
||||
.universalIdentifier,
|
||||
title: 'Hello World',
|
||||
position: 1000,
|
||||
icon: 'IconWorld',
|
||||
@@ -97,6 +96,37 @@ export default definePageLayoutTab({
|
||||
### Основные моменты
|
||||
|
||||
* `pageLayoutUniversalIdentifier` является **обязательным** и должен указывать на макет страницы, который уже существует на момент установки — либо стандартный макет Twenty, либо определённый вашим собственным приложением. Кросс-приложенческие ссылки на макеты, которыми владеет другое установленное приложение, на данный момент не поддерживаются. Если родительский макет отсутствует, установка завершается с понятной ошибкой проверки.
|
||||
|
||||
* Для стандартных макетов Twenty импортируйте идентификаторы из `twenty-sdk/define`:
|
||||
|
||||
```ts
|
||||
import { STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS } from 'twenty-sdk/define';
|
||||
|
||||
// STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.companyRecordPage.universalIdentifier
|
||||
// STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.personRecordPage.universalIdentifier
|
||||
// STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.taskRecordPage.universalIdentifier
|
||||
// STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.opportunityRecordPage.universalIdentifier
|
||||
// STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.noteRecordPage.universalIdentifier
|
||||
// …
|
||||
```
|
||||
|
||||
Каждый элемент макета также предоставляет свои `tabs` и их `widgets`, поэтому вы можете ссылаться на любой уровень:
|
||||
|
||||
```ts
|
||||
STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.taskRecordPage.tabs.home.universalIdentifier
|
||||
STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.taskRecordPage.tabs.home.widgets.fields.universalIdentifier
|
||||
```
|
||||
|
||||
Также доступен короткий псевдоним `STANDARD_PAGE_LAYOUT`:
|
||||
|
||||
```ts
|
||||
import { STANDARD_PAGE_LAYOUT } from 'twenty-sdk/define';
|
||||
|
||||
STANDARD_PAGE_LAYOUT.companyRecordPage.universalIdentifier;
|
||||
```
|
||||
|
||||
* `widgets` ограничены только этой вкладкой — они ссылаются на [front components](/l/ru/developers/extend/apps/layout/front-components), представления и т. п. точно так же, как виджеты, определённые непосредственно в `definePageLayout`.
|
||||
|
||||
* `position` управляет порядком относительно существующих вкладок в целевом макете. Выберите значение, которое поместит вашу вкладку в нужное место относительно встроенных вкладок.
|
||||
|
||||
* Используйте это вместо `definePageLayout`, когда вы хотите только добавить к существующему макету. Используйте `definePageLayout`, когда вы управляете всем макетом.
|
||||
|
||||
@@ -53,6 +53,10 @@ export default defineLogicFunction({
|
||||
Доступные типы триггеров:
|
||||
* **httpRoute**: Публикует вашу функцию по HTTP-пути и методу **под конечной точкой `/s/`**:
|
||||
> например, `path: '/post-card/create'` вызывается по адресу `https://your-twenty-server.com/s/post-card/create`
|
||||
|
||||
<Note>
|
||||
Чтобы вызвать логическую функцию, запускаемую маршрутом, из фронтенд-компонента (без интерфейса), см. раздел [Вызов логической функции](/l/ru/developers/extend/apps/layout/front-components#calling-a-logic-function).
|
||||
</Note>
|
||||
* **cron**: Запускает вашу функцию по расписанию с использованием выражения CRON.
|
||||
* **databaseEvent**: Запускается при событиях жизненного цикла объектов рабочего пространства. Когда операция события — `updated`, можно указать конкретные поля для отслеживания в массиве `updatedFields`. Если оставить не заданным или пустым, любое обновление будет вызывать функцию.
|
||||
> например, `person.updated`, `*.created`, `company.*`
|
||||
|
||||
@@ -43,6 +43,8 @@ export default defineField({
|
||||
|
||||
* Dosya konumu size bağlıdır. Genel kabul gören yapı `src/fields/\<name>.field.ts` şeklindedir, ancak SDK `src/` içinde herhangi bir yerdeki alanları algılar.
|
||||
|
||||
* Standart bir sayfa yerleşimine (örneğin, Görev veya Şirket detay sayfası) bir sekme eklemek için, `twenty-sdk/define` içindeki `STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS` ile birlikte [`definePageLayoutTab`](/l/tr/developers/extend/apps/layout/page-layouts#definepagelayouttab) kullanın.
|
||||
|
||||
## Mevcut bir nesneye ilişki ekleme
|
||||
|
||||
Bir ilişki alanı eklemek için (örneğin özel nesnenizi standart bir `Person` nesnesine bağlamak), `FieldType.RELATION` ile `defineField()` kullanın. Desen, satır içi ilişkilerle aynıdır ancak `objectUniversalIdentifier` açıkça ayarlanır. Çift yönlü desen için [Relations](/l/tr/developers/extend/apps/data/relations) bölümüne bakın.
|
||||
|
||||
@@ -103,6 +103,10 @@ export default defineCommandMenuItem({
|
||||
});
|
||||
```
|
||||
|
||||
<Note>
|
||||
`RECORD_SELECTION` zaten boş olmayan bir seçim anlamına gelir — `numberOfSelectedRecords` ifadesini yalnızca belirli sayılar için kullanın (örneğin `>= 2`).
|
||||
</Note>
|
||||
|
||||
### Bağlam değişkenleri
|
||||
|
||||
Bunlar sayfanın mevcut durumunu temsil eder:
|
||||
|
||||
@@ -196,6 +196,94 @@ export default defineFrontComponent({
|
||||
});
|
||||
```
|
||||
|
||||
## Bir mantık işlevini çağırma
|
||||
|
||||
Ön bileşenler, tarayıcı tarafında izole bir Web Worker içinde çalışırken, [mantık işlevleri](/l/tr/developers/extend/apps/logic/logic-functions) sunucu tarafında çalışır. İkisi arasında doğrudan, işlem içi bir çağrı yoktur — bunun yerine, bir ön bileşen bir mantık işlevine HTTP üzerinden erişir.
|
||||
|
||||
`httpRouteTriggerSettings` ile bildirilen bir mantık işlevi, `${TWENTY_API_URL}/s\<path>` altındaki `/s/` uç noktasında sunulur. Ön bileşeniniz bu rotayı, Twenty tarafından Worker'a enjekte edilen `TWENTY_APP_ACCESS_TOKEN` ile kimlik doğrulayarak `fetch` ile çağırır.
|
||||
|
||||
Küçük, yeniden kullanılabilir bir yardımcı işlev çağrı noktalarını sade tutar:
|
||||
|
||||
```ts src/shared/call-app-route.ts
|
||||
export async function callAppRoute(
|
||||
path: string,
|
||||
body: Record<string, unknown>,
|
||||
): Promise<unknown> {
|
||||
const apiUrl = process.env.TWENTY_API_URL ?? '';
|
||||
const token = process.env.TWENTY_APP_ACCESS_TOKEN;
|
||||
|
||||
const res = await fetch(`${apiUrl}/s${path}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error(`Logic function failed (${res.status})`);
|
||||
}
|
||||
|
||||
return res.json();
|
||||
}
|
||||
```
|
||||
|
||||
Başsız bir ön bileşen, çağrıyı `Command` bileşeni aracılığıyla mount sırasında çalıştırabilir ve ardından otomatik olarak unmount olabilir:
|
||||
|
||||
```tsx src/front-components/sync-prs.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk/define';
|
||||
import { Command } from 'twenty-sdk/command';
|
||||
import { callAppRoute } from 'src/shared/call-app-route';
|
||||
|
||||
const SyncPrs = () => {
|
||||
const execute = async () => {
|
||||
await callAppRoute('/github/fetch-prs', {
|
||||
owner: 'twentyhq',
|
||||
repo: 'twenty',
|
||||
});
|
||||
};
|
||||
|
||||
return <Command execute={execute} />;
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: '...',
|
||||
name: 'sync-prs',
|
||||
description: 'Triggers the fetch-prs logic function',
|
||||
isHeadless: true,
|
||||
component: SyncPrs,
|
||||
});
|
||||
```
|
||||
|
||||
`callAppRoute` fonksiyonuna geçirilen `path`, mantık işlevinin `httpRouteTriggerSettings.path` değeriyle eşleşmelidir (`/s` öneki yardımcı işlev tarafından eklenir):
|
||||
|
||||
```ts src/logic-functions/fetch-prs.logic-function.ts
|
||||
import { defineLogicFunction } from 'twenty-sdk/define';
|
||||
import type { RoutePayload } from 'twenty-sdk/logic-function';
|
||||
|
||||
const handler = async (event: RoutePayload) => {
|
||||
const { owner, repo } = (event.body ?? {}) as { owner: string; repo: string };
|
||||
// ...fetch from GitHub and persist records...
|
||||
return { ok: true };
|
||||
};
|
||||
|
||||
export default defineLogicFunction({
|
||||
universalIdentifier: '...',
|
||||
name: 'fetch-prs',
|
||||
handler,
|
||||
httpRouteTriggerSettings: {
|
||||
path: '/github/fetch-prs',
|
||||
httpMethod: 'POST',
|
||||
isAuthRequired: true,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
<Note>
|
||||
`TWENTY_API_URL` ve `TWENTY_APP_ACCESS_TOKEN` otomatik olarak enjekte edilir — bkz. [Uygulama değişkenleri](#application-variables). Gizli uygulama değişkenleri asla ön bileşenlere açığa çıkarılmadığından, API anahtarlarını ve diğer hassas mantığı ön bileşende değil, mantık işlevinin içinde tutun.
|
||||
</Note>
|
||||
|
||||
## Çalışma zamanı bağlamına erişme
|
||||
|
||||
Bileşeninizin içinde, geçerli kullanıcıya, kayda ve bileşen örneğine erişmek için SDK hook'larını kullanın:
|
||||
|
||||
@@ -65,16 +65,15 @@ Bunu yalnızca mevcut bir düzene **sekme eklemek** istediğinizde kullanın —
|
||||
import {
|
||||
definePageLayoutTab,
|
||||
PageLayoutTabLayoutMode,
|
||||
STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS,
|
||||
} from 'twenty-sdk/define';
|
||||
import { HELLO_WORLD_FRONT_COMPONENT_UNIVERSAL_IDENTIFIER } from '../front-components/hello-world';
|
||||
|
||||
const COMPANY_RECORD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIER =
|
||||
'20202020-ab01-4001-8001-c0aba11c0100';
|
||||
|
||||
export default definePageLayoutTab({
|
||||
universalIdentifier: 'b1b2b3b4-b5b6-4000-8000-000000000001',
|
||||
pageLayoutUniversalIdentifier:
|
||||
COMPANY_RECORD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIER,
|
||||
STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.companyRecordPage
|
||||
.universalIdentifier,
|
||||
title: 'Hello World',
|
||||
position: 1000,
|
||||
icon: 'IconWorld',
|
||||
@@ -97,6 +96,37 @@ export default definePageLayoutTab({
|
||||
### Önemli noktalar
|
||||
|
||||
* `pageLayoutUniversalIdentifier` **zorunludur** ve kurulum anında zaten var olan bir sayfa düzenini işaret etmelidir — standart bir Twenty düzeni veya kendi uygulamanız tarafından tanımlanan bir düzen olabilir. Başka yüklü bir uygulamaya ait düzenlere uygulamalar arası referanslar bugün desteklenmemektedir. Üst düzen eksik olduğunda, kurulum net bir doğrulama hatasıyla başarısız olur.
|
||||
|
||||
* Standart Twenty yerleşimleri için tanımlayıcıları `twenty-sdk/define` içinden içe aktarın:
|
||||
|
||||
```ts
|
||||
import { STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS } from 'twenty-sdk/define';
|
||||
|
||||
// STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.companyRecordPage.universalIdentifier
|
||||
// STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.personRecordPage.universalIdentifier
|
||||
// STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.taskRecordPage.universalIdentifier
|
||||
// STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.opportunityRecordPage.universalIdentifier
|
||||
// STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.noteRecordPage.universalIdentifier
|
||||
// …
|
||||
```
|
||||
|
||||
Her yerleşim girdisi ayrıca `tabs` ve bunların `widgets` ögelerini de açığa çıkarır, böylece herhangi bir düzeye başvurabilirsiniz:
|
||||
|
||||
```ts
|
||||
STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.taskRecordPage.tabs.home.universalIdentifier
|
||||
STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.taskRecordPage.tabs.home.widgets.fields.universalIdentifier
|
||||
```
|
||||
|
||||
Kısa bir takma ad `STANDARD_PAGE_LAYOUT` da kullanılabilir:
|
||||
|
||||
```ts
|
||||
import { STANDARD_PAGE_LAYOUT } from 'twenty-sdk/define';
|
||||
|
||||
STANDARD_PAGE_LAYOUT.companyRecordPage.universalIdentifier;
|
||||
```
|
||||
|
||||
* `widgets` yalnızca bu sekmeyle sınırlıdır — satır içi olarak `definePageLayout` içinde tanımlanan widget'larda olduğu gibi, [ön uç bileşenlerine](/l/tr/developers/extend/apps/layout/front-components), görünümlere vb. tam olarak aynı şekilde referans verirler.
|
||||
|
||||
* `position`, hedeflenen düzende mevcut sekmelere göre sıralamayı kontrol eder. Yerleşik sekmelere göre sekmenizi istediğiniz konuma yerleştirecek bir değer seçin.
|
||||
|
||||
* Yalnızca mevcut bir düzene ekleme yapmak istediğinizde `definePageLayout` yerine bunu kullanın. Tüm düzene sahip olduğunuzda `definePageLayout` kullanın.
|
||||
|
||||
@@ -53,6 +53,10 @@ export default defineLogicFunction({
|
||||
Kullanılabilir tetikleyici türleri:
|
||||
* **httpRoute**: İşlevinizi bir HTTP yolu ve yöntemiyle **`/s/` uç noktasının altında** kullanıma sunar:
|
||||
> örn. `path: '/post-card/create'` `https://your-twenty-server.com/s/post-card/create` adresinden çağrılabilir
|
||||
|
||||
<Note>
|
||||
Arayüzsüz bir ön uç bileşeninden rota tarafından tetiklenen mantık fonksiyonunu çağırmak için bkz. [Mantık fonksiyonu çağırma](/l/tr/developers/extend/apps/layout/front-components#calling-a-logic-function).
|
||||
</Note>
|
||||
* **cron**: Bir CRON ifadesi kullanarak işlevinizi bir zamanlamayla çalıştırır.
|
||||
* **databaseEvent**: Çalışma alanı nesnesi yaşam döngüsü olaylarında çalışır. Olay işlemi `updated` olduğunda, dinlenecek belirli alanlar `updatedFields` dizisinde belirtilebilir. Tanımsız veya boş bırakılırsa, herhangi bir güncelleme işlevi tetikler.
|
||||
> örn. `person.updated`, `*.created`, `company.*`
|
||||
|
||||
@@ -43,6 +43,8 @@ export default defineField({
|
||||
|
||||
* 文件位置由你决定。 约定是使用 `src/fields/\<name>.field.ts`,但 SDK 会在整个 `src/` 中检测字段。
|
||||
|
||||
* 要在标准页面布局(例如任务或公司详情页面)中添加一个选项卡,请使用 [`definePageLayoutTab`](/l/zh/developers/extend/apps/layout/page-layouts#definepagelayouttab),并结合来自 `twenty-sdk/define` 的 `STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS`。
|
||||
|
||||
## 向现有对象添加关系
|
||||
|
||||
要添加关系字段(例如将你的自定义对象链接到标准 `Person`),请将 `defineField()` 与 `FieldType.RELATION` 一起使用。 模式与内联关系相同,但需要显式设置 `objectUniversalIdentifier`。 有关双向模式,请参见[关系](/l/zh/developers/extend/apps/data/relations)。
|
||||
|
||||
@@ -103,6 +103,10 @@ export default defineCommandMenuItem({
|
||||
});
|
||||
```
|
||||
|
||||
<Note>
|
||||
`RECORD_SELECTION` 已经意味着非空选择 — 仅在需要表达具体数量时使用 `numberOfSelectedRecords`(例如 `>= 2`)。
|
||||
</Note>
|
||||
|
||||
### 上下文变量
|
||||
|
||||
这些变量表示页面的当前状态:
|
||||
|
||||
@@ -196,6 +196,94 @@ export default defineFrontComponent({
|
||||
});
|
||||
```
|
||||
|
||||
## 调用逻辑函数
|
||||
|
||||
前端组件在沙盒 Web Worker 中于浏览器端运行,而[逻辑函数](/l/zh/developers/extend/apps/logic/logic-functions)在服务器端运行。 二者之间没有直接的进程内调用——前端组件通过 HTTP 访问逻辑函数。
|
||||
|
||||
使用 `httpRouteTriggerSettings` 声明的逻辑函数会通过 `/s/` 端点暴露在 `${TWENTY_API_URL}/s\<path>` 下。 你的前端组件使用 `fetch` 调用该路由,并使用 Twenty 注入到 worker 中的 `TWENTY_APP_ACCESS_TOKEN` 进行身份验证。
|
||||
|
||||
一个小型可复用的辅助函数可以让调用端保持简洁:
|
||||
|
||||
```ts src/shared/call-app-route.ts
|
||||
export async function callAppRoute(
|
||||
path: string,
|
||||
body: Record<string, unknown>,
|
||||
): Promise<unknown> {
|
||||
const apiUrl = process.env.TWENTY_API_URL ?? '';
|
||||
const token = process.env.TWENTY_APP_ACCESS_TOKEN;
|
||||
|
||||
const res = await fetch(`${apiUrl}/s${path}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error(`Logic function failed (${res.status})`);
|
||||
}
|
||||
|
||||
return res.json();
|
||||
}
|
||||
```
|
||||
|
||||
无头前端组件可以通过 `Command` 组件在挂载时执行调用,然后自动卸载:
|
||||
|
||||
```tsx src/front-components/sync-prs.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk/define';
|
||||
import { Command } from 'twenty-sdk/command';
|
||||
import { callAppRoute } from 'src/shared/call-app-route';
|
||||
|
||||
const SyncPrs = () => {
|
||||
const execute = async () => {
|
||||
await callAppRoute('/github/fetch-prs', {
|
||||
owner: 'twentyhq',
|
||||
repo: 'twenty',
|
||||
});
|
||||
};
|
||||
|
||||
return <Command execute={execute} />;
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: '...',
|
||||
name: 'sync-prs',
|
||||
description: 'Triggers the fetch-prs logic function',
|
||||
isHeadless: true,
|
||||
component: SyncPrs,
|
||||
});
|
||||
```
|
||||
|
||||
传递给 `callAppRoute` 的 `path` 必须与逻辑函数的 `httpRouteTriggerSettings.path` 匹配(`/s` 前缀由辅助函数添加):
|
||||
|
||||
```ts src/logic-functions/fetch-prs.logic-function.ts
|
||||
import { defineLogicFunction } from 'twenty-sdk/define';
|
||||
import type { RoutePayload } from 'twenty-sdk/logic-function';
|
||||
|
||||
const handler = async (event: RoutePayload) => {
|
||||
const { owner, repo } = (event.body ?? {}) as { owner: string; repo: string };
|
||||
// ...fetch from GitHub and persist records...
|
||||
return { ok: true };
|
||||
};
|
||||
|
||||
export default defineLogicFunction({
|
||||
universalIdentifier: '...',
|
||||
name: 'fetch-prs',
|
||||
handler,
|
||||
httpRouteTriggerSettings: {
|
||||
path: '/github/fetch-prs',
|
||||
httpMethod: 'POST',
|
||||
isAuthRequired: true,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
<Note>
|
||||
`TWENTY_API_URL` 和 `TWENTY_APP_ACCESS_TOKEN` 会被自动注入——参见 [应用变量](#application-variables)。 由于机密应用变量永远不会暴露给前端组件,请将 API 密钥和其他敏感逻辑保留在逻辑函数中,而不是前端组件中。
|
||||
</Note>
|
||||
|
||||
## 访问运行时上下文
|
||||
|
||||
在组件内部,使用 SDK 的 hooks 获取当前用户、记录和组件实例:
|
||||
|
||||
@@ -65,16 +65,15 @@ export default definePageLayout({
|
||||
import {
|
||||
definePageLayoutTab,
|
||||
PageLayoutTabLayoutMode,
|
||||
STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS,
|
||||
} from 'twenty-sdk/define';
|
||||
import { HELLO_WORLD_FRONT_COMPONENT_UNIVERSAL_IDENTIFIER } from '../front-components/hello-world';
|
||||
|
||||
const COMPANY_RECORD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIER =
|
||||
'20202020-ab01-4001-8001-c0aba11c0100';
|
||||
|
||||
export default definePageLayoutTab({
|
||||
universalIdentifier: 'b1b2b3b4-b5b6-4000-8000-000000000001',
|
||||
pageLayoutUniversalIdentifier:
|
||||
COMPANY_RECORD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIER,
|
||||
STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.companyRecordPage
|
||||
.universalIdentifier,
|
||||
title: 'Hello World',
|
||||
position: 1000,
|
||||
icon: 'IconWorld',
|
||||
@@ -97,6 +96,37 @@ export default definePageLayoutTab({
|
||||
### 关键点
|
||||
|
||||
* `pageLayoutUniversalIdentifier` 是**必需的**,并且必须在安装时指向一个已存在的页面布局——可以是标准的 Twenty 布局,也可以是由你自己的应用定义的布局。 当前不支持跨应用引用由其他已安装应用拥有的布局。 当父布局缺失时,安装会失败,并给出清晰的验证错误。
|
||||
|
||||
* 对于标准 Twenty 布局,从 `twenty-sdk/define` 导入标识符:
|
||||
|
||||
```ts
|
||||
import { STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS } from 'twenty-sdk/define';
|
||||
|
||||
// STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.companyRecordPage.universalIdentifier
|
||||
// STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.personRecordPage.universalIdentifier
|
||||
// STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.taskRecordPage.universalIdentifier
|
||||
// STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.opportunityRecordPage.universalIdentifier
|
||||
// STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.noteRecordPage.universalIdentifier
|
||||
// …
|
||||
```
|
||||
|
||||
每个布局条目还会公开其 `tabs` 及其 `widgets`,因此你可以引用任意层级:
|
||||
|
||||
```ts
|
||||
STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.taskRecordPage.tabs.home.universalIdentifier
|
||||
STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.taskRecordPage.tabs.home.widgets.fields.universalIdentifier
|
||||
```
|
||||
|
||||
还提供了一个简短别名 `STANDARD_PAGE_LAYOUT`:
|
||||
|
||||
```ts
|
||||
import { STANDARD_PAGE_LAYOUT } from 'twenty-sdk/define';
|
||||
|
||||
STANDARD_PAGE_LAYOUT.companyRecordPage.universalIdentifier;
|
||||
```
|
||||
|
||||
* `widgets` 仅作用于此选项卡——它们引用[前端组件](/l/zh/developers/extend/apps/layout/front-components)、视图等,其方式与在 `definePageLayout` 中内联定义的小部件完全相同。
|
||||
|
||||
* `position` 控制目标布局中相对于现有选项卡的排序。 选择一个取值,使你的选项卡相对于内置选项卡位于你想要的位置。
|
||||
|
||||
* 当你只想向现有布局进行添加时,请使用此功能,而不是 `definePageLayout`。 当你拥有整个布局时,请使用 `definePageLayout`。
|
||||
|
||||
@@ -53,6 +53,10 @@ export default defineLogicFunction({
|
||||
可用的触发器类型:
|
||||
* **httpRoute**:在 **`/s/` 端点**下通过 HTTP 路径和方法公开你的函数:
|
||||
> 例如 `path: '/post-card/create'` 可在 `https://your-twenty-server.com/s/post-card/create` 调用
|
||||
|
||||
<Note>
|
||||
要从(无头)前端组件调用由路由触发的逻辑函数,请参见[调用逻辑函数](/l/zh/developers/extend/apps/layout/front-components#calling-a-logic-function)。
|
||||
</Note>
|
||||
* **cron**:使用 CRON 表达式按计划运行你的函数。
|
||||
* **databaseEvent**:在工作区对象生命周期事件上运行。 当事件操作为 `updated` 时,可以在 `updatedFields` 数组中指定要监听的特定字段。 如果未定义或为空,任何更新都会触发该函数。
|
||||
> 例如 `person.updated`、`*.created`、`company.*`
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"private": true,
|
||||
"license": "AGPL-3.0",
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.56.1",
|
||||
"playwright": "^1.56.1"
|
||||
"@playwright/test": "^1.60.0",
|
||||
"playwright": "^1.60.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,11 +36,11 @@
|
||||
"@storybook/addon-vitest": "^10.2.13",
|
||||
"@storybook/react-vite": "^10.2.13",
|
||||
"@types/node": "^24.0.0",
|
||||
"@types/react": "^19.0.0",
|
||||
"@types/react-dom": "^19.0.0",
|
||||
"@types/react": "^18.2.39",
|
||||
"@types/react-dom": "^18.2.15",
|
||||
"@typescript/native-preview": "^7.0.0-dev.20260116.1",
|
||||
"@vitest/browser-playwright": "^4.0.18",
|
||||
"playwright": "^1.56.1",
|
||||
"playwright": "^1.60.0",
|
||||
"prettier": "^3.1.1",
|
||||
"storybook": "^10.2.13",
|
||||
"styled-components": "^6.1.0",
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
import { createContext } from 'react';
|
||||
|
||||
export type SetEditableFocused = (focused: boolean) => void;
|
||||
|
||||
export const FrontComponentInputFocusContext =
|
||||
createContext<SetEditableFocused | null>(null);
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
isString,
|
||||
isUndefined,
|
||||
} from '@sniptt/guards';
|
||||
import React from 'react';
|
||||
import React, { useContext } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { EVENT_TO_REACT } from '@/constants/EventToReact';
|
||||
@@ -15,6 +15,10 @@ import {
|
||||
type SerializedEventData,
|
||||
type SerializedFileData,
|
||||
} from '@/constants/SerializedEventData';
|
||||
import {
|
||||
FrontComponentInputFocusContext,
|
||||
type SetEditableFocused,
|
||||
} from '@/host/contexts/FrontComponentInputFocusContext';
|
||||
|
||||
const INTERNAL_PROPS = new Set(['element', 'receiver', 'components']);
|
||||
|
||||
@@ -352,18 +356,41 @@ const createCaretPreservingElement = (
|
||||
htmlTag: 'input' | 'textarea',
|
||||
reactProps: Record<string, unknown>,
|
||||
forcedProps: Record<string, unknown> | undefined,
|
||||
setEditableFocused: SetEditableFocused | null,
|
||||
) => {
|
||||
const { value, defaultValue, ...rest } = reactProps;
|
||||
const {
|
||||
value,
|
||||
defaultValue,
|
||||
onFocus: forwardedOnFocus,
|
||||
onBlur: forwardedOnBlur,
|
||||
...rest
|
||||
} = reactProps;
|
||||
const initialValue = isNonEmptyString(defaultValue)
|
||||
? defaultValue
|
||||
: isNonEmptyString(value)
|
||||
? value
|
||||
: undefined;
|
||||
|
||||
const handleFocus = (event: React.FocusEvent<CaretPreservingElement>) => {
|
||||
setEditableFocused?.(true);
|
||||
if (isFunction(forwardedOnFocus)) {
|
||||
forwardedOnFocus(event);
|
||||
}
|
||||
};
|
||||
|
||||
const handleBlur = (event: React.FocusEvent<CaretPreservingElement>) => {
|
||||
setEditableFocused?.(false);
|
||||
if (isFunction(forwardedOnBlur)) {
|
||||
forwardedOnBlur(event);
|
||||
}
|
||||
};
|
||||
|
||||
return React.createElement(htmlTag, {
|
||||
...rest,
|
||||
...forcedProps,
|
||||
defaultValue: initialValue,
|
||||
onFocus: handleFocus,
|
||||
onBlur: handleBlur,
|
||||
ref: (node: CaretPreservingElement | null) => {
|
||||
if (!isDefined(node)) {
|
||||
return;
|
||||
@@ -380,13 +407,19 @@ export const createHtmlHostWrapper = (htmlTag: string) => {
|
||||
const isVoid = VOID_ELEMENTS.has(htmlTag);
|
||||
|
||||
return ({ children, ...props }: WrapperProps) => {
|
||||
const setEditableFocused = useContext(FrontComponentInputFocusContext);
|
||||
const reactProps = filterProps(props);
|
||||
|
||||
if (
|
||||
htmlTag === 'textarea' ||
|
||||
(htmlTag === 'input' && isTextLikeInputType(reactProps.type))
|
||||
) {
|
||||
return createCaretPreservingElement(htmlTag, reactProps, forcedProps);
|
||||
return createCaretPreservingElement(
|
||||
htmlTag,
|
||||
reactProps,
|
||||
forcedProps,
|
||||
setEditableFocused,
|
||||
);
|
||||
}
|
||||
|
||||
return React.createElement(
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
export { FrontComponentRenderer } from './host/components/FrontComponentRenderer';
|
||||
export {
|
||||
FrontComponentInputFocusContext,
|
||||
type SetEditableFocused,
|
||||
} from './host/contexts/FrontComponentInputFocusContext';
|
||||
export { componentRegistry } from './host/generated/host-component-registry';
|
||||
export { FrontComponentErrorEffect } from './remote/components/FrontComponentErrorEffect';
|
||||
export { FrontComponentInitializeHostCommunicationApiEffect } from './remote/components/FrontComponentInitializeHostCommunicationApiEffect';
|
||||
|
||||
@@ -157,7 +157,7 @@
|
||||
"@lingui/cli": "^5.1.2",
|
||||
"@lingui/swc-plugin": "^5.11.0",
|
||||
"@lingui/vite-plugin": "^5.1.2",
|
||||
"@playwright/test": "^1.56.1",
|
||||
"@playwright/test": "^1.60.0",
|
||||
"@storybook-community/storybook-addon-cookie": "^5.0.0",
|
||||
"@storybook/addon-coverage": "^3.0.0",
|
||||
"@storybook/addon-docs": "^10.3.3",
|
||||
@@ -192,7 +192,7 @@
|
||||
"optionator": "^0.9.1",
|
||||
"oxlint": "^1.51.0",
|
||||
"oxlint-tsgolint": "^0.16.0",
|
||||
"playwright": "^1.56.1",
|
||||
"playwright": "^1.60.0",
|
||||
"prettier": "^3.1.1",
|
||||
"rollup-plugin-node-polyfills": "^0.2.1",
|
||||
"rollup-plugin-visualizer": "^5.14.0",
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 64 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 91 KiB After Width: | Height: | Size: 70 KiB |
@@ -283,13 +283,13 @@ export type FeatureFlag = {
|
||||
};
|
||||
|
||||
export enum FeatureFlagKey {
|
||||
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_REST_METADATA_API_NEW_FORMAT_DIRECT = 'IS_REST_METADATA_API_NEW_FORMAT_DIRECT',
|
||||
IS_SETTINGS_DISCOVERY_HERO_ENABLED = 'IS_SETTINGS_DISCOVERY_HERO_ENABLED',
|
||||
IS_UNIQUE_INDEXES_ENABLED = 'IS_UNIQUE_INDEXES_ENABLED'
|
||||
}
|
||||
|
||||
@@ -399,6 +399,7 @@ export type Mutation = {
|
||||
setAdminAiModelsRecommended: Scalars['Boolean'];
|
||||
setAdminDefaultAiModel: Scalars['Boolean'];
|
||||
setMaintenanceMode: Scalars['Boolean'];
|
||||
updateAdminApplicationRegistrationVariable: ApplicationRegistrationVariableDto;
|
||||
updateDatabaseConfigVariable: Scalars['Boolean'];
|
||||
updateWorkspaceFeatureFlag: Scalars['Boolean'];
|
||||
};
|
||||
@@ -492,6 +493,11 @@ export type MutationSetMaintenanceModeArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationUpdateAdminApplicationRegistrationVariableArgs = {
|
||||
input: UpdateApplicationRegistrationVariableInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationUpdateDatabaseConfigVariableArgs = {
|
||||
key: Scalars['String'];
|
||||
value: Scalars['JSON'];
|
||||
@@ -732,6 +738,17 @@ export type SystemHealthService = {
|
||||
status: AdminPanelHealthServiceStatus;
|
||||
};
|
||||
|
||||
export type UpdateApplicationRegistrationVariableInput = {
|
||||
id: Scalars['String'];
|
||||
update: UpdateApplicationRegistrationVariablePayload;
|
||||
};
|
||||
|
||||
export type UpdateApplicationRegistrationVariablePayload = {
|
||||
description?: InputMaybe<Scalars['String']>;
|
||||
resetValue?: InputMaybe<Scalars['Boolean']>;
|
||||
value?: InputMaybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export enum UpgradeHealth {
|
||||
BEHIND = 'BEHIND',
|
||||
FAILED = 'FAILED',
|
||||
@@ -923,6 +940,13 @@ export type GetModelsDevSuggestionsQueryVariables = Exact<{
|
||||
|
||||
export type GetModelsDevSuggestionsQuery = { __typename?: 'Query', getModelsDevSuggestions: Array<{ __typename?: 'ModelsDevModelSuggestion', modelId: string, name: string, inputCostPerMillionTokens: number, outputCostPerMillionTokens: number, cachedInputCostPerMillionTokens?: number | null, cacheCreationCostPerMillionTokens?: number | null, contextWindowTokens: number, maxOutputTokens: number, modalities: Array<string>, supportsReasoning: boolean }> };
|
||||
|
||||
export type UpdateAdminApplicationRegistrationVariableMutationVariables = Exact<{
|
||||
input: UpdateApplicationRegistrationVariableInput;
|
||||
}>;
|
||||
|
||||
|
||||
export type UpdateAdminApplicationRegistrationVariableMutation = { __typename?: 'Mutation', updateAdminApplicationRegistrationVariable: { __typename?: 'ApplicationRegistrationVariableDTO', id: string, key: string, description: string, isSecret: boolean, isRequired: boolean, isFilled: boolean, createdAt: string, updatedAt: string } };
|
||||
|
||||
export type FindAdminApplicationRegistrationVariablesQueryVariables = Exact<{
|
||||
applicationRegistrationId: Scalars['String'];
|
||||
}>;
|
||||
@@ -1154,6 +1178,7 @@ export const GetAdminAiUsageByWorkspaceDocument = {"kind":"Document","definition
|
||||
export const GetAiProvidersDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetAiProviders"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getAiProviders"}}]}}]} as unknown as DocumentNode<GetAiProvidersQuery, GetAiProvidersQueryVariables>;
|
||||
export const GetModelsDevProvidersDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetModelsDevProviders"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getModelsDevProviders"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"modelCount"}},{"kind":"Field","name":{"kind":"Name","value":"npm"}}]}}]}}]} as unknown as DocumentNode<GetModelsDevProvidersQuery, GetModelsDevProvidersQueryVariables>;
|
||||
export const GetModelsDevSuggestionsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetModelsDevSuggestions"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"providerType"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getModelsDevSuggestions"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"providerType"},"value":{"kind":"Variable","name":{"kind":"Name","value":"providerType"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"modelId"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"inputCostPerMillionTokens"}},{"kind":"Field","name":{"kind":"Name","value":"outputCostPerMillionTokens"}},{"kind":"Field","name":{"kind":"Name","value":"cachedInputCostPerMillionTokens"}},{"kind":"Field","name":{"kind":"Name","value":"cacheCreationCostPerMillionTokens"}},{"kind":"Field","name":{"kind":"Name","value":"contextWindowTokens"}},{"kind":"Field","name":{"kind":"Name","value":"maxOutputTokens"}},{"kind":"Field","name":{"kind":"Name","value":"modalities"}},{"kind":"Field","name":{"kind":"Name","value":"supportsReasoning"}}]}}]}}]} as unknown as DocumentNode<GetModelsDevSuggestionsQuery, GetModelsDevSuggestionsQueryVariables>;
|
||||
export const UpdateAdminApplicationRegistrationVariableDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateAdminApplicationRegistrationVariable"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UpdateApplicationRegistrationVariableInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateAdminApplicationRegistrationVariable"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"isSecret"}},{"kind":"Field","name":{"kind":"Name","value":"isRequired"}},{"kind":"Field","name":{"kind":"Name","value":"isFilled"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}}]} as unknown as DocumentNode<UpdateAdminApplicationRegistrationVariableMutation, UpdateAdminApplicationRegistrationVariableMutationVariables>;
|
||||
export const FindAdminApplicationRegistrationVariablesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FindAdminApplicationRegistrationVariables"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"applicationRegistrationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findAdminApplicationRegistrationVariables"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"applicationRegistrationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"applicationRegistrationId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"isSecret"}},{"kind":"Field","name":{"kind":"Name","value":"isRequired"}},{"kind":"Field","name":{"kind":"Name","value":"isFilled"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}}]} as unknown as DocumentNode<FindAdminApplicationRegistrationVariablesQuery, FindAdminApplicationRegistrationVariablesQueryVariables>;
|
||||
export const FindAllApplicationRegistrationsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FindAllApplicationRegistrations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findAllApplicationRegistrations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ApplicationRegistrationFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ApplicationRegistrationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ApplicationRegistration"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"universalIdentifier"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"logoUrl"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthClientId"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthRedirectUris"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthScopes"}},{"kind":"Field","name":{"kind":"Name","value":"sourceType"}},{"kind":"Field","name":{"kind":"Name","value":"sourcePackage"}},{"kind":"Field","name":{"kind":"Name","value":"latestAvailableVersion"}},{"kind":"Field","name":{"kind":"Name","value":"isListed"}},{"kind":"Field","name":{"kind":"Name","value":"isFeatured"}},{"kind":"Field","name":{"kind":"Name","value":"isPreInstalled"}},{"kind":"Field","name":{"kind":"Name","value":"isConfigured"}},{"kind":"Field","name":{"kind":"Name","value":"ownerWorkspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<FindAllApplicationRegistrationsQuery, FindAllApplicationRegistrationsQueryVariables>;
|
||||
export const CreateDatabaseConfigVariableDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateDatabaseConfigVariable"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"key"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"value"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createDatabaseConfigVariable"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"key"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}},{"kind":"Argument","name":{"kind":"Name","value":"value"},"value":{"kind":"Variable","name":{"kind":"Name","value":"value"}}}]}]}}]} as unknown as DocumentNode<CreateDatabaseConfigVariableMutation, CreateDatabaseConfigVariableMutationVariables>;
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user