@optifye/dashboard-core 6.11.12 → 6.11.14

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,40 @@ 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);
33537
- var getVideoGridBaseColorState = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => getEfficiencyColor(getVideoGridMetricValue(workspace), legend);
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
+ };
33538
33782
  var isLowWipGreenOverride = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => {
33539
- if (!hasAssemblyRecentFlow(workspace)) {
33783
+ if (!hasVideoGridRecentFlow(workspace) || !isVideoGridWipGated(workspace)) {
33540
33784
  return false;
33541
33785
  }
33542
33786
  if (getVideoGridBaseColorState(workspace, legend) !== "red") {
@@ -33575,7 +33819,10 @@ var getSyntheticLowWipDisplayValue = (workspace, minuteBucket) => {
33575
33819
  var getVideoGridDisplayValue = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND, minuteBucket) => isLowWipGreenOverride(workspace, legend) ? getSyntheticLowWipDisplayValue(workspace, minuteBucket) : getVideoGridMetricValue(workspace);
33576
33820
  var getVideoGridColorState = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => {
33577
33821
  const baseColor = getVideoGridBaseColorState(workspace, legend);
33578
- if (!hasAssemblyRecentFlow(workspace)) {
33822
+ if (!hasVideoGridRecentFlow(workspace)) {
33823
+ return baseColor;
33824
+ }
33825
+ if (!isVideoGridWipGated(workspace)) {
33579
33826
  return baseColor;
33580
33827
  }
33581
33828
  if (baseColor !== "red") {
@@ -33597,11 +33844,11 @@ var getVideoGridLegendLabel = (workspaces) => {
33597
33844
  if (visibleWorkspaces.length === 0) {
33598
33845
  return MAP_GRID_LEGEND_LABEL;
33599
33846
  }
33600
- const assemblyEnabledCount = visibleWorkspaces.filter(isAssemblyFlowEnabled).length;
33601
- if (assemblyEnabledCount === 0) {
33847
+ const recentFlowEnabledCount = visibleWorkspaces.filter(isVideoGridRecentFlowEnabled).length;
33848
+ if (recentFlowEnabledCount === 0) {
33602
33849
  return MAP_GRID_LEGEND_LABEL;
33603
33850
  }
33604
- if (assemblyEnabledCount === visibleWorkspaces.length) {
33851
+ if (recentFlowEnabledCount === visibleWorkspaces.length) {
33605
33852
  return VIDEO_GRID_LEGEND_LABEL;
33606
33853
  }
33607
33854
  return MIXED_VIDEO_GRID_LEGEND_LABEL;
@@ -33651,7 +33898,11 @@ var VideoCard = React141__default.memo(({
33651
33898
  const videoGridMetricValue = getVideoGridMetricValue(workspace);
33652
33899
  const videoGridDisplayValue = getVideoGridDisplayValue(workspace, effectiveLegend, displayMinuteBucket);
33653
33900
  const videoGridColorState = getVideoGridColorState(workspace, effectiveLegend);
33654
- const badgeTitle = hasAssemblyRecentFlow(workspace) ? `Flow ${Math.round(videoGridDisplayValue)}%` : `Efficiency ${Math.round(videoGridDisplayValue)}%`;
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";
33655
33906
  const efficiencyOverlayClass = videoGridColorState === "green" ? "bg-[#00D654]/25" : videoGridColorState === "yellow" ? "bg-[#FFD700]/30" : videoGridColorState === "red" ? "bg-[#FF2D0A]/30" : "bg-transparent";
33656
33907
  const efficiencyBarClass = videoGridColorState === "green" ? "bg-[#00AB45]" : videoGridColorState === "yellow" ? "bg-[#FFB020]" : videoGridColorState === "red" ? "bg-[#E34329]" : "bg-gray-500/70";
33657
33908
  const efficiencyStatus = videoGridColorState === "green" ? "High" : videoGridColorState === "yellow" ? "Medium" : videoGridColorState === "red" ? "Low" : "Neutral";
@@ -33733,10 +33984,7 @@ var VideoCard = React141__default.memo(({
33733
33984
  "data-testid": "video-card-metric-badge",
33734
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`,
33735
33986
  title: badgeTitle,
33736
- children: /* @__PURE__ */ jsxs("span", { className: `${compact ? "text-[10px]" : "text-xs"} font-semibold`, children: [
33737
- Math.round(videoGridDisplayValue),
33738
- "%"
33739
- ] })
33987
+ children: /* @__PURE__ */ jsx("span", { className: `${compact ? "text-[10px]" : "text-xs"} font-semibold`, children: badgeLabel })
33740
33988
  }
33741
33989
  ) }),
33742
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(
@@ -33744,7 +33992,7 @@ var VideoCard = React141__default.memo(({
33744
33992
  {
33745
33993
  "data-testid": "video-card-metric-bar",
33746
33994
  className: `h-full ${efficiencyBarClass} transition-all duration-500`,
33747
- style: { width: `${Math.min(100, videoGridMetricValue)}%` }
33995
+ style: { width: `${hasBarMetric ? Math.min(100, Math.max(0, videoGridMetricValue)) : videoGridColorState === "neutral" ? 100 : 0}%` }
33748
33996
  }
33749
33997
  ) })
33750
33998
  ] }),
@@ -33775,7 +34023,7 @@ var VideoCard = React141__default.memo(({
33775
34023
  }
33776
34024
  );
33777
34025
  }, (prevProps, nextProps) => {
33778
- 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) {
33779
34027
  return false;
33780
34028
  }
33781
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) {
@@ -39299,45 +39547,56 @@ var FileManagerFilters = ({
39299
39547
  });
39300
39548
  const [loadingPercentile, setLoadingPercentile] = useState(false);
39301
39549
  const resolvedTargetCycleTime = targetCycleTime && targetCycleTime > 0 ? targetCycleTime : null;
39302
- const getRootCauseConfig = (reason) => {
39303
- const colorConfig = getIdleTimeReasonColor(reason);
39304
- let Icon2 = HelpCircle;
39305
- if (reason.includes("Machine Breakdown")) Icon2 = AlertTriangle;
39306
- else if (reason.includes("Material")) Icon2 = Package;
39307
- else if (reason.includes("Worker") || reason.includes("Absent")) Icon2 = UserX;
39308
- else if (reason.includes("Quality")) Icon2 = XCircle;
39309
- else if (reason.includes("Power")) Icon2 = Zap;
39310
- else if (reason.includes("Maintenance") || reason.includes("Tool")) Icon2 = Wrench;
39311
- 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
+ });
39312
39565
  return {
39313
- color: colorConfig.text,
39314
- bgColor: colorConfig.bg,
39315
- borderColor: colorConfig.border,
39316
- Icon: Icon2,
39317
- 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
39318
39572
  };
39319
- };
39320
- const normalizeIdleReasonLabel = useCallback((label) => {
39321
- return label.replace(/_/g, " ").trim();
39322
39573
  }, []);
39323
- const getIdleTimeRootCause = useCallback((clipId) => {
39324
- const classification = mergedClipClassifications[clipId];
39325
- if (!classification) return "processing";
39326
- if (classification.status === "processing") return "processing";
39327
- return classification.label || "processing";
39328
- }, [mergedClipClassifications]);
39329
39574
  const idleReasonOptions = useMemo(() => {
39330
39575
  const idleClips = clipMetadata["idle_time"] || [];
39331
- const uniqueReasons = /* @__PURE__ */ new Set();
39576
+ const uniqueReasons = /* @__PURE__ */ new Map();
39332
39577
  idleClips.forEach((clip) => {
39333
39578
  const clipId = clip.clipId || clip.id;
39334
39579
  if (!clipId) return;
39335
- const reason = getIdleTimeRootCause(clipId);
39336
- if (!reason || reason === "processing") return;
39337
- 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
+ }
39338
39593
  });
39339
- return Array.from(uniqueReasons).sort((a, b) => a.localeCompare(b));
39340
- }, [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
+ );
39341
39600
  const getClipBadge = useCallback((node) => {
39342
39601
  if (node.categoryId === "idle_time" || node.categoryId === "low_value") {
39343
39602
  return { text: "Idle", className: "bg-red-100 text-red-700" };
@@ -39409,6 +39668,10 @@ var FileManagerFilters = ({
39409
39668
  seededClassifications[clip.clipId] = {
39410
39669
  status: clip.classification_status,
39411
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,
39412
39675
  confidence: clip.classification_confidence ?? void 0
39413
39676
  };
39414
39677
  }
@@ -39792,7 +40055,7 @@ var FileManagerFilters = ({
39792
40055
  return slot ? slot.label : value;
39793
40056
  }, [timeSlots]);
39794
40057
  const isClipInTimeRange = useCallback((clipTimestamp) => {
39795
- if (!isTimeFilterActive || !startTime || !endTime) {
40058
+ if (!startTime || !endTime) {
39796
40059
  return true;
39797
40060
  }
39798
40061
  try {
@@ -39818,9 +40081,8 @@ var FileManagerFilters = ({
39818
40081
  let filteredClips = categoryClips.filter((clip) => isClipInTimeRange(clip.clip_timestamp));
39819
40082
  if (category.id === "idle_time" && idleLabelFilter) {
39820
40083
  filteredClips = filteredClips.filter((clip) => {
39821
- const rootCause = getIdleTimeRootCause(clip.clipId || clip.id);
39822
- const normalizedRootCause = rootCause.replace(/_/g, " ");
39823
- return normalizedRootCause === idleLabelFilter;
40084
+ const classification = getIdleTimeClassification(clip.clipId || clip.id);
40085
+ return classification?.label === idleLabelFilter;
39824
40086
  });
39825
40087
  }
39826
40088
  const displayCount = isTimeFilterActive || category.id === "idle_time" && idleLabelFilter ? filteredClips.length : categoryCount;
@@ -39850,8 +40112,9 @@ var FileManagerFilters = ({
39850
40112
  clipPosition: index + 1,
39851
40113
  // Store 1-based position
39852
40114
  cycleTimeSeconds: cycleTime,
39853
- duration: clip.duration
40115
+ duration: clip.duration,
39854
40116
  // Store duration for custom badge rendering
40117
+ cycleItemCount: clip.cycle_item_count ?? null
39855
40118
  };
39856
40119
  });
39857
40120
  regularCategoryNodes.push({
@@ -40107,14 +40370,14 @@ var FileManagerFilters = ({
40107
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") ? (
40108
40371
  // Show root cause icon for idle time clips
40109
40372
  (() => {
40110
- const rootCause = getIdleTimeRootCause(node.clipId || node.id);
40111
- if (rootCause === "processing") {
40373
+ const classification = getIdleTimeClassification(node.clipId || node.id);
40374
+ if (!classification || classification.status === "processing") {
40112
40375
  return /* @__PURE__ */ jsx(Clock, { className: "h-3.5 w-3.5 text-purple-500", strokeWidth: 2.5 });
40113
40376
  }
40114
40377
  if (!idleTimeVlmEnabled && node.categoryId === "idle_time") {
40115
40378
  return /* @__PURE__ */ jsx(Clock, { className: "h-3.5 w-3.5 text-purple-500", strokeWidth: 2.5 });
40116
40379
  }
40117
- const config = getRootCauseConfig(rootCause.replace(/_/g, " "));
40380
+ const config = getRootCauseConfig(classification);
40118
40381
  if (config) {
40119
40382
  const IconComponent = config.Icon;
40120
40383
  return /* @__PURE__ */ jsx(IconComponent, { className: `h-3.5 w-3.5 ${config.iconColor}`, strokeWidth: 2.5 });
@@ -40136,10 +40399,10 @@ var FileManagerFilters = ({
40136
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" });
40137
40400
  }
40138
40401
  const clipId = node.clipId || node.id;
40139
- const rootCause = getIdleTimeRootCause(clipId);
40140
- const isProcessing = rootCause === "processing";
40141
- const displayLabel = isProcessing ? "Analyzing..." : rootCause.replace(/_/g, " ");
40142
- 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...";
40143
40406
  const bgClass = config ? config.bgColor : "bg-slate-50";
40144
40407
  const textClass = config ? config.color : "text-slate-700";
40145
40408
  const borderClass = config ? config.borderColor : "border-slate-200";
@@ -40149,7 +40412,13 @@ var FileManagerFilters = ({
40149
40412
  // Show badge for other clips
40150
40413
  (() => {
40151
40414
  const badge = getClipBadge(node);
40152
- 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
+ ] });
40153
40422
  })()
40154
40423
  ) })
40155
40424
  ] }),
@@ -40237,7 +40506,7 @@ var FileManagerFilters = ({
40237
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: [
40238
40507
  /* @__PURE__ */ jsxs("span", { className: "font-medium", children: [
40239
40508
  "Reason: ",
40240
- idleLabelFilter.replace(/_/g, " ")
40509
+ selectedIdleReasonOption?.displayName || idleLabelFilter.replace(/_/g, " ")
40241
40510
  ] }),
40242
40511
  /* @__PURE__ */ jsx(
40243
40512
  "button",
@@ -40286,21 +40555,31 @@ var FileManagerFilters = ({
40286
40555
  /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin" }),
40287
40556
  "Loading idle reasons..."
40288
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) => {
40289
- 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
+ }
40290
40569
  return /* @__PURE__ */ jsxs(
40291
40570
  "button",
40292
40571
  {
40293
40572
  onClick: () => {
40294
- setIdleLabelFilter(reason);
40573
+ setIdleLabelFilter(reason.label);
40295
40574
  setShowIdleLabelFilterModal(false);
40296
40575
  },
40297
- 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"}`,
40298
40577
  children: [
40299
40578
  /* @__PURE__ */ jsx(config.Icon, { className: `h-3.5 w-3.5 ${config.iconColor}` }),
40300
- reason
40579
+ reason.displayName
40301
40580
  ]
40302
40581
  },
40303
- reason
40582
+ reason.label
40304
40583
  );
40305
40584
  }) })
40306
40585
  ]
@@ -40415,33 +40694,14 @@ var FileManagerFilters = ({
40415
40694
  slot.value
40416
40695
  )) })
40417
40696
  ] })
40418
- ] }) }),
40419
- /* @__PURE__ */ jsx("div", { className: "px-4 py-3 border-t border-slate-200 bg-white rounded-b-xl", children: /* @__PURE__ */ jsx(
40420
- "button",
40421
- {
40422
- onClick: () => {
40423
- if (startTime && endTime) {
40424
- setIsTimeFilterActive(true);
40425
- }
40426
- setShowTimeFilterModal(false);
40427
- setStartSearchTerm("");
40428
- setEndSearchTerm("");
40429
- },
40430
- disabled: !startTime || !endTime,
40431
- className: `
40432
- w-full px-4 py-2 text-sm font-semibold rounded-lg transition-all
40433
- ${startTime && endTime ? "bg-blue-600 text-white hover:bg-blue-700 active:scale-[0.98]" : "bg-slate-200 text-slate-400 cursor-not-allowed"}
40434
- `,
40435
- children: "Apply"
40436
- }
40437
- ) })
40697
+ ] }) })
40438
40698
  ]
40439
40699
  }
40440
40700
  )
40441
40701
  ] }),
40442
40702
  /* @__PURE__ */ jsxs("div", { className: "px-4 py-3 flex-1 min-h-0 overflow-y-auto scrollbar-thin", children: [
40443
40703
  /* @__PURE__ */ jsx("div", { className: "space-y-2", children: filterTree.map((node) => renderNode(node)) }),
40444
- 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: [
40445
40705
  /* @__PURE__ */ jsx("div", { className: "text-slate-300 mb-4", children: /* @__PURE__ */ jsx(Clock, { className: "h-12 w-12 mx-auto" }) }),
40446
40706
  /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold text-slate-700 mb-2", children: "No clips found" }),
40447
40707
  /* @__PURE__ */ jsx("p", { className: "text-sm text-slate-500 mb-4", children: "No clips match the selected time range" }),
@@ -40451,18 +40711,19 @@ var FileManagerFilters = ({
40451
40711
  onClick: () => {
40452
40712
  setStartTime("");
40453
40713
  setEndTime("");
40714
+ setIsTimeFilterActive(false);
40454
40715
  },
40455
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",
40456
40717
  children: "Clear time filter"
40457
40718
  }
40458
40719
  )
40459
40720
  ] }),
40460
- 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: [
40461
40722
  /* @__PURE__ */ jsx("div", { className: "text-slate-300 mb-4", children: /* @__PURE__ */ jsx(HelpCircle, { className: "h-12 w-12 mx-auto" }) }),
40462
40723
  /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold text-slate-700 mb-2", children: "No clip types available" }),
40463
40724
  /* @__PURE__ */ jsx("p", { className: "text-sm text-slate-500", children: "Loading clip categories..." })
40464
40725
  ] }),
