@burdenoff/microfe-bigconsole 2026.825.1 → 2026.827.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/builder/inspector/LayoutSection.js +71 -0
- package/dist/bigconsole/components/builder/inspector/LayoutSection.js.map +1 -0
- package/dist/bigconsole/components/builder/inspector/index.js +1 -0
- package/dist/bigconsole/components/dashboard/DashboardCanvas.js +137 -121
- package/dist/bigconsole/components/dashboard/DashboardCanvas.js.map +1 -1
- package/dist/bigconsole/components/dashboard/ExportDashboardDialog.js +204 -93
- package/dist/bigconsole/components/dashboard/ExportDashboardDialog.js.map +1 -1
- package/dist/bigconsole/components/dashboard/ShareDialog/ShareDialog.js +259 -133
- package/dist/bigconsole/components/dashboard/ShareDialog/ShareDialog.js.map +1 -1
- package/dist/bigconsole/components/dashboard/StoreTemplatePicker.js +87 -39
- package/dist/bigconsole/components/dashboard/StoreTemplatePicker.js.map +1 -1
- package/dist/bigconsole/components/datasink/DataSinkCard.js +88 -68
- package/dist/bigconsole/components/datasink/DataSinkCard.js.map +1 -1
- package/dist/bigconsole/components/widgets/PropertiesPanel.js +213 -199
- package/dist/bigconsole/components/widgets/PropertiesPanel.js.map +1 -1
- package/dist/bigconsole/components/workflow/WorkflowCard.js +46 -27
- package/dist/bigconsole/components/workflow/WorkflowCard.js.map +1 -1
- package/dist/bigconsole/hooks/useDashboardOperations.js +74 -64
- package/dist/bigconsole/hooks/useDashboardOperations.js.map +1 -1
- package/dist/bigconsole/pages/DashboardBuilderPage.js +1 -1
- package/dist/bigconsole/pages/DashboardsPage.js +386 -316
- package/dist/bigconsole/pages/DashboardsPage.js.map +1 -1
- package/dist/bigconsole/pages/DataSinksPage.js +251 -206
- package/dist/bigconsole/pages/DataSinksPage.js.map +1 -1
- package/dist/bigconsole/pages/InsightsPage.js +646 -378
- package/dist/bigconsole/pages/InsightsPage.js.map +1 -1
- package/dist/bigconsole/pages/WorkflowsPage.js +153 -108
- package/dist/bigconsole/pages/WorkflowsPage.js.map +1 -1
- package/dist/bigconsole/utils/format.js +18 -0
- package/dist/bigconsole/utils/format.js.map +1 -0
- package/dist/bigconsole/utils/widgetPositioning.js +1 -1
- package/dist/generated/wspace-operations.js +1 -0
- package/dist/generated/wspace-operations.js.map +1 -1
- package/package.json +1 -1
|
@@ -65,25 +65,31 @@ var s = ({ className: e }) => /* @__PURE__ */ i("svg", {
|
|
|
65
65
|
strokeWidth: 2,
|
|
66
66
|
d: "M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
|
67
67
|
})]
|
|
68
|
-
}), f = n(function({ workflow: n, onView: f, onEdit: p, onDelete: m }) {
|
|
69
|
-
let
|
|
68
|
+
}), f = n(function({ workflow: n, onView: f, onEdit: p, onDelete: m, onRun: h, isRunning: g = !1 }) {
|
|
69
|
+
let _ = n.dataSinkLinks?.length ?? n.linkedDataSinkCount ?? 0, v = r((e) => {
|
|
70
70
|
if (!e) return "Never";
|
|
71
71
|
try {
|
|
72
72
|
return o(new Date(e), { addSuffix: !0 });
|
|
73
73
|
} catch {
|
|
74
74
|
return "Unknown";
|
|
75
75
|
}
|
|
76
|
-
}, []),
|
|
76
|
+
}, []), y = r(() => {
|
|
77
77
|
f?.(n.id);
|
|
78
|
-
}, [f, n.id]),
|
|
78
|
+
}, [f, n.id]), b = r((e) => {
|
|
79
79
|
e.stopPropagation(), p?.(n.id);
|
|
80
|
-
}, [p, n.id]),
|
|
80
|
+
}, [p, n.id]), x = r((e) => {
|
|
81
81
|
e.stopPropagation(), m?.(n.id);
|
|
82
|
-
}, [m, n.id]),
|
|
82
|
+
}, [m, n.id]), S = r((e) => {
|
|
83
|
+
e.stopPropagation(), !g && h?.(n.id);
|
|
84
|
+
}, [
|
|
85
|
+
g,
|
|
86
|
+
h,
|
|
87
|
+
n.id
|
|
88
|
+
]), C = r((e) => {
|
|
83
89
|
e.stopPropagation(), f?.(n.id);
|
|
84
90
|
}, [f, n.id]);
|
|
85
91
|
return /* @__PURE__ */ a("div", {
|
|
86
|
-
onClick:
|
|
92
|
+
onClick: y,
|
|
87
93
|
className: "min-w-0 cursor-pointer overflow-hidden rounded-card border border-[var(--color-border-subtle)] bg-bg-elevated motion-safe:transition-[box-shadow,border-color] focus-within:border-action-primary-bg hover:border-action-primary-bg hover:shadow-[var(--shadow-elevation-1)]",
|
|
88
94
|
children: [/* @__PURE__ */ a("div", {
|
|
89
95
|
className: "flex items-center justify-between gap-icon-gap border-b border-[var(--color-border-subtle)] bg-bg-sunken px-3 py-2",
|
|
@@ -108,7 +114,7 @@ var s = ({ className: e }) => /* @__PURE__ */ i("svg", {
|
|
|
108
114
|
className: "text-sm font-semibold text-text-primary",
|
|
109
115
|
children: /* @__PURE__ */ i("button", {
|
|
110
116
|
type: "button",
|
|
111
|
-
onClick:
|
|
117
|
+
onClick: C,
|
|
112
118
|
"aria-label": `Open workflow ${n.name}`,
|
|
113
119
|
className: `line-clamp-2 rounded-button text-left ${e}`,
|
|
114
120
|
children: n.name
|
|
@@ -119,21 +125,34 @@ var s = ({ className: e }) => /* @__PURE__ */ i("svg", {
|
|
|
119
125
|
})]
|
|
120
126
|
}), /* @__PURE__ */ a("div", {
|
|
121
127
|
className: "flex shrink-0 items-center gap-1",
|
|
122
|
-
children: [
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
128
|
+
children: [
|
|
129
|
+
h && /* @__PURE__ */ i("button", {
|
|
130
|
+
type: "button",
|
|
131
|
+
onClick: S,
|
|
132
|
+
disabled: g,
|
|
133
|
+
"aria-busy": g,
|
|
134
|
+
className: "inline-flex h-control-md w-[var(--size-controlHeight-md)] items-center justify-center rounded-button text-text-secondary motion-safe:transition-colors hover:bg-bg-sunken hover:text-text-primary disabled:cursor-not-allowed disabled:opacity-60 sm:h-control-sm sm:w-[var(--size-controlHeight-sm)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-bg-surface",
|
|
135
|
+
title: g ? "Running…" : "Run Workflow",
|
|
136
|
+
"aria-label": g ? `Running workflow ${n.name}` : `Run workflow ${n.name}`,
|
|
137
|
+
children: /* @__PURE__ */ i(d, { className: `w-4 h-4 ${g ? "motion-safe:animate-pulse" : ""}` })
|
|
138
|
+
}),
|
|
139
|
+
p && /* @__PURE__ */ i("button", {
|
|
140
|
+
type: "button",
|
|
141
|
+
onClick: b,
|
|
142
|
+
className: "inline-flex h-control-md w-[var(--size-controlHeight-md)] items-center justify-center rounded-button text-text-secondary motion-safe:transition-colors hover:bg-bg-sunken hover:text-text-primary sm:h-control-sm sm:w-[var(--size-controlHeight-sm)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-bg-surface",
|
|
143
|
+
title: "Edit Workflow",
|
|
144
|
+
"aria-label": `Edit workflow ${n.name}`,
|
|
145
|
+
children: /* @__PURE__ */ i(c, { className: "w-4 h-4" })
|
|
146
|
+
}),
|
|
147
|
+
m && /* @__PURE__ */ i("button", {
|
|
148
|
+
type: "button",
|
|
149
|
+
onClick: x,
|
|
150
|
+
className: "inline-flex h-control-md w-[var(--size-controlHeight-md)] items-center justify-center rounded-button text-text-secondary motion-safe:transition-colors hover:bg-status-error-bg/10 hover:text-status-error-text sm:h-control-sm sm:w-[var(--size-controlHeight-sm)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-bg-surface",
|
|
151
|
+
title: "Delete Workflow",
|
|
152
|
+
"aria-label": `Delete workflow ${n.name}`,
|
|
153
|
+
children: /* @__PURE__ */ i(l, { className: "w-4 h-4" })
|
|
154
|
+
})
|
|
155
|
+
]
|
|
137
156
|
})]
|
|
138
157
|
}),
|
|
139
158
|
n.description && /* @__PURE__ */ i("p", {
|
|
@@ -146,12 +165,12 @@ var s = ({ className: e }) => /* @__PURE__ */ i("svg", {
|
|
|
146
165
|
className: "flex min-w-0 flex-wrap items-center gap-x-3 gap-y-1",
|
|
147
166
|
children: [/* @__PURE__ */ a("span", {
|
|
148
167
|
className: "flex items-center gap-1",
|
|
149
|
-
title: `${
|
|
168
|
+
title: `${_} linked DataSinks`,
|
|
150
169
|
children: [
|
|
151
170
|
/* @__PURE__ */ i(u, { className: "w-3.5 h-3.5 shrink-0" }),
|
|
152
|
-
|
|
171
|
+
_,
|
|
153
172
|
" DataSink",
|
|
154
|
-
|
|
173
|
+
_ === 1 ? "" : "s"
|
|
155
174
|
]
|
|
156
175
|
}), /* @__PURE__ */ a("span", {
|
|
157
176
|
className: "flex items-center gap-1",
|
|
@@ -160,7 +179,7 @@ var s = ({ className: e }) => /* @__PURE__ */ i("svg", {
|
|
|
160
179
|
})]
|
|
161
180
|
}), /* @__PURE__ */ i("span", {
|
|
162
181
|
title: n.lastExecutedAt ? `Last executed: ${new Date(n.lastExecutedAt).toLocaleString()}` : "Never executed",
|
|
163
|
-
children:
|
|
182
|
+
children: v(n.lastExecutedAt)
|
|
164
183
|
})]
|
|
165
184
|
})
|
|
166
185
|
]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkflowCard.js","names":[],"sources":["../../../../src/bigconsole/components/workflow/WorkflowCard.tsx"],"sourcesContent":["/**\n * WorkflowCard Component\n *\n * Card component displaying a FluidGrids Workflow summary.\n * Shows name, status, linked DataSinks count, and execution stats.\n *\n * Emphasis (BOFF-5634): the card is a tile inside the list page's `primary`\n * results section, so it sits on `bg-bg-elevated` — one step above the section\n * surface — rather than repeating the generic panel treatment used by every\n * other block in the module. The old 96px empty media band carried no\n * information and out-weighed the title; it is now a compact identity strip.\n */\n\nimport { memo, useCallback } from 'react';\nimport { formatDistanceToNow } from 'date-fns';\nimport { WorkflowStatusBadge } from './WorkflowStatusBadge';\nimport { SECTION_FOCUS_RING } from '../common';\nimport type { FluidGridsWorkflow } from '../../types';\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\ninterface WorkflowCardProps {\n workflow: FluidGridsWorkflow;\n onView?: (id: string) => void;\n onEdit?: (id: string) => void;\n onDelete?: (id: string) => void;\n}\n\n// ============================================================================\n// ICONS\n// ============================================================================\n\nconst WorkflowIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={1.5} d=\"M13 10V3L4 14h7v7l9-11h-7z\" />\n </svg>\n);\n\nconst EditIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z\"\n />\n </svg>\n);\n\nconst DeleteIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\"\n />\n </svg>\n);\n\nconst DataSinkIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4\"\n />\n </svg>\n);\n\nconst PlayIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z\"\n />\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M21 12a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n);\n\n// ============================================================================\n// COMPONENT\n// ============================================================================\n\nexport const WorkflowCard = memo(function WorkflowCard({ workflow, onView, onEdit, onDelete }: WorkflowCardProps) {\n // Calculate linked DataSinks count\n const linkedDataSinkCount = workflow.dataSinkLinks?.length ?? workflow.linkedDataSinkCount ?? 0;\n\n // Format last executed time\n const formatLastExecuted = useCallback((dateStr: string | null): string => {\n if (!dateStr) return 'Never';\n try {\n const date = new Date(dateStr);\n return formatDistanceToNow(date, { addSuffix: true });\n } catch {\n return 'Unknown';\n }\n }, []);\n\n // Event handlers\n const handleCardClick = useCallback(() => {\n onView?.(workflow.id);\n }, [onView, workflow.id]);\n\n const handleEditClick = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onEdit?.(workflow.id);\n },\n [onEdit, workflow.id]\n );\n\n const handleDeleteClick = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onDelete?.(workflow.id);\n },\n [onDelete, workflow.id]\n );\n\n // The title is the real \"open this workflow\" control. The tile itself must NOT\n // carry role=\"button\": that role makes its subtree presentational, which would\n // drop the Edit/Delete buttons and the status badge out of the accessibility\n // tree. The tile keeps a plain click handler as a pointer convenience only.\n const handleTitleClick = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onView?.(workflow.id);\n },\n [onView, workflow.id]\n );\n\n return (\n <div\n onClick={handleCardClick}\n className=\"min-w-0 cursor-pointer overflow-hidden rounded-card border border-[var(--color-border-subtle)] bg-bg-elevated motion-safe:transition-[box-shadow,border-color] focus-within:border-action-primary-bg hover:border-action-primary-bg hover:shadow-[var(--shadow-elevation-1)]\"\n >\n {/* Identity strip: what kind of thing this is + its status, at a glance */}\n <div className=\"flex items-center justify-between gap-icon-gap border-b border-[var(--color-border-subtle)] bg-bg-sunken px-3 py-2\">\n <span className=\"flex min-w-0 items-center gap-icon-gap text-xs font-medium text-text-secondary\">\n <WorkflowIcon className=\"w-4 h-4 shrink-0\" />\n <span className=\"truncate\">Workflow</span>\n </span>\n <WorkflowStatusBadge status={workflow.status} size=\"sm\" />\n </div>\n\n {/* Content */}\n <div className=\"p-card-padding\">\n {/* Title and Actions */}\n <div className=\"mb-2 flex items-start justify-between gap-icon-gap\">\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"text-sm font-semibold text-text-primary\">\n <button\n type=\"button\"\n onClick={handleTitleClick}\n aria-label={`Open workflow ${workflow.name}`}\n className={`line-clamp-2 rounded-button text-left ${SECTION_FOCUS_RING}`}\n >\n {workflow.name}\n </button>\n </h3>\n <p className=\"mt-0.5 truncate font-mono text-xs text-text-secondary\">{workflow.key}</p>\n </div>\n\n <div className=\"flex shrink-0 items-center gap-1\">\n {onEdit && (\n <button\n type=\"button\"\n onClick={handleEditClick}\n className={`inline-flex h-control-md w-[var(--size-controlHeight-md)] items-center justify-center rounded-button text-text-secondary motion-safe:transition-colors hover:bg-bg-sunken hover:text-text-primary sm:h-control-sm sm:w-[var(--size-controlHeight-sm)] ${SECTION_FOCUS_RING}`}\n title=\"Edit Workflow\"\n aria-label={`Edit workflow ${workflow.name}`}\n >\n <EditIcon className=\"w-4 h-4\" />\n </button>\n )}\n {onDelete && (\n <button\n type=\"button\"\n onClick={handleDeleteClick}\n className={`inline-flex h-control-md w-[var(--size-controlHeight-md)] items-center justify-center rounded-button text-text-secondary motion-safe:transition-colors hover:bg-status-error-bg/10 hover:text-status-error-text sm:h-control-sm sm:w-[var(--size-controlHeight-sm)] ${SECTION_FOCUS_RING}`}\n title=\"Delete Workflow\"\n aria-label={`Delete workflow ${workflow.name}`}\n >\n <DeleteIcon className=\"w-4 h-4\" />\n </button>\n )}\n </div>\n </div>\n\n {/* Description */}\n {workflow.description && (\n <p className=\"mb-3 line-clamp-2 text-xs text-text-secondary\">{workflow.description}</p>\n )}\n\n {/* Stats Footer */}\n <div className=\"flex flex-wrap items-center justify-between gap-x-3 gap-y-1 text-xs text-text-muted\">\n <div className=\"flex min-w-0 flex-wrap items-center gap-x-3 gap-y-1\">\n {/* DataSinks Count */}\n <span className=\"flex items-center gap-1\" title={`${linkedDataSinkCount} linked DataSinks`}>\n <DataSinkIcon className=\"w-3.5 h-3.5 shrink-0\" />\n {linkedDataSinkCount} DataSink{linkedDataSinkCount !== 1 ? 's' : ''}\n </span>\n\n {/* Execution Count */}\n <span className=\"flex items-center gap-1\" title={`${workflow.executionCount} executions`}>\n <PlayIcon className=\"w-3.5 h-3.5 shrink-0\" />\n {workflow.executionCount}\n </span>\n </div>\n\n {/* Last Executed */}\n <span\n title={\n workflow.lastExecutedAt\n ? `Last executed: ${new Date(workflow.lastExecutedAt).toLocaleString()}`\n : 'Never executed'\n }\n >\n {formatLastExecuted(workflow.lastExecutedAt)}\n </span>\n </div>\n </div>\n </div>\n );\n});\n\nexport default WorkflowCard;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"WorkflowCard.js","names":[],"sources":["../../../../src/bigconsole/components/workflow/WorkflowCard.tsx"],"sourcesContent":["/**\n * WorkflowCard Component\n *\n * Card component displaying a FluidGrids Workflow summary.\n * Shows name, status, linked DataSinks count, and execution stats.\n *\n * Emphasis (BOFF-5634): the card is a tile inside the list page's `primary`\n * results section, so it sits on `bg-bg-elevated` — one step above the section\n * surface — rather than repeating the generic panel treatment used by every\n * other block in the module. The old 96px empty media band carried no\n * information and out-weighed the title; it is now a compact identity strip.\n */\n\nimport { memo, useCallback } from 'react';\nimport { formatDistanceToNow } from 'date-fns';\nimport { WorkflowStatusBadge } from './WorkflowStatusBadge';\nimport { SECTION_FOCUS_RING } from '../common';\nimport type { FluidGridsWorkflow } from '../../types';\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\ninterface WorkflowCardProps {\n workflow: FluidGridsWorkflow;\n onView?: (id: string) => void;\n onEdit?: (id: string) => void;\n onDelete?: (id: string) => void;\n /**\n * Trigger a run. Omitted when the actor lacks `bigconsole-workflow:execute`,\n * so the affordance is absent rather than present-and-refused.\n */\n onRun?: (id: string) => void;\n /** True while this workflow's run request is in flight. */\n isRunning?: boolean;\n}\n\n// ============================================================================\n// ICONS\n// ============================================================================\n\nconst WorkflowIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={1.5} d=\"M13 10V3L4 14h7v7l9-11h-7z\" />\n </svg>\n);\n\nconst EditIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z\"\n />\n </svg>\n);\n\nconst DeleteIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\"\n />\n </svg>\n);\n\nconst DataSinkIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4\"\n />\n </svg>\n);\n\nconst PlayIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z\"\n />\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M21 12a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n);\n\n// ============================================================================\n// COMPONENT\n// ============================================================================\n\nexport const WorkflowCard = memo(function WorkflowCard({\n workflow,\n onView,\n onEdit,\n onDelete,\n onRun,\n isRunning = false,\n}: WorkflowCardProps) {\n // Calculate linked DataSinks count\n const linkedDataSinkCount = workflow.dataSinkLinks?.length ?? workflow.linkedDataSinkCount ?? 0;\n\n // Format last executed time\n const formatLastExecuted = useCallback((dateStr: string | null): string => {\n if (!dateStr) return 'Never';\n try {\n const date = new Date(dateStr);\n return formatDistanceToNow(date, { addSuffix: true });\n } catch {\n return 'Unknown';\n }\n }, []);\n\n // Event handlers\n const handleCardClick = useCallback(() => {\n onView?.(workflow.id);\n }, [onView, workflow.id]);\n\n const handleEditClick = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onEdit?.(workflow.id);\n },\n [onEdit, workflow.id]\n );\n\n const handleDeleteClick = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onDelete?.(workflow.id);\n },\n [onDelete, workflow.id]\n );\n\n const handleRunClick = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n if (isRunning) return;\n onRun?.(workflow.id);\n },\n [isRunning, onRun, workflow.id]\n );\n\n // The title is the real \"open this workflow\" control. The tile itself must NOT\n // carry role=\"button\": that role makes its subtree presentational, which would\n // drop the Edit/Delete buttons and the status badge out of the accessibility\n // tree. The tile keeps a plain click handler as a pointer convenience only.\n const handleTitleClick = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onView?.(workflow.id);\n },\n [onView, workflow.id]\n );\n\n return (\n <div\n onClick={handleCardClick}\n className=\"min-w-0 cursor-pointer overflow-hidden rounded-card border border-[var(--color-border-subtle)] bg-bg-elevated motion-safe:transition-[box-shadow,border-color] focus-within:border-action-primary-bg hover:border-action-primary-bg hover:shadow-[var(--shadow-elevation-1)]\"\n >\n {/* Identity strip: what kind of thing this is + its status, at a glance */}\n <div className=\"flex items-center justify-between gap-icon-gap border-b border-[var(--color-border-subtle)] bg-bg-sunken px-3 py-2\">\n <span className=\"flex min-w-0 items-center gap-icon-gap text-xs font-medium text-text-secondary\">\n <WorkflowIcon className=\"w-4 h-4 shrink-0\" />\n <span className=\"truncate\">Workflow</span>\n </span>\n <WorkflowStatusBadge status={workflow.status} size=\"sm\" />\n </div>\n\n {/* Content */}\n <div className=\"p-card-padding\">\n {/* Title and Actions */}\n <div className=\"mb-2 flex items-start justify-between gap-icon-gap\">\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"text-sm font-semibold text-text-primary\">\n <button\n type=\"button\"\n onClick={handleTitleClick}\n aria-label={`Open workflow ${workflow.name}`}\n className={`line-clamp-2 rounded-button text-left ${SECTION_FOCUS_RING}`}\n >\n {workflow.name}\n </button>\n </h3>\n <p className=\"mt-0.5 truncate font-mono text-xs text-text-secondary\">{workflow.key}</p>\n </div>\n\n <div className=\"flex shrink-0 items-center gap-1\">\n {onRun && (\n <button\n type=\"button\"\n onClick={handleRunClick}\n disabled={isRunning}\n aria-busy={isRunning}\n className={`inline-flex h-control-md w-[var(--size-controlHeight-md)] items-center justify-center rounded-button text-text-secondary motion-safe:transition-colors hover:bg-bg-sunken hover:text-text-primary disabled:cursor-not-allowed disabled:opacity-60 sm:h-control-sm sm:w-[var(--size-controlHeight-sm)] ${SECTION_FOCUS_RING}`}\n title={isRunning ? 'Running…' : 'Run Workflow'}\n aria-label={isRunning ? `Running workflow ${workflow.name}` : `Run workflow ${workflow.name}`}\n >\n <PlayIcon className={`w-4 h-4 ${isRunning ? 'motion-safe:animate-pulse' : ''}`} />\n </button>\n )}\n {onEdit && (\n <button\n type=\"button\"\n onClick={handleEditClick}\n className={`inline-flex h-control-md w-[var(--size-controlHeight-md)] items-center justify-center rounded-button text-text-secondary motion-safe:transition-colors hover:bg-bg-sunken hover:text-text-primary sm:h-control-sm sm:w-[var(--size-controlHeight-sm)] ${SECTION_FOCUS_RING}`}\n title=\"Edit Workflow\"\n aria-label={`Edit workflow ${workflow.name}`}\n >\n <EditIcon className=\"w-4 h-4\" />\n </button>\n )}\n {onDelete && (\n <button\n type=\"button\"\n onClick={handleDeleteClick}\n className={`inline-flex h-control-md w-[var(--size-controlHeight-md)] items-center justify-center rounded-button text-text-secondary motion-safe:transition-colors hover:bg-status-error-bg/10 hover:text-status-error-text sm:h-control-sm sm:w-[var(--size-controlHeight-sm)] ${SECTION_FOCUS_RING}`}\n title=\"Delete Workflow\"\n aria-label={`Delete workflow ${workflow.name}`}\n >\n <DeleteIcon className=\"w-4 h-4\" />\n </button>\n )}\n </div>\n </div>\n\n {/* Description */}\n {workflow.description && (\n <p className=\"mb-3 line-clamp-2 text-xs text-text-secondary\">{workflow.description}</p>\n )}\n\n {/* Stats Footer */}\n <div className=\"flex flex-wrap items-center justify-between gap-x-3 gap-y-1 text-xs text-text-muted\">\n <div className=\"flex min-w-0 flex-wrap items-center gap-x-3 gap-y-1\">\n {/* DataSinks Count */}\n <span className=\"flex items-center gap-1\" title={`${linkedDataSinkCount} linked DataSinks`}>\n <DataSinkIcon className=\"w-3.5 h-3.5 shrink-0\" />\n {linkedDataSinkCount} DataSink{linkedDataSinkCount !== 1 ? 's' : ''}\n </span>\n\n {/* Execution Count */}\n <span className=\"flex items-center gap-1\" title={`${workflow.executionCount} executions`}>\n <PlayIcon className=\"w-3.5 h-3.5 shrink-0\" />\n {workflow.executionCount}\n </span>\n </div>\n\n {/* Last Executed */}\n <span\n title={\n workflow.lastExecutedAt\n ? `Last executed: ${new Date(workflow.lastExecutedAt).toLocaleString()}`\n : 'Never executed'\n }\n >\n {formatLastExecuted(workflow.lastExecutedAt)}\n </span>\n </div>\n </div>\n </div>\n );\n});\n\nexport default WorkflowCard;\n"],"mappings":";;;;;;;AAyCA,IAAM,KAAgB,EAAE,mBACtB,kBAAC,OAAD;CAAgB;CAAW,MAAK;CAAO,QAAO;CAAe,SAAQ;WACnE,kBAAC,QAAD;EAAM,eAAc;EAAQ,gBAAe;EAAQ,aAAa;EAAK,GAAE;EAA+B,CAAA;CAClG,CAAA,EAGF,KAAY,EAAE,mBAClB,kBAAC,OAAD;CAAgB;CAAW,MAAK;CAAO,QAAO;CAAe,SAAQ;WACnE,kBAAC,QAAD;EACE,eAAc;EACd,gBAAe;EACf,aAAa;EACb,GAAE;EACF,CAAA;CACE,CAAA,EAGF,KAAc,EAAE,mBACpB,kBAAC,OAAD;CAAgB;CAAW,MAAK;CAAO,QAAO;CAAe,SAAQ;WACnE,kBAAC,QAAD;EACE,eAAc;EACd,gBAAe;EACf,aAAa;EACb,GAAE;EACF,CAAA;CACE,CAAA,EAGF,KAAgB,EAAE,mBACtB,kBAAC,OAAD;CAAgB;CAAW,MAAK;CAAO,QAAO;CAAe,SAAQ;WACnE,kBAAC,QAAD;EACE,eAAc;EACd,gBAAe;EACf,aAAa;EACb,GAAE;EACF,CAAA;CACE,CAAA,EAGF,KAAY,EAAE,mBAClB,kBAAC,OAAD;CAAgB;CAAW,MAAK;CAAO,QAAO;CAAe,SAAQ;WAArE,CACE,kBAAC,QAAD;EACE,eAAc;EACd,gBAAe;EACf,aAAa;EACb,GAAE;EACF,CAAA,EACF,kBAAC,QAAD;EAAM,eAAc;EAAQ,gBAAe;EAAQ,aAAa;EAAG,GAAE;EAAuC,CAAA,CACxG;IAOK,IAAe,EAAK,SAAsB,EACrD,aACA,WACA,WACA,aACA,UACA,eAAY,MACQ;CAEpB,IAAM,IAAsB,EAAS,eAAe,UAAU,EAAS,uBAAuB,GAGxF,IAAqB,GAAa,MAAmC;AACzE,MAAI,CAAC,EAAS,QAAO;AACrB,MAAI;AAEF,UAAO,EADM,IAAI,KAAK,EAAQ,EACG,EAAE,WAAW,IAAM,CAAC;UAC/C;AACN,UAAO;;IAER,EAAE,CAAC,EAGA,IAAkB,QAAkB;AACxC,MAAS,EAAS,GAAG;IACpB,CAAC,GAAQ,EAAS,GAAG,CAAC,EAEnB,IAAkB,GACrB,MAAwB;AAEvB,EADA,EAAE,iBAAiB,EACnB,IAAS,EAAS,GAAG;IAEvB,CAAC,GAAQ,EAAS,GAAG,CACtB,EAEK,IAAoB,GACvB,MAAwB;AAEvB,EADA,EAAE,iBAAiB,EACnB,IAAW,EAAS,GAAG;IAEzB,CAAC,GAAU,EAAS,GAAG,CACxB,EAEK,IAAiB,GACpB,MAAwB;AACvB,IAAE,iBAAiB,EACf,MACJ,IAAQ,EAAS,GAAG;IAEtB;EAAC;EAAW;EAAO,EAAS;EAAG,CAChC,EAMK,IAAmB,GACtB,MAAwB;AAEvB,EADA,EAAE,iBAAiB,EACnB,IAAS,EAAS,GAAG;IAEvB,CAAC,GAAQ,EAAS,GAAG,CACtB;AAED,QACE,kBAAC,OAAD;EACE,SAAS;EACT,WAAU;YAFZ,CAKE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,QAAD;IAAM,WAAU;cAAhB,CACE,kBAAC,GAAD,EAAc,WAAU,oBAAqB,CAAA,EAC7C,kBAAC,QAAD;KAAM,WAAU;eAAW;KAAe,CAAA,CACrC;OACP,kBAAC,GAAD;IAAqB,QAAQ,EAAS;IAAQ,MAAK;IAAO,CAAA,CACtD;MAGN,kBAAC,OAAD;GAAK,WAAU;aAAf;IAEE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,MAAD;OAAI,WAAU;iBACZ,kBAAC,UAAD;QACE,MAAK;QACL,SAAS;QACT,cAAY,iBAAiB,EAAS;QACtC,WAAW,yCAAyC;kBAEnD,EAAS;QACH,CAAA;OACN,CAAA,EACL,kBAAC,KAAD;OAAG,WAAU;iBAAyD,EAAS;OAAQ,CAAA,CACnF;SAEN,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACG,KACC,kBAAC,UAAD;QACE,MAAK;QACL,SAAS;QACT,UAAU;QACV,aAAW;QACX,WAAW;QACX,OAAO,IAAY,aAAa;QAChC,cAAY,IAAY,oBAAoB,EAAS,SAAS,gBAAgB,EAAS;kBAEvF,kBAAC,GAAD,EAAU,WAAW,WAAW,IAAY,8BAA8B,MAAQ,CAAA;QAC3E,CAAA;OAEV,KACC,kBAAC,UAAD;QACE,MAAK;QACL,SAAS;QACT,WAAW;QACX,OAAM;QACN,cAAY,iBAAiB,EAAS;kBAEtC,kBAAC,GAAD,EAAU,WAAU,WAAY,CAAA;QACzB,CAAA;OAEV,KACC,kBAAC,UAAD;QACE,MAAK;QACL,SAAS;QACT,WAAW;QACX,OAAM;QACN,cAAY,mBAAmB,EAAS;kBAExC,kBAAC,GAAD,EAAY,WAAU,WAAY,CAAA;QAC3B,CAAA;OAEP;QACF;;IAGL,EAAS,eACR,kBAAC,KAAD;KAAG,WAAU;eAAiD,EAAS;KAAgB,CAAA;IAIzF,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CAEE,kBAAC,QAAD;OAAM,WAAU;OAA0B,OAAO,GAAG,EAAoB;iBAAxE;QACE,kBAAC,GAAD,EAAc,WAAU,wBAAyB,CAAA;QAChD;QAAoB;QAAU,MAAwB,IAAU,KAAN;QACtD;UAGP,kBAAC,QAAD;OAAM,WAAU;OAA0B,OAAO,GAAG,EAAS,eAAe;iBAA5E,CACE,kBAAC,GAAD,EAAU,WAAU,wBAAyB,CAAA,EAC5C,EAAS,eACL;SACH;SAGN,kBAAC,QAAD;MACE,OACE,EAAS,iBACL,kBAAkB,IAAI,KAAK,EAAS,eAAe,CAAC,gBAAgB,KACpE;gBAGL,EAAmB,EAAS,eAAe;MACvC,CAAA,CACH;;IACF;KACF;;EAER"}
|
|
@@ -6,6 +6,10 @@ import { useCallback as l, useEffect as u, useState as d } from "react";
|
|
|
6
6
|
import { useApolloClient as f } from "@apollo/client/react";
|
|
7
7
|
//#region src/bigconsole/hooks/useDashboardOperations.ts
|
|
8
8
|
function p(e) {
|
|
9
|
+
let t = e?.toUpperCase();
|
|
10
|
+
return t === "PRIVATE" || t === "WORKSPACE" || t === "PUBLIC" ? t : void 0;
|
|
11
|
+
}
|
|
12
|
+
function m(e) {
|
|
9
13
|
let t = e.pages?.edges?.map((t) => ({
|
|
10
14
|
id: t.node.id,
|
|
11
15
|
dashboardId: t.node.dashboardId || e.id,
|
|
@@ -26,6 +30,7 @@ function p(e) {
|
|
|
26
30
|
slug: e.name?.toLowerCase().replace(/\s+/g, "-") || "",
|
|
27
31
|
isPublished: e.isPublic || !1,
|
|
28
32
|
isTemplate: e.isTemplate || !1,
|
|
33
|
+
visibility: p(e.visibility),
|
|
29
34
|
layoutConfig: e.layout || {
|
|
30
35
|
columns: 12,
|
|
31
36
|
rowHeight: 100,
|
|
@@ -40,13 +45,18 @@ function p(e) {
|
|
|
40
45
|
updatedAt: e.updatedAt || (/* @__PURE__ */ new Date()).toISOString()
|
|
41
46
|
};
|
|
42
47
|
}
|
|
43
|
-
function
|
|
48
|
+
function h(e) {
|
|
49
|
+
let t = e?.toUpperCase();
|
|
50
|
+
return t === "DRAFT" || t === "PUBLISHED" || t === "ARCHIVED" ? t : void 0;
|
|
51
|
+
}
|
|
52
|
+
function g(e) {
|
|
44
53
|
return {
|
|
45
54
|
id: e.id,
|
|
46
55
|
name: e.name || "Untitled Dashboard",
|
|
47
56
|
description: e.description,
|
|
48
57
|
category: e.category,
|
|
49
58
|
isPublic: e.isPublic,
|
|
59
|
+
status: h(e.status),
|
|
50
60
|
viewCount: e.viewCount,
|
|
51
61
|
widgetCount: e.widgetCount,
|
|
52
62
|
createdAt: e.createdAt || (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -54,10 +64,10 @@ function m(e) {
|
|
|
54
64
|
pageCount: e.pages?.totalCount ?? 0
|
|
55
65
|
};
|
|
56
66
|
}
|
|
57
|
-
function
|
|
58
|
-
let [h,
|
|
67
|
+
function _({ skipFetch: p = !1 } = {}) {
|
|
68
|
+
let [h, _] = d(!1), [v, y] = d(null), [b, x] = d([]), S = f(), C = e((e) => e.currentDashboard), w = e((e) => e.setCurrentDashboard), T = l(async (e) => {
|
|
59
69
|
try {
|
|
60
|
-
|
|
70
|
+
_(!0), y(null), x(((await S.query({
|
|
61
71
|
query: a,
|
|
62
72
|
variables: {
|
|
63
73
|
first: 50,
|
|
@@ -65,34 +75,34 @@ function h() {
|
|
|
65
75
|
includeArchived: !1
|
|
66
76
|
},
|
|
67
77
|
fetchPolicy: "network-only"
|
|
68
|
-
})).data?.listDashboards?.edges || []).map((e) =>
|
|
78
|
+
})).data?.listDashboards?.edges || []).map((e) => g(e.node)));
|
|
69
79
|
} catch (e) {
|
|
70
|
-
|
|
80
|
+
y(e instanceof Error ? e : /* @__PURE__ */ Error("Failed to fetch dashboards"));
|
|
71
81
|
} finally {
|
|
72
|
-
|
|
82
|
+
_(!1);
|
|
73
83
|
}
|
|
74
|
-
}, [
|
|
84
|
+
}, [S]), E = l(async (e, t) => {
|
|
75
85
|
let n = t?.silent ?? !1;
|
|
76
86
|
try {
|
|
77
|
-
n || (
|
|
78
|
-
let t = await
|
|
87
|
+
n || (_(!0), y(null));
|
|
88
|
+
let t = await S.query({
|
|
79
89
|
query: i,
|
|
80
90
|
variables: { id: e },
|
|
81
91
|
fetchPolicy: "network-only"
|
|
82
92
|
});
|
|
83
93
|
if (t.data?.getDashboard) {
|
|
84
|
-
let e =
|
|
85
|
-
return
|
|
94
|
+
let e = m(t.data.getDashboard);
|
|
95
|
+
return w(e), e;
|
|
86
96
|
}
|
|
87
97
|
return null;
|
|
88
98
|
} catch (e) {
|
|
89
|
-
return n ||
|
|
99
|
+
return n || y(e instanceof Error ? e : /* @__PURE__ */ Error("Failed to fetch dashboard")), null;
|
|
90
100
|
} finally {
|
|
91
|
-
n ||
|
|
101
|
+
n || _(!1);
|
|
92
102
|
}
|
|
93
|
-
}, [
|
|
103
|
+
}, [S, w]), D = l(async (e) => {
|
|
94
104
|
try {
|
|
95
|
-
|
|
105
|
+
_(!0), y(null);
|
|
96
106
|
let t = {
|
|
97
107
|
name: e.name,
|
|
98
108
|
description: e.description,
|
|
@@ -101,64 +111,64 @@ function h() {
|
|
|
101
111
|
createDefaultPage: !0
|
|
102
112
|
};
|
|
103
113
|
e.tags && e.tags.length > 0 && (t.metadata = { tags: e.tags });
|
|
104
|
-
let r = await
|
|
114
|
+
let r = await S.mutate({
|
|
105
115
|
mutation: n,
|
|
106
116
|
variables: { input: t }
|
|
107
117
|
});
|
|
108
118
|
if (c(r)) throw s(r);
|
|
109
119
|
if (r.data?.createBigConsoleDashboard) {
|
|
110
|
-
let e =
|
|
111
|
-
return await
|
|
120
|
+
let e = m(r.data.createBigConsoleDashboard);
|
|
121
|
+
return await T(), e;
|
|
112
122
|
}
|
|
113
123
|
return null;
|
|
114
124
|
} catch (e) {
|
|
115
125
|
if (c(e)) throw e;
|
|
116
|
-
return
|
|
126
|
+
return y(e instanceof Error ? e : /* @__PURE__ */ Error("Failed to create dashboard")), null;
|
|
117
127
|
} finally {
|
|
118
|
-
|
|
128
|
+
_(!1);
|
|
119
129
|
}
|
|
120
|
-
}, [
|
|
130
|
+
}, [S, T]), O = l(async (e) => {
|
|
121
131
|
try {
|
|
122
|
-
|
|
123
|
-
let t = await
|
|
132
|
+
_(!0), y(null);
|
|
133
|
+
let t = await S.mutate({
|
|
124
134
|
mutation: o,
|
|
125
135
|
variables: { input: e }
|
|
126
136
|
});
|
|
127
137
|
if (t.data?.updateBigConsoleDashboard) {
|
|
128
|
-
let n =
|
|
129
|
-
return
|
|
138
|
+
let n = m(t.data.updateBigConsoleDashboard);
|
|
139
|
+
return C?.id === e.id && w(n), await T(), n;
|
|
130
140
|
}
|
|
131
141
|
return null;
|
|
132
142
|
} catch (e) {
|
|
133
|
-
return
|
|
143
|
+
return y(e instanceof Error ? e : /* @__PURE__ */ Error("Failed to update dashboard")), null;
|
|
134
144
|
} finally {
|
|
135
|
-
|
|
145
|
+
_(!1);
|
|
136
146
|
}
|
|
137
147
|
}, [
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
]),
|
|
148
|
+
S,
|
|
149
|
+
C?.id,
|
|
150
|
+
w,
|
|
151
|
+
T
|
|
152
|
+
]), k = l(async (e) => {
|
|
143
153
|
try {
|
|
144
|
-
return
|
|
154
|
+
return _(!0), y(null), (await S.mutate({
|
|
145
155
|
mutation: r,
|
|
146
156
|
variables: { id: e }
|
|
147
|
-
})).data?.deleteBigConsoleDashboard ? (
|
|
157
|
+
})).data?.deleteBigConsoleDashboard ? (C?.id === e && w(null), await T(), !0) : !1;
|
|
148
158
|
} catch (e) {
|
|
149
|
-
return
|
|
159
|
+
return y(e instanceof Error ? e : /* @__PURE__ */ Error("Failed to delete dashboard")), !1;
|
|
150
160
|
} finally {
|
|
151
|
-
|
|
161
|
+
_(!1);
|
|
152
162
|
}
|
|
153
163
|
}, [
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
]),
|
|
164
|
+
S,
|
|
165
|
+
C?.id,
|
|
166
|
+
w,
|
|
167
|
+
T
|
|
168
|
+
]), A = l(async (e, n) => {
|
|
159
169
|
try {
|
|
160
|
-
|
|
161
|
-
let r = await
|
|
170
|
+
_(!0), y(null);
|
|
171
|
+
let r = await S.mutate({
|
|
162
172
|
mutation: t,
|
|
163
173
|
variables: { input: {
|
|
164
174
|
sourceDashboardId: e,
|
|
@@ -168,36 +178,36 @@ function h() {
|
|
|
168
178
|
});
|
|
169
179
|
if (c(r)) throw s(r);
|
|
170
180
|
if (r.data?.cloneDashboard) {
|
|
171
|
-
let e =
|
|
172
|
-
return await
|
|
181
|
+
let e = m(r.data.cloneDashboard);
|
|
182
|
+
return await T(), e;
|
|
173
183
|
}
|
|
174
184
|
return null;
|
|
175
185
|
} catch (e) {
|
|
176
186
|
if (c(e)) throw e;
|
|
177
|
-
return
|
|
187
|
+
return y(e instanceof Error ? e : /* @__PURE__ */ Error("Failed to clone dashboard")), null;
|
|
178
188
|
} finally {
|
|
179
|
-
|
|
189
|
+
_(!1);
|
|
180
190
|
}
|
|
181
|
-
}, [
|
|
182
|
-
await
|
|
183
|
-
}, [
|
|
191
|
+
}, [S, T]), j = l(async () => {
|
|
192
|
+
await T();
|
|
193
|
+
}, [T]);
|
|
184
194
|
return u(() => {
|
|
185
|
-
|
|
186
|
-
}, [
|
|
195
|
+
p || T();
|
|
196
|
+
}, [T, p]), {
|
|
187
197
|
loading: h,
|
|
188
|
-
error:
|
|
189
|
-
dashboards:
|
|
190
|
-
currentDashboard:
|
|
191
|
-
fetchDashboards:
|
|
192
|
-
fetchDashboard:
|
|
193
|
-
createDashboard:
|
|
194
|
-
updateDashboard:
|
|
195
|
-
deleteDashboard:
|
|
196
|
-
cloneDashboard:
|
|
197
|
-
refetch:
|
|
198
|
+
error: v,
|
|
199
|
+
dashboards: b,
|
|
200
|
+
currentDashboard: C,
|
|
201
|
+
fetchDashboards: T,
|
|
202
|
+
fetchDashboard: E,
|
|
203
|
+
createDashboard: D,
|
|
204
|
+
updateDashboard: O,
|
|
205
|
+
deleteDashboard: k,
|
|
206
|
+
cloneDashboard: A,
|
|
207
|
+
refetch: j
|
|
198
208
|
};
|
|
199
209
|
}
|
|
200
210
|
//#endregion
|
|
201
|
-
export {
|
|
211
|
+
export { _ as default };
|
|
202
212
|
|
|
203
213
|
//# sourceMappingURL=useDashboardOperations.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useDashboardOperations.js","names":[],"sources":["../../../src/bigconsole/hooks/useDashboardOperations.ts"],"sourcesContent":["/**\n * useDashboardOperations Hook\n *\n * Provides CRUD operations for dashboards using GraphQL.\n */\n\nimport { useCallback, useState, useEffect } from 'react';\nimport { useApolloClient } from '@apollo/client/react';\nimport type { Dashboard, DashboardLayoutConfig } from '../types';\nimport { useDashboardStore } from '../store';\nimport { createBigConsoleQuotaError, isBigConsoleQuotaError } from '../utils/quota';\nimport {\n ListDashboardsDocument,\n GetDashboardDocument,\n CreateDashboardDocument,\n UpdateDashboardDocument,\n DeleteDashboardDocument,\n CloneDashboardDocument,\n} from '../../generated/wspace-operations';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface DashboardListItem {\n id: string;\n name: string;\n description?: string;\n category?: string;\n isPublic?: boolean;\n viewCount?: number;\n widgetCount?: number;\n createdAt: string;\n updatedAt: string;\n pageCount: number;\n}\n\ninterface CreateDashboardInput {\n name: string;\n description?: string;\n category?: string;\n layoutType?: string;\n tags?: string[];\n}\n\ninterface UpdateDashboardInput {\n id: string;\n name?: string;\n description?: string;\n category?: string;\n isPublic?: boolean;\n}\n\ninterface FetchDashboardOptions {\n /**\n * Silent refetch for live-canvas polling: do NOT toggle the global `loading`\n * flag (which would flash the page-level spinner) and do NOT surface a\n * transient fetch error (which would replace the board with the error screen).\n * The last good dashboard stays on screen if a poll fails.\n */\n silent?: boolean;\n}\n\ninterface DashboardOperationsResult {\n loading: boolean;\n error: Error | null;\n dashboards: DashboardListItem[];\n currentDashboard: Dashboard | null;\n\n // Operations\n fetchDashboards: (search?: string) => Promise<void>;\n fetchDashboard: (id: string, options?: FetchDashboardOptions) => Promise<Dashboard | null>;\n createDashboard: (input: CreateDashboardInput) => Promise<Dashboard | null>;\n updateDashboard: (input: UpdateDashboardInput) => Promise<Dashboard | null>;\n deleteDashboard: (id: string) => Promise<boolean>;\n cloneDashboard: (sourceDashboardId: string, name: string) => Promise<Dashboard | null>;\n refetch: () => Promise<void>;\n}\n\n// ============================================================================\n// Helper: Normalize dashboard from GraphQL response\n// ============================================================================\n\n// Raw GraphQL response shape for dashboard data\ninterface RawDashboardData {\n id: string;\n name?: string;\n description?: string;\n workspaceId?: string;\n isPublic?: boolean;\n isTemplate?: boolean;\n layout?: Record<string, unknown>;\n category?: string;\n viewCount?: number;\n widgetCount?: number;\n createdBy?: string;\n ownerId?: string;\n createdAt?: string;\n updatedAt?: string;\n pages?: {\n edges?: Array<{\n node: {\n id: string;\n dashboardId?: string;\n name?: string;\n order?: number;\n layout?: Record<string, unknown>;\n gridColumns?: number;\n createdAt?: string;\n updatedAt?: string;\n };\n }>;\n totalCount?: number;\n };\n}\n\nfunction normalizeDashboard(data: RawDashboardData): Dashboard {\n const pages =\n data.pages?.edges?.map((edge) => ({\n id: edge.node.id,\n dashboardId: edge.node.dashboardId || data.id,\n name: edge.node.name,\n slug: edge.node.name?.toLowerCase().replace(/\\s+/g, '-') || '',\n order: edge.node.order || 0,\n layoutConfig: edge.node.layout || {},\n gridColumns: edge.node.gridColumns || 12,\n widgets: [], // Widgets loaded separately via useWidgetOperations\n createdAt: edge.node.createdAt || new Date().toISOString(),\n updatedAt: edge.node.updatedAt || new Date().toISOString(),\n })) || [];\n\n // GetDashboard caps pages at first:10 to stay under the gateway cost-limit\n // (see DashboardFullFields fragment / BOFF-2720). Surface a warning instead of\n // silently dropping pages if a dashboard ever exceeds the cap.\n const totalPages = data.pages?.totalCount ?? pages.length;\n if (totalPages > pages.length) {\n console.warn(\n `[bigconsole] Dashboard ${data.id} has ${totalPages} pages but only ${pages.length} were loaded ` +\n `(GetDashboard pages cap). Pages beyond the cap are not shown — see BOFF-2720.`\n );\n }\n\n return {\n id: data.id,\n workspaceId: data.workspaceId || '',\n name: data.name || 'Untitled Dashboard',\n description: data.description,\n slug: data.name?.toLowerCase().replace(/\\s+/g, '-') || '',\n isPublished: data.isPublic || false,\n isTemplate: data.isTemplate || false,\n layoutConfig: (data.layout as unknown as DashboardLayoutConfig) || {\n columns: 12,\n rowHeight: 100,\n gap: 10,\n margin: [10, 10],\n containerPadding: [10, 10],\n },\n pages,\n translations: [],\n createdBy: data.createdBy || data.ownerId || '',\n createdAt: data.createdAt || new Date().toISOString(),\n updatedAt: data.updatedAt || new Date().toISOString(),\n };\n}\n\nfunction normalizeDashboardListItem(data: RawDashboardData): DashboardListItem {\n // The list query selects only pages.totalCount (no edges) to stay under the\n // gateway Armor cost-limit — see DashboardListItem fragment / BOFF-2719.\n return {\n id: data.id,\n name: data.name || 'Untitled Dashboard',\n description: data.description,\n category: data.category,\n isPublic: data.isPublic,\n viewCount: data.viewCount,\n widgetCount: data.widgetCount,\n createdAt: data.createdAt || new Date().toISOString(),\n updatedAt: data.updatedAt || new Date().toISOString(),\n pageCount: data.pages?.totalCount ?? 0,\n };\n}\n\n// ============================================================================\n// Hook\n// ============================================================================\n\nexport function useDashboardOperations(): DashboardOperationsResult {\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [dashboards, setDashboards] = useState<DashboardListItem[]>([]);\n\n // Get Apollo Client - will throw if not in ApolloProvider context\n const apolloClient = useApolloClient();\n\n // Store actions\n const currentDashboard = useDashboardStore((state) => state.currentDashboard);\n const setCurrentDashboard = useDashboardStore((state) => state.setCurrentDashboard);\n\n // Fetch dashboards list\n const fetchDashboards = useCallback(\n async (search?: string) => {\n try {\n setLoading(true);\n setError(null);\n\n const result = await apolloClient.query<{ listDashboards?: { edges?: Array<{ node: RawDashboardData }> } }>({\n query: ListDashboardsDocument,\n variables: {\n first: 50,\n search,\n includeArchived: false,\n },\n fetchPolicy: 'network-only',\n });\n\n const edges = result.data?.listDashboards?.edges || [];\n const dashboardsList = edges.map((edge) => normalizeDashboardListItem(edge.node));\n setDashboards(dashboardsList);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to fetch dashboards');\n setError(error);\n } finally {\n setLoading(false);\n }\n },\n [apolloClient]\n );\n\n // Fetch single dashboard\n const fetchDashboard = useCallback(\n async (id: string, options?: FetchDashboardOptions): Promise<Dashboard | null> => {\n const silent = options?.silent ?? false;\n try {\n if (!silent) {\n setLoading(true);\n setError(null);\n }\n\n const result = await apolloClient.query<{ getDashboard?: RawDashboardData }>({\n query: GetDashboardDocument,\n variables: { id },\n fetchPolicy: 'network-only',\n });\n\n if (result.data?.getDashboard) {\n const dashboard = normalizeDashboard(result.data.getDashboard);\n setCurrentDashboard(dashboard);\n return dashboard;\n }\n\n return null;\n } catch (err) {\n // Silent (live-poll) failures must not wipe the board or flip the page to\n // the error screen — keep the last good dashboard on screen.\n if (!silent) {\n const error = err instanceof Error ? err : new Error('Failed to fetch dashboard');\n setError(error);\n }\n return null;\n } finally {\n if (!silent) {\n setLoading(false);\n }\n }\n },\n [apolloClient, setCurrentDashboard]\n );\n\n // Create dashboard\n const createDashboard = useCallback(\n async (input: CreateDashboardInput): Promise<Dashboard | null> => {\n try {\n setLoading(true);\n setError(null);\n\n // Build mutation input\n // Note: Tags require Tag IDs from the Tags service. For now, tags are stored in metadata.\n // Full tag integration would require querying/creating tags via the Tags service first.\n const mutationInput: Record<string, unknown> = {\n name: input.name,\n description: input.description,\n category: input.category || 'CUSTOM',\n layout: input.layoutType || 'GRID',\n createDefaultPage: true,\n };\n\n // Store tags in metadata until full Tags service integration\n if (input.tags && input.tags.length > 0) {\n mutationInput.metadata = {\n tags: input.tags,\n };\n }\n\n const result = await apolloClient.mutate<{ createBigConsoleDashboard?: RawDashboardData }>({\n mutation: CreateDashboardDocument,\n variables: {\n input: mutationInput,\n },\n });\n\n if (isBigConsoleQuotaError(result)) {\n throw createBigConsoleQuotaError(result);\n }\n\n if (result.data?.createBigConsoleDashboard) {\n const newDashboard = normalizeDashboard(result.data.createBigConsoleDashboard);\n await fetchDashboards();\n return newDashboard;\n }\n\n return null;\n } catch (err) {\n if (isBigConsoleQuotaError(err)) {\n throw err;\n }\n const error = err instanceof Error ? err : new Error('Failed to create dashboard');\n setError(error);\n return null;\n } finally {\n setLoading(false);\n }\n },\n [apolloClient, fetchDashboards]\n );\n\n // Update dashboard\n const updateDashboard = useCallback(\n async (input: UpdateDashboardInput): Promise<Dashboard | null> => {\n try {\n setLoading(true);\n setError(null);\n\n const result = await apolloClient.mutate<{ updateBigConsoleDashboard?: RawDashboardData }>({\n mutation: UpdateDashboardDocument,\n variables: { input },\n });\n\n if (result.data?.updateBigConsoleDashboard) {\n const updatedDashboard = normalizeDashboard(result.data.updateBigConsoleDashboard);\n if (currentDashboard?.id === input.id) {\n setCurrentDashboard(updatedDashboard);\n }\n await fetchDashboards();\n return updatedDashboard;\n }\n\n return null;\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to update dashboard');\n setError(error);\n return null;\n } finally {\n setLoading(false);\n }\n },\n [apolloClient, currentDashboard?.id, setCurrentDashboard, fetchDashboards]\n );\n\n // Delete dashboard\n const deleteDashboard = useCallback(\n async (id: string): Promise<boolean> => {\n try {\n setLoading(true);\n setError(null);\n\n const result = await apolloClient.mutate<{ deleteBigConsoleDashboard?: boolean }>({\n mutation: DeleteDashboardDocument,\n variables: { id },\n });\n\n if (result.data?.deleteBigConsoleDashboard) {\n if (currentDashboard?.id === id) {\n setCurrentDashboard(null);\n }\n await fetchDashboards();\n return true;\n }\n\n return false;\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to delete dashboard');\n setError(error);\n return false;\n } finally {\n setLoading(false);\n }\n },\n [apolloClient, currentDashboard?.id, setCurrentDashboard, fetchDashboards]\n );\n\n // Clone dashboard (duplicate including widgets)\n const cloneDashboard = useCallback(\n async (sourceDashboardId: string, name: string): Promise<Dashboard | null> => {\n try {\n setLoading(true);\n setError(null);\n\n const result = await apolloClient.mutate<{ cloneDashboard?: RawDashboardData }>({\n mutation: CloneDashboardDocument,\n variables: {\n input: { sourceDashboardId, name, includeWidgets: true },\n },\n });\n\n if (isBigConsoleQuotaError(result)) {\n throw createBigConsoleQuotaError(result);\n }\n\n if (result.data?.cloneDashboard) {\n const cloned = normalizeDashboard(result.data.cloneDashboard);\n await fetchDashboards();\n return cloned;\n }\n\n return null;\n } catch (err) {\n if (isBigConsoleQuotaError(err)) {\n throw err;\n }\n const error = err instanceof Error ? err : new Error('Failed to clone dashboard');\n setError(error);\n return null;\n } finally {\n setLoading(false);\n }\n },\n [apolloClient, fetchDashboards]\n );\n\n // Refetch\n const refetch = useCallback(async () => {\n await fetchDashboards();\n }, [fetchDashboards]);\n\n // Fetch on mount\n useEffect(() => {\n fetchDashboards();\n }, [fetchDashboards]);\n\n return {\n loading,\n error,\n dashboards,\n currentDashboard,\n fetchDashboards,\n fetchDashboard,\n createDashboard,\n updateDashboard,\n deleteDashboard,\n cloneDashboard,\n refetch,\n };\n}\n\nexport default useDashboardOperations;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useDashboardOperations.js","names":[],"sources":["../../../src/bigconsole/hooks/useDashboardOperations.ts"],"sourcesContent":["/**\n * useDashboardOperations Hook\n *\n * Provides CRUD operations for dashboards using GraphQL.\n */\n\nimport { useCallback, useState, useEffect } from 'react';\nimport { useApolloClient } from '@apollo/client/react';\nimport type { Dashboard, DashboardLayoutConfig, DashboardVisibility } from '../types';\nimport { useDashboardStore } from '../store';\nimport { createBigConsoleQuotaError, isBigConsoleQuotaError } from '../utils/quota';\nimport {\n ListDashboardsDocument,\n GetDashboardDocument,\n CreateDashboardDocument,\n UpdateDashboardDocument,\n DeleteDashboardDocument,\n CloneDashboardDocument,\n} from '../../generated/wspace-operations';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Lifecycle status of a dashboard (`Dashboard.status`, DashboardStatus enum).\n * DRAFT until it is published; ARCHIVED after a soft delete.\n */\nexport type DashboardListStatus = 'DRAFT' | 'PUBLISHED' | 'ARCHIVED';\n\nexport interface DashboardListItem {\n id: string;\n name: string;\n description?: string;\n category?: string;\n isPublic?: boolean;\n /** Undefined only if the field is missing from the response. */\n status?: DashboardListStatus;\n viewCount?: number;\n widgetCount?: number;\n createdAt: string;\n updatedAt: string;\n pageCount: number;\n}\n\ninterface CreateDashboardInput {\n name: string;\n description?: string;\n category?: string;\n layoutType?: string;\n tags?: string[];\n}\n\ninterface UpdateDashboardInput {\n id: string;\n name?: string;\n description?: string;\n category?: string;\n isPublic?: boolean;\n /** General access level (`BigConsoleUpdateDashboardInput.visibility`). */\n visibility?: DashboardVisibility;\n}\n\ninterface FetchDashboardOptions {\n /**\n * Silent refetch for live-canvas polling: do NOT toggle the global `loading`\n * flag (which would flash the page-level spinner) and do NOT surface a\n * transient fetch error (which would replace the board with the error screen).\n * The last good dashboard stays on screen if a poll fails.\n */\n silent?: boolean;\n}\n\ninterface DashboardOperationsResult {\n loading: boolean;\n error: Error | null;\n dashboards: DashboardListItem[];\n currentDashboard: Dashboard | null;\n\n // Operations\n fetchDashboards: (search?: string) => Promise<void>;\n fetchDashboard: (id: string, options?: FetchDashboardOptions) => Promise<Dashboard | null>;\n createDashboard: (input: CreateDashboardInput) => Promise<Dashboard | null>;\n updateDashboard: (input: UpdateDashboardInput) => Promise<Dashboard | null>;\n deleteDashboard: (id: string) => Promise<boolean>;\n cloneDashboard: (sourceDashboardId: string, name: string) => Promise<Dashboard | null>;\n refetch: () => Promise<void>;\n}\n\n// ============================================================================\n// Helper: Normalize dashboard from GraphQL response\n// ============================================================================\n\n// Raw GraphQL response shape for dashboard data\ninterface RawDashboardData {\n id: string;\n name?: string;\n description?: string;\n workspaceId?: string;\n isPublic?: boolean;\n isTemplate?: boolean;\n layout?: Record<string, unknown>;\n category?: string;\n status?: string;\n visibility?: string;\n viewCount?: number;\n widgetCount?: number;\n createdBy?: string;\n ownerId?: string;\n createdAt?: string;\n updatedAt?: string;\n pages?: {\n edges?: Array<{\n node: {\n id: string;\n dashboardId?: string;\n name?: string;\n order?: number;\n layout?: Record<string, unknown>;\n gridColumns?: number;\n createdAt?: string;\n updatedAt?: string;\n };\n }>;\n totalCount?: number;\n };\n}\n\n/**\n * Narrow the raw `visibility` string to the DashboardVisibility enum. An\n * unrecognised value yields `undefined`, which hides the general-access control\n * rather than showing a level the backend never returned.\n */\nfunction toDashboardVisibility(raw: string | undefined): DashboardVisibility | undefined {\n const upper = raw?.toUpperCase();\n return upper === 'PRIVATE' || upper === 'WORKSPACE' || upper === 'PUBLIC' ? upper : undefined;\n}\n\nfunction normalizeDashboard(data: RawDashboardData): Dashboard {\n const pages =\n data.pages?.edges?.map((edge) => ({\n id: edge.node.id,\n dashboardId: edge.node.dashboardId || data.id,\n name: edge.node.name,\n slug: edge.node.name?.toLowerCase().replace(/\\s+/g, '-') || '',\n order: edge.node.order || 0,\n layoutConfig: edge.node.layout || {},\n gridColumns: edge.node.gridColumns || 12,\n widgets: [], // Widgets loaded separately via useWidgetOperations\n createdAt: edge.node.createdAt || new Date().toISOString(),\n updatedAt: edge.node.updatedAt || new Date().toISOString(),\n })) || [];\n\n // GetDashboard caps pages at first:10 to stay under the gateway cost-limit\n // (see DashboardFullFields fragment / BOFF-2720). Surface a warning instead of\n // silently dropping pages if a dashboard ever exceeds the cap.\n const totalPages = data.pages?.totalCount ?? pages.length;\n if (totalPages > pages.length) {\n console.warn(\n `[bigconsole] Dashboard ${data.id} has ${totalPages} pages but only ${pages.length} were loaded ` +\n `(GetDashboard pages cap). Pages beyond the cap are not shown — see BOFF-2720.`\n );\n }\n\n return {\n id: data.id,\n workspaceId: data.workspaceId || '',\n name: data.name || 'Untitled Dashboard',\n description: data.description,\n slug: data.name?.toLowerCase().replace(/\\s+/g, '-') || '',\n isPublished: data.isPublic || false,\n isTemplate: data.isTemplate || false,\n // Selected by DashboardFullFields; it was parsed away here, so the share\n // dialog had no way to know the board's current general-access level.\n visibility: toDashboardVisibility(data.visibility),\n layoutConfig: (data.layout as unknown as DashboardLayoutConfig) || {\n columns: 12,\n rowHeight: 100,\n gap: 10,\n margin: [10, 10],\n containerPadding: [10, 10],\n },\n pages,\n translations: [],\n createdBy: data.createdBy || data.ownerId || '',\n createdAt: data.createdAt || new Date().toISOString(),\n updatedAt: data.updatedAt || new Date().toISOString(),\n };\n}\n\n/**\n * Narrow the raw `status` string to the DashboardStatus enum.\n *\n * The gateway returns the SCREAMING_SNAKE enum name, but normalising defensively\n * (rather than casting) means an unexpected value renders nothing instead of an\n * unstyled badge claiming a status the backend never defined.\n */\nfunction toDashboardListStatus(raw: string | undefined): DashboardListStatus | undefined {\n const upper = raw?.toUpperCase();\n return upper === 'DRAFT' || upper === 'PUBLISHED' || upper === 'ARCHIVED' ? upper : undefined;\n}\n\nfunction normalizeDashboardListItem(data: RawDashboardData): DashboardListItem {\n // The list query selects only pages.totalCount (no edges) to stay under the\n // gateway Armor cost-limit — see DashboardListItem fragment / BOFF-2719.\n return {\n id: data.id,\n name: data.name || 'Untitled Dashboard',\n description: data.description,\n category: data.category,\n isPublic: data.isPublic,\n status: toDashboardListStatus(data.status),\n viewCount: data.viewCount,\n widgetCount: data.widgetCount,\n createdAt: data.createdAt || new Date().toISOString(),\n updatedAt: data.updatedAt || new Date().toISOString(),\n pageCount: data.pages?.totalCount ?? 0,\n };\n}\n\n// ============================================================================\n// Hook\n// ============================================================================\n\nexport interface UseDashboardOperationsOptions {\n /**\n * Skip the mount-time `listDashboards` fetch. For callers that only need a\n * mutation (e.g. the share dialog changing visibility) and must not pull the\n * whole dashboard list to do it.\n */\n skipFetch?: boolean;\n}\n\nexport function useDashboardOperations({\n skipFetch = false,\n}: UseDashboardOperationsOptions = {}): DashboardOperationsResult {\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [dashboards, setDashboards] = useState<DashboardListItem[]>([]);\n\n // Get Apollo Client - will throw if not in ApolloProvider context\n const apolloClient = useApolloClient();\n\n // Store actions\n const currentDashboard = useDashboardStore((state) => state.currentDashboard);\n const setCurrentDashboard = useDashboardStore((state) => state.setCurrentDashboard);\n\n // Fetch dashboards list\n const fetchDashboards = useCallback(\n async (search?: string) => {\n try {\n setLoading(true);\n setError(null);\n\n const result = await apolloClient.query<{ listDashboards?: { edges?: Array<{ node: RawDashboardData }> } }>({\n query: ListDashboardsDocument,\n variables: {\n first: 50,\n search,\n includeArchived: false,\n },\n fetchPolicy: 'network-only',\n });\n\n const edges = result.data?.listDashboards?.edges || [];\n const dashboardsList = edges.map((edge) => normalizeDashboardListItem(edge.node));\n setDashboards(dashboardsList);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to fetch dashboards');\n setError(error);\n } finally {\n setLoading(false);\n }\n },\n [apolloClient]\n );\n\n // Fetch single dashboard\n const fetchDashboard = useCallback(\n async (id: string, options?: FetchDashboardOptions): Promise<Dashboard | null> => {\n const silent = options?.silent ?? false;\n try {\n if (!silent) {\n setLoading(true);\n setError(null);\n }\n\n const result = await apolloClient.query<{ getDashboard?: RawDashboardData }>({\n query: GetDashboardDocument,\n variables: { id },\n fetchPolicy: 'network-only',\n });\n\n if (result.data?.getDashboard) {\n const dashboard = normalizeDashboard(result.data.getDashboard);\n setCurrentDashboard(dashboard);\n return dashboard;\n }\n\n return null;\n } catch (err) {\n // Silent (live-poll) failures must not wipe the board or flip the page to\n // the error screen — keep the last good dashboard on screen.\n if (!silent) {\n const error = err instanceof Error ? err : new Error('Failed to fetch dashboard');\n setError(error);\n }\n return null;\n } finally {\n if (!silent) {\n setLoading(false);\n }\n }\n },\n [apolloClient, setCurrentDashboard]\n );\n\n // Create dashboard\n const createDashboard = useCallback(\n async (input: CreateDashboardInput): Promise<Dashboard | null> => {\n try {\n setLoading(true);\n setError(null);\n\n // Build mutation input\n // Note: Tags require Tag IDs from the Tags service. For now, tags are stored in metadata.\n // Full tag integration would require querying/creating tags via the Tags service first.\n const mutationInput: Record<string, unknown> = {\n name: input.name,\n description: input.description,\n category: input.category || 'CUSTOM',\n layout: input.layoutType || 'GRID',\n createDefaultPage: true,\n };\n\n // Store tags in metadata until full Tags service integration\n if (input.tags && input.tags.length > 0) {\n mutationInput.metadata = {\n tags: input.tags,\n };\n }\n\n const result = await apolloClient.mutate<{ createBigConsoleDashboard?: RawDashboardData }>({\n mutation: CreateDashboardDocument,\n variables: {\n input: mutationInput,\n },\n });\n\n if (isBigConsoleQuotaError(result)) {\n throw createBigConsoleQuotaError(result);\n }\n\n if (result.data?.createBigConsoleDashboard) {\n const newDashboard = normalizeDashboard(result.data.createBigConsoleDashboard);\n await fetchDashboards();\n return newDashboard;\n }\n\n return null;\n } catch (err) {\n if (isBigConsoleQuotaError(err)) {\n throw err;\n }\n const error = err instanceof Error ? err : new Error('Failed to create dashboard');\n setError(error);\n return null;\n } finally {\n setLoading(false);\n }\n },\n [apolloClient, fetchDashboards]\n );\n\n // Update dashboard\n const updateDashboard = useCallback(\n async (input: UpdateDashboardInput): Promise<Dashboard | null> => {\n try {\n setLoading(true);\n setError(null);\n\n const result = await apolloClient.mutate<{ updateBigConsoleDashboard?: RawDashboardData }>({\n mutation: UpdateDashboardDocument,\n variables: { input },\n });\n\n if (result.data?.updateBigConsoleDashboard) {\n const updatedDashboard = normalizeDashboard(result.data.updateBigConsoleDashboard);\n if (currentDashboard?.id === input.id) {\n setCurrentDashboard(updatedDashboard);\n }\n await fetchDashboards();\n return updatedDashboard;\n }\n\n return null;\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to update dashboard');\n setError(error);\n return null;\n } finally {\n setLoading(false);\n }\n },\n [apolloClient, currentDashboard?.id, setCurrentDashboard, fetchDashboards]\n );\n\n // Delete dashboard\n const deleteDashboard = useCallback(\n async (id: string): Promise<boolean> => {\n try {\n setLoading(true);\n setError(null);\n\n const result = await apolloClient.mutate<{ deleteBigConsoleDashboard?: boolean }>({\n mutation: DeleteDashboardDocument,\n variables: { id },\n });\n\n if (result.data?.deleteBigConsoleDashboard) {\n if (currentDashboard?.id === id) {\n setCurrentDashboard(null);\n }\n await fetchDashboards();\n return true;\n }\n\n return false;\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to delete dashboard');\n setError(error);\n return false;\n } finally {\n setLoading(false);\n }\n },\n [apolloClient, currentDashboard?.id, setCurrentDashboard, fetchDashboards]\n );\n\n // Clone dashboard (duplicate including widgets)\n const cloneDashboard = useCallback(\n async (sourceDashboardId: string, name: string): Promise<Dashboard | null> => {\n try {\n setLoading(true);\n setError(null);\n\n const result = await apolloClient.mutate<{ cloneDashboard?: RawDashboardData }>({\n mutation: CloneDashboardDocument,\n variables: {\n input: { sourceDashboardId, name, includeWidgets: true },\n },\n });\n\n if (isBigConsoleQuotaError(result)) {\n throw createBigConsoleQuotaError(result);\n }\n\n if (result.data?.cloneDashboard) {\n const cloned = normalizeDashboard(result.data.cloneDashboard);\n await fetchDashboards();\n return cloned;\n }\n\n return null;\n } catch (err) {\n if (isBigConsoleQuotaError(err)) {\n throw err;\n }\n const error = err instanceof Error ? err : new Error('Failed to clone dashboard');\n setError(error);\n return null;\n } finally {\n setLoading(false);\n }\n },\n [apolloClient, fetchDashboards]\n );\n\n // Refetch\n const refetch = useCallback(async () => {\n await fetchDashboards();\n }, [fetchDashboards]);\n\n // Fetch on mount (unless the caller only wants the mutations)\n useEffect(() => {\n if (skipFetch) return;\n fetchDashboards();\n }, [fetchDashboards, skipFetch]);\n\n return {\n loading,\n error,\n dashboards,\n currentDashboard,\n fetchDashboards,\n fetchDashboard,\n createDashboard,\n updateDashboard,\n deleteDashboard,\n cloneDashboard,\n refetch,\n };\n}\n\nexport default useDashboardOperations;\n"],"mappings":"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"}
|
|
@@ -14,8 +14,8 @@ import { BIGCONSOLE_PERMISSIONS as c } from "../../constants/permissions.js";
|
|
|
14
14
|
import { BuilderCanvas as ee } from "../components/builder/BuilderCanvas.js";
|
|
15
15
|
import { BuilderTopbar as te } from "../components/builder/BuilderTopbar.js";
|
|
16
16
|
import { DashboardEditorShell as l } from "../components/builder/DashboardEditorShell.js";
|
|
17
|
-
import "../components/builder/index.js";
|
|
18
17
|
import { findNextAvailablePosition as ne } from "../utils/widgetPositioning.js";
|
|
18
|
+
import "../components/builder/index.js";
|
|
19
19
|
import re from "../components/dashboard/DashboardCanvas.js";
|
|
20
20
|
import ie from "../components/dashboard/ExportDashboardDialog.js";
|
|
21
21
|
import "../components/dashboard/index.js";
|