@richardmcquiston01/dashboard-widgets-toolkit 0.6.0 → 0.8.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/index.cjs CHANGED
@@ -86,6 +86,26 @@ function fromLegacyDefinition(legacy) {
86
86
  // src/core/definition.ts
87
87
  var WIDGET_SIZES = ["small", "medium", "large", "full"];
88
88
  var WIDGET_FILLS = ["height", "width", "both"];
89
+ var NOT_LOCKED = Object.freeze({
90
+ move: false,
91
+ hide: false,
92
+ minimize: false
93
+ });
94
+ var FULLY_LOCKED = Object.freeze({
95
+ move: true,
96
+ hide: true,
97
+ minimize: true
98
+ });
99
+ function resolveWidgetLock(definition) {
100
+ const setting = definition.locked;
101
+ if (setting === true) return FULLY_LOCKED;
102
+ if (setting === void 0 || setting === false) return NOT_LOCKED;
103
+ return {
104
+ move: setting.move === true,
105
+ hide: setting.hide === true,
106
+ minimize: setting.minimize === true
107
+ };
108
+ }
89
109
  function defineWidget(definition) {
90
110
  return definition;
91
111
  }
@@ -689,9 +709,10 @@ function bySortOrder(items) {
689
709
  (a, b) => (a.item.sortOrder ?? 0) - (b.item.sortOrder ?? 0) || a.index - b.index
690
710
  ).map(({ item }) => item);
691
711
  }
