import { useProjects } from "../api/queries.ts"; import type { Project } from "../api/types.ts"; import { MODULES } from "../modules/index.ts"; import type { HubModule } from "../modules/types.ts"; import { fmtStamp } from "../ui/format.ts"; import { IconButton, IconRefresh } from "../ui/index.ts"; import { useModuleActivity } from "./activity/activity.ts"; import { agentText } from "./activity/agentText.ts"; import { eventText } from "./activity/events.ts"; type WithStatus = HubModule & Required>; const WITH_STATUS = MODULES.filter((m): m is WithStatus => !!m.status); // строка модуля: название, агент (точка + текст), значок обновления, свежесть, событие пакета. // Живой регион role="status" стоит в строке постоянно и меняет только текст (T10.1 #94): вставка вместе с текстом не озвучивается function ModuleRow({ m, project, variant }: { m: WithStatus; project: Project; variant: "expanded" | "collapsed" }) { const act = useModuleActivity(m.name); const { status } = m; const fresh = status.freshness(project); const label = status.refresh?.label; const scope = status.scope === "all" ? "все проекты" : "проект"; const action = label ? `${label} — ${status.scope === "all" ? scope : `${scope} ${project.label}`}` : null; const a = act.agent; const av = a ? agentText(a) : null; const agentLabel = av?.text ?? null, agentHint = av?.hint; const freshText = fresh.error ? `синхронизация не удалась: ${fresh.error}` : fresh.at ? `данные на ${fmtStamp(fresh.at)} · ${scope}` : "обновления ещё не было"; const ev = act.event ? eventText(act.event, label ?? "") : null; const online = !!av?.online; const collapsed = variant === "collapsed"; const eventEl = {ev?.text}; const button = action && (