Use optimistic rendering when executing a workflow with manual trigger (#12695)
This PR adds optimistic rendering at two places: - In the `runWorkflowVersion`, to create a workflow run entry as fast as possible in the cache and render it immediately in the side panel. - In the `ListenUpdatesEffect`, to be sure the cache is properly set; we also need to set the record in the record store that's used in the fields card. ## Before https://github.com/user-attachments/assets/8b360ea9-c292-4e05-82a0-d2f12176bb6f ## After https://github.com/user-attachments/assets/2d11023c-2ceb-4fa3-a951-187b9a0b5743 ### With a slowed-down network https://github.com/user-attachments/assets/7d2a592a-1ea7-455b-856f-bf3d9d905061 ## Follow up I will create next a PR to ensure the viewport is always set when we know the dimensions of the nodes.
This commit is contained in:
committed by
GitHub
parent
a6b8830b91
commit
dae282ca0f
@ -1786,6 +1786,8 @@ export type Role = {
|
|||||||
export type RunWorkflowVersionInput = {
|
export type RunWorkflowVersionInput = {
|
||||||
/** Execution result in JSON format */
|
/** Execution result in JSON format */
|
||||||
payload?: InputMaybe<Scalars['JSON']>;
|
payload?: InputMaybe<Scalars['JSON']>;
|
||||||
|
/** Workflow run ID */
|
||||||
|
workflowRunId?: InputMaybe<Scalars['String']>;
|
||||||
/** Workflow version ID */
|
/** Workflow version ID */
|
||||||
workflowVersionId: Scalars['String'];
|
workflowVersionId: Scalars['String'];
|
||||||
};
|
};
|
||||||
|
|||||||
@ -64,6 +64,7 @@ export const useRunWorkflowRecordActions = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
await runWorkflowVersion({
|
await runWorkflowVersion({
|
||||||
|
workflowId: activeWorkflowVersion.workflowId,
|
||||||
workflowVersionId: activeWorkflowVersion.id,
|
workflowVersionId: activeWorkflowVersion.id,
|
||||||
payload: selectedRecord,
|
payload: selectedRecord,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -16,6 +16,7 @@ export const TestWorkflowSingleRecordAction = () => {
|
|||||||
|
|
||||||
runWorkflowVersion({
|
runWorkflowVersion({
|
||||||
workflowVersionId: workflowWithCurrentVersion.currentVersion.id,
|
workflowVersionId: workflowWithCurrentVersion.currentVersion.id,
|
||||||
|
workflowId: workflowWithCurrentVersion.id,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -52,6 +52,7 @@ export const useRunWorkflowRecordAgnosticActions = () => {
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
runWorkflowVersion({
|
runWorkflowVersion({
|
||||||
workflowVersionId: activeWorkflowVersion.id,
|
workflowVersionId: activeWorkflowVersion.id,
|
||||||
|
workflowId: activeWorkflowVersion.workflowId,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
closeSidePanelOnCommandMenuListActionExecution={false}
|
closeSidePanelOnCommandMenuListActionExecution={false}
|
||||||
|
|||||||
@ -0,0 +1,45 @@
|
|||||||
|
import { useApolloClient } from '@apollo/client';
|
||||||
|
|
||||||
|
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||||
|
import { useFindOneRecordQuery } from '@/object-record/hooks/useFindOneRecordQuery';
|
||||||
|
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||||
|
|
||||||
|
export const useUpsertFindOneRecordQueryInCache = ({
|
||||||
|
objectMetadataItem,
|
||||||
|
recordGqlFields,
|
||||||
|
withSoftDeleted = false,
|
||||||
|
}: {
|
||||||
|
objectMetadataItem: ObjectMetadataItem;
|
||||||
|
recordGqlFields: Record<string, any>;
|
||||||
|
withSoftDeleted?: boolean;
|
||||||
|
}) => {
|
||||||
|
const apolloClient = useApolloClient();
|
||||||
|
|
||||||
|
const { findOneRecordQuery } = useFindOneRecordQuery({
|
||||||
|
objectNameSingular: objectMetadataItem.nameSingular,
|
||||||
|
recordGqlFields,
|
||||||
|
withSoftDeleted,
|
||||||
|
});
|
||||||
|
|
||||||
|
const upsertFindOneRecordQueryInCache = <
|
||||||
|
T extends ObjectRecord = ObjectRecord,
|
||||||
|
>({
|
||||||
|
objectRecordId,
|
||||||
|
objectRecordToOverwrite,
|
||||||
|
}: {
|
||||||
|
objectRecordId: string;
|
||||||
|
objectRecordToOverwrite: T;
|
||||||
|
}) => {
|
||||||
|
apolloClient.writeQuery({
|
||||||
|
query: findOneRecordQuery,
|
||||||
|
variables: { objectRecordId },
|
||||||
|
data: {
|
||||||
|
[objectMetadataItem.nameSingular]: objectRecordToOverwrite,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
upsertFindOneRecordQueryInCache,
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -1,6 +1,18 @@
|
|||||||
|
import { triggerUpdateRecordOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerUpdateRecordOptimisticEffect';
|
||||||
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
|
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||||
|
import { useGetRecordFromCache } from '@/object-record/cache/hooks/useGetRecordFromCache';
|
||||||
|
import { getObjectTypename } from '@/object-record/cache/utils/getObjectTypename';
|
||||||
|
import { getRecordNodeFromRecord } from '@/object-record/cache/utils/getRecordNodeFromRecord';
|
||||||
|
import { updateRecordFromCache } from '@/object-record/cache/utils/updateRecordFromCache';
|
||||||
|
import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields';
|
||||||
|
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
|
||||||
|
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||||
|
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||||
import { useOnDbEvent } from '@/subscription/hooks/useOnDbEvent';
|
import { useOnDbEvent } from '@/subscription/hooks/useOnDbEvent';
|
||||||
import { useApolloClient } from '@apollo/client';
|
import { useApolloClient } from '@apollo/client';
|
||||||
import { capitalize, isDefined } from 'twenty-shared/utils';
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { DatabaseEventAction } from '~/generated/graphql';
|
import { DatabaseEventAction } from '~/generated/graphql';
|
||||||
|
|
||||||
type ListenRecordUpdatesEffectProps = {
|
type ListenRecordUpdatesEffectProps = {
|
||||||
@ -16,28 +28,70 @@ export const ListenRecordUpdatesEffect = ({
|
|||||||
}: ListenRecordUpdatesEffectProps) => {
|
}: ListenRecordUpdatesEffectProps) => {
|
||||||
const apolloClient = useApolloClient();
|
const apolloClient = useApolloClient();
|
||||||
|
|
||||||
|
const { objectMetadataItem } = useObjectMetadataItem({
|
||||||
|
objectNameSingular,
|
||||||
|
});
|
||||||
|
const getRecordFromCache = useGetRecordFromCache({
|
||||||
|
objectNameSingular,
|
||||||
|
});
|
||||||
|
const { objectMetadataItems } = useObjectMetadataItems();
|
||||||
|
const { objectPermissionsByObjectMetadataId } = useObjectPermissions();
|
||||||
|
|
||||||
|
const computedRecordGqlFields = generateDepthOneRecordGqlFields({
|
||||||
|
objectMetadataItem,
|
||||||
|
});
|
||||||
|
|
||||||
|
const setRecordInStore = useRecoilCallback(
|
||||||
|
({ set }) =>
|
||||||
|
(record: ObjectRecord) => {
|
||||||
|
set(recordStoreFamilyState(record.id), record);
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
useOnDbEvent({
|
useOnDbEvent({
|
||||||
input: { recordId, action: DatabaseEventAction.UPDATED },
|
input: { recordId, action: DatabaseEventAction.UPDATED },
|
||||||
onData: (data) => {
|
onData: (data) => {
|
||||||
const updatedRecord = data.onDbEvent.record;
|
const updatedRecord = data.onDbEvent.record;
|
||||||
|
|
||||||
const fieldsUpdater = listenedFields.reduce((acc, listenedField) => {
|
const cachedRecord = getRecordFromCache<ObjectRecord>(recordId);
|
||||||
if (!isDefined(updatedRecord[listenedField])) {
|
const cachedRecordNode = getRecordNodeFromRecord<ObjectRecord>({
|
||||||
return acc;
|
record: cachedRecord,
|
||||||
}
|
objectMetadataItem,
|
||||||
return {
|
objectMetadataItems,
|
||||||
...acc,
|
computeReferences: false,
|
||||||
[listenedField]: () => updatedRecord[listenedField],
|
|
||||||
};
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
apolloClient.cache.modify({
|
|
||||||
id: apolloClient.cache.identify({
|
|
||||||
__typename: capitalize(objectNameSingular),
|
|
||||||
id: recordId,
|
|
||||||
}),
|
|
||||||
fields: fieldsUpdater,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const shouldHandleOptimisticCache =
|
||||||
|
isDefined(cachedRecordNode) && isDefined(cachedRecord);
|
||||||
|
|
||||||
|
if (shouldHandleOptimisticCache) {
|
||||||
|
const computedOptimisticRecord: ObjectRecord = {
|
||||||
|
...cachedRecord,
|
||||||
|
...updatedRecord,
|
||||||
|
id: recordId,
|
||||||
|
__typename: getObjectTypename(objectMetadataItem.nameSingular),
|
||||||
|
};
|
||||||
|
|
||||||
|
updateRecordFromCache({
|
||||||
|
objectMetadataItems,
|
||||||
|
objectMetadataItem,
|
||||||
|
cache: apolloClient.cache,
|
||||||
|
record: computedOptimisticRecord,
|
||||||
|
recordGqlFields: computedRecordGqlFields,
|
||||||
|
objectPermissionsByObjectMetadataId,
|
||||||
|
});
|
||||||
|
|
||||||
|
triggerUpdateRecordOptimisticEffect({
|
||||||
|
cache: apolloClient.cache,
|
||||||
|
objectMetadataItem,
|
||||||
|
currentRecord: cachedRecordNode,
|
||||||
|
updatedRecord: updatedRecord,
|
||||||
|
objectMetadataItems,
|
||||||
|
});
|
||||||
|
|
||||||
|
setRecordInStore(computedOptimisticRecord);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
skip: listenedFields.length === 0,
|
skip: listenedFields.length === 0,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -49,9 +49,7 @@ export const useRunWorkflowRunOpeningInCommandMenuSideEffects = () => {
|
|||||||
if (
|
if (
|
||||||
!(isDefined(workflowRunRecord) && isDefined(workflowRunRecord.output))
|
!(isDefined(workflowRunRecord) && isDefined(workflowRunRecord.output))
|
||||||
) {
|
) {
|
||||||
throw new Error(
|
return;
|
||||||
`No workflow run record found for record ID ${recordId}`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const { stepToOpenByDefault } = generateWorkflowRunDiagram({
|
const { stepToOpenByDefault } = generateWorkflowRunDiagram({
|
||||||
|
|||||||
@ -1,9 +1,24 @@
|
|||||||
|
import { triggerCreateRecordsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerCreateRecordsOptimisticEffect';
|
||||||
|
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||||
import { useOpenRecordInCommandMenu } from '@/command-menu/hooks/useOpenRecordInCommandMenu';
|
import { useOpenRecordInCommandMenu } from '@/command-menu/hooks/useOpenRecordInCommandMenu';
|
||||||
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
|
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { useLazyFindOneRecord } from '@/object-record/hooks/useLazyFindOneRecord';
|
import { useCreateOneRecordInCache } from '@/object-record/cache/hooks/useCreateOneRecordInCache';
|
||||||
|
import { useUpsertFindOneRecordQueryInCache } from '@/object-record/cache/hooks/useUpsertFindOneRecordQueryInCache';
|
||||||
|
import { getObjectTypename } from '@/object-record/cache/utils/getObjectTypename';
|
||||||
|
import { getRecordNodeFromRecord } from '@/object-record/cache/utils/getRecordNodeFromRecord';
|
||||||
|
import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields';
|
||||||
|
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
|
||||||
|
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||||
|
import { computeOptimisticCreateRecordBaseRecordInput } from '@/object-record/utils/computeOptimisticCreateRecordBaseRecordInput';
|
||||||
|
import { computeOptimisticRecordFromInput } from '@/object-record/utils/computeOptimisticRecordFromInput';
|
||||||
import { RUN_WORKFLOW_VERSION } from '@/workflow/graphql/mutations/runWorkflowVersion';
|
import { RUN_WORKFLOW_VERSION } from '@/workflow/graphql/mutations/runWorkflowVersion';
|
||||||
import { WorkflowRun } from '@/workflow/types/Workflow';
|
import { WorkflowRun } from '@/workflow/types/Workflow';
|
||||||
import { useApolloClient, useMutation } from '@apollo/client';
|
import { useApolloClient, useMutation } from '@apollo/client';
|
||||||
|
import { useRecoilCallback, useRecoilValue } from 'recoil';
|
||||||
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
import { v4 } from 'uuid';
|
||||||
import {
|
import {
|
||||||
RunWorkflowVersionMutation,
|
RunWorkflowVersionMutation,
|
||||||
RunWorkflowVersionMutationVariables,
|
RunWorkflowVersionMutationVariables,
|
||||||
@ -11,6 +26,18 @@ import {
|
|||||||
|
|
||||||
export const useRunWorkflowVersion = () => {
|
export const useRunWorkflowVersion = () => {
|
||||||
const apolloClient = useApolloClient();
|
const apolloClient = useApolloClient();
|
||||||
|
|
||||||
|
const { objectMetadataItem } = useObjectMetadataItem({
|
||||||
|
objectNameSingular: CoreObjectNameSingular.WorkflowRun,
|
||||||
|
});
|
||||||
|
const { objectPermissionsByObjectMetadataId } = useObjectPermissions();
|
||||||
|
const createOneRecordInCache = useCreateOneRecordInCache<WorkflowRun>({
|
||||||
|
objectMetadataItem,
|
||||||
|
});
|
||||||
|
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
||||||
|
|
||||||
|
const { objectMetadataItems } = useObjectMetadataItems();
|
||||||
|
|
||||||
const [mutate] = useMutation<
|
const [mutate] = useMutation<
|
||||||
RunWorkflowVersionMutation,
|
RunWorkflowVersionMutation,
|
||||||
RunWorkflowVersionMutationVariables
|
RunWorkflowVersionMutationVariables
|
||||||
@ -18,34 +45,100 @@ export const useRunWorkflowVersion = () => {
|
|||||||
client: apolloClient,
|
client: apolloClient,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { findOneRecord: findOneWorkflowRun } =
|
const computedRecordGqlFields = generateDepthOneRecordGqlFields({
|
||||||
useLazyFindOneRecord<WorkflowRun>({
|
objectMetadataItem,
|
||||||
objectNameSingular: CoreObjectNameSingular.WorkflowRun,
|
});
|
||||||
|
|
||||||
|
const { upsertFindOneRecordQueryInCache } =
|
||||||
|
useUpsertFindOneRecordQueryInCache({
|
||||||
|
objectMetadataItem,
|
||||||
|
recordGqlFields: computedRecordGqlFields,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { openRecordInCommandMenu } = useOpenRecordInCommandMenu();
|
const { openRecordInCommandMenu } = useOpenRecordInCommandMenu();
|
||||||
|
|
||||||
|
const setRecordInStore = useRecoilCallback(
|
||||||
|
({ set }) =>
|
||||||
|
(workflowRun: WorkflowRun) => {
|
||||||
|
set(recordStoreFamilyState(workflowRun.id), workflowRun);
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
const runWorkflowVersion = async ({
|
const runWorkflowVersion = async ({
|
||||||
|
workflowId,
|
||||||
workflowVersionId,
|
workflowVersionId,
|
||||||
payload,
|
payload,
|
||||||
}: {
|
}: {
|
||||||
|
workflowId: string;
|
||||||
workflowVersionId: string;
|
workflowVersionId: string;
|
||||||
payload?: Record<string, any>;
|
payload?: Record<string, any>;
|
||||||
}) => {
|
}) => {
|
||||||
const { data } = await mutate({
|
const workflowRunId = v4();
|
||||||
variables: { input: { workflowVersionId, payload } },
|
|
||||||
|
const recordInput: Partial<WorkflowRun> = {
|
||||||
|
name: '#0',
|
||||||
|
status: 'NOT_STARTED',
|
||||||
|
output: null,
|
||||||
|
context: null,
|
||||||
|
workflowVersionId,
|
||||||
|
workflowId,
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const optimisticRecordInput = computeOptimisticRecordFromInput({
|
||||||
|
cache: apolloClient.cache,
|
||||||
|
currentWorkspaceMember: currentWorkspaceMember,
|
||||||
|
objectMetadataItem,
|
||||||
|
objectMetadataItems,
|
||||||
|
recordInput: {
|
||||||
|
...computeOptimisticCreateRecordBaseRecordInput(objectMetadataItem),
|
||||||
|
...recordInput,
|
||||||
|
id: workflowRunId,
|
||||||
|
},
|
||||||
|
objectPermissionsByObjectMetadataId,
|
||||||
});
|
});
|
||||||
|
|
||||||
const workflowRunId = data?.runWorkflowVersion?.workflowRunId;
|
const recordCreatedInCache = createOneRecordInCache({
|
||||||
|
...optimisticRecordInput,
|
||||||
|
id: workflowRunId,
|
||||||
|
__typename: getObjectTypename(objectMetadataItem.nameSingular),
|
||||||
|
});
|
||||||
|
|
||||||
await findOneWorkflowRun({
|
const recordNodeCreatedInCache = getRecordNodeFromRecord({
|
||||||
|
objectMetadataItem,
|
||||||
|
objectMetadataItems,
|
||||||
|
record: recordCreatedInCache,
|
||||||
|
computeReferences: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!isDefined(recordNodeCreatedInCache)) {
|
||||||
|
throw new Error('The record should have been created in cache');
|
||||||
|
}
|
||||||
|
|
||||||
|
upsertFindOneRecordQueryInCache({
|
||||||
|
objectRecordToOverwrite: recordCreatedInCache,
|
||||||
objectRecordId: workflowRunId,
|
objectRecordId: workflowRunId,
|
||||||
onCompleted: (workflowRun) => {
|
});
|
||||||
openRecordInCommandMenu({
|
|
||||||
objectNameSingular: CoreObjectNameSingular.WorkflowRun,
|
triggerCreateRecordsOptimisticEffect({
|
||||||
recordId: workflowRun.id,
|
cache: apolloClient.cache,
|
||||||
});
|
objectMetadataItem,
|
||||||
},
|
recordsToCreate: [recordNodeCreatedInCache],
|
||||||
|
objectMetadataItems,
|
||||||
|
shouldMatchRootQueryFilter: true,
|
||||||
|
objectPermissionsByObjectMetadataId,
|
||||||
|
});
|
||||||
|
|
||||||
|
setRecordInStore(recordCreatedInCache);
|
||||||
|
|
||||||
|
openRecordInCommandMenu({
|
||||||
|
objectNameSingular: CoreObjectNameSingular.WorkflowRun,
|
||||||
|
recordId: workflowRunId,
|
||||||
|
});
|
||||||
|
|
||||||
|
await mutate({
|
||||||
|
variables: { input: { workflowVersionId, workflowRunId, payload } },
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -10,6 +10,12 @@ export class RunWorkflowVersionInput {
|
|||||||
})
|
})
|
||||||
workflowVersionId: string;
|
workflowVersionId: string;
|
||||||
|
|
||||||
|
@Field(() => String, {
|
||||||
|
description: 'Workflow run ID',
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
workflowRunId?: string | null;
|
||||||
|
|
||||||
@Field(() => graphqlTypeJson, {
|
@Field(() => graphqlTypeJson, {
|
||||||
description: 'Execution result in JSON format',
|
description: 'Execution result in JSON format',
|
||||||
nullable: true,
|
nullable: true,
|
||||||
|
|||||||
@ -56,7 +56,8 @@ export class WorkflowTriggerResolver {
|
|||||||
async runWorkflowVersion(
|
async runWorkflowVersion(
|
||||||
@AuthUser() user: User,
|
@AuthUser() user: User,
|
||||||
@AuthWorkspace() workspace: Workspace,
|
@AuthWorkspace() workspace: Workspace,
|
||||||
@Args('input') { workflowVersionId, payload }: RunWorkflowVersionInput,
|
@Args('input')
|
||||||
|
{ workflowVersionId, workflowRunId, payload }: RunWorkflowVersionInput,
|
||||||
) {
|
) {
|
||||||
const workspaceMemberRepository =
|
const workspaceMemberRepository =
|
||||||
await this.twentyORMGlobalManager.getRepositoryForWorkspace<WorkspaceMemberWorkspaceEntity>(
|
await this.twentyORMGlobalManager.getRepositoryForWorkspace<WorkspaceMemberWorkspaceEntity>(
|
||||||
@ -72,6 +73,7 @@ export class WorkflowTriggerResolver {
|
|||||||
|
|
||||||
return await this.workflowTriggerWorkspaceService.runWorkflowVersion({
|
return await this.workflowTriggerWorkspaceService.runWorkflowVersion({
|
||||||
workflowVersionId,
|
workflowVersionId,
|
||||||
|
workflowRunId: workflowRunId ?? undefined,
|
||||||
payload: payload ?? {},
|
payload: payload ?? {},
|
||||||
createdBy: buildCreatedByFromFullNameMetadata({
|
createdBy: buildCreatedByFromFullNameMetadata({
|
||||||
fullNameMetadata: {
|
fullNameMetadata: {
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common';
|
|||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
|
|
||||||
import { Repository } from 'typeorm';
|
import { Repository } from 'typeorm';
|
||||||
|
import { v4 } from 'uuid';
|
||||||
|
|
||||||
import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action';
|
import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action';
|
||||||
import { objectRecordChangedValues } from 'src/engine/core-modules/event-emitter/utils/object-record-changed-values';
|
import { objectRecordChangedValues } from 'src/engine/core-modules/event-emitter/utils/object-record-changed-values';
|
||||||
@ -39,9 +40,11 @@ export class WorkflowRunWorkspaceService {
|
|||||||
async createWorkflowRun({
|
async createWorkflowRun({
|
||||||
workflowVersionId,
|
workflowVersionId,
|
||||||
createdBy,
|
createdBy,
|
||||||
|
workflowRunId,
|
||||||
}: {
|
}: {
|
||||||
workflowVersionId: string;
|
workflowVersionId: string;
|
||||||
createdBy: ActorMetadata;
|
createdBy: ActorMetadata;
|
||||||
|
workflowRunId?: string;
|
||||||
}) {
|
}) {
|
||||||
const workspaceId =
|
const workspaceId =
|
||||||
this.scopedWorkspaceContextFactory.create()?.workspaceId;
|
this.scopedWorkspaceContextFactory.create()?.workspaceId;
|
||||||
@ -54,7 +57,7 @@ export class WorkflowRunWorkspaceService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const workflowRunRepository =
|
const workflowRunRepository =
|
||||||
await this.twentyORMGlobalManager.getRepositoryForWorkspace(
|
await this.twentyORMGlobalManager.getRepositoryForWorkspace<WorkflowRunWorkspaceEntity>(
|
||||||
workspaceId,
|
workspaceId,
|
||||||
'workflowRun',
|
'workflowRun',
|
||||||
{ shouldBypassPermissionChecks: true },
|
{ shouldBypassPermissionChecks: true },
|
||||||
@ -101,16 +104,19 @@ export class WorkflowRunWorkspaceService {
|
|||||||
workspaceId,
|
workspaceId,
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
const workflowRun = workflowRunRepository.create({
|
||||||
await workflowRunRepository.save({
|
id: workflowRunId ?? v4(),
|
||||||
name: `#${workflowRunCount + 1} - ${workflow.name}`,
|
name: `#${workflowRunCount + 1} - ${workflow.name}`,
|
||||||
workflowVersionId,
|
workflowVersionId,
|
||||||
createdBy,
|
createdBy,
|
||||||
workflowId: workflow.id,
|
workflowId: workflow.id,
|
||||||
status: WorkflowRunStatus.NOT_STARTED,
|
status: WorkflowRunStatus.NOT_STARTED,
|
||||||
position,
|
position,
|
||||||
})
|
});
|
||||||
).id;
|
|
||||||
|
await workflowRunRepository.insert(workflowRun);
|
||||||
|
|
||||||
|
return workflowRun.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
async startWorkflowRun({
|
async startWorkflowRun({
|
||||||
|
|||||||
@ -26,11 +26,13 @@ export class WorkflowRunnerWorkspaceService {
|
|||||||
workflowVersionId,
|
workflowVersionId,
|
||||||
payload,
|
payload,
|
||||||
source,
|
source,
|
||||||
|
workflowRunId: initialWorkflowRunId,
|
||||||
}: {
|
}: {
|
||||||
workspaceId: string;
|
workspaceId: string;
|
||||||
workflowVersionId: string;
|
workflowVersionId: string;
|
||||||
payload: object;
|
payload: object;
|
||||||
source: ActorMetadata;
|
source: ActorMetadata;
|
||||||
|
workflowRunId?: string;
|
||||||
}) {
|
}) {
|
||||||
const canFeatureBeUsed =
|
const canFeatureBeUsed =
|
||||||
await this.billingUsageService.canFeatureBeUsed(workspaceId);
|
await this.billingUsageService.canFeatureBeUsed(workspaceId);
|
||||||
@ -43,6 +45,7 @@ export class WorkflowRunnerWorkspaceService {
|
|||||||
const workflowRunId =
|
const workflowRunId =
|
||||||
await this.workflowRunWorkspaceService.createWorkflowRun({
|
await this.workflowRunWorkspaceService.createWorkflowRun({
|
||||||
workflowVersionId,
|
workflowVersionId,
|
||||||
|
workflowRunId: initialWorkflowRunId,
|
||||||
createdBy: source,
|
createdBy: source,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -63,10 +63,12 @@ export class WorkflowTriggerWorkspaceService {
|
|||||||
workflowVersionId,
|
workflowVersionId,
|
||||||
payload,
|
payload,
|
||||||
createdBy,
|
createdBy,
|
||||||
|
workflowRunId,
|
||||||
}: {
|
}: {
|
||||||
workflowVersionId: string;
|
workflowVersionId: string;
|
||||||
payload: object;
|
payload: object;
|
||||||
createdBy: ActorMetadata;
|
createdBy: ActorMetadata;
|
||||||
|
workflowRunId?: string;
|
||||||
}) {
|
}) {
|
||||||
await this.workflowCommonWorkspaceService.getWorkflowVersionOrFail({
|
await this.workflowCommonWorkspaceService.getWorkflowVersionOrFail({
|
||||||
workflowVersionId,
|
workflowVersionId,
|
||||||
@ -75,6 +77,7 @@ export class WorkflowTriggerWorkspaceService {
|
|||||||
|
|
||||||
return this.workflowRunnerWorkspaceService.run({
|
return this.workflowRunnerWorkspaceService.run({
|
||||||
workspaceId: this.getWorkspaceId(),
|
workspaceId: this.getWorkspaceId(),
|
||||||
|
workflowRunId,
|
||||||
workflowVersionId,
|
workflowVersionId,
|
||||||
payload,
|
payload,
|
||||||
source: createdBy,
|
source: createdBy,
|
||||||
|
|||||||
Reference in New Issue
Block a user