diff --git a/docs/CONTEXTUAL_HELP_CONTRACT.md b/docs/CONTEXTUAL_HELP_CONTRACT.md index b8ba7c5..fce7e99 100644 --- a/docs/CONTEXTUAL_HELP_CONTRACT.md +++ b/docs/CONTEXTUAL_HELP_CONTRACT.md @@ -52,6 +52,8 @@ than adding custom `F1` listeners: - translated label keys provide deterministic field identities for ordinary `FormField`, `ToggleSwitch`, search, date/time, email, button, dialog, and card controls. +- `TableActionGroup` action definitions carry the same identities so focused + row actions can resolve consequence-specific help. Module routes, public routes, settings sections, and administration sections may also declare `helpContextId` and `helpTopicId`. Each module must keep a diff --git a/docs/LOCALIZATION_AND_HELP_QUALITY.md b/docs/LOCALIZATION_AND_HELP_QUALITY.md index 0ba6015..bfe683a 100644 --- a/docs/LOCALIZATION_AND_HELP_QUALITY.md +++ b/docs/LOCALIZATION_AND_HELP_QUALITY.md @@ -42,6 +42,12 @@ Shared controls may set `helpModuleId` when their documentation owner differs from the containing page; the retention editor uses this to resolve Policy help from both administration and Campaign surfaces. +The shared reusable-credential manager keeps Access as its documentation owner +and publishes exact contexts for credential kind, secret replacement/removal, +module and server restrictions, lower-scope visibility, activation, save, and +irreversible deletion. This ensures F1 explains secret custody and the effect on +dependent connections from system, tenant, group, user, and personal surfaces. + The generated `help_review_candidates` list is therefore a content-depth queue, not a list of controls on which F1 cannot work. It should prioritize: diff --git a/webui/scripts/test-core-interface-patterns.mjs b/webui/scripts/test-core-interface-patterns.mjs index 4fb8822..178d360 100644 --- a/webui/scripts/test-core-interface-patterns.mjs +++ b/webui/scripts/test-core-interface-patterns.mjs @@ -36,6 +36,10 @@ assert.match(confirmDialog, /helpContextId=\{helpContextId\}/, "confirm dialogs assert.match(credentials, / {targetOptions.length > 0 && ( - + setDraft({ ...draft, name: event.target.value })} autoFocus /> + + setDraft({ ...draft, name: event.target.value })} autoFocus /> - - setDraft({ ...draft, credentialKind: event.target.value as CredentialKind, secret: "", clearSecret: false })}> - - setDraft({ ...draft, description: event.target.value })} /> + + setDraft({ ...draft, description: event.target.value })} /> - - setDraft({ ...draft, username: event.target.value })} /> + + setDraft({ ...draft, username: event.target.value })} /> - setDraft({ ...draft, secret, clearSecret: false })} disabled={saving} autoComplete="new-password" generator /> + setDraft({ ...draft, secret, clearSecret: false })} disabled={saving} autoComplete="new-password" generator /> {editing !== "new" && ( setDraft({ ...draft, clearSecret })} label="Remove configured secret" /> @@ -552,7 +571,7 @@ export default function CredentialEnvelopeManager({

Empty module or server lists mean every module or server allowed by scope.

- + setDraft({ ...draft, allowedModules: values.join(", ") })} @@ -562,7 +581,7 @@ export default function CredentialEnvelopeManager({ disabled={saving} /> - + setDraft({ ...draft, allowedServerRefs: values.join(", ") })} @@ -573,8 +592,8 @@ export default function CredentialEnvelopeManager({ disabled={saving} /> - setDraft({ ...draft, inheritToLowerScopes })} label="Visible to lower scopes" /> - setDraft({ ...draft, isActive })} label="Active" /> + setDraft({ ...draft, inheritToLowerScopes })} label="Visible to lower scopes" /> + setDraft({ ...draft, isActive })} label="Active" />
@@ -582,6 +601,8 @@ export default function CredentialEnvelopeManager({ I, onClick: noop }, + { id: "inspect", label: "Inspect", icon: I, helpContextId: "test.row.inspect", helpModuleId: "test-module", onClick: noop }, { id: "edit", label: "Edit", icon: E, applicable: false, onClick: noop }, { id: "remove", label: "Remove", icon: R, disabledReason: "Permission denied", onClick: noop } ]} @@ -51,6 +51,8 @@ assertEqual((contextActions.match(/table-action-placeholder/g) ?? []).length, 1, assertEqual(contextActions.includes("disabled-action-tooltip"), true, "disabled table actions can explain their unavailable state"); assertEqual(contextActions.includes('aria-label="Inspect"'), true, "table actions expose an accessible label"); assertEqual(contextActions.includes('title="Inspect"'), true, "table actions expose a native tooltip"); +assertEqual(contextActions.includes('data-help-context-id="test.row.inspect"'), true, "table actions propagate exact contextual help"); +assertEqual(contextActions.includes('data-help-module-id="test-module"'), true, "table actions propagate the documentation owner"); assertEqual(contextActions.includes('aria-hidden="true"'), true, "table action icons stay decorative"); let propagationStopped = false;