@burdenoff/microfe-bigconsole 2026.1012.7 → 2026.1012.8
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/assistantRunPersistence.d.ts +1 -5
- package/dist/bigconsole/assistant/assistantRunPersistence.js +2 -1
- package/dist/bigconsole/assistant/assistantRunStore.d.ts +9 -6
- package/dist/bigconsole/assistant/assistantRunStore.js +17 -1
- package/dist/bigconsole/assistant/usePreviewWidgetDashboard.d.ts +9 -0
- package/dist/bigconsole/assistant/usePreviewWidgetDashboard.js +75 -0
- package/dist/bigconsole/components/preview/AiPreviewPanel.js +111 -94
- package/dist/bigconsole/customWidget/CustomWidgetProposalPanel.js +198 -196
- package/dist/bigconsole/customWidget/proposalSource.d.ts +3 -1
- package/dist/bigconsole/customWidget/proposalSource.js +42 -28
- package/package.json +1 -1
|
@@ -8,11 +8,7 @@ export interface PersistedRun {
|
|
|
8
8
|
conversationId?: string;
|
|
9
9
|
previewOpen: boolean;
|
|
10
10
|
steps: Record<PreviewStepKey, PreviewStepStatus>;
|
|
11
|
-
entityIds:
|
|
12
|
-
datasink?: string;
|
|
13
|
-
dashboard?: string;
|
|
14
|
-
parser?: string;
|
|
15
|
-
};
|
|
11
|
+
entityIds: Partial<Record<PreviewStepKey, string>>;
|
|
16
12
|
updatedAt: number | null;
|
|
17
13
|
}
|
|
18
14
|
export declare function runStorageKey(workspaceId: string): string;
|
|
@@ -18,12 +18,8 @@ interface AssistantRunState {
|
|
|
18
18
|
richMounted: boolean;
|
|
19
19
|
prompt: string;
|
|
20
20
|
steps: Record<PreviewStepKey, PreviewStepStatus>;
|
|
21
|
-
/**
|
|
22
|
-
entityIds:
|
|
23
|
-
datasink?: string;
|
|
24
|
-
dashboard?: string;
|
|
25
|
-
parser?: string;
|
|
26
|
-
};
|
|
21
|
+
/** Confirmed resource ids, including widgets whose parent may need resolving. */
|
|
22
|
+
entityIds: Partial<Record<PreviewStepKey, string>>;
|
|
27
23
|
/** Newest "⏳ …" line — what the agent says it is doing this second. */
|
|
28
24
|
caption: string;
|
|
29
25
|
/** Set when the turn fails, so the panel can stop pretending to be live. */
|
|
@@ -43,6 +39,13 @@ interface AssistantRunState {
|
|
|
43
39
|
entityResultOrder: Partial<Record<PreviewStepKey, number>>;
|
|
44
40
|
startRun: (prompt: string, conversationId?: string) => void;
|
|
45
41
|
applyResult: (id: string, output: unknown, messageOrder?: number) => void;
|
|
42
|
+
resolveWidgetDashboard: (scope: {
|
|
43
|
+
widgetId: string;
|
|
44
|
+
dashboardId: string;
|
|
45
|
+
workspaceId: string;
|
|
46
|
+
actorId: string;
|
|
47
|
+
conversationId: string | null;
|
|
48
|
+
}) => void;
|
|
46
49
|
applyProgress: (content: string) => void;
|
|
47
50
|
finishRun: (error: string | null) => void;
|
|
48
51
|
openPreview: () => void;
|
|
@@ -112,7 +112,7 @@ var _ = i()((r, i) => ({
|
|
|
112
112
|
if (a.length === 0) return r;
|
|
113
113
|
let o = { ...r.steps }, s = { ...r.entityIds }, c = { ...r.entityResultOrder }, l = !1, u = (e, t) => {
|
|
114
114
|
let n = c[e];
|
|
115
|
-
i !== void 0 && n !== void 0 && i < n || (i !== void 0 && (c[e] = i), o[e] = "done",
|
|
115
|
+
i !== void 0 && n !== void 0 && i < n || (i !== void 0 && (c[e] = i), o[e] = "done", s[e] = t, l = !0);
|
|
116
116
|
};
|
|
117
117
|
for (let e of a) u(e.step, e.id), e.dashboardId && u("dashboard", e.dashboardId), e.parserId && u("parser", e.parserId);
|
|
118
118
|
let d = [...r.completedResultIds, t];
|
|
@@ -125,6 +125,22 @@ var _ = i()((r, i) => ({
|
|
|
125
125
|
updatedAt: Date.now()
|
|
126
126
|
} : { completedResultIds: d };
|
|
127
127
|
}),
|
|
128
|
+
resolveWidgetDashboard: (e) => r((t) => {
|
|
129
|
+
if (t.workspaceId !== e.workspaceId || t.actorId !== e.actorId || t.conversationId !== e.conversationId || t.entityIds.widget !== e.widgetId || !/^[A-Za-z0-9_-]{1,128}$/.test(e.dashboardId) || t.entityIds.dashboard) return t;
|
|
130
|
+
let n = t.entityResultOrder.dashboard, r = t.entityResultOrder.widget;
|
|
131
|
+
return n !== void 0 && r !== void 0 && n > r ? t : {
|
|
132
|
+
entityIds: {
|
|
133
|
+
...t.entityIds,
|
|
134
|
+
dashboard: e.dashboardId
|
|
135
|
+
},
|
|
136
|
+
steps: {
|
|
137
|
+
...t.steps,
|
|
138
|
+
dashboard: t.steps.dashboard === "done" ? "done" : "skipped"
|
|
139
|
+
},
|
|
140
|
+
contentRevision: t.contentRevision + 1,
|
|
141
|
+
updatedAt: Date.now()
|
|
142
|
+
};
|
|
143
|
+
}),
|
|
128
144
|
finishRun: (e) => r((t) => {
|
|
129
145
|
let n = { ...t.steps };
|
|
130
146
|
for (let e of o) n[e] === "running" && (n[e] = "pending");
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Resolve relationships omitted from a successful mutation's response selection.
|
|
2
|
+
* Never infer a dashboard from narration or a page id. The gateway authorizes
|
|
3
|
+
* the read in the active workspace; the store rejects late owner/run results.
|
|
4
|
+
*/
|
|
5
|
+
export declare function usePreviewWidgetDashboard(): {
|
|
6
|
+
loading: boolean;
|
|
7
|
+
error: boolean;
|
|
8
|
+
retry: () => void;
|
|
9
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { GetWidgetDocument as e } from "../../generated/wspace-operations.js";
|
|
2
|
+
import { useBigConsole as t } from "../context/BigConsoleContext.js";
|
|
3
|
+
import "../context/index.js";
|
|
4
|
+
import { useAssistantRunStore as n } from "./assistantRunStore.js";
|
|
5
|
+
import { useEffect as r, useState as i } from "react";
|
|
6
|
+
import { useApolloClient as a } from "@apollo/client/react";
|
|
7
|
+
//#region src/bigconsole/assistant/usePreviewWidgetDashboard.ts
|
|
8
|
+
function o() {
|
|
9
|
+
let o = a(), { workspaceId: s, currentUser: c } = t(), l = n((e) => e.entityIds.widget), u = n((e) => e.entityIds.dashboard), d = n((e) => e.actorId), f = n((e) => e.workspaceId), p = n((e) => e.conversationId), m = n((e) => e.resolveWidgetDashboard), h = `${s ?? ""}|${d ?? ""}|${p ?? ""}|${l ?? ""}`, [g, _] = i({
|
|
10
|
+
owner: "",
|
|
11
|
+
loading: !1,
|
|
12
|
+
error: !1
|
|
13
|
+
}), [v, y] = i(0), b = !!(l && !u && s && d && f === s && c?.id === d);
|
|
14
|
+
return r(() => {
|
|
15
|
+
if (!b || !l || !s || !d) return;
|
|
16
|
+
let t = !1;
|
|
17
|
+
return (async () => {
|
|
18
|
+
_({
|
|
19
|
+
owner: h,
|
|
20
|
+
loading: !0,
|
|
21
|
+
error: !1
|
|
22
|
+
});
|
|
23
|
+
try {
|
|
24
|
+
let n = await o.query({
|
|
25
|
+
query: e,
|
|
26
|
+
variables: { id: l },
|
|
27
|
+
fetchPolicy: "no-cache",
|
|
28
|
+
context: {
|
|
29
|
+
requiredWorkspaceAuth: !0,
|
|
30
|
+
requiredWorkspaceId: s,
|
|
31
|
+
queryDeduplication: !1
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
if (t) return;
|
|
35
|
+
let r = n.data?.getWidget;
|
|
36
|
+
if (r?.id !== l || !r.dashboardId) throw Error("Widget dashboard is unavailable");
|
|
37
|
+
m({
|
|
38
|
+
widgetId: l,
|
|
39
|
+
dashboardId: r.dashboardId,
|
|
40
|
+
workspaceId: s,
|
|
41
|
+
actorId: d,
|
|
42
|
+
conversationId: p
|
|
43
|
+
}), _({
|
|
44
|
+
owner: h,
|
|
45
|
+
loading: !1,
|
|
46
|
+
error: !1
|
|
47
|
+
});
|
|
48
|
+
} catch {
|
|
49
|
+
t || _({
|
|
50
|
+
owner: h,
|
|
51
|
+
loading: !1,
|
|
52
|
+
error: !0
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
})(), () => {
|
|
56
|
+
t = !0;
|
|
57
|
+
};
|
|
58
|
+
}, [
|
|
59
|
+
o,
|
|
60
|
+
b,
|
|
61
|
+
l,
|
|
62
|
+
s,
|
|
63
|
+
d,
|
|
64
|
+
p,
|
|
65
|
+
h,
|
|
66
|
+
m,
|
|
67
|
+
v
|
|
68
|
+
]), {
|
|
69
|
+
loading: b && (g.owner !== h || g.loading),
|
|
70
|
+
error: b && g.owner === h && g.error,
|
|
71
|
+
retry: () => y((e) => e + 1)
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
//#endregion
|
|
75
|
+
export { o as usePreviewWidgetDashboard };
|
|
@@ -3,166 +3,183 @@ import "../../context/index.js";
|
|
|
3
3
|
import { PREVIEW_STEPS as t, useAssistantRunStore as n } from "../../assistant/assistantRunStore.js";
|
|
4
4
|
import { useBigConsolePreviewControl as r } from "../../assistant/usePreviewControl.js";
|
|
5
5
|
import { useAssistantRunWorkspace as i } from "../../assistant/useAssistantRunWorkspace.js";
|
|
6
|
-
import {
|
|
6
|
+
import { usePreviewWidgetDashboard as a } from "../../assistant/usePreviewWidgetDashboard.js";
|
|
7
|
+
import { Section as o } from "../common/Section.js";
|
|
7
8
|
import "../common/index.js";
|
|
8
|
-
import { DOCK_CLEARANCE as
|
|
9
|
-
import { DashboardContent as
|
|
10
|
-
import { useEffect as
|
|
11
|
-
import { ArrowUpRight as
|
|
12
|
-
import { Button as
|
|
13
|
-
import { useI18n as
|
|
14
|
-
import { jsx as
|
|
15
|
-
import { AssistantEntityPreview as
|
|
9
|
+
import { DOCK_CLEARANCE as s, PreviewMeta as c, STEP_LABEL as l, formatAgo as u, previewLabels as d } from "./previewShared.js";
|
|
10
|
+
import { DashboardContent as f, DataSinkContent as p, ParserContent as m, WidgetsContent as h } from "./AiPreviewContent.js";
|
|
11
|
+
import { useEffect as g, useRef as _, useState as v } from "react";
|
|
12
|
+
import { ArrowUpRight as y, Loader2 as b, Sparkles as x, X as S } from "lucide-react";
|
|
13
|
+
import { Button as C } from "@burdenoff/fe-libs/ui";
|
|
14
|
+
import { useI18n as w } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
15
|
+
import { jsx as T, jsxs as E } from "react/jsx-runtime";
|
|
16
|
+
import { AssistantEntityPreview as D } from "@burdenoff/fe-libs/shared/assistant";
|
|
16
17
|
//#region src/bigconsole/components/preview/AiPreviewPanel.tsx
|
|
17
|
-
function
|
|
18
|
-
return /* @__PURE__ */
|
|
18
|
+
function O({ children: e }) {
|
|
19
|
+
return /* @__PURE__ */ T("div", {
|
|
19
20
|
className: "min-w-0 overflow-y-auto p-3",
|
|
20
21
|
style: { maxHeight: "min(440px, 60vh)" },
|
|
21
22
|
children: e
|
|
22
23
|
});
|
|
23
24
|
}
|
|
24
|
-
function
|
|
25
|
-
let { t } =
|
|
26
|
-
return /* @__PURE__ */
|
|
25
|
+
function k({ onOpen: e }) {
|
|
26
|
+
let { t } = w();
|
|
27
|
+
return /* @__PURE__ */ E(C, {
|
|
27
28
|
size: "sm",
|
|
28
29
|
variant: "outline",
|
|
29
30
|
onClick: e,
|
|
30
31
|
"data-testid": "ai-preview-open-entity",
|
|
31
|
-
children: [t("bigconsole.widget.aiPreview.open", "Open"), /* @__PURE__ */
|
|
32
|
+
children: [t("bigconsole.widget.aiPreview.open", "Open"), /* @__PURE__ */ T(y, { className: "ml-1 size-3.5" })]
|
|
32
33
|
});
|
|
33
34
|
}
|
|
34
|
-
function
|
|
35
|
-
let { t:
|
|
36
|
-
i()
|
|
37
|
-
let
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
35
|
+
function A() {
|
|
36
|
+
let { t: y } = w();
|
|
37
|
+
i();
|
|
38
|
+
let A = a();
|
|
39
|
+
r();
|
|
40
|
+
let j = e(), M = n((e) => e.isRunning), N = n((e) => e.previewOpen), P = n((e) => e.hasRun), F = n((e) => e.steps), I = n((e) => e.entityIds), L = n((e) => e.caption), R = n((e) => e.error), z = n((e) => e.updatedAt), B = n((e) => e.openPreview), V = n((e) => e.closePreview), H = n((e) => e.setRichMounted);
|
|
41
|
+
g(() => (H(!0), () => {
|
|
42
|
+
H(!1);
|
|
43
|
+
}), [H]);
|
|
44
|
+
let [U, W] = v(0), G = _(!1);
|
|
45
|
+
if (g(() => {
|
|
46
|
+
M && !G.current && W((e) => e + 1), G.current = M;
|
|
47
|
+
}, [M]), !P) return null;
|
|
48
|
+
if (!N) return /* @__PURE__ */ E("div", {
|
|
46
49
|
className: "flex flex-wrap items-center justify-end gap-control-gap px-4 pt-3 md:px-6",
|
|
47
|
-
style: { marginRight:
|
|
48
|
-
children: [/* @__PURE__ */
|
|
50
|
+
style: { marginRight: s },
|
|
51
|
+
children: [/* @__PURE__ */ T("span", {
|
|
49
52
|
className: "text-xs text-text-muted",
|
|
50
|
-
children:
|
|
51
|
-
}), /* @__PURE__ */
|
|
53
|
+
children: M ? y("bigconsole.widget.aiPreview.buildRunning", "AI build running") : y("bigconsole.widget.aiPreview.buildFinished", "AI build finished")
|
|
54
|
+
}), /* @__PURE__ */ E(C, {
|
|
52
55
|
size: "sm",
|
|
53
56
|
variant: "outline",
|
|
54
|
-
onClick:
|
|
57
|
+
onClick: B,
|
|
55
58
|
"data-testid": "ai-preview-open",
|
|
56
59
|
children: [
|
|
57
|
-
/* @__PURE__ */
|
|
58
|
-
|
|
59
|
-
|
|
60
|
+
/* @__PURE__ */ T(x, { className: "mr-1.5 size-4" }),
|
|
61
|
+
y("bigconsole.widget.aiPreview.previewButton", "Preview"),
|
|
62
|
+
M ? /* @__PURE__ */ T(b, { className: "ml-1.5 size-3.5 animate-spin" }) : null
|
|
60
63
|
]
|
|
61
64
|
})]
|
|
62
65
|
});
|
|
63
|
-
let
|
|
66
|
+
let K = I.dashboard, q = A.error ? /* @__PURE__ */ E("div", {
|
|
67
|
+
role: "alert",
|
|
68
|
+
"data-testid": "ai-preview-widget-parent-error",
|
|
69
|
+
children: [/* @__PURE__ */ T("p", { children: y("bigconsole.widget.aiPreview.widgetParentError", "Could not load this widget’s dashboard. It may be unavailable or you may no longer have access.") }), /* @__PURE__ */ T(C, {
|
|
70
|
+
variant: "outline",
|
|
71
|
+
size: "sm",
|
|
72
|
+
onClick: A.retry,
|
|
73
|
+
children: y("bigconsole.widget.customWidget.action.retry", "Retry")
|
|
74
|
+
})]
|
|
75
|
+
}) : A.loading && !K ? /* @__PURE__ */ E("div", {
|
|
76
|
+
role: "status",
|
|
77
|
+
"data-testid": "ai-preview-widget-parent-loading",
|
|
78
|
+
className: "flex items-center gap-2",
|
|
79
|
+
children: [/* @__PURE__ */ T(b, { className: "size-4 animate-spin" }), y("bigconsole.widget.aiPreview.widgetParentLoading", "Loading this widget’s dashboard…")]
|
|
80
|
+
}) : null, J = t.map((e) => ({
|
|
64
81
|
id: e,
|
|
65
|
-
label:
|
|
66
|
-
status:
|
|
67
|
-
})),
|
|
82
|
+
label: y(l[e].key, l[e].fallback),
|
|
83
|
+
status: F[e]
|
|
84
|
+
})), Y = [
|
|
68
85
|
{
|
|
69
86
|
id: "datasink",
|
|
70
|
-
label:
|
|
71
|
-
render: () => /* @__PURE__ */
|
|
87
|
+
label: y("bigconsole.widget.aiPreview.tab.dataSink", "Data Sink"),
|
|
88
|
+
render: () => /* @__PURE__ */ T(O, { children: /* @__PURE__ */ T(o, {
|
|
72
89
|
emphasis: "standard",
|
|
73
90
|
padding: "compact",
|
|
74
91
|
headingLevel: 3,
|
|
75
|
-
title:
|
|
76
|
-
description:
|
|
77
|
-
actions:
|
|
78
|
-
children: /* @__PURE__ */
|
|
79
|
-
id:
|
|
80
|
-
live:
|
|
92
|
+
title: y("bigconsole.widget.aiPreview.dataSinkRows", "Data sink rows"),
|
|
93
|
+
description: y("bigconsole.widget.aiPreview.dataSinkRowsHint", "The rows the assistant just landed, straight from the sink."),
|
|
94
|
+
actions: I.datasink ? /* @__PURE__ */ T(k, { onOpen: () => j(`/datasinks/${I.datasink}`) }) : void 0,
|
|
95
|
+
children: /* @__PURE__ */ T(p, {
|
|
96
|
+
id: I.datasink,
|
|
97
|
+
live: M
|
|
81
98
|
})
|
|
82
99
|
}) })
|
|
83
100
|
},
|
|
84
101
|
{
|
|
85
102
|
id: "dashboard",
|
|
86
|
-
label:
|
|
87
|
-
render: () => /* @__PURE__ */
|
|
103
|
+
label: y("bigconsole.widget.aiPreview.tab.dashboard", "Dashboard"),
|
|
104
|
+
render: () => /* @__PURE__ */ T(O, { children: /* @__PURE__ */ T(o, {
|
|
88
105
|
emphasis: "standard",
|
|
89
106
|
padding: "compact",
|
|
90
107
|
headingLevel: 3,
|
|
91
|
-
title:
|
|
92
|
-
description:
|
|
93
|
-
actions:
|
|
94
|
-
children: /* @__PURE__ */
|
|
95
|
-
dashboardId:
|
|
96
|
-
live:
|
|
108
|
+
title: y("bigconsole.widget.aiPreview.tab.dashboard", "Dashboard"),
|
|
109
|
+
description: y("bigconsole.widget.aiPreview.dashboardHint", "The live board, rendered exactly as the real page renders it."),
|
|
110
|
+
actions: K ? /* @__PURE__ */ T(k, { onOpen: () => j(`/dashboards/${K}`) }) : void 0,
|
|
111
|
+
children: q ?? /* @__PURE__ */ T(f, {
|
|
112
|
+
dashboardId: K,
|
|
113
|
+
live: M
|
|
97
114
|
})
|
|
98
115
|
}) })
|
|
99
116
|
},
|
|
100
117
|
{
|
|
101
118
|
id: "parser",
|
|
102
|
-
label:
|
|
103
|
-
render: () => /* @__PURE__ */
|
|
119
|
+
label: y("bigconsole.widget.aiPreview.tab.parser", "Parser"),
|
|
120
|
+
render: () => /* @__PURE__ */ T(O, { children: /* @__PURE__ */ T(o, {
|
|
104
121
|
emphasis: "standard",
|
|
105
122
|
padding: "compact",
|
|
106
123
|
headingLevel: 3,
|
|
107
|
-
title:
|
|
108
|
-
description:
|
|
109
|
-
actions:
|
|
110
|
-
children: /* @__PURE__ */
|
|
111
|
-
parserId:
|
|
112
|
-
live:
|
|
124
|
+
title: y("bigconsole.widget.aiPreview.parserOutput", "Parser output"),
|
|
125
|
+
description: y("bigconsole.widget.aiPreview.parserOutputHint", "The rows after the parser's transform, so you can check the shape."),
|
|
126
|
+
actions: I.parser ? /* @__PURE__ */ T(k, { onOpen: () => j(`/parsers/${I.parser}`) }) : void 0,
|
|
127
|
+
children: /* @__PURE__ */ T(m, {
|
|
128
|
+
parserId: I.parser,
|
|
129
|
+
live: M
|
|
113
130
|
})
|
|
114
131
|
}) })
|
|
115
132
|
},
|
|
116
133
|
{
|
|
117
134
|
id: "widget",
|
|
118
|
-
label:
|
|
119
|
-
render: () => /* @__PURE__ */
|
|
135
|
+
label: y("bigconsole.widget.aiPreview.tab.widget", "Widget"),
|
|
136
|
+
render: () => /* @__PURE__ */ T(O, { children: /* @__PURE__ */ T(o, {
|
|
120
137
|
emphasis: "standard",
|
|
121
138
|
padding: "compact",
|
|
122
139
|
headingLevel: 3,
|
|
123
|
-
title:
|
|
124
|
-
description:
|
|
125
|
-
actions:
|
|
126
|
-
children: /* @__PURE__ */
|
|
127
|
-
dashboardId:
|
|
128
|
-
live:
|
|
140
|
+
title: y("bigconsole.widget.aiPreview.widgets", "Widgets"),
|
|
141
|
+
description: y("bigconsole.widget.aiPreview.widgetsHint", "Every widget on the new dashboard, rendered live."),
|
|
142
|
+
actions: K ? /* @__PURE__ */ T(k, { onOpen: () => j(`/dashboards/${K}`) }) : void 0,
|
|
143
|
+
children: q ?? /* @__PURE__ */ T(h, {
|
|
144
|
+
dashboardId: K,
|
|
145
|
+
live: M
|
|
129
146
|
})
|
|
130
147
|
}) })
|
|
131
148
|
}
|
|
132
149
|
];
|
|
133
|
-
return /* @__PURE__ */
|
|
150
|
+
return /* @__PURE__ */ E("div", {
|
|
134
151
|
"data-testid": "ai-preview-panel",
|
|
135
|
-
style: { paddingRight:
|
|
152
|
+
style: { paddingRight: s },
|
|
136
153
|
className: "mx-4 mt-3 min-w-0 md:mx-6",
|
|
137
|
-
children: [/* @__PURE__ */
|
|
154
|
+
children: [/* @__PURE__ */ T("h2", {
|
|
138
155
|
className: "sr-only",
|
|
139
|
-
children:
|
|
140
|
-
}), /* @__PURE__ */
|
|
141
|
-
title:
|
|
142
|
-
runKey: String(
|
|
143
|
-
steps:
|
|
144
|
-
tabs:
|
|
156
|
+
children: y("bigconsole.widget.aiPreview.title", "AI Preview")
|
|
157
|
+
}), /* @__PURE__ */ T(D, {
|
|
158
|
+
title: y("bigconsole.widget.aiPreview.title", "AI Preview"),
|
|
159
|
+
runKey: String(U),
|
|
160
|
+
steps: J,
|
|
161
|
+
tabs: Y,
|
|
145
162
|
follow: "produced",
|
|
146
|
-
caption:
|
|
147
|
-
error:
|
|
148
|
-
meta: /* @__PURE__ */
|
|
149
|
-
state:
|
|
150
|
-
stateLabel:
|
|
151
|
-
updatedLabel:
|
|
152
|
-
updatedAt:
|
|
153
|
-
ago: (e) =>
|
|
163
|
+
caption: M ? L || y("bigconsole.widget.aiPreview.working", "Working…") : y("bigconsole.widget.aiPreview.done", "Done"),
|
|
164
|
+
error: R,
|
|
165
|
+
meta: /* @__PURE__ */ T(c, {
|
|
166
|
+
state: M ? "running" : R ? "stopped" : "idle",
|
|
167
|
+
stateLabel: M ? y("bigconsole.widget.aiPreview.live", "Live") : R ? y("bigconsole.widget.aiPreview.stopped", "Stopped") : null,
|
|
168
|
+
updatedLabel: y("bigconsole.widget.aiPreview.updated", "updated"),
|
|
169
|
+
updatedAt: z,
|
|
170
|
+
ago: (e) => u(e, y)
|
|
154
171
|
}),
|
|
155
|
-
headerActions: /* @__PURE__ */
|
|
172
|
+
headerActions: /* @__PURE__ */ T(C, {
|
|
156
173
|
size: "sm",
|
|
157
174
|
variant: "ghost",
|
|
158
|
-
onClick:
|
|
159
|
-
"aria-label":
|
|
175
|
+
onClick: V,
|
|
176
|
+
"aria-label": y("bigconsole.widget.aiPreview.closeAriaLabel", "Close preview"),
|
|
160
177
|
"data-testid": "ai-preview-close",
|
|
161
|
-
children: /* @__PURE__ */
|
|
178
|
+
children: /* @__PURE__ */ T(S, { className: "size-4" })
|
|
162
179
|
}),
|
|
163
|
-
labels:
|
|
180
|
+
labels: d(y)
|
|
164
181
|
})]
|
|
165
182
|
});
|
|
166
183
|
}
|
|
167
184
|
//#endregion
|
|
168
|
-
export {
|
|
185
|
+
export { A as AiPreviewPanel };
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
import { Section as e, SectionStack as t } from "../components/common/Section.js";
|
|
2
2
|
import "../components/common/index.js";
|
|
3
3
|
import n from "../components/widgets/WidgetErrorBoundary.js";
|
|
4
|
-
import
|
|
5
|
-
import { PROPOSABLE_WIDGET_TYPES as
|
|
6
|
-
import { localProposalSource as
|
|
7
|
-
import { memo as
|
|
8
|
-
import { AlertTriangle as
|
|
9
|
-
import { Button as
|
|
10
|
-
import { useI18n as
|
|
11
|
-
import { Fragment as
|
|
4
|
+
import r from "../renderers/adapters/BigConsoleRenderer.js";
|
|
5
|
+
import { PROPOSABLE_WIDGET_TYPES as ee, derivePreviewState as i, isProposableWidgetType as a, validateProposal as o } from "./proposalContract.js";
|
|
6
|
+
import { changeProposalWidgetType as s, localProposalSource as c } from "./proposalSource.js";
|
|
7
|
+
import { memo as l, useCallback as u, useEffect as d, useMemo as f, useState as p } from "react";
|
|
8
|
+
import { AlertTriangle as m, Check as h, Loader2 as g, RefreshCw as te, Sparkles as ne, X as _ } from "lucide-react";
|
|
9
|
+
import { Button as v, Input as y, Label as b, Textarea as re } from "@burdenoff/fe-libs/ui";
|
|
10
|
+
import { useI18n as ie } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
11
|
+
import { Fragment as ae, jsx as x, jsxs as S } from "react/jsx-runtime";
|
|
12
12
|
//#region src/bigconsole/customWidget/CustomWidgetProposalPanel.tsx
|
|
13
|
-
var
|
|
13
|
+
var oe = "w-full", se = {
|
|
14
14
|
loading: "neutral",
|
|
15
15
|
valid: "neutral",
|
|
16
16
|
"no-data": "warning",
|
|
17
17
|
"field-mismatch": "warning",
|
|
18
18
|
"access-error": "danger"
|
|
19
19
|
};
|
|
20
|
-
function
|
|
20
|
+
function ce(e, t) {
|
|
21
21
|
let n = (/* @__PURE__ */ new Date(0)).toISOString();
|
|
22
22
|
return {
|
|
23
23
|
id: `preview-${e.id}`,
|
|
@@ -45,14 +45,14 @@ function b(e, t) {
|
|
|
45
45
|
updatedAt: n
|
|
46
46
|
};
|
|
47
47
|
}
|
|
48
|
-
function
|
|
48
|
+
function le(e) {
|
|
49
49
|
if (Array.isArray(e)) {
|
|
50
50
|
let t = e.find((e) => e && typeof e == "object");
|
|
51
51
|
return t ? Object.keys(t) : [];
|
|
52
52
|
}
|
|
53
53
|
if (e && typeof e == "object") return Object.keys(e);
|
|
54
54
|
}
|
|
55
|
-
function
|
|
55
|
+
function C(e) {
|
|
56
56
|
if (Array.isArray(e)) return e.length;
|
|
57
57
|
if (e && typeof e == "object") {
|
|
58
58
|
let t = e.cells;
|
|
@@ -60,247 +60,247 @@ function S(e) {
|
|
|
60
60
|
}
|
|
61
61
|
return 0;
|
|
62
62
|
}
|
|
63
|
-
var
|
|
64
|
-
let { t:
|
|
63
|
+
var w = l(function({ sinks: l, parsers: w, resolvePreviewData: T, onApprove: E, onClose: D, source: O = c }) {
|
|
64
|
+
let { t: k } = ie(), A = f(() => ({
|
|
65
65
|
loading: {
|
|
66
|
-
title:
|
|
67
|
-
body:
|
|
66
|
+
title: k("bigconsole.widget.customWidget.preview.loading.title", "Building preview…"),
|
|
67
|
+
body: k("bigconsole.widget.customWidget.preview.loading.body", "Reading the selected data binding.")
|
|
68
68
|
},
|
|
69
69
|
valid: {
|
|
70
|
-
title:
|
|
70
|
+
title: k("bigconsole.widget.customWidget.preview.valid.title", "Preview"),
|
|
71
71
|
body: ""
|
|
72
72
|
},
|
|
73
73
|
"no-data": {
|
|
74
|
-
title:
|
|
75
|
-
body:
|
|
74
|
+
title: k("bigconsole.widget.customWidget.preview.noData.title", "No data returned"),
|
|
75
|
+
body: k("bigconsole.widget.customWidget.preview.noData.body", "The binding is valid but the data source returned no rows. The widget will render empty until the sink has data.")
|
|
76
76
|
},
|
|
77
77
|
"field-mismatch": {
|
|
78
|
-
title:
|
|
79
|
-
body:
|
|
78
|
+
title: k("bigconsole.widget.customWidget.preview.fieldMismatch.title", "Field mismatch"),
|
|
79
|
+
body: k("bigconsole.widget.customWidget.preview.fieldMismatch.body", "Some mapped fields are not present in the parser output. Fix the mapping below before approving.")
|
|
80
80
|
},
|
|
81
81
|
"access-error": {
|
|
82
|
-
title:
|
|
83
|
-
body:
|
|
82
|
+
title: k("bigconsole.widget.customWidget.preview.accessError.title", "Cannot read this data"),
|
|
83
|
+
body: k("bigconsole.widget.customWidget.preview.accessError.body", "You do not have access to the proposed DataSink or parser in this workspace.")
|
|
84
84
|
}
|
|
85
|
-
}), [
|
|
86
|
-
permittedDataSinkIds:
|
|
87
|
-
permittedParserIds:
|
|
88
|
-
availableFields:
|
|
85
|
+
}), [k]), [j, ue] = p(""), [M, N] = p(null), [P, F] = p(!1), [I, L] = p(!1), [R, z] = p(null), [B, V] = p(void 0), [H, U] = p(!1), [W, G] = p(!1), K = f(() => l.map((e) => e.id), [l]), q = f(() => w.map((e) => e.id), [w]), J = f(() => le(B), [B]), Y = f(() => M ? o(M, {
|
|
86
|
+
permittedDataSinkIds: K,
|
|
87
|
+
permittedParserIds: q,
|
|
88
|
+
availableFields: J
|
|
89
89
|
}) : {
|
|
90
90
|
issues: [],
|
|
91
91
|
canApprove: !1
|
|
92
92
|
}, [
|
|
93
|
-
|
|
94
|
-
G,
|
|
93
|
+
M,
|
|
95
94
|
K,
|
|
96
|
-
q
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
95
|
+
q,
|
|
96
|
+
J
|
|
97
|
+
]), X = f(() => i(Y, {
|
|
98
|
+
loading: H,
|
|
99
|
+
accessError: W,
|
|
100
|
+
rowCount: C(B)
|
|
101
101
|
}), [
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
102
|
+
Y,
|
|
103
|
+
H,
|
|
104
|
+
W,
|
|
105
|
+
B
|
|
106
106
|
]);
|
|
107
|
-
|
|
108
|
-
if (!
|
|
109
|
-
|
|
107
|
+
d(() => {
|
|
108
|
+
if (!M || !M.binding.dataSinkId) {
|
|
109
|
+
V(void 0);
|
|
110
110
|
return;
|
|
111
111
|
}
|
|
112
112
|
let e = !1;
|
|
113
|
-
return
|
|
114
|
-
e ||
|
|
113
|
+
return U(!0), G(!1), T(M).then((t) => {
|
|
114
|
+
e || V(t);
|
|
115
115
|
}).catch(() => {
|
|
116
|
-
e || (
|
|
116
|
+
e || (V(void 0), G(!0));
|
|
117
117
|
}).finally(() => {
|
|
118
|
-
e ||
|
|
118
|
+
e || U(!1);
|
|
119
119
|
}), () => {
|
|
120
120
|
e = !0;
|
|
121
121
|
};
|
|
122
|
-
}, [
|
|
123
|
-
let
|
|
124
|
-
if (
|
|
125
|
-
|
|
122
|
+
}, [M ? `${M.binding.dataSinkId}|${M.binding.parserId ?? ""}|${M.binding.dataPath ?? ""}` : "", T]);
|
|
123
|
+
let de = u(async () => {
|
|
124
|
+
if (j.trim()) {
|
|
125
|
+
F(!0), z(null);
|
|
126
126
|
try {
|
|
127
|
-
|
|
128
|
-
prompt:
|
|
129
|
-
sinks:
|
|
130
|
-
parsers:
|
|
127
|
+
N(await O.propose({
|
|
128
|
+
prompt: j.trim(),
|
|
129
|
+
sinks: l,
|
|
130
|
+
parsers: w
|
|
131
131
|
}));
|
|
132
132
|
} finally {
|
|
133
|
-
|
|
133
|
+
F(!1);
|
|
134
134
|
}
|
|
135
135
|
}
|
|
136
136
|
}, [
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
]),
|
|
142
|
-
|
|
143
|
-
}, []),
|
|
144
|
-
|
|
145
|
-
}, []),
|
|
146
|
-
if (!(!
|
|
147
|
-
|
|
137
|
+
j,
|
|
138
|
+
O,
|
|
139
|
+
l,
|
|
140
|
+
w
|
|
141
|
+
]), Z = u((e) => {
|
|
142
|
+
N((t) => t && e(t));
|
|
143
|
+
}, []), fe = u(() => {
|
|
144
|
+
N(null), V(void 0), G(!1), z(null);
|
|
145
|
+
}, []), pe = u(async () => {
|
|
146
|
+
if (!(!M || !Y.canApprove || H || W)) {
|
|
147
|
+
L(!0), z(null);
|
|
148
148
|
try {
|
|
149
|
-
await
|
|
149
|
+
await E(M), D();
|
|
150
150
|
} catch (e) {
|
|
151
|
-
|
|
151
|
+
z(e instanceof Error ? e.message : k("bigconsole.widget.customWidget.error.couldNotSaveWidget", "Could not save the widget."));
|
|
152
152
|
} finally {
|
|
153
|
-
|
|
153
|
+
L(!1);
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
156
|
}, [
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
T,
|
|
157
|
+
M,
|
|
158
|
+
Y.canApprove,
|
|
159
|
+
H,
|
|
160
|
+
W,
|
|
162
161
|
E,
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
162
|
+
D,
|
|
163
|
+
k
|
|
164
|
+
]), Q = Y.issues.filter((e) => e.severity === "error"), $ = Y.issues.filter((e) => e.severity === "warning");
|
|
165
|
+
return /* @__PURE__ */ x("section", {
|
|
166
166
|
"data-testid": "custom-widget-proposal-panel",
|
|
167
|
-
"aria-label":
|
|
167
|
+
"aria-label": k("bigconsole.widget.customWidget.panel.ariaLabel", "AI custom widget builder"),
|
|
168
168
|
className: "flex h-full w-full min-w-0 flex-col overflow-y-auto p-4",
|
|
169
|
-
children: /* @__PURE__ */
|
|
170
|
-
title:
|
|
169
|
+
children: /* @__PURE__ */ S(t, { children: [/* @__PURE__ */ x(e, {
|
|
170
|
+
title: k("bigconsole.widget.customWidget.prompt.label", "Describe the widget you need"),
|
|
171
171
|
description: "Plain English. The assistant proposes a typed widget you can edit before anything is saved.",
|
|
172
|
-
icon: /* @__PURE__ */
|
|
172
|
+
icon: /* @__PURE__ */ x(ne, {
|
|
173
173
|
className: "size-4",
|
|
174
174
|
"aria-hidden": "true"
|
|
175
175
|
}),
|
|
176
|
-
actions: /* @__PURE__ */
|
|
176
|
+
actions: /* @__PURE__ */ S("div", {
|
|
177
177
|
className: "flex flex-wrap gap-2",
|
|
178
|
-
children: [/* @__PURE__ */
|
|
178
|
+
children: [/* @__PURE__ */ S(v, {
|
|
179
179
|
"data-testid": "custom-widget-generate",
|
|
180
|
-
onClick:
|
|
181
|
-
disabled: !
|
|
182
|
-
children: [
|
|
180
|
+
onClick: de,
|
|
181
|
+
disabled: !j.trim() || P,
|
|
182
|
+
children: [P ? /* @__PURE__ */ x(g, {
|
|
183
183
|
className: "mr-2 size-4 animate-spin",
|
|
184
184
|
"aria-hidden": "true"
|
|
185
|
-
}) : null,
|
|
186
|
-
}),
|
|
185
|
+
}) : null, M ? k("bigconsole.widget.customWidget.action.regenerate", "Regenerate") : k("bigconsole.widget.customWidget.action.generateProposal", "Generate proposal")]
|
|
186
|
+
}), M ? /* @__PURE__ */ S(v, {
|
|
187
187
|
variant: "outline",
|
|
188
188
|
"data-testid": "custom-widget-reject",
|
|
189
|
-
onClick:
|
|
190
|
-
children: [/* @__PURE__ */
|
|
189
|
+
onClick: fe,
|
|
190
|
+
children: [/* @__PURE__ */ x(_, {
|
|
191
191
|
className: "mr-1 size-4",
|
|
192
192
|
"aria-hidden": "true"
|
|
193
|
-
}),
|
|
193
|
+
}), k("bigconsole.widget.customWidget.action.reject", "Reject")]
|
|
194
194
|
}) : null]
|
|
195
195
|
}),
|
|
196
|
-
children: /* @__PURE__ */
|
|
196
|
+
children: /* @__PURE__ */ S("div", {
|
|
197
197
|
className: "flex flex-col gap-2",
|
|
198
|
-
children: [/* @__PURE__ */
|
|
198
|
+
children: [/* @__PURE__ */ x(b, {
|
|
199
199
|
htmlFor: "custom-widget-prompt",
|
|
200
200
|
children: "What should it show?"
|
|
201
|
-
}), /* @__PURE__ */
|
|
201
|
+
}), /* @__PURE__ */ x(re, {
|
|
202
202
|
id: "custom-widget-prompt",
|
|
203
203
|
"data-testid": "custom-widget-prompt",
|
|
204
|
-
value:
|
|
205
|
-
onChange: (e) =>
|
|
206
|
-
placeholder:
|
|
204
|
+
value: j,
|
|
205
|
+
onChange: (e) => ue(e.target.value),
|
|
206
|
+
placeholder: k("bigconsole.widget.customWidget.prompt.placeholder", "e.g. a funnel of signup conversion stages"),
|
|
207
207
|
rows: 3
|
|
208
208
|
})]
|
|
209
209
|
})
|
|
210
|
-
}),
|
|
211
|
-
/* @__PURE__ */
|
|
210
|
+
}), M ? /* @__PURE__ */ S(ae, { children: [
|
|
211
|
+
/* @__PURE__ */ S(e, {
|
|
212
212
|
emphasis: "primary",
|
|
213
|
-
tone:
|
|
214
|
-
title:
|
|
215
|
-
description:
|
|
216
|
-
meta: /* @__PURE__ */
|
|
213
|
+
tone: se[X],
|
|
214
|
+
title: A[X].title,
|
|
215
|
+
description: M.binding.parserId ? k("bigconsole.widget.customWidget.preview.parserDescription", "Rendered using the saved parser output.") : k("bigconsole.widget.customWidget.preview.sourceDescription", "Rendered using up to 50 source rows. Full data may differ."),
|
|
216
|
+
meta: /* @__PURE__ */ x("span", {
|
|
217
217
|
"data-testid": "custom-widget-preview-state",
|
|
218
|
-
"data-state":
|
|
218
|
+
"data-state": X,
|
|
219
219
|
className: "rounded-pill bg-bg-sunken px-2 py-0.5 text-xs text-text-secondary",
|
|
220
|
-
children:
|
|
220
|
+
children: X
|
|
221
221
|
}),
|
|
222
|
-
children: [/* @__PURE__ */
|
|
222
|
+
children: [/* @__PURE__ */ x("div", {
|
|
223
223
|
"data-testid": "custom-widget-preview",
|
|
224
224
|
className: "min-h-[220px] min-w-0 rounded-card border border-[var(--color-border-subtle)] bg-bg-surface p-2",
|
|
225
|
-
children:
|
|
225
|
+
children: X === "loading" ? /* @__PURE__ */ S("div", {
|
|
226
226
|
className: "flex h-[200px] items-center justify-center text-text-secondary",
|
|
227
|
-
children: [/* @__PURE__ */ g
|
|
227
|
+
children: [/* @__PURE__ */ x(g, {
|
|
228
228
|
className: "mr-2 size-4 animate-spin",
|
|
229
229
|
"aria-hidden": "true"
|
|
230
|
-
}), /* @__PURE__ */
|
|
230
|
+
}), /* @__PURE__ */ x("span", {
|
|
231
231
|
className: "text-sm",
|
|
232
|
-
children:
|
|
232
|
+
children: A.loading.body
|
|
233
233
|
})]
|
|
234
|
-
}) :
|
|
234
|
+
}) : X === "valid" ? /* @__PURE__ */ x("div", {
|
|
235
235
|
className: "h-[200px]",
|
|
236
|
-
children: /* @__PURE__ */
|
|
237
|
-
widgetId: `preview-${
|
|
238
|
-
children: /* @__PURE__ */
|
|
239
|
-
widget:
|
|
240
|
-
data:
|
|
236
|
+
children: /* @__PURE__ */ x(n, {
|
|
237
|
+
widgetId: `preview-${M.id}`,
|
|
238
|
+
children: /* @__PURE__ */ x(r, {
|
|
239
|
+
widget: ce(M, k("bigconsole.widget.customWidget.untitledWidget", "Untitled widget")),
|
|
240
|
+
data: B
|
|
241
241
|
})
|
|
242
242
|
})
|
|
243
|
-
}) : /* @__PURE__ */
|
|
243
|
+
}) : /* @__PURE__ */ S("div", {
|
|
244
244
|
className: "flex h-[200px] flex-col items-center justify-center gap-2 px-4 text-center",
|
|
245
245
|
children: [
|
|
246
|
-
/* @__PURE__ */
|
|
246
|
+
/* @__PURE__ */ x(m, {
|
|
247
247
|
className: "size-5 text-[var(--color-status-warning-text)]",
|
|
248
248
|
"aria-hidden": "true"
|
|
249
249
|
}),
|
|
250
|
-
/* @__PURE__ */
|
|
250
|
+
/* @__PURE__ */ x("p", {
|
|
251
251
|
className: "text-sm text-text-secondary",
|
|
252
|
-
children:
|
|
252
|
+
children: A[X].body
|
|
253
253
|
}),
|
|
254
|
-
|
|
254
|
+
X === "access-error" ? /* @__PURE__ */ S(v, {
|
|
255
255
|
size: "sm",
|
|
256
256
|
variant: "outline",
|
|
257
|
-
onClick: () =>
|
|
258
|
-
children: [/* @__PURE__ */
|
|
257
|
+
onClick: () => Z((e) => ({ ...e })),
|
|
258
|
+
children: [/* @__PURE__ */ x(te, {
|
|
259
259
|
className: "mr-1 size-3.5",
|
|
260
260
|
"aria-hidden": "true"
|
|
261
|
-
}),
|
|
261
|
+
}), k("bigconsole.widget.customWidget.action.retry", "Retry")]
|
|
262
262
|
}) : null
|
|
263
263
|
]
|
|
264
264
|
})
|
|
265
|
-
}),
|
|
265
|
+
}), M.rationale ? /* @__PURE__ */ x("p", {
|
|
266
266
|
className: "mt-2 text-xs text-text-secondary",
|
|
267
267
|
"data-testid": "custom-widget-rationale",
|
|
268
|
-
children:
|
|
268
|
+
children: M.rationale
|
|
269
269
|
}) : null]
|
|
270
270
|
}),
|
|
271
|
-
Q.length > 0 || $.length > 0 ? /* @__PURE__ */
|
|
271
|
+
Q.length > 0 || $.length > 0 ? /* @__PURE__ */ x(e, {
|
|
272
272
|
tone: Q.length > 0 ? "danger" : "warning",
|
|
273
273
|
padding: "compact",
|
|
274
274
|
headingLevel: 3,
|
|
275
275
|
title: Q.length > 0 ? `${Q.length} ${Q.length === 1 ? "problem" : "problems"} to fix before approving` : `${$.length} ${$.length === 1 ? "warning" : "warnings"}`,
|
|
276
|
-
children: /* @__PURE__ */
|
|
276
|
+
children: /* @__PURE__ */ x("ul", {
|
|
277
277
|
"data-testid": "custom-widget-issues",
|
|
278
278
|
className: "flex min-w-0 flex-col gap-1",
|
|
279
|
-
children: [...Q, ...$].map((e) => /* @__PURE__ */
|
|
279
|
+
children: [...Q, ...$].map((e) => /* @__PURE__ */ x("li", {
|
|
280
280
|
"data-severity": e.severity,
|
|
281
281
|
className: `break-words text-xs ${e.severity === "error" ? "text-[var(--color-status-error-text)]" : "text-[var(--color-status-warning-text)]"}`,
|
|
282
282
|
children: e.message
|
|
283
283
|
}, `${e.code}-${e.path ?? ""}`))
|
|
284
284
|
})
|
|
285
285
|
}) : null,
|
|
286
|
-
/* @__PURE__ */
|
|
287
|
-
title:
|
|
286
|
+
/* @__PURE__ */ x(e, {
|
|
287
|
+
title: k("bigconsole.widget.customWidget.proposal.heading", "Proposal"),
|
|
288
288
|
description: "Every field is editable — the assistant proposes, you dispose.",
|
|
289
289
|
"data-testid": "custom-widget-proposal-fields",
|
|
290
|
-
children: /* @__PURE__ */
|
|
290
|
+
children: /* @__PURE__ */ S("div", {
|
|
291
291
|
className: "flex flex-col gap-3",
|
|
292
292
|
children: [
|
|
293
|
-
/* @__PURE__ */
|
|
293
|
+
/* @__PURE__ */ S("div", {
|
|
294
294
|
className: "flex flex-col gap-1",
|
|
295
|
-
children: [/* @__PURE__ */
|
|
295
|
+
children: [/* @__PURE__ */ x(b, {
|
|
296
296
|
htmlFor: "custom-widget-title",
|
|
297
|
-
children:
|
|
298
|
-
}), /* @__PURE__ */
|
|
297
|
+
children: k("bigconsole.widget.customWidget.field.title", "Title")
|
|
298
|
+
}), /* @__PURE__ */ x(y, {
|
|
299
299
|
id: "custom-widget-title",
|
|
300
300
|
"data-testid": "custom-widget-title",
|
|
301
|
-
className:
|
|
302
|
-
value:
|
|
303
|
-
onChange: (e) =>
|
|
301
|
+
className: oe,
|
|
302
|
+
value: M.presentation.title,
|
|
303
|
+
onChange: (e) => Z((t) => ({
|
|
304
304
|
...t,
|
|
305
305
|
presentation: {
|
|
306
306
|
...t.presentation,
|
|
@@ -309,104 +309,106 @@ var C = a(function({ sinks: a, parsers: C, resolvePreviewData: w, onApprove: T,
|
|
|
309
309
|
}))
|
|
310
310
|
})]
|
|
311
311
|
}),
|
|
312
|
-
/* @__PURE__ */
|
|
312
|
+
/* @__PURE__ */ S("div", {
|
|
313
313
|
className: "flex flex-col gap-1",
|
|
314
|
-
children: [/* @__PURE__ */
|
|
314
|
+
children: [/* @__PURE__ */ x(b, {
|
|
315
315
|
htmlFor: "custom-widget-type",
|
|
316
|
-
children:
|
|
317
|
-
}), /* @__PURE__ */
|
|
316
|
+
children: k("bigconsole.widget.customWidget.field.widgetType", "Widget type")
|
|
317
|
+
}), /* @__PURE__ */ x("select", {
|
|
318
318
|
id: "custom-widget-type",
|
|
319
319
|
"data-testid": "custom-widget-type",
|
|
320
|
-
value:
|
|
321
|
-
onChange: (e) =>
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
}
|
|
320
|
+
value: M.widgetType,
|
|
321
|
+
onChange: (e) => {
|
|
322
|
+
let t = e.target.value;
|
|
323
|
+
a(t) && Z((e) => s(e, t));
|
|
324
|
+
},
|
|
325
325
|
className: "w-full rounded-md border border-[var(--color-border-default)] bg-bg-surface px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg",
|
|
326
|
-
children:
|
|
326
|
+
children: ee.map((e) => /* @__PURE__ */ x("option", {
|
|
327
327
|
value: e,
|
|
328
328
|
children: e
|
|
329
329
|
}, e))
|
|
330
330
|
})]
|
|
331
331
|
}),
|
|
332
|
-
/* @__PURE__ */
|
|
332
|
+
/* @__PURE__ */ S("div", {
|
|
333
333
|
className: "flex flex-col gap-1",
|
|
334
|
-
children: [/* @__PURE__ */
|
|
334
|
+
children: [/* @__PURE__ */ x(b, {
|
|
335
335
|
htmlFor: "custom-widget-sink",
|
|
336
|
-
children:
|
|
337
|
-
}), /* @__PURE__ */
|
|
336
|
+
children: k("bigconsole.widget.customWidget.field.dataSink", "DataSink")
|
|
337
|
+
}), /* @__PURE__ */ S("select", {
|
|
338
338
|
id: "custom-widget-sink",
|
|
339
339
|
"data-testid": "custom-widget-sink",
|
|
340
|
-
value:
|
|
340
|
+
value: M.binding.dataSinkId,
|
|
341
341
|
onChange: (e) => {
|
|
342
|
-
let t =
|
|
343
|
-
|
|
342
|
+
let t = l.find((t) => t.id === e.target.value);
|
|
343
|
+
Z((n) => ({
|
|
344
344
|
...n,
|
|
345
345
|
binding: {
|
|
346
346
|
...n.binding,
|
|
347
347
|
dataSinkId: e.target.value,
|
|
348
348
|
dataSinkKey: t?.key
|
|
349
|
-
}
|
|
349
|
+
},
|
|
350
|
+
rationale: void 0
|
|
350
351
|
}));
|
|
351
352
|
},
|
|
352
353
|
className: "w-full rounded-md border border-[var(--color-border-default)] bg-bg-surface px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg",
|
|
353
|
-
children: [/* @__PURE__ */
|
|
354
|
+
children: [/* @__PURE__ */ x("option", {
|
|
354
355
|
value: "",
|
|
355
|
-
children:
|
|
356
|
-
}),
|
|
356
|
+
children: k("bigconsole.widget.customWidget.field.selectDataSink", "Select a DataSink…")
|
|
357
|
+
}), l.map((e) => /* @__PURE__ */ x("option", {
|
|
357
358
|
value: e.id,
|
|
358
359
|
children: e.name || e.key
|
|
359
360
|
}, e.id))]
|
|
360
361
|
})]
|
|
361
362
|
}),
|
|
362
|
-
/* @__PURE__ */
|
|
363
|
+
/* @__PURE__ */ S("div", {
|
|
363
364
|
className: "flex flex-col gap-1",
|
|
364
|
-
children: [/* @__PURE__ */
|
|
365
|
+
children: [/* @__PURE__ */ x(b, {
|
|
365
366
|
htmlFor: "custom-widget-parser",
|
|
366
|
-
children:
|
|
367
|
-
}), /* @__PURE__ */
|
|
367
|
+
children: k("bigconsole.widget.customWidget.field.parser", "Parser")
|
|
368
|
+
}), /* @__PURE__ */ S("select", {
|
|
368
369
|
id: "custom-widget-parser",
|
|
369
370
|
"data-testid": "custom-widget-parser",
|
|
370
|
-
value:
|
|
371
|
+
value: M.binding.parserId ?? "",
|
|
371
372
|
onChange: (e) => {
|
|
372
|
-
let t =
|
|
373
|
-
|
|
373
|
+
let t = w.find((t) => t.id === e.target.value);
|
|
374
|
+
Z((n) => ({
|
|
374
375
|
...n,
|
|
375
376
|
binding: {
|
|
376
377
|
...n.binding,
|
|
377
378
|
parserId: e.target.value || void 0,
|
|
378
379
|
parserName: t?.name
|
|
379
|
-
}
|
|
380
|
+
},
|
|
381
|
+
rationale: void 0
|
|
380
382
|
}));
|
|
381
383
|
},
|
|
382
384
|
className: "w-full rounded-md border border-[var(--color-border-default)] bg-bg-surface px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg",
|
|
383
|
-
children: [/* @__PURE__ */
|
|
385
|
+
children: [/* @__PURE__ */ x("option", {
|
|
384
386
|
value: "",
|
|
385
|
-
children:
|
|
386
|
-
}),
|
|
387
|
+
children: k("bigconsole.widget.customWidget.field.noParser", "No parser")
|
|
388
|
+
}), w.map((e) => /* @__PURE__ */ x("option", {
|
|
387
389
|
value: e.id,
|
|
388
390
|
children: e.name
|
|
389
391
|
}, e.id))]
|
|
390
392
|
})]
|
|
391
393
|
}),
|
|
392
|
-
Object.keys(
|
|
394
|
+
Object.keys(M.fieldMapping).length > 0 ? /* @__PURE__ */ S("fieldset", {
|
|
393
395
|
className: "flex flex-col gap-2",
|
|
394
396
|
"data-testid": "custom-widget-field-mapping",
|
|
395
397
|
children: [
|
|
396
|
-
/* @__PURE__ */
|
|
398
|
+
/* @__PURE__ */ x("legend", {
|
|
397
399
|
className: "text-sm font-medium text-text-primary",
|
|
398
|
-
children:
|
|
400
|
+
children: k("bigconsole.widget.customWidget.fieldMapping.legend", "Field mapping")
|
|
399
401
|
}),
|
|
400
|
-
Object.entries(
|
|
402
|
+
Object.entries(M.fieldMapping).map(([e, t]) => /* @__PURE__ */ S("div", {
|
|
401
403
|
className: "flex flex-col gap-1",
|
|
402
|
-
children: [/* @__PURE__ */
|
|
404
|
+
children: [/* @__PURE__ */ x(b, {
|
|
403
405
|
htmlFor: `custom-widget-field-${e}`,
|
|
404
406
|
children: e
|
|
405
|
-
}), /* @__PURE__ */
|
|
407
|
+
}), /* @__PURE__ */ x(y, {
|
|
406
408
|
id: `custom-widget-field-${e}`,
|
|
407
409
|
"data-testid": `custom-widget-field-${e}`,
|
|
408
410
|
value: t,
|
|
409
|
-
onChange: (t) =>
|
|
411
|
+
onChange: (t) => Z((n) => ({
|
|
410
412
|
...n,
|
|
411
413
|
fieldMapping: {
|
|
412
414
|
...n.fieldMapping,
|
|
@@ -415,59 +417,59 @@ var C = a(function({ sinks: a, parsers: C, resolvePreviewData: w, onApprove: T,
|
|
|
415
417
|
}))
|
|
416
418
|
})]
|
|
417
419
|
}, e)),
|
|
418
|
-
|
|
420
|
+
J?.length ? /* @__PURE__ */ x("p", {
|
|
419
421
|
className: "break-words text-xs text-text-secondary",
|
|
420
|
-
children:
|
|
422
|
+
children: k("bigconsole.widget.customWidget.fieldMapping.available", "Available: {{fields}}", { fields: J.join(", ") })
|
|
421
423
|
}) : null
|
|
422
424
|
]
|
|
423
425
|
}) : null
|
|
424
426
|
]
|
|
425
427
|
})
|
|
426
428
|
}),
|
|
427
|
-
|
|
429
|
+
R ? /* @__PURE__ */ x(e, {
|
|
428
430
|
tone: "danger",
|
|
429
431
|
padding: "compact",
|
|
430
432
|
headingLevel: 3,
|
|
431
433
|
title: "Could not add the widget",
|
|
432
|
-
children: /* @__PURE__ */
|
|
434
|
+
children: /* @__PURE__ */ x("p", {
|
|
433
435
|
role: "alert",
|
|
434
436
|
className: "break-words text-xs text-[var(--color-status-error-text)]",
|
|
435
437
|
"data-testid": "custom-widget-approve-error",
|
|
436
|
-
children:
|
|
438
|
+
children: R
|
|
437
439
|
})
|
|
438
440
|
}) : null,
|
|
439
|
-
/* @__PURE__ */
|
|
441
|
+
/* @__PURE__ */ S("div", {
|
|
440
442
|
className: "flex flex-wrap gap-2 border-t border-[var(--color-border-subtle)] pt-3",
|
|
441
|
-
children: [/* @__PURE__ */
|
|
443
|
+
children: [/* @__PURE__ */ S(v, {
|
|
442
444
|
"data-testid": "custom-widget-approve",
|
|
443
|
-
onClick:
|
|
444
|
-
disabled: !
|
|
445
|
-
children: [
|
|
445
|
+
onClick: pe,
|
|
446
|
+
disabled: !Y.canApprove || H || W || I,
|
|
447
|
+
children: [I ? /* @__PURE__ */ x(g, {
|
|
446
448
|
className: "mr-2 size-4 animate-spin",
|
|
447
449
|
"aria-hidden": "true"
|
|
448
|
-
}) : /* @__PURE__ */
|
|
450
|
+
}) : /* @__PURE__ */ x(h, {
|
|
449
451
|
className: "mr-1 size-4",
|
|
450
452
|
"aria-hidden": "true"
|
|
451
|
-
}),
|
|
452
|
-
}), /* @__PURE__ */
|
|
453
|
+
}), k("bigconsole.widget.customWidget.action.approveAndAdd", "Approve & add to dashboard")]
|
|
454
|
+
}), /* @__PURE__ */ x(v, {
|
|
453
455
|
variant: "outline",
|
|
454
|
-
onClick:
|
|
456
|
+
onClick: D,
|
|
455
457
|
"data-testid": "custom-widget-cancel",
|
|
456
|
-
children:
|
|
458
|
+
children: k("bigconsole.widget.customWidget.action.cancel", "Cancel")
|
|
457
459
|
})]
|
|
458
460
|
})
|
|
459
|
-
] }) : /* @__PURE__ */
|
|
461
|
+
] }) : /* @__PURE__ */ x(e, {
|
|
460
462
|
emphasis: "muted",
|
|
461
463
|
padding: "compact",
|
|
462
464
|
title: "No proposal yet",
|
|
463
465
|
headingLevel: 3,
|
|
464
|
-
children: /* @__PURE__ */
|
|
466
|
+
children: /* @__PURE__ */ x("p", {
|
|
465
467
|
className: "text-sm text-text-secondary",
|
|
466
468
|
"data-testid": "custom-widget-empty",
|
|
467
|
-
children:
|
|
469
|
+
children: k("bigconsole.widget.customWidget.empty", "No proposal yet. Describe a widget and the assistant will propose one for you to review — nothing is added to the dashboard until you approve it.")
|
|
468
470
|
})
|
|
469
471
|
})] })
|
|
470
472
|
});
|
|
471
473
|
});
|
|
472
474
|
//#endregion
|
|
473
|
-
export {
|
|
475
|
+
export { w as default };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CustomWidgetProposal } from './proposalContract';
|
|
1
|
+
import { CustomWidgetProposal, ProposableWidgetType } from './proposalContract';
|
|
2
2
|
|
|
3
3
|
/** A sink the current user may bind to, as the panel knows it. */
|
|
4
4
|
export interface ProposalCandidateSink {
|
|
@@ -33,6 +33,8 @@ export interface CustomWidgetProposalSource {
|
|
|
33
33
|
readonly id: string;
|
|
34
34
|
propose(request: ProposalRequest): Promise<CustomWidgetProposal>;
|
|
35
35
|
}
|
|
36
|
+
/** Keep shared human edits while removing mappings the new renderer cannot use. */
|
|
37
|
+
export declare function changeProposalWidgetType(proposal: CustomWidgetProposal, widgetType: ProposableWidgetType): CustomWidgetProposal;
|
|
36
38
|
/**
|
|
37
39
|
* Derives a proposal from the prompt and the workspace's real, permitted sinks
|
|
38
40
|
* and parsers. Deterministic, so the review UI and its tests behave predictably.
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
+
import { PROPOSABLE_WIDGET_TYPES as e } from "./proposalContract.js";
|
|
1
2
|
//#region src/bigconsole/customWidget/proposalSource.ts
|
|
2
|
-
function
|
|
3
|
+
function t(e) {
|
|
3
4
|
return e.filter((e) => !e.deletedAt && e.isActive !== !1).map(({ id: e, key: t, name: n }) => ({
|
|
4
5
|
id: e,
|
|
5
6
|
key: t,
|
|
6
7
|
name: n
|
|
7
8
|
}));
|
|
8
9
|
}
|
|
9
|
-
var
|
|
10
|
+
var n = [
|
|
10
11
|
{
|
|
11
12
|
type: "funnel_chart",
|
|
12
13
|
words: [
|
|
@@ -65,7 +66,7 @@ var t = [
|
|
|
65
66
|
"graph"
|
|
66
67
|
]
|
|
67
68
|
}
|
|
68
|
-
],
|
|
69
|
+
], r = [
|
|
69
70
|
{
|
|
70
71
|
chartType: "bar",
|
|
71
72
|
words: ["bar"]
|
|
@@ -92,17 +93,17 @@ var t = [
|
|
|
92
93
|
]
|
|
93
94
|
}
|
|
94
95
|
];
|
|
95
|
-
function
|
|
96
|
-
let
|
|
97
|
-
for (let { type: e, words: r } of
|
|
96
|
+
function i(e) {
|
|
97
|
+
let t = e.toLowerCase();
|
|
98
|
+
for (let { type: e, words: r } of n) if (r.some((e) => t.includes(e))) return e;
|
|
98
99
|
return "chart";
|
|
99
100
|
}
|
|
100
|
-
function
|
|
101
|
+
function a(e) {
|
|
101
102
|
let t = e.toLowerCase();
|
|
102
|
-
for (let { chartType: e, words:
|
|
103
|
+
for (let { chartType: e, words: n } of r) if (n.some((e) => t.includes(e))) return e;
|
|
103
104
|
return "line";
|
|
104
105
|
}
|
|
105
|
-
function
|
|
106
|
+
function o(e, t) {
|
|
106
107
|
if (t.length === 0) return;
|
|
107
108
|
let n = e.toLowerCase().split(/[^a-z0-9]+/).filter((e) => e.length > 2), r;
|
|
108
109
|
for (let e of t) {
|
|
@@ -114,7 +115,7 @@ function a(e, t) {
|
|
|
114
115
|
}
|
|
115
116
|
return r?.sink ?? t[0];
|
|
116
117
|
}
|
|
117
|
-
function
|
|
118
|
+
function s(e) {
|
|
118
119
|
switch (e) {
|
|
119
120
|
case "heatmap": return {
|
|
120
121
|
xAxisField: "column",
|
|
@@ -138,7 +139,20 @@ function o(e) {
|
|
|
138
139
|
};
|
|
139
140
|
}
|
|
140
141
|
}
|
|
141
|
-
function
|
|
142
|
+
function c(t, n) {
|
|
143
|
+
if (t.widgetType === n) return t;
|
|
144
|
+
let r = s(n), i = Object.fromEntries(Object.entries(r).map(([e, n]) => [e, t.fieldMapping[e] ?? n])), a = new Set(e.flatMap((e) => Object.keys(s(e)))), o = new Set([...a].filter((e) => !Object.hasOwn(r, e)));
|
|
145
|
+
return {
|
|
146
|
+
...t,
|
|
147
|
+
widgetType: n,
|
|
148
|
+
fieldMapping: i,
|
|
149
|
+
presentation: {
|
|
150
|
+
...t.presentation,
|
|
151
|
+
config: Object.fromEntries(Object.entries(t.presentation.config).filter(([e]) => !o.has(e)))
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
function l(e, t) {
|
|
142
156
|
let n = {
|
|
143
157
|
showLegend: !0,
|
|
144
158
|
showTooltip: !0
|
|
@@ -146,7 +160,7 @@ function s(e, t) {
|
|
|
146
160
|
switch (e) {
|
|
147
161
|
case "chart": return {
|
|
148
162
|
...n,
|
|
149
|
-
chartType:
|
|
163
|
+
chartType: a(t),
|
|
150
164
|
showGrid: !0
|
|
151
165
|
};
|
|
152
166
|
case "funnel_chart": return {
|
|
@@ -173,37 +187,37 @@ function s(e, t) {
|
|
|
173
187
|
default: return n;
|
|
174
188
|
}
|
|
175
189
|
}
|
|
176
|
-
function
|
|
190
|
+
function u(e) {
|
|
177
191
|
let t = e.trim().replace(/^(please\s+)?(create|build|make|add|show me|show|give me)\s+(an?\s+|the\s+)?/i, "").split(/[.;\n]/)[0].trim();
|
|
178
192
|
if (!t) return "Custom widget";
|
|
179
193
|
let n = t.charAt(0).toUpperCase() + t.slice(1);
|
|
180
194
|
return n.length > 60 ? `${n.slice(0, 57)}…` : n;
|
|
181
195
|
}
|
|
182
|
-
var
|
|
196
|
+
var d = 0, f = {
|
|
183
197
|
id: "local-heuristic-v1",
|
|
184
198
|
async propose({ prompt: e, sinks: t, parsers: n }) {
|
|
185
|
-
let
|
|
186
|
-
return
|
|
199
|
+
let r = i(e), a = o(e, t), c = a ? n.find((e) => e.inputSinkKey === a.key) : void 0;
|
|
200
|
+
return d += 1, {
|
|
187
201
|
version: "1.0",
|
|
188
|
-
id: `proposal-${
|
|
202
|
+
id: `proposal-${d}`,
|
|
189
203
|
sourcePrompt: e,
|
|
190
|
-
generatedBy:
|
|
191
|
-
widgetType:
|
|
204
|
+
generatedBy: f.id,
|
|
205
|
+
widgetType: r,
|
|
192
206
|
binding: {
|
|
193
|
-
dataSinkId:
|
|
194
|
-
dataSinkKey:
|
|
195
|
-
parserId:
|
|
196
|
-
parserName:
|
|
207
|
+
dataSinkId: a?.id ?? "",
|
|
208
|
+
dataSinkKey: a?.key,
|
|
209
|
+
parserId: c?.id,
|
|
210
|
+
parserName: c?.name
|
|
197
211
|
},
|
|
198
|
-
fieldMapping:
|
|
212
|
+
fieldMapping: s(r),
|
|
199
213
|
presentation: {
|
|
200
|
-
title:
|
|
214
|
+
title: u(e),
|
|
201
215
|
description: `Generated from: "${e}"`,
|
|
202
|
-
config:
|
|
216
|
+
config: l(r, e)
|
|
203
217
|
},
|
|
204
|
-
rationale:
|
|
218
|
+
rationale: a ? `Matched DataSink "${a.key}"${c ? ` and parser "${c.name}"` : " (no parser found for this sink)"}.` : "No DataSink is available in this workspace — create one before saving this widget."
|
|
205
219
|
};
|
|
206
220
|
}
|
|
207
221
|
};
|
|
208
222
|
//#endregion
|
|
209
|
-
export {
|
|
223
|
+
export { c as changeProposalWidgetType, f as localProposalSource, t as selectActiveProposalSinks };
|