19a91a1641
Completes FC-6.3 with the UI. - SeriesView gains tabs: Browse (the existing grid) + Suggestions. - Suggestions tab: pending matches as rows (post → series, per-signal strength chips, score), Add (→ chapter) / Skip (→ dismiss); a "Matching on" toggle and a threshold field (both DB-backed via /settings/import), and a Rescan button that enqueues the background matcher. - seriesSuggestions store wires load / accept / dismiss / rescan / settings. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
76 lines
2.3 KiB
JavaScript
76 lines
2.3 KiB
JavaScript
import { defineStore } from 'pinia'
|
|
import { ref } from 'vue'
|
|
import { useApi } from '../composables/useApi.js'
|
|
import { useAsyncAction } from '../composables/useAsyncAction.js'
|
|
import { toast } from '../utils/toast.js'
|
|
|
|
// Backs the Series → Suggestions tab (FC-6.3). The matcher is confirm-only:
|
|
// accept turns a suggestion into a chapter; skip dismisses it. enabled +
|
|
// threshold are the operator-tunable knobs (DB-backed via /settings/import).
|
|
export const useSeriesSuggestionsStore = defineStore('seriesSuggestions', () => {
|
|
const api = useApi()
|
|
const suggestions = ref([])
|
|
const enabled = ref(true)
|
|
const threshold = ref(0.5)
|
|
const { loading, error, run } = useAsyncAction({ errorAs: 'message' })
|
|
|
|
async function load() {
|
|
await run(async () => {
|
|
const body = await api.get('/api/series/suggestions')
|
|
suggestions.value = body.suggestions || []
|
|
})
|
|
}
|
|
|
|
async function loadSettings() {
|
|
const s = await api.get('/api/settings/import')
|
|
enabled.value = s.series_suggest_enabled
|
|
threshold.value = s.series_suggest_threshold
|
|
}
|
|
|
|
async function saveSettings(patch) {
|
|
await api.patch('/api/settings/import', { body: patch })
|
|
}
|
|
|
|
async function setEnabled(v) {
|
|
enabled.value = v
|
|
await saveSettings({ series_suggest_enabled: v })
|
|
}
|
|
|
|
async function setThreshold(v) {
|
|
threshold.value = v
|
|
await saveSettings({ series_suggest_threshold: v })
|
|
}
|
|
|
|
async function accept(id) {
|
|
try {
|
|
await api.post(`/api/series/suggestions/${id}/accept`, {})
|
|
suggestions.value = suggestions.value.filter(s => s.id !== id)
|
|
toast({ text: 'Added to series', type: 'success' })
|
|
} catch (e) {
|
|
toast({ text: `Accept failed: ${e.message}`, type: 'error' })
|
|
}
|
|
}
|
|
|
|
async function dismiss(id) {
|
|
try {
|
|
await api.post(`/api/series/suggestions/${id}/dismiss`, {})
|
|
suggestions.value = suggestions.value.filter(s => s.id !== id)
|
|
} catch (e) {
|
|
toast({ text: `Skip failed: ${e.message}`, type: 'error' })
|
|
}
|
|
}
|
|
|
|
async function rescan() {
|
|
await api.post('/api/series/suggestions/rescan', {})
|
|
toast({
|
|
text: 'Rescan queued — runs in the background; reload to see new matches.',
|
|
type: 'info'
|
|
})
|
|
}
|
|
|
|
return {
|
|
suggestions, enabled, threshold, loading, error,
|
|
load, loadSettings, setEnabled, setThreshold, accept, dismiss, rescan
|
|
}
|
|
})
|