@richardmcquiston01/dashboard-widgets-toolkit 0.14.0 → 0.16.0
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.cjs +2232 -1587
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +49 -3
- package/dist/core.d.ts +49 -3
- package/dist/core.js +2210 -1588
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +2232 -1587
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2210 -1588
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +600 -59
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +25 -2
- package/dist/react.d.ts +25 -2
- package/dist/react.js +600 -59
- package/dist/react.js.map +1 -1
- package/dist/{storage-_Eb8Y98-.d.cts → storage-oivwB7al.d.cts} +247 -56
- package/dist/{storage-_Eb8Y98-.d.ts → storage-oivwB7al.d.ts} +247 -56
- package/package.json +1 -1
package/dist/react.js
CHANGED
|
@@ -828,6 +828,14 @@ var DEFAULT_LABELS = {
|
|
|
828
828
|
menuMoveLater: "Move later",
|
|
829
829
|
menuHide: "Hide",
|
|
830
830
|
menuOptions: "Options\u2026",
|
|
831
|
+
menuDuplicate: "Duplicate",
|
|
832
|
+
duplicate: (title) => `Duplicate ${title}`,
|
|
833
|
+
duplicateBlocked: (title, reason) => `Duplicate ${title} (unavailable: ${reason})`,
|
|
834
|
+
duplicated: (title) => `Duplicated ${title}`,
|
|
835
|
+
optionsDelete: "Delete this widget",
|
|
836
|
+
confirmDelete: "Delete this widget? Its settings are lost.",
|
|
837
|
+
deleted: (title) => `Deleted ${title}`,
|
|
838
|
+
suggestedViewTitle: (title, viewLabel) => `${title} ${viewLabel}`,
|
|
831
839
|
optionsFor: (title) => `Options for ${title}`,
|
|
832
840
|
optionsTitleField: "Title",
|
|
833
841
|
titleInUse: "Another widget already uses this title.",
|
|
@@ -835,6 +843,8 @@ var DEFAULT_LABELS = {
|
|
|
835
843
|
widthDefault: "Default",
|
|
836
844
|
widthOption: (width, share) => `${width} of 12 (${share})`,
|
|
837
845
|
optionsFlexible: "Grow to fill empty space in the row",
|
|
846
|
+
optionsViewField: "View",
|
|
847
|
+
viewDefault: (viewLabel) => `${viewLabel} (default)`,
|
|
838
848
|
optionsDeclared: "Data",
|
|
839
849
|
apply: "Apply",
|
|
840
850
|
cancel: "Cancel",
|
|
@@ -1935,13 +1945,15 @@ var NOT_LOCKED = Object.freeze({
|
|
|
1935
1945
|
move: false,
|
|
1936
1946
|
hide: false,
|
|
1937
1947
|
minimize: false,
|
|
1938
|
-
options: false
|
|
1948
|
+
options: false,
|
|
1949
|
+
clone: false
|
|
1939
1950
|
});
|
|
1940
1951
|
var FULLY_LOCKED = Object.freeze({
|
|
1941
1952
|
move: true,
|
|
1942
1953
|
hide: true,
|
|
1943
1954
|
minimize: true,
|
|
1944
|
-
options: true
|
|
1955
|
+
options: true,
|
|
1956
|
+
clone: true
|
|
1945
1957
|
});
|
|
1946
1958
|
function resolveWidgetLock(definition) {
|
|
1947
1959
|
const setting = definition.locked;
|
|
@@ -1951,7 +1963,8 @@ function resolveWidgetLock(definition) {
|
|
|
1951
1963
|
move: setting.move === true,
|
|
1952
1964
|
hide: setting.hide === true,
|
|
1953
1965
|
minimize: setting.minimize === true,
|
|
1954
|
-
options: setting.options === true
|
|
1966
|
+
options: setting.options === true,
|
|
1967
|
+
clone: setting.clone === true
|
|
1955
1968
|
};
|
|
1956
1969
|
}
|
|
1957
1970
|
function sortDefinitions(definitions) {
|
|
@@ -1972,6 +1985,282 @@ function isWidgetVisibleTo(definition, roles) {
|
|
|
1972
1985
|
return definition.roles.some((role) => roles.includes(role));
|
|
1973
1986
|
}
|
|
1974
1987
|
|
|
1988
|
+
// src/core/payload.ts
|
|
1989
|
+
var WIDGET_KINDS = [
|
|
1990
|
+
"TEXT",
|
|
1991
|
+
"KPI",
|
|
1992
|
+
"GAUGE",
|
|
1993
|
+
"TABLE",
|
|
1994
|
+
"BAR_LIST",
|
|
1995
|
+
"ALERT_LIST",
|
|
1996
|
+
"GRAPH"
|
|
1997
|
+
];
|
|
1998
|
+
function isWidgetKind(value) {
|
|
1999
|
+
return typeof value === "string" && WIDGET_KINDS.includes(value);
|
|
2000
|
+
}
|
|
2001
|
+
var VALUE_FORMATS = ["number", "currency", "percent"];
|
|
2002
|
+
var MAX_GRAPH_SERIES = 8;
|
|
2003
|
+
var DEFAULT_EMPTY_TEXT = "Nothing to show yet.";
|
|
2004
|
+
function isWidgetEmptyState(payload) {
|
|
2005
|
+
return "empty" in payload && payload.empty === true;
|
|
2006
|
+
}
|
|
2007
|
+
function emptyTextFor(payload) {
|
|
2008
|
+
if (isWidgetEmptyState(payload)) {
|
|
2009
|
+
return payload.text;
|
|
2010
|
+
}
|
|
2011
|
+
switch (payload.kind) {
|
|
2012
|
+
case "TABLE":
|
|
2013
|
+
return payload.rows.length === 0 ? DEFAULT_EMPTY_TEXT : null;
|
|
2014
|
+
case "BAR_LIST":
|
|
2015
|
+
return payload.items.length === 0 ? DEFAULT_EMPTY_TEXT : null;
|
|
2016
|
+
case "ALERT_LIST":
|
|
2017
|
+
return payload.items.length === 0 ? payload.emptyText : null;
|
|
2018
|
+
case "GRAPH":
|
|
2019
|
+
return payload.series.every((series) => series.points.length === 0) ? DEFAULT_EMPTY_TEXT : null;
|
|
2020
|
+
case "TEXT":
|
|
2021
|
+
case "KPI":
|
|
2022
|
+
case "GAUGE":
|
|
2023
|
+
return null;
|
|
2024
|
+
}
|
|
2025
|
+
}
|
|
2026
|
+
|
|
2027
|
+
// src/core/views.ts
|
|
2028
|
+
var BASE_VIEW_KEY = "base";
|
|
2029
|
+
var VIEW_CONVERSIONS = {
|
|
2030
|
+
tableToBarList: { from: "TABLE", to: "BAR_LIST" },
|
|
2031
|
+
tableToGraph: { from: "TABLE", to: "GRAPH" },
|
|
2032
|
+
barListToTable: { from: "BAR_LIST", to: "TABLE" },
|
|
2033
|
+
graphToTable: { from: "GRAPH", to: "TABLE" },
|
|
2034
|
+
barListToGraph: { from: "BAR_LIST", to: "GRAPH" }
|
|
2035
|
+
};
|
|
2036
|
+
var KIND_LABELS = {
|
|
2037
|
+
TEXT: "Text",
|
|
2038
|
+
KPI: "Number",
|
|
2039
|
+
GAUGE: "Gauge",
|
|
2040
|
+
TABLE: "Table",
|
|
2041
|
+
BAR_LIST: "Bars",
|
|
2042
|
+
ALERT_LIST: "List",
|
|
2043
|
+
GRAPH: "Chart"
|
|
2044
|
+
};
|
|
2045
|
+
function kindLabel(kind) {
|
|
2046
|
+
return KIND_LABELS[kind];
|
|
2047
|
+
}
|
|
2048
|
+
function hasViews(item) {
|
|
2049
|
+
return item.views !== void 0 && item.views.length > 0;
|
|
2050
|
+
}
|
|
2051
|
+
function findView(item, key) {
|
|
2052
|
+
return item.views?.find((view) => view.key === key);
|
|
2053
|
+
}
|
|
2054
|
+
function viewChoices(item) {
|
|
2055
|
+
if (!hasViews(item)) return [];
|
|
2056
|
+
return [
|
|
2057
|
+
{
|
|
2058
|
+
key: BASE_VIEW_KEY,
|
|
2059
|
+
label: item.baseViewLabel ?? kindLabel(item.kind),
|
|
2060
|
+
kind: item.kind
|
|
2061
|
+
},
|
|
2062
|
+
...(item.views ?? []).map(({ key, label, kind }) => ({
|
|
2063
|
+
key,
|
|
2064
|
+
label,
|
|
2065
|
+
kind
|
|
2066
|
+
}))
|
|
2067
|
+
];
|
|
2068
|
+
}
|
|
2069
|
+
function isKnownView(item, key) {
|
|
2070
|
+
return key !== void 0 && (key === BASE_VIEW_KEY || findView(item, key) !== void 0);
|
|
2071
|
+
}
|
|
2072
|
+
function effectiveViewKey(item, chosen) {
|
|
2073
|
+
if (!hasViews(item)) return BASE_VIEW_KEY;
|
|
2074
|
+
if (isKnownView(item, chosen)) return chosen;
|
|
2075
|
+
if (isKnownView(item, item.defaultView)) return item.defaultView;
|
|
2076
|
+
return BASE_VIEW_KEY;
|
|
2077
|
+
}
|
|
2078
|
+
function cellValue2(cell) {
|
|
2079
|
+
const value = cell?.value;
|
|
2080
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
2081
|
+
}
|
|
2082
|
+
function columnName(table, index) {
|
|
2083
|
+
return table.columns[index]?.label ?? `#${index + 1}`;
|
|
2084
|
+
}
|
|
2085
|
+
function checkColumn(table, index, field, context) {
|
|
2086
|
+
if (!Number.isInteger(index) || index < 0 || index >= table.columns.length) {
|
|
2087
|
+
return `${context.where}: ${field} column ${index} does not exist (the table has ${table.columns.length} columns, numbered from 0).`;
|
|
2088
|
+
}
|
|
2089
|
+
return void 0;
|
|
2090
|
+
}
|
|
2091
|
+
function numericColumn(table, index, context) {
|
|
2092
|
+
const numbers = [];
|
|
2093
|
+
for (const [rowIndex, row] of table.rows.entries()) {
|
|
2094
|
+
const value = cellValue2(row[index]);
|
|
2095
|
+
if (value === void 0) {
|
|
2096
|
+
return err(
|
|
2097
|
+
`${context.where}: row ${rowIndex + 1}, column ${index + 1} ("${columnName(table, index)}") has no numeric value. Add value to the cells.`
|
|
2098
|
+
);
|
|
2099
|
+
}
|
|
2100
|
+
numbers.push(value);
|
|
2101
|
+
}
|
|
2102
|
+
return ok(numbers);
|
|
2103
|
+
}
|
|
2104
|
+
function tableToBarList(table, conversion, context) {
|
|
2105
|
+
const bad = checkColumn(table, conversion.label, "label", context) ?? checkColumn(table, conversion.value, "value", context);
|
|
2106
|
+
if (bad !== void 0) return err(bad);
|
|
2107
|
+
const numbers = numericColumn(table, conversion.value, context);
|
|
2108
|
+
if (!numbers.ok) return numbers;
|
|
2109
|
+
const items = table.rows.map((row, index) => ({
|
|
2110
|
+
label: row[conversion.label]?.text ?? "",
|
|
2111
|
+
value: numbers.value[index],
|
|
2112
|
+
display: row[conversion.value]?.text ?? String(numbers.value[index])
|
|
2113
|
+
}));
|
|
2114
|
+
return ok({ kind: "BAR_LIST", items });
|
|
2115
|
+
}
|
|
2116
|
+
function tableToGraph(table, conversion, context) {
|
|
2117
|
+
if (conversion.values.length === 0 || conversion.values.length > MAX_GRAPH_SERIES) {
|
|
2118
|
+
return err(
|
|
2119
|
+
`${context.where}: a chart needs 1 to ${MAX_GRAPH_SERIES} series columns, got ${conversion.values.length}.`
|
|
2120
|
+
);
|
|
2121
|
+
}
|
|
2122
|
+
let bad = checkColumn(
|
|
2123
|
+
table,
|
|
2124
|
+
conversion.label,
|
|
2125
|
+
"label",
|
|
2126
|
+
context
|
|
2127
|
+
);
|
|
2128
|
+
for (const index of conversion.values) {
|
|
2129
|
+
bad ??= checkColumn(table, index, "series", context);
|
|
2130
|
+
}
|
|
2131
|
+
if (bad !== void 0) return err(bad);
|
|
2132
|
+
const series = [];
|
|
2133
|
+
for (const index of conversion.values) {
|
|
2134
|
+
const numbers = numericColumn(table, index, context);
|
|
2135
|
+
if (!numbers.ok) return numbers;
|
|
2136
|
+
series.push({
|
|
2137
|
+
name: columnName(table, index),
|
|
2138
|
+
points: table.rows.map((row, rowIndex) => ({
|
|
2139
|
+
label: row[conversion.label]?.text ?? "",
|
|
2140
|
+
value: numbers.value[rowIndex]
|
|
2141
|
+
}))
|
|
2142
|
+
});
|
|
2143
|
+
}
|
|
2144
|
+
return ok({
|
|
2145
|
+
kind: "GRAPH",
|
|
2146
|
+
series,
|
|
2147
|
+
chartType: conversion.chartType,
|
|
2148
|
+
valueFormat: conversion.valueFormat ?? "number",
|
|
2149
|
+
...conversion.currency === void 0 ? {} : { currency: conversion.currency },
|
|
2150
|
+
xLabel: columnName(table, conversion.label)
|
|
2151
|
+
});
|
|
2152
|
+
}
|
|
2153
|
+
function barListToTable(list, conversion) {
|
|
2154
|
+
return ok({
|
|
2155
|
+
kind: "TABLE",
|
|
2156
|
+
columns: [
|
|
2157
|
+
{ label: conversion.labelHeading ?? "Name" },
|
|
2158
|
+
{ label: conversion.valueHeading ?? "Value", numeric: true }
|
|
2159
|
+
],
|
|
2160
|
+
rows: list.items.map((item) => [
|
|
2161
|
+
{ text: item.label },
|
|
2162
|
+
{ text: item.display ?? String(item.value), value: item.value }
|
|
2163
|
+
])
|
|
2164
|
+
});
|
|
2165
|
+
}
|
|
2166
|
+
function graphToTable(graph, context) {
|
|
2167
|
+
const first = graph.series[0];
|
|
2168
|
+
if (first === void 0)
|
|
2169
|
+
return err(`${context.where}: the chart has no series.`);
|
|
2170
|
+
const format = {
|
|
2171
|
+
...graph.currency === void 0 ? {} : { currency: graph.currency },
|
|
2172
|
+
...context.locale === void 0 ? {} : { locale: context.locale }
|
|
2173
|
+
};
|
|
2174
|
+
return ok({
|
|
2175
|
+
kind: "TABLE",
|
|
2176
|
+
columns: [
|
|
2177
|
+
{ label: graph.xLabel ?? "Label" },
|
|
2178
|
+
...graph.series.map((series) => ({ label: series.name, numeric: true }))
|
|
2179
|
+
],
|
|
2180
|
+
rows: first.points.map((point, index) => [
|
|
2181
|
+
{ text: point.label },
|
|
2182
|
+
...graph.series.map((series) => {
|
|
2183
|
+
const value = series.points[index]?.value;
|
|
2184
|
+
return value === void 0 ? { text: "\u2014" } : { text: formatValue(value, graph.valueFormat, format), value };
|
|
2185
|
+
})
|
|
2186
|
+
])
|
|
2187
|
+
});
|
|
2188
|
+
}
|
|
2189
|
+
function barListToGraph(list, conversion) {
|
|
2190
|
+
return ok({
|
|
2191
|
+
kind: "GRAPH",
|
|
2192
|
+
series: [
|
|
2193
|
+
{
|
|
2194
|
+
name: conversion.seriesName ?? "Value",
|
|
2195
|
+
points: list.items.map((item) => ({
|
|
2196
|
+
label: item.label,
|
|
2197
|
+
value: item.value
|
|
2198
|
+
}))
|
|
2199
|
+
}
|
|
2200
|
+
],
|
|
2201
|
+
chartType: conversion.chartType,
|
|
2202
|
+
valueFormat: conversion.valueFormat ?? "number",
|
|
2203
|
+
...conversion.currency === void 0 ? {} : { currency: conversion.currency }
|
|
2204
|
+
});
|
|
2205
|
+
}
|
|
2206
|
+
function convertView(widgetKey, view, data, options = {}) {
|
|
2207
|
+
const conversion = view.convert;
|
|
2208
|
+
const context = {
|
|
2209
|
+
where: `Widget ${JSON.stringify(widgetKey)} view ${JSON.stringify(view.key)}`,
|
|
2210
|
+
...options.locale === void 0 ? {} : { locale: options.locale }
|
|
2211
|
+
};
|
|
2212
|
+
const expected = VIEW_CONVERSIONS[conversion.type]?.from;
|
|
2213
|
+
if (expected === void 0) {
|
|
2214
|
+
return err(
|
|
2215
|
+
`${context.where}: unknown conversion type ${JSON.stringify(conversion.type)}.`
|
|
2216
|
+
);
|
|
2217
|
+
}
|
|
2218
|
+
if (data.kind !== expected) {
|
|
2219
|
+
return err(
|
|
2220
|
+
`${context.where}: ${conversion.type} reads a ${expected} payload, but the widget returned ${data.kind}.`
|
|
2221
|
+
);
|
|
2222
|
+
}
|
|
2223
|
+
switch (conversion.type) {
|
|
2224
|
+
case "tableToBarList":
|
|
2225
|
+
return tableToBarList(data, conversion, context);
|
|
2226
|
+
case "tableToGraph":
|
|
2227
|
+
return tableToGraph(data, conversion, context);
|
|
2228
|
+
case "barListToTable":
|
|
2229
|
+
return barListToTable(data, conversion);
|
|
2230
|
+
case "graphToTable":
|
|
2231
|
+
return graphToTable(data, context);
|
|
2232
|
+
case "barListToGraph":
|
|
2233
|
+
return barListToGraph(data, conversion);
|
|
2234
|
+
}
|
|
2235
|
+
}
|
|
2236
|
+
function applyView(widget, chosen, options = {}) {
|
|
2237
|
+
const key = effectiveViewKey(widget.definition, chosen);
|
|
2238
|
+
const view = findView(widget.definition, key);
|
|
2239
|
+
if (view === void 0) return widget;
|
|
2240
|
+
const definition = {
|
|
2241
|
+
...widget.definition,
|
|
2242
|
+
kind: view.kind
|
|
2243
|
+
};
|
|
2244
|
+
if (widget.status === "loading") return { ...widget, definition };
|
|
2245
|
+
if (widget.status === "empty") return { ...widget, definition };
|
|
2246
|
+
if (widget.status === "error") return { ...widget, definition };
|
|
2247
|
+
const converted = convertView(
|
|
2248
|
+
widget.definition.key,
|
|
2249
|
+
view,
|
|
2250
|
+
widget.data,
|
|
2251
|
+
options
|
|
2252
|
+
);
|
|
2253
|
+
if (!converted.ok) {
|
|
2254
|
+
return {
|
|
2255
|
+
definition,
|
|
2256
|
+
status: "error",
|
|
2257
|
+
error: converted.error,
|
|
2258
|
+
...widget.options === void 0 ? {} : { options: widget.options }
|
|
2259
|
+
};
|
|
2260
|
+
}
|
|
2261
|
+
return { ...widget, definition, data: converted.value };
|
|
2262
|
+
}
|
|
2263
|
+
|
|
1975
2264
|
// src/core/settings.ts
|
|
1976
2265
|
var MAX_WIDGET_TITLE_LENGTH = 80;
|
|
1977
2266
|
var MAX_COLUMN_LIST = 100;
|
|
@@ -1999,6 +2288,7 @@ function parseOne(raw) {
|
|
|
1999
2288
|
const width = raw["width"];
|
|
2000
2289
|
const flexible = raw["flexible"];
|
|
2001
2290
|
const options = raw["options"];
|
|
2291
|
+
const view = raw["view"];
|
|
2002
2292
|
const cleanTitle = typeof title === "string" ? title.trim().slice(0, MAX_WIDGET_TITLE_LENGTH) : "";
|
|
2003
2293
|
const chosen = {};
|
|
2004
2294
|
if (isRecord(options)) {
|
|
@@ -2011,7 +2301,8 @@ function parseOne(raw) {
|
|
|
2011
2301
|
...cleanTitle === "" ? {} : { title: cleanTitle },
|
|
2012
2302
|
...isWidgetWidth(width) ? { width } : {},
|
|
2013
2303
|
...typeof flexible === "boolean" ? { flexible } : {},
|
|
2014
|
-
...Object.keys(chosen).length === 0 ? {} : { options: chosen }
|
|
2304
|
+
...Object.keys(chosen).length === 0 ? {} : { options: chosen },
|
|
2305
|
+
...typeof view === "string" && view !== "" && view.length <= 80 ? { view } : {}
|
|
2015
2306
|
};
|
|
2016
2307
|
return Object.keys(settings).length === 0 ? void 0 : settings;
|
|
2017
2308
|
}
|
|
@@ -2079,12 +2370,18 @@ function effectiveDefinitions(definitions, layout, options = {}) {
|
|
|
2079
2370
|
}
|
|
2080
2371
|
function sameSettings(a, b) {
|
|
2081
2372
|
if (a === b) return true;
|
|
2082
|
-
return a?.title === b?.title && a?.width === b?.width && a?.flexible === b?.flexible && sameOptionValues(a?.options ?? {}, b?.options ?? {});
|
|
2373
|
+
return a?.title === b?.title && a?.width === b?.width && a?.flexible === b?.flexible && a?.view === b?.view && sameOptionValues(a?.options ?? {}, b?.options ?? {});
|
|
2083
2374
|
}
|
|
2084
2375
|
function setWidgetSettings(layout, key, patch) {
|
|
2085
2376
|
const before = layout.settings?.[key];
|
|
2086
2377
|
const draft = { ...before };
|
|
2087
|
-
for (const field of [
|
|
2378
|
+
for (const field of [
|
|
2379
|
+
"title",
|
|
2380
|
+
"width",
|
|
2381
|
+
"flexible",
|
|
2382
|
+
"options",
|
|
2383
|
+
"view"
|
|
2384
|
+
]) {
|
|
2088
2385
|
if (!(field in patch)) continue;
|
|
2089
2386
|
const value = patch[field];
|
|
2090
2387
|
if (value === void 0) {
|
|
@@ -2117,6 +2414,62 @@ function isTitleInUse(definitions, layout, key, title) {
|
|
|
2117
2414
|
);
|
|
2118
2415
|
}
|
|
2119
2416
|
|
|
2417
|
+
// src/core/clones.ts
|
|
2418
|
+
function cloneNumber(key) {
|
|
2419
|
+
const match = /#(\d+)$/.exec(key);
|
|
2420
|
+
return match === null ? void 0 : Number(match[1]);
|
|
2421
|
+
}
|
|
2422
|
+
function cleanClones(definitions, clones, options = {}) {
|
|
2423
|
+
if (clones === void 0) return void 0;
|
|
2424
|
+
const byKey = new Map(definitions.map((d) => [d.key, d]));
|
|
2425
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2426
|
+
const kept = [];
|
|
2427
|
+
for (const clone of clones) {
|
|
2428
|
+
if (seen.has(clone.key)) continue;
|
|
2429
|
+
const original = byKey.get(clone.from);
|
|
2430
|
+
if (original === void 0 || original.sourceKey !== void 0) continue;
|
|
2431
|
+
const existing = byKey.get(clone.key);
|
|
2432
|
+
if (existing !== void 0 && existing.sourceKey !== clone.from) continue;
|
|
2433
|
+
if (options.overrideLocks !== true && resolveWidgetLock(original).clone) {
|
|
2434
|
+
continue;
|
|
2435
|
+
}
|
|
2436
|
+
seen.add(clone.key);
|
|
2437
|
+
kept.push(clone);
|
|
2438
|
+
}
|
|
2439
|
+
if (kept.length === 0) return void 0;
|
|
2440
|
+
return kept.length === clones.length && kept.every((c, i) => c === clones[i]) ? clones : kept;
|
|
2441
|
+
}
|
|
2442
|
+
function defaultCloneTitle(original, clone, index) {
|
|
2443
|
+
const base = original.title ?? original.key;
|
|
2444
|
+
const suffix = ` (#${cloneNumber(clone.key) ?? index + 1})`;
|
|
2445
|
+
return `${base.slice(0, MAX_WIDGET_TITLE_LENGTH - suffix.length)}${suffix}`;
|
|
2446
|
+
}
|
|
2447
|
+
function withClones(definitions, layout, options = {}) {
|
|
2448
|
+
const valid = cleanClones(
|
|
2449
|
+
definitions,
|
|
2450
|
+
layout.clones,
|
|
2451
|
+
options
|
|
2452
|
+
);
|
|
2453
|
+
if (valid === void 0) return definitions;
|
|
2454
|
+
const present = new Set(definitions.map((d) => d.key));
|
|
2455
|
+
const toAdd = valid.filter((c) => !present.has(c.key));
|
|
2456
|
+
if (toAdd.length === 0) return definitions;
|
|
2457
|
+
const out = [];
|
|
2458
|
+
for (const definition of definitions) {
|
|
2459
|
+
out.push(definition);
|
|
2460
|
+
toAdd.forEach((clone, index) => {
|
|
2461
|
+
if (clone.from !== definition.key) return;
|
|
2462
|
+
const copy = { ...definition };
|
|
2463
|
+
copy.key = clone.key;
|
|
2464
|
+
copy.sourceKey = definition.key;
|
|
2465
|
+
copy.title = defaultCloneTitle(definition, clone, index);
|
|
2466
|
+
delete copy.locked;
|
|
2467
|
+
out.push(copy);
|
|
2468
|
+
});
|
|
2469
|
+
}
|
|
2470
|
+
return out;
|
|
2471
|
+
}
|
|
2472
|
+
|
|
2120
2473
|
// src/core/layout.ts
|
|
2121
2474
|
var MAX_PAGE_TITLE_LENGTH = 30;
|
|
2122
2475
|
var MAX_PARSED_PAGES = 50;
|
|
@@ -2594,6 +2947,114 @@ function moveWidgetToPage(definitions, layout, widgetKey, targetKey, options = {
|
|
|
2594
2947
|
}
|
|
2595
2948
|
return ok(moved);
|
|
2596
2949
|
}
|
|
2950
|
+
|
|
2951
|
+
// src/core/duplicate.ts
|
|
2952
|
+
function canDuplicate(definitions, key, options = {}) {
|
|
2953
|
+
const definition = definitions.find(
|
|
2954
|
+
(d) => d.key === key
|
|
2955
|
+
);
|
|
2956
|
+
if (definition === void 0) return false;
|
|
2957
|
+
if (options.overrideLocks === true) return true;
|
|
2958
|
+
const sourceKey = definition.sourceKey ?? definition.key;
|
|
2959
|
+
const original = definitions.find(
|
|
2960
|
+
(d) => d.key === sourceKey
|
|
2961
|
+
);
|
|
2962
|
+
return original !== void 0 && !resolveWidgetLock(original).clone;
|
|
2963
|
+
}
|
|
2964
|
+
function nextCloneKey(definitions, layout, fromKey) {
|
|
2965
|
+
const taken = /* @__PURE__ */ new Set([
|
|
2966
|
+
...definitions.map((d) => d.key),
|
|
2967
|
+
...(layout.clones ?? []).map((c) => c.key)
|
|
2968
|
+
]);
|
|
2969
|
+
let highest = 0;
|
|
2970
|
+
for (const clone of layout.clones ?? []) {
|
|
2971
|
+
if (clone.from === fromKey) {
|
|
2972
|
+
highest = Math.max(highest, cloneNumber(clone.key) ?? 0);
|
|
2973
|
+
}
|
|
2974
|
+
}
|
|
2975
|
+
let n = highest + 1;
|
|
2976
|
+
while (taken.has(`${fromKey}#${n}`)) n += 1;
|
|
2977
|
+
return `${fromKey}#${n}`;
|
|
2978
|
+
}
|
|
2979
|
+
function duplicateWidget(definitions, layout, key, options = {}) {
|
|
2980
|
+
const widget = definitions.find((d) => d.key === key);
|
|
2981
|
+
if (widget === void 0) {
|
|
2982
|
+
return err(`Widget ${JSON.stringify(key)} isn't on this dashboard.`);
|
|
2983
|
+
}
|
|
2984
|
+
const originalKey = widget.sourceKey ?? widget.key;
|
|
2985
|
+
if (!canDuplicate(definitions, key, options)) {
|
|
2986
|
+
return err(
|
|
2987
|
+
`Widget ${JSON.stringify(originalKey)} is locked against duplicating.`
|
|
2988
|
+
);
|
|
2989
|
+
}
|
|
2990
|
+
const cloneKey = nextCloneKey(definitions, layout, originalKey);
|
|
2991
|
+
const copiedSettings = (() => {
|
|
2992
|
+
const mine = layout.settings?.[key];
|
|
2993
|
+
if (mine === void 0) return void 0;
|
|
2994
|
+
const { title: _title, ...rest } = mine;
|
|
2995
|
+
return Object.keys(rest).length === 0 ? void 0 : rest;
|
|
2996
|
+
})();
|
|
2997
|
+
const settings = copiedSettings === void 0 ? layout.settings : { ...layout.settings, [cloneKey]: copiedSettings };
|
|
2998
|
+
let next = {
|
|
2999
|
+
...layout,
|
|
3000
|
+
clones: [...layout.clones ?? [], { key: cloneKey, from: originalKey }],
|
|
3001
|
+
...settings === void 0 ? {} : { settings }
|
|
3002
|
+
};
|
|
3003
|
+
const all = withClones(definitions, next, options);
|
|
3004
|
+
const assigned = assignPages(all, next);
|
|
3005
|
+
const pageKey = [...assigned].find(
|
|
3006
|
+
([, widgets]) => widgets.some((w) => w.key === key)
|
|
3007
|
+
)?.[0];
|
|
3008
|
+
if (pageKey !== void 0) {
|
|
3009
|
+
const view = pageLayout(next, pageKey);
|
|
3010
|
+
const onPage = assigned.get(pageKey) ?? [];
|
|
3011
|
+
if (view !== void 0) {
|
|
3012
|
+
const shown = visibleWidgets(onPage, view).filter((d) => !resolveWidgetLock(d).move && d.key !== cloneKey).map((d) => d.key);
|
|
3013
|
+
const at = shown.indexOf(key);
|
|
3014
|
+
const order = at === -1 ? [...shown, cloneKey] : [...shown.slice(0, at + 1), cloneKey, ...shown.slice(at + 1)];
|
|
3015
|
+
next = withPageLayout(next, pageKey, { ...view, order });
|
|
3016
|
+
}
|
|
3017
|
+
}
|
|
3018
|
+
if (hasPages(next) && pageKey !== void 0) {
|
|
3019
|
+
const effective = effectiveDefinitions(all, next, options);
|
|
3020
|
+
const room = pageRoom(effective, next, pageKey, options);
|
|
3021
|
+
if (room !== void 0 && room.rowsUsed > room.maxRows) {
|
|
3022
|
+
const page = next.pages?.find(
|
|
3023
|
+
(p) => p.key === pageKey
|
|
3024
|
+
);
|
|
3025
|
+
const width = effective.find(
|
|
3026
|
+
(d) => d.key === cloneKey
|
|
3027
|
+
)?.width;
|
|
3028
|
+
return err(
|
|
3029
|
+
`Page "${page?.title ?? pageKey}" has no room for a widget${width === void 0 ? "" : ` ${width} wide`} (it holds ${room.maxRows} rows).`
|
|
3030
|
+
);
|
|
3031
|
+
}
|
|
3032
|
+
}
|
|
3033
|
+
return ok({ layout: next, key: cloneKey });
|
|
3034
|
+
}
|
|
3035
|
+
function deleteClone(layout, key) {
|
|
3036
|
+
if (layout.clones?.some((clone) => clone.key === key) !== true) return layout;
|
|
3037
|
+
const without2 = (keys) => keys.includes(key) ? keys.filter((k) => k !== key) : keys;
|
|
3038
|
+
const { clones, settings, ...rest } = layout;
|
|
3039
|
+
const remaining = (clones ?? []).filter((c) => c.key !== key);
|
|
3040
|
+
const { [key]: _gone, ...otherSettings } = settings ?? {};
|
|
3041
|
+
return {
|
|
3042
|
+
...rest,
|
|
3043
|
+
order: without2(layout.order),
|
|
3044
|
+
hidden: without2(layout.hidden),
|
|
3045
|
+
minimized: without2(layout.minimized),
|
|
3046
|
+
...layout.pages === void 0 ? {} : {
|
|
3047
|
+
pages: layout.pages.map((page) => ({
|
|
3048
|
+
...page,
|
|
3049
|
+
order: without2(page.order),
|
|
3050
|
+
hidden: without2(page.hidden),
|
|
3051
|
+
minimized: without2(page.minimized)
|
|
3052
|
+
}))
|
|
3053
|
+
},
|
|
3054
|
+
...Object.keys(otherSettings).length === 0 ? {} : { settings: otherSettings },
|
|
3055
|
+
...remaining.length === 0 ? {} : { clones: remaining }
|
|
3056
|
+
};
|
|
3057
|
+
}
|
|
2597
3058
|
function InlineConfirm({
|
|
2598
3059
|
message,
|
|
2599
3060
|
onAnswer
|
|
@@ -2788,7 +3249,8 @@ function draftFrom(settings) {
|
|
|
2788
3249
|
title: settings?.title ?? "",
|
|
2789
3250
|
width: settings?.width,
|
|
2790
3251
|
flexible: settings?.flexible,
|
|
2791
|
-
options: settings?.options ?? {}
|
|
3252
|
+
options: settings?.options ?? {},
|
|
3253
|
+
view: settings?.view
|
|
2792
3254
|
};
|
|
2793
3255
|
}
|
|
2794
3256
|
function storedDefault(option) {
|
|
@@ -2813,7 +3275,9 @@ function patchFrom(definition, draft) {
|
|
|
2813
3275
|
title: title === "" ? void 0 : title,
|
|
2814
3276
|
width: draft.width,
|
|
2815
3277
|
flexible: draft.flexible === void 0 || draft.flexible === isFlexible(definition) ? void 0 : draft.flexible,
|
|
2816
|
-
options: Object.keys(options).length === 0 ? void 0 : options
|
|
3278
|
+
options: Object.keys(options).length === 0 ? void 0 : options,
|
|
3279
|
+
// Choosing the author's own default view again clears the setting.
|
|
3280
|
+
view: draft.view === void 0 || draft.view === effectiveViewKey(definition, void 0) ? void 0 : draft.view
|
|
2817
3281
|
};
|
|
2818
3282
|
}
|
|
2819
3283
|
function patchKey(patch) {
|
|
@@ -2821,19 +3285,28 @@ function patchKey(patch) {
|
|
|
2821
3285
|
for (const key of Object.keys(patch.options ?? {}).sort()) {
|
|
2822
3286
|
options[key] = patch.options[key];
|
|
2823
3287
|
}
|
|
2824
|
-
return JSON.stringify([
|
|
3288
|
+
return JSON.stringify([
|
|
3289
|
+
patch.title,
|
|
3290
|
+
patch.width,
|
|
3291
|
+
patch.flexible,
|
|
3292
|
+
options,
|
|
3293
|
+
patch.view
|
|
3294
|
+
]);
|
|
2825
3295
|
}
|
|
2826
3296
|
var EMPTY_PATCH = {
|
|
2827
3297
|
title: void 0,
|
|
2828
3298
|
width: void 0,
|
|
2829
3299
|
flexible: void 0,
|
|
2830
|
-
options: void 0
|
|
3300
|
+
options: void 0,
|
|
3301
|
+
view: void 0
|
|
2831
3302
|
};
|
|
2832
3303
|
function WidgetOptionsDialog({
|
|
2833
3304
|
definition,
|
|
2834
3305
|
settings,
|
|
2835
3306
|
baseline,
|
|
2836
3307
|
isTitleInUse: isTitleInUse2,
|
|
3308
|
+
sourceTitle,
|
|
3309
|
+
onDelete,
|
|
2837
3310
|
onApply,
|
|
2838
3311
|
onClose
|
|
2839
3312
|
}) {
|
|
@@ -2846,6 +3319,7 @@ function WidgetOptionsDialog({
|
|
|
2846
3319
|
const [confirming, setConfirming] = useState(
|
|
2847
3320
|
void 0
|
|
2848
3321
|
);
|
|
3322
|
+
const autoTitle = useRef(void 0);
|
|
2849
3323
|
useEffect(() => {
|
|
2850
3324
|
const dialog = dialogRef.current;
|
|
2851
3325
|
if (dialog === null) return void 0;
|
|
@@ -2865,6 +3339,7 @@ function WidgetOptionsDialog({
|
|
|
2865
3339
|
const canRevert = baselineKey !== void 0 && baselineKey !== savedKey;
|
|
2866
3340
|
const canReset = savedKey !== patchKey(EMPTY_PATCH);
|
|
2867
3341
|
const range = widthRange(definition);
|
|
3342
|
+
const views = viewChoices(definition);
|
|
2868
3343
|
const effectiveFlexible = draft.flexible ?? isFlexible(definition);
|
|
2869
3344
|
function requestClose() {
|
|
2870
3345
|
if (confirming !== void 0) {
|
|
@@ -2887,6 +3362,9 @@ function WidgetOptionsDialog({
|
|
|
2887
3362
|
} else if (which === "reset") {
|
|
2888
3363
|
onApply(EMPTY_PATCH);
|
|
2889
3364
|
onClose();
|
|
3365
|
+
} else if (which === "delete") {
|
|
3366
|
+
onDelete?.();
|
|
3367
|
+
onClose();
|
|
2890
3368
|
} else if (baseline !== void 0) {
|
|
2891
3369
|
onApply(patchFrom(definition, draftFrom(baseline.settings)));
|
|
2892
3370
|
onClose();
|
|
@@ -2902,7 +3380,8 @@ function WidgetOptionsDialog({
|
|
|
2902
3380
|
apply: labels.confirmApply,
|
|
2903
3381
|
discard: labels.confirmDiscard,
|
|
2904
3382
|
reset: labels.confirmResetOptions,
|
|
2905
|
-
revert: labels.confirmRevertOptions
|
|
3383
|
+
revert: labels.confirmRevertOptions,
|
|
3384
|
+
delete: labels.confirmDelete
|
|
2906
3385
|
};
|
|
2907
3386
|
const widths = [];
|
|
2908
3387
|
for (let width = range.min; width <= range.max; width += 1)
|
|
@@ -2990,6 +3469,46 @@ function WidgetOptionsDialog({
|
|
|
2990
3469
|
),
|
|
2991
3470
|
labels.optionsFlexible
|
|
2992
3471
|
] }),
|
|
3472
|
+
views.length > 0 && /* @__PURE__ */ jsxs("div", { className: "dwt-options-field", children: [
|
|
3473
|
+
/* @__PURE__ */ jsx("label", { htmlFor: `${baseId}-view`, children: labels.optionsViewField }),
|
|
3474
|
+
/* @__PURE__ */ jsx(
|
|
3475
|
+
"select",
|
|
3476
|
+
{
|
|
3477
|
+
id: `${baseId}-view`,
|
|
3478
|
+
value: effectiveViewKey(definition, draft.view),
|
|
3479
|
+
onChange: (event) => {
|
|
3480
|
+
const value = event.target.value;
|
|
3481
|
+
setDraft((current) => {
|
|
3482
|
+
const next = { ...current, view: value };
|
|
3483
|
+
if (sourceTitle === void 0 || current.title.trim() !== "" && current.title !== autoTitle.current) {
|
|
3484
|
+
return next;
|
|
3485
|
+
}
|
|
3486
|
+
const label = views.find(
|
|
3487
|
+
(view) => view.key === value
|
|
3488
|
+
)?.label;
|
|
3489
|
+
const startView = effectiveViewKey(
|
|
3490
|
+
definition,
|
|
3491
|
+
settings?.view
|
|
3492
|
+
);
|
|
3493
|
+
if (label === void 0 || value === startView) {
|
|
3494
|
+
autoTitle.current = void 0;
|
|
3495
|
+
return { ...next, title: "" };
|
|
3496
|
+
}
|
|
3497
|
+
let suggestion = labels.suggestedViewTitle(
|
|
3498
|
+
sourceTitle,
|
|
3499
|
+
label
|
|
3500
|
+
);
|
|
3501
|
+
for (let n = 2; isTitleInUse2?.(suggestion) === true && n < 50; n += 1) {
|
|
3502
|
+
suggestion = `${labels.suggestedViewTitle(sourceTitle, label)} (#${n})`;
|
|
3503
|
+
}
|
|
3504
|
+
autoTitle.current = suggestion;
|
|
3505
|
+
return { ...next, title: suggestion };
|
|
3506
|
+
});
|
|
3507
|
+
},
|
|
3508
|
+
children: views.map((view) => /* @__PURE__ */ jsx("option", { value: view.key, children: view.key === effectiveViewKey(definition, void 0) ? labels.viewDefault(view.label) : view.label }, view.key))
|
|
3509
|
+
}
|
|
3510
|
+
)
|
|
3511
|
+
] }),
|
|
2993
3512
|
(definition.options?.length ?? 0) > 0 && /* @__PURE__ */ jsxs("fieldset", { className: "dwt-options-group", children: [
|
|
2994
3513
|
/* @__PURE__ */ jsx("legend", { children: labels.optionsDeclared }),
|
|
2995
3514
|
(definition.options ?? []).map((option) => /* @__PURE__ */ jsx(
|
|
@@ -3041,6 +3560,15 @@ function WidgetOptionsDialog({
|
|
|
3041
3560
|
onClick: () => setConfirming("revert"),
|
|
3042
3561
|
children: labels.revertToBeforeEditing
|
|
3043
3562
|
}
|
|
3563
|
+
),
|
|
3564
|
+
onDelete !== void 0 && /* @__PURE__ */ jsx(
|
|
3565
|
+
"button",
|
|
3566
|
+
{
|
|
3567
|
+
type: "button",
|
|
3568
|
+
className: slot("button", "dwt-button"),
|
|
3569
|
+
onClick: () => setConfirming("delete"),
|
|
3570
|
+
children: labels.optionsDelete
|
|
3571
|
+
}
|
|
3044
3572
|
)
|
|
3045
3573
|
] }) : /* @__PURE__ */ jsx(
|
|
3046
3574
|
InlineConfirm,
|
|
@@ -3969,10 +4497,13 @@ function DashboardInner({
|
|
|
3969
4497
|
className
|
|
3970
4498
|
}) {
|
|
3971
4499
|
const slot = useSlotClassName();
|
|
3972
|
-
const { labels } = useWidgetSettings();
|
|
4500
|
+
const { labels, locale } = useWidgetSettings();
|
|
3973
4501
|
const effectiveWidgets = widgets.map((w) => {
|
|
3974
|
-
const settings = savedLayout.settings?.[w.definition.key];
|
|
3975
|
-
|
|
4502
|
+
const settings = !overrideLocks && isOptionsLocked(w.definition) ? void 0 : savedLayout.settings?.[w.definition.key];
|
|
4503
|
+
const styled = settings === void 0 ? w : { ...w, definition: applySettings(w.definition, settings) };
|
|
4504
|
+
return applyView(styled, settings?.view, {
|
|
4505
|
+
...locale === void 0 ? {} : { locale }
|
|
4506
|
+
});
|
|
3976
4507
|
});
|
|
3977
4508
|
const definitions = effectiveWidgets.map(
|
|
3978
4509
|
(w) => overrideLocks ? withoutLock(w.definition) : w.definition
|
|
@@ -4042,6 +4573,29 @@ function DashboardInner({
|
|
|
4042
4573
|
setPageError(void 0);
|
|
4043
4574
|
change(withPageLayout(layout, activeKey, next));
|
|
4044
4575
|
}
|
|
4576
|
+
function duplicateItems(definition, key, title) {
|
|
4577
|
+
const sources = [...authorDefinitions.values()];
|
|
4578
|
+
if (!canDuplicate(sources, key, { overrideLocks })) return [];
|
|
4579
|
+
const trial = duplicateWidget(sources, layout, key, {
|
|
4580
|
+
overrideLocks,
|
|
4581
|
+
...roomOptions
|
|
4582
|
+
});
|
|
4583
|
+
return [
|
|
4584
|
+
{
|
|
4585
|
+
kind: "action",
|
|
4586
|
+
key: "duplicate",
|
|
4587
|
+
label: labels.menuDuplicate,
|
|
4588
|
+
ariaLabel: trial.ok ? labels.duplicate(title) : labels.duplicateBlocked(title, trial.error),
|
|
4589
|
+
disabled: !trial.ok,
|
|
4590
|
+
onSelect: () => {
|
|
4591
|
+
if (!trial.ok) return;
|
|
4592
|
+
change(trial.value.layout);
|
|
4593
|
+
setOptionsKey(trial.value.key);
|
|
4594
|
+
setAnnouncement(labels.duplicated(title));
|
|
4595
|
+
}
|
|
4596
|
+
}
|
|
4597
|
+
];
|
|
4598
|
+
}
|
|
4045
4599
|
function selectPage(pageKey) {
|
|
4046
4600
|
const index = pages.findIndex((page) => page.key === pageKey);
|
|
4047
4601
|
if (index === -1) return;
|
|
@@ -4171,10 +4725,16 @@ function DashboardInner({
|
|
|
4171
4725
|
definitions,
|
|
4172
4726
|
defaultLayout ?? EMPTY_LAYOUT
|
|
4173
4727
|
);
|
|
4174
|
-
const {
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4728
|
+
const {
|
|
4729
|
+
settings: _defaultSettings,
|
|
4730
|
+
clones: _defaultClones,
|
|
4731
|
+
...arrangement
|
|
4732
|
+
} = arranged;
|
|
4733
|
+
change({
|
|
4734
|
+
...arrangement,
|
|
4735
|
+
...layout.settings === void 0 ? {} : { settings: layout.settings },
|
|
4736
|
+
...layout.clones === void 0 ? {} : { clones: layout.clones }
|
|
4737
|
+
});
|
|
4178
4738
|
} else if (yes && which === "revert" && snapshot !== void 0) {
|
|
4179
4739
|
change(snapshot);
|
|
4180
4740
|
}
|
|
@@ -4480,6 +5040,7 @@ function DashboardInner({
|
|
|
4480
5040
|
onSelect: () => setOptionsKey(key)
|
|
4481
5041
|
}
|
|
4482
5042
|
],
|
|
5043
|
+
...duplicateItems(definition, key, title),
|
|
4483
5044
|
...pageTargets,
|
|
4484
5045
|
...lock.hide ? [] : [
|
|
4485
5046
|
{
|
|
@@ -4574,6 +5135,21 @@ function DashboardInner({
|
|
|
4574
5135
|
definition: authorDefinitions.get(optionsKey),
|
|
4575
5136
|
settings: layout.settings?.[optionsKey],
|
|
4576
5137
|
...snapshot === void 0 ? {} : { baseline: { settings: snapshot.settings?.[optionsKey] } },
|
|
5138
|
+
...authorDefinitions.get(optionsKey)?.sourceKey === void 0 ? {} : {
|
|
5139
|
+
sourceTitle: effectiveWidgets.find(
|
|
5140
|
+
(w) => w.definition.key === authorDefinitions.get(optionsKey)?.sourceKey
|
|
5141
|
+
)?.definition.title ?? authorDefinitions.get(optionsKey)?.sourceKey ?? "",
|
|
5142
|
+
onDelete: () => {
|
|
5143
|
+
change(deleteClone(layout, optionsKey));
|
|
5144
|
+
setAnnouncement(
|
|
5145
|
+
labels.deleted(
|
|
5146
|
+
effectiveWidgets.find(
|
|
5147
|
+
(w) => w.definition.key === optionsKey
|
|
5148
|
+
)?.definition.title ?? optionsKey
|
|
5149
|
+
)
|
|
5150
|
+
);
|
|
5151
|
+
}
|
|
5152
|
+
},
|
|
4577
5153
|
isTitleInUse: (title) => isTitleInUse(
|
|
4578
5154
|
widgets.map((w) => w.definition),
|
|
4579
5155
|
layout,
|
|
@@ -4817,45 +5393,6 @@ function useStoredLayout(options) {
|
|
|
4817
5393
|
};
|
|
4818
5394
|
}
|
|
4819
5395
|
|
|
4820
|
-
// src/core/payload.ts
|
|
4821
|
-
var WIDGET_KINDS = [
|
|
4822
|
-
"TEXT",
|
|
4823
|
-
"KPI",
|
|
4824
|
-
"GAUGE",
|
|
4825
|
-
"TABLE",
|
|
4826
|
-
"BAR_LIST",
|
|
4827
|
-
"ALERT_LIST",
|
|
4828
|
-
"GRAPH"
|
|
4829
|
-
];
|
|
4830
|
-
function isWidgetKind(value) {
|
|
4831
|
-
return typeof value === "string" && WIDGET_KINDS.includes(value);
|
|
4832
|
-
}
|
|
4833
|
-
var VALUE_FORMATS = ["number", "currency", "percent"];
|
|
4834
|
-
var MAX_GRAPH_SERIES = 8;
|
|
4835
|
-
var DEFAULT_EMPTY_TEXT = "Nothing to show yet.";
|
|
4836
|
-
function isWidgetEmptyState(payload) {
|
|
4837
|
-
return "empty" in payload && payload.empty === true;
|
|
4838
|
-
}
|
|
4839
|
-
function emptyTextFor(payload) {
|
|
4840
|
-
if (isWidgetEmptyState(payload)) {
|
|
4841
|
-
return payload.text;
|
|
4842
|
-
}
|
|
4843
|
-
switch (payload.kind) {
|
|
4844
|
-
case "TABLE":
|
|
4845
|
-
return payload.rows.length === 0 ? DEFAULT_EMPTY_TEXT : null;
|
|
4846
|
-
case "BAR_LIST":
|
|
4847
|
-
return payload.items.length === 0 ? DEFAULT_EMPTY_TEXT : null;
|
|
4848
|
-
case "ALERT_LIST":
|
|
4849
|
-
return payload.items.length === 0 ? payload.emptyText : null;
|
|
4850
|
-
case "GRAPH":
|
|
4851
|
-
return payload.series.every((series) => series.points.length === 0) ? DEFAULT_EMPTY_TEXT : null;
|
|
4852
|
-
case "TEXT":
|
|
4853
|
-
case "KPI":
|
|
4854
|
-
case "GAUGE":
|
|
4855
|
-
return null;
|
|
4856
|
-
}
|
|
4857
|
-
}
|
|
4858
|
-
|
|
4859
5396
|
// src/core/validate.ts
|
|
4860
5397
|
var MAX_REPORTED_PROBLEMS = 10;
|
|
4861
5398
|
function describeType2(value) {
|
|
@@ -5160,7 +5697,7 @@ function loadingWidgets(definitions) {
|
|
|
5160
5697
|
return definitions.map((definition) => ({ definition, status: "loading" }));
|
|
5161
5698
|
}
|
|
5162
5699
|
function cacheKeyFor(definition, options, values) {
|
|
5163
|
-
const base = options.cacheKey === void 0 ? definition.key : options.cacheKey(definition);
|
|
5700
|
+
const base = options.cacheKey === void 0 ? definition.sourceKey ?? definition.key : options.cacheKey(definition);
|
|
5164
5701
|
return values === void 0 ? base : `${base}${optionsCacheSuffix(definition, values, options)}`;
|
|
5165
5702
|
}
|
|
5166
5703
|
function optionValuesFor(definition, options) {
|
|
@@ -5334,7 +5871,11 @@ function createWidgetLoader(options) {
|
|
|
5334
5871
|
}
|
|
5335
5872
|
}
|
|
5336
5873
|
if (!isCurrent()) return;
|
|
5337
|
-
const
|
|
5874
|
+
const providerKey = definition.sourceKey ?? key;
|
|
5875
|
+
const provider = Object.prototype.hasOwnProperty.call(
|
|
5876
|
+
providers,
|
|
5877
|
+
providerKey
|
|
5878
|
+
) ? providers[providerKey] : void 0;
|
|
5338
5879
|
const result = await resolveWidgetUnapplied(definition, provider, context, {
|
|
5339
5880
|
...runOptions,
|
|
5340
5881
|
signal: controller.signal
|