diff --git a/front/src/components/favorites/List.vue b/front/src/components/favorites/List.vue index 9c2a17aa5..4644a8bb8 100644 --- a/front/src/components/favorites/List.vue +++ b/front/src/components/favorites/List.vue @@ -7,16 +7,15 @@ 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 useOrdering, { OrderingProps } 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' +import { OrderingField } from '~/store/ui' -interface Props { - orderingConfigName: RouteWithPreferences | null +interface Props extends OrderingProps { defaultPage?: number defaultPaginateBy?: number } diff --git a/front/src/components/library/Albums.vue b/front/src/components/library/Albums.vue index fea7d6f6c..8e884295a 100644 --- a/front/src/components/library/Albums.vue +++ b/front/src/components/library/Albums.vue @@ -5,18 +5,17 @@ import $ from 'jquery' import { onBeforeRouteUpdate, useRouter } from 'vue-router' import { computed, onMounted, reactive, ref, watch } from 'vue' import { useGettext } from 'vue3-gettext' -import { OrderingField, RouteWithPreferences } from '~/store/ui' +import { OrderingField } from '~/store/ui' import AlbumCard from '~/components/audio/album/Card.vue' import Pagination from '~/components/vui/Pagination.vue' import TagsSelector from '~/components/library/TagsSelector.vue' import useLogger from '~/composables/useLogger' import useSharedLabels from '~/composables/locale/useSharedLabels' -import useOrdering from '~/composables/useOrdering' +import useOrdering, { OrderingProps } from '~/composables/useOrdering' import { useStore } from '~/store' -interface Props { - orderingConfigName: RouteWithPreferences | null +interface Props extends OrderingProps { defaultPage?: number defaultPaginateBy?: number defaultQuery?: string @@ -61,11 +60,6 @@ const updateQueryString = () => router.replace({ } }) -const search = () => { - page.value = props.defaultPage - updateQueryString() -} - watch(page, updateQueryString) onOrderingUpdate(updateQueryString) @@ -128,7 +122,7 @@ const labels = computed(() => ({
diff --git a/front/src/components/library/Artists.vue b/front/src/components/library/Artists.vue index 4f4c38f5e..fdc75b831 100644 --- a/front/src/components/library/Artists.vue +++ b/front/src/components/library/Artists.vue @@ -8,15 +8,14 @@ import Pagination from '~/components/vui/Pagination.vue' import TagsSelector from '~/components/library/TagsSelector.vue' import useLogger from '~/composables/useLogger' import useSharedLabels from '~/composables/locale/useSharedLabels' -import { RouteWithPreferences } from '~/store/ui' +import { OrderingField } from '~/store/ui' import { computed, reactive, ref, watch } from 'vue' import { useGettext } from 'vue3-gettext' import { useStore } from '~/store' -import useOrdering from '~/composables/useOrdering' +import useOrdering, { OrderingProps } from '~/composables/useOrdering' import { onBeforeRouteUpdate, useRouter } from 'vue-router' -interface Props { - orderingConfigName: RouteWithPreferences | null +interface Props extends OrderingProps { defaultPage?: number defaultPaginateBy?: number defaultQuery?: string @@ -40,6 +39,11 @@ const query = ref(props.defaultQuery) const tags = reactive(props.defaultTags.slice()) const excludeCompilation = ref(true) +const orderingOptions: [OrderingField, keyof typeof sharedLabels.filters][] = [ + ['creation_date', 'creation_date'], + ['name', 'name'] +] + const logger = useLogger() const sharedLabels = useSharedLabels() @@ -58,11 +62,6 @@ const updateQueryString = () => router.replace({ } }) -const search = () => { - page.value = props.defaultPage - updateQueryString() -} - watch(page, updateQueryString) onOrderingUpdate(updateQueryString) @@ -126,7 +125,7 @@ const labels = computed(() => ({
@@ -196,13 +195,13 @@ const labels = computed(() => ({ v-model="paginateBy" class="ui dropdown" > - - - diff --git a/front/src/components/library/Library.vue b/front/src/components/library/Library.vue index 3ed9fc055..6c27f499a 100644 --- a/front/src/components/library/Library.vue +++ b/front/src/components/library/Library.vue @@ -3,21 +3,3 @@
- - diff --git a/front/src/components/library/Podcasts.vue b/front/src/components/library/Podcasts.vue index 4c9dbd374..6dc7ead6a 100644 --- a/front/src/components/library/Podcasts.vue +++ b/front/src/components/library/Podcasts.vue @@ -1,3 +1,122 @@ + + - - diff --git a/front/src/components/library/Radios.vue b/front/src/components/library/Radios.vue index 4121622dd..61f71cb76 100644 --- a/front/src/components/library/Radios.vue +++ b/front/src/components/library/Radios.vue @@ -1,3 +1,110 @@ + + - - diff --git a/front/src/components/manage/ChannelsTable.vue b/front/src/components/manage/ChannelsTable.vue index 1ab09b48c..e3613601a 100644 --- a/front/src/components/manage/ChannelsTable.vue +++ b/front/src/components/manage/ChannelsTable.vue @@ -1,16 +1,100 @@ + + - - diff --git a/front/src/components/manage/library/AlbumsTable.vue b/front/src/components/manage/library/AlbumsTable.vue index d2141bc72..ac9d5ab6f 100644 --- a/front/src/components/manage/library/AlbumsTable.vue +++ b/front/src/components/manage/library/AlbumsTable.vue @@ -1,16 +1,114 @@ + + - - diff --git a/front/src/components/manage/library/ArtistsTable.vue b/front/src/components/manage/library/ArtistsTable.vue index 095f740e2..fb0bf8987 100644 --- a/front/src/components/manage/library/ArtistsTable.vue +++ b/front/src/components/manage/library/ArtistsTable.vue @@ -1,16 +1,118 @@ + + - - diff --git a/front/src/components/manage/library/EditsCardList.vue b/front/src/components/manage/library/EditsCardList.vue index dce313370..5ded0db29 100644 --- a/front/src/components/manage/library/EditsCardList.vue +++ b/front/src/components/manage/library/EditsCardList.vue @@ -1,3 +1,158 @@ + + - - diff --git a/front/src/composables/locale/useSharedLabels.ts b/front/src/composables/locale/useSharedLabels.ts index f4841933a..88b4aec21 100644 --- a/front/src/composables/locale/useSharedLabels.ts +++ b/front/src/composables/locale/useSharedLabels.ts @@ -69,6 +69,7 @@ export default () => ({ creation_date: $pgettext('Content/*/*/Noun', 'Creation date'), release_date: $pgettext('Content/*/*/Noun', 'Release date'), accessed_date: $pgettext('Content/*/*/Noun', 'Accessed date'), + applied_date: $pgettext('Content/*/*/Noun', 'Applied date'), first_seen: $pgettext('Content/Moderation/Dropdown/Noun', 'First seen date'), last_seen: $pgettext('Content/Moderation/Dropdown/Noun', 'Last seen date'), modification_date: $pgettext('Content/Playlist/Dropdown/Noun', 'Modification date'), diff --git a/front/src/composables/useOrdering.ts b/front/src/composables/useOrdering.ts index 836e68432..e275825a9 100644 --- a/front/src/composables/useOrdering.ts +++ b/front/src/composables/useOrdering.ts @@ -4,6 +4,10 @@ import { useRoute } from 'vue-router' import { useStore } from '~/store' import { OrderingDirection, OrderingField, RouteWithPreferences } from '~/store/ui' +export interface OrderingProps { + orderingConfigName: RouteWithPreferences | null +} + export default (orderingConfigName: MaybeRef) => { const store = useStore() const route = useRoute() diff --git a/front/src/composables/useSmartSearch.ts b/front/src/composables/useSmartSearch.ts new file mode 100644 index 000000000..d275d0bed --- /dev/null +++ b/front/src/composables/useSmartSearch.ts @@ -0,0 +1,83 @@ +import { MaybeRef, refWithControl } from '@vueuse/core' +import { computed, ref, unref, watch } from 'vue' +import { useRouter } from 'vue-router' +import { compileTokens, normalizeQuery, parseTokens, Token } from '~/utils/search' + +export interface SmartSearchProps { + defaultQuery?: string + updateUrl?: boolean +} + +export default (defaultQuery: MaybeRef, updateUrl: MaybeRef) => { + const query = refWithControl(unref(defaultQuery)) + const tokens = ref([] as Token[]) + + watch(query, (value) => { + // TODO (wvffle): Move normalizeQuery and parseTokens into the composable file + tokens.value = parseTokens(normalizeQuery(value)) + }, { immediate: true }) + + const updateHandlers = new Set<() => void>() + const onSearch = (fn: () => void) => { + updateHandlers.add(fn) + return () => updateHandlers.delete(fn) + } + + const router = useRouter() + watch(tokens, (value) => { + const newQuery = compileTokens(value) + if (unref(updateUrl)) { + return router.replace({ query: { q: newQuery } }) + } + + // TODO (wvffle): updateUrl = false only in FilesTable.vue + query.set(newQuery, false) + for (const handler of updateHandlers) { + handler() + } + // this.page = 1 + // this.fetchData() + }, { deep: true }) + + const getTokenValue = (key: string, fallback: string) => { + const matching = tokens.value.find(token => { + return token.field === key + }) + + return matching?.value ?? fallback + } + + const addSearchToken = (key: string, value: string) => { + if (value === '') { + tokens.value = tokens.value.filter(token => { + return token.field !== key + }) + + return + } + + const existing = tokens.value.filter(token => { + return token.field === key + }) + + if (!existing.length) { + tokens.value.push({ field: key, value }) + return + } + + // TODO (wvffle): Check if triggers reactivity + for (const token of existing) { + token.value = value + } + } + + return { + getTokenValue, + addSearchToken, + onSearch, + query: computed({ + get: () => compileTokens(tokens.value), + set: (value: string) => query.set(value, true) + }) + } +} diff --git a/front/src/store/ui.ts b/front/src/store/ui.ts index 03085dd81..3d66cb767 100644 --- a/front/src/store/ui.ts +++ b/front/src/store/ui.ts @@ -18,7 +18,9 @@ export type RouteWithPreferences = 'library.artists.browse' | 'library.podcasts. export type WebSocketEventName = 'inbox.item_added' | 'import.status_updated' | 'mutation.created' | 'mutation.updated' | 'report.created' | 'user_request.created' | 'Listen' -export type OrderingField = 'creation_date' | 'title' | 'album__title' | 'artist__name' | 'release_date' +export type OrderingField = 'creation_date' | 'title' | 'album__title' | 'artist__name' | 'release_date' | 'name' + | 'applied_date' + export type OrderingDirection = '-' | '+' interface RoutePreferences { paginateBy: number diff --git a/front/src/utils/search.ts b/front/src/utils/search.ts index 07f5a19ae..2a6d4fcfd 100644 --- a/front/src/utils/search.ts +++ b/front/src/utils/search.ts @@ -1,4 +1,4 @@ -interface Token { +export interface Token { field: string | null value: string } diff --git a/front/src/views/playlists/List.vue b/front/src/views/playlists/List.vue index cf50cd52c..1f35bb6cd 100644 --- a/front/src/views/playlists/List.vue +++ b/front/src/views/playlists/List.vue @@ -83,13 +83,13 @@ v-model="paginateBy" class="ui dropdown" > - - -