feat(front): suggest previously used tags in `<Pills>` component #2448
This commit is contained in:
parent
65529429a6
commit
a97a8d53d1
|
@ -5,6 +5,7 @@ import type { paths } from '~/generated/types'
|
|||
import { slugify } from 'transliteration'
|
||||
import { reactive, computed, ref, watchEffect, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useDataStore } from '~/ui/stores/data'
|
||||
|
||||
import axios from 'axios'
|
||||
import AttachmentInput from '~/components/common/AttachmentInput.vue'
|
||||
|
@ -35,6 +36,7 @@ const props = withDefaults(defineProps<Props>(), {
|
|||
})
|
||||
|
||||
const { t } = useI18n()
|
||||
const dataStore = useDataStore()
|
||||
|
||||
const newValues = reactive({
|
||||
name: props.object?.artist?.name ?? '',
|
||||
|
@ -261,7 +263,7 @@ defineExpose({
|
|||
:get="model => { newValues.tags = model.currents.map(({ label }) => label) }"
|
||||
:set="model => ({
|
||||
currents: newValues.tags.map(tag => ({ type: 'custom' as const, label: tag })),
|
||||
others: [].map(tag => ({ type: 'custom' as const, label: tag }))
|
||||
others: dataStore.tags().value.map(({ name }) => ({ type: 'custom' as const, label: name }))
|
||||
})"
|
||||
:label="t('components.audio.ChannelForm.label.tags')"
|
||||
/>
|
||||
|
|
|
@ -11,6 +11,7 @@ import { useI18n } from 'vue-i18n'
|
|||
import { syncRef } from '@vueuse/core'
|
||||
import { sortedUniq } from 'lodash-es'
|
||||
import { useStore } from '~/store'
|
||||
import { useDataStore } from '~/ui/stores/data'
|
||||
import { useModal } from '~/ui/composables/useModal.ts'
|
||||
|
||||
import axios from 'axios'
|
||||
|
@ -101,6 +102,7 @@ const fetchData = async () => {
|
|||
}
|
||||
|
||||
const store = useStore()
|
||||
const dataStore = useDataStore()
|
||||
watch(() => store.state.moderation.lastUpdate, fetchData)
|
||||
watch([page, tags, q, ordering, orderingDirection, () => props.scope], fetchData)
|
||||
fetchData()
|
||||
|
@ -153,9 +155,8 @@ const paginateOptions = computed(() => sortedUniq([12, 30, 50, paginateBy.value]
|
|||
v-if="typeof tags === 'object'"
|
||||
:get="model => { tags = model.currents.map(({ label }) => label) }"
|
||||
:set="model => ({
|
||||
...model,
|
||||
others: [],
|
||||
currents: tags.map(tag => ({ type: 'custom' as const, label: tag })),
|
||||
others: dataStore.tags().value.map(({ name }) => ({ type: 'preset' as const, label: name })),
|
||||
})"
|
||||
:label="t('components.library.Albums.label.tags')"
|
||||
style="max-width: 150px;"
|
||||
|
|
|
@ -10,6 +10,7 @@ import { useI18n } from 'vue-i18n'
|
|||
import { syncRef } from '@vueuse/core'
|
||||
import { sortedUniq } from 'lodash-es'
|
||||
import { useStore } from '~/store'
|
||||
import { useDataStore } from '~/ui/stores/data'
|
||||
import { useModal } from '~/ui/composables/useModal.ts'
|
||||
|
||||
import axios from 'axios'
|
||||
|
@ -101,6 +102,7 @@ const fetchData = async () => {
|
|||
}
|
||||
|
||||
const store = useStore()
|
||||
const dataStore = useDataStore()
|
||||
watch([() => store.state.moderation.lastUpdate, excludeCompilation], fetchData)
|
||||
watch([page, tags, q, ordering, orderingDirection, () => props.scope], fetchData)
|
||||
fetchData()
|
||||
|
@ -153,9 +155,8 @@ const paginateOptions = computed(() => sortedUniq([12, 30, 50, paginateBy.value]
|
|||
v-if="typeof tags === 'object'"
|
||||
:get="model => { tags = model.currents.map(({ label }) => label) }"
|
||||
:set="model => ({
|
||||
...model,
|
||||
others: [],
|
||||
currents: tags.map(tag => ({ type: 'custom' as const, label: tag })),
|
||||
others: dataStore.tags().value.map(({ name }) => ({ type: 'preset' as const, label: name })),
|
||||
})"
|
||||
:label="t('components.library.Artists.label.tags')"
|
||||
style="max-width: 150px;"
|
||||
|
|
|
@ -318,8 +318,8 @@ const resetField = (fieldId: string) => {
|
|||
:get="model => { values[fieldConfig.id] = model.currents.map(({ label }) => label) }"
|
||||
:set="model => ({
|
||||
...model,
|
||||
others: [],
|
||||
currents: (values[fieldConfig.id] as string[]).map(tag => ({ type: 'custom' as const, label: tag })),
|
||||
others: dataStore.tags().value.map(({ name }) => ({ type: 'preset' as const, label: name })),
|
||||
})"
|
||||
:label="fieldConfig.label"
|
||||
:required="fieldConfig.required"
|
||||
|
|
|
@ -10,6 +10,7 @@ import { useI18n } from 'vue-i18n'
|
|||
import { syncRef } from '@vueuse/core'
|
||||
import { sortedUniq } from 'lodash-es'
|
||||
import { useStore } from '~/store'
|
||||
import { useDataStore } from '~/ui/stores/data'
|
||||
import { useModal } from '~/ui/composables/useModal.ts'
|
||||
|
||||
import axios from 'axios'
|
||||
|
@ -60,11 +61,6 @@ const submittable = ref(false)
|
|||
|
||||
const tags = useRouteQuery<string[]>('tag', [])
|
||||
|
||||
computed(() => ({
|
||||
currents: [].map(tag => ({ type: 'custom' as const, label: tag })),
|
||||
others: tags.value.map(tag => ({ type: 'custom' as const, label: tag }))
|
||||
}))
|
||||
|
||||
const q = useRouteQuery('query', '')
|
||||
const query = ref(q.value)
|
||||
syncRef(q, query, { direction: 'ltr' })
|
||||
|
@ -116,6 +112,7 @@ const fetchData = async () => {
|
|||
}
|
||||
|
||||
const store = useStore()
|
||||
const dataStore = useDataStore()
|
||||
watch(() => store.state.moderation.lastUpdate, fetchData)
|
||||
watch([page, tags, q, ordering, orderingDirection], fetchData)
|
||||
fetchData()
|
||||
|
@ -179,9 +176,8 @@ const { to: upload } = useModal('upload')
|
|||
v-if="typeof tags === 'object'"
|
||||
:get="model => { tags = model.currents.map(({ label }) => label) }"
|
||||
:set="model => ({
|
||||
...model,
|
||||
others: [],
|
||||
currents: tags.map(tag => ({ type: 'custom' as const, label: tag })),
|
||||
others: dataStore.tags().value.map(({ name }) => ({ type: 'preset' as const, label: name })),
|
||||
})"
|
||||
:label="t('components.library.Podcasts.label.tags')"
|
||||
style="max-width: 150px;"
|
||||
|
|
|
@ -2,7 +2,8 @@ import { defineStore } from 'pinia'
|
|||
import { ref, computed, type Ref } from 'vue'
|
||||
import axios from 'axios'
|
||||
|
||||
import type { Album, Artist, Track } from '~/types'
|
||||
import type { Album, Artist, Tag, Track } from '~/types'
|
||||
import type { components } from '~/generated/types'
|
||||
|
||||
/**
|
||||
* Fetch an item from the API.
|
||||
|
@ -51,6 +52,23 @@ export const useDataStore
|
|||
track: {}
|
||||
}
|
||||
|
||||
const tagsCache = ref<Tag[]>([])
|
||||
var tagsTimestamp = 0
|
||||
|
||||
/**
|
||||
* @returns an auto-updating reference to all tags or `[]` if either none are loaded yet, or there was an error
|
||||
*/
|
||||
const tags = () => {
|
||||
// Re-fetch if immediate is true or the item is not cached or older than 1 second
|
||||
if (tagsTimestamp< Date.now() - 1000) {
|
||||
axios.get<components['schemas']['PaginatedTagList']>('tags/', { params: { page_size: 10000 } }).then(({ data }) => {
|
||||
tagsTimestamp = Date.now();
|
||||
tagsCache.value = data.results;
|
||||
});
|
||||
}
|
||||
return tagsCache;
|
||||
}
|
||||
|
||||
/** Inspect the cache with the Vue Devtools (Pinia tab); read-only */
|
||||
const data = computed(() => cache)
|
||||
|
||||
|
@ -81,6 +99,8 @@ export const useDataStore
|
|||
|
||||
return {
|
||||
data,
|
||||
get
|
||||
get,
|
||||
tagsCache,
|
||||
tags
|
||||
}
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue