@visns-studio/visns-components 5.26.2 → 5.26.4

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/package.json CHANGED
@@ -94,7 +94,7 @@
94
94
  "react-dom": "^17.0.0 || ^18.0.0"
95
95
  },
96
96
  "name": "@visns-studio/visns-components",
97
- "version": "5.26.2",
97
+ "version": "5.26.4",
98
98
  "description": "Various packages to assist in the development of our Custom Applications.",
99
99
  "main": "src/index.js",
100
100
  "files": [
@@ -545,13 +545,35 @@ const showModal = (title, content) => {
545
545
  };
546
546
 
547
547
 
548
+ // Duplicate widget ids (seen in saved user layouts) collide in the data map,
549
+ // double-fetch, and can crash the renderer — keep the first occurrence only.
550
+ const dedupeWidgets = (dashSetting) => {
551
+ if (!dashSetting?.widgets) return dashSetting;
552
+ const seen = new Set();
553
+ const widgets = dashSetting.widgets.filter((widget) => {
554
+ if (seen.has(widget.id)) {
555
+ console.warn(
556
+ `GenericDashboard: dropping duplicate widget id "${widget.id}"`
557
+ );
558
+ return false;
559
+ }
560
+ seen.add(widget.id);
561
+ return true;
562
+ });
563
+ return widgets.length === dashSetting.widgets.length
564
+ ? dashSetting
565
+ : { ...dashSetting, widgets };
566
+ };
567
+
548
568
  function GenericDashboard({ setting, userProfile, dynamicDashboard = false }) {
549
569
  const swapy = useRef(null);
550
570
  const container = useRef(null);
551
571
  const navigate = useNavigate();
552
572
  const initialLoadRef = useRef(true); // Ref to track initial load
553
- const [dashboardSetting, setDashboardSetting] = useState(
554
- dynamicDashboard ? userProfile.dashboard_setting || setting : setting
573
+ const [dashboardSetting, setDashboardSetting] = useState(() =>
574
+ dedupeWidgets(
575
+ dynamicDashboard ? userProfile.dashboard_setting || setting : setting
576
+ )
555
577
  );
556
578
  const [data, setData] = useState({});
557
579
  const [dropdowns, setDropdowns] = useState({});
@@ -662,19 +684,31 @@ function GenericDashboard({ setting, userProfile, dynamicDashboard = false }) {
662
684
  return null;
663
685
  });
664
686
 
665
- const results = await Promise.all(promises);
687
+ // allSettled: one failed widget request must not blank the whole
688
+ // dashboard — failed widgets stay empty, the rest still render.
689
+ const results = await Promise.allSettled(promises);
666
690
 
667
691
  const fetchedData = dashboardSetting.widgets.reduce(
668
692
  (acc, widget, index) => {
669
- if (results[index]) {
693
+ const result = results[index];
694
+
695
+ if (result.status === 'rejected') {
696
+ console.error(
697
+ `Error fetching data for widget ${widget.id}:`,
698
+ result.reason
699
+ );
700
+ return acc;
701
+ }
702
+
703
+ if (result.value) {
670
704
  // Check if the response indicates an error
671
- if (results[index]?.data?.value) {
705
+ if (result.value?.data?.value) {
672
706
  console.error(
673
707
  `API error for widget ${widget.id}:`,
674
- results[index].data.value
708
+ result.value.data.value
675
709
  );
676
710
  } else {
677
- acc[widget.id] = results[index]?.data;
711
+ acc[widget.id] = result.value?.data;
678
712
  }
679
713
  }
680
714
  return acc;
@@ -1110,11 +1144,10 @@ function GenericDashboard({ setting, userProfile, dynamicDashboard = false }) {
1110
1144
  }`}
1111
1145
  >
1112
1146
  <span>
1113
- {(Array.isArray(widgetData) &&
1114
- widgetData.length === 0) ||
1115
- widgetData == null
1116
- ? parse(`&nbsp;`)
1117
- : widgetData}
1147
+ {typeof widgetData === 'number' ||
1148
+ typeof widgetData === 'string'
1149
+ ? widgetData
1150
+ : parse(`&nbsp;`)}
1118
1151
  </span>
1119
1152
  </div>
1120
1153
  {widget.button && (