@optifye/dashboard-core 6.11.11 → 6.11.13

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
@@ -10,8 +10,8 @@ import { EventEmitter } from 'events';
10
10
  import { createClient, REALTIME_SUBSCRIBE_STATES } from '@supabase/supabase-js';
11
11
  import Hls, { Events, ErrorTypes } from 'hls.js';
12
12
  import useSWR from 'swr';
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';
13
14
  import { memo, noop, warning, invariant, progress, secondsToMilliseconds, millisecondsToSeconds } from 'motion-utils';
14
- 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, Wrench, XCircle, Package, UserX, Zap, HelpCircle, Tag, Palette, CheckCircle2, RefreshCw, TrendingDown, FolderOpen, Folder, Sliders, Activity, 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, Flame, Crown, Medal } from 'lucide-react';
15
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';
16
16
  import { Slot } from '@radix-ui/react-slot';
17
17
  import * as SelectPrimitive from '@radix-ui/react-select';
@@ -3417,6 +3417,25 @@ function isValidFactoryViewConfiguration(entityConfig) {
3417
3417
  return lineIds.length > 0;
3418
3418
  }
3419
3419
 
3420
+ // src/lib/constants/videoGridMetricMode.ts
3421
+ var VALID_VIDEO_GRID_METRIC_MODES = /* @__PURE__ */ new Set([
3422
+ "efficiency",
3423
+ "recent_flow",
3424
+ "recent_flow_wip_gated"
3425
+ ]);
3426
+ var normalizeVideoGridMetricMode = (value, assemblyEnabled = false) => {
3427
+ const normalized = typeof value === "string" ? value.trim().toLowerCase() : "";
3428
+ if (VALID_VIDEO_GRID_METRIC_MODES.has(normalized)) {
3429
+ return normalized;
3430
+ }
3431
+ return assemblyEnabled ? "recent_flow_wip_gated" : "efficiency";
3432
+ };
3433
+ var isRecentFlowVideoGridMetricMode = (value, assemblyEnabled = false) => {
3434
+ const normalized = normalizeVideoGridMetricMode(value, assemblyEnabled);
3435
+ return normalized === "recent_flow" || normalized === "recent_flow_wip_gated";
3436
+ };
3437
+ var isWipGatedVideoGridMetricMode = (value, assemblyEnabled = false) => normalizeVideoGridMetricMode(value, assemblyEnabled) === "recent_flow_wip_gated";
3438
+
3420
3439
  // src/lib/services/lineMetricsSelection.ts
