@richardmcquiston01/dashboard-widgets-toolkit 0.2.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +90 -8
- package/dist/core.cjs +642 -69
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +61 -18
- package/dist/core.d.ts +61 -18
- package/dist/core.js +623 -70
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +642 -69
- 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 +623 -70
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +1516 -86
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +155 -14
- package/dist/react.d.ts +155 -14
- package/dist/react.js +1514 -88
- package/dist/react.js.map +1 -1
- package/dist/{scale-Bhjc5Eqt.d.cts → scale-dWDGE1zW.d.cts} +327 -118
- package/dist/{scale-Bhjc5Eqt.d.ts → scale-dWDGE1zW.d.ts} +327 -118
- package/dist/styles.css +154 -6
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -192,7 +192,395 @@ function kpiDelta(current, previous, options = {}) {
|
|
|
192
192
|
};
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
+
// src/core/result.ts
|
|
196
|
+
function ok(value) {
|
|
197
|
+
return { ok: true, value };
|
|
198
|
+
}
|
|
199
|
+
function err(error) {
|
|
200
|
+
return { ok: false, error };
|
|
201
|
+
}
|
|
202
|
+
function describeUnknownError(cause) {
|
|
203
|
+
if (cause instanceof Error) {
|
|
204
|
+
return cause.message === "" ? cause.name : cause.message;
|
|
205
|
+
}
|
|
206
|
+
if (typeof cause === "string") {
|
|
207
|
+
return cause;
|
|
208
|
+
}
|
|
209
|
+
try {
|
|
210
|
+
const json = JSON.stringify(cause);
|
|
211
|
+
return json ?? String(cause);
|
|
212
|
+
} catch {
|
|
213
|
+
return String(cause);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// src/core/url.ts
|
|
218
|
+
var SCHEME_PATTERN = /^([a-z][a-z0-9+.-]*):/i;
|
|
219
|
+
var IGNORED_IN_SCHEME = /[\u0000- \u007f]/g;
|
|
220
|
+
function schemeOf(url) {
|
|
221
|
+
const match = SCHEME_PATTERN.exec(
|
|
222
|
+
url.replace(IGNORED_IN_SCHEME, "")
|
|
223
|
+
);
|
|
224
|
+
return match === null ? null : (match[1] ?? "").toLowerCase();
|
|
225
|
+
}
|
|
226
|
+
function isSafeHref(url) {
|
|
227
|
+
if (url.trim() === "") {
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
230
|
+
const scheme = schemeOf(url);
|
|
231
|
+
return scheme === null || scheme === "http" || scheme === "https" || scheme === "mailto";
|
|
232
|
+
}
|
|
233
|
+
function isSafeImageUrl(url) {
|
|
234
|
+
if (url.trim() === "") {
|
|
235
|
+
return false;
|
|
236
|
+
}
|
|
237
|
+
const scheme = schemeOf(url);
|
|
238
|
+
return scheme === null || scheme === "http" || scheme === "https";
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// src/core/detail.ts
|
|
242
|
+
var DETAIL_MODES = ["client", "server"];
|
|
243
|
+
var DEFAULT_DETAIL_PAGE_SIZE = 25;
|
|
244
|
+
var MAX_DETAIL_PAGE_SIZE = 200;
|
|
245
|
+
function resolveDetailOptions(definition) {
|
|
246
|
+
const detail = definition.detail;
|
|
247
|
+
if (detail === void 0 || detail === false) return void 0;
|
|
248
|
+
const options = detail === true ? {} : detail;
|
|
249
|
+
return {
|
|
250
|
+
title: options.title ?? definition.title,
|
|
251
|
+
pageSize: options.pageSize ?? DEFAULT_DETAIL_PAGE_SIZE,
|
|
252
|
+
mode: options.mode ?? "client"
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
function defaultDetailQuery(pageSize = DEFAULT_DETAIL_PAGE_SIZE) {
|
|
256
|
+
return { page: 1, pageSize };
|
|
257
|
+
}
|
|
258
|
+
function fold(text) {
|
|
259
|
+
return text.normalize("NFD").replace(/\p{M}/gu, "").toLowerCase();
|
|
260
|
+
}
|
|
261
|
+
function cellValue(cell) {
|
|
262
|
+
return cell.value ?? cell.text;
|
|
263
|
+
}
|
|
264
|
+
function cellMatches(cell, needle) {
|
|
265
|
+
return fold(String(cellValue(cell))).includes(needle);
|
|
266
|
+
}
|
|
267
|
+
function compareCells(a, b, collator) {
|
|
268
|
+
const left = cellValue(a);
|
|
269
|
+
const right = cellValue(b);
|
|
270
|
+
if (typeof left === "number" && typeof right === "number") {
|
|
271
|
+
return left - right;
|
|
272
|
+
}
|
|
273
|
+
if (typeof left === "number") return -1;
|
|
274
|
+
if (typeof right === "number") return 1;
|
|
275
|
+
return collator.compare(left, right);
|
|
276
|
+
}
|
|
277
|
+
function queryRows(data, query, locale) {
|
|
278
|
+
const indexOf = new Map(
|
|
279
|
+
data.columns.map((column, index) => [column.key, index])
|
|
280
|
+
);
|
|
281
|
+
const filterEntries = [];
|
|
282
|
+
for (const [key, text] of Object.entries(query.filters ?? {})) {
|
|
283
|
+
const index = indexOf.get(key);
|
|
284
|
+
if (index === void 0) {
|
|
285
|
+
return err(
|
|
286
|
+
`Detail query: filter column "${key}" does not exist. Columns: ${listKeys(data)}.`
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
const needle = fold(text.trim());
|
|
290
|
+
if (needle !== "") filterEntries.push({ index, needle });
|
|
291
|
+
}
|
|
292
|
+
let sortIndex = -1;
|
|
293
|
+
if (query.sort !== void 0) {
|
|
294
|
+
const found = indexOf.get(query.sort.column);
|
|
295
|
+
const column = found === void 0 ? void 0 : data.columns[found];
|
|
296
|
+
if (found === void 0 || column === void 0) {
|
|
297
|
+
return err(
|
|
298
|
+
`Detail query: sort column "${query.sort.column}" does not exist. Columns: ${listKeys(data)}.`
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
if (column.sortable === false) {
|
|
302
|
+
return err(
|
|
303
|
+
`Detail query: column "${column.key}" is not sortable (sortable: false).`
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
sortIndex = found;
|
|
307
|
+
}
|
|
308
|
+
const search = fold((query.search ?? "").trim());
|
|
309
|
+
let rows = data.rows.filter(
|
|
310
|
+
(row) => filterEntries.every(({ index, needle }) => {
|
|
311
|
+
const cell = row[index];
|
|
312
|
+
return cell !== void 0 && cellMatches(cell, needle);
|
|
313
|
+
}) && (search === "" || row.some((cell) => cellMatches(cell, search)))
|
|
314
|
+
);
|
|
315
|
+
if (query.sort !== void 0 && sortIndex >= 0) {
|
|
316
|
+
const collator = new Intl.Collator(locale, {
|
|
317
|
+
numeric: true,
|
|
318
|
+
sensitivity: "base"
|
|
319
|
+
});
|
|
320
|
+
const sign = query.sort.direction === "desc" ? -1 : 1;
|
|
321
|
+
rows = rows.map((row, position) => ({ row, position })).sort((a, b) => {
|
|
322
|
+
const left = a.row[sortIndex];
|
|
323
|
+
const right = b.row[sortIndex];
|
|
324
|
+
const order = left === void 0 || right === void 0 ? 0 : sign * compareCells(left, right, collator);
|
|
325
|
+
return order || a.position - b.position;
|
|
326
|
+
}).map(({ row }) => row);
|
|
327
|
+
}
|
|
328
|
+
const pageSize = Math.max(1, Math.floor(query.pageSize));
|
|
329
|
+
const pageCount = Math.max(1, Math.ceil(rows.length / pageSize));
|
|
330
|
+
const page = Math.min(Math.max(1, Math.floor(query.page)), pageCount);
|
|
331
|
+
return ok({
|
|
332
|
+
rows: rows.slice((page - 1) * pageSize, page * pageSize),
|
|
333
|
+
totalRows: rows.length,
|
|
334
|
+
page,
|
|
335
|
+
pageCount
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
function listKeys(data) {
|
|
339
|
+
return data.columns.map((column) => `"${column.key}"`).join(", ");
|
|
340
|
+
}
|
|
341
|
+
var FILTER_PREFIX = "f.";
|
|
342
|
+
function serializeDetailQuery(query) {
|
|
343
|
+
const parts = [];
|
|
344
|
+
const add = (key, value) => {
|
|
345
|
+
parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
|
|
346
|
+
};
|
|
347
|
+
if (query.search !== void 0 && query.search !== "") {
|
|
348
|
+
add("q", query.search);
|
|
349
|
+
}
|
|
350
|
+
if (query.sort !== void 0) {
|
|
351
|
+
add("sort", `${query.sort.column}:${query.sort.direction}`);
|
|
352
|
+
}
|
|
353
|
+
for (const [column, text] of Object.entries(query.filters ?? {})) {
|
|
354
|
+
if (text !== "") add(`${FILTER_PREFIX}${column}`, text);
|
|
355
|
+
}
|
|
356
|
+
if (query.page > 1) add("page", String(query.page));
|
|
357
|
+
return parts.join("&");
|
|
358
|
+
}
|
|
359
|
+
function parseDetailQuery(queryString, pageSize = DEFAULT_DETAIL_PAGE_SIZE, data) {
|
|
360
|
+
let search;
|
|
361
|
+
let sort;
|
|
362
|
+
let page = 1;
|
|
363
|
+
const filters = {};
|
|
364
|
+
const columnKeys = data === void 0 ? void 0 : new Set(data.columns.map((column) => column.key));
|
|
365
|
+
const text = queryString.startsWith("?") ? queryString.slice(1) : queryString;
|
|
366
|
+
for (const pair of text.split("&")) {
|
|
367
|
+
if (pair === "") continue;
|
|
368
|
+
const equals = pair.indexOf("=");
|
|
369
|
+
const rawKey = equals < 0 ? pair : pair.slice(0, equals);
|
|
370
|
+
const rawValue = equals < 0 ? "" : pair.slice(equals + 1);
|
|
371
|
+
let key;
|
|
372
|
+
let value;
|
|
373
|
+
try {
|
|
374
|
+
key = decodeURIComponent(rawKey.replace(/\+/g, " "));
|
|
375
|
+
value = decodeURIComponent(rawValue.replace(/\+/g, " "));
|
|
376
|
+
} catch {
|
|
377
|
+
return err(
|
|
378
|
+
`Detail query: "${pair}" is not valid percent-encoding in the URL.`
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
if (key === "q") {
|
|
382
|
+
search = value;
|
|
383
|
+
} else if (key === "page") {
|
|
384
|
+
if (!/^[1-9]\d*$/.test(value)) {
|
|
385
|
+
return err(
|
|
386
|
+
`Detail query: page must be a whole number from 1, got "${value}".`
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
page = Number(value);
|
|
390
|
+
} else if (key === "sort") {
|
|
391
|
+
const colon = value.lastIndexOf(":");
|
|
392
|
+
const column = colon < 0 ? value : value.slice(0, colon);
|
|
393
|
+
const direction = colon < 0 ? "asc" : value.slice(colon + 1);
|
|
394
|
+
if (column === "" || direction !== "asc" && direction !== "desc") {
|
|
395
|
+
return err(
|
|
396
|
+
`Detail query: sort must look like "column:asc" or "column:desc", got "${value}".`
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
if (columnKeys !== void 0 && !columnKeys.has(column)) {
|
|
400
|
+
return err(`Detail query: sort column "${column}" does not exist.`);
|
|
401
|
+
}
|
|
402
|
+
sort = { column, direction };
|
|
403
|
+
} else if (key.startsWith(FILTER_PREFIX)) {
|
|
404
|
+
const column = key.slice(FILTER_PREFIX.length);
|
|
405
|
+
if (columnKeys !== void 0 && !columnKeys.has(column)) {
|
|
406
|
+
return err(`Detail query: filter column "${column}" does not exist.`);
|
|
407
|
+
}
|
|
408
|
+
if (value !== "") filters[column] = value;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
return ok({
|
|
412
|
+
...search === void 0 || search === "" ? {} : { search },
|
|
413
|
+
...Object.keys(filters).length === 0 ? {} : { filters },
|
|
414
|
+
...sort === void 0 ? {} : { sort },
|
|
415
|
+
page,
|
|
416
|
+
pageSize
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
function describeType(value) {
|
|
420
|
+
if (value === null) return "null";
|
|
421
|
+
if (Array.isArray(value)) return "array";
|
|
422
|
+
return typeof value;
|
|
423
|
+
}
|
|
424
|
+
function validateDetailData(data, subject = "Detail data") {
|
|
425
|
+
const problems = [];
|
|
426
|
+
if (typeof data !== "object" || data === null || Array.isArray(data)) {
|
|
427
|
+
return err(`${subject}: must be an object, got ${describeType(data)}.`);
|
|
428
|
+
}
|
|
429
|
+
const record = data;
|
|
430
|
+
const columns = record["columns"];
|
|
431
|
+
const rows = record["rows"];
|
|
432
|
+
const keys = /* @__PURE__ */ new Set();
|
|
433
|
+
let columnCount = 0;
|
|
434
|
+
if (!Array.isArray(columns) || columns.length === 0) {
|
|
435
|
+
problems.push(
|
|
436
|
+
`columns must be a non-empty array, got ${describeType(columns)}.`
|
|
437
|
+
);
|
|
438
|
+
} else {
|
|
439
|
+
columnCount = columns.length;
|
|
440
|
+
columns.forEach((column, index) => {
|
|
441
|
+
const at = `columns[${index}]`;
|
|
442
|
+
if (typeof column !== "object" || column === null) {
|
|
443
|
+
problems.push(`${at} must be an object, got ${describeType(column)}.`);
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
const fields = column;
|
|
447
|
+
const key = fields["key"];
|
|
448
|
+
if (typeof key !== "string" || key === "") {
|
|
449
|
+
problems.push(`${at}.key must be a non-empty string.`);
|
|
450
|
+
} else if (keys.has(key)) {
|
|
451
|
+
problems.push(`${at}.key "${key}" is used by an earlier column.`);
|
|
452
|
+
} else {
|
|
453
|
+
keys.add(key);
|
|
454
|
+
}
|
|
455
|
+
if (typeof fields["label"] !== "string") {
|
|
456
|
+
problems.push(
|
|
457
|
+
`${at}.label must be a string, got ${describeType(fields["label"])}.`
|
|
458
|
+
);
|
|
459
|
+
}
|
|
460
|
+
for (const flag of ["numeric", "sortable", "filterable"]) {
|
|
461
|
+
const flagValue = fields[flag];
|
|
462
|
+
if (flagValue !== void 0 && typeof flagValue !== "boolean") {
|
|
463
|
+
problems.push(
|
|
464
|
+
`${at}.${flag} must be a boolean, got ${describeType(flagValue)}.`
|
|
465
|
+
);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
if (!Array.isArray(rows)) {
|
|
471
|
+
problems.push(`rows must be an array, got ${describeType(rows)}.`);
|
|
472
|
+
} else {
|
|
473
|
+
rows.forEach((row, rowIndex) => {
|
|
474
|
+
if (!Array.isArray(row)) {
|
|
475
|
+
problems.push(
|
|
476
|
+
`rows[${rowIndex}] must be an array of cells, got ${describeType(row)}.`
|
|
477
|
+
);
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
if (columnCount > 0 && row.length !== columnCount) {
|
|
481
|
+
problems.push(
|
|
482
|
+
`rows[${rowIndex}] has ${row.length} cells but there are ${columnCount} columns.`
|
|
483
|
+
);
|
|
484
|
+
}
|
|
485
|
+
row.forEach((cell, cellIndex) => {
|
|
486
|
+
const at = `rows[${rowIndex}][${cellIndex}]`;
|
|
487
|
+
if (typeof cell !== "object" || cell === null) {
|
|
488
|
+
problems.push(`${at} must be an object, got ${describeType(cell)}.`);
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
const fields = cell;
|
|
492
|
+
if (typeof fields["text"] !== "string") {
|
|
493
|
+
problems.push(
|
|
494
|
+
`${at}.text must be a string, got ${describeType(fields["text"])}.`
|
|
495
|
+
);
|
|
496
|
+
}
|
|
497
|
+
const value = fields["value"];
|
|
498
|
+
if (value !== void 0 && typeof value !== "string" && !(typeof value === "number" && Number.isFinite(value))) {
|
|
499
|
+
problems.push(
|
|
500
|
+
`${at}.value must be a string or a finite number, got ${describeType(value)}.`
|
|
501
|
+
);
|
|
502
|
+
}
|
|
503
|
+
const href = fields["href"];
|
|
504
|
+
if (href !== void 0) {
|
|
505
|
+
if (typeof href !== "string") {
|
|
506
|
+
problems.push(
|
|
507
|
+
`${at}.href must be a string, got ${describeType(href)}.`
|
|
508
|
+
);
|
|
509
|
+
} else if (!isSafeHref(href)) {
|
|
510
|
+
problems.push(
|
|
511
|
+
`${at}.href "${href}" is not allowed (only http, https, mailto and relative URLs).`
|
|
512
|
+
);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
});
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
const totalRows = record["totalRows"];
|
|
519
|
+
if (totalRows !== void 0 && !(typeof totalRows === "number" && Number.isInteger(totalRows) && totalRows >= 0)) {
|
|
520
|
+
problems.push(
|
|
521
|
+
`totalRows must be a non-negative whole number, got ${describeType(totalRows)}.`
|
|
522
|
+
);
|
|
523
|
+
}
|
|
524
|
+
if (problems.length > 0) {
|
|
525
|
+
return err(`${subject}: ${problems.join(" ")}`);
|
|
526
|
+
}
|
|
527
|
+
return ok(data);
|
|
528
|
+
}
|
|
529
|
+
function deriveDetailData(data, locale) {
|
|
530
|
+
if (data.kind === "TABLE") {
|
|
531
|
+
if (data.footer !== void 0) return void 0;
|
|
532
|
+
return {
|
|
533
|
+
columns: data.columns.map((column, index) => ({
|
|
534
|
+
key: `c${index}`,
|
|
535
|
+
label: column.label,
|
|
536
|
+
...column.numeric === void 0 ? {} : { numeric: column.numeric }
|
|
537
|
+
})),
|
|
538
|
+
rows: data.rows
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
if (data.kind === "BAR_LIST") {
|
|
542
|
+
return {
|
|
543
|
+
columns: [
|
|
544
|
+
{ key: "label", label: "Name" },
|
|
545
|
+
{ key: "value", label: "Value", numeric: true }
|
|
546
|
+
],
|
|
547
|
+
rows: data.items.map((item) => [
|
|
548
|
+
{ text: item.label },
|
|
549
|
+
{
|
|
550
|
+
text: item.display ?? formatValue(item.value, "number", { locale }),
|
|
551
|
+
value: item.value
|
|
552
|
+
}
|
|
553
|
+
])
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
return void 0;
|
|
557
|
+
}
|
|
558
|
+
|
|
195
559
|
// src/core/grid.ts
|
|
560
|
+
var WIDTH_COLUMNS = 12;
|
|
561
|
+
var MIN_WIDGET_WIDTH = 2;
|
|
562
|
+
var MAX_WIDGET_WIDTH = 12;
|
|
563
|
+
function isWidgetWidth(value) {
|
|
564
|
+
return typeof value === "number" && Number.isInteger(value) && value >= MIN_WIDGET_WIDTH && value <= MAX_WIDGET_WIDTH;
|
|
565
|
+
}
|
|
566
|
+
function widthForSize(size) {
|
|
567
|
+
switch (size) {
|
|
568
|
+
case "small":
|
|
569
|
+
return 3;
|
|
570
|
+
case "large":
|
|
571
|
+
return 6;
|
|
572
|
+
case "full":
|
|
573
|
+
return 12;
|
|
574
|
+
default:
|
|
575
|
+
return 4;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
function itemWidth(item) {
|
|
579
|
+
return isWidgetWidth(item.width) ? item.width : widthForSize(item.defaultSize);
|
|
580
|
+
}
|
|
581
|
+
function usesWidthColumns(items) {
|
|
582
|
+
return items.some((item) => item.width !== void 0);
|
|
583
|
+
}
|
|
196
584
|
function fillsWidth(fill) {
|
|
197
585
|
return fill === "width" || fill === "both";
|
|
198
586
|
}
|
|
@@ -205,6 +593,16 @@ function baseColumnSpan(size, columns, largeSpan = 2) {
|
|
|
205
593
|
return 1;
|
|
206
594
|
}
|
|
207
595
|
function fillColumnSpans(items, columns, largeSpan = 2) {
|
|
596
|
+
return placeAndFill(
|
|
597
|
+
items,
|
|
598
|
+
columns,
|
|
599
|
+
(item, trackCount) => baseColumnSpan(item.defaultSize, trackCount, largeSpan)
|
|
600
|
+
);
|
|
601
|
+
}
|
|
602
|
+
function fillWidthSpans(items) {
|
|
603
|
+
return placeAndFill(items, WIDTH_COLUMNS, itemWidth);
|
|
604
|
+
}
|
|
605
|
+
function placeAndFill(items, columns, spanOf) {
|
|
208
606
|
const trackCount = Math.max(1, Math.floor(columns));
|
|
209
607
|
const spans = /* @__PURE__ */ new Map();
|
|
210
608
|
let row = [];
|
|
@@ -223,11 +621,7 @@ function fillColumnSpans(items, columns, largeSpan = 2) {
|
|
|
223
621
|
used = 0;
|
|
224
622
|
}
|
|
225
623
|
for (const item of items) {
|
|
226
|
-
const span =
|
|
227
|
-
item.defaultSize,
|
|
228
|
-
trackCount,
|
|
229
|
-
largeSpan
|
|
230
|
-
);
|
|
624
|
+
const span = Math.min(spanOf(item, trackCount), trackCount);
|
|
231
625
|
if (used + span > trackCount && row.length > 0) closeRow();
|
|
232
626
|
row.push({ item, span });
|
|
233
627
|
used += span;
|
|
@@ -378,55 +772,9 @@ function pruneLayout(definitions, layout) {
|
|
|
378
772
|
return next.order.length === layout.order.length && next.hidden.length === layout.hidden.length && next.minimized.length === layout.minimized.length ? layout : next;
|
|
379
773
|
}
|
|
380
774
|
|
|
381
|
-
// src/core/result.ts
|
|
382
|
-
function ok(value) {
|
|
383
|
-
return { ok: true, value };
|
|
384
|
-
}
|
|
385
|
-
function err(error) {
|
|
386
|
-
return { ok: false, error };
|
|
387
|
-
}
|
|
388
|
-
function describeUnknownError(cause) {
|
|
389
|
-
if (cause instanceof Error) {
|
|
390
|
-
return cause.message === "" ? cause.name : cause.message;
|
|
391
|
-
}
|
|
392
|
-
if (typeof cause === "string") {
|
|
393
|
-
return cause;
|
|
394
|
-
}
|
|
395
|
-
try {
|
|
396
|
-
const json = JSON.stringify(cause);
|
|
397
|
-
return json ?? String(cause);
|
|
398
|
-
} catch {
|
|
399
|
-
return String(cause);
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
// src/core/url.ts
|
|
404
|
-
var SCHEME_PATTERN = /^([a-z][a-z0-9+.-]*):/i;
|
|
405
|
-
var IGNORED_IN_SCHEME = /[\u0000- \u007f]/g;
|
|
406
|
-
function schemeOf(url) {
|
|
407
|
-
const match = SCHEME_PATTERN.exec(
|
|
408
|
-
url.replace(IGNORED_IN_SCHEME, "")
|
|
409
|
-
);
|
|
410
|
-
return match === null ? null : (match[1] ?? "").toLowerCase();
|
|
411
|
-
}
|
|
412
|
-
function isSafeHref(url) {
|
|
413
|
-
if (url.trim() === "") {
|
|
414
|
-
return false;
|
|
415
|
-
}
|
|
416
|
-
const scheme = schemeOf(url);
|
|
417
|
-
return scheme === null || scheme === "http" || scheme === "https" || scheme === "mailto";
|
|
418
|
-
}
|
|
419
|
-
function isSafeImageUrl(url) {
|
|
420
|
-
if (url.trim() === "") {
|
|
421
|
-
return false;
|
|
422
|
-
}
|
|
423
|
-
const scheme = schemeOf(url);
|
|
424
|
-
return scheme === null || scheme === "http" || scheme === "https";
|
|
425
|
-
}
|
|
426
|
-
|
|
427
775
|
// src/core/validate.ts
|
|
428
776
|
var MAX_REPORTED_PROBLEMS = 10;
|
|
429
|
-
function
|
|
777
|
+
function describeType2(value) {
|
|
430
778
|
if (value === null) return "null";
|
|
431
779
|
if (Array.isArray(value)) return "array";
|
|
432
780
|
if (typeof value === "number" && !Number.isFinite(value)) {
|
|
@@ -444,7 +792,7 @@ function requireString(record, field, path, problems) {
|
|
|
444
792
|
const value = record[field];
|
|
445
793
|
if (typeof value !== "string") {
|
|
446
794
|
problems.push(
|
|
447
|
-
`${join(path, field)} must be a string, got ${
|
|
795
|
+
`${join(path, field)} must be a string, got ${describeType2(value)}.`
|
|
448
796
|
);
|
|
449
797
|
}
|
|
450
798
|
}
|
|
@@ -457,7 +805,7 @@ function requireNumber(record, field, path, problems) {
|
|
|
457
805
|
const value = record[field];
|
|
458
806
|
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
459
807
|
problems.push(
|
|
460
|
-
`${join(path, field)} must be a finite number, got ${
|
|
808
|
+
`${join(path, field)} must be a finite number, got ${describeType2(value)}.`
|
|
461
809
|
);
|
|
462
810
|
}
|
|
463
811
|
}
|
|
@@ -470,7 +818,7 @@ function optionalBoolean(record, field, path, problems) {
|
|
|
470
818
|
const value = record[field];
|
|
471
819
|
if (value !== void 0 && typeof value !== "boolean") {
|
|
472
820
|
problems.push(
|
|
473
|
-
`${join(path, field)} must be a boolean, got ${
|
|
821
|
+
`${join(path, field)} must be a boolean, got ${describeType2(value)}.`
|
|
474
822
|
);
|
|
475
823
|
}
|
|
476
824
|
}
|
|
@@ -479,7 +827,7 @@ function optionalUrl(record, field, path, problems, isSafe, allowed) {
|
|
|
479
827
|
if (value === void 0) return;
|
|
480
828
|
if (typeof value !== "string") {
|
|
481
829
|
problems.push(
|
|
482
|
-
`${join(path, field)} must be a string, got ${
|
|
830
|
+
`${join(path, field)} must be a string, got ${describeType2(value)}.`
|
|
483
831
|
);
|
|
484
832
|
} else if (!isSafe(value)) {
|
|
485
833
|
problems.push(
|
|
@@ -491,7 +839,7 @@ function requireArray(record, field, path, problems) {
|
|
|
491
839
|
const value = record[field];
|
|
492
840
|
if (!Array.isArray(value)) {
|
|
493
841
|
problems.push(
|
|
494
|
-
`${join(path, field)} must be an array, got ${
|
|
842
|
+
`${join(path, field)} must be an array, got ${describeType2(value)}.`
|
|
495
843
|
);
|
|
496
844
|
return null;
|
|
497
845
|
}
|
|
@@ -501,7 +849,7 @@ function requireOneOf(record, field, options, path, problems) {
|
|
|
501
849
|
const value = record[field];
|
|
502
850
|
if (typeof value !== "string" || !options.includes(value)) {
|
|
503
851
|
problems.push(
|
|
504
|
-
`${join(path, field)} must be one of ${options.map((o) => `"${o}"`).join(", ")}, got ${typeof value === "string" ? JSON.stringify(value) :
|
|
852
|
+
`${join(path, field)} must be one of ${options.map((o) => `"${o}"`).join(", ")}, got ${typeof value === "string" ? JSON.stringify(value) : describeType2(value)}.`
|
|
505
853
|
);
|
|
506
854
|
}
|
|
507
855
|
}
|
|
@@ -512,7 +860,7 @@ function eachRecord(items, path, problems, check) {
|
|
|
512
860
|
check(item, itemPath);
|
|
513
861
|
} else {
|
|
514
862
|
problems.push(
|
|
515
|
-
`${itemPath} must be an object, got ${
|
|
863
|
+
`${itemPath} must be an object, got ${describeType2(item)}.`
|
|
516
864
|
);
|
|
517
865
|
}
|
|
518
866
|
});
|
|
@@ -558,7 +906,7 @@ function checkPayloadFields(kind, data, problems) {
|
|
|
558
906
|
const rowPath = `rows[${rowIndex}]`;
|
|
559
907
|
if (!Array.isArray(row)) {
|
|
560
908
|
problems.push(
|
|
561
|
-
`${rowPath} must be an array of cells, got ${
|
|
909
|
+
`${rowPath} must be an array of cells, got ${describeType2(row)}.`
|
|
562
910
|
);
|
|
563
911
|
return;
|
|
564
912
|
}
|
|
@@ -654,6 +1002,25 @@ function checkPayloadFields(kind, data, problems) {
|
|
|
654
1002
|
}
|
|
655
1003
|
}
|
|
656
1004
|
}
|
|
1005
|
+
function checkDetailOption(detail, problems) {
|
|
1006
|
+
if (detail === void 0 || typeof detail === "boolean") return;
|
|
1007
|
+
if (!isRecord(detail)) {
|
|
1008
|
+
problems.push(
|
|
1009
|
+
`detail must be true, false or an options object, got ${describeType2(detail)}.`
|
|
1010
|
+
);
|
|
1011
|
+
return;
|
|
1012
|
+
}
|
|
1013
|
+
optionalString(detail, "title", "detail", problems);
|
|
1014
|
+
const pageSize = detail["pageSize"];
|
|
1015
|
+
if (pageSize !== void 0 && !(typeof pageSize === "number" && Number.isInteger(pageSize) && pageSize >= 1 && pageSize <= MAX_DETAIL_PAGE_SIZE)) {
|
|
1016
|
+
problems.push(
|
|
1017
|
+
`detail.pageSize must be a whole number from 1 to ${MAX_DETAIL_PAGE_SIZE}, got ${typeof pageSize === "number" ? String(pageSize) : describeType2(pageSize)}.`
|
|
1018
|
+
);
|
|
1019
|
+
}
|
|
1020
|
+
if (detail["mode"] !== void 0) {
|
|
1021
|
+
requireOneOf(detail, "mode", DETAIL_MODES, "detail", problems);
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
657
1024
|
function formatProblems(prefix, problems) {
|
|
658
1025
|
const shown = problems.slice(0, MAX_REPORTED_PROBLEMS);
|
|
659
1026
|
const more = problems.length - shown.length;
|
|
@@ -662,12 +1029,12 @@ function formatProblems(prefix, problems) {
|
|
|
662
1029
|
function validateWidgetData(value, options = {}) {
|
|
663
1030
|
const subject = options.widgetKey === void 0 ? "Widget data" : `Widget ${JSON.stringify(options.widgetKey)}`;
|
|
664
1031
|
if (!isRecord(value)) {
|
|
665
|
-
return err(`${subject}: must be an object, got ${
|
|
1032
|
+
return err(`${subject}: must be an object, got ${describeType2(value)}.`);
|
|
666
1033
|
}
|
|
667
1034
|
if (value["empty"] === true) {
|
|
668
1035
|
if (typeof value["text"] !== "string") {
|
|
669
1036
|
return err(
|
|
670
|
-
`${subject} (empty): text must be a string, got ${
|
|
1037
|
+
`${subject} (empty): text must be a string, got ${describeType2(value["text"])}.`
|
|
671
1038
|
);
|
|
672
1039
|
}
|
|
673
1040
|
return ok(value);
|
|
@@ -675,7 +1042,7 @@ function validateWidgetData(value, options = {}) {
|
|
|
675
1042
|
const kind = value["kind"];
|
|
676
1043
|
if (!isWidgetKind(kind)) {
|
|
677
1044
|
return err(
|
|
678
|
-
`${subject}: kind must be one of ${WIDGET_KINDS.join(", ")} (or the payload must be {"empty": true, "text": ...}), got ${typeof kind === "string" ? JSON.stringify(kind) :
|
|
1045
|
+
`${subject}: kind must be one of ${WIDGET_KINDS.join(", ")} (or the payload must be {"empty": true, "text": ...}), got ${typeof kind === "string" ? JSON.stringify(kind) : describeType2(kind)}.`
|
|
679
1046
|
);
|
|
680
1047
|
}
|
|
681
1048
|
if (options.expectedKind !== void 0 && kind !== options.expectedKind) {
|
|
@@ -693,7 +1060,7 @@ function validateWidgetData(value, options = {}) {
|
|
|
693
1060
|
function validateWidgetDefinition(value) {
|
|
694
1061
|
if (!isRecord(value)) {
|
|
695
1062
|
return err(
|
|
696
|
-
`Widget definition: must be an object, got ${
|
|
1063
|
+
`Widget definition: must be an object, got ${describeType2(value)}.`
|
|
697
1064
|
);
|
|
698
1065
|
}
|
|
699
1066
|
const subject = typeof value["key"] === "string" ? `Widget definition ${JSON.stringify(value["key"])}` : "Widget definition";
|
|
@@ -711,7 +1078,7 @@ function validateWidgetDefinition(value) {
|
|
|
711
1078
|
roles?.forEach((role, index) => {
|
|
712
1079
|
if (typeof role !== "string") {
|
|
713
1080
|
problems.push(
|
|
714
|
-
`roles[${index}] must be a string, got ${
|
|
1081
|
+
`roles[${index}] must be a string, got ${describeType2(role)}.`
|
|
715
1082
|
);
|
|
716
1083
|
}
|
|
717
1084
|
});
|
|
@@ -720,6 +1087,12 @@ function validateWidgetDefinition(value) {
|
|
|
720
1087
|
if (value["defaultSize"] !== void 0) {
|
|
721
1088
|
requireOneOf(value, "defaultSize", WIDGET_SIZES, "", problems);
|
|
722
1089
|
}
|
|
1090
|
+
if (value["width"] !== void 0 && !isWidgetWidth(value["width"])) {
|
|
1091
|
+
problems.push(
|
|
1092
|
+
`width must be an integer from ${MIN_WIDGET_WIDTH} to ${MAX_WIDGET_WIDTH} (twelfths of the row), got ${typeof value["width"] === "number" ? String(value["width"]) : describeType2(value["width"])}.`
|
|
1093
|
+
);
|
|
1094
|
+
}
|
|
1095
|
+
checkDetailOption(value["detail"], problems);
|
|
723
1096
|
if (value["fill"] !== void 0) {
|
|
724
1097
|
requireOneOf(value, "fill", WIDGET_FILLS, "", problems);
|
|
725
1098
|
}
|
|
@@ -756,23 +1129,78 @@ function failedWidget(definition, error) {
|
|
|
756
1129
|
function loadingWidgets(definitions) {
|
|
757
1130
|
return definitions.map((definition) => ({ definition, status: "loading" }));
|
|
758
1131
|
}
|
|
1132
|
+
function cacheKeyFor(definition, options) {
|
|
1133
|
+
return options.cacheKey === void 0 ? definition.key : options.cacheKey(definition);
|
|
1134
|
+
}
|
|
1135
|
+
var LoadInterruption = class extends Error {
|
|
1136
|
+
};
|
|
759
1137
|
async function resolveWidget(definition, provider, context, options = {}) {
|
|
1138
|
+
const quotedKey = JSON.stringify(definition.key);
|
|
760
1139
|
if (provider === void 0) {
|
|
761
1140
|
return failedWidget(
|
|
762
1141
|
definition,
|
|
763
|
-
`Widget ${
|
|
1142
|
+
`Widget ${quotedKey}: no provider is registered for this key.`
|
|
1143
|
+
);
|
|
1144
|
+
}
|
|
1145
|
+
if (options.signal?.aborted === true) {
|
|
1146
|
+
return failedWidget(
|
|
1147
|
+
definition,
|
|
1148
|
+
`Widget ${quotedKey}: loading was canceled before it started.`
|
|
764
1149
|
);
|
|
765
1150
|
}
|
|
1151
|
+
const controller = new AbortController();
|
|
1152
|
+
const onExternalAbort = () => controller.abort(options.signal?.reason);
|
|
1153
|
+
options.signal?.addEventListener("abort", onExternalAbort, { once: true });
|
|
1154
|
+
let timedOut = false;
|
|
1155
|
+
const timeoutMs = options.timeoutMs !== void 0 && options.timeoutMs > 0 ? options.timeoutMs : void 0;
|
|
1156
|
+
const timer = timeoutMs === void 0 ? void 0 : setTimeout(() => {
|
|
1157
|
+
timedOut = true;
|
|
1158
|
+
controller.abort(new Error(`Timed out after ${timeoutMs} ms.`));
|
|
1159
|
+
}, timeoutMs);
|
|
1160
|
+
const interrupted = new Promise((_resolve, reject) => {
|
|
1161
|
+
controller.signal.addEventListener(
|
|
1162
|
+
"abort",
|
|
1163
|
+
() => reject(new LoadInterruption()),
|
|
1164
|
+
{ once: true }
|
|
1165
|
+
);
|
|
1166
|
+
});
|
|
766
1167
|
let payload;
|
|
767
1168
|
try {
|
|
768
|
-
payload = await
|
|
1169
|
+
payload = await Promise.race([
|
|
1170
|
+
Promise.resolve().then(() => {
|
|
1171
|
+
if (controller.signal.aborted) throw new LoadInterruption();
|
|
1172
|
+
return provider(context, definition, { signal: controller.signal });
|
|
1173
|
+
}),
|
|
1174
|
+
interrupted
|
|
1175
|
+
]);
|
|
769
1176
|
} catch (cause) {
|
|
1177
|
+
if (cause instanceof LoadInterruption) {
|
|
1178
|
+
return failedWidget(
|
|
1179
|
+
definition,
|
|
1180
|
+
timedOut ? `Widget ${quotedKey}: provider timed out after ${timeoutMs} ms.` : `Widget ${quotedKey}: loading was canceled.`
|
|
1181
|
+
);
|
|
1182
|
+
}
|
|
770
1183
|
return failedWidget(
|
|
771
1184
|
definition,
|
|
772
|
-
`Widget ${
|
|
1185
|
+
`Widget ${quotedKey}: provider failed: ${describeUnknownError(cause)}`
|
|
773
1186
|
);
|
|
1187
|
+
} finally {
|
|
1188
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
1189
|
+
options.signal?.removeEventListener("abort", onExternalAbort);
|
|
1190
|
+
}
|
|
1191
|
+
const resolved = resolvePayload(definition, payload, options);
|
|
1192
|
+
if (resolved.status !== "ok") return resolved;
|
|
1193
|
+
const storedAt = Date.now();
|
|
1194
|
+
if (options.cache !== void 0) {
|
|
1195
|
+
try {
|
|
1196
|
+
await options.cache.set(cacheKeyFor(definition, options), {
|
|
1197
|
+
payload: resolved.data,
|
|
1198
|
+
storedAt
|
|
1199
|
+
});
|
|
1200
|
+
} catch {
|
|
1201
|
+
}
|
|
774
1202
|
}
|
|
775
|
-
return
|
|
1203
|
+
return { ...resolved, updatedAt: storedAt };
|
|
776
1204
|
}
|
|
777
1205
|
function widgetsFor(definitions, roles) {
|
|
778
1206
|
return sortDefinitions(
|
|
@@ -793,6 +1221,131 @@ async function resolveWidgets(definitions, providers, context, options = {}) {
|
|
|
793
1221
|
);
|
|
794
1222
|
}
|
|
795
1223
|
|
|
1224
|
+
// src/core/loader.ts
|
|
1225
|
+
function createWidgetLoader(options) {
|
|
1226
|
+
const { definitions, providers, context, ...resolveOptions } = options;
|
|
1227
|
+
const visible = widgetsFor(definitions, context.roles);
|
|
1228
|
+
let snapshot = loadingWidgets(visible);
|
|
1229
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
1230
|
+
const started = /* @__PURE__ */ new Set();
|
|
1231
|
+
const generations = /* @__PURE__ */ new Map();
|
|
1232
|
+
const inFlight = /* @__PURE__ */ new Map();
|
|
1233
|
+
let disposed = false;
|
|
1234
|
+
function publish(next) {
|
|
1235
|
+
snapshot = next;
|
|
1236
|
+
for (const listener of [...listeners]) {
|
|
1237
|
+
try {
|
|
1238
|
+
listener();
|
|
1239
|
+
} catch {
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
function replace(key, widget) {
|
|
1244
|
+
publish(
|
|
1245
|
+
snapshot.map(
|
|
1246
|
+
(current) => current.definition.key === key ? widget : current
|
|
1247
|
+
)
|
|
1248
|
+
);
|
|
1249
|
+
}
|
|
1250
|
+
function abortAll(reason) {
|
|
1251
|
+
for (const controller of inFlight.values()) controller.abort(reason);
|
|
1252
|
+
inFlight.clear();
|
|
1253
|
+
}
|
|
1254
|
+
resolveOptions.signal?.addEventListener(
|
|
1255
|
+
"abort",
|
|
1256
|
+
() => abortAll(resolveOptions.signal?.reason),
|
|
1257
|
+
{ once: true }
|
|
1258
|
+
);
|
|
1259
|
+
async function run(definition, readCache) {
|
|
1260
|
+
const key = definition.key;
|
|
1261
|
+
const generation = (generations.get(key) ?? 0) + 1;
|
|
1262
|
+
generations.set(key, generation);
|
|
1263
|
+
inFlight.get(key)?.abort(new Error("Superseded by a newer load."));
|
|
1264
|
+
const controller = new AbortController();
|
|
1265
|
+
inFlight.set(key, controller);
|
|
1266
|
+
const isCurrent = () => !disposed && generations.get(key) === generation;
|
|
1267
|
+
if (readCache && resolveOptions.cache !== void 0) {
|
|
1268
|
+
try {
|
|
1269
|
+
const entry = await resolveOptions.cache.get(
|
|
1270
|
+
cacheKeyFor(definition, resolveOptions)
|
|
1271
|
+
);
|
|
1272
|
+
if (entry !== void 0 && isCurrent()) {
|
|
1273
|
+
const cached = resolvePayload(
|
|
1274
|
+
definition,
|
|
1275
|
+
entry.payload,
|
|
1276
|
+
resolveOptions
|
|
1277
|
+
);
|
|
1278
|
+
if (cached.status === "ok") {
|
|
1279
|
+
replace(key, { ...cached, updatedAt: entry.storedAt, stale: true });
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
} catch {
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
if (!isCurrent()) return;
|
|
1286
|
+
const provider = Object.prototype.hasOwnProperty.call(providers, key) ? providers[key] : void 0;
|
|
1287
|
+
const result = await resolveWidget(definition, provider, context, {
|
|
1288
|
+
...resolveOptions,
|
|
1289
|
+
signal: controller.signal
|
|
1290
|
+
});
|
|
1291
|
+
if (!isCurrent()) return;
|
|
1292
|
+
inFlight.delete(key);
|
|
1293
|
+
replace(key, result);
|
|
1294
|
+
}
|
|
1295
|
+
function start(definition, readCache) {
|
|
1296
|
+
started.add(definition.key);
|
|
1297
|
+
void run(definition, readCache);
|
|
1298
|
+
}
|
|
1299
|
+
function definitionFor(key) {
|
|
1300
|
+
return visible.find((definition) => definition.key === key);
|
|
1301
|
+
}
|
|
1302
|
+
function load(key) {
|
|
1303
|
+
if (disposed || started.has(key)) return;
|
|
1304
|
+
const definition = definitionFor(key);
|
|
1305
|
+
if (definition !== void 0) start(definition, true);
|
|
1306
|
+
}
|
|
1307
|
+
function loadAll() {
|
|
1308
|
+
for (const definition of visible) load(definition.key);
|
|
1309
|
+
}
|
|
1310
|
+
function refresh(key, refreshOptions) {
|
|
1311
|
+
if (disposed) return;
|
|
1312
|
+
const keys = key === void 0 ? [...started] : [key];
|
|
1313
|
+
for (const target of keys) {
|
|
1314
|
+
const definition = definitionFor(target);
|
|
1315
|
+
if (definition === void 0) continue;
|
|
1316
|
+
if (refreshOptions?.skipInFlight === true && inFlight.has(target)) {
|
|
1317
|
+
continue;
|
|
1318
|
+
}
|
|
1319
|
+
const current = snapshot.find(
|
|
1320
|
+
(widget) => widget.definition.key === target
|
|
1321
|
+
);
|
|
1322
|
+
if (current?.status === "error") {
|
|
1323
|
+
replace(target, { definition, status: "loading" });
|
|
1324
|
+
}
|
|
1325
|
+
start(definition, false);
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
function dispose() {
|
|
1329
|
+
disposed = true;
|
|
1330
|
+
abortAll(new Error("The widget loader was disposed."));
|
|
1331
|
+
listeners.clear();
|
|
1332
|
+
}
|
|
1333
|
+
function subscribe(listener) {
|
|
1334
|
+
listeners.add(listener);
|
|
1335
|
+
return () => {
|
|
1336
|
+
listeners.delete(listener);
|
|
1337
|
+
};
|
|
1338
|
+
}
|
|
1339
|
+
return {
|
|
1340
|
+
getSnapshot: () => snapshot,
|
|
1341
|
+
subscribe,
|
|
1342
|
+
load,
|
|
1343
|
+
loadAll,
|
|
1344
|
+
refresh,
|
|
1345
|
+
dispose
|
|
1346
|
+
};
|
|
1347
|
+
}
|
|
1348
|
+
|
|
796
1349
|
// src/core/scale.ts
|
|
797
1350
|
function niceStep(value) {
|
|
798
1351
|
if (!(value > 0) || !Number.isFinite(value)) return 1;
|
|
@@ -825,22 +1378,33 @@ function labelStride(count, maxLabels = 6) {
|
|
|
825
1378
|
|
|
826
1379
|
exports.DEFAULT_COMPARISON_LABEL = DEFAULT_COMPARISON_LABEL;
|
|
827
1380
|
exports.DEFAULT_CURRENCY = DEFAULT_CURRENCY;
|
|
1381
|
+
exports.DEFAULT_DETAIL_PAGE_SIZE = DEFAULT_DETAIL_PAGE_SIZE;
|
|
828
1382
|
exports.DEFAULT_EMPTY_TEXT = DEFAULT_EMPTY_TEXT;
|
|
1383
|
+
exports.DETAIL_MODES = DETAIL_MODES;
|
|
829
1384
|
exports.EMPTY_LAYOUT = EMPTY_LAYOUT;
|
|
1385
|
+
exports.MAX_DETAIL_PAGE_SIZE = MAX_DETAIL_PAGE_SIZE;
|
|
830
1386
|
exports.MAX_GRAPH_SERIES = MAX_GRAPH_SERIES;
|
|
831
1387
|
exports.MAX_REPORTED_PROBLEMS = MAX_REPORTED_PROBLEMS;
|
|
1388
|
+
exports.MAX_WIDGET_WIDTH = MAX_WIDGET_WIDTH;
|
|
1389
|
+
exports.MIN_WIDGET_WIDTH = MIN_WIDGET_WIDTH;
|
|
832
1390
|
exports.VALUE_FORMATS = VALUE_FORMATS;
|
|
833
1391
|
exports.WIDGET_FILLS = WIDGET_FILLS;
|
|
834
1392
|
exports.WIDGET_KINDS = WIDGET_KINDS;
|
|
835
1393
|
exports.WIDGET_SIZES = WIDGET_SIZES;
|
|
1394
|
+
exports.WIDTH_COLUMNS = WIDTH_COLUMNS;
|
|
836
1395
|
exports.baseColumnSpan = baseColumnSpan;
|
|
1396
|
+
exports.cacheKeyFor = cacheKeyFor;
|
|
1397
|
+
exports.createWidgetLoader = createWidgetLoader;
|
|
1398
|
+
exports.defaultDetailQuery = defaultDetailQuery;
|
|
837
1399
|
exports.defineWidget = defineWidget;
|
|
1400
|
+
exports.deriveDetailData = deriveDetailData;
|
|
838
1401
|
exports.describeUnknownError = describeUnknownError;
|
|
839
1402
|
exports.emptyTextFor = emptyTextFor;
|
|
840
1403
|
exports.emptyWidget = emptyWidget;
|
|
841
1404
|
exports.err = err;
|
|
842
1405
|
exports.failedWidget = failedWidget;
|
|
843
1406
|
exports.fillColumnSpans = fillColumnSpans;
|
|
1407
|
+
exports.fillWidthSpans = fillWidthSpans;
|
|
844
1408
|
exports.fillsHeight = fillsHeight;
|
|
845
1409
|
exports.fillsWidth = fillsWidth;
|
|
846
1410
|
exports.formatCount = formatCount;
|
|
@@ -856,6 +1420,8 @@ exports.isSafeImageUrl = isSafeImageUrl;
|
|
|
856
1420
|
exports.isWidgetEmptyState = isWidgetEmptyState;
|
|
857
1421
|
exports.isWidgetKind = isWidgetKind;
|
|
858
1422
|
exports.isWidgetVisibleTo = isWidgetVisibleTo;
|
|
1423
|
+
exports.isWidgetWidth = isWidgetWidth;
|
|
1424
|
+
exports.itemWidth = itemWidth;
|
|
859
1425
|
exports.kpiDelta = kpiDelta;
|
|
860
1426
|
exports.labelStride = labelStride;
|
|
861
1427
|
exports.loadingWidgets = loadingWidgets;
|
|
@@ -867,13 +1433,17 @@ exports.moveWidgetUp = moveWidgetUp;
|
|
|
867
1433
|
exports.niceDomain = niceDomain;
|
|
868
1434
|
exports.niceStep = niceStep;
|
|
869
1435
|
exports.ok = ok;
|
|
1436
|
+
exports.parseDetailQuery = parseDetailQuery;
|
|
870
1437
|
exports.parseLayout = parseLayout;
|
|
871
1438
|
exports.percentChange = percentChange;
|
|
872
1439
|
exports.pruneLayout = pruneLayout;
|
|
1440
|
+
exports.queryRows = queryRows;
|
|
1441
|
+
exports.resolveDetailOptions = resolveDetailOptions;
|
|
873
1442
|
exports.resolvePayload = resolvePayload;
|
|
874
1443
|
exports.resolveWidget = resolveWidget;
|
|
875
1444
|
exports.resolveWidgets = resolveWidgets;
|
|
876
1445
|
exports.restoreWidget = restoreWidget;
|
|
1446
|
+
exports.serializeDetailQuery = serializeDetailQuery;
|
|
877
1447
|
exports.serializeLayout = serializeLayout;
|
|
878
1448
|
exports.shareOf = shareOf;
|
|
879
1449
|
exports.showWidget = showWidget;
|
|
@@ -881,9 +1451,12 @@ exports.sortDefinitions = sortDefinitions;
|
|
|
881
1451
|
exports.toggleHidden = toggleHidden;
|
|
882
1452
|
exports.toggleMinimized = toggleMinimized;
|
|
883
1453
|
exports.upgradeLegacyWidgetData = upgradeLegacyWidgetData;
|
|
1454
|
+
exports.usesWidthColumns = usesWidthColumns;
|
|
1455
|
+
exports.validateDetailData = validateDetailData;
|
|
884
1456
|
exports.validateWidgetData = validateWidgetData;
|
|
885
1457
|
exports.validateWidgetDefinition = validateWidgetDefinition;
|
|
886
1458
|
exports.visibleWidgets = visibleWidgets;
|
|
887
1459
|
exports.widgetsFor = widgetsFor;
|
|
1460
|
+
exports.widthForSize = widthForSize;
|
|
888
1461
|
//# sourceMappingURL=index.cjs.map
|
|
889
1462
|
//# sourceMappingURL=index.cjs.map
|