@hansenexus/hud 0.1.0 → 0.2.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/README.md +42 -23
- package/dist/index.d.ts +39 -0
- package/dist/index.js +399 -0
- package/package.json +45 -136
- package/chunk-0cj8dkk7.js +0 -127
- package/chunk-1atxwdhw.js +0 -48
- package/chunk-24vrg16w.js +0 -39
- package/chunk-3j9sm249.js +0 -26
- package/chunk-50pq4sg6.js +0 -41
- package/chunk-5gtx3pza.js +0 -9
- package/chunk-6gw4x08j.js +0 -264
- package/chunk-6jt8yg4m.js +0 -117
- package/chunk-71se605m.js +0 -85
- package/chunk-82nm9wcg.js +0 -316
- package/chunk-8tam7r3h.js +0 -68
- package/chunk-babjpqkb.js +0 -52
- package/chunk-c5y856ad.js +0 -98
- package/chunk-ghxh8926.js +0 -172
- package/chunk-hc2g0n35.js +0 -24
- package/chunk-k0vr8dsy.js +0 -179
- package/chunk-k50yfp5d.js +0 -166
- package/chunk-kyeb6qeq.js +0 -95
- package/chunk-msqkkqw7.js +0 -140
- package/chunk-nm82wr8r.js +0 -58
- package/chunk-r06bpmy6.js +0 -79
- package/chunk-t9eh4t0b.js +0 -89
- package/chunk-tf774c4w.js +0 -115
- package/chunk-v086j53b.js +0 -19
- package/chunk-wspz08q7.js +0 -67
- package/chunk-xezxydm3.js +0 -47
- package/chunk-xjn0896g.js +0 -574
- package/chunk-xztw0xyt.js +0 -113
- package/chunk-zzrpd92r.js +0 -172
- package/core/access.d.mts +0 -53
- package/core/access.js +0 -27
- package/core/api-types.d.mts +0 -146
- package/core/api-types.js +0 -9
- package/core/capabilities.d.mts +0 -27
- package/core/capabilities.js +0 -14
- package/core/capture-buffer.d.mts +0 -37
- package/core/capture-buffer.js +0 -9
- package/core/force-state.d.mts +0 -68
- package/core/force-state.js +0 -21
- package/core/mock-cookie.d.mts +0 -30
- package/core/mock-cookie.js +0 -15
- package/core/types.d.mts +0 -59
- package/core/types.js +0 -9
- package/hud-provider.d.mts +0 -38
- package/hud-provider.js +0 -15
- package/hud.d.mts +0 -15
- package/hud.js +0 -18
- package/index.d.mts +0 -94
- package/index.js +0 -170
- package/lazy-panel.d.mts +0 -28
- package/lazy-panel.js +0 -11
- package/panels/cicd-panel.d.mts +0 -9
- package/panels/cicd-panel.js +0 -13
- package/panels/debug-info-panel.d.mts +0 -21
- package/panels/debug-info-panel.js +0 -9
- package/panels/dispatch-panel.d.mts +0 -10
- package/panels/dispatch-panel.js +0 -14
- package/panels/env-info-panel.d.mts +0 -9
- package/panels/env-info-panel.js +0 -12
- package/panels/feature-flags-panel.d.mts +0 -26
- package/panels/feature-flags-panel.js +0 -9
- package/panels/force-state-panel.d.mts +0 -11
- package/panels/force-state-panel.js +0 -113
- package/panels/info-row.d.mts +0 -21
- package/panels/info-row.js +0 -14
- package/panels/mock-seed-panel.d.mts +0 -15
- package/panels/mock-seed-panel.js +0 -14
- package/panels/network-console-panel.d.mts +0 -6
- package/panels/network-console-panel.js +0 -9
- package/panels/role-switcher-panel.d.mts +0 -28
- package/panels/role-switcher-panel.js +0 -9
- package/panels/sessions-panel.d.mts +0 -6
- package/panels/sessions-panel.js +0 -13
- package/panels/tokens-panel.d.mts +0 -38
- package/panels/tokens-panel.js +0 -9
- package/panels/unlock-panel.d.mts +0 -33
- package/panels/unlock-panel.js +0 -14
- package/panels/variants-panel.d.mts +0 -51
- package/panels/variants-panel.js +0 -12
- package/panels/vitals-panel.d.mts +0 -11
- package/panels/vitals-panel.js +0 -15
- package/server/guard.d.mts +0 -42
- package/server/guard.js +0 -12
- package/server/unlock.d.mts +0 -28
- package/server/unlock.js +0 -108
- package/state-boundary.d.mts +0 -25
- package/state-boundary.js +0 -54
package/chunk-6gw4x08j.js
DELETED
|
@@ -1,264 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
bridgeFetch,
|
|
3
|
-
getBridgeInfo
|
|
4
|
-
} from "./chunk-50pq4sg6.js";
|
|
5
|
-
import {
|
|
6
|
-
clearGrabbedPayload,
|
|
7
|
-
getGrabberState,
|
|
8
|
-
startGrab,
|
|
9
|
-
subscribeGrabber,
|
|
10
|
-
useDevDrawer
|
|
11
|
-
} from "./chunk-82nm9wcg.js";
|
|
12
|
-
import {
|
|
13
|
-
useHud
|
|
14
|
-
} from "./chunk-wspz08q7.js";
|
|
15
|
-
import {
|
|
16
|
-
LoadingSpinner,
|
|
17
|
-
PanelSection
|
|
18
|
-
} from "./chunk-kyeb6qeq.js";
|
|
19
|
-
import {
|
|
20
|
-
Badge,
|
|
21
|
-
Button
|
|
22
|
-
} from "./chunk-xztw0xyt.js";
|
|
23
|
-
|
|
24
|
-
// panels/dispatch-panel.tsx
|
|
25
|
-
import { Crosshair, Send, X } from "lucide-react";
|
|
26
|
-
import { useEffect, useMemo, useState, useSyncExternalStore } from "react";
|
|
27
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
28
|
-
"use client";
|
|
29
|
-
function DispatchPanel() {
|
|
30
|
-
const { config } = useHud();
|
|
31
|
-
const { closeDrawer } = useDevDrawer();
|
|
32
|
-
const grabber = useSyncExternalStore(subscribeGrabber, getGrabberState, getGrabberState);
|
|
33
|
-
const [bridge, setBridge] = useState(undefined);
|
|
34
|
-
const [target, setTarget] = useState("docket");
|
|
35
|
-
const [note, setNote] = useState("");
|
|
36
|
-
const [runs, setRuns] = useState([]);
|
|
37
|
-
const apiBase = config.apiBase ?? "/api/hud";
|
|
38
|
-
useEffect(() => {
|
|
39
|
-
let cancelled = false;
|
|
40
|
-
getBridgeInfo(apiBase).then((info) => {
|
|
41
|
-
if (cancelled)
|
|
42
|
-
return;
|
|
43
|
-
setBridge(info);
|
|
44
|
-
if (!info)
|
|
45
|
-
setTarget("hermes");
|
|
46
|
-
});
|
|
47
|
-
return () => {
|
|
48
|
-
cancelled = true;
|
|
49
|
-
};
|
|
50
|
-
}, [apiBase]);
|
|
51
|
-
const payload = grabber.payload;
|
|
52
|
-
const targets = useMemo(() => [
|
|
53
|
-
{
|
|
54
|
-
id: "docket",
|
|
55
|
-
label: "Local Claude session (docket)",
|
|
56
|
-
detail: "worktree + claude -p via the bridge — events land on the docket board",
|
|
57
|
-
enabled: bridge != null,
|
|
58
|
-
disabledReason: "bridge not reachable (run `bun hud:bridge` in the repo)"
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
id: "queue",
|
|
62
|
-
label: "Queue marker (.claude/queue)",
|
|
63
|
-
detail: "human in the loop — the next Claude session picks it up",
|
|
64
|
-
enabled: bridge != null,
|
|
65
|
-
disabledReason: "bridge not reachable"
|
|
66
|
-
},
|
|
67
|
-
{
|
|
68
|
-
id: "hermes",
|
|
69
|
-
label: "Hermes (remote)",
|
|
70
|
-
detail: "via the console hub → hermes-dispatch workflow, tier balanced",
|
|
71
|
-
enabled: true,
|
|
72
|
-
disabledReason: ""
|
|
73
|
-
}
|
|
74
|
-
], [bridge]);
|
|
75
|
-
async function send() {
|
|
76
|
-
if (!payload)
|
|
77
|
-
return;
|
|
78
|
-
const title = `${payload.anchor.label} — ${note.slice(0, 60) || "hud dispatch"}`;
|
|
79
|
-
const localId = `local-${Date.now()}`;
|
|
80
|
-
setRuns((prev) => [{ id: localId, title, target, status: "sending" }, ...prev]);
|
|
81
|
-
clearGrabbedPayload();
|
|
82
|
-
setNote("");
|
|
83
|
-
try {
|
|
84
|
-
let res;
|
|
85
|
-
if (target === "hermes") {
|
|
86
|
-
res = await fetch(`${apiBase}/dispatch`, {
|
|
87
|
-
method: "POST",
|
|
88
|
-
headers: { "Content-Type": "application/json", "x-hud-internal": "1" },
|
|
89
|
-
body: JSON.stringify({ target, note, payload })
|
|
90
|
-
});
|
|
91
|
-
} else {
|
|
92
|
-
if (!bridge)
|
|
93
|
-
throw new Error("bridge not reachable");
|
|
94
|
-
res = await bridgeFetch(bridge, "/dispatch", {
|
|
95
|
-
method: "POST",
|
|
96
|
-
body: JSON.stringify({ target, note, payload })
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
const body = await res.json();
|
|
100
|
-
setRuns((prev) => prev.map((run) => run.id === localId ? {
|
|
101
|
-
...run,
|
|
102
|
-
status: body.ok ? "dispatched" : "failed",
|
|
103
|
-
detail: body.runId ?? body.markerPath ?? body.error
|
|
104
|
-
} : run));
|
|
105
|
-
} catch (error) {
|
|
106
|
-
setRuns((prev) => prev.map((run) => run.id === localId ? {
|
|
107
|
-
...run,
|
|
108
|
-
status: "failed",
|
|
109
|
-
detail: error instanceof Error ? error.message : "dispatch failed"
|
|
110
|
-
} : run));
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
114
|
-
className: "space-y-4",
|
|
115
|
-
children: [
|
|
116
|
-
!payload && /* @__PURE__ */ jsx(PanelSection, {
|
|
117
|
-
icon: Crosshair,
|
|
118
|
-
title: "Grab an element",
|
|
119
|
-
children: /* @__PURE__ */ jsxs("div", {
|
|
120
|
-
className: "px-2",
|
|
121
|
-
children: [
|
|
122
|
-
/* @__PURE__ */ jsxs(Button, {
|
|
123
|
-
size: "sm",
|
|
124
|
-
className: "h-7 text-xs",
|
|
125
|
-
onClick: () => {
|
|
126
|
-
closeDrawer();
|
|
127
|
-
startGrab();
|
|
128
|
-
},
|
|
129
|
-
children: [
|
|
130
|
-
/* @__PURE__ */ jsx(Crosshair, {
|
|
131
|
-
className: "mr-1.5 h-3.5 w-3.5"
|
|
132
|
-
}),
|
|
133
|
-
"Grab element"
|
|
134
|
-
]
|
|
135
|
-
}),
|
|
136
|
-
/* @__PURE__ */ jsx("p", {
|
|
137
|
-
className: "mt-2 text-[10px] text-muted-foreground/60",
|
|
138
|
-
children: "Click any element on the page — selector, source hints, recent errors, and vitals become the dispatch payload."
|
|
139
|
-
})
|
|
140
|
-
]
|
|
141
|
-
})
|
|
142
|
-
}),
|
|
143
|
-
payload && /* @__PURE__ */ jsx(PanelSection, {
|
|
144
|
-
icon: Send,
|
|
145
|
-
title: "Dispatch",
|
|
146
|
-
children: /* @__PURE__ */ jsxs("div", {
|
|
147
|
-
className: "space-y-2 px-2",
|
|
148
|
-
children: [
|
|
149
|
-
/* @__PURE__ */ jsx(PayloadPreview, {
|
|
150
|
-
payload,
|
|
151
|
-
onDiscard: clearGrabbedPayload
|
|
152
|
-
}),
|
|
153
|
-
/* @__PURE__ */ jsx("textarea", {
|
|
154
|
-
value: note,
|
|
155
|
-
onChange: (e) => setNote(e.target.value),
|
|
156
|
-
placeholder: "Instruction, e.g.: button feels heavy — try a ghost variant",
|
|
157
|
-
className: "min-h-[52px] w-full rounded-md border bg-muted/20 p-2 font-mono text-[11px] outline-none focus:ring-1 focus:ring-ring"
|
|
158
|
-
}),
|
|
159
|
-
/* @__PURE__ */ jsx("div", {
|
|
160
|
-
className: "space-y-1",
|
|
161
|
-
children: targets.map((t) => /* @__PURE__ */ jsxs("label", {
|
|
162
|
-
className: `flex cursor-pointer items-start gap-2 rounded-md border p-2 ${target === t.id ? "border-primary/60 bg-muted/30" : "border-border/50"} ${t.enabled ? "" : "cursor-not-allowed opacity-50"}`,
|
|
163
|
-
children: [
|
|
164
|
-
/* @__PURE__ */ jsx("input", {
|
|
165
|
-
type: "radio",
|
|
166
|
-
name: "hud-dispatch-target",
|
|
167
|
-
checked: target === t.id,
|
|
168
|
-
disabled: !t.enabled,
|
|
169
|
-
onChange: () => setTarget(t.id),
|
|
170
|
-
className: "mt-0.5"
|
|
171
|
-
}),
|
|
172
|
-
/* @__PURE__ */ jsxs("span", {
|
|
173
|
-
children: [
|
|
174
|
-
/* @__PURE__ */ jsx("span", {
|
|
175
|
-
className: "block text-xs font-medium",
|
|
176
|
-
children: t.label
|
|
177
|
-
}),
|
|
178
|
-
/* @__PURE__ */ jsx("span", {
|
|
179
|
-
className: "block text-[10px] text-muted-foreground",
|
|
180
|
-
children: t.enabled ? t.detail : t.disabledReason
|
|
181
|
-
})
|
|
182
|
-
]
|
|
183
|
-
})
|
|
184
|
-
]
|
|
185
|
-
}, t.id))
|
|
186
|
-
}),
|
|
187
|
-
/* @__PURE__ */ jsxs(Button, {
|
|
188
|
-
size: "sm",
|
|
189
|
-
className: "h-7 text-xs",
|
|
190
|
-
onClick: send,
|
|
191
|
-
children: [
|
|
192
|
-
/* @__PURE__ */ jsx(Send, {
|
|
193
|
-
className: "mr-1.5 h-3 w-3"
|
|
194
|
-
}),
|
|
195
|
-
"Dispatch"
|
|
196
|
-
]
|
|
197
|
-
})
|
|
198
|
-
]
|
|
199
|
-
})
|
|
200
|
-
}),
|
|
201
|
-
bridge === undefined && /* @__PURE__ */ jsx(LoadingSpinner, {}),
|
|
202
|
-
runs.length > 0 && /* @__PURE__ */ jsx(PanelSection, {
|
|
203
|
-
title: "Dispatched from this session",
|
|
204
|
-
children: runs.map((run) => /* @__PURE__ */ jsxs("div", {
|
|
205
|
-
className: "flex items-center gap-2 px-2 py-1 font-mono text-[10.5px]",
|
|
206
|
-
children: [
|
|
207
|
-
/* @__PURE__ */ jsx(Badge, {
|
|
208
|
-
variant: "outline",
|
|
209
|
-
className: `h-4 px-1.5 text-[9px] ${run.status === "dispatched" ? "text-emerald-500" : run.status === "failed" ? "text-red-500" : "text-amber-500"}`,
|
|
210
|
-
children: run.status
|
|
211
|
-
}),
|
|
212
|
-
/* @__PURE__ */ jsx("span", {
|
|
213
|
-
className: "min-w-0 flex-1 truncate",
|
|
214
|
-
children: run.title
|
|
215
|
-
}),
|
|
216
|
-
/* @__PURE__ */ jsx("span", {
|
|
217
|
-
className: "text-muted-foreground/60",
|
|
218
|
-
children: run.target
|
|
219
|
-
}),
|
|
220
|
-
run.detail && /* @__PURE__ */ jsx("span", {
|
|
221
|
-
className: "max-w-[180px] truncate text-muted-foreground/60",
|
|
222
|
-
title: run.detail,
|
|
223
|
-
children: run.detail
|
|
224
|
-
})
|
|
225
|
-
]
|
|
226
|
-
}, run.id))
|
|
227
|
-
})
|
|
228
|
-
]
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
function PayloadPreview({
|
|
232
|
-
payload,
|
|
233
|
-
onDiscard
|
|
234
|
-
}) {
|
|
235
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
236
|
-
className: "rounded-md border bg-muted/20 p-2",
|
|
237
|
-
children: [
|
|
238
|
-
/* @__PURE__ */ jsxs("div", {
|
|
239
|
-
className: "flex items-center gap-2",
|
|
240
|
-
children: [
|
|
241
|
-
/* @__PURE__ */ jsx("span", {
|
|
242
|
-
className: "min-w-0 flex-1 truncate font-mono text-[11px]",
|
|
243
|
-
children: payload.anchor.label
|
|
244
|
-
}),
|
|
245
|
-
/* @__PURE__ */ jsx(Button, {
|
|
246
|
-
variant: "ghost",
|
|
247
|
-
size: "icon",
|
|
248
|
-
className: "h-5 w-5",
|
|
249
|
-
onClick: onDiscard,
|
|
250
|
-
children: /* @__PURE__ */ jsx(X, {
|
|
251
|
-
className: "h-3 w-3"
|
|
252
|
-
})
|
|
253
|
-
})
|
|
254
|
-
]
|
|
255
|
-
}),
|
|
256
|
-
/* @__PURE__ */ jsx("pre", {
|
|
257
|
-
className: "mt-1 max-h-40 overflow-auto text-[9.5px] leading-relaxed text-muted-foreground",
|
|
258
|
-
children: JSON.stringify(payload, null, 2)
|
|
259
|
-
})
|
|
260
|
-
]
|
|
261
|
-
});
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
export { DispatchPanel };
|
package/chunk-6jt8yg4m.js
DELETED
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
LoadingSpinner,
|
|
3
|
-
PanelSection
|
|
4
|
-
} from "./chunk-kyeb6qeq.js";
|
|
5
|
-
import {
|
|
6
|
-
Badge,
|
|
7
|
-
Button
|
|
8
|
-
} from "./chunk-xztw0xyt.js";
|
|
9
|
-
|
|
10
|
-
// panels/role-switcher-panel.tsx
|
|
11
|
-
import { Check, Shield, User } from "lucide-react";
|
|
12
|
-
import { useState } from "react";
|
|
13
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
14
|
-
"use client";
|
|
15
|
-
function RoleSwitcherPanel({ adapter }) {
|
|
16
|
-
const { roles, currentRoleId, currentUserLabel, isLoading = false, onSwitch } = adapter;
|
|
17
|
-
const [switching, setSwitching] = useState(false);
|
|
18
|
-
const [error, setError] = useState(null);
|
|
19
|
-
async function handleSwitch(roleId) {
|
|
20
|
-
if (roleId === currentRoleId)
|
|
21
|
-
return;
|
|
22
|
-
setSwitching(true);
|
|
23
|
-
setError(null);
|
|
24
|
-
try {
|
|
25
|
-
await onSwitch(roleId);
|
|
26
|
-
} catch (err) {
|
|
27
|
-
setError(err instanceof Error ? err.message : "Role switch failed");
|
|
28
|
-
} finally {
|
|
29
|
-
setSwitching(false);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
if (isLoading)
|
|
33
|
-
return /* @__PURE__ */ jsx(LoadingSpinner, {});
|
|
34
|
-
const current = roles.find((role) => role.id === currentRoleId);
|
|
35
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
36
|
-
className: "space-y-4",
|
|
37
|
-
children: [
|
|
38
|
-
/* @__PURE__ */ jsx(PanelSection, {
|
|
39
|
-
icon: Shield,
|
|
40
|
-
title: "Current Role",
|
|
41
|
-
children: /* @__PURE__ */ jsxs("div", {
|
|
42
|
-
className: "border bg-muted/30 px-3 py-2",
|
|
43
|
-
children: [
|
|
44
|
-
/* @__PURE__ */ jsxs("div", {
|
|
45
|
-
className: "flex items-center gap-2",
|
|
46
|
-
children: [
|
|
47
|
-
/* @__PURE__ */ jsx(User, {
|
|
48
|
-
className: "h-4 w-4 text-muted-foreground"
|
|
49
|
-
}),
|
|
50
|
-
/* @__PURE__ */ jsx("span", {
|
|
51
|
-
className: "text-sm font-medium",
|
|
52
|
-
children: currentUserLabel ?? "Unknown"
|
|
53
|
-
})
|
|
54
|
-
]
|
|
55
|
-
}),
|
|
56
|
-
/* @__PURE__ */ jsx(Badge, {
|
|
57
|
-
variant: "outline",
|
|
58
|
-
className: `mt-1 ${current?.badgeClassName ?? ""}`,
|
|
59
|
-
children: current?.label ?? currentRoleId ?? "—"
|
|
60
|
-
})
|
|
61
|
-
]
|
|
62
|
-
})
|
|
63
|
-
}),
|
|
64
|
-
/* @__PURE__ */ jsx(PanelSection, {
|
|
65
|
-
title: "Switch Role",
|
|
66
|
-
children: roles.map((role) => {
|
|
67
|
-
const isCurrent = role.id === currentRoleId;
|
|
68
|
-
return /* @__PURE__ */ jsxs(Button, {
|
|
69
|
-
variant: "ghost",
|
|
70
|
-
size: "sm",
|
|
71
|
-
disabled: isCurrent || switching,
|
|
72
|
-
className: "w-full justify-between text-xs",
|
|
73
|
-
onClick: () => handleSwitch(role.id),
|
|
74
|
-
children: [
|
|
75
|
-
/* @__PURE__ */ jsxs("div", {
|
|
76
|
-
className: "flex items-center gap-2",
|
|
77
|
-
children: [
|
|
78
|
-
/* @__PURE__ */ jsx("span", {
|
|
79
|
-
className: `h-2 w-2 rounded-full ${isCurrent ? "bg-primary" : "bg-muted-foreground/30"}`
|
|
80
|
-
}),
|
|
81
|
-
/* @__PURE__ */ jsx("span", {
|
|
82
|
-
children: role.label
|
|
83
|
-
})
|
|
84
|
-
]
|
|
85
|
-
}),
|
|
86
|
-
/* @__PURE__ */ jsxs("div", {
|
|
87
|
-
className: "flex items-center gap-1.5",
|
|
88
|
-
children: [
|
|
89
|
-
role.level !== undefined && /* @__PURE__ */ jsxs("span", {
|
|
90
|
-
className: "text-[10px] text-muted-foreground",
|
|
91
|
-
children: [
|
|
92
|
-
"Lvl ",
|
|
93
|
-
role.level
|
|
94
|
-
]
|
|
95
|
-
}),
|
|
96
|
-
isCurrent && /* @__PURE__ */ jsx(Check, {
|
|
97
|
-
className: "h-3 w-3 text-primary"
|
|
98
|
-
})
|
|
99
|
-
]
|
|
100
|
-
})
|
|
101
|
-
]
|
|
102
|
-
}, role.id);
|
|
103
|
-
})
|
|
104
|
-
}),
|
|
105
|
-
error && /* @__PURE__ */ jsx("p", {
|
|
106
|
-
className: "px-2 text-[10px] text-destructive",
|
|
107
|
-
children: error
|
|
108
|
-
}),
|
|
109
|
-
/* @__PURE__ */ jsx("p", {
|
|
110
|
-
className: "text-[10px] text-muted-foreground/60",
|
|
111
|
-
children: "Role changes take effect immediately. Use this for testing role-based access."
|
|
112
|
-
})
|
|
113
|
-
]
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
export { RoleSwitcherPanel };
|
package/chunk-71se605m.js
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
LoadingSpinner
|
|
3
|
-
} from "./chunk-kyeb6qeq.js";
|
|
4
|
-
import {
|
|
5
|
-
Badge,
|
|
6
|
-
Switch
|
|
7
|
-
} from "./chunk-xztw0xyt.js";
|
|
8
|
-
|
|
9
|
-
// panels/feature-flags-panel.tsx
|
|
10
|
-
import { Flag } from "lucide-react";
|
|
11
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
12
|
-
"use client";
|
|
13
|
-
function FeatureFlagsPanel({ adapter }) {
|
|
14
|
-
const { flags, isLoading = false, onToggle } = adapter;
|
|
15
|
-
if (isLoading)
|
|
16
|
-
return /* @__PURE__ */ jsx(LoadingSpinner, {});
|
|
17
|
-
const categories = [...new Set(flags.map((flag) => flag.category ?? "general"))];
|
|
18
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
19
|
-
className: "space-y-4",
|
|
20
|
-
children: [
|
|
21
|
-
categories.map((category) => /* @__PURE__ */ jsxs("div", {
|
|
22
|
-
children: [
|
|
23
|
-
/* @__PURE__ */ jsxs("h4", {
|
|
24
|
-
className: "mb-2 flex items-center gap-1.5 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground",
|
|
25
|
-
children: [
|
|
26
|
-
/* @__PURE__ */ jsx(Flag, {
|
|
27
|
-
className: "h-3 w-3"
|
|
28
|
-
}),
|
|
29
|
-
category
|
|
30
|
-
]
|
|
31
|
-
}),
|
|
32
|
-
/* @__PURE__ */ jsx("div", {
|
|
33
|
-
className: "space-y-1",
|
|
34
|
-
children: flags.filter((flag) => (flag.category ?? "general") === category).map((flag) => /* @__PURE__ */ jsx(FlagRow, {
|
|
35
|
-
flag,
|
|
36
|
-
onToggle: () => void onToggle(flag.id)
|
|
37
|
-
}, flag.id))
|
|
38
|
-
})
|
|
39
|
-
]
|
|
40
|
-
}, category)),
|
|
41
|
-
flags.length === 0 && /* @__PURE__ */ jsx("p", {
|
|
42
|
-
className: "px-2 text-[10px] text-muted-foreground/60",
|
|
43
|
-
children: "No flags registered."
|
|
44
|
-
})
|
|
45
|
-
]
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
function FlagRow({ flag, onToggle }) {
|
|
49
|
-
const isOverridden = flag.enabled !== flag.defaultValue;
|
|
50
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
51
|
-
className: "flex items-center justify-between px-2 py-1.5 hover:bg-muted/50",
|
|
52
|
-
children: [
|
|
53
|
-
/* @__PURE__ */ jsxs("div", {
|
|
54
|
-
className: "min-w-0 flex-1",
|
|
55
|
-
children: [
|
|
56
|
-
/* @__PURE__ */ jsxs("div", {
|
|
57
|
-
className: "flex items-center gap-1.5",
|
|
58
|
-
children: [
|
|
59
|
-
/* @__PURE__ */ jsx("span", {
|
|
60
|
-
className: "text-xs font-medium",
|
|
61
|
-
children: flag.label
|
|
62
|
-
}),
|
|
63
|
-
isOverridden && /* @__PURE__ */ jsx(Badge, {
|
|
64
|
-
variant: "outline",
|
|
65
|
-
className: "h-4 border-amber-500/50 px-1 text-[9px] text-amber-500",
|
|
66
|
-
children: "overridden"
|
|
67
|
-
})
|
|
68
|
-
]
|
|
69
|
-
}),
|
|
70
|
-
flag.description && /* @__PURE__ */ jsx("p", {
|
|
71
|
-
className: "truncate text-[10px] text-muted-foreground",
|
|
72
|
-
children: flag.description
|
|
73
|
-
})
|
|
74
|
-
]
|
|
75
|
-
}),
|
|
76
|
-
/* @__PURE__ */ jsx(Switch, {
|
|
77
|
-
checked: flag.enabled,
|
|
78
|
-
onCheckedChange: onToggle,
|
|
79
|
-
className: "ml-2 shrink-0"
|
|
80
|
-
})
|
|
81
|
-
]
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export { FeatureFlagsPanel };
|