@optifye/dashboard-core 6.12.5 → 6.12.6

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.js CHANGED
@@ -21902,6 +21902,24 @@ var getConfigurableShortWorkspaceDisplayName = (workspaceId, workspaceConfig, li
21902
21902
  return fullName;
21903
21903
  };
21904
21904
 
21905
+ // src/lib/utils/efficiencyValidity.ts
21906
+ var MIN_VALID_OUTPUT_EFFICIENCY = 5;
21907
+ var MIN_VALID_UPTIME_EFFICIENCY = 1;
21908
+ var normalizeMonitoringMode = (mode) => String(mode ?? "").trim().toLowerCase() === "uptime" ? "uptime" : "output";
21909
+ var toFiniteNumberOrNull = (value) => {
21910
+ if (typeof value === "number" && Number.isFinite(value)) return value;
21911
+ if (typeof value === "string" && value.trim() !== "") {
21912
+ const parsed = Number(value);
21913
+ return Number.isFinite(parsed) ? parsed : null;
21914
+ }
21915
+ return null;
21916
+ };
21917
+ var isValidAggregateEfficiency = (monitoringMode, efficiency) => {
21918
+ const value = toFiniteNumberOrNull(efficiency);
21919
+ if (value === null) return false;
21920
+ return normalizeMonitoringMode(monitoringMode) === "uptime" ? value >= MIN_VALID_UPTIME_EFFICIENCY : value >= MIN_VALID_OUTPUT_EFFICIENCY;
21921
+ };
21922
+
21905
21923
  // src/lib/utils/kpis.ts
