@richardmcquiston01/dashboard-widgets-toolkit 0.13.0 → 0.14.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 +713 -383
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +2 -2
- package/dist/core.d.ts +2 -2
- package/dist/core.js +697 -384
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +713 -383
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +697 -384
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +836 -60
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +53 -4
- package/dist/react.d.ts +53 -4
- package/dist/react.js +836 -61
- package/dist/react.js.map +1 -1
- package/dist/{storage-DNB7gjvT.d.cts → storage-_Eb8Y98-.d.cts} +144 -3
- package/dist/{storage-DNB7gjvT.d.ts → storage-_Eb8Y98-.d.ts} +144 -3
- package/dist/styles.css +146 -0
- package/package.json +1 -1
package/dist/core.js
CHANGED
|
@@ -87,12 +87,14 @@ var WIDGET_FILLS = ["height", "width", "both"];
|
|
|
87
87
|
var NOT_LOCKED = Object.freeze({
|
|
88
88
|
move: false,
|
|
89
89
|
hide: false,
|
|
90
|
-
minimize: false
|
|
90
|
+
minimize: false,
|
|
91
|
+
options: false
|
|
91
92
|
});
|
|
92
93
|
var FULLY_LOCKED = Object.freeze({
|
|
93
94
|
move: true,
|
|
94
95
|
hide: true,
|
|
95
|
-
minimize: true
|
|
96
|
+
minimize: true,
|
|
97
|
+
options: true
|
|
96
98
|
});
|
|
97
99
|
function resolveWidgetLock(definition) {
|
|
98
100
|
const setting = definition.locked;
|
|
@@ -101,7 +103,8 @@ function resolveWidgetLock(definition) {
|
|
|
101
103
|
return {
|
|
102
104
|
move: setting.move === true,
|
|
103
105
|
hide: setting.hide === true,
|
|
104
|
-
minimize: setting.minimize === true
|
|
106
|
+
minimize: setting.minimize === true,
|
|
107
|
+
options: setting.options === true
|
|
105
108
|
};
|
|
106
109
|
}
|
|
107
110
|
function defineWidget(definition) {
|
|
@@ -683,6 +686,546 @@ function placeAndFillRows(items, columns, spanOf) {
|
|
|
683
686
|
return { spans, rows };
|
|
684
687
|
}
|
|
685
688
|
|
|
689
|
+
// src/core/options.ts
|
|
690
|
+
var DATE_RANGE_PRESETS = [
|
|
691
|
+
"today",
|
|
692
|
+
"yesterday",
|
|
693
|
+
"last7",
|
|
694
|
+
"last30",
|
|
695
|
+
"last90",
|
|
696
|
+
"thisMonth",
|
|
697
|
+
"lastMonth",
|
|
698
|
+
"thisYear",
|
|
699
|
+
"lastYear"
|
|
700
|
+
];
|
|
701
|
+
var WIDGET_OPTION_TYPES = [
|
|
702
|
+
"choice",
|
|
703
|
+
"number",
|
|
704
|
+
"boolean",
|
|
705
|
+
"text",
|
|
706
|
+
"dateRange",
|
|
707
|
+
"color",
|
|
708
|
+
"sort",
|
|
709
|
+
"columns"
|
|
710
|
+
];
|
|
711
|
+
var MAX_WIDGET_OPTIONS = 20;
|
|
712
|
+
var MAX_TEXT_OPTION_LENGTH = 500;
|
|
713
|
+
var OPTION_KEY_PATTERN = /^[A-Za-z][A-Za-z0-9_-]{0,39}$/;
|
|
714
|
+
var COLOR_PATTERN = /^#[0-9a-fA-F]{6}$/;
|
|
715
|
+
var INTERVAL_PATTERN = /^(\d{4}-\d{2}-\d{2})\/(\d{4}-\d{2}-\d{2})$/;
|
|
716
|
+
var CONTROL_CHARACTERS = /[\u0000-\u001f\u007f]/;
|
|
717
|
+
function isColumnKeyFor(kind, key) {
|
|
718
|
+
if (kind === "TABLE") return /^c\d+$/.test(key);
|
|
719
|
+
if (kind === "BAR_LIST") return key === "label" || key === "value";
|
|
720
|
+
return false;
|
|
721
|
+
}
|
|
722
|
+
function isClientApplied(option) {
|
|
723
|
+
return (option.type === "sort" || option.type === "columns") && option.apply === "client";
|
|
724
|
+
}
|
|
725
|
+
function civilToday(context) {
|
|
726
|
+
const now = context.now ?? Date.now();
|
|
727
|
+
let timeZone = context.timeZone ?? "UTC";
|
|
728
|
+
try {
|
|
729
|
+
new Intl.DateTimeFormat("en-US", { timeZone });
|
|
730
|
+
} catch {
|
|
731
|
+
timeZone = "UTC";
|
|
732
|
+
}
|
|
733
|
+
const parts = new Intl.DateTimeFormat("en-US", {
|
|
734
|
+
timeZone,
|
|
735
|
+
year: "numeric",
|
|
736
|
+
month: "2-digit",
|
|
737
|
+
day: "2-digit"
|
|
738
|
+
}).formatToParts(new Date(now));
|
|
739
|
+
const pick = (type) => Number(parts.find((part) => part.type === type)?.value ?? "0");
|
|
740
|
+
return { year: pick("year"), month: pick("month"), day: pick("day") };
|
|
741
|
+
}
|
|
742
|
+
function toIso(epochMs) {
|
|
743
|
+
return new Date(epochMs).toISOString().slice(0, 10);
|
|
744
|
+
}
|
|
745
|
+
var DAY_MS = 864e5;
|
|
746
|
+
function parseIsoDay(text) {
|
|
747
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(text);
|
|
748
|
+
if (match === null) return void 0;
|
|
749
|
+
const epoch = Date.UTC(
|
|
750
|
+
Number(match[1]),
|
|
751
|
+
Number(match[2]) - 1,
|
|
752
|
+
Number(match[3])
|
|
753
|
+
);
|
|
754
|
+
return toIso(epoch) === text ? epoch : void 0;
|
|
755
|
+
}
|
|
756
|
+
function isIsoInterval(value) {
|
|
757
|
+
const match = INTERVAL_PATTERN.exec(value);
|
|
758
|
+
if (match === null) return false;
|
|
759
|
+
const start = parseIsoDay(match[1]);
|
|
760
|
+
const end = parseIsoDay(match[2]);
|
|
761
|
+
return start !== void 0 && end !== void 0 && start <= end;
|
|
762
|
+
}
|
|
763
|
+
function isPreset(value) {
|
|
764
|
+
return DATE_RANGE_PRESETS.includes(value);
|
|
765
|
+
}
|
|
766
|
+
function resolveDateRange(value, context = {}) {
|
|
767
|
+
if (isIsoInterval(value)) return value;
|
|
768
|
+
if (!isPreset(value)) return void 0;
|
|
769
|
+
const today = civilToday(context);
|
|
770
|
+
const todayMs = Date.UTC(today.year, today.month - 1, today.day);
|
|
771
|
+
const range = (startMs, endMs) => `${toIso(startMs)}/${toIso(endMs)}`;
|
|
772
|
+
switch (value) {
|
|
773
|
+
case "today":
|
|
774
|
+
return range(todayMs, todayMs);
|
|
775
|
+
case "yesterday":
|
|
776
|
+
return range(todayMs - DAY_MS, todayMs - DAY_MS);
|
|
777
|
+
case "last7":
|
|
778
|
+
return range(todayMs - 6 * DAY_MS, todayMs);
|
|
779
|
+
case "last30":
|
|
780
|
+
return range(todayMs - 29 * DAY_MS, todayMs);
|
|
781
|
+
case "last90":
|
|
782
|
+
return range(todayMs - 89 * DAY_MS, todayMs);
|
|
783
|
+
case "thisMonth":
|
|
784
|
+
return range(Date.UTC(today.year, today.month - 1, 1), todayMs);
|
|
785
|
+
case "lastMonth":
|
|
786
|
+
return range(
|
|
787
|
+
Date.UTC(today.year, today.month - 2, 1),
|
|
788
|
+
Date.UTC(today.year, today.month - 1, 1) - DAY_MS
|
|
789
|
+
);
|
|
790
|
+
case "thisYear":
|
|
791
|
+
return range(Date.UTC(today.year, 0, 1), todayMs);
|
|
792
|
+
case "lastYear":
|
|
793
|
+
return range(
|
|
794
|
+
Date.UTC(today.year - 1, 0, 1),
|
|
795
|
+
Date.UTC(today.year, 0, 1) - DAY_MS
|
|
796
|
+
);
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
function onStepGrid(option, value) {
|
|
800
|
+
if (option.step === void 0) return true;
|
|
801
|
+
const steps = (value - option.min) / option.step;
|
|
802
|
+
return Math.abs(steps - Math.round(steps)) < 1e-9;
|
|
803
|
+
}
|
|
804
|
+
function parseSortValue(value) {
|
|
805
|
+
const separator = value.lastIndexOf(":");
|
|
806
|
+
if (separator <= 0) return void 0;
|
|
807
|
+
const column = value.slice(0, separator);
|
|
808
|
+
const direction = value.slice(separator + 1);
|
|
809
|
+
if (direction !== "asc" && direction !== "desc") return void 0;
|
|
810
|
+
return { column, direction };
|
|
811
|
+
}
|
|
812
|
+
function sortFromOptions(definition, values) {
|
|
813
|
+
if (values === void 0) return void 0;
|
|
814
|
+
const sortOption = definition.options?.find(
|
|
815
|
+
(option) => option.type === "sort"
|
|
816
|
+
);
|
|
817
|
+
if (sortOption === void 0) return void 0;
|
|
818
|
+
const chosen = values[sortOption.key];
|
|
819
|
+
return typeof chosen === "string" ? parseSortValue(chosen) : void 0;
|
|
820
|
+
}
|
|
821
|
+
function coerceOptionValue(option, value, context = {}) {
|
|
822
|
+
switch (option.type) {
|
|
823
|
+
case "choice":
|
|
824
|
+
return typeof value === "string" && option.choices.some((choice) => choice.value === value) ? value : void 0;
|
|
825
|
+
case "number":
|
|
826
|
+
return typeof value === "number" && Number.isFinite(value) && value >= option.min && value <= option.max && onStepGrid(option, value) ? value : void 0;
|
|
827
|
+
case "boolean":
|
|
828
|
+
return typeof value === "boolean" ? value : void 0;
|
|
829
|
+
case "text": {
|
|
830
|
+
if (typeof value !== "string") return void 0;
|
|
831
|
+
const trimmed = value.trim();
|
|
832
|
+
return trimmed.length <= option.maxLength && !CONTROL_CHARACTERS.test(trimmed) ? trimmed : void 0;
|
|
833
|
+
}
|
|
834
|
+
case "dateRange": {
|
|
835
|
+
if (typeof value !== "string") return void 0;
|
|
836
|
+
if (isPreset(value) && option.presets !== void 0 && !option.presets.some((preset) => preset.value === value)) {
|
|
837
|
+
return void 0;
|
|
838
|
+
}
|
|
839
|
+
return resolveDateRange(value, context);
|
|
840
|
+
}
|
|
841
|
+
case "color":
|
|
842
|
+
return typeof value === "string" && COLOR_PATTERN.test(value) ? value.toLowerCase() : void 0;
|
|
843
|
+
case "sort": {
|
|
844
|
+
if (typeof value !== "string") return void 0;
|
|
845
|
+
const sort = parseSortValue(value);
|
|
846
|
+
return sort !== void 0 && option.columns.some((column) => column.key === sort.column) ? value : void 0;
|
|
847
|
+
}
|
|
848
|
+
case "columns": {
|
|
849
|
+
if (!Array.isArray(value) || value.length === 0) return void 0;
|
|
850
|
+
const keys = value;
|
|
851
|
+
const allowed = new Set(option.columns.map((c) => c.key));
|
|
852
|
+
const seen = /* @__PURE__ */ new Set();
|
|
853
|
+
for (const key of keys) {
|
|
854
|
+
if (typeof key !== "string" || !allowed.has(key) || seen.has(key)) {
|
|
855
|
+
return void 0;
|
|
856
|
+
}
|
|
857
|
+
seen.add(key);
|
|
858
|
+
}
|
|
859
|
+
return [...seen];
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
function defaultOptionValue(option, context = {}) {
|
|
864
|
+
switch (option.type) {
|
|
865
|
+
case "dateRange":
|
|
866
|
+
return resolveDateRange(option.default, context);
|
|
867
|
+
case "sort":
|
|
868
|
+
return option.default;
|
|
869
|
+
case "columns":
|
|
870
|
+
return [...option.default];
|
|
871
|
+
default:
|
|
872
|
+
return option.default;
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
var NO_VALUES = Object.freeze({});
|
|
876
|
+
function resolveOptionValues(definition, chosen, context = {}) {
|
|
877
|
+
const options = definition.options;
|
|
878
|
+
if (options === void 0 || options.length === 0) return NO_VALUES;
|
|
879
|
+
const values = {};
|
|
880
|
+
for (const option of options) {
|
|
881
|
+
const picked = chosen?.[option.key];
|
|
882
|
+
const value = (picked === void 0 ? void 0 : coerceOptionValue(option, picked, context)) ?? defaultOptionValue(option, context);
|
|
883
|
+
if (value !== void 0) values[option.key] = value;
|
|
884
|
+
}
|
|
885
|
+
return values;
|
|
886
|
+
}
|
|
887
|
+
function sameValue(a, b) {
|
|
888
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
889
|
+
return a.length === b.length && a.every((item, i) => item === b[i]);
|
|
890
|
+
}
|
|
891
|
+
return a === b;
|
|
892
|
+
}
|
|
893
|
+
function sameOptionValues(a, b) {
|
|
894
|
+
const keys = Object.keys({ ...a, ...b });
|
|
895
|
+
return keys.every((key) => sameValue(a[key], b[key]));
|
|
896
|
+
}
|
|
897
|
+
function optionsCacheSuffix(definition, values, context = {}) {
|
|
898
|
+
const parts = [];
|
|
899
|
+
for (const option of definition.options ?? []) {
|
|
900
|
+
if (isClientApplied(option)) continue;
|
|
901
|
+
const value = values[option.key];
|
|
902
|
+
if (sameValue(value, defaultOptionValue(option, context))) continue;
|
|
903
|
+
parts.push(
|
|
904
|
+
`${option.key}=${encodeURIComponent(JSON.stringify(value ?? null))}`
|
|
905
|
+
);
|
|
906
|
+
}
|
|
907
|
+
parts.sort();
|
|
908
|
+
return parts.length === 0 ? "" : `?${parts.join("&")}`;
|
|
909
|
+
}
|
|
910
|
+
function tableColumnIndex(key) {
|
|
911
|
+
const match = /^c(\d+)$/.exec(key);
|
|
912
|
+
return match === null ? void 0 : Number(match[1]);
|
|
913
|
+
}
|
|
914
|
+
function sortBarItems(items, sort) {
|
|
915
|
+
const sign = sort.direction === "desc" ? -1 : 1;
|
|
916
|
+
return items.map((item, index) => ({ item, index })).sort((a, b) => {
|
|
917
|
+
const order = sort.column === "value" ? a.item.value - b.item.value : a.item.label.localeCompare(b.item.label);
|
|
918
|
+
return order * sign || a.index - b.index;
|
|
919
|
+
}).map(({ item }) => item);
|
|
920
|
+
}
|
|
921
|
+
function applyClientOptions(definition, data, values) {
|
|
922
|
+
const options = definition.options ?? [];
|
|
923
|
+
const sortOption = options.find(
|
|
924
|
+
(o) => o.type === "sort" && o.apply === "client"
|
|
925
|
+
);
|
|
926
|
+
const columnsOption = options.find(
|
|
927
|
+
(o) => o.type === "columns" && o.apply === "client"
|
|
928
|
+
);
|
|
929
|
+
const sortValue = sortOption === void 0 ? void 0 : values[sortOption.key];
|
|
930
|
+
const columnsValue = columnsOption === void 0 ? void 0 : values[columnsOption.key];
|
|
931
|
+
let next = data;
|
|
932
|
+
if (typeof sortValue === "string") {
|
|
933
|
+
const sort = parseSortValue(sortValue);
|
|
934
|
+
if (sort !== void 0 && next.kind === "BAR_LIST") {
|
|
935
|
+
if (sort.column === "label" || sort.column === "value") {
|
|
936
|
+
next = { ...next, items: sortBarItems(next.items, sort) };
|
|
937
|
+
}
|
|
938
|
+
} else if (sort !== void 0 && next.kind === "TABLE") {
|
|
939
|
+
const index = tableColumnIndex(sort.column);
|
|
940
|
+
if (index !== void 0 && index < next.columns.length) {
|
|
941
|
+
const sorted = queryRows(tableDetailData(next), {
|
|
942
|
+
page: 1,
|
|
943
|
+
pageSize: Math.max(1, next.rows.length),
|
|
944
|
+
sort
|
|
945
|
+
});
|
|
946
|
+
if (sorted.ok) next = { ...next, rows: sorted.value.rows };
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
if (Array.isArray(columnsValue) && next.kind === "TABLE") {
|
|
951
|
+
const table = next;
|
|
952
|
+
const indexes = columnsValue.map(tableColumnIndex).filter(
|
|
953
|
+
(index) => index !== void 0 && index < table.columns.length
|
|
954
|
+
);
|
|
955
|
+
if (indexes.length > 0) {
|
|
956
|
+
next = {
|
|
957
|
+
...table,
|
|
958
|
+
columns: indexes.map((i) => table.columns[i]),
|
|
959
|
+
rows: table.rows.map((row) => indexes.map((i) => row[i]))
|
|
960
|
+
};
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
return next;
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
// src/core/settings.ts
|
|
967
|
+
var MAX_WIDGET_TITLE_LENGTH = 80;
|
|
968
|
+
var MAX_PARSED_SETTINGS = 500;
|
|
969
|
+
var MAX_COLUMN_LIST = 100;
|
|
970
|
+
var MAX_VALUE_LENGTH = 500;
|
|
971
|
+
function isRecord(value) {
|
|
972
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
973
|
+
}
|
|
974
|
+
function parseOptionValue(value) {
|
|
975
|
+
if (typeof value === "string") {
|
|
976
|
+
return value.length <= MAX_VALUE_LENGTH ? value : void 0;
|
|
977
|
+
}
|
|
978
|
+
if (typeof value === "number")
|
|
979
|
+
return Number.isFinite(value) ? value : void 0;
|
|
980
|
+
if (typeof value === "boolean") return value;
|
|
981
|
+
if (Array.isArray(value) && value.length <= MAX_COLUMN_LIST) {
|
|
982
|
+
return value.every(
|
|
983
|
+
(entry) => typeof entry === "string" && entry.length <= MAX_VALUE_LENGTH
|
|
984
|
+
) ? value : void 0;
|
|
985
|
+
}
|
|
986
|
+
return void 0;
|
|
987
|
+
}
|
|
988
|
+
function parseOne(raw) {
|
|
989
|
+
if (!isRecord(raw)) return void 0;
|
|
990
|
+
const title = raw["title"];
|
|
991
|
+
const width = raw["width"];
|
|
992
|
+
const flexible = raw["flexible"];
|
|
993
|
+
const options = raw["options"];
|
|
994
|
+
const cleanTitle = typeof title === "string" ? title.trim().slice(0, MAX_WIDGET_TITLE_LENGTH) : "";
|
|
995
|
+
const chosen = {};
|
|
996
|
+
if (isRecord(options)) {
|
|
997
|
+
for (const [key, value] of Object.entries(options)) {
|
|
998
|
+
const parsed = parseOptionValue(value);
|
|
999
|
+
if (parsed !== void 0) chosen[key] = parsed;
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
const settings = {
|
|
1003
|
+
...cleanTitle === "" ? {} : { title: cleanTitle },
|
|
1004
|
+
...isWidgetWidth(width) ? { width } : {},
|
|
1005
|
+
...typeof flexible === "boolean" ? { flexible } : {},
|
|
1006
|
+
...Object.keys(chosen).length === 0 ? {} : { options: chosen }
|
|
1007
|
+
};
|
|
1008
|
+
return Object.keys(settings).length === 0 ? void 0 : settings;
|
|
1009
|
+
}
|
|
1010
|
+
function parseSettings(raw) {
|
|
1011
|
+
if (!isRecord(raw)) return void 0;
|
|
1012
|
+
const parsed = {};
|
|
1013
|
+
for (const [key, value] of Object.entries(raw).slice(
|
|
1014
|
+
0,
|
|
1015
|
+
MAX_PARSED_SETTINGS
|
|
1016
|
+
)) {
|
|
1017
|
+
if (key === "") continue;
|
|
1018
|
+
const one = parseOne(value);
|
|
1019
|
+
if (one !== void 0) parsed[key] = one;
|
|
1020
|
+
}
|
|
1021
|
+
return Object.keys(parsed).length === 0 ? void 0 : parsed;
|
|
1022
|
+
}
|
|
1023
|
+
function serializeSettings(settings) {
|
|
1024
|
+
if (settings === void 0) return void 0;
|
|
1025
|
+
const out = {};
|
|
1026
|
+
for (const key of Object.keys(settings)) {
|
|
1027
|
+
const one = settings[key];
|
|
1028
|
+
if (one === void 0) continue;
|
|
1029
|
+
const piece = {
|
|
1030
|
+
...one.title === void 0 ? {} : { title: one.title },
|
|
1031
|
+
...one.width === void 0 ? {} : { width: one.width },
|
|
1032
|
+
...one.flexible === void 0 ? {} : { flexible: one.flexible },
|
|
1033
|
+
...one.options === void 0 || Object.keys(one.options).length === 0 ? {} : { options: { ...one.options } }
|
|
1034
|
+
};
|
|
1035
|
+
if (Object.keys(piece).length > 0) out[key] = piece;
|
|
1036
|
+
}
|
|
1037
|
+
return Object.keys(out).length === 0 ? void 0 : out;
|
|
1038
|
+
}
|
|
1039
|
+
function widthRange(item) {
|
|
1040
|
+
const min = isWidgetWidth(item.minWidth) ? item.minWidth : MIN_WIDGET_WIDTH;
|
|
1041
|
+
const max = isWidgetWidth(item.maxWidth) ? item.maxWidth : MAX_WIDGET_WIDTH;
|
|
1042
|
+
return { min, max: Math.max(min, max) };
|
|
1043
|
+
}
|
|
1044
|
+
var WIDTH_SHARES = {
|
|
1045
|
+
2: "1/6",
|
|
1046
|
+
3: "1/4",
|
|
1047
|
+
4: "1/3",
|
|
1048
|
+
5: "5/12",
|
|
1049
|
+
6: "1/2",
|
|
1050
|
+
7: "7/12",
|
|
1051
|
+
8: "2/3",
|
|
1052
|
+
9: "3/4",
|
|
1053
|
+
10: "5/6",
|
|
1054
|
+
11: "11/12",
|
|
1055
|
+
12: "Full"
|
|
1056
|
+
};
|
|
1057
|
+
function widthShareLabel(width) {
|
|
1058
|
+
return WIDTH_SHARES[width] ?? `${width}/12`;
|
|
1059
|
+
}
|
|
1060
|
+
function isOptionsLocked(item) {
|
|
1061
|
+
return resolveWidgetLock(item).options;
|
|
1062
|
+
}
|
|
1063
|
+
function fillWith(fill, flexible) {
|
|
1064
|
+
const heightToo = fill === "height" || fill === "both";
|
|
1065
|
+
if (flexible) return heightToo ? "both" : "width";
|
|
1066
|
+
return heightToo ? "height" : void 0;
|
|
1067
|
+
}
|
|
1068
|
+
function isFlexible(item, settings) {
|
|
1069
|
+
if (settings?.flexible !== void 0) return settings.flexible;
|
|
1070
|
+
return item.fill === "width" || item.fill === "both";
|
|
1071
|
+
}
|
|
1072
|
+
function applySettings(definition, settings) {
|
|
1073
|
+
if (settings === void 0) return definition;
|
|
1074
|
+
const range = widthRange(definition);
|
|
1075
|
+
const width = settings.width === void 0 ? void 0 : Math.min(range.max, Math.max(range.min, settings.width));
|
|
1076
|
+
const title = settings.title === void 0 || settings.title.trim() === "" ? void 0 : settings.title;
|
|
1077
|
+
const flexibleChanged = settings.flexible !== void 0 && settings.flexible !== isFlexible(definition, void 0);
|
|
1078
|
+
if (title === void 0 && width === void 0 && !flexibleChanged) {
|
|
1079
|
+
return definition;
|
|
1080
|
+
}
|
|
1081
|
+
const next = { ...definition };
|
|
1082
|
+
if (title !== void 0) next.title = title;
|
|
1083
|
+
if (width !== void 0) next.width = width;
|
|
1084
|
+
if (flexibleChanged) {
|
|
1085
|
+
const fill = fillWith(
|
|
1086
|
+
definition.fill,
|
|
1087
|
+
settings.flexible === true
|
|
1088
|
+
);
|
|
1089
|
+
if (fill === void 0) {
|
|
1090
|
+
delete next.fill;
|
|
1091
|
+
} else {
|
|
1092
|
+
next.fill = fill;
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
return next;
|
|
1096
|
+
}
|
|
1097
|
+
function effectiveDefinitions(definitions, layout, options = {}) {
|
|
1098
|
+
return definitions.map(
|
|
1099
|
+
(definition) => options.overrideLocks !== true && isOptionsLocked(definition) ? definition : applySettings(definition, layout.settings?.[definition.key])
|
|
1100
|
+
);
|
|
1101
|
+
}
|
|
1102
|
+
function widgetOptionValues(definition, settings) {
|
|
1103
|
+
const declared = definition.options ?? [];
|
|
1104
|
+
const values = {};
|
|
1105
|
+
for (const option of declared) {
|
|
1106
|
+
const picked = settings?.options?.[option.key];
|
|
1107
|
+
const value = (picked === void 0 ? void 0 : coerceOptionValue(option, picked)) ?? defaultOptionValue(option);
|
|
1108
|
+
if (value !== void 0) values[option.key] = value;
|
|
1109
|
+
}
|
|
1110
|
+
return values;
|
|
1111
|
+
}
|
|
1112
|
+
function optionValuesFromLayout(definitions, layout, options = {}) {
|
|
1113
|
+
const out = {};
|
|
1114
|
+
for (const definition of definitions) {
|
|
1115
|
+
if (definition.options === void 0 || definition.options.length === 0) {
|
|
1116
|
+
continue;
|
|
1117
|
+
}
|
|
1118
|
+
const locked = options.overrideLocks !== true && isOptionsLocked(definition);
|
|
1119
|
+
out[definition.key] = locked ? {} : layout.settings?.[definition.key]?.options ?? {};
|
|
1120
|
+
}
|
|
1121
|
+
return out;
|
|
1122
|
+
}
|
|
1123
|
+
function sameSettings(a, b) {
|
|
1124
|
+
if (a === b) return true;
|
|
1125
|
+
return a?.title === b?.title && a?.width === b?.width && a?.flexible === b?.flexible && sameOptionValues(a?.options ?? {}, b?.options ?? {});
|
|
1126
|
+
}
|
|
1127
|
+
function setWidgetSettings(layout, key, patch) {
|
|
1128
|
+
const before = layout.settings?.[key];
|
|
1129
|
+
const draft = { ...before };
|
|
1130
|
+
for (const field of ["title", "width", "flexible", "options"]) {
|
|
1131
|
+
if (!(field in patch)) continue;
|
|
1132
|
+
const value = patch[field];
|
|
1133
|
+
if (value === void 0) {
|
|
1134
|
+
delete draft[field];
|
|
1135
|
+
} else {
|
|
1136
|
+
draft[field] = value;
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
const merged = parseOne(draft);
|
|
1140
|
+
if (sameSettings(before, merged)) return layout;
|
|
1141
|
+
const rest = { ...layout.settings };
|
|
1142
|
+
if (merged === void 0) {
|
|
1143
|
+
delete rest[key];
|
|
1144
|
+
} else {
|
|
1145
|
+
rest[key] = merged;
|
|
1146
|
+
}
|
|
1147
|
+
const { settings: _previous, ...others } = layout;
|
|
1148
|
+
return Object.keys(rest).length === 0 ? others : { ...others, settings: rest };
|
|
1149
|
+
}
|
|
1150
|
+
function clearWidgetSettings(layout, key) {
|
|
1151
|
+
if (layout.settings?.[key] === void 0) return layout;
|
|
1152
|
+
return setWidgetSettings(layout, key, {
|
|
1153
|
+
title: void 0,
|
|
1154
|
+
width: void 0,
|
|
1155
|
+
flexible: void 0,
|
|
1156
|
+
options: void 0
|
|
1157
|
+
});
|
|
1158
|
+
}
|
|
1159
|
+
function normalizeTitle(title) {
|
|
1160
|
+
return title.normalize("NFKC").trim().toLowerCase();
|
|
1161
|
+
}
|
|
1162
|
+
function isTitleInUse(definitions, layout, key, title) {
|
|
1163
|
+
const wanted = normalizeTitle(title);
|
|
1164
|
+
if (wanted === "") return false;
|
|
1165
|
+
return effectiveDefinitions(definitions, layout, {
|
|
1166
|
+
overrideLocks: true
|
|
1167
|
+
}).some(
|
|
1168
|
+
(other) => other.key !== key && normalizeTitle(other.title ?? other.key) === wanted
|
|
1169
|
+
);
|
|
1170
|
+
}
|
|
1171
|
+
function uniqueTitle(taken, title) {
|
|
1172
|
+
if (!taken.has(normalizeTitle(title))) return title;
|
|
1173
|
+
for (let n = 2; ; n += 1) {
|
|
1174
|
+
const suffix = ` (#${n})`;
|
|
1175
|
+
const candidate = `${title.slice(0, MAX_WIDGET_TITLE_LENGTH - suffix.length)}${suffix}`;
|
|
1176
|
+
if (!taken.has(normalizeTitle(candidate))) return candidate;
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
function normalizeSettings(definitions, layout, options = {}) {
|
|
1180
|
+
const settings = layout.settings;
|
|
1181
|
+
if (settings === void 0) return layout;
|
|
1182
|
+
const cleaned = {};
|
|
1183
|
+
const taken = /* @__PURE__ */ new Set();
|
|
1184
|
+
for (const definition of definitions) {
|
|
1185
|
+
const renamed = settings[definition.key]?.title !== void 0 && (options.overrideLocks === true || !isOptionsLocked(definition));
|
|
1186
|
+
if (!renamed) taken.add(normalizeTitle(definition.title ?? definition.key));
|
|
1187
|
+
}
|
|
1188
|
+
for (const definition of definitions) {
|
|
1189
|
+
const one = settings[definition.key];
|
|
1190
|
+
if (one === void 0) continue;
|
|
1191
|
+
if (options.overrideLocks !== true && isOptionsLocked(definition)) continue;
|
|
1192
|
+
const range = widthRange(definition);
|
|
1193
|
+
const chosen = {};
|
|
1194
|
+
for (const option of definition.options ?? []) {
|
|
1195
|
+
const picked = one.options?.[option.key];
|
|
1196
|
+
if (picked === void 0) continue;
|
|
1197
|
+
const value = coerceOptionValue(option, picked);
|
|
1198
|
+
if (value !== void 0) {
|
|
1199
|
+
chosen[option.key] = option.type === "dateRange" ? picked : value;
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
let title = one.title;
|
|
1203
|
+
if (title !== void 0) {
|
|
1204
|
+
title = title.trim().slice(0, MAX_WIDGET_TITLE_LENGTH);
|
|
1205
|
+
if (title === "") {
|
|
1206
|
+
title = void 0;
|
|
1207
|
+
} else {
|
|
1208
|
+
title = uniqueTitle(taken, title);
|
|
1209
|
+
taken.add(normalizeTitle(title));
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
const next = {
|
|
1213
|
+
...title === void 0 ? {} : { title },
|
|
1214
|
+
...one.width === void 0 ? {} : { width: Math.min(range.max, Math.max(range.min, one.width)) },
|
|
1215
|
+
...one.flexible === void 0 ? {} : { flexible: one.flexible },
|
|
1216
|
+
...Object.keys(chosen).length === 0 ? {} : { options: chosen }
|
|
1217
|
+
};
|
|
1218
|
+
if (Object.keys(next).length > 0) {
|
|
1219
|
+
cleaned[definition.key] = sameSettings(one, next) ? one : next;
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
const keys = Object.keys(cleaned);
|
|
1223
|
+
const unchanged = keys.length === Object.keys(settings).length && keys.every((key) => cleaned[key] === settings[key]);
|
|
1224
|
+
if (unchanged) return layout;
|
|
1225
|
+
const { settings: _previous, ...others } = layout;
|
|
1226
|
+
return keys.length === 0 ? others : { ...others, settings: cleaned };
|
|
1227
|
+
}
|
|
1228
|
+
|
|
686
1229
|
// src/core/layout.ts
|
|
687
1230
|
var MAX_PAGE_TITLE_LENGTH = 30;
|
|
688
1231
|
var MAX_PARSED_PAGES = 50;
|
|
@@ -717,18 +1260,23 @@ function parseLayout(raw) {
|
|
|
717
1260
|
const hidden = uniqueStrings(record["hidden"]);
|
|
718
1261
|
const minimized = uniqueStrings(record["minimized"]);
|
|
719
1262
|
const pages = parsePages(record["pages"]);
|
|
1263
|
+
const settings = parseSettings(
|
|
1264
|
+
record["settings"]
|
|
1265
|
+
);
|
|
1266
|
+
const withSettings = settings === void 0 ? {} : { settings };
|
|
720
1267
|
if (pages.length > 0) {
|
|
721
1268
|
return {
|
|
722
1269
|
order: EMPTY_LAYOUT.order,
|
|
723
1270
|
hidden: EMPTY_LAYOUT.hidden,
|
|
724
1271
|
minimized: EMPTY_LAYOUT.minimized,
|
|
725
|
-
pages
|
|
1272
|
+
pages,
|
|
1273
|
+
...withSettings
|
|
726
1274
|
};
|
|
727
1275
|
}
|
|
728
1276
|
if (order.length === 0 && hidden.length === 0 && minimized.length === 0) {
|
|
729
|
-
return EMPTY_LAYOUT;
|
|
1277
|
+
return settings === void 0 ? EMPTY_LAYOUT : { ...EMPTY_LAYOUT, settings };
|
|
730
1278
|
}
|
|
731
|
-
return { order, hidden, minimized };
|
|
1279
|
+
return { order, hidden, minimized, ...withSettings };
|
|
732
1280
|
}
|
|
733
1281
|
function parsePages(value) {
|
|
734
1282
|
if (!Array.isArray(value)) return [];
|
|
@@ -775,7 +1323,8 @@ function serializeLayout(layout) {
|
|
|
775
1323
|
minimized: [...page.minimized],
|
|
776
1324
|
...page.maxRows === void 0 ? {} : { maxRows: page.maxRows }
|
|
777
1325
|
}))
|
|
778
|
-
}
|
|
1326
|
+
},
|
|
1327
|
+
...serializeSettings(layout.settings) === void 0 ? {} : { settings: serializeSettings(layout.settings) }
|
|
779
1328
|
});
|
|
780
1329
|
}
|
|
781
1330
|
function bySortOrder(items) {
|
|
@@ -843,378 +1392,101 @@ function freeSlotIndexes(ordered) {
|
|
|
843
1392
|
ordered.forEach((item, index) => {
|
|
844
1393
|
if (!isPinned(item)) slots.push(index);
|
|
845
1394
|
});
|
|
846
|
-
return slots;
|
|
847
|
-
}
|
|
848
|
-
function moveWidgetBy(definitions, layout, key, offset) {
|
|
849
|
-
const current = visibleWidgets(definitions, layout);
|
|
850
|
-
const fromIndex = current.findIndex((d) => d.key === key);
|
|
851
|
-
if (fromIndex === -1) return layout;
|
|
852
|
-
const freeSlots = freeSlotIndexes(current);
|
|
853
|
-
const fromFree = freeSlots.indexOf(fromIndex);
|
|
854
|
-
if (fromFree === -1) return layout;
|
|
855
|
-
const toFree = Math.max(
|
|
856
|
-
0,
|
|
857
|
-
Math.min(freeSlots.length - 1, fromFree + Math.trunc(offset))
|
|
858
|
-
);
|
|
859
|
-
return moveWidget(definitions, layout, key, freeSlots[toFree]);
|
|
860
|
-
}
|
|
861
|
-
function moveWidgetUp(definitions, layout, key) {
|
|
862
|
-
return moveWidgetBy(definitions, layout, key, -1);
|
|
863
|
-
}
|
|
864
|
-
function moveWidgetDown(definitions, layout, key) {
|
|
865
|
-
return moveWidgetBy(definitions, layout, key, 1);
|
|
866
|
-
}
|
|
867
|
-
function isHidden(layout, key) {
|
|
868
|
-
return layout.hidden.includes(key);
|
|
869
|
-
}
|
|
870
|
-
function isMinimized(layout, key) {
|
|
871
|
-
return layout.minimized.includes(key);
|
|
872
|
-
}
|
|
873
|
-
function hideWidget(layout, key) {
|
|
874
|
-
if (isHidden(layout, key)) return layout;
|
|
875
|
-
return { ...layout, hidden: [...layout.hidden, key] };
|
|
876
|
-
}
|
|
877
|
-
function showWidget(layout, key) {
|
|
878
|
-
if (!isHidden(layout, key)) return layout;
|
|
879
|
-
return {
|
|
880
|
-
...layout,
|
|
881
|
-
hidden: layout.hidden.filter((k) => k !== key),
|
|
882
|
-
minimized: layout.minimized.filter((k) => k !== key)
|
|
883
|
-
};
|
|
884
|
-
}
|
|
885
|
-
function toggleHidden(layout, key) {
|
|
886
|
-
return isHidden(layout, key) ? showWidget(layout, key) : hideWidget(layout, key);
|
|
887
|
-
}
|
|
888
|
-
function minimizeWidget(layout, key) {
|
|
889
|
-
if (isMinimized(layout, key)) return layout;
|
|
890
|
-
return { ...layout, minimized: [...layout.minimized, key] };
|
|
891
|
-
}
|
|
892
|
-
function restoreWidget(layout, key) {
|
|
893
|
-
if (!isMinimized(layout, key)) return layout;
|
|
894
|
-
return { ...layout, minimized: layout.minimized.filter((k) => k !== key) };
|
|
895
|
-
}
|
|
896
|
-
function toggleMinimized(layout, key) {
|
|
897
|
-
return isMinimized(layout, key) ? restoreWidget(layout, key) : minimizeWidget(layout, key);
|
|
898
|
-
}
|
|
899
|
-
function pruneLayout(definitions, layout) {
|
|
900
|
-
const known = new Set(definitions.map((d) => d.key));
|
|
901
|
-
const keep = (keys) => keys.every((k) => known.has(k)) ? keys : keys.filter((k) => known.has(k));
|
|
902
|
-
return mapLayoutLists(layout, (lists) => ({
|
|
903
|
-
order: keep(lists.order),
|
|
904
|
-
hidden: keep(lists.hidden),
|
|
905
|
-
minimized: keep(lists.minimized)
|
|
906
|
-
}));
|
|
907
|
-
}
|
|
908
|
-
function mapLayoutLists(layout, change) {
|
|
909
|
-
const top = change(layout);
|
|
910
|
-
const pages = layout.pages?.map((page) => {
|
|
911
|
-
const next = change(page);
|
|
912
|
-
return next.order === page.order && next.hidden === page.hidden && next.minimized === page.minimized ? page : { ...page, ...next };
|
|
913
|
-
});
|
|
914
|
-
const pagesChanged = pages !== void 0 && pages.some((page, i) => page !== layout.pages?.[i]);
|
|
915
|
-
if (top.order === layout.order && top.hidden === layout.hidden && top.minimized === layout.minimized && !pagesChanged) {
|
|
916
|
-
return layout;
|
|
917
|
-
}
|
|
918
|
-
return {
|
|
919
|
-
...layout,
|
|
920
|
-
...top,
|
|
921
|
-
...pages === void 0 ? {} : { pages }
|
|
922
|
-
};
|
|
923
|
-
}
|
|
924
|
-
function enforceLocks(definitions, layout, options = {}) {
|
|
925
|
-
if (options.overrideLocks === true) return layout;
|
|
926
|
-
const noMove = /* @__PURE__ */ new Set();
|
|
927
|
-
const noHide = /* @__PURE__ */ new Set();
|
|
928
|
-
const noMinimize = /* @__PURE__ */ new Set();
|
|
929
|
-
for (const definition of definitions) {
|
|
930
|
-
const lock = resolveWidgetLock(definition);
|
|
931
|
-
if (lock.move) noMove.add(definition.key);
|
|
932
|
-
if (lock.hide) noHide.add(definition.key);
|
|
933
|
-
if (lock.minimize) noMinimize.add(definition.key);
|
|
934
|
-
}
|
|
935
|
-
const without2 = (keys, drop) => keys.some((key) => drop.has(key)) ? keys.filter((key) => !drop.has(key)) : keys;
|
|
936
|
-
return mapLayoutLists(layout, (lists) => ({
|
|
937
|
-
order: without2(lists.order, noMove),
|
|
938
|
-
hidden: without2(lists.hidden, noHide),
|
|
939
|
-
minimized: without2(lists.minimized, noMinimize)
|
|
940
|
-
}));
|
|
941
|
-
}
|
|
942
|
-
|
|
943
|
-
// src/core/options.ts
|
|
944
|
-
var DATE_RANGE_PRESETS = [
|
|
945
|
-
"today",
|
|
946
|
-
"yesterday",
|
|
947
|
-
"last7",
|
|
948
|
-
"last30",
|
|
949
|
-
"last90",
|
|
950
|
-
"thisMonth",
|
|
951
|
-
"lastMonth",
|
|
952
|
-
"thisYear",
|
|
953
|
-
"lastYear"
|
|
954
|
-
];
|
|
955
|
-
var WIDGET_OPTION_TYPES = [
|
|
956
|
-
"choice",
|
|
957
|
-
"number",
|
|
958
|
-
"boolean",
|
|
959
|
-
"text",
|
|
960
|
-
"dateRange",
|
|
961
|
-
"color",
|
|
962
|
-
"sort",
|
|
963
|
-
"columns"
|
|
964
|
-
];
|
|
965
|
-
var MAX_WIDGET_OPTIONS = 20;
|
|
966
|
-
var MAX_TEXT_OPTION_LENGTH = 500;
|
|
967
|
-
var OPTION_KEY_PATTERN = /^[A-Za-z][A-Za-z0-9_-]{0,39}$/;
|
|
968
|
-
var COLOR_PATTERN = /^#[0-9a-fA-F]{6}$/;
|
|
969
|
-
var INTERVAL_PATTERN = /^(\d{4}-\d{2}-\d{2})\/(\d{4}-\d{2}-\d{2})$/;
|
|
970
|
-
var CONTROL_CHARACTERS = /[\u0000-\u001f\u007f]/;
|
|
971
|
-
function isColumnKeyFor(kind, key) {
|
|
972
|
-
if (kind === "TABLE") return /^c\d+$/.test(key);
|
|
973
|
-
if (kind === "BAR_LIST") return key === "label" || key === "value";
|
|
974
|
-
return false;
|
|
975
|
-
}
|
|
976
|
-
function isClientApplied(option) {
|
|
977
|
-
return (option.type === "sort" || option.type === "columns") && option.apply === "client";
|
|
978
|
-
}
|
|
979
|
-
function civilToday(context) {
|
|
980
|
-
const now = context.now ?? Date.now();
|
|
981
|
-
let timeZone = context.timeZone ?? "UTC";
|
|
982
|
-
try {
|
|
983
|
-
new Intl.DateTimeFormat("en-US", { timeZone });
|
|
984
|
-
} catch {
|
|
985
|
-
timeZone = "UTC";
|
|
986
|
-
}
|
|
987
|
-
const parts = new Intl.DateTimeFormat("en-US", {
|
|
988
|
-
timeZone,
|
|
989
|
-
year: "numeric",
|
|
990
|
-
month: "2-digit",
|
|
991
|
-
day: "2-digit"
|
|
992
|
-
}).formatToParts(new Date(now));
|
|
993
|
-
const pick = (type) => Number(parts.find((part) => part.type === type)?.value ?? "0");
|
|
994
|
-
return { year: pick("year"), month: pick("month"), day: pick("day") };
|
|
995
|
-
}
|
|
996
|
-
function toIso(epochMs) {
|
|
997
|
-
return new Date(epochMs).toISOString().slice(0, 10);
|
|
998
|
-
}
|
|
999
|
-
var DAY_MS = 864e5;
|
|
1000
|
-
function parseIsoDay(text) {
|
|
1001
|
-
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(text);
|
|
1002
|
-
if (match === null) return void 0;
|
|
1003
|
-
const epoch = Date.UTC(
|
|
1004
|
-
Number(match[1]),
|
|
1005
|
-
Number(match[2]) - 1,
|
|
1006
|
-
Number(match[3])
|
|
1007
|
-
);
|
|
1008
|
-
return toIso(epoch) === text ? epoch : void 0;
|
|
1009
|
-
}
|
|
1010
|
-
function isIsoInterval(value) {
|
|
1011
|
-
const match = INTERVAL_PATTERN.exec(value);
|
|
1012
|
-
if (match === null) return false;
|
|
1013
|
-
const start = parseIsoDay(match[1]);
|
|
1014
|
-
const end = parseIsoDay(match[2]);
|
|
1015
|
-
return start !== void 0 && end !== void 0 && start <= end;
|
|
1016
|
-
}
|
|
1017
|
-
function isPreset(value) {
|
|
1018
|
-
return DATE_RANGE_PRESETS.includes(value);
|
|
1019
|
-
}
|
|
1020
|
-
function resolveDateRange(value, context = {}) {
|
|
1021
|
-
if (isIsoInterval(value)) return value;
|
|
1022
|
-
if (!isPreset(value)) return void 0;
|
|
1023
|
-
const today = civilToday(context);
|
|
1024
|
-
const todayMs = Date.UTC(today.year, today.month - 1, today.day);
|
|
1025
|
-
const range = (startMs, endMs) => `${toIso(startMs)}/${toIso(endMs)}`;
|
|
1026
|
-
switch (value) {
|
|
1027
|
-
case "today":
|
|
1028
|
-
return range(todayMs, todayMs);
|
|
1029
|
-
case "yesterday":
|
|
1030
|
-
return range(todayMs - DAY_MS, todayMs - DAY_MS);
|
|
1031
|
-
case "last7":
|
|
1032
|
-
return range(todayMs - 6 * DAY_MS, todayMs);
|
|
1033
|
-
case "last30":
|
|
1034
|
-
return range(todayMs - 29 * DAY_MS, todayMs);
|
|
1035
|
-
case "last90":
|
|
1036
|
-
return range(todayMs - 89 * DAY_MS, todayMs);
|
|
1037
|
-
case "thisMonth":
|
|
1038
|
-
return range(Date.UTC(today.year, today.month - 1, 1), todayMs);
|
|
1039
|
-
case "lastMonth":
|
|
1040
|
-
return range(
|
|
1041
|
-
Date.UTC(today.year, today.month - 2, 1),
|
|
1042
|
-
Date.UTC(today.year, today.month - 1, 1) - DAY_MS
|
|
1043
|
-
);
|
|
1044
|
-
case "thisYear":
|
|
1045
|
-
return range(Date.UTC(today.year, 0, 1), todayMs);
|
|
1046
|
-
case "lastYear":
|
|
1047
|
-
return range(
|
|
1048
|
-
Date.UTC(today.year - 1, 0, 1),
|
|
1049
|
-
Date.UTC(today.year, 0, 1) - DAY_MS
|
|
1050
|
-
);
|
|
1051
|
-
}
|
|
1395
|
+
return slots;
|
|
1052
1396
|
}
|
|
1053
|
-
function
|
|
1054
|
-
|
|
1055
|
-
const
|
|
1056
|
-
|
|
1397
|
+
function moveWidgetBy(definitions, layout, key, offset) {
|
|
1398
|
+
const current = visibleWidgets(definitions, layout);
|
|
1399
|
+
const fromIndex = current.findIndex((d) => d.key === key);
|
|
1400
|
+
if (fromIndex === -1) return layout;
|
|
1401
|
+
const freeSlots = freeSlotIndexes(current);
|
|
1402
|
+
const fromFree = freeSlots.indexOf(fromIndex);
|
|
1403
|
+
if (fromFree === -1) return layout;
|
|
1404
|
+
const toFree = Math.max(
|
|
1405
|
+
0,
|
|
1406
|
+
Math.min(freeSlots.length - 1, fromFree + Math.trunc(offset))
|
|
1407
|
+
);
|
|
1408
|
+
return moveWidget(definitions, layout, key, freeSlots[toFree]);
|
|
1057
1409
|
}
|
|
1058
|
-
function
|
|
1059
|
-
|
|
1060
|
-
if (separator <= 0) return void 0;
|
|
1061
|
-
const column = value.slice(0, separator);
|
|
1062
|
-
const direction = value.slice(separator + 1);
|
|
1063
|
-
if (direction !== "asc" && direction !== "desc") return void 0;
|
|
1064
|
-
return { column, direction };
|
|
1410
|
+
function moveWidgetUp(definitions, layout, key) {
|
|
1411
|
+
return moveWidgetBy(definitions, layout, key, -1);
|
|
1065
1412
|
}
|
|
1066
|
-
function
|
|
1067
|
-
|
|
1068
|
-
const sortOption = definition.options?.find(
|
|
1069
|
-
(option) => option.type === "sort"
|
|
1070
|
-
);
|
|
1071
|
-
if (sortOption === void 0) return void 0;
|
|
1072
|
-
const chosen = values[sortOption.key];
|
|
1073
|
-
return typeof chosen === "string" ? parseSortValue(chosen) : void 0;
|
|
1413
|
+
function moveWidgetDown(definitions, layout, key) {
|
|
1414
|
+
return moveWidgetBy(definitions, layout, key, 1);
|
|
1074
1415
|
}
|
|
1075
|
-
function
|
|
1076
|
-
|
|
1077
|
-
case "choice":
|
|
1078
|
-
return typeof value === "string" && option.choices.some((choice) => choice.value === value) ? value : void 0;
|
|
1079
|
-
case "number":
|
|
1080
|
-
return typeof value === "number" && Number.isFinite(value) && value >= option.min && value <= option.max && onStepGrid(option, value) ? value : void 0;
|
|
1081
|
-
case "boolean":
|
|
1082
|
-
return typeof value === "boolean" ? value : void 0;
|
|
1083
|
-
case "text": {
|
|
1084
|
-
if (typeof value !== "string") return void 0;
|
|
1085
|
-
const trimmed = value.trim();
|
|
1086
|
-
return trimmed.length <= option.maxLength && !CONTROL_CHARACTERS.test(trimmed) ? trimmed : void 0;
|
|
1087
|
-
}
|
|
1088
|
-
case "dateRange": {
|
|
1089
|
-
if (typeof value !== "string") return void 0;
|
|
1090
|
-
if (isPreset(value) && option.presets !== void 0 && !option.presets.some((preset) => preset.value === value)) {
|
|
1091
|
-
return void 0;
|
|
1092
|
-
}
|
|
1093
|
-
return resolveDateRange(value, context);
|
|
1094
|
-
}
|
|
1095
|
-
case "color":
|
|
1096
|
-
return typeof value === "string" && COLOR_PATTERN.test(value) ? value.toLowerCase() : void 0;
|
|
1097
|
-
case "sort": {
|
|
1098
|
-
if (typeof value !== "string") return void 0;
|
|
1099
|
-
const sort = parseSortValue(value);
|
|
1100
|
-
return sort !== void 0 && option.columns.some((column) => column.key === sort.column) ? value : void 0;
|
|
1101
|
-
}
|
|
1102
|
-
case "columns": {
|
|
1103
|
-
if (!Array.isArray(value) || value.length === 0) return void 0;
|
|
1104
|
-
const keys = value;
|
|
1105
|
-
const allowed = new Set(option.columns.map((c) => c.key));
|
|
1106
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1107
|
-
for (const key of keys) {
|
|
1108
|
-
if (typeof key !== "string" || !allowed.has(key) || seen.has(key)) {
|
|
1109
|
-
return void 0;
|
|
1110
|
-
}
|
|
1111
|
-
seen.add(key);
|
|
1112
|
-
}
|
|
1113
|
-
return [...seen];
|
|
1114
|
-
}
|
|
1115
|
-
}
|
|
1416
|
+
function isHidden(layout, key) {
|
|
1417
|
+
return layout.hidden.includes(key);
|
|
1116
1418
|
}
|
|
1117
|
-
function
|
|
1118
|
-
|
|
1119
|
-
case "dateRange":
|
|
1120
|
-
return resolveDateRange(option.default, context);
|
|
1121
|
-
case "sort":
|
|
1122
|
-
return option.default;
|
|
1123
|
-
case "columns":
|
|
1124
|
-
return [...option.default];
|
|
1125
|
-
default:
|
|
1126
|
-
return option.default;
|
|
1127
|
-
}
|
|
1419
|
+
function isMinimized(layout, key) {
|
|
1420
|
+
return layout.minimized.includes(key);
|
|
1128
1421
|
}
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
if (options === void 0 || options.length === 0) return NO_VALUES;
|
|
1133
|
-
const values = {};
|
|
1134
|
-
for (const option of options) {
|
|
1135
|
-
const picked = chosen?.[option.key];
|
|
1136
|
-
const value = (picked === void 0 ? void 0 : coerceOptionValue(option, picked, context)) ?? defaultOptionValue(option, context);
|
|
1137
|
-
if (value !== void 0) values[option.key] = value;
|
|
1138
|
-
}
|
|
1139
|
-
return values;
|
|
1422
|
+
function hideWidget(layout, key) {
|
|
1423
|
+
if (isHidden(layout, key)) return layout;
|
|
1424
|
+
return { ...layout, hidden: [...layout.hidden, key] };
|
|
1140
1425
|
}
|
|
1141
|
-
function
|
|
1142
|
-
if (
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1426
|
+
function showWidget(layout, key) {
|
|
1427
|
+
if (!isHidden(layout, key)) return layout;
|
|
1428
|
+
return {
|
|
1429
|
+
...layout,
|
|
1430
|
+
hidden: layout.hidden.filter((k) => k !== key),
|
|
1431
|
+
minimized: layout.minimized.filter((k) => k !== key)
|
|
1432
|
+
};
|
|
1146
1433
|
}
|
|
1147
|
-
function
|
|
1148
|
-
|
|
1149
|
-
return keys.every((key) => sameValue(a[key], b[key]));
|
|
1434
|
+
function toggleHidden(layout, key) {
|
|
1435
|
+
return isHidden(layout, key) ? showWidget(layout, key) : hideWidget(layout, key);
|
|
1150
1436
|
}
|
|
1151
|
-
function
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
if (isClientApplied(option)) continue;
|
|
1155
|
-
const value = values[option.key];
|
|
1156
|
-
if (sameValue(value, defaultOptionValue(option, context))) continue;
|
|
1157
|
-
parts.push(
|
|
1158
|
-
`${option.key}=${encodeURIComponent(JSON.stringify(value ?? null))}`
|
|
1159
|
-
);
|
|
1160
|
-
}
|
|
1161
|
-
parts.sort();
|
|
1162
|
-
return parts.length === 0 ? "" : `?${parts.join("&")}`;
|
|
1437
|
+
function minimizeWidget(layout, key) {
|
|
1438
|
+
if (isMinimized(layout, key)) return layout;
|
|
1439
|
+
return { ...layout, minimized: [...layout.minimized, key] };
|
|
1163
1440
|
}
|
|
1164
|
-
function
|
|
1165
|
-
|
|
1166
|
-
return
|
|
1441
|
+
function restoreWidget(layout, key) {
|
|
1442
|
+
if (!isMinimized(layout, key)) return layout;
|
|
1443
|
+
return { ...layout, minimized: layout.minimized.filter((k) => k !== key) };
|
|
1167
1444
|
}
|
|
1168
|
-
function
|
|
1169
|
-
|
|
1170
|
-
return items.map((item, index) => ({ item, index })).sort((a, b) => {
|
|
1171
|
-
const order = sort.column === "value" ? a.item.value - b.item.value : a.item.label.localeCompare(b.item.label);
|
|
1172
|
-
return order * sign || a.index - b.index;
|
|
1173
|
-
}).map(({ item }) => item);
|
|
1445
|
+
function toggleMinimized(layout, key) {
|
|
1446
|
+
return isMinimized(layout, key) ? restoreWidget(layout, key) : minimizeWidget(layout, key);
|
|
1174
1447
|
}
|
|
1175
|
-
function
|
|
1176
|
-
const
|
|
1177
|
-
const
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
(
|
|
1182
|
-
);
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
const
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
const index = tableColumnIndex(sort.column);
|
|
1194
|
-
if (index !== void 0 && index < next.columns.length) {
|
|
1195
|
-
const sorted = queryRows(tableDetailData(next), {
|
|
1196
|
-
page: 1,
|
|
1197
|
-
pageSize: Math.max(1, next.rows.length),
|
|
1198
|
-
sort
|
|
1199
|
-
});
|
|
1200
|
-
if (sorted.ok) next = { ...next, rows: sorted.value.rows };
|
|
1201
|
-
}
|
|
1202
|
-
}
|
|
1448
|
+
function pruneLayout(definitions, layout) {
|
|
1449
|
+
const known = new Set(definitions.map((d) => d.key));
|
|
1450
|
+
const keep = (keys) => keys.every((k) => known.has(k)) ? keys : keys.filter((k) => known.has(k));
|
|
1451
|
+
return mapLayoutLists(layout, (lists) => ({
|
|
1452
|
+
order: keep(lists.order),
|
|
1453
|
+
hidden: keep(lists.hidden),
|
|
1454
|
+
minimized: keep(lists.minimized)
|
|
1455
|
+
}));
|
|
1456
|
+
}
|
|
1457
|
+
function mapLayoutLists(layout, change) {
|
|
1458
|
+
const top = change(layout);
|
|
1459
|
+
const pages = layout.pages?.map((page) => {
|
|
1460
|
+
const next = change(page);
|
|
1461
|
+
return next.order === page.order && next.hidden === page.hidden && next.minimized === page.minimized ? page : { ...page, ...next };
|
|
1462
|
+
});
|
|
1463
|
+
const pagesChanged = pages !== void 0 && pages.some((page, i) => page !== layout.pages?.[i]);
|
|
1464
|
+
if (top.order === layout.order && top.hidden === layout.hidden && top.minimized === layout.minimized && !pagesChanged) {
|
|
1465
|
+
return layout;
|
|
1203
1466
|
}
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1467
|
+
return {
|
|
1468
|
+
...layout,
|
|
1469
|
+
...top,
|
|
1470
|
+
...pages === void 0 ? {} : { pages }
|
|
1471
|
+
};
|
|
1472
|
+
}
|
|
1473
|
+
function enforceLocks(definitions, layout, options = {}) {
|
|
1474
|
+
if (options.overrideLocks === true) return layout;
|
|
1475
|
+
const noMove = /* @__PURE__ */ new Set();
|
|
1476
|
+
const noHide = /* @__PURE__ */ new Set();
|
|
1477
|
+
const noMinimize = /* @__PURE__ */ new Set();
|
|
1478
|
+
for (const definition of definitions) {
|
|
1479
|
+
const lock = resolveWidgetLock(definition);
|
|
1480
|
+
if (lock.move) noMove.add(definition.key);
|
|
1481
|
+
if (lock.hide) noHide.add(definition.key);
|
|
1482
|
+
if (lock.minimize) noMinimize.add(definition.key);
|
|
1216
1483
|
}
|
|
1217
|
-
|
|
1484
|
+
const without2 = (keys, drop) => keys.some((key) => drop.has(key)) ? keys.filter((key) => !drop.has(key)) : keys;
|
|
1485
|
+
return mapLayoutLists(layout, (lists) => ({
|
|
1486
|
+
order: without2(lists.order, noMove),
|
|
1487
|
+
hidden: without2(lists.hidden, noHide),
|
|
1488
|
+
minimized: without2(lists.minimized, noMinimize)
|
|
1489
|
+
}));
|
|
1218
1490
|
}
|
|
1219
1491
|
|
|
1220
1492
|
// src/core/validate.ts
|
|
@@ -1227,7 +1499,7 @@ function describeType2(value) {
|
|
|
1227
1499
|
}
|
|
1228
1500
|
return typeof value;
|
|
1229
1501
|
}
|
|
1230
|
-
function
|
|
1502
|
+
function isRecord2(value) {
|
|
1231
1503
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1232
1504
|
}
|
|
1233
1505
|
function join(path, field) {
|
|
@@ -1309,7 +1581,7 @@ function requireOneOf(record, field, options, path, problems) {
|
|
|
1309
1581
|
function eachRecord(items, path, problems, check) {
|
|
1310
1582
|
items.forEach((item, index) => {
|
|
1311
1583
|
const itemPath = `${path}[${index}]`;
|
|
1312
|
-
if (
|
|
1584
|
+
if (isRecord2(item)) {
|
|
1313
1585
|
check(item, itemPath);
|
|
1314
1586
|
} else {
|
|
1315
1587
|
problems.push(
|
|
@@ -1458,7 +1730,7 @@ function checkPayloadFields(kind, data, problems) {
|
|
|
1458
1730
|
}
|
|
1459
1731
|
function checkDetailOption(detail, problems) {
|
|
1460
1732
|
if (detail === void 0 || typeof detail === "boolean") return;
|
|
1461
|
-
if (!
|
|
1733
|
+
if (!isRecord2(detail)) {
|
|
1462
1734
|
problems.push(
|
|
1463
1735
|
`detail must be true, false or an options object, got ${describeType2(detail)}.`
|
|
1464
1736
|
);
|
|
@@ -1477,13 +1749,13 @@ function checkDetailOption(detail, problems) {
|
|
|
1477
1749
|
}
|
|
1478
1750
|
function checkTableControlsOption(controls, kind, problems) {
|
|
1479
1751
|
if (controls === void 0 || controls === false) return;
|
|
1480
|
-
if (typeof controls !== "boolean" && !
|
|
1752
|
+
if (typeof controls !== "boolean" && !isRecord2(controls)) {
|
|
1481
1753
|
problems.push(
|
|
1482
1754
|
`tableControls must be true, false or an options object, got ${describeType2(controls)}.`
|
|
1483
1755
|
);
|
|
1484
1756
|
return;
|
|
1485
1757
|
}
|
|
1486
|
-
if (
|
|
1758
|
+
if (isRecord2(controls)) {
|
|
1487
1759
|
optionalBoolean(controls, "search", "tableControls", problems);
|
|
1488
1760
|
optionalBoolean(controls, "sort", "tableControls", problems);
|
|
1489
1761
|
}
|
|
@@ -1493,9 +1765,39 @@ function checkTableControlsOption(controls, kind, problems) {
|
|
|
1493
1765
|
);
|
|
1494
1766
|
}
|
|
1495
1767
|
}
|
|
1768
|
+
function checkWidthLimits(value, problems) {
|
|
1769
|
+
for (const field of ["minWidth", "maxWidth"]) {
|
|
1770
|
+
const limit = value[field];
|
|
1771
|
+
if (limit !== void 0 && !isWidgetWidth(limit)) {
|
|
1772
|
+
problems.push(
|
|
1773
|
+
`${field} must be an integer from ${MIN_WIDGET_WIDTH} to ${MAX_WIDGET_WIDTH} (twelfths of the row), got ${typeof limit === "number" ? String(limit) : describeType2(limit)}.`
|
|
1774
|
+
);
|
|
1775
|
+
return;
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
const { minWidth, maxWidth, width } = value;
|
|
1779
|
+
if (isWidgetWidth(minWidth) && isWidgetWidth(maxWidth) && minWidth > maxWidth) {
|
|
1780
|
+
problems.push(
|
|
1781
|
+
`minWidth (${minWidth}) must not be more than maxWidth (${maxWidth}).`
|
|
1782
|
+
);
|
|
1783
|
+
return;
|
|
1784
|
+
}
|
|
1785
|
+
if (isWidgetWidth(width)) {
|
|
1786
|
+
if (isWidgetWidth(minWidth) && width < minWidth) {
|
|
1787
|
+
problems.push(
|
|
1788
|
+
`width (${width}) must not be less than minWidth (${minWidth}).`
|
|
1789
|
+
);
|
|
1790
|
+
}
|
|
1791
|
+
if (isWidgetWidth(maxWidth) && width > maxWidth) {
|
|
1792
|
+
problems.push(
|
|
1793
|
+
`width (${width}) must not be more than maxWidth (${maxWidth}).`
|
|
1794
|
+
);
|
|
1795
|
+
}
|
|
1796
|
+
}
|
|
1797
|
+
}
|
|
1496
1798
|
function checkLockedOption(locked, problems) {
|
|
1497
1799
|
if (locked === void 0 || typeof locked === "boolean") return;
|
|
1498
|
-
if (!
|
|
1800
|
+
if (!isRecord2(locked)) {
|
|
1499
1801
|
problems.push(
|
|
1500
1802
|
`locked must be true, false or an object, got ${describeType2(locked)}.`
|
|
1501
1803
|
);
|
|
@@ -1504,6 +1806,7 @@ function checkLockedOption(locked, problems) {
|
|
|
1504
1806
|
optionalBoolean(locked, "move", "locked", problems);
|
|
1505
1807
|
optionalBoolean(locked, "hide", "locked", problems);
|
|
1506
1808
|
optionalBoolean(locked, "minimize", "locked", problems);
|
|
1809
|
+
optionalBoolean(locked, "options", "locked", problems);
|
|
1507
1810
|
}
|
|
1508
1811
|
function checkOptionColumns(option, path, kind, problems) {
|
|
1509
1812
|
const columns = option["columns"];
|
|
@@ -1516,7 +1819,7 @@ function checkOptionColumns(option, path, kind, problems) {
|
|
|
1516
1819
|
const keys = [];
|
|
1517
1820
|
columns.forEach((entry, index) => {
|
|
1518
1821
|
const entryPath = `${path}.columns[${index}]`;
|
|
1519
|
-
if (!
|
|
1822
|
+
if (!isRecord2(entry)) {
|
|
1520
1823
|
problems.push(
|
|
1521
1824
|
`${entryPath} must be an object, got ${describeType2(entry)}.`
|
|
1522
1825
|
);
|
|
@@ -1541,7 +1844,7 @@ function checkOptionColumns(option, path, kind, problems) {
|
|
|
1541
1844
|
return keys;
|
|
1542
1845
|
}
|
|
1543
1846
|
function checkOption(option, path, kind, seenKeys, seenTypes, problems) {
|
|
1544
|
-
if (!
|
|
1847
|
+
if (!isRecord2(option)) {
|
|
1545
1848
|
problems.push(`${path} must be an object, got ${describeType2(option)}.`);
|
|
1546
1849
|
return;
|
|
1547
1850
|
}
|
|
@@ -1573,7 +1876,7 @@ function checkOption(option, path, kind, seenKeys, seenTypes, problems) {
|
|
|
1573
1876
|
} else {
|
|
1574
1877
|
choices.forEach((choice, index) => {
|
|
1575
1878
|
const choicePath = `${path}.choices[${index}]`;
|
|
1576
|
-
if (!
|
|
1879
|
+
if (!isRecord2(choice)) {
|
|
1577
1880
|
problems.push(
|
|
1578
1881
|
`${choicePath} must be an object, got ${describeType2(choice)}.`
|
|
1579
1882
|
);
|
|
@@ -1663,7 +1966,7 @@ function checkOption(option, path, kind, seenKeys, seenTypes, problems) {
|
|
|
1663
1966
|
} else {
|
|
1664
1967
|
presets.forEach((preset, index) => {
|
|
1665
1968
|
const presetPath = `${path}.presets[${index}]`;
|
|
1666
|
-
if (!
|
|
1969
|
+
if (!isRecord2(preset)) {
|
|
1667
1970
|
problems.push(
|
|
1668
1971
|
`${presetPath} must be an object, got ${describeType2(preset)}.`
|
|
1669
1972
|
);
|
|
@@ -1790,7 +2093,7 @@ function formatProblems(prefix, problems) {
|
|
|
1790
2093
|
}
|
|
1791
2094
|
function validateWidgetData(value, options = {}) {
|
|
1792
2095
|
const subject = options.widgetKey === void 0 ? "Widget data" : `Widget ${JSON.stringify(options.widgetKey)}`;
|
|
1793
|
-
if (!
|
|
2096
|
+
if (!isRecord2(value)) {
|
|
1794
2097
|
return err(`${subject}: must be an object, got ${describeType2(value)}.`);
|
|
1795
2098
|
}
|
|
1796
2099
|
if (value["empty"] === true) {
|
|
@@ -1820,7 +2123,7 @@ function validateWidgetData(value, options = {}) {
|
|
|
1820
2123
|
return ok(value);
|
|
1821
2124
|
}
|
|
1822
2125
|
function validateWidgetDefinition(value) {
|
|
1823
|
-
if (!
|
|
2126
|
+
if (!isRecord2(value)) {
|
|
1824
2127
|
return err(
|
|
1825
2128
|
`Widget definition: must be an object, got ${describeType2(value)}.`
|
|
1826
2129
|
);
|
|
@@ -1854,6 +2157,7 @@ function validateWidgetDefinition(value) {
|
|
|
1854
2157
|
`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"])}.`
|
|
1855
2158
|
);
|
|
1856
2159
|
}
|
|
2160
|
+
checkWidthLimits(value, problems);
|
|
1857
2161
|
checkDetailOption(value["detail"], problems);
|
|
1858
2162
|
checkTableControlsOption(value["tableControls"], value["kind"], problems);
|
|
1859
2163
|
checkLockedOption(value["locked"], problems);
|
|
@@ -2515,7 +2819,7 @@ function withoutLockField(definition) {
|
|
|
2515
2819
|
delete copy.locked;
|
|
2516
2820
|
return copy;
|
|
2517
2821
|
}
|
|
2518
|
-
function
|
|
2822
|
+
function uniqueTitle2(taken, title, index) {
|
|
2519
2823
|
let base = title.trim().slice(0, MAX_PAGE_TITLE_LENGTH);
|
|
2520
2824
|
if (base === "") base = `Page ${index + 1}`;
|
|
2521
2825
|
let candidate = base;
|
|
@@ -2536,9 +2840,18 @@ function samePages(a, b) {
|
|
|
2536
2840
|
}
|
|
2537
2841
|
function normalizeLayout(definitions, layout, options = {}) {
|
|
2538
2842
|
const known = pruneLayout(definitions, layout);
|
|
2539
|
-
const
|
|
2843
|
+
const enforced = enforceLocks(definitions, known, options);
|
|
2844
|
+
const locked = normalizeSettings(
|
|
2845
|
+
definitions,
|
|
2846
|
+
enforced,
|
|
2847
|
+
options
|
|
2848
|
+
);
|
|
2540
2849
|
if (!hasPages(locked)) return locked === layout ? layout : locked;
|
|
2541
|
-
const defs =
|
|
2850
|
+
const defs = effectiveDefinitions(
|
|
2851
|
+
options.overrideLocks === true ? definitions.map(withoutLockField) : definitions,
|
|
2852
|
+
locked,
|
|
2853
|
+
options
|
|
2854
|
+
);
|
|
2542
2855
|
const taken = /* @__PURE__ */ new Set();
|
|
2543
2856
|
const seenKeys = /* @__PURE__ */ new Set();
|
|
2544
2857
|
const held = /* @__PURE__ */ new Set();
|
|
@@ -2551,7 +2864,7 @@ function normalizeLayout(definitions, layout, options = {}) {
|
|
|
2551
2864
|
];
|
|
2552
2865
|
const next = {
|
|
2553
2866
|
...page,
|
|
2554
|
-
title:
|
|
2867
|
+
title: uniqueTitle2(taken, page.title, index),
|
|
2555
2868
|
order: keep(page.order),
|
|
2556
2869
|
hidden: keep(page.hidden),
|
|
2557
2870
|
minimized: keep(page.minimized)
|
|
@@ -2639,7 +2952,7 @@ function normalizeLayout(definitions, layout, options = {}) {
|
|
|
2639
2952
|
}
|
|
2640
2953
|
if (!placed) {
|
|
2641
2954
|
const key = nextPageKey(work());
|
|
2642
|
-
const title =
|
|
2955
|
+
const title = uniqueTitle2(
|
|
2643
2956
|
new Set(pages.map((p) => normalizedTitle(p.title))),
|
|
2644
2957
|
`Page ${pages.length + 1}`,
|
|
2645
2958
|
pages.length
|
|
@@ -2651,7 +2964,7 @@ function normalizeLayout(definitions, layout, options = {}) {
|
|
|
2651
2964
|
}
|
|
2652
2965
|
}
|
|
2653
2966
|
const result = work();
|
|
2654
|
-
return samePages(layout.pages ?? [], pages) && sameKeys(layout.order, result.order) ? layout : result;
|
|
2967
|
+
return samePages(layout.pages ?? [], pages) && sameKeys(layout.order, result.order) && locked.settings === layout.settings ? layout : result;
|
|
2655
2968
|
}
|
|
2656
2969
|
|
|
2657
2970
|
// src/core/scale.ts
|
|
@@ -3483,6 +3796,6 @@ function indent(block) {
|
|
|
3483
3796
|
return block.split("\n").map((line) => ` ${line}`).join("\n");
|
|
3484
3797
|
}
|
|
3485
3798
|
|
|
3486
|
-
export { DATE_RANGE_PRESETS, DEFAULT_COMPARISON_LABEL, DEFAULT_CURRENCY, DEFAULT_DETAIL_PAGE_SIZE, DEFAULT_EMPTY_TEXT, DEFAULT_MAX_LAYOUT_BYTES, DEFAULT_PAGE_KEY, DEFAULT_PAGE_ROWS, DETAIL_MODES, EMPTY_LAYOUT, LAYOUT_ENVELOPE_VERSION, MAX_DETAIL_PAGE_SIZE, MAX_GRAPH_SERIES, MAX_PAGE_ROWS, MAX_PAGE_TITLE_LENGTH, MAX_PARSED_PAGES, MAX_REPORTED_PROBLEMS, MAX_TEXT_OPTION_LENGTH, MAX_WIDGET_OPTIONS, MAX_WIDGET_WIDTH, MIN_WIDGET_WIDTH, OPTION_KEY_PATTERN, THEME_TOKEN_VARIABLES, VALUE_FORMATS, WIDGET_FILLS, WIDGET_KINDS, WIDGET_OPTION_TYPES, WIDGET_SIZES, WIDTH_COLUMNS, addPage, applyClientOptions, assignPages, baseColumnSpan, cacheKeyFor, coerceOptionValue, createLayoutPersistence, createTheme, createWidgetLoader, defaultDetailQuery, defaultOptionValue, defineWidget, deriveDetailData, describeUnknownError, emptyTextFor, emptyWidget, enforceLocks, err, failedWidget, fillColumnSpans, fillWidthSpans, fillsHeight, fillsWidth, finalizeWidget, fitCount, formatCount, formatPercentChange, formatValue, fromLegacyDefinition, hasPages, hiddenWidgets, hideWidget, isClientApplied, isColumnKeyFor, isHidden, isIsoInterval, isMinimized, isSafeHref, isSafeImageUrl, isWidgetEmptyState, isWidgetKind, isWidgetVisibleTo, isWidgetWidth, itemWidth, kpiDelta, labelStride, loadingWidgets, memoryAdapter, minimizeWidget, movePage, moveWidget, moveWidgetBy, moveWidgetDown, moveWidgetToPage, moveWidgetUp, nextPageKey, niceDomain, niceStep, normalizeLayout, ok, optionValuesFor, optionsCacheSuffix, pageLayout, pageList, pageOf, pageRoom, pageWidgets, parseDetailQuery, parseLayout, parseSortValue, percentChange, placeRows, pruneLayout, queryRows, readOnly, removePage, renamePage, resolveDateRange, resolveDetailOptions, resolveOptionValues, resolvePageKey, resolvePayload, resolveTableControls, resolveWidget, resolveWidgetLock, resolveWidgetUnapplied, resolveWidgets, restoreWidget, sameOptionValues, serializeDetailQuery, serializeLayout, shareOf, showWidget, sortDefinitions, sortFromOptions, tableDetailData, toggleHidden, toggleMinimized, upgradeLegacyWidgetData, usesWidthColumns, utf8Length, validateDetailData, validateWidgetData, validateWidgetDefinition, visibleWidgets, widgetsFor, widthForSize, withEncoding, withFallback, withLogging, withPageLayout, withPrefix, withReadCache, withRetry };
|
|
3799
|
+
export { DATE_RANGE_PRESETS, DEFAULT_COMPARISON_LABEL, DEFAULT_CURRENCY, DEFAULT_DETAIL_PAGE_SIZE, DEFAULT_EMPTY_TEXT, DEFAULT_MAX_LAYOUT_BYTES, DEFAULT_PAGE_KEY, DEFAULT_PAGE_ROWS, DETAIL_MODES, EMPTY_LAYOUT, LAYOUT_ENVELOPE_VERSION, MAX_DETAIL_PAGE_SIZE, MAX_GRAPH_SERIES, MAX_PAGE_ROWS, MAX_PAGE_TITLE_LENGTH, MAX_PARSED_PAGES, MAX_PARSED_SETTINGS, MAX_REPORTED_PROBLEMS, MAX_TEXT_OPTION_LENGTH, MAX_WIDGET_OPTIONS, MAX_WIDGET_TITLE_LENGTH, MAX_WIDGET_WIDTH, MIN_WIDGET_WIDTH, OPTION_KEY_PATTERN, THEME_TOKEN_VARIABLES, VALUE_FORMATS, WIDGET_FILLS, WIDGET_KINDS, WIDGET_OPTION_TYPES, WIDGET_SIZES, WIDTH_COLUMNS, addPage, applyClientOptions, applySettings, assignPages, baseColumnSpan, cacheKeyFor, clearWidgetSettings, coerceOptionValue, createLayoutPersistence, createTheme, createWidgetLoader, defaultDetailQuery, defaultOptionValue, defineWidget, deriveDetailData, describeUnknownError, effectiveDefinitions, emptyTextFor, emptyWidget, enforceLocks, err, failedWidget, fillColumnSpans, fillWidthSpans, fillsHeight, fillsWidth, finalizeWidget, fitCount, formatCount, formatPercentChange, formatValue, fromLegacyDefinition, hasPages, hiddenWidgets, hideWidget, isClientApplied, isColumnKeyFor, isFlexible, isHidden, isIsoInterval, isMinimized, isOptionsLocked, isSafeHref, isSafeImageUrl, isTitleInUse, isWidgetEmptyState, isWidgetKind, isWidgetVisibleTo, isWidgetWidth, itemWidth, kpiDelta, labelStride, loadingWidgets, memoryAdapter, minimizeWidget, movePage, moveWidget, moveWidgetBy, moveWidgetDown, moveWidgetToPage, moveWidgetUp, nextPageKey, niceDomain, niceStep, normalizeLayout, normalizeSettings, normalizeTitle, ok, optionValuesFor, optionValuesFromLayout, optionsCacheSuffix, pageLayout, pageList, pageOf, pageRoom, pageWidgets, parseDetailQuery, parseLayout, parseSettings, parseSortValue, percentChange, placeRows, pruneLayout, queryRows, readOnly, removePage, renamePage, resolveDateRange, resolveDetailOptions, resolveOptionValues, resolvePageKey, resolvePayload, resolveTableControls, resolveWidget, resolveWidgetLock, resolveWidgetUnapplied, resolveWidgets, restoreWidget, sameOptionValues, serializeDetailQuery, serializeLayout, serializeSettings, setWidgetSettings, shareOf, showWidget, sortDefinitions, sortFromOptions, tableDetailData, toggleHidden, toggleMinimized, upgradeLegacyWidgetData, usesWidthColumns, utf8Length, validateDetailData, validateWidgetData, validateWidgetDefinition, visibleWidgets, widgetOptionValues, widgetsFor, widthForSize, widthRange, widthShareLabel, withEncoding, withFallback, withLogging, withPageLayout, withPrefix, withReadCache, withRetry };
|
|
3487
3800
|
//# sourceMappingURL=core.js.map
|
|
3488
3801
|
//# sourceMappingURL=core.js.map
|