import type { ModuleManifest, WidgetContext } from "../_core/module"; import { z } from "zod"; import { listLists, listWidgetItems, searchItems, searchLists } from "./server/queries"; import { canShareList, loadListForShare, type ListShareData } from "./server/share-queries"; import { ListSharedView } from "./components/shared-view"; import { ListWidget } from "./components/list-widget"; const listIdsSchema = z.union([z.literal("all"), z.array(z.string().uuid())]); const listWidgetConfigSchema = z.object({ listIds: listIdsSchema, showCompleted: z.boolean(), limit: z.number().int().min(1).max(50).optional(), }); async function ListWidgetServer({ config }: { config: unknown; ctx: WidgetContext }) { const parsed = listWidgetConfigSchema.parse(config); const items = await listWidgetItems({ listIds: parsed.listIds, showCompleted: parsed.showCompleted, limit: parsed.limit ?? 10, }); return ; } const manifest: ModuleManifest = { id: "lists", name: "Lists", nav: { href: "/lists", label: "Lists", icon: "list" }, entities: [ { type: "lists.list", label: { singular: "List", plural: "Lists" }, share: { canShare: true, defaultCapabilities: ["read", "write"] }, search: { search: searchLists }, resolveUrl: (id) => `/lists/${id}`, canShareEntity: canShareList, loadForShare: loadListForShare, renderSharedView: ({ data, capabilities, token }) => ( ), renderActivity: (entry) => { const name = entry.payload?.name as string | undefined; if (entry.action === "create") return `Created list${name ? ` "${name}"` : ""}`; if (entry.action === "archive") return `Archived list${name ? ` "${name}"` : ""}`; if (entry.action === "delete") return "Deleted list"; return `Updated list${name ? ` "${name}"` : ""}`; }, }, { type: "lists.item", label: { singular: "List item", plural: "List items" }, share: { canShare: false }, search: { search: searchItems }, resolveUrl: (id) => `/lists/items/${id}`, renderActivity: (entry) => { const text = entry.payload?.text as string | undefined; if (entry.action === "create") return `Added${text ? ` "${text}"` : " item"}`; if (entry.action === "delete") return `Removed${text ? ` "${text}"` : " item"}`; if (entry.action === "toggle") { const done = entry.payload?.done as boolean | undefined; const label = text ? ` "${text}"` : " item"; return done ? `Checked off${label}` : `Unchecked${label}`; } return `Updated${text ? ` "${text}"` : " item"}`; }, }, ], dashboardWidgets: [ { id: "lists.list", title: "List items", description: "Open or completed items from selected lists.", category: "Lists", defaultSize: { w: 4, h: 3 }, minSize: { w: 3, h: 2 }, defaultPriority: 30, configSchema: listWidgetConfigSchema, defaultConfig: { listIds: "all", showCompleted: false }, resolveConfigOptions: async () => ({ lists: (await listLists()).map((list) => ({ id: list.id, type: list.type, name: list.name, })), }), render: (props) => , }, ], quickAdds: [ { id: "lists.add-shopping", label: "Add to shopping", icon: "shopping-cart", url: "/lists", }, { id: "lists.add-task", label: "Add to tasks", icon: "list-checks", url: "/lists", }, { id: "lists.new-list", label: "New list", icon: "list-plus", url: "/lists", }, ], }; export default manifest;