@optifye/dashboard-core 6.11.12 → 6.11.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -10,8 +10,8 @@ import { EventEmitter } from 'events';
10
10
  import { createClient, REALTIME_SUBSCRIBE_STATES } from '@supabase/supabase-js';
11
11
  import Hls, { Events, ErrorTypes } from 'hls.js';
12
12
  import useSWR from 'swr';
13
+ import { Camera, AlertTriangle, ChevronDown, ChevronUp, Check, Map as Map$1, Video, ShieldCheck, Star, Award, Filter, X, Coffee, Plus, ArrowUp, ArrowDown, ArrowRight, ArrowLeft, Clock, Calendar, Save, AlertCircle, Loader2, Minus, ChevronLeft, ChevronRight, TrendingUp, Sparkles, Pause, Play, XCircle, HelpCircle, Activity, Wrench, UserX, Package, RefreshCw, Palette, CheckCircle2, TrendingDown, FolderOpen, Folder, Tag, Sliders, Layers, Search, Edit2, CheckCircle, User, Users, Shield, Building2, Mail, Lock, Info, Share2, Trophy, Target, Download, Sun, Moon, MousePointer, UserPlus, UserCog, Trash2, Eye, MoreVertical, BarChart3, Pencil, UserCheck, LogOut, Film, MessageSquare, Menu, Send, Copy, Settings, LifeBuoy, EyeOff, Zap, Flame, Crown, Medal } from 'lucide-react';
13
14
  import { memo, noop, warning, invariant, progress, secondsToMilliseconds, millisecondsToSeconds } from 'motion-utils';
14
- import { Camera, AlertTriangle, ChevronDown, ChevronUp, Check, Map as Map$1, Video, ShieldCheck, Star, Award, Filter, X, Coffee, Plus, ArrowUp, ArrowDown, ArrowRight, ArrowLeft, Clock, Calendar, Save, AlertCircle, Loader2, Minus, ChevronLeft, ChevronRight, TrendingUp, Sparkles, Pause, Play, Wrench, XCircle, Package, UserX, Zap, HelpCircle, Tag, Palette, CheckCircle2, RefreshCw, TrendingDown, FolderOpen, Folder, Sliders, Activity, Layers, Search, Edit2, CheckCircle, User, Users, Shield, Building2, Mail, Lock, Info, Share2, Trophy, Target, Download, Sun, Moon, MousePointer, UserPlus, UserCog, Trash2, Eye, MoreVertical, BarChart3, Pencil, UserCheck, LogOut, Film, MessageSquare, Menu, Send, Copy, Settings, LifeBuoy, EyeOff, Flame, Crown, Medal } from 'lucide-react';
15
15
  import { BarChart as BarChart$1, CartesianGrid, XAxis, YAxis, ReferenceLine, Tooltip, Legend, Bar, LabelList, ResponsiveContainer, LineChart as LineChart$1, Line, PieChart, Pie, Cell, ComposedChart, Area, ScatterChart, Scatter } from 'recharts';
16
16
  import { Slot } from '@radix-ui/react-slot';
17
17
  import * as SelectPrimitive from '@radix-ui/react-select';
@@ -3417,6 +3417,25 @@ function isValidFactoryViewConfiguration(entityConfig) {
3417
3417
  return lineIds.length > 0;
3418
3418
  }
3419
3419
 
3420
+ // src/lib/constants/videoGridMetricMode.ts
3421
+ var VALID_VIDEO_GRID_METRIC_MODES = /* @__PURE__ */ new Set([
3422
+ "efficiency",
3423
+ "recent_flow",
3424
+ "recent_flow_wip_gated"
3425
+ ]);
3426
+ var normalizeVideoGridMetricMode = (value, assemblyEnabled = false) => {
3427
+ const normalized = typeof value === "string" ? value.trim().toLowerCase() : "";
3428
+ if (VALID_VIDEO_GRID_METRIC_MODES.has(normalized)) {
3429
+ return normalized;
3430
+ }
3431
+ return assemblyEnabled ? "recent_flow_wip_gated" : "efficiency";
3432
+ };
3433
+ var isRecentFlowVideoGridMetricMode = (value, assemblyEnabled = false) => {
3434
+ const normalized = normalizeVideoGridMetricMode(value, assemblyEnabled);
3435
+ return normalized === "recent_flow" || normalized === "recent_flow_wip_gated";
3436
+ };
3437
+ var isWipGatedVideoGridMetricMode = (value, assemblyEnabled = false) => normalizeVideoGridMetricMode(value, assemblyEnabled) === "recent_flow_wip_gated";
3438
+
3420
3439
  // src/lib/services/lineMetricsSelection.ts
