feat: show managed integration status

- Render a record-keyed status view for managed profiles\n- Refuse shared Settings links before actor controls mount\n- Localize intentional unavailable states
This commit is contained in:
Marc-André Bombeck committed 2026-08-06 02:38:54 +02:00
1 parent 54cd3e3959
commit 03ee01ba56
17 files changed
+343 -32

No files matched your search

@@ -10,6 +10,7 @@ import {
SETTINGS_DESTINATION_INVENTORY,
} from "@/lib/record-settings/classification";
import { toRecordSettingsDto } from "@/lib/record-settings/dto";
import { resolveManagedIntegrationState } from "@/lib/record-settings/integrations";
import { recordSettingsKeys } from "@/lib/query-keys";
describe("record settings contract", () => {
@@ -36,6 +37,11 @@ describe("record settings contract", () => {
"record-1",
"detail",
]);
expect(recordSettingsKeys.recordSettingsIntegrations("record-1")).toEqual([
"record-settings",
"record-1",
"integrations",
]);
});
it("does not let an adult MANAGE grant use Guardian-only configuration", () => {
@@ -66,4 +72,28 @@ describe("record settings contract", () => {
expect(isGuardianSettingsWriteAllowed("integrations")).toBe(false);
expect(isGuardianSettingsWriteAllowed("ai")).toBe(false);
});
it("does not report a synthetic ledger row as a managed connection", () => {
const connected = {
withings: false,
whoop: false,
fitbit: false,
nightscout: false,
polar: false,
oura: false,
"google-health": false,
strava: false,
} as const;
expect(
resolveManagedIntegrationState("connected", connected, "withings"),
).toBe("disconnected");
expect(
resolveManagedIntegrationState(
"error_reauth",
{ ...connected, oura: true },
"oura",
),
).toBe("error_reauth");
});
});
+23 -8
View File
@@ -6,19 +6,34 @@ import { describe, expect, it } from "vitest";
const fromRoot = (...segments: string[]) => resolve(process.cwd(), ...segments);
describe("managed record settings UI", () => {
it("renders integration status without connection controls", async () => {
const [statusView, settingsPage] = await Promise.all([
readFile(
fromRoot("src/components/settings/managed-integration-status.tsx"),
"utf8",
),
readFile(fromRoot("src/app/settings/[section]/page.tsx"), "utf8"),
]);
it("gates shared deep links and renders integration status without controls", async () => {
const [statusView, settingsPage, sectionGate, ...localeBundles] =
await Promise.all([
readFile(
fromRoot("src/components/settings/managed-integration-status.tsx"),
"utf8",
),
readFile(fromRoot("src/app/settings/[section]/page.tsx"), "utf8"),
readFile(
fromRoot("src/components/settings/record-settings-section-gate.tsx"),
"utf8",
),
...["de", "en", "es", "fr", "it", "pl"].map((locale) =>
readFile(fromRoot(`messages/${locale}.json`), "utf8"),
),
]);
expect(statusView).toContain("recordSettingsIntegrations");
expect(statusView).toContain("/api/record-settings/integrations");
expect(statusView).not.toContain("<Button");
expect(statusView).not.toContain("<Link");
expect(settingsPage).toContain("RecordSettingsSectionGate");
expect(sectionGate).toContain("if (!inSharedRecord) return children");
expect(sectionGate).toContain("ManagedIntegrationStatus");
for (const bundle of localeBundles) {
expect(bundle).toContain('"sharedRecord"');
expect(bundle).toContain('"unavailableTitle"');
expect(bundle).toContain('"integrationStatusDescription"');
}
});
});