import { useEffect, useState } from "react"; import { useJiraRefresh } from "../../shell/refresh.ts"; import { refreshText } from "../../shell/refreshStatus.ts"; import { applyTheme, readTheme, saveTheme, THEME_NAMES, THEMES, type Theme } from "../../shell/theme.ts"; import { statusText, type BoardStatus } from "../status.ts"; import type { BoardModel, Visible } from "../types.ts"; import { NOT_IN_HUB } from "../constants.ts"; import { Dropdown } from "../../ui/index.ts"; interface ToolbarProps { label: string; title: string; status: BoardStatus | null; byDate: boolean; snap: boolean; model: BoardModel; vis: Visible; problemCount: number; problemsOpen: boolean; tableOpen: boolean; onReload(): void; onFile(name: string, text: string): void; onProblems(): void; onExport(): void; onTable(): void; onSnap(): void; onReset(): void; } export function Toolbar(p: ToolbarProps) { const [theme, setTheme] = useState(readTheme); const [confirm, setConfirm] = useState(false); useEffect(() => { if (!confirm) return; const t = setTimeout(() => setConfirm(false), 8000); return () => clearTimeout(t); }, [confirm]); const refresh = useJiraRefresh(); // кнопка и ход пакета временно здесь; в верхней панели — с Task 5 const rt = refresh.event ? refreshText(refresh.event) : null; const st = p.status ? statusText(p.status) : rt ? { text: rt.text, warn: rt.tone === "error" || rt.tone === "warning" } : null; const m = p.model, v = p.vis, r = v.removed; const coreShown = v.nodes.filter((n) => !n.dim).length, ctxShown = v.nodes.length - coreShown; const nextTheme = () => { const t = THEMES[(THEMES.indexOf(theme) + 1) % THEMES.length]; setTheme(t); saveTheme(t); applyTheme(t); }; return (

Доска связей

{p.label} {st && {st.text}} {coreShown} задач из {m.nodes.filter((n) => !n.stub).length} {ctxShown > 0 && <> · +{ctxShown} соседи по связям} {" · "}{v.links.length} связей из {m.links.length} {r.loose > 0 && <> · скрыто без связей: {r.loose}} ( )}> {(close) => ( <>
{!confirm ? : (
Вернуть автоматическую раскладку {p.byDate ? "режима «по датам»" : "(обычную; раскладка «по датам» останется)"}, порядок и раскрытие дорожек?
)} )}
); } // предупреждения о данных под шапкой (строки 878–880) export function Notice({ model }: { model: BoardModel }) { const notes = [...model.problems]; if (model.missing) notes.push(`упомянуты в связях, но в ${model.stubLane === NOT_IN_HUB ? "зеркале хаба" : "файле"} отсутствуют: ${model.missing}`); if (!notes.length) return null; return
{notes.map((n) => {n})}
; }