diff --git a/packages/editor-ui/src/components/MainHeader/WorkflowDetails.spec.ts b/packages/editor-ui/src/components/MainHeader/WorkflowDetails.spec.ts index 075ba6beaf..4eb0a829d9 100644 --- a/packages/editor-ui/src/components/MainHeader/WorkflowDetails.spec.ts +++ b/packages/editor-ui/src/components/MainHeader/WorkflowDetails.spec.ts @@ -30,7 +30,7 @@ const initialState = { areTagsEnabled: true, }, [STORES.TAGS]: { - tags: { + tagsById: { 1: { id: '1', name: 'tag1', diff --git a/packages/editor-ui/src/components/MainHeader/WorkflowDetails.vue b/packages/editor-ui/src/components/MainHeader/WorkflowDetails.vue index 06f08b5afe..babf3b36df 100644 --- a/packages/editor-ui/src/components/MainHeader/WorkflowDetails.vue +++ b/packages/editor-ui/src/components/MainHeader/WorkflowDetails.vue @@ -413,7 +413,7 @@ async function onWorkflowMenuSelect(action: WORKFLOW_MENU_ACTIONS): Promise { - const { usageCount, ...tag } = tagsStore.getTagById(tagId); + const { usageCount, ...tag } = tagsStore.tagsById[tagId]; return tag; }), diff --git a/packages/editor-ui/src/components/TagsContainer.vue b/packages/editor-ui/src/components/TagsContainer.vue index e0b12a73cf..ff14bafdec 100644 --- a/packages/editor-ui/src/components/TagsContainer.vue +++ b/packages/editor-ui/src/components/TagsContainer.vue @@ -103,7 +103,7 @@ export default defineComponent({ }, tags() { const tags = this.tagIds - .map((tagId: string) => this.tagsStore.getTagById(tagId)) + .map((tagId: string) => this.tagsStore.tagsById[tagId]) .filter(Boolean); // if tag has been deleted from store let toDisplay: TagEl[] = this.limit ? tags.slice(0, this.limit) : tags; diff --git a/packages/editor-ui/src/components/TagsDropdown.vue b/packages/editor-ui/src/components/TagsDropdown.vue index dbfbd49147..0a5ac3b493 100644 --- a/packages/editor-ui/src/components/TagsDropdown.vue +++ b/packages/editor-ui/src/components/TagsDropdown.vue @@ -130,7 +130,7 @@ export default defineComponent({ }); const appliedTags = computed(() => { - return props.modelValue.filter((id: string) => tagsStore.getTagById(id)); + return props.modelValue.filter((id: string) => tagsStore.tagsById[id]); }); watch( diff --git a/packages/editor-ui/src/components/TagsManager/TagsManager.vue b/packages/editor-ui/src/components/TagsManager/TagsManager.vue index 7fc47aec74..02bfee1dd2 100644 --- a/packages/editor-ui/src/components/TagsManager/TagsManager.vue +++ b/packages/editor-ui/src/components/TagsManager/TagsManager.vue @@ -72,7 +72,7 @@ export default defineComponent({ return this.tagsStore.isLoading; }, tags(): ITag[] { - return this.tagIds.map((tagId: string) => this.tagsStore.getTagById(tagId)).filter(Boolean); // if tag is deleted from store + return this.tagIds.map((tagId: string) => this.tagsStore.tagsById[tagId]).filter(Boolean); // if tag is deleted from store }, hasTags(): boolean { return this.tags.length > 0; @@ -110,7 +110,7 @@ export default defineComponent({ }, async onUpdate(id: string, name: string, cb: (tag: boolean, error?: Error) => void) { - const tag = this.tagsStore.getTagById(id); + const tag = this.tagsStore.tagsById[id]; const oldName = tag.name; try { @@ -144,11 +144,11 @@ export default defineComponent({ }, async onDelete(id: string, cb: (deleted: boolean, error?: Error) => void) { - const tag = this.tagsStore.getTagById(id); + const tag = this.tagsStore.tagsById[id]; const name = tag.name; try { - const deleted = await this.tagsStore.delete(id); + const deleted = await this.tagsStore.deleteTagById(id); if (!deleted) { throw new Error(this.$locale.baseText('tagsManager.couldNotDeleteTag')); } diff --git a/packages/editor-ui/src/stores/tags.store.ts b/packages/editor-ui/src/stores/tags.store.ts index b9daa4183a..4dab82a8cb 100644 --- a/packages/editor-ui/src/stores/tags.store.ts +++ b/packages/editor-ui/src/stores/tags.store.ts @@ -1,105 +1,114 @@ -import { createTag, deleteTag, getTags, updateTag } from '@/api/tags'; +import * as tagsApi from '@/api/tags'; import { STORES } from '@/constants'; -import type { ITag, ITagsState } from '@/Interface'; +import type { ITag } from '@/Interface'; import { defineStore } from 'pinia'; import { useRootStore } from './root.store'; +import { computed, ref } from 'vue'; import { useWorkflowsStore } from './workflows.store'; -export const useTagsStore = defineStore(STORES.TAGS, { - state: (): ITagsState => ({ - tags: {}, - loading: false, - fetchedAll: false, - fetchedUsageCount: false, - }), - getters: { - allTags(): ITag[] { - return Object.values(this.tags).sort((a, b) => a.name.localeCompare(b.name)); - }, - isLoading(): boolean { - return this.loading; - }, - hasTags(): boolean { - return Object.keys(this.tags).length > 0; - }, - getTagById() { - return (id: string) => this.tags[id]; - }, - }, - actions: { - setAllTags(tags: ITag[]): void { - this.tags = tags.reduce((accu: { [id: string]: ITag }, tag: ITag) => { - accu[tag.id] = tag; +export const useTagsStore = defineStore(STORES.TAGS, () => { + const tagsById = ref>({}); + const loading = ref(false); + const fetchedAll = ref(false); + const fetchedUsageCount = ref(false); - return accu; - }, {}); - this.fetchedAll = true; - }, - upsertTags(tags: ITag[]): void { - tags.forEach((tag) => { - const tagId = tag.id; - const currentTag = this.tags[tagId]; - if (currentTag) { - const newTag = { - ...currentTag, - ...tag, - }; - this.tags = { - ...this.tags, - [tagId]: newTag, - }; - } else { - this.tags = { - ...this.tags, - [tagId]: tag, - }; - } - }); - }, - deleteTag(id: string): void { - const { [id]: deleted, ...rest } = this.tags; - this.tags = rest; - }, + const rootStore = useRootStore(); + const workflowsStore = useWorkflowsStore(); - async fetchAll(params?: { force?: boolean; withUsageCount?: boolean }): Promise { - const { force = false, withUsageCount = false } = params || {}; - if (!force && this.fetchedAll && this.fetchedUsageCount === withUsageCount) { - return Object.values(this.tags); + // Computed + + const allTags = computed(() => { + return Object.values(tagsById.value).sort((a, b) => a.name.localeCompare(b.name)); + }); + + const isLoading = computed(() => loading.value); + + const hasTags = computed(() => Object.keys(tagsById.value).length > 0); + + // Methods + + const setAllTags = (loadedTags: ITag[]) => { + tagsById.value = loadedTags.reduce((accu: { [id: string]: ITag }, tag: ITag) => { + accu[tag.id] = tag; + + return accu; + }, {}); + fetchedAll.value = true; + }; + + const upsertTags = (toUpsertTags: ITag[]) => { + toUpsertTags.forEach((toUpsertTag) => { + const tagId = toUpsertTag.id; + const currentTag = tagsById.value[tagId]; + if (currentTag) { + const newTag = { + ...currentTag, + ...toUpsertTag, + }; + tagsById.value = { + ...tagsById.value, + [tagId]: newTag, + }; + } else { + tagsById.value = { + ...tagsById.value, + [tagId]: toUpsertTag, + }; } + }); + }; - this.loading = true; - const rootStore = useRootStore(); - const tags = await getTags(rootStore.restApiContext, Boolean(withUsageCount)); - this.setAllTags(tags); - this.loading = false; + const deleteTag = (id: string) => { + const { [id]: deleted, ...rest } = tagsById.value; + tagsById.value = rest; + }; - return tags; - }, - async create(name: string): Promise { - const rootStore = useRootStore(); - const tag = await createTag(rootStore.restApiContext, { name }); - this.upsertTags([tag]); + const fetchAll = async (params?: { force?: boolean; withUsageCount?: boolean }) => { + const { force = false, withUsageCount = false } = params || {}; + if (!force && fetchedAll.value && fetchedUsageCount.value === withUsageCount) { + return Object.values(tagsById.value); + } - return tag; - }, - async rename({ id, name }: { id: string; name: string }) { - const rootStore = useRootStore(); - const tag = await updateTag(rootStore.restApiContext, id, { name }); - this.upsertTags([tag]); + loading.value = true; + const retrievedTags = await tagsApi.getTags(rootStore.restApiContext, Boolean(withUsageCount)); + setAllTags(retrievedTags); + loading.value = false; + return retrievedTags; + }; - return tag; - }, - async delete(id: string) { - const rootStore = useRootStore(); - const deleted = await deleteTag(rootStore.restApiContext, id); + const create = async (name: string) => { + const createdTag = await tagsApi.createTag(rootStore.restApiContext, { name }); + upsertTags([createdTag]); + return createdTag; + }; - if (deleted) { - this.deleteTag(id); - const workflowsStore = useWorkflowsStore(); - workflowsStore.removeWorkflowTagId(id); - } + const rename = async ({ id, name }: { id: string; name: string }) => { + const updatedTag = await tagsApi.updateTag(rootStore.restApiContext, id, { name }); + upsertTags([updatedTag]); + return updatedTag; + }; - return deleted; - }, - }, + const deleteTagById = async (id: string) => { + const deleted = await tagsApi.deleteTag(rootStore.restApiContext, id); + + if (deleted) { + deleteTag(id); + workflowsStore.removeWorkflowTagId(id); + } + + return deleted; + }; + + return { + allTags, + isLoading, + hasTags, + tagsById, + fetchAll, + create, + rename, + deleteTagById, + upsertTags, + deleteTag, + }; });