mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-24 20:24:05 -08:00
fix: Stop listening button not working in NDV (#9023)
This commit is contained in:
parent
e2bde6b751
commit
02219dde2f
|
@ -658,4 +658,18 @@ describe('NDV', () => {
|
||||||
cy.realPress('Escape');
|
cy.realPress('Escape');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Stop listening for trigger event from NDV', () => {
|
||||||
|
workflowPage.actions.addInitialNodeToCanvas('Local File Trigger', {
|
||||||
|
keepNdvOpen: true,
|
||||||
|
action: 'On Changes To A Specific File',
|
||||||
|
isTrigger: true,
|
||||||
|
});
|
||||||
|
ndv.getters.triggerPanelExecuteButton().should('exist');
|
||||||
|
ndv.getters.triggerPanelExecuteButton().click();
|
||||||
|
ndv.getters.triggerPanelExecuteButton().should('contain', 'Stop Listening');
|
||||||
|
ndv.getters.triggerPanelExecuteButton().click();
|
||||||
|
ndv.getters.triggerPanelExecuteButton().should('contain', 'Test step');
|
||||||
|
workflowPage.getters.successToast().should('exist');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -145,19 +145,20 @@ export class WorkflowPage extends BasePage {
|
||||||
},
|
},
|
||||||
addInitialNodeToCanvas: (
|
addInitialNodeToCanvas: (
|
||||||
nodeDisplayName: string,
|
nodeDisplayName: string,
|
||||||
opts?: { keepNdvOpen?: boolean; action?: string },
|
opts?: { keepNdvOpen?: boolean; action?: string, isTrigger?: boolean},
|
||||||
) => {
|
) => {
|
||||||
this.getters.canvasPlusButton().click();
|
this.getters.canvasPlusButton().click();
|
||||||
this.getters.nodeCreatorSearchBar().type(nodeDisplayName);
|
this.getters.nodeCreatorSearchBar().type(nodeDisplayName);
|
||||||
this.getters.nodeCreatorSearchBar().type('{enter}');
|
this.getters.nodeCreatorSearchBar().type('{enter}');
|
||||||
if (opts?.action) {
|
if (opts?.action) {
|
||||||
|
const itemId = opts.isTrigger ? 'Triggers' : 'Actions';
|
||||||
// Expand actions category if it's collapsed
|
// Expand actions category if it's collapsed
|
||||||
nodeCreator.getters
|
nodeCreator.getters
|
||||||
.getCategoryItem('Actions')
|
.getCategoryItem(itemId)
|
||||||
.parent()
|
.parent()
|
||||||
.then(($el) => {
|
.then(($el) => {
|
||||||
if ($el.attr('data-category-collapsed') === 'true') {
|
if ($el.attr('data-category-collapsed') === 'true') {
|
||||||
nodeCreator.getters.getCategoryItem('Actions').click();
|
nodeCreator.getters.getCategoryItem(itemId).click();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
nodeCreator.getters.getCreatorItem(opts.action).click();
|
nodeCreator.getters.getCreatorItem(opts.action).click();
|
||||||
|
|
|
@ -77,18 +77,20 @@ export default defineComponent({
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
emits: ['stopExecution', 'execute'],
|
||||||
setup(props) {
|
setup(props) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const workflowsStore = useWorkflowsStore();
|
const workflowsStore = useWorkflowsStore();
|
||||||
const node = workflowsStore.getNodeByName(props.nodeName);
|
const node = workflowsStore.getNodeByName(props.nodeName);
|
||||||
const pinnedData = usePinnedData(node);
|
const pinnedData = usePinnedData(node);
|
||||||
const externalHooks = useExternalHooks();
|
const externalHooks = useExternalHooks();
|
||||||
const { runWorkflow } = useRunWorkflow({ router });
|
const { runWorkflow, stopCurrentExecution } = useRunWorkflow({ router });
|
||||||
|
|
||||||
return {
|
return {
|
||||||
externalHooks,
|
externalHooks,
|
||||||
pinnedData,
|
pinnedData,
|
||||||
runWorkflow,
|
runWorkflow,
|
||||||
|
stopCurrentExecution,
|
||||||
...useToast(),
|
...useToast(),
|
||||||
...useMessage(),
|
...useMessage(),
|
||||||
};
|
};
|
||||||
|
@ -236,6 +238,7 @@ export default defineComponent({
|
||||||
} else if (this.isListeningForEvents) {
|
} else if (this.isListeningForEvents) {
|
||||||
await this.stopWaitingForWebhook();
|
await this.stopWaitingForWebhook();
|
||||||
} else if (this.isListeningForWorkflowEvents) {
|
} else if (this.isListeningForWorkflowEvents) {
|
||||||
|
await this.stopCurrentExecution();
|
||||||
this.$emit('stopExecution');
|
this.$emit('stopExecution');
|
||||||
} else {
|
} else {
|
||||||
let shouldUnpinAndExecute = false;
|
let shouldUnpinAndExecute = false;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import type {
|
import type {
|
||||||
IExecutionPushResponse,
|
IExecutionPushResponse,
|
||||||
IExecutionResponse,
|
IExecutionResponse,
|
||||||
|
IPushDataExecutionFinished,
|
||||||
IStartRunData,
|
IStartRunData,
|
||||||
IWorkflowDb,
|
IWorkflowDb,
|
||||||
} from '@/Interface';
|
} from '@/Interface';
|
||||||
|
@ -13,6 +14,7 @@ import type {
|
||||||
IWorkflowBase,
|
IWorkflowBase,
|
||||||
Workflow,
|
Workflow,
|
||||||
StartNodeData,
|
StartNodeData,
|
||||||
|
IRun,
|
||||||
} from 'n8n-workflow';
|
} from 'n8n-workflow';
|
||||||
import {
|
import {
|
||||||
NodeHelpers,
|
NodeHelpers,
|
||||||
|
@ -449,9 +451,67 @@ export function useRunWorkflow(options: { router: ReturnType<typeof useRouter> }
|
||||||
return { runData: newRunData, startNodeNames };
|
return { runData: newRunData, startNodeNames };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function stopCurrentExecution() {
|
||||||
|
const executionId = workflowsStore.activeExecutionId;
|
||||||
|
if (executionId === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await workflowsStore.stopCurrentExecution(executionId);
|
||||||
|
} catch (error) {
|
||||||
|
// Execution stop might fail when the execution has already finished. Let's treat this here.
|
||||||
|
const execution = await this.workflowsStore.getExecution(executionId);
|
||||||
|
|
||||||
|
if (execution === undefined) {
|
||||||
|
// execution finished but was not saved (e.g. due to low connectivity)
|
||||||
|
workflowsStore.finishActiveExecution({
|
||||||
|
executionId,
|
||||||
|
data: { finished: true, stoppedAt: new Date() },
|
||||||
|
});
|
||||||
|
workflowsStore.executingNode.length = 0;
|
||||||
|
uiStore.removeActiveAction('workflowRunning');
|
||||||
|
|
||||||
|
titleSet(workflowsStore.workflowName, 'IDLE');
|
||||||
|
toast.showMessage({
|
||||||
|
title: i18n.baseText('nodeView.showMessage.stopExecutionCatch.unsaved.title'),
|
||||||
|
message: i18n.baseText('nodeView.showMessage.stopExecutionCatch.unsaved.message'),
|
||||||
|
type: 'success',
|
||||||
|
});
|
||||||
|
} else if (execution?.finished) {
|
||||||
|
// execution finished before it could be stopped
|
||||||
|
const executedData = {
|
||||||
|
data: execution.data,
|
||||||
|
finished: execution.finished,
|
||||||
|
mode: execution.mode,
|
||||||
|
startedAt: execution.startedAt,
|
||||||
|
stoppedAt: execution.stoppedAt,
|
||||||
|
} as IRun;
|
||||||
|
const pushData = {
|
||||||
|
data: executedData,
|
||||||
|
executionId,
|
||||||
|
retryOf: execution.retryOf,
|
||||||
|
} as IPushDataExecutionFinished;
|
||||||
|
workflowsStore.finishActiveExecution(pushData);
|
||||||
|
titleSet(execution.workflowData.name, 'IDLE');
|
||||||
|
workflowsStore.executingNode.length = 0;
|
||||||
|
workflowsStore.setWorkflowExecutionData(executedData as IExecutionResponse);
|
||||||
|
uiStore.removeActiveAction('workflowRunning');
|
||||||
|
toast.showMessage({
|
||||||
|
title: i18n.baseText('nodeView.showMessage.stopExecutionCatch.title'),
|
||||||
|
message: i18n.baseText('nodeView.showMessage.stopExecutionCatch.message'),
|
||||||
|
type: 'success',
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
toast.showError(error, i18n.baseText('nodeView.showError.stopExecution.title'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
consolidateRunDataAndStartNodes,
|
consolidateRunDataAndStartNodes,
|
||||||
runWorkflow,
|
runWorkflow,
|
||||||
runWorkflowApi,
|
runWorkflowApi,
|
||||||
|
stopCurrentExecution,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -279,7 +279,6 @@ import type {
|
||||||
INodeTypeDescription,
|
INodeTypeDescription,
|
||||||
INodeTypeNameVersion,
|
INodeTypeNameVersion,
|
||||||
IPinData,
|
IPinData,
|
||||||
IRun,
|
|
||||||
ITaskData,
|
ITaskData,
|
||||||
ITelemetryTrackProperties,
|
ITelemetryTrackProperties,
|
||||||
IWorkflowBase,
|
IWorkflowBase,
|
||||||
|
@ -303,7 +302,6 @@ import type {
|
||||||
IUpdateInformation,
|
IUpdateInformation,
|
||||||
IWorkflowDataUpdate,
|
IWorkflowDataUpdate,
|
||||||
XYPosition,
|
XYPosition,
|
||||||
IPushDataExecutionFinished,
|
|
||||||
ITag,
|
ITag,
|
||||||
INewWorkflowData,
|
INewWorkflowData,
|
||||||
IWorkflowTemplate,
|
IWorkflowTemplate,
|
||||||
|
@ -492,7 +490,7 @@ export default defineComponent({
|
||||||
const { callDebounced } = useDebounce();
|
const { callDebounced } = useDebounce();
|
||||||
const canvasPanning = useCanvasPanning(nodeViewRootRef, { onMouseMoveEnd });
|
const canvasPanning = useCanvasPanning(nodeViewRootRef, { onMouseMoveEnd });
|
||||||
const workflowHelpers = useWorkflowHelpers({ router });
|
const workflowHelpers = useWorkflowHelpers({ router });
|
||||||
const { runWorkflow } = useRunWorkflow({ router });
|
const { runWorkflow, stopCurrentExecution } = useRunWorkflow({ router });
|
||||||
|
|
||||||
return {
|
return {
|
||||||
locale,
|
locale,
|
||||||
|
@ -509,6 +507,7 @@ export default defineComponent({
|
||||||
onMouseMoveEnd,
|
onMouseMoveEnd,
|
||||||
workflowHelpers,
|
workflowHelpers,
|
||||||
runWorkflow,
|
runWorkflow,
|
||||||
|
stopCurrentExecution,
|
||||||
callDebounced,
|
callDebounced,
|
||||||
...useCanvasMouseSelect(),
|
...useCanvasMouseSelect(),
|
||||||
...useGlobalLinkActions(),
|
...useGlobalLinkActions(),
|
||||||
|
@ -1930,67 +1929,8 @@ export default defineComponent({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
async stopExecution() {
|
async stopExecution() {
|
||||||
const executionId = this.workflowsStore.activeExecutionId;
|
await this.stopCurrentExecution();
|
||||||
if (executionId === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
this.stopExecutionInProgress = true;
|
|
||||||
await this.workflowsStore.stopCurrentExecution(executionId);
|
|
||||||
} catch (error) {
|
|
||||||
// Execution stop might fail when the execution has already finished. Let's treat this here.
|
|
||||||
const execution = await this.workflowsStore.getExecution(executionId);
|
|
||||||
|
|
||||||
if (execution === undefined) {
|
|
||||||
// execution finished but was not saved (e.g. due to low connectivity)
|
|
||||||
|
|
||||||
this.workflowsStore.finishActiveExecution({
|
|
||||||
executionId,
|
|
||||||
data: { finished: true, stoppedAt: new Date() },
|
|
||||||
});
|
|
||||||
this.workflowsStore.executingNode.length = 0;
|
|
||||||
this.uiStore.removeActiveAction('workflowRunning');
|
|
||||||
|
|
||||||
this.titleSet(this.workflowsStore.workflowName, 'IDLE');
|
|
||||||
this.showMessage({
|
|
||||||
title: this.$locale.baseText('nodeView.showMessage.stopExecutionCatch.unsaved.title'),
|
|
||||||
message: this.$locale.baseText(
|
|
||||||
'nodeView.showMessage.stopExecutionCatch.unsaved.message',
|
|
||||||
),
|
|
||||||
type: 'success',
|
|
||||||
});
|
|
||||||
} else if (execution?.finished) {
|
|
||||||
// execution finished before it could be stopped
|
|
||||||
|
|
||||||
const executedData = {
|
|
||||||
data: execution.data,
|
|
||||||
finished: execution.finished,
|
|
||||||
mode: execution.mode,
|
|
||||||
startedAt: execution.startedAt,
|
|
||||||
stoppedAt: execution.stoppedAt,
|
|
||||||
} as IRun;
|
|
||||||
const pushData = {
|
|
||||||
data: executedData,
|
|
||||||
executionId,
|
|
||||||
retryOf: execution.retryOf,
|
|
||||||
} as IPushDataExecutionFinished;
|
|
||||||
this.workflowsStore.finishActiveExecution(pushData);
|
|
||||||
this.titleSet(execution.workflowData.name, 'IDLE');
|
|
||||||
this.workflowsStore.executingNode.length = 0;
|
|
||||||
this.workflowsStore.setWorkflowExecutionData(executedData as IExecutionResponse);
|
|
||||||
this.uiStore.removeActiveAction('workflowRunning');
|
|
||||||
this.showMessage({
|
|
||||||
title: this.$locale.baseText('nodeView.showMessage.stopExecutionCatch.title'),
|
|
||||||
message: this.$locale.baseText('nodeView.showMessage.stopExecutionCatch.message'),
|
|
||||||
type: 'success',
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.showError(error, this.$locale.baseText('nodeView.showError.stopExecution.title'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.stopExecutionInProgress = false;
|
this.stopExecutionInProgress = false;
|
||||||
|
|
||||||
void this.workflowHelpers.getWorkflowDataToSave().then((workflowData) => {
|
void this.workflowHelpers.getWorkflowDataToSave().then((workflowData) => {
|
||||||
const trackProps = {
|
const trackProps = {
|
||||||
workflow_id: this.workflowsStore.workflowId,
|
workflow_id: this.workflowsStore.workflowId,
|
||||||
|
|
Loading…
Reference in a new issue