The host knows what it launched and, after a disconnect, that it is counting down to closing it. None of that was visible: the console showed a stream with no game, and a game on its way to being closed was something you found out about afterwards. The Dashboard gains a running-game card above the session card — box art matched against the catalog it already fetches, so no new endpoint and no request on the 2 s status poll. "End now" means the two different things the row's state implies: a live game ends by stopping its session (what then happens to the game follows the policy — stopping a session is not licence to close a game), while one already waiting out its reconnect window has no session left to stop and is ended directly. The settings card sits next to the display keep-alive policy because that is the same question one step out: keep-alive decides how long a *display* outlives a disconnect, this decides whether the *game* does. The copy says plainly what `always` costs, that a drop is not someone pressing Stop, and that a display kept forever is unaffected either way — the precedence rule that would otherwise surprise someone. Where a build enforces nothing (macOS, no launch path) the controls are shown disabled rather than hidden: "does nothing here" is information. Also fixes the story fixtures, which had gone stale against the `games[]` field Phase 1 added, and adds a story for the state the card exists for — a game whose client walked away. web: build + tsc clean, biome-formatted; en/de messages complete.
33 lines
950 B
TypeScript
33 lines
950 B
TypeScript
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
import { DashboardView } from "@/sections/Dashboard/view";
|
|
import { statusActive, statusGrace, statusIdle } from "./lib/fixtures";
|
|
|
|
const meta = {
|
|
title: "Pages/Dashboard",
|
|
component: DashboardView,
|
|
args: {
|
|
onStopSession: () => {},
|
|
onRequestIdr: () => {},
|
|
onEndGame: () => {},
|
|
isStopping: false,
|
|
isRequestingIdr: false,
|
|
isEndingGame: false,
|
|
},
|
|
} satisfies Meta<typeof DashboardView>;
|
|
|
|
export default meta;
|
|
type Story = StoryObj<typeof meta>;
|
|
|
|
export const ActiveSession: Story = {
|
|
args: { status: { data: statusActive, isLoading: false, error: null } },
|
|
};
|
|
|
|
export const Idle: Story = {
|
|
args: { status: { data: statusIdle, isLoading: false, error: null } },
|
|
};
|
|
|
|
/** A game whose client vanished: the host closes it when the countdown runs out. */
|
|
export const GameWaitingForItsClient: Story = {
|
|
args: { status: { data: statusGrace, isLoading: false, error: null } },
|
|
};
|