fix(housekeeping): serialize workspace client props
This commit is contained in:
1 parent
8a31556d51
commit
cb77b2d3b9
7 files changed
+59
-15
No files matched your search
@@ -3,7 +3,6 @@
|
||||
import type {
|
||||
HousekeepingRouteDefinition,
|
||||
HousekeepingSurface,
|
||||
HousekeepingWidgetDefinition,
|
||||
} from "../../../foundation/contracts";
|
||||
import type { HousekeepingPreferences } from "../../../foundation/preferences/schema";
|
||||
import type { HousekeepingWidgetLoadResult } from "../../../foundation/registry";
|
||||
@@ -13,6 +12,7 @@ import {
|
||||
type HousekeepingPreferenceSaver,
|
||||
WidgetSettings,
|
||||
} from "../../../foundation/shell/widget-settings";
|
||||
import type { OperationsWidgetOption } from "../personalization-model";
|
||||
|
||||
export interface OperationsPersonalizationLabels {
|
||||
readonly favorites: {
|
||||
@@ -55,7 +55,7 @@ export function OperationsPersonalization({
|
||||
}: {
|
||||
readonly preferences: HousekeepingPreferences;
|
||||
readonly routes: readonly HousekeepingRouteDefinition[];
|
||||
readonly widgets: readonly HousekeepingWidgetDefinition[];
|
||||
readonly widgets: readonly OperationsWidgetOption[];
|
||||
readonly widgetResult: HousekeepingWidgetLoadResult;
|
||||
readonly surface: HousekeepingSurface;
|
||||
readonly labels: OperationsPersonalizationLabels;
|
||||
|
||||
@@ -4,10 +4,10 @@ import { PERMS } from "@/lib/permission-slugs";
|
||||
import {
|
||||
anyCapability,
|
||||
type HousekeepingRouteDefinition,
|
||||
type HousekeepingWidgetDefinition,
|
||||
ok,
|
||||
} from "../../../foundation/contracts";
|
||||
import { defaultHousekeepingPreferences } from "../../../foundation/preferences/schema";
|
||||
import type { OperationsWidgetOption } from "../personalization-model";
|
||||
import type { OperationsWorkspaceLoadResult } from "../queries";
|
||||
import { OperationsWorkspacePage } from "./workspace";
|
||||
|
||||
@@ -20,13 +20,10 @@ const routes: readonly HousekeepingRouteDefinition[] = [
|
||||
capability,
|
||||
},
|
||||
];
|
||||
const widgets: readonly HousekeepingWidgetDefinition[] = [
|
||||
const widgets: readonly OperationsWidgetOption[] = [
|
||||
{
|
||||
id: "people.queue",
|
||||
owner: "people",
|
||||
capability,
|
||||
kind: "mandatory",
|
||||
load: async () => ok({}, "widget"),
|
||||
},
|
||||
];
|
||||
const preferences = {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import type {
|
||||
HousekeepingRouteDefinition,
|
||||
HousekeepingSurface,
|
||||
HousekeepingWidgetDefinition,
|
||||
} from "../../../foundation/contracts";
|
||||
import { HousekeepingPageShell } from "../../../foundation/page/housekeeping-page-shell";
|
||||
import { OperationalInbox } from "../../../foundation/shell/operational-inbox";
|
||||
import { RecentWork } from "../../../foundation/shell/recent-work";
|
||||
import type { HousekeepingPreferenceSaver } from "../../../foundation/shell/widget-settings";
|
||||
import type { OperationsWidgetOption } from "../personalization-model";
|
||||
import type { OperationsWorkspaceLoadResult } from "../queries";
|
||||
import {
|
||||
OperationsPersonalization,
|
||||
@@ -50,7 +50,7 @@ export function OperationsWorkspacePage({
|
||||
}: {
|
||||
readonly result: OperationsWorkspaceLoadResult;
|
||||
readonly routes: readonly HousekeepingRouteDefinition[];
|
||||
readonly widgetDefinitions: readonly HousekeepingWidgetDefinition[];
|
||||
readonly widgetDefinitions: readonly OperationsWidgetOption[];
|
||||
readonly surface: HousekeepingSurface;
|
||||
readonly labels: OperationsWorkspaceLabels;
|
||||
readonly routeTitles: Readonly<Record<string, string>>;
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
anyCapability,
|
||||
type HousekeepingWidgetDefinition,
|
||||
ok,
|
||||
} from "../../foundation/contracts";
|
||||
import { toOperationsWidgetOptions } from "./personalization-model";
|
||||
|
||||
describe("toOperationsWidgetOptions", () => {
|
||||
it("projects provider definitions to a serializable client view model", () => {
|
||||
const load = vi.fn(async () => ok({ count: 1 }, "widget"));
|
||||
const definitions: readonly HousekeepingWidgetDefinition[] = [
|
||||
{
|
||||
id: "people.queue",
|
||||
owner: "people",
|
||||
capability: anyCapability("admin.users.view"),
|
||||
kind: "mandatory",
|
||||
load,
|
||||
},
|
||||
];
|
||||
|
||||
const options = toOperationsWidgetOptions(definitions);
|
||||
|
||||
expect(options).toEqual([{ id: "people.queue", kind: "mandatory" }]);
|
||||
expect(structuredClone(options)).toEqual(options);
|
||||
expect(options[0]).not.toHaveProperty("load");
|
||||
expect(load).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
import type {
|
||||
HousekeepingWidgetDefinition,
|
||||
HousekeepingWidgetKind,
|
||||
} from "../../foundation/contracts";
|
||||
|
||||
export interface OperationsWidgetOption {
|
||||
readonly id: string;
|
||||
readonly kind: HousekeepingWidgetKind;
|
||||
}
|
||||
|
||||
export function toOperationsWidgetOptions(
|
||||
definitions: readonly HousekeepingWidgetDefinition[],
|
||||
): readonly OperationsWidgetOption[] {
|
||||
return definitions.map(({ id, kind }) => ({ id, kind }));
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
type OperationsWorkspaceLabels,
|
||||
OperationsWorkspacePage,
|
||||
} from "./pages/workspace";
|
||||
import { toOperationsWidgetOptions } from "./personalization-model";
|
||||
import { operationsWorkspaceQuery } from "./queries";
|
||||
|
||||
export async function renderOperationsWorkspacePage(
|
||||
@@ -138,7 +139,7 @@ export async function renderOperationsWorkspacePage(
|
||||
return createElement(OperationsWorkspacePage, {
|
||||
result: workspaceResult,
|
||||
routes,
|
||||
widgetDefinitions,
|
||||
widgetDefinitions: toOperationsWidgetOptions(widgetDefinitions),
|
||||
surface: input.surface ?? "preview",
|
||||
labels,
|
||||
routeTitles,
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import type {
|
||||
HousekeepingResult,
|
||||
HousekeepingWidgetDefinition,
|
||||
} from "../contracts";
|
||||
import type { HousekeepingResult, HousekeepingWidgetKind } from "../contracts";
|
||||
import type { HousekeepingPreferences } from "../preferences/schema";
|
||||
|
||||
export type HousekeepingPreferenceSaver = (
|
||||
@@ -44,6 +41,11 @@ export interface WidgetSettingsLabels {
|
||||
readonly error: string;
|
||||
}
|
||||
|
||||
export interface HousekeepingWidgetOption {
|
||||
readonly id: string;
|
||||
readonly kind: HousekeepingWidgetKind;
|
||||
}
|
||||
|
||||
export function WidgetSettings({
|
||||
preferences: initialPreferences,
|
||||
widgets,
|
||||
@@ -52,7 +54,7 @@ export function WidgetSettings({
|
||||
titles = {},
|
||||
}: {
|
||||
readonly preferences: HousekeepingPreferences;
|
||||
readonly widgets: readonly HousekeepingWidgetDefinition[];
|
||||
readonly widgets: readonly HousekeepingWidgetOption[];
|
||||
readonly savePreferences: HousekeepingPreferenceSaver;
|
||||
readonly labels: WidgetSettingsLabels;
|
||||
readonly titles?: Readonly<Record<string, string>>;
|
||||
|
||||
Reference in new issue
Block a user