@inkindcards/semantic-layer 0.1.3 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-JTSHUCCY.js +252 -0
- package/dist/chunk-JTSHUCCY.js.map +1 -0
- package/dist/{chunk-P72N6ISJ.js → chunk-LWUN7GNU.js} +32 -2
- package/dist/chunk-LWUN7GNU.js.map +1 -0
- package/dist/{chunk-I4L4FFJY.cjs → chunk-YUVOMSAQ.cjs} +32 -2
- package/dist/chunk-YUVOMSAQ.cjs.map +1 -0
- package/dist/chunk-Z5DR3TCI.cjs +261 -0
- package/dist/chunk-Z5DR3TCI.cjs.map +1 -0
- package/dist/components.cjs +627 -2
- package/dist/components.cjs.map +1 -1
- package/dist/components.d.cts +16 -2
- package/dist/components.d.ts +16 -2
- package/dist/components.js +626 -3
- package/dist/components.js.map +1 -1
- package/dist/index.cjs +3 -3
- package/dist/index.d.cts +87 -3
- package/dist/index.d.ts +87 -3
- package/dist/index.js +1 -1
- package/dist/react.cjs +26 -13
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +72 -3
- package/dist/react.d.ts +72 -3
- package/dist/react.js +6 -5
- package/dist/react.js.map +1 -1
- package/dist/{types-Ds_6aDEw.d.cts → types-Dc8Zdacw.d.cts} +44 -1
- package/dist/{types-Ds_6aDEw.d.ts → types-Dc8Zdacw.d.ts} +44 -1
- package/package.json +1 -1
- package/dist/chunk-I4L4FFJY.cjs.map +0 -1
- package/dist/chunk-OJVM3RPD.cjs +0 -135
- package/dist/chunk-OJVM3RPD.cjs.map +0 -1
- package/dist/chunk-P72N6ISJ.js.map +0 -1
- package/dist/chunk-RGVYFSW2.js +0 -129
- package/dist/chunk-RGVYFSW2.js.map +0 -1
package/dist/components.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkZ5DR3TCI_cjs = require('./chunk-Z5DR3TCI.cjs');
|
|
4
4
|
var react = require('react');
|
|
5
5
|
var jsxRuntime = require('react/jsx-runtime');
|
|
6
6
|
|
|
@@ -56,7 +56,7 @@ function MetricPicker({
|
|
|
56
56
|
searchPlaceholder = "Search metrics and dimensions...",
|
|
57
57
|
className
|
|
58
58
|
}) {
|
|
59
|
-
const { fields, categories, isLoading, error } =
|
|
59
|
+
const { fields, categories, isLoading, error } = chunkZ5DR3TCI_cjs.useMetrics();
|
|
60
60
|
const [search, setSearch] = react.useState("");
|
|
61
61
|
const filtered = react.useMemo(() => {
|
|
62
62
|
let result = fields;
|
|
@@ -191,7 +191,632 @@ function ResultsTable({
|
|
|
191
191
|
] })
|
|
192
192
|
] });
|
|
193
193
|
}
|
|
194
|
+
var rootStyle = {
|
|
195
|
+
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
196
|
+
maxWidth: 960,
|
|
197
|
+
margin: "0 auto",
|
|
198
|
+
padding: 24
|
|
199
|
+
};
|
|
200
|
+
var headingStyle = {
|
|
201
|
+
fontSize: 24,
|
|
202
|
+
fontWeight: 700,
|
|
203
|
+
color: "#111827",
|
|
204
|
+
margin: "0 0 4px"
|
|
205
|
+
};
|
|
206
|
+
var subStyle = {
|
|
207
|
+
fontSize: 14,
|
|
208
|
+
color: "#6b7280",
|
|
209
|
+
margin: "0 0 20px"
|
|
210
|
+
};
|
|
211
|
+
var searchBarStyle = {
|
|
212
|
+
display: "flex",
|
|
213
|
+
gap: 8,
|
|
214
|
+
marginBottom: 20
|
|
215
|
+
};
|
|
216
|
+
var searchInput = {
|
|
217
|
+
flex: 1,
|
|
218
|
+
padding: "10px 14px",
|
|
219
|
+
fontSize: 14,
|
|
220
|
+
border: "1px solid #d1d5db",
|
|
221
|
+
borderRadius: 8,
|
|
222
|
+
outline: "none",
|
|
223
|
+
boxSizing: "border-box"
|
|
224
|
+
};
|
|
225
|
+
var filterBtn = (active) => ({
|
|
226
|
+
padding: "8px 14px",
|
|
227
|
+
fontSize: 13,
|
|
228
|
+
fontWeight: 500,
|
|
229
|
+
borderRadius: 6,
|
|
230
|
+
border: "1px solid " + (active ? "#3b82f6" : "#d1d5db"),
|
|
231
|
+
backgroundColor: active ? "#eff6ff" : "#fff",
|
|
232
|
+
color: active ? "#1d4ed8" : "#374151",
|
|
233
|
+
cursor: "pointer"
|
|
234
|
+
});
|
|
235
|
+
var categoryStyle = {
|
|
236
|
+
marginBottom: 24
|
|
237
|
+
};
|
|
238
|
+
var categoryHeader = {
|
|
239
|
+
fontSize: 13,
|
|
240
|
+
fontWeight: 600,
|
|
241
|
+
textTransform: "uppercase",
|
|
242
|
+
letterSpacing: "0.05em",
|
|
243
|
+
color: "#6b7280",
|
|
244
|
+
marginBottom: 8,
|
|
245
|
+
paddingBottom: 6,
|
|
246
|
+
borderBottom: "1px solid #e5e7eb"
|
|
247
|
+
};
|
|
248
|
+
var fieldCard = {
|
|
249
|
+
display: "flex",
|
|
250
|
+
justifyContent: "space-between",
|
|
251
|
+
alignItems: "flex-start",
|
|
252
|
+
padding: "10px 12px",
|
|
253
|
+
borderRadius: 6,
|
|
254
|
+
marginBottom: 4,
|
|
255
|
+
backgroundColor: "#fafafa",
|
|
256
|
+
border: "1px solid #f3f4f6"
|
|
257
|
+
};
|
|
258
|
+
var fieldNameStyle = {
|
|
259
|
+
fontSize: 15,
|
|
260
|
+
fontWeight: 600,
|
|
261
|
+
color: "#111827"
|
|
262
|
+
};
|
|
263
|
+
var fieldDescStyle = {
|
|
264
|
+
fontSize: 13,
|
|
265
|
+
color: "#6b7280",
|
|
266
|
+
marginTop: 2
|
|
267
|
+
};
|
|
268
|
+
var codeName = {
|
|
269
|
+
fontSize: 12,
|
|
270
|
+
color: "#6366f1",
|
|
271
|
+
fontFamily: "monospace",
|
|
272
|
+
marginTop: 2
|
|
273
|
+
};
|
|
274
|
+
var badgeStyle = (type) => ({
|
|
275
|
+
display: "inline-block",
|
|
276
|
+
padding: "2px 8px",
|
|
277
|
+
fontSize: 11,
|
|
278
|
+
fontWeight: 600,
|
|
279
|
+
borderRadius: 9999,
|
|
280
|
+
whiteSpace: "nowrap",
|
|
281
|
+
backgroundColor: type === "metric" ? "#eff6ff" : type === "time_dimension" ? "#f0fdf4" : "#f3f4f6",
|
|
282
|
+
color: type === "metric" ? "#1d4ed8" : type === "time_dimension" ? "#15803d" : "#6b7280"
|
|
283
|
+
});
|
|
284
|
+
var copyBtn = {
|
|
285
|
+
padding: "4px 8px",
|
|
286
|
+
fontSize: 11,
|
|
287
|
+
fontWeight: 500,
|
|
288
|
+
color: "#6366f1",
|
|
289
|
+
backgroundColor: "#eef2ff",
|
|
290
|
+
border: "1px solid #c7d2fe",
|
|
291
|
+
borderRadius: 4,
|
|
292
|
+
cursor: "pointer",
|
|
293
|
+
whiteSpace: "nowrap"
|
|
294
|
+
};
|
|
295
|
+
var statsBar = {
|
|
296
|
+
display: "flex",
|
|
297
|
+
gap: 16,
|
|
298
|
+
marginBottom: 16,
|
|
299
|
+
fontSize: 14
|
|
300
|
+
};
|
|
301
|
+
var statItem = {
|
|
302
|
+
display: "flex",
|
|
303
|
+
alignItems: "center",
|
|
304
|
+
gap: 4,
|
|
305
|
+
color: "#6b7280"
|
|
306
|
+
};
|
|
307
|
+
var statNum = { fontWeight: 700, color: "#111827" };
|
|
308
|
+
var emptyStyle = {
|
|
309
|
+
padding: 40,
|
|
310
|
+
textAlign: "center",
|
|
311
|
+
color: "#9ca3af",
|
|
312
|
+
fontSize: 14
|
|
313
|
+
};
|
|
314
|
+
function DataCatalog({ className, showCopyButton = true, fieldTypes }) {
|
|
315
|
+
const { fields, metrics, dimensions, isLoading, error } = chunkZ5DR3TCI_cjs.useMetrics();
|
|
316
|
+
const [search, setSearch] = react.useState("");
|
|
317
|
+
const [typeFilter, setTypeFilter] = react.useState("all");
|
|
318
|
+
const [copiedField, setCopiedField] = react.useState(null);
|
|
319
|
+
const filtered = react.useMemo(() => {
|
|
320
|
+
let result = fields;
|
|
321
|
+
if (fieldTypes) result = result.filter((f) => fieldTypes.includes(f.type));
|
|
322
|
+
if (typeFilter !== "all") result = result.filter((f) => f.type === typeFilter);
|
|
323
|
+
if (search) {
|
|
324
|
+
const q = search.toLowerCase();
|
|
325
|
+
result = result.filter(
|
|
326
|
+
(f) => f.displayName.toLowerCase().includes(q) || f.name.toLowerCase().includes(q) || f.description.toLowerCase().includes(q) || f.category.toLowerCase().includes(q)
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
return result;
|
|
330
|
+
}, [fields, fieldTypes, typeFilter, search]);
|
|
331
|
+
const grouped = react.useMemo(() => {
|
|
332
|
+
const map = /* @__PURE__ */ new Map();
|
|
333
|
+
for (const f of filtered) {
|
|
334
|
+
const list = map.get(f.category) || [];
|
|
335
|
+
list.push(f);
|
|
336
|
+
map.set(f.category, list);
|
|
337
|
+
}
|
|
338
|
+
return map;
|
|
339
|
+
}, [filtered]);
|
|
340
|
+
const handleCopy = react.useCallback(async (name) => {
|
|
341
|
+
try {
|
|
342
|
+
await navigator.clipboard.writeText(name);
|
|
343
|
+
setCopiedField(name);
|
|
344
|
+
setTimeout(() => setCopiedField(null), 1500);
|
|
345
|
+
} catch {
|
|
346
|
+
}
|
|
347
|
+
}, []);
|
|
348
|
+
if (isLoading) return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { ...rootStyle, ...emptyStyle }, children: "Loading data catalog..." });
|
|
349
|
+
if (error) return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { ...rootStyle, padding: 24, color: "#ef4444" }, children: error });
|
|
350
|
+
const timeDims = fields.filter((f) => f.type === "time_dimension");
|
|
351
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: rootStyle, className, children: [
|
|
352
|
+
/* @__PURE__ */ jsxRuntime.jsx("h1", { style: headingStyle, children: "Data Catalog" }),
|
|
353
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { style: subStyle, children: "Browse available metrics and dimensions from the semantic layer" }),
|
|
354
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: statsBar, children: [
|
|
355
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: statItem, children: [
|
|
356
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: statNum, children: metrics.length }),
|
|
357
|
+
" metrics"
|
|
358
|
+
] }),
|
|
359
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: statItem, children: [
|
|
360
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: statNum, children: dimensions.length - timeDims.length }),
|
|
361
|
+
" dimensions"
|
|
362
|
+
] }),
|
|
363
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: statItem, children: [
|
|
364
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: statNum, children: timeDims.length }),
|
|
365
|
+
" time dimensions"
|
|
366
|
+
] })
|
|
367
|
+
] }),
|
|
368
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: searchBarStyle, children: [
|
|
369
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
370
|
+
"input",
|
|
371
|
+
{
|
|
372
|
+
style: searchInput,
|
|
373
|
+
placeholder: "Search by name, description, or category...",
|
|
374
|
+
value: search,
|
|
375
|
+
onChange: (e) => setSearch(e.target.value)
|
|
376
|
+
}
|
|
377
|
+
),
|
|
378
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { style: filterBtn(typeFilter === "all"), onClick: () => setTypeFilter("all"), children: "All" }),
|
|
379
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { style: filterBtn(typeFilter === "metric"), onClick: () => setTypeFilter("metric"), children: "Metrics" }),
|
|
380
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { style: filterBtn(typeFilter === "dimension"), onClick: () => setTypeFilter("dimension"), children: "Dimensions" }),
|
|
381
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { style: filterBtn(typeFilter === "time_dimension"), onClick: () => setTypeFilter("time_dimension"), children: "Time" })
|
|
382
|
+
] }),
|
|
383
|
+
Array.from(grouped.entries()).map(([category, categoryFields]) => /* @__PURE__ */ jsxRuntime.jsxs("div", { style: categoryStyle, children: [
|
|
384
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: categoryHeader, children: [
|
|
385
|
+
category,
|
|
386
|
+
" (",
|
|
387
|
+
categoryFields.length,
|
|
388
|
+
")"
|
|
389
|
+
] }),
|
|
390
|
+
categoryFields.map((f) => /* @__PURE__ */ jsxRuntime.jsxs("div", { style: fieldCard, children: [
|
|
391
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { flex: 1 }, children: [
|
|
392
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
|
|
393
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: fieldNameStyle, children: f.displayName }),
|
|
394
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: badgeStyle(f.type), children: f.type })
|
|
395
|
+
] }),
|
|
396
|
+
f.description && /* @__PURE__ */ jsxRuntime.jsx("div", { style: fieldDescStyle, children: f.description }),
|
|
397
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: codeName, children: f.name })
|
|
398
|
+
] }),
|
|
399
|
+
showCopyButton && /* @__PURE__ */ jsxRuntime.jsx("button", { style: copyBtn, onClick: () => handleCopy(f.name), children: copiedField === f.name ? "Copied!" : "Copy name" })
|
|
400
|
+
] }, f.id))
|
|
401
|
+
] }, category)),
|
|
402
|
+
grouped.size === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: emptyStyle, children: search ? "No fields match your search." : "No data available. The gateway may not be configured yet." })
|
|
403
|
+
] });
|
|
404
|
+
}
|
|
405
|
+
var rootStyle2 = {
|
|
406
|
+
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
407
|
+
maxWidth: 960,
|
|
408
|
+
margin: "0 auto",
|
|
409
|
+
padding: 24
|
|
410
|
+
};
|
|
411
|
+
var headingStyle2 = {
|
|
412
|
+
fontSize: 24,
|
|
413
|
+
fontWeight: 700,
|
|
414
|
+
color: "#111827",
|
|
415
|
+
margin: "0 0 4px"
|
|
416
|
+
};
|
|
417
|
+
var subStyle2 = {
|
|
418
|
+
fontSize: 14,
|
|
419
|
+
color: "#6b7280",
|
|
420
|
+
margin: "0 0 20px"
|
|
421
|
+
};
|
|
422
|
+
var tabBarStyle = {
|
|
423
|
+
display: "flex",
|
|
424
|
+
gap: 0,
|
|
425
|
+
borderBottom: "1px solid #e5e7eb",
|
|
426
|
+
marginBottom: 24
|
|
427
|
+
};
|
|
428
|
+
var tabBase = {
|
|
429
|
+
padding: "10px 20px",
|
|
430
|
+
fontSize: 14,
|
|
431
|
+
fontWeight: 500,
|
|
432
|
+
cursor: "pointer",
|
|
433
|
+
background: "none",
|
|
434
|
+
border: "none",
|
|
435
|
+
borderBottom: "2px solid transparent",
|
|
436
|
+
color: "#6b7280"
|
|
437
|
+
};
|
|
438
|
+
var tabActive = {
|
|
439
|
+
...tabBase,
|
|
440
|
+
color: "#111827",
|
|
441
|
+
borderBottomColor: "#3b82f6"
|
|
442
|
+
};
|
|
443
|
+
var tableStyle2 = {
|
|
444
|
+
width: "100%",
|
|
445
|
+
borderCollapse: "collapse",
|
|
446
|
+
fontSize: 14
|
|
447
|
+
};
|
|
448
|
+
var thStyle2 = {
|
|
449
|
+
padding: "10px 12px",
|
|
450
|
+
textAlign: "left",
|
|
451
|
+
fontWeight: 600,
|
|
452
|
+
fontSize: 12,
|
|
453
|
+
color: "#6b7280",
|
|
454
|
+
backgroundColor: "#f9fafb",
|
|
455
|
+
borderBottom: "1px solid #e5e7eb"
|
|
456
|
+
};
|
|
457
|
+
var tdStyle2 = {
|
|
458
|
+
padding: "8px 12px",
|
|
459
|
+
borderBottom: "1px solid #f3f4f6",
|
|
460
|
+
color: "#111827"
|
|
461
|
+
};
|
|
462
|
+
var btnPrimary = {
|
|
463
|
+
padding: "8px 16px",
|
|
464
|
+
fontSize: 14,
|
|
465
|
+
fontWeight: 500,
|
|
466
|
+
color: "#fff",
|
|
467
|
+
backgroundColor: "#3b82f6",
|
|
468
|
+
border: "none",
|
|
469
|
+
borderRadius: 6,
|
|
470
|
+
cursor: "pointer"
|
|
471
|
+
};
|
|
472
|
+
var btnDanger = {
|
|
473
|
+
...btnPrimary,
|
|
474
|
+
backgroundColor: "#ef4444"
|
|
475
|
+
};
|
|
476
|
+
var btnSecondary = {
|
|
477
|
+
...btnPrimary,
|
|
478
|
+
backgroundColor: "#fff",
|
|
479
|
+
color: "#374151",
|
|
480
|
+
border: "1px solid #d1d5db"
|
|
481
|
+
};
|
|
482
|
+
var inputStyle = {
|
|
483
|
+
padding: "6px 10px",
|
|
484
|
+
fontSize: 14,
|
|
485
|
+
border: "1px solid #d1d5db",
|
|
486
|
+
borderRadius: 6,
|
|
487
|
+
width: "100%",
|
|
488
|
+
boxSizing: "border-box"
|
|
489
|
+
};
|
|
490
|
+
var selectStyle = { ...inputStyle, width: "auto" };
|
|
491
|
+
var cardStyle = {
|
|
492
|
+
border: "1px solid #e5e7eb",
|
|
493
|
+
borderRadius: 8,
|
|
494
|
+
padding: 16,
|
|
495
|
+
marginBottom: 16,
|
|
496
|
+
backgroundColor: "#fff"
|
|
497
|
+
};
|
|
498
|
+
var errorBanner = {
|
|
499
|
+
padding: "10px 14px",
|
|
500
|
+
backgroundColor: "#fef2f2",
|
|
501
|
+
color: "#b91c1c",
|
|
502
|
+
borderRadius: 6,
|
|
503
|
+
fontSize: 14,
|
|
504
|
+
marginBottom: 16
|
|
505
|
+
};
|
|
506
|
+
var badgeStyle2 = {
|
|
507
|
+
display: "inline-block",
|
|
508
|
+
padding: "2px 8px",
|
|
509
|
+
fontSize: 11,
|
|
510
|
+
fontWeight: 600,
|
|
511
|
+
borderRadius: 9999,
|
|
512
|
+
backgroundColor: "#eff6ff",
|
|
513
|
+
color: "#1d4ed8"
|
|
514
|
+
};
|
|
515
|
+
var badgeGreen = { ...badgeStyle2, backgroundColor: "#f0fdf4", color: "#15803d" };
|
|
516
|
+
var badgeGray = { ...badgeStyle2, backgroundColor: "#f3f4f6", color: "#6b7280" };
|
|
517
|
+
var checkboxStyle = { width: 16, height: 16, cursor: "pointer" };
|
|
518
|
+
var emptyStyle2 = {
|
|
519
|
+
padding: 24,
|
|
520
|
+
textAlign: "center",
|
|
521
|
+
color: "#9ca3af",
|
|
522
|
+
fontSize: 14
|
|
523
|
+
};
|
|
524
|
+
function FieldsTab() {
|
|
525
|
+
const { fields, isLoading, error, createField, updateField, deleteField } = chunkZ5DR3TCI_cjs.useAdminFields();
|
|
526
|
+
const [showAdd, setShowAdd] = react.useState(false);
|
|
527
|
+
const [newName, setNewName] = react.useState("");
|
|
528
|
+
const [newType, setNewType] = react.useState("metric");
|
|
529
|
+
const [newDisplay, setNewDisplay] = react.useState("");
|
|
530
|
+
const [newDesc, setNewDesc] = react.useState("");
|
|
531
|
+
const [actionError, setActionError] = react.useState(null);
|
|
532
|
+
const handleAdd = react.useCallback(async () => {
|
|
533
|
+
if (!newName.trim()) return;
|
|
534
|
+
setActionError(null);
|
|
535
|
+
try {
|
|
536
|
+
await createField({
|
|
537
|
+
field_name: newName.trim(),
|
|
538
|
+
field_type: newType,
|
|
539
|
+
display_name: newDisplay.trim() || void 0,
|
|
540
|
+
description: newDesc.trim() || void 0
|
|
541
|
+
});
|
|
542
|
+
setNewName("");
|
|
543
|
+
setNewDisplay("");
|
|
544
|
+
setNewDesc("");
|
|
545
|
+
setShowAdd(false);
|
|
546
|
+
} catch (err) {
|
|
547
|
+
setActionError(err instanceof Error ? err.message : "Failed to create field");
|
|
548
|
+
}
|
|
549
|
+
}, [newName, newType, newDisplay, newDesc, createField]);
|
|
550
|
+
const handleToggle = react.useCallback(async (f) => {
|
|
551
|
+
try {
|
|
552
|
+
await updateField({ id: f.id, is_active: !f.is_active });
|
|
553
|
+
} catch (err) {
|
|
554
|
+
setActionError(err instanceof Error ? err.message : "Failed to update");
|
|
555
|
+
}
|
|
556
|
+
}, [updateField]);
|
|
557
|
+
const handleDelete = react.useCallback(async (id) => {
|
|
558
|
+
if (!confirm("Delete this field? This also removes it from all roles.")) return;
|
|
559
|
+
try {
|
|
560
|
+
await deleteField(id);
|
|
561
|
+
} catch (err) {
|
|
562
|
+
setActionError(err instanceof Error ? err.message : "Failed to delete");
|
|
563
|
+
}
|
|
564
|
+
}, [deleteField]);
|
|
565
|
+
if (isLoading) return /* @__PURE__ */ jsxRuntime.jsx("div", { style: emptyStyle2, children: "Loading fields..." });
|
|
566
|
+
if (error) return /* @__PURE__ */ jsxRuntime.jsx("div", { style: errorBanner, children: error });
|
|
567
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
568
|
+
actionError && /* @__PURE__ */ jsxRuntime.jsx("div", { style: errorBanner, children: actionError }),
|
|
569
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 16 }, children: [
|
|
570
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: { fontSize: 14, color: "#6b7280" }, children: [
|
|
571
|
+
fields.length,
|
|
572
|
+
" curated field",
|
|
573
|
+
fields.length !== 1 ? "s" : ""
|
|
574
|
+
] }),
|
|
575
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { style: btnPrimary, onClick: () => setShowAdd(!showAdd), children: showAdd ? "Cancel" : "+ Add field" })
|
|
576
|
+
] }),
|
|
577
|
+
showAdd && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: cardStyle, children: [
|
|
578
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "grid", gridTemplateColumns: "1fr auto 1fr", gap: 8, marginBottom: 8 }, children: [
|
|
579
|
+
/* @__PURE__ */ jsxRuntime.jsx("input", { style: inputStyle, placeholder: "field_name (from dbt)", value: newName, onChange: (e) => setNewName(e.target.value) }),
|
|
580
|
+
/* @__PURE__ */ jsxRuntime.jsxs("select", { style: selectStyle, value: newType, onChange: (e) => setNewType(e.target.value), children: [
|
|
581
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "metric", children: "metric" }),
|
|
582
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "dimension", children: "dimension" }),
|
|
583
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "time_dimension", children: "time_dimension" })
|
|
584
|
+
] }),
|
|
585
|
+
/* @__PURE__ */ jsxRuntime.jsx("input", { style: inputStyle, placeholder: "Display name (optional)", value: newDisplay, onChange: (e) => setNewDisplay(e.target.value) })
|
|
586
|
+
] }),
|
|
587
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: 8 }, children: [
|
|
588
|
+
/* @__PURE__ */ jsxRuntime.jsx("input", { style: { ...inputStyle, flex: 1 }, placeholder: "Description (optional)", value: newDesc, onChange: (e) => setNewDesc(e.target.value), onKeyDown: (e) => e.key === "Enter" && handleAdd() }),
|
|
589
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { style: btnPrimary, onClick: handleAdd, children: "Save" })
|
|
590
|
+
] })
|
|
591
|
+
] }),
|
|
592
|
+
/* @__PURE__ */ jsxRuntime.jsxs("table", { style: tableStyle2, children: [
|
|
593
|
+
/* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
|
|
594
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { style: thStyle2, children: "Field Name" }),
|
|
595
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { style: thStyle2, children: "Type" }),
|
|
596
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { style: thStyle2, children: "Display Name" }),
|
|
597
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { style: thStyle2, children: "Active" }),
|
|
598
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { style: { ...thStyle2, textAlign: "right" }, children: "Actions" })
|
|
599
|
+
] }) }),
|
|
600
|
+
/* @__PURE__ */ jsxRuntime.jsxs("tbody", { children: [
|
|
601
|
+
fields.map((f) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
|
|
602
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { style: tdStyle2, children: /* @__PURE__ */ jsxRuntime.jsx("code", { style: { fontSize: 13 }, children: f.field_name }) }),
|
|
603
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { style: tdStyle2, children: /* @__PURE__ */ jsxRuntime.jsx("span", { style: f.field_type === "metric" ? badgeStyle2 : f.field_type === "time_dimension" ? badgeGreen : badgeGray, children: f.field_type }) }),
|
|
604
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { style: tdStyle2, children: f.display_name || /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "#9ca3af" }, children: "\u2014" }) }),
|
|
605
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { style: tdStyle2, children: /* @__PURE__ */ jsxRuntime.jsx("input", { type: "checkbox", checked: f.is_active, onChange: () => handleToggle(f), style: checkboxStyle }) }),
|
|
606
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { style: { ...tdStyle2, textAlign: "right" }, children: /* @__PURE__ */ jsxRuntime.jsx("button", { style: { ...btnDanger, padding: "4px 10px", fontSize: 12 }, onClick: () => handleDelete(f.id), children: "Delete" }) })
|
|
607
|
+
] }, f.id)),
|
|
608
|
+
fields.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("tr", { children: /* @__PURE__ */ jsxRuntime.jsx("td", { colSpan: 5, style: emptyStyle2, children: "No curated fields yet. Add fields to start restricting access." }) })
|
|
609
|
+
] })
|
|
610
|
+
] })
|
|
611
|
+
] });
|
|
612
|
+
}
|
|
613
|
+
function RolesTab() {
|
|
614
|
+
const { roles, isLoading, error, createRole, deleteRole, setRoleFields } = chunkZ5DR3TCI_cjs.useAdminRoles();
|
|
615
|
+
const { fields } = chunkZ5DR3TCI_cjs.useAdminFields();
|
|
616
|
+
const [showAdd, setShowAdd] = react.useState(false);
|
|
617
|
+
const [newName, setNewName] = react.useState("");
|
|
618
|
+
const [newDesc, setNewDesc] = react.useState("");
|
|
619
|
+
const [editingRole, setEditingRole] = react.useState(null);
|
|
620
|
+
const [actionError, setActionError] = react.useState(null);
|
|
621
|
+
const handleAdd = react.useCallback(async () => {
|
|
622
|
+
if (!newName.trim()) return;
|
|
623
|
+
setActionError(null);
|
|
624
|
+
try {
|
|
625
|
+
await createRole({ name: newName.trim(), description: newDesc.trim() || void 0 });
|
|
626
|
+
setNewName("");
|
|
627
|
+
setNewDesc("");
|
|
628
|
+
setShowAdd(false);
|
|
629
|
+
} catch (err) {
|
|
630
|
+
setActionError(err instanceof Error ? err.message : "Failed to create role");
|
|
631
|
+
}
|
|
632
|
+
}, [newName, newDesc, createRole]);
|
|
633
|
+
const handleDelete = react.useCallback(async (id) => {
|
|
634
|
+
if (!confirm("Delete this role? Users assigned to it will lose this role's access.")) return;
|
|
635
|
+
try {
|
|
636
|
+
await deleteRole(id);
|
|
637
|
+
} catch (err) {
|
|
638
|
+
setActionError(err instanceof Error ? err.message : "Failed to delete");
|
|
639
|
+
}
|
|
640
|
+
}, [deleteRole]);
|
|
641
|
+
const getFieldIds = (role) => new Set((role.role_field_access || []).map((rfa) => rfa.curated_field_id));
|
|
642
|
+
const handleToggleField = react.useCallback(async (role, fieldId) => {
|
|
643
|
+
const current = getFieldIds(role);
|
|
644
|
+
if (current.has(fieldId)) current.delete(fieldId);
|
|
645
|
+
else current.add(fieldId);
|
|
646
|
+
setActionError(null);
|
|
647
|
+
try {
|
|
648
|
+
await setRoleFields(role.id, Array.from(current));
|
|
649
|
+
} catch (err) {
|
|
650
|
+
setActionError(err instanceof Error ? err.message : "Failed to update");
|
|
651
|
+
}
|
|
652
|
+
}, [setRoleFields]);
|
|
653
|
+
if (isLoading) return /* @__PURE__ */ jsxRuntime.jsx("div", { style: emptyStyle2, children: "Loading roles..." });
|
|
654
|
+
if (error) return /* @__PURE__ */ jsxRuntime.jsx("div", { style: errorBanner, children: error });
|
|
655
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
656
|
+
actionError && /* @__PURE__ */ jsxRuntime.jsx("div", { style: errorBanner, children: actionError }),
|
|
657
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 16 }, children: [
|
|
658
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: { fontSize: 14, color: "#6b7280" }, children: [
|
|
659
|
+
roles.length,
|
|
660
|
+
" role",
|
|
661
|
+
roles.length !== 1 ? "s" : ""
|
|
662
|
+
] }),
|
|
663
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { style: btnPrimary, onClick: () => setShowAdd(!showAdd), children: showAdd ? "Cancel" : "+ Add role" })
|
|
664
|
+
] }),
|
|
665
|
+
showAdd && /* @__PURE__ */ jsxRuntime.jsx("div", { style: cardStyle, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: 8 }, children: [
|
|
666
|
+
/* @__PURE__ */ jsxRuntime.jsx("input", { style: { ...inputStyle, flex: 1 }, placeholder: "Role name", value: newName, onChange: (e) => setNewName(e.target.value) }),
|
|
667
|
+
/* @__PURE__ */ jsxRuntime.jsx("input", { style: { ...inputStyle, flex: 2 }, placeholder: "Description (optional)", value: newDesc, onChange: (e) => setNewDesc(e.target.value), onKeyDown: (e) => e.key === "Enter" && handleAdd() }),
|
|
668
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { style: btnPrimary, onClick: handleAdd, children: "Save" })
|
|
669
|
+
] }) }),
|
|
670
|
+
roles.map((role) => {
|
|
671
|
+
const assignedIds = getFieldIds(role);
|
|
672
|
+
const isEditing = editingRole === role.id;
|
|
673
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: cardStyle, children: [
|
|
674
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: isEditing ? 12 : 0 }, children: [
|
|
675
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
676
|
+
/* @__PURE__ */ jsxRuntime.jsx("strong", { style: { fontSize: 16 }, children: role.name }),
|
|
677
|
+
role.is_default && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { ...badgeGreen, marginLeft: 8 }, children: "default" }),
|
|
678
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: { ...badgeGray, marginLeft: 8 }, children: [
|
|
679
|
+
assignedIds.size,
|
|
680
|
+
" field",
|
|
681
|
+
assignedIds.size !== 1 ? "s" : ""
|
|
682
|
+
] }),
|
|
683
|
+
role.description && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 13, color: "#6b7280", marginTop: 2 }, children: role.description })
|
|
684
|
+
] }),
|
|
685
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: 8 }, children: [
|
|
686
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { style: btnSecondary, onClick: () => setEditingRole(isEditing ? null : role.id), children: isEditing ? "Done" : "Edit fields" }),
|
|
687
|
+
!role.is_default && /* @__PURE__ */ jsxRuntime.jsx("button", { style: { ...btnDanger, padding: "6px 12px", fontSize: 12 }, onClick: () => handleDelete(role.id), children: "Delete" })
|
|
688
|
+
] })
|
|
689
|
+
] }),
|
|
690
|
+
isEditing && fields.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(240px, 1fr))", gap: 4 }, children: fields.filter((f) => f.is_active).map((f) => /* @__PURE__ */ jsxRuntime.jsxs("label", { style: { display: "flex", alignItems: "center", gap: 8, padding: "4px 0", fontSize: 13, cursor: "pointer" }, children: [
|
|
691
|
+
/* @__PURE__ */ jsxRuntime.jsx("input", { type: "checkbox", checked: assignedIds.has(f.id), onChange: () => handleToggleField(role, f.id), style: checkboxStyle }),
|
|
692
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: f.display_name || f.field_name }),
|
|
693
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: f.field_type === "metric" ? badgeStyle2 : badgeGray, children: f.field_type })
|
|
694
|
+
] }, f.id)) }),
|
|
695
|
+
isEditing && fields.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: emptyStyle2, children: "No curated fields defined yet. Add fields in the Fields tab first." })
|
|
696
|
+
] }, role.id);
|
|
697
|
+
}),
|
|
698
|
+
roles.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: emptyStyle2, children: "No roles defined." })
|
|
699
|
+
] });
|
|
700
|
+
}
|
|
701
|
+
function UsersTab() {
|
|
702
|
+
const { users, isLoading, error, assignUserRole, removeUserRole } = chunkZ5DR3TCI_cjs.useAdminUsers();
|
|
703
|
+
const { roles } = chunkZ5DR3TCI_cjs.useAdminRoles();
|
|
704
|
+
const [showAdd, setShowAdd] = react.useState(false);
|
|
705
|
+
const [newUserId, setNewUserId] = react.useState("");
|
|
706
|
+
const [newEmail, setNewEmail] = react.useState("");
|
|
707
|
+
const [newRoleId, setNewRoleId] = react.useState(0);
|
|
708
|
+
const [newIsAdmin, setNewIsAdmin] = react.useState(false);
|
|
709
|
+
const [actionError, setActionError] = react.useState(null);
|
|
710
|
+
const handleAdd = react.useCallback(async () => {
|
|
711
|
+
if (!newUserId.trim() || !newEmail.trim() || !newRoleId) return;
|
|
712
|
+
setActionError(null);
|
|
713
|
+
try {
|
|
714
|
+
await assignUserRole({ user_id: newUserId.trim(), email: newEmail.trim(), role_id: newRoleId, is_admin: newIsAdmin });
|
|
715
|
+
setNewUserId("");
|
|
716
|
+
setNewEmail("");
|
|
717
|
+
setNewIsAdmin(false);
|
|
718
|
+
setShowAdd(false);
|
|
719
|
+
} catch (err) {
|
|
720
|
+
setActionError(err instanceof Error ? err.message : "Failed to assign role");
|
|
721
|
+
}
|
|
722
|
+
}, [newUserId, newEmail, newRoleId, newIsAdmin, assignUserRole]);
|
|
723
|
+
const handleRemove = react.useCallback(async (u) => {
|
|
724
|
+
if (!confirm(`Remove ${u.email} from this role?`)) return;
|
|
725
|
+
try {
|
|
726
|
+
await removeUserRole({ user_id: u.user_id, role_id: u.role_id });
|
|
727
|
+
} catch (err) {
|
|
728
|
+
setActionError(err instanceof Error ? err.message : "Failed to remove");
|
|
729
|
+
}
|
|
730
|
+
}, [removeUserRole]);
|
|
731
|
+
const grouped = react.useMemo(() => {
|
|
732
|
+
const map = /* @__PURE__ */ new Map();
|
|
733
|
+
for (const u of users) {
|
|
734
|
+
const list = map.get(u.email) || [];
|
|
735
|
+
list.push(u);
|
|
736
|
+
map.set(u.email, list);
|
|
737
|
+
}
|
|
738
|
+
return map;
|
|
739
|
+
}, [users]);
|
|
740
|
+
if (isLoading) return /* @__PURE__ */ jsxRuntime.jsx("div", { style: emptyStyle2, children: "Loading users..." });
|
|
741
|
+
if (error) return /* @__PURE__ */ jsxRuntime.jsx("div", { style: errorBanner, children: error });
|
|
742
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
743
|
+
actionError && /* @__PURE__ */ jsxRuntime.jsx("div", { style: errorBanner, children: actionError }),
|
|
744
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 16 }, children: [
|
|
745
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: { fontSize: 14, color: "#6b7280" }, children: [
|
|
746
|
+
grouped.size,
|
|
747
|
+
" user",
|
|
748
|
+
grouped.size !== 1 ? "s" : "",
|
|
749
|
+
" with role assignments"
|
|
750
|
+
] }),
|
|
751
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { style: btnPrimary, onClick: () => setShowAdd(!showAdd), children: showAdd ? "Cancel" : "+ Assign user" })
|
|
752
|
+
] }),
|
|
753
|
+
showAdd && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: cardStyle, children: [
|
|
754
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr auto", gap: 8, marginBottom: 8 }, children: [
|
|
755
|
+
/* @__PURE__ */ jsxRuntime.jsx("input", { style: inputStyle, placeholder: "User UUID (from Supabase Auth)", value: newUserId, onChange: (e) => setNewUserId(e.target.value) }),
|
|
756
|
+
/* @__PURE__ */ jsxRuntime.jsx("input", { style: inputStyle, placeholder: "Email", value: newEmail, onChange: (e) => setNewEmail(e.target.value) }),
|
|
757
|
+
/* @__PURE__ */ jsxRuntime.jsxs("select", { style: selectStyle, value: newRoleId, onChange: (e) => setNewRoleId(Number(e.target.value)), children: [
|
|
758
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: 0, children: "Select role..." }),
|
|
759
|
+
roles.map((r) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: r.id, children: r.name }, r.id))
|
|
760
|
+
] })
|
|
761
|
+
] }),
|
|
762
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [
|
|
763
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { style: { display: "flex", alignItems: "center", gap: 6, fontSize: 13, cursor: "pointer" }, children: [
|
|
764
|
+
/* @__PURE__ */ jsxRuntime.jsx("input", { type: "checkbox", checked: newIsAdmin, onChange: (e) => setNewIsAdmin(e.target.checked), style: checkboxStyle }),
|
|
765
|
+
"Admin access"
|
|
766
|
+
] }),
|
|
767
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { flex: 1 } }),
|
|
768
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { style: btnPrimary, onClick: handleAdd, children: "Assign" })
|
|
769
|
+
] })
|
|
770
|
+
] }),
|
|
771
|
+
Array.from(grouped.entries()).map(([email, assignments]) => /* @__PURE__ */ jsxRuntime.jsxs("div", { style: cardStyle, children: [
|
|
772
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
|
|
773
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
774
|
+
/* @__PURE__ */ jsxRuntime.jsx("strong", { style: { fontSize: 14 }, children: email }),
|
|
775
|
+
assignments.some((a) => a.is_admin) && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { ...badgeGreen, marginLeft: 8 }, children: "admin" })
|
|
776
|
+
] }),
|
|
777
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: { fontSize: 12, color: "#9ca3af", fontFamily: "monospace" }, children: [
|
|
778
|
+
assignments[0].user_id.slice(0, 8),
|
|
779
|
+
"..."
|
|
780
|
+
] })
|
|
781
|
+
] }),
|
|
782
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", gap: 6, marginTop: 8, flexWrap: "wrap" }, children: assignments.map((a) => /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { display: "inline-flex", alignItems: "center", gap: 4, ...badgeStyle2 }, children: [
|
|
783
|
+
a.access_roles?.name || `role #${a.role_id}`,
|
|
784
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
785
|
+
"button",
|
|
786
|
+
{
|
|
787
|
+
onClick: () => handleRemove(a),
|
|
788
|
+
style: { background: "none", border: "none", cursor: "pointer", color: "#6b7280", fontSize: 14, padding: 0, lineHeight: 1 },
|
|
789
|
+
title: "Remove role",
|
|
790
|
+
children: "\xD7"
|
|
791
|
+
}
|
|
792
|
+
)
|
|
793
|
+
] }, a.id)) })
|
|
794
|
+
] }, email)),
|
|
795
|
+
grouped.size === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: emptyStyle2, children: "No user role assignments yet. Users without an explicit role get the default role's access." })
|
|
796
|
+
] });
|
|
797
|
+
}
|
|
798
|
+
function AdminDashboard({ className }) {
|
|
799
|
+
const { isAuthenticated, isLoading: authLoading } = chunkZ5DR3TCI_cjs.useAuth();
|
|
800
|
+
const [tab, setTab] = react.useState("fields");
|
|
801
|
+
const [initError, setInitError] = react.useState(null);
|
|
802
|
+
if (authLoading) return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { ...rootStyle2, ...emptyStyle2 }, children: "Loading..." });
|
|
803
|
+
if (!isAuthenticated) return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { ...rootStyle2, ...emptyStyle2 }, children: "Sign in to access the admin dashboard." });
|
|
804
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: rootStyle2, className, children: [
|
|
805
|
+
/* @__PURE__ */ jsxRuntime.jsx("h1", { style: headingStyle2, children: "Semantic Layer Admin" }),
|
|
806
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { style: subStyle2, children: "Manage curated fields, roles, and user access" }),
|
|
807
|
+
initError && /* @__PURE__ */ jsxRuntime.jsx("div", { style: errorBanner, children: initError }),
|
|
808
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: tabBarStyle, children: ["fields", "roles", "users"].map((t) => /* @__PURE__ */ jsxRuntime.jsx("button", { style: tab === t ? tabActive : tabBase, onClick: () => {
|
|
809
|
+
setTab(t);
|
|
810
|
+
setInitError(null);
|
|
811
|
+
}, children: t.charAt(0).toUpperCase() + t.slice(1) }, t)) }),
|
|
812
|
+
tab === "fields" && /* @__PURE__ */ jsxRuntime.jsx(FieldsTab, {}),
|
|
813
|
+
tab === "roles" && /* @__PURE__ */ jsxRuntime.jsx(RolesTab, {}),
|
|
814
|
+
tab === "users" && /* @__PURE__ */ jsxRuntime.jsx(UsersTab, {})
|
|
815
|
+
] });
|
|
816
|
+
}
|
|
194
817
|
|
|
818
|
+
exports.AdminDashboard = AdminDashboard;
|
|
819
|
+
exports.DataCatalog = DataCatalog;
|
|
195
820
|
exports.MetricPicker = MetricPicker;
|
|
196
821
|
exports.ResultsTable = ResultsTable;
|
|
197
822
|
//# sourceMappingURL=components.cjs.map
|