import { useQuery } from '@tanstack/react-query'; import { VS_NFD_PROFILE, describeCompliance, isVsNfdCompliant, type VsNfdMode, type VsNfdProfileView, } from '@dorfteich/shared'; import { useTranslation } from 'react-i18next'; import { apiGet } from '../lib/api'; /** * VS-NfD profile marking (issue #244, ADR 0027): in mode `marked`, every * catalog-listed control shows an accessible deviation marking. The check * runs against the CURRENT control value (saved or not), so the operator * is warned at the point of choice. Admin-only surfaces — the endpoint is * Site-Admin-guarded, matching every caller. */ export function useVsNfdMarking(): { mode: VsNfdMode; view: VsNfdProfileView | undefined; /** Translated marking text for a violating value, else undefined. */ markingFor: (key: string, value: unknown) => string | undefined; /** True when the control must not be rendered (#245): mode hidden/ * enforced and the SAVED value is compliant. */ hides: (key: string, savedValue: unknown) => boolean; } { const { t } = useTranslation('settings'); const query = useQuery({ queryKey: ['admin', 'vs-nfd-profile'], queryFn: () => apiGet('/admin/system/vs-nfd-profile'), staleTime: 60_000, }); const mode = query.data?.mode ?? 'off'; return { mode, view: query.data, markingFor(key, value) { // Marking applies in `marked`, and in `hidden`/`enforced` to values // that are ALREADY violating — an existing violation is never // silently hidden (#245). if (mode === 'off') return undefined; const entry = VS_NFD_PROFILE.find((e) => e.scope === 'instance' && e.key === key); if (!entry || isVsNfdCompliant(entry, value)) return undefined; return t('admin.vsNfd.marking', { value: describeCompliance(entry.compliance) }); }, hides(key, savedValue) { // The `hidden` treatment (#245, `enforced` renders the same, #246): // a compliant control whose only purpose would be enabling a // violation disappears; a violating one stays visible WITH its // marking so the deviation is surfaced, never buried. if (mode !== 'hidden' && mode !== 'enforced') return false; const entry = VS_NFD_PROFILE.find((e) => e.scope === 'instance' && e.key === key); return entry !== undefined && isVsNfdCompliant(entry, savedValue); }, }; } /** * The one accessible per-section note that options are hidden by * deployment policy (#245) — policy must be distinguishable from missing * features for anyone reading the settings page. */ export function VsNfdHiddenNote(): React.JSX.Element { const { t } = useTranslation('settings'); return (

{t('admin.vsNfd.hiddenNote')}

); } /** * The marking element for controls not wrapped in (checkbox rows): * icon + text, colour never alone; wire `id` into the control's * aria-describedby so screen readers announce it with the control. */ export function VsNfdMark({ id, text }: { id?: string; text: string }): React.JSX.Element { return ( {text} ); }