mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-22 19:23:31 +00:00
Align Patrol findings footer recency
Patrol findings empty-state timing now consumes the canonical recency label so scoped activity is rendered consistently as activity rather than generic or full-patrol recency.
This commit is contained in:
@@ -173,6 +173,10 @@ formatting future schedule timestamps through generic relative-time helpers;
|
||||
otherwise the findings footer can contradict the header by rendering the same
|
||||
next scheduled patrol as `just now` while the main Patrol shell correctly
|
||||
shows a multi-hour countdown.
|
||||
That footer must also use the canonical Patrol recency label rather than a
|
||||
generic `Last:` prefix, so scoped-only recent activity is rendered as
|
||||
`Last activity` and does not silently revert to patrol/full-verification
|
||||
language in the findings surface.
|
||||
When Patrol is currently running, that strip should still stay factual rather
|
||||
than switching to another verdict label: the runtime may add an explicit
|
||||
in-progress indicator, but the primary activity label remains recent activity
|
||||
|
||||
@@ -61,6 +61,7 @@ interface FindingsPanelProps {
|
||||
showControls?: boolean;
|
||||
nextPatrolAt?: string;
|
||||
lastPatrolAt?: string;
|
||||
lastPatrolLabel?: string;
|
||||
patrolIntervalMs?: number;
|
||||
scopeResourceIds?: string[];
|
||||
scopeResourceTypes?: string[];
|
||||
@@ -1161,7 +1162,7 @@ export const FindingsPanel: Component<FindingsPanelProps> = (props) => {
|
||||
d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<span>Last: {formatTime(props.lastPatrolAt!)}</span>
|
||||
<span>{props.lastPatrolLabel ?? 'Last'}: {formatTime(props.lastPatrolAt!)}</span>
|
||||
</div>
|
||||
</Show>
|
||||
<Show when={props.nextPatrolAt}>
|
||||
|
||||
@@ -163,6 +163,11 @@ describe('aiFindingPresentation', () => {
|
||||
expect(findingsPanelSource).toContain('<CountdownTimer targetDate={props.nextPatrolAt!} prefix="Next: " />');
|
||||
expect(findingsPanelSource).not.toContain('Next: {formatTime(props.nextPatrolAt!)}');
|
||||
});
|
||||
|
||||
it('uses the supplied canonical patrol recency label in the footer', () => {
|
||||
expect(findingsPanelSource).toContain("{props.lastPatrolLabel ?? 'Last'}: {formatTime(props.lastPatrolAt!)}");
|
||||
expect(findingsPanelSource).not.toContain('<span>Last: {formatTime(props.lastPatrolAt!)}</span>');
|
||||
});
|
||||
});
|
||||
|
||||
describe('sourceColors', () => {
|
||||
|
||||
@@ -4,10 +4,16 @@ import { ApprovalBanner, PatrolStatusBar, RunHistoryPanel } from '@/components/p
|
||||
import { getFindingSeverityToneClasses } from '@/utils/aiFindingPresentation';
|
||||
import { formatRelativeTime } from '@/utils/format';
|
||||
import { formatTriggerReason } from '@/utils/patrolFormat';
|
||||
import { getPatrolRecencyPresentation } from '@/utils/patrolSummaryPresentation';
|
||||
import type { PatrolIntelligenceState } from './usePatrolIntelligenceState';
|
||||
|
||||
export function PatrolIntelligenceWorkspace(props: { state: PatrolIntelligenceState }) {
|
||||
const state = props.state;
|
||||
const recency = () =>
|
||||
getPatrolRecencyPresentation({
|
||||
runs: state.patrolRunHistory() ?? [],
|
||||
lastPatrolAt: state.patrolStatus()?.last_patrol_at,
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -96,6 +102,7 @@ export function PatrolIntelligenceWorkspace(props: { state: PatrolIntelligenceSt
|
||||
<FindingsPanel
|
||||
nextPatrolAt={state.patrolStatus()?.next_patrol_at}
|
||||
lastPatrolAt={state.patrolStatus()?.last_patrol_at}
|
||||
lastPatrolLabel={recency().label}
|
||||
patrolIntervalMs={state.patrolStatus()?.interval_ms}
|
||||
filterOverride={state.selectedRun() ? 'all' : state.findingsFilterOverride()}
|
||||
filterFindingIds={state.selectedRunFindingIds()}
|
||||
|
||||
Reference in New Issue
Block a user