Skip to content

Commit

Permalink
Add collections to the search&media stores & service
Browse files Browse the repository at this point in the history
  • Loading branch information
obulat committed Oct 5, 2023
1 parent 3db4968 commit 58e54b1
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 21 deletions.
8 changes: 6 additions & 2 deletions frontend/src/data/api-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export interface ApiService {
client: AxiosInstance
query<T = unknown>(
resource: string,
slug: string,
params: Record<string, string>
): Promise<AxiosResponse<T>>
get<T = unknown>(
Expand Down Expand Up @@ -138,19 +139,22 @@ export const createApiService = ({

/**
* @param resource - The endpoint of the resource
* @param slug - the optional additional endpoint, used for collections.
* @param params - Url parameter object
* @returns response The API response object
*/
query<T = unknown>(
resource: string,
params: Record<string, string>
slug: string = "",
params: Record<string, string> = {}
): Promise<AxiosResponse<T>> {
return client.get(`${getResourceSlug(resource)}`, { params })
return client.get(`${getResourceSlug(resource)}${slug}`, { params })
},

/**
* @param resource - The endpoint of the resource
* @param slug - The sub-endpoint of the resource
* @param params - Url query parameter object
* @returns Response The API response object
*/
get<T = unknown>(
Expand Down
10 changes: 8 additions & 2 deletions frontend/src/data/media-service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { decodeMediaData } from "~/utils/decode-media-data"
import type { PaginatedSearchQuery } from "~/types/search"
import type {
PaginatedCollectionQuery,
PaginatedSearchQuery,
} from "~/types/search"
import type { ApiService } from "~/data/api-service"
import type { DetailFromMediaType, Media } from "~/types/media"
import { AUDIO, type SupportedMediaType } from "~/constants/media"
Expand Down Expand Up @@ -45,9 +48,11 @@ class MediaService<T extends Media> {
/**
* Search for media items by keyword.
* @param params - API search query parameters
* @param slug - optional slug to get a collection
*/
async search(
params: PaginatedSearchQuery
params: PaginatedSearchQuery | PaginatedCollectionQuery,
slug: string = ""
): Promise<MediaResult<Record<string, Media>>> {
// Add the `peaks` param to all audio searches automatically
if (this.mediaType === AUDIO) {
Expand All @@ -56,6 +61,7 @@ class MediaService<T extends Media> {

const res = await this.apiService.query<MediaResult<T[]>>(
this.mediaType,
slug,
params as unknown as Record<string, string>
)
return this.transformResults(res.data)
Expand Down
26 changes: 10 additions & 16 deletions frontend/src/stores/media/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ import { isSearchTypeSupported, useSearchStore } from "~/stores/search"
import { useRelatedMediaStore } from "~/stores/media/related-media"
import { deepFreeze } from "~/utils/deep-freeze"

import { PaginatedSearchQuery } from "~/types/search"

export type MediaStoreResult = {
count: number
pageCount: number
Expand Down Expand Up @@ -443,23 +441,19 @@ export const useMediaStore = defineStore("media", {
mediaType: SupportedMediaType
shouldPersistMedia: boolean
}) {
const queryParams = useSearchStore()
.searchQueryParams as PaginatedSearchQuery
let page = 1
const searchStore = useSearchStore()
const { pathSlug, query } = searchStore.getSearchUrlParts(mediaType)

let page = shouldPersistMedia ? this.results[mediaType].page + 1 : 1
if (shouldPersistMedia) {
/**
* If `shouldPersistMedia` is true, then we increment the page that was set by a previous
* fetch. Normally, if `shouldPersistMedia` is true, `page` should have been set to 1 by the
* previous fetch.
*/
page = this.results[mediaType].page + 1
queryParams.page = `${page}`
// Page parameter is only necessary for pages after the first page.
query.page = `${page}`
}
this._updateFetchState(mediaType, "start")
try {
const accessToken = this.$nuxt.$openverseApiToken
const service = initServices[mediaType](accessToken)
const data = await service.search(queryParams)
const data = await service.search(query, pathSlug)
const mediaCount = data.result_count
let errorData: FetchingError | undefined
/**
Expand All @@ -469,11 +463,11 @@ export const useMediaStore = defineStore("media", {
if (!mediaCount) {
page = 0
errorData = {
message: `No results found for ${queryParams.q}`,
message: `No results found for ${query.q}`,
code: NO_RESULT,
requestKind: "search",
searchType: mediaType,
details: { searchTerm: queryParams.q ?? "" },
details: { searchTerm: query.q ?? "" },
}
}
this._updateFetchState(mediaType, "end", errorData)
Expand All @@ -489,7 +483,7 @@ export const useMediaStore = defineStore("media", {
return mediaCount
} catch (error: unknown) {
const errorData = parseFetchingError(error, mediaType, "search", {
searchTerm: queryParams.q ?? "",
searchTerm: query.q ?? "",
})

this._updateFetchState(mediaType, "end", errorData)
Expand Down
75 changes: 74 additions & 1 deletion frontend/src/stores/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,13 @@ import { useProviderStore } from "~/stores/provider"
import { useFeatureFlagStore } from "~/stores/feature-flag"
import { useMediaStore } from "~/stores/media"

import { SearchQuery, PaginatedSearchQuery } from "~/types/search"
import {
SearchQuery,
SearchStrategy,
PaginatedSearchQuery,
CollectionParams,
PaginatedCollectionQuery,
} from "~/types/search"

import type { Ref } from "vue"

Expand All @@ -53,6 +59,8 @@ export const isSearchTypeSupported = (

export interface SearchState {
searchType: SearchType
strategy: SearchStrategy
collectionParams: CollectionParams | null
recentSearches: Ref<string[]>
backToSearchPath: string
searchTerm: string
Expand Down Expand Up @@ -100,10 +108,22 @@ export function computeQueryParams(
return search_query
}

export function collectionToPath(collectionParams: CollectionParams) {
if ("tag" in collectionParams) {
return `tag/${collectionParams.tag}`
} else if ("creator" in collectionParams) {
return `source/${collectionParams.source}/creator/${collectionParams.creator}`
} else {
return `source/${collectionParams.source}`
}
}

export const useSearchStore = defineStore("search", {
state: (): SearchState => ({
searchType: ALL_MEDIA,
searchTerm: "",
strategy: "default",
collectionParams: null,
backToSearchPath: "",
localSearchTerm: "",
recentSearches: useStorage<string[]>("recent-searches", []),
Expand Down Expand Up @@ -186,6 +206,27 @@ export const useSearchStore = defineStore("search", {
},
},
actions: {
setStrategy(
strategy: SearchStrategy,
collectionParams: CollectionParams | null
) {
this.strategy = strategy
this.collectionParams = collectionParams
if (strategy !== "default") {
this.clearFilters()
}
},
getSearchUrlParts(mediaType: SupportedMediaType) {
const query: PaginatedSearchQuery | PaginatedCollectionQuery =
this.strategy === "default"
? computeQueryParams(mediaType, this.filters, this.searchTerm, "API")
: {}
const pathSlug =
this.collectionParams === null
? ""
: collectionToPath(this.collectionParams)
return { query, pathSlug }
},
setBackToSearchPath(path: string) {
this.backToSearchPath = path
},
Expand Down Expand Up @@ -235,6 +276,38 @@ export const useSearchStore = defineStore("search", {
query: queryParams as unknown as Dictionary<string>,
})
},

/**
* Returns localized frontend path for the given collection.
* Does not support query parameters for now.
*/
getCollectionPath({
type,
tag,
creator,
source,
}: {
type: SupportedMediaType
tag?: string
creator?: string
source?: string
}) {
if (!tag && !source) {
throw new Error(
"Must provide a tag, a source or creator and source for a collection path."
)
}
let path = `/${type}/`
if (tag) {
path += `tag/${tag}/`
} else if (creator) {
path += `source/${source}/creator/${creator}/`
} else {
path += `source/${source}/`
}
return this.$nuxt.localePath(path)
},

setSearchType(type: SearchType) {
const featureFlagStore = useFeatureFlagStore()
if (
Expand Down
10 changes: 10 additions & 0 deletions frontend/src/types/search.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { INCLUDE_SENSITIVE_QUERY_PARAM } from "~/constants/content-safety"

export type Collection = "tag" | "creator" | "source"
export type SearchStrategy = "default" | Collection

/**
* The filter query parameters.
Expand Down Expand Up @@ -39,3 +40,12 @@ export type SearchQuery = SearchFilterQuery & SearchRequestQuery
export type PaginatedSearchQuery = SearchRequestQuery &
PaginatedParams &
SearchFilterQuery

export type PaginatedCollectionQuery = PaginatedParams & {
[key: string]: string
}

export type CollectionParams =
| { tag: string }
| { source: string; creator: string }
| { source: string }

0 comments on commit 58e54b1

Please sign in to comment.