mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-16 09:36:44 +00:00
refactor(editor): Move templates api to @n8n/rest-api-client package (no-changelog) (#16542)
This commit is contained in:
@@ -18,3 +18,6 @@ CHANGELOG.md
|
|||||||
**/*.js
|
**/*.js
|
||||||
**/*.json
|
**/*.json
|
||||||
**/*.jsonc
|
**/*.jsonc
|
||||||
|
|
||||||
|
# Auto-generated
|
||||||
|
**/components.d.ts
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
7
packages/frontend/@n8n/rest-api-client/src/api/tags.ts
Normal file
7
packages/frontend/@n8n/rest-api-client/src/api/tags.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export interface ITag {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
usageCount?: number;
|
||||||
|
createdAt?: string;
|
||||||
|
updatedAt?: string;
|
||||||
|
}
|
||||||
195
packages/frontend/@n8n/rest-api-client/src/api/templates.ts
Normal file
195
packages/frontend/@n8n/rest-api-client/src/api/templates.ts
Normal 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);
|
||||||
|
}
|
||||||
42
packages/frontend/@n8n/rest-api-client/src/api/workflows.ts
Normal file
42
packages/frontend/@n8n/rest-api-client/src/api/workflows.ts
Normal 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;
|
||||||
|
}
|
||||||
@@ -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[];
|
||||||
|
|||||||
@@ -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>({
|
||||||
|
|||||||
@@ -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',
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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<{
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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}`,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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[];
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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>();
|
||||||
|
|
||||||
|
|||||||
@@ -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');
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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) => {
|
||||||
|
|||||||
@@ -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: [
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
Reference in New Issue
Block a user