3421
3440
  var toTimestamp = (value) => {
3422
3441
  if (typeof value !== "string") return 0;
@@ -3878,7 +3897,7 @@ var dashboardService = {
3878
3897
  company_name: data.company_name || "Company X",
3879
3898
  date: data.date,
3880
3899
  shift_id: data.shift_id,
3881
- action_name: data.action_name || "",
3900
+ action_name: data.action_display_name || data.action_name || "",
3882
3901
  shift_start: data.shift_start || (data.shift_id === (shiftConfig.dayShift?.id ?? 0) ? shiftConfig.dayShift?.startTime : shiftConfig.nightShift?.startTime) || "00:00",
3883
3902
  shift_end: data.shift_end || (data.shift_id === (shiftConfig.dayShift?.id ?? 0) ? shiftConfig.dayShift?.endTime : shiftConfig.nightShift?.endTime) || "00:00",
3884
3903
  shift_type: data.shift_type || (data.shift_id === (shiftConfig.dayShift?.id ?? 0) ? "Day" : "Night"),
@@ -3947,7 +3966,9 @@ var dashboardService = {
3947
3966
  company_id,
3948
3967
  companies!lines_company_id_fkey(company_name:name),
3949
3968
  enable,
3950
- monitoring_mode
3969
+ monitoring_mode,
3970
+ assembly,
3971
+ video_grid_metric_mode
3951
3972
  `).eq("enable", true);
3952
3973
  if (companyId) {
3953
3974
  query = query.eq("company_id", companyId);
@@ -3967,7 +3988,12 @@ var dashboardService = {
3967
3988
  company_name: line.companies?.company_name ?? "N/A",
3968
3989
  enable: line.enable ?? true,
3969
3990
  // Default to true if not specified
3970
- monitoring_mode: line.monitoring_mode ?? "output"
3991
+ monitoring_mode: line.monitoring_mode ?? "output",
3992
+ assembly: line.assembly ?? false,
3993
+ video_grid_metric_mode: normalizeVideoGridMetricMode(
3994
+ line.video_grid_metric_mode,
3995
+ line.assembly ?? false
3996
+ )
3971
3997
  }));
3972
3998
  return transformedLines;
3973
3999
  } catch (err) {
@@ -4004,7 +4030,7 @@ var dashboardService = {
4004
4030
  }
4005
4031
  const lineIdsToQuery = configuredLineIds;
4006
4032
  const [line1Result, metricsResult2] = await Promise.all([
4007
- supabase.from(linesTable).select("id, line_name, factory_id, monitoring_mode, factories!lines_factory_id_fkey(factory_name), company_id, companies!lines_company_id_fkey(company_name:name)").eq("id", defaultLineId).single(),
4033
+ supabase.from(linesTable).select("id, line_name, factory_id, monitoring_mode, assembly, video_grid_metric_mode, factories!lines_factory_id_fkey(factory_name), company_id, companies!lines_company_id_fkey(company_name:name)").eq("id", defaultLineId).single(),
4008
4034
  supabase.from(lineMetricsTable).select("*").in("line_id", lineIdsToQuery).eq("shift_id", queryShiftId).eq("date", queryDate)
4009
4035
  ]);
4010
4036
  if (line1Result.error) throw line1Result.error;
@@ -4083,7 +4109,7 @@ var dashboardService = {
4083
4109
  throw new Error("Company ID must be configured for detailed line requests.");
4084
4110
  }
4085
4111
  const [lineResult, metricsResult] = await Promise.all([
4086
- supabase.from(linesTable).select("id, line_name, factory_id, monitoring_mode, factories!lines_factory_id_fkey(factory_name), company_id, companies!lines_company_id_fkey(company_name:name)").eq("id", lineIdToQuery).single(),
4112
+ supabase.from(linesTable).select("id, line_name, factory_id, monitoring_mode, assembly, video_grid_metric_mode, factories!lines_factory_id_fkey(factory_name), company_id, companies!lines_company_id_fkey(company_name:name)").eq("id", lineIdToQuery).single(),
4087
4113
  supabase.from(lineMetricsTable).select("*").eq("line_id", lineIdToQuery).eq("shift_id", queryShiftId).eq("date", queryDate)
4088
4114
  ]);
4089
4115
  if (lineResult.error) throw lineResult.error;
@@ -4899,25 +4925,25 @@ var workspaceService = {
4899
4925
  if (!configuredFactoryId) {
4900
4926
  throw new Error("Factory ID (entityConfig.factoryId) must be configured to update line thresholds.");
4901
4927
  }
4902
- let outputWorkspaces = workspaces.filter((ws) => ws.action_type === "packaging");
4928
+ let outputWorkspaces = workspaces.filter((ws) => ws.action_type === "output");
4903
4929
  if (outputWorkspaces.length === 0) {
4904
- const packagingKeywords = ["packaging", "package", "packing", "pack"];
4905
- const possiblePackagingWorkspaces = workspaces.filter((ws) => {
4930
+ const outputKeywords = ["output", "packaging", "package", "packing", "pack"];
4931
+ const possibleOutputWorkspaces = workspaces.filter((ws) => {
4906
4932
  if (ws.workspace_id && typeof ws.workspace_id === "string") {
4907
4933
  const wsIdLower = ws.workspace_id.toLowerCase();
4908
- return packagingKeywords.some((keyword) => wsIdLower.includes(keyword));
4934
+ return outputKeywords.some((keyword) => wsIdLower.includes(keyword));
4909
4935
  }
4910
4936
  return false;
4911
4937
  });
4912
- if (possiblePackagingWorkspaces.length > 0) {
4913
- outputWorkspaces = possiblePackagingWorkspaces;
4938
+ if (possibleOutputWorkspaces.length > 0) {
4939
+ outputWorkspaces = possibleOutputWorkspaces;
4914
4940
  } else {
4915
- console.warn("[WorkspaceService] Unable to determine packaging workspaces for threshold calculation. Using all workspaces.");
4941
+ console.warn("[WorkspaceService] Unable to determine output-family workspaces for threshold calculation. Using all workspaces.");
4916
4942
  outputWorkspaces = workspaces;
4917
4943
  }
4918
4944
  }
4919
4945
  if (outputWorkspaces.length === 0 && workspaces.length > 0) {
4920
- console.warn('[WorkspaceService] No workspaces with action_type "packaging" found for line threshold calculation. Thresholds might be zero.');
4946
+ console.warn('[WorkspaceService] No workspaces with action_type "output" found for line threshold calculation. Thresholds might be zero.');
4921
4947
  }
4922
4948
  const totalDayOutput = outputWorkspaces.reduce((sum, ws) => sum + (ws.action_total_day_output || 0), 0);
4923
4949
  const totalPPH = outputWorkspaces.reduce((sum, ws) => sum + (ws.action_pph_threshold || 0), 0);
@@ -8437,7 +8463,11 @@ var LinesService = class {
8437
8463
  createdAt: line.created_at,
8438
8464
  factoryId: line.factory_id,
8439
8465
  monitoringMode: line.monitoring_mode ?? "output",
8440
- assembly: line.assembly ?? false
8466
+ assembly: line.assembly ?? false,
8467
+ videoGridMetricMode: normalizeVideoGridMetricMode(
8468
+ line.video_grid_metric_mode,
8469
+ line.assembly ?? false
8470
+ )
8441
8471
  }));
8442
8472
  } catch (error) {
8443
8473
  console.error("Error fetching lines:", error);
@@ -8481,7 +8511,11 @@ var LinesService = class {
8481
8511
  createdAt: line.created_at,
8482
8512
  factoryId: line.factory_id,
8483
8513
  monitoringMode: line.monitoring_mode ?? "output",
8484
- assembly: line.assembly ?? false
8514
+ assembly: line.assembly ?? false,
8515
+ videoGridMetricMode: normalizeVideoGridMetricMode(
8516
+ line.video_grid_metric_mode,
8517
+ line.assembly ?? false
8518
+ )
8485
8519
  }));
8486
8520
  } catch (error) {
8487
8521
  console.error("Error fetching all lines:", error);
@@ -8533,7 +8567,12 @@ var LinesService = class {
8533
8567
  isActive: data.enable,
8534
8568
  createdAt: data.created_at,
8535
8569
  factoryId: data.factory_id,
8536
- monitoringMode: data.monitoring_mode ?? "output"
8570
+ monitoringMode: data.monitoring_mode ?? "output",
8571
+ assembly: data.assembly ?? false,
8572
+ videoGridMetricMode: normalizeVideoGridMetricMode(
8573
+ data.video_grid_metric_mode,
8574
+ data.assembly ?? false
8575
+ )
8537
8576
  };
8538
8577
  } catch (error) {
8539
8578
  console.error("Error fetching line:", error);
@@ -9674,78 +9713,6 @@ var createStorageService = (supabase) => ({
9674
9713
  }
9675
9714
  });
9676
9715
 
9677
- // src/lib/constants/idleTimeColors.ts
9678
- var IDLE_TIME_REASON_COLORS = {
9679
- "Operator Absent": {
9680
- hex: "#dc2626",
9681
- // red-600 - Critical/Urgent
9682
- text: "text-red-600",
9683
- bg: "bg-red-50",
9684
- border: "border-red-200"
9685
- },
9686
- "No Material": {
9687
- hex: "#f59e0b",
9688
- // amber-500 - Warning/Supply Chain
9689
- text: "text-amber-600",
9690
- bg: "bg-amber-50",
9691
- border: "border-amber-200"
9692
- },
9693
- "Machine Downtime": {
9694
- hex: "#3b82f6",
9695
- // blue-500 - Scheduled/Technical
9696
- text: "text-blue-600",
9697
- bg: "bg-blue-50",
9698
- border: "border-blue-200"
9699
- },
9700
- "Operator Idle": {
9701
- hex: "#8b5cf6",
9702
- // violet-500 - Low Priority/Behavioral
9703
- text: "text-violet-600",
9704
- bg: "bg-violet-50",
9705
- border: "border-violet-200"
9706
- }
9707
- };
9708
- var FALLBACK_HEX_COLORS = [
9709
- "#dc2626",
9710
- // red-600
9711
- "#ea580c",
9712
- // orange-600
9713
- "#ca8a04",
9714
- // yellow-600
9715
- "#16a34a",
9716
- // green-600
9717
- "#0891b2",
9718
- // cyan-600
9719
- "#2563eb",
9720
- // blue-600
9721
- "#7c3aed",
9722
- // violet-600
9723
- "#c026d3"
9724
- // fuchsia-600
9725
- ];
9726
- var DEFAULT_CONFIG3 = {
9727
- hex: "#9ca3af",
9728
- text: "text-gray-500",
9729
- bg: "bg-gray-50",
9730
- border: "border-gray-200"
9731
- };
9732
- function getIdleTimeReasonColor(reason, index = 0) {
9733
- const normalizedReason = reason.includes("_") ? reason.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ") : reason;
9734
- if (IDLE_TIME_REASON_COLORS[normalizedReason]) {
9735
- return IDLE_TIME_REASON_COLORS[normalizedReason];
9736
- }
9737
- const lowerReason = normalizedReason.toLowerCase();
9738
- const foundKey = Object.keys(IDLE_TIME_REASON_COLORS).find((k) => k.toLowerCase() === lowerReason);
9739
- if (foundKey) {
9740
- return IDLE_TIME_REASON_COLORS[foundKey];
9741
- }
9742
- const fallbackHex = FALLBACK_HEX_COLORS[index % FALLBACK_HEX_COLORS.length];
9743
- return {
9744
- ...DEFAULT_CONFIG3,
9745
- hex: fallbackHex
9746
- };
9747
- }
9748
-
9749
9716
  // src/lib/services/idleTimeReasonService.ts
9750
9717
  async function fetchIdleTimeReasons(params) {
9751
9718
  const { workspaceId, lineId, date, shiftId, startDate, endDate, token } = params;
@@ -9803,7 +9770,12 @@ async function fetchIdleTimeReasons(params) {
9803
9770
  }
9804
9771
  function transformToChartData(data) {
9805
9772
  return data.reasons.map((reason) => ({
9806
- name: formatReasonLabel(reason.reason),
9773
+ name: reason.display_name || formatReasonLabel(reason.reason_key || reason.reason),
9774
+ reasonKey: reason.reason_key || reason.reason,
9775
+ displayName: reason.display_name || formatReasonLabel(reason.reason_key || reason.reason),
9776
+ paletteToken: reason.palette_token,
9777
+ iconToken: reason.icon_token,
9778
+ isKnown: reason.is_known,
9807
9779
  value: reason.percentage,
9808
9780
  totalDurationSeconds: reason.total_duration_seconds,
9809
9781
  efficiencyLossPercentage: reason.efficiency_loss_percentage ?? null
@@ -9812,9 +9784,6 @@ function transformToChartData(data) {
9812
9784
  function formatReasonLabel(reason) {
9813
9785
  return reason.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
9814
9786
  }
9815
- function getReasonColor(reason, index = 0) {
9816
- return getIdleTimeReasonColor(reason, index).hex;
9817
- }
9818
9787
 
9819
9788
  // src/lib/services/sessionTracker.ts
9820
9789
  function generateSessionId() {
@@ -11537,6 +11506,52 @@ var workspaceMetricsStore = {
11537
11506
  }
11538
11507
  };
11539
11508
 
11509
+ // src/lib/constants/actions.ts
11510
+ var ACTION_NAMES = {
11511
+ /** Assembly operations */
11512
+ ASSEMBLY: "Assembly",
11513
+ /** Packaging operations */
11514
+ PACKAGING: "Packaging",
11515
+ /** Output operations (user-facing label for the legacy packaging family) */
11516
+ OUTPUT: "Output",
11517
+ /** Inspection operations */
11518
+ INSPECTION: "Inspection",
11519
+ /** Testing operations */
11520
+ TESTING: "Testing",
11521
+ /** Quality control operations */
11522
+ QUALITY_CONTROL: "Quality Control"
11523
+ };
11524
+ var ACTION_FAMILIES = {
11525
+ ASSEMBLY: "assembly",
11526
+ OUTPUT: "output",
11527
+ OTHER: "other"
11528
+ };
11529
+ var normalizeActionFamily = (params) => {
11530
+ const explicitValue = (params.actionFamily ?? params.actionType ?? "").trim().toLowerCase();
11531
+ if (explicitValue === ACTION_FAMILIES.ASSEMBLY) return ACTION_FAMILIES.ASSEMBLY;
11532
+ if (explicitValue === ACTION_FAMILIES.OUTPUT || explicitValue === "packaging") {
11533
+ return ACTION_FAMILIES.OUTPUT;
11534
+ }
11535
+ if (explicitValue === ACTION_FAMILIES.OTHER) return ACTION_FAMILIES.OTHER;
11536
+ const normalizedName = (params.actionName ?? "").trim().toLowerCase();
11537
+ if (!normalizedName) return null;
11538
+ if (normalizedName === "output" || normalizedName.includes("packag")) {
11539
+ return ACTION_FAMILIES.OUTPUT;
11540
+ }
11541
+ if (normalizedName.includes("assembly")) {
11542
+ return ACTION_FAMILIES.ASSEMBLY;
11543
+ }
11544
+ return ACTION_FAMILIES.OTHER;
11545
+ };
11546
+ var getActionDisplayName = (params) => {
11547
+ const explicitDisplayName = (params.displayName ?? "").trim();
11548
+ if (explicitDisplayName) return explicitDisplayName;
11549
+ const family = normalizeActionFamily(params);
11550
+ if (family === ACTION_FAMILIES.OUTPUT) return ACTION_NAMES.OUTPUT;
11551
+ if (family === ACTION_FAMILIES.ASSEMBLY) return ACTION_NAMES.ASSEMBLY;
11552
+ return (params.actionName ?? "").trim();
11553
+ };
11554
+
11540
11555
  // src/lib/utils/workspaceMetricsTransform.ts
11541
11556
  var coerceNumber = (value, fallback = 0) => {
11542
11557
  const num = typeof value === "number" ? value : Number(value);
@@ -11726,10 +11741,17 @@ var toWorkspaceDetailedMetrics = ({
11726
11741
  const targetOutput = coerceNumber(data.target_output ?? data.total_day_output, 0);
11727
11742
  const idealOutput = coerceNumber(data.ideal_output ?? data.ideal_output_until_now, 0);
11728
11743
  const outputDifference = totalActions - idealOutput;
11744
+ const hourlyCycleTimes = Array.isArray(data.hourly_cycle_times) ? data.hourly_cycle_times.map((value) => coerceNumber(value, 0)) : [];
11729
11745
  const totalWorkspacesValue = coerceNumber(
11730
11746
  data.total_workspaces ?? lineMetricsById?.[data.line_id || ""]?.total_workspaces ?? workspaceConfig.totalWorkspaces,
11731
11747
  0
11732
11748
  );
11749
+ const actionFamily = normalizeActionFamily({
11750
+ actionFamily: data.action_family,
11751
+ actionType: data.action_type,
11752
+ actionName: data.action_name
11753
+ });
11754
+ const actionType = actionFamily === "assembly" || actionFamily === "output" ? actionFamily : null;
11733
11755
  return {
11734
11756
  workspace_id: data.workspace_id,
11735
11757
  workspace_name: data.workspace_name,
@@ -11740,8 +11762,20 @@ var toWorkspaceDetailedMetrics = ({
11740
11762
  company_name: data.company_name || "",
11741
11763
  date: data.date,
11742
11764
  shift_id: shiftId,
11743
- action_name: data.action_name || "",
11744
- action_type: data.action_type === "assembly" || data.action_type === "packaging" ? data.action_type : null,
11765
+ action_name: getActionDisplayName({
11766
+ displayName: data.action_display_name,
11767
+ actionFamily: data.action_family,
11768
+ actionType: data.action_type,
11769
+ actionName: data.action_name
11770
+ }),
11771
+ action_type: actionType,
11772
+ action_family: actionFamily,
11773
+ action_display_name: getActionDisplayName({
11774
+ displayName: data.action_display_name,
11775
+ actionFamily: data.action_family,
11776
+ actionType: data.action_type,
11777
+ actionName: data.action_name
11778
+ }),
11745
11779
  shift_start: shiftStart,
11746
11780
  shift_end: shiftEnd,
11747
11781
  shift_type: shiftType,
@@ -11754,6 +11788,7 @@ var toWorkspaceDetailedMetrics = ({
11754
11788
  avg_efficiency: coerceNumber(data.efficiency ?? data.avg_efficiency, 0),
11755
11789
  total_actions: totalActions,
11756
11790
  hourly_action_counts: hourlyActionCounts,
11791
+ hourly_cycle_times: hourlyCycleTimes,
11757
11792
  workspace_rank: coerceNumber(data.workspace_rank, 0),
11758
11793
  total_workspaces: totalWorkspacesValue,
11759
11794
  ideal_output_until_now: idealOutput,
@@ -13292,6 +13327,12 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
13292
13327
  const transformedWorkspaceData = allWorkspaceMetrics.map((item) => {
13293
13328
  const idleTimeValue = typeof item.idle_time === "number" ? item.idle_time : Number(item.idle_time);
13294
13329
  const idleTimeSeconds = Number.isFinite(idleTimeValue) ? idleTimeValue : void 0;
13330
+ const actionFamily = normalizeActionFamily({
13331
+ actionFamily: item.action_family,
13332
+ actionType: item.action_type,
13333
+ actionName: item.action_name
13334
+ });
13335
+ const actionType = actionFamily === "assembly" || actionFamily === "output" ? actionFamily : null;
13295
13336
  return {
13296
13337
  company_id: item.company_id || companyId,
13297
13338
  line_id: item.line_id,
@@ -13311,7 +13352,18 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
13311
13352
  monitoring_mode: item.monitoring_mode ?? void 0,
13312
13353
  idle_time: idleTimeSeconds,
13313
13354
  assembly_enabled: item.assembly_enabled ?? false,
13314
- action_type: item.action_type === "assembly" || item.action_type === "packaging" ? item.action_type : null,
13355
+ video_grid_metric_mode: normalizeVideoGridMetricMode(
13356
+ item.video_grid_metric_mode,
13357
+ item.assembly_enabled ?? false
13358
+ ),
13359
+ action_type: actionType,
13360
+ action_family: actionFamily,
13361
+ action_display_name: getActionDisplayName({
13362
+ displayName: item.action_display_name,
13363
+ actionFamily: item.action_family,
13364
+ actionType: item.action_type,
13365
+ actionName: item.action_name
13366
+ }),
13315
13367
  recent_flow_mode: item.recent_flow_mode ?? void 0,
13316
13368
  recent_flow_percent: item.recent_flow_percent ?? null,
13317
13369
  recent_flow_actual_rate_pph: item.recent_flow_actual_rate_pph ?? null,
@@ -19231,8 +19283,115 @@ function useIdleTimeReasons({
19231
19283
  refetch: fetchData
19232
19284
  };
19233
19285
  }
19286
+ var DEFAULT_PALETTE_TOKEN = "slate";
19287
+ var DEFAULT_ICON_TOKEN = "help-circle";
19288
+ var PALETTE_CONFIG = {
19289
+ red: {
19290
+ hex: "#dc2626",
19291
+ textClass: "text-red-600",
19292
+ bgClass: "bg-red-50",
19293
+ borderClass: "border-red-200"
19294
+ },
19295
+ amber: {
19296
+ hex: "#f59e0b",
19297
+ textClass: "text-amber-600",
19298
+ bgClass: "bg-amber-50",
19299
+ borderClass: "border-amber-200"
19300
+ },
19301
+ blue: {
19302
+ hex: "#3b82f6",
19303
+ textClass: "text-blue-600",
19304
+ bgClass: "bg-blue-50",
19305
+ borderClass: "border-blue-200"
19306
+ },
19307
+ violet: {
19308
+ hex: "#8b5cf6",
19309
+ textClass: "text-violet-600",
19310
+ bgClass: "bg-violet-50",
19311
+ borderClass: "border-violet-200"
19312
+ },
19313
+ emerald: {
19314
+ hex: "#10b981",
19315
+ textClass: "text-emerald-600",
19316
+ bgClass: "bg-emerald-50",
19317
+ borderClass: "border-emerald-200"
19318
+ },
19319
+ cyan: {
19320
+ hex: "#0891b2",
19321
+ textClass: "text-cyan-600",
19322
+ bgClass: "bg-cyan-50",
19323
+ borderClass: "border-cyan-200"
19324
+ },
19325
+ slate: {
19326
+ hex: "#64748b",
19327
+ textClass: "text-slate-600",
19328
+ bgClass: "bg-slate-50",
19329
+ borderClass: "border-slate-200"
19330
+ }
19331
+ };
19332
+ var ICON_CONFIG = {
19333
+ "alert-triangle": AlertTriangle,
19334
+ "refresh-cw": RefreshCw,
19335
+ package: Package,
19336
+ clock: Clock,
19337
+ "user-x": UserX,
19338
+ wrench: Wrench,
19339
+ activity: Activity,
19340
+ "help-circle": HelpCircle
19341
+ };
19342
+ var humanizeIdleReasonLabel = (value) => {
19343
+ const text = String(value || "").trim();
19344
+ if (!text) {
19345
+ return "Unknown";
19346
+ }
19347
+ return text.replace(/_/g, " ").split(/\s+/).filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
19348
+ };
19349
+ var normalizePaletteToken = (value) => {
19350
+ const token = String(value || "").trim().toLowerCase();
19351
+ if (token in PALETTE_CONFIG) {
19352
+ return token;
19353
+ }
19354
+ return DEFAULT_PALETTE_TOKEN;
19355
+ };
19356
+ var normalizeIconToken = (value) => {
19357
+ const token = String(value || "").trim().toLowerCase();
19358
+ if (token in ICON_CONFIG) {
19359
+ return token;
19360
+ }
19361
+ return DEFAULT_ICON_TOKEN;
19362
+ };
19363
+ var getIdleReasonPresentation = (metadata) => {
19364
+ const label = typeof metadata?.label === "string" && metadata.label.trim() ? metadata.label.trim() : null;
19365
+ const displayName = typeof metadata?.displayName === "string" && metadata.displayName.trim() ? metadata.displayName.trim() : humanizeIdleReasonLabel(label);
19366
+ const paletteToken = normalizePaletteToken(metadata?.paletteToken);
19367
+ const iconToken = normalizeIconToken(metadata?.iconToken);
19368
+ return {
19369
+ label,
19370
+ displayName,
19371
+ paletteToken,
19372
+ iconToken,
19373
+ isKnown: Boolean(metadata?.isKnown),
19374
+ Icon: ICON_CONFIG[iconToken],
19375
+ ...PALETTE_CONFIG[paletteToken]
19376
+ };
19377
+ };
19378
+ var getIdleReasonHexColor = (metadata) => getIdleReasonPresentation(metadata).hex;
19234
19379
 
19235
19380
  // src/lib/services/clipClassificationService.ts
19381
+ var normalizeClassification = (value) => {
19382
+ const rawLabel = typeof value?.label === "string" ? value.label.trim() : "";
19383
+ const label = rawLabel || void 0;
19384
+ const parsedConfidence = typeof value?.confidence === "number" ? value.confidence : typeof value?.confidence === "string" ? Number(value.confidence) : void 0;
19385
+ return {
19386
+ status: value?.status === "classified" ? "classified" : "processing",
19387
+ label,
19388
+ displayName: typeof value?.display_name === "string" ? value.display_name : label ? humanizeIdleReasonLabel(label) : void 0,
19389
+ paletteToken: typeof value?.palette_token === "string" ? value.palette_token : void 0,
19390
+ iconToken: typeof value?.icon_token === "string" ? value.icon_token : void 0,
19391
+ isKnown: typeof value?.is_known === "boolean" ? value.is_known : void 0,
19392
+ confidence: parsedConfidence !== void 0 && Number.isFinite(parsedConfidence) ? parsedConfidence : void 0
19393
+ };
19394
+ };
19236
19395
  function parseCleanLabel(rawLabel) {
19237
19396
  if (!rawLabel) return null;
19238
19397
  const patterns = [
@@ -19286,7 +19445,13 @@ async function fetchClassifications(clipIds, token) {
19286
19445
  );
19287
19446
  }
19288
19447
  const data = await response.json();
19289
- return data.classifications || {};
19448
+ const rawClassifications = data.classifications || {};
19449
+ return Object.fromEntries(
19450
+ Object.entries(rawClassifications).map(([clipId, classification]) => [
19451
+ clipId,
19452
+ normalizeClassification(classification)
19453
+ ])
19454
+ );
19290
19455
  } catch (error) {
19291
19456
  console.error("Error fetching chunk:", error);
19292
19457
  return Object.fromEntries(
@@ -19327,21 +19492,30 @@ function useClassificationRealtimeUpdates({
19327
19492
  },
19328
19493
  (payload) => {
19329
19494
  console.log("[useClassificationRealtimeUpdates] New classification:", payload);
19330
- try {
19331
- const { clip_id, clip_label, confidence_score } = payload.new;
19332
- const parsedLabel = parseCleanLabel(clip_label);
19333
- if (parsedLabel) {
19334
- onClassificationUpdate(clip_id, {
19335
- status: "classified",
19336
- label: parsedLabel,
19337
- confidence: confidence_score || 0
19338
- });
19339
- } else {
19340
- console.warn("[useClassificationRealtimeUpdates] Failed to parse label:", clip_label);
19495
+ void (async () => {
19496
+ try {
19497
+ const { clip_id, clip_label, confidence_score } = payload.new;
19498
+ const token = await getAccessTokenOrRedirect(supabase, { redirectReason: "session_expired" });
19499
+ const fetched = await fetchClassifications([clip_id], token);
19500
+ const classification = fetched[clip_id];
19501
+ if (classification) {
19502
+ onClassificationUpdate(clip_id, classification);
19503
+ return;
19504
+ }
19505
+ const parsedLabel = parseCleanLabel(clip_label);
19506
+ if (parsedLabel) {
19507
+ onClassificationUpdate(clip_id, {
19508
+ status: "classified",
19509
+ label: parsedLabel,
19510
+ confidence: confidence_score || 0
19511
+ });
19512
+ } else {
19513
+ console.warn("[useClassificationRealtimeUpdates] Failed to parse label:", clip_label);
19514
+ }
19515
+ } catch (error) {
19516
+ console.error("[useClassificationRealtimeUpdates] Error processing update:", error);
19341
19517
  }
19342
- } catch (error) {
19343
- console.error("[useClassificationRealtimeUpdates] Error processing update:", error);
19344
- }
19518
+ })();
19345
19519
  }
19346
19520
  ).subscribe((status) => {
19347
19521
  console.log(`[useClassificationRealtimeUpdates] Subscription status:`, status);
@@ -32373,90 +32547,99 @@ var CycleTimeOverTimeChart = ({
32373
32547
  data,
32374
32548
  idealCycleTime,
32375
32549
  shiftStart,
32376
- className = ""
32550
+ shiftEnd,
32551
+ xAxisMode = "recent",
32552
+ datasetKey,
32553
+ className = "",
32554
+ showIdleTime = false,
32555
+ idleTimeData = []
32377
32556
  }) => {
32378
32557
  const MAX_DATA_POINTS = 40;
32379
32558
  const containerRef = React141__default.useRef(null);
32380
32559
  const [containerReady, setContainerReady] = React141__default.useState(false);
32381
- const getHourFromTimeString = (timeStr) => {
32382
- const [hours, minutes] = timeStr.split(":");
32383
- return parseInt(hours);
32560
+ const parseTimeToMinutes3 = (value) => {
32561
+ const [hours, minutes] = value.split(":").map(Number);
32562
+ if (!Number.isFinite(hours) || !Number.isFinite(minutes)) return 0;
32563
+ return hours * 60 + minutes;
32384
32564
  };
32385
- getHourFromTimeString(shiftStart);
32386
- const getDisplayData = (rawData) => {
32387
- return rawData.slice(Math.max(0, rawData.length - MAX_DATA_POINTS));
32565
+ const formatHourLabel = (slotIndex) => {
32566
+ const baseMinutes = parseTimeToMinutes3(shiftStart);
32567
+ const absoluteMinutes = baseMinutes + slotIndex * 60;
32568
+ const hour24 = Math.floor(absoluteMinutes % (24 * 60) / 60);
32569
+ const ampm = hour24 >= 12 ? "PM" : "AM";
32570
+ const hour12 = hour24 % 12 || 12;
32571
+ return `${hour12}${ampm}`;
32572
+ };
32573
+ const formatHourRangeLabel = (slotIndex) => {
32574
+ const startLabel = formatHourLabel(slotIndex);
32575
+ const endLabel = shiftEnd && slotIndex === DURATION - 1 ? formatHourLabel(slotIndex + 1) : formatHourLabel(slotIndex + 1);
32576
+ return `${startLabel} - ${endLabel}`;
32388
32577
  };
32578
+ const getDisplayData = React141__default.useCallback((rawData) => {
32579
+ if (xAxisMode === "hourly") return rawData;
32580
+ return rawData.slice(Math.max(0, rawData.length - MAX_DATA_POINTS));
32581
+ }, [xAxisMode]);
32389
32582
  const displayData = getDisplayData(data);
32390
32583
  const DURATION = displayData.length;
32391
- const [animatedData, setAnimatedData] = React141__default.useState(Array(DURATION).fill(0));
32392
- const prevDataRef = React141__default.useRef(Array(DURATION).fill(0));
32393
- const animationFrameRef = React141__default.useRef(null);
32394
- const animateToNewData = React141__default.useCallback((targetData) => {
32395
- const startData = [...prevDataRef.current];
32396
- const startTime = performance.now();
32397
- const duration = 1200;
32398
- const animate = (currentTime) => {
32399
- const elapsed = currentTime - startTime;
32400
- const progress7 = Math.min(elapsed / duration, 1);
32401
- const easeOutQuint = (t) => 1 - Math.pow(1 - t, 5);
32402
- const easedProgress = easeOutQuint(progress7);
32403
- const newData = startData.map((start, index) => {
32404
- const target = targetData[index] || 0;
32405
- const change = target - start;
32406
- const scaleFactor = Math.min(1, 50 / Math.abs(change || 1));
32407
- const adjustedEasing = progress7 * (scaleFactor + (1 - scaleFactor) * easedProgress);
32408
- return start + change * adjustedEasing;
32409
- });
32410
- setAnimatedData(newData);
32411
- prevDataRef.current = newData;
32412
- if (progress7 < 1) {
32413
- animationFrameRef.current = requestAnimationFrame(animate);
32414
- } else {
32415
- setAnimatedData(targetData);
32416
- prevDataRef.current = targetData;
32417
- }
32418
- };
32419
- if (animationFrameRef.current) {
32420
- cancelAnimationFrame(animationFrameRef.current);
32421
- }
32422
- animationFrameRef.current = requestAnimationFrame(animate);
32423
- }, []);
32584
+ const effectiveDatasetKey = datasetKey || `cycle-time:${xAxisMode}`;
32585
+ const [animatedDatasetKey, setAnimatedDatasetKey] = React141__default.useState(null);
32586
+ const shouldAnimate = animatedDatasetKey !== effectiveDatasetKey;
32587
+ const handleAnimationEnd = React141__default.useCallback(() => {
32588
+ setAnimatedDatasetKey((currentValue) => currentValue === effectiveDatasetKey ? currentValue : effectiveDatasetKey);
32589
+ }, [effectiveDatasetKey]);
32590
+ const finalData = displayData;
32424
32591
  React141__default.useEffect(() => {
32425
- if (JSON.stringify(data) !== JSON.stringify(prevDataRef.current)) {
32426
- const processedData = getDisplayData(data);
32427
- animateToNewData(processedData);
32592
+ const containerNode = containerRef.current;
32593
+ if (!containerNode) {
32594
+ setContainerReady(true);
32595
+ return void 0;
32428
32596
  }
32429
- return () => {
32430
- if (animationFrameRef.current) {
32431
- cancelAnimationFrame(animationFrameRef.current);
32432
- }
32433
- };
32434
- }, [data, animateToNewData]);
32435
- React141__default.useEffect(() => {
32597
+ let frameId = null;
32598
+ let resizeObserver = null;
32436
32599
  const checkContainerDimensions = () => {
32437
- if (containerRef.current) {
32438
- const rect = containerRef.current.getBoundingClientRect();
32439
- if (rect.width > 0 && rect.height > 0) {
32440
- setContainerReady(true);
32441
- }
32600
+ const rect = containerNode.getBoundingClientRect();
32601
+ const isReady = rect.width > 0 && rect.height > 0;
32602
+ if (isReady) {
32603
+ setContainerReady(true);
32442
32604
  }
32605
+ return isReady;
32443
32606
  };
32444
- checkContainerDimensions();
32445
- const resizeObserver = new ResizeObserver(checkContainerDimensions);
32446
- if (containerRef.current) {
32447
- resizeObserver.observe(containerRef.current);
32607
+ if (checkContainerDimensions()) {
32608
+ return void 0;
32448
32609
  }
32449
- const fallbackTimeout = setTimeout(() => {
32610
+ frameId = window.requestAnimationFrame(() => {
32611
+ checkContainerDimensions();
32612
+ });
32613
+ if (typeof ResizeObserver !== "undefined") {
32614
+ resizeObserver = new ResizeObserver(() => {
32615
+ if (checkContainerDimensions() && resizeObserver) {
32616
+ resizeObserver.disconnect();
32617
+ resizeObserver = null;
32618
+ }
32619
+ });
32620
+ resizeObserver.observe(containerNode);
32621
+ } else {
32450
32622
  setContainerReady(true);
32451
- }, 100);
32623
+ }
32452
32624
  return () => {
32453
- resizeObserver.disconnect();
32454
- clearTimeout(fallbackTimeout);
32625
+ if (frameId !== null) {
32626
+ window.cancelAnimationFrame(frameId);
32627
+ }
32628
+ resizeObserver?.disconnect();
32455
32629
  };
32456
32630
  }, []);
32631
+ const labelInterval = React141__default.useMemo(() => {
32632
+ if (xAxisMode === "hourly") {
32633
+ return Math.max(1, Math.ceil(DURATION / 8));
32634
+ }
32635
+ return 5;
32636
+ }, [xAxisMode, DURATION]);
32457
32637
  const formatTimeLabel = (dataIndex) => {
32458
32638
  if (DURATION === 0) return "";
32459
- if (dataIndex % 5 !== 0 && dataIndex !== DURATION - 1) return "";
32639
+ if (dataIndex % labelInterval !== 0 && dataIndex !== DURATION - 1) return "";
32640
+ if (xAxisMode === "hourly") {
32641
+ return formatHourLabel(dataIndex);
32642
+ }
32460
32643
  const timeAgo = (DURATION - 1 - dataIndex) * 90;
32461
32644
  const minutes = Math.floor(timeAgo / 60);
32462
32645
  const seconds = timeAgo % 60;
@@ -32470,6 +32653,9 @@ var CycleTimeOverTimeChart = ({
32470
32653
  };
32471
32654
  const formatTooltipTime = (dataIndex) => {
32472
32655
  if (DURATION === 0) return "";
32656
+ if (xAxisMode === "hourly") {
32657
+ return formatHourRangeLabel(dataIndex);
32658
+ }
32473
32659
  const timeAgo = (DURATION - 1 - dataIndex) * 90;
32474
32660
  const minutes = Math.floor(timeAgo / 60);
32475
32661
  const seconds = timeAgo % 60;
@@ -32483,39 +32669,40 @@ var CycleTimeOverTimeChart = ({
32483
32669
  return `${minutes} minutes ${seconds} seconds ago`;
32484
32670
  }
32485
32671
  };
32486
- const chartData = Array.from({ length: DURATION }, (_, i) => {
32672
+ const chartData = React141__default.useMemo(() => Array.from({ length: DURATION }, (_, i) => {
32487
32673
  return {
32488
32674
  timeIndex: i,
32489
32675
  label: formatTimeLabel(i),
32490
32676
  tooltip: formatTooltipTime(i),
32491
- cycleTime: animatedData[i] || 0,
32492
- color: (animatedData[i] || 0) <= idealCycleTime ? "#00AB45" : "#E34329"
32677
+ cycleTime: finalData[i] || 0,
32678
+ idleMinutes: showIdleTime && idleTimeData && idleTimeData[i] || 0,
32679
+ color: (finalData[i] || 0) <= idealCycleTime ? "#00AB45" : "#E34329"
32493
32680
  };
32494
- });
32495
- const renderLegend = () => /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center text-sm text-gray-600 absolute -bottom-1 left-0 right-0 bg-white py-1", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border border-gray-100 rounded-full px-3 py-1", children: [
32496
- /* @__PURE__ */ jsx("div", { className: "w-8 flex items-center", children: /* @__PURE__ */ jsx("div", { className: "w-full border-t-2 border-[#E34329] border-dashed" }) }),
32497
- /* @__PURE__ */ jsxs("span", { children: [
32498
- "Standard: ",
32499
- idealCycleTime.toFixed(1),
32500
- " seconds"
32501
- ] })
32502
- ] }) });
32681
+ }), [DURATION, finalData, showIdleTime, idleTimeData, idealCycleTime]);
32682
+ const renderLegend = () => {
32683
+ if (!showIdleTime) return null;
32684
+ return /* @__PURE__ */ jsx("div", { className: "flex items-center justify-start text-[10px] font-bold text-gray-500 mb-6 tracking-[0.05em] gap-5", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
32685
+ /* @__PURE__ */ jsx("div", { className: "w-2.5 h-2.5 rounded-full bg-[#f59e0b]" }),
32686
+ /* @__PURE__ */ jsx("span", { children: "Idle Time (min)" })
32687
+ ] }) });
32688
+ };
32503
32689
  return /* @__PURE__ */ jsxs(
32504
32690
  "div",
32505
32691
  {
32506
32692
  ref: containerRef,
32507
- className: `w-full h-full min-w-0 relative pb-8 ${className}`,
32693
+ className: `w-full h-full min-w-0 flex flex-col relative pb-2 ${className}`,
32508
32694
  style: { minHeight: "200px", minWidth: 0 },
32509
32695
  children: [
32510
- containerReady ? /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
32696
+ renderLegend(),
32697
+ /* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 w-full", children: containerReady ? /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
32511
32698
  LineChart$1,
32512
32699
  {
32513
32700
  data: chartData,
32514
32701
  margin: {
32515
- top: 25,
32702
+ top: 5,
32516
32703
  right: 30,
32517
32704
  bottom: 25,
32518
- left: 35
32705
+ left: 10
32519
32706
  },
32520
32707
  children: [
32521
32708
  /* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", vertical: false }),
@@ -32525,17 +32712,18 @@ var CycleTimeOverTimeChart = ({
32525
32712
  dataKey: "label",
32526
32713
  tick: { fontSize: 11 },
32527
32714
  interval: 0,
32528
- angle: -30,
32529
- textAnchor: "end",
32530
- tickMargin: 15,
32531
- height: 60
32715
+ angle: xAxisMode === "hourly" ? 0 : -30,
32716
+ textAnchor: xAxisMode === "hourly" ? "middle" : "end",
32717
+ tickMargin: xAxisMode === "hourly" ? 8 : 15,
32718
+ height: xAxisMode === "hourly" ? 40 : 60
32532
32719
  }
32533
32720
  ),
32534
32721
  /* @__PURE__ */ jsx(
32535
32722
  YAxis,
32536
32723
  {
32537
32724
  tickMargin: 8,
32538
- width: 35,
32725
+ width: 45,
32726
+ yAxisId: "cycle",
32539
32727
  domain: ["auto", "auto"],
32540
32728
  ticks: [0, idealCycleTime, ...Array.from({ length: 4 }, (_, i) => (i + 1) * Math.ceil(idealCycleTime / 2))].sort((a, b) => a - b),
32541
32729
  tickFormatter: (value) => String(value),
@@ -32559,6 +32747,20 @@ var CycleTimeOverTimeChart = ({
32559
32747
  }
32560
32748
  }
32561
32749
  ),
32750
+ showIdleTime && /* @__PURE__ */ jsx(
32751
+ YAxis,
32752
+ {
32753
+ yAxisId: "idle",
32754
+ orientation: "right",
32755
+ tickMargin: 8,
32756
+ width: 35,
32757
+ domain: [0, 60],
32758
+ tickFormatter: (value) => `${value}m`,
32759
+ tick: { fontSize: 11, fill: "#f59e0b" },
32760
+ axisLine: false,
32761
+ tickLine: false
32762
+ }
32763
+ ),
32562
32764
  /* @__PURE__ */ jsx(
32563
32765
  Tooltip,
32564
32766
  {
@@ -32586,8 +32788,11 @@ var CycleTimeOverTimeChart = ({
32586
32788
  }
32587
32789
  return label;
32588
32790
  },
32589
- formatter: (value) => {
32791
+ formatter: (value, name) => {
32590
32792
  const numValue = typeof value === "number" ? value : Number(value);
32793
+ if (name === "idleMinutes") {
32794
+ return [`${numValue.toFixed(0)} minutes`, "Idle Time"];
32795
+ }
32591
32796
  return [`${numValue.toFixed(1)} seconds`, "Cycle Time"];
32592
32797
  },
32593
32798
  animationDuration: 200
@@ -32597,6 +32802,7 @@ var CycleTimeOverTimeChart = ({
32597
32802
  ReferenceLine,
32598
32803
  {
32599
32804
  y: idealCycleTime,
32805
+ yAxisId: "cycle",
32600
32806
  stroke: "#E34329",
32601
32807
  strokeDasharray: "3 3",
32602
32808
  strokeWidth: 2,
@@ -32613,6 +32819,7 @@ var CycleTimeOverTimeChart = ({
32613
32819
  Line,
32614
32820
  {
32615
32821
  type: "monotone",
32822
+ yAxisId: "cycle",
32616
32823
  dataKey: "cycleTime",
32617
32824
  stroke: "#3B82F6",
32618
32825
  strokeWidth: 2,
@@ -32662,15 +32869,35 @@ var CycleTimeOverTimeChart = ({
32662
32869
  }
32663
32870
  );
32664
32871
  },
32872
+ isAnimationActive: shouldAnimate,
32665
32873
  animationBegin: 0,
32666
- animationDuration: 1500,
32874
+ animationDuration: 1200,
32875
+ animationEasing: "ease-out",
32876
+ onAnimationEnd: handleAnimationEnd
32877
+ },
32878
+ `${effectiveDatasetKey}:cycle`
32879
+ ),
32880
+ showIdleTime && /* @__PURE__ */ jsx(
32881
+ Line,
32882
+ {
32883
+ type: "monotone",
32884
+ yAxisId: "idle",
32885
+ dataKey: "idleMinutes",
32886
+ stroke: "#f59e0b",
32887
+ strokeWidth: 2,
32888
+ strokeDasharray: "4 4",
32889
+ dot: { r: 4, fill: "#f59e0b", stroke: "#fff", strokeWidth: 1 },
32890
+ activeDot: { r: 6, fill: "#f59e0b", stroke: "#fff", strokeWidth: 2 },
32891
+ isAnimationActive: shouldAnimate,
32892
+ animationBegin: 0,
32893
+ animationDuration: 1200,
32667
32894
  animationEasing: "ease-out"
32668
- }
32895
+ },
32896
+ `${effectiveDatasetKey}:idle`
32669
32897
  )
32670
32898
  ]
32671
32899
  }
32672
- ) }) : /* @__PURE__ */ jsx("div", { className: "w-full h-full flex items-center justify-center bg-gray-50 rounded-lg", children: /* @__PURE__ */ jsx("div", { className: "text-gray-500 text-sm", children: "Loading chart..." }) }),
32673
- renderLegend()
32900
+ ) }) : /* @__PURE__ */ jsx("div", { className: "w-full h-full flex items-center justify-center bg-gray-50 rounded-lg", children: /* @__PURE__ */ jsx("div", { className: "text-gray-500 text-sm", children: "Loading chart..." }) }) })
32674
32901
  ]
32675
32902
  }
32676
32903
  );
@@ -32862,7 +33089,7 @@ var HourlyOutputChartComponent = ({
32862
33089
  if (!classification.label) {
32863
33090
  return "Reason unavailable";
32864
33091
  }
32865
- return classification.label.replace(/_/g, " ");
33092
+ return classification.displayName || classification.label.replace(/_/g, " ");
32866
33093
  }, [idleClipRanges, idleTimeClipClassifications]);
32867
33094
  const { shiftDuration, shiftEndTime, hasPartialLastHour } = React141__default.useMemo(() => {
32868
33095
  console.log("[HourlyOutputChart] Calculating shift duration with:", {
@@ -33520,23 +33747,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);
@@ -59924,7 +60354,7 @@ var MonthlyRangeFilter = ({
59924
60354
  "overflow-hidden bg-white animate-in fade-in zoom-in-95 duration-200 flex",
59925
60355
  isInline ? "relative mt-2 w-full rounded-xl border border-gray-200" : "absolute right-0 z-50 mt-2 w-[520px] rounded-xl border border-gray-100 shadow-2xl"
59926
60356
  ), children: [
59927
- /* @__PURE__ */ jsxs("div", { className: "w-40 bg-[#F8FAFF] border-r border-gray-100 p-4 flex flex-col justify-between", children: [
60357
+ !singleDateOnly && /* @__PURE__ */ jsxs("div", { className: "w-40 bg-gray-50 border-r border-gray-100 p-4 flex flex-col justify-between", children: [
59928
60358
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
59929
60359
  presets.map((preset) => /* @__PURE__ */ jsx(
59930
60360
  "button",
@@ -59933,7 +60363,7 @@ var MonthlyRangeFilter = ({
59933
60363
  onClick: () => handlePresetClick(preset),
59934
60364
  className: clsx(
59935
60365
  "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"
60366
+ activePreset === preset.label ? "bg-blue-50 text-blue-600 font-semibold" : "text-gray-600 hover:bg-gray-100/80"
59937
60367
  ),
59938
60368
  children: preset.label
59939
60369
  },
@@ -59946,7 +60376,7 @@ var MonthlyRangeFilter = ({
59946
60376
  onClick: () => setActivePreset("Custom"),
59947
60377
  className: clsx(
59948
60378
  "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"
60379
+ activePreset === "Custom" ? "bg-blue-50 text-blue-600 font-semibold" : "text-gray-600 hover:bg-gray-100/80"
59950
60380
  ),
59951
60381
  children: "Custom"
59952
60382
  }
@@ -59968,7 +60398,7 @@ var MonthlyRangeFilter = ({
59968
60398
  type: "button",
59969
60399
  onClick: handleApply,
59970
60400
  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",
60401
+ className: "w-full py-2.5 bg-blue-600 text-white text-sm font-semibold rounded-lg hover:bg-blue-700 transition-all disabled:opacity-50 disabled:cursor-not-allowed",
59972
60402
  children: "Apply"
59973
60403
  }
59974
60404
  )
@@ -60018,9 +60448,9 @@ var MonthlyRangeFilter = ({
60018
60448
  const dayNum = day.getDate();
60019
60449
  const isFutureDay = startOfDay(day) > startOfDay(today);
60020
60450
  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" }),
60451
+ inRange && !isStart && !isEnd && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 -inset-x-0.5 bg-blue-50 z-0" }),
60452
+ inRange && isStart && !isSingleDaySelection && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 right-0 left-1/2 bg-blue-50 z-0" }),
60453
+ inRange && isEnd && !isSingleDaySelection && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 left-0 right-1/2 bg-blue-50 z-0" }),
60024
60454
  /* @__PURE__ */ jsx(
60025
60455
  "button",
60026
60456
  {
@@ -60029,19 +60459,47 @@ var MonthlyRangeFilter = ({
60029
60459
  disabled: isFutureDay,
60030
60460
  className: clsx(
60031
60461
  "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",
60462
+ // Future day NOT in range
60463
+ isFutureDay && !inRange && "text-gray-300 cursor-not-allowed",
60033
60464
  // Not in range
60034
- !isFutureDay && !inRange && "text-gray-700 hover:bg-gray-50 rounded-lg",
60465
+ !isFutureDay && !inRange && "text-gray-700 hover:bg-gray-100 rounded-lg",
60035
60466
  // Middle of range
60036
- inRange && !isStart && !isEnd && "text-[#4F46E5]",
60467
+ inRange && !isStart && !isEnd && clsx(
60468
+ "text-blue-600",
60469
+ isFutureDay && "cursor-not-allowed opacity-60"
60470
+ ),
60037
60471
  // Start/End of range or Single selection
60038
- (isStart || isEnd) && "bg-[#4F46E5] text-white rounded-lg shadow-sm"
60472
+ (isStart || isEnd) && clsx(
60473
+ "bg-blue-600 text-white rounded-lg shadow-sm",
60474
+ isFutureDay && "cursor-not-allowed opacity-80"
60475
+ )
60039
60476
  ),
60040
60477
  children: dayNum
60041
60478
  }
60042
60479
  )
60043
60480
  ] }, day.toISOString());
60044
- }) })
60481
+ }) }),
60482
+ singleDateOnly && /* @__PURE__ */ jsxs("div", { className: "mt-4 flex items-center justify-end gap-2 border-t border-gray-100 pt-3", children: [
60483
+ /* @__PURE__ */ jsx(
60484
+ "button",
60485
+ {
60486
+ type: "button",
60487
+ onClick: handleReset,
60488
+ className: "px-3 py-1.5 text-sm font-medium text-gray-500 hover:text-gray-700 transition-colors",
60489
+ children: "Reset"
60490
+ }
60491
+ ),
60492
+ /* @__PURE__ */ jsx(
60493
+ "button",
60494
+ {
60495
+ type: "button",
60496
+ onClick: handleApply,
60497
+ disabled: !rangeStart,
60498
+ className: "px-4 py-1.5 bg-blue-600 text-white text-sm font-semibold rounded-lg hover:bg-blue-700 transition-all disabled:opacity-50 disabled:cursor-not-allowed",
60499
+ children: "Apply"
60500
+ }
60501
+ )
60502
+ ] })
60045
60503
  ] })
60046
60504
  ] })
60047
60505
  ] });
@@ -61818,7 +62276,36 @@ var getMonthDateInfo = (timezone) => {
61818
62276
  const monthEndDate = fromZonedTime(`${monthEndKey}T23:59:59`, timezone);
61819
62277
  return { startDate, endDate, monthEndDate };
61820
62278
  };
61821
- var LeaderboardCountdown = ({ targetDate, format: format8, finishedLabel = "Finished", placeholder = "--", onFinished }) => {
62279
+ var createKpisOverviewUrl = ({
62280
+ tab,
62281
+ date,
62282
+ shift
62283
+ }) => {
62284
+ const params = new URLSearchParams();
62285
+ if (tab) {
62286
+ params.set("tab", tab);
62287
+ }
62288
+ if (date) {
62289
+ params.set("date", date);
62290
+ }
62291
+ if (typeof shift === "number" && Number.isFinite(shift)) {
62292
+ params.set("shift", shift.toString());
62293
+ }
62294
+ const queryString = params.toString();
62295
+ return queryString ? `/kpis?${queryString}` : "/kpis";
62296
+ };
62297
+ var getZonedDateAtMidday = (dateKey, timezone) => fromZonedTime(`${dateKey}T12:00:00`, timezone);
62298
+ var formatDateKey = (dateKey, timezone, options) => {
62299
+ try {
62300
+ return new Intl.DateTimeFormat("en-US", {
62301
+ ...options,
62302
+ timeZone: timezone
62303
+ }).format(getZonedDateAtMidday(dateKey, timezone));
62304
+ } catch {
62305
+ return dateKey;
62306
+ }
62307
+ };
62308
+ var LeaderboardCountdown = ({ targetDate, format: format9, finishedLabel = "Finished", placeholder = "--", onFinished }) => {
61822
62309
  const [time2, setTime] = useState("");
61823
62310
  const hasFinishedRef = useRef(false);
61824
62311
  useEffect(() => {
@@ -61840,7 +62327,7 @@ var LeaderboardCountdown = ({ targetDate, format: format8, finishedLabel = "Fini
61840
62327
  }
61841
62328
  return;
61842
62329
  }
61843
- if (format8 === "days") {
62330
+ if (format9 === "days") {
61844
62331
  const days = Math.floor(diff / (1e3 * 60 * 60 * 24));
61845
62332
  const hours = Math.floor(diff % (1e3 * 60 * 60 * 24) / (1e3 * 60 * 60));
61846
62333
  setTime(`${days} days ${hours} hours`);
@@ -61855,7 +62342,7 @@ var LeaderboardCountdown = ({ targetDate, format: format8, finishedLabel = "Fini
61855
62342
  tick();
61856
62343
  const interval = setInterval(tick, 1e3);
61857
62344
  return () => clearInterval(interval);
61858
- }, [targetDate, format8, finishedLabel, placeholder, onFinished]);
62345
+ }, [targetDate, format9, finishedLabel, placeholder, onFinished]);
61859
62346
  return /* @__PURE__ */ jsx(Fragment, { children: time2 });
61860
62347
  };
61861
62348
  var LinesLeaderboard = ({
@@ -61873,7 +62360,9 @@ var LinesLeaderboard = ({
61873
62360
  shiftEndDate,
61874
62361
  monthEndDate,
61875
62362
  viewType,
61876
- setViewType
62363
+ setViewType,
62364
+ timezone: _timezone,
62365
+ isHistoricalDaily
61877
62366
  }) => {
61878
62367
  const formatEfficiency = (value) => typeof value === "number" && Number.isFinite(value) ? `${value.toFixed(1)}%` : "--";
61879
62368
  const assignedLineIdSet = React141__default.useMemo(
@@ -61966,10 +62455,10 @@ var LinesLeaderboard = ({
61966
62455
  }
61967
62456
  }, [timeRange, leaderboardData, isLoadingToday, isLoadingMonthly]);
61968
62457
  const topThree = leaderboardData.slice(0, 3);
61969
- leaderboardData.slice(3);
61970
62458
  const countdownTarget = timeRange === "monthly" ? monthEndDate : shiftEndDate;
61971
62459
  const countdownFormat = timeRange === "monthly" ? "days" : "clock";
61972
62460
  const countdownFinishedLabel = timeRange === "monthly" ? "Finished" : "Shift Ended";
62461
+ const showCountdown = timeRange === "monthly" || !isHistoricalDaily;
61973
62462
  const handleCountdownFinished = React141__default.useCallback(() => {
61974
62463
  trackCoreEvent("Leaderboard Countdown Finished", {
61975
62464
  countdown_type: timeRange === "monthly" ? "month_end" : "shift_end",
@@ -62043,7 +62532,7 @@ var LinesLeaderboard = ({
62043
62532
  }
62044
62533
  )
62045
62534
  ] }),
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: [
62535
+ /* @__PURE__ */ jsx("div", { className: "md:absolute md:right-0 md:top-1/2 md:-translate-y-1/2 flex flex-wrap items-center justify-center md:justify-end gap-2", children: showCountdown && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5 px-4 py-2 bg-white rounded-full shadow-sm border border-gray-100", children: [
62047
62536
  /* @__PURE__ */ jsx(Clock, { className: "w-4 h-4 text-orange-500" }),
62048
62537
  /* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-2", children: [
62049
62538
  /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider", children: "Ends in" }),
@@ -62164,7 +62653,7 @@ var LinesLeaderboard = ({
62164
62653
  /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-gray-900", children: item.supervisorName })
62165
62654
  ] }) }),
62166
62655
  /* @__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) }) }) })
62656
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-3 whitespace-nowrap text-right", children: /* @__PURE__ */ jsx("div", { className: "flex flex-col items-end", children: /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-gray-900", children: formatEfficiency(item.efficiency) }) }) })
62168
62657
  ]
62169
62658
  },
62170
62659
  item.id
@@ -62338,6 +62827,9 @@ var KPIsOverviewView = ({
62338
62827
  const [activeTab, setActiveTab] = useState("today");
62339
62828
  const [timeRange, setTimeRange] = useState("today");
62340
62829
  const [viewType, setViewType] = useState("operator");
62830
+ const [selectedLeaderboardDate, setSelectedLeaderboardDate] = useState("");
62831
+ const [selectedLeaderboardShiftId, setSelectedLeaderboardShiftId] = useState(0);
62832
+ const [hasHydratedLeaderboardRouteState, setHasHydratedLeaderboardRouteState] = useState(false);
62341
62833
  const [loading, setLoading] = useState(true);
62342
62834
  const [error, setError] = useState(null);
62343
62835
  const [topPerformer, setTopPerformer] = useState({
@@ -62359,13 +62851,6 @@ var KPIsOverviewView = ({
62359
62851
  const [monthlyError, setMonthlyError] = useState(null);
62360
62852
  const dailyRequestKeyRef = useRef(null);
62361
62853
  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
62854
  const supabase = useSupabase();
62370
62855
  const { user } = useAuth();
62371
62856
  const dashboardConfig = useDashboardConfig();
@@ -62451,7 +62936,77 @@ var KPIsOverviewView = ({
62451
62936
  () => getShiftEndDate(currentShiftDetails, configuredTimezone),
62452
62937
  [currentShiftDetails, configuredTimezone]
62453
62938
  );
62454
- const shiftName = (currentShiftDetails.shiftName || "Day").replace(/ Shift$/i, "");
62939
+ React141__default.useMemo(() => {
62940
+ if (shiftConfig?.shifts && shiftConfig.shifts.length > 0) {
62941
+ return shiftConfig.shifts.map((shift) => ({
62942
+ id: shift.shiftId,
62943
+ label: shift.shiftName || `Shift ${shift.shiftId}`,
62944
+ startTime: shift.startTime,
62945
+ endTime: shift.endTime
62946
+ }));
62947
+ }
62948
+ return [
62949
+ { id: 0, label: "Day Shift", startTime: "06:00", endTime: "18:00" },
62950
+ { id: 1, label: "Night Shift", startTime: "18:00", endTime: "06:00" }
62951
+ ];
62952
+ }, [shiftConfig]);
62953
+ const effectiveLeaderboardDate = selectedLeaderboardDate || currentShiftDate;
62954
+ const effectiveLeaderboardShiftId = Number.isFinite(selectedLeaderboardShiftId) ? selectedLeaderboardShiftId : currentShiftId;
62955
+ const isHistoricalLeaderboardDaily = activeTab === "leaderboard" && timeRange === "today" && (effectiveLeaderboardDate !== currentShiftDate || effectiveLeaderboardShiftId !== currentShiftId);
62956
+ useEffect(() => {
62957
+ if (!router.isReady) return;
62958
+ const tabQuery = router.query.tab;
62959
+ const dateQuery = router.query.date;
62960
+ const shiftQuery = router.query.shift;
62961
+ const parsedShiftQuery = typeof shiftQuery === "string" ? Number.parseInt(shiftQuery, 10) : Number.NaN;
62962
+ const hasHistoricalQuery = tabQuery === "leaderboard" && typeof dateQuery === "string" && Number.isFinite(parsedShiftQuery);
62963
+ setActiveTab(tabQuery === "leaderboard" ? "leaderboard" : "today");
62964
+ if (hasHistoricalQuery) {
62965
+ setSelectedLeaderboardDate(dateQuery);
62966
+ setSelectedLeaderboardShiftId(parsedShiftQuery);
62967
+ setTimeRange("today");
62968
+ } else {
62969
+ setSelectedLeaderboardDate(currentShiftDate);
62970
+ setSelectedLeaderboardShiftId(currentShiftId);
62971
+ }
62972
+ setHasHydratedLeaderboardRouteState(true);
62973
+ }, [
62974
+ router.isReady,
62975
+ router.query.tab,
62976
+ router.query.date,
62977
+ router.query.shift,
62978
+ currentShiftDate,
62979
+ currentShiftId
62980
+ ]);
62981
+ useEffect(() => {
62982
+ if (!router.isReady || !hasHydratedLeaderboardRouteState) return;
62983
+ const expectedTab = activeTab === "leaderboard" ? "leaderboard" : void 0;
62984
+ const expectedDate = activeTab === "leaderboard" && timeRange === "today" && isHistoricalLeaderboardDaily ? effectiveLeaderboardDate : void 0;
62985
+ const expectedShift = expectedDate !== void 0 ? effectiveLeaderboardShiftId.toString() : void 0;
62986
+ const currentTab = typeof router.query.tab === "string" ? router.query.tab : void 0;
62987
+ const currentDateQuery = typeof router.query.date === "string" ? router.query.date : void 0;
62988
+ const currentShiftQuery = typeof router.query.shift === "string" ? router.query.shift : void 0;
62989
+ if (currentTab === expectedTab && currentDateQuery === expectedDate && currentShiftQuery === expectedShift) {
62990
+ return;
62991
+ }
62992
+ void router.replace(
62993
+ createKpisOverviewUrl({
62994
+ tab: expectedTab === "leaderboard" ? "leaderboard" : void 0,
62995
+ date: expectedDate,
62996
+ shift: expectedShift !== void 0 ? Number.parseInt(expectedShift, 10) : void 0
62997
+ }),
62998
+ void 0,
62999
+ { shallow: true }
63000
+ );
63001
+ }, [
63002
+ router,
63003
+ activeTab,
63004
+ timeRange,
63005
+ effectiveLeaderboardDate,
63006
+ effectiveLeaderboardShiftId,
63007
+ hasHydratedLeaderboardRouteState,
63008
+ isHistoricalLeaderboardDaily
63009
+ ]);
62455
63010
  const factoryViewId = entityConfig.factoryViewId || "factory";
62456
63011
  const {
62457
63012
  lineMetrics,
@@ -62626,10 +63181,10 @@ var KPIsOverviewView = ({
62626
63181
  }, [supabase, resolvedCompanyId, leaderboardLinesForView, monthStartDate, monthEndDateKey, viewType]);
62627
63182
  const fetchDailyLeaderboard = useCallback(async () => {
62628
63183
  if (!supabase || !resolvedCompanyId || leaderboardLinesForView.length === 0) return;
62629
- if (!currentShiftDate) return;
63184
+ if (!effectiveLeaderboardDate) return;
62630
63185
  const targetLineIds = leaderboardLinesForView.map((line) => line.id);
62631
63186
  const lineIdsKey = targetLineIds.slice().sort().join(",");
62632
- const requestKey = `${resolvedCompanyId}|${currentShiftDate}|${currentShiftId}|${lineIdsKey}`;
63187
+ const requestKey = `${resolvedCompanyId}|${effectiveLeaderboardDate}|${effectiveLeaderboardShiftId}|${lineIdsKey}`;
62633
63188
  if (dailyRequestKeyRef.current === requestKey) return;
62634
63189
  dailyRequestKeyRef.current = requestKey;
62635
63190
  setDailyLoading(true);
@@ -62637,8 +63192,8 @@ var KPIsOverviewView = ({
62637
63192
  try {
62638
63193
  const entries = await lineLeaderboardService.getDailyLineLeaderboard(supabase, {
62639
63194
  companyId: resolvedCompanyId,
62640
- date: currentShiftDate,
62641
- shiftId: currentShiftId,
63195
+ date: effectiveLeaderboardDate,
63196
+ shiftId: effectiveLeaderboardShiftId,
62642
63197
  lineIds: targetLineIds,
62643
63198
  lineMode: viewType === "machine" ? "uptime" : "output"
62644
63199
  });
@@ -62656,7 +63211,14 @@ var KPIsOverviewView = ({
62656
63211
  } finally {
62657
63212
  setDailyLoading(false);
62658
63213
  }
62659
- }, [supabase, resolvedCompanyId, leaderboardLinesForView, currentShiftDate, currentShiftId, viewType]);
63214
+ }, [
63215
+ supabase,
63216
+ resolvedCompanyId,
63217
+ leaderboardLinesForView,
63218
+ effectiveLeaderboardDate,
63219
+ effectiveLeaderboardShiftId,
63220
+ viewType
63221
+ ]);
62660
63222
  useEffect(() => {
62661
63223
  if (activeTab !== "leaderboard") return;
62662
63224
  fetchMonthlyLeaderboard();
@@ -62745,6 +63307,12 @@ var KPIsOverviewView = ({
62745
63307
  trackProps.status = isEfficiencyOnTrack(kpis.efficiency?.value) ? "On Track" : "Behind";
62746
63308
  }
62747
63309
  trackCoreEvent("Line Card Clicked", trackProps);
63310
+ if (activeTab === "leaderboard" && timeRange === "today" && isHistoricalLeaderboardDaily) {
63311
+ navigation.navigate(
63312
+ `/kpis/${line.id}?date=${encodeURIComponent(effectiveLeaderboardDate)}&shift=${effectiveLeaderboardShiftId}`
63313
+ );
63314
+ return;
63315
+ }
62748
63316
  navigation.navigate(`/kpis/${line.id}`);
62749
63317
  };
62750
63318
  const handleBackClick = useCallback(() => {
@@ -62770,21 +63338,24 @@ var KPIsOverviewView = ({
62770
63338
  });
62771
63339
  setActiveTab(newTab);
62772
63340
  }, [activeTab, leaderboardLines.length, lines.length]);
62773
- const formatLocalDate2 = (date) => {
62774
- const options = {
63341
+ const formatLocalDate2 = useCallback((dateKey) => {
63342
+ return formatDateKey(dateKey, configuredTimezone, {
62775
63343
  year: "numeric",
62776
63344
  month: "long",
62777
63345
  day: "numeric"
62778
- };
62779
- return date.toLocaleDateString("en-US", options);
62780
- };
63346
+ });
63347
+ }, [configuredTimezone]);
62781
63348
  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()}`;
63349
+ const zonedNow = toZonedTime(/* @__PURE__ */ new Date(), configuredTimezone);
63350
+ const startOfMonthKey = buildDateKey(zonedNow.getFullYear(), zonedNow.getMonth(), 1);
63351
+ const endOfMonthKey = buildDateKey(
63352
+ zonedNow.getFullYear(),
63353
+ zonedNow.getMonth(),
63354
+ new Date(zonedNow.getFullYear(), zonedNow.getMonth() + 1, 0).getDate()
63355
+ );
63356
+ const startLabel = formatDateKey(startOfMonthKey, configuredTimezone, { month: "short", day: "numeric" });
63357
+ const endLabel = formatDateKey(endOfMonthKey, configuredTimezone, { month: "short", day: "numeric" });
63358
+ return `${startLabel} - ${endLabel}, ${zonedNow.getFullYear()}`;
62788
63359
  };
62789
63360
  const isMonthlyMode = activeTab === "leaderboard" && timeRange === "monthly";
62790
63361
  const isLeaderboardLoading = timeRange === "today" ? dailyLoading : monthlyLoading;
@@ -62793,8 +63364,13 @@ var KPIsOverviewView = ({
62793
63364
  const showTopPerformerImage = Boolean(topPerformer.imageUrl) && !topPerformerImageError;
62794
63365
  typeof topPerformer.efficiency === "number" && Number.isFinite(topPerformer.efficiency);
62795
63366
  topPerformerLoading ? "--" : typeof topPerformer.efficiency === "number" && Number.isFinite(topPerformer.efficiency) ? `${topPerformer.efficiency.toFixed(1)}%` : "--";
63367
+ const showHistoricalLeaderboardHeader = activeTab === "leaderboard" && timeRange === "today" && isHistoricalLeaderboardDaily;
63368
+ const headerDateKey = activeTab === "leaderboard" && timeRange === "today" ? effectiveLeaderboardDate : monthEndDateKey;
63369
+ const headerShiftId = showHistoricalLeaderboardHeader ? effectiveLeaderboardShiftId : currentShiftDetails.shiftId;
63370
+ const headerShiftName = getShiftNameById(headerShiftId, configuredTimezone, shiftConfig).replace(/ Shift$/i, "");
63371
+ const headerDateLabel = isMonthlyMode ? getMonthRange() : formatLocalDate2(headerDateKey);
62796
63372
  const getShiftIcon = (shiftId) => {
62797
- const shiftNameLower = shiftName.toLowerCase();
63373
+ const shiftNameLower = getShiftNameById(shiftId, configuredTimezone, shiftConfig).toLowerCase();
62798
63374
  if (shiftNameLower.includes("day") || shiftNameLower.includes("morning") || shiftId === 0) {
62799
63375
  return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
62800
63376
  }
@@ -62897,18 +63473,26 @@ var KPIsOverviewView = ({
62897
63473
  ),
62898
63474
  /* @__PURE__ */ jsx("div", { className: "flex-1 flex items-center justify-center", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
62899
63475
  /* @__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" })
63476
+ /* @__PURE__ */ jsx(
63477
+ "div",
63478
+ {
63479
+ className: `h-2 w-2 rounded-full ring-2 ${showHistoricalLeaderboardHeader ? "bg-amber-500 ring-amber-500/20" : "bg-emerald-500 animate-pulse ring-emerald-500/20"}`
63480
+ }
63481
+ )
62901
63482
  ] }) }),
62902
63483
  /* @__PURE__ */ jsx("div", { className: "w-12" })
62903
63484
  ] }),
