From 47a8726e2769ddfa6b2ea0784daa37b532ee0605 Mon Sep 17 00:00:00 2001 From: nntrivi2001 Date: Tue, 8 Sep 2026 10:54:10 +0700 Subject: [PATCH] chore(client): drop dead UI code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nothing imports SessionCard, CardSkeleton, shortModel or agentPillLabel — the Sessions page renders its own list, formatModelName replaced shortModel, and the UI labels agents through agentOriginLabel. Removes the symbols, their Public surface entries, and the ARCHITECTURE mention of SessionCard. --- ARCHITECTURE.md | 2 +- client/src/components/SessionCard.tsx | 156 -------------------------- client/src/components/Skeleton.tsx | 22 ---- client/src/lib/event-grouping.ts | 31 +---- client/src/lib/format.ts | 23 ---- 5 files changed, 3 insertions(+), 231 deletions(-) delete mode 100644 client/src/components/SessionCard.tsx diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 73d94e0a..88c6967f 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -2438,7 +2438,7 @@ The function handles: - Version number dot-joining (hyphen-separated digits → dotted) - Title-casing for word segments -Components that consume this: SessionDetail, Analytics (donut chart + breakdown), Dashboard (model stats), MessageList, SessionCard, AgentCard, SessionDrillIn, and EventDetail. +Components that consume this: SessionDetail, Analytics (donut chart + breakdown), Dashboard (model stats), MessageList, AgentCard, SessionDrillIn, and EventDetail. ### Data Flow diff --git a/client/src/components/SessionCard.tsx b/client/src/components/SessionCard.tsx deleted file mode 100644 index f4e4f35e..00000000 --- a/client/src/components/SessionCard.tsx +++ /dev/null @@ -1,156 +0,0 @@ -/** - * @file SessionCard.tsx - * @description Compact session card for the Kanban board's "Sessions" view. - * Mirrors AgentCard's information hierarchy (icon · title · meta line) but - * surfaces session-relevant fields: model, agent count, cost, last activity. - * Clicking the card navigates to the session detail page. - * @author Nguyễn Ngọc Trí Vĩ - */ -/* ============================================================================= - * MODULE_GUIDE — extended in-file reference (comments only; safe to read, never executed) - * ============================================================================= - * **Purpose:** Dashboard module consumed by the React client, MCP tools, or desktop shell depending on deployment mode. - * - * ## Design constraints - * - Local-first: no telemetry leaves the machine unless the user configures webhooks. - * - Fail-safe hooks path on the server must never block Claude Code; UI mirrors that - * philosophy by degrading gracefully (empty states, stale badges, reconnect loops). - * - Destructive flows stay behind explicit confirmation modals and server-side gates. - * - Internationalization: user-visible strings belong in i18n JSON, not literals here. - * - * ## Remote data & SSH - * Remote Data Sources let operators aggregate multiple machines. SSH entries describe - * how to reach a peer dashboard; the global data scope (`dataScope.ts`) narrows every - * scoped GET via `?sources=`. Health checks and import history surface in Settings. - * - * ## Internal dependencies - * - `./StatusBadge` - * - `../lib/types` - * - `../lib/format` - * - * ## Public surface - * - `SessionCard` — exported API; see TSDoc on the symbol for behavior. - * - * ## Testing pointers - * - Prefer colocated `__tests__` with Vitest + Testing Library for UI. - * - Server contract changes require `npm run test:server` and OpenAPI sync. - * - * ## Related docs - * - `ARCHITECTURE.md` — hooks → API → SQLite → WebSocket → UI pipeline. - * - `docs/API.md` — REST reference. - * - `skills/file-headers/` — mandatory `@author` header policy. - * ============================================================================= */ -/* ----------------------------------------------------------------------------- - * EXPORT CATALOG — quick index of symbols defined below (documentation only). - * ----------------------------------------------------------------------------- - * **SessionCard** - * Part of this module's public contract. Downstream imports should treat - * the signature and return type as stable unless release notes say otherwise. - * When behavior changes, update the `@file` overview and relevant tests. - * - * ----------------------------------------------------------------------------- */ - -import { useTranslation } from "react-i18next"; -import { useNavigate } from "react-router-dom"; -import { FolderOpen, Bot, Clock, Coins, Cpu } from "lucide-react"; -import { SessionStatusBadge } from "./StatusBadge"; -import { - effectiveSessionStatus, - isSessionAwaitingInput, - sessionAwaitingReason, -} from "../lib/types"; -import type { Session } from "../lib/types"; -import { formatDuration, timeAgo, formatModelName } from "../lib/format"; - -interface SessionCardProps { - session: Session; - onClick?: () => void; -} - -function formatCost(cost: number): string { - if (!Number.isFinite(cost) || cost <= 0) return "$0"; - if (cost >= 1) return `$${cost.toFixed(2)}`; - if (cost >= 0.01) return `$${cost.toFixed(3)}`; - return `$${cost.toFixed(4)}`; -} - -export function SessionCard({ session, onClick }: SessionCardProps) { - const navigate = useNavigate(); - const { t } = useTranslation("kanban"); - const isActive = session.status === "active"; - const isWaiting = isSessionAwaitingInput(session); - const status = effectiveSessionStatus(session); - const title = session.name?.trim() || t("session.anonymous"); - const agentCount = session.agent_count ?? 0; - const model = formatModelName(session.model); - const lastActivity = session.last_activity || session.ended_at || session.started_at; - - function handleClick() { - if (onClick) onClick(); - else navigate(`/sessions/${session.id}`); - } - - return ( -
-
-
-
- -
-
-

