@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.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 {
|
|
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';
|
|
@@ -3981,7 +3981,8 @@ var dashboardService = {
|
|
|
3981
3981
|
enable,
|
|
3982
3982
|
monitoring_mode,
|
|
3983
3983
|
assembly,
|
|
3984
|
-
video_grid_metric_mode
|
|
3984
|
+
video_grid_metric_mode,
|
|
3985
|
+
recent_flow_window_minutes
|
|
3985
3986
|
`).eq("enable", true);
|
|
3986
3987
|
if (companyId) {
|
|
3987
3988
|
query = query.eq("company_id", companyId);
|
|
@@ -4006,7 +4007,8 @@ var dashboardService = {
|
|
|
4006
4007
|
video_grid_metric_mode: normalizeVideoGridMetricMode(
|
|
4007
4008
|
line.video_grid_metric_mode,
|
|
4008
4009
|
line.assembly ?? false
|
|
4009
|
-
)
|
|
4010
|
+
),
|
|
4011
|
+
recent_flow_window_minutes: line.recent_flow_window_minutes ?? 7
|
|
4010
4012
|
}));
|
|
4011
4013
|
return transformedLines;
|
|
4012
4014
|
} catch (err) {
|
|
@@ -4043,7 +4045,7 @@ var dashboardService = {
|
|
|
4043
4045
|
}
|
|
4044
4046
|
const lineIdsToQuery = configuredLineIds;
|
|
4045
4047
|
const [line1Result, metricsResult2] = await Promise.all([
|
|
4046
|
-
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(),
|
|
4047
4049
|
supabase.from(lineMetricsTable).select("*").in("line_id", lineIdsToQuery).eq("shift_id", queryShiftId).eq("date", queryDate)
|
|
4048
4050
|
]);
|
|
4049
4051
|
if (line1Result.error) throw line1Result.error;
|
|
@@ -4099,6 +4101,7 @@ var dashboardService = {
|
|
|
4099
4101
|
date: queryDate,
|
|
4100
4102
|
shift_id: queryShiftId,
|
|
4101
4103
|
monitoring_mode: line1Data.monitoring_mode ?? void 0,
|
|
4104
|
+
recent_flow_window_minutes: line1Data.recent_flow_window_minutes ?? 7,
|
|
4102
4105
|
metrics: {
|
|
4103
4106
|
avg_efficiency: avgEfficiency,
|
|
4104
4107
|
avg_cycle_time: combinedMetricsData.avg_cycle_time / numLines,
|
|
@@ -4122,7 +4125,7 @@ var dashboardService = {
|
|
|
4122
4125
|
throw new Error("Company ID must be configured for detailed line requests.");
|
|
4123
4126
|
}
|
|
4124
4127
|
const [lineResult, metricsResult] = await Promise.all([
|
|
4125
|
-
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(),
|
|
4126
4129
|
supabase.from(lineMetricsTable).select("*").eq("line_id", lineIdToQuery).eq("shift_id", queryShiftId).eq("date", queryDate)
|
|
4127
4130
|
]);
|
|
4128
4131
|
if (lineResult.error) throw lineResult.error;
|
|
@@ -4147,6 +4150,7 @@ var dashboardService = {
|
|
|
4147
4150
|
date: queryDate,
|
|
4148
4151
|
shift_id: queryShiftId,
|
|
4149
4152
|
monitoring_mode: lineData.monitoring_mode ?? void 0,
|
|
4153
|
+
recent_flow_window_minutes: lineData.recent_flow_window_minutes ?? 7,
|
|
4150
4154
|
metrics: {
|
|
4151
4155
|
avg_efficiency: metrics2?.avg_efficiency ?? 0,
|
|
4152
4156
|
avg_cycle_time: metrics2?.avg_cycle_time || 0,
|
|
@@ -8480,7 +8484,8 @@ var LinesService = class {
|
|
|
8480
8484
|
videoGridMetricMode: normalizeVideoGridMetricMode(
|
|
8481
8485
|
line.video_grid_metric_mode,
|
|
8482
8486
|
line.assembly ?? false
|
|
8483
|
-
)
|
|
8487
|
+
),
|
|
8488
|
+
recentFlowWindowMinutes: line.recent_flow_window_minutes ?? 7
|
|
8484
8489
|
}));
|
|
8485
8490
|
} catch (error) {
|
|
8486
8491
|
console.error("Error fetching lines:", error);
|
|
@@ -8528,7 +8533,8 @@ var LinesService = class {
|
|
|
8528
8533
|
videoGridMetricMode: normalizeVideoGridMetricMode(
|
|
8529
8534
|
line.video_grid_metric_mode,
|
|
8530
8535
|
line.assembly ?? false
|
|
8531
|
-
)
|
|
8536
|
+
),
|
|
8537
|
+
recentFlowWindowMinutes: line.recent_flow_window_minutes ?? 7
|
|
8532
8538
|
}));
|
|
8533
8539
|
} catch (error) {
|
|
8534
8540
|
console.error("Error fetching all lines:", error);
|
|
@@ -8585,7 +8591,8 @@ var LinesService = class {
|
|
|
8585
8591
|
videoGridMetricMode: normalizeVideoGridMetricMode(
|
|
8586
8592
|
data.video_grid_metric_mode,
|
|
8587
8593
|
data.assembly ?? false
|
|
8588
|
-
)
|
|
8594
|
+
),
|
|
8595
|
+
recentFlowWindowMinutes: data.recent_flow_window_minutes ?? 7
|
|
8589
8596
|
};
|
|
8590
8597
|
} catch (error) {
|
|
8591
8598
|
console.error("Error fetching line:", error);
|
|
@@ -13339,6 +13346,7 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
13339
13346
|
actionName: item.action_name
|
|
13340
13347
|
}),
|
|
13341
13348
|
recent_flow_percent: item.recent_flow_percent ?? null,
|
|
13349
|
+
recent_flow_window_minutes: item.recent_flow_window_minutes ?? null,
|
|
13342
13350
|
recent_flow_effective_end_at: item.recent_flow_effective_end_at ?? null,
|
|
13343
13351
|
recent_flow_computed_at: item.recent_flow_computed_at ?? null,
|
|
13344
13352
|
incoming_wip_current: item.incoming_wip_current ?? null,
|
|
@@ -32595,6 +32603,212 @@ var CycleTimeChart = React141__default.memo(CycleTimeChartComponent, (prevProps,
|
|
|
32595
32603
|
});
|
|
32596
32604
|
});
|
|
32597
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
|
+
};
|
|
32598
32812
|
var CycleTimeOverTimeChart = ({
|
|
32599
32813
|
data,
|
|
32600
32814
|
idealCycleTime,
|
|
@@ -32604,7 +32818,8 @@ var CycleTimeOverTimeChart = ({
|
|
|
32604
32818
|
datasetKey,
|
|
32605
32819
|
className = "",
|
|
32606
32820
|
showIdleTime = false,
|
|
32607
|
-
idleTimeData = []
|
|
32821
|
+
idleTimeData = [],
|
|
32822
|
+
idleTimeSlots = []
|
|
32608
32823
|
}) => {
|
|
32609
32824
|
const MAX_DATA_POINTS = 40;
|
|
32610
32825
|
const containerRef = React141__default.useRef(null);
|
|
@@ -32707,50 +32922,60 @@ var CycleTimeOverTimeChart = ({
|
|
|
32707
32922
|
if (!visibleEntries.length) {
|
|
32708
32923
|
return null;
|
|
32709
32924
|
}
|
|
32710
|
-
|
|
32711
|
-
|
|
32712
|
-
|
|
32713
|
-
|
|
32714
|
-
|
|
32715
|
-
|
|
32716
|
-
|
|
32717
|
-
|
|
32718
|
-
|
|
32719
|
-
|
|
32720
|
-
|
|
32721
|
-
|
|
32722
|
-
|
|
32723
|
-
|
|
32724
|
-
|
|
32725
|
-
|
|
32726
|
-
|
|
32727
|
-
|
|
32728
|
-
|
|
32729
|
-
|
|
32730
|
-
|
|
32731
|
-
|
|
32732
|
-
|
|
32733
|
-
|
|
32734
|
-
|
|
32735
|
-
|
|
32736
|
-
|
|
32737
|
-
|
|
32738
|
-
|
|
32739
|
-
|
|
32740
|
-
|
|
32741
|
-
|
|
32742
|
-
|
|
32743
|
-
|
|
32744
|
-
|
|
32745
|
-
|
|
32746
|
-
|
|
32747
|
-
|
|
32748
|
-
|
|
32749
|
-
|
|
32750
|
-
|
|
32751
|
-
|
|
32752
|
-
|
|
32753
|
-
|
|
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]);
|
|
32754
32979
|
const renderCycleDot = React141__default.useCallback((props) => {
|
|
32755
32980
|
const { cx: cx2, cy, payload } = props;
|
|
32756
32981
|
const cycleTime = getNumericValue(payload?.cycleTime);
|
|
@@ -32819,14 +33044,18 @@ var CycleTimeOverTimeChart = ({
|
|
|
32819
33044
|
r: 4,
|
|
32820
33045
|
fill: "#f59e0b",
|
|
32821
33046
|
stroke: "#fff",
|
|
32822
|
-
strokeWidth: 1
|
|
33047
|
+
strokeWidth: 1,
|
|
33048
|
+
style: {
|
|
33049
|
+
opacity: showIdleTime ? 1 : 0,
|
|
33050
|
+
transition: "opacity 0.3s ease-in-out"
|
|
33051
|
+
}
|
|
32823
33052
|
}
|
|
32824
33053
|
);
|
|
32825
|
-
}, [getNumericValue]);
|
|
33054
|
+
}, [getNumericValue, showIdleTime]);
|
|
32826
33055
|
const renderIdleActiveDot = React141__default.useCallback((props) => {
|
|
32827
33056
|
const { cx: cx2, cy, payload } = props;
|
|
32828
33057
|
const idleMinutes = getNumericValue(payload?.idleMinutes);
|
|
32829
|
-
if (idleMinutes === null) {
|
|
33058
|
+
if (idleMinutes === null || !showIdleTime) {
|
|
32830
33059
|
return /* @__PURE__ */ jsx("g", {});
|
|
32831
33060
|
}
|
|
32832
33061
|
return /* @__PURE__ */ jsx(
|
|
@@ -32840,25 +33069,40 @@ var CycleTimeOverTimeChart = ({
|
|
|
32840
33069
|
strokeWidth: 2
|
|
32841
33070
|
}
|
|
32842
33071
|
);
|
|
32843
|
-
}, [getNumericValue]);
|
|
33072
|
+
}, [getNumericValue, showIdleTime]);
|
|
32844
33073
|
const chartData = React141__default.useMemo(() => Array.from({ length: DURATION }, (_, i) => {
|
|
32845
33074
|
const cycleTime = getNumericValue(finalData[i]);
|
|
32846
|
-
const
|
|
33075
|
+
const useIdleSlots = idleTimeSlots.length > 0;
|
|
33076
|
+
const idleSlot = useIdleSlots ? idleTimeSlots[i] ?? null : null;
|
|
33077
|
+
const idleMinutes = useIdleSlots ? idleSlot?.idleMinutes ?? null : getNumericValue(idleTimeData[i]);
|
|
32847
33078
|
return {
|
|
32848
33079
|
timeIndex: i,
|
|
32849
33080
|
label: formatTimeLabel(i),
|
|
32850
|
-
tooltip: formatTooltipTime(i),
|
|
33081
|
+
tooltip: idleSlot?.timeRange || formatTooltipTime(i),
|
|
33082
|
+
timeRange: idleSlot?.timeRange || formatTooltipTime(i),
|
|
33083
|
+
hourIndex: idleSlot?.hourIndex ?? i,
|
|
32851
33084
|
cycleTime,
|
|
32852
33085
|
idleMinutes,
|
|
33086
|
+
idleArray: idleSlot?.idleArray || [],
|
|
32853
33087
|
color: cycleTime !== null && cycleTime <= idealCycleTime ? "#00AB45" : "#E34329"
|
|
32854
33088
|
};
|
|
32855
|
-
}), [DURATION, finalData,
|
|
33089
|
+
}), [DURATION, finalData, idleTimeData, idleTimeSlots, idealCycleTime, getNumericValue]);
|
|
32856
33090
|
const renderLegend = () => {
|
|
32857
|
-
|
|
32858
|
-
|
|
32859
|
-
|
|
32860
|
-
|
|
32861
|
-
|
|
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
|
+
);
|
|
32862
33106
|
};
|
|
32863
33107
|
return /* @__PURE__ */ jsxs(
|
|
32864
33108
|
"div",
|
|
@@ -32929,7 +33173,7 @@ var CycleTimeOverTimeChart = ({
|
|
|
32929
33173
|
}
|
|
32930
33174
|
}
|
|
32931
33175
|
),
|
|
32932
|
-
|
|
33176
|
+
/* @__PURE__ */ jsx(
|
|
32933
33177
|
YAxis,
|
|
32934
33178
|
{
|
|
32935
33179
|
yAxisId: "idle",
|
|
@@ -32938,7 +33182,11 @@ var CycleTimeOverTimeChart = ({
|
|
|
32938
33182
|
width: 35,
|
|
32939
33183
|
domain: [0, 60],
|
|
32940
33184
|
tickFormatter: (value) => `${value}m`,
|
|
32941
|
-
tick: {
|
|
33185
|
+
tick: {
|
|
33186
|
+
fontSize: 11,
|
|
33187
|
+
fill: showIdleTime ? "#f59e0b" : "transparent",
|
|
33188
|
+
style: { transition: "fill 0.3s ease-in-out" }
|
|
33189
|
+
},
|
|
32942
33190
|
axisLine: false,
|
|
32943
33191
|
tickLine: false
|
|
32944
33192
|
}
|
|
@@ -32986,7 +33234,7 @@ var CycleTimeOverTimeChart = ({
|
|
|
32986
33234
|
},
|
|
32987
33235
|
`${effectiveDatasetKey}:cycle`
|
|
32988
33236
|
),
|
|
32989
|
-
|
|
33237
|
+
/* @__PURE__ */ jsx(
|
|
32990
33238
|
Line,
|
|
32991
33239
|
{
|
|
32992
33240
|
type: "monotone",
|
|
@@ -33001,7 +33249,11 @@ var CycleTimeOverTimeChart = ({
|
|
|
33001
33249
|
isAnimationActive: true,
|
|
33002
33250
|
animationBegin: 300,
|
|
33003
33251
|
animationDuration: 1500,
|
|
33004
|
-
animationEasing: "ease-out"
|
|
33252
|
+
animationEasing: "ease-out",
|
|
33253
|
+
style: {
|
|
33254
|
+
strokeOpacity: showIdleTime ? 1 : 0,
|
|
33255
|
+
transition: "stroke-opacity 0.3s ease-in-out"
|
|
33256
|
+
}
|
|
33005
33257
|
},
|
|
33006
33258
|
`${effectiveDatasetKey}:idle`
|
|
33007
33259
|
)
|
|
@@ -33156,89 +33408,20 @@ var HourlyOutputChartComponent = ({
|
|
|
33156
33408
|
shiftEnd,
|
|
33157
33409
|
showIdleTime = false,
|
|
33158
33410
|
idleTimeHourly,
|
|
33159
|
-
idleTimeClips,
|
|
33160
|
-
idleTimeClipClassifications,
|
|
33161
|
-
shiftDate,
|
|
33162
|
-
timezone,
|
|
33163
33411
|
className = ""
|
|
33164
33412
|
}) => {
|
|
33165
33413
|
const containerRef = React141__default.useRef(null);
|
|
33166
33414
|
const [containerReady, setContainerReady] = React141__default.useState(false);
|
|
33167
33415
|
const [containerWidth, setContainerWidth] = React141__default.useState(0);
|
|
33168
|
-
const
|
|
33169
|
-
|
|
33170
|
-
|
|
33171
|
-
const minute = parseInt(minutes || "0");
|
|
33172
|
-
const decimalHour = hour + minute / 60;
|
|
33173
|
-
return { hour, minute, decimalHour };
|
|
33174
|
-
};
|
|
33175
|
-
const shiftStartTime = getTimeFromTimeString2(shiftStart);
|
|
33176
|
-
React141__default.useMemo(() => {
|
|
33177
|
-
if (!shiftDate || !timezone) return null;
|
|
33178
|
-
const hour = shiftStartTime.hour.toString().padStart(2, "0");
|
|
33179
|
-
const minute = shiftStartTime.minute.toString().padStart(2, "0");
|
|
33180
|
-
return fromZonedTime(`${shiftDate}T${hour}:${minute}:00`, timezone);
|
|
33181
|
-
}, [shiftDate, timezone, shiftStartTime.hour, shiftStartTime.minute]);
|
|
33182
|
-
const idleClipRanges = React141__default.useMemo(() => {
|
|
33183
|
-
if (!idleTimeClips || idleTimeClips.length === 0) return [];
|
|
33184
|
-
return idleTimeClips.map((clip) => ({
|
|
33185
|
-
id: clip.id,
|
|
33186
|
-
start: clip.idle_start_time ? new Date(clip.idle_start_time) : null,
|
|
33187
|
-
end: clip.idle_end_time ? new Date(clip.idle_end_time) : null
|
|
33188
|
-
})).filter((clip) => clip.start && clip.end);
|
|
33189
|
-
}, [idleTimeClips]);
|
|
33190
|
-
React141__default.useCallback((rangeStart, rangeEnd) => {
|
|
33191
|
-
if (!rangeStart || !rangeEnd || idleClipRanges.length === 0) {
|
|
33192
|
-
return "Reason unavailable";
|
|
33193
|
-
}
|
|
33194
|
-
const matchingClip = idleClipRanges.find((clip) => rangeStart >= clip.start && rangeEnd <= clip.end) || idleClipRanges.find((clip) => rangeStart < clip.end && rangeEnd > clip.start);
|
|
33195
|
-
if (!matchingClip) {
|
|
33196
|
-
return "Reason unavailable";
|
|
33197
|
-
}
|
|
33198
|
-
const classification = idleTimeClipClassifications?.[matchingClip.id];
|
|
33199
|
-
if (!classification || classification.status === "processing") {
|
|
33200
|
-
return "Analyzing...";
|
|
33201
|
-
}
|
|
33202
|
-
if (!classification.label) {
|
|
33203
|
-
return "Reason unavailable";
|
|
33204
|
-
}
|
|
33205
|
-
return classification.displayName || classification.label.replace(/_/g, " ");
|
|
33206
|
-
}, [idleClipRanges, idleTimeClipClassifications]);
|
|
33207
|
-
const { shiftDuration, shiftEndTime, hasPartialLastHour } = React141__default.useMemo(() => {
|
|
33208
|
-
console.log("[HourlyOutputChart] Calculating shift duration with:", {
|
|
33416
|
+
const idleSlots = React141__default.useMemo(
|
|
33417
|
+
() => buildHourlyIdleSlots({
|
|
33418
|
+
idleTimeHourly,
|
|
33209
33419
|
shiftStart,
|
|
33210
|
-
shiftEnd
|
|
33211
|
-
|
|
33212
|
-
|
|
33213
|
-
|
|
33214
|
-
|
|
33215
|
-
return {
|
|
33216
|
-
shiftDuration: 11,
|
|
33217
|
-
shiftEndTime: null,
|
|
33218
|
-
hasPartialLastHour: false
|
|
33219
|
-
};
|
|
33220
|
-
}
|
|
33221
|
-
const endTime = getTimeFromTimeString2(shiftEnd);
|
|
33222
|
-
let duration = endTime.decimalHour - shiftStartTime.decimalHour;
|
|
33223
|
-
if (duration <= 0) {
|
|
33224
|
-
duration += 24;
|
|
33225
|
-
}
|
|
33226
|
-
const hasPartial = endTime.minute > 0 && endTime.minute < 60;
|
|
33227
|
-
const hourCount = hasPartial ? Math.ceil(duration) : Math.round(duration);
|
|
33228
|
-
console.log("[HourlyOutputChart] Shift calculation results:", {
|
|
33229
|
-
endTime,
|
|
33230
|
-
duration,
|
|
33231
|
-
hasPartial,
|
|
33232
|
-
hourCount
|
|
33233
|
-
});
|
|
33234
|
-
return {
|
|
33235
|
-
shiftDuration: hourCount,
|
|
33236
|
-
shiftEndTime: endTime,
|
|
33237
|
-
hasPartialLastHour: hasPartial
|
|
33238
|
-
};
|
|
33239
|
-
}, [shiftEnd, shiftStartTime.decimalHour]);
|
|
33240
|
-
const SHIFT_DURATION = shiftDuration;
|
|
33241
|
-
shiftEndTime ? shiftEndTime.hour : (shiftStartTime.hour + SHIFT_DURATION) % 24;
|
|
33420
|
+
shiftEnd
|
|
33421
|
+
}),
|
|
33422
|
+
[idleTimeHourly, shiftStart, shiftEnd]
|
|
33423
|
+
);
|
|
33424
|
+
const SHIFT_DURATION = idleSlots.length;
|
|
33242
33425
|
const [animatedData, setAnimatedData] = React141__default.useState(
|
|
33243
33426
|
() => Array(SHIFT_DURATION).fill(0)
|
|
33244
33427
|
);
|
|
@@ -33361,121 +33544,22 @@ var HourlyOutputChartComponent = ({
|
|
|
33361
33544
|
}
|
|
33362
33545
|
return { interval: 0, angle: -30, height: 64, tickFont: 9, tickMargin: 6 };
|
|
33363
33546
|
}, [containerWidth]);
|
|
33364
|
-
const formatHour = React141__default.useCallback((hourIndex) => {
|
|
33365
|
-
const isLastHour = hourIndex === SHIFT_DURATION - 1;
|
|
33366
|
-
const startDecimalHour = shiftStartTime.decimalHour + hourIndex;
|
|
33367
|
-
const startHour = Math.floor(startDecimalHour) % 24;
|
|
33368
|
-
const startMinute = Math.round(startDecimalHour % 1 * 60);
|
|
33369
|
-
let endHour, endMinute;
|
|
33370
|
-
if (isLastHour && shiftEndTime) {
|
|
33371
|
-
endHour = shiftEndTime.hour;
|
|
33372
|
-
endMinute = shiftEndTime.minute;
|
|
33373
|
-
} else {
|
|
33374
|
-
const endDecimalHour = startDecimalHour + 1;
|
|
33375
|
-
endHour = Math.floor(endDecimalHour) % 24;
|
|
33376
|
-
endMinute = Math.round(endDecimalHour % 1 * 60);
|
|
33377
|
-
}
|
|
33378
|
-
const formatTime5 = (h, m) => {
|
|
33379
|
-
const period = h >= 12 ? "PM" : "AM";
|
|
33380
|
-
const hour12 = h === 0 ? 12 : h > 12 ? h - 12 : h;
|
|
33381
|
-
if (m === 0) {
|
|
33382
|
-
return `${hour12}${period}`;
|
|
33383
|
-
}
|
|
33384
|
-
return `${hour12}:${m.toString().padStart(2, "0")}${period}`;
|
|
33385
|
-
};
|
|
33386
|
-
return `${formatTime5(startHour, startMinute)}-${formatTime5(endHour, endMinute)}`;
|
|
33387
|
-
}, [shiftStartTime.decimalHour, SHIFT_DURATION, shiftEndTime]);
|
|
33388
|
-
const formatTimeRange2 = React141__default.useCallback((hourIndex) => {
|
|
33389
|
-
const isLastHour = hourIndex === SHIFT_DURATION - 1;
|
|
33390
|
-
const startDecimalHour = shiftStartTime.decimalHour + hourIndex;
|
|
33391
|
-
const startHour = Math.floor(startDecimalHour) % 24;
|
|
33392
|
-
const startMinute = Math.round(startDecimalHour % 1 * 60);
|
|
33393
|
-
let endHour, endMinute;
|
|
33394
|
-
if (isLastHour && shiftEndTime) {
|
|
33395
|
-
endHour = shiftEndTime.hour;
|
|
33396
|
-
endMinute = shiftEndTime.minute;
|
|
33397
|
-
} else {
|
|
33398
|
-
const endDecimalHour = startDecimalHour + 1;
|
|
33399
|
-
endHour = Math.floor(endDecimalHour) % 24;
|
|
33400
|
-
endMinute = Math.round(endDecimalHour % 1 * 60);
|
|
33401
|
-
}
|
|
33402
|
-
const formatTime5 = (h, m) => {
|
|
33403
|
-
const period = h >= 12 ? "PM" : "AM";
|
|
33404
|
-
const hour12 = h === 0 ? 12 : h > 12 ? h - 12 : h;
|
|
33405
|
-
return `${hour12}:${m.toString().padStart(2, "0")} ${period}`;
|
|
33406
|
-
};
|
|
33407
|
-
return `${formatTime5(startHour, startMinute)} - ${formatTime5(endHour, endMinute)}`;
|
|
33408
|
-
}, [shiftStartTime.decimalHour, SHIFT_DURATION, shiftEndTime]);
|
|
33409
33547
|
const chartData = React141__default.useMemo(() => {
|
|
33410
33548
|
return Array.from({ length: SHIFT_DURATION }, (_, i) => {
|
|
33411
|
-
const
|
|
33412
|
-
const startMinute = shiftStartTime.minute;
|
|
33413
|
-
let idleArray = [];
|
|
33414
|
-
let idleMinutes = 0;
|
|
33415
|
-
if (idleTimeHourly) {
|
|
33416
|
-
if (startMinute > 0) {
|
|
33417
|
-
if (i === 0) {
|
|
33418
|
-
const firstHourData = idleTimeHourly[actualHour.toString()] || [];
|
|
33419
|
-
const nextHour = (actualHour + 1) % 24;
|
|
33420
|
-
const nextHourData = idleTimeHourly[nextHour.toString()] || [];
|
|
33421
|
-
idleArray = [
|
|
33422
|
-
...firstHourData.slice(startMinute) || [],
|
|
33423
|
-
...nextHourData.slice(0, startMinute) || []
|
|
33424
|
-
];
|
|
33425
|
-
} else if (i < SHIFT_DURATION - 1) {
|
|
33426
|
-
const currentHourData = idleTimeHourly[actualHour.toString()] || [];
|
|
33427
|
-
const nextHour = (actualHour + 1) % 24;
|
|
33428
|
-
const nextHourData = idleTimeHourly[nextHour.toString()] || [];
|
|
33429
|
-
idleArray = [
|
|
33430
|
-
...currentHourData.slice(startMinute) || [],
|
|
33431
|
-
...nextHourData.slice(0, startMinute) || []
|
|
33432
|
-
];
|
|
33433
|
-
} else {
|
|
33434
|
-
const hasPartialLastHour2 = shiftEndTime && shiftEndTime.minute > 0 && shiftEndTime.minute < 60;
|
|
33435
|
-
if (hasPartialLastHour2) {
|
|
33436
|
-
const currentHourData = idleTimeHourly[actualHour.toString()] || [];
|
|
33437
|
-
const nextHour = (actualHour + 1) % 24;
|
|
33438
|
-
const nextHourData = idleTimeHourly[nextHour.toString()] || [];
|
|
33439
|
-
if (startMinute > 0) {
|
|
33440
|
-
const firstPart = currentHourData.slice(startMinute) || [];
|
|
33441
|
-
const secondPart = nextHourData.slice(0, shiftEndTime.minute) || [];
|
|
33442
|
-
idleArray = [...firstPart, ...secondPart];
|
|
33443
|
-
} else {
|
|
33444
|
-
idleArray = currentHourData.slice(0, shiftEndTime.minute) || [];
|
|
33445
|
-
}
|
|
33446
|
-
} else {
|
|
33447
|
-
const currentHourData = idleTimeHourly[actualHour.toString()] || [];
|
|
33448
|
-
const nextHour = (actualHour + 1) % 24;
|
|
33449
|
-
const nextHourData = idleTimeHourly[nextHour.toString()] || [];
|
|
33450
|
-
idleArray = [
|
|
33451
|
-
...currentHourData.slice(startMinute) || [],
|
|
33452
|
-
...nextHourData.slice(0, startMinute) || []
|
|
33453
|
-
];
|
|
33454
|
-
}
|
|
33455
|
-
}
|
|
33456
|
-
} else {
|
|
33457
|
-
const currentHourData = idleTimeHourly[actualHour.toString()] || [];
|
|
33458
|
-
if (i === SHIFT_DURATION - 1 && shiftEndTime && shiftEndTime.minute > 0 && shiftEndTime.minute < 60) {
|
|
33459
|
-
idleArray = currentHourData.slice(0, shiftEndTime.minute) || [];
|
|
33460
|
-
} else {
|
|
33461
|
-
idleArray = currentHourData || [];
|
|
33462
|
-
}
|
|
33463
|
-
}
|
|
33464
|
-
}
|
|
33465
|
-
idleMinutes = idleArray.filter((val) => val === "1" || val === 1).length;
|
|
33549
|
+
const idleSlot = idleSlots[i];
|
|
33466
33550
|
return {
|
|
33467
|
-
hourIndex: i,
|
|
33468
|
-
hour:
|
|
33469
|
-
timeRange:
|
|
33551
|
+
hourIndex: idleSlot?.hourIndex ?? i,
|
|
33552
|
+
hour: idleSlot?.hour || "",
|
|
33553
|
+
timeRange: idleSlot?.timeRange || "",
|
|
33470
33554
|
output: animatedData[i] || 0,
|
|
33471
33555
|
originalOutput: data[i] || 0,
|
|
33472
33556
|
// Keep original data for labels
|
|
33473
33557
|
color: (animatedData[i] || 0) >= Math.round(pphThreshold) ? "#00AB45" : "#E34329",
|
|
33474
|
-
idleMinutes,
|
|
33475
|
-
idleArray
|
|
33558
|
+
idleMinutes: idleSlot?.idleMinutes || 0,
|
|
33559
|
+
idleArray: idleSlot?.idleArray || []
|
|
33476
33560
|
};
|
|
33477
33561
|
});
|
|
33478
|
-
}, [animatedData, data, pphThreshold,
|
|
33562
|
+
}, [animatedData, data, pphThreshold, idleSlots, SHIFT_DURATION]);
|
|
33479
33563
|
const IdleBar = React141__default.useMemo(() => {
|
|
33480
33564
|
if (!idleBarState.visible) return null;
|
|
33481
33565
|
return /* @__PURE__ */ jsx(
|
|
@@ -33637,36 +33721,11 @@ var HourlyOutputChartComponent = ({
|
|
|
33637
33721
|
content: (props) => {
|
|
33638
33722
|
if (!props.active || !props.payload || props.payload.length === 0) return null;
|
|
33639
33723
|
const data2 = props.payload[0].payload;
|
|
33640
|
-
const
|
|
33641
|
-
|
|
33642
|
-
|
|
33643
|
-
data2.
|
|
33644
|
-
|
|
33645
|
-
if (!currentRange) {
|
|
33646
|
-
currentRange = { start: idx, end: idx };
|
|
33647
|
-
} else {
|
|
33648
|
-
currentRange.end = idx;
|
|
33649
|
-
}
|
|
33650
|
-
} else if (val !== "x" && currentRange) {
|
|
33651
|
-
idleRanges.push(currentRange);
|
|
33652
|
-
currentRange = null;
|
|
33653
|
-
}
|
|
33654
|
-
});
|
|
33655
|
-
if (currentRange) {
|
|
33656
|
-
idleRanges.push(currentRange);
|
|
33657
|
-
}
|
|
33658
|
-
}
|
|
33659
|
-
const formatIdleTimestamp = (minuteIdx) => {
|
|
33660
|
-
const fallbackIndex = chartData.findIndex((item) => item.timeRange === data2.timeRange);
|
|
33661
|
-
const hourOffset = Number.isFinite(data2.hourIndex) ? data2.hourIndex : fallbackIndex;
|
|
33662
|
-
const safeHourOffset = hourOffset >= 0 ? hourOffset : 0;
|
|
33663
|
-
const totalMinutes = (shiftStartTime.hour + safeHourOffset) * 60 + shiftStartTime.minute + minuteIdx;
|
|
33664
|
-
const hour = Math.floor(totalMinutes / 60) % 24;
|
|
33665
|
-
const minute = totalMinutes % 60;
|
|
33666
|
-
const period = hour >= 12 ? "PM" : "AM";
|
|
33667
|
-
const hour12 = hour === 0 ? 12 : hour > 12 ? hour - 12 : hour;
|
|
33668
|
-
return `${hour12}:${minute.toString().padStart(2, "0")} ${period}`;
|
|
33669
|
-
};
|
|
33724
|
+
const idlePeriods = showIdleTime ? getHourlyIdlePeriods({
|
|
33725
|
+
idleArray: data2.idleArray,
|
|
33726
|
+
shiftStart,
|
|
33727
|
+
hourIndex: Number.isFinite(data2.hourIndex) ? data2.hourIndex : 0
|
|
33728
|
+
}) : [];
|
|
33670
33729
|
return /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-xl shadow-xl border border-gray-100 p-4 min-w-[220px]", children: [
|
|
33671
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 }) }),
|
|
33672
33731
|
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
@@ -33685,27 +33744,22 @@ var HourlyOutputChartComponent = ({
|
|
|
33685
33744
|
" minutes"
|
|
33686
33745
|
] })
|
|
33687
33746
|
] }) }),
|
|
33688
|
-
|
|
33747
|
+
idlePeriods.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mt-3 bg-gray-50 rounded-lg p-2.5", children: [
|
|
33689
33748
|
/* @__PURE__ */ jsx("p", { className: "font-medium text-gray-700 text-xs mb-2", children: "Idle periods:" }),
|
|
33690
|
-
/* @__PURE__ */ jsx("div", { className: "space-y-1 max-h-32 overflow-y-auto pr-1", children:
|
|
33691
|
-
const duration = range.end - range.start + 1;
|
|
33692
|
-
const startTime = formatIdleTimestamp(range.start);
|
|
33693
|
-
const endTime = formatIdleTimestamp(range.end + 1);
|
|
33694
|
-
const fallbackIndex = chartData.findIndex((item) => item.timeRange === data2.timeRange);
|
|
33695
|
-
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) => {
|
|
33696
33750
|
return /* @__PURE__ */ jsxs("div", { className: "text-gray-600 flex items-center gap-2 text-xs", children: [
|
|
33697
33751
|
/* @__PURE__ */ jsx("span", { className: "inline-block w-1.5 h-1.5 bg-orange-400 rounded-full flex-shrink-0" }),
|
|
33698
|
-
/* @__PURE__ */ jsx("span", { children: duration === 1 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
33699
|
-
startTime,
|
|
33752
|
+
/* @__PURE__ */ jsx("span", { children: period.duration === 1 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
33753
|
+
period.startTime,
|
|
33700
33754
|
" (",
|
|
33701
|
-
duration,
|
|
33755
|
+
period.duration,
|
|
33702
33756
|
" min)"
|
|
33703
33757
|
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
33704
|
-
startTime,
|
|
33758
|
+
period.startTime,
|
|
33705
33759
|
" - ",
|
|
33706
|
-
endTime,
|
|
33760
|
+
period.endTime,
|
|
33707
33761
|
" (",
|
|
33708
|
-
duration,
|
|
33762
|
+
period.duration,
|
|
33709
33763
|
" mins)"
|
|
33710
33764
|
] }) })
|
|
33711
33765
|
] }, index);
|
|
@@ -33860,9 +33914,8 @@ var HourlyOutputChart = React141__default.memo(HourlyOutputChartComponent, (prev
|
|
|
33860
33914
|
HourlyOutputChart.displayName = "HourlyOutputChart";
|
|
33861
33915
|
|
|
33862
33916
|
// src/components/dashboard/grid/videoGridMetricUtils.ts
|
|
33863
|
-
var VIDEO_GRID_LEGEND_LABEL = "7 Minute Efficiency";
|
|
33864
33917
|
var MAP_GRID_LEGEND_LABEL = "Efficiency";
|
|
33865
|
-
var MIXED_VIDEO_GRID_LEGEND_LABEL = "Efficiency";
|
|
33918
|
+
var MIXED_VIDEO_GRID_LEGEND_LABEL = "Flow Efficiency";
|
|
33866
33919
|
var isFiniteNumber = (value) => typeof value === "number" && Number.isFinite(value);
|
|
33867
33920
|
var isVideoGridRecentFlowEnabled = (workspace) => isRecentFlowVideoGridMetricMode(
|
|
33868
33921
|
workspace.video_grid_metric_mode,
|
|
@@ -33961,8 +34014,15 @@ var getVideoGridLegendLabel = (workspaces) => {
|
|
|
33961
34014
|
if (recentFlowEnabledCount === 0) {
|
|
33962
34015
|
return MAP_GRID_LEGEND_LABEL;
|
|
33963
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
|
+
);
|
|
33964
34020
|
if (recentFlowEnabledCount === visibleWorkspaces.length) {
|
|
33965
|
-
|
|
34021
|
+
if (recentFlowWindows.size === 1) {
|
|
34022
|
+
const [windowMinutes] = Array.from(recentFlowWindows);
|
|
34023
|
+
return `${windowMinutes} Minute Efficiency`;
|
|
34024
|
+
}
|
|
34025
|
+
return MIXED_VIDEO_GRID_LEGEND_LABEL;
|
|
33966
34026
|
}
|
|
33967
34027
|
return MIXED_VIDEO_GRID_LEGEND_LABEL;
|
|
33968
34028
|
};
|
|
@@ -35909,7 +35969,7 @@ var HourlyUptimeChartComponent = ({
|
|
|
35909
35969
|
idleRanges.push(currentRange);
|
|
35910
35970
|
}
|
|
35911
35971
|
}
|
|
35912
|
-
const
|
|
35972
|
+
const formatIdleTimestamp2 = (minuteIdx) => {
|
|
35913
35973
|
const totalMinutes = (shiftStartTime.hour + data.hourIndex) * 60 + shiftStartTime.minute + minuteIdx;
|
|
35914
35974
|
const hour = Math.floor(totalMinutes / 60) % 24;
|
|
35915
35975
|
const minute = totalMinutes % 60;
|
|
@@ -35939,8 +35999,8 @@ var HourlyUptimeChartComponent = ({
|
|
|
35939
35999
|
/* @__PURE__ */ jsx("p", { className: "font-medium text-gray-700 text-xs mb-2", children: "Idle periods:" }),
|
|
35940
36000
|
/* @__PURE__ */ jsx("div", { className: "space-y-1 max-h-32 overflow-y-auto pr-1", children: idleRanges.map((range, index) => {
|
|
35941
36001
|
const duration = range.end - range.start + 1;
|
|
35942
|
-
const startTime =
|
|
35943
|
-
const endTime =
|
|
36002
|
+
const startTime = formatIdleTimestamp2(range.start);
|
|
36003
|
+
const endTime = formatIdleTimestamp2(range.end + 1);
|
|
35944
36004
|
return /* @__PURE__ */ jsxs("div", { className: "text-gray-600 flex items-center gap-2 text-xs", children: [
|
|
35945
36005
|
/* @__PURE__ */ jsx("span", { className: "inline-block w-1.5 h-1.5 bg-orange-400 rounded-full flex-shrink-0" }),
|
|
35946
36006
|
/* @__PURE__ */ jsx("span", { children: duration === 1 ? `${startTime} (${duration} min)` : `${startTime} - ${endTime} (${duration} mins)` })
|
|
@@ -69187,56 +69247,43 @@ var WorkspaceDetailView = ({
|
|
|
69187
69247
|
const canToggleChartIdleTime = !isUptimeMode && !shouldShowCycleTimeLoadingState && !shouldShowCycleTimeUnavailableState;
|
|
69188
69248
|
const idleClipDate = date || workspace?.date || calculatedOperationalDate || getOperationalDate(timezone);
|
|
69189
69249
|
const idleClipShiftId = parsedShiftId ?? workspace?.shift_id;
|
|
69190
|
-
const
|
|
69191
|
-
|
|
69192
|
-
|
|
69193
|
-
|
|
69194
|
-
|
|
69195
|
-
|
|
69196
|
-
|
|
69197
|
-
|
|
69198
|
-
|
|
69199
|
-
|
|
69200
|
-
|
|
69201
|
-
|
|
69202
|
-
|
|
69203
|
-
|
|
69204
|
-
|
|
69205
|
-
|
|
69206
|
-
|
|
69207
|
-
if (endSlotMins > endTotal) endSlotMins = endTotal;
|
|
69208
|
-
let idleCount = 0;
|
|
69209
|
-
for (let m = startSlotMins; m < endSlotMins; m++) {
|
|
69210
|
-
const hourKey = Math.floor(m / 60) % 24;
|
|
69211
|
-
const minuteKey = m % 60;
|
|
69212
|
-
const hourData = idleTimeHourlyObj[hourKey.toString()] || [];
|
|
69213
|
-
if (Array.isArray(hourData)) {
|
|
69214
|
-
const val = hourData[minuteKey];
|
|
69215
|
-
if (val === 1 || val === "1") {
|
|
69216
|
-
idleCount++;
|
|
69217
|
-
}
|
|
69218
|
-
}
|
|
69219
|
-
}
|
|
69220
|
-
result[i] = idleCount;
|
|
69221
|
-
}
|
|
69222
|
-
return result;
|
|
69223
|
-
}, [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
|
+
);
|
|
69224
69267
|
const hourlyIdleMinutes = useMemo(
|
|
69225
69268
|
() => maskFutureHourlySeries({
|
|
69226
69269
|
data: rawHourlyIdleMinutes,
|
|
69227
|
-
shiftStart:
|
|
69228
|
-
shiftEnd:
|
|
69270
|
+
shiftStart: authoritativeCycleMetrics?.shift_start,
|
|
69271
|
+
shiftEnd: authoritativeCycleMetrics?.shift_end,
|
|
69229
69272
|
shiftDate: idleClipDate,
|
|
69230
69273
|
timezone: effectiveCycleTimeTimezone
|
|
69231
69274
|
}),
|
|
69232
69275
|
[
|
|
69233
69276
|
rawHourlyIdleMinutes,
|
|
69234
|
-
|
|
69235
|
-
|
|
69277
|
+
authoritativeCycleMetrics?.shift_start,
|
|
69278
|
+
authoritativeCycleMetrics?.shift_end,
|
|
69236
69279
|
idleClipDate,
|
|
69237
69280
|
effectiveCycleTimeTimezone
|
|
69238
69281
|
]
|
|
69239
69282
|
);
|
|
69283
|
+
const hourlyIdleSlots = useMemo(
|
|
69284
|
+
() => rawHourlyIdleSlots.map((slot, index) => hourlyIdleMinutes[index] === null ? null : slot),
|
|
69285
|
+
[rawHourlyIdleSlots, hourlyIdleMinutes]
|
|
69286
|
+
);
|
|
69240
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: [
|
|
69241
69288
|
/* @__PURE__ */ jsx("h4", { className: "text-base font-semibold text-amber-900", children: "Cycle data unavailable" }),
|
|
69242
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." }),
|
|
@@ -69792,7 +69839,8 @@ var WorkspaceDetailView = ({
|
|
|
69792
69839
|
xAxisMode: "hourly",
|
|
69793
69840
|
datasetKey: cycleTimeDatasetKey,
|
|
69794
69841
|
showIdleTime: showChartIdleTime,
|
|
69795
|
-
idleTimeData: hourlyIdleMinutes
|
|
69842
|
+
idleTimeData: hourlyIdleMinutes,
|
|
69843
|
+
idleTimeSlots: hourlyIdleSlots
|
|
69796
69844
|
}
|
|
69797
69845
|
) : null : /* @__PURE__ */ jsx(
|
|
69798
69846
|
HourlyOutputChart2,
|
|
@@ -69921,7 +69969,8 @@ var WorkspaceDetailView = ({
|
|
|
69921
69969
|
xAxisMode: "hourly",
|
|
69922
69970
|
datasetKey: cycleTimeDatasetKey,
|
|
69923
69971
|
showIdleTime: showChartIdleTime,
|
|
69924
|
-
idleTimeData: hourlyIdleMinutes
|
|
69972
|
+
idleTimeData: hourlyIdleMinutes,
|
|
69973
|
+
idleTimeSlots: hourlyIdleSlots
|
|
69925
69974
|
}
|
|
69926
69975
|
) : null : /* @__PURE__ */ jsx(
|
|
69927
69976
|
HourlyOutputChart2,
|