@optifye/dashboard-core 4.2.3 → 4.2.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/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import * as React33 from 'react';
2
- import React33__default, { createContext, memo, useState, useEffect, useRef, useCallback, useMemo, useContext, useLayoutEffect, useId, Children, isValidElement, useInsertionEffect, forwardRef, Fragment as Fragment$1, createElement, Component } from 'react';
1
+ import * as React14 from 'react';
2
+ import React14__default, { createContext, useRef, useCallback, useState, useMemo, useEffect, memo, useContext, useLayoutEffect, useId, Children, isValidElement, useInsertionEffect, forwardRef, Fragment as Fragment$1, createElement, Component } from 'react';
3
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
4
  import { useRouter } from 'next/router';
5
5
  import { subDays, format, parseISO, isValid, isFuture, isToday } from 'date-fns';
@@ -12,7 +12,7 @@ import { noop, warning, invariant, progress, secondsToMilliseconds, milliseconds
12
12
  import { getValueTransition, hover, press, isPrimaryPointer, GroupPlaybackControls, setDragLock, supportsLinearEasing, attachTimeline, isGenerator, calcGeneratorDuration, isWaapiSupportedEasing, mapEasingToNativeEasing, maxGeneratorDuration, generateLinearEasing, isBezierDefinition } from 'motion-dom';
13
13
  import { ResponsiveContainer, BarChart as BarChart$1, CartesianGrid, XAxis, YAxis, Tooltip, ReferenceLine, Bar, Cell, LabelList, PieChart, Pie, Legend, LineChart as LineChart$1, Line } from 'recharts';
14
14
  import { Slot } from '@radix-ui/react-slot';
15
- import { ChevronDown, ChevronUp, Check, Camera, ShieldCheck, Star, Award, X, Coffee, Plus, Clock, Minus, ArrowDown, ArrowUp, Search, CheckCircle, AlertTriangle, Info, Share2, Download, User, XCircle, ChevronLeft, ChevronRight, AlertCircle, Sun, Moon, MessageSquare, Trash2, ArrowLeft, RefreshCw, Menu, Send, Copy, Edit2, UserCheck, Save, LogOut, Calendar, Settings, LifeBuoy, Loader2, ArrowLeftIcon as ArrowLeftIcon$1, Settings2, CheckCircle2, EyeOff, Eye, Zap, UserCircle } from 'lucide-react';
15
+ import { Camera, ChevronDown, ChevronUp, Check, ShieldCheck, Star, Award, X, Coffee, Plus, Clock, Minus, ArrowDown, ArrowUp, Search, CheckCircle, AlertTriangle, Info, Share2, Download, User, XCircle, ChevronLeft, ChevronRight, AlertCircle, Sun, Moon, MessageSquare, Trash2, ArrowLeft, RefreshCw, Menu, Send, Copy, Edit2, UserCheck, Save, LogOut, Calendar, Settings, LifeBuoy, Loader2, ArrowLeftIcon as ArrowLeftIcon$1, Settings2, CheckCircle2, EyeOff, Eye, Zap, UserCircle } from 'lucide-react';
16
16
  import { DayPicker, useNavigation as useNavigation$1 } from 'react-day-picker';
17
17
  import html2canvas from 'html2canvas';
18
18
  import jsPDF, { jsPDF as jsPDF$1 } from 'jspdf';
@@ -188,14 +188,14 @@ var _getDashboardConfigInstance = () => {
188
188
  }
189
189
  return dashboardConfigInstance;
190
190
  };
