@burdenoff/microfe-bigconsole 2026.1001.4 → 2026.1004.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.
Files changed (39) hide show
  1. package/dist/bigconsole/components/dashboard/CreateDashboardDialog.d.ts.map +1 -1
  2. package/dist/bigconsole/components/dashboard/CreateDashboardDialog.js +220 -161
  3. package/dist/bigconsole/components/dashboard/CreateDashboardDialog.js.map +1 -1
  4. package/dist/bigconsole/components/dashboard/TemplateInstallOptions.d.ts +11 -0
  5. package/dist/bigconsole/components/dashboard/TemplateInstallOptions.d.ts.map +1 -0
  6. package/dist/bigconsole/components/dashboard/TemplateInstallOptions.js +208 -0
  7. package/dist/bigconsole/components/dashboard/TemplateInstallOptions.js.map +1 -0
  8. package/dist/bigconsole/components/dashboard/TemplateLayoutPreview.d.ts +7 -0
  9. package/dist/bigconsole/components/dashboard/TemplateLayoutPreview.d.ts.map +1 -0
  10. package/dist/bigconsole/components/dashboard/TemplateLayoutPreview.js +51 -0
  11. package/dist/bigconsole/components/dashboard/TemplateLayoutPreview.js.map +1 -0
  12. package/dist/bigconsole/hooks/useStoreDashboardTemplates.d.ts +2 -0
  13. package/dist/bigconsole/hooks/useStoreDashboardTemplates.d.ts.map +1 -1
  14. package/dist/bigconsole/hooks/useStoreDashboardTemplates.js +91 -90
  15. package/dist/bigconsole/hooks/useStoreDashboardTemplates.js.map +1 -1
  16. package/dist/bigconsole/pages/DashboardsPage.d.ts.map +1 -1
  17. package/dist/bigconsole/pages/DashboardsPage.js +25 -20
  18. package/dist/bigconsole/pages/DashboardsPage.js.map +1 -1
  19. package/dist/bigconsole/pages/DataSinkBuilderPage.js +1 -0
  20. package/dist/bigconsole/pages/DataSinkBuilderPage.js.map +1 -1
  21. package/dist/bigconsole/pages/InsightsPage.js +1 -0
  22. package/dist/bigconsole/pages/InsightsPage.js.map +1 -1
  23. package/dist/bigconsole/pages/ParserBuilderPage.js +1 -0
  24. package/dist/bigconsole/pages/ParserBuilderPage.js.map +1 -1
  25. package/dist/bigconsole/pages/WorkflowsPage.js +1 -0
  26. package/dist/bigconsole/pages/WorkflowsPage.js.map +1 -1
  27. package/dist/bigconsole/utils/dashboardTemplateContent.d.ts +10 -0
  28. package/dist/bigconsole/utils/dashboardTemplateContent.d.ts.map +1 -0
  29. package/dist/bigconsole/utils/dashboardTemplateContent.js +36 -0
  30. package/dist/bigconsole/utils/dashboardTemplateContent.js.map +1 -0
  31. package/dist/bigconsole/utils/templateInstallInputs.d.ts +5 -0
  32. package/dist/bigconsole/utils/templateInstallInputs.d.ts.map +1 -0
  33. package/dist/bigconsole/utils/templateInstallInputs.js +22 -0
  34. package/dist/bigconsole/utils/templateInstallInputs.js.map +1 -0
  35. package/dist/generated/global-operations.d.ts +1 -0
  36. package/dist/generated/global-operations.d.ts.map +1 -1
  37. package/dist/generated/global-operations.js +1 -0
  38. package/dist/generated/global-operations.js.map +1 -1
  39. package/package.json +1 -1
@@ -1,10 +1,11 @@
1
- import { BrowseDashboardTemplatesDocument as e, CreateDashboardTemplateAppDocument as t, CreateDashboardTemplateVersionDocument as n, GetDashboardTemplateDetailDocument as r } from "../../generated/global-operations.js";
2
- import { BUILD_DASHBOARD_TEMPLATE_CONTENT as i, IMPORT_DASHBOARD_TEMPLATE as a } from "../graphql/storeTemplates.js";
3
- import { useCallback as o, useEffect as s, useMemo as c, useState as l } from "react";
4
- import { useApolloClient as u } from "@apollo/client/react";
5
- import { useGatewayClient as d } from "@burdenoff/fe-libs/shared/graphql";
1
+ import { isInstallableDashboardTemplate as e, withDashboardTemplateMetadata as t } from "../utils/dashboardTemplateContent.js";
2
+ import { BrowseDashboardTemplatesDocument as n, CreateDashboardTemplateAppDocument as r, CreateDashboardTemplateVersionDocument as i, GetDashboardTemplateDetailDocument as a } from "../../generated/global-operations.js";
3
+ import { BUILD_DASHBOARD_TEMPLATE_CONTENT as o, IMPORT_DASHBOARD_TEMPLATE as s } from "../graphql/storeTemplates.js";
4
+ import { useCallback as c, useEffect as l, useMemo as u, useState as d } from "react";
5
+ import { useApolloClient as f } from "@apollo/client/react";
6
+ import { useGatewayClient as p } from "@burdenoff/fe-libs/shared/graphql";
6
7
  //#region src/bigconsole/hooks/useStoreDashboardTemplates.ts