{title}

-

- {session.id.slice(0, 12)} -

-
-
- {/* compact: cards are narrow — inline reason chip would squeeze the - title, so the reason stays hover-tooltip-only here. */} - -
- - {session.cwd && ( -

- {session.cwd} -

- )} - -
- - - {t("session.agentSummary", { count: agentCount })} - - {model && ( - - - {model} - - )} - {typeof session.cost === "number" && session.cost > 0 && ( - - - {formatCost(session.cost)} - - )} - - - {session.ended_at - ? `${t("ran")}${formatDuration(session.started_at, session.ended_at)}` - : `${t("running")}${formatDuration(session.started_at, new Date().toISOString())}`} - - - {timeAgo(session.ended_at || lastActivity)} - -
-
- ); -} diff --git a/client/src/components/Skeleton.tsx b/client/src/components/Skeleton.tsx index 813813d5..a5a22270 100644 --- a/client/src/components/Skeleton.tsx +++ b/client/src/components/Skeleton.tsx @@ -29,7 +29,6 @@ * - `StatValueSkeleton` — exported API; see TSDoc on the symbol for behavior. * - `TextSkeleton` — exported API; see TSDoc on the symbol for behavior. * - `TableRowSkeleton` — exported API; see TSDoc on the symbol for behavior. - * - `CardSkeleton` — exported API; see TSDoc on the symbol for behavior. * * ## Testing pointers * - Prefer colocated `__tests__` with Vitest + Testing Library for UI. @@ -63,11 +62,6 @@ * the signature and return type as stable unless release notes say otherwise. * When behavior changes, update the `@file` overview and relevant tests. * - * **CardSkeleton** - * Part of this module's public contract. Downstream imports should treat - * the signature and return type as stable unless release notes say otherwise. - * When behavior changes, update the `@file` overview and relevant tests. - * * ----------------------------------------------------------------------------- */ import type { CSSProperties } from "react"; @@ -145,19 +139,3 @@ export function TableRowSkeleton({ columns, widths }: { columns: number; widths? ); } - -/** - * Block placeholder for card-shaped content (kanban cards, list items). - */ -export function CardSkeleton({ className = "" }: { className?: string }) { - return ( -
- - -
- - -
-
- ); -} diff --git a/client/src/lib/event-grouping.ts b/client/src/lib/event-grouping.ts index 00882a7c..34f24171 100644 --- a/client/src/lib/event-grouping.ts +++ b/client/src/lib/event-grouping.ts @@ -59,7 +59,6 @@ * - `buildEventTitle` — exported API; see TSDoc on the symbol for behavior. * - `shortAgentLabel` — exported API; see TSDoc on the symbol for behavior. * - `AgentInfo` — exported API; see TSDoc on the symbol for behavior. - * - `agentPillLabel` — exported API; see TSDoc on the symbol for behavior. * - `agentOriginLabel` — exported API; see TSDoc on the symbol for behavior. * - `buildOriginLabel` — exported API; see TSDoc on the symbol for behavior. * - `projectFromCwd` — exported API; see TSDoc on the symbol for behavior. @@ -97,11 +96,6 @@ * the signature and return type as stable unless release notes say otherwise. * When behavior changes, update the `@file` overview and relevant tests. * - * **agentPillLabel** - * Part of this module's public contract. Downstream imports should treat - * the signature and return type as stable unless release notes say otherwise. - * When behavior changes, update the `@file` overview and relevant tests. - * * **agentOriginLabel** * Part of this module's public contract. Downstream imports should treat * the signature and return type as stable unless release notes say otherwise. @@ -689,29 +683,8 @@ function singleAgentSegment(info: AgentInfo): string | null { return null; } -/** Resolves the pill label for an event's agent. Returns null when the event - * comes from the session's main agent (the pill is noise in that case) or - * when no info is available. Prefers subagent_type (e.g. "frontend-reviewer"), - * then the agent's name, and finally the last-8 short ID fallback. - * @param agentId The event's `agent_id`; null yields null. - * @param info Optional {@link AgentInfo} for that agent, when known. - * @returns The pill text, or null when nothing worth showing exists. - */ -export function agentPillLabel(agentId: string | null, info: AgentInfo | undefined): string | null { - if (!agentId) return null; - if (info) { - const seg = singleAgentSegment(info); - // A concrete subagent label wins outright. - if (seg !== null) return seg; - // Known main agent with no segment → deliberately no pill. - if (info.type === "main") return null; - } - // No usable info: fall back to the id-derived short label. - return shortAgentLabel(agentId); -} - -/** Resolves a label that always identifies an event's agent origin - unlike - * agentPillLabel, this returns "main" for main agents instead of null. Used +/** Resolves a label that always identifies an event's agent origin - it returns + * "main" for main agents rather than hiding them. Used * by the inline origin prefix ("{session} › {agent} · {action}"). * * When an `agentInfoById` map is provided AND the event's agent has a diff --git a/client/src/lib/format.ts b/client/src/lib/format.ts index 7e3311cb..be6f96e6 100644 --- a/client/src/lib/format.ts +++ b/client/src/lib/format.ts @@ -57,7 +57,6 @@ * - `fmt` — exported API; see TSDoc on the symbol for behavior. * - `fmtCost` — exported API; see TSDoc on the symbol for behavior. * - `fmtCostFull` — exported API; see TSDoc on the symbol for behavior. - * - `shortModel` — exported API; see TSDoc on the symbol for behavior. * - `formatModelName` — exported API; see TSDoc on the symbol for behavior. * - `pathBasename` — exported API; see TSDoc on the symbol for behavior. * @@ -133,11 +132,6 @@ * the signature and return type as stable unless release notes say otherwise. * When behavior changes, update the `@file` overview and relevant tests. * - * **shortModel** - * Part of this module's public contract. Downstream imports should treat - * the signature and return type as stable unless release notes say otherwise. - * When behavior changes, update the `@file` overview and relevant tests. - * * **formatModelName** * Part of this module's public contract. Downstream imports should treat * the signature and return type as stable unless release notes say otherwise. @@ -431,23 +425,6 @@ export function fmtCostFull(n: number, decimals = 2): string { // Model-name + path formatters // =========================================================================== -/** - * Strip the date suffix from a Claude model ID: - * "claude-opus-4-7-20260101" → "opus-4-7". Returns the original string - * when the pattern doesn't match, and null/undefined unchanged. - * @param model A raw model identifier, or null/undefined. - * @returns The captured `tier-major(-minor)` slug (e.g. `"opus-4-7"`), the original - * string if it isn't a `claude-…` id, or `null` for falsy input. - * @remarks The capture group `([a-z]+-\d+(?:-\d+)?)` grabs the family plus a one- or - * two-segment version (`sonnet-4`, `opus-4-7`) but stops before the trailing - * `-YYYYMMDD` date. This is the terse form; {@link formatModelName} is the pretty one. - */ -export function shortModel(model: string | null | undefined): string | null { - if (!model) return null; - const m = model.match(/claude-([a-z]+-\d+(?:-\d+)?)/i); - return m?.[1] ?? model; // captured slug, else the input unchanged -} - /** * Lookup from a lowercased leading token to its display brand. Drives the * brand-specific formatting branches in {@link formatModelName}; a token absent