@optifye/dashboard-core 6.12.49 → 6.12.50

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
@@ -13791,12 +13791,22 @@ var stripSeconds = (timeStr) => {
13791
13791
  if (!timeStr) return timeStr;
13792
13792
  return timeStr.substring(0, 5);
13793
13793
  };
13794
+ var normalizeOffDays = (value) => {
13795
+ if (!value) return [];
13796
+ if (Array.isArray(value)) {
13797
+ return value.map((day) => String(day || "").trim().toLowerCase()).filter(Boolean);
13798
+ }
13799
+ if (Array.isArray(value.off_days)) return normalizeOffDays(value.off_days);
13800
+ if (Array.isArray(value.offDays)) return normalizeOffDays(value.offDays);
13801
+ return [];
13802
+ };
13794
13803
  var buildShiftConfigFromOperatingHoursRows = (rows, fallback) => {
13795
13804
  const mapped = (rows || []).map((row) => ({
13796
13805
  shiftId: row.shift_id,
13797
13806
  shiftName: row.shift_name || `Shift ${row.shift_id}`,
13798
13807
  startTime: stripSeconds(row.start_time),
13799
13808
  endTime: stripSeconds(row.end_time),
13809
+ offDays: normalizeOffDays(row.off_days),
13800
13810
  breaks: (() => {
13801
13811
  const raw = Array.isArray(row.breaks) ? row.breaks : Array.isArray(row.breaks?.breaks) ? row.breaks.breaks : [];
13802
13812
  return raw.map((b) => ({
@@ -13856,7 +13866,7 @@ var fetchAndStoreShiftConfig = async (supabase, lineId, fallback) => {
13856
13866
  if (existing) return existing;
13857
13867
  const promise = (async () => {
13858
13868
  try {
13859
- const { data, error } = await supabase.from("line_operating_hours").select("line_id, shift_id, shift_name, start_time, end_time, breaks, timezone").eq("line_id", lineId);
13869
+ const { data, error } = await supabase.from("line_operating_hours").select("line_id, shift_id, shift_name, start_time, end_time, breaks, timezone, off_days").eq("line_id", lineId);
13860
13870
  if (error) {
13861
13871
  throw new Error(`Failed to fetch shift config: ${error.message}`);
13862
13872
  }
@@ -14549,7 +14559,7 @@ var useMultiLineShiftConfigs = (lineIds, fallbackConfig) => {
14549
14559
  setError(null);
14550
14560
  }
14551
14561
  console.log(`[useMultiLineShiftConfigs] Fetching shift configs for ${missingLineIds.length} lines`);
14552
- const { data, error: fetchError } = await supabase.from("line_operating_hours").select("line_id, shift_id, shift_name, start_time, end_time, breaks, timezone").in("line_id", missingLineIds);
14562
+ const { data, error: fetchError } = await supabase.from("line_operating_hours").select("line_id, shift_id, shift_name, start_time, end_time, breaks, timezone, off_days").in("line_id", missingLineIds);
14553
14563
  if (fetchError) {
14554
14564
  console.error("[useMultiLineShiftConfigs] Error fetching shift configs:", fetchError);
14555
14565
  throw new Error(`Failed to fetch shift configs: ${fetchError.message}`);
@@ -37779,7 +37789,12 @@ var HourlyOutputChartComponent = ({
37779
37789
  }, [idleBarState.visible, idleBarState.key, idleBarState.shouldAnimate]);
37780
37790
  const maxDataValue = Math.max(...data, 0);
37781
37791
  const numericChartTargets = chartData.map((d) => d.target).filter((target) => target !== null && Number.isFinite(target));
37782
- const maxTargetValue = Math.max(...numericChartTargets, pphThreshold, 0);
37792
+ const hasAuthoritativeNumericTargets = hasHourlyTargetOutputProp && numericChartTargets.length > 0;
37793
+ const maxTargetValue = Math.max(
37794
+ ...numericChartTargets,
37795
+ hasAuthoritativeNumericTargets ? 0 : pphThreshold,
37796
+ 0
37797
+ );
37783
37798
  const maxYValue = Math.max(
37784
37799
  Math.ceil(maxTargetValue * 1.5),
37785
37800
  Math.ceil(maxDataValue * 1.15)
@@ -37934,14 +37949,9 @@ var HourlyOutputChartComponent = ({
37934
37949
  return /* @__PURE__ */ jsx("g", { children: lines });
37935
37950
  }, [hourlyTargetSegments, targetTimelineSegments, SHIFT_DURATION, pphThreshold, targetLineEndOffset, hasHourlyTargetOutputProp]);
37936
37951
  const renderLegend = () => {
37937
- const uniqueTargets = [...new Set(
37938
- chartData.map((d) => d.target).filter((target) => target !== null && Number.isFinite(target)).map((target) => Math.round(target))
37939
- )].sort((a, b) => a - b);
37940
- const unitLabel = hasHourlyTargetOutputProp ? "units" : "units/hr";
37941
- const targetText = uniqueTargets.length === 0 ? `Target` : uniqueTargets.length === 1 ? `Target: ${uniqueTargets[0]} ${unitLabel}` : `Target: ${uniqueTargets[0]} - ${uniqueTargets[uniqueTargets.length - 1]} ${unitLabel}`;
37942
37952
  return /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center text-sm text-gray-600 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: [
37943
37953
  /* @__PURE__ */ jsx("div", { className: "w-8 flex items-center", children: /* @__PURE__ */ jsx("div", { className: "w-full border-t-2 border-[#E34329] border-dashed" }) }),
37944
- /* @__PURE__ */ jsx("span", { children: targetText })
37954
+ /* @__PURE__ */ jsx("span", { children: "Target" })
37945
37955
  ] }) });
37946
37956
  };
37947
37957
  return /* @__PURE__ */ jsxs(
@@ -52459,6 +52469,106 @@ var getOrdinal = (n) => {
52459
52469
  const v = n % 100;
52460
52470
  return n + (suffix[(v - 20) % 10] || suffix[v] || suffix[0]);
52461
52471
  };
52472
+ var resolveDailyTargetOutput = (shiftData) => {
52473
+ if (!shiftData || shiftData.hasData === false) return 0;
52474
+ const target = Number(shiftData?.targetOutput || shiftData?.idealOutput || 0);
52475
+ return Number.isFinite(target) && target > 0 ? target : 0;
52476
+ };
52477
+ var getUniqueRoundedTargets = (data) => Array.from(new Set(
52478
+ data.map((entry) => Number(entry.targetOutput || 0)).filter((target) => Number.isFinite(target) && target > 0).map((target) => Math.round(target))
52479
+ )).sort((a, b) => a - b);
52480
+ var formatDailyTargetLegend = (targets) => {
52481
+ if (targets.length === 0) return "";
52482
+ if (targets.length === 1) return `Target: ${targets[0].toLocaleString()} units/day`;
52483
+ return `Target: ${targets[0].toLocaleString()} - ${targets[targets.length - 1].toLocaleString()} units/day`;
52484
+ };
52485
+ var WEEKDAY_NAMES = ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"];
52486
+ var getShiftOffDays = (shiftConfig, selectedShiftId) => {
52487
+ const shift = shiftConfig?.shifts?.find((candidate) => candidate.shiftId === selectedShiftId);
52488
+ const raw = shift?.offDays || shift?.off_days || [];
52489
+ return Array.isArray(raw) ? raw.map((day) => String(day || "").trim().toLowerCase()).filter(Boolean) : [];
52490
+ };
52491
+ var isScheduledOffDay = (dateKey, shiftConfig, selectedShiftId) => {
52492
+ const offDays = getShiftOffDays(shiftConfig, selectedShiftId);
52493
+ if (offDays.length === 0) return false;
52494
+ const date = parseDateKeyToDate(dateKey);
52495
+ return offDays.includes(WEEKDAY_NAMES[date.getDay()]);
52496
+ };
52497
+ var renderDailyOutputCapsules = (props, data) => {
52498
+ const { offset, yAxisMap } = props;
52499
+ if (!offset || !yAxisMap || data.length === 0) return null;
52500
+ const { left, width } = offset;
52501
+ const yAxis = yAxisMap.default || yAxisMap[0];
52502
+ if (!Number.isFinite(left) || !Number.isFinite(width) || width <= 0 || !yAxis?.scale) {
52503
+ return null;
52504
+ }
52505
+ const slotWidth = width / data.length;
52506
+ const capsuleWidth = Math.max(10, Math.min(28, slotWidth * 0.44));
52507
+ const radius = capsuleWidth / 2;
52508
+ const baseY = yAxis.scale(0);
52509
+ const capsules = [];
52510
+ data.forEach((entry, index) => {
52511
+ const target = Number(entry.targetOutput || 0);
52512
+ const output = Number(entry.output || 0);
52513
+ if ((!Number.isFinite(target) || target <= 0) && (!Number.isFinite(output) || output <= 0)) return;
52514
+ const x = left + index * slotWidth + (slotWidth - capsuleWidth) / 2;
52515
+ const targetTop = target > 0 ? yAxis.scale(target) : yAxis.scale(output);
52516
+ const capsuleTop = Math.min(targetTop, baseY - 4);
52517
+ const capsuleHeight = Math.max(baseY - capsuleTop, 4);
52518
+ const fillValue = target > 0 ? Math.min(Math.max(output, 0), target) : Math.max(output, 0);
52519
+ const fillTop = fillValue > 0 ? Math.max(yAxis.scale(fillValue), capsuleTop) : baseY;
52520
+ const fillHeight = Math.max(baseY - fillTop, 0);
52521
+ const fillColor = target > 0 ? output >= target ? "#00AB45" : "#E34329" : entry.color || "#6b7280";
52522
+ const trackFill = output >= target ? "#f0fdf4" : "#fff5f3";
52523
+ const trackStroke = output >= target ? "#00AB45" : "#E34329";
52524
+ const clipId = `line-daily-output-capsule-${index}`;
52525
+ capsules.push(
52526
+ /* @__PURE__ */ jsxs("g", { children: [
52527
+ /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx("clipPath", { id: clipId, children: /* @__PURE__ */ jsx(
52528
+ "rect",
52529
+ {
52530
+ x,
52531
+ y: capsuleTop,
52532
+ width: capsuleWidth,
52533
+ height: capsuleHeight,
52534
+ rx: radius,
52535
+ ry: radius
52536
+ }
52537
+ ) }) }),
52538
+ target > 0 && /* @__PURE__ */ jsx(
52539
+ "rect",
52540
+ {
52541
+ "data-testid": "daily-target-capsule-track",
52542
+ x,
52543
+ y: capsuleTop,
52544
+ width: capsuleWidth,
52545
+ height: capsuleHeight,
52546
+ rx: radius,
52547
+ ry: radius,
52548
+ fill: trackFill,
52549
+ stroke: trackStroke,
52550
+ strokeWidth: 1.5
52551
+ }
52552
+ ),
52553
+ /* @__PURE__ */ jsx(
52554
+ "rect",
52555
+ {
52556
+ "data-testid": "daily-output-capsule-fill",
52557
+ x,
52558
+ y: fillTop,
52559
+ width: capsuleWidth,
52560
+ height: fillHeight,
52561
+ rx: fillHeight >= capsuleHeight ? radius : 0,
52562
+ ry: fillHeight >= capsuleHeight ? radius : 0,
52563
+ fill: fillColor,
52564
+ clipPath: target > 0 ? `url(#${clipId})` : void 0
52565
+ }
52566
+ )
52567
+ ] }, `daily-output-capsule-${index}`)
52568
+ );
52569
+ });
52570
+ return capsules.length > 0 ? /* @__PURE__ */ jsx("g", { children: capsules }) : null;
52571
+ };
52462
52572
  var CustomTooltip2 = ({ active, payload, label, isUptimeMode }) => {
52463
52573
  if (!active || !payload || payload.length === 0) return null;
52464
52574
  if (isUptimeMode) {
@@ -52542,6 +52652,7 @@ var LineMonthlyHistory = ({
52542
52652
  legend,
52543
52653
  monitoringMode,
52544
52654
  lineAssembly = false,
52655
+ shiftConfig,
52545
52656
  underperformingWorkspaces = {},
52546
52657
  lineId,
52547
52658
  selectedShiftId = 0,
@@ -52559,6 +52670,13 @@ var LineMonthlyHistory = ({
52559
52670
  const { isIdleTimeVlmEnabled } = useIdleTimeVlmConfig();
52560
52671
  const idleTimeVlmEnabled = isIdleTimeVlmEnabled(lineId);
52561
52672
  const isUptimeMode = monitoringMode === "uptime";
52673
+ const [isMobile, setIsMobile] = useState(false);
52674
+ useEffect(() => {
52675
+ const checkMobile = () => setIsMobile(window.innerWidth < 640);
52676
+ checkMobile();
52677
+ window.addEventListener("resize", checkMobile);
52678
+ return () => window.removeEventListener("resize", checkMobile);
52679
+ }, []);
52562
52680
  const chartKey = useMemo(() => `${lineId}-${month}-${year}-${selectedShiftId}-${rangeStart}-${rangeEnd}`, [lineId, month, year, selectedShiftId, rangeStart, rangeEnd]);
52563
52681
  const monthBounds = useMemo(() => getMonthKeyBounds(year, month), [year, month]);
52564
52682
  const normalizedRange = useMemo(() => {
@@ -52720,29 +52838,21 @@ var LineMonthlyHistory = ({
52720
52838
  });
52721
52839
  }
52722
52840
  const yAxisMax2 = maxHours > 0 ? 100 : 1;
52723
- return { data: dailyData2, maxOutput: 0, lastSetTarget: 0, yAxisMax: yAxisMax2 };
52841
+ return { data: dailyData2, maxOutput: 0, targetValues: [], yAxisMax: yAxisMax2, targetLegend: "" };
52724
52842
  }
52725
52843
  const dailyData = [];
52726
52844
  let maxOutput = 0;
52727
- let lastSetTarget = 0;
52728
- for (let i = rangeDateKeys.length - 1; i >= 0; i--) {
52729
- const dayKey = rangeDateKeys[i];
52730
- const dayData = analysisMonthlyDataByKey.get(dayKey);
52731
- const shiftData = dayData ? getShiftData2(dayData, selectedShiftId) : null;
52732
- const idealOutput = shiftData ? shiftData.idealOutput || 0 : 0;
52733
- if (idealOutput > 0) {
52734
- lastSetTarget = idealOutput;
52735
- break;
52736
- }
52737
- }
52845
+ let maxTarget = 0;
52738
52846
  for (const dayKey of rangeDateKeys) {
52739
52847
  const day = Number(dayKey.slice(-2));
52740
52848
  const dayData = analysisMonthlyDataByKey.get(dayKey);
52849
+ const isOffDay = isScheduledOffDay(dayKey, shiftConfig, selectedShiftId);
52741
52850
  const shiftData = dayData ? getShiftData2(dayData, selectedShiftId) : null;
52742
- const output = shiftData && hasRealData(shiftData) ? shiftData.output || 0 : 0;
52743
- const idealOutput = shiftData ? shiftData.idealOutput || 0 : 0;
52851
+ const output = !isOffDay && shiftData && hasRealData(shiftData) ? shiftData.output || 0 : 0;
52852
+ const targetOutput = isOffDay ? 0 : resolveDailyTargetOutput(shiftData);
52744
52853
  if (output > maxOutput) maxOutput = output;
52745
- const color2 = output >= lastSetTarget ? "#00AB45" : "#E34329";
52854
+ if (targetOutput > maxTarget) maxTarget = targetOutput;
52855
+ const color2 = targetOutput > 0 && output >= targetOutput ? "#00AB45" : "#E34329";
52746
52856
  dailyData.push({
52747
52857
  hour: getOrdinal(day),
52748
52858
  // Using ordinal format (1st, 2nd, 3rd, etc.)
@@ -52750,17 +52860,25 @@ var LineMonthlyHistory = ({
52750
52860
  output,
52751
52861
  originalOutput: output,
52752
52862
  // For label display
52753
- idealOutput,
52863
+ idealOutput: targetOutput,
52864
+ targetOutput,
52754
52865
  color: color2
52755
52866
  });
52756
52867
  }
52757
- const calculatedMax = Math.max(maxOutput, lastSetTarget);
52868
+ const calculatedMax = Math.max(maxOutput, maxTarget);
52758
52869
  const yAxisMax = calculatedMax > 0 ? calculatedMax * 1.1 : 100;
52759
- return { data: dailyData, maxOutput, lastSetTarget, yAxisMax };
52760
- }, [analysisMonthlyDataByKey, normalizedRange.endKey, normalizedRange.startKey, selectedShiftId, isUptimeMode, timezone]);
52870
+ const targetValues = getUniqueRoundedTargets(dailyData);
52871
+ return {
52872
+ data: dailyData,
52873
+ maxOutput,
52874
+ targetValues,
52875
+ yAxisMax,
52876
+ targetLegend: formatDailyTargetLegend(targetValues)
52877
+ };
52878
+ }, [analysisMonthlyDataByKey, normalizedRange.endKey, normalizedRange.startKey, selectedShiftId, isUptimeMode, timezone, shiftConfig]);
52761
52879
  const yAxisTicks = useMemo(() => {
52762
52880
  const max = chartData.yAxisMax;
52763
- const target = chartData.lastSetTarget;
52881
+ const targets = chartData.targetValues || [];
52764
52882
  if (!max || max <= 0) return void 0;
52765
52883
  const desiredIntervals = 4;
52766
52884
  const roughStep = max / desiredIntervals;
@@ -52774,11 +52892,18 @@ var LineMonthlyHistory = ({
52774
52892
  for (let v = 0; v <= max; v += step) {
52775
52893
  ticks.push(Math.round(v));
52776
52894
  }
52777
- if (target > 0) {
52778
- ticks.push(Math.round(target));
52779
- }
52895
+ targets.forEach((target) => ticks.push(Math.round(target)));
52780
52896
  return Array.from(new Set(ticks)).filter((v) => v >= 0 && v <= max).sort((a, b) => a - b);
52781
- }, [chartData.yAxisMax, chartData.lastSetTarget]);
52897
+ }, [chartData.yAxisMax, chartData.targetValues]);
52898
+ const visibleYAxisTicks = useMemo(() => {
52899
+ if (!isMobile || isUptimeMode || !yAxisTicks || yAxisTicks.length <= 3) return yAxisTicks;
52900
+ const importantTicks = /* @__PURE__ */ new Set([
52901
+ 0,
52902
+ Math.round(chartData.yAxisMax),
52903
+ ...chartData.targetValues || []
52904
+ ]);
52905
+ return yAxisTicks.filter((tick) => importantTicks.has(Math.round(tick))).sort((a, b) => a - b).slice(-3);
52906
+ }, [chartData.targetValues, chartData.yAxisMax, isMobile, isUptimeMode, yAxisTicks]);
52782
52907
  const pieChartData = useMemo(() => {
52783
52908
  if (!isUptimeMode) return [];
52784
52909
  const validShifts = (analysisMonthlyData || []).map((day) => getShiftData2(day, selectedShiftId)).filter(
@@ -53097,36 +53222,35 @@ var LineMonthlyHistory = ({
53097
53222
  ] }),
53098
53223
  /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-lg sm:rounded-xl shadow-sm border border-gray-100 p-2 sm:p-3 lg:p-4", children: [
53099
53224
  /* @__PURE__ */ jsx("h3", { className: "text-xs sm:text-sm font-bold text-gray-700 mb-1 sm:mb-2 text-left", children: isUptimeMode ? "Daily Utilization" : "Daily Output" }),
53100
- /* @__PURE__ */ jsx("div", { className: "h-[160px] sm:h-[180px] lg:h-[220px]", children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
53225
+ /* @__PURE__ */ jsx("div", { className: "h-[140px] sm:h-[180px] lg:h-[220px]", children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
53101
53226
  BarChart$1,
53102
53227
  {
53103
53228
  data: chartData.data,
53104
- margin: { top: 20, right: 10, bottom: 40, left: 10 },
53229
+ margin: isMobile ? { top: 8, right: 4, bottom: 28, left: 0 } : { top: 20, right: 10, bottom: 40, left: 10 },
53105
53230
  children: [
53106
53231
  /* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#f3f4f6" }),
53107
53232
  /* @__PURE__ */ jsx(
53108
53233
  XAxis,
53109
53234
  {
53110
53235
  dataKey: "hour",
53111
- tick: { fontSize: 10, fill: "#6b7280" },
53112
- interval: 0,
53236
+ tick: { fontSize: isMobile ? 9 : 10, fill: "#6b7280" },
53237
+ interval: isMobile ? 3 : 0,
53113
53238
  angle: -45,
53114
53239
  textAnchor: "end",
53115
- height: 60
53240
+ height: isMobile ? 42 : 60
53116
53241
  }
53117
53242
  ),
53118
53243
  /* @__PURE__ */ jsx(
53119
53244
  YAxis,
53120
53245
  {
53121
53246
  domain: [0, chartData.yAxisMax],
53122
- width: 40,
53123
- ticks: isUptimeMode ? [0, 25, 50, 75, 100] : yAxisTicks,
53247
+ width: isMobile ? 34 : 40,
53248
+ ticks: isUptimeMode ? [0, 25, 50, 75, 100] : visibleYAxisTicks,
53124
53249
  tickFormatter: isUptimeMode ? (value) => `${value}%` : void 0,
53125
53250
  tick: isUptimeMode ? void 0 : (props) => {
53126
53251
  const { x, y, payload } = props;
53127
53252
  const value = Math.round(payload.value);
53128
- const targetValue = Math.round(chartData.lastSetTarget);
53129
- const isTarget = value === targetValue && targetValue > 0;
53253
+ const isTarget = (chartData.targetValues || []).includes(value);
53130
53254
  return /* @__PURE__ */ jsx(
53131
53255
  "text",
53132
53256
  {
@@ -53149,15 +53273,7 @@ var LineMonthlyHistory = ({
53149
53273
  content: (props) => /* @__PURE__ */ jsx(CustomTooltip2, { ...props, isUptimeMode })
53150
53274
  }
53151
53275
  ),
53152
- !isUptimeMode && chartData.lastSetTarget > 0 && /* @__PURE__ */ jsx(
53153
- ReferenceLine,
53154
- {
53155
- y: chartData.lastSetTarget,
53156
- stroke: "#E34329",
53157
- strokeDasharray: "5 5",
53158
- strokeWidth: 2
53159
- }
53160
- ),
53276
+ !isUptimeMode && /* @__PURE__ */ jsx(Customized, { component: (props) => renderDailyOutputCapsules(props, chartData.data) }),
53161
53277
  isUptimeMode ? /* @__PURE__ */ jsxs(Fragment, { children: [
53162
53278
  /* @__PURE__ */ jsx(
53163
53279
  Bar,
@@ -53190,6 +53306,8 @@ var LineMonthlyHistory = ({
53190
53306
  {
53191
53307
  dataKey: "output",
53192
53308
  radius: [4, 4, 0, 0],
53309
+ fill: "transparent",
53310
+ opacity: 0,
53193
53311
  isAnimationActive: true,
53194
53312
  animationBegin: 0,
53195
53313
  animationDuration: 1e3,
@@ -53208,13 +53326,9 @@ var LineMonthlyHistory = ({
53208
53326
  },
53209
53327
  chartKey
53210
53328
  ) }) }),
53211
- !isUptimeMode && chartData.lastSetTarget > 0 && /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center text-sm text-gray-600 bg-white py-1 pt-2", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border border-gray-100 rounded-full px-3 py-1", children: [
53212
- /* @__PURE__ */ jsx("div", { className: "w-8 flex items-center", children: /* @__PURE__ */ jsx("div", { className: "w-full border-t-2 border-[#E34329] border-dashed" }) }),
53213
- /* @__PURE__ */ jsxs("span", { children: [
53214
- "Target: ",
53215
- Math.round(chartData.lastSetTarget),
53216
- " units/day"
53217
- ] })
53329
+ !isUptimeMode && chartData.targetValues.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center text-sm text-gray-600 bg-white py-1 pt-2", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border border-gray-100 rounded-full px-3 py-1", children: [
53330
+ /* @__PURE__ */ jsx("div", { className: "relative h-5 w-3 rounded-full border border-[#E34329] bg-[#fff5f3] overflow-hidden", children: /* @__PURE__ */ jsx("div", { className: "absolute inset-x-0 bottom-0 h-1/2 bg-[#E34329]" }) }),
53331
+ /* @__PURE__ */ jsx("span", { children: chartData.targetLegend })
53218
53332
  ] }) })
53219
53333
  ] })
53220
53334
  ] })
@@ -55137,6 +55251,106 @@ var formatCycleSeconds = (value) => {
55137
55251
  if (!Number.isFinite(value)) return "0.0s";
55138
55252
  return `${value.toFixed(1)}s`;
55139
55253
  };
55254
+ var resolveDailyTargetOutput2 = (shiftData) => {
55255
+ if (!shiftData || shiftData.hasData === false) return 0;
55256
+ const target = Number(shiftData?.targetOutput || shiftData?.idealOutput || 0);
55257
+ return Number.isFinite(target) && target > 0 ? target : 0;
55258
+ };
55259
+ var getUniqueRoundedTargets2 = (data) => Array.from(new Set(
55260
+ data.map((entry) => Number(entry.targetOutput || 0)).filter((target) => Number.isFinite(target) && target > 0).map((target) => Math.round(target))
55261
+ )).sort((a, b) => a - b);
55262
+ var formatDailyTargetLegend2 = (targets) => {
55263
+ if (targets.length === 0) return "";
55264
+ if (targets.length === 1) return `Target: ${targets[0].toLocaleString()} units/day`;
55265
+ return `Target: ${targets[0].toLocaleString()} - ${targets[targets.length - 1].toLocaleString()} units/day`;
55266
+ };
55267
+ var WEEKDAY_NAMES2 = ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"];
55268
+ var getShiftOffDays2 = (shiftConfig, selectedShiftId) => {
55269
+ const shift = shiftConfig?.shifts?.find((candidate) => candidate.shiftId === selectedShiftId);
55270
+ const raw = shift?.offDays || shift?.off_days || [];
55271
+ return Array.isArray(raw) ? raw.map((day) => String(day || "").trim().toLowerCase()).filter(Boolean) : [];
55272
+ };
55273
+ var isScheduledOffDay2 = (dateKey, shiftConfig, selectedShiftId) => {
55274
+ const offDays = getShiftOffDays2(shiftConfig, selectedShiftId);
55275
+ if (offDays.length === 0) return false;
55276
+ const date = parseDateKeyToDate(dateKey);
55277
+ return offDays.includes(WEEKDAY_NAMES2[date.getDay()]);
55278
+ };
55279
+ var renderDailyOutputCapsules2 = (props, data) => {
55280
+ const { offset, yAxisMap } = props;
55281
+ if (!offset || !yAxisMap || data.length === 0) return null;
55282
+ const { left, width } = offset;
55283
+ const yAxis = yAxisMap.default || yAxisMap[0];
55284
+ if (!Number.isFinite(left) || !Number.isFinite(width) || width <= 0 || !yAxis?.scale) {
55285
+ return null;
55286
+ }
55287
+ const slotWidth = width / data.length;
55288
+ const capsuleWidth = Math.max(10, Math.min(28, slotWidth * 0.44));
55289
+ const radius = capsuleWidth / 2;
55290
+ const baseY = yAxis.scale(0);
55291
+ const capsules = [];
55292
+ data.forEach((entry, index) => {
55293
+ const target = Number(entry.targetOutput || 0);
55294
+ const output = Number(entry.output || 0);
55295
+ if ((!Number.isFinite(target) || target <= 0) && (!Number.isFinite(output) || output <= 0)) return;
55296
+ const x = left + index * slotWidth + (slotWidth - capsuleWidth) / 2;
55297
+ const targetTop = target > 0 ? yAxis.scale(target) : yAxis.scale(output);
55298
+ const capsuleTop = Math.min(targetTop, baseY - 4);
55299
+ const capsuleHeight = Math.max(baseY - capsuleTop, 4);
55300
+ const fillValue = target > 0 ? Math.min(Math.max(output, 0), target) : Math.max(output, 0);
55301
+ const fillTop = fillValue > 0 ? Math.max(yAxis.scale(fillValue), capsuleTop) : baseY;
55302
+ const fillHeight = Math.max(baseY - fillTop, 0);
55303
+ const fillColor = target > 0 ? output >= target ? "#00AB45" : "#E34329" : entry.color || "#6b7280";
55304
+ const trackFill = output >= target ? "#f0fdf4" : "#fff5f3";
55305
+ const trackStroke = output >= target ? "#00AB45" : "#E34329";
55306
+ const clipId = `workspace-daily-output-capsule-${index}`;
55307
+ capsules.push(
55308
+ /* @__PURE__ */ jsxs("g", { children: [
55309
+ /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx("clipPath", { id: clipId, children: /* @__PURE__ */ jsx(
55310
+ "rect",
55311
+ {
55312
+ x,
55313
+ y: capsuleTop,
55314
+ width: capsuleWidth,
55315
+ height: capsuleHeight,
55316
+ rx: radius,
55317
+ ry: radius
55318
+ }
55319
+ ) }) }),
55320
+ target > 0 && /* @__PURE__ */ jsx(
55321
+ "rect",
55322
+ {
55323
+ "data-testid": "daily-target-capsule-track",
55324
+ x,
55325
+ y: capsuleTop,
55326
+ width: capsuleWidth,
55327
+ height: capsuleHeight,
55328
+ rx: radius,
55329
+ ry: radius,
55330
+ fill: trackFill,
55331
+ stroke: trackStroke,
55332
+ strokeWidth: 1.5
55333
+ }
55334
+ ),
55335
+ /* @__PURE__ */ jsx(
55336
+ "rect",
55337
+ {
55338
+ "data-testid": "daily-output-capsule-fill",
55339
+ x,
55340
+ y: fillTop,
55341
+ width: capsuleWidth,
55342
+ height: fillHeight,
55343
+ rx: fillHeight >= capsuleHeight ? radius : 0,
55344
+ ry: fillHeight >= capsuleHeight ? radius : 0,
55345
+ fill: fillColor,
55346
+ clipPath: target > 0 ? `url(#${clipId})` : void 0
55347
+ }
55348
+ )
55349
+ ] }, `daily-output-capsule-${index}`)
55350
+ );
55351
+ });
55352
+ return capsules.length > 0 ? /* @__PURE__ */ jsx("g", { children: capsules }) : null;
55353
+ };
55140
55354
  var CustomTooltip3 = ({ active, payload, label, isUptimeMode }) => {
55141
55355
  if (!active || !payload || payload.length === 0) return null;
55142
55356
  if (isUptimeMode) {
@@ -55316,28 +55530,20 @@ var WorkspaceMonthlyHistory = ({
55316
55530
  });
55317
55531
  }
55318
55532
  const yAxisMax2 = maxHours > 0 ? maxHours * 1.1 : 1;
55319
- return { data: dailyData, yAxisMax: yAxisMax2, lastSetTarget: 0 };
55533
+ return { data: dailyData, yAxisMax: yAxisMax2, targetValues: [], targetLegend: "" };
55320
55534
  }
55321
55535
  let maxOutput = 0;
55322
- let lastSetTarget = 0;
55323
- for (let i = rangeDateKeys.length - 1; i >= 0; i--) {
55324
- const dateKey = rangeDateKeys[i];
55325
- const dayData = analysisMonthlyDataByKey.get(dateKey);
55326
- const shiftData = dayData ? getShiftData(dayData, selectedShiftId) : null;
55327
- const idealOutput = shiftData ? shiftData.idealOutput : 0;
55328
- if (idealOutput > 0) {
55329
- lastSetTarget = idealOutput;
55330
- break;
55331
- }
55332
- }
55536
+ let maxTarget = 0;
55333
55537
  for (const dateKey of rangeDateKeys) {
55334
55538
  const dayData = analysisMonthlyDataByKey.get(dateKey);
55335
55539
  const dayNumber = Number(dateKey.slice(-2));
55540
+ const isOffDay = isScheduledOffDay2(dateKey, shiftConfig, selectedShiftId);
55336
55541
  const shiftData = dayData ? getShiftData(dayData, selectedShiftId) : null;
55337
- const output = shiftData && hasRealData(shiftData) ? shiftData.output : 0;
55338
- const idealOutput = shiftData ? shiftData.idealOutput : 0;
55542
+ const output = !isOffDay && shiftData && hasRealData(shiftData) ? shiftData.output : 0;
55543
+ const targetOutput = isOffDay ? 0 : resolveDailyTargetOutput2(shiftData);
55339
55544
  if (output > maxOutput) maxOutput = output;
55340
- const color2 = output >= lastSetTarget ? "#00AB45" : "#E34329";
55545
+ if (targetOutput > maxTarget) maxTarget = targetOutput;
55546
+ const color2 = targetOutput > 0 && output >= targetOutput ? "#00AB45" : "#E34329";
55341
55547
  dailyData.push({
55342
55548
  hour: getOrdinal2(dayNumber),
55343
55549
  // Using ordinal format (1st, 2nd, 3rd, etc.)
@@ -55345,21 +55551,29 @@ var WorkspaceMonthlyHistory = ({
55345
55551
  output,
55346
55552
  originalOutput: output,
55347
55553
  // For label display
55348
- idealOutput,
55554
+ idealOutput: targetOutput,
55555
+ targetOutput,
55349
55556
  efficiency: shiftData && hasRealData(shiftData) ? shiftData.efficiency : 0,
55350
55557
  color: color2,
55351
55558
  idleMinutes: 0
55352
55559
  // Not used but keeps structure consistent
55353
55560
  });
55354
55561
  }
55355
- const calculatedMax = Math.max(maxOutput, lastSetTarget);
55562
+ const calculatedMax = Math.max(maxOutput, maxTarget);
55356
55563
  const yAxisMax = calculatedMax > 0 ? calculatedMax * 1.1 : 100;
55357
- return { data: dailyData, maxOutput, lastSetTarget, yAxisMax };
55358
- }, [analysisMonthlyDataByKey, rangeDateKeys, selectedShiftId, isUptimeMode, shiftWorkSeconds]);
55564
+ const targetValues = getUniqueRoundedTargets2(dailyData);
55565
+ return {
55566
+ data: dailyData,
55567
+ maxOutput,
55568
+ targetValues,
55569
+ yAxisMax,
55570
+ targetLegend: formatDailyTargetLegend2(targetValues)
55571
+ };
55572
+ }, [analysisMonthlyDataByKey, rangeDateKeys, selectedShiftId, isUptimeMode, shiftConfig, shiftWorkSeconds]);
55359
55573
  const yAxisTicks = useMemo(() => {
55360
55574
  if (isUptimeMode) return void 0;
55361
55575
  const max = chartData.yAxisMax;
55362
- const target = chartData.lastSetTarget;
55576
+ const targets = chartData.targetValues || [];
55363
55577
  if (!max || max <= 0) return void 0;
55364
55578
  const desiredIntervals = 4;
55365
55579
  const roughStep = max / desiredIntervals;
@@ -55373,7 +55587,7 @@ var WorkspaceMonthlyHistory = ({
55373
55587
  for (let v = 0; v <= max; v += step) {
55374
55588
  ticks.push(Math.round(v));
55375
55589
  }
55376
- if (target > 0) {
55590
+ targets.forEach((target) => {
55377
55591
  const roundedTarget = Math.round(target);
55378
55592
  if (!ticks.includes(roundedTarget)) {
55379
55593
  let nearestIndex = -1;
@@ -55392,9 +55606,18 @@ var WorkspaceMonthlyHistory = ({
55392
55606
  ticks.push(roundedTarget);
55393
55607
  }
55394
55608
  }
55395
- }
55609
+ });
55396
55610
  return ticks.filter((v) => v >= 0 && v <= max * 1.05).sort((a, b) => a - b);
55397
- }, [chartData.yAxisMax, chartData.lastSetTarget, isUptimeMode]);
55611
+ }, [chartData.yAxisMax, chartData.targetValues, isUptimeMode]);
55612
+ const visibleYAxisTicks = useMemo(() => {
55613
+ if (!isMobile || isUptimeMode || !yAxisTicks || yAxisTicks.length <= 3) return yAxisTicks;
55614
+ const importantTicks = /* @__PURE__ */ new Set([
55615
+ 0,
55616
+ Math.round(chartData.yAxisMax),
55617
+ ...chartData.targetValues || []
55618
+ ]);
55619
+ return yAxisTicks.filter((tick) => importantTicks.has(Math.round(tick))).sort((a, b) => a - b).slice(-3);
55620
+ }, [chartData.targetValues, chartData.yAxisMax, isMobile, isUptimeMode, yAxisTicks]);
55398
55621
  const pieChartData = useMemo(() => {
55399
55622
  const aggregateMode = isUptimeMode ? "uptime" : "output";
55400
55623
  const validShifts = analysisMonthlyData.map((d) => getShiftData(d, selectedShiftId)).filter(
@@ -55784,22 +56007,22 @@ var WorkspaceMonthlyHistory = ({
55784
56007
  ] }),
55785
56008
  (!isAssemblyWorkspace || isUptimeMode) && /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-lg shadow-sm border border-gray-100 p-4 flex-1", children: [
55786
56009
  /* @__PURE__ */ jsx("h3", { className: "text-lg font-bold text-gray-700 mb-3 text-left", children: isUptimeMode ? "Daily Utilization" : "Daily Output" }),
55787
- /* @__PURE__ */ jsx("div", { style: { height: "220px" }, children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
56010
+ /* @__PURE__ */ jsx("div", { style: { height: isMobile ? "150px" : "220px" }, children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
55788
56011
  BarChart$1,
55789
56012
  {
55790
56013
  data: chartData.data,
55791
- margin: { top: 20, right: 10, bottom: 40, left: 10 },
56014
+ margin: isMobile ? { top: 8, right: 4, bottom: 28, left: 0 } : { top: 20, right: 10, bottom: 40, left: 10 },
55792
56015
  children: [
55793
56016
  /* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#f3f4f6" }),
55794
56017
  /* @__PURE__ */ jsx(
55795
56018
  XAxis,
55796
56019
  {
55797
56020
  dataKey: "hour",
55798
- tick: { fontSize: 10, fill: "#6b7280" },
55799
- interval: isMobile ? "preserveStartEnd" : 0,
56021
+ tick: { fontSize: isMobile ? 9 : 10, fill: "#6b7280" },
56022
+ interval: isMobile ? 3 : 0,
55800
56023
  angle: -45,
55801
56024
  textAnchor: "end",
55802
- height: 60
56025
+ height: isMobile ? 42 : 60
55803
56026
  }
55804
56027
  ),
55805
56028
  isUptimeMode ? /* @__PURE__ */ jsx(
@@ -55814,13 +56037,12 @@ var WorkspaceMonthlyHistory = ({
55814
56037
  YAxis,
55815
56038
  {
55816
56039
  domain: [0, chartData.yAxisMax],
55817
- width: 40,
55818
- ticks: yAxisTicks,
56040
+ width: isMobile ? 34 : 40,
56041
+ ticks: visibleYAxisTicks,
55819
56042
  tick: (props) => {
55820
56043
  const { x, y, payload } = props;
55821
56044
  const value = Math.round(payload.value);
55822
- const targetValue = Math.round(chartData.lastSetTarget);
55823
- const isTarget = value === targetValue && targetValue > 0;
56045
+ const isTarget = (chartData.targetValues || []).includes(value);
55824
56046
  return /* @__PURE__ */ jsx(
55825
56047
  "text",
55826
56048
  {
@@ -55843,15 +56065,7 @@ var WorkspaceMonthlyHistory = ({
55843
56065
  content: (props) => /* @__PURE__ */ jsx(CustomTooltip3, { ...props, isUptimeMode })
55844
56066
  }
55845
56067
  ),
55846
- !isUptimeMode && chartData.lastSetTarget > 0 && /* @__PURE__ */ jsx(
55847
- ReferenceLine,
55848
- {
55849
- y: chartData.lastSetTarget,
55850
- stroke: "#E34329",
55851
- strokeDasharray: "5 5",
55852
- strokeWidth: 2
55853
- }
55854
- ),
56068
+ !isUptimeMode && /* @__PURE__ */ jsx(Customized, { component: (props) => renderDailyOutputCapsules2(props, chartData.data) }),
55855
56069
  isUptimeMode ? /* @__PURE__ */ jsxs(Fragment, { children: [
55856
56070
  /* @__PURE__ */ jsx(
55857
56071
  Bar,
@@ -55884,6 +56098,8 @@ var WorkspaceMonthlyHistory = ({
55884
56098
  {
55885
56099
  dataKey: "output",
55886
56100
  radius: [4, 4, 0, 0],
56101
+ fill: "transparent",
56102
+ opacity: 0,
55887
56103
  isAnimationActive: true,
55888
56104
  animationBegin: 0,
55889
56105
  animationDuration: 1e3,
@@ -55927,13 +56143,9 @@ var WorkspaceMonthlyHistory = ({
55927
56143
  /* @__PURE__ */ jsx("span", { className: "w-2.5 h-2.5 rounded-full", style: { backgroundColor: "#e5e7eb" } }),
55928
56144
  /* @__PURE__ */ jsx("span", { className: "text-xs text-gray-600", children: "Idle" })
55929
56145
  ] })
55930
- ] }) : chartData.lastSetTarget > 0 && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
55931
- /* @__PURE__ */ jsx("div", { className: "w-12 h-0.5 border-t-2 border-dashed", style: { borderColor: "#E34329" } }),
55932
- /* @__PURE__ */ jsxs("span", { className: "text-xs text-gray-600", children: [
55933
- "Target: ",
55934
- Math.round(chartData.lastSetTarget),
55935
- " units/day"
55936
- ] })
56146
+ ] }) : chartData.targetValues.length > 0 && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
56147
+ /* @__PURE__ */ jsx("div", { className: "relative h-5 w-3 rounded-full border border-[#E34329] bg-[#fff5f3] overflow-hidden", children: /* @__PURE__ */ jsx("div", { className: "absolute inset-x-0 bottom-0 h-1/2 bg-[#E34329]" }) }),
56148
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-gray-600", children: chartData.targetLegend })
55937
56149
  ] }) })
55938
56150
  ] })
55939
56151
  ] })
@@ -67563,6 +67775,17 @@ var setSessionSeenValue = (key) => {
67563
67775
  };
67564
67776
  var buildAllGreenCelebrationSeenKey = (identity) => `${ALL_GREEN_CELEBRATION_SEEN_PREFIX}${identity}`;
67565
67777
  var buildAllGreenMilestoneSeenKey = (identity, milestoneSeconds) => `${ALL_GREEN_MILESTONE_SEEN_PREFIX}${identity}:${milestoneSeconds}`;
67778
+ var LINE_SELECTOR_INDICATOR_VERSION = "incident_exclamation_v1";
67779
+ var LineSelectorIncidentIcon = ({ lineId }) => /* @__PURE__ */ jsx(
67780
+ "span",
67781
+ {
67782
+ "data-testid": `line-selector-incident-icon-${lineId}`,
67783
+ "aria-label": "Line needs attention",
67784
+ role: "img",
67785
+ className: "inline-flex h-5 w-5 flex-shrink-0 items-center justify-center rounded-full border border-rose-200 bg-white text-[13px] font-semibold leading-none text-rose-600 shadow-[0_1px_2px_rgba(15,23,42,0.06)]",
67786
+ children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "-mt-px", children: "!" })
67787
+ }
67788
+ );
67566
67789
  var LoadingPageCmp = LoadingPage_default;
67567
67790
  var LoadingOverlayCmp = LoadingOverlay_default;
67568
67791
  function HomeView({
@@ -67902,25 +68125,49 @@ function HomeView({
67902
68125
  const currentIsCurrentScopeResolved = isBootstrapMonitorMode ? bootstrapMonitor.isCurrentScopeResolved : legacyIsCurrentScopeResolved;
67903
68126
  const currentMetricsError = isBootstrapMonitorMode ? bootstrapMonitor.error : legacyMetricsError;
67904
68127
  const currentRefetchMetrics = isBootstrapMonitorMode ? bootstrapMonitor.refetch : refetchLegacyMetrics;
67905
- const lineSelectorSignalStatusByLine = useMemo(() => {
67906
- const statusByLine = /* @__PURE__ */ new Map();
68128
+ const lineSelectorIndicatorByLine = useMemo(() => {
68129
+ const indicatorByLine = /* @__PURE__ */ new Map();
67907
68130
  const legend = currentEfficiencyLegend || DEFAULT_EFFICIENCY_LEGEND;
67908
68131
  const addRows = (rows) => {
67909
68132
  (rows || []).forEach((row) => {
67910
68133
  const lineId = typeof row?.line_id === "string" ? row.line_id : "";
67911
- if (!lineId || statusByLine.has(lineId)) {
68134
+ if (!lineId) {
68135
+ return;
68136
+ }
68137
+ if (row?.red_flow_incident?.active === true) {
68138
+ indicatorByLine.set(lineId, "incident");
68139
+ return;
68140
+ }
68141
+ if (indicatorByLine.get(lineId) === "incident") {
67912
68142
  return;
67913
68143
  }
67914
68144
  const status = getKpiSignalStatus(row?.line_signal, legend);
67915
- if (status) {
67916
- statusByLine.set(lineId, status);
68145
+ if (status === "attention") {
68146
+ indicatorByLine.set(lineId, "red");
67917
68147
  }
67918
68148
  });
67919
68149
  };
67920
68150
  addRows(currentSelectorLineMetrics);
67921
68151
  addRows(currentLineMetrics);
67922
- return statusByLine;
68152
+ return indicatorByLine;
67923
68153
  }, [currentEfficiencyLegend, currentLineMetrics, currentSelectorLineMetrics]);
68154
+ const lineSelectorIndicatorStats = useMemo(() => {
68155
+ let incidentLineCount = 0;
68156
+ let redFlowLineCount = 0;
68157
+ visibleLineIds.forEach((lineId) => {
68158
+ const indicator = lineSelectorIndicatorByLine.get(lineId);
68159
+ if (indicator === "incident") {
68160
+ incidentLineCount += 1;
68161
+ } else if (indicator === "red") {
68162
+ redFlowLineCount += 1;
68163
+ }
68164
+ });
68165
+ return {
68166
+ incidentLineCount,
68167
+ redFlowLineCount,
68168
+ hasAnyIncident: incidentLineCount > 0
68169
+ };
68170
+ }, [lineSelectorIndicatorByLine, visibleLineIds]);
67924
68171
  const metricsDisplayNames = useMemo(() => {
67925
68172
  const nextDisplayNames = {};
67926
68173
  currentWorkspaceMetrics.forEach((workspace) => {
@@ -68777,9 +69024,12 @@ function HomeView({
68777
69024
  new_line_ids: normalizedLineIds,
68778
69025
  selected_line_count: normalizedLineIds.length,
68779
69026
  selection_mode: isAllLinesSelection(normalizedLineIds) ? "all" : normalizedLineIds.length === 1 ? "single" : "custom",
69027
+ incident_line_count: lineSelectorIndicatorStats.incidentLineCount,
69028
+ red_flow_line_count: lineSelectorIndicatorStats.redFlowLineCount,
69029
+ selector_indicator_version: LINE_SELECTOR_INDICATOR_VERSION,
68780
69030
  line_name: getLineSelectionLabel(normalizedLineIds)
68781
69031
  });
68782
- }, [factoryViewId, getLineSelectionLabel, getTrackedLineScope, selectedLineIds, selectedLineIdsKey, visibleLineIds]);
69032
+ }, [factoryViewId, getLineSelectionLabel, getTrackedLineScope, lineSelectorIndicatorStats, selectedLineIds, selectedLineIdsKey, visibleLineIds]);
68783
69033
  useCallback(() => {
68784
69034
  updateSelectedLineIds(visibleLineIds);
68785
69035
  }, [updateSelectedLineIds, visibleLineIds]);
@@ -68837,7 +69087,10 @@ function HomeView({
68837
69087
  current_display_mode_label: getHomeDisplayModeLabel(displayMode),
68838
69088
  selected_line_ids: selectedLineIds,
68839
69089
  selected_line_count: selectedLineIds.length,
68840
- is_all_lines: isAllLinesSelection(selectedLineIds)
69090
+ is_all_lines: isAllLinesSelection(selectedLineIds),
69091
+ incident_line_count: lineSelectorIndicatorStats.incidentLineCount,
69092
+ red_flow_line_count: lineSelectorIndicatorStats.redFlowLineCount,
69093
+ selector_indicator_version: LINE_SELECTOR_INDICATOR_VERSION
68841
69094
  });
68842
69095
  }
68843
69096
  },
@@ -68878,8 +69131,8 @@ function HomeView({
68878
69131
  ] }),
68879
69132
  /* @__PURE__ */ jsx("div", { className: "max-h-56 space-y-0.5 overflow-y-auto pr-1", children: visibleLineIds.map((lineId) => {
68880
69133
  const isChecked = pendingSelectedLineIds.includes(lineId);
68881
- const signalStatus = lineSelectorSignalStatusByLine.get(lineId);
68882
- const signalDotClass = signalStatus === "stable" ? "bg-green-500" : signalStatus === "warning" ? "bg-yellow-400" : signalStatus === "attention" ? "bg-red-500" : "";
69134
+ const selectorIndicator = lineSelectorIndicatorByLine.get(lineId);
69135
+ const lineLabel = mergedLineNames[lineId] || `Line ${lineId.substring(0, 4)}`;
68883
69136
  return /* @__PURE__ */ jsxs(
68884
69137
  "label",
68885
69138
  {
@@ -68889,6 +69142,7 @@ function HomeView({
68889
69142
  "input",
68890
69143
  {
68891
69144
  type: "checkbox",
69145
+ "aria-label": lineLabel,
68892
69146
  className: "h-4 w-4 rounded border-slate-300 text-blue-600 focus:ring-blue-500",
68893
69147
  checked: isChecked,
68894
69148
  onChange: () => {
@@ -68904,12 +69158,12 @@ function HomeView({
68904
69158
  }
68905
69159
  }
68906
69160
  ),
68907
- /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: mergedLineNames[lineId] || `Line ${lineId.substring(0, 4)}` }),
68908
- /* @__PURE__ */ jsx("span", { className: "flex h-2.5 w-2.5 flex-shrink-0 items-center justify-center", children: signalStatus ? /* @__PURE__ */ jsx(
69161
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: lineLabel }),
69162
+ /* @__PURE__ */ jsx("span", { className: "flex h-5 w-5 flex-shrink-0 items-center justify-center", children: selectorIndicator === "incident" ? /* @__PURE__ */ jsx(LineSelectorIncidentIcon, { lineId }) : selectorIndicator === "red" && !lineSelectorIndicatorStats.hasAnyIncident ? /* @__PURE__ */ jsx(
68909
69163
  "span",
68910
69164
  {
68911
69165
  "data-testid": `line-selector-signal-dot-${lineId}`,
68912
- className: `h-2 w-2 rounded-full ${signalDotClass}`,
69166
+ className: "h-2 w-2 rounded-full bg-red-500",
68913
69167
  "aria-hidden": "true"
68914
69168
  }
68915
69169
  ) : null })
@@ -68941,7 +69195,8 @@ function HomeView({
68941
69195
  mergedLineNames,
68942
69196
  selectedLineIds,
68943
69197
  pendingSelectedLineIds,
68944
- lineSelectorSignalStatusByLine,
69198
+ lineSelectorIndicatorByLine,
69199
+ lineSelectorIndicatorStats,
68945
69200
  displayMode,
68946
69201
  slideshowActiveLineId,
68947
69202
  visibleLineIds,