Adopt shared WebUI layout primitives
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
import { DescriptionList } from "@govoplan/core-webui";
|
||||||
|
import { MetricGrid } from "@govoplan/core-webui";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import {
|
import {
|
||||||
DismissibleAlert,
|
DismissibleAlert,
|
||||||
@@ -43,7 +45,7 @@ export default function OpsHealthWidget({ settings, refreshKey }: { settings: Ap
|
|||||||
<div className="button-row compact-actions">
|
<div className="button-row compact-actions">
|
||||||
<DocumentationHelpLink reference={OPS_DOCUMENTATION} />
|
<DocumentationHelpLink reference={OPS_DOCUMENTATION} />
|
||||||
</div>
|
</div>
|
||||||
<div className="metric-grid inside dashboard-widget-metrics">
|
<MetricGrid columns={3} spacing="none">
|
||||||
<MetricCard label="Readiness" value={ready ? "ready" : "blocked"} tone={ready ? "good" : "danger"} detail={status?.readiness.profile ?? "-"} />
|
<MetricCard label="Readiness" value={ready ? "ready" : "blocked"} tone={ready ? "good" : "danger"} detail={status?.readiness.profile ?? "-"} />
|
||||||
<MetricCard label="Workers" value={status?.summary.celery_enabled ? workerMetrics?.workers ?? 0 : "off"} tone={status?.summary.celery_enabled && !missingQueues.length ? "good" : "warning"} detail={missingQueues.length ? `${missingQueues.length} queue(s) without a consumer` : status?.summary.celery_enabled ? "All configured queues covered" : "Single-process mode"} />
|
<MetricCard label="Workers" value={status?.summary.celery_enabled ? workerMetrics?.workers ?? 0 : "off"} tone={status?.summary.celery_enabled && !missingQueues.length ? "good" : "warning"} detail={missingQueues.length ? `${missingQueues.length} queue(s) without a consumer` : status?.summary.celery_enabled ? "All configured queues covered" : "Single-process mode"} />
|
||||||
<MetricCard label="Active tasks" value={workerMetrics?.active_tasks ?? 0} tone="info" detail={status?.summary.celery_enabled ? "Reported by live workers" : "Workers disabled"} />
|
<MetricCard label="Active tasks" value={workerMetrics?.active_tasks ?? 0} tone="info" detail={status?.summary.celery_enabled ? "Reported by live workers" : "Workers disabled"} />
|
||||||
@@ -54,16 +56,16 @@ export default function OpsHealthWidget({ settings, refreshKey }: { settings: Ap
|
|||||||
<MetricCard label="Backup" value={status?.summary.backup_state ?? "unknown"} tone={status?.summary.backup_state === "ok" ? "good" : "warning"} detail="Backup and restore evidence" />
|
<MetricCard label="Backup" value={status?.summary.backup_state ?? "unknown"} tone={status?.summary.backup_state === "ok" ? "good" : "warning"} detail="Backup and restore evidence" />
|
||||||
<MetricCard label="Probes" value={status?.summary.operational_probe_count ?? 0} tone="neutral" detail="Module-owned operational checks" />
|
<MetricCard label="Probes" value={status?.summary.operational_probe_count ?? 0} tone="neutral" detail="Module-owned operational checks" />
|
||||||
<MetricCard label="Warnings" value={warningCount + errorCount} tone={errorCount ? "danger" : warningCount ? "warning" : "good"} detail="Current health checks" />
|
<MetricCard label="Warnings" value={warningCount + errorCount} tone={errorCount ? "danger" : warningCount ? "warning" : "good"} detail="Current health checks" />
|
||||||
</div>
|
</MetricGrid>
|
||||||
{status?.readiness.blockers.length ?
|
{status?.readiness.blockers.length ?
|
||||||
<dl className="detail-list dashboard-compact-list below-grid">
|
<DescriptionList variant="inline" termWidth="compact" className="below-grid">
|
||||||
{status.readiness.blockers.slice(0, 3).map((blocker) =>
|
{status.readiness.blockers.slice(0, 3).map((blocker) =>
|
||||||
<div key={blocker.id}>
|
<div key={blocker.id}>
|
||||||
<dt><StatusBadge status={blocker.state === "error" ? "error" : "warning"} label={blocker.state} /></dt>
|
<dt><StatusBadge status={blocker.state === "error" ? "error" : "warning"} label={blocker.state} /></dt>
|
||||||
<dd><strong>{blocker.label}</strong><span className="muted"> · {blocker.detail}</span></dd>
|
<dd><strong>{blocker.label}</strong><span className="muted"> · {blocker.detail}</span></dd>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</dl> :
|
</DescriptionList> :
|
||||||
<p className="muted below-grid">No readiness blockers reported.</p>
|
<p className="muted below-grid">No readiness blockers reported.</p>
|
||||||
}
|
}
|
||||||
</LoadingFrame>);
|
</LoadingFrame>);
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { DescriptionList } from "@govoplan/core-webui";
|
||||||
|
import { MetricGrid } from "@govoplan/core-webui";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { PauseCircle, PlayCircle, RefreshCw } from "lucide-react";
|
import { PauseCircle, PlayCircle, RefreshCw } from "lucide-react";
|
||||||
import { ContentGrid,
|
import { ContentGrid,
|
||||||
@@ -146,7 +148,7 @@ export default function OpsPage({ settings, auth }: {settings: ApiSettings;auth:
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<LoadingFrame loading={loading} label="i18n:govoplan-ops.loading_operations_status.6890fe6e">
|
<LoadingFrame loading={loading} label="i18n:govoplan-ops.loading_operations_status.6890fe6e">
|
||||||
<div className="metric-grid">
|
<MetricGrid>
|
||||||
<MetricCard label="i18n:govoplan-ops.profile.ff4fc027" value={status?.summary.active_profile ?? "-"} tone="info" detail={status?.summary.database_url ?? "i18n:govoplan-ops.no_database_url.51a2db0c"} />
|
<MetricCard label="i18n:govoplan-ops.profile.ff4fc027" value={status?.summary.active_profile ?? "-"} tone="info" detail={status?.summary.database_url ?? "i18n:govoplan-ops.no_database_url.51a2db0c"} />
|
||||||
<MetricCard label="i18n:govoplan-ops.readiness.1db9d6fb" value={ready ? "ready" : "not ready"} tone={ready ? "good" : "danger"} detail={status?.readiness.blockers.length ? `${status.readiness.blockers.length} blocker(s)` : "i18n:govoplan-ops.no_readiness_blockers.0df259bd"} />
|
<MetricCard label="i18n:govoplan-ops.readiness.1db9d6fb" value={ready ? "ready" : "not ready"} tone={ready ? "good" : "danger"} detail={status?.readiness.blockers.length ? `${status.readiness.blockers.length} blocker(s)` : "i18n:govoplan-ops.no_readiness_blockers.0df259bd"} />
|
||||||
<MetricCard label="i18n:govoplan-ops.modules.04e9462c" value={status?.summary.module_count ?? 0} tone="neutral" detail="i18n:govoplan-ops.enabled_in_the_runtime_registry.d2c6142d" />
|
<MetricCard label="i18n:govoplan-ops.modules.04e9462c" value={status?.summary.module_count ?? 0} tone="neutral" detail="i18n:govoplan-ops.enabled_in_the_runtime_registry.d2c6142d" />
|
||||||
@@ -165,7 +167,7 @@ export default function OpsPage({ settings, auth }: {settings: ApiSettings;auth:
|
|||||||
<MetricCard label="Recovery" value={status?.summary.recovery_required_count ?? 0} tone={status?.summary.recovery_required_count ? "danger" : "good"} detail="Operations requiring recovery attention" />
|
<MetricCard label="Recovery" value={status?.summary.recovery_required_count ?? 0} tone={status?.summary.recovery_required_count ? "danger" : "good"} detail="Operations requiring recovery attention" />
|
||||||
<MetricCard label="Provider bindings" value={status?.governance.summary.configured_external_provider_count ?? 0} tone={status?.governance.summary.provider_attention_count ? "warning" : "good"} detail={`${status?.governance.summary.provider_attention_count ?? 0} requiring attention`} />
|
<MetricCard label="Provider bindings" value={status?.governance.summary.configured_external_provider_count ?? 0} tone={status?.governance.summary.provider_attention_count ? "warning" : "good"} detail={`${status?.governance.summary.provider_attention_count ?? 0} requiring attention`} />
|
||||||
<MetricCard label="i18n:govoplan-ops.infrastructure_capabilities" value={status?.summary.infrastructure_capability_count ?? 0} tone={status?.infrastructure.available ? "good" : "neutral"} detail={i18nMessage("i18n:govoplan-ops.pending_post_install_tasks", { value0: status?.summary.pending_post_install_task_count ?? 0 })} />
|
<MetricCard label="i18n:govoplan-ops.infrastructure_capabilities" value={status?.summary.infrastructure_capability_count ?? 0} tone={status?.infrastructure.available ? "good" : "neutral"} detail={i18nMessage("i18n:govoplan-ops.pending_post_install_tasks", { value0: status?.summary.pending_post_install_task_count ?? 0 })} />
|
||||||
</div>
|
</MetricGrid>
|
||||||
|
|
||||||
<ContentGrid columns={2} collapseAt="workspace" className="">
|
<ContentGrid columns={2} collapseAt="workspace" className="">
|
||||||
<Card title="i18n:govoplan-ops.health_checks.201c869f">
|
<Card title="i18n:govoplan-ops.health_checks.201c869f">
|
||||||
@@ -196,12 +198,12 @@ export default function OpsPage({ settings, auth }: {settings: ApiSettings;auth:
|
|||||||
|
|
||||||
<Card title="i18n:govoplan-ops.infrastructure_capabilities">
|
<Card title="i18n:govoplan-ops.infrastructure_capabilities">
|
||||||
<InfrastructureCapabilityTable items={status?.infrastructure.capabilities ?? []} />
|
<InfrastructureCapabilityTable items={status?.infrastructure.capabilities ?? []} />
|
||||||
{(status?.infrastructure.post_install_tasks.length ?? 0) > 0 && <dl className="detail-list">
|
{(status?.infrastructure.post_install_tasks.length ?? 0) > 0 && <DescriptionList variant="inline">
|
||||||
{status?.infrastructure.post_install_tasks.map((task) => <div key={task.resume_key}>
|
{status?.infrastructure.post_install_tasks.map((task) => <div key={task.resume_key}>
|
||||||
<dt><StatusBadge status="warning" label={task.state} /></dt>
|
<dt><StatusBadge status="warning" label={task.state} /></dt>
|
||||||
<dd><strong>{task.summary}</strong><span className="muted"> · {task.owner_module} · {task.required_inputs.join(", ")}</span></dd>
|
<dd><strong>{task.summary}</strong><span className="muted"> · {task.owner_module} · {task.required_inputs.join(", ")}</span></dd>
|
||||||
</div>)}
|
</div>)}
|
||||||
</dl>}
|
</DescriptionList>}
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card title="i18n:govoplan-ops.sizing_assumptions.6ade9a90">
|
<Card title="i18n:govoplan-ops.sizing_assumptions.6ade9a90">
|
||||||
@@ -476,14 +478,14 @@ function GovernanceTable({ modules }: { modules: OpsGovernanceModule[] }) {
|
|||||||
function CheckList({ checks }: {checks: OpsCheck[];}) {
|
function CheckList({ checks }: {checks: OpsCheck[];}) {
|
||||||
if (!checks.length) return <p className="muted">i18n:govoplan-ops.no_health_checks_reported.03c067c4</p>;
|
if (!checks.length) return <p className="muted">i18n:govoplan-ops.no_health_checks_reported.03c067c4</p>;
|
||||||
return (
|
return (
|
||||||
<dl className="detail-list">
|
<DescriptionList variant="inline">
|
||||||
{checks.map((check) =>
|
{checks.map((check) =>
|
||||||
<div key={check.id}>
|
<div key={check.id}>
|
||||||
<dt><StatusBadge status={stateTone(check.state)} label={check.state} /></dt>
|
<dt><StatusBadge status={stateTone(check.state)} label={check.state} /></dt>
|
||||||
<dd><strong>{check.label}</strong><span className="muted"> · {check.detail}</span></dd>
|
<dd><strong>{check.label}</strong><span className="muted"> · {check.detail}</span></dd>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</dl>);
|
</DescriptionList>);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user