692
- function visibleWidgets(definitions, layout) {
693
- const hidden = new Set(layout.hidden);
694
- const visible = definitions.filter((d) => !hidden.has(d.key));
712
+ function isPinned(item) {
713
+ return resolveWidgetLock(item).move;
714
+ }
715
+ function viewerOrder(visible, layout) {
695
716
  const byKey = new Map(visible.map((d) => [d.key, d]));
696
717
  const ordered = [];
697
718
  for (const key of layout.order) {
@@ -706,34 +727,62 @@ function visibleWidgets(definitions, layout) {
706
727
  }
707
728
  return ordered;
708
729
  }
730
+ function placeAroundPinned(visible, free) {
731
+ const slots = bySortOrder(visible).map(
732
+ (item) => isPinned(item) ? item : void 0
733
+ );
734
+ let next = 0;
735
+ return slots.map((pinned) => pinned ?? free[next++]);
736
+ }
737
+ function visibleWidgets(definitions, layout) {
738
+ const hidden = new Set(layout.hidden);
739
+ const visible = definitions.filter((d) => !hidden.has(d.key));
740
+ const ordered = viewerOrder(visible, layout);
741
+ if (!visible.some(isPinned)) return ordered;
742
+ return placeAroundPinned(
743
+ visible,
744
+ ordered.filter((item) => !isPinned(item))
745
+ );
746
+ }
709
747
  function hiddenWidgets(definitions, layout) {
710
748
  const hidden = new Set(layout.hidden);
711
749
  return bySortOrder(definitions.filter((d) => hidden.has(d.key)));
712
750
  }
713
751
  function moveWidget(definitions, layout, key, toIndex) {
714
- const current = visibleWidgets(definitions, layout).map(
715
- (d) => d.key
716
- );
717
- const fromIndex = current.indexOf(key);
718
- if (fromIndex === -1 || !Number.isInteger(toIndex) || toIndex < 0 || toIndex >= current.length || toIndex === fromIndex) {
752
+ const current = visibleWidgets(definitions, layout);
753
+ const fromIndex = current.findIndex((d) => d.key === key);
754
+ const mover = current[fromIndex];
755
+ if (mover === void 0 || !Number.isInteger(toIndex) || toIndex < 0 || toIndex >= current.length || toIndex === fromIndex || isPinned(mover) || isPinned(current[toIndex])) {
719
756
  return layout;
720
757
  }
721
- const next = [...current];
722
- next.splice(fromIndex, 1);
723
- next.splice(toIndex, 0, key);
724
- return { ...layout, order: next };
758
+ const freeSlots = freeSlotIndexes(current);
759
+ const free = current.filter((item) => !isPinned(item));
760
+ const fromFree = freeSlots.indexOf(fromIndex);
761
+ const toFree = freeSlots.indexOf(toIndex);
762
+ free.splice(fromFree, 1);
763
+ free.splice(toFree, 0, mover);
764
+ const next = placeAroundPinned(current, free);
765
+ return { ...layout, order: next.map((d) => d.key) };
766
+ }
767
+ function freeSlotIndexes(ordered) {
768
+ const slots = [];
769
+ ordered.forEach((item, index) => {
770
+ if (!isPinned(item)) slots.push(index);
771
+ });
772
+ return slots;
725
773
  }
726
774
  function moveWidgetBy(definitions, layout, key, offset) {
727
- const current = visibleWidgets(definitions, layout).map(
728
- (d) => d.key
729
- );
730
- const fromIndex = current.indexOf(key);
775
+ const current = visibleWidgets(definitions, layout);
776
+ const fromIndex = current.findIndex((d) => d.key === key);
731
777
  if (fromIndex === -1) return layout;
732
- const toIndex = Math.max(
778
+ const freeSlots = freeSlotIndexes(current);
779
+ const fromFree = freeSlots.indexOf(fromIndex);
780
+ if (fromFree === -1) return layout;
781
+ const toFree = Math.max(
733
782
  0,
734
- Math.min(current.length - 1, fromIndex + Math.trunc(offset))
783
+ Math.min(freeSlots.length - 1, fromFree + Math.trunc(offset))
735
784
  );
736
- return moveWidget(definitions, layout, key, toIndex);
785
+ return moveWidget(definitions, layout, key, freeSlots[toFree]);
737
786
  }
738
787
  function moveWidgetUp(definitions, layout, key) {
739
788
  return moveWidgetBy(definitions, layout, key, -1);
@@ -783,6 +832,23 @@ function pruneLayout(definitions, layout) {
783
832
  };
784
833
  return next.order.length === layout.order.length && next.hidden.length === layout.hidden.length && next.minimized.length === layout.minimized.length ? layout : next;
785
834
  }
835
+ function enforceLocks(definitions, layout, options = {}) {
836
+ if (options.overrideLocks === true) return layout;
837
+ const noMove = /* @__PURE__ */ new Set();
838
+ const noHide = /* @__PURE__ */ new Set();
839
+ const noMinimize = /* @__PURE__ */ new Set();
840
+ for (const definition of definitions) {
841
+ const lock = resolveWidgetLock(definition);
842
+ if (lock.move) noMove.add(definition.key);
843
+ if (lock.hide) noHide.add(definition.key);
844
+ if (lock.minimize) noMinimize.add(definition.key);
845
+ }
846
+ const without = (keys, drop) => keys.some((key) => drop.has(key)) ? keys.filter((key) => !drop.has(key)) : keys;
847
+ const order = without(layout.order, noMove);
848
+ const hidden = without(layout.hidden, noHide);
849
+ const minimized = without(layout.minimized, noMinimize);
850
+ return order === layout.order && hidden === layout.hidden && minimized === layout.minimized ? layout : { ...layout, order, hidden, minimized };
851
+ }
786
852
 
787
853
  // src/core/validate.ts
788
854
  var MAX_REPORTED_PROBLEMS = 10;
@@ -826,6 +892,14 @@ function optionalNumber(record, field, path, problems) {
826
892
  requireNumber(record, field, path, problems);
827
893
  }
828
894
  }
895
+ function optionalSortValue(record, path, problems) {
896
+ const value = record["value"];
897
+ if (value !== void 0 && typeof value !== "string" && !(typeof value === "number" && Number.isFinite(value))) {
898
+ problems.push(
899
+ `${path}.value must be a string or a finite number, got ${describeType2(value)}.`
900
+ );
901
+ }
902
+ }
829
903
  function optionalBoolean(record, field, path, problems) {
830
904
  const value = record[field];
831
905
  if (value !== void 0 && typeof value !== "boolean") {
@@ -929,6 +1003,7 @@ function checkPayloadFields(kind, data, problems) {
929
1003
  }
930
1004
  eachRecord(row, rowPath, problems, (cell, cellPath) => {
931
1005
  requireString(cell, "text", cellPath, problems);
1006
+ optionalSortValue(cell, cellPath, problems);
932
1007
  optionalUrl(
933
1008
  cell,
934
1009
  "href",
@@ -1051,6 +1126,18 @@ function checkTableControlsOption(controls, kind, problems) {
1051
1126
  );
1052
1127
  }
1053
1128
  }
1129
+ function checkLockedOption(locked, problems) {
1130
+ if (locked === void 0 || typeof locked === "boolean") return;
1131
+ if (!isRecord(locked)) {
1132
+ problems.push(
1133
+ `locked must be true, false or an object, got ${describeType2(locked)}.`
1134
+ );
1135
+ return;
1136
+ }
1137
+ optionalBoolean(locked, "move", "locked", problems);
1138
+ optionalBoolean(locked, "hide", "locked", problems);
1139
+ optionalBoolean(locked, "minimize", "locked", problems);
1140
+ }
1054
1141
  function formatProblems(prefix, problems) {
1055
1142
  const shown = problems.slice(0, MAX_REPORTED_PROBLEMS);
1056
1143
  const more = problems.length - shown.length;
@@ -1124,6 +1211,7 @@ function validateWidgetDefinition(value) {
1124
1211
  }
1125
1212
  checkDetailOption(value["detail"], problems);
1126
1213
  checkTableControlsOption(value["tableControls"], value["kind"], problems);
1214
+ checkLockedOption(value["locked"], problems);
1127
1215
  if (value["fill"] !== void 0) {
1128
1216
  requireOneOf(value, "fill", WIDGET_FILLS, "", problems);
1129
1217
  }
@@ -1432,6 +1520,7 @@ exports.deriveDetailData = deriveDetailData;
1432
1520
  exports.describeUnknownError = describeUnknownError;
1433
1521
  exports.emptyTextFor = emptyTextFor;
1434
1522
  exports.emptyWidget = emptyWidget;
1523
+ exports.enforceLocks = enforceLocks;
1435
1524
  exports.err = err;
1436
1525
  exports.failedWidget = failedWidget;
1437
1526
  exports.fillColumnSpans = fillColumnSpans;
@@ -1473,6 +1562,7 @@ exports.resolveDetailOptions = resolveDetailOptions;
1473
1562
  exports.resolvePayload = resolvePayload;
1474
1563
  exports.resolveTableControls = resolveTableControls;
1475
1564
  exports.resolveWidget = resolveWidget;
1565
+ exports.resolveWidgetLock = resolveWidgetLock;
1476
1566
  exports.resolveWidgets = resolveWidgets;
1477
1567
  exports.restoreWidget = restoreWidget;
1478
1568
  exports.serializeDetailQuery = serializeDetailQuery;