feat(front): federated search in search modal

This commit is contained in:
ArneBo 2025-04-23 13:09:35 +02:00
parent 0f2be469da
commit 3ad9022556
1 changed files with 42 additions and 25 deletions

View File

@ -9,9 +9,12 @@ import { trim, uniqBy } from 'lodash-es'
import useErrorHandler from '~/composables/useErrorHandler'
import { useI18n } from 'vue-i18n'
import { useModal } from '~/ui/composables/useModal.ts'
import { useStore } from '~/store'
import ArtistCard from '~/components/artist/Card.vue'
import PlaylistCard from '~/components/playlists/Card.vue'
import ChannelCard from '~/components/audio/ChannelCard.vue'
import ActorLink from '~/components/common/ActorLink.vue'
import TrackTable from '~/components/audio/track/Table.vue'
import AlbumCard from '~/components/album/Card.vue'
import RadioCard from '~/components/radios/Card.vue'
@ -279,6 +282,26 @@ watch(results, () => {
openSections.value = new Set(categoriesWithResults.map(({ type }) => type))
})
// Subscribe to an RSS feed
const store = useStore()
/**
* Subscribe to an RSS feed and return the route for the subscribed channel
* @param url The RSS feed URL
* @returns The route object for the subscribed channel
*/
const rssSubscribe = async (url: string) => {
try {
const response = await axios.post('channels/rss-subscribe/', { url })
store.commit('channels/subscriptions', { uuid: response.data.channel.uuid, value: true })
return response.data.channel
} catch (error) {
useErrorHandler(error as Error)
return null
}
}
// Search
const search = async () => {
@ -324,13 +347,10 @@ const search = async () => {
} else {
// TODO: add (@)type key to Response type
if (category.type === 'rss') {
const response = await axios.post<Response['rss']>(
category.endpoint,
{ url: trimmedQuery.value }
)
results.value.type = category.type
results.value.rss = [response.data]
responses.value[category.type] = response.data
const channel = await rssSubscribe(trimmedQuery.value)
if (channel) {
results.value.rss = [channel] // Store the subscribed channel
}
} else if (category.type === 'federation') {
const response = await axios.post<Response['federation']>(
category.endpoint,
@ -406,8 +426,6 @@ const radioConfig = computed<RadioConfig | null>(() =>
// Start the search
watch(queryDebounced, search, { immediate: true })
// TODO: Include redirectRoute function from RemoteSearchForm.vue and adapt to !results.value and results.value.type instead of objInfo
</script>
<template>
@ -501,30 +519,29 @@ watch(queryDebounced, search, { immediate: true })
<!-- If response has "url": "webfinger://node1@node1.funkwhale.test" -> Link to go directly to the federation page -->
<span v-if="category.type === 'rss' && count(category) > 0">
<Alert>{{ t('modals.search.tryAgain') }}</Alert>
<Link
v-for="channel in resultsPerCategory(category)"
:key="channel.artist.fid"
:to="channel.artist.fid"
autofocus
<template v-if="category.type === 'rss' && count(category) > 0">
<Alert
blue
style="grid-column: 1 / -1"
>
{{ channel.artist.name }}
</Link>
</span>
{{ t('modals.search.tryAgain') }}
</Alert>
<channel-card
v-if="results.rss && results.rss[0]"
:key="results.rss[0].uuid"
:object="results.rss[0]"
/>
</template>
<span v-else-if="category.type === 'federation' && count(category) > 0">
<!-- TODO: Federation search: backend adapter + display, fix results_per_category query -->
<!-- {{ resultsPerCategory(category) }} -->
<!-- TODO: compute :to url for federated object -->
<Link
<ActorLink
v-for="result in resultsPerCategory(category)"
:key="result.id"
:to="{name: 'profile.full', params: result.object?.full_username}"
target="_blank"
>
{{ result.object?.full_username }}
</Link>
:actor="result.object"
/>
</span>
<EmptyState