3421
3440
  var toTimestamp = (value) => {
3422
3441
  if (typeof value !== "string") return 0;
@@ -3878,7 +3897,7 @@ var dashboardService = {
3878
3897
  company_name: data.company_name || "Company X",
3879
3898
  date: data.date,
3880
3899
  shift_id: data.shift_id,
3881
- action_name: data.action_name || "",
3900
+ action_name: data.action_display_name || data.action_name || "",
3882
3901
  shift_start: data.shift_start || (data.shift_id === (shiftConfig.dayShift?.id ?? 0) ? shiftConfig.dayShift?.startTime : shiftConfig.nightShift?.startTime) || "00:00",
3883
3902
  shift_end: data.shift_end || (data.shift_id === (shiftConfig.dayShift?.id ?? 0) ? shiftConfig.dayShift?.endTime : shiftConfig.nightShift?.endTime) || "00:00",
3884
3903
  shift_type: data.shift_type || (data.shift_id === (shiftConfig.dayShift?.id ?? 0) ? "Day" : "Night"),
@@ -3947,7 +3966,9 @@ var dashboardService = {
3947
3966
  company_id,
3948
3967
  companies!lines_company_id_fkey(company_name:name),
3949
3968
  enable,
3950
- monitoring_mode
3969
+ monitoring_mode,
3970
+ assembly,
3971
+ video_grid_metric_mode
3951
3972
  `).eq("enable", true);
3952
3973
  if (companyId) {
3953
3974
  query = query.eq("company_id", companyId);
@@ -3967,7 +3988,12 @@ var dashboardService = {
3967
3988
  company_name: line.companies?.company_name ?? "N/A",
3968
3989
  enable: line.enable ?? true,
3969
3990
  // Default to true if not specified
3970
- monitoring_mode: line.monitoring_mode ?? "output"
3991
+ monitoring_mode: line.monitoring_mode ?? "output",
3992
+ assembly: line.assembly ?? false,
3993
+ video_grid_metric_mode: normalizeVideoGridMetricMode(
3994
+ line.video_grid_metric_mode,
3995
+ line.assembly ?? false
3996
+ )
3971
3997
  }));
3972
3998
  return transformedLines;
3973
3999
  } catch (err) {
@@ -4004,7 +4030,7 @@ var dashboardService = {
4004
4030
  }
4005
4031
  const lineIdsToQuery = configuredLineIds;
4006
4032
  const [line1Result, metricsResult2] = await Promise.all([
4007
- supabase.from(linesTable).select("id, line_name, factory_id, monitoring_mode, factories!lines_factory_id_fkey(factory_name), company_id, companies!lines_company_id_fkey(company_name:name)").eq("id", defaultLineId).single(),
4033
+ supabase.from(linesTable).select("id, line_name, factory_id, monitoring_mode, assembly, video_grid_metric_mode, factories!lines_factory_id_fkey(factory_name), company_id, companies!lines_company_id_fkey(company_name:name)").eq("id", defaultLineId).single(),
4008
4034
  supabase.from(lineMetricsTable).select("*").in("line_id", lineIdsToQuery).eq("shift_id", queryShiftId).eq("date", queryDate)
4009
4035
  ]);
4010
4036
  if (line1Result.error) throw line1Result.error;
@@ -4083,7 +4109,7 @@ var dashboardService = {
4083
4109
  throw new Error("Company ID must be configured for detailed line requests.");
4084
4110
  }
4085
4111
  const [lineResult, metricsResult] = await Promise.all([
4086
- supabase.from(linesTable).select("id, line_name, factory_id, monitoring_mode, factories!lines_factory_id_fkey(factory_name), company_id, companies!lines_company_id_fkey(company_name:name)").eq("id", lineIdToQuery).single(),
4112
+ supabase.from(linesTable).select("id, line_name, factory_id, monitoring_mode, assembly, video_grid_metric_mode, factories!lines_factory_id_fkey(factory_name), company_id, companies!lines_company_id_fkey(company_name:name)").eq("id", lineIdToQuery).single(),
4087
4113
  supabase.from(lineMetricsTable).select("*").eq("line_id", lineIdToQuery).eq("shift_id", queryShiftId).eq("date", queryDate)
4088
4114
  ]);
4089
4115
  if (lineResult.error) throw lineResult.error;
@@ -4899,25 +4925,25 @@ var workspaceService = {
4899
4925
  if (!configuredFactoryId) {
4900
4926
  throw new Error("Factory ID (entityConfig.factoryId) must be configured to update line thresholds.");
4901
4927
  }
4902
- let outputWorkspaces = workspaces.filter((ws) => ws.action_type === "packaging");
4928
+ let outputWorkspaces = workspaces.filter((ws) => ws.action_type === "output");
4903
4929
  if (outputWorkspaces.length === 0) {
4904
- const packagingKeywords = ["packaging", "package", "packing", "pack"];
4905
- const possiblePackagingWorkspaces = workspaces.filter((ws) => {
4930
+ const outputKeywords = ["output", "packaging", "package", "packing", "pack"];
4931
+ const possibleOutputWorkspaces = workspaces.filter((ws) => {
4906
4932
  if (ws.workspace_id && typeof ws.workspace_id === "string") {
4907
4933
  const wsIdLower = ws.workspace_id.toLowerCase();
4908
- return packagingKeywords.some((keyword) => wsIdLower.includes(keyword));
4934
+ return outputKeywords.some((keyword) => wsIdLower.includes(keyword));
4909
4935
  }
4910
4936
  return false;
4911
4937
  });
4912
- if (possiblePackagingWorkspaces.length > 0) {
4913
- outputWorkspaces = possiblePackagingWorkspaces;
4938
+ if (possibleOutputWorkspaces.length > 0) {
4939
+ outputWorkspaces = possibleOutputWorkspaces;
4914
4940
  } else {
4915
- console.warn("[WorkspaceService] Unable to determine packaging workspaces for threshold calculation. Using all workspaces.");
4941
+ console.warn("[WorkspaceService] Unable to determine output-family workspaces for threshold calculation. Using all workspaces.");
4916
4942
  outputWorkspaces = workspaces;
4917
4943
  }
4918
4944
  }
4919
4945
  if (outputWorkspaces.length === 0 && workspaces.length > 0) {
4920
- console.warn('[WorkspaceService] No workspaces with action_type "packaging" found for line threshold calculation. Thresholds might be zero.');
4946
+ console.warn('[WorkspaceService] No workspaces with action_type "output" found for line threshold calculation. Thresholds might be zero.');
4921
4947
  }
4922
4948
  const totalDayOutput = outputWorkspaces.reduce((sum, ws) => sum + (ws.action_total_day_output || 0), 0);
4923
4949
  const totalPPH = outputWorkspaces.reduce((sum, ws) => sum + (ws.action_pph_threshold || 0), 0);
@@ -8437,7 +8463,11 @@ var LinesService = class {
8437
8463
  createdAt: line.created_at,
8438
8464
  factoryId: line.factory_id,
8439
8465
  monitoringMode: line.monitoring_mode ?? "output",
8440
- assembly: line.assembly ?? false
8466
+ assembly: line.assembly ?? false,
8467
+ videoGridMetricMode: normalizeVideoGridMetricMode(
8468
+ line.video_grid_metric_mode,
8469
+ line.assembly ?? false
8470
+ )
8441
8471
  }));
8442
8472
  } catch (error) {
8443
8473
  console.error("Error fetching lines:", error);
@@ -8481,7 +8511,11 @@ var LinesService = class {
8481
8511
  createdAt: line.created_at,
8482
8512
  factoryId: line.factory_id,
8483
8513
  monitoringMode: line.monitoring_mode ?? "output",
8484
- assembly: line.assembly ?? false
8514
+ assembly: line.assembly ?? false,
8515
+ videoGridMetricMode: normalizeVideoGridMetricMode(
8516
+ line.video_grid_metric_mode,
8517
+ line.assembly ?? false
8518
+ )
8485
8519
  }));
8486
8520
  } catch (error) {
8487
8521
  console.error("Error fetching all lines:", error);
@@ -8533,7 +8567,12 @@ var LinesService = class {
8533
8567
  isActive: data.enable,
8534
8568
  createdAt: data.created_at,
8535
8569
  factoryId: data.factory_id,
8536
- monitoringMode: data.monitoring_mode ?? "output"
8570
+ monitoringMode: data.monitoring_mode ?? "output",
8571
+ assembly: data.assembly ?? false,
8572
+ videoGridMetricMode: normalizeVideoGridMetricMode(
8573
+ data.video_grid_metric_mode,
8574
+ data.assembly ?? false
8575
+ )
8537
8576
  };
8538
8577
  } catch (error) {
8539
8578
  console.error("Error fetching line:", error);
@@ -9674,78 +9713,6 @@ var createStorageService = (supabase) => ({
9674
9713
  }
9675
9714
  });
9676
9715
 
9677
- // src/lib/constants/idleTimeColors.ts
9678
- var IDLE_TIME_REASON_COLORS = {
9679
- "Operator Absent": {
9680
- hex: "#dc2626",
9681
- // red-600 - Critical/Urgent
9682
- text: "text-red-600",
9683
- bg: "bg-red-50",
9684
- border: "border-red-200"
9685
- },
9686
- "No Material": {
9687
- hex: "#f59e0b",
9688
- // amber-500 - Warning/Supply Chain
9689
- text: "text-amber-600",
9690
- bg: "bg-amber-50",
9691
- border: "border-amber-200"
9692
- },
9693
- "Machine Downtime": {
9694
- hex: "#3b82f6",
9695
- // blue-500 - Scheduled/Technical
9696
- text: "text-blue-600",
9697
- bg: "bg-blue-50",
9698
- border: "border-blue-200"
9699
- },
9700
- "Operator Idle": {
9701
- hex: "#8b5cf6",
9702
- // violet-500 - Low Priority/Behavioral
9703
- text: "text-violet-600",
9704
- bg: "bg-violet-50",
9705
- border: "border-violet-200"
9706
- }
9707
- };
9708
- var FALLBACK_HEX_COLORS = [
9709
- "#dc2626",
9710
- // red-600
9711
- "#ea580c",
9712
- // orange-600
9713
- "#ca8a04",
9714
- // yellow-600
9715
- "#16a34a",
9716
- // green-600
9717
- "#0891b2",
9718
- // cyan-600
9719
- "#2563eb",
9720
- // blue-600
9721
- "#7c3aed",
9722
- // violet-600
9723
- "#c026d3"
9724
- // fuchsia-600
9725
- ];
9726
- var DEFAULT_CONFIG3 = {
9727
- hex: "#9ca3af",
9728
- text: "text-gray-500",
9729
- bg: "bg-gray-50",
9730
- border: "border-gray-200"
9731
- };
9732
- function getIdleTimeReasonColor(reason, index = 0) {
9733
- const normalizedReason = reason.includes("_") ? reason.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ") : reason;
9734
- if (IDLE_TIME_REASON_COLORS[normalizedReason]) {
9735
- return IDLE_TIME_REASON_COLORS[normalizedReason];
9736
- }
9737
- const lowerReason = normalizedReason.toLowerCase();
9738
- const foundKey = Object.keys(IDLE_TIME_REASON_COLORS).find((k) => k.toLowerCase() === lowerReason);
9739
- if (foundKey) {
9740
- return IDLE_TIME_REASON_COLORS[foundKey];
9741
- }
9742
- const fallbackHex = FALLBACK_HEX_COLORS[index % FALLBACK_HEX_COLORS.length];
9743
- return {
9744
- ...DEFAULT_CONFIG3,
9745
- hex: fallbackHex
9746
- };
9747
- }
9748
-
9749
9716
  // src/lib/services/idleTimeReasonService.ts
9750
9717
  async function fetchIdleTimeReasons(params) {
9751
9718
  const { workspaceId, lineId, date, shiftId, startDate, endDate, token } = params;
@@ -9803,7 +9770,12 @@ async function fetchIdleTimeReasons(params) {
9803
9770
  }
9804
9771
  function transformToChartData(data) {
9805
9772
  return data.reasons.map((reason) => ({
9806
- name: formatReasonLabel(reason.reason),
9773
+ name: reason.display_name || formatReasonLabel(reason.reason_key || reason.reason),
9774
+ reasonKey: reason.reason_key || reason.reason,
9775
+ displayName: reason.display_name || formatReasonLabel(reason.reason_key || reason.reason),
9776
+ paletteToken: reason.palette_token,
9777
+ iconToken: reason.icon_token,
9778
+ isKnown: reason.is_known,
9807
9779
  value: reason.percentage,
9808
9780
  totalDurationSeconds: reason.total_duration_seconds,
9809
9781
  efficiencyLossPercentage: reason.efficiency_loss_percentage ?? null
@@ -9812,9 +9784,6 @@ function transformToChartData(data) {
9812
9784
  function formatReasonLabel(reason) {
9813
9785
  return reason.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
9814
9786
  }
9815
- function getReasonColor(reason, index = 0) {
9816
- return getIdleTimeReasonColor(reason, index).hex;
9817
- }
9818
9787
 
9819
9788
  // src/lib/services/sessionTracker.ts
9820
9789
  function generateSessionId() {
@@ -11537,6 +11506,52 @@ var workspaceMetricsStore = {
11537
11506
  }
11538
11507
  };
11539
11508
 
11509
+ // src/lib/constants/actions.ts
11510
+ var ACTION_NAMES = {
11511
+ /** Assembly operations */
11512
+ ASSEMBLY: "Assembly",
11513
+ /** Packaging operations */
11514
+ PACKAGING: "Packaging",
11515
+ /** Output operations (user-facing label for the legacy packaging family) */
11516
+ OUTPUT: "Output",
11517
+ /** Inspection operations */
11518
+ INSPECTION: "Inspection",
11519
+ /** Testing operations */
11520
+ TESTING: "Testing",
11521
+ /** Quality control operations */
11522
+ QUALITY_CONTROL: "Quality Control"
11523
+ };
11524
+ var ACTION_FAMILIES = {
11525
+ ASSEMBLY: "assembly",
11526
+ OUTPUT: "output",
11527
+ OTHER: "other"
11528
+ };
11529
+ var normalizeActionFamily = (params) => {
11530
+ const explicitValue = (params.actionFamily ?? params.actionType ?? "").trim().toLowerCase();
11531
+ if (explicitValue === ACTION_FAMILIES.ASSEMBLY) return ACTION_FAMILIES.ASSEMBLY;
11532
+ if (explicitValue === ACTION_FAMILIES.OUTPUT || explicitValue === "packaging") {
11533
+ return ACTION_FAMILIES.OUTPUT;
11534
+ }
11535
+ if (explicitValue === ACTION_FAMILIES.OTHER) return ACTION_FAMILIES.OTHER;
11536
+ const normalizedName = (params.actionName ?? "").trim().toLowerCase();
11537
+ if (!normalizedName) return null;
11538
+ if (normalizedName === "output" || normalizedName.includes("packag")) {
11539
+ return ACTION_FAMILIES.OUTPUT;
11540
+ }
11541
+ if (normalizedName.includes("assembly")) {
11542
+ return ACTION_FAMILIES.ASSEMBLY;
11543
+ }
11544
+ return ACTION_FAMILIES.OTHER;
11545
+ };
11546
+ var getActionDisplayName = (params) => {
11547
+ const explicitDisplayName = (params.displayName ?? "").trim();
11548
+ if (explicitDisplayName) return explicitDisplayName;
11549
+ const family = normalizeActionFamily(params);
11550
+ if (family === ACTION_FAMILIES.OUTPUT) return ACTION_NAMES.OUTPUT;
11551
+ if (family === ACTION_FAMILIES.ASSEMBLY) return ACTION_NAMES.ASSEMBLY;
11552
+ return (params.actionName ?? "").trim();
11553
+ };
11554
+
11540
11555
  // src/lib/utils/workspaceMetricsTransform.ts
11541
11556
  var coerceNumber = (value, fallback = 0) => {
11542
11557
  const num = typeof value === "number" ? value : Number(value);
@@ -11726,10 +11741,17 @@ var toWorkspaceDetailedMetrics = ({
11726
11741
  const targetOutput = coerceNumber(data.target_output ?? data.total_day_output, 0);
11727
11742
  const idealOutput = coerceNumber(data.ideal_output ?? data.ideal_output_until_now, 0);
11728
11743
  const outputDifference = totalActions - idealOutput;
11744
+ const hourlyCycleTimes = Array.isArray(data.hourly_cycle_times) ? data.hourly_cycle_times.map((value) => coerceNumber(value, 0)) : [];
11729
11745
  const totalWorkspacesValue = coerceNumber(
11730
11746
  data.total_workspaces ?? lineMetricsById?.[data.line_id || ""]?.total_workspaces ?? workspaceConfig.totalWorkspaces,
11731
11747
  0
11732
11748
  );
11749
+ const actionFamily = normalizeActionFamily({
11750
+ actionFamily: data.action_family,
11751
+ actionType: data.action_type,
11752
+ actionName: data.action_name
11753
+ });
11754
+ const actionType = actionFamily === "assembly" || actionFamily === "output" ? actionFamily : null;
11733
11755
  return {
11734
11756
  workspace_id: data.workspace_id,
11735
11757
  workspace_name: data.workspace_name,
@@ -11740,8 +11762,20 @@ var toWorkspaceDetailedMetrics = ({
11740
11762
  company_name: data.company_name || "",
11741
11763
  date: data.date,
11742
11764
  shift_id: shiftId,
11743
- action_name: data.action_name || "",
11744
- action_type: data.action_type === "assembly" || data.action_type === "packaging" ? data.action_type : null,
11765
+ action_name: getActionDisplayName({
11766
+ displayName: data.action_display_name,
11767
+ actionFamily: data.action_family,
11768
+ actionType: data.action_type,
11769
+ actionName: data.action_name
11770
+ }),
11771
+ action_type: actionType,
11772
+ action_family: actionFamily,
11773
+ action_display_name: getActionDisplayName({
11774
+ displayName: data.action_display_name,
11775
+ actionFamily: data.action_family,
11776
+ actionType: data.action_type,
11777
+ actionName: data.action_name
11778
+ }),
11745
11779
  shift_start: shiftStart,
11746
11780
  shift_end: shiftEnd,
11747
11781
  shift_type: shiftType,
@@ -11754,6 +11788,7 @@ var toWorkspaceDetailedMetrics = ({
11754
11788
  avg_efficiency: coerceNumber(data.efficiency ?? data.avg_efficiency, 0),
11755
11789
  total_actions: totalActions,
11756
11790
  hourly_action_counts: hourlyActionCounts,
11791
+ hourly_cycle_times: hourlyCycleTimes,
11757
11792
  workspace_rank: coerceNumber(data.workspace_rank, 0),
11758
11793
  total_workspaces: totalWorkspacesValue,
11759
11794
  ideal_output_until_now: idealOutput,
@@ -13292,6 +13327,12 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
13292
13327
  const transformedWorkspaceData = allWorkspaceMetrics.map((item) => {
13293
13328
  const idleTimeValue = typeof item.idle_time === "number" ? item.idle_time : Number(item.idle_time);
13294
13329
  const idleTimeSeconds = Number.isFinite(idleTimeValue) ? idleTimeValue : void 0;
13330
+ const actionFamily = normalizeActionFamily({
13331
+ actionFamily: item.action_family,
13332
+ actionType: item.action_type,
13333
+ actionName: item.action_name
13334
+ });
13335
+ const actionType = actionFamily === "assembly" || actionFamily === "output" ? actionFamily : null;
13295
13336
  return {
13296
13337
  company_id: item.company_id || companyId,
13297
13338
  line_id: item.line_id,
@@ -13311,7 +13352,18 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
13311
13352
  monitoring_mode: item.monitoring_mode ?? void 0,
13312
13353
  idle_time: idleTimeSeconds,
13313
13354
  assembly_enabled: item.assembly_enabled ?? false,
13314
- action_type: item.action_type === "assembly" || item.action_type === "packaging" ? item.action_type : null,
13355
+ video_grid_metric_mode: normalizeVideoGridMetricMode(
13356
+ item.video_grid_metric_mode,
13357
+ item.assembly_enabled ?? false
13358
+ ),
13359
+ action_type: actionType,
13360
+ action_family: actionFamily,
13361
+ action_display_name: getActionDisplayName({
13362
+ displayName: item.action_display_name,
13363
+ actionFamily: item.action_family,
13364
+ actionType: item.action_type,
13365
+ actionName: item.action_name
13366
+ }),
13315
13367
  recent_flow_mode: item.recent_flow_mode ?? void 0,
13316
13368
  recent_flow_percent: item.recent_flow_percent ?? null,
13317
13369
  recent_flow_actual_rate_pph: item.recent_flow_actual_rate_pph ?? null,
@@ -19231,8 +19283,115 @@ function useIdleTimeReasons({
19231
19283
  refetch: fetchData
19232
19284
  };
19233
19285
  }
19286
+ var DEFAULT_PALETTE_TOKEN = "slate";
19287
+ var DEFAULT_ICON_TOKEN = "help-circle";
19288
+ var PALETTE_CONFIG = {
19289
+ red: {
19290
+ hex: "#dc2626",
19291
+ textClass: "text-red-600",
19292
+ bgClass: "bg-red-50",
19293
+ borderClass: "border-red-200"
19294
+ },
19295
+ amber: {
19296
+ hex: "#f59e0b",
19297
+ textClass: "text-amber-600",
19298
+ bgClass: "bg-amber-50",
19299
+ borderClass: "border-amber-200"
19300
+ },
19301
+ blue: {
19302
+ hex: "#3b82f6",
19303
+ textClass: "text-blue-600",
19304
+ bgClass: "bg-blue-50",
19305
+ borderClass: "border-blue-200"
19306
+ },
19307
+ violet: {
19308
+ hex: "#8b5cf6",
19309
+ textClass: "text-violet-600",
19310
+ bgClass: "bg-violet-50",
19311
+ borderClass: "border-violet-200"
19312
+ },
19313
+ emerald: {
19314
+ hex: "#10b981",
19315
+ textClass: "text-emerald-600",
19316
+ bgClass: "bg-emerald-50",
19317
+ borderClass: "border-emerald-200"
19318
+ },
19319
+ cyan: {
19320
+ hex: "#0891b2",
19321
+ textClass: "text-cyan-600",
19322
+ bgClass: "bg-cyan-50",
19323
+ borderClass: "border-cyan-200"
19324
+ },
19325
+ slate: {
19326
+ hex: "#64748b",
19327
+ textClass: "text-slate-600",
19328
+ bgClass: "bg-slate-50",
19329
+ borderClass: "border-slate-200"
19330
+ }
19331
+ };
19332
+ var ICON_CONFIG = {
19333
+ "alert-triangle": AlertTriangle,
19334
+ "refresh-cw": RefreshCw,
19335
+ package: Package,
19336
+ clock: Clock,
19337
+ "user-x": UserX,
19338
+ wrench: Wrench,
19339
+ activity: Activity,
19340
+ "help-circle": HelpCircle
19341
+ };
19342
+ var humanizeIdleReasonLabel = (value) => {
19343
+ const text = String(value || "").trim();
19344
+ if (!text) {
19345
+ return "Unknown";
19346
+ }
19347
+ return text.replace(/_/g, " ").split(/\s+/).filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
19348
+ };
19349
+ var normalizePaletteToken = (value) => {
19350
+ const token = String(value || "").trim().toLowerCase();
19351
+ if (token in PALETTE_CONFIG) {
19352
+ return token;
19353
+ }
19354
+ return DEFAULT_PALETTE_TOKEN;
19355
+ };
19356
+ var normalizeIconToken = (value) => {
19357
+ const token = String(value || "").trim().toLowerCase();
19358
+ if (token in ICON_CONFIG) {
19359
+ return token;
19360
+ }
19361
+ return DEFAULT_ICON_TOKEN;
19362
+ };
19363
+ var getIdleReasonPresentation = (metadata) => {
19364
+ const label = typeof metadata?.label === "string" && metadata.label.trim() ? metadata.label.trim() : null;
19365
+ const displayName = typeof metadata?.displayName === "string" && metadata.displayName.trim() ? metadata.displayName.trim() : humanizeIdleReasonLabel(label);
19366
+ const paletteToken = normalizePaletteToken(metadata?.paletteToken);
19367
+ const iconToken = normalizeIconToken(metadata?.iconToken);
19368
+ return {
19369
+ label,
19370
+ displayName,
19371
+ paletteToken,
19372
+ iconToken,
19373
+ isKnown: Boolean(metadata?.isKnown),
19374
+ Icon: ICON_CONFIG[iconToken],
19375
+ ...PALETTE_CONFIG[paletteToken]
19376
+ };
19377
+ };
19378
+ var getIdleReasonHexColor = (metadata) => getIdleReasonPresentation(metadata).hex;
19234
19379
 
19235
19380
  // src/lib/services/clipClassificationService.ts
19381
+ var normalizeClassification = (value) => {
19382
+ const rawLabel = typeof value?.label === "string" ? value.label.trim() : "";
19383
+ const label = rawLabel || void 0;
19384
+ const parsedConfidence = typeof value?.confidence === "number" ? value.confidence : typeof value?.confidence === "string" ? Number(value.confidence) : void 0;
19385
+ return {
19386
+ status: value?.status === "classified" ? "classified" : "processing",
19387
+ label,
19388
+ displayName: typeof value?.display_name === "string" ? value.display_name : label ? humanizeIdleReasonLabel(label) : void 0,
19389
+ paletteToken: typeof value?.palette_token === "string" ? value.palette_token : void 0,
19390
+ iconToken: typeof value?.icon_token === "string" ? value.icon_token : void 0,
19391
+ isKnown: typeof value?.is_known === "boolean" ? value.is_known : void 0,
19392
+ confidence: parsedConfidence !== void 0 && Number.isFinite(parsedConfidence) ? parsedConfidence : void 0
19393
+ };
19394
+ };
19236
19395
  function parseCleanLabel(rawLabel) {
19237
19396
  if (!rawLabel) return null;
19238
19397
  const patterns = [
@@ -19286,7 +19445,13 @@ async function fetchClassifications(clipIds, token) {
19286
19445
  );
19287
19446
  }
19288
19447
  const data = await response.json();
19289
- return data.classifications || {};
19448
+ const rawClassifications = data.classifications || {};
19449
+ return Object.fromEntries(
19450
+ Object.entries(rawClassifications).map(([clipId, classification]) => [
19451
+ clipId,
19452
+ normalizeClassification(classification)
19453
+ ])
19454
+ );
19290
19455
  } catch (error) {
19291
19456
  console.error("Error fetching chunk:", error);
19292
19457
  return Object.fromEntries(
@@ -19327,21 +19492,30 @@ function useClassificationRealtimeUpdates({
19327
19492
  },
19328
19493
  (payload) => {
19329
19494
  console.log("[useClassificationRealtimeUpdates] New classification:", payload);
19330
- try {
19331
- const { clip_id, clip_label, confidence_score } = payload.new;
19332
- const parsedLabel = parseCleanLabel(clip_label);
19333
- if (parsedLabel) {
19334
- onClassificationUpdate(clip_id, {
19335
- status: "classified",
19336
- label: parsedLabel,
19337
- confidence: confidence_score || 0
19338
- });
19339
- } else {
19340
- console.warn("[useClassificationRealtimeUpdates] Failed to parse label:", clip_label);
19495
+ void (async () => {
19496
+ try {
19497
+ const { clip_id, clip_label, confidence_score } = payload.new;
19498
+ const token = await getAccessTokenOrRedirect(supabase, { redirectReason: "session_expired" });
19499
+ const fetched = await fetchClassifications([clip_id], token);
19500
+ const classification = fetched[clip_id];
19501
+ if (classification) {
19502
+ onClassificationUpdate(clip_id, classification);
19503
+ return;
19504
+ }
19505
+ const parsedLabel = parseCleanLabel(clip_label);
19506
+ if (parsedLabel) {
19507
+ onClassificationUpdate(clip_id, {
19508
+ status: "classified",
19509
+ label: parsedLabel,
19510
+ confidence: confidence_score || 0
19511
+ });
19512
+ } else {
19513
+ console.warn("[useClassificationRealtimeUpdates] Failed to parse label:", clip_label);
19514
+ }
19515
+ } catch (error) {
19516
+ console.error("[useClassificationRealtimeUpdates] Error processing update:", error);
19341
19517
  }
19342
- } catch (error) {
19343
- console.error("[useClassificationRealtimeUpdates] Error processing update:", error);
19344
- }
19518
+ })();
19345
19519
  }
19346
19520
  ).subscribe((status) => {
19347
19521
  console.log(`[useClassificationRealtimeUpdates] Subscription status:`, status);
@@ -32373,90 +32547,99 @@ var CycleTimeOverTimeChart = ({
32373
32547
  data,
32374
32548
  idealCycleTime,
32375
32549
  shiftStart,
32376
- className = ""
32550
+ shiftEnd,
32551
+ xAxisMode = "recent",
32552
+ datasetKey,
32553
+ className = "",
32554
+ showIdleTime = false,
32555
+ idleTimeData = []
32377
32556
  }) => {
32378
32557
  const MAX_DATA_POINTS = 40;
32379
32558
  const containerRef = React141__default.useRef(null);
32380
32559
  const [containerReady, setContainerReady] = React141__default.useState(false);
32381
- const getHourFromTimeString = (timeStr) => {
32382
- const [hours, minutes] = timeStr.split(":");
32383
- return parseInt(hours);
32560
+ const parseTimeToMinutes3 = (value) => {
32561
+ const [hours, minutes] = value.split(":").map(Number);
32562
+ if (!Number.isFinite(hours) || !Number.isFinite(minutes)) return 0;
32563
+ return hours * 60 + minutes;
32384
32564
  };
32385
- getHourFromTimeString(shiftStart);
32386
- const getDisplayData = (rawData) => {
32387
- return rawData.slice(Math.max(0, rawData.length - MAX_DATA_POINTS));
32565
+ const formatHourLabel = (slotIndex) => {
32566
+ const baseMinutes = parseTimeToMinutes3(shiftStart);
32567
+ const absoluteMinutes = baseMinutes + slotIndex * 60;
32568
+ const hour24 = Math.floor(absoluteMinutes % (24 * 60) / 60);
32569
+ const ampm = hour24 >= 12 ? "PM" : "AM";
32570
+ const hour12 = hour24 % 12 || 12;
32571
+ return `${hour12}${ampm}`;
32572
+ };
32573
+ const formatHourRangeLabel = (slotIndex) => {
32574
+ const startLabel = formatHourLabel(slotIndex);
32575
+ const endLabel = shiftEnd && slotIndex === DURATION - 1 ? formatHourLabel(slotIndex + 1) : formatHourLabel(slotIndex + 1);
32576
+ return `${startLabel} - ${endLabel}`;
32388
32577
  };
32578
+ const getDisplayData = React141__default.useCallback((rawData) => {
32579
+ if (xAxisMode === "hourly") return rawData;
32580
+ return rawData.slice(Math.max(0, rawData.length - MAX_DATA_POINTS));
32581
+ }, [xAxisMode]);
32389
32582
  const displayData = getDisplayData(data);
32390
32583
  const DURATION = displayData.length;
32391
- const [animatedData, setAnimatedData] = React141__default.useState(Array(DURATION).fill(0));
32392
- const prevDataRef = React141__default.useRef(Array(DURATION).fill(0));
32393
- const animationFrameRef = React141__default.useRef(null);
32394
- const animateToNewData = React141__default.useCallback((targetData) => {
32395
- const startData = [...prevDataRef.current];
32396
- const startTime = performance.now();
32397
- const duration = 1200;
32398
- const animate = (currentTime) => {
32399
- const elapsed = currentTime - startTime;
32400
- const progress7 = Math.min(elapsed / duration, 1);
32401
- const easeOutQuint = (t) => 1 - Math.pow(1 - t, 5);
32402
- const easedProgress = easeOutQuint(progress7);
32403
- const newData = startData.map((start, index) => {
32404
- const target = targetData[index] || 0;
32405
- const change = target - start;
32406
- const scaleFactor = Math.min(1, 50 / Math.abs(change || 1));
32407
- const adjustedEasing = progress7 * (scaleFactor + (1 - scaleFactor) * easedProgress);
32408
- return start + change * adjustedEasing;
32409
- });
32410
- setAnimatedData(newData);
32411
- prevDataRef.current = newData;
32412
- if (progress7 < 1) {
32413
- animationFrameRef.current = requestAnimationFrame(animate);
32414
- } else {
32415
- setAnimatedData(targetData);
32416
- prevDataRef.current = targetData;
32417
- }
32418
- };
32419
- if (animationFrameRef.current) {
32420
- cancelAnimationFrame(animationFrameRef.current);
32421
- }
32422
- animationFrameRef.current = requestAnimationFrame(animate);
32423
- }, []);
32584
+ 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
+ const finalData = displayData;
32424
32591
  React141__default.useEffect(() => {
32425
- if (JSON.stringify(data) !== JSON.stringify(prevDataRef.current)) {
32426
- const processedData = getDisplayData(data);
32427
- animateToNewData(processedData);
32592
+ const containerNode = containerRef.current;
32593
+ if (!containerNode) {
32594
+ setContainerReady(true);
32595
+ return void 0;
32428
32596
  }
32429
- return () => {
32430
- if (animationFrameRef.current) {
32431
- cancelAnimationFrame(animationFrameRef.current);
32432
- }
32433
- };
32434
- }, [data, animateToNewData]);
32435
- React141__default.useEffect(() => {
32597
+ let frameId = null;
32598
+ let resizeObserver = null;
32436
32599
  const checkContainerDimensions = () => {
32437
- if (containerRef.current) {
32438
- const rect = containerRef.current.getBoundingClientRect();
32439
- if (rect.width > 0 && rect.height > 0) {
32440
- setContainerReady(true);
32441
- }
32600
+ const rect = containerNode.getBoundingClientRect();
32601
+ const isReady = rect.width > 0 && rect.height > 0;
32602
+ if (isReady) {
32603
+ setContainerReady(true);
32442
32604
  }
32605
+ return isReady;
32443
32606
  };
32444
- checkContainerDimensions();
32445
- const resizeObserver = new ResizeObserver(checkContainerDimensions);
32446
- if (containerRef.current) {
32447
- resizeObserver.observe(containerRef.current);
32607
+ if (checkContainerDimensions()) {
32608
+ return void 0;
32448
32609
  }
32449
- const fallbackTimeout = setTimeout(() => {
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 {
32450
32622
  setContainerReady(true);
32451
- }, 100);
32623
+ }
32452
32624
  return () => {
32453
- resizeObserver.disconnect();
32454
- clearTimeout(fallbackTimeout);
32625
+ if (frameId !== null) {
32626
+ window.cancelAnimationFrame(frameId);
32627
+ }
32628
+ resizeObserver?.disconnect();
32455
32629
  };
32456
32630
  }, []);
32631
+ const labelInterval = React141__default.useMemo(() => {
32632
+ if (xAxisMode === "hourly") {
32633
+ return Math.max(1, Math.ceil(DURATION / 8));
32634
+ }
32635
+ return 5;
32636
+ }, [xAxisMode, DURATION]);
32457
32637
  const formatTimeLabel = (dataIndex) => {
32458
32638
  if (DURATION === 0) return "";
32459
- if (dataIndex % 5 !== 0 && dataIndex !== DURATION - 1) return "";
32639
+ if (dataIndex % labelInterval !== 0 && dataIndex !== DURATION - 1) return "";
32640
+ if (xAxisMode === "hourly") {
32641
+ return formatHourLabel(dataIndex);
32642
+ }
32460
32643
  const timeAgo = (DURATION - 1 - dataIndex) * 90;
32461
32644
  const minutes = Math.floor(timeAgo / 60);
32462
32645
  const seconds = timeAgo % 60;
@@ -32470,6 +32653,9 @@ var CycleTimeOverTimeChart = ({
32470
32653
  };
32471
32654
  const formatTooltipTime = (dataIndex) => {
32472
32655
  if (DURATION === 0) return "";
32656
+ if (xAxisMode === "hourly") {
32657
+ return formatHourRangeLabel(dataIndex);
32658
+ }
32473
32659
  const timeAgo = (DURATION - 1 - dataIndex) * 90;
32474
32660
  const minutes = Math.floor(timeAgo / 60);
32475
32661
  const seconds = timeAgo % 60;
@@ -32483,39 +32669,40 @@ var CycleTimeOverTimeChart = ({
32483
32669
  return `${minutes} minutes ${seconds} seconds ago`;
32484
32670
  }
32485
32671
  };
32486
- const chartData = Array.from({ length: DURATION }, (_, i) => {
32672
+ const chartData = React141__default.useMemo(() => Array.from({ length: DURATION }, (_, i) => {
32487
32673
  return {
32488
32674
  timeIndex: i,
32489
32675
  label: formatTimeLabel(i),
32490
32676
  tooltip: formatTooltipTime(i),
32491
- cycleTime: animatedData[i] || 0,
32492
- color: (animatedData[i] || 0) <= idealCycleTime ? "#00AB45" : "#E34329"
32677
+ cycleTime: finalData[i] || 0,
32678
+ idleMinutes: showIdleTime && idleTimeData && idleTimeData[i] || 0,
32679
+ color: (finalData[i] || 0) <= idealCycleTime ? "#00AB45" : "#E34329"
32493
32680
  };
32494
- });
32495
- const renderLegend = () => /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center text-sm text-gray-600 absolute -bottom-1 left-0 right-0 bg-white py-1", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border border-gray-100 rounded-full px-3 py-1", children: [
32496
- /* @__PURE__ */ jsx("div", { className: "w-8 flex items-center", children: /* @__PURE__ */ jsx("div", { className: "w-full border-t-2 border-[#E34329] border-dashed" }) }),
32497
- /* @__PURE__ */ jsxs("span", { children: [
32498
- "Standard: ",
32499
- idealCycleTime.toFixed(1),
32500
- " seconds"
32501
- ] })
32502
- ] }) });
32681
+ }), [DURATION, finalData, showIdleTime, idleTimeData, idealCycleTime]);
32682
+ const renderLegend = () => {
32683
+ if (!showIdleTime) return null;
32684
+ 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: [
32685
+ /* @__PURE__ */ jsx("div", { className: "w-2.5 h-2.5 rounded-full bg-[#f59e0b]" }),
32686
+ /* @__PURE__ */ jsx("span", { children: "Idle Time (min)" })
32687
+ ] }) });
32688
+ };
32503
32689
  return /* @__PURE__ */ jsxs(
32504
32690
  "div",
32505
32691
  {
32506
32692
  ref: containerRef,
32507
- className: `w-full h-full min-w-0 relative pb-8 ${className}`,
32693
+ className: `w-full h-full min-w-0 flex flex-col relative pb-2 ${className}`,
32508
32694
  style: { minHeight: "200px", minWidth: 0 },
32509
32695
  children: [
32510
- containerReady ? /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
32696
+ 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(
32511
32698
  LineChart$1,
32512
32699
  {
32513
32700
  data: chartData,
32514
32701
  margin: {
32515
- top: 25,
32702
+ top: 5,
32516
32703
  right: 30,
32517
32704
  bottom: 25,
32518
- left: 35
32705
+ left: 10
32519
32706
  },
32520
32707
  children: [
32521
32708
  /* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", vertical: false }),
@@ -32525,17 +32712,18 @@ var CycleTimeOverTimeChart = ({
32525
32712
  dataKey: "label",
32526
32713
  tick: { fontSize: 11 },
32527
32714
  interval: 0,
32528
- angle: -30,
32529
- textAnchor: "end",
32530
- tickMargin: 15,
32531
- height: 60
32715
+ angle: xAxisMode === "hourly" ? 0 : -30,
32716
+ textAnchor: xAxisMode === "hourly" ? "middle" : "end",
32717
+ tickMargin: xAxisMode === "hourly" ? 8 : 15,
32718
+ height: xAxisMode === "hourly" ? 40 : 60
32532
32719
  }
32533
32720
  ),
32534
32721
  /* @__PURE__ */ jsx(
32535
32722
  YAxis,
32536
32723
  {
32537
32724
  tickMargin: 8,
32538
- width: 35,
32725
+ width: 45,
32726
+ yAxisId: "cycle",
32539
32727
  domain: ["auto", "auto"],
32540
32728
  ticks: [0, idealCycleTime, ...Array.from({ length: 4 }, (_, i) => (i + 1) * Math.ceil(idealCycleTime / 2))].sort((a, b) => a - b),
32541
32729
  tickFormatter: (value) => String(value),
@@ -32559,6 +32747,20 @@ var CycleTimeOverTimeChart = ({
32559
32747
  }
32560
32748
  }
32561
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
+ ),
32562
32764
  /* @__PURE__ */ jsx(
32563
32765
  Tooltip,
32564
32766
  {
@@ -32586,8 +32788,11 @@ var CycleTimeOverTimeChart = ({
32586
32788
  }
32587
32789
  return label;
32588
32790
  },
32589
- formatter: (value) => {
32791
+ formatter: (value, name) => {
32590
32792
  const numValue = typeof value === "number" ? value : Number(value);
32793
+ if (name === "idleMinutes") {
32794
+ return [`${numValue.toFixed(0)} minutes`, "Idle Time"];
32795
+ }
32591
32796
  return [`${numValue.toFixed(1)} seconds`, "Cycle Time"];
32592
32797
  },
32593
32798
  animationDuration: 200
@@ -32597,6 +32802,7 @@ var CycleTimeOverTimeChart = ({
32597
32802
  ReferenceLine,
32598
32803
  {
32599
32804
  y: idealCycleTime,
32805
+ yAxisId: "cycle",
32600
32806
  stroke: "#E34329",
32601
32807
  strokeDasharray: "3 3",
32602
32808
  strokeWidth: 2,
@@ -32613,6 +32819,7 @@ var CycleTimeOverTimeChart = ({
32613
32819
  Line,
32614
32820
  {
32615
32821
  type: "monotone",
32822
+ yAxisId: "cycle",
32616
32823
  dataKey: "cycleTime",
32617
32824
  stroke: "#3B82F6",
32618
32825
  strokeWidth: 2,
@@ -32662,15 +32869,35 @@ var CycleTimeOverTimeChart = ({
32662
32869
  }
32663
32870
  );
32664
32871
  },
32872
+ isAnimationActive: shouldAnimate,
32665
32873
  animationBegin: 0,
32666
- animationDuration: 1500,
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,
32667
32894
  animationEasing: "ease-out"
32668
- }
32895
+ },
32896
+ `${effectiveDatasetKey}:idle`
32669
32897
  )
32670
32898
  ]
32671
32899
  }
32672
- ) }) : /* @__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..." }) }),
32673
- renderLegend()
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..." }) }) })
32674
32901
  ]
32675
32902
  }
32676
32903
  );
@@ -32862,7 +33089,7 @@ var HourlyOutputChartComponent = ({
32862
33089
  if (!classification.label) {
32863
33090
  return "Reason unavailable";
32864
33091
  }
32865
- return classification.label.replace(/_/g, " ");
33092
+ return classification.displayName || classification.label.replace(/_/g, " ");
32866
33093
  }, [idleClipRanges, idleTimeClipClassifications]);
32867
33094
  const { shiftDuration, shiftEndTime, hasPartialLastHour } = React141__default.useMemo(() => {
32868
33095
  console.log("[HourlyOutputChart] Calculating shift duration with:", {
@@ -33520,23 +33747,82 @@ var HourlyOutputChart = React141__default.memo(HourlyOutputChartComponent, (prev
33520
33747
  HourlyOutputChart.displayName = "HourlyOutputChart";
33521
33748
 
33522
33749
  // src/components/dashboard/grid/videoGridMetricUtils.ts
33523
- var VIDEO_GRID_LEGEND_LABEL = "7-min Flow";
33750
+ var VIDEO_GRID_LEGEND_LABEL = "Flow";
33524
33751
  var MAP_GRID_LEGEND_LABEL = "Efficiency";
33525
33752
  var MIXED_VIDEO_GRID_LEGEND_LABEL = "Flow / Efficiency";
33526
33753
  var isFiniteNumber2 = (value) => typeof value === "number" && Number.isFinite(value);
33527
- var isAssemblyFlowEnabled = (workspace) => workspace.assembly_enabled === true;
33528
- var hasAssemblyRecentFlow = (workspace) => isAssemblyFlowEnabled(workspace) && isFiniteNumber2(workspace.recent_flow_percent);
33754
+ var isVideoGridRecentFlowEnabled = (workspace) => isRecentFlowVideoGridMetricMode(
33755
+ workspace.video_grid_metric_mode,
33756
+ workspace.assembly_enabled === true
33757
+ );
33758
+ var isVideoGridWipGated = (workspace) => isWipGatedVideoGridMetricMode(
33759
+ workspace.video_grid_metric_mode,
33760
+ workspace.assembly_enabled === true
33761
+ );
33762
+ var hasVideoGridRecentFlow = (workspace) => isVideoGridRecentFlowEnabled(workspace) && isFiniteNumber2(workspace.recent_flow_percent);
33763
+ var isVideoGridRecentFlowUnavailable = (workspace) => isVideoGridRecentFlowEnabled(workspace) && !hasVideoGridRecentFlow(workspace);
33529
33764
  var getVideoGridMetricValue = (workspace) => {
33530
33765
  const recentFlowPercent = workspace.recent_flow_percent;
33531
- if (hasAssemblyRecentFlow(workspace) && isFiniteNumber2(recentFlowPercent)) {
33766
+ if (hasVideoGridRecentFlow(workspace) && isFiniteNumber2(recentFlowPercent)) {
33532
33767
  return recentFlowPercent;
33533
33768
  }
33769
+ if (isVideoGridRecentFlowUnavailable(workspace)) {
33770
+ return null;
33771
+ }
33534
33772
  return workspace.efficiency;
33535
33773
  };
33536
33774
  var hasIncomingWipMapping = (workspace) => Boolean(workspace.incoming_wip_buffer_name);
33775
+ var getVideoGridBaseColorState = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => {
33776
+ const metricValue = getVideoGridMetricValue(workspace);
33777
+ if (!isFiniteNumber2(metricValue)) {
33778
+ return "neutral";
33779
+ }
33780
+ return getEfficiencyColor(metricValue, legend);
33781
+ };
33782
+ var isLowWipGreenOverride = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => {
33783
+ if (!hasVideoGridRecentFlow(workspace) || !isVideoGridWipGated(workspace)) {
33784
+ return false;
33785
+ }
33786
+ if (getVideoGridBaseColorState(workspace, legend) !== "red") {
33787
+ return false;
33788
+ }
33789
+ if (!hasIncomingWipMapping(workspace)) {
33790
+ return false;
33791
+ }
33792
+ return isFiniteNumber2(workspace.incoming_wip_current) && workspace.incoming_wip_current <= 1;
33793
+ };
33794
+ var toMinuteBucket = (minuteBucket) => Number.isFinite(minuteBucket) ? Math.floor(minuteBucket) : Math.floor(Date.now() / 6e4);
33795
+ var getEffectiveFlowMinuteBucket = (workspace) => {
33796
+ const effectiveAt = workspace.recent_flow_effective_end_at;
33797
+ if (!effectiveAt) {
33798
+ return void 0;
33799
+ }
33800
+ const timestamp = Date.parse(effectiveAt);
33801
+ if (!Number.isFinite(timestamp)) {
33802
+ return void 0;
33803
+ }
33804
+ return Math.floor(timestamp / 6e4);
33805
+ };
33806
+ var hashWorkspaceKey = (workspace) => {
33807
+ const workspaceKey = workspace.workspace_uuid || workspace.workspace_name || "unknown";
33808
+ let hash = 0;
33809
+ for (let index = 0; index < workspaceKey.length; index += 1) {
33810
+ hash = (hash * 31 + workspaceKey.charCodeAt(index)) % 2147483647;
33811
+ }
33812
+ return hash;
33813
+ };
33814
+ var getSyntheticLowWipDisplayValue = (workspace, minuteBucket) => {
33815
+ const bucket = getEffectiveFlowMinuteBucket(workspace) ?? toMinuteBucket(minuteBucket);
33816
+ const offset = (hashWorkspaceKey(workspace) % 11 + bucket % 11 + 11) % 11;
33817
+ return 100 + offset;
33818
+ };
33819
+ var getVideoGridDisplayValue = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND, minuteBucket) => isLowWipGreenOverride(workspace, legend) ? getSyntheticLowWipDisplayValue(workspace, minuteBucket) : getVideoGridMetricValue(workspace);
33537
33820
  var getVideoGridColorState = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => {
33538
- const baseColor = getEfficiencyColor(getVideoGridMetricValue(workspace), legend);
33539
- if (!hasAssemblyRecentFlow(workspace)) {
33821
+ const baseColor = getVideoGridBaseColorState(workspace, legend);
33822
+ if (!hasVideoGridRecentFlow(workspace)) {
33823
+ return baseColor;
33824
+ }
33825
+ if (!isVideoGridWipGated(workspace)) {
33540
33826
  return baseColor;
33541
33827
  }
33542
33828
  if (baseColor !== "red") {
@@ -33548,7 +33834,7 @@ var getVideoGridColorState = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) =>
33548
33834
  if (!isFiniteNumber2(workspace.incoming_wip_current)) {
33549
33835
  return "neutral";
33550
33836
  }
33551
- if (workspace.incoming_wip_current <= 1) {
33837
+ if (isLowWipGreenOverride(workspace, legend)) {
33552
33838
  return "green";
33553
33839
  }
33554
33840
  return baseColor;
@@ -33558,11 +33844,11 @@ var getVideoGridLegendLabel = (workspaces) => {
33558
33844
  if (visibleWorkspaces.length === 0) {
33559
33845
  return MAP_GRID_LEGEND_LABEL;
33560
33846
  }
33561
- const assemblyEnabledCount = visibleWorkspaces.filter(isAssemblyFlowEnabled).length;
33562
- if (assemblyEnabledCount === 0) {
33847
+ const recentFlowEnabledCount = visibleWorkspaces.filter(isVideoGridRecentFlowEnabled).length;
33848
+ if (recentFlowEnabledCount === 0) {
33563
33849
  return MAP_GRID_LEGEND_LABEL;
33564
33850
  }
33565
- if (assemblyEnabledCount === visibleWorkspaces.length) {
33851
+ if (recentFlowEnabledCount === visibleWorkspaces.length) {
33566
33852
  return VIDEO_GRID_LEGEND_LABEL;
33567
33853
  }
33568
33854
  return MIXED_VIDEO_GRID_LEGEND_LABEL;
@@ -33589,6 +33875,7 @@ var VideoCard = React141__default.memo(({
33589
33875
  useRAF = true,
33590
33876
  className = "",
33591
33877
  compact = false,
33878
+ displayMinuteBucket,
33592
33879
  displayName,
33593
33880
  lastSeenLabel,
33594
33881
  onMouseEnter,
@@ -33609,8 +33896,13 @@ var VideoCard = React141__default.memo(({
33609
33896
  const lastSeenText = lastSeenLabel || "Unknown";
33610
33897
  const workspaceDisplayName = displayName || getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
33611
33898
  const videoGridMetricValue = getVideoGridMetricValue(workspace);
33899
+ const videoGridDisplayValue = getVideoGridDisplayValue(workspace, effectiveLegend, displayMinuteBucket);
33612
33900
  const videoGridColorState = getVideoGridColorState(workspace, effectiveLegend);
33613
- const badgeTitle = hasAssemblyRecentFlow(workspace) ? `Flow ${Math.round(videoGridMetricValue)}%` : `Efficiency ${Math.round(videoGridMetricValue)}%`;
33901
+ const isRecentFlowCard = isVideoGridRecentFlowEnabled(workspace);
33902
+ const hasDisplayMetric = typeof videoGridDisplayValue === "number" && Number.isFinite(videoGridDisplayValue);
33903
+ const hasBarMetric = typeof videoGridMetricValue === "number" && Number.isFinite(videoGridMetricValue);
33904
+ const badgeTitle = hasVideoGridRecentFlow(workspace) ? `Flow ${Math.round(videoGridDisplayValue ?? 0)}%` : isRecentFlowCard ? "Flow unavailable" : `Efficiency ${Math.round(videoGridDisplayValue ?? 0)}%`;
33905
+ const badgeLabel = hasDisplayMetric ? `${Math.round(videoGridDisplayValue)}%` : "X";
33614
33906
  const efficiencyOverlayClass = videoGridColorState === "green" ? "bg-[#00D654]/25" : videoGridColorState === "yellow" ? "bg-[#FFD700]/30" : videoGridColorState === "red" ? "bg-[#FF2D0A]/30" : "bg-transparent";
33615
33907
  const efficiencyBarClass = videoGridColorState === "green" ? "bg-[#00AB45]" : videoGridColorState === "yellow" ? "bg-[#FFB020]" : videoGridColorState === "red" ? "bg-[#E34329]" : "bg-gray-500/70";
33616
33908
  const efficiencyStatus = videoGridColorState === "green" ? "High" : videoGridColorState === "yellow" ? "Medium" : videoGridColorState === "red" ? "Low" : "Neutral";
@@ -33689,19 +33981,18 @@ var VideoCard = React141__default.memo(({
33689
33981
  /* @__PURE__ */ jsx("div", { className: `absolute ${compact ? "top-1 right-1" : "top-2 right-2"} z-30`, children: /* @__PURE__ */ jsx(
33690
33982
  "div",
33691
33983
  {
33984
+ "data-testid": "video-card-metric-badge",
33692
33985
  className: `bg-black/70 backdrop-blur-sm rounded ${compact ? "px-1.5 py-1" : "px-2 py-1"} text-white border border-white/10`,
33693
33986
  title: badgeTitle,
33694
- children: /* @__PURE__ */ jsxs("span", { className: `${compact ? "text-[10px]" : "text-xs"} font-semibold`, children: [
33695
- Math.round(videoGridMetricValue),
33696
- "%"
33697
- ] })
33987
+ children: /* @__PURE__ */ jsx("span", { className: `${compact ? "text-[10px]" : "text-xs"} font-semibold`, children: badgeLabel })
33698
33988
  }
33699
33989
  ) }),
33700
33990
  /* @__PURE__ */ jsx("div", { className: `absolute bottom-0 left-0 right-0 ${compact ? "h-0.5" : "h-1"} bg-black/50 z-30`, children: /* @__PURE__ */ jsx(
33701
33991
  "div",
33702
33992
  {
33993
+ "data-testid": "video-card-metric-bar",
33703
33994
  className: `h-full ${efficiencyBarClass} transition-all duration-500`,
33704
- style: { width: `${Math.min(100, videoGridMetricValue)}%` }
33995
+ style: { width: `${hasBarMetric ? Math.min(100, Math.max(0, videoGridMetricValue)) : videoGridColorState === "neutral" ? 100 : 0}%` }
33705
33996
  }
33706
33997
  ) })
33707
33998
  ] }),
@@ -33732,7 +34023,7 @@ var VideoCard = React141__default.memo(({
33732
34023
  }
33733
34024
  );
33734
34025
  }, (prevProps, nextProps) => {
33735
- if (prevProps.workspace.efficiency !== nextProps.workspace.efficiency || prevProps.workspace.assembly_enabled !== nextProps.workspace.assembly_enabled || prevProps.workspace.recent_flow_percent !== nextProps.workspace.recent_flow_percent || 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) {
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) {
33736
34027
  return false;
33737
34028
  }
33738
34029
  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) {
@@ -33750,6 +34041,9 @@ var VideoCard = React141__default.memo(({
33750
34041
  if (prevProps.compact !== nextProps.compact) {
33751
34042
  return false;
33752
34043
  }
34044
+ if (prevProps.displayMinuteBucket !== nextProps.displayMinuteBucket) {
34045
+ return false;
34046
+ }
33753
34047
  if (prevProps.hlsUrl !== nextProps.hlsUrl || prevProps.shouldPlay !== nextProps.shouldPlay) {
33754
34048
  return false;
33755
34049
  }
@@ -34033,6 +34327,7 @@ var VideoGridView = React141__default.memo(({
34033
34327
  stream_source: isR2Stream ? "r2" : "media_config"
34034
34328
  });
34035
34329
  }, []);
34330
+ const displayMinuteBucket = Math.floor(Date.now() / 6e4);
34036
34331
  return /* @__PURE__ */ jsx("div", { className: `relative overflow-hidden h-full w-full ${className}`, children: /* @__PURE__ */ jsx("div", { ref: containerRef, className: "h-full w-full p-3 sm:p-2", children: /* @__PURE__ */ jsx(
34037
34332
  "div",
34038
34333
  {
@@ -34122,6 +34417,7 @@ var VideoGridView = React141__default.memo(({
34122
34417
  ),
34123
34418
  lastSeenLabel: card.lastSeenLabel,
34124
34419
  useRAF: effectiveUseRAF,
34420
+ displayMinuteBucket,
34125
34421
  compact: !selectedLine,
34126
34422
  onMouseEnter: onWorkspaceHover ? () => onWorkspaceHover(card.workspaceId) : void 0,
34127
34423
  onMouseLeave: onWorkspaceHoverEnd ? () => onWorkspaceHoverEnd(card.workspaceId) : void 0
@@ -39251,45 +39547,56 @@ var FileManagerFilters = ({
39251
39547
  });
39252
39548
  const [loadingPercentile, setLoadingPercentile] = useState(false);
39253
39549
  const resolvedTargetCycleTime = targetCycleTime && targetCycleTime > 0 ? targetCycleTime : null;
39254
- const getRootCauseConfig = (reason) => {
39255
- const colorConfig = getIdleTimeReasonColor(reason);
39256
- let Icon2 = HelpCircle;
39257
- if (reason.includes("Machine Breakdown")) Icon2 = AlertTriangle;
39258
- else if (reason.includes("Material")) Icon2 = Package;
39259
- else if (reason.includes("Worker") || reason.includes("Absent")) Icon2 = UserX;
39260
- else if (reason.includes("Quality")) Icon2 = XCircle;
39261
- else if (reason.includes("Power")) Icon2 = Zap;
39262
- else if (reason.includes("Maintenance") || reason.includes("Tool")) Icon2 = Wrench;
39263
- else if (reason.includes("Present") || reason.includes("Idle")) Icon2 = Clock;
39550
+ const getIdleTimeClassification = useCallback((clipId) => {
39551
+ const classification = mergedClipClassifications[clipId];
39552
+ return classification || null;
39553
+ }, [mergedClipClassifications]);
39554
+ const getRootCauseConfig = useCallback((classification) => {
39555
+ if (!classification || classification.status === "processing") {
39556
+ return null;
39557
+ }
39558
+ const presentation = getIdleReasonPresentation({
39559
+ label: classification.label,
39560
+ displayName: classification.displayName,
39561
+ paletteToken: classification.paletteToken,
39562
+ iconToken: classification.iconToken,
39563
+ isKnown: classification.isKnown
39564
+ });
39264
39565
  return {
39265
- color: colorConfig.text,
39266
- bgColor: colorConfig.bg,
39267
- borderColor: colorConfig.border,
39268
- Icon: Icon2,
39269
- iconColor: colorConfig.text
39566
+ color: presentation.textClass,
39567
+ bgColor: presentation.bgClass,
39568
+ borderColor: presentation.borderClass,
39569
+ Icon: presentation.Icon,
39570
+ iconColor: presentation.textClass,
39571
+ displayName: presentation.displayName
39270
39572
  };
39271
- };
39272
- const normalizeIdleReasonLabel = useCallback((label) => {
39273
- return label.replace(/_/g, " ").trim();
39274
39573
  }, []);
39275
- const getIdleTimeRootCause = useCallback((clipId) => {
39276
- const classification = mergedClipClassifications[clipId];
39277
- if (!classification) return "processing";
39278
- if (classification.status === "processing") return "processing";
39279
- return classification.label || "processing";
39280
- }, [mergedClipClassifications]);
39281
39574
  const idleReasonOptions = useMemo(() => {
39282
39575
  const idleClips = clipMetadata["idle_time"] || [];
39283
- const uniqueReasons = /* @__PURE__ */ new Set();
39576
+ const uniqueReasons = /* @__PURE__ */ new Map();
39284
39577
  idleClips.forEach((clip) => {
39285
39578
  const clipId = clip.clipId || clip.id;
39286
39579
  if (!clipId) return;
39287
- const reason = getIdleTimeRootCause(clipId);
39288
- if (!reason || reason === "processing") return;
39289
- uniqueReasons.add(normalizeIdleReasonLabel(reason));
39580
+ const classification = getIdleTimeClassification(clipId);
39581
+ if (!classification || classification.status === "processing" || !classification.label) {
39582
+ return;
39583
+ }
39584
+ if (!uniqueReasons.has(classification.label)) {
39585
+ uniqueReasons.set(classification.label, {
39586
+ label: classification.label,
39587
+ displayName: classification.displayName || classification.label.replace(/_/g, " "),
39588
+ paletteToken: classification.paletteToken,
39589
+ iconToken: classification.iconToken,
39590
+ isKnown: classification.isKnown
39591
+ });
39592
+ }
39290
39593
  });
39291
- return Array.from(uniqueReasons).sort((a, b) => a.localeCompare(b));
39292
- }, [clipMetadata, getIdleTimeRootCause, normalizeIdleReasonLabel]);
39594
+ return Array.from(uniqueReasons.values()).sort((a, b) => a.displayName.localeCompare(b.displayName));
39595
+ }, [clipMetadata, getIdleTimeClassification]);
39596
+ const selectedIdleReasonOption = useMemo(
39597
+ () => idleReasonOptions.find((reason) => reason.label === idleLabelFilter) || null,
39598
+ [idleReasonOptions, idleLabelFilter]
39599
+ );
39293
39600
  const getClipBadge = useCallback((node) => {
39294
39601
  if (node.categoryId === "idle_time" || node.categoryId === "low_value") {
39295
39602
  return { text: "Idle", className: "bg-red-100 text-red-700" };
@@ -39361,6 +39668,10 @@ var FileManagerFilters = ({
39361
39668
  seededClassifications[clip.clipId] = {
39362
39669
  status: clip.classification_status,
39363
39670
  label: clip.classification_label || void 0,
39671
+ displayName: clip.classification_display_name || void 0,
39672
+ paletteToken: clip.classification_palette_token || void 0,
39673
+ iconToken: clip.classification_icon_token || void 0,
39674
+ isKnown: clip.classification_is_known ?? void 0,
39364
39675
  confidence: clip.classification_confidence ?? void 0
39365
39676
  };
39366
39677
  }
@@ -39744,7 +40055,7 @@ var FileManagerFilters = ({
39744
40055
  return slot ? slot.label : value;
39745
40056
  }, [timeSlots]);
39746
40057
  const isClipInTimeRange = useCallback((clipTimestamp) => {
39747
- if (!isTimeFilterActive || !startTime || !endTime) {
40058
+ if (!startTime || !endTime) {
39748
40059
  return true;
39749
40060
  }
39750
40061
  try {
@@ -39770,9 +40081,8 @@ var FileManagerFilters = ({
39770
40081
  let filteredClips = categoryClips.filter((clip) => isClipInTimeRange(clip.clip_timestamp));
39771
40082
  if (category.id === "idle_time" && idleLabelFilter) {
39772
40083
  filteredClips = filteredClips.filter((clip) => {
39773
- const rootCause = getIdleTimeRootCause(clip.clipId || clip.id);
39774
- const normalizedRootCause = rootCause.replace(/_/g, " ");
39775
- return normalizedRootCause === idleLabelFilter;
40084
+ const classification = getIdleTimeClassification(clip.clipId || clip.id);
40085
+ return classification?.label === idleLabelFilter;
39776
40086
  });
39777
40087
  }
39778
40088
  const displayCount = isTimeFilterActive || category.id === "idle_time" && idleLabelFilter ? filteredClips.length : categoryCount;
@@ -39802,8 +40112,9 @@ var FileManagerFilters = ({
39802
40112
  clipPosition: index + 1,
39803
40113
  // Store 1-based position
39804
40114
  cycleTimeSeconds: cycleTime,
39805
- duration: clip.duration
40115
+ duration: clip.duration,
39806
40116
  // Store duration for custom badge rendering
40117
+ cycleItemCount: clip.cycle_item_count ?? null
39807
40118
  };
39808
40119
  });
39809
40120
  regularCategoryNodes.push({
@@ -40059,14 +40370,14 @@ var FileManagerFilters = ({
40059
40370
  /* @__PURE__ */ jsx("div", { className: `flex-shrink-0 mr-3 ${node.type === "category" || node.type === "percentile-category" ? "p-2 rounded-lg shadow-sm group-hover:scale-110 transition-transform duration-200" : "p-0.5"} ${colorClasses && (node.type === "category" || node.type === "percentile-category") ? `${colorClasses.bg} border border-white/60` : ""}`, children: node.type === "video" && (node.categoryId === "idle_time" || node.categoryId === "low_value") ? (
40060
40371
  // Show root cause icon for idle time clips
40061
40372
  (() => {
40062
- const rootCause = getIdleTimeRootCause(node.clipId || node.id);
40063
- if (rootCause === "processing") {
40373
+ const classification = getIdleTimeClassification(node.clipId || node.id);
40374
+ if (!classification || classification.status === "processing") {
40064
40375
  return /* @__PURE__ */ jsx(Clock, { className: "h-3.5 w-3.5 text-purple-500", strokeWidth: 2.5 });
40065
40376
  }
40066
40377
  if (!idleTimeVlmEnabled && node.categoryId === "idle_time") {
40067
40378
  return /* @__PURE__ */ jsx(Clock, { className: "h-3.5 w-3.5 text-purple-500", strokeWidth: 2.5 });
40068
40379
  }
40069
- const config = getRootCauseConfig(rootCause.replace(/_/g, " "));
40380
+ const config = getRootCauseConfig(classification);
40070
40381
  if (config) {
40071
40382
  const IconComponent = config.Icon;
40072
40383
  return /* @__PURE__ */ jsx(IconComponent, { className: `h-3.5 w-3.5 ${config.iconColor}`, strokeWidth: 2.5 });
@@ -40088,10 +40399,10 @@ var FileManagerFilters = ({
40088
40399
  return /* @__PURE__ */ jsx("div", { className: `inline-flex items-center px-2 py-0.5 rounded-md border text-[10px] font-bold ${isLong ? "bg-purple-50 text-purple-700 border-purple-200" : "bg-gray-50 text-gray-600 border-gray-200"}`, children: isLong ? "Long" : "Short" });
40089
40400
  }
40090
40401
  const clipId = node.clipId || node.id;
40091
- const rootCause = getIdleTimeRootCause(clipId);
40092
- const isProcessing = rootCause === "processing";
40093
- const displayLabel = isProcessing ? "Analyzing..." : rootCause.replace(/_/g, " ");
40094
- const config = isProcessing ? null : getRootCauseConfig(displayLabel);
40402
+ const classification = getIdleTimeClassification(clipId);
40403
+ const isProcessing = !classification || classification.status === "processing";
40404
+ const config = isProcessing ? null : getRootCauseConfig(classification);
40405
+ const displayLabel = config?.displayName || "Analyzing...";
40095
40406
  const bgClass = config ? config.bgColor : "bg-slate-50";
40096
40407
  const textClass = config ? config.color : "text-slate-700";
40097
40408
  const borderClass = config ? config.borderColor : "border-slate-200";
@@ -40101,7 +40412,13 @@ var FileManagerFilters = ({
40101
40412
  // Show badge for other clips
40102
40413
  (() => {
40103
40414
  const badge = getClipBadge(node);
40104
- return /* @__PURE__ */ jsx("span", { className: `inline-flex items-center px-1.5 py-0.5 rounded-md text-xs font-medium ${badge.className}`, children: badge.text });
40415
+ return /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1.5", children: [
40416
+ /* @__PURE__ */ jsx("span", { className: `inline-flex items-center px-1.5 py-0.5 rounded-md text-xs font-medium ${badge.className}`, children: badge.text }),
40417
+ node.categoryId === "cycle_completion" && node.cycleItemCount && node.cycleItemCount > 1 ? /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded-md text-xs font-semibold bg-blue-100 text-blue-700 border border-blue-200", children: [
40418
+ "x",
40419
+ node.cycleItemCount
40420
+ ] }) : null
40421
+ ] });
40105
40422
  })()
40106
40423
  ) })
40107
40424
  ] }),
@@ -40189,7 +40506,7 @@ var FileManagerFilters = ({
40189
40506
  idleLabelFilter && activeFilter === "idle_time" && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 text-xs text-purple-600 bg-purple-50/60 px-3 py-1.5 rounded-lg border border-purple-100", children: [
40190
40507
  /* @__PURE__ */ jsxs("span", { className: "font-medium", children: [
40191
40508
  "Reason: ",
40192
- idleLabelFilter.replace(/_/g, " ")
40509
+ selectedIdleReasonOption?.displayName || idleLabelFilter.replace(/_/g, " ")
40193
40510
  ] }),
40194
40511
  /* @__PURE__ */ jsx(
40195
40512
  "button",
@@ -40238,21 +40555,31 @@ var FileManagerFilters = ({
40238
40555
  /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin" }),
40239
40556
  "Loading idle reasons..."
40240
40557
  ] }) : idleReasonOptions.length === 0 ? /* @__PURE__ */ jsx("div", { className: "px-3 py-4 text-sm text-slate-500", children: "No classified idle reasons found yet." }) : idleReasonOptions.map((reason) => {
40241
- const config = getRootCauseConfig(reason);
40558
+ const config = getRootCauseConfig({
40559
+ status: "classified",
40560
+ label: reason.label,
40561
+ displayName: reason.displayName,
40562
+ paletteToken: reason.paletteToken,
40563
+ iconToken: reason.iconToken,
40564
+ isKnown: reason.isKnown
40565
+ });
40566
+ if (!config) {
40567
+ return null;
40568
+ }
40242
40569
  return /* @__PURE__ */ jsxs(
40243
40570
  "button",
40244
40571
  {
40245
40572
  onClick: () => {
40246
- setIdleLabelFilter(reason);
40573
+ setIdleLabelFilter(reason.label);
40247
40574
  setShowIdleLabelFilterModal(false);
40248
40575
  },
40249
- className: `w-full px-3 py-2 text-left text-sm rounded-lg transition-colors flex items-center gap-2 mb-1 ${idleLabelFilter === reason ? "bg-purple-50 text-purple-700 font-medium" : "text-slate-700 hover:bg-slate-50"}`,
40576
+ className: `w-full px-3 py-2 text-left text-sm rounded-lg transition-colors flex items-center gap-2 mb-1 ${idleLabelFilter === reason.label ? "bg-purple-50 text-purple-700 font-medium" : "text-slate-700 hover:bg-slate-50"}`,
40250
40577
  children: [
40251
40578
  /* @__PURE__ */ jsx(config.Icon, { className: `h-3.5 w-3.5 ${config.iconColor}` }),
40252
- reason
40579
+ reason.displayName
40253
40580
  ]
40254
40581
  },
40255
- reason
40582
+ reason.label
40256
40583
  );
40257
40584
  }) })
40258
40585
  ]
@@ -40367,33 +40694,14 @@ var FileManagerFilters = ({
40367
40694
  slot.value
40368
40695
  )) })
40369
40696
  ] })
40370
- ] }) }),
40371
- /* @__PURE__ */ jsx("div", { className: "px-4 py-3 border-t border-slate-200 bg-white rounded-b-xl", children: /* @__PURE__ */ jsx(
40372
- "button",
40373
- {
40374
- onClick: () => {
40375
- if (startTime && endTime) {
40376
- setIsTimeFilterActive(true);
40377
- }
40378
- setShowTimeFilterModal(false);
40379
- setStartSearchTerm("");
40380
- setEndSearchTerm("");
40381
- },
40382
- disabled: !startTime || !endTime,
40383
- className: `
40384
- w-full px-4 py-2 text-sm font-semibold rounded-lg transition-all
40385
- ${startTime && endTime ? "bg-blue-600 text-white hover:bg-blue-700 active:scale-[0.98]" : "bg-slate-200 text-slate-400 cursor-not-allowed"}
40386
- `,
40387
- children: "Apply"
40388
- }
40389
- ) })
40697
+ ] }) })
40390
40698
  ]
40391
40699
  }
40392
40700
  )
40393
40701
  ] }),
40394
40702
  /* @__PURE__ */ jsxs("div", { className: "px-4 py-3 flex-1 min-h-0 overflow-y-auto scrollbar-thin", children: [
40395
40703
  /* @__PURE__ */ jsx("div", { className: "space-y-2", children: filterTree.map((node) => renderNode(node)) }),
40396
- filterTree.length === 0 && isTimeFilterActive && (startTime || endTime) && /* @__PURE__ */ jsxs("div", { className: "text-center py-12", children: [
40704
+ filterTree.length === 0 && (startTime || endTime) && /* @__PURE__ */ jsxs("div", { className: "text-center py-12", children: [
40397
40705
  /* @__PURE__ */ jsx("div", { className: "text-slate-300 mb-4", children: /* @__PURE__ */ jsx(Clock, { className: "h-12 w-12 mx-auto" }) }),
40398
40706
  /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold text-slate-700 mb-2", children: "No clips found" }),
40399
40707
  /* @__PURE__ */ jsx("p", { className: "text-sm text-slate-500 mb-4", children: "No clips match the selected time range" }),
@@ -40403,18 +40711,19 @@ var FileManagerFilters = ({
40403
40711
  onClick: () => {
40404
40712
  setStartTime("");
40405
40713
  setEndTime("");
40714
+ setIsTimeFilterActive(false);
40406
40715
  },
40407
40716
  className: "inline-flex items-center px-4 py-2 bg-blue-50 text-blue-600 text-sm font-medium rounded-lg hover:bg-blue-100 transition-colors duration-200",
40408
40717
  children: "Clear time filter"
40409
40718
  }
40410
40719
  )
40411
40720
  ] }),
40412
- filterTree.length === 0 && !isTimeFilterActive && categories.length === 0 && /* @__PURE__ */ jsxs("div", { className: "text-center py-12", children: [
40721
+ filterTree.length === 0 && !startTime && !endTime && categories.length === 0 && /* @__PURE__ */ jsxs("div", { className: "text-center py-12", children: [
40413
40722
  /* @__PURE__ */ jsx("div", { className: "text-slate-300 mb-4", children: /* @__PURE__ */ jsx(HelpCircle, { className: "h-12 w-12 mx-auto" }) }),
40414
40723
  /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold text-slate-700 mb-2", children: "No clip types available" }),
40415
40724
  /* @__PURE__ */ jsx("p", { className: "text-sm text-slate-500", children: "Loading clip categories..." })
40416
40725
  ] }),
40417
- filterTree.length === 0 && !isTimeFilterActive && categories.length > 0 && /* @__PURE__ */ jsxs("div", { className: "text-center py-12", children: [
40726
+ filterTree.length === 0 && !startTime && !endTime && categories.length > 0 && /* @__PURE__ */ jsxs("div", { className: "text-center py-12", children: [
40418
40727
  /* @__PURE__ */ jsx("div", { className: "text-slate-300 mb-4", children: /* @__PURE__ */ jsx(Play, { className: "h-12 w-12 mx-auto" }) }),
40419
40728
  /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold text-slate-700 mb-2", children: "No clips available" }),
40420
40729
  /* @__PURE__ */ jsx("p", { className: "text-sm text-slate-500", children: "No clips found for the selected time period" })
@@ -40818,6 +41127,34 @@ function useClipsRealtimeUpdates({
40818
41127
  hasNewClips: newClipsNotification !== null && newClipsNotification.count > 0
40819
41128
  };
40820
41129
  }
41130
+ var parseFiniteNumber2 = (value) => {
41131
+ if (typeof value === "number" && Number.isFinite(value)) {
41132
+ return value;
41133
+ }
41134
+ if (typeof value === "string") {
41135
+ const parsed = Number(value);
41136
+ if (Number.isFinite(parsed)) {
41137
+ return parsed;
41138
+ }
41139
+ }
41140
+ return null;
41141
+ };
41142
+ var getMultiCycleItemCount = (clip) => {
41143
+ if (!clip || clip.categoryId !== "cycle_completion") {
41144
+ return null;
41145
+ }
41146
+ const cycleItemCount = parseFiniteNumber2(clip.cycle_item_count);
41147
+ return cycleItemCount !== null && cycleItemCount > 1 ? cycleItemCount : null;
41148
+ };
41149
+ var OVERLAY_ICON_COLOR_BY_PALETTE = {
41150
+ red: "text-red-300",
41151
+ amber: "text-amber-300",
41152
+ blue: "text-blue-300",
41153
+ violet: "text-violet-300",
41154
+ emerald: "text-emerald-300",
41155
+ cyan: "text-cyan-300",
41156
+ slate: "text-slate-200"
41157
+ };
40821
41158
  var BottlenecksContent = ({
40822
41159
  workspaceId,
40823
41160
  workspaceName,
@@ -41558,6 +41895,10 @@ var BottlenecksContent = ({
41558
41895
  classificationUpdates[clipId] = {
41559
41896
  status,
41560
41897
  label: clip.classification_label || void 0,
41898
+ displayName: clip.classification_display_name || void 0,
41899
+ paletteToken: clip.classification_palette_token || void 0,
41900
+ iconToken: clip.classification_icon_token || void 0,
41901
+ isKnown: clip.classification_is_known ?? void 0,
41561
41902
  confidence: clip.classification_confidence ?? void 0
41562
41903
  };
41563
41904
  });
@@ -42342,79 +42683,13 @@ var BottlenecksContent = ({
42342
42683
  return () => window.removeEventListener("keydown", handleEscape);
42343
42684
  }
42344
42685
  }, [isFullscreen, exitFullscreen]);
42345
- const ROOT_CAUSE_CONFIG = {
42346
- "Machine Breakdown": {
42347
- color: "text-white",
42348
- bgColor: "bg-black/60 backdrop-blur-sm",
42349
- borderColor: "border-transparent",
42350
- Icon: AlertTriangle,
42351
- iconColor: "text-red-500",
42352
- // Standard red for high visibility on dark
42353
- dotColor: "bg-red-600"
42354
- },
42355
- "Other": {
42356
- color: "text-white",
42357
- bgColor: "bg-black/60 backdrop-blur-sm",
42358
- borderColor: "border-transparent",
42359
- Icon: HelpCircle,
42360
- iconColor: "text-gray-400",
42361
- dotColor: "bg-gray-500"
42362
- },
42363
- "Power Outage": {
42364
- color: "text-white",
42365
- bgColor: "bg-black/60 backdrop-blur-sm",
42366
- borderColor: "border-transparent",
42367
- Icon: Zap,
42368
- iconColor: "text-red-400",
42369
- // Lighter red
42370
- dotColor: "bg-red-500"
42371
- },
42372
- "Worker Absent": {
42373
- color: "text-white",
42374
- bgColor: "bg-black/60 backdrop-blur-sm",
42375
- borderColor: "border-transparent",
42376
- Icon: UserX,
42377
- iconColor: "text-red-400",
42378
- // Lighter red
42379
- dotColor: "bg-red-500"
42380
- },
42381
- "Material Shortage": {
42382
- color: "text-white",
42383
- bgColor: "bg-black/60 backdrop-blur-sm",
42384
- borderColor: "border-transparent",
42385
- Icon: Package,
42386
- iconColor: "text-red-300",
42387
- // Even lighter red
42388
- dotColor: "bg-red-400"
42389
- },
42390
- "Quality Issue": {
42391
- color: "text-white",
42392
- bgColor: "bg-black/60 backdrop-blur-sm",
42393
- borderColor: "border-transparent",
42394
- Icon: XCircle,
42395
- iconColor: "text-red-300",
42396
- // Even lighter red
42397
- dotColor: "bg-red-400"
42398
- },
42399
- "Scheduled Maintenance": {
42400
- color: "text-white",
42401
- bgColor: "bg-black/60 backdrop-blur-sm",
42402
- borderColor: "border-transparent",
42403
- Icon: Wrench,
42404
- iconColor: "text-red-200",
42405
- // Very light red
42406
- dotColor: "bg-red-300"
42407
- }
42408
- };
42409
- const getIdleTimeRootCause = useCallback((video) => {
42686
+ const getIdleTimeClassification = useCallback((video) => {
42410
42687
  if (video.type !== "idle_time") return null;
42411
42688
  const videoId = video.id || video.clipId;
42412
- if (!videoId) return "processing";
42689
+ if (!videoId) return null;
42413
42690
  const classification = clipClassifications[videoId];
42414
- console.log(`[getIdleTimeRootCause] Looking up ${videoId}: `, classification);
42415
- if (!classification) return "processing";
42416
- if (classification.status === "processing") return "processing";
42417
- return classification.label || "processing";
42691
+ console.log(`[getIdleTimeClassification] Looking up ${videoId}: `, classification);
42692
+ return classification || null;
42418
42693
  }, [clipClassifications]);
42419
42694
  const getIdleTimeConfidence = useCallback((video) => {
42420
42695
  if (video.type !== "idle_time") return null;
@@ -42425,36 +42700,35 @@ var BottlenecksContent = ({
42425
42700
  if (classification.status === "processing") return null;
42426
42701
  return classification.confidence ?? null;
42427
42702
  }, [clipClassifications]);
42428
- const formatDisplayLabel = useCallback((label) => {
42429
- return label.replace(/_/g, " ");
42430
- }, []);
42431
- const getRootCauseConfig = useCallback((rootCause) => {
42432
- if (!rootCause) return null;
42433
- if (rootCause === "processing") {
42703
+ const getRootCauseConfig = useCallback((classification) => {
42704
+ if (!classification || classification.status === "processing") {
42434
42705
  return {
42435
42706
  color: "text-white",
42436
42707
  bgColor: "bg-black/60 backdrop-blur-sm",
42437
- borderColor: "border-gray-500/30",
42708
+ borderColor: "border-white/10",
42438
42709
  Icon: Clock,
42439
- iconColor: "text-purple-500",
42440
- dotColor: "bg-gray-400",
42710
+ iconColor: "text-purple-300",
42711
+ dotColor: "bg-purple-400",
42441
42712
  displayName: "Analyzing..."
42442
42713
  };
42443
42714
  }
42444
- const hardcodedConfig = ROOT_CAUSE_CONFIG[rootCause];
42445
- if (hardcodedConfig) {
42446
- return hardcodedConfig;
42447
- }
42715
+ const presentation = getIdleReasonPresentation({
42716
+ label: classification.label,
42717
+ displayName: classification.displayName,
42718
+ paletteToken: classification.paletteToken,
42719
+ iconToken: classification.iconToken,
42720
+ isKnown: classification.isKnown
42721
+ });
42448
42722
  return {
42449
42723
  color: "text-white",
42450
42724
  bgColor: "bg-black/60 backdrop-blur-sm",
42451
- borderColor: "border-purple-500/30",
42452
- Icon: Tag,
42453
- iconColor: "text-purple-400",
42454
- dotColor: "bg-purple-400",
42455
- displayName: formatDisplayLabel(rootCause)
42725
+ borderColor: "border-white/10",
42726
+ Icon: presentation.Icon,
42727
+ iconColor: OVERLAY_ICON_COLOR_BY_PALETTE[presentation.paletteToken] || OVERLAY_ICON_COLOR_BY_PALETTE.slate,
42728
+ dotColor: presentation.bgClass,
42729
+ displayName: presentation.displayName
42456
42730
  };
42457
- }, [formatDisplayLabel]);
42731
+ }, []);
42458
42732
  const getClipTypeLabel = useCallback((video) => {
42459
42733
  if (!video) return "";
42460
42734
  const currentFilter = activeFilterRef.current;
@@ -42619,15 +42893,15 @@ var BottlenecksContent = ({
42619
42893
  (currentVideo.type === "cycle_completion" || currentVideo.type === "bottleneck" && currentVideo.description.toLowerCase().includes("cycle time")) && currentVideo.cycle_time_seconds || currentVideo.type === "idle_time" || currentVideo.type === "low_value" ? currentVideo.type === "idle_time" ? (
42620
42894
  // Show full colored badge for idle time
42621
42895
  (() => {
42622
- const rootCause = getIdleTimeRootCause(currentVideo);
42896
+ const classification = getIdleTimeClassification(currentVideo);
42623
42897
  const confidence = getIdleTimeConfidence(currentVideo);
42624
- const config = getRootCauseConfig(rootCause);
42898
+ const config = getRootCauseConfig(classification);
42625
42899
  if (!config) return null;
42626
42900
  const IconComponent = config.Icon;
42627
42901
  return /* @__PURE__ */ jsxs(Fragment, { children: [
42628
- idleTimeVlmEnabled && /* @__PURE__ */ jsx("div", { className: "absolute top-3 left-3 z-10", children: /* @__PURE__ */ jsxs("div", { className: `inline-flex items-center gap-1.5 px-2.5 py-1.5 rounded-md border ${config.bgColor} ${config.borderColor} shadow-lg`, children: [
42629
- /* @__PURE__ */ jsx(IconComponent, { className: `h-3.5 w-3.5 ${config.iconColor}`, strokeWidth: 2.5 }),
42630
- /* @__PURE__ */ jsx("span", { className: `font-medium text-xs ${config.color}`, children: config.displayName || (rootCause ? formatDisplayLabel(rootCause) : "Analyzing...") })
42902
+ idleTimeVlmEnabled && /* @__PURE__ */ jsx("div", { className: "absolute top-3 left-3 z-10", children: /* @__PURE__ */ jsxs("div", { className: `inline-flex max-w-[18rem] items-center gap-1.5 rounded-md border px-2.5 py-1.5 shadow-lg ${config.bgColor} ${config.borderColor}`, children: [
42903
+ /* @__PURE__ */ jsx(IconComponent, { className: `h-3.5 w-3.5 flex-shrink-0 ${config.iconColor}`, strokeWidth: 2.5 }),
42904
+ /* @__PURE__ */ jsx("span", { className: `truncate font-medium text-xs ${config.color}`, children: config.displayName || "Analyzing..." })
42631
42905
  ] }) }),
42632
42906
  idleTimeVlmEnabled && confidence !== null && (() => {
42633
42907
  const confidencePercent = confidence * 100;
@@ -42662,9 +42936,9 @@ var BottlenecksContent = ({
42662
42936
  currentVideo.type === "idle_time" ? (
42663
42937
  // Show full colored badge for idle time
42664
42938
  (() => {
42665
- const rootCause = getIdleTimeRootCause(currentVideo);
42939
+ const classification = getIdleTimeClassification(currentVideo);
42666
42940
  const confidence = getIdleTimeConfidence(currentVideo);
42667
- const config = getRootCauseConfig(rootCause);
42941
+ const config = getRootCauseConfig(classification);
42668
42942
  if (!config) return null;
42669
42943
  const IconComponent = config.Icon;
42670
42944
  return /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -42673,9 +42947,9 @@ var BottlenecksContent = ({
42673
42947
  (confidence * 100).toFixed(0),
42674
42948
  "%"
42675
42949
  ] }) }) }),
42676
- idleTimeVlmEnabled && /* @__PURE__ */ jsx("div", { className: "absolute top-3 right-3 z-10", children: /* @__PURE__ */ jsxs("div", { className: `inline-flex items-center gap-1.5 px-2.5 py-1.5 rounded-md border ${config.bgColor} ${config.borderColor} shadow-lg`, children: [
42677
- /* @__PURE__ */ jsx(IconComponent, { className: `h-3.5 w-3.5 ${config.iconColor}`, strokeWidth: 2.5 }),
42678
- /* @__PURE__ */ jsx("span", { className: `font-medium text-xs ${config.color}`, children: rootCause })
42950
+ idleTimeVlmEnabled && /* @__PURE__ */ jsx("div", { className: "absolute top-3 right-3 z-10", children: /* @__PURE__ */ jsxs("div", { className: `inline-flex max-w-[18rem] items-center gap-1.5 rounded-md border px-2.5 py-1.5 shadow-lg ${config.bgColor} ${config.borderColor}`, children: [
42951
+ /* @__PURE__ */ jsx(IconComponent, { className: `h-3.5 w-3.5 flex-shrink-0 ${config.iconColor}`, strokeWidth: 2.5 }),
42952
+ /* @__PURE__ */ jsx("span", { className: `truncate font-medium text-xs ${config.color}`, children: config.displayName || "Analyzing..." })
42679
42953
  ] }) })
42680
42954
  ] });
42681
42955
  })()
@@ -42715,6 +42989,7 @@ var BottlenecksContent = ({
42715
42989
  /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500", children: "No clips found" })
42716
42990
  ] }) : /* @__PURE__ */ jsx("div", { className: "space-y-2", children: triageClips.map((clip, index) => {
42717
42991
  const isIdleTime = clip.categoryId === "idle_time";
42992
+ const cycleItemCount = getMultiCycleItemCount(clip);
42718
42993
  const timeString = isIdleTime && clip.idle_start_time && clip.idle_end_time ? formatIdleTimeRange(clip.idle_start_time, clip.idle_end_time, timezone) : new Date(clip.clip_timestamp).toLocaleTimeString("en-US", {
42719
42994
  hour12: true,
42720
42995
  hour: "numeric",
@@ -42767,15 +43042,15 @@ var BottlenecksContent = ({
42767
43042
  // Idle time clips - show root cause label below time
42768
43043
  (() => {
42769
43044
  const clipId = clip.id || clip.clipId;
42770
- const rootCause = getIdleTimeRootCause({
43045
+ const classification = getIdleTimeClassification({
42771
43046
  id: clipId,
42772
43047
  type: "idle_time",
42773
43048
  creation_timestamp: clip.clip_timestamp
42774
43049
  });
42775
- console.log(`[BottlenecksContent] Sidebar clip ${clipId}: rootCause=${rootCause}, classification=`, clipClassifications[clipId]);
42776
- const config = getRootCauseConfig(rootCause);
43050
+ console.log(`[BottlenecksContent] Sidebar clip ${clipId}: classification=`, clipClassifications[clipId]);
43051
+ const config = getRootCauseConfig(classification);
42777
43052
  if (!config) {
42778
- console.log(`[BottlenecksContent] No config found for rootCause: ${rootCause}`);
43053
+ console.log(`[BottlenecksContent] No config found for classification on clip: ${clipId}`);
42779
43054
  return null;
42780
43055
  }
42781
43056
  const IconComponent = config.Icon;
@@ -42790,7 +43065,7 @@ var BottlenecksContent = ({
42790
43065
  ] }) })
42791
43066
  ] }),
42792
43067
  /* @__PURE__ */ jsx("div", { className: "pl-6", children: idleTimeVlmEnabled ? /* @__PURE__ */ jsx("span", { className: "inline-flex items-center px-2 py-0.5 rounded-md border text-xs font-medium bg-gray-50 text-gray-700 border-gray-200", children: (() => {
42793
- const displayText = config.displayName || (rootCause ? formatDisplayLabel(rootCause) : "Analyzing...");
43068
+ const displayText = config.displayName || "Analyzing...";
42794
43069
  console.log(`[BottlenecksContent] Displaying label: "${displayText}" for clip ${clipId}`);
42795
43070
  return displayText;
42796
43071
  })() }) : (() => {
@@ -42810,7 +43085,13 @@ var BottlenecksContent = ({
42810
43085
  clip.duration ? `${clip.duration.toFixed(1)}s` : "N/A",
42811
43086
  ")"
42812
43087
  ] }) }),
42813
- /* @__PURE__ */ jsx("span", { className: `px-2 py-1 text-xs font-semibold rounded ${badgeColor}`, children: badgeText })
43088
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
43089
+ cycleItemCount ? /* @__PURE__ */ jsxs("span", { className: "px-2 py-1 text-xs font-semibold rounded border border-blue-200 bg-blue-100 text-blue-700", children: [
43090
+ "x",
43091
+ cycleItemCount
43092
+ ] }) : null,
43093
+ /* @__PURE__ */ jsx("span", { className: `px-2 py-1 text-xs font-semibold rounded ${badgeColor}`, children: badgeText })
43094
+ ] })
42814
43095
  ] })
42815
43096
  )
42816
43097
  },
@@ -42903,15 +43184,15 @@ var BottlenecksContent = ({
42903
43184
  (currentVideo.type === "cycle_completion" || currentVideo.type === "bottleneck" && currentVideo.description.toLowerCase().includes("cycle time")) && currentVideo.cycle_time_seconds || currentVideo.type === "idle_time" || currentVideo.type === "low_value" ? currentVideo.type === "idle_time" ? (
42904
43185
  // Show full colored badge for idle time
42905
43186
  (() => {
42906
- const rootCause = getIdleTimeRootCause(currentVideo);
43187
+ const classification = getIdleTimeClassification(currentVideo);
42907
43188
  const confidence = getIdleTimeConfidence(currentVideo);
42908
- const config = getRootCauseConfig(rootCause);
43189
+ const config = getRootCauseConfig(classification);
42909
43190
  if (!config) return null;
42910
43191
  const IconComponent = config.Icon;
42911
43192
  return /* @__PURE__ */ jsxs(Fragment, { children: [
42912
- idleTimeVlmEnabled && /* @__PURE__ */ jsx("div", { className: "absolute top-4 left-4 z-50", children: /* @__PURE__ */ jsxs("div", { className: `inline-flex items-center gap-2 px-3 py-2 rounded-md border ${config.bgColor} ${config.borderColor} shadow-lg`, children: [
42913
- /* @__PURE__ */ jsx(IconComponent, { className: `h-4 w-4 ${config.iconColor}`, strokeWidth: 2.5 }),
42914
- /* @__PURE__ */ jsx("span", { className: `font-medium text-sm ${config.color}`, children: rootCause })
43193
+ idleTimeVlmEnabled && /* @__PURE__ */ jsx("div", { className: "absolute top-4 left-4 z-50", children: /* @__PURE__ */ jsxs("div", { className: `inline-flex max-w-[20rem] items-center gap-2 rounded-md border px-3 py-2 shadow-lg ${config.bgColor} ${config.borderColor}`, children: [
43194
+ /* @__PURE__ */ jsx(IconComponent, { className: `h-4 w-4 flex-shrink-0 ${config.iconColor}`, strokeWidth: 2.5 }),
43195
+ /* @__PURE__ */ jsx("span", { className: `truncate font-medium text-sm ${config.color}`, children: config.displayName || "Analyzing..." })
42915
43196
  ] }) }),
42916
43197
  idleTimeVlmEnabled && confidence !== null && /* @__PURE__ */ jsx("div", { className: "absolute top-4 right-4 z-50", children: /* @__PURE__ */ jsx("div", { className: "inline-flex items-center gap-1.5 px-3 py-2 rounded-lg bg-black/70 backdrop-blur-sm shadow-lg border border-white/10", children: /* @__PURE__ */ jsxs("span", { className: "font-medium text-sm text-white", children: [
42917
43198
  "AI Confidence: ",
@@ -42933,9 +43214,9 @@ var BottlenecksContent = ({
42933
43214
  ] }) }) : currentVideo.type === "idle_time" ? (
42934
43215
  // Show full colored badge for idle time
42935
43216
  (() => {
42936
- const rootCause = getIdleTimeRootCause(currentVideo);
43217
+ const classification = getIdleTimeClassification(currentVideo);
42937
43218
  const confidence = getIdleTimeConfidence(currentVideo);
42938
- const config = getRootCauseConfig(rootCause);
43219
+ const config = getRootCauseConfig(classification);
42939
43220
  if (!config) return null;
42940
43221
  const IconComponent = config.Icon;
42941
43222
  return /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -42944,9 +43225,9 @@ var BottlenecksContent = ({
42944
43225
  (confidence * 100).toFixed(0),
42945
43226
  "%"
42946
43227
  ] }) }) }),
42947
- idleTimeVlmEnabled && /* @__PURE__ */ jsx("div", { className: "absolute top-4 right-20 z-50", children: /* @__PURE__ */ jsxs("div", { className: `inline-flex items-center gap-2 px-3 py-2 rounded-md border ${config.bgColor} ${config.borderColor} shadow-lg`, children: [
42948
- /* @__PURE__ */ jsx(IconComponent, { className: `h-4 w-4 ${config.iconColor}`, strokeWidth: 2.5 }),
42949
- /* @__PURE__ */ jsx("span", { className: `font-medium text-sm ${config.color}`, children: rootCause })
43228
+ idleTimeVlmEnabled && /* @__PURE__ */ jsx("div", { className: "absolute top-4 right-20 z-50", children: /* @__PURE__ */ jsxs("div", { className: `inline-flex max-w-[20rem] items-center gap-2 rounded-md border px-3 py-2 shadow-lg ${config.bgColor} ${config.borderColor}`, children: [
43229
+ /* @__PURE__ */ jsx(IconComponent, { className: `h-4 w-4 flex-shrink-0 ${config.iconColor}`, strokeWidth: 2.5 }),
43230
+ /* @__PURE__ */ jsx("span", { className: `truncate font-medium text-sm ${config.color}`, children: config.displayName || "Analyzing..." })
42950
43231
  ] }) })
42951
43232
  ] });
42952
43233
  })()
@@ -44895,16 +45176,6 @@ var LineHistoryCalendar = ({
44895
45176
  ] });
44896
45177
  };
44897
45178
  var LineHistoryCalendar_default = LineHistoryCalendar;
44898
- var STATIC_COLORS = {
44899
- "Operator Absent": "#dc2626",
44900
- // red-600 - Critical/Urgent
44901
- "No Material": "#f59e0b",
44902
- // amber-500 - Warning/Supply Chain
44903
- "Machine Downtime": "#3b82f6",
44904
- // blue-500 - Scheduled/Technical
44905
- "Operator Idle": "#8b5cf6"
44906
- // violet-500 - Low Priority/Behavioral
44907
- };
44908
45179
  var PRODUCTIVE_COLOR = "#00AB45";
44909
45180
  var IDLE_COLOR = "#e5e7eb";
44910
45181
  var formatDuration = (seconds) => {
@@ -44927,19 +45198,21 @@ var formatDuration = (seconds) => {
44927
45198
  }
44928
45199
  return parts.join(" ");
44929
45200
  };
44930
- var getColorForEntry = (name, index) => {
44931
- const normalized = name.trim().toLowerCase();
45201
+ var getColorForEntry = (entry) => {
45202
+ const normalized = entry.name.trim().toLowerCase();
44932
45203
  if (normalized === "productive" || normalized === "productive time") {
44933
45204
  return PRODUCTIVE_COLOR;
44934
45205
  }
44935
45206
  if (normalized === "idle" || normalized === "idle time") {
44936
45207
  return IDLE_COLOR;
44937
45208
  }
44938
- if (STATIC_COLORS[name]) {
44939
- return STATIC_COLORS[name];
44940
- }
44941
- const snakeCaseName = name.replace(/ /g, "_");
44942
- return getReasonColor(snakeCaseName, index);
45209
+ return getIdleReasonHexColor({
45210
+ label: entry.reasonKey || entry.name,
45211
+ displayName: entry.displayName || entry.name,
45212
+ paletteToken: entry.paletteToken,
45213
+ iconToken: entry.iconToken,
45214
+ isKnown: entry.isKnown
45215
+ });
44943
45216
  };
44944
45217
  var CustomTooltip = ({ active, payload, hideTotalDuration }) => {
44945
45218
  if (active && payload && payload.length) {
@@ -44953,8 +45226,8 @@ var CustomTooltip = ({ active, payload, hideTotalDuration }) => {
44953
45226
  const hasContributors = contributors.length > 0;
44954
45227
  return /* @__PURE__ */ jsxs("div", { className: "bg-white p-3 border border-gray-100 shadow-lg rounded-lg text-xs z-50 min-w-[280px]", children: [
44955
45228
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 pb-2 mb-2 border-b border-slate-100", children: [
44956
- /* @__PURE__ */ jsx("div", { className: "w-2.5 h-2.5 rounded-full flex-shrink-0", style: { backgroundColor: payload[0].payload.fill || getColorForEntry(payload[0].name, 0) } }),
44957
- /* @__PURE__ */ jsx("span", { className: "font-semibold text-slate-800 text-[13px]", children: payload[0].name.replace(/_/g, " ") })
45229
+ /* @__PURE__ */ jsx("div", { className: "w-2.5 h-2.5 rounded-full flex-shrink-0", style: { backgroundColor: payload[0].payload.fill || getColorForEntry(payload[0].payload) } }),
45230
+ /* @__PURE__ */ jsx("span", { className: "font-semibold text-slate-800 text-[13px]", children: datum?.displayName || payload[0].name.replace(/_/g, " ") })
44958
45231
  ] }),
44959
45232
  /* @__PURE__ */ jsxs("div", { className: "space-y-1.5 pb-1", children: [
44960
45233
  /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center gap-4", children: [
@@ -45015,7 +45288,8 @@ var IdleTimeReasonChartComponent = ({
45015
45288
  isLoading = false,
45016
45289
  error = null,
45017
45290
  hideTotalDuration = false,
45018
- updateAnimation = "replay"
45291
+ updateAnimation = "replay",
45292
+ variant = "pie"
45019
45293
  }) => {
45020
45294
  const [activeData, setActiveData] = React141__default.useState([]);
45021
45295
  React141__default.useEffect(() => {
@@ -45060,6 +45334,73 @@ var IdleTimeReasonChartComponent = ({
45060
45334
  if (!data || data.length === 0) {
45061
45335
  return /* @__PURE__ */ jsx(EmptyState, { message: "No Idle Time reasons available" });
45062
45336
  }
45337
+ if (variant === "bar") {
45338
+ return /* @__PURE__ */ jsx(
45339
+ "div",
45340
+ {
45341
+ className: "w-full h-full flex items-center overflow-visible focus:outline-none",
45342
+ tabIndex: -1,
45343
+ onFocus: (e) => e.currentTarget.blur(),
45344
+ children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
45345
+ BarChart$1,
45346
+ {
45347
+ data: activeData,
45348
+ layout: "vertical",
45349
+ margin: { top: 5, right: 30, left: 10, bottom: 5 },
45350
+ barCategoryGap: 8,
45351
+ barGap: 2,
45352
+ children: [
45353
+ /* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", horizontal: false, vertical: true }),
45354
+ /* @__PURE__ */ jsx(
45355
+ XAxis,
45356
+ {
45357
+ type: "number",
45358
+ hide: false,
45359
+ domain: [0, 100],
45360
+ ticks: [0, 20, 40, 60, 80, 100],
45361
+ tickFormatter: (val) => `${val}%`,
45362
+ tick: { fontSize: 10, fill: "#6b7280" },
45363
+ axisLine: { stroke: "#e5e7eb" },
45364
+ tickLine: false
45365
+ }
45366
+ ),
45367
+ /* @__PURE__ */ jsx(
45368
+ YAxis,
45369
+ {
45370
+ type: "category",
45371
+ dataKey: "name",
45372
+ tick: { fontSize: 11, fill: "#4b5563" },
45373
+ tickFormatter: (val) => typeof val === "string" ? val.replace(/_/g, " ") : val,
45374
+ width: 90,
45375
+ axisLine: false,
45376
+ tickLine: false
45377
+ }
45378
+ ),
45379
+ /* @__PURE__ */ jsx(
45380
+ Tooltip,
45381
+ {
45382
+ cursor: { fill: "rgba(0,0,0,0.04)" },
45383
+ content: /* @__PURE__ */ jsx(CustomTooltip, { hideTotalDuration })
45384
+ }
45385
+ ),
45386
+ /* @__PURE__ */ jsx(
45387
+ Bar,
45388
+ {
45389
+ dataKey: "value",
45390
+ radius: [0, 4, 4, 0],
45391
+ animationDuration: 1500,
45392
+ animationEasing: "ease-out",
45393
+ isAnimationActive: true,
45394
+ barSize: 20,
45395
+ children: activeData.map((entry, index) => /* @__PURE__ */ jsx(Cell, { fill: getColorForEntry(entry) }, `cell-${index}`))
45396
+ }
45397
+ )
45398
+ ]
45399
+ }
45400
+ ) })
45401
+ }
45402
+ );
45403
+ }
45063
45404
  return /* @__PURE__ */ jsxs(Fragment, { children: [
45064
45405
  /* @__PURE__ */ jsx("style", { children: `
45065
45406
  .recharts-wrapper:focus,
@@ -45121,7 +45462,7 @@ var IdleTimeReasonChartComponent = ({
45121
45462
  children: activeData.map((entry, index) => /* @__PURE__ */ jsx(
45122
45463
  Cell,
45123
45464
  {
45124
- fill: getColorForEntry(entry.name, index),
45465
+ fill: getColorForEntry(entry),
45125
45466
  strokeWidth: 0
45126
45467
  },
45127
45468
  `cell-${index}`
@@ -45138,10 +45479,10 @@ var IdleTimeReasonChartComponent = ({
45138
45479
  "span",
45139
45480
  {
45140
45481
  className: "inline-block w-2.5 h-2.5 rounded-full mr-1.5 mt-0.5 flex-shrink-0",
45141
- style: { backgroundColor: getColorForEntry(entry.name, index) }
45482
+ style: { backgroundColor: getColorForEntry(entry) }
45142
45483
  }
45143
45484
  ),
45144
- /* @__PURE__ */ jsx("span", { className: "text-gray-600 leading-tight text-[11px] sm:text-xs break-words", children: entry.name.replace(/_/g, " ") })
45485
+ /* @__PURE__ */ jsx("span", { className: "text-gray-600 leading-tight text-[11px] sm:text-xs break-words", children: entry.displayName || entry.name.replace(/_/g, " ") })
45145
45486
  ] }, `item-${index}`)) }) })
