@tenorlab/react-dashboard 1.4.1 → 1.4.3
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/core.d.ts +26 -1
- package/dist/core.es.js +76 -67
- package/dist/react-dashboard.d.ts +1 -0
- package/package.json +2 -2
package/dist/core.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export declare const blankDashboardConfig: IDashboardConfig;
|
|
|
5
5
|
* Helper function to create dynamic entries
|
|
6
6
|
* This helps keep the catalog registration clean
|
|
7
7
|
*/
|
|
8
|
-
export declare const createDynamicEntry: (key: string, loader: TWidgetFactoryBase, metaData: TWidgetMetaInfoBase) => [string, IDynamicWidgetCatalogEntryBase];
|
|
8
|
+
export declare const createDynamicEntry: (key: string, loader: TWidgetFactoryBase, isRemote: boolean, metaData: TWidgetMetaInfoBase) => [string, IDynamicWidgetCatalogEntryBase];
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* @name createStaticEntry
|
|
@@ -14,6 +14,12 @@ export declare const createDynamicEntry: (key: string, loader: TWidgetFactoryBas
|
|
|
14
14
|
*/
|
|
15
15
|
export declare const createStaticEntry: <TFrameworkComponentType = any>(key: string, component: TFrameworkComponentType, metaData?: TWidgetMetaInfoBase) => [string, IDynamicWidgetCatalogEntryBase];
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
* @name cssSettingsCatalog
|
|
19
|
+
* @description Catalog of available dashboard settings (array of IDashboardSettingEntry)
|
|
20
|
+
* @see IDashboardSettingEntry
|
|
21
|
+
* @remarks step should never be less than 0.1 as we do some rounding in other places ...
|
|
22
|
+
*/
|
|
17
23
|
export declare const cssSettingsCatalog: IDashboardSettingEntry[];
|
|
18
24
|
|
|
19
25
|
/**
|
|
@@ -49,7 +55,18 @@ export declare const DashboardMaxZoomScale: 1;
|
|
|
49
55
|
|
|
50
56
|
export declare const DashboardMinZoomScale: 0.7;
|
|
51
57
|
|
|
58
|
+
/**
|
|
59
|
+
* @name dashboardSettingsUtils
|
|
60
|
+
* @description Contains utils for the dashboard custom settings
|
|
61
|
+
*/
|
|
52
62
|
export declare const dashboardSettingsUtils: {
|
|
63
|
+
/**
|
|
64
|
+
* @name incrementOrDecrementValue
|
|
65
|
+
* @description Increments or decrement a value based on the direction parameter
|
|
66
|
+
* @param item: an instance of IDashboardSettingEntry
|
|
67
|
+
* @param direction: -1 (for decrement) or 1 (for increment)
|
|
68
|
+
* @returns the update item
|
|
69
|
+
*/
|
|
53
70
|
incrementOrDecrementValue: (item: IDashboardSettingEntry, direction: -1 | 1) => IDashboardSettingEntry;
|
|
54
71
|
};
|
|
55
72
|
|
|
@@ -168,6 +185,7 @@ export declare interface IDynamicWidgetCatalogEntryBase<TFrameworkElementType =
|
|
|
168
185
|
key: TDashboardWidgetKey;
|
|
169
186
|
title: string;
|
|
170
187
|
isContainer?: boolean;
|
|
188
|
+
isRemote?: boolean;
|
|
171
189
|
meta?: TWidgetMetaInfoBase<TFrameworkElementType>;
|
|
172
190
|
component?: TFrameworkComponentType;
|
|
173
191
|
loader?: TWidgetFactoryBase<TFrameworkComponentType>;
|
|
@@ -272,6 +290,13 @@ export declare type TWidgetMetaInfoBase<TFrameworkElementType = any> = {
|
|
|
272
290
|
|
|
273
291
|
export declare type TWidgetSize = 'default' | 'large' | 'xlarge';
|
|
274
292
|
|
|
293
|
+
/**
|
|
294
|
+
* @name useDashboardStorageService
|
|
295
|
+
* @description
|
|
296
|
+
* This implementation of IDashboardStorageService uses localStorage to store custom dashboard configurations.
|
|
297
|
+
* Developers can implement their own version of the dashboard storage service to store the data in a database or other way if needed.
|
|
298
|
+
* @returns An instance of IDashboardStorageService
|
|
299
|
+
*/
|
|
275
300
|
export declare const useDashboardStorageService: () => IDashboardStorageService;
|
|
276
301
|
|
|
277
302
|
export { }
|
package/dist/core.es.js
CHANGED
|
@@ -77,61 +77,68 @@ const w = [
|
|
|
77
77
|
value: "1.0rem"
|
|
78
78
|
}
|
|
79
79
|
], S = ["rem", "pc", "cm", "in", "em", "vh", "vw", "%"], b = (e, t) => S.includes(e) ? t : 1, E = {
|
|
80
|
+
/**
|
|
81
|
+
* @name incrementOrDecrementValue
|
|
82
|
+
* @description Increments or decrement a value based on the direction parameter
|
|
83
|
+
* @param item: an instance of IDashboardSettingEntry
|
|
84
|
+
* @param direction: -1 (for decrement) or 1 (for increment)
|
|
85
|
+
* @returns the update item
|
|
86
|
+
*/
|
|
80
87
|
incrementOrDecrementValue: (e, t) => {
|
|
81
|
-
const
|
|
88
|
+
const a = e.value.match(/([\d.]+)/), i = a ? parseFloat(a[1]) : 0, s = e.value.match(/([^\d.]+)/), n = s ? s[1] : e.defaultUnit, r = b(n, e.step) * t, c = `${Math.max(i + r, e.minValue).toFixed(1)}${n}`;
|
|
82
89
|
return {
|
|
83
90
|
...e,
|
|
84
91
|
value: c
|
|
85
92
|
};
|
|
86
93
|
}
|
|
87
|
-
}, f = (e, t) => `dashboards_${t}_${e}`, v = async (e, t,
|
|
94
|
+
}, f = (e, t) => `dashboards_${t}_${e}`, v = async (e, t, a, i) => {
|
|
88
95
|
const s = localStorage.getItem(f(e, t));
|
|
89
96
|
if (s)
|
|
90
97
|
try {
|
|
91
98
|
const n = JSON.parse(s);
|
|
92
|
-
return n.length < 1 ? [
|
|
93
|
-
r.dashboardId || (r.dashboardId = "default"), r.dashboardName || (r.dashboardName = `Dashboard ${r.dashboardId}`), r.responsiveGrid = r.responsiveGrid ?? !1, (r.widgets || []).length < 1 && (r.widgets =
|
|
99
|
+
return n.length < 1 ? [i] : (n.forEach((r) => {
|
|
100
|
+
r.dashboardId || (r.dashboardId = "default"), r.dashboardName || (r.dashboardName = `Dashboard ${r.dashboardId}`), r.responsiveGrid = r.responsiveGrid ?? !1, (r.widgets || []).length < 1 && (r.widgets = i.widgets);
|
|
94
101
|
const c = (r.cssSettings || []).filter(
|
|
95
|
-
(o) =>
|
|
102
|
+
(o) => i.cssSettings.some((d) => d.key === o.key)
|
|
96
103
|
);
|
|
97
104
|
if (c.length < 1)
|
|
98
|
-
r.cssSettings = [...
|
|
105
|
+
r.cssSettings = [...i.cssSettings];
|
|
99
106
|
else {
|
|
100
107
|
c.forEach((d) => {
|
|
101
108
|
d.value = (d.value || "").replace(/NaN/g, "");
|
|
102
|
-
const l =
|
|
109
|
+
const l = i.cssSettings.find(
|
|
103
110
|
(g) => g.key === d.key
|
|
104
111
|
);
|
|
105
112
|
l && (Object.keys(l).forEach((g) => {
|
|
106
113
|
g in d || (d[g] = l[g]);
|
|
107
114
|
}), d.step = l.step, d.minValue = l.minValue, d.defaultValue = l.defaultValue, d.defaultUnit = l.defaultUnit, /\d+/g.test(d.value) === !1 && (d.value = l ? l.value : "1.0rem"));
|
|
108
115
|
});
|
|
109
|
-
const o =
|
|
116
|
+
const o = i.cssSettings.filter((d) => !c.some(
|
|
110
117
|
(l) => l.key === d.key
|
|
111
118
|
));
|
|
112
119
|
r.cssSettings = [...c, ...o];
|
|
113
120
|
}
|
|
114
121
|
r.widgets = r.widgets.filter(
|
|
115
|
-
(o) => o.includes("WidgetContainer") ||
|
|
122
|
+
(o) => o.includes("WidgetContainer") || a.has(o)
|
|
116
123
|
), r.childWidgetsConfig = r.childWidgetsConfig.filter(
|
|
117
|
-
(o) =>
|
|
124
|
+
(o) => a.has(o.widgetKey)
|
|
118
125
|
), r.zoomScale ? r.zoomScale < 0.7 && (r.zoomScale = 0.7) : r.zoomScale = 1;
|
|
119
126
|
}), n);
|
|
120
127
|
} catch (n) {
|
|
121
128
|
console.warn("Error parsing saved dashboard config:", n);
|
|
122
129
|
}
|
|
123
|
-
return [
|
|
124
|
-
}, C = async (e, t,
|
|
125
|
-
|
|
130
|
+
return [i];
|
|
131
|
+
}, C = async (e, t, a, i) => {
|
|
132
|
+
a.forEach((n) => {
|
|
126
133
|
if (n.userID = e, n.clientAppKey = t, n.responsiveGrid = n.responsiveGrid ?? !1, typeof n != "object")
|
|
127
134
|
throw new Error("Invalid dashboard configuration");
|
|
128
135
|
n.widgets = n.widgets.filter(
|
|
129
|
-
(r) => r.includes("WidgetContainer") ||
|
|
136
|
+
(r) => r.includes("WidgetContainer") || i.has(r)
|
|
130
137
|
), n.childWidgetsConfig = n.childWidgetsConfig.filter(
|
|
131
|
-
(r) =>
|
|
138
|
+
(r) => i.has(r.widgetKey)
|
|
132
139
|
), n.zoomScale ? n.zoomScale < 0.7 && (n.zoomScale = 0.7) : n.zoomScale = 1;
|
|
133
140
|
});
|
|
134
|
-
const s = JSON.stringify(
|
|
141
|
+
const s = JSON.stringify(a);
|
|
135
142
|
return localStorage.setItem(f(e, t), s), !0;
|
|
136
143
|
}, W = {
|
|
137
144
|
getSavedDashboards: v,
|
|
@@ -153,92 +160,94 @@ const w = [
|
|
|
153
160
|
let t = Number(e || 0);
|
|
154
161
|
return t < m && (t = m), t > p && (t = p), t;
|
|
155
162
|
}, j = (e, t) => {
|
|
156
|
-
let
|
|
157
|
-
return D(
|
|
163
|
+
let a = Number(Number((V * t).toFixed(2)).toFixed(2)), i = Number((Number(e) + a).toFixed(2));
|
|
164
|
+
return D(i);
|
|
158
165
|
}, N = (e) => {
|
|
159
166
|
let t = {
|
|
160
167
|
...e
|
|
161
168
|
};
|
|
162
|
-
return t.widgets = t.widgets.filter((
|
|
163
|
-
if (`${
|
|
164
|
-
const
|
|
165
|
-
(s) => s.parentWidgetKey ===
|
|
169
|
+
return t.widgets = t.widgets.filter((a) => {
|
|
170
|
+
if (`${a}`.includes("WidgetContainer")) {
|
|
171
|
+
const i = t.childWidgetsConfig.filter(
|
|
172
|
+
(s) => s.parentWidgetKey === a
|
|
166
173
|
);
|
|
167
|
-
if (!
|
|
174
|
+
if (!i || i.length === 0)
|
|
168
175
|
return t.widgets = t.widgets.filter(
|
|
169
|
-
(s) => s !==
|
|
176
|
+
(s) => s !== a
|
|
170
177
|
), !1;
|
|
171
178
|
}
|
|
172
179
|
return !0;
|
|
173
180
|
}), t;
|
|
174
181
|
}, x = (e) => {
|
|
175
182
|
const t = e.widgets.filter(
|
|
176
|
-
(
|
|
177
|
-
),
|
|
178
|
-
return t.forEach((
|
|
179
|
-
const n = `${
|
|
180
|
-
i
|
|
181
|
-
}), e.widgets = e.widgets.map((
|
|
182
|
-
const s =
|
|
183
|
+
(i) => i.includes("WidgetContainer")
|
|
184
|
+
), a = {};
|
|
185
|
+
return t.forEach((i, s) => {
|
|
186
|
+
const n = `${i.split("_container")[0]}_container${s + 1}`;
|
|
187
|
+
a[i] = n;
|
|
188
|
+
}), e.widgets = e.widgets.map((i) => a[i] || i), e.childWidgetsConfig = e.childWidgetsConfig.map((i) => {
|
|
189
|
+
const s = i.parentWidgetKey, n = a[s];
|
|
183
190
|
return {
|
|
184
|
-
...
|
|
191
|
+
...i,
|
|
185
192
|
// If a new key exists, use it. If not, keep the original key.
|
|
186
193
|
parentWidgetKey: n || s
|
|
187
194
|
};
|
|
188
195
|
}), e;
|
|
189
196
|
}, u = (e, t) => {
|
|
190
|
-
const
|
|
197
|
+
const a = `${e}`.includes("Container"), i = a ? ["Container"] : ["Widget"], s = t?.name || e, n = t?.description || (a ? "Container" : "Unknown");
|
|
191
198
|
return {
|
|
192
199
|
name: s,
|
|
193
200
|
description: n,
|
|
194
|
-
categories:
|
|
201
|
+
categories: i,
|
|
195
202
|
noDuplicatedWidgets: !0,
|
|
196
203
|
icon: void 0,
|
|
197
204
|
externalDependencies: []
|
|
198
205
|
};
|
|
199
|
-
}, I = (e, t,
|
|
200
|
-
const
|
|
206
|
+
}, I = (e, t, a) => t[e] || u(e, a), M = (e, t) => t.get(e)?.meta || u(e), k = (e, t, a) => {
|
|
207
|
+
const i = a || u(e);
|
|
201
208
|
return [
|
|
202
209
|
e,
|
|
203
210
|
{
|
|
204
211
|
key: e,
|
|
205
|
-
title:
|
|
212
|
+
title: i.name,
|
|
206
213
|
isContainer: `${e}`.includes("Container"),
|
|
207
|
-
|
|
214
|
+
isRemote: !1,
|
|
215
|
+
meta: i,
|
|
208
216
|
component: t
|
|
209
217
|
}
|
|
210
218
|
];
|
|
211
|
-
}, h = (e, t, i) => {
|
|
212
|
-
const
|
|
219
|
+
}, h = (e, t, a, i) => {
|
|
220
|
+
const s = i || u(e);
|
|
213
221
|
return [
|
|
214
222
|
e,
|
|
215
223
|
{
|
|
216
224
|
key: e,
|
|
217
|
-
title:
|
|
225
|
+
title: s.name,
|
|
218
226
|
isContainer: !1,
|
|
219
|
-
|
|
227
|
+
isRemote: a,
|
|
228
|
+
meta: s,
|
|
220
229
|
loader: t
|
|
221
230
|
}
|
|
222
231
|
];
|
|
223
232
|
}, F = (e) => {
|
|
224
233
|
const t = e.match(/\/widget-([a-zA-Z0-9-]+)\/index\.ts$/);
|
|
225
234
|
if (t && t[1]) {
|
|
226
|
-
const
|
|
235
|
+
const a = t[1], i = a.split("-"), s = `Widget${i.map((r) => r.charAt(0).toUpperCase() + r.slice(1)).join("")}`, n = i.map((r) => r.charAt(0).toUpperCase() + r.slice(1)).join(" ");
|
|
227
236
|
return {
|
|
228
237
|
key: s,
|
|
229
238
|
title: n,
|
|
230
|
-
folder:
|
|
239
|
+
folder: a
|
|
231
240
|
};
|
|
232
241
|
}
|
|
233
242
|
return null;
|
|
234
|
-
}, $ = (e, t,
|
|
235
|
-
const s = `${t}/widget-${
|
|
243
|
+
}, $ = (e, t, a, i) => {
|
|
244
|
+
const s = `${t}/widget-${a}/meta.ts`, n = e[s];
|
|
236
245
|
if (!n)
|
|
237
246
|
return;
|
|
238
|
-
const r = `${
|
|
247
|
+
const r = `${i}Meta`;
|
|
239
248
|
return n[r] || void 0;
|
|
240
|
-
}, A = async (e) => new Promise(async (t,
|
|
241
|
-
const
|
|
249
|
+
}, A = async (e) => new Promise(async (t, a) => {
|
|
250
|
+
const i = [];
|
|
242
251
|
try {
|
|
243
252
|
const s = await (await fetch(`${e}?${Math.random()}`)).json();
|
|
244
253
|
for (const n in s) {
|
|
@@ -254,32 +263,32 @@ const w = [
|
|
|
254
263
|
// Or a logic to map a string name to a Lucide component
|
|
255
264
|
externalDependencies: r.meta?.externalDependencies || []
|
|
256
265
|
};
|
|
257
|
-
|
|
266
|
+
i.push(h(n, c, !0, o));
|
|
258
267
|
}
|
|
259
268
|
t({
|
|
260
|
-
entries:
|
|
269
|
+
entries: i,
|
|
261
270
|
message: "",
|
|
262
271
|
details: ""
|
|
263
272
|
});
|
|
264
273
|
} catch (s) {
|
|
265
|
-
console.error("Remote plugin discovery failed:", s),
|
|
274
|
+
console.error("Remote plugin discovery failed:", s), a({
|
|
266
275
|
entries: [],
|
|
267
276
|
message: "Remote plugin discovery failed:",
|
|
268
277
|
details: typeof s == "object" ? JSON.stringify(s) : s
|
|
269
278
|
});
|
|
270
279
|
}
|
|
271
|
-
}), K = (e, t,
|
|
280
|
+
}), K = (e, t, a, i = !0) => {
|
|
272
281
|
const s = [];
|
|
273
282
|
for (const n in t) {
|
|
274
283
|
const r = t[n], c = F(n);
|
|
275
284
|
if (c && r) {
|
|
276
285
|
const { key: o, title: d, folder: l } = c;
|
|
277
|
-
let g = $(
|
|
286
|
+
let g = $(a, e, l, o);
|
|
278
287
|
if (g || (g = u(o, {
|
|
279
|
-
description: `Local ${
|
|
280
|
-
})),
|
|
288
|
+
description: `Local ${i ? "dynamic" : "static"} widget`
|
|
289
|
+
})), i)
|
|
281
290
|
s.push(
|
|
282
|
-
h(o, r, g)
|
|
291
|
+
h(o, r, !1, g)
|
|
283
292
|
);
|
|
284
293
|
else {
|
|
285
294
|
const y = r.default || r;
|
|
@@ -288,13 +297,13 @@ const w = [
|
|
|
288
297
|
}
|
|
289
298
|
}
|
|
290
299
|
return s;
|
|
291
|
-
},
|
|
300
|
+
}, R = (e, t = "color") => {
|
|
292
301
|
if (typeof window > "u") return "#FFFFFF";
|
|
293
|
-
const
|
|
294
|
-
Array.isArray(e) ? e.forEach((s) =>
|
|
295
|
-
const
|
|
296
|
-
return document.body.removeChild(
|
|
297
|
-
},
|
|
302
|
+
const a = document.createElement("div");
|
|
303
|
+
Array.isArray(e) ? e.forEach((s) => a.classList.add(s)) : e.split(" ").forEach((s) => a.classList.add(s)), a.style.display = "none", document.body.appendChild(a);
|
|
304
|
+
const i = window.getComputedStyle(a)[t];
|
|
305
|
+
return document.body.removeChild(a), i;
|
|
306
|
+
}, G = {
|
|
298
307
|
/**
|
|
299
308
|
* @name getCssVariableValue
|
|
300
309
|
* @description Return the value of a CSS custom property from the current HTML document
|
|
@@ -323,8 +332,8 @@ const w = [
|
|
|
323
332
|
*/
|
|
324
333
|
restoreCssVarsFromSettings: (e) => {
|
|
325
334
|
const t = document.documentElement;
|
|
326
|
-
e.forEach((
|
|
327
|
-
t.style.setProperty(
|
|
335
|
+
e.forEach((a) => {
|
|
336
|
+
t.style.setProperty(a.cssProperty, a.value);
|
|
328
337
|
});
|
|
329
338
|
}
|
|
330
339
|
}, Z = (e, ...t) => [
|
|
@@ -340,7 +349,7 @@ export {
|
|
|
340
349
|
h as createDynamicEntry,
|
|
341
350
|
k as createStaticEntry,
|
|
342
351
|
w as cssSettingsCatalog,
|
|
343
|
-
|
|
352
|
+
G as cssVarsUtils,
|
|
344
353
|
E as dashboardSettingsUtils,
|
|
345
354
|
x as ensureContainersSequence,
|
|
346
355
|
D as ensureZoomScaleIsWithinRange,
|
|
@@ -355,6 +364,6 @@ export {
|
|
|
355
364
|
F as parseKeyAndTitleFromFilePath,
|
|
356
365
|
A as remoteWidgetDiscovery,
|
|
357
366
|
N as removeEmptyContainers,
|
|
358
|
-
|
|
367
|
+
R as resolveColorFromClass,
|
|
359
368
|
P as useDashboardStorageService
|
|
360
369
|
};
|
|
@@ -169,6 +169,7 @@ export declare interface IDynamicWidgetCatalogEntryBase<TFrameworkElementType =
|
|
|
169
169
|
key: TDashboardWidgetKey;
|
|
170
170
|
title: string;
|
|
171
171
|
isContainer?: boolean;
|
|
172
|
+
isRemote?: boolean;
|
|
172
173
|
meta?: TWidgetMetaInfoBase<TFrameworkElementType>;
|
|
173
174
|
component?: TFrameworkComponentType;
|
|
174
175
|
loader?: TWidgetFactoryBase<TFrameworkComponentType>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tenorlab/react-dashboard",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.3",
|
|
4
4
|
"description": "Foundation components for creating user-configurable dashboards in React",
|
|
5
5
|
"author": "Damiano Fusco",
|
|
6
6
|
"type": "module",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"zustand": "^5.0.0 || ^5.0.9"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
|
-
"@tenorlab/dashboard-core": "^1.
|
|
57
|
+
"@tenorlab/dashboard-core": "^1.4.2",
|
|
58
58
|
"@types/node": "^24.10.1",
|
|
59
59
|
"@types/react": "19.2.3",
|
|
60
60
|
"@types/react-dom": "19.2.3",
|