@consciousclouds/operator-shell 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +36 -0
- package/LICENSE +194 -0
- package/README.md +319 -0
- package/dist/chief/ChiefDrawer.d.ts +11 -0
- package/dist/chief/ChiefDrawer.d.ts.map +1 -0
- package/dist/chief/ChiefDrawer.js +49 -0
- package/dist/chief/ChiefDrawer.js.map +1 -0
- package/dist/chief/ChiefPanel.d.ts +10 -0
- package/dist/chief/ChiefPanel.d.ts.map +1 -0
- package/dist/chief/ChiefPanel.js +46 -0
- package/dist/chief/ChiefPanel.js.map +1 -0
- package/dist/chief/ChiefRegion.d.ts +9 -0
- package/dist/chief/ChiefRegion.d.ts.map +1 -0
- package/dist/chief/ChiefRegion.js +55 -0
- package/dist/chief/ChiefRegion.js.map +1 -0
- package/dist/chief/ChiefSession.d.ts +21 -0
- package/dist/chief/ChiefSession.d.ts.map +1 -0
- package/dist/chief/ChiefSession.js +9 -0
- package/dist/chief/ChiefSession.js.map +1 -0
- package/dist/chief/directive.d.ts +15 -0
- package/dist/chief/directive.d.ts.map +1 -0
- package/dist/chief/directive.js +20 -0
- package/dist/chief/directive.js.map +1 -0
- package/dist/chief/turn-adapter.d.ts +52 -0
- package/dist/chief/turn-adapter.d.ts.map +1 -0
- package/dist/chief/turn-adapter.js +23 -0
- package/dist/chief/turn-adapter.js.map +1 -0
- package/dist/chief/use-chief-shortcut.d.ts +17 -0
- package/dist/chief/use-chief-shortcut.d.ts.map +1 -0
- package/dist/chief/use-chief-shortcut.js +61 -0
- package/dist/chief/use-chief-shortcut.js.map +1 -0
- package/dist/chief/use-chief-turn.d.ts +50 -0
- package/dist/chief/use-chief-turn.d.ts.map +1 -0
- package/dist/chief/use-chief-turn.js +99 -0
- package/dist/chief/use-chief-turn.js.map +1 -0
- package/dist/flavor/types.d.ts +189 -0
- package/dist/flavor/types.d.ts.map +1 -0
- package/dist/flavor/types.js +13 -0
- package/dist/flavor/types.js.map +1 -0
- package/dist/frame/OperatorShell.d.ts +91 -0
- package/dist/frame/OperatorShell.d.ts.map +1 -0
- package/dist/frame/OperatorShell.js +54 -0
- package/dist/frame/OperatorShell.js.map +1 -0
- package/dist/guard/PermissionProvider.d.ts +49 -0
- package/dist/guard/PermissionProvider.d.ts.map +1 -0
- package/dist/guard/PermissionProvider.js +103 -0
- package/dist/guard/PermissionProvider.js.map +1 -0
- package/dist/guard/RouteGuard.d.ts +45 -0
- package/dist/guard/RouteGuard.d.ts.map +1 -0
- package/dist/guard/RouteGuard.js +59 -0
- package/dist/guard/RouteGuard.js.map +1 -0
- package/dist/guard/permissions.d.ts +88 -0
- package/dist/guard/permissions.d.ts.map +1 -0
- package/dist/guard/permissions.js +105 -0
- package/dist/guard/permissions.js.map +1 -0
- package/dist/header/EnvironmentSwitcher.d.ts +5 -0
- package/dist/header/EnvironmentSwitcher.d.ts.map +1 -0
- package/dist/header/EnvironmentSwitcher.js +51 -0
- package/dist/header/EnvironmentSwitcher.js.map +1 -0
- package/dist/header/OperatorHeader.d.ts +25 -0
- package/dist/header/OperatorHeader.d.ts.map +1 -0
- package/dist/header/OperatorHeader.js +13 -0
- package/dist/header/OperatorHeader.js.map +1 -0
- package/dist/header/OperatorProfileMenu.d.ts +2 -0
- package/dist/header/OperatorProfileMenu.d.ts.map +1 -0
- package/dist/header/OperatorProfileMenu.js +14 -0
- package/dist/header/OperatorProfileMenu.js.map +1 -0
- package/dist/header/ThemeToggle.d.ts +2 -0
- package/dist/header/ThemeToggle.d.ts.map +1 -0
- package/dist/header/ThemeToggle.js +17 -0
- package/dist/header/ThemeToggle.js.map +1 -0
- package/dist/icons/registry.d.ts +57 -0
- package/dist/icons/registry.d.ts.map +1 -0
- package/dist/icons/registry.js +83 -0
- package/dist/icons/registry.js.map +1 -0
- package/dist/index.d.ts +77 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +129 -0
- package/dist/index.js.map +1 -0
- package/dist/inspector/InspectorProvider.d.ts +41 -0
- package/dist/inspector/InspectorProvider.d.ts.map +1 -0
- package/dist/inspector/InspectorProvider.js +63 -0
- package/dist/inspector/InspectorProvider.js.map +1 -0
- package/dist/inspector/types.d.ts +91 -0
- package/dist/inspector/types.d.ts.map +1 -0
- package/dist/inspector/types.js +40 -0
- package/dist/inspector/types.js.map +1 -0
- package/dist/nav/routes.d.ts +39 -0
- package/dist/nav/routes.d.ts.map +1 -0
- package/dist/nav/routes.js +46 -0
- package/dist/nav/routes.js.map +1 -0
- package/dist/palette/CommandPalette.d.ts +40 -0
- package/dist/palette/CommandPalette.d.ts.map +1 -0
- package/dist/palette/CommandPalette.js +108 -0
- package/dist/palette/CommandPalette.js.map +1 -0
- package/dist/palette/commands.d.ts +58 -0
- package/dist/palette/commands.d.ts.map +1 -0
- package/dist/palette/commands.js +81 -0
- package/dist/palette/commands.js.map +1 -0
- package/dist/palette/search-sources.d.ts +126 -0
- package/dist/palette/search-sources.d.ts.map +1 -0
- package/dist/palette/search-sources.js +101 -0
- package/dist/palette/search-sources.js.map +1 -0
- package/dist/palette/use-search-results.d.ts +4 -0
- package/dist/palette/use-search-results.d.ts.map +1 -0
- package/dist/palette/use-search-results.js +51 -0
- package/dist/palette/use-search-results.js.map +1 -0
- package/dist/sidebar/OperatorSidebar.d.ts +44 -0
- package/dist/sidebar/OperatorSidebar.d.ts.map +1 -0
- package/dist/sidebar/OperatorSidebar.js +30 -0
- package/dist/sidebar/OperatorSidebar.js.map +1 -0
- package/dist/workspace/CanvasWorkspace.d.ts +78 -0
- package/dist/workspace/CanvasWorkspace.d.ts.map +1 -0
- package/dist/workspace/CanvasWorkspace.js +44 -0
- package/dist/workspace/CanvasWorkspace.js.map +1 -0
- package/dist/workspace/DashboardWorkspace.d.ts +91 -0
- package/dist/workspace/DashboardWorkspace.d.ts.map +1 -0
- package/dist/workspace/DashboardWorkspace.js +39 -0
- package/dist/workspace/DashboardWorkspace.js.map +1 -0
- package/dist/workspace/FormWorkspace.d.ts +107 -0
- package/dist/workspace/FormWorkspace.d.ts.map +1 -0
- package/dist/workspace/FormWorkspace.js +38 -0
- package/dist/workspace/FormWorkspace.js.map +1 -0
- package/dist/workspace/GraphWorkspace.d.ts +112 -0
- package/dist/workspace/GraphWorkspace.d.ts.map +1 -0
- package/dist/workspace/GraphWorkspace.js +147 -0
- package/dist/workspace/GraphWorkspace.js.map +1 -0
- package/dist/workspace/TableWorkspace.d.ts +74 -0
- package/dist/workspace/TableWorkspace.d.ts.map +1 -0
- package/dist/workspace/TableWorkspace.js +25 -0
- package/dist/workspace/TableWorkspace.js.map +1 -0
- package/dist/workspace/WorkspaceHost.d.ts +26 -0
- package/dist/workspace/WorkspaceHost.d.ts.map +1 -0
- package/dist/workspace/WorkspaceHost.js +21 -0
- package/dist/workspace/WorkspaceHost.js.map +1 -0
- package/dist/workspace/registry.d.ts +30 -0
- package/dist/workspace/registry.d.ts.map +1 -0
- package/dist/workspace/registry.js +33 -0
- package/dist/workspace/registry.js.map +1 -0
- package/dist/workspace/types.d.ts +79 -0
- package/dist/workspace/types.d.ts.map +1 -0
- package/dist/workspace/types.js +48 -0
- package/dist/workspace/types.js.map +1 -0
- package/package.json +64 -0
- package/styles/source.css +16 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* CommandPalette — the shell-owned ⌘K palette over the registry `command`
|
|
5
|
+
* component (@consciousclouds/ui, cmdk). The shell owns the BEHAVIOR
|
|
6
|
+
* (keybinding, open/close, filtering, execution); the Flavor owns the
|
|
7
|
+
* VOCABULARY (nav-derived route commands + inert declared references, see
|
|
8
|
+
* palette/commands.ts); the product owns the MEANING of non-route commands
|
|
9
|
+
* through the injected `runCommand` executor — the same injection pattern as
|
|
10
|
+
* icons and the permission resolver.
|
|
11
|
+
*
|
|
12
|
+
* The palette is ALSO the Search surface (the doctrine skeleton's Search
|
|
13
|
+
* experience): product-injected `searchSources` (see search-sources.ts) run
|
|
14
|
+
* against the typed text and their results render alongside the command
|
|
15
|
+
* groups, gated by the SAME fail-closed permission snapshot. An erroring,
|
|
16
|
+
* in-flight, or absent source contributes nothing. A result's action either
|
|
17
|
+
* navigates (the palette's own door) or opens the shell-owned inspector by
|
|
18
|
+
* entity kind — which keeps its own fail-closed gate (an undeclared or
|
|
19
|
+
* view-less kind refuses to open and the palette simply stays).
|
|
20
|
+
*
|
|
21
|
+
* Controlled open state: the frame holds it so the header's search button
|
|
22
|
+
* and the ⌘K keybinding open the same instance.
|
|
23
|
+
*/
|
|
24
|
+
import * as React from "react";
|
|
25
|
+
import { useRouter } from "next/navigation";
|
|
26
|
+
import { CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, } from "@consciousclouds/ui";
|
|
27
|
+
import { collectPermissionRefs } from "../guard/permissions.js";
|
|
28
|
+
import { usePermissionDecisions } from "../guard/PermissionProvider.js";
|
|
29
|
+
import { resolveIcon } from "../icons/registry.js";
|
|
30
|
+
import { useInspector } from "../inspector/InspectorProvider.js";
|
|
31
|
+
import { derivePaletteGroups } from "./commands.js";
|
|
32
|
+
import { useSearchResults } from "./use-search-results.js";
|
|
33
|
+
export function CommandPalette({ flavor, resolvePermission, icons, iconFamily, runCommand, searchSources, open, onOpenChange, placeholder = "Type a command or search…", }) {
|
|
34
|
+
const router = useRouter();
|
|
35
|
+
const inspector = useInspector();
|
|
36
|
+
// The palette text — controlled so the search sources can see it. Reset on
|
|
37
|
+
// close: the next open starts commands-only, no stale query.
|
|
38
|
+
const [query, setQuery] = React.useState("");
|
|
39
|
+
React.useEffect(() => {
|
|
40
|
+
if (!open)
|
|
41
|
+
setQuery("");
|
|
42
|
+
}, [open]);
|
|
43
|
+
// The registry ⌘K binding: meta/ctrl+K toggles, anywhere on the document.
|
|
44
|
+
React.useEffect(() => {
|
|
45
|
+
const down = (event) => {
|
|
46
|
+
if (event.key === "k" && (event.metaKey || event.ctrlKey)) {
|
|
47
|
+
event.preventDefault();
|
|
48
|
+
onOpenChange(!open);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
document.addEventListener("keydown", down);
|
|
52
|
+
return () => document.removeEventListener("keydown", down);
|
|
53
|
+
}, [open, onOpenChange]);
|
|
54
|
+
// Resolve every gated reference (nav + declared commands + search sources)
|
|
55
|
+
// through the live seam, then snapshot the decisions into the SYNC lookup
|
|
56
|
+
// the pure derivations take: allowed passes, loading/denied/absent ⇒
|
|
57
|
+
// unknown ⇒ denied (fail-closed while an async resolver is still deciding).
|
|
58
|
+
const permissionRefs = collectPermissionRefs([
|
|
59
|
+
...flavor.nav.flatMap((group) => group.items),
|
|
60
|
+
...(flavor.commands ?? []).flatMap((group) => group.items),
|
|
61
|
+
...(searchSources ?? []),
|
|
62
|
+
]);
|
|
63
|
+
const decisions = usePermissionDecisions(permissionRefs, resolvePermission);
|
|
64
|
+
const snapshotResolver = (permission) => decisions[permission] === "allowed" ? "allowed" : "unknown";
|
|
65
|
+
const groups = derivePaletteGroups(flavor, snapshotResolver, Boolean(runCommand));
|
|
66
|
+
// The Search experience: the injected sources run against the typed text
|
|
67
|
+
// under the SAME decisions snapshot; in-flight/erroring/absent sources
|
|
68
|
+
// contribute nothing (use-search-results.ts holds the fail-closed rules).
|
|
69
|
+
const searchGroups = useSearchResults(searchSources, open ? query : "", decisions);
|
|
70
|
+
const select = (action) => {
|
|
71
|
+
// Close first so navigation lands on an unobstructed surface.
|
|
72
|
+
onOpenChange(false);
|
|
73
|
+
if (action.kind === "navigate")
|
|
74
|
+
router.push(action.href);
|
|
75
|
+
else
|
|
76
|
+
runCommand?.(action.command);
|
|
77
|
+
};
|
|
78
|
+
const selectResult = (action) => {
|
|
79
|
+
if (action.kind === "navigate") {
|
|
80
|
+
onOpenChange(false);
|
|
81
|
+
router.push(action.href);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
// Inspector door: open FIRST, close only on acceptance — a fail-closed
|
|
85
|
+
// refusal (undeclared/view-less kind) leaves the palette exactly as it
|
|
86
|
+
// was (no panel, no crash, no dead-end close).
|
|
87
|
+
const opened = inspector.open({
|
|
88
|
+
kind: action.entityKind,
|
|
89
|
+
entity: action.entity,
|
|
90
|
+
title: action.title,
|
|
91
|
+
description: action.description,
|
|
92
|
+
});
|
|
93
|
+
if (opened)
|
|
94
|
+
onOpenChange(false);
|
|
95
|
+
};
|
|
96
|
+
return (_jsxs(CommandDialog, { open: open, onOpenChange: onOpenChange, title: "Command palette", description: "Search the console's destinations and commands", children: [_jsx(CommandInput, { placeholder: placeholder, value: query, onValueChange: setQuery }), _jsxs(CommandList, { children: [_jsx(CommandEmpty, { children: "No results found." }), groups.map((group) => (_jsx(CommandGroup, { heading: group.label, children: group.commands.map((command) => {
|
|
97
|
+
const Icon = command.icon ? resolveIcon(command.icon, icons, iconFamily) : null;
|
|
98
|
+
return (_jsxs(CommandItem, { value: command.label, keywords: command.keywords, onSelect: () => select(command.action), children: [Icon && _jsx(Icon, {}), _jsx("span", { children: command.label })] }, command.id));
|
|
99
|
+
}) }, group.id))), searchGroups.map((group) => (_jsx(CommandGroup, { heading: group.label, children: group.results.map((result) => {
|
|
100
|
+
const Icon = result.icon ? resolveIcon(result.icon, icons, iconFamily) : null;
|
|
101
|
+
return (_jsxs(CommandItem, { value: `${group.id}:${result.id}`,
|
|
102
|
+
// The source already matched these results against the
|
|
103
|
+
// typed text (it may match fields cmdk can't see), so pin
|
|
104
|
+
// them past cmdk's own filter by including the query.
|
|
105
|
+
keywords: [query, result.label, ...(result.keywords ?? [])], onSelect: () => selectResult(result.action), children: [Icon && _jsx(Icon, {}), _jsx("span", { children: result.label })] }, `${group.id}:${result.id}`));
|
|
106
|
+
}) }, group.id)))] })] }));
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=CommandPalette.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CommandPalette.js","sourceRoot":"","sources":["../../src/palette/CommandPalette.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The palette's pure command derivation. Commands are DECLARATIVE:
|
|
3
|
+
*
|
|
4
|
+
* - Route commands are AUTO-DERIVED from `flavor.nav` — the same tree the
|
|
5
|
+
* sidebar renders, so the palette can never disagree with navigation
|
|
6
|
+
* (no second route list anywhere, per nav/routes.ts).
|
|
7
|
+
* - `flavor.commands` adds inert reference entries (Declarative-Flavor
|
|
8
|
+
* law): `href` entries navigate; `command` entries name a reference the
|
|
9
|
+
* product's injected runner interprets — and are HIDDEN when no runner
|
|
10
|
+
* is injected (fail-closed: a reference nobody interprets cannot
|
|
11
|
+
* execute).
|
|
12
|
+
* - Every entry passes the SAME permission gate as the sidebar
|
|
13
|
+
* (isPermitted — unknown ⇒ denied, contracts §5). The palette is a
|
|
14
|
+
* second door to the console; it opens exactly as wide as the first.
|
|
15
|
+
*
|
|
16
|
+
* Pure data-in/data-out so the gating behavior is provable without a DOM.
|
|
17
|
+
*/
|
|
18
|
+
import type { OperatorFlavor } from "../flavor/types.js";
|
|
19
|
+
import type { SyncPermissionResolver } from "../guard/permissions.js";
|
|
20
|
+
/** What a selected command does. The palette executes; products never inject functions here. */
|
|
21
|
+
export type PaletteAction = {
|
|
22
|
+
kind: "navigate";
|
|
23
|
+
href: string;
|
|
24
|
+
} | {
|
|
25
|
+
kind: "run";
|
|
26
|
+
command: string;
|
|
27
|
+
};
|
|
28
|
+
/** One resolved, permitted palette entry. */
|
|
29
|
+
export interface PaletteCommand {
|
|
30
|
+
id: string;
|
|
31
|
+
label: string;
|
|
32
|
+
/** Icon NAME for the shell's icon registry (nav items always carry one). */
|
|
33
|
+
icon?: string;
|
|
34
|
+
/** Extra match terms beyond the label. */
|
|
35
|
+
keywords?: string[];
|
|
36
|
+
action: PaletteAction;
|
|
37
|
+
}
|
|
38
|
+
/** A rendered palette section. */
|
|
39
|
+
export interface PaletteGroup {
|
|
40
|
+
id: string;
|
|
41
|
+
label: string;
|
|
42
|
+
commands: PaletteCommand[];
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Derive the visible palette groups for a Flavor under a permission
|
|
46
|
+
* resolver. `hasRunner` reports whether the product injected a `runCommand`
|
|
47
|
+
* executor — without one, `command`-reference entries are dropped
|
|
48
|
+
* (fail-closed), while `href` entries remain (the shell itself can navigate).
|
|
49
|
+
*
|
|
50
|
+
* The resolver here is SYNC by design (the derivation stays pure/provable):
|
|
51
|
+
* for an async product resolver, the palette component snapshots the live
|
|
52
|
+
* decisions from usePermissionDecisions into a sync lookup — an in-flight
|
|
53
|
+
* (`loading`) decision snapshots to `unknown` ⇒ denied, so the palette is
|
|
54
|
+
* fail-closed WHILE resolving and the entry appears once allowed (a palette
|
|
55
|
+
* has no useful loading row; the sidebar carries the visible loading state).
|
|
56
|
+
*/
|
|
57
|
+
export declare function derivePaletteGroups(flavor: OperatorFlavor, resolvePermission: SyncPermissionResolver, hasRunner: boolean): PaletteGroup[];
|
|
58
|
+
//# sourceMappingURL=commands.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/palette/commands.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAGtE,gGAAgG;AAChG,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAErC,6CAA6C;AAC7C,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,EAAE,aAAa,CAAC;CACvB;AAED,kCAAkC;AAClC,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,cAAc,EAAE,CAAC;CAC5B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,cAAc,EACtB,iBAAiB,EAAE,sBAAsB,EACzC,SAAS,EAAE,OAAO,GACjB,YAAY,EAAE,CAmChB"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The palette's pure command derivation. Commands are DECLARATIVE:
|
|
3
|
+
*
|
|
4
|
+
* - Route commands are AUTO-DERIVED from `flavor.nav` — the same tree the
|
|
5
|
+
* sidebar renders, so the palette can never disagree with navigation
|
|
6
|
+
* (no second route list anywhere, per nav/routes.ts).
|
|
7
|
+
* - `flavor.commands` adds inert reference entries (Declarative-Flavor
|
|
8
|
+
* law): `href` entries navigate; `command` entries name a reference the
|
|
9
|
+
* product's injected runner interprets — and are HIDDEN when no runner
|
|
10
|
+
* is injected (fail-closed: a reference nobody interprets cannot
|
|
11
|
+
* execute).
|
|
12
|
+
* - Every entry passes the SAME permission gate as the sidebar
|
|
13
|
+
* (isPermitted — unknown ⇒ denied, contracts §5). The palette is a
|
|
14
|
+
* second door to the console; it opens exactly as wide as the first.
|
|
15
|
+
*
|
|
16
|
+
* Pure data-in/data-out so the gating behavior is provable without a DOM.
|
|
17
|
+
*/
|
|
18
|
+
import { isPermitted } from "../guard/permissions.js";
|
|
19
|
+
/**
|
|
20
|
+
* Derive the visible palette groups for a Flavor under a permission
|
|
21
|
+
* resolver. `hasRunner` reports whether the product injected a `runCommand`
|
|
22
|
+
* executor — without one, `command`-reference entries are dropped
|
|
23
|
+
* (fail-closed), while `href` entries remain (the shell itself can navigate).
|
|
24
|
+
*
|
|
25
|
+
* The resolver here is SYNC by design (the derivation stays pure/provable):
|
|
26
|
+
* for an async product resolver, the palette component snapshots the live
|
|
27
|
+
* decisions from usePermissionDecisions into a sync lookup — an in-flight
|
|
28
|
+
* (`loading`) decision snapshots to `unknown` ⇒ denied, so the palette is
|
|
29
|
+
* fail-closed WHILE resolving and the entry appears once allowed (a palette
|
|
30
|
+
* has no useful loading row; the sidebar carries the visible loading state).
|
|
31
|
+
*/
|
|
32
|
+
export function derivePaletteGroups(flavor, resolvePermission, hasRunner) {
|
|
33
|
+
const groups = [];
|
|
34
|
+
// Route commands, straight from the nav tree the sidebar renders.
|
|
35
|
+
for (const group of flavor.nav) {
|
|
36
|
+
const commands = group.items
|
|
37
|
+
.filter((item) => isPermitted(item.requiredPermission, resolvePermission))
|
|
38
|
+
.map((item) => ({
|
|
39
|
+
id: `nav:${item.id}`,
|
|
40
|
+
label: item.label,
|
|
41
|
+
icon: item.icon,
|
|
42
|
+
action: { kind: "navigate", href: item.href },
|
|
43
|
+
}));
|
|
44
|
+
if (commands.length > 0)
|
|
45
|
+
groups.push({ id: `nav:${group.id}`, label: group.label, commands });
|
|
46
|
+
}
|
|
47
|
+
// Declared commands — additive, same gate, runner-aware.
|
|
48
|
+
for (const group of flavor.commands ?? []) {
|
|
49
|
+
const commands = [];
|
|
50
|
+
for (const item of group.items) {
|
|
51
|
+
if (!isPermitted(item.requiredPermission, resolvePermission))
|
|
52
|
+
continue;
|
|
53
|
+
const action = toAction(item.href, item.command, hasRunner);
|
|
54
|
+
if (!action)
|
|
55
|
+
continue;
|
|
56
|
+
commands.push({
|
|
57
|
+
id: `cmd:${item.id}`,
|
|
58
|
+
label: item.label,
|
|
59
|
+
icon: item.icon,
|
|
60
|
+
keywords: item.keywords,
|
|
61
|
+
action,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
if (commands.length > 0)
|
|
65
|
+
groups.push({ id: `cmd:${group.id}`, label: group.label, commands });
|
|
66
|
+
}
|
|
67
|
+
return groups;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* An entry resolves to exactly one action or none: `href` wins if both are
|
|
71
|
+
* (mis)declared, a `command` reference needs an injected runner, and an
|
|
72
|
+
* entry with neither is inert misdeclaration — dropped, never guessed at.
|
|
73
|
+
*/
|
|
74
|
+
function toAction(href, command, hasRunner) {
|
|
75
|
+
if (href)
|
|
76
|
+
return { kind: "navigate", href };
|
|
77
|
+
if (command && hasRunner)
|
|
78
|
+
return { kind: "run", command };
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=commands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../../src/palette/commands.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAyBtD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,mBAAmB,CACjC,MAAsB,EACtB,iBAAyC,EACzC,SAAkB;IAElB,MAAM,MAAM,GAAmB,EAAE,CAAC;IAElC,kEAAkE;IAClE,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,GAAG,EAAE,CAAC;QAC/B,MAAM,QAAQ,GAAqB,KAAK,CAAC,KAAK;aAC3C,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,kBAAkB,EAAE,iBAAiB,CAAC,CAAC;aACzE,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACd,EAAE,EAAE,OAAO,IAAI,CAAC,EAAE,EAAE;YACpB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,MAAM,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE;SAC9C,CAAC,CAAC,CAAC;QACN,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;YAAE,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,OAAO,KAAK,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;IAChG,CAAC;IAED,yDAAyD;IACzD,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,QAAQ,IAAI,EAAE,EAAE,CAAC;QAC1C,MAAM,QAAQ,GAAqB,EAAE,CAAC;QACtC,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YAC/B,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,kBAAkB,EAAE,iBAAiB,CAAC;gBAAE,SAAS;YACvE,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;YAC5D,IAAI,CAAC,MAAM;gBAAE,SAAS;YACtB,QAAQ,CAAC,IAAI,CAAC;gBACZ,EAAE,EAAE,OAAO,IAAI,CAAC,EAAE,EAAE;gBACpB,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,MAAM;aACP,CAAC,CAAC;QACL,CAAC;QACD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;YAAE,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,OAAO,KAAK,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;IAChG,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,SAAS,QAAQ,CACf,IAAwB,EACxB,OAA2B,EAC3B,SAAkB;IAElB,IAAI,IAAI;QAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;IAC5C,IAAI,OAAO,IAAI,SAAS;QAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;IAC1D,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Search sources — the doctrine skeleton's Search experience as a typed
|
|
3
|
+
* injection seam (frontend-platform-doctrine.md, Operator Platform contract
|
|
4
|
+
* skeleton: "Search — the platform owns the search surface, invocation, and
|
|
5
|
+
* result rendering contract; the product fills WHICH sources and scopes are
|
|
6
|
+
* searchable").
|
|
7
|
+
*
|
|
8
|
+
* The split, same as every other slot:
|
|
9
|
+
* - The SHELL owns the surface — the ⌘K palette renders source results
|
|
10
|
+
* alongside its command groups and executes the selected action.
|
|
11
|
+
* - The PRODUCT injects `SearchSource` values through the shell's
|
|
12
|
+
* `searchSources` prop (the same injection pattern as icons / the
|
|
13
|
+
* permission resolver / `inspectorViews` / `runCommand`) — product code,
|
|
14
|
+
* never Flavor logic (a Flavor is inert data; `query` is a function).
|
|
15
|
+
* - A source's `query` runs on the PRODUCT'S side of the membrane (its own
|
|
16
|
+
* BFF / already-held reads). No transport, URL, or credential ever
|
|
17
|
+
* enters this package.
|
|
18
|
+
*
|
|
19
|
+
* FAIL-CLOSED, three ways (the palette dual of the inspector's refusal):
|
|
20
|
+
* - a source gated by `requiredPermission` that is not explicitly allowed
|
|
21
|
+
* under the SAME snapshot the palette's commands gate on is NEVER
|
|
22
|
+
* QUERIED (denied/unknown/in-flight resolution ⇒ zero results),
|
|
23
|
+
* - an erroring source (rejection or synchronous throw) contributes
|
|
24
|
+
* nothing — siblings are unaffected, the palette never crashes,
|
|
25
|
+
* - an in-flight source contributes nothing until it resolves (the hook
|
|
26
|
+
* in use-search-results.ts enforces this; absent sources trivially
|
|
27
|
+
* contribute nothing).
|
|
28
|
+
*
|
|
29
|
+
* A result's action is PaletteAction-shaped: `navigate` reuses the palette's
|
|
30
|
+
* href navigation; `inspect` opens the shell-owned inspector by entity KIND
|
|
31
|
+
* with an ALREADY-RESOLVED entity (the source fetched it — the inspector
|
|
32
|
+
* contract's "the opener hands it the entity" rule, and the inspector's own
|
|
33
|
+
* fail-closed gate still applies: an undeclared or view-less kind refuses).
|
|
34
|
+
*
|
|
35
|
+
* This module is PURE (no React): the contract + the query machinery,
|
|
36
|
+
* provable without a DOM. The React half lives in use-search-results.ts.
|
|
37
|
+
*/
|
|
38
|
+
import type { SyncPermissionResolver } from "../guard/permissions.js";
|
|
39
|
+
/**
|
|
40
|
+
* What selecting a search result does — PaletteAction-shaped, extended with
|
|
41
|
+
* the inspector door (the palette executes; sources return data, never
|
|
42
|
+
* callbacks).
|
|
43
|
+
*/
|
|
44
|
+
export type SearchResultAction = {
|
|
45
|
+
kind: "navigate";
|
|
46
|
+
href: string;
|
|
47
|
+
} | {
|
|
48
|
+
kind: "inspect";
|
|
49
|
+
/**
|
|
50
|
+
* Entity-kind REFERENCE — must be Flavor-declared AND have an injected
|
|
51
|
+
* inspector view, or the open fails closed (no panel, palette stays).
|
|
52
|
+
*/
|
|
53
|
+
entityKind: string;
|
|
54
|
+
/** The already-resolved entity the inspector view will present. */
|
|
55
|
+
entity: unknown;
|
|
56
|
+
/** Inspector panel title (defaults to the kind reference). */
|
|
57
|
+
title?: string;
|
|
58
|
+
/** Optional one-line description under the title. */
|
|
59
|
+
description?: string;
|
|
60
|
+
};
|
|
61
|
+
/** One result a source returns for a query. Data only — no components, no callbacks. */
|
|
62
|
+
export interface SearchResult {
|
|
63
|
+
/** Stable id, unique within the source. */
|
|
64
|
+
id: string;
|
|
65
|
+
label: string;
|
|
66
|
+
/** Icon NAME for the shell's icon registry (unknown names fail closed to UNKNOWN_ICON). */
|
|
67
|
+
icon?: string;
|
|
68
|
+
/** Extra match terms beyond the label. */
|
|
69
|
+
keywords?: string[];
|
|
70
|
+
action: SearchResultAction;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* A product-injected searchable source. `query` is product code (it runs the
|
|
74
|
+
* product's own reads) — which is exactly why sources arrive through a shell
|
|
75
|
+
* PROP and never through the Flavor (Declarative-Flavor law: a Flavor holds
|
|
76
|
+
* no functions).
|
|
77
|
+
*/
|
|
78
|
+
export interface SearchSource {
|
|
79
|
+
/** Stable source id (unique across the injected set). */
|
|
80
|
+
id: string;
|
|
81
|
+
/** The palette group heading its results render under. */
|
|
82
|
+
label: string;
|
|
83
|
+
/**
|
|
84
|
+
* Permission REFERENCE gating the whole source — resolved through the SAME
|
|
85
|
+
* fail-closed snapshot as the palette's commands: anything but an explicit
|
|
86
|
+
* `allowed` means the source is never queried.
|
|
87
|
+
*/
|
|
88
|
+
requiredPermission?: string;
|
|
89
|
+
/**
|
|
90
|
+
* The product's search. Receives the trimmed palette text; returns results
|
|
91
|
+
* already filtered/ranked by the source. A rejection (or throw) makes the
|
|
92
|
+
* source contribute nothing for that query — never a crash.
|
|
93
|
+
*/
|
|
94
|
+
query: (text: string) => Promise<SearchResult[]>;
|
|
95
|
+
}
|
|
96
|
+
/** A rendered search section — the source's results under its group label. */
|
|
97
|
+
export interface SearchResultGroup {
|
|
98
|
+
/** `search:${source.id}` — disjoint from the command groups' `nav:`/`cmd:` namespaces. */
|
|
99
|
+
id: string;
|
|
100
|
+
label: string;
|
|
101
|
+
results: SearchResult[];
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* The permission gate, shared with the command derivation: a gated source
|
|
105
|
+
* passes only on an explicit `allowed` (unknown/denied/in-flight ⇒ dropped —
|
|
106
|
+
* and a dropped source is never queried, so denial can't even leak timing).
|
|
107
|
+
*/
|
|
108
|
+
export declare function permittedSearchSources(sources: readonly SearchSource[] | undefined, resolvePermission: SyncPermissionResolver): SearchSource[];
|
|
109
|
+
/**
|
|
110
|
+
* A result is rendered only if it is SHAPED like one — a malformed entry
|
|
111
|
+
* from a product source is dropped, never guessed at (fail-closed at the
|
|
112
|
+
* data boundary, same posture as the icon registry's unknown names).
|
|
113
|
+
*/
|
|
114
|
+
export declare function isSearchResult(value: unknown): value is SearchResult;
|
|
115
|
+
/**
|
|
116
|
+
* Run one query pass across the injected sources — the pure core the palette
|
|
117
|
+
* hook awaits:
|
|
118
|
+
*
|
|
119
|
+
* - blank text queries NOTHING (the palette starts as commands-only),
|
|
120
|
+
* - only permitted sources are queried (fail-closed gate above),
|
|
121
|
+
* - each source is independent: an error/throw or an empty/malformed
|
|
122
|
+
* answer contributes nothing while siblings still land,
|
|
123
|
+
* - group order follows injection order (deterministic rendering).
|
|
124
|
+
*/
|
|
125
|
+
export declare function querySearchSources(sources: readonly SearchSource[] | undefined, text: string, resolvePermission: SyncPermissionResolver): Promise<SearchResultGroup[]>;
|
|
126
|
+
//# sourceMappingURL=search-sources.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-sources.d.ts","sourceRoot":"","sources":["../../src/palette/search-sources.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAGtE;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAC1B;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAClC;IACE,IAAI,EAAE,SAAS,CAAC;IAChB;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,MAAM,EAAE,OAAO,CAAC;IAChB,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qDAAqD;IACrD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEN,wFAAwF;AACxF,MAAM,WAAW,YAAY;IAC3B,2CAA2C;IAC3C,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,2FAA2F;IAC3F,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,EAAE,kBAAkB,CAAC;CAC5B;AAED;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,yDAAyD;IACzD,EAAE,EAAE,MAAM,CAAC;IACX,0DAA0D;IAC1D,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;OAIG;IACH,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;CAClD;AAED,8EAA8E;AAC9E,MAAM,WAAW,iBAAiB;IAChC,0FAA0F;IAC1F,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,YAAY,EAAE,CAAC;CACzB;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,SAAS,YAAY,EAAE,GAAG,SAAS,EAC5C,iBAAiB,EAAE,sBAAsB,GACxC,YAAY,EAAE,CAKhB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,YAAY,CASpE;AAED;;;;;;;;;GASG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,SAAS,YAAY,EAAE,GAAG,SAAS,EAC5C,IAAI,EAAE,MAAM,EACZ,iBAAiB,EAAE,sBAAsB,GACxC,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAsB9B"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Search sources — the doctrine skeleton's Search experience as a typed
|
|
3
|
+
* injection seam (frontend-platform-doctrine.md, Operator Platform contract
|
|
4
|
+
* skeleton: "Search — the platform owns the search surface, invocation, and
|
|
5
|
+
* result rendering contract; the product fills WHICH sources and scopes are
|
|
6
|
+
* searchable").
|
|
7
|
+
*
|
|
8
|
+
* The split, same as every other slot:
|
|
9
|
+
* - The SHELL owns the surface — the ⌘K palette renders source results
|
|
10
|
+
* alongside its command groups and executes the selected action.
|
|
11
|
+
* - The PRODUCT injects `SearchSource` values through the shell's
|
|
12
|
+
* `searchSources` prop (the same injection pattern as icons / the
|
|
13
|
+
* permission resolver / `inspectorViews` / `runCommand`) — product code,
|
|
14
|
+
* never Flavor logic (a Flavor is inert data; `query` is a function).
|
|
15
|
+
* - A source's `query` runs on the PRODUCT'S side of the membrane (its own
|
|
16
|
+
* BFF / already-held reads). No transport, URL, or credential ever
|
|
17
|
+
* enters this package.
|
|
18
|
+
*
|
|
19
|
+
* FAIL-CLOSED, three ways (the palette dual of the inspector's refusal):
|
|
20
|
+
* - a source gated by `requiredPermission` that is not explicitly allowed
|
|
21
|
+
* under the SAME snapshot the palette's commands gate on is NEVER
|
|
22
|
+
* QUERIED (denied/unknown/in-flight resolution ⇒ zero results),
|
|
23
|
+
* - an erroring source (rejection or synchronous throw) contributes
|
|
24
|
+
* nothing — siblings are unaffected, the palette never crashes,
|
|
25
|
+
* - an in-flight source contributes nothing until it resolves (the hook
|
|
26
|
+
* in use-search-results.ts enforces this; absent sources trivially
|
|
27
|
+
* contribute nothing).
|
|
28
|
+
*
|
|
29
|
+
* A result's action is PaletteAction-shaped: `navigate` reuses the palette's
|
|
30
|
+
* href navigation; `inspect` opens the shell-owned inspector by entity KIND
|
|
31
|
+
* with an ALREADY-RESOLVED entity (the source fetched it — the inspector
|
|
32
|
+
* contract's "the opener hands it the entity" rule, and the inspector's own
|
|
33
|
+
* fail-closed gate still applies: an undeclared or view-less kind refuses).
|
|
34
|
+
*
|
|
35
|
+
* This module is PURE (no React): the contract + the query machinery,
|
|
36
|
+
* provable without a DOM. The React half lives in use-search-results.ts.
|
|
37
|
+
*/
|
|
38
|
+
import { isPermitted } from "../guard/permissions.js";
|
|
39
|
+
/**
|
|
40
|
+
* The permission gate, shared with the command derivation: a gated source
|
|
41
|
+
* passes only on an explicit `allowed` (unknown/denied/in-flight ⇒ dropped —
|
|
42
|
+
* and a dropped source is never queried, so denial can't even leak timing).
|
|
43
|
+
*/
|
|
44
|
+
export function permittedSearchSources(sources, resolvePermission) {
|
|
45
|
+
if (!sources || sources.length === 0)
|
|
46
|
+
return [];
|
|
47
|
+
return sources.filter((source) => isPermitted(source.requiredPermission, resolvePermission));
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* A result is rendered only if it is SHAPED like one — a malformed entry
|
|
51
|
+
* from a product source is dropped, never guessed at (fail-closed at the
|
|
52
|
+
* data boundary, same posture as the icon registry's unknown names).
|
|
53
|
+
*/
|
|
54
|
+
export function isSearchResult(value) {
|
|
55
|
+
if (typeof value !== "object" || value === null)
|
|
56
|
+
return false;
|
|
57
|
+
const result = value;
|
|
58
|
+
if (typeof result.id !== "string" || typeof result.label !== "string")
|
|
59
|
+
return false;
|
|
60
|
+
const action = result.action;
|
|
61
|
+
if (typeof action !== "object" || action === null)
|
|
62
|
+
return false;
|
|
63
|
+
if (action.kind === "navigate")
|
|
64
|
+
return typeof action.href === "string";
|
|
65
|
+
if (action.kind === "inspect")
|
|
66
|
+
return typeof action.entityKind === "string";
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Run one query pass across the injected sources — the pure core the palette
|
|
71
|
+
* hook awaits:
|
|
72
|
+
*
|
|
73
|
+
* - blank text queries NOTHING (the palette starts as commands-only),
|
|
74
|
+
* - only permitted sources are queried (fail-closed gate above),
|
|
75
|
+
* - each source is independent: an error/throw or an empty/malformed
|
|
76
|
+
* answer contributes nothing while siblings still land,
|
|
77
|
+
* - group order follows injection order (deterministic rendering).
|
|
78
|
+
*/
|
|
79
|
+
export async function querySearchSources(sources, text, resolvePermission) {
|
|
80
|
+
const trimmed = text.trim();
|
|
81
|
+
if (trimmed.length === 0)
|
|
82
|
+
return [];
|
|
83
|
+
const permitted = permittedSearchSources(sources, resolvePermission);
|
|
84
|
+
if (permitted.length === 0)
|
|
85
|
+
return [];
|
|
86
|
+
const settled = await Promise.all(permitted.map(async (source) => {
|
|
87
|
+
let results;
|
|
88
|
+
try {
|
|
89
|
+
const answer = await source.query(trimmed);
|
|
90
|
+
results = Array.isArray(answer) ? answer.filter(isSearchResult) : [];
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return null; // an erroring source contributes nothing — never a crash
|
|
94
|
+
}
|
|
95
|
+
if (results.length === 0)
|
|
96
|
+
return null;
|
|
97
|
+
return { id: `search:${source.id}`, label: source.label, results };
|
|
98
|
+
}));
|
|
99
|
+
return settled.filter((group) => group !== null);
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=search-sources.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-sources.js","sourceRoot":"","sources":["../../src/palette/search-sources.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAqEtD;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CACpC,OAA4C,EAC5C,iBAAyC;IAEzC,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAChD,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAC/B,WAAW,CAAC,MAAM,CAAC,kBAAkB,EAAE,iBAAiB,CAAC,CAC1D,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,MAAM,GAAG,KAA8B,CAAC;IAC9C,IAAI,OAAO,MAAM,CAAC,EAAE,KAAK,QAAQ,IAAI,OAAO,MAAM,CAAC,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACpF,MAAM,MAAM,GAAG,MAAM,CAAC,MAAiD,CAAC;IACxE,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAChE,IAAI,MAAM,CAAC,IAAI,KAAK,UAAU;QAAE,OAAO,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,CAAC;IACvE,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,OAAO,MAAM,CAAC,UAAU,KAAK,QAAQ,CAAC;IAC5E,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAA4C,EAC5C,IAAY,EACZ,iBAAyC;IAEzC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEpC,MAAM,SAAS,GAAG,sBAAsB,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC;IACrE,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEtC,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,EAAqC,EAAE;QAChE,IAAI,OAAuB,CAAC;QAC5B,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAC3C,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACvE,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC,CAAC,yDAAyD;QACxE,CAAC;QACD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QACtC,OAAO,EAAE,EAAE,EAAE,UAAU,MAAM,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC;IACrE,CAAC,CAAC,CACH,CAAC;IAEF,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAA8B,EAAE,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC;AAC/E,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { PermissionGateStatus } from "../guard/permissions.js";
|
|
2
|
+
import type { SearchResultGroup, SearchSource } from "./search-sources.js";
|
|
3
|
+
export declare function useSearchResults(sources: readonly SearchSource[] | undefined, text: string, decisions: Readonly<Record<string, PermissionGateStatus>>): SearchResultGroup[];
|
|
4
|
+
//# sourceMappingURL=use-search-results.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-search-results.d.ts","sourceRoot":"","sources":["../../src/palette/use-search-results.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,oBAAoB,EAA0B,MAAM,yBAAyB,CAAC;AAC5F,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAG3E,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,SAAS,YAAY,EAAE,GAAG,SAAS,EAC5C,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC,GACxD,iBAAiB,EAAE,CAoCrB"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
/**
|
|
3
|
+
* The React half of the search-source seam: run the injected sources against
|
|
4
|
+
* the palette text and hold the CURRENT results — with the fail-closed
|
|
5
|
+
* in-flight rule enforced here:
|
|
6
|
+
*
|
|
7
|
+
* - while a query pass is in flight, the sources contribute NOTHING (the
|
|
8
|
+
* previous pass's results are cleared the moment the text changes — the
|
|
9
|
+
* palette never shows results for a query the user is no longer typing),
|
|
10
|
+
* - a stale pass (the text moved on before it settled) is DISCARDED, never
|
|
11
|
+
* rendered,
|
|
12
|
+
* - blank text / no sources ⇒ no query, no results, synchronously.
|
|
13
|
+
*
|
|
14
|
+
* Permission gating rides the SAME live decisions map the palette's command
|
|
15
|
+
* derivation snapshots (usePermissionDecisions state): anything but an
|
|
16
|
+
* explicit `allowed` on a gated source means it is never queried. The
|
|
17
|
+
* decisions map is React state with stable identity between settlements, so
|
|
18
|
+
* it is the correct effect dependency (a per-render closure would not be).
|
|
19
|
+
*/
|
|
20
|
+
import * as React from "react";
|
|
21
|
+
import { permittedSearchSources, querySearchSources } from "./search-sources.js";
|
|
22
|
+
export function useSearchResults(sources, text, decisions) {
|
|
23
|
+
const [groups, setGroups] = React.useState([]);
|
|
24
|
+
React.useEffect(() => {
|
|
25
|
+
// Snapshot the live decisions into the sync gate the pure core takes:
|
|
26
|
+
// allowed passes; loading/denied/absent ⇒ unknown ⇒ the source is
|
|
27
|
+
// dropped before it is ever queried (fail-closed while resolving).
|
|
28
|
+
const snapshot = (permission) => decisions[permission] === "allowed" ? "allowed" : "unknown";
|
|
29
|
+
// Nothing searchable (blank text / no sources / none permitted) ⇒
|
|
30
|
+
// nothing rendered, no query fired, no async pass left dangling.
|
|
31
|
+
if (text.trim().length === 0 ||
|
|
32
|
+
permittedSearchSources(sources, snapshot).length === 0) {
|
|
33
|
+
setGroups([]);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
// In-flight contributes nothing: clear immediately, render on settle.
|
|
37
|
+
setGroups([]);
|
|
38
|
+
let stale = false;
|
|
39
|
+
querySearchSources(sources, text, snapshot).then((next) => {
|
|
40
|
+
if (!stale)
|
|
41
|
+
setGroups(next);
|
|
42
|
+
});
|
|
43
|
+
// querySearchSources never rejects (per-source errors are absorbed), so
|
|
44
|
+
// no catch is needed — but staleness still guards the resolution.
|
|
45
|
+
return () => {
|
|
46
|
+
stale = true;
|
|
47
|
+
};
|
|
48
|
+
}, [sources, text, decisions]);
|
|
49
|
+
return groups;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=use-search-results.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-search-results.js","sourceRoot":"","sources":["../../src/palette/use-search-results.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAEjF,MAAM,UAAU,gBAAgB,CAC9B,OAA4C,EAC5C,IAAY,EACZ,SAAyD;IAEzD,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAsB,EAAE,CAAC,CAAC;IAEpE,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,sEAAsE;QACtE,kEAAkE;QAClE,mEAAmE;QACnE,MAAM,QAAQ,GAA2B,CAAC,UAAU,EAAE,EAAE,CACtD,SAAS,CAAC,UAAU,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;QAE9D,kEAAkE;QAClE,iEAAiE;QACjE,IACE,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC;YACxB,sBAAsB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,MAAM,KAAK,CAAC,EACtD,CAAC;YACD,SAAS,CAAC,EAAE,CAAC,CAAC;YACd,OAAO;QACT,CAAC;QAED,sEAAsE;QACtE,SAAS,CAAC,EAAE,CAAC,CAAC;QACd,IAAI,KAAK,GAAG,KAAK,CAAC;QAElB,kBAAkB,CAAC,OAAO,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;YACxD,IAAI,CAAC,KAAK;gBAAE,SAAS,CAAC,IAAI,CAAC,CAAC;QAC9B,CAAC,CAAC,CAAC;QACH,wEAAwE;QACxE,kEAAkE;QAElE,OAAO,GAAG,EAAE;YACV,KAAK,GAAG,IAAI,CAAC;QACf,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;IAE/B,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OperatorSidebar — the shell's nav engine over the open-registry sidebar
|
|
3
|
+
* primitives (icon-collapsible, per the sidebar-07/sidebar-16 block
|
|
4
|
+
* patterns). It reads the Flavor: the product-context block from
|
|
5
|
+
* `flavor.product`, groups/items from `flavor.nav` (string icon names
|
|
6
|
+
* resolved through the icon registry), and gates items through the injected
|
|
7
|
+
* permission resolver — fail-closed, with EXPLICIT states (contracts §5):
|
|
8
|
+
*
|
|
9
|
+
* - `allowed` → the item renders,
|
|
10
|
+
* - `loading` → a registry SidebarMenuSkeleton holds the slot while an
|
|
11
|
+
* async resolver decides (no flash of a link the decision may remove),
|
|
12
|
+
* - `denied`/unknown → the item does not exist here (hidden, not disabled —
|
|
13
|
+
* a denied destination is not advertised),
|
|
14
|
+
* - a group whose gated items all vanish vanishes with them (no orphan
|
|
15
|
+
* group labels).
|
|
16
|
+
*
|
|
17
|
+
* The shell owns navigation behavior; the product declares the tree.
|
|
18
|
+
*/
|
|
19
|
+
import type * as React from "react";
|
|
20
|
+
import type { OperatorFlavor } from "../flavor/types.js";
|
|
21
|
+
import type { PermissionResolver } from "../guard/permissions.js";
|
|
22
|
+
import type { IconRegistry } from "../icons/registry.js";
|
|
23
|
+
export interface OperatorSidebarProps {
|
|
24
|
+
flavor: OperatorFlavor;
|
|
25
|
+
/** The product's permission resolution (§5), sync or async. Fail-closed on unknown. */
|
|
26
|
+
resolvePermission: PermissionResolver;
|
|
27
|
+
/** Product icon-vocabulary extensions for the registry. */
|
|
28
|
+
icons?: IconRegistry;
|
|
29
|
+
/**
|
|
30
|
+
* The resolved icon family (the frame reads the Brand's inert
|
|
31
|
+
* `iconFamily` declaration and resolves it via `resolveIconFamily`).
|
|
32
|
+
* Absent ⇒ the shipped family — same deterministic default.
|
|
33
|
+
*/
|
|
34
|
+
iconFamily?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Workspace-switcher SLOT (typed seam, INERT until backend PRE-1 — see
|
|
37
|
+
* OperatorShellProps.workspaceSwitcher and the Flavor's `workspaces`
|
|
38
|
+
* field). Nothing injected (today: every product) ⇒ nothing renders; the
|
|
39
|
+
* static product block below stays the whole context chrome.
|
|
40
|
+
*/
|
|
41
|
+
workspaceSwitcher?: React.ReactNode;
|
|
42
|
+
}
|
|
43
|
+
export declare function OperatorSidebar({ flavor, resolvePermission, icons, iconFamily, workspaceSwitcher, }: OperatorSidebarProps): import("react/jsx-runtime").JSX.Element;
|
|
44
|
+
//# sourceMappingURL=OperatorSidebar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OperatorSidebar.d.ts","sourceRoot":"","sources":["../../src/sidebar/OperatorSidebar.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AAkBpC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAGlE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAIzD,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,cAAc,CAAC;IACvB,uFAAuF;IACvF,iBAAiB,EAAE,kBAAkB,CAAC;IACtC,2DAA2D;IAC3D,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CACrC;AAED,wBAAgB,eAAe,CAAC,EAC9B,MAAM,EACN,iBAAiB,EACjB,KAAK,EACL,UAAU,EACV,iBAAiB,GAClB,EAAE,oBAAoB,2CA8EtB"}
|