sdlc-hub/web/src/shell/DataStatus.tsx
2026-10-22 08:51:23 +04:00

49 lines
2.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useBoard } from "../api/queries.ts";
import { fmtStamp } from "../board/model/util.ts";
import { Button, IconButton, IconRefresh } from "../ui/index.ts";
import { useJiraRefresh } from "./refresh.ts";
import { refreshText } from "./refreshStatus.ts";
const HINT = "Поставить в хаб пакет «обновление по базовой JQL» и дождаться его: агент перечитает задачи из Jira";
// состояние данных: агент, время последнего полного обновления, кнопка «Обновить из Jira» и ход пакета;
// compact — свёрнутая боковая панель: кнопка-значок с точкой агента, тексты в подсказке (#69, design 3)
export function DataStatus({ project, compact = false }: { project: string | null; compact?: boolean }) {
const refresh = useJiraRefresh();
const board = useBoard(project);
const ls = board.data?.last_sync ?? null;
const agent = refresh.agent;
const rt = refresh.event ? refreshText(refresh.event) : null;
const seen = agent?.last_seen_at ? `последний выход на связь: ${fmtStamp(agent.last_seen_at)}` : "выхода на связь ещё не было";
const agentText = agent ? (agent.online ? "агент на связи" : "агент офлайн") : null;
const syncText = board.data ? (ls ? `данные на ${fmtStamp(ls.finished_at)}` : "полного обновления не было") : null;
const event = <span className={`data-status__event${rt ? ` data-status__event--${rt.tone}` : ""}${compact ? " visually-hidden" : ""}`}
role="status" title={rt?.text}>{rt?.text}</span>;
if (compact) {
const title = ["Обновить из Jira", agentText, syncText, rt?.text].filter(Boolean).join(" · ");
return (
<div className="data-status data-status--compact">
<IconButton label="Обновить из Jira" title={title} disabled={refresh.busy} aria-busy={refresh.busy ? "true" : undefined}
icon={refresh.busy ? <span className="ui-spinner" aria-hidden="true" /> : <IconRefresh />} onClick={() => void refresh.start()} />
{agent && <span className={"data-status__dot" + (agent.online ? " is-online" : "")} aria-hidden="true" />}
{event}
</div>
);
}
return (
<div className="data-status">
{agent && (
<span className="data-status__agent" title={seen}>
<span className={"data-status__dot" + (agent.online ? " is-online" : "")} aria-hidden="true" />
{agentText}
</span>
)}
{syncText && <span className="data-status__sync">{syncText}</span>}
<Button variant="primary" icon={<IconRefresh />} loading={refresh.busy} onClick={() => void refresh.start()} title={HINT}>
Обновить из Jira
</Button>
{event}
</div>
);
}