@optifye/dashboard-core 6.11.15 → 6.11.16

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
@@ -12,7 +12,7 @@ import Hls, { Events, ErrorTypes } from 'hls.js';
12
12
  import useSWR from 'swr';
13
13
  import { Camera, AlertTriangle, ChevronDown, ChevronUp, Check, Map as Map$1, Video, ShieldCheck, Star, Award, Filter, X, Coffee, Plus, ArrowUp, ArrowDown, ArrowRight, ArrowLeft, Clock, Calendar, Save, AlertCircle, Loader2, Minus, ChevronLeft, ChevronRight, TrendingUp, Sparkles, Pause, Play, XCircle, HelpCircle, Activity, Wrench, UserX, Package, RefreshCw, Palette, CheckCircle2, TrendingDown, FolderOpen, Folder, Tag, Sliders, Layers, Search, Edit2, CheckCircle, User, Users, Shield, Building2, Mail, Lock, Info, Share2, Trophy, Target, Download, Sun, Moon, MousePointer, UserPlus, UserCog, Trash2, Eye, MoreVertical, BarChart3, Pencil, UserCheck, LogOut, Film, MessageSquare, Menu, Send, Copy, Settings, LifeBuoy, EyeOff, Zap, Flame, Crown, Medal } from 'lucide-react';
14
14
  import { memo, noop, warning, invariant, progress, secondsToMilliseconds, millisecondsToSeconds } from 'motion-utils';
15
- import { BarChart as BarChart$1, CartesianGrid, XAxis, YAxis, ReferenceLine, Tooltip, Legend, Bar, LabelList, ResponsiveContainer, LineChart as LineChart$1, Line, PieChart, Pie, Cell, ComposedChart, Area, ScatterChart, Scatter } from 'recharts';
15
+ import { BarChart as BarChart$1, CartesianGrid, XAxis, YAxis, ReferenceLine, Tooltip, Legend, Bar, LabelList, ResponsiveContainer, PieChart, Pie, Cell, LineChart as LineChart$1, Line, ComposedChart, Area, ScatterChart, Scatter } from 'recharts';
16
16
  import { Slot } from '@radix-ui/react-slot';
17
17
  import * as SelectPrimitive from '@radix-ui/react-select';
18
18
  import { DayPicker, useNavigation as useNavigation$1 } from 'react-day-picker';
@@ -12835,6 +12835,7 @@ var useShiftGroups = ({
12835
12835
  }) => {
12836
12836
  const [shiftGroups, setShiftGroups] = useState([]);
12837
12837
  const [shiftGroupsKey, setShiftGroupsKey] = useState("");
12838
+ const [hasComputed, setHasComputed] = useState(false);
12838
12839
  const lastKeyRef = useRef("");
12839
12840
  const mapRef = useRef(shiftConfigMap);
12840
12841
  useEffect(() => {
@@ -12845,6 +12846,7 @@ var useShiftGroups = ({
12845
12846
  lastKeyRef.current = "";
12846
12847
  setShiftGroups([]);
12847
12848
  setShiftGroupsKey("");
12849
+ setHasComputed(false);
12848
12850
  return;
12849
12851
  }
12850
12852
  let isMounted = true;
@@ -12857,6 +12859,7 @@ var useShiftGroups = ({
12857
12859
  setShiftGroups(groups);
12858
12860
  setShiftGroupsKey(key);
12859
12861
  }
12862
+ setHasComputed(true);
12860
12863
  };
12861
12864
  compute();
12862
12865
  const intervalId = setInterval(compute, pollIntervalMs);
@@ -12865,7 +12868,7 @@ var useShiftGroups = ({
12865
12868
  clearInterval(intervalId);
12866
12869
  };
12867
12870
  }, [enabled, shiftConfigMap.size, timezone, pollIntervalMs]);
12868
- return { shiftGroups, shiftGroupsKey };
12871
+ return { shiftGroups, shiftGroupsKey, hasComputed };
12869
12872
  };
12870
12873
 
12871
12874
  // src/lib/types/efficiencyLegend.ts
@@ -12927,52 +12930,6 @@ function getEfficiencyTextColorClasses(efficiency, legend = DEFAULT_EFFICIENCY_L
12927
12930
  }
12928
12931
  }
12929
12932
 
12930
- // src/lib/hooks/useDashboardMetrics.recentFlow.ts
12931
- var isFiniteNumber = (value) => typeof value === "number" && Number.isFinite(value);
12932
- var getWorkspaceRecentFlowCacheKey = (workspace) => {
12933
- const workspaceKey = workspace.workspace_uuid || workspace.workspace_name || "unknown";
12934
- return `${workspaceKey}|${workspace.date}|${workspace.shift_id}`;
12935
- };
12936
- var toRecentFlowSnapshot = (workspace) => {
12937
- if (!isFiniteNumber(workspace.recent_flow_percent)) {
12938
- return null;
12939
- }
12940
- return {
12941
- recent_flow_percent: workspace.recent_flow_percent,
12942
- recent_flow_actual_rate_pph: workspace.recent_flow_actual_rate_pph ?? null,
12943
- recent_flow_healthy_rate_pph: workspace.recent_flow_healthy_rate_pph ?? null,
12944
- recent_flow_window_minutes: workspace.recent_flow_window_minutes ?? null,
12945
- recent_flow_effective_end_at: workspace.recent_flow_effective_end_at ?? null
12946
- };
12947
- };
12948
- var mergeWorkspaceRecentFlowMetrics = (workspaces, previousCache) => {
12949
- const nextCache = /* @__PURE__ */ new Map();
12950
- const mergedWorkspaces = workspaces.map((workspace) => {
12951
- const cacheKey = getWorkspaceRecentFlowCacheKey(workspace);
12952
- const currentSnapshot = toRecentFlowSnapshot(workspace);
12953
- if (workspace.recent_flow_mode === "computed" && currentSnapshot) {
12954
- nextCache.set(cacheKey, currentSnapshot);
12955
- return workspace;
12956
- }
12957
- if (workspace.recent_flow_mode === "hold") {
12958
- const cachedSnapshot = previousCache.get(cacheKey);
12959
- if (cachedSnapshot) {
12960
- nextCache.set(cacheKey, cachedSnapshot);
12961
- return {
12962
- ...workspace,
12963
- ...cachedSnapshot,
12964
- recent_flow_mode: "hold"
12965
- };
12966
- }
12967
- }
12968
- return workspace;
12969
- });
12970
- return {
12971
- workspaces: mergedWorkspaces,
12972
- cache: nextCache
12973
- };
12974
- };
12975
-
12976
12933
  // src/lib/hooks/useDashboardMetrics.ts
12977
12934
  var DEBUG_DASHBOARD_LOGS = process.env.NEXT_PUBLIC_DEBUG_DASHBOARD === "true";
12978
12935
  var logDebug = (...args) => {
@@ -13061,7 +13018,6 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
13061
13018
  const abortControllerRef = useRef(null);
13062
13019
  const lastFetchKeyRef = useRef(null);
13063
13020
  const inFlightFetchKeyRef = useRef(null);
13064
- const recentFlowCacheRef = useRef(/* @__PURE__ */ new Map());
13065
13021
  const updateQueueRef = useRef(false);
13066
13022
  const onLineMetricsUpdateRef = useRef(onLineMetricsUpdate);
13067
13023
  const shiftGroupsRef = useRef(shiftGroups);
@@ -13095,7 +13051,6 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
13095
13051
  setError(null);
13096
13052
  lastFetchKeyRef.current = null;
13097
13053
  inFlightFetchKeyRef.current = null;
13098
- recentFlowCacheRef.current = /* @__PURE__ */ new Map();
13099
13054
  }, [lineId]);
13100
13055
  const fetchAllMetrics = useCallback(async (options = {}) => {
13101
13056
  const { force = false } = options;
@@ -13370,12 +13325,9 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
13370
13325
  actionType: item.action_type,
13371
13326
  actionName: item.action_name
13372
13327
  }),
13373
- recent_flow_mode: item.recent_flow_mode ?? void 0,
13374
13328
  recent_flow_percent: item.recent_flow_percent ?? null,
13375
- recent_flow_actual_rate_pph: item.recent_flow_actual_rate_pph ?? null,
13376
- recent_flow_healthy_rate_pph: item.recent_flow_healthy_rate_pph ?? null,
13377
- recent_flow_window_minutes: item.recent_flow_window_minutes ?? null,
13378
13329
  recent_flow_effective_end_at: item.recent_flow_effective_end_at ?? null,
13330
+ recent_flow_computed_at: item.recent_flow_computed_at ?? null,
13379
13331
  incoming_wip_current: item.incoming_wip_current ?? null,
13380
13332
  incoming_wip_effective_at: item.incoming_wip_effective_at ?? null,
13381
13333
  incoming_wip_buffer_name: item.incoming_wip_buffer_name ?? null
@@ -13386,16 +13338,11 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
13386
13338
  const wsNumB = parseInt(b.workspace_name?.replace(/[^0-9]/g, "") || "0");
13387
13339
  return wsNumA - wsNumB;
13388
13340
  });
13389
- const {
13390
- workspaces: mergedWorkspaceData,
13391
- cache: nextRecentFlowCache
13392
- } = mergeWorkspaceRecentFlowMetrics(transformedWorkspaceData, recentFlowCacheRef.current);
13393
- recentFlowCacheRef.current = nextRecentFlowCache;
13394
- mergedWorkspaceData.forEach((metric) => {
13341
+ transformedWorkspaceData.forEach((metric) => {
13395
13342
  workspaceMetricsStore.setOverview(metric);
13396
13343
  });
13397
13344
  const newMetricsState = {
13398
- workspaceMetrics: mergedWorkspaceData,
13345
+ workspaceMetrics: transformedWorkspaceData,
13399
13346
  lineMetrics: allLineMetrics || [],
13400
13347
  metadata: { hasFlowBuffers, idleTimeVlmByLine },
13401
13348
  efficiencyLegend: efficiencyLegend ?? DEFAULT_EFFICIENCY_LEGEND
@@ -16820,7 +16767,7 @@ var useActiveBreaks = (lineIds) => {
16820
16767
  const [isLoading, setIsLoading] = useState(true);
16821
16768
  const [error, setError] = useState(null);
16822
16769
  const supabase = useSupabase();
16823
- const parseTimeToMinutes3 = (timeStr) => {
16770
+ const parseTimeToMinutes4 = (timeStr) => {
16824
16771
  const [hours, minutes] = timeStr.split(":").map(Number);
16825
16772
  return hours * 60 + minutes;
16826
16773
  };
@@ -16829,8 +16776,8 @@ var useActiveBreaks = (lineIds) => {
16829
16776
  return now4.getHours() * 60 + now4.getMinutes();
16830
16777
  };
16831
16778
  const isTimeInBreak = (breakStart, breakEnd, currentMinutes) => {
16832
- const startMinutes = parseTimeToMinutes3(breakStart);
16833
- const endMinutes = parseTimeToMinutes3(breakEnd);
16779
+ const startMinutes = parseTimeToMinutes4(breakStart);
16780
+ const endMinutes = parseTimeToMinutes4(breakEnd);
16834
16781
  if (endMinutes < startMinutes) {
16835
16782
  return currentMinutes >= startMinutes || currentMinutes < endMinutes;
16836
16783
  } else {
@@ -16838,8 +16785,8 @@ var useActiveBreaks = (lineIds) => {
16838
16785
  }
16839
16786
  };
16840
16787
  const calculateBreakProgress = (breakStart, breakEnd, currentMinutes) => {
16841
- const startMinutes = parseTimeToMinutes3(breakStart);
16842
- const endMinutes = parseTimeToMinutes3(breakEnd);
16788
+ const startMinutes = parseTimeToMinutes4(breakStart);
16789
+ const endMinutes = parseTimeToMinutes4(breakEnd);
16843
16790
  let elapsedMinutes = 0;
16844
16791
  let remainingMinutes = 0;
16845
16792
  if (endMinutes < startMinutes) {
@@ -16857,8 +16804,8 @@ var useActiveBreaks = (lineIds) => {
16857
16804
  return { elapsedMinutes, remainingMinutes };
16858
16805
  };
16859
16806
  const isTimeInShift = (startTime, endTime, currentMinutes) => {
16860
- const startMinutes = parseTimeToMinutes3(startTime);
16861
- const endMinutes = parseTimeToMinutes3(endTime);
16807
+ const startMinutes = parseTimeToMinutes4(startTime);
16808
+ const endMinutes = parseTimeToMinutes4(endTime);
16862
16809
  if (endMinutes < startMinutes) {
16863
16810
  return currentMinutes >= startMinutes || currentMinutes < endMinutes;
16864
16811
  } else {
@@ -16918,8 +16865,8 @@ var useActiveBreaks = (lineIds) => {
16918
16865
  const endTime = breakItem.end || breakItem.endTime || "00:00";
16919
16866
  let duration = breakItem.duration || 0;
16920
16867
  if (!duration || duration === 0) {
16921
- const startMinutes = parseTimeToMinutes3(startTime);
16922
- const endMinutes = parseTimeToMinutes3(endTime);
16868
+ const startMinutes = parseTimeToMinutes4(startTime);
16869
+ const endMinutes = parseTimeToMinutes4(endTime);
16923
16870
  duration = endMinutes < startMinutes ? endMinutes + 24 * 60 - startMinutes : endMinutes - startMinutes;
16924
16871
  }
16925
16872
  return {
@@ -16935,8 +16882,8 @@ var useActiveBreaks = (lineIds) => {
16935
16882
  const endTime = breakItem.end || breakItem.endTime || "00:00";
16936
16883
  let duration = breakItem.duration || 0;
16937
16884
  if (!duration || duration === 0) {
16938
- const startMinutes = parseTimeToMinutes3(startTime);
16939
- const endMinutes = parseTimeToMinutes3(endTime);
16885
+ const startMinutes = parseTimeToMinutes4(startTime);
16886
+ const endMinutes = parseTimeToMinutes4(endTime);
16940
16887
  duration = endMinutes < startMinutes ? endMinutes + 24 * 60 - startMinutes : endMinutes - startMinutes;
16941
16888
  }
16942
16889
  return {
@@ -23017,6 +22964,16 @@ var createThrottledReload = (interval = 5e3, maxReloads = 3) => {
23017
22964
  };
23018
22965
  var throttledReloadDashboard = createThrottledReload(5e3, 3);
23019
22966
 
22967
+ // src/lib/utils/dev/localDevTestLogin.ts
22968
+ var isLoopbackHostname = (hostname) => {
22969
+ const normalized = String(hostname || "").trim().toLowerCase();
22970
+ return normalized === "localhost" || normalized === "127.0.0.1" || normalized === "::1";
22971
+ };
22972
+ var shouldEnableLocalDevTestLogin = ({
22973
+ enabledFlag,
22974
+ hostname
22975
+ }) => enabledFlag && isLoopbackHostname(hostname);
22976
+
23020
22977
  // src/lib/utils/index.ts
23021
22978
  var formatIdleTime = (idleTimeInSeconds) => {
23022
22979
  if (!idleTimeInSeconds || idleTimeInSeconds <= 0) {
@@ -31201,12 +31158,16 @@ var LoginPage = ({
31201
31158
  onRateLimitCheck,
31202
31159
  logoSrc = optifye_logo_default,
31203
31160
  logoAlt = "Optifye",
31204
- brandName = "Optifye"
31161
+ brandName = "Optifye",
31162
+ showDevTestLogin = false,
31163
+ devTestLoginLabel = "Sign in as Test User",
31164
+ onDevTestLogin
31205
31165
  }) => {
31206
31166
  const [email, setEmail] = useState("");
31207
31167
  const [otp, setOtp] = useState("");
31208
31168
  const [step, setStep] = useState("email");
31209
31169
  const [loading, setLoading] = useState(false);
31170
+ const [devLoginLoading, setDevLoginLoading] = useState(false);
31210
31171
  const [error, setError] = useState(null);
31211
31172
  const [countdown, setCountdown] = useState(0);
31212
31173
  const supabase = useSupabase();
@@ -31270,6 +31231,25 @@ var LoginPage = ({
31270
31231
  startCountdown();
31271
31232
  }
31272
31233
  };
31234
+ const handleDevTestLogin = async () => {
31235
+ if (!onDevTestLogin) {
31236
+ return;
31237
+ }
31238
+ setDevLoginLoading(true);
31239
+ setError(null);
31240
+ try {
31241
+ const result = await onDevTestLogin();
31242
+ const nextError = typeof result === "object" && result !== null && "error" in result ? result.error : null;
31243
+ if (typeof nextError === "string" && nextError.trim()) {
31244
+ setError(nextError);
31245
+ }
31246
+ } catch (err) {
31247
+ console.error("Dev test login failed:", err);
31248
+ setError("Dev test login unavailable.");
31249
+ } finally {
31250
+ setDevLoginLoading(false);
31251
+ }
31252
+ };
31273
31253
  return /* @__PURE__ */ jsx("div", { className: "min-h-screen flex items-center justify-center bg-gradient-to-br from-slate-50 to-slate-100", children: /* @__PURE__ */ jsxs("div", { className: "max-w-md w-full mx-4", children: [
31274
31254
  /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-2xl shadow-xl border border-slate-200 p-8", children: [
31275
31255
  /* @__PURE__ */ jsxs("div", { className: "text-center mb-8", children: [
@@ -31310,7 +31290,7 @@ var LoginPage = ({
31310
31290
  "button",
31311
31291
  {
31312
31292
  type: "submit",
31313
- disabled: loading,
31293
+ disabled: loading || devLoginLoading,
31314
31294
  className: "w-full py-3 px-4 bg-slate-900 hover:bg-slate-800 focus:ring-2 focus:ring-slate-600 focus:ring-offset-2 text-white font-medium rounded-xl transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center",
31315
31295
  children: loading ? /* @__PURE__ */ jsxs(Fragment, { children: [
31316
31296
  /* @__PURE__ */ jsxs("svg", { className: "animate-spin -ml-1 mr-3 h-4 w-4 text-white", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [
@@ -31320,7 +31300,31 @@ var LoginPage = ({
31320
31300
  "Sending..."
31321
31301
  ] }) : "Continue with Email"
31322
31302
  }
31323
- )
31303
+ ),
31304
+ showDevTestLogin && onDevTestLogin ? /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
31305
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
31306
+ /* @__PURE__ */ jsx("div", { className: "h-px flex-1 bg-slate-200" }),
31307
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium uppercase tracking-[0.2em] text-slate-400", children: "Local Dev" }),
31308
+ /* @__PURE__ */ jsx("div", { className: "h-px flex-1 bg-slate-200" })
31309
+ ] }),
31310
+ /* @__PURE__ */ jsx(
31311
+ "button",
31312
+ {
31313
+ type: "button",
31314
+ disabled: loading || devLoginLoading,
31315
+ onClick: () => void handleDevTestLogin(),
31316
+ className: "w-full py-3 px-4 bg-white hover:bg-slate-50 focus:ring-2 focus:ring-slate-400 focus:ring-offset-2 text-slate-700 font-medium rounded-xl border border-slate-200 transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center",
31317
+ children: devLoginLoading ? /* @__PURE__ */ jsxs(Fragment, { children: [
31318
+ /* @__PURE__ */ jsxs("svg", { className: "animate-spin -ml-1 mr-3 h-4 w-4 text-slate-700", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [
31319
+ /* @__PURE__ */ jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
31320
+ /* @__PURE__ */ jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" })
31321
+ ] }),
31322
+ "Signing In..."
31323
+ ] }) : devTestLoginLabel
31324
+ }
31325
+ ),
31326
+ /* @__PURE__ */ jsx("p", { className: "text-center text-xs text-slate-500", children: "Localhost-only convenience login for the shared test account." })
31327
+ ] }) : null
31324
31328
  ] }) : /* @__PURE__ */ jsxs("form", { className: "space-y-6", onSubmit: handleVerifyOTP, children: [
31325
31329
  /* @__PURE__ */ jsxs("div", { children: [
31326
31330
  /* @__PURE__ */ jsx("label", { htmlFor: "otp", className: "block text-sm font-medium text-slate-700 mb-2 text-center", children: "Enter the 6-digit code sent to" }),
@@ -31345,7 +31349,7 @@ var LoginPage = ({
31345
31349
  "button",
31346
31350
  {
31347
31351
  type: "submit",
31348
- disabled: loading || otp.length !== 6,
31352
+ disabled: loading || devLoginLoading || otp.length !== 6,
31349
31353
  className: "w-full py-3 px-4 bg-slate-900 hover:bg-slate-800 focus:ring-2 focus:ring-slate-600 focus:ring-offset-2 text-white font-medium rounded-xl transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center",
31350
31354
  children: loading ? /* @__PURE__ */ jsxs(Fragment, { children: [
31351
31355
  /* @__PURE__ */ jsxs("svg", { className: "animate-spin -ml-1 mr-3 h-4 w-4 text-white", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [
@@ -32186,31 +32190,35 @@ var LineChartComponent = ({
32186
32190
  ...restOfChartProps
32187
32191
  }) => {
32188
32192
  const containerRef = React141__default.useRef(null);
32189
- const [containerReady, setContainerReady] = React141__default.useState(false);
32190
- const themeConfig = useThemeConfig();
32191
- const { formatNumber } = useFormatNumber();
32193
+ const [dimensions, setDimensions] = React141__default.useState({ width: 0, height: 0 });
32194
+ const [hasValidData, setHasValidData] = React141__default.useState(false);
32192
32195
  React141__default.useEffect(() => {
32193
- const checkContainerDimensions = () => {
32194
- if (containerRef.current) {
32195
- const rect = containerRef.current.getBoundingClientRect();
32196
- if (rect.width > 0 && rect.height > 0) {
32197
- setContainerReady(true);
32198
- }
32199
- }
32200
- };
32201
- checkContainerDimensions();
32202
- const resizeObserver = new ResizeObserver(checkContainerDimensions);
32203
- if (containerRef.current) {
32204
- resizeObserver.observe(containerRef.current);
32196
+ const currentHasValidData = data && lines && lines.length > 0 && data.some(
32197
+ (item) => lines.some((line) => {
32198
+ const val = item[line.dataKey];
32199
+ return typeof val === "number" && val > 0;
32200
+ })
32201
+ );
32202
+ if (currentHasValidData && !hasValidData) {
32203
+ setHasValidData(true);
32205
32204
  }
32206
- const fallbackTimeout = setTimeout(() => {
32207
- setContainerReady(true);
32208
- }, 100);
32209
- return () => {
32210
- resizeObserver.disconnect();
32211
- clearTimeout(fallbackTimeout);
32212
- };
32205
+ }, [data, lines, hasValidData]);
32206
+ React141__default.useEffect(() => {
32207
+ if (!containerRef.current) return;
32208
+ const observer = new ResizeObserver((entries) => {
32209
+ const entry = entries[0];
32210
+ if (entry) {
32211
+ setDimensions({
32212
+ width: entry.contentRect.width,
32213
+ height: entry.contentRect.height
32214
+ });
32215
+ }
32216
+ });
32217
+ observer.observe(containerRef.current);
32218
+ return () => observer.disconnect();
32213
32219
  }, []);
32220
+ const themeConfig = useThemeConfig();
32221
+ const { formatNumber } = useFormatNumber();
32214
32222
  const yAxisTickFormatter = (value) => {
32215
32223
  return `${formatNumber(value)}${yAxisUnit || ""}`;
32216
32224
  };
@@ -32232,57 +32240,71 @@ var LineChartComponent = ({
32232
32240
  const gridStrokeColor = themeConfig?.gray?.["300"] || "#ccc";
32233
32241
  const axisTickFillColor = themeConfig?.gray?.["600"] || "#666";
32234
32242
  const axisStrokeColor = themeConfig?.gray?.["400"] || "#999";
32235
- const chartContent = /* @__PURE__ */ jsxs(LineChart$1, { data, margin: { top: 5, right: 30, left: 20, bottom: 20 }, ...restOfChartProps, children: [
32236
- showGrid && /* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", stroke: gridStrokeColor }),
32237
- /* @__PURE__ */ jsx(
32238
- XAxis,
32239
- {
32240
- dataKey: xAxisDataKey,
32241
- label: xAxisLabel ? { value: xAxisLabel, position: "insideBottom", offset: -10 } : void 0,
32242
- tickFormatter: xAxisTickFormatter,
32243
- tick: { fontSize: 12, fill: axisTickFillColor },
32244
- stroke: axisStrokeColor
32245
- }
32246
- ),
32247
- /* @__PURE__ */ jsx(
32248
- YAxis,
32249
- {
32250
- label: yAxisLabel ? { value: yAxisLabel, angle: -90, position: "insideLeft" } : void 0,
32251
- tickFormatter: yAxisTickFormatter,
32252
- domain: yAxisDomain,
32253
- tick: { fontSize: 12, fill: axisTickFillColor },
32254
- stroke: axisStrokeColor
32255
- }
32256
- ),
32257
- showTooltip && /* @__PURE__ */ jsx(
32258
- Tooltip,
32259
- {
32260
- formatter: tooltipFormatter || defaultTooltipFormatter,
32261
- labelFormatter: tooltipLabelFormatter,
32262
- itemStyle: { color: "#111827" },
32263
- cursor: { strokeDasharray: "3 3" }
32264
- }
32265
- ),
32266
- showLegend && /* @__PURE__ */ jsx(Legend, { payload: legendPayload }),
32267
- lines.map((lineConfig, index) => {
32268
- const lineProps = {
32269
- ...lineConfig,
32270
- key: lineConfig.dataKey,
32271
- type: lineConfig.type || "monotone",
32272
- stroke: lineConfig.stroke || defaultColors[index % defaultColors.length],
32273
- activeDot: lineConfig.activeDot !== void 0 ? lineConfig.activeDot : { r: 6 }
32274
- };
32275
- return /* @__PURE__ */ jsx(Line, { ...lineProps, children: lineConfig.labelList && /* @__PURE__ */ jsx(
32276
- LabelList,
32277
- {
32278
- dataKey: lineConfig.dataKey,
32279
- position: "top",
32280
- formatter: (value) => formatNumber(value),
32281
- ...typeof lineConfig.labelList === "object" ? lineConfig.labelList : {}
32282
- }
32283
- ) });
32284
- })
32285
- ] });
32243
+ const renderChartContent = (chartWidth, chartHeight) => /* @__PURE__ */ jsxs(
32244
+ LineChart$1,
32245
+ {
32246
+ width: chartWidth,
32247
+ height: chartHeight,
32248
+ data,
32249
+ margin: { top: 5, right: 30, left: 20, bottom: 20 },
32250
+ ...restOfChartProps,
32251
+ children: [
32252
+ showGrid && /* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", stroke: gridStrokeColor }),
32253
+ /* @__PURE__ */ jsx(
32254
+ XAxis,
32255
+ {
32256
+ dataKey: xAxisDataKey,
32257
+ label: xAxisLabel ? { value: xAxisLabel, position: "insideBottom", offset: -10 } : void 0,
32258
+ tickFormatter: xAxisTickFormatter,
32259
+ tick: { fontSize: 12, fill: axisTickFillColor },
32260
+ stroke: axisStrokeColor
32261
+ }
32262
+ ),
32263
+ /* @__PURE__ */ jsx(
32264
+ YAxis,
32265
+ {
32266
+ label: yAxisLabel ? { value: yAxisLabel, angle: -90, position: "insideLeft" } : void 0,
32267
+ tickFormatter: yAxisTickFormatter,
32268
+ domain: yAxisDomain,
32269
+ tick: { fontSize: 12, fill: axisTickFillColor },
32270
+ stroke: axisStrokeColor
32271
+ }
32272
+ ),
32273
+ showTooltip && /* @__PURE__ */ jsx(
32274
+ Tooltip,
32275
+ {
32276
+ formatter: tooltipFormatter || defaultTooltipFormatter,
32277
+ labelFormatter: tooltipLabelFormatter,
32278
+ itemStyle: { color: "#111827" },
32279
+ cursor: { strokeDasharray: "3 3" }
32280
+ }
32281
+ ),
32282
+ showLegend && /* @__PURE__ */ jsx(Legend, { payload: legendPayload }),
32283
+ lines.map((lineConfig, index) => {
32284
+ const lineProps = {
32285
+ ...lineConfig,
32286
+ key: lineConfig.dataKey,
32287
+ type: lineConfig.type || "monotone",
32288
+ stroke: lineConfig.stroke || defaultColors[index % defaultColors.length],
32289
+ activeDot: lineConfig.activeDot !== void 0 ? lineConfig.activeDot : { r: 6 },
32290
+ isAnimationActive: true,
32291
+ animationDuration: 1500,
32292
+ animationBegin: 300
32293
+ };
32294
+ return /* @__PURE__ */ jsx(Line, { ...lineProps, children: lineConfig.labelList && /* @__PURE__ */ jsx(
32295
+ LabelList,
32296
+ {
32297
+ dataKey: lineConfig.dataKey,
32298
+ position: "top",
32299
+ formatter: (value) => formatNumber(value),
32300
+ ...typeof lineConfig.labelList === "object" ? lineConfig.labelList : {}
32301
+ }
32302
+ ) });
32303
+ })
32304
+ ]
32305
+ },
32306
+ hasValidData ? "valid" : "empty"
32307
+ );
32286
32308
  if (responsive) {
32287
32309
  return /* @__PURE__ */ jsx(
32288
32310
  "div",
@@ -32290,11 +32312,20 @@ var LineChartComponent = ({
32290
32312
  ref: containerRef,
32291
32313
  className: clsx(fillContainer ? "w-full h-full" : "w-full h-auto", className),
32292
32314
  style: fillContainer ? { height: "100%", minHeight: "50px", minWidth: "100px" } : { aspectRatio: `${aspect}/1`, minHeight: "50px", minWidth: "100px" },
32293
- children: containerReady ? /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: chartContent }) : /* @__PURE__ */ jsx("div", { className: "w-full h-full flex items-center justify-center bg-gray-50 rounded-lg", children: /* @__PURE__ */ jsx("div", { className: "text-gray-500 text-sm", children: "Loading chart..." }) })
32315
+ children: /* @__PURE__ */ jsx(
32316
+ motion.div,
32317
+ {
32318
+ initial: { opacity: 0 },
32319
+ animate: { opacity: 1 },
32320
+ transition: { duration: 0.5 },
32321
+ className: "w-full h-full",
32322
+ children: dimensions.width > 0 && dimensions.height > 0 && renderChartContent(dimensions.width, dimensions.height)
32323
+ }
32324
+ )
32294
32325
  }
32295
32326
  );
32296
32327
  }
32297
- return /* @__PURE__ */ jsx("div", { className: clsx("w-full", className), children: chartContent });
32328
+ return /* @__PURE__ */ jsx("div", { className: clsx("w-full", className), children: renderChartContent(restOfChartProps.width, restOfChartProps.height) });
32298
32329
  };
32299
32330
  var LineChart = React141__default.memo(LineChartComponent, (prevProps, nextProps) => {
32300
32331
  if (prevProps.xAxisDataKey !== nextProps.xAxisDataKey || prevProps.xAxisLabel !== nextProps.xAxisLabel || prevProps.yAxisLabel !== nextProps.yAxisLabel || prevProps.yAxisUnit !== nextProps.yAxisUnit || prevProps.className !== nextProps.className || prevProps.showGrid !== nextProps.showGrid || prevProps.showLegend !== nextProps.showLegend || prevProps.showTooltip !== nextProps.showTooltip || prevProps.responsive !== nextProps.responsive || prevProps.aspect !== nextProps.aspect || JSON.stringify(prevProps.yAxisDomain) !== JSON.stringify(nextProps.yAxisDomain)) {
@@ -32562,14 +32593,35 @@ var CycleTimeOverTimeChart = ({
32562
32593
  }) => {
32563
32594
  const MAX_DATA_POINTS = 40;
32564
32595
  const containerRef = React141__default.useRef(null);
32565
- const [containerReady, setContainerReady] = React141__default.useState(false);
32566
- const parseTimeToMinutes3 = (value) => {
32596
+ const [dimensions, setDimensions] = React141__default.useState({ width: 0, height: 0 });
32597
+ const [hasValidData, setHasValidData] = React141__default.useState(false);
32598
+ React141__default.useEffect(() => {
32599
+ const currentHasValidData = data && data.some((val) => val !== null && val > 0);
32600
+ if (currentHasValidData && !hasValidData) {
32601
+ setHasValidData(true);
32602
+ }
32603
+ }, [data, hasValidData]);
32604
+ React141__default.useEffect(() => {
32605
+ if (!containerRef.current) return;
32606
+ const observer = new ResizeObserver((entries) => {
32607
+ const entry = entries[0];
32608
+ if (entry) {
32609
+ setDimensions({
32610
+ width: entry.contentRect.width,
32611
+ height: entry.contentRect.height
32612
+ });
32613
+ }
32614
+ });
32615
+ observer.observe(containerRef.current);
32616
+ return () => observer.disconnect();
32617
+ }, []);
32618
+ const parseTimeToMinutes4 = (value) => {
32567
32619
  const [hours, minutes] = value.split(":").map(Number);
32568
32620
  if (!Number.isFinite(hours) || !Number.isFinite(minutes)) return 0;
32569
32621
  return hours * 60 + minutes;
32570
32622
  };
32571
32623
  const formatHourLabel = (slotIndex) => {
32572
- const baseMinutes = parseTimeToMinutes3(shiftStart);
32624
+ const baseMinutes = parseTimeToMinutes4(shiftStart);
32573
32625
  const absoluteMinutes = baseMinutes + slotIndex * 60;
32574
32626
  const hour24 = Math.floor(absoluteMinutes % (24 * 60) / 60);
32575
32627
  const ampm = hour24 >= 12 ? "PM" : "AM";
@@ -32588,52 +32640,7 @@ var CycleTimeOverTimeChart = ({
32588
32640
  const displayData = getDisplayData(data);
32589
32641
  const DURATION = displayData.length;
32590
32642
  const effectiveDatasetKey = datasetKey || `cycle-time:${xAxisMode}`;
32591
- const [animatedDatasetKey, setAnimatedDatasetKey] = React141__default.useState(null);
32592
- const shouldAnimate = animatedDatasetKey !== effectiveDatasetKey;
32593
- const handleAnimationEnd = React141__default.useCallback(() => {
32594
- setAnimatedDatasetKey((currentValue) => currentValue === effectiveDatasetKey ? currentValue : effectiveDatasetKey);
32595
- }, [effectiveDatasetKey]);
32596
32643
  const finalData = displayData;
32597
- React141__default.useEffect(() => {
32598
- const containerNode = containerRef.current;
32599
- if (!containerNode) {
32600
- setContainerReady(true);
32601
- return void 0;
32602
- }
32603
- let frameId = null;
32604
- let resizeObserver = null;
32605
- const checkContainerDimensions = () => {
32606
- const rect = containerNode.getBoundingClientRect();
32607
- const isReady = rect.width > 0 && rect.height > 0;
32608
- if (isReady) {
32609
- setContainerReady(true);
32610
- }
32611
- return isReady;
32612
- };
32613
- if (checkContainerDimensions()) {
32614
- return void 0;
32615
- }
32616
- frameId = window.requestAnimationFrame(() => {
32617
- checkContainerDimensions();
32618
- });
32619
- if (typeof ResizeObserver !== "undefined") {
32620
- resizeObserver = new ResizeObserver(() => {
32621
- if (checkContainerDimensions() && resizeObserver) {
32622
- resizeObserver.disconnect();
32623
- resizeObserver = null;
32624
- }
32625
- });
32626
- resizeObserver.observe(containerNode);
32627
- } else {
32628
- setContainerReady(true);
32629
- }
32630
- return () => {
32631
- if (frameId !== null) {
32632
- window.cancelAnimationFrame(frameId);
32633
- }
32634
- resizeObserver?.disconnect();
32635
- };
32636
- }, []);
32637
32644
  const labelInterval = React141__default.useMemo(() => {
32638
32645
  if (xAxisMode === "hourly") {
32639
32646
  return Math.max(1, Math.ceil(DURATION / 8));
@@ -32841,144 +32848,154 @@ var CycleTimeOverTimeChart = ({
32841
32848
  return /* @__PURE__ */ jsxs(
32842
32849
  "div",
32843
32850
  {
32844
- ref: containerRef,
32845
32851
  className: `w-full h-full min-w-0 flex flex-col relative pb-2 ${className}`,
32846
32852
  style: { minHeight: "200px", minWidth: 0 },
32847
32853
  children: [
32848
32854
  renderLegend(),
32849
- /* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 w-full", children: containerReady ? /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
32850
- LineChart$1,
32855
+ /* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 w-full", ref: containerRef, children: /* @__PURE__ */ jsx(
32856
+ motion.div,
32851
32857
  {
32852
- data: chartData,
32853
- margin: {
32854
- top: 5,
32855
- right: 30,
32856
- bottom: 25,
32857
- left: 10
32858
- },
32859
- children: [
32860
- /* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", vertical: false }),
32861
- /* @__PURE__ */ jsx(
32862
- XAxis,
32863
- {
32864
- dataKey: "label",
32865
- tick: { fontSize: 11 },
32866
- interval: 0,
32867
- angle: xAxisMode === "hourly" ? 0 : -30,
32868
- textAnchor: xAxisMode === "hourly" ? "middle" : "end",
32869
- tickMargin: xAxisMode === "hourly" ? 8 : 15,
32870
- height: xAxisMode === "hourly" ? 40 : 60
32871
- }
32872
- ),
32873
- /* @__PURE__ */ jsx(
32874
- YAxis,
32875
- {
32876
- tickMargin: 8,
32877
- width: 45,
32878
- yAxisId: "cycle",
32879
- domain: ["auto", "auto"],
32880
- ticks: [0, idealCycleTime, ...Array.from({ length: 4 }, (_, i) => (i + 1) * Math.ceil(idealCycleTime / 2))].sort((a, b) => a - b),
32881
- tickFormatter: (value) => String(value),
32882
- tick: (props) => {
32883
- const { x, y, payload } = props;
32884
- const displayValue = typeof payload.value === "number" ? payload.value.toFixed(1) : String(payload.value);
32885
- return /* @__PURE__ */ jsx("g", { transform: `translate(${x},${y})`, children: /* @__PURE__ */ jsx(
32886
- "text",
32887
- {
32888
- x: 0,
32889
- y: 0,
32890
- dy: 4,
32891
- textAnchor: "end",
32892
- fill: payload.value === idealCycleTime ? "#E34329" : "#666",
32893
- fontSize: 12,
32894
- fontWeight: payload.value === idealCycleTime ? "bold" : "normal",
32895
- children: displayValue
32896
- },
32897
- `tick-${payload.value}-${x}-${y}`
32898
- ) });
32899
- }
32900
- }
32901
- ),
32902
- showIdleTime && /* @__PURE__ */ jsx(
32903
- YAxis,
32904
- {
32905
- yAxisId: "idle",
32906
- orientation: "right",
32907
- tickMargin: 8,
32908
- width: 35,
32909
- domain: [0, 60],
32910
- tickFormatter: (value) => `${value}m`,
32911
- tick: { fontSize: 11, fill: "#f59e0b" },
32912
- axisLine: false,
32913
- tickLine: false
32914
- }
32915
- ),
32916
- /* @__PURE__ */ jsx(
32917
- Tooltip,
32918
- {
32919
- cursor: { stroke: "#E5E7EB", strokeWidth: 1 },
32920
- content: renderChartTooltip,
32921
- animationDuration: 200
32922
- }
32923
- ),
32924
- /* @__PURE__ */ jsx(
32925
- ReferenceLine,
32926
- {
32927
- y: idealCycleTime,
32928
- yAxisId: "cycle",
32929
- stroke: "#E34329",
32930
- strokeDasharray: "3 3",
32931
- strokeWidth: 2,
32932
- label: {
32933
- position: "right",
32934
- value: `${idealCycleTime.toFixed(1)}s`,
32935
- fill: "#E34329",
32936
- fontSize: 12,
32937
- fontWeight: 500
32938
- }
32939
- }
32940
- ),
32941
- /* @__PURE__ */ jsx(
32942
- Line,
32943
- {
32944
- type: "monotone",
32945
- yAxisId: "cycle",
32946
- dataKey: "cycleTime",
32947
- stroke: "#3B82F6",
32948
- strokeWidth: 2,
32949
- connectNulls: false,
32950
- dot: renderCycleDot,
32951
- activeDot: renderCycleActiveDot,
32952
- isAnimationActive: shouldAnimate,
32953
- animationBegin: 0,
32954
- animationDuration: 1200,
32955
- animationEasing: "ease-out",
32956
- onAnimationEnd: handleAnimationEnd
32957
- },
32958
- `${effectiveDatasetKey}:cycle`
32959
- ),
32960
- showIdleTime && /* @__PURE__ */ jsx(
32961
- Line,
32962
- {
32963
- type: "monotone",
32964
- yAxisId: "idle",
32965
- dataKey: "idleMinutes",
32966
- stroke: "#f59e0b",
32967
- strokeWidth: 2,
32968
- strokeDasharray: "4 4",
32969
- connectNulls: false,
32970
- dot: renderIdleDot,
32971
- activeDot: renderIdleActiveDot,
32972
- isAnimationActive: shouldAnimate,
32973
- animationBegin: 0,
32974
- animationDuration: 1200,
32975
- animationEasing: "ease-out"
32858
+ initial: { opacity: 0 },
32859
+ animate: { opacity: 1 },
32860
+ transition: { duration: 0.5 },
32861
+ className: "w-full h-full",
32862
+ children: dimensions.width > 0 && dimensions.height > 0 && /* @__PURE__ */ jsxs(
32863
+ LineChart$1,
32864
+ {
32865
+ width: dimensions.width,
32866
+ height: dimensions.height,
32867
+ data: chartData,
32868
+ margin: {
32869
+ top: 5,
32870
+ right: 30,
32871
+ bottom: 25,
32872
+ left: 10
32976
32873
  },
32977
- `${effectiveDatasetKey}:idle`
32978
- )
32979
- ]
32874
+ children: [
32875
+ /* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", vertical: false }),
32876
+ /* @__PURE__ */ jsx(
32877
+ XAxis,
32878
+ {
32879
+ dataKey: "label",
32880
+ tick: { fontSize: 11 },
32881
+ interval: 0,
32882
+ angle: xAxisMode === "hourly" ? 0 : -30,
32883
+ textAnchor: xAxisMode === "hourly" ? "middle" : "end",
32884
+ tickMargin: xAxisMode === "hourly" ? 8 : 15,
32885
+ height: xAxisMode === "hourly" ? 40 : 60
32886
+ }
32887
+ ),
32888
+ /* @__PURE__ */ jsx(
32889
+ YAxis,
32890
+ {
32891
+ tickMargin: 8,
32892
+ width: 45,
32893
+ yAxisId: "cycle",
32894
+ domain: ["auto", "auto"],
32895
+ ticks: [0, idealCycleTime, ...Array.from({ length: 4 }, (_, i) => (i + 1) * Math.ceil(idealCycleTime / 2))].sort((a, b) => a - b),
32896
+ tickFormatter: (value) => String(value),
32897
+ tick: (props) => {
32898
+ const { x, y, payload } = props;
32899
+ const displayValue = typeof payload.value === "number" ? payload.value.toFixed(1) : String(payload.value);
32900
+ return /* @__PURE__ */ jsx("g", { transform: `translate(${x},${y})`, children: /* @__PURE__ */ jsx(
32901
+ "text",
32902
+ {
32903
+ x: 0,
32904
+ y: 0,
32905
+ dy: 4,
32906
+ textAnchor: "end",
32907
+ fill: payload.value === idealCycleTime ? "#E34329" : "#666",
32908
+ fontSize: 12,
32909
+ fontWeight: payload.value === idealCycleTime ? "bold" : "normal",
32910
+ children: displayValue
32911
+ },
32912
+ `tick-${payload.value}-${x}-${y}`
32913
+ ) });
32914
+ }
32915
+ }
32916
+ ),
32917
+ showIdleTime && /* @__PURE__ */ jsx(
32918
+ YAxis,
32919
+ {
32920
+ yAxisId: "idle",
32921
+ orientation: "right",
32922
+ tickMargin: 8,
32923
+ width: 35,
32924
+ domain: [0, 60],
32925
+ tickFormatter: (value) => `${value}m`,
32926
+ tick: { fontSize: 11, fill: "#f59e0b" },
32927
+ axisLine: false,
32928
+ tickLine: false
32929
+ }
32930
+ ),
32931
+ /* @__PURE__ */ jsx(
32932
+ Tooltip,
32933
+ {
32934
+ cursor: { stroke: "#E5E7EB", strokeWidth: 1 },
32935
+ content: renderChartTooltip,
32936
+ animationDuration: 200
32937
+ }
32938
+ ),
32939
+ /* @__PURE__ */ jsx(
32940
+ ReferenceLine,
32941
+ {
32942
+ y: idealCycleTime,
32943
+ yAxisId: "cycle",
32944
+ stroke: "#E34329",
32945
+ strokeDasharray: "3 3",
32946
+ strokeWidth: 2,
32947
+ label: {
32948
+ position: "right",
32949
+ value: `${idealCycleTime.toFixed(1)}s`,
32950
+ fill: "#E34329",
32951
+ fontSize: 12,
32952
+ fontWeight: 500
32953
+ }
32954
+ }
32955
+ ),
32956
+ /* @__PURE__ */ jsx(
32957
+ Line,
32958
+ {
32959
+ type: "monotone",
32960
+ yAxisId: "cycle",
32961
+ dataKey: "cycleTime",
32962
+ stroke: "#3B82F6",
32963
+ strokeWidth: 2,
32964
+ connectNulls: false,
32965
+ dot: renderCycleDot,
32966
+ activeDot: renderCycleActiveDot,
32967
+ isAnimationActive: true,
32968
+ animationBegin: 300,
32969
+ animationDuration: 1500,
32970
+ animationEasing: "ease-out"
32971
+ },
32972
+ `${effectiveDatasetKey}:cycle`
32973
+ ),
32974
+ showIdleTime && /* @__PURE__ */ jsx(
32975
+ Line,
32976
+ {
32977
+ type: "monotone",
32978
+ yAxisId: "idle",
32979
+ dataKey: "idleMinutes",
32980
+ stroke: "#f59e0b",
32981
+ strokeWidth: 2,
32982
+ strokeDasharray: "4 4",
32983
+ connectNulls: false,
32984
+ dot: renderIdleDot,
32985
+ activeDot: renderIdleActiveDot,
32986
+ isAnimationActive: true,
32987
+ animationBegin: 300,
32988
+ animationDuration: 1500,
32989
+ animationEasing: "ease-out"
32990
+ },
32991
+ `${effectiveDatasetKey}:idle`
32992
+ )
32993
+ ]
32994
+ },
32995
+ hasValidData ? "valid" : "empty"
32996
+ )
32980
32997
  }
32981
- ) }) : /* @__PURE__ */ jsx("div", { className: "w-full h-full flex items-center justify-center bg-gray-50 rounded-lg", children: /* @__PURE__ */ jsx("div", { className: "text-gray-500 text-sm", children: "Loading chart..." }) }) })
32998
+ ) })
32982
32999
  ]
32983
33000
  }
32984
33001
  );
@@ -33828,10 +33845,10 @@ var HourlyOutputChart = React141__default.memo(HourlyOutputChartComponent, (prev
33828
33845
  HourlyOutputChart.displayName = "HourlyOutputChart";
33829
33846
 
33830
33847
  // src/components/dashboard/grid/videoGridMetricUtils.ts
33831
- var VIDEO_GRID_LEGEND_LABEL = "Flow";
33848
+ var VIDEO_GRID_LEGEND_LABEL = "7 Minute Efficiency";
33832
33849
  var MAP_GRID_LEGEND_LABEL = "Efficiency";
33833
- var MIXED_VIDEO_GRID_LEGEND_LABEL = "Flow / Efficiency";
33834
- var isFiniteNumber2 = (value) => typeof value === "number" && Number.isFinite(value);
33850
+ var MIXED_VIDEO_GRID_LEGEND_LABEL = "Efficiency";
33851
+ var isFiniteNumber = (value) => typeof value === "number" && Number.isFinite(value);
33835
33852
  var isVideoGridRecentFlowEnabled = (workspace) => isRecentFlowVideoGridMetricMode(
33836
33853
  workspace.video_grid_metric_mode,
33837
33854
  workspace.assembly_enabled === true
@@ -33840,11 +33857,11 @@ var isVideoGridWipGated = (workspace) => isWipGatedVideoGridMetricMode(
33840
33857
  workspace.video_grid_metric_mode,
33841
33858
  workspace.assembly_enabled === true
33842
33859
  );
33843
- var hasVideoGridRecentFlow = (workspace) => isVideoGridRecentFlowEnabled(workspace) && isFiniteNumber2(workspace.recent_flow_percent);
33860
+ var hasVideoGridRecentFlow = (workspace) => isVideoGridRecentFlowEnabled(workspace) && isFiniteNumber(workspace.recent_flow_percent);
33844
33861
  var isVideoGridRecentFlowUnavailable = (workspace) => isVideoGridRecentFlowEnabled(workspace) && !hasVideoGridRecentFlow(workspace);
33845
33862
  var getVideoGridMetricValue = (workspace) => {
33846
33863
  const recentFlowPercent = workspace.recent_flow_percent;
33847
- if (hasVideoGridRecentFlow(workspace) && isFiniteNumber2(recentFlowPercent)) {
33864
+ if (hasVideoGridRecentFlow(workspace) && isFiniteNumber(recentFlowPercent)) {
33848
33865
  return recentFlowPercent;
33849
33866
  }
33850
33867
  if (isVideoGridRecentFlowUnavailable(workspace)) {
@@ -33855,7 +33872,7 @@ var getVideoGridMetricValue = (workspace) => {
33855
33872
  var hasIncomingWipMapping = (workspace) => Boolean(workspace.incoming_wip_buffer_name);
33856
33873
  var getVideoGridBaseColorState = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => {
33857
33874
  const metricValue = getVideoGridMetricValue(workspace);
33858
- if (!isFiniteNumber2(metricValue)) {
33875
+ if (!isFiniteNumber(metricValue)) {
33859
33876
  return "neutral";
33860
33877
  }
33861
33878
  return getEfficiencyColor(metricValue, legend);
@@ -33870,7 +33887,7 @@ var isLowWipGreenOverride = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => {
33870
33887
  if (!hasIncomingWipMapping(workspace)) {
33871
33888
  return false;
33872
33889
  }
33873
- return isFiniteNumber2(workspace.incoming_wip_current) && workspace.incoming_wip_current <= 1;
33890
+ return isFiniteNumber(workspace.incoming_wip_current) && workspace.incoming_wip_current <= 1;
33874
33891
  };
33875
33892
  var toMinuteBucket = (minuteBucket) => Number.isFinite(minuteBucket) ? Math.floor(minuteBucket) : Math.floor(Date.now() / 6e4);
33876
33893
  var getEffectiveFlowMinuteBucket = (workspace) => {
@@ -33912,7 +33929,7 @@ var getVideoGridColorState = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) =>
33912
33929
  if (!hasIncomingWipMapping(workspace)) {
33913
33930
  return baseColor;
33914
33931
  }
33915
- if (!isFiniteNumber2(workspace.incoming_wip_current)) {
33932
+ if (!isFiniteNumber(workspace.incoming_wip_current)) {
33916
33933
  return "neutral";
33917
33934
  }
33918
33935
  if (isLowWipGreenOverride(workspace, legend)) {
@@ -34104,7 +34121,7 @@ var VideoCard = React141__default.memo(({
34104
34121
  }
34105
34122
  );
34106
34123
  }, (prevProps, nextProps) => {
34107
- if (prevProps.workspace.efficiency !== nextProps.workspace.efficiency || prevProps.workspace.assembly_enabled !== nextProps.workspace.assembly_enabled || prevProps.workspace.video_grid_metric_mode !== nextProps.workspace.video_grid_metric_mode || prevProps.workspace.recent_flow_mode !== nextProps.workspace.recent_flow_mode || prevProps.workspace.recent_flow_percent !== nextProps.workspace.recent_flow_percent || prevProps.workspace.recent_flow_effective_end_at !== nextProps.workspace.recent_flow_effective_end_at || prevProps.workspace.incoming_wip_current !== nextProps.workspace.incoming_wip_current || prevProps.workspace.incoming_wip_buffer_name !== nextProps.workspace.incoming_wip_buffer_name || prevProps.workspace.trend !== nextProps.workspace.trend || prevProps.workspace.performance_score !== nextProps.workspace.performance_score || prevProps.workspace.pph !== nextProps.workspace.pph) {
34124
+ if (prevProps.workspace.efficiency !== nextProps.workspace.efficiency || prevProps.workspace.assembly_enabled !== nextProps.workspace.assembly_enabled || prevProps.workspace.video_grid_metric_mode !== nextProps.workspace.video_grid_metric_mode || prevProps.workspace.recent_flow_percent !== nextProps.workspace.recent_flow_percent || prevProps.workspace.recent_flow_effective_end_at !== nextProps.workspace.recent_flow_effective_end_at || prevProps.workspace.incoming_wip_current !== nextProps.workspace.incoming_wip_current || prevProps.workspace.incoming_wip_buffer_name !== nextProps.workspace.incoming_wip_buffer_name || prevProps.workspace.trend !== nextProps.workspace.trend || prevProps.workspace.performance_score !== nextProps.workspace.performance_score || prevProps.workspace.pph !== nextProps.workspace.pph) {
34108
34125
  return false;
34109
34126
  }
34110
34127
  if (prevProps.workspace.workspace_uuid !== nextProps.workspace.workspace_uuid || prevProps.workspace.workspace_name !== nextProps.workspace.workspace_name || prevProps.workspace.line_id !== nextProps.workspace.line_id) {
@@ -44572,7 +44589,7 @@ var ShiftDisplay = memo$1(({ className, variant = "default", lineId }) => {
44572
44589
  return null;
44573
44590
  }
44574
44591
  };
44575
- const getShiftIcon = (shift) => {
44592
+ const getShiftIcon2 = (shift) => {
44576
44593
  if (shift === "Day") {
44577
44594
  return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx("path", { fillRule: "evenodd", d: "M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z", clipRule: "evenodd" }) });
44578
44595
  } else {
@@ -44598,7 +44615,7 @@ var ShiftDisplay = memo$1(({ className, variant = "default", lineId }) => {
44598
44615
  }
44599
44616
  if (variant === "enhanced") {
44600
44617
  return /* @__PURE__ */ jsxs("div", { className: `inline-flex items-center gap-2 bg-blue-50 rounded-lg px-3 py-1.5 ${className ?? ""}`, children: [
44601
- /* @__PURE__ */ jsx("div", { className: "text-blue-800", children: getShiftIcon(currentShiftText) }),
44618
+ /* @__PURE__ */ jsx("div", { className: "text-blue-800", children: getShiftIcon2(currentShiftText) }),
44602
44619
  /* @__PURE__ */ jsxs("span", { className: "text-base font-medium text-blue-800", children: [
44603
44620
  currentShiftText,
44604
44621
  " Shift"
@@ -44606,7 +44623,7 @@ var ShiftDisplay = memo$1(({ className, variant = "default", lineId }) => {
44606
44623
  ] });
44607
44624
  }
44608
44625
  return /* @__PURE__ */ jsxs("div", { className: `inline-flex items-center gap-2 bg-blue-50 rounded-lg px-3 py-1.5 ${className ?? ""}`, children: [
44609
- /* @__PURE__ */ jsx("div", { className: "text-blue-800", children: getShiftIcon(currentShiftText) }),
44626
+ /* @__PURE__ */ jsx("div", { className: "text-blue-800", children: getShiftIcon2(currentShiftText) }),
44610
44627
  /* @__PURE__ */ jsxs("span", { className: "text-base font-medium text-blue-800", children: [
44611
44628
  currentShiftText,
44612
44629
  " Shift"
@@ -47243,7 +47260,7 @@ var LinePdfGenerator = ({
47243
47260
  doc.setLineWidth(0.8);
47244
47261
  doc.line(20, 123, 190, 123);
47245
47262
  const hourlyOverviewStartY = 128;
47246
- const parseTimeToMinutes3 = (timeStr) => {
47263
+ const parseTimeToMinutes4 = (timeStr) => {
47247
47264
  const [hours, minutes] = timeStr.split(":");
47248
47265
  const hour = parseInt(hours, 10);
47249
47266
  const minute = parseInt(minutes || "0", 10);
@@ -47276,7 +47293,7 @@ var LinePdfGenerator = ({
47276
47293
  };
47277
47294
  };
47278
47295
  const getHourlyTimeRanges = (startTimeStr, endTimeStr) => {
47279
- const startMinutes = parseTimeToMinutes3(startTimeStr);
47296
+ const startMinutes = parseTimeToMinutes4(startTimeStr);
47280
47297
  if (Number.isNaN(startMinutes)) {
47281
47298
  return [];
47282
47299
  }
@@ -47284,7 +47301,7 @@ var LinePdfGenerator = ({
47284
47301
  const defaultHours = 11;
47285
47302
  return Array.from({ length: defaultHours }, (_, i) => buildRange(startMinutes + i * 60, 60));
47286
47303
  }
47287
- const endMinutes = parseTimeToMinutes3(endTimeStr);
47304
+ const endMinutes = parseTimeToMinutes4(endTimeStr);
47288
47305
  if (Number.isNaN(endMinutes)) {
47289
47306
  const fallbackHours = 11;
47290
47307
  return Array.from({ length: fallbackHours }, (_, i) => buildRange(startMinutes + i * 60, 60));
@@ -49053,7 +49070,7 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
49053
49070
  minute: "2-digit",
49054
49071
  hour12: true
49055
49072
  });
49056
- const parseTimeToMinutes3 = (timeValue) => {
49073
+ const parseTimeToMinutes4 = (timeValue) => {
49057
49074
  const [hourPart, minutePart] = timeValue.split(":").map(Number);
49058
49075
  const hour = Number.isFinite(hourPart) ? hourPart : 0;
49059
49076
  const minute = Number.isFinite(minutePart) ? minutePart : 0;
@@ -49070,8 +49087,8 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
49070
49087
  const IST_OFFSET_MINUTES = 330;
49071
49088
  return Date.UTC(year, month - 1, day, hour, minute) - IST_OFFSET_MINUTES * 60 * 1e3;
49072
49089
  };
49073
- const shiftStartMinutes = parseTimeToMinutes3(workspace.shift_start);
49074
- const shiftEndMinutes = parseTimeToMinutes3(workspace.shift_end);
49090
+ const shiftStartMinutes = parseTimeToMinutes4(workspace.shift_start);
49091
+ const shiftEndMinutes = parseTimeToMinutes4(workspace.shift_end);
49075
49092
  const wrapsMidnight = shiftEndMinutes <= shiftStartMinutes;
49076
49093
  const shiftStartUtcMs = toShiftUtcMs(workspace.date, workspace.shift_start);
49077
49094
  const shiftEndUtcMs = toShiftUtcMs(workspace.date, workspace.shift_end) + (wrapsMidnight ? 24 * 60 * 60 * 1e3 : 0);
@@ -51378,7 +51395,7 @@ var DashboardHeader = memo$1(({ lineTitle, className = "", headerControls, lineI
51378
51395
  const rawName = currentShift.shiftName || "Day";
51379
51396
  return rawName.toLowerCase().includes("shift") ? rawName : `${rawName} Shift`;
51380
51397
  };
51381
- const getShiftIcon = () => {
51398
+ const getShiftIcon2 = () => {
51382
51399
  const currentShift = getCurrentShift(timezone, shiftConfig);
51383
51400
  const shiftName = (currentShift.shiftName || "").toLowerCase();
51384
51401
  if (shiftName.includes("day") || shiftName.includes("morning") || currentShift.shiftId === 0) {
@@ -51412,7 +51429,7 @@ var DashboardHeader = memo$1(({ lineTitle, className = "", headerControls, lineI
51412
51429
  /* @__PURE__ */ jsx("span", { className: "font-medium", children: /* @__PURE__ */ jsx(Timer2, {}) }),
51413
51430
  /* @__PURE__ */ jsx("span", { className: "text-gray-300", children: "|" }),
51414
51431
  isShiftConfigLoading ? /* @__PURE__ */ jsx("div", { className: "h-3.5 w-16 bg-gray-200 rounded animate-pulse" }) : /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 font-medium", children: [
51415
- /* @__PURE__ */ jsx("span", { className: "opacity-75", children: getShiftIcon() }),
51432
+ /* @__PURE__ */ jsx("span", { className: "opacity-75", children: getShiftIcon2() }),
51416
51433
  getShiftName()
51417
51434
  ] })
51418
51435
  ] })
@@ -51429,7 +51446,7 @@ var DashboardHeader = memo$1(({ lineTitle, className = "", headerControls, lineI
51429
51446
  /* @__PURE__ */ jsxs("div", { className: "mt-2 inline-flex flex-wrap items-center gap-3", children: [
51430
51447
  /* @__PURE__ */ jsx("div", { className: "text-xs md:text-sm font-medium text-gray-600 whitespace-nowrap", children: /* @__PURE__ */ jsx(Timer2, {}) }),
51431
51448
  /* @__PURE__ */ jsx("div", { className: "inline-flex items-center gap-1", children: isShiftConfigLoading ? /* @__PURE__ */ jsx("div", { className: "h-4 w-20 bg-gray-200 rounded animate-pulse" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
51432
- /* @__PURE__ */ jsx("div", { className: "text-gray-600", children: getShiftIcon() }),
51449
+ /* @__PURE__ */ jsx("div", { className: "text-gray-600", children: getShiftIcon2() }),
51433
51450
  /* @__PURE__ */ jsx("span", { className: "text-xs md:text-sm font-medium text-gray-600 whitespace-nowrap", children: getShiftName() })
51434
51451
  ] }) })
51435
51452
  ] })
@@ -58400,7 +58417,7 @@ var FactoryView = ({
58400
58417
  const currentShift = getCurrentShiftInfo();
58401
58418
  return (currentShift.shiftName || "Day").replace(/ Shift$/i, "");
58402
58419
  };
58403
- const getShiftIcon = () => {
58420
+ const getShiftIcon2 = () => {
58404
58421
  const currentShift = getCurrentShiftInfo();
58405
58422
  const shiftNameLower = (currentShift.shiftName || "").toLowerCase();
58406
58423
  if (shiftNameLower.includes("day") || shiftNameLower.includes("morning") || currentShift.shiftId === 0) {
@@ -58446,7 +58463,7 @@ var FactoryView = ({
58446
58463
  /* @__PURE__ */ jsxs("div", { className: "mt-2 flex items-center justify-center gap-2", children: [
58447
58464
  /* @__PURE__ */ jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-gray-100 rounded-full", children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-700", children: /* @__PURE__ */ jsx(ISTTimer_default, {}) }) }),
58448
58465
  /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
58449
- /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon() }),
58466
+ /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon2() }),
58450
58467
  /* @__PURE__ */ jsxs("span", { className: "text-xs font-medium text-gray-700", children: [
58451
58468
  getShiftName(),
58452
58469
  " Shift"
@@ -58465,7 +58482,7 @@ var FactoryView = ({
58465
58482
  " IST"
58466
58483
  ] }),
58467
58484
  /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1", children: [
58468
- /* @__PURE__ */ jsx("div", { className: "text-gray-600", children: getShiftIcon() }),
58485
+ /* @__PURE__ */ jsx("div", { className: "text-gray-600", children: getShiftIcon2() }),
58469
58486
  /* @__PURE__ */ jsxs("span", { className: "text-sm font-medium text-gray-600", children: [
58470
58487
  getShiftName(),
58471
58488
  " Shift"
@@ -61177,7 +61194,7 @@ var KPIDetailView = ({
61177
61194
  const getShiftName = useCallback((shiftId) => {
61178
61195
  return getShiftNameById(shiftId, configuredTimezone, shiftConfig);
61179
61196
  }, [configuredTimezone, shiftConfig]);
61180
- const getShiftIcon = useCallback((shiftId) => {
61197
+ const getShiftIcon2 = useCallback((shiftId) => {
61181
61198
  if (shiftId === 0) {
61182
61199
  return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
61183
61200
  }
@@ -62057,7 +62074,7 @@ var KPIDetailView = ({
62057
62074
  /* @__PURE__ */ jsxs("div", { className: "sm:hidden mt-3 flex items-center justify-center gap-2", children: [
62058
62075
  /* @__PURE__ */ jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-gray-100 rounded-full", children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-700", children: chartMetrics && formatLocalDate(new Date(chartMetrics.date)) }) }),
62059
62076
  /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
62060
- /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon(chartMetrics.shift_id ?? 0) }),
62077
+ /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon2(chartMetrics.shift_id ?? 0) }),
62061
62078
  /* @__PURE__ */ jsxs("span", { className: "text-xs font-medium text-gray-700", children: [
62062
62079
  getShiftName(chartMetrics.shift_id ?? 0).replace(/ Shift$/i, ""),
62063
62080
  " Shift"
@@ -62083,7 +62100,7 @@ var KPIDetailView = ({
62083
62100
  /* @__PURE__ */ jsx("div", { className: "w-px h-4 bg-blue-200" })
62084
62101
  ] }),
62085
62102
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
62086
- /* @__PURE__ */ jsx("div", { className: "opacity-70", children: getShiftIcon(chartMetrics.shift_id ?? 0) }),
62103
+ /* @__PURE__ */ jsx("div", { className: "opacity-70", children: getShiftIcon2(chartMetrics.shift_id ?? 0) }),
62087
62104
  /* @__PURE__ */ jsxs("span", { className: "text-sm md:text-base font-semibold uppercase tracking-wider", children: [
62088
62105
  getShiftName(chartMetrics.shift_id ?? 0).replace(/ Shift$/i, ""),
62089
62106
  " Shift"
@@ -62101,7 +62118,7 @@ var KPIDetailView = ({
62101
62118
  return `${startDate.toLocaleDateString("en-US", { month: "short", day: "numeric" })} - ${endDate.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })}`;
62102
62119
  })() }) }),
62103
62120
  /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
62104
- /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon(selectedShiftId) }),
62121
+ /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon2(selectedShiftId) }),
62105
62122
  /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-700", children: getShiftName(selectedShiftId) })
62106
62123
  ] })
62107
62124
  ] }),
@@ -62118,7 +62135,7 @@ var KPIDetailView = ({
62118
62135
  ] }),
62119
62136
  /* @__PURE__ */ jsx("div", { className: "w-px h-4 bg-blue-200" }),
62120
62137
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
62121
- /* @__PURE__ */ jsx("div", { className: "opacity-70", children: getShiftIcon(selectedShiftId) }),
62138
+ /* @__PURE__ */ jsx("div", { className: "opacity-70", children: getShiftIcon2(selectedShiftId) }),
62122
62139
  /* @__PURE__ */ jsxs("span", { className: "text-sm md:text-base font-semibold uppercase tracking-wider", children: [
62123
62140
  getShiftName(selectedShiftId).replace(/ Shift$/i, ""),
62124
62141
  " Shift"
@@ -63494,7 +63511,7 @@ var KPIsOverviewView = ({
63494
63511
  const headerShiftId = showHistoricalLeaderboardHeader ? effectiveLeaderboardShiftId : currentShiftDetails.shiftId;
63495
63512
  const headerShiftName = getShiftNameById(headerShiftId, configuredTimezone, shiftConfig).replace(/ Shift$/i, "");
63496
63513
  const headerDateLabel = isMonthlyMode ? getMonthRange() : formatLocalDate2(headerDateKey);
63497
- const getShiftIcon = (shiftId) => {
63514
+ const getShiftIcon2 = (shiftId) => {
63498
63515
  const shiftNameLower = getShiftNameById(shiftId, configuredTimezone, shiftConfig).toLowerCase();
63499
63516
  if (shiftNameLower.includes("day") || shiftNameLower.includes("morning") || shiftId === 0) {
63500
63517
  return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
@@ -63611,7 +63628,7 @@ var KPIsOverviewView = ({
63611
63628
  /* @__PURE__ */ jsx("div", { className: `inline-flex items-center bg-gray-100 rounded-full ${isMonthlyMode ? "px-4 py-1.5 ring-1 ring-gray-200 shadow-sm" : "px-2.5 py-1"}`, children: /* @__PURE__ */ jsx("span", { className: `font-medium text-gray-700 ${isMonthlyMode ? "text-sm" : "text-xs"}`, children: headerDateLabel }) }),
63612
63629
  !isMonthlyMode && /* @__PURE__ */ jsxs(Fragment, { children: [
63613
63630
  /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
63614
- /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon(headerShiftId) }),
63631
+ /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon2(headerShiftId) }),
63615
63632
  /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-700", children: headerShiftName })
63616
63633
  ] }),
63617
63634
  showHistoricalLeaderboardHeader ? /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-amber-50 text-amber-700 rounded-full", children: [
@@ -63807,7 +63824,7 @@ var KPIsOverviewView = ({
63807
63824
  !isMonthlyMode && /* @__PURE__ */ jsxs(Fragment, { children: [
63808
63825
  /* @__PURE__ */ jsx("div", { className: "w-px h-4 bg-blue-200" }),
63809
63826
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
63810
- /* @__PURE__ */ jsx("div", { className: "opacity-70", children: getShiftIcon(headerShiftId) }),
63827
+ /* @__PURE__ */ jsx("div", { className: "opacity-70", children: getShiftIcon2(headerShiftId) }),
63811
63828
  /* @__PURE__ */ jsxs("span", { className: "text-sm font-semibold uppercase tracking-wider", children: [
63812
63829
  headerShiftName,
63813
63830
  " Shift"
@@ -63951,6 +63968,52 @@ var KPIsOverviewView = ({
63951
63968
  ] });
63952
63969
  };
63953
63970
  var KPIsOverviewView_default = KPIsOverviewView;
63971
+ var toFiniteNumber = (value) => {
63972
+ if (typeof value === "number" && Number.isFinite(value)) return value;
63973
+ if (typeof value === "string" && value.trim() !== "") {
63974
+ const parsed = Number(value);
63975
+ return Number.isFinite(parsed) ? parsed : null;
63976
+ }
63977
+ return null;
63978
+ };
63979
+ var getCycleRatio = (workspace) => {
63980
+ const idealCycleTime = toFiniteNumber(workspace.ideal_cycle_time);
63981
+ const avgCycleTime = toFiniteNumber(workspace.avg_cycle_time);
63982
+ if (idealCycleTime === null || avgCycleTime === null || idealCycleTime <= 0 || avgCycleTime <= 0) {
63983
+ return null;
63984
+ }
63985
+ return idealCycleTime / avgCycleTime;
63986
+ };
63987
+ var formatCycleTimeValue = (value) => {
63988
+ const numericValue = toFiniteNumber(value);
63989
+ if (numericValue === null || numericValue <= 0) return "--";
63990
+ return `${numericValue.toFixed(1)}s`;
63991
+ };
63992
+ var CycleTimeComparison = memo$1(({
63993
+ workspace,
63994
+ variant = "table"
63995
+ }) => {
63996
+ const averageValue = formatCycleTimeValue(workspace.avg_cycle_time);
63997
+ const standardValue = formatCycleTimeValue(workspace.ideal_cycle_time);
63998
+ if (variant === "mobile") {
63999
+ return /* @__PURE__ */ jsxs("div", { className: "mt-2 flex items-center justify-between py-2 border-t border-gray-100", children: [
64000
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-500 uppercase tracking-wider", children: "Standard Cycle Time" }),
64001
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium tabular-nums text-gray-500", children: standardValue })
64002
+ ] });
64003
+ }
64004
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
64005
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
64006
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium uppercase tracking-wider text-gray-500", children: "Average" }),
64007
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold tabular-nums text-gray-900", children: averageValue })
64008
+ ] }),
64009
+ /* @__PURE__ */ jsx("div", { className: "h-6 w-px bg-gray-200" }),
64010
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
64011
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium uppercase tracking-wider text-gray-500", children: "Standard" }),
64012
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium tabular-nums text-gray-500", children: standardValue })
64013
+ ] })
64014
+ ] });
64015
+ }, (prevProps, nextProps) => prevProps.variant === nextProps.variant && prevProps.workspace.avg_cycle_time === nextProps.workspace.avg_cycle_time && prevProps.workspace.ideal_cycle_time === nextProps.workspace.ideal_cycle_time);
64016
+ CycleTimeComparison.displayName = "CycleTimeComparison";
63954
64017
  var IsolatedTimer = memo$1(() => {
63955
64018
  return /* @__PURE__ */ jsx(ISTTimer_default, {});
63956
64019
  });
@@ -63968,11 +64031,11 @@ var HeaderRibbon = memo$1(({
63968
64031
  currentDate,
63969
64032
  currentMobileDate,
63970
64033
  shiftId,
63971
- getShiftIcon,
64034
+ getShiftIcon: getShiftIcon2,
63972
64035
  getShiftName,
63973
64036
  showTimer = true
63974
64037
  }) => {
63975
- const shiftIcon = useMemo(() => getShiftIcon(shiftId), [getShiftIcon, shiftId]);
64038
+ const shiftIcon = useMemo(() => getShiftIcon2(shiftId), [getShiftIcon2, shiftId]);
63976
64039
  const shiftName = useMemo(() => getShiftName(shiftId), [getShiftName, shiftId]);
63977
64040
  return /* @__PURE__ */ jsxs(Fragment, { children: [
63978
64041
  /* @__PURE__ */ jsxs("div", { className: "sm:hidden mt-3 flex items-center justify-center gap-2", children: [
@@ -64014,8 +64077,9 @@ var MobileWorkspaceCard = memo$1(({
64014
64077
  isClickable,
64015
64078
  onWorkspaceClick,
64016
64079
  getMedalIcon,
64017
- efficiencyLabel
64018
- }) => /* @__PURE__ */ jsx(
64080
+ metricLabel,
64081
+ isAssemblyMode
64082
+ }) => /* @__PURE__ */ jsxs(
64019
64083
  motion.div,
64020
64084
  {
64021
64085
  layout: true,
@@ -64026,28 +64090,31 @@ var MobileWorkspaceCard = memo$1(({
64026
64090
  },
64027
64091
  onClick: isClickable ? () => onWorkspaceClick(workspace, rank) : void 0,
64028
64092
  className: `${cardClass} p-3 rounded-lg border shadow-sm active:scale-[0.98] ${isClickable ? "cursor-pointer" : "cursor-not-allowed opacity-75"}`,
64029
- children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-2", children: [
64030
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
64031
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
64032
- /* @__PURE__ */ jsxs("div", { className: "text-2xl font-bold text-gray-700", children: [
64033
- "#",
64034
- rank
64093
+ children: [
64094
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-2 gap-3", children: [
64095
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
64096
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
64097
+ /* @__PURE__ */ jsxs("div", { className: "text-2xl font-bold text-gray-700", children: [
64098
+ "#",
64099
+ rank
64100
+ ] }),
64101
+ getMedalIcon(rank)
64035
64102
  ] }),
64036
- getMedalIcon(rank)
64103
+ /* @__PURE__ */ jsxs("div", { children: [
64104
+ /* @__PURE__ */ jsx("div", { className: "font-semibold text-gray-900", children: workspace.displayName }),
64105
+ /* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500", children: workspace.lineName })
64106
+ ] })
64037
64107
  ] }),
64038
- /* @__PURE__ */ jsxs("div", { children: [
64039
- /* @__PURE__ */ jsx("div", { className: "font-semibold text-gray-900", children: workspace.displayName }),
64040
- /* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500", children: workspace.lineName })
64108
+ /* @__PURE__ */ jsxs("div", { className: "text-right", children: [
64109
+ /* @__PURE__ */ jsx("div", { className: "font-bold text-gray-900 text-lg", children: isAssemblyMode ? /* @__PURE__ */ jsx("span", { className: "tabular-nums", children: formatCycleTimeValue(workspace.avg_cycle_time) }) : /* @__PURE__ */ jsx(AnimatedEfficiency, { value: workspace.efficiency || 0 }) }),
64110
+ /* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500", children: metricLabel })
64041
64111
  ] })
64042
64112
  ] }),
64043
- /* @__PURE__ */ jsxs("div", { className: "text-right", children: [
64044
- /* @__PURE__ */ jsx("div", { className: "text-lg font-bold text-gray-900", children: /* @__PURE__ */ jsx(AnimatedEfficiency, { value: workspace.efficiency || 0 }) }),
64045
- /* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500", children: efficiencyLabel })
64046
- ] })
64047
- ] })
64113
+ isAssemblyMode && /* @__PURE__ */ jsx(CycleTimeComparison, { workspace, variant: "mobile" })
64114
+ ]
64048
64115
  }
64049
64116
  ), (prevProps, nextProps) => {
64050
- return prevProps.efficiencyLabel === nextProps.efficiencyLabel && prevProps.rank === nextProps.rank && prevProps.cardClass === nextProps.cardClass && prevProps.isClickable === nextProps.isClickable && prevProps.workspace.workspace_uuid === nextProps.workspace.workspace_uuid && prevProps.workspace.efficiency === nextProps.workspace.efficiency && prevProps.workspace.action_count === nextProps.workspace.action_count && prevProps.workspace.action_threshold === nextProps.workspace.action_threshold && prevProps.workspace.avg_cycle_time === nextProps.workspace.avg_cycle_time && prevProps.workspace.displayName === nextProps.workspace.displayName && prevProps.workspace.lineName === nextProps.workspace.lineName;
64117
+ return prevProps.metricLabel === nextProps.metricLabel && prevProps.isAssemblyMode === nextProps.isAssemblyMode && prevProps.rank === nextProps.rank && prevProps.cardClass === nextProps.cardClass && prevProps.isClickable === nextProps.isClickable && prevProps.workspace.workspace_uuid === nextProps.workspace.workspace_uuid && prevProps.workspace.efficiency === nextProps.workspace.efficiency && prevProps.workspace.ideal_cycle_time === nextProps.workspace.ideal_cycle_time && prevProps.workspace.action_count === nextProps.workspace.action_count && prevProps.workspace.action_threshold === nextProps.workspace.action_threshold && prevProps.workspace.avg_cycle_time === nextProps.workspace.avg_cycle_time && prevProps.workspace.displayName === nextProps.workspace.displayName && prevProps.workspace.lineName === nextProps.workspace.lineName;
64051
64118
  });
64052
64119
  MobileWorkspaceCard.displayName = "MobileWorkspaceCard";
64053
64120
  var DesktopWorkspaceRow = memo$1(({
@@ -64056,7 +64123,8 @@ var DesktopWorkspaceRow = memo$1(({
64056
64123
  rowClass,
64057
64124
  isClickable,
64058
64125
  onWorkspaceClick,
64059
- getMedalIcon
64126
+ getMedalIcon,
64127
+ isAssemblyMode
64060
64128
  }) => /* @__PURE__ */ jsxs(
64061
64129
  motion.tr,
64062
64130
  {
@@ -64073,11 +64141,11 @@ var DesktopWorkspaceRow = memo$1(({
64073
64141
  ] }) }),
64074
64142
  /* @__PURE__ */ jsx("td", { className: "px-3 py-2.5 sm:p-4 text-sm sm:text-base whitespace-nowrap", children: /* @__PURE__ */ jsx("div", { className: "font-medium", children: workspace.displayName }) }),
64075
64143
  /* @__PURE__ */ jsx("td", { className: "px-3 py-2.5 sm:p-4 text-sm sm:text-base whitespace-nowrap", children: /* @__PURE__ */ jsx("div", { className: "font-medium", children: workspace.lineName }) }),
64076
- /* @__PURE__ */ jsx("td", { className: "px-3 py-2.5 sm:p-4 text-sm sm:text-base font-medium whitespace-nowrap", children: /* @__PURE__ */ jsx(AnimatedEfficiency, { value: workspace.efficiency || 0 }) })
64144
+ /* @__PURE__ */ jsx("td", { className: `px-3 py-2.5 sm:p-4 text-sm sm:text-base font-medium ${isAssemblyMode ? "" : "whitespace-nowrap"}`, children: isAssemblyMode ? /* @__PURE__ */ jsx(CycleTimeComparison, { workspace, variant: "table" }) : /* @__PURE__ */ jsx(AnimatedEfficiency, { value: workspace.efficiency || 0 }) })
64077
64145
  ]
64078
64146
  }
64079
64147
  ), (prevProps, nextProps) => {
64080
- return prevProps.index === nextProps.index && prevProps.rowClass === nextProps.rowClass && prevProps.isClickable === nextProps.isClickable && prevProps.workspace.workspace_uuid === nextProps.workspace.workspace_uuid && prevProps.workspace.efficiency === nextProps.workspace.efficiency && prevProps.workspace.displayName === nextProps.workspace.displayName && prevProps.workspace.lineName === nextProps.workspace.lineName;
64148
+ return prevProps.index === nextProps.index && prevProps.rowClass === nextProps.rowClass && prevProps.isClickable === nextProps.isClickable && prevProps.isAssemblyMode === nextProps.isAssemblyMode && prevProps.workspace.workspace_uuid === nextProps.workspace.workspace_uuid && prevProps.workspace.efficiency === nextProps.workspace.efficiency && prevProps.workspace.ideal_cycle_time === nextProps.workspace.ideal_cycle_time && prevProps.workspace.avg_cycle_time === nextProps.workspace.avg_cycle_time && prevProps.workspace.displayName === nextProps.workspace.displayName && prevProps.workspace.lineName === nextProps.workspace.lineName;
64081
64149
  });
64082
64150
  DesktopWorkspaceRow.displayName = "DesktopWorkspaceRow";
64083
64151
  var LeaderboardDetailView = memo$1(({
@@ -64099,6 +64167,7 @@ var LeaderboardDetailView = memo$1(({
64099
64167
  const supabase = useSupabase();
64100
64168
  const [sortAscending, setSortAscending] = useState(false);
64101
64169
  const [viewType, setViewType] = useState("operator");
64170
+ const [outputCategory, setOutputCategory] = useState("standard");
64102
64171
  const [activeTab, setActiveTab] = useState("today");
64103
64172
  const timezone = useAppTimezone();
64104
64173
  const staticShiftConfig = useShiftConfig();
@@ -64177,6 +64246,7 @@ var LeaderboardDetailView = memo$1(({
64177
64246
  const monthlyRequestKeyRef = useRef(null);
64178
64247
  const leaderboardUpdateQueuedRef = useRef(false);
64179
64248
  const leaderboardUpdateTimerRef = useRef(null);
64249
+ const leaderboardViewTrackedRef = useRef(null);
64180
64250
  const filterRef = useRef(null);
64181
64251
  const filterButtonRef = useRef(null);
64182
64252
  const mobileFilterButtonRef = useRef(null);
@@ -64309,6 +64379,17 @@ var LeaderboardDetailView = memo$1(({
64309
64379
  }
64310
64380
  return Array.from(uniqueLines.entries()).map(([id3, name]) => ({ id: id3, label: name }));
64311
64381
  }, [configuredLineIds, lines, getLineName]);
64382
+ const scopedLines = useMemo(() => {
64383
+ const configuredLineIdSet = new Set(configuredLineIds);
64384
+ return lines.filter((line) => configuredLineIds.length === 0 || configuredLineIdSet.has(line.id));
64385
+ }, [configuredLineIds, lines]);
64386
+ const scopedLineAssemblyMap = useMemo(() => {
64387
+ const map = /* @__PURE__ */ new Map();
64388
+ scopedLines.forEach((line) => {
64389
+ map.set(line.id, line.assembly === true);
64390
+ });
64391
+ return map;
64392
+ }, [scopedLines]);
64312
64393
  const shiftOptions = useMemo(() => {
64313
64394
  if (activeShiftConfig?.shifts && activeShiftConfig.shifts.length > 0) {
64314
64395
  return activeShiftConfig.shifts.map((shift2) => ({
@@ -64332,6 +64413,33 @@ var LeaderboardDetailView = memo$1(({
64332
64413
  const parsed = Number(selectedShiftFilter);
64333
64414
  return Number.isFinite(parsed) ? parsed : void 0;
64334
64415
  }, [selectedShiftFilter]);
64416
+ const outputScopeLines = useMemo(() => {
64417
+ const outputLines = scopedLines.filter((line) => (line.monitoring_mode ?? "output") !== "uptime");
64418
+ if (selectedLineFilter === "all") {
64419
+ return outputLines;
64420
+ }
64421
+ return outputLines.filter((line) => line.id === selectedLineFilter);
64422
+ }, [scopedLines, selectedLineFilter]);
64423
+ const hasAssemblyOutputScope = useMemo(
64424
+ () => outputScopeLines.some((line) => line.assembly === true),
64425
+ [outputScopeLines]
64426
+ );
64427
+ const hasStandardOutputScope = useMemo(
64428
+ () => outputScopeLines.some((line) => line.assembly !== true),
64429
+ [outputScopeLines]
64430
+ );
64431
+ const showOutputCategoryDropdown = viewType === "operator" && hasAssemblyOutputScope && hasStandardOutputScope;
64432
+ const isAssemblyMode = viewType === "operator" && outputCategory === "assembly";
64433
+ useEffect(() => {
64434
+ if (viewType !== "operator") return;
64435
+ if (hasAssemblyOutputScope && !hasStandardOutputScope && outputCategory !== "assembly") {
64436
+ setOutputCategory("assembly");
64437
+ return;
64438
+ }
64439
+ if (hasStandardOutputScope && !hasAssemblyOutputScope && outputCategory !== "standard") {
64440
+ setOutputCategory("standard");
64441
+ }
64442
+ }, [viewType, hasAssemblyOutputScope, hasStandardOutputScope, outputCategory]);
64335
64443
  const handleLineFilterChange = useCallback((value) => {
64336
64444
  setSelectedLineFilter(value);
64337
64445
  }, []);
@@ -64341,17 +64449,19 @@ var LeaderboardDetailView = memo$1(({
64341
64449
  const clearFilters = useCallback(() => {
64342
64450
  setSortAscending(false);
64343
64451
  setSelectedLineFilter("all");
64452
+ setOutputCategory("standard");
64344
64453
  setSelectedShiftFilter(currentShiftInfo.shiftId.toString());
64345
64454
  }, [currentShiftInfo.shiftId]);
64346
64455
  const activeFiltersCount = useMemo(() => {
64347
64456
  let count = 0;
64348
64457
  if (sortAscending) count++;
64349
64458
  if (selectedLineFilter !== "all") count++;
64459
+ if (showOutputCategoryDropdown && outputCategory !== "standard") count++;
64350
64460
  if (selectedShiftFilter !== currentShiftInfo.shiftId.toString()) {
64351
64461
  count++;
64352
64462
  }
64353
64463
  return count;
64354
- }, [sortAscending, selectedLineFilter, selectedShiftFilter, currentShiftInfo.shiftId]);
64464
+ }, [sortAscending, selectedLineFilter, outputCategory, showOutputCategoryDropdown, selectedShiftFilter, currentShiftInfo.shiftId]);
64355
64465
  const shouldFetchShiftConfigs = !date && shiftId === void 0;
64356
64466
  const {
64357
64467
  shiftConfigMap: multiLineShiftConfigMap,
@@ -64403,7 +64513,8 @@ var LeaderboardDetailView = memo$1(({
64403
64513
  action_count: entry.total_output || 0,
64404
64514
  pph: entry.avg_pph || 0,
64405
64515
  performance_score: entry.performance_score ?? 0,
64406
- avg_cycle_time: entry.avg_cycle_time || 0,
64516
+ avg_cycle_time: toFiniteNumber(entry.avg_cycle_time) ?? 0,
64517
+ ideal_cycle_time: toFiniteNumber(entry.ideal_cycle_time) ?? void 0,
64407
64518
  trend: 0,
64408
64519
  predicted_output: 0,
64409
64520
  efficiency: entry.efficiency || 0,
@@ -64581,7 +64692,7 @@ var LeaderboardDetailView = memo$1(({
64581
64692
  const currentShift = getCurrentShift(timezone || "Asia/Kolkata", activeShiftConfig);
64582
64693
  return currentShift.shiftName || getShiftNameById(currentShift.shiftId, timezone || "Asia/Kolkata", activeShiftConfig);
64583
64694
  }, [timezone, activeShiftConfig, shiftGroups]);
64584
- const getShiftIcon = useCallback((shiftId2) => {
64695
+ const getShiftIcon2 = useCallback((shiftId2) => {
64585
64696
  if (shiftId2 === void 0 && shiftGroups.length > 1) {
64586
64697
  return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
64587
64698
  }
@@ -64647,15 +64758,20 @@ var LeaderboardDetailView = memo$1(({
64647
64758
  if (!canOpenWorkspace(workspace.line_id)) {
64648
64759
  return;
64649
64760
  }
64761
+ const cycleRatio = getCycleRatio(workspace);
64650
64762
  trackCoreEvent("Workspace from Leaderboard Clicked", {
64651
64763
  workspace_name: workspace.workspace_name,
64652
64764
  workspace_id: workspace.workspace_uuid,
64653
64765
  rank,
64654
64766
  total_workspaces: workspacesLengthRef.current,
64655
64767
  // Use ref instead of state to avoid dependency
64768
+ metric_context: viewType === "machine" ? "machine" : outputCategory,
64656
64769
  efficiency: workspace.efficiency,
64657
64770
  action_count: workspace.action_count,
64658
- action_threshold: workspace.action_threshold
64771
+ action_threshold: workspace.action_threshold,
64772
+ avg_cycle_time: workspace.avg_cycle_time,
64773
+ ideal_cycle_time: workspace.ideal_cycle_time ?? null,
64774
+ cycle_ratio: cycleRatio
64659
64775
  });
64660
64776
  const displayName = workspace.displayName || getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
64661
64777
  const navParams = workspace.workspace_uuid ? getWorkspaceNavigationParams(workspace.workspace_uuid, displayName, workspace.line_id) : "";
@@ -64679,7 +64795,7 @@ var LeaderboardDetailView = memo$1(({
64679
64795
  const combinedParams = navParams ? `${navParams}&${contextParamString}` : `?${contextParamString}`;
64680
64796
  navigation.navigate(`/workspace/${workspace.workspace_uuid}${combinedParams}`);
64681
64797
  }
64682
- }, [canOpenWorkspace, onWorkspaceClick, navigation, date, shiftId]);
64798
+ }, [canOpenWorkspace, onWorkspaceClick, navigation, date, shiftId, outputCategory, viewType]);
64683
64799
  useEffect(() => {
64684
64800
  workspacesLengthRef.current = activeEntries.length || 0;
64685
64801
  }, [activeEntries.length]);
@@ -64700,16 +64816,20 @@ var LeaderboardDetailView = memo$1(({
64700
64816
  return activeEntries.map((ws) => ({
64701
64817
  ...ws,
64702
64818
  displayName: ws.displayName || getWorkspaceDisplayName(ws.workspace_name, ws.line_id),
64703
- lineName: getLineName(ws.line_id)
64819
+ lineName: getLineName(ws.line_id),
64820
+ isAssemblyLine: scopedLineAssemblyMap.get(ws.line_id) === true
64704
64821
  }));
64705
- }, [activeEntries, getLineName]);
64822
+ }, [activeEntries, getLineName, scopedLineAssemblyMap]);
64706
64823
  const sortedWorkspaces = useMemo(() => {
64707
64824
  let filtered = [...workspaceDisplayData];
64708
64825
  filtered = filtered.filter((ws) => {
64709
64826
  if (viewType === "machine") {
64710
64827
  return ws.monitoring_mode === "uptime";
64711
64828
  }
64712
- return ws.monitoring_mode !== "uptime";
64829
+ if (ws.monitoring_mode === "uptime") {
64830
+ return false;
64831
+ }
64832
+ return isAssemblyMode ? ws.isAssemblyLine : !ws.isAssemblyLine;
64713
64833
  });
64714
64834
  if (selectedLineFilter !== "all") {
64715
64835
  filtered = filtered.filter((ws) => ws.line_id === selectedLineFilter);
@@ -64718,13 +64838,61 @@ var LeaderboardDetailView = memo$1(({
64718
64838
  filtered = filtered.filter((ws) => ws.shift_id?.toString() === selectedShiftFilter);
64719
64839
  }
64720
64840
  return filtered.sort((a, b) => {
64841
+ if (isAssemblyMode) {
64842
+ const ratioA = getCycleRatio(a);
64843
+ const ratioB = getCycleRatio(b);
64844
+ if (ratioA === null && ratioB === null) return 0;
64845
+ if (ratioA === null) return 1;
64846
+ if (ratioB === null) return -1;
64847
+ return sortAscending ? ratioA - ratioB : ratioB - ratioA;
64848
+ }
64721
64849
  const effA = a.efficiency || 0;
64722
64850
  const effB = b.efficiency || 0;
64723
64851
  return sortAscending ? effA - effB : effB - effA;
64724
64852
  });
64725
- }, [workspaceDisplayData, sortAscending, selectedLineFilter, selectedShiftFilter, activeTab, viewType]);
64853
+ }, [workspaceDisplayData, sortAscending, selectedLineFilter, selectedShiftFilter, activeTab, viewType, isAssemblyMode]);
64726
64854
  const loading = activeTab === "today" ? todayLoading : monthlyLoading;
64727
64855
  const error = activeTab === "today" ? todayError : monthlyError;
64856
+ useEffect(() => {
64857
+ if (loading || error || sortedWorkspaces.length === 0) return;
64858
+ const trackingKey = [
64859
+ activeTab,
64860
+ viewType,
64861
+ outputCategory,
64862
+ selectedLineFilter,
64863
+ selectedShiftFilter,
64864
+ sortAscending ? "asc" : "desc",
64865
+ sortedWorkspaces.length
64866
+ ].join("|");
64867
+ if (leaderboardViewTrackedRef.current === trackingKey) return;
64868
+ leaderboardViewTrackedRef.current = trackingKey;
64869
+ const topWorkspace = sortedWorkspaces[0];
64870
+ trackCoreEvent("Workspace Leaderboard View Loaded", {
64871
+ time_range: activeTab,
64872
+ view_type: viewType,
64873
+ metric_context: viewType === "machine" ? "machine" : outputCategory,
64874
+ line_filter: selectedLineFilter,
64875
+ shift_filter: selectedShiftFilter,
64876
+ sort_direction: sortAscending ? "asc" : "desc",
64877
+ workspace_count: sortedWorkspaces.length,
64878
+ top_workspace_id: topWorkspace?.workspace_uuid ?? null,
64879
+ top_workspace_name: topWorkspace?.workspace_name ?? null,
64880
+ top_efficiency: topWorkspace?.efficiency ?? null,
64881
+ top_avg_cycle_time: topWorkspace?.avg_cycle_time ?? null,
64882
+ top_ideal_cycle_time: topWorkspace?.ideal_cycle_time ?? null,
64883
+ top_cycle_ratio: topWorkspace ? getCycleRatio(topWorkspace) : null
64884
+ });
64885
+ }, [
64886
+ loading,
64887
+ error,
64888
+ sortedWorkspaces,
64889
+ activeTab,
64890
+ viewType,
64891
+ outputCategory,
64892
+ selectedLineFilter,
64893
+ selectedShiftFilter,
64894
+ sortAscending
64895
+ ]);
64728
64896
  const currentDateFormatted = useMemo(() => {
64729
64897
  const dateStr = (/* @__PURE__ */ new Date()).toDateString();
64730
64898
  return formatDate2(new Date(dateStr));
@@ -64742,7 +64910,9 @@ var LeaderboardDetailView = memo$1(({
64742
64910
  error.message
64743
64911
  ] }) });
64744
64912
  }
64745
- const efficiencyLabel = viewType === "machine" ? "Utilization" : "Efficiency";
64913
+ const metricLabel = viewType === "machine" ? "Utilization" : isAssemblyMode ? "Cycle Time" : "Efficiency";
64914
+ const descendingSortLabel = "Highest to Lowest";
64915
+ const ascendingSortLabel = "Lowest to Highest";
64746
64916
  return /* @__PURE__ */ jsxs("div", { className: `min-h-screen bg-slate-50 flex flex-col ${className}`, style: { willChange: "contents" }, children: [
64747
64917
  /* @__PURE__ */ jsx("div", { className: "sticky top-0 z-20 bg-white shadow-sm border-b border-gray-200/80", children: /* @__PURE__ */ jsxs("div", { className: "px-3 sm:px-6 md:px-8 py-2 sm:py-2.5", children: [
64748
64918
  /* @__PURE__ */ jsx("div", { className: "sm:hidden", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
@@ -64792,7 +64962,7 @@ var LeaderboardDetailView = memo$1(({
64792
64962
  ] }),
64793
64963
  /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
64794
64964
  /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
64795
- /* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-gray-500 uppercase tracking-wide ml-1", children: efficiencyLabel }),
64965
+ /* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-gray-500 uppercase tracking-wide ml-1", children: metricLabel }),
64796
64966
  /* @__PURE__ */ jsx("div", { className: "relative", children: /* @__PURE__ */ jsxs(
64797
64967
  "select",
64798
64968
  {
@@ -64801,8 +64971,25 @@ var LeaderboardDetailView = memo$1(({
64801
64971
  className: "w-full appearance-none pl-3 pr-8 py-2 text-sm bg-gray-50 border border-gray-200 hover:border-gray-300 rounded-lg text-gray-900 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:bg-white transition-all cursor-pointer",
64802
64972
  style: { backgroundImage: `url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e")`, backgroundPosition: `right 0.75rem center`, backgroundRepeat: `no-repeat`, backgroundSize: `1.2em 1.2em` },
64803
64973
  children: [
64804
- /* @__PURE__ */ jsx("option", { value: "desc", children: "Highest to Lowest" }),
64805
- /* @__PURE__ */ jsx("option", { value: "asc", children: "Lowest to Highest" })
64974
+ /* @__PURE__ */ jsx("option", { value: "desc", children: descendingSortLabel }),
64975
+ /* @__PURE__ */ jsx("option", { value: "asc", children: ascendingSortLabel })
64976
+ ]
64977
+ }
64978
+ ) })
64979
+ ] }),
64980
+ showOutputCategoryDropdown && /* @__PURE__ */ jsxs("div", { className: "space-y-1 sm:hidden", children: [
64981
+ /* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-gray-500 uppercase tracking-wide ml-1", children: "Output Type" }),
64982
+ /* @__PURE__ */ jsx("div", { className: "relative", children: /* @__PURE__ */ jsxs(
64983
+ "select",
64984
+ {
64985
+ "aria-label": "Output leaderboard category",
64986
+ value: outputCategory,
64987
+ onChange: (e) => setOutputCategory(e.target.value),
64988
+ className: "w-full appearance-none pl-3 pr-8 py-2 text-sm bg-gray-50 border border-gray-200 hover:border-gray-300 rounded-lg text-gray-900 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:bg-white transition-all cursor-pointer",
64989
+ style: { backgroundImage: `url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e")`, backgroundPosition: `right 0.75rem center`, backgroundRepeat: `no-repeat`, backgroundSize: `1.2em 1.2em` },
64990
+ children: [
64991
+ /* @__PURE__ */ jsx("option", { value: "standard", children: "Standard" }),
64992
+ /* @__PURE__ */ jsx("option", { value: "assembly", children: "Assembly" })
64806
64993
  ]
64807
64994
  }
64808
64995
  ) })
@@ -64844,7 +65031,7 @@ var LeaderboardDetailView = memo$1(({
64844
65031
  currentDate: activeTab === "monthly" ? monthlyRangeText : currentDateFormatted,
64845
65032
  currentMobileDate: activeTab === "monthly" ? monthlyRangeText : currentMobileDateFormatted,
64846
65033
  shiftId: activeTab === "monthly" ? monthlyShiftId : todayShiftId,
64847
- getShiftIcon,
65034
+ getShiftIcon: getShiftIcon2,
64848
65035
  getShiftName,
64849
65036
  showTimer: activeTab === "today"
64850
65037
  }
@@ -64942,6 +65129,20 @@ var LeaderboardDetailView = memo$1(({
64942
65129
  ]
64943
65130
  }
64944
65131
  ) }),
65132
+ showOutputCategoryDropdown && /* @__PURE__ */ jsx("div", { className: "relative", children: /* @__PURE__ */ jsxs(
65133
+ "select",
65134
+ {
65135
+ "aria-label": "Output leaderboard category",
65136
+ value: outputCategory,
65137
+ onChange: (e) => setOutputCategory(e.target.value),
65138
+ className: "appearance-none pl-3 pr-8 py-1.5 text-sm font-medium bg-white border border-gray-200 hover:border-gray-300 rounded-lg text-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500 transition-all cursor-pointer shadow-sm",
65139
+ style: { backgroundImage: `url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e")`, backgroundPosition: `right 0.5rem center`, backgroundRepeat: `no-repeat`, backgroundSize: `1.2em 1.2em` },
65140
+ children: [
65141
+ /* @__PURE__ */ jsx("option", { value: "standard", children: "Standard" }),
65142
+ /* @__PURE__ */ jsx("option", { value: "assembly", children: "Assembly" })
65143
+ ]
65144
+ }
65145
+ ) }),
64945
65146
  /* @__PURE__ */ jsxs(
64946
65147
  "button",
64947
65148
  {
@@ -64973,7 +65174,8 @@ var LeaderboardDetailView = memo$1(({
64973
65174
  isClickable: canOpenWorkspace(ws.line_id),
64974
65175
  onWorkspaceClick: stableHandleWorkspaceClick,
64975
65176
  getMedalIcon: stableGetMedalIcon,
64976
- efficiencyLabel
65177
+ metricLabel,
65178
+ isAssemblyMode
64977
65179
  },
64978
65180
  ws.workspace_uuid
64979
65181
  );
@@ -64984,7 +65186,7 @@ var LeaderboardDetailView = memo$1(({
64984
65186
  /* @__PURE__ */ jsx("th", { className: "px-3 py-2.5 sm:p-4 text-left text-xs sm:text-sm font-semibold text-gray-600 whitespace-nowrap", children: "Rank" }),
64985
65187
  /* @__PURE__ */ jsx("th", { className: "px-3 py-2.5 sm:p-4 text-left text-xs sm:text-sm font-semibold text-gray-600 whitespace-nowrap", children: "Workspace" }),
64986
65188
  /* @__PURE__ */ jsx("th", { className: "px-3 py-2.5 sm:p-4 text-left text-xs sm:text-sm font-semibold text-gray-600 whitespace-nowrap", children: "Line" }),
64987
- /* @__PURE__ */ jsx("th", { className: "px-3 py-2.5 sm:p-4 text-left text-xs sm:text-sm font-semibold text-gray-600 whitespace-nowrap", children: efficiencyLabel })
65189
+ /* @__PURE__ */ jsx("th", { className: "px-3 py-2.5 sm:p-4 text-left text-xs sm:text-sm font-semibold text-gray-600 whitespace-nowrap", children: metricLabel })
64988
65190
  ] }) }),
64989
65191
  /* @__PURE__ */ jsx("tbody", { className: "divide-y divide-gray-100", children: sortedWorkspaces.map((ws, index) => {
64990
65192
  const isTopThree = index < 3;
@@ -64997,7 +65199,8 @@ var LeaderboardDetailView = memo$1(({
64997
65199
  rowClass,
64998
65200
  isClickable: canOpenWorkspace(ws.line_id),
64999
65201
  onWorkspaceClick: stableHandleWorkspaceClick,
65000
- getMedalIcon: stableGetMedalIcon
65202
+ getMedalIcon: stableGetMedalIcon,
65203
+ isAssemblyMode
65001
65204
  },
65002
65205
  ws.workspace_uuid
65003
65206
  );
@@ -65015,7 +65218,10 @@ function LoginView({
65015
65218
  logoSrc = optifye_logo_default,
65016
65219
  logoAlt = "Optifye",
65017
65220
  brandName = "Optifye",
65018
- onRateLimitCheck
65221
+ onRateLimitCheck,
65222
+ showDevTestLogin = false,
65223
+ devTestLoginLabel,
65224
+ onDevTestLogin
65019
65225
  }) {
65020
65226
  return /* @__PURE__ */ jsx(
65021
65227
  LoginPage,
@@ -65023,7 +65229,10 @@ function LoginView({
65023
65229
  logoSrc,
65024
65230
  logoAlt,
65025
65231
  brandName,
65026
- onRateLimitCheck
65232
+ onRateLimitCheck,
65233
+ showDevTestLogin,
65234
+ devTestLoginLabel,
65235
+ onDevTestLogin
65027
65236
  }
65028
65237
  );
65029
65238
  }
@@ -68211,20 +68420,30 @@ function useTimezone(options = {}) {
68211
68420
  }
68212
68421
 
68213
68422
  // src/views/workspace-detail-view.utils.ts
68214
- var getWorkspaceCycleTimePresentation = ({
68423
+ var getWorkspaceDetailLayoutMode = ({
68215
68424
  workspace,
68216
68425
  showCycleTimeChart
68217
68426
  }) => {
68218
68427
  if (workspace?.monitoring_mode === "uptime") {
68219
- return "output";
68428
+ return "uptime";
68220
68429
  }
68221
68430
  if (showCycleTimeChart === false) {
68222
68431
  return "output";
68223
68432
  }
68224
- if (!shouldUseAssemblyCycleTimeLayout(workspace)) {
68433
+ return shouldUseAssemblyCycleTimeLayout(workspace) ? "assembly_cycle" : "output";
68434
+ };
68435
+ var getCycleTimeRenderState = ({
68436
+ workspace,
68437
+ authoritativeMetrics,
68438
+ showCycleTimeChart
68439
+ }) => {
68440
+ if (getWorkspaceDetailLayoutMode({ workspace, showCycleTimeChart }) !== "assembly_cycle") {
68225
68441
  return "output";
68226
68442
  }
68227
- return workspace?.cycle_time_data_status === "missing_clips" ? "cycle_unavailable" : "cycle_chart";
68443
+ if (!authoritativeMetrics) {
68444
+ return "chart_loading";
68445
+ }
68446
+ return authoritativeMetrics.cycle_time_data_status === "missing_clips" ? "cycle_unavailable" : "cycle_chart";
68228
68447
  };
68229
68448
  var formatDateInTimezone = (date = /* @__PURE__ */ new Date(), timezone, options) => {
68230
68449
  const defaultOptions = {
@@ -68632,33 +68851,34 @@ var WorkspaceDetailView = ({
68632
68851
  idle_time_hourly: void 0
68633
68852
  };
68634
68853
  }, [cachedOverviewMetrics, shiftConfig?.shifts]);
68635
- const workspace = (isHistoricView ? historicMetrics : liveMetrics) || cachedDetailedMetrics || overviewFallback;
68854
+ const authoritativeCycleMetrics = isHistoricView ? historicMetrics : liveMetrics;
68855
+ const workspace = authoritativeCycleMetrics || cachedDetailedMetrics || overviewFallback;
68636
68856
  const { timezone: cycleTimeTimezone } = useTimezone({
68637
68857
  lineId: effectiveLineId || workspace?.line_id || void 0,
68638
68858
  workspaceId: workspaceId || void 0
68639
68859
  });
68640
68860
  const effectiveCycleTimeTimezone = cycleTimeTimezone || timezone;
68641
- const detailedWorkspaceMetrics = (isHistoricView ? historicMetrics : liveMetrics) || cachedDetailedMetrics;
68861
+ const detailedWorkspaceMetrics = authoritativeCycleMetrics || cachedDetailedMetrics;
68642
68862
  const cycleTimeChartData = useMemo(
68643
- () => Array.isArray(workspace?.hourly_cycle_times) ? workspace.hourly_cycle_times.map((value) => {
68863
+ () => Array.isArray(authoritativeCycleMetrics?.hourly_cycle_times) ? authoritativeCycleMetrics.hourly_cycle_times.map((value) => {
68644
68864
  const numericValue = Number(value);
68645
68865
  return Number.isFinite(numericValue) ? numericValue : 0;
68646
68866
  }) : [],
68647
- [workspace?.hourly_cycle_times]
68867
+ [authoritativeCycleMetrics?.hourly_cycle_times]
68648
68868
  );
68649
68869
  const maskedCycleTimeChartData = useMemo(
68650
68870
  () => maskFutureHourlySeries({
68651
68871
  data: cycleTimeChartData,
68652
- shiftStart: workspace?.shift_start,
68653
- shiftEnd: workspace?.shift_end,
68654
- shiftDate: workspace?.date || date || calculatedOperationalDate || null,
68872
+ shiftStart: authoritativeCycleMetrics?.shift_start,
68873
+ shiftEnd: authoritativeCycleMetrics?.shift_end,
68874
+ shiftDate: authoritativeCycleMetrics?.date || date || calculatedOperationalDate || null,
68655
68875
  timezone: effectiveCycleTimeTimezone
68656
68876
  }),
68657
68877
  [
68658
68878
  cycleTimeChartData,
68659
- workspace?.shift_start,
68660
- workspace?.shift_end,
68661
- workspace?.date,
68879
+ authoritativeCycleMetrics?.shift_start,
68880
+ authoritativeCycleMetrics?.shift_end,
68881
+ authoritativeCycleMetrics?.date,
68662
68882
  date,
68663
68883
  calculatedOperationalDate,
68664
68884
  effectiveCycleTimeTimezone
@@ -68666,13 +68886,13 @@ var WorkspaceDetailView = ({
68666
68886
  );
68667
68887
  const cycleTimeDatasetKey = useMemo(
68668
68888
  () => [
68669
- workspace?.workspace_id || workspaceId || "workspace",
68670
- date || workspace?.date || "live",
68671
- parsedShiftId ?? workspace?.shift_id ?? "current",
68889
+ authoritativeCycleMetrics?.workspace_id || workspaceId || "workspace",
68890
+ date || authoritativeCycleMetrics?.date || "live",
68891
+ parsedShiftId ?? authoritativeCycleMetrics?.shift_id ?? "current",
68672
68892
  "hourly",
68673
68893
  "backend"
68674
68894
  ].join(":"),
68675
- [workspace?.workspace_id, workspaceId, date, workspace?.date, parsedShiftId, workspace?.shift_id]
68895
+ [authoritativeCycleMetrics?.workspace_id, workspaceId, date, authoritativeCycleMetrics?.date, parsedShiftId, authoritativeCycleMetrics?.shift_id]
68676
68896
  );
68677
68897
  const hasWorkspaceSnapshot = Boolean(workspace);
68678
68898
  const loading = ((isHistoricView ? historicLoading : liveLoading) || isShiftConfigLoading) && !hasWorkspaceSnapshot;
@@ -68921,30 +69141,46 @@ var WorkspaceDetailView = ({
68921
69141
  action_type: workspace.action_type
68922
69142
  } : null;
68923
69143
  const isAssemblyWorkspace = shouldUseAssemblyCycleTimeLayout(workspaceCycleTimeEligibility);
68924
- const cycleTimePresentation = getWorkspaceCycleTimePresentation({
69144
+ const layoutMode = getWorkspaceDetailLayoutMode({
69145
+ workspace: workspace ? {
69146
+ monitoring_mode: workspace.monitoring_mode,
69147
+ line_assembly_enabled: workspace.line_assembly_enabled,
69148
+ action_family: workspace.action_family,
69149
+ action_type: workspace.action_type
69150
+ } : null,
69151
+ showCycleTimeChart
69152
+ });
69153
+ const isAssemblyCycleLayout = layoutMode === "assembly_cycle";
69154
+ const isOutputLayout = layoutMode === "output";
69155
+ const cycleTimePresentation = getCycleTimeRenderState({
68925
69156
  workspace: workspace ? {
68926
69157
  monitoring_mode: workspace.monitoring_mode,
68927
69158
  line_assembly_enabled: workspace.line_assembly_enabled,
68928
69159
  action_family: workspace.action_family,
68929
- action_type: workspace.action_type,
68930
- cycle_time_data_status: workspace.cycle_time_data_status
69160
+ action_type: workspace.action_type
69161
+ } : null,
69162
+ authoritativeMetrics: authoritativeCycleMetrics ? {
69163
+ cycle_time_data_status: authoritativeCycleMetrics.cycle_time_data_status
68931
69164
  } : null,
68932
69165
  showCycleTimeChart
68933
69166
  });
68934
- const shouldShowCycleTimeChart = cycleTimePresentation !== "output";
69167
+ const shouldShowCycleTimeChart = cycleTimePresentation === "cycle_chart";
68935
69168
  const shouldShowCycleTimeUnavailableState = cycleTimePresentation === "cycle_unavailable";
68936
- const showIdleBreakdownChart = !shouldShowCycleTimeChart && idleTimeVlmEnabled;
69169
+ const shouldShowCycleTimeLoadingState = cycleTimePresentation === "chart_loading";
69170
+ const shouldShowAssemblyOverviewLoadingState = isAssemblyCycleLayout && shouldShowCycleTimeLoadingState && hasWorkspaceSnapshot;
69171
+ const showIdleBreakdownChart = !isAssemblyCycleLayout && idleTimeVlmEnabled;
69172
+ const canToggleChartIdleTime = !isUptimeMode && !shouldShowCycleTimeLoadingState && !shouldShowCycleTimeUnavailableState;
68937
69173
  const idleClipDate = date || workspace?.date || calculatedOperationalDate || getOperationalDate(timezone);
68938
69174
  const idleClipShiftId = parsedShiftId ?? workspace?.shift_id;
68939
69175
  const rawHourlyIdleMinutes = useMemo(() => {
68940
69176
  if (!shouldShowCycleTimeChart || !workspace?.idle_time_hourly || !workspace?.shift_start) return [];
68941
- const parseTimeToMinutes3 = (time2) => {
69177
+ const parseTimeToMinutes4 = (time2) => {
68942
69178
  const [h, m] = time2.split(":").map(Number);
68943
69179
  if (!Number.isFinite(h) || !Number.isFinite(m)) return 0;
68944
69180
  return h * 60 + m;
68945
69181
  };
68946
- const startTotal = parseTimeToMinutes3(workspace.shift_start);
68947
- const endTotalRaw = workspace.shift_end ? parseTimeToMinutes3(workspace.shift_end) : startTotal + 11 * 60;
69182
+ const startTotal = parseTimeToMinutes4(workspace.shift_start);
69183
+ const endTotalRaw = workspace.shift_end ? parseTimeToMinutes4(workspace.shift_end) : startTotal + 11 * 60;
68948
69184
  const endTotal = endTotalRaw <= startTotal ? endTotalRaw + 24 * 60 : endTotalRaw;
68949
69185
  const shiftDuration = Math.max(60, endTotal - startTotal);
68950
69186
  const totalHourSlots = Math.max(1, Math.ceil(shiftDuration / 60));
@@ -68994,6 +69230,18 @@ var WorkspaceDetailView = ({
68994
69230
  workspace.cycle_completion_clip_count
68995
69231
  ] })
68996
69232
  ] }), [workspace?.cycle_completion_clip_count]);
69233
+ const assemblyOverviewLoadingView = useMemo(() => /* @__PURE__ */ jsxs("div", { className: "space-y-4 pb-4", "data-testid": "assembly-overview-loading-state", children: [
69234
+ /* @__PURE__ */ jsx("div", { className: "bg-white rounded-lg shadow-sm p-6 lg:p-8", children: /* @__PURE__ */ jsx("div", { className: "min-h-[280px] lg:min-h-[340px] flex flex-col justify-center", children: /* @__PURE__ */ jsxs("div", { className: "w-full max-w-xl mx-auto animate-pulse space-y-3", children: [
69235
+ /* @__PURE__ */ jsx("div", { className: "h-3 bg-gray-200 rounded-full w-3/4 mx-auto" }),
69236
+ /* @__PURE__ */ jsx("div", { className: "h-3 bg-gray-100 rounded-full w-full" }),
69237
+ /* @__PURE__ */ jsx("div", { className: "h-3 bg-gray-100 rounded-full w-5/6 mx-auto" })
69238
+ ] }) }) }),
69239
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4", children: [0, 1, 2].map((index) => /* @__PURE__ */ jsx("div", { className: "bg-white rounded-lg shadow-sm p-5", children: /* @__PURE__ */ jsxs("div", { className: "animate-pulse space-y-3", children: [
69240
+ /* @__PURE__ */ jsx("div", { className: "h-4 w-24 bg-gray-200 rounded" }),
69241
+ /* @__PURE__ */ jsx("div", { className: "h-10 w-20 bg-gray-100 rounded" }),
69242
+ /* @__PURE__ */ jsx("div", { className: "h-3 w-28 bg-gray-100 rounded" })
69243
+ ] }) }, index)) })
69244
+ ] }), []);
68997
69245
  const shiftDurationMinutes = useMemo(
68998
69246
  () => getShiftDurationMinutes(workspace?.shift_start, workspace?.shift_end),
68999
69247
  [workspace?.shift_start, workspace?.shift_end]
@@ -69048,7 +69296,7 @@ var WorkspaceDetailView = ({
69048
69296
  }, [isUptimeMode, uptimeSeries, shiftDurationMinutes, elapsedShiftMinutes, workspace?.idle_time]);
69049
69297
  const overviewTabLabel = isUptimeMode ? "Utilization" : "Efficiency";
69050
69298
  const idleClipFetchEnabled = Boolean(
69051
- workspaceId && idleClipDate && idleClipShiftId !== void 0 && activeTab === "overview" && idleTimeVlmEnabled && !shouldShowCycleTimeChart && !isUptimeMode
69299
+ workspaceId && idleClipDate && idleClipShiftId !== void 0 && activeTab === "overview" && idleTimeVlmEnabled && isOutputLayout
69052
69300
  );
69053
69301
  const {
69054
69302
  idleClips: idleTimeClips,
@@ -69119,7 +69367,7 @@ var WorkspaceDetailView = ({
69119
69367
  }
69120
69368
  }
69121
69369
  };
69122
- const getShiftIcon = (shiftType) => {
69370
+ const getShiftIcon2 = (shiftType) => {
69123
69371
  const shiftTypeLower = shiftType?.toLowerCase() || "";
69124
69372
  if (shiftTypeLower.includes("day") || shiftTypeLower.includes("morning")) {
69125
69373
  return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
@@ -69268,7 +69516,7 @@ var WorkspaceDetailView = ({
69268
69516
  /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: (() => {
69269
69517
  const shift2 = shiftConfig?.shifts?.find((s) => s.shiftId === selectedShift);
69270
69518
  const shiftName = shift2?.shiftName || (selectedShift === 0 ? "Day Shift" : "Night Shift");
69271
- return getShiftIcon(shiftName);
69519
+ return getShiftIcon2(shiftName);
69272
69520
  })() }),
69273
69521
  /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-700", children: (() => {
69274
69522
  const shift2 = shiftConfig?.shifts?.find((s) => s.shiftId === selectedShift);
@@ -69296,7 +69544,7 @@ var WorkspaceDetailView = ({
69296
69544
  /* @__PURE__ */ jsx("div", { className: "opacity-70", children: (() => {
69297
69545
  const shift2 = shiftConfig?.shifts?.find((s) => s.shiftId === selectedShift);
69298
69546
  const shiftName = shift2?.shiftName || (selectedShift === 0 ? "Day Shift" : "Night Shift");
69299
- return getShiftIcon(shiftName);
69547
+ return getShiftIcon2(shiftName);
69300
69548
  })() }),
69301
69549
  /* @__PURE__ */ jsx("span", { className: "text-sm md:text-base font-semibold uppercase tracking-wider", children: (() => {
69302
69550
  const shift2 = shiftConfig?.shifts?.find((s) => s.shiftId === selectedShift);
@@ -69309,7 +69557,7 @@ var WorkspaceDetailView = ({
69309
69557
  /* @__PURE__ */ jsxs("div", { className: "sm:hidden mt-3 flex items-center justify-center gap-2", children: [
69310
69558
  /* @__PURE__ */ jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-gray-100 rounded-full", children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-700", children: formatISTDate2(new Date(workspace.date)) }) }),
69311
69559
  /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
69312
- /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon(workspace.shift_type) }),
69560
+ /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon2(workspace.shift_type) }),
69313
69561
  /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-700", children: workspace.shift_type })
69314
69562
  ] }),
69315
69563
  !date && !shift && !usingFallbackData ? /* @__PURE__ */ jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-green-100 rounded-full", children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-green-700", children: /* @__PURE__ */ jsx(LiveTimer, {}) }) }) : date ? /* @__PURE__ */ jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-blue-100 rounded-full", children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-blue-700", children: getDaysDifference(workspace.date, timezone, dashboardConfig?.shiftConfig?.dayShift?.startTime || "06:00") }) }) : usingFallbackData ? /* @__PURE__ */ jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-amber-100 rounded-full", children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-amber-700", children: getDaysDifference(workspace.date, timezone, dashboardConfig?.shiftConfig?.dayShift?.startTime || "06:00") }) }) : null
@@ -69340,7 +69588,7 @@ var WorkspaceDetailView = ({
69340
69588
  /* @__PURE__ */ jsx("div", { className: "w-px h-4 bg-blue-200" })
69341
69589
  ] }),
69342
69590
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
69343
- /* @__PURE__ */ jsx("div", { className: "opacity-70", children: getShiftIcon(workspace.shift_type) }),
69591
+ /* @__PURE__ */ jsx("div", { className: "opacity-70", children: getShiftIcon2(workspace.shift_type) }),
69344
69592
  /* @__PURE__ */ jsxs("span", { className: "text-sm md:text-base font-semibold uppercase tracking-wider", children: [
69345
69593
  workspace.shift_type.replace(/ Shift$/i, ""),
69346
69594
  " Shift"
@@ -69459,9 +69707,9 @@ var WorkspaceDetailView = ({
69459
69707
  ] })
69460
69708
  ] }),
69461
69709
  /* @__PURE__ */ jsxs("div", { className: "flex-grow p-1.5 sm:p-2 lg:p-4", children: [
69462
- activeTab === "overview" && /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full lg:h-[calc(100vh-12rem)] overflow-y-auto lg:min-h-0 pb-4", children: [
69710
+ activeTab === "overview" && /* @__PURE__ */ jsx("div", { className: "flex flex-col h-full lg:h-[calc(100vh-12rem)] overflow-y-auto lg:min-h-0 pb-4", children: shouldShowAssemblyOverviewLoadingState ? assemblyOverviewLoadingView : /* @__PURE__ */ jsxs(Fragment, { children: [
69463
69711
  /* @__PURE__ */ jsxs("div", { className: "block lg:hidden space-y-6 pb-6", children: [
69464
- !shouldShowCycleTimeChart && !isUptimeMode && /* @__PURE__ */ jsxs(
69712
+ isOutputLayout && !isUptimeMode && /* @__PURE__ */ jsxs(
69465
69713
  motion.div,
69466
69714
  {
69467
69715
  className: "bg-white rounded-lg shadow-sm p-6 h-[300px]",
@@ -69489,8 +69737,8 @@ var WorkspaceDetailView = ({
69489
69737
  animate: "animate",
69490
69738
  children: [
69491
69739
  /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center mb-4", children: [
69492
- /* @__PURE__ */ jsx("h3", { className: "text-lg font-bold text-gray-700", children: isUptimeMode ? "Machine Utilization" : shouldShowCycleTimeChart ? "Cycle time trend" : "Hourly Output" }),
69493
- !isUptimeMode && !shouldShowCycleTimeUnavailableState && /* @__PURE__ */ jsx(
69740
+ /* @__PURE__ */ jsx("h3", { className: "text-lg font-bold text-gray-700", children: isUptimeMode ? "Machine Utilization" : isAssemblyCycleLayout ? "Cycle time trend" : "Hourly Output" }),
69741
+ canToggleChartIdleTime && /* @__PURE__ */ jsx(
69494
69742
  "button",
69495
69743
  {
69496
69744
  onClick: () => setShowChartIdleTime(!showChartIdleTime),
@@ -69519,19 +69767,19 @@ var WorkspaceDetailView = ({
69519
69767
  timezone,
69520
69768
  elapsedMinutes: elapsedShiftMinutes
69521
69769
  }
69522
- ) : shouldShowCycleTimeUnavailableState ? cycleTimeUnavailableView : shouldShowCycleTimeChart ? /* @__PURE__ */ jsx(
69770
+ ) : isAssemblyCycleLayout ? shouldShowCycleTimeUnavailableState ? cycleTimeUnavailableView : shouldShowCycleTimeChart ? /* @__PURE__ */ jsx(
69523
69771
  CycleTimeOverTimeChart,
69524
69772
  {
69525
69773
  data: maskedCycleTimeChartData,
69526
- idealCycleTime: workspace.ideal_cycle_time || 0,
69527
- shiftStart: workspace.shift_start || "",
69528
- shiftEnd: workspace.shift_end || "",
69774
+ idealCycleTime: authoritativeCycleMetrics?.ideal_cycle_time || 0,
69775
+ shiftStart: authoritativeCycleMetrics?.shift_start || "",
69776
+ shiftEnd: authoritativeCycleMetrics?.shift_end || "",
69529
69777
  xAxisMode: "hourly",
69530
69778
  datasetKey: cycleTimeDatasetKey,
69531
69779
  showIdleTime: showChartIdleTime,
69532
69780
  idleTimeData: hourlyIdleMinutes
69533
69781
  }
69534
- ) : /* @__PURE__ */ jsx(
69782
+ ) : null : /* @__PURE__ */ jsx(
69535
69783
  HourlyOutputChart2,
69536
69784
  {
69537
69785
  data: workspace.hourly_action_counts || [],
@@ -69551,7 +69799,7 @@ var WorkspaceDetailView = ({
69551
69799
  ]
69552
69800
  }
69553
69801
  ),
69554
- !shouldShowCycleTimeChart && idleTimeVlmEnabled && /* @__PURE__ */ jsxs(
69802
+ showIdleBreakdownChart && /* @__PURE__ */ jsxs(
69555
69803
  motion.div,
69556
69804
  {
69557
69805
  className: "bg-white rounded-lg shadow-sm p-4 h-[300px]",
@@ -69571,7 +69819,7 @@ var WorkspaceDetailView = ({
69571
69819
  ]
69572
69820
  }
69573
69821
  ),
69574
- isUptimeMode ? /* @__PURE__ */ jsx(UptimeMetricCards, { workspace, uptimePieData }) : shouldShowCycleTimeChart ? /* @__PURE__ */ jsx(
69822
+ isUptimeMode ? /* @__PURE__ */ jsx(UptimeMetricCards, { workspace, uptimePieData }) : isAssemblyCycleLayout ? /* @__PURE__ */ jsx(
69575
69823
  WorkspaceCycleTimeMetricCards,
69576
69824
  {
69577
69825
  workspace,
@@ -69591,7 +69839,7 @@ var WorkspaceDetailView = ({
69591
69839
  desktopTopSectionClass
69592
69840
  ),
69593
69841
  children: [
69594
- !shouldShowCycleTimeChart && !isUptimeMode && /* @__PURE__ */ jsxs(
69842
+ isOutputLayout && !isUptimeMode && /* @__PURE__ */ jsxs(
69595
69843
  motion.div,
69596
69844
  {
69597
69845
  className: "bg-white rounded-lg shadow-sm p-4 lg:col-span-2 flex flex-col min-h-0",
@@ -69615,15 +69863,15 @@ var WorkspaceDetailView = ({
69615
69863
  {
69616
69864
  className: clsx(
69617
69865
  "bg-white rounded-lg shadow-sm p-4 flex flex-col min-h-0",
69618
- isUptimeMode && showIdleBreakdownChart ? "lg:col-span-2" : shouldShowCycleTimeChart || isUptimeMode ? "lg:col-span-10" : idleTimeVlmEnabled ? "lg:col-span-6" : "lg:col-span-8"
69866
+ isUptimeMode && showIdleBreakdownChart ? "lg:col-span-2" : isAssemblyCycleLayout || isUptimeMode ? "lg:col-span-10" : idleTimeVlmEnabled ? "lg:col-span-6" : "lg:col-span-8"
69619
69867
  ),
69620
69868
  variants: chartCardVariants,
69621
69869
  initial: "initial",
69622
69870
  animate: "animate",
69623
69871
  children: [
69624
69872
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3 mb-4 flex-none", children: [
69625
- /* @__PURE__ */ jsx("h3", { className: "text-lg font-bold text-gray-700", children: isUptimeMode ? "Machine Utilization" : shouldShowCycleTimeChart ? "Cycle time trend" : "Hourly Output" }),
69626
- !isUptimeMode && !shouldShowCycleTimeUnavailableState && /* @__PURE__ */ jsx(
69873
+ /* @__PURE__ */ jsx("h3", { className: "text-lg font-bold text-gray-700", children: isUptimeMode ? "Machine Utilization" : isAssemblyCycleLayout ? "Cycle time trend" : "Hourly Output" }),
69874
+ canToggleChartIdleTime && /* @__PURE__ */ jsx(
69627
69875
  "button",
69628
69876
  {
69629
69877
  onClick: () => setShowChartIdleTime(!showChartIdleTime),
@@ -69648,19 +69896,19 @@ var WorkspaceDetailView = ({
69648
69896
  timezone,
69649
69897
  elapsedMinutes: elapsedShiftMinutes
69650
69898
  }
69651
- ) : shouldShowCycleTimeUnavailableState ? cycleTimeUnavailableView : shouldShowCycleTimeChart ? /* @__PURE__ */ jsx(
69899
+ ) : isAssemblyCycleLayout ? shouldShowCycleTimeUnavailableState ? cycleTimeUnavailableView : shouldShowCycleTimeChart ? /* @__PURE__ */ jsx(
69652
69900
  CycleTimeOverTimeChart,
69653
69901
  {
69654
69902
  data: maskedCycleTimeChartData,
69655
- idealCycleTime: workspace.ideal_cycle_time || 0,
69656
- shiftStart: workspace.shift_start || "",
69657
- shiftEnd: workspace.shift_end || "",
69903
+ idealCycleTime: authoritativeCycleMetrics?.ideal_cycle_time || 0,
69904
+ shiftStart: authoritativeCycleMetrics?.shift_start || "",
69905
+ shiftEnd: authoritativeCycleMetrics?.shift_end || "",
69658
69906
  xAxisMode: "hourly",
69659
69907
  datasetKey: cycleTimeDatasetKey,
69660
69908
  showIdleTime: showChartIdleTime,
69661
69909
  idleTimeData: hourlyIdleMinutes
69662
69910
  }
69663
- ) : /* @__PURE__ */ jsx(
69911
+ ) : null : /* @__PURE__ */ jsx(
69664
69912
  HourlyOutputChart2,
69665
69913
  {
69666
69914
  data: workspace.hourly_action_counts || [],
@@ -69678,7 +69926,7 @@ var WorkspaceDetailView = ({
69678
69926
  ]
69679
69927
  }
69680
69928
  ),
69681
- !shouldShowCycleTimeChart && idleTimeVlmEnabled && /* @__PURE__ */ jsxs(
69929
+ showIdleBreakdownChart && /* @__PURE__ */ jsxs(
69682
69930
  motion.div,
69683
69931
  {
69684
69932
  className: clsx(
@@ -69704,7 +69952,7 @@ var WorkspaceDetailView = ({
69704
69952
  ]
69705
69953
  }
69706
69954
  ),
69707
- isUptimeMode ? /* @__PURE__ */ jsx("div", { className: clsx("flex min-h-0", desktopBottomSectionClass), children: /* @__PURE__ */ jsx(UptimeMetricCards, { workspace, uptimePieData, className: "flex-1" }) }) : shouldShowCycleTimeChart ? /* @__PURE__ */ jsx(
69955
+ isUptimeMode ? /* @__PURE__ */ jsx("div", { className: clsx("flex min-h-0", desktopBottomSectionClass), children: /* @__PURE__ */ jsx(UptimeMetricCards, { workspace, uptimePieData, className: "flex-1" }) }) : isAssemblyCycleLayout ? /* @__PURE__ */ jsx(
69708
69956
  WorkspaceCycleTimeMetricCards,
69709
69957
  {
69710
69958
  workspace,
@@ -69715,7 +69963,7 @@ var WorkspaceDetailView = ({
69715
69963
  }
69716
69964
  ) : /* @__PURE__ */ jsx("div", { className: clsx("flex min-h-0", desktopBottomSectionClass), children: /* @__PURE__ */ jsx(WorkspaceMetricCards, { workspace, legend: efficiencyLegend, className: "flex-1" }) })
69717
69965
  ] })
69718
- ] }),
69966
+ ] }) }),
69719
69967
  activeTab === "monthly_history" && /* @__PURE__ */ jsxs("div", { className: "h-[calc(100vh-10rem)] overflow-y-auto px-2 sm:px-4 lg:px-0", children: [
69720
69968
  usingFallbackData && !date && !shift && /* @__PURE__ */ jsx("div", { className: "mb-3 sm:mb-4 bg-amber-50 border border-amber-200 rounded-lg px-3 sm:px-4 py-2 sm:py-3 text-amber-800", children: /* @__PURE__ */ jsxs("p", { className: "text-xs sm:text-sm font-medium flex items-center", children: [
69721
69969
  /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-4 w-4 sm:h-5 sm:w-5 mr-2", viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { fillRule: "evenodd", d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z", clipRule: "evenodd" }) }),
@@ -72347,7 +72595,7 @@ var normalizeLabel = (value) => {
72347
72595
  const trimmed = value.trim();
72348
72596
  return trimmed.length > 0 ? trimmed : void 0;
72349
72597
  };
72350
- var toFiniteNumber = (value) => {
72598
+ var toFiniteNumber2 = (value) => {
72351
72599
  if (typeof value === "number" && Number.isFinite(value)) return value;
72352
72600
  if (typeof value === "string" && value.trim().length > 0) {
72353
72601
  const parsed = Number(value);
@@ -72381,7 +72629,7 @@ var formatImprovementPieceGain = (pcsGain) => {
72381
72629
  var getPositiveImprovementGain = ({
72382
72630
  estimated_gain_pieces
72383
72631
  }) => {
72384
- const issueGain = toFiniteNumber(estimated_gain_pieces);
72632
+ const issueGain = toFiniteNumber2(estimated_gain_pieces);
72385
72633
  return {
72386
72634
  pcsGain: issueGain !== null && issueGain > 0 ? issueGain : null
72387
72635
  };
@@ -72389,7 +72637,7 @@ var getPositiveImprovementGain = ({
72389
72637
  var getImprovementPcsGainSortValue = (input) => {
72390
72638
  const { pcsGain } = getPositiveImprovementGain(input);
72391
72639
  if (pcsGain !== null) return pcsGain;
72392
- const raw = toFiniteNumber(input.estimated_gain_pieces);
72640
+ const raw = toFiniteNumber2(input.estimated_gain_pieces);
72393
72641
  return raw ?? null;
72394
72642
  };
72395
72643
  var getImprovementDisplayMetadata = ({
@@ -72409,7 +72657,7 @@ var getImprovementDisplayMetadata = ({
72409
72657
  metadataLabel: [workstationLabel, lineLabel, supervisorLabel].join(" \xB7 ")
72410
72658
  };
72411
72659
  };
72412
- var toFiniteNumber2 = (value) => {
72660
+ var toFiniteNumber3 = (value) => {
72413
72661
  if (typeof value === "number" && Number.isFinite(value)) return value;
72414
72662
  if (typeof value === "string" && value.trim().length > 0) {
72415
72663
  const parsed = Number(value);
@@ -72437,15 +72685,15 @@ var compareImprovementRecommendationPriority = (left, right) => {
72437
72685
  if (leftIndustrial !== rightIndustrial) {
72438
72686
  return rightIndustrial - leftIndustrial;
72439
72687
  }
72440
- const leftGain = toFiniteNumber2(left.estimated_gain_pieces);
72441
- const rightGain = toFiniteNumber2(right.estimated_gain_pieces);
72688
+ const leftGain = toFiniteNumber3(left.estimated_gain_pieces);
72689
+ const rightGain = toFiniteNumber3(right.estimated_gain_pieces);
72442
72690
  if (leftGain !== rightGain) {
72443
72691
  if (leftGain === null) return 1;
72444
72692
  if (rightGain === null) return -1;
72445
72693
  return rightGain - leftGain;
72446
72694
  }
72447
- const leftRatio = toFiniteNumber2(left.gain_to_target_ratio);
72448
- const rightRatio = toFiniteNumber2(right.gain_to_target_ratio);
72695
+ const leftRatio = toFiniteNumber3(left.gain_to_target_ratio);
72696
+ const rightRatio = toFiniteNumber3(right.gain_to_target_ratio);
72449
72697
  if (leftRatio !== rightRatio) {
72450
72698
  if (leftRatio === null) return 1;
72451
72699
  if (rightRatio === null) return -1;
@@ -75750,6 +75998,7 @@ var EMPTY_OVERVIEW_POOREST_LINES = {
75750
75998
  };
75751
75999
  var EMPTY_OVERVIEW_TREND = {
75752
76000
  shift_mode: "all",
76001
+ granularity: "day",
75753
76002
  points: []
75754
76003
  };
75755
76004
  var EMPTY_IDLE_BREAKDOWN = [];
@@ -75822,8 +76071,11 @@ var normalizePoorestLines = (value) => ({
75822
76071
  });
75823
76072
  var normalizeTrend = (value) => ({
75824
76073
  shift_mode: value?.shift_mode || "all",
76074
+ granularity: value?.granularity === "hour" ? "hour" : "day",
75825
76075
  points: (value?.points || []).map((point) => ({
75826
76076
  date: point?.date,
76077
+ label: point?.label,
76078
+ hour_index: normalizeNumber(point?.hour_index),
75827
76079
  avg_efficiency: normalizeNumber(point?.avg_efficiency)
75828
76080
  }))
75829
76081
  });
@@ -76165,17 +76417,25 @@ var formatSignedIdleDuration = (seconds) => {
76165
76417
  const sign = seconds > 0 ? "+" : "-";
76166
76418
  return `${sign}${formatIdleDuration(Math.abs(seconds))}`;
76167
76419
  };
76168
- var formatComparisonWindow = (dayCount, comparisonStrategy) => {
76420
+ var formatComparisonWindow = ({
76421
+ currentDayCount,
76422
+ previousDayCount,
76423
+ comparisonStrategy,
76424
+ shiftMode
76425
+ }) => {
76169
76426
  if (comparisonStrategy === "previous_full_week") return "last week";
76170
- if (!dayCount || !Number.isFinite(dayCount)) return "previous range";
76171
- return `previous ${dayCount} ${dayCount === 1 ? "day" : "days"}`;
76427
+ if (comparisonStrategy === "matched_range" && shiftMode !== "all" && currentDayCount === 1 && previousDayCount === 1) {
76428
+ return "previous day";
76429
+ }
76430
+ if (!previousDayCount || !Number.isFinite(previousDayCount)) return "previous range";
76431
+ return `previous ${previousDayCount} ${previousDayCount === 1 ? "day" : "days"}`;
76172
76432
  };
76173
76433
  var buildDeltaBadge = (delta, options) => {
76174
76434
  if (delta === null || delta === void 0 || !Number.isFinite(delta)) {
76175
76435
  return {
76176
76436
  icon: null,
76177
- className: "bg-slate-100 text-slate-500",
76178
- text: `No ${options.comparisonLabel} baseline`
76437
+ className: "bg-slate-100 text-slate-400",
76438
+ text: "\u2014"
76179
76439
  };
76180
76440
  }
76181
76441
  const direction = delta >= 0 ? "up" : "down";
@@ -76186,6 +76446,25 @@ var buildDeltaBadge = (delta, options) => {
76186
76446
  text: `${options.formatter(delta)} vs ${options.comparisonLabel}`
76187
76447
  };
76188
76448
  };
76449
+ var normalizeShiftLabel = (shiftName, shiftMode) => {
76450
+ const trimmedName = shiftName?.trim();
76451
+ if (trimmedName) {
76452
+ return /shift/i.test(trimmedName) ? trimmedName : `${trimmedName} Shift`;
76453
+ }
76454
+ if (shiftMode === "night") return "Night Shift";
76455
+ return "Day Shift";
76456
+ };
76457
+ var getShiftIcon = (shiftName, shiftMode) => {
76458
+ const normalizedName = (shiftName || "").toLowerCase();
76459
+ const normalizedMode = shiftMode || "day";
76460
+ if (normalizedName.includes("day") || normalizedName.includes("morning") || normalizedMode === "day") {
76461
+ return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
76462
+ }
76463
+ if (normalizedName.includes("night") || normalizedName.includes("evening") || normalizedMode === "night") {
76464
+ return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" }) });
76465
+ }
76466
+ return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
76467
+ };
76189
76468
  var buildLineDeltaTone = (delta, comparisonLabel) => {
76190
76469
  if (delta === null || delta === void 0 || !Number.isFinite(delta)) {
76191
76470
  return {
@@ -76241,6 +76520,8 @@ var OperationsOverviewHeader = React141__default.memo(({
76241
76520
  dateRange,
76242
76521
  displayDateRange,
76243
76522
  trendMode,
76523
+ isLiveScope,
76524
+ liveShiftName,
76244
76525
  lineOptions,
76245
76526
  supervisorOptions,
76246
76527
  selectedSupervisorId,
@@ -76254,6 +76535,14 @@ var OperationsOverviewHeader = React141__default.memo(({
76254
76535
  }) => {
76255
76536
  bumpRenderCounter();
76256
76537
  const subtitleRange = displayDateRange || dateRange;
76538
+ const liveShiftLabel = React141__default.useMemo(
76539
+ () => normalizeShiftLabel(liveShiftName, trendMode),
76540
+ [liveShiftName, trendMode]
76541
+ );
76542
+ const liveShiftIcon = React141__default.useMemo(
76543
+ () => getShiftIcon(liveShiftName, trendMode),
76544
+ [liveShiftName, trendMode]
76545
+ );
76257
76546
  const [isFilterOpen, setIsFilterOpen] = React141__default.useState(false);
76258
76547
  const [isLinesDropdownOpen, setIsLinesDropdownOpen] = React141__default.useState(false);
76259
76548
  const filterRef = React141__default.useRef(null);
@@ -76370,9 +76659,25 @@ var OperationsOverviewHeader = React141__default.memo(({
76370
76659
  className: "flex-shrink-0 -ml-1"
76371
76660
  }
76372
76661
  ) : /* @__PURE__ */ jsx("div", { className: "w-8 flex-shrink-0" }),
76373
- /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col items-center justify-center", children: [
76374
- /* @__PURE__ */ jsx("h1", { className: "text-lg font-semibold text-gray-900 text-center px-1 truncate max-w-[200px]", children: "Operations Overview" }),
76375
- /* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium text-slate-500 text-center mt-0.5", children: mobileSubtitle })
76662
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col items-center justify-center min-w-0", children: [
76663
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center gap-1.5 min-w-0 max-w-[240px]", children: [
76664
+ /* @__PURE__ */ jsx("h1", { className: "text-lg font-semibold text-gray-900 leading-tight text-center truncate", children: "Operations Overview" }),
76665
+ isLiveScope ? /* @__PURE__ */ jsx(
76666
+ "div",
76667
+ {
76668
+ "data-testid": "operations-overview-live-indicator",
76669
+ className: "h-2 w-2 rounded-full bg-emerald-500 animate-pulse ring-2 ring-emerald-500/20 flex-shrink-0"
76670
+ }
76671
+ ) : null
76672
+ ] }),
76673
+ /* @__PURE__ */ jsxs("div", { className: "mt-1 flex flex-wrap items-center justify-center gap-x-2 gap-y-1 text-[11px] font-medium text-slate-500 min-w-0", children: [
76674
+ /* @__PURE__ */ jsx("span", { className: "truncate text-center", children: mobileSubtitle }),
76675
+ isLiveScope ? /* @__PURE__ */ jsx("span", { className: "text-slate-300", children: "|" }) : null,
76676
+ isLiveScope ? /* @__PURE__ */ jsx("span", { "data-testid": "operations-overview-live-meta", className: "inline-flex items-center gap-1.5 text-gray-600 min-w-0", children: /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 justify-center truncate", children: [
76677
+ /* @__PURE__ */ jsx("span", { className: "opacity-75 shrink-0", children: liveShiftIcon }),
76678
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: liveShiftLabel })
76679
+ ] }) }) : null
76680
+ ] })
76376
76681
  ] }),
76377
76682
  /* @__PURE__ */ jsxs("div", { className: "flex-shrink-0 flex items-center gap-1.5", children: [
76378
76683
  /* @__PURE__ */ jsx(
@@ -76391,22 +76696,40 @@ var OperationsOverviewHeader = React141__default.memo(({
76391
76696
  {
76392
76697
  ref: mobileFilterButtonRef,
76393
76698
  onClick: handleFilterToggle,
76394
- className: `p-2 rounded-full transition-colors relative ${isFilterOpen || activeFilterCount > 0 ? "bg-blue-50" : "active:bg-gray-100"}`,
76699
+ className: `p-2 rounded-full transition-colors relative ${isFilterOpen || activeFilterCount > 0 ? "bg-slate-100 text-slate-700" : "active:bg-gray-100 text-slate-600"}`,
76395
76700
  "aria-label": "Open filters",
76396
76701
  children: [
76397
- /* @__PURE__ */ jsx(Filter, { className: `w-5 h-5 ${activeFilterCount > 0 ? "text-blue-600" : "text-gray-700"}` }),
76398
- activeFilterCount > 0 ? /* @__PURE__ */ jsx("span", { className: "absolute -top-1 -right-1 flex items-center justify-center w-4 h-4 bg-blue-600 text-white text-[10px] rounded-full font-bold", children: activeFilterCount }) : null
76702
+ /* @__PURE__ */ jsx(Filter, { className: "w-5 h-5" }),
76703
+ activeFilterCount > 0 ? /* @__PURE__ */ jsx("span", { className: "absolute -top-1 -right-1 flex items-center justify-center w-4 h-4 bg-slate-700 text-white text-[10px] rounded-full font-bold", children: activeFilterCount }) : null
76399
76704
  ]
76400
76705
  }
76401
76706
  )
76402
76707
  ] })
76403
76708
  ] }) }),
76404
- /* @__PURE__ */ jsx("div", { className: "hidden sm:block", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center relative min-h-[56px]", children: [
76405
- /* @__PURE__ */ jsxs("div", { className: "absolute left-1/2 -translate-x-1/2 flex flex-col items-center pointer-events-none", children: [
76406
- /* @__PURE__ */ jsx("h1", { className: "text-2xl md:text-3xl lg:text-4xl font-semibold text-gray-900 tracking-tight text-center pointer-events-auto leading-tight mb-0.5", children: "Operations Overview" }),
76407
- /* @__PURE__ */ jsx("span", { className: "text-xs sm:text-sm font-medium text-slate-500 text-center pointer-events-auto", children: desktopSubtitle })
76709
+ /* @__PURE__ */ jsx("div", { className: "hidden sm:block", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center relative min-h-[64px]", children: [
76710
+ /* @__PURE__ */ jsxs("div", { className: "absolute left-1/2 -translate-x-1/2 flex flex-col items-center min-w-0 max-w-[min(70vw,720px)]", children: [
76711
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center gap-2 min-w-0 max-w-full", children: [
76712
+ /* @__PURE__ */ jsx("h1", { className: "text-2xl md:text-3xl lg:text-4xl font-semibold text-gray-900 tracking-tight leading-tight text-center truncate max-w-full", children: "Operations Overview" }),
76713
+ isLiveScope ? /* @__PURE__ */ jsx(
76714
+ "div",
76715
+ {
76716
+ "data-testid": "operations-overview-live-indicator",
76717
+ className: "h-1.5 w-1.5 md:h-2 md:w-2 rounded-full bg-green-500 animate-pulse ring-2 ring-green-500/30 ring-offset-1 flex-shrink-0"
76718
+ }
76719
+ ) : null
76720
+ ] }),
76721
+ /* @__PURE__ */ jsxs("div", { className: "mt-2 flex flex-wrap items-center justify-center gap-x-3 gap-y-1 text-xs sm:text-sm font-medium text-slate-500 text-center", children: [
76722
+ /* @__PURE__ */ jsx("span", { children: desktopSubtitle }),
76723
+ isLiveScope ? /* @__PURE__ */ jsxs(Fragment, { children: [
76724
+ /* @__PURE__ */ jsx("span", { className: "text-slate-300", children: "|" }),
76725
+ /* @__PURE__ */ jsx("span", { "data-testid": "operations-overview-live-meta", className: "inline-flex items-center gap-1.5 text-gray-600", children: /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5 justify-center", children: [
76726
+ /* @__PURE__ */ jsx("span", { className: "opacity-75", children: liveShiftIcon }),
76727
+ liveShiftLabel
76728
+ ] }) })
76729
+ ] }) : null
76730
+ ] })
76408
76731
  ] }),
76409
- /* @__PURE__ */ jsxs("div", { className: "absolute right-0 flex items-center gap-3", children: [
76732
+ /* @__PURE__ */ jsxs("div", { className: "absolute right-0 flex items-center gap-3 shrink-0", children: [
76410
76733
  /* @__PURE__ */ jsx("div", { className: "flex items-center", children: /* @__PURE__ */ jsx(
76411
76734
  MonthlyRangeFilter_default,
76412
76735
  {
@@ -76423,12 +76746,12 @@ var OperationsOverviewHeader = React141__default.memo(({
76423
76746
  {
76424
76747
  ref: filterButtonRef,
76425
76748
  onClick: handleFilterToggle,
76426
- className: `flex items-center gap-2 px-3 py-1.5 rounded-lg border text-sm font-medium transition-all shadow-sm ${isFilterOpen || activeFilterCount > 0 ? "border-blue-500 bg-blue-50 text-blue-700 ring-1 ring-blue-500" : "border-slate-200 bg-white text-slate-700 hover:bg-slate-50"}`,
76749
+ className: `flex items-center gap-2 px-3 py-1.5 rounded-lg border text-sm font-medium transition-all shadow-sm ${isFilterOpen || activeFilterCount > 0 ? "border-slate-300 bg-slate-50 text-slate-700" : "border-slate-200 bg-white text-slate-600 hover:bg-slate-50 hover:text-slate-700"}`,
76427
76750
  "aria-label": "Open filters",
76428
76751
  children: [
76429
- /* @__PURE__ */ jsx(Filter, { className: `w-[18px] h-[18px] ${activeFilterCount > 0 ? "text-blue-600" : "text-slate-500"}` }),
76752
+ /* @__PURE__ */ jsx(Filter, { className: `w-[18px] h-[18px] ${isFilterOpen || activeFilterCount > 0 ? "text-slate-500" : "text-slate-400"}` }),
76430
76753
  "Filters",
76431
- /* @__PURE__ */ jsx(ChevronDown, { className: `w-4 h-4 ml-0.5 transition-transform duration-200 ${isFilterOpen ? "rotate-180" : ""}` })
76754
+ /* @__PURE__ */ jsx(ChevronDown, { className: `w-4 h-4 ml-0.5 text-slate-400 transition-transform duration-200 ${isFilterOpen ? "rotate-180" : ""}` })
76432
76755
  ]
76433
76756
  }
76434
76757
  )
@@ -76556,11 +76879,18 @@ var OverviewSummaryCards = React141__default.memo(({ store }) => {
76556
76879
  const snapshot = useOperationsOverviewSnapshot(store);
76557
76880
  const showSnapshotSkeleton = snapshot.loading && !snapshot.hasLoadedOnce;
76558
76881
  const comparisonLabel = React141__default.useMemo(() => {
76559
- return formatComparisonWindow(
76560
- scope.previous_range?.day_count ?? null,
76561
- scope.comparison_strategy
76562
- );
76563
- }, [scope.comparison_strategy, scope.previous_range?.day_count]);
76882
+ return formatComparisonWindow({
76883
+ currentDayCount: scope.current_range?.day_count ?? null,
76884
+ previousDayCount: scope.previous_range?.day_count ?? null,
76885
+ comparisonStrategy: scope.comparison_strategy,
76886
+ shiftMode: scope.shift_mode
76887
+ });
76888
+ }, [
76889
+ scope.comparison_strategy,
76890
+ scope.current_range?.day_count,
76891
+ scope.previous_range?.day_count,
76892
+ scope.shift_mode
76893
+ ]);
76564
76894
  const [isIdleContributorsOpen, setIsIdleContributorsOpen] = React141__default.useState(false);
76565
76895
  const [isIdleContributorsPinned, setIsIdleContributorsPinned] = React141__default.useState(false);
76566
76896
  const idleContributorsRef = React141__default.useRef(null);
@@ -76650,10 +76980,17 @@ var OverviewSummaryCards = React141__default.memo(({ store }) => {
76650
76980
  roundOne(snapshot.data.summary.plant_efficiency.current),
76651
76981
  "%"
76652
76982
  ] }),
76653
- /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-1 px-2.5 py-1 rounded-full ${plantEfficiencyBadge.className}`, children: [
76654
- plantEfficiencyBadge.icon === "up" ? /* @__PURE__ */ jsx(ArrowUp, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : plantEfficiencyBadge.icon === "down" ? /* @__PURE__ */ jsx(ArrowDown, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : null,
76655
- /* @__PURE__ */ jsx("span", { className: "text-xs sm:text-sm font-medium", children: plantEfficiencyBadge.text })
76656
- ] })
76983
+ /* @__PURE__ */ jsxs(
76984
+ "div",
76985
+ {
76986
+ "data-testid": "operations-overview-efficiency-delta",
76987
+ className: `flex items-center gap-1 px-2.5 py-1 rounded-full ${plantEfficiencyBadge.className}`,
76988
+ children: [
76989
+ plantEfficiencyBadge.icon === "up" ? /* @__PURE__ */ jsx(ArrowUp, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : plantEfficiencyBadge.icon === "down" ? /* @__PURE__ */ jsx(ArrowDown, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : null,
76990
+ /* @__PURE__ */ jsx("span", { className: "text-xs sm:text-sm font-medium", children: plantEfficiencyBadge.text })
76991
+ ]
76992
+ }
76993
+ )
76657
76994
  ] }) : /* @__PURE__ */ jsx("div", { className: "mt-2 text-sm text-slate-400", children: "No efficiency data available" })
76658
76995
  ] }),
76659
76996
  /* @__PURE__ */ jsxs(
@@ -76699,10 +77036,17 @@ var OverviewSummaryCards = React141__default.memo(({ store }) => {
76699
77036
  /* @__PURE__ */ jsx("div", { className: "mb-1", children: /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-gray-700", children: "Idle Time per Workstation" }) }),
76700
77037
  showSnapshotSkeleton ? /* @__PURE__ */ jsx(OverviewMetricCardSkeleton, {}) : snapshot.data.summary.avg_idle_per_workstation?.current_seconds !== null && snapshot.data.summary.avg_idle_per_workstation?.current_seconds !== void 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2 sm:gap-3 mt-1", children: [
76701
77038
  /* @__PURE__ */ jsx("span", { className: "text-2xl sm:text-3xl font-bold text-slate-800 tracking-tight", children: formatIdleDuration(snapshot.data.summary.avg_idle_per_workstation.current_seconds) }),
76702
- /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-1 px-2.5 py-1 rounded-full ${idleBadge.className}`, children: [
76703
- idleBadge.icon === "up" ? /* @__PURE__ */ jsx(ArrowUp, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : idleBadge.icon === "down" ? /* @__PURE__ */ jsx(ArrowDown, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : null,
76704
- /* @__PURE__ */ jsx("span", { className: "text-xs sm:text-sm font-medium", children: idleBadge.text })
76705
- ] })
77039
+ /* @__PURE__ */ jsxs(
77040
+ "div",
77041
+ {
77042
+ "data-testid": "operations-overview-idle-delta",
77043
+ className: `flex items-center gap-1 px-2.5 py-1 rounded-full ${idleBadge.className}`,
77044
+ children: [
77045
+ idleBadge.icon === "up" ? /* @__PURE__ */ jsx(ArrowUp, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : idleBadge.icon === "down" ? /* @__PURE__ */ jsx(ArrowDown, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : null,
77046
+ /* @__PURE__ */ jsx("span", { className: "text-xs sm:text-sm font-medium", children: idleBadge.text })
77047
+ ]
77048
+ }
77049
+ )
76706
77050
  ] }) : /* @__PURE__ */ jsx("div", { className: "mt-2 text-sm text-slate-400", children: "No idle time data available" })
76707
77051
  ]
76708
77052
  }
@@ -76765,11 +77109,18 @@ var PoorestPerformersCard = React141__default.memo(({
76765
77109
  }
76766
77110
  }, [availableLineModes?.has_output, availableLineModes?.has_uptime, poorestLineMode]);
76767
77111
  const comparisonLabel = React141__default.useMemo(() => {
76768
- return formatComparisonWindow(
76769
- scope.previous_range?.day_count ?? null,
76770
- scope.comparison_strategy
76771
- );
76772
- }, [scope.comparison_strategy, scope.previous_range?.day_count]);
77112
+ return formatComparisonWindow({
77113
+ currentDayCount: scope.current_range?.day_count ?? null,
77114
+ previousDayCount: scope.previous_range?.day_count ?? null,
77115
+ comparisonStrategy: scope.comparison_strategy,
77116
+ shiftMode: scope.shift_mode
77117
+ });
77118
+ }, [
77119
+ scope.comparison_strategy,
77120
+ scope.current_range?.day_count,
77121
+ scope.previous_range?.day_count,
77122
+ scope.shift_mode
77123
+ ]);
76773
77124
  const showSnapshotSkeleton = snapshot.loading && !snapshot.hasLoadedOnce;
76774
77125
  const mergedPoorestLines = React141__default.useMemo(() => {
76775
77126
  const rows = snapshot.data.poorest_lines?.[poorestLineMode] || [];
@@ -76926,7 +77277,8 @@ IdleBreakdownCard.displayName = "IdleBreakdownCard";
76926
77277
  var EfficiencyTrendCard = React141__default.memo(({
76927
77278
  store,
76928
77279
  dateRange,
76929
- appTimezone
77280
+ appTimezone,
77281
+ hourlyLabelStartTime
76930
77282
  }) => {
76931
77283
  bumpRenderCounter();
76932
77284
  const trend = useOperationsOverviewTrend(store);
@@ -76936,7 +77288,41 @@ var EfficiencyTrendCard = React141__default.memo(({
76936
77288
  );
76937
77289
  const isCurrentWeekToDateRange = dateRange.startKey === currentWeekRange.startKey && dateRange.endKey === currentWeekRange.endKey;
76938
77290
  const showInitialSkeleton = trend.loading && trend.lastUpdated === null;
77291
+ const isHourlyTrend = trend.data.granularity === "hour";
76939
77292
  const trendData = React141__default.useMemo(() => {
77293
+ if (isHourlyTrend) {
77294
+ return (trend.data.points || []).map((point, index) => ({
77295
+ name: (() => {
77296
+ const rawLabel = point.label?.trim() || "";
77297
+ if (!hourlyLabelStartTime) {
77298
+ return rawLabel || `Hour ${index + 1}`;
77299
+ }
77300
+ if (rawLabel && !/^Hour\s+\d+$/i.test(rawLabel)) {
77301
+ return rawLabel;
77302
+ }
77303
+ const hourIndex = typeof point.hour_index === "number" ? point.hour_index : index;
77304
+ const [hoursPart, minutesPart] = hourlyLabelStartTime.split(":");
77305
+ const startHours = Number(hoursPart);
77306
+ const startMinutes = Number(minutesPart);
77307
+ if (!Number.isFinite(startHours) || !Number.isFinite(startMinutes)) {
77308
+ return rawLabel || `Hour ${index + 1}`;
77309
+ }
77310
+ const totalMinutes = startHours * 60 + startMinutes + hourIndex * 60;
77311
+ const hour24 = Math.floor(totalMinutes / 60) % 24;
77312
+ const minutes = totalMinutes % 60;
77313
+ const suffix = hour24 < 12 ? "AM" : "PM";
77314
+ const hour12 = hour24 % 12 || 12;
77315
+ if (minutes === 0) {
77316
+ return `${hour12} ${suffix}`;
77317
+ }
77318
+ return `${hour12}:${minutes.toString().padStart(2, "0")} ${suffix}`;
77319
+ })(),
77320
+ efficiency: (() => {
77321
+ const value = toNumber3(point.avg_efficiency);
77322
+ return value === null ? void 0 : value;
77323
+ })()
77324
+ }));
77325
+ }
76940
77326
  const pointsByDate = new Map(
76941
77327
  (trend.data.points || []).flatMap((point) => {
76942
77328
  if (!point.date) return [];
@@ -76974,12 +77360,13 @@ var EfficiencyTrendCard = React141__default.memo(({
76974
77360
  })()
76975
77361
  };
76976
77362
  });
76977
- }, [currentWeekRange.startKey, isCurrentWeekToDateRange, trend.data.points]);
77363
+ }, [currentWeekRange.startKey, hourlyLabelStartTime, isCurrentWeekToDateRange, isHourlyTrend, trend.data.points]);
76978
77364
  const trendTooltipLabelFormatter = React141__default.useCallback((label, payload) => {
77365
+ if (isHourlyTrend) return label;
76979
77366
  const dayOfWeek = payload?.[0]?.payload?.dayOfWeek;
76980
77367
  if (!dayOfWeek || typeof label !== "string") return label;
76981
77368
  return `${label} (${dayOfWeek})`;
76982
- }, []);
77369
+ }, [isHourlyTrend]);
76983
77370
  return /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-xl shadow-[0_2px_10px_-3px_rgba(6,81,237,0.1)] border border-slate-100 flex flex-col overflow-hidden text-left", children: [
76984
77371
  /* @__PURE__ */ jsx("div", { className: "px-6 py-5 flex-none flex justify-between items-center border-b border-slate-50/50", children: /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-gray-700", children: "Efficiency Trend" }) }),
76985
77372
  /* @__PURE__ */ jsx("div", { className: "flex-1 min-h-[250px] w-full p-4 pt-4 relative", children: showInitialSkeleton ? /* @__PURE__ */ jsx(OverviewChartSkeleton, {}) : /* @__PURE__ */ jsx("div", { className: "absolute inset-0 pb-2 pr-4 pl-1", children: /* @__PURE__ */ jsx(
@@ -77133,7 +77520,8 @@ var useOperationsOverviewRefresh = ({
77133
77520
  endKey,
77134
77521
  trendMode,
77135
77522
  comparisonStrategy,
77136
- isLiveScope
77523
+ isLiveScope,
77524
+ enabled = true
77137
77525
  }) => {
77138
77526
  const lineIdsKey = React141__default.useMemo(() => lineIds.join(","), [lineIds]);
77139
77527
  const scopeSignature = React141__default.useMemo(
@@ -77179,7 +77567,7 @@ var useOperationsOverviewRefresh = ({
77179
77567
  }, []);
77180
77568
  const runRefresh = React141__default.useCallback(
77181
77569
  async (section, begin, onSuccess, onError, request, reason) => {
77182
- if (!supabase || !companyId || lineIds.length === 0) return;
77570
+ if (!enabled || !supabase || !companyId || lineIds.length === 0) return;
77183
77571
  const requestId = requestIdsRef.current[section] + 1;
77184
77572
  requestIdsRef.current[section] = requestId;
77185
77573
  controllersRef.current[section]?.abort();
@@ -77199,7 +77587,7 @@ var useOperationsOverviewRefresh = ({
77199
77587
  onError(error instanceof Error ? error.message : `Failed to refresh ${section}`);
77200
77588
  }
77201
77589
  },
77202
- [companyId, lineIds.length, supabase]
77590
+ [companyId, enabled, lineIds.length, supabase]
77203
77591
  );
77204
77592
  const refreshSnapshot = React141__default.useCallback(
77205
77593
  async (reason) => {
@@ -77369,6 +77757,12 @@ var useOperationsOverviewRefresh = ({
77369
77757
  });
77370
77758
  }, [refreshAll, startPolling, stopPolling]);
77371
77759
  React141__default.useEffect(() => {
77760
+ if (!enabled) {
77761
+ stopPolling("disabled");
77762
+ abortAll();
77763
+ store.reset();
77764
+ return;
77765
+ }
77372
77766
  if (!supabase || !companyId || lineIds.length === 0) {
77373
77767
  stopPolling("scope_invalid");
77374
77768
  abortAll();
@@ -77376,9 +77770,9 @@ var useOperationsOverviewRefresh = ({
77376
77770
  return;
77377
77771
  }
77378
77772
  void refreshAll("scope_change");
77379
- }, [abortAll, companyId, lineIds.length, refreshAll, scopeSignature, stopPolling, store, supabase]);
77773
+ }, [abortAll, companyId, enabled, lineIds.length, refreshAll, scopeSignature, stopPolling, store, supabase]);
77380
77774
  React141__default.useEffect(() => {
77381
- if (!isLiveScope || !supabase || !companyId || lineIds.length === 0) {
77775
+ if (!enabled || !isLiveScope || !supabase || !companyId || lineIds.length === 0) {
77382
77776
  isPageActiveRef.current = false;
77383
77777
  stopPolling("live_scope_disabled");
77384
77778
  return;
@@ -77434,11 +77828,63 @@ var useOperationsOverviewRefresh = ({
77434
77828
  window.removeEventListener("pageshow", handlePageShow);
77435
77829
  window.removeEventListener("pagehide", handlePageHide);
77436
77830
  };
77437
- }, [companyId, getIsPageActive, isLiveScope, lineIds.length, refreshFromResume, startPolling, stopPolling, supabase]);
77831
+ }, [companyId, enabled, getIsPageActive, isLiveScope, lineIds.length, refreshFromResume, startPolling, stopPolling, supabase]);
77832
+ };
77833
+ var parseTimeToMinutes3 = (value) => {
77834
+ if (!value) return null;
77835
+ const parts = value.split(":");
77836
+ if (parts.length < 2) return null;
77837
+ const hours = Number(parts[0]);
77838
+ const minutes = Number(parts[1]);
77839
+ if (!Number.isFinite(hours) || !Number.isFinite(minutes)) return null;
77840
+ if (hours < 0 || hours > 23 || minutes < 0 || minutes > 59) return null;
77841
+ return hours * 60 + minutes;
77842
+ };
77843
+ var normalizeShiftId = (value) => {
77844
+ if (typeof value === "number" && Number.isFinite(value)) {
77845
+ return value;
77846
+ }
77847
+ if (typeof value === "string" && value.trim().length > 0) {
77848
+ const parsed = Number(value);
77849
+ return Number.isFinite(parsed) ? parsed : null;
77850
+ }
77851
+ return null;
77852
+ };
77853
+ var classifyShiftBucket = ({
77854
+ shiftName,
77855
+ shiftId,
77856
+ startTime,
77857
+ endTime
77858
+ }) => {
77859
+ const normalizedName = (shiftName || "").trim().toLowerCase();
77860
+ if (normalizedName) {
77861
+ if (["night", "graveyard", "evening"].some((keyword) => normalizedName.includes(keyword))) {
77862
+ return "night";
77863
+ }
77864
+ if (["day", "morning"].some((keyword) => normalizedName.includes(keyword))) {
77865
+ return "day";
77866
+ }
77867
+ }
77868
+ const startMinutes = parseTimeToMinutes3(startTime);
77869
+ const endMinutes = parseTimeToMinutes3(endTime);
77870
+ if (startMinutes !== null) {
77871
+ if (startMinutes >= 4 * 60 && startMinutes < 18 * 60) return "day";
77872
+ return "night";
77873
+ }
77874
+ if (endMinutes !== null) {
77875
+ if (endMinutes >= 6 * 60 && endMinutes <= 21 * 60) return "day";
77876
+ return "night";
77877
+ }
77878
+ const normalizedShiftId = normalizeShiftId(shiftId);
77879
+ if (normalizedShiftId === 0) return "day";
77880
+ if (normalizedShiftId === 1) return "night";
77881
+ return null;
77438
77882
  };
77439
77883
  var PlantHeadView = () => {
77440
77884
  const supabase = useSupabase();
77441
77885
  const entityConfig = useEntityConfig();
77886
+ const factoryViewId = entityConfig.factoryViewId || "factory";
77887
+ const staticShiftConfig = useShiftConfig();
77442
77888
  const appTimezone = useAppTimezone() || "UTC";
77443
77889
  const { navigate } = useNavigation();
77444
77890
  const { accessibleLineIds } = useUserLineAccess();
@@ -77446,11 +77892,21 @@ var PlantHeadView = () => {
77446
77892
  useHideMobileHeader(!!mobileMenuContext);
77447
77893
  const storeRef = React141__default.useRef(createOperationsOverviewStore());
77448
77894
  const store = storeRef.current;
77449
- const [dateRange, setDateRange] = React141__default.useState(() => getCurrentWeekToDateRange(appTimezone));
77450
- const [usesThisWeekComparison, setUsesThisWeekComparison] = React141__default.useState(true);
77895
+ const fallbackOperationalDate = React141__default.useMemo(
77896
+ () => getOperationalDate(appTimezone),
77897
+ [appTimezone]
77898
+ );
77899
+ const [dateRange, setDateRange] = React141__default.useState(() => ({
77900
+ startKey: fallbackOperationalDate,
77901
+ endKey: fallbackOperationalDate
77902
+ }));
77903
+ const [usesThisWeekComparison, setUsesThisWeekComparison] = React141__default.useState(false);
77451
77904
  const [trendMode, setTrendMode] = React141__default.useState("all");
77452
77905
  const [selectedSupervisorId, setSelectedSupervisorId] = React141__default.useState("all");
77453
77906
  const [selectedLineIds, setSelectedLineIds] = React141__default.useState([]);
77907
+ const [isInitialScopeReady, setIsInitialScopeReady] = React141__default.useState(false);
77908
+ const hasAutoInitializedScopeRef = React141__default.useRef(false);
77909
+ const hasUserAdjustedScopeRef = React141__default.useRef(false);
77454
77910
  React141__default.useEffect(() => {
77455
77911
  trackCorePageView("Operations Overview", {
77456
77912
  dashboard_surface: "operations_overview"
@@ -77472,8 +77928,10 @@ var PlantHeadView = () => {
77472
77928
  return dateRange;
77473
77929
  }, [currentWeekDisplayRange, dateRange, isCurrentWeekToDateRange, usesThisWeekComparison]);
77474
77930
  const normalizedLineIds = React141__default.useMemo(
77475
- () => Array.from(new Set((accessibleLineIds || []).filter(Boolean))).sort(),
77476
- [accessibleLineIds]
77931
+ () => Array.from(new Set(
77932
+ (accessibleLineIds || []).filter(Boolean).filter((lineId) => lineId !== factoryViewId)
77933
+ )).sort(),
77934
+ [accessibleLineIds, factoryViewId]
77477
77935
  );
77478
77936
  const lineIdsKey = React141__default.useMemo(
77479
77937
  () => normalizedLineIds.join(","),
@@ -77547,14 +78005,81 @@ var PlantHeadView = () => {
77547
78005
  () => selectedLineIds.length > 0 ? selectedLineIds : normalizedLineIds,
77548
78006
  [normalizedLineIds, selectedLineIds]
77549
78007
  );
78008
+ const {
78009
+ shiftConfigMap,
78010
+ isLoading: isShiftConfigLoading
78011
+ } = useMultiLineShiftConfigs(scopedLineIds, staticShiftConfig);
78012
+ const { shiftGroups, hasComputed: hasComputedShiftGroups } = useShiftGroups({
78013
+ enabled: scopedLineIds.length > 0 && !isShiftConfigLoading,
78014
+ shiftConfigMap,
78015
+ timezone: appTimezone
78016
+ });
78017
+ const currentShiftScope = React141__default.useMemo(() => {
78018
+ if (shiftGroups.length !== 1) return null;
78019
+ const group = shiftGroups[0];
78020
+ const referenceLineId = group.lineIds[0];
78021
+ const referenceShiftConfig = referenceLineId ? shiftConfigMap.get(referenceLineId) : null;
78022
+ const normalizedGroupShiftId = normalizeShiftId(group.shiftId);
78023
+ const shiftDefinition = referenceShiftConfig?.shifts?.find((shift) => normalizeShiftId(shift.shiftId) === normalizedGroupShiftId);
78024
+ const resolvedMode = classifyShiftBucket({
78025
+ shiftName: group.shiftName,
78026
+ shiftId: normalizedGroupShiftId,
78027
+ startTime: shiftDefinition?.startTime,
78028
+ endTime: shiftDefinition?.endTime
78029
+ });
78030
+ if (!resolvedMode || resolvedMode === "all") return null;
78031
+ return {
78032
+ date: group.date,
78033
+ trendMode: resolvedMode,
78034
+ shiftName: shiftDefinition?.shiftName || group.shiftName || null
78035
+ };
78036
+ }, [shiftConfigMap, shiftGroups]);
78037
+ const isShiftScopeResolved = React141__default.useMemo(
78038
+ () => !isShiftConfigLoading && hasComputedShiftGroups,
78039
+ [hasComputedShiftGroups, isShiftConfigLoading]
78040
+ );
77550
78041
  const initializedTimezoneRef = React141__default.useRef(appTimezone);
77551
78042
  React141__default.useEffect(() => {
77552
78043
  if (initializedTimezoneRef.current === appTimezone) return;
77553
- setDateRange(getCurrentWeekToDateRange(appTimezone));
77554
- setUsesThisWeekComparison(true);
78044
+ hasAutoInitializedScopeRef.current = false;
78045
+ hasUserAdjustedScopeRef.current = false;
78046
+ setDateRange({
78047
+ startKey: fallbackOperationalDate,
78048
+ endKey: fallbackOperationalDate
78049
+ });
78050
+ setTrendMode("all");
78051
+ setUsesThisWeekComparison(false);
78052
+ setIsInitialScopeReady(false);
77555
78053
  initializedTimezoneRef.current = appTimezone;
77556
- }, [appTimezone]);
78054
+ }, [appTimezone, fallbackOperationalDate]);
78055
+ React141__default.useEffect(() => {
78056
+ if (hasAutoInitializedScopeRef.current || hasUserAdjustedScopeRef.current) {
78057
+ return;
78058
+ }
78059
+ if (scopedLineIds.length === 0) {
78060
+ return;
78061
+ }
78062
+ if (!isShiftScopeResolved) {
78063
+ return;
78064
+ }
78065
+ setDateRange((previous) => {
78066
+ const nextStartKey = currentShiftScope?.date || fallbackOperationalDate;
78067
+ if (previous.startKey === nextStartKey && previous.endKey === nextStartKey) {
78068
+ return previous;
78069
+ }
78070
+ return {
78071
+ startKey: nextStartKey,
78072
+ endKey: nextStartKey
78073
+ };
78074
+ });
78075
+ setTrendMode(currentShiftScope?.trendMode || "all");
78076
+ setUsesThisWeekComparison(false);
78077
+ hasAutoInitializedScopeRef.current = true;
78078
+ setIsInitialScopeReady(true);
78079
+ }, [currentShiftScope, fallbackOperationalDate, isShiftScopeResolved, scopedLineIds.length]);
77557
78080
  const handleDateRangeChange = React141__default.useCallback((range, meta) => {
78081
+ hasUserAdjustedScopeRef.current = true;
78082
+ setIsInitialScopeReady(true);
77558
78083
  trackCoreEvent("Operations Overview Date Range Changed", {
77559
78084
  start_date: range.startKey,
77560
78085
  end_date: range.endKey
@@ -77571,6 +78096,8 @@ var PlantHeadView = () => {
77571
78096
  });
77572
78097
  }, []);
77573
78098
  const handleTrendModeChange = React141__default.useCallback((mode) => {
78099
+ hasUserAdjustedScopeRef.current = true;
78100
+ setIsInitialScopeReady(true);
77574
78101
  setTrendMode(mode);
77575
78102
  }, []);
77576
78103
  const handleSelectedLineIdsChange = React141__default.useCallback((lineIds) => {
@@ -77597,15 +78124,6 @@ var PlantHeadView = () => {
77597
78124
  params.set("rangeEnd", dateRange.endKey);
77598
78125
  return `/kpis/${lineId}?${params.toString()}`;
77599
78126
  }, [dateRange.endKey, dateRange.startKey]);
77600
- const handleOpenLineMonthlyHistory = React141__default.useCallback((lineId, lineName) => {
77601
- trackCoreEvent("Operations Overview Line Clicked", {
77602
- line_id: lineId,
77603
- line_name: lineName,
77604
- range_start: dateRange.startKey,
77605
- range_end: dateRange.endKey
77606
- });
77607
- navigate(buildLineMonthlyHistoryUrl(lineId));
77608
- }, [buildLineMonthlyHistoryUrl, dateRange.endKey, dateRange.startKey, navigate]);
77609
78127
  const handleViewAllPoorestPerformers = React141__default.useCallback(() => {
77610
78128
  trackCoreEvent("Operations Overview View All Clicked", { section: "poorest_performers" });
77611
78129
  navigate("/kpis?tab=leaderboard");
@@ -77631,16 +78149,74 @@ var PlantHeadView = () => {
77631
78149
  }
77632
78150
  return void 0;
77633
78151
  }, [isCurrentWeekToDateRange, usesThisWeekComparison]);
78152
+ const effectiveDateRange = React141__default.useMemo(() => {
78153
+ if (isInitialScopeReady) {
78154
+ return dateRange;
78155
+ }
78156
+ const nextStartKey = currentShiftScope?.date || fallbackOperationalDate;
78157
+ return {
78158
+ startKey: nextStartKey,
78159
+ endKey: nextStartKey
78160
+ };
78161
+ }, [currentShiftScope, dateRange, fallbackOperationalDate, isInitialScopeReady]);
78162
+ const effectiveTrendMode = React141__default.useMemo(
78163
+ () => isInitialScopeReady ? trendMode : currentShiftScope?.trendMode || "all",
78164
+ [currentShiftScope, isInitialScopeReady, trendMode]
78165
+ );
78166
+ const hourlyLabelStartTime = React141__default.useMemo(() => {
78167
+ if (effectiveTrendMode === "all" || scopedLineIds.length === 0) {
78168
+ return null;
78169
+ }
78170
+ const shiftStartTimes = /* @__PURE__ */ new Set();
78171
+ scopedLineIds.forEach((lineId) => {
78172
+ const shiftConfig = shiftConfigMap.get(lineId);
78173
+ const matchingShift = shiftConfig?.shifts?.find((shift) => classifyShiftBucket({
78174
+ shiftName: shift.shiftName,
78175
+ shiftId: shift.shiftId,
78176
+ startTime: shift.startTime,
78177
+ endTime: shift.endTime
78178
+ }) === effectiveTrendMode);
78179
+ if (matchingShift?.startTime) {
78180
+ shiftStartTimes.add(matchingShift.startTime);
78181
+ }
78182
+ });
78183
+ if (shiftStartTimes.size !== 1) {
78184
+ return null;
78185
+ }
78186
+ return Array.from(shiftStartTimes)[0] || null;
78187
+ }, [effectiveTrendMode, scopedLineIds, shiftConfigMap]);
78188
+ const isSingleDayShiftScope = React141__default.useMemo(
78189
+ () => effectiveDateRange.startKey === effectiveDateRange.endKey && effectiveTrendMode !== "all",
78190
+ [effectiveDateRange.endKey, effectiveDateRange.startKey, effectiveTrendMode]
78191
+ );
78192
+ const isLiveScope = React141__default.useMemo(
78193
+ () => isSingleDayShiftScope && currentShiftScope !== null && effectiveDateRange.startKey === currentShiftScope.date && effectiveTrendMode === currentShiftScope.trendMode,
78194
+ [currentShiftScope, effectiveDateRange.startKey, effectiveTrendMode, isSingleDayShiftScope]
78195
+ );
78196
+ const handleOpenLineDetails = React141__default.useCallback((lineId, lineName) => {
78197
+ trackCoreEvent("Operations Overview Line Clicked", {
78198
+ line_id: lineId,
78199
+ line_name: lineName,
78200
+ range_start: dateRange.startKey,
78201
+ range_end: dateRange.endKey
78202
+ });
78203
+ if (isLiveScope) {
78204
+ navigate(`/kpis/${lineId}?returnTo=${encodeURIComponent("/")}`);
78205
+ return;
78206
+ }
78207
+ navigate(buildLineMonthlyHistoryUrl(lineId));
78208
+ }, [buildLineMonthlyHistoryUrl, dateRange.endKey, dateRange.startKey, isLiveScope, navigate]);
77634
78209
  useOperationsOverviewRefresh({
77635
78210
  store,
77636
78211
  supabase,
77637
78212
  companyId: entityConfig.companyId,
77638
78213
  lineIds: scopedLineIds,
77639
- startKey: dateRange.startKey,
77640
- endKey: dateRange.endKey,
77641
- trendMode,
78214
+ startKey: effectiveDateRange.startKey,
78215
+ endKey: effectiveDateRange.endKey,
78216
+ trendMode: effectiveTrendMode,
77642
78217
  comparisonStrategy,
77643
- isLiveScope: isCurrentWeekToDateRange
78218
+ isLiveScope,
78219
+ enabled: scopedLineIds.length > 0 && isShiftScopeResolved
77644
78220
  });
77645
78221
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col min-h-screen bg-slate-50 w-full font-sans", children: [
77646
78222
  /* @__PURE__ */ jsx(
@@ -77649,6 +78225,8 @@ var PlantHeadView = () => {
77649
78225
  dateRange,
77650
78226
  displayDateRange: headerDateRange,
77651
78227
  trendMode,
78228
+ isLiveScope,
78229
+ liveShiftName: currentShiftScope?.shiftName || null,
77652
78230
  lineOptions,
77653
78231
  supervisorOptions,
77654
78232
  selectedSupervisorId,
@@ -77671,7 +78249,7 @@ var PlantHeadView = () => {
77671
78249
  store,
77672
78250
  supervisorsByLineId,
77673
78251
  onViewAll: handleViewAllPoorestPerformers,
77674
- onLineClick: handleOpenLineMonthlyHistory
78252
+ onLineClick: handleOpenLineDetails
77675
78253
  }
77676
78254
  ),
77677
78255
  /* @__PURE__ */ jsx(
@@ -77688,7 +78266,8 @@ var PlantHeadView = () => {
77688
78266
  {
77689
78267
  store,
77690
78268
  dateRange,
77691
- appTimezone
78269
+ appTimezone,
78270
+ hourlyLabelStartTime
77692
78271
  }
77693
78272
  ),
77694
78273
  /* @__PURE__ */ jsx(
@@ -78182,4 +78761,4 @@ var streamProxyConfig = {
78182
78761
  }
78183
78762
  };
78184
78763
 
78185
- export { ACTION_FAMILIES, ACTION_NAMES, AIAgentView_default as AIAgentView, AcceptInvite, AcceptInviteView_default as AcceptInviteView, AdvancedFilterDialog, AdvancedFilterPanel, AudioService, AuthCallback, AuthCallbackView_default as AuthCallbackView, AuthProvider, AuthService, AuthenticatedBottleneckClipsView, AuthenticatedFactoryView, AuthenticatedHelpView, AuthenticatedHomeView, AuthenticatedShiftsView, AuthenticatedTargetsView, AuthenticatedTicketsView, AuthenticatedWorkspaceHealthView, AvatarUpload, AxelNotificationPopup, AxelOrb, BackButton, BackButtonMinimal, BarChart, BaseHistoryCalendar, BottleneckClipsModal, BottleneckClipsView_default as BottleneckClipsView, BottlenecksContent, BreakNotificationPopup, CachePrefetchStatus, Card2 as Card, CardContent2 as CardContent, CardDescription2 as CardDescription, CardFooter2 as CardFooter, CardHeader2 as CardHeader, CardTitle2 as CardTitle, ChangeRoleDialog, ClipFilterProvider, ClipsCostView_default as ClipsCostView, CompactWorkspaceHealthCard, ConfirmRemoveUserDialog, CongratulationsOverlay, CroppedHlsVideoPlayer, CroppedVideoPlayer, CycleTimeChart, CycleTimeOverTimeChart, DEFAULT_ANALYTICS_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_CONFIG, DEFAULT_DATABASE_CONFIG, DEFAULT_DATE_TIME_CONFIG, DEFAULT_ENDPOINTS_CONFIG, DEFAULT_ENTITY_CONFIG, DEFAULT_HOME_VIEW_CONFIG, DEFAULT_MAP_VIEW_CONFIG, DEFAULT_SHIFT_CONFIG, DEFAULT_SHIFT_DATA, DEFAULT_THEME_CONFIG, DEFAULT_VIDEO_CONFIG, DEFAULT_WORKSPACE_CONFIG, DEFAULT_WORKSPACE_POSITIONS, DashboardHeader, DashboardLayout, DashboardOverridesProvider, DashboardProvider, DateDisplay_default as DateDisplay, DateTimeDisplay, DebugAuth, DebugAuthView_default as DebugAuthView, DetailedHealthStatus, DiagnosisVideoModal, EFFICIENCY_ON_TRACK_THRESHOLD, EmptyStateMessage, EncouragementOverlay, FactoryAssignmentDropdown, FactoryView_default as FactoryView, FileManagerFilters, FilterDialogTrigger, FirstTimeLoginDebug, FirstTimeLoginHandler, FittingTitle, GaugeChart, GridComponentsPlaceholder, HamburgerButton, Header, HealthDateShiftSelector, HealthStatusGrid, HealthStatusIndicator, HelpView_default as HelpView, HlsVideoPlayer, HomeView_default as HomeView, HourlyOutputChart2 as HourlyOutputChart, HourlyUptimeChart, ISTTimer_default as ISTTimer, IdleTimeVlmConfigProvider, ImprovementCenterView_default as ImprovementCenterView, InlineEditableText, InteractiveOnboardingTour, InvitationService, InvitationsTable, InviteUserDialog, KPICard, KPIDetailView_default as KPIDetailView, KPIGrid, KPIHeader, KPISection, KPIsOverviewView_default as KPIsOverviewView, LINE_1_UUID, LINE_2_UUID, LargeOutputProgressChart, LeaderboardDetailView_default as LeaderboardDetailView, Legend5 as Legend, LineAssignmentDropdown, LineChart, LineHistoryCalendar, LineMonthlyHistory, LineMonthlyPdfGenerator, LinePdfExportButton, LinePdfGenerator, LineWhatsAppShareButton, LinesService, LiveTimer, LoadingInline, LoadingOverlay_default as LoadingOverlay, LoadingPage_default as LoadingPage, LoadingSkeleton, LoadingState, LoginPage, LoginView_default as LoginView, Logo, MainLayout, MapGridView, MetricCard_default as MetricCard, MinimalOnboardingPopup, MobileMenuProvider, NewClipsNotification, NoWorkspaceData, OnboardingDemo, OnboardingTour, OptifyeAgentClient, OptifyeLogoLoader_default as OptifyeLogoLoader, OutputProgressChart, PageHeader, PieChart4 as PieChart, PlantHeadView_default as PlantHeadView, PlayPauseIndicator, PrefetchConfigurationError, PrefetchError, PrefetchEvents, PrefetchStatus, PrefetchTimeoutError, ProfileView_default as ProfileView, RegistryProvider, RoleBadge, S3ClipsSupabaseService as S3ClipsService, S3Service, SKUManagementView, SOPComplianceChart, SSEChatClient, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, SessionTracker, SessionTrackingContext, SessionTrackingProvider, SettingsPopup, ShiftDisplay_default as ShiftDisplay, ShiftsView_default as ShiftsView, SideNavBar, SignupWithInvitation, SilentErrorBoundary, SimpleOnboardingPopup, SingleVideoStream_default as SingleVideoStream, Skeleton, SubscriptionManager, SubscriptionManagerProvider, SupabaseProvider, SupervisorDropdown_default as SupervisorDropdown, SupervisorManagementView_default as SupervisorManagementView, SupervisorService, TargetWorkspaceGrid, TargetsView_default as TargetsView, TeamManagementView_default as TeamManagementView, ThreadSidebar, TicketHistory_default as TicketHistory, TicketHistoryService, TicketsView_default as TicketsView, TimeDisplay_default as TimeDisplay, TimePickerDropdown, Timer_default as Timer, TimezoneProvider, TimezoneService, UptimeDonutChart, UptimeLineChart, UptimeMetricCards, UserAvatar, UserManagementService, UserManagementTable, UserService, UserUsageDetailModal, UserUsageStats, VideoCard, VideoGridView, VideoPlayer, VideoPreloader, WORKSPACE_POSITIONS, WhatsAppShareButton, WorkspaceCard, WorkspaceCycleTimeMetricCards, WorkspaceDetailView_default as WorkspaceDetailView, WorkspaceDisplayNameExample, WorkspaceGrid, WorkspaceGridItem, WorkspaceHealthCard, WorkspaceHealthView_default as WorkspaceHealthView, WorkspaceHistoryCalendar, WorkspaceMetricCards, WorkspaceMetricCardsImpl, WorkspaceMonthlyDataFetcher, WorkspaceMonthlyHistory, WorkspaceMonthlyPdfGenerator, WorkspacePdfExportButton, WorkspacePdfGenerator, WorkspaceWhatsAppShareButton, actionService, aggregateKPIsFromLineMetricsRows, alertsService, apiUtils, areAllLinesOnSameShift, authCoreService, authOTPService, authRateLimitService, awardsService, buildDateKey, buildKPIsFromLineMetricsRow, buildShiftGroupsKey, canRoleAccessDashboardPath, canRoleAccessTeamManagement, canRoleAssignFactories, canRoleAssignLines, canRoleChangeRole, canRoleInviteRole, canRoleManageCompany, canRoleManageTargets, canRoleManageUsers, canRoleRemoveUser, canRoleViewClipsCost, canRoleViewUsageStats, captureSentryException, captureSentryMessage, checkRateLimit2 as checkRateLimit, clearAllRateLimits2 as clearAllRateLimits, clearRateLimit2 as clearRateLimit, clearS3VideoCache, clearS3VideoFromCache, clearSentryContext, clearWorkspaceDisplayNamesCache, cn, createDefaultKPIs, createInvitationService, createLinesService, createSessionTracker, createStorageService, createStreamProxyHandler, createSupabaseClient, createSupervisorService, createThrottledReload, createUserManagementService, createUserService, dashboardService, deleteThread, fetchIdleTimeReasons, filterDataByDateKeyRange, forceRefreshWorkspaceDisplayNames, formatAwardMonth, formatDateInZone, formatDateKeyForDisplay, formatDateTimeInZone, formatDuration2 as formatDuration, formatISTDate, formatIdleTime, formatRangeLabel, formatReasonLabel, formatRelativeTime, formatTimeInZone, fromUrlFriendlyName, getActionDisplayName, getAllLineDisplayNames, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAllWorkspaceDisplayNamesSnapshot, getAnonClient, getAssignableRoles, getAssignmentColumnLabel, getAvailableShiftIds, getAwardBadgeType, getAwardDescription, getAwardTitle, getBrowserName, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getConfiguredLineIds, getCoreSessionRecordingProperties, getCoreSessionReplayUrl, getCurrentShift, getCurrentShiftForLine, getCurrentTimeInZone, getCurrentWeekFullRange, getCurrentWeekToDateRange, getDashboardHeaderTimeInZone, getDateKeyFromDate, getDaysDifferenceInZone, getDefaultCameraStreamUrl, getDefaultLineId, getDefaultTabForWorkspace, getInitials, getLineDisplayName, getManufacturingInsights, getMetricsTablePrefix, getMonthKeyBounds, getMonthWeekRanges, getNextUpdateInterval, getOperationalDate, getRoleAssignmentKind, getRoleDescription, getRoleLabel, getRoleMetadata, getRoleNavPaths, getS3SignedUrl, getS3VideoSrc, getShiftData, getShiftNameById, getShiftWorkDurationSeconds, getShortShiftName, getShortWorkspaceDisplayName, getShortWorkspaceDisplayNameAsync, getStoredWorkspaceMappings, getSubscriptionManager, getThreadMessages, getUniformShiftGroup, getUserThreads, getUserThreadsPaginated, getVisibleRolesForCurrentUser, getWorkspaceDisplayName, getWorkspaceDisplayNameAsync, getWorkspaceDisplayNamesMap, getWorkspaceFromUrl, getWorkspaceNavigationParams, groupLinesByShift, hasAnyShiftData, identifyCoreUser, initializeCoreMixpanel, isEfficiencyOnTrack, isFactoryScopedRole, isFullMonthRange, isLegacyConfiguration, isPrefetchError, isRecentFlowVideoGridMetricMode, isSafari, isSupervisorRole, isTransitionPeriod, isUrlPermanentlyFailed, isValidFactoryViewConfiguration, isValidLineInfoPayload, isValidPrefetchParams, isValidPrefetchStatus, isValidWorkspaceDetailedMetricsPayload, isValidWorkspaceMetricsPayload, isWipGatedVideoGridMetricMode, isWorkspaceDisplayNamesLoaded, isWorkspaceDisplayNamesLoading, lineLeaderboardService, linesService, mergeWithDefaultConfig, migrateLegacyConfiguration, normalizeActionFamily, normalizeDateKeyRange, normalizeRoleLevel, normalizeVideoGridMetricMode, optifyeAgentClient, parseDateKeyToDate, parseS3Uri, preInitializeWorkspaceDisplayNames, preloadS3Video, preloadS3VideoUrl, preloadS3VideosUrl, preloadVideoUrl, preloadVideosUrl, qualityService, realtimeService, refreshWorkspaceDisplayNames, resetCoreMixpanel, resetFailedUrl, resetSubscriptionManager, s3VideoPreloader, setSentryUserContext, setSentryWorkspaceContext, shuffleArray, simulateApiDelay, skuService, startCoreSessionRecording, stopCoreSessionRecording, storeWorkspaceMapping, streamProxyConfig, subscribeWorkspaceDisplayNames, throttledReloadDashboard, toUrlFriendlyName, trackCoreEvent, trackCorePageView, transformToChartData, updateThreadTitle, upsertWorkspaceDisplayNameInCache, useAccessControl, useActiveBreaks, useActiveLineId, useAllWorkspaceMetrics, useAnalyticsConfig, useAppTimezone, useAudioService, useAuth, useAuthConfig, useAxelNotifications, useCanSaveTargets, useClipFilter, useClipTypes, useClipTypesWithCounts, useClipsInit, useCompanyClipsCost, useCompanyUsersUsage, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useDynamicShiftConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHasLineAccess, useHideMobileHeader, useHistoricWorkspaceMetrics, useHlsStream, useHlsStreamWithCropping, useHookOverride, useHourEndTimer, useHourlyTargetAchievements, useHourlyTargetMisses, useIdleTimeClipClassifications, useIdleTimeReasons, useIdleTimeVlmConfig, useKpiTrends, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineShiftConfig, useLineSupervisor, useLineWorkspaceMetrics, useLines, useMessages, useMetrics, useMobileMenu, useMonthlyTrend, useMultiLineShiftConfigs, useNavigation, useOperationalShiftKey, useOptionalSupabase, useOverrides, usePageOverride, usePrefetchClipCounts, useRealtimeLineMetrics, useRegistry, useSKUs, useSessionKeepAlive, useSessionTracking, useSessionTrackingContext, useShiftConfig, useShiftGroups, useShifts, useSubscriptionManager, useSubscriptionManagerSafe, useSupabase, useSupabaseClient, useSupervisorsByLineIds, useTargets, useTeamManagementPermissions, useTheme, useThemeConfig, useThreads, useTicketHistory, useTimezoneContext, useUserLineAccess, useUserUsage, useVideoConfig, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceHealthById, useWorkspaceHealthLastSeen, useWorkspaceHealthStatus, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, useWorkspaceUptimeTimeline, useWorkspaceVideoStreams, userService, videoPrefetchManager, videoPreloader, weeklyTopPerformerService, whatsappService, withAccessControl, withAuth, withRegistry, withTimezone, workspaceHealthService, workspaceService };
78764
+ export { ACTION_FAMILIES, ACTION_NAMES, AIAgentView_default as AIAgentView, AcceptInvite, AcceptInviteView_default as AcceptInviteView, AdvancedFilterDialog, AdvancedFilterPanel, AudioService, AuthCallback, AuthCallbackView_default as AuthCallbackView, AuthProvider, AuthService, AuthenticatedBottleneckClipsView, AuthenticatedFactoryView, AuthenticatedHelpView, AuthenticatedHomeView, AuthenticatedShiftsView, AuthenticatedTargetsView, AuthenticatedTicketsView, AuthenticatedWorkspaceHealthView, AvatarUpload, AxelNotificationPopup, AxelOrb, BackButton, BackButtonMinimal, BarChart, BaseHistoryCalendar, BottleneckClipsModal, BottleneckClipsView_default as BottleneckClipsView, BottlenecksContent, BreakNotificationPopup, CachePrefetchStatus, Card2 as Card, CardContent2 as CardContent, CardDescription2 as CardDescription, CardFooter2 as CardFooter, CardHeader2 as CardHeader, CardTitle2 as CardTitle, ChangeRoleDialog, ClipFilterProvider, ClipsCostView_default as ClipsCostView, CompactWorkspaceHealthCard, ConfirmRemoveUserDialog, CongratulationsOverlay, CroppedHlsVideoPlayer, CroppedVideoPlayer, CycleTimeChart, CycleTimeOverTimeChart, DEFAULT_ANALYTICS_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_CONFIG, DEFAULT_DATABASE_CONFIG, DEFAULT_DATE_TIME_CONFIG, DEFAULT_ENDPOINTS_CONFIG, DEFAULT_ENTITY_CONFIG, DEFAULT_HOME_VIEW_CONFIG, DEFAULT_MAP_VIEW_CONFIG, DEFAULT_SHIFT_CONFIG, DEFAULT_SHIFT_DATA, DEFAULT_THEME_CONFIG, DEFAULT_VIDEO_CONFIG, DEFAULT_WORKSPACE_CONFIG, DEFAULT_WORKSPACE_POSITIONS, DashboardHeader, DashboardLayout, DashboardOverridesProvider, DashboardProvider, DateDisplay_default as DateDisplay, DateTimeDisplay, DebugAuth, DebugAuthView_default as DebugAuthView, DetailedHealthStatus, DiagnosisVideoModal, EFFICIENCY_ON_TRACK_THRESHOLD, EmptyStateMessage, EncouragementOverlay, FactoryAssignmentDropdown, FactoryView_default as FactoryView, FileManagerFilters, FilterDialogTrigger, FirstTimeLoginDebug, FirstTimeLoginHandler, FittingTitle, GaugeChart, GridComponentsPlaceholder, HamburgerButton, Header, HealthDateShiftSelector, HealthStatusGrid, HealthStatusIndicator, HelpView_default as HelpView, HlsVideoPlayer, HomeView_default as HomeView, HourlyOutputChart2 as HourlyOutputChart, HourlyUptimeChart, ISTTimer_default as ISTTimer, IdleTimeVlmConfigProvider, ImprovementCenterView_default as ImprovementCenterView, InlineEditableText, InteractiveOnboardingTour, InvitationService, InvitationsTable, InviteUserDialog, KPICard, KPIDetailView_default as KPIDetailView, KPIGrid, KPIHeader, KPISection, KPIsOverviewView_default as KPIsOverviewView, LINE_1_UUID, LINE_2_UUID, LargeOutputProgressChart, LeaderboardDetailView_default as LeaderboardDetailView, Legend5 as Legend, LineAssignmentDropdown, LineChart, LineHistoryCalendar, LineMonthlyHistory, LineMonthlyPdfGenerator, LinePdfExportButton, LinePdfGenerator, LineWhatsAppShareButton, LinesService, LiveTimer, LoadingInline, LoadingOverlay_default as LoadingOverlay, LoadingPage_default as LoadingPage, LoadingSkeleton, LoadingState, LoginPage, LoginView_default as LoginView, Logo, MainLayout, MapGridView, MetricCard_default as MetricCard, MinimalOnboardingPopup, MobileMenuProvider, NewClipsNotification, NoWorkspaceData, OnboardingDemo, OnboardingTour, OptifyeAgentClient, OptifyeLogoLoader_default as OptifyeLogoLoader, OutputProgressChart, PageHeader, PieChart4 as PieChart, PlantHeadView_default as PlantHeadView, PlayPauseIndicator, PrefetchConfigurationError, PrefetchError, PrefetchEvents, PrefetchStatus, PrefetchTimeoutError, ProfileView_default as ProfileView, RegistryProvider, RoleBadge, S3ClipsSupabaseService as S3ClipsService, S3Service, SKUManagementView, SOPComplianceChart, SSEChatClient, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, SessionTracker, SessionTrackingContext, SessionTrackingProvider, SettingsPopup, ShiftDisplay_default as ShiftDisplay, ShiftsView_default as ShiftsView, SideNavBar, SignupWithInvitation, SilentErrorBoundary, SimpleOnboardingPopup, SingleVideoStream_default as SingleVideoStream, Skeleton, SubscriptionManager, SubscriptionManagerProvider, SupabaseProvider, SupervisorDropdown_default as SupervisorDropdown, SupervisorManagementView_default as SupervisorManagementView, SupervisorService, TargetWorkspaceGrid, TargetsView_default as TargetsView, TeamManagementView_default as TeamManagementView, ThreadSidebar, TicketHistory_default as TicketHistory, TicketHistoryService, TicketsView_default as TicketsView, TimeDisplay_default as TimeDisplay, TimePickerDropdown, Timer_default as Timer, TimezoneProvider, TimezoneService, UptimeDonutChart, UptimeLineChart, UptimeMetricCards, UserAvatar, UserManagementService, UserManagementTable, UserService, UserUsageDetailModal, UserUsageStats, VideoCard, VideoGridView, VideoPlayer, VideoPreloader, WORKSPACE_POSITIONS, WhatsAppShareButton, WorkspaceCard, WorkspaceCycleTimeMetricCards, WorkspaceDetailView_default as WorkspaceDetailView, WorkspaceDisplayNameExample, WorkspaceGrid, WorkspaceGridItem, WorkspaceHealthCard, WorkspaceHealthView_default as WorkspaceHealthView, WorkspaceHistoryCalendar, WorkspaceMetricCards, WorkspaceMetricCardsImpl, WorkspaceMonthlyDataFetcher, WorkspaceMonthlyHistory, WorkspaceMonthlyPdfGenerator, WorkspacePdfExportButton, WorkspacePdfGenerator, WorkspaceWhatsAppShareButton, actionService, aggregateKPIsFromLineMetricsRows, alertsService, apiUtils, areAllLinesOnSameShift, authCoreService, authOTPService, authRateLimitService, awardsService, buildDateKey, buildKPIsFromLineMetricsRow, buildShiftGroupsKey, canRoleAccessDashboardPath, canRoleAccessTeamManagement, canRoleAssignFactories, canRoleAssignLines, canRoleChangeRole, canRoleInviteRole, canRoleManageCompany, canRoleManageTargets, canRoleManageUsers, canRoleRemoveUser, canRoleViewClipsCost, canRoleViewUsageStats, captureSentryException, captureSentryMessage, checkRateLimit2 as checkRateLimit, clearAllRateLimits2 as clearAllRateLimits, clearRateLimit2 as clearRateLimit, clearS3VideoCache, clearS3VideoFromCache, clearSentryContext, clearWorkspaceDisplayNamesCache, cn, createDefaultKPIs, createInvitationService, createLinesService, createSessionTracker, createStorageService, createStreamProxyHandler, createSupabaseClient, createSupervisorService, createThrottledReload, createUserManagementService, createUserService, dashboardService, deleteThread, fetchIdleTimeReasons, filterDataByDateKeyRange, forceRefreshWorkspaceDisplayNames, formatAwardMonth, formatDateInZone, formatDateKeyForDisplay, formatDateTimeInZone, formatDuration2 as formatDuration, formatISTDate, formatIdleTime, formatRangeLabel, formatReasonLabel, formatRelativeTime, formatTimeInZone, fromUrlFriendlyName, getActionDisplayName, getAllLineDisplayNames, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAllWorkspaceDisplayNamesSnapshot, getAnonClient, getAssignableRoles, getAssignmentColumnLabel, getAvailableShiftIds, getAwardBadgeType, getAwardDescription, getAwardTitle, getBrowserName, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getConfiguredLineIds, getCoreSessionRecordingProperties, getCoreSessionReplayUrl, getCurrentShift, getCurrentShiftForLine, getCurrentTimeInZone, getCurrentWeekFullRange, getCurrentWeekToDateRange, getDashboardHeaderTimeInZone, getDateKeyFromDate, getDaysDifferenceInZone, getDefaultCameraStreamUrl, getDefaultLineId, getDefaultTabForWorkspace, getInitials, getLineDisplayName, getManufacturingInsights, getMetricsTablePrefix, getMonthKeyBounds, getMonthWeekRanges, getNextUpdateInterval, getOperationalDate, getRoleAssignmentKind, getRoleDescription, getRoleLabel, getRoleMetadata, getRoleNavPaths, getS3SignedUrl, getS3VideoSrc, getShiftData, getShiftNameById, getShiftWorkDurationSeconds, getShortShiftName, getShortWorkspaceDisplayName, getShortWorkspaceDisplayNameAsync, getStoredWorkspaceMappings, getSubscriptionManager, getThreadMessages, getUniformShiftGroup, getUserThreads, getUserThreadsPaginated, getVisibleRolesForCurrentUser, getWorkspaceDisplayName, getWorkspaceDisplayNameAsync, getWorkspaceDisplayNamesMap, getWorkspaceFromUrl, getWorkspaceNavigationParams, groupLinesByShift, hasAnyShiftData, identifyCoreUser, initializeCoreMixpanel, isEfficiencyOnTrack, isFactoryScopedRole, isFullMonthRange, isLegacyConfiguration, isLoopbackHostname, isPrefetchError, isRecentFlowVideoGridMetricMode, isSafari, isSupervisorRole, isTransitionPeriod, isUrlPermanentlyFailed, isValidFactoryViewConfiguration, isValidLineInfoPayload, isValidPrefetchParams, isValidPrefetchStatus, isValidWorkspaceDetailedMetricsPayload, isValidWorkspaceMetricsPayload, isWipGatedVideoGridMetricMode, isWorkspaceDisplayNamesLoaded, isWorkspaceDisplayNamesLoading, lineLeaderboardService, linesService, mergeWithDefaultConfig, migrateLegacyConfiguration, normalizeActionFamily, normalizeDateKeyRange, normalizeRoleLevel, normalizeVideoGridMetricMode, optifyeAgentClient, parseDateKeyToDate, parseS3Uri, preInitializeWorkspaceDisplayNames, preloadS3Video, preloadS3VideoUrl, preloadS3VideosUrl, preloadVideoUrl, preloadVideosUrl, qualityService, realtimeService, refreshWorkspaceDisplayNames, resetCoreMixpanel, resetFailedUrl, resetSubscriptionManager, s3VideoPreloader, setSentryUserContext, setSentryWorkspaceContext, shouldEnableLocalDevTestLogin, shuffleArray, simulateApiDelay, skuService, startCoreSessionRecording, stopCoreSessionRecording, storeWorkspaceMapping, streamProxyConfig, subscribeWorkspaceDisplayNames, throttledReloadDashboard, toUrlFriendlyName, trackCoreEvent, trackCorePageView, transformToChartData, updateThreadTitle, upsertWorkspaceDisplayNameInCache, useAccessControl, useActiveBreaks, useActiveLineId, useAllWorkspaceMetrics, useAnalyticsConfig, useAppTimezone, useAudioService, useAuth, useAuthConfig, useAxelNotifications, useCanSaveTargets, useClipFilter, useClipTypes, useClipTypesWithCounts, useClipsInit, useCompanyClipsCost, useCompanyUsersUsage, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useDynamicShiftConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHasLineAccess, useHideMobileHeader, useHistoricWorkspaceMetrics, useHlsStream, useHlsStreamWithCropping, useHookOverride, useHourEndTimer, useHourlyTargetAchievements, useHourlyTargetMisses, useIdleTimeClipClassifications, useIdleTimeReasons, useIdleTimeVlmConfig, useKpiTrends, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineShiftConfig, useLineSupervisor, useLineWorkspaceMetrics, useLines, useMessages, useMetrics, useMobileMenu, useMonthlyTrend, useMultiLineShiftConfigs, useNavigation, useOperationalShiftKey, useOptionalSupabase, useOverrides, usePageOverride, usePrefetchClipCounts, useRealtimeLineMetrics, useRegistry, useSKUs, useSessionKeepAlive, useSessionTracking, useSessionTrackingContext, useShiftConfig, useShiftGroups, useShifts, useSubscriptionManager, useSubscriptionManagerSafe, useSupabase, useSupabaseClient, useSupervisorsByLineIds, useTargets, useTeamManagementPermissions, useTheme, useThemeConfig, useThreads, useTicketHistory, useTimezoneContext, useUserLineAccess, useUserUsage, useVideoConfig, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceHealthById, useWorkspaceHealthLastSeen, useWorkspaceHealthStatus, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, useWorkspaceUptimeTimeline, useWorkspaceVideoStreams, userService, videoPrefetchManager, videoPreloader, weeklyTopPerformerService, whatsappService, withAccessControl, withAuth, withRegistry, withTimezone, workspaceHealthService, workspaceService };