@burdenoff/microfe-bigconsole 2026.804.2 → 2026.805.2

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.
Files changed (53) hide show
  1. package/dist/bigconsole/AdminRoot.js +21 -16
  2. package/dist/bigconsole/AdminRoot.js.map +1 -1
  3. package/dist/bigconsole/BigConsoleRoot.js +44 -39
  4. package/dist/bigconsole/BigConsoleRoot.js.map +1 -1
  5. package/dist/bigconsole/components/dashboard/DashboardToolbar.js +115 -100
  6. package/dist/bigconsole/components/dashboard/DashboardToolbar.js.map +1 -1
  7. package/dist/bigconsole/components/dashboard/PageTabsManager/PageTabsManager.js +100 -98
  8. package/dist/bigconsole/components/dashboard/PageTabsManager/PageTabsManager.js.map +1 -1
  9. package/dist/bigconsole/components/dashboard/ShareDialog/EmbedTab.js +164 -161
  10. package/dist/bigconsole/components/dashboard/ShareDialog/EmbedTab.js.map +1 -1
  11. package/dist/bigconsole/components/datasink/DataSinkCard.js +20 -20
  12. package/dist/bigconsole/components/datasink/DataSinkCard.js.map +1 -1
  13. package/dist/bigconsole/components/datasink/ImportDataGuideDialog.js +216 -49
  14. package/dist/bigconsole/components/datasink/ImportDataGuideDialog.js.map +1 -1
  15. package/dist/bigconsole/components/widgets/ActionConfigDialog.js +96 -90
  16. package/dist/bigconsole/components/widgets/ActionConfigDialog.js.map +1 -1
  17. package/dist/bigconsole/components/widgets/WidgetMenu.js +87 -76
  18. package/dist/bigconsole/components/widgets/WidgetMenu.js.map +1 -1
  19. package/dist/bigconsole/components/widgets/widget-actions/WidgetActions.js +120 -118
  20. package/dist/bigconsole/components/widgets/widget-actions/WidgetActions.js.map +1 -1
  21. package/dist/bigconsole/pages/DashboardBuilderPage.js +113 -104
  22. package/dist/bigconsole/pages/DashboardBuilderPage.js.map +1 -1
  23. package/dist/bigconsole/pages/DashboardViewPage.js +208 -199
  24. package/dist/bigconsole/pages/DashboardViewPage.js.map +1 -1
  25. package/dist/bigconsole/pages/DashboardsPage.js +376 -325
  26. package/dist/bigconsole/pages/DashboardsPage.js.map +1 -1
  27. package/dist/bigconsole/pages/DataParsersPage.js +135 -125
  28. package/dist/bigconsole/pages/DataParsersPage.js.map +1 -1
  29. package/dist/bigconsole/pages/DataSinkBuilderPage.js +182 -172
  30. package/dist/bigconsole/pages/DataSinkBuilderPage.js.map +1 -1
  31. package/dist/bigconsole/pages/DataSinkViewPage.js +233 -198
  32. package/dist/bigconsole/pages/DataSinkViewPage.js.map +1 -1
  33. package/dist/bigconsole/pages/DataSinksPage.js +281 -268
  34. package/dist/bigconsole/pages/DataSinksPage.js.map +1 -1
  35. package/dist/bigconsole/pages/ParserBuilderPage.js +238 -223
  36. package/dist/bigconsole/pages/ParserBuilderPage.js.map +1 -1
  37. package/dist/bigconsole/pages/ParserViewPage.js +162 -144
  38. package/dist/bigconsole/pages/ParserViewPage.js.map +1 -1
  39. package/dist/bigconsole/pages/PipelineBuilderPage.js +212 -204
  40. package/dist/bigconsole/pages/PipelineBuilderPage.js.map +1 -1
  41. package/dist/bigconsole/pages/PipelineViewPage.js +191 -183
  42. package/dist/bigconsole/pages/PipelineViewPage.js.map +1 -1
  43. package/dist/bigconsole/pages/PipelinesPage.js +128 -103
  44. package/dist/bigconsole/pages/PipelinesPage.js.map +1 -1
  45. package/dist/bigconsole/pages/WorkflowViewPage.js +238 -217
  46. package/dist/bigconsole/pages/WorkflowViewPage.js.map +1 -1
  47. package/dist/bigconsole/pages/WorkflowsPage.js +116 -102
  48. package/dist/bigconsole/pages/WorkflowsPage.js.map +1 -1
  49. package/dist/bigconsole/utils/csv.js +91 -0
  50. package/dist/bigconsole/utils/csv.js.map +1 -0
  51. package/dist/constants/permissions.js +83 -0
  52. package/dist/constants/permissions.js.map +1 -0
  53. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"ImportDataGuideDialog.js","names":[],"sources":["../../../../src/bigconsole/components/datasink/ImportDataGuideDialog.tsx"],"sourcesContent":["/**\n * Guides a user on how to import data into a DataSink (via a workflow) and\n * navigates them to the Workflows page. Named to avoid confusion with\n * ImportDataSinkDialog, which imports a DataSink config from JSON.\n */\n\nimport { type FC, memo } from 'react';\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n Button,\n} from '@burdenoff/fe-libs/ui';\nimport { Upload, Workflow, ArrowRight } from 'lucide-react';\n\nexport interface ImportDataGuideDialogProps {\n /** Whether dialog is open */\n isOpen: boolean;\n /** DataSink name for context */\n dataSinkName?: string;\n /** Callback when dialog is closed */\n onClose: () => void;\n /** Callback when the user chooses to go to the Workflows page */\n onGoToWorkflows: () => void;\n}\n\nconst STEPS = [\n 'Go to the Workflows page and create a new workflow.',\n 'Add a source node to fetch your data, then a node that writes to this data sink.',\n 'Run the workflow — the imported data appears here in the data preview.',\n];\n\nexport const ImportDataGuideDialog: FC<ImportDataGuideDialogProps> = memo(function ImportDataGuideDialog({\n isOpen,\n dataSinkName,\n onClose,\n onGoToWorkflows,\n}) {\n return (\n <Dialog open={isOpen} onOpenChange={(open) => !open && onClose()}>\n <DialogContent className=\"sm:max-w-lg\">\n <DialogHeader>\n <div className=\"flex items-center gap-3\">\n <div className=\"flex size-10 items-center justify-center rounded-lg bg-action-primary-bg/10\">\n <Upload className=\"size-5 text-action-primary-bg\" />\n </div>\n <DialogTitle>Import data</DialogTitle>\n </div>\n <DialogDescription>\n {dataSinkName ? `Populate “${dataSinkName}” with a workflow` : 'Populate this data sink with a workflow'}\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"py-2 space-y-4\">\n <p className=\"text-sm text-text-primary leading-relaxed\">\n Data is imported into a data sink by building a <strong>workflow</strong>. A workflow fetches data from your\n source (an API, database, file, or app) and writes it into this data sink so your dashboards can read it.\n </p>\n\n <ol className=\"space-y-3\">\n {STEPS.map((step, index) => (\n <li key={index} className=\"flex items-start gap-3\">\n <span className=\"flex size-6 shrink-0 items-center justify-center rounded-full bg-bg-sunken text-xs font-semibold text-text-primary\">\n {index + 1}\n </span>\n <p className=\"text-sm text-text-secondary leading-relaxed\">{step}</p>\n </li>\n ))}\n </ol>\n </div>\n\n <DialogFooter>\n <Button variant=\"outline\" onClick={onClose}>\n Cancel\n </Button>\n <Button onClick={onGoToWorkflows}>\n <Workflow className=\"size-4\" />\n Go to Workflows\n <ArrowRight className=\"size-4\" />\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n );\n});\n\nexport default ImportDataGuideDialog;\n"],"mappings":";;;;;AA6BA,IAAM,IAAQ;CACZ;CACA;CACA;CACD,EAEY,IAAwD,EAAK,SAA+B,EACvG,WACA,iBACA,YACA,sBACC;AACD,QACE,kBAAC,GAAD;EAAQ,MAAM;EAAQ,eAAe,MAAS,CAAC,KAAQ,GAAS;YAC9D,kBAAC,GAAD;GAAe,WAAU;aAAzB;IACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,GAAD,EAAQ,WAAU,iCAAkC,CAAA;MAChD,CAAA,EACN,kBAAC,GAAD,EAAA,UAAa,eAAyB,CAAA,CAClC;QACN,kBAAC,GAAD,EAAA,UACG,IAAe,aAAa,EAAa,qBAAqB,2CAC7C,CAAA,CACP,EAAA,CAAA;IAEf,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,KAAD;MAAG,WAAU;gBAAb;OAAyD;OACP,kBAAC,UAAD,EAAA,UAAQ,YAAiB,CAAA;;OAEvE;SAEJ,kBAAC,MAAD;MAAI,WAAU;gBACX,EAAM,KAAK,GAAM,MAChB,kBAAC,MAAD;OAAgB,WAAU;iBAA1B,CACE,kBAAC,QAAD;QAAM,WAAU;kBACb,IAAQ;QACJ,CAAA,EACP,kBAAC,KAAD;QAAG,WAAU;kBAA+C;QAAS,CAAA,CAClE;SALI,EAKJ,CACL;MACC,CAAA,CACD;;IAEN,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;KAAQ,SAAQ;KAAU,SAAS;eAAS;KAEnC,CAAA,EACT,kBAAC,GAAD;KAAQ,SAAS;eAAjB;MACE,kBAAC,GAAD,EAAU,WAAU,UAAW,CAAA;;MAE/B,kBAAC,GAAD,EAAY,WAAU,UAAW,CAAA;MAC1B;OACI,EAAA,CAAA;IACD;;EACT,CAAA;EAEX"}
1
+ {"version":3,"file":"ImportDataGuideDialog.js","names":[],"sources":["../../../../src/bigconsole/components/datasink/ImportDataGuideDialog.tsx"],"sourcesContent":["/**\n * Import data into a DataSink. Offers two methods:\n * 1. Build a workflow — a repeatable, scheduled pipeline (the primary path).\n * 2. Upload a CSV file directly (parsed client-side, written to the sink) —\n * the quickest path for one-off or small datasets.\n *\n * Named to avoid confusion with ImportDataSinkDialog, which imports a DataSink\n * *config* from JSON.\n */\n\nimport { type ChangeEvent, type FC, memo, useCallback, useEffect, useRef, useState } from 'react';\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n Button,\n} from '@burdenoff/fe-libs/ui';\nimport { Upload, Workflow, ArrowRight, FileUp, Loader2, AlertTriangle } from 'lucide-react';\n\nimport { parseCsv, type ParsedCsv } from '../../utils';\n\nexport interface ImportDataGuideDialogProps {\n /** Whether dialog is open */\n isOpen: boolean;\n /** DataSink name for context */\n dataSinkName?: string;\n /** Whether the sink already holds data — a CSV import would replace it. */\n hasExistingData?: boolean;\n /** Callback when dialog is closed */\n onClose: () => void;\n /** Callback when the user chooses to go to the Workflows page */\n onGoToWorkflows: () => void;\n /**\n * When provided, enables the direct CSV upload method. Receives the parsed\n * rows and should persist them to the DataSink. Resolves true on success\n * (the dialog then closes) or false on a handled failure.\n */\n onImportCsv?: (rows: Record<string, unknown>[]) => Promise<boolean>;\n}\n\nconst MAX_PREVIEW_COLUMNS = 6;\n\n/** Guard against reading a huge file fully into memory (~3-4x its size). */\nconst MAX_CSV_BYTES = 10_000_000; // 10 MB\n\n/** Cap rows so a single updateDataSink payload stays a sane size. */\nconst MAX_CSV_ROWS = 50_000;\n\nexport const ImportDataGuideDialog: FC<ImportDataGuideDialogProps> = memo(function ImportDataGuideDialog({\n isOpen,\n dataSinkName,\n hasExistingData,\n onClose,\n onGoToWorkflows,\n onImportCsv,\n}) {\n const fileInputRef = useRef<HTMLInputElement>(null);\n // Monotonic token for the in-flight file read; bumped on every new selection\n // or reset so a slow read that resolves late can detect it was superseded.\n const readSeqRef = useRef(0);\n const [fileName, setFileName] = useState<string | null>(null);\n const [parsed, setParsed] = useState<ParsedCsv | null>(null);\n const [parseError, setParseError] = useState<string | null>(null);\n const [importError, setImportError] = useState<string | null>(null);\n const [isImporting, setIsImporting] = useState(false);\n\n const resetUploadState = useCallback(() => {\n readSeqRef.current += 1; // invalidate any in-flight file read\n setFileName(null);\n setParsed(null);\n setParseError(null);\n setImportError(null);\n setIsImporting(false);\n }, []);\n\n // Clear any prior selection whenever the dialog is (re)opened or closed.\n useEffect(() => {\n if (!isOpen) resetUploadState();\n }, [isOpen, resetUploadState]);\n\n const handleFileChange = useCallback(async (event: ChangeEvent<HTMLInputElement>) => {\n const file = event.target.files?.[0];\n // Reset the input so selecting the same file again re-triggers onChange.\n event.target.value = '';\n if (!file) return;\n\n const seq = (readSeqRef.current += 1);\n setParsed(null);\n setParseError(null);\n setImportError(null);\n setFileName(file.name);\n\n if (file.size > MAX_CSV_BYTES) {\n setParseError('This CSV is larger than 10 MB. Import large datasets with a workflow instead.');\n return;\n }\n\n try {\n const text = await file.text();\n if (seq !== readSeqRef.current) return; // superseded by a newer selection/close\n const result = parseCsv(text);\n if (result.rows.length > MAX_CSV_ROWS) {\n setParseError(\n `This CSV has ${result.rows.length.toLocaleString()} rows (limit ${MAX_CSV_ROWS.toLocaleString()}). Import large datasets with a workflow instead.`\n );\n return;\n }\n setParsed(result);\n } catch (err) {\n if (seq !== readSeqRef.current) return;\n setParsed(null);\n setParseError(err instanceof Error ? err.message : 'Failed to parse the CSV file.');\n }\n }, []);\n\n const handleConfirmImport = useCallback(async () => {\n if (!parsed || !onImportCsv) return;\n setIsImporting(true);\n setImportError(null);\n try {\n const ok = await onImportCsv(parsed.rows);\n if (ok) {\n onClose();\n } else {\n setImportError('Import failed. Please try again.');\n }\n } catch (err) {\n setImportError(err instanceof Error ? err.message : 'Import failed. Please try again.');\n } finally {\n setIsImporting(false);\n }\n }, [parsed, onImportCsv, onClose]);\n\n const openFilePicker = useCallback(() => fileInputRef.current?.click(), []);\n\n const previewColumns = parsed?.columns.slice(0, MAX_PREVIEW_COLUMNS) ?? [];\n const extraColumns = parsed ? parsed.columns.length - previewColumns.length : 0;\n\n return (\n <Dialog open={isOpen} onOpenChange={(open) => !open && !isImporting && onClose()}>\n <DialogContent className=\"sm:max-w-lg\">\n <DialogHeader>\n <div className=\"flex items-center gap-3\">\n <div className=\"flex size-10 items-center justify-center rounded-lg bg-action-primary-bg/10\">\n <Upload className=\"size-5 text-action-primary-bg\" />\n </div>\n <DialogTitle>Import data</DialogTitle>\n </div>\n <DialogDescription>\n {dataSinkName ? `Add data to “${dataSinkName}”` : 'Add data to this data sink'}\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"py-2 space-y-5\">\n <section className=\"space-y-3\">\n <div>\n <h3 className=\"text-sm font-semibold text-text-primary\">Build a workflow</h3>\n <p className=\"text-sm text-text-secondary leading-relaxed\">\n The recommended way to keep this data sink up to date — build a repeatable, scheduled pipeline that\n fetches from your source (an API, database, or app) and writes into this data sink on every run.\n </p>\n </div>\n <Button variant=\"default\" onClick={onGoToWorkflows} disabled={isImporting} className=\"w-full\">\n <Workflow className=\"size-4\" />\n Go to Workflows\n <ArrowRight className=\"size-4\" />\n </Button>\n </section>\n\n {onImportCsv && (\n <div className=\"flex items-center gap-3\">\n <span className=\"h-px flex-1 bg-border-subtle\" />\n <span className=\"text-xs font-medium uppercase tracking-wide text-text-tertiary\">Or</span>\n <span className=\"h-px flex-1 bg-border-subtle\" />\n </div>\n )}\n\n {onImportCsv && (\n <section className=\"space-y-3\">\n <div>\n <h3 className=\"text-sm font-semibold text-text-primary\">Upload a CSV file</h3>\n <p className=\"text-sm text-text-secondary leading-relaxed\">\n For a quick, one-off import, upload a spreadsheet export and it becomes available to your dashboards\n right away.\n </p>\n </div>\n\n {hasExistingData && (\n <div className=\"flex items-start gap-2 rounded-lg border border-status-warning-border bg-status-warning-bg px-3 py-2\">\n <AlertTriangle className=\"size-4 shrink-0 text-status-warning-text mt-0.5\" />\n <p className=\"text-sm text-status-warning-text\">\n This data sink already has data — importing a CSV will replace it.\n </p>\n </div>\n )}\n\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\".csv,text/csv\"\n className=\"hidden\"\n onChange={handleFileChange}\n aria-label=\"Choose a CSV file to import\"\n />\n\n {!parsed && (\n <button\n type=\"button\"\n onClick={openFilePicker}\n className=\"flex w-full flex-col items-center justify-center gap-2 rounded-lg border border-dashed border-border-default bg-bg-sunken px-4 py-6 text-center transition-colors hover:border-action-primary-bg hover:bg-action-primary-bg/5\"\n >\n <FileUp className=\"size-6 text-text-tertiary\" />\n <span className=\"text-sm font-medium text-text-primary\">\n {fileName ? 'Choose a different CSV file' : 'Choose a CSV file'}\n </span>\n <span className=\"text-xs text-text-tertiary\">The first row is used as column names.</span>\n </button>\n )}\n\n {parseError && (\n <div className=\"rounded-lg border border-status-error-border bg-status-error-bg px-3 py-2\">\n <p className=\"text-sm text-status-error-text\">{parseError}</p>\n </div>\n )}\n\n {parsed && (\n <div className=\"space-y-3 rounded-lg border border-border-default bg-bg-sunken p-4\">\n <div className=\"flex items-center justify-between gap-3\">\n <span className=\"truncate text-sm font-medium text-text-primary\" title={fileName ?? undefined}>\n {fileName}\n </span>\n <button\n type=\"button\"\n onClick={openFilePicker}\n disabled={isImporting}\n className=\"shrink-0 text-xs font-medium text-action-primary-bg hover:underline disabled:cursor-not-allowed disabled:opacity-50 disabled:no-underline\"\n >\n Change file\n </button>\n </div>\n <p className=\"text-sm text-text-secondary\">\n Ready to import <strong className=\"text-text-primary\">{parsed.rows.length}</strong>{' '}\n {parsed.rows.length === 1 ? 'row' : 'rows'} ×{' '}\n <strong className=\"text-text-primary\">{parsed.columns.length}</strong>{' '}\n {parsed.columns.length === 1 ? 'column' : 'columns'}.\n </p>\n <div className=\"flex flex-wrap gap-1.5\">\n {previewColumns.map((col) => (\n <span\n key={col}\n className=\"rounded-full bg-bg-surface px-2 py-0.5 text-xs text-text-secondary border border-border-subtle\"\n >\n {col}\n </span>\n ))}\n {extraColumns > 0 && (\n <span className=\"rounded-full px-2 py-0.5 text-xs text-text-tertiary\">+{extraColumns} more</span>\n )}\n </div>\n\n {importError && <p className=\"text-sm text-status-error-text\">{importError}</p>}\n\n <Button onClick={handleConfirmImport} disabled={isImporting} className=\"w-full\">\n {isImporting ? (\n <>\n <Loader2 className=\"size-4 animate-spin\" />\n Importing…\n </>\n ) : (\n <>\n <Upload className=\"size-4\" />\n Import {parsed.rows.length} {parsed.rows.length === 1 ? 'row' : 'rows'}\n </>\n )}\n </Button>\n </div>\n )}\n </section>\n )}\n </div>\n\n <DialogFooter>\n <Button variant=\"outline\" onClick={onClose} disabled={isImporting}>\n Cancel\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n );\n});\n\nexport default ImportDataGuideDialog;\n"],"mappings":"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"}
@@ -1,9 +1,11 @@
1
- import { memo as e, useCallback as t, useEffect as n, useRef as r, useState as i } from "react";
2
- import { ChevronDown as ee, ChevronRight as te, Pencil as ne, Plus as re, Zap as ie } from "lucide-react";
3
- import { Button as ae, Checkbox as a, Dialog as oe, DialogContent as se, DialogDescription as ce, DialogFooter as le, DialogHeader as ue, DialogTitle as de, Input as o, Select as s, SelectContent as c, SelectItem as l, SelectTrigger as u, SelectValue as d, Spinner as fe, Textarea as pe } from "@burdenoff/fe-libs/ui";
1
+ import { BIGCONSOLE_PERMISSIONS as e } from "../../../constants/permissions.js";
2
+ import { memo as t, useCallback as n, useEffect as r, useRef as i, useState as a } from "react";
3
+ import { PermissionButton as ee } from "@burdenoff/fe-libs/shared/components";
4
+ import { ChevronDown as te, ChevronRight as ne, Pencil as re, Plus as ie, Zap as ae } from "lucide-react";
5
+ import { Button as oe, Checkbox as se, Dialog as ce, DialogContent as le, DialogDescription as ue, DialogFooter as de, DialogHeader as fe, DialogTitle as pe, Input as o, Select as s, SelectContent as c, SelectItem as l, SelectTrigger as u, SelectValue as d, Spinner as me, Textarea as he } from "@burdenoff/fe-libs/ui";
4
6
  import { jsx as f, jsxs as p } from "react/jsx-runtime";