62904
63485
  /* @__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()) }) }),
63486
+ /* @__PURE__ */ jsx("div", { className: `inline-flex items-center bg-gray-100 rounded-full ${isMonthlyMode ? "px-4 py-1.5 ring-1 ring-gray-200 shadow-sm" : "px-2.5 py-1"}`, children: /* @__PURE__ */ jsx("span", { className: `font-medium text-gray-700 ${isMonthlyMode ? "text-sm" : "text-xs"}`, children: headerDateLabel }) }),
62906
63487
  !isMonthlyMode && /* @__PURE__ */ jsxs(Fragment, { children: [
62907
63488
  /* @__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 })
63489
+ /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon(headerShiftId) }),
63490
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-700", children: headerShiftName })
62910
63491
  ] }),
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, {}) }) })
63492
+ showHistoricalLeaderboardHeader ? /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-amber-50 text-amber-700 rounded-full", children: [
63493
+ /* @__PURE__ */ jsx(Clock, { className: "w-3 h-3" }),
63494
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium", children: "Historical" })
63495
+ ] }) : /* @__PURE__ */ jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-green-100 rounded-full", children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-green-700", children: /* @__PURE__ */ jsx(ISTTimer_default, {}) }) })
62912
63496
  ] })
62913
63497
  ] }),
62914
63498
  activeTab !== "leaderboard" && /* @__PURE__ */ jsx("div", { className: "mt-4 bg-white shadow-md hover:shadow-lg transition-all duration-300 ease-out hover:scale-[1.01] relative rounded-2xl border border-amber-100 pl-2 pr-4 py-1.5 flex items-center justify-between group", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4 min-w-0", children: [
@@ -63009,7 +63593,12 @@ var KPIsOverviewView = ({
63009
63593
  ) }),
63010
63594
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
63011
63595
  /* @__PURE__ */ jsx("h1", { className: "text-2xl md:text-3xl lg:text-4xl font-semibold text-gray-900 tracking-tight", children: activeTab === "leaderboard" ? "Leaderboard" : "Overview" }),
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" })
63596
+ /* @__PURE__ */ jsx(
63597
+ "div",
63598
+ {
63599
+ className: `h-2.5 w-2.5 rounded-full ring-4 flex-shrink-0 ${showHistoricalLeaderboardHeader ? "bg-amber-500 ring-amber-500/10" : "bg-emerald-500 animate-pulse ring-emerald-500/10"}`
63600
+ }
63601
+ )
63013
63602
  ] }),
63014
63603
  !topPerformerLoading && activeTab !== "leaderboard" && /* @__PURE__ */ jsx("div", { className: "absolute right-0 top-1/2 -translate-y-1/2 z-10", children: /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-2xl border border-amber-200 shadow-md pl-1.5 pr-4 py-1.5 flex items-center gap-4 transition-all hover:shadow-lg hover:border-amber-300 group", children: [
63015
63604
  /* @__PURE__ */ jsxs("div", { className: "relative", children: [
@@ -63079,7 +63668,7 @@ var KPIsOverviewView = ({
63079
63668
  ] }) })
63080
63669
  ] }),
63081
63670
  /* @__PURE__ */ jsx("div", { className: "bg-blue-50/50 px-4 py-2 rounded-xl border border-blue-100/50 backdrop-blur-sm", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center gap-6", children: [
63082
- !isMonthlyMode && /* @__PURE__ */ jsxs(Fragment, { children: [
63671
+ !isMonthlyMode && !showHistoricalLeaderboardHeader && /* @__PURE__ */ jsxs(Fragment, { children: [
63083
63672
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-blue-700", children: [
63084
63673
  /* @__PURE__ */ jsx("svg", { className: "w-4 h-4 opacity-70", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) }),
63085
63674
  /* @__PURE__ */ jsx("span", { className: "text-base font-semibold tabular-nums", children: /* @__PURE__ */ jsx(ISTTimer_default, {}) })
@@ -63088,16 +63677,23 @@ var KPIsOverviewView = ({
63088
63677
  ] }),
63089
63678
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
63090
63679
  /* @__PURE__ */ jsx("svg", { className: `w-4 h-4 opacity-70 ${isMonthlyMode ? "scale-110" : ""}`, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) }),
63091
- /* @__PURE__ */ jsx("span", { className: `${isMonthlyMode ? "text-base font-medium" : "text-sm font-medium"}`, children: isMonthlyMode ? getMonthRange() : formatLocalDate2(/* @__PURE__ */ new Date()) })
63680
+ /* @__PURE__ */ jsx("span", { className: `${isMonthlyMode ? "text-base font-medium" : "text-sm font-medium"}`, children: headerDateLabel })
63092
63681
  ] }),
63093
63682
  !isMonthlyMode && /* @__PURE__ */ jsxs(Fragment, { children: [
63094
63683
  /* @__PURE__ */ jsx("div", { className: "w-px h-4 bg-blue-200" }),
63095
63684
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
63096
- /* @__PURE__ */ jsx("div", { className: "opacity-70", children: getShiftIcon(currentShiftDetails.shiftId) }),
63685
+ /* @__PURE__ */ jsx("div", { className: "opacity-70", children: getShiftIcon(headerShiftId) }),
63097
63686
  /* @__PURE__ */ jsxs("span", { className: "text-sm font-semibold uppercase tracking-wider", children: [
63098
- shiftName,
63687
+ headerShiftName,
63099
63688
  " Shift"
63100
63689
  ] })
63690
+ ] }),
63691
+ showHistoricalLeaderboardHeader && /* @__PURE__ */ jsxs(Fragment, { children: [
63692
+ /* @__PURE__ */ jsx("div", { className: "w-px h-4 bg-blue-200" }),
63693
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-2.5 py-1 bg-amber-50 text-amber-700 rounded-full border border-amber-200", children: [
63694
+ /* @__PURE__ */ jsx(Clock, { className: "w-3.5 h-3.5" }),
63695
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold uppercase tracking-wider", children: "Historical" })
63696
+ ] })
63101
63697
  ] })
