@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "create-twenty-app",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"description": "Command-line interface to create Twenty application",
|
||||
"main": "dist/cli.cjs",
|
||||
"bin": "dist/cli.cjs",
|
||||
|
||||
@@ -70,7 +70,7 @@ describe('copyBaseApplicationProject', () => {
|
||||
const packageJson = await fs.readJson(packageJsonPath);
|
||||
expect(packageJson.name).toBe('my-test-app');
|
||||
expect(packageJson.version).toBe('0.1.0');
|
||||
expect(packageJson.dependencies['twenty-sdk']).toBe('0.5.0');
|
||||
expect(packageJson.dependencies['twenty-sdk']).toBe('0.5.1');
|
||||
expect(packageJson.scripts['app:dev']).toBe('twenty app:dev');
|
||||
});
|
||||
|
||||
|
||||
@@ -277,7 +277,7 @@ const createPackageJson = async ({
|
||||
'lint:fix': 'eslint --fix',
|
||||
},
|
||||
dependencies: {
|
||||
'twenty-sdk': '0.5.0',
|
||||
'twenty-sdk': '0.5.1',
|
||||
},
|
||||
devDependencies: {
|
||||
typescript: '^5.9.3',
|
||||
|
||||
@@ -987,14 +987,6 @@ export type CreateCommandMenuItemInput = {
|
||||
workflowVersionId?: InputMaybe<Scalars['UUID']>;
|
||||
};
|
||||
|
||||
export type CreateDefaultLogicFunctionInput = {
|
||||
description?: InputMaybe<Scalars['String']>;
|
||||
isTool?: InputMaybe<Scalars['Boolean']>;
|
||||
name: Scalars['String'];
|
||||
timeoutSeconds?: InputMaybe<Scalars['Float']>;
|
||||
toolInputSchema?: InputMaybe<Scalars['JSON']>;
|
||||
};
|
||||
|
||||
export type CreateFieldInput = {
|
||||
defaultValue?: InputMaybe<Scalars['JSON']>;
|
||||
description?: InputMaybe<Scalars['String']>;
|
||||
@@ -1027,6 +1019,20 @@ export type CreateFrontComponentInput = {
|
||||
sourceComponentPath: Scalars['String'];
|
||||
};
|
||||
|
||||
export type CreateLogicFunctionFromSourceInput = {
|
||||
cronTriggerSettings?: InputMaybe<Scalars['JSON']>;
|
||||
databaseEventTriggerSettings?: InputMaybe<Scalars['JSON']>;
|
||||
description?: InputMaybe<Scalars['String']>;
|
||||
httpRouteTriggerSettings?: InputMaybe<Scalars['JSON']>;
|
||||
id?: InputMaybe<Scalars['UUID']>;
|
||||
isTool?: InputMaybe<Scalars['Boolean']>;
|
||||
name: Scalars['String'];
|
||||
source?: InputMaybe<Scalars['JSON']>;
|
||||
timeoutSeconds?: InputMaybe<Scalars['Float']>;
|
||||
toolInputSchema?: InputMaybe<Scalars['JSON']>;
|
||||
universalIdentifier?: InputMaybe<Scalars['UUID']>;
|
||||
};
|
||||
|
||||
export type CreateNavigationMenuItemInput = {
|
||||
folderId?: InputMaybe<Scalars['UUID']>;
|
||||
link?: InputMaybe<Scalars['String']>;
|
||||
@@ -1444,8 +1450,6 @@ export type EventWithQueryIds = {
|
||||
};
|
||||
|
||||
export type ExecuteOneLogicFunctionInput = {
|
||||
/** Force rebuild from source before executing */
|
||||
forceRebuild?: InputMaybe<Scalars['Boolean']>;
|
||||
/** Id of the logic function to execute */
|
||||
id: Scalars['UUID'];
|
||||
/** Payload in JSON format */
|
||||
@@ -1955,7 +1959,6 @@ export type Location = {
|
||||
export type LogicFunction = {
|
||||
__typename?: 'LogicFunction';
|
||||
applicationId?: Maybe<Scalars['UUID']>;
|
||||
builtHandlerPath: Scalars['String'];
|
||||
createdAt: Scalars['DateTime'];
|
||||
cronTriggerSettings?: Maybe<Scalars['JSON']>;
|
||||
databaseEventTriggerSettings?: Maybe<Scalars['JSON']>;
|
||||
@@ -2070,7 +2073,6 @@ export type Mutation = {
|
||||
createCoreViewGroup: CoreViewGroup;
|
||||
createCoreViewSort: CoreViewSort;
|
||||
createDatabaseConfigVariable: Scalars['Boolean'];
|
||||
createDefaultLogicFunction: LogicFunction;
|
||||
createEmailingDomain: EmailingDomain;
|
||||
createFile: File;
|
||||
createFrontComponent: FrontComponent;
|
||||
@@ -2084,6 +2086,7 @@ export type Mutation = {
|
||||
createOneAppToken: AppToken;
|
||||
createOneApplication: Application;
|
||||
createOneField: Field;
|
||||
createOneLogicFunction: LogicFunction;
|
||||
createOneObject: Object;
|
||||
createOneRole: Role;
|
||||
createPageLayout: PageLayout;
|
||||
@@ -2188,11 +2191,11 @@ export type Mutation = {
|
||||
updateDatabaseConfigVariable: Scalars['Boolean'];
|
||||
updateFrontComponent: FrontComponent;
|
||||
updateLabPublicFeatureFlag: FeatureFlagDto;
|
||||
updateLogicFunctionSource: Scalars['Boolean'];
|
||||
updateNavigationMenuItem: NavigationMenuItem;
|
||||
updateOneAgent: Agent;
|
||||
updateOneApplicationVariable: Scalars['Boolean'];
|
||||
updateOneField: Field;
|
||||
updateOneLogicFunction: Scalars['Boolean'];
|
||||
updateOneObject: Object;
|
||||
updateOneRole: Role;
|
||||
updatePageLayout: PageLayout;
|
||||
@@ -2329,11 +2332,6 @@ export type MutationCreateDatabaseConfigVariableArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationCreateDefaultLogicFunctionArgs = {
|
||||
input: CreateDefaultLogicFunctionInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationCreateEmailingDomainArgs = {
|
||||
domain: Scalars['String'];
|
||||
driver: EmailingDomainDriver;
|
||||
@@ -2403,6 +2401,11 @@ export type MutationCreateOneFieldArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationCreateOneLogicFunctionArgs = {
|
||||
input: CreateLogicFunctionFromSourceInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationCreateOneObjectArgs = {
|
||||
input: CreateOneObjectInput;
|
||||
};
|
||||
@@ -2900,11 +2903,6 @@ export type MutationUpdateLabPublicFeatureFlagArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationUpdateLogicFunctionSourceArgs = {
|
||||
input: UpdateLogicFunctionSourceInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationUpdateNavigationMenuItemArgs = {
|
||||
input: UpdateOneNavigationMenuItemInput;
|
||||
};
|
||||
@@ -2927,6 +2925,11 @@ export type MutationUpdateOneFieldArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationUpdateOneLogicFunctionArgs = {
|
||||
input: UpdateLogicFunctionFromSourceInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationUpdateOneObjectArgs = {
|
||||
input: UpdateOneObjectInput;
|
||||
};
|
||||
@@ -3567,7 +3570,7 @@ export type Query = {
|
||||
getDatabaseConfigVariable: ConfigVariable;
|
||||
getEmailingDomains: Array<EmailingDomain>;
|
||||
getIndicatorHealthStatus: AdminPanelHealthServiceData;
|
||||
getLogicFunctionSourceCode?: Maybe<Scalars['JSON']>;
|
||||
getLogicFunctionSourceCode?: Maybe<Scalars['String']>;
|
||||
getMeteredProductsUsage: Array<BillingMeteredProductUsageOutput>;
|
||||
getPageLayout?: Maybe<PageLayout>;
|
||||
getPageLayoutTab: PageLayoutTab;
|
||||
@@ -4395,11 +4398,27 @@ export type UpdateLabPublicFeatureFlagInput = {
|
||||
value: Scalars['Boolean'];
|
||||
};
|
||||
|
||||
export type UpdateLogicFunctionSourceInput = {
|
||||
/** The source code (Sources) to write. Only updates source files. */
|
||||
code: Scalars['JSON'];
|
||||
/** The id of the logic function. */
|
||||
export type UpdateLogicFunctionFromSourceInput = {
|
||||
/** Id of the logic function to update */
|
||||
id: Scalars['UUID'];
|
||||
/** The logic function updates */
|
||||
update: UpdateLogicFunctionFromSourceInputUpdates;
|
||||
};
|
||||
|
||||
export type UpdateLogicFunctionFromSourceInputUpdates = {
|
||||
checksum?: InputMaybe<Scalars['String']>;
|
||||
cronTriggerSettings?: InputMaybe<Scalars['JSON']>;
|
||||
databaseEventTriggerSettings?: InputMaybe<Scalars['JSON']>;
|
||||
description?: InputMaybe<Scalars['String']>;
|
||||
handlerName?: InputMaybe<Scalars['String']>;
|
||||
httpRouteTriggerSettings?: InputMaybe<Scalars['JSON']>;
|
||||
isBuildUpToDate?: InputMaybe<Scalars['Boolean']>;
|
||||
isTool?: InputMaybe<Scalars['Boolean']>;
|
||||
name?: InputMaybe<Scalars['String']>;
|
||||
sourceHandlerCode?: InputMaybe<Scalars['String']>;
|
||||
sourceHandlerPath?: InputMaybe<Scalars['String']>;
|
||||
timeoutSeconds?: InputMaybe<Scalars['Float']>;
|
||||
toolInputSchema?: InputMaybe<Scalars['JSON']>;
|
||||
};
|
||||
|
||||
export type UpdateNavigationMenuItemInput = {
|
||||
@@ -5240,7 +5259,7 @@ export type UpdateOneApplicationVariableMutationVariables = Exact<{
|
||||
|
||||
export type UpdateOneApplicationVariableMutation = { __typename?: 'Mutation', updateOneApplicationVariable: boolean };
|
||||
|
||||
export type ApplicationFieldsFragment = { __typename?: 'Application', id: string, name: string, description: string, version: string, universalIdentifier: string, canBeUninstalled: boolean, availablePackages: any, applicationVariables: Array<{ __typename?: 'ApplicationVariable', id: string, key: string, value: string, description: string, isSecret: boolean }>, agents: Array<{ __typename?: 'Agent', id: string, name: string, label: string, description?: string | null, icon?: string | null, prompt: string, modelId: string, responseFormat?: any | null, roleId?: string | null, isCustom: boolean, modelConfiguration?: any | null, evaluationInputs: Array<string>, applicationId?: string | null, createdAt: string, updatedAt: string }>, objects: Array<{ __typename?: 'Object', id: string, nameSingular: string, namePlural: string, labelSingular: string, labelPlural: string, description?: string | null, icon?: string | null, isCustom: boolean, isRemote: boolean, isActive: boolean, isSystem: boolean, isUIReadOnly: boolean, createdAt: string, updatedAt: string, labelIdentifierFieldMetadataId?: string | null, imageIdentifierFieldMetadataId?: string | null, applicationId: string, shortcut?: string | null, isLabelSyncedWithName: boolean, isSearchable: boolean, duplicateCriteria?: Array<Array<string>> | null, indexMetadataList: Array<{ __typename?: 'Index', id: string, createdAt: string, updatedAt: string, name: string, indexWhereClause?: string | null, indexType: IndexType, isUnique: boolean, isCustom?: boolean | null, indexFieldMetadataList: Array<{ __typename?: 'IndexField', id: string, fieldMetadataId: string, createdAt: string, updatedAt: string, order: number }> }>, fieldsList: Array<{ __typename?: 'Field', id: string, type: FieldMetadataType, name: string, label: string, description?: string | null, icon?: string | null, isCustom?: boolean | null, isActive?: boolean | null, isSystem?: boolean | null, isUIReadOnly?: boolean | null, isNullable?: boolean | null, isUnique?: boolean | null, createdAt: string, updatedAt: string, defaultValue?: any | null, options?: any | null, settings?: any | null, isLabelSyncedWithName?: boolean | null, morphId?: string | null, applicationId: string, relation?: { __typename?: 'Relation', type: RelationType, sourceObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, targetObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, sourceFieldMetadata: { __typename?: 'Field', id: string, name: string }, targetFieldMetadata: { __typename?: 'Field', id: string, name: string } } | null, morphRelations?: Array<{ __typename?: 'Relation', type: RelationType, sourceObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, targetObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, sourceFieldMetadata: { __typename?: 'Field', id: string, name: string }, targetFieldMetadata: { __typename?: 'Field', id: string, name: string } }> | null }> }>, logicFunctions: Array<{ __typename?: 'LogicFunction', id: string, name: string, description?: string | null, runtime: string, timeoutSeconds: number, sourceHandlerPath: string, builtHandlerPath: string, handlerName: string, toolInputSchema?: any | null, isTool: boolean, applicationId?: string | null, createdAt: string, updatedAt: string }> };
|
||||
export type ApplicationFieldsFragment = { __typename?: 'Application', id: string, name: string, description: string, version: string, universalIdentifier: string, canBeUninstalled: boolean, availablePackages: any, applicationVariables: Array<{ __typename?: 'ApplicationVariable', id: string, key: string, value: string, description: string, isSecret: boolean }>, agents: Array<{ __typename?: 'Agent', id: string, name: string, label: string, description?: string | null, icon?: string | null, prompt: string, modelId: string, responseFormat?: any | null, roleId?: string | null, isCustom: boolean, modelConfiguration?: any | null, evaluationInputs: Array<string>, applicationId?: string | null, createdAt: string, updatedAt: string }>, objects: Array<{ __typename?: 'Object', id: string, nameSingular: string, namePlural: string, labelSingular: string, labelPlural: string, description?: string | null, icon?: string | null, isCustom: boolean, isRemote: boolean, isActive: boolean, isSystem: boolean, isUIReadOnly: boolean, createdAt: string, updatedAt: string, labelIdentifierFieldMetadataId?: string | null, imageIdentifierFieldMetadataId?: string | null, applicationId: string, shortcut?: string | null, isLabelSyncedWithName: boolean, isSearchable: boolean, duplicateCriteria?: Array<Array<string>> | null, indexMetadataList: Array<{ __typename?: 'Index', id: string, createdAt: string, updatedAt: string, name: string, indexWhereClause?: string | null, indexType: IndexType, isUnique: boolean, isCustom?: boolean | null, indexFieldMetadataList: Array<{ __typename?: 'IndexField', id: string, fieldMetadataId: string, createdAt: string, updatedAt: string, order: number }> }>, fieldsList: Array<{ __typename?: 'Field', id: string, type: FieldMetadataType, name: string, label: string, description?: string | null, icon?: string | null, isCustom?: boolean | null, isActive?: boolean | null, isSystem?: boolean | null, isUIReadOnly?: boolean | null, isNullable?: boolean | null, isUnique?: boolean | null, createdAt: string, updatedAt: string, defaultValue?: any | null, options?: any | null, settings?: any | null, isLabelSyncedWithName?: boolean | null, morphId?: string | null, applicationId: string, relation?: { __typename?: 'Relation', type: RelationType, sourceObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, targetObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, sourceFieldMetadata: { __typename?: 'Field', id: string, name: string }, targetFieldMetadata: { __typename?: 'Field', id: string, name: string } } | null, morphRelations?: Array<{ __typename?: 'Relation', type: RelationType, sourceObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, targetObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, sourceFieldMetadata: { __typename?: 'Field', id: string, name: string }, targetFieldMetadata: { __typename?: 'Field', id: string, name: string } }> | null }> }>, logicFunctions: Array<{ __typename?: 'LogicFunction', id: string, name: string, description?: string | null, runtime: string, timeoutSeconds: number, sourceHandlerPath: string, handlerName: string, toolInputSchema?: any | null, isTool: boolean, applicationId?: string | null, createdAt: string, updatedAt: string }> };
|
||||
|
||||
export type FindManyApplicationsQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
@@ -5252,7 +5271,7 @@ export type FindOneApplicationQueryVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type FindOneApplicationQuery = { __typename?: 'Query', findOneApplication: { __typename?: 'Application', id: string, name: string, description: string, version: string, universalIdentifier: string, canBeUninstalled: boolean, availablePackages: any, applicationVariables: Array<{ __typename?: 'ApplicationVariable', id: string, key: string, value: string, description: string, isSecret: boolean }>, agents: Array<{ __typename?: 'Agent', id: string, name: string, label: string, description?: string | null, icon?: string | null, prompt: string, modelId: string, responseFormat?: any | null, roleId?: string | null, isCustom: boolean, modelConfiguration?: any | null, evaluationInputs: Array<string>, applicationId?: string | null, createdAt: string, updatedAt: string }>, objects: Array<{ __typename?: 'Object', id: string, nameSingular: string, namePlural: string, labelSingular: string, labelPlural: string, description?: string | null, icon?: string | null, isCustom: boolean, isRemote: boolean, isActive: boolean, isSystem: boolean, isUIReadOnly: boolean, createdAt: string, updatedAt: string, labelIdentifierFieldMetadataId?: string | null, imageIdentifierFieldMetadataId?: string | null, applicationId: string, shortcut?: string | null, isLabelSyncedWithName: boolean, isSearchable: boolean, duplicateCriteria?: Array<Array<string>> | null, indexMetadataList: Array<{ __typename?: 'Index', id: string, createdAt: string, updatedAt: string, name: string, indexWhereClause?: string | null, indexType: IndexType, isUnique: boolean, isCustom?: boolean | null, indexFieldMetadataList: Array<{ __typename?: 'IndexField', id: string, fieldMetadataId: string, createdAt: string, updatedAt: string, order: number }> }>, fieldsList: Array<{ __typename?: 'Field', id: string, type: FieldMetadataType, name: string, label: string, description?: string | null, icon?: string | null, isCustom?: boolean | null, isActive?: boolean | null, isSystem?: boolean | null, isUIReadOnly?: boolean | null, isNullable?: boolean | null, isUnique?: boolean | null, createdAt: string, updatedAt: string, defaultValue?: any | null, options?: any | null, settings?: any | null, isLabelSyncedWithName?: boolean | null, morphId?: string | null, applicationId: string, relation?: { __typename?: 'Relation', type: RelationType, sourceObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, targetObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, sourceFieldMetadata: { __typename?: 'Field', id: string, name: string }, targetFieldMetadata: { __typename?: 'Field', id: string, name: string } } | null, morphRelations?: Array<{ __typename?: 'Relation', type: RelationType, sourceObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, targetObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, sourceFieldMetadata: { __typename?: 'Field', id: string, name: string }, targetFieldMetadata: { __typename?: 'Field', id: string, name: string } }> | null }> }>, logicFunctions: Array<{ __typename?: 'LogicFunction', id: string, name: string, description?: string | null, runtime: string, timeoutSeconds: number, sourceHandlerPath: string, builtHandlerPath: string, handlerName: string, toolInputSchema?: any | null, isTool: boolean, applicationId?: string | null, createdAt: string, updatedAt: string }> } };
|
||||
export type FindOneApplicationQuery = { __typename?: 'Query', findOneApplication: { __typename?: 'Application', id: string, name: string, description: string, version: string, universalIdentifier: string, canBeUninstalled: boolean, availablePackages: any, applicationVariables: Array<{ __typename?: 'ApplicationVariable', id: string, key: string, value: string, description: string, isSecret: boolean }>, agents: Array<{ __typename?: 'Agent', id: string, name: string, label: string, description?: string | null, icon?: string | null, prompt: string, modelId: string, responseFormat?: any | null, roleId?: string | null, isCustom: boolean, modelConfiguration?: any | null, evaluationInputs: Array<string>, applicationId?: string | null, createdAt: string, updatedAt: string }>, objects: Array<{ __typename?: 'Object', id: string, nameSingular: string, namePlural: string, labelSingular: string, labelPlural: string, description?: string | null, icon?: string | null, isCustom: boolean, isRemote: boolean, isActive: boolean, isSystem: boolean, isUIReadOnly: boolean, createdAt: string, updatedAt: string, labelIdentifierFieldMetadataId?: string | null, imageIdentifierFieldMetadataId?: string | null, applicationId: string, shortcut?: string | null, isLabelSyncedWithName: boolean, isSearchable: boolean, duplicateCriteria?: Array<Array<string>> | null, indexMetadataList: Array<{ __typename?: 'Index', id: string, createdAt: string, updatedAt: string, name: string, indexWhereClause?: string | null, indexType: IndexType, isUnique: boolean, isCustom?: boolean | null, indexFieldMetadataList: Array<{ __typename?: 'IndexField', id: string, fieldMetadataId: string, createdAt: string, updatedAt: string, order: number }> }>, fieldsList: Array<{ __typename?: 'Field', id: string, type: FieldMetadataType, name: string, label: string, description?: string | null, icon?: string | null, isCustom?: boolean | null, isActive?: boolean | null, isSystem?: boolean | null, isUIReadOnly?: boolean | null, isNullable?: boolean | null, isUnique?: boolean | null, createdAt: string, updatedAt: string, defaultValue?: any | null, options?: any | null, settings?: any | null, isLabelSyncedWithName?: boolean | null, morphId?: string | null, applicationId: string, relation?: { __typename?: 'Relation', type: RelationType, sourceObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, targetObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, sourceFieldMetadata: { __typename?: 'Field', id: string, name: string }, targetFieldMetadata: { __typename?: 'Field', id: string, name: string } } | null, morphRelations?: Array<{ __typename?: 'Relation', type: RelationType, sourceObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, targetObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, sourceFieldMetadata: { __typename?: 'Field', id: string, name: string }, targetFieldMetadata: { __typename?: 'Field', id: string, name: string } }> | null }> }>, logicFunctions: Array<{ __typename?: 'LogicFunction', id: string, name: string, description?: string | null, runtime: string, timeoutSeconds: number, sourceHandlerPath: string, handlerName: string, toolInputSchema?: any | null, isTool: boolean, applicationId?: string | null, createdAt: string, updatedAt: string }> } };
|
||||
|
||||
export type UploadFileMutationVariables = Exact<{
|
||||
file: Scalars['Upload'];
|
||||
@@ -5595,6 +5614,22 @@ export type UploadFilesFieldFileMutationVariables = Exact<{
|
||||
|
||||
export type UploadFilesFieldFileMutation = { __typename?: 'Mutation', uploadFilesFieldFile: { __typename?: 'File', id: string, path: string, size: number, createdAt: string } };
|
||||
|
||||
export type LogicFunctionFieldsFragment = { __typename?: 'LogicFunction', id: string, name: string, description?: string | null, runtime: string, timeoutSeconds: number, sourceHandlerPath: string, handlerName: string, toolInputSchema?: any | null, isTool: boolean, applicationId?: string | null, createdAt: string, updatedAt: string };
|
||||
|
||||
export type CreateOneLogicFunctionMutationVariables = Exact<{
|
||||
input: CreateLogicFunctionFromSourceInput;
|
||||
}>;
|
||||
|
||||
|
||||
export type CreateOneLogicFunctionMutation = { __typename?: 'Mutation', createOneLogicFunction: { __typename?: 'LogicFunction', id: string, name: string, description?: string | null, runtime: string, timeoutSeconds: number, sourceHandlerPath: string, handlerName: string, toolInputSchema?: any | null, isTool: boolean, applicationId?: string | null, createdAt: string, updatedAt: string } };
|
||||
|
||||
export type DeleteOneLogicFunctionMutationVariables = Exact<{
|
||||
input: LogicFunctionIdInput;
|
||||
}>;
|
||||
|
||||
|
||||
export type DeleteOneLogicFunctionMutation = { __typename?: 'Mutation', deleteOneLogicFunction: { __typename?: 'LogicFunction', id: string, name: string, description?: string | null, runtime: string, timeoutSeconds: number, sourceHandlerPath: string, handlerName: string, toolInputSchema?: any | null, isTool: boolean, applicationId?: string | null, createdAt: string, updatedAt: string } };
|
||||
|
||||
export type ExecuteOneLogicFunctionMutationVariables = Exact<{
|
||||
input: ExecuteOneLogicFunctionInput;
|
||||
}>;
|
||||
@@ -5602,19 +5637,38 @@ export type ExecuteOneLogicFunctionMutationVariables = Exact<{
|
||||
|
||||
export type ExecuteOneLogicFunctionMutation = { __typename?: 'Mutation', executeOneLogicFunction: { __typename?: 'LogicFunctionExecutionResult', data?: any | null, logs: string, duration: number, status: LogicFunctionExecutionStatus, error?: any | null } };
|
||||
|
||||
export type UpdateLogicFunctionSourceMutationVariables = Exact<{
|
||||
input: UpdateLogicFunctionSourceInput;
|
||||
export type UpdateOneLogicFunctionMutationVariables = Exact<{
|
||||
input: UpdateLogicFunctionFromSourceInput;
|
||||
}>;
|
||||
|
||||
|
||||
export type UpdateLogicFunctionSourceMutation = { __typename?: 'Mutation', updateLogicFunctionSource: boolean };
|
||||
export type UpdateOneLogicFunctionMutation = { __typename?: 'Mutation', updateOneLogicFunction: boolean };
|
||||
|
||||
export type FindManyAvailablePackagesQueryVariables = Exact<{
|
||||
input: LogicFunctionIdInput;
|
||||
}>;
|
||||
|
||||
|
||||
export type FindManyAvailablePackagesQuery = { __typename?: 'Query', getAvailablePackages: any };
|
||||
|
||||
export type FindManyLogicFunctionsQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type FindManyLogicFunctionsQuery = { __typename?: 'Query', findManyLogicFunctions: Array<{ __typename?: 'LogicFunction', id: string, name: string, description?: string | null, runtime: string, timeoutSeconds: number, sourceHandlerPath: string, handlerName: string, toolInputSchema?: any | null, isTool: boolean, applicationId?: string | null, createdAt: string, updatedAt: string }> };
|
||||
|
||||
export type FindOneLogicFunctionQueryVariables = Exact<{
|
||||
input: LogicFunctionIdInput;
|
||||
}>;
|
||||
|
||||
|
||||
export type FindOneLogicFunctionQuery = { __typename?: 'Query', findOneLogicFunction: { __typename?: 'LogicFunction', id: string, name: string, description?: string | null, runtime: string, timeoutSeconds: number, sourceHandlerPath: string, handlerName: string, toolInputSchema?: any | null, isTool: boolean, applicationId?: string | null, createdAt: string, updatedAt: string } };
|
||||
|
||||
export type GetLogicFunctionSourceCodeQueryVariables = Exact<{
|
||||
input: LogicFunctionIdInput;
|
||||
}>;
|
||||
|
||||
|
||||
export type GetLogicFunctionSourceCodeQuery = { __typename?: 'Query', getLogicFunctionSourceCode?: any | null };
|
||||
export type GetLogicFunctionSourceCodeQuery = { __typename?: 'Query', getLogicFunctionSourceCode?: string | null };
|
||||
|
||||
export type FindManyMarketplaceAppsQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
@@ -6026,41 +6080,6 @@ export type UpdateLabPublicFeatureFlagMutationVariables = Exact<{
|
||||
|
||||
export type UpdateLabPublicFeatureFlagMutation = { __typename?: 'Mutation', updateLabPublicFeatureFlag: { __typename?: 'FeatureFlagDTO', key: FeatureFlagKey, value: boolean } };
|
||||
|
||||
export type LogicFunctionFieldsFragment = { __typename?: 'LogicFunction', id: string, name: string, description?: string | null, runtime: string, timeoutSeconds: number, sourceHandlerPath: string, builtHandlerPath: string, handlerName: string, toolInputSchema?: any | null, isTool: boolean, applicationId?: string | null, createdAt: string, updatedAt: string };
|
||||
|
||||
export type CreateDefaultLogicFunctionItemMutationVariables = Exact<{
|
||||
input: CreateDefaultLogicFunctionInput;
|
||||
}>;
|
||||
|
||||
|
||||
export type CreateDefaultLogicFunctionItemMutation = { __typename?: 'Mutation', createDefaultLogicFunction: { __typename?: 'LogicFunction', id: string, name: string, description?: string | null, runtime: string, timeoutSeconds: number, sourceHandlerPath: string, builtHandlerPath: string, handlerName: string, toolInputSchema?: any | null, isTool: boolean, applicationId?: string | null, createdAt: string, updatedAt: string } };
|
||||
|
||||
export type DeleteOneLogicFunctionMutationVariables = Exact<{
|
||||
input: LogicFunctionIdInput;
|
||||
}>;
|
||||
|
||||
|
||||
export type DeleteOneLogicFunctionMutation = { __typename?: 'Mutation', deleteOneLogicFunction: { __typename?: 'LogicFunction', id: string, name: string, description?: string | null, runtime: string, timeoutSeconds: number, sourceHandlerPath: string, builtHandlerPath: string, handlerName: string, toolInputSchema?: any | null, isTool: boolean, applicationId?: string | null, createdAt: string, updatedAt: string } };
|
||||
|
||||
export type FindManyAvailablePackagesQueryVariables = Exact<{
|
||||
input: LogicFunctionIdInput;
|
||||
}>;
|
||||
|
||||
|
||||
export type FindManyAvailablePackagesQuery = { __typename?: 'Query', getAvailablePackages: any };
|
||||
|
||||
export type GetManyLogicFunctionsQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type GetManyLogicFunctionsQuery = { __typename?: 'Query', findManyLogicFunctions: Array<{ __typename?: 'LogicFunction', id: string, name: string, description?: string | null, runtime: string, timeoutSeconds: number, sourceHandlerPath: string, builtHandlerPath: string, handlerName: string, toolInputSchema?: any | null, isTool: boolean, applicationId?: string | null, createdAt: string, updatedAt: string }> };
|
||||
|
||||
export type GetOneLogicFunctionQueryVariables = Exact<{
|
||||
input: LogicFunctionIdInput;
|
||||
}>;
|
||||
|
||||
|
||||
export type GetOneLogicFunctionQuery = { __typename?: 'Query', findOneLogicFunction: { __typename?: 'LogicFunction', id: string, name: string, description?: string | null, runtime: string, timeoutSeconds: number, sourceHandlerPath: string, builtHandlerPath: string, handlerName: string, toolInputSchema?: any | null, isTool: boolean, applicationId?: string | null, createdAt: string, updatedAt: string } };
|
||||
|
||||
export type UploadWorkspaceMemberProfilePictureMutationVariables = Exact<{
|
||||
file: Scalars['Upload'];
|
||||
}>;
|
||||
@@ -6751,7 +6770,6 @@ export const LogicFunctionFieldsFragmentDoc = gql`
|
||||
runtime
|
||||
timeoutSeconds
|
||||
sourceHandlerPath
|
||||
builtHandlerPath
|
||||
handlerName
|
||||
toolInputSchema
|
||||
isTool
|
||||
@@ -10171,6 +10189,72 @@ export function useUploadFilesFieldFileMutation(baseOptions?: Apollo.MutationHoo
|
||||
export type UploadFilesFieldFileMutationHookResult = ReturnType<typeof useUploadFilesFieldFileMutation>;
|
||||
export type UploadFilesFieldFileMutationResult = Apollo.MutationResult<UploadFilesFieldFileMutation>;
|
||||
export type UploadFilesFieldFileMutationOptions = Apollo.BaseMutationOptions<UploadFilesFieldFileMutation, UploadFilesFieldFileMutationVariables>;
|
||||
export const CreateOneLogicFunctionDocument = gql`
|
||||
mutation CreateOneLogicFunction($input: CreateLogicFunctionFromSourceInput!) {
|
||||
createOneLogicFunction(input: $input) {
|
||||
...LogicFunctionFields
|
||||
}
|
||||
}
|
||||
${LogicFunctionFieldsFragmentDoc}`;
|
||||
export type CreateOneLogicFunctionMutationFn = Apollo.MutationFunction<CreateOneLogicFunctionMutation, CreateOneLogicFunctionMutationVariables>;
|
||||
|
||||
/**
|
||||
* __useCreateOneLogicFunctionMutation__
|
||||
*
|
||||
* To run a mutation, you first call `useCreateOneLogicFunctionMutation` within a React component and pass it any options that fit your needs.
|
||||
* When your component renders, `useCreateOneLogicFunctionMutation` returns a tuple that includes:
|
||||
* - A mutate function that you can call at any time to execute the mutation
|
||||
* - An object with fields that represent the current status of the mutation's execution
|
||||
*
|
||||
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
|
||||
*
|
||||
* @example
|
||||
* const [createOneLogicFunctionMutation, { data, loading, error }] = useCreateOneLogicFunctionMutation({
|
||||
* variables: {
|
||||
* input: // value for 'input'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useCreateOneLogicFunctionMutation(baseOptions?: Apollo.MutationHookOptions<CreateOneLogicFunctionMutation, CreateOneLogicFunctionMutationVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useMutation<CreateOneLogicFunctionMutation, CreateOneLogicFunctionMutationVariables>(CreateOneLogicFunctionDocument, options);
|
||||
}
|
||||
export type CreateOneLogicFunctionMutationHookResult = ReturnType<typeof useCreateOneLogicFunctionMutation>;
|
||||
export type CreateOneLogicFunctionMutationResult = Apollo.MutationResult<CreateOneLogicFunctionMutation>;
|
||||
export type CreateOneLogicFunctionMutationOptions = Apollo.BaseMutationOptions<CreateOneLogicFunctionMutation, CreateOneLogicFunctionMutationVariables>;
|
||||
export const DeleteOneLogicFunctionDocument = gql`
|
||||
mutation DeleteOneLogicFunction($input: LogicFunctionIdInput!) {
|
||||
deleteOneLogicFunction(input: $input) {
|
||||
...LogicFunctionFields
|
||||
}
|
||||
}
|
||||
${LogicFunctionFieldsFragmentDoc}`;
|
||||
export type DeleteOneLogicFunctionMutationFn = Apollo.MutationFunction<DeleteOneLogicFunctionMutation, DeleteOneLogicFunctionMutationVariables>;
|
||||
|
||||
/**
|
||||
* __useDeleteOneLogicFunctionMutation__
|
||||
*
|
||||
* To run a mutation, you first call `useDeleteOneLogicFunctionMutation` within a React component and pass it any options that fit your needs.
|
||||
* When your component renders, `useDeleteOneLogicFunctionMutation` returns a tuple that includes:
|
||||
* - A mutate function that you can call at any time to execute the mutation
|
||||
* - An object with fields that represent the current status of the mutation's execution
|
||||
*
|
||||
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
|
||||
*
|
||||
* @example
|
||||
* const [deleteOneLogicFunctionMutation, { data, loading, error }] = useDeleteOneLogicFunctionMutation({
|
||||
* variables: {
|
||||
* input: // value for 'input'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useDeleteOneLogicFunctionMutation(baseOptions?: Apollo.MutationHookOptions<DeleteOneLogicFunctionMutation, DeleteOneLogicFunctionMutationVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useMutation<DeleteOneLogicFunctionMutation, DeleteOneLogicFunctionMutationVariables>(DeleteOneLogicFunctionDocument, options);
|
||||
}
|
||||
export type DeleteOneLogicFunctionMutationHookResult = ReturnType<typeof useDeleteOneLogicFunctionMutation>;
|
||||
export type DeleteOneLogicFunctionMutationResult = Apollo.MutationResult<DeleteOneLogicFunctionMutation>;
|
||||
export type DeleteOneLogicFunctionMutationOptions = Apollo.BaseMutationOptions<DeleteOneLogicFunctionMutation, DeleteOneLogicFunctionMutationVariables>;
|
||||
export const ExecuteOneLogicFunctionDocument = gql`
|
||||
mutation ExecuteOneLogicFunction($input: ExecuteOneLogicFunctionInput!) {
|
||||
executeOneLogicFunction(input: $input) {
|
||||
@@ -10208,37 +10292,139 @@ export function useExecuteOneLogicFunctionMutation(baseOptions?: Apollo.Mutation
|
||||
export type ExecuteOneLogicFunctionMutationHookResult = ReturnType<typeof useExecuteOneLogicFunctionMutation>;
|
||||
export type ExecuteOneLogicFunctionMutationResult = Apollo.MutationResult<ExecuteOneLogicFunctionMutation>;
|
||||
export type ExecuteOneLogicFunctionMutationOptions = Apollo.BaseMutationOptions<ExecuteOneLogicFunctionMutation, ExecuteOneLogicFunctionMutationVariables>;
|
||||
export const UpdateLogicFunctionSourceDocument = gql`
|
||||
mutation UpdateLogicFunctionSource($input: UpdateLogicFunctionSourceInput!) {
|
||||
updateLogicFunctionSource(input: $input)
|
||||
export const UpdateOneLogicFunctionDocument = gql`
|
||||
mutation UpdateOneLogicFunction($input: UpdateLogicFunctionFromSourceInput!) {
|
||||
updateOneLogicFunction(input: $input)
|
||||
}
|
||||
`;
|
||||
export type UpdateLogicFunctionSourceMutationFn = Apollo.MutationFunction<UpdateLogicFunctionSourceMutation, UpdateLogicFunctionSourceMutationVariables>;
|
||||
export type UpdateOneLogicFunctionMutationFn = Apollo.MutationFunction<UpdateOneLogicFunctionMutation, UpdateOneLogicFunctionMutationVariables>;
|
||||
|
||||
/**
|
||||
* __useUpdateLogicFunctionSourceMutation__
|
||||
* __useUpdateOneLogicFunctionMutation__
|
||||
*
|
||||
* To run a mutation, you first call `useUpdateLogicFunctionSourceMutation` within a React component and pass it any options that fit your needs.
|
||||
* When your component renders, `useUpdateLogicFunctionSourceMutation` returns a tuple that includes:
|
||||
* To run a mutation, you first call `useUpdateOneLogicFunctionMutation` within a React component and pass it any options that fit your needs.
|
||||
* When your component renders, `useUpdateOneLogicFunctionMutation` returns a tuple that includes:
|
||||
* - A mutate function that you can call at any time to execute the mutation
|
||||
* - An object with fields that represent the current status of the mutation's execution
|
||||
*
|
||||
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
|
||||
*
|
||||
* @example
|
||||
* const [updateLogicFunctionSourceMutation, { data, loading, error }] = useUpdateLogicFunctionSourceMutation({
|
||||
* const [updateOneLogicFunctionMutation, { data, loading, error }] = useUpdateOneLogicFunctionMutation({
|
||||
* variables: {
|
||||
* input: // value for 'input'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useUpdateLogicFunctionSourceMutation(baseOptions?: Apollo.MutationHookOptions<UpdateLogicFunctionSourceMutation, UpdateLogicFunctionSourceMutationVariables>) {
|
||||
export function useUpdateOneLogicFunctionMutation(baseOptions?: Apollo.MutationHookOptions<UpdateOneLogicFunctionMutation, UpdateOneLogicFunctionMutationVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useMutation<UpdateLogicFunctionSourceMutation, UpdateLogicFunctionSourceMutationVariables>(UpdateLogicFunctionSourceDocument, options);
|
||||
return Apollo.useMutation<UpdateOneLogicFunctionMutation, UpdateOneLogicFunctionMutationVariables>(UpdateOneLogicFunctionDocument, options);
|
||||
}
|
||||
export type UpdateLogicFunctionSourceMutationHookResult = ReturnType<typeof useUpdateLogicFunctionSourceMutation>;
|
||||
export type UpdateLogicFunctionSourceMutationResult = Apollo.MutationResult<UpdateLogicFunctionSourceMutation>;
|
||||
export type UpdateLogicFunctionSourceMutationOptions = Apollo.BaseMutationOptions<UpdateLogicFunctionSourceMutation, UpdateLogicFunctionSourceMutationVariables>;
|
||||
export type UpdateOneLogicFunctionMutationHookResult = ReturnType<typeof useUpdateOneLogicFunctionMutation>;
|
||||
export type UpdateOneLogicFunctionMutationResult = Apollo.MutationResult<UpdateOneLogicFunctionMutation>;
|
||||
export type UpdateOneLogicFunctionMutationOptions = Apollo.BaseMutationOptions<UpdateOneLogicFunctionMutation, UpdateOneLogicFunctionMutationVariables>;
|
||||
export const FindManyAvailablePackagesDocument = gql`
|
||||
query FindManyAvailablePackages($input: LogicFunctionIdInput!) {
|
||||
getAvailablePackages(input: $input)
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useFindManyAvailablePackagesQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useFindManyAvailablePackagesQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useFindManyAvailablePackagesQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||
*
|
||||
* @example
|
||||
* const { data, loading, error } = useFindManyAvailablePackagesQuery({
|
||||
* variables: {
|
||||
* input: // value for 'input'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useFindManyAvailablePackagesQuery(baseOptions: Apollo.QueryHookOptions<FindManyAvailablePackagesQuery, FindManyAvailablePackagesQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<FindManyAvailablePackagesQuery, FindManyAvailablePackagesQueryVariables>(FindManyAvailablePackagesDocument, options);
|
||||
}
|
||||
export function useFindManyAvailablePackagesLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<FindManyAvailablePackagesQuery, FindManyAvailablePackagesQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<FindManyAvailablePackagesQuery, FindManyAvailablePackagesQueryVariables>(FindManyAvailablePackagesDocument, options);
|
||||
}
|
||||
export type FindManyAvailablePackagesQueryHookResult = ReturnType<typeof useFindManyAvailablePackagesQuery>;
|
||||
export type FindManyAvailablePackagesLazyQueryHookResult = ReturnType<typeof useFindManyAvailablePackagesLazyQuery>;
|
||||
export type FindManyAvailablePackagesQueryResult = Apollo.QueryResult<FindManyAvailablePackagesQuery, FindManyAvailablePackagesQueryVariables>;
|
||||
export const FindManyLogicFunctionsDocument = gql`
|
||||
query FindManyLogicFunctions {
|
||||
findManyLogicFunctions {
|
||||
...LogicFunctionFields
|
||||
}
|
||||
}
|
||||
${LogicFunctionFieldsFragmentDoc}`;
|
||||
|
||||
/**
|
||||
* __useFindManyLogicFunctionsQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useFindManyLogicFunctionsQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useFindManyLogicFunctionsQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||
*
|
||||
* @example
|
||||
* const { data, loading, error } = useFindManyLogicFunctionsQuery({
|
||||
* variables: {
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useFindManyLogicFunctionsQuery(baseOptions?: Apollo.QueryHookOptions<FindManyLogicFunctionsQuery, FindManyLogicFunctionsQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<FindManyLogicFunctionsQuery, FindManyLogicFunctionsQueryVariables>(FindManyLogicFunctionsDocument, options);
|
||||
}
|
||||
export function useFindManyLogicFunctionsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<FindManyLogicFunctionsQuery, FindManyLogicFunctionsQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<FindManyLogicFunctionsQuery, FindManyLogicFunctionsQueryVariables>(FindManyLogicFunctionsDocument, options);
|
||||
}
|
||||
export type FindManyLogicFunctionsQueryHookResult = ReturnType<typeof useFindManyLogicFunctionsQuery>;
|
||||
export type FindManyLogicFunctionsLazyQueryHookResult = ReturnType<typeof useFindManyLogicFunctionsLazyQuery>;
|
||||
export type FindManyLogicFunctionsQueryResult = Apollo.QueryResult<FindManyLogicFunctionsQuery, FindManyLogicFunctionsQueryVariables>;
|
||||
export const FindOneLogicFunctionDocument = gql`
|
||||
query FindOneLogicFunction($input: LogicFunctionIdInput!) {
|
||||
findOneLogicFunction(input: $input) {
|
||||
...LogicFunctionFields
|
||||
}
|
||||
}
|
||||
${LogicFunctionFieldsFragmentDoc}`;
|
||||
|
||||
/**
|
||||
* __useFindOneLogicFunctionQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useFindOneLogicFunctionQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useFindOneLogicFunctionQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||
*
|
||||
* @example
|
||||
* const { data, loading, error } = useFindOneLogicFunctionQuery({
|
||||
* variables: {
|
||||
* input: // value for 'input'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useFindOneLogicFunctionQuery(baseOptions: Apollo.QueryHookOptions<FindOneLogicFunctionQuery, FindOneLogicFunctionQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<FindOneLogicFunctionQuery, FindOneLogicFunctionQueryVariables>(FindOneLogicFunctionDocument, options);
|
||||
}
|
||||
export function useFindOneLogicFunctionLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<FindOneLogicFunctionQuery, FindOneLogicFunctionQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<FindOneLogicFunctionQuery, FindOneLogicFunctionQueryVariables>(FindOneLogicFunctionDocument, options);
|
||||
}
|
||||
export type FindOneLogicFunctionQueryHookResult = ReturnType<typeof useFindOneLogicFunctionQuery>;
|
||||
export type FindOneLogicFunctionLazyQueryHookResult = ReturnType<typeof useFindOneLogicFunctionLazyQuery>;
|
||||
export type FindOneLogicFunctionQueryResult = Apollo.QueryResult<FindOneLogicFunctionQuery, FindOneLogicFunctionQueryVariables>;
|
||||
export const GetLogicFunctionSourceCodeDocument = gql`
|
||||
query GetLogicFunctionSourceCode($input: LogicFunctionIdInput!) {
|
||||
getLogicFunctionSourceCode(input: $input)
|
||||
@@ -12583,174 +12769,6 @@ export function useUpdateLabPublicFeatureFlagMutation(baseOptions?: Apollo.Mutat
|
||||
export type UpdateLabPublicFeatureFlagMutationHookResult = ReturnType<typeof useUpdateLabPublicFeatureFlagMutation>;
|
||||
export type UpdateLabPublicFeatureFlagMutationResult = Apollo.MutationResult<UpdateLabPublicFeatureFlagMutation>;
|
||||
export type UpdateLabPublicFeatureFlagMutationOptions = Apollo.BaseMutationOptions<UpdateLabPublicFeatureFlagMutation, UpdateLabPublicFeatureFlagMutationVariables>;
|
||||
export const CreateDefaultLogicFunctionItemDocument = gql`
|
||||
mutation CreateDefaultLogicFunctionItem($input: CreateDefaultLogicFunctionInput!) {
|
||||
createDefaultLogicFunction(input: $input) {
|
||||
...LogicFunctionFields
|
||||
}
|
||||
}
|
||||
${LogicFunctionFieldsFragmentDoc}`;
|
||||
export type CreateDefaultLogicFunctionItemMutationFn = Apollo.MutationFunction<CreateDefaultLogicFunctionItemMutation, CreateDefaultLogicFunctionItemMutationVariables>;
|
||||
|
||||
/**
|
||||
* __useCreateDefaultLogicFunctionItemMutation__
|
||||
*
|
||||
* To run a mutation, you first call `useCreateDefaultLogicFunctionItemMutation` within a React component and pass it any options that fit your needs.
|
||||
* When your component renders, `useCreateDefaultLogicFunctionItemMutation` returns a tuple that includes:
|
||||
* - A mutate function that you can call at any time to execute the mutation
|
||||
* - An object with fields that represent the current status of the mutation's execution
|
||||
*
|
||||
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
|
||||
*
|
||||
* @example
|
||||
* const [createDefaultLogicFunctionItemMutation, { data, loading, error }] = useCreateDefaultLogicFunctionItemMutation({
|
||||
* variables: {
|
||||
* input: // value for 'input'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useCreateDefaultLogicFunctionItemMutation(baseOptions?: Apollo.MutationHookOptions<CreateDefaultLogicFunctionItemMutation, CreateDefaultLogicFunctionItemMutationVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useMutation<CreateDefaultLogicFunctionItemMutation, CreateDefaultLogicFunctionItemMutationVariables>(CreateDefaultLogicFunctionItemDocument, options);
|
||||
}
|
||||
export type CreateDefaultLogicFunctionItemMutationHookResult = ReturnType<typeof useCreateDefaultLogicFunctionItemMutation>;
|
||||
export type CreateDefaultLogicFunctionItemMutationResult = Apollo.MutationResult<CreateDefaultLogicFunctionItemMutation>;
|
||||
export type CreateDefaultLogicFunctionItemMutationOptions = Apollo.BaseMutationOptions<CreateDefaultLogicFunctionItemMutation, CreateDefaultLogicFunctionItemMutationVariables>;
|
||||
export const DeleteOneLogicFunctionDocument = gql`
|
||||
mutation DeleteOneLogicFunction($input: LogicFunctionIdInput!) {
|
||||
deleteOneLogicFunction(input: $input) {
|
||||
...LogicFunctionFields
|
||||
}
|
||||
}
|
||||
${LogicFunctionFieldsFragmentDoc}`;
|
||||
export type DeleteOneLogicFunctionMutationFn = Apollo.MutationFunction<DeleteOneLogicFunctionMutation, DeleteOneLogicFunctionMutationVariables>;
|
||||
|
||||
/**
|
||||
* __useDeleteOneLogicFunctionMutation__
|
||||
*
|
||||
* To run a mutation, you first call `useDeleteOneLogicFunctionMutation` within a React component and pass it any options that fit your needs.
|
||||
* When your component renders, `useDeleteOneLogicFunctionMutation` returns a tuple that includes:
|
||||
* - A mutate function that you can call at any time to execute the mutation
|
||||
* - An object with fields that represent the current status of the mutation's execution
|
||||
*
|
||||
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
|
||||
*
|
||||
* @example
|
||||
* const [deleteOneLogicFunctionMutation, { data, loading, error }] = useDeleteOneLogicFunctionMutation({
|
||||
* variables: {
|
||||
* input: // value for 'input'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useDeleteOneLogicFunctionMutation(baseOptions?: Apollo.MutationHookOptions<DeleteOneLogicFunctionMutation, DeleteOneLogicFunctionMutationVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useMutation<DeleteOneLogicFunctionMutation, DeleteOneLogicFunctionMutationVariables>(DeleteOneLogicFunctionDocument, options);
|
||||
}
|
||||
export type DeleteOneLogicFunctionMutationHookResult = ReturnType<typeof useDeleteOneLogicFunctionMutation>;
|
||||
export type DeleteOneLogicFunctionMutationResult = Apollo.MutationResult<DeleteOneLogicFunctionMutation>;
|
||||
export type DeleteOneLogicFunctionMutationOptions = Apollo.BaseMutationOptions<DeleteOneLogicFunctionMutation, DeleteOneLogicFunctionMutationVariables>;
|
||||
export const FindManyAvailablePackagesDocument = gql`
|
||||
query FindManyAvailablePackages($input: LogicFunctionIdInput!) {
|
||||
getAvailablePackages(input: $input)
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useFindManyAvailablePackagesQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useFindManyAvailablePackagesQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useFindManyAvailablePackagesQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||
*
|
||||
* @example
|
||||
* const { data, loading, error } = useFindManyAvailablePackagesQuery({
|
||||
* variables: {
|
||||
* input: // value for 'input'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useFindManyAvailablePackagesQuery(baseOptions: Apollo.QueryHookOptions<FindManyAvailablePackagesQuery, FindManyAvailablePackagesQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<FindManyAvailablePackagesQuery, FindManyAvailablePackagesQueryVariables>(FindManyAvailablePackagesDocument, options);
|
||||
}
|
||||
export function useFindManyAvailablePackagesLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<FindManyAvailablePackagesQuery, FindManyAvailablePackagesQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<FindManyAvailablePackagesQuery, FindManyAvailablePackagesQueryVariables>(FindManyAvailablePackagesDocument, options);
|
||||
}
|
||||
export type FindManyAvailablePackagesQueryHookResult = ReturnType<typeof useFindManyAvailablePackagesQuery>;
|
||||
export type FindManyAvailablePackagesLazyQueryHookResult = ReturnType<typeof useFindManyAvailablePackagesLazyQuery>;
|
||||
export type FindManyAvailablePackagesQueryResult = Apollo.QueryResult<FindManyAvailablePackagesQuery, FindManyAvailablePackagesQueryVariables>;
|
||||
export const GetManyLogicFunctionsDocument = gql`
|
||||
query GetManyLogicFunctions {
|
||||
findManyLogicFunctions {
|
||||
...LogicFunctionFields
|
||||
}
|
||||
}
|
||||
${LogicFunctionFieldsFragmentDoc}`;
|
||||
|
||||
/**
|
||||
* __useGetManyLogicFunctionsQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useGetManyLogicFunctionsQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useGetManyLogicFunctionsQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||
*
|
||||
* @example
|
||||
* const { data, loading, error } = useGetManyLogicFunctionsQuery({
|
||||
* variables: {
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useGetManyLogicFunctionsQuery(baseOptions?: Apollo.QueryHookOptions<GetManyLogicFunctionsQuery, GetManyLogicFunctionsQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<GetManyLogicFunctionsQuery, GetManyLogicFunctionsQueryVariables>(GetManyLogicFunctionsDocument, options);
|
||||
}
|
||||
export function useGetManyLogicFunctionsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<GetManyLogicFunctionsQuery, GetManyLogicFunctionsQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<GetManyLogicFunctionsQuery, GetManyLogicFunctionsQueryVariables>(GetManyLogicFunctionsDocument, options);
|
||||
}
|
||||
export type GetManyLogicFunctionsQueryHookResult = ReturnType<typeof useGetManyLogicFunctionsQuery>;
|
||||
export type GetManyLogicFunctionsLazyQueryHookResult = ReturnType<typeof useGetManyLogicFunctionsLazyQuery>;
|
||||
export type GetManyLogicFunctionsQueryResult = Apollo.QueryResult<GetManyLogicFunctionsQuery, GetManyLogicFunctionsQueryVariables>;
|
||||
export const GetOneLogicFunctionDocument = gql`
|
||||
query GetOneLogicFunction($input: LogicFunctionIdInput!) {
|
||||
findOneLogicFunction(input: $input) {
|
||||
...LogicFunctionFields
|
||||
}
|
||||
}
|
||||
${LogicFunctionFieldsFragmentDoc}`;
|
||||
|
||||
/**
|
||||
* __useGetOneLogicFunctionQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useGetOneLogicFunctionQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useGetOneLogicFunctionQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||
*
|
||||
* @example
|
||||
* const { data, loading, error } = useGetOneLogicFunctionQuery({
|
||||
* variables: {
|
||||
* input: // value for 'input'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useGetOneLogicFunctionQuery(baseOptions: Apollo.QueryHookOptions<GetOneLogicFunctionQuery, GetOneLogicFunctionQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<GetOneLogicFunctionQuery, GetOneLogicFunctionQueryVariables>(GetOneLogicFunctionDocument, options);
|
||||
}
|
||||
export function useGetOneLogicFunctionLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<GetOneLogicFunctionQuery, GetOneLogicFunctionQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<GetOneLogicFunctionQuery, GetOneLogicFunctionQueryVariables>(GetOneLogicFunctionDocument, options);
|
||||
}
|
||||
export type GetOneLogicFunctionQueryHookResult = ReturnType<typeof useGetOneLogicFunctionQuery>;
|
||||
export type GetOneLogicFunctionLazyQueryHookResult = ReturnType<typeof useGetOneLogicFunctionLazyQuery>;
|
||||
export type GetOneLogicFunctionQueryResult = Apollo.QueryResult<GetOneLogicFunctionQuery, GetOneLogicFunctionQueryVariables>;
|
||||
export const UploadWorkspaceMemberProfilePictureDocument = gql`
|
||||
mutation UploadWorkspaceMemberProfilePicture($file: Upload!) {
|
||||
uploadWorkspaceMemberProfilePicture(file: $file) {
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import { AGENT_FRAGMENT } from '@/ai/graphql/fragments/agentFragment';
|
||||
import { OBJECT_METADATA_FRAGMENT } from '@/object-metadata/graphql/fragment';
|
||||
import { LOGIC_FUNCTION_FRAGMENT } from '@/settings/logic-functions/graphql/fragments/logicFunctionFragment';
|
||||
import { LOGIC_FUNCTION_FRAGMENT } from '@/logic-functions/graphql/fragments/logicFunctionFragment';
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
export const APPLICATION_FRAGMENT = gql`
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export const INDEX_FILE_NAME = 'index.ts';
|
||||
@@ -1 +0,0 @@
|
||||
export const SOURCE_FOLDER_NAME = 'src';
|
||||
-1
@@ -8,7 +8,6 @@ export const LOGIC_FUNCTION_FRAGMENT = gql`
|
||||
runtime
|
||||
timeoutSeconds
|
||||
sourceHandlerPath
|
||||
builtHandlerPath
|
||||
handlerName
|
||||
toolInputSchema
|
||||
isTool
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import { gql } from '@apollo/client';
|
||||
import { LOGIC_FUNCTION_FRAGMENT } from '@/logic-functions/graphql/fragments/logicFunctionFragment';
|
||||
|
||||
export const CREATE_ONE_LOGIC_FUNCTION = gql`
|
||||
${LOGIC_FUNCTION_FRAGMENT}
|
||||
mutation CreateOneLogicFunction($input: CreateLogicFunctionFromSourceInput!) {
|
||||
createOneLogicFunction(input: $input) {
|
||||
...LogicFunctionFields
|
||||
}
|
||||
}
|
||||
`;
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { gql } from '@apollo/client';
|
||||
import { LOGIC_FUNCTION_FRAGMENT } from '@/settings/logic-functions/graphql/fragments/logicFunctionFragment';
|
||||
import { LOGIC_FUNCTION_FRAGMENT } from '@/logic-functions/graphql/fragments/logicFunctionFragment';
|
||||
|
||||
export const DELETE_ONE_LOGIC_FUNCTION = gql`
|
||||
${LOGIC_FUNCTION_FRAGMENT}
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
export const UPDATE_LOGIC_FUNCTION_SOURCE = gql`
|
||||
mutation UpdateLogicFunctionSource($input: UpdateLogicFunctionSourceInput!) {
|
||||
updateLogicFunctionSource(input: $input)
|
||||
}
|
||||
`;
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
export const UPDATE_ONE_LOGIC_FUNCTION = gql`
|
||||
mutation UpdateOneLogicFunction($input: UpdateLogicFunctionFromSourceInput!) {
|
||||
updateOneLogicFunction(input: $input)
|
||||
}
|
||||
`;
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
import { gql } from '@apollo/client';
|
||||
import { LOGIC_FUNCTION_FRAGMENT } from '@/settings/logic-functions/graphql/fragments/logicFunctionFragment';
|
||||
import { LOGIC_FUNCTION_FRAGMENT } from '@/logic-functions/graphql/fragments/logicFunctionFragment';
|
||||
|
||||
export const FIND_MANY_LOGIC_FUNCTIONS = gql`
|
||||
${LOGIC_FUNCTION_FRAGMENT}
|
||||
query GetManyLogicFunctions {
|
||||
query FindManyLogicFunctions {
|
||||
findManyLogicFunctions {
|
||||
...LogicFunctionFields
|
||||
}
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
import { gql } from '@apollo/client';
|
||||
import { LOGIC_FUNCTION_FRAGMENT } from '@/settings/logic-functions/graphql/fragments/logicFunctionFragment';
|
||||
import { LOGIC_FUNCTION_FRAGMENT } from '@/logic-functions/graphql/fragments/logicFunctionFragment';
|
||||
|
||||
export const FIND_ONE_LOGIC_FUNCTION = gql`
|
||||
${LOGIC_FUNCTION_FRAGMENT}
|
||||
query GetOneLogicFunction($input: LogicFunctionIdInput!) {
|
||||
query FindOneLogicFunction($input: LogicFunctionIdInput!) {
|
||||
findOneLogicFunction(input: $input) {
|
||||
...LogicFunctionFields
|
||||
}
|
||||
+19
-4
@@ -1,21 +1,36 @@
|
||||
import { useLogicFunctionUpdateFormState } from '@/settings/logic-functions/hooks/useLogicFunctionUpdateFormState';
|
||||
import { useLogicFunctionUpdateFormState } from '@/logic-functions/hooks/useLogicFunctionUpdateFormState';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { RecoilRoot } from 'recoil';
|
||||
|
||||
jest.mock('@/settings/logic-functions/hooks/useGetOneLogicFunction', () => ({
|
||||
jest.mock('@/logic-functions/hooks/useGetOneLogicFunction', () => ({
|
||||
useGetOneLogicFunction: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('@/logic-functions/hooks/useGetLogicFunctionSourceCode', () => ({
|
||||
useGetLogicFunctionSourceCode: jest.fn(),
|
||||
}));
|
||||
|
||||
const mockCode = 'export const main = async (): Promise<void> => { return; }';
|
||||
|
||||
describe('useLogicFunctionUpdateFormState', () => {
|
||||
test('should return a form', () => {
|
||||
const logicFunctionId = 'logicFunctionId';
|
||||
const useGetOneLogicFunctionMock = jest.requireMock(
|
||||
'@/settings/logic-functions/hooks/useGetOneLogicFunction',
|
||||
'@/logic-functions/hooks/useGetOneLogicFunction',
|
||||
);
|
||||
const useGetLogicFunctionSourceCodeMock = jest.requireMock(
|
||||
'@/logic-functions/hooks/useGetLogicFunctionSourceCode',
|
||||
);
|
||||
useGetOneLogicFunctionMock.useGetOneLogicFunction.mockReturnValue({
|
||||
logicFunction: { name: 'name' },
|
||||
loading: false,
|
||||
});
|
||||
useGetLogicFunctionSourceCodeMock.useGetLogicFunctionSourceCode.mockReturnValue(
|
||||
{
|
||||
code: mockCode,
|
||||
loading: false,
|
||||
},
|
||||
);
|
||||
const { result } = renderHook(
|
||||
() => useLogicFunctionUpdateFormState({ logicFunctionId }),
|
||||
{
|
||||
@@ -28,7 +43,7 @@ describe('useLogicFunctionUpdateFormState', () => {
|
||||
expect(formValues).toEqual({
|
||||
name: '',
|
||||
description: '',
|
||||
code: { src: { 'index.ts': '' } },
|
||||
code: mockCode,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,4 @@
|
||||
import { EXECUTE_ONE_LOGIC_FUNCTION } from '@/logic-functions/graphql/mutations/executeOneLogicFunction';
|
||||
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
|
||||
import { logicFunctionTestDataFamilyState } from '@/workflow/workflow-steps/workflow-actions/code-action/states/logicFunctionTestDataFamilyState';
|
||||
import { useMutation } from '@apollo/client';
|
||||
import { useState } from 'react';
|
||||
@@ -11,7 +10,6 @@ import { sleep } from '~/utils/sleep';
|
||||
type ExecuteOneLogicFunctionInput = {
|
||||
id: string;
|
||||
payload: object;
|
||||
forceRebuild?: boolean;
|
||||
};
|
||||
|
||||
type ExecuteOneLogicFunctionResult = {
|
||||
@@ -34,21 +32,16 @@ export const useExecuteLogicFunction = ({
|
||||
callback?: (result: object) => void;
|
||||
}) => {
|
||||
const [isExecuting, setIsExecuting] = useState(false);
|
||||
const apolloMetadataClient = useApolloCoreClient();
|
||||
const [executeOneLogicFunctionMutation] = useMutation<
|
||||
{ executeOneLogicFunction: ExecuteOneLogicFunctionResult },
|
||||
{ input: ExecuteOneLogicFunctionInput }
|
||||
>(EXECUTE_ONE_LOGIC_FUNCTION, {
|
||||
client: apolloMetadataClient,
|
||||
});
|
||||
>(EXECUTE_ONE_LOGIC_FUNCTION);
|
||||
|
||||
const [logicFunctionTestData, setLogicFunctionTestData] = useRecoilState(
|
||||
logicFunctionTestDataFamilyState(logicFunctionId),
|
||||
);
|
||||
|
||||
const executeLogicFunction = async ({
|
||||
forceRebuild = false,
|
||||
}: { forceRebuild?: boolean } = {}) => {
|
||||
const executeLogicFunction = async () => {
|
||||
try {
|
||||
setIsExecuting(true);
|
||||
await sleep(200); // Delay artificially to avoid flashing the UI
|
||||
@@ -57,7 +50,6 @@ export const useExecuteLogicFunction = ({
|
||||
input: {
|
||||
id: logicFunctionId,
|
||||
payload: logicFunctionTestData.input,
|
||||
forceRebuild,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
+1
-4
@@ -1,6 +1,5 @@
|
||||
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import { FIND_MANY_AVAILABLE_PACKAGES } from '@/settings/logic-functions/graphql/queries/findManyAvailablePackages';
|
||||
import { FIND_MANY_AVAILABLE_PACKAGES } from '@/logic-functions/graphql/queries/findManyAvailablePackages';
|
||||
import {
|
||||
type FindManyAvailablePackagesQuery,
|
||||
type FindManyAvailablePackagesQueryVariables,
|
||||
@@ -8,12 +7,10 @@ import {
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
export const useGetAvailablePackages = (input: LogicFunctionIdInput) => {
|
||||
const apolloMetadataClient = useApolloCoreClient();
|
||||
const { data } = useQuery<
|
||||
FindManyAvailablePackagesQuery,
|
||||
FindManyAvailablePackagesQueryVariables
|
||||
>(FIND_MANY_AVAILABLE_PACKAGES, {
|
||||
client: apolloMetadataClient ?? undefined,
|
||||
variables: {
|
||||
input,
|
||||
},
|
||||
+2
-12
@@ -1,7 +1,5 @@
|
||||
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
|
||||
import { GET_LOGIC_FUNCTION_SOURCE_CODE } from '@/logic-functions/graphql/queries/getLogicFunctionSourceCode';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import { type Sources } from 'twenty-shared/types';
|
||||
import {
|
||||
type GetLogicFunctionSourceCodeQuery,
|
||||
type GetLogicFunctionSourceCodeQueryVariables,
|
||||
@@ -11,24 +9,16 @@ export const useGetLogicFunctionSourceCode = ({
|
||||
logicFunctionId,
|
||||
}: {
|
||||
logicFunctionId: string;
|
||||
}): { code: Sources | null; loading: boolean } => {
|
||||
const apolloMetadataClient = useApolloCoreClient();
|
||||
}) => {
|
||||
const { data, loading } = useQuery<
|
||||
GetLogicFunctionSourceCodeQuery,
|
||||
GetLogicFunctionSourceCodeQueryVariables
|
||||
>(GET_LOGIC_FUNCTION_SOURCE_CODE, {
|
||||
client: apolloMetadataClient ?? undefined,
|
||||
variables: {
|
||||
input: { id: logicFunctionId },
|
||||
},
|
||||
skip: !logicFunctionId,
|
||||
});
|
||||
|
||||
const raw = data?.getLogicFunctionSourceCode;
|
||||
const code =
|
||||
raw != null && typeof raw === 'object' && !Array.isArray(raw)
|
||||
? (raw as Sources)
|
||||
: null;
|
||||
|
||||
return { code, loading };
|
||||
return { code: data?.getLogicFunctionSourceCode, loading };
|
||||
};
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import { FIND_ONE_LOGIC_FUNCTION } from '@/logic-functions/graphql/queries/findOneLogicFunction';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import {
|
||||
type FindOneLogicFunctionQuery,
|
||||
type FindOneLogicFunctionQueryVariables,
|
||||
type LogicFunctionIdInput,
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
export const useGetOneLogicFunction = ({
|
||||
id,
|
||||
onCompleted,
|
||||
}: LogicFunctionIdInput & {
|
||||
onCompleted?: (data: FindOneLogicFunctionQuery) => void;
|
||||
}) => {
|
||||
const { data, loading } = useQuery<
|
||||
FindOneLogicFunctionQuery,
|
||||
FindOneLogicFunctionQueryVariables
|
||||
>(FIND_ONE_LOGIC_FUNCTION, {
|
||||
variables: {
|
||||
input: { id },
|
||||
},
|
||||
onCompleted,
|
||||
});
|
||||
return {
|
||||
logicFunction: data?.findOneLogicFunction || null,
|
||||
loading,
|
||||
};
|
||||
};
|
||||
+19
-8
@@ -1,11 +1,11 @@
|
||||
import { useGetOneLogicFunction } from '@/settings/logic-functions/hooks/useGetOneLogicFunction';
|
||||
import { type Dispatch, type SetStateAction, useState } from 'react';
|
||||
import { type Sources } from 'twenty-shared/types';
|
||||
import { useGetOneLogicFunction } from '@/logic-functions/hooks/useGetOneLogicFunction';
|
||||
import { type Dispatch, type SetStateAction, useEffect, useState } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import {
|
||||
type GetOneLogicFunctionQuery,
|
||||
type FindOneLogicFunctionQuery,
|
||||
type LogicFunction,
|
||||
} from '~/generated-metadata/graphql';
|
||||
import { useGetLogicFunctionSourceCode } from '@/logic-functions/hooks/useGetLogicFunctionSourceCode';
|
||||
|
||||
export type LogicFunctionNewFormValues = {
|
||||
name: string;
|
||||
@@ -13,7 +13,7 @@ export type LogicFunctionNewFormValues = {
|
||||
};
|
||||
|
||||
export type LogicFunctionFormValues = LogicFunctionNewFormValues & {
|
||||
code: Sources;
|
||||
code: string;
|
||||
};
|
||||
|
||||
type SetLogicFunctionFormValues = Dispatch<
|
||||
@@ -33,13 +33,18 @@ export const useLogicFunctionUpdateFormState = ({
|
||||
const [formValues, setFormValues] = useState<LogicFunctionFormValues>({
|
||||
name: '',
|
||||
description: '',
|
||||
code: { src: { 'index.ts': '' } },
|
||||
code: '',
|
||||
});
|
||||
|
||||
const { code: codeFromApi, loading: logicFunctionSourceCodeLoading } =
|
||||
useGetLogicFunctionSourceCode({
|
||||
logicFunctionId,
|
||||
});
|
||||
|
||||
const { logicFunction, loading: logicFunctionLoading } =
|
||||
useGetOneLogicFunction({
|
||||
id: logicFunctionId,
|
||||
onCompleted: (data: GetOneLogicFunctionQuery) => {
|
||||
onCompleted: (data: FindOneLogicFunctionQuery) => {
|
||||
const fn = data?.findOneLogicFunction;
|
||||
|
||||
if (isDefined(fn)) {
|
||||
@@ -52,10 +57,16 @@ export const useLogicFunctionUpdateFormState = ({
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (isDefined(codeFromApi)) {
|
||||
setFormValues((prev) => ({ ...prev, code: codeFromApi }));
|
||||
}
|
||||
}, [codeFromApi]);
|
||||
|
||||
return {
|
||||
formValues,
|
||||
setFormValues,
|
||||
logicFunction,
|
||||
loading: logicFunctionLoading,
|
||||
loading: logicFunctionLoading || logicFunctionSourceCodeLoading,
|
||||
};
|
||||
};
|
||||
+24
-38
@@ -1,65 +1,55 @@
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { UPDATE_LOGIC_FUNCTION_SOURCE } from '@/logic-functions/graphql/mutations/updateLogicFunctionSource';
|
||||
import { UPDATE_ONE_LOGIC_FUNCTION } from '@/logic-functions/graphql/mutations/updateOneLogicFunction';
|
||||
import { GET_LOGIC_FUNCTION_SOURCE_CODE } from '@/logic-functions/graphql/queries/getLogicFunctionSourceCode';
|
||||
import { useMetadataErrorHandler } from '@/metadata-error-handler/hooks/useMetadataErrorHandler';
|
||||
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
|
||||
import { type MetadataRequestResult } from '@/object-metadata/types/MetadataRequestResult.type';
|
||||
import { CREATE_DEFAULT_LOGIC_FUNCTION } from '@/settings/logic-functions/graphql/mutations/createDefaultLogicFunction';
|
||||
import { DELETE_ONE_LOGIC_FUNCTION } from '@/settings/logic-functions/graphql/mutations/deleteOneLogicFunction';
|
||||
import { FIND_MANY_LOGIC_FUNCTIONS } from '@/settings/logic-functions/graphql/queries/findManyLogicFunctions';
|
||||
import { CREATE_ONE_LOGIC_FUNCTION } from '@/logic-functions/graphql/mutations/createOneLogicFunction';
|
||||
import { DELETE_ONE_LOGIC_FUNCTION } from '@/logic-functions/graphql/mutations/deleteOneLogicFunction';
|
||||
import { FIND_MANY_LOGIC_FUNCTIONS } from '@/logic-functions/graphql/queries/findManyLogicFunctions';
|
||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||
import { ApolloError, useMutation } from '@apollo/client';
|
||||
import { getOperationName } from '@apollo/client/utilities';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { type Sources, CrudOperationType } from 'twenty-shared/types';
|
||||
import { CrudOperationType } from 'twenty-shared/types';
|
||||
import {
|
||||
type CreateDefaultLogicFunctionItemMutation,
|
||||
type CreateDefaultLogicFunctionItemMutationVariables,
|
||||
type CreateOneLogicFunctionMutation,
|
||||
type CreateOneLogicFunctionMutationVariables,
|
||||
type DeleteOneLogicFunctionMutation,
|
||||
type DeleteOneLogicFunctionMutationVariables,
|
||||
type UpdateOneLogicFunctionMutation,
|
||||
type UpdateOneLogicFunctionMutationVariables,
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
type UpdateLogicFunctionSourceMutationVariables = {
|
||||
input: { id: string; code: Sources };
|
||||
};
|
||||
|
||||
export const usePersistLogicFunction = () => {
|
||||
const apolloMetadataClient = useApolloCoreClient();
|
||||
const { handleMetadataError } = useMetadataErrorHandler();
|
||||
const { enqueueErrorSnackBar } = useSnackBar();
|
||||
|
||||
const [createDefaultLogicFunctionMutation] = useMutation<
|
||||
CreateDefaultLogicFunctionItemMutation,
|
||||
CreateDefaultLogicFunctionItemMutationVariables
|
||||
>(CREATE_DEFAULT_LOGIC_FUNCTION, {
|
||||
client: apolloMetadataClient,
|
||||
});
|
||||
const [createLogicFunctionMutation] = useMutation<
|
||||
CreateOneLogicFunctionMutation,
|
||||
CreateOneLogicFunctionMutationVariables
|
||||
>(CREATE_ONE_LOGIC_FUNCTION);
|
||||
|
||||
const [deleteLogicFunctionMutation] = useMutation<
|
||||
DeleteOneLogicFunctionMutation,
|
||||
DeleteOneLogicFunctionMutationVariables
|
||||
>(DELETE_ONE_LOGIC_FUNCTION, {
|
||||
client: apolloMetadataClient,
|
||||
});
|
||||
>(DELETE_ONE_LOGIC_FUNCTION);
|
||||
|
||||
const [updateLogicFunctionSourceMutation] = useMutation<
|
||||
{ updateLogicFunctionSource: boolean },
|
||||
UpdateLogicFunctionSourceMutationVariables
|
||||
>(UPDATE_LOGIC_FUNCTION_SOURCE, {
|
||||
client: apolloMetadataClient,
|
||||
});
|
||||
UpdateOneLogicFunctionMutation,
|
||||
UpdateOneLogicFunctionMutationVariables
|
||||
>(UPDATE_ONE_LOGIC_FUNCTION);
|
||||
|
||||
const createLogicFunction = useCallback(
|
||||
async (
|
||||
variables: CreateDefaultLogicFunctionItemMutationVariables,
|
||||
variables: CreateOneLogicFunctionMutationVariables,
|
||||
): Promise<
|
||||
MetadataRequestResult<
|
||||
Awaited<ReturnType<typeof createDefaultLogicFunctionMutation>>
|
||||
Awaited<ReturnType<typeof createLogicFunctionMutation>>
|
||||
>
|
||||
> => {
|
||||
try {
|
||||
const result = await createDefaultLogicFunctionMutation({
|
||||
const result = await createLogicFunctionMutation({
|
||||
variables,
|
||||
awaitRefetchQueries: true,
|
||||
refetchQueries: [getOperationName(FIND_MANY_LOGIC_FUNCTIONS) ?? ''],
|
||||
@@ -85,16 +75,12 @@ export const usePersistLogicFunction = () => {
|
||||
};
|
||||
}
|
||||
},
|
||||
[
|
||||
createDefaultLogicFunctionMutation,
|
||||
handleMetadataError,
|
||||
enqueueErrorSnackBar,
|
||||
],
|
||||
[createLogicFunctionMutation, handleMetadataError, enqueueErrorSnackBar],
|
||||
);
|
||||
|
||||
const updateLogicFunctionSource = useCallback(
|
||||
const updateLogicFunction = useCallback(
|
||||
async (
|
||||
variables: UpdateLogicFunctionSourceMutationVariables,
|
||||
variables: UpdateOneLogicFunctionMutationVariables,
|
||||
): Promise<
|
||||
MetadataRequestResult<
|
||||
Awaited<ReturnType<typeof updateLogicFunctionSourceMutation>>
|
||||
@@ -174,7 +160,7 @@ export const usePersistLogicFunction = () => {
|
||||
|
||||
return {
|
||||
createLogicFunction,
|
||||
updateLogicFunctionSource,
|
||||
updateLogicFunction,
|
||||
deleteLogicFunction,
|
||||
};
|
||||
};
|
||||
|
||||
-146
@@ -1,146 +0,0 @@
|
||||
import { computeNewSources } from '@/logic-functions/utils/computeNewSources';
|
||||
|
||||
describe('computeNewSources', () => {
|
||||
it('should compute new code input root 0', () => {
|
||||
const previousCodeInput = {
|
||||
'index.ts': 'export const toto = () => {}',
|
||||
};
|
||||
|
||||
const filePath = 'index.ts';
|
||||
|
||||
const value = 'export const totoUpdated = () => {}';
|
||||
|
||||
const expectedResult = {
|
||||
'index.ts': 'export const totoUpdated = () => {}',
|
||||
};
|
||||
|
||||
expect(
|
||||
computeNewSources({ previousCode: previousCodeInput, filePath, value }),
|
||||
).toEqual(expectedResult);
|
||||
});
|
||||
|
||||
it('should compute new code input root 0 file changed', () => {
|
||||
const previousCodeInput = {
|
||||
'.env': 'ENV=env',
|
||||
'index.ts': 'export const toto = () => {}',
|
||||
};
|
||||
|
||||
const filePath = '.env';
|
||||
|
||||
const value = 'ENV=env\nENV2=env2';
|
||||
|
||||
const expectedResult = {
|
||||
'.env': 'ENV=env\nENV2=env2',
|
||||
'index.ts': 'export const toto = () => {}',
|
||||
};
|
||||
|
||||
expect(
|
||||
computeNewSources({ previousCode: previousCodeInput, filePath, value }),
|
||||
).toEqual(expectedResult);
|
||||
});
|
||||
|
||||
it('should compute new code input root 0 with multiple files', () => {
|
||||
const previousCodeInput = {
|
||||
'index.ts': 'export const toto = () => {}',
|
||||
'.env': 'ENV',
|
||||
};
|
||||
|
||||
const filePath = 'index.ts';
|
||||
|
||||
const value = 'export const totoUpdated = () => {}';
|
||||
|
||||
const expectedResult = {
|
||||
'index.ts': 'export const totoUpdated = () => {}',
|
||||
'.env': 'ENV',
|
||||
};
|
||||
|
||||
expect(
|
||||
computeNewSources({ previousCode: previousCodeInput, filePath, value }),
|
||||
).toEqual(expectedResult);
|
||||
});
|
||||
|
||||
it('should compute new code input root 1', () => {
|
||||
const previousCodeInput = {
|
||||
src: { 'index.ts': 'export const toto = () => {}' },
|
||||
};
|
||||
|
||||
const filePath = 'src/index.ts';
|
||||
|
||||
const value = 'export const totoUpdated = () => {}';
|
||||
|
||||
const expectedResult = {
|
||||
src: { 'index.ts': 'export const totoUpdated = () => {}' },
|
||||
};
|
||||
|
||||
expect(
|
||||
computeNewSources({ previousCode: previousCodeInput, filePath, value }),
|
||||
).toEqual(expectedResult);
|
||||
});
|
||||
|
||||
it('should compute new code input root 1 with multiple files', () => {
|
||||
const previousCodeInput = {
|
||||
src: {
|
||||
'index.ts': 'export const toto = () => {}',
|
||||
'index2.ts': 'export const toto2 = () => {}',
|
||||
},
|
||||
};
|
||||
|
||||
const filePath = 'src/index.ts';
|
||||
|
||||
const value = 'export const totoUpdated = () => {}';
|
||||
|
||||
const expectedResult = {
|
||||
src: {
|
||||
'index.ts': 'export const totoUpdated = () => {}',
|
||||
'index2.ts': 'export const toto2 = () => {}',
|
||||
},
|
||||
};
|
||||
|
||||
expect(
|
||||
computeNewSources({ previousCode: previousCodeInput, filePath, value }),
|
||||
).toEqual(expectedResult);
|
||||
});
|
||||
|
||||
it('should compute new code input root 1 with added files', () => {
|
||||
const previousCodeInput = {
|
||||
src: {
|
||||
'index.ts': 'export const toto = () => {}',
|
||||
},
|
||||
};
|
||||
|
||||
const filePath = 'src/index2.ts';
|
||||
|
||||
const value = 'export const toto2 = () => {}';
|
||||
|
||||
const expectedResult = {
|
||||
src: {
|
||||
'index.ts': 'export const toto = () => {}',
|
||||
'index2.ts': 'export const toto2 = () => {}',
|
||||
},
|
||||
};
|
||||
|
||||
expect(
|
||||
computeNewSources({ previousCode: previousCodeInput, filePath, value }),
|
||||
).toEqual(expectedResult);
|
||||
});
|
||||
|
||||
it('should compute new code input multiple roots', () => {
|
||||
const previousCodeInput = {
|
||||
'.env': 'ENV=env',
|
||||
src: { 'index.ts': 'export const toto = () => {}' },
|
||||
};
|
||||
|
||||
const filePath = 'src/index.ts';
|
||||
|
||||
const value = 'export const totoUpdated = () => {}';
|
||||
|
||||
const expectedResult = {
|
||||
src: { 'index.ts': 'export const totoUpdated = () => {}' },
|
||||
'.env': 'ENV=env',
|
||||
};
|
||||
|
||||
expect(
|
||||
computeNewSources({ previousCode: previousCodeInput, filePath, value }),
|
||||
).toEqual(expectedResult);
|
||||
});
|
||||
});
|
||||
-59
@@ -1,59 +0,0 @@
|
||||
// IA Generated
|
||||
|
||||
import { flattenSources } from '@/logic-functions/utils/flattenSources';
|
||||
import { type Sources } from 'twenty-shared/types';
|
||||
|
||||
describe('flattenSources', () => {
|
||||
it('flattens nested sources with root files', () => {
|
||||
const input: Sources = {
|
||||
'.env': 'KEY=VALUE',
|
||||
src: {
|
||||
'index.ts': 'export const a = 1',
|
||||
lib: {
|
||||
'util.ts': 'export const util = () => {}',
|
||||
},
|
||||
},
|
||||
docs: {
|
||||
'README.md': '# Hello',
|
||||
},
|
||||
};
|
||||
|
||||
const result = flattenSources(input);
|
||||
|
||||
expect(result).toEqual([
|
||||
{ path: '.env', content: 'KEY=VALUE' },
|
||||
{ path: 'docs/README.md', content: '# Hello' },
|
||||
{ path: 'src/index.ts', content: 'export const a = 1' },
|
||||
{ path: 'src/lib/util.ts', content: 'export const util = () => {}' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('handles deep nesting and preserves file contents', () => {
|
||||
const input: Sources = {
|
||||
a: { b: { c: { d: { 'file.ts': 'content' } } } },
|
||||
};
|
||||
|
||||
expect(flattenSources(input)).toEqual([
|
||||
{ path: 'a/b/c/d/file.ts', content: 'content' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('ignores empty folders and non-string leaves', () => {
|
||||
const input: Sources = {
|
||||
empty: {},
|
||||
weird: {
|
||||
oops: 42,
|
||||
} as unknown as Sources,
|
||||
file: 'ok',
|
||||
};
|
||||
|
||||
const res = flattenSources(input);
|
||||
expect(res).toEqual([{ path: 'file', content: 'ok' }]);
|
||||
});
|
||||
|
||||
it('accepts a custom basePath prefix', () => {
|
||||
const input: Sources = { src: { 'index.ts': 'x' } };
|
||||
const res = flattenSources(input, 'pkg');
|
||||
expect(res).toEqual([{ path: 'pkg/src/index.ts', content: 'x' }]);
|
||||
});
|
||||
});
|
||||
@@ -1,48 +0,0 @@
|
||||
import { type Sources } from 'twenty-shared/types';
|
||||
|
||||
export const computeNewSources = ({
|
||||
previousCode,
|
||||
filePath,
|
||||
value,
|
||||
}: {
|
||||
previousCode: Sources;
|
||||
filePath: string;
|
||||
value: string;
|
||||
}): Sources => {
|
||||
const result = { ...previousCode };
|
||||
|
||||
const parts = filePath.split('/').filter(Boolean);
|
||||
|
||||
if (parts.length === 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (parts.length === 1) {
|
||||
result[filePath] = value;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const [root, ...rest] = parts;
|
||||
|
||||
const newFilePath = rest.join('/');
|
||||
|
||||
if (
|
||||
typeof result?.[root] === 'string' ||
|
||||
typeof previousCode[root] === 'string'
|
||||
) {
|
||||
throw Error('Cannot compute new code input');
|
||||
}
|
||||
|
||||
return {
|
||||
...previousCode,
|
||||
[root]: {
|
||||
...previousCode[root],
|
||||
...computeNewSources({
|
||||
previousCode: result?.[root] ?? {},
|
||||
filePath: newFilePath,
|
||||
value,
|
||||
}),
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -1,28 +0,0 @@
|
||||
// IA Generated
|
||||
import { type Sources } from 'twenty-shared/types';
|
||||
|
||||
type FlatSource = { path: string; content: string };
|
||||
|
||||
export const flattenSources = (
|
||||
sources: Sources,
|
||||
basePath = '',
|
||||
): FlatSource[] => {
|
||||
const out: FlatSource[] = [];
|
||||
|
||||
const join = (a: string, b: string) => (a ? `${a}/${b}` : b);
|
||||
|
||||
const walk = (node: Sources, prefix: string) => {
|
||||
for (const [name, value] of Object.entries(node)) {
|
||||
if (typeof value === 'string') {
|
||||
out.push({ path: join(prefix, name), content: value });
|
||||
} else if (value && typeof value === 'object') {
|
||||
walk(value as Sources, join(prefix, name));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
walk(sources, basePath);
|
||||
|
||||
out.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));
|
||||
return out;
|
||||
};
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { useGetAvailablePackages } from '@/settings/logic-functions/hooks/useGetAvailablePackages';
|
||||
import { useGetAvailablePackages } from '@/logic-functions/hooks/useGetAvailablePackages';
|
||||
import { type EditorProps, type Monaco } from '@monaco-editor/react';
|
||||
import { type editor } from 'monaco-editor';
|
||||
import { AutoTypings } from 'monaco-editor-auto-typings';
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { type LogicFunctionNewFormValues } from '@/settings/logic-functions/hooks/useLogicFunctionUpdateFormState';
|
||||
import { type LogicFunctionNewFormValues } from '@/logic-functions/hooks/useLogicFunctionUpdateFormState';
|
||||
import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput';
|
||||
import { TextArea } from '@/ui/input/components/TextArea';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
-12
@@ -21,13 +21,11 @@ export const SettingsLogicFunctionCodeEditorTab = ({
|
||||
handleExecute,
|
||||
onChange,
|
||||
isTesting = false,
|
||||
isManaged = false,
|
||||
}: {
|
||||
files: File[];
|
||||
handleExecute: () => void;
|
||||
onChange: (filePath: string, value: string) => void;
|
||||
isTesting?: boolean;
|
||||
isManaged?: boolean;
|
||||
}) => {
|
||||
const activeTabId = useRecoilComponentValue(
|
||||
activeTabIdComponentState,
|
||||
@@ -68,16 +66,6 @@ export const SettingsLogicFunctionCodeEditorTab = ({
|
||||
onChange={(newCodeValue: string) =>
|
||||
onChange(activeTabId, newCodeValue)
|
||||
}
|
||||
options={
|
||||
isManaged
|
||||
? {
|
||||
readOnly: true,
|
||||
readOnlyMessage: {
|
||||
value: t`Managed logic functions are not editable`,
|
||||
},
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</Section>
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import { SettingsLogicFunctionNewForm } from '@/settings/logic-functions/components/SettingsLogicFunctionNewForm';
|
||||
import { SettingsLogicFunctionTabEnvironmentVariablesSection } from '@/settings/logic-functions/components/SettingsLogicFunctionTabEnvironmentVariablesSection';
|
||||
import { type LogicFunctionFormValues } from '@/settings/logic-functions/hooks/useLogicFunctionUpdateFormState';
|
||||
import { type LogicFunctionFormValues } from '@/logic-functions/hooks/useLogicFunctionUpdateFormState';
|
||||
|
||||
export const SettingsLogicFunctionSettingsTab = ({
|
||||
formValues,
|
||||
|
||||
+58
-49
@@ -5,21 +5,24 @@ import { TableHeader } from '@/ui/layout/table/components/TableHeader';
|
||||
import { TableRow } from '@/ui/layout/table/components/TableRow';
|
||||
import styled from '@emotion/styled';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { H2Title } from 'twenty-ui/display';
|
||||
import { H2Title, OverflowingTextWithTooltip } from 'twenty-ui/display';
|
||||
import { Section } from 'twenty-ui/layout';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { TableCell } from '@/ui/layout/table/components/TableCell';
|
||||
import { REACT_APP_SERVER_BASE_URL } from '~/config';
|
||||
import { Tag } from 'twenty-ui/components';
|
||||
import { type LogicFunction } from '~/generated-metadata/graphql';
|
||||
|
||||
export const StyledRouteTriggerTableRow = styled(TableRow)`
|
||||
grid-template-columns: 1fr 120px 120px;
|
||||
`;
|
||||
|
||||
// TODO: @Charles put back with new sources
|
||||
// const StyledTableCell = styled(TableCell)`
|
||||
// color: ${({ theme }) => theme.font.color.tertiary};
|
||||
// gap: ${({ theme }) => theme.spacing(2)};
|
||||
// min-width: 0;
|
||||
// overflow: hidden;
|
||||
// `;
|
||||
const StyledTableCell = styled(TableCell)`
|
||||
color: ${({ theme }) => theme.font.color.tertiary};
|
||||
gap: ${({ theme }) => theme.spacing(2)};
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
`;
|
||||
|
||||
const StyledRouteTriggerTableHeaderRow = styled(StyledRouteTriggerTableRow)`
|
||||
margin-bottom: ${({ theme }) => theme.spacing(2)};
|
||||
@@ -36,22 +39,31 @@ const StyledEmptyState = styled.div`
|
||||
`;
|
||||
|
||||
export const SettingsLogicFunctionTriggersTab = ({
|
||||
logicFunction: _logicFunction,
|
||||
logicFunction,
|
||||
}: {
|
||||
logicFunction: LogicFunction;
|
||||
}) => {
|
||||
const { t } = useLingui();
|
||||
|
||||
const cronTriggers: [] = [];
|
||||
const cronTrigger = logicFunction.cronTriggerSettings;
|
||||
|
||||
const routeTriggers: [] = [];
|
||||
const routeTrigger = logicFunction.httpRouteTriggerSettings;
|
||||
|
||||
const databaseEvents: [] = [];
|
||||
const databaseEventTriggerSettings =
|
||||
logicFunction.databaseEventTriggerSettings;
|
||||
|
||||
const hasNoTriggers =
|
||||
databaseEvents.length === 0 &&
|
||||
cronTriggers.length === 0 &&
|
||||
routeTriggers.length === 0;
|
||||
let databaseEventTrigger = undefined;
|
||||
|
||||
if (isDefined(databaseEventTriggerSettings)) {
|
||||
const [object, action]: [string, string] =
|
||||
databaseEventTriggerSettings.eventName.split('.');
|
||||
databaseEventTrigger = {
|
||||
object,
|
||||
action,
|
||||
updatedFields: databaseEventTriggerSettings.updatedFields,
|
||||
};
|
||||
}
|
||||
const hasNoTriggers = !cronTrigger && !routeTrigger && !databaseEventTrigger;
|
||||
|
||||
if (hasNoTriggers) {
|
||||
return (
|
||||
@@ -69,37 +81,37 @@ export const SettingsLogicFunctionTriggersTab = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
{databaseEvents.length > 0 && (
|
||||
{isDefined(databaseEventTrigger) && (
|
||||
<Section>
|
||||
<H2Title
|
||||
title={t`Database event`}
|
||||
description={t`Select the events that should trigger the function`}
|
||||
/>
|
||||
<SettingsDatabaseEventsForm events={databaseEvents} disabled />
|
||||
<SettingsDatabaseEventsForm
|
||||
events={[databaseEventTrigger]}
|
||||
disabled
|
||||
/>
|
||||
</Section>
|
||||
)}
|
||||
|
||||
{cronTriggers.length > 0 && (
|
||||
{isDefined(cronTrigger) && (
|
||||
<Section>
|
||||
<H2Title
|
||||
title={t`Cron`}
|
||||
description={t`Triggers the function at regular intervals`}
|
||||
/>
|
||||
{cronTriggers.map((cronTrigger, index) => (
|
||||
<FormTextFieldInput
|
||||
key={index}
|
||||
label={t`Expression`}
|
||||
placeholder="0 */1 * * *"
|
||||
hint={t`Format: [Minute] [Hour] [Day of Month] [Month] [Day of Week]`}
|
||||
onChange={() => {}}
|
||||
readonly
|
||||
defaultValue={cronTrigger}
|
||||
/>
|
||||
))}
|
||||
<FormTextFieldInput
|
||||
label={t`Expression`}
|
||||
placeholder="0 */1 * * *"
|
||||
hint={t`Format: [Minute] [Hour] [Day of Month] [Month] [Day of Week]`}
|
||||
onChange={() => {}}
|
||||
readonly
|
||||
defaultValue={cronTrigger.pattern}
|
||||
/>
|
||||
</Section>
|
||||
)}
|
||||
|
||||
{routeTriggers.length > 0 && (
|
||||
{isDefined(routeTrigger) && (
|
||||
<Section>
|
||||
<H2Title
|
||||
title={t`Http`}
|
||||
@@ -111,24 +123,21 @@ export const SettingsLogicFunctionTriggersTab = ({
|
||||
<TableHeader>{t`Method`}</TableHeader>
|
||||
<TableHeader>{t`Auth Required`}</TableHeader>
|
||||
</StyledRouteTriggerTableHeaderRow>
|
||||
{routeTriggers.map((_, _index) => (
|
||||
<></>
|
||||
// <StyledRouteTriggerTableRow key={index}>
|
||||
// <StyledTableCell>
|
||||
// <OverflowingTextWithTooltip
|
||||
// text={`${REACT_APP_SERVER_BASE_URL}/s${routeTrigger.path}`}
|
||||
// />
|
||||
// </StyledTableCell>
|
||||
// <StyledTableCell>{routeTrigger.httpMethod}</StyledTableCell>
|
||||
// <StyledTableCell>
|
||||
// <Tag
|
||||
// text={routeTrigger.isAuthRequired ? t`True` : t`False`}
|
||||
// color={routeTrigger.isAuthRequired ? 'green' : 'orange'}
|
||||
// weight="medium"
|
||||
// />
|
||||
// </StyledTableCell>
|
||||
// </StyledRouteTriggerTableRow>
|
||||
))}
|
||||
<StyledRouteTriggerTableRow>
|
||||
<StyledTableCell>
|
||||
<OverflowingTextWithTooltip
|
||||
text={`${REACT_APP_SERVER_BASE_URL}/s${routeTrigger.path}`}
|
||||
/>
|
||||
</StyledTableCell>
|
||||
<StyledTableCell>{routeTrigger.httpMethod}</StyledTableCell>
|
||||
<StyledTableCell>
|
||||
<Tag
|
||||
text={routeTrigger.isAuthRequired ? t`True` : t`False`}
|
||||
color={routeTrigger.isAuthRequired ? 'green' : 'orange'}
|
||||
weight="medium"
|
||||
/>
|
||||
</StyledTableCell>
|
||||
</StyledRouteTriggerTableRow>
|
||||
</Table>
|
||||
</Section>
|
||||
)}
|
||||
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
import { gql } from '@apollo/client';
|
||||
import { LOGIC_FUNCTION_FRAGMENT } from '@/settings/logic-functions/graphql/fragments/logicFunctionFragment';
|
||||
|
||||
export const CREATE_DEFAULT_LOGIC_FUNCTION = gql`
|
||||
${LOGIC_FUNCTION_FRAGMENT}
|
||||
mutation CreateDefaultLogicFunctionItem(
|
||||
$input: CreateDefaultLogicFunctionInput!
|
||||
) {
|
||||
createDefaultLogicFunction(input: $input) {
|
||||
...LogicFunctionFields
|
||||
}
|
||||
}
|
||||
`;
|
||||
-31
@@ -1,31 +0,0 @@
|
||||
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
|
||||
import { FIND_ONE_LOGIC_FUNCTION } from '@/settings/logic-functions/graphql/queries/findOneLogicFunction';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import {
|
||||
type GetOneLogicFunctionQuery,
|
||||
type GetOneLogicFunctionQueryVariables,
|
||||
type LogicFunctionIdInput,
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
export const useGetOneLogicFunction = ({
|
||||
id,
|
||||
onCompleted,
|
||||
}: LogicFunctionIdInput & {
|
||||
onCompleted?: (data: GetOneLogicFunctionQuery) => void;
|
||||
}) => {
|
||||
const apolloMetadataClient = useApolloCoreClient();
|
||||
const { data, loading } = useQuery<
|
||||
GetOneLogicFunctionQuery,
|
||||
GetOneLogicFunctionQueryVariables
|
||||
>(FIND_ONE_LOGIC_FUNCTION, {
|
||||
client: apolloMetadataClient ?? undefined,
|
||||
variables: {
|
||||
input: { id },
|
||||
},
|
||||
onCompleted,
|
||||
});
|
||||
return {
|
||||
logicFunction: data?.findOneLogicFunction || null,
|
||||
loading,
|
||||
};
|
||||
};
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
import { createState } from 'twenty-ui/utilities';
|
||||
import { type GetManyLogicFunctionsQuery } from '~/generated-metadata/graphql';
|
||||
import { type FindManyLogicFunctionsQuery } from '~/generated-metadata/graphql';
|
||||
|
||||
export type LogicFunction =
|
||||
GetManyLogicFunctionsQuery['findManyLogicFunctions'][number];
|
||||
FindManyLogicFunctionsQuery['findManyLogicFunctions'][number];
|
||||
|
||||
export const logicFunctionsState = createState<LogicFunction[]>({
|
||||
key: 'logicFunctionsState',
|
||||
|
||||
@@ -29,7 +29,7 @@ import {
|
||||
useFindAllCoreViewsQuery,
|
||||
useFindAllRecordPageLayoutsQuery,
|
||||
useGetCurrentUserQuery,
|
||||
useGetManyLogicFunctionsQuery,
|
||||
useFindManyLogicFunctionsQuery,
|
||||
} from '~/generated-metadata/graphql';
|
||||
import { dateLocaleState } from '~/localization/states/dateLocaleState';
|
||||
import { dynamicActivate } from '~/utils/i18n/dynamicActivate';
|
||||
@@ -131,7 +131,7 @@ export const MetadataProviderEffect = () => {
|
||||
},
|
||||
);
|
||||
|
||||
const { data: logicFunctionsData } = useGetManyLogicFunctionsQuery({
|
||||
const { data: logicFunctionsData } = useFindManyLogicFunctionsQuery({
|
||||
skip: !isLoggedIn,
|
||||
});
|
||||
|
||||
|
||||
+16
-38
@@ -1,6 +1,8 @@
|
||||
import { useGetLogicFunctionSourceCode } from '@/logic-functions/hooks/useGetLogicFunctionSourceCode';
|
||||
import { useGetAvailablePackages } from '@/settings/logic-functions/hooks/useGetAvailablePackages';
|
||||
import { type LogicFunctionFormValues } from '@/settings/logic-functions/hooks/useLogicFunctionUpdateFormState';
|
||||
import { useGetAvailablePackages } from '@/logic-functions/hooks/useGetAvailablePackages';
|
||||
import {
|
||||
type LogicFunctionFormValues,
|
||||
useLogicFunctionUpdateFormState,
|
||||
} from '@/logic-functions/hooks/useLogicFunctionUpdateFormState';
|
||||
import { useFullScreenModal } from '@/ui/layout/fullscreen/hooks/useFullScreenModal';
|
||||
import { type BreadcrumbProps } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
|
||||
import { useGetUpdatableWorkflowVersionOrThrow } from '@/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow';
|
||||
@@ -11,7 +13,6 @@ import { setNestedValue } from '@/workflow/workflow-steps/workflow-actions/code-
|
||||
|
||||
import { CmdEnterActionButton } from '@/action-menu/components/CmdEnterActionButton';
|
||||
import { LogicFunctionExecutionResult } from '@/logic-functions/components/LogicFunctionExecutionResult';
|
||||
import { INDEX_FILE_NAME } from '@/logic-functions/constants/IndexFileName';
|
||||
import { getFunctionInputFromSourceCode } from '@/logic-functions/utils/getFunctionInputFromSourceCode';
|
||||
import { mergeDefaultFunctionInputAndFunctionInput } from '@/logic-functions/utils/mergeDefaultFunctionInputAndFunctionInput';
|
||||
import { InputLabel } from '@/ui/input/components/InputLabel';
|
||||
@@ -35,10 +36,8 @@ import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components
|
||||
import styled from '@emotion/styled';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
|
||||
import { SOURCE_FOLDER_NAME } from '@/logic-functions/constants/SourceFolderName';
|
||||
import { useExecuteLogicFunction } from '@/logic-functions/hooks/useExecuteLogicFunction';
|
||||
import { usePersistLogicFunction } from '@/logic-functions/hooks/usePersistLogicFunction';
|
||||
import { computeNewSources } from '@/logic-functions/utils/computeNewSources';
|
||||
import { WorkflowStepFooter } from '@/workflow/workflow-steps/components/WorkflowStepFooter';
|
||||
import { CODE_ACTION } from '@/workflow/workflow-steps/workflow-actions/constants/actions/CodeAction';
|
||||
import { type Monaco } from '@monaco-editor/react';
|
||||
@@ -104,7 +103,7 @@ export const WorkflowEditActionCode = ({
|
||||
activeTabIdComponentState,
|
||||
WORKFLOW_LOGIC_FUNCTION_TAB_LIST_COMPONENT_ID,
|
||||
);
|
||||
const { updateLogicFunctionSource } = usePersistLogicFunction();
|
||||
const { updateLogicFunction } = usePersistLogicFunction();
|
||||
const { getUpdatableWorkflowVersion } =
|
||||
useGetUpdatableWorkflowVersionOrThrow();
|
||||
|
||||
@@ -126,21 +125,8 @@ export const WorkflowEditActionCode = ({
|
||||
action.settings.input.logicFunctionInput,
|
||||
);
|
||||
|
||||
const { code: codeFromApi, loading } = useGetLogicFunctionSourceCode({
|
||||
logicFunctionId,
|
||||
});
|
||||
|
||||
const [formValues, setFormValues] = useState<LogicFunctionFormValues>({
|
||||
name: '',
|
||||
description: '',
|
||||
code: { src: { 'index.ts': '' } },
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (isDefined(codeFromApi)) {
|
||||
setFormValues((prev) => ({ ...prev, code: codeFromApi }));
|
||||
}
|
||||
}, [codeFromApi]);
|
||||
const { formValues, setFormValues, loading } =
|
||||
useLogicFunctionUpdateFormState({ logicFunctionId });
|
||||
|
||||
const updateOutputSchemaFromTestResult = async (testResult: object) => {
|
||||
if (actionOptions.readonly === true) {
|
||||
@@ -159,10 +145,12 @@ export const WorkflowEditActionCode = ({
|
||||
});
|
||||
|
||||
const handleSave = useDebouncedCallback(async () => {
|
||||
await updateLogicFunctionSource({
|
||||
await updateLogicFunction({
|
||||
input: {
|
||||
id: logicFunctionId,
|
||||
code: formValues.code,
|
||||
update: {
|
||||
sourceHandlerCode: formValues.code,
|
||||
},
|
||||
},
|
||||
});
|
||||
}, 500);
|
||||
@@ -174,11 +162,7 @@ export const WorkflowEditActionCode = ({
|
||||
setFormValues((prevState: LogicFunctionFormValues) => {
|
||||
return {
|
||||
...prevState,
|
||||
code: computeNewSources({
|
||||
previousCode: prevState['code'],
|
||||
filePath: `${SOURCE_FOLDER_NAME}/${INDEX_FILE_NAME}`,
|
||||
value: newCode,
|
||||
}),
|
||||
code: newCode,
|
||||
};
|
||||
});
|
||||
await handleSave();
|
||||
@@ -273,7 +257,7 @@ export const WorkflowEditActionCode = ({
|
||||
}
|
||||
|
||||
if (!isExecuting) {
|
||||
await executeLogicFunction({ forceRebuild: true });
|
||||
await executeLogicFunction();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -387,12 +371,6 @@ export const WorkflowEditActionCode = ({
|
||||
setIsFullScreen(false);
|
||||
};
|
||||
|
||||
const indexFileContent =
|
||||
typeof formValues.code?.[SOURCE_FOLDER_NAME] !== 'string' &&
|
||||
typeof formValues.code[SOURCE_FOLDER_NAME][INDEX_FILE_NAME] === 'string'
|
||||
? formValues.code[SOURCE_FOLDER_NAME][INDEX_FILE_NAME]
|
||||
: '';
|
||||
|
||||
const fullScreenOverlay = renderFullScreenModal(
|
||||
<div data-globally-prevent-click-outside="true">
|
||||
<WorkflowEditActionCodeFields
|
||||
@@ -404,7 +382,7 @@ export const WorkflowEditActionCode = ({
|
||||
<StyledFullScreenCodeEditorContainer>
|
||||
<CodeEditor
|
||||
height="100%"
|
||||
value={indexFileContent}
|
||||
value={formValues.code}
|
||||
language="typescript"
|
||||
onChange={handleCodeChange}
|
||||
onMount={handleEditorDidMount}
|
||||
@@ -439,7 +417,7 @@ export const WorkflowEditActionCode = ({
|
||||
readonly={actionOptions.readonly}
|
||||
/>
|
||||
<WorkflowCodeEditor
|
||||
value={indexFileContent}
|
||||
value={formValues.code}
|
||||
onChange={handleCodeChange}
|
||||
onMount={handleEditorDidMount}
|
||||
options={{
|
||||
|
||||
+2
-11
@@ -1,9 +1,7 @@
|
||||
import { useGetAvailablePackages } from '@/settings/logic-functions/hooks/useGetAvailablePackages';
|
||||
import { useGetAvailablePackages } from '@/logic-functions/hooks/useGetAvailablePackages';
|
||||
import { type WorkflowCodeAction } from '@/workflow/types/Workflow';
|
||||
import { useGetLogicFunctionSourceCode } from '@/logic-functions/hooks/useGetLogicFunctionSourceCode';
|
||||
|
||||
import { INDEX_FILE_NAME } from '@/logic-functions/constants/IndexFileName';
|
||||
import { SOURCE_FOLDER_NAME } from '@/logic-functions/constants/SourceFolderName';
|
||||
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
|
||||
import { WorkflowEditActionCodeFields } from '@/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionCodeFields';
|
||||
import { getWrongExportedFunctionMarkers } from '@/workflow/workflow-steps/workflow-actions/code-action/utils/getWrongExportedFunctionMarkers';
|
||||
@@ -52,13 +50,6 @@ export const WorkflowReadonlyActionCode = ({
|
||||
return null;
|
||||
}
|
||||
|
||||
const indexFileContent =
|
||||
code != null &&
|
||||
typeof code?.[SOURCE_FOLDER_NAME] !== 'string' &&
|
||||
typeof code[SOURCE_FOLDER_NAME]?.[INDEX_FILE_NAME] === 'string'
|
||||
? code[SOURCE_FOLDER_NAME][INDEX_FILE_NAME]
|
||||
: '';
|
||||
|
||||
return (
|
||||
<>
|
||||
<WorkflowStepBody>
|
||||
@@ -69,7 +60,7 @@ export const WorkflowReadonlyActionCode = ({
|
||||
<StyledCodeEditorContainer>
|
||||
<CodeEditor
|
||||
height={343}
|
||||
value={indexFileContent}
|
||||
value={code ?? undefined}
|
||||
language="typescript"
|
||||
onMount={handleEditorDidMount}
|
||||
setMarkers={getWrongExportedFunctionMarkers}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import { getDefaultFunctionInputFromInputSchema } from '@/logic-functions/utils/getDefaultFunctionInputFromInputSchema';
|
||||
import { mergeDefaultFunctionInputAndFunctionInput } from '@/logic-functions/utils/mergeDefaultFunctionInputAndFunctionInput';
|
||||
import { useGetOneLogicFunction } from '@/settings/logic-functions/hooks/useGetOneLogicFunction';
|
||||
import { useGetOneLogicFunction } from '@/logic-functions/hooks/useGetOneLogicFunction';
|
||||
import { type WorkflowLogicFunctionAction } from '@/workflow/types/Workflow';
|
||||
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
|
||||
import { WorkflowStepFooter } from '@/workflow/workflow-steps/components/WorkflowStepFooter';
|
||||
|
||||
@@ -131,24 +131,24 @@ export const SettingsToolsTable = () => {
|
||||
});
|
||||
|
||||
if (result.status === 'successful' && isDefined(result.response?.data)) {
|
||||
const newFunction = result.response.data.createDefaultLogicFunction;
|
||||
const newLogicFunction = result.response.data.createOneLogicFunction;
|
||||
enqueueSuccessSnackBar({ message: t`Tool created` });
|
||||
|
||||
// Navigate to the logic function detail page
|
||||
// The applicationId might be null for workspace-level functions
|
||||
const applicationId = (newFunction as { applicationId?: string })
|
||||
const applicationId = (newLogicFunction as { applicationId?: string })
|
||||
.applicationId;
|
||||
if (isDefined(applicationId)) {
|
||||
navigate(
|
||||
getSettingsPath(SettingsPath.ApplicationLogicFunctionDetail, {
|
||||
applicationId,
|
||||
logicFunctionId: newFunction.id,
|
||||
logicFunctionId: newLogicFunction.id,
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
navigate(
|
||||
getSettingsPath(SettingsPath.LogicFunctionDetail, {
|
||||
logicFunctionId: newFunction.id,
|
||||
logicFunctionId: newLogicFunction.id,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
+90
-4
@@ -1,3 +1,6 @@
|
||||
import { getToolInputSchemaFromSourceCode } from '@/logic-functions/utils/getToolInputSchemaFromSourceCode';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
|
||||
import { useExecuteLogicFunction } from '@/logic-functions/hooks/useExecuteLogicFunction';
|
||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||
import { SettingsLogicFunctionLabelContainer } from '@/settings/logic-functions/components/SettingsLogicFunctionLabelContainer';
|
||||
@@ -7,23 +10,35 @@ import { SettingsLogicFunctionTriggersTab } from '@/settings/logic-functions/com
|
||||
import {
|
||||
type LogicFunctionFormValues,
|
||||
useLogicFunctionUpdateFormState,
|
||||
} from '@/settings/logic-functions/hooks/useLogicFunctionUpdateFormState';
|
||||
} from '@/logic-functions/hooks/useLogicFunctionUpdateFormState';
|
||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
|
||||
import { TabList } from '@/ui/layout/tab-list/components/TabList';
|
||||
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { SettingsPath } from 'twenty-shared/types';
|
||||
import { getSettingsPath, isDefined } from 'twenty-shared/utils';
|
||||
import { IconBolt, IconPlayerPlay, IconSettings } from 'twenty-ui/display';
|
||||
import {
|
||||
IconBolt,
|
||||
IconCode,
|
||||
IconPlayerPlay,
|
||||
IconSettings,
|
||||
} from 'twenty-ui/display';
|
||||
import { useFindOneApplicationQuery } from '~/generated-metadata/graphql';
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { useDebouncedCallback } from 'use-debounce';
|
||||
import { usePersistLogicFunction } from '@/logic-functions/hooks/usePersistLogicFunction';
|
||||
import { SettingsLogicFunctionCodeEditorTab } from '@/settings/logic-functions/components/tabs/SettingsLogicFunctionCodeEditorTab';
|
||||
|
||||
const LOGIC_FUNCTION_DETAIL_ID = 'logic-function-detail';
|
||||
|
||||
export const SettingsLogicFunctionDetail = () => {
|
||||
const { logicFunctionId = '', applicationId = '' } = useParams();
|
||||
|
||||
const navigate = useNavigate();
|
||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
||||
|
||||
const { data, loading: applicationLoading } = useFindOneApplicationQuery({
|
||||
variables: { id: applicationId },
|
||||
skip: !applicationId,
|
||||
@@ -31,6 +46,11 @@ export const SettingsLogicFunctionDetail = () => {
|
||||
|
||||
const applicationName = data?.findOneApplication?.name;
|
||||
|
||||
const workspaceCustomApplicationId =
|
||||
currentWorkspace?.workspaceCustomApplication?.id;
|
||||
|
||||
const isManaged = applicationId !== workspaceCustomApplicationId;
|
||||
|
||||
const instanceId = `${LOGIC_FUNCTION_DETAIL_ID}-${logicFunctionId}`;
|
||||
|
||||
const activeTabId = useRecoilComponentValue(
|
||||
@@ -41,14 +61,33 @@ export const SettingsLogicFunctionDetail = () => {
|
||||
const { formValues, setFormValues, logicFunction, loading } =
|
||||
useLogicFunctionUpdateFormState({ logicFunctionId });
|
||||
|
||||
const { updateLogicFunction } = usePersistLogicFunction();
|
||||
|
||||
const { executeLogicFunction, isExecuting } = useExecuteLogicFunction({
|
||||
logicFunctionId,
|
||||
});
|
||||
|
||||
const handleExecute = async () => {
|
||||
await executeLogicFunction({ forceRebuild: false });
|
||||
await executeLogicFunction();
|
||||
};
|
||||
|
||||
const handleSave = useDebouncedCallback(
|
||||
async (toolInputSchema?: object | null) => {
|
||||
await updateLogicFunction({
|
||||
input: {
|
||||
id: logicFunctionId,
|
||||
update: {
|
||||
name: formValues.name,
|
||||
description: formValues.description,
|
||||
sourceHandlerCode: formValues.code,
|
||||
...(toolInputSchema !== undefined && { toolInputSchema }),
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
500,
|
||||
);
|
||||
|
||||
const onChange = (key: string) => {
|
||||
return (value: string) => {
|
||||
setFormValues((prevState: LogicFunctionFormValues) => ({
|
||||
@@ -58,12 +97,43 @@ export const SettingsLogicFunctionDetail = () => {
|
||||
};
|
||||
};
|
||||
|
||||
const onCodeChange = async (filePath: string, value: string) => {
|
||||
setFormValues((prevState: LogicFunctionFormValues) => {
|
||||
return {
|
||||
...prevState,
|
||||
code: value,
|
||||
};
|
||||
});
|
||||
|
||||
// Parse and save schema if editing the handler file
|
||||
let toolInputSchema: object | null | undefined;
|
||||
|
||||
if (filePath === logicFunction?.sourceHandlerPath) {
|
||||
toolInputSchema = await getToolInputSchemaFromSourceCode(value);
|
||||
}
|
||||
|
||||
await handleSave(toolInputSchema);
|
||||
};
|
||||
|
||||
const handleTestFunction = async () => {
|
||||
navigate('#test');
|
||||
await executeLogicFunction();
|
||||
};
|
||||
|
||||
const tabs = [
|
||||
{
|
||||
id: 'editor',
|
||||
title: t`Editor`,
|
||||
Icon: IconCode,
|
||||
disabled: isManaged,
|
||||
hide: isManaged,
|
||||
},
|
||||
{ id: 'settings', title: t`Settings`, Icon: IconSettings },
|
||||
{ id: 'test', title: t`Test`, Icon: IconPlayerPlay },
|
||||
{ id: 'triggers', title: t`Triggers`, Icon: IconBolt },
|
||||
];
|
||||
|
||||
const isEditorTab = activeTabId === 'editor';
|
||||
const isTriggersTab = activeTabId === 'triggers';
|
||||
const isSettingsTab = activeTabId === 'settings';
|
||||
const isTestTab = activeTabId === 'test';
|
||||
@@ -104,6 +174,14 @@ export const SettingsLogicFunctionDetail = () => {
|
||||
{ children: `${logicFunction?.name}` },
|
||||
];
|
||||
|
||||
const files = [
|
||||
{
|
||||
path: 'index.ts',
|
||||
content: formValues.code,
|
||||
language: 'typescript',
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
!loading &&
|
||||
!applicationLoading && (
|
||||
@@ -118,6 +196,14 @@ export const SettingsLogicFunctionDetail = () => {
|
||||
>
|
||||
<SettingsPageContainer>
|
||||
<TabList tabs={tabs} componentInstanceId={instanceId} />
|
||||
{isEditorTab && (
|
||||
<SettingsLogicFunctionCodeEditorTab
|
||||
files={files}
|
||||
handleExecute={handleTestFunction}
|
||||
onChange={onCodeChange}
|
||||
isTesting={isExecuting}
|
||||
/>
|
||||
)}
|
||||
{isTriggersTab && logicFunction && (
|
||||
<SettingsLogicFunctionTriggersTab logicFunction={logicFunction} />
|
||||
)}
|
||||
|
||||
+6
-1
@@ -14,13 +14,17 @@ import { sleep } from '~/utils/sleep';
|
||||
const SOURCE_CODE_FULL_PATH =
|
||||
'logic-function/20202020-1c25-4d02-bf25-6aeccf7ea419/adb4bd21-7670-4c81-9f74-1fc196fe87ea/source.ts';
|
||||
|
||||
const APPLICATION_ID = '20202020-64aa-4b6f-b003-9c74b97cee20';
|
||||
|
||||
const meta: Meta<PageDecoratorArgs> = {
|
||||
title: 'Pages/Settings/LogicFunctions/SettingsLogicFunctionDetail',
|
||||
component: SettingsLogicFunctionDetail,
|
||||
decorators: [PageDecorator],
|
||||
args: {
|
||||
routePath: '/settings/function/',
|
||||
routePath:
|
||||
'/settings/applications/:applicationId/logicFunctions/:logicFunctionId',
|
||||
routeParams: {
|
||||
':applicationId': APPLICATION_ID,
|
||||
':logicFunctionId': 'adb4bd21-7670-4c81-9f74-1fc196fe87ea',
|
||||
},
|
||||
},
|
||||
@@ -34,6 +38,7 @@ const meta: Meta<PageDecoratorArgs> = {
|
||||
logicFunction: {
|
||||
__typename: 'LogicFunction',
|
||||
id: 'adb4bd21-7670-4c81-9f74-1fc196fe87ea',
|
||||
applicationId: APPLICATION_ID,
|
||||
name: 'Logic Function Name',
|
||||
description: '',
|
||||
runtime: 'nodejs22.x',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "twenty-sdk",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"main": "dist/index.cjs",
|
||||
"module": "dist/index.mjs",
|
||||
"types": "dist/index.d.ts",
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
generated
|
||||
-1
@@ -3,7 +3,6 @@ import type { Manifest } from 'twenty-shared/application';
|
||||
import { PermissionFlagType } from 'twenty-shared/constants';
|
||||
|
||||
export const EXPECTED_MANIFEST: Manifest = {
|
||||
sources: {},
|
||||
publicAssets: [
|
||||
{
|
||||
checksum: '99496069dcc2a1488e1cae9f826d2707',
|
||||
|
||||
-1
@@ -2,7 +2,6 @@ import { FieldType } from '@/sdk';
|
||||
import type { Manifest } from 'twenty-shared/application';
|
||||
|
||||
export const EXPECTED_MANIFEST: Manifest = {
|
||||
sources: {},
|
||||
application: {
|
||||
universalIdentifier: 'e1e2e3e4-e5e6-4000-8000-000000000001',
|
||||
displayName: 'Root App',
|
||||
|
||||
@@ -26,5 +26,4 @@ export const normalizeManifestForComparison = <T extends JsonManifestInput>(
|
||||
? '[checksum]'
|
||||
: '',
|
||||
})),
|
||||
sources: {}, // removing sources for now, waiting compressed file implementation
|
||||
});
|
||||
|
||||
@@ -574,7 +574,7 @@ export class ApiService {
|
||||
);
|
||||
|
||||
const response: AxiosResponse = await this.client.post(
|
||||
'/graphql',
|
||||
'/metadata',
|
||||
formData,
|
||||
);
|
||||
|
||||
|
||||
-1
@@ -32,7 +32,6 @@ const validManifest: Manifest = {
|
||||
logicFunctions: [],
|
||||
roles: [],
|
||||
publicAssets: [],
|
||||
sources: {},
|
||||
};
|
||||
|
||||
describe('manifestValidate', () => {
|
||||
|
||||
@@ -11,9 +11,8 @@ import {
|
||||
type LogicFunctionConfig,
|
||||
} from '@/sdk';
|
||||
import { glob } from 'fast-glob';
|
||||
import * as fs from 'fs-extra';
|
||||
import { readFile } from 'fs-extra';
|
||||
import { basename, extname, relative, sep } from 'path';
|
||||
import { basename, extname, relative } from 'path';
|
||||
import {
|
||||
type ApplicationManifest,
|
||||
type AssetManifest,
|
||||
@@ -25,7 +24,6 @@ import {
|
||||
type ObjectManifest,
|
||||
type RoleManifest,
|
||||
} from 'twenty-shared/application';
|
||||
import { type Sources } from 'twenty-shared/types';
|
||||
import { assertUnreachable } from 'twenty-shared/utils';
|
||||
|
||||
const loadSources = async (appPath: string): Promise<string[]> => {
|
||||
@@ -44,32 +42,6 @@ const loadAssets = async (appPath: string) => {
|
||||
});
|
||||
};
|
||||
|
||||
const computeSources = async (
|
||||
appPath: string,
|
||||
sourceFilePaths: string[],
|
||||
): Promise<Sources> => {
|
||||
const sources: Sources = {};
|
||||
|
||||
for (const filepath of sourceFilePaths) {
|
||||
const relPath = relative(appPath, filepath);
|
||||
const parts = relPath.split(sep);
|
||||
const content = await fs.readFile(filepath, 'utf8');
|
||||
|
||||
let current: Sources = sources;
|
||||
for (let i = 0; i < parts.length; i++) {
|
||||
const part = parts[i];
|
||||
if (i === parts.length - 1) {
|
||||
current[part] = content;
|
||||
} else {
|
||||
current[part] = (current[part] ?? {}) as Sources;
|
||||
current = current[part] as Sources;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sources;
|
||||
};
|
||||
|
||||
export const buildManifest = async (
|
||||
appPath: string,
|
||||
): Promise<{
|
||||
@@ -240,7 +212,6 @@ export const buildManifest = async (
|
||||
logicFunctions,
|
||||
frontComponents,
|
||||
publicAssets,
|
||||
sources: await computeSources(appPath, filePaths),
|
||||
};
|
||||
|
||||
const entityFilePaths: EntityFilePaths = {
|
||||
|
||||
@@ -21,11 +21,11 @@
|
||||
"outDir": "dist/assets"
|
||||
},
|
||||
{
|
||||
"include": "engine/core-modules/application-layer/constants/seed-dependencies/**",
|
||||
"include": "engine/core-modules/application/constants/seed-dependencies/**",
|
||||
"outDir": "dist/assets"
|
||||
},
|
||||
{
|
||||
"include": "engine/core-modules/application-layer/constants/yarn-engine/**",
|
||||
"include": "engine/core-modules/application/constants/yarn-engine/**",
|
||||
"outDir": "dist/assets"
|
||||
},
|
||||
{
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/
|
||||
import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { parseAvailablePackagesFromPackageJsonAndYarnLock } from 'src/engine/core-modules/application-layer/utils/parse-available-packages-from-package-json-and-yarn-lock.util';
|
||||
import { parseAvailablePackagesFromPackageJsonAndYarnLock } from 'src/engine/core-modules/application/utils/parse-available-packages-from-package-json-and-yarn-lock.util';
|
||||
import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service';
|
||||
import { FileSettings } from 'src/engine/core-modules/file/types/file-settings.types';
|
||||
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
|
||||
+3
-2
@@ -214,12 +214,13 @@ export class MigrateWorkflowCodeStepsCommand extends ActiveOrSuspendedWorkspaces
|
||||
name: oldLogicFunction.name,
|
||||
description: oldLogicFunction.description ?? undefined,
|
||||
timeoutSeconds: oldLogicFunction.timeoutSeconds ?? 300,
|
||||
toolInputSchema: oldLogicFunction.toolInputSchema ?? undefined,
|
||||
toolInputSchema: oldLogicFunction.toolInputSchema ?? {},
|
||||
isTool: oldLogicFunction.isTool ?? false,
|
||||
handlerName: oldLogicFunction.handlerName,
|
||||
sourceHandlerPath: `${NEW_WORKFLOW_RESOURCE_PREFIX}/${newLogicFunctionId}/src/index.ts`,
|
||||
builtHandlerPath: `${NEW_WORKFLOW_RESOURCE_PREFIX}/${newLogicFunctionId}/src/index.mjs`,
|
||||
handlerName: oldLogicFunction.handlerName,
|
||||
checksum,
|
||||
isBuildUpToDate: true,
|
||||
},
|
||||
workspaceId,
|
||||
ownerFlatApplication: oldLogicFunction.application,
|
||||
|
||||
+5
-3
@@ -13,9 +13,6 @@ import { RecordPositionService } from 'src/engine/core-modules/record-position/s
|
||||
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
|
||||
import {
|
||||
DEFAULT_BUILT_HANDLER_PATH,
|
||||
DEFAULT_HANDLER_NAME,
|
||||
DEFAULT_SOURCE_HANDLER_PATH,
|
||||
LogicFunctionEntity,
|
||||
LogicFunctionRuntime,
|
||||
} from 'src/engine/metadata-modules/logic-function/logic-function.entity';
|
||||
@@ -24,6 +21,11 @@ import { WorkflowVersionStatus } from 'src/modules/workflow/common/standard-obje
|
||||
import { WorkflowStatus } from 'src/modules/workflow/common/standard-objects/workflow.workspace-entity';
|
||||
import { WorkflowActionType } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action-type.enum';
|
||||
import { WorkflowTriggerType } from 'src/modules/workflow/workflow-trigger/types/workflow-trigger.type';
|
||||
import {
|
||||
DEFAULT_BUILT_HANDLER_PATH,
|
||||
DEFAULT_HANDLER_NAME,
|
||||
DEFAULT_SOURCE_HANDLER_PATH,
|
||||
} from 'src/engine/metadata-modules/logic-function/constants/handler.contant';
|
||||
|
||||
const OLD_BUILT_FOLDER = 'built-function';
|
||||
const OLD_SOURCE_FOLDER = 'serverless-function';
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
import { type MigrationInterface, type QueryRunner } from 'typeorm';
|
||||
|
||||
export class AddLogicFunctionIsBuildUpToDateColumn1770725043111
|
||||
implements MigrationInterface
|
||||
{
|
||||
name = 'AddLogicFunctionIsBuildUpToDateColumn1770725043111';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."logicFunction" ADD "isBuildUpToDate" boolean NOT NULL DEFAULT true`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."logicFunction" ALTER COLUMN "sourceHandlerPath" DROP DEFAULT`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."logicFunction" ALTER COLUMN "builtHandlerPath" DROP DEFAULT`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."logicFunction" ALTER COLUMN "handlerName" DROP DEFAULT`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."logicFunction" ALTER COLUMN "handlerName" SET DEFAULT 'main'`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."logicFunction" ALTER COLUMN "builtHandlerPath" SET DEFAULT 'src/index.mjs'`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."logicFunction" ALTER COLUMN "sourceHandlerPath" SET DEFAULT 'src/index.ts'`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."logicFunction" DROP COLUMN "isBuildUpToDate"`,
|
||||
);
|
||||
}
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
|
||||
import { ApplicationLayerService } from 'src/engine/core-modules/application-layer/application-layer.service';
|
||||
import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module';
|
||||
import { FileModule } from 'src/engine/core-modules/file/file.module';
|
||||
|
||||
@Module({
|
||||
imports: [WorkspaceCacheModule, FileModule],
|
||||
providers: [ApplicationLayerService],
|
||||
exports: [ApplicationLayerService],
|
||||
})
|
||||
export class ApplicationLayerModule {}
|
||||
-46
@@ -1,46 +0,0 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
|
||||
import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service';
|
||||
|
||||
@Injectable()
|
||||
export class ApplicationLayerService {
|
||||
constructor(
|
||||
private readonly fileStorageService: FileStorageService,
|
||||
private readonly workspaceCacheService: WorkspaceCacheService,
|
||||
) {}
|
||||
|
||||
async getAvailablePackages({
|
||||
logicFunctionId,
|
||||
workspaceId,
|
||||
}: {
|
||||
logicFunctionId: string;
|
||||
workspaceId: string;
|
||||
}) {
|
||||
const { flatLogicFunctionMaps, flatApplicationMaps } =
|
||||
await this.workspaceCacheService.getOrRecompute(workspaceId, [
|
||||
'flatLogicFunctionMaps',
|
||||
'flatApplicationMaps',
|
||||
]);
|
||||
|
||||
const logicFunctionUniversalIdentifier =
|
||||
flatLogicFunctionMaps.universalIdentifierById[logicFunctionId];
|
||||
|
||||
if (!logicFunctionUniversalIdentifier) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const logicFunction =
|
||||
flatLogicFunctionMaps.byUniversalIdentifier[
|
||||
logicFunctionUniversalIdentifier
|
||||
];
|
||||
|
||||
if (!logicFunction) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const application = flatApplicationMaps.byId[logicFunction.applicationId];
|
||||
|
||||
return application?.availablePackages ?? {};
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -6,6 +6,6 @@ export const SEED_DEPENDENCIES_DIRNAME = path.resolve(
|
||||
__dirname,
|
||||
path.join(
|
||||
ASSET_PATH,
|
||||
'engine/core-modules/application-layer/constants/seed-dependencies',
|
||||
'engine/core-modules/application/constants/seed-dependencies',
|
||||
),
|
||||
);
|
||||
+1
-1
@@ -6,6 +6,6 @@ export const YARN_ENGINE_DIRNAME = path.resolve(
|
||||
__dirname,
|
||||
path.join(
|
||||
ASSET_PATH,
|
||||
'engine/core-modules/application-layer/constants/yarn-engine',
|
||||
'engine/core-modules/application/constants/yarn-engine',
|
||||
),
|
||||
);
|
||||
+1
-1
@@ -4,7 +4,6 @@ import { FileFolder } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { PackageJson } from 'type-fest';
|
||||
|
||||
import { getDefaultApplicationPackageFields } from 'src/engine/core-modules/application-layer/utils/get-default-application-package-fields.util';
|
||||
import { ApplicationEntity } from 'src/engine/core-modules/application/application.entity';
|
||||
import {
|
||||
ApplicationException,
|
||||
@@ -15,6 +14,7 @@ import { ApplicationInput } from 'src/engine/core-modules/application/dtos/appli
|
||||
import { ApplicationManifestMigrationService } from 'src/engine/core-modules/application/services/application-manifest-migration.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { getDefaultApplicationPackageFields } from 'src/engine/core-modules/application/utils/get-default-application-package-fields.util';
|
||||
import { getEmptyApplicationManifestAllUniversalFlatEntityMaps } from 'src/engine/core-modules/application/utils/get-empty-application-manifest-all-universal-flat-entity-maps.util';
|
||||
import { getSubApplicationFromToAllFlatEntityMaps } from 'src/engine/core-modules/application/utils/get-sub-application-from-to-all-flat-entity-maps.util';
|
||||
import { ApplicationVariableEntityService } from 'src/engine/core-modules/applicationVariable/application-variable.service';
|
||||
|
||||
+2
-2
@@ -10,8 +10,8 @@ import {
|
||||
ApplicationException,
|
||||
ApplicationExceptionCode,
|
||||
} from 'src/engine/core-modules/application/application.exception';
|
||||
import { getDefaultApplicationPackageFields } from 'src/engine/core-modules/application-layer/utils/get-default-application-package-fields.util';
|
||||
import { parseAvailablePackagesFromPackageJsonAndYarnLock } from 'src/engine/core-modules/application-layer/utils/parse-available-packages-from-package-json-and-yarn-lock.util';
|
||||
import { getDefaultApplicationPackageFields } from 'src/engine/core-modules/application/utils/get-default-application-package-fields.util';
|
||||
import { parseAvailablePackagesFromPackageJsonAndYarnLock } from 'src/engine/core-modules/application/utils/parse-available-packages-from-package-json-and-yarn-lock.util';
|
||||
import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service';
|
||||
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { ALL_FLAT_ENTITY_MAPS_PROPERTIES } from 'src/engine/metadata-modules/flat-entity/constant/all-flat-entity-maps-properties.constant';
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ import { promises as fs, statSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import { promisify } from 'util';
|
||||
|
||||
import { YARN_ENGINE_DIRNAME } from 'src/engine/core-modules/application-layer/constants/yarn-engine-dirname';
|
||||
import { YARN_ENGINE_DIRNAME } from 'src/engine/core-modules/application/constants/yarn-engine-dirname';
|
||||
|
||||
const execFilePromise = promisify(execFile);
|
||||
|
||||
+1
@@ -35,6 +35,7 @@ export const fromLogicFunctionManifestToUniversalFlatLogicFunction = ({
|
||||
logicFunctionManifest.databaseEventTriggerSettings ?? null,
|
||||
httpRouteTriggerSettings:
|
||||
logicFunctionManifest.httpRouteTriggerSettings ?? null,
|
||||
isBuildUpToDate: true,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
deletedAt: null,
|
||||
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
import { readFile } from 'fs/promises';
|
||||
import path from 'path';
|
||||
|
||||
import { parseAvailablePackagesFromPackageJsonAndYarnLock } from 'src/engine/core-modules/application-layer/utils/parse-available-packages-from-package-json-and-yarn-lock.util';
|
||||
import { SEED_DEPENDENCIES_DIRNAME } from 'src/engine/core-modules/application-layer/constants/seed-dependencies-dirname';
|
||||
import { parseAvailablePackagesFromPackageJsonAndYarnLock } from 'src/engine/core-modules/application/utils/parse-available-packages-from-package-json-and-yarn-lock.util';
|
||||
import { SEED_DEPENDENCIES_DIRNAME } from 'src/engine/core-modules/application/constants/seed-dependencies-dirname';
|
||||
|
||||
// To regenerate: use logicFunctionCreateHash from logic-function-create-hash.utils.
|
||||
// package.json: hash(JSON.stringify(JSON.parse(content))). yarn.lock: hash(content).
|
||||
+1
-1
@@ -314,7 +314,7 @@ export class CacheStorageService {
|
||||
const formattedKey = `${this.namespace}:${key}`;
|
||||
|
||||
if (process.env.NODE_ENV === 'test') {
|
||||
return `integration-tests:${formattedKey}`;
|
||||
return `${CacheStorageNamespace.IntegrationTests}:${formattedKey}`;
|
||||
}
|
||||
|
||||
return formattedKey;
|
||||
|
||||
+1
@@ -7,4 +7,5 @@ export enum CacheStorageNamespace {
|
||||
EngineHealth = 'engine:health',
|
||||
EngineMetrics = 'engine:metrics',
|
||||
EngineSubscriptions = 'engine:subscriptions',
|
||||
IntegrationTests = 'integration-tests',
|
||||
}
|
||||
|
||||
@@ -66,7 +66,6 @@ import { TrashCleanupModule } from 'src/engine/trash-cleanup/trash-cleanup.modul
|
||||
import { WorkspaceEventEmitterModule } from 'src/engine/workspace-event-emitter/workspace-event-emitter.module';
|
||||
import { ChannelSyncModule } from 'src/modules/connected-account/channel-sync/channel-sync.module';
|
||||
import { DashboardModule } from 'src/modules/dashboard/dashboard.module';
|
||||
import { ApplicationLayerModule } from 'src/engine/core-modules/application-layer/application-layer.module';
|
||||
import { LogicFunctionResourceService } from 'src/engine/core-modules/logic-function/logic-function-resource/logic-function-resource.service';
|
||||
|
||||
import { AuditModule } from './audit/audit.module';
|
||||
@@ -89,7 +88,6 @@ import { FileModule } from './file/file.module';
|
||||
RowLevelPermissionModule,
|
||||
OpenApiModule,
|
||||
ApplicationModule,
|
||||
ApplicationLayerModule,
|
||||
ApplicationSyncModule,
|
||||
AppTokenModule,
|
||||
TimelineMessagingModule,
|
||||
|
||||
+16
-109
@@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { mkdir, readdir, readFile, stat } from 'fs/promises';
|
||||
import { join } from 'path';
|
||||
import { basename, dirname, join } from 'path';
|
||||
import { type Readable } from 'stream';
|
||||
|
||||
import { isObject } from '@sniptt/guards';
|
||||
@@ -197,45 +197,6 @@ export class FileStorageService {
|
||||
return sources;
|
||||
}
|
||||
|
||||
async readFolder(params: ResourceIdentifier): Promise<Sources> {
|
||||
const driver = this.fileStorageDriverFactory.getCurrentDriver();
|
||||
const onStoragePath = this.buildOnStoragePath(params);
|
||||
const tempDir = `/tmp/twenty-read-folder-${Date.now()}`;
|
||||
|
||||
await mkdir(tempDir, { recursive: true });
|
||||
|
||||
await driver.downloadFolder({
|
||||
onStoragePath,
|
||||
localPath: tempDir,
|
||||
});
|
||||
|
||||
return this.readLocalFolderToSources(tempDir);
|
||||
}
|
||||
|
||||
uploadFolder(
|
||||
params: ResourceIdentifier & { localPath: string },
|
||||
): Promise<void> {
|
||||
const driver = this.fileStorageDriverFactory.getCurrentDriver();
|
||||
const onStoragePath = this.buildOnStoragePath(params);
|
||||
|
||||
return driver.uploadFolder({
|
||||
localPath: params.localPath,
|
||||
onStoragePath,
|
||||
});
|
||||
}
|
||||
|
||||
downloadFolder(
|
||||
params: ResourceIdentifier & { localPath: string },
|
||||
): Promise<void> {
|
||||
const driver = this.fileStorageDriverFactory.getCurrentDriver();
|
||||
const onStoragePath = this.buildOnStoragePath(params);
|
||||
|
||||
return driver.downloadFolder({
|
||||
onStoragePath,
|
||||
localPath: params.localPath,
|
||||
});
|
||||
}
|
||||
|
||||
downloadFile(
|
||||
params: ResourceIdentifier & { localPath: string },
|
||||
): Promise<void> {
|
||||
@@ -339,7 +300,7 @@ export class FileStorageService {
|
||||
return driver.copy(params);
|
||||
}
|
||||
|
||||
copy({
|
||||
async copy({
|
||||
from,
|
||||
to,
|
||||
}: {
|
||||
@@ -348,68 +309,21 @@ export class FileStorageService {
|
||||
}): Promise<void> {
|
||||
const driver = this.fileStorageDriverFactory.getCurrentDriver();
|
||||
|
||||
const fromPath = this.buildOnStoragePath(from);
|
||||
const toPath = this.buildOnStoragePath(to);
|
||||
|
||||
const isFile = await driver.checkFileExists({ filePath: fromPath });
|
||||
|
||||
if (isFile) {
|
||||
return driver.copy({
|
||||
from: { folderPath: dirname(fromPath), filename: basename(fromPath) },
|
||||
to: { folderPath: dirname(toPath), filename: basename(toPath) },
|
||||
});
|
||||
}
|
||||
|
||||
return driver.copy({
|
||||
from: { folderPath: this.buildOnStoragePath(from) },
|
||||
to: { folderPath: this.buildOnStoragePath(to) },
|
||||
});
|
||||
}
|
||||
|
||||
async moveFile({
|
||||
from,
|
||||
to,
|
||||
workspaceId,
|
||||
}: {
|
||||
from: {
|
||||
applicationId: string;
|
||||
fileFolder: FileFolder;
|
||||
destinationPath: string;
|
||||
};
|
||||
to: {
|
||||
applicationId: string;
|
||||
fileFolder: FileFolder;
|
||||
destinationPath: string;
|
||||
};
|
||||
workspaceId: string;
|
||||
}): Promise<void> {
|
||||
const file = await this.fileRepository.findOneOrFail({
|
||||
where: {
|
||||
workspaceId,
|
||||
applicationId: from.applicationId,
|
||||
path: `${from.fileFolder}/${from.destinationPath}`,
|
||||
},
|
||||
});
|
||||
|
||||
const driver = this.fileStorageDriverFactory.getCurrentDriver();
|
||||
|
||||
await driver.move({
|
||||
from: {
|
||||
folderPath: `${file.workspaceId}/${from.applicationId}/${from.fileFolder}`,
|
||||
filename: from.destinationPath,
|
||||
},
|
||||
to: {
|
||||
folderPath: `${file.workspaceId}/${to.applicationId}/${to.fileFolder}`,
|
||||
filename: to.destinationPath,
|
||||
},
|
||||
});
|
||||
|
||||
await this.fileRepository.update(file.id, {
|
||||
applicationId: to.applicationId,
|
||||
path: `${to.fileFolder}/${to.destinationPath}`,
|
||||
});
|
||||
}
|
||||
|
||||
move({
|
||||
from,
|
||||
to,
|
||||
}: {
|
||||
from: ResourceIdentifier;
|
||||
to: ResourceIdentifier;
|
||||
}): Promise<void> {
|
||||
const driver = this.fileStorageDriverFactory.getCurrentDriver();
|
||||
|
||||
return driver.move({
|
||||
from: { folderPath: this.buildOnStoragePath(from) },
|
||||
to: { folderPath: this.buildOnStoragePath(to) },
|
||||
from: { folderPath: fromPath },
|
||||
to: { folderPath: toPath },
|
||||
});
|
||||
}
|
||||
|
||||
@@ -425,11 +339,4 @@ export class FileStorageService {
|
||||
|
||||
return driver.checkFileExists({ filePath: onStoragePath });
|
||||
}
|
||||
|
||||
checkFolderExists(params: ResourceIdentifier): Promise<boolean> {
|
||||
const driver = this.fileStorageDriverFactory.getCurrentDriver();
|
||||
const onStoragePath = this.buildOnStoragePath(params);
|
||||
|
||||
return driver.checkFolderExists({ folderPath: onStoragePath });
|
||||
}
|
||||
}
|
||||
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
import { readS3FolderContent } from 'src/engine/core-modules/file-storage/utils/read-s3-folder-content';
|
||||
|
||||
describe('read-s3-folder-content', () => {
|
||||
it('should format files to sources properly', () => {
|
||||
const files = [
|
||||
{ path: 'f1/file1.ts', fileContent: 'content1' },
|
||||
{ path: 'f1/f11/file11.ts', fileContent: 'content11' },
|
||||
{ path: 'f1/file2.ts', fileContent: 'content2' },
|
||||
{ path: 'file3.ts', fileContent: 'content3' },
|
||||
];
|
||||
|
||||
const expectedResult = {
|
||||
'file3.ts': 'content3',
|
||||
f1: {
|
||||
'file1.ts': 'content1',
|
||||
'file2.ts': 'content2',
|
||||
f11: { 'file11.ts': 'content11' },
|
||||
},
|
||||
};
|
||||
|
||||
const result = readS3FolderContent(files);
|
||||
|
||||
expect(result).toEqual(expectedResult);
|
||||
});
|
||||
});
|
||||
-31
@@ -1,31 +0,0 @@
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { isObject } from '@sniptt/guards';
|
||||
import { type Sources } from 'twenty-shared/types';
|
||||
|
||||
export const readS3FolderContent = (
|
||||
files: { path: string; fileContent: string }[],
|
||||
) => {
|
||||
const result: Sources = {};
|
||||
|
||||
for (const { path, fileContent } of files) {
|
||||
const segments = path.split('/');
|
||||
const fileName = segments.pop();
|
||||
|
||||
if (!isDefined(fileName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let cursor: Sources = result;
|
||||
|
||||
for (const segment of segments) {
|
||||
if (!isObject(cursor[segment])) {
|
||||
cursor[segment] = {};
|
||||
}
|
||||
cursor = cursor[segment] as Sources;
|
||||
}
|
||||
|
||||
cursor[fileName] = fileContent;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
+9
-2
@@ -38,8 +38,9 @@ import {
|
||||
LogicFunctionExceptionCode,
|
||||
} from 'src/engine/metadata-modules/logic-function/logic-function.exception';
|
||||
import { type FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type';
|
||||
import { copyYarnEngineAndBuildDependencies } from 'src/engine/core-modules/application-layer/utils/copy-yarn-engine-and-build-dependencies';
|
||||
import { copyYarnEngineAndBuildDependencies } from 'src/engine/core-modules/application/utils/copy-yarn-engine-and-build-dependencies';
|
||||
import { type LogicFunctionResourceService } from 'src/engine/core-modules/logic-function/logic-function-resource/logic-function-resource.service';
|
||||
import { callWithTimeout } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/call-with-timeout';
|
||||
|
||||
const UPDATE_FUNCTION_DURATION_TIMEOUT_IN_SECONDS = 60;
|
||||
const CREDENTIALS_DURATION_IN_SECONDS = 60 * 60; // 1h
|
||||
@@ -322,6 +323,7 @@ export class LambdaDriver implements LogicFunctionDriver {
|
||||
applicationUniversalIdentifier,
|
||||
payload,
|
||||
env,
|
||||
timeoutMs = 900_000,
|
||||
}: LogicFunctionExecuteParams): Promise<LogicFunctionExecuteResult> {
|
||||
await this.build({
|
||||
flatLogicFunction,
|
||||
@@ -355,7 +357,12 @@ export class LambdaDriver implements LogicFunctionDriver {
|
||||
const command = new InvokeCommand(params);
|
||||
|
||||
try {
|
||||
const result = await (await this.getLambdaClient()).send(command);
|
||||
const lambdaClient = await this.getLambdaClient();
|
||||
|
||||
const result = await callWithTimeout({
|
||||
callback: () => lambdaClient.send(command),
|
||||
timeoutMs,
|
||||
});
|
||||
|
||||
const parsedResult = result.Payload
|
||||
? JSON.parse(result.Payload.transformToString())
|
||||
|
||||
+10
-13
@@ -13,7 +13,7 @@ import { LOGIC_FUNCTION_EXECUTOR_TMPDIR_FOLDER } from 'src/engine/core-modules/l
|
||||
import { ConsoleListener } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/intercept-console';
|
||||
import { TemporaryDirManager } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/temporary-dir-manager';
|
||||
import { LogicFunctionExecutionStatus } from 'src/engine/metadata-modules/logic-function/dtos/logic-function-execution-result.dto';
|
||||
import { copyYarnEngineAndBuildDependencies } from 'src/engine/core-modules/application-layer/utils/copy-yarn-engine-and-build-dependencies';
|
||||
import { copyYarnEngineAndBuildDependencies } from 'src/engine/core-modules/application/utils/copy-yarn-engine-and-build-dependencies';
|
||||
import type { LogicFunctionResourceService } from 'src/engine/core-modules/logic-function/logic-function-resource/logic-function-resource.service';
|
||||
|
||||
export interface LocalDriverOptions {
|
||||
@@ -76,6 +76,7 @@ export class LocalDriver implements LogicFunctionDriver {
|
||||
applicationUniversalIdentifier,
|
||||
payload,
|
||||
env,
|
||||
timeoutMs = 900_000,
|
||||
}: LogicFunctionExecuteParams): Promise<LogicFunctionExecuteResult> {
|
||||
await this.build({
|
||||
flatApplication,
|
||||
@@ -89,17 +90,13 @@ export class LocalDriver implements LogicFunctionDriver {
|
||||
try {
|
||||
const { sourceTemporaryDir } = await temporaryDirManager.init();
|
||||
|
||||
const inMemoryBuiltHandlerPath = join(
|
||||
sourceTemporaryDir,
|
||||
flatLogicFunction.builtHandlerPath,
|
||||
);
|
||||
|
||||
await this.logicFunctionResourceService.copyBuiltCodeInMemory({
|
||||
workspaceId: flatLogicFunction.workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
builtHandlerPath: flatLogicFunction.builtHandlerPath,
|
||||
inMemoryDestinationPath: inMemoryBuiltHandlerPath,
|
||||
});
|
||||
const inMemoryBuiltHandlerPath =
|
||||
await this.logicFunctionResourceService.copyBuiltCodeInMemory({
|
||||
workspaceId: flatLogicFunction.workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
builtHandlerPath: flatLogicFunction.builtHandlerPath,
|
||||
inMemoryDestinationPath: sourceTemporaryDir,
|
||||
});
|
||||
|
||||
try {
|
||||
await fs.symlink(
|
||||
@@ -161,7 +158,7 @@ export class LocalDriver implements LogicFunctionDriver {
|
||||
runnerPath,
|
||||
env: env ?? {},
|
||||
payload,
|
||||
timeoutMs: 900_000, // timeout is handled by the logic function service
|
||||
timeoutMs,
|
||||
});
|
||||
|
||||
if (stdout)
|
||||
|
||||
+1
@@ -26,6 +26,7 @@ export type LogicFunctionExecuteParams = {
|
||||
applicationUniversalIdentifier: string;
|
||||
payload: object;
|
||||
env?: Record<string, string>;
|
||||
timeoutMs?: number;
|
||||
};
|
||||
|
||||
export interface LogicFunctionDriver {
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
export const callWithTimeout = async <T>({
|
||||
callback,
|
||||
timeoutMs,
|
||||
}: {
|
||||
callback: () => Promise<T>;
|
||||
timeoutMs: number;
|
||||
}): Promise<T> => {
|
||||
return Promise.race([
|
||||
callback(),
|
||||
new Promise<T>((_, reject) =>
|
||||
setTimeout(() => reject(new Error('Execution timed out')), timeoutMs),
|
||||
),
|
||||
]);
|
||||
};
|
||||
+7
-25
@@ -83,16 +83,13 @@ export class LogicFunctionExecutorService {
|
||||
flatLogicFunction,
|
||||
});
|
||||
|
||||
const resultLogicFunction = await this.callWithTimeout({
|
||||
callback: () =>
|
||||
this.driver.execute({
|
||||
flatLogicFunction,
|
||||
flatApplication,
|
||||
applicationUniversalIdentifier: flatApplication.universalIdentifier,
|
||||
payload,
|
||||
env: envVariables,
|
||||
}),
|
||||
timeoutMs: flatLogicFunction.timeoutSeconds * 1000,
|
||||
const resultLogicFunction = await this.driver.execute({
|
||||
flatLogicFunction,
|
||||
flatApplication,
|
||||
applicationUniversalIdentifier: flatApplication.universalIdentifier,
|
||||
payload,
|
||||
env: envVariables,
|
||||
timeoutMs: flatLogicFunction.timeoutSeconds * 1_000,
|
||||
});
|
||||
|
||||
await this.handleExecutionResult({
|
||||
@@ -121,21 +118,6 @@ export class LogicFunctionExecutorService {
|
||||
}
|
||||
}
|
||||
|
||||
private async callWithTimeout<T>({
|
||||
callback,
|
||||
timeoutMs,
|
||||
}: {
|
||||
callback: () => Promise<T>;
|
||||
timeoutMs: number;
|
||||
}): Promise<T> {
|
||||
return Promise.race([
|
||||
callback(),
|
||||
new Promise<T>((_, reject) =>
|
||||
setTimeout(() => reject(new Error('Execution timed out')), timeoutMs),
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
private async getFlatEntitiesOrThrow({
|
||||
workspaceId,
|
||||
logicFunctionId,
|
||||
|
||||
+63
-125
@@ -4,9 +4,8 @@ import crypto from 'crypto';
|
||||
import fs from 'fs/promises';
|
||||
import { dirname, join } from 'path';
|
||||
|
||||
import { isObject } from '@sniptt/guards';
|
||||
import { build } from 'esbuild';
|
||||
import { FileFolder, Sources } from 'twenty-shared/types';
|
||||
import { FileFolder } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { NODE_ESM_CJS_BANNER } from 'twenty-shared/application';
|
||||
|
||||
@@ -14,64 +13,56 @@ import { FileStorageExceptionCode } from 'src/engine/core-modules/file-storage/i
|
||||
|
||||
import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service';
|
||||
import { TemporaryDirManager } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/temporary-dir-manager';
|
||||
import {
|
||||
getLogicFunctionBaseFolderPath,
|
||||
getRelativePathFromBase,
|
||||
} from 'src/engine/core-modules/logic-function/logic-function-resource/utils/get-logic-function-handler-path.util';
|
||||
import {
|
||||
getLogicFunctionSeedProjectFiles,
|
||||
LogicFunctionSeedProjectFile,
|
||||
} from 'src/engine/core-modules/logic-function/logic-function-resource/utils/get-logic-function-seed-project-files.util';
|
||||
import {
|
||||
DEFAULT_BUILT_HANDLER_PATH,
|
||||
DEFAULT_SOURCE_HANDLER_PATH,
|
||||
} from 'src/engine/metadata-modules/logic-function/logic-function.entity';
|
||||
import {
|
||||
LogicFunctionException,
|
||||
LogicFunctionExceptionCode,
|
||||
} from 'src/engine/metadata-modules/logic-function/logic-function.exception';
|
||||
import { streamToBuffer } from 'src/utils/stream-to-buffer';
|
||||
|
||||
type SeedSourceFilesParams = {
|
||||
type Identifier = {
|
||||
workspaceId: string;
|
||||
applicationUniversalIdentifier: string;
|
||||
sourceSubfolder: string;
|
||||
};
|
||||
|
||||
type SeedSourceFilesParams = Identifier & {
|
||||
sourceHandlerPath: string;
|
||||
builtHandlerPath: string;
|
||||
};
|
||||
|
||||
type SeedSourceFilesResult = {
|
||||
sourceHandlerPath: string;
|
||||
builtHandlerPath: string;
|
||||
handlerName: string;
|
||||
checksum: string;
|
||||
};
|
||||
|
||||
type UpdateSourceFilesParams = {
|
||||
sourceHandlerPath: string;
|
||||
workspaceId: string;
|
||||
applicationUniversalIdentifier: string;
|
||||
code: Sources;
|
||||
type UpdateSourceFilesParams = Omit<
|
||||
SeedSourceFilesParams,
|
||||
'builtHandlerPath'
|
||||
> & {
|
||||
sourceHandlerCode: string;
|
||||
};
|
||||
|
||||
type BuildFromSourceParams = {
|
||||
type BuildFromSourceParams = Identifier & {
|
||||
sourceHandlerPath: string;
|
||||
builtHandlerPath: string;
|
||||
workspaceId: string;
|
||||
applicationUniversalIdentifier: string;
|
||||
};
|
||||
|
||||
type GetSourceCodeParams = {
|
||||
type GetSourceCodeParams = Identifier & {
|
||||
sourceHandlerPath: string;
|
||||
workspaceId: string;
|
||||
applicationUniversalIdentifier: string;
|
||||
};
|
||||
|
||||
type CopySourceParams = {
|
||||
type GetBuiltCodeParams = Identifier & {
|
||||
builtHandlerPath: string;
|
||||
};
|
||||
|
||||
type CopySourceParams = Identifier & {
|
||||
fromSourceHandlerPath: string;
|
||||
fromBuiltHandlerPath: string;
|
||||
toSourceHandlerPath: string;
|
||||
fromBuiltHandlerPath: string;
|
||||
toBuiltHandlerPath: string;
|
||||
workspaceId: string;
|
||||
applicationUniversalIdentifier: string;
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
@@ -81,11 +72,9 @@ export class LogicFunctionResourceService {
|
||||
async seedSourceFiles({
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
sourceSubfolder,
|
||||
sourceHandlerPath,
|
||||
builtHandlerPath,
|
||||
}: SeedSourceFilesParams): Promise<SeedSourceFilesResult> {
|
||||
const sourceHandlerPath = `${sourceSubfolder}/${DEFAULT_SOURCE_HANDLER_PATH}`;
|
||||
const builtHandlerPath = `${sourceSubfolder}/${DEFAULT_BUILT_HANDLER_PATH}`;
|
||||
|
||||
const seedProjectFiles = await getLogicFunctionSeedProjectFiles();
|
||||
|
||||
const sourceFiles = seedProjectFiles.filter(
|
||||
@@ -138,40 +127,28 @@ export class LogicFunctionResourceService {
|
||||
|
||||
return {
|
||||
handlerName: 'main',
|
||||
sourceHandlerPath,
|
||||
builtHandlerPath,
|
||||
checksum,
|
||||
};
|
||||
}
|
||||
|
||||
async updateSourceFiles({
|
||||
async uploadSourceFile({
|
||||
sourceHandlerPath,
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
code,
|
||||
sourceHandlerCode,
|
||||
}: UpdateSourceFilesParams): Promise<void> {
|
||||
const temporaryDirManager = new TemporaryDirManager();
|
||||
|
||||
try {
|
||||
const { sourceTemporaryDir } = await temporaryDirManager.init();
|
||||
|
||||
await this.writeSourcesToLocalFolder(code, sourceTemporaryDir);
|
||||
|
||||
const baseFolderPath = getLogicFunctionBaseFolderPath(sourceHandlerPath);
|
||||
|
||||
await this.fileStorageService.uploadFolder({
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
fileFolder: FileFolder.Source,
|
||||
resourcePath: baseFolderPath,
|
||||
localPath: sourceTemporaryDir,
|
||||
});
|
||||
} finally {
|
||||
await temporaryDirManager.clean();
|
||||
}
|
||||
await this.fileStorageService.writeFile({
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
fileFolder: FileFolder.Source,
|
||||
resourcePath: sourceHandlerPath,
|
||||
sourceFile: sourceHandlerCode,
|
||||
settings: { isTemporaryFile: false, toDelete: false },
|
||||
mimeType: 'application/typescript',
|
||||
});
|
||||
}
|
||||
|
||||
async buildFromSource({
|
||||
async buildFromSourceFile({
|
||||
sourceHandlerPath,
|
||||
builtHandlerPath,
|
||||
workspaceId,
|
||||
@@ -182,29 +159,18 @@ export class LogicFunctionResourceService {
|
||||
try {
|
||||
const { sourceTemporaryDir } = await temporaryDirManager.init();
|
||||
|
||||
const baseFolderPath = getLogicFunctionBaseFolderPath(sourceHandlerPath);
|
||||
|
||||
await this.fileStorageService.downloadFolder({
|
||||
await this.fileStorageService.downloadFile({
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
fileFolder: FileFolder.Source,
|
||||
resourcePath: baseFolderPath,
|
||||
localPath: sourceTemporaryDir,
|
||||
resourcePath: sourceHandlerPath,
|
||||
localPath: join(sourceTemporaryDir, sourceHandlerPath),
|
||||
});
|
||||
|
||||
const relativeSourcePath = getRelativePathFromBase(
|
||||
sourceHandlerPath,
|
||||
baseFolderPath,
|
||||
);
|
||||
const relativeBuiltPath = getRelativePathFromBase(
|
||||
builtHandlerPath,
|
||||
baseFolderPath,
|
||||
);
|
||||
|
||||
const builtBundleFilePath = await this.buildInMemory({
|
||||
sourceTemporaryDir,
|
||||
sourceHandlerPath: relativeSourcePath,
|
||||
builtHandlerPath: relativeBuiltPath,
|
||||
sourceHandlerPath,
|
||||
builtHandlerPath,
|
||||
});
|
||||
|
||||
const builtFile = await fs.readFile(builtBundleFilePath, 'utf-8');
|
||||
@@ -230,20 +196,22 @@ export class LogicFunctionResourceService {
|
||||
}
|
||||
}
|
||||
|
||||
async getSourceCode({
|
||||
async getSourceFile({
|
||||
sourceHandlerPath,
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
}: GetSourceCodeParams): Promise<Sources | null> {
|
||||
const baseFolderPath = getLogicFunctionBaseFolderPath(sourceHandlerPath);
|
||||
|
||||
}: GetSourceCodeParams): Promise<string | null> {
|
||||
try {
|
||||
return await this.fileStorageService.readFolder({
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
fileFolder: FileFolder.Source,
|
||||
resourcePath: baseFolderPath,
|
||||
});
|
||||
return (
|
||||
await streamToBuffer(
|
||||
await this.fileStorageService.readFile({
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
fileFolder: FileFolder.Source,
|
||||
resourcePath: sourceHandlerPath,
|
||||
}),
|
||||
)
|
||||
).toString('utf-8');
|
||||
} catch (error) {
|
||||
if (
|
||||
isDefined(error) &&
|
||||
@@ -259,34 +227,24 @@ export class LogicFunctionResourceService {
|
||||
|
||||
async copyResources({
|
||||
fromSourceHandlerPath,
|
||||
fromBuiltHandlerPath,
|
||||
toSourceHandlerPath,
|
||||
fromBuiltHandlerPath,
|
||||
toBuiltHandlerPath,
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
}: CopySourceParams): Promise<void> {
|
||||
const fromSourceBaseFolderPath = getLogicFunctionBaseFolderPath(
|
||||
fromSourceHandlerPath,
|
||||
);
|
||||
const toSourceBaseFolderPath =
|
||||
getLogicFunctionBaseFolderPath(toSourceHandlerPath);
|
||||
const fromBuiltBaseFolderPath =
|
||||
getLogicFunctionBaseFolderPath(fromBuiltHandlerPath);
|
||||
const toBuiltBaseFolderPath =
|
||||
getLogicFunctionBaseFolderPath(toBuiltHandlerPath);
|
||||
|
||||
await this.fileStorageService.copy({
|
||||
from: {
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
fileFolder: FileFolder.Source,
|
||||
resourcePath: fromSourceBaseFolderPath,
|
||||
resourcePath: fromSourceHandlerPath,
|
||||
},
|
||||
to: {
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
fileFolder: FileFolder.Source,
|
||||
resourcePath: toSourceBaseFolderPath,
|
||||
resourcePath: toSourceHandlerPath,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -295,13 +253,13 @@ export class LogicFunctionResourceService {
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
fileFolder: FileFolder.BuiltLogicFunction,
|
||||
resourcePath: fromBuiltBaseFolderPath,
|
||||
resourcePath: fromBuiltHandlerPath,
|
||||
},
|
||||
to: {
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
fileFolder: FileFolder.BuiltLogicFunction,
|
||||
resourcePath: toBuiltBaseFolderPath,
|
||||
resourcePath: toBuiltHandlerPath,
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -337,11 +295,7 @@ export class LogicFunctionResourceService {
|
||||
builtHandlerPath,
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
}: {
|
||||
builtHandlerPath: string;
|
||||
workspaceId: string;
|
||||
applicationUniversalIdentifier: string;
|
||||
}): Promise<string> {
|
||||
}: GetBuiltCodeParams): Promise<string> {
|
||||
return (
|
||||
await streamToBuffer(
|
||||
await this.fileStorageService.readFile({
|
||||
@@ -359,36 +313,20 @@ export class LogicFunctionResourceService {
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
inMemoryDestinationPath,
|
||||
}: {
|
||||
builtHandlerPath: string;
|
||||
workspaceId: string;
|
||||
applicationUniversalIdentifier: string;
|
||||
}: GetBuiltCodeParams & {
|
||||
inMemoryDestinationPath: string;
|
||||
}): Promise<void> {
|
||||
}): Promise<string> {
|
||||
const localPath = join(inMemoryDestinationPath, builtHandlerPath);
|
||||
|
||||
await this.fileStorageService.downloadFile({
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
fileFolder: FileFolder.BuiltLogicFunction,
|
||||
resourcePath: builtHandlerPath,
|
||||
localPath: inMemoryDestinationPath,
|
||||
localPath,
|
||||
});
|
||||
}
|
||||
|
||||
async writeSourcesToLocalFolder(
|
||||
sources: Sources,
|
||||
localPath: string,
|
||||
): Promise<void> {
|
||||
for (const key of Object.keys(sources)) {
|
||||
const filePath = join(localPath, key);
|
||||
const value = sources[key];
|
||||
|
||||
if (isObject(value)) {
|
||||
await this.writeSourcesToLocalFolder(value as Sources, filePath);
|
||||
continue;
|
||||
}
|
||||
await fs.mkdir(dirname(filePath), { recursive: true });
|
||||
await fs.writeFile(filePath, value);
|
||||
}
|
||||
return localPath;
|
||||
}
|
||||
|
||||
private async buildInMemory({
|
||||
|
||||
+1
@@ -84,6 +84,7 @@ exports[`ALL_UNIVERSAL_FLAT_ENTITY_PROPERTIES_TO_COMPARE_AND_STRINGIFY should ma
|
||||
"handlerName",
|
||||
"toolInputSchema",
|
||||
"isTool",
|
||||
"isBuildUpToDate",
|
||||
"deletedAt",
|
||||
"cronTriggerSettings",
|
||||
"databaseEventTriggerSettings",
|
||||
+1
@@ -149,6 +149,7 @@ export const ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME = {
|
||||
handlerName: { toStringify: false, universalProperty: undefined },
|
||||
toolInputSchema: { toStringify: true, universalProperty: undefined },
|
||||
isTool: { toStringify: false, universalProperty: undefined },
|
||||
isBuildUpToDate: { toStringify: false, universalProperty: undefined },
|
||||
deletedAt: { toStringify: false, universalProperty: undefined },
|
||||
cronTriggerSettings: { toStringify: true, universalProperty: undefined },
|
||||
databaseEventTriggerSettings: {
|
||||
|
||||
+2
-1
@@ -12,4 +12,5 @@ export const FLAT_LOGIC_FUNCTION_EDITABLE_PROPERTIES = [
|
||||
'cronTriggerSettings',
|
||||
'databaseEventTriggerSettings',
|
||||
'httpRouteTriggerSettings',
|
||||
] as const satisfies (MetadataEntityPropertyName<'logicFunction'> | 'code')[];
|
||||
'isBuildUpToDate',
|
||||
] as const satisfies MetadataEntityPropertyName<'logicFunction'>[];
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
export const DEFAULT_BUILT_HANDLER_PATH = 'src/index.mjs';
|
||||
export const DEFAULT_SOURCE_HANDLER_PATH = 'src/index.ts';
|
||||
export const DEFAULT_HANDLER_NAME = 'main';
|
||||
-52
@@ -1,52 +0,0 @@
|
||||
import { Field, HideField, InputType } from '@nestjs/graphql';
|
||||
|
||||
import {
|
||||
IsBoolean,
|
||||
IsNotEmpty,
|
||||
IsNumber,
|
||||
IsObject,
|
||||
IsOptional,
|
||||
IsString,
|
||||
Max,
|
||||
Min,
|
||||
} from 'class-validator';
|
||||
import graphqlTypeJson from 'graphql-type-json';
|
||||
|
||||
@InputType()
|
||||
export class CreateDefaultLogicFunctionInput {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@Field()
|
||||
name: string;
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
@Field({ nullable: true })
|
||||
description?: string;
|
||||
|
||||
@IsNumber()
|
||||
@Field({ nullable: true })
|
||||
@Min(1)
|
||||
@Max(900)
|
||||
@IsOptional()
|
||||
timeoutSeconds?: number;
|
||||
|
||||
@HideField()
|
||||
applicationId?: string;
|
||||
|
||||
@HideField()
|
||||
universalIdentifier?: string;
|
||||
|
||||
@HideField()
|
||||
id?: string;
|
||||
|
||||
@Field(() => graphqlTypeJson, { nullable: true })
|
||||
@IsObject()
|
||||
@IsOptional()
|
||||
toolInputSchema?: object;
|
||||
|
||||
@IsBoolean()
|
||||
@Field({ nullable: true })
|
||||
@IsOptional()
|
||||
isTool?: boolean;
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
import { Field, InputType } from '@nestjs/graphql';
|
||||
|
||||
import {
|
||||
IsBoolean,
|
||||
IsNotEmpty,
|
||||
IsNumber,
|
||||
IsObject,
|
||||
IsOptional,
|
||||
IsString,
|
||||
IsUUID,
|
||||
Max,
|
||||
Min,
|
||||
} from 'class-validator';
|
||||
import graphqlTypeJson from 'graphql-type-json';
|
||||
import {
|
||||
CronTriggerSettings,
|
||||
DatabaseEventTriggerSettings,
|
||||
HttpRouteTriggerSettings,
|
||||
} from 'twenty-shared/application';
|
||||
|
||||
import type { JsonbProperty } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/jsonb-property.type';
|
||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||
import { LogicFunctionSourceInput } from 'src/engine/metadata-modules/logic-function/dtos/logic-function-source.input';
|
||||
|
||||
@InputType()
|
||||
export class CreateLogicFunctionFromSourceInput {
|
||||
@IsUUID()
|
||||
@IsOptional()
|
||||
@Field(() => UUIDScalarType, { nullable: true })
|
||||
id?: string;
|
||||
|
||||
@IsUUID()
|
||||
@IsOptional()
|
||||
@Field(() => UUIDScalarType, { nullable: true })
|
||||
universalIdentifier?: string;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@Field()
|
||||
name: string;
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
@Field({ nullable: true })
|
||||
description?: string;
|
||||
|
||||
@IsNumber()
|
||||
@Field({ nullable: true })
|
||||
@Min(1)
|
||||
@Max(900)
|
||||
@IsOptional()
|
||||
timeoutSeconds?: number;
|
||||
|
||||
@Field(() => graphqlTypeJson, { nullable: true })
|
||||
@IsObject()
|
||||
@IsOptional()
|
||||
toolInputSchema?: object;
|
||||
|
||||
@IsBoolean()
|
||||
@Field({ nullable: true })
|
||||
@IsOptional()
|
||||
isTool?: boolean;
|
||||
|
||||
@IsObject()
|
||||
@Field(() => graphqlTypeJson, { nullable: true })
|
||||
@IsOptional()
|
||||
source?: JsonbProperty<LogicFunctionSourceInput>;
|
||||
|
||||
@IsObject()
|
||||
@Field(() => graphqlTypeJson, { nullable: true })
|
||||
@IsOptional()
|
||||
cronTriggerSettings?: JsonbProperty<CronTriggerSettings>;
|
||||
|
||||
@IsObject()
|
||||
@Field(() => graphqlTypeJson, { nullable: true })
|
||||
@IsOptional()
|
||||
databaseEventTriggerSettings?: JsonbProperty<DatabaseEventTriggerSettings>;
|
||||
|
||||
@IsObject()
|
||||
@Field(() => graphqlTypeJson, { nullable: true })
|
||||
@IsOptional()
|
||||
httpRouteTriggerSettings?: JsonbProperty<HttpRouteTriggerSettings>;
|
||||
}
|
||||
+58
-6
@@ -1,6 +1,16 @@
|
||||
import { Field, HideField, InputType } from '@nestjs/graphql';
|
||||
import { Field, InputType } from '@nestjs/graphql';
|
||||
|
||||
import { IsObject, IsOptional, IsString } from 'class-validator';
|
||||
import {
|
||||
IsBoolean,
|
||||
IsNotEmpty,
|
||||
IsNumber,
|
||||
IsObject,
|
||||
IsOptional,
|
||||
IsString,
|
||||
IsUUID,
|
||||
Max,
|
||||
Min,
|
||||
} from 'class-validator';
|
||||
import graphqlTypeJson from 'graphql-type-json';
|
||||
import {
|
||||
CronTriggerSettings,
|
||||
@@ -9,12 +19,54 @@ import {
|
||||
} from 'twenty-shared/application';
|
||||
|
||||
import type { JsonbProperty } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/jsonb-property.type';
|
||||
import { CreateDefaultLogicFunctionInput } from 'src/engine/metadata-modules/logic-function/dtos/create-default-logic-function.input';
|
||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||
|
||||
@InputType()
|
||||
export class CreateLogicFunctionInput extends CreateDefaultLogicFunctionInput {
|
||||
@HideField()
|
||||
checksum: string;
|
||||
export class CreateLogicFunction {
|
||||
@IsUUID()
|
||||
@IsOptional()
|
||||
@Field(() => UUIDScalarType, { nullable: true })
|
||||
id?: string;
|
||||
|
||||
@IsUUID()
|
||||
@IsOptional()
|
||||
@Field(() => UUIDScalarType, { nullable: true })
|
||||
universalIdentifier?: string;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@Field()
|
||||
name: string;
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
@Field({ nullable: true })
|
||||
description?: string;
|
||||
|
||||
@IsNumber()
|
||||
@Field({ nullable: true })
|
||||
@Min(1)
|
||||
@Max(900)
|
||||
@IsOptional()
|
||||
timeoutSeconds?: number;
|
||||
|
||||
@Field(() => graphqlTypeJson, { nullable: false })
|
||||
@IsObject()
|
||||
toolInputSchema: object;
|
||||
|
||||
@IsBoolean()
|
||||
@Field({ nullable: true })
|
||||
@IsOptional()
|
||||
isTool?: boolean;
|
||||
|
||||
@IsBoolean()
|
||||
@Field({ nullable: false })
|
||||
isBuildUpToDate: boolean;
|
||||
|
||||
@IsString()
|
||||
@Field({ nullable: true })
|
||||
@IsOptional()
|
||||
checksum?: string;
|
||||
|
||||
@IsString()
|
||||
@Field({ nullable: false })
|
||||
|
||||
+1
-15
@@ -1,12 +1,6 @@
|
||||
import { Field, InputType } from '@nestjs/graphql';
|
||||
|
||||
import {
|
||||
IsBoolean,
|
||||
IsNotEmpty,
|
||||
IsObject,
|
||||
IsOptional,
|
||||
IsUUID,
|
||||
} from 'class-validator';
|
||||
import { IsNotEmpty, IsObject, IsUUID } from 'class-validator';
|
||||
import graphqlTypeJson from 'graphql-type-json';
|
||||
|
||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||
@@ -25,12 +19,4 @@ export class ExecuteOneLogicFunctionInput {
|
||||
})
|
||||
@IsObject()
|
||||
payload: JSON;
|
||||
|
||||
@Field(() => Boolean, {
|
||||
description: 'Force rebuild from source before executing',
|
||||
nullable: true,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
forceRebuild?: boolean;
|
||||
}
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
import { Field, InputType } from '@nestjs/graphql';
|
||||
|
||||
import { IsObject, IsString } from 'class-validator';
|
||||
import graphqlTypeJson from 'graphql-type-json';
|
||||
|
||||
@InputType()
|
||||
export class LogicFunctionSourceInput {
|
||||
@IsString()
|
||||
@Field({ nullable: false })
|
||||
sourceHandlerCode: string;
|
||||
|
||||
@Field(() => graphqlTypeJson, { nullable: false })
|
||||
@IsObject()
|
||||
toolInputSchema: object;
|
||||
|
||||
@IsString()
|
||||
@Field({ nullable: false })
|
||||
handlerName: string;
|
||||
}
|
||||
-4
@@ -62,10 +62,6 @@ export class LogicFunctionDTO {
|
||||
@Field()
|
||||
sourceHandlerPath: string;
|
||||
|
||||
@IsString()
|
||||
@Field()
|
||||
builtHandlerPath: string;
|
||||
|
||||
@IsString()
|
||||
@Field()
|
||||
handlerName: string;
|
||||
|
||||
+21
-16
@@ -24,9 +24,9 @@ import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/
|
||||
import type { JsonbProperty } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/jsonb-property.type';
|
||||
|
||||
@InputType()
|
||||
class UpdateLogicFunctionInputUpdates {
|
||||
class UpdateLogicFunctionFromSourceInputUpdates {
|
||||
@IsString()
|
||||
@Field()
|
||||
@Field({ nullable: true })
|
||||
@IsOptional()
|
||||
name?: string;
|
||||
|
||||
@@ -42,6 +42,16 @@ class UpdateLogicFunctionInputUpdates {
|
||||
@IsOptional()
|
||||
timeoutSeconds?: number;
|
||||
|
||||
@IsString()
|
||||
@Field({ nullable: true })
|
||||
@IsOptional()
|
||||
sourceHandlerCode?: string;
|
||||
|
||||
@Field(() => graphqlTypeJson, { nullable: true })
|
||||
@IsObject()
|
||||
@IsOptional()
|
||||
toolInputSchema?: object;
|
||||
|
||||
@IsString()
|
||||
@Field({ nullable: true })
|
||||
@IsOptional()
|
||||
@@ -52,21 +62,16 @@ class UpdateLogicFunctionInputUpdates {
|
||||
@IsOptional()
|
||||
sourceHandlerPath?: string;
|
||||
|
||||
@IsString()
|
||||
@Field({ nullable: true })
|
||||
@IsOptional()
|
||||
builtHandlerPath?: string;
|
||||
|
||||
@Field(() => graphqlTypeJson, { nullable: true })
|
||||
@IsObject()
|
||||
@IsOptional()
|
||||
toolInputSchema?: object;
|
||||
|
||||
@IsBoolean()
|
||||
@Field({ nullable: true })
|
||||
@IsOptional()
|
||||
isTool?: boolean;
|
||||
|
||||
@IsBoolean()
|
||||
@Field({ nullable: true })
|
||||
@IsOptional()
|
||||
isBuildUpToDate?: boolean;
|
||||
|
||||
@IsString()
|
||||
@Field({ nullable: true })
|
||||
@IsOptional()
|
||||
@@ -89,7 +94,7 @@ class UpdateLogicFunctionInputUpdates {
|
||||
}
|
||||
|
||||
@InputType()
|
||||
export class UpdateLogicFunctionSourceInput {
|
||||
export class UpdateLogicFunctionFromSourceInput {
|
||||
@Field(() => UUIDScalarType, {
|
||||
description: 'Id of the logic function to update',
|
||||
})
|
||||
@@ -97,10 +102,10 @@ export class UpdateLogicFunctionSourceInput {
|
||||
@IsUUID()
|
||||
id: string;
|
||||
|
||||
@Type(() => UpdateLogicFunctionInputUpdates)
|
||||
@Type(() => UpdateLogicFunctionFromSourceInputUpdates)
|
||||
@ValidateNested()
|
||||
@Field(() => UpdateLogicFunctionInputUpdates, {
|
||||
@Field(() => UpdateLogicFunctionFromSourceInputUpdates, {
|
||||
description: 'The logic function updates',
|
||||
})
|
||||
update: UpdateLogicFunctionInputUpdates;
|
||||
update: UpdateLogicFunctionFromSourceInputUpdates;
|
||||
}
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
import { Field, InputType } from '@nestjs/graphql';
|
||||
|
||||
import { IsNotEmpty, IsObject, IsUUID } from 'class-validator';
|
||||
import graphqlTypeJson from 'graphql-type-json';
|
||||
|
||||
import type { Sources } from 'twenty-shared/types';
|
||||
|
||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||
|
||||
@InputType()
|
||||
export class UpdateLogicFunctionSourceInput {
|
||||
@Field(() => UUIDScalarType, {
|
||||
description: 'The id of the logic function.',
|
||||
})
|
||||
@IsNotEmpty()
|
||||
@IsUUID()
|
||||
id!: string;
|
||||
|
||||
@Field(() => graphqlTypeJson, {
|
||||
description:
|
||||
'The source code (Sources) to write. Only updates source files.',
|
||||
})
|
||||
@IsObject()
|
||||
code!: Sources;
|
||||
}
|
||||
+6
-7
@@ -24,10 +24,6 @@ export enum LogicFunctionRuntime {
|
||||
NODE22 = 'nodejs22.x',
|
||||
}
|
||||
|
||||
export const DEFAULT_SOURCE_HANDLER_PATH = 'src/index.ts';
|
||||
export const DEFAULT_BUILT_HANDLER_PATH = 'src/index.mjs';
|
||||
export const DEFAULT_HANDLER_NAME = 'main';
|
||||
|
||||
@Entity('logicFunction')
|
||||
@Index('IDX_LOGIC_FUNCTION_ID_DELETED_AT', ['id', 'deletedAt'])
|
||||
export class LogicFunctionEntity
|
||||
@@ -40,13 +36,13 @@ export class LogicFunctionEntity
|
||||
@Column({ nullable: false })
|
||||
name: string;
|
||||
|
||||
@Column({ nullable: false, default: DEFAULT_SOURCE_HANDLER_PATH })
|
||||
@Column({ nullable: false })
|
||||
sourceHandlerPath: string;
|
||||
|
||||
@Column({ nullable: false, default: DEFAULT_BUILT_HANDLER_PATH })
|
||||
@Column({ nullable: false })
|
||||
builtHandlerPath: string;
|
||||
|
||||
@Column({ nullable: false, default: DEFAULT_HANDLER_NAME })
|
||||
@Column({ nullable: false })
|
||||
handlerName: string;
|
||||
|
||||
@Column({ nullable: true, type: 'varchar' })
|
||||
@@ -68,6 +64,9 @@ export class LogicFunctionEntity
|
||||
@Column({ nullable: false, default: false })
|
||||
isTool: boolean;
|
||||
|
||||
@Column({ nullable: false, type: 'boolean', default: true })
|
||||
isBuildUpToDate: boolean;
|
||||
|
||||
@Column({ nullable: true, type: 'jsonb' })
|
||||
cronTriggerSettings: JsonbProperty<CronTriggerSettings> | null;
|
||||
|
||||
|
||||
+3
-5
@@ -3,7 +3,6 @@ import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm';
|
||||
|
||||
import { ApplicationLayerModule } from 'src/engine/core-modules/application-layer/application-layer.module';
|
||||
import { ApplicationEntity } from 'src/engine/core-modules/application/application.entity';
|
||||
import { ApplicationModule } from 'src/engine/core-modules/application/application.module';
|
||||
import { AuditModule } from 'src/engine/core-modules/audit/audit.module';
|
||||
@@ -19,7 +18,7 @@ import { LogicFunctionLayerModule } from 'src/engine/metadata-modules/logic-func
|
||||
import { LogicFunctionEntity } from 'src/engine/metadata-modules/logic-function/logic-function.entity';
|
||||
import { LogicFunctionResolver } from 'src/engine/metadata-modules/logic-function/logic-function.resolver';
|
||||
import { LogicFunctionMetadataService } from 'src/engine/metadata-modules/logic-function/services/logic-function-metadata.service';
|
||||
import { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/services/logic-function.service';
|
||||
import { LogicFunctionFromSourceService } from 'src/engine/metadata-modules/logic-function/services/logic-function-from-source.service';
|
||||
import { WorkspaceFlatLogicFunctionMapCacheService } from 'src/engine/metadata-modules/logic-function/services/workspace-flat-logic-function-map-cache.service';
|
||||
import { PermissionsModule } from 'src/engine/metadata-modules/permissions/permissions.module';
|
||||
import { SubscriptionsModule } from 'src/engine/subscriptions/subscriptions.module';
|
||||
@@ -32,7 +31,6 @@ import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace
|
||||
TypeOrmModule.forFeature([ApplicationEntity, FeatureFlagEntity]),
|
||||
ThrottlerModule,
|
||||
ApplicationModule,
|
||||
ApplicationLayerModule,
|
||||
AuditModule,
|
||||
FeatureFlagModule,
|
||||
PermissionsModule,
|
||||
@@ -46,10 +44,10 @@ import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace
|
||||
],
|
||||
providers: [
|
||||
LogicFunctionMetadataService,
|
||||
LogicFunctionService,
|
||||
LogicFunctionFromSourceService,
|
||||
LogicFunctionResolver,
|
||||
WorkspaceFlatLogicFunctionMapCacheService,
|
||||
],
|
||||
exports: [LogicFunctionMetadataService, LogicFunctionService],
|
||||
exports: [LogicFunctionMetadataService, LogicFunctionFromSourceService],
|
||||
})
|
||||
export class LogicFunctionModule {}
|
||||
|
||||
+30
-21
@@ -14,18 +14,19 @@ import { FeatureFlagGuard } from 'src/engine/guards/feature-flag.guard';
|
||||
import { NoPermissionGuard } from 'src/engine/guards/no-permission.guard';
|
||||
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
|
||||
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||
import { CreateDefaultLogicFunctionInput } from 'src/engine/metadata-modules/logic-function/dtos/create-default-logic-function.input';
|
||||
import { ExecuteOneLogicFunctionInput } from 'src/engine/metadata-modules/logic-function/dtos/execute-logic-function.input';
|
||||
import { LogicFunctionExecutionResultDTO } from 'src/engine/metadata-modules/logic-function/dtos/logic-function-execution-result.dto';
|
||||
import { LogicFunctionIdInput } from 'src/engine/metadata-modules/logic-function/dtos/logic-function-id.input';
|
||||
import { LogicFunctionLogsDTO } from 'src/engine/metadata-modules/logic-function/dtos/logic-function-logs.dto';
|
||||
import { LogicFunctionLogsInput } from 'src/engine/metadata-modules/logic-function/dtos/logic-function-logs.input';
|
||||
import { LogicFunctionDTO } from 'src/engine/metadata-modules/logic-function/dtos/logic-function.dto';
|
||||
import { UpdateLogicFunctionSourceInput } from 'src/engine/metadata-modules/logic-function/dtos/update-logic-function-source.input';
|
||||
import { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/services/logic-function.service';
|
||||
import { LogicFunctionFromSourceService } from 'src/engine/metadata-modules/logic-function/services/logic-function-from-source.service';
|
||||
import { logicFunctionGraphQLApiExceptionHandler } from 'src/engine/metadata-modules/logic-function/utils/logic-function-graphql-api-exception-handler.utils';
|
||||
import { SubscriptionChannel } from 'src/engine/subscriptions/enums/subscription-channel.enum';
|
||||
import { SubscriptionService } from 'src/engine/subscriptions/subscription.service';
|
||||
import { CreateLogicFunctionFromSourceInput } from 'src/engine/metadata-modules/logic-function/dtos/create-logic-function-from-source.input';
|
||||
import { UpdateLogicFunctionFromSourceInput } from 'src/engine/metadata-modules/logic-function/dtos/update-logic-function-from-source.input';
|
||||
import { LogicFunctionMetadataService } from 'src/engine/metadata-modules/logic-function/services/logic-function-metadata.service';
|
||||
|
||||
@UseGuards(WorkspaceAuthGuard, FeatureFlagGuard, NoPermissionGuard)
|
||||
@MetadataResolver()
|
||||
@@ -33,7 +34,8 @@ import { SubscriptionService } from 'src/engine/subscriptions/subscription.servi
|
||||
@UseFilters(PreventNestToAutoLogGraphqlErrorsFilter)
|
||||
export class LogicFunctionResolver {
|
||||
constructor(
|
||||
private readonly logicFunctionService: LogicFunctionService,
|
||||
private readonly logicFunctionFromSourceService: LogicFunctionFromSourceService,
|
||||
private readonly logicFunctionMetadataService: LogicFunctionMetadataService,
|
||||
private readonly subscriptionService: SubscriptionService,
|
||||
) {}
|
||||
|
||||
@@ -43,7 +45,10 @@ export class LogicFunctionResolver {
|
||||
@AuthWorkspace() { id: workspaceId }: WorkspaceEntity,
|
||||
): Promise<LogicFunctionDTO> {
|
||||
try {
|
||||
return await this.logicFunctionService.findOne({ id, workspaceId });
|
||||
return await this.logicFunctionMetadataService.findOne({
|
||||
id,
|
||||
workspaceId,
|
||||
});
|
||||
} catch (error) {
|
||||
return logicFunctionGraphQLApiExceptionHandler(error);
|
||||
}
|
||||
@@ -54,7 +59,9 @@ export class LogicFunctionResolver {
|
||||
@AuthWorkspace() { id: workspaceId }: WorkspaceEntity,
|
||||
): Promise<LogicFunctionDTO[]> {
|
||||
try {
|
||||
return await this.logicFunctionService.findMany({ workspaceId });
|
||||
return await this.logicFunctionMetadataService.findMany({
|
||||
workspaceId,
|
||||
});
|
||||
} catch (error) {
|
||||
return logicFunctionGraphQLApiExceptionHandler(error);
|
||||
}
|
||||
@@ -67,8 +74,8 @@ export class LogicFunctionResolver {
|
||||
@AuthWorkspace() { id: workspaceId }: WorkspaceEntity,
|
||||
) {
|
||||
try {
|
||||
return await this.logicFunctionService.getAvailablePackages({
|
||||
id,
|
||||
return await this.logicFunctionMetadataService.getAvailablePackages({
|
||||
logicFunctionId: id,
|
||||
workspaceId,
|
||||
});
|
||||
} catch (error) {
|
||||
@@ -83,7 +90,10 @@ export class LogicFunctionResolver {
|
||||
@AuthWorkspace() { id: workspaceId }: WorkspaceEntity,
|
||||
): Promise<LogicFunctionDTO> {
|
||||
try {
|
||||
return await this.logicFunctionService.deleteOne({ id, workspaceId });
|
||||
return await this.logicFunctionFromSourceService.deleteOne({
|
||||
id,
|
||||
workspaceId,
|
||||
});
|
||||
} catch (error) {
|
||||
return logicFunctionGraphQLApiExceptionHandler(error);
|
||||
}
|
||||
@@ -91,12 +101,12 @@ export class LogicFunctionResolver {
|
||||
|
||||
@Mutation(() => LogicFunctionDTO)
|
||||
@UseGuards(SettingsPermissionGuard(PermissionFlagType.WORKFLOWS))
|
||||
async createDefaultLogicFunction(
|
||||
@Args('input') input: CreateDefaultLogicFunctionInput,
|
||||
async createOneLogicFunction(
|
||||
@Args('input') input: CreateLogicFunctionFromSourceInput,
|
||||
@AuthWorkspace() { id: workspaceId }: WorkspaceEntity,
|
||||
): Promise<LogicFunctionDTO> {
|
||||
try {
|
||||
return await this.logicFunctionService.createDefault({
|
||||
return await this.logicFunctionFromSourceService.createOne({
|
||||
input,
|
||||
workspaceId,
|
||||
});
|
||||
@@ -108,14 +118,13 @@ export class LogicFunctionResolver {
|
||||
@Mutation(() => LogicFunctionExecutionResultDTO)
|
||||
@UseGuards(SettingsPermissionGuard(PermissionFlagType.WORKFLOWS))
|
||||
async executeOneLogicFunction(
|
||||
@Args('input') { id, payload, forceRebuild }: ExecuteOneLogicFunctionInput,
|
||||
@Args('input') { id, payload }: ExecuteOneLogicFunctionInput,
|
||||
@AuthWorkspace() { id: workspaceId }: WorkspaceEntity,
|
||||
): Promise<LogicFunctionExecutionResultDTO> {
|
||||
try {
|
||||
return await this.logicFunctionService.executeOne({
|
||||
return await this.logicFunctionFromSourceService.executeOne({
|
||||
id,
|
||||
payload,
|
||||
forceRebuild,
|
||||
workspaceId,
|
||||
});
|
||||
} catch (error) {
|
||||
@@ -123,14 +132,14 @@ export class LogicFunctionResolver {
|
||||
}
|
||||
}
|
||||
|
||||
@Query(() => graphqlTypeJson, { nullable: true })
|
||||
@Query(() => String, { nullable: true })
|
||||
@UseGuards(SettingsPermissionGuard(PermissionFlagType.WORKFLOWS))
|
||||
async getLogicFunctionSourceCode(
|
||||
@Args('input') { id }: LogicFunctionIdInput,
|
||||
@AuthWorkspace() { id: workspaceId }: WorkspaceEntity,
|
||||
) {
|
||||
try {
|
||||
return await this.logicFunctionService.getSourceCode({
|
||||
return await this.logicFunctionFromSourceService.getSourceCode({
|
||||
id,
|
||||
workspaceId,
|
||||
});
|
||||
@@ -141,14 +150,14 @@ export class LogicFunctionResolver {
|
||||
|
||||
@Mutation(() => Boolean)
|
||||
@UseGuards(SettingsPermissionGuard(PermissionFlagType.WORKFLOWS))
|
||||
async updateLogicFunctionSource(
|
||||
@Args('input') { id, code }: UpdateLogicFunctionSourceInput,
|
||||
async updateOneLogicFunction(
|
||||
@Args('input') { id, update }: UpdateLogicFunctionFromSourceInput,
|
||||
@AuthWorkspace() { id: workspaceId }: WorkspaceEntity,
|
||||
): Promise<boolean> {
|
||||
try {
|
||||
await this.logicFunctionService.updateLogicFunctionSource({
|
||||
await this.logicFunctionFromSourceService.updateOne({
|
||||
id,
|
||||
code,
|
||||
update,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
|
||||
+134
-112
@@ -1,93 +1,37 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { Sources } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { join } from 'path';
|
||||
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { ApplicationLayerService } from 'src/engine/core-modules/application-layer/application-layer.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { LogicFunctionExecutorService } from 'src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.service';
|
||||
import { LogicFunctionResourceService } from 'src/engine/core-modules/logic-function/logic-function-resource/logic-function-resource.service';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { CreateDefaultLogicFunctionInput } from 'src/engine/metadata-modules/logic-function/dtos/create-default-logic-function.input';
|
||||
import { LogicFunctionExecutionResultDTO } from 'src/engine/metadata-modules/logic-function/dtos/logic-function-execution-result.dto';
|
||||
import { LogicFunctionDTO } from 'src/engine/metadata-modules/logic-function/dtos/logic-function.dto';
|
||||
import { LogicFunctionMetadataService } from 'src/engine/metadata-modules/logic-function/services/logic-function-metadata.service';
|
||||
import { FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type';
|
||||
import { findFlatLogicFunctionOrThrow } from 'src/engine/metadata-modules/logic-function/utils/find-flat-logic-function-or-throw.util';
|
||||
import { fromFlatLogicFunctionToLogicFunctionDto } from 'src/engine/metadata-modules/logic-function/utils/from-flat-logic-function-to-logic-function-dto.util';
|
||||
import { CreateLogicFunctionFromSourceInput } from 'src/engine/metadata-modules/logic-function/dtos/create-logic-function-from-source.input';
|
||||
import { SEED_LOGIC_FUNCTION_INPUT_SCHEMA } from 'src/engine/core-modules/logic-function/logic-function-resource/constants/seed-logic-function-input-schema';
|
||||
import { UpdateLogicFunctionFromSourceInput } from 'src/engine/metadata-modules/logic-function/dtos/update-logic-function-from-source.input';
|
||||
import { getLogicFunctionSubfolderForFromSource } from 'src/engine/metadata-modules/logic-function/utils/get-logic-function-subfolder-for-from-source';
|
||||
import {
|
||||
DEFAULT_BUILT_HANDLER_PATH,
|
||||
DEFAULT_SOURCE_HANDLER_PATH,
|
||||
} from 'src/engine/metadata-modules/logic-function/constants/handler.contant';
|
||||
|
||||
@Injectable()
|
||||
export class LogicFunctionService {
|
||||
export class LogicFunctionFromSourceService {
|
||||
constructor(
|
||||
private readonly logicFunctionExecutorService: LogicFunctionExecutorService,
|
||||
private readonly logicFunctionMetadataService: LogicFunctionMetadataService,
|
||||
private readonly logicFunctionResourceService: LogicFunctionResourceService,
|
||||
private readonly applicationService: ApplicationService,
|
||||
private readonly applicationLayerService: ApplicationLayerService,
|
||||
private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService,
|
||||
) {}
|
||||
|
||||
async findOne({
|
||||
id,
|
||||
workspaceId,
|
||||
}: {
|
||||
id: string;
|
||||
workspaceId: string;
|
||||
}): Promise<LogicFunctionDTO> {
|
||||
const { flatLogicFunctionMaps } =
|
||||
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatLogicFunctionMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
const flatLogicFunction = findFlatLogicFunctionOrThrow({
|
||||
id,
|
||||
flatLogicFunctionMaps,
|
||||
});
|
||||
|
||||
return fromFlatLogicFunctionToLogicFunctionDto({ flatLogicFunction });
|
||||
}
|
||||
|
||||
async findMany({
|
||||
workspaceId,
|
||||
}: {
|
||||
workspaceId: string;
|
||||
}): Promise<LogicFunctionDTO[]> {
|
||||
const { flatLogicFunctionMaps } =
|
||||
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatLogicFunctionMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
return Object.values(flatLogicFunctionMaps.byUniversalIdentifier)
|
||||
.filter(
|
||||
(flatLogicFunction): flatLogicFunction is FlatLogicFunction =>
|
||||
isDefined(flatLogicFunction) &&
|
||||
!isDefined(flatLogicFunction.deletedAt),
|
||||
)
|
||||
.map((flatLogicFunction) =>
|
||||
fromFlatLogicFunctionToLogicFunctionDto({ flatLogicFunction }),
|
||||
);
|
||||
}
|
||||
|
||||
async getAvailablePackages({
|
||||
id,
|
||||
workspaceId,
|
||||
}: {
|
||||
id: string;
|
||||
workspaceId: string;
|
||||
}) {
|
||||
return this.applicationLayerService.getAvailablePackages({
|
||||
logicFunctionId: id,
|
||||
workspaceId,
|
||||
});
|
||||
}
|
||||
|
||||
async deleteOne({
|
||||
id,
|
||||
workspaceId,
|
||||
@@ -104,11 +48,27 @@ export class LogicFunctionService {
|
||||
return fromFlatLogicFunctionToLogicFunctionDto({ flatLogicFunction });
|
||||
}
|
||||
|
||||
async createDefault({
|
||||
private getHandlerPaths(logicFunctionId: string) {
|
||||
const logicFunctionSubfolder =
|
||||
getLogicFunctionSubfolderForFromSource(logicFunctionId);
|
||||
|
||||
return {
|
||||
sourceHandlerPath: join(
|
||||
logicFunctionSubfolder,
|
||||
DEFAULT_SOURCE_HANDLER_PATH,
|
||||
),
|
||||
builtHandlerPath: join(
|
||||
logicFunctionSubfolder,
|
||||
DEFAULT_BUILT_HANDLER_PATH,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
async createOne({
|
||||
input,
|
||||
workspaceId,
|
||||
}: {
|
||||
input: CreateDefaultLogicFunctionInput;
|
||||
input: CreateLogicFunctionFromSourceInput;
|
||||
workspaceId: string;
|
||||
}): Promise<LogicFunctionDTO> {
|
||||
const { workspaceCustomFlatApplication } =
|
||||
@@ -118,9 +78,40 @@ export class LogicFunctionService {
|
||||
|
||||
const logicFunctionId = input.id ?? v4();
|
||||
|
||||
const { sourceHandlerPath, builtHandlerPath, handlerName, checksum } =
|
||||
const { sourceHandlerPath, builtHandlerPath } =
|
||||
this.getHandlerPaths(logicFunctionId);
|
||||
|
||||
if (input.source) {
|
||||
await this.logicFunctionResourceService.uploadSourceFile({
|
||||
sourceHandlerPath,
|
||||
sourceHandlerCode: input.source.sourceHandlerCode,
|
||||
applicationUniversalIdentifier:
|
||||
workspaceCustomFlatApplication.universalIdentifier,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
const flatLogicFunction =
|
||||
await this.logicFunctionMetadataService.createOne({
|
||||
input: {
|
||||
...input,
|
||||
handlerName: input.source.handlerName,
|
||||
toolInputSchema: input.source.toolInputSchema,
|
||||
sourceHandlerPath,
|
||||
builtHandlerPath,
|
||||
id: logicFunctionId,
|
||||
isBuildUpToDate: false,
|
||||
},
|
||||
workspaceId,
|
||||
ownerFlatApplication: workspaceCustomFlatApplication,
|
||||
});
|
||||
|
||||
return fromFlatLogicFunctionToLogicFunctionDto({ flatLogicFunction });
|
||||
}
|
||||
|
||||
const { handlerName, checksum } =
|
||||
await this.logicFunctionResourceService.seedSourceFiles({
|
||||
sourceSubfolder: logicFunctionId,
|
||||
sourceHandlerPath,
|
||||
builtHandlerPath,
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier:
|
||||
workspaceCustomFlatApplication.universalIdentifier,
|
||||
@@ -135,6 +126,8 @@ export class LogicFunctionService {
|
||||
builtHandlerPath,
|
||||
handlerName,
|
||||
checksum,
|
||||
toolInputSchema: SEED_LOGIC_FUNCTION_INPUT_SCHEMA,
|
||||
isBuildUpToDate: true,
|
||||
},
|
||||
workspaceId,
|
||||
ownerFlatApplication: workspaceCustomFlatApplication,
|
||||
@@ -144,35 +137,84 @@ export class LogicFunctionService {
|
||||
return fromFlatLogicFunctionToLogicFunctionDto({ flatLogicFunction });
|
||||
}
|
||||
|
||||
// TODO: remove forceRebuild parameter and add a column called shouldRebuild or isBuiltUpToDate
|
||||
async updateOne({
|
||||
id,
|
||||
update,
|
||||
workspaceId,
|
||||
}: {
|
||||
id: string;
|
||||
update: UpdateLogicFunctionFromSourceInput['update'];
|
||||
workspaceId: string;
|
||||
}): Promise<void> {
|
||||
const { applicationUniversalIdentifier, flatLogicFunction } =
|
||||
await this.getLogicFunctionContext({ id, workspaceId });
|
||||
|
||||
let formattedUpdate: UpdateLogicFunctionFromSourceInput['update'] = {
|
||||
...update,
|
||||
};
|
||||
|
||||
if (update.sourceHandlerCode) {
|
||||
await this.logicFunctionResourceService.uploadSourceFile({
|
||||
sourceHandlerPath: flatLogicFunction.sourceHandlerPath,
|
||||
sourceHandlerCode: update.sourceHandlerCode,
|
||||
applicationUniversalIdentifier,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
formattedUpdate = {
|
||||
...formattedUpdate,
|
||||
isBuildUpToDate: false,
|
||||
};
|
||||
}
|
||||
|
||||
await this.logicFunctionMetadataService.updateOne({
|
||||
id,
|
||||
update: formattedUpdate,
|
||||
workspaceId,
|
||||
});
|
||||
}
|
||||
|
||||
async buildOneFromSource({
|
||||
id,
|
||||
workspaceId,
|
||||
}: {
|
||||
id: string;
|
||||
workspaceId: string;
|
||||
}): Promise<void> {
|
||||
const { flatLogicFunction, applicationUniversalIdentifier } =
|
||||
await this.getLogicFunctionContext({ id, workspaceId });
|
||||
|
||||
const { checksum } =
|
||||
await this.logicFunctionResourceService.buildFromSourceFile({
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
sourceHandlerPath: flatLogicFunction.sourceHandlerPath,
|
||||
builtHandlerPath: flatLogicFunction.builtHandlerPath,
|
||||
});
|
||||
|
||||
await this.logicFunctionMetadataService.updateOne({
|
||||
id,
|
||||
update: { checksum, isBuildUpToDate: true },
|
||||
workspaceId,
|
||||
});
|
||||
}
|
||||
|
||||
async executeOne({
|
||||
id,
|
||||
payload,
|
||||
forceRebuild,
|
||||
workspaceId,
|
||||
}: {
|
||||
id: string;
|
||||
payload: object;
|
||||
forceRebuild?: boolean;
|
||||
workspaceId: string;
|
||||
}): Promise<LogicFunctionExecutionResultDTO> {
|
||||
if (forceRebuild) {
|
||||
const { flatLogicFunction, applicationUniversalIdentifier } =
|
||||
await this.getLogicFunctionContext({ id, workspaceId });
|
||||
const { flatLogicFunction } = await this.getLogicFunctionContext({
|
||||
id,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
const { checksum } =
|
||||
await this.logicFunctionResourceService.buildFromSource({
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
sourceHandlerPath: flatLogicFunction.sourceHandlerPath,
|
||||
builtHandlerPath: flatLogicFunction.builtHandlerPath,
|
||||
});
|
||||
|
||||
await this.logicFunctionMetadataService.updateChecksum({
|
||||
id,
|
||||
checksum,
|
||||
workspaceId,
|
||||
});
|
||||
if (!flatLogicFunction.isBuildUpToDate) {
|
||||
await this.buildOneFromSource({ workspaceId, id });
|
||||
}
|
||||
|
||||
const result = await this.logicFunctionExecutorService.execute({
|
||||
@@ -204,37 +246,17 @@ export class LogicFunctionService {
|
||||
}: {
|
||||
id: string;
|
||||
workspaceId: string;
|
||||
}): Promise<Sources | null> {
|
||||
}): Promise<string | null> {
|
||||
const { flatLogicFunction, applicationUniversalIdentifier } =
|
||||
await this.getLogicFunctionContext({ id, workspaceId });
|
||||
|
||||
return this.logicFunctionResourceService.getSourceCode({
|
||||
return this.logicFunctionResourceService.getSourceFile({
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
sourceHandlerPath: flatLogicFunction.sourceHandlerPath,
|
||||
});
|
||||
}
|
||||
|
||||
async updateLogicFunctionSource({
|
||||
id,
|
||||
code,
|
||||
workspaceId,
|
||||
}: {
|
||||
id: string;
|
||||
code: Sources;
|
||||
workspaceId: string;
|
||||
}): Promise<void> {
|
||||
const { flatLogicFunction, applicationUniversalIdentifier } =
|
||||
await this.getLogicFunctionContext({ id, workspaceId });
|
||||
|
||||
await this.logicFunctionResourceService.updateSourceFiles({
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
sourceHandlerPath: flatLogicFunction.sourceHandlerPath,
|
||||
code,
|
||||
});
|
||||
}
|
||||
|
||||
private async getLogicFunctionContext({
|
||||
id,
|
||||
workspaceId,
|
||||
+90
-63
@@ -7,18 +7,20 @@ import { type FlatApplication } from 'src/engine/core-modules/application/types/
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
import type { CreateLogicFunctionInput } from 'src/engine/metadata-modules/logic-function/dtos/create-logic-function.input';
|
||||
import type { UpdateLogicFunctionSourceInput } from 'src/engine/metadata-modules/logic-function/dtos/update-logic-function.input';
|
||||
import {
|
||||
LogicFunctionException,
|
||||
LogicFunctionExceptionCode,
|
||||
} from 'src/engine/metadata-modules/logic-function/logic-function.exception';
|
||||
import { FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type';
|
||||
import { findFlatLogicFunctionOrThrow } from 'src/engine/metadata-modules/logic-function/utils/find-flat-logic-function-or-throw.util';
|
||||
import { fromCreateLogicFunctionInputToFlatLogicFunction } from 'src/engine/metadata-modules/logic-function/utils/from-create-logic-function-input-to-flat-logic-function.util';
|
||||
import { fromCreateLogicFunctionInputToFlatLogicFunction } from 'src/engine/metadata-modules/logic-function/utils/from-create-logic-function-from-source-input-to-flat-logic-function.util';
|
||||
import { fromUpdateLogicFunctionInputToFlatLogicFunctionToUpdateOrThrow } from 'src/engine/metadata-modules/logic-function/utils/from-update-logic-function-input-to-flat-logic-function-to-update-or-throw.util';
|
||||
import { WorkspaceMigrationBuilderException } from 'src/engine/workspace-manager/workspace-migration/exceptions/workspace-migration-builder-exception';
|
||||
import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service';
|
||||
import { LogicFunctionDTO } from 'src/engine/metadata-modules/logic-function/dtos/logic-function.dto';
|
||||
import { fromFlatLogicFunctionToLogicFunctionDto } from 'src/engine/metadata-modules/logic-function/utils/from-flat-logic-function-to-logic-function-dto.util';
|
||||
import { CreateLogicFunction } from 'src/engine/metadata-modules/logic-function/dtos/create-logic-function.input';
|
||||
import { UpdateLogicFunctionFromSourceInput } from 'src/engine/metadata-modules/logic-function/dtos/update-logic-function-from-source.input';
|
||||
|
||||
@Injectable()
|
||||
export class LogicFunctionMetadataService {
|
||||
@@ -28,12 +30,59 @@ export class LogicFunctionMetadataService {
|
||||
private readonly applicationService: ApplicationService,
|
||||
) {}
|
||||
|
||||
async findOne({
|
||||
id,
|
||||
workspaceId,
|
||||
}: {
|
||||
id: string;
|
||||
workspaceId: string;
|
||||
}): Promise<LogicFunctionDTO> {
|
||||
const { flatLogicFunctionMaps } =
|
||||
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatLogicFunctionMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
const flatLogicFunction = findFlatLogicFunctionOrThrow({
|
||||
id,
|
||||
flatLogicFunctionMaps,
|
||||
});
|
||||
|
||||
return fromFlatLogicFunctionToLogicFunctionDto({ flatLogicFunction });
|
||||
}
|
||||
|
||||
async findMany({
|
||||
workspaceId,
|
||||
}: {
|
||||
workspaceId: string;
|
||||
}): Promise<LogicFunctionDTO[]> {
|
||||
const { flatLogicFunctionMaps } =
|
||||
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatLogicFunctionMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
return Object.values(flatLogicFunctionMaps.byUniversalIdentifier)
|
||||
.filter(
|
||||
(flatLogicFunction): flatLogicFunction is FlatLogicFunction =>
|
||||
isDefined(flatLogicFunction) &&
|
||||
!isDefined(flatLogicFunction.deletedAt),
|
||||
)
|
||||
.map((flatLogicFunction) =>
|
||||
fromFlatLogicFunctionToLogicFunctionDto({ flatLogicFunction }),
|
||||
);
|
||||
}
|
||||
|
||||
async createOne({
|
||||
input,
|
||||
workspaceId,
|
||||
ownerFlatApplication,
|
||||
}: {
|
||||
input: Omit<CreateLogicFunctionInput, 'applicationId'>;
|
||||
input: CreateLogicFunction;
|
||||
ownerFlatApplication: FlatApplication;
|
||||
workspaceId: string;
|
||||
}) {
|
||||
@@ -86,7 +135,7 @@ export class LogicFunctionMetadataService {
|
||||
ownerFlatApplication,
|
||||
}: {
|
||||
id: string;
|
||||
update: UpdateLogicFunctionSourceInput['update'];
|
||||
update: Omit<UpdateLogicFunctionFromSourceInput['update'], 'source'>;
|
||||
workspaceId: string;
|
||||
ownerFlatApplication?: FlatApplication;
|
||||
}) {
|
||||
@@ -142,64 +191,6 @@ export class LogicFunctionMetadataService {
|
||||
);
|
||||
}
|
||||
|
||||
async updateChecksum({
|
||||
id,
|
||||
checksum,
|
||||
workspaceId,
|
||||
}: {
|
||||
id: string;
|
||||
checksum: string;
|
||||
workspaceId: string;
|
||||
}) {
|
||||
const resolvedOwnerFlatApplication = (
|
||||
await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow(
|
||||
{ workspaceId },
|
||||
)
|
||||
).workspaceCustomFlatApplication;
|
||||
|
||||
const { flatLogicFunctionMaps } =
|
||||
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatLogicFunctionMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
const flatLogicFunction = findFlatLogicFunctionOrThrow({
|
||||
id,
|
||||
flatLogicFunctionMaps,
|
||||
});
|
||||
|
||||
const optimisticallyUpdatedFlatLogicFunction = {
|
||||
...flatLogicFunction,
|
||||
checksum,
|
||||
};
|
||||
|
||||
const validateAndBuildResult =
|
||||
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
|
||||
{
|
||||
allFlatEntityOperationByMetadataName: {
|
||||
logicFunction: {
|
||||
flatEntityToCreate: [],
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [optimisticallyUpdatedFlatLogicFunction],
|
||||
},
|
||||
},
|
||||
workspaceId,
|
||||
isSystemBuild: false,
|
||||
applicationUniversalIdentifier:
|
||||
resolvedOwnerFlatApplication.universalIdentifier,
|
||||
},
|
||||
);
|
||||
|
||||
if (isDefined(validateAndBuildResult)) {
|
||||
throw new WorkspaceMigrationBuilderException(
|
||||
validateAndBuildResult,
|
||||
'Multiple validation errors occurred while updating logic function checksum',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private async getFlatLogicFunctionAfterUpdate(
|
||||
id: string,
|
||||
workspaceId: string,
|
||||
@@ -285,4 +276,40 @@ export class LogicFunctionMetadataService {
|
||||
|
||||
return existingFlatLogicFunction;
|
||||
}
|
||||
|
||||
async getAvailablePackages({
|
||||
logicFunctionId,
|
||||
workspaceId,
|
||||
}: {
|
||||
logicFunctionId: string;
|
||||
workspaceId: string;
|
||||
}) {
|
||||
const { flatLogicFunctionMaps, flatApplicationMaps } =
|
||||
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatLogicFunctionMaps', 'flatApplicationMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
const logicFunctionUniversalIdentifier =
|
||||
flatLogicFunctionMaps.universalIdentifierById[logicFunctionId];
|
||||
|
||||
if (!logicFunctionUniversalIdentifier) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const logicFunction =
|
||||
flatLogicFunctionMaps.byUniversalIdentifier[
|
||||
logicFunctionUniversalIdentifier
|
||||
];
|
||||
|
||||
if (!logicFunction) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const application = flatApplicationMaps.byId[logicFunction.applicationId];
|
||||
|
||||
return application?.availablePackages ?? {};
|
||||
}
|
||||
}
|
||||
|
||||
+1
-5
@@ -1,8 +1,4 @@
|
||||
import { type Sources } from 'twenty-shared/types';
|
||||
|
||||
import { type FlatEntityFrom } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-from.type';
|
||||
import { type LogicFunctionEntity } from 'src/engine/metadata-modules/logic-function/logic-function.entity';
|
||||
|
||||
export type FlatLogicFunction = FlatEntityFrom<LogicFunctionEntity> & {
|
||||
code?: Sources;
|
||||
};
|
||||
export type FlatLogicFunction = FlatEntityFrom<LogicFunctionEntity>;
|
||||
|
||||
+8
-16
@@ -1,15 +1,12 @@
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { type CreateLogicFunctionInput } from 'src/engine/metadata-modules/logic-function/dtos/create-logic-function.input';
|
||||
import {
|
||||
DEFAULT_HANDLER_NAME,
|
||||
LogicFunctionRuntime,
|
||||
} from 'src/engine/metadata-modules/logic-function/logic-function.entity';
|
||||
import { LogicFunctionRuntime } from 'src/engine/metadata-modules/logic-function/logic-function.entity';
|
||||
import { type FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type';
|
||||
import { type CreateLogicFunction } from 'src/engine/metadata-modules/logic-function/dtos/create-logic-function.input';
|
||||
|
||||
export type FromCreateLogicFunctionInputToFlatLogicFunctionArgs = {
|
||||
createLogicFunctionInput: Omit<CreateLogicFunctionInput, 'applicationId'>;
|
||||
createLogicFunctionInput: CreateLogicFunction;
|
||||
workspaceId: string;
|
||||
ownerFlatApplication: FlatApplication;
|
||||
};
|
||||
@@ -22,14 +19,9 @@ export const fromCreateLogicFunctionInputToFlatLogicFunction = ({
|
||||
const id = rawCreateLogicFunctionInput.id ?? v4();
|
||||
const currentDate = new Date();
|
||||
|
||||
const sourceHandlerPath = rawCreateLogicFunctionInput.sourceHandlerPath;
|
||||
const builtHandlerPath = rawCreateLogicFunctionInput.builtHandlerPath;
|
||||
|
||||
const universalIdentifier =
|
||||
rawCreateLogicFunctionInput.universalIdentifier ?? v4();
|
||||
|
||||
const checksum = rawCreateLogicFunctionInput.checksum;
|
||||
|
||||
return {
|
||||
id,
|
||||
cronTriggerSettings:
|
||||
@@ -40,10 +32,9 @@ export const fromCreateLogicFunctionInputToFlatLogicFunction = ({
|
||||
rawCreateLogicFunctionInput.httpRouteTriggerSettings ?? null,
|
||||
name: rawCreateLogicFunctionInput.name,
|
||||
description: rawCreateLogicFunctionInput.description ?? null,
|
||||
sourceHandlerPath,
|
||||
handlerName:
|
||||
rawCreateLogicFunctionInput.handlerName ?? DEFAULT_HANDLER_NAME,
|
||||
builtHandlerPath,
|
||||
sourceHandlerPath: rawCreateLogicFunctionInput.sourceHandlerPath,
|
||||
handlerName: rawCreateLogicFunctionInput.handlerName,
|
||||
builtHandlerPath: rawCreateLogicFunctionInput.builtHandlerPath,
|
||||
universalIdentifier,
|
||||
createdAt: currentDate.toISOString(),
|
||||
updatedAt: currentDate.toISOString(),
|
||||
@@ -52,9 +43,10 @@ export const fromCreateLogicFunctionInputToFlatLogicFunction = ({
|
||||
runtime: LogicFunctionRuntime.NODE22,
|
||||
timeoutSeconds: rawCreateLogicFunctionInput.timeoutSeconds ?? 300,
|
||||
workspaceId,
|
||||
checksum,
|
||||
checksum: rawCreateLogicFunctionInput.checksum ?? null,
|
||||
toolInputSchema: rawCreateLogicFunctionInput.toolInputSchema ?? null,
|
||||
isTool: rawCreateLogicFunctionInput?.isTool ?? false,
|
||||
isBuildUpToDate: rawCreateLogicFunctionInput.isBuildUpToDate,
|
||||
applicationUniversalIdentifier: ownerFlatApplication.universalIdentifier,
|
||||
};
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user