191
- var DashboardConfigContext = React33.createContext(void 0);
191
+ var DashboardConfigContext = React14.createContext(void 0);
192
192
  var DashboardProvider = ({ config: userProvidedConfig, children }) => {
193
- const fullConfig = React33.useMemo(() => mergeWithDefaultConfig(userProvidedConfig), [userProvidedConfig]);
193
+ const fullConfig = React14.useMemo(() => mergeWithDefaultConfig(userProvidedConfig), [userProvidedConfig]);
194
194
  _setDashboardConfigInstance(fullConfig);
195
- React33.useEffect(() => {
195
+ React14.useEffect(() => {
196
196
  _setDashboardConfigInstance(fullConfig);
197
197
  }, [fullConfig]);
198
- React33.useEffect(() => {
198
+ React14.useEffect(() => {
199
199
  if (!fullConfig.theme) return;
200
200
  const styleId = "dashboard-core-theme-vars";
201
201
  let styleEl = document.getElementById(styleId);
@@ -221,7 +221,7 @@ var DashboardProvider = ({ config: userProvidedConfig, children }) => {
221
221
  return /* @__PURE__ */ jsx(DashboardConfigContext.Provider, { value: fullConfig, children });
222
222
  };
223
223
  var useDashboardConfig = () => {
224
- const ctx = React33.useContext(DashboardConfigContext);
224
+ const ctx = React14.useContext(DashboardConfigContext);
225
225
  if (!ctx) throw new Error("useDashboardConfig must be used within a DashboardProvider");
226
226
  return ctx;
227
227
  };
@@ -849,6 +849,63 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
849
849
  if (recentData) {
850
850
  console.log(`[useWorkspaceDetailedMetrics] Found fallback data from date: ${recentData.date}, shift: ${recentData.shift_id}`);
851
851
  const outputDifference2 = (recentData.total_output || 0) - (recentData.ideal_output || 0);
852
+ const workspaceMatch2 = recentData.workspace_name?.match(/WS(\d+)/);
853
+ const workspaceNumber2 = workspaceMatch2 ? parseInt(workspaceMatch2[1]) : 0;
854
+ const specialWsStart2 = workspaceConfig.specialWorkspaces?.startId ?? 19;
855
+ const specialWsEnd2 = workspaceConfig.specialWorkspaces?.endId ?? 34;
856
+ const isSpecialWorkspace2 = workspaceNumber2 >= specialWsStart2 && workspaceNumber2 <= specialWsEnd2;
857
+ const outputHourly2 = recentData.output_hourly || {};
858
+ const hasOutputHourlyData2 = outputHourly2 && typeof outputHourly2 === "object" && Object.keys(outputHourly2).length > 0;
859
+ let hourlyActionCounts2 = [];
860
+ if (hasOutputHourlyData2) {
861
+ console.log("Using new output_hourly column for workspace (fallback):", recentData.workspace_name);
862
+ console.log("Raw output_hourly data (fallback):", outputHourly2);
863
+ const isNightShift = recentData.shift_id === 1;
864
+ const shiftStart = recentData.shift_start || (isNightShift ? "22:00" : "06:00");
865
+ const shiftEnd = recentData.shift_end || (isNightShift ? "06:00" : "14:00");
866
+ const startHour = parseInt(shiftStart.split(":")[0]);
867
+ let expectedHours = [];
868
+ if (isNightShift) {
869
+ for (let i = 0; i < 9; i++) {
870
+ expectedHours.push((startHour + i) % 24);
871
+ }
872
+ } else {
873
+ for (let i = 0; i < 9; i++) {
874
+ expectedHours.push((startHour + i) % 24);
875
+ }
876
+ }
877
+ console.log("Expected shift hours (fallback):", expectedHours);
878
+ console.log("Available data hours (fallback):", Object.keys(outputHourly2));
879
+ hourlyActionCounts2 = expectedHours.map((expectedHour) => {
880
+ let hourData = outputHourly2[expectedHour.toString()];
881
+ if (!hourData && isNightShift) {
882
+ for (const [storedHour, data2] of Object.entries(outputHourly2)) {
883
+ if (Array.isArray(data2) && data2.length > 0 && data2.some((val) => val > 0)) {
884
+ if (storedHour === "18" && expectedHour === 1) {
885
+ hourData = data2;
886
+ console.log(`Mapping stored hour ${storedHour} to expected hour ${expectedHour} (fallback)`);
887
+ break;
888
+ }
889
+ }
890
+ }
891
+ }
892
+ return Array.isArray(hourData) ? hourData.reduce((sum, count) => sum + (count || 0), 0) : 0;
893
+ });
894
+ console.log("Final hourly action counts (fallback):", hourlyActionCounts2);
895
+ } else {
896
+ console.log("Using output_array fallback for workspace (fallback):", recentData.workspace_name);
897
+ const minuteByMinuteArray = recentData.output_array || [];
898
+ if (isSpecialWorkspace2) {
899
+ const last40Readings = minuteByMinuteArray.slice(Math.max(0, minuteByMinuteArray.length - 40));
900
+ hourlyActionCounts2 = last40Readings;
901
+ } else {
902
+ for (let i = 0; i < minuteByMinuteArray.length; i += 60) {
903
+ const hourSlice = minuteByMinuteArray.slice(i, Math.min(i + 60, minuteByMinuteArray.length));
904
+ const hourlySum = hourSlice.reduce((sum, count) => sum + count, 0);
905
+ hourlyActionCounts2.push(hourlySum);
906
+ }
907
+ }
908
+ }
852
909
  const transformedData2 = {
853
910
  workspace_id: recentData.workspace_id,
854
911
  workspace_name: recentData.workspace_name,
@@ -869,12 +926,14 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
869
926
  ideal_cycle_time: recentData.ideal_cycle_time || 0,
870
927
  avg_efficiency: recentData.efficiency || 0,
871
928
  total_actions: recentData.total_output || 0,
872
- hourly_action_counts: recentData.output_array || [],
929
+ hourly_action_counts: hourlyActionCounts2,
930
+ // Now uses the NEW logic with fallback
873
931
  workspace_rank: recentData.workspace_rank || 0,
874
932
  total_workspaces: recentData.total_workspaces || workspaceConfig.totalWorkspaces || 42,
875
933
  ideal_output_until_now: recentData.ideal_output || 0,
876
934
  output_difference: outputDifference2,
877
935
  idle_time: recentData.idle_time || 0,
936
+ idle_time_hourly: recentData.idle_time_hourly || void 0,
878
937
  ...recentData.compliance_efficiency !== void 0 && { compliance_efficiency: recentData.compliance_efficiency },
879
938
  ...recentData.sop_check !== void 0 && { sop_check: recentData.sop_check }
880
939
  };
@@ -901,17 +960,66 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
901
960
  const specialWsStart = workspaceConfig.specialWorkspaces?.startId ?? 19;
902
961
  const specialWsEnd = workspaceConfig.specialWorkspaces?.endId ?? 34;
903
962
  const isSpecialWorkspace = workspaceNumber >= specialWsStart && workspaceNumber <= specialWsEnd;
904
- const minuteByMinuteArray = data.output_array || [];
963
+ const outputHourly = data.output_hourly || {};
964
+ console.log("[DEBUG] Raw data.output_hourly:", data.output_hourly);
965
+ console.log("[DEBUG] outputHourly after || {}:", outputHourly);
966
+ console.log("[DEBUG] typeof outputHourly:", typeof outputHourly);
967
+ console.log("[DEBUG] Object.keys(outputHourly):", Object.keys(outputHourly));
968
+ console.log("[DEBUG] Object.keys(outputHourly).length:", Object.keys(outputHourly).length);
969
+ const hasOutputHourlyData = outputHourly && typeof outputHourly === "object" && Object.keys(outputHourly).length > 0;
970
+ console.log("[DEBUG] hasOutputHourlyData:", hasOutputHourlyData);
905
971
  let hourlyActionCounts = [];
906
- if (isSpecialWorkspace) {
907
- const last40Readings = minuteByMinuteArray.slice(Math.max(0, minuteByMinuteArray.length - 40));
908
- hourlyActionCounts = last40Readings;
972
+ if (hasOutputHourlyData) {
973
+ console.log("\u2705 Using new output_hourly column for workspace:", data.workspace_name);
974
+ console.log("Raw output_hourly data:", JSON.stringify(outputHourly));
975
+ const isNightShift = data.shift_id === 1;
976
+ const shiftStart = data.shift_start || (isNightShift ? "22:00" : "06:00");
977
+ const shiftEnd = data.shift_end || (isNightShift ? "06:00" : "14:00");
978
+ const startHour = parseInt(shiftStart.split(":")[0]);
979
+ let expectedHours = [];
980
+ if (isNightShift) {
981
+ for (let i = 0; i < 9; i++) {
982
+ expectedHours.push((startHour + i) % 24);
983
+ }
984
+ } else {
985
+ for (let i = 0; i < 9; i++) {
986
+ expectedHours.push((startHour + i) % 24);
987
+ }
988
+ }
989
+ console.log("Expected shift hours:", expectedHours);
990
+ console.log("Available data hours:", Object.keys(outputHourly));
991
+ hourlyActionCounts = expectedHours.map((expectedHour) => {
992
+ let hourData = outputHourly[expectedHour.toString()];
993
+ if (!hourData && isNightShift) {
994
+ for (const [storedHour, data2] of Object.entries(outputHourly)) {
995
+ if (Array.isArray(data2) && data2.length > 0 && data2.some((val) => val > 0)) {
996
+ if (storedHour === "18" && expectedHour === 1) {
997
+ hourData = data2;
998
+ console.log(`Mapping stored hour ${storedHour} to expected hour ${expectedHour}`);
999
+ break;
1000
+ }
1001
+ }
1002
+ }
1003
+ }
1004
+ return Array.isArray(hourData) ? hourData.reduce((sum, count) => sum + (count || 0), 0) : 0;
1005
+ });
1006
+ console.log("Final hourly action counts:", hourlyActionCounts);
909
1007
  } else {
910
- for (let i = 0; i < minuteByMinuteArray.length; i += 60) {
911
- const hourSlice = minuteByMinuteArray.slice(i, Math.min(i + 60, minuteByMinuteArray.length));
912
- const hourlySum = hourSlice.reduce((sum, count) => sum + count, 0);
913
- hourlyActionCounts.push(hourlySum);
1008
+ console.log("\u274C Using output_array fallback for workspace:", data.workspace_name);
1009
+ console.log("[DEBUG] Fallback reason - hasOutputHourlyData is false");
1010
+ console.log("[DEBUG] data.output_hourly was:", data.output_hourly);
1011
+ const minuteByMinuteArray = data.output_array || [];
1012
+ if (isSpecialWorkspace) {
1013
+ const last40Readings = minuteByMinuteArray.slice(Math.max(0, minuteByMinuteArray.length - 40));
1014
+ hourlyActionCounts = last40Readings;
1015
+ } else {
1016
+ for (let i = 0; i < minuteByMinuteArray.length; i += 60) {
1017
+ const hourSlice = minuteByMinuteArray.slice(i, Math.min(i + 60, minuteByMinuteArray.length));
1018
+ const hourlySum = hourSlice.reduce((sum, count) => sum + count, 0);
1019
+ hourlyActionCounts.push(hourlySum);
1020
+ }
914
1021
  }
1022
+ console.log("Final hourly action counts:", hourlyActionCounts);
915
1023
  }
916
1024
  const transformedData = {
917
1025
  workspace_id: data.workspace_id,
@@ -940,6 +1048,8 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
940
1048
  output_difference: outputDifference,
941
1049
  idle_time: data.idle_time || 0,
942
1050
  // Add idle_time from performance_metrics table
1051
+ idle_time_hourly: data.idle_time_hourly || void 0,
1052
+ // Add idle_time_hourly from performance_metrics table
943
1053
  ...data.compliance_efficiency !== void 0 && { compliance_efficiency: data.compliance_efficiency },
944
1054
  ...data.sop_check !== void 0 && { sop_check: data.sop_check }
945
1055
  };
@@ -1460,16 +1570,56 @@ var dashboardService = {
1460
1570
  const specialStart = workspaceConfig.specialWorkspaces?.startId ?? 19;
1461
1571
  const specialEnd = workspaceConfig.specialWorkspaces?.endId ?? 34;
1462
1572
  const isSpecialWorkspace = workspaceNumber >= specialStart && workspaceNumber <= specialEnd;
1463
- const minuteByMinuteArray = data.output_array || [];
1573
+ const outputHourly = data.output_hourly || {};
1574
+ const hasOutputHourlyData = outputHourly && typeof outputHourly === "object" && Object.keys(outputHourly).length > 0;
1464
1575
  let hourlyActionCounts = [];
1465
- if (isSpecialWorkspace) {
1466
- const numReadings = workspaceConfig.specialWorkspaces?.hourlyReadingsCount ?? 40;
1467
- hourlyActionCounts = minuteByMinuteArray.slice(-numReadings);
1576
+ if (hasOutputHourlyData) {
1577
+ console.log("Using new output_hourly column for workspace:", data.workspace_name);
1578
+ console.log("Raw output_hourly data:", outputHourly);
1579
+ const isNightShift = data.shift_id === 1;
1580
+ const shiftStart = data.shift_start || (isNightShift ? "22:00" : "06:00");
1581
+ const shiftEnd = data.shift_end || (isNightShift ? "06:00" : "14:00");
1582
+ const startHour = parseInt(shiftStart.split(":")[0]);
1583
+ let expectedHours = [];
1584
+ if (isNightShift) {
1585
+ for (let i = 0; i < 9; i++) {
1586
+ expectedHours.push((startHour + i) % 24);
1587
+ }
1588
+ } else {
1589
+ for (let i = 0; i < 9; i++) {
1590
+ expectedHours.push((startHour + i) % 24);
1591
+ }
1592
+ }
1593
+ console.log("Expected shift hours:", expectedHours);
1594
+ console.log("Available data hours:", Object.keys(outputHourly));
1595
+ hourlyActionCounts = expectedHours.map((expectedHour) => {
1596
+ let hourData = outputHourly[expectedHour.toString()];
1597
+ if (!hourData && isNightShift) {
1598
+ for (const [storedHour, data2] of Object.entries(outputHourly)) {
1599
+ if (Array.isArray(data2) && data2.length > 0 && data2.some((val) => val > 0)) {
1600
+ if (storedHour === "18" && expectedHour === 1) {
1601
+ hourData = data2;
1602
+ console.log(`Mapping stored hour ${storedHour} to expected hour ${expectedHour}`);
1603
+ break;
1604
+ }
1605
+ }
1606
+ }
1607
+ }
1608
+ return Array.isArray(hourData) ? hourData.reduce((sum, count) => sum + (count || 0), 0) : 0;
1609
+ });
1610
+ console.log("Final hourly action counts:", hourlyActionCounts);
1468
1611
  } else {
1469
- for (let i = 0; i < minuteByMinuteArray.length; i += 60) {
1470
- const hourSlice = minuteByMinuteArray.slice(i, Math.min(i + 60, minuteByMinuteArray.length));
1471
- const hourlySum = hourSlice.reduce((sum, count) => sum + (count ?? 0), 0);
1472
- hourlyActionCounts.push(hourlySum);
1612
+ console.log("Using output_array fallback for workspace:", data.workspace_name);
1613
+ const minuteByMinuteArray = data.output_array || [];
1614
+ if (isSpecialWorkspace) {
1615
+ const numReadings = workspaceConfig.specialWorkspaces?.hourlyReadingsCount ?? 40;
1616
+ hourlyActionCounts = minuteByMinuteArray.slice(-numReadings);
1617
+ } else {
1618
+ for (let i = 0; i < minuteByMinuteArray.length; i += 60) {
1619
+ const hourSlice = minuteByMinuteArray.slice(i, Math.min(i + 60, minuteByMinuteArray.length));
1620
+ const hourlySum = hourSlice.reduce((sum, count) => sum + (count ?? 0), 0);
1621
+ hourlyActionCounts.push(hourlySum);
1622
+ }
1473
1623
  }
1474
1624
  }
1475
1625
  const transformedData = {
@@ -1498,6 +1648,7 @@ var dashboardService = {
1498
1648
  ideal_output_until_now: data.ideal_output || 0,
1499
1649
  output_difference: outputDifference,
1500
1650
  idle_time: data.idle_time || 0,
1651
+ idle_time_hourly: data.idle_time_hourly || void 0,
1501
1652
  ...data.compliance_efficiency !== void 0 && { compliance_efficiency: data.compliance_efficiency },
1502
1653
  ...data.sop_check !== void 0 && { sop_check: data.sop_check }
1503
1654
  };
@@ -1650,18 +1801,20 @@ var dashboardService = {
1650
1801
  date: queryDate,
1651
1802
  shift_id: queryShiftId,
1652
1803
  metrics: {
1653
- avg_efficiency: avgEfficiencyFromLineMetrics,
1654
- avg_cycle_time: 0,
1804
+ avg_efficiency: avgEfficiencyFromPerf2 > 0 ? avgEfficiencyFromPerf2 : avgEfficiencyFromLineMetrics,
1805
+ // Use performance data first, fallback to line metrics
1806
+ avg_cycle_time: combinedMetricsData.avg_cycle_time / numLines,
1655
1807
  current_output: combinedMetricsData.current_output,
1656
1808
  ideal_output: combinedMetricsData.ideal_output,
1657
- total_workspaces: 44,
1809
+ total_workspaces: combinedMetricsData.total_workspaces || 44,
1810
+ // Use combined or default
1658
1811
  underperforming_workspaces: underperformingCount2,
1659
- line_threshold: combinedMetricsData.ideal_output,
1660
- threshold_pph: 0,
1661
- shift_start: "06:00",
1662
- shift_end: "14:00",
1812
+ line_threshold: combinedMetricsData.line_threshold,
1813
+ threshold_pph: combinedMetricsData.threshold_pph / numLines,
1814
+ shift_start: metricsData?.[0]?.shift_start || shiftConfig.dayShift?.startTime || "06:00",
1815
+ shift_end: metricsData?.[0]?.shift_end || shiftConfig.dayShift?.endTime || "18:00",
1663
1816
  last_updated: (/* @__PURE__ */ new Date()).toISOString(),
1664
- output_array: combinedMetricsData.output_array || [],
1817
+ output_array: combinedMetricsData.output_array,
1665
1818
  underperforming_workspace_names: [],
1666
1819
  underperforming_workspace_uuids: [],
1667
1820
  poorest_performing_workspaces: []
@@ -1693,7 +1846,8 @@ var dashboardService = {
1693
1846
  date: queryDate,
1694
1847
  shift_id: queryShiftId,
1695
1848
  metrics: {
1696
- avg_efficiency: metrics2?.avg_efficiency ?? avgEfficiencyFromPerf,
1849
+ avg_efficiency: avgEfficiencyFromPerf > 0 ? avgEfficiencyFromPerf : metrics2?.avg_efficiency ?? 0,
1850
+ // Use performance data first, fallback to line metrics
1697
1851
  avg_cycle_time: metrics2?.avg_cycle_time || 0,
1698
1852
  current_output: metrics2?.current_output || 0,
1699
1853
  ideal_output: metrics2?.ideal_output || metrics2?.line_threshold || 0,
@@ -1701,8 +1855,8 @@ var dashboardService = {
1701
1855
  underperforming_workspaces: underperformingCount,
1702
1856
  line_threshold: metrics2?.line_threshold || 0,
1703
1857
  threshold_pph: metrics2?.threshold_pph || 0,
1704
- shift_start: metrics2?.shift_start || shiftConfig.dayShift?.startTime || "00:00",
1705
- shift_end: metrics2?.shift_end || shiftConfig.dayShift?.endTime || "00:00",
1858
+ shift_start: metrics2?.shift_start || shiftConfig.dayShift?.startTime || "06:00",
1859
+ shift_end: metrics2?.shift_end || shiftConfig.dayShift?.endTime || "18:00",
1706
1860
  last_updated: metrics2?.last_updated || (/* @__PURE__ */ new Date()).toISOString(),
1707
1861
  output_array: metrics2?.output_array || [],
1708
1862
  underperforming_workspace_names: metrics2?.underperforming_workspace_names || [],
@@ -4284,8 +4438,26 @@ async function initializeWorkspaceDisplayNames(explicitLineId) {
4284
4438
  isInitializing = false;
4285
4439
  }
4286
4440
  }
4441
+ var preInitializeWorkspaceDisplayNames = async (lineId) => {
4442
+ console.log("\u{1F504} preInitializeWorkspaceDisplayNames called for lineId:", lineId);
4443
+ if (isInitialized || isInitializing) {
4444
+ console.log("\u{1F504} Already initialized or initializing, skipping pre-init");
4445
+ return;
4446
+ }
4447
+ await initializeWorkspaceDisplayNames(lineId);
4448
+ };
4449
+ var forceRefreshWorkspaceDisplayNames = async (lineId) => {
4450
+ console.log("\u{1F504} forceRefreshWorkspaceDisplayNames called for lineId:", lineId);
4451
+ clearWorkspaceDisplayNamesCache();
4452
+ await initializeWorkspaceDisplayNames(lineId);
4453
+ };
4287
4454
  console.log("\u{1F504} Module loaded, will initialize lazily when first function is called");
4288
4455
  var getWorkspaceDisplayName = (workspaceId, lineId) => {
4456
+ if (!isInitialized && !isInitializing) {
4457
+ console.log(`\u{1F504} [DEBUG] getWorkspaceDisplayName(${workspaceId}) - Not initialized, triggering lazy init...`);
4458
+ } else if (isInitializing) {
4459
+ console.log(`\u{1F504} [DEBUG] getWorkspaceDisplayName(${workspaceId}) - Currently initializing...`);
4460
+ }
4289
4461
  if (!isInitialized && !isInitializing) {
4290
4462
  console.log("\u{1F504} Lazy initialization triggered by getWorkspaceDisplayName");
4291
4463
  initializeWorkspaceDisplayNames(lineId).catch((error) => {
@@ -4369,6 +4541,7 @@ var clearWorkspaceDisplayNamesCache = () => {
4369
4541
  workspaceService.clearWorkspaceDisplayNamesCache();
4370
4542
  runtimeWorkspaceDisplayNames = {};
4371
4543
  isInitialized = false;
4544
+ isInitializing = false;
4372
4545
  };
4373
4546
 
4374
4547
  // src/lib/hooks/useWorkspaceDisplayNames.ts
@@ -8037,7 +8210,7 @@ var MotionConfigContext = createContext({
8037
8210
  });
8038
8211
 
8039
8212
  // ../../node_modules/framer-motion/dist/es/components/AnimatePresence/PopChild.mjs
8040
- var PopChildMeasure = class extends React33.Component {
8213
+ var PopChildMeasure = class extends React14.Component {
8041
8214
  getSnapshotBeforeUpdate(prevProps) {
8042
8215
  const element = this.props.childRef.current;
8043
8216
  if (element && prevProps.isPresent && !this.props.isPresent) {
@@ -8092,7 +8265,7 @@ function PopChild({ children, isPresent }) {
8092
8265
  document.head.removeChild(style);
8093
8266
  };
8094
8267
  }, [isPresent]);
8095
- return jsx(PopChildMeasure, { isPresent, childRef: ref, sizeRef: size, children: React33.cloneElement(children, { ref }) });
8268
+ return jsx(PopChildMeasure, { isPresent, childRef: ref, sizeRef: size, children: React14.cloneElement(children, { ref }) });
8096
8269
  }
8097
8270
 
8098
8271
  // ../../node_modules/framer-motion/dist/es/components/AnimatePresence/PresenceChild.mjs
@@ -8129,7 +8302,7 @@ var PresenceChild = ({ children, initial, isPresent, onExitComplete, custom, pre
8129
8302
  useMemo(() => {
8130
8303
  presenceChildren.forEach((_, key) => presenceChildren.set(key, false));
8131
8304
  }, [isPresent]);
8132
- React33.useEffect(() => {
8305
+ React14.useEffect(() => {
8133
8306
  !isPresent && !presenceChildren.size && onExitComplete && onExitComplete();
8134
8307
  }, [isPresent]);
8135
8308
  if (mode === "popLayout") {
@@ -15398,7 +15571,7 @@ var LoadingPage = ({
15398
15571
  subMessage = "Please wait while we prepare your data",
15399
15572
  className
15400
15573
  }) => {
15401
- React33__default.useEffect(() => {
15574
+ React14__default.useEffect(() => {
15402
15575
  console.log("LoadingPage rendered with message:", message);
15403
15576
  const timeout = setTimeout(() => {
15404
15577
  console.warn("LoadingPage has been visible for more than 8 seconds. This might indicate an issue.");
@@ -15441,10 +15614,10 @@ var withAuth = (WrappedComponent2, options) => {
15441
15614
  return function WithAuthComponent(props) {
15442
15615
  const { session, loading } = useAuth();
15443
15616
  const router = useRouter();
15444
- React33.useEffect(() => {
15617
+ React14.useEffect(() => {
15445
15618
  console.log("withAuth state:", { loading, hasSession: !!session, requireAuth: defaultOptions.requireAuth });
15446
15619
  }, [session, loading]);
15447
- React33.useEffect(() => {
15620
+ React14.useEffect(() => {
15448
15621
  if (!loading && defaultOptions.requireAuth && !session) {
15449
15622
  console.log("Redirecting to login from withAuth");
15450
15623
  router.replace(defaultOptions.redirectTo);
@@ -16131,10 +16304,10 @@ var CycleTimeOverTimeChart = ({
16131
16304
  };
16132
16305
  const displayData = getDisplayData(data);
16133
16306
  const DURATION = displayData.length;
16134
- const [animatedData, setAnimatedData] = React33__default.useState(Array(DURATION).fill(0));
16135
- const prevDataRef = React33__default.useRef(Array(DURATION).fill(0));
16136
- const animationFrameRef = React33__default.useRef(null);
16137
- const animateToNewData = React33__default.useCallback((targetData) => {
16307
+ const [animatedData, setAnimatedData] = React14__default.useState(Array(DURATION).fill(0));
16308
+ const prevDataRef = React14__default.useRef(Array(DURATION).fill(0));
16309
+ const animationFrameRef = React14__default.useRef(null);
16310
+ const animateToNewData = React14__default.useCallback((targetData) => {
16138
16311
  const startData = [...prevDataRef.current];
16139
16312
  const startTime = performance.now();
16140
16313
  const duration = 1200;
@@ -16164,7 +16337,7 @@ var CycleTimeOverTimeChart = ({
16164
16337
  }
16165
16338
  animationFrameRef.current = requestAnimationFrame(animate);
16166
16339
  }, []);
16167
- React33__default.useEffect(() => {
16340
+ React14__default.useEffect(() => {
16168
16341
  if (JSON.stringify(data) !== JSON.stringify(prevDataRef.current)) {
16169
16342
  const processedData = getDisplayData(data);
16170
16343
  animateToNewData(processedData);
@@ -16388,7 +16561,7 @@ var CycleTimeOverTimeChart = ({
16388
16561
  renderLegend()
16389
16562
  ] });
16390
16563
  };
16391
- var Card = React33.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
16564
+ var Card = React14.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
16392
16565
  "div",
16393
16566
  {
16394
16567
  ref,
@@ -16400,7 +16573,7 @@ var Card = React33.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */
16400
16573
  }
16401
16574
  ));
16402
16575
  Card.displayName = "Card";
16403
- var CardHeader = React33.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
16576
+ var CardHeader = React14.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
16404
16577
  "div",
16405
16578
  {
16406
16579
  ref,
@@ -16409,7 +16582,7 @@ var CardHeader = React33.forwardRef(({ className, ...props }, ref) => /* @__PURE
16409
16582
  }
16410
16583
  ));
16411
16584
  CardHeader.displayName = "CardHeader";
16412
- var CardTitle = React33.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
16585
+ var CardTitle = React14.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
16413
16586
  "h3",
16414
16587
  {
16415
16588
  ref,
@@ -16421,7 +16594,7 @@ var CardTitle = React33.forwardRef(({ className, ...props }, ref) => /* @__PURE_
16421
16594
  }
16422
16595
  ));
16423
16596
  CardTitle.displayName = "CardTitle";
16424
- var CardDescription = React33.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
16597
+ var CardDescription = React14.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
16425
16598
  "p",
16426
16599
  {
16427
16600
  ref,
@@ -16430,9 +16603,9 @@ var CardDescription = React33.forwardRef(({ className, ...props }, ref) => /* @_
16430
16603
  }
16431
16604
  ));
16432
16605
  CardDescription.displayName = "CardDescription";
16433
- var CardContent = React33.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("p-6 pt-0", className), ...props }));
16606
+ var CardContent = React14.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("p-6 pt-0", className), ...props }));
16434
16607
  CardContent.displayName = "CardContent";
16435
- var CardFooter = React33.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
16608
+ var CardFooter = React14.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
16436
16609
  "div",
16437
16610
  {
16438
16611
  ref,
@@ -16508,7 +16681,7 @@ var buttonVariants = cva(
16508
16681
  }
16509
16682
  }
16510
16683
  );
16511
- var Button = React33.forwardRef(
16684
+ var Button = React14.forwardRef(
16512
16685
  ({ className, variant, size, asChild = false, ...props }, ref) => {
16513
16686
  const Comp = asChild ? Slot : "button";
16514
16687
  return /* @__PURE__ */ jsx(
@@ -16539,10 +16712,30 @@ var HourlyOutputChart = ({
16539
16712
  };
16540
16713
  const shiftStartTime = getTimeFromTimeString(shiftStart);
16541
16714
  const SHIFT_DURATION = 11;
16542
- const [animatedData, setAnimatedData] = React33__default.useState(Array(SHIFT_DURATION).fill(0));
16543
- const prevDataRef = React33__default.useRef(Array(SHIFT_DURATION).fill(0));
16544
- const animationFrameRef = React33__default.useRef(null);
16545
- const animateToNewData = React33__default.useCallback((targetData) => {
16715
+ const [animatedData, setAnimatedData] = React14__default.useState(Array(SHIFT_DURATION).fill(0));
16716
+ const prevDataRef = React14__default.useRef(Array(SHIFT_DURATION).fill(0));
16717
+ const animationFrameRef = React14__default.useRef(null);
16718
+ const [shouldAnimateIdle, setShouldAnimateIdle] = React14__default.useState(false);
16719
+ const prevShowIdleTimeRef = React14__default.useRef(showIdleTime);
16720
+ const animationTimeoutRef = React14__default.useRef(null);
16721
+ React14__default.useEffect(() => {
16722
+ if (showIdleTime && !prevShowIdleTimeRef.current) {
16723
+ setShouldAnimateIdle(true);
16724
+ if (animationTimeoutRef.current) {
16725
+ clearTimeout(animationTimeoutRef.current);
16726
+ }
16727
+ animationTimeoutRef.current = setTimeout(() => {
16728
+ setShouldAnimateIdle(false);
16729
+ }, 1e3);
16730
+ }
16731
+ prevShowIdleTimeRef.current = showIdleTime;
16732
+ return () => {
16733
+ if (animationTimeoutRef.current) {
16734
+ clearTimeout(animationTimeoutRef.current);
16735
+ }
16736
+ };
16737
+ }, [showIdleTime]);
16738
+ const animateToNewData = React14__default.useCallback((targetData) => {
16546
16739
  const startData = [...prevDataRef.current];
16547
16740
  const startTime = performance.now();
16548
16741
  const duration = 1200;
@@ -16572,7 +16765,7 @@ var HourlyOutputChart = ({
16572
16765
  }
16573
16766
  animationFrameRef.current = requestAnimationFrame(animate);
16574
16767
  }, []);
16575
- React33__default.useEffect(() => {
16768
+ React14__default.useEffect(() => {
16576
16769
  if (JSON.stringify(data) !== JSON.stringify(prevDataRef.current)) {
16577
16770
  const shiftData = data.slice(0, SHIFT_DURATION);
16578
16771
  animateToNewData(shiftData);
@@ -16583,7 +16776,7 @@ var HourlyOutputChart = ({
16583
16776
  }
16584
16777
  };
16585
16778
  }, [data, animateToNewData]);
16586
- const formatHour = (hourIndex) => {
16779
+ const formatHour = React14__default.useCallback((hourIndex) => {
16587
16780
  const startDecimalHour = shiftStartTime.decimalHour + hourIndex;
16588
16781
  const startHour = Math.floor(startDecimalHour) % 24;
16589
16782
  const startMinute = Math.round(startDecimalHour % 1 * 60);
@@ -16599,8 +16792,8 @@ var HourlyOutputChart = ({
16599
16792
  return `${hour12}:${m.toString().padStart(2, "0")}${period}`;
16600
16793
  };
16601
16794
  return `${formatTime2(startHour, startMinute)}-${formatTime2(endHour, endMinute)}`;
16602
- };
16603
- const formatTimeRange = (hourIndex) => {
16795
+ }, [shiftStartTime.decimalHour]);
16796
+ const formatTimeRange = React14__default.useCallback((hourIndex) => {
16604
16797
  const startDecimalHour = shiftStartTime.decimalHour + hourIndex;
16605
16798
  const startHour = Math.floor(startDecimalHour) % 24;
16606
16799
  const startMinute = Math.round(startDecimalHour % 1 * 60);
@@ -16613,22 +16806,24 @@ var HourlyOutputChart = ({
16613
16806
  return `${hour12}:${m.toString().padStart(2, "0")} ${period}`;
16614
16807
  };
16615
16808
  return `${formatTime2(startHour, startMinute)} - ${formatTime2(endHour, endMinute)}`;
16616
- };
16617
- const chartData = Array.from({ length: SHIFT_DURATION }, (_, i) => {
16618
- const actualHour = (shiftStartTime.hour + i) % 24;
16619
- const idleArray = idleTimeHourly?.[actualHour.toString()] || [];
16620
- const idleMinutes = idleArray.filter((val) => val === "1").length;
16621
- return {
16622
- hour: formatHour(i),
16623
- timeRange: formatTimeRange(i),
16624
- output: animatedData[i] || 0,
16625
- originalOutput: data[i] || 0,
16626
- // Keep original data for labels
16627
- color: (animatedData[i] || 0) >= Math.round(pphThreshold) ? "#00AB45" : "#E34329",
16628
- idleMinutes,
16629
- idleArray
16630
- };
16631
- });
16809
+ }, [shiftStartTime.decimalHour]);
16810
+ const chartData = React14__default.useMemo(() => {
16811
+ return Array.from({ length: SHIFT_DURATION }, (_, i) => {
16812
+ const actualHour = (shiftStartTime.hour + i) % 24;
16813
+ const idleArray = idleTimeHourly?.[actualHour.toString()] || [];
16814
+ const idleMinutes = idleArray.filter((val) => val === "1").length;
16815
+ return {
16816
+ hour: formatHour(i),
16817
+ timeRange: formatTimeRange(i),
16818
+ output: animatedData[i] || 0,
16819
+ originalOutput: data[i] || 0,
16820
+ // Keep original data for labels
16821
+ color: (animatedData[i] || 0) >= Math.round(pphThreshold) ? "#00AB45" : "#E34329",
16822
+ idleMinutes,
16823
+ idleArray
16824
+ };
16825
+ });
16826
+ }, [animatedData, data, pphThreshold, idleTimeHourly, shiftStartTime.hour, formatHour, formatTimeRange]);
16632
16827
  const maxYValue = Math.ceil(pphThreshold * 1.5);
16633
16828
  const generateYAxisTicks = () => {
16634
16829
  const targetValue = Math.round(pphThreshold);
@@ -16721,10 +16916,10 @@ var HourlyOutputChart = ({
16721
16916
  contentStyle: {
16722
16917
  backgroundColor: "white",
16723
16918
  border: "none",
16724
- borderRadius: "8px",
16725
- boxShadow: "0 4px 12px rgba(0,0,0,0.1)",
16726
- padding: "8px 12px",
16727
- fontSize: "13px"
16919
+ borderRadius: "12px",
16920
+ boxShadow: "0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)",
16921
+ padding: "0",
16922
+ fontSize: "14px"
16728
16923
  },
16729
16924
  content: (props) => {
16730
16925
  if (!props.active || !props.payload || props.payload.length === 0) return null;
@@ -16758,48 +16953,54 @@ var HourlyOutputChart = ({
16758
16953
  const hour12 = hour === 0 ? 12 : hour > 12 ? hour - 12 : hour;
16759
16954
  return `${hour12}:${minute.toString().padStart(2, "0")} ${period}`;
16760
16955
  };
16761
- return /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-lg shadow-lg p-3 min-w-[180px]", children: [
16762
- /* @__PURE__ */ jsx("p", { className: "font-semibold text-gray-700 mb-2", children: data2.timeRange }),
16763
- /* @__PURE__ */ jsxs("p", { className: "text-gray-600", children: [
16764
- "Output: ",
16765
- /* @__PURE__ */ jsxs("span", { className: "font-medium text-gray-800", children: [
16766
- Math.round(data2.output),
16767
- " units"
16768
- ] })
16769
- ] }),
16770
- showIdleTime && data2.idleMinutes > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
16771
- /* @__PURE__ */ jsxs("p", { className: "text-gray-600 mb-1 border-t pt-1 mt-1", children: [
16772
- "Idle Time: ",
16773
- /* @__PURE__ */ jsxs("span", { className: "font-medium text-gray-700", children: [
16774
- data2.idleMinutes,
16775
- " minutes"
16956
+ return /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-xl shadow-xl border border-gray-100 p-4 min-w-[220px]", children: [
16957
+ /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between mb-3", children: /* @__PURE__ */ jsx("p", { className: "font-semibold text-gray-900 text-sm", children: data2.timeRange }) }),
16958
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
16959
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
16960
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-gray-500", children: "Output" }),
16961
+ /* @__PURE__ */ jsxs("span", { className: "font-semibold text-gray-900 text-sm", children: [
16962
+ Math.round(data2.output),
16963
+ " units"
16776
16964
  ] })
16777
16965
  ] }),
16778
- idleRanges.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mt-2 text-xs", children: [
16779
- /* @__PURE__ */ jsx("p", { className: "font-medium text-gray-600 mb-1", children: "Idle periods:" }),
16780
- /* @__PURE__ */ jsx("div", { className: "space-y-0.5 max-h-32 overflow-y-auto", children: idleRanges.map((range, index) => {
16781
- const duration = range.end - range.start + 1;
16782
- const startTime = formatIdleTimestamp(range.start);
16783
- const endTime = formatIdleTimestamp(range.end + 1);
16784
- return /* @__PURE__ */ jsxs("div", { className: "text-gray-500 flex items-center gap-1", children: [
16785
- /* @__PURE__ */ jsx("span", { className: "inline-block w-1 h-1 bg-gray-400 rounded-full" }),
16786
- duration === 1 ? /* @__PURE__ */ jsxs("span", { children: [
16787
- startTime,
16788
- " ",
16789
- /* @__PURE__ */ jsx("span", { className: "text-gray-400", children: "(1 min)" })
16790
- ] }) : /* @__PURE__ */ jsxs("span", { children: [
16791
- startTime,
16792
- " - ",
16793
- endTime,
16794
- " ",
16795
- /* @__PURE__ */ jsxs("span", { className: "text-gray-400", children: [
16796
- "(",
16797
- duration,
16798
- " min)"
16799
- ] })
16800
- ] })
16801
- ] }, index);
16802
- }) })
16966
+ showIdleTime && data2.idleMinutes > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
16967
+ /* @__PURE__ */ jsx("div", { className: "border-t border-gray-100 pt-2", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
16968
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-gray-500", children: "Idle Time" }),
16969
+ /* @__PURE__ */ jsxs("span", { className: "font-semibold text-orange-600 text-sm", children: [
16970
+ data2.idleMinutes,
16971
+ " minutes"
16972
+ ] })
16973
+ ] }) }),
16974
+ idleRanges.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mt-3 bg-gray-50 rounded-lg p-2.5", children: [
16975
+ /* @__PURE__ */ jsx("p", { className: "font-medium text-gray-700 text-xs mb-2", children: "Idle periods:" }),
16976
+ /* @__PURE__ */ jsx("div", { className: "space-y-1 max-h-32 overflow-y-auto pr-1", children: idleRanges.map((range, index) => {
16977
+ const duration = range.end - range.start + 1;
16978
+ const startTime = formatIdleTimestamp(range.start);
16979
+ const endTime = formatIdleTimestamp(range.end + 1);
16980
+ return /* @__PURE__ */ jsxs("div", { className: "text-gray-600 flex items-center gap-2 text-xs", children: [
16981
+ /* @__PURE__ */ jsx("span", { className: "inline-block w-1.5 h-1.5 bg-orange-400 rounded-full flex-shrink-0" }),
16982
+ /* @__PURE__ */ jsx("span", { children: duration === 1 ? /* @__PURE__ */ jsxs(Fragment, { children: [
16983
+ startTime,
16984
+ " ",
16985
+ /* @__PURE__ */ jsxs("span", { className: "text-gray-400", children: [
16986
+ "(",
16987
+ duration,
16988
+ " min)"
16989
+ ] })
16990
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
16991
+ startTime,
16992
+ " - ",
16993
+ endTime,
16994
+ " ",
16995
+ /* @__PURE__ */ jsxs("span", { className: "text-gray-400", children: [
16996
+ "(",
16997
+ duration,
16998
+ " min)"
16999
+ ] })
17000
+ ] }) })
17001
+ ] }, index);
17002
+ }) })
17003
+ ] })
16803
17004
  ] })
16804
17005
  ] })
16805
17006
  ] });
@@ -16889,10 +17090,40 @@ var HourlyOutputChart = ({
16889
17090
  radius: [10, 10, 0, 0],
16890
17091
  fill: "url(#idlePattern)",
16891
17092
  opacity: 0.7,
16892
- isAnimationActive: true,
16893
- animationBegin: 200,
16894
- animationDuration: 800,
16895
- animationEasing: "ease-out"
17093
+ isAnimationActive: shouldAnimateIdle,
17094
+ animationBegin: shouldAnimateIdle ? 200 : 0,
17095
+ animationDuration: shouldAnimateIdle ? 800 : 0,
17096
+ animationEasing: "ease-out",
17097
+ children: /* @__PURE__ */ jsx(
17098
+ LabelList,
17099
+ {
17100
+ dataKey: "idleMinutes",
17101
+ position: "top",
17102
+ content: (props) => {
17103
+ const { x, y, width, value } = props;
17104
+ if (!value || value === 0) return null;
17105
+ return /* @__PURE__ */ jsxs(
17106
+ "text",
17107
+ {
17108
+ x: x + width / 2,
17109
+ y: y - 2,
17110
+ textAnchor: "middle",
17111
+ fontSize: "9",
17112
+ fontWeight: "600",
17113
+ fill: "#6b7280",
17114
+ style: {
17115
+ opacity: 1,
17116
+ pointerEvents: "none"
17117
+ },
17118
+ children: [
17119
+ value,
17120
+ "m"
17121
+ ]
17122
+ }
17123
+ );
17124
+ }
17125
+ }
17126
+ )
16896
17127
  }
16897
17128
  ),
16898
17129
  /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs("pattern", { id: "idlePattern", patternUnits: "userSpaceOnUse", width: "4", height: "4", children: [
@@ -16905,155 +17136,479 @@ var HourlyOutputChart = ({
16905
17136
  renderLegend()
16906
17137
  ] });
16907
17138
  };
16908
- var defaults = {
16909
- Card,
16910
- CardHeader,
16911
- CardTitle,
16912
- CardDescription,
16913
- CardContent,
16914
- CardFooter,
16915
- Button,
16916
- HourlyOutputChart
16917
- };
16918
- var RegistryCtx = createContext(defaults);
16919
- var useRegistry = () => {
16920
- const context = useContext(RegistryCtx);
16921
- if (!context) {
16922
- throw new Error("useRegistry must be used within a RegistryProvider");
16923
- }
16924
- return context;
16925
- };
16926
- function RegistryProvider({
16927
- children,
16928
- components = {}
16929
- }) {
16930
- if (process.env.NODE_ENV === "development") {
16931
- const validKeys = Object.keys(defaults);
16932
- Object.keys(components).forEach((key) => {
16933
- if (!validKeys.includes(key)) {
16934
- console.warn(`[RegistryProvider] Unknown component key: "${key}". Valid keys are: ${validKeys.join(", ")}`);
16935
- }
16936
- });
16937
- }
16938
- const mergedComponents = { ...defaults, ...components };
16939
- return /* @__PURE__ */ jsx(RegistryCtx.Provider, { value: mergedComponents, children });
16940
- }
16941
- function withRegistry(Component3) {
16942
- function WithRegistry(props) {
16943
- useRegistry();
16944
- return /* @__PURE__ */ jsx(Component3, { ...props });
16945
- }
16946
- WithRegistry.displayName = `withRegistry(${Component3.displayName || Component3.name})`;
16947
- return WithRegistry;
16948
- }
16949
- var HourlyOutputChart2 = (props) => {
16950
- const { HourlyOutputChart: RegisteredHourlyOutputChart } = useRegistry();
16951
- return /* @__PURE__ */ jsx(RegisteredHourlyOutputChart, { ...props });
16952
- };
16953
- var HourlyComplianceDot = (props) => {
16954
- const { cx: cx2, cy, index, payload, targetCompliance } = props;
16955
- const complianceValue = payload?.compliance;
16956
- if (typeof index !== "number" || index % 60 !== 0 || typeof complianceValue !== "number" || complianceValue === null) {
16957
- return null;
16958
- }
16959
- const roundedValue = Math.round(complianceValue);
16960
- const isAboveTarget = roundedValue >= targetCompliance;
16961
- const labelColor = isAboveTarget ? "#10B981" : "#EF4444";
16962
- return /* @__PURE__ */ jsxs("g", { children: [
16963
- /* @__PURE__ */ jsx("circle", { cx: cx2, cy, r: 4, fill: "#EF4444" }),
16964
- " ",
16965
- /* @__PURE__ */ jsx(
16966
- "text",
16967
- {
16968
- x: cx2,
16969
- y: cy ? cy - 10 : 0,
16970
- dy: 0,
16971
- textAnchor: "middle",
16972
- fill: labelColor,
16973
- fontSize: 12,
16974
- fontWeight: 600,
16975
- children: `${roundedValue}%`
16976
- }
16977
- )
16978
- ] });
17139
+ var TREND_STYLES = {
17140
+ 0: { arrow: "\u2193", color: "text-red-500 font-bold text-shadow" },
17141
+ // Down
17142
+ 1: { arrow: "\u2013", color: "text-gray-500 font-bold text-shadow" },
17143
+ // Unchanged
17144
+ 2: { arrow: "\u2191", color: "text-green-500 font-bold text-shadow" }
17145
+ // Up
16979
17146
  };
16980
- var SOPComplianceChart = ({
16981
- data = [],
16982
- targetCompliance = 95,
16983
- shiftStart,
17147
+ var getTrendArrowAndColor = (trend) => TREND_STYLES[trend] || { arrow: "", color: "" };
17148
+ var VideoCard = React14__default.memo(({
17149
+ workspace,
17150
+ hlsUrl,
17151
+ shouldPlay,
17152
+ onClick,
17153
+ onFatalError,
17154
+ isVeryLowEfficiency = false,
16984
17155
  className = ""
16985
17156
  }) => {
16986
- const getHourFromTimeString = (timeStr) => {
16987
- const [hours, minutes] = timeStr.split(":");
16988
- return parseInt(hours);
16989
- };
16990
- const shiftStartHour = getHourFromTimeString(shiftStart);
16991
- const SHIFT_DURATION_HOURS = 9;
16992
- const MINUTES_PER_HOUR = 60;
16993
- const TOTAL_MINUTES = SHIFT_DURATION_HOURS * MINUTES_PER_HOUR;
16994
- const mockData = Array.from(
16995
- { length: TOTAL_MINUTES },
16996
- () => Math.floor(Math.random() * 10) + 90
16997
- );
16998
- const [animatedData, setAnimatedData] = useState([]);
16999
- const prevDataRef = useRef([]);
17000
- const animationFrameRef = useRef(null);
17001
- const animateToNewData = useCallback((targetData) => {
17002
- const startData = [...prevDataRef.current];
17003
- while (startData.length < targetData.length) {
17004
- startData.push(startData.length > 0 ? startData[startData.length - 1] : 0);
17005
- }
17006
- const startTime = performance.now();
17007
- const duration = 400;
17008
- const animate = (currentTime) => {
17009
- const elapsed = currentTime - startTime;
17010
- const progress6 = Math.min(elapsed / duration, 1);
17011
- const easeOutQuad = (t) => 1 - (1 - t) * (1 - t);
17012
- const easedProgress = easeOutQuad(progress6);
17013
- const newData = startData.map((start, index) => {
17014
- if (index >= targetData.length) return start;
17015
- const target = targetData[index];
17016
- const change = target - start;
17017
- return start + change * easedProgress;
17018
- });
17019
- setAnimatedData(newData);
17020
- prevDataRef.current = newData;
17021
- if (progress6 < 1) {
17022
- animationFrameRef.current = requestAnimationFrame(animate);
17023
- } else {
17024
- setAnimatedData(targetData);
17025
- prevDataRef.current = targetData;
17026
- }
17027
- };
17028
- if (animationFrameRef.current) {
17029
- cancelAnimationFrame(animationFrameRef.current);
17030
- }
17031
- animationFrameRef.current = requestAnimationFrame(animate);
17032
- }, []);
17033
- useEffect(() => {
17034
- if (data.length === 0) {
17035
- if (prevDataRef.current.length === 0) {
17036
- animateToNewData(mockData);
17037
- }
17038
- return;
17157
+ const videoRef = useRef(null);
17158
+ useHlsStream(videoRef, {
17159
+ src: hlsUrl,
17160
+ shouldPlay,
17161
+ onFatalError: onFatalError ?? (() => throttledReloadDashboard())
17162
+ });
17163
+ const displayName = getWorkspaceDisplayName(workspace.workspace_name);
17164
+ workspace.workspace_uuid || workspace.workspace_name;
17165
+ const getEfficiencyOverlayColor = (efficiency) => {
17166
+ if (efficiency >= 80) {
17167
+ return "bg-[#00D654]/25";
17168
+ } else if (efficiency >= 70) {
17169
+ return "bg-[#FFD700]/30";
17170
+ } else {
17171
+ return "bg-[#FF2D0A]/30";
17039
17172
  }
17040
- const actualData = [...data];
17041
- if (JSON.stringify(actualData) !== JSON.stringify(prevDataRef.current)) {
17042
- animateToNewData(actualData);
17173
+ };
17174
+ const getEfficiencyBarColor = (efficiency) => {
17175
+ if (efficiency >= 80) {
17176
+ return "bg-[#00AB45]";
17177
+ } else if (efficiency >= 70) {
17178
+ return "bg-[#FFB020]";
17179
+ } else {
17180
+ return "bg-[#E34329]";
17043
17181
  }
17044
- return () => {
17045
- if (animationFrameRef.current) {
17046
- cancelAnimationFrame(animationFrameRef.current);
17047
- }
17048
- };
17049
- }, [data, animateToNewData, mockData]);
17050
- const formatTime2 = (minuteIndex) => {
17051
- const totalMinutes = shiftStartHour * 60 + minuteIndex;
17052
- const hours = Math.floor(totalMinutes / 60) % 24;
17053
- const minutes = totalMinutes % 60;
17054
- const formattedHour = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours;
17055
- const ampm = hours >= 12 ? "PM" : "AM";
17056
- return `${formattedHour}:${minutes.toString().padStart(2, "0")} ${ampm}`;
17182
+ };
17183
+ const efficiencyOverlayClass = getEfficiencyOverlayColor(workspace.efficiency);
17184
+ const efficiencyBarClass = getEfficiencyBarColor(workspace.efficiency);
17185
+ const trendInfo = workspace.trend !== void 0 ? getTrendArrowAndColor(workspace.trend) : null;
17186
+ const handleClick = useCallback(() => {
17187
+ if (onClick) {
17188
+ onClick();
17189
+ }
17190
+ }, [onClick]);
17191
+ return /* @__PURE__ */ jsxs(
17192
+ "div",
17193
+ {
17194
+ className: `workspace-card relative bg-gray-950 rounded-md overflow-hidden cursor-pointer transform hover:scale-[1.005] transition-transform duration-200 shadow-sm ${className}`,
17195
+ style: { width: "100%", height: "100%" },
17196
+ onClick: handleClick,
17197
+ title: displayName,
17198
+ tabIndex: 0,
17199
+ "aria-label": `Open workspace ${displayName}`,
17200
+ onKeyDown: (e) => {
17201
+ if (e.key === "Enter" || e.key === " ") {
17202
+ e.preventDefault();
17203
+ handleClick();
17204
+ }
17205
+ },
17206
+ children: [
17207
+ isVeryLowEfficiency && /* @__PURE__ */ jsx("div", { className: "absolute top-1 left-2 z-30", children: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
17208
+ /* @__PURE__ */ jsx("div", { className: "absolute -inset-1 bg-red-400/50 rounded-full blur-sm animate-pulse" }),
17209
+ /* @__PURE__ */ jsx("div", { className: "absolute -inset-0.5 bg-red-500/30 rounded-full blur-md animate-ping [animation-duration:1.5s]" }),
17210
+ /* @__PURE__ */ jsx("div", { className: "bg-[#E34329] w-5 h-5 rounded-full flex items-center justify-center text-white font-bold text-xs shadow-lg ring-2 ring-red-400/40 border border-red-400/80 animate-pulse", children: "!" })
17211
+ ] }) }),
17212
+ /* @__PURE__ */ jsxs("div", { className: "relative w-full h-full overflow-hidden bg-black", children: [
17213
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-black z-0", children: /* @__PURE__ */ jsxs("div", { className: "animate-pulse flex flex-col items-center", children: [
17214
+ /* @__PURE__ */ jsx(Camera, { className: "w-6 h-6 text-gray-500" }),
17215
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-gray-500 mt-1", children: "Loading..." })
17216
+ ] }) }),
17217
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 z-10", children: /* @__PURE__ */ jsx(
17218
+ "video",
17219
+ {
17220
+ ref: videoRef,
17221
+ className: "h-full w-full object-cover",
17222
+ playsInline: true,
17223
+ muted: true,
17224
+ disablePictureInPicture: true,
17225
+ controlsList: "nodownload noplaybackrate"
17226
+ }
17227
+ ) }),
17228
+ /* @__PURE__ */ jsx("div", { className: `absolute inset-0 z-20 pointer-events-none ${efficiencyOverlayClass}` }),
17229
+ /* @__PURE__ */ jsxs("div", { className: "absolute top-2 right-2 z-30 bg-black/70 backdrop-blur-sm rounded px-2 py-0.5 text-white text-xs font-semibold border border-white/10", children: [
17230
+ Math.round(workspace.efficiency),
17231
+ "%"
17232
+ ] }),
17233
+ /* @__PURE__ */ jsx("div", { className: "absolute bottom-0 left-0 right-0 h-1 bg-black/50 z-30", children: /* @__PURE__ */ jsx(
17234
+ "div",
17235
+ {
17236
+ className: `h-full ${efficiencyBarClass} transition-all duration-500`,
17237
+ style: { width: `${Math.min(100, workspace.efficiency)}%` }
17238
+ }
17239
+ ) })
17240
+ ] }),
17241
+ /* @__PURE__ */ jsxs("div", { className: "absolute bottom-0 left-0 right-0 bg-black bg-opacity-60 p-1.5 flex justify-between items-center z-10", children: [
17242
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
17243
+ /* @__PURE__ */ jsx(Camera, { size: 12, className: "text-white" }),
17244
+ /* @__PURE__ */ jsx("p", { className: "text-white text-xs font-medium tracking-wide", children: displayName })
17245
+ ] }),
17246
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
17247
+ trendInfo && /* @__PURE__ */ jsx(
17248
+ "div",
17249
+ {
17250
+ className: `text-lg ${trendInfo.color}`,
17251
+ style: { lineHeight: 1, display: "flex", alignItems: "center" },
17252
+ children: trendInfo.arrow
17253
+ }
17254
+ ),
17255
+ /* @__PURE__ */ jsx("div", { className: "w-1.5 h-1.5 rounded-full bg-green-500" }),
17256
+ /* @__PURE__ */ jsx("span", { className: "text-white text-xs", children: "Live" })
17257
+ ] })
17258
+ ] })
17259
+ ]
17260
+ }
17261
+ );
17262
+ }, (prevProps, nextProps) => {
17263
+ return prevProps.workspace.workspace_uuid === nextProps.workspace.workspace_uuid && prevProps.workspace.workspace_name === nextProps.workspace.workspace_name && Math.abs(prevProps.workspace.efficiency - nextProps.workspace.efficiency) < 1 && prevProps.hlsUrl === nextProps.hlsUrl && prevProps.shouldPlay === nextProps.shouldPlay;
17264
+ });
17265
+ VideoCard.displayName = "VideoCard";
17266
+ var DEFAULT_WORKSPACE_HLS_URLS = {
17267
+ "WS1": "https://dnh-hls.optifye.ai/cam1/index.m3u8",
17268
+ "WS2": "https://dnh-hls.optifye.ai/cam2/index.m3u8",
17269
+ "WS3": "https://dnh-hls.optifye.ai/cam3/index.m3u8",
17270
+ "WS4": "https://dnh-hls.optifye.ai/cam3/index.m3u8",
17271
+ "WS01": "https://59.144.218.58:8443/camera6.m3u8",
17272
+ "WS02": "https://59.144.218.58:8443/camera2.m3u8",
17273
+ "WS03": "https://59.144.218.58:8443/camera3.m3u8",
17274
+ "WS04": "https://59.144.218.58:8443/camera4.m3u8",
17275
+ "WS05": "https://59.144.218.58:8443/camera1.m3u8",
17276
+ "WS06": "https://59.144.218.58:8443/camera5.m3u8"
17277
+ };
17278
+ var DEFAULT_HLS_URL = "https://192.168.5.9:8443/cam1.m3u8";
17279
+ var VideoGridView = React14__default.memo(({
17280
+ workspaces,
17281
+ selectedLine,
17282
+ className = "",
17283
+ lineIdMapping = {},
17284
+ videoSources = {}
17285
+ }) => {
17286
+ const router = useRouter();
17287
+ const containerRef = useRef(null);
17288
+ const observerRef = useRef(null);
17289
+ const [gridCols, setGridCols] = useState(4);
17290
+ const [visibleWorkspaces, setVisibleWorkspaces] = useState(/* @__PURE__ */ new Set());
17291
+ const mergedVideoSources = {
17292
+ defaultHlsUrl: videoSources.defaultHlsUrl || DEFAULT_HLS_URL,
17293
+ workspaceHlsUrls: { ...DEFAULT_WORKSPACE_HLS_URLS, ...videoSources.workspaceHlsUrls }
17294
+ };
17295
+ const getWorkspaceHlsUrl = useCallback((workspaceName) => {
17296
+ const wsName = workspaceName.toUpperCase();
17297
+ return mergedVideoSources.workspaceHlsUrls[wsName] || mergedVideoSources.defaultHlsUrl;
17298
+ }, [mergedVideoSources]);
17299
+ const veryLowEfficiencyWorkspaces = useMemo(() => {
17300
+ return new Set(
17301
+ workspaces.filter((w) => w.efficiency < 50 && w.efficiency >= 10).map((w) => w.workspace_name)
17302
+ );
17303
+ }, [workspaces]);
17304
+ const filteredWorkspaces = useMemo(() => {
17305
+ return selectedLine === 1 ? workspaces.filter((w) => {
17306
+ if (w.workspace_name === "WS5-5") return true;
17307
+ if (w.workspace_name === "WS32-5") return false;
17308
+ try {
17309
+ const wsNumber = parseInt(w.workspace_name.replace("WS", ""));
17310
+ return wsNumber >= 1 && wsNumber <= 22;
17311
+ } catch {
17312
+ return true;
17313
+ }
17314
+ }) : selectedLine === 2 ? workspaces.filter((w) => {
17315
+ if (w.workspace_name === "WS5-5") return false;
17316
+ if (w.workspace_name === "WS32-5") return true;
17317
+ try {
17318
+ const wsNumber = parseInt(w.workspace_name.replace("WS", ""));
17319
+ return wsNumber >= 23 && wsNumber <= 44;
17320
+ } catch {
17321
+ return false;
17322
+ }
17323
+ }) : workspaces;
17324
+ }, [workspaces, selectedLine]);
17325
+ const calculateOptimalGrid = useCallback(() => {
17326
+ if (!containerRef.current) return;
17327
+ const containerPadding = 16;
17328
+ const containerWidth = containerRef.current.clientWidth - containerPadding;
17329
+ const containerHeight = containerRef.current.clientHeight - containerPadding;
17330
+ const count = filteredWorkspaces.length;
17331
+ if (count === 0) {
17332
+ setGridCols(1);
17333
+ return;
17334
+ }
17335
+ let bestCols = 1;
17336
+ let bestScore = 0;
17337
+ const targetAspectRatio = 16 / 9;
17338
+ const gap = 8;
17339
+ const maxCols = Math.min(count, 6);
17340
+ for (let cols = 1; cols <= maxCols; cols++) {
17341
+ const rows = Math.ceil(count / cols);
17342
+ const availableWidth = containerWidth - gap * (cols - 1);
17343
+ const availableHeight = containerHeight - gap * (rows - 1);
17344
+ const cellWidth = availableWidth / cols;
17345
+ const cellHeight = availableHeight / rows;
17346
+ const minCellWidth = containerWidth < 800 ? 120 : 150;
17347
+ const minCellHeight = containerHeight < 600 ? 80 : 100;
17348
+ if (cellWidth < minCellWidth || cellHeight < minCellHeight) continue;
17349
+ const totalUsedArea = cellWidth * cellHeight * count;
17350
+ const totalAvailableArea = containerWidth * containerHeight;
17351
+ const spaceUtilization = totalUsedArea / totalAvailableArea;
17352
+ const actualAspectRatio = cellWidth / cellHeight;
17353
+ const aspectRatioScore = 1 / (1 + Math.abs(actualAspectRatio - targetAspectRatio) * 0.3);
17354
+ const score = spaceUtilization * 0.9 + aspectRatioScore * 0.1;
17355
+ if (score > bestScore) {
17356
+ bestScore = score;
17357
+ bestCols = cols;
17358
+ }
17359
+ }
17360
+ if (bestScore === 0) {
17361
+ bestCols = Math.ceil(Math.sqrt(count));
17362
+ }
17363
+ setGridCols(bestCols);
17364
+ }, [filteredWorkspaces.length]);
17365
+ useEffect(() => {
17366
+ calculateOptimalGrid();
17367
+ const handleResize = () => calculateOptimalGrid();
17368
+ window.addEventListener("resize", handleResize);
17369
+ return () => window.removeEventListener("resize", handleResize);
17370
+ }, [calculateOptimalGrid]);
17371
+ useEffect(() => {
17372
+ if (!containerRef.current) return;
17373
+ const options = {
17374
+ root: null,
17375
+ rootMargin: "50px",
17376
+ threshold: 0.1
17377
+ };
17378
+ observerRef.current = new IntersectionObserver((entries) => {
17379
+ entries.forEach((entry) => {
17380
+ const workspaceId = entry.target.getAttribute("data-workspace-id");
17381
+ if (!workspaceId) return;
17382
+ setVisibleWorkspaces((prev) => {
17383
+ const next = new Set(prev);
17384
+ if (entry.isIntersecting) {
17385
+ next.add(workspaceId);
17386
+ } else {
17387
+ next.delete(workspaceId);
17388
+ }
17389
+ return next;
17390
+ });
17391
+ });
17392
+ }, options);
17393
+ const elements = containerRef.current.querySelectorAll("[data-workspace-id]");
17394
+ elements.forEach((el) => observerRef.current?.observe(el));
17395
+ return () => {
17396
+ observerRef.current?.disconnect();
17397
+ };
17398
+ }, [filteredWorkspaces]);
17399
+ const handleWorkspaceClick = useCallback((workspace) => {
17400
+ const workspaceId = workspace.workspace_uuid || workspace.workspace_name;
17401
+ trackCoreEvent("Workspace Detail Clicked", {
17402
+ workspace_name: workspace.workspace_name,
17403
+ workspace_id: workspaceId,
17404
+ view_type: "video_grid",
17405
+ performance_score: workspace.performance_score,
17406
+ efficiency: workspace.efficiency,
17407
+ action_count: workspace.action_count
17408
+ });
17409
+ const displayName = getWorkspaceDisplayName(workspace.workspace_name);
17410
+ const navParams = getWorkspaceNavigationParams(workspaceId, displayName);
17411
+ router.push(`/workspace/${workspaceId}${navParams}`);
17412
+ }, [router]);
17413
+ return /* @__PURE__ */ jsx("div", { className: `relative overflow-hidden h-full w-full ${className}`, children: /* @__PURE__ */ jsx("div", { ref: containerRef, className: "h-full w-full p-2", children: /* @__PURE__ */ jsx(
17414
+ "div",
17415
+ {
17416
+ className: "grid h-full w-full gap-2",
17417
+ style: {
17418
+ gridTemplateColumns: `repeat(${gridCols}, 1fr)`,
17419
+ gridTemplateRows: `repeat(${Math.ceil(filteredWorkspaces.length / gridCols)}, 1fr)`,
17420
+ minHeight: "100%"
17421
+ },
17422
+ children: filteredWorkspaces.sort((a, b) => {
17423
+ const aNum = parseInt(a.workspace_name.slice(2));
17424
+ const bNum = parseInt(b.workspace_name.slice(2));
17425
+ if (!selectedLine) {
17426
+ const aIsLine2 = a.line_id === lineIdMapping.line2;
17427
+ const bIsLine2 = b.line_id === lineIdMapping.line2;
17428
+ if (aIsLine2 !== bIsLine2) {
17429
+ return aIsLine2 ? 1 : -1;
17430
+ }
17431
+ }
17432
+ return aNum - bNum;
17433
+ }).map((workspace) => {
17434
+ const workspaceId = workspace.workspace_uuid || workspace.workspace_name;
17435
+ const isVisible = visibleWorkspaces.has(workspaceId);
17436
+ const isVeryLowEfficiency = veryLowEfficiencyWorkspaces.has(workspace.workspace_name);
17437
+ return /* @__PURE__ */ jsx(
17438
+ "div",
17439
+ {
17440
+ "data-workspace-id": workspaceId,
17441
+ className: "workspace-card relative min-h-0 min-w-0",
17442
+ style: { width: "100%", height: "100%" },
17443
+ children: /* @__PURE__ */ jsx(
17444
+ VideoCard,
17445
+ {
17446
+ workspace,
17447
+ hlsUrl: getWorkspaceHlsUrl(workspace.workspace_name),
17448
+ shouldPlay: isVisible,
17449
+ onClick: () => handleWorkspaceClick(workspace),
17450
+ onFatalError: throttledReloadDashboard,
17451
+ isVeryLowEfficiency
17452
+ }
17453
+ )
17454
+ },
17455
+ workspaceId
17456
+ );
17457
+ })
17458
+ }
17459
+ ) }) });
17460
+ });
17461
+ VideoGridView.displayName = "VideoGridView";
17462
+ var defaults = {
17463
+ Card,
17464
+ CardHeader,
17465
+ CardTitle,
17466
+ CardDescription,
17467
+ CardContent,
17468
+ CardFooter,
17469
+ Button,
17470
+ HourlyOutputChart,
17471
+ VideoGridView
17472
+ };
17473
+ var RegistryCtx = createContext(defaults);
17474
+ var useRegistry = () => {
17475
+ const context = useContext(RegistryCtx);
17476
+ if (!context) {
17477
+ throw new Error("useRegistry must be used within a RegistryProvider");
17478
+ }
17479
+ return context;
17480
+ };
17481
+ function RegistryProvider({
17482
+ children,
17483
+ components = {}
17484
+ }) {
17485
+ if (process.env.NODE_ENV === "development") {
17486
+ const validKeys = Object.keys(defaults);
17487
+ Object.keys(components).forEach((key) => {
17488
+ if (!validKeys.includes(key)) {
17489
+ console.warn(`[RegistryProvider] Unknown component key: "${key}". Valid keys are: ${validKeys.join(", ")}`);
17490
+ }
17491
+ });
17492
+ }
17493
+ const mergedComponents = { ...defaults, ...components };
17494
+ return /* @__PURE__ */ jsx(RegistryCtx.Provider, { value: mergedComponents, children });
17495
+ }
17496
+ function withRegistry(Component3) {
17497
+ function WithRegistry(props) {
17498
+ useRegistry();
17499
+ return /* @__PURE__ */ jsx(Component3, { ...props });
17500
+ }
17501
+ WithRegistry.displayName = `withRegistry(${Component3.displayName || Component3.name})`;
17502
+ return WithRegistry;
17503
+ }
17504
+ var HourlyOutputChart2 = (props) => {
17505
+ const { HourlyOutputChart: RegisteredHourlyOutputChart } = useRegistry();
17506
+ return /* @__PURE__ */ jsx(RegisteredHourlyOutputChart, { ...props });
17507
+ };
17508
+ var HourlyComplianceDot = (props) => {
17509
+ const { cx: cx2, cy, index, payload, targetCompliance } = props;
17510
+ const complianceValue = payload?.compliance;
17511
+ if (typeof index !== "number" || index % 60 !== 0 || typeof complianceValue !== "number" || complianceValue === null) {
17512
+ return null;
17513
+ }
17514
+ const roundedValue = Math.round(complianceValue);
17515
+ const isAboveTarget = roundedValue >= targetCompliance;
17516
+ const labelColor = isAboveTarget ? "#10B981" : "#EF4444";
17517
+ return /* @__PURE__ */ jsxs("g", { children: [
17518
+ /* @__PURE__ */ jsx("circle", { cx: cx2, cy, r: 4, fill: "#EF4444" }),
17519
+ " ",
17520
+ /* @__PURE__ */ jsx(
17521
+ "text",
17522
+ {
17523
+ x: cx2,
17524
+ y: cy ? cy - 10 : 0,
17525
+ dy: 0,
17526
+ textAnchor: "middle",
17527
+ fill: labelColor,
17528
+ fontSize: 12,
17529
+ fontWeight: 600,
17530
+ children: `${roundedValue}%`
17531
+ }
17532
+ )
17533
+ ] });
17534
+ };
17535
+ var SOPComplianceChart = ({
17536
+ data = [],
17537
+ targetCompliance = 95,
17538
+ shiftStart,
17539
+ className = ""
17540
+ }) => {
17541
+ const getHourFromTimeString = (timeStr) => {
17542
+ const [hours, minutes] = timeStr.split(":");
17543
+ return parseInt(hours);
17544
+ };
17545
+ const shiftStartHour = getHourFromTimeString(shiftStart);
17546
+ const SHIFT_DURATION_HOURS = 9;
17547
+ const MINUTES_PER_HOUR = 60;
17548
+ const TOTAL_MINUTES = SHIFT_DURATION_HOURS * MINUTES_PER_HOUR;
17549
+ const mockData = Array.from(
17550
+ { length: TOTAL_MINUTES },
17551
+ () => Math.floor(Math.random() * 10) + 90
17552
+ );
17553
+ const [animatedData, setAnimatedData] = useState([]);
17554
+ const prevDataRef = useRef([]);
17555
+ const animationFrameRef = useRef(null);
17556
+ const animateToNewData = useCallback((targetData) => {
17557
+ const startData = [...prevDataRef.current];
17558
+ while (startData.length < targetData.length) {
17559
+ startData.push(startData.length > 0 ? startData[startData.length - 1] : 0);
17560
+ }
17561
+ const startTime = performance.now();
17562
+ const duration = 400;
17563
+ const animate = (currentTime) => {
17564
+ const elapsed = currentTime - startTime;
17565
+ const progress6 = Math.min(elapsed / duration, 1);
17566
+ const easeOutQuad = (t) => 1 - (1 - t) * (1 - t);
17567
+ const easedProgress = easeOutQuad(progress6);
17568
+ const newData = startData.map((start, index) => {
17569
+ if (index >= targetData.length) return start;
17570
+ const target = targetData[index];
17571
+ const change = target - start;
17572
+ return start + change * easedProgress;
17573
+ });
17574
+ setAnimatedData(newData);
17575
+ prevDataRef.current = newData;
17576
+ if (progress6 < 1) {
17577
+ animationFrameRef.current = requestAnimationFrame(animate);
17578
+ } else {
17579
+ setAnimatedData(targetData);
17580
+ prevDataRef.current = targetData;
17581
+ }
17582
+ };
17583
+ if (animationFrameRef.current) {
17584
+ cancelAnimationFrame(animationFrameRef.current);
17585
+ }
17586
+ animationFrameRef.current = requestAnimationFrame(animate);
17587
+ }, []);
17588
+ useEffect(() => {
17589
+ if (data.length === 0) {
17590
+ if (prevDataRef.current.length === 0) {
17591
+ animateToNewData(mockData);
17592
+ }
17593
+ return;
17594
+ }
17595
+ const actualData = [...data];
17596
+ if (JSON.stringify(actualData) !== JSON.stringify(prevDataRef.current)) {
17597
+ animateToNewData(actualData);
17598
+ }
17599
+ return () => {
17600
+ if (animationFrameRef.current) {
17601
+ cancelAnimationFrame(animationFrameRef.current);
17602
+ }
17603
+ };
17604
+ }, [data, animateToNewData, mockData]);
17605
+ const formatTime2 = (minuteIndex) => {
17606
+ const totalMinutes = shiftStartHour * 60 + minuteIndex;
17607
+ const hours = Math.floor(totalMinutes / 60) % 24;
17608
+ const minutes = totalMinutes % 60;
17609
+ const formattedHour = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours;
17610
+ const ampm = hours >= 12 ? "PM" : "AM";
17611
+ return `${formattedHour}:${minutes.toString().padStart(2, "0")} ${ampm}`;
17057
17612
  };
17058
17613
  const chartData = Array.from({ length: TOTAL_MINUTES }, (_, index) => {
17059
17614
  const hasDataForMinute = index < animatedData.length - 10;
@@ -17321,7 +17876,7 @@ var EmptyStateMessage = ({
17321
17876
  iconClassName
17322
17877
  }) => {
17323
17878
  let IconContent = null;
17324
- if (React33__default.isValidElement(iconType)) {
17879
+ if (React14__default.isValidElement(iconType)) {
17325
17880
  IconContent = iconType;
17326
17881
  } else if (typeof iconType === "string") {
17327
17882
  const MappedIcon = IconMap[iconType];
@@ -17420,11 +17975,6 @@ var BreakNotificationPopup = ({
17420
17975
  }, 6e4);
17421
17976
  return () => clearInterval(timer);
17422
17977
  }, []);
17423
- useEffect(() => {
17424
- if (activeBreaks.length > 0) {
17425
- setIsDismissed(false);
17426
- }
17427
- }, [activeBreaks]);
17428
17978
  const handleDismiss = () => {
17429
17979
  setIsDismissed(true);
17430
17980
  onDismiss?.();
@@ -17447,57 +17997,54 @@ var BreakNotificationPopup = ({
17447
17997
  animate: { opacity: 1, x: 0, y: 0 },
17448
17998
  exit: { opacity: 0, x: 100, y: -20 },
17449
17999
  transition: { duration: 0.3, ease: "easeOut" },
17450
- className: `fixed top-4 right-4 z-50 max-w-sm w-full ${className}`,
17451
- children: /* @__PURE__ */ jsxs("div", { className: "bg-card text-card-foreground rounded-lg border shadow-sm overflow-hidden", children: [
17452
- activeBreaks.map((breakItem, index) => /* @__PURE__ */ jsx(
17453
- motion.div,
17454
- {
17455
- initial: { opacity: 0, y: 20 },
17456
- animate: { opacity: 1, y: 0 },
17457
- transition: { delay: index * 0.1 },
17458
- className: `p-4 ${index > 0 ? "border-t" : ""}`,
17459
- children: /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between", children: [
17460
- /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-3 flex-1", children: [
17461
- /* @__PURE__ */ jsx("div", { className: "w-2 h-2 bg-amber-500 rounded-full animate-pulse flex-shrink-0 mt-2" }),
17462
- /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
17463
- /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between mb-2", children: /* @__PURE__ */ jsx("h4", { className: "font-medium text-sm", children: breakItem.remarks || "Break" }) }),
17464
- /* @__PURE__ */ jsx("div", { className: "space-y-1 text-xs text-muted-foreground", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
17465
- /* @__PURE__ */ jsxs("span", { children: [
17466
- "Duration: ",
17467
- breakItem.duration,
17468
- " min"
17469
- ] }),
17470
- /* @__PURE__ */ jsxs("span", { children: [
17471
- "Elapsed: ",
17472
- formatTime2(breakItem.elapsedMinutes)
17473
- ] })
17474
- ] }) }),
17475
- /* @__PURE__ */ jsx("div", { className: "mt-3", children: /* @__PURE__ */ jsx("div", { className: "w-full bg-muted rounded-full h-1", children: /* @__PURE__ */ jsx(
17476
- "div",
17477
- {
17478
- className: "h-1 bg-primary rounded-full transition-all duration-1000",
17479
- style: {
17480
- width: `${Math.min(100, Math.max(0, breakItem.elapsedMinutes / breakItem.duration * 100))}%`
17481
- }
18000
+ className: `fixed top-24 right-4 z-50 max-w-xs w-full ${className}`,
18001
+ children: /* @__PURE__ */ jsx("div", { className: "bg-white text-gray-900 rounded-lg border border-gray-200 shadow-lg overflow-hidden", children: activeBreaks.map((breakItem, index) => /* @__PURE__ */ jsx(
18002
+ motion.div,
18003
+ {
18004
+ initial: { opacity: 0, y: 20 },
18005
+ animate: { opacity: 1, y: 0 },
18006
+ transition: { delay: index * 0.1 },
18007
+ className: `p-3 ${index > 0 ? "border-t border-gray-100" : ""}`,
18008
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between", children: [
18009
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-3 flex-1", children: [
18010
+ /* @__PURE__ */ jsx("div", { className: "w-2 h-2 bg-amber-500 rounded-full animate-pulse flex-shrink-0 mt-2" }),
18011
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
18012
+ /* @__PURE__ */ jsx("div", { className: "mb-1", children: /* @__PURE__ */ jsx("h4", { className: "font-semibold text-sm text-gray-900", children: breakItem.remarks || "Break" }) }),
18013
+ /* @__PURE__ */ jsx("div", { className: "mb-2", children: /* @__PURE__ */ jsxs("div", { className: "text-xs text-gray-600 font-medium", children: [
18014
+ breakItem.startTime,
18015
+ " - ",
18016
+ breakItem.endTime
18017
+ ] }) }),
18018
+ /* @__PURE__ */ jsx("div", { className: "mb-2", children: /* @__PURE__ */ jsxs("div", { className: "text-xs text-gray-500", children: [
18019
+ formatTime2(breakItem.elapsedMinutes),
18020
+ " / ",
18021
+ breakItem.duration,
18022
+ " min"
18023
+ ] }) }),
18024
+ /* @__PURE__ */ jsx("div", { className: "mt-2", children: /* @__PURE__ */ jsx("div", { className: "w-full bg-gray-200 rounded-full h-1.5", children: /* @__PURE__ */ jsx(
18025
+ "div",
18026
+ {
18027
+ className: "h-1.5 bg-blue-500 rounded-full transition-all duration-1000",
18028
+ style: {
18029
+ width: `${Math.min(100, Math.max(0, breakItem.elapsedMinutes / breakItem.duration * 100))}%`
17482
18030
  }
17483
- ) }) })
17484
- ] })
17485
- ] }),
17486
- index === 0 && /* @__PURE__ */ jsx(
17487
- "button",
17488
- {
17489
- onClick: handleDismiss,
17490
- className: "ml-3 text-muted-foreground hover:text-foreground transition-colors p-1 -mt-1",
17491
- "aria-label": "Dismiss notification",
17492
- children: /* @__PURE__ */ jsx(X, { className: "w-4 h-4" })
17493
- }
17494
- )
17495
- ] })
17496
- },
17497
- `${breakItem.lineId}-${breakItem.startTime}-${index}`
17498
- )),
17499
- /* @__PURE__ */ jsx("div", { className: "px-4 py-2 text-xs text-muted-foreground text-center border-t", children: "Updates automatically every minute" })
17500
- ] })
18031
+ }
18032
+ ) }) })
18033
+ ] })
18034
+ ] }),
18035
+ index === 0 && /* @__PURE__ */ jsx(
18036
+ "button",
18037
+ {
18038
+ onClick: handleDismiss,
18039
+ className: "ml-2 text-gray-400 hover:text-gray-600 transition-colors p-1 rounded-full hover:bg-gray-100",
18040
+ "aria-label": "Dismiss notification",
18041
+ children: /* @__PURE__ */ jsx(X, { className: "w-3 h-3" })
18042
+ }
18043
+ )
18044
+ ] })
18045
+ },
18046
+ `${breakItem.lineId}-${breakItem.startTime}-${index}`
18047
+ )) })
17501
18048
  }
17502
18049
  ) });
17503
18050
  };
@@ -19887,7 +20434,7 @@ function Skeleton({ className, ...props }) {
19887
20434
  var Select = SelectPrimitive.Root;
19888
20435
  var SelectGroup = SelectPrimitive.Group;
19889
20436
  var SelectValue = SelectPrimitive.Value;
19890
- var SelectTrigger = React33.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
20437
+ var SelectTrigger = React14.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
19891
20438
  SelectPrimitive.Trigger,
19892
20439
  {
19893
20440
  ref,
@@ -19903,7 +20450,7 @@ var SelectTrigger = React33.forwardRef(({ className, children, ...props }, ref)
19903
20450
  }
19904
20451
  ));
19905
20452
  SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
19906
- var SelectScrollUpButton = React33.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
20453
+ var SelectScrollUpButton = React14.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
19907
20454
  SelectPrimitive.ScrollUpButton,
19908
20455
  {
19909
20456
  ref,
@@ -19913,7 +20460,7 @@ var SelectScrollUpButton = React33.forwardRef(({ className, ...props }, ref) =>
19913
20460
  }
19914
20461
  ));
19915
20462
  SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
19916
- var SelectScrollDownButton = React33.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
20463
+ var SelectScrollDownButton = React14.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
19917
20464
  SelectPrimitive.ScrollDownButton,
19918
20465
  {
19919
20466
  ref,
@@ -19923,7 +20470,7 @@ var SelectScrollDownButton = React33.forwardRef(({ className, ...props }, ref) =
19923
20470
  }
19924
20471
  ));
19925
20472
  SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
19926
- var SelectContent = React33.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
20473
+ var SelectContent = React14.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
19927
20474
  SelectPrimitive.Content,
19928
20475
  {
19929
20476
  ref,
@@ -19951,7 +20498,7 @@ var SelectContent = React33.forwardRef(({ className, children, position = "poppe
19951
20498
  }
19952
20499
  ) }));
19953
20500
  SelectContent.displayName = SelectPrimitive.Content.displayName;
19954
- var SelectLabel = React33.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
20501
+ var SelectLabel = React14.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
19955
20502
  SelectPrimitive.Label,
19956
20503
  {
19957
20504
  ref,
@@ -19960,7 +20507,7 @@ var SelectLabel = React33.forwardRef(({ className, ...props }, ref) => /* @__PUR
19960
20507
  }
19961
20508
  ));
19962
20509
  SelectLabel.displayName = SelectPrimitive.Label.displayName;
19963
- var SelectItem = React33.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
20510
+ var SelectItem = React14.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
19964
20511
  SelectPrimitive.Item,
19965
20512
  {
19966
20513
  ref,
@@ -19976,7 +20523,7 @@ var SelectItem = React33.forwardRef(({ className, children, ...props }, ref) =>
19976
20523
  }
19977
20524
  ));
19978
20525
  SelectItem.displayName = SelectPrimitive.Item.displayName;
19979
- var SelectSeparator = React33.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
20526
+ var SelectSeparator = React14.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
19980
20527
  SelectPrimitive.Separator,
19981
20528
  {
19982
20529
  ref,
@@ -21686,352 +22233,29 @@ var BottlenecksContent = ({
21686
22233
  handlePrevious();
21687
22234
  },
21688
22235
  disabled: currentIndex === 0 || filteredVideos.length === 0,
21689
- className: `absolute left-4 top-1/2 -translate-y-1/2 z-[102] p-3 rounded-full bg-black/30 hover:bg-black/50 text-white transition-all ${currentIndex === 0 ? "opacity-30 cursor-not-allowed" : ""}`,
21690
- "aria-label": "Previous video",
21691
- children: /* @__PURE__ */ jsx(ChevronLeft, { className: "h-7 w-7" })
21692
- }
21693
- ),
21694
- /* @__PURE__ */ jsx(
21695
- "button",
21696
- {
21697
- onClick: (e) => {
21698
- e.stopPropagation();
21699
- handleNext();
21700
- },
21701
- disabled: currentIndex === filteredVideos.length - 1 || filteredVideos.length === 0,
21702
- className: `absolute right-4 top-1/2 -translate-y-1/2 z-[102] p-3 rounded-full bg-black/30 hover:bg-black/50 text-white transition-all ${currentIndex === filteredVideos.length - 1 ? "opacity-30 cursor-not-allowed" : ""}`,
21703
- "aria-label": "Next video",
21704
- children: /* @__PURE__ */ jsx(ChevronRight, { className: "h-7 w-7" })
21705
- }
21706
- )
21707
- ]
21708
- }
21709
- )
21710
- ] });
21711
- };
21712
- var TREND_STYLES = {
21713
- 0: { arrow: "\u2193", color: "text-red-500 font-bold text-shadow" },
21714
- // Down
21715
- 1: { arrow: "\u2013", color: "text-gray-500 font-bold text-shadow" },
21716
- // Unchanged
21717
- 2: { arrow: "\u2191", color: "text-green-500 font-bold text-shadow" }
21718
- // Up
21719
- };
21720
- var getTrendArrowAndColor = (trend) => TREND_STYLES[trend] || { arrow: "", color: "" };
21721
- var VideoCard = React33__default.memo(({
21722
- workspace,
21723
- hlsUrl,
21724
- shouldPlay,
21725
- onClick,
21726
- onFatalError,
21727
- isVeryLowEfficiency = false,
21728
- className = ""
21729
- }) => {
21730
- const videoRef = useRef(null);
21731
- useHlsStream(videoRef, {
21732
- src: hlsUrl,
21733
- shouldPlay,
21734
- onFatalError: onFatalError ?? (() => throttledReloadDashboard())
21735
- });
21736
- const displayName = getWorkspaceDisplayName(workspace.workspace_name);
21737
- workspace.workspace_uuid || workspace.workspace_name;
21738
- const getEfficiencyOverlayColor = (efficiency) => {
21739
- if (efficiency >= 80) {
21740
- return "bg-[#00D654]/25";
21741
- } else if (efficiency >= 70) {
21742
- return "bg-[#FFD700]/30";
21743
- } else {
21744
- return "bg-[#FF2D0A]/30";
21745
- }
21746
- };
21747
- const getEfficiencyBarColor = (efficiency) => {
21748
- if (efficiency >= 80) {
21749
- return "bg-[#00AB45]";
21750
- } else if (efficiency >= 70) {
21751
- return "bg-[#FFB020]";
21752
- } else {
21753
- return "bg-[#E34329]";
21754
- }
21755
- };
21756
- const efficiencyOverlayClass = getEfficiencyOverlayColor(workspace.efficiency);
21757
- const efficiencyBarClass = getEfficiencyBarColor(workspace.efficiency);
21758
- const trendInfo = workspace.trend !== void 0 ? getTrendArrowAndColor(workspace.trend) : null;
21759
- const handleClick = useCallback(() => {
21760
- if (onClick) {
21761
- onClick();
21762
- }
21763
- }, [onClick]);
21764
- return /* @__PURE__ */ jsxs(
21765
- "div",
21766
- {
21767
- className: `workspace-card relative bg-gray-950 rounded-md overflow-hidden cursor-pointer transform hover:scale-[1.005] transition-transform duration-200 shadow-sm ${className}`,
21768
- style: { width: "100%", height: "100%" },
21769
- onClick: handleClick,
21770
- title: displayName,
21771
- tabIndex: 0,
21772
- "aria-label": `Open workspace ${displayName}`,
21773
- onKeyDown: (e) => {
21774
- if (e.key === "Enter" || e.key === " ") {
21775
- e.preventDefault();
21776
- handleClick();
21777
- }
21778
- },
21779
- children: [
21780
- isVeryLowEfficiency && /* @__PURE__ */ jsx("div", { className: "absolute top-1 left-2 z-30", children: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
21781
- /* @__PURE__ */ jsx("div", { className: "absolute -inset-1 bg-red-400/50 rounded-full blur-sm animate-pulse" }),
21782
- /* @__PURE__ */ jsx("div", { className: "absolute -inset-0.5 bg-red-500/30 rounded-full blur-md animate-ping [animation-duration:1.5s]" }),
21783
- /* @__PURE__ */ jsx("div", { className: "bg-[#E34329] w-5 h-5 rounded-full flex items-center justify-center text-white font-bold text-xs shadow-lg ring-2 ring-red-400/40 border border-red-400/80 animate-pulse", children: "!" })
21784
- ] }) }),
21785
- /* @__PURE__ */ jsxs("div", { className: "relative w-full h-full overflow-hidden bg-black", children: [
21786
- /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-black z-0", children: /* @__PURE__ */ jsxs("div", { className: "animate-pulse flex flex-col items-center", children: [
21787
- /* @__PURE__ */ jsx(Camera, { className: "w-6 h-6 text-gray-500" }),
21788
- /* @__PURE__ */ jsx("span", { className: "text-xs text-gray-500 mt-1", children: "Loading..." })
21789
- ] }) }),
21790
- /* @__PURE__ */ jsx("div", { className: "absolute inset-0 z-10", children: /* @__PURE__ */ jsx(
21791
- "video",
21792
- {
21793
- ref: videoRef,
21794
- className: "h-full w-full object-cover",
21795
- playsInline: true,
21796
- muted: true,
21797
- disablePictureInPicture: true,
21798
- controlsList: "nodownload noplaybackrate"
22236
+ className: `absolute left-4 top-1/2 -translate-y-1/2 z-[102] p-3 rounded-full bg-black/30 hover:bg-black/50 text-white transition-all ${currentIndex === 0 ? "opacity-30 cursor-not-allowed" : ""}`,
22237
+ "aria-label": "Previous video",
22238
+ children: /* @__PURE__ */ jsx(ChevronLeft, { className: "h-7 w-7" })
21799
22239
  }
21800
- ) }),
21801
- /* @__PURE__ */ jsx("div", { className: `absolute inset-0 z-20 pointer-events-none ${efficiencyOverlayClass}` }),
21802
- /* @__PURE__ */ jsxs("div", { className: "absolute top-2 right-2 z-30 bg-black/70 backdrop-blur-sm rounded px-2 py-0.5 text-white text-xs font-semibold border border-white/10", children: [
21803
- Math.round(workspace.efficiency),
21804
- "%"
21805
- ] }),
21806
- /* @__PURE__ */ jsx("div", { className: "absolute bottom-0 left-0 right-0 h-1 bg-black/50 z-30", children: /* @__PURE__ */ jsx(
21807
- "div",
22240
+ ),
22241
+ /* @__PURE__ */ jsx(
22242
+ "button",
21808
22243
  {
21809
- className: `h-full ${efficiencyBarClass} transition-all duration-500`,
21810
- style: { width: `${Math.min(100, workspace.efficiency)}%` }
22244
+ onClick: (e) => {
22245
+ e.stopPropagation();
22246
+ handleNext();
22247
+ },
22248
+ disabled: currentIndex === filteredVideos.length - 1 || filteredVideos.length === 0,
22249
+ className: `absolute right-4 top-1/2 -translate-y-1/2 z-[102] p-3 rounded-full bg-black/30 hover:bg-black/50 text-white transition-all ${currentIndex === filteredVideos.length - 1 ? "opacity-30 cursor-not-allowed" : ""}`,
22250
+ "aria-label": "Next video",
22251
+ children: /* @__PURE__ */ jsx(ChevronRight, { className: "h-7 w-7" })
21811
22252
  }
21812
- ) })
21813
- ] }),
21814
- /* @__PURE__ */ jsxs("div", { className: "absolute bottom-0 left-0 right-0 bg-black bg-opacity-60 p-1.5 flex justify-between items-center z-10", children: [
21815
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
21816
- /* @__PURE__ */ jsx(Camera, { size: 12, className: "text-white" }),
21817
- /* @__PURE__ */ jsx("p", { className: "text-white text-xs font-medium tracking-wide", children: displayName })
21818
- ] }),
21819
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
21820
- trendInfo && /* @__PURE__ */ jsx(
21821
- "div",
21822
- {
21823
- className: `text-lg ${trendInfo.color}`,
21824
- style: { lineHeight: 1, display: "flex", alignItems: "center" },
21825
- children: trendInfo.arrow
21826
- }
21827
- ),
21828
- /* @__PURE__ */ jsx("div", { className: "w-1.5 h-1.5 rounded-full bg-green-500" }),
21829
- /* @__PURE__ */ jsx("span", { className: "text-white text-xs", children: "Live" })
21830
- ] })
21831
- ] })
21832
- ]
21833
- }
21834
- );
21835
- }, (prevProps, nextProps) => {
21836
- return prevProps.workspace.workspace_uuid === nextProps.workspace.workspace_uuid && prevProps.workspace.workspace_name === nextProps.workspace.workspace_name && Math.abs(prevProps.workspace.efficiency - nextProps.workspace.efficiency) < 1 && prevProps.hlsUrl === nextProps.hlsUrl && prevProps.shouldPlay === nextProps.shouldPlay;
21837
- });
21838
- VideoCard.displayName = "VideoCard";
21839
- var DEFAULT_WORKSPACE_HLS_URLS = {
21840
- "WS1": "https://dnh-hls.optifye.ai/cam1/index.m3u8",
21841
- "WS2": "https://dnh-hls.optifye.ai/cam2/index.m3u8",
21842
- "WS3": "https://dnh-hls.optifye.ai/cam3/index.m3u8",
21843
- "WS4": "https://dnh-hls.optifye.ai/cam3/index.m3u8",
21844
- "WS01": "https://59.144.218.58:8443/camera6.m3u8",
21845
- "WS02": "https://59.144.218.58:8443/camera2.m3u8",
21846
- "WS03": "https://59.144.218.58:8443/camera3.m3u8",
21847
- "WS04": "https://59.144.218.58:8443/camera4.m3u8",
21848
- "WS05": "https://59.144.218.58:8443/camera1.m3u8",
21849
- "WS06": "https://59.144.218.58:8443/camera5.m3u8"
21850
- };
21851
- var DEFAULT_HLS_URL = "https://192.168.5.9:8443/cam1.m3u8";
21852
- var VideoGridView = React33__default.memo(({
21853
- workspaces,
21854
- selectedLine,
21855
- className = "",
21856
- lineIdMapping = {},
21857
- videoSources = {}
21858
- }) => {
21859
- const router = useRouter();
21860
- const containerRef = useRef(null);
21861
- const observerRef = useRef(null);
21862
- const [gridCols, setGridCols] = useState(4);
21863
- const [visibleWorkspaces, setVisibleWorkspaces] = useState(/* @__PURE__ */ new Set());
21864
- const mergedVideoSources = {
21865
- defaultHlsUrl: videoSources.defaultHlsUrl || DEFAULT_HLS_URL,
21866
- workspaceHlsUrls: { ...DEFAULT_WORKSPACE_HLS_URLS, ...videoSources.workspaceHlsUrls }
21867
- };
21868
- const getWorkspaceHlsUrl = useCallback((workspaceName) => {
21869
- const wsName = workspaceName.toUpperCase();
21870
- return mergedVideoSources.workspaceHlsUrls[wsName] || mergedVideoSources.defaultHlsUrl;
21871
- }, [mergedVideoSources]);
21872
- const veryLowEfficiencyWorkspaces = useMemo(() => {
21873
- return new Set(
21874
- workspaces.filter((w) => w.efficiency < 50 && w.efficiency >= 10).map((w) => w.workspace_name)
21875
- );
21876
- }, [workspaces]);
21877
- const filteredWorkspaces = useMemo(() => {
21878
- return selectedLine === 1 ? workspaces.filter((w) => {
21879
- if (w.workspace_name === "WS5-5") return true;
21880
- if (w.workspace_name === "WS32-5") return false;
21881
- try {
21882
- const wsNumber = parseInt(w.workspace_name.replace("WS", ""));
21883
- return wsNumber >= 1 && wsNumber <= 22;
21884
- } catch {
21885
- return true;
21886
- }
21887
- }) : selectedLine === 2 ? workspaces.filter((w) => {
21888
- if (w.workspace_name === "WS5-5") return false;
21889
- if (w.workspace_name === "WS32-5") return true;
21890
- try {
21891
- const wsNumber = parseInt(w.workspace_name.replace("WS", ""));
21892
- return wsNumber >= 23 && wsNumber <= 44;
21893
- } catch {
21894
- return false;
21895
- }
21896
- }) : workspaces;
21897
- }, [workspaces, selectedLine]);
21898
- const calculateOptimalGrid = useCallback(() => {
21899
- if (!containerRef.current) return;
21900
- const containerPadding = 16;
21901
- const containerWidth = containerRef.current.clientWidth - containerPadding;
21902
- const containerHeight = containerRef.current.clientHeight - containerPadding;
21903
- const count = filteredWorkspaces.length;
21904
- if (count === 0) {
21905
- setGridCols(1);
21906
- return;
21907
- }
21908
- let bestCols = 1;
21909
- let bestScore = 0;
21910
- const targetAspectRatio = 16 / 9;
21911
- const gap = 8;
21912
- const maxCols = Math.min(count, 6);
21913
- for (let cols = 1; cols <= maxCols; cols++) {
21914
- const rows = Math.ceil(count / cols);
21915
- const availableWidth = containerWidth - gap * (cols - 1);
21916
- const availableHeight = containerHeight - gap * (rows - 1);
21917
- const cellWidth = availableWidth / cols;
21918
- const cellHeight = availableHeight / rows;
21919
- const minCellWidth = containerWidth < 800 ? 120 : 150;
21920
- const minCellHeight = containerHeight < 600 ? 80 : 100;
21921
- if (cellWidth < minCellWidth || cellHeight < minCellHeight) continue;
21922
- const totalUsedArea = cellWidth * cellHeight * count;
21923
- const totalAvailableArea = containerWidth * containerHeight;
21924
- const spaceUtilization = totalUsedArea / totalAvailableArea;
21925
- const actualAspectRatio = cellWidth / cellHeight;
21926
- const aspectRatioScore = 1 / (1 + Math.abs(actualAspectRatio - targetAspectRatio) * 0.3);
21927
- const score = spaceUtilization * 0.9 + aspectRatioScore * 0.1;
21928
- if (score > bestScore) {
21929
- bestScore = score;
21930
- bestCols = cols;
22253
+ )
22254
+ ]
21931
22255
  }
21932
- }
21933
- if (bestScore === 0) {
21934
- bestCols = Math.ceil(Math.sqrt(count));
21935
- }
21936
- setGridCols(bestCols);
21937
- }, [filteredWorkspaces.length]);
21938
- useEffect(() => {
21939
- calculateOptimalGrid();
21940
- const handleResize = () => calculateOptimalGrid();
21941
- window.addEventListener("resize", handleResize);
21942
- return () => window.removeEventListener("resize", handleResize);
21943
- }, [calculateOptimalGrid]);
21944
- useEffect(() => {
21945
- if (!containerRef.current) return;
21946
- const options = {
21947
- root: null,
21948
- rootMargin: "50px",
21949
- threshold: 0.1
21950
- };
21951
- observerRef.current = new IntersectionObserver((entries) => {
21952
- entries.forEach((entry) => {
21953
- const workspaceId = entry.target.getAttribute("data-workspace-id");
21954
- if (!workspaceId) return;
21955
- setVisibleWorkspaces((prev) => {
21956
- const next = new Set(prev);
21957
- if (entry.isIntersecting) {
21958
- next.add(workspaceId);
21959
- } else {
21960
- next.delete(workspaceId);
21961
- }
21962
- return next;
21963
- });
21964
- });
21965
- }, options);
21966
- const elements = containerRef.current.querySelectorAll("[data-workspace-id]");
21967
- elements.forEach((el) => observerRef.current?.observe(el));
21968
- return () => {
21969
- observerRef.current?.disconnect();
21970
- };
21971
- }, [filteredWorkspaces]);
21972
- const handleWorkspaceClick = useCallback((workspace) => {
21973
- const workspaceId = workspace.workspace_uuid || workspace.workspace_name;
21974
- trackCoreEvent("Workspace Detail Clicked", {
21975
- workspace_name: workspace.workspace_name,
21976
- workspace_id: workspaceId,
21977
- view_type: "video_grid",
21978
- performance_score: workspace.performance_score,
21979
- efficiency: workspace.efficiency,
21980
- action_count: workspace.action_count
21981
- });
21982
- const displayName = getWorkspaceDisplayName(workspace.workspace_name);
21983
- const navParams = getWorkspaceNavigationParams(workspaceId, displayName);
21984
- router.push(`/workspace/${workspaceId}${navParams}`);
21985
- }, [router]);
21986
- return /* @__PURE__ */ jsx("div", { className: `relative overflow-hidden h-full w-full ${className}`, children: /* @__PURE__ */ jsx("div", { ref: containerRef, className: "h-full w-full p-2", children: /* @__PURE__ */ jsx(
21987
- "div",
21988
- {
21989
- className: "grid h-full w-full gap-2",
21990
- style: {
21991
- gridTemplateColumns: `repeat(${gridCols}, 1fr)`,
21992
- gridTemplateRows: `repeat(${Math.ceil(filteredWorkspaces.length / gridCols)}, 1fr)`,
21993
- minHeight: "100%"
21994
- },
21995
- children: filteredWorkspaces.sort((a, b) => {
21996
- const aNum = parseInt(a.workspace_name.slice(2));
21997
- const bNum = parseInt(b.workspace_name.slice(2));
21998
- if (!selectedLine) {
21999
- const aIsLine2 = a.line_id === lineIdMapping.line2;
22000
- const bIsLine2 = b.line_id === lineIdMapping.line2;
22001
- if (aIsLine2 !== bIsLine2) {
22002
- return aIsLine2 ? 1 : -1;
22003
- }
22004
- }
22005
- return aNum - bNum;
22006
- }).map((workspace) => {
22007
- const workspaceId = workspace.workspace_uuid || workspace.workspace_name;
22008
- const isVisible = visibleWorkspaces.has(workspaceId);
22009
- const isVeryLowEfficiency = veryLowEfficiencyWorkspaces.has(workspace.workspace_name);
22010
- return /* @__PURE__ */ jsx(
22011
- "div",
22012
- {
22013
- "data-workspace-id": workspaceId,
22014
- className: "workspace-card relative min-h-0 min-w-0",
22015
- style: { width: "100%", height: "100%" },
22016
- children: /* @__PURE__ */ jsx(
22017
- VideoCard,
22018
- {
22019
- workspace,
22020
- hlsUrl: getWorkspaceHlsUrl(workspace.workspace_name),
22021
- shouldPlay: isVisible,
22022
- onClick: () => handleWorkspaceClick(workspace),
22023
- onFatalError: throttledReloadDashboard,
22024
- isVeryLowEfficiency
22025
- }
22026
- )
22027
- },
22028
- workspaceId
22029
- );
22030
- })
22031
- }
22032
- ) }) });
22033
- });
22034
- VideoGridView.displayName = "VideoGridView";
22256
+ )
22257
+ ] });
22258
+ };
22035
22259
  var getEfficiencyColor = (efficiency) => {
22036
22260
  if (efficiency >= 80) {
22037
22261
  return "bg-[#00AB45]/90 hover:bg-[#00AB45]/95";
@@ -22132,7 +22356,7 @@ var arePropsEqual = (prevProps, nextProps) => {
22132
22356
  return prevProps.data.efficiency === nextProps.data.efficiency && prevProps.data.trend_score === nextProps.data.trend_score && prevProps.data.workspace_id === nextProps.data.workspace_id && prevProps.data.workspace_name === nextProps.data.workspace_name && prevProps.isBottleneck === nextProps.isBottleneck && prevProps.isLowEfficiency === nextProps.isLowEfficiency && prevProps.isVeryLowEfficiency === nextProps.isVeryLowEfficiency && // Position doesn't need deep equality check as it's generally static
22133
22357
  prevProps.position.id === nextProps.position.id;
22134
22358
  };
22135
- var WorkspaceGridItem = React33__default.memo(({
22359
+ var WorkspaceGridItem = React14__default.memo(({
22136
22360
  data,
22137
22361
  position,
22138
22362
  isBottleneck = false,
@@ -22225,7 +22449,7 @@ var WorkspaceGridItem = React33__default.memo(({
22225
22449
  );
22226
22450
  }, arePropsEqual);
22227
22451
  WorkspaceGridItem.displayName = "WorkspaceGridItem";
22228
- var WorkspaceGrid = React33__default.memo(({
22452
+ var WorkspaceGrid = React14__default.memo(({
22229
22453
  workspaces,
22230
22454
  isPdfMode = false,
22231
22455
  customWorkspacePositions,
@@ -22241,13 +22465,14 @@ var WorkspaceGrid = React33__default.memo(({
22241
22465
  total_workspaces: workspaces.length
22242
22466
  });
22243
22467
  }, [workspaces.length]);
22468
+ const { VideoGridView: VideoGridViewComponent } = useRegistry();
22244
22469
  return /* @__PURE__ */ jsxs("div", { className: `relative w-full h-full overflow-hidden ${className}`, children: [
22245
22470
  /* @__PURE__ */ jsxs("div", { className: "absolute top-0 left-2 sm:left-4 right-2 sm:right-8 z-20", children: [
22246
22471
  /* @__PURE__ */ jsx("div", { className: "flex flex-row items-center justify-between py-1 sm:py-1.5 gap-2", children: /* @__PURE__ */ jsx("div", { className: "hidden sm:block", children: /* @__PURE__ */ jsx(Legend5, {}) }) }),
22247
22472
  /* @__PURE__ */ jsx("div", { className: "sm:hidden mt-1", children: /* @__PURE__ */ jsx(Legend5, {}) })
22248
22473
  ] }),
22249
22474
  /* @__PURE__ */ jsx("div", { className: "absolute top-10 sm:top-16 left-0 right-0 bottom-0", children: /* @__PURE__ */ jsx(
22250
- VideoGridView,
22475
+ VideoGridViewComponent,
22251
22476
  {
22252
22477
  workspaces,
22253
22478
  videoSources
@@ -22414,7 +22639,7 @@ var KPICard = ({
22414
22639
  }) => {
22415
22640
  useThemeConfig();
22416
22641
  const { formatNumber } = useFormatNumber();
22417
- const trendInfo = React33__default.useMemo(() => {
22642
+ const trendInfo = React14__default.useMemo(() => {
22418
22643
  let trendValue = trend || "neutral";
22419
22644
  if (change !== void 0 && trend === void 0) {
22420
22645
  trendValue = change > 0 ? "up" : change < 0 ? "down" : "neutral";
@@ -22437,7 +22662,7 @@ var KPICard = ({
22437
22662
  const shouldShowTrend = !(change === 0 && trend === void 0);
22438
22663
  return { trendValue, Icon: Icon2, colorClass, shouldShowTrend };
22439
22664
  }, [trend, change]);
22440
- const formattedValue = React33__default.useMemo(() => {
22665
+ const formattedValue = React14__default.useMemo(() => {
22441
22666
  if (title === "Quality Compliance" && typeof value === "number") {
22442
22667
  return value.toFixed(1);
22443
22668
  }
@@ -22451,7 +22676,7 @@ var KPICard = ({
22451
22676
  }
22452
22677
  return value;
22453
22678
  }, [value, title]);
22454
- const formattedChange = React33__default.useMemo(() => {
22679
+ const formattedChange = React14__default.useMemo(() => {
22455
22680
  if (change === void 0 || change === 0) return null;
22456
22681
  const absChange = Math.abs(change);
22457
22682
  return formatNumber(absChange, { minimumFractionDigits: 0, maximumFractionDigits: 1 });
@@ -22863,7 +23088,7 @@ var Breadcrumbs = ({ items }) => {
22863
23088
  }
22864
23089
  }
22865
23090
  };
22866
- return /* @__PURE__ */ jsx("nav", { "aria-label": "Breadcrumb", className: "mb-1 flex items-center space-x-1 text-xs font-medium text-gray-500 dark:text-gray-400", children: items.map((item, index) => /* @__PURE__ */ jsxs(React33__default.Fragment, { children: [
23091
+ return /* @__PURE__ */ jsx("nav", { "aria-label": "Breadcrumb", className: "mb-1 flex items-center space-x-1 text-xs font-medium text-gray-500 dark:text-gray-400", children: items.map((item, index) => /* @__PURE__ */ jsxs(React14__default.Fragment, { children: [
22867
23092
  index > 0 && /* @__PURE__ */ jsx(ChevronRight, { className: "h-3 w-3 text-gray-400 dark:text-gray-500" }),
22868
23093
  /* @__PURE__ */ jsxs(
22869
23094
  "span",
@@ -23682,7 +23907,7 @@ var ThreadSidebar = ({
23682
23907
  ] });
23683
23908
  };
23684
23909
  var axelProfilePng = "/axel-profile.png";
23685
- var ProfilePicture = React33__default.memo(({ alt = "Axel", className = "w-12 h-12" }) => {
23910
+ var ProfilePicture = React14__default.memo(({ alt = "Axel", className = "w-12 h-12" }) => {
23686
23911
  return /* @__PURE__ */ jsx("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsx("div", { className: `${className} rounded-xl overflow-hidden shadow-sm`, children: /* @__PURE__ */ jsx(
23687
23912
  "img",
23688
23913
  {
@@ -24412,7 +24637,7 @@ var AIAgentView = () => {
24412
24637
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
24413
24638
  });
24414
24639
  },
24415
- placeholder: "Ask me about production optimization, quality metrics, or any manufacturing challenge...",
24640
+ placeholder: "Ask me anything about your shop-floor",
24416
24641
  className: "w-full resize-none bg-transparent px-2 py-2 pr-12 focus:outline-none placeholder-gray-500 text-gray-900 text-sm leading-relaxed",
24417
24642
  rows: 1,
24418
24643
  style: { minHeight: "24px", maxHeight: "120px" }
@@ -24587,7 +24812,7 @@ var AIAgentView = () => {
24587
24812
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
24588
24813
  });
24589
24814
  },
24590
- placeholder: "Ask me about production optimization, quality metrics, or any manufacturing challenge...",
24815
+ placeholder: "Ask me anything about your shop-floor",
24591
24816
  className: "w-full resize-none bg-transparent px-2 py-2 pr-12 focus:outline-none placeholder-gray-500 text-gray-900 text-sm leading-relaxed",
24592
24817
  rows: 1,
24593
24818
  style: { minHeight: "24px", maxHeight: "120px" }
@@ -25547,6 +25772,24 @@ function HomeView({
25547
25772
  const [selectedLineId, setSelectedLineId] = useState(defaultLineId);
25548
25773
  const [isChangingFilter, setIsChangingFilter] = useState(false);
25549
25774
  const [errorMessage, setErrorMessage] = useState(null);
25775
+ const [displayNamesInitialized, setDisplayNamesInitialized] = useState(false);
25776
+ useEffect(() => {
25777
+ const initDisplayNames = async () => {
25778
+ try {
25779
+ await preInitializeWorkspaceDisplayNames(selectedLineId);
25780
+ setDisplayNamesInitialized(true);
25781
+ } catch (error) {
25782
+ console.error("Failed to pre-initialize workspace display names:", error);
25783
+ setDisplayNamesInitialized(true);
25784
+ }
25785
+ };
25786
+ initDisplayNames();
25787
+ }, [selectedLineId]);
25788
+ const {
25789
+ displayNames: workspaceDisplayNames,
25790
+ loading: displayNamesLoading,
25791
+ error: displayNamesError
25792
+ } = useWorkspaceDisplayNames(void 0, selectedLineId);
25550
25793
  useCallback(() => {
25551
25794
  console.log("Refetching KPIs after line metrics update");
25552
25795
  }, []);
@@ -25619,16 +25862,16 @@ function HomeView({
25619
25862
  const lineTitle = useMemo(() => {
25620
25863
  return factoryName;
25621
25864
  }, [factoryName]);
25622
- const isLoading = !isHydrated || metricsLoading || kpisLoading || isChangingFilter;
25865
+ const isLoading = !isHydrated || metricsLoading || kpisLoading || isChangingFilter || displayNamesLoading || !displayNamesInitialized;
25623
25866
  if (isLoading) {
25624
25867
  return /* @__PURE__ */ jsx("div", { className: "min-h-screen bg-slate-50", children: /* @__PURE__ */ jsx(LoadingPageCmp, { message: "Loading dashboard..." }) });
25625
25868
  }
25626
- if (errorMessage) {
25869
+ if (errorMessage || displayNamesError) {
25627
25870
  return /* @__PURE__ */ jsx("div", { className: "flex h-screen items-center justify-center", children: /* @__PURE__ */ jsx("div", { className: "rounded-lg bg-white p-6 shadow-lg", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-3 text-red-500", children: [
25628
25871
  /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-6 w-6", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }),
25629
25872
  /* @__PURE__ */ jsxs("span", { className: "text-lg font-medium", children: [
25630
25873
  "Error: ",
25631
- errorMessage
25874
+ errorMessage || displayNamesError?.message
25632
25875
  ] })
25633
25876
  ] }) }) });
25634
25877
  }
@@ -25648,7 +25891,7 @@ function HomeView({
25648
25891
  /* @__PURE__ */ jsx(DashboardHeader, { lineTitle, className: "mb-1 sm:mb-0" }),
25649
25892
  memoizedKPIs && /* @__PURE__ */ jsx(KPISection2, { kpis: memoizedKPIs, className: "w-full sm:w-auto" })
25650
25893
  ] }) }),
25651
- /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto sm:overflow-hidden", children: memoizedWorkspaceMetrics.length > 0 ? /* @__PURE__ */ jsx("div", { className: "h-full sm:h-full min-h-[calc(100vh-80px)] sm:min-h-0", children: React33__default.createElement(WorkspaceGrid, {
25894
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto sm:overflow-hidden", children: memoizedWorkspaceMetrics.length > 0 ? /* @__PURE__ */ jsx("div", { className: "h-full sm:h-full min-h-[calc(100vh-80px)] sm:min-h-0", children: React14__default.createElement(WorkspaceGrid, {
25652
25895
  workspaces: memoizedWorkspaceMetrics,
25653
25896
  lineNames,
25654
25897
  factoryView: factoryViewId,
@@ -25669,7 +25912,7 @@ function HomeView({
25669
25912
  }
25670
25913
  );
25671
25914
  }
25672
- var AuthenticatedHomeView = withAuth(React33__default.memo(HomeView));
25915
+ var AuthenticatedHomeView = withAuth(React14__default.memo(HomeView));
25673
25916
  var HomeView_default = HomeView;
25674
25917
 
25675
25918
  // src/views/kpi-detail-view.types.ts
@@ -26502,7 +26745,7 @@ var LineCard = ({ line, onClick }) => {
26502
26745
  const { kpis, isLoading, error } = useLineKPIs({ lineId: line.id });
26503
26746
  const shiftConfig = useShiftConfig();
26504
26747
  const dateTimeConfig = useDateTimeConfig();
26505
- const isOnTrack = React33__default.useMemo(() => {
26748
+ const isOnTrack = React14__default.useMemo(() => {
26506
26749
  if (!kpis) return null;
26507
26750
  const currentTime = /* @__PURE__ */ new Date();
26508
26751
  const timezone = dateTimeConfig.defaultTimezone || "Asia/Kolkata";
@@ -30466,4 +30709,4 @@ var S3Service = class {
30466
30709
  }
30467
30710
  };
30468
30711
 
30469
- export { ACTION_NAMES, AIAgentView_default as AIAgentView, AuthCallback, AuthCallbackView_default as AuthCallbackView, AuthProvider, AuthenticatedFactoryView, AuthenticatedHelpView, AuthenticatedHomeView, AuthenticatedTargetsView, BarChart, BaseHistoryCalendar, BottlenecksContent, BreakNotificationPopup, Card2 as Card, CardContent2 as CardContent, CardDescription2 as CardDescription, CardFooter2 as CardFooter, CardHeader2 as CardHeader, CardTitle2 as CardTitle, CycleTimeChart, CycleTimeOverTimeChart, DEFAULT_ANALYTICS_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_CONFIG, DEFAULT_DATABASE_CONFIG, DEFAULT_DATE_TIME_CONFIG, DEFAULT_ENDPOINTS_CONFIG, DEFAULT_ENTITY_CONFIG, DEFAULT_SHIFT_CONFIG, DEFAULT_THEME_CONFIG, DEFAULT_WORKSPACE_CONFIG, DEFAULT_WORKSPACE_POSITIONS, DashboardHeader, DashboardLayout, DashboardOverridesProvider, DashboardProvider, DateDisplay_default as DateDisplay, DateTimeDisplay, DebugAuth, DebugAuthView_default as DebugAuthView, EmptyStateMessage, FactoryView_default as FactoryView, GridComponentsPlaceholder, Header, HelpView_default as HelpView, HomeView_default as HomeView, HourlyOutputChart2 as HourlyOutputChart, ISTTimer_default as ISTTimer, KPICard, KPIDetailView_default as KPIDetailView, KPIGrid, KPIHeader, KPISection, KPIsOverviewView_default as KPIsOverviewView, LINE_1_UUID, LargeOutputProgressChart, LeaderboardDetailView_default as LeaderboardDetailView, Legend5 as Legend, LineChart, LineHistoryCalendar, LineMonthlyHistory, LineMonthlyPdfGenerator, LinePdfExportButton, LinePdfGenerator, LineWhatsAppShareButton, LiveTimer, LoadingOverlay_default as LoadingOverlay, LoadingPage_default as LoadingPage, LoadingSpinner_default as LoadingSpinner, LoginPage, LoginView_default as LoginView, MainLayout, MetricCard_default as MetricCard, NoWorkspaceData, OptifyeAgentClient, OutputProgressChart, PageHeader, ProfileView_default as ProfileView, RegistryProvider, S3Service, SOPComplianceChart, SSEChatClient, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, ShiftDisplay_default as ShiftDisplay, ShiftsView_default as ShiftsView, SideNavBar, SingleVideoStream_default as SingleVideoStream, Skeleton, SlackAPI, SupabaseProvider, TargetWorkspaceGrid, TargetsView_default as TargetsView, ThreadSidebar, TimeDisplay_default as TimeDisplay, TimePickerDropdown, VideoCard, VideoGridView, VideoPreloader, WORKSPACE_POSITIONS, WhatsAppShareButton, WorkspaceCard, WorkspaceDetailView_default as WorkspaceDetailView, WorkspaceGrid, WorkspaceGridItem, WorkspaceHistoryCalendar, WorkspaceMetricCards, WorkspaceMonthlyDataFetcher, WorkspaceMonthlyPdfGenerator, WorkspacePdfExportButton, WorkspacePdfGenerator, WorkspaceWhatsAppShareButton, actionService, apiUtils, authCoreService, authOTPService, authRateLimitService, checkRateLimit2 as checkRateLimit, clearAllRateLimits2 as clearAllRateLimits, clearRateLimit2 as clearRateLimit, clearS3VideoCache, clearS3VideoFromCache, clearWorkspaceDisplayNamesCache, cn, createStreamProxyHandler, createSupabaseClient, createThrottledReload, dashboardService, deleteThread, formatDateInZone, formatDateTimeInZone, formatISTDate, formatIdleTime, formatTimeInZone, fromUrlFriendlyName, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAnonClient, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getCurrentShift, getCurrentTimeInZone, getDashboardHeaderTimeInZone, getDaysDifferenceInZone, getDefaultCameraStreamUrl, getDefaultTabForWorkspace, getManufacturingInsights, getMetricsTablePrefix, getOperationalDate, getS3SignedUrl, getS3VideoSrc, getShortWorkspaceDisplayName, getShortWorkspaceDisplayNameAsync, getStoredWorkspaceMappings, getThreadMessages, getUserThreads, getUserThreadsPaginated, getWorkspaceDisplayName, getWorkspaceDisplayNameAsync, getWorkspaceDisplayNamesMap, getWorkspaceFromUrl, getWorkspaceNavigationParams, identifyCoreUser, initializeCoreMixpanel, isTransitionPeriod, isValidLineInfoPayload, isValidWorkspaceDetailedMetricsPayload, isValidWorkspaceMetricsPayload, isWorkspaceDisplayNamesLoaded, isWorkspaceDisplayNamesLoading, mergeWithDefaultConfig, optifyeAgentClient, preloadS3Video, preloadS3VideoUrl, preloadS3VideosUrl, preloadVideoUrl, preloadVideosUrl, qualityService, realtimeService, refreshWorkspaceDisplayNames, resetCoreMixpanel, s3VideoPreloader, storeWorkspaceMapping, streamProxyConfig, throttledReloadDashboard, toUrlFriendlyName, trackCoreEvent, trackCorePageView, updateThreadTitle, useActiveBreaks, useAnalyticsConfig, useAuth, useAuthConfig, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHistoricWorkspaceMetrics, useHlsStream, useHookOverride, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineWorkspaceMetrics, useMessages, useMetrics, useNavigation, useOverrides, usePageOverride, useRealtimeLineMetrics, useRegistry, useShiftConfig, useShifts, useSupabase, useSupabaseClient, useTargets, useTheme, useThemeConfig, useThreads, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, videoPreloader, whatsappService, withAuth, withRegistry, workspaceService };
30712
+ export { ACTION_NAMES, AIAgentView_default as AIAgentView, AuthCallback, AuthCallbackView_default as AuthCallbackView, AuthProvider, AuthenticatedFactoryView, AuthenticatedHelpView, AuthenticatedHomeView, AuthenticatedTargetsView, BarChart, BaseHistoryCalendar, BottlenecksContent, BreakNotificationPopup, Card2 as Card, CardContent2 as CardContent, CardDescription2 as CardDescription, CardFooter2 as CardFooter, CardHeader2 as CardHeader, CardTitle2 as CardTitle, CycleTimeChart, CycleTimeOverTimeChart, DEFAULT_ANALYTICS_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_CONFIG, DEFAULT_DATABASE_CONFIG, DEFAULT_DATE_TIME_CONFIG, DEFAULT_ENDPOINTS_CONFIG, DEFAULT_ENTITY_CONFIG, DEFAULT_SHIFT_CONFIG, DEFAULT_THEME_CONFIG, DEFAULT_WORKSPACE_CONFIG, DEFAULT_WORKSPACE_POSITIONS, DashboardHeader, DashboardLayout, DashboardOverridesProvider, DashboardProvider, DateDisplay_default as DateDisplay, DateTimeDisplay, DebugAuth, DebugAuthView_default as DebugAuthView, EmptyStateMessage, FactoryView_default as FactoryView, GridComponentsPlaceholder, Header, HelpView_default as HelpView, HomeView_default as HomeView, HourlyOutputChart2 as HourlyOutputChart, ISTTimer_default as ISTTimer, KPICard, KPIDetailView_default as KPIDetailView, KPIGrid, KPIHeader, KPISection, KPIsOverviewView_default as KPIsOverviewView, LINE_1_UUID, LargeOutputProgressChart, LeaderboardDetailView_default as LeaderboardDetailView, Legend5 as Legend, LineChart, LineHistoryCalendar, LineMonthlyHistory, LineMonthlyPdfGenerator, LinePdfExportButton, LinePdfGenerator, LineWhatsAppShareButton, LiveTimer, LoadingOverlay_default as LoadingOverlay, LoadingPage_default as LoadingPage, LoadingSpinner_default as LoadingSpinner, LoginPage, LoginView_default as LoginView, MainLayout, MetricCard_default as MetricCard, NoWorkspaceData, OptifyeAgentClient, OutputProgressChart, PageHeader, ProfileView_default as ProfileView, RegistryProvider, S3Service, SOPComplianceChart, SSEChatClient, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, ShiftDisplay_default as ShiftDisplay, ShiftsView_default as ShiftsView, SideNavBar, SingleVideoStream_default as SingleVideoStream, Skeleton, SlackAPI, SupabaseProvider, TargetWorkspaceGrid, TargetsView_default as TargetsView, ThreadSidebar, TimeDisplay_default as TimeDisplay, TimePickerDropdown, VideoCard, VideoGridView, VideoPreloader, WORKSPACE_POSITIONS, WhatsAppShareButton, WorkspaceCard, WorkspaceDetailView_default as WorkspaceDetailView, WorkspaceGrid, WorkspaceGridItem, WorkspaceHistoryCalendar, WorkspaceMetricCards, WorkspaceMonthlyDataFetcher, WorkspaceMonthlyPdfGenerator, WorkspacePdfExportButton, WorkspacePdfGenerator, WorkspaceWhatsAppShareButton, actionService, apiUtils, authCoreService, authOTPService, authRateLimitService, checkRateLimit2 as checkRateLimit, clearAllRateLimits2 as clearAllRateLimits, clearRateLimit2 as clearRateLimit, clearS3VideoCache, clearS3VideoFromCache, clearWorkspaceDisplayNamesCache, cn, createStreamProxyHandler, createSupabaseClient, createThrottledReload, dashboardService, deleteThread, forceRefreshWorkspaceDisplayNames, formatDateInZone, formatDateTimeInZone, formatISTDate, formatIdleTime, formatTimeInZone, fromUrlFriendlyName, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAnonClient, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getCurrentShift, getCurrentTimeInZone, getDashboardHeaderTimeInZone, getDaysDifferenceInZone, getDefaultCameraStreamUrl, getDefaultTabForWorkspace, getManufacturingInsights, getMetricsTablePrefix, getOperationalDate, getS3SignedUrl, getS3VideoSrc, getShortWorkspaceDisplayName, getShortWorkspaceDisplayNameAsync, getStoredWorkspaceMappings, getThreadMessages, getUserThreads, getUserThreadsPaginated, getWorkspaceDisplayName, getWorkspaceDisplayNameAsync, getWorkspaceDisplayNamesMap, getWorkspaceFromUrl, getWorkspaceNavigationParams, identifyCoreUser, initializeCoreMixpanel, isTransitionPeriod, isValidLineInfoPayload, isValidWorkspaceDetailedMetricsPayload, isValidWorkspaceMetricsPayload, isWorkspaceDisplayNamesLoaded, isWorkspaceDisplayNamesLoading, mergeWithDefaultConfig, optifyeAgentClient, preInitializeWorkspaceDisplayNames, preloadS3Video, preloadS3VideoUrl, preloadS3VideosUrl, preloadVideoUrl, preloadVideosUrl, qualityService, realtimeService, refreshWorkspaceDisplayNames, resetCoreMixpanel, s3VideoPreloader, storeWorkspaceMapping, streamProxyConfig, throttledReloadDashboard, toUrlFriendlyName, trackCoreEvent, trackCorePageView, updateThreadTitle, useActiveBreaks, useAnalyticsConfig, useAuth, useAuthConfig, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHistoricWorkspaceMetrics, useHlsStream, useHookOverride, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineWorkspaceMetrics, useMessages, useMetrics, useNavigation, useOverrides, usePageOverride, useRealtimeLineMetrics, useRegistry, useShiftConfig, useShifts, useSupabase, useSupabaseClient, useTargets, useTheme, useThemeConfig, useThreads, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, videoPreloader, whatsappService, withAuth, withRegistry, workspaceService };