45146
45487
  ]
45147
45488
  }
@@ -45266,7 +45607,6 @@ var LineMonthlyHistory = ({
45266
45607
  const { isIdleTimeVlmEnabled } = useIdleTimeVlmConfig();
45267
45608
  const idleTimeVlmEnabled = isIdleTimeVlmEnabled(lineId);
45268
45609
  const isUptimeMode = monitoringMode === "uptime";
45269
- const effectiveLegend = legend || DEFAULT_EFFICIENCY_LEGEND;
45270
45610
  const chartKey = useMemo(() => `${lineId}-${month}-${year}-${selectedShiftId}-${rangeStart}-${rangeEnd}`, [lineId, month, year, selectedShiftId, rangeStart, rangeEnd]);
45271
45611
  const monthBounds = useMemo(() => getMonthKeyBounds(year, month), [year, month]);
45272
45612
  const normalizedRange = useMemo(() => {
@@ -45314,20 +45654,20 @@ var LineMonthlyHistory = ({
45314
45654
  { efficiency: 0, underperforming: 0, totalWorkspaces: 0, count: 0 }
45315
45655
  );
45316
45656
  const avgEfficiency = averages.count > 0 ? averages.efficiency / averages.count : 0;
45317
- const { underperformingDays, totalDays } = (analysisMonthlyData || []).reduce(
45657
+ const outputAverages = (analysisMonthlyData || []).reduce(
45318
45658
  (acc, day) => {
45319
45659
  const shiftData = getShiftData2(day, selectedShiftId);
45320
45660
  if (!shiftData || !hasRealData(shiftData)) {
45321
45661
  return acc;
45322
45662
  }
45323
- const status = getEfficiencyColor(shiftData.avg_efficiency || 0, effectiveLegend);
45324
45663
  return {
45325
- totalDays: acc.totalDays + 1,
45326
- underperformingDays: acc.underperformingDays + (status === "red" ? 1 : 0)
45664
+ output: acc.output + (shiftData.output || 0),
45665
+ count: acc.count + 1
45327
45666
  };
45328
45667
  },
45329
- { underperformingDays: 0, totalDays: 0 }
45668
+ { output: 0, count: 0 }
45330
45669
  );
45670
+ const avgOutput = outputAverages.count > 0 ? outputAverages.output / outputAverages.count : 0;
45331
45671
  const uptimeSummary = useMemo(() => {
45332
45672
  if (!isUptimeMode) return null;
45333
45673
  const validDays = (analysisMonthlyData || []).map((day) => getShiftData2(day, selectedShiftId)).filter((shiftData) => shiftData && hasRealData(shiftData)).map((shiftData) => ({ shiftData, totals: getUptimeTotals(shiftData) }));
@@ -45360,6 +45700,10 @@ var LineMonthlyHistory = ({
45360
45700
  const efficiencyImproved = efficiencyDelta >= 0;
45361
45701
  const EfficiencyTrendIcon = efficiencyImproved ? ArrowUp : ArrowDown;
45362
45702
  const efficiencyTrendText = `${Math.abs(efficiencyDelta).toFixed(1)}%`;
45703
+ const outputDelta = trendSummary?.avg_daily_output?.delta_pp ?? 0;
45704
+ const outputImproved = outputDelta >= 0;
45705
+ const OutputTrendIcon = outputImproved ? ArrowUp : ArrowDown;
45706
+ const outputTrendText = `${Math.abs(outputDelta).toFixed(1)}%`;
45363
45707
  const utilizationDelta = efficiencyDelta;
45364
45708
  const utilizationImproved = utilizationDelta >= 0;
45365
45709
  const UtilizationTrendIcon = utilizationImproved ? ArrowUp : ArrowDown;
@@ -45644,12 +45988,17 @@ var LineMonthlyHistory = ({
45644
45988
  ] })
45645
45989
  ] }),
45646
45990
  /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-lg shadow-sm border border-gray-100 p-4 flex flex-col justify-between", children: [
45647
- /* @__PURE__ */ jsx("h3", { className: "text-sm font-bold text-gray-700 mb-2", children: "No. of underperforming days" }),
45648
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2 flex-nowrap", children: /* @__PURE__ */ jsxs("div", { className: "text-xl font-bold text-gray-900", children: [
45649
- underperformingDays,
45650
- "/",
45651
- totalDays
45652
- ] }) })
45991
+ /* @__PURE__ */ jsx("h3", { className: "text-sm font-bold text-gray-700 mb-2", children: "Avg. Output" }),
45992
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 flex-nowrap", children: [
45993
+ /* @__PURE__ */ jsx("div", { className: "text-xl font-bold text-gray-900", children: Math.round(avgOutput).toLocaleString() }),
45994
+ /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-1 ${outputImproved ? "bg-emerald-50 text-emerald-600" : "bg-red-50 text-red-600"} px-1.5 py-0.5 rounded-full text-[10px] font-medium whitespace-nowrap flex-shrink-0`, children: [
45995
+ /* @__PURE__ */ jsx(OutputTrendIcon, { className: "w-3 h-3" }),
45996
+ /* @__PURE__ */ jsxs("span", { children: [
45997
+ outputTrendText,
45998
+ " vs last month"
45999
+ ] })
46000
+ ] })
46001
+ ] })
45653
46002
  ] })
45654
46003
  ] }),
45655
46004
  isUptimeMode ? /* @__PURE__ */ jsxs("div", { className: `grid grid-cols-1 ${idleTimeVlmEnabled ? "sm:grid-cols-2" : "sm:grid-cols-1"} gap-2 sm:gap-3 lg:gap-4`, children: [
@@ -46168,11 +46517,6 @@ var LineMonthlyPdfGenerator = ({
46168
46517
  doc.text("Working Days:", 25, kpiStartY + kpiSpacing * 2);
46169
46518
  doc.setFont("helvetica", "bold");
46170
46519
  doc.text(`${outputMetrics.totalDays} days`, 120, kpiStartY + kpiSpacing * 2);
46171
- createKPIBox(kpiStartY + kpiSpacing * 3);
46172
- doc.setFont("helvetica", "normal");
46173
- doc.text("Underperforming Days:", 25, kpiStartY + kpiSpacing * 3);
46174
- doc.setFont("helvetica", "bold");
46175
- doc.text(`${outputMetrics.underperformingDays} of ${outputMetrics.totalDays}`, 120, kpiStartY + kpiSpacing * 3);
46176
46520
  }
46177
46521
  } else {
46178
46522
  doc.setFontSize(12);
@@ -47750,7 +48094,8 @@ var WorkspaceMonthlyHistory = ({
47750
48094
  availableShifts,
47751
48095
  monthlyDataLoading = false,
47752
48096
  className = "",
47753
- trendSummary
48097
+ trendSummary,
48098
+ isAssemblyWorkspace = false
47754
48099
  }) => {
47755
48100
  const effectiveLegend = legend || DEFAULT_EFFICIENCY_LEGEND;
47756
48101
  const isUptimeMode = monitoringMode === "uptime";
@@ -47989,12 +48334,8 @@ var WorkspaceMonthlyHistory = ({
47989
48334
  }, [analysisMonthlyData, selectedShiftId, isUptimeMode, shiftWorkSeconds]);
47990
48335
  const efficiencyDelta = trendSummary?.avg_efficiency?.delta_pp ?? 0;
47991
48336
  const efficiencyImproved = efficiencyDelta >= 0;
47992
- const outputDeltaRaw = trendSummary?.avg_daily_output?.delta_pp ?? 0;
47993
48337
  const cycleDeltaRaw = trendSummary?.avg_cycle_time?.delta_seconds ?? 0;
47994
- const outputPrev = trendSummary?.avg_daily_output?.previous ?? 0;
47995
48338
  const cyclePrev = trendSummary?.avg_cycle_time?.previous ?? 0;
47996
- const outputDelta = outputPrev ? outputDeltaRaw / outputPrev * 100 : 0;
47997
- const outputImproved = outputDelta >= 0;
47998
48339
  const cycleDelta = cyclePrev ? cycleDeltaRaw / cyclePrev * 100 : 0;
47999
48340
  const cycleWorsened = cycleDelta > 0;
48000
48341
  const utilizationDelta = efficiencyDelta;
@@ -48074,7 +48415,7 @@ var WorkspaceMonthlyHistory = ({
48074
48415
  shift.id
48075
48416
  )) }) }),
48076
48417
  /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-2 gap-6", children: [
48077
- /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-xl shadow-sm border border-gray-100 p-4 sm:p-6", children: [
48418
+ /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-xl shadow-sm border border-gray-100 p-4 sm:p-6 flex flex-col", children: [
48078
48419
  /* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 gap-2", children: WEEKDAYS3.map((day, idx) => /* @__PURE__ */ jsx("div", { className: "text-sm font-medium text-gray-500 dark:text-gray-400 text-center", children: day }, day)) }),
48079
48420
  /* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 gap-2 mt-6", children: calendarData.calendar.map((day, index) => {
48080
48421
  const dayNumber = index >= calendarData.startOffset ? index - calendarData.startOffset + 1 : null;
@@ -48162,8 +48503,32 @@ var WorkspaceMonthlyHistory = ({
48162
48503
  ) }, index);
48163
48504
  }) })
48164
48505
  ] }),
48165
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
48166
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-4", children: [
48506
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 h-full", children: [
48507
+ isAssemblyWorkspace && !isUptimeMode ? /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-4 md:grid-cols-2", children: [
48508
+ /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-lg shadow-sm border border-gray-100 p-4 flex flex-col justify-between", children: [
48509
+ /* @__PURE__ */ jsx("div", { className: "text-sm font-semibold text-gray-600 mb-1", children: "Avg Idle Time" }),
48510
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 flex-nowrap", children: [
48511
+ /* @__PURE__ */ jsx("div", { className: "text-2xl font-bold text-gray-900", children: formatIdleTime(metrics2?.avgIdleTime ?? 0) }),
48512
+ /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-1 ${idleImproved ? "bg-emerald-50 text-emerald-600" : "bg-red-50 text-red-600"} px-2 py-0.5 rounded-full text-[10px] font-medium whitespace-nowrap flex-shrink-0`, children: [
48513
+ idleImproved ? /* @__PURE__ */ jsx(ArrowDown, { className: "w-3 h-3" }) : /* @__PURE__ */ jsx(ArrowUp, { className: "w-3 h-3" }),
48514
+ /* @__PURE__ */ jsx("span", { children: idleTrendText })
48515
+ ] })
48516
+ ] })
48517
+ ] }),
48518
+ /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-lg shadow-sm border border-gray-100 p-4 flex flex-col justify-between", children: [
48519
+ /* @__PURE__ */ jsx("div", { className: "text-sm font-semibold text-gray-600 mb-1", children: "Avg Cycle Time" }),
48520
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 flex-nowrap", children: [
48521
+ /* @__PURE__ */ jsxs("div", { className: "text-2xl font-bold text-gray-900", children: [
48522
+ metrics2?.avgCycleTime ?? 0,
48523
+ "s"
48524
+ ] }),
48525
+ /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-1 ${cycleWorsened ? "bg-red-50 text-red-600" : "bg-emerald-50 text-emerald-600"} px-2 py-0.5 rounded-full text-[10px] font-medium whitespace-nowrap flex-shrink-0`, children: [
48526
+ cycleWorsened ? /* @__PURE__ */ jsx(ArrowUp, { className: "w-3 h-3" }) : /* @__PURE__ */ jsx(ArrowDown, { className: "w-3 h-3" }),
48527
+ /* @__PURE__ */ jsx("span", { children: `${Math.abs(cycleDelta).toFixed(1)}% vs last month` })
48528
+ ] })
48529
+ ] })
48530
+ ] })
48531
+ ] }) : /* @__PURE__ */ jsxs("div", { className: `grid grid-cols-1 gap-4 ${isUptimeMode ? "md:grid-cols-3" : "md:grid-cols-2"}`, children: [
48167
48532
  /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-lg shadow-sm border border-gray-100 p-4 flex flex-col justify-between", children: [
48168
48533
  /* @__PURE__ */ jsx("div", { className: "text-sm font-semibold text-gray-600 mb-1", children: isUptimeMode ? "Avg Utilization" : "Avg Efficiency" }),
48169
48534
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 flex-nowrap", children: [
@@ -48177,16 +48542,13 @@ var WorkspaceMonthlyHistory = ({
48177
48542
  ] })
48178
48543
  ] })
48179
48544
  ] }),
48180
- /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-lg shadow-sm border border-gray-100 p-4 flex flex-col justify-between", children: [
48181
- /* @__PURE__ */ jsx("div", { className: "text-sm font-semibold text-gray-600 mb-1", children: isUptimeMode ? "Avg Idle Time" : "Avg Daily Output" }),
48545
+ isUptimeMode && /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-lg shadow-sm border border-gray-100 p-4 flex flex-col justify-between", children: [
48546
+ /* @__PURE__ */ jsx("div", { className: "text-sm font-semibold text-gray-600 mb-1", children: "Avg Idle Time" }),
48182
48547
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 flex-nowrap", children: [
48183
- /* @__PURE__ */ jsx("div", { className: "text-2xl font-bold text-gray-900", children: isUptimeMode ? formatIdleTime(metrics2?.avgIdleTime ?? 0) : metrics2?.avgDailyOutput?.toLocaleString?.() ?? 0 }),
48184
- isUptimeMode ? /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-1 ${idleImproved ? "bg-emerald-50 text-emerald-600" : "bg-red-50 text-red-600"} px-2 py-0.5 rounded-full text-[10px] font-medium whitespace-nowrap flex-shrink-0`, children: [
48548
+ /* @__PURE__ */ jsx("div", { className: "text-2xl font-bold text-gray-900", children: formatIdleTime(metrics2?.avgIdleTime ?? 0) }),
48549
+ /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-1 ${idleImproved ? "bg-emerald-50 text-emerald-600" : "bg-red-50 text-red-600"} px-2 py-0.5 rounded-full text-[10px] font-medium whitespace-nowrap flex-shrink-0`, children: [
48185
48550
  idleImproved ? /* @__PURE__ */ jsx(ArrowDown, { className: "w-3 h-3" }) : /* @__PURE__ */ jsx(ArrowUp, { className: "w-3 h-3" }),
48186
48551
  /* @__PURE__ */ jsx("span", { children: idleTrendText })
48187
- ] }) : /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-1 ${outputImproved ? "bg-emerald-50 text-emerald-600" : "bg-red-50 text-red-600"} px-2 py-0.5 rounded-full text-[10px] font-medium whitespace-nowrap flex-shrink-0`, children: [
48188
- outputImproved ? /* @__PURE__ */ jsx(ArrowUp, { className: "w-3 h-3" }) : /* @__PURE__ */ jsx(ArrowDown, { className: "w-3 h-3" }),
48189
- /* @__PURE__ */ jsx("span", { children: `${Math.abs(outputDelta).toFixed(1)}% vs last month` })
48190
48552
  ] })
