@optifye/dashboard-core 6.11.14 → 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';
@@ -11742,6 +11742,9 @@ var toWorkspaceDetailedMetrics = ({
11742
11742
  const idealOutput = coerceNumber(data.ideal_output ?? data.ideal_output_until_now, 0);
11743
11743
  const outputDifference = totalActions - idealOutput;
11744
11744
  const hourlyCycleTimes = Array.isArray(data.hourly_cycle_times) ? data.hourly_cycle_times.map((value) => coerceNumber(value, 0)) : [];
11745
+ const cycleCompletionClipCount = data.cycle_completion_clip_count === null || data.cycle_completion_clip_count === void 0 ? null : coerceNumber(data.cycle_completion_clip_count, 0);
11746
+ const cycleTimeDataStatus = data.cycle_time_data_status === "missing_clips" ? "missing_clips" : data.cycle_time_data_status === "available" ? "available" : null;
11747
+ const cycleTimeTimezone = typeof data.cycle_time_timezone === "string" ? data.cycle_time_timezone : null;
11745
11748
  const totalWorkspacesValue = coerceNumber(
11746
11749
  data.total_workspaces ?? lineMetricsById?.[data.line_id || ""]?.total_workspaces ?? workspaceConfig.totalWorkspaces,
11747
11750
  0
@@ -11789,6 +11792,9 @@ var toWorkspaceDetailedMetrics = ({
11789
11792
  total_actions: totalActions,
11790
11793
  hourly_action_counts: hourlyActionCounts,
11791
11794
  hourly_cycle_times: hourlyCycleTimes,
11795
+ cycle_completion_clip_count: cycleCompletionClipCount,
11796
+ cycle_time_data_status: cycleTimeDataStatus,
11797
+ cycle_time_timezone: cycleTimeTimezone,
11792
11798
  workspace_rank: coerceNumber(data.workspace_rank, 0),
11793
11799
  total_workspaces: totalWorkspacesValue,
11794
11800
  ideal_output_until_now: idealOutput,
@@ -12829,6 +12835,7 @@ var useShiftGroups = ({
12829
12835
  }) => {
12830
12836
  const [shiftGroups, setShiftGroups] = useState([]);
12831
12837
  const [shiftGroupsKey, setShiftGroupsKey] = useState("");
12838
+ const [hasComputed, setHasComputed] = useState(false);
12832
12839
  const lastKeyRef = useRef("");
12833
12840
  const mapRef = useRef(shiftConfigMap);
12834
12841
  useEffect(() => {
@@ -12839,6 +12846,7 @@ var useShiftGroups = ({
12839
12846
  lastKeyRef.current = "";
12840
12847
  setShiftGroups([]);
12841
12848
  setShiftGroupsKey("");
12849
+ setHasComputed(false);
12842
12850
  return;
12843
12851
  }
12844
12852
  let isMounted = true;
@@ -12851,6 +12859,7 @@ var useShiftGroups = ({
12851
12859
  setShiftGroups(groups);
12852
12860
  setShiftGroupsKey(key);
12853
12861
  }
12862
+ setHasComputed(true);
12854
12863
  };
12855
12864
  compute();
12856
12865
  const intervalId = setInterval(compute, pollIntervalMs);
@@ -12859,7 +12868,7 @@ var useShiftGroups = ({
12859
12868
  clearInterval(intervalId);
12860
12869
  };
12861
12870
  }, [enabled, shiftConfigMap.size, timezone, pollIntervalMs]);
12862
- return { shiftGroups, shiftGroupsKey };
12871
+ return { shiftGroups, shiftGroupsKey, hasComputed };
12863
12872
  };
12864
12873
 
12865
12874
  // src/lib/types/efficiencyLegend.ts
@@ -12921,52 +12930,6 @@ function getEfficiencyTextColorClasses(efficiency, legend = DEFAULT_EFFICIENCY_L
12921
12930
  }
12922
12931
  }
12923
12932
 
12924
- // src/lib/hooks/useDashboardMetrics.recentFlow.ts
12925
- var isFiniteNumber = (value) => typeof value === "number" && Number.isFinite(value);
12926
- var getWorkspaceRecentFlowCacheKey = (workspace) => {
12927
- const workspaceKey = workspace.workspace_uuid || workspace.workspace_name || "unknown";
12928
- return `${workspaceKey}|${workspace.date}|${workspace.shift_id}`;
12929
- };
12930
- var toRecentFlowSnapshot = (workspace) => {
12931
- if (!isFiniteNumber(workspace.recent_flow_percent)) {
12932
- return null;
12933
- }
12934
- return {
12935
- recent_flow_percent: workspace.recent_flow_percent,
12936
- recent_flow_actual_rate_pph: workspace.recent_flow_actual_rate_pph ?? null,
12937
- recent_flow_healthy_rate_pph: workspace.recent_flow_healthy_rate_pph ?? null,
12938
- recent_flow_window_minutes: workspace.recent_flow_window_minutes ?? null,
12939
- recent_flow_effective_end_at: workspace.recent_flow_effective_end_at ?? null
12940
- };
12941
- };
12942
- var mergeWorkspaceRecentFlowMetrics = (workspaces, previousCache) => {
12943
- const nextCache = /* @__PURE__ */ new Map();
12944
- const mergedWorkspaces = workspaces.map((workspace) => {
12945
- const cacheKey = getWorkspaceRecentFlowCacheKey(workspace);
12946
- const currentSnapshot = toRecentFlowSnapshot(workspace);
12947
- if (workspace.recent_flow_mode === "computed" && currentSnapshot) {
12948
- nextCache.set(cacheKey, currentSnapshot);
12949
- return workspace;
12950
- }
12951
- if (workspace.recent_flow_mode === "hold") {
12952
- const cachedSnapshot = previousCache.get(cacheKey);
12953
- if (cachedSnapshot) {
12954
- nextCache.set(cacheKey, cachedSnapshot);
12955
- return {
12956
- ...workspace,
12957
- ...cachedSnapshot,
12958
- recent_flow_mode: "hold"
12959
- };
12960
- }
12961
- }
12962
- return workspace;
12963
- });
12964
- return {
12965
- workspaces: mergedWorkspaces,
12966
- cache: nextCache
12967
- };
12968
- };
12969
-
12970
12933
  // src/lib/hooks/useDashboardMetrics.ts
12971
12934
  var DEBUG_DASHBOARD_LOGS = process.env.NEXT_PUBLIC_DEBUG_DASHBOARD === "true";
12972
12935
  var logDebug = (...args) => {
@@ -13055,7 +13018,6 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
13055
13018
  const abortControllerRef = useRef(null);
13056
13019
  const lastFetchKeyRef = useRef(null);
13057
13020
  const inFlightFetchKeyRef = useRef(null);
13058
- const recentFlowCacheRef = useRef(/* @__PURE__ */ new Map());
13059
13021
  const updateQueueRef = useRef(false);
13060
13022
  const onLineMetricsUpdateRef = useRef(onLineMetricsUpdate);
13061
13023
  const shiftGroupsRef = useRef(shiftGroups);
@@ -13089,7 +13051,6 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
13089
13051
  setError(null);
13090
13052
  lastFetchKeyRef.current = null;
13091
13053
  inFlightFetchKeyRef.current = null;
13092
- recentFlowCacheRef.current = /* @__PURE__ */ new Map();
13093
13054
  }, [lineId]);
13094
13055
  const fetchAllMetrics = useCallback(async (options = {}) => {
13095
13056
  const { force = false } = options;
@@ -13364,12 +13325,9 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
13364
13325
  actionType: item.action_type,
13365
13326
  actionName: item.action_name
13366
13327
  }),
13367
- recent_flow_mode: item.recent_flow_mode ?? void 0,
13368
13328
  recent_flow_percent: item.recent_flow_percent ?? null,
13369
- recent_flow_actual_rate_pph: item.recent_flow_actual_rate_pph ?? null,
13370
- recent_flow_healthy_rate_pph: item.recent_flow_healthy_rate_pph ?? null,
13371
- recent_flow_window_minutes: item.recent_flow_window_minutes ?? null,
13372
13329
  recent_flow_effective_end_at: item.recent_flow_effective_end_at ?? null,
13330
+ recent_flow_computed_at: item.recent_flow_computed_at ?? null,
13373
13331
  incoming_wip_current: item.incoming_wip_current ?? null,
13374
13332
  incoming_wip_effective_at: item.incoming_wip_effective_at ?? null,
13375
13333
  incoming_wip_buffer_name: item.incoming_wip_buffer_name ?? null
@@ -13380,16 +13338,11 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
13380
13338
  const wsNumB = parseInt(b.workspace_name?.replace(/[^0-9]/g, "") || "0");
13381
13339
  return wsNumA - wsNumB;
13382
13340
  });
13383
- const {
13384
- workspaces: mergedWorkspaceData,
13385
- cache: nextRecentFlowCache
13386
- } = mergeWorkspaceRecentFlowMetrics(transformedWorkspaceData, recentFlowCacheRef.current);
13387
- recentFlowCacheRef.current = nextRecentFlowCache;
13388
- mergedWorkspaceData.forEach((metric) => {
13341
+ transformedWorkspaceData.forEach((metric) => {
13389
13342
  workspaceMetricsStore.setOverview(metric);
13390
13343
  });
13391
13344
  const newMetricsState = {
13392
- workspaceMetrics: mergedWorkspaceData,
13345
+ workspaceMetrics: transformedWorkspaceData,
13393
13346
  lineMetrics: allLineMetrics || [],
13394
13347
  metadata: { hasFlowBuffers, idleTimeVlmByLine },
13395
13348
  efficiencyLegend: efficiencyLegend ?? DEFAULT_EFFICIENCY_LEGEND
@@ -16814,7 +16767,7 @@ var useActiveBreaks = (lineIds) => {
16814
16767
  const [isLoading, setIsLoading] = useState(true);
16815
16768
  const [error, setError] = useState(null);
16816
16769
  const supabase = useSupabase();
16817
- const parseTimeToMinutes3 = (timeStr) => {
16770
+ const parseTimeToMinutes4 = (timeStr) => {
16818
16771
  const [hours, minutes] = timeStr.split(":").map(Number);
16819
16772
  return hours * 60 + minutes;
16820
16773
  };
@@ -16823,8 +16776,8 @@ var useActiveBreaks = (lineIds) => {
16823
16776
  return now4.getHours() * 60 + now4.getMinutes();
16824
16777
  };
16825
16778
  const isTimeInBreak = (breakStart, breakEnd, currentMinutes) => {
16826
- const startMinutes = parseTimeToMinutes3(breakStart);
16827
- const endMinutes = parseTimeToMinutes3(breakEnd);
16779
+ const startMinutes = parseTimeToMinutes4(breakStart);
16780
+ const endMinutes = parseTimeToMinutes4(breakEnd);
16828
16781
  if (endMinutes < startMinutes) {
16829
16782
  return currentMinutes >= startMinutes || currentMinutes < endMinutes;
16830
16783
  } else {
@@ -16832,8 +16785,8 @@ var useActiveBreaks = (lineIds) => {
16832
16785
  }
16833
16786
  };
16834
16787
  const calculateBreakProgress = (breakStart, breakEnd, currentMinutes) => {
16835
- const startMinutes = parseTimeToMinutes3(breakStart);
16836
- const endMinutes = parseTimeToMinutes3(breakEnd);
16788
+ const startMinutes = parseTimeToMinutes4(breakStart);
16789
+ const endMinutes = parseTimeToMinutes4(breakEnd);
16837
16790
  let elapsedMinutes = 0;
16838
16791
  let remainingMinutes = 0;
16839
16792
  if (endMinutes < startMinutes) {
@@ -16851,8 +16804,8 @@ var useActiveBreaks = (lineIds) => {
16851
16804
  return { elapsedMinutes, remainingMinutes };
16852
16805
  };
16853
16806
  const isTimeInShift = (startTime, endTime, currentMinutes) => {
16854
- const startMinutes = parseTimeToMinutes3(startTime);
16855
- const endMinutes = parseTimeToMinutes3(endTime);
16807
+ const startMinutes = parseTimeToMinutes4(startTime);
16808
+ const endMinutes = parseTimeToMinutes4(endTime);
16856
16809
  if (endMinutes < startMinutes) {
16857
16810
  return currentMinutes >= startMinutes || currentMinutes < endMinutes;
16858
16811
  } else {
@@ -16912,8 +16865,8 @@ var useActiveBreaks = (lineIds) => {
16912
16865
  const endTime = breakItem.end || breakItem.endTime || "00:00";
16913
16866
  let duration = breakItem.duration || 0;
16914
16867
  if (!duration || duration === 0) {
16915
- const startMinutes = parseTimeToMinutes3(startTime);
16916
- const endMinutes = parseTimeToMinutes3(endTime);
16868
+ const startMinutes = parseTimeToMinutes4(startTime);
16869
+ const endMinutes = parseTimeToMinutes4(endTime);
16917
16870
  duration = endMinutes < startMinutes ? endMinutes + 24 * 60 - startMinutes : endMinutes - startMinutes;
16918
16871
  }
16919
16872
  return {
@@ -16929,8 +16882,8 @@ var useActiveBreaks = (lineIds) => {
16929
16882
  const endTime = breakItem.end || breakItem.endTime || "00:00";
16930
16883
  let duration = breakItem.duration || 0;
16931
16884
  if (!duration || duration === 0) {
16932
- const startMinutes = parseTimeToMinutes3(startTime);
16933
- const endMinutes = parseTimeToMinutes3(endTime);
16885
+ const startMinutes = parseTimeToMinutes4(startTime);
16886
+ const endMinutes = parseTimeToMinutes4(endTime);
16934
16887
  duration = endMinutes < startMinutes ? endMinutes + 24 * 60 - startMinutes : endMinutes - startMinutes;
16935
16888
  }
16936
16889
  return {
@@ -23011,6 +22964,16 @@ var createThrottledReload = (interval = 5e3, maxReloads = 3) => {
23011
22964
  };
23012
22965
  var throttledReloadDashboard = createThrottledReload(5e3, 3);
23013
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
+
23014
22977
  // src/lib/utils/index.ts
23015
22978
  var formatIdleTime = (idleTimeInSeconds) => {
23016
22979
  if (!idleTimeInSeconds || idleTimeInSeconds <= 0) {
@@ -31195,12 +31158,16 @@ var LoginPage = ({
31195
31158
  onRateLimitCheck,
31196
31159
  logoSrc = optifye_logo_default,
31197
31160
  logoAlt = "Optifye",
31198
- brandName = "Optifye"
31161
+ brandName = "Optifye",
31162
+ showDevTestLogin = false,
31163
+ devTestLoginLabel = "Sign in as Test User",
31164
+ onDevTestLogin
31199
31165
  }) => {
31200
31166
  const [email, setEmail] = useState("");
31201
31167
  const [otp, setOtp] = useState("");
31202
31168
  const [step, setStep] = useState("email");
31203
31169
  const [loading, setLoading] = useState(false);
31170
+ const [devLoginLoading, setDevLoginLoading] = useState(false);
31204
31171
  const [error, setError] = useState(null);
31205
31172
  const [countdown, setCountdown] = useState(0);
31206
31173
  const supabase = useSupabase();
@@ -31264,6 +31231,25 @@ var LoginPage = ({
31264
31231
  startCountdown();
31265
31232
  }
31266
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
+ };
31267
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: [
31268
31254
  /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-2xl shadow-xl border border-slate-200 p-8", children: [
31269
31255
  /* @__PURE__ */ jsxs("div", { className: "text-center mb-8", children: [
@@ -31304,7 +31290,7 @@ var LoginPage = ({
31304
31290
  "button",
31305
31291
  {
31306
31292
  type: "submit",
31307
- disabled: loading,
31293
+ disabled: loading || devLoginLoading,
31308
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",
31309
31295
  children: loading ? /* @__PURE__ */ jsxs(Fragment, { children: [
31310
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: [
@@ -31314,7 +31300,31 @@ var LoginPage = ({
31314
31300
  "Sending..."
31315
31301
  ] }) : "Continue with Email"
31316
31302
  }
31317
- )
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
31318
31328
  ] }) : /* @__PURE__ */ jsxs("form", { className: "space-y-6", onSubmit: handleVerifyOTP, children: [
31319
31329
  /* @__PURE__ */ jsxs("div", { children: [
31320
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" }),
@@ -31339,7 +31349,7 @@ var LoginPage = ({
31339
31349
  "button",
31340
31350
  {
31341
31351
  type: "submit",
31342
- disabled: loading || otp.length !== 6,
31352
+ disabled: loading || devLoginLoading || otp.length !== 6,
31343
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",
31344
31354
  children: loading ? /* @__PURE__ */ jsxs(Fragment, { children: [
31345
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: [
@@ -32180,31 +32190,35 @@ var LineChartComponent = ({
32180
32190
  ...restOfChartProps
32181
32191
  }) => {
32182
32192
  const containerRef = React141__default.useRef(null);
32183
- const [containerReady, setContainerReady] = React141__default.useState(false);
32184
- const themeConfig = useThemeConfig();
32185
- const { formatNumber } = useFormatNumber();
32193
+ const [dimensions, setDimensions] = React141__default.useState({ width: 0, height: 0 });
32194
+ const [hasValidData, setHasValidData] = React141__default.useState(false);
32186
32195
  React141__default.useEffect(() => {
32187
- const checkContainerDimensions = () => {
32188
- if (containerRef.current) {
32189
- const rect = containerRef.current.getBoundingClientRect();
32190
- if (rect.width > 0 && rect.height > 0) {
32191
- setContainerReady(true);
32192
- }
32193
- }
32194
- };
32195
- checkContainerDimensions();
32196
- const resizeObserver = new ResizeObserver(checkContainerDimensions);
32197
- if (containerRef.current) {
32198
- 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);
32199
32204
  }
32200
- const fallbackTimeout = setTimeout(() => {
32201
- setContainerReady(true);
32202
- }, 100);
32203
- return () => {
32204
- resizeObserver.disconnect();
32205
- clearTimeout(fallbackTimeout);
32206
- };
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();
32207
32219
  }, []);
32220
+ const themeConfig = useThemeConfig();
32221
+ const { formatNumber } = useFormatNumber();
32208
32222
  const yAxisTickFormatter = (value) => {
32209
32223
  return `${formatNumber(value)}${yAxisUnit || ""}`;
32210
32224
  };
@@ -32226,57 +32240,71 @@ var LineChartComponent = ({
32226
32240
  const gridStrokeColor = themeConfig?.gray?.["300"] || "#ccc";
32227
32241
  const axisTickFillColor = themeConfig?.gray?.["600"] || "#666";
32228
32242
  const axisStrokeColor = themeConfig?.gray?.["400"] || "#999";
32229
- const chartContent = /* @__PURE__ */ jsxs(LineChart$1, { data, margin: { top: 5, right: 30, left: 20, bottom: 20 }, ...restOfChartProps, children: [
32230
- showGrid && /* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", stroke: gridStrokeColor }),
32231
- /* @__PURE__ */ jsx(
32232
- XAxis,
32233
- {
32234
- dataKey: xAxisDataKey,
32235
- label: xAxisLabel ? { value: xAxisLabel, position: "insideBottom", offset: -10 } : void 0,
32236
- tickFormatter: xAxisTickFormatter,
32237
- tick: { fontSize: 12, fill: axisTickFillColor },
32238
- stroke: axisStrokeColor
32239
- }
32240
- ),
32241
- /* @__PURE__ */ jsx(
32242
- YAxis,
32243
- {
32244
- label: yAxisLabel ? { value: yAxisLabel, angle: -90, position: "insideLeft" } : void 0,
32245
- tickFormatter: yAxisTickFormatter,
32246
- domain: yAxisDomain,
32247
- tick: { fontSize: 12, fill: axisTickFillColor },
32248
- stroke: axisStrokeColor
32249
- }
32250
- ),
32251
- showTooltip && /* @__PURE__ */ jsx(
32252
- Tooltip,
32253
- {
32254
- formatter: tooltipFormatter || defaultTooltipFormatter,
32255
- labelFormatter: tooltipLabelFormatter,
32256
- itemStyle: { color: "#111827" },
32257
- cursor: { strokeDasharray: "3 3" }
32258
- }
32259
- ),
32260
- showLegend && /* @__PURE__ */ jsx(Legend, { payload: legendPayload }),
32261
- lines.map((lineConfig, index) => {
32262
- const lineProps = {
32263
- ...lineConfig,
32264
- key: lineConfig.dataKey,
32265
- type: lineConfig.type || "monotone",
32266
- stroke: lineConfig.stroke || defaultColors[index % defaultColors.length],
32267
- activeDot: lineConfig.activeDot !== void 0 ? lineConfig.activeDot : { r: 6 }
32268
- };
32269
- return /* @__PURE__ */ jsx(Line, { ...lineProps, children: lineConfig.labelList && /* @__PURE__ */ jsx(
32270
- LabelList,
32271
- {
32272
- dataKey: lineConfig.dataKey,
32273
- position: "top",
32274
- formatter: (value) => formatNumber(value),
32275
- ...typeof lineConfig.labelList === "object" ? lineConfig.labelList : {}
32276
- }
32277
- ) });
32278
- })
32279
- ] });
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
+ );
32280
32308
  if (responsive) {
32281
32309
  return /* @__PURE__ */ jsx(
32282
32310
  "div",
@@ -32284,11 +32312,20 @@ var LineChartComponent = ({
32284
32312
  ref: containerRef,
32285
32313
  className: clsx(fillContainer ? "w-full h-full" : "w-full h-auto", className),
32286
32314
  style: fillContainer ? { height: "100%", minHeight: "50px", minWidth: "100px" } : { aspectRatio: `${aspect}/1`, minHeight: "50px", minWidth: "100px" },
32287
- 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
+ )
32288
32325
  }
32289
32326
  );
32290
32327
  }
32291
- 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) });
32292
32329
  };
32293
32330
  var LineChart = React141__default.memo(LineChartComponent, (prevProps, nextProps) => {
32294
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)) {
@@ -32556,14 +32593,35 @@ var CycleTimeOverTimeChart = ({
32556
32593
  }) => {
32557
32594
  const MAX_DATA_POINTS = 40;
32558
32595
  const containerRef = React141__default.useRef(null);
32559
- const [containerReady, setContainerReady] = React141__default.useState(false);
32560
- 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) => {
32561
32619
  const [hours, minutes] = value.split(":").map(Number);
32562
32620
  if (!Number.isFinite(hours) || !Number.isFinite(minutes)) return 0;
32563
32621
  return hours * 60 + minutes;
32564
32622
  };
32565
32623
  const formatHourLabel = (slotIndex) => {
32566
- const baseMinutes = parseTimeToMinutes3(shiftStart);
32624
+ const baseMinutes = parseTimeToMinutes4(shiftStart);
32567
32625
  const absoluteMinutes = baseMinutes + slotIndex * 60;
32568
32626
  const hour24 = Math.floor(absoluteMinutes % (24 * 60) / 60);
32569
32627
  const ampm = hour24 >= 12 ? "PM" : "AM";
@@ -32582,52 +32640,7 @@ var CycleTimeOverTimeChart = ({
32582
32640
  const displayData = getDisplayData(data);
32583
32641
  const DURATION = displayData.length;
32584
32642
  const effectiveDatasetKey = datasetKey || `cycle-time:${xAxisMode}`;
32585
- const [animatedDatasetKey, setAnimatedDatasetKey] = React141__default.useState(null);
32586
- const shouldAnimate = animatedDatasetKey !== effectiveDatasetKey;
32587
- const handleAnimationEnd = React141__default.useCallback(() => {
32588
- setAnimatedDatasetKey((currentValue) => currentValue === effectiveDatasetKey ? currentValue : effectiveDatasetKey);
32589
- }, [effectiveDatasetKey]);
32590
32643
  const finalData = displayData;
32591
- React141__default.useEffect(() => {
32592
- const containerNode = containerRef.current;
32593
- if (!containerNode) {
32594
- setContainerReady(true);
32595
- return void 0;
32596
- }
32597
- let frameId = null;
32598
- let resizeObserver = null;
32599
- const checkContainerDimensions = () => {
32600
- const rect = containerNode.getBoundingClientRect();
32601
- const isReady = rect.width > 0 && rect.height > 0;
32602
- if (isReady) {
32603
- setContainerReady(true);
32604
- }
32605
- return isReady;
32606
- };
32607
- if (checkContainerDimensions()) {
32608
- return void 0;
32609
- }
32610
- frameId = window.requestAnimationFrame(() => {
32611
- checkContainerDimensions();
32612
- });
32613
- if (typeof ResizeObserver !== "undefined") {
32614
- resizeObserver = new ResizeObserver(() => {
32615
- if (checkContainerDimensions() && resizeObserver) {
32616
- resizeObserver.disconnect();
32617
- resizeObserver = null;
32618
- }
32619
- });
32620
- resizeObserver.observe(containerNode);
32621
- } else {
32622
- setContainerReady(true);
32623
- }
32624
- return () => {
32625
- if (frameId !== null) {
32626
- window.cancelAnimationFrame(frameId);
32627
- }
32628
- resizeObserver?.disconnect();
32629
- };
32630
- }, []);
32631
32644
  const labelInterval = React141__default.useMemo(() => {
32632
32645
  if (xAxisMode === "hourly") {
32633
32646
  return Math.max(1, Math.ceil(DURATION / 8));
@@ -32669,16 +32682,162 @@ var CycleTimeOverTimeChart = ({
32669
32682
  return `${minutes} minutes ${seconds} seconds ago`;
32670
32683
  }
32671
32684
  };
32685
+ const getNumericValue = React141__default.useCallback((value) => typeof value === "number" && Number.isFinite(value) ? value : null, []);
32686
+ const renderChartTooltip = React141__default.useCallback((tooltipProps) => {
32687
+ const { active, payload } = tooltipProps;
32688
+ if (!active || !Array.isArray(payload) || payload.length === 0) {
32689
+ return null;
32690
+ }
32691
+ const visibleEntries = payload.filter((entry) => getNumericValue(entry.value) !== null);
32692
+ if (!visibleEntries.length) {
32693
+ return null;
32694
+ }
32695
+ return /* @__PURE__ */ jsxs(
32696
+ "div",
32697
+ {
32698
+ style: {
32699
+ backgroundColor: "white",
32700
+ border: "none",
32701
+ borderRadius: "8px",
32702
+ boxShadow: "0 4px 12px rgba(0,0,0,0.1)",
32703
+ padding: "8px 12px",
32704
+ fontSize: "13px"
32705
+ },
32706
+ children: [
32707
+ /* @__PURE__ */ jsx(
32708
+ "div",
32709
+ {
32710
+ style: {
32711
+ color: "#374151",
32712
+ fontWeight: 600,
32713
+ marginBottom: "4px"
32714
+ },
32715
+ children: payload[0]?.payload?.tooltip || ""
32716
+ }
32717
+ ),
32718
+ visibleEntries.map((entry) => {
32719
+ const numericValue = getNumericValue(entry.value);
32720
+ if (numericValue === null) {
32721
+ return null;
32722
+ }
32723
+ return /* @__PURE__ */ jsx(
32724
+ "div",
32725
+ {
32726
+ style: {
32727
+ color: "#4B5563",
32728
+ padding: "2px 0"
32729
+ },
32730
+ children: entry.name === "idleMinutes" ? `Idle Time: ${numericValue.toFixed(0)} minutes` : `Cycle Time: ${numericValue.toFixed(1)} seconds`
32731
+ },
32732
+ `${entry.name}-${numericValue}`
32733
+ );
32734
+ })
32735
+ ]
32736
+ }
32737
+ );
32738
+ }, [getNumericValue]);
32739
+ const renderCycleDot = React141__default.useCallback((props) => {
32740
+ const { cx: cx2, cy, payload } = props;
32741
+ const cycleTime = getNumericValue(payload?.cycleTime);
32742
+ if (cycleTime === null) {
32743
+ return /* @__PURE__ */ jsx("g", {});
32744
+ }
32745
+ return /* @__PURE__ */ jsx(
32746
+ "circle",
32747
+ {
32748
+ cx: cx2,
32749
+ cy,
32750
+ r: 4,
32751
+ fill: cycleTime <= idealCycleTime ? "#00AB45" : "#E34329",
32752
+ stroke: "#fff",
32753
+ strokeWidth: 1,
32754
+ style: {
32755
+ filter: "brightness(1)",
32756
+ transition: "filter 0.3s ease, transform 0.3s ease",
32757
+ cursor: "pointer"
32758
+ },
32759
+ onMouseEnter: (e) => {
32760
+ const target = e.target;
32761
+ target.style.filter = "brightness(1.2)";
32762
+ target.style.transform = "scale(1.2)";
32763
+ },
32764
+ onMouseLeave: (e) => {
32765
+ const target = e.target;
32766
+ target.style.filter = "brightness(1)";
32767
+ target.style.transform = "scale(1)";
32768
+ }
32769
+ }
32770
+ );
32771
+ }, [getNumericValue, idealCycleTime]);
32772
+ const renderCycleActiveDot = React141__default.useCallback((props) => {
32773
+ const { cx: cx2, cy, payload } = props;
32774
+ const cycleTime = getNumericValue(payload?.cycleTime);
32775
+ if (cycleTime === null) {
32776
+ return /* @__PURE__ */ jsx("g", {});
32777
+ }
32778
+ return /* @__PURE__ */ jsx(
32779
+ "circle",
32780
+ {
32781
+ cx: cx2,
32782
+ cy,
32783
+ r: 6,
32784
+ fill: cycleTime <= idealCycleTime ? "#00AB45" : "#E34329",
32785
+ stroke: "#fff",
32786
+ strokeWidth: 2,
32787
+ style: {
32788
+ filter: "drop-shadow(0 0 2px rgba(0,0,0,0.2))"
32789
+ }
32790
+ }
32791
+ );
32792
+ }, [getNumericValue, idealCycleTime]);
32793
+ const renderIdleDot = React141__default.useCallback((props) => {
32794
+ const { cx: cx2, cy, payload } = props;
32795
+ const idleMinutes = getNumericValue(payload?.idleMinutes);
32796
+ if (idleMinutes === null) {
32797
+ return /* @__PURE__ */ jsx("g", {});
32798
+ }
32799
+ return /* @__PURE__ */ jsx(
32800
+ "circle",
32801
+ {
32802
+ cx: cx2,
32803
+ cy,
32804
+ r: 4,
32805
+ fill: "#f59e0b",
32806
+ stroke: "#fff",
32807
+ strokeWidth: 1
32808
+ }
32809
+ );
32810
+ }, [getNumericValue]);
32811
+ const renderIdleActiveDot = React141__default.useCallback((props) => {
32812
+ const { cx: cx2, cy, payload } = props;
32813
+ const idleMinutes = getNumericValue(payload?.idleMinutes);
32814
+ if (idleMinutes === null) {
32815
+ return /* @__PURE__ */ jsx("g", {});
32816
+ }
32817
+ return /* @__PURE__ */ jsx(
32818
+ "circle",
32819
+ {
32820
+ cx: cx2,
32821
+ cy,
32822
+ r: 6,
32823
+ fill: "#f59e0b",
32824
+ stroke: "#fff",
32825
+ strokeWidth: 2
32826
+ }
32827
+ );
32828
+ }, [getNumericValue]);
32672
32829
  const chartData = React141__default.useMemo(() => Array.from({ length: DURATION }, (_, i) => {
32830
+ const cycleTime = getNumericValue(finalData[i]);
32831
+ const idleMinutes = showIdleTime ? getNumericValue(idleTimeData[i]) : null;
32673
32832
  return {
32674
32833
  timeIndex: i,
32675
32834
  label: formatTimeLabel(i),
32676
32835
  tooltip: formatTooltipTime(i),
32677
- cycleTime: finalData[i] || 0,
32678
- idleMinutes: showIdleTime && idleTimeData && idleTimeData[i] || 0,
32679
- color: (finalData[i] || 0) <= idealCycleTime ? "#00AB45" : "#E34329"
32836
+ cycleTime,
32837
+ idleMinutes,
32838
+ color: cycleTime !== null && cycleTime <= idealCycleTime ? "#00AB45" : "#E34329"
32680
32839
  };
32681
- }), [DURATION, finalData, showIdleTime, idleTimeData, idealCycleTime]);
32840
+ }), [DURATION, finalData, showIdleTime, idleTimeData, idealCycleTime, getNumericValue]);
32682
32841
  const renderLegend = () => {
32683
32842
  if (!showIdleTime) return null;
32684
32843
  return /* @__PURE__ */ jsx("div", { className: "flex items-center justify-start text-[10px] font-bold text-gray-500 mb-6 tracking-[0.05em] gap-5", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
@@ -32689,215 +32848,154 @@ var CycleTimeOverTimeChart = ({
32689
32848
  return /* @__PURE__ */ jsxs(
32690
32849
  "div",
32691
32850
  {
32692
- ref: containerRef,
32693
32851
  className: `w-full h-full min-w-0 flex flex-col relative pb-2 ${className}`,
32694
32852
  style: { minHeight: "200px", minWidth: 0 },
32695
32853
  children: [
32696
32854
  renderLegend(),
32697
- /* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 w-full", children: containerReady ? /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
32698
- LineChart$1,
32855
+ /* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 w-full", ref: containerRef, children: /* @__PURE__ */ jsx(
32856
+ motion.div,
32699
32857
  {
32700
- data: chartData,
32701
- margin: {
32702
- top: 5,
32703
- right: 30,
32704
- bottom: 25,
32705
- left: 10
32706
- },
32707
- children: [
32708
- /* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", vertical: false }),
32709
- /* @__PURE__ */ jsx(
32710
- XAxis,
32711
- {
32712
- dataKey: "label",
32713
- tick: { fontSize: 11 },
32714
- interval: 0,
32715
- angle: xAxisMode === "hourly" ? 0 : -30,
32716
- textAnchor: xAxisMode === "hourly" ? "middle" : "end",
32717
- tickMargin: xAxisMode === "hourly" ? 8 : 15,
32718
- height: xAxisMode === "hourly" ? 40 : 60
32719
- }
32720
- ),
32721
- /* @__PURE__ */ jsx(
32722
- YAxis,
32723
- {
32724
- tickMargin: 8,
32725
- width: 45,
32726
- yAxisId: "cycle",
32727
- domain: ["auto", "auto"],
32728
- ticks: [0, idealCycleTime, ...Array.from({ length: 4 }, (_, i) => (i + 1) * Math.ceil(idealCycleTime / 2))].sort((a, b) => a - b),
32729
- tickFormatter: (value) => String(value),
32730
- tick: (props) => {
32731
- const { x, y, payload } = props;
32732
- const displayValue = typeof payload.value === "number" ? payload.value.toFixed(1) : String(payload.value);
32733
- return /* @__PURE__ */ jsx("g", { transform: `translate(${x},${y})`, children: /* @__PURE__ */ jsx(
32734
- "text",
32735
- {
32736
- x: 0,
32737
- y: 0,
32738
- dy: 4,
32739
- textAnchor: "end",
32740
- fill: payload.value === idealCycleTime ? "#E34329" : "#666",
32741
- fontSize: 12,
32742
- fontWeight: payload.value === idealCycleTime ? "bold" : "normal",
32743
- children: displayValue
32744
- },
32745
- `tick-${payload.value}-${x}-${y}`
32746
- ) });
32747
- }
32748
- }
32749
- ),
32750
- showIdleTime && /* @__PURE__ */ jsx(
32751
- YAxis,
32752
- {
32753
- yAxisId: "idle",
32754
- orientation: "right",
32755
- tickMargin: 8,
32756
- width: 35,
32757
- domain: [0, 60],
32758
- tickFormatter: (value) => `${value}m`,
32759
- tick: { fontSize: 11, fill: "#f59e0b" },
32760
- axisLine: false,
32761
- tickLine: false
32762
- }
32763
- ),
32764
- /* @__PURE__ */ jsx(
32765
- Tooltip,
32766
- {
32767
- cursor: { stroke: "#E5E7EB", strokeWidth: 1 },
32768
- contentStyle: {
32769
- backgroundColor: "white",
32770
- border: "none",
32771
- borderRadius: "8px",
32772
- boxShadow: "0 4px 12px rgba(0,0,0,0.1)",
32773
- padding: "8px 12px",
32774
- fontSize: "13px"
32775
- },
32776
- labelStyle: {
32777
- color: "#374151",
32778
- fontWeight: 600,
32779
- marginBottom: "4px"
32780
- },
32781
- itemStyle: {
32782
- color: "#4B5563",
32783
- padding: "2px 0"
32784
- },
32785
- labelFormatter: (label, payload) => {
32786
- if (payload && payload[0]) {
32787
- return payload[0].payload.tooltip;
32788
- }
32789
- return label;
32790
- },
32791
- formatter: (value, name) => {
32792
- const numValue = typeof value === "number" ? value : Number(value);
32793
- if (name === "idleMinutes") {
32794
- return [`${numValue.toFixed(0)} minutes`, "Idle Time"];
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
32873
+ },
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
32795
32886
  }
32796
- return [`${numValue.toFixed(1)} seconds`, "Cycle Time"];
32797
- },
32798
- animationDuration: 200
32799
- }
32800
- ),
32801
- /* @__PURE__ */ jsx(
32802
- ReferenceLine,
32803
- {
32804
- y: idealCycleTime,
32805
- yAxisId: "cycle",
32806
- stroke: "#E34329",
32807
- strokeDasharray: "3 3",
32808
- strokeWidth: 2,
32809
- label: {
32810
- position: "right",
32811
- value: `${idealCycleTime.toFixed(1)}s`,
32812
- fill: "#E34329",
32813
- fontSize: 12,
32814
- fontWeight: 500
32815
- }
32816
- }
32817
- ),
32818
- /* @__PURE__ */ jsx(
32819
- Line,
32820
- {
32821
- type: "monotone",
32822
- yAxisId: "cycle",
32823
- dataKey: "cycleTime",
32824
- stroke: "#3B82F6",
32825
- strokeWidth: 2,
32826
- dot: (props) => {
32827
- const { cx: cx2, cy, payload } = props;
32828
- return /* @__PURE__ */ jsx(
32829
- "circle",
32830
- {
32831
- cx: cx2,
32832
- cy,
32833
- r: 4,
32834
- fill: payload.cycleTime <= idealCycleTime ? "#00AB45" : "#E34329",
32835
- stroke: "#fff",
32836
- strokeWidth: 1,
32837
- style: {
32838
- filter: "brightness(1)",
32839
- transition: "filter 0.3s ease, transform 0.3s ease",
32840
- cursor: "pointer"
32841
- },
32842
- onMouseEnter: (e) => {
32843
- const target = e.target;
32844
- target.style.filter = "brightness(1.2)";
32845
- target.style.transform = "scale(1.2)";
32846
- },
32847
- onMouseLeave: (e) => {
32848
- const target = e.target;
32849
- target.style.filter = "brightness(1)";
32850
- target.style.transform = "scale(1)";
32851
- }
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
+ ) });
32852
32914
  }
32853
- );
32854
- },
32855
- activeDot: (props) => {
32856
- const { cx: cx2, cy, payload } = props;
32857
- return /* @__PURE__ */ jsx(
32858
- "circle",
32859
- {
32860
- cx: cx2,
32861
- cy,
32862
- r: 6,
32863
- fill: payload.cycleTime <= idealCycleTime ? "#00AB45" : "#E34329",
32864
- stroke: "#fff",
32865
- strokeWidth: 2,
32866
- style: {
32867
- filter: "drop-shadow(0 0 2px rgba(0,0,0,0.2))"
32868
- }
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
32869
32953
  }
32870
- );
32871
- },
32872
- isAnimationActive: shouldAnimate,
32873
- animationBegin: 0,
32874
- animationDuration: 1200,
32875
- animationEasing: "ease-out",
32876
- onAnimationEnd: handleAnimationEnd
32877
- },
32878
- `${effectiveDatasetKey}:cycle`
32879
- ),
32880
- showIdleTime && /* @__PURE__ */ jsx(
32881
- Line,
32882
- {
32883
- type: "monotone",
32884
- yAxisId: "idle",
32885
- dataKey: "idleMinutes",
32886
- stroke: "#f59e0b",
32887
- strokeWidth: 2,
32888
- strokeDasharray: "4 4",
32889
- dot: { r: 4, fill: "#f59e0b", stroke: "#fff", strokeWidth: 1 },
32890
- activeDot: { r: 6, fill: "#f59e0b", stroke: "#fff", strokeWidth: 2 },
32891
- isAnimationActive: shouldAnimate,
32892
- animationBegin: 0,
32893
- animationDuration: 1200,
32894
- animationEasing: "ease-out"
32895
- },
32896
- `${effectiveDatasetKey}:idle`
32897
- )
32898
- ]
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
+ )
32899
32997
  }
32900
- ) }) : /* @__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
+ ) })
32901
32999
  ]
32902
33000
  }
32903
33001
  );
@@ -33747,10 +33845,10 @@ var HourlyOutputChart = React141__default.memo(HourlyOutputChartComponent, (prev
33747
33845
  HourlyOutputChart.displayName = "HourlyOutputChart";
33748
33846
 
33749
33847
  // src/components/dashboard/grid/videoGridMetricUtils.ts
33750
- var VIDEO_GRID_LEGEND_LABEL = "Flow";
33848
+ var VIDEO_GRID_LEGEND_LABEL = "7 Minute Efficiency";
33751
33849
  var MAP_GRID_LEGEND_LABEL = "Efficiency";
33752
- var MIXED_VIDEO_GRID_LEGEND_LABEL = "Flow / Efficiency";
33753
- 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);
33754
33852
  var isVideoGridRecentFlowEnabled = (workspace) => isRecentFlowVideoGridMetricMode(
33755
33853
  workspace.video_grid_metric_mode,
33756
33854
  workspace.assembly_enabled === true
@@ -33759,11 +33857,11 @@ var isVideoGridWipGated = (workspace) => isWipGatedVideoGridMetricMode(
33759
33857
  workspace.video_grid_metric_mode,
33760
33858
  workspace.assembly_enabled === true
33761
33859
  );
33762
- var hasVideoGridRecentFlow = (workspace) => isVideoGridRecentFlowEnabled(workspace) && isFiniteNumber2(workspace.recent_flow_percent);
33860
+ var hasVideoGridRecentFlow = (workspace) => isVideoGridRecentFlowEnabled(workspace) && isFiniteNumber(workspace.recent_flow_percent);
33763
33861
  var isVideoGridRecentFlowUnavailable = (workspace) => isVideoGridRecentFlowEnabled(workspace) && !hasVideoGridRecentFlow(workspace);
33764
33862
  var getVideoGridMetricValue = (workspace) => {
33765
33863
  const recentFlowPercent = workspace.recent_flow_percent;
33766
- if (hasVideoGridRecentFlow(workspace) && isFiniteNumber2(recentFlowPercent)) {
33864
+ if (hasVideoGridRecentFlow(workspace) && isFiniteNumber(recentFlowPercent)) {
33767
33865
  return recentFlowPercent;
33768
33866
  }
33769
33867
  if (isVideoGridRecentFlowUnavailable(workspace)) {
@@ -33774,7 +33872,7 @@ var getVideoGridMetricValue = (workspace) => {
33774
33872
  var hasIncomingWipMapping = (workspace) => Boolean(workspace.incoming_wip_buffer_name);
33775
33873
  var getVideoGridBaseColorState = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => {
33776
33874
  const metricValue = getVideoGridMetricValue(workspace);
33777
- if (!isFiniteNumber2(metricValue)) {
33875
+ if (!isFiniteNumber(metricValue)) {
33778
33876
  return "neutral";
33779
33877
  }
33780
33878
  return getEfficiencyColor(metricValue, legend);
@@ -33789,7 +33887,7 @@ var isLowWipGreenOverride = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => {
33789
33887
  if (!hasIncomingWipMapping(workspace)) {
33790
33888
  return false;
33791
33889
  }
33792
- return isFiniteNumber2(workspace.incoming_wip_current) && workspace.incoming_wip_current <= 1;
33890
+ return isFiniteNumber(workspace.incoming_wip_current) && workspace.incoming_wip_current <= 1;
33793
33891
  };
33794
33892
  var toMinuteBucket = (minuteBucket) => Number.isFinite(minuteBucket) ? Math.floor(minuteBucket) : Math.floor(Date.now() / 6e4);
33795
33893
  var getEffectiveFlowMinuteBucket = (workspace) => {
@@ -33831,7 +33929,7 @@ var getVideoGridColorState = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) =>
33831
33929
  if (!hasIncomingWipMapping(workspace)) {
33832
33930
  return baseColor;
33833
33931
  }
33834
- if (!isFiniteNumber2(workspace.incoming_wip_current)) {
33932
+ if (!isFiniteNumber(workspace.incoming_wip_current)) {
33835
33933
  return "neutral";
33836
33934
  }
33837
33935
  if (isLowWipGreenOverride(workspace, legend)) {
@@ -34023,7 +34121,7 @@ var VideoCard = React141__default.memo(({
34023
34121
  }
34024
34122
  );
34025
34123
  }, (prevProps, nextProps) => {
34026
- 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) {
34027
34125
  return false;
34028
34126
  }
34029
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) {
@@ -34615,8 +34713,20 @@ var CardFooter2 = (props) => {
34615
34713
  return /* @__PURE__ */ jsx(RegisteredCardFooter, { ...props });
34616
34714
  };
34617
34715
 
34716
+ // src/lib/utils/workspaceDetailCycleTime.ts
34717
+ var resolveWorkspaceDetailActionFamily = (workspace) => {
34718
+ if (workspace?.action_family === "assembly" || workspace?.action_family === "output" || workspace?.action_family === "other") {
34719
+ return workspace.action_family;
34720
+ }
34721
+ if (workspace?.action_type === "assembly" || workspace?.action_type === "output") {
34722
+ return workspace.action_type;
34723
+ }
34724
+ return null;
34725
+ };
34726
+ var shouldUseAssemblyCycleTimeLayout = (workspace) => workspace?.line_assembly_enabled === true && resolveWorkspaceDetailActionFamily(workspace) === "assembly";
34727
+
34618
34728
  // src/components/dashboard/workspace/workspaceDetailCardRules.ts
34619
- var shouldHideWorkspaceEfficiencyCard = (workspace) => workspace?.line_assembly_enabled === true && workspace?.action_type === "assembly";
34729
+ var shouldHideWorkspaceEfficiencyCard = (workspace) => shouldUseAssemblyCycleTimeLayout(workspace);
34620
34730
  var WorkspaceMetricCardsImpl = ({
34621
34731
  workspace,
34622
34732
  className,
@@ -35325,6 +35435,37 @@ var getShiftElapsedMinutes = ({
35325
35435
  const elapsed = differenceInMinutes(now4, shiftStartDate);
35326
35436
  return Math.min(Math.max(elapsed, 0), shiftMinutes);
35327
35437
  };
35438
+ var maskFutureHourlySeries = ({
35439
+ data,
35440
+ shiftStart,
35441
+ shiftEnd,
35442
+ shiftDate,
35443
+ timezone,
35444
+ now: now4 = /* @__PURE__ */ new Date()
35445
+ }) => {
35446
+ if (!Array.isArray(data)) {
35447
+ return [];
35448
+ }
35449
+ const normalizedData = data.map((value) => typeof value === "number" && Number.isFinite(value) ? value : null);
35450
+ if (!normalizedData.length) {
35451
+ return normalizedData;
35452
+ }
35453
+ const shiftMinutes = getShiftDurationMinutes(shiftStart, shiftEnd);
35454
+ const elapsedMinutes = getShiftElapsedMinutes({
35455
+ shiftStart,
35456
+ shiftEnd,
35457
+ shiftDate,
35458
+ timezone,
35459
+ now: now4
35460
+ });
35461
+ if (shiftMinutes === null || elapsedMinutes === null || elapsedMinutes >= shiftMinutes) {
35462
+ return normalizedData;
35463
+ }
35464
+ return normalizedData.map((value, index) => {
35465
+ const slotStartMinutes = index * 60;
35466
+ return slotStartMinutes > elapsedMinutes ? null : value;
35467
+ });
35468
+ };
35328
35469
  var buildUptimeSeries = ({
35329
35470
  idleTimeHourly,
35330
35471
  shiftStart,
@@ -44448,7 +44589,7 @@ var ShiftDisplay = memo$1(({ className, variant = "default", lineId }) => {
44448
44589
  return null;
44449
44590
  }
44450
44591
  };
44451
- const getShiftIcon = (shift) => {
44592
+ const getShiftIcon2 = (shift) => {
44452
44593
  if (shift === "Day") {
44453
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" }) });
44454
44595
  } else {
@@ -44474,7 +44615,7 @@ var ShiftDisplay = memo$1(({ className, variant = "default", lineId }) => {
44474
44615
  }
44475
44616
  if (variant === "enhanced") {
44476
44617
  return /* @__PURE__ */ jsxs("div", { className: `inline-flex items-center gap-2 bg-blue-50 rounded-lg px-3 py-1.5 ${className ?? ""}`, children: [
44477
- /* @__PURE__ */ jsx("div", { className: "text-blue-800", children: getShiftIcon(currentShiftText) }),
44618
+ /* @__PURE__ */ jsx("div", { className: "text-blue-800", children: getShiftIcon2(currentShiftText) }),
44478
44619
  /* @__PURE__ */ jsxs("span", { className: "text-base font-medium text-blue-800", children: [
44479
44620
  currentShiftText,
44480
44621
  " Shift"
@@ -44482,7 +44623,7 @@ var ShiftDisplay = memo$1(({ className, variant = "default", lineId }) => {
44482
44623
  ] });
44483
44624
  }
44484
44625
  return /* @__PURE__ */ jsxs("div", { className: `inline-flex items-center gap-2 bg-blue-50 rounded-lg px-3 py-1.5 ${className ?? ""}`, children: [
44485
- /* @__PURE__ */ jsx("div", { className: "text-blue-800", children: getShiftIcon(currentShiftText) }),
44626
+ /* @__PURE__ */ jsx("div", { className: "text-blue-800", children: getShiftIcon2(currentShiftText) }),
44486
44627
  /* @__PURE__ */ jsxs("span", { className: "text-base font-medium text-blue-800", children: [
44487
44628
  currentShiftText,
44488
44629
  " Shift"
@@ -47119,7 +47260,7 @@ var LinePdfGenerator = ({
47119
47260
  doc.setLineWidth(0.8);
47120
47261
  doc.line(20, 123, 190, 123);
47121
47262
  const hourlyOverviewStartY = 128;
47122
- const parseTimeToMinutes3 = (timeStr) => {
47263
+ const parseTimeToMinutes4 = (timeStr) => {
47123
47264
  const [hours, minutes] = timeStr.split(":");
47124
47265
  const hour = parseInt(hours, 10);
47125
47266
  const minute = parseInt(minutes || "0", 10);
@@ -47152,7 +47293,7 @@ var LinePdfGenerator = ({
47152
47293
  };
47153
47294
  };
47154
47295
  const getHourlyTimeRanges = (startTimeStr, endTimeStr) => {
47155
- const startMinutes = parseTimeToMinutes3(startTimeStr);
47296
+ const startMinutes = parseTimeToMinutes4(startTimeStr);
47156
47297
  if (Number.isNaN(startMinutes)) {
47157
47298
  return [];
47158
47299
  }
@@ -47160,7 +47301,7 @@ var LinePdfGenerator = ({
47160
47301
  const defaultHours = 11;
47161
47302
  return Array.from({ length: defaultHours }, (_, i) => buildRange(startMinutes + i * 60, 60));
47162
47303
  }
47163
- const endMinutes = parseTimeToMinutes3(endTimeStr);
47304
+ const endMinutes = parseTimeToMinutes4(endTimeStr);
47164
47305
  if (Number.isNaN(endMinutes)) {
47165
47306
  const fallbackHours = 11;
47166
47307
  return Array.from({ length: fallbackHours }, (_, i) => buildRange(startMinutes + i * 60, 60));
@@ -48863,7 +49004,7 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
48863
49004
  setIsGenerating(true);
48864
49005
  try {
48865
49006
  const isUptimeMode = workspace.monitoring_mode === "uptime";
48866
- const isAssemblyCycleMode = !isUptimeMode && workspace.line_assembly_enabled === true && workspace.action_type === "assembly";
49007
+ const isAssemblyCycleMode = !isUptimeMode && shouldUseAssemblyCycleTimeLayout(workspace);
48867
49008
  const shiftMinutes = getShiftDurationMinutes(workspace.shift_start, workspace.shift_end);
48868
49009
  const shiftSeconds = shiftMinutes ? shiftMinutes * 60 : 0;
48869
49010
  const idleSeconds = Math.max(workspace.idle_time || 0, 0);
@@ -48929,7 +49070,7 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
48929
49070
  minute: "2-digit",
48930
49071
  hour12: true
48931
49072
  });
48932
- const parseTimeToMinutes3 = (timeValue) => {
49073
+ const parseTimeToMinutes4 = (timeValue) => {
48933
49074
  const [hourPart, minutePart] = timeValue.split(":").map(Number);
48934
49075
  const hour = Number.isFinite(hourPart) ? hourPart : 0;
48935
49076
  const minute = Number.isFinite(minutePart) ? minutePart : 0;
@@ -48946,8 +49087,8 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
48946
49087
  const IST_OFFSET_MINUTES = 330;
48947
49088
  return Date.UTC(year, month - 1, day, hour, minute) - IST_OFFSET_MINUTES * 60 * 1e3;
48948
49089
  };
48949
- const shiftStartMinutes = parseTimeToMinutes3(workspace.shift_start);
48950
- const shiftEndMinutes = parseTimeToMinutes3(workspace.shift_end);
49090
+ const shiftStartMinutes = parseTimeToMinutes4(workspace.shift_start);
49091
+ const shiftEndMinutes = parseTimeToMinutes4(workspace.shift_end);
48951
49092
  const wrapsMidnight = shiftEndMinutes <= shiftStartMinutes;
48952
49093
  const shiftStartUtcMs = toShiftUtcMs(workspace.date, workspace.shift_start);
48953
49094
  const shiftEndUtcMs = toShiftUtcMs(workspace.date, workspace.shift_end) + (wrapsMidnight ? 24 * 60 * 60 * 1e3 : 0);
@@ -51254,7 +51395,7 @@ var DashboardHeader = memo$1(({ lineTitle, className = "", headerControls, lineI
51254
51395
  const rawName = currentShift.shiftName || "Day";
51255
51396
  return rawName.toLowerCase().includes("shift") ? rawName : `${rawName} Shift`;
51256
51397
  };
51257
- const getShiftIcon = () => {
51398
+ const getShiftIcon2 = () => {
51258
51399
  const currentShift = getCurrentShift(timezone, shiftConfig);
51259
51400
  const shiftName = (currentShift.shiftName || "").toLowerCase();
51260
51401
  if (shiftName.includes("day") || shiftName.includes("morning") || currentShift.shiftId === 0) {
@@ -51288,7 +51429,7 @@ var DashboardHeader = memo$1(({ lineTitle, className = "", headerControls, lineI
51288
51429
  /* @__PURE__ */ jsx("span", { className: "font-medium", children: /* @__PURE__ */ jsx(Timer2, {}) }),
51289
51430
  /* @__PURE__ */ jsx("span", { className: "text-gray-300", children: "|" }),
51290
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: [
51291
- /* @__PURE__ */ jsx("span", { className: "opacity-75", children: getShiftIcon() }),
51432
+ /* @__PURE__ */ jsx("span", { className: "opacity-75", children: getShiftIcon2() }),
51292
51433
  getShiftName()
51293
51434
  ] })
51294
51435
  ] })
@@ -51305,7 +51446,7 @@ var DashboardHeader = memo$1(({ lineTitle, className = "", headerControls, lineI
51305
51446
  /* @__PURE__ */ jsxs("div", { className: "mt-2 inline-flex flex-wrap items-center gap-3", children: [
51306
51447
  /* @__PURE__ */ jsx("div", { className: "text-xs md:text-sm font-medium text-gray-600 whitespace-nowrap", children: /* @__PURE__ */ jsx(Timer2, {}) }),
51307
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: [
51308
- /* @__PURE__ */ jsx("div", { className: "text-gray-600", children: getShiftIcon() }),
51449
+ /* @__PURE__ */ jsx("div", { className: "text-gray-600", children: getShiftIcon2() }),
51309
51450
  /* @__PURE__ */ jsx("span", { className: "text-xs md:text-sm font-medium text-gray-600 whitespace-nowrap", children: getShiftName() })
51310
51451
  ] }) })
51311
51452
  ] })
@@ -58276,7 +58417,7 @@ var FactoryView = ({
58276
58417
  const currentShift = getCurrentShiftInfo();
58277
58418
  return (currentShift.shiftName || "Day").replace(/ Shift$/i, "");
58278
58419
  };
58279
- const getShiftIcon = () => {
58420
+ const getShiftIcon2 = () => {
58280
58421
  const currentShift = getCurrentShiftInfo();
58281
58422
  const shiftNameLower = (currentShift.shiftName || "").toLowerCase();
58282
58423
  if (shiftNameLower.includes("day") || shiftNameLower.includes("morning") || currentShift.shiftId === 0) {
@@ -58322,7 +58463,7 @@ var FactoryView = ({
58322
58463
  /* @__PURE__ */ jsxs("div", { className: "mt-2 flex items-center justify-center gap-2", children: [
58323
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, {}) }) }),
58324
58465
  /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
58325
- /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon() }),
58466
+ /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon2() }),
58326
58467
  /* @__PURE__ */ jsxs("span", { className: "text-xs font-medium text-gray-700", children: [
58327
58468
  getShiftName(),
58328
58469
  " Shift"
@@ -58341,7 +58482,7 @@ var FactoryView = ({
58341
58482
  " IST"
58342
58483
  ] }),
58343
58484
  /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1", children: [
58344
- /* @__PURE__ */ jsx("div", { className: "text-gray-600", children: getShiftIcon() }),
58485
+ /* @__PURE__ */ jsx("div", { className: "text-gray-600", children: getShiftIcon2() }),
58345
58486
  /* @__PURE__ */ jsxs("span", { className: "text-sm font-medium text-gray-600", children: [
58346
58487
  getShiftName(),
58347
58488
  " Shift"
@@ -61053,7 +61194,7 @@ var KPIDetailView = ({
61053
61194
  const getShiftName = useCallback((shiftId) => {
61054
61195
  return getShiftNameById(shiftId, configuredTimezone, shiftConfig);
61055
61196
  }, [configuredTimezone, shiftConfig]);
61056
- const getShiftIcon = useCallback((shiftId) => {
61197
+ const getShiftIcon2 = useCallback((shiftId) => {
61057
61198
  if (shiftId === 0) {
61058
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" }) });
61059
61200
  }
@@ -61933,7 +62074,7 @@ var KPIDetailView = ({
61933
62074
  /* @__PURE__ */ jsxs("div", { className: "sm:hidden mt-3 flex items-center justify-center gap-2", children: [
61934
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)) }) }),
61935
62076
  /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
61936
- /* @__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) }),
61937
62078
  /* @__PURE__ */ jsxs("span", { className: "text-xs font-medium text-gray-700", children: [
61938
62079
  getShiftName(chartMetrics.shift_id ?? 0).replace(/ Shift$/i, ""),
61939
62080
  " Shift"
@@ -61959,7 +62100,7 @@ var KPIDetailView = ({
61959
62100
  /* @__PURE__ */ jsx("div", { className: "w-px h-4 bg-blue-200" })
61960
62101
  ] }),
61961
62102
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
61962
- /* @__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) }),
61963
62104
  /* @__PURE__ */ jsxs("span", { className: "text-sm md:text-base font-semibold uppercase tracking-wider", children: [
61964
62105
  getShiftName(chartMetrics.shift_id ?? 0).replace(/ Shift$/i, ""),
61965
62106
  " Shift"
@@ -61977,7 +62118,7 @@ var KPIDetailView = ({
61977
62118
  return `${startDate.toLocaleDateString("en-US", { month: "short", day: "numeric" })} - ${endDate.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })}`;
61978
62119
  })() }) }),
61979
62120
  /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
61980
- /* @__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) }),
61981
62122
  /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-700", children: getShiftName(selectedShiftId) })
61982
62123
  ] })
61983
62124
  ] }),
@@ -61994,7 +62135,7 @@ var KPIDetailView = ({
61994
62135
  ] }),
61995
62136
  /* @__PURE__ */ jsx("div", { className: "w-px h-4 bg-blue-200" }),
61996
62137
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
61997
- /* @__PURE__ */ jsx("div", { className: "opacity-70", children: getShiftIcon(selectedShiftId) }),
62138
+ /* @__PURE__ */ jsx("div", { className: "opacity-70", children: getShiftIcon2(selectedShiftId) }),
61998
62139
  /* @__PURE__ */ jsxs("span", { className: "text-sm md:text-base font-semibold uppercase tracking-wider", children: [
61999
62140
  getShiftName(selectedShiftId).replace(/ Shift$/i, ""),
62000
62141
  " Shift"
@@ -63370,7 +63511,7 @@ var KPIsOverviewView = ({
63370
63511
  const headerShiftId = showHistoricalLeaderboardHeader ? effectiveLeaderboardShiftId : currentShiftDetails.shiftId;
63371
63512
  const headerShiftName = getShiftNameById(headerShiftId, configuredTimezone, shiftConfig).replace(/ Shift$/i, "");
63372
63513
  const headerDateLabel = isMonthlyMode ? getMonthRange() : formatLocalDate2(headerDateKey);
63373
- const getShiftIcon = (shiftId) => {
63514
+ const getShiftIcon2 = (shiftId) => {
63374
63515
  const shiftNameLower = getShiftNameById(shiftId, configuredTimezone, shiftConfig).toLowerCase();
63375
63516
  if (shiftNameLower.includes("day") || shiftNameLower.includes("morning") || shiftId === 0) {
63376
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" }) });
@@ -63487,7 +63628,7 @@ var KPIsOverviewView = ({
63487
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 }) }),
63488
63629
  !isMonthlyMode && /* @__PURE__ */ jsxs(Fragment, { children: [
63489
63630
  /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
63490
- /* @__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) }),
63491
63632
  /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-700", children: headerShiftName })
63492
63633
  ] }),
63493
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: [
@@ -63683,7 +63824,7 @@ var KPIsOverviewView = ({
63683
63824
  !isMonthlyMode && /* @__PURE__ */ jsxs(Fragment, { children: [
63684
63825
  /* @__PURE__ */ jsx("div", { className: "w-px h-4 bg-blue-200" }),
63685
63826
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
63686
- /* @__PURE__ */ jsx("div", { className: "opacity-70", children: getShiftIcon(headerShiftId) }),
63827
+ /* @__PURE__ */ jsx("div", { className: "opacity-70", children: getShiftIcon2(headerShiftId) }),
63687
63828
  /* @__PURE__ */ jsxs("span", { className: "text-sm font-semibold uppercase tracking-wider", children: [
63688
63829
  headerShiftName,
63689
63830
  " Shift"
@@ -63827,6 +63968,52 @@ var KPIsOverviewView = ({
63827
63968
  ] });
63828
63969
  };
63829
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";
63830
64017
  var IsolatedTimer = memo$1(() => {
63831
64018
  return /* @__PURE__ */ jsx(ISTTimer_default, {});
63832
64019
  });
@@ -63844,11 +64031,11 @@ var HeaderRibbon = memo$1(({
63844
64031
  currentDate,
63845
64032
  currentMobileDate,
63846
64033
  shiftId,
63847
- getShiftIcon,
64034
+ getShiftIcon: getShiftIcon2,
63848
64035
  getShiftName,
63849
64036
  showTimer = true
63850
64037
  }) => {
63851
- const shiftIcon = useMemo(() => getShiftIcon(shiftId), [getShiftIcon, shiftId]);
64038
+ const shiftIcon = useMemo(() => getShiftIcon2(shiftId), [getShiftIcon2, shiftId]);
63852
64039
  const shiftName = useMemo(() => getShiftName(shiftId), [getShiftName, shiftId]);
63853
64040
  return /* @__PURE__ */ jsxs(Fragment, { children: [
63854
64041
  /* @__PURE__ */ jsxs("div", { className: "sm:hidden mt-3 flex items-center justify-center gap-2", children: [
@@ -63890,8 +64077,9 @@ var MobileWorkspaceCard = memo$1(({
63890
64077
  isClickable,
63891
64078
  onWorkspaceClick,
63892
64079
  getMedalIcon,
63893
- efficiencyLabel
63894
- }) => /* @__PURE__ */ jsx(
64080
+ metricLabel,
64081
+ isAssemblyMode
64082
+ }) => /* @__PURE__ */ jsxs(
63895
64083
  motion.div,
63896
64084
  {
63897
64085
  layout: true,
@@ -63902,28 +64090,31 @@ var MobileWorkspaceCard = memo$1(({
63902
64090
  },
63903
64091
  onClick: isClickable ? () => onWorkspaceClick(workspace, rank) : void 0,
63904
64092
  className: `${cardClass} p-3 rounded-lg border shadow-sm active:scale-[0.98] ${isClickable ? "cursor-pointer" : "cursor-not-allowed opacity-75"}`,
63905
- children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-2", children: [
63906
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
63907
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
63908
- /* @__PURE__ */ jsxs("div", { className: "text-2xl font-bold text-gray-700", children: [
63909
- "#",
63910
- 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)
63911
64102
  ] }),
63912
- 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
+ ] })
63913
64107
  ] }),
63914
- /* @__PURE__ */ jsxs("div", { children: [
63915
- /* @__PURE__ */ jsx("div", { className: "font-semibold text-gray-900", children: workspace.displayName }),
63916
- /* @__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 })
63917
64111
  ] })
63918
64112
  ] }),
63919
- /* @__PURE__ */ jsxs("div", { className: "text-right", children: [
63920
- /* @__PURE__ */ jsx("div", { className: "text-lg font-bold text-gray-900", children: /* @__PURE__ */ jsx(AnimatedEfficiency, { value: workspace.efficiency || 0 }) }),
63921
- /* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500", children: efficiencyLabel })
63922
- ] })
63923
- ] })
64113
+ isAssemblyMode && /* @__PURE__ */ jsx(CycleTimeComparison, { workspace, variant: "mobile" })
64114
+ ]
63924
64115
  }
63925
64116
  ), (prevProps, nextProps) => {
63926
- 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;
63927
64118
  });
63928
64119
  MobileWorkspaceCard.displayName = "MobileWorkspaceCard";
63929
64120
  var DesktopWorkspaceRow = memo$1(({
@@ -63932,7 +64123,8 @@ var DesktopWorkspaceRow = memo$1(({
63932
64123
  rowClass,
63933
64124
  isClickable,
63934
64125
  onWorkspaceClick,
63935
- getMedalIcon
64126
+ getMedalIcon,
64127
+ isAssemblyMode
63936
64128
  }) => /* @__PURE__ */ jsxs(
63937
64129
  motion.tr,
63938
64130
  {
@@ -63949,11 +64141,11 @@ var DesktopWorkspaceRow = memo$1(({
63949
64141
  ] }) }),
63950
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 }) }),
63951
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 }) }),
63952
- /* @__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 }) })
63953
64145
  ]
63954
64146
  }
63955
64147
  ), (prevProps, nextProps) => {
63956
- 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;
63957
64149
  });
63958
64150
  DesktopWorkspaceRow.displayName = "DesktopWorkspaceRow";
63959
64151
  var LeaderboardDetailView = memo$1(({
@@ -63975,6 +64167,7 @@ var LeaderboardDetailView = memo$1(({
63975
64167
  const supabase = useSupabase();
63976
64168
  const [sortAscending, setSortAscending] = useState(false);
63977
64169
  const [viewType, setViewType] = useState("operator");
64170
+ const [outputCategory, setOutputCategory] = useState("standard");
63978
64171
  const [activeTab, setActiveTab] = useState("today");
63979
64172
  const timezone = useAppTimezone();
63980
64173
  const staticShiftConfig = useShiftConfig();
@@ -64053,6 +64246,7 @@ var LeaderboardDetailView = memo$1(({
64053
64246
  const monthlyRequestKeyRef = useRef(null);
64054
64247
  const leaderboardUpdateQueuedRef = useRef(false);
64055
64248
  const leaderboardUpdateTimerRef = useRef(null);
64249
+ const leaderboardViewTrackedRef = useRef(null);
64056
64250
  const filterRef = useRef(null);
64057
64251
  const filterButtonRef = useRef(null);
64058
64252
  const mobileFilterButtonRef = useRef(null);
@@ -64185,6 +64379,17 @@ var LeaderboardDetailView = memo$1(({
64185
64379
  }
64186
64380
  return Array.from(uniqueLines.entries()).map(([id3, name]) => ({ id: id3, label: name }));
64187
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]);
64188
64393
  const shiftOptions = useMemo(() => {
64189
64394
  if (activeShiftConfig?.shifts && activeShiftConfig.shifts.length > 0) {
64190
64395
  return activeShiftConfig.shifts.map((shift2) => ({
@@ -64208,6 +64413,33 @@ var LeaderboardDetailView = memo$1(({
64208
64413
  const parsed = Number(selectedShiftFilter);
64209
64414
  return Number.isFinite(parsed) ? parsed : void 0;
64210
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]);
64211
64443
  const handleLineFilterChange = useCallback((value) => {
64212
64444
  setSelectedLineFilter(value);
64213
64445
  }, []);
@@ -64217,17 +64449,19 @@ var LeaderboardDetailView = memo$1(({
64217
64449
  const clearFilters = useCallback(() => {
64218
64450
  setSortAscending(false);
64219
64451
  setSelectedLineFilter("all");
64452
+ setOutputCategory("standard");
64220
64453
  setSelectedShiftFilter(currentShiftInfo.shiftId.toString());
64221
64454
  }, [currentShiftInfo.shiftId]);
64222
64455
  const activeFiltersCount = useMemo(() => {
64223
64456
  let count = 0;
64224
64457
  if (sortAscending) count++;
64225
64458
  if (selectedLineFilter !== "all") count++;
64459
+ if (showOutputCategoryDropdown && outputCategory !== "standard") count++;
64226
64460
  if (selectedShiftFilter !== currentShiftInfo.shiftId.toString()) {
64227
64461
  count++;
64228
64462
  }
64229
64463
  return count;
64230
- }, [sortAscending, selectedLineFilter, selectedShiftFilter, currentShiftInfo.shiftId]);
64464
+ }, [sortAscending, selectedLineFilter, outputCategory, showOutputCategoryDropdown, selectedShiftFilter, currentShiftInfo.shiftId]);
64231
64465
  const shouldFetchShiftConfigs = !date && shiftId === void 0;
64232
64466
  const {
64233
64467
  shiftConfigMap: multiLineShiftConfigMap,
@@ -64279,7 +64513,8 @@ var LeaderboardDetailView = memo$1(({
64279
64513
  action_count: entry.total_output || 0,
64280
64514
  pph: entry.avg_pph || 0,
64281
64515
  performance_score: entry.performance_score ?? 0,
64282
- 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,
64283
64518
  trend: 0,
64284
64519
  predicted_output: 0,
64285
64520
  efficiency: entry.efficiency || 0,
@@ -64457,7 +64692,7 @@ var LeaderboardDetailView = memo$1(({
64457
64692
  const currentShift = getCurrentShift(timezone || "Asia/Kolkata", activeShiftConfig);
64458
64693
  return currentShift.shiftName || getShiftNameById(currentShift.shiftId, timezone || "Asia/Kolkata", activeShiftConfig);
64459
64694
  }, [timezone, activeShiftConfig, shiftGroups]);
64460
- const getShiftIcon = useCallback((shiftId2) => {
64695
+ const getShiftIcon2 = useCallback((shiftId2) => {
64461
64696
  if (shiftId2 === void 0 && shiftGroups.length > 1) {
64462
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" }) });
64463
64698
  }
@@ -64523,15 +64758,20 @@ var LeaderboardDetailView = memo$1(({
64523
64758
  if (!canOpenWorkspace(workspace.line_id)) {
64524
64759
  return;
64525
64760
  }
64761
+ const cycleRatio = getCycleRatio(workspace);
64526
64762
  trackCoreEvent("Workspace from Leaderboard Clicked", {
64527
64763
  workspace_name: workspace.workspace_name,
64528
64764
  workspace_id: workspace.workspace_uuid,
64529
64765
  rank,
64530
64766
  total_workspaces: workspacesLengthRef.current,
64531
64767
  // Use ref instead of state to avoid dependency
64768
+ metric_context: viewType === "machine" ? "machine" : outputCategory,
64532
64769
  efficiency: workspace.efficiency,
64533
64770
  action_count: workspace.action_count,
64534
- 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
64535
64775
  });
64536
64776
  const displayName = workspace.displayName || getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
64537
64777
  const navParams = workspace.workspace_uuid ? getWorkspaceNavigationParams(workspace.workspace_uuid, displayName, workspace.line_id) : "";
@@ -64555,7 +64795,7 @@ var LeaderboardDetailView = memo$1(({
64555
64795
  const combinedParams = navParams ? `${navParams}&${contextParamString}` : `?${contextParamString}`;
64556
64796
  navigation.navigate(`/workspace/${workspace.workspace_uuid}${combinedParams}`);
64557
64797
  }
64558
- }, [canOpenWorkspace, onWorkspaceClick, navigation, date, shiftId]);
64798
+ }, [canOpenWorkspace, onWorkspaceClick, navigation, date, shiftId, outputCategory, viewType]);
64559
64799
  useEffect(() => {
64560
64800
  workspacesLengthRef.current = activeEntries.length || 0;
64561
64801
  }, [activeEntries.length]);
@@ -64576,16 +64816,20 @@ var LeaderboardDetailView = memo$1(({
64576
64816
  return activeEntries.map((ws) => ({
64577
64817
  ...ws,
64578
64818
  displayName: ws.displayName || getWorkspaceDisplayName(ws.workspace_name, ws.line_id),
64579
- lineName: getLineName(ws.line_id)
64819
+ lineName: getLineName(ws.line_id),
64820
+ isAssemblyLine: scopedLineAssemblyMap.get(ws.line_id) === true
64580
64821
  }));
64581
- }, [activeEntries, getLineName]);
64822
+ }, [activeEntries, getLineName, scopedLineAssemblyMap]);
64582
64823
  const sortedWorkspaces = useMemo(() => {
64583
64824
  let filtered = [...workspaceDisplayData];
64584
64825
  filtered = filtered.filter((ws) => {
64585
64826
  if (viewType === "machine") {
64586
64827
  return ws.monitoring_mode === "uptime";
64587
64828
  }
64588
- return ws.monitoring_mode !== "uptime";
64829
+ if (ws.monitoring_mode === "uptime") {
64830
+ return false;
64831
+ }
64832
+ return isAssemblyMode ? ws.isAssemblyLine : !ws.isAssemblyLine;
64589
64833
  });
64590
64834
  if (selectedLineFilter !== "all") {
64591
64835
  filtered = filtered.filter((ws) => ws.line_id === selectedLineFilter);
@@ -64594,13 +64838,61 @@ var LeaderboardDetailView = memo$1(({
64594
64838
  filtered = filtered.filter((ws) => ws.shift_id?.toString() === selectedShiftFilter);
64595
64839
  }
64596
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
+ }
64597
64849
  const effA = a.efficiency || 0;
64598
64850
  const effB = b.efficiency || 0;
64599
64851
  return sortAscending ? effA - effB : effB - effA;
64600
64852
  });
64601
- }, [workspaceDisplayData, sortAscending, selectedLineFilter, selectedShiftFilter, activeTab, viewType]);
64853
+ }, [workspaceDisplayData, sortAscending, selectedLineFilter, selectedShiftFilter, activeTab, viewType, isAssemblyMode]);
64602
64854
  const loading = activeTab === "today" ? todayLoading : monthlyLoading;
64603
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
+ ]);
64604
64896
  const currentDateFormatted = useMemo(() => {
64605
64897
  const dateStr = (/* @__PURE__ */ new Date()).toDateString();
64606
64898
  return formatDate2(new Date(dateStr));
@@ -64618,7 +64910,9 @@ var LeaderboardDetailView = memo$1(({
64618
64910
  error.message
64619
64911
  ] }) });
64620
64912
  }
64621
- 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";
64622
64916
  return /* @__PURE__ */ jsxs("div", { className: `min-h-screen bg-slate-50 flex flex-col ${className}`, style: { willChange: "contents" }, children: [
64623
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: [
64624
64918
  /* @__PURE__ */ jsx("div", { className: "sm:hidden", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
@@ -64668,7 +64962,7 @@ var LeaderboardDetailView = memo$1(({
64668
64962
  ] }),
64669
64963
  /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
64670
64964
  /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
64671
- /* @__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 }),
64672
64966
  /* @__PURE__ */ jsx("div", { className: "relative", children: /* @__PURE__ */ jsxs(
64673
64967
  "select",
64674
64968
  {
@@ -64677,8 +64971,25 @@ var LeaderboardDetailView = memo$1(({
64677
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",
64678
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` },
64679
64973
  children: [
64680
- /* @__PURE__ */ jsx("option", { value: "desc", children: "Highest to Lowest" }),
64681
- /* @__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" })
64682
64993
  ]
64683
64994
  }
64684
64995
  ) })
@@ -64720,7 +65031,7 @@ var LeaderboardDetailView = memo$1(({
64720
65031
  currentDate: activeTab === "monthly" ? monthlyRangeText : currentDateFormatted,
64721
65032
  currentMobileDate: activeTab === "monthly" ? monthlyRangeText : currentMobileDateFormatted,
64722
65033
  shiftId: activeTab === "monthly" ? monthlyShiftId : todayShiftId,
64723
- getShiftIcon,
65034
+ getShiftIcon: getShiftIcon2,
64724
65035
  getShiftName,
64725
65036
  showTimer: activeTab === "today"
64726
65037
  }
@@ -64818,6 +65129,20 @@ var LeaderboardDetailView = memo$1(({
64818
65129
  ]
64819
65130
  }
64820
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
+ ) }),
64821
65146
  /* @__PURE__ */ jsxs(
64822
65147
  "button",
64823
65148
  {
@@ -64849,7 +65174,8 @@ var LeaderboardDetailView = memo$1(({
64849
65174
  isClickable: canOpenWorkspace(ws.line_id),
64850
65175
  onWorkspaceClick: stableHandleWorkspaceClick,
64851
65176
  getMedalIcon: stableGetMedalIcon,
64852
- efficiencyLabel
65177
+ metricLabel,
65178
+ isAssemblyMode
64853
65179
  },
64854
65180
  ws.workspace_uuid
64855
65181
  );
@@ -64860,7 +65186,7 @@ var LeaderboardDetailView = memo$1(({
64860
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" }),
64861
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" }),
64862
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" }),
64863
- /* @__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 })
64864
65190
  ] }) }),
64865
65191
  /* @__PURE__ */ jsx("tbody", { className: "divide-y divide-gray-100", children: sortedWorkspaces.map((ws, index) => {
64866
65192
  const isTopThree = index < 3;
@@ -64873,7 +65199,8 @@ var LeaderboardDetailView = memo$1(({
64873
65199
  rowClass,
64874
65200
  isClickable: canOpenWorkspace(ws.line_id),
64875
65201
  onWorkspaceClick: stableHandleWorkspaceClick,
64876
- getMedalIcon: stableGetMedalIcon
65202
+ getMedalIcon: stableGetMedalIcon,
65203
+ isAssemblyMode
64877
65204
  },
64878
65205
  ws.workspace_uuid
64879
65206
  );
@@ -64891,7 +65218,10 @@ function LoginView({
64891
65218
  logoSrc = optifye_logo_default,
64892
65219
  logoAlt = "Optifye",
64893
65220
  brandName = "Optifye",
64894
- onRateLimitCheck
65221
+ onRateLimitCheck,
65222
+ showDevTestLogin = false,
65223
+ devTestLoginLabel,
65224
+ onDevTestLogin
64895
65225
  }) {
64896
65226
  return /* @__PURE__ */ jsx(
64897
65227
  LoginPage,
@@ -64899,7 +65229,10 @@ function LoginView({
64899
65229
  logoSrc,
64900
65230
  logoAlt,
64901
65231
  brandName,
64902
- onRateLimitCheck
65232
+ onRateLimitCheck,
65233
+ showDevTestLogin,
65234
+ devTestLoginLabel,
65235
+ onDevTestLogin
64903
65236
  }
64904
65237
  );
64905
65238
  }
@@ -68034,8 +68367,84 @@ var TargetsView = ({
68034
68367
  var TargetsViewWithDisplayNames = withAllWorkspaceDisplayNames(TargetsView);
68035
68368
  var TargetsView_default = TargetsViewWithDisplayNames;
68036
68369
  var AuthenticatedTargetsView = withAuth(React141__default.memo(TargetsViewWithDisplayNames));
68370
+ function useTimezone(options = {}) {
68371
+ const dashboardConfig = useDashboardConfig();
68372
+ const workspaceConfig = useWorkspaceConfig();
68373
+ const defaultTimezone = dashboardConfig?.dateTimeConfig?.defaultTimezone || "Asia/Kolkata";
68374
+ const [timezone, setTimezone] = useState(defaultTimezone);
68375
+ const [isLoading, setIsLoading] = useState(true);
68376
+ const [error, setError] = useState(null);
68377
+ const fetchTimezone = useCallback(async () => {
68378
+ setIsLoading(true);
68379
+ setError(null);
68380
+ try {
68381
+ let fetchedTimezone = defaultTimezone;
68382
+ if (options.lineId) {
68383
+ fetchedTimezone = await timezoneService.getTimezoneForLine(options.lineId, defaultTimezone);
68384
+ } else if (options.workspaceId || workspaceConfig && "id" in workspaceConfig) {
68385
+ const wsId = options.workspaceId || (workspaceConfig && "id" in workspaceConfig ? workspaceConfig.id : void 0);
68386
+ if (wsId) {
68387
+ fetchedTimezone = await timezoneService.getTimezoneForWorkspace(wsId, defaultTimezone);
68388
+ }
68389
+ } else if (options.companyId || dashboardConfig && "company" in dashboardConfig) {
68390
+ const compId = options.companyId || (dashboardConfig && "company" in dashboardConfig ? dashboardConfig.company?.id : void 0);
68391
+ if (compId) {
68392
+ fetchedTimezone = await timezoneService.getTimezoneForCompany(compId, defaultTimezone);
68393
+ }
68394
+ }
68395
+ setTimezone(fetchedTimezone);
68396
+ } catch (err) {
68397
+ console.error("Error fetching timezone:", err);
68398
+ setError(err instanceof Error ? err : new Error("Failed to fetch timezone"));
68399
+ setTimezone(defaultTimezone);
68400
+ } finally {
68401
+ setIsLoading(false);
68402
+ }
68403
+ }, [
68404
+ options.lineId,
68405
+ options.workspaceId,
68406
+ options.companyId,
68407
+ workspaceConfig,
68408
+ dashboardConfig,
68409
+ defaultTimezone
68410
+ ]);
68411
+ useEffect(() => {
68412
+ fetchTimezone();
68413
+ }, [fetchTimezone]);
68414
+ return {
68415
+ timezone,
68416
+ isLoading,
68417
+ error,
68418
+ refetch: fetchTimezone
68419
+ };
68420
+ }
68037
68421
 
68038
68422
  // src/views/workspace-detail-view.utils.ts
68423
+ var getWorkspaceDetailLayoutMode = ({
68424
+ workspace,
68425
+ showCycleTimeChart
68426
+ }) => {
68427
+ if (workspace?.monitoring_mode === "uptime") {
68428
+ return "uptime";
68429
+ }
68430
+ if (showCycleTimeChart === false) {
68431
+ return "output";
68432
+ }
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") {
68441
+ return "output";
68442
+ }
68443
+ if (!authoritativeMetrics) {
68444
+ return "chart_loading";
68445
+ }
68446
+ return authoritativeMetrics.cycle_time_data_status === "missing_clips" ? "cycle_unavailable" : "cycle_chart";
68447
+ };
68039
68448
  var formatDateInTimezone = (date = /* @__PURE__ */ new Date(), timezone, options) => {
68040
68449
  const defaultOptions = {
68041
68450
  day: "numeric",
@@ -68419,6 +68828,7 @@ var WorkspaceDetailView = ({
68419
68828
  date: cachedOverviewMetrics.date,
68420
68829
  shift_id: cachedOverviewMetrics.shift_id,
68421
68830
  action_name: "",
68831
+ action_family: cachedOverviewMetrics.action_family ?? null,
68422
68832
  action_type: cachedOverviewMetrics.action_type ?? null,
68423
68833
  monitoring_mode: cachedOverviewMetrics.monitoring_mode ?? "output",
68424
68834
  shift_start: shiftDefinition?.startTime || "",
@@ -68441,23 +68851,48 @@ var WorkspaceDetailView = ({
68441
68851
  idle_time_hourly: void 0
68442
68852
  };
68443
68853
  }, [cachedOverviewMetrics, shiftConfig?.shifts]);
68444
- const workspace = (isHistoricView ? historicMetrics : liveMetrics) || cachedDetailedMetrics || overviewFallback;
68445
- const detailedWorkspaceMetrics = (isHistoricView ? historicMetrics : liveMetrics) || cachedDetailedMetrics;
68854
+ const authoritativeCycleMetrics = isHistoricView ? historicMetrics : liveMetrics;
68855
+ const workspace = authoritativeCycleMetrics || cachedDetailedMetrics || overviewFallback;
68856
+ const { timezone: cycleTimeTimezone } = useTimezone({
68857
+ lineId: effectiveLineId || workspace?.line_id || void 0,
68858
+ workspaceId: workspaceId || void 0
68859
+ });
68860
+ const effectiveCycleTimeTimezone = cycleTimeTimezone || timezone;
68861
+ const detailedWorkspaceMetrics = authoritativeCycleMetrics || cachedDetailedMetrics;
68446
68862
  const cycleTimeChartData = useMemo(
68447
- () => 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) => {
68448
68864
  const numericValue = Number(value);
68449
68865
  return Number.isFinite(numericValue) ? numericValue : 0;
68450
68866
  }) : [],
68451
- [workspace?.hourly_cycle_times]
68867
+ [authoritativeCycleMetrics?.hourly_cycle_times]
68868
+ );
68869
+ const maskedCycleTimeChartData = useMemo(
68870
+ () => maskFutureHourlySeries({
68871
+ data: cycleTimeChartData,
68872
+ shiftStart: authoritativeCycleMetrics?.shift_start,
68873
+ shiftEnd: authoritativeCycleMetrics?.shift_end,
68874
+ shiftDate: authoritativeCycleMetrics?.date || date || calculatedOperationalDate || null,
68875
+ timezone: effectiveCycleTimeTimezone
68876
+ }),
68877
+ [
68878
+ cycleTimeChartData,
68879
+ authoritativeCycleMetrics?.shift_start,
68880
+ authoritativeCycleMetrics?.shift_end,
68881
+ authoritativeCycleMetrics?.date,
68882
+ date,
68883
+ calculatedOperationalDate,
68884
+ effectiveCycleTimeTimezone
68885
+ ]
68452
68886
  );
68453
68887
  const cycleTimeDatasetKey = useMemo(
68454
68888
  () => [
68455
- workspace?.workspace_id || workspaceId || "workspace",
68456
- date || workspace?.date || "live",
68457
- parsedShiftId ?? workspace?.shift_id ?? "current",
68458
- "hourly"
68889
+ authoritativeCycleMetrics?.workspace_id || workspaceId || "workspace",
68890
+ date || authoritativeCycleMetrics?.date || "live",
68891
+ parsedShiftId ?? authoritativeCycleMetrics?.shift_id ?? "current",
68892
+ "hourly",
68893
+ "backend"
68459
68894
  ].join(":"),
68460
- [workspace?.workspace_id, workspaceId, date, workspace?.date, parsedShiftId, workspace?.shift_id]
68895
+ [authoritativeCycleMetrics?.workspace_id, workspaceId, date, authoritativeCycleMetrics?.date, parsedShiftId, authoritativeCycleMetrics?.shift_id]
68461
68896
  );
68462
68897
  const hasWorkspaceSnapshot = Boolean(workspace);
68463
68898
  const loading = ((isHistoricView ? historicLoading : liveLoading) || isShiftConfigLoading) && !hasWorkspaceSnapshot;
@@ -68700,22 +69135,52 @@ var WorkspaceDetailView = ({
68700
69135
  return filterDataByDateKeyRange(monthlyData, range);
68701
69136
  }, [monthlyData, range]);
68702
69137
  const formattedWorkspaceName = displayName || formatWorkspaceName3(workspace?.workspace_name || "", effectiveLineId);
68703
- const workspaceActionType = workspace && "action_type" in workspace ? workspace.action_type : void 0;
68704
- const workspaceAssemblyEnabled = workspace && "line_assembly_enabled" in workspace ? workspace.line_assembly_enabled === true : false;
68705
- const isAssemblyWorkspace = workspaceActionType === "assembly" || workspaceAssemblyEnabled;
68706
- const shouldShowCycleTimeChart = !isUptimeMode && (showCycleTimeChart ?? isAssemblyWorkspace);
68707
- const showIdleBreakdownChart = !shouldShowCycleTimeChart && idleTimeVlmEnabled;
69138
+ const workspaceCycleTimeEligibility = workspace ? {
69139
+ line_assembly_enabled: workspace.line_assembly_enabled,
69140
+ action_family: workspace.action_family,
69141
+ action_type: workspace.action_type
69142
+ } : null;
69143
+ const isAssemblyWorkspace = shouldUseAssemblyCycleTimeLayout(workspaceCycleTimeEligibility);
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({
69156
+ workspace: workspace ? {
69157
+ monitoring_mode: workspace.monitoring_mode,
69158
+ line_assembly_enabled: workspace.line_assembly_enabled,
69159
+ action_family: workspace.action_family,
69160
+ action_type: workspace.action_type
69161
+ } : null,
69162
+ authoritativeMetrics: authoritativeCycleMetrics ? {
69163
+ cycle_time_data_status: authoritativeCycleMetrics.cycle_time_data_status
69164
+ } : null,
69165
+ showCycleTimeChart
69166
+ });
69167
+ const shouldShowCycleTimeChart = cycleTimePresentation === "cycle_chart";
69168
+ const shouldShowCycleTimeUnavailableState = cycleTimePresentation === "cycle_unavailable";
69169
+ const shouldShowCycleTimeLoadingState = cycleTimePresentation === "chart_loading";
69170
+ const shouldShowAssemblyOverviewLoadingState = isAssemblyCycleLayout && shouldShowCycleTimeLoadingState && hasWorkspaceSnapshot;
69171
+ const showIdleBreakdownChart = !isAssemblyCycleLayout && idleTimeVlmEnabled;
69172
+ const canToggleChartIdleTime = !isUptimeMode && !shouldShowCycleTimeLoadingState && !shouldShowCycleTimeUnavailableState;
68708
69173
  const idleClipDate = date || workspace?.date || calculatedOperationalDate || getOperationalDate(timezone);
68709
69174
  const idleClipShiftId = parsedShiftId ?? workspace?.shift_id;
68710
- const hourlyIdleMinutes = useMemo(() => {
69175
+ const rawHourlyIdleMinutes = useMemo(() => {
68711
69176
  if (!shouldShowCycleTimeChart || !workspace?.idle_time_hourly || !workspace?.shift_start) return [];
68712
- const parseTimeToMinutes3 = (time2) => {
69177
+ const parseTimeToMinutes4 = (time2) => {
68713
69178
  const [h, m] = time2.split(":").map(Number);
68714
69179
  if (!Number.isFinite(h) || !Number.isFinite(m)) return 0;
68715
69180
  return h * 60 + m;
68716
69181
  };
68717
- const startTotal = parseTimeToMinutes3(workspace.shift_start);
68718
- 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;
68719
69184
  const endTotal = endTotalRaw <= startTotal ? endTotalRaw + 24 * 60 : endTotalRaw;
68720
69185
  const shiftDuration = Math.max(60, endTotal - startTotal);
68721
69186
  const totalHourSlots = Math.max(1, Math.ceil(shiftDuration / 60));
@@ -68741,6 +69206,42 @@ var WorkspaceDetailView = ({
68741
69206
  }
68742
69207
  return result;
68743
69208
  }, [shouldShowCycleTimeChart, workspace?.idle_time_hourly, workspace?.shift_start, workspace?.shift_end]);
69209
+ const hourlyIdleMinutes = useMemo(
69210
+ () => maskFutureHourlySeries({
69211
+ data: rawHourlyIdleMinutes,
69212
+ shiftStart: workspace?.shift_start,
69213
+ shiftEnd: workspace?.shift_end,
69214
+ shiftDate: idleClipDate,
69215
+ timezone: effectiveCycleTimeTimezone
69216
+ }),
69217
+ [
69218
+ rawHourlyIdleMinutes,
69219
+ workspace?.shift_start,
69220
+ workspace?.shift_end,
69221
+ idleClipDate,
69222
+ effectiveCycleTimeTimezone
69223
+ ]
69224
+ );
69225
+ const cycleTimeUnavailableView = useMemo(() => /* @__PURE__ */ jsxs("div", { className: "w-full h-full rounded-lg border border-amber-200 bg-amber-50/70 px-6 py-5 text-center flex flex-col items-center justify-center", children: [
69226
+ /* @__PURE__ */ jsx("h4", { className: "text-base font-semibold text-amber-900", children: "Cycle data unavailable" }),
69227
+ /* @__PURE__ */ jsx("p", { className: "mt-2 max-w-md text-sm text-amber-800", children: "This workstation has cycle-time metrics for the selected shift, but no matching `cycle_completion` clips were found for the chart." }),
69228
+ typeof workspace?.cycle_completion_clip_count === "number" && /* @__PURE__ */ jsxs("p", { className: "mt-3 text-xs font-medium uppercase tracking-[0.08em] text-amber-700", children: [
69229
+ "matched cycle clips: ",
69230
+ workspace.cycle_completion_clip_count
69231
+ ] })
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
+ ] }), []);
68744
69245
  const shiftDurationMinutes = useMemo(
68745
69246
  () => getShiftDurationMinutes(workspace?.shift_start, workspace?.shift_end),
68746
69247
  [workspace?.shift_start, workspace?.shift_end]
@@ -68795,7 +69296,7 @@ var WorkspaceDetailView = ({
68795
69296
  }, [isUptimeMode, uptimeSeries, shiftDurationMinutes, elapsedShiftMinutes, workspace?.idle_time]);
68796
69297
  const overviewTabLabel = isUptimeMode ? "Utilization" : "Efficiency";
68797
69298
  const idleClipFetchEnabled = Boolean(
68798
- workspaceId && idleClipDate && idleClipShiftId !== void 0 && activeTab === "overview" && idleTimeVlmEnabled && !shouldShowCycleTimeChart && !isUptimeMode
69299
+ workspaceId && idleClipDate && idleClipShiftId !== void 0 && activeTab === "overview" && idleTimeVlmEnabled && isOutputLayout
68799
69300
  );
68800
69301
  const {
68801
69302
  idleClips: idleTimeClips,
@@ -68866,7 +69367,7 @@ var WorkspaceDetailView = ({
68866
69367
  }
68867
69368
  }
68868
69369
  };
68869
- const getShiftIcon = (shiftType) => {
69370
+ const getShiftIcon2 = (shiftType) => {
68870
69371
  const shiftTypeLower = shiftType?.toLowerCase() || "";
68871
69372
  if (shiftTypeLower.includes("day") || shiftTypeLower.includes("morning")) {
68872
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" }) });
@@ -69015,7 +69516,7 @@ var WorkspaceDetailView = ({
69015
69516
  /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: (() => {
69016
69517
  const shift2 = shiftConfig?.shifts?.find((s) => s.shiftId === selectedShift);
69017
69518
  const shiftName = shift2?.shiftName || (selectedShift === 0 ? "Day Shift" : "Night Shift");
69018
- return getShiftIcon(shiftName);
69519
+ return getShiftIcon2(shiftName);
69019
69520
  })() }),
69020
69521
  /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-700", children: (() => {
69021
69522
  const shift2 = shiftConfig?.shifts?.find((s) => s.shiftId === selectedShift);
@@ -69043,7 +69544,7 @@ var WorkspaceDetailView = ({
69043
69544
  /* @__PURE__ */ jsx("div", { className: "opacity-70", children: (() => {
69044
69545
  const shift2 = shiftConfig?.shifts?.find((s) => s.shiftId === selectedShift);
69045
69546
  const shiftName = shift2?.shiftName || (selectedShift === 0 ? "Day Shift" : "Night Shift");
69046
- return getShiftIcon(shiftName);
69547
+ return getShiftIcon2(shiftName);
69047
69548
  })() }),
69048
69549
  /* @__PURE__ */ jsx("span", { className: "text-sm md:text-base font-semibold uppercase tracking-wider", children: (() => {
69049
69550
  const shift2 = shiftConfig?.shifts?.find((s) => s.shiftId === selectedShift);
@@ -69056,7 +69557,7 @@ var WorkspaceDetailView = ({
69056
69557
  /* @__PURE__ */ jsxs("div", { className: "sm:hidden mt-3 flex items-center justify-center gap-2", children: [
69057
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)) }) }),
69058
69559
  /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
69059
- /* @__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) }),
69060
69561
  /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-700", children: workspace.shift_type })
69061
69562
  ] }),
69062
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
@@ -69087,7 +69588,7 @@ var WorkspaceDetailView = ({
69087
69588
  /* @__PURE__ */ jsx("div", { className: "w-px h-4 bg-blue-200" })
69088
69589
  ] }),
69089
69590
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
69090
- /* @__PURE__ */ jsx("div", { className: "opacity-70", children: getShiftIcon(workspace.shift_type) }),
69591
+ /* @__PURE__ */ jsx("div", { className: "opacity-70", children: getShiftIcon2(workspace.shift_type) }),
69091
69592
  /* @__PURE__ */ jsxs("span", { className: "text-sm md:text-base font-semibold uppercase tracking-wider", children: [
69092
69593
  workspace.shift_type.replace(/ Shift$/i, ""),
69093
69594
  " Shift"
@@ -69206,9 +69707,9 @@ var WorkspaceDetailView = ({
69206
69707
  ] })
69207
69708
  ] }),
69208
69709
  /* @__PURE__ */ jsxs("div", { className: "flex-grow p-1.5 sm:p-2 lg:p-4", children: [
69209
- 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: [
69210
69711
  /* @__PURE__ */ jsxs("div", { className: "block lg:hidden space-y-6 pb-6", children: [
69211
- !shouldShowCycleTimeChart && !isUptimeMode && /* @__PURE__ */ jsxs(
69712
+ isOutputLayout && !isUptimeMode && /* @__PURE__ */ jsxs(
69212
69713
  motion.div,
69213
69714
  {
69214
69715
  className: "bg-white rounded-lg shadow-sm p-6 h-[300px]",
@@ -69236,8 +69737,8 @@ var WorkspaceDetailView = ({
69236
69737
  animate: "animate",
69237
69738
  children: [
69238
69739
  /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center mb-4", children: [
69239
- /* @__PURE__ */ jsx("h3", { className: "text-lg font-bold text-gray-700", children: isUptimeMode ? "Machine Utilization" : shouldShowCycleTimeChart ? "Cycle time trend" : "Hourly Output" }),
69240
- !isUptimeMode && /* @__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(
69241
69742
  "button",
69242
69743
  {
69243
69744
  onClick: () => setShowChartIdleTime(!showChartIdleTime),
@@ -69266,19 +69767,19 @@ var WorkspaceDetailView = ({
69266
69767
  timezone,
69267
69768
  elapsedMinutes: elapsedShiftMinutes
69268
69769
  }
69269
- ) : shouldShowCycleTimeChart ? /* @__PURE__ */ jsx(
69770
+ ) : isAssemblyCycleLayout ? shouldShowCycleTimeUnavailableState ? cycleTimeUnavailableView : shouldShowCycleTimeChart ? /* @__PURE__ */ jsx(
69270
69771
  CycleTimeOverTimeChart,
69271
69772
  {
69272
- data: cycleTimeChartData,
69273
- idealCycleTime: workspace.ideal_cycle_time || 0,
69274
- shiftStart: workspace.shift_start || "",
69275
- shiftEnd: workspace.shift_end || "",
69773
+ data: maskedCycleTimeChartData,
69774
+ idealCycleTime: authoritativeCycleMetrics?.ideal_cycle_time || 0,
69775
+ shiftStart: authoritativeCycleMetrics?.shift_start || "",
69776
+ shiftEnd: authoritativeCycleMetrics?.shift_end || "",
69276
69777
  xAxisMode: "hourly",
69277
69778
  datasetKey: cycleTimeDatasetKey,
69278
69779
  showIdleTime: showChartIdleTime,
69279
69780
  idleTimeData: hourlyIdleMinutes
69280
69781
  }
69281
- ) : /* @__PURE__ */ jsx(
69782
+ ) : null : /* @__PURE__ */ jsx(
69282
69783
  HourlyOutputChart2,
69283
69784
  {
69284
69785
  data: workspace.hourly_action_counts || [],
@@ -69298,7 +69799,7 @@ var WorkspaceDetailView = ({
69298
69799
  ]
69299
69800
  }
69300
69801
  ),
69301
- !shouldShowCycleTimeChart && idleTimeVlmEnabled && /* @__PURE__ */ jsxs(
69802
+ showIdleBreakdownChart && /* @__PURE__ */ jsxs(
69302
69803
  motion.div,
69303
69804
  {
69304
69805
  className: "bg-white rounded-lg shadow-sm p-4 h-[300px]",
@@ -69318,7 +69819,7 @@ var WorkspaceDetailView = ({
69318
69819
  ]
69319
69820
  }
69320
69821
  ),
69321
- isUptimeMode ? /* @__PURE__ */ jsx(UptimeMetricCards, { workspace, uptimePieData }) : shouldShowCycleTimeChart ? /* @__PURE__ */ jsx(
69822
+ isUptimeMode ? /* @__PURE__ */ jsx(UptimeMetricCards, { workspace, uptimePieData }) : isAssemblyCycleLayout ? /* @__PURE__ */ jsx(
69322
69823
  WorkspaceCycleTimeMetricCards,
69323
69824
  {
69324
69825
  workspace,
@@ -69338,7 +69839,7 @@ var WorkspaceDetailView = ({
69338
69839
  desktopTopSectionClass
69339
69840
  ),
69340
69841
  children: [
69341
- !shouldShowCycleTimeChart && !isUptimeMode && /* @__PURE__ */ jsxs(
69842
+ isOutputLayout && !isUptimeMode && /* @__PURE__ */ jsxs(
69342
69843
  motion.div,
69343
69844
  {
69344
69845
  className: "bg-white rounded-lg shadow-sm p-4 lg:col-span-2 flex flex-col min-h-0",
@@ -69362,15 +69863,15 @@ var WorkspaceDetailView = ({
69362
69863
  {
69363
69864
  className: clsx(
69364
69865
  "bg-white rounded-lg shadow-sm p-4 flex flex-col min-h-0",
69365
- 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"
69366
69867
  ),
69367
69868
  variants: chartCardVariants,
69368
69869
  initial: "initial",
69369
69870
  animate: "animate",
69370
69871
  children: [
69371
69872
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3 mb-4 flex-none", children: [
69372
- /* @__PURE__ */ jsx("h3", { className: "text-lg font-bold text-gray-700", children: isUptimeMode ? "Machine Utilization" : shouldShowCycleTimeChart ? "Cycle time trend" : "Hourly Output" }),
69373
- !isUptimeMode && /* @__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(
69374
69875
  "button",
69375
69876
  {
69376
69877
  onClick: () => setShowChartIdleTime(!showChartIdleTime),
@@ -69395,19 +69896,19 @@ var WorkspaceDetailView = ({
69395
69896
  timezone,
69396
69897
  elapsedMinutes: elapsedShiftMinutes
69397
69898
  }
69398
- ) : shouldShowCycleTimeChart ? /* @__PURE__ */ jsx(
69899
+ ) : isAssemblyCycleLayout ? shouldShowCycleTimeUnavailableState ? cycleTimeUnavailableView : shouldShowCycleTimeChart ? /* @__PURE__ */ jsx(
69399
69900
  CycleTimeOverTimeChart,
69400
69901
  {
69401
- data: cycleTimeChartData,
69402
- idealCycleTime: workspace.ideal_cycle_time || 0,
69403
- shiftStart: workspace.shift_start || "",
69404
- shiftEnd: workspace.shift_end || "",
69902
+ data: maskedCycleTimeChartData,
69903
+ idealCycleTime: authoritativeCycleMetrics?.ideal_cycle_time || 0,
69904
+ shiftStart: authoritativeCycleMetrics?.shift_start || "",
69905
+ shiftEnd: authoritativeCycleMetrics?.shift_end || "",
69405
69906
  xAxisMode: "hourly",
69406
69907
  datasetKey: cycleTimeDatasetKey,
69407
69908
  showIdleTime: showChartIdleTime,
69408
69909
  idleTimeData: hourlyIdleMinutes
69409
69910
  }
69410
- ) : /* @__PURE__ */ jsx(
69911
+ ) : null : /* @__PURE__ */ jsx(
69411
69912
  HourlyOutputChart2,
69412
69913
  {
69413
69914
  data: workspace.hourly_action_counts || [],
@@ -69425,7 +69926,7 @@ var WorkspaceDetailView = ({
69425
69926
  ]
69426
69927
  }
69427
69928
  ),
69428
- !shouldShowCycleTimeChart && idleTimeVlmEnabled && /* @__PURE__ */ jsxs(
69929
+ showIdleBreakdownChart && /* @__PURE__ */ jsxs(
69429
69930
  motion.div,
69430
69931
  {
69431
69932
  className: clsx(
@@ -69451,7 +69952,7 @@ var WorkspaceDetailView = ({
69451
69952
  ]
69452
69953
  }
69453
69954
  ),
69454
- 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(
69455
69956
  WorkspaceCycleTimeMetricCards,
69456
69957
  {
69457
69958
  workspace,
@@ -69462,7 +69963,7 @@ var WorkspaceDetailView = ({
69462
69963
  }
69463
69964
  ) : /* @__PURE__ */ jsx("div", { className: clsx("flex min-h-0", desktopBottomSectionClass), children: /* @__PURE__ */ jsx(WorkspaceMetricCards, { workspace, legend: efficiencyLegend, className: "flex-1" }) })
69464
69965
  ] })
69465
- ] }),
69966
+ ] }) }),
69466
69967
  activeTab === "monthly_history" && /* @__PURE__ */ jsxs("div", { className: "h-[calc(100vh-10rem)] overflow-y-auto px-2 sm:px-4 lg:px-0", children: [
69467
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: [
69468
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" }) }),
@@ -72094,7 +72595,7 @@ var normalizeLabel = (value) => {
72094
72595
  const trimmed = value.trim();
72095
72596
  return trimmed.length > 0 ? trimmed : void 0;
72096
72597
  };
72097
- var toFiniteNumber = (value) => {
72598
+ var toFiniteNumber2 = (value) => {
72098
72599
  if (typeof value === "number" && Number.isFinite(value)) return value;
72099
72600
  if (typeof value === "string" && value.trim().length > 0) {
72100
72601
  const parsed = Number(value);
@@ -72128,7 +72629,7 @@ var formatImprovementPieceGain = (pcsGain) => {
72128
72629
  var getPositiveImprovementGain = ({
72129
72630
  estimated_gain_pieces
72130
72631
  }) => {
72131
- const issueGain = toFiniteNumber(estimated_gain_pieces);
72632
+ const issueGain = toFiniteNumber2(estimated_gain_pieces);
72132
72633
  return {
72133
72634
  pcsGain: issueGain !== null && issueGain > 0 ? issueGain : null
72134
72635
  };
@@ -72136,7 +72637,7 @@ var getPositiveImprovementGain = ({
72136
72637
  var getImprovementPcsGainSortValue = (input) => {
72137
72638
  const { pcsGain } = getPositiveImprovementGain(input);
72138
72639
  if (pcsGain !== null) return pcsGain;
72139
- const raw = toFiniteNumber(input.estimated_gain_pieces);
72640
+ const raw = toFiniteNumber2(input.estimated_gain_pieces);
72140
72641
  return raw ?? null;
72141
72642
  };
72142
72643
  var getImprovementDisplayMetadata = ({
@@ -72156,7 +72657,7 @@ var getImprovementDisplayMetadata = ({
72156
72657
  metadataLabel: [workstationLabel, lineLabel, supervisorLabel].join(" \xB7 ")
72157
72658
  };
72158
72659
  };
72159
- var toFiniteNumber2 = (value) => {
72660
+ var toFiniteNumber3 = (value) => {
72160
72661
  if (typeof value === "number" && Number.isFinite(value)) return value;
72161
72662
  if (typeof value === "string" && value.trim().length > 0) {
72162
72663
  const parsed = Number(value);
@@ -72184,15 +72685,15 @@ var compareImprovementRecommendationPriority = (left, right) => {
72184
72685
  if (leftIndustrial !== rightIndustrial) {
72185
72686
  return rightIndustrial - leftIndustrial;
72186
72687
  }
72187
- const leftGain = toFiniteNumber2(left.estimated_gain_pieces);
72188
- const rightGain = toFiniteNumber2(right.estimated_gain_pieces);
72688
+ const leftGain = toFiniteNumber3(left.estimated_gain_pieces);
72689
+ const rightGain = toFiniteNumber3(right.estimated_gain_pieces);
72189
72690
  if (leftGain !== rightGain) {
72190
72691
  if (leftGain === null) return 1;
72191
72692
  if (rightGain === null) return -1;
72192
72693
  return rightGain - leftGain;
72193
72694
  }
72194
- const leftRatio = toFiniteNumber2(left.gain_to_target_ratio);
72195
- 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);
72196
72697
  if (leftRatio !== rightRatio) {
72197
72698
  if (leftRatio === null) return 1;
72198
72699
  if (rightRatio === null) return -1;
@@ -75497,6 +75998,7 @@ var EMPTY_OVERVIEW_POOREST_LINES = {
75497
75998
  };
75498
75999
  var EMPTY_OVERVIEW_TREND = {
75499
76000
  shift_mode: "all",
76001
+ granularity: "day",
75500
76002
  points: []
75501
76003
  };
75502
76004
  var EMPTY_IDLE_BREAKDOWN = [];
@@ -75569,8 +76071,11 @@ var normalizePoorestLines = (value) => ({
75569
76071
  });
75570
76072
  var normalizeTrend = (value) => ({
75571
76073
  shift_mode: value?.shift_mode || "all",
76074
+ granularity: value?.granularity === "hour" ? "hour" : "day",
75572
76075
  points: (value?.points || []).map((point) => ({
75573
76076
  date: point?.date,
76077
+ label: point?.label,
76078
+ hour_index: normalizeNumber(point?.hour_index),
75574
76079
  avg_efficiency: normalizeNumber(point?.avg_efficiency)
75575
76080
  }))
75576
76081
  });
@@ -75912,17 +76417,25 @@ var formatSignedIdleDuration = (seconds) => {
75912
76417
  const sign = seconds > 0 ? "+" : "-";
75913
76418
  return `${sign}${formatIdleDuration(Math.abs(seconds))}`;
75914
76419
  };
75915
- var formatComparisonWindow = (dayCount, comparisonStrategy) => {
76420
+ var formatComparisonWindow = ({
76421
+ currentDayCount,
76422
+ previousDayCount,
76423
+ comparisonStrategy,
76424
+ shiftMode
76425
+ }) => {
75916
76426
  if (comparisonStrategy === "previous_full_week") return "last week";
75917
- if (!dayCount || !Number.isFinite(dayCount)) return "previous range";
75918
- 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"}`;
75919
76432
  };
75920
76433
  var buildDeltaBadge = (delta, options) => {
75921
76434
  if (delta === null || delta === void 0 || !Number.isFinite(delta)) {
75922
76435
  return {
75923
76436
  icon: null,
75924
- className: "bg-slate-100 text-slate-500",
75925
- text: `No ${options.comparisonLabel} baseline`
76437
+ className: "bg-slate-100 text-slate-400",
76438
+ text: "\u2014"
75926
76439
  };
75927
76440
  }
75928
76441
  const direction = delta >= 0 ? "up" : "down";
@@ -75933,6 +76446,25 @@ var buildDeltaBadge = (delta, options) => {
75933
76446
  text: `${options.formatter(delta)} vs ${options.comparisonLabel}`
75934
76447
  };
75935
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
+ };
75936
76468
  var buildLineDeltaTone = (delta, comparisonLabel) => {
75937
76469
  if (delta === null || delta === void 0 || !Number.isFinite(delta)) {
75938
76470
  return {
@@ -75988,6 +76520,8 @@ var OperationsOverviewHeader = React141__default.memo(({
75988
76520
  dateRange,
75989
76521
  displayDateRange,
75990
76522
  trendMode,
76523
+ isLiveScope,
76524
+ liveShiftName,
75991
76525
  lineOptions,
75992
76526
  supervisorOptions,
75993
76527
  selectedSupervisorId,
@@ -76001,6 +76535,14 @@ var OperationsOverviewHeader = React141__default.memo(({
76001
76535
  }) => {
76002
76536
  bumpRenderCounter();
76003
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
+ );
76004
76546
  const [isFilterOpen, setIsFilterOpen] = React141__default.useState(false);
76005
76547
  const [isLinesDropdownOpen, setIsLinesDropdownOpen] = React141__default.useState(false);
76006
76548
  const filterRef = React141__default.useRef(null);
@@ -76117,9 +76659,25 @@ var OperationsOverviewHeader = React141__default.memo(({
76117
76659
  className: "flex-shrink-0 -ml-1"
76118
76660
  }
76119
76661
  ) : /* @__PURE__ */ jsx("div", { className: "w-8 flex-shrink-0" }),
76120
- /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col items-center justify-center", children: [
76121
- /* @__PURE__ */ jsx("h1", { className: "text-lg font-semibold text-gray-900 text-center px-1 truncate max-w-[200px]", children: "Operations Overview" }),
76122
- /* @__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
+ ] })
76123
76681
  ] }),
76124
76682
  /* @__PURE__ */ jsxs("div", { className: "flex-shrink-0 flex items-center gap-1.5", children: [
76125
76683
  /* @__PURE__ */ jsx(
@@ -76138,22 +76696,40 @@ var OperationsOverviewHeader = React141__default.memo(({
76138
76696
  {
76139
76697
  ref: mobileFilterButtonRef,
76140
76698
  onClick: handleFilterToggle,
76141
- 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"}`,
76142
76700
  "aria-label": "Open filters",
76143
76701
  children: [
76144
- /* @__PURE__ */ jsx(Filter, { className: `w-5 h-5 ${activeFilterCount > 0 ? "text-blue-600" : "text-gray-700"}` }),
76145
- 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
76146
76704
  ]
76147
76705
  }
76148
76706
  )
76149
76707
  ] })
76150
76708
  ] }) }),
76151
- /* @__PURE__ */ jsx("div", { className: "hidden sm:block", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center relative min-h-[56px]", children: [
76152
- /* @__PURE__ */ jsxs("div", { className: "absolute left-1/2 -translate-x-1/2 flex flex-col items-center pointer-events-none", children: [
76153
- /* @__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" }),
76154
- /* @__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
+ ] })
76155
76731
  ] }),
76156
- /* @__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: [
76157
76733
  /* @__PURE__ */ jsx("div", { className: "flex items-center", children: /* @__PURE__ */ jsx(
76158
76734
  MonthlyRangeFilter_default,
76159
76735
  {
@@ -76170,12 +76746,12 @@ var OperationsOverviewHeader = React141__default.memo(({
76170
76746
  {
76171
76747
  ref: filterButtonRef,
76172
76748
  onClick: handleFilterToggle,
76173
- 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"}`,
76174
76750
  "aria-label": "Open filters",
76175
76751
  children: [
76176
- /* @__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"}` }),
76177
76753
  "Filters",
76178
- /* @__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" : ""}` })
76179
76755
  ]
76180
76756
  }
76181
76757
  )
@@ -76303,11 +76879,18 @@ var OverviewSummaryCards = React141__default.memo(({ store }) => {
76303
76879
  const snapshot = useOperationsOverviewSnapshot(store);
76304
76880
  const showSnapshotSkeleton = snapshot.loading && !snapshot.hasLoadedOnce;
76305
76881
  const comparisonLabel = React141__default.useMemo(() => {
76306
- return formatComparisonWindow(
76307
- scope.previous_range?.day_count ?? null,
76308
- scope.comparison_strategy
76309
- );
76310
- }, [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
+ ]);
76311
76894
  const [isIdleContributorsOpen, setIsIdleContributorsOpen] = React141__default.useState(false);
76312
76895
  const [isIdleContributorsPinned, setIsIdleContributorsPinned] = React141__default.useState(false);
76313
76896
  const idleContributorsRef = React141__default.useRef(null);
@@ -76397,10 +76980,17 @@ var OverviewSummaryCards = React141__default.memo(({ store }) => {
76397
76980
  roundOne(snapshot.data.summary.plant_efficiency.current),
76398
76981
  "%"
76399
76982
  ] }),
76400
- /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-1 px-2.5 py-1 rounded-full ${plantEfficiencyBadge.className}`, children: [
76401
- 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,
76402
- /* @__PURE__ */ jsx("span", { className: "text-xs sm:text-sm font-medium", children: plantEfficiencyBadge.text })
76403
- ] })
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
+ )
76404
76994
  ] }) : /* @__PURE__ */ jsx("div", { className: "mt-2 text-sm text-slate-400", children: "No efficiency data available" })
76405
76995
  ] }),
76406
76996
  /* @__PURE__ */ jsxs(
@@ -76446,10 +77036,17 @@ var OverviewSummaryCards = React141__default.memo(({ store }) => {
76446
77036
  /* @__PURE__ */ jsx("div", { className: "mb-1", children: /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-gray-700", children: "Idle Time per Workstation" }) }),
76447
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: [
76448
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) }),
76449
- /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-1 px-2.5 py-1 rounded-full ${idleBadge.className}`, children: [
76450
- 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,
76451
- /* @__PURE__ */ jsx("span", { className: "text-xs sm:text-sm font-medium", children: idleBadge.text })
76452
- ] })
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
+ )
76453
77050
  ] }) : /* @__PURE__ */ jsx("div", { className: "mt-2 text-sm text-slate-400", children: "No idle time data available" })
76454
77051
  ]
76455
77052
  }
@@ -76512,11 +77109,18 @@ var PoorestPerformersCard = React141__default.memo(({
76512
77109
  }
76513
77110
  }, [availableLineModes?.has_output, availableLineModes?.has_uptime, poorestLineMode]);
76514
77111
  const comparisonLabel = React141__default.useMemo(() => {
76515
- return formatComparisonWindow(
76516
- scope.previous_range?.day_count ?? null,
76517
- scope.comparison_strategy
76518
- );
76519
- }, [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
+ ]);
76520
77124
  const showSnapshotSkeleton = snapshot.loading && !snapshot.hasLoadedOnce;
76521
77125
  const mergedPoorestLines = React141__default.useMemo(() => {
76522
77126
  const rows = snapshot.data.poorest_lines?.[poorestLineMode] || [];
@@ -76673,7 +77277,8 @@ IdleBreakdownCard.displayName = "IdleBreakdownCard";
76673
77277
  var EfficiencyTrendCard = React141__default.memo(({
76674
77278
  store,
76675
77279
  dateRange,
76676
- appTimezone
77280
+ appTimezone,
77281
+ hourlyLabelStartTime
76677
77282
  }) => {
76678
77283
  bumpRenderCounter();
76679
77284
  const trend = useOperationsOverviewTrend(store);
@@ -76683,7 +77288,41 @@ var EfficiencyTrendCard = React141__default.memo(({
76683
77288
  );
76684
77289
  const isCurrentWeekToDateRange = dateRange.startKey === currentWeekRange.startKey && dateRange.endKey === currentWeekRange.endKey;
76685
77290
  const showInitialSkeleton = trend.loading && trend.lastUpdated === null;
77291
+ const isHourlyTrend = trend.data.granularity === "hour";
76686
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
+ }
76687
77326
  const pointsByDate = new Map(
76688
77327
  (trend.data.points || []).flatMap((point) => {
76689
77328
  if (!point.date) return [];
@@ -76721,12 +77360,13 @@ var EfficiencyTrendCard = React141__default.memo(({
76721
77360
  })()
76722
77361
  };
76723
77362
  });
76724
- }, [currentWeekRange.startKey, isCurrentWeekToDateRange, trend.data.points]);
77363
+ }, [currentWeekRange.startKey, hourlyLabelStartTime, isCurrentWeekToDateRange, isHourlyTrend, trend.data.points]);
76725
77364
  const trendTooltipLabelFormatter = React141__default.useCallback((label, payload) => {
77365
+ if (isHourlyTrend) return label;
76726
77366
  const dayOfWeek = payload?.[0]?.payload?.dayOfWeek;
76727
77367
  if (!dayOfWeek || typeof label !== "string") return label;
76728
77368
  return `${label} (${dayOfWeek})`;
76729
- }, []);
77369
+ }, [isHourlyTrend]);
76730
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: [
76731
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" }) }),
76732
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(
@@ -76880,7 +77520,8 @@ var useOperationsOverviewRefresh = ({
76880
77520
  endKey,
76881
77521
  trendMode,
76882
77522
  comparisonStrategy,
76883
- isLiveScope
77523
+ isLiveScope,
77524
+ enabled = true
76884
77525
  }) => {
76885
77526
  const lineIdsKey = React141__default.useMemo(() => lineIds.join(","), [lineIds]);
76886
77527
  const scopeSignature = React141__default.useMemo(
@@ -76926,7 +77567,7 @@ var useOperationsOverviewRefresh = ({
76926
77567
  }, []);
76927
77568
  const runRefresh = React141__default.useCallback(
76928
77569
  async (section, begin, onSuccess, onError, request, reason) => {
76929
- if (!supabase || !companyId || lineIds.length === 0) return;
77570
+ if (!enabled || !supabase || !companyId || lineIds.length === 0) return;
76930
77571
  const requestId = requestIdsRef.current[section] + 1;
76931
77572
  requestIdsRef.current[section] = requestId;
76932
77573
  controllersRef.current[section]?.abort();
@@ -76946,7 +77587,7 @@ var useOperationsOverviewRefresh = ({
76946
77587
  onError(error instanceof Error ? error.message : `Failed to refresh ${section}`);
76947
77588
  }
76948
77589
  },
76949
- [companyId, lineIds.length, supabase]
77590
+ [companyId, enabled, lineIds.length, supabase]
76950
77591
  );
76951
77592
  const refreshSnapshot = React141__default.useCallback(
76952
77593
  async (reason) => {
@@ -77116,6 +77757,12 @@ var useOperationsOverviewRefresh = ({
77116
77757
  });
77117
77758
  }, [refreshAll, startPolling, stopPolling]);
77118
77759
  React141__default.useEffect(() => {
77760
+ if (!enabled) {
77761
+ stopPolling("disabled");
77762
+ abortAll();
77763
+ store.reset();
77764
+ return;
77765
+ }
77119
77766
  if (!supabase || !companyId || lineIds.length === 0) {
77120
77767
  stopPolling("scope_invalid");
77121
77768
  abortAll();
@@ -77123,9 +77770,9 @@ var useOperationsOverviewRefresh = ({
77123
77770
  return;
77124
77771
  }
77125
77772
  void refreshAll("scope_change");
77126
- }, [abortAll, companyId, lineIds.length, refreshAll, scopeSignature, stopPolling, store, supabase]);
77773
+ }, [abortAll, companyId, enabled, lineIds.length, refreshAll, scopeSignature, stopPolling, store, supabase]);
77127
77774
  React141__default.useEffect(() => {
77128
- if (!isLiveScope || !supabase || !companyId || lineIds.length === 0) {
77775
+ if (!enabled || !isLiveScope || !supabase || !companyId || lineIds.length === 0) {
77129
77776
  isPageActiveRef.current = false;
77130
77777
  stopPolling("live_scope_disabled");
77131
77778
  return;
@@ -77181,11 +77828,63 @@ var useOperationsOverviewRefresh = ({
77181
77828
  window.removeEventListener("pageshow", handlePageShow);
77182
77829
  window.removeEventListener("pagehide", handlePageHide);
77183
77830
  };
77184
- }, [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;
77185
77882
  };
77186
77883
  var PlantHeadView = () => {
77187
77884
  const supabase = useSupabase();
77188
77885
  const entityConfig = useEntityConfig();
77886
+ const factoryViewId = entityConfig.factoryViewId || "factory";
77887
+ const staticShiftConfig = useShiftConfig();
77189
77888
  const appTimezone = useAppTimezone() || "UTC";
77190
77889
  const { navigate } = useNavigation();
77191
77890
  const { accessibleLineIds } = useUserLineAccess();
@@ -77193,11 +77892,21 @@ var PlantHeadView = () => {
77193
77892
  useHideMobileHeader(!!mobileMenuContext);
77194
77893
  const storeRef = React141__default.useRef(createOperationsOverviewStore());
77195
77894
  const store = storeRef.current;
77196
- const [dateRange, setDateRange] = React141__default.useState(() => getCurrentWeekToDateRange(appTimezone));
77197
- 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);
77198
77904
  const [trendMode, setTrendMode] = React141__default.useState("all");
77199
77905
  const [selectedSupervisorId, setSelectedSupervisorId] = React141__default.useState("all");
77200
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);
77201
77910
  React141__default.useEffect(() => {
77202
77911
  trackCorePageView("Operations Overview", {
77203
77912
  dashboard_surface: "operations_overview"
@@ -77219,8 +77928,10 @@ var PlantHeadView = () => {
77219
77928
  return dateRange;
77220
77929
  }, [currentWeekDisplayRange, dateRange, isCurrentWeekToDateRange, usesThisWeekComparison]);
77221
77930
  const normalizedLineIds = React141__default.useMemo(
77222
- () => Array.from(new Set((accessibleLineIds || []).filter(Boolean))).sort(),
77223
- [accessibleLineIds]
77931
+ () => Array.from(new Set(
77932
+ (accessibleLineIds || []).filter(Boolean).filter((lineId) => lineId !== factoryViewId)
77933
+ )).sort(),
77934
+ [accessibleLineIds, factoryViewId]
77224
77935
  );
77225
77936
  const lineIdsKey = React141__default.useMemo(
77226
77937
  () => normalizedLineIds.join(","),
@@ -77294,14 +78005,81 @@ var PlantHeadView = () => {
77294
78005
  () => selectedLineIds.length > 0 ? selectedLineIds : normalizedLineIds,
77295
78006
  [normalizedLineIds, selectedLineIds]
77296
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
+ );
77297
78041
  const initializedTimezoneRef = React141__default.useRef(appTimezone);
77298
78042
  React141__default.useEffect(() => {
77299
78043
  if (initializedTimezoneRef.current === appTimezone) return;
77300
- setDateRange(getCurrentWeekToDateRange(appTimezone));
77301
- 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);
77302
78053
  initializedTimezoneRef.current = appTimezone;
77303
- }, [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]);
77304
78080
  const handleDateRangeChange = React141__default.useCallback((range, meta) => {
78081
+ hasUserAdjustedScopeRef.current = true;
78082
+ setIsInitialScopeReady(true);
77305
78083
  trackCoreEvent("Operations Overview Date Range Changed", {
77306
78084
  start_date: range.startKey,
77307
78085
  end_date: range.endKey
@@ -77318,6 +78096,8 @@ var PlantHeadView = () => {
77318
78096
  });
77319
78097
  }, []);
77320
78098
  const handleTrendModeChange = React141__default.useCallback((mode) => {
78099
+ hasUserAdjustedScopeRef.current = true;
78100
+ setIsInitialScopeReady(true);
77321
78101
  setTrendMode(mode);
77322
78102
  }, []);
77323
78103
  const handleSelectedLineIdsChange = React141__default.useCallback((lineIds) => {
@@ -77344,15 +78124,6 @@ var PlantHeadView = () => {
77344
78124
  params.set("rangeEnd", dateRange.endKey);
77345
78125
  return `/kpis/${lineId}?${params.toString()}`;
77346
78126
  }, [dateRange.endKey, dateRange.startKey]);
77347
- const handleOpenLineMonthlyHistory = React141__default.useCallback((lineId, lineName) => {
77348
- trackCoreEvent("Operations Overview Line Clicked", {
77349
- line_id: lineId,
77350
- line_name: lineName,
77351
- range_start: dateRange.startKey,
77352
- range_end: dateRange.endKey
77353
- });
77354
- navigate(buildLineMonthlyHistoryUrl(lineId));
77355
- }, [buildLineMonthlyHistoryUrl, dateRange.endKey, dateRange.startKey, navigate]);
77356
78127
  const handleViewAllPoorestPerformers = React141__default.useCallback(() => {
77357
78128
  trackCoreEvent("Operations Overview View All Clicked", { section: "poorest_performers" });
77358
78129
  navigate("/kpis?tab=leaderboard");
@@ -77378,16 +78149,74 @@ var PlantHeadView = () => {
77378
78149
  }
77379
78150
  return void 0;
77380
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]);
77381
78209
  useOperationsOverviewRefresh({
77382
78210
  store,
77383
78211
  supabase,
77384
78212
  companyId: entityConfig.companyId,
77385
78213
  lineIds: scopedLineIds,
77386
- startKey: dateRange.startKey,
77387
- endKey: dateRange.endKey,
77388
- trendMode,
78214
+ startKey: effectiveDateRange.startKey,
78215
+ endKey: effectiveDateRange.endKey,
78216
+ trendMode: effectiveTrendMode,
77389
78217
  comparisonStrategy,
77390
- isLiveScope: isCurrentWeekToDateRange
78218
+ isLiveScope,
78219
+ enabled: scopedLineIds.length > 0 && isShiftScopeResolved
77391
78220
  });
77392
78221
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col min-h-screen bg-slate-50 w-full font-sans", children: [
77393
78222
  /* @__PURE__ */ jsx(
@@ -77396,6 +78225,8 @@ var PlantHeadView = () => {
77396
78225
  dateRange,
77397
78226
  displayDateRange: headerDateRange,
77398
78227
  trendMode,
78228
+ isLiveScope,
78229
+ liveShiftName: currentShiftScope?.shiftName || null,
77399
78230
  lineOptions,
77400
78231
  supervisorOptions,
77401
78232
  selectedSupervisorId,
@@ -77418,7 +78249,7 @@ var PlantHeadView = () => {
77418
78249
  store,
77419
78250
  supervisorsByLineId,
77420
78251
  onViewAll: handleViewAllPoorestPerformers,
77421
- onLineClick: handleOpenLineMonthlyHistory
78252
+ onLineClick: handleOpenLineDetails
77422
78253
  }
77423
78254
  ),
77424
78255
  /* @__PURE__ */ jsx(
@@ -77435,7 +78266,8 @@ var PlantHeadView = () => {
77435
78266
  {
77436
78267
  store,
77437
78268
  dateRange,
77438
- appTimezone
78269
+ appTimezone,
78270
+ hourlyLabelStartTime
77439
78271
  }
77440
78272
  ),
77441
78273
  /* @__PURE__ */ jsx(
@@ -77929,4 +78761,4 @@ var streamProxyConfig = {
77929
78761
  }
77930
78762
  };
77931
78763
 
77932
- 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 };