Remove frontend resource capability arrays

This commit is contained in:
rcourtman 2026-03-19 14:17:00 +00:00
parent a4b95bef92
commit cb20115799
8 changed files with 11 additions and 146 deletions

View file

@ -164,11 +164,11 @@ turning the timeline filter into an arbitrary free-text escape hatch.
The router now wires the tenant resource state provider during initial setup
when a multi-tenant monitor is present, so tenant-scoped storage and recovery
pages do not hit a missing-provider 500 before the monitor is fully wired.
The shared unified-resource consumer hook now also preserves `capabilities`,
`relationships`, `recentChanges`, `facetCounts`, `policy`, and `aiSafeSummary`
fields when storage and recovery surfaces read unified resources, so those
pages see the same control-plane facets as the dedicated resource drawer
instead of flattening them away locally.
The shared unified-resource consumer hook now also preserves `recentChanges`,
`facetCounts`, `policy`, and `aiSafeSummary` fields when storage and recovery
surfaces read unified resources, so those pages see the same control-plane
timeline facets as the dedicated resource drawer instead of flattening them
away locally.
The same storage-facing runtime paths now also normalize org scope through
`frontend-modern/src/utils/orgScope.ts` before building cache keys or
multi-tenant fetch state, so Dashboard, StorageSummary, and other storage
@ -734,6 +734,6 @@ publishes. The same hook and the resource-identity helpers it depends on now
share the canonical trimmed-string utility instead of each surface rebuilding
its own whitespace cleanup, so storage and recovery identity checks stay
aligned with the other resource-graph consumers. That same boundary now also
owns the backend facet-bundle route for capability, relationship, and timeline
history reads, so storage and recovery surfaces must continue to consume the
shared bundle rather than issuing separate local resource-detail fetches.
owns the backend facet-bundle route for timeline history and related change
counts, so storage and recovery surfaces must continue to consume the shared
bundle rather than issuing separate local resource-detail fetches.

View file

@ -557,9 +557,9 @@ rebuilding resource-change labels locally.
That frontend consumer rule now applies on the canonical decode path too:
`frontend-modern/src/hooks/useUnifiedResources.ts` must preserve backend-owned
policy metadata and AI-safe summaries as first-class `Resource` fields, and it
must treat the backend refresh path as the source of truth instead of
re-normalizing policy strings or AI-safe summaries locally.
policy metadata, AI-safe summaries, recent changes, and facet counts as
first-class `Resource` fields, and it must treat the backend refresh path as
the source of truth instead of re-normalizing those values locally.
Shared infrastructure consumers such as the unified resource table and detail
drawer must present that owned metadata through shared helpers instead of
reconstructing privacy posture from display names, source types, or other

View file