48191
48553
  ] })
48192
48554
  ] }),
@@ -48208,9 +48570,9 @@ var WorkspaceMonthlyHistory = ({
48208
48570
  ] })
48209
48571
  ] }),
48210
48572
  /* @__PURE__ */ jsxs("div", { className: `grid grid-cols-1 ${idleTimeVlmEnabled ? "sm:grid-cols-2" : "sm:grid-cols-1"} gap-4`, children: [
48211
- /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-lg shadow-sm border border-gray-100 p-4", children: [
48573
+ /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-lg shadow-sm border border-gray-100 p-4 flex flex-col", children: [
48212
48574
  /* @__PURE__ */ jsx("h3", { className: "text-lg font-bold text-gray-700 mb-3 text-left", children: isUptimeMode ? "Utilization" : "Time Utilization" }),
48213
- pieChartData.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "w-full h-[160px] flex items-center overflow-hidden", children: [
48575
+ pieChartData.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "w-full flex items-center overflow-hidden h-[160px]", children: [
48214
48576
  /* @__PURE__ */ jsx("div", { className: "flex-1 h-full min-w-0 relative flex items-center justify-center", children: /* @__PURE__ */ jsxs("div", { className: "relative w-full aspect-square max-h-full", style: { maxWidth: "min(100%, 280px)", containerType: "inline-size" }, children: [
48215
48577
  /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsx(PieChart, { children: /* @__PURE__ */ jsx(
48216
48578
  Pie,
@@ -48283,7 +48645,7 @@ var WorkspaceMonthlyHistory = ({
48283
48645
  ] }) })
48284
48646
  ] }) : /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-[160px]", children: /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-400", children: "No data available" }) })
48285
48647
  ] }),
