@optifye/dashboard-core 6.11.17 → 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.d.mts +14 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +389 -340
- package/dist/index.mjs +390 -341
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4010,7 +4010,8 @@ var dashboardService = {
|
|
|
4010
4010
|
enable,
|
|
4011
4011
|
monitoring_mode,
|
|
4012
4012
|
assembly,
|
|
4013
|
-
video_grid_metric_mode
|
|
4013
|
+
video_grid_metric_mode,
|
|
4014
|
+
recent_flow_window_minutes
|
|
4014
4015
|
`).eq("enable", true);
|
|
4015
4016
|
if (companyId) {
|
|
4016
4017
|
query = query.eq("company_id", companyId);
|
|
@@ -4035,7 +4036,8 @@ var dashboardService = {
|
|
|
4035
4036
|
video_grid_metric_mode: normalizeVideoGridMetricMode(
|
|
4036
4037
|
line.video_grid_metric_mode,
|
|
4037
4038
|
line.assembly ?? false
|
|
4038
|
-
)
|
|
4039
|
+
),
|
|
4040
|
+
recent_flow_window_minutes: line.recent_flow_window_minutes ?? 7
|
|
4039
4041
|
}));
|
|
4040
4042
|
return transformedLines;
|
|
4041
4043
|
} catch (err) {
|
|
@@ -4072,7 +4074,7 @@ var dashboardService = {
|
|
|
4072
4074
|
}
|
|
4073
4075
|
const lineIdsToQuery = configuredLineIds;
|
|
4074
4076
|
const [line1Result, metricsResult2] = await Promise.all([
|
|
4075
|
-
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(),
|
|
4077
|
+
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(),
|
|
4076
4078
|
supabase.from(lineMetricsTable).select("*").in("line_id", lineIdsToQuery).eq("shift_id", queryShiftId).eq("date", queryDate)
|
|
4077
4079
|
]);
|
|
4078
4080
|
if (line1Result.error) throw line1Result.error;
|
|
@@ -4128,6 +4130,7 @@ var dashboardService = {
|
|
|
4128
4130
|
date: queryDate,
|
|
4129
4131
|
shift_id: queryShiftId,
|
|
4130
4132
|
monitoring_mode: line1Data.monitoring_mode ?? void 0,
|
|
4133
|
+
recent_flow_window_minutes: line1Data.recent_flow_window_minutes ?? 7,
|
|
4131
4134
|
metrics: {
|
|
4132
4135
|
avg_efficiency: avgEfficiency,
|
|
4133
4136
|
avg_cycle_time: combinedMetricsData.avg_cycle_time / numLines,
|
|
@@ -4151,7 +4154,7 @@ var dashboardService = {
|
|
|
4151
4154
|
throw new Error("Company ID must be configured for detailed line requests.");
|
|
4152
4155
|
}
|
|
4153
4156
|
const [lineResult, metricsResult] = await Promise.all([
|
|
4154
|
-
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(),
|
|
4157
|
+
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(),
|
|
4155
4158
|
supabase.from(lineMetricsTable).select("*").eq("line_id", lineIdToQuery).eq("shift_id", queryShiftId).eq("date", queryDate)
|
|
4156
4159
|
]);
|
|
4157
4160
|
if (lineResult.error) throw lineResult.error;
|
|
@@ -4176,6 +4179,7 @@ var dashboardService = {
|
|
|
4176
4179
|
date: queryDate,
|
|
4177
4180
|
shift_id: queryShiftId,
|
|
4178
4181
|
monitoring_mode: lineData.monitoring_mode ?? void 0,
|
|
4182
|
+
recent_flow_window_minutes: lineData.recent_flow_window_minutes ?? 7,
|
|
4179
4183
|
metrics: {
|
|
4180
4184
|
avg_efficiency: metrics2?.avg_efficiency ?? 0,
|
|
4181
4185
|
avg_cycle_time: metrics2?.avg_cycle_time || 0,
|
|
@@ -8509,7 +8513,8 @@ var LinesService = class {
|
|
|
8509
8513
|
videoGridMetricMode: normalizeVideoGridMetricMode(
|
|
8510
8514
|
line.video_grid_metric_mode,
|
|
8511
8515
|
line.assembly ?? false
|
|
8512
|
-
)
|
|
8516
|
+
),
|
|
8517
|
+
recentFlowWindowMinutes: line.recent_flow_window_minutes ?? 7
|
|
8513
8518
|
}));
|
|
8514
8519
|
} catch (error) {
|
|
8515
8520
|
console.error("Error fetching lines:", error);
|
|
@@ -8557,7 +8562,8 @@ var LinesService = class {
|
|
|
8557
8562
|
videoGridMetricMode: normalizeVideoGridMetricMode(
|
|
8558
8563
|
line.video_grid_metric_mode,
|
|
8559
8564
|
line.assembly ?? false
|
|
8560
|
-
)
|
|
8565
|
+
),
|
|
8566
|
+
recentFlowWindowMinutes: line.recent_flow_window_minutes ?? 7
|
|
8561
8567
|
}));
|
|
8562
8568
|
} catch (error) {
|
|
8563
8569
|
console.error("Error fetching all lines:", error);
|
|
@@ -8614,7 +8620,8 @@ var LinesService = class {
|
|
|
8614
8620
|
videoGridMetricMode: normalizeVideoGridMetricMode(
|
|
8615
8621
|
data.video_grid_metric_mode,
|
|
8616
8622
|
data.assembly ?? false
|
|
8617
|
-
)
|
|
8623
|
+
),
|
|
8624
|
+
recentFlowWindowMinutes: data.recent_flow_window_minutes ?? 7
|
|
8618
8625
|
};
|
|
8619
8626
|
} catch (error) {
|
|
8620
8627
|
console.error("Error fetching line:", error);
|
|
@@ -13368,6 +13375,7 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
13368
13375
|
actionName: item.action_name
|
|
13369
13376
|
}),
|
|
13370
13377
|
recent_flow_percent: item.recent_flow_percent ?? null,
|
|
13378
|
+
recent_flow_window_minutes: item.recent_flow_window_minutes ?? null,
|
|
13371
13379
|
recent_flow_effective_end_at: item.recent_flow_effective_end_at ?? null,
|
|
13372
13380
|
recent_flow_computed_at: item.recent_flow_computed_at ?? null,
|
|
13373
13381
|
incoming_wip_current: item.incoming_wip_current ?? null,
|
|
@@ -32624,6 +32632,212 @@ var CycleTimeChart = React141__namespace.default.memo(CycleTimeChartComponent, (
|
|
|
32624
32632
|
});
|
|
32625
32633
|
});
|
|
32626
32634
|
CycleTimeChart.displayName = "CycleTimeChart";
|
|
32635
|
+
|
|
32636
|
+
// src/lib/utils/hourlyIdle.ts
|
|
32637
|
+
var DEFAULT_SHIFT_DURATION = 11;
|
|
32638
|
+
var normalizeMinuteSeries = (idleTimeHourly) => {
|
|
32639
|
+
if (!idleTimeHourly || typeof idleTimeHourly !== "object") {
|
|
32640
|
+
return {};
|
|
32641
|
+
}
|
|
32642
|
+
return Object.fromEntries(
|
|
32643
|
+
Object.entries(idleTimeHourly).map(([key, value]) => {
|
|
32644
|
+
if (Array.isArray(value)) {
|
|
32645
|
+
return [key, value];
|
|
32646
|
+
}
|
|
32647
|
+
if (value && Array.isArray(value.values)) {
|
|
32648
|
+
return [key, value.values];
|
|
32649
|
+
}
|
|
32650
|
+
return [key, []];
|
|
32651
|
+
})
|
|
32652
|
+
);
|
|
32653
|
+
};
|
|
32654
|
+
var parseTimeString = (timeValue) => {
|
|
32655
|
+
const [hoursPart, minutesPart] = timeValue.split(":");
|
|
32656
|
+
const hour = Number.parseInt(hoursPart, 10);
|
|
32657
|
+
const minute = Number.parseInt(minutesPart ?? "0", 10);
|
|
32658
|
+
const safeHour = Number.isFinite(hour) ? hour : 0;
|
|
32659
|
+
const safeMinute = Number.isFinite(minute) ? minute : 0;
|
|
32660
|
+
return {
|
|
32661
|
+
hour: safeHour,
|
|
32662
|
+
minute: safeMinute,
|
|
32663
|
+
decimalHour: safeHour + safeMinute / 60
|
|
32664
|
+
};
|
|
32665
|
+
};
|
|
32666
|
+
var buildShiftLayout = ({
|
|
32667
|
+
shiftStart,
|
|
32668
|
+
shiftEnd
|
|
32669
|
+
}) => {
|
|
32670
|
+
const shiftStartTime = parseTimeString(shiftStart);
|
|
32671
|
+
if (!shiftEnd) {
|
|
32672
|
+
return {
|
|
32673
|
+
shiftDuration: DEFAULT_SHIFT_DURATION,
|
|
32674
|
+
shiftStartTime,
|
|
32675
|
+
shiftEndTime: null,
|
|
32676
|
+
hasPartialLastHour: false
|
|
32677
|
+
};
|
|
32678
|
+
}
|
|
32679
|
+
const shiftEndTime = parseTimeString(shiftEnd);
|
|
32680
|
+
let duration = shiftEndTime.decimalHour - shiftStartTime.decimalHour;
|
|
32681
|
+
if (duration <= 0) {
|
|
32682
|
+
duration += 24;
|
|
32683
|
+
}
|
|
32684
|
+
const hasPartialLastHour = shiftEndTime.minute > 0 && shiftEndTime.minute < 60;
|
|
32685
|
+
const shiftDuration = hasPartialLastHour ? Math.ceil(duration) : Math.round(duration);
|
|
32686
|
+
return {
|
|
32687
|
+
shiftDuration,
|
|
32688
|
+
shiftStartTime,
|
|
32689
|
+
shiftEndTime,
|
|
32690
|
+
hasPartialLastHour
|
|
32691
|
+
};
|
|
32692
|
+
};
|
|
32693
|
+
var formatCompactTime = (hour, minute) => {
|
|
32694
|
+
const period = hour >= 12 ? "PM" : "AM";
|
|
32695
|
+
const hour12 = hour === 0 ? 12 : hour > 12 ? hour - 12 : hour;
|
|
32696
|
+
if (minute === 0) {
|
|
32697
|
+
return `${hour12}${period}`;
|
|
32698
|
+
}
|
|
32699
|
+
return `${hour12}:${minute.toString().padStart(2, "0")}${period}`;
|
|
32700
|
+
};
|
|
32701
|
+
var formatFullTime = (hour, minute) => {
|
|
32702
|
+
const period = hour >= 12 ? "PM" : "AM";
|
|
32703
|
+
const hour12 = hour === 0 ? 12 : hour > 12 ? hour - 12 : hour;
|
|
32704
|
+
return `${hour12}:${minute.toString().padStart(2, "0")} ${period}`;
|
|
32705
|
+
};
|
|
32706
|
+
var getSlotTimeBounds = (hourIndex, layout2) => {
|
|
32707
|
+
const isLastHour = hourIndex === layout2.shiftDuration - 1;
|
|
32708
|
+
const startDecimalHour = layout2.shiftStartTime.decimalHour + hourIndex;
|
|
32709
|
+
const startHour = Math.floor(startDecimalHour) % 24;
|
|
32710
|
+
const startMinute = Math.round(startDecimalHour % 1 * 60);
|
|
32711
|
+
let endHour;
|
|
32712
|
+
let endMinute;
|
|
32713
|
+
if (isLastHour && layout2.shiftEndTime) {
|
|
32714
|
+
endHour = layout2.shiftEndTime.hour;
|
|
32715
|
+
endMinute = layout2.shiftEndTime.minute;
|
|
32716
|
+
} else {
|
|
32717
|
+
const endDecimalHour = startDecimalHour + 1;
|
|
32718
|
+
endHour = Math.floor(endDecimalHour) % 24;
|
|
32719
|
+
endMinute = Math.round(endDecimalHour % 1 * 60);
|
|
32720
|
+
}
|
|
32721
|
+
return {
|
|
32722
|
+
startHour,
|
|
32723
|
+
startMinute,
|
|
32724
|
+
endHour,
|
|
32725
|
+
endMinute
|
|
32726
|
+
};
|
|
32727
|
+
};
|
|
32728
|
+
var getIdleArrayForHour = (hourIndex, idleTimeHourly, layout2) => {
|
|
32729
|
+
const actualHour = (layout2.shiftStartTime.hour + hourIndex) % 24;
|
|
32730
|
+
const startMinute = layout2.shiftStartTime.minute;
|
|
32731
|
+
if (startMinute > 0) {
|
|
32732
|
+
if (hourIndex === 0) {
|
|
32733
|
+
const firstHourData = idleTimeHourly[actualHour.toString()] || [];
|
|
32734
|
+
const nextHourData2 = idleTimeHourly[((actualHour + 1) % 24).toString()] || [];
|
|
32735
|
+
return [
|
|
32736
|
+
...firstHourData.slice(startMinute),
|
|
32737
|
+
...nextHourData2.slice(0, startMinute)
|
|
32738
|
+
];
|
|
32739
|
+
}
|
|
32740
|
+
if (hourIndex < layout2.shiftDuration - 1) {
|
|
32741
|
+
const currentHourData3 = idleTimeHourly[actualHour.toString()] || [];
|
|
32742
|
+
const nextHourData2 = idleTimeHourly[((actualHour + 1) % 24).toString()] || [];
|
|
32743
|
+
return [
|
|
32744
|
+
...currentHourData3.slice(startMinute),
|
|
32745
|
+
...nextHourData2.slice(0, startMinute)
|
|
32746
|
+
];
|
|
32747
|
+
}
|
|
32748
|
+
if (layout2.hasPartialLastHour && layout2.shiftEndTime) {
|
|
32749
|
+
const currentHourData3 = idleTimeHourly[actualHour.toString()] || [];
|
|
32750
|
+
const nextHourData2 = idleTimeHourly[((actualHour + 1) % 24).toString()] || [];
|
|
32751
|
+
return [
|
|
32752
|
+
...currentHourData3.slice(startMinute),
|
|
32753
|
+
...nextHourData2.slice(0, layout2.shiftEndTime.minute)
|
|
32754
|
+
];
|
|
32755
|
+
}
|
|
32756
|
+
const currentHourData2 = idleTimeHourly[actualHour.toString()] || [];
|
|
32757
|
+
const nextHourData = idleTimeHourly[((actualHour + 1) % 24).toString()] || [];
|
|
32758
|
+
return [
|
|
32759
|
+
...currentHourData2.slice(startMinute),
|
|
32760
|
+
...nextHourData.slice(0, startMinute)
|
|
32761
|
+
];
|
|
32762
|
+
}
|
|
32763
|
+
const currentHourData = idleTimeHourly[actualHour.toString()] || [];
|
|
32764
|
+
if (hourIndex === layout2.shiftDuration - 1 && layout2.hasPartialLastHour && layout2.shiftEndTime) {
|
|
32765
|
+
return currentHourData.slice(0, layout2.shiftEndTime.minute);
|
|
32766
|
+
}
|
|
32767
|
+
return currentHourData;
|
|
32768
|
+
};
|
|
32769
|
+
var buildHourlyIdleSlots = ({
|
|
32770
|
+
idleTimeHourly,
|
|
32771
|
+
shiftStart,
|
|
32772
|
+
shiftEnd
|
|
32773
|
+
}) => {
|
|
32774
|
+
const normalizedIdleTimeHourly = normalizeMinuteSeries(idleTimeHourly);
|
|
32775
|
+
const layout2 = buildShiftLayout({ shiftStart, shiftEnd });
|
|
32776
|
+
return Array.from({ length: layout2.shiftDuration }, (_, hourIndex) => {
|
|
32777
|
+
const { startHour, startMinute, endHour, endMinute } = getSlotTimeBounds(hourIndex, layout2);
|
|
32778
|
+
const idleArray = getIdleArrayForHour(hourIndex, normalizedIdleTimeHourly, layout2);
|
|
32779
|
+
const idleMinutes = idleArray.filter((value) => value === 1 || value === "1").length;
|
|
32780
|
+
return {
|
|
32781
|
+
hourIndex,
|
|
32782
|
+
hour: `${formatCompactTime(startHour, startMinute)}-${formatCompactTime(endHour, endMinute)}`,
|
|
32783
|
+
timeRange: `${formatFullTime(startHour, startMinute)} - ${formatFullTime(endHour, endMinute)}`,
|
|
32784
|
+
idleMinutes,
|
|
32785
|
+
idleArray
|
|
32786
|
+
};
|
|
32787
|
+
});
|
|
32788
|
+
};
|
|
32789
|
+
var formatIdleTimestamp = ({
|
|
32790
|
+
shiftStart,
|
|
32791
|
+
hourIndex,
|
|
32792
|
+
minuteIndex
|
|
32793
|
+
}) => {
|
|
32794
|
+
const shiftStartTime = parseTimeString(shiftStart);
|
|
32795
|
+
const totalMinutes = (shiftStartTime.hour + hourIndex) * 60 + shiftStartTime.minute + minuteIndex;
|
|
32796
|
+
const hour = Math.floor(totalMinutes / 60) % 24;
|
|
32797
|
+
const minute = totalMinutes % 60;
|
|
32798
|
+
return formatFullTime(hour, minute);
|
|
32799
|
+
};
|
|
32800
|
+
var getHourlyIdlePeriods = ({
|
|
32801
|
+
idleArray,
|
|
32802
|
+
shiftStart,
|
|
32803
|
+
hourIndex
|
|
32804
|
+
}) => {
|
|
32805
|
+
if (!Array.isArray(idleArray) || idleArray.length === 0) {
|
|
32806
|
+
return [];
|
|
32807
|
+
}
|
|
32808
|
+
const periods = [];
|
|
32809
|
+
let currentRange = null;
|
|
32810
|
+
idleArray.forEach((value, minuteIndex) => {
|
|
32811
|
+
if (value === 1 || value === "1") {
|
|
32812
|
+
if (!currentRange) {
|
|
32813
|
+
currentRange = { start: minuteIndex, end: minuteIndex };
|
|
32814
|
+
} else {
|
|
32815
|
+
currentRange.end = minuteIndex;
|
|
32816
|
+
}
|
|
32817
|
+
} else if (value !== "x" && currentRange) {
|
|
32818
|
+
periods.push(currentRange);
|
|
32819
|
+
currentRange = null;
|
|
32820
|
+
}
|
|
32821
|
+
});
|
|
32822
|
+
if (currentRange) {
|
|
32823
|
+
periods.push(currentRange);
|
|
32824
|
+
}
|
|
32825
|
+
return periods.map((period) => ({
|
|
32826
|
+
start: period.start,
|
|
32827
|
+
end: period.end,
|
|
32828
|
+
duration: period.end - period.start + 1,
|
|
32829
|
+
startTime: formatIdleTimestamp({
|
|
32830
|
+
shiftStart,
|
|
32831
|
+
hourIndex,
|
|
32832
|
+
minuteIndex: period.start
|
|
32833
|
+
}),
|
|
32834
|
+
endTime: formatIdleTimestamp({
|
|
32835
|
+
shiftStart,
|
|
32836
|
+
hourIndex,
|
|
32837
|
+
minuteIndex: period.end + 1
|
|
32838
|
+
})
|
|
32839
|
+
}));
|
|
32840
|
+
};
|
|
32627
32841
|
var CycleTimeOverTimeChart = ({
|
|
32628
32842
|
data,
|
|
32629
32843
|
idealCycleTime,
|
|
@@ -32633,7 +32847,8 @@ var CycleTimeOverTimeChart = ({
|
|
|
32633
32847
|
datasetKey,
|
|
32634
32848
|
className = "",
|
|
32635
32849
|
showIdleTime = false,
|
|
32636
|
-
idleTimeData = []
|
|
32850
|
+
idleTimeData = [],
|
|
32851
|
+
idleTimeSlots = []
|
|
32637
32852
|
}) => {
|
|
32638
32853
|
const MAX_DATA_POINTS = 40;
|
|
32639
32854
|
const containerRef = React141__namespace.default.useRef(null);
|
|
@@ -32736,50 +32951,60 @@ var CycleTimeOverTimeChart = ({
|
|
|
32736
32951
|
if (!visibleEntries.length) {
|
|
32737
32952
|
return null;
|
|
32738
32953
|
}
|
|
32739
|
-
|
|
32740
|
-
|
|
32741
|
-
|
|
32742
|
-
|
|
32743
|
-
|
|
32744
|
-
|
|
32745
|
-
|
|
32746
|
-
|
|
32747
|
-
|
|
32748
|
-
|
|
32749
|
-
|
|
32750
|
-
|
|
32751
|
-
|
|
32752
|
-
|
|
32753
|
-
|
|
32754
|
-
|
|
32755
|
-
|
|
32756
|
-
|
|
32757
|
-
|
|
32758
|
-
|
|
32759
|
-
|
|
32760
|
-
|
|
32761
|
-
|
|
32762
|
-
|
|
32763
|
-
|
|
32764
|
-
|
|
32765
|
-
|
|
32766
|
-
|
|
32767
|
-
|
|
32768
|
-
|
|
32769
|
-
|
|
32770
|
-
|
|
32771
|
-
|
|
32772
|
-
|
|
32773
|
-
|
|
32774
|
-
|
|
32775
|
-
|
|
32776
|
-
|
|
32777
|
-
|
|
32778
|
-
|
|
32779
|
-
|
|
32780
|
-
|
|
32781
|
-
|
|
32782
|
-
|
|
32954
|
+
const dataPoint = payload[0]?.payload || {};
|
|
32955
|
+
const idlePeriods = showIdleTime && typeof dataPoint.idleMinutes === "number" && dataPoint.idleMinutes > 0 ? getHourlyIdlePeriods({
|
|
32956
|
+
idleArray: dataPoint.idleArray,
|
|
32957
|
+
shiftStart,
|
|
32958
|
+
hourIndex: Number.isFinite(dataPoint.hourIndex) ? dataPoint.hourIndex : 0
|
|
32959
|
+
}) : [];
|
|
32960
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-xl shadow-xl border border-gray-100 p-4 min-w-[220px]", children: [
|
|
32961
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-between mb-3", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-semibold text-gray-900 text-sm", children: dataPoint.timeRange || dataPoint.tooltip || "" }) }),
|
|
32962
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
32963
|
+
visibleEntries.map((entry) => {
|
|
32964
|
+
const numericValue = getNumericValue(entry.value);
|
|
32965
|
+
if (numericValue === null) {
|
|
32966
|
+
return null;
|
|
32967
|
+
}
|
|
32968
|
+
if (entry.name === "idleMinutes") {
|
|
32969
|
+
if (!showIdleTime) return null;
|
|
32970
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-gray-100 pt-2", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
32971
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-gray-500", children: "Idle Time" }),
|
|
32972
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-semibold text-orange-600 text-sm", children: [
|
|
32973
|
+
numericValue.toFixed(0),
|
|
32974
|
+
" minutes"
|
|
32975
|
+
] })
|
|
32976
|
+
] }) }, `${entry.name}-${numericValue}`);
|
|
32977
|
+
}
|
|
32978
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
32979
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-gray-500", children: "Cycle Time" }),
|
|
32980
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-semibold text-gray-900 text-sm", children: [
|
|
32981
|
+
numericValue.toFixed(1),
|
|
32982
|
+
" seconds"
|
|
32983
|
+
] })
|
|
32984
|
+
] }, `${entry.name}-${numericValue}`);
|
|
32985
|
+
}),
|
|
32986
|
+
idlePeriods.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 bg-gray-50 rounded-lg p-2.5", children: [
|
|
32987
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium text-gray-700 text-xs mb-2", children: "Idle periods:" }),
|
|
32988
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1 max-h-32 overflow-y-auto pr-1", children: idlePeriods.map((period, index) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-gray-600 flex items-center gap-2 text-xs", children: [
|
|
32989
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-block w-1.5 h-1.5 bg-orange-400 rounded-full flex-shrink-0" }),
|
|
32990
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: period.duration === 1 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
32991
|
+
period.startTime,
|
|
32992
|
+
" (",
|
|
32993
|
+
period.duration,
|
|
32994
|
+
" min)"
|
|
32995
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
32996
|
+
period.startTime,
|
|
32997
|
+
" - ",
|
|
32998
|
+
period.endTime,
|
|
32999
|
+
" (",
|
|
33000
|
+
period.duration,
|
|
33001
|
+
" mins)"
|
|
33002
|
+
] }) })
|
|
33003
|
+
] }, index)) })
|
|
33004
|
+
] })
|
|
33005
|
+
] })
|
|
33006
|
+
] });
|
|
33007
|
+
}, [getNumericValue, shiftStart, showIdleTime]);
|
|
32783
33008
|
const renderCycleDot = React141__namespace.default.useCallback((props) => {
|
|
32784
33009
|
const { cx: cx2, cy, payload } = props;
|
|
32785
33010
|
const cycleTime = getNumericValue(payload?.cycleTime);
|
|
@@ -32848,14 +33073,18 @@ var CycleTimeOverTimeChart = ({
|
|
|
32848
33073
|
r: 4,
|
|
32849
33074
|
fill: "#f59e0b",
|
|
32850
33075
|
stroke: "#fff",
|
|
32851
|
-
strokeWidth: 1
|
|
33076
|
+
strokeWidth: 1,
|
|
33077
|
+
style: {
|
|
33078
|
+
opacity: showIdleTime ? 1 : 0,
|
|
33079
|
+
transition: "opacity 0.3s ease-in-out"
|
|
33080
|
+
}
|
|
32852
33081
|
}
|
|
32853
33082
|
);
|
|
32854
|
-
}, [getNumericValue]);
|
|
33083
|
+
}, [getNumericValue, showIdleTime]);
|
|
32855
33084
|
const renderIdleActiveDot = React141__namespace.default.useCallback((props) => {
|
|
32856
33085
|
const { cx: cx2, cy, payload } = props;
|
|
32857
33086
|
const idleMinutes = getNumericValue(payload?.idleMinutes);
|
|
32858
|
-
if (idleMinutes === null) {
|
|
33087
|
+
if (idleMinutes === null || !showIdleTime) {
|
|
32859
33088
|
return /* @__PURE__ */ jsxRuntime.jsx("g", {});
|
|
32860
33089
|
}
|
|
32861
33090
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -32869,25 +33098,40 @@ var CycleTimeOverTimeChart = ({
|
|
|
32869
33098
|
strokeWidth: 2
|
|
32870
33099
|
}
|
|
32871
33100
|
);
|
|
32872
|
-
}, [getNumericValue]);
|
|
33101
|
+
}, [getNumericValue, showIdleTime]);
|
|
32873
33102
|
const chartData = React141__namespace.default.useMemo(() => Array.from({ length: DURATION }, (_, i) => {
|
|
32874
33103
|
const cycleTime = getNumericValue(finalData[i]);
|
|
32875
|
-
const
|
|
33104
|
+
const useIdleSlots = idleTimeSlots.length > 0;
|
|
33105
|
+
const idleSlot = useIdleSlots ? idleTimeSlots[i] ?? null : null;
|
|
33106
|
+
const idleMinutes = useIdleSlots ? idleSlot?.idleMinutes ?? null : getNumericValue(idleTimeData[i]);
|
|
32876
33107
|
return {
|
|
32877
33108
|
timeIndex: i,
|
|
32878
33109
|
label: formatTimeLabel(i),
|
|
32879
|
-
tooltip: formatTooltipTime(i),
|
|
33110
|
+
tooltip: idleSlot?.timeRange || formatTooltipTime(i),
|
|
33111
|
+
timeRange: idleSlot?.timeRange || formatTooltipTime(i),
|
|
33112
|
+
hourIndex: idleSlot?.hourIndex ?? i,
|
|
32880
33113
|
cycleTime,
|
|
32881
33114
|
idleMinutes,
|
|
33115
|
+
idleArray: idleSlot?.idleArray || [],
|
|
32882
33116
|
color: cycleTime !== null && cycleTime <= idealCycleTime ? "#00AB45" : "#E34329"
|
|
32883
33117
|
};
|
|
32884
|
-
}), [DURATION, finalData,
|
|
33118
|
+
}), [DURATION, finalData, idleTimeData, idleTimeSlots, idealCycleTime, getNumericValue]);
|
|
32885
33119
|
const renderLegend = () => {
|
|
32886
|
-
|
|
32887
|
-
|
|
32888
|
-
|
|
32889
|
-
|
|
32890
|
-
|
|
33120
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
33121
|
+
"div",
|
|
33122
|
+
{
|
|
33123
|
+
className: "flex items-center justify-start text-[10px] font-bold text-gray-500 mb-6 tracking-[0.05em] gap-5",
|
|
33124
|
+
style: {
|
|
33125
|
+
opacity: showIdleTime ? 1 : 0,
|
|
33126
|
+
pointerEvents: showIdleTime ? "auto" : "none",
|
|
33127
|
+
transition: "opacity 0.3s ease-in-out"
|
|
33128
|
+
},
|
|
33129
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
33130
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-2.5 h-2.5 rounded-full bg-[#f59e0b]" }),
|
|
33131
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Idle Time (min)" })
|
|
33132
|
+
] })
|
|
33133
|
+
}
|
|
33134
|
+
);
|
|
32891
33135
|
};
|
|
32892
33136
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
32893
33137
|
"div",
|
|
@@ -32958,7 +33202,7 @@ var CycleTimeOverTimeChart = ({
|
|
|
32958
33202
|
}
|
|
32959
33203
|
}
|
|
32960
33204
|
),
|
|
32961
|
-
|
|
33205
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
32962
33206
|
recharts.YAxis,
|
|
32963
33207
|
{
|
|
32964
33208
|
yAxisId: "idle",
|
|
@@ -32967,7 +33211,11 @@ var CycleTimeOverTimeChart = ({
|
|
|
32967
33211
|
width: 35,
|
|
32968
33212
|
domain: [0, 60],
|
|
32969
33213
|
tickFormatter: (value) => `${value}m`,
|
|
32970
|
-
tick: {
|
|
33214
|
+
tick: {
|
|
33215
|
+
fontSize: 11,
|
|
33216
|
+
fill: showIdleTime ? "#f59e0b" : "transparent",
|
|
33217
|
+
style: { transition: "fill 0.3s ease-in-out" }
|
|
33218
|
+
},
|
|
32971
33219
|
axisLine: false,
|
|
32972
33220
|
tickLine: false
|
|
32973
33221
|
}
|
|
@@ -33015,7 +33263,7 @@ var CycleTimeOverTimeChart = ({
|
|
|
33015
33263
|
},
|
|
33016
33264
|
`${effectiveDatasetKey}:cycle`
|
|
33017
33265
|
),
|
|
33018
|
-
|
|
33266
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
33019
33267
|
recharts.Line,
|
|
33020
33268
|
{
|
|
33021
33269
|
type: "monotone",
|
|
@@ -33030,7 +33278,11 @@ var CycleTimeOverTimeChart = ({
|
|
|
33030
33278
|
isAnimationActive: true,
|
|
33031
33279
|
animationBegin: 300,
|
|
33032
33280
|
animationDuration: 1500,
|
|
33033
|
-
animationEasing: "ease-out"
|
|
33281
|
+
animationEasing: "ease-out",
|
|
33282
|
+
style: {
|
|
33283
|
+
strokeOpacity: showIdleTime ? 1 : 0,
|
|
33284
|
+
transition: "stroke-opacity 0.3s ease-in-out"
|
|
33285
|
+
}
|
|
33034
33286
|
},
|
|
33035
33287
|
`${effectiveDatasetKey}:idle`
|
|
33036
33288
|
)
|
|
@@ -33185,89 +33437,20 @@ var HourlyOutputChartComponent = ({
|
|
|
33185
33437
|
shiftEnd,
|
|
33186
33438
|
showIdleTime = false,
|
|
33187
33439
|
idleTimeHourly,
|
|
33188
|
-
idleTimeClips,
|
|
33189
|
-
idleTimeClipClassifications,
|
|
33190
|
-
shiftDate,
|
|
33191
|
-
timezone,
|
|
33192
33440
|
className = ""
|
|
33193
33441
|
}) => {
|
|
33194
33442
|
const containerRef = React141__namespace.default.useRef(null);
|
|
33195
33443
|
const [containerReady, setContainerReady] = React141__namespace.default.useState(false);
|
|
33196
33444
|
const [containerWidth, setContainerWidth] = React141__namespace.default.useState(0);
|
|
33197
|
-
const
|
|
33198
|
-
|
|
33199
|
-
|
|
33200
|
-
const minute = parseInt(minutes || "0");
|
|
33201
|
-
const decimalHour = hour + minute / 60;
|
|
33202
|
-
return { hour, minute, decimalHour };
|
|
33203
|
-
};
|
|
33204
|
-
const shiftStartTime = getTimeFromTimeString2(shiftStart);
|
|
33205
|
-
React141__namespace.default.useMemo(() => {
|
|
33206
|
-
if (!shiftDate || !timezone) return null;
|
|
33207
|
-
const hour = shiftStartTime.hour.toString().padStart(2, "0");
|
|
33208
|
-
const minute = shiftStartTime.minute.toString().padStart(2, "0");
|
|
33209
|
-
return dateFnsTz.fromZonedTime(`${shiftDate}T${hour}:${minute}:00`, timezone);
|
|
33210
|
-
}, [shiftDate, timezone, shiftStartTime.hour, shiftStartTime.minute]);
|
|
33211
|
-
const idleClipRanges = React141__namespace.default.useMemo(() => {
|
|
33212
|
-
if (!idleTimeClips || idleTimeClips.length === 0) return [];
|
|
33213
|
-
return idleTimeClips.map((clip) => ({
|
|
33214
|
-
id: clip.id,
|
|
33215
|
-
start: clip.idle_start_time ? new Date(clip.idle_start_time) : null,
|
|
33216
|
-
end: clip.idle_end_time ? new Date(clip.idle_end_time) : null
|
|
33217
|
-
})).filter((clip) => clip.start && clip.end);
|
|
33218
|
-
}, [idleTimeClips]);
|
|
33219
|
-
React141__namespace.default.useCallback((rangeStart, rangeEnd) => {
|
|
33220
|
-
if (!rangeStart || !rangeEnd || idleClipRanges.length === 0) {
|
|
33221
|
-
return "Reason unavailable";
|
|
33222
|
-
}
|
|
33223
|
-
const matchingClip = idleClipRanges.find((clip) => rangeStart >= clip.start && rangeEnd <= clip.end) || idleClipRanges.find((clip) => rangeStart < clip.end && rangeEnd > clip.start);
|
|
33224
|
-
if (!matchingClip) {
|
|
33225
|
-
return "Reason unavailable";
|
|
33226
|
-
}
|
|
33227
|
-
const classification = idleTimeClipClassifications?.[matchingClip.id];
|
|
33228
|
-
if (!classification || classification.status === "processing") {
|
|
33229
|
-
return "Analyzing...";
|
|
33230
|
-
}
|
|
33231
|
-
if (!classification.label) {
|
|
33232
|
-
return "Reason unavailable";
|
|
33233
|
-
}
|
|
33234
|
-
return classification.displayName || classification.label.replace(/_/g, " ");
|
|
33235
|
-
}, [idleClipRanges, idleTimeClipClassifications]);
|
|
33236
|
-
const { shiftDuration, shiftEndTime, hasPartialLastHour } = React141__namespace.default.useMemo(() => {
|
|
33237
|
-
console.log("[HourlyOutputChart] Calculating shift duration with:", {
|
|
33445
|
+
const idleSlots = React141__namespace.default.useMemo(
|
|
33446
|
+
() => buildHourlyIdleSlots({
|
|
33447
|
+
idleTimeHourly,
|
|
33238
33448
|
shiftStart,
|
|
33239
|
-
shiftEnd
|
|
33240
|
-
|
|
33241
|
-
|
|
33242
|
-
|
|
33243
|
-
|
|
33244
|
-
return {
|
|
33245
|
-
shiftDuration: 11,
|
|
33246
|
-
shiftEndTime: null,
|
|
33247
|
-
hasPartialLastHour: false
|
|
33248
|
-
};
|
|
33249
|
-
}
|
|
33250
|
-
const endTime = getTimeFromTimeString2(shiftEnd);
|
|
33251
|
-
let duration = endTime.decimalHour - shiftStartTime.decimalHour;
|
|
33252
|
-
if (duration <= 0) {
|
|
33253
|
-
duration += 24;
|
|
33254
|
-
}
|
|
33255
|
-
const hasPartial = endTime.minute > 0 && endTime.minute < 60;
|
|
33256
|
-
const hourCount = hasPartial ? Math.ceil(duration) : Math.round(duration);
|
|
33257
|
-
console.log("[HourlyOutputChart] Shift calculation results:", {
|
|
33258
|
-
endTime,
|
|
33259
|
-
duration,
|
|
33260
|
-
hasPartial,
|
|
33261
|
-
hourCount
|
|
33262
|
-
});
|
|
33263
|
-
return {
|
|
33264
|
-
shiftDuration: hourCount,
|
|
33265
|
-
shiftEndTime: endTime,
|
|
33266
|
-
hasPartialLastHour: hasPartial
|
|
33267
|
-
};
|
|
33268
|
-
}, [shiftEnd, shiftStartTime.decimalHour]);
|
|
33269
|
-
const SHIFT_DURATION = shiftDuration;
|
|
33270
|
-
shiftEndTime ? shiftEndTime.hour : (shiftStartTime.hour + SHIFT_DURATION) % 24;
|
|
33449
|
+
shiftEnd
|
|
33450
|
+
}),
|
|
33451
|
+
[idleTimeHourly, shiftStart, shiftEnd]
|
|
33452
|
+
);
|
|
33453
|
+
const SHIFT_DURATION = idleSlots.length;
|
|
33271
33454
|
const [animatedData, setAnimatedData] = React141__namespace.default.useState(
|
|
33272
33455
|
() => Array(SHIFT_DURATION).fill(0)
|
|
33273
33456
|
);
|
|
@@ -33390,121 +33573,22 @@ var HourlyOutputChartComponent = ({
|
|
|
33390
33573
|
}
|
|
33391
33574
|
return { interval: 0, angle: -30, height: 64, tickFont: 9, tickMargin: 6 };
|
|
33392
33575
|
}, [containerWidth]);
|
|
33393
|
-
const formatHour = React141__namespace.default.useCallback((hourIndex) => {
|
|
33394
|
-
const isLastHour = hourIndex === SHIFT_DURATION - 1;
|
|
33395
|
-
const startDecimalHour = shiftStartTime.decimalHour + hourIndex;
|
|
33396
|
-
const startHour = Math.floor(startDecimalHour) % 24;
|
|
33397
|
-
const startMinute = Math.round(startDecimalHour % 1 * 60);
|
|
33398
|
-
let endHour, endMinute;
|
|
33399
|
-
if (isLastHour && shiftEndTime) {
|
|
33400
|
-
endHour = shiftEndTime.hour;
|
|
33401
|
-
endMinute = shiftEndTime.minute;
|
|
33402
|
-
} else {
|
|
33403
|
-
const endDecimalHour = startDecimalHour + 1;
|
|
33404
|
-
endHour = Math.floor(endDecimalHour) % 24;
|
|
33405
|
-
endMinute = Math.round(endDecimalHour % 1 * 60);
|
|
33406
|
-
}
|
|
33407
|
-
const formatTime5 = (h, m) => {
|
|
33408
|
-
const period = h >= 12 ? "PM" : "AM";
|
|
33409
|
-
const hour12 = h === 0 ? 12 : h > 12 ? h - 12 : h;
|
|
33410
|
-
if (m === 0) {
|
|
33411
|
-
return `${hour12}${period}`;
|
|
33412
|
-
}
|
|
33413
|
-
return `${hour12}:${m.toString().padStart(2, "0")}${period}`;
|
|
33414
|
-
};
|
|
33415
|
-
return `${formatTime5(startHour, startMinute)}-${formatTime5(endHour, endMinute)}`;
|
|
33416
|
-
}, [shiftStartTime.decimalHour, SHIFT_DURATION, shiftEndTime]);
|
|
33417
|
-
const formatTimeRange2 = React141__namespace.default.useCallback((hourIndex) => {
|
|
33418
|
-
const isLastHour = hourIndex === SHIFT_DURATION - 1;
|
|
33419
|
-
const startDecimalHour = shiftStartTime.decimalHour + hourIndex;
|
|
33420
|
-
const startHour = Math.floor(startDecimalHour) % 24;
|
|
33421
|
-
const startMinute = Math.round(startDecimalHour % 1 * 60);
|
|
33422
|
-
let endHour, endMinute;
|
|
33423
|
-
if (isLastHour && shiftEndTime) {
|
|
33424
|
-
endHour = shiftEndTime.hour;
|
|
33425
|
-
endMinute = shiftEndTime.minute;
|
|
33426
|
-
} else {
|
|
33427
|
-
const endDecimalHour = startDecimalHour + 1;
|
|
33428
|
-
endHour = Math.floor(endDecimalHour) % 24;
|
|
33429
|
-
endMinute = Math.round(endDecimalHour % 1 * 60);
|
|
33430
|
-
}
|
|
33431
|
-
const formatTime5 = (h, m) => {
|
|
33432
|
-
const period = h >= 12 ? "PM" : "AM";
|
|
33433
|
-
const hour12 = h === 0 ? 12 : h > 12 ? h - 12 : h;
|
|
33434
|
-
return `${hour12}:${m.toString().padStart(2, "0")} ${period}`;
|
|
33435
|
-
};
|
|
33436
|
-
return `${formatTime5(startHour, startMinute)} - ${formatTime5(endHour, endMinute)}`;
|
|
33437
|
-
}, [shiftStartTime.decimalHour, SHIFT_DURATION, shiftEndTime]);
|
|
33438
33576
|
const chartData = React141__namespace.default.useMemo(() => {
|
|
33439
33577
|
return Array.from({ length: SHIFT_DURATION }, (_, i) => {
|
|
33440
|
-
const
|
|
33441
|
-
const startMinute = shiftStartTime.minute;
|
|
33442
|
-
let idleArray = [];
|
|
33443
|
-
let idleMinutes = 0;
|
|
33444
|
-
if (idleTimeHourly) {
|
|
33445
|
-
if (startMinute > 0) {
|
|
33446
|
-
if (i === 0) {
|
|
33447
|
-
const firstHourData = idleTimeHourly[actualHour.toString()] || [];
|
|
33448
|
-
const nextHour = (actualHour + 1) % 24;
|
|
33449
|
-
const nextHourData = idleTimeHourly[nextHour.toString()] || [];
|
|
33450
|
-
idleArray = [
|
|
33451
|
-
...firstHourData.slice(startMinute) || [],
|
|
33452
|
-
...nextHourData.slice(0, startMinute) || []
|
|
33453
|
-
];
|
|
33454
|
-
} else if (i < SHIFT_DURATION - 1) {
|
|
33455
|
-
const currentHourData = idleTimeHourly[actualHour.toString()] || [];
|
|
33456
|
-
const nextHour = (actualHour + 1) % 24;
|
|
33457
|
-
const nextHourData = idleTimeHourly[nextHour.toString()] || [];
|
|
33458
|
-
idleArray = [
|
|
33459
|
-
...currentHourData.slice(startMinute) || [],
|
|
33460
|
-
...nextHourData.slice(0, startMinute) || []
|
|
33461
|
-
];
|
|
33462
|
-
} else {
|
|
33463
|
-
const hasPartialLastHour2 = shiftEndTime && shiftEndTime.minute > 0 && shiftEndTime.minute < 60;
|
|
33464
|
-
if (hasPartialLastHour2) {
|
|
33465
|
-
const currentHourData = idleTimeHourly[actualHour.toString()] || [];
|
|
33466
|
-
const nextHour = (actualHour + 1) % 24;
|
|
33467
|
-
const nextHourData = idleTimeHourly[nextHour.toString()] || [];
|
|
33468
|
-
if (startMinute > 0) {
|
|
33469
|
-
const firstPart = currentHourData.slice(startMinute) || [];
|
|
33470
|
-
const secondPart = nextHourData.slice(0, shiftEndTime.minute) || [];
|
|
33471
|
-
idleArray = [...firstPart, ...secondPart];
|
|
33472
|
-
} else {
|
|
33473
|
-
idleArray = currentHourData.slice(0, shiftEndTime.minute) || [];
|
|
33474
|
-
}
|
|
33475
|
-
} else {
|
|
33476
|
-
const currentHourData = idleTimeHourly[actualHour.toString()] || [];
|
|
33477
|
-
const nextHour = (actualHour + 1) % 24;
|
|
33478
|
-
const nextHourData = idleTimeHourly[nextHour.toString()] || [];
|
|
33479
|
-
idleArray = [
|
|
33480
|
-
...currentHourData.slice(startMinute) || [],
|
|
33481
|
-
...nextHourData.slice(0, startMinute) || []
|
|
33482
|
-
];
|
|
33483
|
-
}
|
|
33484
|
-
}
|
|
33485
|
-
} else {
|
|
33486
|
-
const currentHourData = idleTimeHourly[actualHour.toString()] || [];
|
|
33487
|
-
if (i === SHIFT_DURATION - 1 && shiftEndTime && shiftEndTime.minute > 0 && shiftEndTime.minute < 60) {
|
|
33488
|
-
idleArray = currentHourData.slice(0, shiftEndTime.minute) || [];
|
|
33489
|
-
} else {
|
|
33490
|
-
idleArray = currentHourData || [];
|
|
33491
|
-
}
|
|
33492
|
-
}
|
|
33493
|
-
}
|
|
33494
|
-
idleMinutes = idleArray.filter((val) => val === "1" || val === 1).length;
|
|
33578
|
+
const idleSlot = idleSlots[i];
|
|
33495
33579
|
return {
|
|
33496
|
-
hourIndex: i,
|
|
33497
|
-
hour:
|
|
33498
|
-
timeRange:
|
|
33580
|
+
hourIndex: idleSlot?.hourIndex ?? i,
|
|
33581
|
+
hour: idleSlot?.hour || "",
|
|
33582
|
+
timeRange: idleSlot?.timeRange || "",
|
|
33499
33583
|
output: animatedData[i] || 0,
|
|
33500
33584
|
originalOutput: data[i] || 0,
|
|
33501
33585
|
// Keep original data for labels
|
|
33502
33586
|
color: (animatedData[i] || 0) >= Math.round(pphThreshold) ? "#00AB45" : "#E34329",
|
|
33503
|
-
idleMinutes,
|
|
33504
|
-
idleArray
|
|
33587
|
+
idleMinutes: idleSlot?.idleMinutes || 0,
|
|
33588
|
+
idleArray: idleSlot?.idleArray || []
|
|
33505
33589
|
};
|
|
33506
33590
|
});
|
|
33507
|
-
}, [animatedData, data, pphThreshold,
|
|
33591
|
+
}, [animatedData, data, pphThreshold, idleSlots, SHIFT_DURATION]);
|
|
33508
33592
|
const IdleBar = React141__namespace.default.useMemo(() => {
|
|
33509
33593
|
if (!idleBarState.visible) return null;
|
|
33510
33594
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -33666,36 +33750,11 @@ var HourlyOutputChartComponent = ({
|
|
|
33666
33750
|
content: (props) => {
|
|
33667
33751
|
if (!props.active || !props.payload || props.payload.length === 0) return null;
|
|
33668
33752
|
const data2 = props.payload[0].payload;
|
|
33669
|
-
const
|
|
33670
|
-
|
|
33671
|
-
|
|
33672
|
-
data2.
|
|
33673
|
-
|
|
33674
|
-
if (!currentRange) {
|
|
33675
|
-
currentRange = { start: idx, end: idx };
|
|
33676
|
-
} else {
|
|
33677
|
-
currentRange.end = idx;
|
|
33678
|
-
}
|
|
33679
|
-
} else if (val !== "x" && currentRange) {
|
|
33680
|
-
idleRanges.push(currentRange);
|
|
33681
|
-
currentRange = null;
|
|
33682
|
-
}
|
|
33683
|
-
});
|
|
33684
|
-
if (currentRange) {
|
|
33685
|
-
idleRanges.push(currentRange);
|
|
33686
|
-
}
|
|
33687
|
-
}
|
|
33688
|
-
const formatIdleTimestamp = (minuteIdx) => {
|
|
33689
|
-
const fallbackIndex = chartData.findIndex((item) => item.timeRange === data2.timeRange);
|
|
33690
|
-
const hourOffset = Number.isFinite(data2.hourIndex) ? data2.hourIndex : fallbackIndex;
|
|
33691
|
-
const safeHourOffset = hourOffset >= 0 ? hourOffset : 0;
|
|
33692
|
-
const totalMinutes = (shiftStartTime.hour + safeHourOffset) * 60 + shiftStartTime.minute + minuteIdx;
|
|
33693
|
-
const hour = Math.floor(totalMinutes / 60) % 24;
|
|
33694
|
-
const minute = totalMinutes % 60;
|
|
33695
|
-
const period = hour >= 12 ? "PM" : "AM";
|
|
33696
|
-
const hour12 = hour === 0 ? 12 : hour > 12 ? hour - 12 : hour;
|
|
33697
|
-
return `${hour12}:${minute.toString().padStart(2, "0")} ${period}`;
|
|
33698
|
-
};
|
|
33753
|
+
const idlePeriods = showIdleTime ? getHourlyIdlePeriods({
|
|
33754
|
+
idleArray: data2.idleArray,
|
|
33755
|
+
shiftStart,
|
|
33756
|
+
hourIndex: Number.isFinite(data2.hourIndex) ? data2.hourIndex : 0
|
|
33757
|
+
}) : [];
|
|
33699
33758
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-xl shadow-xl border border-gray-100 p-4 min-w-[220px]", children: [
|
|
33700
33759
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-between mb-3", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-semibold text-gray-900 text-sm", children: data2.timeRange }) }),
|
|
33701
33760
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
@@ -33714,27 +33773,22 @@ var HourlyOutputChartComponent = ({
|
|
|
33714
33773
|
" minutes"
|
|
33715
33774
|
] })
|
|
33716
33775
|
] }) }),
|
|
33717
|
-
|
|
33776
|
+
idlePeriods.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 bg-gray-50 rounded-lg p-2.5", children: [
|
|
33718
33777
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium text-gray-700 text-xs mb-2", children: "Idle periods:" }),
|
|
33719
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1 max-h-32 overflow-y-auto pr-1", children:
|
|
33720
|
-
const duration = range.end - range.start + 1;
|
|
33721
|
-
const startTime = formatIdleTimestamp(range.start);
|
|
33722
|
-
const endTime = formatIdleTimestamp(range.end + 1);
|
|
33723
|
-
const fallbackIndex = chartData.findIndex((item) => item.timeRange === data2.timeRange);
|
|
33724
|
-
Number.isFinite(data2.hourIndex) ? data2.hourIndex : fallbackIndex;
|
|
33778
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1 max-h-32 overflow-y-auto pr-1", children: idlePeriods.map((period, index) => {
|
|
33725
33779
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-gray-600 flex items-center gap-2 text-xs", children: [
|
|
33726
33780
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-block w-1.5 h-1.5 bg-orange-400 rounded-full flex-shrink-0" }),
|
|
33727
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: duration === 1 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
33728
|
-
startTime,
|
|
33781
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: period.duration === 1 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
33782
|
+
period.startTime,
|
|
33729
33783
|
" (",
|
|
33730
|
-
duration,
|
|
33784
|
+
period.duration,
|
|
33731
33785
|
" min)"
|
|
33732
33786
|
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
33733
|
-
startTime,
|
|
33787
|
+
period.startTime,
|
|
33734
33788
|
" - ",
|
|
33735
|
-
endTime,
|
|
33789
|
+
period.endTime,
|
|
33736
33790
|
" (",
|
|
33737
|
-
duration,
|
|
33791
|
+
period.duration,
|
|
33738
33792
|
" mins)"
|
|
33739
33793
|
] }) })
|
|
33740
33794
|
] }, index);
|
|
@@ -33889,9 +33943,8 @@ var HourlyOutputChart = React141__namespace.default.memo(HourlyOutputChartCompon
|
|
|
33889
33943
|
HourlyOutputChart.displayName = "HourlyOutputChart";
|
|
33890
33944
|
|
|
33891
33945
|
// src/components/dashboard/grid/videoGridMetricUtils.ts
|
|
33892
|
-
var VIDEO_GRID_LEGEND_LABEL = "7 Minute Efficiency";
|
|
33893
33946
|
var MAP_GRID_LEGEND_LABEL = "Efficiency";
|
|
33894
|
-
var MIXED_VIDEO_GRID_LEGEND_LABEL = "Efficiency";
|
|
33947
|
+
var MIXED_VIDEO_GRID_LEGEND_LABEL = "Flow Efficiency";
|
|
33895
33948
|
var isFiniteNumber = (value) => typeof value === "number" && Number.isFinite(value);
|
|
33896
33949
|
var isVideoGridRecentFlowEnabled = (workspace) => isRecentFlowVideoGridMetricMode(
|
|
33897
33950
|
workspace.video_grid_metric_mode,
|
|
@@ -33990,8 +34043,15 @@ var getVideoGridLegendLabel = (workspaces) => {
|
|
|
33990
34043
|
if (recentFlowEnabledCount === 0) {
|
|
33991
34044
|
return MAP_GRID_LEGEND_LABEL;
|
|
33992
34045
|
}
|
|
34046
|
+
const recentFlowWindows = new Set(
|
|
34047
|
+
visibleWorkspaces.filter(isVideoGridRecentFlowEnabled).map((workspace) => workspace.recent_flow_window_minutes ?? 7).filter((value) => typeof value === "number" && Number.isFinite(value))
|
|
34048
|
+
);
|
|
33993
34049
|
if (recentFlowEnabledCount === visibleWorkspaces.length) {
|
|
33994
|
-
|
|
34050
|
+
if (recentFlowWindows.size === 1) {
|
|
34051
|
+
const [windowMinutes] = Array.from(recentFlowWindows);
|
|
34052
|
+
return `${windowMinutes} Minute Efficiency`;
|
|
34053
|
+
}
|
|
34054
|
+
return MIXED_VIDEO_GRID_LEGEND_LABEL;
|
|
33995
34055
|
}
|
|
33996
34056
|
return MIXED_VIDEO_GRID_LEGEND_LABEL;
|
|
33997
34057
|
};
|
|
@@ -35938,7 +35998,7 @@ var HourlyUptimeChartComponent = ({
|
|
|
35938
35998
|
idleRanges.push(currentRange);
|
|
35939
35999
|
}
|
|
35940
36000
|
}
|
|
35941
|
-
const
|
|
36001
|
+
const formatIdleTimestamp2 = (minuteIdx) => {
|
|
35942
36002
|
const totalMinutes = (shiftStartTime.hour + data.hourIndex) * 60 + shiftStartTime.minute + minuteIdx;
|
|
35943
36003
|
const hour = Math.floor(totalMinutes / 60) % 24;
|
|
35944
36004
|
const minute = totalMinutes % 60;
|
|
@@ -35968,8 +36028,8 @@ var HourlyUptimeChartComponent = ({
|
|
|
35968
36028
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium text-gray-700 text-xs mb-2", children: "Idle periods:" }),
|
|
35969
36029
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1 max-h-32 overflow-y-auto pr-1", children: idleRanges.map((range, index) => {
|
|
35970
36030
|
const duration = range.end - range.start + 1;
|
|
35971
|
-
const startTime =
|
|
35972
|
-
const endTime =
|
|
36031
|
+
const startTime = formatIdleTimestamp2(range.start);
|
|
36032
|
+
const endTime = formatIdleTimestamp2(range.end + 1);
|
|
35973
36033
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-gray-600 flex items-center gap-2 text-xs", children: [
|
|
35974
36034
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-block w-1.5 h-1.5 bg-orange-400 rounded-full flex-shrink-0" }),
|
|
35975
36035
|
/* @__PURE__ */ jsxRuntime.jsx("span", { children: duration === 1 ? `${startTime} (${duration} min)` : `${startTime} - ${endTime} (${duration} mins)` })
|
|
@@ -69216,56 +69276,43 @@ var WorkspaceDetailView = ({
|
|
|
69216
69276
|
const canToggleChartIdleTime = !isUptimeMode && !shouldShowCycleTimeLoadingState && !shouldShowCycleTimeUnavailableState;
|
|
69217
69277
|
const idleClipDate = date || workspace?.date || calculatedOperationalDate || getOperationalDate(timezone);
|
|
69218
69278
|
const idleClipShiftId = parsedShiftId ?? workspace?.shift_id;
|
|
69219
|
-
const
|
|
69220
|
-
|
|
69221
|
-
|
|
69222
|
-
|
|
69223
|
-
|
|
69224
|
-
|
|
69225
|
-
|
|
69226
|
-
|
|
69227
|
-
|
|
69228
|
-
|
|
69229
|
-
|
|
69230
|
-
|
|
69231
|
-
|
|
69232
|
-
|
|
69233
|
-
|
|
69234
|
-
|
|
69235
|
-
|
|
69236
|
-
if (endSlotMins > endTotal) endSlotMins = endTotal;
|
|
69237
|
-
let idleCount = 0;
|
|
69238
|
-
for (let m = startSlotMins; m < endSlotMins; m++) {
|
|
69239
|
-
const hourKey = Math.floor(m / 60) % 24;
|
|
69240
|
-
const minuteKey = m % 60;
|
|
69241
|
-
const hourData = idleTimeHourlyObj[hourKey.toString()] || [];
|
|
69242
|
-
if (Array.isArray(hourData)) {
|
|
69243
|
-
const val = hourData[minuteKey];
|
|
69244
|
-
if (val === 1 || val === "1") {
|
|
69245
|
-
idleCount++;
|
|
69246
|
-
}
|
|
69247
|
-
}
|
|
69248
|
-
}
|
|
69249
|
-
result[i] = idleCount;
|
|
69250
|
-
}
|
|
69251
|
-
return result;
|
|
69252
|
-
}, [shouldShowCycleTimeChart, workspace?.idle_time_hourly, workspace?.shift_start, workspace?.shift_end]);
|
|
69279
|
+
const rawHourlyIdleSlots = React141.useMemo(
|
|
69280
|
+
() => !shouldShowCycleTimeChart || !authoritativeCycleMetrics?.shift_start ? [] : buildHourlyIdleSlots({
|
|
69281
|
+
idleTimeHourly: authoritativeCycleMetrics.idle_time_hourly,
|
|
69282
|
+
shiftStart: authoritativeCycleMetrics.shift_start,
|
|
69283
|
+
shiftEnd: authoritativeCycleMetrics.shift_end
|
|
69284
|
+
}),
|
|
69285
|
+
[
|
|
69286
|
+
shouldShowCycleTimeChart,
|
|
69287
|
+
authoritativeCycleMetrics?.idle_time_hourly,
|
|
69288
|
+
authoritativeCycleMetrics?.shift_start,
|
|
69289
|
+
authoritativeCycleMetrics?.shift_end
|
|
69290
|
+
]
|
|
69291
|
+
);
|
|
69292
|
+
const rawHourlyIdleMinutes = React141.useMemo(
|
|
69293
|
+
() => rawHourlyIdleSlots.map((slot) => slot.idleMinutes),
|
|
69294
|
+
[rawHourlyIdleSlots]
|
|
69295
|
+
);
|
|
69253
69296
|
const hourlyIdleMinutes = React141.useMemo(
|
|
69254
69297
|
() => maskFutureHourlySeries({
|
|
69255
69298
|
data: rawHourlyIdleMinutes,
|
|
69256
|
-
shiftStart:
|
|
69257
|
-
shiftEnd:
|
|
69299
|
+
shiftStart: authoritativeCycleMetrics?.shift_start,
|
|
69300
|
+
shiftEnd: authoritativeCycleMetrics?.shift_end,
|
|
69258
69301
|
shiftDate: idleClipDate,
|
|
69259
69302
|
timezone: effectiveCycleTimeTimezone
|
|
69260
69303
|
}),
|
|
69261
69304
|
[
|
|
69262
69305
|
rawHourlyIdleMinutes,
|
|
69263
|
-
|
|
69264
|
-
|
|
69306
|
+
authoritativeCycleMetrics?.shift_start,
|
|
69307
|
+
authoritativeCycleMetrics?.shift_end,
|
|
69265
69308
|
idleClipDate,
|
|
69266
69309
|
effectiveCycleTimeTimezone
|
|
69267
69310
|
]
|
|
69268
69311
|
);
|
|
69312
|
+
const hourlyIdleSlots = React141.useMemo(
|
|
69313
|
+
() => rawHourlyIdleSlots.map((slot, index) => hourlyIdleMinutes[index] === null ? null : slot),
|
|
69314
|
+
[rawHourlyIdleSlots, hourlyIdleMinutes]
|
|
69315
|
+
);
|
|
69269
69316
|
const cycleTimeUnavailableView = React141.useMemo(() => /* @__PURE__ */ jsxRuntime.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: [
|
|
69270
69317
|
/* @__PURE__ */ jsxRuntime.jsx("h4", { className: "text-base font-semibold text-amber-900", children: "Cycle data unavailable" }),
|
|
69271
69318
|
/* @__PURE__ */ jsxRuntime.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." }),
|
|
@@ -69821,7 +69868,8 @@ var WorkspaceDetailView = ({
|
|
|
69821
69868
|
xAxisMode: "hourly",
|
|
69822
69869
|
datasetKey: cycleTimeDatasetKey,
|
|
69823
69870
|
showIdleTime: showChartIdleTime,
|
|
69824
|
-
idleTimeData: hourlyIdleMinutes
|
|
69871
|
+
idleTimeData: hourlyIdleMinutes,
|
|
69872
|
+
idleTimeSlots: hourlyIdleSlots
|
|
69825
69873
|
}
|
|
69826
69874
|
) : null : /* @__PURE__ */ jsxRuntime.jsx(
|
|
69827
69875
|
HourlyOutputChart2,
|
|
@@ -69950,7 +69998,8 @@ var WorkspaceDetailView = ({
|
|
|
69950
69998
|
xAxisMode: "hourly",
|
|
69951
69999
|
datasetKey: cycleTimeDatasetKey,
|
|
69952
70000
|
showIdleTime: showChartIdleTime,
|
|
69953
|
-
idleTimeData: hourlyIdleMinutes
|
|
70001
|
+
idleTimeData: hourlyIdleMinutes,
|
|
70002
|
+
idleTimeSlots: hourlyIdleSlots
|
|
69954
70003
|
}
|
|
69955
70004
|
) : null : /* @__PURE__ */ jsxRuntime.jsx(
|
|
69956
70005
|
HourlyOutputChart2,
|