7
- function f(e) {
8
+ function m(e) {
8
9
  let t = e.pricingModel ?? "FREE";
9
10
  return {
10
11
  id: e.id,
@@ -22,20 +23,20 @@ function f(e) {
22
23
  requiresPurchase: t !== "FREE" && (e.price ?? 0) > 0
23
24
  };
24
25
  }
25
- function p(p = {}) {
26
- let { search: m, category: h, autoLoad: g = !0 } = p, _ = d("global"), v = u(), [y, b] = l([]), [x, S] = l(0), [C, w] = l(!1), [T, E] = l(null), D = o(async (t) => {
27
- if (_) {
28
- w(!0), E(null);
26
+ function h(h = {}) {
27
+ let { search: g, category: _, autoLoad: v = !0 } = h, y = p("global"), b = f(), [x, S] = d([]), [C, w] = d(0), [T, E] = d(!1), [D, O] = d(null), k = c(async (t) => {
28
+ if (y) {
29
+ E(!0), O(null);
29
30
  try {
30
- let n = await _.query({
31
- query: e,
31
+ let r = ((await y.query({
32
+ query: n,
32
33
  variables: { input: {
33
34
  filter: {
34
35
  type: "DASHBOARD",
35
36
  status: "PUBLISHED",
36
37
  compatibleWith: "bigconsole",
37
- ...t ?? m ? { search: t ?? m } : {},
38
- ...h && h !== "ALL" ? { category: h } : {}
38
+ ...t ?? g ? { search: t ?? g } : {},
39
+ ..._ && _ !== "ALL" ? { category: _ } : {}
39
40
  },
40
41
  sortBy: "RELEVANCE",
41
42
  pagination: {
@@ -44,50 +45,50 @@ function p(p = {}) {
44
45
  }
45
46
  } },
46
47
  fetchPolicy: "network-only"
47
- });
48
- b((n.data?.browseStore?.products ?? []).map(f)), S(n.data?.browseStore?.totalCount ?? 0);
48
+ })).data?.browseStore?.products ?? []).filter((t) => e(t.content));
49
+ S(r.map(m)), w(r.length);
49
50
  } catch (e) {
50
- E(e instanceof Error ? e.message : "Failed to load templates from the store"), b([]), S(0);
51
+ O(e instanceof Error ? e.message : "Failed to load templates from the store"), S([]), w(0);
51
52
  } finally {
52
- w(!1);
53
+ E(!1);
53
54
  }
54
55
  }
55
56
  }, [
56
- _,
57
- m,
58
- h
57
+ y,
58
+ g,
59
+ _
59
60
  ]);
60
- s(() => {
61
- g && D();
62
- }, [g, D]);
63
- let O = o(async (e) => {
64
- if (!_) return null;
61
+ l(() => {
62
+ v && k();
63
+ }, [v, k]);
64
+ let A = c(async (t) => {
65
+ if (!y) return null;
65
66
  try {
66
- let t = (await _.query({
67
- query: r,
68
- variables: { id: e },
67
+ let n = (await y.query({
68
+ query: a,
69
+ variables: { id: t },
69
70
  fetchPolicy: "network-only"
70
71
  })).data?.product?.content;
71
- if (!t || typeof t != "object") return null;
72
- let n = t;
73
- return n.definition ? {
74
- definition: n.definition,
75
- requiredDataSinks: n.requiredDataSinks ?? [],
76
- requiredWidgetTypes: n.requiredWidgetTypes ?? [],
77
- requiredInputs: n.requiredInputs ?? [],
78
- defaultDashboardName: n.defaultDashboardName,
79
- defaultCategory: n.defaultCategory ?? null,
80
- defaultTags: n.defaultTags ?? [],
81
- difficultyLevel: n.difficultyLevel ?? "medium"
72
+ if (!e(n)) return null;
73
+ let r = n;
74
+ return r.definition ? {
75
+ definition: r.definition,
76
+ requiredDataSinks: r.requiredDataSinks ?? [],
77
+ requiredWidgetTypes: r.requiredWidgetTypes ?? [],
78
+ requiredInputs: r.requiredInputs ?? [],
79
+ defaultDashboardName: r.defaultDashboardName,
80
+ defaultCategory: r.defaultCategory ?? null,
81
+ defaultTags: r.defaultTags ?? [],
82
+ difficultyLevel: r.difficultyLevel ?? "medium"
82
83
  } : null;
83
84
  } catch {
84
85
  return null;
85
86
  }
86
- }, [_]), k = o(async (e) => {
87
- let t = (await v.mutate({
88
- mutation: a,
87
+ }, [y]), j = c(async (e) => {
88
+ let n = (await b.mutate({
89
+ mutation: s,
89
90
  variables: { input: {
90
- content: e.content,
91
+ content: t(e.content, e),
91
92
  sourceTemplateId: e.templateId,
92
93
  sourceTemplateName: e.templateName,
93
94
  ...e.name ? { name: e.name } : {},
@@ -96,14 +97,14 @@ function p(p = {}) {
96
97
  ...e.inputValues && Object.keys(e.inputValues).length ? { inputValues: e.inputValues } : {}
97
98
  } }
98
99
  })).data?.importDashboardTemplate;
99
- return t ? {
100
- success: t.success,
101
- dashboardId: t.dashboard?.id,
102
- errorMessage: t.errorMessage,
103
- unresolvedSlots: t.unresolvedSlots ?? [],
104
- resolvedSlots: t.resolvedSlots ?? [],
105
- widgetsNeedingData: t.widgetsNeedingData ?? 0,
106
- warnings: t.warnings ?? []
100
+ return n ? {
101
+ success: n.success,
102
+ dashboardId: n.dashboard?.id,
103
+ errorMessage: n.errorMessage,
104
+ unresolvedSlots: n.unresolvedSlots ?? [],
105
+ resolvedSlots: n.resolvedSlots ?? [],
106
+ widgetsNeedingData: n.widgetsNeedingData ?? 0,
107
+ warnings: n.warnings ?? []
107
108
  } : {
108
109
  success: !1,
109
110
  errorMessage: "No response from the server",
@@ -112,19 +113,19 @@ function p(p = {}) {
112
113
  widgetsNeedingData: 0,
113
114
  warnings: []
114
115
  };
115
- }, [v]), A = o(async (e) => {
116
- let r = (e) => ({
116
+ }, [b]), M = c(async (e) => {
117
+ let t = (e) => ({
117
118
  success: !1,
118
119
  errorMessage: e,
119
120
  sinkCount: 0,
120
121
  unknownSinkIds: [],
121
122
  sampleDataSinkCount: 0
122
123
  });
123
- if (!_) return r("Store is unavailable right now.");
124
- let a, o = 0, s = [], c = 0;
124
+ if (!y) return t("Store is unavailable right now.");
125
+ let n, a = 0, s = [], c = 0;
125
126
  try {
126
- let t = (await v.query({
127
- query: i,
127
+ let r = (await b.query({
128
+ query: o,
128
129
  variables: {
129
130
  dashboardId: e.dashboardId,
130
131
  defaultDashboardName: e.name,
@@ -134,14 +135,14 @@ function p(p = {}) {
134
135
  },
135
136
  fetchPolicy: "network-only"
136
137
  })).data?.buildDashboardTemplateContent;
137
- if (!t?.content) return r("Could not build a template from this dashboard.");
138
- a = t.content, o = t.sinkCount, s = t.unknownSinkIds ?? [], c = t.sampleDataSinkCount ?? 0;
138
+ if (!r?.content) return t("Could not build a template from this dashboard.");
139
+ n = r.content, a = r.sinkCount, s = r.unknownSinkIds ?? [], c = r.sampleDataSinkCount ?? 0;
139
140
  } catch (e) {
140
- return r(e instanceof Error ? e.message : "Failed to build the template.");
141
+ return t(e instanceof Error ? e.message : "Failed to build the template.");
141
142
  }
142
143
  try {
143
- let i = (await _.mutate({
144
- mutation: t,
144
+ let o = (await y.mutate({
145
+ mutation: r,
145
146
  variables: { input: {
146
147
  appType: "DASHBOARD",
147
148
  name: e.name,
@@ -153,58 +154,58 @@ function p(p = {}) {
153
154
  compatibleProducts: ["bigconsole"]
154
155
  } }
155
156
  })).data?.createApplication;
156
- return i ? (await _.mutate({
157
- mutation: n,
157
+ return o ? (await y.mutate({
158
+ mutation: i,
158
159
  variables: {
159
- applicationId: i.id,
160
+ applicationId: o.id,
160
161
  input: {
161
162
  version: "1.0.0",
162
- manifest: a
163
+ manifest: n
163
164
  }
164
165
  }
165
166
  }), {
166
167
  success: !0,
167
- applicationId: i.id,
168
- status: i.status,
169
- sinkCount: o,
168
+ applicationId: o.id,
169
+ status: o.status,
170
+ sinkCount: a,
170
171
  unknownSinkIds: s,
171
172
  sampleDataSinkCount: c
172
173
  }) : {
173
- ...r("The developer portal did not create the app."),
174
- sinkCount: o,
174
+ ...t("The developer portal did not create the app."),
175
+ sinkCount: a,
175
176
  unknownSinkIds: s,
176
177
  sampleDataSinkCount: c
177
178
  };
178
179
  } catch (e) {
179
180
  return {
180
- ...r(e instanceof Error ? e.message : "Failed to publish to the developer portal."),
181
- sinkCount: o,
181
+ ...t(e instanceof Error ? e.message : "Failed to publish to the developer portal."),
182
+ sinkCount: a,
182
183
  unknownSinkIds: s,
183
184
  sampleDataSinkCount: c
184
185
  };
185
186
  }
186
- }, [_, v]);
187
- return c(() => ({
188
- templates: y,
189
- loading: C,
190
- error: T,
191
- totalCount: x,
192
- refetch: D,
193
- fetchTemplateContent: O,
194
- installTemplate: k,
195
- publishToStore: A
187
+ }, [y, b]);
188
+ return u(() => ({
189
+ templates: x,
190
+ loading: T,
191
+ error: D,
192
+ totalCount: C,
193
+ refetch: k,
194
+ fetchTemplateContent: A,
195
+ installTemplate: j,
196
+ publishToStore: M
196
197
  }), [
197
- y,
198
- C,
199
- T,
200
198
  x,
199
+ T,
201
200
  D,
202
- O,
201
+ C,
203
202
  k,
204
- A
203
+ A,
204
+ j,
205
+ M
205
206
  ]);
206
207
  }
207
208
  //#endregion
208
- export { p as default };
209
+ export { h as default };
209
210
 
210
211
  //# sourceMappingURL=useStoreDashboardTemplates.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useStoreDashboardTemplates.js","names":[],"sources":["../../../src/bigconsole/hooks/useStoreDashboardTemplates.ts"],"sourcesContent":["/**\n * Store-distributed dashboard templates.\n *\n * Dashboard templates live in the global store as `StoreProduct` rows of type\n * `DASHBOARD` whose `content` column holds a `DashboardTemplateContent`\n * document. This mirrors how FluidGrids sources its workflow templates\n * (`browseStore(type: WORKFLOW)` → `content.definitionJson` →\n * `importWorkflowTemplate`).\n *\n * Two gateways are involved: the catalog is read from the **global** gateway,\n * and the install mutation runs against the **workspace** gateway, which is\n * where the dashboard is created.\n *\n * @module bigconsole/hooks/useStoreDashboardTemplates\n */\nimport { useApolloClient } from '@apollo/client/react';\nimport { useGatewayClient } from '@burdenoff/fe-libs/shared/graphql';\nimport { useCallback, useEffect, useMemo, useState } from 'react';\n\nimport {\n BROWSE_DASHBOARD_TEMPLATES,\n BUILD_DASHBOARD_TEMPLATE_CONTENT,\n CREATE_TEMPLATE_APP,\n CREATE_TEMPLATE_VERSION,\n GET_DASHBOARD_TEMPLATE_DETAIL,\n IMPORT_DASHBOARD_TEMPLATE,\n} from '../graphql/storeTemplates';\n\n/** A column a widget expects from the sink bound to its slot. */\nexport interface TemplateExpectedField {\n name: string;\n role?: string;\n}\n\n/** A data-binding slot the template needs filled. */\nexport interface TemplateRequiredDataSink {\n slot: string;\n label: string;\n description?: string | null;\n expectedFields: TemplateExpectedField[];\n widgetTitles: string[];\n}\n\nexport interface TemplateRequiredWidgetType {\n widgetType: string;\n widgetTypeKey?: string | null;\n publishType: 'BUILTIN' | 'STORE' | 'CUSTOM';\n displayName?: string;\n requiresPurchase?: boolean;\n}\n\nexport interface TemplateRequiredInput {\n name: string;\n type: 'string' | 'number' | 'boolean' | 'select' | 'secret';\n label: string;\n placeholder?: string;\n required: boolean;\n defaultValue?: string | number | boolean | null;\n options?: { label: string; value: string }[];\n helpText?: string;\n}\n\nexport interface DashboardTemplateContent {\n definition: unknown;\n requiredDataSinks: TemplateRequiredDataSink[];\n requiredWidgetTypes: TemplateRequiredWidgetType[];\n requiredInputs: TemplateRequiredInput[];\n defaultDashboardName?: string;\n defaultCategory?: string | null;\n defaultTags?: string[];\n difficultyLevel?: 'easy' | 'medium' | 'hard';\n}\n\n/** A store product presented as a template card. */\nexport interface StoreDashboardTemplate {\n id: string;\n name: string;\n slug: string;\n description?: string | null;\n icon?: string | null;\n category?: string | null;\n tags: string[];\n featured: boolean;\n downloads: number;\n rating?: number | null;\n pricingModel: string;\n price: number;\n /** True for anything the workspace has to buy before it can be installed. */\n requiresPurchase: boolean;\n}\n\ninterface RawStoreProduct {\n id: string;\n name: string;\n slug: string;\n description?: string | null;\n icon?: string | null;\n category?: string | null;\n tags?: string[] | null;\n featured?: boolean | null;\n downloads?: number | null;\n rating?: number | null;\n pricingModel?: string | null;\n price?: number | null;\n}\n\nexport interface InstallTemplateArgs {\n templateId: string;\n templateName: string;\n content: DashboardTemplateContent;\n name?: string;\n visibility?: string;\n dataSinkBindings?: { slot: string; dataSinkId: string }[];\n inputValues?: Record<string, unknown>;\n}\n\nexport interface InstallTemplateResult {\n success: boolean;\n dashboardId?: string;\n errorMessage?: string;\n unresolvedSlots: string[];\n resolvedSlots: string[];\n widgetsNeedingData: number;\n warnings: string[];\n}\n\nfunction normalizeProduct(raw: RawStoreProduct): StoreDashboardTemplate {\n const pricingModel = raw.pricingModel ?? 'FREE';\n return {\n id: raw.id,\n name: raw.name,\n slug: raw.slug,\n description: raw.description ?? null,\n icon: raw.icon ?? null,\n category: raw.category ?? null,\n tags: raw.tags ?? [],\n featured: raw.featured ?? false,\n downloads: raw.downloads ?? 0,\n rating: raw.rating ?? null,\n pricingModel,\n price: raw.price ?? 0,\n requiresPurchase: pricingModel !== 'FREE' && (raw.price ?? 0) > 0,\n };\n}\n\nexport interface PublishToStoreArgs {\n dashboardId: string;\n name: string;\n slug: string;\n description: string;\n category?: string;\n tags?: string[];\n /** Embed a few real rows per data source so the board renders populated. */\n includeSampleData?: boolean;\n}\n\nexport interface PublishToStoreResult {\n success: boolean;\n /** The DRAFT devportal application created for this template. */\n applicationId?: string;\n status?: string;\n errorMessage?: string;\n /** Distinct data sinks the dashboard referenced, all tokenised into slots. */\n sinkCount: number;\n /** Sinks that could not be resolved; their slots fall back to positional names. */\n unknownSinkIds: string[];\n /** How many data sources contributed sample rows. */\n sampleDataSinkCount: number;\n}\n\nexport interface UseStoreDashboardTemplatesResult {\n templates: StoreDashboardTemplate[];\n loading: boolean;\n error: string | null;\n totalCount: number;\n refetch: (search?: string) => Promise<void>;\n /** Fetch the full template document. Kept lazy: content is large. */\n fetchTemplateContent: (templateId: string) => Promise<DashboardTemplateContent | null>;\n installTemplate: (args: InstallTemplateArgs) => Promise<InstallTemplateResult>;\n publishToStore: (args: PublishToStoreArgs) => Promise<PublishToStoreResult>;\n}\n\nexport function useStoreDashboardTemplates(\n options: { search?: string; category?: string; autoLoad?: boolean } = {}\n): UseStoreDashboardTemplatesResult {\n const { search, category, autoLoad = true } = options;\n\n const globalClient = useGatewayClient('global');\n const workspaceClient = useApolloClient();\n\n const [templates, setTemplates] = useState<StoreDashboardTemplate[]>([]);\n const [totalCount, setTotalCount] = useState(0);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const refetch = useCallback(\n async (overrideSearch?: string): Promise<void> => {\n if (!globalClient) return;\n setLoading(true);\n setError(null);\n try {\n const result = await globalClient.query<{\n browseStore?: { products?: RawStoreProduct[]; totalCount?: number };\n }>({\n query: BROWSE_DASHBOARD_TEMPLATES,\n variables: {\n input: {\n filter: {\n type: 'DASHBOARD',\n status: 'PUBLISHED',\n // Without this a template published from another product's\n // devportal listing would show up in BigConsole's gallery.\n compatibleWith: 'bigconsole',\n ...((overrideSearch ?? search) ? { search: overrideSearch ?? search } : {}),\n ...(category && category !== 'ALL' ? { category } : {}),\n },\n sortBy: 'RELEVANCE',\n pagination: { limit: 50, offset: 0 },\n },\n },\n fetchPolicy: 'network-only',\n });\n\n setTemplates((result.data?.browseStore?.products ?? []).map(normalizeProduct));\n setTotalCount(result.data?.browseStore?.totalCount ?? 0);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to load templates from the store');\n setTemplates([]);\n setTotalCount(0);\n } finally {\n setLoading(false);\n }\n },\n [globalClient, search, category]\n );\n\n useEffect(() => {\n if (autoLoad) void refetch();\n }, [autoLoad, refetch]);\n\n const fetchTemplateContent = useCallback(\n async (templateId: string): Promise<DashboardTemplateContent | null> => {\n if (!globalClient) return null;\n try {\n const result = await globalClient.query<{ product?: { content?: unknown } }>({\n query: GET_DASHBOARD_TEMPLATE_DETAIL,\n variables: { id: templateId },\n fetchPolicy: 'network-only',\n });\n const content = result.data?.product?.content;\n if (!content || typeof content !== 'object') return null;\n const doc = content as Partial<DashboardTemplateContent>;\n if (!doc.definition) return null;\n return {\n definition: doc.definition,\n requiredDataSinks: doc.requiredDataSinks ?? [],\n requiredWidgetTypes: doc.requiredWidgetTypes ?? [],\n requiredInputs: doc.requiredInputs ?? [],\n defaultDashboardName: doc.defaultDashboardName,\n defaultCategory: doc.defaultCategory ?? null,\n defaultTags: doc.defaultTags ?? [],\n difficultyLevel: doc.difficultyLevel ?? 'medium',\n };\n } catch {\n return null;\n }\n },\n [globalClient]\n );\n\n const installTemplate = useCallback(\n async (args: InstallTemplateArgs): Promise<InstallTemplateResult> => {\n const result = await workspaceClient.mutate<{\n importDashboardTemplate?: InstallTemplateResult & { dashboard?: { id: string } | null };\n }>({\n mutation: IMPORT_DASHBOARD_TEMPLATE,\n variables: {\n input: {\n content: args.content,\n sourceTemplateId: args.templateId,\n sourceTemplateName: args.templateName,\n ...(args.name ? { name: args.name } : {}),\n ...(args.visibility ? { visibility: args.visibility } : {}),\n ...(args.dataSinkBindings?.length ? { dataSinkBindings: args.dataSinkBindings } : {}),\n ...(args.inputValues && Object.keys(args.inputValues).length ? { inputValues: args.inputValues } : {}),\n },\n },\n });\n\n const payload = result.data?.importDashboardTemplate;\n if (!payload) {\n return {\n success: false,\n errorMessage: 'No response from the server',\n unresolvedSlots: [],\n resolvedSlots: [],\n widgetsNeedingData: 0,\n warnings: [],\n };\n }\n\n return {\n success: payload.success,\n dashboardId: payload.dashboard?.id,\n errorMessage: payload.errorMessage,\n unresolvedSlots: payload.unresolvedSlots ?? [],\n resolvedSlots: payload.resolvedSlots ?? [],\n widgetsNeedingData: payload.widgetsNeedingData ?? 0,\n warnings: payload.warnings ?? [],\n };\n },\n [workspaceClient]\n );\n\n /**\n * Turn a live dashboard into a Dashboard Template application in the\n * developer portal.\n *\n * It deliberately does NOT create a StoreProduct directly. devportal already\n * owns dashboard-template publishing end to end — versioning, submit/review,\n * publisher identity, and the `metadata.sourceApplicationId` the store uses\n * for ownership on later updates. Writing a product straight to the store\n * would fork that pipeline and orphan the listing: a later devportal publish\n * of the same slug would hit the store's slug-collision guard and refuse.\n *\n * So this fills in the one thing devportal cannot do — produce the template\n * document from a live dashboard — and hands off to the existing flow. The\n * app is left in DRAFT so the author reviews the listing and submits it\n * themselves.\n *\n * Two hops: the workspace gateway tokenises the dashboard (it owns the data\n * sinks), the global gateway owns devportal. Brokering through the client\n * keeps both directions free of cross-layer M2M, exactly like install.\n */\n const publishToStore = useCallback(\n async (args: PublishToStoreArgs): Promise<PublishToStoreResult> => {\n const failure = (errorMessage: string): PublishToStoreResult => ({\n success: false,\n errorMessage,\n sinkCount: 0,\n unknownSinkIds: [],\n sampleDataSinkCount: 0,\n });\n\n if (!globalClient) return failure('Store is unavailable right now.');\n\n let content: unknown;\n let sinkCount = 0;\n let unknownSinkIds: string[] = [];\n let sampleDataSinkCount = 0;\n try {\n const built = await workspaceClient.query<{\n buildDashboardTemplateContent?: {\n content: unknown;\n sinkCount: number;\n unknownSinkIds: string[];\n sampleDataSinkCount: number;\n };\n }>({\n query: BUILD_DASHBOARD_TEMPLATE_CONTENT,\n variables: {\n dashboardId: args.dashboardId,\n defaultDashboardName: args.name,\n defaultCategory: args.category ?? null,\n defaultTags: args.tags ?? [],\n includeSampleData: args.includeSampleData ?? false,\n },\n fetchPolicy: 'network-only',\n });\n const payload = built.data?.buildDashboardTemplateContent;\n if (!payload?.content) return failure('Could not build a template from this dashboard.');\n content = payload.content;\n sinkCount = payload.sinkCount;\n unknownSinkIds = payload.unknownSinkIds ?? [];\n sampleDataSinkCount = payload.sampleDataSinkCount ?? 0;\n } catch (err) {\n return failure(err instanceof Error ? err.message : 'Failed to build the template.');\n }\n\n try {\n const app = await globalClient.mutate<{\n createApplication?: { id: string; status: string };\n }>({\n mutation: CREATE_TEMPLATE_APP,\n variables: {\n input: {\n appType: 'DASHBOARD',\n name: args.name,\n slug: args.slug,\n shortDescription: args.description.slice(0, 200),\n description: args.description,\n ...(args.category ? { category: args.category } : {}),\n tags: args.tags ?? [],\n compatibleProducts: ['bigconsole'],\n },\n },\n });\n\n const application = app.data?.createApplication;\n if (!application) {\n return {\n ...failure('The developer portal did not create the app.'),\n sinkCount,\n unknownSinkIds,\n sampleDataSinkCount,\n };\n }\n\n // The version manifest is what devportal maps onto StoreProduct.content\n // when the app is submitted and approved.\n await globalClient.mutate({\n mutation: CREATE_TEMPLATE_VERSION,\n variables: {\n applicationId: application.id,\n input: { version: '1.0.0', manifest: content },\n },\n });\n\n return {\n success: true,\n applicationId: application.id,\n status: application.status,\n sinkCount,\n unknownSinkIds,\n sampleDataSinkCount,\n };\n } catch (err) {\n return {\n ...failure(err instanceof Error ? err.message : 'Failed to publish to the developer portal.'),\n sinkCount,\n unknownSinkIds,\n sampleDataSinkCount,\n };\n }\n },\n [globalClient, workspaceClient]\n );\n\n return useMemo(\n () => ({\n templates,\n loading,\n error,\n totalCount,\n refetch,\n fetchTemplateContent,\n installTemplate,\n publishToStore,\n }),\n [templates, loading, error, totalCount, refetch, fetchTemplateContent, installTemplate, publishToStore]\n );\n}\n\nexport default useStoreDashboardTemplates;\n"],"mappings":"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"}
1
+ {"version":3,"file":"useStoreDashboardTemplates.js","names":[],"sources":["../../../src/bigconsole/hooks/useStoreDashboardTemplates.ts"],"sourcesContent":["/**\n * Store-distributed dashboard templates.\n *\n * Dashboard templates live in the global store as `StoreProduct` rows of type\n * `DASHBOARD` whose `content` column holds a `DashboardTemplateContent`\n * document. This mirrors how FluidGrids sources its workflow templates\n * (`browseStore(type: WORKFLOW)` → `content.definitionJson` →\n * `importWorkflowTemplate`).\n *\n * Two gateways are involved: the catalog is read from the **global** gateway,\n * and the install mutation runs against the **workspace** gateway, which is\n * where the dashboard is created.\n *\n * @module bigconsole/hooks/useStoreDashboardTemplates\n */\nimport { useApolloClient } from '@apollo/client/react';\nimport { useGatewayClient } from '@burdenoff/fe-libs/shared/graphql';\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport { isInstallableDashboardTemplate, withDashboardTemplateMetadata } from '../utils/dashboardTemplateContent';\n\nimport {\n BROWSE_DASHBOARD_TEMPLATES,\n BUILD_DASHBOARD_TEMPLATE_CONTENT,\n CREATE_TEMPLATE_APP,\n CREATE_TEMPLATE_VERSION,\n GET_DASHBOARD_TEMPLATE_DETAIL,\n IMPORT_DASHBOARD_TEMPLATE,\n} from '../graphql/storeTemplates';\n\n/** A column a widget expects from the sink bound to its slot. */\nexport interface TemplateExpectedField {\n name: string;\n role?: string;\n}\n\n/** A data-binding slot the template needs filled. */\nexport interface TemplateRequiredDataSink {\n slot: string;\n label: string;\n description?: string | null;\n expectedFields: TemplateExpectedField[];\n widgetTitles: string[];\n}\n\nexport interface TemplateRequiredWidgetType {\n widgetType: string;\n widgetTypeKey?: string | null;\n publishType: 'BUILTIN' | 'STORE' | 'CUSTOM';\n displayName?: string;\n requiresPurchase?: boolean;\n}\n\nexport interface TemplateRequiredInput {\n name: string;\n type: 'string' | 'number' | 'boolean' | 'select' | 'secret';\n label: string;\n placeholder?: string;\n required: boolean;\n defaultValue?: string | number | boolean | null;\n options?: { label: string; value: string }[];\n helpText?: string;\n}\n\nexport interface DashboardTemplateContent {\n definition: unknown;\n requiredDataSinks: TemplateRequiredDataSink[];\n requiredWidgetTypes: TemplateRequiredWidgetType[];\n requiredInputs: TemplateRequiredInput[];\n defaultDashboardName?: string;\n defaultCategory?: string | null;\n defaultTags?: string[];\n difficultyLevel?: 'easy' | 'medium' | 'hard';\n}\n\n/** A store product presented as a template card. */\nexport interface StoreDashboardTemplate {\n id: string;\n name: string;\n slug: string;\n description?: string | null;\n icon?: string | null;\n category?: string | null;\n tags: string[];\n featured: boolean;\n downloads: number;\n rating?: number | null;\n pricingModel: string;\n price: number;\n /** True for anything the workspace has to buy before it can be installed. */\n requiresPurchase: boolean;\n}\n\ninterface RawStoreProduct {\n id: string;\n name: string;\n slug: string;\n description?: string | null;\n icon?: string | null;\n category?: string | null;\n tags?: string[] | null;\n featured?: boolean | null;\n downloads?: number | null;\n rating?: number | null;\n pricingModel?: string | null;\n price?: number | null;\n content?: unknown;\n}\n\nexport interface InstallTemplateArgs {\n templateId: string;\n templateName: string;\n content: DashboardTemplateContent;\n name?: string;\n visibility?: string;\n description?: string;\n tags?: string[];\n dataSinkBindings?: { slot: string; dataSinkId: string }[];\n inputValues?: Record<string, unknown>;\n}\n\nexport interface InstallTemplateResult {\n success: boolean;\n dashboardId?: string;\n errorMessage?: string;\n unresolvedSlots: string[];\n resolvedSlots: string[];\n widgetsNeedingData: number;\n warnings: string[];\n}\n\nfunction normalizeProduct(raw: RawStoreProduct): StoreDashboardTemplate {\n const pricingModel = raw.pricingModel ?? 'FREE';\n return {\n id: raw.id,\n name: raw.name,\n slug: raw.slug,\n description: raw.description ?? null,\n icon: raw.icon ?? null,\n category: raw.category ?? null,\n tags: raw.tags ?? [],\n featured: raw.featured ?? false,\n downloads: raw.downloads ?? 0,\n rating: raw.rating ?? null,\n pricingModel,\n price: raw.price ?? 0,\n requiresPurchase: pricingModel !== 'FREE' && (raw.price ?? 0) > 0,\n };\n}\n\nexport interface PublishToStoreArgs {\n dashboardId: string;\n name: string;\n slug: string;\n description: string;\n category?: string;\n tags?: string[];\n /** Embed a few real rows per data source so the board renders populated. */\n includeSampleData?: boolean;\n}\n\nexport interface PublishToStoreResult {\n success: boolean;\n /** The DRAFT devportal application created for this template. */\n applicationId?: string;\n status?: string;\n errorMessage?: string;\n /** Distinct data sinks the dashboard referenced, all tokenised into slots. */\n sinkCount: number;\n /** Sinks that could not be resolved; their slots fall back to positional names. */\n unknownSinkIds: string[];\n /** How many data sources contributed sample rows. */\n sampleDataSinkCount: number;\n}\n\nexport interface UseStoreDashboardTemplatesResult {\n templates: StoreDashboardTemplate[];\n loading: boolean;\n error: string | null;\n totalCount: number;\n refetch: (search?: string) => Promise<void>;\n /** Fetch the full template document. Kept lazy: content is large. */\n fetchTemplateContent: (templateId: string) => Promise<DashboardTemplateContent | null>;\n installTemplate: (args: InstallTemplateArgs) => Promise<InstallTemplateResult>;\n publishToStore: (args: PublishToStoreArgs) => Promise<PublishToStoreResult>;\n}\n\nexport function useStoreDashboardTemplates(\n options: { search?: string; category?: string; autoLoad?: boolean } = {}\n): UseStoreDashboardTemplatesResult {\n const { search, category, autoLoad = true } = options;\n\n const globalClient = useGatewayClient('global');\n const workspaceClient = useApolloClient();\n\n const [templates, setTemplates] = useState<StoreDashboardTemplate[]>([]);\n const [totalCount, setTotalCount] = useState(0);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const refetch = useCallback(\n async (overrideSearch?: string): Promise<void> => {\n if (!globalClient) return;\n setLoading(true);\n setError(null);\n try {\n const result = await globalClient.query<{\n browseStore?: { products?: RawStoreProduct[]; totalCount?: number };\n }>({\n query: BROWSE_DASHBOARD_TEMPLATES,\n variables: {\n input: {\n filter: {\n type: 'DASHBOARD',\n status: 'PUBLISHED',\n // Without this a template published from another product's\n // devportal listing would show up in BigConsole's gallery.\n compatibleWith: 'bigconsole',\n ...((overrideSearch ?? search) ? { search: overrideSearch ?? search } : {}),\n ...(category && category !== 'ALL' ? { category } : {}),\n },\n sortBy: 'RELEVANCE',\n pagination: { limit: 50, offset: 0 },\n },\n },\n fetchPolicy: 'network-only',\n });\n\n const installable = (result.data?.browseStore?.products ?? []).filter((product) =>\n isInstallableDashboardTemplate(product.content)\n );\n setTemplates(installable.map(normalizeProduct));\n setTotalCount(installable.length);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to load templates from the store');\n setTemplates([]);\n setTotalCount(0);\n } finally {\n setLoading(false);\n }\n },\n [globalClient, search, category]\n );\n\n useEffect(() => {\n if (autoLoad) void refetch();\n }, [autoLoad, refetch]);\n\n const fetchTemplateContent = useCallback(\n async (templateId: string): Promise<DashboardTemplateContent | null> => {\n if (!globalClient) return null;\n try {\n const result = await globalClient.query<{ product?: { content?: unknown } }>({\n query: GET_DASHBOARD_TEMPLATE_DETAIL,\n variables: { id: templateId },\n fetchPolicy: 'network-only',\n });\n const content = result.data?.product?.content;\n if (!isInstallableDashboardTemplate(content)) return null;\n const doc = content as Partial<DashboardTemplateContent>;\n if (!doc.definition) return null;\n return {\n definition: doc.definition,\n requiredDataSinks: doc.requiredDataSinks ?? [],\n requiredWidgetTypes: doc.requiredWidgetTypes ?? [],\n requiredInputs: doc.requiredInputs ?? [],\n defaultDashboardName: doc.defaultDashboardName,\n defaultCategory: doc.defaultCategory ?? null,\n defaultTags: doc.defaultTags ?? [],\n difficultyLevel: doc.difficultyLevel ?? 'medium',\n };\n } catch {\n return null;\n }\n },\n [globalClient]\n );\n\n const installTemplate = useCallback(\n async (args: InstallTemplateArgs): Promise<InstallTemplateResult> => {\n const result = await workspaceClient.mutate<{\n importDashboardTemplate?: InstallTemplateResult & { dashboard?: { id: string } | null };\n }>({\n mutation: IMPORT_DASHBOARD_TEMPLATE,\n variables: {\n input: {\n content: withDashboardTemplateMetadata(args.content, args),\n sourceTemplateId: args.templateId,\n sourceTemplateName: args.templateName,\n ...(args.name ? { name: args.name } : {}),\n ...(args.visibility ? { visibility: args.visibility } : {}),\n ...(args.dataSinkBindings?.length ? { dataSinkBindings: args.dataSinkBindings } : {}),\n ...(args.inputValues && Object.keys(args.inputValues).length ? { inputValues: args.inputValues } : {}),\n },\n },\n });\n\n const payload = result.data?.importDashboardTemplate;\n if (!payload) {\n return {\n success: false,\n errorMessage: 'No response from the server',\n unresolvedSlots: [],\n resolvedSlots: [],\n widgetsNeedingData: 0,\n warnings: [],\n };\n }\n\n return {\n success: payload.success,\n dashboardId: payload.dashboard?.id,\n errorMessage: payload.errorMessage,\n unresolvedSlots: payload.unresolvedSlots ?? [],\n resolvedSlots: payload.resolvedSlots ?? [],\n widgetsNeedingData: payload.widgetsNeedingData ?? 0,\n warnings: payload.warnings ?? [],\n };\n },\n [workspaceClient]\n );\n\n /**\n * Turn a live dashboard into a Dashboard Template application in the\n * developer portal.\n *\n * It deliberately does NOT create a StoreProduct directly. devportal already\n * owns dashboard-template publishing end to end — versioning, submit/review,\n * publisher identity, and the `metadata.sourceApplicationId` the store uses\n * for ownership on later updates. Writing a product straight to the store\n * would fork that pipeline and orphan the listing: a later devportal publish\n * of the same slug would hit the store's slug-collision guard and refuse.\n *\n * So this fills in the one thing devportal cannot do — produce the template\n * document from a live dashboard — and hands off to the existing flow. The\n * app is left in DRAFT so the author reviews the listing and submits it\n * themselves.\n *\n * Two hops: the workspace gateway tokenises the dashboard (it owns the data\n * sinks), the global gateway owns devportal. Brokering through the client\n * keeps both directions free of cross-layer M2M, exactly like install.\n */\n const publishToStore = useCallback(\n async (args: PublishToStoreArgs): Promise<PublishToStoreResult> => {\n const failure = (errorMessage: string): PublishToStoreResult => ({\n success: false,\n errorMessage,\n sinkCount: 0,\n unknownSinkIds: [],\n sampleDataSinkCount: 0,\n });\n\n if (!globalClient) return failure('Store is unavailable right now.');\n\n let content: unknown;\n let sinkCount = 0;\n let unknownSinkIds: string[] = [];\n let sampleDataSinkCount = 0;\n try {\n const built = await workspaceClient.query<{\n buildDashboardTemplateContent?: {\n content: unknown;\n sinkCount: number;\n unknownSinkIds: string[];\n sampleDataSinkCount: number;\n };\n }>({\n query: BUILD_DASHBOARD_TEMPLATE_CONTENT,\n variables: {\n dashboardId: args.dashboardId,\n defaultDashboardName: args.name,\n defaultCategory: args.category ?? null,\n defaultTags: args.tags ?? [],\n includeSampleData: args.includeSampleData ?? false,\n },\n fetchPolicy: 'network-only',\n });\n const payload = built.data?.buildDashboardTemplateContent;\n if (!payload?.content) return failure('Could not build a template from this dashboard.');\n content = payload.content;\n sinkCount = payload.sinkCount;\n unknownSinkIds = payload.unknownSinkIds ?? [];\n sampleDataSinkCount = payload.sampleDataSinkCount ?? 0;\n } catch (err) {\n return failure(err instanceof Error ? err.message : 'Failed to build the template.');\n }\n\n try {\n const app = await globalClient.mutate<{\n createApplication?: { id: string; status: string };\n }>({\n mutation: CREATE_TEMPLATE_APP,\n variables: {\n input: {\n appType: 'DASHBOARD',\n name: args.name,\n slug: args.slug,\n shortDescription: args.description.slice(0, 200),\n description: args.description,\n ...(args.category ? { category: args.category } : {}),\n tags: args.tags ?? [],\n compatibleProducts: ['bigconsole'],\n },\n },\n });\n\n const application = app.data?.createApplication;\n if (!application) {\n return {\n ...failure('The developer portal did not create the app.'),\n sinkCount,\n unknownSinkIds,\n sampleDataSinkCount,\n };\n }\n\n // The version manifest is what devportal maps onto StoreProduct.content\n // when the app is submitted and approved.\n await globalClient.mutate({\n mutation: CREATE_TEMPLATE_VERSION,\n variables: {\n applicationId: application.id,\n input: { version: '1.0.0', manifest: content },\n },\n });\n\n return {\n success: true,\n applicationId: application.id,\n status: application.status,\n sinkCount,\n unknownSinkIds,\n sampleDataSinkCount,\n };\n } catch (err) {\n return {\n ...failure(err instanceof Error ? err.message : 'Failed to publish to the developer portal.'),\n sinkCount,\n unknownSinkIds,\n sampleDataSinkCount,\n };\n }\n },\n [globalClient, workspaceClient]\n );\n\n return useMemo(\n () => ({\n templates,\n loading,\n error,\n totalCount,\n refetch,\n fetchTemplateContent,\n installTemplate,\n publishToStore,\n }),\n [templates, loading, error, totalCount, refetch, fetchTemplateContent, installTemplate, publishToStore]\n );\n}\n\nexport default useStoreDashboardTemplates;\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardsPage.d.ts","sourceRoot":"","sources":["../../../src/bigconsole/pages/DashboardsPage.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,KAAK,EAAE,EAA0C,MAAM,OAAO,CAAC;AAyMxE,eAAO,MAAM,cAAc,EAAE,EAsnC3B,CAAC;AAEH,eAAe,cAAc,CAAC"}
1
+ {"version":3,"file":"DashboardsPage.d.ts","sourceRoot":"","sources":["../../../src/bigconsole/pages/DashboardsPage.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,KAAK,EAAE,EAA0C,MAAM,OAAO,CAAC;AA2MxE,eAAO,MAAM,cAAc,EAAE,EA4nC3B,CAAC;AAEH,eAAe,cAAc,CAAC"}
@@ -89,26 +89,29 @@ var Ee = d(function({ title: e, subtitle: t, createLabel: n, importLabel: r, onC
89
89
  children: t
90
90
  })]
91
91
  })]
92
- }), /* @__PURE__ */ D(S, {
93
- primary: {
94
- label: n,
95
- onSelect: i,
96
- disabled: !o,
97
- icon: /* @__PURE__ */ D(v, { style: {
98
- marginRight: "var(--space-iconGap)",
99
- height: "var(--size-icon-sm)",
100
- width: "var(--size-icon-sm)"
101
- } })
102
- },
103
- actions: [{
104
- label: r,
105
- onSelect: a,
106
- disabled: !ee,
107
- icon: /* @__PURE__ */ D(ye, { style: {
108
- height: "var(--size-icon-sm)",
109
- width: "var(--size-icon-sm)"
110
- } })
111
- }]
92
+ }), /* @__PURE__ */ D("div", {
93
+ "data-tour": "bigconsole-dashboard-create",
94
+ children: /* @__PURE__ */ D(S, {
95
+ primary: {
96
+ label: n,
97
+ onSelect: i,
98
+ disabled: !o,
99
+ icon: /* @__PURE__ */ D(v, { style: {
100
+ marginRight: "var(--space-iconGap)",
101
+ height: "var(--size-icon-sm)",
102
+ width: "var(--size-icon-sm)"
103
+ } })
104
+ },
105
+ actions: [{
106
+ label: r,
107
+ onSelect: a,
108
+ disabled: !ee,
109
+ icon: /* @__PURE__ */ D(ye, { style: {
110
+ height: "var(--size-icon-sm)",
111
+ width: "var(--size-icon-sm)"
112
+ } })
113
+ }]
114
+ })
112
115
  })]
113
116
  })
114
117
  })]
@@ -254,6 +257,7 @@ var Ee = d(function({ title: e, subtitle: t, createLabel: n, importLabel: r, onC
254
257
  description: y("bigconsole.dashboards.accessDenied.description", "You don't have permission to view dashboards.")
255
258
  });
256
259
  if (z) return /* @__PURE__ */ O("div", {
260
+ "data-tour": "bigconsole-dashboards-list",
257
261
  style: {
258
262
  minHeight: "100vh",
259
263
  backgroundColor: "var(--color-bg-canvas)"
@@ -276,6 +280,7 @@ var Ee = d(function({ title: e, subtitle: t, createLabel: n, importLabel: r, onC
276
280
  });
277
281
  let Ze = X.length;
278
282
  return /* @__PURE__ */ O("div", {
283
+ "data-tour": "bigconsole-dashboards-list",
279
284
  style: {
280
285
  minHeight: "100vh",
281
286
  backgroundColor: "var(--color-bg-canvas)"