Allow to stop running workflow (#15270)
https://github.com/user-attachments/assets/599154e4-8743-471b-b05a-721b635bcf4e On stoppage: - if no running steps, mark pending as failed and end the workflow - if running steps, set as stopping and exit. Going to the next step, as the workflow is not running anymore, it will naturally stop
This commit is contained in:
@@ -1825,7 +1825,7 @@ export type Mutation = {
|
||||
restorePageLayoutWidget: PageLayoutWidget;
|
||||
retryJobs: RetryJobsResponse;
|
||||
revokeApiKey?: Maybe<ApiKey>;
|
||||
runWorkflowVersion: WorkflowRun;
|
||||
runWorkflowVersion: RunWorkflowVersionOutput;
|
||||
saveImapSmtpCaldavAccount: ImapSmtpCaldavConnectionSuccess;
|
||||
sendInvitations: SendInvitationsOutput;
|
||||
setMeteredSubscriptionPrice: BillingUpdateOutput;
|
||||
@@ -1836,6 +1836,7 @@ export type Mutation = {
|
||||
skipBookOnboardingStep: OnboardingStepSuccess;
|
||||
skipSyncEmailOnboardingStep: OnboardingStepSuccess;
|
||||
startChannelSync: ChannelSyncSuccess;
|
||||
stopWorkflowRun: WorkflowRun;
|
||||
submitFormStep: Scalars['Boolean'];
|
||||
switchBillingPlan: BillingUpdateOutput;
|
||||
switchSubscriptionInterval: BillingUpdateOutput;
|
||||
@@ -2516,6 +2517,11 @@ export type MutationStartChannelSyncArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationStopWorkflowRunArgs = {
|
||||
workflowRunId: Scalars['UUID'];
|
||||
};
|
||||
|
||||
|
||||
export type MutationSubmitFormStepArgs = {
|
||||
input: SubmitFormStepInput;
|
||||
};
|
||||
@@ -3702,6 +3708,11 @@ export type RunWorkflowVersionInput = {
|
||||
workflowVersionId: Scalars['UUID'];
|
||||
};
|
||||
|
||||
export type RunWorkflowVersionOutput = {
|
||||
__typename?: 'RunWorkflowVersionOutput';
|
||||
workflowRunId: Scalars['UUID'];
|
||||
};
|
||||
|
||||
export type SsoConnection = {
|
||||
__typename?: 'SSOConnection';
|
||||
id: Scalars['UUID'];
|
||||
@@ -4585,9 +4596,21 @@ export enum WorkflowActionType {
|
||||
|
||||
export type WorkflowRun = {
|
||||
__typename?: 'WorkflowRun';
|
||||
workflowRunId: Scalars['UUID'];
|
||||
id: Scalars['UUID'];
|
||||
status: WorkflowRunStatusEnum;
|
||||
};
|
||||
|
||||
/** Status of the workflow run */
|
||||
export enum WorkflowRunStatusEnum {
|
||||
COMPLETED = 'COMPLETED',
|
||||
ENQUEUED = 'ENQUEUED',
|
||||
FAILED = 'FAILED',
|
||||
NOT_STARTED = 'NOT_STARTED',
|
||||
RUNNING = 'RUNNING',
|
||||
STOPPED = 'STOPPED',
|
||||
STOPPING = 'STOPPING'
|
||||
}
|
||||
|
||||
export type WorkflowStepPosition = {
|
||||
__typename?: 'WorkflowStepPosition';
|
||||
x: Scalars['Float'];
|
||||
@@ -6152,7 +6175,14 @@ export type RunWorkflowVersionMutationVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type RunWorkflowVersionMutation = { __typename?: 'Mutation', runWorkflowVersion: { __typename?: 'WorkflowRun', workflowRunId: string } };
|
||||
export type RunWorkflowVersionMutation = { __typename?: 'Mutation', runWorkflowVersion: { __typename?: 'RunWorkflowVersionOutput', workflowRunId: string } };
|
||||
|
||||
export type StopWorkflowRunMutationVariables = Exact<{
|
||||
workflowRunId: Scalars['UUID'];
|
||||
}>;
|
||||
|
||||
|
||||
export type StopWorkflowRunMutation = { __typename?: 'Mutation', stopWorkflowRun: { __typename: 'WorkflowRun', id: string, status: WorkflowRunStatusEnum } };
|
||||
|
||||
export type UpdateWorkflowRunStepMutationVariables = Exact<{
|
||||
input: UpdateWorkflowRunStepInput;
|
||||
@@ -13865,6 +13895,41 @@ export function useRunWorkflowVersionMutation(baseOptions?: Apollo.MutationHookO
|
||||
export type RunWorkflowVersionMutationHookResult = ReturnType<typeof useRunWorkflowVersionMutation>;
|
||||
export type RunWorkflowVersionMutationResult = Apollo.MutationResult<RunWorkflowVersionMutation>;
|
||||
export type RunWorkflowVersionMutationOptions = Apollo.BaseMutationOptions<RunWorkflowVersionMutation, RunWorkflowVersionMutationVariables>;
|
||||
export const StopWorkflowRunDocument = gql`
|
||||
mutation StopWorkflowRun($workflowRunId: UUID!) {
|
||||
stopWorkflowRun(workflowRunId: $workflowRunId) {
|
||||
id
|
||||
status
|
||||
__typename
|
||||
}
|
||||
}
|
||||
`;
|
||||
export type StopWorkflowRunMutationFn = Apollo.MutationFunction<StopWorkflowRunMutation, StopWorkflowRunMutationVariables>;
|
||||
|
||||
/**
|
||||
* __useStopWorkflowRunMutation__
|
||||
*
|
||||
* To run a mutation, you first call `useStopWorkflowRunMutation` within a React component and pass it any options that fit your needs.
|
||||
* When your component renders, `useStopWorkflowRunMutation` 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 [stopWorkflowRunMutation, { data, loading, error }] = useStopWorkflowRunMutation({
|
||||
* variables: {
|
||||
* workflowRunId: // value for 'workflowRunId'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useStopWorkflowRunMutation(baseOptions?: Apollo.MutationHookOptions<StopWorkflowRunMutation, StopWorkflowRunMutationVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useMutation<StopWorkflowRunMutation, StopWorkflowRunMutationVariables>(StopWorkflowRunDocument, options);
|
||||
}
|
||||
export type StopWorkflowRunMutationHookResult = ReturnType<typeof useStopWorkflowRunMutation>;
|
||||
export type StopWorkflowRunMutationResult = Apollo.MutationResult<StopWorkflowRunMutation>;
|
||||
export type StopWorkflowRunMutationOptions = Apollo.BaseMutationOptions<StopWorkflowRunMutation, StopWorkflowRunMutationVariables>;
|
||||
export const UpdateWorkflowRunStepDocument = gql`
|
||||
mutation UpdateWorkflowRunStep($input: UpdateWorkflowRunStepInput!) {
|
||||
updateWorkflowRunStep(input: $input) {
|
||||
|
||||
@@ -1780,7 +1780,7 @@ export type Mutation = {
|
||||
restorePageLayoutWidget: PageLayoutWidget;
|
||||
retryJobs: RetryJobsResponse;
|
||||
revokeApiKey?: Maybe<ApiKey>;
|
||||
runWorkflowVersion: WorkflowRun;
|
||||
runWorkflowVersion: RunWorkflowVersionOutput;
|
||||
saveImapSmtpCaldavAccount: ImapSmtpCaldavConnectionSuccess;
|
||||
sendInvitations: SendInvitationsOutput;
|
||||
setMeteredSubscriptionPrice: BillingUpdateOutput;
|
||||
@@ -1791,6 +1791,7 @@ export type Mutation = {
|
||||
skipBookOnboardingStep: OnboardingStepSuccess;
|
||||
skipSyncEmailOnboardingStep: OnboardingStepSuccess;
|
||||
startChannelSync: ChannelSyncSuccess;
|
||||
stopWorkflowRun: WorkflowRun;
|
||||
submitFormStep: Scalars['Boolean'];
|
||||
switchBillingPlan: BillingUpdateOutput;
|
||||
switchSubscriptionInterval: BillingUpdateOutput;
|
||||
@@ -2447,6 +2448,11 @@ export type MutationStartChannelSyncArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationStopWorkflowRunArgs = {
|
||||
workflowRunId: Scalars['UUID'];
|
||||
};
|
||||
|
||||
|
||||
export type MutationSubmitFormStepArgs = {
|
||||
input: SubmitFormStepInput;
|
||||
};
|
||||
@@ -3548,6 +3554,11 @@ export type RunWorkflowVersionInput = {
|
||||
workflowVersionId: Scalars['UUID'];
|
||||
};
|
||||
|
||||
export type RunWorkflowVersionOutput = {
|
||||
__typename?: 'RunWorkflowVersionOutput';
|
||||
workflowRunId: Scalars['UUID'];
|
||||
};
|
||||
|
||||
export type SsoConnection = {
|
||||
__typename?: 'SSOConnection';
|
||||
id: Scalars['UUID'];
|
||||
@@ -4413,9 +4424,21 @@ export enum WorkflowActionType {
|
||||
|
||||
export type WorkflowRun = {
|
||||
__typename?: 'WorkflowRun';
|
||||
workflowRunId: Scalars['UUID'];
|
||||
id: Scalars['UUID'];
|
||||
status: WorkflowRunStatusEnum;
|
||||
};
|
||||
|
||||
/** Status of the workflow run */
|
||||
export enum WorkflowRunStatusEnum {
|
||||
COMPLETED = 'COMPLETED',
|
||||
ENQUEUED = 'ENQUEUED',
|
||||
FAILED = 'FAILED',
|
||||
NOT_STARTED = 'NOT_STARTED',
|
||||
RUNNING = 'RUNNING',
|
||||
STOPPED = 'STOPPED',
|
||||
STOPPING = 'STOPPING'
|
||||
}
|
||||
|
||||
export type WorkflowStepPosition = {
|
||||
__typename?: 'WorkflowStepPosition';
|
||||
x: Scalars['Float'];
|
||||
|
||||
+46
-22
@@ -3,21 +3,45 @@ import { NoSelectionRecordActionKeys } from '@/action-menu/actions/record-action
|
||||
import { SingleRecordActionKeys } from '@/action-menu/actions/record-actions/single-record/types/SingleRecordActionsKey';
|
||||
import { SeeVersionWorkflowRunSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/workflow-run-actions/components/SeeVersionWorkflowRunSingleRecordAction';
|
||||
import { SeeWorkflowWorkflowRunSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/workflow-run-actions/components/SeeWorkflowWorkflowRunSingleRecordAction';
|
||||
import { StopWorkflowRunSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/workflow-run-actions/components/StopWorkflowRunSingleRecordAction';
|
||||
import { WorkflowRunSingleRecordActionKeys } from '@/action-menu/actions/record-actions/single-record/workflow-run-actions/types/WorkflowRunSingleRecordActionsKeys';
|
||||
import { inheritActionsFromDefaultConfig } from '@/action-menu/actions/record-actions/utils/inheritActionsFromDefaultConfig';
|
||||
import { ActionScope } from '@/action-menu/actions/types/ActionScope';
|
||||
import { ActionType } from '@/action-menu/actions/types/ActionType';
|
||||
import { ActionViewType } from '@/action-menu/actions/types/ActionViewType';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { IconSettingsAutomation, IconVersions } from 'twenty-ui/display';
|
||||
import {
|
||||
IconPlayerStop,
|
||||
IconSettingsAutomation,
|
||||
IconVersions,
|
||||
} from 'twenty-ui/display';
|
||||
|
||||
export const WORKFLOW_RUNS_ACTIONS_CONFIG = inheritActionsFromDefaultConfig({
|
||||
config: {
|
||||
[WorkflowRunSingleRecordActionKeys.STOP]: {
|
||||
key: WorkflowRunSingleRecordActionKeys.STOP,
|
||||
label: msg`Stop`,
|
||||
shortLabel: msg`Stop`,
|
||||
position: 0,
|
||||
isPinned: true,
|
||||
type: ActionType.Standard,
|
||||
scope: ActionScope.RecordSelection,
|
||||
Icon: IconPlayerStop,
|
||||
shouldBeRegistered: ({ selectedRecord }) => {
|
||||
return selectedRecord?.status === 'RUNNING';
|
||||
},
|
||||
availableOn: [
|
||||
ActionViewType.SHOW_PAGE,
|
||||
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionViewType.INDEX_PAGE_BULK_SELECTION,
|
||||
],
|
||||
component: <StopWorkflowRunSingleRecordAction />,
|
||||
},
|
||||
[WorkflowRunSingleRecordActionKeys.SEE_WORKFLOW]: {
|
||||
key: WorkflowRunSingleRecordActionKeys.SEE_WORKFLOW,
|
||||
label: msg`See workflow`,
|
||||
shortLabel: msg`See workflow`,
|
||||
position: 0,
|
||||
position: 1,
|
||||
isPinned: true,
|
||||
type: ActionType.Standard,
|
||||
scope: ActionScope.RecordSelection,
|
||||
@@ -33,7 +57,7 @@ export const WORKFLOW_RUNS_ACTIONS_CONFIG = inheritActionsFromDefaultConfig({
|
||||
key: WorkflowRunSingleRecordActionKeys.SEE_VERSION,
|
||||
label: msg`See version`,
|
||||
shortLabel: msg`See version`,
|
||||
position: 1,
|
||||
position: 2,
|
||||
isPinned: true,
|
||||
type: ActionType.Standard,
|
||||
scope: ActionScope.RecordSelection,
|
||||
@@ -68,63 +92,63 @@ export const WORKFLOW_RUNS_ACTIONS_CONFIG = inheritActionsFromDefaultConfig({
|
||||
propertiesToOverwrite: {
|
||||
[SingleRecordActionKeys.ADD_TO_FAVORITES]: {
|
||||
isPinned: false,
|
||||
position: 2,
|
||||
position: 3,
|
||||
},
|
||||
[SingleRecordActionKeys.REMOVE_FROM_FAVORITES]: {
|
||||
isPinned: false,
|
||||
position: 3,
|
||||
position: 4,
|
||||
},
|
||||
[SingleRecordActionKeys.EXPORT_FROM_RECORD_INDEX]: {
|
||||
position: 4,
|
||||
position: 5,
|
||||
label: msg`Export run`,
|
||||
},
|
||||
[SingleRecordActionKeys.EXPORT_FROM_RECORD_SHOW]: {
|
||||
position: 4,
|
||||
position: 5,
|
||||
label: msg`Export run`,
|
||||
},
|
||||
[MultipleRecordsActionKeys.EXPORT]: {
|
||||
position: 5,
|
||||
position: 6,
|
||||
label: msg`Export runs`,
|
||||
},
|
||||
[NoSelectionRecordActionKeys.EXPORT_VIEW]: {
|
||||
position: 6,
|
||||
position: 7,
|
||||
label: msg`Export view`,
|
||||
},
|
||||
[NoSelectionRecordActionKeys.SEE_DELETED_RECORDS]: {
|
||||
position: 7,
|
||||
position: 8,
|
||||
label: msg`See deleted runs`,
|
||||
},
|
||||
[NoSelectionRecordActionKeys.HIDE_DELETED_RECORDS]: {
|
||||
position: 8,
|
||||
position: 9,
|
||||
label: msg`Hide deleted runs`,
|
||||
},
|
||||
[SingleRecordActionKeys.NAVIGATE_TO_PREVIOUS_RECORD]: {
|
||||
position: 9,
|
||||
},
|
||||
[SingleRecordActionKeys.NAVIGATE_TO_NEXT_RECORD]: {
|
||||
position: 10,
|
||||
},
|
||||
[NoSelectionRecordActionKeys.GO_TO_WORKFLOWS]: {
|
||||
[SingleRecordActionKeys.NAVIGATE_TO_NEXT_RECORD]: {
|
||||
position: 11,
|
||||
},
|
||||
[NoSelectionRecordActionKeys.GO_TO_WORKFLOWS]: {
|
||||
position: 12,
|
||||
isPinned: true,
|
||||
},
|
||||
[NoSelectionRecordActionKeys.GO_TO_PEOPLE]: {
|
||||
position: 12,
|
||||
},
|
||||
[NoSelectionRecordActionKeys.GO_TO_COMPANIES]: {
|
||||
position: 13,
|
||||
},
|
||||
[NoSelectionRecordActionKeys.GO_TO_OPPORTUNITIES]: {
|
||||
[NoSelectionRecordActionKeys.GO_TO_COMPANIES]: {
|
||||
position: 14,
|
||||
},
|
||||
[NoSelectionRecordActionKeys.GO_TO_SETTINGS]: {
|
||||
[NoSelectionRecordActionKeys.GO_TO_OPPORTUNITIES]: {
|
||||
position: 15,
|
||||
},
|
||||
[NoSelectionRecordActionKeys.GO_TO_TASKS]: {
|
||||
[NoSelectionRecordActionKeys.GO_TO_SETTINGS]: {
|
||||
position: 16,
|
||||
},
|
||||
[NoSelectionRecordActionKeys.GO_TO_NOTES]: {
|
||||
[NoSelectionRecordActionKeys.GO_TO_TASKS]: {
|
||||
position: 17,
|
||||
},
|
||||
[NoSelectionRecordActionKeys.GO_TO_NOTES]: {
|
||||
position: 18,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
import { Action } from '@/action-menu/actions/components/Action';
|
||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { useStopWorkflowRun } from '@/workflow/hooks/useStopWorkflowRun';
|
||||
|
||||
export const StopWorkflowRunSingleRecordAction = () => {
|
||||
const contextStoreTargetedRecordsRule = useRecoilComponentValue(
|
||||
contextStoreTargetedRecordsRuleComponentState,
|
||||
);
|
||||
|
||||
if (
|
||||
contextStoreTargetedRecordsRule.mode === 'exclusion' ||
|
||||
(contextStoreTargetedRecordsRule.mode === 'selection' &&
|
||||
contextStoreTargetedRecordsRule.selectedRecordIds.length === 0)
|
||||
) {
|
||||
throw new Error('Selected record ID is required');
|
||||
}
|
||||
|
||||
const selectedRecordIds = contextStoreTargetedRecordsRule.selectedRecordIds;
|
||||
const { stopWorkflowRun } = useStopWorkflowRun();
|
||||
|
||||
const handleClick = async () => {
|
||||
for (const selectedRecordId of selectedRecordIds) {
|
||||
await stopWorkflowRun(selectedRecordId);
|
||||
}
|
||||
};
|
||||
|
||||
return <Action onClick={handleClick} />;
|
||||
};
|
||||
+1
@@ -1,4 +1,5 @@
|
||||
export enum WorkflowRunSingleRecordActionKeys {
|
||||
STOP = 'stop-workflow-run-single-record',
|
||||
SEE_WORKFLOW = 'see-workflow-workflow-run-single-record',
|
||||
SEE_VERSION = 'see-version-workflow-run-single-record',
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
export const STOP_WORKFLOW_RUN = gql`
|
||||
mutation StopWorkflowRun($workflowRunId: UUID!) {
|
||||
stopWorkflowRun(workflowRunId: $workflowRunId) {
|
||||
id
|
||||
status
|
||||
__typename
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -0,0 +1,29 @@
|
||||
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
|
||||
import { useRegisterObjectOperation } from '@/object-record/hooks/useRegisterObjectOperation';
|
||||
import { useStopWorkflowRunMutation } from '~/generated-metadata/graphql';
|
||||
|
||||
export const useStopWorkflowRun = () => {
|
||||
const apolloCoreClient = useApolloCoreClient();
|
||||
const [mutate] = useStopWorkflowRunMutation({
|
||||
client: apolloCoreClient,
|
||||
});
|
||||
const { registerObjectOperation } = useRegisterObjectOperation();
|
||||
|
||||
const stopWorkflowRun = async (workflowRunId: string) => {
|
||||
const { data } = await mutate({
|
||||
variables: {
|
||||
workflowRunId,
|
||||
},
|
||||
});
|
||||
|
||||
registerObjectOperation('workflowRun', {
|
||||
type: 'update-one',
|
||||
result: {
|
||||
updatedRecord: data?.stopWorkflowRun,
|
||||
updateInput: { id: workflowRunId },
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return { stopWorkflowRun };
|
||||
};
|
||||
+14
@@ -34,6 +34,20 @@ export const getWorkflowRunStatusTagProps = ({
|
||||
};
|
||||
}
|
||||
|
||||
if (workflowRunStatus === 'STOPPING') {
|
||||
return {
|
||||
color: 'orange',
|
||||
text: 'Stopping',
|
||||
};
|
||||
}
|
||||
|
||||
if (workflowRunStatus === 'STOPPED') {
|
||||
return {
|
||||
color: 'gray',
|
||||
text: 'Stopped',
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
color: 'red',
|
||||
text: 'Failed',
|
||||
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
import { InjectDataSource, InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { Command } from 'nest-commander';
|
||||
import { DataSource, Repository } from 'typeorm';
|
||||
|
||||
import {
|
||||
ActiveOrSuspendedWorkspacesMigrationCommandRunner,
|
||||
type RunOnWorkspaceArgs,
|
||||
} from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner';
|
||||
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
||||
import { getWorkspaceSchemaName } from 'src/engine/workspace-datasource/utils/get-workspace-schema-name.util';
|
||||
import { WORKFLOW_RUN_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
|
||||
import { WorkflowRunStatus } from 'src/modules/workflow/common/standard-objects/workflow-run.workspace-entity';
|
||||
|
||||
@Command({
|
||||
name: 'upgrade:1-10:add-workflow-run-stop-statuses',
|
||||
description: 'Add stopped and stopping statuses to workflow runs',
|
||||
})
|
||||
export class AddWorkflowRunStopStatusesCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner {
|
||||
constructor(
|
||||
@InjectRepository(WorkspaceEntity)
|
||||
protected readonly workspaceRepository: Repository<WorkspaceEntity>,
|
||||
protected readonly twentyORMGlobalManager: TwentyORMGlobalManager,
|
||||
@InjectRepository(FieldMetadataEntity)
|
||||
private readonly fieldMetadataRepository: Repository<FieldMetadataEntity>,
|
||||
@InjectDataSource()
|
||||
private readonly coreDataSource: DataSource,
|
||||
) {
|
||||
super(workspaceRepository, twentyORMGlobalManager);
|
||||
}
|
||||
|
||||
override async runOnWorkspace({
|
||||
workspaceId,
|
||||
options,
|
||||
}: RunOnWorkspaceArgs): Promise<void> {
|
||||
this.logger.log(
|
||||
`Adding stopped and stopping statuses to workflow runs for workspace ${workspaceId}`,
|
||||
);
|
||||
|
||||
const workflowRunStatusFieldMetadata =
|
||||
await this.fieldMetadataRepository.findOne({
|
||||
where: {
|
||||
standardId: WORKFLOW_RUN_STANDARD_FIELD_IDS.status,
|
||||
},
|
||||
});
|
||||
|
||||
if (!workflowRunStatusFieldMetadata) {
|
||||
this.logger.error(
|
||||
`Workflow run status field metadata not found for workspace ${workspaceId}`,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const workflowRunStatusFieldMetadataOptions =
|
||||
workflowRunStatusFieldMetadata.options;
|
||||
|
||||
if (
|
||||
workflowRunStatusFieldMetadataOptions?.some(
|
||||
(option) =>
|
||||
option.value === WorkflowRunStatus.STOPPED ||
|
||||
option.value === WorkflowRunStatus.STOPPING,
|
||||
)
|
||||
) {
|
||||
this.logger.log(
|
||||
`Workflow run status field metadata options already contain stopped and stopping statuses for workspace ${workspaceId}`,
|
||||
);
|
||||
|
||||
return;
|
||||
} else if (options.dryRun) {
|
||||
this.logger.log(
|
||||
`Would add stopped and stopping statuses to workflow run status field metadata for workspace ${workspaceId}`,
|
||||
);
|
||||
} else {
|
||||
workflowRunStatusFieldMetadataOptions?.push({
|
||||
value: WorkflowRunStatus.STOPPING,
|
||||
label: 'Stopping',
|
||||
position: 5,
|
||||
color: 'orange',
|
||||
});
|
||||
workflowRunStatusFieldMetadataOptions?.push({
|
||||
value: WorkflowRunStatus.STOPPED,
|
||||
label: 'Stopped',
|
||||
position: 6,
|
||||
color: 'gray',
|
||||
});
|
||||
|
||||
await this.fieldMetadataRepository.save(workflowRunStatusFieldMetadata);
|
||||
|
||||
this.logger.log(
|
||||
`Stopped and stopping statuses added to workflow run status field metadata for workspace ${workspaceId}`,
|
||||
);
|
||||
}
|
||||
|
||||
const schemaName = getWorkspaceSchemaName(workspaceId);
|
||||
|
||||
if (options.dryRun) {
|
||||
this.logger.log(
|
||||
`Would try to add stopped and stopping statuses to workflow run status enum for workspace ${workspaceId}`,
|
||||
);
|
||||
} else {
|
||||
try {
|
||||
await this.coreDataSource.query(
|
||||
`ALTER TYPE ${schemaName}."workflowRun_status_enum" ADD VALUE 'STOPPING'`,
|
||||
);
|
||||
this.logger.log(
|
||||
`Stopping status added to workflow run status enum for workspace ${workspaceId}`,
|
||||
);
|
||||
await this.coreDataSource.query(
|
||||
`ALTER TYPE ${schemaName}."workflowRun_status_enum" ADD VALUE 'STOPPED'`,
|
||||
);
|
||||
this.logger.log(
|
||||
`Stopped status added to workflow run status enum for workspace ${workspaceId}`,
|
||||
);
|
||||
} catch (error) {
|
||||
this.logger.error(
|
||||
`Error adding stopped and stopping statuses to workflow run status enum for workspace ${workspaceId}: ${error}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
-1
@@ -1,23 +1,27 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { AddWorkflowRunStopStatusesCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-add-workflow-run-stop-statuses.command';
|
||||
import { MigrateAttachmentAuthorToCreatedByCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-migrate-attachment-author-to-created-by.command';
|
||||
import { MigrateAttachmentTypeToFileCategoryCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-migrate-attachment-type-to-file-category.command';
|
||||
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { WorkspaceSchemaManagerModule } from 'src/engine/twenty-orm/workspace-schema-manager/workspace-schema-manager.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([WorkspaceEntity]),
|
||||
TypeOrmModule.forFeature([WorkspaceEntity, FieldMetadataEntity]),
|
||||
WorkspaceSchemaManagerModule,
|
||||
],
|
||||
providers: [
|
||||
MigrateAttachmentAuthorToCreatedByCommand,
|
||||
MigrateAttachmentTypeToFileCategoryCommand,
|
||||
AddWorkflowRunStopStatusesCommand,
|
||||
],
|
||||
exports: [
|
||||
MigrateAttachmentAuthorToCreatedByCommand,
|
||||
MigrateAttachmentTypeToFileCategoryCommand,
|
||||
AddWorkflowRunStopStatusesCommand,
|
||||
],
|
||||
})
|
||||
export class V1_10_UpgradeVersionCommandModule {}
|
||||
|
||||
+3
-1
@@ -19,6 +19,7 @@ import { AddEnqueuedStatusToWorkflowRunCommand } from 'src/database/commands/upg
|
||||
import { FixSchemaArrayTypeCommand } from 'src/database/commands/upgrade-version-command/1-1/1-1-fix-schema-array-type.command';
|
||||
import { FixUpdateStandardFieldsIsLabelSyncedWithName } from 'src/database/commands/upgrade-version-command/1-1/1-1-fix-update-standard-field-is-label-synced-with-name.command';
|
||||
import { MigrateWorkflowRunStatesCommand } from 'src/database/commands/upgrade-version-command/1-1/1-1-migrate-workflow-run-state.command';
|
||||
import { AddWorkflowRunStopStatusesCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-add-workflow-run-stop-statuses.command';
|
||||
import { MigrateAttachmentAuthorToCreatedByCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-migrate-attachment-author-to-created-by.command';
|
||||
import { MigrateAttachmentTypeToFileCategoryCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-migrate-attachment-type-to-file-category.command';
|
||||
import { AddEnqueuedStatusToWorkflowRunV2Command } from 'src/database/commands/upgrade-version-command/1-2/1-2-add-enqueued-status-to-workflow-run-v2.command';
|
||||
@@ -101,6 +102,7 @@ export class UpgradeCommand extends UpgradeCommandRunner {
|
||||
// 1.10 Commands
|
||||
protected readonly migrateAttachmentAuthorToCreatedByCommand: MigrateAttachmentAuthorToCreatedByCommand,
|
||||
protected readonly migrateAttachmentTypeToFileCategoryCommand: MigrateAttachmentTypeToFileCategoryCommand,
|
||||
protected readonly addWorkflowRunStopStatusesCommand: AddWorkflowRunStopStatusesCommand,
|
||||
) {
|
||||
super(
|
||||
workspaceRepository,
|
||||
@@ -206,7 +208,7 @@ export class UpgradeCommand extends UpgradeCommandRunner {
|
||||
};
|
||||
|
||||
const commands_1100: VersionCommands = {
|
||||
beforeSyncMetadata: [],
|
||||
beforeSyncMetadata: [this.addWorkflowRunStopStatusesCommand],
|
||||
afterSyncMetadata: [
|
||||
this.migrateAttachmentAuthorToCreatedByCommand,
|
||||
this.migrateAttachmentTypeToFileCategoryCommand,
|
||||
|
||||
@@ -19,6 +19,7 @@ export enum MetricsKeys {
|
||||
WorkflowRunStartedManualTrigger = 'workflow-run/started/manual-trigger',
|
||||
WorkflowRunCompleted = 'workflow-run/completed',
|
||||
WorkflowRunFailed = 'workflow-run/failed',
|
||||
WorkflowRunStopped = 'workflow-run/stopped',
|
||||
WorkflowRunFailedThrottled = 'workflow-run/failed/throttled',
|
||||
WorkflowRunFailedToEnqueue = 'workflow-run/failed/to-enqueue',
|
||||
AIToolExecutionFailed = 'ai-tool-execution/failed',
|
||||
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
import { Field, ObjectType } from '@nestjs/graphql';
|
||||
|
||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||
|
||||
@ObjectType('RunWorkflowVersionOutput')
|
||||
export class RunWorkflowVersionOutput {
|
||||
@Field(() => UUIDScalarType)
|
||||
workflowRunId: string;
|
||||
}
|
||||
@@ -1,9 +1,13 @@
|
||||
import { Field, ObjectType } from '@nestjs/graphql';
|
||||
|
||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||
import { WorkflowRunStatus } from 'src/modules/workflow/common/standard-objects/workflow-run.workspace-entity';
|
||||
|
||||
@ObjectType('WorkflowRun')
|
||||
export class WorkflowRunDTO {
|
||||
@Field(() => UUIDScalarType)
|
||||
workflowRunId: string;
|
||||
id: string;
|
||||
|
||||
@Field(() => WorkflowRunStatus)
|
||||
status: WorkflowRunStatus;
|
||||
}
|
||||
|
||||
+10
-1
@@ -7,6 +7,7 @@ import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules
|
||||
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
|
||||
import { UserEntity } from 'src/engine/core-modules/user/user.entity';
|
||||
import { RunWorkflowVersionInput } from 'src/engine/core-modules/workflow/dtos/run-workflow-version-input.dto';
|
||||
import { RunWorkflowVersionOutput } from 'src/engine/core-modules/workflow/dtos/run-workflow-version-output.dto';
|
||||
import { WorkflowRunDTO } from 'src/engine/core-modules/workflow/dtos/workflow-run.dto';
|
||||
import { WorkflowTriggerGraphqlApiExceptionFilter } from 'src/engine/core-modules/workflow/filters/workflow-trigger-graphql-api-exception.filter';
|
||||
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
@@ -59,7 +60,7 @@ export class WorkflowTriggerResolver {
|
||||
);
|
||||
}
|
||||
|
||||
@Mutation(() => WorkflowRunDTO)
|
||||
@Mutation(() => RunWorkflowVersionOutput)
|
||||
async runWorkflowVersion(
|
||||
@AuthUser() user: UserEntity,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
@@ -91,4 +92,12 @@ export class WorkflowTriggerResolver {
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
@Mutation(() => WorkflowRunDTO)
|
||||
async stopWorkflowRun(
|
||||
@Args('workflowRunId', { type: () => UUIDScalarType })
|
||||
workflowRunId: string,
|
||||
) {
|
||||
return this.workflowTriggerWorkspaceService.stopWorkflowRun(workflowRunId);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-1
@@ -18,7 +18,10 @@ export class WorkflowRunUpdateOnePreQueryHook
|
||||
_objectName: string,
|
||||
payload: UpdateOneResolverArgs<WorkflowRunWorkspaceEntity>,
|
||||
): Promise<UpdateOneResolverArgs<WorkflowRunWorkspaceEntity>> {
|
||||
if (Object.keys(payload.data).length === 1 && payload.data.name) {
|
||||
const allowedFields = ['name'];
|
||||
const payloadKeys = Object.keys(payload.data);
|
||||
|
||||
if (payloadKeys.every((key) => allowedFields.includes(key))) {
|
||||
return payload;
|
||||
}
|
||||
|
||||
|
||||
+21
@@ -1,3 +1,5 @@
|
||||
import { registerEnumType } from '@nestjs/graphql';
|
||||
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { type WorkflowRunStepInfos } from 'twenty-shared/workflow';
|
||||
@@ -40,8 +42,15 @@ export enum WorkflowRunStatus {
|
||||
COMPLETED = 'COMPLETED',
|
||||
FAILED = 'FAILED',
|
||||
ENQUEUED = 'ENQUEUED',
|
||||
STOPPING = 'STOPPING',
|
||||
STOPPED = 'STOPPED',
|
||||
}
|
||||
|
||||
registerEnumType(WorkflowRunStatus, {
|
||||
name: 'WorkflowRunStatusEnum',
|
||||
description: 'Status of the workflow run',
|
||||
});
|
||||
|
||||
export type StepOutput = {
|
||||
id: string;
|
||||
output: WorkflowActionOutput;
|
||||
@@ -159,6 +168,18 @@ export class WorkflowRunWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
position: 4,
|
||||
color: 'blue',
|
||||
},
|
||||
{
|
||||
value: WorkflowRunStatus.STOPPING,
|
||||
label: 'Stopping',
|
||||
position: 5,
|
||||
color: 'orange',
|
||||
},
|
||||
{
|
||||
value: WorkflowRunStatus.STOPPED,
|
||||
label: 'Stopped',
|
||||
position: 6,
|
||||
color: 'gray',
|
||||
},
|
||||
],
|
||||
defaultValue: "'NOT_STARTED'",
|
||||
})
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
import { StepStatus, type WorkflowRunStepInfos } from 'twenty-shared/workflow';
|
||||
|
||||
import { type WorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action.type';
|
||||
|
||||
export const workflowHasRunningSteps = ({
|
||||
stepInfos,
|
||||
steps,
|
||||
}: {
|
||||
stepInfos: WorkflowRunStepInfos;
|
||||
steps: WorkflowAction[];
|
||||
}) => {
|
||||
return steps.some(
|
||||
(step) => stepInfos[step.id]?.status === StepStatus.RUNNING,
|
||||
);
|
||||
};
|
||||
+13
@@ -20,6 +20,7 @@ import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queu
|
||||
import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service';
|
||||
import { WorkspaceEventEmitter } from 'src/engine/workspace-event-emitter/workspace-event-emitter';
|
||||
import { WorkflowRunStatus } from 'src/modules/workflow/common/standard-objects/workflow-run.workspace-entity';
|
||||
import { workflowHasRunningSteps } from 'src/modules/workflow/common/utils/workflow-has-running-steps.util';
|
||||
import { WorkflowActionFactory } from 'src/modules/workflow/workflow-executor/factories/workflow-action.factory';
|
||||
import { type WorkflowActionOutput } from 'src/modules/workflow/workflow-executor/types/workflow-action-output.type';
|
||||
import {
|
||||
@@ -224,6 +225,18 @@ export class WorkflowExecutorWorkspaceService {
|
||||
|
||||
const steps = workflowRun.state.flow.steps;
|
||||
|
||||
if (workflowRun.status === WorkflowRunStatus.STOPPING) {
|
||||
if (!workflowHasRunningSteps({ stepInfos, steps })) {
|
||||
await this.workflowRunWorkspaceService.endWorkflowRun({
|
||||
workflowRunId,
|
||||
workspaceId,
|
||||
status: WorkflowRunStatus.STOPPED,
|
||||
});
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (workflowShouldFail({ stepInfos, steps })) {
|
||||
await this.workflowRunWorkspaceService.endWorkflowRun({
|
||||
workflowRunId,
|
||||
|
||||
+37
-38
@@ -190,7 +190,7 @@ export class WorkflowRunWorkspaceService {
|
||||
}: {
|
||||
workflowRunId: string;
|
||||
workspaceId: string;
|
||||
status: WorkflowRunStatus;
|
||||
status: Extract<WorkflowRunStatus, 'COMPLETED' | 'FAILED' | 'STOPPED'>;
|
||||
error?: string;
|
||||
}) {
|
||||
const workflowRunToUpdate = await this.getWorkflowRunOrFail({
|
||||
@@ -199,13 +199,10 @@ export class WorkflowRunWorkspaceService {
|
||||
});
|
||||
|
||||
let updatedStepInfos = {};
|
||||
const shouldUpdateStepInfos = status === WorkflowRunStatus.FAILED;
|
||||
|
||||
if (shouldUpdateStepInfos) {
|
||||
updatedStepInfos = this.markRunningStepsAsFailed({
|
||||
stepInfosToUpdate: workflowRunToUpdate.state?.stepInfos ?? {},
|
||||
});
|
||||
}
|
||||
updatedStepInfos = this.markRunningStepsAsFailed({
|
||||
stepInfosToUpdate: workflowRunToUpdate.state?.stepInfos ?? {},
|
||||
});
|
||||
|
||||
const partialUpdate = {
|
||||
status,
|
||||
@@ -213,7 +210,7 @@ export class WorkflowRunWorkspaceService {
|
||||
state: {
|
||||
...workflowRunToUpdate.state,
|
||||
workflowRunError: error,
|
||||
...(shouldUpdateStepInfos && { stepInfos: updatedStepInfos }),
|
||||
stepInfos: updatedStepInfos,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -223,7 +220,9 @@ export class WorkflowRunWorkspaceService {
|
||||
key:
|
||||
status === WorkflowRunStatus.COMPLETED
|
||||
? MetricsKeys.WorkflowRunCompleted
|
||||
: MetricsKeys.WorkflowRunFailed,
|
||||
: status === WorkflowRunStatus.STOPPED
|
||||
? MetricsKeys.WorkflowRunStopped
|
||||
: MetricsKeys.WorkflowRunFailed,
|
||||
eventId: workflowRunId,
|
||||
});
|
||||
}
|
||||
@@ -378,35 +377,7 @@ export class WorkflowRunWorkspaceService {
|
||||
return workflowRun;
|
||||
}
|
||||
|
||||
private getInitState(
|
||||
workflowVersion: WorkflowVersionWorkspaceEntity,
|
||||
triggerPayload: object,
|
||||
): WorkflowRunState | undefined {
|
||||
if (
|
||||
!isDefined(workflowVersion.trigger) ||
|
||||
!isDefined(workflowVersion.steps)
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
flow: {
|
||||
trigger: workflowVersion.trigger,
|
||||
steps: workflowVersion.steps,
|
||||
},
|
||||
stepInfos: {
|
||||
trigger: { status: StepStatus.NOT_STARTED, result: triggerPayload },
|
||||
...Object.fromEntries(
|
||||
workflowVersion.steps.map((step) => [
|
||||
step.id,
|
||||
{ status: StepStatus.NOT_STARTED },
|
||||
]),
|
||||
),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private async updateWorkflowRun({
|
||||
async updateWorkflowRun({
|
||||
workflowRunId,
|
||||
workspaceId,
|
||||
partialUpdate,
|
||||
@@ -441,6 +412,34 @@ export class WorkflowRunWorkspaceService {
|
||||
);
|
||||
}
|
||||
|
||||
private getInitState(
|
||||
workflowVersion: WorkflowVersionWorkspaceEntity,
|
||||
triggerPayload: object,
|
||||
): WorkflowRunState | undefined {
|
||||
if (
|
||||
!isDefined(workflowVersion.trigger) ||
|
||||
!isDefined(workflowVersion.steps)
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
flow: {
|
||||
trigger: workflowVersion.trigger,
|
||||
steps: workflowVersion.steps,
|
||||
},
|
||||
stepInfos: {
|
||||
trigger: { status: StepStatus.NOT_STARTED, result: triggerPayload },
|
||||
...Object.fromEntries(
|
||||
workflowVersion.steps.map((step) => [
|
||||
step.id,
|
||||
{ status: StepStatus.NOT_STARTED },
|
||||
]),
|
||||
),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private markRunningStepsAsFailed({
|
||||
stepInfosToUpdate,
|
||||
}: {
|
||||
|
||||
+53
@@ -14,9 +14,14 @@ import {
|
||||
WorkflowVersionStepExceptionCode,
|
||||
} from 'src/modules/workflow/common/exceptions/workflow-version-step.exception';
|
||||
import { WorkflowRunStatus } from 'src/modules/workflow/common/standard-objects/workflow-run.workspace-entity';
|
||||
import { workflowHasRunningSteps } from 'src/modules/workflow/common/utils/workflow-has-running-steps.util';
|
||||
import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service';
|
||||
import { WorkflowVersionStepOperationsWorkspaceService } from 'src/modules/workflow/workflow-builder/workflow-version-step/workflow-version-step-operations.workspace-service';
|
||||
import { isWorkflowFormAction } from 'src/modules/workflow/workflow-executor/workflow-actions/form/guards/is-workflow-form-action.guard';
|
||||
import {
|
||||
WorkflowRunException,
|
||||
WorkflowRunExceptionCode,
|
||||
} from 'src/modules/workflow/workflow-runner/exceptions/workflow-run.exception';
|
||||
import { RunWorkflowJob } from 'src/modules/workflow/workflow-runner/jobs/run-workflow.job';
|
||||
import { type RunWorkflowJobData } from 'src/modules/workflow/workflow-runner/types/run-workflow-job-data.type';
|
||||
import { WorkflowRunQueueWorkspaceService } from 'src/modules/workflow/workflow-runner/workflow-run-queue/workspace-services/workflow-run-queue.workspace-service';
|
||||
@@ -191,4 +196,52 @@ export class WorkflowRunnerWorkspaceService {
|
||||
workspaceId,
|
||||
);
|
||||
}
|
||||
|
||||
async stopWorkflowRun(workspaceId: string, workflowRunId: string) {
|
||||
const workflowRun =
|
||||
await this.workflowRunWorkspaceService.getWorkflowRunOrFail({
|
||||
workflowRunId,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
if (workflowRun.status !== WorkflowRunStatus.RUNNING) {
|
||||
throw new WorkflowRunException(
|
||||
'Workflow run is not running',
|
||||
WorkflowRunExceptionCode.INVALID_OPERATION,
|
||||
{
|
||||
userFriendlyMessage: msg`Workflow run is not running`,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
let newStatus: WorkflowRunStatus;
|
||||
|
||||
if (
|
||||
workflowHasRunningSteps({
|
||||
stepInfos: workflowRun.state.stepInfos,
|
||||
steps: workflowRun.state.flow.steps,
|
||||
})
|
||||
) {
|
||||
await this.workflowRunWorkspaceService.updateWorkflowRun({
|
||||
workflowRunId,
|
||||
workspaceId,
|
||||
partialUpdate: {
|
||||
status: WorkflowRunStatus.STOPPING,
|
||||
},
|
||||
});
|
||||
newStatus = WorkflowRunStatus.STOPPING;
|
||||
} else {
|
||||
await this.workflowRunWorkspaceService.endWorkflowRun({
|
||||
workflowRunId,
|
||||
workspaceId,
|
||||
status: WorkflowRunStatus.STOPPED,
|
||||
});
|
||||
newStatus = WorkflowRunStatus.STOPPED;
|
||||
}
|
||||
|
||||
return {
|
||||
id: workflowRun.id,
|
||||
status: newStatus,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+7
@@ -142,6 +142,13 @@ export class WorkflowTriggerWorkspaceService {
|
||||
return true;
|
||||
}
|
||||
|
||||
async stopWorkflowRun(workflowRunId: string) {
|
||||
return this.workflowRunnerWorkspaceService.stopWorkflowRun(
|
||||
this.getWorkspaceId(),
|
||||
workflowRunId,
|
||||
);
|
||||
}
|
||||
|
||||
private async performActivationSteps(
|
||||
workflow: WorkflowWorkspaceEntity,
|
||||
workflowVersion: WorkflowVersionWorkspaceEntity,
|
||||
|
||||
@@ -6,4 +6,6 @@ export const workflowRunStatusSchema = z.enum([
|
||||
'COMPLETED',
|
||||
'FAILED',
|
||||
'ENQUEUED',
|
||||
'STOPPING',
|
||||
'STOPPED',
|
||||
]);
|
||||
|
||||
Reference in New Issue
Block a user