diff --git a/apps/web/lib/api/__tests__/plugin-public.test.ts b/apps/web/lib/api/__tests__/plugin-public.test.ts index afd9415..c7012e2 100644 --- a/apps/web/lib/api/__tests__/plugin-public.test.ts +++ b/apps/web/lib/api/__tests__/plugin-public.test.ts @@ -93,7 +93,7 @@ describe("buildPluginGameResponse — shape contract", () => { const r = await buildPluginGameResponse({ game: { id: "g1", steamAppId: 123, title: "X", slug: "x" }, entries, recent: entries, - estFps: { avg: 72.3, low: 35, onePct: 38, high: 140, count: 25 }, + estFps: { avg: 72.3, low: 35, onePct: 38, high: 140, count: 25, tdpAvg: 13.5 }, }) expect(r.estFps).not.toBeNull() expect(r.estFps!.avg).toBe(72.3) diff --git a/apps/web/lib/api/plugin-public.ts b/apps/web/lib/api/plugin-public.ts index cb601a2..f977023 100644 --- a/apps/web/lib/api/plugin-public.ts +++ b/apps/web/lib/api/plugin-public.ts @@ -71,7 +71,7 @@ export async function buildPluginGameResponse(args: { game: PluginGameRow | null entries?: PluginEntryRow[] recent?: PluginEntryRow[] - estFps?: { avg: number; low: number | null; onePct: number | null; high: number | null; count: number } | null + estFps?: { avg: number; low: number | null; onePct: number | null; high: number | null; count: number; tdpAvg: number | null } | null }): Promise { if (!args.game) { return { game: null, estFps: null, topEntries: [], recentEntries: [] } diff --git a/plugins/decky-vault/src/components/LibraryAppPanel.tsx b/plugins/decky-vault/src/components/LibraryAppPanel.tsx index 020efda..601a3a4 100644 --- a/plugins/decky-vault/src/components/LibraryAppPanel.tsx +++ b/plugins/decky-vault/src/components/LibraryAppPanel.tsx @@ -16,6 +16,22 @@ interface Props { baseUrl: string } +function openExternalUrl(url: string) { + try { + if (Router?.NavigateToExternalWeb) { + Router.NavigateToExternalWeb(url) + return + } + } catch (e) { + console.error("[DeckyVault] NavigateToExternalWeb failed:", e) + } + try { + window.open(url, "_blank") + } catch (e) { + console.error("[DeckyVault] window.open failed:", e) + } +} + export default function LibraryAppPanel({ appId, title, hardwareSlug, baseUrl }: Props) { const [data, setData] = useState(null) const [devices, setDevices] = useState([]) @@ -58,14 +74,14 @@ export default function LibraryAppPanel({ appId, title, hardwareSlug, baseUrl }: .map((d) => ({ label: `${d.name} (${d.count})`, data: d.slug })), ] - const gameUrl = data?.game?.slug - ? `${baseUrl}/games/${data.game.slug}` + const gameUrl = data?.game?.steamAppId + ? `${baseUrl}/game/${data.game.steamAppId}` : `${baseUrl}/games` if (loading) { return ( -
+
DeckyVault loading…
@@ -75,7 +91,7 @@ export default function LibraryAppPanel({ appId, title, hardwareSlug, baseUrl }: if (fetchError) { return ( -
+
DeckyVault: {fetchError}
@@ -85,7 +101,7 @@ export default function LibraryAppPanel({ appId, title, hardwareSlug, baseUrl }: if (!data || !data.game) { return ( -
+
Not on DeckyVault — add it
@@ -94,41 +110,35 @@ export default function LibraryAppPanel({ appId, title, hardwareSlug, baseUrl }: return ( <> - {/* Quick stats row */} + {/* Stats + device dropdown inline */} -
- {device && data.estFps ? ( - - {data.estFps.avg} avg FPS - {data.estFps.onePct != null && {data.estFps.onePct} 1% low} - {data.estFps.low != null && {data.estFps.low} min} - {data.estFps.high != null && {data.estFps.high} max} - {data.estFps.tdpAvg != null && {data.estFps.tdpAvg}W TDP} - {data.estFps.count} entries - - ) : ( - - {device - ? "No entries for this device yet" - : "Select a device to see estimated FPS"} - - )} +
+ + {data.estFps ? ( + + {data.estFps.avg} avg + {data.estFps.onePct != null && {data.estFps.onePct} 1% low} + {data.estFps.low != null && {data.estFps.low} min} + {data.estFps.high != null && {data.estFps.high} max} + {data.estFps.tdpAvg != null && {data.estFps.tdpAvg}W TDP} + ({data.estFps.count}) + + ) : ( + No data yet + )} + + setDevice(opt.data as string)} + />
- {/* Device dropdown */} + {/* View Details button */} - setDevice(opt.data as string)} - /> - - - {/* Open on DeckyVault button */} - - Router.NavigateToExternalWeb(gameUrl)}> - View on DeckyVault + openExternalUrl(gameUrl)}> + View Details