refactor(editor): Move templates api to @n8n/rest-api-client package (no-changelog) (#16542)

This commit is contained in:
Alex Grozav
2025-06-23 14:04:33 +03:00
committed by GitHub
parent 662ac1bb57
commit 9c654dbbf7
59 changed files with 423 additions and 417 deletions

View File

@@ -18,3 +18,6 @@ CHANGELOG.md
**/*.js **/*.js
**/*.json **/*.json
**/*.jsonc **/*.jsonc
# Auto-generated
**/components.d.ts

View File

@@ -14,7 +14,10 @@ export * from './roles';
export * from './settings'; export * from './settings';
export * from './module-settings'; export * from './module-settings';
export * from './sso'; export * from './sso';
export * from './tags';
export * from './templates';
export * from './ui'; export * from './ui';
export * from './versions'; export * from './versions';
export * from './webhooks'; export * from './webhooks';
export * from './workflowHistory'; export * from './workflowHistory';
export * from './workflows';

View File

@@ -0,0 +1,7 @@
export interface ITag {
id: string;
name: string;
usageCount?: number;
createdAt?: string;
updatedAt?: string;
}

View File

@@ -0,0 +1,195 @@
import type { RawAxiosRequestHeaders } from 'axios';
import type { INode, INodeCredentialsDetails } from 'n8n-workflow';
import type { VersionNode } from './versions';
import type { WorkflowData } from './workflows';
import { get } from '../utils';
export interface IWorkflowTemplateNode
extends Pick<
INode,
'name' | 'type' | 'position' | 'parameters' | 'typeVersion' | 'webhookId' | 'id' | 'disabled'
> {
// The credentials in a template workflow have a different type than in a regular workflow
credentials?: IWorkflowTemplateNodeCredentials;
}
export interface IWorkflowTemplateNodeCredentials {
[key: string]: string | INodeCredentialsDetails;
}
export interface IWorkflowTemplate {
id: number;
name: string;
workflow: Pick<WorkflowData, 'connections' | 'settings' | 'pinData'> & {
nodes: IWorkflowTemplateNode[];
};
}
export interface ITemplatesNode extends VersionNode {
id: number;
categories?: ITemplatesCategory[];
}
export interface ITemplatesCollection {
id: number;
name: string;
nodes: ITemplatesNode[];
workflows: Array<{ id: number }>;
}
interface ITemplatesImage {
id: number;
url: string;
}
interface ITemplatesCollectionExtended extends ITemplatesCollection {
description: string | null;
image: ITemplatesImage[];
categories: ITemplatesCategory[];
createdAt: string;
}
export interface ITemplatesCollectionFull extends ITemplatesCollectionExtended {
full: true;
}
export interface ITemplatesCollectionResponse extends ITemplatesCollectionExtended {
workflows: ITemplatesWorkflow[];
}
/**
* A template without the actual workflow definition
*/
export interface ITemplatesWorkflow {
id: number;
createdAt: string;
name: string;
nodes: ITemplatesNode[];
totalViews: number;
user: {
username: string;
};
}
export interface ITemplatesWorkflowInfo {
nodeCount: number;
nodeTypes: {
[key: string]: {
count: number;
};
};
}
export type TemplateSearchFacet = {
field_name: string;
sampled: boolean;
stats: {
total_values: number;
};
counts: Array<{
count: number;
highlighted: string;
value: string;
}>;
};
export interface ITemplatesWorkflowResponse extends ITemplatesWorkflow, IWorkflowTemplate {
description: string | null;
image: ITemplatesImage[];
categories: ITemplatesCategory[];
workflowInfo: ITemplatesWorkflowInfo;
}
/**
* A template with also the full workflow definition
*/
export interface ITemplatesWorkflowFull extends ITemplatesWorkflowResponse {
full: true;
}
export interface ITemplatesQuery {
categories: string[];
search: string;
}
export interface ITemplatesCategory {
id: number;
name: string;
}
function stringifyArray(arr: string[]) {
return arr.join(',');
}
export async function testHealthEndpoint(apiEndpoint: string) {
return await get(apiEndpoint, '/health');
}
export async function getCategories(
apiEndpoint: string,
headers?: RawAxiosRequestHeaders,
): Promise<{ categories: ITemplatesCategory[] }> {
return await get(apiEndpoint, '/templates/categories', undefined, headers);
}
export async function getCollections(
apiEndpoint: string,
query: ITemplatesQuery,
headers?: RawAxiosRequestHeaders,
): Promise<{ collections: ITemplatesCollection[] }> {
return await get(
apiEndpoint,
'/templates/collections',
{ category: query.categories, search: query.search },
headers,
);
}
export async function getWorkflows(
apiEndpoint: string,
query: { page: number; limit: number; categories: string[]; search: string },
headers?: RawAxiosRequestHeaders,
): Promise<{
totalWorkflows: number;
workflows: ITemplatesWorkflow[];
filters: TemplateSearchFacet[];
}> {
return await get(
apiEndpoint,
'/templates/search',
{
page: query.page,
rows: query.limit,
category: stringifyArray(query.categories),
search: query.search,
},
headers,
);
}
export async function getCollectionById(
apiEndpoint: string,
collectionId: string,
headers?: RawAxiosRequestHeaders,
): Promise<{ collection: ITemplatesCollectionResponse }> {
return await get(apiEndpoint, `/templates/collections/${collectionId}`, undefined, headers);
}
export async function getTemplateById(
apiEndpoint: string,
templateId: string,
headers?: RawAxiosRequestHeaders,
): Promise<{ workflow: ITemplatesWorkflowResponse }> {
return await get(apiEndpoint, `/templates/workflows/${templateId}`, undefined, headers);
}
export async function getWorkflowTemplate(
apiEndpoint: string,
templateId: string,
headers?: RawAxiosRequestHeaders,
): Promise<IWorkflowTemplate> {
return await get(apiEndpoint, `/workflows/templates/${templateId}`, undefined, headers);
}

View File

@@ -0,0 +1,42 @@
import type { IWorkflowSettings, IConnections, INode, IPinData } from 'n8n-workflow';
import type { ITag } from './tags';
export interface WorkflowMetadata {
onboardingId?: string;
templateId?: string;
instanceId?: string;
templateCredsSetupCompleted?: boolean;
}
// Simple version of n8n-workflow.Workflow
export interface WorkflowData {
id?: string;
name?: string;
active?: boolean;
nodes: INode[];
connections: IConnections;
settings?: IWorkflowSettings;
tags?: string[];
pinData?: IPinData;
versionId?: string;
meta?: WorkflowMetadata;
}
export interface WorkflowDataUpdate {
id?: string;
name?: string;
nodes?: INode[];
connections?: IConnections;
settings?: IWorkflowSettings;
active?: boolean;
tags?: ITag[] | string[]; // string[] when store or requested, ITag[] from API response
pinData?: IPinData;
versionId?: string;
meta?: WorkflowMetadata;
parentFolderId?: string;
}
export interface WorkflowDataCreate extends WorkflowDataUpdate {
projectId?: string;
}

View File

@@ -41,15 +41,21 @@ import type {
INodeExecutionData, INodeExecutionData,
INodeProperties, INodeProperties,
NodeConnectionType, NodeConnectionType,
INodeCredentialsDetails,
StartNodeData, StartNodeData,
IPersonalizationSurveyAnswersV4, IPersonalizationSurveyAnswersV4,
AnnotationVote, AnnotationVote,
ITaskData, ITaskData,
ISourceData, ISourceData,
} from 'n8n-workflow'; } from 'n8n-workflow';
import type { Version, VersionNode } from '@n8n/rest-api-client/api/versions'; import type { Version } from '@n8n/rest-api-client/api/versions';
import type { Cloud, InstanceUsage } from '@n8n/rest-api-client/api/cloudPlans'; import type { Cloud, InstanceUsage } from '@n8n/rest-api-client/api/cloudPlans';
import type {
WorkflowMetadata,
WorkflowData,
WorkflowDataCreate,
WorkflowDataUpdate,
} from '@n8n/rest-api-client/api/workflows';
import type { ITag } from '@n8n/rest-api-client/api/tags';
import type { import type {
AI_NODE_CREATOR_VIEW, AI_NODE_CREATOR_VIEW,
@@ -203,7 +209,7 @@ export interface IAiData {
} }
export interface IStartRunData { export interface IStartRunData {
workflowData: IWorkflowData; workflowData: WorkflowData;
startNodes?: StartNodeData[]; startNodes?: StartNodeData[];
destinationNode?: string; destinationNode?: string;
runData?: IRunData; runData?: IRunData;
@@ -230,49 +236,17 @@ export interface ITableData {
}; };
} }
// Simple version of n8n-workflow.Workflow
export interface IWorkflowData {
id?: string;
name?: string;
active?: boolean;
nodes: INode[];
connections: IConnections;
settings?: IWorkflowSettings;
tags?: string[];
pinData?: IPinData;
versionId?: string;
meta?: WorkflowMetadata;
}
export interface IWorkflowDataUpdate {
id?: string;
name?: string;
nodes?: INode[];
connections?: IConnections;
settings?: IWorkflowSettings;
active?: boolean;
tags?: ITag[] | string[]; // string[] when store or requested, ITag[] from API response
pinData?: IPinData;
versionId?: string;
meta?: WorkflowMetadata;
parentFolderId?: string;
}
export interface IWorkflowDataCreate extends IWorkflowDataUpdate {
projectId?: string;
}
/** /**
* Workflow data with mandatory `templateId` * Workflow data with mandatory `templateId`
* This is used to identify sample workflows that we create for onboarding * This is used to identify sample workflows that we create for onboarding
*/ */
export interface WorkflowDataWithTemplateId extends Omit<IWorkflowDataCreate, 'meta'> { export interface WorkflowDataWithTemplateId extends Omit<WorkflowDataCreate, 'meta'> {
meta: WorkflowMetadata & { meta: WorkflowMetadata & {
templateId: Required<WorkflowMetadata>['templateId']; templateId: Required<WorkflowMetadata>['templateId'];
}; };
} }
export interface IWorkflowToShare extends IWorkflowDataUpdate { export interface IWorkflowToShare extends WorkflowDataUpdate {
meta: WorkflowMetadata; meta: WorkflowMetadata;
} }
@@ -281,38 +255,10 @@ export interface NewWorkflowResponse {
defaultSettings: IWorkflowSettings; defaultSettings: IWorkflowSettings;
} }
export interface IWorkflowTemplateNode
extends Pick<
INodeUi,
'name' | 'type' | 'position' | 'parameters' | 'typeVersion' | 'webhookId' | 'id' | 'disabled'
> {
// The credentials in a template workflow have a different type than in a regular workflow
credentials?: IWorkflowTemplateNodeCredentials;
}
export interface IWorkflowTemplateNodeCredentials {
[key: string]: string | INodeCredentialsDetails;
}
export interface IWorkflowTemplate {
id: number;
name: string;
workflow: Pick<IWorkflowData, 'connections' | 'settings' | 'pinData'> & {
nodes: IWorkflowTemplateNode[];
};
}
export interface INewWorkflowData { export interface INewWorkflowData {
name: string; name: string;
} }
export interface WorkflowMetadata {
onboardingId?: string;
templateId?: string;
instanceId?: string;
templateCredsSetupCompleted?: boolean;
}
// Almost identical to cli.Interfaces.ts // Almost identical to cli.Interfaces.ts
export interface IWorkflowDb { export interface IWorkflowDb {
id: string; id: string;
@@ -627,93 +573,6 @@ export interface IUserPermissions {
}; };
} }
export interface ITemplatesCollection {
id: number;
name: string;
nodes: ITemplatesNode[];
workflows: Array<{ id: number }>;
}
interface ITemplatesImage {
id: number;
url: string;
}
interface ITemplatesCollectionExtended extends ITemplatesCollection {
description: string | null;
image: ITemplatesImage[];
categories: ITemplatesCategory[];
createdAt: string;
}
export interface ITemplatesCollectionFull extends ITemplatesCollectionExtended {
full: true;
}
export interface ITemplatesCollectionResponse extends ITemplatesCollectionExtended {
workflows: ITemplatesWorkflow[];
}
/**
* A template without the actual workflow definition
*/
export interface ITemplatesWorkflow {
id: number;
createdAt: string;
name: string;
nodes: ITemplatesNode[];
totalViews: number;
user: {
username: string;
};
}
export interface ITemplatesWorkflowInfo {
nodeCount: number;
nodeTypes: {
[key: string]: {
count: number;
};
};
}
export type TemplateSearchFacet = {
field_name: string;
sampled: boolean;
stats: {
total_values: number;
};
counts: Array<{
count: number;
highlighted: string;
value: string;
}>;
};
export interface ITemplatesWorkflowResponse extends ITemplatesWorkflow, IWorkflowTemplate {
description: string | null;
image: ITemplatesImage[];
categories: ITemplatesCategory[];
workflowInfo: ITemplatesWorkflowInfo;
}
/**
* A template with also the full workflow definition
*/
export interface ITemplatesWorkflowFull extends ITemplatesWorkflowResponse {
full: true;
}
export interface ITemplatesQuery {
categories: string[];
search: string;
}
export interface ITemplatesCategory {
id: number;
name: string;
}
export type WorkflowCallerPolicyDefaultOption = 'any' | 'none' | 'workflowsFromAList'; export type WorkflowCallerPolicyDefaultOption = 'any' | 'none' | 'workflowsFromAList';
export interface IWorkflowSettings extends IWorkflowSettingsWorkflow { export interface IWorkflowSettings extends IWorkflowSettingsWorkflow {
@@ -893,13 +752,6 @@ export type NodeTypeSelectedPayload = {
export interface SubcategorizedNodeTypes { export interface SubcategorizedNodeTypes {
[subcategory: string]: INodeCreateElement[]; [subcategory: string]: INodeCreateElement[];
} }
export interface ITag {
id: string;
name: string;
usageCount?: number;
createdAt?: string;
updatedAt?: string;
}
export interface ITagRow { export interface ITagRow {
tag?: ITag; tag?: ITag;
@@ -911,11 +763,6 @@ export interface ITagRow {
canDelete?: boolean; canDelete?: boolean;
} }
export interface ITemplatesNode extends VersionNode {
id: number;
categories?: ITemplatesCategory[];
}
export interface INodeMetadata { export interface INodeMetadata {
parametersLastUpdatedAt?: number; parametersLastUpdatedAt?: number;
pinnedDataLastUpdatedAt?: number; pinnedDataLastUpdatedAt?: number;
@@ -1130,28 +977,6 @@ export interface INodeTypesState {
nodeTypes: NodeTypesByTypeNameAndVersion; nodeTypes: NodeTypesByTypeNameAndVersion;
} }
export interface ITemplateState {
categories: ITemplatesCategory[];
collections: { [id: string]: ITemplatesCollection };
workflows: { [id: string]: ITemplatesWorkflow | ITemplatesWorkflowFull };
workflowSearches: {
[search: string]: {
workflowIds: string[];
totalWorkflows: number;
loadingMore?: boolean;
categories?: ITemplatesCategory[];
};
};
collectionSearches: {
[search: string]: {
collectionIds: string[];
};
};
currentSessionId: string;
previousSessionId: string;
currentN8nPath: string;
}
export interface IVersionsState { export interface IVersionsState {
versionNotificationSettings: IVersionNotificationSettings; versionNotificationSettings: IVersionNotificationSettings;
nextVersions: Version[]; nextVersions: Version[];

View File

@@ -1,5 +1,5 @@
import { Factory } from 'miragejs'; import { Factory } from 'miragejs';
import type { ITag } from '@/Interface'; import type { ITag } from '@n8n/rest-api-client/api/tags';
import { faker } from '@faker-js/faker'; import { faker } from '@faker-js/faker';
export const tagFactory = Factory.extend<ITag>({ export const tagFactory = Factory.extend<ITag>({

View File

@@ -1,4 +1,4 @@
import type { ITag } from '@/Interface'; import type { ITag } from '@n8n/rest-api-client/api/tags';
export const tags: ITag[] = [ export const tags: ITag[] = [
{ {
id: '1', id: '1',

View File

@@ -1,4 +1,4 @@
import type { ITag } from '@/Interface'; import type { ITag } from '@n8n/rest-api-client/api/tags';
import { Model } from 'miragejs'; import { Model } from 'miragejs';
import type { ModelDefinition } from 'miragejs/-types'; import type { ModelDefinition } from 'miragejs/-types';

View File

@@ -1,4 +1,4 @@
import type { ITag } from '@/Interface'; import type { ITag } from '@n8n/rest-api-client/api/tags';
import type { IRestApiContext } from '@n8n/rest-api-client'; import type { IRestApiContext } from '@n8n/rest-api-client';
import { makeRestApiRequest } from '@n8n/rest-api-client'; import { makeRestApiRequest } from '@n8n/rest-api-client';
import type { CreateOrUpdateTagRequestDto, RetrieveTagQueryDto } from '@n8n/api-types'; import type { CreateOrUpdateTagRequestDto, RetrieveTagQueryDto } from '@n8n/api-types';

View File

@@ -1,86 +0,0 @@
import type { RawAxiosRequestHeaders } from 'axios';
import type {
ITemplatesCategory,
ITemplatesCollection,
ITemplatesQuery,
ITemplatesWorkflow,
ITemplatesCollectionResponse,
ITemplatesWorkflowResponse,
IWorkflowTemplate,
TemplateSearchFacet,
} from '@/Interface';
import { get } from '@n8n/rest-api-client';
function stringifyArray(arr: string[]) {
return arr.join(',');
}
export async function testHealthEndpoint(apiEndpoint: string) {
return await get(apiEndpoint, '/health');
}
export async function getCategories(
apiEndpoint: string,
headers?: RawAxiosRequestHeaders,
): Promise<{ categories: ITemplatesCategory[] }> {
return await get(apiEndpoint, '/templates/categories', undefined, headers);
}
export async function getCollections(
apiEndpoint: string,
query: ITemplatesQuery,
headers?: RawAxiosRequestHeaders,
): Promise<{ collections: ITemplatesCollection[] }> {
return await get(
apiEndpoint,
'/templates/collections',
{ category: query.categories, search: query.search },
headers,
);
}
export async function getWorkflows(
apiEndpoint: string,
query: { page: number; limit: number; categories: string[]; search: string },
headers?: RawAxiosRequestHeaders,
): Promise<{
totalWorkflows: number;
workflows: ITemplatesWorkflow[];
filters: TemplateSearchFacet[];
}> {
return await get(
apiEndpoint,
'/templates/search',
{
page: query.page,
rows: query.limit,
category: stringifyArray(query.categories),
search: query.search,
},
headers,
);
}
export async function getCollectionById(
apiEndpoint: string,
collectionId: string,
headers?: RawAxiosRequestHeaders,
): Promise<{ collection: ITemplatesCollectionResponse }> {
return await get(apiEndpoint, `/templates/collections/${collectionId}`, undefined, headers);
}
export async function getTemplateById(
apiEndpoint: string,
templateId: string,
headers?: RawAxiosRequestHeaders,
): Promise<{ workflow: ITemplatesWorkflowResponse }> {
return await get(apiEndpoint, `/templates/workflows/${templateId}`, undefined, headers);
}
export async function getWorkflowTemplate(
apiEndpoint: string,
templateId: string,
headers?: RawAxiosRequestHeaders,
): Promise<IWorkflowTemplate> {
return await get(apiEndpoint, `/workflows/templates/${templateId}`, undefined, headers);
}

View File

@@ -4,7 +4,7 @@ import { useUsersStore } from '@/stores/users.store';
import { computed, watch, ref, onBeforeUnmount } from 'vue'; import { computed, watch, ref, onBeforeUnmount } from 'vue';
import AskAssistantChat from '@n8n/design-system/components/AskAssistantChat/AskAssistantChat.vue'; import AskAssistantChat from '@n8n/design-system/components/AskAssistantChat/AskAssistantChat.vue';
import { useTelemetry } from '@/composables/useTelemetry'; import { useTelemetry } from '@/composables/useTelemetry';
import type { IWorkflowDataUpdate } from '@/Interface'; import type { WorkflowDataUpdate } from '@n8n/rest-api-client/api/workflows';
import { nodeViewEventBus } from '@/event-bus'; import { nodeViewEventBus } from '@/event-bus';
import { v4 as uuid } from 'uuid'; import { v4 as uuid } from 'uuid';
import { useI18n } from '@n8n/i18n'; import { useI18n } from '@n8n/i18n';
@@ -37,7 +37,7 @@ async function onUserMessage(content: string) {
await builderStore.initBuilderChat(content, 'chat'); await builderStore.initBuilderChat(content, 'chat');
} }
function fixWorkflowStickiesPosition(workflowData: IWorkflowDataUpdate): IWorkflowDataUpdate { function fixWorkflowStickiesPosition(workflowData: WorkflowDataUpdate): WorkflowDataUpdate {
const STICKY_WIDTH = 480; const STICKY_WIDTH = 480;
const HEADERS_HEIGHT = 40; const HEADERS_HEIGHT = 40;
const NEW_LINE_HEIGHT = 20; const NEW_LINE_HEIGHT = 20;
@@ -76,7 +76,7 @@ function fixWorkflowStickiesPosition(workflowData: IWorkflowDataUpdate): IWorkfl
} }
function onInsertWorkflow(code: string) { function onInsertWorkflow(code: string) {
let workflowData: IWorkflowDataUpdate; let workflowData: WorkflowDataUpdate;
try { try {
workflowData = JSON.parse(code); workflowData = JSON.parse(code);
} catch (error) { } catch (error) {

View File

@@ -6,7 +6,7 @@ import WorkflowTagsDropdown from '@/components/WorkflowTagsDropdown.vue';
import Modal from '@/components/Modal.vue'; import Modal from '@/components/Modal.vue';
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 type { IWorkflowDataUpdate } from '@/Interface'; import type { WorkflowDataUpdate } from '@n8n/rest-api-client/api/workflows';
import { createEventBus, type EventBus } from '@n8n/utils/event-bus'; import { createEventBus, type EventBus } from '@n8n/utils/event-bus';
import { useCredentialsStore } from '@/stores/credentials.store'; import { useCredentialsStore } from '@/stores/credentials.store';
import { useWorkflowHelpers } from '@/composables/useWorkflowHelpers'; import { useWorkflowHelpers } from '@/composables/useWorkflowHelpers';
@@ -86,7 +86,7 @@ const save = async (): Promise<void> => {
isSaving.value = true; isSaving.value = true;
try { try {
let workflowToUpdate: IWorkflowDataUpdate | undefined; let workflowToUpdate: WorkflowDataUpdate | undefined;
if (currentWorkflowId !== PLACEHOLDER_EMPTY_WORKFLOW_ID) { if (currentWorkflowId !== PLACEHOLDER_EMPTY_WORKFLOW_ID) {
const { const {
createdAt, createdAt,

View File

@@ -47,10 +47,10 @@ import { computed, ref, useCssModule, useTemplateRef, watch } from 'vue';
import type { import type {
ActionDropdownItem, ActionDropdownItem,
FolderShortInfo, FolderShortInfo,
IWorkflowDataUpdate,
IWorkflowDb, IWorkflowDb,
IWorkflowToShare, IWorkflowToShare,
} from '@/Interface'; } from '@/Interface';
import type { WorkflowDataUpdate } from '@n8n/rest-api-client/api/workflows';
import { usePageRedirectionHelper } from '@/composables/usePageRedirectionHelper'; import { usePageRedirectionHelper } from '@/composables/usePageRedirectionHelper';
import { useTelemetry } from '@/composables/useTelemetry'; import { useTelemetry } from '@/composables/useTelemetry';
import type { PathItem } from '@n8n/design-system/components/N8nBreadcrumbs/Breadcrumbs.vue'; import type { PathItem } from '@n8n/design-system/components/N8nBreadcrumbs/Breadcrumbs.vue';
@@ -407,7 +407,7 @@ async function handleFileImport(): Promise<void> {
if (inputRef?.files && inputRef.files.length !== 0) { if (inputRef?.files && inputRef.files.length !== 0) {
const reader = new FileReader(); const reader = new FileReader();
reader.onload = () => { reader.onload = () => {
let workflowData: IWorkflowDataUpdate; let workflowData: WorkflowDataUpdate;
try { try {
workflowData = JSON.parse(reader.result as string); workflowData = JSON.parse(reader.result as string);
} catch (error) { } catch (error) {

View File

@@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed } from 'vue'; import { computed } from 'vue';
import NodeIcon from '@/components/NodeIcon.vue'; import NodeIcon from '@/components/NodeIcon.vue';
import type { ITemplatesNode } from '@/Interface'; import type { ITemplatesNode } from '@n8n/rest-api-client/api/templates';
import { filterTemplateNodes } from '@/utils/nodeTypesUtils'; import { filterTemplateNodes } from '@/utils/nodeTypesUtils';
const props = withDefaults( const props = withDefaults(

View File

@@ -1,7 +1,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { ref, computed, onMounted, onBeforeUnmount, nextTick } from 'vue'; import { ref, computed, onMounted, onBeforeUnmount, nextTick } from 'vue';
import type { ComponentInstance } from 'vue'; import type { ComponentInstance } from 'vue';
import type { ITag } from '@/Interface'; import type { ITag } from '@n8n/rest-api-client/api/tags';
import IntersectionObserver from './IntersectionObserver.vue'; import IntersectionObserver from './IntersectionObserver.vue';
import IntersectionObserved from './IntersectionObserved.vue'; import IntersectionObserved from './IntersectionObserved.vue';
import { createEventBus } from '@n8n/utils/event-bus'; import { createEventBus } from '@n8n/utils/event-bus';

View File

@@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'; import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue';
import { onClickOutside } from '@vueuse/core'; import { onClickOutside } from '@vueuse/core';
import type { ITag } from '@/Interface'; import type { ITag } from '@n8n/rest-api-client/api/tags';
import { MAX_TAG_NAME_LENGTH } from '@/constants'; import { MAX_TAG_NAME_LENGTH } from '@/constants';
import { N8nOption, N8nSelect } from '@n8n/design-system'; import { N8nOption, N8nSelect } from '@n8n/design-system';
import type { EventBus } from '@n8n/utils/event-bus'; import type { EventBus } from '@n8n/utils/event-bus';

View File

@@ -4,7 +4,7 @@ import { useI18n } from '@n8n/i18n';
import { useToast } from '@/composables/useToast'; import { useToast } from '@/composables/useToast';
import { useAnnotationTagsStore } from '@/stores/tags.store'; import { useAnnotationTagsStore } from '@/stores/tags.store';
import TagsManager from './TagsManager.vue'; import TagsManager from './TagsManager.vue';
import type { ITag } from '@/Interface'; import type { ITag } from '@n8n/rest-api-client/api/tags';
import { ANNOTATION_TAGS_MANAGER_MODAL_KEY } from '@/constants'; import { ANNOTATION_TAGS_MANAGER_MODAL_KEY } from '@/constants';
const i18n = useI18n(); const i18n = useI18n();

View File

@@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, onMounted } from 'vue'; import { ref, computed, onMounted } from 'vue';
import type { ITag } from '@/Interface'; import type { ITag } from '@n8n/rest-api-client/api/tags';
import TagsView from '@/components/TagsManager/TagsView/TagsView.vue'; import TagsView from '@/components/TagsManager/TagsView/TagsView.vue';
import NoTagsView from '@/components/TagsManager/NoTagsView.vue'; import NoTagsView from '@/components/TagsManager/NoTagsView.vue';
import Modal from '@/components/Modal.vue'; import Modal from '@/components/Modal.vue';

View File

@@ -1,6 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed } from 'vue'; import { ref, computed } from 'vue';
import type { ITag, ITagRow } from '@/Interface'; import type { ITag } from '@n8n/rest-api-client/api/tags';
import type { ITagRow } from '@/Interface';
import { useI18n } from '@n8n/i18n'; import { useI18n } from '@n8n/i18n';
import TagsTableHeader from '@/components/TagsManager/TagsView/TagsTableHeader.vue'; import TagsTableHeader from '@/components/TagsManager/TagsView/TagsTableHeader.vue';
import TagsTable from '@/components/TagsManager/TagsView/TagsTable.vue'; import TagsTable from '@/components/TagsManager/TagsView/TagsTable.vue';

View File

@@ -4,7 +4,7 @@ import { useI18n } from '@n8n/i18n';
import { useToast } from '@/composables/useToast'; import { useToast } from '@/composables/useToast';
import { useTagsStore } from '@/stores/tags.store'; import { useTagsStore } from '@/stores/tags.store';
import TagsManager from './TagsManager.vue'; import TagsManager from './TagsManager.vue';
import type { ITag } from '@/Interface'; import type { ITag } from '@n8n/rest-api-client/api/tags';
import { TAGS_MANAGER_MODAL_KEY } from '@/constants'; import { TAGS_MANAGER_MODAL_KEY } from '@/constants';
const i18n = useI18n(); const i18n = useI18n();

View File

@@ -2,7 +2,7 @@
import { abbreviateNumber } from '@/utils/typesUtils'; import { abbreviateNumber } from '@/utils/typesUtils';
import NodeList from './NodeList.vue'; import NodeList from './NodeList.vue';
import TimeAgo from '@/components/TimeAgo.vue'; import TimeAgo from '@/components/TimeAgo.vue';
import type { ITemplatesWorkflow } from '@/Interface'; import type { ITemplatesWorkflow } from '@n8n/rest-api-client/api/templates';
import { useI18n } from '@n8n/i18n'; import { useI18n } from '@n8n/i18n';
import type { BaseTextKey } from '@n8n/i18n'; import type { BaseTextKey } from '@n8n/i18n';

View File

@@ -8,7 +8,7 @@ import type {
ITemplatesCollectionFull, ITemplatesCollectionFull,
ITemplatesNode, ITemplatesNode,
ITemplatesWorkflow, ITemplatesWorkflow,
} from '@/Interface'; } from '@n8n/rest-api-client/api/templates';
import { useTemplatesStore } from '@/stores/templates.store'; import { useTemplatesStore } from '@/stores/templates.store';
import TimeAgo from '@/components/TimeAgo.vue'; import TimeAgo from '@/components/TimeAgo.vue';
import { isFullTemplatesCollection, isTemplatesWorkflow } from '@/utils/templates/typeGuards'; import { isFullTemplatesCollection, isTemplatesWorkflow } from '@/utils/templates/typeGuards';

View File

@@ -1,6 +1,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import { computed, ref, watch } from 'vue'; import { computed, ref, watch } from 'vue';
import type { ITemplatesCategory } from '@/Interface'; import type { ITemplatesCategory } from '@n8n/rest-api-client/api/templates';
import { useI18n } from '@n8n/i18n'; import { useI18n } from '@n8n/i18n';
interface Props { interface Props {

View File

@@ -1,7 +1,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { onBeforeUnmount, onMounted, ref } from 'vue'; import { onBeforeUnmount, onMounted, ref } from 'vue';
import TemplateCard from './TemplateCard.vue'; import TemplateCard from './TemplateCard.vue';
import type { ITemplatesWorkflow } from '@/Interface'; import type { ITemplatesWorkflow } from '@n8n/rest-api-client/api/templates';
import { useI18n } from '@n8n/i18n'; import { useI18n } from '@n8n/i18n';
interface Props { interface Props {

View File

@@ -2,7 +2,7 @@
import Card from '@/components/CollectionWorkflowCard.vue'; import Card from '@/components/CollectionWorkflowCard.vue';
import NodeList from '@/components/NodeList.vue'; import NodeList from '@/components/NodeList.vue';
import { useI18n } from '@n8n/i18n'; import { useI18n } from '@n8n/i18n';
import type { ITemplatesCollection } from '@/Interface'; import type { ITemplatesCollection } from '@n8n/rest-api-client/api/templates';
withDefaults( withDefaults(
defineProps<{ defineProps<{

View File

@@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { nextTick, onBeforeMount, onMounted, ref, watch } from 'vue'; import { nextTick, onBeforeMount, onMounted, ref, watch } from 'vue';
import type { ITemplatesCollection } from '@/Interface'; import type { ITemplatesCollection } from '@n8n/rest-api-client/api/templates';
import Card from '@/components/CollectionWorkflowCard.vue'; import Card from '@/components/CollectionWorkflowCard.vue';
import TemplatesInfoCard from '@/components/TemplatesInfoCard.vue'; import TemplatesInfoCard from '@/components/TemplatesInfoCard.vue';
import { VueAgile } from 'vue-agile'; import { VueAgile } from 'vue-agile';

View File

@@ -2,7 +2,8 @@
import { onMounted, onBeforeUnmount, ref, computed, watch } from 'vue'; import { onMounted, onBeforeUnmount, ref, computed, watch } from 'vue';
import { useI18n } from '@n8n/i18n'; import { useI18n } from '@n8n/i18n';
import { useToast } from '@/composables/useToast'; import { useToast } from '@/composables/useToast';
import type { IWorkflowDb, IWorkflowTemplate } from '@/Interface'; import type { IWorkflowDb } from '@/Interface';
import type { IWorkflowTemplate } from '@n8n/rest-api-client/api/templates';
import { useExecutionsStore } from '@/stores/executions.store'; import { useExecutionsStore } from '@/stores/executions.store';
const props = withDefaults( const props = withDefaults(

View File

@@ -22,7 +22,7 @@ import { useProjectsStore } from '@/stores/projects.store';
import { useTelemetry } from '@/composables/useTelemetry'; import { useTelemetry } from '@/composables/useTelemetry';
import { VIEWS } from '@/constants'; import { VIEWS } from '@/constants';
import { SAMPLE_SUBWORKFLOW_TRIGGER_ID, SAMPLE_SUBWORKFLOW_WORKFLOW } from '@/constants.workflows'; import { SAMPLE_SUBWORKFLOW_TRIGGER_ID, SAMPLE_SUBWORKFLOW_WORKFLOW } from '@/constants.workflows';
import type { IWorkflowDataCreate } from '@/Interface'; import type { WorkflowDataCreate } from '@n8n/rest-api-client/api/workflows';
import { useDocumentVisibility } from '@/composables/useDocumentVisibility'; import { useDocumentVisibility } from '@/composables/useDocumentVisibility';
export interface Props { export interface Props {
@@ -36,7 +36,7 @@ export interface Props {
forceShowExpression?: boolean; forceShowExpression?: boolean;
parameterIssues?: string[]; parameterIssues?: string[];
parameter: INodeProperties; parameter: INodeProperties;
sampleWorkflow?: IWorkflowDataCreate; sampleWorkflow?: WorkflowDataCreate;
newResourceLabel?: string; newResourceLabel?: string;
} }
@@ -254,7 +254,7 @@ const onAddResourceClicked = async () => {
(w) => w.name && new RegExp(workflowName).test(w.name), (w) => w.name && new RegExp(workflowName).test(w.name),
); );
const workflow: IWorkflowDataCreate = { const workflow: WorkflowDataCreate = {
...sampleWorkflow, ...sampleWorkflow,
name: `${workflowName} ${sampleSubWorkflows.length + 1}`, name: `${workflowName} ${sampleSubWorkflows.length + 1}`,
}; };

View File

@@ -2,12 +2,8 @@
import { ref, computed, onMounted } from 'vue'; import { ref, computed, onMounted } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { useToast } from '@/composables/useToast'; import { useToast } from '@/composables/useToast';
import type { import type { ITimeoutHMS, IWorkflowSettings, IWorkflowShortResponse } from '@/Interface';
ITimeoutHMS, import type { WorkflowDataUpdate } from '@n8n/rest-api-client/api/workflows';
IWorkflowDataUpdate,
IWorkflowSettings,
IWorkflowShortResponse,
} from '@/Interface';
import Modal from '@/components/Modal.vue'; import Modal from '@/components/Modal.vue';
import { import {
EnterpriseEditionFeature, EnterpriseEditionFeature,
@@ -298,7 +294,7 @@ const convertToHMS = (num: number): ITimeoutHMS => {
const saveSettings = async () => { const saveSettings = async () => {
// Set that the active state should be changed // Set that the active state should be changed
const data: IWorkflowDataUpdate & { settings: IWorkflowSettings } = { const data: WorkflowDataUpdate & { settings: IWorkflowSettings } = {
settings: workflowSettings.value, settings: workflowSettings.value,
}; };

View File

@@ -2,7 +2,7 @@
import { computed } from 'vue'; import { computed } from 'vue';
import TagsContainer from './TagsContainer.vue'; import TagsContainer from './TagsContainer.vue';
import { useTagsStore } from '@/stores/tags.store'; import { useTagsStore } from '@/stores/tags.store';
import type { ITag } from '@/Interface'; import type { ITag } from '@n8n/rest-api-client/api/tags';
interface Props { interface Props {
tagIds: string[]; tagIds: string[];

View File

@@ -14,7 +14,8 @@ import { useRoute, useRouter } from 'vue-router';
import type { BaseTextKey } from '@n8n/i18n'; import type { BaseTextKey } from '@n8n/i18n';
import type { Scope } from '@n8n/permissions'; import type { Scope } from '@n8n/permissions';
import type { BaseFolderItem, BaseResource, ITag, ResourceParentFolder } from '@/Interface'; import type { ITag } from '@n8n/rest-api-client/api/tags';
import type { BaseFolderItem, BaseResource, ResourceParentFolder } from '@/Interface';
import { isSharedResource, isResourceSortableByDate } from '@/utils/typeGuards'; import { isSharedResource, isResourceSortableByDate } from '@/utils/typeGuards';
import { useN8nLocalStorage } from '@/composables/useN8nLocalStorage'; import { useN8nLocalStorage } from '@/composables/useN8nLocalStorage';

View File

@@ -11,14 +11,8 @@ import { NodeConnectionTypes, NodeHelpers, UserError } from 'n8n-workflow';
import { useCanvasOperations } from '@/composables/useCanvasOperations'; import { useCanvasOperations } from '@/composables/useCanvasOperations';
import type { CanvasConnection, CanvasNode } from '@/types'; import type { CanvasConnection, CanvasNode } from '@/types';
import { CanvasConnectionMode } from '@/types'; import { CanvasConnectionMode } from '@/types';
import type { import type { ICredentialsResponse, IExecutionResponse, INodeUi, IWorkflowDb } from '@/Interface';
ICredentialsResponse, import type { IWorkflowTemplate, IWorkflowTemplateNode } from '@n8n/rest-api-client/api/templates';
IExecutionResponse,
INodeUi,
IWorkflowDb,
IWorkflowTemplate,
IWorkflowTemplateNode,
} from '@/Interface';
import { RemoveNodeCommand, ReplaceNodeParametersCommand } from '@/models/history'; import { RemoveNodeCommand, ReplaceNodeParametersCommand } from '@/models/history';
import { useWorkflowsStore } from '@/stores/workflows.store'; import { useWorkflowsStore } from '@/stores/workflows.store';
import { useUIStore } from '@/stores/ui.store'; import { useUIStore } from '@/stores/ui.store';

View File

@@ -7,15 +7,14 @@ import type {
AddedNodesAndConnections, AddedNodesAndConnections,
IExecutionResponse, IExecutionResponse,
INodeUi, INodeUi,
ITag,
IUsedCredential, IUsedCredential,
IWorkflowData,
IWorkflowDataUpdate,
IWorkflowDb, IWorkflowDb,
IWorkflowTemplate,
WorkflowDataWithTemplateId, WorkflowDataWithTemplateId,
XYPosition, XYPosition,
} from '@/Interface'; } from '@/Interface';
import type { ITag } from '@n8n/rest-api-client/api/tags';
import type { IWorkflowTemplate } from '@n8n/rest-api-client/api/templates';
import type { WorkflowData, WorkflowDataUpdate } from '@n8n/rest-api-client/api/workflows';
import { useDataSchema } from '@/composables/useDataSchema'; import { useDataSchema } from '@/composables/useDataSchema';
import { useExternalHooks } from '@/composables/useExternalHooks'; import { useExternalHooks } from '@/composables/useExternalHooks';
import { useI18n } from '@n8n/i18n'; import { useI18n } from '@n8n/i18n';
@@ -1627,7 +1626,7 @@ export function useCanvasOperations() {
* Import operations * Import operations
*/ */
function removeUnknownCredentials(workflow: IWorkflowDataUpdate) { function removeUnknownCredentials(workflow: WorkflowDataUpdate) {
if (!workflow?.nodes) return; if (!workflow?.nodes) return;
for (const node of workflow.nodes) { for (const node of workflow.nodes) {
@@ -1644,9 +1643,9 @@ export function useCanvasOperations() {
} }
async function addImportedNodesToWorkflow( async function addImportedNodesToWorkflow(
data: IWorkflowDataUpdate, data: WorkflowDataUpdate,
{ trackBulk = true, trackHistory = false, viewport = DEFAULT_VIEWPORT_BOUNDARIES } = {}, { trackBulk = true, trackHistory = false, viewport = DEFAULT_VIEWPORT_BOUNDARIES } = {},
): Promise<IWorkflowDataUpdate> { ): Promise<WorkflowDataUpdate> {
// Because nodes with the same name maybe already exist, it could // Because nodes with the same name maybe already exist, it could
// be needed that they have to be renamed. Also could it be possible // be needed that they have to be renamed. Also could it be possible
// that nodes are not allowed to be created because they have a create // that nodes are not allowed to be created because they have a create
@@ -1818,7 +1817,7 @@ export function useCanvasOperations() {
} }
async function importWorkflowData( async function importWorkflowData(
workflowData: IWorkflowDataUpdate, workflowData: WorkflowDataUpdate,
source: string, source: string,
{ {
importTags = true, importTags = true,
@@ -1831,7 +1830,7 @@ export function useCanvasOperations() {
trackHistory?: boolean; trackHistory?: boolean;
viewport?: ViewportBoundaries; viewport?: ViewportBoundaries;
} = {}, } = {},
): Promise<IWorkflowDataUpdate> { ): Promise<WorkflowDataUpdate> {
uiStore.resetLastInteractedWith(); uiStore.resetLastInteractedWith();
// If it is JSON check if it looks on the first look like data we can use // If it is JSON check if it looks on the first look like data we can use
@@ -1947,7 +1946,7 @@ export function useCanvasOperations() {
} }
} }
async function importWorkflowTags(workflowData: IWorkflowDataUpdate) { async function importWorkflowTags(workflowData: WorkflowDataUpdate) {
const allTags = await tagsStore.fetchAll(); const allTags = await tagsStore.fetchAll();
const tagNames = new Set(allTags.map((tag) => tag.name)); const tagNames = new Set(allTags.map((tag) => tag.name));
@@ -1978,8 +1977,8 @@ export function useCanvasOperations() {
workflowsStore.addWorkflowTagIds(tagIds); workflowsStore.addWorkflowTagIds(tagIds);
} }
async function fetchWorkflowDataFromUrl(url: string): Promise<IWorkflowDataUpdate | undefined> { async function fetchWorkflowDataFromUrl(url: string): Promise<WorkflowDataUpdate | undefined> {
let workflowData: IWorkflowDataUpdate; let workflowData: WorkflowDataUpdate;
canvasStore.startLoading(); canvasStore.startLoading();
try { try {
@@ -1994,12 +1993,12 @@ export function useCanvasOperations() {
return workflowData; return workflowData;
} }
function getNodesToSave(nodes: INode[]): IWorkflowData { function getNodesToSave(nodes: INode[]): WorkflowData {
const data = { const data = {
nodes: [] as INodeUi[], nodes: [] as INodeUi[],
connections: {} as IConnections, connections: {} as IConnections,
pinData: {} as IPinData, pinData: {} as IPinData,
} satisfies IWorkflowData; } satisfies WorkflowData;
const exportedNodeNames = new Set<string>(); const exportedNodeNames = new Set<string>();

View File

@@ -14,7 +14,8 @@ import type {
} from 'n8n-workflow'; } from 'n8n-workflow';
import { useRunWorkflow } from '@/composables/useRunWorkflow'; import { useRunWorkflow } from '@/composables/useRunWorkflow';
import type { IExecutionResponse, IStartRunData, IWorkflowData } from '@/Interface'; import type { IExecutionResponse, IStartRunData } from '@/Interface';
import type { WorkflowData } from '@n8n/rest-api-client/api/workflows';
import { useWorkflowsStore } from '@/stores/workflows.store'; import { useWorkflowsStore } from '@/stores/workflows.store';
import { useUIStore } from '@/stores/ui.store'; import { useUIStore } from '@/stores/ui.store';
import { useWorkflowHelpers } from '@/composables/useWorkflowHelpers'; import { useWorkflowHelpers } from '@/composables/useWorkflowHelpers';
@@ -244,7 +245,7 @@ describe('useRunWorkflow({ router })', () => {
disabled: false, disabled: false,
}, },
], ],
} as unknown as IWorkflowData); } as unknown as WorkflowData);
const result = await runWorkflow({}); const result = await runWorkflow({});
@@ -278,7 +279,7 @@ describe('useRunWorkflow({ router })', () => {
pinData: { pinData: {
Slack: [{ json: { value: 'data2' } }], Slack: [{ json: { value: 'data2' } }],
}, },
} as unknown as IWorkflowData); } as unknown as WorkflowData);
const mockExecutionResponse = { executionId: '123' }; const mockExecutionResponse = { executionId: '123' };
@@ -291,7 +292,7 @@ describe('useRunWorkflow({ router })', () => {
vi.mocked(workflowHelpers).getWorkflowDataToSave.mockResolvedValue({ vi.mocked(workflowHelpers).getWorkflowDataToSave.mockResolvedValue({
id: 'workflowId', id: 'workflowId',
nodes: [], nodes: [],
} as unknown as IWorkflowData); } as unknown as WorkflowData);
vi.mocked(workflowsStore).getWorkflowRunData = { vi.mocked(workflowsStore).getWorkflowRunData = {
NodeName: [], NodeName: [],
}; };
@@ -328,7 +329,7 @@ describe('useRunWorkflow({ router })', () => {
vi.mocked(workflowHelpers).getWorkflowDataToSave.mockResolvedValue({ vi.mocked(workflowHelpers).getWorkflowDataToSave.mockResolvedValue({
id: 'workflowId', id: 'workflowId',
nodes: [], nodes: [],
} as unknown as IWorkflowData); } as unknown as WorkflowData);
vi.mocked(workflowsStore).getWorkflowRunData = { vi.mocked(workflowsStore).getWorkflowRunData = {
NodeName: [], NodeName: [],
}; };
@@ -350,7 +351,7 @@ describe('useRunWorkflow({ router })', () => {
vi.mocked(workflowHelpers).getWorkflowDataToSave.mockResolvedValue({ vi.mocked(workflowHelpers).getWorkflowDataToSave.mockResolvedValue({
id: 'workflowId', id: 'workflowId',
nodes: [], nodes: [],
} as unknown as IWorkflowData); } as unknown as WorkflowData);
vi.mocked(workflowsStore).getWorkflowRunData = { vi.mocked(workflowsStore).getWorkflowRunData = {
NodeName: [], NodeName: [],
}; };
@@ -391,7 +392,7 @@ describe('useRunWorkflow({ router })', () => {
vi.mocked(workflowHelpers).getWorkflowDataToSave.mockResolvedValue({ vi.mocked(workflowHelpers).getWorkflowDataToSave.mockResolvedValue({
id: 'workflowId', id: 'workflowId',
nodes: [], nodes: [],
} as unknown as IWorkflowData); } as unknown as WorkflowData);
vi.mocked(workflowsStore).getWorkflowRunData = { vi.mocked(workflowsStore).getWorkflowRunData = {
[parentNodeName]: [ [parentNodeName]: [
@@ -465,7 +466,7 @@ describe('useRunWorkflow({ router })', () => {
} as unknown as Workflow); } as unknown as Workflow);
vi.mocked(workflowHelpers).getWorkflowDataToSave.mockResolvedValue({ vi.mocked(workflowHelpers).getWorkflowDataToSave.mockResolvedValue({
nodes: [], nodes: [],
} as unknown as IWorkflowData); } as unknown as WorkflowData);
vi.mocked(workflowHelpers).executeData.mockResolvedValue({ vi.mocked(workflowHelpers).executeData.mockResolvedValue({
data: {}, data: {},
node: {}, node: {},
@@ -496,7 +497,7 @@ describe('useRunWorkflow({ router })', () => {
mock<Workflow>({ getChildNodes: vi.fn().mockReturnValue([]) }), mock<Workflow>({ getChildNodes: vi.fn().mockReturnValue([]) }),
); );
vi.mocked(workflowHelpers).getWorkflowDataToSave.mockResolvedValue( vi.mocked(workflowHelpers).getWorkflowDataToSave.mockResolvedValue(
mock<IWorkflowData>({ nodes: [] }), mock<WorkflowData>({ nodes: [] }),
); );
const { runWorkflow } = composable; const { runWorkflow } = composable;
@@ -527,7 +528,7 @@ describe('useRunWorkflow({ router })', () => {
}), }),
); );
vi.mocked(workflowHelpers).getWorkflowDataToSave.mockResolvedValue( vi.mocked(workflowHelpers).getWorkflowDataToSave.mockResolvedValue(
mock<IWorkflowData>({ nodes: [] }), mock<WorkflowData>({ nodes: [] }),
); );
const { runWorkflow } = composable; const { runWorkflow } = composable;
@@ -566,7 +567,7 @@ describe('useRunWorkflow({ router })', () => {
}), }),
); );
vi.mocked(workflowHelpers).getWorkflowDataToSave.mockResolvedValue( vi.mocked(workflowHelpers).getWorkflowDataToSave.mockResolvedValue(
mock<IWorkflowData>({ nodes: [] }), mock<WorkflowData>({ nodes: [] }),
); );
const { runWorkflow } = composable; const { runWorkflow } = composable;
@@ -594,7 +595,7 @@ describe('useRunWorkflow({ router })', () => {
mock<Workflow>({ getChildNodes: vi.fn().mockReturnValue([]) }), mock<Workflow>({ getChildNodes: vi.fn().mockReturnValue([]) }),
); );
vi.mocked(workflowHelpers).getWorkflowDataToSave.mockResolvedValue( vi.mocked(workflowHelpers).getWorkflowDataToSave.mockResolvedValue(
mock<IWorkflowData>({ nodes: [] }), mock<WorkflowData>({ nodes: [] }),
); );
// ACT // ACT
@@ -625,7 +626,7 @@ describe('useRunWorkflow({ router })', () => {
vi.mocked(workflowsStore).nodesIssuesExist = false; vi.mocked(workflowsStore).nodesIssuesExist = false;
vi.mocked(workflowHelpers).getCurrentWorkflow.mockReturnValue(workflow); vi.mocked(workflowHelpers).getCurrentWorkflow.mockReturnValue(workflow);
vi.mocked(workflowHelpers).getWorkflowDataToSave.mockResolvedValue( vi.mocked(workflowHelpers).getWorkflowDataToSave.mockResolvedValue(
mock<IWorkflowData>({ id: 'workflowId', nodes: [] }), mock<WorkflowData>({ id: 'workflowId', nodes: [] }),
); );
vi.mocked(workflowsStore).getWorkflowRunData = mockRunData; vi.mocked(workflowsStore).getWorkflowRunData = mockRunData;
@@ -738,7 +739,7 @@ describe('useRunWorkflow({ router })', () => {
vi.mocked(workflowsStore).nodesIssuesExist = false; vi.mocked(workflowsStore).nodesIssuesExist = false;
vi.mocked(workflowHelpers).getCurrentWorkflow.mockReturnValue(workflow); vi.mocked(workflowHelpers).getCurrentWorkflow.mockReturnValue(workflow);
vi.mocked(workflowHelpers).getWorkflowDataToSave.mockResolvedValue( vi.mocked(workflowHelpers).getWorkflowDataToSave.mockResolvedValue(
mock<IWorkflowData>({ id: 'workflowId', nodes: [] }), mock<WorkflowData>({ id: 'workflowId', nodes: [] }),
); );
vi.mocked(workflowsStore).getWorkflowRunData = mockRunData; vi.mocked(workflowsStore).getWorkflowRunData = mockRunData;
@@ -767,7 +768,7 @@ describe('useRunWorkflow({ router })', () => {
vi.mocked(workflowsStore).nodesIssuesExist = false; vi.mocked(workflowsStore).nodesIssuesExist = false;
vi.mocked(workflowHelpers).getCurrentWorkflow.mockReturnValue(workflow); vi.mocked(workflowHelpers).getCurrentWorkflow.mockReturnValue(workflow);
vi.mocked(workflowHelpers).getWorkflowDataToSave.mockResolvedValue( vi.mocked(workflowHelpers).getWorkflowDataToSave.mockResolvedValue(
mock<IWorkflowData>({ id: 'workflowId', nodes: [] }), mock<WorkflowData>({ id: 'workflowId', nodes: [] }),
); );
vi.mocked(workflowsStore).getWorkflowRunData = mockRunData; vi.mocked(workflowsStore).getWorkflowRunData = mockRunData;
@@ -789,7 +790,7 @@ describe('useRunWorkflow({ router })', () => {
vi.mocked(workflowHelpers).getWorkflowDataToSave.mockResolvedValue({ vi.mocked(workflowHelpers).getWorkflowDataToSave.mockResolvedValue({
id: workflow.id, id: workflow.id,
nodes: [], nodes: [],
} as unknown as IWorkflowData); } as unknown as WorkflowData);
// Simulate failed execution start // Simulate failed execution start
vi.mocked(workflowsStore).runWorkflow.mockRejectedValueOnce(new Error()); vi.mocked(workflowsStore).runWorkflow.mockRejectedValueOnce(new Error());
@@ -915,7 +916,7 @@ describe('useRunWorkflow({ router })', () => {
vi.mocked(workflowHelpers).getWorkflowDataToSave.mockResolvedValue({ vi.mocked(workflowHelpers).getWorkflowDataToSave.mockResolvedValue({
id: 'workflowId', id: 'workflowId',
nodes: [], nodes: [],
} as unknown as IWorkflowData); } as unknown as WorkflowData);
await runWorkflowComposable.runEntireWorkflow('main', 'foo'); await runWorkflowComposable.runEntireWorkflow('main', 'foo');

View File

@@ -17,7 +17,8 @@ import { VIEWS, WORKFLOW_EXTRACTION_NAME_MODAL_KEY } from '@/constants';
import { useHistoryStore } from '@/stores/history.store'; import { useHistoryStore } from '@/stores/history.store';
import { useCanvasOperations } from './useCanvasOperations'; import { useCanvasOperations } from './useCanvasOperations';
import type { AddedNode, INodeUi, IWorkflowDataCreate, IWorkflowDb } from '@/Interface'; import type { AddedNode, INodeUi, IWorkflowDb } from '@/Interface';
import type { WorkflowDataCreate } from '@n8n/rest-api-client/api/workflows';
import { useI18n } from '@n8n/i18n'; import { useI18n } from '@n8n/i18n';
import { PUSH_NODES_OFFSET } from '@/utils/nodeViewUtils'; import { PUSH_NODES_OFFSET } from '@/utils/nodeViewUtils';
import { useUIStore } from '@/stores/ui.store'; import { useUIStore } from '@/stores/ui.store';
@@ -128,7 +129,7 @@ export function useWorkflowExtraction() {
selectionChildrenVariables: Map<string, string>, selectionChildrenVariables: Map<string, string>,
startNodeName: string, startNodeName: string,
returnNodeName: string, returnNodeName: string,
): IWorkflowDataCreate { ): WorkflowDataCreate {
const newConnections = Object.fromEntries( const newConnections = Object.fromEntries(
Object.entries(connections).filter(([k]) => nodes.some((x) => x.name === k)), Object.entries(connections).filter(([k]) => nodes.some((x) => x.name === k)),
); );
@@ -253,7 +254,7 @@ export function useWorkflowExtraction() {
return [summedUp[0] / summedUp[2], summedUp[1] / summedUp[2]]; return [summedUp[0] / summedUp[2], summedUp[1] / summedUp[2]];
} }
async function tryCreateWorkflow(workflowData: IWorkflowDataCreate): Promise<IWorkflowDb | null> { async function tryCreateWorkflow(workflowData: WorkflowDataCreate): Promise<IWorkflowDb | null> {
try { try {
const createdWorkflow = await workflowsStore.createNewWorkflow(workflowData); const createdWorkflow = await workflowsStore.createNewWorkflow(workflowData);

View File

@@ -1,4 +1,5 @@
import type { IExecutionResponse, IWorkflowData, IWorkflowDb } from '@/Interface'; import type { IExecutionResponse, IWorkflowDb } from '@/Interface';
import type { WorkflowData } from '@n8n/rest-api-client/api/workflows';
import { useWorkflowHelpers } from '@/composables/useWorkflowHelpers'; import { useWorkflowHelpers } from '@/composables/useWorkflowHelpers';
import { createTestingPinia } from '@pinia/testing'; import { createTestingPinia } from '@pinia/testing';
import { setActivePinia } from 'pinia'; import { setActivePinia } from 'pinia';
@@ -358,7 +359,7 @@ describe('useWorkflowHelpers', () => {
uiStore.stateIsDirty = true; uiStore.stateIsDirty = true;
vi.spyOn(workflowHelpers, 'getWorkflowDataToSave').mockResolvedValue({ vi.spyOn(workflowHelpers, 'getWorkflowDataToSave').mockResolvedValue({
nodes: [], nodes: [],
} as unknown as IWorkflowData); } as unknown as WorkflowData);
expect(await workflowHelpers.checkConflictingWebhooks('12345')).toEqual(null); expect(await workflowHelpers.checkConflictingWebhooks('12345')).toEqual(null);
}); });
}); });

View File

@@ -27,14 +27,13 @@ import type {
ICredentialsResponse, ICredentialsResponse,
INodeTypesMaxCount, INodeTypesMaxCount,
INodeUi, INodeUi,
ITag,
IWorkflowData,
IWorkflowDataUpdate,
IWorkflowDb, IWorkflowDb,
TargetItem, TargetItem,
WorkflowTitleStatus, WorkflowTitleStatus,
XYPosition, XYPosition,
} from '@/Interface'; } from '@/Interface';
import type { ITag } from '@n8n/rest-api-client/api/tags';
import type { WorkflowData, WorkflowDataUpdate } from '@n8n/rest-api-client/api/workflows';
import { useNodeHelpers } from '@/composables/useNodeHelpers'; import { useNodeHelpers } from '@/composables/useNodeHelpers';
@@ -510,7 +509,7 @@ export function useWorkflowHelpers() {
nodes.push(nodeData); nodes.push(nodeData);
} }
const data: IWorkflowData = { const data: WorkflowData = {
name: workflowsStore.workflowName, name: workflowsStore.workflowName,
nodes, nodes,
pinData: workflowsStore.pinnedWorkflowData, pinData: workflowsStore.pinnedWorkflowData,
@@ -762,7 +761,7 @@ export function useWorkflowHelpers() {
{ workflowId, active }: { workflowId: string; active?: boolean }, { workflowId, active }: { workflowId: string; active?: boolean },
partialData = false, partialData = false,
) { ) {
let data: IWorkflowDataUpdate = {}; let data: WorkflowDataUpdate = {};
const isCurrentWorkflow = workflowId === workflowsStore.workflowId; const isCurrentWorkflow = workflowId === workflowsStore.workflowId;
if (isCurrentWorkflow) { if (isCurrentWorkflow) {
@@ -796,7 +795,7 @@ export function useWorkflowHelpers() {
// Updates the position of all the nodes that the top-left node // Updates the position of all the nodes that the top-left node
// is at the given position // is at the given position
function updateNodePositions( function updateNodePositions(
workflowData: IWorkflowData | IWorkflowDataUpdate, workflowData: WorkflowData | WorkflowDataUpdate,
position: XYPosition, position: XYPosition,
): void { ): void {
if (workflowData.nodes === undefined) { if (workflowData.nodes === undefined) {
@@ -827,7 +826,7 @@ export function useWorkflowHelpers() {
} }
function removeForeignCredentialsFromWorkflow( function removeForeignCredentialsFromWorkflow(
workflow: IWorkflowData | IWorkflowDataUpdate, workflow: WorkflowData | WorkflowDataUpdate,
usableCredentials: ICredentialsResponse[], usableCredentials: ICredentialsResponse[],
): void { ): void {
(workflow.nodes ?? []).forEach((node: INode) => { (workflow.nodes ?? []).forEach((node: INode) => {

View File

@@ -6,7 +6,7 @@ import { createTestingPinia } from '@pinia/testing';
import { setActivePinia } from 'pinia'; import { setActivePinia } from 'pinia';
import { useNpsSurveyStore } from '@/stores/npsSurvey.store'; import { useNpsSurveyStore } from '@/stores/npsSurvey.store';
import { useWorkflowsStore } from '@/stores/workflows.store'; import { useWorkflowsStore } from '@/stores/workflows.store';
import type { IWorkflowDataUpdate } from '@/Interface'; import type { WorkflowDataUpdate } from '@n8n/rest-api-client/api/workflows';
import { mockedStore } from '@/__tests__/utils'; import { mockedStore } from '@/__tests__/utils';
import { createTestNode, createTestWorkflow, mockNodeTypeDescription } from '@/__tests__/mocks'; import { createTestNode, createTestWorkflow, mockNodeTypeDescription } from '@/__tests__/mocks';
import { CHAT_TRIGGER_NODE_TYPE } from 'n8n-workflow'; import { CHAT_TRIGGER_NODE_TYPE } from 'n8n-workflow';
@@ -22,7 +22,7 @@ vi.mock('@/composables/useMessage', () => {
}; };
}); });
const getDuplicateTestWorkflow = (): IWorkflowDataUpdate => ({ const getDuplicateTestWorkflow = (): WorkflowDataUpdate => ({
name: 'Duplicate webhook test', name: 'Duplicate webhook test',
active: false, active: false,
nodes: [ nodes: [

View File

@@ -15,13 +15,9 @@ import { useWorkflowHelpers } from '@/composables/useWorkflowHelpers';
import { useWorkflowsStore } from '@/stores/workflows.store'; import { useWorkflowsStore } from '@/stores/workflows.store';
import { useSourceControlStore } from '@/stores/sourceControl.store'; import { useSourceControlStore } from '@/stores/sourceControl.store';
import { useCanvasStore } from '@/stores/canvas.store'; import { useCanvasStore } from '@/stores/canvas.store';
import type { import type { IUpdateInformation, NotificationOptions } from '@/Interface';
ITag, import type { ITag } from '@n8n/rest-api-client/api/tags';
IUpdateInformation, import type { WorkflowDataCreate, WorkflowDataUpdate } from '@n8n/rest-api-client/api/workflows';
IWorkflowDataCreate,
IWorkflowDataUpdate,
NotificationOptions,
} from '@/Interface';
import type { IDataObject, INode, IWorkflowSettings } from 'n8n-workflow'; import type { IDataObject, INode, IWorkflowSettings } from 'n8n-workflow';
import { useNodeTypesStore } from '@/stores/nodeTypes.store'; import { useNodeTypesStore } from '@/stores/nodeTypes.store';
import { useToast } from './useToast'; import { useToast } from './useToast';
@@ -134,7 +130,7 @@ export function useWorkflowSaving({ router }: { router: ReturnType<typeof useRou
async function getWorkflowDeactivationInfo( async function getWorkflowDeactivationInfo(
workflowId: string, workflowId: string,
request: IWorkflowDataUpdate, request: WorkflowDataUpdate,
): Promise<Partial<NotificationOptions> | undefined> { ): Promise<Partial<NotificationOptions> | undefined> {
const missingActivatableTriggerNode = const missingActivatableTriggerNode =
request.nodes !== undefined && !request.nodes.some(isNodeActivatable); request.nodes !== undefined && !request.nodes.some(isNodeActivatable);
@@ -187,7 +183,7 @@ export function useWorkflowSaving({ router }: { router: ReturnType<typeof useRou
} }
uiStore.addActiveAction('workflowSaving'); uiStore.addActiveAction('workflowSaving');
const workflowDataRequest: IWorkflowDataUpdate = await getWorkflowDataToSave(); const workflowDataRequest: WorkflowDataUpdate = await getWorkflowDataToSave();
// This can happen if the user has another workflow in the browser history and navigates // This can happen if the user has another workflow in the browser history and navigates
// via the browser back button, encountering our warning dialog with the new route already set // via the browser back button, encountering our warning dialog with the new route already set
if (workflowDataRequest.id !== currentWorkflow) { if (workflowDataRequest.id !== currentWorkflow) {
@@ -306,14 +302,14 @@ export function useWorkflowSaving({ router }: { router: ReturnType<typeof useRou
openInNewWindow?: boolean; openInNewWindow?: boolean;
resetNodeIds?: boolean; resetNodeIds?: boolean;
parentFolderId?: string; parentFolderId?: string;
data?: IWorkflowDataCreate; data?: WorkflowDataCreate;
} = {}, } = {},
redirect = true, redirect = true,
): Promise<boolean> { ): Promise<boolean> {
try { try {
uiStore.addActiveAction('workflowSaving'); uiStore.addActiveAction('workflowSaving');
const workflowDataRequest: IWorkflowDataCreate = data || (await getWorkflowDataToSave()); const workflowDataRequest: WorkflowDataCreate = data || (await getWorkflowDataToSave());
const changedNodes = {} as IDataObject; const changedNodes = {} as IDataObject;
if (resetNodeIds) { if (resetNodeIds) {

View File

@@ -1,8 +1,9 @@
import { NodeConnectionTypes } from 'n8n-workflow'; import { NodeConnectionTypes } from 'n8n-workflow';
import type { INodeUi, IWorkflowDataCreate } from './Interface'; import type { INodeUi } from './Interface';
import type { WorkflowDataCreate } from '@n8n/rest-api-client/api/workflows';
export const SAMPLE_SUBWORKFLOW_TRIGGER_ID = 'c055762a-8fe7-4141-a639-df2372f30060'; export const SAMPLE_SUBWORKFLOW_TRIGGER_ID = 'c055762a-8fe7-4141-a639-df2372f30060';
export const SAMPLE_SUBWORKFLOW_WORKFLOW: IWorkflowDataCreate = { export const SAMPLE_SUBWORKFLOW_WORKFLOW: WorkflowDataCreate = {
name: 'My Sub-Workflow', name: 'My Sub-Workflow',
nodes: [ nodes: [
{ {
@@ -40,7 +41,7 @@ export const SAMPLE_SUBWORKFLOW_WORKFLOW: IWorkflowDataCreate = {
pinData: {}, pinData: {},
}; };
export const SAMPLE_EVALUATION_WORKFLOW: IWorkflowDataCreate = { export const SAMPLE_EVALUATION_WORKFLOW: WorkflowDataCreate = {
name: 'My Evaluation Sub-Workflow', name: 'My Evaluation Sub-Workflow',
nodes: [ nodes: [
{ {

View File

@@ -9,7 +9,7 @@ import type {
import * as eventsApi from '@n8n/rest-api-client/api/events'; import * as eventsApi from '@n8n/rest-api-client/api/events';
import * as settingsApi from '@n8n/rest-api-client/api/settings'; import * as settingsApi from '@n8n/rest-api-client/api/settings';
import * as moduleSettingsApi from '@n8n/rest-api-client/api/module-settings'; import * as moduleSettingsApi from '@n8n/rest-api-client/api/module-settings';
import { testHealthEndpoint } from '@/api/templates'; import { testHealthEndpoint } from '@n8n/rest-api-client/api/templates';
import { import {
INSECURE_CONNECTION_WARNING, INSECURE_CONNECTION_WARNING,
LOCAL_STORAGE_EXPERIMENTAL_DOCKED_NODE_SETTINGS, LOCAL_STORAGE_EXPERIMENTAL_DOCKED_NODE_SETTINGS,

View File

@@ -1,6 +1,6 @@
import { createTagsApi } from '@/api/tags'; import { createTagsApi } from '@/api/tags';
import { STORES } from '@n8n/stores'; import { STORES } from '@n8n/stores';
import type { ITag } from '@/Interface'; import type { ITag } from '@n8n/rest-api-client/api/tags';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { useRootStore } from '@n8n/stores/useRootStore'; import { useRootStore } from '@n8n/stores/useRootStore';
import { computed, ref } from 'vue'; import { computed, ref } from 'vue';

View File

@@ -1,8 +1,10 @@
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { TEMPLATES_URLS } from '@/constants'; import { TEMPLATES_URLS } from '@/constants';
import { STORES } from '@n8n/stores'; import { STORES } from '@n8n/stores';
import type { INodeUi } from '@/Interface';
import { useSettingsStore } from './settings.store';
import * as templatesApi from '@n8n/rest-api-client/api/templates';
import type { import type {
INodeUi,
ITemplatesCategory, ITemplatesCategory,
ITemplatesCollection, ITemplatesCollection,
ITemplatesCollectionFull, ITemplatesCollectionFull,
@@ -10,15 +12,35 @@ import type {
ITemplatesWorkflow, ITemplatesWorkflow,
ITemplatesWorkflowFull, ITemplatesWorkflowFull,
IWorkflowTemplate, IWorkflowTemplate,
} from '@/Interface'; } from '@n8n/rest-api-client/api/templates';
import { useSettingsStore } from './settings.store';
import * as templatesApi from '@/api/templates';
import { getNodesWithNormalizedPosition } from '@/utils/nodeViewUtils'; import { getNodesWithNormalizedPosition } from '@/utils/nodeViewUtils';
import { useRootStore } from '@n8n/stores/useRootStore'; import { useRootStore } from '@n8n/stores/useRootStore';
import { useUsersStore } from './users.store'; import { useUsersStore } from './users.store';
import { useWorkflowsStore } from './workflows.store'; import { useWorkflowsStore } from './workflows.store';
import { computed, ref } from 'vue'; import { computed, ref } from 'vue';
export interface ITemplateState {
categories: ITemplatesCategory[];
collections: { [id: string]: ITemplatesCollection };
workflows: { [id: string]: ITemplatesWorkflow | ITemplatesWorkflowFull };
workflowSearches: {
[search: string]: {
workflowIds: string[];
totalWorkflows: number;
loadingMore?: boolean;
categories?: ITemplatesCategory[];
};
};
collectionSearches: {
[search: string]: {
collectionIds: string[];
};
};
currentSessionId: string;
previousSessionId: string;
currentN8nPath: string;
}
const TEMPLATES_PAGE_SIZE = 20; const TEMPLATES_PAGE_SIZE = 20;
function getSearchKey(query: ITemplatesQuery): string { function getSearchKey(query: ITemplatesQuery): string {

View File

@@ -1,7 +1,8 @@
import { computed } from 'vue'; import { computed } from 'vue';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { saveAs } from 'file-saver'; import { saveAs } from 'file-saver';
import type { IWorkflowDataUpdate, IWorkflowDb } from '@/Interface'; import type { IWorkflowDb } from '@/Interface';
import type { WorkflowDataUpdate } from '@n8n/rest-api-client/api/workflows';
import type { import type {
WorkflowHistory, WorkflowHistory,
WorkflowVersion, WorkflowVersion,
@@ -68,7 +69,7 @@ export const useWorkflowHistoryStore = defineStore('workflowHistory', () => {
const newWorkflow = await getNewWorkflow(rootStore.restApiContext, { const newWorkflow = await getNewWorkflow(rootStore.restApiContext, {
name: `${name} (${data.formattedCreatedAt})`, name: `${name} (${data.formattedCreatedAt})`,
}); });
const newWorkflowData: IWorkflowDataUpdate = { const newWorkflowData: WorkflowDataUpdate = {
nodes, nodes,
connections, connections,
name: newWorkflow.name, name: newWorkflow.name,
@@ -83,7 +84,7 @@ export const useWorkflowHistoryStore = defineStore('workflowHistory', () => {
): Promise<IWorkflowDb> => { ): Promise<IWorkflowDb> => {
const workflowVersion = await getWorkflowVersion(workflowId, workflowVersionId); const workflowVersion = await getWorkflowVersion(workflowId, workflowVersionId);
const { connections, nodes } = workflowVersion; const { connections, nodes } = workflowVersion;
const updateData: IWorkflowDataUpdate = { connections, nodes }; const updateData: WorkflowDataUpdate = { connections, nodes };
if (shouldDeactivate) { if (shouldDeactivate) {
updateData.active = false; updateData.active = false;

View File

@@ -23,16 +23,18 @@ import type {
IStartRunData, IStartRunData,
IUpdateInformation, IUpdateInformation,
IUsedCredential, IUsedCredential,
IWorkflowDataUpdate,
IWorkflowDb, IWorkflowDb,
IWorkflowsMap, IWorkflowsMap,
NodeMetadataMap, NodeMetadataMap,
WorkflowMetadata,
IExecutionFlattedResponse, IExecutionFlattedResponse,
IWorkflowTemplateNode,
IWorkflowDataCreate,
WorkflowListResource, WorkflowListResource,
} from '@/Interface'; } from '@/Interface';
import type { IWorkflowTemplateNode } from '@n8n/rest-api-client/api/templates';
import type {
WorkflowMetadata,
WorkflowDataCreate,
WorkflowDataUpdate,
} from '@n8n/rest-api-client/api/workflows';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import type { import type {
IConnection, IConnection,
@@ -1681,7 +1683,7 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, () => {
* Ensures that the new workflow is not active upon creation. * Ensures that the new workflow is not active upon creation.
* If the project ID is not provided in the data, it assigns the current project ID from the project store. * If the project ID is not provided in the data, it assigns the current project ID from the project store.
*/ */
async function createNewWorkflow(sendData: IWorkflowDataCreate): Promise<IWorkflowDb> { async function createNewWorkflow(sendData: WorkflowDataCreate): Promise<IWorkflowDb> {
// make sure that the new ones are not active // make sure that the new ones are not active
sendData.active = false; sendData.active = false;
@@ -1714,7 +1716,7 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, () => {
async function updateWorkflow( async function updateWorkflow(
id: string, id: string,
data: IWorkflowDataUpdate, data: WorkflowDataUpdate,
forceSave = false, forceSave = false,
): Promise<IWorkflowDb> { ): Promise<IWorkflowDb> {
if (data.settings === null) { if (data.settings === null) {

View File

@@ -17,9 +17,9 @@ import type {
INodeUpdatePropertiesInformation, INodeUpdatePropertiesInformation,
IPersonalizationLatestVersion, IPersonalizationLatestVersion,
IWorkflowDb, IWorkflowDb,
IWorkflowTemplateNode,
NodeFilterType, NodeFilterType,
} from '@/Interface'; } from '@/Interface';
import type { IWorkflowTemplateNode } from '@n8n/rest-api-client/api/templates';
import type { ComponentPublicInstance } from 'vue'; import type { ComponentPublicInstance } from 'vue';
import type { useWebhooksStore } from '@/stores/webhooks.store'; import type { useWebhooksStore } from '@/stores/webhooks.store';

View File

@@ -2,9 +2,9 @@ import type {
AppliedThemeOption, AppliedThemeOption,
INodeUi, INodeUi,
INodeUpdatePropertiesInformation, INodeUpdatePropertiesInformation,
ITemplatesNode,
NodeAuthenticationOption, NodeAuthenticationOption,
} from '@/Interface'; } from '@/Interface';
import type { ITemplatesNode } from '@n8n/rest-api-client/api/templates';
import { import {
CORE_NODES_CATEGORY, CORE_NODES_CATEGORY,
MAIN_AUTH_FIELD_NAME, MAIN_AUTH_FIELD_NAME,

View File

@@ -5,7 +5,7 @@ import { vi } from 'vitest';
import { mock } from 'vitest-mock-extended'; import { mock } from 'vitest-mock-extended';
import { VIEWS } from '@/constants'; import { VIEWS } from '@/constants';
import type { ITemplatesWorkflowFull } from '@/Interface'; import type { ITemplatesWorkflowFull } from '@n8n/rest-api-client/api/templates';
import { Telemetry } from '@/plugins/telemetry'; import { Telemetry } from '@/plugins/telemetry';
import type { NodeTypesStore } from '@/stores/nodeTypes.store'; import type { NodeTypesStore } from '@/stores/nodeTypes.store';
import { useNodeTypesStore } from '@/stores/nodeTypes.store'; import { useNodeTypesStore } from '@/stores/nodeTypes.store';

View File

@@ -1,9 +1,6 @@
import type { import type { INodeUi } from '@/Interface';
INodeUi, import type { ITemplatesWorkflowFull, IWorkflowTemplate } from '@n8n/rest-api-client/api/templates';
ITemplatesWorkflowFull, import type { WorkflowData } from '@n8n/rest-api-client/api/workflows';
IWorkflowData,
IWorkflowTemplate,
} from '@/Interface';
import { getNewWorkflow } from '@/api/workflows'; import { getNewWorkflow } from '@/api/workflows';
import { VIEWS } from '@/constants'; import { VIEWS } from '@/constants';
import type { useRootStore } from '@n8n/stores/useRootStore'; import type { useRootStore } from '@n8n/stores/useRootStore';
@@ -45,7 +42,7 @@ export async function createWorkflowFromTemplate(opts: {
const nodes = getNodesWithNormalizedPosition(nodesWithCreds) as INodeUi[]; const nodes = getNodesWithNormalizedPosition(nodesWithCreds) as INodeUi[];
const connections = template.workflow.connections; const connections = template.workflow.connections;
const workflowToCreate: IWorkflowData = { const workflowToCreate: WorkflowData = {
name: workflowData.name, name: workflowData.name,
nodes, nodes,
connections, connections,

View File

@@ -1,5 +1,5 @@
import { mock } from 'vitest-mock-extended'; import { mock } from 'vitest-mock-extended';
import type { IWorkflowTemplateNode } from '@/Interface'; import type { IWorkflowTemplateNode } from '@n8n/rest-api-client/api/templates';
import { import {
keyFromCredentialTypeAndName, keyFromCredentialTypeAndName,
replaceAllTemplateNodeCredentials, replaceAllTemplateNodeCredentials,

View File

@@ -1,4 +1,8 @@
import type { IWorkflowTemplateNode, IWorkflowTemplateNodeCredentials } from '@/Interface'; import type {
IWorkflowTemplateNode,
IWorkflowTemplateNodeCredentials,
} from '@n8n/rest-api-client/api/templates';
import type { NodeTypeProvider } from '@/utils/nodeTypes/nodeTypeTransforms'; import type { NodeTypeProvider } from '@/utils/nodeTypes/nodeTypeTransforms';
import { getNodeTypeDisplayableCredentials } from '@/utils/nodes/nodeTransforms'; import { getNodeTypeDisplayableCredentials } from '@/utils/nodes/nodeTransforms';
import type { NormalizedTemplateNodeCredentials } from '@/utils/templates/templateTypes'; import type { NormalizedTemplateNodeCredentials } from '@/utils/templates/templateTypes';

View File

@@ -2,7 +2,7 @@ import type {
ITemplatesCollection, ITemplatesCollection,
ITemplatesCollectionFull, ITemplatesCollectionFull,
ITemplatesWorkflow, ITemplatesWorkflow,
} from '@/Interface'; } from '@n8n/rest-api-client/api/templates';
export function isTemplatesWorkflow( export function isTemplatesWorkflow(
template: ITemplatesWorkflow | ITemplatesCollection | ITemplatesCollectionFull | null, template: ITemplatesWorkflow | ITemplatesCollection | ITemplatesCollectionFull | null,

View File

@@ -27,15 +27,15 @@ import type {
IExecutionResponse, IExecutionResponse,
INodeUi, INodeUi,
IUpdateInformation, IUpdateInformation,
IWorkflowDataUpdate,
IWorkflowDb, IWorkflowDb,
IWorkflowTemplate,
NodeCreatorOpenSource, NodeCreatorOpenSource,
NodeFilterType, NodeFilterType,
ToggleNodeCreatorOptions, ToggleNodeCreatorOptions,
WorkflowDataWithTemplateId, WorkflowDataWithTemplateId,
XYPosition, XYPosition,
} from '@/Interface'; } from '@/Interface';
import type { IWorkflowTemplate } from '@n8n/rest-api-client/api/templates';
import type { WorkflowDataUpdate } from '@n8n/rest-api-client/api/workflows';
import type { import type {
Connection, Connection,
Dimensions, Dimensions,
@@ -769,7 +769,7 @@ async function onClipboardPaste(plainTextData: string): Promise<void> {
return; return;
} }
let workflowData: IWorkflowDataUpdate | null | undefined = null; let workflowData: WorkflowDataUpdate | null | undefined = null;
// Check if it is an URL which could contain workflow data // Check if it is an URL which could contain workflow data
if (plainTextData.match(VALID_WORKFLOW_IMPORT_URL_REGEX)) { if (plainTextData.match(VALID_WORKFLOW_IMPORT_URL_REGEX)) {
@@ -796,7 +796,7 @@ async function onClipboardPaste(plainTextData: string): Promise<void> {
workflowData = await fetchWorkflowDataFromUrl(plainTextData); workflowData = await fetchWorkflowDataFromUrl(plainTextData);
} else { } else {
// Pasted data is possible workflow data // Pasted data is possible workflow data
workflowData = jsonParse<IWorkflowDataUpdate | null>(plainTextData, { fallbackValue: null }); workflowData = jsonParse<WorkflowDataUpdate | null>(plainTextData, { fallbackValue: null });
} }
if (!workflowData) { if (!workflowData) {
@@ -1048,7 +1048,7 @@ function onRevertDeleteConnection({ connection }: { connection: [IConnection, IC
* Import / Export * Import / Export
*/ */
async function importWorkflowExact({ workflow: workflowData }: { workflow: IWorkflowDataUpdate }) { async function importWorkflowExact({ workflow: workflowData }: { workflow: WorkflowDataUpdate }) {
if (!workflowData.nodes || !workflowData.connections) { if (!workflowData.nodes || !workflowData.connections) {
throw new Error('Invalid workflow object'); throw new Error('Invalid workflow object');
} }
@@ -1066,7 +1066,7 @@ async function importWorkflowExact({ workflow: workflowData }: { workflow: IWork
} }
async function onImportWorkflowDataEvent(data: IDataObject) { async function onImportWorkflowDataEvent(data: IDataObject) {
const workflowData = data.data as IWorkflowDataUpdate; const workflowData = data.data as WorkflowDataUpdate;
await importWorkflowData(workflowData, 'file', { await importWorkflowData(workflowData, 'file', {
viewport: viewportBoundaries.value, viewport: viewportBoundaries.value,
}); });

View File

@@ -1,9 +1,9 @@
import { faker } from '@faker-js/faker/locale/en'; import { faker } from '@faker-js/faker/locale/en';
import type { ICredentialsResponse } from '@/Interface';
import type { import type {
ICredentialsResponse,
ITemplatesWorkflowFull, ITemplatesWorkflowFull,
IWorkflowTemplateNode, IWorkflowTemplateNode,
} from '@/Interface'; } from '@n8n/rest-api-client/api/templates';
export const newFullOneNodeTemplate = (node: IWorkflowTemplateNode): ITemplatesWorkflowFull => ({ export const newFullOneNodeTemplate = (node: IWorkflowTemplateNode): ITemplatesWorkflowFull => ({
full: true, full: true,

View File

@@ -3,11 +3,11 @@ import { createTestingPinia } from '@pinia/testing';
import { mock } from 'vitest-mock-extended'; import { mock } from 'vitest-mock-extended';
import type { ICredentialType } from 'n8n-workflow'; import type { ICredentialType } from 'n8n-workflow';
import type { ICredentialsResponse } from '@/Interface';
import type { import type {
ICredentialsResponse,
ITemplatesWorkflowFull, ITemplatesWorkflowFull,
IWorkflowTemplateNode, IWorkflowTemplateNode,
} from '@/Interface'; } from '@n8n/rest-api-client/api/templates';
import { useTemplatesStore } from '@/stores/templates.store'; import { useTemplatesStore } from '@/stores/templates.store';
import { keyFromCredentialTypeAndName } from '@/utils/templates/templateTransforms'; import { keyFromCredentialTypeAndName } from '@/utils/templates/templateTransforms';
import { useSetupTemplateStore } from '@/views/SetupWorkflowFromTemplateView/setupTemplate.store'; import { useSetupTemplateStore } from '@/views/SetupWorkflowFromTemplateView/setupTemplate.store';

View File

@@ -1,5 +1,5 @@
import { mock } from 'vitest-mock-extended'; import { mock } from 'vitest-mock-extended';
import type { IWorkflowTemplateNode } from '@/Interface'; import type { IWorkflowTemplateNode } from '@n8n/rest-api-client/api/templates';
import { keyFromCredentialTypeAndName } from '@/utils/templates/templateTransforms'; import { keyFromCredentialTypeAndName } from '@/utils/templates/templateTransforms';
import type { IWorkflowTemplateNodeWithCredentials } from '@/utils/templates/templateTransforms'; import type { IWorkflowTemplateNodeWithCredentials } from '@/utils/templates/templateTransforms';
import type { CredentialUsages } from '@/views/SetupWorkflowFromTemplateView/useCredentialSetupState'; import type { CredentialUsages } from '@/views/SetupWorkflowFromTemplateView/useCredentialSetupState';

View File

@@ -3,7 +3,7 @@ import { computed, onMounted, ref, watch } from 'vue';
import TemplateDetails from '@/components/TemplateDetails.vue'; import TemplateDetails from '@/components/TemplateDetails.vue';
import TemplateList from '@/components/TemplateList.vue'; import TemplateList from '@/components/TemplateList.vue';
import TemplatesView from './TemplatesView.vue'; import TemplatesView from './TemplatesView.vue';
import type { ITemplatesWorkflow } from '@/Interface'; import type { ITemplatesWorkflow } from '@n8n/rest-api-client/api/templates';
import { VIEWS } from '@/constants'; import { VIEWS } from '@/constants';
import { useTemplatesStore } from '@/stores/templates.store'; import { useTemplatesStore } from '@/stores/templates.store';
import { useTemplateWorkflow } from '@/utils/templates/templateActions'; import { useTemplateWorkflow } from '@/utils/templates/templateActions';

View File

@@ -5,7 +5,7 @@ import TemplateFilters from '@/components/TemplateFilters.vue';
import TemplateList from '@/components/TemplateList.vue'; import TemplateList from '@/components/TemplateList.vue';
import TemplatesView from '@/views/TemplatesView.vue'; import TemplatesView from '@/views/TemplatesView.vue';
import type { ITemplatesCategory } from '@/Interface'; import type { ITemplatesCategory } from '@n8n/rest-api-client/api/templates';
import type { IDataObject } from 'n8n-workflow'; import type { IDataObject } from 'n8n-workflow';
import { CREATOR_HUB_URL, VIEWS } from '@/constants'; import { CREATOR_HUB_URL, VIEWS } from '@/constants';
import { useSettingsStore } from '@/stores/settings.store'; import { useSettingsStore } from '@/stores/settings.store';