5
7
  //#region src/bigconsole/components/widgets/ActionConfigDialog.tsx
6
- var me = [{
8
+ var ge = [{
7
9
  value: "WEBHOOK",
8
10
  label: "Call a webhook / my API",
9
11
  hint: "Sends an HTTP request to the URL below every time the button is clicked."
@@ -11,13 +13,13 @@ var me = [{
11
13
  value: "EMIT",
12
14
  label: "Just emit an event (advanced)",
13
15
  hint: "Emits widget:<name>:clicked. Wire it up yourself in the Webhooks/Events section."
14
- }], he = [
16
+ }], _e = [
15
17
  "POST",
16
18
  "GET",
17
19
  "PUT",
18
20
  "PATCH",
19
21
  "DELETE"
20
- ], ge = [
22
+ ], ve = [
21
23
  {
22
24
  value: "PRIMARY",
23
25
  label: "Primary",
@@ -43,7 +45,7 @@ var me = [{
43
45
  label: "Danger",
44
46
  color: "var(--color-action-danger-bg)"
45
47
  }
46
- ], _e = [
48
+ ], ye = [
47
49
  {
48
50
  value: "",
49
51
  label: "No icon"
@@ -120,19 +122,19 @@ var h = {
120
122
  border: "1px solid var(--color-border)",
121
123
  boxShadow: "var(--shadow-elevation-3)",
122
124
  borderRadius: "var(--radius-button)"
123
- }, v = e(function({ isOpen: e, action: v, initialWebhook: y, isLoading: b = !1, saveError: ve, onClose: ye, onSave: be }) {
124
- let x = !!v, S = r(null), C = r(!1), [w, T] = i(""), [E, D] = i(""), [O, k] = i(!1), [A, j] = i("PRIMARY"), [M, N] = i(""), [P, F] = i("WEBHOOK"), [I, L] = i(""), [R, z] = i("POST"), [B, V] = i(!1), [H, U] = i(!1), [xe, Se] = i(!1), [W, G] = i(!1), [K, q] = i("Confirm Action"), [J, Y] = i("Are you sure you want to proceed?"), [Ce, X] = i("Confirm"), [we, Z] = i("Cancel"), [Q, $] = i(null);
125
- n(() => {
126
- if (!e) return;
127
- C.current = !1, L(""), z("POST"), v ? (T(v.label), D(v.name), k(!1), j(v.style), N(v.icon || ""), V(v.disabled), U(v.hidden), F("EMIT"), G(!!v.confirmation), v.confirmation ? (q(v.confirmation.title), Y(v.confirmation.message), X(v.confirmation.confirmLabel || "Confirm"), Z(v.confirmation.cancelLabel || "Cancel")) : (q("Confirm Action"), Y("Are you sure you want to proceed?"), X("Confirm"), Z("Cancel"))) : (T(""), D(""), k(!1), j("PRIMARY"), N(""), F("WEBHOOK"), V(!1), U(!1), G(!1), q("Confirm Action"), Y("Are you sure you want to proceed?"), X("Confirm"), Z("Cancel")), Se(!1), $(null);
128
- let t = requestAnimationFrame(() => requestAnimationFrame(() => S.current?.focus()));
129
- return () => cancelAnimationFrame(t);
130
- }, [e, v]), n(() => {
131
- !e || !y || C.current || (F("WEBHOOK"), L(y.url), z(y.method));
132
- }, [e, y]);
133
- let Te = t((e) => {
125
+ }, v = t(function({ isOpen: t, action: v, initialWebhook: y, isLoading: b = !1, saveError: be, onClose: xe, onSave: Se }) {
126
+ let x = !!v, S = i(null), C = i(!1), [w, T] = a(""), [E, D] = a(""), [O, k] = a(!1), [A, j] = a("PRIMARY"), [M, N] = a(""), [P, F] = a("WEBHOOK"), [I, L] = a(""), [R, z] = a("POST"), [B, V] = a(!1), [H, U] = a(!1), [Ce, we] = a(!1), [W, G] = a(!1), [Te, K] = a("Confirm Action"), [Ee, q] = a("Are you sure you want to proceed?"), [J, Y] = a("Confirm"), [X, Z] = a("Cancel"), [Q, $] = a(null);
127
+ r(() => {
128
+ if (!t) return;
129
+ C.current = !1, L(""), z("POST"), v ? (T(v.label), D(v.name), k(!1), j(v.style), N(v.icon || ""), V(v.disabled), U(v.hidden), F("EMIT"), G(!!v.confirmation), v.confirmation ? (K(v.confirmation.title), q(v.confirmation.message), Y(v.confirmation.confirmLabel || "Confirm"), Z(v.confirmation.cancelLabel || "Cancel")) : (K("Confirm Action"), q("Are you sure you want to proceed?"), Y("Confirm"), Z("Cancel"))) : (T(""), D(""), k(!1), j("PRIMARY"), N(""), F("WEBHOOK"), V(!1), U(!1), G(!1), K("Confirm Action"), q("Are you sure you want to proceed?"), Y("Confirm"), Z("Cancel")), we(!1), $(null);
130
+ let e = requestAnimationFrame(() => requestAnimationFrame(() => S.current?.focus()));
131
+ return () => cancelAnimationFrame(e);
132
+ }, [t, v]), r(() => {
133
+ !t || !y || C.current || (F("WEBHOOK"), L(y.url), z(y.method));
134
+ }, [t, y]);
135
+ let De = n((e) => {
134
136
  T(e), O || D(m(e)), Q && $(null);
135
- }, [O, Q]), Ee = t((e) => {
137
+ }, [O, Q]), Oe = n((e) => {
136
138
  e.preventDefault();
137
139
  let t = w.trim();
138
140
  if (!t) {
@@ -156,15 +158,15 @@ var h = {
156
158
  }
157
159
  }
158
160
  let r = W ? {
159
- title: K.trim() || "Confirm Action",
160
- message: J.trim() || "Are you sure?",
161
- confirmLabel: Ce.trim() || "Confirm",
162
- cancelLabel: we.trim() || "Cancel"
161
+ title: Te.trim() || "Confirm Action",
162
+ message: Ee.trim() || "Are you sure?",
163
+ confirmLabel: J.trim() || "Confirm",
164
+ cancelLabel: X.trim() || "Cancel"
163
165
  } : void 0, i = P === "WEBHOOK" ? {
164
166
  url: I.trim(),
165
167
  method: R
166
168
  } : null;
167
- be(x && v ? {
169
+ Se(x && v ? {
168
170
  id: v.id,
169
171
  name: n,
170
172
  label: t,
@@ -196,23 +198,23 @@ var h = {
196
198
  B,
197
199
  H,
198
200
  W,
199
- K,
201
+ Te,
202
+ Ee,
200
203
  J,
201
- Ce,
202
- we,
204
+ X,
203
205
  x,
204
206
  v,
205
- be
206
- ]), De = (e) => ge.find((t) => t.value === e)?.color || "var(--color-action-primary-bg)", Oe = me.find((e) => e.value === P);
207
- return /* @__PURE__ */ f(oe, {
208
- open: e,
209
- onOpenChange: (e) => !e && !b && ye(),
210
- children: /* @__PURE__ */ p(se, {
207
+ Se
208
+ ]), ke = (e) => ve.find((t) => t.value === e)?.color || "var(--color-action-primary-bg)", Ae = ge.find((e) => e.value === P);
209
+ return /* @__PURE__ */ f(ce, {
210
+ open: t,
211
+ onOpenChange: (e) => !e && !b && xe(),
212
+ children: /* @__PURE__ */ p(le, {
211
213
  style: {
212
214
  maxWidth: "500px",
213
215
  padding: 0
214
216
  },
215
- children: [/* @__PURE__ */ f(ue, {
217
+ children: [/* @__PURE__ */ f(fe, {
216
218
  style: { padding: "var(--space-pagePadding) var(--space-pagePadding) 0" },
217
219
  children: /* @__PURE__ */ p("div", {
218
220
  style: {
@@ -231,12 +233,12 @@ var h = {
231
233
  backgroundColor: "var(--color-action-primary-bg)",
232
234
  boxShadow: "var(--shadow-elevation-2)"
233
235
  },
234
- children: f(x ? ne : ie, { style: {
236
+ children: f(x ? re : ae, { style: {
235
237
  height: "var(--size-icon-lg)",
236
238
  width: "var(--size-icon-lg)",
237
239
  color: "var(--color-action-primary-text)"
238
240
  } })
239
- }), /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f(de, {
241
+ }), /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f(pe, {
240
242
  style: {
241
243
  fontSize: "var(--font-size-heading-h4)",
242
244
  fontWeight: "var(--font-weight-bold)",
@@ -244,7 +246,7 @@ var h = {
244
246
  margin: 0
245
247
  },
246
248
  children: x ? "Edit Button" : "Add Button"
247
- }), /* @__PURE__ */ f(ce, {
249
+ }), /* @__PURE__ */ f(ue, {
248
250
  style: {
249
251
  fontSize: "var(--font-size-body-sm)",
250
252
  color: "var(--color-text-secondary)",
@@ -254,7 +256,7 @@ var h = {
254
256
  })] })]
255
257
  })
256
258
  }), /* @__PURE__ */ p("form", {
257
- onSubmit: Ee,
259
+ onSubmit: Oe,
258
260
  children: [/* @__PURE__ */ p("div", {
259
261
  style: {
260
262
  padding: "var(--space-pagePadding)",
@@ -262,7 +264,7 @@ var h = {
262
264
  overflowY: "auto"
263
265
  },
264
266
  children: [
265
- (Q || ve) && /* @__PURE__ */ f("div", {
267
+ (Q || be) && /* @__PURE__ */ f("div", {
266
268
  style: {
267
269
  padding: "var(--space-controlGap)",
268
270
  backgroundColor: "var(--color-status-error-bgSubtle)",
@@ -276,7 +278,7 @@ var h = {
276
278
  color: "var(--color-status-error-text)",
277
279
  margin: 0
278
280
  },
279
- children: Q || ve
281
+ children: Q || be
280
282
  })
281
283
  }),
282
284
  /* @__PURE__ */ p("div", {
@@ -292,7 +294,7 @@ var h = {
292
294
  /* @__PURE__ */ f(o, {
293
295
  ref: S,
294
296
  value: w,
295
- onChange: (e) => Te(e.target.value),
297
+ onChange: (e) => De(e.target.value),
296
298
  placeholder: "e.g., Refresh Data, Export CSV",
297
299
  disabled: b,
298
300
  style: {
@@ -328,7 +330,7 @@ var h = {
328
330
  children: /* @__PURE__ */ f(d, {})
329
331
  }), /* @__PURE__ */ f(c, {
330
332
  style: _,
331
- children: ge.map((e) => /* @__PURE__ */ f(l, {
333
+ children: ve.map((e) => /* @__PURE__ */ f(l, {
332
334
  value: e.value,
333
335
  children: e.label
334
336
  }, e.value))
@@ -351,7 +353,7 @@ var h = {
351
353
  ..._,
352
354
  maxHeight: "200px"
353
355
  },
354
- children: _e.map((e) => /* @__PURE__ */ f(l, {
356
+ children: ye.map((e) => /* @__PURE__ */ f(l, {
355
357
  value: e.value || "none",
356
358
  children: e.label
357
359
  }, e.value || "none"))
@@ -381,7 +383,7 @@ var h = {
381
383
  fontSize: "var(--font-size-body-sm)",
382
384
  fontWeight: "var(--font-weight-medium)",
383
385
  borderRadius: "var(--radius-button)",
384
- backgroundColor: De(A),
386
+ backgroundColor: ke(A),
385
387
  color: "var(--color-action-primary-text)",
386
388
  border: "none",
387
389
  cursor: "default"
@@ -410,15 +412,15 @@ var h = {
410
412
  children: /* @__PURE__ */ f(d, {})
411
413
  }), /* @__PURE__ */ f(c, {
412
414
  style: _,
413
- children: me.map((e) => /* @__PURE__ */ f(l, {
415
+ children: ge.map((e) => /* @__PURE__ */ f(l, {
414
416
  value: e.value,
415
417
  children: e.label
416
418
  }, e.value))
417
419
  })]
418
420
  }),
419
- Oe && /* @__PURE__ */ f("p", {
421
+ Ae && /* @__PURE__ */ f("p", {
420
422
  style: g,
421
- children: Oe.hint
423
+ children: Ae.hint
422
424
  })
423
425
  ]
424
426
  }),
@@ -469,7 +471,7 @@ var h = {
469
471
  children: /* @__PURE__ */ f(d, {})
470
472
  }), /* @__PURE__ */ f(c, {
471
473
  style: _,
472
- children: he.map((e) => /* @__PURE__ */ f(l, {
474
+ children: _e.map((e) => /* @__PURE__ */ f(l, {
473
475
  value: e,
474
476
  children: e
475
477
  }, e))
@@ -509,7 +511,7 @@ var h = {
509
511
  cursor: "pointer",
510
512
  marginBottom: "var(--space-formGap)"
511
513
  },
512
- children: [/* @__PURE__ */ f(a, {
514
+ children: [/* @__PURE__ */ f(se, {
513
515
  checked: W,
514
516
  onCheckedChange: (e) => G(e === !0),
515
517
  disabled: b
@@ -540,8 +542,8 @@ var h = {
540
542
  },
541
543
  children: "Dialog Title"
542
544
  }), /* @__PURE__ */ f(o, {
543
- value: K,
544
- onChange: (e) => q(e.target.value),
545
+ value: Te,
546
+ onChange: (e) => K(e.target.value),
545
547
  disabled: b,
546
548
  style: {
547
549
  height: "var(--size-controlHeight-sm)",
@@ -557,9 +559,9 @@ var h = {
557
559
  marginBottom: "var(--space-controlGap)"
558
560
  },
559
561
  children: "Message"
560
- }), /* @__PURE__ */ f(pe, {
561
- value: J,
562
- onChange: (e) => Y(e.target.value),
562
+ }), /* @__PURE__ */ f(he, {
563
+ value: Ee,
564
+ onChange: (e) => q(e.target.value),
563
565
  rows: 2,
564
566
  disabled: b,
565
567
  style: {
@@ -583,8 +585,8 @@ var h = {
583
585
  },
584
586
  children: "Confirm Button"
585
587
  }), /* @__PURE__ */ f(o, {
586
- value: Ce,
587
- onChange: (e) => X(e.target.value),
588
+ value: J,
589
+ onChange: (e) => Y(e.target.value),
588
590
  disabled: b,
589
591
  style: {
590
592
  height: "var(--size-controlHeight-sm)",
@@ -600,7 +602,7 @@ var h = {
600
602
  },
601
603
  children: "Cancel Button"
602
604
  }), /* @__PURE__ */ f(o, {
603
- value: we,
605
+ value: X,
604
606
  onChange: (e) => Z(e.target.value),
605
607
  disabled: b,
606
608
  style: {
@@ -619,7 +621,7 @@ var h = {
619
621
  },
620
622
  children: [/* @__PURE__ */ p("button", {
621
623
  type: "button",
622
- onClick: () => Se((e) => !e),
624
+ onClick: () => we((e) => !e),
623
625
  style: {
624
626
  display: "flex",
625
627
  alignItems: "center",
@@ -632,11 +634,11 @@ var h = {
632
634
  fontWeight: "var(--font-weight-semibold)",
633
635
  color: "var(--color-text-primary)"
634
636
  },
635
- children: [f(xe ? ee : te, { style: {
637
+ children: [f(Ce ? te : ne, { style: {
636
638
  height: "14px",
637
639
  width: "14px"
638
640
  } }), "Advanced"]
639
- }), xe && /* @__PURE__ */ p("div", {
641
+ }), Ce && /* @__PURE__ */ p("div", {
640
642
  style: {
641
643
  marginTop: "var(--space-formGap)",
642
644
  display: "flex",
@@ -688,7 +690,7 @@ var h = {
688
690
  gap: "var(--space-controlGap)",
689
691
  cursor: "pointer"
690
692
  },
691
- children: [/* @__PURE__ */ f(a, {
693
+ children: [/* @__PURE__ */ f(se, {
692
694
  checked: B,
693
695
  onCheckedChange: (e) => V(e === !0),
694
696
  disabled: b
@@ -706,7 +708,7 @@ var h = {
706
708
  gap: "var(--space-controlGap)",
707
709
  cursor: "pointer"
708
710
  },
709
- children: [/* @__PURE__ */ f(a, {
711
+ children: [/* @__PURE__ */ f(se, {
710
712
  checked: H,
711
713
  onCheckedChange: (e) => U(e === !0),
712
714
  disabled: b
@@ -722,7 +724,7 @@ var h = {
722
724
  })]
723
725
  })
724
726
  ]
725
- }), /* @__PURE__ */ p(le, {
727
+ }), /* @__PURE__ */ p(de, {
726
728
  style: {
727
729
  padding: "var(--space-formGap) var(--space-pagePadding)",
728
730
  borderTop: "1px solid var(--color-border)",
@@ -731,40 +733,44 @@ var h = {
731
733
  justifyContent: "flex-end",
732
734
  gap: "var(--space-controlGap)"
733
735
  },
734
- children: [/* @__PURE__ */ f(ae, {
736
+ children: [/* @__PURE__ */ f(oe, {
735
737
  type: "button",
736
738
  variant: "outline",
737
- onClick: ye,
739
+ onClick: xe,
738
740
  disabled: b,
739
741
  style: { height: "var(--size-controlHeight-md)" },
740
742
  children: "Cancel"
741
- }), /* @__PURE__ */ f(ae, {
742
- type: "submit",
743
- disabled: b || !w.trim(),
744
- style: {
745
- height: "var(--size-controlHeight-md)",
746
- backgroundColor: "var(--color-action-primary-bg)"
747
- },
748
- children: b ? /* @__PURE__ */ p("span", {
749
- style: {
750
- display: "flex",
751
- alignItems: "center",
752
- gap: "var(--space-iconGap)"
753
- },
754
- children: [/* @__PURE__ */ f(fe, { style: {
755
- height: "var(--size-icon-sm)",
756
- width: "var(--size-icon-sm)"
757
- } }), "Saving..."]
758
- }) : /* @__PURE__ */ p("span", {
743
+ }), /* @__PURE__ */ f(ee, {
744
+ permission: x ? e.WIDGET_ACTION_UPDATE : e.WIDGET_ACTION_CREATE,
745
+ deniedBehavior: "disable",
746
+ children: /* @__PURE__ */ f(oe, {
747
+ type: "submit",
748
+ disabled: b || !w.trim(),
759
749
  style: {
760
- display: "flex",
761
- alignItems: "center",
762
- gap: "var(--space-iconGap)"
750
+ height: "var(--size-controlHeight-md)",
751
+ backgroundColor: "var(--color-action-primary-bg)"
763
752
  },
764
- children: [f(x ? ne : re, { style: {
765
- height: "var(--size-icon-sm)",
766
- width: "var(--size-icon-sm)"
767
- } }), x ? "Update Button" : "Add Button"]
753
+ children: b ? /* @__PURE__ */ p("span", {
754
+ style: {
755
+ display: "flex",
756
+ alignItems: "center",
757
+ gap: "var(--space-iconGap)"
758
+ },
759
+ children: [/* @__PURE__ */ f(me, { style: {
760
+ height: "var(--size-icon-sm)",
761
+ width: "var(--size-icon-sm)"
762
+ } }), "Saving..."]
763
+ }) : /* @__PURE__ */ p("span", {
764
+ style: {
765
+ display: "flex",
766
+ alignItems: "center",
767
+ gap: "var(--space-iconGap)"
768
+ },
769
+ children: [f(x ? re : ie, { style: {
770
+ height: "var(--size-icon-sm)",
771
+ width: "var(--size-icon-sm)"
772
+ } }), x ? "Update Button" : "Add Button"]
773
+ })
768
774
  })
769
775
  })]
770
776
  })]