40465
- 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: [
40466
40727
  /* @__PURE__ */ jsx("div", { className: "text-slate-300 mb-4", children: /* @__PURE__ */ jsx(Play, { className: "h-12 w-12 mx-auto" }) }),
40467
40728
  /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold text-slate-700 mb-2", children: "No clips available" }),
40468
40729
  /* @__PURE__ */ jsx("p", { className: "text-sm text-slate-500", children: "No clips found for the selected time period" })
@@ -40866,6 +41127,34 @@ function useClipsRealtimeUpdates({
40866
41127
  hasNewClips: newClipsNotification !== null && newClipsNotification.count > 0
40867
41128
  };
40868
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
+ };
40869
41158
  var BottlenecksContent = ({
40870
41159
  workspaceId,
40871
41160
  workspaceName,
@@ -41606,6 +41895,10 @@ var BottlenecksContent = ({
41606
41895
  classificationUpdates[clipId] = {
41607
41896
  status,
41608
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,
41609
41902
  confidence: clip.classification_confidence ?? void 0
41610
41903
  };
41611
41904
  });
@@ -42390,79 +42683,13 @@ var BottlenecksContent = ({
42390
42683
  return () => window.removeEventListener("keydown", handleEscape);
42391
42684
  }
42392
42685
  }, [isFullscreen, exitFullscreen]);
42393
- const ROOT_CAUSE_CONFIG = {
42394
- "Machine Breakdown": {
42395
- color: "text-white",
42396
- bgColor: "bg-black/60 backdrop-blur-sm",
42397
- borderColor: "border-transparent",
42398
- Icon: AlertTriangle,
42399
- iconColor: "text-red-500",
42400
- // Standard red for high visibility on dark
42401
- dotColor: "bg-red-600"
42402
- },
42403
- "Other": {
42404
- color: "text-white",
42405
- bgColor: "bg-black/60 backdrop-blur-sm",
42406
- borderColor: "border-transparent",
42407
- Icon: HelpCircle,
42408
- iconColor: "text-gray-400",
42409
- dotColor: "bg-gray-500"
42410
- },
42411
- "Power Outage": {
42412
- color: "text-white",
42413
- bgColor: "bg-black/60 backdrop-blur-sm",
42414
- borderColor: "border-transparent",
42415
- Icon: Zap,
42416
- iconColor: "text-red-400",
42417
- // Lighter red
42418
- dotColor: "bg-red-500"
42419
- },
42420
- "Worker Absent": {
42421
- color: "text-white",
42422
- bgColor: "bg-black/60 backdrop-blur-sm",
42423
- borderColor: "border-transparent",
42424
- Icon: UserX,
42425
- iconColor: "text-red-400",
42426
- // Lighter red
42427
- dotColor: "bg-red-500"
42428
- },
42429
- "Material Shortage": {
42430
- color: "text-white",
42431
- bgColor: "bg-black/60 backdrop-blur-sm",
42432
- borderColor: "border-transparent",
42433
- Icon: Package,
42434
- iconColor: "text-red-300",
42435
- // Even lighter red
42436
- dotColor: "bg-red-400"
42437
- },
42438
- "Quality Issue": {
42439
- color: "text-white",
42440
- bgColor: "bg-black/60 backdrop-blur-sm",
42441
- borderColor: "border-transparent",
42442
- Icon: XCircle,
42443
- iconColor: "text-red-300",
42444
- // Even lighter red
42445
- dotColor: "bg-red-400"
42446
- },
42447
- "Scheduled Maintenance": {
42448
- color: "text-white",
42449
- bgColor: "bg-black/60 backdrop-blur-sm",
42450
- borderColor: "border-transparent",
42451
- Icon: Wrench,
42452
- iconColor: "text-red-200",
42453
- // Very light red
42454
- dotColor: "bg-red-300"
42455
- }
42456
- };
42457
- const getIdleTimeRootCause = useCallback((video) => {
42686
+ const getIdleTimeClassification = useCallback((video) => {
42458
42687
  if (video.type !== "idle_time") return null;
42459
42688
  const videoId = video.id || video.clipId;
42460
- if (!videoId) return "processing";
42689
+ if (!videoId) return null;
42461
42690
  const classification = clipClassifications[videoId];
42462
- console.log(`[getIdleTimeRootCause] Looking up ${videoId}: `, classification);
42463
- if (!classification) return "processing";
42464
- if (classification.status === "processing") return "processing";
42465
- return classification.label || "processing";
42691
+ console.log(`[getIdleTimeClassification] Looking up ${videoId}: `, classification);
42692
+ return classification || null;
42466
42693
  }, [clipClassifications]);
42467
42694
  const getIdleTimeConfidence = useCallback((video) => {
42468
42695
  if (video.type !== "idle_time") return null;
@@ -42473,36 +42700,35 @@ var BottlenecksContent = ({
42473
42700
  if (classification.status === "processing") return null;
42474
42701
  return classification.confidence ?? null;
42475
42702
  }, [clipClassifications]);
42476
- const formatDisplayLabel = useCallback((label) => {
42477
- return label.replace(/_/g, " ");
42478
- }, []);
42479
- const getRootCauseConfig = useCallback((rootCause) => {
42480
- if (!rootCause) return null;
42481
- if (rootCause === "processing") {
42703
+ const getRootCauseConfig = useCallback((classification) => {
42704
+ if (!classification || classification.status === "processing") {
42482
42705
  return {
42483
42706
  color: "text-white",
42484
42707
  bgColor: "bg-black/60 backdrop-blur-sm",
42485
- borderColor: "border-gray-500/30",
42708
+ borderColor: "border-white/10",
42486
42709
  Icon: Clock,
42487
- iconColor: "text-purple-500",
42488
- dotColor: "bg-gray-400",
42710
+ iconColor: "text-purple-300",
42711
+ dotColor: "bg-purple-400",
42489
42712
  displayName: "Analyzing..."
42490
42713
  };
42491
42714
  }
42492
- const hardcodedConfig = ROOT_CAUSE_CONFIG[rootCause];
42493
- if (hardcodedConfig) {
42494
- return hardcodedConfig;
42495
- }
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
+ });
42496
42722
  return {
42497
42723
  color: "text-white",
42498
42724
  bgColor: "bg-black/60 backdrop-blur-sm",
42499
- borderColor: "border-purple-500/30",
42500
- Icon: Tag,
42501
- iconColor: "text-purple-400",
42502
- dotColor: "bg-purple-400",
42503
- 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
42504
42730
  };
42505
- }, [formatDisplayLabel]);
42731
+ }, []);
42506
42732
  const getClipTypeLabel = useCallback((video) => {
42507
42733
  if (!video) return "";
42508
42734
  const currentFilter = activeFilterRef.current;
@@ -42667,15 +42893,15 @@ var BottlenecksContent = ({
42667
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" ? (
42668
42894
  // Show full colored badge for idle time
42669
42895
  (() => {
42670
- const rootCause = getIdleTimeRootCause(currentVideo);
42896
+ const classification = getIdleTimeClassification(currentVideo);
42671
42897
  const confidence = getIdleTimeConfidence(currentVideo);
42672
- const config = getRootCauseConfig(rootCause);
42898
+ const config = getRootCauseConfig(classification);
42673
42899
  if (!config) return null;
42674
42900
  const IconComponent = config.Icon;
42675
42901
  return /* @__PURE__ */ jsxs(Fragment, { children: [
42676
- 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: [
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: 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..." })
42679
42905
  ] }) }),
42680
42906
  idleTimeVlmEnabled && confidence !== null && (() => {
42681
42907
  const confidencePercent = confidence * 100;
@@ -42710,9 +42936,9 @@ var BottlenecksContent = ({
42710
42936
  currentVideo.type === "idle_time" ? (
42711
42937
  // Show full colored badge for idle time
42712
42938
  (() => {
42713
- const rootCause = getIdleTimeRootCause(currentVideo);
42939
+ const classification = getIdleTimeClassification(currentVideo);
42714
42940
  const confidence = getIdleTimeConfidence(currentVideo);
42715
- const config = getRootCauseConfig(rootCause);
42941
+ const config = getRootCauseConfig(classification);
42716
42942
  if (!config) return null;
42717
42943
  const IconComponent = config.Icon;
42718
42944
  return /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -42721,9 +42947,9 @@ var BottlenecksContent = ({
42721
42947
  (confidence * 100).toFixed(0),
42722
42948
  "%"
42723
42949
  ] }) }) }),
42724
- 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: [
42725
- /* @__PURE__ */ jsx(IconComponent, { className: `h-3.5 w-3.5 ${config.iconColor}`, strokeWidth: 2.5 }),
42726
- /* @__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..." })
42727
42953
  ] }) })
42728
42954
  ] });
42729
42955
  })()
@@ -42763,6 +42989,7 @@ var BottlenecksContent = ({
42763
42989
  /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500", children: "No clips found" })
42764
42990
  ] }) : /* @__PURE__ */ jsx("div", { className: "space-y-2", children: triageClips.map((clip, index) => {
42765
42991
  const isIdleTime = clip.categoryId === "idle_time";
42992
+ const cycleItemCount = getMultiCycleItemCount(clip);
42766
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", {
42767
42994
  hour12: true,
42768
42995
  hour: "numeric",
@@ -42815,15 +43042,15 @@ var BottlenecksContent = ({
42815
43042
  // Idle time clips - show root cause label below time
42816
43043
  (() => {
42817
43044
  const clipId = clip.id || clip.clipId;
42818
- const rootCause = getIdleTimeRootCause({
43045
+ const classification = getIdleTimeClassification({
42819
43046
  id: clipId,
42820
43047
  type: "idle_time",
42821
43048
  creation_timestamp: clip.clip_timestamp
42822
43049
  });
42823
- console.log(`[BottlenecksContent] Sidebar clip ${clipId}: rootCause=${rootCause}, classification=`, clipClassifications[clipId]);
42824
- const config = getRootCauseConfig(rootCause);
43050
+ console.log(`[BottlenecksContent] Sidebar clip ${clipId}: classification=`, clipClassifications[clipId]);
43051
+ const config = getRootCauseConfig(classification);
42825
43052
  if (!config) {
42826
- console.log(`[BottlenecksContent] No config found for rootCause: ${rootCause}`);
43053
+ console.log(`[BottlenecksContent] No config found for classification on clip: ${clipId}`);
42827
43054
  return null;
42828
43055
  }
42829
43056
  const IconComponent = config.Icon;
@@ -42838,7 +43065,7 @@ var BottlenecksContent = ({
42838
43065
  ] }) })
42839
43066
  ] }),
42840
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: (() => {
42841
- const displayText = config.displayName || (rootCause ? formatDisplayLabel(rootCause) : "Analyzing...");
43068
+ const displayText = config.displayName || "Analyzing...";
42842
43069
  console.log(`[BottlenecksContent] Displaying label: "${displayText}" for clip ${clipId}`);
42843
43070
  return displayText;
42844
43071
  })() }) : (() => {
@@ -42858,7 +43085,13 @@ var BottlenecksContent = ({
42858
43085
  clip.duration ? `${clip.duration.toFixed(1)}s` : "N/A",
42859
43086
  ")"
42860
43087
  ] }) }),
42861
- /* @__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
+ ] })
42862
43095
  ] })
42863
43096
  )
42864
43097
  },
@@ -42951,15 +43184,15 @@ var BottlenecksContent = ({
42951
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" ? (
42952
43185
  // Show full colored badge for idle time
42953
43186
  (() => {
42954
- const rootCause = getIdleTimeRootCause(currentVideo);
43187
+ const classification = getIdleTimeClassification(currentVideo);
42955
43188
  const confidence = getIdleTimeConfidence(currentVideo);
42956
- const config = getRootCauseConfig(rootCause);
43189
+ const config = getRootCauseConfig(classification);
42957
43190
  if (!config) return null;
42958
43191
  const IconComponent = config.Icon;
42959
43192
  return /* @__PURE__ */ jsxs(Fragment, { children: [
42960
- 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: [
42961
- /* @__PURE__ */ jsx(IconComponent, { className: `h-4 w-4 ${config.iconColor}`, strokeWidth: 2.5 }),
42962
- /* @__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..." })
42963
43196
  ] }) }),
42964
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: [
42965
43198
  "AI Confidence: ",
@@ -42981,9 +43214,9 @@ var BottlenecksContent = ({
42981
43214
  ] }) }) : currentVideo.type === "idle_time" ? (
42982
43215
  // Show full colored badge for idle time
42983
43216
  (() => {
42984
- const rootCause = getIdleTimeRootCause(currentVideo);
43217
+ const classification = getIdleTimeClassification(currentVideo);
42985
43218
  const confidence = getIdleTimeConfidence(currentVideo);
42986
- const config = getRootCauseConfig(rootCause);
43219
+ const config = getRootCauseConfig(classification);
42987
43220
  if (!config) return null;
42988
43221
  const IconComponent = config.Icon;
42989
43222
  return /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -42992,9 +43225,9 @@ var BottlenecksContent = ({
42992
43225
  (confidence * 100).toFixed(0),
42993
43226
  "%"
42994
43227
  ] }) }) }),
42995
- 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: [
42996
- /* @__PURE__ */ jsx(IconComponent, { className: `h-4 w-4 ${config.iconColor}`, strokeWidth: 2.5 }),
42997
- /* @__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..." })
42998
43231
  ] }) })
42999
43232
  ] });
43000
43233
  })()
@@ -44943,16 +45176,6 @@ var LineHistoryCalendar = ({
44943
45176
  ] });
44944
45177
  };
44945
45178
  var LineHistoryCalendar_default = LineHistoryCalendar;
44946
- var STATIC_COLORS = {
44947
- "Operator Absent": "#dc2626",
44948
- // red-600 - Critical/Urgent
44949
- "No Material": "#f59e0b",
44950
- // amber-500 - Warning/Supply Chain
44951
- "Machine Downtime": "#3b82f6",
44952
- // blue-500 - Scheduled/Technical
44953
- "Operator Idle": "#8b5cf6"
44954
- // violet-500 - Low Priority/Behavioral
44955
- };
44956
45179
  var PRODUCTIVE_COLOR = "#00AB45";
44957
45180
  var IDLE_COLOR = "#e5e7eb";
44958
45181
  var formatDuration = (seconds) => {
@@ -44975,19 +45198,21 @@ var formatDuration = (seconds) => {
44975
45198
  }
44976
45199
  return parts.join(" ");
44977
45200
  };
44978
- var getColorForEntry = (name, index) => {
44979
- const normalized = name.trim().toLowerCase();
45201
+ var getColorForEntry = (entry) => {
45202
+ const normalized = entry.name.trim().toLowerCase();
44980
45203
  if (normalized === "productive" || normalized === "productive time") {
44981
45204
  return PRODUCTIVE_COLOR;
44982
45205
  }
44983
45206
  if (normalized === "idle" || normalized === "idle time") {
44984
45207
  return IDLE_COLOR;
44985
45208
  }
44986
- if (STATIC_COLORS[name]) {
44987
- return STATIC_COLORS[name];
44988
- }
44989
- const snakeCaseName = name.replace(/ /g, "_");
44990
- 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
+ });
44991
45216
  };
44992
45217
  var CustomTooltip = ({ active, payload, hideTotalDuration }) => {
44993
45218
  if (active && payload && payload.length) {
@@ -45001,8 +45226,8 @@ var CustomTooltip = ({ active, payload, hideTotalDuration }) => {
45001
45226
  const hasContributors = contributors.length > 0;
45002
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: [
45003
45228
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 pb-2 mb-2 border-b border-slate-100", children: [
45004
- /* @__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) } }),
45005
- /* @__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, " ") })
45006
45231
  ] }),
45007
45232
  /* @__PURE__ */ jsxs("div", { className: "space-y-1.5 pb-1", children: [
45008
45233
  /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center gap-4", children: [
@@ -45063,7 +45288,8 @@ var IdleTimeReasonChartComponent = ({
45063
45288
  isLoading = false,
45064
45289
  error = null,
45065
45290
  hideTotalDuration = false,
45066
- updateAnimation = "replay"
45291
+ updateAnimation = "replay",
45292
+ variant = "pie"
45067
45293
  }) => {
45068
45294
  const [activeData, setActiveData] = React141__default.useState([]);
45069
45295
  React141__default.useEffect(() => {
@@ -45108,6 +45334,73 @@ var IdleTimeReasonChartComponent = ({
45108
45334
  if (!data || data.length === 0) {
45109
45335
  return /* @__PURE__ */ jsx(EmptyState, { message: "No Idle Time reasons available" });
45110
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
+ }
45111
45404
  return /* @__PURE__ */ jsxs(Fragment, { children: [
45112
45405
  /* @__PURE__ */ jsx("style", { children: `
45113
45406
  .recharts-wrapper:focus,
@@ -45169,7 +45462,7 @@ var IdleTimeReasonChartComponent = ({
45169
45462
  children: activeData.map((entry, index) => /* @__PURE__ */ jsx(
45170
45463
  Cell,
45171
45464
  {
45172
- fill: getColorForEntry(entry.name, index),
45465
+ fill: getColorForEntry(entry),
45173
45466
  strokeWidth: 0
45174
45467
  },
45175
45468
  `cell-${index}`
@@ -45186,10 +45479,10 @@ var IdleTimeReasonChartComponent = ({
45186
45479
  "span",
45187
45480
  {
45188
45481
  className: "inline-block w-2.5 h-2.5 rounded-full mr-1.5 mt-0.5 flex-shrink-0",
45189
- style: { backgroundColor: getColorForEntry(entry.name, index) }
45482
+ style: { backgroundColor: getColorForEntry(entry) }
45190
45483
  }
45191
45484
  ),
45192
- /* @__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, " ") })
45193
45486
  ] }, `item-${index}`)) }) })
45194
45487
  ]
45195
45488
  }
@@ -45314,7 +45607,6 @@ var LineMonthlyHistory = ({
45314
45607
  const { isIdleTimeVlmEnabled } = useIdleTimeVlmConfig();
45315
45608
  const idleTimeVlmEnabled = isIdleTimeVlmEnabled(lineId);
45316
45609
  const isUptimeMode = monitoringMode === "uptime";
45317
- const effectiveLegend = legend || DEFAULT_EFFICIENCY_LEGEND;
45318
45610
  const chartKey = useMemo(() => `${lineId}-${month}-${year}-${selectedShiftId}-${rangeStart}-${rangeEnd}`, [lineId, month, year, selectedShiftId, rangeStart, rangeEnd]);
45319
45611
  const monthBounds = useMemo(() => getMonthKeyBounds(year, month), [year, month]);
45320
45612
  const normalizedRange = useMemo(() => {
@@ -45362,20 +45654,20 @@ var LineMonthlyHistory = ({
45362
45654
  { efficiency: 0, underperforming: 0, totalWorkspaces: 0, count: 0 }
45363
45655
  );
45364
45656
  const avgEfficiency = averages.count > 0 ? averages.efficiency / averages.count : 0;
45365
- const { underperformingDays, totalDays } = (analysisMonthlyData || []).reduce(
45657
+ const outputAverages = (analysisMonthlyData || []).reduce(
45366
45658
  (acc, day) => {
45367
45659
  const shiftData = getShiftData2(day, selectedShiftId);
45368
45660
  if (!shiftData || !hasRealData(shiftData)) {
45369
45661
  return acc;
45370
45662
  }
45371
- const status = getEfficiencyColor(shiftData.avg_efficiency || 0, effectiveLegend);
45372
45663
  return {
45373
- totalDays: acc.totalDays + 1,
45374
- underperformingDays: acc.underperformingDays + (status === "red" ? 1 : 0)
45664
+ output: acc.output + (shiftData.output || 0),
45665
+ count: acc.count + 1
45375
45666
  };
45376
45667
  },
45377
- { underperformingDays: 0, totalDays: 0 }
45668
+ { output: 0, count: 0 }
45378
45669
  );
45670
+ const avgOutput = outputAverages.count > 0 ? outputAverages.output / outputAverages.count : 0;
45379
45671
  const uptimeSummary = useMemo(() => {
45380
45672
  if (!isUptimeMode) return null;
45381
45673
  const validDays = (analysisMonthlyData || []).map((day) => getShiftData2(day, selectedShiftId)).filter((shiftData) => shiftData && hasRealData(shiftData)).map((shiftData) => ({ shiftData, totals: getUptimeTotals(shiftData) }));
@@ -45408,6 +45700,10 @@ var LineMonthlyHistory = ({
45408
45700
  const efficiencyImproved = efficiencyDelta >= 0;
45409
45701
  const EfficiencyTrendIcon = efficiencyImproved ? ArrowUp : ArrowDown;
45410
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)}%`;
45411
45707
  const utilizationDelta = efficiencyDelta;
45412
45708
  const utilizationImproved = utilizationDelta >= 0;
45413
45709
  const UtilizationTrendIcon = utilizationImproved ? ArrowUp : ArrowDown;
@@ -45692,12 +45988,17 @@ var LineMonthlyHistory = ({
45692
45988
  ] })
45693
45989
  ] }),
45694
45990
  /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-lg shadow-sm border border-gray-100 p-4 flex flex-col justify-between", children: [
45695
- /* @__PURE__ */ jsx("h3", { className: "text-sm font-bold text-gray-700 mb-2", children: "No. of underperforming days" }),
45696
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2 flex-nowrap", children: /* @__PURE__ */ jsxs("div", { className: "text-xl font-bold text-gray-900", children: [
45697
- underperformingDays,
45698
- "/",
45699
- totalDays
45700
- ] }) })
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
+ ] })
45701
46002
  ] })
45702
46003
  ] }),
45703
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: [
@@ -46216,11 +46517,6 @@ var LineMonthlyPdfGenerator = ({
46216
46517
  doc.text("Working Days:", 25, kpiStartY + kpiSpacing * 2);
46217
46518
  doc.setFont("helvetica", "bold");
46218
46519
  doc.text(`${outputMetrics.totalDays} days`, 120, kpiStartY + kpiSpacing * 2);
46219
- createKPIBox(kpiStartY + kpiSpacing * 3);
46220
- doc.setFont("helvetica", "normal");
46221
- doc.text("Underperforming Days:", 25, kpiStartY + kpiSpacing * 3);
46222
- doc.setFont("helvetica", "bold");
46223
- doc.text(`${outputMetrics.underperformingDays} of ${outputMetrics.totalDays}`, 120, kpiStartY + kpiSpacing * 3);
46224
46520
  }
46225
46521
  } else {
46226
46522
  doc.setFontSize(12);
@@ -47798,7 +48094,8 @@ var WorkspaceMonthlyHistory = ({
47798
48094
  availableShifts,
47799
48095
  monthlyDataLoading = false,
47800
48096
  className = "",
47801
- trendSummary
48097
+ trendSummary,
48098
+ isAssemblyWorkspace = false
47802
48099
  }) => {
47803
48100
  const effectiveLegend = legend || DEFAULT_EFFICIENCY_LEGEND;
47804
48101
  const isUptimeMode = monitoringMode === "uptime";
@@ -48037,12 +48334,8 @@ var WorkspaceMonthlyHistory = ({
48037
48334
  }, [analysisMonthlyData, selectedShiftId, isUptimeMode, shiftWorkSeconds]);
48038
48335
  const efficiencyDelta = trendSummary?.avg_efficiency?.delta_pp ?? 0;
48039
48336
  const efficiencyImproved = efficiencyDelta >= 0;
48040
- const outputDeltaRaw = trendSummary?.avg_daily_output?.delta_pp ?? 0;
48041
48337
  const cycleDeltaRaw = trendSummary?.avg_cycle_time?.delta_seconds ?? 0;
48042
- const outputPrev = trendSummary?.avg_daily_output?.previous ?? 0;
48043
48338
  const cyclePrev = trendSummary?.avg_cycle_time?.previous ?? 0;
48044
- const outputDelta = outputPrev ? outputDeltaRaw / outputPrev * 100 : 0;
48045
- const outputImproved = outputDelta >= 0;
48046
48339
  const cycleDelta = cyclePrev ? cycleDeltaRaw / cyclePrev * 100 : 0;
48047
48340
  const cycleWorsened = cycleDelta > 0;
48048
48341
  const utilizationDelta = efficiencyDelta;
@@ -48122,7 +48415,7 @@ var WorkspaceMonthlyHistory = ({
48122
48415
  shift.id
48123
48416
  )) }) }),
48124
48417
  /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-2 gap-6", children: [
48125
- /* @__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: [
48126
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)) }),
48127
48420
  /* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 gap-2 mt-6", children: calendarData.calendar.map((day, index) => {
48128
48421
  const dayNumber = index >= calendarData.startOffset ? index - calendarData.startOffset + 1 : null;
@@ -48210,8 +48503,32 @@ var WorkspaceMonthlyHistory = ({
48210
48503
  ) }, index);
48211
48504
  }) })
48212
48505
  ] }),
48213
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
48214
- /* @__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: [
48215
48532
  /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-lg shadow-sm border border-gray-100 p-4 flex flex-col justify-between", children: [
48216
48533
  /* @__PURE__ */ jsx("div", { className: "text-sm font-semibold text-gray-600 mb-1", children: isUptimeMode ? "Avg Utilization" : "Avg Efficiency" }),
48217
48534
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 flex-nowrap", children: [
@@ -48225,16 +48542,13 @@ var WorkspaceMonthlyHistory = ({
48225
48542
  ] })
48226
48543
  ] })
48227
48544
  ] }),
48228
- /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-lg shadow-sm border border-gray-100 p-4 flex flex-col justify-between", children: [
48229
- /* @__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" }),
48230
48547
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 flex-nowrap", children: [
48231
- /* @__PURE__ */ jsx("div", { className: "text-2xl font-bold text-gray-900", children: isUptimeMode ? formatIdleTime(metrics2?.avgIdleTime ?? 0) : metrics2?.avgDailyOutput?.toLocaleString?.() ?? 0 }),
48232
- 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: [
48233
48550
  idleImproved ? /* @__PURE__ */ jsx(ArrowDown, { className: "w-3 h-3" }) : /* @__PURE__ */ jsx(ArrowUp, { className: "w-3 h-3" }),
48234
48551
  /* @__PURE__ */ jsx("span", { children: idleTrendText })
48235
- ] }) : /* @__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: [
48236
- outputImproved ? /* @__PURE__ */ jsx(ArrowUp, { className: "w-3 h-3" }) : /* @__PURE__ */ jsx(ArrowDown, { className: "w-3 h-3" }),
48237
- /* @__PURE__ */ jsx("span", { children: `${Math.abs(outputDelta).toFixed(1)}% vs last month` })
48238
48552
  ] })
48239
48553
  ] })
48240
48554
  ] }),
@@ -48256,9 +48570,9 @@ var WorkspaceMonthlyHistory = ({
48256
48570
  ] })
48257
48571
  ] }),
48258
48572
  /* @__PURE__ */ jsxs("div", { className: `grid grid-cols-1 ${idleTimeVlmEnabled ? "sm:grid-cols-2" : "sm:grid-cols-1"} gap-4`, children: [
48259
- /* @__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: [
48260
48574
  /* @__PURE__ */ jsx("h3", { className: "text-lg font-bold text-gray-700 mb-3 text-left", children: isUptimeMode ? "Utilization" : "Time Utilization" }),
48261
- 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: [
48262
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: [
48263
48577
  /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsx(PieChart, { children: /* @__PURE__ */ jsx(
48264
48578
  Pie,
@@ -48331,7 +48645,7 @@ var WorkspaceMonthlyHistory = ({
48331
48645
  ] }) })
48332
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" }) })
48333
48647
  ] }),
48334
- 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: [
48335
48649
  /* @__PURE__ */ jsx("h3", { className: "text-lg font-bold text-gray-700 mb-3 text-left", children: "Idle Time Breakdown" }),
48336
48650
  /* @__PURE__ */ jsx("div", { className: "h-[160px]", children: /* @__PURE__ */ jsx(
48337
48651
  IdleTimeReasonChart,
@@ -48343,7 +48657,7 @@ var WorkspaceMonthlyHistory = ({
48343
48657
  ) })
48344
48658
  ] })
48345
48659
  ] }),
48346
- /* @__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: [
48347
48661
  /* @__PURE__ */ jsx("h3", { className: "text-lg font-bold text-gray-700 mb-3 text-left", children: isUptimeMode ? "Daily Utilization" : "Daily Output" }),
48348
48662
  /* @__PURE__ */ jsx("div", { style: { height: "220px" }, children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
48349
48663
  BarChart$1,
@@ -48541,7 +48855,7 @@ var WorkspaceWhatsAppShareButton = ({
48541
48855
  }
48542
48856
  );
48543
48857
  };
48544
- var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiencyLegend }) => {
48858
+ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiencyLegend, hourlyCycleTimes }) => {
48545
48859
  const [isGenerating, setIsGenerating] = useState(false);
48546
48860
  const entityConfig = useEntityConfig();
48547
48861
  const effectiveLegend = efficiencyLegend || DEFAULT_EFFICIENCY_LEGEND;
@@ -48549,6 +48863,7 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
48549
48863
  setIsGenerating(true);
48550
48864
  try {
48551
48865
  const isUptimeMode = workspace.monitoring_mode === "uptime";
48866
+ const isAssemblyCycleMode = !isUptimeMode && workspace.line_assembly_enabled === true && workspace.action_type === "assembly";
48552
48867
  const shiftMinutes = getShiftDurationMinutes(workspace.shift_start, workspace.shift_end);
48553
48868
  const shiftSeconds = shiftMinutes ? shiftMinutes * 60 : 0;
48554
48869
  const idleSeconds = Math.max(workspace.idle_time || 0, 0);
@@ -48609,9 +48924,38 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
48609
48924
  minute: "2-digit",
48610
48925
  hour12: true
48611
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;
48612
48956
  doc.setFontSize(12);
48613
48957
  doc.setTextColor(80, 80, 80);
48614
- doc.text(`Report Period: ${shiftStartTime} - ${currentTime}`, 20, 79);
48958
+ doc.text(`Report Period: ${shiftStartTime} - ${reportPeriodEndTime}`, 20, 79);
48615
48959
  doc.setTextColor(0, 0, 0);
48616
48960
  doc.setDrawColor(180, 180, 180);
48617
48961
  doc.setLineWidth(0.8);
@@ -48625,10 +48969,8 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
48625
48969
  };
48626
48970
  const perfOverviewStartY = 93;
48627
48971
  const hasIdleTimeReason = idleTimeReasons && idleTimeReasons.length > 0;
48628
- let perfOverviewHeight = hasIdleTimeReason ? 80 : 70;
48629
- if (isUptimeMode) {
48630
- perfOverviewHeight = hasIdleTimeReason ? 70 : 60;
48631
- }
48972
+ const perfOverviewRows = isUptimeMode ? 3 : isAssemblyCycleMode ? 2 : 4;
48973
+ const perfOverviewHeight = 30 + perfOverviewRows * 10 + (hasIdleTimeReason ? 10 : 0);
48632
48974
  doc.setFillColor(245, 245, 245);
48633
48975
  doc.roundedRect(15, perfOverviewStartY, 180, perfOverviewHeight, 3, 3, "F");
48634
48976
  doc.setFontSize(18);
@@ -48656,6 +48998,19 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
48656
48998
  doc.text("Stoppages:", 25, kpiStartY + kpiSpacing * 2);
48657
48999
  doc.setFont("helvetica", "bold");
48658
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);
48659
49014
  } else {
48660
49015
  createKPIBox(kpiStartY);
48661
49016
  doc.setFontSize(11);
@@ -48692,17 +49047,11 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
48692
49047
  const reasonText = `${reasonName} (${topReason.value.toFixed(1)}%)`;
48693
49048
  doc.text(reasonText, 120, reasonY);
48694
49049
  }
48695
- let separatorBeforeHourlyY = hasIdleTimeReason ? 183 : 173;
48696
- if (isUptimeMode) {
48697
- separatorBeforeHourlyY -= 10;
48698
- }
49050
+ const separatorBeforeHourlyY = perfOverviewStartY + perfOverviewHeight + 10;
48699
49051
  doc.setDrawColor(180, 180, 180);
48700
49052
  doc.setLineWidth(0.8);
48701
49053
  doc.line(20, separatorBeforeHourlyY, 190, separatorBeforeHourlyY);
48702
- let hourlyPerfStartY = hasIdleTimeReason ? 188 : 178;
48703
- if (isUptimeMode) {
48704
- hourlyPerfStartY -= 10;
48705
- }
49054
+ const hourlyPerfStartY = separatorBeforeHourlyY + 5;
48706
49055
  const uptimeSeries = isUptimeMode ? buildUptimeSeries({
48707
49056
  idleTimeHourly: workspace.idle_time_hourly,
48708
49057
  shiftStart: workspace.shift_start,
@@ -48720,8 +49069,9 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
48720
49069
  const uptimePercent = total > 0 ? Math.round(activeMinutes / total * 100) : 0;
48721
49070
  return { activeMinutes, idleMinutes, uptimePercent };
48722
49071
  }) : [];
48723
- 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 || [];
48724
49073
  const hourlyTarget = workspace.pph_threshold;
49074
+ const cycleTarget = workspace.ideal_cycle_time || 0;
48725
49075
  const pageHeight = doc.internal.pageSize.height;
48726
49076
  const maxContentY = pageHeight - 15;
48727
49077
  const baseTableStartY = hourlyPerfStartY + 31;
@@ -48746,12 +49096,16 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
48746
49096
  doc.setFont("helvetica", "bold");
48747
49097
  doc.setTextColor(40, 40, 40);
48748
49098
  const hourlyTitleY = hourlyPerfStartY + 10;
48749
- 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
+ );
48750
49104
  doc.setTextColor(0, 0, 0);
48751
49105
  const headerY = titleFontSize === 16 ? hourlyPerfStartY + 18 : hourlyPerfStartY + 20;
48752
49106
  const gridTopY = headerY - 5;
48753
49107
  const headerBottomY = gridTopY + 8;
48754
- 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];
48755
49109
  const totalRows = hourlyData.length;
48756
49110
  const gridBottomY = headerBottomY + totalRows * rowHeight;
48757
49111
  const tableHeight = gridBottomY - gridTopY;
@@ -48772,6 +49126,10 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
48772
49126
  doc.text("Time Range", 25, headerTextY);