63102
63698
  ] })
63103
63699
  ] }) }),
@@ -63120,19 +63716,52 @@ var KPIsOverviewView = ({
63120
63716
  }
63121
63717
  )
63122
63718
  ] }),
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
- ) })
63719
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
63720
+ activeTab === "leaderboard" && timeRange === "today" && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
63721
+ /* @__PURE__ */ jsx(
63722
+ MonthlyRangeFilter_default,
63723
+ {
63724
+ month: parseDateKeyToDate(effectiveLeaderboardDate).getMonth(),
63725
+ year: parseDateKeyToDate(effectiveLeaderboardDate).getFullYear(),
63726
+ timezone: configuredTimezone,
63727
+ value: {
63728
+ startKey: effectiveLeaderboardDate,
63729
+ endKey: effectiveLeaderboardDate
63730
+ },
63731
+ onChange: (range) => {
63732
+ setSelectedLeaderboardDate(range.startKey);
63733
+ },
63734
+ showLabel: false,
63735
+ singleDateOnly: true
63736
+ }
63737
+ ),
63738
+ isHistoricalLeaderboardDaily && /* @__PURE__ */ jsx(
63739
+ "button",
63740
+ {
63741
+ type: "button",
63742
+ onClick: () => {
63743
+ setSelectedLeaderboardDate(currentShiftDate);
63744
+ setSelectedLeaderboardShiftId(currentShiftId);
63745
+ },
63746
+ className: "text-xs font-medium text-blue-600 hover:text-blue-700 whitespace-nowrap",
63747
+ children: "Return to Live"
63748
+ }
63749
+ )
63750
+ ] }),
63751
+ (activeTab === "leaderboard" || activeTab === "today") && showViewTypeDropdown && /* @__PURE__ */ jsx("div", { className: "relative", children: /* @__PURE__ */ jsxs(
63752
+ "select",
63753
+ {
63754
+ value: viewType,
63755
+ onChange: (e) => setViewType(e.target.value),
63756
+ className: "appearance-none pl-3 pr-8 py-1.5 text-sm font-medium bg-white border border-gray-200 hover:border-gray-300 rounded-lg text-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500 transition-all cursor-pointer shadow-sm",
63757
+ style: { backgroundImage: `url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e")`, backgroundPosition: `right 0.5rem center`, backgroundRepeat: `no-repeat`, backgroundSize: `1.2em 1.2em` },
63758
+ children: [
63759
+ /* @__PURE__ */ jsx("option", { value: "operator", children: "Workforce" }),
63760
+ /* @__PURE__ */ jsx("option", { value: "machine", children: "Machine" })
63761
+ ]
63762
+ }
63763
+ ) })
63764
+ ] })
63136
63765
  ] })
63137
63766
  ] })
63138
63767
  ] }) }),
@@ -63177,7 +63806,9 @@ var KPIsOverviewView = ({
63177
63806
  shiftEndDate,
63178
63807
  monthEndDate,
63179
63808
  viewType,
63180
- setViewType
63809
+ setViewType,
63810
+ timezone: configuredTimezone,
63811
+ isHistoricalDaily: isHistoricalLeaderboardDaily
63181
63812
  }
63182
63813
  ) })
63183
63814
  ) })
@@ -64719,51 +65350,41 @@ var ClipsCostView = () => {
64719
65350
  /* @__PURE__ */ jsx("div", { className: "min-w-[120px]" })
64720
65351
  ] }) })
64721
65352
  ] }) }),
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: [
65353
+ /* @__PURE__ */ jsx("main", { className: "flex-1 p-4 sm:p-6 lg:p-8 max-w-5xl mx-auto w-full", children: error ? /* @__PURE__ */ jsxs("div", { className: "p-4 bg-red-50 border border-red-200 rounded-lg flex items-start gap-3 text-red-700 animate-in fade-in slide-in-from-top-2 max-w-2xl mx-auto", children: [
64723
65354
  /* @__PURE__ */ jsx(AlertCircle, { className: "h-5 w-5 flex-shrink-0 mt-0.5" }),
64724
65355
  /* @__PURE__ */ jsxs("div", { children: [
64725
65356
  /* @__PURE__ */ jsx("h3", { className: "font-medium", children: "Error loading usage data" }),
64726
65357
  /* @__PURE__ */ jsx("p", { className: "text-sm mt-1 text-red-600", children: error })
64727
65358
  ] })
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(
65359
+ ] }) : /* @__PURE__ */ jsxs("div", { className: "mt-8 grid grid-cols-1 lg:grid-cols-3 gap-6 animate-in fade-in slide-in-from-bottom-4 duration-500", children: [
65360
+ /* @__PURE__ */ jsx("div", { className: "lg:col-span-2", children: /* @__PURE__ */ jsx(Card2, { className: "overflow-hidden shadow-sm border-gray-200 bg-white h-full flex flex-col justify-center", children: /* @__PURE__ */ jsx(CardContent2, { className: "p-10 lg:p-14", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center text-center", children: [
65361
+ /* @__PURE__ */ jsx("div", { className: "p-4 bg-blue-50/50 rounded-2xl mb-6 ring-1 ring-blue-100/50", children: /* @__PURE__ */ jsx(Film, { className: "h-10 w-10 text-blue-600", strokeWidth: 1.5 }) }),
65362
+ /* @__PURE__ */ jsx("h2", { className: "text-base font-semibold text-gray-600 uppercase tracking-widest mb-3", children: "Current Month Usage" }),
65363
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-gray-400 mb-6", children: formatMonthLabel(data?.monthStart) }),
65364
+ /* @__PURE__ */ jsx("div", { className: "flex items-baseline gap-2 mb-2", children: /* @__PURE__ */ jsx("div", { className: "text-7xl font-bold text-gray-900 tabular-nums tracking-tighter", children: formatNumber(data?.monthlyClassifications || 0) }) }),
65365
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500 mt-4", children: "Clips analyzed and processed by our AI pipeline" })
65366
+ ] }) }) }) }),
65367
+ /* @__PURE__ */ jsx("div", { className: "lg:col-span-1", children: /* @__PURE__ */ jsx(Card2, { className: "overflow-hidden shadow-sm border-gray-200 bg-white h-full", children: /* @__PURE__ */ jsxs(CardContent2, { className: "p-6 lg:p-8 flex flex-col h-full", children: [
65368
+ /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-gray-900 mb-6 uppercase tracking-widest", children: "Previous Months" }),
65369
+ (data?.historicalMonthlyClassifications?.length || 0) === 0 ? /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col items-center justify-center text-center py-8", children: [
65370
+ /* @__PURE__ */ jsx("div", { className: "p-3 bg-gray-50 rounded-full mb-3", children: /* @__PURE__ */ jsx(Film, { className: "h-6 w-6 text-gray-400", strokeWidth: 1.5 }) }),
65371
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500", children: "No historical month usage yet." })
65372
+ ] }) : /* @__PURE__ */ jsx("div", { className: "space-y-3 flex-1 overflow-y-auto pr-2", children: data?.historicalMonthlyClassifications.map((item) => /* @__PURE__ */ jsxs(
64738
65373
  "div",
64739
65374
  {
64740
- className: "flex items-center justify-between rounded-md border border-gray-100 bg-gray-50 px-3 py-2",
65375
+ className: "group flex items-center justify-between rounded-xl border border-gray-100 bg-gray-50/50 hover:bg-white hover:border-gray-200 hover:shadow-sm px-4 py-3.5 transition-all duration-200",
64741
65376
  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) })
65377
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-gray-600 group-hover:text-gray-900 transition-colors", children: formatMonthLabel(item.monthStart) }),
65378
+ /* @__PURE__ */ jsx("span", { className: "text-base font-semibold text-gray-900 tabular-nums", children: formatNumber(item.classifications) })
64744
65379
  ]
64745
65380
  },
64746
65381
  item.monthStart
64747
65382
  )) })
64748
- ] }) })
65383
+ ] }) }) })
64749
65384
  ] }) })
64750
65385
  ] });
64751
65386
  };
64752
65387
  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
