@edspencer/paddock 0.66.2 → 0.67.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/package.json +1 -1
- package/packages/server/dist/routes/chats.js +14 -2
- package/packages/server/dist/session-hub.d.ts +10 -0
- package/packages/server/dist/session-hub.js +16 -2
- package/packages/server/dist/ws-protocol.d.ts +15 -0
- package/packages/server/dist/ws.js +1 -0
- package/packages/server/package.json +1 -1
- package/packages/web/dist/assets/InstanceConfigPage-sDbCoFxC.js +2 -0
- package/packages/web/dist/assets/{MarkdownRenderer-DDVO0zhl.js → MarkdownRenderer-MaSe5aAI.js} +11 -11
- package/packages/web/dist/assets/ProjectMenu-DmWpr9od.js +2 -0
- package/packages/web/dist/assets/ProjectRedirect-BJeDERUd.js +2 -0
- package/packages/web/dist/assets/ProjectView-Bbecs1u7.js +13 -0
- package/packages/web/dist/assets/ProjectsGrid-BE4cAtu5.js +2 -0
- package/packages/web/dist/assets/Surfaces-DtSsbnLh.js +2 -0
- package/packages/web/dist/assets/{arc-DXqVnx_r.js → arc-NLb6J_GZ.js} +1 -1
- package/packages/web/dist/assets/{architectureDiagram-3BPJPVTR-FgkfD1Bk.js → architectureDiagram-3BPJPVTR-BbiSIctn.js} +1 -1
- package/packages/web/dist/assets/{blockDiagram-GPEHLZMM-WwkIIJsI.js → blockDiagram-GPEHLZMM-Br1sRzRE.js} +1 -1
- package/packages/web/dist/assets/{c4Diagram-AAUBKEIU-BIzkTibx.js → c4Diagram-AAUBKEIU-DUvJurko.js} +1 -1
- package/packages/web/dist/assets/channel-bezC0w5b.js +2 -0
- package/packages/web/dist/assets/{chunk-2J33WTMH-C4TBH3R6.js → chunk-2J33WTMH-Cm_E_LAD.js} +1 -1
- package/packages/web/dist/assets/{chunk-4BX2VUAB-DTKJZlRM.js → chunk-4BX2VUAB-CK6R2MCN.js} +1 -1
- package/packages/web/dist/assets/{chunk-55IACEB6-BC9_Qc8h.js → chunk-55IACEB6-D7HXvxGy.js} +1 -1
- package/packages/web/dist/assets/{chunk-727SXJPM-D3gQ4rP3.js → chunk-727SXJPM-BLwevzlY.js} +1 -1
- package/packages/web/dist/assets/{chunk-AQP2D5EJ-My2AXBvz.js → chunk-AQP2D5EJ-CpLWD5so.js} +1 -1
- package/packages/web/dist/assets/{chunk-FMBD7UC4-D09zE6Ow.js → chunk-FMBD7UC4-BNlt1t19.js} +1 -1
- package/packages/web/dist/assets/{chunk-ND2GUHAM-CUSgeCLl.js → chunk-ND2GUHAM-CIt5gAq8.js} +1 -1
- package/packages/web/dist/assets/{chunk-QZHKN3VN-B6jVPYgy.js → chunk-QZHKN3VN-B1uwIQ9c.js} +1 -1
- package/packages/web/dist/assets/classDiagram-4FO5ZUOK-DMgrTmQU.js +2 -0
- package/packages/web/dist/assets/classDiagram-v2-Q7XG4LA2-DMgrTmQU.js +2 -0
- package/packages/web/dist/assets/{core-DPY0seI-.js → core-HXUN76Po.js} +1 -1
- package/packages/web/dist/assets/{cose-bilkent-S5V4N54A-BasCiARv.js → cose-bilkent-S5V4N54A-DJ4_5jxB.js} +1 -1
- package/packages/web/dist/assets/{dagre-BM42HDAG-Cimn11Qe.js → dagre-BM42HDAG-Bc9-haAu.js} +1 -1
- package/packages/web/dist/assets/{diagram-2AECGRRQ-fe9cDHyn.js → diagram-2AECGRRQ-nLOtPDzu.js} +1 -1
- package/packages/web/dist/assets/{diagram-5GNKFQAL-T0tQlfbl.js → diagram-5GNKFQAL-DThV84R3.js} +1 -1
- package/packages/web/dist/assets/{diagram-KO2AKTUF-dLORrSiu.js → diagram-KO2AKTUF-C5hcR1vA.js} +1 -1
- package/packages/web/dist/assets/{diagram-LMA3HP47-iUMeaR-J.js → diagram-LMA3HP47-BEFzrSHy.js} +1 -1
- package/packages/web/dist/assets/{diagram-OG6HWLK6-oEH6olHK.js → diagram-OG6HWLK6-BY5lPsX7.js} +1 -1
- package/packages/web/dist/assets/{erDiagram-TEJ5UH35-VtQqF9SY.js → erDiagram-TEJ5UH35-y_kB8ETg.js} +1 -1
- package/packages/web/dist/assets/{flowDiagram-I6XJVG4X-wvF2EkJa.js → flowDiagram-I6XJVG4X-Cuhha5cF.js} +1 -1
- package/packages/web/dist/assets/{ganttDiagram-6RSMTGT7-ng4qJ0E1.js → ganttDiagram-6RSMTGT7-DFJpciK5.js} +1 -1
- package/packages/web/dist/assets/{gitGraphDiagram-PVQCEYII-BV4aWy8k.js → gitGraphDiagram-PVQCEYII-FoA0yuh-.js} +1 -1
- package/packages/web/dist/assets/index-BxLurJvz.css +1 -0
- package/packages/web/dist/assets/index-C_PXsGTD.js +71 -0
- package/packages/web/dist/assets/{infoDiagram-5YYISTIA-BpGTxAjU.js → infoDiagram-5YYISTIA-CKYqD8-c.js} +1 -1
- package/packages/web/dist/assets/{ishikawaDiagram-YF4QCWOH-Cj36LyoS.js → ishikawaDiagram-YF4QCWOH-CCIxHIBw.js} +1 -1
- package/packages/web/dist/assets/{journeyDiagram-JHISSGLW-0vNlg3um.js → journeyDiagram-JHISSGLW-lGYoSyk0.js} +1 -1
- package/packages/web/dist/assets/{kanban-definition-UN3LZRKU-wijkEDaR.js → kanban-definition-UN3LZRKU-B3D7CIwy.js} +1 -1
- package/packages/web/dist/assets/{linear-LqRymMD_.js → linear-BiplJBex.js} +1 -1
- package/packages/web/dist/assets/{mermaid.core-DPrhSs95.js → mermaid.core-BJ7aEinZ.js} +4 -4
- package/packages/web/dist/assets/{mindmap-definition-RKZ34NQL-en-uGqgC.js → mindmap-definition-RKZ34NQL-BiXcOtHo.js} +1 -1
- package/packages/web/dist/assets/{pieDiagram-4H26LBE5-DKBZ2Vnx.js → pieDiagram-4H26LBE5-tnkj45YF.js} +1 -1
- package/packages/web/dist/assets/{quadrantDiagram-W4KKPZXB--g-WtxyL.js → quadrantDiagram-W4KKPZXB-LqReq3Gl.js} +1 -1
- package/packages/web/dist/assets/{requirementDiagram-4Y6WPE33-Dl4eYxDI.js → requirementDiagram-4Y6WPE33-C1uk9Jty.js} +1 -1
- package/packages/web/dist/assets/{sankeyDiagram-5OEKKPKP-7lt4gqSw.js → sankeyDiagram-5OEKKPKP-eQQ3OKrV.js} +1 -1
- package/packages/web/dist/assets/{sequenceDiagram-3UESZ5HK-COgq-dXg.js → sequenceDiagram-3UESZ5HK-C6-a0lH4.js} +1 -1
- package/packages/web/dist/assets/{stateDiagram-AJRCARHV-CL6XC79S.js → stateDiagram-AJRCARHV-CsTOkKqz.js} +1 -1
- package/packages/web/dist/assets/stateDiagram-v2-BHNVJYJU-Bsc-VlVI.js +2 -0
- package/packages/web/dist/assets/{timeline-definition-PNZ67QCA-C5egKeGT.js → timeline-definition-PNZ67QCA-DUBXH1x-.js} +1 -1
- package/packages/web/dist/assets/{vennDiagram-CIIHVFJN-C_UhtC8u.js → vennDiagram-CIIHVFJN-CcQrNnou.js} +1 -1
- package/packages/web/dist/assets/{wardley-L42UT6IY-Bj9chUqz.js → wardley-L42UT6IY-Br823uUV.js} +1 -1
- package/packages/web/dist/assets/{wardleyDiagram-YWT4CUSO-D7VnZoRp.js → wardleyDiagram-YWT4CUSO-DRBECQc_.js} +1 -1
- package/packages/web/dist/assets/{xychartDiagram-2RQKCTM6-VrWLDoi4.js → xychartDiagram-2RQKCTM6--HtSFP24.js} +1 -1
- package/packages/web/dist/fonts/alegreya-latin-italic.woff2 +0 -0
- package/packages/web/dist/fonts/alegreya-latin.woff2 +0 -0
- package/packages/web/dist/fonts/alegreya-sc-latin-500.woff2 +0 -0
- package/packages/web/dist/fonts/alegreya-sc-latin-700.woff2 +0 -0
- package/packages/web/dist/fonts/courier-prime-latin-400.woff2 +0 -0
- package/packages/web/dist/fonts/courier-prime-latin-700.woff2 +0 -0
- package/packages/web/dist/fonts/courier-prime-latin-italic.woff2 +0 -0
- package/packages/web/dist/fonts/iosevka-terminal-400.woff2 +0 -0
- package/packages/web/dist/fonts/iosevka-terminal-700.woff2 +0 -0
- package/packages/web/dist/fonts/martian-mono-latin.woff2 +0 -0
- package/packages/web/dist/fonts/saira-latin.woff2 +0 -0
- package/packages/web/dist/index.html +61 -12
- package/packages/web/dist/sw.js +1 -1
- package/packages/web/dist/assets/InstanceConfigPage-DKzAHOhx.js +0 -2
- package/packages/web/dist/assets/ProjectRedirect-WczXTV0_.js +0 -2
- package/packages/web/dist/assets/ProjectView-Dd_myWpV.js +0 -13
- package/packages/web/dist/assets/ProjectsGrid-BeJj0q6Y.js +0 -2
- package/packages/web/dist/assets/channel-DUsOl5_p.js +0 -2
- package/packages/web/dist/assets/classDiagram-4FO5ZUOK-CIdDKEqH.js +0 -2
- package/packages/web/dist/assets/classDiagram-v2-Q7XG4LA2-CIdDKEqH.js +0 -2
- package/packages/web/dist/assets/format-CvRqOKZU.js +0 -2
- package/packages/web/dist/assets/index-DGNSeqL-.js +0 -71
- package/packages/web/dist/assets/index-DMRbU1Jl.css +0 -1
- package/packages/web/dist/assets/stateDiagram-v2-BHNVJYJU-BDlRyphY.js +0 -2
package/package.json
CHANGED
|
@@ -150,7 +150,7 @@ export function registerChatWorkspaceRoutes(app, ctx) {
|
|
|
150
150
|
schema: {
|
|
151
151
|
tags: ["Chats"],
|
|
152
152
|
summary: "List the chats in this workspace's subtree that are running or unread",
|
|
153
|
-
description: "Returns `{ running, unread }` — the chats in this workspace AND its descendants that currently have a live turn (`running`) or hold an unread reply (`unread`). Each row is a chat DTO plus the `projectSlug`/`projectName` it belongs to, so a fleet-wide list stays attributable. On the root mount (`/api/root/chats/attention`) the subtree is the whole instance, because the root workspace's key (`\"\"`) prefixes every workspace key; on a project mount it is that project alone. A chat is never in both lists: a live turn hasn't landed a reply yet, so running wins.",
|
|
153
|
+
description: "Returns `{ running, unread }` — the chats in this workspace AND its descendants that currently have a live turn (`running`) or hold an unread reply (`unread`). Each row is a chat DTO plus the `projectSlug`/`projectName` it belongs to, so a fleet-wide list stays attributable. On the root mount (`/api/root/chats/attention`) the subtree is the whole instance, because the root workspace's key (`\"\"`) prefixes every workspace key; on a project mount it is that project alone. A chat is never in both lists: a live turn hasn't landed a reply yet, so running wins. `running` rows additionally carry resolved `contextTokens`/`contextLimit` so a caller can draw a context gauge for live work; `unread` rows do not, because resolving usage streams a transcript per chat and only the running set is bounded by how many turns can be in flight at once.",
|
|
154
154
|
params: {
|
|
155
155
|
type: "object",
|
|
156
156
|
properties: {
|
|
@@ -197,7 +197,19 @@ export function registerChatWorkspaceRoutes(app, ctx) {
|
|
|
197
197
|
const provenanceOf = (s) => runProvenance.get(s.sessionId);
|
|
198
198
|
const triggerOf = makeTriggerResolver(p);
|
|
199
199
|
const parentOf = makeParentResolver(runProvenance, messageProvenance, p.slug, (id) => parentDetach.isDetached(keeper, id));
|
|
200
|
-
|
|
200
|
+
// Usage is deliberately NOT resolved for the whole subtree: it streams
|
|
201
|
+
// a transcript per chat, and this route refetches on every turn
|
|
202
|
+
// boundary across the fleet. A RUNNING chat is the one exception —
|
|
203
|
+
// every context gauge in the app (Home's running rows, the fleet
|
|
204
|
+
// readout) reads `contextTokens`/`contextLimit` off these rows, and
|
|
205
|
+
// with no resolver they were always null, so the gauges rendered
|
|
206
|
+
// blank. The running set is bounded by how many turns can be in
|
|
207
|
+
// flight at once (a handful), not by how many chats the instance
|
|
208
|
+
// holds, so the cost stays proportional to live work and not to
|
|
209
|
+
// history.
|
|
210
|
+
const usageOf = chatUsageResolver(p.dir, p.model ?? DEFAULT_MODEL);
|
|
211
|
+
const usageIfRunning = async (s) => isRunning(s.sessionId) ? usageOf(s) : null;
|
|
212
|
+
const chats = await buildProjectChats(p.dir, sessions, usageIfRunning, archivedOf, lastTurnAt, lastSeenOf, provenanceOf, triggerOf, starredOf, unreadOf, parentOf);
|
|
201
213
|
for (const c of chats) {
|
|
202
214
|
const row = { ...c, projectSlug: p.slug, projectName: p.name };
|
|
203
215
|
if (isRunning(c.sessionId)) {
|
|
@@ -72,6 +72,14 @@ interface Turn {
|
|
|
72
72
|
baseSeq: number;
|
|
73
73
|
nextSeq: number;
|
|
74
74
|
running: boolean;
|
|
75
|
+
/**
|
|
76
|
+
* Epoch-ms the turn began. The hub is the only place that knows this: a job
|
|
77
|
+
* record is written when a turn ENDS, and the transcript's own timestamps are
|
|
78
|
+
* the model's, not the run's. Surfaced on {@link ActiveInfo} so a client that
|
|
79
|
+
* loads mid-turn — or reconnects — can still say how long the fleet has been
|
|
80
|
+
* working, rather than restarting every clock at zero on every page load.
|
|
81
|
+
*/
|
|
82
|
+
startedAt: number;
|
|
75
83
|
evictTimer: ReturnType<typeof setTimeout> | null;
|
|
76
84
|
}
|
|
77
85
|
/** How long a completed turn's buffer lingers so an end-of-turn reconnect still gets the tail. */
|
|
@@ -97,6 +105,8 @@ export interface ActiveInfo {
|
|
|
97
105
|
/** The running turn's cancellable job id, if known yet (null early in a turn). */
|
|
98
106
|
jobId: string | null;
|
|
99
107
|
running: boolean;
|
|
108
|
+
/** Epoch-ms this turn started. See {@link Turn.startedAt}. */
|
|
109
|
+
startedAt: number;
|
|
100
110
|
}
|
|
101
111
|
/** Why a turn is being cancelled, and which socket asked for it. */
|
|
102
112
|
export interface CancelIntent {
|
|
@@ -107,6 +107,7 @@ export class SessionHub {
|
|
|
107
107
|
baseSeq: 0,
|
|
108
108
|
nextSeq: 0,
|
|
109
109
|
running: true,
|
|
110
|
+
startedAt: Date.now(),
|
|
110
111
|
evictTimer: null,
|
|
111
112
|
};
|
|
112
113
|
const handle = new TurnHandle(this, turn);
|
|
@@ -203,14 +204,26 @@ export class SessionHub {
|
|
|
203
204
|
const turn = this.bySession.get(sessionId);
|
|
204
205
|
if (!turn || !turn.running)
|
|
205
206
|
return null;
|
|
206
|
-
return {
|
|
207
|
+
return {
|
|
208
|
+
sessionId,
|
|
209
|
+
projectSlug: turn.projectSlug,
|
|
210
|
+
jobId: turn.jobId,
|
|
211
|
+
running: true,
|
|
212
|
+
startedAt: turn.startedAt,
|
|
213
|
+
};
|
|
207
214
|
}
|
|
208
215
|
/** Snapshot of every session with a running turn (for a newly-connected client). */
|
|
209
216
|
runningSessions() {
|
|
210
217
|
const out = [];
|
|
211
218
|
for (const [sessionId, turn] of this.bySession) {
|
|
212
219
|
if (turn.running) {
|
|
213
|
-
out.push({
|
|
220
|
+
out.push({
|
|
221
|
+
sessionId,
|
|
222
|
+
projectSlug: turn.projectSlug,
|
|
223
|
+
jobId: turn.jobId,
|
|
224
|
+
running: true,
|
|
225
|
+
startedAt: turn.startedAt,
|
|
226
|
+
});
|
|
214
227
|
}
|
|
215
228
|
}
|
|
216
229
|
return out;
|
|
@@ -288,6 +301,7 @@ export class SessionHub {
|
|
|
288
301
|
projectSlug: turn.projectSlug,
|
|
289
302
|
jobId: turn.jobId,
|
|
290
303
|
running: turn.running,
|
|
304
|
+
startedAt: turn.startedAt,
|
|
291
305
|
});
|
|
292
306
|
}
|
|
293
307
|
recipients(turn) {
|
|
@@ -393,6 +393,21 @@ export interface ChatActiveMessage {
|
|
|
393
393
|
/** The running turn's cancellable job id, when known. */
|
|
394
394
|
jobId: string | null;
|
|
395
395
|
running: boolean;
|
|
396
|
+
/**
|
|
397
|
+
* Epoch-ms the running turn began, from the session hub. The hub is the only
|
|
398
|
+
* thing that knows: a job record is written when a turn ENDS, and the
|
|
399
|
+
* transcript's timestamps are the model's rather than the run's. Because the
|
|
400
|
+
* server replays its whole running snapshot to every socket on connect, a
|
|
401
|
+
* client that reloads mid-turn still learns the true start — which is what
|
|
402
|
+
* lets a fleet readout say "running 12:04" instead of restarting at zero on
|
|
403
|
+
* every page load.
|
|
404
|
+
*
|
|
405
|
+
* Sent on the STOP frame too (`running: false`), where it describes the turn
|
|
406
|
+
* that just ended and a client has no use for it — the hub emits one frame
|
|
407
|
+
* shape for both transitions rather than branching. Optional on the wire so
|
|
408
|
+
* a client built against an older server still parses the frame.
|
|
409
|
+
*/
|
|
410
|
+
startedAt?: number;
|
|
396
411
|
};
|
|
397
412
|
}
|
|
398
413
|
/**
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{j as e,l as f,r as c,q as Z,s as ee,t as te,v as ve,w as ie,x as le,y as ye,z as we,D as oe,E as Ne,F as ke,b as F,A as ce,G as Ce,X as Se,H as Ae,I as Ee,J as Re,K as $e,O as Me}from"./index-C_PXsGTD.js";import{B as R,S as ne}from"./Surfaces-DtSsbnLh.js";const K=["w-full rounded-lg border border-edge-strong bg-surface-sunken px-3 py-2 text-sm text-fg","outline-none motion-fast transition-[border-color,box-shadow]","focus:border-accent focus:ring-2 focus:ring-accent/25","disabled:cursor-not-allowed disabled:opacity-60","aria-[invalid=true]:border-danger aria-[invalid=true]:focus:ring-danger/25"].join(" ");function B({className:t,...n}){return e.jsx("input",{className:f(K,t),...n})}function Oe({className:t,...n}){return e.jsx("textarea",{className:f(K,"resize-y",t),...n})}function Ie({className:t,...n}){return e.jsx("select",{className:f(K,t),...n})}function Pe({checked:t,onChange:n,label:s,disabled:l,id:r,className:a}){const x=c.useId(),m=r??x;return e.jsxs("label",{htmlFor:m,className:f("relative inline-block shrink-0 cursor-pointer",a),children:[e.jsx("input",{id:m,type:"checkbox","aria-label":s,className:"peer sr-only",checked:t,disabled:l,onChange:g=>n(g.target.checked)}),e.jsx("span",{className:f("block h-[18px] w-8 rounded-full bg-edge-strong","motion-fast transition-colors","after:absolute after:left-0.5 after:top-0.5 after:h-3.5 after:w-3.5 after:rounded-full","after:bg-surface-raised after:shadow-2xs after:transition-transform after:content-['']","peer-checked:bg-accent-solid peer-checked:after:translate-x-3.5","peer-focus-visible:ring-2 peer-focus-visible:ring-accent/50","peer-disabled:opacity-50")})]})}const de={neutral:"bg-surface-active text-fg-muted",accent:"bg-accent-soft text-accent",success:"bg-success-soft text-success",warn:"bg-warn-soft text-warn",danger:"bg-danger-soft text-danger",info:"bg-info-soft text-info",lineage:"bg-lineage-soft text-lineage"},ue={neutral:"bg-fg-subtle",accent:"bg-accent-solid",success:"bg-success-solid",warn:"bg-warn-solid",danger:"bg-danger-solid",info:"bg-info-solid",lineage:"bg-lineage-solid"};function xe({tone:t="neutral",shape:n="tag",size:s="md",dot:l=!1,icon:r,title:a,className:x,children:m}){return e.jsxs("span",{title:a,className:f("inline-flex items-center gap-1 font-medium leading-none",n==="pill"?"rounded-full px-2 py-0.5":"rounded-md px-1.5 py-0.5",s==="sm"?"text-3xs":"text-2xs",de[t],x),children:[l&&e.jsx("span",{className:f("h-1.5 w-1.5 shrink-0 rounded-full",ue[t])}),r,m]})}function L({tone:t="neutral",pulse:n=!1,className:s}){return e.jsx("span",{className:f("inline-block h-2 w-2 shrink-0 rounded-full",ue[t],n&&"animate-pulse",s)})}function Te({tone:t="info",icon:n,className:s,children:l}){const r={neutral:"border-edge",accent:"border-accent-edge",success:"border-success-edge",warn:"border-warn-edge",danger:"border-danger-edge",info:"border-info-edge",lineage:"border-lineage-edge"};return e.jsxs("div",{role:t==="danger"?"alert":void 0,className:f("flex items-start gap-2 rounded-lg border px-3 py-2 text-sm",de[t],r[t],s),children:[n&&e.jsx("span",{className:"mt-0.5 shrink-0",children:n}),e.jsx("div",{className:"min-w-0",children:l})]})}const Fe=Array.from({length:72},(t,n)=>n*5),S=[...le].sort((t,n)=>t.hue-n.hue),z=(t,n)=>Math.min(Math.abs(t-n),360-Math.abs(t-n));function se(t){const n=S.reduce((r,a)=>z(a.hue,t)<z(r.hue,t)?a:r);if(z(n.hue,t)<=8)return n.name;const s=S.find(r=>r.hue>t)??S[0];return`between ${S[(S.indexOf(s)-1+S.length)%S.length].name} and ${s.name}`}function Le({theme:t,dark:n,hue:s,className:l}){const r=c.useRef(null);return c.useLayoutEffect(()=>{const a=r.current;a&&(s===null?we(a):oe(s,a))},[t,n,s]),e.jsx("div",{ref:r,"data-theme":t,className:f("overflow-hidden rounded-lg border border-edge",n&&"dark",l),children:e.jsxs("div",{className:"flex h-full items-center gap-2 bg-surface p-2",children:[e.jsxs("div",{className:"flex-1 rounded-md border border-edge-subtle bg-surface-raised p-1.5",children:[e.jsx("div",{className:"h-1 w-4/5 rounded-full bg-fg"}),e.jsx("div",{className:"mt-1 h-1 w-3/5 rounded-full bg-fg-subtle"})]}),e.jsx("div",{className:"grid h-6 w-6 shrink-0 place-items-center rounded-md bg-accent-solid",children:e.jsx("div",{className:"h-1 w-3 rounded-full bg-accent-fg"})})]})})}function De({hexes:t,hue:n,active:s,onCommit:l}){const r=c.useRef(null),a=c.useRef(null),x=c.useRef(null),m=c.useRef(0),g=c.useRef(null),p=c.useRef(!1),j=c.useRef(null),u=c.useMemo(()=>{if(t.length===0)return;const d=t.map((b,y)=>`${b} ${(y/t.length*100).toFixed(2)}%`);return d.push(`${t[0]} 100%`),`linear-gradient(to right, ${d.join(", ")})`},[t]),h=c.useCallback(d=>{a.current&&(a.current.style.left=`${d/360*100}%`),x.current&&(x.current.textContent=se(d))},[]);c.useEffect(()=>{p.current||h(n)},[n,h]);const N=d=>{var $;const b=($=r.current)==null?void 0:$.getBoundingClientRect();if(!b||b.width===0)return 0;const y=Math.min(1,Math.max(0,(d-b.left)/b.width));return Math.round(y*360)%360},w=c.useCallback(d=>{g.current=d,!m.current&&(m.current=requestAnimationFrame(()=>{m.current=0;const b=g.current;g.current=null,b!==null&&(h(b),oe(b,document.documentElement,{context:j.current??void 0,live:!0}))}))},[h]);c.useEffect(()=>()=>cancelAnimationFrame(m.current),[]);const P=d=>{p.current=!1,j.current=null,cancelAnimationFrame(m.current),m.current=0,g.current=null,l(d)};return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"mt-2 flex items-baseline justify-between gap-2",children:[e.jsx("span",{className:"text-3xs text-fg-subtle",children:"Drag along the strip"}),e.jsx("span",{ref:x,className:"text-3xs font-medium text-fg-muted","aria-hidden":!0})]}),e.jsx("div",{ref:r,role:"slider",tabIndex:0,"aria-label":"Accent colour","aria-valuemin":0,"aria-valuemax":359,"aria-valuenow":n,"aria-valuetext":s?se(n):"the theme’s own colour",onPointerDown:d=>{d.currentTarget.setPointerCapture(d.pointerId),p.current=!0,j.current=Ne(),w(N(d.clientX))},onPointerMove:d=>{p.current&&w(N(d.clientX))},onPointerUp:d=>{p.current&&P(N(d.clientX))},onPointerCancel:()=>{p.current&&P(n)},onKeyDown:d=>{const b=d.key==="PageUp"||d.key==="PageDown"?15:d.shiftKey?10:2;let y=null;d.key==="ArrowLeft"||d.key==="ArrowDown"||d.key==="PageDown"?y=(n-b+360)%360:d.key==="ArrowRight"||d.key==="ArrowUp"||d.key==="PageUp"?y=(n+b)%360:d.key==="Home"?y=0:d.key==="End"&&(y=359),y!==null&&(d.preventDefault(),l(y))},style:{backgroundImage:u,touchAction:"none"},className:f("relative mt-1 h-8 cursor-pointer rounded-lg border border-edge shadow-xs select-none","focus-visible:focus-ring"),children:e.jsx("div",{ref:a,"aria-hidden":!0,style:{left:`${n/360*100}%`},className:f("pointer-events-none absolute top-1/2 h-[calc(100%+6px)] w-1.5 -translate-x-1/2 -translate-y-1/2 rounded-full","border border-fg bg-surface-raised shadow-sm",!s&&"opacity-0")})})]})}function Ve({className:t}){const[n,s]=c.useState(Z),[l,r]=c.useState(null),a=typeof document<"u"&&document.documentElement.classList.contains("dark"),x=c.useRef(n),m=c.useCallback(u=>{const h={...x.current,...u};x.current=h,s(h),r(ee(h))},[]);c.useEffect(()=>{const u=h=>r(h.detail);return window.addEventListener(te,u),r(ee(Z())),()=>window.removeEventListener(te,u)},[]);const g=c.useMemo(()=>ve(Fe),[n.theme,a,l==null?void 0:l.mode]),p=(l==null?void 0:l.hue)??0,j=n.hue!==null;return e.jsxs("div",{className:f("space-y-5",t),children:[e.jsxs("fieldset",{children:[e.jsx("legend",{className:"text-2xs font-semibold uppercase tracking-wide text-fg-muted",children:"Theme"}),e.jsx("div",{className:f("mt-2 grid gap-2","grid-cols-2 sm:grid-cols-4"),children:ie.map(u=>{const h=n.theme===u.id;return e.jsxs("button",{type:"button","aria-pressed":h,title:`${u.label} — ${u.blurb}`,onClick:()=>m({theme:u.id}),className:f("motion-fast rounded-xl border text-left transition-[border-color,box-shadow]","focus-visible:focus-ring","p-1.5",h?"border-accent-edge bg-accent-soft shadow-xs":"border-edge bg-surface-raised hover:border-edge-strong"),children:[e.jsx(Le,{theme:u.id,dark:a,hue:n.hue,className:"h-10"}),e.jsxs("div",{className:"mt-1.5 min-w-0 px-0.5 pb-0.5",children:[e.jsx("span",{className:"block truncate text-xs font-semibold text-fg",children:u.label}),e.jsx("span",{className:"mt-0.5 line-clamp-2 text-3xs leading-snug text-fg-muted",children:u.blurb})]})]},u.id)})})]}),e.jsxs("div",{className:f("grid gap-5 lg:grid-cols-[minmax(0,1fr)_15rem] lg:items-start"),children:[e.jsxs("fieldset",{children:[e.jsx("legend",{className:"text-2xs font-semibold uppercase tracking-wide text-fg-muted",children:"Accent colour"}),e.jsx("p",{className:"mt-1 text-3xs leading-snug text-fg-subtle",children:"Pick any colour. The theme adjusts it so buttons and labels stay readable in both light and dark."}),e.jsx(De,{hexes:g,hue:p,active:j,onCommit:u=>m({hue:u})}),e.jsxs("div",{className:"mt-2 flex flex-wrap gap-1",children:[e.jsx("button",{type:"button",onClick:()=>m({hue:null}),"aria-pressed":!j,className:f("motion-fast rounded-md border px-2 py-1 text-3xs transition-colors","focus-visible:focus-ring",j?"border-edge text-fg-muted hover:border-edge-strong hover:text-fg":"border-accent-edge bg-accent-soft text-accent"),children:"Theme’s own"}),le.map(u=>{const h=j&&Math.abs(p-u.hue)<2.5;return e.jsxs("button",{type:"button","aria-pressed":h,onClick:()=>m({hue:u.hue}),className:f("motion-fast inline-flex items-center gap-1.5 rounded-md border px-2 py-1 text-3xs transition-colors","focus-visible:focus-ring",h?"border-edge-strong bg-surface-active text-fg":"border-edge text-fg-muted hover:border-edge-strong hover:text-fg"),children:[e.jsx("span",{"aria-hidden":!0,className:"h-2.5 w-2.5 rounded-full",style:{backgroundColor:g[Math.round(u.hue/5)%g.length]}}),u.name]},u.name)})]})]}),e.jsxs("fieldset",{children:[e.jsx("legend",{className:"text-2xs font-semibold uppercase tracking-wide text-fg-muted",children:"Tint the background"}),e.jsx("p",{className:"mt-1 text-3xs leading-snug text-fg-subtle",children:"Colours the whole page a little, not just the buttons. Useful for telling two Paddock instances apart at a glance."}),e.jsx("div",{className:"mt-2 inline-flex rounded-lg border border-edge p-0.5",children:ye.map(u=>e.jsx("button",{type:"button","aria-pressed":n.tint===u.level,onClick:()=>m({tint:u.level}),className:f("motion-fast rounded-md px-2.5 py-1 text-3xs transition-colors","focus-visible:focus-ring",n.tint===u.level?"bg-surface-active font-medium text-fg":"text-fg-muted hover:text-fg"),children:u.label},u.level))})]})]}),e.jsx(Be,{})]})}function Be(){return e.jsxs("div",{children:[e.jsx("p",{className:"text-2xs font-semibold uppercase tracking-wide text-fg-muted",children:"Preview"}),e.jsxs("div",{className:"mt-2 flex flex-wrap items-center gap-2 rounded-xl border border-edge bg-surface p-3",children:[e.jsx(R,{variant:"primary",size:"sm",children:"Send"}),e.jsx(R,{variant:"ghost",size:"sm",children:"Cancel"}),e.jsx(R,{variant:"link",size:"sm",children:"A link"}),e.jsx("span",{className:"inline-flex items-center gap-1 rounded-md border border-accent-edge bg-accent-soft px-1.5 py-0.5 text-2xs font-medium text-accent",children:"accent chip"}),e.jsx(xe,{tone:"accent",shape:"pill",dot:!0,children:"running"}),e.jsxs("span",{className:"inline-flex items-center gap-1.5 text-2xs text-fg-subtle",children:[e.jsx("span",{className:"h-4 w-4 rounded-md border border-edge bg-accent-solid-hover","aria-hidden":!0}),"hovered"]}),e.jsxs("span",{className:"ml-auto inline-flex items-center gap-1.5",children:[e.jsx(L,{tone:"success"}),e.jsx(L,{tone:"warn"}),e.jsx(L,{tone:"danger"}),e.jsx(L,{tone:"info"}),e.jsx("span",{className:"text-2xs text-fg-subtle",children:"status hues (theme’s, not yours)"})]})]})]})}const G="mx-auto w-full max-w-4xl",He="sm:w-64";function Ue(){const[t,n]=c.useState(null),[s,l]=c.useState(!0),[r,a]=c.useState(null),[x,m]=c.useState({}),[g,p]=c.useState(!1),[j,u]=c.useState(null),[h,N]=c.useState(!1),[w,P]=c.useState(""),[d,b]=c.useState(!1),[y,$]=c.useState(null),X=c.useRef(null),me=ke("(min-width: 1024px)");c.useEffect(()=>{let i=!0;return l(!0),F.getInstanceConfig().then(o=>{i&&(n(o),a(null))}).catch(o=>i&&a(o instanceof Error?o.message:String(o))).finally(()=>i&&l(!1)),()=>{i=!1}},[]);const fe=(i,o)=>{N(!1),u(null),m(v=>({...v,[i]:o}))},ge=i=>re(i,x),H=c.useMemo(()=>t?t.groups.flatMap(i=>i.fields):[],[t]),k=c.useMemo(()=>H.filter(i=>i.editable&&!i.envOverridden).filter(i=>Object.prototype.hasOwnProperty.call(x,i.key)).filter(i=>!ae(x[i.key],q(i))).map(i=>i.key),[H,x]),J=c.useMemo(()=>new Set(k),[k]),C=c.useMemo(()=>{if(!t)return[];const i=w.trim().toLowerCase(),o=[];for(const v of t.groups){const O=i!==""&&v.label.toLowerCase().includes(i),I=v.fields.filter(A=>{const T=re(A,x);return d&&ae(T,A.default)?!1:i===""||O?!0:Ze(A).includes(i)});I.length>0&&o.push({...v,fields:I})}return o},[t,w,d,x]),Y=C.reduce((i,o)=>i+o.fields.length,0),he=w.trim()!==""||d,U=!d&&(w.trim()===""||tt.includes(w.trim().toLowerCase())),M=c.useMemo(()=>U?[V,...C]:C,[U,C]),pe=C.some(i=>i.fields.some(o=>o.envOverridden)),Q=et(C,J);c.useEffect(()=>{const i=X.current;if(!i||M.length===0)return;const o=M.map(O=>O.id),v=()=>{const O=i.getBoundingClientRect().top;let I=o[0];for(const A of o){const T=document.getElementById(D(A));if(T)if(T.getBoundingClientRect().top-O<=80)I=A;else break}$(I)};return v(),i.addEventListener("scroll",v,{passive:!0}),()=>i.removeEventListener("scroll",v)},[M]);const W=i=>{var v;const o=document.getElementById(D(i));(v=o==null?void 0:o.scrollIntoView)==null||v.call(o,{behavior:"smooth",block:"start"}),$(i)},be=async()=>{if(k.length===0||!t)return;const i={};for(const o of k)i[o]=x[o];p(!0),u(null);try{await F.updateInstanceConfig(i,t.configVersion);const o=await F.getInstanceConfig();n(o),m({}),N(!0)}catch(o){if(o instanceof Ee&&o.status===409)try{n(await F.getInstanceConfig())}catch{}u(o instanceof Error?o.message:String(o))}finally{p(!1)}},je=()=>{m({}),u(null),N(!1)};return e.jsxs("div",{className:"flex min-h-0 flex-1",children:[t&&e.jsx(ze,{groups:M,active:y,onJump:W,dirtyCount:Q}),e.jsxs("div",{className:"flex min-h-0 min-w-0 flex-1 flex-col",children:[t&&e.jsx("div",{className:"border-b border-edge px-4 py-2.5 sm:px-6",children:e.jsxs("div",{className:G,children:[e.jsx(_e,{query:w,onQuery:P,modifiedOnly:d,onModifiedOnly:b,visibleCount:Y,totalCount:H.length,filtering:he,autoFocus:me}),e.jsx(Ge,{groups:M,active:y,onJump:W,dirtyCount:Q})]})}),e.jsx("div",{ref:X,className:"min-h-0 flex-1 overflow-y-auto px-4 py-5 sm:px-6",children:e.jsxs("div",{className:G,children:[U&&e.jsx("div",{className:"mb-8 border-b border-edge pb-7",children:e.jsx(ne,{id:D(V.id),title:V.label,description:V.description,variant:"rule",first:!0,children:e.jsx(Ve,{})})}),e.jsx(Ke,{saved:h,configPath:t==null?void 0:t.configPath,restartRequired:(t==null?void 0:t.restartRequired)??!1,fileError:t==null?void 0:t.configFileError}),s&&e.jsx("p",{className:"text-sm text-fg-muted",children:"Loading…"}),r&&e.jsxs("p",{className:"text-sm text-danger",role:"alert",children:["Failed to load settings: ",r]}),t&&pe&&e.jsx(qe,{}),t&&Y===0&&e.jsxs("p",{className:"py-8 text-center text-sm text-fg-muted",children:["No settings match"," ",w.trim()?e.jsxs(e.Fragment,{children:["“",e.jsx("span",{className:"font-medium",children:w.trim()}),"”"]}):"this filter","."]}),C.map(i=>e.jsx(ne,{id:D(i.id),title:i.label,description:i.description,variant:"card",flush:!0,children:e.jsx("div",{className:"divide-y divide-edge-subtle",children:i.fields.map(o=>e.jsx(Xe,{field:o,value:ge(o),dirty:J.has(o.key),onChange:v=>fe(o.key,v)},o.key))})},i.id))]})}),t&&e.jsx("footer",{className:"border-t border-edge px-4 py-3 sm:px-6",children:e.jsxs("div",{className:`${G} flex items-center gap-3`,children:[j&&e.jsxs("span",{className:"flex min-w-0 items-center gap-1.5 text-sm text-danger",role:"alert",children:[e.jsx(ce,{width:14,height:14,className:"shrink-0"}),e.jsx("span",{className:"truncate",children:j})]}),e.jsx("span",{className:"ml-auto shrink-0 text-xs tabular text-fg-subtle",children:k.length>0?`${k.length} unsaved change${k.length===1?"":"s"}`:"No changes"}),e.jsx(R,{variant:"subtle",onClick:je,disabled:k.length===0||g,children:"Reset"}),e.jsx(R,{variant:"primary",onClick:be,disabled:k.length===0,loading:g,loadingLabel:"Saving…",children:"Save changes"})]})})]})]})}function ze({groups:t,active:n,onJump:s,dirtyCount:l}){return e.jsx("nav",{"aria-label":"Config sections",className:"hidden w-52 shrink-0 overflow-y-auto border-r border-edge px-2 py-4 lg:block",children:e.jsx("ul",{className:"space-y-0.5",children:t.map(r=>{const a=r.id===n,x=l[r.id]??0;return e.jsx("li",{children:e.jsxs("button",{type:"button",onClick:()=>s(r.id),"aria-current":a?"true":void 0,className:f("motion-fast flex w-full items-center gap-2 rounded-md px-2.5 py-1.5 text-left text-sm transition-colors",a?"bg-surface-selected font-medium text-fg":"text-fg-muted hover:bg-surface-hover hover:text-fg"),children:[e.jsx("span",{className:"min-w-0 flex-1 truncate",children:r.label}),x>0&&e.jsx("span",{className:"h-1.5 w-1.5 shrink-0 rounded-full bg-accent-solid","aria-label":`${x} unsaved`}),r.fields.length>0&&e.jsx("span",{className:"shrink-0 text-2xs tabular text-fg-subtle",children:r.fields.length})]})},r.id)})})})}function Ge({groups:t,active:n,onJump:s,dirtyCount:l}){return t.length===0?null:e.jsx("nav",{"aria-label":"Config sections",className:"-mx-1 mt-2 flex gap-1 overflow-x-auto px-1 pb-0.5 lg:hidden",children:t.map(r=>{const a=r.id===n,x=l[r.id]??0;return e.jsxs("button",{type:"button",onClick:()=>s(r.id),"aria-current":a?"true":void 0,className:f("motion-fast flex shrink-0 items-center gap-1.5 rounded-md px-2.5 py-1 text-xs transition-colors",a?"bg-surface-selected font-medium text-fg":"text-fg-muted hover:bg-surface-hover hover:text-fg"),children:[r.label,x>0&&e.jsx("span",{className:"h-1.5 w-1.5 rounded-full bg-accent-solid","aria-label":`${x} unsaved`})]},r.id)})})}function _e({query:t,onQuery:n,modifiedOnly:s,onModifiedOnly:l,visibleCount:r,totalCount:a,filtering:x,autoFocus:m}){return e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsxs("div",{className:"relative min-w-0 flex-1 sm:max-w-sm",children:[e.jsx(Ce,{width:14,height:14,className:"pointer-events-none absolute left-2.5 top-1/2 -translate-y-1/2 text-fg-subtle"}),e.jsx(B,{type:"search","aria-label":"Search settings",placeholder:"Search settings, keys, env vars…",className:"h-8 py-0 pl-8 pr-7 [&::-webkit-search-cancel-button]:appearance-none",value:t,autoFocus:m,onChange:g=>n(g.target.value),onKeyDown:g=>{g.key==="Escape"&&t!==""&&(g.preventDefault(),n(""))}}),t!==""&&e.jsx("button",{type:"button","aria-label":"Clear search",onClick:()=>n(""),className:"absolute right-2 top-1/2 -translate-y-1/2 text-fg-subtle hover:text-fg",children:e.jsx(Se,{width:13,height:13})})]}),e.jsx("button",{type:"button","aria-pressed":s,onClick:()=>l(!s),className:f("motion-fast shrink-0 rounded-md border px-2.5 py-1 text-xs transition-colors",s?"border-accent-edge bg-accent-soft text-accent":"border-edge text-fg-muted hover:text-fg"),children:"Modified only"}),e.jsx("span",{className:"shrink-0 text-xs tabular text-fg-subtle",children:x?`${r} of ${a}`:`${a} settings`})]})}function Ke({saved:t,configPath:n,restartRequired:s,fileError:l}){const r=l?"danger":t?"success":"warn";return e.jsx(Te,{tone:r,className:"mb-5 leading-snug",icon:r==="success"?e.jsx(Ae,{width:15,height:15}):e.jsx(ce,{width:15,height:15}),children:e.jsx("span",{role:"status",children:l?e.jsxs(e.Fragment,{children:[e.jsxs("strong",{children:["Could not read ",_(n),"."]})," ",l," — the values below are the running instance's; what a restart would load is unknown until the file parses."]}):t?e.jsxs(e.Fragment,{children:[e.jsx("strong",{children:"Saved to disk."})," These changes take effect only after the server restarts."]}):s?e.jsxs(e.Fragment,{children:[e.jsx("strong",{children:"Restart pending."})," ",e.jsx("code",{className:"font-mono text-xs",children:_(n)})," holds changes the running instance has not picked up — the fields below marked"," ",e.jsx(E,{tone:"warn",children:"restart"})," differ from what is in force right now."]}):e.jsxs(e.Fragment,{children:["Changes here are written to"," ",e.jsx("code",{className:"font-mono text-xs",children:_(n)})," and take effect only after the server restarts — the running instance keeps its current config until then."]})})})}function qe(){return e.jsxs("p",{className:"mb-5 text-xs leading-snug text-fg-muted",children:["Settings marked ",e.jsx(E,{tone:"neutral",children:"env"})," are overridden by an environment variable, which wins over this file — edit that variable (and restart) to change them."]})}function Xe({field:t,value:n,dirty:s,onChange:l}){const r=!t.editable||t.envOverridden,a=`cfg-${t.key}`,x=t.help?`${a}-help`:void 0,m=t.type==="boolean",g=c.useMemo(()=>We(t,q(t)),[t]),p=m&&!r,j=!t.help&&!t.envOverridden&&!t.pendingRestart,u=j?"items-center":"items-start",h=j?"sm:items-center":"sm:items-start",N=r?e.jsx(Qe,{field:t,value:n}):m?e.jsx(Pe,{id:a,checked:!!n,onChange:l,label:t.label}):e.jsx(Ye,{field:t,value:n,onChange:l,inputId:a,describedBy:x});return e.jsxs("div",{className:"relative px-4 py-3",children:[s&&e.jsx("span",{"aria-hidden":!0,className:"absolute inset-y-2 left-0 w-0.5 rounded-full bg-accent-solid"}),e.jsxs("div",{className:f(g?"":p?`flex gap-4 ${u}`:`sm:flex sm:gap-6 ${h}`),children:[e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-1.5",children:[e.jsx("label",{htmlFor:r?void 0:a,className:"text-sm font-medium text-fg",children:t.label}),t.sensitive&&e.jsx(E,{tone:"warn",children:"sensitive"}),t.envOverridden&&e.jsx(E,{tone:"neutral",title:`Overridden by environment variable ${t.envVar} — edit that env var (and restart) to change it.`,children:"env"}),!t.editable&&!t.envOverridden&&e.jsx(E,{tone:"neutral",children:"read-only"}),t.pendingRestart&&e.jsx(E,{tone:"warn",title:"The config file and the running instance disagree on this field — restart to apply.",children:"restart"})]}),t.help&&e.jsx("p",{id:x,className:"mt-0.5 text-xs leading-snug text-fg-muted",children:t.help}),t.envOverridden&&e.jsx("p",{className:"mt-1 truncate font-mono text-2xs text-fg-subtle",children:t.envVar}),t.pendingRestart&&e.jsxs("p",{className:"mt-1 text-2xs leading-snug text-warn",children:["In force now: ",e.jsx("span",{className:"font-mono",children:Je(t.value)})]})]}),e.jsx("div",{className:f(g?"mt-2":p?"flex shrink-0 justify-end":`mt-2 sm:mt-0 sm:shrink-0 ${He}`),children:N})]})]})}function Je(t){if(t==null||t==="")return"(not set)";const s=(Array.isArray(t)?t.join(", "):String(t)).replace(/\s+/g," ").trim();return s.length>60?`${s.slice(0,60)}…`:s}function E({children:t,tone:n,title:s}){return e.jsx(xe,{tone:n,size:"sm",title:s,className:"uppercase tracking-wide",children:t})}function Ye({field:t,value:n,onChange:s,inputId:l,describedBy:r}){if(t.type==="enum")return e.jsx(Ie,{id:l,"aria-describedby":r,value:String(n??""),onChange:a=>s(a.target.value),children:(t.enumValues??[]).map(a=>e.jsx("option",{value:a,children:a},a))});if(t.type==="number")return e.jsx(B,{id:l,type:"number","aria-describedby":r,className:"tabular",value:n==null?"":String(n),placeholder:t.default===null?"default":String(t.default),onChange:a=>s(a.target.value===""?null:Number(a.target.value))});if(t.type==="text"){const a=n==null||n===t.default,x=n==null?String(t.default??""):String(n),m=typeof t.default=="string"&&!a;return e.jsxs("div",{children:[e.jsx(Oe,{id:l,"aria-describedby":r,className:"min-h-[7rem] font-mono text-xs leading-relaxed",rows:6,spellCheck:!1,value:x,onChange:g=>s(g.target.value)}),e.jsxs("div",{className:"mt-1 flex items-center justify-between gap-3 text-xs text-fg-muted",children:[e.jsx("span",{children:a?"Using the built-in default.":n===""?"Empty — nothing will be appended.":`${x.length.toLocaleString()} characters.`}),m&&e.jsx(R,{variant:"link",size:"sm",className:"shrink-0",onClick:()=>s(null),children:"Restore default"})]})]})}if(t.type==="string-list"){const a=Array.isArray(n)?n.join(", "):String(n??"");return e.jsx(B,{id:l,type:"text","aria-describedby":r,value:a,onChange:x=>s(x.target.value.split(",").map(m=>m.trim()).filter(Boolean))})}return e.jsx(B,{id:l,type:"text","aria-describedby":r,value:n==null?"":String(n),placeholder:t.default===null?"":String(t.default),onChange:a=>s(a.target.value)})}function Qe({field:t,value:n}){const s="rounded-lg bg-surface-sunken px-3 py-2 font-mono text-xs text-fg-muted";return t.type==="boolean"?e.jsx("div",{className:s,children:n?"true":"false"}):n==null||n===""?e.jsx("div",{className:s,children:e.jsx("span",{className:"italic text-fg-subtle",children:t.type==="text"&&n===""?"(empty — nothing appended)":"(not set)"})}):t.type==="text"?e.jsx("div",{className:f(s,"max-h-40 overflow-y-auto whitespace-pre-wrap leading-relaxed"),children:String(n)}):e.jsx("div",{className:f(s,"break-all"),children:Array.isArray(n)?n.join(", "):String(n)})}function We(t,n){return t.type==="text"||t.type==="string-list"?!0:(Array.isArray(n)?n.join(", "):n==null?"":String(n)).length>38}function Ze(t){return[t.label,t.key,t.help,t.envVar,...t.enumValues??[]].filter(Boolean).join(" ").toLowerCase()}function et(t,n){const s={};for(const l of t)s[l.id]=l.fields.filter(r=>n.has(r.key)).length;return s}const D=t=>`cfg-section-${t}`,V={id:"appearance",label:"Appearance",description:"Theme and accent colour for this browser. Applies immediately — no save, no restart.",fields:[]},tt=["appearance theme themes colour color accent tint dark light font",...ie.map(t=>t.id)].join(" ");function q(t){return t.pendingValue===void 0?t.value:t.pendingValue}function re(t,n){return Object.prototype.hasOwnProperty.call(n,t.key)?n[t.key]:q(t)}function ae(t,n){return Array.isArray(t)&&Array.isArray(n)?t.length===n.length&&t.every((s,l)=>s===n[l]):t===n}function _(t){if(!t)return"paddock.config.yaml";const n=t.split("/");return n[n.length-1]||t}function rt(){const t=Re(),n=(t==null?void 0:t.openNav)??(()=>{});return e.jsxs("div",{className:"flex h-full min-h-0 flex-col",children:[e.jsxs("header",{className:"pt-safe flex items-center gap-2 border-b border-edge px-3 pb-2.5 sm:px-6 lg:py-4",children:[e.jsx("button",{type:"button",onClick:n,"aria-label":"Open menu",className:"btn-subtle -ml-1 shrink-0 px-2 py-1.5 lg:hidden",children:e.jsx($e,{width:20,height:20})}),e.jsx(Me,{width:18,height:18,className:"shrink-0 text-fg-subtle"}),e.jsx("h1",{className:"text-md font-semibold tracking-tight",children:"Config"})]}),e.jsx(Ue,{})]})}export{rt as InstanceConfigPage};
|
|
2
|
+
|