steam-backlog-enforcer/web/src/screens/Picks.tsx
Krzysztof kuhy Rudnicki 1bdf360193 pick keeps already-picked games; fast install reports progress
pick and pick-manual no longer uninstall games that are already allowed:
the outgoing assignment is kept as a released pick (installed, no lock)
until 'pick --replace', done/check, or abandon-pick. The allowed set is
capped at max_manual_picks + 1; a pick over it is refused before the
candidate list / confirmation, naming the games. status and the web
Picks card list kept games with an Abandon button.

Fast install now tracks the installer log from the spawn offset: web
jobs drive the progress bar (per-depot %, phase) and echo a line every
30 s; daemon-started runs are exposed via ctl status / /api/daemon and
shown on the Dashboard.

Also: web deps bumped for dependency freshness (react-query 5.104.5,
typescript-eslint 8.72.0, vite 8.3.5, node 24.22.1 in CI).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CUaX4zAa6H4sMu3jd6RFdb
2026-10-23 20:14:12 +02:00

58 lines
2.4 KiB
TypeScript

import { useQuery } from '@tanstack/react-query'
import { q } from '../api/queries'
import { CommandButton, CommandCard } from '../commands/CommandCard'
import { Empty, ErrorNotice, Loading } from '../ui/Notice'
import { Actions, Card, PageHead } from '../ui/Page'
/** Everything that changes which game is assigned. */
export function Picks() {
const { data, error } = useQuery(q.status)
const none = data !== undefined && data.manual_picks.length === 0 && data.kept_picks.length === 0
return (
<>
<PageHead
title="Picks"
sub={data?.current_game_name ? <>Assigned: <strong>{data.current_game_name}</strong></> : 'Which game you are playing, and how to move on.'}
/>
<Actions>
<CommandCard name="check" label="Check" />
<CommandCard name="done" label="Done" tone="primary" />
<CommandCard name="pick" label="Pick…" />
<CommandCard name="scan" label="Scan" />
<CommandCard name="pick-manual" label="Lock in a game…" />
</Actions>
<Card title="Manual picks">
{error && <ErrorNotice error={error} />}
{!data && !error && <Loading what="status" />}
{none && (
<Empty>No manual picks. "Lock in a game" adds one and locks most commands for 14 days.</Empty>
)}
<ul className="rows">
{data?.manual_picks.map((p) => (
<li key={p.app_id} className="row">
<span className="grow">
<strong>{p.name}</strong> <span className="muted">· picked {p.age_days} d ago · {p.app_id}</span>
</span>
<CommandButton name="abandon-pick" preset={{ app_id: p.app_id }} label="Abandon…" tone="danger" />
</li>
))}
{/* Released, expired or kept by "Pick…": still installed and playable. */}
{data?.kept_picks.map((p) => (
<li key={p.app_id} className="row">
<span className="grow">
<strong>{p.name}</strong> <span className="muted">· kept · no lock · {p.app_id}</span>
</span>
<CommandButton name="abandon-pick" preset={{ app_id: p.app_id }} label="Abandon…" tone="danger" />
</li>
))}
</ul>
{none && (
<div className="actions">
<CommandButton name="abandon-pick" label="Abandon a pick by app id…" />
</div>
)}
</Card>
</>
)
}