48286
- idleTimeVlmEnabled && /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-lg shadow-sm border border-gray-100 p-4 h-full", children: [
48648
+ idleTimeVlmEnabled && /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-lg shadow-sm border border-gray-100 p-4 h-full flex flex-col", children: [
48287
48649
  /* @__PURE__ */ jsx("h3", { className: "text-lg font-bold text-gray-700 mb-3 text-left", children: "Idle Time Breakdown" }),
48288
48650
  /* @__PURE__ */ jsx("div", { className: "h-[160px]", children: /* @__PURE__ */ jsx(
48289
48651
  IdleTimeReasonChart,
@@ -48295,7 +48657,7 @@ var WorkspaceMonthlyHistory = ({
48295
48657
  ) })
48296
48658
  ] })
48297
48659
  ] }),
48298
- /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-lg shadow-sm border border-gray-100 p-4 flex-1", children: [
48660
+ (!isAssemblyWorkspace || isUptimeMode) && /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-lg shadow-sm border border-gray-100 p-4 flex-1", children: [
48299
48661
  /* @__PURE__ */ jsx("h3", { className: "text-lg font-bold text-gray-700 mb-3 text-left", children: isUptimeMode ? "Daily Utilization" : "Daily Output" }),
48300
48662
  /* @__PURE__ */ jsx("div", { style: { height: "220px" }, children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
48301
48663
  BarChart$1,
@@ -48493,7 +48855,7 @@ var WorkspaceWhatsAppShareButton = ({
48493
48855
  }
48494
48856
  );
48495
48857
  };
48496
- var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiencyLegend }) => {
48858
+ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiencyLegend, hourlyCycleTimes }) => {
48497
48859
  const [isGenerating, setIsGenerating] = useState(false);
48498
48860
  const entityConfig = useEntityConfig();
48499
48861
  const effectiveLegend = efficiencyLegend || DEFAULT_EFFICIENCY_LEGEND;
@@ -48501,6 +48863,7 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
48501
48863
  setIsGenerating(true);
48502
48864
  try {
48503
48865
  const isUptimeMode = workspace.monitoring_mode === "uptime";
48866
+ const isAssemblyCycleMode = !isUptimeMode && workspace.line_assembly_enabled === true && workspace.action_type === "assembly";
48504
48867
  const shiftMinutes = getShiftDurationMinutes(workspace.shift_start, workspace.shift_end);
48505
48868
  const shiftSeconds = shiftMinutes ? shiftMinutes * 60 : 0;
48506
48869
  const idleSeconds = Math.max(workspace.idle_time || 0, 0);
@@ -48561,9 +48924,38 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
48561
48924
  minute: "2-digit",
48562
48925
  hour12: true
48563
48926
  });
48927
+ const shiftEndTime = (/* @__PURE__ */ new Date(`2000-01-01 ${workspace.shift_end}`)).toLocaleTimeString("en-IN", {
48928
+ hour: "2-digit",
48929
+ minute: "2-digit",
48930
+ hour12: true
48931
+ });
48932
+ const parseTimeToMinutes3 = (timeValue) => {
48933
+ const [hourPart, minutePart] = timeValue.split(":").map(Number);
48934
+ const hour = Number.isFinite(hourPart) ? hourPart : 0;
48935
+ const minute = Number.isFinite(minutePart) ? minutePart : 0;
48936
+ return hour * 60 + minute;
48937
+ };
48938
+ const toShiftUtcMs = (dateKey, timeValue) => {
48939
+ const [yearPart, monthPart, dayPart] = dateKey.split("-").map(Number);
48940
+ const year = Number.isFinite(yearPart) ? yearPart : 1970;
48941
+ const month = Number.isFinite(monthPart) ? monthPart : 1;
48942
+ const day = Number.isFinite(dayPart) ? dayPart : 1;
48943
+ const [hourPart, minutePart] = timeValue.split(":").map(Number);
48944
+ const hour = Number.isFinite(hourPart) ? hourPart : 0;
48945
+ const minute = Number.isFinite(minutePart) ? minutePart : 0;
48946
+ const IST_OFFSET_MINUTES = 330;
48947
+ return Date.UTC(year, month - 1, day, hour, minute) - IST_OFFSET_MINUTES * 60 * 1e3;
48948
+ };
48949
+ const shiftStartMinutes = parseTimeToMinutes3(workspace.shift_start);
48950
+ const shiftEndMinutes = parseTimeToMinutes3(workspace.shift_end);
48951
+ const wrapsMidnight = shiftEndMinutes <= shiftStartMinutes;
48952
+ const shiftStartUtcMs = toShiftUtcMs(workspace.date, workspace.shift_start);
48953
+ const shiftEndUtcMs = toShiftUtcMs(workspace.date, workspace.shift_end) + (wrapsMidnight ? 24 * 60 * 60 * 1e3 : 0);
48954
+ const isShiftInProgress = Date.now() >= shiftStartUtcMs && Date.now() < shiftEndUtcMs;
48955
+ const reportPeriodEndTime = isShiftInProgress ? currentTime : shiftEndTime;
48564
48956
  doc.setFontSize(12);
48565
48957
  doc.setTextColor(80, 80, 80);
48566
- doc.text(`Report Period: ${shiftStartTime} - ${currentTime}`, 20, 79);
48958
+ doc.text(`Report Period: ${shiftStartTime} - ${reportPeriodEndTime}`, 20, 79);
48567
48959
  doc.setTextColor(0, 0, 0);
48568
48960
  doc.setDrawColor(180, 180, 180);
48569
48961
  doc.setLineWidth(0.8);
@@ -48577,10 +48969,8 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
48577
48969
  };
48578
48970
  const perfOverviewStartY = 93;
48579
48971
  const hasIdleTimeReason = idleTimeReasons && idleTimeReasons.length > 0;
48580
- let perfOverviewHeight = hasIdleTimeReason ? 80 : 70;
48581
- if (isUptimeMode) {
48582
- perfOverviewHeight = hasIdleTimeReason ? 70 : 60;
48583
- }
48972
+ const perfOverviewRows = isUptimeMode ? 3 : isAssemblyCycleMode ? 2 : 4;
48973
+ const perfOverviewHeight = 30 + perfOverviewRows * 10 + (hasIdleTimeReason ? 10 : 0);
48584
48974
  doc.setFillColor(245, 245, 245);
48585
48975
  doc.roundedRect(15, perfOverviewStartY, 180, perfOverviewHeight, 3, 3, "F");
48586
48976
  doc.setFontSize(18);
@@ -48608,6 +48998,19 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
48608
48998
  doc.text("Stoppages:", 25, kpiStartY + kpiSpacing * 2);
48609
48999
  doc.setFont("helvetica", "bold");
48610
49000
  doc.text(`${workspace.total_actions}`, 120, kpiStartY + kpiSpacing * 2);
49001
+ } else if (isAssemblyCycleMode) {
49002
+ createKPIBox(kpiStartY);
49003
+ doc.setFontSize(11);
49004
+ doc.setFont("helvetica", "normal");
49005
+ doc.text("Average Cycle Time:", 25, kpiStartY);
49006
+ doc.setFont("helvetica", "bold");
49007
+ doc.text(`${(workspace.avg_cycle_time || 0).toFixed(1)}s`, 120, kpiStartY);
49008
+ createKPIBox(kpiStartY + kpiSpacing);
49009
+ doc.setFont("helvetica", "normal");
49010
+ doc.text("Total Idle Time:", 25, kpiStartY + kpiSpacing);
49011
+ doc.setFont("helvetica", "bold");
49012
+ const idleTimeFormatted = formatIdleTime(workspace.idle_time);
49013
+ doc.text(idleTimeFormatted, 120, kpiStartY + kpiSpacing);
48611
49014
  } else {
48612
49015
  createKPIBox(kpiStartY);
48613
49016
  doc.setFontSize(11);
@@ -48644,17 +49047,11 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
48644
49047
  const reasonText = `${reasonName} (${topReason.value.toFixed(1)}%)`;
48645
49048
  doc.text(reasonText, 120, reasonY);
48646
49049
  }
48647
- let separatorBeforeHourlyY = hasIdleTimeReason ? 183 : 173;
48648
- if (isUptimeMode) {
48649
- separatorBeforeHourlyY -= 10;
48650
- }
49050
+ const separatorBeforeHourlyY = perfOverviewStartY + perfOverviewHeight + 10;
48651
49051
  doc.setDrawColor(180, 180, 180);
48652
49052
  doc.setLineWidth(0.8);
48653
49053
  doc.line(20, separatorBeforeHourlyY, 190, separatorBeforeHourlyY);
48654
- let hourlyPerfStartY = hasIdleTimeReason ? 188 : 178;
48655
- if (isUptimeMode) {
48656
- hourlyPerfStartY -= 10;
48657
- }
49054
+ const hourlyPerfStartY = separatorBeforeHourlyY + 5;
48658
49055
  const uptimeSeries = isUptimeMode ? buildUptimeSeries({
48659
49056
  idleTimeHourly: workspace.idle_time_hourly,
48660
49057
  shiftStart: workspace.shift_start,
@@ -48672,8 +49069,9 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
48672
49069
  const uptimePercent = total > 0 ? Math.round(activeMinutes / total * 100) : 0;
48673
49070
  return { activeMinutes, idleMinutes, uptimePercent };
48674
49071
  }) : [];
48675
- const hourlyData = isUptimeMode ? hourlyUptime : workspace.hourly_action_counts || [];
49072
+ const hourlyData = isUptimeMode ? hourlyUptime : isAssemblyCycleMode ? hourlyCycleTimes && hourlyCycleTimes.length > 0 ? hourlyCycleTimes : workspace.hourly_action_counts || [] : workspace.hourly_action_counts || [];
48676
49073
  const hourlyTarget = workspace.pph_threshold;
49074
+ const cycleTarget = workspace.ideal_cycle_time || 0;
48677
49075
  const pageHeight = doc.internal.pageSize.height;
48678
49076
  const maxContentY = pageHeight - 15;
48679
49077
  const baseTableStartY = hourlyPerfStartY + 31;
@@ -48698,12 +49096,16 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
48698
49096
  doc.setFont("helvetica", "bold");
48699
49097
  doc.setTextColor(40, 40, 40);
48700
49098
  const hourlyTitleY = hourlyPerfStartY + 10;
48701
- doc.text(isUptimeMode ? "Hourly Utilization" : "Hourly Performance", 20, hourlyTitleY);
49099
+ doc.text(
49100
+ isUptimeMode ? "Hourly Utilization" : isAssemblyCycleMode ? "Hourly Cycle Time" : "Hourly Performance",
49101
+ 20,
49102
+ hourlyTitleY
49103
+ );
48702
49104
  doc.setTextColor(0, 0, 0);
48703
49105
  const headerY = titleFontSize === 16 ? hourlyPerfStartY + 18 : hourlyPerfStartY + 20;
48704
49106
  const gridTopY = headerY - 5;
48705
49107
  const headerBottomY = gridTopY + 8;
48706
- const colBoundaries = isUptimeMode ? [20, 105, 190] : [20, 70, 100, 130, 155, 190];
49108
+ const colBoundaries = isUptimeMode ? [20, 105, 190] : isAssemblyCycleMode ? [20, 85, 125, 165, 190] : [20, 70, 100, 130, 155, 190];
48707
49109
  const totalRows = hourlyData.length;
48708
49110
  const gridBottomY = headerBottomY + totalRows * rowHeight;
48709
49111
  const tableHeight = gridBottomY - gridTopY;
@@ -48724,6 +49126,10 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
48724
49126
  doc.text("Time Range", 25, headerTextY);
