@legioncodeinc/hive 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/LICENSE +661 -0
- package/README.md +262 -0
- package/dist/cli-commands.d.ts +41 -0
- package/dist/cli-commands.js +76 -0
- package/dist/cli-commands.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +46 -0
- package/dist/cli.js.map +1 -0
- package/dist/daemon/dashboard/app.js +118 -0
- package/dist/daemon/dashboard/host.d.ts +90 -0
- package/dist/daemon/dashboard/host.js +172 -0
- package/dist/daemon/dashboard/host.js.map +1 -0
- package/dist/daemon/dashboard/web-assets.d.ts +88 -0
- package/dist/daemon/dashboard/web-assets.js +195 -0
- package/dist/daemon/dashboard/web-assets.js.map +1 -0
- package/dist/daemon/fleet-status.d.ts +15 -0
- package/dist/daemon/fleet-status.js +56 -0
- package/dist/daemon/fleet-status.js.map +1 -0
- package/dist/daemon/gate.d.ts +55 -0
- package/dist/daemon/gate.js +128 -0
- package/dist/daemon/gate.js.map +1 -0
- package/dist/daemon/proxy.d.ts +38 -0
- package/dist/daemon/proxy.js +126 -0
- package/dist/daemon/proxy.js.map +1 -0
- package/dist/daemon/registry.d.ts +31 -0
- package/dist/daemon/registry.js +120 -0
- package/dist/daemon/registry.js.map +1 -0
- package/dist/daemon/server.d.ts +41 -0
- package/dist/daemon/server.js +126 -0
- package/dist/daemon/server.js.map +1 -0
- package/dist/daemon/setup-auth.d.ts +37 -0
- package/dist/daemon/setup-auth.js +51 -0
- package/dist/daemon/setup-auth.js.map +1 -0
- package/dist/daemon/telemetry-proxy.d.ts +47 -0
- package/dist/daemon/telemetry-proxy.js +63 -0
- package/dist/daemon/telemetry-proxy.js.map +1 -0
- package/dist/dashboard/contracts.d.ts +235 -0
- package/dist/dashboard/contracts.js +43 -0
- package/dist/dashboard/contracts.js.map +1 -0
- package/dist/dashboard/web/app.d.ts +44 -0
- package/dist/dashboard/web/app.js +179 -0
- package/dist/dashboard/web/app.js.map +1 -0
- package/dist/dashboard/web/boot-route.d.ts +23 -0
- package/dist/dashboard/web/boot-route.js +29 -0
- package/dist/dashboard/web/boot-route.js.map +1 -0
- package/dist/dashboard/web/build-graph-button.d.ts +46 -0
- package/dist/dashboard/web/build-graph-button.js +81 -0
- package/dist/dashboard/web/build-graph-button.js.map +1 -0
- package/dist/dashboard/web/buzzing-screen.d.ts +30 -0
- package/dist/dashboard/web/buzzing-screen.js +135 -0
- package/dist/dashboard/web/buzzing-screen.js.map +1 -0
- package/dist/dashboard/web/folder-picker.d.ts +54 -0
- package/dist/dashboard/web/folder-picker.js +125 -0
- package/dist/dashboard/web/folder-picker.js.map +1 -0
- package/dist/dashboard/web/graph-layout.d.ts +101 -0
- package/dist/dashboard/web/graph-layout.js +0 -0
- package/dist/dashboard/web/graph-layout.js.map +1 -0
- package/dist/dashboard/web/harness-strip.d.ts +38 -0
- package/dist/dashboard/web/harness-strip.js +65 -0
- package/dist/dashboard/web/harness-strip.js.map +1 -0
- package/dist/dashboard/web/health-rail.d.ts +26 -0
- package/dist/dashboard/web/health-rail.js +61 -0
- package/dist/dashboard/web/health-rail.js.map +1 -0
- package/dist/dashboard/web/main.d.ts +22 -0
- package/dist/dashboard/web/main.js +51 -0
- package/dist/dashboard/web/main.js.map +1 -0
- package/dist/dashboard/web/needs-project.d.ts +51 -0
- package/dist/dashboard/web/needs-project.js +69 -0
- package/dist/dashboard/web/needs-project.js.map +1 -0
- package/dist/dashboard/web/page-frame.d.ts +95 -0
- package/dist/dashboard/web/page-frame.js +98 -0
- package/dist/dashboard/web/page-frame.js.map +1 -0
- package/dist/dashboard/web/pages/coming-soon.d.ts +23 -0
- package/dist/dashboard/web/pages/coming-soon.js +19 -0
- package/dist/dashboard/web/pages/coming-soon.js.map +1 -0
- package/dist/dashboard/web/pages/dashboard.d.ts +32 -0
- package/dist/dashboard/web/pages/dashboard.js +205 -0
- package/dist/dashboard/web/pages/dashboard.js.map +1 -0
- package/dist/dashboard/web/pages/graph.d.ts +72 -0
- package/dist/dashboard/web/pages/graph.js +362 -0
- package/dist/dashboard/web/pages/graph.js.map +1 -0
- package/dist/dashboard/web/pages/harnesses.d.ts +65 -0
- package/dist/dashboard/web/pages/harnesses.js +210 -0
- package/dist/dashboard/web/pages/harnesses.js.map +1 -0
- package/dist/dashboard/web/pages/health.d.ts +22 -0
- package/dist/dashboard/web/pages/health.js +91 -0
- package/dist/dashboard/web/pages/health.js.map +1 -0
- package/dist/dashboard/web/pages/lifecycle-panel.d.ts +60 -0
- package/dist/dashboard/web/pages/lifecycle-panel.js +187 -0
- package/dist/dashboard/web/pages/lifecycle-panel.js.map +1 -0
- package/dist/dashboard/web/pages/logs.d.ts +55 -0
- package/dist/dashboard/web/pages/logs.js +311 -0
- package/dist/dashboard/web/pages/logs.js.map +1 -0
- package/dist/dashboard/web/pages/memories.d.ts +35 -0
- package/dist/dashboard/web/pages/memories.js +439 -0
- package/dist/dashboard/web/pages/memories.js.map +1 -0
- package/dist/dashboard/web/pages/projects.d.ts +38 -0
- package/dist/dashboard/web/pages/projects.js +325 -0
- package/dist/dashboard/web/pages/projects.js.map +1 -0
- package/dist/dashboard/web/pages/roi-chart.d.ts +52 -0
- package/dist/dashboard/web/pages/roi-chart.js +133 -0
- package/dist/dashboard/web/pages/roi-chart.js.map +1 -0
- package/dist/dashboard/web/pages/roi.d.ts +93 -0
- package/dist/dashboard/web/pages/roi.js +375 -0
- package/dist/dashboard/web/pages/roi.js.map +1 -0
- package/dist/dashboard/web/pages/settings.d.ts +103 -0
- package/dist/dashboard/web/pages/settings.js +420 -0
- package/dist/dashboard/web/pages/settings.js.map +1 -0
- package/dist/dashboard/web/pages/sync.d.ts +59 -0
- package/dist/dashboard/web/pages/sync.js +280 -0
- package/dist/dashboard/web/pages/sync.js.map +1 -0
- package/dist/dashboard/web/panels.d.ts +178 -0
- package/dist/dashboard/web/panels.js +471 -0
- package/dist/dashboard/web/panels.js.map +1 -0
- package/dist/dashboard/web/primitives.d.ts +80 -0
- package/dist/dashboard/web/primitives.js +208 -0
- package/dist/dashboard/web/primitives.js.map +1 -0
- package/dist/dashboard/web/readiness-splash.d.ts +39 -0
- package/dist/dashboard/web/readiness-splash.js +201 -0
- package/dist/dashboard/web/readiness-splash.js.map +1 -0
- package/dist/dashboard/web/registry.d.ts +96 -0
- package/dist/dashboard/web/registry.js +99 -0
- package/dist/dashboard/web/registry.js.map +1 -0
- package/dist/dashboard/web/router.d.ts +48 -0
- package/dist/dashboard/web/router.js +76 -0
- package/dist/dashboard/web/router.js.map +1 -0
- package/dist/dashboard/web/scope-context.d.ts +155 -0
- package/dist/dashboard/web/scope-context.js +266 -0
- package/dist/dashboard/web/scope-context.js.map +1 -0
- package/dist/dashboard/web/service-icons.d.ts +33 -0
- package/dist/dashboard/web/service-icons.js +80 -0
- package/dist/dashboard/web/service-icons.js.map +1 -0
- package/dist/dashboard/web/setup-gate.d.ts +116 -0
- package/dist/dashboard/web/setup-gate.js +272 -0
- package/dist/dashboard/web/setup-gate.js.map +1 -0
- package/dist/dashboard/web/sidebar.d.ts +63 -0
- package/dist/dashboard/web/sidebar.js +91 -0
- package/dist/dashboard/web/sidebar.js.map +1 -0
- package/dist/dashboard/web/use-fleet-telemetry.d.ts +111 -0
- package/dist/dashboard/web/use-fleet-telemetry.js +278 -0
- package/dist/dashboard/web/use-fleet-telemetry.js.map +1 -0
- package/dist/dashboard/web/wire.d.ts +1937 -0
- package/dist/dashboard/web/wire.js +1837 -0
- package/dist/dashboard/web/wire.js.map +1 -0
- package/dist/errors.d.ts +5 -0
- package/dist/errors.js +11 -0
- package/dist/errors.js.map +1 -0
- package/dist/install/registry.d.ts +35 -0
- package/dist/install/registry.js +110 -0
- package/dist/install/registry.js.map +1 -0
- package/dist/lock.d.ts +10 -0
- package/dist/lock.js +87 -0
- package/dist/lock.js.map +1 -0
- package/dist/service/commands.d.ts +15 -0
- package/dist/service/commands.js +49 -0
- package/dist/service/commands.js.map +1 -0
- package/dist/service/index.d.ts +38 -0
- package/dist/service/index.js +174 -0
- package/dist/service/index.js.map +1 -0
- package/dist/service/platform.d.ts +37 -0
- package/dist/service/platform.js +67 -0
- package/dist/service/platform.js.map +1 -0
- package/dist/service/templates.d.ts +10 -0
- package/dist/service/templates.js +120 -0
- package/dist/service/templates.js.map +1 -0
- package/dist/shared/constants.d.ts +15 -0
- package/dist/shared/constants.js +19 -0
- package/dist/shared/constants.js.map +1 -0
- package/dist/shared/daemon-routing.d.ts +11 -0
- package/dist/shared/daemon-routing.js +38 -0
- package/dist/shared/daemon-routing.js.map +1 -0
- package/dist/shared/fleet-readiness.d.ts +18 -0
- package/dist/shared/fleet-readiness.js +9 -0
- package/dist/shared/fleet-readiness.js.map +1 -0
- package/dist/shared/fleet-telemetry.d.ts +68 -0
- package/dist/shared/fleet-telemetry.js +61 -0
- package/dist/shared/fleet-telemetry.js.map +1 -0
- package/dist/shared/lifecycle-flags.d.ts +34 -0
- package/dist/shared/lifecycle-flags.js +39 -0
- package/dist/shared/lifecycle-flags.js.map +1 -0
- package/dist/shared/memory-types.d.ts +55 -0
- package/dist/shared/memory-types.js +75 -0
- package/dist/shared/memory-types.js.map +1 -0
- package/dist/shared/service-status.d.ts +82 -0
- package/dist/shared/service-status.js +97 -0
- package/dist/shared/service-status.js.map +1 -0
- package/dist/telemetry/emit.d.ts +197 -0
- package/dist/telemetry/emit.js +196 -0
- package/dist/telemetry/emit.js.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* The Org → Workspace → Project SCOPE context — PRD-050b seam, FILLED by PRD-049e.
|
|
4
|
+
*
|
|
5
|
+
* ════════════════════════════════════════════════════════════════════════════
|
|
6
|
+
* 050b carved the seam (a context + a hook + a slot) so the 049e scope switcher could slot into the
|
|
7
|
+
* sidebar WITHOUT reworking `host.ts`/`renderShell`/the shell. 049e FILLS it: a real
|
|
8
|
+
* {@link ScopeProvider} hydrates the switchable Org→Workspace→Project selection from the daemon's
|
|
9
|
+
* loopback enumeration endpoints, the {@link ScopeSwitcherSlot} renders the dropdowns, and every
|
|
10
|
+
* scope-aware page reads the active project via {@link useScope}. The shell stays scope-UNAWARE —
|
|
11
|
+
* scope lives entirely in the React app, never baked into the server-rendered shell.
|
|
12
|
+
* ════════════════════════════════════════════════════════════════════════════
|
|
13
|
+
*
|
|
14
|
+
* ── The contract (unchanged from 050b — additive only) ──────────────────────
|
|
15
|
+
* - {@link DashboardScope} `{ org, workspace, project? }` — what a page reads.
|
|
16
|
+
* - {@link useScope} — the hook every scope-aware surface uses. 049e makes it reactive to the
|
|
17
|
+
* switcher's selection; a surface written against this hook needs NO change.
|
|
18
|
+
* - {@link ScopeSwitcherSlot} — the sidebar region. 050b returned null; 049e renders the picker.
|
|
19
|
+
*
|
|
20
|
+
* ── Viewer-side selection (49e-AC-4) ─────────────────────────────────────────
|
|
21
|
+
* The selection drives WHICH data the pages show (it stamps the `x-honeycomb-project` read header).
|
|
22
|
+
* It does NOT overwrite a developer's per-folder CLI bindings: there is NO write to `projects.json`
|
|
23
|
+
* anywhere in this module. The selection is persisted ONLY in `localStorage` (the dashboard session),
|
|
24
|
+
* so a reload restores the last view without touching the registry.
|
|
25
|
+
*/
|
|
26
|
+
import React from "react";
|
|
27
|
+
/** The single-scope default the app starts from (the loopback local tenant) until enumeration resolves. */
|
|
28
|
+
export const DEFAULT_SCOPE = Object.freeze({ org: "local", workspace: "default" });
|
|
29
|
+
/** The `localStorage` key the dashboard persists its last viewer-side selection under (49e — viewer-side). */
|
|
30
|
+
export const SCOPE_STORAGE_KEY = "honeycomb.dashboard.scope";
|
|
31
|
+
/** The React context (the 049e mount point). Defaults to the single loopback scope + a no-op setter. */
|
|
32
|
+
export const ScopeContext = React.createContext({
|
|
33
|
+
scope: DEFAULT_SCOPE,
|
|
34
|
+
setScope: () => {
|
|
35
|
+
// No-op default: outside a ScopeProvider there is exactly one scope. The provider replaces this.
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
/**
|
|
39
|
+
* Read the active dashboard scope (the hook every scope-aware surface uses). Reactive to the switcher's
|
|
40
|
+
* selection when rendered inside a {@link ScopeProvider}; returns the single default otherwise. Read
|
|
41
|
+
* scope from HERE, never bake a single-workspace assumption into a page or the shell.
|
|
42
|
+
*/
|
|
43
|
+
export function useScope() {
|
|
44
|
+
return React.useContext(ScopeContext);
|
|
45
|
+
}
|
|
46
|
+
/** The default switcher value (empty enumeration + no-op handlers) — used outside a {@link ScopeProvider}. */
|
|
47
|
+
const DEFAULT_SWITCHER = Object.freeze({
|
|
48
|
+
orgs: [],
|
|
49
|
+
workspaces: [],
|
|
50
|
+
projects: [],
|
|
51
|
+
projectsHydrated: false,
|
|
52
|
+
loadingWorkspaces: false,
|
|
53
|
+
switchFeedback: null,
|
|
54
|
+
selectOrg: () => { },
|
|
55
|
+
selectWorkspace: () => { },
|
|
56
|
+
selectProject: () => { },
|
|
57
|
+
});
|
|
58
|
+
/** The switcher-data context (the enumeration + dropdown handlers). The slot reads it; pages do not. */
|
|
59
|
+
export const ScopeSwitcherContext = React.createContext(DEFAULT_SWITCHER);
|
|
60
|
+
/** Read the switcher's enumeration state + handlers (the {@link ScopeSwitcherSlot} uses this). */
|
|
61
|
+
export function useScopeSwitcher() {
|
|
62
|
+
return React.useContext(ScopeSwitcherContext);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Read the persisted viewer-side selection from `localStorage` (49e — persistence is acceptable, and
|
|
66
|
+
* viewer-side: a read of the dashboard's own store, never the registry). Fail-soft: a missing/malformed
|
|
67
|
+
* value yields `null` (the provider then resolves from the daemon default), never a throw.
|
|
68
|
+
*/
|
|
69
|
+
export function loadPersistedScope() {
|
|
70
|
+
try {
|
|
71
|
+
if (typeof localStorage === "undefined")
|
|
72
|
+
return null;
|
|
73
|
+
const raw = localStorage.getItem(SCOPE_STORAGE_KEY);
|
|
74
|
+
if (raw === null || raw === "")
|
|
75
|
+
return null;
|
|
76
|
+
const parsed = JSON.parse(raw);
|
|
77
|
+
if (typeof parsed !== "object" || parsed === null)
|
|
78
|
+
return null;
|
|
79
|
+
const obj = parsed;
|
|
80
|
+
const org = typeof obj.org === "string" ? obj.org : "";
|
|
81
|
+
const workspace = typeof obj.workspace === "string" ? obj.workspace : "";
|
|
82
|
+
if (org === "" || workspace === "")
|
|
83
|
+
return null;
|
|
84
|
+
const project = typeof obj.project === "string" && obj.project !== "" ? obj.project : undefined;
|
|
85
|
+
return project !== undefined ? { org, workspace, project } : { org, workspace };
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/** Persist the viewer-side selection to `localStorage` (49e). Fail-soft — a storage error is swallowed intentionally. */
|
|
92
|
+
export function persistScope(scope) {
|
|
93
|
+
try {
|
|
94
|
+
if (typeof localStorage === "undefined")
|
|
95
|
+
return;
|
|
96
|
+
localStorage.setItem(SCOPE_STORAGE_KEY, JSON.stringify(scope));
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
// localStorage may be unavailable (private mode / quota). The selection still works in-memory;
|
|
100
|
+
// only the cross-reload persistence is lost — never a thrown error into React.
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* The SCOPE PROVIDER (PRD-049e) — owns the switchable selection + the enumeration state, and feeds both
|
|
105
|
+
* the lean {@link ScopeContext} (pages) and the rich {@link ScopeSwitcherContext} (the slot). Mounted by
|
|
106
|
+
* the {@link import("./app.js").Shell} around the sidebar + outlet, so every page + the switcher share
|
|
107
|
+
* ONE source of truth.
|
|
108
|
+
*
|
|
109
|
+
* On mount it hydrates the orgs (privilege-scoped), then the workspaces + projects for the
|
|
110
|
+
* resolved/persisted org, and restores the persisted project selection (viewer-side). Selecting an Org
|
|
111
|
+
* re-enumerates workspaces (the daemon re-mints the org-bound token FIRST — 49e-AC-3); selecting a
|
|
112
|
+
* Workspace re-enumerates projects; selecting a Project re-scopes the pages (the project flows into
|
|
113
|
+
* `useScope().scope.project`, which the pages thread into the wire fetchers). NO write to `projects.json`
|
|
114
|
+
* happens here — the selection is purely viewer-side (49e-AC-4).
|
|
115
|
+
*/
|
|
116
|
+
export function ScopeProvider({ wire, children }) {
|
|
117
|
+
const persisted = React.useMemo(() => loadPersistedScope(), []);
|
|
118
|
+
const [scope, setScopeState] = React.useState(persisted ?? DEFAULT_SCOPE);
|
|
119
|
+
const [orgs, setOrgs] = React.useState([]);
|
|
120
|
+
const [workspaces, setWorkspaces] = React.useState([]);
|
|
121
|
+
const [projects, setProjects] = React.useState([]);
|
|
122
|
+
const [projectsHydrated, setProjectsHydrated] = React.useState(false);
|
|
123
|
+
const [loadingWorkspaces, setLoadingWorkspaces] = React.useState(false);
|
|
124
|
+
// IRD-122 (122-AC-4): the last switch's outcome, so no switcher change is ever a silent no-op.
|
|
125
|
+
const [switchFeedback, setSwitchFeedback] = React.useState(null);
|
|
126
|
+
/** Commit a new scope: persist it (viewer-side) + update state so pages re-render against it. */
|
|
127
|
+
const commitScope = React.useCallback((next) => {
|
|
128
|
+
setScopeState(next);
|
|
129
|
+
persistScope(next);
|
|
130
|
+
}, []);
|
|
131
|
+
// The setScope a page would call (e.g. a deep link). Persists + re-renders; no enumeration side effect.
|
|
132
|
+
const setScope = React.useCallback((next) => commitScope(next), [commitScope]);
|
|
133
|
+
/** Enumerate a workspace's projects (sets the hydrated flag so the 059b first-run CTA can key off it). */
|
|
134
|
+
const loadProjects = React.useCallback(async () => {
|
|
135
|
+
const rows = await wire.scopeProjects();
|
|
136
|
+
setProjects(rows);
|
|
137
|
+
setProjectsHydrated(true);
|
|
138
|
+
}, [wire]);
|
|
139
|
+
// Hydrate orgs once on mount (49e-AC-1). The list is privilege-scoped server-side.
|
|
140
|
+
React.useEffect(() => {
|
|
141
|
+
let alive = true;
|
|
142
|
+
void (async () => {
|
|
143
|
+
const rows = await wire.scopeOrgs();
|
|
144
|
+
if (!alive)
|
|
145
|
+
return;
|
|
146
|
+
setOrgs(rows);
|
|
147
|
+
})();
|
|
148
|
+
// Also hydrate the workspaces + projects for the initial (persisted/default) org so the dropdowns
|
|
149
|
+
// are populated on first render without requiring an org re-select.
|
|
150
|
+
void (async () => {
|
|
151
|
+
const ws = await wire.scopeWorkspaces();
|
|
152
|
+
if (!alive)
|
|
153
|
+
return;
|
|
154
|
+
setWorkspaces(ws.workspaces);
|
|
155
|
+
})();
|
|
156
|
+
void loadProjects();
|
|
157
|
+
return () => {
|
|
158
|
+
alive = false;
|
|
159
|
+
};
|
|
160
|
+
}, [wire, loadProjects]);
|
|
161
|
+
// IRD-122 (122-AC-1 / 122-AC-2): selecting an org now PERSISTS a real org switch via the daemon
|
|
162
|
+
// (re-mint the org-bound token + save to credentials.json — the SAME mechanic as `honeycomb org
|
|
163
|
+
// switch`), THEN re-enumerates the new org's workspaces. The switch is no longer viewer-only: on
|
|
164
|
+
// success `whoami` reflects it. Feedback is surfaced (122-AC-4) — pending while re-minting, then
|
|
165
|
+
// persisted or error; a FAILED persist does NOT silently change the dashboard view (we keep the prior
|
|
166
|
+
// scope so the control never lies about what is active).
|
|
167
|
+
const selectOrg = React.useCallback((org) => {
|
|
168
|
+
setLoadingWorkspaces(true);
|
|
169
|
+
setSwitchFeedback({ kind: "persisted", message: "switching org…", pending: true });
|
|
170
|
+
void (async () => {
|
|
171
|
+
try {
|
|
172
|
+
const ack = await wire.switchOrg(org);
|
|
173
|
+
if (!ack.switched) {
|
|
174
|
+
// The persist failed (no credential / unknown org / re-mint error). Surface it; do NOT
|
|
175
|
+
// mutate the active scope — the switcher honestly reflects that nothing changed.
|
|
176
|
+
setSwitchFeedback({ kind: "error", message: ack.error !== undefined && ack.error !== "" ? `could not switch: ${ack.error}` : "could not switch org" });
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
// Persisted (re-minted if the org changed). Commit the view to the now-active org + reset the
|
|
180
|
+
// workspace (a concrete workspace belonged to the previous org), then re-enumerate.
|
|
181
|
+
commitScope({ org: ack.org, workspace: DEFAULT_SCOPE.workspace, project: undefined });
|
|
182
|
+
const ws = await wire.scopeWorkspaces(ack.org);
|
|
183
|
+
setWorkspaces(ws.workspaces);
|
|
184
|
+
setProjects([]);
|
|
185
|
+
setProjectsHydrated(true);
|
|
186
|
+
setSwitchFeedback({ kind: "persisted", message: ack.reminted ? `switched to ${ack.orgName ?? ack.org} · re-minted` : `switched to ${ack.orgName ?? ack.org}` });
|
|
187
|
+
}
|
|
188
|
+
finally {
|
|
189
|
+
setLoadingWorkspaces(false);
|
|
190
|
+
}
|
|
191
|
+
})();
|
|
192
|
+
}, [wire, commitScope]);
|
|
193
|
+
// IRD-122: selecting a workspace PERSISTS the workspace switch via the daemon (write the workspace id
|
|
194
|
+
// to credentials.json — no re-mint), THEN re-enumerates its projects. Failure is surfaced, never silent.
|
|
195
|
+
const selectWorkspace = React.useCallback((workspace) => {
|
|
196
|
+
setSwitchFeedback({ kind: "persisted", message: "switching workspace…", pending: true });
|
|
197
|
+
void (async () => {
|
|
198
|
+
const ack = await wire.switchWorkspace(workspace);
|
|
199
|
+
if (!ack.switched) {
|
|
200
|
+
setSwitchFeedback({ kind: "error", message: ack.error !== undefined && ack.error !== "" ? `could not switch: ${ack.error}` : "could not switch workspace" });
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
commitScope({ org: scope.org, workspace: ack.workspace, project: undefined });
|
|
204
|
+
await loadProjects();
|
|
205
|
+
setSwitchFeedback({ kind: "persisted", message: `switched to ${ack.workspace}` });
|
|
206
|
+
})();
|
|
207
|
+
}, [wire, commitScope, scope.org, loadProjects]);
|
|
208
|
+
// 122-AC-3: the project dropdown is a VIEW FILTER. Selecting a project re-scopes the pages
|
|
209
|
+
// (viewer-side; NO registry write — 49e-AC-4) and surfaces "view filter" feedback so the user
|
|
210
|
+
// understands it changes the VIEW, not where capture is written (that is folder/binding-driven —
|
|
211
|
+
// PRD-059). `undefined` clears the selection (the needs-selection empty state, 49e-AC-5).
|
|
212
|
+
const selectProject = React.useCallback((project) => {
|
|
213
|
+
commitScope({ org: scope.org, workspace: scope.workspace, ...(project !== undefined ? { project } : {}) });
|
|
214
|
+
setSwitchFeedback({ kind: "view", message: project !== undefined ? "view filter — capture is set by folder binding" : "view cleared" });
|
|
215
|
+
}, [commitScope, scope.org, scope.workspace]);
|
|
216
|
+
const scopeValue = React.useMemo(() => ({ scope, setScope }), [scope, setScope]);
|
|
217
|
+
const switcherValue = React.useMemo(() => ({ orgs, workspaces, projects, projectsHydrated, loadingWorkspaces, switchFeedback, selectOrg, selectWorkspace, selectProject }), [orgs, workspaces, projects, projectsHydrated, loadingWorkspaces, switchFeedback, selectOrg, selectWorkspace, selectProject]);
|
|
218
|
+
return (_jsx(ScopeContext.Provider, { value: scopeValue, children: _jsx(ScopeSwitcherContext.Provider, { value: switcherValue, children: children }) }));
|
|
219
|
+
}
|
|
220
|
+
/** The shared `<select>` styling for the switcher dropdowns (existing DS tokens only — no new token). */
|
|
221
|
+
const SELECT_STYLE = {
|
|
222
|
+
width: "100%",
|
|
223
|
+
height: 30,
|
|
224
|
+
padding: "0 8px",
|
|
225
|
+
background: "var(--bg-elevated)",
|
|
226
|
+
border: "1px solid var(--border-default)",
|
|
227
|
+
borderRadius: "var(--radius-md)",
|
|
228
|
+
color: "var(--text-secondary)",
|
|
229
|
+
fontFamily: "var(--font-mono)",
|
|
230
|
+
fontSize: 12,
|
|
231
|
+
cursor: "pointer",
|
|
232
|
+
};
|
|
233
|
+
/** One labeled dropdown row in the switcher (a mono caption + a `<select>`). */
|
|
234
|
+
function SwitcherSelect({ label, testId, value, disabled, onChange, children, }) {
|
|
235
|
+
return (_jsxs("label", { style: { display: "flex", flexDirection: "column", gap: 3 }, children: [_jsx("span", { style: { fontFamily: "var(--font-mono)", fontSize: 10, color: "var(--text-tertiary)", textTransform: "uppercase", letterSpacing: "0.08em" }, children: label }), _jsx("select", { "data-testid": testId, value: value, disabled: disabled, onChange: (e) => onChange(e.target.value), style: { ...SELECT_STYLE, opacity: disabled ? 0.6 : 1 }, children: children })] }));
|
|
236
|
+
}
|
|
237
|
+
/** The reserved inbox project id (mirrored from the resolver; a literal so this stays a thin-client view). */
|
|
238
|
+
const UNSORTED_PROJECT_ID = "__unsorted__";
|
|
239
|
+
/** The `<option>` value the project `<select>` uses for "no project selected" (the needs-selection state). */
|
|
240
|
+
const NO_PROJECT_VALUE = "";
|
|
241
|
+
/**
|
|
242
|
+
* The Org→Workspace→Project SWITCHER (PRD-049e) — the body that fills the 050b slot. Three dependent
|
|
243
|
+
* dropdowns hydrated from the {@link useScopeSwitcher} enumeration state; the active selection comes from
|
|
244
|
+
* {@link useScope}. Changing the Org re-enumerates workspaces (after the daemon re-mints — 49e-AC-3),
|
|
245
|
+
* changing the Workspace re-enumerates projects, and changing the Project re-scopes every page
|
|
246
|
+
* (viewer-side; no registry write — 49e-AC-4). In the collapsed rail it renders nothing (the switcher
|
|
247
|
+
* needs labels) — the sidebar expands to switch scope.
|
|
248
|
+
*/
|
|
249
|
+
export function ScopeSwitcherSlot({ collapsed }) {
|
|
250
|
+
const { scope } = useScope();
|
|
251
|
+
const switcher = useScopeSwitcher();
|
|
252
|
+
// The collapsed icon-rail has no room for three labeled dropdowns; render nothing (the expanded rail
|
|
253
|
+
// is where scope is switched). This keeps the collapsed layout identical to 050b.
|
|
254
|
+
if (collapsed)
|
|
255
|
+
return null;
|
|
256
|
+
return (_jsxs("div", { "data-testid": "scope-switcher", style: { display: "flex", flexDirection: "column", gap: 8 }, children: [_jsxs(SwitcherSelect, { label: "org", testId: "scope-org", value: scope.org, onChange: switcher.selectOrg, children: [switcher.orgs.length === 0 && _jsx("option", { value: scope.org, children: scope.org }), switcher.orgs.map((o) => (_jsx("option", { value: o.id, children: o.name !== "" ? o.name : o.id }, o.id)))] }), _jsxs(SwitcherSelect, { label: "workspace", testId: "scope-workspace", value: scope.workspace, disabled: switcher.loadingWorkspaces, onChange: switcher.selectWorkspace, children: [switcher.workspaces.length === 0 && _jsx("option", { value: scope.workspace, children: switcher.loadingWorkspaces ? "loading…" : scope.workspace }), switcher.workspaces.map((w) => (_jsx("option", { value: w.id, children: w.name !== "" ? w.name : w.id }, w.id)))] }), _jsxs(SwitcherSelect, { label: "project \u00B7 view filter", testId: "scope-project", value: scope.project ?? NO_PROJECT_VALUE, onChange: (v) => switcher.selectProject(v === NO_PROJECT_VALUE ? undefined : v), children: [_jsx("option", { value: NO_PROJECT_VALUE, children: "\u2014 select a project \u2014" }), switcher.projects.map((p) => (_jsx("option", { value: p.projectId, children: p.projectId === UNSORTED_PROJECT_ID ? "(unsorted inbox)" : p.name !== "" ? p.name : p.projectId }, p.projectId)))] }), _jsx("span", { "data-testid": "project-view-hint", style: { fontFamily: "var(--font-mono)", fontSize: 10, color: "var(--text-tertiary)", lineHeight: 1.4 }, children: "Filters what you VIEW. To set where Honeycomb captures, bind a folder in Projects." }), switcher.switchFeedback !== null && (_jsxs("span", { "data-testid": "switch-feedback", "data-kind": switcher.switchFeedback.kind, style: {
|
|
257
|
+
fontFamily: "var(--font-mono)",
|
|
258
|
+
fontSize: 10,
|
|
259
|
+
color: switcher.switchFeedback.kind === "error"
|
|
260
|
+
? "var(--severity-critical)"
|
|
261
|
+
: switcher.switchFeedback.kind === "persisted"
|
|
262
|
+
? "var(--verified)"
|
|
263
|
+
: "var(--text-tertiary)",
|
|
264
|
+
}, children: [switcher.switchFeedback.pending === true ? "⟳ " : switcher.switchFeedback.kind === "persisted" ? "✓ " : "", switcher.switchFeedback.message] }))] }));
|
|
265
|
+
}
|
|
266
|
+
//# sourceMappingURL=scope-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope-context.js","sourceRoot":"","sources":["../../../src/dashboard/web/scope-context.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The bee-related status SVG set + the single shared state→icon mapping — hive PRD-004b.
|
|
3
|
+
*
|
|
4
|
+
* Five distinct bee-motif icons, one per locked {@link ServiceState} (`error`, `degraded`,
|
|
5
|
+
* `starting`, `warming`, `active`), plus a fail-safe fallback for any unexpected value (svg-AC-5).
|
|
6
|
+
* Every icon differs in SHAPE/MOTIF, not only color (svg-AC-2), so the set reads in grayscale and
|
|
7
|
+
* for color-vision-deficient operators:
|
|
8
|
+
*
|
|
9
|
+
* - `starting` — an empty honeycomb CELL outline (not yet emerged; no bee drawn at all).
|
|
10
|
+
* - `warming` — a bee body with small, half-folded wings (just emerged, wings unfurling).
|
|
11
|
+
* - `active` — a bee body with full, wide-spread wings (settled and flying).
|
|
12
|
+
* - `degraded` — a bee body with ONE wing only (asymmetric) plus a small caution mark.
|
|
13
|
+
* - `error` — a bee body lying on its back (rotated) with its wings crossed into an X.
|
|
14
|
+
*
|
|
15
|
+
* {@link ServiceStateIcon} is the ONE shared resolver every consumer (`/buzzing` tiles, PRD-004a;
|
|
16
|
+
* the health rail pills, PRD-005a) renders through (svg-AC-4), so a state means the same icon
|
|
17
|
+
* everywhere. Every stroke/fill uses `currentColor` (dark-mode legible, svg-AC-3) with color used
|
|
18
|
+
* only as reinforcement — never the sole differentiator (svg-AC-2).
|
|
19
|
+
*/
|
|
20
|
+
import React from "react";
|
|
21
|
+
import { type ServiceState } from "../../shared/service-status.js";
|
|
22
|
+
/**
|
|
23
|
+
* The single shared state→icon mapping (svg-AC-4). Every consumer resolves a state's icon through
|
|
24
|
+
* THIS function only — never a per-component switch — so `/buzzing` and the health rail render the
|
|
25
|
+
* identical icon for the identical state.
|
|
26
|
+
*/
|
|
27
|
+
export declare function ServiceStateIcon({ state }: {
|
|
28
|
+
readonly state: string;
|
|
29
|
+
}): React.JSX.Element;
|
|
30
|
+
/** A short, human label per state (used for `title`/`aria-label` alongside the icon). */
|
|
31
|
+
export declare const SERVICE_STATE_LABEL: Record<ServiceState, string>;
|
|
32
|
+
/** The color token reinforcing (never solely conveying, svg-AC-2) each state. */
|
|
33
|
+
export declare const SERVICE_STATE_COLOR: Record<ServiceState, string>;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { isServiceState } from "../../shared/service-status.js";
|
|
3
|
+
/** Shared bee-body path data (an oval-ish body with two stripe lines), reused by every drawn-bee icon. */
|
|
4
|
+
function BeeBody() {
|
|
5
|
+
return (_jsxs(_Fragment, { children: [_jsx("ellipse", { cx: 12, cy: 13, rx: 4.4, ry: 5.4, fill: "none", stroke: "currentColor", strokeWidth: 1.6 }), _jsx("path", { d: "M8.4 11.2h7.2M8.1 14.4h7.8", stroke: "currentColor", strokeWidth: 1.4, strokeLinecap: "round" }), _jsx("circle", { cx: 12, cy: 6.6, r: 2.1, fill: "none", stroke: "currentColor", strokeWidth: 1.6 }), _jsx("path", { d: "M10.8 5.2 9.6 3.2M13.2 5.2l1.2-2", stroke: "currentColor", strokeWidth: 1.3, strokeLinecap: "round" })] }));
|
|
6
|
+
}
|
|
7
|
+
const ICON_PROPS = {
|
|
8
|
+
width: 22,
|
|
9
|
+
height: 22,
|
|
10
|
+
viewBox: "0 0 24 24",
|
|
11
|
+
"aria-hidden": true,
|
|
12
|
+
focusable: false,
|
|
13
|
+
};
|
|
14
|
+
/** `starting` — an empty honeycomb cell outline; no bee has emerged yet. */
|
|
15
|
+
function StartingIcon() {
|
|
16
|
+
return (_jsxs("svg", { ...ICON_PROPS, "data-service-state": "starting", children: [_jsx("path", { d: "M12 3.5 19 7.75v8.5L12 20.5 5 16.25v-8.5z", fill: "none", stroke: "currentColor", strokeWidth: 1.6, strokeDasharray: "2.5 2.5", strokeLinejoin: "round" }), _jsx("circle", { cx: 12, cy: 12, r: 1.6, fill: "currentColor", opacity: 0.6 })] }));
|
|
17
|
+
}
|
|
18
|
+
/** `warming` — a bee with small, half-open wings (just checked in, not yet settled). */
|
|
19
|
+
function WarmingIcon() {
|
|
20
|
+
return (_jsxs("svg", { ...ICON_PROPS, "data-service-state": "warming", children: [_jsx(BeeBody, {}), _jsx("path", { d: "M8.2 12.4c-1.6-.6-2.6-.2-3-.7M15.8 12.4c1.6-.6 2.6-.2 3-.7", fill: "none", stroke: "currentColor", strokeWidth: 1.3, strokeLinecap: "round", opacity: 0.65 })] }));
|
|
21
|
+
}
|
|
22
|
+
/** `active` — a bee with full, wide-spread wings (settled, healthy, flying). */
|
|
23
|
+
function ActiveIcon() {
|
|
24
|
+
return (_jsxs("svg", { ...ICON_PROPS, "data-service-state": "active", children: [_jsx(BeeBody, {}), _jsx("ellipse", { cx: 5.6, cy: 10.4, rx: 2.6, ry: 1.7, fill: "none", stroke: "currentColor", strokeWidth: 1.3, transform: "rotate(-24 5.6 10.4)" }), _jsx("ellipse", { cx: 18.4, cy: 10.4, rx: 2.6, ry: 1.7, fill: "none", stroke: "currentColor", strokeWidth: 1.3, transform: "rotate(24 18.4 10.4)" })] }));
|
|
25
|
+
}
|
|
26
|
+
/** `degraded` — a bee with only ONE wing (asymmetric) plus a small caution mark. */
|
|
27
|
+
function DegradedIcon() {
|
|
28
|
+
return (_jsxs("svg", { ...ICON_PROPS, "data-service-state": "degraded", children: [_jsx(BeeBody, {}), _jsx("ellipse", { cx: 18.4, cy: 10.4, rx: 2.6, ry: 1.7, fill: "none", stroke: "currentColor", strokeWidth: 1.3, transform: "rotate(24 18.4 10.4)" }), _jsx("path", { d: "M18.4 2.4v3.6M18.4 7.4v.01", stroke: "currentColor", strokeWidth: 1.6, strokeLinecap: "round" })] }));
|
|
29
|
+
}
|
|
30
|
+
/** `error` — a bee on its back with wings crossed into an X (stopped, needs attention). */
|
|
31
|
+
function ErrorIcon() {
|
|
32
|
+
return (_jsxs("svg", { ...ICON_PROPS, "data-service-state": "error", children: [_jsx("g", { transform: "rotate(180 12 12)", children: _jsx(BeeBody, {}) }), _jsx("path", { d: "M8.6 9.6l3.4 3.4-3.4 3.4M15.4 9.6l-3.4 3.4 3.4 3.4", stroke: "currentColor", strokeWidth: 1.4, strokeLinecap: "round", opacity: 0.85 })] }));
|
|
33
|
+
}
|
|
34
|
+
/** The fail-safe fallback icon for any value outside the five locked states (svg-AC-5). */
|
|
35
|
+
function UnknownIcon() {
|
|
36
|
+
return (_jsxs("svg", { ...ICON_PROPS, "data-service-state": "unknown", children: [_jsx("circle", { cx: 12, cy: 12, r: 8, fill: "none", stroke: "currentColor", strokeWidth: 1.6, strokeDasharray: "3 3" }), _jsx("path", { d: "M12 9v4M12 15.5v.01", stroke: "currentColor", strokeWidth: 1.8, strokeLinecap: "round" })] }));
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The single shared state→icon mapping (svg-AC-4). Every consumer resolves a state's icon through
|
|
40
|
+
* THIS function only — never a per-component switch — so `/buzzing` and the health rail render the
|
|
41
|
+
* identical icon for the identical state.
|
|
42
|
+
*/
|
|
43
|
+
export function ServiceStateIcon({ state }) {
|
|
44
|
+
if (!isServiceState(state))
|
|
45
|
+
return _jsx(UnknownIcon, {});
|
|
46
|
+
const resolved = state;
|
|
47
|
+
switch (resolved) {
|
|
48
|
+
case "starting":
|
|
49
|
+
return _jsx(StartingIcon, {});
|
|
50
|
+
case "warming":
|
|
51
|
+
return _jsx(WarmingIcon, {});
|
|
52
|
+
case "active":
|
|
53
|
+
return _jsx(ActiveIcon, {});
|
|
54
|
+
case "degraded":
|
|
55
|
+
return _jsx(DegradedIcon, {});
|
|
56
|
+
case "error":
|
|
57
|
+
return _jsx(ErrorIcon, {});
|
|
58
|
+
default: {
|
|
59
|
+
const exhaustive = resolved;
|
|
60
|
+
return exhaustive;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/** A short, human label per state (used for `title`/`aria-label` alongside the icon). */
|
|
65
|
+
export const SERVICE_STATE_LABEL = {
|
|
66
|
+
starting: "starting",
|
|
67
|
+
warming: "warming up",
|
|
68
|
+
active: "active",
|
|
69
|
+
degraded: "degraded",
|
|
70
|
+
error: "error",
|
|
71
|
+
};
|
|
72
|
+
/** The color token reinforcing (never solely conveying, svg-AC-2) each state. */
|
|
73
|
+
export const SERVICE_STATE_COLOR = {
|
|
74
|
+
starting: "var(--text-tertiary)",
|
|
75
|
+
warming: "var(--severity-warning)",
|
|
76
|
+
active: "var(--verified)",
|
|
77
|
+
degraded: "var(--severity-warning)",
|
|
78
|
+
error: "var(--severity-critical)",
|
|
79
|
+
};
|
|
80
|
+
//# sourceMappingURL=service-icons.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-icons.js","sourceRoot":"","sources":["../../../src/dashboard/web/service-icons.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `/login` route's GUIDED-SETUP content — PRD-050b (b-AC-3 / b-AC-6) · PRD-003b (l-AC-1
|
|
3
|
+
* through l-AC-8, relocating this view from a pre-mount React gate to its own path).
|
|
4
|
+
*
|
|
5
|
+
* `/login` is served by hive's server ONLY when the portal gate (`gate.ts`, PRD-003a) has
|
|
6
|
+
* already determined the operator is NOT logged in (or the operator landed here directly — `/login`
|
|
7
|
+
* is gate-exempt, l-AC-3). So this module no longer decides "pre-auth vs authenticated" itself —
|
|
8
|
+
* that decision is the server's. {@link LoginScreen} renders ONE of:
|
|
9
|
+
*
|
|
10
|
+
* - the plain first-time {@link GuidedSetup} screen — a clear "let's connect your account" panel
|
|
11
|
+
* fronted by the **"First time setup"** button (b-AC-6). The button BEGINS the on-page device
|
|
12
|
+
* flow (`POST /setup/login`, proxied per l-AC-1/l-AC-2) and shows the returned `user_code` +
|
|
13
|
+
* the verification link; the daemon keeps polling → mint → persist in the background.
|
|
14
|
+
* - {@link MigrationInterrupted} / {@link CoexistenceWarning} when `/setup/state` reports one of
|
|
15
|
+
* those states (unchanged from the prior pre-auth gate; only the addressing moved).
|
|
16
|
+
*
|
|
17
|
+
* ── The live transition is a POLL, then a hard navigation (l-AC-7 / l-AC-8) ──
|
|
18
|
+
* While on `/login` this screen polls `setupState()` on an interval, exactly like the retired
|
|
19
|
+
* pre-mount gate did. The instant the login flow writes the shared credential, the next poll
|
|
20
|
+
* reports `authenticated: true`; instead of swapping to a client-rendered `<Shell>` (the old
|
|
21
|
+
* behavior), this screen does a HARD navigation (`window.location.assign("/")`) so hive's
|
|
22
|
+
* server gate re-validates health+auth and serves the authoritative next screen. This keeps the
|
|
23
|
+
* gate — not this component — as the single source of truth for "where does an authenticated
|
|
24
|
+
* operator land" (ADR-0004), and correctly falls back to `/buzzing` instead of the dashboard if
|
|
25
|
+
* the fleet happens to be unhealthy at that exact moment.
|
|
26
|
+
*
|
|
27
|
+
* ── b-AC-6: the button is PRESENT in fresh-install, ABSENT once linked ───────
|
|
28
|
+
* The "First time setup" button renders ONLY in the pre-auth branch. Once `authenticated` flips
|
|
29
|
+
* true the whole {@link GuidedSetup} subtree (button included) unmounts as this screen navigates
|
|
30
|
+
* away — so the button is structurally absent in the linked state, not merely hidden.
|
|
31
|
+
*
|
|
32
|
+
* ── No token, no secret, no portal session (l-AC-5) ──────────────────────────
|
|
33
|
+
* This screen reads only `/setup/state` (install metadata) and `/setup/login` (user_code + URIs).
|
|
34
|
+
* NO token crosses either wire (the schemas have no token field by construction), and it creates,
|
|
35
|
+
* stores, or reads no portal-specific cookie or session — credential presence via `/setup/state` is
|
|
36
|
+
* the sole source of truth (ADR-0004's rejection of a portal session).
|
|
37
|
+
*/
|
|
38
|
+
import React from "react";
|
|
39
|
+
import { type SetupStateWire, type WireClient } from "./wire.js";
|
|
40
|
+
/** How often the pre-auth screen polls `/setup/state` for the live transition (ms). */
|
|
41
|
+
export declare const SETUP_POLL_MS: 2500;
|
|
42
|
+
/**
|
|
43
|
+
* True when the setup state shows an INTERRUPTED migration (a non-terminal `migration.phase`) — the
|
|
44
|
+
* dashboard must then present the resume/rollback affordance, NEVER a clean state (d-AC-7).
|
|
45
|
+
*/
|
|
46
|
+
export declare function isMigrationInterrupted(state: SetupStateWire): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* True when the setup state shows a PRIOR Hivemind install that has NOT yet been migrated (d-AC-1) — the
|
|
49
|
+
* dashboard renders the coexistence-warning wizard rather than the plain first-time state. Keys off the
|
|
50
|
+
* derived `priorTool.hivemind === "present"` (or the raw `~/.hivemind` dir presence), and is suppressed
|
|
51
|
+
* once `priorTool.hivemind === "migrated"`.
|
|
52
|
+
*/
|
|
53
|
+
export declare function hasUnmigratedPriorHivemind(state: SetupStateWire): boolean;
|
|
54
|
+
/** Props for {@link LoginScreen} — the injected wire client + the asset base. */
|
|
55
|
+
export interface LoginScreenProps {
|
|
56
|
+
/** The wire client (injected by a unit test with a mocked fetch; defaults to the live one). */
|
|
57
|
+
readonly client?: WireClient;
|
|
58
|
+
/** The base path the host serves the logo/assets under. */
|
|
59
|
+
readonly assetBase?: string;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The guided-setup PRE-AUTH screen (b-AC-6). A single centered panel: the brand mark, a short
|
|
63
|
+
* "connect your account" line, and the "First time setup" button that begins the on-page login. Once
|
|
64
|
+
* the login grant arrives the panel shows the `user_code` + the verification link (the daemon polls →
|
|
65
|
+
* persists in the background; the parent {@link LoginScreen} polls `/setup/state` and hard-navigates
|
|
66
|
+
* to the dashboard when the credential lands). The migration variant (a detected prior Hivemind) is 050d.
|
|
67
|
+
*/
|
|
68
|
+
export declare function GuidedSetup({ wire, assetBase, state, }: {
|
|
69
|
+
wire: WireClient;
|
|
70
|
+
assetBase: string;
|
|
71
|
+
state: SetupStateWire;
|
|
72
|
+
}): React.JSX.Element;
|
|
73
|
+
/**
|
|
74
|
+
* The COEXISTENCE-WARNING wizard — PRD-050d (d-AC-1 / d-AC-2 / d-AC-3 / d-AC-4). Renders instead of the
|
|
75
|
+
* plain first-time {@link GuidedSetup} when a prior, un-migrated Hivemind install is detected. It states
|
|
76
|
+
* — BEFORE any destructive action — that running Hivemind and Honeycomb together is UNSUPPORTED and what
|
|
77
|
+
* "Proceed with Honeycomb" does (back up + uninstall Hivemind, then reuse the shared login), then gates
|
|
78
|
+
* the migrate call behind an explicit CONFIRM step (d-AC-2).
|
|
79
|
+
*
|
|
80
|
+
* On "Proceed" it POSTs `migrateFromHivemind`: a `migrated` result lets the parent's `/setup/state` poll
|
|
81
|
+
* flip to the dashboard (no re-auth — the shared credential was adopted, d-AC-4); a `needsLogin` result
|
|
82
|
+
* hands off to the on-page device flow ({@link GuidedSetup}'s login button, the 050c `--ref mario` flow);
|
|
83
|
+
* an `ok:false` partial failure shows the plain-language message + the backup path (d-AC-5), never a stack.
|
|
84
|
+
*/
|
|
85
|
+
export declare function CoexistenceWarning({ wire, assetBase, onNeedsLogin, }: {
|
|
86
|
+
wire: WireClient;
|
|
87
|
+
assetBase: string;
|
|
88
|
+
/** Called when the migration completed the uninstall but needs the device flow to finish linking (d-AC-4). */
|
|
89
|
+
onNeedsLogin: () => void;
|
|
90
|
+
}): React.JSX.Element;
|
|
91
|
+
/**
|
|
92
|
+
* The INTERRUPTED-MIGRATION surface — PRD-050d (d-AC-7). Rendered when `/setup/state` reports a
|
|
93
|
+
* NON-TERMINAL `migration.phase` (a daemon crash mid-migration). It NEVER presents the machine as cleanly
|
|
94
|
+
* migrated or cleanly reverted: it states the migration was interrupted and offers RESUME (re-run the
|
|
95
|
+
* idempotent migration) or ROLL BACK (restore the Hivemind backup). The backup path is shown for trust.
|
|
96
|
+
*/
|
|
97
|
+
export declare function MigrationInterrupted({ wire, assetBase, state, onNeedsLogin, }: {
|
|
98
|
+
wire: WireClient;
|
|
99
|
+
assetBase: string;
|
|
100
|
+
state: SetupStateWire;
|
|
101
|
+
onNeedsLogin: () => void;
|
|
102
|
+
}): React.JSX.Element;
|
|
103
|
+
/**
|
|
104
|
+
* The `/login` route's top-level content (b-AC-3 / b-AC-6 / d-AC-1 / d-AC-7 / l-AC-1 / l-AC-7 /
|
|
105
|
+
* l-AC-8). Polls `/setup/state` and renders ONE of:
|
|
106
|
+
* - the {@link MigrationInterrupted} resume/rollback surface when a migration is mid-flight (d-AC-7);
|
|
107
|
+
* - the {@link CoexistenceWarning} wizard when a prior un-migrated Hivemind is detected (d-AC-1);
|
|
108
|
+
* - the plain first-time {@link GuidedSetup} otherwise (l-AC-1).
|
|
109
|
+
* Once `/setup/state.authenticated` flips true, this screen does a HARD navigation to `/` instead
|
|
110
|
+
* of rendering the dashboard itself (l-AC-7 / l-AC-8) — see the module doc for why that stays the
|
|
111
|
+
* server gate's decision, not this component's.
|
|
112
|
+
*
|
|
113
|
+
* The FIRST render shows the guided-setup state (the fresh-install-safe default) until the first
|
|
114
|
+
* poll resolves, so a slow first read never flashes a stale state.
|
|
115
|
+
*/
|
|
116
|
+
export declare function LoginScreen({ client, assetBase }?: LoginScreenProps): React.JSX.Element;
|