mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-05-14 08:20:11 +00:00
Hide default policy badges in infra rows
This commit is contained in:
parent
3f0ea4ec82
commit
bb35c8eb7c
6 changed files with 92 additions and 2 deletions
|
|
@ -393,6 +393,10 @@ share the canonical cluster-name helpers in the shared agent-resource layer,
|
|||
so route labels, pod grouping, and cluster-name fetch keys keep using the
|
||||
same source of truth instead of rebuilding the `clusterName`/`context`/
|
||||
`clusterId` prefix locally.
|
||||
The infrastructure host-table hot path now also suppresses the default
|
||||
`Internal` + `Cloud Summary` policy pair in row chrome. That baseline posture
|
||||
still belongs to the canonical policy contract, but repeating it on every host
|
||||
burns row-density budget without adding operator-grade signal.
|
||||
The shared node adapter also uses that same cluster-name helper for the
|
||||
infrastructure summary surface, so Proxmox node projections stay aligned with
|
||||
the same canonical cluster label instead of carrying a raw adapter-local
|
||||
|
|
|
|||
|
|
@ -199,6 +199,12 @@ The same policy presenter now also owns the routing-scope labels used across
|
|||
AI-facing policy surfaces, while the resource detail drawer stays on
|
||||
per-resource policy lines instead of reconstructing a separate
|
||||
`Allowed`/`Blocked` row or `Cloud Summary` decision row locally.
|
||||
The infrastructure host-table shell now treats the default
|
||||
`Internal` + `Cloud Summary` posture as canonical policy metadata that should
|
||||
stay available in the drawer and AI/governance surfaces without being promoted
|
||||
to always-on row chrome. Inline row badges are reserved for non-default policy
|
||||
states so the canonical resource surface does not imply that every host carries
|
||||
an operator-actionable governance exception.
|
||||
The shared routing policy itself now stays intentionally minimal: it carries
|
||||
only the routing scope and the redaction hints derived from canonical
|
||||
sensitivity, and the cloud-summary decision is derived from that scope
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import {
|
|||
import { getAgentStatusIndicator } from '@/utils/status';
|
||||
import { getPreferredResourceDisplayName } from '@/utils/resourceIdentity';
|
||||
import {
|
||||
getResourcePolicyBadges,
|
||||
getResourcePolicyTableBadges,
|
||||
shouldShowResourceAlternateName,
|
||||
} from '@/utils/resourcePolicyPresentation';
|
||||
import { ResourceDetailDrawer } from './ResourceDetailDrawer';
|
||||
|
|
@ -267,7 +267,7 @@ export const UnifiedResourceHostTableCard: Component<UnifiedResourceHostTableCar
|
|||
() => unifiedSourceBadges().length > 0,
|
||||
);
|
||||
const policyBadges = createMemo(() =>
|
||||
getResourcePolicyBadges(resource.policy),
|
||||
getResourcePolicyTableBadges(resource.policy),
|
||||
);
|
||||
const workloadsHref = createMemo(() => buildWorkloadsHref(resource));
|
||||
|
||||
|
|
|
|||
|
|
@ -249,6 +249,49 @@ describe('UnifiedResourceTable performance contract', () => {
|
|||
expect(matchesSearch(governedResource, 'secret-host-9')).toBe(false);
|
||||
});
|
||||
|
||||
it('suppresses the default policy posture badges in host-table rows while preserving exceptional policy badges', async () => {
|
||||
const resources = [
|
||||
makeResource(0, {
|
||||
name: 'default-policy-host',
|
||||
displayName: 'Default Policy Host',
|
||||
policy: {
|
||||
sensitivity: 'internal',
|
||||
routing: { scope: 'cloud-summary' },
|
||||
},
|
||||
}),
|
||||
makeResource(1, {
|
||||
name: 'governed-host',
|
||||
displayName: 'Governed Host',
|
||||
policy: {
|
||||
sensitivity: 'sensitive',
|
||||
routing: { scope: 'local-first', redact: ['hostname'] },
|
||||
},
|
||||
}),
|
||||
];
|
||||
|
||||
const { container } = render(() => (
|
||||
<UnifiedResourceTable
|
||||
resources={resources}
|
||||
expandedResourceId={null}
|
||||
onExpandedResourceChange={vi.fn()}
|
||||
groupingMode="flat"
|
||||
/>
|
||||
));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(container.querySelector('table')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
const body = container.querySelector('tbody');
|
||||
expect(body).not.toBeNull();
|
||||
const bodyQueries = within(body as HTMLElement);
|
||||
|
||||
expect(bodyQueries.queryByText('Internal')).not.toBeInTheDocument();
|
||||
expect(bodyQueries.queryByText('Cloud Summary')).not.toBeInTheDocument();
|
||||
expect(bodyQueries.getByText('Sensitive')).toBeInTheDocument();
|
||||
expect(bodyQueries.getByText('Local First')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders facet summary badges without changing the Profile S row budget', async () => {
|
||||
const resources = makeResources(PROFILES.S, (i) =>
|
||||
i === 0
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import {
|
|||
RESOURCE_POLICY_REDACTION_ORDER,
|
||||
RESOURCE_POLICY_ROUTING_ORDER,
|
||||
RESOURCE_POLICY_SENSITIVITY_ORDER,
|
||||
getResourcePolicyTableBadges,
|
||||
getResourcePolicyDisplayLabel,
|
||||
getResourcePolicyRedactionSummaries,
|
||||
getResourcePolicyRoutingSummaries,
|
||||
|
|
@ -34,6 +35,27 @@ describe('resourcePolicyPresentation utils', () => {
|
|||
).toEqual(['Hostname', 'IP Address']);
|
||||
});
|
||||
|
||||
it('suppresses the default internal cloud-summary posture in table rows', () => {
|
||||
expect(
|
||||
getResourcePolicyTableBadges({
|
||||
sensitivity: 'internal',
|
||||
routing: {
|
||||
scope: 'cloud-summary',
|
||||
},
|
||||
}),
|
||||
).toEqual([]);
|
||||
|
||||
expect(
|
||||
getResourcePolicyTableBadges({
|
||||
sensitivity: 'sensitive',
|
||||
routing: {
|
||||
scope: 'local-first',
|
||||
redact: ['hostname'],
|
||||
},
|
||||
}).map((badge) => badge.label),
|
||||
).toEqual(['Sensitive', 'Local First']);
|
||||
});
|
||||
|
||||
it('uses the governed aiSafeSummary for redacted resources', () => {
|
||||
expect(
|
||||
getResourcePolicyDisplayLabel({
|
||||
|
|
|
|||
|
|
@ -108,6 +108,21 @@ export const getResourcePolicyBadges = (policy?: ResourcePolicy): PolicyBadgePre
|
|||
return [sensitivityPresentation[policy.sensitivity], routingPresentation[policy.routing.scope]];
|
||||
};
|
||||
|
||||
export const getResourcePolicyTableBadges = (policy?: ResourcePolicy): PolicyBadgePresentation[] => {
|
||||
if (!policy) return [];
|
||||
|
||||
const hasDefaultPolicyPosture =
|
||||
policy.sensitivity === 'internal' &&
|
||||
policy.routing.scope === 'cloud-summary' &&
|
||||
(policy.routing.redact?.length ?? 0) === 0;
|
||||
|
||||
if (hasDefaultPolicyPosture) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return getResourcePolicyBadges(policy);
|
||||
};
|
||||
|
||||
export const getResourceSensitivityLabel = (sensitivity?: ResourceSensitivity): string =>
|
||||
sensitivity ? sensitivityPresentation[sensitivity].label : 'Unclassified';
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue