refactor(recovery): reduce summary header duplication

This commit is contained in:
rcourtman
2026-03-29 12:33:10 +01:00
parent 35c7aea985
commit 7ebfce5f20
3 changed files with 25 additions and 15 deletions
@@ -771,10 +771,12 @@ shared monitoring-card rhythm of one dominant metric plus compact supporting
rows rather than reviving bespoke visual telemetry that makes the strip read
heavier than the rest of Pulse.
That same scan rule should also use the summary header for the first, obvious
recovery counts. The header should carry total protected items plus the top
healthy/attention cues in the same way other Pulse monitoring summaries expose
their first read, while the `Posture` card focuses on the composition of the
attention state instead of repeating the same healthy count again.
recovery counts. The header should carry total protected items plus one top
status cue, not a second copy of the full posture breakdown. When recovery has
attention-state items, the header should surface that attention cue; otherwise
it may carry the healthy cue. The `Posture` card then owns the composition of
the posture state instead of having the header and card repeat both healthy and
attention counts at once.
That same differentiation rule applies across cards too. `Posture` and
`Freshness` should not lead with the same stale/attention headline; the
freshness card should emphasize recent successful coverage such as fresh-in-24h
@@ -62,7 +62,7 @@ describe('RecoverySummary', () => {
expect(screen.getByText(/recovery points/i)).toBeInTheDocument();
expect(screen.getByText(/item types/i)).toBeInTheDocument();
expect(screen.getByText('2 platforms')).toBeInTheDocument();
expect(screen.getAllByText('1 healthy').length).toBeGreaterThan(1);
expect(screen.getAllByText('1 healthy')).toHaveLength(1);
expect(screen.getByText('1 attention')).toBeInTheDocument();
expect(screen.getByText('1 stale')).toBeInTheDocument();
expect(screen.getByText('fresh in 24h')).toBeInTheDocument();
@@ -108,6 +108,23 @@ export const RecoverySummary: Component<RecoverySummaryProps> = (props) => {
if (!latestLabel) return undefined;
return <span class="ml-auto truncate text-xs text-muted">{latestLabel}</span>;
});
const headerStatusCue = createMemo(() => {
if (attentionCount() > 0) {
return (
<span class="text-amber-600 dark:text-amber-400">
{attentionCount()} attention
</span>
);
}
if (healthyCount() > 0) {
return (
<span class="text-emerald-600 dark:text-emerald-400">
{healthyCount()} healthy
</span>
);
}
return undefined;
});
return (
<Show when={hasRollups()}>
@@ -115,16 +132,7 @@ export const RecoverySummary: Component<RecoverySummaryProps> = (props) => {
headerLeft={
<>
<span class="font-medium text-base-content">{summary().total} protected items</span>
<Show when={healthyCount() > 0}>
<span class="text-emerald-600 dark:text-emerald-400">
{healthyCount()} healthy
</span>
</Show>
<Show when={attentionCount() > 0}>
<span class="text-amber-600 dark:text-amber-400">
{attentionCount()} attention
</span>
</Show>
<Show when={headerStatusCue()}>{headerStatusCue()}</Show>
</>
}
timeRange={props.timeRange()}