@ -259,26 +259,6 @@ describe('UnifiedResourceTable performance contract', () => {
backupJobCount: 1,
},
},
capabilities: [
{
name: 'backup',
type: 'native',
description: 'Create a backup snapshot',
minimumApprovalLevel: 'admin',
},
],
relationships: [
{
sourceId: 'pbs-service',
targetId: 'storage-1',
type: 'depends_on',
confidence: 0.88,
active: true,
discoverer: 'proxmox_adapter',
observedAt: new Date().toISOString(),
lastSeenAt: new Date().toISOString(),
},
],
recentChanges: [
{
id: 'pbs-change-1',
@ -304,26 +284,6 @@ describe('UnifiedResourceTable performance contract', () => {
nodeCount: 1,
},
},
capabilities: [
{
name: 'thresholds',
type: 'common',
description: 'Adjust mail gateway thresholds',
minimumApprovalLevel: 'dry_run_only',
},
],
relationships: [
{
sourceId: 'pmg-service',
targetId: 'mail-queue-1',
type: 'depends_on',
confidence: 0.9,
active: true,
discoverer: 'proxmox_adapter',
observedAt: new Date().toISOString(),
lastSeenAt: new Date().toISOString(),
},
],
recentChanges: [
{
id: 'pmg-change-1',

View file

@ -46,32 +46,6 @@ const resource: Resource = {
redact: ['hostname', 'alias'],
},
},
capabilities: [
{
name: 'restart',
type: 'native',
description: 'Restart the host',
minimumApprovalLevel: 'admin',
},
{
name: 'drain',
type: 'common',
description: 'Drain services safely',
minimumApprovalLevel: 'dry_run_only',
},
],
relationships: [
{
sourceId: 'resource-1',
targetId: 'storage-1',
type: 'depends_on',
confidence: 0.94,
active: true,
discoverer: 'proxmox_adapter',
observedAt: new Date().toISOString(),
lastSeenAt: new Date().toISOString(),
},
],
recentChanges: [
{
id: 'change-1',

View file

@ -168,26 +168,6 @@ describe('UnifiedResourceTable workloads links', () => {
backupJobCount: 1,
},
},
capabilities: [
{
name: 'backup',
type: 'native',
description: 'Create a backup snapshot',
minimumApprovalLevel: 'admin',
},
],
relationships: [
{
sourceId: 'pbs-1',
targetId: 'storage-1',
type: 'depends_on',
confidence: 0.88,
active: true,
discoverer: 'proxmox_adapter',
observedAt: new Date().toISOString(),
lastSeenAt: new Date().toISOString(),
},
],
recentChanges: [
{
id: 'pbs-change-1',
@ -213,26 +193,6 @@ describe('UnifiedResourceTable workloads links', () => {
nodeCount: 1,
},
},
capabilities: [
{
name: 'thresholds',
type: 'common',
description: 'Adjust mail gateway thresholds',
minimumApprovalLevel: 'dry_run_only',
},
],
relationships: [
{
sourceId: 'pmg-1',
targetId: 'mail-queue-1',
type: 'depends_on',
confidence: 0.9,
active: true,
discoverer: 'proxmox_adapter',
observedAt: new Date().toISOString(),
lastSeenAt: new Date().toISOString(),
},
],
recentChanges: [
{
id: 'pmg-change-1',

View file

@ -775,27 +775,6 @@ describe('useUnifiedResources', () => {
await flushAsync();
await waitForResourceCount(() => result!.resources().length);
expect(result!.resources()[0]?.capabilities).toEqual([
{
name: 'restart',
type: 'common',
description: 'Restart the resource safely.',
minimumApprovalLevel: 'admin',
platform: 'proxmox',
},
]);
expect(result!.resources()[0]?.relationships).toEqual([
{
sourceId: 'node:pve-1',
targetId: 'node-facets',
type: 'runs_on',
confidence: 0.98,
active: true,
discoverer: 'proxmox_adapter',
observedAt: '2026-03-18T12:00:00Z',
lastSeenAt: '2026-03-18T12:05:00Z',
},
]);
expect(result!.resources()[0]?.recentChanges).toEqual([
{
id: 'change-1',

View file

@ -8,7 +8,6 @@ import { asTrimmedString } from '@/utils/stringUtils';
import { getGlobalWebSocketStore } from '@/stores/websocket-global';
import type {
Resource,
ResourceCapability,
ResourceChange,
ResourceFacetCounts,
ResourceDiscoveryTarget,
@ -16,7 +15,6 @@ import type {
ResourcePBSMeta,
ResourceStatus,
ResourceStorageMeta,
ResourceRelationship,
ResourceType,
} from '@/types/resource';
import { normalizeDiskArray } from '@/utils/format';
@ -303,8 +301,6 @@ type APIResource = {
lastUpdated?: string;
};
kubernetes?: APIKubernetesData;
capabilities?: ResourceCapability[];
relationships?: ResourceRelationship[];
recentChanges?: ResourceChange[];
facetCounts?: ResourceFacetCounts;
physicalDisk?: {
@ -632,8 +628,6 @@ const toResource = (v2: APIResource): Resource => {
canonicalIdentity: v2.canonicalIdentity,
policy: v2.policy as Resource['policy'],
aiSafeSummary: v2.aiSafeSummary as Resource['aiSafeSummary'],
capabilities: v2.capabilities,
relationships: v2.relationships,
recentChanges: v2.recentChanges,
facetCounts: v2.facetCounts,
platformData: {

View file

@ -491,8 +491,6 @@ export interface Resource {
canonicalIdentity?: ResourceCanonicalIdentity;
policy?: ResourcePolicy;
aiSafeSummary?: string;
capabilities?: ResourceCapability[];
relationships?: ResourceRelationship[];
recentChanges?: ResourceChange[];
facetCounts?: ResourceFacetCounts;