@visns-studio/visns-components 5.26.3 → 5.26.5

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.3",
97
+ "version": "5.26.5",
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,34 @@ 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
- const initialLoadRef = useRef(true); // Ref to track initial load
553
- const [dashboardSetting, setDashboardSetting] = useState(
554
- dynamicDashboard ? userProfile.dashboard_setting || setting : setting
572
+ const [dashboardSetting, setDashboardSetting] = useState(() =>
573
+ dedupeWidgets(
574
+ dynamicDashboard ? userProfile.dashboard_setting || setting : setting
575
+ )
555
576
  );
556
577
  const [data, setData] = useState({});
557
578
  const [dropdowns, setDropdowns] = useState({});
@@ -699,42 +720,14 @@ function GenericDashboard({ setting, userProfile, dynamicDashboard = false }) {
699
720
  }
700
721
  };
701
722
 
702
- // Single useEffect for initial data fetch
703
- useEffect(() => {
704
- // This will run once after filters are initialized
705
- if (Object.keys(filters).length > 0 && initialLoadRef.current) {
706
- // Fetch data once with initial filters
707
- fetchData(filters);
708
- // Mark initial load as complete
709
- initialLoadRef.current = false;
710
- }
711
- }, [filters]);
712
-
713
- // Handle filter changes after initial load
714
- const isInitialFilterChangeRef = useRef(true);
715
-
723
+ // Single fetch trigger: filters are (re)built whenever dashboardSetting
724
+ // changes, so every load path funnels through this one effect — the old
725
+ // split effects fired twice per mount (every widget fetched twice).
716
726
  useEffect(() => {
717
- // Skip the first filter change (which happens during initialization)
718
- if (isInitialFilterChangeRef.current) {
719
- isInitialFilterChangeRef.current = false;
720
- return;
721
- }
722
-
723
- // Only fetch data if filters have been initialized
724
- if (!initialLoadRef.current && Object.keys(filters).length > 0) {
725
- fetchData(filters);
726
- }
727
+ if (Object.keys(filters).length === 0) return;
728
+ fetchData(filters);
727
729
  }, [filters]);
728
730
 
729
- // Handle dashboardSetting changes
730
- useEffect(() => {
731
- // Skip the initial render
732
- if (!initialLoadRef.current) {
733
- // Only fetch data if it's not the initial load
734
- fetchData(filters);
735
- }
736
- }, [dashboardSetting]);
737
-
738
731
  // Handle window resize events to update viewportWidth
739
732
  useEffect(() => {
740
733
  const handleResize = () => {
@@ -1122,11 +1115,10 @@ function GenericDashboard({ setting, userProfile, dynamicDashboard = false }) {
1122
1115
  }`}
1123
1116
  >
1124
1117
  <span>
1125
- {(Array.isArray(widgetData) &&
1126
- widgetData.length === 0) ||
1127
- widgetData == null
1128
- ? parse(`&nbsp;`)
1129
- : widgetData}
1118
+ {typeof widgetData === 'number' ||
1119
+ typeof widgetData === 'string'
1120
+ ? widgetData
1121
+ : parse(`&nbsp;`)}
1130
1122
  </span>
1131
1123
  </div>
1132
1124
  {widget.button && (