Govern shared feedback presentation helpers

This commit is contained in:
rcourtman
2026-03-24 15:45:55 +00:00
parent 0f32d5b079
commit ec99ef6018
4 changed files with 53 additions and 10 deletions
@@ -96,6 +96,11 @@ work extends shared components instead of creating new local variants.
67. `frontend-modern/src/utils/dashboardGuestPresentation.ts`
68. `frontend-modern/src/utils/dashboardKpiPresentation.ts`
69. `frontend-modern/src/utils/dashboardTrendPresentation.ts`
70. `frontend-modern/src/components/Toast/Toast.tsx`
71. `frontend-modern/src/utils/toast.ts`
72. `frontend-modern/src/utils/semanticTonePresentation.ts`
73. `frontend-modern/src/utils/emptyStatePresentation.ts`
74. `frontend-modern/src/utils/typeColumnPresentation.ts`
61. `frontend-modern/src/pages/__tests__/Operations.helpers.test.ts`
59. `frontend-modern/src/components/Settings/NetworkDiscoverySection.tsx`
60. `frontend-modern/src/components/Settings/NetworkBoundarySettingsSection.tsx`
@@ -770,6 +775,18 @@ arrow-delimited label presentation used across AI, Patrol, Storage/Recovery,
and other feature surfaces. Feature contracts may depend on that helper, but
they should not re-home or fork those generic text-formatting rules into
feature-local utilities.
That same shared presentation boundary now also owns operator feedback and
shared table-label semantics. `frontend-modern/src/components/Toast/Toast.tsx`
stays the render shell for the global toast stack,
`frontend-modern/src/utils/toast.ts` owns the app-level trigger helper,
`frontend-modern/src/utils/semanticTonePresentation.ts` owns canonical toast
and diagnostics tone classes, `frontend-modern/src/utils/emptyStatePresentation.ts`
owns the shared empty-state tone styling consumed by `EmptyState`, and
`frontend-modern/src/utils/typeColumnPresentation.ts` owns the single
canonical type-column label used across dashboard and alert tables. Future
feedback, empty-state, or shared type-column work should extend those helpers
instead of reintroducing panel-local tone classes, app-local toast wiring, or
copy drift between tables.
First-session educational surfaces must also stay brief, flat, and model-led.
When Pulse needs to teach a user how a flow works, the primary on-screen
guidance should collapse to a few short descriptions of the real product
@@ -2347,6 +2347,7 @@
"frontend-modern/src/components/Settings/useSystemLogsPanelState.ts",
"frontend-modern/src/components/SetupWizard/SetupCompletionPreview.tsx",
"frontend-modern/src/components/SetupWizard/SetupWizard.tsx",
"frontend-modern/src/components/Toast/Toast.tsx",
"frontend-modern/src/features/dashboardOverview/ActionRequiredPanel.tsx",
"frontend-modern/src/features/dashboardOverview/DashboardCustomizer.tsx",
"frontend-modern/src/features/dashboardOverview/index.ts",
@@ -2363,15 +2364,19 @@
"frontend-modern/src/utils/dashboardTrendPresentation.ts",
"frontend-modern/src/utils/diagnosticsPresentation.ts",
"frontend-modern/src/utils/discoveryPresentation.ts",
"frontend-modern/src/utils/emptyStatePresentation.ts",
"frontend-modern/src/utils/problemResourcePresentation.ts",
"frontend-modern/src/utils/reportableResourceTypes.ts",
"frontend-modern/src/utils/reportingPresentation.ts",
"frontend-modern/src/utils/reportingResourceTypes.ts",
"frontend-modern/src/utils/semanticTonePresentation.ts",
"frontend-modern/src/utils/settingsShellPresentation.ts",
"frontend-modern/src/utils/ssoProviderPresentation.ts",
"frontend-modern/src/utils/systemLogsPresentation.ts",
"frontend-modern/src/utils/systemSettingsPresentation.ts",
"frontend-modern/src/utils/textPresentation.ts",
"frontend-modern/src/utils/toast.ts",
"frontend-modern/src/utils/typeColumnPresentation.ts",
"frontend-modern/src/utils/updatesPresentation.ts"
],
"verification": {
@@ -2525,6 +2530,27 @@
"frontend-modern/src/utils/__tests__/dashboardTrendPresentation.test.ts"
]
},
{
"id": "shared-feedback-and-column-presentation",
"label": "shared feedback and column presentation proof",
"match_prefixes": [],
"match_files": [
"frontend-modern/src/components/Toast/Toast.tsx",
"frontend-modern/src/utils/emptyStatePresentation.ts",
"frontend-modern/src/utils/semanticTonePresentation.ts",
"frontend-modern/src/utils/toast.ts",
"frontend-modern/src/utils/typeColumnPresentation.ts"
],
"allow_same_subsystem_tests": false,
"test_prefixes": [],
"exact_files": [
"frontend-modern/src/components/shared/TypeColumn.guardrails.test.ts",
"frontend-modern/src/components/Toast/__tests__/Toast.test.tsx",
"frontend-modern/src/utils/__tests__/emptyStatePresentation.test.ts",
"frontend-modern/src/utils/__tests__/semanticTonePresentation.test.ts",
"frontend-modern/src/utils/__tests__/typeColumnPresentation.test.ts"
]
},
{
"id": "ai-settings-presentation-helper",
"label": "AI settings presentation helper proof",
@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vitest';
import guestRowSource from '@/components/Dashboard/GuestRow.tsx?raw';
import guestRowModelSource from '@/components/Dashboard/guestRowModel.tsx?raw';
import recoverySource from '@/components/Recovery/Recovery.tsx?raw';
import responsiveSource from '@/types/responsive.ts?raw';
import typeColumnDefinitionSource from '@/utils/typeColumnDefinition.ts?raw';
@@ -60,10 +60,10 @@ describe('type column guardrails', () => {
});
it('routes runtime Type columns through the shared helper', () => {
expect(guestRowSource).toContain('createVisibleCanonicalTypeColumn()');
expect(guestRowSource).not.toContain('createCanonicalTypeColumn');
expect(guestRowSource).not.toMatch(INLINE_TYPE_COLUMN_PATTERN);
expect(guestRowSource).not.toContain("defaultVisibility:");
expect(guestRowModelSource).toContain('createVisibleCanonicalTypeColumn()');
expect(guestRowModelSource).not.toContain('createCanonicalTypeColumn');
expect(guestRowModelSource).not.toMatch(INLINE_TYPE_COLUMN_PATTERN);
expect(guestRowModelSource).not.toContain("defaultVisibility:");
expect(recoverySource).toContain('createHiddenCanonicalTypeColumn()');
expect(recoverySource).not.toContain('createCanonicalTypeColumn');
@@ -92,7 +92,7 @@ describe('type column guardrails', () => {
.sort();
expect(typeColumnUsers).toEqual([
'../Dashboard/GuestRow.tsx',
'../Dashboard/guestRowModel.tsx',
'../Recovery/Recovery.tsx',
]);
@@ -127,7 +127,7 @@ describe('type column guardrails', () => {
.sort();
expect(directHelperImportUsers).toEqual([
'../Dashboard/GuestRow.tsx',
'../Dashboard/guestRowModel.tsx',
'../Recovery/Recovery.tsx',
]);
});
@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vitest';
import alertsHistoryTabSource from '@/features/alerts/tabs/HistoryTab.tsx?raw';
import alertHistoryTableSectionSource from '@/features/alerts/AlertHistoryTableSection.tsx?raw';
import problemResourcesTableSource from '@/features/dashboardOverview/ProblemResourcesTable.tsx?raw';
import { TYPE_COLUMN_LABEL } from '@/utils/typeColumnContract';
import { getTypeColumnLabel } from '@/utils/typeColumnPresentation';
@@ -17,7 +17,7 @@ describe('typeColumnPresentation', () => {
it('keeps fixed runtime Type headers on the shared label utility', () => {
expect(problemResourcesTableSource).toContain('getTypeColumnLabel()');
expect(alertsHistoryTabSource).toContain('getTypeColumnLabel()');
expect(alertHistoryTableSectionSource).toContain('getTypeColumnLabel()');
});
it('limits runtime Type header label helper imports to the known allowlist', () => {
@@ -33,7 +33,7 @@ describe('typeColumnPresentation', () => {
.sort();
expect(directTypeLabelHelperUsers).toEqual([
'../../features/alerts/tabs/HistoryTab.tsx',
'../../features/alerts/AlertHistoryTableSection.tsx',
'../../features/dashboardOverview/ProblemResourcesTable.tsx',
]);
});