diff --git a/front/src/components/library/Albums.vue b/front/src/components/library/Albums.vue index 9ba9af3fe..4560ff56d 100644 --- a/front/src/components/library/Albums.vue +++ b/front/src/components/library/Albums.vue @@ -48,8 +48,9 @@ const props = withDefaults(defineProps(), { const page = usePage() -const tags = useRouteQuery('tag', []) -const tagList = useTags().model(tags.value) +const tags = useRouteQuery('tag', [], { transform: (param: string | string[] | null) => (param === null ? [] : Array.isArray(param) ? param : [param]).filter(p => p.trim() !== '') }) + +const tagList = useTags(tags) const q = useRouteQuery('query', '') const query = ref(q.value ?? '') @@ -152,6 +153,7 @@ const paginateOptions = computed(() => sortedUniq([12, 30, 50, paginateBy.value] autofocus :placeholder="labels.searchPlaceholder" /> + {{ tagList }} () => { +export const useTags = (currents: Ref) => { const store = useStore() - // Two-way bind with store - const tags = computed({ - get: () => store.state.ui.tags || [], - set: function(value) { - store.commit('ui/tags', value) - } - }) - // Ignore quick successive fetch triggers const ignorePeriod = 500 @@ -30,11 +26,13 @@ export const useTags = () => { // Wait after changing a tag before re-fetching const refetchInterval = 6000 + // Number of tags to load on one page const maxTags = 100000 const lastFetched = ref(0) const fetch = async () => { + // console.log('FETCH TAGS') // Ignore subsequent fetch commands triggered in quick succession if (lastFetched.value + ignorePeriod > Date.now()) return @@ -50,40 +48,48 @@ export const useTags = () => { { params: { page: 1, page_size: maxTags } } ) - tags.value = response.data.results + // console.log('TAGS RESPONSE.data.results', response.data.results) + store.commit('ui/tags', response.data.results) } - return ({ - /** - * @param currents Initial selected tags - * @returns v-model for `Pills` component - */ - model: (currents: string[] = []) => { - fetch(); - return computed({ + fetch(); - // Get currents initially from parameter. Get others from backend. - get: (): Model => ({ - currents: currents.map(tag => ({ - label: tag, - type: tags.value.some(({ name }) => tag === name) ? 'preset' : 'custom' - })), - others: tags.value - .filter(({ name }) => !currents.includes(name)) - .map(({ name }) => ({ - label: name, - type: 'preset' - })) - }), + /** + * @returns v-model for `Pills` component + */ + return computed({ + get () { + // console.log("GET TAGS") + return ({ + // Get `currents` from parameter + currents: currents.value.map(tag => ({ + label: tag, + type: (store.state.ui.tags || []).some(({ name }) => tag === name) ? 'preset' : 'custom' + } as const)), - // Re-fetch after each new setting - set: function (_) { - window.setTimeout(fetch, refetchInterval) - // TODO: Broadcast new custom tags so that other pills components can use them - } - }) + // Get `others` from cache + others: (store.state.ui.tags || []) + .filter(({ name }) => !currents.value.includes(name)) + .map(({ name }) => ({ + label: name, + type: 'preset' + } as const)) + })}, + + set (model) { + // console.log('SET TAGS', response.data.results) + + // Set parameter `currents` from `model.currents` + currents.value = model.currents.map(({ label }) => label) + + // Set runtime-only options from `model.others` and `model.current` + // TODO: Broadcast new custom tags so that other pills components can use them + + // Re-fetch after each new setting + window.setTimeout(fetch, refetchInterval) } - }) +}) } // alternative ways to generate tags +// ...