mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-25 20:54:07 -08:00
fix(editor): Fix route component caching, incorrect use of array reduce method and enable WF history feature (#7434)
Co-authored-by: Giulio Andreini <andreini@netseven.it>
This commit is contained in:
parent
ae616f146b
commit
12a89e6d14
151
cypress/e2e/30-editor-after-route-changes.cy.ts
Normal file
151
cypress/e2e/30-editor-after-route-changes.cy.ts
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
import {
|
||||||
|
CODE_NODE_NAME,
|
||||||
|
EDIT_FIELDS_SET_NODE_NAME,
|
||||||
|
IF_NODE_NAME,
|
||||||
|
INSTANCE_OWNER,
|
||||||
|
SCHEDULE_TRIGGER_NODE_NAME,
|
||||||
|
} from '../constants';
|
||||||
|
import {
|
||||||
|
WorkflowExecutionsTab,
|
||||||
|
WorkflowPage as WorkflowPageClass,
|
||||||
|
WorkflowHistoryPage,
|
||||||
|
} from '../pages';
|
||||||
|
|
||||||
|
const workflowPage = new WorkflowPageClass();
|
||||||
|
const executionsTab = new WorkflowExecutionsTab();
|
||||||
|
const workflowHistoryPage = new WorkflowHistoryPage();
|
||||||
|
|
||||||
|
const createNewWorkflowAndActivate = () => {
|
||||||
|
workflowPage.actions.visit();
|
||||||
|
workflowPage.actions.addNodeToCanvas(SCHEDULE_TRIGGER_NODE_NAME);
|
||||||
|
workflowPage.actions.saveWorkflowOnButtonClick();
|
||||||
|
workflowPage.actions.activateWorkflow();
|
||||||
|
cy.get('.el-notification .el-notification--error').should('not.exist');
|
||||||
|
};
|
||||||
|
|
||||||
|
const editWorkflowAndDeactivate = () => {
|
||||||
|
workflowPage.getters.canvasNodePlusEndpointByName(SCHEDULE_TRIGGER_NODE_NAME).click();
|
||||||
|
workflowPage.getters.nodeCreatorSearchBar().should('be.visible');
|
||||||
|
workflowPage.actions.addNodeToCanvas(EDIT_FIELDS_SET_NODE_NAME, false);
|
||||||
|
cy.get('.jtk-connector').should('have.length', 1);
|
||||||
|
workflowPage.actions.saveWorkflowOnButtonClick();
|
||||||
|
workflowPage.getters.activatorSwitch().click();
|
||||||
|
workflowPage.actions.zoomToFit();
|
||||||
|
cy.get('.el-notification .el-notification--error').should('not.exist');
|
||||||
|
};
|
||||||
|
|
||||||
|
const editWorkflowMoreAndActivate = () => {
|
||||||
|
cy.drag(workflowPage.getters.getEndpointSelector('plus', EDIT_FIELDS_SET_NODE_NAME), [200, 200], {
|
||||||
|
realMouse: true,
|
||||||
|
});
|
||||||
|
workflowPage.getters.nodeCreatorSearchBar().should('be.visible');
|
||||||
|
|
||||||
|
workflowPage.actions.addNodeToCanvas(CODE_NODE_NAME, false);
|
||||||
|
workflowPage.getters.nodeViewBackground().click(600, 200, { force: true });
|
||||||
|
cy.get('.jtk-connector').should('have.length', 2);
|
||||||
|
workflowPage.actions.zoomToFit();
|
||||||
|
workflowPage.actions.saveWorkflowOnButtonClick();
|
||||||
|
|
||||||
|
workflowPage.actions.addNodeToCanvas(IF_NODE_NAME);
|
||||||
|
workflowPage.getters.nodeViewBackground().click(600, 200, { force: true });
|
||||||
|
cy.get('.jtk-connector').should('have.length', 2);
|
||||||
|
|
||||||
|
const position = {
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
};
|
||||||
|
workflowPage.getters
|
||||||
|
.canvasNodeByName(IF_NODE_NAME)
|
||||||
|
.click()
|
||||||
|
.then(($element) => {
|
||||||
|
position.top = $element.position().top;
|
||||||
|
position.left = $element.position().left;
|
||||||
|
});
|
||||||
|
|
||||||
|
cy.drag('[data-test-id="canvas-node"].jtk-drag-selected', [50, 200], { clickToFinish: true });
|
||||||
|
workflowPage.getters
|
||||||
|
.canvasNodes()
|
||||||
|
.last()
|
||||||
|
.then(($element) => {
|
||||||
|
const finalPosition = {
|
||||||
|
top: $element.position().top,
|
||||||
|
left: $element.position().left,
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(finalPosition.top).to.be.greaterThan(position.top);
|
||||||
|
expect(finalPosition.left).to.be.greaterThan(position.left);
|
||||||
|
});
|
||||||
|
|
||||||
|
cy.draganddrop(
|
||||||
|
workflowPage.getters.getEndpointSelector('output', CODE_NODE_NAME),
|
||||||
|
workflowPage.getters.getEndpointSelector('input', IF_NODE_NAME),
|
||||||
|
);
|
||||||
|
cy.get('.jtk-connector').should('have.length', 3);
|
||||||
|
|
||||||
|
workflowPage.actions.saveWorkflowOnButtonClick();
|
||||||
|
workflowPage.getters.activatorSwitch().click();
|
||||||
|
cy.get('.el-notification .el-notification--error').should('not.exist');
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('Editor actions should work', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.enableFeature('debugInEditor');
|
||||||
|
cy.enableFeature('workflowHistory');
|
||||||
|
cy.signin({ email: INSTANCE_OWNER.email, password: INSTANCE_OWNER.password });
|
||||||
|
createNewWorkflowAndActivate();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('after saving a new workflow', () => {
|
||||||
|
editWorkflowAndDeactivate();
|
||||||
|
editWorkflowMoreAndActivate();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('after switching between Editor and Executions', () => {
|
||||||
|
cy.intercept('GET', '/rest/executions?filter=*').as('getExecutions');
|
||||||
|
cy.intercept('GET', '/rest/executions-current?filter=*').as('getCurrentExecutions');
|
||||||
|
|
||||||
|
executionsTab.actions.switchToExecutionsTab();
|
||||||
|
cy.wait(['@getExecutions', '@getCurrentExecutions']);
|
||||||
|
cy.wait(500);
|
||||||
|
executionsTab.actions.switchToEditorTab();
|
||||||
|
editWorkflowAndDeactivate();
|
||||||
|
editWorkflowMoreAndActivate();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('after switching between Editor and Debug', () => {
|
||||||
|
cy.intercept('GET', '/rest/executions?filter=*').as('getExecutions');
|
||||||
|
cy.intercept('GET', '/rest/executions/*').as('getExecution');
|
||||||
|
cy.intercept('GET', '/rest/executions-current?filter=*').as('getCurrentExecutions');
|
||||||
|
cy.intercept('POST', '/rest/workflows/run').as('postWorkflowRun');
|
||||||
|
|
||||||
|
editWorkflowAndDeactivate();
|
||||||
|
workflowPage.actions.executeWorkflow();
|
||||||
|
cy.wait(['@postWorkflowRun']);
|
||||||
|
|
||||||
|
executionsTab.actions.switchToExecutionsTab();
|
||||||
|
cy.wait(['@getExecutions', '@getCurrentExecutions']);
|
||||||
|
|
||||||
|
executionsTab.getters.executionListItems().should('have.length', 1).first().click();
|
||||||
|
cy.wait(['@getExecution']);
|
||||||
|
|
||||||
|
executionsTab.getters.executionDebugButton().should('have.text', 'Copy to editor').click();
|
||||||
|
editWorkflowMoreAndActivate();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('after switching between Editor and Workflow history', () => {
|
||||||
|
cy.intercept('GET', '/rest/workflow-history/workflow/*/version/*').as('getVersion');
|
||||||
|
cy.intercept('GET', '/rest/workflow-history/workflow/*').as('getHistory');
|
||||||
|
|
||||||
|
editWorkflowAndDeactivate();
|
||||||
|
workflowPage.getters.workflowHistoryButton().click();
|
||||||
|
cy.wait(['@getHistory']);
|
||||||
|
cy.wait(['@getVersion']);
|
||||||
|
|
||||||
|
cy.intercept('GET', '/rest/workflows/*').as('workflowGet');
|
||||||
|
workflowHistoryPage.getters.workflowHistoryCloseButton().click();
|
||||||
|
cy.wait(['@workflowGet']);
|
||||||
|
cy.wait(1000);
|
||||||
|
|
||||||
|
editWorkflowMoreAndActivate();
|
||||||
|
});
|
||||||
|
});
|
|
@ -10,3 +10,4 @@ export * from './ndv';
|
||||||
export * from './bannerStack';
|
export * from './bannerStack';
|
||||||
export * from './workflow-executions-tab';
|
export * from './workflow-executions-tab';
|
||||||
export * from './signin';
|
export * from './signin';
|
||||||
|
export * from './workflow-history';
|
||||||
|
|
7
cypress/pages/workflow-history.ts
Normal file
7
cypress/pages/workflow-history.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import { BasePage } from "./base";
|
||||||
|
|
||||||
|
export class WorkflowHistoryPage extends BasePage {
|
||||||
|
getters = {
|
||||||
|
workflowHistoryCloseButton: () => cy.getByTestId('workflow-history-close-button'),
|
||||||
|
}
|
||||||
|
}
|
|
@ -124,6 +124,7 @@ export class WorkflowPage extends BasePage {
|
||||||
addStickyButton: () => cy.getByTestId('add-sticky-button'),
|
addStickyButton: () => cy.getByTestId('add-sticky-button'),
|
||||||
stickies: () => cy.getByTestId('sticky'),
|
stickies: () => cy.getByTestId('sticky'),
|
||||||
editorTabButton: () => cy.getByTestId('radio-button-workflow'),
|
editorTabButton: () => cy.getByTestId('radio-button-workflow'),
|
||||||
|
workflowHistoryButton: () => cy.getByTestId('workflow-history-button'),
|
||||||
};
|
};
|
||||||
actions = {
|
actions = {
|
||||||
visit: (preventNodeViewUnload = true) => {
|
visit: (preventNodeViewUnload = true) => {
|
||||||
|
|
|
@ -20,9 +20,10 @@
|
||||||
</div>
|
</div>
|
||||||
<div id="content" :class="$style.content">
|
<div id="content" :class="$style.content">
|
||||||
<router-view v-slot="{ Component }">
|
<router-view v-slot="{ Component }">
|
||||||
<keep-alive include="NodeView" :max="1">
|
<keep-alive v-if="$route.meta.keepWorkflowAlive" include="NodeView" :max="1">
|
||||||
<component :is="Component" />
|
<component :is="Component" />
|
||||||
</keep-alive>
|
</keep-alive>
|
||||||
|
<component v-else :is="Component" />
|
||||||
</router-view>
|
</router-view>
|
||||||
</div>
|
</div>
|
||||||
<Modals />
|
<Modals />
|
||||||
|
@ -257,7 +258,7 @@ export default defineComponent({
|
||||||
void this.postAuthenticate();
|
void this.postAuthenticate();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async $route(route) {
|
async $route() {
|
||||||
await this.initSettings();
|
await this.initSettings();
|
||||||
await this.redirectIfNecessary();
|
await this.redirectIfNecessary();
|
||||||
|
|
||||||
|
|
|
@ -108,6 +108,7 @@
|
||||||
>
|
>
|
||||||
<n8n-icon-button
|
<n8n-icon-button
|
||||||
:disabled="isWorkflowHistoryButtonDisabled"
|
:disabled="isWorkflowHistoryButtonDisabled"
|
||||||
|
data-test-id="workflow-history-button"
|
||||||
type="tertiary"
|
type="tertiary"
|
||||||
icon="history"
|
icon="history"
|
||||||
size="medium"
|
size="medium"
|
||||||
|
@ -349,9 +350,8 @@ export default defineComponent({
|
||||||
return actions;
|
return actions;
|
||||||
},
|
},
|
||||||
isWorkflowHistoryFeatureEnabled(): boolean {
|
isWorkflowHistoryFeatureEnabled(): boolean {
|
||||||
return (
|
return this.settingsStore.isEnterpriseFeatureEnabled(
|
||||||
this.settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.WorkflowHistory) &&
|
EnterpriseEditionFeature.WorkflowHistory,
|
||||||
this.settingsStore.isDevRelease
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
workflowHistoryRoute(): { name: string; params: { workflowId: string } } {
|
workflowHistoryRoute(): { name: string; params: { workflowId: string } } {
|
||||||
|
|
|
@ -17,6 +17,7 @@ const props = defineProps<{
|
||||||
workflowVersion: WorkflowVersion | null;
|
workflowVersion: WorkflowVersion | null;
|
||||||
actions: UserAction[];
|
actions: UserAction[];
|
||||||
isListLoading?: boolean;
|
isListLoading?: boolean;
|
||||||
|
isFirstItemShown?: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
|
@ -42,6 +43,12 @@ const workflowVersionPreview = computed<IWorkflowDb | undefined>(() => {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const actions = computed(() =>
|
||||||
|
props.isFirstItemShown
|
||||||
|
? props.actions.filter((action) => action.value !== 'restore')
|
||||||
|
: props.actions,
|
||||||
|
);
|
||||||
|
|
||||||
const onAction = ({
|
const onAction = ({
|
||||||
action,
|
action,
|
||||||
id,
|
id,
|
||||||
|
@ -67,11 +74,10 @@ const onAction = ({
|
||||||
<workflow-history-list-item
|
<workflow-history-list-item
|
||||||
:class="$style.card"
|
:class="$style.card"
|
||||||
v-if="props.workflowVersion"
|
v-if="props.workflowVersion"
|
||||||
:full="true"
|
|
||||||
:index="-1"
|
:index="-1"
|
||||||
:item="props.workflowVersion"
|
:item="props.workflowVersion"
|
||||||
:isActive="false"
|
:isActive="false"
|
||||||
:actions="props.actions"
|
:actions="actions"
|
||||||
@action="onAction"
|
@action="onAction"
|
||||||
>
|
>
|
||||||
<template #default="{ formattedCreatedAt }">
|
<template #default="{ formattedCreatedAt }">
|
||||||
|
@ -99,7 +105,7 @@ const onAction = ({
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
<template #action-toggle-button>
|
<template #action-toggle-button>
|
||||||
<n8n-button type="tertiary" size="small" data-test-id="action-toggle-button">
|
<n8n-button type="tertiary" size="large" data-test-id="action-toggle-button">
|
||||||
{{ i18n.baseText('workflowHistory.content.actions') }}
|
{{ i18n.baseText('workflowHistory.content.actions') }}
|
||||||
<n8n-icon class="ml-3xs" icon="chevron-down" size="small" />
|
<n8n-icon class="ml-3xs" icon="chevron-down" size="small" />
|
||||||
</n8n-button>
|
</n8n-button>
|
||||||
|
@ -146,8 +152,9 @@ const onAction = ({
|
||||||
|
|
||||||
&:first-child {
|
&:first-child {
|
||||||
padding-top: var(--spacing-3xs);
|
padding-top: var(--spacing-3xs);
|
||||||
padding-bottom: var(--spacing-3xs);
|
padding-bottom: var(--spacing-4xs);
|
||||||
* {
|
* {
|
||||||
|
margin-top: auto;
|
||||||
font-size: var(--font-size-m);
|
font-size: var(--font-size-m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,6 +168,7 @@ const onAction = ({
|
||||||
}
|
}
|
||||||
|
|
||||||
.label {
|
.label {
|
||||||
|
color: var(--color-text-light);
|
||||||
padding-right: var(--spacing-4xs);
|
padding-right: var(--spacing-4xs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,9 @@ const listElement = ref<Element | null>(null);
|
||||||
const shouldAutoScroll = ref(true);
|
const shouldAutoScroll = ref(true);
|
||||||
const observer = ref<IntersectionObserver | null>(null);
|
const observer = ref<IntersectionObserver | null>(null);
|
||||||
|
|
||||||
|
const getActions = (index: number) =>
|
||||||
|
index === 0 ? props.actions.filter((action) => action.value !== 'restore') : props.actions;
|
||||||
|
|
||||||
const observeElement = (element: Element) => {
|
const observeElement = (element: Element) => {
|
||||||
observer.value = new IntersectionObserver(
|
observer.value = new IntersectionObserver(
|
||||||
([entry]) => {
|
([entry]) => {
|
||||||
|
@ -109,7 +112,7 @@ const onItemMounted = ({
|
||||||
:index="index"
|
:index="index"
|
||||||
:item="item"
|
:item="item"
|
||||||
:isActive="item.versionId === props.activeItem?.versionId"
|
:isActive="item.versionId === props.activeItem?.versionId"
|
||||||
:actions="props.actions"
|
:actions="getActions(index)"
|
||||||
@action="onAction"
|
@action="onAction"
|
||||||
@preview="onPreview"
|
@preview="onPreview"
|
||||||
@mounted="onItemMounted"
|
@mounted="onItemMounted"
|
||||||
|
|
|
@ -34,7 +34,7 @@ export function longestCommonPrefix(...strings: string[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return acc.slice(0, i);
|
return acc.slice(0, i);
|
||||||
});
|
}, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process user input if expressions are used as part of complex expression
|
// Process user input if expressions are used as part of complex expression
|
||||||
|
|
|
@ -235,6 +235,7 @@ export const routes = [
|
||||||
},
|
},
|
||||||
meta: {
|
meta: {
|
||||||
nodeView: true,
|
nodeView: true,
|
||||||
|
keepWorkflowAlive: true,
|
||||||
permissions: {
|
permissions: {
|
||||||
allow: {
|
allow: {
|
||||||
loginStatus: [LOGIN_STATUS.LoggedIn],
|
loginStatus: [LOGIN_STATUS.LoggedIn],
|
||||||
|
@ -362,6 +363,7 @@ export const routes = [
|
||||||
},
|
},
|
||||||
meta: {
|
meta: {
|
||||||
nodeView: true,
|
nodeView: true,
|
||||||
|
keepWorkflowAlive: true,
|
||||||
permissions: {
|
permissions: {
|
||||||
allow: {
|
allow: {
|
||||||
loginStatus: [LOGIN_STATUS.LoggedIn],
|
loginStatus: [LOGIN_STATUS.LoggedIn],
|
||||||
|
@ -393,6 +395,7 @@ export const routes = [
|
||||||
},
|
},
|
||||||
meta: {
|
meta: {
|
||||||
nodeView: true,
|
nodeView: true,
|
||||||
|
keepWorkflowAlive: true,
|
||||||
permissions: {
|
permissions: {
|
||||||
allow: {
|
allow: {
|
||||||
loginStatus: [LOGIN_STATUS.LoggedIn],
|
loginStatus: [LOGIN_STATUS.LoggedIn],
|
||||||
|
|
|
@ -90,7 +90,13 @@ export const useWorkflowHistoryStore = defineStore('workflowHistory', () => {
|
||||||
updateData.active = false;
|
updateData.active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return workflowsStore.updateWorkflow(workflowId, updateData, true);
|
return workflowsStore.updateWorkflow(workflowId, updateData, true).catch(async (error) => {
|
||||||
|
if (error.httpStatusCode === 400 && error.message.includes('can not be activated')) {
|
||||||
|
return workflowsStore.fetchWorkflow(workflowId);
|
||||||
|
} else {
|
||||||
|
throw new Error(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -325,7 +325,7 @@ export const getLeftmostTopNode = (nodes: INodeUi[]): INodeUi => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
});
|
}, nodes[0]);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getWorkflowCorners = (nodes: INodeUi[]): IBounds => {
|
export const getWorkflowCorners = (nodes: INodeUi[]): IBounds => {
|
||||||
|
@ -949,15 +949,17 @@ export const getInputEndpointUUID = (
|
||||||
export const getFixedNodesList = (workflowNodes: INode[]) => {
|
export const getFixedNodesList = (workflowNodes: INode[]) => {
|
||||||
const nodes = [...workflowNodes];
|
const nodes = [...workflowNodes];
|
||||||
|
|
||||||
const leftmostTop = getLeftmostTopNode(nodes);
|
if (nodes.length) {
|
||||||
|
const leftmostTop = getLeftmostTopNode(nodes);
|
||||||
|
|
||||||
const diffX = DEFAULT_START_POSITION_X - leftmostTop.position[0];
|
const diffX = DEFAULT_START_POSITION_X - leftmostTop.position[0];
|
||||||
const diffY = DEFAULT_START_POSITION_Y - leftmostTop.position[1];
|
const diffY = DEFAULT_START_POSITION_Y - leftmostTop.position[1];
|
||||||
|
|
||||||
nodes.map((node) => {
|
nodes.forEach((node) => {
|
||||||
node.position[0] += diffX + NODE_SIZE * 2;
|
node.position[0] += diffX + NODE_SIZE * 2;
|
||||||
node.position[1] += diffY;
|
node.position[1] += diffY;
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return nodes;
|
return nodes;
|
||||||
};
|
};
|
||||||
|
|
|
@ -67,6 +67,10 @@ const actions = computed<UserAction[]>(() =>
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const isFirstItemShown = computed(
|
||||||
|
() => workflowHistory.value[0]?.versionId === route.params.versionId,
|
||||||
|
);
|
||||||
|
|
||||||
const loadMore = async (queryParams: WorkflowHistoryRequestParams) => {
|
const loadMore = async (queryParams: WorkflowHistoryRequestParams) => {
|
||||||
const history = await workflowHistoryStore.getWorkflowHistory(
|
const history = await workflowHistoryStore.getWorkflowHistory(
|
||||||
route.params.workflowId,
|
route.params.workflowId,
|
||||||
|
@ -294,14 +298,14 @@ watchEffect(async () => {
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div :class="$style.view">
|
<div :class="$style.view">
|
||||||
<n8n-heading :class="$style.header" tag="h2" size="medium" bold>
|
<n8n-heading :class="$style.header" tag="h2" size="medium">
|
||||||
{{ activeWorkflow?.name }}
|
{{ activeWorkflow?.name }}
|
||||||
</n8n-heading>
|
</n8n-heading>
|
||||||
<div :class="$style.corner">
|
<div :class="$style.corner">
|
||||||
<n8n-heading tag="h2" size="medium" bold>
|
<n8n-heading tag="h2" size="medium" bold>
|
||||||
{{ i18n.baseText('workflowHistory.title') }}
|
{{ i18n.baseText('workflowHistory.title') }}
|
||||||
</n8n-heading>
|
</n8n-heading>
|
||||||
<router-link :to="editorRoute">
|
<router-link :to="editorRoute" data-test-id="workflow-history-close-button">
|
||||||
<n8n-button type="tertiary" icon="times" size="small" text square />
|
<n8n-button type="tertiary" icon="times" size="small" text square />
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
|
@ -326,9 +330,10 @@ watchEffect(async () => {
|
||||||
<workflow-history-content
|
<workflow-history-content
|
||||||
v-if="canRender"
|
v-if="canRender"
|
||||||
:workflow="activeWorkflow"
|
:workflow="activeWorkflow"
|
||||||
:workflow-version="activeWorkflowVersion"
|
:workflowVersion="activeWorkflowVersion"
|
||||||
:actions="actions"
|
:actions="actions"
|
||||||
:isListLoading="isListLoading"
|
:isListLoading="isListLoading"
|
||||||
|
:isFirstItemShown="isFirstItemShown"
|
||||||
@action="onAction"
|
@action="onAction"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue