@optifye/dashboard-core 6.12.26 → 6.12.28

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
@@ -14320,9 +14320,11 @@ var useLeaderboardMetrics = (date, shiftId, limit = 10, filter2 = "all") => {
14320
14320
  `/api/dashboard/leaderboard?${params.toString()}`
14321
14321
  );
14322
14322
  let entries = (data.entries || []).slice();
14323
- entries.sort(
14324
- (a, b) => (b.leaderboard_value ?? b.efficiency ?? 0) - (a.leaderboard_value ?? a.efficiency ?? 0)
14325
- );
14323
+ entries.sort((a, b) => {
14324
+ const valueA = a.leaderboard_metric_kind === "cycle_time" ? a.leaderboard_value : a.efficiency;
14325
+ const valueB = b.leaderboard_metric_kind === "cycle_time" ? b.leaderboard_value : b.efficiency;
14326
+ return (valueB ?? -1) - (valueA ?? -1);
14327
+ });
14326
14328
  if (filter2 === "top") {
14327
14329
  entries = entries.slice(0, limit);
14328
14330
  } else if (filter2 === "bottom") {
@@ -22075,14 +22077,87 @@ var toNumber = (value) => {
22075
22077
  }
22076
22078
  return 0;
22077
22079
  };
22080
+ var toOptionalNumber = (value) => {
22081
+ if (typeof value === "number" && Number.isFinite(value)) return value;
22082
+ if (typeof value === "string" && value.trim() !== "") {
22083
+ const parsed = Number(value);
22084
+ return Number.isFinite(parsed) ? parsed : null;
22085
+ }
22086
+ return null;
22087
+ };
22078
22088
  var EFFICIENCY_ON_TRACK_THRESHOLD = 100;
22079
22089
  var isEfficiencyOnTrack = (efficiency) => toNumber(efficiency) >= EFFICIENCY_ON_TRACK_THRESHOLD;
22090
+ var KPI_SIGNAL_LABELS = {
22091
+ stable: "Stable",
22092
+ warning: "Warning",
22093
+ attention: "Attention"
22094
+ };
22095
+ var normalizeLineSignalSource = (source) => source === "recent_flow" ? "recent_flow" : "efficiency";
22096
+ var normalizeLineSignal = (lineSignal, fallbackEfficiency, fallbackWeight) => {
22097
+ if (lineSignal && typeof lineSignal === "object") {
22098
+ const raw = lineSignal;
22099
+ return {
22100
+ source: normalizeLineSignalSource(raw.source),
22101
+ percent: toOptionalNumber(raw.percent),
22102
+ weight: toOptionalNumber(raw.weight),
22103
+ mode: raw.mode === "unavailable" ? "unavailable" : "computed",
22104
+ reason: typeof raw.reason === "string" ? raw.reason : raw.reason ?? null,
22105
+ effectiveEndAt: raw.effective_end_at ?? raw.effectiveEndAt ?? null,
22106
+ computedAt: raw.computed_at ?? raw.computedAt ?? null
22107
+ };
22108
+ }
22109
+ const percent2 = toOptionalNumber(fallbackEfficiency);
22110
+ if (percent2 === null) return null;
22111
+ return {
22112
+ source: "efficiency",
22113
+ percent: percent2,
22114
+ weight: toOptionalNumber(fallbackWeight),
22115
+ mode: "computed",
22116
+ reason: "fallback_efficiency",
22117
+ effectiveEndAt: null,
22118
+ computedAt: null
22119
+ };
22120
+ };
22121
+ var getKpiSignalStatus = (signal, legend = DEFAULT_EFFICIENCY_LEGEND) => {
22122
+ const percent2 = toOptionalNumber(signal?.percent);
22123
+ if (percent2 === null) return null;
22124
+ const color2 = getEfficiencyColor(percent2, legend);
22125
+ if (color2 === "green") return "stable";
22126
+ if (color2 === "yellow") return "warning";
22127
+ return "attention";
22128
+ };
22129
+ var getKpiSignalLabel = (signal, legend = DEFAULT_EFFICIENCY_LEGEND) => {
22130
+ const status = getKpiSignalStatus(signal, legend);
22131
+ return status ? KPI_SIGNAL_LABELS[status] : null;
22132
+ };
22133
+ var aggregateLineSignals = (signals) => {
22134
+ const numericSignals = signals.filter(
22135
+ (signal) => signal !== null && signal !== void 0 && toOptionalNumber(signal.percent) !== null
22136
+ );
22137
+ if (numericSignals.length === 0) return null;
22138
+ const percent2 = numericSignals.reduce(
22139
+ (sum, signal) => sum + (toOptionalNumber(signal.percent) ?? 0),
22140
+ 0
22141
+ ) / numericSignals.length;
22142
+ const signalSources = new Set(numericSignals.map((signal) => signal.source));
22143
+ const source = signalSources.size === 1 ? numericSignals[0].source : "mixed";
22144
+ return {
22145
+ source,
22146
+ percent: percent2,
22147
+ weight: null,
22148
+ mode: "computed",
22149
+ reason: "average",
22150
+ effectiveEndAt: null,
22151
+ computedAt: null
22152
+ };
22153
+ };
22080
22154
  var createDefaultKPIs = () => ({
22081
22155
  underperformingWorkers: { current: 0, total: 0, change: 0 },
22082
22156
  efficiency: { value: 0, change: 0 },
22083
22157
  outputProgress: { current: 0, target: 0, idealOutput: 0, change: 0 },
22084
22158
  avgCycleTime: { value: 0, change: 0 },
22085
- qualityCompliance: { value: 95, change: 0 }
22159
+ qualityCompliance: { value: 95, change: 0 },
22160
+ lineSignal: null
22086
22161
  });
22087
22162
  var buildKPIsFromLineMetricsRow = (row) => {
22088
22163
  if (!row) return createDefaultKPIs();
@@ -22116,15 +22191,28 @@ var buildKPIsFromLineMetricsRow = (row) => {
22116
22191
  qualityCompliance: {
22117
22192
  value: 95,
22118
22193
  change: 0
22119
- }
22194
+ },
22195
+ lineSignal: normalizeLineSignal(row.line_signal, avgEfficiency, idealOutput || lineThreshold)
22120
22196
  };
22121
22197
  };
22122
22198
  var aggregateKPIsFromLineMetricsRows = (rows) => {
22123
22199
  if (!rows || rows.length === 0) return createDefaultKPIs();
22200
+ const lineSignal = aggregateLineSignals(
22201
+ rows.map((row) => normalizeLineSignal(
22202
+ row?.line_signal,
22203
+ row?.avg_efficiency,
22204
+ row?.ideal_output ?? row?.line_threshold
22205
+ ))
22206
+ );
22124
22207
  const eligibleRows = rows.filter(
22125
22208
  (row) => isValidAggregateEfficiency(row?.monitoring_mode ?? row?.monitoringMode, row?.avg_efficiency)
22126
22209
  );
22127
- if (eligibleRows.length === 0) return createDefaultKPIs();
22210
+ if (eligibleRows.length === 0) {
22211
+ return {
22212
+ ...createDefaultKPIs(),
22213
+ lineSignal
22214
+ };
22215
+ }
22128
22216
  const currentOutputSum = eligibleRows.reduce((sum, row) => sum + toNumber(row.current_output), 0);
22129
22217
  const lineThresholdSum = eligibleRows.reduce(
22130
22218
  (sum, row) => sum + (row?.output_target_recalculated !== void 0 && row?.output_target_recalculated !== null ? toNumber(row.output_target_recalculated) : toNumber(row.line_threshold)),
@@ -22171,7 +22259,8 @@ var aggregateKPIsFromLineMetricsRows = (rows) => {
22171
22259
  qualityCompliance: {
22172
22260
  value: 95,
22173
22261
  change: 0
22174
- }
22262
+ },
22263
+ lineSignal
22175
22264
  };
22176
22265
  };
22177
22266
 
@@ -34725,19 +34814,19 @@ var SkuRow = ({ sku, isSelected, isLive, onSelect }) => {
34725
34814
  onClick: () => onSelect?.(isSelected ? null : sku.sku_id),
34726
34815
  "data-testid": `sku-progress-row-${sku.sku_id}`,
34727
34816
  children: [
34728
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline justify-between gap-3", children: [
34729
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 truncate", children: [
34817
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-3", children: [
34818
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2 flex-1 min-w-0", children: [
34730
34819
  /* @__PURE__ */ jsxRuntime.jsx(
34731
34820
  "span",
34732
34821
  {
34733
- className: "text-sm font-semibold text-gray-800 truncate",
34822
+ className: "text-xs sm:text-sm font-semibold text-gray-800 break-words line-clamp-2",
34734
34823
  title: skuLabel,
34735
34824
  children: skuLabel
34736
34825
  }
34737
34826
  ),
34738
- isLive && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-2 h-2 rounded-full bg-green-500 shrink-0 shadow-[0_0_4px_rgba(34,197,94,0.6)]", title: "Currently running" })
34827
+ isLive && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-2 h-2 rounded-full bg-green-500 shrink-0 shadow-[0_0_4px_rgba(34,197,94,0.6)] mt-1.5", title: "Currently running" })
34739
34828
  ] }),
34740
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-gray-500 font-medium tabular-nums shrink-0", children: [
34829
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-gray-500 font-medium tabular-nums shrink-0 pt-0.5", children: [
34741
34830
  Math.round(current),
34742
34831
  " / ",
34743
34832
  Math.round(target)
@@ -45075,7 +45164,7 @@ var FileManagerFilters = ({
45075
45164
  onClick: () => {
45076
45165
  onIdleClipSortChange?.(idleClipSort === "latest" ? "idle_duration_desc" : "latest");
45077
45166
  },
45078
- 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"}`,
45167
+ className: `p-2 rounded-xl transition-all duration-200 ${idleClipSort === "idle_duration_desc" ? "bg-blue-100 text-blue-600 hover:bg-blue-200 shadow-sm" : "bg-slate-100 text-slate-600 hover:bg-slate-200"}`,
45079
45168
  title: idleClipSort === "idle_duration_desc" ? "Sort by newest first" : "Sort by longest idle first",
45080
45169
  "aria-label": idleClipSort === "idle_duration_desc" ? "Sort idle clips by newest first" : "Sort idle clips by longest idle first",
45081
45170
  children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDownWideNarrow, { className: "h-5 w-5" })
@@ -45142,7 +45231,7 @@ var FileManagerFilters = ({
45142
45231
  }
45143
45232
  )
45144
45233
  ] }),
45145
- 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: [
45234
+ activeFilter === "idle_time" && idleClipSort === "idle_duration_desc" && /* @__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: [
45146
45235
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDownWideNarrow, { className: "h-3.5 w-3.5" }),
45147
45236
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Longest idle first" }),
45148
45237
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -45152,7 +45241,7 @@ var FileManagerFilters = ({
45152
45241
  e.stopPropagation();
45153
45242
  onIdleClipSortChange?.("latest");
45154
45243
  },
45155
- className: "rounded-full p-0.5 transition-colors hover:bg-orange-100",
45244
+ className: "rounded-full p-0.5 transition-colors hover:bg-blue-100",
45156
45245
  title: "Clear idle sort",
45157
45246
  children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-3.5 w-3.5" })
45158
45247
  }
@@ -58007,118 +58096,114 @@ var SideNavBar = React144.memo(({
58007
58096
  children: /* @__PURE__ */ jsxRuntime.jsx(Logo, { className: "w-12 h-12 object-contain cursor-pointer" })
58008
58097
  }
58009
58098
  ) }),
58010
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 w-full py-6 px-4 overflow-y-auto", children: [
58011
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-6", children: [
58012
- canAccessPath("/") && /* @__PURE__ */ jsxRuntime.jsxs(
58013
- "button",
58014
- {
58015
- onClick: handleHomeClick,
58016
- className: homeButtonClasses,
58017
- "aria-label": "Home",
58018
- tabIndex: 0,
58019
- role: "tab",
58020
- "aria-selected": isPathActive("/"),
58021
- children: [
58022
- /* @__PURE__ */ jsxRuntime.jsx(outline.HomeIcon, { className: "w-5 h-5 mb-1" }),
58023
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight", children: "Home" })
58024
- ]
58025
- }
58026
- ),
58027
- showLiveMonitorLink && canAccessPath("/live-monitor") && /* @__PURE__ */ jsxRuntime.jsxs(
58028
- "button",
58029
- {
58030
- onClick: handleLiveClick,
58031
- className: `${liveButtonClasses} mt-3`,
58032
- "aria-label": "Monitor",
58033
- tabIndex: 0,
58034
- role: "tab",
58035
- "aria-selected": isPathActive("/live-monitor"),
58036
- children: [
58037
- /* @__PURE__ */ jsxRuntime.jsx(outline.VideoCameraIcon, { className: "w-5 h-5 mb-1" }),
58038
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight", children: "Monitor" })
58039
- ]
58040
- }
58041
- )
58042
- ] }),
58043
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
58044
- canAccessPath("/leaderboard") && /* @__PURE__ */ jsxRuntime.jsxs(
58045
- "button",
58046
- {
58047
- onClick: handleLeaderboardClick,
58048
- className: leaderboardButtonClasses,
58049
- "aria-label": "Leaderboard",
58050
- tabIndex: 0,
58051
- role: "tab",
58052
- "aria-selected": isPathActive("/leaderboard"),
58053
- children: [
58054
- /* @__PURE__ */ jsxRuntime.jsx(outline.TrophyIcon, { className: "w-5 h-5 mb-1" }),
58055
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight", children: "Leaders" })
58056
- ]
58057
- }
58058
- ),
58059
- canAccessPath("/kpis") && /* @__PURE__ */ jsxRuntime.jsxs(
58060
- "button",
58061
- {
58062
- onClick: handleKPIsClick,
58063
- className: kpisButtonClasses,
58064
- "aria-label": "Lines",
58065
- tabIndex: 0,
58066
- role: "tab",
58067
- "aria-selected": isPathActive("/kpis"),
58068
- children: [
58069
- /* @__PURE__ */ jsxRuntime.jsx(outline.ChartBarIcon, { className: "w-5 h-5 mb-1" }),
58070
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight", children: "Lines" })
58071
- ]
58072
- }
58073
- ),
58074
- canAccessPath("/improvement-center") && /* @__PURE__ */ jsxRuntime.jsxs(
58075
- "button",
58076
- {
58077
- onClick: handleImprovementClick,
58078
- className: improvementButtonClasses,
58079
- "aria-label": "Improvement Center",
58080
- tabIndex: 0,
58081
- role: "tab",
58082
- "aria-selected": isPathActive("/improvement-center"),
58083
- children: [
58084
- /* @__PURE__ */ jsxRuntime.jsx(outline.LightBulbIcon, { className: "w-5 h-5 mb-1" }),
58085
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight text-center", children: "Improve" })
58086
- ]
58087
- }
58088
- ),
58089
- showSupervisorManagement,
58090
- skuEnabled && canAccessPath("/skus") && /* @__PURE__ */ jsxRuntime.jsxs(
58091
- "button",
58092
- {
58093
- onClick: handleSKUsClick,
58094
- className: skusButtonClasses,
58095
- "aria-label": "SKU Management",
58096
- tabIndex: 0,
58097
- role: "tab",
58098
- "aria-selected": isPathActive("/skus"),
58099
- children: [
58100
- /* @__PURE__ */ jsxRuntime.jsx(outline.CubeIcon, { className: "w-5 h-5 mb-1" }),
58101
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight", children: "SKUs" })
58102
- ]
58103
- }
58104
- ),
58105
- canAccessPath("/health") && /* @__PURE__ */ jsxRuntime.jsxs(
58106
- "button",
58107
- {
58108
- onClick: handleHealthClick,
58109
- className: healthButtonClasses,
58110
- "aria-label": "System Health",
58111
- tabIndex: 0,
58112
- role: "tab",
58113
- "aria-selected": isPathActive("/health"),
58114
- children: [
58115
- /* @__PURE__ */ jsxRuntime.jsx(outline.HeartIcon, { className: "w-5 h-5 mb-1" }),
58116
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight", children: "Health" })
58117
- ]
58118
- }
58119
- )
58120
- ] })
58121
- ] }),
58099
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 w-full py-6 px-4 overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
58100
+ canAccessPath("/") && /* @__PURE__ */ jsxRuntime.jsxs(
58101
+ "button",
58102
+ {
58103
+ onClick: handleHomeClick,
58104
+ className: homeButtonClasses,
58105
+ "aria-label": "Home",
58106
+ tabIndex: 0,
58107
+ role: "tab",
58108
+ "aria-selected": isPathActive("/"),
58109
+ children: [
58110
+ /* @__PURE__ */ jsxRuntime.jsx(outline.HomeIcon, { className: "w-5 h-5 mb-1" }),
58111
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight", children: "Home" })
58112
+ ]
58113
+ }
58114
+ ),
58115
+ showLiveMonitorLink && canAccessPath("/live-monitor") && /* @__PURE__ */ jsxRuntime.jsxs(
58116
+ "button",
58117
+ {
58118
+ onClick: handleLiveClick,
58119
+ className: liveButtonClasses,
58120
+ "aria-label": "Monitor",
58121
+ tabIndex: 0,
58122
+ role: "tab",
58123
+ "aria-selected": isPathActive("/live-monitor"),
58124
+ children: [
58125
+ /* @__PURE__ */ jsxRuntime.jsx(outline.VideoCameraIcon, { className: "w-5 h-5 mb-1" }),
58126
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight", children: "Monitor" })
58127
+ ]
58128
+ }
58129
+ ),
58130
+ canAccessPath("/leaderboard") && /* @__PURE__ */ jsxRuntime.jsxs(
58131
+ "button",
58132
+ {
58133
+ onClick: handleLeaderboardClick,
58134
+ className: leaderboardButtonClasses,
58135
+ "aria-label": "Leaderboard",
58136
+ tabIndex: 0,
58137
+ role: "tab",
58138
+ "aria-selected": isPathActive("/leaderboard"),
58139
+ children: [
58140
+ /* @__PURE__ */ jsxRuntime.jsx(outline.TrophyIcon, { className: "w-5 h-5 mb-1" }),
58141
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight", children: "Leaders" })
58142
+ ]
58143
+ }
58144
+ ),
58145
+ canAccessPath("/kpis") && /* @__PURE__ */ jsxRuntime.jsxs(
58146
+ "button",
58147
+ {
58148
+ onClick: handleKPIsClick,
58149
+ className: kpisButtonClasses,
58150
+ "aria-label": "Lines",
58151
+ tabIndex: 0,
58152
+ role: "tab",
58153
+ "aria-selected": isPathActive("/kpis"),
58154
+ children: [
58155
+ /* @__PURE__ */ jsxRuntime.jsx(outline.ChartBarIcon, { className: "w-5 h-5 mb-1" }),
58156
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight", children: "Lines" })
58157
+ ]
58158
+ }
58159
+ ),
58160
+ canAccessPath("/improvement-center") && /* @__PURE__ */ jsxRuntime.jsxs(
58161
+ "button",
58162
+ {
58163
+ onClick: handleImprovementClick,
58164
+ className: improvementButtonClasses,
58165
+ "aria-label": "Improvement Center",
58166
+ tabIndex: 0,
58167
+ role: "tab",
58168
+ "aria-selected": isPathActive("/improvement-center"),
58169
+ children: [
58170
+ /* @__PURE__ */ jsxRuntime.jsx(outline.LightBulbIcon, { className: "w-5 h-5 mb-1" }),
58171
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight text-center", children: "Improve" })
58172
+ ]
58173
+ }
58174
+ ),
58175
+ showSupervisorManagement,
58176
+ skuEnabled && canAccessPath("/skus") && /* @__PURE__ */ jsxRuntime.jsxs(
58177
+ "button",
58178
+ {
58179
+ onClick: handleSKUsClick,
58180
+ className: skusButtonClasses,
58181
+ "aria-label": "SKU Management",
58182
+ tabIndex: 0,
58183
+ role: "tab",
58184
+ "aria-selected": isPathActive("/skus"),
58185
+ children: [
58186
+ /* @__PURE__ */ jsxRuntime.jsx(outline.CubeIcon, { className: "w-5 h-5 mb-1" }),
58187
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight", children: "SKUs" })
58188
+ ]
58189
+ }
58190
+ ),
58191
+ canAccessPath("/health") && /* @__PURE__ */ jsxRuntime.jsxs(
58192
+ "button",
58193
+ {
58194
+ onClick: handleHealthClick,
58195
+ className: healthButtonClasses,
58196
+ "aria-label": "System Health",
58197
+ tabIndex: 0,
58198
+ role: "tab",
58199
+ "aria-selected": isPathActive("/health"),
58200
+ children: [
58201
+ /* @__PURE__ */ jsxRuntime.jsx(outline.HeartIcon, { className: "w-5 h-5 mb-1" }),
58202
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight", children: "Health" })
58203
+ ]
58204
+ }
58205
+ )
58206
+ ] }) }),
58122
58207
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full py-4 px-4 border-t border-gray-100 flex-shrink-0 flex flex-col gap-2", children: settingsItems.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
58123
58208
  "button",
58124
58209
  {
@@ -58171,7 +58256,7 @@ var SideNavBar = React144.memo(({
58171
58256
  "button",
58172
58257
  {
58173
58258
  onClick: handleMobileNavClick(handleLiveClick),
58174
- className: `${getMobileButtonClass("/live-monitor")} mt-2`,
58259
+ className: getMobileButtonClass("/live-monitor"),
58175
58260
  "aria-label": "Monitor",
58176
58261
  children: [
58177
58262
  /* @__PURE__ */ jsxRuntime.jsx(outline.VideoCameraIcon, { className: getIconClass("/live-monitor") }),
@@ -69737,6 +69822,19 @@ var formatDateKey2 = (dateKey, timezone, options) => {
69737
69822
  return dateKey;
69738
69823
  }
69739
69824
  };
69825
+ var getFirstName = (displayName) => {
69826
+ const trimmedName = displayName.trim();
69827
+ if (!trimmedName) return "";
69828
+ return trimmedName.split(/\s+/)[0];
69829
+ };
69830
+ var formatSupervisorFirstNames = (supervisors, fallbackSupervisorNames) => {
69831
+ const firstNames = supervisors.map((supervisor) => getFirstName(supervisor.displayName)).filter((name) => name.length > 0);
69832
+ if (firstNames.length > 0) {
69833
+ return Array.from(new Set(firstNames)).join(", ");
69834
+ }
69835
+ const fallbackFirstNames = fallbackSupervisorNames.flatMap((names) => names.split(",")).map(getFirstName).filter((name) => name.length > 0);
69836
+ return fallbackFirstNames.length > 0 ? Array.from(new Set(fallbackFirstNames)).join(", ") : "Unassigned";
69837
+ };
69740
69838
  var LeaderboardCountdown = ({ targetDate, format: format10, finishedLabel = "Finished", placeholder = "--", onFinished }) => {
69741
69839
  const [time2, setTime] = React144.useState("");
69742
69840
  const hasFinishedRef = React144.useRef(false);
@@ -69862,7 +69960,7 @@ var LinesLeaderboard = ({
69862
69960
  });
69863
69961
  const supervisors = Array.from(supervisorByUserId.values());
69864
69962
  const primarySupervisor = supervisors[0];
69865
- const supervisorName = supervisors.length > 1 ? `${supervisors.length} supervisors` : primarySupervisor?.displayName || fallbackSupervisorNames[0] || "Unassigned";
69963
+ const supervisorName = formatSupervisorFirstNames(supervisors, fallbackSupervisorNames);
69866
69964
  const supervisorImage = primarySupervisor?.profilePhotoUrl || null;
69867
69965
  return {
69868
69966
  ...row,
@@ -70122,21 +70220,49 @@ var LinesLeaderboard = ({
70122
70220
  ] }) }) }) })
70123
70221
  ] });
70124
70222
  };
70223
+ var SIGNAL_PILL_STYLES = {
70224
+ stable: {
70225
+ container: "bg-emerald-100 text-emerald-700 border border-emerald-200",
70226
+ dot: "bg-emerald-500"
70227
+ },
70228
+ warning: {
70229
+ container: "bg-amber-100 text-amber-700 border border-amber-200",
70230
+ dot: "bg-amber-500"
70231
+ },
70232
+ attention: {
70233
+ container: "bg-red-100 text-red-700 border border-red-200",
70234
+ dot: "bg-red-500"
70235
+ }
70236
+ };
70237
+ var KpiSignalPill = ({ signal, efficiencyLegend }) => {
70238
+ const status = getKpiSignalStatus(signal, efficiencyLegend);
70239
+ const label = getKpiSignalLabel(signal, efficiencyLegend);
70240
+ if (!status || !label) return null;
70241
+ const styles2 = SIGNAL_PILL_STYLES[status];
70242
+ return /* @__PURE__ */ jsxRuntime.jsxs(
70243
+ "div",
70244
+ {
70245
+ className: `flex items-center gap-1.5 px-2.5 sm:px-3 py-1 sm:py-1.5 rounded-full text-xs font-medium flex-shrink-0 ${styles2.container}`,
70246
+ style: { minWidth: "fit-content" },
70247
+ children: [
70248
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: `w-2 h-2 rounded-full ${styles2.dot} animate-pulse` }),
70249
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: label })
70250
+ ]
70251
+ }
70252
+ );
70253
+ };
70125
70254
  var LineCard = ({
70126
70255
  line,
70127
70256
  kpis,
70128
70257
  isLoading,
70129
70258
  error,
70130
70259
  onClick,
70260
+ efficiencyLegend,
70131
70261
  supervisorEnabled = false,
70132
70262
  supervisorName,
70133
70263
  supervisors
70134
70264
  }) => {
70135
70265
  const isUptimeLine = (line.monitoring_mode ?? "output") === "uptime";
70136
- const isOnTrack = React144__namespace.default.useMemo(() => {
70137
- if (!kpis) return null;
70138
- return isEfficiencyOnTrack(kpis.efficiency.value);
70139
- }, [kpis]);
70140
70266
  return /* @__PURE__ */ jsxRuntime.jsxs(
70141
70267
  motion.div,
70142
70268
  {
@@ -70208,10 +70334,7 @@ var LineCard = ({
70208
70334
  ] })
70209
70335
  ] })
70210
70336
  ] }),
70211
- !isUptimeLine && kpis && isOnTrack !== null && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-center gap-1.5 px-2.5 sm:px-3 py-1 sm:py-1.5 rounded-full text-xs font-medium flex-shrink-0 ${isOnTrack ? "bg-emerald-100 text-emerald-700 border border-emerald-200" : "bg-red-100 text-red-700 border border-red-200"}`, style: { minWidth: "fit-content" }, children: [
70212
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: `w-2 h-2 rounded-full ${isOnTrack ? "bg-emerald-500" : "bg-red-500"} animate-pulse` }),
70213
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: isOnTrack ? "On Track" : "Behind" })
70214
- ] })
70337
+ !isUptimeLine && kpis && /* @__PURE__ */ jsxRuntime.jsx(KpiSignalPill, { signal: kpis.lineSignal, efficiencyLegend })
70215
70338
  ] }) }),
70216
70339
  isLoading && !kpis && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
70217
70340
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "animate-pulse", children: [
@@ -70279,12 +70402,9 @@ var KpiGroupCard = ({
70279
70402
  isLoading,
70280
70403
  error,
70281
70404
  isUptimeMode,
70405
+ efficiencyLegend,
70282
70406
  onClick
70283
70407
  }) => {
70284
- const isOnTrack = React144__namespace.default.useMemo(() => {
70285
- if (!kpis) return null;
70286
- return isEfficiencyOnTrack(kpis.efficiency.value);
70287
- }, [kpis]);
70288
70408
  const outputTarget = Number(kpis?.outputProgress?.target ?? 0);
70289
70409
  const outputCurrent = Number(kpis?.outputProgress?.current ?? 0);
70290
70410
  const progressPercent = outputTarget > 0 ? Math.min(outputCurrent / outputTarget * 100, 100) : 0;
@@ -70308,10 +70428,7 @@ var KpiGroupCard = ({
70308
70428
  ),
70309
70429
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-xs font-medium text-gray-500", children: subtitle })
70310
70430
  ] }),
70311
- !isUptimeMode && kpis && isOnTrack !== null && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-center gap-1.5 px-2.5 sm:px-3 py-1 sm:py-1.5 rounded-full text-xs font-medium flex-shrink-0 ${isOnTrack ? "bg-emerald-100 text-emerald-700 border border-emerald-200" : "bg-red-100 text-red-700 border border-red-200"}`, style: { minWidth: "fit-content" }, children: [
70312
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: `w-2 h-2 rounded-full ${isOnTrack ? "bg-emerald-500" : "bg-red-500"} animate-pulse` }),
70313
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: isOnTrack ? "On Track" : "Behind" })
70314
- ] })
70431
+ !isUptimeMode && kpis && /* @__PURE__ */ jsxRuntime.jsx(KpiSignalPill, { signal: kpis.lineSignal, efficiencyLegend })
70315
70432
  ] }) }),
70316
70433
  isLoading && !kpis && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
70317
70434
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "animate-pulse", children: [
@@ -70436,12 +70553,16 @@ var KPIsOverviewView = ({
70436
70553
  () => new Set(resolvedAssignedLineIds),
70437
70554
  [resolvedAssignedLineIds]
70438
70555
  );
70556
+ const loadedLineIds = React144__namespace.default.useMemo(
70557
+ () => lines.map((line) => line.id).filter(Boolean),
70558
+ [lines]
70559
+ );
70439
70560
  const metricsLineIds = React144__namespace.default.useMemo(() => {
70440
70561
  if (isSuperAdmin) {
70441
- return lineIds ?? [];
70562
+ return loadedLineIds.length > 0 ? loadedLineIds : lineIds ?? [];
70442
70563
  }
70443
70564
  return resolvedAssignedLineIds;
70444
- }, [isSuperAdmin, lineIds, resolvedAssignedLineIds]);
70565
+ }, [isSuperAdmin, loadedLineIds, lineIds, resolvedAssignedLineIds]);
70445
70566
  const assignedLineIdsForLeaderboard = isSuperAdmin ? void 0 : resolvedAssignedLineIds;
70446
70567
  const leaderboardLinesForView = React144__namespace.default.useMemo(() => {
70447
70568
  const targetMode = viewType === "machine" ? "uptime" : "output";
@@ -70628,7 +70749,8 @@ var KPIsOverviewView = ({
70628
70749
  const {
70629
70750
  lineMetrics,
70630
70751
  isLoading: metricsLoading,
70631
- error: metricsError
70752
+ error: metricsError,
70753
+ efficiencyLegend
70632
70754
  } = useDashboardMetrics({
70633
70755
  lineId: factoryViewId,
70634
70756
  userAccessibleLineIds: metricsLineIds
@@ -70972,7 +71094,11 @@ var KPIsOverviewView = ({
70972
71094
  trackProps.output_current = kpis.outputProgress?.current;
70973
71095
  trackProps.output_target = kpis.outputProgress?.target;
70974
71096
  trackProps.underperforming_workers = kpis.underperformingWorkers?.current;
70975
- trackProps.status = isEfficiencyOnTrack(kpis.efficiency?.value) ? "On Track" : "Behind";
71097
+ const signalLabel = getKpiSignalLabel(kpis.lineSignal, efficiencyLegend);
71098
+ if (signalLabel) {
71099
+ trackProps.status = signalLabel;
71100
+ trackProps.signal_source = kpis.lineSignal?.source ?? null;
71101
+ }
70976
71102
  }
70977
71103
  trackCoreEvent("Line Card Clicked", trackProps);
70978
71104
  if (activeTab === "leaderboard" && timeRange === "today" && isHistoricalLeaderboardDaily) {
@@ -71058,6 +71184,7 @@ var KPIsOverviewView = ({
71058
71184
  isLoading: metricsLoading,
71059
71185
  error: metricsError,
71060
71186
  onClick: (kpis) => handleLineClick(line, kpis),
71187
+ efficiencyLegend,
71061
71188
  supervisorEnabled,
71062
71189
  supervisorName: supervisorNamesByLineId.get(line.id) || null,
71063
71190
  supervisors: supervisorsByLineId?.get(line.id)
@@ -71079,6 +71206,7 @@ var KPIsOverviewView = ({
71079
71206
  isLoading: metricsLoading,
71080
71207
  error: metricsError,
71081
71208
  isUptimeMode: viewType === "machine",
71209
+ efficiencyLegend,
71082
71210
  onClick
71083
71211
  },
71084
71212
  key
@@ -71488,16 +71616,16 @@ var AnimatedEfficiency = React144.memo(({ value }) => {
71488
71616
  });
71489
71617
  AnimatedEfficiency.displayName = "AnimatedEfficiency";
71490
71618
  var getWorkspaceLeaderboardMetricValue = (workspace) => {
71491
- if (workspace.leaderboard_metric_kind === "recent_flow_shift_average") {
71619
+ if (workspace.leaderboard_metric_kind === "cycle_time") {
71492
71620
  const cycleRatio = getCycleRatio(workspace);
71493
- return cycleRatio === null ? null : cycleRatio * 100;
71621
+ return toFiniteNumber(workspace.leaderboard_value) ?? (cycleRatio === null ? null : cycleRatio * 100);
71494
71622
  }
71495
- return toFiniteNumber(workspace.leaderboard_value) ?? toFiniteNumber(workspace.efficiency);
71623
+ return toFiniteNumber(workspace.efficiency);
71496
71624
  };
71497
71625
  var getWorkspaceDisplayedMetricValue = (workspace) => getWorkspaceLeaderboardMetricValue(workspace);
71498
- var getWorkspaceLeaderboardMetricLabel = (workspace, defaultLabel) => workspace.leaderboard_metric_kind === "recent_flow_shift_average" ? "Actual CT / Standard CT" : defaultLabel;
71626
+ var getWorkspaceLeaderboardMetricLabel = (workspace, defaultLabel) => workspace.leaderboard_metric_kind === "cycle_time" ? "Actual CT / Standard CT" : defaultLabel;
71499
71627
  var renderWorkspaceLeaderboardMetric = (workspace) => {
71500
- if (workspace.leaderboard_metric_kind === "recent_flow_shift_average") {
71628
+ if (workspace.leaderboard_metric_kind === "cycle_time") {
71501
71629
  const actualCT = formatCycleTimeValue(workspace.avg_cycle_time);
71502
71630
  const standardCT = formatCycleTimeValue(workspace.ideal_cycle_time);
71503
71631
  return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "tabular-nums", children: [
@@ -72466,13 +72594,13 @@ var LeaderboardDetailView = React144.memo(({
72466
72594
  error.message
72467
72595
  ] }) });
72468
72596
  }
72469
- const hasRecentFlowLeaderboardRows = sortedWorkspaces.some(
72470
- (workspace) => workspace.leaderboard_metric_kind === "recent_flow_shift_average"
72597
+ const hasCycleTimeLeaderboardRows = sortedWorkspaces.some(
72598
+ (workspace) => workspace.leaderboard_metric_kind === "cycle_time"
72471
72599
  );
72472
72600
  const hasEfficiencyLeaderboardRows = sortedWorkspaces.some(
72473
- (workspace) => workspace.leaderboard_metric_kind !== "recent_flow_shift_average"
72601
+ (workspace) => workspace.leaderboard_metric_kind !== "cycle_time"
72474
72602
  );
72475
- const metricLabel = viewType === "machine" ? "Utilization" : hasRecentFlowLeaderboardRows && !hasEfficiencyLeaderboardRows ? "Actual CT / Standard CT" : hasRecentFlowLeaderboardRows && hasEfficiencyLeaderboardRows ? "Performance" : "Efficiency";
72603
+ const metricLabel = viewType === "machine" ? "Utilization" : hasCycleTimeLeaderboardRows && !hasEfficiencyLeaderboardRows ? "Actual CT / Standard CT" : hasCycleTimeLeaderboardRows && hasEfficiencyLeaderboardRows ? "Performance" : "Efficiency";
72476
72604
  const descendingSortLabel = "Highest to Lowest";
72477
72605
  const ascendingSortLabel = "Lowest to Highest";
72478
72606
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `min-h-screen bg-slate-50 flex flex-col ${className}`, style: { willChange: "contents" }, children: [
@@ -87265,6 +87393,7 @@ exports.KPIDetailView = KPIDetailView_default;
87265
87393
  exports.KPIGrid = KPIGrid;
87266
87394
  exports.KPIHeader = KPIHeader;
87267
87395
  exports.KPISection = KPISection;
87396
+ exports.KPI_SIGNAL_LABELS = KPI_SIGNAL_LABELS;
87268
87397
  exports.KPIsOverviewView = KPIsOverviewView_default;
87269
87398
  exports.LINE_1_UUID = LINE_1_UUID;
87270
87399
  exports.LINE_2_UUID = LINE_2_UUID;
@@ -87398,6 +87527,7 @@ exports.WorkspaceWhatsAppShareButton = WorkspaceWhatsAppShareButton;
87398
87527
  exports.actionService = actionService;
87399
87528
  exports.addSentryBreadcrumb = addSentryBreadcrumb;
87400
87529
  exports.aggregateKPIsFromLineMetricsRows = aggregateKPIsFromLineMetricsRows;
87530
+ exports.aggregateLineSignals = aggregateLineSignals;
87401
87531
  exports.alertsService = alertsService;
87402
87532
  exports.apiUtils = apiUtils;
87403
87533
  exports.areAllLinesOnSameShift = areAllLinesOnSameShift;
@@ -87502,6 +87632,8 @@ exports.getDefaultCameraStreamUrl = getDefaultCameraStreamUrl;
87502
87632
  exports.getDefaultLineId = getDefaultLineId;
87503
87633
  exports.getDefaultTabForWorkspace = getDefaultTabForWorkspace;
87504
87634
  exports.getInitials = getInitials;
87635
+ exports.getKpiSignalLabel = getKpiSignalLabel;
87636
+ exports.getKpiSignalStatus = getKpiSignalStatus;
87505
87637
  exports.getLineDisplayName = getLineDisplayName;
87506
87638
  exports.getManufacturingInsights = getManufacturingInsights;
87507
87639
  exports.getMetricsTablePrefix = getMetricsTablePrefix;