@richardmcquiston01/dashboard-widgets-toolkit 0.9.0 → 0.10.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 +605 -14
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +134 -3
- package/dist/core.d.ts +134 -3
- package/dist/core.js +583 -15
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +605 -14
- 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 +583 -15
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +1014 -164
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +39 -2
- package/dist/react.d.ts +39 -2
- package/dist/react.js +1014 -164
- package/dist/react.js.map +1 -1
- package/dist/{scale-CrXxawQn.d.cts → scale-N69bo7wo.d.cts} +36 -1
- package/dist/{scale-CrXxawQn.d.ts → scale-N69bo7wo.d.ts} +36 -1
- package/dist/styles.css +138 -0
- package/package.json +1 -1
package/dist/react.js
CHANGED
|
@@ -427,21 +427,36 @@ function fillColumnSpans(items, columns, largeSpan = 2) {
|
|
|
427
427
|
function fillWidthSpans(items) {
|
|
428
428
|
return placeAndFill(items, WIDTH_COLUMNS, itemWidth);
|
|
429
429
|
}
|
|
430
|
+
function placeRows(items) {
|
|
431
|
+
return placeAndFillRows(items, WIDTH_COLUMNS, itemWidth).rows;
|
|
432
|
+
}
|
|
430
433
|
function placeAndFill(items, columns, spanOf) {
|
|
434
|
+
return placeAndFillRows(items, columns, spanOf).spans;
|
|
435
|
+
}
|
|
436
|
+
function placeAndFillRows(items, columns, spanOf) {
|
|
431
437
|
const trackCount = Math.max(1, Math.floor(columns));
|
|
432
438
|
const spans = /* @__PURE__ */ new Map();
|
|
439
|
+
const rows = [];
|
|
433
440
|
let row = [];
|
|
434
441
|
let used = 0;
|
|
435
442
|
function closeRow() {
|
|
443
|
+
if (row.length === 0) return;
|
|
436
444
|
const fillers = row.filter(({ item }) => fillsWidth(item.fill));
|
|
437
445
|
const leftover = trackCount - used;
|
|
446
|
+
const finalSpans = /* @__PURE__ */ new Map();
|
|
438
447
|
if (fillers.length > 0) {
|
|
439
448
|
const share = Math.floor(leftover / fillers.length);
|
|
440
449
|
const remainder = leftover % fillers.length;
|
|
441
450
|
fillers.forEach(({ item, span }, index) => {
|
|
442
|
-
|
|
451
|
+
const grown = span + share + (index < remainder ? 1 : 0);
|
|
452
|
+
spans.set(item.key, grown);
|
|
453
|
+
finalSpans.set(item.key, grown);
|
|
443
454
|
});
|
|
444
455
|
}
|
|
456
|
+
rows.push({
|
|
457
|
+
keys: row.map(({ item }) => item.key),
|
|
458
|
+
spans: row.map(({ item, span }) => finalSpans.get(item.key) ?? span)
|
|
459
|
+
});
|
|
445
460
|
row = [];
|
|
446
461
|
used = 0;
|
|
447
462
|
}
|
|
@@ -452,7 +467,7 @@ function placeAndFill(items, columns, spanOf) {
|
|
|
452
467
|
used += span;
|
|
453
468
|
}
|
|
454
469
|
closeRow();
|
|
455
|
-
return spans;
|
|
470
|
+
return { spans, rows };
|
|
456
471
|
}
|
|
457
472
|
|
|
458
473
|
// src/core/scale.ts
|
|
@@ -535,6 +550,27 @@ var DEFAULT_LABELS = {
|
|
|
535
550
|
dashboardControls: "Dashboard controls",
|
|
536
551
|
locked: (title) => `${title} is locked`,
|
|
537
552
|
lockedForViewers: (title) => `${title} is locked for viewers`,
|
|
553
|
+
pageBar: "Pages",
|
|
554
|
+
pageTabName: (index, count, title) => `Page ${index} of ${count}: ${title}`,
|
|
555
|
+
previousPageButton: "Previous page",
|
|
556
|
+
nextPageButton: "Next page",
|
|
557
|
+
managePages: "Manage pages",
|
|
558
|
+
addPage: "Add page",
|
|
559
|
+
renamePage: (title) => `Rename ${title}`,
|
|
560
|
+
pageTitle: "Page title",
|
|
561
|
+
savePageTitle: "Save page title",
|
|
562
|
+
cancelPageTitle: "Cancel renaming",
|
|
563
|
+
deletePage: (title) => `Delete ${title}`,
|
|
564
|
+
confirmDeletePage: (title) => `Delete the page "${title}" and move its widgets to another page?`,
|
|
565
|
+
movePageLeft: (title) => `Move ${title} page left`,
|
|
566
|
+
movePageRight: (title) => `Move ${title} page right`,
|
|
567
|
+
moveToPage: (title) => `Move ${title} to another page`,
|
|
568
|
+
moveToPagePlaceholder: "Move to page\u2026",
|
|
569
|
+
moveToPageOption: (title, rowsFree) => `${title} (${rowsFree} ${rowsFree === 1 ? "row" : "rows"} free)`,
|
|
570
|
+
newPageOption: "New page\u2026",
|
|
571
|
+
movedToPage: (title, pageTitle) => `${title} moved to ${pageTitle}`,
|
|
572
|
+
pageFull: (pageTitle, maxRows) => `Page "${pageTitle}" is full (${maxRows} rows). Move or hide a widget first.`,
|
|
573
|
+
emptyPage: "This page has no widgets. Move one here from another page.",
|
|
538
574
|
opensInNewTab: "(opens in a new tab)",
|
|
539
575
|
view: (title) => `View ${title}`,
|
|
540
576
|
close: "Close",
|
|
@@ -1623,6 +1659,9 @@ function isWidgetVisibleTo(definition, roles) {
|
|
|
1623
1659
|
}
|
|
1624
1660
|
|
|
1625
1661
|
// src/core/layout.ts
|
|
1662
|
+
var MAX_PAGE_TITLE_LENGTH = 30;
|
|
1663
|
+
var MAX_PARSED_PAGES = 50;
|
|
1664
|
+
var MAX_PAGE_ROWS = 20;
|
|
1626
1665
|
var EMPTY_LAYOUT = Object.freeze({
|
|
1627
1666
|
order: Object.freeze([]),
|
|
1628
1667
|
hidden: Object.freeze([]),
|
|
@@ -1737,6 +1776,22 @@ function restoreWidget(layout, key) {
|
|
|
1737
1776
|
function toggleMinimized(layout, key) {
|
|
1738
1777
|
return isMinimized(layout, key) ? restoreWidget(layout, key) : minimizeWidget(layout, key);
|
|
1739
1778
|
}
|
|
1779
|
+
function mapLayoutLists(layout, change) {
|
|
1780
|
+
const top = change(layout);
|
|
1781
|
+
const pages = layout.pages?.map((page) => {
|
|
1782
|
+
const next = change(page);
|
|
1783
|
+
return next.order === page.order && next.hidden === page.hidden && next.minimized === page.minimized ? page : { ...page, ...next };
|
|
1784
|
+
});
|
|
1785
|
+
const pagesChanged = pages !== void 0 && pages.some((page, i) => page !== layout.pages?.[i]);
|
|
1786
|
+
if (top.order === layout.order && top.hidden === layout.hidden && top.minimized === layout.minimized && !pagesChanged) {
|
|
1787
|
+
return layout;
|
|
1788
|
+
}
|
|
1789
|
+
return {
|
|
1790
|
+
...layout,
|
|
1791
|
+
...top,
|
|
1792
|
+
...pages === void 0 ? {} : { pages }
|
|
1793
|
+
};
|
|
1794
|
+
}
|
|
1740
1795
|
function enforceLocks(definitions, layout, options = {}) {
|
|
1741
1796
|
if (options.overrideLocks === true) return layout;
|
|
1742
1797
|
const noMove = /* @__PURE__ */ new Set();
|
|
@@ -1748,11 +1803,337 @@ function enforceLocks(definitions, layout, options = {}) {
|
|
|
1748
1803
|
if (lock.hide) noHide.add(definition.key);
|
|
1749
1804
|
if (lock.minimize) noMinimize.add(definition.key);
|
|
1750
1805
|
}
|
|
1751
|
-
const
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1806
|
+
const without2 = (keys, drop) => keys.some((key) => drop.has(key)) ? keys.filter((key) => !drop.has(key)) : keys;
|
|
1807
|
+
return mapLayoutLists(layout, (lists) => ({
|
|
1808
|
+
order: without2(lists.order, noMove),
|
|
1809
|
+
hidden: without2(lists.hidden, noHide),
|
|
1810
|
+
minimized: without2(lists.minimized, noMinimize)
|
|
1811
|
+
}));
|
|
1812
|
+
}
|
|
1813
|
+
|
|
1814
|
+
// src/core/pages.ts
|
|
1815
|
+
var DEFAULT_PAGE_KEY = "default";
|
|
1816
|
+
var DEFAULT_PAGE_ROWS = 4;
|
|
1817
|
+
function rowsAllowed(page, options) {
|
|
1818
|
+
const rows = page.maxRows ?? options.maxRows ?? DEFAULT_PAGE_ROWS;
|
|
1819
|
+
return Math.max(1, Math.min(MAX_PAGE_ROWS, Math.floor(rows)));
|
|
1820
|
+
}
|
|
1821
|
+
function hasPages(layout) {
|
|
1822
|
+
return layout.pages !== void 0 && layout.pages.length > 0;
|
|
1823
|
+
}
|
|
1824
|
+
function pageList(layout) {
|
|
1825
|
+
if (layout.pages !== void 0 && layout.pages.length > 0) {
|
|
1826
|
+
return layout.pages;
|
|
1827
|
+
}
|
|
1828
|
+
return [
|
|
1829
|
+
{
|
|
1830
|
+
key: DEFAULT_PAGE_KEY,
|
|
1831
|
+
title: "Page 1",
|
|
1832
|
+
order: layout.order,
|
|
1833
|
+
hidden: layout.hidden,
|
|
1834
|
+
minimized: layout.minimized
|
|
1835
|
+
}
|
|
1836
|
+
];
|
|
1837
|
+
}
|
|
1838
|
+
function withExplicitPages(layout) {
|
|
1839
|
+
if (hasPages(layout)) return layout;
|
|
1840
|
+
return {
|
|
1841
|
+
...layout,
|
|
1842
|
+
order: [],
|
|
1843
|
+
hidden: [],
|
|
1844
|
+
minimized: [],
|
|
1845
|
+
pages: pageList(layout)
|
|
1846
|
+
};
|
|
1847
|
+
}
|
|
1848
|
+
function sameKeys(a, b) {
|
|
1849
|
+
return a === b || a.length === b.length && a.every((k, i) => k === b[i]);
|
|
1850
|
+
}
|
|
1851
|
+
function pageLayout(layout, pageKey) {
|
|
1852
|
+
if (!hasPages(layout))
|
|
1853
|
+
return pageKey === DEFAULT_PAGE_KEY ? layout : void 0;
|
|
1854
|
+
const page = layout.pages?.find(
|
|
1855
|
+
(p) => p.key === pageKey
|
|
1856
|
+
);
|
|
1857
|
+
if (page === void 0) return void 0;
|
|
1858
|
+
const { pages, ...rest } = layout;
|
|
1859
|
+
return {
|
|
1860
|
+
...rest,
|
|
1861
|
+
order: page.order,
|
|
1862
|
+
hidden: page.hidden,
|
|
1863
|
+
minimized: page.minimized
|
|
1864
|
+
};
|
|
1865
|
+
}
|
|
1866
|
+
function withPageLayout(layout, pageKey, next) {
|
|
1867
|
+
const current = pageLayout(layout, pageKey);
|
|
1868
|
+
if (current === void 0 || sameKeys(current.order, next.order) && sameKeys(current.hidden, next.hidden) && sameKeys(current.minimized, next.minimized)) {
|
|
1869
|
+
return layout;
|
|
1870
|
+
}
|
|
1871
|
+
if (!hasPages(layout)) {
|
|
1872
|
+
return {
|
|
1873
|
+
...layout,
|
|
1874
|
+
order: next.order,
|
|
1875
|
+
hidden: next.hidden,
|
|
1876
|
+
minimized: next.minimized
|
|
1877
|
+
};
|
|
1878
|
+
}
|
|
1879
|
+
return {
|
|
1880
|
+
...layout,
|
|
1881
|
+
pages: (layout.pages ?? []).map(
|
|
1882
|
+
(page) => page.key === pageKey ? {
|
|
1883
|
+
...page,
|
|
1884
|
+
order: next.order,
|
|
1885
|
+
hidden: next.hidden,
|
|
1886
|
+
minimized: next.minimized
|
|
1887
|
+
} : page
|
|
1888
|
+
)
|
|
1889
|
+
};
|
|
1890
|
+
}
|
|
1891
|
+
function normalizedTitle(title) {
|
|
1892
|
+
return title.trim().normalize("NFKC").toLowerCase();
|
|
1893
|
+
}
|
|
1894
|
+
function resolvePageKey(layout, reference) {
|
|
1895
|
+
if (reference === void 0 || reference === "") return void 0;
|
|
1896
|
+
const pages = pageList(layout);
|
|
1897
|
+
const byKey = pages.find((p) => p.key === reference);
|
|
1898
|
+
if (byKey !== void 0) return byKey.key;
|
|
1899
|
+
const wanted = normalizedTitle(reference);
|
|
1900
|
+
return pages.find((p) => normalizedTitle(p.title) === wanted)?.key;
|
|
1901
|
+
}
|
|
1902
|
+
function homePageKey(layout, item) {
|
|
1903
|
+
return resolvePageKey(layout, item.page) ?? pageList(layout)[0].key;
|
|
1904
|
+
}
|
|
1905
|
+
function assignPages(definitions, layout) {
|
|
1906
|
+
const pages = pageList(layout);
|
|
1907
|
+
const assigned = new Map(pages.map((p) => [p.key, []]));
|
|
1908
|
+
for (const definition of definitions) {
|
|
1909
|
+
let pageKey;
|
|
1910
|
+
if (!resolveWidgetLock(definition).move) {
|
|
1911
|
+
pageKey = pages.find(
|
|
1912
|
+
(p) => p.order.includes(definition.key) || p.hidden.includes(definition.key)
|
|
1913
|
+
)?.key;
|
|
1914
|
+
}
|
|
1915
|
+
assigned.get(pageKey ?? homePageKey(layout, definition))?.push(definition);
|
|
1916
|
+
}
|
|
1917
|
+
return assigned;
|
|
1918
|
+
}
|
|
1919
|
+
function pageOf(definitions, layout, key) {
|
|
1920
|
+
for (const [pageKey, widgets] of assignPages(definitions, layout)) {
|
|
1921
|
+
if (widgets.some((w) => w.key === key)) return pageKey;
|
|
1922
|
+
}
|
|
1923
|
+
return void 0;
|
|
1924
|
+
}
|
|
1925
|
+
function pageWidgets(definitions, layout, pageKey) {
|
|
1926
|
+
const onPage = assignPages(definitions, layout).get(pageKey) ?? [];
|
|
1927
|
+
const view = pageLayout(layout, pageKey);
|
|
1928
|
+
return view === void 0 ? [] : visibleWidgets(onPage, view);
|
|
1929
|
+
}
|
|
1930
|
+
function pageRoom(definitions, layout, pageKey, options = {}) {
|
|
1931
|
+
const page = pageList(layout).find(
|
|
1932
|
+
(p) => p.key === pageKey
|
|
1933
|
+
);
|
|
1934
|
+
if (page === void 0) return void 0;
|
|
1935
|
+
const maxRows = rowsAllowed(page, options);
|
|
1936
|
+
const rowsUsed = placeRows(
|
|
1937
|
+
pageWidgets(definitions, layout, pageKey)
|
|
1938
|
+
).length;
|
|
1939
|
+
return { maxRows, rowsUsed, rowsFree: Math.max(0, maxRows - rowsUsed) };
|
|
1940
|
+
}
|
|
1941
|
+
function describePage(page) {
|
|
1942
|
+
return `Page "${page.title}"`;
|
|
1943
|
+
}
|
|
1944
|
+
function titleOf(item) {
|
|
1945
|
+
return item.title ?? item.key;
|
|
1946
|
+
}
|
|
1947
|
+
function checkTitle(layout, title, exceptKey) {
|
|
1948
|
+
const trimmed = title.trim();
|
|
1949
|
+
if (trimmed === "") return err("A page title must not be empty.");
|
|
1950
|
+
if (trimmed.length > MAX_PAGE_TITLE_LENGTH) {
|
|
1951
|
+
return err(
|
|
1952
|
+
`Page title "${trimmed}" is ${trimmed.length} characters; the most is ${MAX_PAGE_TITLE_LENGTH}.`
|
|
1953
|
+
);
|
|
1954
|
+
}
|
|
1955
|
+
const wanted = normalizedTitle(trimmed);
|
|
1956
|
+
const clash = pageList(layout).find(
|
|
1957
|
+
(p) => p.key !== exceptKey && normalizedTitle(p.title) === wanted
|
|
1958
|
+
);
|
|
1959
|
+
if (clash !== void 0) {
|
|
1960
|
+
return err(`Another page is already called "${clash.title}".`);
|
|
1961
|
+
}
|
|
1962
|
+
return ok(trimmed);
|
|
1963
|
+
}
|
|
1964
|
+
function nextPageKey(layout) {
|
|
1965
|
+
const keys = new Set(pageList(layout).map((p) => p.key));
|
|
1966
|
+
let n = 1;
|
|
1967
|
+
while (keys.has(`page-${n}`)) n += 1;
|
|
1968
|
+
return `page-${n}`;
|
|
1969
|
+
}
|
|
1970
|
+
function nextPageTitle(layout) {
|
|
1971
|
+
const used = new Set(
|
|
1972
|
+
pageList(layout).map((p) => normalizedTitle(p.title))
|
|
1973
|
+
);
|
|
1974
|
+
let n = pageList(layout).length + 1;
|
|
1975
|
+
while (used.has(normalizedTitle(`Page ${n}`))) n += 1;
|
|
1976
|
+
return `Page ${n}`;
|
|
1977
|
+
}
|
|
1978
|
+
function addPage(layout, options = {}) {
|
|
1979
|
+
if (pageList(layout).length >= MAX_PARSED_PAGES) {
|
|
1980
|
+
return err(
|
|
1981
|
+
`The layout already has ${MAX_PARSED_PAGES} pages, the most it can keep.`
|
|
1982
|
+
);
|
|
1983
|
+
}
|
|
1984
|
+
const key = options.key ?? nextPageKey(layout);
|
|
1985
|
+
if (pageList(layout).some((p) => p.key === key)) {
|
|
1986
|
+
return err(`A page with the key "${key}" already exists.`);
|
|
1987
|
+
}
|
|
1988
|
+
const title = checkTitle(
|
|
1989
|
+
layout,
|
|
1990
|
+
options.title ?? nextPageTitle(layout)
|
|
1991
|
+
);
|
|
1992
|
+
if (!title.ok) return title;
|
|
1993
|
+
const base = withExplicitPages(layout);
|
|
1994
|
+
const page = {
|
|
1995
|
+
key,
|
|
1996
|
+
title: title.value,
|
|
1997
|
+
order: [],
|
|
1998
|
+
hidden: [],
|
|
1999
|
+
minimized: []
|
|
2000
|
+
};
|
|
2001
|
+
return ok({ ...base, pages: [...base.pages ?? [], page] });
|
|
2002
|
+
}
|
|
2003
|
+
function renamePage(layout, pageKey, title) {
|
|
2004
|
+
const page = pageList(layout).find(
|
|
2005
|
+
(p) => p.key === pageKey
|
|
2006
|
+
);
|
|
2007
|
+
if (page === void 0) return err(`Page "${pageKey}" doesn't exist.`);
|
|
2008
|
+
const checked = checkTitle(layout, title, pageKey);
|
|
2009
|
+
if (!checked.ok) return checked;
|
|
2010
|
+
if (checked.value === page.title) return ok(layout);
|
|
2011
|
+
const base = withExplicitPages(layout);
|
|
2012
|
+
return ok({
|
|
2013
|
+
...base,
|
|
2014
|
+
pages: (base.pages ?? []).map(
|
|
2015
|
+
(p) => p.key === pageKey ? { ...p, title: checked.value } : p
|
|
2016
|
+
)
|
|
2017
|
+
});
|
|
2018
|
+
}
|
|
2019
|
+
function movePage(layout, pageKey, offset) {
|
|
2020
|
+
const pages = layout.pages ?? [];
|
|
2021
|
+
const from = pages.findIndex((p) => p.key === pageKey);
|
|
2022
|
+
if (from === -1) return layout;
|
|
2023
|
+
const to = Math.max(
|
|
2024
|
+
0,
|
|
2025
|
+
Math.min(pages.length - 1, from + Math.trunc(offset))
|
|
2026
|
+
);
|
|
2027
|
+
if (to === from) return layout;
|
|
2028
|
+
const next = [...pages];
|
|
2029
|
+
const [moved] = next.splice(from, 1);
|
|
2030
|
+
next.splice(to, 0, moved);
|
|
2031
|
+
return { ...layout, pages: next };
|
|
2032
|
+
}
|
|
2033
|
+
function overflowing(definitions, layout, options) {
|
|
2034
|
+
return pageList(layout).find(
|
|
2035
|
+
(page) => placeRows(pageWidgets(definitions, layout, page.key)).length > rowsAllowed(page, options)
|
|
2036
|
+
);
|
|
2037
|
+
}
|
|
2038
|
+
function removePage(definitions, layout, pageKey, options = {}) {
|
|
2039
|
+
const pages = pageList(layout);
|
|
2040
|
+
const index = pages.findIndex((p) => p.key === pageKey);
|
|
2041
|
+
const page = pages[index];
|
|
2042
|
+
if (page === void 0) return err(`Page "${pageKey}" doesn't exist.`);
|
|
2043
|
+
if (pages.length === 1) {
|
|
2044
|
+
return err(
|
|
2045
|
+
`${describePage(page)} is the only page, so it can't be removed.`
|
|
2046
|
+
);
|
|
2047
|
+
}
|
|
2048
|
+
const target = pages[index > 0 ? index - 1 : 1];
|
|
2049
|
+
const merged = {
|
|
2050
|
+
...layout,
|
|
2051
|
+
pages: pages.filter((p) => p.key !== pageKey).map(
|
|
2052
|
+
(p) => p.key === target.key ? {
|
|
2053
|
+
...p,
|
|
2054
|
+
order: index > 0 ? [...p.order, ...page.order] : [...page.order, ...p.order],
|
|
2055
|
+
hidden: [...p.hidden, ...page.hidden],
|
|
2056
|
+
minimized: [...p.minimized, ...page.minimized]
|
|
2057
|
+
} : p
|
|
2058
|
+
)
|
|
2059
|
+
};
|
|
2060
|
+
const full = overflowing(
|
|
2061
|
+
definitions,
|
|
2062
|
+
merged,
|
|
2063
|
+
options
|
|
2064
|
+
);
|
|
2065
|
+
if (full !== void 0) {
|
|
2066
|
+
return err(
|
|
2067
|
+
`${describePage(page)} has widgets that don't fit on the other pages (${describePage(full)} would need more than ${rowsAllowed(full, options)} rows). Move or hide some first.`
|
|
2068
|
+
);
|
|
2069
|
+
}
|
|
2070
|
+
return ok(merged);
|
|
2071
|
+
}
|
|
2072
|
+
function without(keys, key) {
|
|
2073
|
+
return keys.includes(key) ? keys.filter((k) => k !== key) : keys;
|
|
2074
|
+
}
|
|
2075
|
+
function moveWidgetToPage(definitions, layout, widgetKey, targetKey, options = {}) {
|
|
2076
|
+
const widget = definitions.find((d) => d.key === widgetKey);
|
|
2077
|
+
if (widget === void 0) {
|
|
2078
|
+
return err(
|
|
2079
|
+
`Widget "${widgetKey}" isn't one of the widgets, so it can't be moved to a page.`
|
|
2080
|
+
);
|
|
2081
|
+
}
|
|
2082
|
+
const pages = pageList(layout);
|
|
2083
|
+
const target = pages.find((p) => p.key === targetKey);
|
|
2084
|
+
if (target === void 0) return err(`Page "${targetKey}" doesn't exist.`);
|
|
2085
|
+
const sourceKey = pageOf(definitions, layout, widgetKey);
|
|
2086
|
+
if (sourceKey === targetKey) return ok(layout);
|
|
2087
|
+
if (resolveWidgetLock(widget).move) {
|
|
2088
|
+
return err(
|
|
2089
|
+
`Widget "${titleOf(widget)}" is locked against moving, so it can't be moved to ${describePage(target)}.`
|
|
2090
|
+
);
|
|
2091
|
+
}
|
|
2092
|
+
const base = withExplicitPages(layout);
|
|
2093
|
+
const source = (base.pages ?? []).find(
|
|
2094
|
+
(p) => p.key === sourceKey
|
|
2095
|
+
);
|
|
2096
|
+
const hidden = source.hidden.includes(widgetKey);
|
|
2097
|
+
const minimized = source.minimized.includes(widgetKey);
|
|
2098
|
+
const targetOrder = pageWidgets(
|
|
2099
|
+
definitions,
|
|
2100
|
+
base,
|
|
2101
|
+
targetKey
|
|
2102
|
+
).map((d) => d.key);
|
|
2103
|
+
const moved = {
|
|
2104
|
+
...base,
|
|
2105
|
+
pages: (base.pages ?? []).map((p) => {
|
|
2106
|
+
if (p.key === sourceKey) {
|
|
2107
|
+
return {
|
|
2108
|
+
...p,
|
|
2109
|
+
order: without(p.order, widgetKey),
|
|
2110
|
+
hidden: without(p.hidden, widgetKey),
|
|
2111
|
+
minimized: without(p.minimized, widgetKey)
|
|
2112
|
+
};
|
|
2113
|
+
}
|
|
2114
|
+
if (p.key === targetKey) {
|
|
2115
|
+
return {
|
|
2116
|
+
...p,
|
|
2117
|
+
order: hidden ? p.order : [...targetOrder, widgetKey],
|
|
2118
|
+
hidden: hidden ? [...p.hidden, widgetKey] : p.hidden,
|
|
2119
|
+
minimized: minimized ? [...p.minimized, widgetKey] : p.minimized
|
|
2120
|
+
};
|
|
2121
|
+
}
|
|
2122
|
+
return p;
|
|
2123
|
+
})
|
|
2124
|
+
};
|
|
2125
|
+
if (!hidden) {
|
|
2126
|
+
const allowed = rowsAllowed(target, options);
|
|
2127
|
+
const needed = placeRows(
|
|
2128
|
+
pageWidgets(definitions, moved, targetKey)
|
|
2129
|
+
).length;
|
|
2130
|
+
if (needed > allowed) {
|
|
2131
|
+
return err(
|
|
2132
|
+
`${describePage(target)} has no room for "${titleOf(widget)}": it would need row ${needed}, and the page allows ${allowed}.`
|
|
2133
|
+
);
|
|
2134
|
+
}
|
|
2135
|
+
}
|
|
2136
|
+
return ok(moved);
|
|
1756
2137
|
}
|
|
1757
2138
|
function nextSort(current, column) {
|
|
1758
2139
|
if (current?.column !== column) return { column, direction: "asc" };
|
|
@@ -2033,6 +2414,25 @@ function useDetailData(definition, load, enabled, fallback) {
|
|
|
2033
2414
|
}, [enabled, load, fallback, definition, attempt]);
|
|
2034
2415
|
return { state, reload: () => setAttempt((count) => count + 1) };
|
|
2035
2416
|
}
|
|
2417
|
+
var NEW_PAGE_VALUE = "__new-page__";
|
|
2418
|
+
function PagePanel({
|
|
2419
|
+
paged,
|
|
2420
|
+
id,
|
|
2421
|
+
labelledBy,
|
|
2422
|
+
children
|
|
2423
|
+
}) {
|
|
2424
|
+
if (!paged) return /* @__PURE__ */ jsx(Fragment, { children });
|
|
2425
|
+
return /* @__PURE__ */ jsx(
|
|
2426
|
+
"div",
|
|
2427
|
+
{
|
|
2428
|
+
role: "tabpanel",
|
|
2429
|
+
id,
|
|
2430
|
+
"aria-labelledby": labelledBy,
|
|
2431
|
+
className: "dwt-page-panel",
|
|
2432
|
+
children
|
|
2433
|
+
}
|
|
2434
|
+
);
|
|
2435
|
+
}
|
|
2036
2436
|
var NARROW_VIEWPORT_QUERY = "(max-width: 640px)";
|
|
2037
2437
|
var WIDE_GRID_PX = 900;
|
|
2038
2438
|
function useFillSpans(definitions, gridRef, twelve) {
|
|
@@ -2203,6 +2603,181 @@ function InlineConfirm({
|
|
|
2203
2603
|
}
|
|
2204
2604
|
);
|
|
2205
2605
|
}
|
|
2606
|
+
function PageTabs({
|
|
2607
|
+
pages,
|
|
2608
|
+
activeKey,
|
|
2609
|
+
idPrefix,
|
|
2610
|
+
panelId,
|
|
2611
|
+
announcement,
|
|
2612
|
+
onSelect
|
|
2613
|
+
}) {
|
|
2614
|
+
const slot = useSlotClassName();
|
|
2615
|
+
const { labels } = useWidgetSettings();
|
|
2616
|
+
const tabs = useRef(/* @__PURE__ */ new Map());
|
|
2617
|
+
const activeIndex = pages.findIndex((p) => p.key === activeKey);
|
|
2618
|
+
function onKeyDown(event, index) {
|
|
2619
|
+
const last = pages.length - 1;
|
|
2620
|
+
let next;
|
|
2621
|
+
switch (event.key) {
|
|
2622
|
+
case "ArrowRight":
|
|
2623
|
+
case "ArrowDown":
|
|
2624
|
+
next = index === last ? 0 : index + 1;
|
|
2625
|
+
break;
|
|
2626
|
+
case "ArrowLeft":
|
|
2627
|
+
case "ArrowUp":
|
|
2628
|
+
next = index === 0 ? last : index - 1;
|
|
2629
|
+
break;
|
|
2630
|
+
case "Home":
|
|
2631
|
+
next = 0;
|
|
2632
|
+
break;
|
|
2633
|
+
case "End":
|
|
2634
|
+
next = last;
|
|
2635
|
+
break;
|
|
2636
|
+
default:
|
|
2637
|
+
return;
|
|
2638
|
+
}
|
|
2639
|
+
event.preventDefault();
|
|
2640
|
+
const target = pages[next];
|
|
2641
|
+
if (target === void 0) return;
|
|
2642
|
+
onSelect(target.key);
|
|
2643
|
+
tabs.current.get(target.key)?.focus();
|
|
2644
|
+
}
|
|
2645
|
+
return /* @__PURE__ */ jsxs("div", { className: slot("pageBar", "dwt-pages"), children: [
|
|
2646
|
+
/* @__PURE__ */ jsx(
|
|
2647
|
+
"button",
|
|
2648
|
+
{
|
|
2649
|
+
type: "button",
|
|
2650
|
+
className: slot(
|
|
2651
|
+
"button",
|
|
2652
|
+
"dwt-button",
|
|
2653
|
+
"dwt-icon-button",
|
|
2654
|
+
"dwt-page-nav"
|
|
2655
|
+
),
|
|
2656
|
+
"aria-label": labels.previousPageButton,
|
|
2657
|
+
disabled: activeIndex <= 0,
|
|
2658
|
+
onClick: () => onSelect(pages[activeIndex - 1].key),
|
|
2659
|
+
children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u2039" })
|
|
2660
|
+
}
|
|
2661
|
+
),
|
|
2662
|
+
/* @__PURE__ */ jsx("div", { role: "tablist", "aria-label": labels.pageBar, className: "dwt-page-tabs", children: pages.map((page, index) => {
|
|
2663
|
+
const selected = page.key === activeKey;
|
|
2664
|
+
return /* @__PURE__ */ jsxs(
|
|
2665
|
+
"button",
|
|
2666
|
+
{
|
|
2667
|
+
ref: (element) => {
|
|
2668
|
+
if (element === null) tabs.current.delete(page.key);
|
|
2669
|
+
else tabs.current.set(page.key, element);
|
|
2670
|
+
},
|
|
2671
|
+
type: "button",
|
|
2672
|
+
role: "tab",
|
|
2673
|
+
id: `${idPrefix}-tab-${index}`,
|
|
2674
|
+
"aria-selected": selected,
|
|
2675
|
+
"aria-controls": panelId,
|
|
2676
|
+
"aria-label": labels.pageTabName(
|
|
2677
|
+
index + 1,
|
|
2678
|
+
pages.length,
|
|
2679
|
+
page.title
|
|
2680
|
+
),
|
|
2681
|
+
title: page.title,
|
|
2682
|
+
tabIndex: selected ? 0 : -1,
|
|
2683
|
+
className: slot("button", "dwt-page-tab"),
|
|
2684
|
+
onClick: () => onSelect(page.key),
|
|
2685
|
+
onKeyDown: (event) => onKeyDown(event, index),
|
|
2686
|
+
children: [
|
|
2687
|
+
/* @__PURE__ */ jsx("span", { className: "dwt-page-tab-title", children: page.title }),
|
|
2688
|
+
/* @__PURE__ */ jsx("span", { className: "dwt-page-dot", "aria-hidden": "true" })
|
|
2689
|
+
]
|
|
2690
|
+
},
|
|
2691
|
+
page.key
|
|
2692
|
+
);
|
|
2693
|
+
}) }),
|
|
2694
|
+
/* @__PURE__ */ jsx(
|
|
2695
|
+
"button",
|
|
2696
|
+
{
|
|
2697
|
+
type: "button",
|
|
2698
|
+
className: slot(
|
|
2699
|
+
"button",
|
|
2700
|
+
"dwt-button",
|
|
2701
|
+
"dwt-icon-button",
|
|
2702
|
+
"dwt-page-nav"
|
|
2703
|
+
),
|
|
2704
|
+
"aria-label": labels.nextPageButton,
|
|
2705
|
+
disabled: activeIndex === pages.length - 1,
|
|
2706
|
+
onClick: () => onSelect(pages[activeIndex + 1].key),
|
|
2707
|
+
children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u203A" })
|
|
2708
|
+
}
|
|
2709
|
+
),
|
|
2710
|
+
/* @__PURE__ */ jsx("span", { className: "dwt-visually-hidden", "aria-live": "polite", children: announcement })
|
|
2711
|
+
] });
|
|
2712
|
+
}
|
|
2713
|
+
function PageRenameForm({
|
|
2714
|
+
initial,
|
|
2715
|
+
onSubmit,
|
|
2716
|
+
onCancel
|
|
2717
|
+
}) {
|
|
2718
|
+
const slot = useSlotClassName();
|
|
2719
|
+
const { labels } = useWidgetSettings();
|
|
2720
|
+
const [title, setTitle] = useState(initial);
|
|
2721
|
+
const [error, setError] = useState(void 0);
|
|
2722
|
+
const inputRef = useRef(null);
|
|
2723
|
+
useEffect(() => {
|
|
2724
|
+
inputRef.current?.focus();
|
|
2725
|
+
inputRef.current?.select();
|
|
2726
|
+
}, []);
|
|
2727
|
+
return /* @__PURE__ */ jsxs(
|
|
2728
|
+
"form",
|
|
2729
|
+
{
|
|
2730
|
+
className: "dwt-page-rename",
|
|
2731
|
+
onSubmit: (event) => {
|
|
2732
|
+
event.preventDefault();
|
|
2733
|
+
setError(onSubmit(title));
|
|
2734
|
+
},
|
|
2735
|
+
onKeyDown: (event) => {
|
|
2736
|
+
if (event.key === "Escape") {
|
|
2737
|
+
event.stopPropagation();
|
|
2738
|
+
onCancel();
|
|
2739
|
+
}
|
|
2740
|
+
},
|
|
2741
|
+
children: [
|
|
2742
|
+
/* @__PURE__ */ jsx(
|
|
2743
|
+
"input",
|
|
2744
|
+
{
|
|
2745
|
+
ref: inputRef,
|
|
2746
|
+
type: "text",
|
|
2747
|
+
className: "dwt-page-title-input",
|
|
2748
|
+
"aria-label": labels.pageTitle,
|
|
2749
|
+
"aria-invalid": error !== void 0,
|
|
2750
|
+
maxLength: MAX_PAGE_TITLE_LENGTH,
|
|
2751
|
+
value: title,
|
|
2752
|
+
onChange: (event) => setTitle(event.target.value)
|
|
2753
|
+
}
|
|
2754
|
+
),
|
|
2755
|
+
/* @__PURE__ */ jsx(
|
|
2756
|
+
"button",
|
|
2757
|
+
{
|
|
2758
|
+
type: "submit",
|
|
2759
|
+
className: slot("button", "dwt-button", "dwt-icon-button"),
|
|
2760
|
+
"aria-label": labels.savePageTitle,
|
|
2761
|
+
title: labels.savePageTitle,
|
|
2762
|
+
children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u2713" })
|
|
2763
|
+
}
|
|
2764
|
+
),
|
|
2765
|
+
/* @__PURE__ */ jsx(
|
|
2766
|
+
"button",
|
|
2767
|
+
{
|
|
2768
|
+
type: "button",
|
|
2769
|
+
className: slot("button", "dwt-button", "dwt-icon-button"),
|
|
2770
|
+
"aria-label": labels.cancelPageTitle,
|
|
2771
|
+
title: labels.cancelPageTitle,
|
|
2772
|
+
onClick: onCancel,
|
|
2773
|
+
children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u2715" })
|
|
2774
|
+
}
|
|
2775
|
+
),
|
|
2776
|
+
error !== void 0 && /* @__PURE__ */ jsx("span", { role: "alert", className: "dwt-page-error", children: error })
|
|
2777
|
+
]
|
|
2778
|
+
}
|
|
2779
|
+
);
|
|
2780
|
+
}
|
|
2206
2781
|
function withoutLock(definition) {
|
|
2207
2782
|
if (definition.locked === void 0) return definition;
|
|
2208
2783
|
const copy = { ...definition };
|
|
@@ -2220,6 +2795,11 @@ function DashboardInner({
|
|
|
2220
2795
|
onEditingChange,
|
|
2221
2796
|
defaultLayout,
|
|
2222
2797
|
toolbar = true,
|
|
2798
|
+
activePage: activePageProp,
|
|
2799
|
+
defaultActivePage,
|
|
2800
|
+
onActivePageChange,
|
|
2801
|
+
maxRows,
|
|
2802
|
+
maxPages,
|
|
2223
2803
|
onRetry,
|
|
2224
2804
|
loadDetail,
|
|
2225
2805
|
onOpenDetail,
|
|
@@ -2235,8 +2815,19 @@ function DashboardInner({
|
|
|
2235
2815
|
const byKey = new Map(
|
|
2236
2816
|
widgets.map((w) => [w.definition.key, w])
|
|
2237
2817
|
);
|
|
2238
|
-
const
|
|
2239
|
-
const
|
|
2818
|
+
const pages = pageList(layout);
|
|
2819
|
+
const paged = pages.length >= 2;
|
|
2820
|
+
const [activeState, setActiveState] = useState(
|
|
2821
|
+
defaultActivePage
|
|
2822
|
+
);
|
|
2823
|
+
const requested = activePageProp ?? activeState;
|
|
2824
|
+
const activePage = pages.find((page) => page.key === requested) ?? pages[0];
|
|
2825
|
+
const activeKey = activePage.key;
|
|
2826
|
+
const pageDefs = assignPages(definitions, layout).get(activeKey) ?? [];
|
|
2827
|
+
const view = pageLayout(layout, activeKey) ?? layout;
|
|
2828
|
+
const roomOptions = maxRows === void 0 ? {} : { maxRows };
|
|
2829
|
+
const visible = visibleWidgets(pageDefs, view);
|
|
2830
|
+
const hidden = hiddenWidgets(pageDefs, view);
|
|
2240
2831
|
const editable = onLayoutChange !== void 0;
|
|
2241
2832
|
const toggleMode = editMode === "toggle";
|
|
2242
2833
|
const [editingState, setEditingState] = useState(defaultEditing);
|
|
@@ -2255,10 +2846,16 @@ function DashboardInner({
|
|
|
2255
2846
|
);
|
|
2256
2847
|
const pending = editing ? confirming : void 0;
|
|
2257
2848
|
const [announcement, setAnnouncement] = useState("");
|
|
2849
|
+
const [pageAnnouncement, setPageAnnouncement] = useState("");
|
|
2850
|
+
const [pageError, setPageError] = useState(void 0);
|
|
2851
|
+
const [pageEditor, setPageEditor] = useState(void 0);
|
|
2852
|
+
const editorMode = pageEditor?.key === activeKey ? pageEditor.mode : void 0;
|
|
2853
|
+
const instanceId = useId();
|
|
2854
|
+
const panelId = `${instanceId}-panel`;
|
|
2258
2855
|
const toggleRef = useRef(null);
|
|
2259
2856
|
const resetRef = useRef(null);
|
|
2260
|
-
const minimized = editable ? visible.filter((definition) => isMinimized(
|
|
2261
|
-
const shown = editable ? visible.filter((definition) => !isMinimized(
|
|
2857
|
+
const minimized = editable ? visible.filter((definition) => isMinimized(view, definition.key)) : [];
|
|
2858
|
+
const shown = editable ? visible.filter((definition) => !isMinimized(view, definition.key)) : visible;
|
|
2262
2859
|
const [detailKey, setDetailKey] = useState(void 0);
|
|
2263
2860
|
const gridRef = useRef(null);
|
|
2264
2861
|
const twelve = usesWidthColumns(shown);
|
|
@@ -2270,6 +2867,110 @@ function DashboardInner({
|
|
|
2270
2867
|
function change(next) {
|
|
2271
2868
|
if (next !== layout) onLayoutChange?.(next);
|
|
2272
2869
|
}
|
|
2870
|
+
function changePage(next) {
|
|
2871
|
+
setPageError(void 0);
|
|
2872
|
+
change(withPageLayout(layout, activeKey, next));
|
|
2873
|
+
}
|
|
2874
|
+
function selectPage(pageKey) {
|
|
2875
|
+
const index = pages.findIndex((page) => page.key === pageKey);
|
|
2876
|
+
if (index === -1) return;
|
|
2877
|
+
if (activePageProp === void 0) setActiveState(pageKey);
|
|
2878
|
+
onActivePageChange?.(pageKey);
|
|
2879
|
+
setPageError(void 0);
|
|
2880
|
+
setPageEditor(void 0);
|
|
2881
|
+
setPageAnnouncement(
|
|
2882
|
+
labels.pageTabName(
|
|
2883
|
+
index + 1,
|
|
2884
|
+
pages.length,
|
|
2885
|
+
pages[index].title
|
|
2886
|
+
)
|
|
2887
|
+
);
|
|
2888
|
+
}
|
|
2889
|
+
function addPageAction() {
|
|
2890
|
+
const added = addPage(layout);
|
|
2891
|
+
if (!added.ok) {
|
|
2892
|
+
setPageError(added.error);
|
|
2893
|
+
return;
|
|
2894
|
+
}
|
|
2895
|
+
change(added.value);
|
|
2896
|
+
const created = added.value.pages?.at(-1);
|
|
2897
|
+
if (created !== void 0) {
|
|
2898
|
+
if (activePageProp === void 0) setActiveState(created.key);
|
|
2899
|
+
onActivePageChange?.(created.key);
|
|
2900
|
+
setPageError(void 0);
|
|
2901
|
+
setPageEditor({ mode: "rename", key: created.key });
|
|
2902
|
+
}
|
|
2903
|
+
}
|
|
2904
|
+
function renamePageAction(title) {
|
|
2905
|
+
const renamed = renamePage(layout, activeKey, title);
|
|
2906
|
+
if (!renamed.ok) return renamed.error;
|
|
2907
|
+
change(renamed.value);
|
|
2908
|
+
setPageEditor(void 0);
|
|
2909
|
+
return void 0;
|
|
2910
|
+
}
|
|
2911
|
+
function deletePageAction() {
|
|
2912
|
+
const index = pages.findIndex((page) => page.key === activeKey);
|
|
2913
|
+
const removed = removePage(definitions, layout, activeKey, roomOptions);
|
|
2914
|
+
setPageEditor(void 0);
|
|
2915
|
+
if (!removed.ok) {
|
|
2916
|
+
setPageError(removed.error);
|
|
2917
|
+
return;
|
|
2918
|
+
}
|
|
2919
|
+
const neighbor = pages[index > 0 ? index - 1 : 1];
|
|
2920
|
+
change(removed.value);
|
|
2921
|
+
if (neighbor !== void 0) selectPage(neighbor.key);
|
|
2922
|
+
}
|
|
2923
|
+
function moveWidgetAction(widgetKey, targetKey) {
|
|
2924
|
+
let target = targetKey;
|
|
2925
|
+
let base = layout;
|
|
2926
|
+
if (targetKey === NEW_PAGE_VALUE) {
|
|
2927
|
+
const added = addPage(layout);
|
|
2928
|
+
if (!added.ok) {
|
|
2929
|
+
setPageError(added.error);
|
|
2930
|
+
return;
|
|
2931
|
+
}
|
|
2932
|
+
base = added.value;
|
|
2933
|
+
target = (added.value.pages?.at(-1)).key;
|
|
2934
|
+
}
|
|
2935
|
+
const moved = moveWidgetToPage(
|
|
2936
|
+
definitions,
|
|
2937
|
+
base,
|
|
2938
|
+
widgetKey,
|
|
2939
|
+
target,
|
|
2940
|
+
roomOptions
|
|
2941
|
+
);
|
|
2942
|
+
if (!moved.ok) {
|
|
2943
|
+
setPageError(moved.error);
|
|
2944
|
+
return;
|
|
2945
|
+
}
|
|
2946
|
+
setPageError(void 0);
|
|
2947
|
+
change(moved.value);
|
|
2948
|
+
const destination = moved.value.pages?.find(
|
|
2949
|
+
(page) => page.key === target
|
|
2950
|
+
);
|
|
2951
|
+
setPageAnnouncement(
|
|
2952
|
+
labels.movedToPage(
|
|
2953
|
+
byKey.get(widgetKey)?.definition.title ?? widgetKey,
|
|
2954
|
+
destination?.title ?? target
|
|
2955
|
+
)
|
|
2956
|
+
);
|
|
2957
|
+
}
|
|
2958
|
+
function showAction(widgetKey) {
|
|
2959
|
+
const next = withPageLayout(
|
|
2960
|
+
layout,
|
|
2961
|
+
activeKey,
|
|
2962
|
+
showWidget(view, widgetKey)
|
|
2963
|
+
);
|
|
2964
|
+
if (hasPages(next)) {
|
|
2965
|
+
const room = pageRoom(definitions, next, activeKey, roomOptions);
|
|
2966
|
+
if (room !== void 0 && room.rowsUsed > room.maxRows) {
|
|
2967
|
+
setPageError(labels.pageFull(activePage.title, room.maxRows));
|
|
2968
|
+
return;
|
|
2969
|
+
}
|
|
2970
|
+
}
|
|
2971
|
+
setPageError(void 0);
|
|
2972
|
+
change(next);
|
|
2973
|
+
}
|
|
2273
2974
|
function setEditing(next) {
|
|
2274
2975
|
if (editingProp === void 0) setEditingState(next);
|
|
2275
2976
|
onEditingChange?.(next);
|
|
@@ -2347,176 +3048,312 @@ function DashboardInner({
|
|
|
2347
3048
|
]
|
|
2348
3049
|
}
|
|
2349
3050
|
),
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
]
|
|
2363
|
-
},
|
|
2364
|
-
definition.key
|
|
2365
|
-
))
|
|
2366
|
-
] }),
|
|
2367
|
-
minimized.length > 0 && /* @__PURE__ */ jsxs(
|
|
3051
|
+
paged && /* @__PURE__ */ jsx(
|
|
3052
|
+
PageTabs,
|
|
3053
|
+
{
|
|
3054
|
+
pages,
|
|
3055
|
+
activeKey,
|
|
3056
|
+
idPrefix: instanceId,
|
|
3057
|
+
panelId,
|
|
3058
|
+
announcement: pageAnnouncement,
|
|
3059
|
+
onSelect: selectPage
|
|
3060
|
+
}
|
|
3061
|
+
),
|
|
3062
|
+
controlsShown && /* @__PURE__ */ jsxs(
|
|
2368
3063
|
"div",
|
|
2369
3064
|
{
|
|
2370
|
-
|
|
3065
|
+
role: "group",
|
|
3066
|
+
"aria-label": labels.managePages,
|
|
3067
|
+
className: "dwt-page-manage",
|
|
2371
3068
|
children: [
|
|
2372
|
-
/* @__PURE__ */ jsx(
|
|
2373
|
-
minimized.map((definition) => /* @__PURE__ */ jsxs(
|
|
3069
|
+
/* @__PURE__ */ jsx(
|
|
2374
3070
|
"button",
|
|
2375
3071
|
{
|
|
2376
3072
|
type: "button",
|
|
2377
|
-
className: slot("button", "dwt-button"
|
|
2378
|
-
|
|
2379
|
-
onClick:
|
|
2380
|
-
children:
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
3073
|
+
className: slot("button", "dwt-button"),
|
|
3074
|
+
disabled: maxPages !== void 0 && pages.length >= maxPages,
|
|
3075
|
+
onClick: addPageAction,
|
|
3076
|
+
children: labels.addPage
|
|
3077
|
+
}
|
|
3078
|
+
),
|
|
3079
|
+
paged && editorMode === "rename" && /* @__PURE__ */ jsx(
|
|
3080
|
+
PageRenameForm,
|
|
3081
|
+
{
|
|
3082
|
+
initial: activePage.title,
|
|
3083
|
+
onSubmit: renamePageAction,
|
|
3084
|
+
onCancel: () => setPageEditor(void 0)
|
|
2384
3085
|
},
|
|
2385
|
-
|
|
2386
|
-
)
|
|
3086
|
+
activeKey
|
|
3087
|
+
),
|
|
3088
|
+
paged && editorMode !== "rename" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3089
|
+
/* @__PURE__ */ jsx(
|
|
3090
|
+
"button",
|
|
3091
|
+
{
|
|
3092
|
+
type: "button",
|
|
3093
|
+
className: slot("button", "dwt-button", "dwt-icon-button"),
|
|
3094
|
+
"aria-label": labels.renamePage(activePage.title),
|
|
3095
|
+
title: labels.renamePage(activePage.title),
|
|
3096
|
+
onClick: () => setPageEditor({ mode: "rename", key: activeKey }),
|
|
3097
|
+
children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u270E" })
|
|
3098
|
+
}
|
|
3099
|
+
),
|
|
3100
|
+
/* @__PURE__ */ jsx(
|
|
3101
|
+
"button",
|
|
3102
|
+
{
|
|
3103
|
+
type: "button",
|
|
3104
|
+
className: slot("button", "dwt-button", "dwt-icon-button"),
|
|
3105
|
+
"aria-label": labels.movePageLeft(activePage.title),
|
|
3106
|
+
title: labels.movePageLeft(activePage.title),
|
|
3107
|
+
disabled: pages[0]?.key === activeKey,
|
|
3108
|
+
onClick: () => change(movePage(layout, activeKey, -1)),
|
|
3109
|
+
children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u2190" })
|
|
3110
|
+
}
|
|
3111
|
+
),
|
|
3112
|
+
/* @__PURE__ */ jsx(
|
|
3113
|
+
"button",
|
|
3114
|
+
{
|
|
3115
|
+
type: "button",
|
|
3116
|
+
className: slot("button", "dwt-button", "dwt-icon-button"),
|
|
3117
|
+
"aria-label": labels.movePageRight(activePage.title),
|
|
3118
|
+
title: labels.movePageRight(activePage.title),
|
|
3119
|
+
disabled: pages.at(-1)?.key === activeKey,
|
|
3120
|
+
onClick: () => change(movePage(layout, activeKey, 1)),
|
|
3121
|
+
children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u2192" })
|
|
3122
|
+
}
|
|
3123
|
+
),
|
|
3124
|
+
/* @__PURE__ */ jsx(
|
|
3125
|
+
"button",
|
|
3126
|
+
{
|
|
3127
|
+
type: "button",
|
|
3128
|
+
className: slot("button", "dwt-button", "dwt-icon-button"),
|
|
3129
|
+
"aria-label": labels.deletePage(activePage.title),
|
|
3130
|
+
title: labels.deletePage(activePage.title),
|
|
3131
|
+
onClick: () => setPageEditor({ mode: "delete", key: activeKey }),
|
|
3132
|
+
children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xD7" })
|
|
3133
|
+
}
|
|
3134
|
+
)
|
|
3135
|
+
] }),
|
|
3136
|
+
paged && editorMode === "delete" && /* @__PURE__ */ jsx(
|
|
3137
|
+
InlineConfirm,
|
|
3138
|
+
{
|
|
3139
|
+
message: labels.confirmDeletePage(activePage.title),
|
|
3140
|
+
onAnswer: (yes) => yes ? deletePageAction() : setPageEditor(void 0)
|
|
3141
|
+
}
|
|
3142
|
+
),
|
|
3143
|
+
pageError !== void 0 && /* @__PURE__ */ jsx("span", { role: "alert", className: "dwt-page-error", children: pageError })
|
|
2387
3144
|
]
|
|
2388
3145
|
}
|
|
2389
3146
|
),
|
|
2390
|
-
|
|
2391
|
-
|
|
3147
|
+
/* @__PURE__ */ jsxs(
|
|
3148
|
+
PagePanel,
|
|
2392
3149
|
{
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
const title = definition.title;
|
|
2402
|
-
const lock = resolveWidgetLock(definition);
|
|
2403
|
-
const ownLock = resolveWidgetLock(
|
|
2404
|
-
widget.definition
|
|
2405
|
-
);
|
|
2406
|
-
const isLocked = ownLock.move || ownLock.hide || ownLock.minimize;
|
|
2407
|
-
const lockLabel = overrideLocks ? labels.lockedForViewers(title) : labels.locked(title);
|
|
2408
|
-
const canMoveEarlier = !lock.move && moveWidgetBy(definitions, layout, key, -1) !== layout;
|
|
2409
|
-
const canMoveLater = !lock.move && moveWidgetBy(definitions, layout, key, 1) !== layout;
|
|
2410
|
-
const actions = controlsShown ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2411
|
-
isLocked && /* @__PURE__ */ jsx(
|
|
2412
|
-
"span",
|
|
3150
|
+
paged,
|
|
3151
|
+
id: panelId,
|
|
3152
|
+
labelledBy: `${instanceId}-tab-${pages.findIndex((p) => p.key === activeKey)}`,
|
|
3153
|
+
children: [
|
|
3154
|
+
controlsShown && hidden.length > 0 && /* @__PURE__ */ jsxs("div", { className: slot("hiddenBar", "dwt-hidden-bar"), children: [
|
|
3155
|
+
/* @__PURE__ */ jsx("span", { className: "dwt-hidden-label", children: labels.hiddenWidgets }),
|
|
3156
|
+
hidden.map((definition) => /* @__PURE__ */ jsxs(
|
|
3157
|
+
"button",
|
|
2413
3158
|
{
|
|
2414
|
-
|
|
2415
|
-
className: "dwt-
|
|
2416
|
-
"aria-label":
|
|
2417
|
-
|
|
2418
|
-
children:
|
|
2419
|
-
"
|
|
3159
|
+
type: "button",
|
|
3160
|
+
className: slot("button", "dwt-button", "dwt-show-button"),
|
|
3161
|
+
"aria-label": labels.show(definition.title),
|
|
3162
|
+
onClick: () => showAction(definition.key),
|
|
3163
|
+
children: [
|
|
3164
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "+ " }),
|
|
3165
|
+
definition.title
|
|
3166
|
+
]
|
|
3167
|
+
},
|
|
3168
|
+
definition.key
|
|
3169
|
+
))
|
|
3170
|
+
] }),
|
|
3171
|
+
minimized.length > 0 && /* @__PURE__ */ jsxs(
|
|
3172
|
+
"div",
|
|
3173
|
+
{
|
|
3174
|
+
className: slot("hiddenBar", "dwt-hidden-bar", "dwt-minimized-bar"),
|
|
3175
|
+
children: [
|
|
3176
|
+
/* @__PURE__ */ jsx("span", { className: "dwt-hidden-label", children: labels.minimizedWidgets }),
|
|
3177
|
+
minimized.map((definition) => /* @__PURE__ */ jsxs(
|
|
3178
|
+
"button",
|
|
2420
3179
|
{
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
focusable: "false",
|
|
3180
|
+
type: "button",
|
|
3181
|
+
className: slot("button", "dwt-button", "dwt-show-button"),
|
|
3182
|
+
"aria-label": labels.expand(definition.title),
|
|
3183
|
+
onClick: () => changePage(toggleMinimized(view, definition.key)),
|
|
2426
3184
|
children: [
|
|
2427
|
-
/* @__PURE__ */ jsx(
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
3185
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u25B8 " }),
|
|
3186
|
+
definition.title
|
|
3187
|
+
]
|
|
3188
|
+
},
|
|
3189
|
+
definition.key
|
|
3190
|
+
))
|
|
3191
|
+
]
|
|
3192
|
+
}
|
|
3193
|
+
),
|
|
3194
|
+
visible.length === 0 ? /* @__PURE__ */ jsx("p", { className: slot("empty", "dwt-empty", "dwt-dashboard-empty"), children: paged && pageDefs.length === 0 ? labels.emptyPage : definitions.length === 0 ? labels.noWidgets : labels.allHidden }) : shown.length === 0 ? null : /* @__PURE__ */ jsx(
|
|
3195
|
+
"div",
|
|
3196
|
+
{
|
|
3197
|
+
ref: gridRef,
|
|
3198
|
+
className: slot("grid", "dwt-grid", twelve && "dwt-grid--twelve"),
|
|
3199
|
+
children: shown.map((definition, index) => {
|
|
3200
|
+
const widget = byKey.get(
|
|
3201
|
+
definition.key
|
|
3202
|
+
);
|
|
3203
|
+
if (widget === void 0) return null;
|
|
3204
|
+
const key = definition.key;
|
|
3205
|
+
const title = definition.title;
|
|
3206
|
+
const lock = resolveWidgetLock(definition);
|
|
3207
|
+
const ownLock = resolveWidgetLock(
|
|
3208
|
+
widget.definition
|
|
3209
|
+
);
|
|
3210
|
+
const isLocked = ownLock.move || ownLock.hide || ownLock.minimize;
|
|
3211
|
+
const lockLabel = overrideLocks ? labels.lockedForViewers(title) : labels.locked(title);
|
|
3212
|
+
const canMoveEarlier = !lock.move && moveWidgetBy(pageDefs, view, key, -1) !== view;
|
|
3213
|
+
const canMoveLater = !lock.move && moveWidgetBy(pageDefs, view, key, 1) !== view;
|
|
3214
|
+
const actions = controlsShown ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3215
|
+
isLocked && /* @__PURE__ */ jsx(
|
|
3216
|
+
"span",
|
|
3217
|
+
{
|
|
3218
|
+
role: "img",
|
|
3219
|
+
className: "dwt-lock",
|
|
3220
|
+
"aria-label": lockLabel,
|
|
3221
|
+
title: lockLabel,
|
|
3222
|
+
children: /* @__PURE__ */ jsxs(
|
|
3223
|
+
"svg",
|
|
2440
3224
|
{
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
3225
|
+
viewBox: "0 0 16 16",
|
|
3226
|
+
width: "14",
|
|
3227
|
+
height: "14",
|
|
3228
|
+
"aria-hidden": "true",
|
|
3229
|
+
focusable: "false",
|
|
3230
|
+
children: [
|
|
3231
|
+
/* @__PURE__ */ jsx(
|
|
3232
|
+
"rect",
|
|
3233
|
+
{
|
|
3234
|
+
x: "3",
|
|
3235
|
+
y: "7",
|
|
3236
|
+
width: "10",
|
|
3237
|
+
height: "7",
|
|
3238
|
+
rx: "1.5",
|
|
3239
|
+
fill: "currentColor"
|
|
3240
|
+
}
|
|
3241
|
+
),
|
|
3242
|
+
/* @__PURE__ */ jsx(
|
|
3243
|
+
"path",
|
|
3244
|
+
{
|
|
3245
|
+
d: "M5.5 7V5a2.5 2.5 0 0 1 5 0v2",
|
|
3246
|
+
fill: "none",
|
|
3247
|
+
stroke: "currentColor",
|
|
3248
|
+
strokeWidth: "1.4"
|
|
3249
|
+
}
|
|
3250
|
+
)
|
|
3251
|
+
]
|
|
2445
3252
|
}
|
|
2446
3253
|
)
|
|
2447
|
-
|
|
2448
|
-
}
|
|
2449
|
-
)
|
|
2450
|
-
}
|
|
2451
|
-
),
|
|
2452
|
-
!lock.move && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2453
|
-
/* @__PURE__ */ jsx(
|
|
2454
|
-
"button",
|
|
2455
|
-
{
|
|
2456
|
-
type: "button",
|
|
2457
|
-
className: slot(
|
|
2458
|
-
"button",
|
|
2459
|
-
"dwt-button",
|
|
2460
|
-
"dwt-icon-button"
|
|
3254
|
+
}
|
|
2461
3255
|
),
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
3256
|
+
!lock.move && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3257
|
+
/* @__PURE__ */ jsx(
|
|
3258
|
+
"button",
|
|
3259
|
+
{
|
|
3260
|
+
type: "button",
|
|
3261
|
+
className: slot(
|
|
3262
|
+
"button",
|
|
3263
|
+
"dwt-button",
|
|
3264
|
+
"dwt-icon-button"
|
|
3265
|
+
),
|
|
3266
|
+
"aria-label": labels.moveEarlier(title),
|
|
3267
|
+
title: labels.moveEarlier(title),
|
|
3268
|
+
disabled: index === 0 || !canMoveEarlier,
|
|
3269
|
+
onClick: () => changePage(moveWidgetBy(pageDefs, view, key, -1)),
|
|
3270
|
+
children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u2191" })
|
|
3271
|
+
}
|
|
3272
|
+
),
|
|
3273
|
+
/* @__PURE__ */ jsx(
|
|
3274
|
+
"button",
|
|
3275
|
+
{
|
|
3276
|
+
type: "button",
|
|
3277
|
+
className: slot(
|
|
3278
|
+
"button",
|
|
3279
|
+
"dwt-button",
|
|
3280
|
+
"dwt-icon-button"
|
|
3281
|
+
),
|
|
3282
|
+
"aria-label": labels.moveLater(title),
|
|
3283
|
+
title: labels.moveLater(title),
|
|
3284
|
+
disabled: index === shown.length - 1 || !canMoveLater,
|
|
3285
|
+
onClick: () => changePage(moveWidgetBy(pageDefs, view, key, 1)),
|
|
3286
|
+
children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u2193" })
|
|
3287
|
+
}
|
|
3288
|
+
),
|
|
3289
|
+
paged && /* @__PURE__ */ jsxs(
|
|
3290
|
+
"select",
|
|
3291
|
+
{
|
|
3292
|
+
className: "dwt-move-select",
|
|
3293
|
+
"aria-label": labels.moveToPage(title),
|
|
3294
|
+
value: "",
|
|
3295
|
+
onChange: (event) => {
|
|
3296
|
+
if (event.target.value !== "") {
|
|
3297
|
+
moveWidgetAction(key, event.target.value);
|
|
3298
|
+
}
|
|
3299
|
+
},
|
|
3300
|
+
children: [
|
|
3301
|
+
/* @__PURE__ */ jsx("option", { value: "", children: labels.moveToPagePlaceholder }),
|
|
3302
|
+
pages.filter((page) => page.key !== activeKey).map((page) => /* @__PURE__ */ jsx("option", { value: page.key, children: labels.moveToPageOption(
|
|
3303
|
+
page.title,
|
|
3304
|
+
pageRoom(
|
|
3305
|
+
definitions,
|
|
3306
|
+
layout,
|
|
3307
|
+
page.key,
|
|
3308
|
+
roomOptions
|
|
3309
|
+
)?.rowsFree ?? 0
|
|
3310
|
+
) }, page.key)),
|
|
3311
|
+
(maxPages === void 0 || pages.length < maxPages) && /* @__PURE__ */ jsx("option", { value: NEW_PAGE_VALUE, children: labels.newPageOption })
|
|
3312
|
+
]
|
|
3313
|
+
}
|
|
3314
|
+
)
|
|
3315
|
+
] }),
|
|
3316
|
+
!lock.hide && /* @__PURE__ */ jsx(
|
|
2474
3317
|
"button",
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
...headingLevel === void 0 ? {} : { headingLevel },
|
|
2515
|
-
...onRetry === void 0 || widget.status !== "error" ? {} : { onRetry: () => onRetry(key) }
|
|
2516
|
-
},
|
|
2517
|
-
key
|
|
2518
|
-
);
|
|
2519
|
-
})
|
|
3318
|
+
{
|
|
3319
|
+
type: "button",
|
|
3320
|
+
className: slot(
|
|
3321
|
+
"button",
|
|
3322
|
+
"dwt-button",
|
|
3323
|
+
"dwt-icon-button"
|
|
3324
|
+
),
|
|
3325
|
+
"aria-label": labels.hide(title),
|
|
3326
|
+
title: labels.hide(title),
|
|
3327
|
+
onClick: () => changePage(hideWidget(view, key)),
|
|
3328
|
+
children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xD7" })
|
|
3329
|
+
}
|
|
3330
|
+
)
|
|
3331
|
+
] }) : void 0;
|
|
3332
|
+
const viewable = resolveDetailOptions(definition) !== void 0 && (onOpenDetail !== void 0 || loadDetail !== void 0 || widget.status === "ok" && deriveDetailData(widget.data) !== void 0);
|
|
3333
|
+
return /* @__PURE__ */ jsx(
|
|
3334
|
+
ResolvedWidgetCard,
|
|
3335
|
+
{
|
|
3336
|
+
widget,
|
|
3337
|
+
...viewable ? {
|
|
3338
|
+
onView: () => onOpenDetail === void 0 ? setDetailKey(key) : onOpenDetail(key)
|
|
3339
|
+
} : {},
|
|
3340
|
+
...spanProps(spans, key),
|
|
3341
|
+
...widthProps(twelve, definition),
|
|
3342
|
+
minimized: isMinimized(view, key),
|
|
3343
|
+
editing: toggleMode && controlsShown,
|
|
3344
|
+
...actions === void 0 ? {} : { actions },
|
|
3345
|
+
...editable && !lock.minimize ? {
|
|
3346
|
+
onToggleMinimized: () => changePage(toggleMinimized(view, key))
|
|
3347
|
+
} : {},
|
|
3348
|
+
...headingLevel === void 0 ? {} : { headingLevel },
|
|
3349
|
+
...onRetry === void 0 || widget.status !== "error" ? {} : { onRetry: () => onRetry(key) }
|
|
3350
|
+
},
|
|
3351
|
+
key
|
|
3352
|
+
);
|
|
3353
|
+
})
|
|
3354
|
+
}
|
|
3355
|
+
)
|
|
3356
|
+
]
|
|
2520
3357
|
}
|
|
2521
3358
|
),
|
|
2522
3359
|
detailKey !== void 0 && byKey.get(detailKey) !== void 0 && /* @__PURE__ */ jsx(
|
|
@@ -3175,8 +4012,21 @@ function useWidgets(definitions, providers, context, options = {}) {
|
|
|
3175
4012
|
},
|
|
3176
4013
|
{ rootMargin }
|
|
3177
4014
|
);
|
|
3178
|
-
|
|
3179
|
-
|
|
4015
|
+
const observed = /* @__PURE__ */ new WeakSet();
|
|
4016
|
+
const observeNewCards = () => {
|
|
4017
|
+
grid.querySelectorAll("[data-widget-key]").forEach((card) => {
|
|
4018
|
+
if (observed.has(card)) return;
|
|
4019
|
+
observed.add(card);
|
|
4020
|
+
observer.observe(card);
|
|
4021
|
+
});
|
|
4022
|
+
};
|
|
4023
|
+
observeNewCards();
|
|
4024
|
+
const mutations = typeof MutationObserver === "undefined" ? void 0 : new MutationObserver(observeNewCards);
|
|
4025
|
+
mutations?.observe(grid, { childList: true, subtree: true });
|
|
4026
|
+
return () => {
|
|
4027
|
+
mutations?.disconnect();
|
|
4028
|
+
observer.disconnect();
|
|
4029
|
+
};
|
|
3180
4030
|
}, [loader, loadWhen, rootMargin, cardKeys]);
|
|
3181
4031
|
useEffect(() => {
|
|
3182
4032
|
if (loader === null || !(refreshMs > 0)) return void 0;
|