@burdenoff/microfe-bigconsole 2026.812.2 → 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/customWidget/CustomWidgetBuilderSheet.js +44 -47
- package/dist/bigconsole/customWidget/CustomWidgetBuilderSheet.js.map +1 -1
- package/dist/bigconsole/customWidget/proposalSource.js +31 -24
- package/dist/bigconsole/customWidget/proposalSource.js.map +1 -1
- package/dist/bigconsole/hooks/useDashboardOperations.js +74 -64
- package/dist/bigconsole/hooks/useDashboardOperations.js.map +1 -1
- package/dist/bigconsole/hooks/useDataSinkOperations.js +2 -2
- package/dist/bigconsole/hooks/useDataSinkOperations.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
|
@@ -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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"}
|
|
@@ -49,7 +49,7 @@ function g(e) {
|
|
|
49
49
|
function _(_ = {}) {
|
|
50
50
|
let { workspaceId: v, skipFetch: y = !1 } = _, [b, x] = m(!1), [S, C] = m(null), w = h(), T = e((e) => e.dataSinks), E = e((e) => e.setDataSinks), D = e((e) => e.addDataSink), O = e((e) => e.updateDataSink), k = e((e) => e.removeDataSink), A = e((e) => e.setDataSinkRefreshing), j = p(() => Array.from(T.values()), [T]), M = d(async (e) => {
|
|
51
51
|
try {
|
|
52
|
-
x(!0), C(null);
|
|
52
|
+
x(!0), C(null), E([]);
|
|
53
53
|
let t = ((await w.query({
|
|
54
54
|
query: c,
|
|
55
55
|
variables: {
|
|
@@ -61,7 +61,7 @@ function _(_ = {}) {
|
|
|
61
61
|
})).data?.listDataSinks?.edges || []).map((e) => g(e.node));
|
|
62
62
|
return E(t), t;
|
|
63
63
|
} catch (e) {
|
|
64
|
-
return C(e instanceof Error ? e : /* @__PURE__ */ Error("Failed to fetch DataSinks")), [];
|
|
64
|
+
return C(e instanceof Error ? e : /* @__PURE__ */ Error("Failed to fetch DataSinks")), E([]), [];
|
|
65
65
|
} finally {
|
|
66
66
|
x(!1);
|
|
67
67
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useDataSinkOperations.js","names":[],"sources":["../../../src/bigconsole/hooks/useDataSinkOperations.ts"],"sourcesContent":["/**\n * DataSink Operations Hook\n *\n * Custom hook for DataSink CRUD operations with Apollo Client.\n * Integrates with the DataSink Zustand store for state management.\n */\n\nimport { useState, useMemo, useCallback, useEffect } from 'react';\nimport { useApolloClient } from '@apollo/client/react';\nimport { useDataSinkStore } from '../store/dataSinkStore';\nimport {\n ListDataSinksDocument,\n GetDataSinkDocument,\n GetDataSinkDataDocument,\n CreateDataSinkDocument,\n UpdateDataSinkDocument,\n DeleteDataSinkDocument,\n RefreshDataSinkDocument,\n InvalidateDataSinkCacheDocument,\n BatchCreateDataSinksDocument,\n BatchDeleteDataSinksDocument,\n} from '../../generated/wspace-operations';\nimport type { DataSink, DataSinkStatus, CreateDataSinkInput, UpdateDataSinkInput } from '../types';\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\ninterface UseDataSinkOperationsOptions {\n workspaceId?: string;\n skipFetch?: boolean;\n}\n\ninterface DataSinkFilters {\n status?: DataSinkStatus;\n isActive?: boolean;\n search?: string;\n}\n\ninterface RefreshDataSinkInput {\n id: string;\n forceRefresh?: boolean;\n}\n\ninterface InvalidateCacheResult {\n count: number;\n invalidatedIds: string[];\n success: boolean;\n message?: string;\n}\n\ninterface DataSinkDataResult {\n raw: unknown;\n extracted: unknown;\n cached: boolean;\n version: number;\n fetchedAt: string;\n // v3.0: pagination metadata (non-null totalCount only for array payloads).\n totalCount?: number | null;\n limit?: number | null;\n offset?: number | null;\n hasMore?: boolean | null;\n}\n\n// GraphQL Query/Mutation Result Types\ninterface ListDataSinksResult {\n listDataSinks?: {\n edges: Array<{ node: unknown }>;\n pageInfo?: { hasNextPage: boolean; endCursor?: string };\n };\n}\n\ninterface GetDataSinkResult {\n getDataSink?: unknown;\n}\n\ninterface GetDataSinkDataResult {\n getDataSinkData?: DataSinkDataResult;\n}\n\ninterface CreateDataSinkResult {\n createDataSink?: unknown;\n}\n\ninterface UpdateDataSinkResult {\n updateDataSink?: unknown;\n}\n\ninterface DeleteDataSinkResult {\n deleteDataSink?: boolean;\n}\n\ninterface RefreshDataSinkResult {\n refreshDataSink?: unknown;\n}\n\ninterface InvalidateDataSinkCacheResult {\n invalidateDataSinkCache?: InvalidateCacheResult;\n}\n\ninterface BatchCreateDataSinksResult {\n batchCreateDataSinks?: unknown[];\n}\n\ninterface BatchDeleteDataSinksResult {\n batchDeleteDataSinks?: Array<{ id: string; deletedAt: string }>;\n}\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\n/**\n * Normalize GraphQL response to DataSink type\n */\nfunction normalizeDataSink(data: unknown): DataSink {\n const raw = data as Record<string, unknown>;\n return {\n id: raw.id as string,\n workspaceId: raw.workspaceId as string,\n tenantId: raw.tenantId as string,\n name: (raw.name as string) || null,\n description: (raw.description as string) || null,\n key: raw.key as string,\n fluidGridsWorkflowId: (raw.fluidGridsWorkflowId as string) || null,\n fluidGridsWorkflowExecutionId: (raw.fluidGridsWorkflowExecutionId as string) || null,\n config: (raw.config as Record<string, unknown>) || null,\n data: (raw.data as Record<string, unknown>) || {},\n dataStats: (raw.dataStats as DataSink['dataStats']) || null,\n lastRefreshedAt: (raw.lastRefreshedAt as string) || new Date().toISOString(),\n lastRefreshedBy: (raw.lastRefreshedBy as string) || null,\n expiresAt: (raw.expiresAt as string) || null,\n nextRefreshAt: (raw.nextRefreshAt as string) || null,\n ttl: (raw.ttl as number) ?? 0,\n version: (raw.version as number) ?? 1,\n sizeBytes: (raw.sizeBytes as number) ?? 0,\n isActive: (raw.isActive as boolean) ?? true,\n fieldMaskingEnabled: (raw.fieldMaskingEnabled as boolean) ?? false,\n fieldMaskingRules: (raw.fieldMaskingRules as Record<string, unknown>) || null,\n status: (raw.status as DataSink['status']) || 'ready',\n statusChangedAt: (raw.statusChangedAt as string) || null,\n statusChangedBy: (raw.statusChangedBy as string) || null,\n setupState: (raw.setupState as DataSink['setupState']) || 'not_started',\n refresh: (raw.refresh as DataSink['refresh']) || null,\n exports: (raw.exports as DataSink['exports']) || null,\n alerts: (raw.alerts as DataSink['alerts']) || null,\n quota: (raw.quota as DataSink['quota']) || null,\n workflowLinks: raw.workflowLinks as DataSink['workflowLinks'],\n linkedWorkflowCount: raw.linkedWorkflowCount as number | undefined,\n metadata: (raw.metadata as Record<string, unknown>) || null,\n createdAt: raw.createdAt as string,\n createdBy: (raw.createdBy as string) || '',\n updatedAt: raw.updatedAt as string,\n updatedBy: (raw.updatedBy as string) || '',\n deletedAt: (raw.deletedAt as string) || null,\n deletedBy: (raw.deletedBy as string) || null,\n };\n}\n\n// ============================================================================\n// HOOK\n// ============================================================================\n\nexport function useDataSinkOperations(options: UseDataSinkOperationsOptions = {}) {\n const { workspaceId, skipFetch = false } = options;\n\n // Local state\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n // Apollo client\n const client = useApolloClient();\n\n // Store selectors and actions\n const dataSinksMap = useDataSinkStore((state) => state.dataSinks);\n const setDataSinks = useDataSinkStore((state) => state.setDataSinks);\n const addDataSink = useDataSinkStore((state) => state.addDataSink);\n const updateDataSinkInStore = useDataSinkStore((state) => state.updateDataSink);\n const removeDataSink = useDataSinkStore((state) => state.removeDataSink);\n const setDataSinkRefreshing = useDataSinkStore((state) => state.setDataSinkRefreshing);\n\n // Memoized array of datasinks\n const dataSinks = useMemo(() => Array.from(dataSinksMap.values()), [dataSinksMap]);\n\n // ============================================================================\n // OPERATIONS\n // ============================================================================\n\n /**\n * Fetch all datasinks with optional filters\n */\n const fetchDataSinks = useCallback(\n async (filters?: DataSinkFilters): Promise<DataSink[]> => {\n try {\n setLoading(true);\n setError(null);\n\n const result = await client.query<ListDataSinksResult>({\n query: ListDataSinksDocument,\n variables: {\n status: filters?.status,\n isActive: filters?.isActive,\n search: filters?.search,\n },\n fetchPolicy: 'network-only',\n });\n\n const edges = result.data?.listDataSinks?.edges || [];\n const normalized = edges.map((edge: { node: unknown }) => normalizeDataSink(edge.node));\n\n setDataSinks(normalized);\n return normalized;\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to fetch DataSinks');\n setError(error);\n return [];\n } finally {\n setLoading(false);\n }\n },\n [client, setDataSinks]\n );\n\n /**\n * Fetch a single datasink by ID\n */\n const fetchDataSink = useCallback(\n async (id: string): Promise<DataSink | null> => {\n try {\n setLoading(true);\n setError(null);\n\n const result = await client.query<GetDataSinkResult>({\n query: GetDataSinkDocument,\n variables: { id },\n fetchPolicy: 'network-only',\n });\n\n if (result.data?.getDataSink) {\n const normalized = normalizeDataSink(result.data.getDataSink);\n addDataSink(normalized);\n return normalized;\n }\n\n return null;\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to fetch DataSink');\n setError(error);\n return null;\n } finally {\n setLoading(false);\n }\n },\n [client, addDataSink]\n );\n\n /**\n * Get datasink data for preview\n */\n const getDataSinkData = useCallback(\n async (\n idOrKey: { id?: string; key?: string },\n options?: {\n dataPath?: string;\n forceRefresh?: boolean;\n // v3.0: server-side pagination + filter for array payloads.\n limit?: number;\n offset?: number;\n filter?: Array<{ field: string; op: string; value: unknown }>;\n }\n ): Promise<DataSinkDataResult | null> => {\n try {\n setLoading(true);\n setError(null);\n\n const result = await client.query<GetDataSinkDataResult>({\n query: GetDataSinkDataDocument,\n variables: {\n id: idOrKey.id,\n key: idOrKey.key,\n dataPath: options?.dataPath,\n forceRefresh: options?.forceRefresh,\n limit: options?.limit,\n offset: options?.offset,\n filter: options?.filter,\n },\n fetchPolicy: 'network-only',\n });\n\n return result.data?.getDataSinkData || null;\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to get DataSink data');\n setError(error);\n return null;\n } finally {\n setLoading(false);\n }\n },\n [client]\n );\n\n /**\n * Create a new datasink\n */\n const createDataSink = useCallback(\n async (input: CreateDataSinkInput): Promise<DataSink | null> => {\n try {\n setLoading(true);\n setError(null);\n\n const result = await client.mutate<CreateDataSinkResult>({\n mutation: CreateDataSinkDocument,\n variables: { input },\n });\n\n if (result.data?.createDataSink) {\n const normalized = normalizeDataSink(result.data.createDataSink);\n addDataSink(normalized);\n return normalized;\n }\n\n return null;\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to create DataSink');\n setError(error);\n return null;\n } finally {\n setLoading(false);\n }\n },\n [client, addDataSink]\n );\n\n /**\n * Update an existing datasink\n */\n const updateDataSink = useCallback(\n async (input: UpdateDataSinkInput): Promise<DataSink | null> => {\n try {\n setLoading(true);\n setError(null);\n\n const result = await client.mutate<UpdateDataSinkResult>({\n mutation: UpdateDataSinkDocument,\n variables: { input },\n });\n\n if (result.data?.updateDataSink) {\n const normalized = normalizeDataSink(result.data.updateDataSink);\n updateDataSinkInStore(normalized.id, normalized);\n return normalized;\n }\n\n return null;\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to update DataSink');\n setError(error);\n return null;\n } finally {\n setLoading(false);\n }\n },\n [client, updateDataSinkInStore]\n );\n\n /**\n * Delete a datasink\n */\n const deleteDataSink = useCallback(\n async (id: string): Promise<boolean> => {\n try {\n setLoading(true);\n setError(null);\n\n const result = await client.mutate<DeleteDataSinkResult>({\n mutation: DeleteDataSinkDocument,\n variables: { id },\n });\n\n if (result.data?.deleteDataSink) {\n removeDataSink(id);\n return true;\n }\n\n return false;\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to delete DataSink');\n setError(error);\n return false;\n } finally {\n setLoading(false);\n }\n },\n [client, removeDataSink]\n );\n\n /**\n * Refresh a datasink's data\n */\n const refreshDataSink = useCallback(\n async (input: RefreshDataSinkInput): Promise<DataSink | null> => {\n try {\n setLoading(true);\n setError(null);\n\n if (input.id) {\n setDataSinkRefreshing(input.id, true);\n }\n\n const result = await client.mutate<RefreshDataSinkResult>({\n mutation: RefreshDataSinkDocument,\n variables: { input },\n });\n\n if (result.data?.refreshDataSink) {\n const normalized = normalizeDataSink(result.data.refreshDataSink);\n updateDataSinkInStore(normalized.id, normalized);\n setDataSinkRefreshing(normalized.id, false);\n return normalized;\n }\n\n return null;\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to refresh DataSink');\n setError(error);\n if (input.id) {\n setDataSinkRefreshing(input.id, false);\n }\n return null;\n } finally {\n setLoading(false);\n }\n },\n [client, updateDataSinkInStore, setDataSinkRefreshing]\n );\n\n /**\n * Invalidate datasink cache\n */\n const invalidateCache = useCallback(\n async (id?: string): Promise<InvalidateCacheResult> => {\n try {\n setLoading(true);\n setError(null);\n\n const result = await client.mutate<InvalidateDataSinkCacheResult>({\n mutation: InvalidateDataSinkCacheDocument,\n variables: {\n id,\n },\n });\n\n return (\n result.data?.invalidateDataSinkCache || {\n count: 0,\n invalidatedIds: [],\n success: false,\n }\n );\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to invalidate cache');\n setError(error);\n return {\n count: 0,\n invalidatedIds: [],\n success: false,\n message: error.message,\n };\n } finally {\n setLoading(false);\n }\n },\n [client, workspaceId]\n );\n\n /**\n * Batch create datasinks\n */\n const batchCreateDataSinks = useCallback(\n async (inputs: CreateDataSinkInput[]): Promise<DataSink[]> => {\n try {\n setLoading(true);\n setError(null);\n\n const result = await client.mutate<BatchCreateDataSinksResult>({\n mutation: BatchCreateDataSinksDocument,\n variables: { inputs },\n });\n\n if (result.data?.batchCreateDataSinks) {\n const normalized = result.data.batchCreateDataSinks.map(normalizeDataSink);\n normalized.forEach(addDataSink);\n return normalized;\n }\n\n return [];\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to batch create DataSinks');\n setError(error);\n return [];\n } finally {\n setLoading(false);\n }\n },\n [client, addDataSink]\n );\n\n /**\n * Batch delete datasinks\n */\n const batchDeleteDataSinks = useCallback(\n async (ids: string[]): Promise<{ id: string; deletedAt: string }[]> => {\n try {\n setLoading(true);\n setError(null);\n\n const result = await client.mutate<BatchDeleteDataSinksResult>({\n mutation: BatchDeleteDataSinksDocument,\n variables: { ids },\n });\n\n if (result.data?.batchDeleteDataSinks) {\n ids.forEach(removeDataSink);\n return result.data.batchDeleteDataSinks;\n }\n\n return [];\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to batch delete DataSinks');\n setError(error);\n return [];\n } finally {\n setLoading(false);\n }\n },\n [client, removeDataSink]\n );\n\n /**\n * Refetch all datasinks\n */\n const refetch = useCallback(async () => {\n await fetchDataSinks();\n }, [fetchDataSinks]);\n\n // Auto-fetch on mount if not skipped\n useEffect(() => {\n if (!skipFetch) {\n fetchDataSinks();\n }\n }, [skipFetch, fetchDataSinks]);\n\n return {\n loading,\n error,\n dataSinks,\n fetchDataSinks,\n fetchDataSink,\n getDataSinkData,\n createDataSink,\n updateDataSink,\n deleteDataSink,\n refreshDataSink,\n invalidateCache,\n batchCreateDataSinks,\n batchDeleteDataSinks,\n refetch,\n };\n}\n\nexport default useDataSinkOperations;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useDataSinkOperations.js","names":[],"sources":["../../../src/bigconsole/hooks/useDataSinkOperations.ts"],"sourcesContent":["/**\n * DataSink Operations Hook\n *\n * Custom hook for DataSink CRUD operations with Apollo Client.\n * Integrates with the DataSink Zustand store for state management.\n */\n\nimport { useState, useMemo, useCallback, useEffect } from 'react';\nimport { useApolloClient } from '@apollo/client/react';\nimport { useDataSinkStore } from '../store/dataSinkStore';\nimport {\n ListDataSinksDocument,\n GetDataSinkDocument,\n GetDataSinkDataDocument,\n CreateDataSinkDocument,\n UpdateDataSinkDocument,\n DeleteDataSinkDocument,\n RefreshDataSinkDocument,\n InvalidateDataSinkCacheDocument,\n BatchCreateDataSinksDocument,\n BatchDeleteDataSinksDocument,\n} from '../../generated/wspace-operations';\nimport type { DataSink, DataSinkStatus, CreateDataSinkInput, UpdateDataSinkInput } from '../types';\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\ninterface UseDataSinkOperationsOptions {\n workspaceId?: string;\n skipFetch?: boolean;\n}\n\ninterface DataSinkFilters {\n status?: DataSinkStatus;\n isActive?: boolean;\n search?: string;\n}\n\ninterface RefreshDataSinkInput {\n id: string;\n forceRefresh?: boolean;\n}\n\ninterface InvalidateCacheResult {\n count: number;\n invalidatedIds: string[];\n success: boolean;\n message?: string;\n}\n\ninterface DataSinkDataResult {\n raw: unknown;\n extracted: unknown;\n cached: boolean;\n version: number;\n fetchedAt: string;\n // v3.0: pagination metadata (non-null totalCount only for array payloads).\n totalCount?: number | null;\n limit?: number | null;\n offset?: number | null;\n hasMore?: boolean | null;\n}\n\n// GraphQL Query/Mutation Result Types\ninterface ListDataSinksResult {\n listDataSinks?: {\n edges: Array<{ node: unknown }>;\n pageInfo?: { hasNextPage: boolean; endCursor?: string };\n };\n}\n\ninterface GetDataSinkResult {\n getDataSink?: unknown;\n}\n\ninterface GetDataSinkDataResult {\n getDataSinkData?: DataSinkDataResult;\n}\n\ninterface CreateDataSinkResult {\n createDataSink?: unknown;\n}\n\ninterface UpdateDataSinkResult {\n updateDataSink?: unknown;\n}\n\ninterface DeleteDataSinkResult {\n deleteDataSink?: boolean;\n}\n\ninterface RefreshDataSinkResult {\n refreshDataSink?: unknown;\n}\n\ninterface InvalidateDataSinkCacheResult {\n invalidateDataSinkCache?: InvalidateCacheResult;\n}\n\ninterface BatchCreateDataSinksResult {\n batchCreateDataSinks?: unknown[];\n}\n\ninterface BatchDeleteDataSinksResult {\n batchDeleteDataSinks?: Array<{ id: string; deletedAt: string }>;\n}\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\n/**\n * Normalize GraphQL response to DataSink type\n */\nfunction normalizeDataSink(data: unknown): DataSink {\n const raw = data as Record<string, unknown>;\n return {\n id: raw.id as string,\n workspaceId: raw.workspaceId as string,\n tenantId: raw.tenantId as string,\n name: (raw.name as string) || null,\n description: (raw.description as string) || null,\n key: raw.key as string,\n fluidGridsWorkflowId: (raw.fluidGridsWorkflowId as string) || null,\n fluidGridsWorkflowExecutionId: (raw.fluidGridsWorkflowExecutionId as string) || null,\n config: (raw.config as Record<string, unknown>) || null,\n data: (raw.data as Record<string, unknown>) || {},\n dataStats: (raw.dataStats as DataSink['dataStats']) || null,\n lastRefreshedAt: (raw.lastRefreshedAt as string) || new Date().toISOString(),\n lastRefreshedBy: (raw.lastRefreshedBy as string) || null,\n expiresAt: (raw.expiresAt as string) || null,\n nextRefreshAt: (raw.nextRefreshAt as string) || null,\n ttl: (raw.ttl as number) ?? 0,\n version: (raw.version as number) ?? 1,\n sizeBytes: (raw.sizeBytes as number) ?? 0,\n isActive: (raw.isActive as boolean) ?? true,\n fieldMaskingEnabled: (raw.fieldMaskingEnabled as boolean) ?? false,\n fieldMaskingRules: (raw.fieldMaskingRules as Record<string, unknown>) || null,\n status: (raw.status as DataSink['status']) || 'ready',\n statusChangedAt: (raw.statusChangedAt as string) || null,\n statusChangedBy: (raw.statusChangedBy as string) || null,\n setupState: (raw.setupState as DataSink['setupState']) || 'not_started',\n refresh: (raw.refresh as DataSink['refresh']) || null,\n exports: (raw.exports as DataSink['exports']) || null,\n alerts: (raw.alerts as DataSink['alerts']) || null,\n quota: (raw.quota as DataSink['quota']) || null,\n workflowLinks: raw.workflowLinks as DataSink['workflowLinks'],\n linkedWorkflowCount: raw.linkedWorkflowCount as number | undefined,\n metadata: (raw.metadata as Record<string, unknown>) || null,\n createdAt: raw.createdAt as string,\n createdBy: (raw.createdBy as string) || '',\n updatedAt: raw.updatedAt as string,\n updatedBy: (raw.updatedBy as string) || '',\n deletedAt: (raw.deletedAt as string) || null,\n deletedBy: (raw.deletedBy as string) || null,\n };\n}\n\n// ============================================================================\n// HOOK\n// ============================================================================\n\nexport function useDataSinkOperations(options: UseDataSinkOperationsOptions = {}) {\n const { workspaceId, skipFetch = false } = options;\n\n // Local state\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n // Apollo client\n const client = useApolloClient();\n\n // Store selectors and actions\n const dataSinksMap = useDataSinkStore((state) => state.dataSinks);\n const setDataSinks = useDataSinkStore((state) => state.setDataSinks);\n const addDataSink = useDataSinkStore((state) => state.addDataSink);\n const updateDataSinkInStore = useDataSinkStore((state) => state.updateDataSink);\n const removeDataSink = useDataSinkStore((state) => state.removeDataSink);\n const setDataSinkRefreshing = useDataSinkStore((state) => state.setDataSinkRefreshing);\n\n // Memoized array of datasinks\n const dataSinks = useMemo(() => Array.from(dataSinksMap.values()), [dataSinksMap]);\n\n // ============================================================================\n // OPERATIONS\n // ============================================================================\n\n /**\n * Fetch all datasinks with optional filters\n */\n const fetchDataSinks = useCallback(\n async (filters?: DataSinkFilters): Promise<DataSink[]> => {\n try {\n setLoading(true);\n setError(null);\n // Fail closed while the authoritative workspace list is refreshed.\n // A persisted Zustand snapshot may contain sinks deleted by another\n // tab, an API client, or an E2E harness; proposal pickers must never\n // bind to those stale records while this network request is pending.\n setDataSinks([]);\n\n const result = await client.query<ListDataSinksResult>({\n query: ListDataSinksDocument,\n variables: {\n status: filters?.status,\n isActive: filters?.isActive,\n search: filters?.search,\n },\n fetchPolicy: 'network-only',\n });\n\n const edges = result.data?.listDataSinks?.edges || [];\n const normalized = edges.map((edge: { node: unknown }) => normalizeDataSink(edge.node));\n\n setDataSinks(normalized);\n return normalized;\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to fetch DataSinks');\n setError(error);\n // Do not retain a previously permitted resource set after an auth,\n // workspace-context, or network failure.\n setDataSinks([]);\n return [];\n } finally {\n setLoading(false);\n }\n },\n [client, setDataSinks]\n );\n\n /**\n * Fetch a single datasink by ID\n */\n const fetchDataSink = useCallback(\n async (id: string): Promise<DataSink | null> => {\n try {\n setLoading(true);\n setError(null);\n\n const result = await client.query<GetDataSinkResult>({\n query: GetDataSinkDocument,\n variables: { id },\n fetchPolicy: 'network-only',\n });\n\n if (result.data?.getDataSink) {\n const normalized = normalizeDataSink(result.data.getDataSink);\n addDataSink(normalized);\n return normalized;\n }\n\n return null;\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to fetch DataSink');\n setError(error);\n return null;\n } finally {\n setLoading(false);\n }\n },\n [client, addDataSink]\n );\n\n /**\n * Get datasink data for preview\n */\n const getDataSinkData = useCallback(\n async (\n idOrKey: { id?: string; key?: string },\n options?: {\n dataPath?: string;\n forceRefresh?: boolean;\n // v3.0: server-side pagination + filter for array payloads.\n limit?: number;\n offset?: number;\n filter?: Array<{ field: string; op: string; value: unknown }>;\n }\n ): Promise<DataSinkDataResult | null> => {\n try {\n setLoading(true);\n setError(null);\n\n const result = await client.query<GetDataSinkDataResult>({\n query: GetDataSinkDataDocument,\n variables: {\n id: idOrKey.id,\n key: idOrKey.key,\n dataPath: options?.dataPath,\n forceRefresh: options?.forceRefresh,\n limit: options?.limit,\n offset: options?.offset,\n filter: options?.filter,\n },\n fetchPolicy: 'network-only',\n });\n\n return result.data?.getDataSinkData || null;\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to get DataSink data');\n setError(error);\n return null;\n } finally {\n setLoading(false);\n }\n },\n [client]\n );\n\n /**\n * Create a new datasink\n */\n const createDataSink = useCallback(\n async (input: CreateDataSinkInput): Promise<DataSink | null> => {\n try {\n setLoading(true);\n setError(null);\n\n const result = await client.mutate<CreateDataSinkResult>({\n mutation: CreateDataSinkDocument,\n variables: { input },\n });\n\n if (result.data?.createDataSink) {\n const normalized = normalizeDataSink(result.data.createDataSink);\n addDataSink(normalized);\n return normalized;\n }\n\n return null;\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to create DataSink');\n setError(error);\n return null;\n } finally {\n setLoading(false);\n }\n },\n [client, addDataSink]\n );\n\n /**\n * Update an existing datasink\n */\n const updateDataSink = useCallback(\n async (input: UpdateDataSinkInput): Promise<DataSink | null> => {\n try {\n setLoading(true);\n setError(null);\n\n const result = await client.mutate<UpdateDataSinkResult>({\n mutation: UpdateDataSinkDocument,\n variables: { input },\n });\n\n if (result.data?.updateDataSink) {\n const normalized = normalizeDataSink(result.data.updateDataSink);\n updateDataSinkInStore(normalized.id, normalized);\n return normalized;\n }\n\n return null;\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to update DataSink');\n setError(error);\n return null;\n } finally {\n setLoading(false);\n }\n },\n [client, updateDataSinkInStore]\n );\n\n /**\n * Delete a datasink\n */\n const deleteDataSink = useCallback(\n async (id: string): Promise<boolean> => {\n try {\n setLoading(true);\n setError(null);\n\n const result = await client.mutate<DeleteDataSinkResult>({\n mutation: DeleteDataSinkDocument,\n variables: { id },\n });\n\n if (result.data?.deleteDataSink) {\n removeDataSink(id);\n return true;\n }\n\n return false;\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to delete DataSink');\n setError(error);\n return false;\n } finally {\n setLoading(false);\n }\n },\n [client, removeDataSink]\n );\n\n /**\n * Refresh a datasink's data\n */\n const refreshDataSink = useCallback(\n async (input: RefreshDataSinkInput): Promise<DataSink | null> => {\n try {\n setLoading(true);\n setError(null);\n\n if (input.id) {\n setDataSinkRefreshing(input.id, true);\n }\n\n const result = await client.mutate<RefreshDataSinkResult>({\n mutation: RefreshDataSinkDocument,\n variables: { input },\n });\n\n if (result.data?.refreshDataSink) {\n const normalized = normalizeDataSink(result.data.refreshDataSink);\n updateDataSinkInStore(normalized.id, normalized);\n setDataSinkRefreshing(normalized.id, false);\n return normalized;\n }\n\n return null;\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to refresh DataSink');\n setError(error);\n if (input.id) {\n setDataSinkRefreshing(input.id, false);\n }\n return null;\n } finally {\n setLoading(false);\n }\n },\n [client, updateDataSinkInStore, setDataSinkRefreshing]\n );\n\n /**\n * Invalidate datasink cache\n */\n const invalidateCache = useCallback(\n async (id?: string): Promise<InvalidateCacheResult> => {\n try {\n setLoading(true);\n setError(null);\n\n const result = await client.mutate<InvalidateDataSinkCacheResult>({\n mutation: InvalidateDataSinkCacheDocument,\n variables: {\n id,\n },\n });\n\n return (\n result.data?.invalidateDataSinkCache || {\n count: 0,\n invalidatedIds: [],\n success: false,\n }\n );\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to invalidate cache');\n setError(error);\n return {\n count: 0,\n invalidatedIds: [],\n success: false,\n message: error.message,\n };\n } finally {\n setLoading(false);\n }\n },\n [client, workspaceId]\n );\n\n /**\n * Batch create datasinks\n */\n const batchCreateDataSinks = useCallback(\n async (inputs: CreateDataSinkInput[]): Promise<DataSink[]> => {\n try {\n setLoading(true);\n setError(null);\n\n const result = await client.mutate<BatchCreateDataSinksResult>({\n mutation: BatchCreateDataSinksDocument,\n variables: { inputs },\n });\n\n if (result.data?.batchCreateDataSinks) {\n const normalized = result.data.batchCreateDataSinks.map(normalizeDataSink);\n normalized.forEach(addDataSink);\n return normalized;\n }\n\n return [];\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to batch create DataSinks');\n setError(error);\n return [];\n } finally {\n setLoading(false);\n }\n },\n [client, addDataSink]\n );\n\n /**\n * Batch delete datasinks\n */\n const batchDeleteDataSinks = useCallback(\n async (ids: string[]): Promise<{ id: string; deletedAt: string }[]> => {\n try {\n setLoading(true);\n setError(null);\n\n const result = await client.mutate<BatchDeleteDataSinksResult>({\n mutation: BatchDeleteDataSinksDocument,\n variables: { ids },\n });\n\n if (result.data?.batchDeleteDataSinks) {\n ids.forEach(removeDataSink);\n return result.data.batchDeleteDataSinks;\n }\n\n return [];\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to batch delete DataSinks');\n setError(error);\n return [];\n } finally {\n setLoading(false);\n }\n },\n [client, removeDataSink]\n );\n\n /**\n * Refetch all datasinks\n */\n const refetch = useCallback(async () => {\n await fetchDataSinks();\n }, [fetchDataSinks]);\n\n // Auto-fetch on mount if not skipped\n useEffect(() => {\n if (!skipFetch) {\n fetchDataSinks();\n }\n }, [skipFetch, fetchDataSinks]);\n\n return {\n loading,\n error,\n dataSinks,\n fetchDataSinks,\n fetchDataSink,\n getDataSinkData,\n createDataSink,\n updateDataSink,\n deleteDataSink,\n refreshDataSink,\n invalidateCache,\n batchCreateDataSinks,\n batchDeleteDataSinks,\n refetch,\n };\n}\n\nexport default useDataSinkOperations;\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";
|