21906
21924
  var toNumber = (value) => {
21907
21925
  if (typeof value === "number" && Number.isFinite(value)) return value;
@@ -21957,7 +21975,9 @@ var buildKPIsFromLineMetricsRow = (row) => {
21957
21975
  };
21958
21976
  var aggregateKPIsFromLineMetricsRows = (rows) => {
21959
21977
  if (!rows || rows.length === 0) return createDefaultKPIs();
21960
- const eligibleRows = rows.filter((row) => toNumber(row?.avg_efficiency) >= 5);
21978
+ const eligibleRows = rows.filter(
21979
+ (row) => isValidAggregateEfficiency(row?.monitoring_mode ?? row?.monitoringMode, row?.avg_efficiency)
21980
+ );
21961
21981
  if (eligibleRows.length === 0) return createDefaultKPIs();
21962
21982
  const currentOutputSum = eligibleRows.reduce((sum, row) => sum + toNumber(row.current_output), 0);
21963
21983
  const lineThresholdSum = eligibleRows.reduce(
@@ -37285,8 +37305,8 @@ var HourlyOutputChart = React144__namespace.default.memo(
37285
37305
  HourlyOutputChart.displayName = "HourlyOutputChart";
37286
37306
 
37287
37307
  // src/components/dashboard/grid/videoGridMetricUtils.ts
37308
+ var VIDEO_GRID_LEGEND_LABEL = "Real-Time efficiency";
37288
37309
  var MAP_GRID_LEGEND_LABEL = "Efficiency";
37289
- var MIXED_VIDEO_GRID_LEGEND_LABEL = "Live Efficiency";
37290
37310
  var isFiniteNumber2 = (value) => typeof value === "number" && Number.isFinite(value);
37291
37311
  var isVideoGridRecentFlowEnabled = (workspace) => isRecentFlowVideoGridMetricMode(
37292
37312
  workspace.video_grid_metric_mode,
@@ -37298,7 +37318,7 @@ var isVideoGridWipGated = (workspace) => isWipGatedVideoGridMetricMode(
37298
37318
  );
37299
37319
  var hasVideoGridRecentFlow = (workspace) => isVideoGridRecentFlowEnabled(workspace) && isFiniteNumber2(workspace.recent_flow_percent);
37300
37320
  var isVideoGridRecentFlowUnavailable = (workspace) => isVideoGridRecentFlowEnabled(workspace) && !hasVideoGridRecentFlow(workspace);
37301
- var getVideoGridMetricValue = (workspace) => {
37321
+ var getRawVideoGridMetricValue = (workspace) => {
37302
37322
  const recentFlowPercent = workspace.recent_flow_percent;
37303
37323
  if (hasVideoGridRecentFlow(workspace) && isFiniteNumber2(recentFlowPercent)) {
37304
37324
  return recentFlowPercent;
@@ -37310,7 +37330,7 @@ var getVideoGridMetricValue = (workspace) => {
37310
37330
  };
37311
37331
  var hasIncomingWipMapping = (workspace) => Boolean(workspace.incoming_wip_buffer_name);
37312
37332
  var getVideoGridBaseColorState = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => {
37313
- const metricValue = getVideoGridMetricValue(workspace);
37333
+ const metricValue = getRawVideoGridMetricValue(workspace);
37314
37334
  if (!isFiniteNumber2(metricValue)) {
37315
37335
  return "neutral";
37316
37336
  }
@@ -37334,6 +37354,25 @@ var isLowWipGreenOverride = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => {
37334
37354
  }
37335
37355
  return isFiniteNumber2(workspace.incoming_wip_current) && workspace.incoming_wip_current <= 1;
37336
37356
  };
37357
+ var isHighEfficiencyRedFlowOverride = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => {
37358
+ if (workspace.scheduled_break_active === true) {
37359
+ return false;
37360
+ }
37361
+ if (workspace.recent_flow_forced_zero_after_shift === true) {
37362
+ return false;
37363
+ }
37364
+ if (!hasVideoGridRecentFlow(workspace) || !isVideoGridWipGated(workspace)) {
37365
+ return false;
37366
+ }
37367
+ if (isLowWipGreenOverride(workspace, legend)) {
37368
+ return false;
37369
+ }
37370
+ if (getVideoGridBaseColorState(workspace, legend) !== "red") {
37371
+ return false;
37372
+ }
37373
+ return isFiniteNumber2(workspace.efficiency) && workspace.efficiency > 100;
37374
+ };
37375
+ var getVideoGridMetricValue = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => isHighEfficiencyRedFlowOverride(workspace, legend) ? workspace.efficiency : getRawVideoGridMetricValue(workspace);
37337
37376
  var toMinuteBucket = (minuteBucket) => Number.isFinite(minuteBucket) ? Math.floor(minuteBucket) : Math.floor(Date.now() / 6e4);
37338
37377
  var getEffectiveFlowMinuteBucket = (workspace) => {
37339
37378
  const effectiveAt = workspace.recent_flow_effective_end_at;
@@ -37359,7 +37398,7 @@ var getSyntheticLowWipDisplayValue = (workspace, minuteBucket) => {
37359
37398
  const offset = (hashWorkspaceKey(workspace) % 11 + bucket % 11 + 11) % 11;
37360
37399
  return 100 + offset;
37361
37400
  };
37362
- var getVideoGridDisplayValue = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND, minuteBucket) => isLowWipGreenOverride(workspace, legend) ? getSyntheticLowWipDisplayValue(workspace, minuteBucket) : getVideoGridMetricValue(workspace);
37401
+ var getVideoGridDisplayValue = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND, minuteBucket) => isLowWipGreenOverride(workspace, legend) ? getSyntheticLowWipDisplayValue(workspace, minuteBucket) : getVideoGridMetricValue(workspace, legend);
37363
37402
  var getVideoGridColorState = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => {
37364
37403
  const baseColor = getVideoGridBaseColorState(workspace, legend);
37365
37404
  if (!hasVideoGridRecentFlow(workspace)) {
@@ -37371,15 +37410,18 @@ var getVideoGridColorState = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) =>
37371
37410
  if (baseColor !== "red") {
37372
37411
  return baseColor;
37373
37412
  }
37413
+ if (isLowWipGreenOverride(workspace, legend)) {
37414
+ return "green";
37415
+ }
37416
+ if (isHighEfficiencyRedFlowOverride(workspace, legend)) {
37417
+ return getEfficiencyColor(workspace.efficiency, legend);
37418
+ }
37374
37419
  if (!hasIncomingWipMapping(workspace)) {
37375
37420
  return baseColor;
37376
37421
  }
37377
37422
  if (!isFiniteNumber2(workspace.incoming_wip_current)) {
37378
37423
  return "neutral";
37379
37424
  }
37380
- if (isLowWipGreenOverride(workspace, legend)) {
37381
- return "green";
37382
- }
37383
37425
  return baseColor;
37384
37426
  };
37385
37427
  var getVideoGridLegendLabel = (workspaces) => {
@@ -37387,21 +37429,7 @@ var getVideoGridLegendLabel = (workspaces) => {
37387
37429
  if (visibleWorkspaces.length === 0) {
37388
37430
  return MAP_GRID_LEGEND_LABEL;
37389
37431
  }
37390
- const recentFlowEnabledCount = visibleWorkspaces.filter(isVideoGridRecentFlowEnabled).length;
37391
- if (recentFlowEnabledCount === 0) {
37392
- return MAP_GRID_LEGEND_LABEL;
37393
- }
37394
- const recentFlowWindows = new Set(
37395
- visibleWorkspaces.filter(isVideoGridRecentFlowEnabled).map((workspace) => workspace.recent_flow_window_minutes ?? 7).filter((value) => typeof value === "number" && Number.isFinite(value))
37396
- );
37397
- if (recentFlowEnabledCount === visibleWorkspaces.length) {
37398
- if (recentFlowWindows.size === 1) {
37399
- const [windowMinutes] = Array.from(recentFlowWindows);
37400
- return `${windowMinutes} Minute Efficiency`;
37401
- }
37402
- return MIXED_VIDEO_GRID_LEGEND_LABEL;
37403
- }
37404
- return MIXED_VIDEO_GRID_LEGEND_LABEL;
37432
+ return visibleWorkspaces.some(isVideoGridRecentFlowEnabled) ? VIDEO_GRID_LEGEND_LABEL : MAP_GRID_LEGEND_LABEL;
37405
37433
  };
37406
37434
  function getTrendArrowAndColor(trend) {
37407
37435
  if (trend > 0) {
@@ -37444,14 +37472,15 @@ var VideoCard = React144__namespace.default.memo(({
37444
37472
  const showOffline = Boolean(isStreamStale);
37445
37473
  const lastSeenText = lastSeenLabel || "Unknown";
37446
37474
  const workspaceDisplayName = displayName || workspace.displayName || workspace.workspace_name;
37447
- const videoGridMetricValue = getVideoGridMetricValue(workspace);
37475
+ const videoGridMetricValue = getVideoGridMetricValue(workspace, effectiveLegend);
37448
37476
  const videoGridDisplayValue = getVideoGridDisplayValue(workspace, effectiveLegend, displayMinuteBucket);
37449
37477
  const videoGridColorState = getVideoGridColorState(workspace, effectiveLegend);
37450
37478
  const isRecentFlowCard = isVideoGridRecentFlowEnabled(workspace);
37479
+ const isHighEfficiencyOverride = isHighEfficiencyRedFlowOverride(workspace, effectiveLegend);
37451
37480
  const hasDisplayMetric = typeof videoGridDisplayValue === "number" && Number.isFinite(videoGridDisplayValue);
37452
37481
  const hasBarMetric = typeof videoGridMetricValue === "number" && Number.isFinite(videoGridMetricValue);
37453
37482
  const shouldRenderMetricBadge = hasDisplayMetric;
37454
- const badgeTitle = hasVideoGridRecentFlow(workspace) ? `Flow ${Math.round(videoGridDisplayValue ?? 0)}%` : isRecentFlowCard ? "Flow unavailable" : `Efficiency ${Math.round(videoGridDisplayValue ?? 0)}%`;
37483
+ const badgeTitle = isHighEfficiencyOverride ? `Efficiency ${Math.round(videoGridDisplayValue ?? 0)}%` : hasVideoGridRecentFlow(workspace) ? `Flow ${Math.round(videoGridDisplayValue ?? 0)}%` : isRecentFlowCard ? "Flow unavailable" : `Efficiency ${Math.round(videoGridDisplayValue ?? 0)}%`;
37455
37484
  const badgeLabel = `${Math.round(videoGridDisplayValue ?? 0)}%`;
37456
37485
  const efficiencyOverlayClass = videoGridColorState === "green" ? "bg-[#00D654]/25" : videoGridColorState === "yellow" ? "bg-[#FFD700]/30" : videoGridColorState === "red" ? "bg-[#FF2D0A]/30" : "bg-transparent";
37457
37486
  const efficiencyBarClass = videoGridColorState === "green" ? "bg-[#00AB45]" : videoGridColorState === "yellow" ? "bg-[#FFB020]" : videoGridColorState === "red" ? "bg-[#E34329]" : "bg-gray-500/70";
@@ -43288,6 +43317,21 @@ var parseCycleTime = (value) => {
43288
43317
  var extractCycleTimeSeconds = (clip) => {
43289
43318
  return parseCycleTime(clip?.cycleTimeSeconds) ?? parseCycleTime(clip?.cycle_time_seconds) ?? parseCycleTime(clip?.duration) ?? parseCycleTime(clip?.original_task_metadata?.cycle_time) ?? null;
43290
43319
  };
43320
+ var formatDurationLabel = (seconds) => {
43321
+ if (typeof seconds !== "number" || !Number.isFinite(seconds) || seconds <= 0) {
43322
+ return null;
43323
+ }
43324
+ const roundedSeconds = Math.round(seconds);
43325
+ if (roundedSeconds < 60) {
43326
+ return `${roundedSeconds}s`;
43327
+ }
43328
+ const minutes = Math.floor(roundedSeconds / 60);
43329
+ const remainingSeconds = roundedSeconds % 60;
43330
+ if (minutes < 10) {
43331
+ return remainingSeconds > 0 ? `${minutes}m ${remainingSeconds}s` : `${minutes}m`;
43332
+ }
43333
+ return `${Math.round(roundedSeconds / 60)} min`;
43334
+ };
43291
43335
  var getSeverityIcon = (severity, categoryId, cycleTimeSeconds, targetCycleTime, clipId) => {
43292
43336
  if (categoryId === "idle_time" || categoryId === "low_value" || categoryId === "longest-idles") {
43293
43337
  return null;
@@ -43363,7 +43407,9 @@ var FileManagerFilters = ({
43363
43407
  idleTimeVlmEnabled = false,
43364
43408
  showPercentileCycleFilters = true,
43365
43409
  prefetchedClipMetadata,
43366
- activeCategoryLoading
43410
+ activeCategoryLoading,
43411
+ idleClipSort = "latest",
43412
+ onIdleClipSortChange
43367
43413
  }) => {
43368
43414
  const [expandedNodes, setExpandedNodes] = React144.useState(/* @__PURE__ */ new Set());
43369
43415
  const [startTime, setStartTime] = React144.useState("");
@@ -43386,6 +43432,7 @@ var FileManagerFilters = ({
43386
43432
  const [localClipClassifications, setLocalClipClassifications] = React144.useState({});
43387
43433
  const clipMetadataRef = React144.useRef({});
43388
43434
  const inFlightMetadataRequestsRef = React144.useRef(/* @__PURE__ */ new Set());
43435
+ const previousIdleClipSortRef = React144.useRef(idleClipSort);
43389
43436
  const mergedClipClassifications = React144.useMemo(() => ({
43390
43437
  ...clipClassifications || {},
43391
43438
  ...localClipClassifications
@@ -43393,6 +43440,36 @@ var FileManagerFilters = ({
43393
43440
  React144.useEffect(() => {
43394
43441
  clipMetadataRef.current = clipMetadata;
43395
43442
  }, [clipMetadata]);
43443
+ React144.useEffect(() => {
43444
+ if (previousIdleClipSortRef.current === idleClipSort) {
43445
+ return;
43446
+ }
43447
+ previousIdleClipSortRef.current = idleClipSort;
43448
+ setClipMetadata((prev) => {
43449
+ if (!prev.idle_time) {
43450
+ return prev;
43451
+ }
43452
+ const next = { ...prev };
43453
+ delete next.idle_time;
43454
+ return next;
43455
+ });
43456
+ setCategoryPages((prev) => {
43457
+ if (prev.idle_time === void 0) {
43458
+ return prev;
43459
+ }
43460
+ const next = { ...prev };
43461
+ delete next.idle_time;
43462
+ return next;
43463
+ });
43464
+ setCategoryHasMore((prev) => {
43465
+ if (prev.idle_time === void 0) {
43466
+ return prev;
43467
+ }
43468
+ const next = { ...prev };
43469
+ delete next.idle_time;
43470
+ return next;
43471
+ });
43472
+ }, [idleClipSort]);
43396
43473
  const isCategoryExternallyManaged = React144.useCallback((categoryId) => {
43397
43474
  if (!categoryId) {
43398
43475
  return false;
@@ -43551,6 +43628,7 @@ var FileManagerFilters = ({
43551
43628
  return null;
43552
43629
  }
43553
43630
  }, [supabase]);
43631
+ const getMetadataLoadingKey = React144.useCallback((categoryId, page) => `${categoryId}-${page}-${categoryId === "idle_time" ? idleClipSort : "latest"}`, [idleClipSort]);
43554
43632
  const fetchClipMetadataPage = React144.useCallback(async (categoryId, page = 1) => {
43555
43633
  if (!workspaceId || !date || shift === void 0) {
43556
43634
  throw new Error("Missing required params for clip metadata fetch");
@@ -43570,7 +43648,8 @@ var FileManagerFilters = ({
43570
43648
  limit: CLIP_METADATA_PAGE_SIZE,
43571
43649
  knownTotal: typeof counts?.[categoryId] === "number" ? counts[categoryId] : null,
43572
43650
  snapshotDateTime,
43573
- snapshotClipId
43651
+ snapshotClipId,
43652
+ sort: categoryId === "idle_time" ? idleClipSort : "latest"
43574
43653
  }),
43575
43654
  redirectReason: "session_expired"
43576
43655
  });
@@ -43578,7 +43657,7 @@ var FileManagerFilters = ({
43578
43657
  throw new Error(`API error: ${response.status}`);
43579
43658
  }
43580
43659
  return response.json();
43581
- }, [workspaceId, date, shift, counts, snapshotDateTime, snapshotClipId, supabase]);
43660
+ }, [workspaceId, date, shift, counts, snapshotDateTime, snapshotClipId, idleClipSort, supabase]);
43582
43661
  const seedIdleClassifications = React144.useCallback(async (clips) => {
43583
43662
  if (!idleTimeVlmEnabled || clips.length === 0) {
43584
43663
  return;
@@ -43634,7 +43713,7 @@ var FileManagerFilters = ({
43634
43713
  console.warn("[FileManager] Missing required params for clip metadata fetch");
43635
43714
  return;
43636
43715
  }
43637
- const loadingKey = `${categoryId}-${page}`;
43716
+ const loadingKey = getMetadataLoadingKey(categoryId, page);
43638
43717
  if (inFlightMetadataRequestsRef.current.has(loadingKey)) {
43639
43718
  return;
43640
43719
  }
@@ -43662,7 +43741,7 @@ var FileManagerFilters = ({
43662
43741
  return newSet;
43663
43742
  });
43664
43743
  }
43665
- }, [workspaceId, date, shift, fetchClipMetadataPage, idleTimeVlmEnabled, seedIdleClassifications]);
43744
+ }, [workspaceId, date, shift, fetchClipMetadataPage, idleTimeVlmEnabled, seedIdleClassifications, getMetadataLoadingKey]);
43666
43745
  const ensureAllIdleTimeClipMetadataLoaded = React144.useCallback(async () => {
43667
43746
  if (!workspaceId || !date || shift === void 0) {
43668
43747
  return;
@@ -44036,15 +44115,17 @@ var FileManagerFilters = ({
44036
44115
  const colorClasses = getColorClasses(category.color);
44037
44116
  const clipNodes = filteredClips.map((clip, index) => {
44038
44117
  const cycleTime = extractCycleTimeSeconds(clip);
44118
+ const idleDuration = category.id === "idle_time" ? clip.idle_duration_seconds ?? clip.duration : null;
44119
+ const idleDurationLabel = formatDurationLabel(idleDuration);
44039
44120
  const baseTimeLabel = formatClipExplorerTimeLabel({
44040
44121
  categoryId: category.id,
44041
44122
  clipTimestamp: clip.clip_timestamp,
44042
44123
  timezone,
44043
- durationSeconds: clip.duration,
44124
+ durationSeconds: idleDuration ?? clip.duration,
44044
44125
  idleStartTime: clip.idle_start_time,
44045
44126
  idleEndTime: clip.idle_end_time
44046
44127
  });
44047
- const displayLabel = `${baseTimeLabel}${clip.duration && category.id !== "idle_time" && category.id !== "low_value" ? ` - (${clip.duration.toFixed(1)}s)` : ""}`;
44128
+ const displayLabel = `${baseTimeLabel}${idleDurationLabel && category.id === "idle_time" ? ` - (${idleDurationLabel})` : ""}${clip.duration && category.id !== "idle_time" && category.id !== "low_value" ? ` - (${clip.duration.toFixed(1)}s)` : ""}`;
44048
44129
  return {
44049
44130
  id: clip.id,
44050
44131
  label: displayLabel,
@@ -44058,7 +44139,7 @@ var FileManagerFilters = ({
44058
44139
  clipPosition: index + 1,
44059
44140
  // Store 1-based position
44060
44141
  cycleTimeSeconds: cycleTime,
44061
- duration: clip.duration,
44142
+ duration: idleDuration ?? clip.duration,
44062
44143
  // Store duration for custom badge rendering
44063
44144
  cycleItemCount: clip.cycle_item_count ?? null
44064
44145
  };
@@ -44380,11 +44461,11 @@ var FileManagerFilters = ({
44380
44461
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
44381
44462
  "Loading clips..."
44382
44463
  ] }) }),
44383
- loadingCategories.has(`${node.id}-${(categoryPages[node.id] || 0) + 1}`) && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-2 px-3 text-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center text-sm text-slate-500", children: [
44464
+ loadingCategories.has(getMetadataLoadingKey(node.id, (categoryPages[node.id] || 0) + 1)) && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-2 px-3 text-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center text-sm text-slate-500", children: [
44384
44465
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "animate-spin mr-2 h-4 w-4 border-2 border-slate-300 border-t-blue-500 rounded-full" }),
44385
44466
  "Loading more clips..."
44386
44467
  ] }) }),
44387
- categoryHasMore[node.id] && !loadingCategories.has(`${node.id}-${(categoryPages[node.id] || 0) + 1}`) && /* @__PURE__ */ jsxRuntime.jsxs(
44468
+ categoryHasMore[node.id] && !loadingCategories.has(getMetadataLoadingKey(node.id, (categoryPages[node.id] || 0) + 1)) && /* @__PURE__ */ jsxRuntime.jsxs(
44388
44469
  "button",
44389
44470
  {
44390
44471
  onClick: (e) => {
@@ -44411,6 +44492,18 @@ var FileManagerFilters = ({
44411
44492
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-bold text-slate-900 tracking-tight", children: "Clips Explorer" }) })
44412
44493
  ] }),
44413
44494
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center space-x-2", children: [
44495
+ activeFilter === "idle_time" && /* @__PURE__ */ jsxRuntime.jsx(
44496
+ "button",
44497
+ {
44498
+ onClick: () => {
44499
+ onIdleClipSortChange?.(idleClipSort === "latest" ? "idle_duration_desc" : "latest");
44500
+ },
44501
+ className: `p-2 rounded-xl transition-all duration-200 ${idleClipSort === "idle_duration_desc" ? "bg-orange-100 text-orange-600 hover:bg-orange-200 shadow-sm" : "bg-slate-100 text-slate-600 hover:bg-slate-200"}`,
44502
+ title: idleClipSort === "idle_duration_desc" ? "Sort by newest first" : "Sort by longest idle first",
44503
+ "aria-label": idleClipSort === "idle_duration_desc" ? "Sort idle clips by newest first" : "Sort idle clips by longest idle first",
44504
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDownWideNarrow, { className: "h-5 w-5" })
44505
+ }
44506
+ ),
44414
44507
  activeFilter === "idle_time" && idleTimeVlmEnabled && /* @__PURE__ */ jsxRuntime.jsx(
44415
44508
  "button",
44416
44509
  {
@@ -44431,8 +44524,8 @@ var FileManagerFilters = ({
44431
44524
  )
44432
44525
  ] })
44433
44526
  ] }),
44434
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2 mt-3", children: [
44435
- isTimeFilterActive && startTime && endTime && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2 text-xs text-blue-600 bg-blue-50/60 px-3 py-1.5 rounded-lg border border-blue-100", children: [
44527
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 flex flex-wrap items-center gap-2", children: [
44528
+ isTimeFilterActive && startTime && endTime && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex w-fit items-center gap-2 rounded-full border border-blue-100 bg-blue-50/70 px-2.5 py-1 text-xs text-blue-700 shadow-sm", children: [
44436
44529
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-medium", children: [
44437
44530
  "Time: ",
44438
44531
  getDisplayValue(startTime),
@@ -44448,13 +44541,13 @@ var FileManagerFilters = ({
44448
44541
  setEndTime("");
44449
44542
  setIsTimeFilterActive(false);
44450
44543
  },
44451
- className: "ml-2 hover:bg-blue-100 rounded p-0.5 transition-colors",
44544
+ className: "rounded-full p-0.5 transition-colors hover:bg-blue-100",
44452
44545
  title: "Clear time filter",
44453
44546
  children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-3.5 w-3.5" })
44454
44547
  }
44455
44548
  )
44456
44549
  ] }),
44457
- idleLabelFilter && activeFilter === "idle_time" && /* @__PURE__ */ jsxRuntime.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: [
44550
+ idleLabelFilter && activeFilter === "idle_time" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex w-fit items-center gap-2 rounded-full border border-purple-100 bg-purple-50/70 px-2.5 py-1 text-xs text-purple-700 shadow-sm", children: [
44458
44551
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-medium", children: [
44459
44552
  "Reason: ",
44460
44553
  selectedIdleReasonOption?.displayName || idleLabelFilter.replace(/_/g, " ")
@@ -44466,11 +44559,27 @@ var FileManagerFilters = ({
44466
44559
  e.stopPropagation();
44467
44560
  setIdleLabelFilter(null);
44468
44561
  },
44469
- className: "ml-2 hover:bg-purple-100 rounded p-0.5 transition-colors",
44562
+ className: "rounded-full p-0.5 transition-colors hover:bg-purple-100",
44470
44563
  title: "Clear label filter",
44471
44564
  children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-3.5 w-3.5" })
44472
44565
  }
44473
44566
  )
44567
+ ] }),
44568
+ activeFilter === "idle_time" && idleClipSort === "idle_duration_desc" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex w-fit items-center gap-2 rounded-full border border-orange-100 bg-orange-50/70 px-2.5 py-1 text-xs text-orange-700 shadow-sm", children: [
44569
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDownWideNarrow, { className: "h-3.5 w-3.5" }),
44570
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Longest idle first" }),
44571
+ /* @__PURE__ */ jsxRuntime.jsx(
44572
+ "button",
44573
+ {
44574
+ onClick: (e) => {
44575
+ e.stopPropagation();
44576
+ onIdleClipSortChange?.("latest");
44577
+ },
44578
+ className: "rounded-full p-0.5 transition-colors hover:bg-orange-100",
44579
+ title: "Clear idle sort",
44580
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-3.5 w-3.5" })
44581
+ }
44582
+ )
44474
44583
  ] })
44475
44584
  ] })
44476
44585
  ] }),
@@ -45234,8 +45343,10 @@ var BottlenecksContent = ({
45234
45343
  const [clipClassifications, setClipClassifications] = React144.useState({});
45235
45344
  const [categoryMetadata, setCategoryMetadata] = React144.useState([]);
45236
45345
  const [categoryMetadataCategoryId, setCategoryMetadataCategoryId] = React144.useState(null);
45346
+ const [categoryMetadataSort, setCategoryMetadataSort] = React144.useState(null);
45237
45347
  const [currentMetadataIndex, setCurrentMetadataIndex] = React144.useState(0);
45238
45348
  const [metadataCache, setMetadataCache] = React144.useState({});
45349
+ const [idleClipSort, setIdleClipSort] = React144.useState("latest");
45239
45350
  const invalidateMetadataCache = React144.useCallback((categories) => {
45240
45351
  setMetadataCache((prevCache) => {
45241
45352
  if (!prevCache || Object.keys(prevCache).length === 0) {
@@ -45266,6 +45377,7 @@ var BottlenecksContent = ({
45266
45377
  const [isFullscreen, setIsFullscreen] = React144.useState(false);
45267
45378
  const categoryMetadataRef = React144.useRef([]);
45268
45379
  const currentMetadataIndexRef = React144.useRef(0);
45380
+ const previousIdleClipSortRef = React144.useRef(idleClipSort);
45269
45381
  const clearRetryTimeout = React144.useCallback(() => {
45270
45382
  if (retryTimeoutRef.current) {
45271
45383
  clearTimeout(retryTimeoutRef.current);
@@ -45712,9 +45824,13 @@ var BottlenecksContent = ({
45712
45824
  }
45713
45825
  return ["fast-cycles", "slow-cycles", "longest-idles"].includes(categoryId);
45714
45826
  }, [isFastSlowClipFiltersEnabled]);
45827
+ const shouldUseMetadataNavigation = React144.useCallback((categoryId) => {
45828
+ return isPercentileCategory(categoryId) || categoryId === "idle_time" && idleClipSort === "idle_duration_desc";
45829
+ }, [idleClipSort, isPercentileCategory]);
45715
45830
  const getMetadataCacheKey = React144.useCallback((categoryId) => {
45716
- return `${categoryId}-${effectiveDateString}-${effectiveShiftId}-${snapshotDateTime ?? "nosnap"}-${snapshotClipId ?? "nosnap"}`;
45717
- }, [effectiveDateString, effectiveShiftId, snapshotDateTime, snapshotClipId]);
45831
+ const sortKey = categoryId === "idle_time" ? idleClipSort : "latest";
45832
+ return `${categoryId}-${effectiveDateString}-${effectiveShiftId}-${snapshotDateTime ?? "nosnap"}-${snapshotClipId ?? "nosnap"}-${sortKey}`;
45833
+ }, [effectiveDateString, effectiveShiftId, snapshotDateTime, snapshotClipId, idleClipSort]);
45718
45834
  const setVisibleCategoryMetadata = React144.useCallback((categoryId, clips) => {
45719
45835
  if (activeFilterRef.current !== categoryId) {
45720
45836
  return false;
@@ -45722,8 +45838,9 @@ var BottlenecksContent = ({
45722
45838
  categoryMetadataRef.current = clips;
45723
45839
  setCategoryMetadata(clips);
45724
45840
  setCategoryMetadataCategoryId(clips.length > 0 ? categoryId : null);
45841
+ setCategoryMetadataSort(clips.length > 0 ? categoryId === "idle_time" ? idleClipSort : "latest" : null);
45725
45842
  return true;
45726
- }, []);
45843
+ }, [idleClipSort]);
45727
45844
  const applyMetadataSnapshot = React144.useCallback((categoryId, clips, total) => {
45728
45845
  if (!clips || clips.length === 0) {
45729
45846
  return;
@@ -45734,11 +45851,11 @@ var BottlenecksContent = ({
45734
45851
  [cacheKey]: clips
45735
45852
  }));
45736
45853
  setVisibleCategoryMetadata(categoryId, clips);
45737
- if (!isPercentileCategory(categoryId) && typeof total === "number") {
45854
+ if (!shouldUseMetadataNavigation(categoryId) && typeof total === "number") {
45738
45855
  currentTotalRef.current = total;
45739
45856
  setCurrentTotal(total);
45740
45857
  }
45741
- }, [getMetadataCacheKey, isPercentileCategory, setVisibleCategoryMetadata]);
45858
+ }, [getMetadataCacheKey, shouldUseMetadataNavigation, setVisibleCategoryMetadata]);
45742
45859
  const getClipTypesForPercentileCategory = React144.useCallback((categoryId) => {
45743
45860
  switch (categoryId) {
45744
45861
  case "fast-cycles":
@@ -45764,6 +45881,7 @@ var BottlenecksContent = ({
45764
45881
  }
45765
45882
  setCategoryMetadata([]);
45766
45883
  setCategoryMetadataCategoryId(null);
45884
+ setCategoryMetadataSort(null);
45767
45885
  categoryMetadataRef.current = [];
45768
45886
  updateActiveFilter(fallbackFilter);
45769
45887
  }, [isFastSlowClipFiltersEnabled, activeFilter, dynamicCounts, clipTypes, updateActiveFilter]);
@@ -45811,6 +45929,7 @@ var BottlenecksContent = ({
45811
45929
  if (!isFastSlowClipFiltersEnabled && (categoryId === "fast-cycles" || categoryId === "slow-cycles")) {
45812
45930
  setCategoryMetadata([]);
45813
45931
  setCategoryMetadataCategoryId(null);
45932
+ setCategoryMetadataSort(null);
45814
45933
  categoryMetadataRef.current = [];
45815
45934
  return;
45816
45935
  }
@@ -45881,7 +46000,8 @@ var BottlenecksContent = ({
45881
46000
  limit: 100,
45882
46001
  knownTotal: mergedCounts[categoryId] ?? null,
45883
46002
  snapshotDateTime,
45884
- snapshotClipId
46003
+ snapshotClipId,
46004
+ sort: categoryId === "idle_time" ? idleClipSort : "latest"
45885
46005
  }),
45886
46006
  redirectReason: "session_expired"
45887
46007
  });
@@ -45960,6 +46080,7 @@ var BottlenecksContent = ({
45960
46080
  if (activeFilterRef.current === categoryId) {
45961
46081
  setCategoryMetadata([]);
45962
46082
  setCategoryMetadataCategoryId(null);
46083
+ setCategoryMetadataSort(null);
45963
46084
  categoryMetadataRef.current = [];
45964
46085
  }
45965
46086
  }
@@ -45968,7 +46089,26 @@ var BottlenecksContent = ({
45968
46089
  } finally {
45969
46090
  setIsCategoryLoading(false);
45970
46091
  }
45971
- }, [workspaceId, effectiveDateString, effectiveShiftId, getMetadataCacheKey, isPercentileCategory, isFastSlowClipFiltersEnabled, metadataCache, s3ClipsService, clearLoadingState, isEffectiveShiftReady, snapshotDateTime, snapshotClipId, supabase, setVisibleCategoryMetadata]);
46092
+ }, [workspaceId, effectiveDateString, effectiveShiftId, getMetadataCacheKey, isPercentileCategory, isFastSlowClipFiltersEnabled, metadataCache, s3ClipsService, clearLoadingState, isEffectiveShiftReady, snapshotDateTime, snapshotClipId, idleClipSort, supabase, setVisibleCategoryMetadata]);
46093
+ React144.useEffect(() => {
46094
+ if (previousIdleClipSortRef.current === idleClipSort) {
46095
+ return;
46096
+ }
46097
+ previousIdleClipSortRef.current = idleClipSort;
46098
+ if (activeFilterRef.current !== "idle_time") {
46099
+ return;
46100
+ }
46101
+ setCategoryMetadata([]);
46102
+ setCategoryMetadataCategoryId(null);
46103
+ setCategoryMetadataSort(null);
46104
+ categoryMetadataRef.current = [];
46105
+ setCurrentMetadataIndex(0);
46106
+ currentMetadataIndexRef.current = 0;
46107
+ setCurrentPosition(0);
46108
+ currentPositionRef.current = 0;
46109
+ setIsCategoryLoading(true);
46110
+ void loadCategoryMetadata("idle_time", true, true);
46111
+ }, [idleClipSort, loadCategoryMetadata]);
45972
46112
  React144.useEffect(() => {
45973
46113
  if (previousFilterRef.current !== activeFilter) {
45974
46114
  console.log(`Filter changed from ${previousFilterRef.current} to ${activeFilter} - resetting to first video`);
@@ -45979,6 +46119,7 @@ var BottlenecksContent = ({
45979
46119
  loadingCategoryRef.current = null;
45980
46120
  setCategoryMetadata([]);
45981
46121
  setCategoryMetadataCategoryId(null);
46122
+ setCategoryMetadataSort(null);
45982
46123
  setCurrentMetadataIndex(0);
45983
46124
  categoryMetadataRef.current = [];
45984
46125
  currentMetadataIndexRef.current = 0;
@@ -46077,7 +46218,7 @@ var BottlenecksContent = ({
46077
46218
  }
46078
46219
  if (metadataArray.length === 0) {
46079
46220
  console.warn(`[BottlenecksContent] No metadata available for category ${categoryId} after refresh`);
46080
- if (!isPercentileCategory(categoryId)) {
46221
+ if (!shouldUseMetadataNavigation(categoryId)) {
46081
46222
  const resolvedPosition = typeof position === "number" ? position : 1;
46082
46223
  currentPositionRef.current = resolvedPosition;
46083
46224
  setCurrentPosition(resolvedPosition);
@@ -46090,7 +46231,7 @@ var BottlenecksContent = ({
46090
46231
  const clickedClipIndex = metadataArray.findIndex((clip) => clip.clipId === clipId);
46091
46232
  if (clickedClipIndex === -1) {
46092
46233
  console.warn(`[BottlenecksContent] Clip ${clipId} not found after metadata refresh`);
46093
- if (!isPercentileCategory(categoryId)) {
46234
+ if (!shouldUseMetadataNavigation(categoryId)) {
46094
46235
  const resolvedPosition = typeof position === "number" ? position : 1;
46095
46236
  currentPositionRef.current = resolvedPosition;
46096
46237
  setCurrentPosition(resolvedPosition);
@@ -46102,7 +46243,7 @@ var BottlenecksContent = ({
46102
46243
  }
46103
46244
  setCurrentMetadataIndex(clickedClipIndex);
46104
46245
  currentMetadataIndexRef.current = clickedClipIndex;
46105
- if (!isPercentileCategory(categoryId)) {
46246
+ if (!shouldUseMetadataNavigation(categoryId)) {
46106
46247
  const position2 = clickedClipIndex + 1;
46107
46248
  currentPositionRef.current = position2;
46108
46249
  setCurrentPosition(position2);
@@ -46132,7 +46273,7 @@ var BottlenecksContent = ({
46132
46273
  clearLoadingState();
46133
46274
  }
46134
46275
  }
46135
- }, [workspaceId, s3ClipsService, updateActiveFilter, clearLoadingState, clearRetryTimeout, loadCategoryMetadata, applyMetadataSnapshot, mergedCounts, isPercentileCategory]);
46276
+ }, [workspaceId, s3ClipsService, updateActiveFilter, clearLoadingState, clearRetryTimeout, loadCategoryMetadata, applyMetadataSnapshot, mergedCounts, shouldUseMetadataNavigation]);
46136
46277
  const restartCurrentClipPlayback = React144.useCallback(() => {
46137
46278
  if (!currentClipId) {
46138
46279
  return;
@@ -46153,7 +46294,7 @@ var BottlenecksContent = ({
46153
46294
  return;
46154
46295
  }
46155
46296
  const activeCategory = activeFilterRef.current;
46156
- if (!activeCategory || activeCategory === "all" || isPercentileCategory(activeCategory)) {
46297
+ if (!activeCategory || activeCategory === "all" || shouldUseMetadataNavigation(activeCategory)) {
46157
46298
  return;
46158
46299
  }
46159
46300
  let cancelled = false;
@@ -46186,7 +46327,7 @@ var BottlenecksContent = ({
46186
46327
  }, [
46187
46328
  newClipsNotification,
46188
46329
  s3ClipsService,
46189
- isPercentileCategory,
46330
+ shouldUseMetadataNavigation,
46190
46331
  currentClipId,
46191
46332
  invalidateMetadataCache,
46192
46333
  loadAndPlayClipById,
@@ -46238,7 +46379,7 @@ var BottlenecksContent = ({
46238
46379
  }
46239
46380
  }
46240
46381
  try {
46241
- if (!isPercentileCategory(currentFilter)) {
46382
+ if (!shouldUseMetadataNavigation(currentFilter)) {
46242
46383
  if (!s3ClipsService || !workspaceId || !currentClipId) {
46243
46384
  throw new Error("S3 clips service not available");
46244
46385
  }
@@ -46338,7 +46479,7 @@ var BottlenecksContent = ({
46338
46479
  } else {
46339
46480
  const firstClipMeta = metadataArray[0];
46340
46481
  if (firstClipMeta?.clipId && firstClipMeta.clipId !== currentClipId) {
46341
- console.log(`[handleNext] Reached end of ${currentFilter}, looping back to newest percentile clip ${firstClipMeta.clipId}`);
46482
+ console.log(`[handleNext] Reached end of ${currentFilter}, looping back to first metadata clip ${firstClipMeta.clipId}`);
46342
46483
  await loadAndPlayClipById(firstClipMeta.clipId, currentFilter, 1, {
46343
46484
  clips: metadataArray,
46344
46485
  total: metadataArray.length
@@ -46364,7 +46505,7 @@ var BottlenecksContent = ({
46364
46505
  });
46365
46506
  clearLoadingState();
46366
46507
  }
46367
- }, [clearLoadingState, clearRetryTimeout, s3ClipsService, loadCategoryMetadata, loadAndPlayClipById, isPercentileCategory, workspaceId, currentClipId, effectiveDateString, effectiveShiftId, snapshotDateTime, snapshotClipId, mergedCounts]);
46508
+ }, [clearLoadingState, clearRetryTimeout, s3ClipsService, loadCategoryMetadata, loadAndPlayClipById, shouldUseMetadataNavigation, workspaceId, currentClipId, effectiveDateString, effectiveShiftId, snapshotDateTime, snapshotClipId, mergedCounts]);
46368
46509
  const handlePrevious = React144.useCallback(async () => {
46369
46510
  if (!isMountedRef.current || navigationLockRef.current) return;
46370
46511
  const currentFilter = activeFilterRef.current;
@@ -46383,7 +46524,7 @@ var BottlenecksContent = ({
46383
46524
  }
46384
46525
  }
46385
46526
  try {
46386
- if (!isPercentileCategory(currentFilter)) {
46527
+ if (!shouldUseMetadataNavigation(currentFilter)) {
46387
46528
  if (!s3ClipsService || !workspaceId || !currentClipId) {
46388
46529
  throw new Error("S3 clips service not available");
46389
46530
  }
@@ -46468,7 +46609,7 @@ var BottlenecksContent = ({
46468
46609
  });
46469
46610
  clearLoadingState();
46470
46611
  }
46471
- }, [clearLoadingState, clearRetryTimeout, s3ClipsService, loadCategoryMetadata, isPercentileCategory, workspaceId, currentClipId, effectiveDateString, effectiveShiftId, snapshotDateTime, snapshotClipId, mergedCounts]);
46612
+ }, [clearLoadingState, clearRetryTimeout, s3ClipsService, loadCategoryMetadata, shouldUseMetadataNavigation, workspaceId, currentClipId, effectiveDateString, effectiveShiftId, snapshotDateTime, snapshotClipId, mergedCounts]);
46472
46613
  const currentVideo = React144.useMemo(() => {
46473
46614
  if (!filteredVideos || filteredVideos.length === 0 || currentIndex >= filteredVideos.length) {
46474
46615
  return null;
@@ -46535,22 +46676,22 @@ var BottlenecksContent = ({
46535
46676
  }
46536
46677
  }, [currentVideo?.id, isShareLoading, supabase, workspaceId, workspaceName]);
46537
46678
  React144.useMemo(() => {
46538
- if (isPercentileCategory(activeFilter)) {
46679
+ if (shouldUseMetadataNavigation(activeFilter)) {
46539
46680
  return categoryMetadata.length;
46540
46681
  }
46541
46682
  return currentTotal || mergedCounts[activeFilter] || 0;
46542
- }, [activeFilter, categoryMetadata.length, currentTotal, mergedCounts, isPercentileCategory]);
46683
+ }, [activeFilter, categoryMetadata.length, currentTotal, mergedCounts, shouldUseMetadataNavigation]);
46543
46684
  React144.useMemo(() => {
46544
- if (isPercentileCategory(activeFilter)) {
46685
+ if (shouldUseMetadataNavigation(activeFilter)) {
46545
46686
  return categoryMetadata.length > 0 ? currentMetadataIndex + 1 : 0;
46546
46687
  }
46547
46688
  return currentPosition;
46548
- }, [activeFilter, categoryMetadata.length, currentMetadataIndex, currentPosition, isPercentileCategory]);
46549
- const prefetchedExplorerMetadata = React144.useMemo(() => buildPrefetchedExplorerMetadata(
46689
+ }, [activeFilter, categoryMetadata.length, currentMetadataIndex, currentPosition, shouldUseMetadataNavigation]);
46690
+ const prefetchedExplorerMetadata = React144.useMemo(() => activeFilter === "idle_time" && categoryMetadataSort !== idleClipSort ? void 0 : buildPrefetchedExplorerMetadata(
46550
46691
  activeFilter,
46551
46692
  categoryMetadataCategoryId,
46552
46693
  categoryMetadata
46553
- ), [activeFilter, categoryMetadata, categoryMetadataCategoryId]);
46694
+ ), [activeFilter, categoryMetadata, categoryMetadataCategoryId, categoryMetadataSort, idleClipSort]);
46554
46695
  const classificationClipIds = React144.useMemo(() => {
46555
46696
  if (!idleTimeVlmEnabled) {
46556
46697
  return [];
@@ -47299,7 +47440,12 @@ var BottlenecksContent = ({
47299
47440
  showPercentileCycleFilters: isFastSlowClipFiltersEnabled,
47300
47441
  prefetchedClipMetadata: prefetchedExplorerMetadata,
47301
47442
  activeCategoryLoading: isCategoryLoading,
47443
+ idleClipSort,
47444
+ onIdleClipSortChange: setIdleClipSort,
47302
47445
  onFilterChange: (filterId) => {
47446
+ if (filterId !== "idle_time") {
47447
+ setIdleClipSort("latest");
47448
+ }
47303
47449
  updateActiveFilter(filterId);
47304
47450
  const category = categoriesToShow.find((cat) => cat.type === filterId);
47305
47451
  if (category) {
@@ -49222,6 +49368,11 @@ var LineHistoryCalendar = ({
49222
49368
  return calendar;
49223
49369
  }, [data, month, year, configuredTimezone]);
49224
49370
  const hasRealData = (shift) => {
49371
+ if (isUptimeMode) {
49372
+ if (shift.hasData === true) return true;
49373
+ const efficiency = Number(shift.avg_efficiency);
49374
+ return shift.total_workspaces > 0 || shift.underperforming_workspaces > 0 || (shift.output || 0) > 0 || (shift.available_time_seconds || 0) > 0 || (shift.active_time_seconds || 0) > 0 || (shift.idle_time_seconds || 0) > 0 || Number.isFinite(efficiency) && efficiency > 0;
49375
+ }
49225
49376
  if (shift.hasData !== void 0) return shift.hasData;
49226
49377
  return shift.total_workspaces > 0 || shift.avg_efficiency > 0 || shift.underperforming_workspaces > 0;
49227
49378
  };
@@ -49854,13 +50005,18 @@ var LineMonthlyHistory = ({
49854
50005
  enabled: !!lineId && idleTimeVlmEnabled
49855
50006
  });
49856
50007
  const hasRealData = (shift) => {
50008
+ if (isUptimeMode) {
50009
+ if (shift.hasData === true) return true;
50010
+ const efficiency = Number(shift.avg_efficiency);
50011
+ return shift.total_workspaces > 0 || shift.underperforming_workspaces > 0 || (shift.output || 0) > 0 || (shift.idealOutput || 0) > 0 || (shift.idle_time_seconds || 0) > 0 || (shift.active_time_seconds || 0) > 0 || (shift.available_time_seconds || 0) > 0 || Number.isFinite(efficiency) && efficiency > 0;
50012
+ }
49857
50013
  if (shift.hasData !== void 0) return shift.hasData;
49858
50014
  return shift.avg_efficiency > 0 || shift.underperforming_workspaces > 0 || shift.total_workspaces > 0 || (shift.output || 0) > 0 || (shift.idealOutput || 0) > 0 || (shift.idle_time_seconds || 0) > 0 || (shift.active_time_seconds || 0) > 0 || (shift.available_time_seconds || 0) > 0;
49859
50015
  };
49860
50016
  const averages = (analysisMonthlyData || []).reduce(
49861
50017
  (acc, day) => {
49862
50018
  const shiftData = getShiftData2(day, selectedShiftId);
49863
- if (!shiftData || shiftData?.avg_efficiency < 5) {
50019
+ if (!shiftData || !isValidAggregateEfficiency(isUptimeMode ? "uptime" : "output", shiftData.avg_efficiency)) {
49864
50020
  return acc;
49865
50021
  }
49866
50022
  return {
@@ -49889,7 +50045,9 @@ var LineMonthlyHistory = ({
49889
50045
  const avgOutput = outputAverages.count > 0 ? outputAverages.output / outputAverages.count : 0;
49890
50046
  const uptimeSummary = React144.useMemo(() => {
49891
50047
  if (!isUptimeMode) return null;
49892
- const validDays = (analysisMonthlyData || []).map((day) => getShiftData2(day, selectedShiftId)).filter((shiftData) => shiftData && hasRealData(shiftData)).map((shiftData) => ({ shiftData, totals: getUptimeTotals(shiftData) }));
50048
+ const validDays = (analysisMonthlyData || []).map((day) => getShiftData2(day, selectedShiftId)).filter(
50049
+ (shiftData) => shiftData && hasRealData(shiftData) && isValidAggregateEfficiency("uptime", shiftData.avg_efficiency)
50050
+ ).map((shiftData) => ({ shiftData, totals: getUptimeTotals(shiftData) }));
49893
50051
  if (!validDays.length) {
49894
50052
  return { avgUtilization: 0, avgIdleTime: 0, avgDailyStoppages: 0 };
49895
50053
  }
@@ -50037,7 +50195,9 @@ var LineMonthlyHistory = ({
50037
50195
  }, [chartData.yAxisMax, chartData.lastSetTarget]);
50038
50196
  const pieChartData = React144.useMemo(() => {
50039
50197
  if (!isUptimeMode) return [];
50040
- const validShifts = (analysisMonthlyData || []).map((day) => getShiftData2(day, selectedShiftId)).filter(hasRealData);
50198
+ const validShifts = (analysisMonthlyData || []).map((day) => getShiftData2(day, selectedShiftId)).filter(
50199
+ (shift) => shift && hasRealData(shift) && isValidAggregateEfficiency("uptime", shift.avg_efficiency)
50200
+ );
50041
50201
  if (!validShifts.length) return [];
50042
50202
  const efficiencyValues = validShifts.map((shift) => Number.isFinite(shift.avg_efficiency) ? Number(shift.avg_efficiency) : null).filter((value) => value !== null);
50043
50203
  if (!efficiencyValues.length) return [];
@@ -50647,7 +50807,9 @@ var LineMonthlyPdfGenerator = ({
50647
50807
  const productiveSeconds = activeSecondsRaw > 0 ? Math.min(activeSecondsRaw, availableSeconds) : Math.max(availableSeconds - idleSeconds, 0);
50648
50808
  return { availableSeconds, productiveSeconds, idleSeconds };
50649
50809
  };
50650
- const validShifts = validDays.map((day) => getLineShiftData2(day, selectedShiftId)).filter((shift) => isUptimeMode ? hasShiftData(shift) : shift.avg_efficiency >= 5);
50810
+ const validShifts = validDays.map((day) => getLineShiftData2(day, selectedShiftId)).filter(
50811
+ (shift) => hasShiftData(shift) && isValidAggregateEfficiency(isUptimeMode ? "uptime" : "output", shift.avg_efficiency)
50812
+ );
50651
50813
  const monthlyMetrics = validShifts.length > 0 ? isUptimeMode ? (() => {
50652
50814
  let utilizationSum = 0;
50653
50815
  let idleTimeSum = 0;
@@ -52632,7 +52794,10 @@ var WorkspaceMonthlyHistory = ({
52632
52794
  return ticks.filter((v) => v >= 0 && v <= max * 1.05).sort((a, b) => a - b);
52633
52795
  }, [chartData.yAxisMax, chartData.lastSetTarget, isUptimeMode]);
52634
52796
  const pieChartData = React144.useMemo(() => {
52635
- const validShifts = analysisMonthlyData.map((d) => getShiftData(d, selectedShiftId)).filter(hasRealData);
52797
+ const aggregateMode = isUptimeMode ? "uptime" : "output";
52798
+ const validShifts = analysisMonthlyData.map((d) => getShiftData(d, selectedShiftId)).filter(
52799
+ (shift) => shift && hasRealData(shift) && isValidAggregateEfficiency(aggregateMode, shift.efficiency)
52800
+ );
52636
52801
  if (validShifts.length === 0) return [];
52637
52802
  const efficiencyValues = validShifts.map((shift) => Number.isFinite(shift.efficiency) ? Number(shift.efficiency) : null).filter((value) => value !== null);
52638
52803
  if (!efficiencyValues.length) return [];
@@ -52643,10 +52808,10 @@ var WorkspaceMonthlyHistory = ({
52643
52808
  { name: "Productive", value: productivePercent },
52644
52809
  { name: "Idle", value: idlePercent }
52645
52810
  ];
52646
- }, [analysisMonthlyData, selectedShiftId, shiftWorkSeconds]);
52811
+ }, [analysisMonthlyData, selectedShiftId, isUptimeMode]);
52647
52812
  const metrics2 = React144.useMemo(() => {
52648
52813
  const validShifts = analysisMonthlyData.map((d) => getShiftData(d, selectedShiftId)).filter(hasRealData);
52649
- const filteredShifts = isUptimeMode ? validShifts : validShifts.filter((shift) => (shift.efficiency ?? 0) >= 5);
52814
+ const filteredShifts = isUptimeMode ? validShifts.filter((shift) => isValidAggregateEfficiency("uptime", shift.efficiency)) : validShifts.filter((shift) => isValidAggregateEfficiency("output", shift.efficiency));
52650
52815
  if (filteredShifts.length === 0) return null;
52651
52816
  const totalEfficiency = filteredShifts.reduce((sum, shift) => sum + (shift.efficiency || 0), 0);
52652
52817
  const totalUtilization = filteredShifts.reduce(
@@ -53866,7 +54031,7 @@ var WorkspaceMonthlyPdfGenerator = ({
53866
54031
  const shift = getShiftData(dayData, selectedShiftId);
53867
54032
  return { dayData, shift };
53868
54033
  }).filter(({ shift }) => hasShiftData(shift)).sort((left, right) => getDayDateKey(right.dayData).localeCompare(getDayDateKey(left.dayData)));
53869
- const filteredShifts = isUptimeMode ? validShifts : validShifts.filter((shift) => (shift.efficiency ?? 0) >= 5);
54034
+ const filteredShifts = isUptimeMode ? validShifts.filter((shift) => isValidAggregateEfficiency("uptime", shift.efficiency)) : validShifts.filter((shift) => isValidAggregateEfficiency("output", shift.efficiency));
53870
54035
  const monthlyMetrics = filteredShifts.length > 0 ? isUptimeMode ? (() => {
53871
54036
  const totalIdleTime = filteredShifts.reduce((sum, shift) => sum + shift.idleTime, 0);
53872
54037
  const totalCycleTime = filteredShifts.reduce((sum, shift) => sum + shift.cycleTime, 0);
@@ -67038,7 +67203,15 @@ var KPIDetailView = ({
67038
67203
  const fallbackTimes = resolveMonthlyShiftTimes(metric.shift_id);
67039
67204
  const resolvedShiftStart = metric.shift_start || fallbackTimes.start;
67040
67205
  const resolvedShiftEnd = metric.shift_end || fallbackTimes.end;
67041
- const hasBackendUptimeSeconds = isUptimeMode && (Number.isFinite(metric.active_time_seconds) || Number.isFinite(metric.idle_time_seconds) || Number.isFinite(metric.available_time_seconds));
67206
+ const coerceOptionalNumber2 = (value) => {
67207
+ if (value === void 0 || value === null || value === "") return null;
67208
+ const parsed = Number(value);
67209
+ return Number.isFinite(parsed) ? parsed : null;
67210
+ };
67211
+ const metricActiveTimeSeconds = coerceOptionalNumber2(metric.active_time_seconds);
67212
+ const metricIdleTimeSeconds = coerceOptionalNumber2(metric.idle_time_seconds);
67213
+ const metricAvailableTimeSeconds = coerceOptionalNumber2(metric.available_time_seconds);
67214
+ const hasBackendUptimeSeconds = isUptimeMode && (metricActiveTimeSeconds !== null || metricIdleTimeSeconds !== null || metricAvailableTimeSeconds !== null);
67042
67215
  const uptimeSeries2 = isUptimeMode && !hasBackendUptimeSeconds ? buildUptimeSeries({
67043
67216
  idleTimeHourly: metric.idle_time_hourly || {},
67044
67217
  shiftStart: resolvedShiftStart || void 0,
@@ -67046,9 +67219,13 @@ var KPIDetailView = ({
67046
67219
  shiftDate: metric.date,
67047
67220
  timezone: configuredTimezone
67048
67221
  }) : null;
67049
- const idleTimeSeconds = isUptimeMode ? hasBackendUptimeSeconds ? metric.idle_time_seconds || 0 : (uptimeSeries2?.idleMinutes || 0) * 60 : 0;
67050
- const activeTimeSeconds = isUptimeMode ? hasBackendUptimeSeconds ? metric.active_time_seconds || 0 : (uptimeSeries2?.activeMinutes || 0) * 60 : 0;
67051
- const availableTimeSeconds = isUptimeMode ? hasBackendUptimeSeconds ? metric.available_time_seconds || activeTimeSeconds + idleTimeSeconds : (uptimeSeries2?.availableMinutes || 0) * 60 : 0;
67222
+ const idleTimeSeconds = isUptimeMode ? hasBackendUptimeSeconds ? metricIdleTimeSeconds ?? 0 : (uptimeSeries2?.idleMinutes || 0) * 60 : 0;
67223
+ const activeTimeSeconds = isUptimeMode ? hasBackendUptimeSeconds ? metricActiveTimeSeconds ?? 0 : (uptimeSeries2?.activeMinutes || 0) * 60 : 0;
67224
+ const availableTimeSeconds = isUptimeMode ? hasBackendUptimeSeconds ? metricAvailableTimeSeconds ?? activeTimeSeconds + idleTimeSeconds : (uptimeSeries2?.availableMinutes || 0) * 60 : 0;
67225
+ const metricAvgEfficiency = Number(metric.avg_efficiency);
67226
+ const metricTotalWorkspaces = Number(metric.total_workspaces || 0);
67227
+ const metricCurrentOutput = Number(metric.current_output || 0);
67228
+ const hasUptimeMetricData = isUptimeMode && (availableTimeSeconds > 0 || metricTotalWorkspaces > 0 || metricCurrentOutput > 0 || Number.isFinite(metricAvgEfficiency) && metricAvgEfficiency > 0);
67052
67229
  const computedUptimeEfficiency = (() => {
67053
67230
  const availableMinutes = availableTimeSeconds / 60;
67054
67231
  if (!availableMinutes || availableMinutes <= 0) return 0;
@@ -67068,7 +67245,7 @@ var KPIDetailView = ({
67068
67245
  targetOutput: Number(metric.line_threshold ?? metric.ideal_output ?? 0),
67069
67246
  compliance_percentage: 95 + Math.random() * 5,
67070
67247
  // Mock data: random value between 95-100%
67071
- hasData: isUptimeMode ? availableTimeSeconds > 0 : true,
67248
+ hasData: isUptimeMode ? hasUptimeMetricData : true,
67072
67249
  idle_time_seconds: idleTimeSeconds,
67073
67250
  active_time_seconds: activeTimeSeconds,
67074
67251
  available_time_seconds: availableTimeSeconds,