48725
49127
  if (isUptimeMode) {
48726
49128
  doc.text("Utilization", 147, headerTextY);
49129
+ } else if (isAssemblyCycleMode) {
49130
+ doc.text("Standard", 90, headerTextY);
49131
+ doc.text("Average", 130, headerTextY);
49132
+ doc.text("Status", 170, headerTextY);
48727
49133
  } else {
48728
49134
  doc.text("Output", 75, headerTextY);
48729
49135
  doc.text("Target", 105, headerTextY);
@@ -48772,6 +49178,25 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
48772
49178
  if (isUptimeMode) {
48773
49179
  const utilizationStr = dataCollected ? `${uptimePercent}%` : "TBD";
48774
49180
  doc.text(utilizationStr, 147, yPos);
49181
+ } else if (isAssemblyCycleMode) {
49182
+ const actualCycleTime = Number(outputValue) || 0;
49183
+ const standardCycleStr = `${cycleTarget.toFixed(1)}s`;
49184
+ const actualCycleStr = dataCollected ? `${actualCycleTime.toFixed(1)}s` : "TBD";
49185
+ doc.text(standardCycleStr, 90, yPos);
49186
+ doc.text(actualCycleStr, 130, yPos);
49187
+ if (!dataCollected) {
49188
+ doc.setTextColor(100, 100, 100);
49189
+ doc.text("-", 170, yPos);
49190
+ } else if (actualCycleTime > 0 && actualCycleTime <= cycleTarget) {
49191
+ doc.setTextColor(0, 171, 69);
49192
+ doc.setFont("ZapfDingbats", "normal");
49193
+ doc.text("4", 170, yPos);
49194
+ doc.setFont("helvetica", "normal");
49195
+ } else {
49196
+ doc.setTextColor(227, 67, 41);
49197
+ doc.text("\xD7", 170, yPos);
49198
+ }
49199
+ doc.setTextColor(0, 0, 0);
48775
49200
  } else {
48776
49201
  doc.text(outputStr, 75, yPos);
48777
49202
  doc.text(targetStr, 105, yPos);
@@ -48843,7 +49268,8 @@ var WorkspaceMonthlyPdfGenerator = ({
48843
49268
  shiftConfig,
48844
49269
  efficiencyLegend,
48845
49270
  className,
48846
- compact = false
49271
+ compact = false,
49272
+ isAssemblyWorkspace = false
48847
49273
  }) => {
48848
49274
  const [isGenerating, setIsGenerating] = useState(false);
48849
49275
  const effectiveLegend = efficiencyLegend || DEFAULT_EFFICIENCY_LEGEND;
@@ -48966,6 +49392,7 @@ var WorkspaceMonthlyPdfGenerator = ({
48966
49392
  avgOutput: filteredShifts.reduce((sum, shift) => sum + shift.output, 0) / filteredShifts.length,
48967
49393
  avgCycleTime: filteredShifts.reduce((sum, shift) => sum + shift.cycleTime, 0) / filteredShifts.length,
48968
49394
  avgPph: filteredShifts.reduce((sum, shift) => sum + shift.pph, 0) / filteredShifts.length,
49395
+ avgIdleTime: filteredShifts.reduce((sum, shift) => sum + shift.idleTime, 0) / filteredShifts.length,
48969
49396
  totalDays: filteredShifts.length,
48970
49397
  underperformingDays: filteredShifts.filter((shift) => shift.efficiency < effectiveLegend.green_min).length
48971
49398
  } : null;
@@ -48977,7 +49404,8 @@ var WorkspaceMonthlyPdfGenerator = ({
48977
49404
  doc.roundedRect(22, y - 7, 165, 12, 2, 2, "S");
48978
49405
  };
48979
49406
  doc.setFillColor(245, 245, 245);
48980
- doc.roundedRect(15, 95, 180, 70, 3, 3, "F");
49407
+ const isAssemblyWorkspaceAndNotUptime = !isUptimeMode && isAssemblyWorkspace;
49408
+ doc.roundedRect(15, 95, 180, isAssemblyWorkspaceAndNotUptime ? 40 : 70, 3, 3, "F");
48981
49409
  doc.setFontSize(18);
48982
49410
  doc.setFont("helvetica", "bold");
48983
49411
  doc.setTextColor(40, 40, 40);
@@ -49016,32 +49444,41 @@ var WorkspaceMonthlyPdfGenerator = ({
49016
49444
  doc.text(`${uptimeMetrics.underperformingDays} of ${uptimeMetrics.totalDays}`, 120, kpiStartY + kpiSpacing * 4);
49017
49445
  } else {
49018
49446
  const outputMetrics = monthlyMetrics;
49019
- createKPIBox(kpiStartY);
49020
- doc.setFontSize(11);
49021
- doc.setFont("helvetica", "normal");
49022
- doc.text("Average Efficiency:", 25, kpiStartY);
49023
- doc.setFont("helvetica", "bold");
49024
- doc.text(`${outputMetrics.avgEfficiency.toFixed(1)}% (Target: ${Math.round(effectiveLegend.green_min)}%)`, 120, kpiStartY);
49025
- createKPIBox(kpiStartY + kpiSpacing);
49026
- doc.setFont("helvetica", "normal");
49027
- doc.text("Average Output:", 25, kpiStartY + kpiSpacing);
49028
- doc.setFont("helvetica", "bold");
49029
- doc.text(`${Math.round(outputMetrics.avgOutput)} pieces`, 120, kpiStartY + kpiSpacing);
49030
- createKPIBox(kpiStartY + kpiSpacing * 2);
49031
- doc.setFont("helvetica", "normal");
49032
- doc.text("Average PPH:", 25, kpiStartY + kpiSpacing * 2);
49033
- doc.setFont("helvetica", "bold");
49034
- doc.text(`${outputMetrics.avgPph.toFixed(1)} per hour`, 120, kpiStartY + kpiSpacing * 2);
49035
- createKPIBox(kpiStartY + kpiSpacing * 3);
49036
- doc.setFont("helvetica", "normal");
49037
- doc.text("Working Days:", 25, kpiStartY + kpiSpacing * 3);
49038
- doc.setFont("helvetica", "bold");
49039
- doc.text(`${outputMetrics.totalDays} days`, 120, kpiStartY + kpiSpacing * 3);
49040
- createKPIBox(kpiStartY + kpiSpacing * 4);
49041
- doc.setFont("helvetica", "normal");
49042
- doc.text("Underperforming Days:", 25, kpiStartY + kpiSpacing * 4);
49043
- doc.setFont("helvetica", "bold");
49044
- doc.text(`${outputMetrics.underperformingDays} of ${outputMetrics.totalDays}`, 120, kpiStartY + kpiSpacing * 4);
49447
+ if (!isAssemblyWorkspace) {
49448
+ createKPIBox(kpiStartY);
49449
+ doc.setFontSize(11);
49450
+ doc.setFont("helvetica", "normal");
49451
+ doc.text("Average Efficiency:", 25, kpiStartY);
49452
+ doc.setFont("helvetica", "bold");
49453
+ doc.text(`${outputMetrics.avgEfficiency.toFixed(1)}% (Target: ${Math.round(effectiveLegend.green_min)}%)`, 120, kpiStartY);
49454
+ createKPIBox(kpiStartY + kpiSpacing);
49455
+ doc.setFont("helvetica", "normal");
49456
+ doc.text("Average PPH:", 25, kpiStartY + kpiSpacing);
49457
+ doc.setFont("helvetica", "bold");
49458
+ doc.text(`${outputMetrics.avgPph.toFixed(1)} per hour`, 120, kpiStartY + kpiSpacing);
49459
+ createKPIBox(kpiStartY + kpiSpacing * 2);
49460
+ doc.setFont("helvetica", "normal");
49461
+ doc.text("Working Days:", 25, kpiStartY + kpiSpacing * 2);
49462
+ doc.setFont("helvetica", "bold");
49463
+ doc.text(`${outputMetrics.totalDays} days`, 120, kpiStartY + kpiSpacing * 2);
49464
+ createKPIBox(kpiStartY + kpiSpacing * 3);
49465
+ doc.setFont("helvetica", "normal");
49466
+ doc.text("Underperforming Days:", 25, kpiStartY + kpiSpacing * 3);
49467
+ doc.setFont("helvetica", "bold");
49468
+ doc.text(`${outputMetrics.underperformingDays} of ${outputMetrics.totalDays}`, 120, kpiStartY + kpiSpacing * 3);
49469
+ } else {
49470
+ createKPIBox(kpiStartY);
49471
+ doc.setFontSize(11);
49472
+ doc.setFont("helvetica", "normal");
49473
+ doc.text("Average Cycle Time:", 25, kpiStartY);
49474
+ doc.setFont("helvetica", "bold");
49475
+ doc.text(`${Math.round(outputMetrics.avgCycleTime)}s`, 120, kpiStartY);
49476
+ createKPIBox(kpiStartY + kpiSpacing);
49477
+ doc.setFont("helvetica", "normal");
49478
+ doc.text("Average Idle Time:", 25, kpiStartY + kpiSpacing);
49479
+ doc.setFont("helvetica", "bold");
49480
+ doc.text(formatIdleTime(outputMetrics.avgIdleTime ?? 0), 120, kpiStartY + kpiSpacing);
49481
+ }
49045
49482
  }
49046
49483
  } else {
49047
49484
  doc.setFontSize(12);
@@ -49052,29 +49489,33 @@ var WorkspaceMonthlyPdfGenerator = ({
49052
49489
  }
49053
49490
  doc.setDrawColor(180, 180, 180);
49054
49491
  doc.setLineWidth(0.8);
49055
- doc.line(20, 180, 190, 180);
49492
+ const separatorY = isAssemblyWorkspaceAndNotUptime ? 150 : 180;
49493
+ doc.line(20, separatorY, 190, separatorY);
49056
49494
  doc.setFillColor(245, 245, 245);
49057
- doc.roundedRect(15, 185, 180, 85, 3, 3, "F");
49495
+ const dailySectionY = isAssemblyWorkspaceAndNotUptime ? 155 : 185;
49496
+ doc.roundedRect(15, dailySectionY, 180, 85, 3, 3, "F");
49058
49497
  doc.setFontSize(18);
49059
49498
  doc.setFont("helvetica", "bold");
49060
49499
  doc.setTextColor(40, 40, 40);
49061
- doc.text(isUptimeMode ? "Daily Utilization Summary" : "Daily Performance Summary", 20, 195);
49500
+ doc.text(isUptimeMode ? "Daily Utilization Summary" : "Daily Performance Summary", 20, dailySectionY + 10);
49062
49501
  doc.setTextColor(0, 0, 0);
49063
49502
  if (validDays.length > 0) {
49064
49503
  doc.setFontSize(10);
49065
49504
  doc.setFont("helvetica", "bold");
49066
49505
  doc.setFillColor(240, 240, 240);
49067
- doc.roundedRect(20, 200, 170, 7, 1, 1, "F");
49068
- doc.text("Date", 25, 205);
49069
- doc.text(isUptimeMode ? "Productive" : "Actual", 60, 205);
49070
- doc.text(isUptimeMode ? "Idle" : "Standard", 95, 205);
49071
- doc.text(isUptimeMode ? "Utilization" : "Efficiency", 135, 205);
49072
- doc.text("Status", 170, 205);
49506
+ const tableHeaderY = dailySectionY + 15;
49507
+ doc.roundedRect(20, tableHeaderY, 170, 7, 1, 1, "F");
49508
+ const textY = tableHeaderY + 5;
49509
+ doc.text("Date", 25, textY);
49510
+ doc.text(isUptimeMode ? "Productive" : isAssemblyWorkspace ? "Cycle Time" : "Actual", 60, textY);
49511
+ doc.text(isUptimeMode ? "Idle" : isAssemblyWorkspace ? "Target CT" : "Standard", 95, textY);
49512
+ doc.text(isUptimeMode ? "Utilization" : "Efficiency", 135, textY);
49513
+ doc.text("Status", 170, textY);
49073
49514
  doc.setLineWidth(0.2);
49074
49515
  doc.setDrawColor(220, 220, 220);
49075
- doc.line(20, 208, 190, 208);
49516
+ doc.line(20, textY + 3, 190, textY + 3);
49076
49517
  doc.setFont("helvetica", "normal");
49077
- let yPos = 215;
49518
+ let yPos = textY + 10;
49078
49519
  const recentDays = validDays.slice(-10).reverse();
49079
49520
  recentDays.forEach((dayData, index) => {
49080
49521
  if (yPos > 260) return;
@@ -49108,8 +49549,13 @@ var WorkspaceMonthlyPdfGenerator = ({
49108
49549
  }
49109
49550
  doc.setTextColor(0, 0, 0);
49110
49551
  } else {
49111
- doc.text(`${shift.output}`, 60, yPos);
49112
- doc.text(`${shift.targetOutput}`, 95, yPos);
49552
+ if (isAssemblyWorkspace) {
49553
+ doc.text(`${shift.cycleTime.toFixed(1)}`, 60, yPos);
49554
+ doc.text(`${shift.pphThreshold > 0 ? (3600 / shift.pphThreshold).toFixed(1) : "-"}`, 95, yPos);
49555
+ } else {
49556
+ doc.text(`${shift.output}`, 60, yPos);
49557
+ doc.text(`${shift.targetOutput}`, 95, yPos);
49558
+ }
49113
49559
  doc.text(`${shift.efficiency.toFixed(1)}%`, 135, yPos);
49114
49560
  if (shift.efficiency >= effectiveLegend.green_min) {
49115
49561
  doc.setTextColor(0, 171, 69);
@@ -49124,12 +49570,12 @@ var WorkspaceMonthlyPdfGenerator = ({
49124
49570
  });
49125
49571
  doc.setLineWidth(0.2);
49126
49572
  doc.setDrawColor(220, 220, 220);
49127
- doc.roundedRect(20, 200, 170, yPos - 200 - 3, 1, 1, "S");
49573
+ doc.roundedRect(20, tableHeaderY, 170, yPos - tableHeaderY - 3, 1, 1, "S");
49128
49574
  } else {
49129
49575
  doc.setFontSize(12);
49130
49576
  doc.setFont("helvetica", "normal");
49131
49577
  doc.setTextColor(100, 100, 100);
49132
- doc.text("No daily data available for this month", 25, 215);
49578
+ doc.text("No daily data available for this month", 25, dailySectionY + 30);
49133
49579
  doc.setTextColor(0, 0, 0);
49134
49580
  }
49135
49581
  doc.setFontSize(9);
@@ -49162,46 +49608,64 @@ var WorkspaceCycleTimeMetricCards = ({
49162
49608
  workspace,
49163
49609
  className,
49164
49610
  legend,
49165
- layout: layout2 = "grid"
49611
+ layout: layout2 = "grid",
49612
+ isAssemblyWorkspace = false,
49613
+ idleTimeData
49166
49614
  }) => {
49167
49615
  const effectiveLegend = legend || DEFAULT_EFFICIENCY_LEGEND;
49168
49616
  const efficiencyValue = workspace.avg_efficiency || 0;
49169
49617
  const efficiencyTarget = effectiveLegend.green_min;
49170
49618
  const efficiencyColor = getEfficiencyHexColor(efficiencyValue, effectiveLegend);
49171
- const hideEfficiencyCard = shouldHideWorkspaceEfficiencyCard(workspace);
49172
- const containerClassName = layout2 === "stack" ? `space-y-4 ${className || ""}` : `grid grid-cols-1 sm:grid-cols-2 ${hideEfficiencyCard ? "lg:grid-cols-2" : "lg:grid-cols-3"} gap-3 min-h-0 ${className || ""}`;
49619
+ const hideEfficiencyCard = isAssemblyWorkspace || shouldHideWorkspaceEfficiencyCard(workspace);
49620
+ const totalCards = 2 + (hideEfficiencyCard ? 0 : 1) + (idleTimeData ? 1 : 0);
49621
+ let gridColsClass = "lg:grid-cols-3";
49622
+ if (totalCards === 4) gridColsClass = "lg:grid-cols-4";
49623
+ else if (totalCards === 2) gridColsClass = "lg:grid-cols-2";
49624
+ const containerClassName = layout2 === "stack" ? `space-y-4 ${className || ""}` : `grid grid-cols-1 gap-4 sm:gap-3 sm:grid-cols-2 ${gridColsClass} w-full h-full min-h-0 ${className || ""}`;
49173
49625
  return /* @__PURE__ */ jsxs("div", { className: containerClassName, children: [
49174
- !hideEfficiencyCard && /* @__PURE__ */ jsxs(Card2, { children: [
49175
- /* @__PURE__ */ jsx(CardHeader2, { className: "pb-2 flex-none", children: /* @__PURE__ */ jsx(CardTitle2, { className: "text-lg text-center", children: "Efficiency" }) }),
49176
- /* @__PURE__ */ jsx(CardContent2, { className: "flex-1 flex items-center justify-center py-6", children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
49177
- /* @__PURE__ */ jsxs("p", { className: "text-5xl font-bold", style: { color: efficiencyColor }, children: [
49626
+ !hideEfficiencyCard && /* @__PURE__ */ jsxs(Card2, { className: "flex flex-col bg-white shadow-sm border border-gray-200 h-full min-h-[150px] sm:min-h-0 rounded-xl", children: [
49627
+ /* @__PURE__ */ jsx(CardHeader2, { className: "pb-1 pt-5 flex-none", children: /* @__PURE__ */ jsx(CardTitle2, { className: "text-[15px] font-bold text-center text-gray-900 tracking-wide", children: "Efficiency" }) }),
49628
+ /* @__PURE__ */ jsxs(CardContent2, { className: "flex-1 flex flex-col items-center justify-center pb-6", children: [
49629
+ /* @__PURE__ */ jsxs("p", { className: "text-5xl font-bold tracking-tight", style: { color: efficiencyColor }, children: [
49178
49630
  efficiencyValue.toFixed(1),
49179
49631
  "%"
49180
49632
  ] }),
49181
- /* @__PURE__ */ jsxs("p", { className: "text-sm text-gray-500 mt-2", children: [
49633
+ /* @__PURE__ */ jsxs("p", { className: "text-xs text-gray-500 mt-1 font-medium tracking-wide", children: [
49182
49634
  "Target: ",
49183
49635
  Math.round(efficiencyTarget),
49184
49636
  "%"
49185
49637
  ] })
49186
- ] }) })
49638
+ ] })
49187
49639
  ] }),
49188
- /* @__PURE__ */ jsxs(Card2, { children: [
49189
- /* @__PURE__ */ jsx(CardHeader2, { className: "pb-2 flex-none", children: /* @__PURE__ */ jsx(CardTitle2, { className: "text-lg text-center", children: "Cycle Time (s)" }) }),
49190
- /* @__PURE__ */ jsx(CardContent2, { className: "flex-1 flex items-center justify-center py-6", children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
49191
- /* @__PURE__ */ jsx("p", { className: `text-5xl font-bold ${workspace.avg_cycle_time > (workspace.ideal_cycle_time || 0) ? "text-red-500" : "text-green-500"}`, children: workspace.avg_cycle_time.toFixed(1) }),
49192
- /* @__PURE__ */ jsxs("p", { className: "text-sm text-gray-500 mt-2", children: [
49640
+ /* @__PURE__ */ jsxs(Card2, { className: "flex flex-col bg-white shadow-sm border border-gray-200 h-full min-h-[150px] sm:min-h-0 rounded-xl", children: [
49641
+ /* @__PURE__ */ jsx(CardHeader2, { className: "pb-1 pt-5 flex-none", children: /* @__PURE__ */ jsx(CardTitle2, { className: "text-[15px] font-bold text-center text-gray-900 tracking-wide", children: "Cycle Time (s)" }) }),
49642
+ /* @__PURE__ */ jsxs(CardContent2, { className: "flex-1 flex flex-col items-center justify-center pb-6", children: [
49643
+ /* @__PURE__ */ jsx("p", { className: `text-5xl font-bold tracking-tight ${workspace.avg_cycle_time > (workspace.ideal_cycle_time || 0) ? "text-red-500" : "text-[#34C759]"}`, children: workspace.avg_cycle_time.toFixed(1) }),
49644
+ /* @__PURE__ */ jsxs("p", { className: "text-xs text-gray-500 mt-1 font-medium tracking-wide", children: [
49193
49645
  "Standard: ",
49194
49646
  workspace.ideal_cycle_time?.toFixed(1) || 0,
49195
49647
  "s"
49196
49648
  ] })
49197
- ] }) })
49649
+ ] })
49198
49650
  ] }),
49199
- /* @__PURE__ */ jsxs(Card2, { children: [
49200
- /* @__PURE__ */ jsx(CardHeader2, { className: "pb-2 flex-none", children: /* @__PURE__ */ jsx(CardTitle2, { className: "text-lg text-center", children: "Idle Time" }) }),
49201
- /* @__PURE__ */ jsx(CardContent2, { className: "flex-1 flex items-center justify-center py-6", children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
49202
- /* @__PURE__ */ jsx("p", { className: `text-4xl font-bold ${!workspace.idle_time || workspace.idle_time <= 0 ? "text-green-500" : workspace.idle_time <= 300 ? "text-yellow-500" : "text-red-500"}`, children: formatIdleTime(workspace.idle_time) }),
49203
- /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500 mt-2", children: "Total idle time" })
49204
- ] }) })
49651
+ /* @__PURE__ */ jsxs(Card2, { className: "flex flex-col bg-white shadow-sm border border-gray-200 h-full min-h-[150px] sm:min-h-0 rounded-xl", children: [
49652
+ /* @__PURE__ */ jsx(CardHeader2, { className: "pb-1 pt-5 flex-none", children: /* @__PURE__ */ jsx(CardTitle2, { className: "text-[15px] font-bold text-center text-gray-900 tracking-wide", children: "Idle Time" }) }),
49653
+ /* @__PURE__ */ jsxs(CardContent2, { className: "flex-1 flex flex-col items-center justify-center pb-6", children: [
49654
+ /* @__PURE__ */ jsx("p", { className: `text-5xl font-bold tracking-tight ${!workspace.idle_time || workspace.idle_time <= 0 ? "text-[#34C759]" : workspace.idle_time <= 300 ? "text-yellow-500" : "text-red-500"}`, children: formatIdleTime(workspace.idle_time) }),
49655
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-500 mt-1 font-medium tracking-wide", children: "Total idle time" })
49656
+ ] })
49657
+ ] }),
49658
+ idleTimeData && /* @__PURE__ */ jsxs(Card2, { className: "flex flex-col bg-white shadow-sm border border-gray-200 h-full min-h-[150px] sm:min-h-0 rounded-xl", children: [
49659
+ /* @__PURE__ */ jsx(CardHeader2, { className: "pb-1 pt-5 flex-none", children: /* @__PURE__ */ jsx(CardTitle2, { className: "text-[15px] font-bold text-center text-gray-900 tracking-wide", children: "Idle Time Breakdown" }) }),
49660
+ /* @__PURE__ */ jsx(CardContent2, { className: "flex-1 p-2 flex items-center justify-center h-full sm:h-auto min-h-[120px] sm:min-h-[100px]", children: /* @__PURE__ */ jsx(
49661
+ IdleTimeReasonChart,
49662
+ {
49663
+ data: idleTimeData.chartData,
49664
+ isLoading: idleTimeData.isLoading,
49665
+ error: idleTimeData.error,
49666
+ variant: "bar"
49667
+ }
49668
+ ) })
49205
49669
  ] })
49206
49670
  ] });
49207
49671
  };
@@ -49339,13 +49803,13 @@ var getWorkspaceStyles = (position, isPlaceholder = false) => {
49339
49803
  ${isPlaceholder ? "cursor-default" : ""}`;
49340
49804
  };
49341
49805
  var formatPercentRange = (min, max) => {
49342
- const format8 = (value) => Number.isInteger(value) ? `${value}` : value.toFixed(1);
49806
+ const format9 = (value) => Number.isInteger(value) ? `${value}` : value.toFixed(1);
49343
49807
  if (min >= 100 || max >= 100) {
49344
- return `${format8(min)}+%`;
49808
+ return `${format9(min)}+%`;
49345
49809
  }
49346
- return `${format8(min)}-${format8(max)}%`;
49810
+ return `${format9(min)}-${format9(max)}%`;
49347
49811
  };
49348
- var Legend6 = ({
49812
+ var Legend5 = ({
49349
49813
  useBottleneckLabel = false,
49350
49814
  legend,
49351
49815
  metricLabel = "Efficiency"
@@ -49531,7 +49995,7 @@ var WorkspaceGrid = React141__default.memo(({
49531
49995
  return /* @__PURE__ */ jsxs("div", { className: `relative w-full h-full overflow-hidden ${className}`, children: [
49532
49996
  /* @__PURE__ */ jsxs("div", { className: "absolute top-0 left-2 sm:left-4 right-2 sm:right-8 z-20", children: [
49533
49997
  /* @__PURE__ */ jsxs("div", { className: "flex flex-row items-center justify-between py-1 sm:py-1.5 gap-2", children: [
49534
- /* @__PURE__ */ jsx("div", { className: "hidden sm:block", children: /* @__PURE__ */ jsx(Legend6, { legend, useBottleneckLabel: hasFlowBuffers, metricLabel: legendMetricLabel }) }),
49998
+ /* @__PURE__ */ jsx("div", { className: "hidden sm:block", children: /* @__PURE__ */ jsx(Legend5, { legend, useBottleneckLabel: hasFlowBuffers, metricLabel: legendMetricLabel }) }),
49535
49999
  mapViewEnabled && /* @__PURE__ */ jsx(
49536
50000
  "button",
49537
50001
  {
@@ -49548,7 +50012,7 @@ var WorkspaceGrid = React141__default.memo(({
49548
50012
  }
49549
50013
  )
49550
50014
  ] }),
49551
- /* @__PURE__ */ jsx("div", { className: "sm:hidden mt-1 mr-32", children: /* @__PURE__ */ jsx(Legend6, { legend, useBottleneckLabel: hasFlowBuffers, metricLabel: legendMetricLabel }) })
50015
+ /* @__PURE__ */ jsx("div", { className: "sm:hidden mt-1 mr-32", children: /* @__PURE__ */ jsx(Legend5, { legend, useBottleneckLabel: hasFlowBuffers, metricLabel: legendMetricLabel }) })
49552
50016
  ] }),
49553
50017
  /* @__PURE__ */ jsx("div", { className: "absolute top-14 sm:top-16 left-0 right-0 bottom-0", children: /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: viewMode === "video" ? /* @__PURE__ */ jsx(
49554
50018
  motion.div,
@@ -50059,7 +50523,7 @@ var KPISection = memo$1(({
50059
50523
  value: showSkeleton ? "" : kpis.efficiency.value,
50060
50524
  change: effChange,
50061
50525
  trend: effTrend,
50062
- trendLabel: "today",
50526
+ trendLabel: "vs yesterday",
50063
50527
  trendMode: "pill",
50064
50528
  suffix: "%",
50065
50529
  showZeroChange: true,
@@ -52295,7 +52759,7 @@ var SideNavBar = memo$1(({
52295
52759
  setIsAlertsOpen(willOpen);
52296
52760
  setIsSettingsOpen(false);
52297
52761
  if (willOpen) {
52298
- trackCoreEvent("Alerts Page Clicked", { source: "side_nav" });
52762
+ trackCoreEvent("Alerts page clicked", { source: "side_nav" });
52299
52763
  void refreshAlertsSummary();
52300
52764
  }
52301
52765
  },
@@ -52450,7 +52914,7 @@ var SideNavBar = memo$1(({
52450
52914
  {
52451
52915
  onClick: () => {
52452
52916
  setIsAlertsOpen(true);
52453
- trackCoreEvent("Alerts Page Clicked", { source: "side_nav_mobile" });
52917
+ trackCoreEvent("Alerts page clicked", { source: "side_nav_mobile" });
52454
52918
  void refreshAlertsSummary();
52455
52919
  onMobileMenuClose?.();
52456
52920
  },
@@ -59660,7 +60124,8 @@ var MonthlyRangeFilter = ({
59660
60124
  onMonthNavigate,
59661
60125
  className,
59662
60126
  variant = "default",
59663
- showLabel = true
60127
+ showLabel = true,
60128
+ singleDateOnly = false
59664
60129
  }) => {
59665
60130
  const todayKey = useMemo(
59666
60131
  () => formatInTimeZone(/* @__PURE__ */ new Date(), timezone || "UTC", "yyyy-MM-dd"),
@@ -59748,6 +60213,12 @@ var MonthlyRangeFilter = ({
59748
60213
  }
59749
60214
  setActivePreset("Custom");
59750
60215
  setPendingChangeMeta({ source: "custom" });
60216
+ if (singleDateOnly) {
60217
+ setRangeStart(day);
60218
+ setRangeEnd(day);
60219
+ setSelecting(false);
60220
+ return;
60221
+ }
59751
60222
  if (!selecting || !rangeStart) {
59752
60223
  setRangeStart(day);
59753
60224
  setRangeEnd(null);
@@ -59782,6 +60253,13 @@ var MonthlyRangeFilter = ({
59782
60253
  };
59783
60254
  const handleApply = () => {
59784
60255
  if (rangeStart) {
60256
+ if (singleDateOnly) {
60257
+ const selected = startOfDay(rangeStart) > startOfDay(today) ? startOfDay(today) : startOfDay(rangeStart);
60258
+ const dateKey = format(selected, "yyyy-MM-dd");
60259
+ onChange({ startKey: dateKey, endKey: dateKey }, pendingChangeMeta || { source: "custom" });
60260
+ setIsOpen(false);
60261
+ return;
60262
+ }
59785
60263
  const boundedStart = startOfDay(rangeStart) > startOfDay(today) ? startOfDay(today) : startOfDay(rangeStart);
59786
60264
  const candidateEnd = rangeEnd || rangeStart;
59787
60265
  const boundedEnd = startOfDay(candidateEnd) > startOfDay(today) ? startOfDay(today) : startOfDay(candidateEnd);
@@ -59876,7 +60354,7 @@ var MonthlyRangeFilter = ({
59876
60354
  "overflow-hidden bg-white animate-in fade-in zoom-in-95 duration-200 flex",
59877
60355
  isInline ? "relative mt-2 w-full rounded-xl border border-gray-200" : "absolute right-0 z-50 mt-2 w-[520px] rounded-xl border border-gray-100 shadow-2xl"
59878
60356
  ), children: [
59879
- /* @__PURE__ */ jsxs("div", { className: "w-40 bg-[#F8FAFF] border-r border-gray-100 p-4 flex flex-col justify-between", children: [
60357
+ !singleDateOnly && /* @__PURE__ */ jsxs("div", { className: "w-40 bg-gray-50 border-r border-gray-100 p-4 flex flex-col justify-between", children: [
59880
60358
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
59881
60359
  presets.map((preset) => /* @__PURE__ */ jsx(
59882
60360
  "button",
@@ -59885,7 +60363,7 @@ var MonthlyRangeFilter = ({
59885
60363
  onClick: () => handlePresetClick(preset),
59886
60364
  className: clsx(
59887
60365
  "w-full text-left px-3 py-2 text-sm rounded-lg transition-all duration-200",
59888
- activePreset === preset.label ? "bg-[#EEF2FF] text-[#4F46E5] font-semibold" : "text-gray-600 hover:bg-gray-100/80"
60366
+ activePreset === preset.label ? "bg-blue-50 text-blue-600 font-semibold" : "text-gray-600 hover:bg-gray-100/80"
59889
60367
  ),
59890
60368
  children: preset.label
59891
60369
  },
@@ -59898,7 +60376,7 @@ var MonthlyRangeFilter = ({
59898
60376
  onClick: () => setActivePreset("Custom"),
59899
60377
  className: clsx(
59900
60378
  "w-full text-left px-3 py-2 text-sm rounded-lg transition-all duration-200",
59901
- activePreset === "Custom" ? "bg-[#EEF2FF] text-[#4F46E5] font-semibold" : "text-gray-600 hover:bg-gray-100/80"
60379
+ activePreset === "Custom" ? "bg-blue-50 text-blue-600 font-semibold" : "text-gray-600 hover:bg-gray-100/80"
59902
60380
  ),
59903
60381
  children: "Custom"
59904
60382
  }
@@ -59920,7 +60398,7 @@ var MonthlyRangeFilter = ({
59920
60398
  type: "button",
59921
60399
  onClick: handleApply,
59922
60400
  disabled: !rangeStart,
59923
- className: "w-full py-2.5 bg-[#4F46E5] text-white text-sm font-semibold rounded-lg hover:bg-[#4338CA] transition-all disabled:opacity-50 disabled:cursor-not-allowed",
60401
+ className: "w-full py-2.5 bg-blue-600 text-white text-sm font-semibold rounded-lg hover:bg-blue-700 transition-all disabled:opacity-50 disabled:cursor-not-allowed",
59924
60402
  children: "Apply"
59925
60403
  }
59926
60404
  )
@@ -59970,9 +60448,9 @@ var MonthlyRangeFilter = ({
59970
60448
  const dayNum = day.getDate();
59971
60449
  const isFutureDay = startOfDay(day) > startOfDay(today);
59972
60450
  return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
59973
- inRange && !isStart && !isEnd && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 -inset-x-0.5 bg-[#EEF2FF] z-0" }),
59974
- inRange && isStart && !isSingleDaySelection && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 right-0 left-1/2 bg-[#EEF2FF] z-0" }),
59975
- inRange && isEnd && !isSingleDaySelection && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 left-0 right-1/2 bg-[#EEF2FF] z-0" }),
60451
+ inRange && !isStart && !isEnd && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 -inset-x-0.5 bg-blue-50 z-0" }),
60452
+ inRange && isStart && !isSingleDaySelection && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 right-0 left-1/2 bg-blue-50 z-0" }),
60453
+ inRange && isEnd && !isSingleDaySelection && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 left-0 right-1/2 bg-blue-50 z-0" }),
59976
60454
  /* @__PURE__ */ jsx(
59977
60455
  "button",
59978
60456
  {
@@ -59981,19 +60459,47 @@ var MonthlyRangeFilter = ({
59981
60459
  disabled: isFutureDay,
59982
60460
  className: clsx(
59983
60461
  "h-10 w-full flex items-center justify-center text-sm font-semibold transition-all duration-150 relative z-10",
59984
- isFutureDay && "text-gray-200 cursor-not-allowed",
60462
+ // Future day NOT in range
60463
+ isFutureDay && !inRange && "text-gray-300 cursor-not-allowed",
59985
60464
  // Not in range
59986
- !isFutureDay && !inRange && "text-gray-700 hover:bg-gray-50 rounded-lg",
60465
+ !isFutureDay && !inRange && "text-gray-700 hover:bg-gray-100 rounded-lg",
59987
60466
  // Middle of range
59988
- inRange && !isStart && !isEnd && "text-[#4F46E5]",
60467
+ inRange && !isStart && !isEnd && clsx(
60468
+ "text-blue-600",
60469
+ isFutureDay && "cursor-not-allowed opacity-60"
60470
+ ),
59989
60471
  // Start/End of range or Single selection
59990
- (isStart || isEnd) && "bg-[#4F46E5] text-white rounded-lg shadow-sm"
60472
+ (isStart || isEnd) && clsx(
60473
+ "bg-blue-600 text-white rounded-lg shadow-sm",
60474
+ isFutureDay && "cursor-not-allowed opacity-80"
60475
+ )
59991
60476
  ),
59992
60477
  children: dayNum
59993
60478
  }
59994
60479
  )
59995
60480
  ] }, day.toISOString());
59996
- }) })
60481
+ }) }),
60482
+ singleDateOnly && /* @__PURE__ */ jsxs("div", { className: "mt-4 flex items-center justify-end gap-2 border-t border-gray-100 pt-3", children: [
60483
+ /* @__PURE__ */ jsx(
60484
+ "button",
60485
+ {
60486
+ type: "button",
60487
+ onClick: handleReset,
60488
+ className: "px-3 py-1.5 text-sm font-medium text-gray-500 hover:text-gray-700 transition-colors",
60489
+ children: "Reset"
60490
+ }
60491
+ ),
60492
+ /* @__PURE__ */ jsx(
60493
+ "button",
60494
+ {
60495
+ type: "button",
60496
+ onClick: handleApply,
60497
+ disabled: !rangeStart,
60498
+ className: "px-4 py-1.5 bg-blue-600 text-white text-sm font-semibold rounded-lg hover:bg-blue-700 transition-all disabled:opacity-50 disabled:cursor-not-allowed",
60499
+ children: "Apply"
60500
+ }
60501
+ )
60502
+ ] })
59997
60503
  ] })
59998
60504
  ] })
59999
60505
  ] });
@@ -61770,7 +62276,36 @@ var getMonthDateInfo = (timezone) => {
61770
62276
  const monthEndDate = fromZonedTime(`${monthEndKey}T23:59:59`, timezone);
61771
62277
  return { startDate, endDate, monthEndDate };
61772
62278
  };
61773
- var LeaderboardCountdown = ({ targetDate, format: format8, finishedLabel = "Finished", placeholder = "--", onFinished }) => {
62279
+ var createKpisOverviewUrl = ({
62280
+ tab,
62281
+ date,
62282
+ shift
62283
+ }) => {
62284
+ const params = new URLSearchParams();
62285
+ if (tab) {
62286
+ params.set("tab", tab);
62287
+ }
62288
+ if (date) {
62289
+ params.set("date", date);
62290
+ }
62291
+ if (typeof shift === "number" && Number.isFinite(shift)) {
62292
+ params.set("shift", shift.toString());
62293
+ }
62294
+ const queryString = params.toString();
62295
+ return queryString ? `/kpis?${queryString}` : "/kpis";
62296
+ };
62297
+ var getZonedDateAtMidday = (dateKey, timezone) => fromZonedTime(`${dateKey}T12:00:00`, timezone);
62298
+ var formatDateKey = (dateKey, timezone, options) => {
62299
+ try {
62300
+ return new Intl.DateTimeFormat("en-US", {
62301
+ ...options,
62302
+ timeZone: timezone
62303
+ }).format(getZonedDateAtMidday(dateKey, timezone));
62304
+ } catch {
62305
+ return dateKey;
62306
+ }
62307
+ };
62308
+ var LeaderboardCountdown = ({ targetDate, format: format9, finishedLabel = "Finished", placeholder = "--", onFinished }) => {
61774
62309
  const [time2, setTime] = useState("");
61775
62310
  const hasFinishedRef = useRef(false);
61776
62311
  useEffect(() => {
@@ -61792,7 +62327,7 @@ var LeaderboardCountdown = ({ targetDate, format: format8, finishedLabel = "Fini
61792
62327
  }
61793
62328
  return;
61794
62329
  }
61795
- if (format8 === "days") {
62330
+ if (format9 === "days") {
61796
62331
  const days = Math.floor(diff / (1e3 * 60 * 60 * 24));
61797
62332
  const hours = Math.floor(diff % (1e3 * 60 * 60 * 24) / (1e3 * 60 * 60));
61798
62333
  setTime(`${days} days ${hours} hours`);
@@ -61807,7 +62342,7 @@ var LeaderboardCountdown = ({ targetDate, format: format8, finishedLabel = "Fini
61807
62342
  tick();
61808
62343
  const interval = setInterval(tick, 1e3);
61809
62344
  return () => clearInterval(interval);
61810
- }, [targetDate, format8, finishedLabel, placeholder, onFinished]);
62345
+ }, [targetDate, format9, finishedLabel, placeholder, onFinished]);
61811
62346
  return /* @__PURE__ */ jsx(Fragment, { children: time2 });
61812
62347
  };
61813
62348
  var LinesLeaderboard = ({
@@ -61825,7 +62360,9 @@ var LinesLeaderboard = ({
61825
62360
  shiftEndDate,
61826
62361
  monthEndDate,
61827
62362
  viewType,
61828
- setViewType
62363
+ setViewType,
62364
+ timezone: _timezone,
62365
+ isHistoricalDaily
61829
62366
  }) => {
61830
62367
  const formatEfficiency = (value) => typeof value === "number" && Number.isFinite(value) ? `${value.toFixed(1)}%` : "--";
61831
62368
  const assignedLineIdSet = React141__default.useMemo(
@@ -61918,10 +62455,10 @@ var LinesLeaderboard = ({
61918
62455
  }
61919
62456
  }, [timeRange, leaderboardData, isLoadingToday, isLoadingMonthly]);
61920
62457
  const topThree = leaderboardData.slice(0, 3);
61921
- leaderboardData.slice(3);
61922
62458
  const countdownTarget = timeRange === "monthly" ? monthEndDate : shiftEndDate;
61923
62459
  const countdownFormat = timeRange === "monthly" ? "days" : "clock";
61924
62460
  const countdownFinishedLabel = timeRange === "monthly" ? "Finished" : "Shift Ended";
62461
+ const showCountdown = timeRange === "monthly" || !isHistoricalDaily;
61925
62462
  const handleCountdownFinished = React141__default.useCallback(() => {
61926
62463
  trackCoreEvent("Leaderboard Countdown Finished", {
61927
62464
  countdown_type: timeRange === "monthly" ? "month_end" : "shift_end",
@@ -61995,7 +62532,7 @@ var LinesLeaderboard = ({
61995
62532
  }
61996
62533
  )
61997
62534
  ] }),
61998
- /* @__PURE__ */ jsx("div", { className: "md:absolute md:right-0 md:top-1/2 md:-translate-y-1/2 flex items-center gap-3", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5 px-4 py-2 bg-white rounded-full shadow-sm border border-gray-100", children: [
62535
+ /* @__PURE__ */ jsx("div", { className: "md:absolute md:right-0 md:top-1/2 md:-translate-y-1/2 flex flex-wrap items-center justify-center md:justify-end gap-2", children: showCountdown && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5 px-4 py-2 bg-white rounded-full shadow-sm border border-gray-100", children: [
61999
62536
  /* @__PURE__ */ jsx(Clock, { className: "w-4 h-4 text-orange-500" }),
62000
62537
  /* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-2", children: [
62001
62538
  /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider", children: "Ends in" }),
@@ -62116,7 +62653,7 @@ var LinesLeaderboard = ({
62116
62653
  /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-gray-900", children: item.supervisorName })
62117
62654
  ] }) }),
62118
62655
  /* @__PURE__ */ jsx("td", { className: "px-4 py-3 whitespace-nowrap text-sm text-gray-500", children: item.line.line_name }),
62119
- /* @__PURE__ */ jsx("td", { className: "px-4 py-3 whitespace-nowrap text-right", children: /* @__PURE__ */ jsx("div", { className: "flex flex-col items-end", children: /* @__PURE__ */ jsx("span", { className: "text-sm font-bold text-gray-900", children: formatEfficiency(item.efficiency) }) }) })
62656
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-3 whitespace-nowrap text-right", children: /* @__PURE__ */ jsx("div", { className: "flex flex-col items-end", children: /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-gray-900", children: formatEfficiency(item.efficiency) }) }) })
62120
62657
  ]
62121
62658
  },
62122
62659
  item.id
@@ -62290,6 +62827,9 @@ var KPIsOverviewView = ({
62290
62827
  const [activeTab, setActiveTab] = useState("today");
62291
62828
  const [timeRange, setTimeRange] = useState("today");
62292
62829
  const [viewType, setViewType] = useState("operator");
62830
+ const [selectedLeaderboardDate, setSelectedLeaderboardDate] = useState("");
62831
+ const [selectedLeaderboardShiftId, setSelectedLeaderboardShiftId] = useState(0);
62832
+ const [hasHydratedLeaderboardRouteState, setHasHydratedLeaderboardRouteState] = useState(false);
62293
62833
  const [loading, setLoading] = useState(true);
62294
62834
  const [error, setError] = useState(null);
62295
62835
  const [topPerformer, setTopPerformer] = useState({
@@ -62311,13 +62851,6 @@ var KPIsOverviewView = ({
62311
62851
  const [monthlyError, setMonthlyError] = useState(null);
62312
62852
  const dailyRequestKeyRef = useRef(null);
62313
62853
  const monthlyRequestKeyRef = useRef(null);
62314
- useEffect(() => {
62315
- if (!router.isReady) return;
62316
- const tab = router.query.tab;
62317
- if (tab === "leaderboard") {
62318
- setActiveTab("leaderboard");
62319
- }
62320
- }, [router.isReady, router.query.tab]);
62321
62854
  const supabase = useSupabase();
62322
62855
  const { user } = useAuth();
62323
62856
  const dashboardConfig = useDashboardConfig();
@@ -62403,7 +62936,77 @@ var KPIsOverviewView = ({
62403
62936
  () => getShiftEndDate(currentShiftDetails, configuredTimezone),
62404
62937
  [currentShiftDetails, configuredTimezone]
62405
62938
  );
62406
- const shiftName = (currentShiftDetails.shiftName || "Day").replace(/ Shift$/i, "");
62939
+ React141__default.useMemo(() => {
62940
+ if (shiftConfig?.shifts && shiftConfig.shifts.length > 0) {
62941
+ return shiftConfig.shifts.map((shift) => ({
62942
+ id: shift.shiftId,
62943
+ label: shift.shiftName || `Shift ${shift.shiftId}`,
62944
+ startTime: shift.startTime,
62945
+ endTime: shift.endTime
62946
+ }));
62947
+ }
62948
+ return [
62949
+ { id: 0, label: "Day Shift", startTime: "06:00", endTime: "18:00" },
62950
+ { id: 1, label: "Night Shift", startTime: "18:00", endTime: "06:00" }
62951
+ ];
62952
+ }, [shiftConfig]);
62953
+ const effectiveLeaderboardDate = selectedLeaderboardDate || currentShiftDate;
62954
+ const effectiveLeaderboardShiftId = Number.isFinite(selectedLeaderboardShiftId) ? selectedLeaderboardShiftId : currentShiftId;
62955
+ const isHistoricalLeaderboardDaily = activeTab === "leaderboard" && timeRange === "today" && (effectiveLeaderboardDate !== currentShiftDate || effectiveLeaderboardShiftId !== currentShiftId);
62956
+ useEffect(() => {
62957
+ if (!router.isReady) return;
62958
+ const tabQuery = router.query.tab;
62959
+ const dateQuery = router.query.date;
62960
+ const shiftQuery = router.query.shift;
62961
+ const parsedShiftQuery = typeof shiftQuery === "string" ? Number.parseInt(shiftQuery, 10) : Number.NaN;
62962
+ const hasHistoricalQuery = tabQuery === "leaderboard" && typeof dateQuery === "string" && Number.isFinite(parsedShiftQuery);
62963
+ setActiveTab(tabQuery === "leaderboard" ? "leaderboard" : "today");
62964
+ if (hasHistoricalQuery) {
62965
+ setSelectedLeaderboardDate(dateQuery);
62966
+ setSelectedLeaderboardShiftId(parsedShiftQuery);
62967
+ setTimeRange("today");
62968
+ } else {
62969
+ setSelectedLeaderboardDate(currentShiftDate);
62970
+ setSelectedLeaderboardShiftId(currentShiftId);
62971
+ }
62972
+ setHasHydratedLeaderboardRouteState(true);
62973
+ }, [
62974
+ router.isReady,
62975
+ router.query.tab,
62976
+ router.query.date,
62977
+ router.query.shift,
62978
+ currentShiftDate,
62979
+ currentShiftId
62980
+ ]);
62981
+ useEffect(() => {
62982
+ if (!router.isReady || !hasHydratedLeaderboardRouteState) return;
62983
+ const expectedTab = activeTab === "leaderboard" ? "leaderboard" : void 0;
62984
+ const expectedDate = activeTab === "leaderboard" && timeRange === "today" && isHistoricalLeaderboardDaily ? effectiveLeaderboardDate : void 0;
62985
+ const expectedShift = expectedDate !== void 0 ? effectiveLeaderboardShiftId.toString() : void 0;
62986
+ const currentTab = typeof router.query.tab === "string" ? router.query.tab : void 0;
62987
+ const currentDateQuery = typeof router.query.date === "string" ? router.query.date : void 0;
62988
+ const currentShiftQuery = typeof router.query.shift === "string" ? router.query.shift : void 0;
62989
+ if (currentTab === expectedTab && currentDateQuery === expectedDate && currentShiftQuery === expectedShift) {
62990
+ return;
62991
+ }
62992
+ void router.replace(
62993
+ createKpisOverviewUrl({
62994
+ tab: expectedTab === "leaderboard" ? "leaderboard" : void 0,
62995
+ date: expectedDate,
62996
+ shift: expectedShift !== void 0 ? Number.parseInt(expectedShift, 10) : void 0
62997
+ }),
62998
+ void 0,
62999
+ { shallow: true }
63000
+ );
63001
+ }, [
63002
+ router,
63003
+ activeTab,
63004
+ timeRange,
63005
+ effectiveLeaderboardDate,
63006
+ effectiveLeaderboardShiftId,
63007
+ hasHydratedLeaderboardRouteState,
63008
+ isHistoricalLeaderboardDaily
63009
+ ]);
62407
63010
  const factoryViewId = entityConfig.factoryViewId || "factory";
62408
63011
  const {
62409
63012
  lineMetrics,
@@ -62578,10 +63181,10 @@ var KPIsOverviewView = ({
62578
63181
  }, [supabase, resolvedCompanyId, leaderboardLinesForView, monthStartDate, monthEndDateKey, viewType]);
62579
63182
  const fetchDailyLeaderboard = useCallback(async () => {
62580
63183
  if (!supabase || !resolvedCompanyId || leaderboardLinesForView.length === 0) return;
62581
- if (!currentShiftDate) return;
63184
+ if (!effectiveLeaderboardDate) return;
62582
63185
  const targetLineIds = leaderboardLinesForView.map((line) => line.id);
62583
63186
  const lineIdsKey = targetLineIds.slice().sort().join(",");
62584
- const requestKey = `${resolvedCompanyId}|${currentShiftDate}|${currentShiftId}|${lineIdsKey}`;
63187
+ const requestKey = `${resolvedCompanyId}|${effectiveLeaderboardDate}|${effectiveLeaderboardShiftId}|${lineIdsKey}`;
62585
63188
  if (dailyRequestKeyRef.current === requestKey) return;
62586
63189
  dailyRequestKeyRef.current = requestKey;
62587
63190
  setDailyLoading(true);
@@ -62589,8 +63192,8 @@ var KPIsOverviewView = ({
62589
63192
  try {
62590
63193
  const entries = await lineLeaderboardService.getDailyLineLeaderboard(supabase, {
62591
63194
  companyId: resolvedCompanyId,
62592
- date: currentShiftDate,
62593
- shiftId: currentShiftId,
63195
+ date: effectiveLeaderboardDate,
63196
+ shiftId: effectiveLeaderboardShiftId,
62594
63197
  lineIds: targetLineIds,
62595
63198
  lineMode: viewType === "machine" ? "uptime" : "output"
62596
63199
  });
@@ -62608,7 +63211,14 @@ var KPIsOverviewView = ({
62608
63211
  } finally {
62609
63212
  setDailyLoading(false);
62610
63213
  }
62611
- }, [supabase, resolvedCompanyId, leaderboardLinesForView, currentShiftDate, currentShiftId, viewType]);
63214
+ }, [
63215
+ supabase,
63216
+ resolvedCompanyId,
63217
+ leaderboardLinesForView,
63218
+ effectiveLeaderboardDate,
63219
+ effectiveLeaderboardShiftId,
63220
+ viewType
63221
+ ]);
62612
63222
  useEffect(() => {
62613
63223
  if (activeTab !== "leaderboard") return;
62614
63224
  fetchMonthlyLeaderboard();
@@ -62697,6 +63307,12 @@ var KPIsOverviewView = ({
62697
63307
  trackProps.status = isEfficiencyOnTrack(kpis.efficiency?.value) ? "On Track" : "Behind";
62698
63308
  }
62699
63309
  trackCoreEvent("Line Card Clicked", trackProps);
63310
+ if (activeTab === "leaderboard" && timeRange === "today" && isHistoricalLeaderboardDaily) {
63311
+ navigation.navigate(
63312
+ `/kpis/${line.id}?date=${encodeURIComponent(effectiveLeaderboardDate)}&shift=${effectiveLeaderboardShiftId}`
63313
+ );
63314
+ return;
63315
+ }
62700
63316
  navigation.navigate(`/kpis/${line.id}`);
62701
63317
  };
62702
63318
  const handleBackClick = useCallback(() => {
@@ -62722,21 +63338,24 @@ var KPIsOverviewView = ({
62722
63338
  });
62723
63339
  setActiveTab(newTab);
62724
63340
  }, [activeTab, leaderboardLines.length, lines.length]);
62725
- const formatLocalDate2 = (date) => {
62726
- const options = {
63341
+ const formatLocalDate2 = useCallback((dateKey) => {
63342
+ return formatDateKey(dateKey, configuredTimezone, {
62727
63343
  year: "numeric",
62728
63344
  month: "long",
62729
63345
  day: "numeric"
62730
- };
62731
- return date.toLocaleDateString("en-US", options);
62732
- };
63346
+ });
63347
+ }, [configuredTimezone]);
62733
63348
  const getMonthRange = () => {
62734
- const now4 = /* @__PURE__ */ new Date();
62735
- const startOfMonth2 = new Date(now4.getFullYear(), now4.getMonth(), 1);
62736
- const endOfMonth2 = new Date(now4.getFullYear(), now4.getMonth() + 1, 0);
62737
- const startLabel = startOfMonth2.toLocaleDateString("en-US", { month: "short", day: "numeric" });
62738
- const endLabel = endOfMonth2.toLocaleDateString("en-US", { month: "short", day: "numeric" });
62739
- return `${startLabel} - ${endLabel}, ${now4.getFullYear()}`;
63349
+ const zonedNow = toZonedTime(/* @__PURE__ */ new Date(), configuredTimezone);
63350
+ const startOfMonthKey = buildDateKey(zonedNow.getFullYear(), zonedNow.getMonth(), 1);
63351
+ const endOfMonthKey = buildDateKey(
63352
+ zonedNow.getFullYear(),
63353
+ zonedNow.getMonth(),
63354
+ new Date(zonedNow.getFullYear(), zonedNow.getMonth() + 1, 0).getDate()
63355
+ );
63356
+ const startLabel = formatDateKey(startOfMonthKey, configuredTimezone, { month: "short", day: "numeric" });
63357
+ const endLabel = formatDateKey(endOfMonthKey, configuredTimezone, { month: "short", day: "numeric" });
63358
+ return `${startLabel} - ${endLabel}, ${zonedNow.getFullYear()}`;
62740
63359
  };
62741
63360
  const isMonthlyMode = activeTab === "leaderboard" && timeRange === "monthly";
62742
63361
  const isLeaderboardLoading = timeRange === "today" ? dailyLoading : monthlyLoading;
@@ -62745,8 +63364,13 @@ var KPIsOverviewView = ({
62745
63364
  const showTopPerformerImage = Boolean(topPerformer.imageUrl) && !topPerformerImageError;
62746
63365
  typeof topPerformer.efficiency === "number" && Number.isFinite(topPerformer.efficiency);
62747
63366
  topPerformerLoading ? "--" : typeof topPerformer.efficiency === "number" && Number.isFinite(topPerformer.efficiency) ? `${topPerformer.efficiency.toFixed(1)}%` : "--";
63367
+ const showHistoricalLeaderboardHeader = activeTab === "leaderboard" && timeRange === "today" && isHistoricalLeaderboardDaily;
63368
+ const headerDateKey = activeTab === "leaderboard" && timeRange === "today" ? effectiveLeaderboardDate : monthEndDateKey;
63369
+ const headerShiftId = showHistoricalLeaderboardHeader ? effectiveLeaderboardShiftId : currentShiftDetails.shiftId;
63370
+ const headerShiftName = getShiftNameById(headerShiftId, configuredTimezone, shiftConfig).replace(/ Shift$/i, "");
63371
+ const headerDateLabel = isMonthlyMode ? getMonthRange() : formatLocalDate2(headerDateKey);
62748
63372
  const getShiftIcon = (shiftId) => {
62749
- const shiftNameLower = shiftName.toLowerCase();
63373
+ const shiftNameLower = getShiftNameById(shiftId, configuredTimezone, shiftConfig).toLowerCase();
62750
63374
  if (shiftNameLower.includes("day") || shiftNameLower.includes("morning") || shiftId === 0) {
62751
63375
  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" }) });
62752
63376
  }
@@ -62849,18 +63473,26 @@ var KPIsOverviewView = ({
62849
63473
  ),
62850
63474
  /* @__PURE__ */ jsx("div", { className: "flex-1 flex items-center justify-center", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
62851
63475
  /* @__PURE__ */ jsx("h1", { className: "text-lg font-semibold text-gray-900", children: activeTab === "leaderboard" ? "Leaderboard" : "Overview" }),
62852
- /* @__PURE__ */ jsx("div", { className: "h-2 w-2 rounded-full bg-emerald-500 animate-pulse ring-2 ring-emerald-500/20" })
63476
+ /* @__PURE__ */ jsx(
63477
+ "div",
63478
+ {
63479
+ className: `h-2 w-2 rounded-full ring-2 ${showHistoricalLeaderboardHeader ? "bg-amber-500 ring-amber-500/20" : "bg-emerald-500 animate-pulse ring-emerald-500/20"}`
63480
+ }
63481
+ )
62853
63482
  ] }) }),
62854
63483
  /* @__PURE__ */ jsx("div", { className: "w-12" })
62855
63484
  ] }),
62856
63485
  /* @__PURE__ */ jsxs("div", { className: "mt-2 flex flex-wrap items-center justify-center gap-2", children: [
62857
- /* @__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: isMonthlyMode ? getMonthRange() : formatLocalDate2(/* @__PURE__ */ new Date()) }) }),
63486
+ /* @__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 }) }),
62858
63487
  !isMonthlyMode && /* @__PURE__ */ jsxs(Fragment, { children: [
62859
63488
  /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
62860
- /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon(currentShiftDetails.shiftId) }),
62861
- /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-700", children: shiftName })
63489
+ /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon(headerShiftId) }),
63490
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-700", children: headerShiftName })
62862
63491
  ] }),
62863
- /* @__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(ISTTimer_default, {}) }) })
63492
+ 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: [
63493
+ /* @__PURE__ */ jsx(Clock, { className: "w-3 h-3" }),
63494
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium", children: "Historical" })
63495
+ ] }) : /* @__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(ISTTimer_default, {}) }) })
62864
63496
  ] })
62865
63497
  ] }),
62866
63498
  activeTab !== "leaderboard" && /* @__PURE__ */ jsx("div", { className: "mt-4 bg-white shadow-md hover:shadow-lg transition-all duration-300 ease-out hover:scale-[1.01] relative rounded-2xl border border-amber-100 pl-2 pr-4 py-1.5 flex items-center justify-between group", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4 min-w-0", children: [
@@ -62961,7 +63593,12 @@ var KPIsOverviewView = ({
62961
63593
  ) }),
62962
63594
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
62963
63595
  /* @__PURE__ */ jsx("h1", { className: "text-2xl md:text-3xl lg:text-4xl font-semibold text-gray-900 tracking-tight", children: activeTab === "leaderboard" ? "Leaderboard" : "Overview" }),
62964
- /* @__PURE__ */ jsx("div", { className: "h-2.5 w-2.5 rounded-full bg-emerald-500 animate-pulse ring-4 ring-emerald-500/10 flex-shrink-0" })
63596
+ /* @__PURE__ */ jsx(
63597
+ "div",
63598
+ {
63599
+ className: `h-2.5 w-2.5 rounded-full ring-4 flex-shrink-0 ${showHistoricalLeaderboardHeader ? "bg-amber-500 ring-amber-500/10" : "bg-emerald-500 animate-pulse ring-emerald-500/10"}`
63600
+ }
63601
+ )
62965
63602
  ] }),
62966
63603
  !topPerformerLoading && activeTab !== "leaderboard" && /* @__PURE__ */ jsx("div", { className: "absolute right-0 top-1/2 -translate-y-1/2 z-10", children: /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-2xl border border-amber-200 shadow-md pl-1.5 pr-4 py-1.5 flex items-center gap-4 transition-all hover:shadow-lg hover:border-amber-300 group", children: [
62967
63604
  /* @__PURE__ */ jsxs("div", { className: "relative", children: [
@@ -63031,7 +63668,7 @@ var KPIsOverviewView = ({
63031
63668
  ] }) })
63032
63669
  ] }),
63033
63670
  /* @__PURE__ */ jsx("div", { className: "bg-blue-50/50 px-4 py-2 rounded-xl border border-blue-100/50 backdrop-blur-sm", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center gap-6", children: [
63034
- !isMonthlyMode && /* @__PURE__ */ jsxs(Fragment, { children: [
63671
+ !isMonthlyMode && !showHistoricalLeaderboardHeader && /* @__PURE__ */ jsxs(Fragment, { children: [
63035
63672
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-blue-700", children: [
63036
63673
  /* @__PURE__ */ jsx("svg", { className: "w-4 h-4 opacity-70", 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" }) }),
63037
63674
  /* @__PURE__ */ jsx("span", { className: "text-base font-semibold tabular-nums", children: /* @__PURE__ */ jsx(ISTTimer_default, {}) })
@@ -63040,16 +63677,23 @@ var KPIsOverviewView = ({
63040
63677
  ] }),
63041
63678
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
63042
63679
  /* @__PURE__ */ jsx("svg", { className: `w-4 h-4 opacity-70 ${isMonthlyMode ? "scale-110" : ""}`, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) }),
63043
- /* @__PURE__ */ jsx("span", { className: `${isMonthlyMode ? "text-base font-medium" : "text-sm font-medium"}`, children: isMonthlyMode ? getMonthRange() : formatLocalDate2(/* @__PURE__ */ new Date()) })
63680
+ /* @__PURE__ */ jsx("span", { className: `${isMonthlyMode ? "text-base font-medium" : "text-sm font-medium"}`, children: headerDateLabel })
63044
63681
  ] }),
63045
63682
  !isMonthlyMode && /* @__PURE__ */ jsxs(Fragment, { children: [
63046
63683
  /* @__PURE__ */ jsx("div", { className: "w-px h-4 bg-blue-200" }),
63047
63684
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
63048
- /* @__PURE__ */ jsx("div", { className: "opacity-70", children: getShiftIcon(currentShiftDetails.shiftId) }),
63685
+ /* @__PURE__ */ jsx("div", { className: "opacity-70", children: getShiftIcon(headerShiftId) }),
63049
63686
  /* @__PURE__ */ jsxs("span", { className: "text-sm font-semibold uppercase tracking-wider", children: [
63050
- shiftName,
63687
+ headerShiftName,
63051
63688
  " Shift"
63052
63689
  ] })
63690
+ ] }),
63691
+ showHistoricalLeaderboardHeader && /* @__PURE__ */ jsxs(Fragment, { children: [
63692
+ /* @__PURE__ */ jsx("div", { className: "w-px h-4 bg-blue-200" }),
63693
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-2.5 py-1 bg-amber-50 text-amber-700 rounded-full border border-amber-200", children: [
63694
+ /* @__PURE__ */ jsx(Clock, { className: "w-3.5 h-3.5" }),
63695
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold uppercase tracking-wider", children: "Historical" })
63696
+ ] })
63053
63697
  ] })
63054
63698
  ] })
63055
63699
  ] }) }),
@@ -63072,19 +63716,52 @@ var KPIsOverviewView = ({
63072
63716
  }
63073
63717
  )
63074
63718
  ] }),
63075
- (activeTab === "leaderboard" || activeTab === "today") && showViewTypeDropdown && /* @__PURE__ */ jsx("div", { className: "relative", children: /* @__PURE__ */ jsxs(
63076
- "select",
63077
- {
63078
- value: viewType,
63079
- onChange: (e) => setViewType(e.target.value),
63080
- 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",
63081
- 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` },
63082
- children: [
63083
- /* @__PURE__ */ jsx("option", { value: "operator", children: "Workforce" }),
63084
- /* @__PURE__ */ jsx("option", { value: "machine", children: "Machine" })
63085
- ]
63086
- }
63087
- ) })
63719
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
63720
+ activeTab === "leaderboard" && timeRange === "today" && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
63721
+ /* @__PURE__ */ jsx(
63722
+ MonthlyRangeFilter_default,
63723
+ {
63724
+ month: parseDateKeyToDate(effectiveLeaderboardDate).getMonth(),
63725
+ year: parseDateKeyToDate(effectiveLeaderboardDate).getFullYear(),
63726
+ timezone: configuredTimezone,
63727
+ value: {
63728
+ startKey: effectiveLeaderboardDate,
63729
+ endKey: effectiveLeaderboardDate
63730
+ },
63731
+ onChange: (range) => {
63732
+ setSelectedLeaderboardDate(range.startKey);
63733
+ },
63734
+ showLabel: false,
63735
+ singleDateOnly: true
63736
+ }
63737
+ ),
63738
+ isHistoricalLeaderboardDaily && /* @__PURE__ */ jsx(
63739
+ "button",
63740
+ {
63741
+ type: "button",
63742
+ onClick: () => {
63743
+ setSelectedLeaderboardDate(currentShiftDate);
63744
+ setSelectedLeaderboardShiftId(currentShiftId);
63745
+ },
63746
+ className: "text-xs font-medium text-blue-600 hover:text-blue-700 whitespace-nowrap",
63747
+ children: "Return to Live"
63748
+ }
63749
+ )
63750
+ ] }),
63751
+ (activeTab === "leaderboard" || activeTab === "today") && showViewTypeDropdown && /* @__PURE__ */ jsx("div", { className: "relative", children: /* @__PURE__ */ jsxs(
63752
+ "select",
63753
+ {
63754
+ value: viewType,
63755
+ onChange: (e) => setViewType(e.target.value),
63756
+ 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",
63757
+ 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` },
63758
+ children: [
63759
+ /* @__PURE__ */ jsx("option", { value: "operator", children: "Workforce" }),
63760
+ /* @__PURE__ */ jsx("option", { value: "machine", children: "Machine" })
63761
+ ]
63762
+ }
63763
+ ) })
63764
+ ] })
63088
63765
  ] })
63089
63766
  ] })
63090
63767
  ] }) }),
@@ -63129,7 +63806,9 @@ var KPIsOverviewView = ({
63129
63806
  shiftEndDate,
63130
63807
  monthEndDate,
63131
63808
  viewType,
63132
- setViewType
63809
+ setViewType,
63810
+ timezone: configuredTimezone,
63811
+ isHistoricalDaily: isHistoricalLeaderboardDaily
63133
63812
  }
63134
63813
  ) })
63135
63814
  ) })
@@ -64671,51 +65350,41 @@ var ClipsCostView = () => {
64671
65350
  /* @__PURE__ */ jsx("div", { className: "min-w-[120px]" })
64672
65351
  ] }) })
64673
65352
  ] }) }),
64674
- /* @__PURE__ */ jsx("main", { className: "flex-1 p-4 sm:p-6 lg:p-8 max-w-7xl mx-auto w-full", children: error ? /* @__PURE__ */ jsxs("div", { className: "p-4 bg-red-50 border border-red-200 rounded-lg flex items-start gap-3 text-red-700 animate-in fade-in slide-in-from-top-2 max-w-2xl mx-auto", children: [
65353
+ /* @__PURE__ */ jsx("main", { className: "flex-1 p-4 sm:p-6 lg:p-8 max-w-5xl mx-auto w-full", children: error ? /* @__PURE__ */ jsxs("div", { className: "p-4 bg-red-50 border border-red-200 rounded-lg flex items-start gap-3 text-red-700 animate-in fade-in slide-in-from-top-2 max-w-2xl mx-auto", children: [
64675
65354
  /* @__PURE__ */ jsx(AlertCircle, { className: "h-5 w-5 flex-shrink-0 mt-0.5" }),
64676
65355
  /* @__PURE__ */ jsxs("div", { children: [
64677
65356
  /* @__PURE__ */ jsx("h3", { className: "font-medium", children: "Error loading usage data" }),
64678
65357
  /* @__PURE__ */ jsx("p", { className: "text-sm mt-1 text-red-600", children: error })
64679
65358
  ] })
64680
- ] }) : /* @__PURE__ */ jsxs("div", { className: "max-w-xl mt-8 animate-in fade-in slide-in-from-bottom-4 duration-500", children: [
64681
- /* @__PURE__ */ jsx(Card2, { className: "overflow-hidden shadow-sm border-gray-200 bg-white", children: /* @__PURE__ */ jsx(CardContent2, { className: "p-8", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center text-center", children: [
64682
- /* @__PURE__ */ jsx("div", { className: "p-3 bg-blue-50 rounded-full mb-4", children: /* @__PURE__ */ jsx(Film, { className: "h-8 w-8 text-blue-600" }) }),
64683
- /* @__PURE__ */ jsx("h2", { className: "text-sm font-medium text-gray-500 uppercase tracking-wider mb-2", children: "Clips Analyzed" }),
64684
- /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-500 mb-3", children: formatMonthLabel(data?.monthStart) }),
64685
- /* @__PURE__ */ jsx("div", { className: "text-5xl font-bold text-gray-900 mb-2 tabular-nums tracking-tight", children: formatNumber(data?.monthlyClassifications || 0) })
64686
- ] }) }) }),
64687
- /* @__PURE__ */ jsx(Card2, { className: "mt-4 overflow-hidden shadow-sm border-gray-200 bg-white", children: /* @__PURE__ */ jsxs(CardContent2, { className: "p-6", children: [
64688
- /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-gray-900 mb-3 uppercase tracking-wider", children: "Previous Months" }),
64689
- (data?.historicalMonthlyClassifications?.length || 0) === 0 ? /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500", children: "No historical month usage yet." }) : /* @__PURE__ */ jsx("div", { className: "space-y-2", children: data?.historicalMonthlyClassifications.map((item) => /* @__PURE__ */ jsxs(
65359
+ ] }) : /* @__PURE__ */ jsxs("div", { className: "mt-8 grid grid-cols-1 lg:grid-cols-3 gap-6 animate-in fade-in slide-in-from-bottom-4 duration-500", children: [
65360
+ /* @__PURE__ */ jsx("div", { className: "lg:col-span-2", children: /* @__PURE__ */ jsx(Card2, { className: "overflow-hidden shadow-sm border-gray-200 bg-white h-full flex flex-col justify-center", children: /* @__PURE__ */ jsx(CardContent2, { className: "p-10 lg:p-14", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center text-center", children: [
65361
+ /* @__PURE__ */ jsx("div", { className: "p-4 bg-blue-50/50 rounded-2xl mb-6 ring-1 ring-blue-100/50", children: /* @__PURE__ */ jsx(Film, { className: "h-10 w-10 text-blue-600", strokeWidth: 1.5 }) }),
65362
+ /* @__PURE__ */ jsx("h2", { className: "text-base font-semibold text-gray-600 uppercase tracking-widest mb-3", children: "Current Month Usage" }),
65363
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-gray-400 mb-6", children: formatMonthLabel(data?.monthStart) }),
65364
+ /* @__PURE__ */ jsx("div", { className: "flex items-baseline gap-2 mb-2", children: /* @__PURE__ */ jsx("div", { className: "text-7xl font-bold text-gray-900 tabular-nums tracking-tighter", children: formatNumber(data?.monthlyClassifications || 0) }) }),
65365
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500 mt-4", children: "Clips analyzed and processed by our AI pipeline" })
65366
+ ] }) }) }) }),
65367
+ /* @__PURE__ */ jsx("div", { className: "lg:col-span-1", children: /* @__PURE__ */ jsx(Card2, { className: "overflow-hidden shadow-sm border-gray-200 bg-white h-full", children: /* @__PURE__ */ jsxs(CardContent2, { className: "p-6 lg:p-8 flex flex-col h-full", children: [
65368
+ /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-gray-900 mb-6 uppercase tracking-widest", children: "Previous Months" }),
65369
+ (data?.historicalMonthlyClassifications?.length || 0) === 0 ? /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col items-center justify-center text-center py-8", children: [
65370
+ /* @__PURE__ */ jsx("div", { className: "p-3 bg-gray-50 rounded-full mb-3", children: /* @__PURE__ */ jsx(Film, { className: "h-6 w-6 text-gray-400", strokeWidth: 1.5 }) }),
65371
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500", children: "No historical month usage yet." })
65372
+ ] }) : /* @__PURE__ */ jsx("div", { className: "space-y-3 flex-1 overflow-y-auto pr-2", children: data?.historicalMonthlyClassifications.map((item) => /* @__PURE__ */ jsxs(
64690
65373
  "div",
64691
65374
  {
64692
- className: "flex items-center justify-between rounded-md border border-gray-100 bg-gray-50 px-3 py-2",
65375
+ className: "group flex items-center justify-between rounded-xl border border-gray-100 bg-gray-50/50 hover:bg-white hover:border-gray-200 hover:shadow-sm px-4 py-3.5 transition-all duration-200",
64693
65376
  children: [
64694
- /* @__PURE__ */ jsx("span", { className: "text-sm text-gray-700", children: formatMonthLabel(item.monthStart) }),
64695
- /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-gray-900 tabular-nums", children: formatNumber(item.classifications) })
65377
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-gray-600 group-hover:text-gray-900 transition-colors", children: formatMonthLabel(item.monthStart) }),
65378
+ /* @__PURE__ */ jsx("span", { className: "text-base font-semibold text-gray-900 tabular-nums", children: formatNumber(item.classifications) })
64696
65379
  ]
64697
65380
  },
64698
65381
  item.monthStart
64699
65382
  )) })
64700
- ] }) })
65383
+ ] }) }) })
64701
65384
  ] }) })
64702
65385
  ] });
64703
65386
  };
64704
65387
  var ClipsCostView_default = ClipsCostView;
64705
-
64706
- // src/lib/constants/actions.ts
64707
- var ACTION_NAMES = {
64708
- /** Assembly operations */
64709
- ASSEMBLY: "Assembly",
64710
- /** Packaging operations */
64711
- PACKAGING: "Packaging",
64712
- /** Inspection operations */
64713
- INSPECTION: "Inspection",
64714
- /** Testing operations */
64715
- TESTING: "Testing",
64716
- /** Quality control operations */
64717
- QUALITY_CONTROL: "Quality Control"
64718
- };
64719
65388
  var calculateShiftHours = (startTime, endTime, breaks = []) => {
64720
65389
  if (!startTime || !endTime) return 8;
64721
65390
  const [startHour, startMinute] = startTime.split(":").map(Number);
@@ -65297,9 +65966,9 @@ var ShiftsView = ({
65297
65966
  const actionIds = Array.from(
65298
65967
  new Set(currentThresholds.map((threshold) => threshold.action_id).filter(Boolean))
65299
65968
  );
65300
- const actionNameById = /* @__PURE__ */ new Map();
65969
+ const actionMetadataById = /* @__PURE__ */ new Map();
65301
65970
  if (actionIds.length > 0) {
65302
- const { data: actionRows, error: actionsError } = await supabase.from("actions").select("id, action_name").in("id", actionIds);
65971
+ const { data: actionRows, error: actionsError } = await supabase.from("actions").select("id, action_name, action_family").in("id", actionIds);
65303
65972
  if (actionsError) {
65304
65973
  console.warn(
65305
65974
  `[ShiftsView] Failed to resolve action names for line ${lineId}, shift ${shift.shiftId}: ${actionsError.message}`
@@ -65307,7 +65976,13 @@ var ShiftsView = ({
65307
65976
  } else {
65308
65977
  (actionRows || []).forEach((actionRow) => {
65309
65978
  if (actionRow.id && actionRow.action_name) {
65310
- actionNameById.set(actionRow.id, actionRow.action_name);
65979
+ actionMetadataById.set(actionRow.id, {
65980
+ action_name: actionRow.action_name,
65981
+ action_family: normalizeActionFamily({
65982
+ actionFamily: actionRow.action_family,
65983
+ actionName: actionRow.action_name
65984
+ })
65985
+ });
65311
65986
  }
65312
65987
  });
65313
65988
  }
@@ -65328,7 +66003,7 @@ var ShiftsView = ({
65328
66003
  nextDayOutput = dayOutputToKeep;
65329
66004
  nextPPH = newShiftHours > 0 ? Math.round(dayOutputToKeep / newShiftHours) : 0;
65330
66005
  }
65331
- const resolvedActionName = (typeof threshold.action_name === "string" && threshold.action_name.trim().length > 0 ? threshold.action_name : actionNameById.get(threshold.action_id)) || ACTION_NAMES.ASSEMBLY;
66006
+ const resolvedActionName = (typeof threshold.action_name === "string" && threshold.action_name.trim().length > 0 ? threshold.action_name : actionMetadataById.get(threshold.action_id)?.action_name) || ACTION_NAMES.ASSEMBLY;
65332
66007
  return {
65333
66008
  line_id: threshold.line_id || lineId,
65334
66009
  shift_id: shift.shiftId,
@@ -65349,18 +66024,20 @@ var ShiftsView = ({
65349
66024
  `Failed to update action thresholds for line ${lineId}, shift ${shift.shiftId}: ${thresholdsUpsertError.message}`
65350
66025
  );
65351
66026
  }
65352
- const packagingActionIds = new Set(
65353
- Array.from(actionNameById.entries()).filter(([, actionName]) => actionName.toLowerCase() === ACTION_NAMES.PACKAGING.toLowerCase()).map(([actionId]) => actionId)
66027
+ const outputActionIds = new Set(
66028
+ Array.from(actionMetadataById.entries()).filter(([, action]) => action.action_family === ACTION_FAMILIES.OUTPUT).map(([actionId]) => actionId)
65354
66029
  );
65355
- const packagingThresholds = recalculatedThresholds.filter((threshold) => {
65356
- if (packagingActionIds.has(threshold.action_id)) return true;
65357
- return typeof threshold.action_name === "string" && threshold.action_name.toLowerCase() === ACTION_NAMES.PACKAGING.toLowerCase();
66030
+ const outputThresholds = recalculatedThresholds.filter((threshold) => {
66031
+ if (outputActionIds.has(threshold.action_id)) return true;
66032
+ return normalizeActionFamily({
66033
+ actionName: threshold.action_name
66034
+ }) === ACTION_FAMILIES.OUTPUT;
65358
66035
  });
65359
- const thresholdDayOutput = packagingThresholds.reduce(
66036
+ const thresholdDayOutput = outputThresholds.reduce(
65360
66037
  (sum, threshold) => sum + (Number(threshold.total_day_output) || 0),
65361
66038
  0
65362
66039
  );
65363
- const thresholdPPH = packagingThresholds.reduce(
66040
+ const thresholdPPH = outputThresholds.reduce(
65364
66041
  (sum, threshold) => sum + (Number(threshold.pph_threshold) || 0),
65365
66042
  0
65366
66043
  );
@@ -66571,7 +67248,7 @@ var TargetsViewUI = ({
66571
67248
  "aria-label": `Action type for ${formattedName}`,
66572
67249
  children: [
66573
67250
  /* @__PURE__ */ jsx("option", { value: "assembly", className: "py-2", children: "Assembly" }),
66574
- /* @__PURE__ */ jsx("option", { value: "packaging", className: "py-2", children: "Packaging" })
67251
+ /* @__PURE__ */ jsx("option", { value: "output", className: "py-2", children: ACTION_NAMES.OUTPUT })
66575
67252
  ]
66576
67253
  }
66577
67254
  ) }),
@@ -66642,7 +67319,7 @@ var TargetsViewUI = ({
66642
67319
  "aria-label": `Action type for ${formattedName}`,
66643
67320
  children: [
66644
67321
  /* @__PURE__ */ jsx("option", { value: "assembly", children: "Assembly" }),
66645
- /* @__PURE__ */ jsx("option", { value: "packaging", children: "Packaging" })
67322
+ /* @__PURE__ */ jsx("option", { value: "output", children: ACTION_NAMES.OUTPUT })
66646
67323
  ]
66647
67324
  }
66648
67325
  )
@@ -66847,14 +67524,20 @@ var TargetsView = ({
66847
67524
  throw new Error("Failed to fetch bulk targets data");
66848
67525
  }
66849
67526
  const { data } = bulkResponse;
66850
- const assemblyAction = Object.values(data.actions).find((a) => a.action_name === ACTION_NAMES.ASSEMBLY);
66851
- const packagingAction = Object.values(data.actions).find((a) => a.action_name === ACTION_NAMES.PACKAGING);
66852
- if (!assemblyAction || !packagingAction) {
67527
+ const assemblyAction = data.actions[ACTION_FAMILIES.ASSEMBLY] || Object.values(data.actions).find((a) => normalizeActionFamily({
67528
+ actionFamily: a.action_family,
67529
+ actionName: a.action_name
67530
+ }) === ACTION_FAMILIES.ASSEMBLY);
67531
+ const outputAction = data.actions[ACTION_FAMILIES.OUTPUT] || Object.values(data.actions).find((a) => normalizeActionFamily({
67532
+ actionFamily: a.action_family,
67533
+ actionName: a.action_name
67534
+ }) === ACTION_FAMILIES.OUTPUT);
67535
+ if (!assemblyAction || !outputAction) {
66853
67536
  throw new Error("Could not find required actions in bulk response");
66854
67537
  }
66855
67538
  const actionIdsData = {
66856
67539
  assembly: assemblyAction.id,
66857
- packaging: packagingAction.id
67540
+ output: outputAction.id
66858
67541
  };
66859
67542
  setActionIds(actionIdsData);
66860
67543
  const newAllShiftsData = {};
@@ -66899,12 +67582,16 @@ var TargetsView = ({
66899
67582
  let actionType = "assembly";
66900
67583
  let actionId = actionIdsData.assembly;
66901
67584
  const effectiveActionId = threshold?.action_id ?? ws.action_id;
66902
- if (effectiveActionId === packagingAction.id || !effectiveActionId && ws.action_type === "packaging") {
66903
- actionType = "packaging";
66904
- actionId = packagingAction.id;
66905
- } else if (effectiveActionId === assemblyAction.id || !effectiveActionId && ws.action_type === "assembly") {
67585
+ const effectiveActionFamily = normalizeActionFamily({
67586
+ actionFamily: threshold?.action_family,
67587
+ actionType: ws.action_type
67588
+ });
67589
+ if (effectiveActionFamily === ACTION_FAMILIES.OUTPUT || effectiveActionId === outputAction.id || !effectiveActionId && ws.action_type === "output") {
67590
+ actionType = "output";
67591
+ actionId = effectiveActionId || outputAction.id;
67592
+ } else if (effectiveActionFamily === ACTION_FAMILIES.ASSEMBLY || effectiveActionId === assemblyAction.id || !effectiveActionId && ws.action_type === "assembly") {
66906
67593
  actionType = "assembly";
66907
- actionId = assemblyAction.id;
67594
+ actionId = effectiveActionId || assemblyAction.id;
66908
67595
  }
66909
67596
  return {
66910
67597
  id: ws.id,
@@ -67176,7 +67863,9 @@ var TargetsView = ({
67176
67863
  // Round to whole number
67177
67864
  ideal_cycle_time: Number(ws.targetCycleTime) || 0,
67178
67865
  total_day_output: Number(ws.targetDayOutput) || 0,
67179
- action_name: ws.actionType === "assembly" ? ACTION_NAMES.ASSEMBLY : ACTION_NAMES.PACKAGING,
67866
+ action_name: ws.actionType === "assembly" ? ACTION_NAMES.ASSEMBLY : ACTION_NAMES.OUTPUT,
67867
+ action_family: ws.actionType,
67868
+ display_name: ws.actionType === "assembly" ? ACTION_NAMES.ASSEMBLY : ACTION_NAMES.OUTPUT,
67180
67869
  updated_by: currentEffectiveUserId,
67181
67870
  // Use the potentially hardcoded ID
67182
67871
  ...skuEnabled && lineDataToSave.selectedSKU ? { sku_id: lineDataToSave.selectedSKU.id } : {}
@@ -67184,7 +67873,7 @@ var TargetsView = ({
67184
67873
  console.log(`[handleSaveLine] workspaceThresholdUpdates for ${lineId}:`, workspaceThresholdUpdates);
67185
67874
  await workspaceService.updateActionThresholds(workspaceThresholdUpdates);
67186
67875
  console.log(`[handleSaveLine] Successfully updated action thresholds for ${lineId}`);
67187
- const packagingWorkspaces = lineDataToSave.workspaces.filter((ws) => ws.actionType === "packaging");
67876
+ const outputWorkspaces = lineDataToSave.workspaces.filter((ws) => ws.actionType === "output");
67188
67877
  let resolvedLineThresholdSkuId = lineDataToSave.selectedSKU?.id || null;
67189
67878
  if (!resolvedLineThresholdSkuId) {
67190
67879
  const { data: dummySkuRows, error: dummySkuError } = await supabase.from("skus").select("id").eq("line_id", lineId).eq("sku_definition", "dummy_definition").eq("is_active", true).limit(1);
@@ -67202,8 +67891,8 @@ var TargetsView = ({
67202
67891
  date: currentDate,
67203
67892
  shift_id: selectedShift,
67204
67893
  product_code: lineDataToSave.productId,
67205
- threshold_day_output: packagingWorkspaces.reduce((acc, ws) => acc + (Number(ws.targetDayOutput) || 0), 0),
67206
- threshold_pph: packagingWorkspaces.reduce((acc, ws) => acc + (ws.targetPPH ? Math.round(Number(ws.targetPPH)) : 0), 0),
67894
+ threshold_day_output: outputWorkspaces.reduce((acc, ws) => acc + (Number(ws.targetDayOutput) || 0), 0),
67895
+ threshold_pph: outputWorkspaces.reduce((acc, ws) => acc + (ws.targetPPH ? Math.round(Number(ws.targetPPH)) : 0), 0),
67207
67896
  // Round each PPH value
67208
67897
  sku_id: resolvedLineThresholdSkuId
67209
67898
  };
@@ -67731,6 +68420,7 @@ var WorkspaceDetailView = ({
67731
68420
  avg_efficiency: Number(cachedOverviewMetrics.efficiency || 0),
67732
68421
  total_actions: totalActions,
67733
68422
  hourly_action_counts: [],
68423
+ hourly_cycle_times: [],
67734
68424
  workspace_rank: 0,
67735
68425
  total_workspaces: 0,
67736
68426
  ideal_output_until_now: idealOutput,
@@ -67741,6 +68431,22 @@ var WorkspaceDetailView = ({
67741
68431
  }, [cachedOverviewMetrics, shiftConfig?.shifts]);
67742
68432
  const workspace = (isHistoricView ? historicMetrics : liveMetrics) || cachedDetailedMetrics || overviewFallback;
67743
68433
  const detailedWorkspaceMetrics = (isHistoricView ? historicMetrics : liveMetrics) || cachedDetailedMetrics;
68434
+ const cycleTimeChartData = useMemo(
68435
+ () => Array.isArray(workspace?.hourly_cycle_times) ? workspace.hourly_cycle_times.map((value) => {
68436
+ const numericValue = Number(value);
68437
+ return Number.isFinite(numericValue) ? numericValue : 0;
68438
+ }) : [],
68439
+ [workspace?.hourly_cycle_times]
68440
+ );
68441
+ const cycleTimeDatasetKey = useMemo(
68442
+ () => [
68443
+ workspace?.workspace_id || workspaceId || "workspace",
68444
+ date || workspace?.date || "live",
68445
+ parsedShiftId ?? workspace?.shift_id ?? "current",
68446
+ "hourly"
68447
+ ].join(":"),
68448
+ [workspace?.workspace_id, workspaceId, date, workspace?.date, parsedShiftId, workspace?.shift_id]
68449
+ );
67744
68450
  const hasWorkspaceSnapshot = Boolean(workspace);
67745
68451
  const loading = ((isHistoricView ? historicLoading : liveLoading) || isShiftConfigLoading) && !hasWorkspaceSnapshot;
67746
68452
  const error = isHistoricView ? historicError : liveError;
@@ -67982,10 +68688,47 @@ var WorkspaceDetailView = ({
67982
68688
  return filterDataByDateKeyRange(monthlyData, range);
67983
68689
  }, [monthlyData, range]);
67984
68690
  const formattedWorkspaceName = displayName || formatWorkspaceName3(workspace?.workspace_name || "", effectiveLineId);
67985
- const shouldShowCycleTimeChart = !isUptimeMode && (showCycleTimeChart ?? formattedWorkspaceName.startsWith("FINAL ASSY"));
68691
+ const workspaceActionType = workspace && "action_type" in workspace ? workspace.action_type : void 0;
68692
+ const workspaceAssemblyEnabled = workspace && "line_assembly_enabled" in workspace ? workspace.line_assembly_enabled === true : false;
68693
+ const isAssemblyWorkspace = workspaceActionType === "assembly" || workspaceAssemblyEnabled;
68694
+ const shouldShowCycleTimeChart = !isUptimeMode && (showCycleTimeChart ?? isAssemblyWorkspace);
67986
68695
  const showIdleBreakdownChart = !shouldShowCycleTimeChart && idleTimeVlmEnabled;
67987
68696
  const idleClipDate = date || workspace?.date || calculatedOperationalDate || getOperationalDate(timezone);
67988
68697
  const idleClipShiftId = parsedShiftId ?? workspace?.shift_id;
68698
+ const hourlyIdleMinutes = useMemo(() => {
68699
+ if (!shouldShowCycleTimeChart || !workspace?.idle_time_hourly || !workspace?.shift_start) return [];
68700
+ const parseTimeToMinutes3 = (time2) => {
68701
+ const [h, m] = time2.split(":").map(Number);
68702
+ if (!Number.isFinite(h) || !Number.isFinite(m)) return 0;
68703
+ return h * 60 + m;
68704
+ };
68705
+ const startTotal = parseTimeToMinutes3(workspace.shift_start);
68706
+ const endTotalRaw = workspace.shift_end ? parseTimeToMinutes3(workspace.shift_end) : startTotal + 11 * 60;
68707
+ const endTotal = endTotalRaw <= startTotal ? endTotalRaw + 24 * 60 : endTotalRaw;
68708
+ const shiftDuration = Math.max(60, endTotal - startTotal);
68709
+ const totalHourSlots = Math.max(1, Math.ceil(shiftDuration / 60));
68710
+ const idleTimeHourlyObj = workspace.idle_time_hourly || {};
68711
+ const result = Array(totalHourSlots).fill(0);
68712
+ for (let i = 0; i < totalHourSlots; i++) {
68713
+ const startSlotMins = startTotal + i * 60;
68714
+ let endSlotMins = startSlotMins + 60;
68715
+ if (endSlotMins > endTotal) endSlotMins = endTotal;
68716
+ let idleCount = 0;
68717
+ for (let m = startSlotMins; m < endSlotMins; m++) {
68718
+ const hourKey = Math.floor(m / 60) % 24;
68719
+ const minuteKey = m % 60;
68720
+ const hourData = idleTimeHourlyObj[hourKey.toString()] || [];
68721
+ if (Array.isArray(hourData)) {
68722
+ const val = hourData[minuteKey];
68723
+ if (val === 1 || val === "1") {
68724
+ idleCount++;
68725
+ }
68726
+ }
68727
+ }
68728
+ result[i] = idleCount;
68729
+ }
68730
+ return result;
68731
+ }, [shouldShowCycleTimeChart, workspace?.idle_time_hourly, workspace?.shift_start, workspace?.shift_end]);
67989
68732
  const shiftDurationMinutes = useMemo(
67990
68733
  () => getShiftDurationMinutes(workspace?.shift_start, workspace?.shift_end),
67991
68734
  [workspace?.shift_start, workspace?.shift_end]
@@ -68058,7 +68801,7 @@ var WorkspaceDetailView = ({
68058
68801
  }
68059
68802
  }, [returnUrl]);
68060
68803
  const handleBackNavigation = () => {
68061
- if (date || shift) {
68804
+ if (isHistoricView) {
68062
68805
  setActiveTab("monthly_history");
68063
68806
  if (onNavigate) {
68064
68807
  const params = new URLSearchParams();
@@ -68222,7 +68965,7 @@ var WorkspaceDetailView = ({
68222
68965
  BackButtonMinimal,
68223
68966
  {
68224
68967
  onClick: handleBackNavigation,
68225
- text: previousView === "line_monthly_history" ? "Back to Line History" : returnUrl && returnUrl.includes("monthly_history") ? "Back to Line History" : returnUrl && returnUrl.includes("/kpis/") ? "Back to KPIs" : returnUrl && returnUrl.includes("/leaderboard/") ? "Back to Leaderboard" : (date || shift) && activeTab !== "monthly_history" ? "Back to Monthly History" : "Back",
68968
+ text: previousView === "line_monthly_history" ? "Back to Line History" : returnUrl && returnUrl.includes("monthly_history") ? "Back to Line History" : returnUrl && returnUrl.includes("/kpis/") ? "Back to KPIs" : returnUrl && returnUrl.includes("/leaderboard/") ? "Back to Leaderboard" : isHistoricView && activeTab !== "monthly_history" ? "Back to Monthly History" : "Back",
68226
68969
  size: "default",
68227
68970
  "aria-label": "Navigate back to previous page"
68228
68971
  }
@@ -68399,7 +69142,8 @@ var WorkspaceDetailView = ({
68399
69142
  {
68400
69143
  workspace,
68401
69144
  idleTimeReasons: idleTimeChartData,
68402
- efficiencyLegend
69145
+ efficiencyLegend,
69146
+ hourlyCycleTimes: cycleTimeChartData
68403
69147
  }
68404
69148
  ) }),
68405
69149
  activeTab === "monthly_history" && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
@@ -68480,7 +69224,7 @@ var WorkspaceDetailView = ({
68480
69224
  animate: "animate",
68481
69225
  children: [
68482
69226
  /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center mb-4", children: [
68483
- /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold text-gray-700", children: isUptimeMode ? "Machine Utilization" : shouldShowCycleTimeChart ? "Cycle Time (last 60 minutes)" : "Hourly Output" }),
69227
+ /* @__PURE__ */ jsx("h3", { className: "text-lg font-bold text-gray-700", children: isUptimeMode ? "Machine Utilization" : shouldShowCycleTimeChart ? "Cycle time trend" : "Hourly Output" }),
68484
69228
  !isUptimeMode && /* @__PURE__ */ jsx(
68485
69229
  "button",
68486
69230
  {
@@ -68513,9 +69257,14 @@ var WorkspaceDetailView = ({
68513
69257
  ) : shouldShowCycleTimeChart ? /* @__PURE__ */ jsx(
68514
69258
  CycleTimeOverTimeChart,
68515
69259
  {
68516
- data: workspace.hourly_action_counts || [],
69260
+ data: cycleTimeChartData,
68517
69261
  idealCycleTime: workspace.ideal_cycle_time || 0,
68518
- shiftStart: workspace.shift_start || ""
69262
+ shiftStart: workspace.shift_start || "",
69263
+ shiftEnd: workspace.shift_end || "",
69264
+ xAxisMode: "hourly",
69265
+ datasetKey: cycleTimeDatasetKey,
69266
+ showIdleTime: showChartIdleTime,
69267
+ idleTimeData: hourlyIdleMinutes
68519
69268
  }
68520
69269
  ) : /* @__PURE__ */ jsx(
68521
69270
  HourlyOutputChart2,
@@ -68562,7 +69311,8 @@ var WorkspaceDetailView = ({
68562
69311
  {
68563
69312
  workspace,
68564
69313
  legend: efficiencyLegend,
68565
- layout: "stack"
69314
+ layout: "stack",
69315
+ idleTimeData: idleTimeVlmEnabled ? idleTimeData : void 0
68566
69316
  }
68567
69317
  ) : /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(WorkspaceMetricCards, { workspace, legend: efficiencyLegend, className: "flex-1" }) })
68568
69318
  ] }),
@@ -68607,7 +69357,7 @@ var WorkspaceDetailView = ({
68607
69357
  animate: "animate",
68608
69358
  children: [
68609
69359
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3 mb-4 flex-none", children: [
68610
- /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold text-gray-700", children: isUptimeMode ? "Machine Utilization" : shouldShowCycleTimeChart ? "Cycle Time (last 60 minutes)" : "Hourly Output" }),
69360
+ /* @__PURE__ */ jsx("h3", { className: "text-lg font-bold text-gray-700", children: isUptimeMode ? "Machine Utilization" : shouldShowCycleTimeChart ? "Cycle time trend" : "Hourly Output" }),
68611
69361
  !isUptimeMode && /* @__PURE__ */ jsx(
68612
69362
  "button",
68613
69363
  {
@@ -68636,9 +69386,14 @@ var WorkspaceDetailView = ({
68636
69386
  ) : shouldShowCycleTimeChart ? /* @__PURE__ */ jsx(
68637
69387
  CycleTimeOverTimeChart,
68638
69388
  {
68639
- data: workspace.hourly_action_counts || [],
69389
+ data: cycleTimeChartData,
68640
69390
  idealCycleTime: workspace.ideal_cycle_time || 0,
68641
- shiftStart: workspace.shift_start || ""
69391
+ shiftStart: workspace.shift_start || "",
69392
+ shiftEnd: workspace.shift_end || "",
69393
+ xAxisMode: "hourly",
69394
+ datasetKey: cycleTimeDatasetKey,
69395
+ showIdleTime: showChartIdleTime,
69396
+ idleTimeData: hourlyIdleMinutes
68642
69397
  }
68643
69398
  ) : /* @__PURE__ */ jsx(
68644
69399
  HourlyOutputChart2,
@@ -68690,7 +69445,8 @@ var WorkspaceDetailView = ({
68690
69445
  workspace,
68691
69446
  legend: efficiencyLegend,
68692
69447
  layout: "grid",
68693
- className: desktopBottomSectionClass
69448
+ className: desktopBottomSectionClass,
69449
+ idleTimeData: idleTimeVlmEnabled ? idleTimeData : void 0
68694
69450
  }
68695
69451
  ) : /* @__PURE__ */ jsx("div", { className: clsx("flex min-h-0", desktopBottomSectionClass), children: /* @__PURE__ */ jsx(WorkspaceMetricCards, { workspace, legend: efficiencyLegend, className: "flex-1" }) })
68696
69452
  ] })
@@ -68720,6 +69476,7 @@ var WorkspaceDetailView = ({
68720
69476
  availableShifts: shiftConfig?.shifts?.map((s) => ({ id: s.shiftId, name: s.shiftName })),
68721
69477
  legend: efficiencyLegend,
68722
69478
  trendSummary: workspaceMonthlyTrend,
69479
+ isAssemblyWorkspace,
68723
69480
  onDateSelect: (selectedDate, shiftId) => {
68724
69481
  if (onDateSelect) {
68725
69482
  onDateSelect(selectedDate, shiftId);
@@ -74807,6 +75564,11 @@ var normalizeTrend = (value) => ({
74807
75564
  });
74808
75565
  var normalizeIdleBreakdown = (value) => (value || []).map((item) => ({
74809
75566
  reason: item?.reason?.trim() || "Unknown",
75567
+ reason_key: item?.reason_key?.trim() || item?.reason?.trim() || "unknown",
75568
+ display_name: item?.display_name?.trim() || void 0,
75569
+ palette_token: item?.palette_token?.trim() || void 0,
75570
+ icon_token: item?.icon_token?.trim() || void 0,
75571
+ is_known: typeof item?.is_known === "boolean" ? item.is_known : null,
74810
75572
  percentage: normalizeNumber(item?.percentage),
74811
75573
  total_duration_seconds: normalizeNumber(item?.total_duration_seconds),
74812
75574
  efficiency_loss_percentage: normalizeNumber(item?.efficiency_loss_percentage),
@@ -75858,7 +76620,12 @@ var IdleBreakdownCard = React141__default.memo(({
75858
76620
  const showInitialSkeleton = idle.loading && idle.lastUpdated === null;
75859
76621
  const idleBreakdown = React141__default.useMemo(() => {
75860
76622
  return idle.data.map((item) => ({
75861
- name: item.reason?.trim() || "Unknown",
76623
+ name: item.display_name?.trim() || item.reason?.trim() || "Unknown",
76624
+ reasonKey: item.reason_key?.trim() || item.reason?.trim() || "unknown",
76625
+ displayName: item.display_name?.trim() || item.reason?.trim() || "Unknown",
76626
+ paletteToken: item.palette_token?.trim(),
76627
+ iconToken: item.icon_token?.trim(),
76628
+ isKnown: item.is_known ?? void 0,
75862
76629
  value: toNumber3(item.percentage) || 0,
75863
76630
  totalDurationSeconds: toNumber3(item.total_duration_seconds),
75864
76631
  efficiencyLossPercentage: toNumber3(item.efficiency_loss_percentage),
@@ -77150,4 +77917,4 @@ var streamProxyConfig = {
77150
77917
  }
77151
77918
  };
77152
77919
 
77153
- export { 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, Legend6 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, 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, getReasonColor, 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, isSafari, isSupervisorRole, isTransitionPeriod, isUrlPermanentlyFailed, isValidFactoryViewConfiguration, isValidLineInfoPayload, isValidPrefetchParams, isValidPrefetchStatus, isValidWorkspaceDetailedMetricsPayload, isValidWorkspaceMetricsPayload, isWorkspaceDisplayNamesLoaded, isWorkspaceDisplayNamesLoading, lineLeaderboardService, linesService, mergeWithDefaultConfig, migrateLegacyConfiguration, normalizeDateKeyRange, normalizeRoleLevel, 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 };
77920
+ 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 };