@burdenoff/microfe-bigconsole 2026.803.3 → 2026.804.1
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/components/datasink/ImportDataGuideDialog.js +66 -0
- package/dist/bigconsole/components/datasink/ImportDataGuideDialog.js.map +1 -0
- package/dist/bigconsole/components/parser/DataSinkSelector.js +129 -106
- package/dist/bigconsole/components/parser/DataSinkSelector.js.map +1 -1
- package/dist/bigconsole/components/parser/ParserSelector.js +183 -144
- package/dist/bigconsole/components/parser/ParserSelector.js.map +1 -1
- package/dist/bigconsole/components/widgets/WidgetRegistry.js +1 -1
- package/dist/bigconsole/components/widgets/WidgetRegistry.js.map +1 -1
- package/dist/bigconsole/components/widgets/WidgetWrapper.js +127 -130
- package/dist/bigconsole/components/widgets/WidgetWrapper.js.map +1 -1
- package/dist/bigconsole/components/widgets/iframe-widget/IframeWidget.js +32 -18
- package/dist/bigconsole/components/widgets/iframe-widget/IframeWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/iframe-widget/index.js +2 -2
- package/dist/bigconsole/components/widgets/text-widget/TextWidget.js +25 -19
- package/dist/bigconsole/components/widgets/text-widget/TextWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/text-widget/index.js +3 -2
- package/dist/bigconsole/components/widgets/text-widget/textData.js +71 -0
- package/dist/bigconsole/components/widgets/text-widget/textData.js.map +1 -0
- package/dist/bigconsole/contexts/NavigationContext.js +6 -2
- package/dist/bigconsole/contexts/NavigationContext.js.map +1 -1
- package/dist/bigconsole/pages/DataSinkViewPage.js +136 -101
- package/dist/bigconsole/pages/DataSinkViewPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,47 +1,50 @@
|
|
|
1
|
-
import e from "../../
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
1
|
+
import { useBuildPath as e } from "../../contexts/NavigationContext.js";
|
|
2
|
+
import "../../contexts/index.js";
|
|
3
|
+
import t from "../../hooks/useParserOperations.js";
|
|
4
|
+
import n from "./ParserTypeBadge.js";
|
|
5
|
+
import r from "./ParserStatusBadge.js";
|
|
6
|
+
import { Fragment as i, memo as a, useCallback as o, useEffect as s, useMemo as c, useState as l } from "react";
|
|
7
|
+
import { Plus as u } from "lucide-react";
|
|
8
|
+
import { jsx as d, jsxs as f } from "react/jsx-runtime";
|
|
6
9
|
//#region src/bigconsole/components/parser/ParserSelector.tsx
|
|
7
|
-
var
|
|
10
|
+
var p = "default", m = ({ className: e }) => /* @__PURE__ */ d("svg", {
|
|
8
11
|
className: e,
|
|
9
12
|
fill: "none",
|
|
10
13
|
stroke: "currentColor",
|
|
11
14
|
viewBox: "0 0 24 24",
|
|
12
|
-
children: /* @__PURE__ */
|
|
15
|
+
children: /* @__PURE__ */ d("path", {
|
|
13
16
|
strokeLinecap: "round",
|
|
14
17
|
strokeLinejoin: "round",
|
|
15
18
|
strokeWidth: 2,
|
|
16
19
|
d: "M19 9l-7 7-7-7"
|
|
17
20
|
})
|
|
18
|
-
}),
|
|
21
|
+
}), h = ({ className: e }) => /* @__PURE__ */ f("svg", {
|
|
19
22
|
className: e,
|
|
20
23
|
fill: "none",
|
|
21
24
|
stroke: "currentColor",
|
|
22
25
|
viewBox: "0 0 24 24",
|
|
23
26
|
children: [
|
|
24
|
-
/* @__PURE__ */
|
|
27
|
+
/* @__PURE__ */ d("path", {
|
|
25
28
|
strokeLinecap: "round",
|
|
26
29
|
strokeLinejoin: "round",
|
|
27
30
|
strokeWidth: 2,
|
|
28
31
|
d: "M12 21a9 9 0 100-18 9 9 0 000 18z"
|
|
29
32
|
}),
|
|
30
|
-
/* @__PURE__ */
|
|
33
|
+
/* @__PURE__ */ d("path", {
|
|
31
34
|
strokeLinecap: "round",
|
|
32
35
|
strokeLinejoin: "round",
|
|
33
36
|
strokeWidth: 2,
|
|
34
37
|
d: "M3.6 9h16.8M3.6 15h16.8"
|
|
35
38
|
}),
|
|
36
|
-
/* @__PURE__ */
|
|
39
|
+
/* @__PURE__ */ d("path", {
|
|
37
40
|
strokeLinecap: "round",
|
|
38
41
|
strokeLinejoin: "round",
|
|
39
42
|
strokeWidth: 2,
|
|
40
43
|
d: "M12 3a15 15 0 014 9 15 15 0 01-4 9 15 15 0 01-4-9 15 15 0 014-9z"
|
|
41
44
|
})
|
|
42
45
|
]
|
|
43
|
-
}),
|
|
44
|
-
return /* @__PURE__ */
|
|
46
|
+
}), g = a(function({ parser: e, isSelected: t, onSelect: i, isGlobal: a = !1 }) {
|
|
47
|
+
return /* @__PURE__ */ d("button", {
|
|
45
48
|
type: "button",
|
|
46
49
|
onClick: () => i(e.id),
|
|
47
50
|
className: `
|
|
@@ -50,113 +53,137 @@ var d = "default", f = ({ className: e }) => /* @__PURE__ */ l("svg", {
|
|
|
50
53
|
hover:bg-bg-sunken
|
|
51
54
|
transition-colors
|
|
52
55
|
border-b border-border-default last:border-b-0
|
|
53
|
-
${
|
|
56
|
+
${t ? "bg-action-primary-bg/10" : ""}
|
|
54
57
|
`,
|
|
55
|
-
children: /* @__PURE__ */
|
|
58
|
+
children: /* @__PURE__ */ f("div", {
|
|
56
59
|
className: "flex items-start justify-between gap-2",
|
|
57
|
-
children: [/* @__PURE__ */
|
|
60
|
+
children: [/* @__PURE__ */ f("div", {
|
|
58
61
|
className: "flex-1 min-w-0",
|
|
59
62
|
children: [
|
|
60
|
-
/* @__PURE__ */
|
|
63
|
+
/* @__PURE__ */ f("div", {
|
|
61
64
|
className: "flex items-center gap-2 mb-1",
|
|
62
65
|
children: [
|
|
63
|
-
/* @__PURE__ */
|
|
66
|
+
/* @__PURE__ */ d(n, {
|
|
64
67
|
type: e.type,
|
|
65
68
|
size: "sm"
|
|
66
69
|
}),
|
|
67
|
-
/* @__PURE__ */
|
|
70
|
+
/* @__PURE__ */ d("span", {
|
|
68
71
|
className: "text-sm font-medium text-text-primary truncate",
|
|
69
72
|
children: e.name
|
|
70
73
|
}),
|
|
71
|
-
a && /* @__PURE__ */
|
|
74
|
+
a && /* @__PURE__ */ f("span", {
|
|
72
75
|
className: "inline-flex items-center gap-1 px-1.5 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded",
|
|
73
|
-
children: [/* @__PURE__ */
|
|
76
|
+
children: [/* @__PURE__ */ d(h, { className: "w-3 h-3" }), "Global"]
|
|
74
77
|
})
|
|
75
78
|
]
|
|
76
79
|
}),
|
|
77
|
-
e.description && /* @__PURE__ */
|
|
80
|
+
e.description && /* @__PURE__ */ d("p", {
|
|
78
81
|
className: "text-xs text-text-secondary line-clamp-1 mb-1",
|
|
79
82
|
children: e.description
|
|
80
83
|
}),
|
|
81
|
-
/* @__PURE__ */
|
|
84
|
+
/* @__PURE__ */ d("div", {
|
|
82
85
|
className: "flex items-center gap-2 text-xs text-text-tertiary",
|
|
83
|
-
children: /* @__PURE__ */
|
|
86
|
+
children: /* @__PURE__ */ f("span", { children: [
|
|
84
87
|
e.inputSinkKey,
|
|
85
88
|
" → ",
|
|
86
89
|
e.outputKey
|
|
87
90
|
] })
|
|
88
91
|
})
|
|
89
92
|
]
|
|
90
|
-
}), /* @__PURE__ */
|
|
93
|
+
}), /* @__PURE__ */ d("div", { children: /* @__PURE__ */ d(r, {
|
|
91
94
|
status: e.status,
|
|
92
95
|
size: "sm",
|
|
93
96
|
showIcon: !1
|
|
94
97
|
}) })]
|
|
95
98
|
})
|
|
96
99
|
});
|
|
97
|
-
}),
|
|
98
|
-
let [
|
|
99
|
-
consoleId:
|
|
100
|
-
skipFetch:
|
|
101
|
-
}), { parsers:
|
|
102
|
-
consoleId:
|
|
103
|
-
skipFetch:
|
|
104
|
-
}),
|
|
105
|
-
if (
|
|
106
|
-
let e = new Set(
|
|
107
|
-
return [...
|
|
100
|
+
}), _ = a(function({ consoleId: r, value: a, onChange: h, filterType: _, filterStatus: v = "active", filterInputSinkKey: y, placeholder: b = "Select a parser...", disabled: x = !1, error: S = !1, errorMessage: C }) {
|
|
101
|
+
let [w, T] = l(!1), [E, D] = l(""), O = e(), k = r === p, { parsers: A, loading: j, fetchParsers: M } = t({
|
|
102
|
+
consoleId: r,
|
|
103
|
+
skipFetch: k
|
|
104
|
+
}), { parsers: N, loading: P, fetchParsers: F } = t({
|
|
105
|
+
consoleId: p,
|
|
106
|
+
skipFetch: k
|
|
107
|
+
}), I = c(() => {
|
|
108
|
+
if (k) return A;
|
|
109
|
+
let e = new Set(A.map((e) => e.id)), t = N.filter((t) => !e.has(t.id));
|
|
110
|
+
return [...A, ...t];
|
|
108
111
|
}, [
|
|
109
|
-
D,
|
|
110
112
|
A,
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
if (
|
|
115
|
-
|
|
113
|
+
N,
|
|
114
|
+
k
|
|
115
|
+
]), L = j || P, R = c(() => I.filter((e) => {
|
|
116
|
+
if (_ && e.type !== _ || v && e.status !== v || y && e.inputSinkKey !== y) return !1;
|
|
117
|
+
if (E) {
|
|
118
|
+
let t = E.toLowerCase();
|
|
116
119
|
return e.name.toLowerCase().includes(t) || e.description?.toLowerCase().includes(t) || e.inputSinkKey.toLowerCase().includes(t) || e.outputKey.toLowerCase().includes(t);
|
|
117
120
|
}
|
|
118
121
|
return !0;
|
|
119
122
|
}), [
|
|
120
|
-
|
|
121
|
-
h,
|
|
122
|
-
g,
|
|
123
|
+
I,
|
|
123
124
|
_,
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
125
|
+
v,
|
|
126
|
+
y,
|
|
127
|
+
E
|
|
128
|
+
]), { dashboardScopedParsers: z, globalScopedParsers: B } = c(() => ({
|
|
129
|
+
dashboardScopedParsers: R.filter((e) => e.consoleId !== p),
|
|
130
|
+
globalScopedParsers: R.filter((e) => e.consoleId === p)
|
|
131
|
+
}), [R]), V = I.find((e) => e.id === a);
|
|
132
|
+
s(() => {
|
|
133
|
+
r && (M({
|
|
134
|
+
type: _,
|
|
135
|
+
status: v ?? void 0
|
|
136
|
+
}), k || F({
|
|
137
|
+
type: _,
|
|
138
|
+
status: v ?? void 0
|
|
136
139
|
}));
|
|
137
140
|
}, [
|
|
138
|
-
|
|
139
|
-
h,
|
|
140
|
-
g,
|
|
141
|
+
r,
|
|
141
142
|
_,
|
|
142
|
-
|
|
143
|
+
v,
|
|
144
|
+
y,
|
|
143
145
|
M,
|
|
144
|
-
|
|
146
|
+
F,
|
|
147
|
+
k
|
|
148
|
+
]);
|
|
149
|
+
let H = o((e) => {
|
|
150
|
+
h(e), T(!1), D("");
|
|
151
|
+
}, [h]), U = o(() => {
|
|
152
|
+
if (x) return;
|
|
153
|
+
let e = !w;
|
|
154
|
+
e && (M({
|
|
155
|
+
type: _,
|
|
156
|
+
status: v ?? void 0
|
|
157
|
+
}), k || F({
|
|
158
|
+
type: _,
|
|
159
|
+
status: v ?? void 0
|
|
160
|
+
})), T(e);
|
|
161
|
+
}, [
|
|
162
|
+
x,
|
|
163
|
+
w,
|
|
164
|
+
M,
|
|
165
|
+
F,
|
|
166
|
+
_,
|
|
167
|
+
v,
|
|
168
|
+
k
|
|
169
|
+
]), W = o(() => {
|
|
170
|
+
T(!1);
|
|
171
|
+
}, []), G = o(() => {
|
|
172
|
+
T(!1);
|
|
173
|
+
let e = k ? "/parsers/new" : `/dashboards/${r}/parsers/new`;
|
|
174
|
+
window.open(O(e), "_blank", "noopener,noreferrer");
|
|
175
|
+
}, [
|
|
176
|
+
O,
|
|
177
|
+
r,
|
|
178
|
+
k
|
|
145
179
|
]);
|
|
146
|
-
|
|
147
|
-
p(e), C(!1), T("");
|
|
148
|
-
}, [p]), B = a(() => {
|
|
149
|
-
y || C((e) => !e);
|
|
150
|
-
}, [y]), V = a(() => {
|
|
151
|
-
C(!1);
|
|
152
|
-
}, []);
|
|
153
|
-
return /* @__PURE__ */ u("div", {
|
|
180
|
+
return /* @__PURE__ */ f("div", {
|
|
154
181
|
className: "relative",
|
|
155
182
|
children: [
|
|
156
|
-
/* @__PURE__ */
|
|
183
|
+
/* @__PURE__ */ f("button", {
|
|
157
184
|
type: "button",
|
|
158
|
-
onClick:
|
|
159
|
-
disabled:
|
|
185
|
+
onClick: U,
|
|
186
|
+
disabled: x,
|
|
160
187
|
className: `
|
|
161
188
|
w-full
|
|
162
189
|
px-3 py-2
|
|
@@ -165,99 +192,111 @@ var d = "default", f = ({ className: e }) => /* @__PURE__ */ l("svg", {
|
|
|
165
192
|
text-left
|
|
166
193
|
flex items-center justify-between gap-2
|
|
167
194
|
transition-colors
|
|
168
|
-
${
|
|
169
|
-
${
|
|
170
|
-
${
|
|
195
|
+
${x ? "opacity-50 cursor-not-allowed" : "hover:border-action-primary-bg cursor-pointer"}
|
|
196
|
+
${S ? "border-status-error-border" : "border-border-default"}
|
|
197
|
+
${w ? "border-action-primary-bg ring-2 ring-action-primary-bg/20" : ""}
|
|
171
198
|
`,
|
|
172
|
-
children: [/* @__PURE__ */
|
|
199
|
+
children: [/* @__PURE__ */ d("div", {
|
|
173
200
|
className: "flex-1 min-w-0",
|
|
174
|
-
children:
|
|
201
|
+
children: V ? /* @__PURE__ */ f("div", {
|
|
175
202
|
className: "flex items-center gap-2",
|
|
176
|
-
children: [/* @__PURE__ */
|
|
177
|
-
type:
|
|
203
|
+
children: [/* @__PURE__ */ d(n, {
|
|
204
|
+
type: V.type,
|
|
178
205
|
size: "sm"
|
|
179
|
-
}), /* @__PURE__ */
|
|
206
|
+
}), /* @__PURE__ */ d("span", {
|
|
180
207
|
className: "text-sm text-text-primary truncate",
|
|
181
|
-
children:
|
|
208
|
+
children: V.name
|
|
182
209
|
})]
|
|
183
|
-
}) : /* @__PURE__ */
|
|
210
|
+
}) : /* @__PURE__ */ d("span", {
|
|
184
211
|
className: "text-sm text-text-tertiary",
|
|
185
|
-
children:
|
|
212
|
+
children: b
|
|
186
213
|
})
|
|
187
|
-
}), /* @__PURE__ */
|
|
214
|
+
}), /* @__PURE__ */ d(m, { className: `w-4 h-4 text-text-secondary transition-transform ${w ? "transform rotate-180" : ""}` })]
|
|
188
215
|
}),
|
|
189
|
-
|
|
216
|
+
S && C && /* @__PURE__ */ d("p", {
|
|
190
217
|
className: "mt-1 text-xs text-status-error-text",
|
|
191
|
-
children:
|
|
218
|
+
children: C
|
|
192
219
|
}),
|
|
193
|
-
|
|
220
|
+
w && /* @__PURE__ */ f(i, { children: [/* @__PURE__ */ d("div", {
|
|
194
221
|
className: "fixed inset-0 z-10",
|
|
195
|
-
onClick:
|
|
196
|
-
}), /* @__PURE__ */
|
|
222
|
+
onClick: W
|
|
223
|
+
}), /* @__PURE__ */ f("div", {
|
|
197
224
|
className: "absolute left-0 right-0 top-full mt-1 z-20 bg-bg-surface border border-border-default rounded-md shadow-lg max-h-80 flex flex-col overflow-hidden",
|
|
198
|
-
children: [
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
className: "
|
|
211
|
-
children: "
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
225
|
+
children: [
|
|
226
|
+
/* @__PURE__ */ d("div", {
|
|
227
|
+
className: "p-2 border-b border-border-default",
|
|
228
|
+
children: /* @__PURE__ */ d("input", {
|
|
229
|
+
type: "text",
|
|
230
|
+
placeholder: "Search parsers...",
|
|
231
|
+
value: E,
|
|
232
|
+
onChange: (e) => D(e.target.value),
|
|
233
|
+
className: "\n w-full px-3 py-2\n bg-bg-sunken\n border border-border-default\n rounded-md\n text-sm text-text-primary\n placeholder-text-tertiary\n focus:outline-none\n focus:border-action-primary-bg\n focus:ring-2\n focus:ring-action-primary-bg/20\n "
|
|
234
|
+
})
|
|
235
|
+
}),
|
|
236
|
+
/* @__PURE__ */ d("div", {
|
|
237
|
+
className: "overflow-y-auto flex-1",
|
|
238
|
+
children: L ? /* @__PURE__ */ d("div", {
|
|
239
|
+
className: "p-4 text-center text-sm text-text-secondary",
|
|
240
|
+
children: "Loading parsers..."
|
|
241
|
+
}) : R.length === 0 ? /* @__PURE__ */ d("div", {
|
|
242
|
+
className: "p-4 text-center text-sm text-text-secondary",
|
|
243
|
+
children: "No parsers found"
|
|
244
|
+
}) : /* @__PURE__ */ f(i, { children: [
|
|
245
|
+
/* @__PURE__ */ d("button", {
|
|
246
|
+
type: "button",
|
|
247
|
+
onClick: () => H(null),
|
|
248
|
+
className: `
|
|
220
249
|
w-full px-3 py-2
|
|
221
250
|
text-left text-sm
|
|
222
251
|
hover:bg-bg-sunken
|
|
223
252
|
transition-colors
|
|
224
|
-
${
|
|
253
|
+
${a === null ? "bg-action-primary-bg/10 text-action-primary-bg" : "text-text-secondary"}
|
|
225
254
|
`,
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
255
|
+
children: /* @__PURE__ */ d("span", {
|
|
256
|
+
className: "italic",
|
|
257
|
+
children: "None"
|
|
258
|
+
})
|
|
259
|
+
}),
|
|
260
|
+
z.length > 0 && /* @__PURE__ */ f(i, { children: [/* @__PURE__ */ d("div", {
|
|
261
|
+
className: "px-3 py-1.5 bg-bg-sunken border-y border-border-default",
|
|
262
|
+
children: /* @__PURE__ */ d("span", {
|
|
263
|
+
className: "text-xs font-medium text-text-secondary uppercase tracking-wide",
|
|
264
|
+
children: "Dashboard Parsers"
|
|
265
|
+
})
|
|
266
|
+
}), z.map((e) => /* @__PURE__ */ d(g, {
|
|
267
|
+
parser: e,
|
|
268
|
+
isSelected: a === e.id,
|
|
269
|
+
onSelect: H
|
|
270
|
+
}, e.id))] }),
|
|
271
|
+
B.length > 0 && /* @__PURE__ */ f(i, { children: [/* @__PURE__ */ d("div", {
|
|
272
|
+
className: "px-3 py-1.5 bg-bg-sunken border-y border-border-default",
|
|
273
|
+
children: /* @__PURE__ */ d("span", {
|
|
274
|
+
className: "text-xs font-medium text-text-secondary uppercase tracking-wide",
|
|
275
|
+
children: "Global Parsers"
|
|
276
|
+
})
|
|
277
|
+
}), B.map((e) => /* @__PURE__ */ d(g, {
|
|
278
|
+
parser: e,
|
|
279
|
+
isSelected: a === e.id,
|
|
280
|
+
onSelect: H,
|
|
281
|
+
isGlobal: !0
|
|
282
|
+
}, e.id))] })
|
|
283
|
+
] })
|
|
284
|
+
}),
|
|
285
|
+
/* @__PURE__ */ d("div", {
|
|
286
|
+
className: "p-2 border-t border-border-default",
|
|
287
|
+
children: /* @__PURE__ */ f("button", {
|
|
288
|
+
type: "button",
|
|
289
|
+
onClick: G,
|
|
290
|
+
className: "\n w-full flex items-center gap-2\n px-3 py-2\n text-sm font-medium text-action-primary-bg\n rounded-md\n hover:bg-action-primary-bg/10\n transition-colors\n ",
|
|
291
|
+
children: [/* @__PURE__ */ d(u, { className: "w-4 h-4" }), "Create new parser"]
|
|
292
|
+
})
|
|
293
|
+
})
|
|
294
|
+
]
|
|
256
295
|
})] })
|
|
257
296
|
]
|
|
258
297
|
});
|
|
259
298
|
});
|
|
260
299
|
//#endregion
|
|
261
|
-
export {
|
|
300
|
+
export { _ as default };
|
|
262
301
|
|
|
263
302
|
//# sourceMappingURL=ParserSelector.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ParserSelector.js","names":[],"sources":["../../../../src/bigconsole/components/parser/ParserSelector.tsx"],"sourcesContent":["/**\n * Parser Selector\n *\n * Dropdown component for selecting a parser.\n * Shows both dashboard-specific parsers and global parsers.\n */\n\nimport { memo, useState, useEffect, useCallback, Fragment, useMemo } from 'react';\nimport { useParserOperations } from '../../hooks/useParserOperations';\nimport { ParserTypeBadge } from './ParserTypeBadge';\nimport { ParserStatusBadge } from './ParserStatusBadge';\nimport type { ParserType, ParserStatus } from '../../types';\n\n// Default console ID for global parsers\nconst DEFAULT_CONSOLE_ID = 'default';\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\ninterface ParserSelectorProps {\n /** Console ID */\n consoleId: string;\n /** Currently selected parser ID */\n value: string | null;\n /** Callback when selection changes */\n onChange: (id: string | null) => void;\n /** Filter by type */\n filterType?: ParserType;\n /** Filter by status */\n filterStatus?: ParserStatus;\n /** Filter by input DataSink key */\n filterInputSinkKey?: string | null;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the selector is disabled */\n disabled?: boolean;\n /** Whether to show error state */\n error?: boolean;\n /** Error message to display */\n errorMessage?: string;\n}\n\n// ============================================================================\n// ICONS\n// ============================================================================\n\nconst ChevronDownIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19 9l-7 7-7-7\" />\n </svg>\n);\n\nconst GlobeIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 21a9 9 0 100-18 9 9 0 000 18z\" />\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M3.6 9h16.8M3.6 15h16.8\" />\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 3a15 15 0 014 9 15 15 0 01-4 9 15 15 0 01-4-9 15 15 0 014-9z\"\n />\n </svg>\n);\n\n// ============================================================================\n// PARSER OPTION BUTTON\n// ============================================================================\n\ninterface ParserOptionButtonProps {\n parser: {\n id: string;\n name: string;\n description: string | null;\n type: 'jq' | 'jsonata';\n inputSinkKey: string;\n outputKey: string;\n status: 'active' | 'inactive';\n };\n isSelected: boolean;\n onSelect: (id: string) => void;\n isGlobal?: boolean;\n}\n\nconst ParserOptionButton = memo(function ParserOptionButton({\n parser,\n isSelected,\n onSelect,\n isGlobal = false,\n}: ParserOptionButtonProps) {\n return (\n <button\n type=\"button\"\n onClick={() => onSelect(parser.id)}\n className={`\n w-full px-3 py-2.5\n text-left\n hover:bg-bg-sunken\n transition-colors\n border-b border-border-default last:border-b-0\n ${isSelected ? 'bg-action-primary-bg/10' : ''}\n `}\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex-1 min-w-0\">\n {/* Name and type */}\n <div className=\"flex items-center gap-2 mb-1\">\n <ParserTypeBadge type={parser.type} size=\"sm\" />\n <span className=\"text-sm font-medium text-text-primary truncate\">{parser.name}</span>\n {isGlobal && (\n <span className=\"inline-flex items-center gap-1 px-1.5 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\">\n <GlobeIcon className=\"w-3 h-3\" />\n Global\n </span>\n )}\n </div>\n\n {/* Description */}\n {parser.description && <p className=\"text-xs text-text-secondary line-clamp-1 mb-1\">{parser.description}</p>}\n\n {/* Data flow */}\n <div className=\"flex items-center gap-2 text-xs text-text-tertiary\">\n <span>\n {parser.inputSinkKey} → {parser.outputKey}\n </span>\n </div>\n </div>\n\n {/* Status badge */}\n <div>\n <ParserStatusBadge status={parser.status} size=\"sm\" showIcon={false} />\n </div>\n </div>\n </button>\n );\n});\n\n// ============================================================================\n// MAIN COMPONENT\n// ============================================================================\n\nexport const ParserSelector = memo(function ParserSelector({\n consoleId,\n value,\n onChange,\n filterType,\n filterStatus = 'active',\n filterInputSinkKey,\n placeholder = 'Select a parser...',\n disabled = false,\n error = false,\n errorMessage,\n}: ParserSelectorProps) {\n const [isOpen, setIsOpen] = useState(false);\n const [searchQuery, setSearchQuery] = useState('');\n\n // Determine if we need to fetch global parsers separately\n const isGlobalConsole = consoleId === DEFAULT_CONSOLE_ID;\n\n // Fetch dashboard-specific parsers\n const {\n parsers: dashboardParsers,\n loading: dashboardLoading,\n fetchParsers: fetchDashboardParsers,\n } = useParserOperations({\n consoleId,\n skipFetch: isGlobalConsole, // Skip if already fetching global\n });\n\n // Fetch global parsers (only if consoleId is not already 'default')\n const {\n parsers: globalParsers,\n loading: globalLoading,\n fetchParsers: fetchGlobalParsers,\n } = useParserOperations({\n consoleId: DEFAULT_CONSOLE_ID,\n skipFetch: isGlobalConsole, // Skip if consoleId is already 'default'\n });\n\n // Combine parsers: dashboard-specific + global (avoiding duplicates)\n const allParsers = useMemo(() => {\n if (isGlobalConsole) {\n // If we're already on global console, just return dashboard parsers\n return dashboardParsers;\n }\n\n // Combine both, with dashboard parsers first\n const parserIds = new Set(dashboardParsers.map((p) => p.id));\n const uniqueGlobalParsers = globalParsers.filter((p) => !parserIds.has(p.id));\n\n return [...dashboardParsers, ...uniqueGlobalParsers];\n }, [dashboardParsers, globalParsers, isGlobalConsole]);\n\n // Combined loading state\n const loading = dashboardLoading || globalLoading;\n\n // Filter parsers\n const filteredParsers = useMemo(() => {\n return allParsers.filter((p) => {\n // Filter by type if specified\n if (filterType && p.type !== filterType) return false;\n\n // Filter by status if specified\n if (filterStatus && p.status !== filterStatus) return false;\n\n // Filter by input DataSink key if specified\n if (filterInputSinkKey && p.inputSinkKey !== filterInputSinkKey) return false;\n\n // Filter by search query\n if (searchQuery) {\n const query = searchQuery.toLowerCase();\n return (\n p.name.toLowerCase().includes(query) ||\n p.description?.toLowerCase().includes(query) ||\n p.inputSinkKey.toLowerCase().includes(query) ||\n p.outputKey.toLowerCase().includes(query)\n );\n }\n\n return true;\n });\n }, [allParsers, filterType, filterStatus, filterInputSinkKey, searchQuery]);\n\n // Group parsers by scope for display\n const { dashboardScopedParsers, globalScopedParsers } = useMemo(() => {\n const dashboard = filteredParsers.filter((p) => p.consoleId !== DEFAULT_CONSOLE_ID);\n const global = filteredParsers.filter((p) => p.consoleId === DEFAULT_CONSOLE_ID);\n return { dashboardScopedParsers: dashboard, globalScopedParsers: global };\n }, [filteredParsers]);\n\n // Find selected parser\n const selectedParser = allParsers.find((p) => p.id === value);\n\n // Fetch parsers when console changes or DataSink filter changes\n useEffect(() => {\n if (consoleId) {\n fetchDashboardParsers({ type: filterType, status: filterStatus ?? undefined });\n\n // Also fetch global parsers if not already on global console\n if (!isGlobalConsole) {\n fetchGlobalParsers({ type: filterType, status: filterStatus ?? undefined });\n }\n }\n }, [\n consoleId,\n filterType,\n filterStatus,\n filterInputSinkKey,\n fetchDashboardParsers,\n fetchGlobalParsers,\n isGlobalConsole,\n ]);\n\n // Handle selection\n const handleSelect = useCallback(\n (id: string | null) => {\n onChange(id);\n setIsOpen(false);\n setSearchQuery('');\n },\n [onChange]\n );\n\n // Toggle dropdown\n const handleToggle = useCallback(() => {\n if (!disabled) {\n setIsOpen((prev) => !prev);\n }\n }, [disabled]);\n\n // Close dropdown\n const handleClose = useCallback(() => {\n setIsOpen(false);\n }, []);\n\n return (\n <div className=\"relative\">\n {/* Trigger button */}\n <button\n type=\"button\"\n onClick={handleToggle}\n disabled={disabled}\n className={`\n w-full\n px-3 py-2\n bg-bg-surface\n border rounded-md\n text-left\n flex items-center justify-between gap-2\n transition-colors\n ${disabled ? 'opacity-50 cursor-not-allowed' : 'hover:border-action-primary-bg cursor-pointer'}\n ${error ? 'border-status-error-border' : 'border-border-default'}\n ${isOpen ? 'border-action-primary-bg ring-2 ring-action-primary-bg/20' : ''}\n `}\n >\n <div className=\"flex-1 min-w-0\">\n {selectedParser ? (\n <div className=\"flex items-center gap-2\">\n <ParserTypeBadge type={selectedParser.type} size=\"sm\" />\n <span className=\"text-sm text-text-primary truncate\">{selectedParser.name}</span>\n </div>\n ) : (\n <span className=\"text-sm text-text-tertiary\">{placeholder}</span>\n )}\n </div>\n\n <ChevronDownIcon\n className={`w-4 h-4 text-text-secondary transition-transform ${isOpen ? 'transform rotate-180' : ''}`}\n />\n </button>\n\n {/* Error message */}\n {error && errorMessage && <p className=\"mt-1 text-xs text-status-error-text\">{errorMessage}</p>}\n\n {/* Dropdown */}\n {isOpen && (\n <Fragment>\n {/* Backdrop */}\n <div className=\"fixed inset-0 z-10\" onClick={handleClose} />\n\n {/* Dropdown content */}\n <div className=\"absolute left-0 right-0 top-full mt-1 z-20 bg-bg-surface border border-border-default rounded-md shadow-lg max-h-80 flex flex-col overflow-hidden\">\n {/* Search input */}\n <div className=\"p-2 border-b border-border-default\">\n <input\n type=\"text\"\n placeholder=\"Search parsers...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className={`\n w-full px-3 py-2\n bg-bg-sunken\n border border-border-default\n rounded-md\n text-sm text-text-primary\n placeholder-text-tertiary\n focus:outline-none\n focus:border-action-primary-bg\n focus:ring-2\n focus:ring-action-primary-bg/20\n `}\n />\n </div>\n\n {/* Options list */}\n <div className=\"overflow-y-auto flex-1\">\n {loading ? (\n <div className=\"p-4 text-center text-sm text-text-secondary\">Loading parsers...</div>\n ) : filteredParsers.length === 0 ? (\n <div className=\"p-4 text-center text-sm text-text-secondary\">No parsers found</div>\n ) : (\n <Fragment>\n {/* None option */}\n <button\n type=\"button\"\n onClick={() => handleSelect(null)}\n className={`\n w-full px-3 py-2\n text-left text-sm\n hover:bg-bg-sunken\n transition-colors\n ${value === null ? 'bg-action-primary-bg/10 text-action-primary-bg' : 'text-text-secondary'}\n `}\n >\n <span className=\"italic\">None</span>\n </button>\n\n {/* Dashboard-scoped parsers section */}\n {dashboardScopedParsers.length > 0 && (\n <Fragment>\n <div className=\"px-3 py-1.5 bg-bg-sunken border-y border-border-default\">\n <span className=\"text-xs font-medium text-text-secondary uppercase tracking-wide\">\n Dashboard Parsers\n </span>\n </div>\n {dashboardScopedParsers.map((parser) => (\n <ParserOptionButton\n key={parser.id}\n parser={parser}\n isSelected={value === parser.id}\n onSelect={handleSelect}\n />\n ))}\n </Fragment>\n )}\n\n {/* Global parsers section */}\n {globalScopedParsers.length > 0 && (\n <Fragment>\n <div className=\"px-3 py-1.5 bg-bg-sunken border-y border-border-default\">\n <span className=\"text-xs font-medium text-text-secondary uppercase tracking-wide\">\n Global Parsers\n </span>\n </div>\n {globalScopedParsers.map((parser) => (\n <ParserOptionButton\n key={parser.id}\n parser={parser}\n isSelected={value === parser.id}\n onSelect={handleSelect}\n isGlobal\n />\n ))}\n </Fragment>\n )}\n </Fragment>\n )}\n </div>\n </div>\n </Fragment>\n )}\n </div>\n );\n});\n\nexport default ParserSelector;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ParserSelector.js","names":[],"sources":["../../../../src/bigconsole/components/parser/ParserSelector.tsx"],"sourcesContent":["/**\n * Parser Selector\n *\n * Dropdown component for selecting a parser.\n * Shows both dashboard-specific parsers and global parsers.\n */\n\nimport { memo, useState, useEffect, useCallback, Fragment, useMemo } from 'react';\nimport { Plus } from 'lucide-react';\nimport { useParserOperations } from '../../hooks/useParserOperations';\nimport { useBuildPath } from '../../contexts';\nimport { ParserTypeBadge } from './ParserTypeBadge';\nimport { ParserStatusBadge } from './ParserStatusBadge';\nimport type { ParserType, ParserStatus } from '../../types';\n\n// Default console ID for global parsers\nconst DEFAULT_CONSOLE_ID = 'default';\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\ninterface ParserSelectorProps {\n /** Console ID */\n consoleId: string;\n /** Currently selected parser ID */\n value: string | null;\n /** Callback when selection changes */\n onChange: (id: string | null) => void;\n /** Filter by type */\n filterType?: ParserType;\n /** Filter by status */\n filterStatus?: ParserStatus;\n /** Filter by input DataSink key */\n filterInputSinkKey?: string | null;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the selector is disabled */\n disabled?: boolean;\n /** Whether to show error state */\n error?: boolean;\n /** Error message to display */\n errorMessage?: string;\n}\n\n// ============================================================================\n// ICONS\n// ============================================================================\n\nconst ChevronDownIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19 9l-7 7-7-7\" />\n </svg>\n);\n\nconst GlobeIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 21a9 9 0 100-18 9 9 0 000 18z\" />\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M3.6 9h16.8M3.6 15h16.8\" />\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 3a15 15 0 014 9 15 15 0 01-4 9 15 15 0 01-4-9 15 15 0 014-9z\"\n />\n </svg>\n);\n\n// ============================================================================\n// PARSER OPTION BUTTON\n// ============================================================================\n\ninterface ParserOptionButtonProps {\n parser: {\n id: string;\n name: string;\n description: string | null;\n type: 'jq' | 'jsonata';\n inputSinkKey: string;\n outputKey: string;\n status: 'active' | 'inactive';\n };\n isSelected: boolean;\n onSelect: (id: string) => void;\n isGlobal?: boolean;\n}\n\nconst ParserOptionButton = memo(function ParserOptionButton({\n parser,\n isSelected,\n onSelect,\n isGlobal = false,\n}: ParserOptionButtonProps) {\n return (\n <button\n type=\"button\"\n onClick={() => onSelect(parser.id)}\n className={`\n w-full px-3 py-2.5\n text-left\n hover:bg-bg-sunken\n transition-colors\n border-b border-border-default last:border-b-0\n ${isSelected ? 'bg-action-primary-bg/10' : ''}\n `}\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex-1 min-w-0\">\n {/* Name and type */}\n <div className=\"flex items-center gap-2 mb-1\">\n <ParserTypeBadge type={parser.type} size=\"sm\" />\n <span className=\"text-sm font-medium text-text-primary truncate\">{parser.name}</span>\n {isGlobal && (\n <span className=\"inline-flex items-center gap-1 px-1.5 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\">\n <GlobeIcon className=\"w-3 h-3\" />\n Global\n </span>\n )}\n </div>\n\n {/* Description */}\n {parser.description && <p className=\"text-xs text-text-secondary line-clamp-1 mb-1\">{parser.description}</p>}\n\n {/* Data flow */}\n <div className=\"flex items-center gap-2 text-xs text-text-tertiary\">\n <span>\n {parser.inputSinkKey} → {parser.outputKey}\n </span>\n </div>\n </div>\n\n {/* Status badge */}\n <div>\n <ParserStatusBadge status={parser.status} size=\"sm\" showIcon={false} />\n </div>\n </div>\n </button>\n );\n});\n\n// ============================================================================\n// MAIN COMPONENT\n// ============================================================================\n\nexport const ParserSelector = memo(function ParserSelector({\n consoleId,\n value,\n onChange,\n filterType,\n filterStatus = 'active',\n filterInputSinkKey,\n placeholder = 'Select a parser...',\n disabled = false,\n error = false,\n errorMessage,\n}: ParserSelectorProps) {\n const [isOpen, setIsOpen] = useState(false);\n const [searchQuery, setSearchQuery] = useState('');\n\n const buildPath = useBuildPath();\n\n // Determine if we need to fetch global parsers separately\n const isGlobalConsole = consoleId === DEFAULT_CONSOLE_ID;\n\n // Fetch dashboard-specific parsers\n const {\n parsers: dashboardParsers,\n loading: dashboardLoading,\n fetchParsers: fetchDashboardParsers,\n } = useParserOperations({\n consoleId,\n skipFetch: isGlobalConsole, // Skip if already fetching global\n });\n\n // Fetch global parsers (only if consoleId is not already 'default')\n const {\n parsers: globalParsers,\n loading: globalLoading,\n fetchParsers: fetchGlobalParsers,\n } = useParserOperations({\n consoleId: DEFAULT_CONSOLE_ID,\n skipFetch: isGlobalConsole, // Skip if consoleId is already 'default'\n });\n\n // Combine parsers: dashboard-specific + global (avoiding duplicates)\n const allParsers = useMemo(() => {\n if (isGlobalConsole) {\n // If we're already on global console, just return dashboard parsers\n return dashboardParsers;\n }\n\n // Combine both, with dashboard parsers first\n const parserIds = new Set(dashboardParsers.map((p) => p.id));\n const uniqueGlobalParsers = globalParsers.filter((p) => !parserIds.has(p.id));\n\n return [...dashboardParsers, ...uniqueGlobalParsers];\n }, [dashboardParsers, globalParsers, isGlobalConsole]);\n\n // Combined loading state\n const loading = dashboardLoading || globalLoading;\n\n // Filter parsers\n const filteredParsers = useMemo(() => {\n return allParsers.filter((p) => {\n // Filter by type if specified\n if (filterType && p.type !== filterType) return false;\n\n // Filter by status if specified\n if (filterStatus && p.status !== filterStatus) return false;\n\n // Filter by input DataSink key if specified\n if (filterInputSinkKey && p.inputSinkKey !== filterInputSinkKey) return false;\n\n // Filter by search query\n if (searchQuery) {\n const query = searchQuery.toLowerCase();\n return (\n p.name.toLowerCase().includes(query) ||\n p.description?.toLowerCase().includes(query) ||\n p.inputSinkKey.toLowerCase().includes(query) ||\n p.outputKey.toLowerCase().includes(query)\n );\n }\n\n return true;\n });\n }, [allParsers, filterType, filterStatus, filterInputSinkKey, searchQuery]);\n\n // Group parsers by scope for display\n const { dashboardScopedParsers, globalScopedParsers } = useMemo(() => {\n const dashboard = filteredParsers.filter((p) => p.consoleId !== DEFAULT_CONSOLE_ID);\n const global = filteredParsers.filter((p) => p.consoleId === DEFAULT_CONSOLE_ID);\n return { dashboardScopedParsers: dashboard, globalScopedParsers: global };\n }, [filteredParsers]);\n\n // Find selected parser\n const selectedParser = allParsers.find((p) => p.id === value);\n\n // Fetch parsers when console changes or DataSink filter changes\n useEffect(() => {\n if (consoleId) {\n fetchDashboardParsers({ type: filterType, status: filterStatus ?? undefined });\n\n // Also fetch global parsers if not already on global console\n if (!isGlobalConsole) {\n fetchGlobalParsers({ type: filterType, status: filterStatus ?? undefined });\n }\n }\n }, [\n consoleId,\n filterType,\n filterStatus,\n filterInputSinkKey,\n fetchDashboardParsers,\n fetchGlobalParsers,\n isGlobalConsole,\n ]);\n\n // Handle selection\n const handleSelect = useCallback(\n (id: string | null) => {\n onChange(id);\n setIsOpen(false);\n setSearchQuery('');\n },\n [onChange]\n );\n\n // Toggle dropdown\n const handleToggle = useCallback(() => {\n if (disabled) return;\n const next = !isOpen;\n // Refetch on open so a parser created via the \"Create new\" tab shows\n // up here without needing a full page reload.\n if (next) {\n void fetchDashboardParsers({ type: filterType, status: filterStatus ?? undefined });\n if (!isGlobalConsole) {\n void fetchGlobalParsers({ type: filterType, status: filterStatus ?? undefined });\n }\n }\n setIsOpen(next);\n }, [disabled, isOpen, fetchDashboardParsers, fetchGlobalParsers, filterType, filterStatus, isGlobalConsole]);\n\n // Close dropdown\n const handleClose = useCallback(() => {\n setIsOpen(false);\n }, []);\n\n // Open the create-Parser page in a new tab so the current editing\n // context (e.g. an unsaved widget in the dashboard builder) is preserved.\n // Preserve the dashboard scope so the new parser is created for this\n // console rather than as a global parser.\n const handleCreateNew = useCallback(() => {\n setIsOpen(false);\n const path = isGlobalConsole ? '/parsers/new' : `/dashboards/${consoleId}/parsers/new`;\n window.open(buildPath(path), '_blank', 'noopener,noreferrer');\n }, [buildPath, consoleId, isGlobalConsole]);\n\n return (\n <div className=\"relative\">\n {/* Trigger button */}\n <button\n type=\"button\"\n onClick={handleToggle}\n disabled={disabled}\n className={`\n w-full\n px-3 py-2\n bg-bg-surface\n border rounded-md\n text-left\n flex items-center justify-between gap-2\n transition-colors\n ${disabled ? 'opacity-50 cursor-not-allowed' : 'hover:border-action-primary-bg cursor-pointer'}\n ${error ? 'border-status-error-border' : 'border-border-default'}\n ${isOpen ? 'border-action-primary-bg ring-2 ring-action-primary-bg/20' : ''}\n `}\n >\n <div className=\"flex-1 min-w-0\">\n {selectedParser ? (\n <div className=\"flex items-center gap-2\">\n <ParserTypeBadge type={selectedParser.type} size=\"sm\" />\n <span className=\"text-sm text-text-primary truncate\">{selectedParser.name}</span>\n </div>\n ) : (\n <span className=\"text-sm text-text-tertiary\">{placeholder}</span>\n )}\n </div>\n\n <ChevronDownIcon\n className={`w-4 h-4 text-text-secondary transition-transform ${isOpen ? 'transform rotate-180' : ''}`}\n />\n </button>\n\n {/* Error message */}\n {error && errorMessage && <p className=\"mt-1 text-xs text-status-error-text\">{errorMessage}</p>}\n\n {/* Dropdown */}\n {isOpen && (\n <Fragment>\n {/* Backdrop */}\n <div className=\"fixed inset-0 z-10\" onClick={handleClose} />\n\n {/* Dropdown content */}\n <div className=\"absolute left-0 right-0 top-full mt-1 z-20 bg-bg-surface border border-border-default rounded-md shadow-lg max-h-80 flex flex-col overflow-hidden\">\n {/* Search input */}\n <div className=\"p-2 border-b border-border-default\">\n <input\n type=\"text\"\n placeholder=\"Search parsers...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className={`\n w-full px-3 py-2\n bg-bg-sunken\n border border-border-default\n rounded-md\n text-sm text-text-primary\n placeholder-text-tertiary\n focus:outline-none\n focus:border-action-primary-bg\n focus:ring-2\n focus:ring-action-primary-bg/20\n `}\n />\n </div>\n\n {/* Options list */}\n <div className=\"overflow-y-auto flex-1\">\n {loading ? (\n <div className=\"p-4 text-center text-sm text-text-secondary\">Loading parsers...</div>\n ) : filteredParsers.length === 0 ? (\n <div className=\"p-4 text-center text-sm text-text-secondary\">No parsers found</div>\n ) : (\n <Fragment>\n {/* None option */}\n <button\n type=\"button\"\n onClick={() => handleSelect(null)}\n className={`\n w-full px-3 py-2\n text-left text-sm\n hover:bg-bg-sunken\n transition-colors\n ${value === null ? 'bg-action-primary-bg/10 text-action-primary-bg' : 'text-text-secondary'}\n `}\n >\n <span className=\"italic\">None</span>\n </button>\n\n {/* Dashboard-scoped parsers section */}\n {dashboardScopedParsers.length > 0 && (\n <Fragment>\n <div className=\"px-3 py-1.5 bg-bg-sunken border-y border-border-default\">\n <span className=\"text-xs font-medium text-text-secondary uppercase tracking-wide\">\n Dashboard Parsers\n </span>\n </div>\n {dashboardScopedParsers.map((parser) => (\n <ParserOptionButton\n key={parser.id}\n parser={parser}\n isSelected={value === parser.id}\n onSelect={handleSelect}\n />\n ))}\n </Fragment>\n )}\n\n {/* Global parsers section */}\n {globalScopedParsers.length > 0 && (\n <Fragment>\n <div className=\"px-3 py-1.5 bg-bg-sunken border-y border-border-default\">\n <span className=\"text-xs font-medium text-text-secondary uppercase tracking-wide\">\n Global Parsers\n </span>\n </div>\n {globalScopedParsers.map((parser) => (\n <ParserOptionButton\n key={parser.id}\n parser={parser}\n isSelected={value === parser.id}\n onSelect={handleSelect}\n isGlobal\n />\n ))}\n </Fragment>\n )}\n </Fragment>\n )}\n </div>\n\n {/* Create new — persistent footer action (opens in a new tab) */}\n <div className=\"p-2 border-t border-border-default\">\n <button\n type=\"button\"\n onClick={handleCreateNew}\n className=\"\n w-full flex items-center gap-2\n px-3 py-2\n text-sm font-medium text-action-primary-bg\n rounded-md\n hover:bg-action-primary-bg/10\n transition-colors\n \"\n >\n <Plus className=\"w-4 h-4\" />\n Create new parser\n </button>\n </div>\n </div>\n </Fragment>\n )}\n </div>\n );\n});\n\nexport default ParserSelector;\n"],"mappings":"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"}
|