@optifye/dashboard-core 6.11.16 → 6.11.18

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
@@ -3,7 +3,7 @@ import React141__default, { createContext, useRef, useCallback, useState, useMem
3
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
4
  import { useRouter } from 'next/router';
5
5
  import { toast } from 'sonner';
6
- import { fromZonedTime, formatInTimeZone, toZonedTime } from 'date-fns-tz';
6
+ import { formatInTimeZone, fromZonedTime, toZonedTime } from 'date-fns-tz';
7
7
  import { format, addDays, subMonths, endOfMonth, startOfMonth, endOfDay, eachDayOfInterval, getDay, isSameDay, isWithinInterval, startOfDay, parseISO, subDays, differenceInMinutes, addMinutes, addMonths, isValid, formatDistanceToNow, isToday, isFuture, isBefore } from 'date-fns';
8
8
  import mixpanel from 'mixpanel-browser';
9
9
  import { EventEmitter } from 'events';
@@ -3266,11 +3266,9 @@ var normalizeShiftDefinitions = (timezone, shiftConfig) => {
3266
3266
  }
3267
3267
  return { shifts: legacyShifts, timezone: fallbackTimezone };
3268
3268
  };
3269
- var determineShiftFromDefinitions = (timezone, shifts, now4 = /* @__PURE__ */ new Date()) => {
3269
+ var determineActiveShiftFromDefinitions = (timezone, shifts, now4 = /* @__PURE__ */ new Date()) => {
3270
3270
  const zonedNow = toZonedTime(now4, timezone);
3271
3271
  const currentMinutes = zonedNow.getHours() * 60 + zonedNow.getMinutes();
3272
- let chosen;
3273
- let operationalDate = getOperationalDate(timezone, now4, shifts[0].startTime);
3274
3272
  for (const shift of shifts) {
3275
3273
  const start = parseTimeToMinutes(shift.startTime);
3276
3274
  const endRaw = parseTimeToMinutes(shift.endTime);
@@ -3278,32 +3276,47 @@ var determineShiftFromDefinitions = (timezone, shifts, now4 = /* @__PURE__ */ ne
3278
3276
  const wraps = end <= start;
3279
3277
  if (wraps) end += 1440;
3280
3278
  if (start <= currentMinutes && currentMinutes < end) {
3281
- chosen = shift;
3282
- operationalDate = getOperationalDate(timezone, now4, shift.startTime);
3283
- break;
3279
+ return {
3280
+ shiftId: shift.shiftId,
3281
+ shiftName: shift.shiftName,
3282
+ startTime: shift.startTime,
3283
+ endTime: shift.endTime,
3284
+ timezone,
3285
+ date: getOperationalDate(timezone, now4, shift.startTime)
3286
+ };
3284
3287
  }
3285
3288
  if (start <= currentMinutes + 1440 && currentMinutes + 1440 < end) {
3286
- chosen = shift;
3287
- operationalDate = getOperationalDate(timezone, now4, shift.startTime);
3288
- break;
3289
+ return {
3290
+ shiftId: shift.shiftId,
3291
+ shiftName: shift.shiftName,
3292
+ startTime: shift.startTime,
3293
+ endTime: shift.endTime,
3294
+ timezone,
3295
+ date: getOperationalDate(timezone, now4, shift.startTime)
3296
+ };
3289
3297
  }
3290
3298
  }
3291
- if (!chosen) {
3292
- chosen = shifts[0];
3293
- operationalDate = getOperationalDate(timezone, now4, chosen.startTime);
3299
+ return null;
3300
+ };
3301
+ var getCurrentShift = (timezone, shiftConfig, now4 = /* @__PURE__ */ new Date()) => {
3302
+ const { shifts, timezone: effectiveTz } = normalizeShiftDefinitions(timezone, shiftConfig);
3303
+ const activeShift = determineActiveShiftFromDefinitions(effectiveTz, shifts, now4);
3304
+ if (activeShift) {
3305
+ return activeShift;
3294
3306
  }
3307
+ const fallbackShift = shifts[0];
3295
3308
  return {
3296
- shiftId: chosen.shiftId,
3297
- shiftName: chosen.shiftName,
3298
- startTime: chosen.startTime,
3299
- endTime: chosen.endTime,
3300
- timezone,
3301
- date: operationalDate
3309
+ shiftId: fallbackShift.shiftId,
3310
+ shiftName: fallbackShift.shiftName,
3311
+ startTime: fallbackShift.startTime,
3312
+ endTime: fallbackShift.endTime,
3313
+ timezone: effectiveTz,
3314
+ date: getOperationalDate(effectiveTz, now4, fallbackShift.startTime)
3302
3315
  };
3303
3316
  };
3304
- var getCurrentShift = (timezone, shiftConfig, now4 = /* @__PURE__ */ new Date()) => {
3317
+ var getActiveShift = (timezone, shiftConfig, now4 = /* @__PURE__ */ new Date()) => {
3305
3318
  const { shifts, timezone: effectiveTz } = normalizeShiftDefinitions(timezone, shiftConfig);
3306
- return determineShiftFromDefinitions(effectiveTz, shifts, now4);
3319
+ return determineActiveShiftFromDefinitions(effectiveTz, shifts, now4);
3307
3320
  };
3308
3321
  var isTransitionPeriod = (timezone, shiftConfig, now4 = /* @__PURE__ */ new Date()) => {
3309
3322
  const transitionMinutes = shiftConfig?.transitionPeriodMinutes ?? DEFAULT_TRANSITION_MINUTES;
@@ -3968,7 +3981,8 @@ var dashboardService = {
3968
3981
  enable,
3969
3982
  monitoring_mode,
3970
3983
  assembly,
3971
- video_grid_metric_mode
3984
+ video_grid_metric_mode,
3985
+ recent_flow_window_minutes
3972
3986
  `).eq("enable", true);
3973
3987
  if (companyId) {
3974
3988
  query = query.eq("company_id", companyId);
@@ -3993,7 +4007,8 @@ var dashboardService = {
3993
4007
  video_grid_metric_mode: normalizeVideoGridMetricMode(
3994
4008
  line.video_grid_metric_mode,
3995
4009
  line.assembly ?? false
3996
- )
4010
+ ),
4011
+ recent_flow_window_minutes: line.recent_flow_window_minutes ?? 7
3997
4012
  }));
3998
4013
  return transformedLines;
3999
4014
  } catch (err) {
@@ -4030,7 +4045,7 @@ var dashboardService = {
4030
4045
  }
4031
4046
  const lineIdsToQuery = configuredLineIds;
4032
4047
  const [line1Result, metricsResult2] = await Promise.all([
4033
- supabase.from(linesTable).select("id, line_name, factory_id, monitoring_mode, assembly, video_grid_metric_mode, factories!lines_factory_id_fkey(factory_name), company_id, companies!lines_company_id_fkey(company_name:name)").eq("id", defaultLineId).single(),
4048
+ supabase.from(linesTable).select("id, line_name, factory_id, monitoring_mode, assembly, video_grid_metric_mode, recent_flow_window_minutes, factories!lines_factory_id_fkey(factory_name), company_id, companies!lines_company_id_fkey(company_name:name)").eq("id", defaultLineId).single(),
4034
4049
  supabase.from(lineMetricsTable).select("*").in("line_id", lineIdsToQuery).eq("shift_id", queryShiftId).eq("date", queryDate)
4035
4050
  ]);
4036
4051
  if (line1Result.error) throw line1Result.error;
@@ -4086,6 +4101,7 @@ var dashboardService = {
4086
4101
  date: queryDate,
4087
4102
  shift_id: queryShiftId,
4088
4103
  monitoring_mode: line1Data.monitoring_mode ?? void 0,
4104
+ recent_flow_window_minutes: line1Data.recent_flow_window_minutes ?? 7,
4089
4105
  metrics: {
4090
4106
  avg_efficiency: avgEfficiency,
4091
4107
  avg_cycle_time: combinedMetricsData.avg_cycle_time / numLines,
@@ -4109,7 +4125,7 @@ var dashboardService = {
4109
4125
  throw new Error("Company ID must be configured for detailed line requests.");
4110
4126
  }
4111
4127
  const [lineResult, metricsResult] = await Promise.all([
4112
- supabase.from(linesTable).select("id, line_name, factory_id, monitoring_mode, assembly, video_grid_metric_mode, factories!lines_factory_id_fkey(factory_name), company_id, companies!lines_company_id_fkey(company_name:name)").eq("id", lineIdToQuery).single(),
4128
+ supabase.from(linesTable).select("id, line_name, factory_id, monitoring_mode, assembly, video_grid_metric_mode, recent_flow_window_minutes, factories!lines_factory_id_fkey(factory_name), company_id, companies!lines_company_id_fkey(company_name:name)").eq("id", lineIdToQuery).single(),
4113
4129
  supabase.from(lineMetricsTable).select("*").eq("line_id", lineIdToQuery).eq("shift_id", queryShiftId).eq("date", queryDate)
4114
4130
  ]);
4115
4131
  if (lineResult.error) throw lineResult.error;
@@ -4134,6 +4150,7 @@ var dashboardService = {
4134
4150
  date: queryDate,
4135
4151
  shift_id: queryShiftId,
4136
4152
  monitoring_mode: lineData.monitoring_mode ?? void 0,
4153
+ recent_flow_window_minutes: lineData.recent_flow_window_minutes ?? 7,
4137
4154
  metrics: {
4138
4155
  avg_efficiency: metrics2?.avg_efficiency ?? 0,
4139
4156
  avg_cycle_time: metrics2?.avg_cycle_time || 0,
@@ -8467,7 +8484,8 @@ var LinesService = class {
8467
8484
  videoGridMetricMode: normalizeVideoGridMetricMode(
8468
8485
  line.video_grid_metric_mode,
8469
8486
  line.assembly ?? false
8470
- )
8487
+ ),
8488
+ recentFlowWindowMinutes: line.recent_flow_window_minutes ?? 7
8471
8489
  }));
8472
8490
  } catch (error) {
8473
8491
  console.error("Error fetching lines:", error);
@@ -8515,7 +8533,8 @@ var LinesService = class {
8515
8533
  videoGridMetricMode: normalizeVideoGridMetricMode(
8516
8534
  line.video_grid_metric_mode,
8517
8535
  line.assembly ?? false
8518
- )
8536
+ ),
8537
+ recentFlowWindowMinutes: line.recent_flow_window_minutes ?? 7
8519
8538
  }));
8520
8539
  } catch (error) {
8521
8540
  console.error("Error fetching all lines:", error);
@@ -8572,7 +8591,8 @@ var LinesService = class {
8572
8591
  videoGridMetricMode: normalizeVideoGridMetricMode(
8573
8592
  data.video_grid_metric_mode,
8574
8593
  data.assembly ?? false
8575
- )
8594
+ ),
8595
+ recentFlowWindowMinutes: data.recent_flow_window_minutes ?? 7
8576
8596
  };
8577
8597
  } catch (error) {
8578
8598
  console.error("Error fetching line:", error);
@@ -13326,6 +13346,7 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
13326
13346
  actionName: item.action_name
13327
13347
  }),
13328
13348
  recent_flow_percent: item.recent_flow_percent ?? null,
13349
+ recent_flow_window_minutes: item.recent_flow_window_minutes ?? null,
13329
13350
  recent_flow_effective_end_at: item.recent_flow_effective_end_at ?? null,
13330
13351
  recent_flow_computed_at: item.recent_flow_computed_at ?? null,
13331
13352
  incoming_wip_current: item.incoming_wip_current ?? null,
@@ -32174,6 +32195,7 @@ var LineChartComponent = ({
32174
32195
  xAxisLabel,
32175
32196
  xAxisTickFormatter,
32176
32197
  // Pass through for X-axis tick formatting
32198
+ xAxisInterval,
32177
32199
  yAxisLabel,
32178
32200
  yAxisUnit,
32179
32201
  yAxisDomain,
@@ -32256,6 +32278,7 @@ var LineChartComponent = ({
32256
32278
  dataKey: xAxisDataKey,
32257
32279
  label: xAxisLabel ? { value: xAxisLabel, position: "insideBottom", offset: -10 } : void 0,
32258
32280
  tickFormatter: xAxisTickFormatter,
32281
+ interval: xAxisInterval,
32259
32282
  tick: { fontSize: 12, fill: axisTickFillColor },
32260
32283
  stroke: axisStrokeColor
32261
32284
  }
@@ -32580,6 +32603,212 @@ var CycleTimeChart = React141__default.memo(CycleTimeChartComponent, (prevProps,
32580
32603
  });
32581
32604
  });
32582
32605
  CycleTimeChart.displayName = "CycleTimeChart";
32606
+
32607
+ // src/lib/utils/hourlyIdle.ts
32608
+ var DEFAULT_SHIFT_DURATION = 11;
32609
+ var normalizeMinuteSeries = (idleTimeHourly) => {
32610
+ if (!idleTimeHourly || typeof idleTimeHourly !== "object") {
32611
+ return {};
32612
+ }
32613
+ return Object.fromEntries(
32614
+ Object.entries(idleTimeHourly).map(([key, value]) => {
32615
+ if (Array.isArray(value)) {
32616
+ return [key, value];
32617
+ }
32618
+ if (value && Array.isArray(value.values)) {
32619
+ return [key, value.values];
32620
+ }
32621
+ return [key, []];
32622
+ })
32623
+ );
32624
+ };
32625
+ var parseTimeString = (timeValue) => {
32626
+ const [hoursPart, minutesPart] = timeValue.split(":");
32627
+ const hour = Number.parseInt(hoursPart, 10);
32628
+ const minute = Number.parseInt(minutesPart ?? "0", 10);
32629
+ const safeHour = Number.isFinite(hour) ? hour : 0;
32630
+ const safeMinute = Number.isFinite(minute) ? minute : 0;
32631
+ return {
32632
+ hour: safeHour,
32633
+ minute: safeMinute,
32634
+ decimalHour: safeHour + safeMinute / 60
32635
+ };
32636
+ };
32637
+ var buildShiftLayout = ({
32638
+ shiftStart,
32639
+ shiftEnd
32640
+ }) => {
32641
+ const shiftStartTime = parseTimeString(shiftStart);
32642
+ if (!shiftEnd) {
32643
+ return {
32644
+ shiftDuration: DEFAULT_SHIFT_DURATION,
32645
+ shiftStartTime,
32646
+ shiftEndTime: null,
32647
+ hasPartialLastHour: false
32648
+ };
32649
+ }
32650
+ const shiftEndTime = parseTimeString(shiftEnd);
32651
+ let duration = shiftEndTime.decimalHour - shiftStartTime.decimalHour;
32652
+ if (duration <= 0) {
32653
+ duration += 24;
32654
+ }
32655
+ const hasPartialLastHour = shiftEndTime.minute > 0 && shiftEndTime.minute < 60;
32656
+ const shiftDuration = hasPartialLastHour ? Math.ceil(duration) : Math.round(duration);
32657
+ return {
32658
+ shiftDuration,
32659
+ shiftStartTime,
32660
+ shiftEndTime,
32661
+ hasPartialLastHour
32662
+ };
32663
+ };
32664
+ var formatCompactTime = (hour, minute) => {
32665
+ const period = hour >= 12 ? "PM" : "AM";
32666
+ const hour12 = hour === 0 ? 12 : hour > 12 ? hour - 12 : hour;
32667
+ if (minute === 0) {
32668
+ return `${hour12}${period}`;
32669
+ }
32670
+ return `${hour12}:${minute.toString().padStart(2, "0")}${period}`;
32671
+ };
32672
+ var formatFullTime = (hour, minute) => {
32673
+ const period = hour >= 12 ? "PM" : "AM";
32674
+ const hour12 = hour === 0 ? 12 : hour > 12 ? hour - 12 : hour;
32675
+ return `${hour12}:${minute.toString().padStart(2, "0")} ${period}`;
32676
+ };
32677
+ var getSlotTimeBounds = (hourIndex, layout2) => {
32678
+ const isLastHour = hourIndex === layout2.shiftDuration - 1;
32679
+ const startDecimalHour = layout2.shiftStartTime.decimalHour + hourIndex;
32680
+ const startHour = Math.floor(startDecimalHour) % 24;
32681
+ const startMinute = Math.round(startDecimalHour % 1 * 60);
32682
+ let endHour;
32683
+ let endMinute;
32684
+ if (isLastHour && layout2.shiftEndTime) {
32685
+ endHour = layout2.shiftEndTime.hour;
32686
+ endMinute = layout2.shiftEndTime.minute;
32687
+ } else {
32688
+ const endDecimalHour = startDecimalHour + 1;
32689
+ endHour = Math.floor(endDecimalHour) % 24;
32690
+ endMinute = Math.round(endDecimalHour % 1 * 60);
32691
+ }
32692
+ return {
32693
+ startHour,
32694
+ startMinute,
32695
+ endHour,
32696
+ endMinute
32697
+ };
32698
+ };
32699
+ var getIdleArrayForHour = (hourIndex, idleTimeHourly, layout2) => {
32700
+ const actualHour = (layout2.shiftStartTime.hour + hourIndex) % 24;
32701
+ const startMinute = layout2.shiftStartTime.minute;
32702
+ if (startMinute > 0) {
32703
+ if (hourIndex === 0) {
32704
+ const firstHourData = idleTimeHourly[actualHour.toString()] || [];
32705
+ const nextHourData2 = idleTimeHourly[((actualHour + 1) % 24).toString()] || [];
32706
+ return [
32707
+ ...firstHourData.slice(startMinute),
32708
+ ...nextHourData2.slice(0, startMinute)
32709
+ ];
32710
+ }
32711
+ if (hourIndex < layout2.shiftDuration - 1) {
32712
+ const currentHourData3 = idleTimeHourly[actualHour.toString()] || [];
32713
+ const nextHourData2 = idleTimeHourly[((actualHour + 1) % 24).toString()] || [];
32714
+ return [
32715
+ ...currentHourData3.slice(startMinute),
32716
+ ...nextHourData2.slice(0, startMinute)
32717
+ ];
32718
+ }
32719
+ if (layout2.hasPartialLastHour && layout2.shiftEndTime) {
32720
+ const currentHourData3 = idleTimeHourly[actualHour.toString()] || [];
32721
+ const nextHourData2 = idleTimeHourly[((actualHour + 1) % 24).toString()] || [];
32722
+ return [
32723
+ ...currentHourData3.slice(startMinute),
32724
+ ...nextHourData2.slice(0, layout2.shiftEndTime.minute)
32725
+ ];
32726
+ }
32727
+ const currentHourData2 = idleTimeHourly[actualHour.toString()] || [];
32728
+ const nextHourData = idleTimeHourly[((actualHour + 1) % 24).toString()] || [];
32729
+ return [
32730
+ ...currentHourData2.slice(startMinute),
32731
+ ...nextHourData.slice(0, startMinute)
32732
+ ];
32733
+ }
32734
+ const currentHourData = idleTimeHourly[actualHour.toString()] || [];
32735
+ if (hourIndex === layout2.shiftDuration - 1 && layout2.hasPartialLastHour && layout2.shiftEndTime) {
32736
+ return currentHourData.slice(0, layout2.shiftEndTime.minute);
32737
+ }
32738
+ return currentHourData;
32739
+ };
32740
+ var buildHourlyIdleSlots = ({
32741
+ idleTimeHourly,
32742
+ shiftStart,
32743
+ shiftEnd
32744
+ }) => {
32745
+ const normalizedIdleTimeHourly = normalizeMinuteSeries(idleTimeHourly);
32746
+ const layout2 = buildShiftLayout({ shiftStart, shiftEnd });
32747
+ return Array.from({ length: layout2.shiftDuration }, (_, hourIndex) => {
32748
+ const { startHour, startMinute, endHour, endMinute } = getSlotTimeBounds(hourIndex, layout2);
32749
+ const idleArray = getIdleArrayForHour(hourIndex, normalizedIdleTimeHourly, layout2);
32750
+ const idleMinutes = idleArray.filter((value) => value === 1 || value === "1").length;
32751
+ return {
32752
+ hourIndex,
32753
+ hour: `${formatCompactTime(startHour, startMinute)}-${formatCompactTime(endHour, endMinute)}`,
32754
+ timeRange: `${formatFullTime(startHour, startMinute)} - ${formatFullTime(endHour, endMinute)}`,
32755
+ idleMinutes,
32756
+ idleArray
32757
+ };
32758
+ });
32759
+ };
32760
+ var formatIdleTimestamp = ({
32761
+ shiftStart,
32762
+ hourIndex,
32763
+ minuteIndex
32764
+ }) => {
32765
+ const shiftStartTime = parseTimeString(shiftStart);
32766
+ const totalMinutes = (shiftStartTime.hour + hourIndex) * 60 + shiftStartTime.minute + minuteIndex;
32767
+ const hour = Math.floor(totalMinutes / 60) % 24;
32768
+ const minute = totalMinutes % 60;
32769
+ return formatFullTime(hour, minute);
32770
+ };
32771
+ var getHourlyIdlePeriods = ({
32772
+ idleArray,
32773
+ shiftStart,
32774
+ hourIndex
32775
+ }) => {
32776
+ if (!Array.isArray(idleArray) || idleArray.length === 0) {
32777
+ return [];
32778
+ }
32779
+ const periods = [];
32780
+ let currentRange = null;
32781
+ idleArray.forEach((value, minuteIndex) => {
32782
+ if (value === 1 || value === "1") {
32783
+ if (!currentRange) {
32784
+ currentRange = { start: minuteIndex, end: minuteIndex };
32785
+ } else {
32786
+ currentRange.end = minuteIndex;
32787
+ }
32788
+ } else if (value !== "x" && currentRange) {
32789
+ periods.push(currentRange);
32790
+ currentRange = null;
32791
+ }
32792
+ });
32793
+ if (currentRange) {
32794
+ periods.push(currentRange);
32795
+ }
32796
+ return periods.map((period) => ({
32797
+ start: period.start,
32798
+ end: period.end,
32799
+ duration: period.end - period.start + 1,
32800
+ startTime: formatIdleTimestamp({
32801
+ shiftStart,
32802
+ hourIndex,
32803
+ minuteIndex: period.start
32804
+ }),
32805
+ endTime: formatIdleTimestamp({
32806
+ shiftStart,
32807
+ hourIndex,
32808
+ minuteIndex: period.end + 1
32809
+ })
32810
+ }));
32811
+ };
32583
32812
  var CycleTimeOverTimeChart = ({
32584
32813
  data,
32585
32814
  idealCycleTime,
@@ -32589,7 +32818,8 @@ var CycleTimeOverTimeChart = ({
32589
32818
  datasetKey,
32590
32819
  className = "",
32591
32820
  showIdleTime = false,
32592
- idleTimeData = []
32821
+ idleTimeData = [],
32822
+ idleTimeSlots = []
32593
32823
  }) => {
32594
32824
  const MAX_DATA_POINTS = 40;
32595
32825
  const containerRef = React141__default.useRef(null);
@@ -32692,50 +32922,60 @@ var CycleTimeOverTimeChart = ({
32692
32922
  if (!visibleEntries.length) {
32693
32923
  return null;
32694
32924
  }
32695
- return /* @__PURE__ */ jsxs(
32696
- "div",
32697
- {
32698
- style: {
32699
- backgroundColor: "white",
32700
- border: "none",
32701
- borderRadius: "8px",
32702
- boxShadow: "0 4px 12px rgba(0,0,0,0.1)",
32703
- padding: "8px 12px",
32704
- fontSize: "13px"
32705
- },
32706
- children: [
32707
- /* @__PURE__ */ jsx(
32708
- "div",
32709
- {
32710
- style: {
32711
- color: "#374151",
32712
- fontWeight: 600,
32713
- marginBottom: "4px"
32714
- },
32715
- children: payload[0]?.payload?.tooltip || ""
32716
- }
32717
- ),
32718
- visibleEntries.map((entry) => {
32719
- const numericValue = getNumericValue(entry.value);
32720
- if (numericValue === null) {
32721
- return null;
32722
- }
32723
- return /* @__PURE__ */ jsx(
32724
- "div",
32725
- {
32726
- style: {
32727
- color: "#4B5563",
32728
- padding: "2px 0"
32729
- },
32730
- children: entry.name === "idleMinutes" ? `Idle Time: ${numericValue.toFixed(0)} minutes` : `Cycle Time: ${numericValue.toFixed(1)} seconds`
32731
- },
32732
- `${entry.name}-${numericValue}`
32733
- );
32734
- })
32735
- ]
32736
- }
32737
- );
32738
- }, [getNumericValue]);
32925
+ const dataPoint = payload[0]?.payload || {};
32926
+ const idlePeriods = showIdleTime && typeof dataPoint.idleMinutes === "number" && dataPoint.idleMinutes > 0 ? getHourlyIdlePeriods({
32927
+ idleArray: dataPoint.idleArray,
32928
+ shiftStart,
32929
+ hourIndex: Number.isFinite(dataPoint.hourIndex) ? dataPoint.hourIndex : 0
32930
+ }) : [];
32931
+ return /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-xl shadow-xl border border-gray-100 p-4 min-w-[220px]", children: [
32932
+ /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between mb-3", children: /* @__PURE__ */ jsx("p", { className: "font-semibold text-gray-900 text-sm", children: dataPoint.timeRange || dataPoint.tooltip || "" }) }),
32933
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
32934
+ visibleEntries.map((entry) => {
32935
+ const numericValue = getNumericValue(entry.value);
32936
+ if (numericValue === null) {
32937
+ return null;
32938
+ }
32939
+ if (entry.name === "idleMinutes") {
32940
+ if (!showIdleTime) return null;
32941
+ return /* @__PURE__ */ jsx("div", { className: "border-t border-gray-100 pt-2", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
32942
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-gray-500", children: "Idle Time" }),
32943
+ /* @__PURE__ */ jsxs("span", { className: "font-semibold text-orange-600 text-sm", children: [
32944
+ numericValue.toFixed(0),
32945
+ " minutes"
32946
+ ] })
32947
+ ] }) }, `${entry.name}-${numericValue}`);
32948
+ }
32949
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
32950
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-gray-500", children: "Cycle Time" }),
32951
+ /* @__PURE__ */ jsxs("span", { className: "font-semibold text-gray-900 text-sm", children: [
32952
+ numericValue.toFixed(1),
32953
+ " seconds"
32954
+ ] })
32955
+ ] }, `${entry.name}-${numericValue}`);
32956
+ }),
32957
+ idlePeriods.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mt-3 bg-gray-50 rounded-lg p-2.5", children: [
32958
+ /* @__PURE__ */ jsx("p", { className: "font-medium text-gray-700 text-xs mb-2", children: "Idle periods:" }),
32959
+ /* @__PURE__ */ jsx("div", { className: "space-y-1 max-h-32 overflow-y-auto pr-1", children: idlePeriods.map((period, index) => /* @__PURE__ */ jsxs("div", { className: "text-gray-600 flex items-center gap-2 text-xs", children: [
32960
+ /* @__PURE__ */ jsx("span", { className: "inline-block w-1.5 h-1.5 bg-orange-400 rounded-full flex-shrink-0" }),
32961
+ /* @__PURE__ */ jsx("span", { children: period.duration === 1 ? /* @__PURE__ */ jsxs(Fragment, { children: [
32962
+ period.startTime,
32963
+ " (",
32964
+ period.duration,
32965
+ " min)"
32966
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
32967
+ period.startTime,
32968
+ " - ",
32969
+ period.endTime,
32970
+ " (",
32971
+ period.duration,
32972
+ " mins)"
32973
+ ] }) })
32974
+ ] }, index)) })
32975
+ ] })
32976
+ ] })
32977
+ ] });
32978
+ }, [getNumericValue, shiftStart, showIdleTime]);
32739
32979
  const renderCycleDot = React141__default.useCallback((props) => {
32740
32980
  const { cx: cx2, cy, payload } = props;
32741
32981
  const cycleTime = getNumericValue(payload?.cycleTime);
@@ -32804,14 +33044,18 @@ var CycleTimeOverTimeChart = ({
32804
33044
  r: 4,
32805
33045
  fill: "#f59e0b",
32806
33046
  stroke: "#fff",
32807
- strokeWidth: 1
33047
+ strokeWidth: 1,
33048
+ style: {
33049
+ opacity: showIdleTime ? 1 : 0,
33050
+ transition: "opacity 0.3s ease-in-out"
33051
+ }
32808
33052
  }
32809
33053
  );
32810
- }, [getNumericValue]);
33054
+ }, [getNumericValue, showIdleTime]);
32811
33055
  const renderIdleActiveDot = React141__default.useCallback((props) => {
32812
33056
  const { cx: cx2, cy, payload } = props;
32813
33057
  const idleMinutes = getNumericValue(payload?.idleMinutes);
32814
- if (idleMinutes === null) {
33058
+ if (idleMinutes === null || !showIdleTime) {
32815
33059
  return /* @__PURE__ */ jsx("g", {});
32816
33060
  }
32817
33061
  return /* @__PURE__ */ jsx(
@@ -32825,25 +33069,40 @@ var CycleTimeOverTimeChart = ({
32825
33069
  strokeWidth: 2
32826
33070
  }
32827
33071
  );
32828
- }, [getNumericValue]);
33072
+ }, [getNumericValue, showIdleTime]);
32829
33073
  const chartData = React141__default.useMemo(() => Array.from({ length: DURATION }, (_, i) => {
32830
33074
  const cycleTime = getNumericValue(finalData[i]);
32831
- const idleMinutes = showIdleTime ? getNumericValue(idleTimeData[i]) : null;
33075
+ const useIdleSlots = idleTimeSlots.length > 0;
33076
+ const idleSlot = useIdleSlots ? idleTimeSlots[i] ?? null : null;
33077
+ const idleMinutes = useIdleSlots ? idleSlot?.idleMinutes ?? null : getNumericValue(idleTimeData[i]);
32832
33078
  return {
32833
33079
  timeIndex: i,
32834
33080
  label: formatTimeLabel(i),
32835
- tooltip: formatTooltipTime(i),
33081
+ tooltip: idleSlot?.timeRange || formatTooltipTime(i),
33082
+ timeRange: idleSlot?.timeRange || formatTooltipTime(i),
33083
+ hourIndex: idleSlot?.hourIndex ?? i,
32836
33084
  cycleTime,
32837
33085
  idleMinutes,
33086
+ idleArray: idleSlot?.idleArray || [],
32838
33087
  color: cycleTime !== null && cycleTime <= idealCycleTime ? "#00AB45" : "#E34329"
32839
33088
  };
32840
- }), [DURATION, finalData, showIdleTime, idleTimeData, idealCycleTime, getNumericValue]);
33089
+ }), [DURATION, finalData, idleTimeData, idleTimeSlots, idealCycleTime, getNumericValue]);
32841
33090
  const renderLegend = () => {
32842
- if (!showIdleTime) return null;
32843
- return /* @__PURE__ */ jsx("div", { className: "flex items-center justify-start text-[10px] font-bold text-gray-500 mb-6 tracking-[0.05em] gap-5", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
32844
- /* @__PURE__ */ jsx("div", { className: "w-2.5 h-2.5 rounded-full bg-[#f59e0b]" }),
32845
- /* @__PURE__ */ jsx("span", { children: "Idle Time (min)" })
32846
- ] }) });
33091
+ return /* @__PURE__ */ jsx(
33092
+ "div",
33093
+ {
33094
+ className: "flex items-center justify-start text-[10px] font-bold text-gray-500 mb-6 tracking-[0.05em] gap-5",
33095
+ style: {
33096
+ opacity: showIdleTime ? 1 : 0,
33097
+ pointerEvents: showIdleTime ? "auto" : "none",
33098
+ transition: "opacity 0.3s ease-in-out"
33099
+ },
33100
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
33101
+ /* @__PURE__ */ jsx("div", { className: "w-2.5 h-2.5 rounded-full bg-[#f59e0b]" }),
33102
+ /* @__PURE__ */ jsx("span", { children: "Idle Time (min)" })
33103
+ ] })
33104
+ }
33105
+ );
32847
33106
  };
32848
33107
  return /* @__PURE__ */ jsxs(
32849
33108
  "div",
@@ -32914,7 +33173,7 @@ var CycleTimeOverTimeChart = ({
32914
33173
  }
32915
33174
  }
32916
33175
  ),
32917
- showIdleTime && /* @__PURE__ */ jsx(
33176
+ /* @__PURE__ */ jsx(
32918
33177
  YAxis,
32919
33178
  {
32920
33179
  yAxisId: "idle",
@@ -32923,7 +33182,11 @@ var CycleTimeOverTimeChart = ({
32923
33182
  width: 35,
32924
33183
  domain: [0, 60],
32925
33184
  tickFormatter: (value) => `${value}m`,
32926
- tick: { fontSize: 11, fill: "#f59e0b" },
33185
+ tick: {
33186
+ fontSize: 11,
33187
+ fill: showIdleTime ? "#f59e0b" : "transparent",
33188
+ style: { transition: "fill 0.3s ease-in-out" }
33189
+ },
32927
33190
  axisLine: false,
32928
33191
  tickLine: false
32929
33192
  }
@@ -32971,7 +33234,7 @@ var CycleTimeOverTimeChart = ({
32971
33234
  },
32972
33235
  `${effectiveDatasetKey}:cycle`
32973
33236
  ),
32974
- showIdleTime && /* @__PURE__ */ jsx(
33237
+ /* @__PURE__ */ jsx(
32975
33238
  Line,
32976
33239
  {
32977
33240
  type: "monotone",
@@ -32986,7 +33249,11 @@ var CycleTimeOverTimeChart = ({
32986
33249
  isAnimationActive: true,
32987
33250
  animationBegin: 300,
32988
33251
  animationDuration: 1500,
32989
- animationEasing: "ease-out"
33252
+ animationEasing: "ease-out",
33253
+ style: {
33254
+ strokeOpacity: showIdleTime ? 1 : 0,
33255
+ transition: "stroke-opacity 0.3s ease-in-out"
33256
+ }
32990
33257
  },
32991
33258
  `${effectiveDatasetKey}:idle`
32992
33259
  )
@@ -33141,89 +33408,20 @@ var HourlyOutputChartComponent = ({
33141
33408
  shiftEnd,
33142
33409
  showIdleTime = false,
33143
33410
  idleTimeHourly,
33144
- idleTimeClips,
33145
- idleTimeClipClassifications,
33146
- shiftDate,
33147
- timezone,
33148
33411
  className = ""
33149
33412
  }) => {
33150
33413
  const containerRef = React141__default.useRef(null);
33151
33414
  const [containerReady, setContainerReady] = React141__default.useState(false);
33152
33415
  const [containerWidth, setContainerWidth] = React141__default.useState(0);
33153
- const getTimeFromTimeString2 = (timeStr) => {
33154
- const [hours, minutes] = timeStr.split(":");
33155
- const hour = parseInt(hours);
33156
- const minute = parseInt(minutes || "0");
33157
- const decimalHour = hour + minute / 60;
33158
- return { hour, minute, decimalHour };
33159
- };
33160
- const shiftStartTime = getTimeFromTimeString2(shiftStart);
33161
- React141__default.useMemo(() => {
33162
- if (!shiftDate || !timezone) return null;
33163
- const hour = shiftStartTime.hour.toString().padStart(2, "0");
33164
- const minute = shiftStartTime.minute.toString().padStart(2, "0");
33165
- return fromZonedTime(`${shiftDate}T${hour}:${minute}:00`, timezone);
33166
- }, [shiftDate, timezone, shiftStartTime.hour, shiftStartTime.minute]);
33167
- const idleClipRanges = React141__default.useMemo(() => {
33168
- if (!idleTimeClips || idleTimeClips.length === 0) return [];
33169
- return idleTimeClips.map((clip) => ({
33170
- id: clip.id,
33171
- start: clip.idle_start_time ? new Date(clip.idle_start_time) : null,
33172
- end: clip.idle_end_time ? new Date(clip.idle_end_time) : null
33173
- })).filter((clip) => clip.start && clip.end);
33174
- }, [idleTimeClips]);
33175
- React141__default.useCallback((rangeStart, rangeEnd) => {
33176
- if (!rangeStart || !rangeEnd || idleClipRanges.length === 0) {
33177
- return "Reason unavailable";
33178
- }
33179
- const matchingClip = idleClipRanges.find((clip) => rangeStart >= clip.start && rangeEnd <= clip.end) || idleClipRanges.find((clip) => rangeStart < clip.end && rangeEnd > clip.start);
33180
- if (!matchingClip) {
33181
- return "Reason unavailable";
33182
- }
33183
- const classification = idleTimeClipClassifications?.[matchingClip.id];
33184
- if (!classification || classification.status === "processing") {
33185
- return "Analyzing...";
33186
- }
33187
- if (!classification.label) {
33188
- return "Reason unavailable";
33189
- }
33190
- return classification.displayName || classification.label.replace(/_/g, " ");
33191
- }, [idleClipRanges, idleTimeClipClassifications]);
33192
- const { shiftDuration, shiftEndTime, hasPartialLastHour } = React141__default.useMemo(() => {
33193
- console.log("[HourlyOutputChart] Calculating shift duration with:", {
33416
+ const idleSlots = React141__default.useMemo(
33417
+ () => buildHourlyIdleSlots({
33418
+ idleTimeHourly,
33194
33419
  shiftStart,
33195
- shiftEnd,
33196
- shiftStartTime
33197
- });
33198
- if (!shiftEnd) {
33199
- console.log("[HourlyOutputChart] No shiftEnd provided, using default 11 hours");
33200
- return {
33201
- shiftDuration: 11,
33202
- shiftEndTime: null,
33203
- hasPartialLastHour: false
33204
- };
33205
- }
33206
- const endTime = getTimeFromTimeString2(shiftEnd);
33207
- let duration = endTime.decimalHour - shiftStartTime.decimalHour;
33208
- if (duration <= 0) {
33209
- duration += 24;
33210
- }
33211
- const hasPartial = endTime.minute > 0 && endTime.minute < 60;
33212
- const hourCount = hasPartial ? Math.ceil(duration) : Math.round(duration);
33213
- console.log("[HourlyOutputChart] Shift calculation results:", {
33214
- endTime,
33215
- duration,
33216
- hasPartial,
33217
- hourCount
33218
- });
33219
- return {
33220
- shiftDuration: hourCount,
33221
- shiftEndTime: endTime,
33222
- hasPartialLastHour: hasPartial
33223
- };
33224
- }, [shiftEnd, shiftStartTime.decimalHour]);
33225
- const SHIFT_DURATION = shiftDuration;
33226
- shiftEndTime ? shiftEndTime.hour : (shiftStartTime.hour + SHIFT_DURATION) % 24;
33420
+ shiftEnd
33421
+ }),
33422
+ [idleTimeHourly, shiftStart, shiftEnd]
33423
+ );
33424
+ const SHIFT_DURATION = idleSlots.length;
33227
33425
  const [animatedData, setAnimatedData] = React141__default.useState(
33228
33426
  () => Array(SHIFT_DURATION).fill(0)
33229
33427
  );
@@ -33346,121 +33544,22 @@ var HourlyOutputChartComponent = ({
33346
33544
  }
33347
33545
  return { interval: 0, angle: -30, height: 64, tickFont: 9, tickMargin: 6 };
33348
33546
  }, [containerWidth]);
33349
- const formatHour = React141__default.useCallback((hourIndex) => {
33350
- const isLastHour = hourIndex === SHIFT_DURATION - 1;
33351
- const startDecimalHour = shiftStartTime.decimalHour + hourIndex;
33352
- const startHour = Math.floor(startDecimalHour) % 24;
33353
- const startMinute = Math.round(startDecimalHour % 1 * 60);
33354
- let endHour, endMinute;
33355
- if (isLastHour && shiftEndTime) {
33356
- endHour = shiftEndTime.hour;
33357
- endMinute = shiftEndTime.minute;
33358
- } else {
33359
- const endDecimalHour = startDecimalHour + 1;
33360
- endHour = Math.floor(endDecimalHour) % 24;
33361
- endMinute = Math.round(endDecimalHour % 1 * 60);
33362
- }
33363
- const formatTime5 = (h, m) => {
33364
- const period = h >= 12 ? "PM" : "AM";
33365
- const hour12 = h === 0 ? 12 : h > 12 ? h - 12 : h;
33366
- if (m === 0) {
33367
- return `${hour12}${period}`;
33368
- }
33369
- return `${hour12}:${m.toString().padStart(2, "0")}${period}`;
33370
- };
33371
- return `${formatTime5(startHour, startMinute)}-${formatTime5(endHour, endMinute)}`;
33372
- }, [shiftStartTime.decimalHour, SHIFT_DURATION, shiftEndTime]);
33373
- const formatTimeRange2 = React141__default.useCallback((hourIndex) => {
33374
- const isLastHour = hourIndex === SHIFT_DURATION - 1;
33375
- const startDecimalHour = shiftStartTime.decimalHour + hourIndex;
33376
- const startHour = Math.floor(startDecimalHour) % 24;
33377
- const startMinute = Math.round(startDecimalHour % 1 * 60);
33378
- let endHour, endMinute;
33379
- if (isLastHour && shiftEndTime) {
33380
- endHour = shiftEndTime.hour;
33381
- endMinute = shiftEndTime.minute;
33382
- } else {
33383
- const endDecimalHour = startDecimalHour + 1;
33384
- endHour = Math.floor(endDecimalHour) % 24;
33385
- endMinute = Math.round(endDecimalHour % 1 * 60);
33386
- }
33387
- const formatTime5 = (h, m) => {
33388
- const period = h >= 12 ? "PM" : "AM";
33389
- const hour12 = h === 0 ? 12 : h > 12 ? h - 12 : h;
33390
- return `${hour12}:${m.toString().padStart(2, "0")} ${period}`;
33391
- };
33392
- return `${formatTime5(startHour, startMinute)} - ${formatTime5(endHour, endMinute)}`;
33393
- }, [shiftStartTime.decimalHour, SHIFT_DURATION, shiftEndTime]);
33394
33547
  const chartData = React141__default.useMemo(() => {
33395
33548
  return Array.from({ length: SHIFT_DURATION }, (_, i) => {
33396
- const actualHour = (shiftStartTime.hour + i) % 24;
33397
- const startMinute = shiftStartTime.minute;
33398
- let idleArray = [];
33399
- let idleMinutes = 0;
33400
- if (idleTimeHourly) {
33401
- if (startMinute > 0) {
33402
- if (i === 0) {
33403
- const firstHourData = idleTimeHourly[actualHour.toString()] || [];
33404
- const nextHour = (actualHour + 1) % 24;
33405
- const nextHourData = idleTimeHourly[nextHour.toString()] || [];
33406
- idleArray = [
33407
- ...firstHourData.slice(startMinute) || [],
33408
- ...nextHourData.slice(0, startMinute) || []
33409
- ];
33410
- } else if (i < SHIFT_DURATION - 1) {
33411
- const currentHourData = idleTimeHourly[actualHour.toString()] || [];
33412
- const nextHour = (actualHour + 1) % 24;
33413
- const nextHourData = idleTimeHourly[nextHour.toString()] || [];
33414
- idleArray = [
33415
- ...currentHourData.slice(startMinute) || [],
33416
- ...nextHourData.slice(0, startMinute) || []
33417
- ];
33418
- } else {
33419
- const hasPartialLastHour2 = shiftEndTime && shiftEndTime.minute > 0 && shiftEndTime.minute < 60;
33420
- if (hasPartialLastHour2) {
33421
- const currentHourData = idleTimeHourly[actualHour.toString()] || [];
33422
- const nextHour = (actualHour + 1) % 24;
33423
- const nextHourData = idleTimeHourly[nextHour.toString()] || [];
33424
- if (startMinute > 0) {
33425
- const firstPart = currentHourData.slice(startMinute) || [];
33426
- const secondPart = nextHourData.slice(0, shiftEndTime.minute) || [];
33427
- idleArray = [...firstPart, ...secondPart];
33428
- } else {
33429
- idleArray = currentHourData.slice(0, shiftEndTime.minute) || [];
33430
- }
33431
- } else {
33432
- const currentHourData = idleTimeHourly[actualHour.toString()] || [];
33433
- const nextHour = (actualHour + 1) % 24;
33434
- const nextHourData = idleTimeHourly[nextHour.toString()] || [];
33435
- idleArray = [
33436
- ...currentHourData.slice(startMinute) || [],
33437
- ...nextHourData.slice(0, startMinute) || []
33438
- ];
33439
- }
33440
- }
33441
- } else {
33442
- const currentHourData = idleTimeHourly[actualHour.toString()] || [];
33443
- if (i === SHIFT_DURATION - 1 && shiftEndTime && shiftEndTime.minute > 0 && shiftEndTime.minute < 60) {
33444
- idleArray = currentHourData.slice(0, shiftEndTime.minute) || [];
33445
- } else {
33446
- idleArray = currentHourData || [];
33447
- }
33448
- }
33449
- }
33450
- idleMinutes = idleArray.filter((val) => val === "1" || val === 1).length;
33549
+ const idleSlot = idleSlots[i];
33451
33550
  return {
33452
- hourIndex: i,
33453
- hour: formatHour(i),
33454
- timeRange: formatTimeRange2(i),
33551
+ hourIndex: idleSlot?.hourIndex ?? i,
33552
+ hour: idleSlot?.hour || "",
33553
+ timeRange: idleSlot?.timeRange || "",
33455
33554
  output: animatedData[i] || 0,
33456
33555
  originalOutput: data[i] || 0,
33457
33556
  // Keep original data for labels
33458
33557
  color: (animatedData[i] || 0) >= Math.round(pphThreshold) ? "#00AB45" : "#E34329",
33459
- idleMinutes,
33460
- idleArray
33558
+ idleMinutes: idleSlot?.idleMinutes || 0,
33559
+ idleArray: idleSlot?.idleArray || []
33461
33560
  };
33462
33561
  });
33463
- }, [animatedData, data, pphThreshold, idleTimeHourly, shiftStartTime.hour, shiftStartTime.minute, shiftEndTime, formatHour, formatTimeRange2, SHIFT_DURATION]);
33562
+ }, [animatedData, data, pphThreshold, idleSlots, SHIFT_DURATION]);
33464
33563
  const IdleBar = React141__default.useMemo(() => {
33465
33564
  if (!idleBarState.visible) return null;
33466
33565
  return /* @__PURE__ */ jsx(
@@ -33622,36 +33721,11 @@ var HourlyOutputChartComponent = ({
33622
33721
  content: (props) => {
33623
33722
  if (!props.active || !props.payload || props.payload.length === 0) return null;
33624
33723
  const data2 = props.payload[0].payload;
33625
- const idleRanges = [];
33626
- if (showIdleTime && data2.idleArray) {
33627
- let currentRange = null;
33628
- data2.idleArray.forEach((val, idx) => {
33629
- if (val === "1" || val === 1) {
33630
- if (!currentRange) {
33631
- currentRange = { start: idx, end: idx };
33632
- } else {
33633
- currentRange.end = idx;
33634
- }
33635
- } else if (val !== "x" && currentRange) {
33636
- idleRanges.push(currentRange);
33637
- currentRange = null;
33638
- }
33639
- });
33640
- if (currentRange) {
33641
- idleRanges.push(currentRange);
33642
- }
33643
- }
33644
- const formatIdleTimestamp = (minuteIdx) => {
33645
- const fallbackIndex = chartData.findIndex((item) => item.timeRange === data2.timeRange);
33646
- const hourOffset = Number.isFinite(data2.hourIndex) ? data2.hourIndex : fallbackIndex;
33647
- const safeHourOffset = hourOffset >= 0 ? hourOffset : 0;
33648
- const totalMinutes = (shiftStartTime.hour + safeHourOffset) * 60 + shiftStartTime.minute + minuteIdx;
33649
- const hour = Math.floor(totalMinutes / 60) % 24;
33650
- const minute = totalMinutes % 60;
33651
- const period = hour >= 12 ? "PM" : "AM";
33652
- const hour12 = hour === 0 ? 12 : hour > 12 ? hour - 12 : hour;
33653
- return `${hour12}:${minute.toString().padStart(2, "0")} ${period}`;
33654
- };
33724
+ const idlePeriods = showIdleTime ? getHourlyIdlePeriods({
33725
+ idleArray: data2.idleArray,
33726
+ shiftStart,
33727
+ hourIndex: Number.isFinite(data2.hourIndex) ? data2.hourIndex : 0
33728
+ }) : [];
33655
33729
  return /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-xl shadow-xl border border-gray-100 p-4 min-w-[220px]", children: [
33656
33730
  /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between mb-3", children: /* @__PURE__ */ jsx("p", { className: "font-semibold text-gray-900 text-sm", children: data2.timeRange }) }),
33657
33731
  /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
@@ -33670,27 +33744,22 @@ var HourlyOutputChartComponent = ({
33670
33744
  " minutes"
33671
33745
  ] })
33672
33746
  ] }) }),
33673
- idleRanges.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mt-3 bg-gray-50 rounded-lg p-2.5", children: [
33747
+ idlePeriods.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mt-3 bg-gray-50 rounded-lg p-2.5", children: [
33674
33748
  /* @__PURE__ */ jsx("p", { className: "font-medium text-gray-700 text-xs mb-2", children: "Idle periods:" }),
33675
- /* @__PURE__ */ jsx("div", { className: "space-y-1 max-h-32 overflow-y-auto pr-1", children: idleRanges.map((range, index) => {
33676
- const duration = range.end - range.start + 1;
33677
- const startTime = formatIdleTimestamp(range.start);
33678
- const endTime = formatIdleTimestamp(range.end + 1);
33679
- const fallbackIndex = chartData.findIndex((item) => item.timeRange === data2.timeRange);
33680
- Number.isFinite(data2.hourIndex) ? data2.hourIndex : fallbackIndex;
33749
+ /* @__PURE__ */ jsx("div", { className: "space-y-1 max-h-32 overflow-y-auto pr-1", children: idlePeriods.map((period, index) => {
33681
33750
  return /* @__PURE__ */ jsxs("div", { className: "text-gray-600 flex items-center gap-2 text-xs", children: [
33682
33751
  /* @__PURE__ */ jsx("span", { className: "inline-block w-1.5 h-1.5 bg-orange-400 rounded-full flex-shrink-0" }),
33683
- /* @__PURE__ */ jsx("span", { children: duration === 1 ? /* @__PURE__ */ jsxs(Fragment, { children: [
33684
- startTime,
33752
+ /* @__PURE__ */ jsx("span", { children: period.duration === 1 ? /* @__PURE__ */ jsxs(Fragment, { children: [
33753
+ period.startTime,
33685
33754
  " (",
33686
- duration,
33755
+ period.duration,
33687
33756
  " min)"
33688
33757
  ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
33689
- startTime,
33758
+ period.startTime,
33690
33759
  " - ",
33691
- endTime,
33760
+ period.endTime,
33692
33761
  " (",
33693
- duration,
33762
+ period.duration,
33694
33763
  " mins)"
33695
33764
  ] }) })
33696
33765
  ] }, index);
@@ -33845,9 +33914,8 @@ var HourlyOutputChart = React141__default.memo(HourlyOutputChartComponent, (prev
33845
33914
  HourlyOutputChart.displayName = "HourlyOutputChart";
33846
33915
 
33847
33916
  // src/components/dashboard/grid/videoGridMetricUtils.ts
33848
- var VIDEO_GRID_LEGEND_LABEL = "7 Minute Efficiency";
33849
33917
  var MAP_GRID_LEGEND_LABEL = "Efficiency";
33850
- var MIXED_VIDEO_GRID_LEGEND_LABEL = "Efficiency";
33918
+ var MIXED_VIDEO_GRID_LEGEND_LABEL = "Flow Efficiency";
33851
33919
  var isFiniteNumber = (value) => typeof value === "number" && Number.isFinite(value);
33852
33920
  var isVideoGridRecentFlowEnabled = (workspace) => isRecentFlowVideoGridMetricMode(
33853
33921
  workspace.video_grid_metric_mode,
@@ -33946,8 +34014,15 @@ var getVideoGridLegendLabel = (workspaces) => {
33946
34014
  if (recentFlowEnabledCount === 0) {
33947
34015
  return MAP_GRID_LEGEND_LABEL;
33948
34016
  }
34017
+ const recentFlowWindows = new Set(
34018
+ visibleWorkspaces.filter(isVideoGridRecentFlowEnabled).map((workspace) => workspace.recent_flow_window_minutes ?? 7).filter((value) => typeof value === "number" && Number.isFinite(value))
34019
+ );
33949
34020
  if (recentFlowEnabledCount === visibleWorkspaces.length) {
33950
- return VIDEO_GRID_LEGEND_LABEL;
34021
+ if (recentFlowWindows.size === 1) {
34022
+ const [windowMinutes] = Array.from(recentFlowWindows);
34023
+ return `${windowMinutes} Minute Efficiency`;
34024
+ }
34025
+ return MIXED_VIDEO_GRID_LEGEND_LABEL;
33951
34026
  }
33952
34027
  return MIXED_VIDEO_GRID_LEGEND_LABEL;
33953
34028
  };
@@ -33999,8 +34074,9 @@ var VideoCard = React141__default.memo(({
33999
34074
  const isRecentFlowCard = isVideoGridRecentFlowEnabled(workspace);
34000
34075
  const hasDisplayMetric = typeof videoGridDisplayValue === "number" && Number.isFinite(videoGridDisplayValue);
34001
34076
  const hasBarMetric = typeof videoGridMetricValue === "number" && Number.isFinite(videoGridMetricValue);
34077
+ const shouldRenderMetricBadge = hasDisplayMetric;
34002
34078
  const badgeTitle = hasVideoGridRecentFlow(workspace) ? `Flow ${Math.round(videoGridDisplayValue ?? 0)}%` : isRecentFlowCard ? "Flow unavailable" : `Efficiency ${Math.round(videoGridDisplayValue ?? 0)}%`;
34003
- const badgeLabel = hasDisplayMetric ? `${Math.round(videoGridDisplayValue)}%` : "X";
34079
+ const badgeLabel = `${Math.round(videoGridDisplayValue ?? 0)}%`;
34004
34080
  const efficiencyOverlayClass = videoGridColorState === "green" ? "bg-[#00D654]/25" : videoGridColorState === "yellow" ? "bg-[#FFD700]/30" : videoGridColorState === "red" ? "bg-[#FF2D0A]/30" : "bg-transparent";
34005
34081
  const efficiencyBarClass = videoGridColorState === "green" ? "bg-[#00AB45]" : videoGridColorState === "yellow" ? "bg-[#FFB020]" : videoGridColorState === "red" ? "bg-[#E34329]" : "bg-gray-500/70";
34006
34082
  const efficiencyStatus = videoGridColorState === "green" ? "High" : videoGridColorState === "yellow" ? "Medium" : videoGridColorState === "red" ? "Low" : "Neutral";
@@ -34076,7 +34152,7 @@ var VideoCard = React141__default.memo(({
34076
34152
  lastSeenText
34077
34153
  ] })
34078
34154
  ] }) }),
34079
- /* @__PURE__ */ jsx("div", { className: `absolute ${compact ? "top-1 right-1" : "top-2 right-2"} z-30`, children: /* @__PURE__ */ jsx(
34155
+ shouldRenderMetricBadge && /* @__PURE__ */ jsx("div", { className: `absolute ${compact ? "top-1 right-1" : "top-2 right-2"} z-30`, children: /* @__PURE__ */ jsx(
34080
34156
  "div",
34081
34157
  {
34082
34158
  "data-testid": "video-card-metric-badge",
@@ -35893,7 +35969,7 @@ var HourlyUptimeChartComponent = ({
35893
35969
  idleRanges.push(currentRange);
35894
35970
  }
35895
35971
  }
35896
- const formatIdleTimestamp = (minuteIdx) => {
35972
+ const formatIdleTimestamp2 = (minuteIdx) => {
35897
35973
  const totalMinutes = (shiftStartTime.hour + data.hourIndex) * 60 + shiftStartTime.minute + minuteIdx;
35898
35974
  const hour = Math.floor(totalMinutes / 60) % 24;
35899
35975
  const minute = totalMinutes % 60;
@@ -35923,8 +35999,8 @@ var HourlyUptimeChartComponent = ({
35923
35999
  /* @__PURE__ */ jsx("p", { className: "font-medium text-gray-700 text-xs mb-2", children: "Idle periods:" }),
35924
36000
  /* @__PURE__ */ jsx("div", { className: "space-y-1 max-h-32 overflow-y-auto pr-1", children: idleRanges.map((range, index) => {
35925
36001
  const duration = range.end - range.start + 1;
35926
- const startTime = formatIdleTimestamp(range.start);
35927
- const endTime = formatIdleTimestamp(range.end + 1);
36002
+ const startTime = formatIdleTimestamp2(range.start);
36003
+ const endTime = formatIdleTimestamp2(range.end + 1);
35928
36004
  return /* @__PURE__ */ jsxs("div", { className: "text-gray-600 flex items-center gap-2 text-xs", children: [
35929
36005
  /* @__PURE__ */ jsx("span", { className: "inline-block w-1.5 h-1.5 bg-orange-400 rounded-full flex-shrink-0" }),
35930
36006
  /* @__PURE__ */ jsx("span", { children: duration === 1 ? `${startTime} (${duration} min)` : `${startTime} - ${endTime} (${duration} mins)` })
@@ -49803,8 +49879,7 @@ var WorkspaceCycleTimeMetricCards = ({
49803
49879
  {
49804
49880
  data: idleTimeData.chartData,
49805
49881
  isLoading: idleTimeData.isLoading,
49806
- error: idleTimeData.error,
49807
- variant: "bar"
49882
+ error: idleTimeData.error
49808
49883
  }
49809
49884
  ) })
49810
49885
  ] })
@@ -69172,56 +69247,43 @@ var WorkspaceDetailView = ({
69172
69247
  const canToggleChartIdleTime = !isUptimeMode && !shouldShowCycleTimeLoadingState && !shouldShowCycleTimeUnavailableState;
69173
69248
  const idleClipDate = date || workspace?.date || calculatedOperationalDate || getOperationalDate(timezone);
69174
69249
  const idleClipShiftId = parsedShiftId ?? workspace?.shift_id;
69175
- const rawHourlyIdleMinutes = useMemo(() => {
69176
- if (!shouldShowCycleTimeChart || !workspace?.idle_time_hourly || !workspace?.shift_start) return [];
69177
- const parseTimeToMinutes4 = (time2) => {
69178
- const [h, m] = time2.split(":").map(Number);
69179
- if (!Number.isFinite(h) || !Number.isFinite(m)) return 0;
69180
- return h * 60 + m;
69181
- };
69182
- const startTotal = parseTimeToMinutes4(workspace.shift_start);
69183
- const endTotalRaw = workspace.shift_end ? parseTimeToMinutes4(workspace.shift_end) : startTotal + 11 * 60;
69184
- const endTotal = endTotalRaw <= startTotal ? endTotalRaw + 24 * 60 : endTotalRaw;
69185
- const shiftDuration = Math.max(60, endTotal - startTotal);
69186
- const totalHourSlots = Math.max(1, Math.ceil(shiftDuration / 60));
69187
- const idleTimeHourlyObj = workspace.idle_time_hourly || {};
69188
- const result = Array(totalHourSlots).fill(0);
69189
- for (let i = 0; i < totalHourSlots; i++) {
69190
- const startSlotMins = startTotal + i * 60;
69191
- let endSlotMins = startSlotMins + 60;
69192
- if (endSlotMins > endTotal) endSlotMins = endTotal;
69193
- let idleCount = 0;
69194
- for (let m = startSlotMins; m < endSlotMins; m++) {
69195
- const hourKey = Math.floor(m / 60) % 24;
69196
- const minuteKey = m % 60;
69197
- const hourData = idleTimeHourlyObj[hourKey.toString()] || [];
69198
- if (Array.isArray(hourData)) {
69199
- const val = hourData[minuteKey];
69200
- if (val === 1 || val === "1") {
69201
- idleCount++;
69202
- }
69203
- }
69204
- }
69205
- result[i] = idleCount;
69206
- }
69207
- return result;
69208
- }, [shouldShowCycleTimeChart, workspace?.idle_time_hourly, workspace?.shift_start, workspace?.shift_end]);
69250
+ const rawHourlyIdleSlots = useMemo(
69251
+ () => !shouldShowCycleTimeChart || !authoritativeCycleMetrics?.shift_start ? [] : buildHourlyIdleSlots({
69252
+ idleTimeHourly: authoritativeCycleMetrics.idle_time_hourly,
69253
+ shiftStart: authoritativeCycleMetrics.shift_start,
69254
+ shiftEnd: authoritativeCycleMetrics.shift_end
69255
+ }),
69256
+ [
69257
+ shouldShowCycleTimeChart,
69258
+ authoritativeCycleMetrics?.idle_time_hourly,
69259
+ authoritativeCycleMetrics?.shift_start,
69260
+ authoritativeCycleMetrics?.shift_end
69261
+ ]
69262
+ );
69263
+ const rawHourlyIdleMinutes = useMemo(
69264
+ () => rawHourlyIdleSlots.map((slot) => slot.idleMinutes),
69265
+ [rawHourlyIdleSlots]
69266
+ );
69209
69267
  const hourlyIdleMinutes = useMemo(
69210
69268
  () => maskFutureHourlySeries({
69211
69269
  data: rawHourlyIdleMinutes,
69212
- shiftStart: workspace?.shift_start,
69213
- shiftEnd: workspace?.shift_end,
69270
+ shiftStart: authoritativeCycleMetrics?.shift_start,
69271
+ shiftEnd: authoritativeCycleMetrics?.shift_end,
69214
69272
  shiftDate: idleClipDate,
69215
69273
  timezone: effectiveCycleTimeTimezone
69216
69274
  }),
69217
69275
  [
69218
69276
  rawHourlyIdleMinutes,
69219
- workspace?.shift_start,
69220
- workspace?.shift_end,
69277
+ authoritativeCycleMetrics?.shift_start,
69278
+ authoritativeCycleMetrics?.shift_end,
69221
69279
  idleClipDate,
69222
69280
  effectiveCycleTimeTimezone
69223
69281
  ]
69224
69282
  );
69283
+ const hourlyIdleSlots = useMemo(
69284
+ () => rawHourlyIdleSlots.map((slot, index) => hourlyIdleMinutes[index] === null ? null : slot),
69285
+ [rawHourlyIdleSlots, hourlyIdleMinutes]
69286
+ );
69225
69287
  const cycleTimeUnavailableView = useMemo(() => /* @__PURE__ */ jsxs("div", { className: "w-full h-full rounded-lg border border-amber-200 bg-amber-50/70 px-6 py-5 text-center flex flex-col items-center justify-center", children: [
69226
69288
  /* @__PURE__ */ jsx("h4", { className: "text-base font-semibold text-amber-900", children: "Cycle data unavailable" }),
69227
69289
  /* @__PURE__ */ jsx("p", { className: "mt-2 max-w-md text-sm text-amber-800", children: "This workstation has cycle-time metrics for the selected shift, but no matching `cycle_completion` clips were found for the chart." }),
@@ -69777,7 +69839,8 @@ var WorkspaceDetailView = ({
69777
69839
  xAxisMode: "hourly",
69778
69840
  datasetKey: cycleTimeDatasetKey,
69779
69841
  showIdleTime: showChartIdleTime,
69780
- idleTimeData: hourlyIdleMinutes
69842
+ idleTimeData: hourlyIdleMinutes,
69843
+ idleTimeSlots: hourlyIdleSlots
69781
69844
  }
69782
69845
  ) : null : /* @__PURE__ */ jsx(
69783
69846
  HourlyOutputChart2,
@@ -69906,7 +69969,8 @@ var WorkspaceDetailView = ({
69906
69969
  xAxisMode: "hourly",
69907
69970
  datasetKey: cycleTimeDatasetKey,
69908
69971
  showIdleTime: showChartIdleTime,
69909
- idleTimeData: hourlyIdleMinutes
69972
+ idleTimeData: hourlyIdleMinutes,
69973
+ idleTimeSlots: hourlyIdleSlots
69910
69974
  }
69911
69975
  ) : null : /* @__PURE__ */ jsx(
69912
69976
  HourlyOutputChart2,
@@ -76424,7 +76488,7 @@ var formatComparisonWindow = ({
76424
76488
  shiftMode
76425
76489
  }) => {
76426
76490
  if (comparisonStrategy === "previous_full_week") return "last week";
76427
- if (comparisonStrategy === "matched_range" && shiftMode !== "all" && currentDayCount === 1 && previousDayCount === 1) {
76491
+ if (comparisonStrategy === "matched_range" && currentDayCount === 1 && previousDayCount === 1) {
76428
76492
  return "previous day";
76429
76493
  }
76430
76494
  if (!previousDayCount || !Number.isFinite(previousDayCount)) return "previous range";
@@ -76447,8 +76511,14 @@ var buildDeltaBadge = (delta, options) => {
76447
76511
  };
76448
76512
  };
76449
76513
  var normalizeShiftLabel = (shiftName, shiftMode) => {
76514
+ if (shiftMode === "all") {
76515
+ return "All Shifts";
76516
+ }
76450
76517
  const trimmedName = shiftName?.trim();
76451
76518
  if (trimmedName) {
76519
+ const normalizedName = trimmedName.toLowerCase();
76520
+ if (normalizedName === "day") return "Day Shift";
76521
+ if (normalizedName === "night") return "Night Shift";
76452
76522
  return /shift/i.test(trimmedName) ? trimmedName : `${trimmedName} Shift`;
76453
76523
  }
76454
76524
  if (shiftMode === "night") return "Night Shift";
@@ -76457,6 +76527,9 @@ var normalizeShiftLabel = (shiftName, shiftMode) => {
76457
76527
  var getShiftIcon = (shiftName, shiftMode) => {
76458
76528
  const normalizedName = (shiftName || "").toLowerCase();
76459
76529
  const normalizedMode = shiftMode || "day";
76530
+ if (normalizedMode === "all") {
76531
+ return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
76532
+ }
76460
76533
  if (normalizedName.includes("day") || normalizedName.includes("morning") || normalizedMode === "day") {
76461
76534
  return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
76462
76535
  }
@@ -76535,6 +76608,7 @@ var OperationsOverviewHeader = React141__default.memo(({
76535
76608
  }) => {
76536
76609
  bumpRenderCounter();
76537
76610
  const subtitleRange = displayDateRange || dateRange;
76611
+ const showLiveShiftMeta = isLiveScope && trendMode !== "all";
76538
76612
  const liveShiftLabel = React141__default.useMemo(
76539
76613
  () => normalizeShiftLabel(liveShiftName, trendMode),
76540
76614
  [liveShiftName, trendMode]
@@ -76672,8 +76746,8 @@ var OperationsOverviewHeader = React141__default.memo(({
76672
76746
  ] }),
76673
76747
  /* @__PURE__ */ jsxs("div", { className: "mt-1 flex flex-wrap items-center justify-center gap-x-2 gap-y-1 text-[11px] font-medium text-slate-500 min-w-0", children: [
76674
76748
  /* @__PURE__ */ jsx("span", { className: "truncate text-center", children: mobileSubtitle }),
76675
- isLiveScope ? /* @__PURE__ */ jsx("span", { className: "text-slate-300", children: "|" }) : null,
76676
- isLiveScope ? /* @__PURE__ */ jsx("span", { "data-testid": "operations-overview-live-meta", className: "inline-flex items-center gap-1.5 text-gray-600 min-w-0", children: /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 justify-center truncate", children: [
76749
+ showLiveShiftMeta ? /* @__PURE__ */ jsx("span", { className: "text-slate-300", children: "|" }) : null,
76750
+ showLiveShiftMeta ? /* @__PURE__ */ jsx("span", { "data-testid": "operations-overview-live-meta", className: "inline-flex items-center gap-1.5 text-gray-600 min-w-0", children: /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 justify-center truncate", children: [
76677
76751
  /* @__PURE__ */ jsx("span", { className: "opacity-75 shrink-0", children: liveShiftIcon }),
76678
76752
  /* @__PURE__ */ jsx("span", { className: "truncate", children: liveShiftLabel })
76679
76753
  ] }) }) : null
@@ -76720,7 +76794,7 @@ var OperationsOverviewHeader = React141__default.memo(({
76720
76794
  ] }),
76721
76795
  /* @__PURE__ */ jsxs("div", { className: "mt-2 flex flex-wrap items-center justify-center gap-x-3 gap-y-1 text-xs sm:text-sm font-medium text-slate-500 text-center", children: [
76722
76796
  /* @__PURE__ */ jsx("span", { children: desktopSubtitle }),
76723
- isLiveScope ? /* @__PURE__ */ jsxs(Fragment, { children: [
76797
+ showLiveShiftMeta ? /* @__PURE__ */ jsxs(Fragment, { children: [
76724
76798
  /* @__PURE__ */ jsx("span", { className: "text-slate-300", children: "|" }),
76725
76799
  /* @__PURE__ */ jsx("span", { "data-testid": "operations-overview-live-meta", className: "inline-flex items-center gap-1.5 text-gray-600", children: /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5 justify-center", children: [
76726
76800
  /* @__PURE__ */ jsx("span", { className: "opacity-75", children: liveShiftIcon }),
@@ -77294,18 +77368,18 @@ var EfficiencyTrendCard = React141__default.memo(({
77294
77368
  return (trend.data.points || []).map((point, index) => ({
77295
77369
  name: (() => {
77296
77370
  const rawLabel = point.label?.trim() || "";
77297
- if (!hourlyLabelStartTime) {
77298
- return rawLabel || `Hour ${index + 1}`;
77299
- }
77300
- if (rawLabel && !/^Hour\s+\d+$/i.test(rawLabel)) {
77371
+ if (rawLabel) {
77301
77372
  return rawLabel;
77302
77373
  }
77374
+ if (!hourlyLabelStartTime) {
77375
+ return "";
77376
+ }
77303
77377
  const hourIndex = typeof point.hour_index === "number" ? point.hour_index : index;
77304
77378
  const [hoursPart, minutesPart] = hourlyLabelStartTime.split(":");
77305
77379
  const startHours = Number(hoursPart);
77306
77380
  const startMinutes = Number(minutesPart);
77307
77381
  if (!Number.isFinite(startHours) || !Number.isFinite(startMinutes)) {
77308
- return rawLabel || `Hour ${index + 1}`;
77382
+ return "";
77309
77383
  }
77310
77384
  const totalMinutes = startHours * 60 + startMinutes + hourIndex * 60;
77311
77385
  const hour24 = Math.floor(totalMinutes / 60) % 24;
@@ -77367,6 +77441,12 @@ var EfficiencyTrendCard = React141__default.memo(({
77367
77441
  if (!dayOfWeek || typeof label !== "string") return label;
77368
77442
  return `${label} (${dayOfWeek})`;
77369
77443
  }, [isHourlyTrend]);
77444
+ const trendXAxisTickFormatter = React141__default.useCallback((value, index) => {
77445
+ if (!isHourlyTrend) {
77446
+ return typeof value === "string" ? value : String(value ?? "");
77447
+ }
77448
+ return index % 2 === 0 ? typeof value === "string" ? value : String(value ?? "") : "";
77449
+ }, [isHourlyTrend]);
77370
77450
  return /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-xl shadow-[0_2px_10px_-3px_rgba(6,81,237,0.1)] border border-slate-100 flex flex-col overflow-hidden text-left", children: [
77371
77451
  /* @__PURE__ */ jsx("div", { className: "px-6 py-5 flex-none flex justify-between items-center border-b border-slate-50/50", children: /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-gray-700", children: "Efficiency Trend" }) }),
77372
77452
  /* @__PURE__ */ jsx("div", { className: "flex-1 min-h-[250px] w-full p-4 pt-4 relative", children: showInitialSkeleton ? /* @__PURE__ */ jsx(OverviewChartSkeleton, {}) : /* @__PURE__ */ jsx("div", { className: "absolute inset-0 pb-2 pr-4 pl-1", children: /* @__PURE__ */ jsx(
@@ -77375,6 +77455,8 @@ var EfficiencyTrendCard = React141__default.memo(({
77375
77455
  data: trendData,
77376
77456
  lines: efficiencyLineConfig,
77377
77457
  xAxisDataKey: "name",
77458
+ xAxisInterval: isHourlyTrend ? 0 : void 0,
77459
+ xAxisTickFormatter: trendXAxisTickFormatter,
77378
77460
  yAxisUnit: "%",
77379
77461
  yAxisDomain: [0, 100],
77380
77462
  showLegend: false,
@@ -77880,6 +77962,62 @@ var classifyShiftBucket = ({
77880
77962
  if (normalizedShiftId === 1) return "night";
77881
77963
  return null;
77882
77964
  };
77965
+ var getShiftWindowsForConfig = (shiftConfig, timezone) => {
77966
+ if (shiftConfig?.shifts && shiftConfig.shifts.length > 0) {
77967
+ return shiftConfig.shifts.map((shift) => ({
77968
+ shiftId: shift.shiftId,
77969
+ shiftName: shift.shiftName,
77970
+ startTime: shift.startTime,
77971
+ endTime: shift.endTime
77972
+ }));
77973
+ }
77974
+ const windows = [];
77975
+ if (shiftConfig?.dayShift) {
77976
+ windows.push({
77977
+ shiftId: shiftConfig.dayShift.id ?? 0,
77978
+ shiftName: shiftConfig.dayShift.name || "Day Shift",
77979
+ startTime: shiftConfig.dayShift.startTime || "06:00",
77980
+ endTime: shiftConfig.dayShift.endTime || "18:00"
77981
+ });
77982
+ }
77983
+ if (shiftConfig?.nightShift) {
77984
+ windows.push({
77985
+ shiftId: shiftConfig.nightShift.id ?? 1,
77986
+ shiftName: shiftConfig.nightShift.name || "Night Shift",
77987
+ startTime: shiftConfig.nightShift.startTime || "18:00",
77988
+ endTime: shiftConfig.nightShift.endTime || "06:00"
77989
+ });
77990
+ }
77991
+ if (windows.length > 0) {
77992
+ return windows;
77993
+ }
77994
+ return [
77995
+ {
77996
+ shiftId: 0,
77997
+ shiftName: "Day Shift",
77998
+ startTime: "06:00",
77999
+ endTime: "18:00"
78000
+ },
78001
+ {
78002
+ shiftId: 1,
78003
+ shiftName: "Night Shift",
78004
+ startTime: "18:00",
78005
+ endTime: "06:00"
78006
+ }
78007
+ ];
78008
+ };
78009
+ var normalizeShiftWindowMinutes = (startTime, endTime) => {
78010
+ const startMinutes = parseTimeToMinutes3(startTime);
78011
+ const endMinutesRaw = parseTimeToMinutes3(endTime);
78012
+ if (startMinutes === null || endMinutesRaw === null) {
78013
+ return null;
78014
+ }
78015
+ let endMinutes = endMinutesRaw;
78016
+ if (endMinutes <= startMinutes) {
78017
+ endMinutes += 24 * 60;
78018
+ }
78019
+ return { startMinutes, endMinutes };
78020
+ };
77883
78021
  var PlantHeadView = () => {
77884
78022
  const supabase = useSupabase();
77885
78023
  const entityConfig = useEntityConfig();
@@ -77905,6 +78043,7 @@ var PlantHeadView = () => {
77905
78043
  const [selectedSupervisorId, setSelectedSupervisorId] = React141__default.useState("all");
77906
78044
  const [selectedLineIds, setSelectedLineIds] = React141__default.useState([]);
77907
78045
  const [isInitialScopeReady, setIsInitialScopeReady] = React141__default.useState(false);
78046
+ const [shiftResolutionTick, setShiftResolutionTick] = React141__default.useState(0);
77908
78047
  const hasAutoInitializedScopeRef = React141__default.useRef(false);
77909
78048
  const hasUserAdjustedScopeRef = React141__default.useRef(false);
77910
78049
  React141__default.useEffect(() => {
@@ -78009,34 +78148,151 @@ var PlantHeadView = () => {
78009
78148
  shiftConfigMap,
78010
78149
  isLoading: isShiftConfigLoading
78011
78150
  } = useMultiLineShiftConfigs(scopedLineIds, staticShiftConfig);
78012
- const { shiftGroups, hasComputed: hasComputedShiftGroups } = useShiftGroups({
78013
- enabled: scopedLineIds.length > 0 && !isShiftConfigLoading,
78014
- shiftConfigMap,
78015
- timezone: appTimezone
78016
- });
78017
- const currentShiftScope = React141__default.useMemo(() => {
78018
- if (shiftGroups.length !== 1) return null;
78019
- const group = shiftGroups[0];
78020
- const referenceLineId = group.lineIds[0];
78021
- const referenceShiftConfig = referenceLineId ? shiftConfigMap.get(referenceLineId) : null;
78022
- const normalizedGroupShiftId = normalizeShiftId(group.shiftId);
78023
- const shiftDefinition = referenceShiftConfig?.shifts?.find((shift) => normalizeShiftId(shift.shiftId) === normalizedGroupShiftId);
78024
- const resolvedMode = classifyShiftBucket({
78025
- shiftName: group.shiftName,
78026
- shiftId: normalizedGroupShiftId,
78027
- startTime: shiftDefinition?.startTime,
78028
- endTime: shiftDefinition?.endTime
78029
- });
78030
- if (!resolvedMode || resolvedMode === "all") return null;
78031
- return {
78032
- date: group.date,
78033
- trendMode: resolvedMode,
78034
- shiftName: shiftDefinition?.shiftName || group.shiftName || null
78151
+ React141__default.useEffect(() => {
78152
+ if (scopedLineIds.length === 0 || isShiftConfigLoading) {
78153
+ return;
78154
+ }
78155
+ const intervalId = window.setInterval(() => {
78156
+ setShiftResolutionTick((previous) => previous + 1);
78157
+ }, 6e4);
78158
+ return () => {
78159
+ clearInterval(intervalId);
78035
78160
  };
78036
- }, [shiftConfigMap, shiftGroups]);
78161
+ }, [isShiftConfigLoading, scopedLineIds.length]);
78162
+ const shiftResolutionNow = React141__default.useMemo(
78163
+ () => /* @__PURE__ */ new Date(),
78164
+ [shiftResolutionTick]
78165
+ );
78166
+ const earliestDayShiftStartTime = React141__default.useMemo(() => {
78167
+ const candidateStarts = [];
78168
+ scopedLineIds.forEach((lineId) => {
78169
+ const shiftConfig = shiftConfigMap.get(lineId) || staticShiftConfig;
78170
+ getShiftWindowsForConfig(shiftConfig).forEach((shift) => {
78171
+ const bucket = classifyShiftBucket({
78172
+ shiftName: shift.shiftName,
78173
+ shiftId: shift.shiftId,
78174
+ startTime: shift.startTime,
78175
+ endTime: shift.endTime
78176
+ });
78177
+ const startMinutes = parseTimeToMinutes3(shift.startTime);
78178
+ if (bucket === "day" && startMinutes !== null) {
78179
+ candidateStarts.push(startMinutes);
78180
+ }
78181
+ });
78182
+ });
78183
+ if (candidateStarts.length === 0) {
78184
+ scopedLineIds.forEach((lineId) => {
78185
+ const shiftConfig = shiftConfigMap.get(lineId) || staticShiftConfig;
78186
+ getShiftWindowsForConfig(shiftConfig).forEach((shift) => {
78187
+ const startMinutes = parseTimeToMinutes3(shift.startTime);
78188
+ if (startMinutes !== null) {
78189
+ candidateStarts.push(startMinutes);
78190
+ }
78191
+ });
78192
+ });
78193
+ }
78194
+ if (candidateStarts.length === 0) {
78195
+ return "06:00";
78196
+ }
78197
+ const earliestMinutes = Math.min(...candidateStarts);
78198
+ const hours = Math.floor(earliestMinutes / 60);
78199
+ const minutes = earliestMinutes % 60;
78200
+ return `${hours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}`;
78201
+ }, [appTimezone, scopedLineIds, shiftConfigMap, staticShiftConfig]);
78202
+ const resolvedOperationalToday = React141__default.useMemo(
78203
+ () => getOperationalDate(appTimezone, shiftResolutionNow, earliestDayShiftStartTime),
78204
+ [appTimezone, earliestDayShiftStartTime, shiftResolutionNow]
78205
+ );
78206
+ const activeLineShiftStates = React141__default.useMemo(() => {
78207
+ return scopedLineIds.flatMap((lineId) => {
78208
+ const shiftConfig = shiftConfigMap.get(lineId) || staticShiftConfig;
78209
+ const activeShift = getActiveShift(appTimezone, shiftConfig, shiftResolutionNow);
78210
+ if (!activeShift) {
78211
+ return [];
78212
+ }
78213
+ const trendBucket = classifyShiftBucket({
78214
+ shiftName: activeShift.shiftName,
78215
+ shiftId: activeShift.shiftId,
78216
+ startTime: activeShift.startTime,
78217
+ endTime: activeShift.endTime
78218
+ });
78219
+ if (!trendBucket || trendBucket === "all") {
78220
+ return [];
78221
+ }
78222
+ return [{
78223
+ lineId,
78224
+ trendMode: trendBucket,
78225
+ shiftId: activeShift.shiftId,
78226
+ shiftName: activeShift.shiftName || null,
78227
+ startTime: activeShift.startTime || null,
78228
+ endTime: activeShift.endTime || null,
78229
+ date: activeShift.date
78230
+ }];
78231
+ });
78232
+ }, [appTimezone, scopedLineIds, shiftConfigMap, shiftResolutionNow, staticShiftConfig]);
78233
+ const hasActiveDayShiftLine = React141__default.useMemo(
78234
+ () => activeLineShiftStates.some((shift) => shift.trendMode === "day" && shift.date === resolvedOperationalToday),
78235
+ [activeLineShiftStates, resolvedOperationalToday]
78236
+ );
78237
+ const hasActiveNightShiftLine = React141__default.useMemo(
78238
+ () => activeLineShiftStates.some((shift) => shift.trendMode === "night" && shift.date === resolvedOperationalToday),
78239
+ [activeLineShiftStates, resolvedOperationalToday]
78240
+ );
78241
+ const resolvedTrendMode = isInitialScopeReady ? trendMode : "all";
78242
+ const hourlyWindowStartTime = React141__default.useMemo(() => {
78243
+ if (scopedLineIds.length === 0) {
78244
+ return null;
78245
+ }
78246
+ const startCandidates = [];
78247
+ const endCandidates = [];
78248
+ scopedLineIds.forEach((lineId) => {
78249
+ const shiftConfig = shiftConfigMap.get(lineId) || staticShiftConfig;
78250
+ getShiftWindowsForConfig(shiftConfig).forEach((shift) => {
78251
+ const bucket = classifyShiftBucket({
78252
+ shiftName: shift.shiftName,
78253
+ shiftId: shift.shiftId,
78254
+ startTime: shift.startTime,
78255
+ endTime: shift.endTime
78256
+ });
78257
+ if (resolvedTrendMode !== "all" && bucket !== resolvedTrendMode) {
78258
+ return;
78259
+ }
78260
+ const normalizedWindow = normalizeShiftWindowMinutes(shift.startTime, shift.endTime);
78261
+ if (!normalizedWindow) {
78262
+ return;
78263
+ }
78264
+ startCandidates.push(normalizedWindow.startMinutes);
78265
+ endCandidates.push(normalizedWindow.endMinutes);
78266
+ });
78267
+ });
78268
+ if (resolvedTrendMode === "all") {
78269
+ const dayStartCandidates = startCandidates.length > 0 ? scopedLineIds.flatMap((lineId) => {
78270
+ const shiftConfig = shiftConfigMap.get(lineId) || staticShiftConfig;
78271
+ return getShiftWindowsForConfig(shiftConfig).map((shift) => {
78272
+ const bucket = classifyShiftBucket({
78273
+ shiftName: shift.shiftName,
78274
+ shiftId: shift.shiftId,
78275
+ startTime: shift.startTime,
78276
+ endTime: shift.endTime
78277
+ });
78278
+ return bucket === "day" ? parseTimeToMinutes3(shift.startTime) : null;
78279
+ }).filter((value) => value !== null);
78280
+ }) : [];
78281
+ if (dayStartCandidates.length > 0) {
78282
+ startCandidates.splice(0, startCandidates.length, ...dayStartCandidates);
78283
+ }
78284
+ }
78285
+ if (startCandidates.length === 0 || endCandidates.length === 0) {
78286
+ return null;
78287
+ }
78288
+ const earliestMinutes = Math.min(...startCandidates);
78289
+ const hours = Math.floor(earliestMinutes / 60);
78290
+ const minutes = earliestMinutes % 60;
78291
+ return `${hours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}`;
78292
+ }, [appTimezone, resolvedTrendMode, scopedLineIds, shiftConfigMap, staticShiftConfig]);
78037
78293
  const isShiftScopeResolved = React141__default.useMemo(
78038
- () => !isShiftConfigLoading && hasComputedShiftGroups,
78039
- [hasComputedShiftGroups, isShiftConfigLoading]
78294
+ () => !isShiftConfigLoading,
78295
+ [isShiftConfigLoading]
78040
78296
  );
78041
78297
  const initializedTimezoneRef = React141__default.useRef(appTimezone);
78042
78298
  React141__default.useEffect(() => {
@@ -78063,7 +78319,7 @@ var PlantHeadView = () => {
78063
78319
  return;
78064
78320
  }
78065
78321
  setDateRange((previous) => {
78066
- const nextStartKey = currentShiftScope?.date || fallbackOperationalDate;
78322
+ const nextStartKey = resolvedOperationalToday || fallbackOperationalDate;
78067
78323
  if (previous.startKey === nextStartKey && previous.endKey === nextStartKey) {
78068
78324
  return previous;
78069
78325
  }
@@ -78072,11 +78328,11 @@ var PlantHeadView = () => {
78072
78328
  endKey: nextStartKey
78073
78329
  };
78074
78330
  });
78075
- setTrendMode(currentShiftScope?.trendMode || "all");
78331
+ setTrendMode("all");
78076
78332
  setUsesThisWeekComparison(false);
78077
78333
  hasAutoInitializedScopeRef.current = true;
78078
78334
  setIsInitialScopeReady(true);
78079
- }, [currentShiftScope, fallbackOperationalDate, isShiftScopeResolved, scopedLineIds.length]);
78335
+ }, [fallbackOperationalDate, isShiftScopeResolved, resolvedOperationalToday, scopedLineIds.length]);
78080
78336
  const handleDateRangeChange = React141__default.useCallback((range, meta) => {
78081
78337
  hasUserAdjustedScopeRef.current = true;
78082
78338
  setIsInitialScopeReady(true);
@@ -78153,45 +78409,36 @@ var PlantHeadView = () => {
78153
78409
  if (isInitialScopeReady) {
78154
78410
  return dateRange;
78155
78411
  }
78156
- const nextStartKey = currentShiftScope?.date || fallbackOperationalDate;
78412
+ const nextStartKey = resolvedOperationalToday || fallbackOperationalDate;
78157
78413
  return {
78158
78414
  startKey: nextStartKey,
78159
78415
  endKey: nextStartKey
78160
78416
  };
78161
- }, [currentShiftScope, dateRange, fallbackOperationalDate, isInitialScopeReady]);
78417
+ }, [dateRange, fallbackOperationalDate, isInitialScopeReady, resolvedOperationalToday]);
78162
78418
  const effectiveTrendMode = React141__default.useMemo(
78163
- () => isInitialScopeReady ? trendMode : currentShiftScope?.trendMode || "all",
78164
- [currentShiftScope, isInitialScopeReady, trendMode]
78419
+ () => resolvedTrendMode,
78420
+ [resolvedTrendMode]
78165
78421
  );
78166
78422
  const hourlyLabelStartTime = React141__default.useMemo(() => {
78167
- if (effectiveTrendMode === "all" || scopedLineIds.length === 0) {
78168
- return null;
78169
- }
78170
- const shiftStartTimes = /* @__PURE__ */ new Set();
78171
- scopedLineIds.forEach((lineId) => {
78172
- const shiftConfig = shiftConfigMap.get(lineId);
78173
- const matchingShift = shiftConfig?.shifts?.find((shift) => classifyShiftBucket({
78174
- shiftName: shift.shiftName,
78175
- shiftId: shift.shiftId,
78176
- startTime: shift.startTime,
78177
- endTime: shift.endTime
78178
- }) === effectiveTrendMode);
78179
- if (matchingShift?.startTime) {
78180
- shiftStartTimes.add(matchingShift.startTime);
78181
- }
78182
- });
78183
- if (shiftStartTimes.size !== 1) {
78423
+ if (scopedLineIds.length === 0) {
78184
78424
  return null;
78185
78425
  }
78186
- return Array.from(shiftStartTimes)[0] || null;
78187
- }, [effectiveTrendMode, scopedLineIds, shiftConfigMap]);
78188
- const isSingleDayShiftScope = React141__default.useMemo(
78189
- () => effectiveDateRange.startKey === effectiveDateRange.endKey && effectiveTrendMode !== "all",
78190
- [effectiveDateRange.endKey, effectiveDateRange.startKey, effectiveTrendMode]
78426
+ return hourlyWindowStartTime;
78427
+ }, [hourlyWindowStartTime, scopedLineIds.length]);
78428
+ const isSingleDayScope = React141__default.useMemo(
78429
+ () => effectiveDateRange.startKey === effectiveDateRange.endKey,
78430
+ [effectiveDateRange.endKey, effectiveDateRange.startKey]
78191
78431
  );
78192
78432
  const isLiveScope = React141__default.useMemo(
78193
- () => isSingleDayShiftScope && currentShiftScope !== null && effectiveDateRange.startKey === currentShiftScope.date && effectiveTrendMode === currentShiftScope.trendMode,
78194
- [currentShiftScope, effectiveDateRange.startKey, effectiveTrendMode, isSingleDayShiftScope]
78433
+ () => isSingleDayScope && effectiveDateRange.startKey === resolvedOperationalToday && (effectiveTrendMode === "all" || effectiveTrendMode === "day" && hasActiveDayShiftLine || effectiveTrendMode === "night" && hasActiveNightShiftLine),
78434
+ [
78435
+ effectiveDateRange.startKey,
78436
+ effectiveTrendMode,
78437
+ hasActiveDayShiftLine,
78438
+ hasActiveNightShiftLine,
78439
+ isSingleDayScope,
78440
+ resolvedOperationalToday
78441
+ ]
78195
78442
  );
78196
78443
  const handleOpenLineDetails = React141__default.useCallback((lineId, lineName) => {
78197
78444
  trackCoreEvent("Operations Overview Line Clicked", {
@@ -78226,7 +78473,7 @@ var PlantHeadView = () => {
78226
78473
  displayDateRange: headerDateRange,
78227
78474
  trendMode,
78228
78475
  isLiveScope,
78229
- liveShiftName: currentShiftScope?.shiftName || null,
78476
+ liveShiftName: isLiveScope && trendMode !== "all" ? trendMode : null,
78230
78477
  lineOptions,
78231
78478
  supervisorOptions,
78232
78479
  selectedSupervisorId,
@@ -78761,4 +79008,4 @@ var streamProxyConfig = {
78761
79008
  }
78762
79009
  };
78763
79010
 
78764
- export { ACTION_FAMILIES, ACTION_NAMES, AIAgentView_default as AIAgentView, AcceptInvite, AcceptInviteView_default as AcceptInviteView, AdvancedFilterDialog, AdvancedFilterPanel, AudioService, AuthCallback, AuthCallbackView_default as AuthCallbackView, AuthProvider, AuthService, AuthenticatedBottleneckClipsView, AuthenticatedFactoryView, AuthenticatedHelpView, AuthenticatedHomeView, AuthenticatedShiftsView, AuthenticatedTargetsView, AuthenticatedTicketsView, AuthenticatedWorkspaceHealthView, AvatarUpload, AxelNotificationPopup, AxelOrb, BackButton, BackButtonMinimal, BarChart, BaseHistoryCalendar, BottleneckClipsModal, BottleneckClipsView_default as BottleneckClipsView, BottlenecksContent, BreakNotificationPopup, CachePrefetchStatus, Card2 as Card, CardContent2 as CardContent, CardDescription2 as CardDescription, CardFooter2 as CardFooter, CardHeader2 as CardHeader, CardTitle2 as CardTitle, ChangeRoleDialog, ClipFilterProvider, ClipsCostView_default as ClipsCostView, CompactWorkspaceHealthCard, ConfirmRemoveUserDialog, CongratulationsOverlay, CroppedHlsVideoPlayer, CroppedVideoPlayer, CycleTimeChart, CycleTimeOverTimeChart, DEFAULT_ANALYTICS_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_CONFIG, DEFAULT_DATABASE_CONFIG, DEFAULT_DATE_TIME_CONFIG, DEFAULT_ENDPOINTS_CONFIG, DEFAULT_ENTITY_CONFIG, DEFAULT_HOME_VIEW_CONFIG, DEFAULT_MAP_VIEW_CONFIG, DEFAULT_SHIFT_CONFIG, DEFAULT_SHIFT_DATA, DEFAULT_THEME_CONFIG, DEFAULT_VIDEO_CONFIG, DEFAULT_WORKSPACE_CONFIG, DEFAULT_WORKSPACE_POSITIONS, DashboardHeader, DashboardLayout, DashboardOverridesProvider, DashboardProvider, DateDisplay_default as DateDisplay, DateTimeDisplay, DebugAuth, DebugAuthView_default as DebugAuthView, DetailedHealthStatus, DiagnosisVideoModal, EFFICIENCY_ON_TRACK_THRESHOLD, EmptyStateMessage, EncouragementOverlay, FactoryAssignmentDropdown, FactoryView_default as FactoryView, FileManagerFilters, FilterDialogTrigger, FirstTimeLoginDebug, FirstTimeLoginHandler, FittingTitle, GaugeChart, GridComponentsPlaceholder, HamburgerButton, Header, HealthDateShiftSelector, HealthStatusGrid, HealthStatusIndicator, HelpView_default as HelpView, HlsVideoPlayer, HomeView_default as HomeView, HourlyOutputChart2 as HourlyOutputChart, HourlyUptimeChart, ISTTimer_default as ISTTimer, IdleTimeVlmConfigProvider, ImprovementCenterView_default as ImprovementCenterView, InlineEditableText, InteractiveOnboardingTour, InvitationService, InvitationsTable, InviteUserDialog, KPICard, KPIDetailView_default as KPIDetailView, KPIGrid, KPIHeader, KPISection, KPIsOverviewView_default as KPIsOverviewView, LINE_1_UUID, LINE_2_UUID, LargeOutputProgressChart, LeaderboardDetailView_default as LeaderboardDetailView, Legend5 as Legend, LineAssignmentDropdown, LineChart, LineHistoryCalendar, LineMonthlyHistory, LineMonthlyPdfGenerator, LinePdfExportButton, LinePdfGenerator, LineWhatsAppShareButton, LinesService, LiveTimer, LoadingInline, LoadingOverlay_default as LoadingOverlay, LoadingPage_default as LoadingPage, LoadingSkeleton, LoadingState, LoginPage, LoginView_default as LoginView, Logo, MainLayout, MapGridView, MetricCard_default as MetricCard, MinimalOnboardingPopup, MobileMenuProvider, NewClipsNotification, NoWorkspaceData, OnboardingDemo, OnboardingTour, OptifyeAgentClient, OptifyeLogoLoader_default as OptifyeLogoLoader, OutputProgressChart, PageHeader, PieChart4 as PieChart, PlantHeadView_default as PlantHeadView, PlayPauseIndicator, PrefetchConfigurationError, PrefetchError, PrefetchEvents, PrefetchStatus, PrefetchTimeoutError, ProfileView_default as ProfileView, RegistryProvider, RoleBadge, S3ClipsSupabaseService as S3ClipsService, S3Service, SKUManagementView, SOPComplianceChart, SSEChatClient, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, SessionTracker, SessionTrackingContext, SessionTrackingProvider, SettingsPopup, ShiftDisplay_default as ShiftDisplay, ShiftsView_default as ShiftsView, SideNavBar, SignupWithInvitation, SilentErrorBoundary, SimpleOnboardingPopup, SingleVideoStream_default as SingleVideoStream, Skeleton, SubscriptionManager, SubscriptionManagerProvider, SupabaseProvider, SupervisorDropdown_default as SupervisorDropdown, SupervisorManagementView_default as SupervisorManagementView, SupervisorService, TargetWorkspaceGrid, TargetsView_default as TargetsView, TeamManagementView_default as TeamManagementView, ThreadSidebar, TicketHistory_default as TicketHistory, TicketHistoryService, TicketsView_default as TicketsView, TimeDisplay_default as TimeDisplay, TimePickerDropdown, Timer_default as Timer, TimezoneProvider, TimezoneService, UptimeDonutChart, UptimeLineChart, UptimeMetricCards, UserAvatar, UserManagementService, UserManagementTable, UserService, UserUsageDetailModal, UserUsageStats, VideoCard, VideoGridView, VideoPlayer, VideoPreloader, WORKSPACE_POSITIONS, WhatsAppShareButton, WorkspaceCard, WorkspaceCycleTimeMetricCards, WorkspaceDetailView_default as WorkspaceDetailView, WorkspaceDisplayNameExample, WorkspaceGrid, WorkspaceGridItem, WorkspaceHealthCard, WorkspaceHealthView_default as WorkspaceHealthView, WorkspaceHistoryCalendar, WorkspaceMetricCards, WorkspaceMetricCardsImpl, WorkspaceMonthlyDataFetcher, WorkspaceMonthlyHistory, WorkspaceMonthlyPdfGenerator, WorkspacePdfExportButton, WorkspacePdfGenerator, WorkspaceWhatsAppShareButton, actionService, aggregateKPIsFromLineMetricsRows, alertsService, apiUtils, areAllLinesOnSameShift, authCoreService, authOTPService, authRateLimitService, awardsService, buildDateKey, buildKPIsFromLineMetricsRow, buildShiftGroupsKey, canRoleAccessDashboardPath, canRoleAccessTeamManagement, canRoleAssignFactories, canRoleAssignLines, canRoleChangeRole, canRoleInviteRole, canRoleManageCompany, canRoleManageTargets, canRoleManageUsers, canRoleRemoveUser, canRoleViewClipsCost, canRoleViewUsageStats, captureSentryException, captureSentryMessage, checkRateLimit2 as checkRateLimit, clearAllRateLimits2 as clearAllRateLimits, clearRateLimit2 as clearRateLimit, clearS3VideoCache, clearS3VideoFromCache, clearSentryContext, clearWorkspaceDisplayNamesCache, cn, createDefaultKPIs, createInvitationService, createLinesService, createSessionTracker, createStorageService, createStreamProxyHandler, createSupabaseClient, createSupervisorService, createThrottledReload, createUserManagementService, createUserService, dashboardService, deleteThread, fetchIdleTimeReasons, filterDataByDateKeyRange, forceRefreshWorkspaceDisplayNames, formatAwardMonth, formatDateInZone, formatDateKeyForDisplay, formatDateTimeInZone, formatDuration2 as formatDuration, formatISTDate, formatIdleTime, formatRangeLabel, formatReasonLabel, formatRelativeTime, formatTimeInZone, fromUrlFriendlyName, getActionDisplayName, getAllLineDisplayNames, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAllWorkspaceDisplayNamesSnapshot, getAnonClient, getAssignableRoles, getAssignmentColumnLabel, getAvailableShiftIds, getAwardBadgeType, getAwardDescription, getAwardTitle, getBrowserName, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getConfiguredLineIds, getCoreSessionRecordingProperties, getCoreSessionReplayUrl, getCurrentShift, getCurrentShiftForLine, getCurrentTimeInZone, getCurrentWeekFullRange, getCurrentWeekToDateRange, getDashboardHeaderTimeInZone, getDateKeyFromDate, getDaysDifferenceInZone, getDefaultCameraStreamUrl, getDefaultLineId, getDefaultTabForWorkspace, getInitials, getLineDisplayName, getManufacturingInsights, getMetricsTablePrefix, getMonthKeyBounds, getMonthWeekRanges, getNextUpdateInterval, getOperationalDate, getRoleAssignmentKind, getRoleDescription, getRoleLabel, getRoleMetadata, getRoleNavPaths, getS3SignedUrl, getS3VideoSrc, getShiftData, getShiftNameById, getShiftWorkDurationSeconds, getShortShiftName, getShortWorkspaceDisplayName, getShortWorkspaceDisplayNameAsync, getStoredWorkspaceMappings, getSubscriptionManager, getThreadMessages, getUniformShiftGroup, getUserThreads, getUserThreadsPaginated, getVisibleRolesForCurrentUser, getWorkspaceDisplayName, getWorkspaceDisplayNameAsync, getWorkspaceDisplayNamesMap, getWorkspaceFromUrl, getWorkspaceNavigationParams, groupLinesByShift, hasAnyShiftData, identifyCoreUser, initializeCoreMixpanel, isEfficiencyOnTrack, isFactoryScopedRole, isFullMonthRange, isLegacyConfiguration, isLoopbackHostname, isPrefetchError, isRecentFlowVideoGridMetricMode, isSafari, isSupervisorRole, isTransitionPeriod, isUrlPermanentlyFailed, isValidFactoryViewConfiguration, isValidLineInfoPayload, isValidPrefetchParams, isValidPrefetchStatus, isValidWorkspaceDetailedMetricsPayload, isValidWorkspaceMetricsPayload, isWipGatedVideoGridMetricMode, isWorkspaceDisplayNamesLoaded, isWorkspaceDisplayNamesLoading, lineLeaderboardService, linesService, mergeWithDefaultConfig, migrateLegacyConfiguration, normalizeActionFamily, normalizeDateKeyRange, normalizeRoleLevel, normalizeVideoGridMetricMode, optifyeAgentClient, parseDateKeyToDate, parseS3Uri, preInitializeWorkspaceDisplayNames, preloadS3Video, preloadS3VideoUrl, preloadS3VideosUrl, preloadVideoUrl, preloadVideosUrl, qualityService, realtimeService, refreshWorkspaceDisplayNames, resetCoreMixpanel, resetFailedUrl, resetSubscriptionManager, s3VideoPreloader, setSentryUserContext, setSentryWorkspaceContext, shouldEnableLocalDevTestLogin, shuffleArray, simulateApiDelay, skuService, startCoreSessionRecording, stopCoreSessionRecording, storeWorkspaceMapping, streamProxyConfig, subscribeWorkspaceDisplayNames, throttledReloadDashboard, toUrlFriendlyName, trackCoreEvent, trackCorePageView, transformToChartData, updateThreadTitle, upsertWorkspaceDisplayNameInCache, useAccessControl, useActiveBreaks, useActiveLineId, useAllWorkspaceMetrics, useAnalyticsConfig, useAppTimezone, useAudioService, useAuth, useAuthConfig, useAxelNotifications, useCanSaveTargets, useClipFilter, useClipTypes, useClipTypesWithCounts, useClipsInit, useCompanyClipsCost, useCompanyUsersUsage, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useDynamicShiftConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHasLineAccess, useHideMobileHeader, useHistoricWorkspaceMetrics, useHlsStream, useHlsStreamWithCropping, useHookOverride, useHourEndTimer, useHourlyTargetAchievements, useHourlyTargetMisses, useIdleTimeClipClassifications, useIdleTimeReasons, useIdleTimeVlmConfig, useKpiTrends, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineShiftConfig, useLineSupervisor, useLineWorkspaceMetrics, useLines, useMessages, useMetrics, useMobileMenu, useMonthlyTrend, useMultiLineShiftConfigs, useNavigation, useOperationalShiftKey, useOptionalSupabase, useOverrides, usePageOverride, usePrefetchClipCounts, useRealtimeLineMetrics, useRegistry, useSKUs, useSessionKeepAlive, useSessionTracking, useSessionTrackingContext, useShiftConfig, useShiftGroups, useShifts, useSubscriptionManager, useSubscriptionManagerSafe, useSupabase, useSupabaseClient, useSupervisorsByLineIds, useTargets, useTeamManagementPermissions, useTheme, useThemeConfig, useThreads, useTicketHistory, useTimezoneContext, useUserLineAccess, useUserUsage, useVideoConfig, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceHealthById, useWorkspaceHealthLastSeen, useWorkspaceHealthStatus, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, useWorkspaceUptimeTimeline, useWorkspaceVideoStreams, userService, videoPrefetchManager, videoPreloader, weeklyTopPerformerService, whatsappService, withAccessControl, withAuth, withRegistry, withTimezone, workspaceHealthService, workspaceService };
79011
+ export { ACTION_FAMILIES, ACTION_NAMES, AIAgentView_default as AIAgentView, AcceptInvite, AcceptInviteView_default as AcceptInviteView, AdvancedFilterDialog, AdvancedFilterPanel, AudioService, AuthCallback, AuthCallbackView_default as AuthCallbackView, AuthProvider, AuthService, AuthenticatedBottleneckClipsView, AuthenticatedFactoryView, AuthenticatedHelpView, AuthenticatedHomeView, AuthenticatedShiftsView, AuthenticatedTargetsView, AuthenticatedTicketsView, AuthenticatedWorkspaceHealthView, AvatarUpload, AxelNotificationPopup, AxelOrb, BackButton, BackButtonMinimal, BarChart, BaseHistoryCalendar, BottleneckClipsModal, BottleneckClipsView_default as BottleneckClipsView, BottlenecksContent, BreakNotificationPopup, CachePrefetchStatus, Card2 as Card, CardContent2 as CardContent, CardDescription2 as CardDescription, CardFooter2 as CardFooter, CardHeader2 as CardHeader, CardTitle2 as CardTitle, ChangeRoleDialog, ClipFilterProvider, ClipsCostView_default as ClipsCostView, CompactWorkspaceHealthCard, ConfirmRemoveUserDialog, CongratulationsOverlay, CroppedHlsVideoPlayer, CroppedVideoPlayer, CycleTimeChart, CycleTimeOverTimeChart, DEFAULT_ANALYTICS_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_CONFIG, DEFAULT_DATABASE_CONFIG, DEFAULT_DATE_TIME_CONFIG, DEFAULT_ENDPOINTS_CONFIG, DEFAULT_ENTITY_CONFIG, DEFAULT_HOME_VIEW_CONFIG, DEFAULT_MAP_VIEW_CONFIG, DEFAULT_SHIFT_CONFIG, DEFAULT_SHIFT_DATA, DEFAULT_THEME_CONFIG, DEFAULT_VIDEO_CONFIG, DEFAULT_WORKSPACE_CONFIG, DEFAULT_WORKSPACE_POSITIONS, DashboardHeader, DashboardLayout, DashboardOverridesProvider, DashboardProvider, DateDisplay_default as DateDisplay, DateTimeDisplay, DebugAuth, DebugAuthView_default as DebugAuthView, DetailedHealthStatus, DiagnosisVideoModal, EFFICIENCY_ON_TRACK_THRESHOLD, EmptyStateMessage, EncouragementOverlay, FactoryAssignmentDropdown, FactoryView_default as FactoryView, FileManagerFilters, FilterDialogTrigger, FirstTimeLoginDebug, FirstTimeLoginHandler, FittingTitle, GaugeChart, GridComponentsPlaceholder, HamburgerButton, Header, HealthDateShiftSelector, HealthStatusGrid, HealthStatusIndicator, HelpView_default as HelpView, HlsVideoPlayer, HomeView_default as HomeView, HourlyOutputChart2 as HourlyOutputChart, HourlyUptimeChart, ISTTimer_default as ISTTimer, IdleTimeVlmConfigProvider, ImprovementCenterView_default as ImprovementCenterView, InlineEditableText, InteractiveOnboardingTour, InvitationService, InvitationsTable, InviteUserDialog, KPICard, KPIDetailView_default as KPIDetailView, KPIGrid, KPIHeader, KPISection, KPIsOverviewView_default as KPIsOverviewView, LINE_1_UUID, LINE_2_UUID, LargeOutputProgressChart, LeaderboardDetailView_default as LeaderboardDetailView, Legend5 as Legend, LineAssignmentDropdown, LineChart, LineHistoryCalendar, LineMonthlyHistory, LineMonthlyPdfGenerator, LinePdfExportButton, LinePdfGenerator, LineWhatsAppShareButton, LinesService, LiveTimer, LoadingInline, LoadingOverlay_default as LoadingOverlay, LoadingPage_default as LoadingPage, LoadingSkeleton, LoadingState, LoginPage, LoginView_default as LoginView, Logo, MainLayout, MapGridView, MetricCard_default as MetricCard, MinimalOnboardingPopup, MobileMenuProvider, NewClipsNotification, NoWorkspaceData, OnboardingDemo, OnboardingTour, OptifyeAgentClient, OptifyeLogoLoader_default as OptifyeLogoLoader, OutputProgressChart, PageHeader, PieChart4 as PieChart, PlantHeadView_default as PlantHeadView, PlayPauseIndicator, PrefetchConfigurationError, PrefetchError, PrefetchEvents, PrefetchStatus, PrefetchTimeoutError, ProfileView_default as ProfileView, RegistryProvider, RoleBadge, S3ClipsSupabaseService as S3ClipsService, S3Service, SKUManagementView, SOPComplianceChart, SSEChatClient, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, SessionTracker, SessionTrackingContext, SessionTrackingProvider, SettingsPopup, ShiftDisplay_default as ShiftDisplay, ShiftsView_default as ShiftsView, SideNavBar, SignupWithInvitation, SilentErrorBoundary, SimpleOnboardingPopup, SingleVideoStream_default as SingleVideoStream, Skeleton, SubscriptionManager, SubscriptionManagerProvider, SupabaseProvider, SupervisorDropdown_default as SupervisorDropdown, SupervisorManagementView_default as SupervisorManagementView, SupervisorService, TargetWorkspaceGrid, TargetsView_default as TargetsView, TeamManagementView_default as TeamManagementView, ThreadSidebar, TicketHistory_default as TicketHistory, TicketHistoryService, TicketsView_default as TicketsView, TimeDisplay_default as TimeDisplay, TimePickerDropdown, Timer_default as Timer, TimezoneProvider, TimezoneService, UptimeDonutChart, UptimeLineChart, UptimeMetricCards, UserAvatar, UserManagementService, UserManagementTable, UserService, UserUsageDetailModal, UserUsageStats, VideoCard, VideoGridView, VideoPlayer, VideoPreloader, WORKSPACE_POSITIONS, WhatsAppShareButton, WorkspaceCard, WorkspaceCycleTimeMetricCards, WorkspaceDetailView_default as WorkspaceDetailView, WorkspaceDisplayNameExample, WorkspaceGrid, WorkspaceGridItem, WorkspaceHealthCard, WorkspaceHealthView_default as WorkspaceHealthView, WorkspaceHistoryCalendar, WorkspaceMetricCards, WorkspaceMetricCardsImpl, WorkspaceMonthlyDataFetcher, WorkspaceMonthlyHistory, WorkspaceMonthlyPdfGenerator, WorkspacePdfExportButton, WorkspacePdfGenerator, WorkspaceWhatsAppShareButton, actionService, aggregateKPIsFromLineMetricsRows, alertsService, apiUtils, areAllLinesOnSameShift, authCoreService, authOTPService, authRateLimitService, awardsService, buildDateKey, buildKPIsFromLineMetricsRow, buildShiftGroupsKey, canRoleAccessDashboardPath, canRoleAccessTeamManagement, canRoleAssignFactories, canRoleAssignLines, canRoleChangeRole, canRoleInviteRole, canRoleManageCompany, canRoleManageTargets, canRoleManageUsers, canRoleRemoveUser, canRoleViewClipsCost, canRoleViewUsageStats, captureSentryException, captureSentryMessage, checkRateLimit2 as checkRateLimit, clearAllRateLimits2 as clearAllRateLimits, clearRateLimit2 as clearRateLimit, clearS3VideoCache, clearS3VideoFromCache, clearSentryContext, clearWorkspaceDisplayNamesCache, cn, createDefaultKPIs, createInvitationService, createLinesService, createSessionTracker, createStorageService, createStreamProxyHandler, createSupabaseClient, createSupervisorService, createThrottledReload, createUserManagementService, createUserService, dashboardService, deleteThread, fetchIdleTimeReasons, filterDataByDateKeyRange, forceRefreshWorkspaceDisplayNames, formatAwardMonth, formatDateInZone, formatDateKeyForDisplay, formatDateTimeInZone, formatDuration2 as formatDuration, formatISTDate, formatIdleTime, formatRangeLabel, formatReasonLabel, formatRelativeTime, formatTimeInZone, fromUrlFriendlyName, getActionDisplayName, getActiveShift, getAllLineDisplayNames, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAllWorkspaceDisplayNamesSnapshot, getAnonClient, getAssignableRoles, getAssignmentColumnLabel, getAvailableShiftIds, getAwardBadgeType, getAwardDescription, getAwardTitle, getBrowserName, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getConfiguredLineIds, getCoreSessionRecordingProperties, getCoreSessionReplayUrl, getCurrentShift, getCurrentShiftForLine, getCurrentTimeInZone, getCurrentWeekFullRange, getCurrentWeekToDateRange, getDashboardHeaderTimeInZone, getDateKeyFromDate, getDaysDifferenceInZone, getDefaultCameraStreamUrl, getDefaultLineId, getDefaultTabForWorkspace, getInitials, getLineDisplayName, getManufacturingInsights, getMetricsTablePrefix, getMonthKeyBounds, getMonthWeekRanges, getNextUpdateInterval, getOperationalDate, getRoleAssignmentKind, getRoleDescription, getRoleLabel, getRoleMetadata, getRoleNavPaths, getS3SignedUrl, getS3VideoSrc, getShiftData, getShiftNameById, getShiftWorkDurationSeconds, getShortShiftName, getShortWorkspaceDisplayName, getShortWorkspaceDisplayNameAsync, getStoredWorkspaceMappings, getSubscriptionManager, getThreadMessages, getUniformShiftGroup, getUserThreads, getUserThreadsPaginated, getVisibleRolesForCurrentUser, getWorkspaceDisplayName, getWorkspaceDisplayNameAsync, getWorkspaceDisplayNamesMap, getWorkspaceFromUrl, getWorkspaceNavigationParams, groupLinesByShift, hasAnyShiftData, identifyCoreUser, initializeCoreMixpanel, isEfficiencyOnTrack, isFactoryScopedRole, isFullMonthRange, isLegacyConfiguration, isLoopbackHostname, isPrefetchError, isRecentFlowVideoGridMetricMode, isSafari, isSupervisorRole, isTransitionPeriod, isUrlPermanentlyFailed, isValidFactoryViewConfiguration, isValidLineInfoPayload, isValidPrefetchParams, isValidPrefetchStatus, isValidWorkspaceDetailedMetricsPayload, isValidWorkspaceMetricsPayload, isWipGatedVideoGridMetricMode, isWorkspaceDisplayNamesLoaded, isWorkspaceDisplayNamesLoading, lineLeaderboardService, linesService, mergeWithDefaultConfig, migrateLegacyConfiguration, normalizeActionFamily, normalizeDateKeyRange, normalizeRoleLevel, normalizeVideoGridMetricMode, optifyeAgentClient, parseDateKeyToDate, parseS3Uri, preInitializeWorkspaceDisplayNames, preloadS3Video, preloadS3VideoUrl, preloadS3VideosUrl, preloadVideoUrl, preloadVideosUrl, qualityService, realtimeService, refreshWorkspaceDisplayNames, resetCoreMixpanel, resetFailedUrl, resetSubscriptionManager, s3VideoPreloader, setSentryUserContext, setSentryWorkspaceContext, shouldEnableLocalDevTestLogin, shuffleArray, simulateApiDelay, skuService, startCoreSessionRecording, stopCoreSessionRecording, storeWorkspaceMapping, streamProxyConfig, subscribeWorkspaceDisplayNames, throttledReloadDashboard, toUrlFriendlyName, trackCoreEvent, trackCorePageView, transformToChartData, updateThreadTitle, upsertWorkspaceDisplayNameInCache, useAccessControl, useActiveBreaks, useActiveLineId, useAllWorkspaceMetrics, useAnalyticsConfig, useAppTimezone, useAudioService, useAuth, useAuthConfig, useAxelNotifications, useCanSaveTargets, useClipFilter, useClipTypes, useClipTypesWithCounts, useClipsInit, useCompanyClipsCost, useCompanyUsersUsage, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useDynamicShiftConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHasLineAccess, useHideMobileHeader, useHistoricWorkspaceMetrics, useHlsStream, useHlsStreamWithCropping, useHookOverride, useHourEndTimer, useHourlyTargetAchievements, useHourlyTargetMisses, useIdleTimeClipClassifications, useIdleTimeReasons, useIdleTimeVlmConfig, useKpiTrends, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineShiftConfig, useLineSupervisor, useLineWorkspaceMetrics, useLines, useMessages, useMetrics, useMobileMenu, useMonthlyTrend, useMultiLineShiftConfigs, useNavigation, useOperationalShiftKey, useOptionalSupabase, useOverrides, usePageOverride, usePrefetchClipCounts, useRealtimeLineMetrics, useRegistry, useSKUs, useSessionKeepAlive, useSessionTracking, useSessionTrackingContext, useShiftConfig, useShiftGroups, useShifts, useSubscriptionManager, useSubscriptionManagerSafe, useSupabase, useSupabaseClient, useSupervisorsByLineIds, useTargets, useTeamManagementPermissions, useTheme, useThemeConfig, useThreads, useTicketHistory, useTimezoneContext, useUserLineAccess, useUserUsage, useVideoConfig, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceHealthById, useWorkspaceHealthLastSeen, useWorkspaceHealthStatus, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, useWorkspaceUptimeTimeline, useWorkspaceVideoStreams, userService, videoPrefetchManager, videoPreloader, weeklyTopPerformerService, whatsappService, withAccessControl, withAuth, withRegistry, withTimezone, workspaceHealthService, workspaceService };