Stop workflow in any status (#17271)
Workflows can now be cancelled when not started or enqueued. Also displaying the stop option when selecting all. We got the case of a client that did an infinite loop. So he had a lot of workflows to stop. Supporting select all would have avoid him to wait for 4 hours so we process the runs throttled. This is not something that is supposed to happen often so I did not see the point of refactoring the endpoint. But I wanted the users to have this option just in case
This commit is contained in:
+7
-2
@@ -60,8 +60,13 @@ export const WORKFLOW_RUNS_ACTIONS_CONFIG = inheritActionsFromDefaultConfig({
|
||||
type: ActionType.Standard,
|
||||
scope: ActionScope.RecordSelection,
|
||||
Icon: IconPlayerStop,
|
||||
shouldBeRegistered: ({ selectedRecord }) => {
|
||||
return selectedRecord?.status === 'RUNNING';
|
||||
shouldBeRegistered: ({ selectedRecord, isSelectAll }) => {
|
||||
if (isSelectAll === true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const stoppableStatuses = ['NOT_STARTED', 'ENQUEUED', 'RUNNING'];
|
||||
return stoppableStatuses.includes(selectedRecord?.status);
|
||||
},
|
||||
availableOn: [
|
||||
ActionViewType.SHOW_PAGE,
|
||||
|
||||
+50
-10
@@ -1,27 +1,67 @@
|
||||
import { Action } from '@/action-menu/actions/components/Action';
|
||||
import { contextStoreAnyFieldFilterValueComponentState } from '@/context-store/states/contextStoreAnyFieldFilterValueComponentState';
|
||||
import { contextStoreFilterGroupsComponentState } from '@/context-store/states/contextStoreFilterGroupsComponentState';
|
||||
import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState';
|
||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
import { computeContextStoreFilters } from '@/context-store/utils/computeContextStoreFilters';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { DEFAULT_QUERY_PAGE_SIZE } from '@/object-record/constants/DefaultQueryPageSize';
|
||||
import { useLazyFetchAllRecords } from '@/object-record/hooks/useLazyFetchAllRecords';
|
||||
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
||||
import { useRecordIndexIdFromCurrentContextStore } from '@/object-record/record-index/hooks/useRecordIndexIdFromCurrentContextStore';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { useStopWorkflowRun } from '@/workflow/hooks/useStopWorkflowRun';
|
||||
|
||||
export const StopWorkflowRunSingleRecordAction = () => {
|
||||
const { objectMetadataItem } = useRecordIndexIdFromCurrentContextStore();
|
||||
|
||||
const contextStoreTargetedRecordsRule = useRecoilComponentValue(
|
||||
contextStoreTargetedRecordsRuleComponentState,
|
||||
);
|
||||
|
||||
if (
|
||||
contextStoreTargetedRecordsRule.mode === 'exclusion' ||
|
||||
(contextStoreTargetedRecordsRule.mode === 'selection' &&
|
||||
contextStoreTargetedRecordsRule.selectedRecordIds.length === 0)
|
||||
) {
|
||||
throw new Error('Selected record ID is required');
|
||||
}
|
||||
const contextStoreFilters = useRecoilComponentValue(
|
||||
contextStoreFiltersComponentState,
|
||||
);
|
||||
|
||||
const contextStoreFilterGroups = useRecoilComponentValue(
|
||||
contextStoreFilterGroupsComponentState,
|
||||
);
|
||||
|
||||
const contextStoreAnyFieldFilterValue = useRecoilComponentValue(
|
||||
contextStoreAnyFieldFilterValueComponentState,
|
||||
);
|
||||
|
||||
const { filterValueDependencies } = useFilterValueDependencies();
|
||||
|
||||
const graphqlFilter = computeContextStoreFilters({
|
||||
contextStoreTargetedRecordsRule,
|
||||
contextStoreFilters,
|
||||
contextStoreFilterGroups,
|
||||
objectMetadataItem,
|
||||
filterValueDependencies,
|
||||
contextStoreAnyFieldFilterValue,
|
||||
});
|
||||
|
||||
const { fetchAllRecords: fetchAllRecordIds } = useLazyFetchAllRecords({
|
||||
objectNameSingular: CoreObjectNameSingular.WorkflowRun,
|
||||
filter: graphqlFilter,
|
||||
limit: DEFAULT_QUERY_PAGE_SIZE,
|
||||
recordGqlFields: { id: true },
|
||||
});
|
||||
|
||||
const selectedRecordIds = contextStoreTargetedRecordsRule.selectedRecordIds;
|
||||
const { stopWorkflowRun } = useStopWorkflowRun();
|
||||
|
||||
const handleClick = async () => {
|
||||
for (const selectedRecordId of selectedRecordIds) {
|
||||
await stopWorkflowRun(selectedRecordId);
|
||||
if (contextStoreTargetedRecordsRule.mode === 'selection') {
|
||||
for (const selectedRecordId of contextStoreTargetedRecordsRule.selectedRecordIds) {
|
||||
await stopWorkflowRun(selectedRecordId);
|
||||
}
|
||||
} else {
|
||||
const records = await fetchAllRecordIds();
|
||||
|
||||
for (const record of records) {
|
||||
await stopWorkflowRun(record.id);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+2
@@ -15,6 +15,8 @@ export type ShouldBeRegisteredFunctionParams = {
|
||||
isFavorite?: boolean;
|
||||
isRemote?: boolean;
|
||||
isNoteOrTask?: boolean;
|
||||
isSelectAll?: boolean;
|
||||
loadedRecords?: ObjectRecord[];
|
||||
selectedRecord?: ObjectRecord;
|
||||
numberOfSelectedRecords?: number;
|
||||
workflowWithCurrentVersion?: WorkflowWithCurrentVersion;
|
||||
|
||||
+3
@@ -73,6 +73,8 @@ export const useShouldActionBeRegisteredParams = ({
|
||||
contextStoreTargetedRecordsRule,
|
||||
);
|
||||
|
||||
const isSelectAll = contextStoreTargetedRecordsRule.mode === 'exclusion';
|
||||
|
||||
const getObjectReadPermission = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
(objectMetadataNameSingular: string) => {
|
||||
@@ -113,6 +115,7 @@ export const useShouldActionBeRegisteredParams = ({
|
||||
isInRightDrawer,
|
||||
hasAnySoftDeleteFilterOnView,
|
||||
isShowPage,
|
||||
isSelectAll,
|
||||
selectedRecord,
|
||||
numberOfSelectedRecords,
|
||||
viewType: viewType ?? undefined,
|
||||
|
||||
@@ -80,6 +80,13 @@ export class RunWorkflowJob {
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
if (
|
||||
workflowRun.status !== WorkflowRunStatus.ENQUEUED &&
|
||||
workflowRun.status !== WorkflowRunStatus.NOT_STARTED
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const workflowVersion =
|
||||
await this.workflowCommonWorkspaceService.getWorkflowVersionOrFail({
|
||||
workspaceId,
|
||||
|
||||
+4
-1
@@ -156,7 +156,10 @@ export class WorkflowRunWorkspaceService {
|
||||
workflowRunToUpdate.status !== WorkflowRunStatus.ENQUEUED &&
|
||||
workflowRunToUpdate.status !== WorkflowRunStatus.NOT_STARTED
|
||||
) {
|
||||
return;
|
||||
throw new WorkflowRunException(
|
||||
'Workflow run is not enqueued or not started',
|
||||
WorkflowRunExceptionCode.INVALID_OPERATION,
|
||||
);
|
||||
}
|
||||
|
||||
const partialUpdate = {
|
||||
|
||||
+9
-3
@@ -200,12 +200,18 @@ export class WorkflowRunnerWorkspaceService {
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
if (workflowRun.status !== WorkflowRunStatus.RUNNING) {
|
||||
const stoppableStatuses = [
|
||||
WorkflowRunStatus.NOT_STARTED,
|
||||
WorkflowRunStatus.ENQUEUED,
|
||||
WorkflowRunStatus.RUNNING,
|
||||
];
|
||||
|
||||
if (!stoppableStatuses.includes(workflowRun.status)) {
|
||||
throw new WorkflowRunException(
|
||||
'Workflow run is not running',
|
||||
'Workflow run cannot be stopped',
|
||||
WorkflowRunExceptionCode.INVALID_OPERATION,
|
||||
{
|
||||
userFriendlyMessage: msg`Workflow run is not running`,
|
||||
userFriendlyMessage: msg`Workflow run cannot be stopped in its current status`,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user