@burdenoff/microfe-bigconsole 2026.707.2 → 2026.707.4
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/dist/bigconsole/assistant/createSandboxAssistantTransport.js +73 -50
- package/dist/bigconsole/assistant/createSandboxAssistantTransport.js.map +1 -1
- package/dist/bigconsole/components/widgets/table/TableConfig.js +220 -29
- package/dist/bigconsole/components/widgets/table/TableConfig.js.map +1 -1
- package/package.json +1 -1
|
@@ -23,31 +23,54 @@ function y() {
|
|
|
23
23
|
return new URLSearchParams(window.location.search).get("org") ?? _("organizationId");
|
|
24
24
|
}
|
|
25
25
|
function b(e) {
|
|
26
|
-
return e.info?.
|
|
26
|
+
return e.info?.role ?? e.role;
|
|
27
27
|
}
|
|
28
28
|
function x(e) {
|
|
29
|
-
|
|
29
|
+
let t = e.info?.time?.created;
|
|
30
|
+
if (t !== void 0) return t;
|
|
31
|
+
let n = e.createdAt;
|
|
32
|
+
if (n === void 0) return 0;
|
|
33
|
+
if (typeof n == "string") {
|
|
34
|
+
let e = Date.parse(n);
|
|
35
|
+
return isNaN(e) ? 0 : e;
|
|
36
|
+
}
|
|
37
|
+
return n;
|
|
30
38
|
}
|
|
31
39
|
function S(e) {
|
|
32
|
-
|
|
40
|
+
let t = e.info?.time?.completed;
|
|
41
|
+
if (t !== void 0) return t;
|
|
42
|
+
let n = e.completedAt;
|
|
43
|
+
if (n !== void 0) {
|
|
44
|
+
if (typeof n == "string") {
|
|
45
|
+
let e = Date.parse(n);
|
|
46
|
+
return isNaN(e) ? void 0 : e;
|
|
47
|
+
}
|
|
48
|
+
return n;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function C(e) {
|
|
52
|
+
return (e.parts ?? [] ?? []).filter((e) => e.type === "text" && typeof e.text == "string").map((e) => e.text?.trim() ?? "").filter(Boolean).join("\n") || (typeof e.content == "string" ? e.content.trim() : "");
|
|
53
|
+
}
|
|
54
|
+
function w(e) {
|
|
55
|
+
return (e.parts ?? []).filter((e) => e.type === "tool" && e.tool).map((e) => {
|
|
33
56
|
let t = e.state?.status ?? "running", n = e.tool ?? "tool";
|
|
34
57
|
return t === "completed" ? `Completed: ${n}` : t === "failed" ? `Failed: ${n}` : `Running: ${n}`;
|
|
35
58
|
});
|
|
36
59
|
}
|
|
37
|
-
function
|
|
38
|
-
let i = e.filter((e) => e
|
|
60
|
+
function T(e, t, n, r) {
|
|
61
|
+
let i = e.filter((e) => b(e) === "assistant" && x(e) >= t).sort((e, t) => x(e) - x(t));
|
|
39
62
|
i.length === 0 && e.length > 0 && console.log("[BigConsole-Assistant] buildProgress: no relevant messages", {
|
|
40
63
|
totalMessages: e.length,
|
|
41
64
|
sinceMs: t,
|
|
42
|
-
messageRoles: e.map((e) => e
|
|
43
|
-
messageTimestamps: e.map((e) => e
|
|
65
|
+
messageRoles: e.map((e) => b(e)),
|
|
66
|
+
messageTimestamps: e.map((e) => x(e))
|
|
44
67
|
});
|
|
45
68
|
let a, o;
|
|
46
69
|
if (i.length === 0) a = "Thinking…", o = n === a && r !== void 0 && Date.now() - r >= 15e3;
|
|
47
70
|
else {
|
|
48
|
-
let e = i[i.length - 1], t =
|
|
71
|
+
let e = i[i.length - 1], t = C(e), s = w(e);
|
|
49
72
|
a = [t, ...s].filter(Boolean).join("\n\n") || "Thinking…";
|
|
50
|
-
let c = !!e
|
|
73
|
+
let c = !!S(e) && (!!t || s.length > 0), l = !c && n === a && r !== void 0 && Date.now() - r >= 15e3;
|
|
51
74
|
o = c || l;
|
|
52
75
|
}
|
|
53
76
|
return {
|
|
@@ -55,10 +78,10 @@ function C(e, t, n, r) {
|
|
|
55
78
|
done: o
|
|
56
79
|
};
|
|
57
80
|
}
|
|
58
|
-
function
|
|
81
|
+
function E(e) {
|
|
59
82
|
return e.replace(/(Authorization\s*:\s*Bearer\s+)[^\s\n]+/gi, "$1[REDACTED]").replace(/(X-Workspace-Authorization\s*:\s*Bearer\s+)[^\s\n]+/gi, "$1[REDACTED]").replace(/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9._-]+\.[A-Za-z0-9._-]+\b/g, "[REDACTED_JWT]").replace(/\bsk-ant-[A-Za-z0-9-]+\b/g, "[REDACTED_API_KEY]");
|
|
60
83
|
}
|
|
61
|
-
function
|
|
84
|
+
function D(e) {
|
|
62
85
|
let t = e instanceof Error ? e.message.toLowerCase() : String(e).toLowerCase();
|
|
63
86
|
return t.includes("rate limit exceeded") || t.includes("unauthorized") || t.includes("k8s api error 401") ? !1 : [
|
|
64
87
|
"sandbox not found",
|
|
@@ -76,19 +99,19 @@ function T(e) {
|
|
|
76
99
|
"bootstrap failed"
|
|
77
100
|
].some((e) => t.includes(e));
|
|
78
101
|
}
|
|
79
|
-
function
|
|
80
|
-
let { getAccessToken: _, getWorkspaceToken:
|
|
102
|
+
function O() {
|
|
103
|
+
let { getAccessToken: _, getWorkspaceToken: S, userId: C, workspaceId: w } = f(), [O, k] = u(() => {
|
|
81
104
|
try {
|
|
82
105
|
return [sessionStorage.getItem("bc-assistant-sandbox-id"), sessionStorage.getItem("bc-assistant-session-id")];
|
|
83
106
|
} catch {
|
|
84
107
|
return [null, null];
|
|
85
108
|
}
|
|
86
|
-
}, []),
|
|
87
|
-
|
|
88
|
-
}, []),
|
|
89
|
-
|
|
90
|
-
}, []),
|
|
91
|
-
let a =
|
|
109
|
+
}, []), A = d(O), j = d(k), M = l((e) => {
|
|
110
|
+
A.current = e, e ? sessionStorage.setItem("bc-assistant-sandbox-id", e) : sessionStorage.removeItem("bc-assistant-sandbox-id");
|
|
111
|
+
}, []), N = l((e) => {
|
|
112
|
+
j.current = e, e ? sessionStorage.setItem("bc-assistant-session-id", e) : sessionStorage.removeItem("bc-assistant-session-id");
|
|
113
|
+
}, []), P = l(async (n, i) => {
|
|
114
|
+
let a = A.current;
|
|
92
115
|
if (console.log("[BigConsole-Assistant] ensureRuntime start", {
|
|
93
116
|
sandboxId: a,
|
|
94
117
|
workspaceId: n
|
|
@@ -97,36 +120,36 @@ function E() {
|
|
|
97
120
|
if (!_()) throw Error("The assistant requires an authenticated session. Please sign in again.");
|
|
98
121
|
a = await e(p, n, i), console.log("[BigConsole-Assistant] createAssistantSandbox result", { sandboxId: a });
|
|
99
122
|
}
|
|
100
|
-
console.log("[BigConsole-Assistant] waitForSandboxReady called", { sandboxId: a }), await s(a, n, i), console.log("[BigConsole-Assistant] waitForSandboxReady done", { sandboxId: a }), console.log("[BigConsole-Assistant] waitForAssistantServiceReady called", { sandboxId: a }), await o(a, n, i), console.log("[BigConsole-Assistant] waitForAssistantServiceReady done", { sandboxId: a }),
|
|
123
|
+
console.log("[BigConsole-Assistant] waitForSandboxReady called", { sandboxId: a }), await s(a, n, i), console.log("[BigConsole-Assistant] waitForSandboxReady done", { sandboxId: a }), console.log("[BigConsole-Assistant] waitForAssistantServiceReady called", { sandboxId: a }), await o(a, n, i), console.log("[BigConsole-Assistant] waitForAssistantServiceReady done", { sandboxId: a }), M(a);
|
|
101
124
|
}
|
|
102
|
-
let c =
|
|
125
|
+
let c = j.current;
|
|
103
126
|
return console.log("[BigConsole-Assistant] session check", {
|
|
104
127
|
sessionId: c,
|
|
105
128
|
sandboxId: a
|
|
106
129
|
}), c || (console.log("[BigConsole-Assistant] createAssistantSession called", {
|
|
107
130
|
sandboxId: a,
|
|
108
131
|
workspaceId: n
|
|
109
|
-
}), c = (await t(a, n, p, i)).sessionId,
|
|
132
|
+
}), c = (await t(a, n, p, i)).sessionId, N(c)), {
|
|
110
133
|
sandboxId: a,
|
|
111
134
|
sessionId: c
|
|
112
135
|
};
|
|
113
|
-
}, [_]),
|
|
114
|
-
let o = v(
|
|
136
|
+
}, [_]), F = l(async ({ prompt: e, onProgress: t, signal: r }) => {
|
|
137
|
+
let o = v(w);
|
|
115
138
|
if (console.log("[BigConsole-Assistant] sendPrompt called", {
|
|
116
139
|
promptLength: e.length,
|
|
117
140
|
workspaceId: o,
|
|
118
|
-
hasCtxWorkspaceId: !!
|
|
141
|
+
hasCtxWorkspaceId: !!w,
|
|
119
142
|
authContextKeys: {
|
|
120
143
|
hasAccessToken: !!_(),
|
|
121
|
-
hasWorkspaceToken: !!
|
|
122
|
-
hasUserId: !!
|
|
144
|
+
hasWorkspaceToken: !!S(),
|
|
145
|
+
hasUserId: !!C
|
|
123
146
|
},
|
|
124
147
|
locationSearch: window.location.search
|
|
125
148
|
}), !o) throw Error("The assistant needs an active workspace. Open a workspace and try again.");
|
|
126
149
|
let s = {
|
|
127
150
|
accessToken: _(),
|
|
128
|
-
workspaceToken:
|
|
129
|
-
userId:
|
|
151
|
+
workspaceToken: S(),
|
|
152
|
+
userId: C,
|
|
130
153
|
organizationId: y()
|
|
131
154
|
};
|
|
132
155
|
console.log("[BigConsole-Assistant] authContext prepared", {
|
|
@@ -138,7 +161,7 @@ function E() {
|
|
|
138
161
|
let l = async (u) => {
|
|
139
162
|
try {
|
|
140
163
|
console.log("[BigConsole-Assistant] run attempt", u);
|
|
141
|
-
let { sandboxId: l, sessionId: d } = await
|
|
164
|
+
let { sandboxId: l, sessionId: d } = await P(o, s);
|
|
142
165
|
console.log("[BigConsole-Assistant] ensureRuntime resolved", {
|
|
143
166
|
sandboxId: l,
|
|
144
167
|
sessionId: d
|
|
@@ -150,51 +173,51 @@ function E() {
|
|
|
150
173
|
sessionId: d,
|
|
151
174
|
promptLength: e.length
|
|
152
175
|
}), await a(l, o, d, e, p, c(), s);
|
|
153
|
-
let _ = Date.now() + m, v = Date.now(), y = "",
|
|
176
|
+
let _ = Date.now() + m, v = Date.now(), y = "", S = Date.now(), C = T([], f);
|
|
154
177
|
for (; Date.now() < _;) {
|
|
155
178
|
if (r.aborted) throw Error("Cancelled");
|
|
156
179
|
let e = await i(l, o, d, s, 50);
|
|
157
180
|
if (console.log("[BigConsole-Assistant] poll", {
|
|
158
181
|
elapsedMs: Date.now() - f,
|
|
159
182
|
messageCount: e.length,
|
|
160
|
-
firstFewRoles: e.slice(0, 3).map((e) => e
|
|
161
|
-
firstFewTimestamps: e.slice(0, 3).map((e) => e
|
|
162
|
-
}),
|
|
163
|
-
contentPreview:
|
|
164
|
-
done:
|
|
165
|
-
lastContentChangeAt: Date.now() -
|
|
166
|
-
}),
|
|
183
|
+
firstFewRoles: e.slice(0, 3).map((e) => b(e)),
|
|
184
|
+
firstFewTimestamps: e.slice(0, 3).map((e) => x(e))
|
|
185
|
+
}), C = T(e, f, y, S), console.log("[BigConsole-Assistant] progress", {
|
|
186
|
+
contentPreview: C.content.slice(0, 100),
|
|
187
|
+
done: C.done,
|
|
188
|
+
lastContentChangeAt: Date.now() - S
|
|
189
|
+
}), C.content !== y && (y = C.content, S = Date.now()), t(E(C.content)), C.done) {
|
|
167
190
|
console.log("[BigConsole-Assistant] progress.done=true, breaking poll loop");
|
|
168
191
|
break;
|
|
169
192
|
}
|
|
170
193
|
Date.now() - v > g && (await n(l, o, 600, s).catch(() => void 0), v = Date.now()), await new Promise((e) => setTimeout(e, h));
|
|
171
194
|
}
|
|
172
|
-
if (!
|
|
173
|
-
return { text:
|
|
195
|
+
if (!C.done) throw Error("The assistant timed out while responding. Please try again.");
|
|
196
|
+
return { text: E(C.content) };
|
|
174
197
|
} catch (e) {
|
|
175
198
|
if (console.error("[BigConsole-Assistant] run error", {
|
|
176
199
|
attempt: u,
|
|
177
200
|
error: e instanceof Error ? e.message : String(e),
|
|
178
201
|
stack: e instanceof Error ? e.stack : void 0,
|
|
179
|
-
sandboxId:
|
|
180
|
-
sessionId:
|
|
181
|
-
}), u === 1 &&
|
|
202
|
+
sandboxId: A.current,
|
|
203
|
+
sessionId: j.current
|
|
204
|
+
}), u === 1 && D(e)) return M(null), N(null), l(2);
|
|
182
205
|
throw e;
|
|
183
206
|
}
|
|
184
207
|
};
|
|
185
208
|
return l(1);
|
|
186
209
|
}, [
|
|
210
|
+
w,
|
|
211
|
+
P,
|
|
212
|
+
_,
|
|
187
213
|
S,
|
|
214
|
+
C,
|
|
188
215
|
M,
|
|
189
|
-
|
|
190
|
-
b,
|
|
191
|
-
x,
|
|
192
|
-
A,
|
|
193
|
-
j
|
|
216
|
+
N
|
|
194
217
|
]);
|
|
195
|
-
return u(() => ({ sendPrompt:
|
|
218
|
+
return u(() => ({ sendPrompt: F }), [F]);
|
|
196
219
|
}
|
|
197
220
|
//#endregion
|
|
198
|
-
export {
|
|
221
|
+
export { O as useSandboxAssistantTransport };
|
|
199
222
|
|
|
200
223
|
//# sourceMappingURL=createSandboxAssistantTransport.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createSandboxAssistantTransport.js","names":[],"sources":["../../../src/bigconsole/assistant/createSandboxAssistantTransport.ts"],"sourcesContent":["/**\n * BigConsole adapter for the shared fe-libs AssistantWidget.\n *\n * The floating widget (fe-libs, Layer 1) is backend-agnostic — it calls an\n * injected `AssistantTransport`. This hook builds a transport that drives the\n * sandbox AI assistant (combined `assistant` mode = docs Q&A + api-calls): it\n * provisions/reuses a sandbox, opens a session, dispatches the prompt async,\n * then polls for the streamed answer. The agent introspects the GraphQL schema\n * and performs API calls on the user's behalf using their workspace token,\n * contextual to the current screen (via `gatherPageContext`).\n *\n * This is a faithful port of microfe-vibecontrols'\n * `services/createSandboxAssistantTransport.ts`; the only product-specific\n * difference lives in `assistantApi.createAssistantSandbox`\n * (`AI_ASSISTANT_PRODUCT=bigconsole`).\n */\n\nimport { useCallback, useMemo, useRef } from 'react';\nimport { useAuthToken } from '@burdenoff/fe-libs/shared/providers/shell';\nimport {\n createAssistantSandbox,\n createAssistantSession,\n extendAssistantSandboxTTL,\n findExistingSandbox,\n getAssistantMessages,\n sendAssistantPromptAsync,\n waitForAssistantServiceReady,\n waitForSandboxReady,\n} from './assistantApi';\nimport { gatherPageContext } from './pageContext';\nimport type { AssistantMode, AssistantRawMessage, AssistantSandboxAuthContext } from './types';\n\n/**\n * Locally-defined mirror of the fe-libs `AssistantTransport` contract.\n *\n * Intentionally NOT imported from `@burdenoff/fe-libs`: microfe's tsconfig maps\n * `@burdenoff/fe-libs/*` to fe-libs *source*, so vite-plugin-dts would rewrite a\n * cross-package type used in this hook's public signature to a broken\n * source-relative path in the emitted `.d.ts`. Structural typing makes this\n * shape assignable to fe-libs' `AssistantTransport` at the call site\n * (bigconsole-app's AppShell), which is where compatibility is enforced.\n */\ninterface AssistantSendArgs {\n prompt: string;\n onProgress: (partialText: string) => void;\n signal: AbortSignal;\n}\n\nexport interface AssistantTransport {\n sendPrompt: (args: AssistantSendArgs) => Promise<{ text: string }>;\n}\n\n// The sandbox runs the `ai-assistant-api-calls` image (see assistantApi\n// `getImageForMode` — `assistant` maps to that image). The combined `assistant`\n// mode IS supported by the CF proxy images (v2026.618.3+). VibeControls uses\n// `assistant` mode in production successfully. This enables docs Q&A + API calls.\nconst MODE: AssistantMode = 'assistant';\nconst STREAM_BUDGET_MS = 180_000;\nconst POLL_INTERVAL_MS = 1500;\nconst TTL_EXTEND_INTERVAL_MS = 30_000;\n\n// ── Context helpers (mirror vibecontrols' resolution) ────────────────\n\nfunction getProfileContextValue(key: 'workspaceId' | 'organizationId'): string {\n try {\n const activeContextKey =\n key === 'workspaceId' ? 'burdenoff-active-context-workspace' : 'burdenoff-active-context-organization';\n const activeContextValue = localStorage.getItem(activeContextKey);\n if (activeContextValue) return activeContextValue;\n\n const activeProfileId = sessionStorage.getItem('bf-active-profile');\n if (!activeProfileId) return '';\n const raw = localStorage.getItem(`bf-p-${activeProfileId}-context`);\n if (!raw) return '';\n const context = JSON.parse(raw) as { workspaceId?: string; organizationId?: string };\n return context[key] ?? '';\n } catch {\n return '';\n }\n}\n\nfunction getWorkspaceId(fallback: string | null): string {\n const params = new URLSearchParams(window.location.search);\n return params.get('workspace') ?? getProfileContextValue('workspaceId') ?? fallback ?? '';\n}\n\nfunction getOrganizationId(): string {\n const params = new URLSearchParams(window.location.search);\n return params.get('org') ?? getProfileContextValue('organizationId');\n}\n\n// ── Message-progress helpers (pure; mirror vibecontrols) ─────────────\n\nfunction getRawMessageCreatedAt(message: AssistantRawMessage): number {\n return message.info?.time?.created ?? 0;\n}\n\nfunction getAssistantText(parts: AssistantRawMessage['parts']): string {\n return (parts ?? [])\n .filter((part) => part.type === 'text' && typeof part.text === 'string')\n .map((part) => part.text?.trim() ?? '')\n .filter(Boolean)\n .join('\\n');\n}\n\nfunction getToolProgress(parts: AssistantRawMessage['parts']): string[] {\n return (parts ?? [])\n .filter((part) => part.type === 'tool' && part.tool)\n .map((part) => {\n const status = part.state?.status ?? 'running';\n const tool = part.tool ?? 'tool';\n if (status === 'completed') return `Completed: ${tool}`;\n if (status === 'failed') return `Failed: ${tool}`;\n return `Running: ${tool}`;\n });\n}\n\nfunction buildProgress(\n messages: AssistantRawMessage[],\n sinceMs: number,\n previousContent?: string,\n previousContentAtMs?: number\n): { content: string; done: boolean } {\n const relevant = messages\n .filter((message) => message.info?.role === 'assistant' && getRawMessageCreatedAt(message) >= sinceMs)\n .sort((left, right) => getRawMessageCreatedAt(left) - getRawMessageCreatedAt(right));\n\n // Debug: log message filtering when no relevant messages found\n if (relevant.length === 0 && messages.length > 0) {\n console.log('[BigConsole-Assistant] buildProgress: no relevant messages', {\n totalMessages: messages.length,\n sinceMs,\n messageRoles: messages.map((m) => m.info?.role),\n messageTimestamps: messages.map((m) => m.info?.time?.created),\n });\n }\n\n let content: string;\n let done: boolean;\n\n if (relevant.length === 0) {\n content = 'Thinking…';\n // Staleness fallback: if no messages have appeared after 15+ seconds of polling,\n // treat the response as complete even when messages get filtered out\n // (e.g., due to timestamp skew or role mismatch).\n done =\n previousContent === content && previousContentAtMs !== undefined && Date.now() - previousContentAtMs >= 15_000;\n } else {\n const latest = relevant[relevant.length - 1]!;\n const text = getAssistantText(latest.parts);\n const toolProgress = getToolProgress(latest.parts);\n content = [text, ...toolProgress].filter(Boolean).join('\\n\\n') || 'Thinking…';\n\n const officiallyDone = Boolean(latest.info?.time?.completed) && (Boolean(text) || toolProgress.length > 0);\n\n // Staleness fallback: if content hasn't changed in 15 s, treat the build as\n // complete even when the assistant forgot to set `completed`.\n const staleDone =\n !officiallyDone &&\n previousContent === content &&\n previousContentAtMs !== undefined &&\n Date.now() - previousContentAtMs >= 15_000;\n\n done = officiallyDone || staleDone;\n }\n\n return { content, done };\n}\n\nfunction sanitize(response: string): string {\n return response\n .replace(/(Authorization\\s*:\\s*Bearer\\s+)[^\\s\\n]+/gi, '$1[REDACTED]')\n .replace(/(X-Workspace-Authorization\\s*:\\s*Bearer\\s+)[^\\s\\n]+/gi, '$1[REDACTED]')\n .replace(/\\beyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9._-]+\\.[A-Za-z0-9._-]+\\b/g, '[REDACTED_JWT]')\n .replace(/\\bsk-ant-[A-Za-z0-9-]+\\b/g, '[REDACTED_API_KEY]');\n}\n\nfunction isRecoverable(error: unknown): boolean {\n const message = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();\n if (\n message.includes('rate limit exceeded') ||\n message.includes('unauthorized') ||\n message.includes('k8s api error 401')\n ) {\n return false;\n }\n return [\n 'sandbox not found',\n 'sandbox is not running',\n 'sandbox service not available yet',\n 'sandbox failed',\n 'sandbox startup timed out',\n 'assistant service did not become healthy',\n 'proxy error: 404',\n 'proxy error: 502',\n 'proxy error: 503',\n 'unable to connect',\n 'image pull',\n 'container failed',\n 'bootstrap failed',\n ].some((fragment) => message.includes(fragment));\n}\n\n/**\n * Returns a memoized `AssistantTransport` wired to the BigConsole sandbox\n * assistant agent. The sandbox + session are cached in refs so follow-up turns\n * reuse the warm environment for the lifetime of the host shell.\n */\nexport function useSandboxAssistantTransport(): AssistantTransport {\n const { getAccessToken, getWorkspaceToken, userId, workspaceId: ctxWorkspaceId } = useAuthToken();\n\n // Initialize from sessionStorage so page refresh doesn't create a new sandbox\n const [initialSandboxId, initialSessionId] = useMemo(() => {\n try {\n return [sessionStorage.getItem('bc-assistant-sandbox-id'), sessionStorage.getItem('bc-assistant-session-id')];\n } catch {\n return [null, null] as const;\n }\n }, []);\n\n const sandboxIdRef = useRef<string | null>(initialSandboxId);\n const sessionIdRef = useRef<string | null>(initialSessionId);\n\n const persistSandboxId = useCallback((id: string | null) => {\n sandboxIdRef.current = id;\n if (id) {\n sessionStorage.setItem('bc-assistant-sandbox-id', id);\n } else {\n sessionStorage.removeItem('bc-assistant-sandbox-id');\n }\n }, []);\n\n const persistSessionId = useCallback((id: string | null) => {\n sessionIdRef.current = id;\n if (id) {\n sessionStorage.setItem('bc-assistant-session-id', id);\n } else {\n sessionStorage.removeItem('bc-assistant-session-id');\n }\n }, []);\n\n const ensureRuntime = useCallback(\n async (\n workspaceId: string,\n authContext: AssistantSandboxAuthContext\n ): Promise<{ sandboxId: string; sessionId: string }> => {\n let sandboxId = sandboxIdRef.current;\n console.log('[BigConsole-Assistant] ensureRuntime start', { sandboxId, workspaceId });\n if (!sandboxId) {\n console.log('[BigConsole-Assistant] findExistingSandbox called');\n sandboxId = await findExistingSandbox(workspaceId, MODE, authContext);\n console.log('[BigConsole-Assistant] findExistingSandbox result', { sandboxId });\n if (!sandboxId) {\n if (!getAccessToken()) {\n throw new Error('The assistant requires an authenticated session. Please sign in again.');\n }\n sandboxId = await createAssistantSandbox(MODE, workspaceId, authContext);\n console.log('[BigConsole-Assistant] createAssistantSandbox result', { sandboxId });\n }\n console.log('[BigConsole-Assistant] waitForSandboxReady called', { sandboxId });\n await waitForSandboxReady(sandboxId, workspaceId, authContext);\n console.log('[BigConsole-Assistant] waitForSandboxReady done', { sandboxId });\n console.log('[BigConsole-Assistant] waitForAssistantServiceReady called', { sandboxId });\n await waitForAssistantServiceReady(sandboxId, workspaceId, authContext);\n console.log('[BigConsole-Assistant] waitForAssistantServiceReady done', { sandboxId });\n persistSandboxId(sandboxId);\n }\n\n let sessionId = sessionIdRef.current;\n console.log('[BigConsole-Assistant] session check', { sessionId, sandboxId });\n if (!sessionId) {\n console.log('[BigConsole-Assistant] createAssistantSession called', { sandboxId, workspaceId });\n const result = await createAssistantSession(sandboxId, workspaceId, MODE, authContext);\n sessionId = result.sessionId;\n persistSessionId(sessionId);\n }\n\n return { sandboxId, sessionId };\n },\n [getAccessToken]\n );\n\n const sendPrompt = useCallback(\n async ({ prompt, onProgress, signal }: AssistantSendArgs): Promise<{ text: string }> => {\n const workspaceId = getWorkspaceId(ctxWorkspaceId);\n console.log('[BigConsole-Assistant] sendPrompt called', {\n promptLength: prompt.length,\n workspaceId,\n hasCtxWorkspaceId: !!ctxWorkspaceId,\n authContextKeys: {\n hasAccessToken: !!getAccessToken(),\n hasWorkspaceToken: !!getWorkspaceToken(),\n hasUserId: !!userId,\n },\n locationSearch: window.location.search,\n });\n if (!workspaceId) {\n throw new Error('The assistant needs an active workspace. Open a workspace and try again.');\n }\n const authContext: AssistantSandboxAuthContext = {\n accessToken: getAccessToken(),\n workspaceToken: getWorkspaceToken(),\n userId,\n organizationId: getOrganizationId(),\n };\n console.log('[BigConsole-Assistant] authContext prepared', {\n hasAccessToken: !!authContext.accessToken,\n hasWorkspaceToken: !!authContext.workspaceToken,\n hasUserId: !!authContext.userId,\n hasOrgId: !!authContext.organizationId,\n });\n\n const run = async (attempt: 1 | 2): Promise<{ text: string }> => {\n try {\n console.log('[BigConsole-Assistant] run attempt', attempt);\n const { sandboxId, sessionId } = await ensureRuntime(workspaceId, authContext);\n console.log('[BigConsole-Assistant] ensureRuntime resolved', { sandboxId, sessionId });\n\n const startedAt = Date.now();\n console.log('[BigConsole-Assistant] calling sendAssistantPromptAsync', {\n sandboxId,\n workspaceId,\n sessionId,\n promptLength: prompt.length,\n });\n await sendAssistantPromptAsync(\n sandboxId,\n workspaceId,\n sessionId,\n prompt,\n MODE,\n gatherPageContext(),\n authContext\n );\n\n const timeoutAt = Date.now() + STREAM_BUDGET_MS;\n let lastTtlExtensionAt = Date.now();\n let lastContent = '';\n let lastContentChangeAt = Date.now();\n let progress = buildProgress([], startedAt);\n\n while (Date.now() < timeoutAt) {\n if (signal.aborted) throw new Error('Cancelled');\n\n const messages = await getAssistantMessages(sandboxId, workspaceId, sessionId, authContext, 50);\n console.log('[BigConsole-Assistant] poll', {\n elapsedMs: Date.now() - startedAt,\n messageCount: messages.length,\n firstFewRoles: messages.slice(0, 3).map((m) => m.info?.role),\n firstFewTimestamps: messages.slice(0, 3).map((m) => m.info?.time?.created),\n });\n progress = buildProgress(messages, startedAt, lastContent, lastContentChangeAt);\n console.log('[BigConsole-Assistant] progress', {\n contentPreview: progress.content.slice(0, 100),\n done: progress.done,\n lastContentChangeAt: Date.now() - lastContentChangeAt,\n });\n if (progress.content !== lastContent) {\n lastContent = progress.content;\n lastContentChangeAt = Date.now();\n }\n onProgress(sanitize(progress.content));\n if (progress.done) {\n console.log('[BigConsole-Assistant] progress.done=true, breaking poll loop');\n break;\n }\n\n if (Date.now() - lastTtlExtensionAt > TTL_EXTEND_INTERVAL_MS) {\n await extendAssistantSandboxTTL(sandboxId, workspaceId, 600, authContext).catch(() => undefined);\n lastTtlExtensionAt = Date.now();\n }\n\n await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));\n }\n\n if (!progress.done) {\n throw new Error('The assistant timed out while responding. Please try again.');\n }\n\n return { text: sanitize(progress.content) };\n } catch (error) {\n console.error('[BigConsole-Assistant] run error', {\n attempt,\n error: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n sandboxId: sandboxIdRef.current,\n sessionId: sessionIdRef.current,\n });\n // A stale/expired sandbox or session is recoverable — drop the warm\n // refs and retry once from a clean runtime.\n if (attempt === 1 && isRecoverable(error)) {\n persistSandboxId(null);\n persistSessionId(null);\n return run(2);\n }\n throw error;\n }\n };\n\n return run(1);\n },\n [ctxWorkspaceId, ensureRuntime, getAccessToken, getWorkspaceToken, userId, persistSandboxId, persistSessionId]\n );\n\n return useMemo<AssistantTransport>(() => ({ sendPrompt }), [sendPrompt]);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"createSandboxAssistantTransport.js","names":[],"sources":["../../../src/bigconsole/assistant/createSandboxAssistantTransport.ts"],"sourcesContent":["/**\n * BigConsole adapter for the shared fe-libs AssistantWidget.\n *\n * The floating widget (fe-libs, Layer 1) is backend-agnostic — it calls an\n * injected `AssistantTransport`. This hook builds a transport that drives the\n * sandbox AI assistant (combined `assistant` mode = docs Q&A + api-calls): it\n * provisions/reuses a sandbox, opens a session, dispatches the prompt async,\n * then polls for the streamed answer. The agent introspects the GraphQL schema\n * and performs API calls on the user's behalf using their workspace token,\n * contextual to the current screen (via `gatherPageContext`).\n *\n * This is a faithful port of microfe-vibecontrols'\n * `services/createSandboxAssistantTransport.ts`; the only product-specific\n * difference lives in `assistantApi.createAssistantSandbox`\n * (`AI_ASSISTANT_PRODUCT=bigconsole`).\n */\n\nimport { useCallback, useMemo, useRef } from 'react';\nimport { useAuthToken } from '@burdenoff/fe-libs/shared/providers/shell';\nimport {\n createAssistantSandbox,\n createAssistantSession,\n extendAssistantSandboxTTL,\n findExistingSandbox,\n getAssistantMessages,\n sendAssistantPromptAsync,\n waitForAssistantServiceReady,\n waitForSandboxReady,\n} from './assistantApi';\nimport { gatherPageContext } from './pageContext';\nimport type { AssistantMode, AssistantRawMessage, AssistantSandboxAuthContext } from './types';\n\n/**\n * Locally-defined mirror of the fe-libs `AssistantTransport` contract.\n *\n * Intentionally NOT imported from `@burdenoff/fe-libs`: microfe's tsconfig maps\n * `@burdenoff/fe-libs/*` to fe-libs *source*, so vite-plugin-dts would rewrite a\n * cross-package type used in this hook's public signature to a broken\n * source-relative path in the emitted `.d.ts`. Structural typing makes this\n * shape assignable to fe-libs' `AssistantTransport` at the call site\n * (bigconsole-app's AppShell), which is where compatibility is enforced.\n */\ninterface AssistantSendArgs {\n prompt: string;\n onProgress: (partialText: string) => void;\n signal: AbortSignal;\n}\n\nexport interface AssistantTransport {\n sendPrompt: (args: AssistantSendArgs) => Promise<{ text: string }>;\n}\n\n// The sandbox runs the `ai-assistant-api-calls` image (see assistantApi\n// `getImageForMode` — `assistant` maps to that image). The combined `assistant`\n// mode IS supported by the CF proxy images (v2026.618.3+). VibeControls uses\n// `assistant` mode in production successfully. This enables docs Q&A + API calls.\nconst MODE: AssistantMode = 'assistant';\nconst STREAM_BUDGET_MS = 180_000;\nconst POLL_INTERVAL_MS = 1500;\nconst TTL_EXTEND_INTERVAL_MS = 30_000;\n\n// ── Context helpers (mirror vibecontrols' resolution) ────────────────\n\nfunction getProfileContextValue(key: 'workspaceId' | 'organizationId'): string {\n try {\n const activeContextKey =\n key === 'workspaceId' ? 'burdenoff-active-context-workspace' : 'burdenoff-active-context-organization';\n const activeContextValue = localStorage.getItem(activeContextKey);\n if (activeContextValue) return activeContextValue;\n\n const activeProfileId = sessionStorage.getItem('bf-active-profile');\n if (!activeProfileId) return '';\n const raw = localStorage.getItem(`bf-p-${activeProfileId}-context`);\n if (!raw) return '';\n const context = JSON.parse(raw) as { workspaceId?: string; organizationId?: string };\n return context[key] ?? '';\n } catch {\n return '';\n }\n}\n\nfunction getWorkspaceId(fallback: string | null): string {\n const params = new URLSearchParams(window.location.search);\n return params.get('workspace') ?? getProfileContextValue('workspaceId') ?? fallback ?? '';\n}\n\nfunction getOrganizationId(): string {\n const params = new URLSearchParams(window.location.search);\n return params.get('org') ?? getProfileContextValue('organizationId');\n}\n\n// ── Message-progress helpers (pure; mirror vibecontrols) ─────────────\n\nfunction getMessageRole(message: AssistantRawMessage): string | undefined {\n // Check nested format first, then flat format\n return message.info?.role ?? message.role;\n}\n\nfunction getRawMessageCreatedAt(message: AssistantRawMessage): number {\n // Check nested format first (epoch ms), then flat format (ISO string or epoch ms)\n const nested = message.info?.time?.created;\n if (nested !== undefined) return nested;\n const flat = message.createdAt;\n if (flat === undefined) return 0;\n // If it's a string (ISO), parse it; otherwise treat as epoch ms\n if (typeof flat === 'string') {\n const parsed = Date.parse(flat);\n return isNaN(parsed) ? 0 : parsed;\n }\n return flat;\n}\n\nfunction getMessageCompleted(message: AssistantRawMessage): number | undefined {\n // Check nested format first, then flat format\n const nested = message.info?.time?.completed;\n if (nested !== undefined) return nested;\n const flat = message.completedAt;\n if (flat === undefined) return undefined;\n if (typeof flat === 'string') {\n const parsed = Date.parse(flat);\n return isNaN(parsed) ? undefined : parsed;\n }\n return flat;\n}\n\nfunction getAssistantText(message: AssistantRawMessage): string {\n // Check parts format first (nested), then flat content\n const parts = message.parts ?? [];\n const textFromParts = (parts ?? [])\n .filter((part) => part.type === 'text' && typeof part.text === 'string')\n .map((part) => part.text?.trim() ?? '')\n .filter(Boolean)\n .join('\\n');\n if (textFromParts) return textFromParts;\n // Fallback to flat content field\n return typeof message.content === 'string' ? message.content.trim() : '';\n}\n\nfunction getToolProgress(message: AssistantRawMessage): string[] {\n const parts = message.parts ?? [];\n return parts\n .filter((part) => part.type === 'tool' && part.tool)\n .map((part) => {\n const status = part.state?.status ?? 'running';\n const tool = part.tool ?? 'tool';\n if (status === 'completed') return `Completed: ${tool}`;\n if (status === 'failed') return `Failed: ${tool}`;\n return `Running: ${tool}`;\n });\n}\n\nfunction buildProgress(\n messages: AssistantRawMessage[],\n sinceMs: number,\n previousContent?: string,\n previousContentAtMs?: number\n): { content: string; done: boolean } {\n const relevant = messages\n .filter((message) => getMessageRole(message) === 'assistant' && getRawMessageCreatedAt(message) >= sinceMs)\n .sort((left, right) => getRawMessageCreatedAt(left) - getRawMessageCreatedAt(right));\n\n // Debug: log message filtering when no relevant messages found\n if (relevant.length === 0 && messages.length > 0) {\n console.log('[BigConsole-Assistant] buildProgress: no relevant messages', {\n totalMessages: messages.length,\n sinceMs,\n messageRoles: messages.map((m) => getMessageRole(m)),\n messageTimestamps: messages.map((m) => getRawMessageCreatedAt(m)),\n });\n }\n\n let content: string;\n let done: boolean;\n\n if (relevant.length === 0) {\n content = 'Thinking…';\n // Staleness fallback: if no messages have appeared after 15+ seconds of polling,\n // treat the response as complete even when messages get filtered out\n // (e.g., due to timestamp skew or role mismatch).\n done =\n previousContent === content && previousContentAtMs !== undefined && Date.now() - previousContentAtMs >= 15_000;\n } else {\n const latest = relevant[relevant.length - 1]!;\n const text = getAssistantText(latest);\n const toolProgress = getToolProgress(latest);\n content = [text, ...toolProgress].filter(Boolean).join('\\n\\n') || 'Thinking…';\n\n const officiallyDone = Boolean(getMessageCompleted(latest)) && (Boolean(text) || toolProgress.length > 0);\n\n // Staleness fallback: if content hasn't changed in 15 s, treat the build as\n // complete even when the assistant forgot to set `completed`.\n const staleDone =\n !officiallyDone &&\n previousContent === content &&\n previousContentAtMs !== undefined &&\n Date.now() - previousContentAtMs >= 15_000;\n\n done = officiallyDone || staleDone;\n }\n\n return { content, done };\n}\n\nfunction sanitize(response: string): string {\n return response\n .replace(/(Authorization\\s*:\\s*Bearer\\s+)[^\\s\\n]+/gi, '$1[REDACTED]')\n .replace(/(X-Workspace-Authorization\\s*:\\s*Bearer\\s+)[^\\s\\n]+/gi, '$1[REDACTED]')\n .replace(/\\beyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9._-]+\\.[A-Za-z0-9._-]+\\b/g, '[REDACTED_JWT]')\n .replace(/\\bsk-ant-[A-Za-z0-9-]+\\b/g, '[REDACTED_API_KEY]');\n}\n\nfunction isRecoverable(error: unknown): boolean {\n const message = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();\n if (\n message.includes('rate limit exceeded') ||\n message.includes('unauthorized') ||\n message.includes('k8s api error 401')\n ) {\n return false;\n }\n return [\n 'sandbox not found',\n 'sandbox is not running',\n 'sandbox service not available yet',\n 'sandbox failed',\n 'sandbox startup timed out',\n 'assistant service did not become healthy',\n 'proxy error: 404',\n 'proxy error: 502',\n 'proxy error: 503',\n 'unable to connect',\n 'image pull',\n 'container failed',\n 'bootstrap failed',\n ].some((fragment) => message.includes(fragment));\n}\n\n/**\n * Returns a memoized `AssistantTransport` wired to the BigConsole sandbox\n * assistant agent. The sandbox + session are cached in refs so follow-up turns\n * reuse the warm environment for the lifetime of the host shell.\n */\nexport function useSandboxAssistantTransport(): AssistantTransport {\n const { getAccessToken, getWorkspaceToken, userId, workspaceId: ctxWorkspaceId } = useAuthToken();\n\n // Initialize from sessionStorage so page refresh doesn't create a new sandbox\n const [initialSandboxId, initialSessionId] = useMemo(() => {\n try {\n return [sessionStorage.getItem('bc-assistant-sandbox-id'), sessionStorage.getItem('bc-assistant-session-id')];\n } catch {\n return [null, null] as const;\n }\n }, []);\n\n const sandboxIdRef = useRef<string | null>(initialSandboxId);\n const sessionIdRef = useRef<string | null>(initialSessionId);\n\n const persistSandboxId = useCallback((id: string | null) => {\n sandboxIdRef.current = id;\n if (id) {\n sessionStorage.setItem('bc-assistant-sandbox-id', id);\n } else {\n sessionStorage.removeItem('bc-assistant-sandbox-id');\n }\n }, []);\n\n const persistSessionId = useCallback((id: string | null) => {\n sessionIdRef.current = id;\n if (id) {\n sessionStorage.setItem('bc-assistant-session-id', id);\n } else {\n sessionStorage.removeItem('bc-assistant-session-id');\n }\n }, []);\n\n const ensureRuntime = useCallback(\n async (\n workspaceId: string,\n authContext: AssistantSandboxAuthContext\n ): Promise<{ sandboxId: string; sessionId: string }> => {\n let sandboxId = sandboxIdRef.current;\n console.log('[BigConsole-Assistant] ensureRuntime start', { sandboxId, workspaceId });\n if (!sandboxId) {\n console.log('[BigConsole-Assistant] findExistingSandbox called');\n sandboxId = await findExistingSandbox(workspaceId, MODE, authContext);\n console.log('[BigConsole-Assistant] findExistingSandbox result', { sandboxId });\n if (!sandboxId) {\n if (!getAccessToken()) {\n throw new Error('The assistant requires an authenticated session. Please sign in again.');\n }\n sandboxId = await createAssistantSandbox(MODE, workspaceId, authContext);\n console.log('[BigConsole-Assistant] createAssistantSandbox result', { sandboxId });\n }\n console.log('[BigConsole-Assistant] waitForSandboxReady called', { sandboxId });\n await waitForSandboxReady(sandboxId, workspaceId, authContext);\n console.log('[BigConsole-Assistant] waitForSandboxReady done', { sandboxId });\n console.log('[BigConsole-Assistant] waitForAssistantServiceReady called', { sandboxId });\n await waitForAssistantServiceReady(sandboxId, workspaceId, authContext);\n console.log('[BigConsole-Assistant] waitForAssistantServiceReady done', { sandboxId });\n persistSandboxId(sandboxId);\n }\n\n let sessionId = sessionIdRef.current;\n console.log('[BigConsole-Assistant] session check', { sessionId, sandboxId });\n if (!sessionId) {\n console.log('[BigConsole-Assistant] createAssistantSession called', { sandboxId, workspaceId });\n const result = await createAssistantSession(sandboxId, workspaceId, MODE, authContext);\n sessionId = result.sessionId;\n persistSessionId(sessionId);\n }\n\n return { sandboxId, sessionId };\n },\n [getAccessToken]\n );\n\n const sendPrompt = useCallback(\n async ({ prompt, onProgress, signal }: AssistantSendArgs): Promise<{ text: string }> => {\n const workspaceId = getWorkspaceId(ctxWorkspaceId);\n console.log('[BigConsole-Assistant] sendPrompt called', {\n promptLength: prompt.length,\n workspaceId,\n hasCtxWorkspaceId: !!ctxWorkspaceId,\n authContextKeys: {\n hasAccessToken: !!getAccessToken(),\n hasWorkspaceToken: !!getWorkspaceToken(),\n hasUserId: !!userId,\n },\n locationSearch: window.location.search,\n });\n if (!workspaceId) {\n throw new Error('The assistant needs an active workspace. Open a workspace and try again.');\n }\n const authContext: AssistantSandboxAuthContext = {\n accessToken: getAccessToken(),\n workspaceToken: getWorkspaceToken(),\n userId,\n organizationId: getOrganizationId(),\n };\n console.log('[BigConsole-Assistant] authContext prepared', {\n hasAccessToken: !!authContext.accessToken,\n hasWorkspaceToken: !!authContext.workspaceToken,\n hasUserId: !!authContext.userId,\n hasOrgId: !!authContext.organizationId,\n });\n\n const run = async (attempt: 1 | 2): Promise<{ text: string }> => {\n try {\n console.log('[BigConsole-Assistant] run attempt', attempt);\n const { sandboxId, sessionId } = await ensureRuntime(workspaceId, authContext);\n console.log('[BigConsole-Assistant] ensureRuntime resolved', { sandboxId, sessionId });\n\n const startedAt = Date.now();\n console.log('[BigConsole-Assistant] calling sendAssistantPromptAsync', {\n sandboxId,\n workspaceId,\n sessionId,\n promptLength: prompt.length,\n });\n await sendAssistantPromptAsync(\n sandboxId,\n workspaceId,\n sessionId,\n prompt,\n MODE,\n gatherPageContext(),\n authContext\n );\n\n const timeoutAt = Date.now() + STREAM_BUDGET_MS;\n let lastTtlExtensionAt = Date.now();\n let lastContent = '';\n let lastContentChangeAt = Date.now();\n let progress = buildProgress([], startedAt);\n\n while (Date.now() < timeoutAt) {\n if (signal.aborted) throw new Error('Cancelled');\n\n const messages = await getAssistantMessages(sandboxId, workspaceId, sessionId, authContext, 50);\n console.log('[BigConsole-Assistant] poll', {\n elapsedMs: Date.now() - startedAt,\n messageCount: messages.length,\n firstFewRoles: messages.slice(0, 3).map((m) => getMessageRole(m)),\n firstFewTimestamps: messages.slice(0, 3).map((m) => getRawMessageCreatedAt(m)),\n });\n progress = buildProgress(messages, startedAt, lastContent, lastContentChangeAt);\n console.log('[BigConsole-Assistant] progress', {\n contentPreview: progress.content.slice(0, 100),\n done: progress.done,\n lastContentChangeAt: Date.now() - lastContentChangeAt,\n });\n if (progress.content !== lastContent) {\n lastContent = progress.content;\n lastContentChangeAt = Date.now();\n }\n onProgress(sanitize(progress.content));\n if (progress.done) {\n console.log('[BigConsole-Assistant] progress.done=true, breaking poll loop');\n break;\n }\n\n if (Date.now() - lastTtlExtensionAt > TTL_EXTEND_INTERVAL_MS) {\n await extendAssistantSandboxTTL(sandboxId, workspaceId, 600, authContext).catch(() => undefined);\n lastTtlExtensionAt = Date.now();\n }\n\n await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));\n }\n\n if (!progress.done) {\n throw new Error('The assistant timed out while responding. Please try again.');\n }\n\n return { text: sanitize(progress.content) };\n } catch (error) {\n console.error('[BigConsole-Assistant] run error', {\n attempt,\n error: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n sandboxId: sandboxIdRef.current,\n sessionId: sessionIdRef.current,\n });\n // A stale/expired sandbox or session is recoverable — drop the warm\n // refs and retry once from a clean runtime.\n if (attempt === 1 && isRecoverable(error)) {\n persistSandboxId(null);\n persistSessionId(null);\n return run(2);\n }\n throw error;\n }\n };\n\n return run(1);\n },\n [ctxWorkspaceId, ensureRuntime, getAccessToken, getWorkspaceToken, userId, persistSandboxId, persistSessionId]\n );\n\n return useMemo<AssistantTransport>(() => ({ sendPrompt }), [sendPrompt]);\n}\n"],"mappings":"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"}
|
|
@@ -1,42 +1,135 @@
|
|
|
1
1
|
import { memo as e, useCallback as t, useEffect as n, useMemo as r, useState as i } from "react";
|
|
2
2
|
import { jsx as a, jsxs as o } from "react/jsx-runtime";
|
|
3
3
|
//#region src/bigconsole/components/widgets/table/TableConfig.tsx
|
|
4
|
-
var s =
|
|
5
|
-
|
|
4
|
+
var s = [
|
|
5
|
+
{
|
|
6
|
+
value: "gt",
|
|
7
|
+
label: "> greater than"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
value: "gte",
|
|
11
|
+
label: "≥ at least"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
value: "lt",
|
|
15
|
+
label: "< less than"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
value: "lte",
|
|
19
|
+
label: "≤ at most"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
value: "eq",
|
|
23
|
+
label: "= equals"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
value: "neq",
|
|
27
|
+
label: "≠ not equal"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
value: "between",
|
|
31
|
+
label: "between"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
value: "outside",
|
|
35
|
+
label: "outside"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
value: "contains",
|
|
39
|
+
label: "contains"
|
|
40
|
+
}
|
|
41
|
+
], c = [
|
|
42
|
+
{
|
|
43
|
+
value: "danger",
|
|
44
|
+
label: "Red — danger"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
value: "warning",
|
|
48
|
+
label: "Amber — warning"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
value: "success",
|
|
52
|
+
label: "Green — good"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
value: "info",
|
|
56
|
+
label: "Blue — info"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
value: "neutral",
|
|
60
|
+
label: "Neutral"
|
|
61
|
+
}
|
|
62
|
+
], l = "px-2 py-1 text-xs text-text-primary bg-bg-surface border border-border-default rounded-md focus:outline-none focus:ring-2 focus:ring-action-primary-bg", u = e(function({ config: e, onChange: u }) {
|
|
63
|
+
let [d, f] = i(r(() => (e.columns || []).map((e) => typeof e == "string" ? {
|
|
6
64
|
field: e,
|
|
7
65
|
header: e.charAt(0).toUpperCase() + e.slice(1).replace(/_/g, " ")
|
|
8
66
|
} : e), []));
|
|
9
67
|
n(() => {
|
|
10
|
-
JSON.stringify(e.columns) !== JSON.stringify(
|
|
68
|
+
JSON.stringify(e.columns) !== JSON.stringify(d) && d.length > 0 && u({
|
|
11
69
|
...e,
|
|
12
|
-
columns:
|
|
70
|
+
columns: d
|
|
13
71
|
});
|
|
14
|
-
}, [
|
|
15
|
-
|
|
72
|
+
}, [d]), n(() => {
|
|
73
|
+
f((e.columns || []).map((e) => typeof e == "string" ? {
|
|
16
74
|
field: e,
|
|
17
75
|
header: e.charAt(0).toUpperCase() + e.slice(1).replace(/_/g, " ")
|
|
18
76
|
} : e));
|
|
19
77
|
}, [e.columns]);
|
|
20
|
-
let
|
|
21
|
-
|
|
78
|
+
let p = t((t, n) => {
|
|
79
|
+
u({
|
|
22
80
|
...e,
|
|
23
81
|
[t]: n
|
|
24
82
|
});
|
|
25
|
-
}, [e,
|
|
26
|
-
|
|
83
|
+
}, [e, u]), m = t((e, t, n) => {
|
|
84
|
+
f((r) => {
|
|
27
85
|
let i = [...r];
|
|
28
86
|
return i[e] = {
|
|
29
87
|
...i[e],
|
|
30
88
|
[t]: n
|
|
31
89
|
}, i;
|
|
32
90
|
});
|
|
33
|
-
}, []),
|
|
34
|
-
|
|
91
|
+
}, []), h = t((e, t) => {
|
|
92
|
+
f((n) => {
|
|
93
|
+
let r = [...n];
|
|
94
|
+
return r[e] = {
|
|
95
|
+
...r[e],
|
|
96
|
+
conditionalRules: t
|
|
97
|
+
}, r;
|
|
98
|
+
});
|
|
99
|
+
}, []), g = t((e) => {
|
|
100
|
+
let t = d[e]?.conditionalRules ?? [], n = {
|
|
101
|
+
operator: "gt",
|
|
102
|
+
value: 0,
|
|
103
|
+
style: {
|
|
104
|
+
bgColor: "danger",
|
|
105
|
+
textColor: "danger",
|
|
106
|
+
bold: !0
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
h(e, [...t, n]);
|
|
110
|
+
}, [d, h]), _ = t((e, t, n) => {
|
|
111
|
+
h(e, (d[e]?.conditionalRules ?? []).map((e, r) => r === t ? {
|
|
112
|
+
...e,
|
|
113
|
+
...n
|
|
114
|
+
} : e));
|
|
115
|
+
}, [d, h]), v = t((e, t, n) => {
|
|
116
|
+
h(e, (d[e]?.conditionalRules ?? []).map((e, r) => r === t ? {
|
|
117
|
+
...e,
|
|
118
|
+
style: {
|
|
119
|
+
...e.style,
|
|
120
|
+
bgColor: n,
|
|
121
|
+
textColor: n
|
|
122
|
+
}
|
|
123
|
+
} : e));
|
|
124
|
+
}, [d, h]), y = t((e, t) => {
|
|
125
|
+
h(e, (d[e]?.conditionalRules ?? []).filter((e, n) => n !== t));
|
|
126
|
+
}, [d, h]), b = t(() => {
|
|
127
|
+
f((e) => [...e, {
|
|
35
128
|
field: "",
|
|
36
129
|
header: ""
|
|
37
130
|
}]);
|
|
38
|
-
}, []),
|
|
39
|
-
|
|
131
|
+
}, []), x = t((e) => {
|
|
132
|
+
f((t) => t.filter((t, n) => n !== e));
|
|
40
133
|
}, []);
|
|
41
134
|
return /* @__PURE__ */ o("div", {
|
|
42
135
|
className: "space-y-4",
|
|
@@ -46,7 +139,7 @@ var s = e(function({ config: e, onChange: s }) {
|
|
|
46
139
|
children: "Page Size"
|
|
47
140
|
}), /* @__PURE__ */ o("select", {
|
|
48
141
|
value: e.pageSize || 10,
|
|
49
|
-
onChange: (e) =>
|
|
142
|
+
onChange: (e) => p("pageSize", Number(e.target.value)),
|
|
50
143
|
className: "\n w-full px-3 py-2\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n ",
|
|
51
144
|
children: [
|
|
52
145
|
/* @__PURE__ */ a("option", {
|
|
@@ -74,13 +167,13 @@ var s = e(function({ config: e, onChange: s }) {
|
|
|
74
167
|
children: "Columns"
|
|
75
168
|
}), /* @__PURE__ */ a("button", {
|
|
76
169
|
type: "button",
|
|
77
|
-
onClick:
|
|
170
|
+
onClick: b,
|
|
78
171
|
className: "\n text-sm text-action-primary-bg\n hover:text-action-primary-bgHover\n ",
|
|
79
172
|
children: "+ Add Column"
|
|
80
173
|
})]
|
|
81
174
|
}), /* @__PURE__ */ o("div", {
|
|
82
175
|
className: "space-y-3",
|
|
83
|
-
children: [
|
|
176
|
+
children: [d.map((e, t) => /* @__PURE__ */ o("div", {
|
|
84
177
|
className: "\n p-3\n bg-bg-sunken\n rounded-md\n space-y-2\n ",
|
|
85
178
|
children: [
|
|
86
179
|
/* @__PURE__ */ o("div", {
|
|
@@ -90,7 +183,7 @@ var s = e(function({ config: e, onChange: s }) {
|
|
|
90
183
|
children: ["Column ", t + 1]
|
|
91
184
|
}), /* @__PURE__ */ a("button", {
|
|
92
185
|
type: "button",
|
|
93
|
-
onClick: () =>
|
|
186
|
+
onClick: () => x(t),
|
|
94
187
|
className: "text-state-error hover:text-state-error/80",
|
|
95
188
|
children: /* @__PURE__ */ a("svg", {
|
|
96
189
|
className: "w-4 h-4",
|
|
@@ -111,13 +204,13 @@ var s = e(function({ config: e, onChange: s }) {
|
|
|
111
204
|
children: [/* @__PURE__ */ a("input", {
|
|
112
205
|
type: "text",
|
|
113
206
|
value: e.field || "",
|
|
114
|
-
onChange: (e) =>
|
|
207
|
+
onChange: (e) => m(t, "field", e.target.value),
|
|
115
208
|
placeholder: "Field name",
|
|
116
209
|
className: "\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n "
|
|
117
210
|
}), /* @__PURE__ */ a("input", {
|
|
118
211
|
type: "text",
|
|
119
212
|
value: e.header || "",
|
|
120
|
-
onChange: (e) =>
|
|
213
|
+
onChange: (e) => m(t, "header", e.target.value),
|
|
121
214
|
placeholder: "Header label",
|
|
122
215
|
className: "\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n "
|
|
123
216
|
})]
|
|
@@ -126,7 +219,7 @@ var s = e(function({ config: e, onChange: s }) {
|
|
|
126
219
|
className: "grid grid-cols-2 gap-2",
|
|
127
220
|
children: [/* @__PURE__ */ o("select", {
|
|
128
221
|
value: e.format || "text",
|
|
129
|
-
onChange: (e) =>
|
|
222
|
+
onChange: (e) => m(t, "format", e.target.value),
|
|
130
223
|
className: "\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n ",
|
|
131
224
|
children: [
|
|
132
225
|
/* @__PURE__ */ a("option", {
|
|
@@ -156,7 +249,7 @@ var s = e(function({ config: e, onChange: s }) {
|
|
|
156
249
|
]
|
|
157
250
|
}), /* @__PURE__ */ o("select", {
|
|
158
251
|
value: e.align || "left",
|
|
159
|
-
onChange: (e) =>
|
|
252
|
+
onChange: (e) => m(t, "align", e.target.value),
|
|
160
253
|
className: "\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n ",
|
|
161
254
|
children: [
|
|
162
255
|
/* @__PURE__ */ a("option", {
|
|
@@ -173,9 +266,107 @@ var s = e(function({ config: e, onChange: s }) {
|
|
|
173
266
|
})
|
|
174
267
|
]
|
|
175
268
|
})]
|
|
269
|
+
}),
|
|
270
|
+
/* @__PURE__ */ o("div", {
|
|
271
|
+
className: "pt-2 border-t border-border-default/60",
|
|
272
|
+
children: [
|
|
273
|
+
/* @__PURE__ */ o("div", {
|
|
274
|
+
className: "flex items-center justify-between mb-1",
|
|
275
|
+
children: [/* @__PURE__ */ a("span", {
|
|
276
|
+
className: "text-xs font-medium text-text-secondary",
|
|
277
|
+
children: "Conditional formatting"
|
|
278
|
+
}), /* @__PURE__ */ a("button", {
|
|
279
|
+
type: "button",
|
|
280
|
+
onClick: () => g(t),
|
|
281
|
+
className: "text-xs text-action-primary-bg hover:text-action-primary-bgHover",
|
|
282
|
+
children: "+ Add rule"
|
|
283
|
+
})]
|
|
284
|
+
}),
|
|
285
|
+
(e.conditionalRules?.length ?? 0) === 0 && /* @__PURE__ */ a("p", {
|
|
286
|
+
className: "text-xs text-text-secondary",
|
|
287
|
+
children: "No rules — cell shows its plain value."
|
|
288
|
+
}),
|
|
289
|
+
/* @__PURE__ */ a("div", {
|
|
290
|
+
className: "space-y-2",
|
|
291
|
+
children: (e.conditionalRules ?? []).map((e, n) => {
|
|
292
|
+
let r = e.operator === "between" || e.operator === "outside", i = e.style?.bgColor ?? e.style?.textColor ?? "danger";
|
|
293
|
+
return /* @__PURE__ */ o("div", {
|
|
294
|
+
className: "p-2 bg-bg-surface rounded-md border border-border-default space-y-2",
|
|
295
|
+
children: [/* @__PURE__ */ o("div", {
|
|
296
|
+
className: "flex items-center gap-2",
|
|
297
|
+
children: [
|
|
298
|
+
/* @__PURE__ */ a("select", {
|
|
299
|
+
value: e.operator,
|
|
300
|
+
onChange: (e) => _(t, n, { operator: e.target.value }),
|
|
301
|
+
className: `${l} flex-1`,
|
|
302
|
+
children: s.map((e) => /* @__PURE__ */ a("option", {
|
|
303
|
+
value: e.value,
|
|
304
|
+
children: e.label
|
|
305
|
+
}, e.value))
|
|
306
|
+
}),
|
|
307
|
+
/* @__PURE__ */ a("input", {
|
|
308
|
+
type: "text",
|
|
309
|
+
value: e.value ?? "",
|
|
310
|
+
onChange: (e) => _(t, n, { value: e.target.value }),
|
|
311
|
+
placeholder: "value",
|
|
312
|
+
className: `${l} w-20`
|
|
313
|
+
}),
|
|
314
|
+
r && /* @__PURE__ */ a("input", {
|
|
315
|
+
type: "text",
|
|
316
|
+
value: e.value2 ?? "",
|
|
317
|
+
onChange: (e) => _(t, n, { value2: e.target.value }),
|
|
318
|
+
placeholder: "and",
|
|
319
|
+
className: `${l} w-20`
|
|
320
|
+
}),
|
|
321
|
+
/* @__PURE__ */ a("button", {
|
|
322
|
+
type: "button",
|
|
323
|
+
onClick: () => y(t, n),
|
|
324
|
+
className: "text-state-error hover:text-state-error/80",
|
|
325
|
+
"aria-label": "Remove rule",
|
|
326
|
+
children: /* @__PURE__ */ a("svg", {
|
|
327
|
+
className: "w-3.5 h-3.5",
|
|
328
|
+
fill: "none",
|
|
329
|
+
stroke: "currentColor",
|
|
330
|
+
viewBox: "0 0 24 24",
|
|
331
|
+
children: /* @__PURE__ */ a("path", {
|
|
332
|
+
strokeLinecap: "round",
|
|
333
|
+
strokeLinejoin: "round",
|
|
334
|
+
strokeWidth: 2,
|
|
335
|
+
d: "M6 18L18 6M6 6l12 12"
|
|
336
|
+
})
|
|
337
|
+
})
|
|
338
|
+
})
|
|
339
|
+
]
|
|
340
|
+
}), /* @__PURE__ */ o("div", {
|
|
341
|
+
className: "flex items-center gap-2",
|
|
342
|
+
children: [/* @__PURE__ */ a("select", {
|
|
343
|
+
value: i,
|
|
344
|
+
onChange: (e) => v(t, n, e.target.value),
|
|
345
|
+
className: `${l} flex-1`,
|
|
346
|
+
children: c.map((e) => /* @__PURE__ */ a("option", {
|
|
347
|
+
value: e.value,
|
|
348
|
+
children: e.label
|
|
349
|
+
}, e.value))
|
|
350
|
+
}), /* @__PURE__ */ o("label", {
|
|
351
|
+
className: "flex items-center gap-1 text-xs text-text-primary",
|
|
352
|
+
children: [/* @__PURE__ */ a("input", {
|
|
353
|
+
type: "checkbox",
|
|
354
|
+
checked: e.style?.bold === !0,
|
|
355
|
+
onChange: (r) => _(t, n, { style: {
|
|
356
|
+
...e.style,
|
|
357
|
+
bold: r.target.checked
|
|
358
|
+
} }),
|
|
359
|
+
className: "w-3.5 h-3.5 text-action-primary-bg bg-bg-surface border-border-default rounded focus:ring-action-primary-bg"
|
|
360
|
+
}), "Bold"]
|
|
361
|
+
})]
|
|
362
|
+
})]
|
|
363
|
+
}, n);
|
|
364
|
+
})
|
|
365
|
+
})
|
|
366
|
+
]
|
|
176
367
|
})
|
|
177
368
|
]
|
|
178
|
-
}, t)),
|
|
369
|
+
}, t)), d.length === 0 && /* @__PURE__ */ a("p", {
|
|
179
370
|
className: "text-sm text-text-secondary text-center py-4",
|
|
180
371
|
children: "No columns configured. Columns will be auto-generated from data."
|
|
181
372
|
})]
|
|
@@ -188,7 +379,7 @@ var s = e(function({ config: e, onChange: s }) {
|
|
|
188
379
|
children: [/* @__PURE__ */ a("input", {
|
|
189
380
|
type: "checkbox",
|
|
190
381
|
checked: e.showSearch !== !1,
|
|
191
|
-
onChange: (e) =>
|
|
382
|
+
onChange: (e) => p("showSearch", e.target.checked),
|
|
192
383
|
className: "\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n "
|
|
193
384
|
}), /* @__PURE__ */ a("span", {
|
|
194
385
|
className: "text-sm text-text-primary",
|
|
@@ -200,7 +391,7 @@ var s = e(function({ config: e, onChange: s }) {
|
|
|
200
391
|
children: [/* @__PURE__ */ a("input", {
|
|
201
392
|
type: "checkbox",
|
|
202
393
|
checked: e.showPagination !== !1,
|
|
203
|
-
onChange: (e) =>
|
|
394
|
+
onChange: (e) => p("showPagination", e.target.checked),
|
|
204
395
|
className: "\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n "
|
|
205
396
|
}), /* @__PURE__ */ a("span", {
|
|
206
397
|
className: "text-sm text-text-primary",
|
|
@@ -212,7 +403,7 @@ var s = e(function({ config: e, onChange: s }) {
|
|
|
212
403
|
children: [/* @__PURE__ */ a("input", {
|
|
213
404
|
type: "checkbox",
|
|
214
405
|
checked: e.showExport !== !1,
|
|
215
|
-
onChange: (e) =>
|
|
406
|
+
onChange: (e) => p("showExport", e.target.checked),
|
|
216
407
|
className: "\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n "
|
|
217
408
|
}), /* @__PURE__ */ a("span", {
|
|
218
409
|
className: "text-sm text-text-primary",
|
|
@@ -224,7 +415,7 @@ var s = e(function({ config: e, onChange: s }) {
|
|
|
224
415
|
children: [/* @__PURE__ */ a("input", {
|
|
225
416
|
type: "checkbox",
|
|
226
417
|
checked: e.stickyHeader === !0,
|
|
227
|
-
onChange: (e) =>
|
|
418
|
+
onChange: (e) => p("stickyHeader", e.target.checked),
|
|
228
419
|
className: "\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n "
|
|
229
420
|
}), /* @__PURE__ */ a("span", {
|
|
230
421
|
className: "text-sm text-text-primary",
|
|
@@ -236,7 +427,7 @@ var s = e(function({ config: e, onChange: s }) {
|
|
|
236
427
|
children: [/* @__PURE__ */ a("input", {
|
|
237
428
|
type: "checkbox",
|
|
238
429
|
checked: e.stripedRows === !0,
|
|
239
|
-
onChange: (e) =>
|
|
430
|
+
onChange: (e) => p("stripedRows", e.target.checked),
|
|
240
431
|
className: "\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n "
|
|
241
432
|
}), /* @__PURE__ */ a("span", {
|
|
242
433
|
className: "text-sm text-text-primary",
|
|
@@ -249,6 +440,6 @@ var s = e(function({ config: e, onChange: s }) {
|
|
|
249
440
|
});
|
|
250
441
|
});
|
|
251
442
|
//#endregion
|
|
252
|
-
export {
|
|
443
|
+
export { u as default };
|
|
253
444
|
|
|
254
445
|
//# sourceMappingURL=TableConfig.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TableConfig.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/table/TableConfig.tsx"],"sourcesContent":["/**\n * TableConfig Component\n *\n * Configuration panel for Table widgets.\n */\n\nimport { type FC, memo, useCallback, useMemo, useEffect, useState } from 'react';\nimport type { TableConfig as ConfigType, TableColumnConfig } from '../../../types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface TableConfigProps {\n /** Current configuration */\n config: ConfigType;\n /** Callback when config changes */\n onChange: (config: ConfigType) => void;\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const TableConfig: FC<TableConfigProps> = memo(function TableConfig({ config, onChange }) {\n // Normalize columns - convert string[] to TableColumnConfig[]\n const initialColumns = useMemo(() => {\n return ((config.columns || []) as (string | TableColumnConfig)[]).map((col) => {\n if (typeof col === 'string') {\n return {\n field: col,\n header: col.charAt(0).toUpperCase() + col.slice(1).replace(/_/g, ' '),\n };\n }\n return col as TableColumnConfig;\n });\n }, []); // Only run once on mount\n\n // Local state for columns to make them editable\n const [columns, setColumns] = useState<TableColumnConfig[]>(initialColumns);\n\n // Sync with parent when columns change\n useEffect(() => {\n // Only update if columns actually changed (deep compare)\n const currentStr = JSON.stringify(config.columns);\n const newStr = JSON.stringify(columns);\n if (currentStr !== newStr && columns.length > 0) {\n onChange({ ...config, columns });\n }\n }, [columns]);\n\n // Reset columns when config changes from outside\n useEffect(() => {\n const normalized = ((config.columns || []) as (string | TableColumnConfig)[]).map((col) => {\n if (typeof col === 'string') {\n return {\n field: col,\n header: col.charAt(0).toUpperCase() + col.slice(1).replace(/_/g, ' '),\n };\n }\n return col as TableColumnConfig;\n });\n setColumns(normalized);\n }, [config.columns]);\n\n const handleChange = useCallback(\n <K extends keyof ConfigType>(key: K, value: ConfigType[K]) => {\n onChange({ ...config, [key]: value });\n },\n [config, onChange]\n );\n\n const handleColumnChange = useCallback((index: number, field: keyof TableColumnConfig, value: string) => {\n setColumns((prev) => {\n const newColumns = [...prev];\n newColumns[index] = { ...newColumns[index], [field]: value };\n return newColumns;\n });\n }, []);\n\n const addColumn = useCallback(() => {\n setColumns((prev) => [...prev, { field: '', header: '' }]);\n }, []);\n\n const removeColumn = useCallback((index: number) => {\n setColumns((prev) => prev.filter((_, i) => i !== index));\n }, []);\n\n return (\n <div className=\"space-y-4\">\n {/* Page Size */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">Page Size</label>\n <select\n value={config.pageSize || 10}\n onChange={(e) => handleChange('pageSize', Number(e.target.value))}\n className=\"\n w-full px-3 py-2\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n >\n <option value={10}>10 rows</option>\n <option value={25}>25 rows</option>\n <option value={50}>50 rows</option>\n <option value={100}>100 rows</option>\n </select>\n </div>\n\n {/* Columns Configuration */}\n <div>\n <div className=\"flex items-center justify-between mb-2\">\n <label className=\"text-sm font-medium text-text-primary\">Columns</label>\n <button\n type=\"button\"\n onClick={addColumn}\n className=\"\n text-sm text-action-primary-bg\n hover:text-action-primary-bgHover\n \"\n >\n + Add Column\n </button>\n </div>\n\n <div className=\"space-y-3\">\n {columns.map((col, index) => (\n <div\n key={index}\n className=\"\n p-3\n bg-bg-sunken\n rounded-md\n space-y-2\n \"\n >\n <div className=\"flex items-center justify-between\">\n <span className=\"text-xs text-text-secondary\">Column {index + 1}</span>\n <button\n type=\"button\"\n onClick={() => removeColumn(index)}\n className=\"text-state-error hover:text-state-error/80\"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n <div className=\"grid grid-cols-2 gap-2\">\n <input\n type=\"text\"\n value={col.field || ''}\n onChange={(e) => handleColumnChange(index, 'field', e.target.value)}\n placeholder=\"Field name\"\n className=\"\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n />\n <input\n type=\"text\"\n value={col.header || ''}\n onChange={(e) => handleColumnChange(index, 'header', e.target.value)}\n placeholder=\"Header label\"\n className=\"\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n />\n </div>\n\n <div className=\"grid grid-cols-2 gap-2\">\n <select\n value={col.format || 'text'}\n onChange={(e) => handleColumnChange(index, 'format', e.target.value)}\n className=\"\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n >\n <option value=\"text\">Text</option>\n <option value=\"number\">Number</option>\n <option value=\"currency\">Currency</option>\n <option value=\"percentage\">Percentage</option>\n <option value=\"date\">Date</option>\n <option value=\"badge\">Badge</option>\n </select>\n <select\n value={col.align || 'left'}\n onChange={(e) => handleColumnChange(index, 'align', e.target.value)}\n className=\"\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n >\n <option value=\"left\">Left</option>\n <option value=\"center\">Center</option>\n <option value=\"right\">Right</option>\n </select>\n </div>\n </div>\n ))}\n\n {columns.length === 0 && (\n <p className=\"text-sm text-text-secondary text-center py-4\">\n No columns configured. Columns will be auto-generated from data.\n </p>\n )}\n </div>\n </div>\n\n {/* Toggle Options */}\n <div className=\"space-y-3\">\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.showSearch !== false}\n onChange={(e) => handleChange('showSearch', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">Show search box</span>\n </label>\n\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.showPagination !== false}\n onChange={(e) => handleChange('showPagination', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">Show pagination</span>\n </label>\n\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.showExport !== false}\n onChange={(e) => handleChange('showExport', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">Show export button</span>\n </label>\n\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.stickyHeader === true}\n onChange={(e) => handleChange('stickyHeader', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">Sticky header</span>\n </label>\n\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.stripedRows === true}\n onChange={(e) => handleChange('stripedRows', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">Striped rows</span>\n </label>\n </div>\n </div>\n );\n});\n\nexport default TableConfig;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TableConfig.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/table/TableConfig.tsx"],"sourcesContent":["/**\n * TableConfig Component\n *\n * Configuration panel for Table widgets.\n */\n\nimport { type FC, memo, useCallback, useMemo, useEffect, useState } from 'react';\nimport type { TableConfig as ConfigType, TableColumnConfig } from '../../../types';\nimport type { ConditionalRule, ConditionalOperator, SemanticIntent } from '../utils/conditionalFormat';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface TableConfigProps {\n /** Current configuration */\n config: ConfigType;\n /** Callback when config changes */\n onChange: (config: ConfigType) => void;\n}\n\n// Operators offered in the conditional-formatting editor. Kept to the common,\n// self-explanatory set; the engine supports more (see conditionalFormat.ts).\nconst CF_OPERATORS: { value: ConditionalOperator; label: string }[] = [\n { value: 'gt', label: '> greater than' },\n { value: 'gte', label: '≥ at least' },\n { value: 'lt', label: '< less than' },\n { value: 'lte', label: '≤ at most' },\n { value: 'eq', label: '= equals' },\n { value: 'neq', label: '≠ not equal' },\n { value: 'between', label: 'between' },\n { value: 'outside', label: 'outside' },\n { value: 'contains', label: 'contains' },\n];\n\n// Semantic color intents — theme-safe (never raw hex). Resolved to status tokens.\nconst CF_INTENTS: { value: SemanticIntent; label: string }[] = [\n { value: 'danger', label: 'Red — danger' },\n { value: 'warning', label: 'Amber — warning' },\n { value: 'success', label: 'Green — good' },\n { value: 'info', label: 'Blue — info' },\n { value: 'neutral', label: 'Neutral' },\n];\n\nconst CF_FIELD_CLASS =\n 'px-2 py-1 text-xs text-text-primary bg-bg-surface border border-border-default rounded-md focus:outline-none focus:ring-2 focus:ring-action-primary-bg';\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const TableConfig: FC<TableConfigProps> = memo(function TableConfig({ config, onChange }) {\n // Normalize columns - convert string[] to TableColumnConfig[]\n const initialColumns = useMemo(() => {\n return ((config.columns || []) as (string | TableColumnConfig)[]).map((col) => {\n if (typeof col === 'string') {\n return {\n field: col,\n header: col.charAt(0).toUpperCase() + col.slice(1).replace(/_/g, ' '),\n };\n }\n return col as TableColumnConfig;\n });\n }, []); // Only run once on mount\n\n // Local state for columns to make them editable\n const [columns, setColumns] = useState<TableColumnConfig[]>(initialColumns);\n\n // Sync with parent when columns change\n useEffect(() => {\n // Only update if columns actually changed (deep compare)\n const currentStr = JSON.stringify(config.columns);\n const newStr = JSON.stringify(columns);\n if (currentStr !== newStr && columns.length > 0) {\n onChange({ ...config, columns });\n }\n }, [columns]);\n\n // Reset columns when config changes from outside\n useEffect(() => {\n const normalized = ((config.columns || []) as (string | TableColumnConfig)[]).map((col) => {\n if (typeof col === 'string') {\n return {\n field: col,\n header: col.charAt(0).toUpperCase() + col.slice(1).replace(/_/g, ' '),\n };\n }\n return col as TableColumnConfig;\n });\n setColumns(normalized);\n }, [config.columns]);\n\n const handleChange = useCallback(\n <K extends keyof ConfigType>(key: K, value: ConfigType[K]) => {\n onChange({ ...config, [key]: value });\n },\n [config, onChange]\n );\n\n const handleColumnChange = useCallback((index: number, field: keyof TableColumnConfig, value: string) => {\n setColumns((prev) => {\n const newColumns = [...prev];\n newColumns[index] = { ...newColumns[index], [field]: value };\n return newColumns;\n });\n }, []);\n\n // Conditional-formatting rule edits for a column. The rules array is stored on\n // `column.conditionalRules` and consumed at render time by TableCell.\n const handleColumnRules = useCallback((index: number, rules: ConditionalRule[]) => {\n setColumns((prev) => {\n const newColumns = [...prev];\n newColumns[index] = { ...newColumns[index], conditionalRules: rules };\n return newColumns;\n });\n }, []);\n\n const addRule = useCallback(\n (index: number) => {\n const existing = columns[index]?.conditionalRules ?? [];\n const next: ConditionalRule = {\n operator: 'gt',\n value: 0,\n style: { bgColor: 'danger', textColor: 'danger', bold: true },\n };\n handleColumnRules(index, [...existing, next]);\n },\n [columns, handleColumnRules]\n );\n\n const updateRule = useCallback(\n (colIndex: number, ruleIndex: number, patch: Partial<ConditionalRule>) => {\n const existing = columns[colIndex]?.conditionalRules ?? [];\n const next = existing.map((r, i) => (i === ruleIndex ? { ...r, ...patch } : r));\n handleColumnRules(colIndex, next);\n },\n [columns, handleColumnRules]\n );\n\n const updateRuleStyle = useCallback(\n (colIndex: number, ruleIndex: number, intent: SemanticIntent) => {\n const existing = columns[colIndex]?.conditionalRules ?? [];\n const next = existing.map((r, i) =>\n i === ruleIndex ? { ...r, style: { ...r.style, bgColor: intent, textColor: intent } } : r\n );\n handleColumnRules(colIndex, next);\n },\n [columns, handleColumnRules]\n );\n\n const removeRule = useCallback(\n (colIndex: number, ruleIndex: number) => {\n const existing = columns[colIndex]?.conditionalRules ?? [];\n handleColumnRules(\n colIndex,\n existing.filter((_, i) => i !== ruleIndex)\n );\n },\n [columns, handleColumnRules]\n );\n\n const addColumn = useCallback(() => {\n setColumns((prev) => [...prev, { field: '', header: '' }]);\n }, []);\n\n const removeColumn = useCallback((index: number) => {\n setColumns((prev) => prev.filter((_, i) => i !== index));\n }, []);\n\n return (\n <div className=\"space-y-4\">\n {/* Page Size */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">Page Size</label>\n <select\n value={config.pageSize || 10}\n onChange={(e) => handleChange('pageSize', Number(e.target.value))}\n className=\"\n w-full px-3 py-2\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n >\n <option value={10}>10 rows</option>\n <option value={25}>25 rows</option>\n <option value={50}>50 rows</option>\n <option value={100}>100 rows</option>\n </select>\n </div>\n\n {/* Columns Configuration */}\n <div>\n <div className=\"flex items-center justify-between mb-2\">\n <label className=\"text-sm font-medium text-text-primary\">Columns</label>\n <button\n type=\"button\"\n onClick={addColumn}\n className=\"\n text-sm text-action-primary-bg\n hover:text-action-primary-bgHover\n \"\n >\n + Add Column\n </button>\n </div>\n\n <div className=\"space-y-3\">\n {columns.map((col, index) => (\n <div\n key={index}\n className=\"\n p-3\n bg-bg-sunken\n rounded-md\n space-y-2\n \"\n >\n <div className=\"flex items-center justify-between\">\n <span className=\"text-xs text-text-secondary\">Column {index + 1}</span>\n <button\n type=\"button\"\n onClick={() => removeColumn(index)}\n className=\"text-state-error hover:text-state-error/80\"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n <div className=\"grid grid-cols-2 gap-2\">\n <input\n type=\"text\"\n value={col.field || ''}\n onChange={(e) => handleColumnChange(index, 'field', e.target.value)}\n placeholder=\"Field name\"\n className=\"\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n />\n <input\n type=\"text\"\n value={col.header || ''}\n onChange={(e) => handleColumnChange(index, 'header', e.target.value)}\n placeholder=\"Header label\"\n className=\"\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n />\n </div>\n\n <div className=\"grid grid-cols-2 gap-2\">\n <select\n value={col.format || 'text'}\n onChange={(e) => handleColumnChange(index, 'format', e.target.value)}\n className=\"\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n >\n <option value=\"text\">Text</option>\n <option value=\"number\">Number</option>\n <option value=\"currency\">Currency</option>\n <option value=\"percentage\">Percentage</option>\n <option value=\"date\">Date</option>\n <option value=\"badge\">Badge</option>\n </select>\n <select\n value={col.align || 'left'}\n onChange={(e) => handleColumnChange(index, 'align', e.target.value)}\n className=\"\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n >\n <option value=\"left\">Left</option>\n <option value=\"center\">Center</option>\n <option value=\"right\">Right</option>\n </select>\n </div>\n\n {/* Conditional formatting rules */}\n <div className=\"pt-2 border-t border-border-default/60\">\n <div className=\"flex items-center justify-between mb-1\">\n <span className=\"text-xs font-medium text-text-secondary\">Conditional formatting</span>\n <button\n type=\"button\"\n onClick={() => addRule(index)}\n className=\"text-xs text-action-primary-bg hover:text-action-primary-bgHover\"\n >\n + Add rule\n </button>\n </div>\n\n {(col.conditionalRules?.length ?? 0) === 0 && (\n <p className=\"text-xs text-text-secondary\">No rules — cell shows its plain value.</p>\n )}\n\n <div className=\"space-y-2\">\n {(col.conditionalRules ?? []).map((rule, ruleIndex) => {\n const needsSecond = rule.operator === 'between' || rule.operator === 'outside';\n const currentIntent: SemanticIntent = rule.style?.bgColor ?? rule.style?.textColor ?? 'danger';\n return (\n <div\n key={ruleIndex}\n className=\"p-2 bg-bg-surface rounded-md border border-border-default space-y-2\"\n >\n <div className=\"flex items-center gap-2\">\n <select\n value={rule.operator}\n onChange={(e) =>\n updateRule(index, ruleIndex, { operator: e.target.value as ConditionalOperator })\n }\n className={`${CF_FIELD_CLASS} flex-1`}\n >\n {CF_OPERATORS.map((op) => (\n <option key={op.value} value={op.value}>\n {op.label}\n </option>\n ))}\n </select>\n <input\n type=\"text\"\n value={rule.value ?? ''}\n onChange={(e) => updateRule(index, ruleIndex, { value: e.target.value })}\n placeholder=\"value\"\n className={`${CF_FIELD_CLASS} w-20`}\n />\n {needsSecond && (\n <input\n type=\"text\"\n value={rule.value2 ?? ''}\n onChange={(e) => updateRule(index, ruleIndex, { value2: e.target.value })}\n placeholder=\"and\"\n className={`${CF_FIELD_CLASS} w-20`}\n />\n )}\n <button\n type=\"button\"\n onClick={() => removeRule(index, ruleIndex)}\n className=\"text-state-error hover:text-state-error/80\"\n aria-label=\"Remove rule\"\n >\n <svg className=\"w-3.5 h-3.5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n </div>\n <div className=\"flex items-center gap-2\">\n <select\n value={currentIntent}\n onChange={(e) => updateRuleStyle(index, ruleIndex, e.target.value as SemanticIntent)}\n className={`${CF_FIELD_CLASS} flex-1`}\n >\n {CF_INTENTS.map((it) => (\n <option key={it.value} value={it.value}>\n {it.label}\n </option>\n ))}\n </select>\n <label className=\"flex items-center gap-1 text-xs text-text-primary\">\n <input\n type=\"checkbox\"\n checked={rule.style?.bold === true}\n onChange={(e) =>\n updateRule(index, ruleIndex, { style: { ...rule.style, bold: e.target.checked } })\n }\n className=\"w-3.5 h-3.5 text-action-primary-bg bg-bg-surface border-border-default rounded focus:ring-action-primary-bg\"\n />\n Bold\n </label>\n </div>\n </div>\n );\n })}\n </div>\n </div>\n </div>\n ))}\n\n {columns.length === 0 && (\n <p className=\"text-sm text-text-secondary text-center py-4\">\n No columns configured. Columns will be auto-generated from data.\n </p>\n )}\n </div>\n </div>\n\n {/* Toggle Options */}\n <div className=\"space-y-3\">\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.showSearch !== false}\n onChange={(e) => handleChange('showSearch', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">Show search box</span>\n </label>\n\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.showPagination !== false}\n onChange={(e) => handleChange('showPagination', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">Show pagination</span>\n </label>\n\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.showExport !== false}\n onChange={(e) => handleChange('showExport', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">Show export button</span>\n </label>\n\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.stickyHeader === true}\n onChange={(e) => handleChange('stickyHeader', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">Sticky header</span>\n </label>\n\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.stripedRows === true}\n onChange={(e) => handleChange('stripedRows', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">Striped rows</span>\n </label>\n </div>\n </div>\n );\n});\n\nexport default TableConfig;\n"],"mappings":"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"}
|