fix(editor): Fix various typecheck issues (no-changelog) (#8739)

This commit is contained in:
Alex Grozav
2024-02-26 16:05:12 +02:00
committed by GitHub
parent 09524304e6
commit c0be43bdbe
16 changed files with 91 additions and 74 deletions

View File

@@ -34,7 +34,7 @@ import {
type INodeListSearchItems, type INodeListSearchItems,
type NodeParameterValueType, type NodeParameterValueType,
type IDisplayOptions, type IDisplayOptions,
type IExecutionsSummary, type ExecutionSummary,
type FeatureFlags, type FeatureFlags,
type ExecutionStatus, type ExecutionStatus,
type ITelemetryTrackProperties, type ITelemetryTrackProperties,
@@ -53,6 +53,7 @@ import type { BulkCommand, Undoable } from '@/models/history';
import type { PartialBy, TupleToUnion } from '@/utils/typeHelpers'; import type { PartialBy, TupleToUnion } from '@/utils/typeHelpers';
import type { Component } from 'vue'; import type { Component } from 'vue';
import type { Scope } from '@n8n/permissions'; import type { Scope } from '@n8n/permissions';
import type { NotificationOptions as ElementNotificationOptions } from 'element-plus';
export * from 'n8n-design-system/types'; export * from 'n8n-design-system/types';
@@ -395,7 +396,7 @@ export interface IExecutionShortResponse {
export interface IExecutionsListResponse { export interface IExecutionsListResponse {
count: number; count: number;
results: IExecutionsSummary[]; results: ExecutionSummary[];
estimated: boolean; estimated: boolean;
} }
@@ -1061,8 +1062,8 @@ export interface IUsedCredential {
export interface WorkflowsState { export interface WorkflowsState {
activeExecutions: IExecutionsCurrentSummaryExtended[]; activeExecutions: IExecutionsCurrentSummaryExtended[];
activeWorkflows: string[]; activeWorkflows: string[];
activeWorkflowExecution: IExecutionsSummary | null; activeWorkflowExecution: ExecutionSummary | null;
currentWorkflowExecutions: IExecutionsSummary[]; currentWorkflowExecutions: ExecutionSummary[];
activeExecutionId: string | null; activeExecutionId: string | null;
executingNode: string[]; executingNode: string[];
executionWaitingForWebhook: boolean; executionWaitingForWebhook: boolean;
@@ -1189,9 +1190,9 @@ export type ModalState = {
httpNodeParameters?: string; httpNodeParameters?: string;
}; };
export type NewCredentialsModal = ModalState & { export interface NewCredentialsModal extends ModalState {
showAuthSelector?: boolean; showAuthSelector?: boolean;
}; }
export type IRunDataDisplayMode = 'table' | 'json' | 'binary' | 'schema' | 'html' | 'ai'; export type IRunDataDisplayMode = 'table' | 'json' | 'binary' | 'schema' | 'html' | 'ai';
export type NodePanelType = 'input' | 'output'; export type NodePanelType = 'input' | 'output';
@@ -1240,6 +1241,10 @@ export interface NDVState {
isMappingOnboarded: boolean; isMappingOnboarded: boolean;
} }
export interface NotificationOptions extends Partial<ElementNotificationOptions> {
message: string | ElementNotificationOptions['message'];
}
export interface UIState { export interface UIState {
activeActions: string[]; activeActions: string[];
activeCredentialType: string | null; activeCredentialType: string | null;
@@ -1398,8 +1403,8 @@ export interface IUsersState {
} }
export interface IWorkflowsState { export interface IWorkflowsState {
currentWorkflowExecutions: IExecutionsSummary[]; currentWorkflowExecutions: ExecutionSummary[];
activeWorkflowExecution: IExecutionsSummary | null; activeWorkflowExecution: ExecutionSummary | null;
finishedExecutionsCount: number; finishedExecutionsCount: number;
} }
export interface IWorkflowsMap { export interface IWorkflowsMap {

View File

@@ -301,7 +301,7 @@ import type {
ExecutionFilterType, ExecutionFilterType,
ExecutionsQueryFilter, ExecutionsQueryFilter,
} from '@/Interface'; } from '@/Interface';
import type { IExecutionsSummary, ExecutionStatus } from 'n8n-workflow'; import type { ExecutionSummary, ExecutionStatus } from 'n8n-workflow';
import { range as _range } from 'lodash-es'; import { range as _range } from 'lodash-es';
import { useUIStore } from '@/stores/ui.store'; import { useUIStore } from '@/stores/ui.store';
import { useWorkflowsStore } from '@/stores/workflows.store'; import { useWorkflowsStore } from '@/stores/workflows.store';
@@ -342,7 +342,7 @@ export default defineComponent({
data() { data() {
return { return {
isMounting: true, isMounting: true,
finishedExecutions: [] as IExecutionsSummary[], finishedExecutions: [] as ExecutionSummary[],
finishedExecutionsCount: 0, finishedExecutionsCount: 0,
finishedExecutionsCountEstimated: false, finishedExecutionsCountEstimated: false,
@@ -388,8 +388,8 @@ export default defineComponent({
activeExecutions(): IExecutionsCurrentSummaryExtended[] { activeExecutions(): IExecutionsCurrentSummaryExtended[] {
return this.workflowsStore.activeExecutions; return this.workflowsStore.activeExecutions;
}, },
combinedExecutions(): IExecutionsSummary[] { combinedExecutions(): ExecutionSummary[] {
const returnData: IExecutionsSummary[] = []; const returnData: ExecutionSummary[] = [];
if (['all', 'running'].includes(this.filter.status)) { if (['all', 'running'].includes(this.filter.status)) {
returnData.push(...this.activeExecutions); returnData.push(...this.activeExecutions);
@@ -428,7 +428,7 @@ export default defineComponent({
closeDialog() { closeDialog() {
this.$emit('closeModal'); this.$emit('closeModal');
}, },
displayExecution(execution: IExecutionsSummary) { displayExecution(execution: ExecutionSummary) {
const route = this.$router.resolve({ const route = this.$router.resolve({
name: VIEWS.EXECUTION_PREVIEW, name: VIEWS.EXECUTION_PREVIEW,
params: { name: execution.workflowId, executionId: execution.id }, params: { name: execution.workflowId, executionId: execution.id },
@@ -529,7 +529,7 @@ export default defineComponent({
this.handleClearSelection(); this.handleClearSelection();
this.isMounting = false; this.isMounting = false;
}, },
async handleActionItemClick(commandData: { command: string; execution: IExecutionsSummary }) { async handleActionItemClick(commandData: { command: string; execution: ExecutionSummary }) {
if (['currentlySaved', 'original'].includes(commandData.command)) { if (['currentlySaved', 'original'].includes(commandData.command)) {
let loadWorkflow = false; let loadWorkflow = false;
if (commandData.command === 'currentlySaved') { if (commandData.command === 'currentlySaved') {
@@ -747,7 +747,7 @@ export default defineComponent({
this.showError(error, this.i18n.baseText('executionsList.showError.loadWorkflows.title')); this.showError(error, this.i18n.baseText('executionsList.showError.loadWorkflows.title'));
} }
}, },
async retryExecution(execution: IExecutionsSummary, loadWorkflow?: boolean) { async retryExecution(execution: ExecutionSummary, loadWorkflow?: boolean) {
this.isDataLoading = true; this.isDataLoading = true;
try { try {
@@ -786,7 +786,7 @@ export default defineComponent({
this.isDataLoading = false; this.isDataLoading = false;
}, },
getStatus(execution: IExecutionsSummary): ExecutionStatus { getStatus(execution: ExecutionSummary): ExecutionStatus {
if (execution.status) { if (execution.status) {
return execution.status; return execution.status;
} else { } else {
@@ -806,10 +806,10 @@ export default defineComponent({
return status; return status;
} }
}, },
getRowClass(execution: IExecutionsSummary): string { getRowClass(execution: ExecutionSummary): string {
return [this.$style.execRow, this.$style[this.getStatus(execution)]].join(' '); return [this.$style.execRow, this.$style[this.getStatus(execution)]].join(' ');
}, },
getStatusText(entry: IExecutionsSummary): string { getStatusText(entry: ExecutionSummary): string {
const status = this.getStatus(entry); const status = this.getStatus(entry);
let text = ''; let text = '';
@@ -833,7 +833,7 @@ export default defineComponent({
return text; return text;
}, },
getStatusTextTranslationPath(entry: IExecutionsSummary): string { getStatusTextTranslationPath(entry: ExecutionSummary): string {
const status = this.getStatus(entry); const status = this.getStatus(entry);
let path = ''; let path = '';
@@ -857,7 +857,7 @@ export default defineComponent({
return path; return path;
}, },
getStatusTooltipText(entry: IExecutionsSummary): string { getStatusTooltipText(entry: ExecutionSummary): string {
const status = this.getStatus(entry); const status = this.getStatus(entry);
let text = ''; let text = '';
@@ -894,7 +894,7 @@ export default defineComponent({
this.showError(error, this.i18n.baseText('executionsList.showError.stopExecution.title')); this.showError(error, this.i18n.baseText('executionsList.showError.stopExecution.title'));
} }
}, },
isExecutionRetriable(execution: IExecutionsSummary): boolean { isExecutionRetriable(execution: ExecutionSummary): boolean {
return ( return (
execution.stoppedAt !== undefined && execution.stoppedAt !== undefined &&
!execution.finished && !execution.finished &&
@@ -903,7 +903,7 @@ export default defineComponent({
!execution.waitTill !execution.waitTill
); );
}, },
async deleteExecution(execution: IExecutionsSummary) { async deleteExecution(execution: ExecutionSummary) {
this.isDataLoading = true; this.isDataLoading = true;
try { try {
await this.workflowsStore.deleteExecutions({ ids: [execution.id] }); await this.workflowsStore.deleteExecutions({ ids: [execution.id] });
@@ -921,17 +921,17 @@ export default defineComponent({
} }
this.isDataLoading = true; this.isDataLoading = true;
}, },
isWaitTillIndefinite(execution: IExecutionsSummary): boolean { isWaitTillIndefinite(execution: ExecutionSummary): boolean {
if (!execution.waitTill) { if (!execution.waitTill) {
return false; return false;
} }
return new Date(execution.waitTill).toISOString() === WAIT_TIME_UNLIMITED; return new Date(execution.waitTill).toISOString() === WAIT_TIME_UNLIMITED;
}, },
isRunning(execution: IExecutionsSummary): boolean { isRunning(execution: ExecutionSummary): boolean {
return this.getStatus(execution) === 'running'; return this.getStatus(execution) === 'running';
}, },
selectAllVisibleExecutions() { selectAllVisibleExecutions() {
this.combinedExecutions.forEach((execution: IExecutionsSummary) => { this.combinedExecutions.forEach((execution: ExecutionSummary) => {
this.selectedItems = { ...this.selectedItems, [execution.id]: true }; this.selectedItems = { ...this.selectedItems, [execution.id]: true };
}); });
}, },

View File

@@ -83,7 +83,7 @@
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import type { IExecutionsSummary } from '@/Interface'; import type { ExecutionSummary } from '@/Interface';
import type { IExecutionUIData } from '@/mixins/executionsHelpers'; import type { IExecutionUIData } from '@/mixins/executionsHelpers';
import { executionHelpers } from '@/mixins/executionsHelpers'; import { executionHelpers } from '@/mixins/executionsHelpers';
import { VIEWS } from '@/constants'; import { VIEWS } from '@/constants';
@@ -97,7 +97,7 @@ export default defineComponent({
mixins: [executionHelpers], mixins: [executionHelpers],
props: { props: {
execution: { execution: {
type: Object as () => IExecutionsSummary, type: Object as () => ExecutionSummary,
required: true, required: true,
}, },
highlight: { highlight: {

View File

@@ -44,7 +44,7 @@ import type {
IWorkflowDb, IWorkflowDb,
} from '@/Interface'; } from '@/Interface';
import type { import type {
IExecutionsSummary, ExecutionSummary,
IConnection, IConnection,
IConnections, IConnections,
IDataObject, IDataObject,
@@ -100,7 +100,7 @@ export default defineComponent({
loading: false, loading: false,
loadingMore: false, loadingMore: false,
filter: {} as ExecutionFilterType, filter: {} as ExecutionFilterType,
temporaryExecution: null as IExecutionsSummary | null, temporaryExecution: null as ExecutionSummary | null,
autoRefresh: false, autoRefresh: false,
autoRefreshTimeout: undefined as undefined | NodeJS.Timer, autoRefreshTimeout: undefined as undefined | NodeJS.Timer,
}; };
@@ -284,7 +284,7 @@ export default defineComponent({
this.loading = true; this.loading = true;
try { try {
const executionIndex = this.executions.findIndex( const executionIndex = this.executions.findIndex(
(execution: IExecutionsSummary) => execution.id === this.$route.params.executionId, (execution: ExecutionSummary) => execution.id === this.$route.params.executionId,
); );
const nextExecution = const nextExecution =
this.executions[executionIndex + 1] || this.executions[executionIndex + 1] ||
@@ -388,8 +388,8 @@ export default defineComponent({
}, },
async loadAutoRefresh(): Promise<void> { async loadAutoRefresh(): Promise<void> {
// Most of the auto-refresh logic is taken from the `ExecutionsList` component // Most of the auto-refresh logic is taken from the `ExecutionsList` component
const fetchedExecutions: IExecutionsSummary[] = await this.loadExecutions(); const fetchedExecutions: ExecutionSummary[] = await this.loadExecutions();
let existingExecutions: IExecutionsSummary[] = [...this.executions]; let existingExecutions: ExecutionSummary[] = [...this.executions];
const alreadyPresentExecutionIds = existingExecutions.map((exec) => parseInt(exec.id, 10)); const alreadyPresentExecutionIds = existingExecutions.map((exec) => parseInt(exec.id, 10));
let lastId = 0; let lastId = 0;
const gaps = [] as number[]; const gaps = [] as number[];
@@ -465,7 +465,7 @@ export default defineComponent({
} }
} }
}, },
async loadExecutions(): Promise<IExecutionsSummary[]> { async loadExecutions(): Promise<ExecutionSummary[]> {
if (!this.currentWorkflow) { if (!this.currentWorkflow) {
return []; return [];
} }
@@ -536,7 +536,7 @@ export default defineComponent({
); );
return; return;
} else { } else {
this.temporaryExecution = existingExecution as IExecutionsSummary; this.temporaryExecution = existingExecution as ExecutionSummary;
} }
} }
// stop if the execution wasn't found in the first 1000 lookups // stop if the execution wasn't found in the first 1000 lookups
@@ -716,7 +716,7 @@ export default defineComponent({
async loadActiveWorkflows(): Promise<void> { async loadActiveWorkflows(): Promise<void> {
await this.workflowsStore.fetchActiveWorkflows(); await this.workflowsStore.fetchActiveWorkflows();
}, },
async onRetryExecution(payload: { execution: IExecutionsSummary; command: string }) { async onRetryExecution(payload: { execution: ExecutionSummary; command: string }) {
const loadWorkflow = payload.command === 'current-workflow'; const loadWorkflow = payload.command === 'current-workflow';
this.showMessage({ this.showMessage({
@@ -733,7 +733,7 @@ export default defineComponent({
retry_type: loadWorkflow ? 'current' : 'original', retry_type: loadWorkflow ? 'current' : 'original',
}); });
}, },
async retryExecution(execution: IExecutionsSummary, loadWorkflow?: boolean) { async retryExecution(execution: ExecutionSummary, loadWorkflow?: boolean) {
try { try {
const retrySuccessful = await this.workflowsStore.retryExecution( const retrySuccessful = await this.workflowsStore.retryExecution(
execution.id, execution.id,

View File

@@ -64,7 +64,7 @@ import ExecutionCard from '@/components/ExecutionsView/ExecutionCard.vue';
import ExecutionsInfoAccordion from '@/components/ExecutionsView/ExecutionsInfoAccordion.vue'; import ExecutionsInfoAccordion from '@/components/ExecutionsView/ExecutionsInfoAccordion.vue';
import ExecutionFilter from '@/components/ExecutionFilter.vue'; import ExecutionFilter from '@/components/ExecutionFilter.vue';
import { VIEWS } from '@/constants'; import { VIEWS } from '@/constants';
import type { IExecutionsSummary } from 'n8n-workflow'; import type { ExecutionSummary } from 'n8n-workflow';
import type { Route } from 'vue-router'; import type { Route } from 'vue-router';
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import type { PropType } from 'vue'; import type { PropType } from 'vue';
@@ -88,7 +88,7 @@ export default defineComponent({
default: false, default: false,
}, },
executions: { executions: {
type: Array as PropType<IExecutionsSummary[]>, type: Array as PropType<ExecutionSummary[]>,
required: true, required: true,
}, },
loading: { loading: {
@@ -100,7 +100,7 @@ export default defineComponent({
default: false, default: false,
}, },
temporaryExecution: { temporaryExecution: {
type: Object as PropType<IExecutionsSummary>, type: Object as PropType<ExecutionSummary>,
default: null, default: null,
}, },
}, },

View File

@@ -4,7 +4,7 @@ import userEvent from '@testing-library/user-event';
import { faker } from '@faker-js/faker'; import { faker } from '@faker-js/faker';
import { createRouter, createWebHistory } from 'vue-router'; import { createRouter, createWebHistory } from 'vue-router';
import { createPinia, PiniaVuePlugin, setActivePinia } from 'pinia'; import { createPinia, PiniaVuePlugin, setActivePinia } from 'pinia';
import type { IExecutionsSummary } from 'n8n-workflow'; import type { ExecutionSummary } from 'n8n-workflow';
import { useSettingsStore } from '@/stores/settings.store'; import { useSettingsStore } from '@/stores/settings.store';
import { useWorkflowsStore } from '@/stores/workflows.store'; import { useWorkflowsStore } from '@/stores/workflows.store';
import ExecutionPreview from '@/components/ExecutionsView/ExecutionPreview.vue'; import ExecutionPreview from '@/components/ExecutionsView/ExecutionPreview.vue';
@@ -48,7 +48,7 @@ const generateUndefinedNullOrString = () => {
} }
}; };
const executionDataFactory = (): IExecutionsSummary => ({ const executionDataFactory = (): ExecutionSummary => ({
id: faker.string.uuid(), id: faker.string.uuid(),
finished: faker.datatype.boolean(), finished: faker.datatype.boolean(),
mode: faker.helpers.arrayElement(['manual', 'trigger']), mode: faker.helpers.arrayElement(['manual', 'trigger']),
@@ -65,7 +65,7 @@ const executionDataFactory = (): IExecutionsSummary => ({
describe('ExecutionPreview.vue', () => { describe('ExecutionPreview.vue', () => {
let workflowsStore: ReturnType<typeof useWorkflowsStore>; let workflowsStore: ReturnType<typeof useWorkflowsStore>;
let settingsStore: ReturnType<typeof useSettingsStore>; let settingsStore: ReturnType<typeof useSettingsStore>;
const executionData: IExecutionsSummary = executionDataFactory(); const executionData: ExecutionSummary = executionDataFactory();
beforeEach(() => { beforeEach(() => {
pinia = createPinia(); pinia = createPinia();

View File

@@ -18,7 +18,7 @@
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import type { Route, RouteLocationRaw } from 'vue-router'; import type { Route, RouteLocationRaw } from 'vue-router';
import { mapStores } from 'pinia'; import { mapStores } from 'pinia';
import type { IExecutionsSummary } from 'n8n-workflow'; import type { ExecutionSummary } from 'n8n-workflow';
import { pushConnection } from '@/mixins/pushConnection'; import { pushConnection } from '@/mixins/pushConnection';
import WorkflowDetails from '@/components/MainHeader/WorkflowDetails.vue'; import WorkflowDetails from '@/components/MainHeader/WorkflowDetails.vue';
import TabBar from '@/components/MainHeader/TabBar.vue'; import TabBar from '@/components/MainHeader/TabBar.vue';
@@ -79,8 +79,8 @@ export default defineComponent({
(this.$route.meta.nodeView || this.$route.meta.keepWorkflowAlive === true) (this.$route.meta.nodeView || this.$route.meta.keepWorkflowAlive === true)
); );
}, },
activeExecution(): IExecutionsSummary { activeExecution(): ExecutionSummary {
return this.workflowsStore.activeWorkflowExecution as IExecutionsSummary; return this.workflowsStore.activeWorkflowExecution as ExecutionSummary;
}, },
readOnly(): boolean { readOnly(): boolean {
return this.sourceControlStore.preferences.branchReadOnly; return this.sourceControlStore.preferences.branchReadOnly;

View File

@@ -191,7 +191,7 @@ import {
import { nodeBase } from '@/mixins/nodeBase'; import { nodeBase } from '@/mixins/nodeBase';
import type { import type {
ConnectionTypes, ConnectionTypes,
IExecutionsSummary, ExecutionSummary,
INodeInputConfiguration, INodeInputConfiguration,
INodeOutputConfiguration, INodeOutputConfiguration,
INodeTypeDescription, INodeTypeDescription,
@@ -494,7 +494,7 @@ export default defineComponent({
return this.data.name; return this.data.name;
}, },
waiting(): string | undefined { waiting(): string | undefined {
const workflowExecution = this.workflowsStore.getWorkflowExecution as IExecutionsSummary; const workflowExecution = this.workflowsStore.getWorkflowExecution as ExecutionSummary;
if (workflowExecution?.waitTill) { if (workflowExecution?.waitTill) {
const lastNodeExecuted = get(workflowExecution, 'data.resultData.lastNodeExecuted'); const lastNodeExecuted = get(workflowExecution, 'data.resultData.lastNodeExecuted');

View File

@@ -6,7 +6,7 @@ import { faker } from '@faker-js/faker';
import { STORES, VIEWS } from '@/constants'; import { STORES, VIEWS } from '@/constants';
import ExecutionsList from '@/components/ExecutionsList.vue'; import ExecutionsList from '@/components/ExecutionsList.vue';
import type { IWorkflowDb } from '@/Interface'; import type { IWorkflowDb } from '@/Interface';
import type { IExecutionsSummary } from 'n8n-workflow'; import type { ExecutionSummary } from 'n8n-workflow';
import { retry, SETTINGS_STORE_DEFAULT_STATE, waitAllPromises } from '@/__tests__/utils'; import { retry, SETTINGS_STORE_DEFAULT_STATE, waitAllPromises } from '@/__tests__/utils';
import { useWorkflowsStore } from '@/stores/workflows.store'; import { useWorkflowsStore } from '@/stores/workflows.store';
import type { RenderOptions } from '@/__tests__/render'; import type { RenderOptions } from '@/__tests__/render';
@@ -48,7 +48,7 @@ const workflowDataFactory = (): IWorkflowDb => ({
versionId: faker.number.int().toString(), versionId: faker.number.int().toString(),
}); });
const executionDataFactory = (): IExecutionsSummary => ({ const executionDataFactory = (): ExecutionSummary => ({
id: faker.string.uuid(), id: faker.string.uuid(),
finished: faker.datatype.boolean(), finished: faker.datatype.boolean(),
mode: faker.helpers.arrayElement(['manual', 'trigger']), mode: faker.helpers.arrayElement(['manual', 'trigger']),
@@ -89,7 +89,7 @@ describe('ExecutionsList.vue', () => {
let workflowsData: IWorkflowDb[]; let workflowsData: IWorkflowDb[];
let executionsData: Array<{ let executionsData: Array<{
count: number; count: number;
results: IExecutionsSummary[]; results: ExecutionSummary[];
estimated: boolean; estimated: boolean;
}>; }>;

View File

@@ -1,7 +1,7 @@
import { vi } from 'vitest'; import { vi } from 'vitest';
import { createPinia, setActivePinia } from 'pinia'; import { createPinia, setActivePinia } from 'pinia';
import { waitFor } from '@testing-library/vue'; import { waitFor } from '@testing-library/vue';
import type { IExecutionsSummary } from 'n8n-workflow'; import type { ExecutionSummary } from 'n8n-workflow';
import { createComponentRenderer } from '@/__tests__/render'; import { createComponentRenderer } from '@/__tests__/render';
import type { INodeUi, IWorkflowDb } from '@/Interface'; import type { INodeUi, IWorkflowDb } from '@/Interface';
import WorkflowPreview from '@/components/WorkflowPreview.vue'; import WorkflowPreview from '@/components/WorkflowPreview.vue';
@@ -152,7 +152,7 @@ describe('WorkflowPreview', () => {
it('should call also iframe postMessage with "setActiveExecution" if active execution is set', async () => { it('should call also iframe postMessage with "setActiveExecution" if active execution is set', async () => {
vi.spyOn(workflowsStore, 'activeWorkflowExecution', 'get').mockReturnValue({ vi.spyOn(workflowsStore, 'activeWorkflowExecution', 'get').mockReturnValue({
id: 'abc', id: 'abc',
} as IExecutionsSummary); } as ExecutionSummary);
const executionId = '123'; const executionId = '123';
renderComponent({ renderComponent({

View File

@@ -1,5 +1,6 @@
import { ElNotification as Notification } from 'element-plus'; import { ElNotification as Notification } from 'element-plus';
import type { NotificationInstance, NotificationOptions, MessageBoxState } from 'element-plus'; import type { NotificationHandle, MessageBoxState } from 'element-plus';
import type { NotificationOptions } from '@/Interface';
import { sanitizeHtml } from '@/utils/htmlUtils'; import { sanitizeHtml } from '@/utils/htmlUtils';
import { useTelemetry } from '@/composables/useTelemetry'; import { useTelemetry } from '@/composables/useTelemetry';
import { useWorkflowsStore } from '@/stores/workflows.store'; import { useWorkflowsStore } from '@/stores/workflows.store';
@@ -8,12 +9,19 @@ import { useI18n } from './useI18n';
import { useExternalHooks } from './useExternalHooks'; import { useExternalHooks } from './useExternalHooks';
import { VIEWS } from '@/constants'; import { VIEWS } from '@/constants';
export interface NotificationErrorWithNodeAndDescription extends Error {
node: {
name: string;
};
description: string;
}
const messageDefaults: Partial<Omit<NotificationOptions, 'message'>> = { const messageDefaults: Partial<Omit<NotificationOptions, 'message'>> = {
dangerouslyUseHTMLString: true, dangerouslyUseHTMLString: true,
position: 'bottom-right', position: 'bottom-right',
}; };
const stickyNotificationQueue: NotificationInstance[] = []; const stickyNotificationQueue: NotificationHandle[] = [];
export function useToast() { export function useToast() {
const telemetry = useTelemetry(); const telemetry = useTelemetry();
@@ -39,7 +47,7 @@ export function useToast() {
telemetry.track('Instance FE emitted error', { telemetry.track('Instance FE emitted error', {
error_title: messageData.title, error_title: messageData.title,
error_message: messageData.message, error_message: messageData.message,
caused_by_credential: causedByCredential(messageData.message), caused_by_credential: causedByCredential(messageData.message as string),
workflow_id: workflowsStore.workflowId, workflow_id: workflowsStore.workflowId,
}); });
} }
@@ -59,7 +67,7 @@ export function useToast() {
dangerouslyUseHTMLString?: boolean; dangerouslyUseHTMLString?: boolean;
}) { }) {
// eslint-disable-next-line prefer-const // eslint-disable-next-line prefer-const
let notification: NotificationInstance; let notification: NotificationHandle;
if (config.closeOnClick) { if (config.closeOnClick) {
const cb = config.onClick; const cb = config.onClick;
config.onClick = () => { config.onClick = () => {
@@ -87,7 +95,7 @@ export function useToast() {
return notification; return notification;
} }
function collapsableDetails({ description, node }: Error) { function collapsableDetails({ description, node }: NotificationErrorWithNodeAndDescription) {
if (!description) return ''; if (!description) return '';
const errorDescription = const errorDescription =
@@ -116,7 +124,7 @@ export function useToast() {
message: ` message: `
${messageLine} ${messageLine}
<i>${error.message}</i> <i>${error.message}</i>
${collapsableDetails(error)}`, ${collapsableDetails(error as NotificationErrorWithNodeAndDescription)}`,
type: 'error', type: 'error',
duration: 0, duration: 0,
}, },
@@ -138,7 +146,7 @@ export function useToast() {
}); });
} }
function showAlert(config: NotificationOptions): NotificationInstance { function showAlert(config: NotificationOptions): NotificationHandle {
return Notification(config); return Notification(config);
} }

View File

@@ -37,6 +37,7 @@ import type {
INodeTypesMaxCount, INodeTypesMaxCount,
INodeUi, INodeUi,
ITag, ITag,
IUpdateInformation,
IWorkflowData, IWorkflowData,
IWorkflowDataUpdate, IWorkflowDataUpdate,
IWorkflowDb, IWorkflowDb,
@@ -1021,7 +1022,7 @@ export function useWorkflowHelpers(router: Router) {
key: 'webhookId', key: 'webhookId',
value: changedNodes[nodeName], value: changedNodes[nodeName],
name: nodeName, name: nodeName,
}; } as IUpdateInformation;
workflowsStore.setNodeValue(changes); workflowsStore.setNodeValue(changes);
}); });

View File

@@ -2,7 +2,7 @@ import { defineComponent } from 'vue';
import { mapStores } from 'pinia'; import { mapStores } from 'pinia';
import { useWorkflowsStore } from '@/stores/workflows.store'; import { useWorkflowsStore } from '@/stores/workflows.store';
import { i18n as locale } from '@/plugins/i18n'; import { i18n as locale } from '@/plugins/i18n';
import type { IExecutionsSummary } from 'n8n-workflow'; import type { ExecutionSummary } from 'n8n-workflow';
import { convertToDisplayDate } from '@/utils/formatters/dateFormatter'; import { convertToDisplayDate } from '@/utils/formatters/dateFormatter';
export interface IExecutionUIData { export interface IExecutionUIData {
@@ -24,15 +24,15 @@ export const executionHelpers = defineComponent({
currentWorkflow(): string { currentWorkflow(): string {
return this.$route.params.name || this.workflowsStore.workflowId; return this.$route.params.name || this.workflowsStore.workflowId;
}, },
executions(): IExecutionsSummary[] { executions(): ExecutionSummary[] {
return this.workflowsStore.currentWorkflowExecutions; return this.workflowsStore.currentWorkflowExecutions;
}, },
activeExecution(): IExecutionsSummary | null { activeExecution(): ExecutionSummary | null {
return this.workflowsStore.activeWorkflowExecution; return this.workflowsStore.activeWorkflowExecution;
}, },
}, },
methods: { methods: {
getExecutionUIDetails(execution: IExecutionsSummary): IExecutionUIData { getExecutionUIDetails(execution: ExecutionSummary): IExecutionUIData {
const status = { const status = {
name: 'unknown', name: 'unknown',
startTime: this.formatDate(execution.startedAt), startTime: this.formatDate(execution.startedAt),

View File

@@ -55,6 +55,8 @@ import type {
ThemeOption, ThemeOption,
AppliedThemeOption, AppliedThemeOption,
SuggestedTemplates, SuggestedTemplates,
NotificationOptions,
ModalState,
} from '@/Interface'; } from '@/Interface';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { useRootStore } from '@/stores/n8nRoot.store'; import { useRootStore } from '@/stores/n8nRoot.store';
@@ -144,7 +146,7 @@ export const useUIStore = defineStore(STORES.UI, {
mode: '', mode: '',
activeId: null, activeId: null,
showAuthSelector: false, showAuthSelector: false,
}, } as ModalState,
}, },
modalStack: [], modalStack: [],
sidebarMenuCollapsed: true, sidebarMenuCollapsed: true,
@@ -172,6 +174,7 @@ export const useUIStore = defineStore(STORES.UI, {
stateIsDirty: false, stateIsDirty: false,
lastSelectedNode: null, lastSelectedNode: null,
lastSelectedNodeOutputIndex: null, lastSelectedNodeOutputIndex: null,
lastSelectedNodeEndpointUuid: null,
nodeViewOffsetPosition: [0, 0], nodeViewOffsetPosition: [0, 0],
nodeViewMoveInProgress: false, nodeViewMoveInProgress: false,
selectedNodes: [], selectedNodes: [],

View File

@@ -40,7 +40,7 @@ import type {
IConnection, IConnection,
IConnections, IConnections,
IDataObject, IDataObject,
IExecutionsSummary, ExecutionSummary,
INode, INode,
INodeConnections, INodeConnections,
INodeCredentials, INodeCredentials,
@@ -263,11 +263,11 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, {
return (nodeName: string) => this.executingNode.includes(nodeName); return (nodeName: string) => this.executingNode.includes(nodeName);
}, },
// Executions getters // Executions getters
getExecutionDataById(): (id: string) => IExecutionsSummary | undefined { getExecutionDataById(): (id: string) => ExecutionSummary | undefined {
return (id: string): IExecutionsSummary | undefined => return (id: string): ExecutionSummary | undefined =>
this.currentWorkflowExecutions.find((execution) => execution.id === id); this.currentWorkflowExecutions.find((execution) => execution.id === id);
}, },
getAllLoadedFinishedExecutions(): IExecutionsSummary[] { getAllLoadedFinishedExecutions(): ExecutionSummary[] {
return this.currentWorkflowExecutions.filter( return this.currentWorkflowExecutions.filter(
(ex) => ex.finished === true || ex.stoppedAt !== undefined, (ex) => ex.finished === true || ex.stoppedAt !== undefined,
); );
@@ -1366,7 +1366,7 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, {
async loadCurrentWorkflowExecutions( async loadCurrentWorkflowExecutions(
requestFilter: ExecutionsQueryFilter, requestFilter: ExecutionsQueryFilter,
): Promise<IExecutionsSummary[]> { ): Promise<ExecutionSummary[]> {
let activeExecutions = []; let activeExecutions = [];
if (!requestFilter.workflowId) { if (!requestFilter.workflowId) {
@@ -1392,11 +1392,11 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, {
return await getExecutionData(rootStore.getRestApiContext, executionId); return await getExecutionData(rootStore.getRestApiContext, executionId);
}, },
deleteExecution(execution: IExecutionsSummary): void { deleteExecution(execution: ExecutionSummary): void {
this.currentWorkflowExecutions.splice(this.currentWorkflowExecutions.indexOf(execution), 1); this.currentWorkflowExecutions.splice(this.currentWorkflowExecutions.indexOf(execution), 1);
}, },
addToCurrentExecutions(executions: IExecutionsSummary[]): void { addToCurrentExecutions(executions: ExecutionSummary[]): void {
executions.forEach((execution) => { executions.forEach((execution) => {
const exists = this.currentWorkflowExecutions.find((ex) => ex.id === execution.id); const exists = this.currentWorkflowExecutions.find((ex) => ex.id === execution.id);
if (!exists && execution.workflowId === this.workflowId) { if (!exists && execution.workflowId === this.workflowId) {

View File

@@ -272,7 +272,7 @@ import type {
IConnection, IConnection,
IConnections, IConnections,
IDataObject, IDataObject,
IExecutionsSummary, ExecutionSummary,
INode, INode,
INodeConnections, INodeConnections,
INodeCredentialsDetails, INodeCredentialsDetails,
@@ -1280,7 +1280,7 @@ export default defineComponent({
}); });
} }
} }
if ((data as IExecutionsSummary).waitTill) { if ((data as ExecutionSummary).waitTill) {
this.showMessage({ this.showMessage({
title: this.$locale.baseText('nodeView.thisExecutionHasntFinishedYet'), title: this.$locale.baseText('nodeView.thisExecutionHasntFinishedYet'),
message: `<a data-action="reload">${this.$locale.baseText( message: `<a data-action="reload">${this.$locale.baseText(