65388
  var calculateShiftHours = (startTime, endTime, breaks = []) => {
64768
65389
  if (!startTime || !endTime) return 8;
64769
65390
  const [startHour, startMinute] = startTime.split(":").map(Number);
@@ -65345,9 +65966,9 @@ var ShiftsView = ({
65345
65966
  const actionIds = Array.from(
65346
65967
  new Set(currentThresholds.map((threshold) => threshold.action_id).filter(Boolean))
65347
65968
  );
65348
- const actionNameById = /* @__PURE__ */ new Map();
65969
+ const actionMetadataById = /* @__PURE__ */ new Map();
65349
65970
  if (actionIds.length > 0) {
65350
- const { data: actionRows, error: actionsError } = await supabase.from("actions").select("id, action_name").in("id", actionIds);
65971
+ const { data: actionRows, error: actionsError } = await supabase.from("actions").select("id, action_name, action_family").in("id", actionIds);
65351
65972
  if (actionsError) {
65352
65973
  console.warn(
65353
65974
  `[ShiftsView] Failed to resolve action names for line ${lineId}, shift ${shift.shiftId}: ${actionsError.message}`
@@ -65355,7 +65976,13 @@ var ShiftsView = ({
65355
65976
  } else {
65356
65977
  (actionRows || []).forEach((actionRow) => {
65357
65978
  if (actionRow.id && actionRow.action_name) {
65358
- actionNameById.set(actionRow.id, actionRow.action_name);
65979
+ actionMetadataById.set(actionRow.id, {
65980
+ action_name: actionRow.action_name,
65981
+ action_family: normalizeActionFamily({
65982
+ actionFamily: actionRow.action_family,
65983
+ actionName: actionRow.action_name
65984
+ })
65985
+ });
65359
65986
  }
65360
65987
  });
65361
65988
  }
@@ -65376,7 +66003,7 @@ var ShiftsView = ({
65376
66003
  nextDayOutput = dayOutputToKeep;
65377
66004
  nextPPH = newShiftHours > 0 ? Math.round(dayOutputToKeep / newShiftHours) : 0;
65378
66005
  }
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;
66006
+ const resolvedActionName = (typeof threshold.action_name === "string" && threshold.action_name.trim().length > 0 ? threshold.action_name : actionMetadataById.get(threshold.action_id)?.action_name) || ACTION_NAMES.ASSEMBLY;
65380
66007
  return {
65381
66008
  line_id: threshold.line_id || lineId,
65382
66009
  shift_id: shift.shiftId,
@@ -65397,18 +66024,20 @@ var ShiftsView = ({
65397
66024
  `Failed to update action thresholds for line ${lineId}, shift ${shift.shiftId}: ${thresholdsUpsertError.message}`
65398
66025
  );
65399
66026
  }
65400
- const packagingActionIds = new Set(
65401
- Array.from(actionNameById.entries()).filter(([, actionName]) => actionName.toLowerCase() === ACTION_NAMES.PACKAGING.toLowerCase()).map(([actionId]) => actionId)
66027
+ const outputActionIds = new Set(
66028
+ Array.from(actionMetadataById.entries()).filter(([, action]) => action.action_family === ACTION_FAMILIES.OUTPUT).map(([actionId]) => actionId)
65402
66029
  );
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();
66030
+ const outputThresholds = recalculatedThresholds.filter((threshold) => {
66031
+ if (outputActionIds.has(threshold.action_id)) return true;
66032
+ return normalizeActionFamily({
66033
+ actionName: threshold.action_name
66034
+ }) === ACTION_FAMILIES.OUTPUT;
65406
66035
  });
65407
- const thresholdDayOutput = packagingThresholds.reduce(
66036
+ const thresholdDayOutput = outputThresholds.reduce(
65408
66037
  (sum, threshold) => sum + (Number(threshold.total_day_output) || 0),
65409
66038
  0
65410
66039
  );
65411
- const thresholdPPH = packagingThresholds.reduce(
66040
+ const thresholdPPH = outputThresholds.reduce(
65412
66041
  (sum, threshold) => sum + (Number(threshold.pph_threshold) || 0),
65413
66042
  0
65414
66043
  );
@@ -66619,7 +67248,7 @@ var TargetsViewUI = ({
66619
67248
  "aria-label": `Action type for ${formattedName}`,
66620
67249
  children: [
66621
67250
  /* @__PURE__ */ jsx("option", { value: "assembly", className: "py-2", children: "Assembly" }),
66622
- /* @__PURE__ */ jsx("option", { value: "packaging", className: "py-2", children: "Packaging" })
67251
+ /* @__PURE__ */ jsx("option", { value: "output", className: "py-2", children: ACTION_NAMES.OUTPUT })
66623
67252
  ]
66624
67253
  }
66625
67254
  ) }),
@@ -66690,7 +67319,7 @@ var TargetsViewUI = ({
66690
67319
  "aria-label": `Action type for ${formattedName}`,
66691
67320
  children: [
66692
67321
  /* @__PURE__ */ jsx("option", { value: "assembly", children: "Assembly" }),
66693
- /* @__PURE__ */ jsx("option", { value: "packaging", children: "Packaging" })
67322
+ /* @__PURE__ */ jsx("option", { value: "output", children: ACTION_NAMES.OUTPUT })
66694
67323
  ]
66695
67324
  }
66696
67325
  )
@@ -66895,14 +67524,20 @@ var TargetsView = ({
66895
67524
  throw new Error("Failed to fetch bulk targets data");
66896
67525
  }
66897
67526
  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) {
67527
+ const assemblyAction = data.actions[ACTION_FAMILIES.ASSEMBLY] || Object.values(data.actions).find((a) => normalizeActionFamily({
67528
+ actionFamily: a.action_family,
67529
+ actionName: a.action_name
67530
+ }) === ACTION_FAMILIES.ASSEMBLY);
67531
+ const outputAction = data.actions[ACTION_FAMILIES.OUTPUT] || Object.values(data.actions).find((a) => normalizeActionFamily({
67532
+ actionFamily: a.action_family,
67533
+ actionName: a.action_name
67534
+ }) === ACTION_FAMILIES.OUTPUT);
67535
+ if (!assemblyAction || !outputAction) {
66901
67536
  throw new Error("Could not find required actions in bulk response");
66902
67537
  }
66903
67538
  const actionIdsData = {
66904
67539
  assembly: assemblyAction.id,
66905
- packaging: packagingAction.id
67540
+ output: outputAction.id
66906
67541
  };
66907
67542
  setActionIds(actionIdsData);
66908
67543
  const newAllShiftsData = {};
@@ -66947,12 +67582,16 @@ var TargetsView = ({
66947
67582
  let actionType = "assembly";
66948
67583
  let actionId = actionIdsData.assembly;
66949
67584
  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") {
67585
+ const effectiveActionFamily = normalizeActionFamily({
67586
+ actionFamily: threshold?.action_family,
67587
+ actionType: ws.action_type
67588
+ });
67589
+ if (effectiveActionFamily === ACTION_FAMILIES.OUTPUT || effectiveActionId === outputAction.id || !effectiveActionId && ws.action_type === "output") {
67590
+ actionType = "output";
67591
+ actionId = effectiveActionId || outputAction.id;
67592
+ } else if (effectiveActionFamily === ACTION_FAMILIES.ASSEMBLY || effectiveActionId === assemblyAction.id || !effectiveActionId && ws.action_type === "assembly") {
66954
67593
  actionType = "assembly";
66955
- actionId = assemblyAction.id;
67594
+ actionId = effectiveActionId || assemblyAction.id;
66956
67595
  }
66957
67596
  return {
66958
67597
  id: ws.id,
@@ -67224,7 +67863,9 @@ var TargetsView = ({
67224
67863
  // Round to whole number
67225
67864
  ideal_cycle_time: Number(ws.targetCycleTime) || 0,
67226
67865
  total_day_output: Number(ws.targetDayOutput) || 0,
67227
- action_name: ws.actionType === "assembly" ? ACTION_NAMES.ASSEMBLY : ACTION_NAMES.PACKAGING,
67866
+ action_name: ws.actionType === "assembly" ? ACTION_NAMES.ASSEMBLY : ACTION_NAMES.OUTPUT,
67867
+ action_family: ws.actionType,
67868
+ display_name: ws.actionType === "assembly" ? ACTION_NAMES.ASSEMBLY : ACTION_NAMES.OUTPUT,
67228
67869
  updated_by: currentEffectiveUserId,
67229
67870
  // Use the potentially hardcoded ID
67230
67871
  ...skuEnabled && lineDataToSave.selectedSKU ? { sku_id: lineDataToSave.selectedSKU.id } : {}
@@ -67232,7 +67873,7 @@ var TargetsView = ({
67232
67873
  console.log(`[handleSaveLine] workspaceThresholdUpdates for ${lineId}:`, workspaceThresholdUpdates);
67233
67874
  await workspaceService.updateActionThresholds(workspaceThresholdUpdates);
67234
67875
  console.log(`[handleSaveLine] Successfully updated action thresholds for ${lineId}`);
67235
- const packagingWorkspaces = lineDataToSave.workspaces.filter((ws) => ws.actionType === "packaging");
67876
+ const outputWorkspaces = lineDataToSave.workspaces.filter((ws) => ws.actionType === "output");
67236
67877
  let resolvedLineThresholdSkuId = lineDataToSave.selectedSKU?.id || null;
67237
67878
  if (!resolvedLineThresholdSkuId) {
67238
67879
  const { data: dummySkuRows, error: dummySkuError } = await supabase.from("skus").select("id").eq("line_id", lineId).eq("sku_definition", "dummy_definition").eq("is_active", true).limit(1);
@@ -67250,8 +67891,8 @@ var TargetsView = ({
67250
67891
  date: currentDate,
67251
67892
  shift_id: selectedShift,
67252
67893
  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),
67894
+ threshold_day_output: outputWorkspaces.reduce((acc, ws) => acc + (Number(ws.targetDayOutput) || 0), 0),
67895
+ threshold_pph: outputWorkspaces.reduce((acc, ws) => acc + (ws.targetPPH ? Math.round(Number(ws.targetPPH)) : 0), 0),
67255
67896
  // Round each PPH value
67256
67897
  sku_id: resolvedLineThresholdSkuId
67257
67898
  };
@@ -67779,6 +68420,7 @@ var WorkspaceDetailView = ({
67779
68420
  avg_efficiency: Number(cachedOverviewMetrics.efficiency || 0),
67780
68421
  total_actions: totalActions,
67781
68422
  hourly_action_counts: [],
68423
+ hourly_cycle_times: [],
67782
68424
  workspace_rank: 0,
67783
68425
  total_workspaces: 0,
67784
68426
  ideal_output_until_now: idealOutput,
@@ -67789,6 +68431,22 @@ var WorkspaceDetailView = ({
67789
68431
  }, [cachedOverviewMetrics, shiftConfig?.shifts]);
67790
68432
  const workspace = (isHistoricView ? historicMetrics : liveMetrics) || cachedDetailedMetrics || overviewFallback;
67791
68433
  const detailedWorkspaceMetrics = (isHistoricView ? historicMetrics : liveMetrics) || cachedDetailedMetrics;
68434
+ const cycleTimeChartData = useMemo(
68435
+ () => Array.isArray(workspace?.hourly_cycle_times) ? workspace.hourly_cycle_times.map((value) => {
68436
+ const numericValue = Number(value);
68437
+ return Number.isFinite(numericValue) ? numericValue : 0;
68438
+ }) : [],
68439
+ [workspace?.hourly_cycle_times]
68440
+ );
68441
+ const cycleTimeDatasetKey = useMemo(
68442
+ () => [
68443
+ workspace?.workspace_id || workspaceId || "workspace",
68444
+ date || workspace?.date || "live",
68445
+ parsedShiftId ?? workspace?.shift_id ?? "current",
68446
+ "hourly"
68447
+ ].join(":"),
68448
+ [workspace?.workspace_id, workspaceId, date, workspace?.date, parsedShiftId, workspace?.shift_id]
68449
+ );
67792
68450
  const hasWorkspaceSnapshot = Boolean(workspace);
67793
68451
  const loading = ((isHistoricView ? historicLoading : liveLoading) || isShiftConfigLoading) && !hasWorkspaceSnapshot;
67794
68452
  const error = isHistoricView ? historicError : liveError;
@@ -68030,10 +68688,47 @@ var WorkspaceDetailView = ({
68030
68688
  return filterDataByDateKeyRange(monthlyData, range);
68031
68689
  }, [monthlyData, range]);
68032
68690
  const formattedWorkspaceName = displayName || formatWorkspaceName3(workspace?.workspace_name || "", effectiveLineId);
68033
- const shouldShowCycleTimeChart = !isUptimeMode && (showCycleTimeChart ?? formattedWorkspaceName.startsWith("FINAL ASSY"));
68691
+ const workspaceActionType = workspace && "action_type" in workspace ? workspace.action_type : void 0;
68692
+ const workspaceAssemblyEnabled = workspace && "line_assembly_enabled" in workspace ? workspace.line_assembly_enabled === true : false;
68693
+ const isAssemblyWorkspace = workspaceActionType === "assembly" || workspaceAssemblyEnabled;
68694
+ const shouldShowCycleTimeChart = !isUptimeMode && (showCycleTimeChart ?? isAssemblyWorkspace);
68034
68695
  const showIdleBreakdownChart = !shouldShowCycleTimeChart && idleTimeVlmEnabled;
68035
68696
  const idleClipDate = date || workspace?.date || calculatedOperationalDate || getOperationalDate(timezone);
68036
68697
  const idleClipShiftId = parsedShiftId ?? workspace?.shift_id;
68698
+ const hourlyIdleMinutes = useMemo(() => {
68699
+ if (!shouldShowCycleTimeChart || !workspace?.idle_time_hourly || !workspace?.shift_start) return [];
68700
+ const parseTimeToMinutes3 = (time2) => {
68701
+ const [h, m] = time2.split(":").map(Number);
68702
+ if (!Number.isFinite(h) || !Number.isFinite(m)) return 0;
68703
+ return h * 60 + m;
68704
+ };
68705
+ const startTotal = parseTimeToMinutes3(workspace.shift_start);
68706
+ const endTotalRaw = workspace.shift_end ? parseTimeToMinutes3(workspace.shift_end) : startTotal + 11 * 60;
68707
+ const endTotal = endTotalRaw <= startTotal ? endTotalRaw + 24 * 60 : endTotalRaw;
68708
+ const shiftDuration = Math.max(60, endTotal - startTotal);
68709
+ const totalHourSlots = Math.max(1, Math.ceil(shiftDuration / 60));
68710
+ const idleTimeHourlyObj = workspace.idle_time_hourly || {};
68711
+ const result = Array(totalHourSlots).fill(0);
68712
+ for (let i = 0; i < totalHourSlots; i++) {
68713
+ const startSlotMins = startTotal + i * 60;
68714
+ let endSlotMins = startSlotMins + 60;
68715
+ if (endSlotMins > endTotal) endSlotMins = endTotal;
68716
+ let idleCount = 0;
68717
+ for (let m = startSlotMins; m < endSlotMins; m++) {
68718
+ const hourKey = Math.floor(m / 60) % 24;
68719
+ const minuteKey = m % 60;
68720
+ const hourData = idleTimeHourlyObj[hourKey.toString()] || [];
68721
+ if (Array.isArray(hourData)) {
68722
+ const val = hourData[minuteKey];
68723
+ if (val === 1 || val === "1") {
68724
+ idleCount++;
68725
+ }
68726
+ }
68727
+ }
68728
+ result[i] = idleCount;
68729
+ }
68730
+ return result;
68731
+ }, [shouldShowCycleTimeChart, workspace?.idle_time_hourly, workspace?.shift_start, workspace?.shift_end]);
68037
68732
  const shiftDurationMinutes = useMemo(
68038
68733
  () => getShiftDurationMinutes(workspace?.shift_start, workspace?.shift_end),
68039
68734
  [workspace?.shift_start, workspace?.shift_end]
@@ -68106,7 +68801,7 @@ var WorkspaceDetailView = ({
68106
68801
  }
68107
68802
  }, [returnUrl]);
68108
68803
  const handleBackNavigation = () => {
68109
- if (date || shift) {
68804
+ if (isHistoricView) {
68110
68805
  setActiveTab("monthly_history");
68111
68806
  if (onNavigate) {
68112
68807
  const params = new URLSearchParams();
@@ -68270,7 +68965,7 @@ var WorkspaceDetailView = ({
68270
68965
  BackButtonMinimal,
68271
68966
  {
68272
68967
  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",
68968
+ text: previousView === "line_monthly_history" ? "Back to Line History" : returnUrl && returnUrl.includes("monthly_history") ? "Back to Line History" : returnUrl && returnUrl.includes("/kpis/") ? "Back to KPIs" : returnUrl && returnUrl.includes("/leaderboard/") ? "Back to Leaderboard" : isHistoricView && activeTab !== "monthly_history" ? "Back to Monthly History" : "Back",
68274
68969
  size: "default",
68275
68970
  "aria-label": "Navigate back to previous page"
68276
68971
  }
@@ -68447,7 +69142,8 @@ var WorkspaceDetailView = ({
68447
69142
  {
68448
69143
  workspace,
68449
69144
  idleTimeReasons: idleTimeChartData,
68450
- efficiencyLegend
69145
+ efficiencyLegend,
69146
+ hourlyCycleTimes: cycleTimeChartData
68451
69147
  }
68452
69148
  ) }),
68453
69149
  activeTab === "monthly_history" && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
@@ -68528,7 +69224,7 @@ var WorkspaceDetailView = ({
68528
69224
  animate: "animate",
68529
69225
  children: [
68530
69226
  /* @__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" }),
69227
+ /* @__PURE__ */ jsx("h3", { className: "text-lg font-bold text-gray-700", children: isUptimeMode ? "Machine Utilization" : shouldShowCycleTimeChart ? "Cycle time trend" : "Hourly Output" }),
68532
69228
  !isUptimeMode && /* @__PURE__ */ jsx(
68533
69229
  "button",
68534
69230
  {
@@ -68561,9 +69257,14 @@ var WorkspaceDetailView = ({
68561
69257
  ) : shouldShowCycleTimeChart ? /* @__PURE__ */ jsx(
68562
69258
  CycleTimeOverTimeChart,
68563
69259
  {
68564
- data: workspace.hourly_action_counts || [],
69260
+ data: cycleTimeChartData,
68565
69261
  idealCycleTime: workspace.ideal_cycle_time || 0,
68566
- shiftStart: workspace.shift_start || ""
69262
+ shiftStart: workspace.shift_start || "",
69263
+ shiftEnd: workspace.shift_end || "",
69264
+ xAxisMode: "hourly",
69265
+ datasetKey: cycleTimeDatasetKey,
69266
+ showIdleTime: showChartIdleTime,
69267
+ idleTimeData: hourlyIdleMinutes
68567
69268
  }
68568
69269
  ) : /* @__PURE__ */ jsx(
68569
69270
  HourlyOutputChart2,
@@ -68610,7 +69311,8 @@ var WorkspaceDetailView = ({
68610
69311
  {
68611
69312
  workspace,
68612
69313
  legend: efficiencyLegend,
68613
- layout: "stack"
69314
+ layout: "stack",
69315
+ idleTimeData: idleTimeVlmEnabled ? idleTimeData : void 0
68614
69316
  }
68615
69317
  ) : /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(WorkspaceMetricCards, { workspace, legend: efficiencyLegend, className: "flex-1" }) })
68616
69318
  ] }),
@@ -68655,7 +69357,7 @@ var WorkspaceDetailView = ({
68655
69357
  animate: "animate",
68656
69358
  children: [
68657
69359
  /* @__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" }),
69360
+ /* @__PURE__ */ jsx("h3", { className: "text-lg font-bold text-gray-700", children: isUptimeMode ? "Machine Utilization" : shouldShowCycleTimeChart ? "Cycle time trend" : "Hourly Output" }),
68659
69361
  !isUptimeMode && /* @__PURE__ */ jsx(
68660
69362
  "button",
68661
69363
  {
@@ -68684,9 +69386,14 @@ var WorkspaceDetailView = ({
68684
69386
  ) : shouldShowCycleTimeChart ? /* @__PURE__ */ jsx(
68685
69387
  CycleTimeOverTimeChart,
68686
69388
  {
68687
- data: workspace.hourly_action_counts || [],
69389
+ data: cycleTimeChartData,
68688
69390
  idealCycleTime: workspace.ideal_cycle_time || 0,
68689
- shiftStart: workspace.shift_start || ""
69391
+ shiftStart: workspace.shift_start || "",
69392
+ shiftEnd: workspace.shift_end || "",
69393
+ xAxisMode: "hourly",
69394
+ datasetKey: cycleTimeDatasetKey,
69395
+ showIdleTime: showChartIdleTime,
69396
+ idleTimeData: hourlyIdleMinutes
68690
69397
  }
68691
69398
  ) : /* @__PURE__ */ jsx(
68692
69399
  HourlyOutputChart2,
@@ -68738,7 +69445,8 @@ var WorkspaceDetailView = ({
68738
69445
  workspace,
68739
69446
  legend: efficiencyLegend,
68740
69447
  layout: "grid",
68741
- className: desktopBottomSectionClass
69448
+ className: desktopBottomSectionClass,
69449
+ idleTimeData: idleTimeVlmEnabled ? idleTimeData : void 0
68742
69450
  }
68743
69451
  ) : /* @__PURE__ */ jsx("div", { className: clsx("flex min-h-0", desktopBottomSectionClass), children: /* @__PURE__ */ jsx(WorkspaceMetricCards, { workspace, legend: efficiencyLegend, className: "flex-1" }) })
68744
69452
  ] })
@@ -68768,6 +69476,7 @@ var WorkspaceDetailView = ({
68768
69476
  availableShifts: shiftConfig?.shifts?.map((s) => ({ id: s.shiftId, name: s.shiftName })),
68769
69477
  legend: efficiencyLegend,
68770
69478
  trendSummary: workspaceMonthlyTrend,
69479
+ isAssemblyWorkspace,
68771
69480
  onDateSelect: (selectedDate, shiftId) => {
68772
69481
  if (onDateSelect) {
68773
69482
  onDateSelect(selectedDate, shiftId);
@@ -74855,6 +75564,11 @@ var normalizeTrend = (value) => ({
74855
75564
  });
74856
75565
  var normalizeIdleBreakdown = (value) => (value || []).map((item) => ({
74857
75566
  reason: item?.reason?.trim() || "Unknown",
75567
+ reason_key: item?.reason_key?.trim() || item?.reason?.trim() || "unknown",
75568
+ display_name: item?.display_name?.trim() || void 0,
75569
+ palette_token: item?.palette_token?.trim() || void 0,
75570
+ icon_token: item?.icon_token?.trim() || void 0,
75571
+ is_known: typeof item?.is_known === "boolean" ? item.is_known : null,
74858
75572
  percentage: normalizeNumber(item?.percentage),
74859
75573
  total_duration_seconds: normalizeNumber(item?.total_duration_seconds),
74860
75574
  efficiency_loss_percentage: normalizeNumber(item?.efficiency_loss_percentage),
@@ -75906,7 +76620,12 @@ var IdleBreakdownCard = React141__default.memo(({
75906
76620
  const showInitialSkeleton = idle.loading && idle.lastUpdated === null;
75907
76621
  const idleBreakdown = React141__default.useMemo(() => {
75908
76622
  return idle.data.map((item) => ({
75909
- name: item.reason?.trim() || "Unknown",
76623
+ name: item.display_name?.trim() || item.reason?.trim() || "Unknown",
76624
+ reasonKey: item.reason_key?.trim() || item.reason?.trim() || "unknown",
76625
+ displayName: item.display_name?.trim() || item.reason?.trim() || "Unknown",
76626
+ paletteToken: item.palette_token?.trim(),
76627
+ iconToken: item.icon_token?.trim(),
76628
+ isKnown: item.is_known ?? void 0,
75910
76629
  value: toNumber3(item.percentage) || 0,
75911
76630
  totalDurationSeconds: toNumber3(item.total_duration_seconds),
75912
76631
  efficiencyLossPercentage: toNumber3(item.efficiency_loss_percentage),
@@ -77198,4 +77917,4 @@ var streamProxyConfig = {
77198
77917
  }
77199
77918
  };
77200
77919
 
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 };
77920
+ export { ACTION_FAMILIES, ACTION_NAMES, AIAgentView_default as AIAgentView, AcceptInvite, AcceptInviteView_default as AcceptInviteView, AdvancedFilterDialog, AdvancedFilterPanel, AudioService, AuthCallback, AuthCallbackView_default as AuthCallbackView, AuthProvider, AuthService, AuthenticatedBottleneckClipsView, AuthenticatedFactoryView, AuthenticatedHelpView, AuthenticatedHomeView, AuthenticatedShiftsView, AuthenticatedTargetsView, AuthenticatedTicketsView, AuthenticatedWorkspaceHealthView, AvatarUpload, AxelNotificationPopup, AxelOrb, BackButton, BackButtonMinimal, BarChart, BaseHistoryCalendar, BottleneckClipsModal, BottleneckClipsView_default as BottleneckClipsView, BottlenecksContent, BreakNotificationPopup, CachePrefetchStatus, Card2 as Card, CardContent2 as CardContent, CardDescription2 as CardDescription, CardFooter2 as CardFooter, CardHeader2 as CardHeader, CardTitle2 as CardTitle, ChangeRoleDialog, ClipFilterProvider, ClipsCostView_default as ClipsCostView, CompactWorkspaceHealthCard, ConfirmRemoveUserDialog, CongratulationsOverlay, CroppedHlsVideoPlayer, CroppedVideoPlayer, CycleTimeChart, CycleTimeOverTimeChart, DEFAULT_ANALYTICS_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_CONFIG, DEFAULT_DATABASE_CONFIG, DEFAULT_DATE_TIME_CONFIG, DEFAULT_ENDPOINTS_CONFIG, DEFAULT_ENTITY_CONFIG, DEFAULT_HOME_VIEW_CONFIG, DEFAULT_MAP_VIEW_CONFIG, DEFAULT_SHIFT_CONFIG, DEFAULT_SHIFT_DATA, DEFAULT_THEME_CONFIG, DEFAULT_VIDEO_CONFIG, DEFAULT_WORKSPACE_CONFIG, DEFAULT_WORKSPACE_POSITIONS, DashboardHeader, DashboardLayout, DashboardOverridesProvider, DashboardProvider, DateDisplay_default as DateDisplay, DateTimeDisplay, DebugAuth, DebugAuthView_default as DebugAuthView, DetailedHealthStatus, DiagnosisVideoModal, EFFICIENCY_ON_TRACK_THRESHOLD, EmptyStateMessage, EncouragementOverlay, FactoryAssignmentDropdown, FactoryView_default as FactoryView, FileManagerFilters, FilterDialogTrigger, FirstTimeLoginDebug, FirstTimeLoginHandler, FittingTitle, GaugeChart, GridComponentsPlaceholder, HamburgerButton, Header, HealthDateShiftSelector, HealthStatusGrid, HealthStatusIndicator, HelpView_default as HelpView, HlsVideoPlayer, HomeView_default as HomeView, HourlyOutputChart2 as HourlyOutputChart, HourlyUptimeChart, ISTTimer_default as ISTTimer, IdleTimeVlmConfigProvider, ImprovementCenterView_default as ImprovementCenterView, InlineEditableText, InteractiveOnboardingTour, InvitationService, InvitationsTable, InviteUserDialog, KPICard, KPIDetailView_default as KPIDetailView, KPIGrid, KPIHeader, KPISection, KPIsOverviewView_default as KPIsOverviewView, LINE_1_UUID, LINE_2_UUID, LargeOutputProgressChart, LeaderboardDetailView_default as LeaderboardDetailView, Legend5 as Legend, LineAssignmentDropdown, LineChart, LineHistoryCalendar, LineMonthlyHistory, LineMonthlyPdfGenerator, LinePdfExportButton, LinePdfGenerator, LineWhatsAppShareButton, LinesService, LiveTimer, LoadingInline, LoadingOverlay_default as LoadingOverlay, LoadingPage_default as LoadingPage, LoadingSkeleton, LoadingState, LoginPage, LoginView_default as LoginView, Logo, MainLayout, MapGridView, MetricCard_default as MetricCard, MinimalOnboardingPopup, MobileMenuProvider, NewClipsNotification, NoWorkspaceData, OnboardingDemo, OnboardingTour, OptifyeAgentClient, OptifyeLogoLoader_default as OptifyeLogoLoader, OutputProgressChart, PageHeader, PieChart4 as PieChart, PlantHeadView_default as PlantHeadView, PlayPauseIndicator, PrefetchConfigurationError, PrefetchError, PrefetchEvents, PrefetchStatus, PrefetchTimeoutError, ProfileView_default as ProfileView, RegistryProvider, RoleBadge, S3ClipsSupabaseService as S3ClipsService, S3Service, SKUManagementView, SOPComplianceChart, SSEChatClient, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, SessionTracker, SessionTrackingContext, SessionTrackingProvider, SettingsPopup, ShiftDisplay_default as ShiftDisplay, ShiftsView_default as ShiftsView, SideNavBar, SignupWithInvitation, SilentErrorBoundary, SimpleOnboardingPopup, SingleVideoStream_default as SingleVideoStream, Skeleton, SubscriptionManager, SubscriptionManagerProvider, SupabaseProvider, SupervisorDropdown_default as SupervisorDropdown, SupervisorManagementView_default as SupervisorManagementView, SupervisorService, TargetWorkspaceGrid, TargetsView_default as TargetsView, TeamManagementView_default as TeamManagementView, ThreadSidebar, TicketHistory_default as TicketHistory, TicketHistoryService, TicketsView_default as TicketsView, TimeDisplay_default as TimeDisplay, TimePickerDropdown, Timer_default as Timer, TimezoneProvider, TimezoneService, UptimeDonutChart, UptimeLineChart, UptimeMetricCards, UserAvatar, UserManagementService, UserManagementTable, UserService, UserUsageDetailModal, UserUsageStats, VideoCard, VideoGridView, VideoPlayer, VideoPreloader, WORKSPACE_POSITIONS, WhatsAppShareButton, WorkspaceCard, WorkspaceCycleTimeMetricCards, WorkspaceDetailView_default as WorkspaceDetailView, WorkspaceDisplayNameExample, WorkspaceGrid, WorkspaceGridItem, WorkspaceHealthCard, WorkspaceHealthView_default as WorkspaceHealthView, WorkspaceHistoryCalendar, WorkspaceMetricCards, WorkspaceMetricCardsImpl, WorkspaceMonthlyDataFetcher, WorkspaceMonthlyHistory, WorkspaceMonthlyPdfGenerator, WorkspacePdfExportButton, WorkspacePdfGenerator, WorkspaceWhatsAppShareButton, actionService, aggregateKPIsFromLineMetricsRows, alertsService, apiUtils, areAllLinesOnSameShift, authCoreService, authOTPService, authRateLimitService, awardsService, buildDateKey, buildKPIsFromLineMetricsRow, buildShiftGroupsKey, canRoleAccessDashboardPath, canRoleAccessTeamManagement, canRoleAssignFactories, canRoleAssignLines, canRoleChangeRole, canRoleInviteRole, canRoleManageCompany, canRoleManageTargets, canRoleManageUsers, canRoleRemoveUser, canRoleViewClipsCost, canRoleViewUsageStats, captureSentryException, captureSentryMessage, checkRateLimit2 as checkRateLimit, clearAllRateLimits2 as clearAllRateLimits, clearRateLimit2 as clearRateLimit, clearS3VideoCache, clearS3VideoFromCache, clearSentryContext, clearWorkspaceDisplayNamesCache, cn, createDefaultKPIs, createInvitationService, createLinesService, createSessionTracker, createStorageService, createStreamProxyHandler, createSupabaseClient, createSupervisorService, createThrottledReload, createUserManagementService, createUserService, dashboardService, deleteThread, fetchIdleTimeReasons, filterDataByDateKeyRange, forceRefreshWorkspaceDisplayNames, formatAwardMonth, formatDateInZone, formatDateKeyForDisplay, formatDateTimeInZone, formatDuration2 as formatDuration, formatISTDate, formatIdleTime, formatRangeLabel, formatReasonLabel, formatRelativeTime, formatTimeInZone, fromUrlFriendlyName, getActionDisplayName, getAllLineDisplayNames, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAllWorkspaceDisplayNamesSnapshot, getAnonClient, getAssignableRoles, getAssignmentColumnLabel, getAvailableShiftIds, getAwardBadgeType, getAwardDescription, getAwardTitle, getBrowserName, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getConfiguredLineIds, getCoreSessionRecordingProperties, getCoreSessionReplayUrl, getCurrentShift, getCurrentShiftForLine, getCurrentTimeInZone, getCurrentWeekFullRange, getCurrentWeekToDateRange, getDashboardHeaderTimeInZone, getDateKeyFromDate, getDaysDifferenceInZone, getDefaultCameraStreamUrl, getDefaultLineId, getDefaultTabForWorkspace, getInitials, getLineDisplayName, getManufacturingInsights, getMetricsTablePrefix, getMonthKeyBounds, getMonthWeekRanges, getNextUpdateInterval, getOperationalDate, getRoleAssignmentKind, getRoleDescription, getRoleLabel, getRoleMetadata, getRoleNavPaths, getS3SignedUrl, getS3VideoSrc, getShiftData, getShiftNameById, getShiftWorkDurationSeconds, getShortShiftName, getShortWorkspaceDisplayName, getShortWorkspaceDisplayNameAsync, getStoredWorkspaceMappings, getSubscriptionManager, getThreadMessages, getUniformShiftGroup, getUserThreads, getUserThreadsPaginated, getVisibleRolesForCurrentUser, getWorkspaceDisplayName, getWorkspaceDisplayNameAsync, getWorkspaceDisplayNamesMap, getWorkspaceFromUrl, getWorkspaceNavigationParams, groupLinesByShift, hasAnyShiftData, identifyCoreUser, initializeCoreMixpanel, isEfficiencyOnTrack, isFactoryScopedRole, isFullMonthRange, isLegacyConfiguration, isPrefetchError, isRecentFlowVideoGridMetricMode, isSafari, isSupervisorRole, isTransitionPeriod, isUrlPermanentlyFailed, isValidFactoryViewConfiguration, isValidLineInfoPayload, isValidPrefetchParams, isValidPrefetchStatus, isValidWorkspaceDetailedMetricsPayload, isValidWorkspaceMetricsPayload, isWipGatedVideoGridMetricMode, isWorkspaceDisplayNamesLoaded, isWorkspaceDisplayNamesLoading, lineLeaderboardService, linesService, mergeWithDefaultConfig, migrateLegacyConfiguration, normalizeActionFamily, normalizeDateKeyRange, normalizeRoleLevel, normalizeVideoGridMetricMode, optifyeAgentClient, parseDateKeyToDate, parseS3Uri, preInitializeWorkspaceDisplayNames, preloadS3Video, preloadS3VideoUrl, preloadS3VideosUrl, preloadVideoUrl, preloadVideosUrl, qualityService, realtimeService, refreshWorkspaceDisplayNames, resetCoreMixpanel, resetFailedUrl, resetSubscriptionManager, s3VideoPreloader, setSentryUserContext, setSentryWorkspaceContext, shuffleArray, simulateApiDelay, skuService, startCoreSessionRecording, stopCoreSessionRecording, storeWorkspaceMapping, streamProxyConfig, subscribeWorkspaceDisplayNames, throttledReloadDashboard, toUrlFriendlyName, trackCoreEvent, trackCorePageView, transformToChartData, updateThreadTitle, upsertWorkspaceDisplayNameInCache, useAccessControl, useActiveBreaks, useActiveLineId, useAllWorkspaceMetrics, useAnalyticsConfig, useAppTimezone, useAudioService, useAuth, useAuthConfig, useAxelNotifications, useCanSaveTargets, useClipFilter, useClipTypes, useClipTypesWithCounts, useClipsInit, useCompanyClipsCost, useCompanyUsersUsage, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useDynamicShiftConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHasLineAccess, useHideMobileHeader, useHistoricWorkspaceMetrics, useHlsStream, useHlsStreamWithCropping, useHookOverride, useHourEndTimer, useHourlyTargetAchievements, useHourlyTargetMisses, useIdleTimeClipClassifications, useIdleTimeReasons, useIdleTimeVlmConfig, useKpiTrends, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineShiftConfig, useLineSupervisor, useLineWorkspaceMetrics, useLines, useMessages, useMetrics, useMobileMenu, useMonthlyTrend, useMultiLineShiftConfigs, useNavigation, useOperationalShiftKey, useOptionalSupabase, useOverrides, usePageOverride, usePrefetchClipCounts, useRealtimeLineMetrics, useRegistry, useSKUs, useSessionKeepAlive, useSessionTracking, useSessionTrackingContext, useShiftConfig, useShiftGroups, useShifts, useSubscriptionManager, useSubscriptionManagerSafe, useSupabase, useSupabaseClient, useSupervisorsByLineIds, useTargets, useTeamManagementPermissions, useTheme, useThemeConfig, useThreads, useTicketHistory, useTimezoneContext, useUserLineAccess, useUserUsage, useVideoConfig, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceHealthById, useWorkspaceHealthLastSeen, useWorkspaceHealthStatus, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, useWorkspaceUptimeTimeline, useWorkspaceVideoStreams, userService, videoPrefetchManager, videoPreloader, weeklyTopPerformerService, whatsappService, withAccessControl, withAuth, withRegistry, withTimezone, workspaceHealthService, workspaceService };