Fix search and dynamic ordering (#1567)
This commit is contained in:
parent
fb27bccaa3
commit
fb4f94fb73
|
@ -24,6 +24,7 @@
|
|||
"@vue/runtime-core": "3.2.38",
|
||||
"@vueuse/core": "9.1.1",
|
||||
"@vueuse/integrations": "9.1.1",
|
||||
"@vueuse/router": "9.1.1",
|
||||
"axios": "0.27.2",
|
||||
"axios-auth-refresh": "3.3.3",
|
||||
"diff": "5.1.0",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import type { ContentCategory, Channel, BackendError, Tag } from '~/types'
|
||||
import type { ContentCategory, Channel, BackendError } from '~/types'
|
||||
|
||||
import { slugify } from 'transliteration'
|
||||
import { reactive, computed, ref, watchEffect, watch } from 'vue'
|
||||
|
@ -34,7 +34,7 @@ const { $pgettext } = useGettext()
|
|||
const newValues = reactive({
|
||||
name: props.object?.artist?.name ?? '',
|
||||
username: props.object?.actor.preferred_username ?? '',
|
||||
tags: props.object?.artist?.tags?.map(name => ({ name } as Tag)) ?? [] as Tag[],
|
||||
tags: props.object?.artist?.tags ?? [] as string[],
|
||||
description: props.object?.artist?.description?.text ?? '',
|
||||
cover: props.object?.artist?.cover?.uuid ?? null,
|
||||
content_category: props.object?.artist?.content_category ?? 'podcast',
|
||||
|
|
|
@ -13,7 +13,7 @@ import useFormData from '~/composables/useFormData'
|
|||
interface Props {
|
||||
clientId: string
|
||||
redirectUri: string
|
||||
scope: string
|
||||
scope: 'me' | 'all'
|
||||
responseType: string
|
||||
nonce: string
|
||||
state: string
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import type { Upload, Tag, Track } from '~/types'
|
||||
import type { Upload, Track } from '~/types'
|
||||
|
||||
import { reactive, computed, watch } from 'vue'
|
||||
|
||||
|
@ -21,16 +21,12 @@ const props = withDefaults(defineProps<Props>(), {
|
|||
values: null
|
||||
})
|
||||
|
||||
const newValues = reactive<Omit<Values, 'tags'> & { tags: Tag[] }>({
|
||||
...(props.values ?? props.upload.import_metadata ?? {}) as Values,
|
||||
tags: ((props.values ?? props.upload.import_metadata)?.tags?.map(name => ({ name })) ?? []) as Tag[]
|
||||
const newValues = reactive<Values>({
|
||||
...(props.values ?? props.upload.import_metadata ?? {}) as Values
|
||||
})
|
||||
|
||||
const isLoading = computed(() => !props.upload)
|
||||
watch(newValues, (values) => emit('update:values', {
|
||||
...values,
|
||||
tags: values.tags?.map(({ name }) => name)
|
||||
}), { immediate: true })
|
||||
watch(newValues, (values) => emit('update:values', values), { immediate: true })
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
<script setup lang="ts">
|
||||
import type { RouteWithPreferences, OrderingField } from '~/store/ui'
|
||||
import type { OrderingProps } from '~/composables/navigation/useOrdering'
|
||||
import type { RouteRecordName } from 'vue-router'
|
||||
import type { OrderingField } from '~/store/ui'
|
||||
import type { Track } from '~/types'
|
||||
import type { OrderingProps } from '~/composables/useOrdering'
|
||||
|
||||
import { computed, onMounted, reactive, ref, watch } from 'vue'
|
||||
import { onBeforeRouteUpdate, useRouter } from 'vue-router'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
import { sortedUniq } from 'lodash-es'
|
||||
import { useStore } from '~/store'
|
||||
|
||||
import axios from 'axios'
|
||||
|
@ -16,24 +17,24 @@ import RadioButton from '~/components/radios/Button.vue'
|
|||
import Pagination from '~/components/vui/Pagination.vue'
|
||||
|
||||
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||
import useOrdering from '~/composables/navigation/useOrdering'
|
||||
import useErrorHandler from '~/composables/useErrorHandler'
|
||||
import useOrdering from '~/composables/useOrdering'
|
||||
import usePage from '~/composables/navigation/usePage'
|
||||
import useLogger from '~/composables/useLogger'
|
||||
|
||||
interface Props extends OrderingProps {
|
||||
defaultPage?: number
|
||||
|
||||
// TODO(wvffle): Remove after https://github.com/vuejs/core/pull/4512 is merged
|
||||
orderingConfigName: RouteWithPreferences | null
|
||||
orderingConfigName?: RouteRecordName
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
defaultPage: 1
|
||||
defaultPage: 1,
|
||||
orderingConfigName: undefined
|
||||
})
|
||||
|
||||
const store = useStore()
|
||||
|
||||
const page = ref(+props.defaultPage)
|
||||
const page = usePage()
|
||||
|
||||
const orderingOptions: [OrderingField, keyof typeof sharedLabels.filters][] = [
|
||||
['creation_date', 'creation_date'],
|
||||
|
@ -45,19 +46,7 @@ const orderingOptions: [OrderingField, keyof typeof sharedLabels.filters][] = [
|
|||
const logger = useLogger()
|
||||
const sharedLabels = useSharedLabels()
|
||||
|
||||
const router = useRouter()
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props.orderingConfigName)
|
||||
|
||||
const updateQueryString = () => router.replace({
|
||||
query: {
|
||||
page: page.value,
|
||||
paginateBy: paginateBy.value,
|
||||
ordering: orderingString.value
|
||||
}
|
||||
})
|
||||
|
||||
watch(page, updateQueryString)
|
||||
onOrderingUpdate(updateQueryString)
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props)
|
||||
|
||||
const results = reactive<Track[]>([])
|
||||
const nextLink = ref()
|
||||
|
@ -97,15 +86,22 @@ const fetchFavorites = async () => {
|
|||
}
|
||||
}
|
||||
|
||||
onBeforeRouteUpdate(fetchFavorites)
|
||||
watch(page, fetchFavorites)
|
||||
fetchFavorites()
|
||||
|
||||
onOrderingUpdate(() => {
|
||||
page.value = 1
|
||||
fetchFavorites()
|
||||
})
|
||||
|
||||
onMounted(() => $('.ui.dropdown').dropdown())
|
||||
|
||||
const { $pgettext } = useGettext()
|
||||
const labels = computed(() => ({
|
||||
title: $pgettext('Head/Favorites/Title', 'Your Favorites')
|
||||
}))
|
||||
|
||||
const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value].sort((a, b) => a - b)))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -194,14 +190,12 @@ const labels = computed(() => ({
|
|||
v-model="paginateBy"
|
||||
class="ui dropdown"
|
||||
>
|
||||
<option :value="12">
|
||||
12
|
||||
</option>
|
||||
<option :value="25">
|
||||
25
|
||||
</option>
|
||||
<option :value="50">
|
||||
50
|
||||
<option
|
||||
v-for="opt in paginateOptions"
|
||||
:key="opt"
|
||||
:value="opt"
|
||||
>
|
||||
{{ opt }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
<script setup lang="ts">
|
||||
import type { RouteWithPreferences, OrderingField } from '~/store/ui'
|
||||
import type { OrderingProps } from '~/composables/useOrdering'
|
||||
import type { OrderingProps } from '~/composables/navigation/useOrdering'
|
||||
import type { Album, BackendResponse } from '~/types'
|
||||
import type { RouteRecordName } from 'vue-router'
|
||||
import type { OrderingField } from '~/store/ui'
|
||||
|
||||
import { onBeforeRouteUpdate, useRouter } from 'vue-router'
|
||||
import { computed, onMounted, reactive, ref, watch } from 'vue'
|
||||
import { computed, onMounted, ref, watch } from 'vue'
|
||||
import { useRouteQuery } from '@vueuse/router'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
import { syncRef } from '@vueuse/core'
|
||||
import { sortedUniq } from 'lodash-es'
|
||||
import { useStore } from '~/store'
|
||||
|
||||
import axios from 'axios'
|
||||
|
@ -16,32 +20,32 @@ import AlbumCard from '~/components/audio/album/Card.vue'
|
|||
import Pagination from '~/components/vui/Pagination.vue'
|
||||
|
||||
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||
import useOrdering from '~/composables/navigation/useOrdering'
|
||||
import useErrorHandler from '~/composables/useErrorHandler'
|
||||
import useOrdering from '~/composables/useOrdering'
|
||||
import usePage from '~/composables/navigation/usePage'
|
||||
import useLogger from '~/composables/useLogger'
|
||||
|
||||
interface Props extends OrderingProps {
|
||||
defaultPage?: number
|
||||
defaultQuery?: string
|
||||
defaultTags?: string[]
|
||||
scope?: string
|
||||
scope?: 'me' | 'all'
|
||||
|
||||
// TODO(wvffle): Remove after https://github.com/vuejs/core/pull/4512 is merged
|
||||
orderingConfigName: RouteWithPreferences | null
|
||||
orderingConfigName?: RouteRecordName
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
defaultPage: 1,
|
||||
defaultQuery: '',
|
||||
defaultTags: () => [],
|
||||
scope: 'all'
|
||||
scope: 'all',
|
||||
orderingConfigName: undefined
|
||||
})
|
||||
|
||||
const page = ref(+props.defaultPage)
|
||||
type ResponseType = { count: number, results: any[] }
|
||||
const result = ref<null | ResponseType>(null)
|
||||
const query = ref(props.defaultQuery)
|
||||
const tags = reactive(props.defaultTags.map(name => ({ name })))
|
||||
const page = usePage()
|
||||
|
||||
const tags = useRouteQuery<string[]>('tag', [])
|
||||
|
||||
const q = useRouteQuery('query', '')
|
||||
const query = ref(q.value)
|
||||
syncRef(q, query, { direction: 'ltr' })
|
||||
|
||||
const result = ref<BackendResponse<Album>>()
|
||||
|
||||
const orderingOptions: [OrderingField, keyof typeof sharedLabels.filters][] = [
|
||||
['creation_date', 'creation_date'],
|
||||
|
@ -52,21 +56,7 @@ const orderingOptions: [OrderingField, keyof typeof sharedLabels.filters][] = [
|
|||
const logger = useLogger()
|
||||
const sharedLabels = useSharedLabels()
|
||||
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props.orderingConfigName)
|
||||
|
||||
const router = useRouter()
|
||||
const updateQueryString = () => router.replace({
|
||||
query: {
|
||||
query: query.value,
|
||||
page: page.value,
|
||||
tag: tags.map(({ name }) => name),
|
||||
paginateBy: paginateBy.value,
|
||||
ordering: orderingString.value
|
||||
}
|
||||
})
|
||||
|
||||
watch(page, updateQueryString)
|
||||
onOrderingUpdate(updateQueryString)
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props)
|
||||
|
||||
const isLoading = ref(false)
|
||||
const fetchData = async () => {
|
||||
|
@ -78,7 +68,7 @@ const fetchData = async () => {
|
|||
q: query.value,
|
||||
ordering: orderingString.value,
|
||||
playable: 'true',
|
||||
tag: tags,
|
||||
tag: tags.value,
|
||||
include_channels: 'true',
|
||||
content_category: 'music'
|
||||
}
|
||||
|
@ -95,7 +85,7 @@ const fetchData = async () => {
|
|||
result.value = response.data
|
||||
} catch (error) {
|
||||
useErrorHandler(error as Error)
|
||||
result.value = null
|
||||
result.value = undefined
|
||||
} finally {
|
||||
logger.timeEnd('Fetching albums')
|
||||
isLoading.value = false
|
||||
|
@ -104,9 +94,19 @@ const fetchData = async () => {
|
|||
|
||||
const store = useStore()
|
||||
watch(() => store.state.moderation.lastUpdate, fetchData)
|
||||
onBeforeRouteUpdate(fetchData)
|
||||
watch(page, fetchData)
|
||||
fetchData()
|
||||
|
||||
const search = () => {
|
||||
page.value = 1
|
||||
q.value = query.value
|
||||
}
|
||||
|
||||
onOrderingUpdate(() => {
|
||||
page.value = 1
|
||||
fetchData()
|
||||
})
|
||||
|
||||
onMounted(() => $('.ui.dropdown').dropdown())
|
||||
|
||||
const { $pgettext } = useGettext()
|
||||
|
@ -114,6 +114,8 @@ const labels = computed(() => ({
|
|||
searchPlaceholder: $pgettext('Content/Search/Input.Placeholder', 'Enter album title…'),
|
||||
title: $pgettext('*/*/*', 'Albums')
|
||||
}))
|
||||
|
||||
const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value].sort((a, b) => a - b)))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -126,7 +128,7 @@ const labels = computed(() => ({
|
|||
</h2>
|
||||
<form
|
||||
:class="['ui', {'loading': isLoading}, 'form']"
|
||||
@submit.prevent="page = props.defaultPage"
|
||||
@submit.prevent="search"
|
||||
>
|
||||
<div class="fields">
|
||||
<div class="field">
|
||||
|
@ -196,14 +198,12 @@ const labels = computed(() => ({
|
|||
v-model="paginateBy"
|
||||
class="ui dropdown"
|
||||
>
|
||||
<option :value="12">
|
||||
12
|
||||
</option>
|
||||
<option :value="25">
|
||||
25
|
||||
</option>
|
||||
<option :value="50">
|
||||
50
|
||||
<option
|
||||
v-for="opt in paginateOptions"
|
||||
:key="opt"
|
||||
:value="opt"
|
||||
>
|
||||
{{ opt }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
<script setup lang="ts">
|
||||
import type { RouteWithPreferences, OrderingField } from '~/store/ui'
|
||||
import type { OrderingProps } from '~/composables/useOrdering'
|
||||
import type { OrderingProps } from '~/composables/navigation/useOrdering'
|
||||
import type { Artist, BackendResponse } from '~/types'
|
||||
import type { RouteRecordName } from 'vue-router'
|
||||
import type { OrderingField } from '~/store/ui'
|
||||
|
||||
import { computed, reactive, ref, watch, onMounted } from 'vue'
|
||||
import { onBeforeRouteUpdate, useRouter } from 'vue-router'
|
||||
import { computed, ref, watch, onMounted } from 'vue'
|
||||
import { useRouteQuery } from '@vueuse/router'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
import { syncRef } from '@vueuse/core'
|
||||
import { sortedUniq } from 'lodash-es'
|
||||
import { useStore } from '~/store'
|
||||
|
||||
import axios from 'axios'
|
||||
|
@ -16,32 +20,32 @@ import ArtistCard from '~/components/audio/artist/Card.vue'
|
|||
import Pagination from '~/components/vui/Pagination.vue'
|
||||
|
||||
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||
import useOrdering from '~/composables/navigation/useOrdering'
|
||||
import useErrorHandler from '~/composables/useErrorHandler'
|
||||
import useOrdering from '~/composables/useOrdering'
|
||||
import usePage from '~/composables/navigation/usePage'
|
||||
import useLogger from '~/composables/useLogger'
|
||||
|
||||
interface Props extends OrderingProps {
|
||||
defaultPage?: number
|
||||
defaultQuery?: string
|
||||
defaultTags?: string[]
|
||||
scope?: string
|
||||
scope?: 'me' | 'all'
|
||||
|
||||
// TODO(wvffle): Remove after https://github.com/vuejs/core/pull/4512 is merged
|
||||
orderingConfigName: RouteWithPreferences | null
|
||||
orderingConfigName?: RouteRecordName
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
defaultPage: 1,
|
||||
defaultQuery: '',
|
||||
defaultTags: () => [],
|
||||
scope: 'all'
|
||||
scope: 'all',
|
||||
orderingConfigName: undefined
|
||||
})
|
||||
|
||||
const page = ref(+props.defaultPage)
|
||||
type ResponseType = { count: number, results: any[] }
|
||||
const result = ref<null | ResponseType>(null)
|
||||
const query = ref(props.defaultQuery)
|
||||
const tags = reactive(props.defaultTags.map(name => ({ name })))
|
||||
const page = usePage()
|
||||
|
||||
const tags = useRouteQuery<string[]>('tag', [])
|
||||
|
||||
const q = useRouteQuery('query', '')
|
||||
const query = ref(q.value)
|
||||
syncRef(q, query, { direction: 'ltr' })
|
||||
|
||||
const result = ref<BackendResponse<Artist>>()
|
||||
const excludeCompilation = ref(true)
|
||||
|
||||
const orderingOptions: [OrderingField, keyof typeof sharedLabels.filters][] = [
|
||||
|
@ -52,23 +56,7 @@ const orderingOptions: [OrderingField, keyof typeof sharedLabels.filters][] = [
|
|||
const logger = useLogger()
|
||||
const sharedLabels = useSharedLabels()
|
||||
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props.orderingConfigName)
|
||||
|
||||
const router = useRouter()
|
||||
const updateQueryString = () => router.replace({
|
||||
query: {
|
||||
query: query.value,
|
||||
page: page.value,
|
||||
tag: tags.map(({ name }) => name),
|
||||
paginateBy: paginateBy.value,
|
||||
ordering: orderingString.value,
|
||||
content_category: 'music',
|
||||
include_channels: 'true'
|
||||
}
|
||||
})
|
||||
|
||||
watch(page, updateQueryString)
|
||||
onOrderingUpdate(updateQueryString)
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props)
|
||||
|
||||
const isLoading = ref(false)
|
||||
const fetchData = async () => {
|
||||
|
@ -80,7 +68,7 @@ const fetchData = async () => {
|
|||
q: query.value,
|
||||
ordering: orderingString.value,
|
||||
playable: 'true',
|
||||
tag: tags,
|
||||
tag: tags.value,
|
||||
include_channels: 'true',
|
||||
content_category: 'music',
|
||||
has_albums: excludeCompilation.value
|
||||
|
@ -98,7 +86,7 @@ const fetchData = async () => {
|
|||
result.value = response.data
|
||||
} catch (error) {
|
||||
useErrorHandler(error as Error)
|
||||
result.value = null
|
||||
result.value = undefined
|
||||
} finally {
|
||||
logger.timeEnd('Fetching artists')
|
||||
isLoading.value = false
|
||||
|
@ -107,9 +95,19 @@ const fetchData = async () => {
|
|||
|
||||
const store = useStore()
|
||||
watch([() => store.state.moderation.lastUpdate, excludeCompilation], fetchData)
|
||||
onBeforeRouteUpdate(fetchData)
|
||||
watch(page, fetchData)
|
||||
fetchData()
|
||||
|
||||
const search = () => {
|
||||
page.value = 1
|
||||
q.value = query.value
|
||||
}
|
||||
|
||||
onOrderingUpdate(() => {
|
||||
page.value = 1
|
||||
fetchData()
|
||||
})
|
||||
|
||||
onMounted(() => $('.ui.dropdown').dropdown())
|
||||
|
||||
const { $pgettext } = useGettext()
|
||||
|
@ -117,6 +115,8 @@ const labels = computed(() => ({
|
|||
searchPlaceholder: $pgettext('Content/Search/Input.Placeholder', 'Search…'),
|
||||
title: $pgettext('*/*/*/Noun', 'Artists')
|
||||
}))
|
||||
|
||||
const paginateOptions = computed(() => sortedUniq([12, 30, 50, paginateBy.value].sort((a, b) => a - b)))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -129,7 +129,7 @@ const labels = computed(() => ({
|
|||
</h2>
|
||||
<form
|
||||
:class="['ui', {'loading': isLoading}, 'form']"
|
||||
@submit.prevent="page = props.defaultPage"
|
||||
@submit.prevent="search"
|
||||
>
|
||||
<div class="fields">
|
||||
<div class="field">
|
||||
|
@ -199,14 +199,12 @@ const labels = computed(() => ({
|
|||
v-model="paginateBy"
|
||||
class="ui dropdown"
|
||||
>
|
||||
<option :value="12">
|
||||
12
|
||||
</option>
|
||||
<option :value="30">
|
||||
30
|
||||
</option>
|
||||
<option :value="50">
|
||||
50
|
||||
<option
|
||||
v-for="opt in paginateOptions"
|
||||
:key="opt"
|
||||
:value="opt"
|
||||
>
|
||||
{{ opt }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import type { VueUploadItem } from 'vue-upload-component'
|
||||
import type { BackendError, Library, FileSystem } from '~/types'
|
||||
import type { VueUploadItem } from 'vue-upload-component'
|
||||
|
||||
import { computed, ref, reactive, watch, nextTick } from 'vue'
|
||||
import { useEventListener, useIntervalFn } from '@vueuse/core'
|
||||
|
@ -268,7 +268,8 @@ const inputFile = (newFile: VueUploadItem) => {
|
|||
}
|
||||
}
|
||||
|
||||
const retry = (files: VueUploadItem[]) => {
|
||||
// NOTE: For some weird reason typescript thinks that xhr field is not compatible with the same type
|
||||
const retry = (files: Omit<VueUploadItem, 'xhr'>[]) => {
|
||||
for (const file of files) {
|
||||
upload.value.update(file, { error: '', progress: '0.00' })
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="main pusher page-library">
|
||||
<router-view :key="$route.fullPath" />
|
||||
<router-view />
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
<script setup lang="ts">
|
||||
import type { RouteWithPreferences, OrderingField } from '~/store/ui'
|
||||
import type { OrderingProps } from '~/composables/useOrdering'
|
||||
import type { OrderingProps } from '~/composables/navigation/useOrdering'
|
||||
import type { Artist, BackendResponse } from '~/types'
|
||||
import type { RouteRecordName } from 'vue-router'
|
||||
import type { OrderingField } from '~/store/ui'
|
||||
|
||||
import { computed, reactive, ref, watch, onMounted } from 'vue'
|
||||
import { onBeforeRouteUpdate, useRouter } from 'vue-router'
|
||||
import { computed, ref, watch, onMounted } from 'vue'
|
||||
import { useRouteQuery } from '@vueuse/router'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
import { syncRef } from '@vueuse/core'
|
||||
import { sortedUniq } from 'lodash-es'
|
||||
import { useStore } from '~/store'
|
||||
|
||||
import axios from 'axios'
|
||||
|
@ -18,33 +22,32 @@ import ArtistCard from '~/components/audio/artist/Card.vue'
|
|||
import Pagination from '~/components/vui/Pagination.vue'
|
||||
|
||||
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||
import useOrdering from '~/composables/navigation/useOrdering'
|
||||
import useErrorHandler from '~/composables/useErrorHandler'
|
||||
import useOrdering from '~/composables/useOrdering'
|
||||
import usePage from '~/composables/navigation/usePage'
|
||||
import useLogger from '~/composables/useLogger'
|
||||
|
||||
interface Props extends OrderingProps {
|
||||
defaultPage?: number
|
||||
|
||||
defaultQuery?: string
|
||||
defaultTags?: string[]
|
||||
scope?: string
|
||||
scope?: 'me' | 'all'
|
||||
|
||||
// TODO(wvffle): Remove after https://github.com/vuejs/core/pull/4512 is merged
|
||||
orderingConfigName: RouteWithPreferences | null
|
||||
orderingConfigName?: RouteRecordName
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
defaultPage: 1,
|
||||
defaultQuery: '',
|
||||
defaultTags: () => [],
|
||||
scope: 'all'
|
||||
scope: 'all',
|
||||
orderingConfigName: undefined
|
||||
})
|
||||
|
||||
const page = ref(+props.defaultPage)
|
||||
type ResponseType = { count: number, results: any[] }
|
||||
const result = ref<null | ResponseType>(null)
|
||||
const query = ref(props.defaultQuery)
|
||||
const tags = reactive(props.defaultTags.map(name => ({ name })))
|
||||
const page = usePage()
|
||||
|
||||
const tags = useRouteQuery<string[]>('tag', [])
|
||||
|
||||
const q = useRouteQuery('query', '')
|
||||
const query = ref(q.value)
|
||||
syncRef(q, query, { direction: 'ltr' })
|
||||
|
||||
const result = ref<BackendResponse<Artist>>()
|
||||
const showSubscribeModal = ref(false)
|
||||
|
||||
const orderingOptions: [OrderingField, keyof typeof sharedLabels.filters][] = [
|
||||
|
@ -55,23 +58,7 @@ const orderingOptions: [OrderingField, keyof typeof sharedLabels.filters][] = [
|
|||
const logger = useLogger()
|
||||
const sharedLabels = useSharedLabels()
|
||||
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props.orderingConfigName)
|
||||
|
||||
const router = useRouter()
|
||||
const updateQueryString = () => router.replace({
|
||||
query: {
|
||||
query: query.value,
|
||||
page: page.value,
|
||||
tag: tags.map(({ name }) => name),
|
||||
paginateBy: paginateBy.value,
|
||||
ordering: orderingString.value,
|
||||
content_category: 'podcast',
|
||||
include_channels: 'true'
|
||||
}
|
||||
})
|
||||
|
||||
watch(page, updateQueryString)
|
||||
onOrderingUpdate(updateQueryString)
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props)
|
||||
|
||||
const isLoading = ref(false)
|
||||
const fetchData = async () => {
|
||||
|
@ -83,7 +70,7 @@ const fetchData = async () => {
|
|||
q: query.value,
|
||||
ordering: orderingString.value,
|
||||
playable: 'true',
|
||||
tag: tags,
|
||||
tag: tags.value,
|
||||
include_channels: 'true',
|
||||
content_category: 'podcast'
|
||||
}
|
||||
|
@ -100,7 +87,7 @@ const fetchData = async () => {
|
|||
result.value = response.data
|
||||
} catch (error) {
|
||||
useErrorHandler(error as Error)
|
||||
result.value = null
|
||||
result.value = undefined
|
||||
} finally {
|
||||
logger.timeEnd('Fetching podcasts')
|
||||
isLoading.value = false
|
||||
|
@ -109,9 +96,19 @@ const fetchData = async () => {
|
|||
|
||||
const store = useStore()
|
||||
watch(() => store.state.moderation.lastUpdate, fetchData)
|
||||
onBeforeRouteUpdate(fetchData)
|
||||
watch(page, fetchData)
|
||||
fetchData()
|
||||
|
||||
const search = () => {
|
||||
page.value = 1
|
||||
q.value = query.value
|
||||
}
|
||||
|
||||
onOrderingUpdate(() => {
|
||||
page.value = 1
|
||||
fetchData()
|
||||
})
|
||||
|
||||
onMounted(() => $('.ui.dropdown').dropdown())
|
||||
|
||||
const { $pgettext } = useGettext()
|
||||
|
@ -119,6 +116,8 @@ const labels = computed(() => ({
|
|||
searchPlaceholder: $pgettext('Content/Search/Input.Placeholder', 'Search…'),
|
||||
title: $pgettext('*/*/*/Noun', 'Podcasts')
|
||||
}))
|
||||
|
||||
const paginateOptions = computed(() => sortedUniq([12, 30, 50, paginateBy.value].sort((a, b) => a - b)))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -131,7 +130,7 @@ const labels = computed(() => ({
|
|||
</h2>
|
||||
<form
|
||||
:class="['ui', {'loading': isLoading}, 'form']"
|
||||
@submit.prevent="page = props.defaultPage"
|
||||
@submit.prevent="search"
|
||||
>
|
||||
<div class="fields">
|
||||
<div class="field">
|
||||
|
@ -201,14 +200,12 @@ const labels = computed(() => ({
|
|||
v-model="paginateBy"
|
||||
class="ui dropdown"
|
||||
>
|
||||
<option :value="12">
|
||||
12
|
||||
</option>
|
||||
<option :value="30">
|
||||
30
|
||||
</option>
|
||||
<option :value="50">
|
||||
50
|
||||
<option
|
||||
v-for="opt in paginateOptions"
|
||||
:key="opt"
|
||||
:value="opt"
|
||||
>
|
||||
{{ opt }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
<script setup lang="ts">
|
||||
import type { RouteWithPreferences, OrderingField } from '~/store/ui'
|
||||
import type { OrderingProps } from '~/composables/useOrdering'
|
||||
import type { OrderingProps } from '~/composables/navigation/useOrdering'
|
||||
import type { Radio, BackendResponse } from '~/types'
|
||||
import type { RouteRecordName } from 'vue-router'
|
||||
import type { OrderingField } from '~/store/ui'
|
||||
|
||||
import { onBeforeRouteUpdate, useRouter } from 'vue-router'
|
||||
import { computed, ref, watch, onMounted } from 'vue'
|
||||
import { computed, onMounted, ref, watch } from 'vue'
|
||||
import { useRouteQuery } from '@vueuse/router'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
import { syncRef } from '@vueuse/core'
|
||||
import { sortedUniq } from 'lodash-es'
|
||||
import { useStore } from '~/store'
|
||||
|
||||
import axios from 'axios'
|
||||
|
@ -14,30 +18,30 @@ import Pagination from '~/components/vui/Pagination.vue'
|
|||
import RadioCard from '~/components/radios/Card.vue'
|
||||
|
||||
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||
import useOrdering from '~/composables/navigation/useOrdering'
|
||||
import useErrorHandler from '~/composables/useErrorHandler'
|
||||
import useOrdering from '~/composables/useOrdering'
|
||||
import usePage from '~/composables/navigation/usePage'
|
||||
import useLogger from '~/composables/useLogger'
|
||||
|
||||
interface Props extends OrderingProps {
|
||||
defaultPage?: number
|
||||
|
||||
defaultQuery?: string
|
||||
scope?: string
|
||||
scope?: 'me' | 'all'
|
||||
|
||||
// TODO(wvffle): Remove after https://github.com/vuejs/core/pull/4512 is merged
|
||||
orderingConfigName: RouteWithPreferences | null
|
||||
orderingConfigName?: RouteRecordName
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
defaultPage: 1,
|
||||
defaultQuery: '',
|
||||
scope: 'all'
|
||||
scope: 'all',
|
||||
orderingConfigName: undefined
|
||||
})
|
||||
|
||||
const page = ref(+props.defaultPage)
|
||||
type ResponseType = { count: number, results: any[] }
|
||||
const result = ref<null | ResponseType>(null)
|
||||
const query = ref(props.defaultQuery)
|
||||
const page = usePage()
|
||||
|
||||
const q = useRouteQuery('query', '')
|
||||
const query = ref(q.value)
|
||||
syncRef(q, query, { direction: 'ltr' })
|
||||
|
||||
const result = ref<BackendResponse<Radio>>()
|
||||
|
||||
const orderingOptions: [OrderingField, keyof typeof sharedLabels.filters][] = [
|
||||
['creation_date', 'creation_date'],
|
||||
|
@ -47,20 +51,7 @@ const orderingOptions: [OrderingField, keyof typeof sharedLabels.filters][] = [
|
|||
const logger = useLogger()
|
||||
const sharedLabels = useSharedLabels()
|
||||
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props.orderingConfigName)
|
||||
|
||||
const router = useRouter()
|
||||
const updateQueryString = () => router.replace({
|
||||
query: {
|
||||
query: query.value,
|
||||
page: page.value,
|
||||
paginateBy: paginateBy.value,
|
||||
ordering: orderingString.value
|
||||
}
|
||||
})
|
||||
|
||||
watch(page, updateQueryString)
|
||||
onOrderingUpdate(updateQueryString)
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props)
|
||||
|
||||
const isLoading = ref(false)
|
||||
const fetchData = async () => {
|
||||
|
@ -82,7 +73,7 @@ const fetchData = async () => {
|
|||
result.value = response.data
|
||||
} catch (error) {
|
||||
useErrorHandler(error as Error)
|
||||
result.value = null
|
||||
result.value = undefined
|
||||
} finally {
|
||||
logger.timeEnd('Fetching radios')
|
||||
isLoading.value = false
|
||||
|
@ -93,9 +84,19 @@ const store = useStore()
|
|||
const isAuthenticated = computed(() => store.state.auth.authenticated)
|
||||
const hasFavorites = computed(() => store.state.favorites.count > 0)
|
||||
|
||||
onBeforeRouteUpdate(fetchData)
|
||||
watch(page, fetchData)
|
||||
fetchData()
|
||||
|
||||
const search = () => {
|
||||
page.value = 1
|
||||
q.value = query.value
|
||||
}
|
||||
|
||||
onOrderingUpdate(() => {
|
||||
page.value = 1
|
||||
fetchData()
|
||||
})
|
||||
|
||||
onMounted(() => $('.ui.dropdown').dropdown())
|
||||
|
||||
const { $pgettext } = useGettext()
|
||||
|
@ -103,6 +104,8 @@ const labels = computed(() => ({
|
|||
searchPlaceholder: $pgettext('Content/Search/Input.Placeholder', 'Enter a radio name…'),
|
||||
title: $pgettext('*/*/*', 'Radios')
|
||||
}))
|
||||
|
||||
const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value].sort((a, b) => a - b)))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -157,7 +160,7 @@ const labels = computed(() => ({
|
|||
<div class="ui hidden divider" />
|
||||
<form
|
||||
:class="['ui', {'loading': isLoading}, 'form']"
|
||||
@submit.prevent="page = props.defaultPage"
|
||||
@submit.prevent="search"
|
||||
>
|
||||
<div class="fields">
|
||||
<div class="field">
|
||||
|
@ -221,14 +224,12 @@ const labels = computed(() => ({
|
|||
v-model="paginateBy"
|
||||
class="ui dropdown"
|
||||
>
|
||||
<option :value="12">
|
||||
12
|
||||
</option>
|
||||
<option :value="25">
|
||||
25
|
||||
</option>
|
||||
<option :value="50">
|
||||
50
|
||||
<option
|
||||
v-for="opt in paginateOptions"
|
||||
:key="opt"
|
||||
:value="opt"
|
||||
>
|
||||
{{ opt }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
|
|
@ -8,11 +8,11 @@ import { useStore } from '~/store'
|
|||
import $ from 'jquery'
|
||||
|
||||
interface Events {
|
||||
(e: 'update:modelValue', tags: Tag[]): void
|
||||
(e: 'update:modelValue', tags: string[]): void
|
||||
}
|
||||
|
||||
interface Props {
|
||||
modelValue: Tag[]
|
||||
modelValue: string[]
|
||||
}
|
||||
|
||||
const emit = defineEmits<Events>()
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
<script setup lang="ts">
|
||||
import type { RouteWithPreferences, OrderingField } from '~/store/ui'
|
||||
import type { SmartSearchProps } from '~/composables/useSmartSearch'
|
||||
import type { OrderingProps } from '~/composables/useOrdering'
|
||||
import type { SmartSearchProps } from '~/composables/navigation/useSmartSearch'
|
||||
import type { OrderingProps } from '~/composables/navigation/useOrdering'
|
||||
import type { RouteRecordName } from 'vue-router'
|
||||
import type { OrderingField } from '~/store/ui'
|
||||
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
@ -11,16 +12,17 @@ import axios from 'axios'
|
|||
import ActionTable from '~/components/common/ActionTable.vue'
|
||||
import Pagination from '~/components/vui/Pagination.vue'
|
||||
|
||||
import useSmartSearch from '~/composables/navigation/useSmartSearch'
|
||||
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||
import useOrdering from '~/composables/navigation/useOrdering'
|
||||
import useErrorHandler from '~/composables/useErrorHandler'
|
||||
import useSmartSearch from '~/composables/useSmartSearch'
|
||||
import useOrdering from '~/composables/useOrdering'
|
||||
import usePage from '~/composables/navigation/usePage'
|
||||
|
||||
interface Props extends SmartSearchProps, OrderingProps {
|
||||
filters?: object
|
||||
|
||||
// TODO(wvffle): Remove after https://github.com/vuejs/core/pull/4512 is merged
|
||||
orderingConfigName: RouteWithPreferences | null
|
||||
orderingConfigName?: RouteRecordName
|
||||
defaultQuery?: string
|
||||
updateUrl?: boolean
|
||||
}
|
||||
|
@ -28,16 +30,17 @@ interface Props extends SmartSearchProps, OrderingProps {
|
|||
const props = withDefaults(defineProps<Props>(), {
|
||||
defaultQuery: '',
|
||||
updateUrl: false,
|
||||
filters: () => ({})
|
||||
filters: () => ({}),
|
||||
orderingConfigName: undefined
|
||||
})
|
||||
|
||||
const page = ref(1)
|
||||
const page = usePage()
|
||||
type ResponseType = { count: number, results: any[] }
|
||||
const result = ref<null | ResponseType>(null)
|
||||
const search = ref()
|
||||
|
||||
const { onSearch, query, addSearchToken, getTokenValue } = useSmartSearch(props.defaultQuery, props.updateUrl)
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props.orderingConfigName)
|
||||
const { onSearch, query, addSearchToken, getTokenValue } = useSmartSearch(props)
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props)
|
||||
|
||||
const orderingOptions: [OrderingField, keyof typeof sharedLabels.filters][] = [
|
||||
['creation_date', 'creation_date'],
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
<script setup lang="ts">
|
||||
import type { RouteWithPreferences, OrderingField } from '~/store/ui'
|
||||
import type { SmartSearchProps } from '~/composables/useSmartSearch'
|
||||
import type { OrderingProps } from '~/composables/useOrdering'
|
||||
import type { SmartSearchProps } from '~/composables/navigation/useSmartSearch'
|
||||
import type { OrderingProps } from '~/composables/navigation/useOrdering'
|
||||
import type { RouteRecordName } from 'vue-router'
|
||||
import type { OrderingField } from '~/store/ui'
|
||||
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
@ -11,16 +12,17 @@ import axios from 'axios'
|
|||
import ActionTable from '~/components/common/ActionTable.vue'
|
||||
import Pagination from '~/components/vui/Pagination.vue'
|
||||
|
||||
import useSmartSearch from '~/composables/navigation/useSmartSearch'
|
||||
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||
import useOrdering from '~/composables/navigation/useOrdering'
|
||||
import useErrorHandler from '~/composables/useErrorHandler'
|
||||
import useSmartSearch from '~/composables/useSmartSearch'
|
||||
import useOrdering from '~/composables/useOrdering'
|
||||
import usePage from '~/composables/navigation/usePage'
|
||||
|
||||
interface Props extends SmartSearchProps, OrderingProps {
|
||||
filters?: object
|
||||
|
||||
// TODO(wvffle): Remove after https://github.com/vuejs/core/pull/4512 is merged
|
||||
orderingConfigName: RouteWithPreferences | null
|
||||
orderingConfigName?: RouteRecordName
|
||||
defaultQuery?: string
|
||||
updateUrl?: boolean
|
||||
}
|
||||
|
@ -28,17 +30,18 @@ interface Props extends SmartSearchProps, OrderingProps {
|
|||
const props = withDefaults(defineProps<Props>(), {
|
||||
defaultQuery: '',
|
||||
updateUrl: false,
|
||||
filters: () => ({})
|
||||
filters: () => ({}),
|
||||
orderingConfigName: undefined
|
||||
})
|
||||
|
||||
const search = ref()
|
||||
|
||||
const page = ref(1)
|
||||
const page = usePage()
|
||||
type ResponseType = { count: number, results: any[] }
|
||||
const result = ref<null | ResponseType>(null)
|
||||
|
||||
const { onSearch, query, addSearchToken } = useSmartSearch(props.defaultQuery, props.updateUrl)
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props.orderingConfigName)
|
||||
const { onSearch, query, addSearchToken } = useSmartSearch(props)
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props)
|
||||
|
||||
const orderingOptions: [OrderingField, keyof typeof sharedLabels.filters][] = [
|
||||
['creation_date', 'creation_date'],
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
<script setup lang="ts">
|
||||
import type { RouteWithPreferences, OrderingField } from '~/store/ui'
|
||||
import type { OrderingProps } from '~/composables/useOrdering'
|
||||
import type { SmartSearchProps } from '~/composables/useSmartSearch'
|
||||
import type { SmartSearchProps } from '~/composables/navigation/useSmartSearch'
|
||||
import type { OrderingProps } from '~/composables/navigation/useOrdering'
|
||||
import type { RouteRecordName } from 'vue-router'
|
||||
import type { OrderingField } from '~/store/ui'
|
||||
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
@ -11,16 +12,17 @@ import axios from 'axios'
|
|||
import ActionTable from '~/components/common/ActionTable.vue'
|
||||
import Pagination from '~/components/vui/Pagination.vue'
|
||||
|
||||
import useSmartSearch from '~/composables/navigation/useSmartSearch'
|
||||
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||
import useOrdering from '~/composables/navigation/useOrdering'
|
||||
import useErrorHandler from '~/composables/useErrorHandler'
|
||||
import useSmartSearch from '~/composables/useSmartSearch'
|
||||
import useOrdering from '~/composables/useOrdering'
|
||||
import usePage from '~/composables/navigation/usePage'
|
||||
|
||||
interface Props extends SmartSearchProps, OrderingProps {
|
||||
filters?: object
|
||||
|
||||
// TODO(wvffle): Remove after https://github.com/vuejs/core/pull/4512 is merged
|
||||
orderingConfigName: RouteWithPreferences | null
|
||||
orderingConfigName?: RouteRecordName
|
||||
defaultQuery?: string
|
||||
updateUrl?: boolean
|
||||
}
|
||||
|
@ -28,17 +30,18 @@ interface Props extends SmartSearchProps, OrderingProps {
|
|||
const props = withDefaults(defineProps<Props>(), {
|
||||
defaultQuery: '',
|
||||
updateUrl: false,
|
||||
filters: () => ({})
|
||||
filters: () => ({}),
|
||||
orderingConfigName: undefined
|
||||
})
|
||||
|
||||
const search = ref()
|
||||
|
||||
const page = ref(1)
|
||||
const page = usePage()
|
||||
type ResponseType = { count: number, results: any[] }
|
||||
const result = ref<null | ResponseType>(null)
|
||||
|
||||
const { onSearch, query, addSearchToken, getTokenValue } = useSmartSearch(props.defaultQuery, props.updateUrl)
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props.orderingConfigName)
|
||||
const { onSearch, query, addSearchToken, getTokenValue } = useSmartSearch(props)
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props)
|
||||
|
||||
const orderingOptions: [OrderingField, keyof typeof sharedLabels.filters][] = [
|
||||
['creation_date', 'creation_date'],
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
<script setup lang="ts">
|
||||
import type { SmartSearchProps } from '~/composables/navigation/useSmartSearch'
|
||||
import type { EditObjectType } from '~/composables/moderation/useEditConfigs'
|
||||
import type { RouteWithPreferences, OrderingField } from '~/store/ui'
|
||||
import type { SmartSearchProps } from '~/composables/useSmartSearch'
|
||||
import type { OrderingProps } from '~/composables/useOrdering'
|
||||
import type { OrderingProps } from '~/composables/navigation/useOrdering'
|
||||
import type { ReviewState, Review } from '~/types'
|
||||
import type { RouteRecordName } from 'vue-router'
|
||||
import type { OrderingField } from '~/store/ui'
|
||||
|
||||
import { ref, reactive, watch, computed } from 'vue'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
@ -15,16 +16,17 @@ import Pagination from '~/components/vui/Pagination.vue'
|
|||
import EditCard from '~/components/library/EditCard.vue'
|
||||
|
||||
import useEditConfigs from '~/composables/moderation/useEditConfigs'
|
||||
import useSmartSearch from '~/composables/navigation/useSmartSearch'
|
||||
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||
import useOrdering from '~/composables/navigation/useOrdering'
|
||||
import useErrorHandler from '~/composables/useErrorHandler'
|
||||
import useSmartSearch from '~/composables/useSmartSearch'
|
||||
import useOrdering from '~/composables/useOrdering'
|
||||
import usePage from '~/composables/navigation/usePage'
|
||||
|
||||
interface Props extends SmartSearchProps, OrderingProps {
|
||||
filters?: object
|
||||
|
||||
// TODO(wvffle): Remove after https://github.com/vuejs/core/pull/4512 is merged
|
||||
orderingConfigName: RouteWithPreferences | null
|
||||
orderingConfigName?: RouteRecordName
|
||||
defaultQuery?: string
|
||||
updateUrl?: boolean
|
||||
}
|
||||
|
@ -32,20 +34,21 @@ interface Props extends SmartSearchProps, OrderingProps {
|
|||
const props = withDefaults(defineProps<Props>(), {
|
||||
defaultQuery: '',
|
||||
updateUrl: false,
|
||||
filters: () => ({})
|
||||
filters: () => ({}),
|
||||
orderingConfigName: undefined
|
||||
})
|
||||
|
||||
const configs = useEditConfigs()
|
||||
const search = ref()
|
||||
|
||||
const page = ref(1)
|
||||
const page = usePage()
|
||||
|
||||
type StateTarget = Review['target']
|
||||
type ResponseType = { count: number, results: Review[] }
|
||||
const result = ref<null | ResponseType>(null)
|
||||
|
||||
const { onSearch, query, addSearchToken, getTokenValue } = useSmartSearch(props.defaultQuery, props.updateUrl)
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props.orderingConfigName)
|
||||
const { onSearch, query, addSearchToken, getTokenValue } = useSmartSearch(props)
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props)
|
||||
|
||||
const orderingOptions: [OrderingField, keyof typeof sharedLabels.filters][] = [
|
||||
['creation_date', 'creation_date'],
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
<script setup lang="ts">
|
||||
import type { RouteWithPreferences, OrderingField } from '~/store/ui'
|
||||
import type { SmartSearchProps } from '~/composables/useSmartSearch'
|
||||
import type { OrderingProps } from '~/composables/useOrdering'
|
||||
import type { SmartSearchProps } from '~/composables/navigation/useSmartSearch'
|
||||
import type { OrderingProps } from '~/composables/navigation/useOrdering'
|
||||
import type { RouteRecordName } from 'vue-router'
|
||||
import type { OrderingField } from '~/store/ui'
|
||||
import type { PrivacyLevel } from '~/types'
|
||||
|
||||
import { computed, ref, watch } from 'vue'
|
||||
|
@ -12,15 +13,16 @@ import ActionTable from '~/components/common/ActionTable.vue'
|
|||
import Pagination from '~/components/vui/Pagination.vue'
|
||||
|
||||
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||
import useSmartSearch from '~/composables/navigation/useSmartSearch'
|
||||
import useOrdering from '~/composables/navigation/useOrdering'
|
||||
import useErrorHandler from '~/composables/useErrorHandler'
|
||||
import useSmartSearch from '~/composables/useSmartSearch'
|
||||
import useOrdering from '~/composables/useOrdering'
|
||||
import usePage from '~/composables/navigation/usePage'
|
||||
|
||||
interface Props extends SmartSearchProps, OrderingProps {
|
||||
filters?: object
|
||||
|
||||
// TODO(wvffle): Remove after https://github.com/vuejs/core/pull/4512 is merged
|
||||
orderingConfigName: RouteWithPreferences | null
|
||||
orderingConfigName?: RouteRecordName
|
||||
defaultQuery?: string
|
||||
updateUrl?: boolean
|
||||
}
|
||||
|
@ -28,17 +30,18 @@ interface Props extends SmartSearchProps, OrderingProps {
|
|||
const props = withDefaults(defineProps<Props>(), {
|
||||
defaultQuery: '',
|
||||
updateUrl: false,
|
||||
filters: () => ({})
|
||||
filters: () => ({}),
|
||||
orderingConfigName: undefined
|
||||
})
|
||||
|
||||
const search = ref()
|
||||
|
||||
const page = ref(1)
|
||||
const page = usePage()
|
||||
type ResponseType = { count: number, results: any[] }
|
||||
const result = ref<null | ResponseType>(null)
|
||||
|
||||
const { onSearch, query, addSearchToken, getTokenValue } = useSmartSearch(props.defaultQuery, props.updateUrl)
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props.orderingConfigName)
|
||||
const { onSearch, query, addSearchToken, getTokenValue } = useSmartSearch(props)
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props)
|
||||
|
||||
const orderingOptions: [OrderingField, keyof typeof sharedLabels.filters][] = [
|
||||
['creation_date', 'creation_date'],
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
<script setup lang="ts">
|
||||
import type { RouteWithPreferences, OrderingField } from '~/store/ui'
|
||||
import type { SmartSearchProps } from '~/composables/useSmartSearch'
|
||||
import type { OrderingProps } from '~/composables/useOrdering'
|
||||
import type { SmartSearchProps } from '~/composables/navigation/useSmartSearch'
|
||||
import type { OrderingProps } from '~/composables/navigation/useOrdering'
|
||||
import type { RouteRecordName } from 'vue-router'
|
||||
import type { OrderingField } from '~/store/ui'
|
||||
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { truncate } from '~/utils/filters'
|
||||
|
@ -14,15 +15,16 @@ import ActionTable from '~/components/common/ActionTable.vue'
|
|||
import Pagination from '~/components/vui/Pagination.vue'
|
||||
|
||||
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||
import useSmartSearch from '~/composables/navigation/useSmartSearch'
|
||||
import useOrdering from '~/composables/navigation/useOrdering'
|
||||
import useErrorHandler from '~/composables/useErrorHandler'
|
||||
import useSmartSearch from '~/composables/useSmartSearch'
|
||||
import useOrdering from '~/composables/useOrdering'
|
||||
import usePage from '~/composables/navigation/usePage'
|
||||
|
||||
interface Props extends SmartSearchProps, OrderingProps {
|
||||
filters?: object
|
||||
|
||||
// TODO(wvffle): Remove after https://github.com/vuejs/core/pull/4512 is merged
|
||||
orderingConfigName: RouteWithPreferences | null
|
||||
orderingConfigName?: RouteRecordName
|
||||
defaultQuery?: string
|
||||
updateUrl?: boolean
|
||||
}
|
||||
|
@ -30,17 +32,18 @@ interface Props extends SmartSearchProps, OrderingProps {
|
|||
const props = withDefaults(defineProps<Props>(), {
|
||||
defaultQuery: '',
|
||||
updateUrl: false,
|
||||
filters: () => ({})
|
||||
filters: () => ({}),
|
||||
orderingConfigName: undefined
|
||||
})
|
||||
|
||||
const search = ref()
|
||||
|
||||
const page = ref(1)
|
||||
const page = usePage()
|
||||
type ResponseType = { count: number, results: any[] }
|
||||
const result = ref<null | ResponseType>(null)
|
||||
|
||||
const { onSearch, query } = useSmartSearch(props.defaultQuery, props.updateUrl)
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props.orderingConfigName)
|
||||
const { onSearch, query } = useSmartSearch(props)
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props)
|
||||
|
||||
const orderingOptions: [OrderingField, keyof typeof sharedLabels.filters][] = [
|
||||
['creation_date', 'creation_date'],
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
<script setup lang="ts">
|
||||
import type { RouteWithPreferences, OrderingField } from '~/store/ui'
|
||||
import type { SmartSearchProps } from '~/composables/useSmartSearch'
|
||||
import type { OrderingProps } from '~/composables/useOrdering'
|
||||
import type { SmartSearchProps } from '~/composables/navigation/useSmartSearch'
|
||||
import type { OrderingProps } from '~/composables/navigation/useOrdering'
|
||||
import type { RouteRecordName } from 'vue-router'
|
||||
import type { OrderingField } from '~/store/ui'
|
||||
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
@ -12,15 +13,16 @@ import useSharedLabels from '~/composables/locale/useSharedLabels'
|
|||
import ActionTable from '~/components/common/ActionTable.vue'
|
||||
import Pagination from '~/components/vui/Pagination.vue'
|
||||
|
||||
import useSmartSearch from '~/composables/navigation/useSmartSearch'
|
||||
import useOrdering from '~/composables/navigation/useOrdering'
|
||||
import useErrorHandler from '~/composables/useErrorHandler'
|
||||
import useSmartSearch from '~/composables/useSmartSearch'
|
||||
import useOrdering from '~/composables/useOrdering'
|
||||
import usePage from '~/composables/navigation/usePage'
|
||||
|
||||
interface Props extends SmartSearchProps, OrderingProps {
|
||||
filters?: object
|
||||
|
||||
// TODO(wvffle): Remove after https://github.com/vuejs/core/pull/4512 is merged
|
||||
orderingConfigName: RouteWithPreferences | null
|
||||
orderingConfigName?: RouteRecordName
|
||||
defaultQuery?: string
|
||||
updateUrl?: boolean
|
||||
}
|
||||
|
@ -28,17 +30,18 @@ interface Props extends SmartSearchProps, OrderingProps {
|
|||
const props = withDefaults(defineProps<Props>(), {
|
||||
defaultQuery: '',
|
||||
updateUrl: false,
|
||||
filters: () => ({})
|
||||
filters: () => ({}),
|
||||
orderingConfigName: undefined
|
||||
})
|
||||
|
||||
const search = ref()
|
||||
|
||||
const page = ref(1)
|
||||
const page = usePage()
|
||||
type ResponseType = { count: number, results: any[] }
|
||||
const result = ref<null | ResponseType>(null)
|
||||
|
||||
const { onSearch, query, addSearchToken } = useSmartSearch(props.defaultQuery, props.updateUrl)
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props.orderingConfigName)
|
||||
const { onSearch, query, addSearchToken } = useSmartSearch(props)
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props)
|
||||
|
||||
const orderingOptions: [OrderingField, keyof typeof sharedLabels.filters][] = [
|
||||
['creation_date', 'creation_date']
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
<script setup lang="ts">
|
||||
import type { ImportStatus, PrivacyLevel, Upload, BackendResponse } from '~/types'
|
||||
import type { RouteWithPreferences, OrderingField } from '~/store/ui'
|
||||
import type { SmartSearchProps } from '~/composables/useSmartSearch'
|
||||
import type { OrderingProps } from '~/composables/useOrdering'
|
||||
import type { SmartSearchProps } from '~/composables/navigation/useSmartSearch'
|
||||
import type { OrderingProps } from '~/composables/navigation/useOrdering'
|
||||
import type { RouteRecordName } from 'vue-router'
|
||||
import type { OrderingField } from '~/store/ui'
|
||||
|
||||
import { humanSize, truncate } from '~/utils/filters'
|
||||
import { ref, computed, watch } from 'vue'
|
||||
|
@ -14,16 +15,17 @@ import ImportStatusModal from '~/components/library/ImportStatusModal.vue'
|
|||
import ActionTable from '~/components/common/ActionTable.vue'
|
||||
import Pagination from '~/components/vui/Pagination.vue'
|
||||
|
||||
import useSmartSearch from '~/composables/navigation/useSmartSearch'
|
||||
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||
import useOrdering from '~/composables/navigation/useOrdering'
|
||||
import useErrorHandler from '~/composables/useErrorHandler'
|
||||
import useSmartSearch from '~/composables/useSmartSearch'
|
||||
import useOrdering from '~/composables/useOrdering'
|
||||
import usePage from '~/composables/navigation/usePage'
|
||||
|
||||
interface Props extends SmartSearchProps, OrderingProps {
|
||||
filters?: object
|
||||
|
||||
// TODO(wvffle): Remove after https://github.com/vuejs/core/pull/4512 is merged
|
||||
orderingConfigName: RouteWithPreferences | null
|
||||
orderingConfigName?: RouteRecordName
|
||||
defaultQuery?: string
|
||||
updateUrl?: boolean
|
||||
}
|
||||
|
@ -31,16 +33,17 @@ interface Props extends SmartSearchProps, OrderingProps {
|
|||
const props = withDefaults(defineProps<Props>(), {
|
||||
defaultQuery: '',
|
||||
updateUrl: false,
|
||||
filters: () => ({})
|
||||
filters: () => ({}),
|
||||
orderingConfigName: undefined
|
||||
})
|
||||
|
||||
const search = ref()
|
||||
|
||||
const page = ref(1)
|
||||
const page = usePage()
|
||||
const result = ref<BackendResponse<Upload>>()
|
||||
|
||||
const { onSearch, query, addSearchToken, getTokenValue } = useSmartSearch(props.defaultQuery, props.updateUrl)
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props.orderingConfigName)
|
||||
const { onSearch, query, addSearchToken, getTokenValue } = useSmartSearch(props)
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props)
|
||||
|
||||
const orderingOptions: [OrderingField, keyof typeof sharedLabels.filters][] = [
|
||||
['creation_date', 'creation_date'],
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
<script setup lang="ts">
|
||||
import type { RouteWithPreferences, OrderingField } from '~/store/ui'
|
||||
import type { OrderingProps } from '~/composables/useOrdering'
|
||||
import type { SmartSearchProps } from '~/composables/useSmartSearch'
|
||||
import type { SmartSearchProps } from '~/composables/navigation/useSmartSearch'
|
||||
import type { OrderingProps } from '~/composables/navigation/useOrdering'
|
||||
import type { RouteRecordName } from 'vue-router'
|
||||
import type { OrderingField } from '~/store/ui'
|
||||
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
@ -12,15 +13,16 @@ import useSharedLabels from '~/composables/locale/useSharedLabels'
|
|||
import ActionTable from '~/components/common/ActionTable.vue'
|
||||
import Pagination from '~/components/vui/Pagination.vue'
|
||||
|
||||
import useSmartSearch from '~/composables/navigation/useSmartSearch'
|
||||
import useOrdering from '~/composables/navigation/useOrdering'
|
||||
import useErrorHandler from '~/composables/useErrorHandler'
|
||||
import useSmartSearch from '~/composables/useSmartSearch'
|
||||
import useOrdering from '~/composables/useOrdering'
|
||||
import usePage from '~/composables/navigation/usePage'
|
||||
|
||||
interface Props extends SmartSearchProps, OrderingProps {
|
||||
filters?: object
|
||||
|
||||
// TODO(wvffle): Remove after https://github.com/vuejs/core/pull/4512 is merged
|
||||
orderingConfigName: RouteWithPreferences | null
|
||||
orderingConfigName?: RouteRecordName
|
||||
defaultQuery?: string
|
||||
updateUrl?: boolean
|
||||
}
|
||||
|
@ -28,17 +30,18 @@ interface Props extends SmartSearchProps, OrderingProps {
|
|||
const props = withDefaults(defineProps<Props>(), {
|
||||
defaultQuery: '',
|
||||
updateUrl: false,
|
||||
filters: () => ({})
|
||||
filters: () => ({}),
|
||||
orderingConfigName: undefined
|
||||
})
|
||||
|
||||
const search = ref()
|
||||
|
||||
const page = ref(1)
|
||||
const page = usePage()
|
||||
type ResponseType = { count: number, results: any[] }
|
||||
const result = ref<null | ResponseType>(null)
|
||||
|
||||
const { onSearch, query, addSearchToken } = useSmartSearch(props.defaultQuery, props.updateUrl)
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props.orderingConfigName)
|
||||
const { onSearch, query, addSearchToken } = useSmartSearch(props)
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props)
|
||||
|
||||
const orderingOptions: [OrderingField, keyof typeof sharedLabels.filters][] = [
|
||||
['creation_date', 'first_seen'],
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
import type { RouteWithPreferences, OrderingField } from '~/store/ui'
|
||||
import type { OrderingProps } from '~/composables/useOrdering'
|
||||
import type { OrderingProps } from '~/composables/navigation/useOrdering'
|
||||
import type { RouteRecordName } from 'vue-router'
|
||||
import type { OrderingField } from '~/store/ui'
|
||||
|
||||
import { watchDebounced } from '@vueuse/core'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
|
@ -12,27 +13,29 @@ import ActionTable from '~/components/common/ActionTable.vue'
|
|||
import Pagination from '~/components/vui/Pagination.vue'
|
||||
|
||||
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||
import useOrdering from '~/composables/navigation/useOrdering'
|
||||
import useErrorHandler from '~/composables/useErrorHandler'
|
||||
import useOrdering from '~/composables/useOrdering'
|
||||
import usePage from '~/composables/navigation/usePage'
|
||||
|
||||
interface Props extends OrderingProps {
|
||||
filters?: object
|
||||
allowListEnabled?: boolean
|
||||
|
||||
// TODO(wvffle): Remove after https://github.com/vuejs/core/pull/4512 is merged
|
||||
orderingConfigName: RouteWithPreferences | null
|
||||
orderingConfigName?: RouteRecordName
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
filters: () => ({}),
|
||||
allowListEnabled: false
|
||||
allowListEnabled: false,
|
||||
orderingConfigName: undefined
|
||||
})
|
||||
|
||||
const page = ref(1)
|
||||
const page = usePage()
|
||||
type ResponseType = { count: number, results: any[] }
|
||||
const result = ref<null | ResponseType>(null)
|
||||
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props.orderingConfigName)
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props)
|
||||
|
||||
const orderingOptions: [OrderingField, keyof typeof sharedLabels.filters][] = [
|
||||
['name', 'name'],
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
import type { RouteWithPreferences, OrderingField } from '~/store/ui'
|
||||
import type { OrderingProps } from '~/composables/useOrdering'
|
||||
import type { OrderingProps } from '~/composables/navigation/useOrdering'
|
||||
import type { RouteRecordName } from 'vue-router'
|
||||
import type { OrderingField } from '~/store/ui'
|
||||
|
||||
import { watchDebounced } from '@vueuse/core'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
|
@ -13,25 +14,27 @@ import ActionTable from '~/components/common/ActionTable.vue'
|
|||
import Pagination from '~/components/vui/Pagination.vue'
|
||||
|
||||
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||
import useOrdering from '~/composables/navigation/useOrdering'
|
||||
import useErrorHandler from '~/composables/useErrorHandler'
|
||||
import useOrdering from '~/composables/useOrdering'
|
||||
import usePage from '~/composables/navigation/usePage'
|
||||
|
||||
interface Props extends OrderingProps {
|
||||
filters?: object
|
||||
|
||||
// TODO(wvffle): Remove after https://github.com/vuejs/core/pull/4512 is merged
|
||||
orderingConfigName: RouteWithPreferences | null
|
||||
orderingConfigName?: RouteRecordName
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
filters: () => ({})
|
||||
filters: () => ({}),
|
||||
orderingConfigName: undefined
|
||||
})
|
||||
|
||||
const page = ref(1)
|
||||
const page = usePage()
|
||||
type ResponseType = { count: number, results: any[] }
|
||||
const result = ref<null | ResponseType>(null)
|
||||
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering } = useOrdering(props.orderingConfigName)
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering } = useOrdering(props)
|
||||
|
||||
const orderingOptions: [OrderingField, keyof typeof sharedLabels.filters][] = [
|
||||
['expiration_date', 'expiration_date'],
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
import type { RouteWithPreferences, OrderingField } from '~/store/ui'
|
||||
import type { OrderingProps } from '~/composables/useOrdering'
|
||||
import type { OrderingProps } from '~/composables/navigation/useOrdering'
|
||||
import type { RouteRecordName } from 'vue-router'
|
||||
import type { OrderingField } from '~/store/ui'
|
||||
|
||||
import { watchDebounced } from '@vueuse/core'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
|
@ -13,17 +14,18 @@ import Pagination from '~/components/vui/Pagination.vue'
|
|||
|
||||
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||
import useErrorHandler from '~/composables/useErrorHandler'
|
||||
import useOrdering from '~/composables/useOrdering'
|
||||
import useOrdering from '~/composables/navigation/useOrdering'
|
||||
|
||||
interface Props extends OrderingProps {
|
||||
filters?: object
|
||||
|
||||
// TODO(wvffle): Remove after https://github.com/vuejs/core/pull/4512 is merged
|
||||
orderingConfigName: RouteWithPreferences | null
|
||||
orderingConfigName?: RouteRecordName
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
filters: () => ({})
|
||||
filters: () => ({}),
|
||||
orderingConfigName: undefined
|
||||
})
|
||||
|
||||
const page = ref(1)
|
||||
|
@ -31,7 +33,7 @@ const query = ref('')
|
|||
type ResponseType = { count: number, results: any[] }
|
||||
const result = ref<null | ResponseType>(null)
|
||||
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props.orderingConfigName)
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props)
|
||||
|
||||
const orderingOptions: [OrderingField, keyof typeof sharedLabels.filters][] = [
|
||||
['date_joined', 'date_joined'],
|
||||
|
|
|
@ -4,6 +4,8 @@ import { range, clamp } from 'lodash-es'
|
|||
import { computed } from 'vue'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
const RANGE = 2
|
||||
|
||||
interface Events {
|
||||
(e: 'update:current', page: number): void
|
||||
}
|
||||
|
@ -24,7 +26,6 @@ const props = withDefaults(defineProps<Props>(), {
|
|||
|
||||
const current = useVModel(props, 'current', emit)
|
||||
|
||||
const RANGE = 2
|
||||
const pages = computed(() => {
|
||||
const start = range(1, 1 + RANGE)
|
||||
const end = range(maxPage.value - RANGE + 1, maxPage.value + 1)
|
||||
|
@ -33,6 +34,13 @@ const pages = computed(() => {
|
|||
clamp(props.current + RANGE, 1, maxPage.value)
|
||||
).filter(i => !start.includes(i) && !end.includes(i))
|
||||
|
||||
if (end[0] - 1 <= start[RANGE - 1]) {
|
||||
return [
|
||||
...start,
|
||||
...end.filter(i => i > start[RANGE - 1])
|
||||
]
|
||||
}
|
||||
|
||||
return [
|
||||
...start,
|
||||
middle.length === 0 && 'skip',
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
import type { RouteRecordName } from 'vue-router'
|
||||
|
||||
import { toRefs, useStorage, syncRef } from '@vueuse/core'
|
||||
import { useRouteQuery } from '@vueuse/router'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { ref, watch } from 'vue'
|
||||
|
||||
export interface OrderingProps {
|
||||
orderingConfigName?: RouteRecordName
|
||||
}
|
||||
|
||||
export default (props: OrderingProps) => {
|
||||
const route = useRoute()
|
||||
|
||||
const preferences = useStorage(`route-preferences:${props.orderingConfigName?.toString() ?? route.name?.toString() ?? '*'}`, {
|
||||
orderingDirection: route.meta.orderingDirection ?? '-',
|
||||
ordering: route.meta.ordering ?? 'creation_date',
|
||||
paginateBy: route.meta.paginateBy ?? 50
|
||||
})
|
||||
|
||||
const {
|
||||
orderingDirection: perfOrderingDirection,
|
||||
paginateBy: perfPaginateBy,
|
||||
ordering: perfOrdering
|
||||
} = toRefs(preferences)
|
||||
|
||||
const queryPaginateBy = useRouteQuery<string>('paginateBy', perfPaginateBy.value.toString())
|
||||
const paginateBy = ref()
|
||||
syncRef(queryPaginateBy, paginateBy, {
|
||||
transform: {
|
||||
ltr: (left) => +left,
|
||||
rtl: (right) => right.toString()
|
||||
}
|
||||
})
|
||||
|
||||
const queryOrdering = useRouteQuery('ordering', perfOrderingDirection.value + perfOrdering.value)
|
||||
console.log(queryOrdering.value)
|
||||
|
||||
watch(queryOrdering, (ordering) => {
|
||||
perfOrderingDirection.value = ordering[0] === '-' ? '-' : '+'
|
||||
perfOrdering.value = ordering[0] === '-' || ordering[0] === '+'
|
||||
? ordering.slice(1)
|
||||
: ordering
|
||||
})
|
||||
|
||||
watch(perfOrderingDirection, (direction) => {
|
||||
if (direction === '-') {
|
||||
queryOrdering.value = direction + perfOrdering.value
|
||||
return
|
||||
}
|
||||
|
||||
queryOrdering.value = perfOrdering.value
|
||||
})
|
||||
|
||||
watch(perfOrdering, (field) => {
|
||||
const direction = perfOrderingDirection.value
|
||||
queryOrdering.value = (direction === '-' ? '-' : '') + field
|
||||
})
|
||||
|
||||
watch(queryPaginateBy, (paginateBy) => {
|
||||
perfPaginateBy.value = +paginateBy
|
||||
})
|
||||
|
||||
const onOrderingUpdate = (fn: () => void) => watch(preferences, fn)
|
||||
|
||||
return {
|
||||
paginateBy,
|
||||
ordering: perfOrdering,
|
||||
orderingDirection: perfOrderingDirection,
|
||||
orderingString: queryOrdering,
|
||||
onOrderingUpdate
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
import { useRouteQuery } from '@vueuse/router'
|
||||
import { syncRef } from '@vueuse/core'
|
||||
import { ref } from 'vue'
|
||||
|
||||
export default () => {
|
||||
const pageQuery = useRouteQuery<string>('page', '1')
|
||||
const page = ref()
|
||||
syncRef(pageQuery, page, {
|
||||
transform: {
|
||||
ltr: (left) => +left,
|
||||
rtl: (right) => right.toString()
|
||||
}
|
||||
})
|
||||
|
||||
return page
|
||||
}
|
|
@ -1,18 +1,17 @@
|
|||
import type { MaybeRef } from '@vueuse/core'
|
||||
import type { Token } from '~/utils/search'
|
||||
|
||||
import { refWithControl } from '@vueuse/core'
|
||||
import { computed, ref, unref, watch } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { compileTokens, normalizeQuery, parseTokens } from '~/utils/search'
|
||||
import { refWithControl } from '@vueuse/core'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
export interface SmartSearchProps {
|
||||
defaultQuery?: string
|
||||
updateUrl?: boolean
|
||||
}
|
||||
|
||||
export default (defaultQuery: MaybeRef<string>, updateUrl: MaybeRef<boolean>) => {
|
||||
const query = refWithControl(unref(defaultQuery))
|
||||
export default (props: SmartSearchProps) => {
|
||||
const query = refWithControl(props.defaultQuery ?? '')
|
||||
const tokens = ref([] as Token[])
|
||||
|
||||
watch(query, (value) => {
|
||||
|
@ -28,7 +27,7 @@ export default (defaultQuery: MaybeRef<string>, updateUrl: MaybeRef<boolean>) =>
|
|||
const router = useRouter()
|
||||
watch(tokens, (value) => {
|
||||
const newQuery = compileTokens(value)
|
||||
if (unref(updateUrl)) {
|
||||
if (props.updateUrl) {
|
||||
return router.replace({ query: { q: newQuery } })
|
||||
}
|
||||
|
||||
|
@ -67,7 +66,6 @@ export default (defaultQuery: MaybeRef<string>, updateUrl: MaybeRef<boolean>) =>
|
|||
return
|
||||
}
|
||||
|
||||
// TODO (wvffle): Check if triggers reactivity
|
||||
for (const token of existing) {
|
||||
token.value = value
|
||||
}
|
|
@ -54,6 +54,10 @@ async function useErrorHandler (error: Error | BackendError, eventId?: string):
|
|||
}
|
||||
}
|
||||
|
||||
if ('isHandled' in error && error.isHandled) {
|
||||
return
|
||||
}
|
||||
|
||||
store.commit('ui/addMessage', {
|
||||
content,
|
||||
date,
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
import type { OrderingDirection, OrderingField, RouteWithPreferences } from '~/store/ui'
|
||||
import type { MaybeRef } from '@vueuse/core'
|
||||
|
||||
import { reactiveComputed, toRefs } from '@vueuse/core'
|
||||
import { computed, unref, watch } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useStore } from '~/store'
|
||||
|
||||
export interface OrderingProps {
|
||||
orderingConfigName: RouteWithPreferences | null
|
||||
}
|
||||
|
||||
export default (orderingConfigName: MaybeRef<RouteWithPreferences | null>) => {
|
||||
const store = useStore()
|
||||
const route = useRoute()
|
||||
|
||||
const config = reactiveComputed(() => {
|
||||
const name = unref(orderingConfigName) ?? route.name as RouteWithPreferences
|
||||
return { ...store.state.ui.routePreferences[name] }
|
||||
})
|
||||
|
||||
const { paginateBy, ordering, orderingDirection } = toRefs(config)
|
||||
|
||||
const orderingString = computed(() => {
|
||||
if (orderingDirection.value === '-') return `-${ordering.value}`
|
||||
return ordering.value
|
||||
})
|
||||
|
||||
const getOrderingFromString = (str: string) => ({
|
||||
direction: (str[0] === '-' ? '-' : '+') as OrderingDirection,
|
||||
field: (str[0] === '-' || str[0] === '+' ? str.slice(1) : str) as OrderingField
|
||||
})
|
||||
|
||||
const onOrderingUpdate = (fn: () => void) => watch(config, fn)
|
||||
|
||||
return {
|
||||
paginateBy,
|
||||
ordering,
|
||||
orderingDirection,
|
||||
orderingString,
|
||||
getOrderingFromString,
|
||||
onOrderingUpdate
|
||||
}
|
||||
}
|
|
@ -30,6 +30,7 @@ export const install: InitModule = ({ store, router }) => {
|
|||
return response
|
||||
}, async (error: BackendError) => {
|
||||
error.backendErrors = []
|
||||
error.isHandled = false
|
||||
|
||||
if (store.state.auth.authenticated && !store.state.auth.oauth.accessToken && error.response?.status === 401) {
|
||||
store.commit('auth/authenticated', false)
|
||||
|
@ -40,8 +41,10 @@ export const install: InitModule = ({ store, router }) => {
|
|||
switch (error.response?.status) {
|
||||
case 404:
|
||||
error.backendErrors.push('Resource not found')
|
||||
error.isHandled = true
|
||||
store.commit('ui/addMessage', {
|
||||
content: error.response?.data,
|
||||
// @ts-expect-error TS does not know about .data structure
|
||||
content: error.response?.data?.detail ?? error.response?.data,
|
||||
class: 'error'
|
||||
})
|
||||
break
|
||||
|
@ -71,6 +74,7 @@ export const install: InitModule = ({ store, router }) => {
|
|||
}
|
||||
|
||||
error.backendErrors.push(message)
|
||||
error.isHandled = true
|
||||
store.commit('ui/addMessage', {
|
||||
content: message,
|
||||
date: new Date(),
|
||||
|
|
|
@ -54,13 +54,7 @@ export default [
|
|||
{
|
||||
path: '/search',
|
||||
name: 'search',
|
||||
component: () => import('~/views/Search.vue'),
|
||||
props: route => ({
|
||||
initialId: route.query.id,
|
||||
initialType: route.query.type || 'artists',
|
||||
initialQuery: route.query.q,
|
||||
initialPage: route.query.page ? +route.query.page : undefined
|
||||
})
|
||||
component: () => import('~/views/Search.vue')
|
||||
},
|
||||
...auth,
|
||||
...settings,
|
||||
|
|
|
@ -20,96 +20,60 @@ export default [
|
|||
path: 'artists/',
|
||||
name: 'library.artists.browse',
|
||||
component: () => import('~/components/library/Artists.vue'),
|
||||
props: route => ({
|
||||
defaultOrdering: route.query.ordering,
|
||||
defaultQuery: route.query.query,
|
||||
defaultTags: Array.isArray(route.query.tag || [])
|
||||
? route.query.tag
|
||||
: [route.query.tag],
|
||||
defaultPage: route.query.page ? +route.query.page : undefined,
|
||||
orderingConfigName: null
|
||||
})
|
||||
meta: {
|
||||
paginateBy: 30
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'me/artists',
|
||||
name: 'library.artists.me',
|
||||
component: () => import('~/components/library/Artists.vue'),
|
||||
props: route => ({
|
||||
scope: 'me',
|
||||
defaultOrdering: route.query.ordering,
|
||||
defaultQuery: route.query.query,
|
||||
defaultTags: Array.isArray(route.query.tag || [])
|
||||
? route.query.tag
|
||||
: [route.query.tag],
|
||||
defaultPage: route.query.page ? +route.query.page : undefined,
|
||||
orderingConfigName: null
|
||||
})
|
||||
props: { scope: 'me' },
|
||||
meta: {
|
||||
paginateBy: 30
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'albums/',
|
||||
name: 'library.albums.browse',
|
||||
component: () => import('~/components/library/Albums.vue'),
|
||||
props: route => ({
|
||||
defaultOrdering: route.query.ordering,
|
||||
defaultQuery: route.query.query,
|
||||
defaultTags: Array.isArray(route.query.tag || [])
|
||||
? route.query.tag
|
||||
: [route.query.tag],
|
||||
defaultPage: route.query.page ? +route.query.page : undefined,
|
||||
orderingConfigName: null
|
||||
})
|
||||
},
|
||||
{
|
||||
path: 'podcasts/',
|
||||
name: 'library.podcasts.browse',
|
||||
component: () => import('~/components/library/Podcasts.vue'),
|
||||
props: route => ({
|
||||
defaultOrdering: route.query.ordering,
|
||||
defaultQuery: route.query.query,
|
||||
defaultTags: Array.isArray(route.query.tag || [])
|
||||
? route.query.tag
|
||||
: [route.query.tag],
|
||||
defaultPage: route.query.page ? +route.query.page : undefined,
|
||||
orderingConfigName: null
|
||||
})
|
||||
meta: {
|
||||
paginateBy: 25
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'me/albums',
|
||||
name: 'library.albums.me',
|
||||
component: () => import('~/components/library/Albums.vue'),
|
||||
props: route => ({
|
||||
scope: 'me',
|
||||
defaultOrdering: route.query.ordering,
|
||||
defaultQuery: route.query.query,
|
||||
defaultTags: Array.isArray(route.query.tag || [])
|
||||
? route.query.tag
|
||||
: [route.query.tag],
|
||||
defaultPage: route.query.page ? +route.query.page : undefined,
|
||||
orderingConfigName: null
|
||||
})
|
||||
props: { scope: 'me' },
|
||||
meta: {
|
||||
paginateBy: 25
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'podcasts/',
|
||||
name: 'library.podcasts.browse',
|
||||
component: () => import('~/components/library/Podcasts.vue'),
|
||||
meta: {
|
||||
paginateBy: 30
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'radios/',
|
||||
name: 'library.radios.browse',
|
||||
component: () => import('~/components/library/Radios.vue'),
|
||||
props: route => ({
|
||||
defaultOrdering: route.query.ordering,
|
||||
defaultQuery: route.query.query,
|
||||
defaultPage: route.query.page ? +route.query.page : undefined,
|
||||
orderingConfigName: null
|
||||
})
|
||||
meta: {
|
||||
paginateBy: 12
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'me/radios/',
|
||||
name: 'library.radios.me',
|
||||
component: () => import('~/components/library/Radios.vue'),
|
||||
props: route => ({
|
||||
scope: 'me',
|
||||
defaultOrdering: route.query.ordering,
|
||||
defaultQuery: route.query.query,
|
||||
defaultPage: route.query.page ? +route.query.page : undefined,
|
||||
orderingConfigName: null
|
||||
})
|
||||
props: { scope: 'me' },
|
||||
meta: {
|
||||
paginateBy: 12
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'radios/build',
|
||||
|
@ -133,24 +97,18 @@ export default [
|
|||
path: 'playlists/',
|
||||
name: 'library.playlists.browse',
|
||||
component: () => import('~/views/playlists/List.vue'),
|
||||
props: route => ({
|
||||
defaultOrdering: route.query.ordering,
|
||||
defaultQuery: route.query.query,
|
||||
defaultPage: route.query.page ? +route.query.page : undefined,
|
||||
orderingConfigName: null
|
||||
})
|
||||
meta: {
|
||||
paginateBy: 25
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'me/playlists/',
|
||||
name: 'library.playlists.me',
|
||||
component: () => import('~/views/playlists/List.vue'),
|
||||
props: route => ({
|
||||
scope: 'me',
|
||||
defaultOrdering: route.query.ordering,
|
||||
defaultQuery: route.query.query,
|
||||
defaultPage: route.query.page ? +route.query.page : undefined,
|
||||
orderingConfigName: null
|
||||
})
|
||||
props: { scope: 'me' },
|
||||
meta: {
|
||||
paginateBy: 25
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'playlists/:id',
|
||||
|
|
|
@ -157,7 +157,9 @@ export default [
|
|||
path: 'reports',
|
||||
name: 'manage.moderation.reports.list',
|
||||
component: () => import('~/views/admin/moderation/ReportsList.vue'),
|
||||
props: route => ({ defaultQuery: route.query.q, updateUrl: true, orderingConfigName: null })
|
||||
meta: {
|
||||
paginateBy: 25
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'reports/:id',
|
||||
|
@ -169,7 +171,9 @@ export default [
|
|||
path: 'requests',
|
||||
name: 'manage.moderation.requests.list',
|
||||
component: () => import('~/views/admin/moderation/RequestsList.vue'),
|
||||
props: route => ({ defaultQuery: route.query.q, updateUrl: true, orderingConfigName: null })
|
||||
meta: {
|
||||
paginateBy: 25
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'requests/:id',
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
import 'vue-router'
|
||||
|
||||
declare module 'vue-router' {
|
||||
interface RouteMeta {
|
||||
orderingDirection?: '-' | '+'
|
||||
ordering?: OrderingField
|
||||
paginateBy?: number
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/* eslint-disable */
|
||||
declare module '*.vue' {
|
||||
import type { DefineComponent } from 'vue'
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
const component: DefineComponent<{}, {}, any>
|
||||
export default component
|
||||
}
|
||||
|
|
|
@ -7,15 +7,6 @@ import moment from 'moment'
|
|||
|
||||
type SupportedExtension = 'flac' | 'ogg' | 'mp3' | 'opus' | 'aac' | 'm4a' | 'aiff' | 'aif'
|
||||
|
||||
export type RouteWithPreferences = 'library.artists.browse' | 'library.podcasts.browse' | 'library.radios.browse'
|
||||
| 'library.playlists.browse' | 'library.albums.me' | 'library.artists.me' | 'library.radios.me'
|
||||
| 'library.playlists.me' | 'content.libraries.files' | 'library.detail.upload' | 'library.detail.edit'
|
||||
| 'library.detail' | 'favorites' | 'manage.channels' | 'manage.library.tags' | 'manage.library.uploads'
|
||||
| 'manage.library.libraries' | 'manage.library.tracks' | 'manage.library.albums' | 'manage.library.artists'
|
||||
| 'manage.library.edits' | 'manage.users.users.list' | 'manage.users.invitations.list'
|
||||
| 'manage.moderation.accounts.list' | 'manage.moderation.domains.list' | 'manage.moderation.requests.list'
|
||||
| 'manage.moderation.reports.list' | 'library.albums.browse'
|
||||
|
||||
export type WebSocketEventName = 'inbox.item_added' | 'import.status_updated' | 'mutation.created' | 'mutation.updated'
|
||||
| 'report.created' | 'user_request.created' | 'Listen'
|
||||
|
||||
|
@ -26,12 +17,6 @@ export type OrderingField = 'creation_date' | 'title' | 'album__title' | 'artist
|
|||
| 'last_activity' | 'username'
|
||||
|
||||
export type OrderingDirection = '-' | '+'
|
||||
interface RoutePreferences {
|
||||
paginateBy: number
|
||||
orderingDirection: OrderingDirection
|
||||
ordering: OrderingField
|
||||
}
|
||||
|
||||
interface WebSocketEvent {
|
||||
type: WebSocketEventName
|
||||
}
|
||||
|
@ -63,7 +48,6 @@ export interface State {
|
|||
|
||||
notifications: Record<NotificationsKey, number>
|
||||
websocketEventsHandlers: Record<WebSocketEventName, WebSocketHandlers>
|
||||
routePreferences: Record<RouteWithPreferences, RoutePreferences>
|
||||
}
|
||||
|
||||
const store: Module<State, RootState> = {
|
||||
|
@ -97,149 +81,7 @@ const store: Module<State, RootState> = {
|
|||
'user_request.created': {},
|
||||
Listen: {}
|
||||
},
|
||||
pageTitle: null,
|
||||
routePreferences: {
|
||||
'library.albums.browse': {
|
||||
paginateBy: 25,
|
||||
orderingDirection: '-',
|
||||
ordering: 'creation_date'
|
||||
},
|
||||
'library.artists.browse': {
|
||||
paginateBy: 30,
|
||||
orderingDirection: '-',
|
||||
ordering: 'creation_date'
|
||||
},
|
||||
'library.podcasts.browse': {
|
||||
paginateBy: 30,
|
||||
orderingDirection: '-',
|
||||
ordering: 'creation_date'
|
||||
},
|
||||
'library.radios.browse': {
|
||||
paginateBy: 12,
|
||||
orderingDirection: '-',
|
||||
ordering: 'creation_date'
|
||||
},
|
||||
'library.playlists.browse': {
|
||||
paginateBy: 25,
|
||||
orderingDirection: '-',
|
||||
ordering: 'creation_date'
|
||||
},
|
||||
'library.albums.me': {
|
||||
paginateBy: 25,
|
||||
orderingDirection: '-',
|
||||
ordering: 'creation_date'
|
||||
},
|
||||
'library.artists.me': {
|
||||
paginateBy: 30,
|
||||
orderingDirection: '-',
|
||||
ordering: 'creation_date'
|
||||
},
|
||||
'library.radios.me': {
|
||||
paginateBy: 12,
|
||||
orderingDirection: '-',
|
||||
ordering: 'creation_date'
|
||||
},
|
||||
'library.playlists.me': {
|
||||
paginateBy: 25,
|
||||
orderingDirection: '-',
|
||||
ordering: 'creation_date'
|
||||
},
|
||||
'content.libraries.files': {
|
||||
paginateBy: 50,
|
||||
orderingDirection: '-',
|
||||
ordering: 'creation_date'
|
||||
},
|
||||
'library.detail.upload': {
|
||||
paginateBy: 50,
|
||||
orderingDirection: '-',
|
||||
ordering: 'creation_date'
|
||||
},
|
||||
'library.detail.edit': {
|
||||
paginateBy: 50,
|
||||
orderingDirection: '-',
|
||||
ordering: 'creation_date'
|
||||
},
|
||||
'library.detail': {
|
||||
paginateBy: 50,
|
||||
orderingDirection: '-',
|
||||
ordering: 'creation_date'
|
||||
},
|
||||
favorites: {
|
||||
paginateBy: 50,
|
||||
orderingDirection: '-',
|
||||
ordering: 'creation_date'
|
||||
},
|
||||
'manage.channels': {
|
||||
paginateBy: 50,
|
||||
orderingDirection: '-',
|
||||
ordering: 'creation_date'
|
||||
},
|
||||
'manage.library.tags': {
|
||||
paginateBy: 50,
|
||||
orderingDirection: '-',
|
||||
ordering: 'creation_date'
|
||||
},
|
||||
'manage.library.uploads': {
|
||||
paginateBy: 50,
|
||||
orderingDirection: '-',
|
||||
ordering: 'creation_date'
|
||||
},
|
||||
'manage.library.libraries': {
|
||||
paginateBy: 50,
|
||||
orderingDirection: '-',
|
||||
ordering: 'creation_date'
|
||||
},
|
||||
'manage.library.tracks': {
|
||||
paginateBy: 50,
|
||||
orderingDirection: '-',
|
||||
ordering: 'creation_date'
|
||||
},
|
||||
'manage.library.albums': {
|
||||
paginateBy: 50,
|
||||
orderingDirection: '-',
|
||||
ordering: 'creation_date'
|
||||
},
|
||||
'manage.library.artists': {
|
||||
paginateBy: 50,
|
||||
orderingDirection: '-',
|
||||
ordering: 'creation_date'
|
||||
},
|
||||
'manage.library.edits': {
|
||||
paginateBy: 25,
|
||||
orderingDirection: '-',
|
||||
ordering: 'creation_date'
|
||||
},
|
||||
'manage.users.users.list': {
|
||||
paginateBy: 50,
|
||||
orderingDirection: '-',
|
||||
ordering: 'creation_date'
|
||||
},
|
||||
'manage.users.invitations.list': {
|
||||
paginateBy: 50,
|
||||
orderingDirection: '-',
|
||||
ordering: 'creation_date'
|
||||
},
|
||||
'manage.moderation.accounts.list': {
|
||||
paginateBy: 50,
|
||||
orderingDirection: '-',
|
||||
ordering: 'creation_date'
|
||||
},
|
||||
'manage.moderation.domains.list': {
|
||||
paginateBy: 50,
|
||||
orderingDirection: '-',
|
||||
ordering: 'creation_date'
|
||||
},
|
||||
'manage.moderation.requests.list': {
|
||||
paginateBy: 25,
|
||||
orderingDirection: '-',
|
||||
ordering: 'creation_date'
|
||||
},
|
||||
'manage.moderation.reports.list': {
|
||||
paginateBy: 25,
|
||||
orderingDirection: '-',
|
||||
ordering: 'creation_date'
|
||||
}
|
||||
}
|
||||
pageTitle: null
|
||||
},
|
||||
getters: {
|
||||
showInstanceSupportMessage: (state, getters, rootState) => {
|
||||
|
|
|
@ -218,6 +218,7 @@ export interface Listening {
|
|||
export interface APIErrorResponse extends Record<string, APIErrorResponse | string[] | { code: string }[]> {}
|
||||
|
||||
export interface BackendError extends AxiosError {
|
||||
isHandled: boolean
|
||||
backendErrors: string[]
|
||||
rawPayload?: APIErrorResponse
|
||||
}
|
||||
|
|
|
@ -1,39 +1,42 @@
|
|||
<script setup lang="ts">
|
||||
import type { RadioConfig } from '~/store/radios'
|
||||
|
||||
import { ref, reactive, computed, watch } from 'vue'
|
||||
import { useRouteQuery } from '@vueuse/router'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
import { syncRef } from '@vueuse/core'
|
||||
|
||||
import axios from 'axios'
|
||||
|
||||
import PlaylistCardList from '~/components/playlists/CardList.vue'
|
||||
import RemoteSearchForm from '~/components/RemoteSearchForm.vue'
|
||||
import ArtistCard from '~/components/audio/artist/Card.vue'
|
||||
import AlbumCard from '~/components/audio/album/Card.vue'
|
||||
import TrackTable from '~/components/audio/track/Table.vue'
|
||||
import AlbumCard from '~/components/audio/album/Card.vue'
|
||||
import Pagination from '~/components/vui/Pagination.vue'
|
||||
import PlaylistCardList from '~/components/playlists/CardList.vue'
|
||||
import RadioCard from '~/components/radios/Card.vue'
|
||||
import RadioButton from '~/components/radios/Button.vue'
|
||||
import RadioCard from '~/components/radios/Card.vue'
|
||||
import TagsList from '~/components/tags/List.vue'
|
||||
import { ref, reactive, computed, watch } from 'vue'
|
||||
import { useRouter, onBeforeRouteUpdate } from 'vue-router'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
import axios from 'axios'
|
||||
|
||||
import useErrorHandler from '~/composables/useErrorHandler'
|
||||
|
||||
type QueryType = 'artists' | 'albums' | 'tracks' | 'playlists' | 'tags' | 'radios' | 'podcasts' | 'series' | 'rss'
|
||||
|
||||
interface Props {
|
||||
initialId?: string
|
||||
initialType?: QueryType
|
||||
initialQuery?: string
|
||||
initialPage?: number
|
||||
}
|
||||
const type = useRouteQuery<QueryType>('type', 'artists')
|
||||
const id = useRouteQuery<string>('id')
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
initialId: '',
|
||||
initialType: 'artists',
|
||||
initialQuery: '',
|
||||
initialPage: 1
|
||||
const pageQuery = useRouteQuery<string>('page', '1')
|
||||
const page = ref(+pageQuery.value)
|
||||
syncRef(pageQuery, page, {
|
||||
transform: {
|
||||
ltr: (left) => +left,
|
||||
rtl: (right) => right.toString()
|
||||
}
|
||||
})
|
||||
|
||||
const query = ref(props.initialQuery)
|
||||
const type = ref(props.initialType)
|
||||
const page = ref(props.initialPage)
|
||||
const q = useRouteQuery('q', '')
|
||||
const query = ref(q.value)
|
||||
syncRef(q, query, { direction: 'ltr' })
|
||||
|
||||
type ResponseType = { count: number, results: any[] }
|
||||
const results = reactive({
|
||||
|
@ -122,19 +125,12 @@ const axiosParams = computed(() => {
|
|||
|
||||
const currentResults = computed(() => results[currentType.value?.id ?? 'artists'])
|
||||
|
||||
const router = useRouter()
|
||||
const updateQueryString = () => router.replace({
|
||||
query: {
|
||||
q: query.value,
|
||||
page: page.value,
|
||||
type: type.value
|
||||
}
|
||||
})
|
||||
|
||||
const isLoading = ref(false)
|
||||
const search = async () => {
|
||||
if (!currentType.value) return
|
||||
|
||||
q.value = query.value
|
||||
|
||||
if (!query.value) {
|
||||
for (const type of types.value) {
|
||||
results[type.id] = null
|
||||
|
@ -144,11 +140,16 @@ const search = async () => {
|
|||
}
|
||||
|
||||
isLoading.value = true
|
||||
const response = await axios.get(currentType.value.endpoint ?? currentType.value.id, {
|
||||
params: axiosParams.value
|
||||
})
|
||||
|
||||
results[currentType.value.id] = response.data
|
||||
try {
|
||||
const response = await axios.get(currentType.value.endpoint ?? currentType.value.id, {
|
||||
params: axiosParams.value
|
||||
})
|
||||
|
||||
results[currentType.value.id] = response.data
|
||||
} catch (error) {
|
||||
useErrorHandler(error as Error)
|
||||
}
|
||||
|
||||
isLoading.value = false
|
||||
|
||||
|
@ -164,25 +165,20 @@ const search = async () => {
|
|||
}
|
||||
}).then(response => {
|
||||
results[type.id] = response.data
|
||||
})
|
||||
}).catch(() => undefined)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
watch(type, () => (page.value = 1))
|
||||
watch(page, updateQueryString)
|
||||
watch(type, () => {
|
||||
page.value = 1
|
||||
search()
|
||||
})
|
||||
|
||||
onBeforeRouteUpdate(search)
|
||||
|
||||
// TODO: (wvffle): Check if it's needed
|
||||
// watch: {
|
||||
// '$route.query.q': async function (v) {
|
||||
// this.query = v
|
||||
// }
|
||||
// },
|
||||
search()
|
||||
|
||||
const labels = computed(() => ({
|
||||
title: props.initialId
|
||||
title: id.value
|
||||
? (
|
||||
type.value === 'rss'
|
||||
? $pgettext('Head/Fetch/Title', 'Subscribe to a podcast RSS feed')
|
||||
|
@ -224,13 +220,13 @@ const radioConfig = computed(() => {
|
|||
>
|
||||
<section class="ui vertical stripe segment">
|
||||
<div
|
||||
v-if="initialId"
|
||||
v-if="id"
|
||||
class="ui small text container"
|
||||
>
|
||||
<h2>{{ labels.title }}</h2>
|
||||
<remote-search-form
|
||||
:initial-id="initialId"
|
||||
:type="initialType"
|
||||
:initial-id="id"
|
||||
:type="type"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
|
|
|
@ -54,58 +54,44 @@ const title = computed(() => labels.value[props.type])
|
|||
v-if="type === 'accounts'"
|
||||
:update-url="true"
|
||||
:default-query="defaultQuery"
|
||||
:ordering-config-name="null"
|
||||
/>
|
||||
<albums-table
|
||||
v-else-if="type === 'albums'"
|
||||
:update-url="true"
|
||||
:default-query="defaultQuery"
|
||||
:ordering-config-name="null"
|
||||
/>
|
||||
<artists-table
|
||||
v-else-if="type === 'artists'"
|
||||
:update-url="true"
|
||||
:default-query="defaultQuery"
|
||||
:ordering-config-name="null"
|
||||
/>
|
||||
<channels-table
|
||||
v-else-if="type === 'channels'"
|
||||
:update-url="true"
|
||||
:default-query="defaultQuery"
|
||||
:ordering-config-name="null"
|
||||
/>
|
||||
<invitations-table
|
||||
v-else-if="type === 'invitations'"
|
||||
:ordering-config-name="null"
|
||||
/>
|
||||
<invitations-table v-else-if="type === 'invitations'" />
|
||||
<libraries-table
|
||||
v-else-if="type === 'libraries'"
|
||||
:update-url="true"
|
||||
:default-query="defaultQuery"
|
||||
:ordering-config-name="null"
|
||||
/>
|
||||
<tags-table
|
||||
v-else-if="type === 'tags'"
|
||||
:update-url="true"
|
||||
:default-query="defaultQuery"
|
||||
:ordering-config-name="null"
|
||||
/>
|
||||
<tracks-table
|
||||
v-else-if="type === 'tracks'"
|
||||
:update-url="true"
|
||||
:default-query="defaultQuery"
|
||||
:ordering-config-name="null"
|
||||
/>
|
||||
<uploads-table
|
||||
v-else-if="type === 'uploads'"
|
||||
:update-url="true"
|
||||
:default-query="defaultQuery"
|
||||
:ordering-config-name="null"
|
||||
/>
|
||||
<users-table
|
||||
v-else-if="type === 'users'"
|
||||
:ordering-config-name="null"
|
||||
/>
|
||||
<users-table v-else-if="type === 'users'" />
|
||||
</section>
|
||||
</main>
|
||||
</template>
|
||||
|
|
|
@ -24,7 +24,6 @@ const labels = computed(() => ({
|
|||
<edits-card-list
|
||||
:update-url="true"
|
||||
:default-query="defaultQuery"
|
||||
:ordering-config-name="null"
|
||||
>
|
||||
<h2 class="ui header">
|
||||
<translate translate-context="Content/Admin/Title/Noun">
|
||||
|
|
|
@ -113,10 +113,7 @@ const createDomain = async () => {
|
|||
</div>
|
||||
</form>
|
||||
<div class="ui clearing hidden divider" />
|
||||
<domains-table
|
||||
:ordering-config-name="null"
|
||||
:allow-list-enabled="allowListEnabled"
|
||||
/>
|
||||
<domains-table :allow-list-enabled="allowListEnabled" />
|
||||
</section>
|
||||
</main>
|
||||
</template>
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
<script setup lang="ts">
|
||||
import type { RouteWithPreferences, OrderingField } from '~/store/ui'
|
||||
import type { SmartSearchProps } from '~/composables/useSmartSearch'
|
||||
import type { OrderingProps } from '~/composables/useOrdering'
|
||||
import type { SmartSearchProps } from '~/composables/navigation/useSmartSearch'
|
||||
import type { OrderingProps } from '~/composables/navigation/useOrdering'
|
||||
import type { Report, BackendResponse } from '~/types'
|
||||
import type { RouteRecordName } from 'vue-router'
|
||||
import type { OrderingField } from '~/store/ui'
|
||||
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
@ -13,35 +15,33 @@ import ReportCategoryDropdown from '~/components/moderation/ReportCategoryDropdo
|
|||
import ReportCard from '~/components/manage/moderation/ReportCard.vue'
|
||||
import Pagination from '~/components/vui/Pagination.vue'
|
||||
|
||||
import useSmartSearch from '~/composables/navigation/useSmartSearch'
|
||||
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||
import useOrdering from '~/composables/navigation/useOrdering'
|
||||
import useErrorHandler from '~/composables/useErrorHandler'
|
||||
import useSmartSearch from '~/composables/useSmartSearch'
|
||||
import useOrdering from '~/composables/useOrdering'
|
||||
import usePage from '~/composables/navigation/usePage'
|
||||
|
||||
interface Props extends SmartSearchProps, OrderingProps {
|
||||
mode?: 'card'
|
||||
|
||||
// TODO(wvffle): Remove after https://github.com/vuejs/core/pull/4512 is merged
|
||||
orderingConfigName: RouteWithPreferences | null
|
||||
defaultQuery?: string
|
||||
orderingConfigName?: RouteRecordName
|
||||
updateUrl?: boolean
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
defaultQuery: '',
|
||||
updateUrl: false,
|
||||
mode: 'card'
|
||||
mode: 'card',
|
||||
orderingConfigName: undefined
|
||||
})
|
||||
|
||||
const search = ref()
|
||||
|
||||
// TODO (wvffle): Make sure everything is it's own type
|
||||
const page = ref(1)
|
||||
type ResponseType = { count: number, results: any[] }
|
||||
const result = ref<null | ResponseType>(null)
|
||||
const page = usePage()
|
||||
const result = ref<BackendResponse<Report>>()
|
||||
|
||||
const { onSearch, query, addSearchToken, getTokenValue } = useSmartSearch(props.defaultQuery, props.updateUrl)
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props.orderingConfigName)
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props)
|
||||
const { onSearch, query, addSearchToken, getTokenValue } = useSmartSearch(props)
|
||||
|
||||
const orderingOptions: [OrderingField, keyof typeof sharedLabels.filters][] = [
|
||||
['creation_date', 'creation_date'],
|
||||
|
@ -74,7 +74,7 @@ const fetchData = async () => {
|
|||
}
|
||||
} catch (error) {
|
||||
useErrorHandler(error as Error)
|
||||
result.value = null
|
||||
result.value = undefined
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
<script setup lang="ts">
|
||||
import type { RouteWithPreferences, OrderingField } from '~/store/ui'
|
||||
import type { OrderingProps } from '~/composables/useOrdering'
|
||||
import type { SmartSearchProps } from '~/composables/useSmartSearch'
|
||||
import type { SmartSearchProps } from '~/composables/navigation/useSmartSearch'
|
||||
import type { OrderingProps } from '~/composables/navigation/useOrdering'
|
||||
import type { UserRequest, BackendResponse } from '~/types'
|
||||
import type { RouteRecordName } from 'vue-router'
|
||||
import type { OrderingField } from '~/store/ui'
|
||||
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
@ -12,32 +14,30 @@ import axios from 'axios'
|
|||
import UserRequestCard from '~/components/manage/moderation/UserRequestCard.vue'
|
||||
import Pagination from '~/components/vui/Pagination.vue'
|
||||
|
||||
import useSmartSearch from '~/composables/navigation/useSmartSearch'
|
||||
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||
import useOrdering from '~/composables/navigation/useOrdering'
|
||||
import useErrorHandler from '~/composables/useErrorHandler'
|
||||
import useSmartSearch from '~/composables/useSmartSearch'
|
||||
import useOrdering from '~/composables/useOrdering'
|
||||
import usePage from '~/composables/navigation/usePage'
|
||||
|
||||
interface Props extends SmartSearchProps, OrderingProps {
|
||||
// TODO(wvffle): Remove after https://github.com/vuejs/core/pull/4512 is merged
|
||||
orderingConfigName: RouteWithPreferences | null
|
||||
defaultQuery?: string
|
||||
orderingConfigName?: RouteRecordName
|
||||
updateUrl?: boolean
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
defaultQuery: '',
|
||||
updateUrl: false
|
||||
updateUrl: false,
|
||||
orderingConfigName: undefined
|
||||
})
|
||||
|
||||
const search = ref()
|
||||
|
||||
// TODO (wvffle): Make sure everything is it's own type
|
||||
const page = ref(1)
|
||||
type ResponseType = { count: number, results: any[] }
|
||||
const result = ref<null | ResponseType>(null)
|
||||
const page = usePage()
|
||||
const result = ref<BackendResponse<UserRequest>>()
|
||||
|
||||
const { onSearch, query, addSearchToken, getTokenValue } = useSmartSearch(props.defaultQuery, props.updateUrl)
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props.orderingConfigName)
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props)
|
||||
const { onSearch, query, addSearchToken, getTokenValue } = useSmartSearch(props)
|
||||
|
||||
const orderingOptions: [OrderingField, keyof typeof sharedLabels.filters][] = [
|
||||
['creation_date', 'creation_date'],
|
||||
|
@ -70,7 +70,7 @@ const fetchData = async () => {
|
|||
}
|
||||
} catch (error) {
|
||||
useErrorHandler(error as Error)
|
||||
result.value = null
|
||||
result.value = undefined
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
|
|
|
@ -10,9 +10,6 @@ defineProps<Props>()
|
|||
|
||||
<template>
|
||||
<section class="ui vertical aligned stripe segment">
|
||||
<library-files-table
|
||||
:ordering-config-name="null"
|
||||
:default-query="query"
|
||||
/>
|
||||
<library-files-table :default-query="query" />
|
||||
</section>
|
||||
</template>
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
<script setup lang="ts">
|
||||
import type { RouteWithPreferences, OrderingField } from '~/store/ui'
|
||||
import type { SmartSearchProps } from '~/composables/useSmartSearch'
|
||||
import type { OrderingProps } from '~/composables/useOrdering'
|
||||
import type { ImportStatus } from '~/types'
|
||||
import type { SmartSearchProps } from '~/composables/navigation/useSmartSearch'
|
||||
import type { OrderingProps } from '~/composables/navigation/useOrdering'
|
||||
import type { ImportStatus, BackendResponse, Upload } from '~/types'
|
||||
import type { RouteRecordName } from 'vue-router'
|
||||
import type { OrderingField } from '~/store/ui'
|
||||
|
||||
import { humanSize, truncate } from '~/utils/filters'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
|
@ -16,9 +17,10 @@ import ActionTable from '~/components/common/ActionTable.vue'
|
|||
import Pagination from '~/components/vui/Pagination.vue'
|
||||
|
||||
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||
import useSmartSearch from '~/composables/navigation/useSmartSearch'
|
||||
import useOrdering from '~/composables/navigation/useOrdering'
|
||||
import useErrorHandler from '~/composables/useErrorHandler'
|
||||
import useSmartSearch from '~/composables/useSmartSearch'
|
||||
import useOrdering from '~/composables/useOrdering'
|
||||
import usePage from '~/composables/navigation/usePage'
|
||||
|
||||
interface Events {
|
||||
(e: 'fetch-start'): void
|
||||
|
@ -30,7 +32,7 @@ interface Props extends SmartSearchProps, OrderingProps {
|
|||
customObjects?: any[]
|
||||
|
||||
// TODO(wvffle): Remove after https://github.com/vuejs/core/pull/4512 is merged
|
||||
orderingConfigName: RouteWithPreferences | null
|
||||
orderingConfigName?: RouteRecordName
|
||||
defaultQuery?: string
|
||||
updateUrl?: boolean
|
||||
}
|
||||
|
@ -41,18 +43,17 @@ const props = withDefaults(defineProps<Props>(), {
|
|||
updateUrl: false,
|
||||
filters: () => ({}),
|
||||
needsRefresh: false,
|
||||
customObjects: () => []
|
||||
customObjects: () => [],
|
||||
orderingConfigName: undefined
|
||||
})
|
||||
|
||||
const search = ref()
|
||||
|
||||
// TODO (wvffle): Make sure everything is it's own type
|
||||
const page = ref(1)
|
||||
type ResponseType = { count: number, results: any[] }
|
||||
const result = ref<null | ResponseType>(null)
|
||||
const page = usePage()
|
||||
const result = ref<BackendResponse<Upload>>()
|
||||
|
||||
const { onSearch, query, addSearchToken, getTokenValue } = useSmartSearch(props.defaultQuery, props.updateUrl)
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props.orderingConfigName)
|
||||
const { onSearch, query, addSearchToken, getTokenValue } = useSmartSearch(props)
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props)
|
||||
|
||||
const orderingOptions: [OrderingField, keyof typeof sharedLabels.filters][] = [
|
||||
['creation_date', 'creation_date'],
|
||||
|
@ -79,8 +80,7 @@ const actions = computed(() => [
|
|||
label: $pgettext('Content/Library/Dropdown/Verb', 'Restart import'),
|
||||
isDangerous: true,
|
||||
allowAll: true,
|
||||
// TODO (wvffle): Find correct type
|
||||
filterCheckable: (filter: { import_status: string }) => {
|
||||
filterCheckable: (filter: { import_status: ImportStatus }) => {
|
||||
return filter.import_status !== 'finished'
|
||||
}
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ const fetchData = async () => {
|
|||
result.value = response.data
|
||||
} catch (error) {
|
||||
useErrorHandler(error as Error)
|
||||
result.value = null
|
||||
result.value = undefined
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
|
|
|
@ -63,10 +63,7 @@ const updateApproved = async (follow: LibraryFollow, approved: boolean) => {
|
|||
Library contents
|
||||
</translate>
|
||||
</h2>
|
||||
<library-files-table
|
||||
:filters="{library: object.uuid}"
|
||||
:ordering-config-name="null"
|
||||
/>
|
||||
<library-files-table :filters="{ library: object.uuid }" />
|
||||
|
||||
<div class="ui hidden divider" />
|
||||
<h2 class="ui header">
|
||||
|
|
|
@ -1,41 +1,46 @@
|
|||
<script setup lang="ts">
|
||||
import type { RouteWithPreferences, OrderingField } from '~/store/ui'
|
||||
import type { OrderingProps } from '~/composables/useOrdering'
|
||||
import type { OrderingProps } from '~/composables/navigation/useOrdering'
|
||||
import type { Playlist, BackendResponse } from '~/types'
|
||||
import type { RouteRecordName } from 'vue-router'
|
||||
import type { OrderingField } from '~/store/ui'
|
||||
|
||||
import { computed, onMounted, ref, watch } from 'vue'
|
||||
import { useRouteQuery } from '@vueuse/router'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
import { syncRef } from '@vueuse/core'
|
||||
import { sortedUniq } from 'lodash-es'
|
||||
|
||||
import axios from 'axios'
|
||||
import $ from 'jquery'
|
||||
|
||||
import { useRouter, onBeforeRouteUpdate } from 'vue-router'
|
||||
import { computed, ref, watch, onMounted } from 'vue'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
import PlaylistCardList from '~/components/playlists/CardList.vue'
|
||||
import Pagination from '~/components/vui/Pagination.vue'
|
||||
|
||||
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||
import useOrdering from '~/composables/navigation/useOrdering'
|
||||
import useErrorHandler from '~/composables/useErrorHandler'
|
||||
import useOrdering from '~/composables/useOrdering'
|
||||
import usePage from '~/composables/navigation/usePage'
|
||||
import useLogger from '~/composables/useLogger'
|
||||
|
||||
interface Props extends OrderingProps {
|
||||
defaultPage?: number
|
||||
defaultQuery?: string
|
||||
scope?: string
|
||||
scope?: 'me' | 'all'
|
||||
|
||||
// TODO(wvffle): Remove after https://github.com/vuejs/core/pull/4512 is merged
|
||||
orderingConfigName: RouteWithPreferences | null
|
||||
orderingConfigName?: RouteRecordName
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
defaultPage: 1,
|
||||
defaultQuery: '',
|
||||
scope: 'all'
|
||||
scope: 'all',
|
||||
orderingConfigName: undefined
|
||||
})
|
||||
|
||||
const page = ref(+props.defaultPage)
|
||||
type ResponseType = { count: number, results: any[] }
|
||||
const result = ref<null | ResponseType>(null)
|
||||
const query = ref(props.defaultQuery)
|
||||
const page = usePage()
|
||||
|
||||
const q = useRouteQuery('query', '')
|
||||
const query = ref(q.value)
|
||||
syncRef(q, query, { direction: 'ltr' })
|
||||
|
||||
const result = ref<BackendResponse<Playlist>>()
|
||||
|
||||
const orderingOptions: [OrderingField, keyof typeof sharedLabels.filters][] = [
|
||||
['creation_date', 'creation_date'],
|
||||
|
@ -46,20 +51,7 @@ const orderingOptions: [OrderingField, keyof typeof sharedLabels.filters][] = [
|
|||
const logger = useLogger()
|
||||
const sharedLabels = useSharedLabels()
|
||||
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props.orderingConfigName)
|
||||
|
||||
const router = useRouter()
|
||||
const updateQueryString = () => router.replace({
|
||||
query: {
|
||||
query: query.value,
|
||||
page: page.value,
|
||||
paginateBy: paginateBy.value,
|
||||
ordering: orderingString.value
|
||||
}
|
||||
})
|
||||
|
||||
watch(page, updateQueryString)
|
||||
onOrderingUpdate(updateQueryString)
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props)
|
||||
|
||||
const isLoading = ref(false)
|
||||
const fetchData = async () => {
|
||||
|
@ -82,15 +74,25 @@ const fetchData = async () => {
|
|||
result.value = response.data
|
||||
} catch (error) {
|
||||
useErrorHandler(error as Error)
|
||||
result.value = null
|
||||
result.value = undefined
|
||||
} finally {
|
||||
logger.timeEnd('Fetching albums')
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
onBeforeRouteUpdate(fetchData)
|
||||
watch(page, fetchData)
|
||||
fetchData()
|
||||
|
||||
const search = () => {
|
||||
page.value = 1
|
||||
q.value = query.value
|
||||
}
|
||||
|
||||
onOrderingUpdate(() => {
|
||||
page.value = 1
|
||||
fetchData()
|
||||
})
|
||||
|
||||
onMounted(() => $('.ui.dropdown').dropdown())
|
||||
|
||||
const { $pgettext } = useGettext()
|
||||
|
@ -98,6 +100,8 @@ const labels = computed(() => ({
|
|||
playlists: $pgettext('*/*/*', 'Playlists'),
|
||||
searchPlaceholder: $pgettext('Content/Playlist/Placeholder/Call to action', 'Enter playlist name…')
|
||||
}))
|
||||
|
||||
const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value].sort((a, b) => a - b)))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -121,7 +125,7 @@ const labels = computed(() => ({
|
|||
</template>
|
||||
<form
|
||||
:class="['ui', {'loading': isLoading}, 'form']"
|
||||
@submit.prevent="updateQueryString();fetchData()"
|
||||
@submit.prevent="search"
|
||||
>
|
||||
<div class="fields">
|
||||
<div class="field">
|
||||
|
@ -185,14 +189,12 @@ const labels = computed(() => ({
|
|||
v-model="paginateBy"
|
||||
class="ui dropdown"
|
||||
>
|
||||
<option :value="12">
|
||||
12
|
||||
</option>
|
||||
<option :value="25">
|
||||
25
|
||||
</option>
|
||||
<option :value="50">
|
||||
50
|
||||
<option
|
||||
v-for="opt in paginateOptions"
|
||||
:key="opt"
|
||||
:value="opt"
|
||||
>
|
||||
{{ opt }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
|
|
@ -1905,6 +1905,14 @@
|
|||
resolved "https://registry.yarnpkg.com/@vueuse/metadata/-/metadata-9.1.1.tgz#b3fe4b97e62096f7566cd8eb107c503998b2c9a6"
|
||||
integrity sha512-XZ2KtSW+85LLHB/IdGILPAtbIVHasPsAW7aqz3BRMzJdAQWRiM/FGa1OKBwLbXtUw/AmjKYFlZJo7eOFIBXRog==
|
||||
|
||||
"@vueuse/router@^9.1.1":
|
||||
version "9.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@vueuse/router/-/router-9.1.1.tgz#356946b97e2499d96d8e9b5cfced5f778edd63c9"
|
||||
integrity sha512-1HE09QYoHEUF2vWJqGEV1GgoFy6ti7gxzahiN9o/GJpyWM11koQd03BhP4RjVbUx3ua2wTYNSmaCKvLJGCnNGg==
|
||||
dependencies:
|
||||
"@vueuse/shared" "9.1.1"
|
||||
vue-demi "*"
|
||||
|
||||
"@vueuse/shared@9.1.1":
|
||||
version "9.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@vueuse/shared/-/shared-9.1.1.tgz#811f47629e281a19013ae6dcdf11ed3e1e91e023"
|
||||
|
|
Loading…
Reference in New Issue