From 3ab0435f27893975df1e4b582b47a5a5ece86794 Mon Sep 17 00:00:00 2001 From: Kasper Seweryn Date: Fri, 6 May 2022 19:41:36 +0000 Subject: [PATCH] Migrate pagination to v-model and start moving away from mixins --- front/src/components/Pagination.vue | 166 +++++----- front/src/components/common/ActionTable.vue | 2 + front/src/components/favorites/List.vue | 334 +++++++++----------- front/src/components/mixins/Ordering.vue | 69 ---- front/src/composables/useOrdering.ts | 38 +++ front/src/main.ts | 1 + front/src/store/ui.ts | 18 +- 7 files changed, 267 insertions(+), 361 deletions(-) delete mode 100644 front/src/components/mixins/Ordering.vue create mode 100644 front/src/composables/useOrdering.ts diff --git a/front/src/components/Pagination.vue b/front/src/components/Pagination.vue index fd3cf0ec2..f91b78f25 100644 --- a/front/src/components/Pagination.vue +++ b/front/src/components/Pagination.vue @@ -1,3 +1,66 @@ + + - - diff --git a/front/src/components/common/ActionTable.vue b/front/src/components/common/ActionTable.vue index 362fb6dca..2d0219f19 100644 --- a/front/src/components/common/ActionTable.vue +++ b/front/src/components/common/ActionTable.vue @@ -196,6 +196,7 @@
+ + +import axios from 'axios' +import $ from 'jquery' +import RadioButton from '~/components/radios/Button.vue' +import Pagination from '~/components/Pagination.vue' +import { checkRedirectToLogin } from '~/utils' +import TrackTable from '~/components/audio/track/Table.vue' +import useLogger from '~/composables/useLogger' +import useSharedLabels from '~/composables/locale/useSharedLabels' +import useOrdering from '~/composables/useOrdering' +import { onBeforeRouteUpdate, useRouter } from 'vue-router' +import { computed, onMounted, reactive, ref, watch } from 'vue' +import { useStore } from '~/store' +import { Track } from '~/types' +import { useGettext } from 'vue3-gettext' +import { OrderingField, RouteWithPreferences } from '~/store/ui' + +interface Props { + orderingConfigName: RouteWithPreferences | null + defaultPage?: number, + defaultPaginateBy?: number +} + +const props = withDefaults(defineProps(), { + defaultPage: 1, + defaultPaginateBy: 1 +}) + +const store = useStore() +await checkRedirectToLogin(store, useRouter()) + +// TODO (wvffle): Make sure everything is it's own type +const page = ref(+props.defaultPage) + +const orderingOptions: [OrderingField, keyof typeof sharedLabels.filters][] = [ + ['creation_date', 'creation_date'], + ['title', 'track_title'], + ['album__title', 'album_title'], + ['artist__name', 'artist_name'] +] + +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 + } +}) + +const results = reactive([]) +const nextLink = ref() +const previousLink = ref() +const count = ref(0) + +const isLoading = ref(false) +const fetchFavorites = async () => { + isLoading.value = true + + const params = { + favorites: 'true', + page: page.value, + page_size: paginateBy.value, + ordering: orderingString.value + } + + try { + logger.time('Loading user favorites') + const response = await axios.get('tracks/', { params: params }) + + results.length = 0 + results.push(...response.data.results) + + for (const track of results) { + store.commit('favorites/track', { id: track.id, value: true }) + } + + count.value = response.data.count + nextLink.value = response.data.next + previousLink.value = response.data.previous + } catch (error) { + // TODO (wvffle): Handle error + } finally { + logger.timeEnd('Loading user favorites') + isLoading.value = false + } +} + +watch(page, updateQueryString) +onOrderingUpdate(updateQueryString) +onBeforeRouteUpdate(fetchFavorites) +fetchFavorites() + +// @ts-expect-error semantic ui +onMounted(() => $('.ui.dropdown').dropdown()) + +const { $pgettext } = useGettext() +const labels = computed(() => ({ + title: $pgettext('Head/Favorites/Title', 'Your Favorites') +})) + + - - diff --git a/front/src/components/mixins/Ordering.vue b/front/src/components/mixins/Ordering.vue deleted file mode 100644 index 787519e91..000000000 --- a/front/src/components/mixins/Ordering.vue +++ /dev/null @@ -1,69 +0,0 @@ - diff --git a/front/src/composables/useOrdering.ts b/front/src/composables/useOrdering.ts new file mode 100644 index 000000000..836e68432 --- /dev/null +++ b/front/src/composables/useOrdering.ts @@ -0,0 +1,38 @@ +import { MaybeRef, reactiveComputed, toRefs } from '@vueuse/core' +import { computed, unref, watch } from 'vue' +import { useRoute } from 'vue-router' +import { useStore } from '~/store' +import { OrderingDirection, OrderingField, RouteWithPreferences } from '~/store/ui' + +export default (orderingConfigName: MaybeRef) => { + 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 + } +} diff --git a/front/src/main.ts b/front/src/main.ts index 348228983..f30216efd 100644 --- a/front/src/main.ts +++ b/front/src/main.ts @@ -50,6 +50,7 @@ Promise.all(modules).finally(() => { logger.info('Everything loaded!') }) +// TODO (wvffle): Rename filters from useSharedLabels to filters from backend // TODO (wvffle): Check for mixin merging: https://v3-migration.vuejs.org/breaking-changes/data-option.html#mixin-merge-behavior-change= // TODO (wvffle): Use emits options: https://v3-migration.vuejs.org/breaking-changes/emits-option.html // TODO (wvffle): Find all array watchers and make them deep diff --git a/front/src/store/ui.ts b/front/src/store/ui.ts index d7f40f54d..9ca6a2b42 100644 --- a/front/src/store/ui.ts +++ b/front/src/store/ui.ts @@ -6,7 +6,7 @@ import { availableLanguages } from '~/init/locale' type SupportedExtension = 'flac' | 'ogg' | 'mp3' | 'opus' | 'aac' | 'm4a' | 'aiff' | 'aif' -type RouteWithPreferences = 'library.artists.browse' | 'library.podcasts.browse' | 'library.radios.browse' +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' @@ -18,12 +18,12 @@ type RouteWithPreferences = 'library.artists.browse' | 'library.podcasts.browse' export type WebSocketEventName = 'inbox.item_added' | 'import.status_updated' | 'mutation.created' | 'mutation.updated' | 'report.created' | 'user_request.created' | 'Listen' -type Ordering = 'creation_date' -type OrderingDirection = '-' +export type OrderingField = 'creation_date' | 'title' | 'album__title' | 'artist__name' +export type OrderingDirection = '-' | '+' interface RoutePreferences { paginateBy: number orderingDirection: OrderingDirection - ordering: Ordering + ordering: OrderingField } interface WebSocketEvent { @@ -351,16 +351,6 @@ const store: Module = { pageTitle: (state, value) => { state.pageTitle = value }, - paginateBy: (state, { route, value }: { route: RouteWithPreferences, value: number }) => { - state.routePreferences[route].paginateBy = value - }, - ordering: (state, { route, value }: { route: RouteWithPreferences, value: Ordering }) => { - state.routePreferences[route].ordering = value - }, - orderingDirection: (state, { route, value }: { route: RouteWithPreferences, value: OrderingDirection }) => { - state.routePreferences[route].orderingDirection = value - }, - window: (state, value) => { state.window = value }