mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 13:52:20 +00:00
fix: close four small gaps around the record surface
The privacy dashboard re-implemented the audit-retention resolver with its own default and its own floor. Two implementations of one disclosure, quoted to the same person on two pages and by the purge job; it uses the shared resolver now. The record-content branch in the settings gate matched a classification rather than a page, so a second manage-writable destination would have rendered the allergy and family-history managers under its own heading without anybody choosing that. It resolves through a slug map, and the contract test fails if the map and the classification disagree in either direction — a destination cannot join the kind without somebody deciding what it renders. The managed-profile nav filter assumed a guardian grant is always manage. It is today, which is why the check was easy to leave out; an entry below that level would have listed destinations the gate refuses. Interpolation used a replacement string, and String.replace reads $&, $`, $', $1 and $$ out of one. A display name containing $' rewrote the sentence around it — and display names land in exactly the sentences that say who did what in somebody's health record. A replacer function has no $ grammar at all, which removes the class rather than escaping the members of it somebody thought of.
This commit is contained in:
1 parent
5de488c35c
commit
6ae0cc993f
9 files changed
+272
-14
No files matched your search
@@ -151,6 +151,21 @@ describe("managed record navigation", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("offers a managed entry below MANAGE nothing at all", () => {
|
||||
// A guardian grant is always MANAGE today, which is exactly why the level
|
||||
// check was easy to leave out of the managed branch. Without it a managed
|
||||
// entry that ever arrived below MANAGE would list destinations the section
|
||||
// gate refuses, sending somebody to a page that explains it cannot open.
|
||||
recordRef.value = { kind: "managed", level: "read" };
|
||||
const html = renderSettings();
|
||||
|
||||
for (const section of SETTINGS_SECTIONS) {
|
||||
expect(html, section.slug).not.toContain(
|
||||
`href="/settings/${section.slug}"`,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it("keeps the exit control present while administering a managed record", () => {
|
||||
recordRef.value = { kind: "managed", level: "manage" };
|
||||
const html = renderToStaticMarkup(
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
isManageDelegateSettingsDestination,
|
||||
SETTINGS_DESTINATION_INVENTORY,
|
||||
} from "@/lib/record-settings/classification";
|
||||
import { RECORD_CONTENT_SECTIONS } from "@/components/settings/record-settings-section-gate";
|
||||
import { toRecordSettingsDto } from "@/lib/record-settings/dto";
|
||||
import { resolveManagedIntegrationState } from "@/lib/record-settings/integrations";
|
||||
import { assertRecordSettingsResponseForRecord } from "@/lib/record-settings/response";
|
||||
@@ -114,6 +115,23 @@ describe("record settings contract", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("gives every record-content destination a page of its own", () => {
|
||||
// Both directions, and the first is the one that matters. `manage-writable`
|
||||
// is a classification; the gate has to know which PAGE each slug is, or a
|
||||
// destination added to the kind would silently inherit the allergy and
|
||||
// family-history managers under its own heading. The map is what says
|
||||
// which, and this is what stops the two drifting apart — a new
|
||||
// manage-writable slug fails here, at the moment it is added, rather than
|
||||
// rendering somebody else's forms.
|
||||
const classified = Object.keys(SETTINGS_DESTINATION_INVENTORY)
|
||||
.filter(isManageDelegateSettingsDestination)
|
||||
.sort();
|
||||
const rendered = Object.keys(RECORD_CONTENT_SECTIONS).sort();
|
||||
|
||||
expect(classified).not.toHaveLength(0);
|
||||
expect(rendered).toEqual(classified);
|
||||
});
|
||||
|
||||
it("leaves exactly one destination on the manage-writable list", () => {
|
||||
// The list is short on purpose and a second entry is a consent decision,
|
||||
// not a classification tidy-up. Pinning the count means a destination
|
||||
|
||||
Reference in new issue
Block a user