48773
49127
  if (isUptimeMode) {
48774
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);
48775
49133
  } else {
48776
49134
  doc.text("Output", 75, headerTextY);
48777
49135
  doc.text("Target", 105, headerTextY);
@@ -48820,6 +49178,25 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
48820
49178
  if (isUptimeMode) {
48821
49179
  const utilizationStr = dataCollected ? `${uptimePercent}%` : "TBD";
48822
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);
48823
49200
  } else {
48824
49201
  doc.text(outputStr, 75, yPos);
48825
49202
  doc.text(targetStr, 105, yPos);
@@ -48891,7 +49268,8 @@ var WorkspaceMonthlyPdfGenerator = ({
48891
49268
  shiftConfig,
48892
49269
  efficiencyLegend,
48893
49270
  className,
48894
- compact = false
49271
+ compact = false,
49272
+ isAssemblyWorkspace = false
48895
49273
  }) => {
48896
49274
  const [isGenerating, setIsGenerating] = useState(false);
48897
49275
  const effectiveLegend = efficiencyLegend || DEFAULT_EFFICIENCY_LEGEND;
@@ -49014,6 +49392,7 @@ var WorkspaceMonthlyPdfGenerator = ({
49014
49392
  avgOutput: filteredShifts.reduce((sum, shift) => sum + shift.output, 0) / filteredShifts.length,
49015
49393
  avgCycleTime: filteredShifts.reduce((sum, shift) => sum + shift.cycleTime, 0) / filteredShifts.length,
49016
49394
  avgPph: filteredShifts.reduce((sum, shift) => sum + shift.pph, 0) / filteredShifts.length,
49395
+ avgIdleTime: filteredShifts.reduce((sum, shift) => sum + shift.idleTime, 0) / filteredShifts.length,
49017
49396
  totalDays: filteredShifts.length,
49018
49397
  underperformingDays: filteredShifts.filter((shift) => shift.efficiency < effectiveLegend.green_min).length
49019
49398
  } : null;
@@ -49025,7 +49404,8 @@ var WorkspaceMonthlyPdfGenerator = ({
49025
49404
  doc.roundedRect(22, y - 7, 165, 12, 2, 2, "S");
49026
49405
  };
49027
49406
  doc.setFillColor(245, 245, 245);
49028
- 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");
49029
49409
  doc.setFontSize(18);
49030
49410
  doc.setFont("helvetica", "bold");
49031
49411
  doc.setTextColor(40, 40, 40);
@@ -49064,32 +49444,41 @@ var WorkspaceMonthlyPdfGenerator = ({
49064
49444
  doc.text(`${uptimeMetrics.underperformingDays} of ${uptimeMetrics.totalDays}`, 120, kpiStartY + kpiSpacing * 4);
49065
49445
  } else {
49066
49446
  const outputMetrics = monthlyMetrics;
49067
- createKPIBox(kpiStartY);
49068
- doc.setFontSize(11);
49069
- doc.setFont("helvetica", "normal");
49070
- doc.text("Average Efficiency:", 25, kpiStartY);
49071
- doc.setFont("helvetica", "bold");
49072
- doc.text(`${outputMetrics.avgEfficiency.toFixed(1)}% (Target: ${Math.round(effectiveLegend.green_min)}%)`, 120, kpiStartY);
49073
- createKPIBox(kpiStartY + kpiSpacing);
49074
- doc.setFont("helvetica", "normal");
49075
- doc.text("Average Output:", 25, kpiStartY + kpiSpacing);
49076
- doc.setFont("helvetica", "bold");
49077
- doc.text(`${Math.round(outputMetrics.avgOutput)} pieces`, 120, kpiStartY + kpiSpacing);
49078
- createKPIBox(kpiStartY + kpiSpacing * 2);
49079
- doc.setFont("helvetica", "normal");
49080
- doc.text("Average PPH:", 25, kpiStartY + kpiSpacing * 2);
49081
- doc.setFont("helvetica", "bold");
49082
- doc.text(`${outputMetrics.avgPph.toFixed(1)} per hour`, 120, kpiStartY + kpiSpacing * 2);
49083
- createKPIBox(kpiStartY + kpiSpacing * 3);
49084
- doc.setFont("helvetica", "normal");
49085
- doc.text("Working Days:", 25, kpiStartY + kpiSpacing * 3);
49086
- doc.setFont("helvetica", "bold");
49087
- doc.text(`${outputMetrics.totalDays} days`, 120, kpiStartY + kpiSpacing * 3);
49088
- createKPIBox(kpiStartY + kpiSpacing * 4);
49089
- doc.setFont("helvetica", "normal");
49090
- doc.text("Underperforming Days:", 25, kpiStartY + kpiSpacing * 4);
49091
- doc.setFont("helvetica", "bold");
49092
- 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
+ }
49093
49482
  }
49094
49483
  } else {
49095
49484
  doc.setFontSize(12);
@@ -49100,29 +49489,33 @@ var WorkspaceMonthlyPdfGenerator = ({
49100
49489
  }
49101
49490
  doc.setDrawColor(180, 180, 180);
49102
49491
  doc.setLineWidth(0.8);
49103
- doc.line(20, 180, 190, 180);
49492
+ const separatorY = isAssemblyWorkspaceAndNotUptime ? 150 : 180;
49493
+ doc.line(20, separatorY, 190, separatorY);
49104
49494
  doc.setFillColor(245, 245, 245);
49105
- 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");
49106
49497
  doc.setFontSize(18);
49107
49498
  doc.setFont("helvetica", "bold");
49108
49499
  doc.setTextColor(40, 40, 40);
49109
- doc.text(isUptimeMode ? "Daily Utilization Summary" : "Daily Performance Summary", 20, 195);
49500
+ doc.text(isUptimeMode ? "Daily Utilization Summary" : "Daily Performance Summary", 20, dailySectionY + 10);
49110
49501
  doc.setTextColor(0, 0, 0);
49111
49502
  if (validDays.length > 0) {
49112
49503
  doc.setFontSize(10);
49113
49504
  doc.setFont("helvetica", "bold");
49114
49505
  doc.setFillColor(240, 240, 240);
49115
- doc.roundedRect(20, 200, 170, 7, 1, 1, "F");
49116
- doc.text("Date", 25, 205);
49117
- doc.text(isUptimeMode ? "Productive" : "Actual", 60, 205);
49118
- doc.text(isUptimeMode ? "Idle" : "Standard", 95, 205);
49119
- doc.text(isUptimeMode ? "Utilization" : "Efficiency", 135, 205);
49120
- 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);
49121
49514
  doc.setLineWidth(0.2);
49122
49515
  doc.setDrawColor(220, 220, 220);
49123
- doc.line(20, 208, 190, 208);
49516
+ doc.line(20, textY + 3, 190, textY + 3);
49124
49517
  doc.setFont("helvetica", "normal");
49125
- let yPos = 215;
49518
+ let yPos = textY + 10;
49126
49519
  const recentDays = validDays.slice(-10).reverse();
49127
49520
  recentDays.forEach((dayData, index) => {
49128
49521
  if (yPos > 260) return;
@@ -49156,8 +49549,13 @@ var WorkspaceMonthlyPdfGenerator = ({
49156
49549
  }
49157
49550
  doc.setTextColor(0, 0, 0);
49158
49551
  } else {
49159
- doc.text(`${shift.output}`, 60, yPos);
49160
- 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
+ }
49161
49559
  doc.text(`${shift.efficiency.toFixed(1)}%`, 135, yPos);
49162
49560
  if (shift.efficiency >= effectiveLegend.green_min) {
49163
49561
  doc.setTextColor(0, 171, 69);
@@ -49172,12 +49570,12 @@ var WorkspaceMonthlyPdfGenerator = ({
49172
49570
  });
49173
49571
  doc.setLineWidth(0.2);
49174
49572
  doc.setDrawColor(220, 220, 220);
49175
- doc.roundedRect(20, 200, 170, yPos - 200 - 3, 1, 1, "S");
49573
+ doc.roundedRect(20, tableHeaderY, 170, yPos - tableHeaderY - 3, 1, 1, "S");
49176
49574
  } else {
49177
49575
  doc.setFontSize(12);
49178
49576
  doc.setFont("helvetica", "normal");
49179
49577
  doc.setTextColor(100, 100, 100);
49180
- doc.text("No daily data available for this month", 25, 215);
49578
+ doc.text("No daily data available for this month", 25, dailySectionY + 30);
49181
49579
  doc.setTextColor(0, 0, 0);
49182
49580
  }
49183
49581
  doc.setFontSize(9);
@@ -49210,46 +49608,64 @@ var WorkspaceCycleTimeMetricCards = ({
49210
49608
  workspace,
49211
49609
  className,
49212
49610
  legend,
49213
- layout: layout2 = "grid"
49611
+ layout: layout2 = "grid",
49612
+ isAssemblyWorkspace = false,
49613
+ idleTimeData
49214
49614
  }) => {
49215
49615
  const effectiveLegend = legend || DEFAULT_EFFICIENCY_LEGEND;
49216
49616
  const efficiencyValue = workspace.avg_efficiency || 0;
49217
49617
  const efficiencyTarget = effectiveLegend.green_min;
49218
49618
  const efficiencyColor = getEfficiencyHexColor(efficiencyValue, effectiveLegend);
49219
- const hideEfficiencyCard = shouldHideWorkspaceEfficiencyCard(workspace);
49220
- 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 || ""}`;
49221
49625
  return /* @__PURE__ */ jsxs("div", { className: containerClassName, children: [
49222
- !hideEfficiencyCard && /* @__PURE__ */ jsxs(Card2, { children: [
49223
- /* @__PURE__ */ jsx(CardHeader2, { className: "pb-2 flex-none", children: /* @__PURE__ */ jsx(CardTitle2, { className: "text-lg text-center", children: "Efficiency" }) }),
49224
- /* @__PURE__ */ jsx(CardContent2, { className: "flex-1 flex items-center justify-center py-6", children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
49225
- /* @__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: [
49226
49630
  efficiencyValue.toFixed(1),
49227
49631
  "%"
49228
49632
  ] }),
49229
- /* @__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: [
49230
49634
  "Target: ",
49231
49635
  Math.round(efficiencyTarget),
49232
49636
  "%"
49233
49637
  ] })
49234
- ] }) })
49638
+ ] })
49235
49639
  ] }),
49236
- /* @__PURE__ */ jsxs(Card2, { children: [
49237
- /* @__PURE__ */ jsx(CardHeader2, { className: "pb-2 flex-none", children: /* @__PURE__ */ jsx(CardTitle2, { className: "text-lg text-center", children: "Cycle Time (s)" }) }),
49238
- /* @__PURE__ */ jsx(CardContent2, { className: "flex-1 flex items-center justify-center py-6", children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
49239
- /* @__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) }),
49240
- /* @__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: [
49241
49645
  "Standard: ",
49242
49646
  workspace.ideal_cycle_time?.toFixed(1) || 0,
49243
49647
  "s"
49244
49648
  ] })
49245
- ] }) })
49649
+ ] })
49246
49650
  ] }),
49247
- /* @__PURE__ */ jsxs(Card2, { children: [
49248
- /* @__PURE__ */ jsx(CardHeader2, { className: "pb-2 flex-none", children: /* @__PURE__ */ jsx(CardTitle2, { className: "text-lg text-center", children: "Idle Time" }) }),
49249
- /* @__PURE__ */ jsx(CardContent2, { className: "flex-1 flex items-center justify-center py-6", children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
49250
- /* @__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) }),
49251
- /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500 mt-2", children: "Total idle time" })
49252
- ] }) })
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
+ ) })
49253
49669
  ] })
49254
49670
  ] });
49255
49671
  };
@@ -49387,13 +49803,13 @@ var getWorkspaceStyles = (position, isPlaceholder = false) => {
49387
49803
  ${isPlaceholder ? "cursor-default" : ""}`;
49388
49804
  };
49389
49805
  var formatPercentRange = (min, max) => {
49390
- const format8 = (value) => Number.isInteger(value) ? `${value}` : value.toFixed(1);
49806
+ const format9 = (value) => Number.isInteger(value) ? `${value}` : value.toFixed(1);
49391
49807
  if (min >= 100 || max >= 100) {
49392
- return `${format8(min)}+%`;
49808
+ return `${format9(min)}+%`;
49393
49809
  }
49394
- return `${format8(min)}-${format8(max)}%`;
49810
+ return `${format9(min)}-${format9(max)}%`;
49395
49811
  };
49396
- var Legend6 = ({
49812
+ var Legend5 = ({
49397
49813
  useBottleneckLabel = false,
49398
49814
  legend,
49399
49815
  metricLabel = "Efficiency"
@@ -49579,7 +49995,7 @@ var WorkspaceGrid = React141__default.memo(({
49579
49995
  return /* @__PURE__ */ jsxs("div", { className: `relative w-full h-full overflow-hidden ${className}`, children: [
49580
49996
  /* @__PURE__ */ jsxs("div", { className: "absolute top-0 left-2 sm:left-4 right-2 sm:right-8 z-20", children: [
49581
49997
  /* @__PURE__ */ jsxs("div", { className: "flex flex-row items-center justify-between py-1 sm:py-1.5 gap-2", children: [
49582
- /* @__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 }) }),
49583
49999
  mapViewEnabled && /* @__PURE__ */ jsx(
49584
50000
  "button",
49585
50001
  {
@@ -49596,7 +50012,7 @@ var WorkspaceGrid = React141__default.memo(({
49596
50012
  }
49597
50013
  )
49598
50014
  ] }),
49599
- /* @__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 }) })
49600
50016
  ] }),
49601
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(
49602
50018
  motion.div,
@@ -50107,7 +50523,7 @@ var KPISection = memo$1(({
50107
50523
  value: showSkeleton ? "" : kpis.efficiency.value,
50108
50524
  change: effChange,
50109
50525
  trend: effTrend,
50110
- trendLabel: "today",
50526
+ trendLabel: "vs yesterday",
50111
50527
  trendMode: "pill",
50112
50528
  suffix: "%",
50113
50529
  showZeroChange: true,
@@ -52343,7 +52759,7 @@ var SideNavBar = memo$1(({
52343
52759
  setIsAlertsOpen(willOpen);
52344
52760
  setIsSettingsOpen(false);
52345
52761
  if (willOpen) {
52346
- trackCoreEvent("Alerts Page Clicked", { source: "side_nav" });
52762
+ trackCoreEvent("Alerts page clicked", { source: "side_nav" });
52347
52763
  void refreshAlertsSummary();
52348
52764
  }
52349
52765
  },
@@ -52498,7 +52914,7 @@ var SideNavBar = memo$1(({
52498
52914
  {
52499
52915
  onClick: () => {
52500
52916
  setIsAlertsOpen(true);
52501
- trackCoreEvent("Alerts Page Clicked", { source: "side_nav_mobile" });
52917
+ trackCoreEvent("Alerts page clicked", { source: "side_nav_mobile" });
52502
52918
  void refreshAlertsSummary();
52503
52919
  onMobileMenuClose?.();
52504
52920
  },
@@ -59708,7 +60124,8 @@ var MonthlyRangeFilter = ({
59708
60124
  onMonthNavigate,
59709
60125
  className,
59710
60126
  variant = "default",
59711
- showLabel = true
60127
+ showLabel = true,
60128
+ singleDateOnly = false
59712
60129
  }) => {
59713
60130
  const todayKey = useMemo(
59714
60131
  () => formatInTimeZone(/* @__PURE__ */ new Date(), timezone || "UTC", "yyyy-MM-dd"),
@@ -59796,6 +60213,12 @@ var MonthlyRangeFilter = ({
59796
60213
  }
59797
60214
  setActivePreset("Custom");
59798
60215
  setPendingChangeMeta({ source: "custom" });
60216
+ if (singleDateOnly) {
60217
+ setRangeStart(day);
60218
+ setRangeEnd(day);
60219
+ setSelecting(false);
60220
+ return;
60221
+ }
59799
60222
  if (!selecting || !rangeStart) {
59800
60223
  setRangeStart(day);
59801
60224
  setRangeEnd(null);
@@ -59830,6 +60253,13 @@ var MonthlyRangeFilter = ({
59830
60253
  };
59831
60254
  const handleApply = () => {
59832
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
+ }
59833
60263
  const boundedStart = startOfDay(rangeStart) > startOfDay(today) ? startOfDay(today) : startOfDay(rangeStart);
59834
60264
  const candidateEnd = rangeEnd || rangeStart;
59835
60265
  const boundedEnd = startOfDay(candidateEnd) > startOfDay(today) ? startOfDay(today) : startOfDay(candidateEnd);
@@ -59894,6 +60324,7 @@ var MonthlyRangeFilter = ({
59894
60324
  {
59895
60325
  type: "button",
59896
60326
  onClick: () => setIsOpen((prev) => !prev),
60327
+ "aria-label": showLabel ? void 0 : singleDateOnly ? "Select date" : "Select date range",
59897
60328
  className: clsx(
59898
60329
  "flex items-center transition-all duration-200 focus:outline-none",
59899
60330
  !showLabel && "p-2 rounded-full hover:bg-gray-100",
@@ -59924,7 +60355,7 @@ var MonthlyRangeFilter = ({
59924
60355
  "overflow-hidden bg-white animate-in fade-in zoom-in-95 duration-200 flex",
59925
60356
  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"
59926
60357
  ), children: [
59927
- /* @__PURE__ */ jsxs("div", { className: "w-40 bg-[#F8FAFF] border-r border-gray-100 p-4 flex flex-col justify-between", children: [
60358
+ !singleDateOnly && /* @__PURE__ */ jsxs("div", { className: "w-40 bg-gray-50 border-r border-gray-100 p-4 flex flex-col justify-between", children: [
59928
60359
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
59929
60360
  presets.map((preset) => /* @__PURE__ */ jsx(
59930
60361
  "button",
@@ -59933,7 +60364,7 @@ var MonthlyRangeFilter = ({
59933
60364
  onClick: () => handlePresetClick(preset),
59934
60365
  className: clsx(
59935
60366
  "w-full text-left px-3 py-2 text-sm rounded-lg transition-all duration-200",
59936
- activePreset === preset.label ? "bg-[#EEF2FF] text-[#4F46E5] font-semibold" : "text-gray-600 hover:bg-gray-100/80"
60367
+ activePreset === preset.label ? "bg-blue-50 text-blue-600 font-semibold" : "text-gray-600 hover:bg-gray-100/80"
59937
60368
  ),
59938
60369
  children: preset.label
59939
60370
  },
@@ -59946,7 +60377,7 @@ var MonthlyRangeFilter = ({
59946
60377
  onClick: () => setActivePreset("Custom"),
59947
60378
  className: clsx(
59948
60379
  "w-full text-left px-3 py-2 text-sm rounded-lg transition-all duration-200",
59949
- activePreset === "Custom" ? "bg-[#EEF2FF] text-[#4F46E5] font-semibold" : "text-gray-600 hover:bg-gray-100/80"
60380
+ activePreset === "Custom" ? "bg-blue-50 text-blue-600 font-semibold" : "text-gray-600 hover:bg-gray-100/80"
59950
60381
  ),
59951
60382
  children: "Custom"
59952
60383
  }
@@ -59968,7 +60399,7 @@ var MonthlyRangeFilter = ({
59968
60399
  type: "button",
59969
60400
  onClick: handleApply,
59970
60401
  disabled: !rangeStart,
59971
- 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",
60402
+ 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",
59972
60403
  children: "Apply"
59973
60404
  }
59974
60405
  )
@@ -60018,9 +60449,9 @@ var MonthlyRangeFilter = ({
60018
60449
  const dayNum = day.getDate();
60019
60450
  const isFutureDay = startOfDay(day) > startOfDay(today);
60020
60451
  return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
60021
- inRange && !isStart && !isEnd && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 -inset-x-0.5 bg-[#EEF2FF] z-0" }),
60022
- inRange && isStart && !isSingleDaySelection && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 right-0 left-1/2 bg-[#EEF2FF] z-0" }),
60023
- inRange && isEnd && !isSingleDaySelection && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 left-0 right-1/2 bg-[#EEF2FF] z-0" }),
60452
+ inRange && !isStart && !isEnd && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 -inset-x-0.5 bg-blue-50 z-0" }),
60453
+ inRange && isStart && !isSingleDaySelection && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 right-0 left-1/2 bg-blue-50 z-0" }),
60454
+ inRange && isEnd && !isSingleDaySelection && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 left-0 right-1/2 bg-blue-50 z-0" }),
60024
60455
  /* @__PURE__ */ jsx(
60025
60456
  "button",
60026
60457
  {
@@ -60029,19 +60460,47 @@ var MonthlyRangeFilter = ({
60029
60460
  disabled: isFutureDay,
60030
60461
  className: clsx(
60031
60462
  "h-10 w-full flex items-center justify-center text-sm font-semibold transition-all duration-150 relative z-10",
60032
- isFutureDay && "text-gray-200 cursor-not-allowed",
60463
+ // Future day NOT in range
60464
+ isFutureDay && !inRange && "text-gray-300 cursor-not-allowed",
60033
60465
  // Not in range
60034
- !isFutureDay && !inRange && "text-gray-700 hover:bg-gray-50 rounded-lg",
60466
+ !isFutureDay && !inRange && "text-gray-700 hover:bg-gray-100 rounded-lg",
60035
60467
  // Middle of range
60036
- inRange && !isStart && !isEnd && "text-[#4F46E5]",
60468
+ inRange && !isStart && !isEnd && clsx(
60469
+ "text-blue-600",
60470
+ isFutureDay && "cursor-not-allowed opacity-60"
60471
+ ),
60037
60472
  // Start/End of range or Single selection
60038
- (isStart || isEnd) && "bg-[#4F46E5] text-white rounded-lg shadow-sm"
60473
+ (isStart || isEnd) && clsx(
60474
+ "bg-blue-600 text-white rounded-lg shadow-sm",
60475
+ isFutureDay && "cursor-not-allowed opacity-80"
60476
+ )
60039
60477
  ),
60040
60478
  children: dayNum
60041
60479
  }
60042
60480
  )
60043
60481
  ] }, day.toISOString());
60044
- }) })
60482
+ }) }),
60483
+ singleDateOnly && /* @__PURE__ */ jsxs("div", { className: "mt-4 flex items-center justify-end gap-2 border-t border-gray-100 pt-3", children: [
60484
+ /* @__PURE__ */ jsx(
60485
+ "button",
60486
+ {
60487
+ type: "button",
60488
+ onClick: handleReset,
60489
+ className: "px-3 py-1.5 text-sm font-medium text-gray-500 hover:text-gray-700 transition-colors",
60490
+ children: "Reset"
60491
+ }
60492
+ ),
60493
+ /* @__PURE__ */ jsx(
60494
+ "button",
60495
+ {
60496
+ type: "button",
60497
+ onClick: handleApply,
60498
+ disabled: !rangeStart,
60499
+ 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",
60500
+ children: "Apply"
60501
+ }
60502
+ )
60503
+ ] })
60045
60504
  ] })
60046
60505
  ] })
60047
60506
  ] });
@@ -61818,7 +62277,36 @@ var getMonthDateInfo = (timezone) => {
61818
62277
  const monthEndDate = fromZonedTime(`${monthEndKey}T23:59:59`, timezone);
61819
62278
  return { startDate, endDate, monthEndDate };
61820
62279
  };
61821
- var LeaderboardCountdown = ({ targetDate, format: format8, finishedLabel = "Finished", placeholder = "--", onFinished }) => {
62280
+ var createKpisOverviewUrl = ({
62281
+ tab,
62282
+ date,
62283
+ shift
62284
+ }) => {
62285
+ const params = new URLSearchParams();
62286
+ if (tab) {
62287
+ params.set("tab", tab);
62288
+ }
62289
+ if (date) {
62290
+ params.set("date", date);
62291
+ }
62292
+ if (typeof shift === "number" && Number.isFinite(shift)) {
62293
+ params.set("shift", shift.toString());
62294
+ }
62295
+ const queryString = params.toString();
62296
+ return queryString ? `/kpis?${queryString}` : "/kpis";
62297
+ };
62298
+ var getZonedDateAtMidday = (dateKey, timezone) => fromZonedTime(`${dateKey}T12:00:00`, timezone);
62299
+ var formatDateKey = (dateKey, timezone, options) => {
62300
+ try {
62301
+ return new Intl.DateTimeFormat("en-US", {
62302
+ ...options,
62303
+ timeZone: timezone
62304
+ }).format(getZonedDateAtMidday(dateKey, timezone));
62305
+ } catch {
62306
+ return dateKey;
62307
+ }
62308
+ };
62309
+ var LeaderboardCountdown = ({ targetDate, format: format9, finishedLabel = "Finished", placeholder = "--", onFinished }) => {
61822
62310
  const [time2, setTime] = useState("");
61823
62311
  const hasFinishedRef = useRef(false);
61824
62312
  useEffect(() => {
@@ -61840,7 +62328,7 @@ var LeaderboardCountdown = ({ targetDate, format: format8, finishedLabel = "Fini
61840
62328
  }
61841
62329
  return;
61842
62330
  }
61843
- if (format8 === "days") {
62331
+ if (format9 === "days") {
61844
62332
  const days = Math.floor(diff / (1e3 * 60 * 60 * 24));
61845
62333
  const hours = Math.floor(diff % (1e3 * 60 * 60 * 24) / (1e3 * 60 * 60));
61846
62334
  setTime(`${days} days ${hours} hours`);
@@ -61855,7 +62343,7 @@ var LeaderboardCountdown = ({ targetDate, format: format8, finishedLabel = "Fini
61855
62343
  tick();
61856
62344
  const interval = setInterval(tick, 1e3);
61857
62345
  return () => clearInterval(interval);
61858
- }, [targetDate, format8, finishedLabel, placeholder, onFinished]);
62346
+ }, [targetDate, format9, finishedLabel, placeholder, onFinished]);
61859
62347
  return /* @__PURE__ */ jsx(Fragment, { children: time2 });
61860
62348
  };
61861
62349
  var LinesLeaderboard = ({
@@ -61873,7 +62361,9 @@ var LinesLeaderboard = ({
61873
62361
  shiftEndDate,
61874
62362
  monthEndDate,
61875
62363
  viewType,
61876
- setViewType
62364
+ setViewType,
62365
+ timezone: _timezone,
62366
+ isHistoricalDaily
61877
62367
  }) => {
61878
62368
  const formatEfficiency = (value) => typeof value === "number" && Number.isFinite(value) ? `${value.toFixed(1)}%` : "--";
61879
62369
  const assignedLineIdSet = React141__default.useMemo(
@@ -61966,10 +62456,10 @@ var LinesLeaderboard = ({
61966
62456
  }
61967
62457
  }, [timeRange, leaderboardData, isLoadingToday, isLoadingMonthly]);
61968
62458
  const topThree = leaderboardData.slice(0, 3);
61969
- leaderboardData.slice(3);
61970
62459
  const countdownTarget = timeRange === "monthly" ? monthEndDate : shiftEndDate;
61971
62460
  const countdownFormat = timeRange === "monthly" ? "days" : "clock";
61972
62461
  const countdownFinishedLabel = timeRange === "monthly" ? "Finished" : "Shift Ended";
62462
+ const showCountdown = timeRange === "monthly" || !isHistoricalDaily;
61973
62463
  const handleCountdownFinished = React141__default.useCallback(() => {
61974
62464
  trackCoreEvent("Leaderboard Countdown Finished", {
61975
62465
  countdown_type: timeRange === "monthly" ? "month_end" : "shift_end",
@@ -62043,7 +62533,7 @@ var LinesLeaderboard = ({
62043
62533
  }
62044
62534
  )
62045
62535
  ] }),
62046
- /* @__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: [
62536
+ /* @__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: [
62047
62537
  /* @__PURE__ */ jsx(Clock, { className: "w-4 h-4 text-orange-500" }),
62048
62538
  /* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-2", children: [
62049
62539
  /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider", children: "Ends in" }),
@@ -62164,7 +62654,7 @@ var LinesLeaderboard = ({
62164
62654
  /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-gray-900", children: item.supervisorName })
62165
62655
  ] }) }),
62166
62656
  /* @__PURE__ */ jsx("td", { className: "px-4 py-3 whitespace-nowrap text-sm text-gray-500", children: item.line.line_name }),
62167
- /* @__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) }) }) })
62657
+ /* @__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) }) }) })
62168
62658
  ]
62169
62659
  },
62170
62660
  item.id
@@ -62338,6 +62828,9 @@ var KPIsOverviewView = ({
62338
62828
  const [activeTab, setActiveTab] = useState("today");
62339
62829
  const [timeRange, setTimeRange] = useState("today");
62340
62830
  const [viewType, setViewType] = useState("operator");
62831
+ const [selectedLeaderboardDate, setSelectedLeaderboardDate] = useState("");
62832
+ const [selectedLeaderboardShiftId, setSelectedLeaderboardShiftId] = useState(0);
62833
+ const [hasHydratedLeaderboardRouteState, setHasHydratedLeaderboardRouteState] = useState(false);
62341
62834
  const [loading, setLoading] = useState(true);
62342
62835
  const [error, setError] = useState(null);
62343
62836
  const [topPerformer, setTopPerformer] = useState({
@@ -62359,13 +62852,6 @@ var KPIsOverviewView = ({
62359
62852
  const [monthlyError, setMonthlyError] = useState(null);
62360
62853
  const dailyRequestKeyRef = useRef(null);
62361
62854
  const monthlyRequestKeyRef = useRef(null);
62362
- useEffect(() => {
62363
- if (!router.isReady) return;
62364
- const tab = router.query.tab;
62365
- if (tab === "leaderboard") {
62366
- setActiveTab("leaderboard");
62367
- }
62368
- }, [router.isReady, router.query.tab]);
62369
62855
  const supabase = useSupabase();
62370
62856
  const { user } = useAuth();
62371
62857
  const dashboardConfig = useDashboardConfig();
@@ -62451,7 +62937,77 @@ var KPIsOverviewView = ({
62451
62937
  () => getShiftEndDate(currentShiftDetails, configuredTimezone),
62452
62938
  [currentShiftDetails, configuredTimezone]
62453
62939
  );
62454
- const shiftName = (currentShiftDetails.shiftName || "Day").replace(/ Shift$/i, "");
62940
+ const leaderboardShiftOptions = React141__default.useMemo(() => {
62941
+ if (shiftConfig?.shifts && shiftConfig.shifts.length > 0) {
62942
+ return shiftConfig.shifts.map((shift) => ({
62943
+ id: shift.shiftId,
62944
+ label: shift.shiftName || `Shift ${shift.shiftId}`,
62945
+ startTime: shift.startTime,
62946
+ endTime: shift.endTime
62947
+ }));
62948
+ }
62949
+ return [
62950
+ { id: 0, label: "Day Shift", startTime: "06:00", endTime: "18:00" },
62951
+ { id: 1, label: "Night Shift", startTime: "18:00", endTime: "06:00" }
62952
+ ];
62953
+ }, [shiftConfig]);
62954
+ const effectiveLeaderboardDate = selectedLeaderboardDate || currentShiftDate;
62955
+ const effectiveLeaderboardShiftId = Number.isFinite(selectedLeaderboardShiftId) ? selectedLeaderboardShiftId : currentShiftId;
62956
+ const isHistoricalLeaderboardDaily = activeTab === "leaderboard" && timeRange === "today" && (effectiveLeaderboardDate !== currentShiftDate || effectiveLeaderboardShiftId !== currentShiftId);
62957
+ useEffect(() => {
62958
+ if (!router.isReady) return;
62959
+ const tabQuery = router.query.tab;
62960
+ const dateQuery = router.query.date;
62961
+ const shiftQuery = router.query.shift;
62962
+ const parsedShiftQuery = typeof shiftQuery === "string" ? Number.parseInt(shiftQuery, 10) : Number.NaN;
62963
+ const hasHistoricalQuery = tabQuery === "leaderboard" && typeof dateQuery === "string" && Number.isFinite(parsedShiftQuery);
62964
+ setActiveTab(tabQuery === "leaderboard" ? "leaderboard" : "today");
62965
+ if (hasHistoricalQuery) {
62966
+ setSelectedLeaderboardDate(dateQuery);
62967
+ setSelectedLeaderboardShiftId(parsedShiftQuery);
62968
+ setTimeRange("today");
62969
+ } else {
62970
+ setSelectedLeaderboardDate(currentShiftDate);
62971
+ setSelectedLeaderboardShiftId(currentShiftId);
62972
+ }
62973
+ setHasHydratedLeaderboardRouteState(true);
62974
+ }, [
62975
+ router.isReady,
62976
+ router.query.tab,
62977
+ router.query.date,
62978
+ router.query.shift,
62979
+ currentShiftDate,
62980
+ currentShiftId
62981
+ ]);
62982
+ useEffect(() => {
62983
+ if (!router.isReady || !hasHydratedLeaderboardRouteState) return;
62984
+ const expectedTab = activeTab === "leaderboard" ? "leaderboard" : void 0;
62985
+ const expectedDate = activeTab === "leaderboard" && timeRange === "today" && isHistoricalLeaderboardDaily ? effectiveLeaderboardDate : void 0;
62986
+ const expectedShift = expectedDate !== void 0 ? effectiveLeaderboardShiftId.toString() : void 0;
62987
+ const currentTab = typeof router.query.tab === "string" ? router.query.tab : void 0;
62988
+ const currentDateQuery = typeof router.query.date === "string" ? router.query.date : void 0;
62989
+ const currentShiftQuery = typeof router.query.shift === "string" ? router.query.shift : void 0;
62990
+ if (currentTab === expectedTab && currentDateQuery === expectedDate && currentShiftQuery === expectedShift) {
62991
+ return;
62992
+ }
62993
+ void router.replace(
62994
+ createKpisOverviewUrl({
62995
+ tab: expectedTab === "leaderboard" ? "leaderboard" : void 0,
62996
+ date: expectedDate,
62997
+ shift: expectedShift !== void 0 ? Number.parseInt(expectedShift, 10) : void 0
62998
+ }),
62999
+ void 0,
63000
+ { shallow: true }
63001
+ );
63002
+ }, [
63003
+ router,
63004
+ activeTab,
63005
+ timeRange,
63006
+ effectiveLeaderboardDate,
63007
+ effectiveLeaderboardShiftId,
63008
+ hasHydratedLeaderboardRouteState,
63009
+ isHistoricalLeaderboardDaily
63010
+ ]);
62455
63011
  const factoryViewId = entityConfig.factoryViewId || "factory";
62456
63012
  const {
62457
63013
  lineMetrics,
@@ -62626,10 +63182,10 @@ var KPIsOverviewView = ({
62626
63182
  }, [supabase, resolvedCompanyId, leaderboardLinesForView, monthStartDate, monthEndDateKey, viewType]);
62627
63183
  const fetchDailyLeaderboard = useCallback(async () => {
62628
63184
  if (!supabase || !resolvedCompanyId || leaderboardLinesForView.length === 0) return;
62629
- if (!currentShiftDate) return;
63185
+ if (!effectiveLeaderboardDate) return;
62630
63186
  const targetLineIds = leaderboardLinesForView.map((line) => line.id);
62631
63187
  const lineIdsKey = targetLineIds.slice().sort().join(",");
62632
- const requestKey = `${resolvedCompanyId}|${currentShiftDate}|${currentShiftId}|${lineIdsKey}`;
63188
+ const requestKey = `${resolvedCompanyId}|${effectiveLeaderboardDate}|${effectiveLeaderboardShiftId}|${lineIdsKey}`;
62633
63189
  if (dailyRequestKeyRef.current === requestKey) return;
62634
63190
  dailyRequestKeyRef.current = requestKey;
62635
63191
  setDailyLoading(true);
@@ -62637,8 +63193,8 @@ var KPIsOverviewView = ({
62637
63193
  try {
62638
63194
  const entries = await lineLeaderboardService.getDailyLineLeaderboard(supabase, {
62639
63195
  companyId: resolvedCompanyId,
62640
- date: currentShiftDate,
62641
- shiftId: currentShiftId,
63196
+ date: effectiveLeaderboardDate,
63197
+ shiftId: effectiveLeaderboardShiftId,
62642
63198
  lineIds: targetLineIds,
62643
63199
  lineMode: viewType === "machine" ? "uptime" : "output"
62644
63200
  });
@@ -62656,7 +63212,14 @@ var KPIsOverviewView = ({
62656
63212
  } finally {
62657
63213
  setDailyLoading(false);
62658
63214
  }
62659
- }, [supabase, resolvedCompanyId, leaderboardLinesForView, currentShiftDate, currentShiftId, viewType]);
63215
+ }, [
63216
+ supabase,
63217
+ resolvedCompanyId,
63218
+ leaderboardLinesForView,
63219
+ effectiveLeaderboardDate,
63220
+ effectiveLeaderboardShiftId,
63221
+ viewType
63222
+ ]);
62660
63223
  useEffect(() => {
62661
63224
  if (activeTab !== "leaderboard") return;
62662
63225
  fetchMonthlyLeaderboard();
@@ -62745,6 +63308,12 @@ var KPIsOverviewView = ({
62745
63308
  trackProps.status = isEfficiencyOnTrack(kpis.efficiency?.value) ? "On Track" : "Behind";
62746
63309
  }
62747
63310
  trackCoreEvent("Line Card Clicked", trackProps);
63311
+ if (activeTab === "leaderboard" && timeRange === "today" && isHistoricalLeaderboardDaily) {
63312
+ navigation.navigate(
63313
+ `/kpis/${line.id}?date=${encodeURIComponent(effectiveLeaderboardDate)}&shift=${effectiveLeaderboardShiftId}`
63314
+ );
63315
+ return;
63316
+ }
62748
63317
  navigation.navigate(`/kpis/${line.id}`);
62749
63318
  };
62750
63319
  const handleBackClick = useCallback(() => {
@@ -62770,21 +63339,24 @@ var KPIsOverviewView = ({
62770
63339
  });
62771
63340
  setActiveTab(newTab);
62772
63341
  }, [activeTab, leaderboardLines.length, lines.length]);
62773
- const formatLocalDate2 = (date) => {
62774
- const options = {
63342
+ const formatLocalDate2 = useCallback((dateKey) => {
63343
+ return formatDateKey(dateKey, configuredTimezone, {
62775
63344
  year: "numeric",
62776
63345
  month: "long",
62777
63346
  day: "numeric"
62778
- };
62779
- return date.toLocaleDateString("en-US", options);
62780
- };
63347
+ });
63348
+ }, [configuredTimezone]);
62781
63349
  const getMonthRange = () => {
62782
- const now4 = /* @__PURE__ */ new Date();
62783
- const startOfMonth2 = new Date(now4.getFullYear(), now4.getMonth(), 1);
62784
- const endOfMonth2 = new Date(now4.getFullYear(), now4.getMonth() + 1, 0);
62785
- const startLabel = startOfMonth2.toLocaleDateString("en-US", { month: "short", day: "numeric" });
62786
- const endLabel = endOfMonth2.toLocaleDateString("en-US", { month: "short", day: "numeric" });
62787
- return `${startLabel} - ${endLabel}, ${now4.getFullYear()}`;
63350
+ const zonedNow = toZonedTime(/* @__PURE__ */ new Date(), configuredTimezone);
63351
+ const startOfMonthKey = buildDateKey(zonedNow.getFullYear(), zonedNow.getMonth(), 1);
63352
+ const endOfMonthKey = buildDateKey(
63353
+ zonedNow.getFullYear(),
63354
+ zonedNow.getMonth(),
63355
+ new Date(zonedNow.getFullYear(), zonedNow.getMonth() + 1, 0).getDate()
63356
+ );
63357
+ const startLabel = formatDateKey(startOfMonthKey, configuredTimezone, { month: "short", day: "numeric" });
63358
+ const endLabel = formatDateKey(endOfMonthKey, configuredTimezone, { month: "short", day: "numeric" });
63359
+ return `${startLabel} - ${endLabel}, ${zonedNow.getFullYear()}`;
62788
63360
  };
62789
63361
  const isMonthlyMode = activeTab === "leaderboard" && timeRange === "monthly";
62790
63362
  const isLeaderboardLoading = timeRange === "today" ? dailyLoading : monthlyLoading;
@@ -62793,8 +63365,13 @@ var KPIsOverviewView = ({
62793
63365
  const showTopPerformerImage = Boolean(topPerformer.imageUrl) && !topPerformerImageError;
62794
63366
  typeof topPerformer.efficiency === "number" && Number.isFinite(topPerformer.efficiency);
62795
63367
  topPerformerLoading ? "--" : typeof topPerformer.efficiency === "number" && Number.isFinite(topPerformer.efficiency) ? `${topPerformer.efficiency.toFixed(1)}%` : "--";
63368
+ const showHistoricalLeaderboardHeader = activeTab === "leaderboard" && timeRange === "today" && isHistoricalLeaderboardDaily;
63369
+ const headerDateKey = activeTab === "leaderboard" && timeRange === "today" ? effectiveLeaderboardDate : monthEndDateKey;
63370
+ const headerShiftId = showHistoricalLeaderboardHeader ? effectiveLeaderboardShiftId : currentShiftDetails.shiftId;
63371
+ const headerShiftName = getShiftNameById(headerShiftId, configuredTimezone, shiftConfig).replace(/ Shift$/i, "");
63372
+ const headerDateLabel = isMonthlyMode ? getMonthRange() : formatLocalDate2(headerDateKey);
62796
63373
  const getShiftIcon = (shiftId) => {
62797
- const shiftNameLower = shiftName.toLowerCase();
63374
+ const shiftNameLower = getShiftNameById(shiftId, configuredTimezone, shiftConfig).toLowerCase();
62798
63375
  if (shiftNameLower.includes("day") || shiftNameLower.includes("morning") || shiftId === 0) {
62799
63376
  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" }) });
62800
63377
  }
@@ -62897,18 +63474,26 @@ var KPIsOverviewView = ({
62897
63474
  ),
62898
63475
  /* @__PURE__ */ jsx("div", { className: "flex-1 flex items-center justify-center", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
62899
63476
  /* @__PURE__ */ jsx("h1", { className: "text-lg font-semibold text-gray-900", children: activeTab === "leaderboard" ? "Leaderboard" : "Overview" }),
62900
- /* @__PURE__ */ jsx("div", { className: "h-2 w-2 rounded-full bg-emerald-500 animate-pulse ring-2 ring-emerald-500/20" })
63477
+ /* @__PURE__ */ jsx(
63478
+ "div",
63479
+ {
63480
+ 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"}`
63481
+ }
63482
+ )
62901
63483
  ] }) }),
62902
63484
  /* @__PURE__ */ jsx("div", { className: "w-12" })
62903
63485
  ] }),
62904
63486
  /* @__PURE__ */ jsxs("div", { className: "mt-2 flex flex-wrap items-center justify-center gap-2", children: [
62905
- /* @__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()) }) }),
63487
+ /* @__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 }) }),
62906
63488
  !isMonthlyMode && /* @__PURE__ */ jsxs(Fragment, { children: [
62907
63489
  /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
62908
- /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon(currentShiftDetails.shiftId) }),
62909
- /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-700", children: shiftName })
63490
+ /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon(headerShiftId) }),
63491
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-700", children: headerShiftName })
62910
63492
  ] }),
62911
- /* @__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, {}) }) })
63493
+ 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: [
63494
+ /* @__PURE__ */ jsx(Clock, { className: "w-3 h-3" }),
63495
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium", children: "Historical" })
63496
+ ] }) : /* @__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, {}) }) })
62912
63497
  ] })
62913
63498
  ] }),
62914
63499
  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: [
@@ -63009,7 +63594,12 @@ var KPIsOverviewView = ({
63009
63594
  ) }),
63010
63595
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
63011
63596
  /* @__PURE__ */ jsx("h1", { className: "text-2xl md:text-3xl lg:text-4xl font-semibold text-gray-900 tracking-tight", children: activeTab === "leaderboard" ? "Leaderboard" : "Overview" }),
63012
- /* @__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" })
63597
+ /* @__PURE__ */ jsx(
63598
+ "div",
63599
+ {
63600
+ 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"}`
63601
+ }
63602
+ )
63013
63603
  ] }),
63014
63604
  !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: [
63015
63605
  /* @__PURE__ */ jsxs("div", { className: "relative", children: [
@@ -63079,7 +63669,7 @@ var KPIsOverviewView = ({
63079
63669
  ] }) })
63080
63670
  ] }),
63081
63671
  /* @__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: [
63082
- !isMonthlyMode && /* @__PURE__ */ jsxs(Fragment, { children: [
63672
+ !isMonthlyMode && !showHistoricalLeaderboardHeader && /* @__PURE__ */ jsxs(Fragment, { children: [
63083
63673
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-blue-700", children: [
63084
63674
  /* @__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" }) }),
63085
63675
  /* @__PURE__ */ jsx("span", { className: "text-base font-semibold tabular-nums", children: /* @__PURE__ */ jsx(ISTTimer_default, {}) })
@@ -63088,16 +63678,23 @@ var KPIsOverviewView = ({
63088
63678
  ] }),
63089
63679
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
63090
63680
  /* @__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" }) }),
63091
- /* @__PURE__ */ jsx("span", { className: `${isMonthlyMode ? "text-base font-medium" : "text-sm font-medium"}`, children: isMonthlyMode ? getMonthRange() : formatLocalDate2(/* @__PURE__ */ new Date()) })
63681
+ /* @__PURE__ */ jsx("span", { className: `${isMonthlyMode ? "text-base font-medium" : "text-sm font-medium"}`, children: headerDateLabel })
63092
63682
  ] }),
63093
63683
  !isMonthlyMode && /* @__PURE__ */ jsxs(Fragment, { children: [
63094
63684
  /* @__PURE__ */ jsx("div", { className: "w-px h-4 bg-blue-200" }),
63095
63685
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
63096
- /* @__PURE__ */ jsx("div", { className: "opacity-70", children: getShiftIcon(currentShiftDetails.shiftId) }),
63686
+ /* @__PURE__ */ jsx("div", { className: "opacity-70", children: getShiftIcon(headerShiftId) }),
63097
63687
  /* @__PURE__ */ jsxs("span", { className: "text-sm font-semibold uppercase tracking-wider", children: [
63098
- shiftName,
63688
+ headerShiftName,
63099
63689
  " Shift"
63100
63690
  ] })
63691
+ ] }),
63692
+ showHistoricalLeaderboardHeader && /* @__PURE__ */ jsxs(Fragment, { children: [
63693
+ /* @__PURE__ */ jsx("div", { className: "w-px h-4 bg-blue-200" }),
63694
+ /* @__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: [
63695
+ /* @__PURE__ */ jsx(Clock, { className: "w-3.5 h-3.5" }),
63696
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold uppercase tracking-wider", children: "Historical" })
63697
+ ] })
63101
63698
  ] })
63102
63699
  ] })
63103
63700
  ] }) }),
@@ -63120,19 +63717,63 @@ var KPIsOverviewView = ({
63120
63717
  }
63121
63718
  )
63122
63719
  ] }),
63123
- (activeTab === "leaderboard" || activeTab === "today") && showViewTypeDropdown && /* @__PURE__ */ jsx("div", { className: "relative", children: /* @__PURE__ */ jsxs(
63124
- "select",
63125
- {
63126
- value: viewType,
63127
- onChange: (e) => setViewType(e.target.value),
63128
- 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",
63129
- 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` },
63130
- children: [
63131
- /* @__PURE__ */ jsx("option", { value: "operator", children: "Workforce" }),
63132
- /* @__PURE__ */ jsx("option", { value: "machine", children: "Machine" })
63133
- ]
63134
- }
63135
- ) })
63720
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
63721
+ activeTab === "leaderboard" && timeRange === "today" && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
63722
+ /* @__PURE__ */ jsx(
63723
+ MonthlyRangeFilter_default,
63724
+ {
63725
+ month: parseDateKeyToDate(effectiveLeaderboardDate).getMonth(),
63726
+ year: parseDateKeyToDate(effectiveLeaderboardDate).getFullYear(),
63727
+ timezone: configuredTimezone,
63728
+ value: {
63729
+ startKey: effectiveLeaderboardDate,
63730
+ endKey: effectiveLeaderboardDate
63731
+ },
63732
+ onChange: (range) => {
63733
+ setSelectedLeaderboardDate(range.startKey);
63734
+ },
63735
+ showLabel: false,
63736
+ singleDateOnly: true
63737
+ }
63738
+ ),
63739
+ /* @__PURE__ */ jsx("div", { className: "relative", children: /* @__PURE__ */ jsx(
63740
+ "select",
63741
+ {
63742
+ "aria-label": "Leaderboard shift",
63743
+ value: effectiveLeaderboardShiftId,
63744
+ onChange: (e) => setSelectedLeaderboardShiftId(Number(e.target.value)),
63745
+ 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 min-w-[170px]",
63746
+ 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` },
63747
+ children: leaderboardShiftOptions.map((shiftOption) => /* @__PURE__ */ jsx("option", { value: shiftOption.id, children: shiftOption.label }, shiftOption.id))
63748
+ }
63749
+ ) }),
63750
+ isHistoricalLeaderboardDaily && /* @__PURE__ */ jsx(
63751
+ "button",
63752
+ {
63753
+ type: "button",
63754
+ onClick: () => {
63755
+ setSelectedLeaderboardDate(currentShiftDate);
63756
+ setSelectedLeaderboardShiftId(currentShiftId);
63757
+ },
63758
+ className: "text-xs font-medium text-blue-600 hover:text-blue-700 whitespace-nowrap",
63759
+ children: "Return to Live"
63760
+ }
63761
+ )
63762
+ ] }),
63763
+ (activeTab === "leaderboard" || activeTab === "today") && showViewTypeDropdown && /* @__PURE__ */ jsx("div", { className: "relative", children: /* @__PURE__ */ jsxs(
63764
+ "select",
63765
+ {
63766
+ value: viewType,
63767
+ onChange: (e) => setViewType(e.target.value),
63768
+ 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",
63769
+ 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` },
63770
+ children: [
63771
+ /* @__PURE__ */ jsx("option", { value: "operator", children: "Workforce" }),
63772
+ /* @__PURE__ */ jsx("option", { value: "machine", children: "Machine" })
63773
+ ]
63774
+ }
63775
+ ) })
63776
+ ] })
63136
63777
  ] })
63137
63778
  ] })
63138
63779
  ] }) }),
@@ -63177,7 +63818,9 @@ var KPIsOverviewView = ({
63177
63818
  shiftEndDate,
63178
63819
  monthEndDate,
63179
63820
  viewType,
63180
- setViewType
63821
+ setViewType,
63822
+ timezone: configuredTimezone,
63823
+ isHistoricalDaily: isHistoricalLeaderboardDaily
63181
63824
  }
63182
63825
  ) })
63183
63826
  ) })
@@ -64719,51 +65362,41 @@ var ClipsCostView = () => {
64719
65362
  /* @__PURE__ */ jsx("div", { className: "min-w-[120px]" })
64720
65363
  ] }) })
64721
65364
  ] }) }),
64722
- /* @__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: [
65365
+ /* @__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: [
64723
65366
  /* @__PURE__ */ jsx(AlertCircle, { className: "h-5 w-5 flex-shrink-0 mt-0.5" }),
64724
65367
  /* @__PURE__ */ jsxs("div", { children: [
64725
65368
  /* @__PURE__ */ jsx("h3", { className: "font-medium", children: "Error loading usage data" }),
64726
65369
  /* @__PURE__ */ jsx("p", { className: "text-sm mt-1 text-red-600", children: error })
64727
65370
  ] })
64728
- ] }) : /* @__PURE__ */ jsxs("div", { className: "max-w-xl mt-8 animate-in fade-in slide-in-from-bottom-4 duration-500", children: [
64729
- /* @__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: [
64730
- /* @__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" }) }),
64731
- /* @__PURE__ */ jsx("h2", { className: "text-sm font-medium text-gray-500 uppercase tracking-wider mb-2", children: "Clips Analyzed" }),
64732
- /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-500 mb-3", children: formatMonthLabel(data?.monthStart) }),
64733
- /* @__PURE__ */ jsx("div", { className: "text-5xl font-bold text-gray-900 mb-2 tabular-nums tracking-tight", children: formatNumber(data?.monthlyClassifications || 0) })
64734
- ] }) }) }),
64735
- /* @__PURE__ */ jsx(Card2, { className: "mt-4 overflow-hidden shadow-sm border-gray-200 bg-white", children: /* @__PURE__ */ jsxs(CardContent2, { className: "p-6", children: [
64736
- /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-gray-900 mb-3 uppercase tracking-wider", children: "Previous Months" }),
64737
- (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(
65371
+ ] }) : /* @__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: [
65372
+ /* @__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: [
65373
+ /* @__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 }) }),
65374
+ /* @__PURE__ */ jsx("h2", { className: "text-base font-semibold text-gray-600 uppercase tracking-widest mb-3", children: "Current Month Usage" }),
65375
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-gray-400 mb-6", children: formatMonthLabel(data?.monthStart) }),
65376
+ /* @__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) }) }),
65377
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500 mt-4", children: "Clips analyzed and processed by our AI pipeline" })
65378
+ ] }) }) }) }),
65379
+ /* @__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: [
65380
+ /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-gray-900 mb-6 uppercase tracking-widest", children: "Previous Months" }),
65381
+ (data?.historicalMonthlyClassifications?.length || 0) === 0 ? /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col items-center justify-center text-center py-8", children: [
65382
+ /* @__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 }) }),
65383
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500", children: "No historical month usage yet." })
65384
+ ] }) : /* @__PURE__ */ jsx("div", { className: "space-y-3 flex-1 overflow-y-auto pr-2", children: data?.historicalMonthlyClassifications.map((item) => /* @__PURE__ */ jsxs(
64738
65385
  "div",
64739
65386
  {
64740
- className: "flex items-center justify-between rounded-md border border-gray-100 bg-gray-50 px-3 py-2",
65387
+ 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",
64741
65388
  children: [
64742
- /* @__PURE__ */ jsx("span", { className: "text-sm text-gray-700", children: formatMonthLabel(item.monthStart) }),
64743
- /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-gray-900 tabular-nums", children: formatNumber(item.classifications) })
65389
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-gray-600 group-hover:text-gray-900 transition-colors", children: formatMonthLabel(item.monthStart) }),
65390
+ /* @__PURE__ */ jsx("span", { className: "text-base font-semibold text-gray-900 tabular-nums", children: formatNumber(item.classifications) })
64744
65391
  ]
64745
65392
  },
64746
65393
  item.monthStart
64747
65394
  )) })
64748
- ] }) })
65395
+ ] }) }) })
64749
65396
  ] }) })
64750
65397
  ] });
64751
65398
  };
64752
65399
  var ClipsCostView_default = ClipsCostView;
64753
-
64754
- // src/lib/constants/actions.ts
64755
- var ACTION_NAMES = {
64756
- /** Assembly operations */
64757
- ASSEMBLY: "Assembly",
64758
- /** Packaging operations */
64759
- PACKAGING: "Packaging",
64760
- /** Inspection operations */
64761
- INSPECTION: "Inspection",
64762
- /** Testing operations */
64763
- TESTING: "Testing",
64764
- /** Quality control operations */
64765
- QUALITY_CONTROL: "Quality Control"
64766
- };
64767
65400
  var calculateShiftHours = (startTime, endTime, breaks = []) => {
64768
65401
  if (!startTime || !endTime) return 8;
64769
65402
  const [startHour, startMinute] = startTime.split(":").map(Number);
@@ -65345,9 +65978,9 @@ var ShiftsView = ({
65345
65978
  const actionIds = Array.from(
65346
65979
  new Set(currentThresholds.map((threshold) => threshold.action_id).filter(Boolean))
65347
65980
  );
65348
- const actionNameById = /* @__PURE__ */ new Map();
65981
+ const actionMetadataById = /* @__PURE__ */ new Map();
65349
65982
  if (actionIds.length > 0) {
65350
- const { data: actionRows, error: actionsError } = await supabase.from("actions").select("id, action_name").in("id", actionIds);
65983
+ const { data: actionRows, error: actionsError } = await supabase.from("actions").select("id, action_name, action_family").in("id", actionIds);
65351
65984
  if (actionsError) {
65352
65985
  console.warn(
65353
65986
  `[ShiftsView] Failed to resolve action names for line ${lineId}, shift ${shift.shiftId}: ${actionsError.message}`
@@ -65355,7 +65988,13 @@ var ShiftsView = ({
65355
65988
  } else {
65356
65989
  (actionRows || []).forEach((actionRow) => {
65357
65990
  if (actionRow.id && actionRow.action_name) {
65358
- actionNameById.set(actionRow.id, actionRow.action_name);
65991
+ actionMetadataById.set(actionRow.id, {
65992
+ action_name: actionRow.action_name,
65993
+ action_family: normalizeActionFamily({
65994
+ actionFamily: actionRow.action_family,
65995
+ actionName: actionRow.action_name
65996
+ })
65997
+ });
65359
65998
  }
65360
65999
  });
65361
66000
  }
@@ -65376,7 +66015,7 @@ var ShiftsView = ({
65376
66015
  nextDayOutput = dayOutputToKeep;
65377
66016
  nextPPH = newShiftHours > 0 ? Math.round(dayOutputToKeep / newShiftHours) : 0;
65378
66017
  }
65379
- const resolvedActionName = (typeof threshold.action_name === "string" && threshold.action_name.trim().length > 0 ? threshold.action_name : actionNameById.get(threshold.action_id)) || ACTION_NAMES.ASSEMBLY;
66018
+ 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;
65380
66019
  return {
65381
66020
  line_id: threshold.line_id || lineId,
65382
66021
  shift_id: shift.shiftId,
@@ -65397,18 +66036,20 @@ var ShiftsView = ({
65397
66036
  `Failed to update action thresholds for line ${lineId}, shift ${shift.shiftId}: ${thresholdsUpsertError.message}`
65398
66037
  );
65399
66038
  }
65400
- const packagingActionIds = new Set(
65401
- Array.from(actionNameById.entries()).filter(([, actionName]) => actionName.toLowerCase() === ACTION_NAMES.PACKAGING.toLowerCase()).map(([actionId]) => actionId)
66039
+ const outputActionIds = new Set(
66040
+ Array.from(actionMetadataById.entries()).filter(([, action]) => action.action_family === ACTION_FAMILIES.OUTPUT).map(([actionId]) => actionId)
65402
66041
  );
65403
- const packagingThresholds = recalculatedThresholds.filter((threshold) => {
65404
- if (packagingActionIds.has(threshold.action_id)) return true;
65405
- return typeof threshold.action_name === "string" && threshold.action_name.toLowerCase() === ACTION_NAMES.PACKAGING.toLowerCase();
66042
+ const outputThresholds = recalculatedThresholds.filter((threshold) => {
66043
+ if (outputActionIds.has(threshold.action_id)) return true;
66044
+ return normalizeActionFamily({
66045
+ actionName: threshold.action_name
66046
+ }) === ACTION_FAMILIES.OUTPUT;
65406
66047
  });
65407
- const thresholdDayOutput = packagingThresholds.reduce(
66048
+ const thresholdDayOutput = outputThresholds.reduce(
65408
66049
  (sum, threshold) => sum + (Number(threshold.total_day_output) || 0),
65409
66050
  0
65410
66051
  );
65411
- const thresholdPPH = packagingThresholds.reduce(
66052
+ const thresholdPPH = outputThresholds.reduce(
65412
66053
  (sum, threshold) => sum + (Number(threshold.pph_threshold) || 0),
65413
66054
  0
65414
66055
  );
@@ -66619,7 +67260,7 @@ var TargetsViewUI = ({
66619
67260
  "aria-label": `Action type for ${formattedName}`,
66620
67261
  children: [
66621
67262
  /* @__PURE__ */ jsx("option", { value: "assembly", className: "py-2", children: "Assembly" }),
66622
- /* @__PURE__ */ jsx("option", { value: "packaging", className: "py-2", children: "Packaging" })
67263
+ /* @__PURE__ */ jsx("option", { value: "output", className: "py-2", children: ACTION_NAMES.OUTPUT })
66623
67264
  ]
66624
67265
  }
66625
67266
  ) }),
@@ -66690,7 +67331,7 @@ var TargetsViewUI = ({
66690
67331
  "aria-label": `Action type for ${formattedName}`,
66691
67332
  children: [
66692
67333
  /* @__PURE__ */ jsx("option", { value: "assembly", children: "Assembly" }),
66693
- /* @__PURE__ */ jsx("option", { value: "packaging", children: "Packaging" })
67334
+ /* @__PURE__ */ jsx("option", { value: "output", children: ACTION_NAMES.OUTPUT })
66694
67335
  ]
66695
67336
  }
66696
67337
  )
@@ -66895,14 +67536,20 @@ var TargetsView = ({
66895
67536
  throw new Error("Failed to fetch bulk targets data");
66896
67537
  }
66897
67538
  const { data } = bulkResponse;
66898
- const assemblyAction = Object.values(data.actions).find((a) => a.action_name === ACTION_NAMES.ASSEMBLY);
66899
- const packagingAction = Object.values(data.actions).find((a) => a.action_name === ACTION_NAMES.PACKAGING);
66900
- if (!assemblyAction || !packagingAction) {
67539
+ const assemblyAction = data.actions[ACTION_FAMILIES.ASSEMBLY] || Object.values(data.actions).find((a) => normalizeActionFamily({
67540
+ actionFamily: a.action_family,
67541
+ actionName: a.action_name
67542
+ }) === ACTION_FAMILIES.ASSEMBLY);
67543
+ const outputAction = data.actions[ACTION_FAMILIES.OUTPUT] || Object.values(data.actions).find((a) => normalizeActionFamily({
67544
+ actionFamily: a.action_family,
67545
+ actionName: a.action_name
67546
+ }) === ACTION_FAMILIES.OUTPUT);
67547
+ if (!assemblyAction || !outputAction) {
66901
67548
  throw new Error("Could not find required actions in bulk response");
66902
67549
  }
66903
67550
  const actionIdsData = {
66904
67551
  assembly: assemblyAction.id,
66905
- packaging: packagingAction.id
67552
+ output: outputAction.id
66906
67553
  };
66907
67554
  setActionIds(actionIdsData);
66908
67555
  const newAllShiftsData = {};
@@ -66947,12 +67594,16 @@ var TargetsView = ({
66947
67594
  let actionType = "assembly";
66948
67595
  let actionId = actionIdsData.assembly;
66949
67596
  const effectiveActionId = threshold?.action_id ?? ws.action_id;
66950
- if (effectiveActionId === packagingAction.id || !effectiveActionId && ws.action_type === "packaging") {
66951
- actionType = "packaging";
66952
- actionId = packagingAction.id;
66953
- } else if (effectiveActionId === assemblyAction.id || !effectiveActionId && ws.action_type === "assembly") {
67597
+ const effectiveActionFamily = normalizeActionFamily({
67598
+ actionFamily: threshold?.action_family,
67599
+ actionType: ws.action_type
67600
+ });
67601
+ if (effectiveActionFamily === ACTION_FAMILIES.OUTPUT || effectiveActionId === outputAction.id || !effectiveActionId && ws.action_type === "output") {
67602
+ actionType = "output";
67603
+ actionId = effectiveActionId || outputAction.id;
67604
+ } else if (effectiveActionFamily === ACTION_FAMILIES.ASSEMBLY || effectiveActionId === assemblyAction.id || !effectiveActionId && ws.action_type === "assembly") {
66954
67605
  actionType = "assembly";
66955
- actionId = assemblyAction.id;
67606
+ actionId = effectiveActionId || assemblyAction.id;
66956
67607
  }
66957
67608
  return {
66958
67609
  id: ws.id,
@@ -67224,7 +67875,9 @@ var TargetsView = ({
67224
67875
  // Round to whole number
67225
67876
  ideal_cycle_time: Number(ws.targetCycleTime) || 0,
67226
67877
  total_day_output: Number(ws.targetDayOutput) || 0,
67227
- action_name: ws.actionType === "assembly" ? ACTION_NAMES.ASSEMBLY : ACTION_NAMES.PACKAGING,
67878
+ action_name: ws.actionType === "assembly" ? ACTION_NAMES.ASSEMBLY : ACTION_NAMES.OUTPUT,
67879
+ action_family: ws.actionType,
67880
+ display_name: ws.actionType === "assembly" ? ACTION_NAMES.ASSEMBLY : ACTION_NAMES.OUTPUT,
67228
67881
  updated_by: currentEffectiveUserId,
67229
67882
  // Use the potentially hardcoded ID
67230
67883
  ...skuEnabled && lineDataToSave.selectedSKU ? { sku_id: lineDataToSave.selectedSKU.id } : {}
@@ -67232,7 +67885,7 @@ var TargetsView = ({
67232
67885
  console.log(`[handleSaveLine] workspaceThresholdUpdates for ${lineId}:`, workspaceThresholdUpdates);
67233
67886
  await workspaceService.updateActionThresholds(workspaceThresholdUpdates);
67234
67887
  console.log(`[handleSaveLine] Successfully updated action thresholds for ${lineId}`);
67235
- const packagingWorkspaces = lineDataToSave.workspaces.filter((ws) => ws.actionType === "packaging");
67888
+ const outputWorkspaces = lineDataToSave.workspaces.filter((ws) => ws.actionType === "output");
67236
67889
  let resolvedLineThresholdSkuId = lineDataToSave.selectedSKU?.id || null;
67237
67890
  if (!resolvedLineThresholdSkuId) {
67238
67891
  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);
@@ -67250,8 +67903,8 @@ var TargetsView = ({
67250
67903
  date: currentDate,
67251
67904
  shift_id: selectedShift,
67252
67905
  product_code: lineDataToSave.productId,
67253
- threshold_day_output: packagingWorkspaces.reduce((acc, ws) => acc + (Number(ws.targetDayOutput) || 0), 0),
67254
- threshold_pph: packagingWorkspaces.reduce((acc, ws) => acc + (ws.targetPPH ? Math.round(Number(ws.targetPPH)) : 0), 0),
67906
+ threshold_day_output: outputWorkspaces.reduce((acc, ws) => acc + (Number(ws.targetDayOutput) || 0), 0),
67907
+ threshold_pph: outputWorkspaces.reduce((acc, ws) => acc + (ws.targetPPH ? Math.round(Number(ws.targetPPH)) : 0), 0),
67255
67908
  // Round each PPH value
67256
67909
  sku_id: resolvedLineThresholdSkuId
67257
67910
  };
@@ -67779,6 +68432,7 @@ var WorkspaceDetailView = ({
67779
68432
  avg_efficiency: Number(cachedOverviewMetrics.efficiency || 0),
67780
68433
  total_actions: totalActions,
67781
68434
  hourly_action_counts: [],
68435
+ hourly_cycle_times: [],
67782
68436
  workspace_rank: 0,
67783
68437
  total_workspaces: 0,
67784
68438
  ideal_output_until_now: idealOutput,
@@ -67789,6 +68443,22 @@ var WorkspaceDetailView = ({
67789
68443
  }, [cachedOverviewMetrics, shiftConfig?.shifts]);
67790
68444
  const workspace = (isHistoricView ? historicMetrics : liveMetrics) || cachedDetailedMetrics || overviewFallback;
67791
68445
  const detailedWorkspaceMetrics = (isHistoricView ? historicMetrics : liveMetrics) || cachedDetailedMetrics;
68446
+ const cycleTimeChartData = useMemo(
68447
+ () => Array.isArray(workspace?.hourly_cycle_times) ? workspace.hourly_cycle_times.map((value) => {
68448
+ const numericValue = Number(value);
68449
+ return Number.isFinite(numericValue) ? numericValue : 0;
68450
+ }) : [],
68451
+ [workspace?.hourly_cycle_times]
68452
+ );
68453
+ const cycleTimeDatasetKey = useMemo(
68454
+ () => [
68455
+ workspace?.workspace_id || workspaceId || "workspace",
68456
+ date || workspace?.date || "live",
68457
+ parsedShiftId ?? workspace?.shift_id ?? "current",
68458
+ "hourly"
68459
+ ].join(":"),
68460
+ [workspace?.workspace_id, workspaceId, date, workspace?.date, parsedShiftId, workspace?.shift_id]
68461
+ );
67792
68462
  const hasWorkspaceSnapshot = Boolean(workspace);
67793
68463
  const loading = ((isHistoricView ? historicLoading : liveLoading) || isShiftConfigLoading) && !hasWorkspaceSnapshot;
67794
68464
  const error = isHistoricView ? historicError : liveError;
@@ -68030,10 +68700,47 @@ var WorkspaceDetailView = ({
68030
68700
  return filterDataByDateKeyRange(monthlyData, range);
68031
68701
  }, [monthlyData, range]);
68032
68702
  const formattedWorkspaceName = displayName || formatWorkspaceName3(workspace?.workspace_name || "", effectiveLineId);
68033
- const shouldShowCycleTimeChart = !isUptimeMode && (showCycleTimeChart ?? formattedWorkspaceName.startsWith("FINAL ASSY"));
68703
+ const workspaceActionType = workspace && "action_type" in workspace ? workspace.action_type : void 0;
68704
+ const workspaceAssemblyEnabled = workspace && "line_assembly_enabled" in workspace ? workspace.line_assembly_enabled === true : false;
68705
+ const isAssemblyWorkspace = workspaceActionType === "assembly" || workspaceAssemblyEnabled;
68706
+ const shouldShowCycleTimeChart = !isUptimeMode && (showCycleTimeChart ?? isAssemblyWorkspace);
68034
68707
  const showIdleBreakdownChart = !shouldShowCycleTimeChart && idleTimeVlmEnabled;
68035
68708
  const idleClipDate = date || workspace?.date || calculatedOperationalDate || getOperationalDate(timezone);
68036
68709
  const idleClipShiftId = parsedShiftId ?? workspace?.shift_id;
68710
+ const hourlyIdleMinutes = useMemo(() => {
68711
+ if (!shouldShowCycleTimeChart || !workspace?.idle_time_hourly || !workspace?.shift_start) return [];
68712
+ const parseTimeToMinutes3 = (time2) => {
68713
+ const [h, m] = time2.split(":").map(Number);
68714
+ if (!Number.isFinite(h) || !Number.isFinite(m)) return 0;
68715
+ return h * 60 + m;
68716
+ };
68717
+ const startTotal = parseTimeToMinutes3(workspace.shift_start);
68718
+ const endTotalRaw = workspace.shift_end ? parseTimeToMinutes3(workspace.shift_end) : startTotal + 11 * 60;
68719
+ const endTotal = endTotalRaw <= startTotal ? endTotalRaw + 24 * 60 : endTotalRaw;
68720
+ const shiftDuration = Math.max(60, endTotal - startTotal);
68721
+ const totalHourSlots = Math.max(1, Math.ceil(shiftDuration / 60));
68722
+ const idleTimeHourlyObj = workspace.idle_time_hourly || {};
68723
+ const result = Array(totalHourSlots).fill(0);
68724
+ for (let i = 0; i < totalHourSlots; i++) {
68725
+ const startSlotMins = startTotal + i * 60;
68726
+ let endSlotMins = startSlotMins + 60;
68727
+ if (endSlotMins > endTotal) endSlotMins = endTotal;
68728
+ let idleCount = 0;
68729
+ for (let m = startSlotMins; m < endSlotMins; m++) {
68730
+ const hourKey = Math.floor(m / 60) % 24;
68731
+ const minuteKey = m % 60;
68732
+ const hourData = idleTimeHourlyObj[hourKey.toString()] || [];
68733
+ if (Array.isArray(hourData)) {
68734
+ const val = hourData[minuteKey];
68735
+ if (val === 1 || val === "1") {
68736
+ idleCount++;
68737
+ }
68738
+ }
68739
+ }
68740
+ result[i] = idleCount;
68741
+ }
68742
+ return result;
68743
+ }, [shouldShowCycleTimeChart, workspace?.idle_time_hourly, workspace?.shift_start, workspace?.shift_end]);
68037
68744
  const shiftDurationMinutes = useMemo(
68038
68745
  () => getShiftDurationMinutes(workspace?.shift_start, workspace?.shift_end),
68039
68746
  [workspace?.shift_start, workspace?.shift_end]
@@ -68106,7 +68813,7 @@ var WorkspaceDetailView = ({
68106
68813
  }
68107
68814
  }, [returnUrl]);
68108
68815
  const handleBackNavigation = () => {
68109
- if (date || shift) {
68816
+ if (isHistoricView) {
68110
68817
  setActiveTab("monthly_history");
68111
68818
  if (onNavigate) {
68112
68819
  const params = new URLSearchParams();
@@ -68270,7 +68977,7 @@ var WorkspaceDetailView = ({
68270
68977
  BackButtonMinimal,
68271
68978
  {
68272
68979
  onClick: handleBackNavigation,
68273
- 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",
68980
+ 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",
68274
68981
  size: "default",
68275
68982
  "aria-label": "Navigate back to previous page"
68276
68983
  }
@@ -68447,7 +69154,8 @@ var WorkspaceDetailView = ({
68447
69154
  {
68448
69155
  workspace,
68449
69156
  idleTimeReasons: idleTimeChartData,
68450
- efficiencyLegend
69157
+ efficiencyLegend,
69158
+ hourlyCycleTimes: cycleTimeChartData
68451
69159
  }
68452
69160
  ) }),
68453
69161
  activeTab === "monthly_history" && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
@@ -68528,7 +69236,7 @@ var WorkspaceDetailView = ({
68528
69236
  animate: "animate",
68529
69237
  children: [
68530
69238
  /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center mb-4", children: [
68531
- /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold text-gray-700", children: isUptimeMode ? "Machine Utilization" : shouldShowCycleTimeChart ? "Cycle Time (last 60 minutes)" : "Hourly Output" }),
69239
+ /* @__PURE__ */ jsx("h3", { className: "text-lg font-bold text-gray-700", children: isUptimeMode ? "Machine Utilization" : shouldShowCycleTimeChart ? "Cycle time trend" : "Hourly Output" }),
68532
69240
  !isUptimeMode && /* @__PURE__ */ jsx(
68533
69241
  "button",
68534
69242
  {
@@ -68561,9 +69269,14 @@ var WorkspaceDetailView = ({
68561
69269
  ) : shouldShowCycleTimeChart ? /* @__PURE__ */ jsx(
68562
69270
  CycleTimeOverTimeChart,
68563
69271
  {
68564
- data: workspace.hourly_action_counts || [],
69272
+ data: cycleTimeChartData,
68565
69273
  idealCycleTime: workspace.ideal_cycle_time || 0,
68566
- shiftStart: workspace.shift_start || ""
69274
+ shiftStart: workspace.shift_start || "",
69275
+ shiftEnd: workspace.shift_end || "",
69276
+ xAxisMode: "hourly",
69277
+ datasetKey: cycleTimeDatasetKey,
69278
+ showIdleTime: showChartIdleTime,
69279
+ idleTimeData: hourlyIdleMinutes
68567
69280
  }
68568
69281
  ) : /* @__PURE__ */ jsx(
68569
69282
  HourlyOutputChart2,
@@ -68610,7 +69323,8 @@ var WorkspaceDetailView = ({
68610
69323
  {
68611
69324
  workspace,
68612
69325
  legend: efficiencyLegend,
68613
- layout: "stack"
69326
+ layout: "stack",
69327
+ idleTimeData: idleTimeVlmEnabled ? idleTimeData : void 0
68614
69328
  }
68615
69329
  ) : /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(WorkspaceMetricCards, { workspace, legend: efficiencyLegend, className: "flex-1" }) })
68616
69330
  ] }),
@@ -68655,7 +69369,7 @@ var WorkspaceDetailView = ({
68655
69369
  animate: "animate",
68656
69370
  children: [
68657
69371
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3 mb-4 flex-none", children: [
68658
- /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold text-gray-700", children: isUptimeMode ? "Machine Utilization" : shouldShowCycleTimeChart ? "Cycle Time (last 60 minutes)" : "Hourly Output" }),
69372
+ /* @__PURE__ */ jsx("h3", { className: "text-lg font-bold text-gray-700", children: isUptimeMode ? "Machine Utilization" : shouldShowCycleTimeChart ? "Cycle time trend" : "Hourly Output" }),
68659
69373
  !isUptimeMode && /* @__PURE__ */ jsx(
68660
69374
  "button",
68661
69375
  {
@@ -68684,9 +69398,14 @@ var WorkspaceDetailView = ({
68684
69398
  ) : shouldShowCycleTimeChart ? /* @__PURE__ */ jsx(
68685
69399
  CycleTimeOverTimeChart,
68686
69400
  {
68687
- data: workspace.hourly_action_counts || [],
69401
+ data: cycleTimeChartData,
68688
69402
  idealCycleTime: workspace.ideal_cycle_time || 0,
68689
- shiftStart: workspace.shift_start || ""
69403
+ shiftStart: workspace.shift_start || "",
69404
+ shiftEnd: workspace.shift_end || "",
69405
+ xAxisMode: "hourly",
69406
+ datasetKey: cycleTimeDatasetKey,
69407
+ showIdleTime: showChartIdleTime,
69408
+ idleTimeData: hourlyIdleMinutes
68690
69409
  }
68691
69410
  ) : /* @__PURE__ */ jsx(
68692
69411
  HourlyOutputChart2,
@@ -68738,7 +69457,8 @@ var WorkspaceDetailView = ({
68738
69457
  workspace,
68739
69458
  legend: efficiencyLegend,
68740
69459
  layout: "grid",
68741
- className: desktopBottomSectionClass
69460
+ className: desktopBottomSectionClass,
69461
+ idleTimeData: idleTimeVlmEnabled ? idleTimeData : void 0
68742
69462
  }
68743
69463
  ) : /* @__PURE__ */ jsx("div", { className: clsx("flex min-h-0", desktopBottomSectionClass), children: /* @__PURE__ */ jsx(WorkspaceMetricCards, { workspace, legend: efficiencyLegend, className: "flex-1" }) })
68744
69464
  ] })
@@ -68768,6 +69488,7 @@ var WorkspaceDetailView = ({
68768
69488
  availableShifts: shiftConfig?.shifts?.map((s) => ({ id: s.shiftId, name: s.shiftName })),
68769
69489
  legend: efficiencyLegend,
68770
69490
  trendSummary: workspaceMonthlyTrend,
69491
+ isAssemblyWorkspace,
68771
69492
  onDateSelect: (selectedDate, shiftId) => {
68772
69493
  if (onDateSelect) {
68773
69494
  onDateSelect(selectedDate, shiftId);
@@ -74855,6 +75576,11 @@ var normalizeTrend = (value) => ({
74855
75576
  });
74856
75577
  var normalizeIdleBreakdown = (value) => (value || []).map((item) => ({
74857
75578
  reason: item?.reason?.trim() || "Unknown",
75579
+ reason_key: item?.reason_key?.trim() || item?.reason?.trim() || "unknown",
75580
+ display_name: item?.display_name?.trim() || void 0,
75581
+ palette_token: item?.palette_token?.trim() || void 0,
75582
+ icon_token: item?.icon_token?.trim() || void 0,
75583
+ is_known: typeof item?.is_known === "boolean" ? item.is_known : null,
74858
75584
  percentage: normalizeNumber(item?.percentage),
74859
75585
  total_duration_seconds: normalizeNumber(item?.total_duration_seconds),
74860
75586
  efficiency_loss_percentage: normalizeNumber(item?.efficiency_loss_percentage),
@@ -75906,7 +76632,12 @@ var IdleBreakdownCard = React141__default.memo(({
75906
76632
  const showInitialSkeleton = idle.loading && idle.lastUpdated === null;
75907
76633
  const idleBreakdown = React141__default.useMemo(() => {
75908
76634
  return idle.data.map((item) => ({
75909
- name: item.reason?.trim() || "Unknown",
76635
+ name: item.display_name?.trim() || item.reason?.trim() || "Unknown",
76636
+ reasonKey: item.reason_key?.trim() || item.reason?.trim() || "unknown",
76637
+ displayName: item.display_name?.trim() || item.reason?.trim() || "Unknown",
76638
+ paletteToken: item.palette_token?.trim(),
76639
+ iconToken: item.icon_token?.trim(),
76640
+ isKnown: item.is_known ?? void 0,
75910
76641
  value: toNumber3(item.percentage) || 0,
75911
76642
  totalDurationSeconds: toNumber3(item.total_duration_seconds),
75912
76643
  efficiencyLossPercentage: toNumber3(item.efficiency_loss_percentage),
@@ -77198,4 +77929,4 @@ var streamProxyConfig = {
77198
77929
  }
77199
77930
  };
77200
77931
 
77201
- 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 };
77932
+ export { ACTION_FAMILIES, ACTION_NAMES, AIAgentView_default as AIAgentView, AcceptInvite, AcceptInviteView_default as AcceptInviteView, AdvancedFilterDialog, AdvancedFilterPanel, AudioService, AuthCallback, AuthCallbackView_default as AuthCallbackView, AuthProvider, AuthService, AuthenticatedBottleneckClipsView, AuthenticatedFactoryView, AuthenticatedHelpView, AuthenticatedHomeView, AuthenticatedShiftsView, AuthenticatedTargetsView, AuthenticatedTicketsView, AuthenticatedWorkspaceHealthView, AvatarUpload, AxelNotificationPopup, AxelOrb, BackButton, BackButtonMinimal, BarChart, BaseHistoryCalendar, BottleneckClipsModal, BottleneckClipsView_default as BottleneckClipsView, BottlenecksContent, BreakNotificationPopup, CachePrefetchStatus, Card2 as Card, CardContent2 as CardContent, CardDescription2 as CardDescription, CardFooter2 as CardFooter, CardHeader2 as CardHeader, CardTitle2 as CardTitle, ChangeRoleDialog, ClipFilterProvider, ClipsCostView_default as ClipsCostView, CompactWorkspaceHealthCard, ConfirmRemoveUserDialog, CongratulationsOverlay, CroppedHlsVideoPlayer, CroppedVideoPlayer, CycleTimeChart, CycleTimeOverTimeChart, DEFAULT_ANALYTICS_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_CONFIG, DEFAULT_DATABASE_CONFIG, DEFAULT_DATE_TIME_CONFIG, DEFAULT_ENDPOINTS_CONFIG, DEFAULT_ENTITY_CONFIG, DEFAULT_HOME_VIEW_CONFIG, DEFAULT_MAP_VIEW_CONFIG, DEFAULT_SHIFT_CONFIG, DEFAULT_SHIFT_DATA, DEFAULT_THEME_CONFIG, DEFAULT_VIDEO_CONFIG, DEFAULT_WORKSPACE_CONFIG, DEFAULT_WORKSPACE_POSITIONS, DashboardHeader, DashboardLayout, DashboardOverridesProvider, DashboardProvider, DateDisplay_default as DateDisplay, DateTimeDisplay, DebugAuth, DebugAuthView_default as DebugAuthView, DetailedHealthStatus, DiagnosisVideoModal, EFFICIENCY_ON_TRACK_THRESHOLD, EmptyStateMessage, EncouragementOverlay, FactoryAssignmentDropdown, FactoryView_default as FactoryView, FileManagerFilters, FilterDialogTrigger, FirstTimeLoginDebug, FirstTimeLoginHandler, FittingTitle, GaugeChart, GridComponentsPlaceholder, HamburgerButton, Header, HealthDateShiftSelector, HealthStatusGrid, HealthStatusIndicator, HelpView_default as HelpView, HlsVideoPlayer, HomeView_default as HomeView, HourlyOutputChart2 as HourlyOutputChart, HourlyUptimeChart, ISTTimer_default as ISTTimer, IdleTimeVlmConfigProvider, ImprovementCenterView_default as ImprovementCenterView, InlineEditableText, InteractiveOnboardingTour, InvitationService, InvitationsTable, InviteUserDialog, KPICard, KPIDetailView_default as KPIDetailView, KPIGrid, KPIHeader, KPISection, KPIsOverviewView_default as KPIsOverviewView, LINE_1_UUID, LINE_2_UUID, LargeOutputProgressChart, LeaderboardDetailView_default as LeaderboardDetailView, Legend5 as Legend, LineAssignmentDropdown, LineChart, LineHistoryCalendar, LineMonthlyHistory, LineMonthlyPdfGenerator, LinePdfExportButton, LinePdfGenerator, LineWhatsAppShareButton, LinesService, LiveTimer, LoadingInline, LoadingOverlay_default as LoadingOverlay, LoadingPage_default as LoadingPage, LoadingSkeleton, LoadingState, LoginPage, LoginView_default as LoginView, Logo, MainLayout, MapGridView, MetricCard_default as MetricCard, MinimalOnboardingPopup, MobileMenuProvider, NewClipsNotification, NoWorkspaceData, OnboardingDemo, OnboardingTour, OptifyeAgentClient, OptifyeLogoLoader_default as OptifyeLogoLoader, OutputProgressChart, PageHeader, PieChart4 as PieChart, PlantHeadView_default as PlantHeadView, PlayPauseIndicator, PrefetchConfigurationError, PrefetchError, PrefetchEvents, PrefetchStatus, PrefetchTimeoutError, ProfileView_default as ProfileView, RegistryProvider, RoleBadge, S3ClipsSupabaseService as S3ClipsService, S3Service, SKUManagementView, SOPComplianceChart, SSEChatClient, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, SessionTracker, SessionTrackingContext, SessionTrackingProvider, SettingsPopup, ShiftDisplay_default as ShiftDisplay, ShiftsView_default as ShiftsView, SideNavBar, SignupWithInvitation, SilentErrorBoundary, SimpleOnboardingPopup, SingleVideoStream_default as SingleVideoStream, Skeleton, SubscriptionManager, SubscriptionManagerProvider, SupabaseProvider, SupervisorDropdown_default as SupervisorDropdown, SupervisorManagementView_default as SupervisorManagementView, SupervisorService, TargetWorkspaceGrid, TargetsView_default as TargetsView, TeamManagementView_default as TeamManagementView, ThreadSidebar, TicketHistory_default as TicketHistory, TicketHistoryService, TicketsView_default as TicketsView, TimeDisplay_default as TimeDisplay, TimePickerDropdown, Timer_default as Timer, TimezoneProvider, TimezoneService, UptimeDonutChart, UptimeLineChart, UptimeMetricCards, UserAvatar, UserManagementService, UserManagementTable, UserService, UserUsageDetailModal, UserUsageStats, VideoCard, VideoGridView, VideoPlayer, VideoPreloader, WORKSPACE_POSITIONS, WhatsAppShareButton, WorkspaceCard, WorkspaceCycleTimeMetricCards, WorkspaceDetailView_default as WorkspaceDetailView, WorkspaceDisplayNameExample, WorkspaceGrid, WorkspaceGridItem, WorkspaceHealthCard, WorkspaceHealthView_default as WorkspaceHealthView, WorkspaceHistoryCalendar, WorkspaceMetricCards, WorkspaceMetricCardsImpl, WorkspaceMonthlyDataFetcher, WorkspaceMonthlyHistory, WorkspaceMonthlyPdfGenerator, WorkspacePdfExportButton, WorkspacePdfGenerator, WorkspaceWhatsAppShareButton, actionService, aggregateKPIsFromLineMetricsRows, alertsService, apiUtils, areAllLinesOnSameShift, authCoreService, authOTPService, authRateLimitService, awardsService, buildDateKey, buildKPIsFromLineMetricsRow, buildShiftGroupsKey, canRoleAccessDashboardPath, canRoleAccessTeamManagement, canRoleAssignFactories, canRoleAssignLines, canRoleChangeRole, canRoleInviteRole, canRoleManageCompany, canRoleManageTargets, canRoleManageUsers, canRoleRemoveUser, canRoleViewClipsCost, canRoleViewUsageStats, captureSentryException, captureSentryMessage, checkRateLimit2 as checkRateLimit, clearAllRateLimits2 as clearAllRateLimits, clearRateLimit2 as clearRateLimit, clearS3VideoCache, clearS3VideoFromCache, clearSentryContext, clearWorkspaceDisplayNamesCache, cn, createDefaultKPIs, createInvitationService, createLinesService, createSessionTracker, createStorageService, createStreamProxyHandler, createSupabaseClient, createSupervisorService, createThrottledReload, createUserManagementService, createUserService, dashboardService, deleteThread, fetchIdleTimeReasons, filterDataByDateKeyRange, forceRefreshWorkspaceDisplayNames, formatAwardMonth, formatDateInZone, formatDateKeyForDisplay, formatDateTimeInZone, formatDuration2 as formatDuration, formatISTDate, formatIdleTime, formatRangeLabel, formatReasonLabel, formatRelativeTime, formatTimeInZone, fromUrlFriendlyName, getActionDisplayName, getAllLineDisplayNames, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAllWorkspaceDisplayNamesSnapshot, getAnonClient, getAssignableRoles, getAssignmentColumnLabel, getAvailableShiftIds, getAwardBadgeType, getAwardDescription, getAwardTitle, getBrowserName, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getConfiguredLineIds, getCoreSessionRecordingProperties, getCoreSessionReplayUrl, getCurrentShift, getCurrentShiftForLine, getCurrentTimeInZone, getCurrentWeekFullRange, getCurrentWeekToDateRange, getDashboardHeaderTimeInZone, getDateKeyFromDate, getDaysDifferenceInZone, getDefaultCameraStreamUrl, getDefaultLineId, getDefaultTabForWorkspace, getInitials, getLineDisplayName, getManufacturingInsights, getMetricsTablePrefix, getMonthKeyBounds, getMonthWeekRanges, getNextUpdateInterval, getOperationalDate, getRoleAssignmentKind, getRoleDescription, getRoleLabel, getRoleMetadata, getRoleNavPaths, getS3SignedUrl, getS3VideoSrc, getShiftData, getShiftNameById, getShiftWorkDurationSeconds, getShortShiftName, getShortWorkspaceDisplayName, getShortWorkspaceDisplayNameAsync, getStoredWorkspaceMappings, getSubscriptionManager, getThreadMessages, getUniformShiftGroup, getUserThreads, getUserThreadsPaginated, getVisibleRolesForCurrentUser, getWorkspaceDisplayName, getWorkspaceDisplayNameAsync, getWorkspaceDisplayNamesMap, getWorkspaceFromUrl, getWorkspaceNavigationParams, groupLinesByShift, hasAnyShiftData, identifyCoreUser, initializeCoreMixpanel, isEfficiencyOnTrack, isFactoryScopedRole, isFullMonthRange, isLegacyConfiguration, isPrefetchError, isRecentFlowVideoGridMetricMode, isSafari, isSupervisorRole, isTransitionPeriod, isUrlPermanentlyFailed, isValidFactoryViewConfiguration, isValidLineInfoPayload, isValidPrefetchParams, isValidPrefetchStatus, isValidWorkspaceDetailedMetricsPayload, isValidWorkspaceMetricsPayload, isWipGatedVideoGridMetricMode, isWorkspaceDisplayNamesLoaded, isWorkspaceDisplayNamesLoading, lineLeaderboardService, linesService, mergeWithDefaultConfig, migrateLegacyConfiguration, normalizeActionFamily, normalizeDateKeyRange, normalizeRoleLevel, normalizeVideoGridMetricMode, optifyeAgentClient, parseDateKeyToDate, parseS3Uri, preInitializeWorkspaceDisplayNames, preloadS3Video, preloadS3VideoUrl, preloadS3VideosUrl, preloadVideoUrl, preloadVideosUrl, qualityService, realtimeService, refreshWorkspaceDisplayNames, resetCoreMixpanel, resetFailedUrl, resetSubscriptionManager, s3VideoPreloader, setSentryUserContext, setSentryWorkspaceContext, shuffleArray, simulateApiDelay, skuService, startCoreSessionRecording, stopCoreSessionRecording, storeWorkspaceMapping, streamProxyConfig, subscribeWorkspaceDisplayNames, throttledReloadDashboard, toUrlFriendlyName, trackCoreEvent, trackCorePageView, transformToChartData, updateThreadTitle, upsertWorkspaceDisplayNameInCache, useAccessControl, useActiveBreaks, useActiveLineId, useAllWorkspaceMetrics, useAnalyticsConfig, useAppTimezone, useAudioService, useAuth, useAuthConfig, useAxelNotifications, useCanSaveTargets, useClipFilter, useClipTypes, useClipTypesWithCounts, useClipsInit, useCompanyClipsCost, useCompanyUsersUsage, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useDynamicShiftConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHasLineAccess, useHideMobileHeader, useHistoricWorkspaceMetrics, useHlsStream, useHlsStreamWithCropping, useHookOverride, useHourEndTimer, useHourlyTargetAchievements, useHourlyTargetMisses, useIdleTimeClipClassifications, useIdleTimeReasons, useIdleTimeVlmConfig, useKpiTrends, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineShiftConfig, useLineSupervisor, useLineWorkspaceMetrics, useLines, useMessages, useMetrics, useMobileMenu, useMonthlyTrend, useMultiLineShiftConfigs, useNavigation, useOperationalShiftKey, useOptionalSupabase, useOverrides, usePageOverride, usePrefetchClipCounts, useRealtimeLineMetrics, useRegistry, useSKUs, useSessionKeepAlive, useSessionTracking, useSessionTrackingContext, useShiftConfig, useShiftGroups, useShifts, useSubscriptionManager, useSubscriptionManagerSafe, useSupabase, useSupabaseClient, useSupervisorsByLineIds, useTargets, useTeamManagementPermissions, useTheme, useThemeConfig, useThreads, useTicketHistory, useTimezoneContext, useUserLineAccess, useUserUsage, useVideoConfig, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceHealthById, useWorkspaceHealthLastSeen, useWorkspaceHealthStatus, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, useWorkspaceUptimeTimeline, useWorkspaceVideoStreams, userService, videoPrefetchManager, videoPreloader, weeklyTopPerformerService, whatsappService, withAccessControl, withAuth, withRegistry, withTimezone, workspaceHealthService, workspaceService };