n8n/packages/editor-ui/src/stores/templates.ts

268 lines
9.5 KiB
TypeScript
Raw Normal View History

refactor(editor): Migrate part of the vuex store to pinia (#4484) * ✨ Added pinia support. Migrated community nodes module. * ✨ Added ui pinia store, moved some data from root store to it, updated modals to work with pinia stores * ✨ Added ui pinia store and migrated a part of the root store * ✨ Migrated `settings` store to pinia * ✨ Removing vuex store refs from router * ✨ Migrated `users` module to pinia store * ⚡ Fixing errors after sync with master * ⚡ One more error after merge * ⚡ Created `workflows` pinia store. Moved large part of root store to it. Started updating references. * ✨ Finished migrating workflows store to pinia * ⚡ Renaming some getters and actions to make more sense * ✨ Finished migrating the root store to pinia * ✨ Migrated ndv store to pinia * ⚡ Renaming main panel dimensions getter so it doesn't clash with data prop name * ✔️ Fixing lint errors * ✨ Migrated `templates` store to pinia * ✨ Migrated the `nodeTypes`store * ⚡ Removed unused pieces of code and oold vuex modules * ✨ Adding vuex calls to pinia store, fi xing wrong references * 💄 Removing leftover $store refs * ⚡ Added legacy getters and mutations to store to support webhooks * ⚡ Added missing front-end hooks, updated vuex state subscriptions to pinia * ✔️ Fixing linting errors * ⚡ Removing vue composition api plugin * ⚡ Fixing main sidebar state when loading node view * 🐛 Fixing an error when activating workflows * 🐛 Fixing isses with workflow settings and executions auto-refresh * 🐛 Removing duplicate listeners which cause import error * 🐛 Fixing route authentication * ⚡ Updating freshly pulled $store refs * Adding deleted const * ⚡ Updating store references in ee features. Reseting NodeView credentials update flag when resetting workspace * ⚡ Adding return type to email submission modal * ⚡ Making NodeView only react to paste event when active * 🐛 Fixing signup view errors * 👌 Addressing PR review comments * 👌 Addressing new PR comments * 👌 Updating invite id logic in signup view
2022-11-04 06:04:31 -07:00
import { defineStore } from "pinia";
import { STORES } from '@/constants';
import { ITemplatesCategory, ITemplatesCollection, ITemplatesCollectionFull, ITemplatesQuery, ITemplateState, ITemplatesWorkflow, ITemplatesWorkflowFull, IWorkflowTemplate } from "@/Interface";
import Vue from "vue";
import { useSettingsStore } from "./settings";
import { getCategories, getCollectionById, getCollections, getTemplateById, getWorkflows, getWorkflowTemplate } from "@/api/templates";
const TEMPLATES_PAGE_SIZE = 10;
function getSearchKey(query: ITemplatesQuery): string {
return JSON.stringify([query.search || '', [...query.categories].sort()]);
}
export const useTemplatesStore = defineStore(STORES.TEMPLATES, {
state: (): ITemplateState => ({
categories: {},
collections: {},
workflows: {},
collectionSearches: {},
workflowSearches: {},
currentSessionId: '',
previousSessionId: '',
}),
getters: {
allCategories(): ITemplatesCategory[] {
return Object.values(this.categories).sort((a: ITemplatesCategory, b: ITemplatesCategory) => a.name > b.name ? 1: -1);
},
getTemplateById() {
return (id: string): null | ITemplatesWorkflow => this.workflows[id];
},
getCollectionById() {
return (id: string): null | ITemplatesCollection => this.collections[id];
},
getCategoryById() {
return (id: string): null | ITemplatesCategory => this.categories[id];
},
getSearchedCollections() {
return (query: ITemplatesQuery) => {
const searchKey = getSearchKey(query);
const search = this.collectionSearches[searchKey];
if (!search) {
return null;
}
return search.collectionIds.map((collectionId: string) => this.collections[collectionId]);
};
},
getSearchedWorkflows() {
return (query: ITemplatesQuery) => {
const searchKey = getSearchKey(query);
const search = this.workflowSearches[searchKey];
if (!search) {
return null;
}
return search.workflowIds.map((workflowId: string) => this.workflows[workflowId]);
};
},
getSearchedWorkflowsTotal() {
return (query: ITemplatesQuery) => {
const searchKey = getSearchKey(query);
const search = this.workflowSearches[searchKey];
return search ? search.totalWorkflows : 0;
};
},
isSearchLoadingMore() {
return (query: ITemplatesQuery) => {
const searchKey = getSearchKey(query);
const search = this.workflowSearches[searchKey];
return Boolean(search && search.loadingMore);
};
},
isSearchFinished() {
return (query: ITemplatesQuery) => {
const searchKey = getSearchKey(query);
const search = this.workflowSearches[searchKey];
return Boolean(search && !search.loadingMore && search.totalWorkflows === search.workflowIds.length);
};
},
},
actions: {
addCategories(categories: ITemplatesCategory[]): void {
categories.forEach((category: ITemplatesCategory) => {
Vue.set(this.categories, category.id, category);
});
},
addCollections(collections: Array<ITemplatesCollection | ITemplatesCollectionFull>): void {
collections.forEach((collection) => {
const workflows = (collection.workflows || []).map((workflow) => ({id: workflow.id}));
const cachedCollection = this.collections[collection.id] || {};
Vue.set(this.collections, collection.id, {
...cachedCollection,
...collection,
workflows,
});
});
},
addWorkflows(workflows: Array<ITemplatesWorkflow | ITemplatesWorkflowFull>): void {
workflows.forEach((workflow: ITemplatesWorkflow) => {
const cachedWorkflow = this.workflows[workflow.id] || {};
Vue.set(this.workflows, workflow.id, {
...cachedWorkflow,
...workflow,
});
});
},
addCollectionSearch(data: {collections: ITemplatesCollection[], query: ITemplatesQuery}): void {
const collectionIds = data.collections.map((collection) => collection.id);
const searchKey = getSearchKey(data.query);
Vue.set(this.collectionSearches, searchKey, {
collectionIds,
});
},
addWorkflowsSearch(data: {totalWorkflows: number; workflows: ITemplatesWorkflow[], query: ITemplatesQuery}): void {
const workflowIds = data.workflows.map((workflow) => workflow.id);
const searchKey = getSearchKey(data.query);
const cachedResults = this.workflowSearches[searchKey];
if (!cachedResults) {
Vue.set(this.workflowSearches, searchKey, {
workflowIds,
totalWorkflows: data.totalWorkflows,
});
return;
}
Vue.set(this.workflowSearches, searchKey, {
workflowIds: [...cachedResults.workflowIds, ...workflowIds],
totalWorkflows: data.totalWorkflows,
});
},
setWorkflowSearchLoading(query: ITemplatesQuery): void {
const searchKey = getSearchKey(query);
const cachedResults = this.workflowSearches[searchKey];
if (!cachedResults) {
return;
}
Vue.set(this.workflowSearches[searchKey], 'loadingMore', true);
},
setWorkflowSearchLoaded(query: ITemplatesQuery): void {
const searchKey = getSearchKey(query);
const cachedResults = this.workflowSearches[searchKey];
if (!cachedResults) {
return;
}
Vue.set(this.workflowSearches[searchKey], 'loadingMore', false);
},
resetSessionId(): void {
this.previousSessionId = this.currentSessionId;
this.currentSessionId = '';
},
setSessionId(): void {
if (!this.currentSessionId) {
this.currentSessionId = `templates-${Date.now()}`;
}
},
async fetchTemplateById(templateId: string): Promise<ITemplatesWorkflow | ITemplatesWorkflowFull> {
const settingsStore = useSettingsStore();
const apiEndpoint: string = settingsStore.templatesHost;
const versionCli: string = settingsStore.versionCli;
const response = await getTemplateById(apiEndpoint, templateId, { 'n8n-version': versionCli });
const template: ITemplatesWorkflowFull = {
...response.workflow,
full: true,
};
this.addWorkflows([template]);
return template;
},
async fetchCollectionById(collectionId: string): Promise<ITemplatesCollection | null> {
const settingsStore = useSettingsStore();
const apiEndpoint: string = settingsStore.templatesHost;
const versionCli: string = settingsStore.versionCli;
const response = await getCollectionById(apiEndpoint, collectionId, { 'n8n-version': versionCli });
const collection: ITemplatesCollectionFull = {
...response.collection,
full: true,
};
this.addCollections([collection]);
this.addWorkflows(response.collection.workflows);
return this.getCollectionById(collectionId);
},
async getCategories(): Promise<ITemplatesCategory[]> {
const cachedCategories = this.allCategories;
if (cachedCategories.length) {
return cachedCategories;
}
const settingsStore = useSettingsStore();
const apiEndpoint: string = settingsStore.templatesHost;
const versionCli: string = settingsStore.versionCli;
const response = await getCategories(apiEndpoint, { 'n8n-version': versionCli });
const categories = response.categories;
this.addCategories(categories);
return categories;
},
async getCollections(query: ITemplatesQuery): Promise<ITemplatesCollection[]> {
const cachedResults = this.getSearchedCollections(query);
if (cachedResults) {
return cachedResults;
}
const settingsStore = useSettingsStore();
const apiEndpoint: string = settingsStore.templatesHost;
const versionCli: string = settingsStore.versionCli;
const response = await getCollections(apiEndpoint, query, { 'n8n-version': versionCli });
const collections = response.collections;
this.addCollections(collections);
this.addCollectionSearch({query, collections});
collections.forEach(collection => this.addWorkflows(collection.workflows as ITemplatesWorkflowFull[]));
return collections;
},
async getWorkflows(query: ITemplatesQuery): Promise<ITemplatesWorkflow[]> {
const cachedResults = this.getSearchedWorkflows(query);
if (cachedResults) {
return cachedResults;
}
const settingsStore = useSettingsStore();
const apiEndpoint: string = settingsStore.templatesHost;
const versionCli: string = settingsStore.versionCli;
const payload = await getWorkflows(apiEndpoint, {...query, skip: 0, limit: TEMPLATES_PAGE_SIZE}, { 'n8n-version': versionCli });
this.addWorkflows(payload.workflows);
this.addWorkflowsSearch({...payload, query});
return this.getSearchedWorkflows(query) || [];
},
async getMoreWorkflows(query: ITemplatesQuery): Promise<ITemplatesWorkflow[]> {
if (this.isSearchLoadingMore(query) && !this.isSearchFinished(query)) {
return [];
}
const cachedResults = this.getSearchedWorkflows(query) || [];
const settingsStore = useSettingsStore();
const apiEndpoint: string = settingsStore.templatesHost;
this.setWorkflowSearchLoading(query);
try {
const payload = await getWorkflows(apiEndpoint, {...query, skip: cachedResults.length, limit: TEMPLATES_PAGE_SIZE});
this.setWorkflowSearchLoaded(query);
this.addWorkflows(payload.workflows);
this.addWorkflowsSearch({...payload, query});
return this.getSearchedWorkflows(query) || [];
} catch (e) {
this.setWorkflowSearchLoaded(query);
throw e;
}
},
async getWorkflowTemplate(templateId: string): Promise<IWorkflowTemplate> {
const settingsStore = useSettingsStore();
const apiEndpoint: string = settingsStore.templatesHost;
const versionCli: string = settingsStore.versionCli;
return await getWorkflowTemplate(apiEndpoint, templateId, { 'n8n-version': versionCli });
},
},
});