diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index ee06def..329e0b9 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -134,26 +134,26 @@ async function del(path: string): Promise { return response.json(); } -// Dashboard -export const fetchCounts = (machineId?: string) => +// Dashboard (Jellyfin-backed; selected via jellyfin_service_id) +export const fetchCounts = (jellyfinServiceId?: string) => get( "/api/dashboard/counts", - machineId ? { machine_id: machineId } : undefined, + jellyfinServiceId ? { jellyfin_service_id: jellyfinServiceId } : undefined, ); -export const fetchLibraries = (machineId?: string) => +export const fetchLibraries = (jellyfinServiceId?: string) => get( "/api/dashboard/libraries", - machineId ? { machine_id: machineId } : undefined, + jellyfinServiceId ? { jellyfin_service_id: jellyfinServiceId } : undefined, ); -export const fetchActivity = (machineId?: string) => +export const fetchActivity = (jellyfinServiceId?: string) => get( "/api/dashboard/activity", - machineId ? { machine_id: machineId } : undefined, + jellyfinServiceId ? { jellyfin_service_id: jellyfinServiceId } : undefined, ); -export const fetchUsers = (machineId?: string) => +export const fetchUsers = (jellyfinServiceId?: string) => get( "/api/users", - machineId ? { machine_id: machineId } : undefined, + jellyfinServiceId ? { jellyfin_service_id: jellyfinServiceId } : undefined, ); // Backward-compatible alias used by older hooks/components. @@ -293,27 +293,27 @@ export const resetLocalDatabase = (payload: ResetLocalDatabaseInput) => ); // Media -export const fetchMediaStatus = (machineId?: string) => +export const fetchMediaStatus = (jellyfinServiceId?: string) => get( "/api/media/status", - machineId ? { machine_id: machineId } : undefined, + jellyfinServiceId ? { jellyfin_service_id: jellyfinServiceId } : undefined, ); -export const buildMediaIndex = (machineId?: string) => +export const buildMediaIndex = (jellyfinServiceId?: string) => post( - machineId - ? `/api/media/build?machine_id=${encodeURIComponent(machineId)}` + jellyfinServiceId + ? `/api/media/build?jellyfin_service_id=${encodeURIComponent(jellyfinServiceId)}` : "/api/media/build", ); -export const stopMediaIndexBuild = (machineId?: string) => +export const stopMediaIndexBuild = (jellyfinServiceId?: string) => post( - machineId - ? `/api/media/stop?machine_id=${encodeURIComponent(machineId)}` + jellyfinServiceId + ? `/api/media/stop?jellyfin_service_id=${encodeURIComponent(jellyfinServiceId)}` : "/api/media/stop", ); -export const forceStopMediaIndexBuild = (machineId?: string) => +export const forceStopMediaIndexBuild = (jellyfinServiceId?: string) => post( - machineId - ? `/api/media/force-stop?machine_id=${encodeURIComponent(machineId)}` + jellyfinServiceId + ? `/api/media/force-stop?jellyfin_service_id=${encodeURIComponent(jellyfinServiceId)}` : "/api/media/force-stop", ); export const queryMedia = (params: { @@ -325,7 +325,7 @@ export const queryMedia = (params: { sort_order?: string; limit?: number; offset?: number; - machineId?: string; + jellyfinServiceId?: string; }) => get("/api/media/query", { libraries: params.libraries || "", @@ -336,7 +336,9 @@ export const queryMedia = (params: { sort_order: params.sort_order || "Ascending", limit: String(params.limit || 100), offset: String(params.offset || 0), - ...(params.machineId ? { machine_id: params.machineId } : {}), + ...(params.jellyfinServiceId + ? { jellyfin_service_id: params.jellyfinServiceId } + : {}), }); // Files diff --git a/frontend/src/hooks/useDashboard.ts b/frontend/src/hooks/useDashboard.ts index 64a1b5d..d472d6a 100644 --- a/frontend/src/hooks/useDashboard.ts +++ b/frontend/src/hooks/useDashboard.ts @@ -9,26 +9,26 @@ import { } from "../api/client"; import type { DashboardShortcutInput } from "../types"; -export function useCounts(machineId?: string) { +export function useCounts(jellyfinServiceId?: string) { return useQuery({ - queryKey: ["dashboard", "counts", machineId ?? "default"], - queryFn: () => fetchCounts(machineId), + queryKey: ["dashboard", "counts", jellyfinServiceId ?? "default"], + queryFn: () => fetchCounts(jellyfinServiceId), staleTime: 5 * 60 * 1000, }); } -export function useLibraries(machineId?: string) { +export function useLibraries(jellyfinServiceId?: string) { return useQuery({ - queryKey: ["dashboard", "libraries", machineId ?? "default"], - queryFn: () => fetchLibraries(machineId), + queryKey: ["dashboard", "libraries", jellyfinServiceId ?? "default"], + queryFn: () => fetchLibraries(jellyfinServiceId), staleTime: 5 * 60 * 1000, }); } -export function useActivity(machineId?: string) { +export function useActivity(jellyfinServiceId?: string) { return useQuery({ - queryKey: ["dashboard", "activity", machineId ?? "default"], - queryFn: () => fetchActivity(machineId), + queryKey: ["dashboard", "activity", jellyfinServiceId ?? "default"], + queryFn: () => fetchActivity(jellyfinServiceId), refetchInterval: 15_000, }); } diff --git a/frontend/src/hooks/useMedia.ts b/frontend/src/hooks/useMedia.ts index a0f8eb8..bd7b273 100644 --- a/frontend/src/hooks/useMedia.ts +++ b/frontend/src/hooks/useMedia.ts @@ -7,10 +7,10 @@ import { forceStopMediaIndexBuild, } from "../api/client"; -export function useMediaStatus(machineId?: string) { +export function useMediaStatus(jellyfinServiceId?: string) { return useQuery({ - queryKey: ["media", "status", machineId ?? "default"], - queryFn: () => fetchMediaStatus(machineId), + queryKey: ["media", "status", jellyfinServiceId ?? "default"], + queryFn: () => fetchMediaStatus(jellyfinServiceId), staleTime: 5_000, refetchInterval: (query) => query.state.data?.build_running ? 1000 : false, @@ -27,7 +27,7 @@ export function useMediaQuery(params: { sort_order?: string; limit?: number; offset?: number; - machineId?: string; + jellyfinServiceId?: string; enabled?: boolean; }) { const { enabled = true, ...queryParams } = params; @@ -44,30 +44,30 @@ function invalidateMedia(queryClient: ReturnType) { queryClient.invalidateQueries({ queryKey: ["media"] }); } -export function useBuildIndex(machineId?: string) { +export function useBuildIndex(jellyfinServiceId?: string) { const queryClient = useQueryClient(); return useMutation({ - mutationFn: () => buildMediaIndex(machineId), + mutationFn: () => buildMediaIndex(jellyfinServiceId), onSuccess: () => { invalidateMedia(queryClient); }, }); } -export function useStopBuildIndex(machineId?: string) { +export function useStopBuildIndex(jellyfinServiceId?: string) { const queryClient = useQueryClient(); return useMutation({ - mutationFn: () => stopMediaIndexBuild(machineId), + mutationFn: () => stopMediaIndexBuild(jellyfinServiceId), onSuccess: () => { invalidateMedia(queryClient); }, }); } -export function useForceStopBuildIndex(machineId?: string) { +export function useForceStopBuildIndex(jellyfinServiceId?: string) { const queryClient = useQueryClient(); return useMutation({ - mutationFn: () => forceStopMediaIndexBuild(machineId), + mutationFn: () => forceStopMediaIndexBuild(jellyfinServiceId), onSuccess: () => { invalidateMedia(queryClient); }, diff --git a/frontend/src/hooks/useUsers.ts b/frontend/src/hooks/useUsers.ts index d8bbd07..4d31114 100644 --- a/frontend/src/hooks/useUsers.ts +++ b/frontend/src/hooks/useUsers.ts @@ -2,10 +2,10 @@ import { useQuery } from "@tanstack/react-query"; import { fetchUsers } from "../api/client"; import type { UserDirectoryResponse } from "../types"; -export function useUsers(machineId?: string) { +export function useUsers(jellyfinServiceId?: string) { return useQuery({ - queryKey: ["users", machineId ?? "default"], - queryFn: () => fetchUsers(machineId), + queryKey: ["users", jellyfinServiceId ?? "default"], + queryFn: () => fetchUsers(jellyfinServiceId), staleTime: 30_000, }); } diff --git a/frontend/src/pages/Applications.tsx b/frontend/src/pages/Applications.tsx index e00b72e..e002554 100644 --- a/frontend/src/pages/Applications.tsx +++ b/frontend/src/pages/Applications.tsx @@ -1,28 +1,23 @@ -import { useMemo, useState } from "react"; +import { useState } from "react"; import { useSearchParams } from "react-router-dom"; import { Alert, AlertDescription } from "@/components/ui/alert"; import { Badge } from "@/components/ui/badge"; import { TabsTrigger } from "@/components/ui/tabs"; import { Media } from "./Media"; import { useCounts, useLibraries } from "../hooks/useDashboard"; -import { useMonitoringSettings } from "../hooks/useSettings"; +import { useServiceInstances } from "../hooks/useServices"; import { SectionCard } from "../components/SectionCard"; import { TabbedCard } from "../components/TabbedCard"; function JellyfinLibraryStats() { const [searchParams] = useSearchParams(); - const { data: machines = [] } = useMonitoringSettings(); - const jellyfinMachines = useMemo( - () => - machines.filter( - (machine) => machine.enabled && machine.services.includes("jellyfin"), - ), - [machines], - ); - const selectedMachineId = - searchParams.get("machine_id") || jellyfinMachines[0]?.id || ""; - const { data: counts } = useCounts(selectedMachineId || undefined); - const { data: libraries } = useLibraries(selectedMachineId || undefined); + const { data: jellyfinServices = [] } = useServiceInstances("jellyfin"); + const selectedServiceId = + searchParams.get("jellyfin_service_id") || + jellyfinServices.find((s) => s.enabled)?.id || + ""; + const { data: counts } = useCounts(selectedServiceId || undefined); + const { data: libraries } = useLibraries(selectedServiceId || undefined); return ( - {selectedMachineId ? "Selected machine" : "Default machine"} + {selectedServiceId ? "Selected service" : "Default service"} } > diff --git a/frontend/src/pages/Media.tsx b/frontend/src/pages/Media.tsx index 0808431..e6dd536 100644 --- a/frontend/src/pages/Media.tsx +++ b/frontend/src/pages/Media.tsx @@ -32,7 +32,7 @@ import { } from "../hooks/useMedia"; import { usePersistentState } from "../hooks/usePersistentState"; import type { MediaItem } from "../types"; -import { useMonitoringSettings } from "../hooks/useSettings"; +import { useServiceInstances } from "../hooks/useServices"; import { useCounts, useLibraries } from "../hooks/useDashboard"; function formatDuration(seconds: number | null | undefined): string { @@ -178,23 +178,18 @@ export function Media() { const navigate = useNavigate(); const [searchParams, setSearchParams] = useSearchParams(); const isSmall = usePrefersSmallScreen(); - const { data: machines } = useMonitoringSettings(); - const jellyfinMachines = useMemo( - () => - (machines ?? []).filter( - (machine) => machine.enabled && machine.services.includes("jellyfin"), - ), - [machines], - ); - const selectedMachineId = - searchParams.get("machine_id") || jellyfinMachines[0]?.id || ""; - const { data: counts } = useCounts(selectedMachineId || undefined); - const { data: libraries } = useLibraries(selectedMachineId || undefined); - const { data: status } = useMediaStatus(selectedMachineId || undefined); - const buildIndex = useBuildIndex(selectedMachineId || undefined); - const stopBuildIndex = useStopBuildIndex(selectedMachineId || undefined); + const { data: jellyfinServices = [] } = useServiceInstances("jellyfin"); + const selectedServiceId = + searchParams.get("jellyfin_service_id") || + jellyfinServices.find((s) => s.enabled)?.id || + ""; + const { data: counts } = useCounts(selectedServiceId || undefined); + const { data: libraries } = useLibraries(selectedServiceId || undefined); + const { data: status } = useMediaStatus(selectedServiceId || undefined); + const buildIndex = useBuildIndex(selectedServiceId || undefined); + const stopBuildIndex = useStopBuildIndex(selectedServiceId || undefined); const forceStopBuildIndex = useForceStopBuildIndex( - selectedMachineId || undefined, + selectedServiceId || undefined, ); const [rawMediaState, setMediaState] = usePersistentState( @@ -215,17 +210,17 @@ export function Media() { const [rowSelection, setRowSelection] = useState({}); useEffect(() => { - if (!searchParams.get("machine_id") && selectedMachineId) { + if (!searchParams.get("jellyfin_service_id") && selectedServiceId) { setSearchParams( (current) => { const next = new URLSearchParams(current); - next.set("machine_id", selectedMachineId); + next.set("jellyfin_service_id", selectedServiceId); return next; }, { replace: true }, ); } - }, [searchParams, selectedMachineId, setSearchParams]); + }, [searchParams, selectedServiceId, setSearchParams]); const { data: queryResult, isLoading } = useMediaDataQuery({ types, @@ -235,7 +230,7 @@ export function Media() { sort_order: sortOrder, limit: pageSize, offset, - machineId: selectedMachineId || undefined, + jellyfinServiceId: selectedServiceId || undefined, enabled: status?.exists ?? false, }); @@ -323,27 +318,27 @@ export function Media() {

Jellyfin

- +