@optifye/dashboard-core 6.12.0 → 6.12.1
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.css +53 -3
- package/dist/index.d.mts +12 -6
- package/dist/index.d.ts +12 -6
- package/dist/index.js +983 -593
- package/dist/index.mjs +983 -593
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -4205,6 +4205,22 @@ var isDummyRow = (row, dummySet) => {
|
|
|
4205
4205
|
if (typeof skuId !== "string" || skuId.length === 0) return false;
|
|
4206
4206
|
return dummySet.has(skuId);
|
|
4207
4207
|
};
|
|
4208
|
+
var isActiveOutputRow = (row) => {
|
|
4209
|
+
const currentOutput = coerceOptionalNumber(row.current_output) ?? 0;
|
|
4210
|
+
const idealOutput = coerceOptionalNumber(row.ideal_output) ?? 0;
|
|
4211
|
+
return currentOutput > 0 || idealOutput > 0;
|
|
4212
|
+
};
|
|
4213
|
+
var roundHalfUpInt = (value) => Math.floor(value + 0.5);
|
|
4214
|
+
var dedupeStringsPreserveOrder = (values) => {
|
|
4215
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4216
|
+
const ordered = [];
|
|
4217
|
+
for (const value of values) {
|
|
4218
|
+
if (!value || seen.has(value)) continue;
|
|
4219
|
+
seen.add(value);
|
|
4220
|
+
ordered.push(value);
|
|
4221
|
+
}
|
|
4222
|
+
return ordered;
|
|
4223
|
+
};
|
|
4208
4224
|
var emptyAggregate = () => ({
|
|
4209
4225
|
current_output: 0,
|
|
4210
4226
|
ideal_output: 0,
|
|
@@ -4323,10 +4339,7 @@ var combineLineMetricsRows = (rows, dummySkuId) => {
|
|
|
4323
4339
|
);
|
|
4324
4340
|
const dummyLineMetricsRow = rows.find((row) => isDummyRow(row, dummySet));
|
|
4325
4341
|
const lineThresholdValue = dummyLineMetricsRow ? safeFloat(dummyLineMetricsRow.line_threshold) : safeFloat(rowsForAggregation[0]?.line_threshold ?? 0);
|
|
4326
|
-
const
|
|
4327
|
-
(acc, row) => acc + safeInt(row.underperforming_workspaces),
|
|
4328
|
-
0
|
|
4329
|
-
);
|
|
4342
|
+
const activeRealRows = rowsForAggregation.filter(isActiveOutputRow);
|
|
4330
4343
|
const weighted = (field) => {
|
|
4331
4344
|
const pairs = [];
|
|
4332
4345
|
rowsForAggregation.forEach((row, idx) => {
|
|
@@ -4348,6 +4361,12 @@ var combineLineMetricsRows = (rows, dummySkuId) => {
|
|
|
4348
4361
|
const avgEfficiency = weighted("avg_efficiency");
|
|
4349
4362
|
const avgCycleTime = weighted("avg_cycle_time");
|
|
4350
4363
|
const thresholdPph = weighted("threshold_pph");
|
|
4364
|
+
const underperformingWorkspaces = activeRealRows.length > 0 ? roundHalfUpInt(
|
|
4365
|
+
activeRealRows.reduce(
|
|
4366
|
+
(acc, row) => acc + safeInt(row.underperforming_workspaces),
|
|
4367
|
+
0
|
|
4368
|
+
) / activeRealRows.length
|
|
4369
|
+
) : 0;
|
|
4351
4370
|
const merged = mergeHourlyFields(rows);
|
|
4352
4371
|
const outputArrays = [];
|
|
4353
4372
|
for (const row of rowsForAggregation) {
|
|
@@ -4370,7 +4389,7 @@ var combineLineMetricsRows = (rows, dummySkuId) => {
|
|
|
4370
4389
|
}
|
|
4371
4390
|
const underperformingNames = [];
|
|
4372
4391
|
const underperformingUuids = [];
|
|
4373
|
-
for (const row of
|
|
4392
|
+
for (const row of activeRealRows) {
|
|
4374
4393
|
const names = row.underperforming_workspace_names;
|
|
4375
4394
|
if (Array.isArray(names)) {
|
|
4376
4395
|
for (const n of names) {
|
|
@@ -4384,6 +4403,8 @@ var combineLineMetricsRows = (rows, dummySkuId) => {
|
|
|
4384
4403
|
}
|
|
4385
4404
|
}
|
|
4386
4405
|
}
|
|
4406
|
+
const dedupedUnderperformingNames = dedupeStringsPreserveOrder(underperformingNames);
|
|
4407
|
+
const dedupedUnderperformingUuids = dedupeStringsPreserveOrder(underperformingUuids);
|
|
4387
4408
|
let totalWorkspacesValue = null;
|
|
4388
4409
|
const primaryTotal = coerceOptionalNumber(primary.total_workspaces);
|
|
4389
4410
|
if (primaryTotal !== null) {
|
|
@@ -4405,9 +4426,9 @@ var combineLineMetricsRows = (rows, dummySkuId) => {
|
|
|
4405
4426
|
line_threshold: lineThresholdValue,
|
|
4406
4427
|
threshold_pph: thresholdPph,
|
|
4407
4428
|
total_workspaces: safeInt(totalWorkspacesValue ?? 0),
|
|
4408
|
-
underperforming_workspaces:
|
|
4409
|
-
underperforming_workspace_names:
|
|
4410
|
-
underperforming_workspace_uuids:
|
|
4429
|
+
underperforming_workspaces: underperformingWorkspaces,
|
|
4430
|
+
underperforming_workspace_names: dedupedUnderperformingNames,
|
|
4431
|
+
underperforming_workspace_uuids: dedupedUnderperformingUuids,
|
|
4411
4432
|
output_array: outputArray,
|
|
4412
4433
|
output_hourly: merged.output_hourly,
|
|
4413
4434
|
idle_time_hourly: merged.idle_time_hourly,
|
|
@@ -5532,11 +5553,11 @@ var getDaysDifferenceInZone = (compareDate, timezone) => {
|
|
|
5532
5553
|
todayInZone.setHours(0, 0, 0, 0);
|
|
5533
5554
|
compareDateInZone.setHours(0, 0, 0, 0);
|
|
5534
5555
|
const diffTime = todayInZone.getTime() - compareDateInZone.getTime();
|
|
5535
|
-
const
|
|
5536
|
-
if (
|
|
5537
|
-
if (
|
|
5538
|
-
if (
|
|
5539
|
-
return `${
|
|
5556
|
+
const diffDays2 = Math.ceil(diffTime / (1e3 * 60 * 60 * 24));
|
|
5557
|
+
if (diffDays2 < 0) return "In the future";
|
|
5558
|
+
if (diffDays2 === 0) return "Today";
|
|
5559
|
+
if (diffDays2 === 1) return "Yesterday";
|
|
5560
|
+
return `${diffDays2} days ago`;
|
|
5540
5561
|
};
|
|
5541
5562
|
var getDashboardHeaderTimeInZone = (date = /* @__PURE__ */ new Date(), timezone, timeOptions, locale = DEFAULT_LOCALE) => {
|
|
5542
5563
|
const defaultOptions = {
|
|
@@ -12983,6 +13004,7 @@ var toWorkspaceDetailedMetrics = ({
|
|
|
12983
13004
|
const targetOutput = coerceNumber(data.target_output ?? data.total_day_output, 0);
|
|
12984
13005
|
const idealOutput = coerceNumber(data.ideal_output ?? data.ideal_output_until_now, 0);
|
|
12985
13006
|
const outputDifference = totalActions - idealOutput;
|
|
13007
|
+
const hourlyTargetOutput = Array.isArray(data.hourly_target_output) ? data.hourly_target_output.map((value) => value === null || value === void 0 ? null : coerceNumber(value, 0)) : null;
|
|
12986
13008
|
const hourlyCycleTimes = Array.isArray(data.hourly_cycle_times) ? data.hourly_cycle_times.map((value) => coerceNumber(value, 0)) : [];
|
|
12987
13009
|
const cycleCompletionClipCount = data.cycle_completion_clip_count === null || data.cycle_completion_clip_count === void 0 ? null : coerceNumber(data.cycle_completion_clip_count, 0);
|
|
12988
13010
|
const cycleTimeDataStatus = data.cycle_time_data_status === "missing_clips" ? "missing_clips" : data.cycle_time_data_status === "available" ? "available" : null;
|
|
@@ -13034,6 +13056,7 @@ var toWorkspaceDetailedMetrics = ({
|
|
|
13034
13056
|
avg_efficiency: coerceNumber(data.efficiency ?? data.avg_efficiency, 0),
|
|
13035
13057
|
total_actions: totalActions,
|
|
13036
13058
|
hourly_action_counts: hourlyActionCounts,
|
|
13059
|
+
hourly_target_output: hourlyTargetOutput,
|
|
13037
13060
|
hourly_cycle_times: hourlyCycleTimes,
|
|
13038
13061
|
cycle_completion_clip_count: cycleCompletionClipCount,
|
|
13039
13062
|
cycle_time_data_status: cycleTimeDataStatus,
|
|
@@ -19650,7 +19673,7 @@ function formatRelativeTime(timestamp) {
|
|
|
19650
19673
|
const diffSeconds = Math.floor(diffMs / 1e3);
|
|
19651
19674
|
const diffMinutes = Math.floor(diffSeconds / 60);
|
|
19652
19675
|
const diffHours = Math.floor(diffMinutes / 60);
|
|
19653
|
-
const
|
|
19676
|
+
const diffDays2 = Math.floor(diffHours / 24);
|
|
19654
19677
|
if (diffSeconds < 60) {
|
|
19655
19678
|
return "Less than a minute ago";
|
|
19656
19679
|
}
|
|
@@ -19662,8 +19685,8 @@ function formatRelativeTime(timestamp) {
|
|
|
19662
19685
|
const hourLabel = diffHours === 1 ? "hour" : "hours";
|
|
19663
19686
|
return `${diffHours} ${hourLabel} ago`;
|
|
19664
19687
|
}
|
|
19665
|
-
const dayLabel =
|
|
19666
|
-
return `${
|
|
19688
|
+
const dayLabel = diffDays2 === 1 ? "day" : "days";
|
|
19689
|
+
return `${diffDays2} ${dayLabel} ago`;
|
|
19667
19690
|
} catch (error) {
|
|
19668
19691
|
console.error("[formatRelativeTime] Error formatting timestamp:", error);
|
|
19669
19692
|
return "Unknown";
|
|
@@ -35162,6 +35185,223 @@ var Button = React144.forwardRef(
|
|
|
35162
35185
|
}
|
|
35163
35186
|
);
|
|
35164
35187
|
Button.displayName = "Button";
|
|
35188
|
+
var padTime = (value) => value.toString().padStart(2, "0");
|
|
35189
|
+
var parseTime = (timeValue) => {
|
|
35190
|
+
if (!timeValue) return null;
|
|
35191
|
+
const [hourPart, minutePart] = timeValue.split(":");
|
|
35192
|
+
const hour = Number.parseInt(hourPart, 10);
|
|
35193
|
+
const minute = Number.parseInt(minutePart ?? "0", 10);
|
|
35194
|
+
if (!Number.isFinite(hour) || !Number.isFinite(minute)) return null;
|
|
35195
|
+
return { hour, minute };
|
|
35196
|
+
};
|
|
35197
|
+
var normalizeIdleTimeHourly = (idleTimeHourly) => {
|
|
35198
|
+
if (!idleTimeHourly || typeof idleTimeHourly !== "object") {
|
|
35199
|
+
return {};
|
|
35200
|
+
}
|
|
35201
|
+
return Object.fromEntries(
|
|
35202
|
+
Object.entries(idleTimeHourly).map(([key, value]) => {
|
|
35203
|
+
if (Array.isArray(value)) return [key, value];
|
|
35204
|
+
if (value && Array.isArray(value.values)) {
|
|
35205
|
+
return [key, value.values];
|
|
35206
|
+
}
|
|
35207
|
+
return [key, []];
|
|
35208
|
+
})
|
|
35209
|
+
);
|
|
35210
|
+
};
|
|
35211
|
+
var interpretIdleValue = (value) => {
|
|
35212
|
+
if (value === 1 || value === "1") return "idle";
|
|
35213
|
+
if (value === 0 || value === "0") return "active";
|
|
35214
|
+
if (value === "x" || value === null || value === void 0) return "unknown";
|
|
35215
|
+
return "unknown";
|
|
35216
|
+
};
|
|
35217
|
+
var getShiftDurationMinutes = (shiftStart, shiftEnd) => {
|
|
35218
|
+
const start = parseTime(shiftStart);
|
|
35219
|
+
const end = parseTime(shiftEnd);
|
|
35220
|
+
if (!start || !end) return null;
|
|
35221
|
+
let duration = end.hour * 60 + end.minute - (start.hour * 60 + start.minute);
|
|
35222
|
+
if (duration <= 0) {
|
|
35223
|
+
duration += 24 * 60;
|
|
35224
|
+
}
|
|
35225
|
+
return duration > 0 ? duration : null;
|
|
35226
|
+
};
|
|
35227
|
+
var getShiftElapsedMinutes = ({
|
|
35228
|
+
shiftStart,
|
|
35229
|
+
shiftEnd,
|
|
35230
|
+
shiftDate,
|
|
35231
|
+
timezone,
|
|
35232
|
+
now: now4 = /* @__PURE__ */ new Date()
|
|
35233
|
+
}) => {
|
|
35234
|
+
if (!shiftDate || !timezone) return null;
|
|
35235
|
+
const startTime = parseTime(shiftStart);
|
|
35236
|
+
const endTime = parseTime(shiftEnd);
|
|
35237
|
+
if (!startTime || !endTime) return null;
|
|
35238
|
+
const shiftStartDate = fromZonedTime(
|
|
35239
|
+
`${shiftDate}T${padTime(startTime.hour)}:${padTime(startTime.minute)}:00`,
|
|
35240
|
+
timezone
|
|
35241
|
+
);
|
|
35242
|
+
let shiftEndDate = fromZonedTime(
|
|
35243
|
+
`${shiftDate}T${padTime(endTime.hour)}:${padTime(endTime.minute)}:00`,
|
|
35244
|
+
timezone
|
|
35245
|
+
);
|
|
35246
|
+
if (shiftEndDate <= shiftStartDate) {
|
|
35247
|
+
shiftEndDate = addDays(shiftEndDate, 1);
|
|
35248
|
+
}
|
|
35249
|
+
const shiftMinutes = Math.max(differenceInMinutes(shiftEndDate, shiftStartDate), 0);
|
|
35250
|
+
if (shiftMinutes <= 0) return null;
|
|
35251
|
+
const elapsed = differenceInMinutes(now4, shiftStartDate);
|
|
35252
|
+
return Math.min(Math.max(elapsed, 0), shiftMinutes);
|
|
35253
|
+
};
|
|
35254
|
+
var maskFutureHourlySeries = ({
|
|
35255
|
+
data,
|
|
35256
|
+
shiftStart,
|
|
35257
|
+
shiftEnd,
|
|
35258
|
+
shiftDate,
|
|
35259
|
+
timezone,
|
|
35260
|
+
now: now4 = /* @__PURE__ */ new Date()
|
|
35261
|
+
}) => {
|
|
35262
|
+
if (!Array.isArray(data)) {
|
|
35263
|
+
return [];
|
|
35264
|
+
}
|
|
35265
|
+
const normalizedData = data.map((value) => typeof value === "number" && Number.isFinite(value) ? value : null);
|
|
35266
|
+
if (!normalizedData.length) {
|
|
35267
|
+
return normalizedData;
|
|
35268
|
+
}
|
|
35269
|
+
const shiftMinutes = getShiftDurationMinutes(shiftStart, shiftEnd);
|
|
35270
|
+
const elapsedMinutes = getShiftElapsedMinutes({
|
|
35271
|
+
shiftStart,
|
|
35272
|
+
shiftEnd,
|
|
35273
|
+
shiftDate,
|
|
35274
|
+
timezone,
|
|
35275
|
+
now: now4
|
|
35276
|
+
});
|
|
35277
|
+
if (shiftMinutes === null || elapsedMinutes === null || elapsedMinutes >= shiftMinutes) {
|
|
35278
|
+
return normalizedData;
|
|
35279
|
+
}
|
|
35280
|
+
return normalizedData.map((value, index) => {
|
|
35281
|
+
const slotStartMinutes = index * 60;
|
|
35282
|
+
return slotStartMinutes > elapsedMinutes ? null : value;
|
|
35283
|
+
});
|
|
35284
|
+
};
|
|
35285
|
+
var buildUptimeSeries = ({
|
|
35286
|
+
idleTimeHourly,
|
|
35287
|
+
shiftStart,
|
|
35288
|
+
shiftEnd,
|
|
35289
|
+
shiftDate,
|
|
35290
|
+
timezone,
|
|
35291
|
+
elapsedMinutes
|
|
35292
|
+
}) => {
|
|
35293
|
+
const normalizedIdle = normalizeIdleTimeHourly(idleTimeHourly || {});
|
|
35294
|
+
const hasIdleData = Object.keys(normalizedIdle).length > 0;
|
|
35295
|
+
if (!hasIdleData || !shiftDate || !timezone) {
|
|
35296
|
+
return {
|
|
35297
|
+
points: [],
|
|
35298
|
+
activeMinutes: 0,
|
|
35299
|
+
idleMinutes: 0,
|
|
35300
|
+
availableMinutes: 0,
|
|
35301
|
+
shiftMinutes: 0,
|
|
35302
|
+
elapsedMinutes: 0,
|
|
35303
|
+
hasData: false
|
|
35304
|
+
};
|
|
35305
|
+
}
|
|
35306
|
+
const startTime = parseTime(shiftStart);
|
|
35307
|
+
const endTime = parseTime(shiftEnd);
|
|
35308
|
+
if (!startTime || !endTime) {
|
|
35309
|
+
return {
|
|
35310
|
+
points: [],
|
|
35311
|
+
activeMinutes: 0,
|
|
35312
|
+
idleMinutes: 0,
|
|
35313
|
+
availableMinutes: 0,
|
|
35314
|
+
shiftMinutes: 0,
|
|
35315
|
+
elapsedMinutes: 0,
|
|
35316
|
+
hasData: false
|
|
35317
|
+
};
|
|
35318
|
+
}
|
|
35319
|
+
const shiftStartDate = fromZonedTime(
|
|
35320
|
+
`${shiftDate}T${padTime(startTime.hour)}:${padTime(startTime.minute)}:00`,
|
|
35321
|
+
timezone
|
|
35322
|
+
);
|
|
35323
|
+
let shiftEndDate = fromZonedTime(
|
|
35324
|
+
`${shiftDate}T${padTime(endTime.hour)}:${padTime(endTime.minute)}:00`,
|
|
35325
|
+
timezone
|
|
35326
|
+
);
|
|
35327
|
+
if (shiftEndDate <= shiftStartDate) {
|
|
35328
|
+
shiftEndDate = addDays(shiftEndDate, 1);
|
|
35329
|
+
}
|
|
35330
|
+
const shiftMinutes = Math.max(differenceInMinutes(shiftEndDate, shiftStartDate), 0);
|
|
35331
|
+
if (shiftMinutes <= 0) {
|
|
35332
|
+
return {
|
|
35333
|
+
points: [],
|
|
35334
|
+
activeMinutes: 0,
|
|
35335
|
+
idleMinutes: 0,
|
|
35336
|
+
availableMinutes: 0,
|
|
35337
|
+
shiftMinutes: 0,
|
|
35338
|
+
elapsedMinutes: 0,
|
|
35339
|
+
hasData: false
|
|
35340
|
+
};
|
|
35341
|
+
}
|
|
35342
|
+
const elapsedMinutesClamped = Number.isFinite(elapsedMinutes) ? Math.min(Math.max(Math.floor(elapsedMinutes ?? 0), 0), shiftMinutes) : shiftMinutes;
|
|
35343
|
+
const points = [];
|
|
35344
|
+
let activeMinutes = 0;
|
|
35345
|
+
let idleMinutes = 0;
|
|
35346
|
+
for (let minuteIndex = 0; minuteIndex < shiftMinutes; minuteIndex += 1) {
|
|
35347
|
+
const minuteDate = addMinutes(shiftStartDate, minuteIndex);
|
|
35348
|
+
const timeLabel = formatInTimeZone(minuteDate, timezone, "h:mm a");
|
|
35349
|
+
if (minuteIndex >= elapsedMinutesClamped) {
|
|
35350
|
+
points.push({
|
|
35351
|
+
minuteIndex,
|
|
35352
|
+
timeLabel,
|
|
35353
|
+
uptime: null,
|
|
35354
|
+
status: "unknown"
|
|
35355
|
+
});
|
|
35356
|
+
continue;
|
|
35357
|
+
}
|
|
35358
|
+
const hourKey = formatInTimeZone(minuteDate, timezone, "H");
|
|
35359
|
+
const minuteKey = Number.parseInt(formatInTimeZone(minuteDate, timezone, "m"), 10);
|
|
35360
|
+
const hourBucket = normalizedIdle[hourKey] || [];
|
|
35361
|
+
const value = Array.isArray(hourBucket) ? hourBucket[minuteKey] : void 0;
|
|
35362
|
+
const status = interpretIdleValue(value);
|
|
35363
|
+
if (status === "active") activeMinutes += 1;
|
|
35364
|
+
if (status === "idle") idleMinutes += 1;
|
|
35365
|
+
points.push({
|
|
35366
|
+
minuteIndex,
|
|
35367
|
+
timeLabel,
|
|
35368
|
+
uptime: status === "active" ? 1 : status === "idle" ? 0 : null,
|
|
35369
|
+
status
|
|
35370
|
+
});
|
|
35371
|
+
}
|
|
35372
|
+
return {
|
|
35373
|
+
points,
|
|
35374
|
+
activeMinutes,
|
|
35375
|
+
idleMinutes,
|
|
35376
|
+
availableMinutes: activeMinutes + idleMinutes,
|
|
35377
|
+
shiftMinutes,
|
|
35378
|
+
elapsedMinutes: elapsedMinutesClamped,
|
|
35379
|
+
hasData: activeMinutes + idleMinutes > 0
|
|
35380
|
+
};
|
|
35381
|
+
};
|
|
35382
|
+
var getUptimeUtilizationPercent = (shift) => {
|
|
35383
|
+
const efficiency = shift.efficiency;
|
|
35384
|
+
if (Number.isFinite(efficiency)) {
|
|
35385
|
+
return Math.round(Math.max(0, Math.min(100, Number(efficiency))));
|
|
35386
|
+
}
|
|
35387
|
+
const idleSeconds = Number.isFinite(shift.idleTime) ? Number(shift.idleTime) : 0;
|
|
35388
|
+
const activeSeconds = Number.isFinite(shift.activeTimeSeconds) ? Number(shift.activeTimeSeconds) : null;
|
|
35389
|
+
let availableSeconds = Number.isFinite(shift.availableTimeSeconds) ? Number(shift.availableTimeSeconds) : null;
|
|
35390
|
+
if (availableSeconds === null) {
|
|
35391
|
+
if ((activeSeconds ?? 0) > 0 || idleSeconds > 0) {
|
|
35392
|
+
availableSeconds = (activeSeconds ?? 0) + idleSeconds;
|
|
35393
|
+
} else {
|
|
35394
|
+
return 0;
|
|
35395
|
+
}
|
|
35396
|
+
}
|
|
35397
|
+
if (availableSeconds <= 0) return 0;
|
|
35398
|
+
const clampedIdleSeconds = Math.min(Math.max(idleSeconds, 0), availableSeconds);
|
|
35399
|
+
const productiveSeconds = Math.max(
|
|
35400
|
+
activeSeconds ?? availableSeconds - clampedIdleSeconds,
|
|
35401
|
+
0
|
|
35402
|
+
);
|
|
35403
|
+
return Math.round(productiveSeconds / availableSeconds * 100);
|
|
35404
|
+
};
|
|
35165
35405
|
|
|
35166
35406
|
// src/components/charts/skuDividerUtils.ts
|
|
35167
35407
|
var HOURLY_TIME_RE = /^(\d{1,2}):(\d{2})/;
|
|
@@ -35174,37 +35414,162 @@ var parseTimeOfDay = (timeValue) => {
|
|
|
35174
35414
|
if (hour < 0 || hour > 23 || minute < 0 || minute > 59) return null;
|
|
35175
35415
|
return { hour, minute };
|
|
35176
35416
|
};
|
|
35177
|
-
var
|
|
35178
|
-
|
|
35417
|
+
var parseDateKey = (value) => {
|
|
35418
|
+
const [yearPart, monthPart, dayPart] = value.split("-").map(Number);
|
|
35419
|
+
if (!Number.isFinite(yearPart) || !Number.isFinite(monthPart) || !Number.isFinite(dayPart)) {
|
|
35420
|
+
return null;
|
|
35421
|
+
}
|
|
35422
|
+
return Date.UTC(yearPart, monthPart - 1, dayPart);
|
|
35423
|
+
};
|
|
35424
|
+
var diffDays = (left, right) => {
|
|
35425
|
+
const leftUtc = parseDateKey(left);
|
|
35426
|
+
const rightUtc = parseDateKey(right);
|
|
35427
|
+
if (leftUtc === null || rightUtc === null) return null;
|
|
35428
|
+
return Math.round((leftUtc - rightUtc) / (24 * 60 * 60 * 1e3));
|
|
35429
|
+
};
|
|
35430
|
+
var getSegmentMinutes = (isoString, timeZone, reportDate) => {
|
|
35431
|
+
const date = new Date(isoString);
|
|
35432
|
+
if (Number.isNaN(date.getTime())) return Number.NaN;
|
|
35433
|
+
const formatter = new Intl.DateTimeFormat("en-US", {
|
|
35434
|
+
timeZone,
|
|
35435
|
+
year: "numeric",
|
|
35436
|
+
month: "2-digit",
|
|
35437
|
+
day: "2-digit",
|
|
35438
|
+
hour: "2-digit",
|
|
35439
|
+
minute: "2-digit",
|
|
35440
|
+
hourCycle: "h23"
|
|
35441
|
+
});
|
|
35442
|
+
const parts = formatter.formatToParts(date).reduce((acc, part) => {
|
|
35443
|
+
if (part.type !== "literal") {
|
|
35444
|
+
acc[part.type] = part.value;
|
|
35445
|
+
}
|
|
35446
|
+
return acc;
|
|
35447
|
+
}, {});
|
|
35448
|
+
const dateKey = `${parts.year}-${parts.month}-${parts.day}`;
|
|
35449
|
+
let minutes = Number(parts.hour) * 60 + Number(parts.minute);
|
|
35450
|
+
const dayDelta = diffDays(dateKey, reportDate);
|
|
35451
|
+
if (dayDelta === null) return Number.NaN;
|
|
35452
|
+
minutes += dayDelta * 24 * 60;
|
|
35453
|
+
return minutes;
|
|
35454
|
+
};
|
|
35455
|
+
var computeSegmentOffsetUtc = (segment, shift) => {
|
|
35179
35456
|
const parsedMs = Date.parse(segment.start_time);
|
|
35180
35457
|
if (Number.isNaN(parsedMs)) return null;
|
|
35181
35458
|
const date = new Date(parsedMs);
|
|
35182
35459
|
const segHour = date.getUTCHours();
|
|
35183
35460
|
const segMinute = date.getUTCMinutes();
|
|
35184
35461
|
const segMinutes = segHour * 60 + segMinute;
|
|
35185
|
-
|
|
35462
|
+
const shiftStartMinutes = shift.startHour * 60 + shift.startMinute;
|
|
35186
35463
|
let deltaMinutes = segMinutes - shiftStartMinutes;
|
|
35187
35464
|
if (deltaMinutes < 0) deltaMinutes += 24 * 60;
|
|
35188
35465
|
const offsetHours = deltaMinutes / 60;
|
|
35189
35466
|
if (offsetHours < 0 || offsetHours > shift.slotCount) return null;
|
|
35190
35467
|
return offsetHours;
|
|
35191
35468
|
};
|
|
35469
|
+
var computeSegmentOffset = (segment, shift) => {
|
|
35470
|
+
if (!segment?.start_time) return null;
|
|
35471
|
+
if (shift.shiftDate && shift.timezone) {
|
|
35472
|
+
const segmentMinutes = getSegmentMinutes(
|
|
35473
|
+
segment.start_time,
|
|
35474
|
+
shift.timezone,
|
|
35475
|
+
shift.shiftDate
|
|
35476
|
+
);
|
|
35477
|
+
if (!Number.isFinite(segmentMinutes)) return null;
|
|
35478
|
+
const shiftStartMinutes = shift.startHour * 60 + shift.startMinute;
|
|
35479
|
+
const deltaMinutes = segmentMinutes - shiftStartMinutes;
|
|
35480
|
+
const offsetHours = deltaMinutes / 60;
|
|
35481
|
+
if (offsetHours < 0 || offsetHours > shift.slotCount) return null;
|
|
35482
|
+
return offsetHours;
|
|
35483
|
+
}
|
|
35484
|
+
return computeSegmentOffsetUtc(segment, shift);
|
|
35485
|
+
};
|
|
35192
35486
|
var resolveShiftWindow2 = (params) => {
|
|
35193
35487
|
const startTime = parseTimeOfDay(params.shiftStart);
|
|
35194
35488
|
if (!startTime) return null;
|
|
35195
35489
|
return {
|
|
35196
35490
|
startHour: startTime.hour,
|
|
35197
35491
|
startMinute: startTime.minute,
|
|
35198
|
-
slotCount: params.slotCount
|
|
35492
|
+
slotCount: params.slotCount,
|
|
35493
|
+
...params.shiftDate ? { shiftDate: params.shiftDate } : {},
|
|
35494
|
+
...params.timezone ? { timezone: params.timezone } : {}
|
|
35199
35495
|
};
|
|
35200
35496
|
};
|
|
35497
|
+
var resolveTimelineEndOffset = ({
|
|
35498
|
+
shiftStart,
|
|
35499
|
+
shiftEnd,
|
|
35500
|
+
slotCount,
|
|
35501
|
+
shiftDate,
|
|
35502
|
+
timezone,
|
|
35503
|
+
now: now4
|
|
35504
|
+
}) => {
|
|
35505
|
+
const normalizedSlotCount = Number.isFinite(slotCount) && slotCount > 0 ? slotCount : 0;
|
|
35506
|
+
if (!shiftDate || !timezone) {
|
|
35507
|
+
return normalizedSlotCount;
|
|
35508
|
+
}
|
|
35509
|
+
const shiftMinutes = getShiftDurationMinutes(shiftStart, shiftEnd);
|
|
35510
|
+
const elapsedMinutes = getShiftElapsedMinutes({
|
|
35511
|
+
shiftStart,
|
|
35512
|
+
shiftEnd,
|
|
35513
|
+
shiftDate,
|
|
35514
|
+
timezone,
|
|
35515
|
+
now: now4
|
|
35516
|
+
});
|
|
35517
|
+
if (shiftMinutes === null || elapsedMinutes === null) {
|
|
35518
|
+
return normalizedSlotCount;
|
|
35519
|
+
}
|
|
35520
|
+
if (elapsedMinutes >= shiftMinutes) {
|
|
35521
|
+
return normalizedSlotCount;
|
|
35522
|
+
}
|
|
35523
|
+
return Math.max(0, Math.min(elapsedMinutes / 60, normalizedSlotCount));
|
|
35524
|
+
};
|
|
35525
|
+
var formatSkuRailLabel = (label, segmentWidth, options = {}) => {
|
|
35526
|
+
const horizontalPadding = options.horizontalPadding ?? 8;
|
|
35527
|
+
const minVisibleChars = options.minVisibleChars ?? 4;
|
|
35528
|
+
const averageCharacterWidth = options.averageCharacterWidth ?? 6.6;
|
|
35529
|
+
const compactAverageCharacterWidth = options.compactAverageCharacterWidth ?? 5;
|
|
35530
|
+
const cssTruncation = options.cssTruncation ?? false;
|
|
35531
|
+
const fullLabelThreshold = 6;
|
|
35532
|
+
if (!label) return null;
|
|
35533
|
+
if (!Number.isFinite(segmentWidth) || segmentWidth <= horizontalPadding * 2) return null;
|
|
35534
|
+
const usableWidth = Math.max(segmentWidth - horizontalPadding * 2, 0);
|
|
35535
|
+
const maxChars = Math.floor(usableWidth / averageCharacterWidth);
|
|
35536
|
+
if (maxChars >= Math.max(minVisibleChars, fullLabelThreshold)) {
|
|
35537
|
+
if (label.length <= maxChars || cssTruncation) return label;
|
|
35538
|
+
if (maxChars <= 1) return null;
|
|
35539
|
+
return `${label.slice(0, Math.max(maxChars - 1, 1)).trimEnd()}\u2026`;
|
|
35540
|
+
}
|
|
35541
|
+
const compactLabel = buildCompactSkuRailLabel(label, Math.max(maxChars, 1));
|
|
35542
|
+
const compactMaxChars = Math.floor(usableWidth / compactAverageCharacterWidth);
|
|
35543
|
+
if (compactMaxChars < 1) return null;
|
|
35544
|
+
if (compactLabel.length <= compactMaxChars || cssTruncation) return compactLabel;
|
|
35545
|
+
if (compactMaxChars <= 2) {
|
|
35546
|
+
return compactLabel.slice(0, compactMaxChars);
|
|
35547
|
+
}
|
|
35548
|
+
return `${compactLabel.slice(0, Math.max(compactMaxChars - 1, 1)).trimEnd()}\u2026`;
|
|
35549
|
+
};
|
|
35550
|
+
var buildCompactSkuRailLabel = (label, maxChars) => {
|
|
35551
|
+
const words = label.trim().split(/\s+/).filter(Boolean);
|
|
35552
|
+
if (words.length === 0) return label;
|
|
35553
|
+
const [firstWord] = words;
|
|
35554
|
+
const acronym = words.map((word) => word[0]).join("").toUpperCase();
|
|
35555
|
+
if (maxChars <= 3 && acronym) {
|
|
35556
|
+
return acronym;
|
|
35557
|
+
}
|
|
35558
|
+
if (firstWord.length >= 4) {
|
|
35559
|
+
return firstWord;
|
|
35560
|
+
}
|
|
35561
|
+
return acronym || firstWord;
|
|
35562
|
+
};
|
|
35201
35563
|
var HourlyOutputChartComponent = ({
|
|
35202
35564
|
data,
|
|
35203
35565
|
pphThreshold,
|
|
35566
|
+
hourlyTargetOutput,
|
|
35204
35567
|
shiftStart,
|
|
35205
35568
|
shiftEnd,
|
|
35206
35569
|
showIdleTime = false,
|
|
35207
35570
|
idleTimeHourly,
|
|
35571
|
+
shiftDate,
|
|
35572
|
+
timezone,
|
|
35208
35573
|
skuSegments,
|
|
35209
35574
|
activeSkuId,
|
|
35210
35575
|
className = ""
|
|
@@ -35212,6 +35577,7 @@ var HourlyOutputChartComponent = ({
|
|
|
35212
35577
|
const containerRef = React144__default.useRef(null);
|
|
35213
35578
|
const [containerReady, setContainerReady] = React144__default.useState(false);
|
|
35214
35579
|
const [containerWidth, setContainerWidth] = React144__default.useState(0);
|
|
35580
|
+
const [hoveredSkuRailLabel, setHoveredSkuRailLabel] = React144__default.useState(null);
|
|
35215
35581
|
const idleSlots = React144__default.useMemo(
|
|
35216
35582
|
() => buildHourlyIdleSlots({
|
|
35217
35583
|
idleTimeHourly,
|
|
@@ -35357,14 +35723,54 @@ var HourlyOutputChartComponent = ({
|
|
|
35357
35723
|
}, [containerWidth]);
|
|
35358
35724
|
const shiftWindow = React144__default.useMemo(() => resolveShiftWindow2({
|
|
35359
35725
|
shiftStart,
|
|
35360
|
-
slotCount: SHIFT_DURATION
|
|
35361
|
-
|
|
35726
|
+
slotCount: SHIFT_DURATION,
|
|
35727
|
+
shiftDate,
|
|
35728
|
+
timezone
|
|
35729
|
+
}), [shiftStart, shiftEnd, SHIFT_DURATION, shiftDate, timezone]);
|
|
35730
|
+
const fallbackTimelineEndOffset = React144__default.useMemo(
|
|
35731
|
+
() => resolveTimelineEndOffset({
|
|
35732
|
+
shiftStart,
|
|
35733
|
+
shiftEnd,
|
|
35734
|
+
slotCount: SHIFT_DURATION,
|
|
35735
|
+
shiftDate,
|
|
35736
|
+
timezone
|
|
35737
|
+
}),
|
|
35738
|
+
[shiftStart, shiftEnd, SHIFT_DURATION, shiftDate, timezone]
|
|
35739
|
+
);
|
|
35740
|
+
const observedTimelineEndOffset = React144__default.useMemo(() => {
|
|
35741
|
+
let lastObservedMinute = -1;
|
|
35742
|
+
idleSlots.forEach((slot) => {
|
|
35743
|
+
slot.idleArray.forEach((value, minuteIndex) => {
|
|
35744
|
+
if (value !== "x" && value !== null && value !== void 0) {
|
|
35745
|
+
lastObservedMinute = Math.max(
|
|
35746
|
+
lastObservedMinute,
|
|
35747
|
+
slot.hourIndex * 60 + minuteIndex
|
|
35748
|
+
);
|
|
35749
|
+
}
|
|
35750
|
+
});
|
|
35751
|
+
});
|
|
35752
|
+
if (lastObservedMinute < 0) return null;
|
|
35753
|
+
return Math.min((lastObservedMinute + 1) / 60, SHIFT_DURATION);
|
|
35754
|
+
}, [idleSlots, SHIFT_DURATION]);
|
|
35755
|
+
const timelineEndOffset = observedTimelineEndOffset ?? fallbackTimelineEndOffset;
|
|
35756
|
+
const targetLineEndOffset = React144__default.useMemo(() => {
|
|
35757
|
+
if (timelineEndOffset >= SHIFT_DURATION) {
|
|
35758
|
+
return SHIFT_DURATION;
|
|
35759
|
+
}
|
|
35760
|
+
if (Number.isInteger(timelineEndOffset)) {
|
|
35761
|
+
return timelineEndOffset;
|
|
35762
|
+
}
|
|
35763
|
+
return Math.min(Math.floor(timelineEndOffset) + 1, SHIFT_DURATION);
|
|
35764
|
+
}, [timelineEndOffset, SHIFT_DURATION]);
|
|
35362
35765
|
const skuTimelineSegments = React144__default.useMemo(() => {
|
|
35363
|
-
if (!skuSegments || skuSegments.length === 0 || !shiftWindow)
|
|
35364
|
-
|
|
35365
|
-
|
|
35366
|
-
|
|
35367
|
-
|
|
35766
|
+
if (!skuSegments || skuSegments.length === 0 || !shiftWindow || timelineEndOffset <= 0) {
|
|
35767
|
+
return [];
|
|
35768
|
+
}
|
|
35769
|
+
const withOffsets = skuSegments.flatMap((segment) => {
|
|
35770
|
+
const offset = computeSegmentOffset(segment, shiftWindow);
|
|
35771
|
+
if (offset === null) return [];
|
|
35772
|
+
return [{ segment, offset }];
|
|
35773
|
+
}).sort((a, b) => a.offset - b.offset);
|
|
35368
35774
|
if (withOffsets.length === 0) return [];
|
|
35369
35775
|
const deduped = [];
|
|
35370
35776
|
const DUPLICATE_OFFSET_THRESHOLD = 1 / 60;
|
|
@@ -35378,9 +35784,9 @@ var HourlyOutputChartComponent = ({
|
|
|
35378
35784
|
deduped[0] = { ...deduped[0], offset: 0 };
|
|
35379
35785
|
}
|
|
35380
35786
|
return deduped.map((entry, index) => {
|
|
35381
|
-
const nextOffset = index < deduped.length - 1 ? deduped[index + 1].offset :
|
|
35382
|
-
const start = Math.max(0, Math.min(entry.offset,
|
|
35383
|
-
const end = Math.max(start, Math.min(nextOffset,
|
|
35787
|
+
const nextOffset = index < deduped.length - 1 ? deduped[index + 1].offset : timelineEndOffset;
|
|
35788
|
+
const start = Math.max(0, Math.min(entry.offset, timelineEndOffset));
|
|
35789
|
+
const end = Math.max(start, Math.min(nextOffset, timelineEndOffset));
|
|
35384
35790
|
return {
|
|
35385
35791
|
skuId: entry.segment.sku_id,
|
|
35386
35792
|
label: entry.segment.sku_code,
|
|
@@ -35389,15 +35795,66 @@ var HourlyOutputChartComponent = ({
|
|
|
35389
35795
|
pphThreshold: entry.segment.pph_threshold ?? pphThreshold
|
|
35390
35796
|
};
|
|
35391
35797
|
}).filter((segment) => segment.end > segment.start);
|
|
35392
|
-
}, [skuSegments, shiftWindow,
|
|
35798
|
+
}, [skuSegments, shiftWindow, timelineEndOffset, pphThreshold]);
|
|
35799
|
+
const targetTimelineSegments = React144__default.useMemo(() => {
|
|
35800
|
+
if (skuTimelineSegments.length === 0) return [];
|
|
35801
|
+
return skuTimelineSegments.map((segment, index) => ({
|
|
35802
|
+
...segment,
|
|
35803
|
+
end: index === skuTimelineSegments.length - 1 ? Math.max(segment.start, targetLineEndOffset) : segment.end
|
|
35804
|
+
})).filter((segment) => segment.end > segment.start);
|
|
35805
|
+
}, [skuTimelineSegments, targetLineEndOffset]);
|
|
35806
|
+
const hasHourlyTargetOutputProp = React144__default.useMemo(
|
|
35807
|
+
() => hourlyTargetOutput !== void 0,
|
|
35808
|
+
[hourlyTargetOutput]
|
|
35809
|
+
);
|
|
35810
|
+
const hasExplicitHourlyTargets = React144__default.useMemo(
|
|
35811
|
+
() => Array.isArray(hourlyTargetOutput) && hourlyTargetOutput.some((value) => value !== null && value !== void 0),
|
|
35812
|
+
[hourlyTargetOutput]
|
|
35813
|
+
);
|
|
35814
|
+
const hourlyTargetSegments = React144__default.useMemo(() => {
|
|
35815
|
+
if (!hasExplicitHourlyTargets) return [];
|
|
35816
|
+
const segments = [];
|
|
35817
|
+
let runStart = null;
|
|
35818
|
+
let runValue = null;
|
|
35819
|
+
const flush = (endIndex) => {
|
|
35820
|
+
if (runStart === null || runValue === null) return;
|
|
35821
|
+
segments.push({ start: runStart, end: endIndex, value: runValue });
|
|
35822
|
+
runStart = null;
|
|
35823
|
+
runValue = null;
|
|
35824
|
+
};
|
|
35825
|
+
for (let i = 0; i < SHIFT_DURATION; i += 1) {
|
|
35826
|
+
const rawValue = Array.isArray(hourlyTargetOutput) ? hourlyTargetOutput[i] : null;
|
|
35827
|
+
const value = rawValue === null || rawValue === void 0 ? null : Number(rawValue);
|
|
35828
|
+
if (value === null || !Number.isFinite(value)) {
|
|
35829
|
+
flush(i);
|
|
35830
|
+
continue;
|
|
35831
|
+
}
|
|
35832
|
+
if (runStart === null || runValue === null) {
|
|
35833
|
+
runStart = i;
|
|
35834
|
+
runValue = value;
|
|
35835
|
+
continue;
|
|
35836
|
+
}
|
|
35837
|
+
if (Math.abs(runValue - value) > 1e-6) {
|
|
35838
|
+
flush(i);
|
|
35839
|
+
runStart = i;
|
|
35840
|
+
runValue = value;
|
|
35841
|
+
}
|
|
35842
|
+
}
|
|
35843
|
+
flush(SHIFT_DURATION);
|
|
35844
|
+
return segments.filter((segment) => segment.end > segment.start);
|
|
35845
|
+
}, [SHIFT_DURATION, hasExplicitHourlyTargets, hourlyTargetOutput]);
|
|
35393
35846
|
const activeSkuHourIndices = React144__default.useMemo(() => {
|
|
35394
35847
|
const indices = /* @__PURE__ */ new Set();
|
|
35395
35848
|
const targets = Array(SHIFT_DURATION).fill(pphThreshold);
|
|
35396
|
-
if (!skuSegments || !shiftWindow) return { indices, targets };
|
|
35397
|
-
const segmentsWithOffsets = skuSegments.
|
|
35398
|
-
|
|
35399
|
-
|
|
35400
|
-
|
|
35849
|
+
if (!skuSegments || !shiftWindow) return { indices, targets, hasTimeline: false };
|
|
35850
|
+
const segmentsWithOffsets = skuSegments.flatMap((segment) => {
|
|
35851
|
+
const offset = computeSegmentOffset(segment, shiftWindow);
|
|
35852
|
+
if (offset === null) return [];
|
|
35853
|
+
return [{ ...segment, offset }];
|
|
35854
|
+
}).sort((a, b) => a.offset - b.offset);
|
|
35855
|
+
if (segmentsWithOffsets.length === 0) {
|
|
35856
|
+
return { indices, targets, hasTimeline: false };
|
|
35857
|
+
}
|
|
35401
35858
|
for (let i = 0; i < SHIFT_DURATION; i++) {
|
|
35402
35859
|
const midpoint = i + 0.5;
|
|
35403
35860
|
let activeSeg = segmentsWithOffsets[0];
|
|
@@ -35417,13 +35874,15 @@ var HourlyOutputChartComponent = ({
|
|
|
35417
35874
|
}
|
|
35418
35875
|
}
|
|
35419
35876
|
}
|
|
35420
|
-
return { indices, targets };
|
|
35877
|
+
return { indices, targets, hasTimeline: true };
|
|
35421
35878
|
}, [skuSegments, activeSkuId, shiftWindow, SHIFT_DURATION, pphThreshold]);
|
|
35422
35879
|
const chartData = React144__default.useMemo(() => {
|
|
35423
|
-
const { indices, targets } = activeSkuHourIndices;
|
|
35880
|
+
const { indices, targets, hasTimeline } = activeSkuHourIndices;
|
|
35424
35881
|
return Array.from({ length: SHIFT_DURATION }, (_, i) => {
|
|
35425
35882
|
const idleSlot = idleSlots[i];
|
|
35426
|
-
const
|
|
35883
|
+
const explicitTarget = hasHourlyTargetOutputProp ? hourlyTargetOutput?.[i] ?? null : void 0;
|
|
35884
|
+
const currentTarget = hasHourlyTargetOutputProp ? explicitTarget : targets[i] || pphThreshold;
|
|
35885
|
+
const comparisonTarget = currentTarget === null || currentTarget === void 0 ? targets[i] || pphThreshold : currentTarget;
|
|
35427
35886
|
return {
|
|
35428
35887
|
hourIndex: idleSlot?.hourIndex ?? i,
|
|
35429
35888
|
hour: idleSlot?.hour || "",
|
|
@@ -35431,16 +35890,16 @@ var HourlyOutputChartComponent = ({
|
|
|
35431
35890
|
output: animatedData[i] || 0,
|
|
35432
35891
|
originalOutput: data[i] || 0,
|
|
35433
35892
|
// Keep original data for labels
|
|
35434
|
-
target: currentTarget,
|
|
35435
|
-
color: (animatedData[i] || 0) >=
|
|
35893
|
+
target: currentTarget ?? null,
|
|
35894
|
+
color: (animatedData[i] || 0) >= comparisonTarget ? "#00AB45" : "#E34329",
|
|
35436
35895
|
idleMinutes: idleSlot?.idleMinutes || 0,
|
|
35437
35896
|
idleArray: idleSlot?.idleArray || [],
|
|
35438
35897
|
skuIndex: i,
|
|
35439
35898
|
isHighlighted: indices.has(i),
|
|
35440
|
-
isDimmed: !!activeSkuId && !indices.has(i)
|
|
35899
|
+
isDimmed: hasTimeline && !!activeSkuId && !indices.has(i)
|
|
35441
35900
|
};
|
|
35442
35901
|
});
|
|
35443
|
-
}, [animatedData, data, pphThreshold, idleSlots, SHIFT_DURATION, activeSkuHourIndices, activeSkuId]);
|
|
35902
|
+
}, [animatedData, data, pphThreshold, idleSlots, SHIFT_DURATION, activeSkuHourIndices, activeSkuId, hourlyTargetOutput, hasHourlyTargetOutputProp]);
|
|
35444
35903
|
const renderSkuTimelineRail = React144__default.useCallback((props) => {
|
|
35445
35904
|
if (!skuTimelineSegments.length || SHIFT_DURATION <= 0) return null;
|
|
35446
35905
|
const offset = props?.offset;
|
|
@@ -35452,8 +35911,9 @@ var HourlyOutputChartComponent = ({
|
|
|
35452
35911
|
const railHeight = 3;
|
|
35453
35912
|
const railY = top - 10;
|
|
35454
35913
|
const baselineY = railY + railHeight / 2;
|
|
35455
|
-
const
|
|
35456
|
-
|
|
35914
|
+
const showHoverLabel = (label, centerX, rY) => {
|
|
35915
|
+
setHoveredSkuRailLabel({ label, centerX, railY: rY });
|
|
35916
|
+
};
|
|
35457
35917
|
return /* @__PURE__ */ jsxs("g", { children: [
|
|
35458
35918
|
/* @__PURE__ */ jsx(
|
|
35459
35919
|
"line",
|
|
@@ -35471,9 +35931,43 @@ var HourlyOutputChartComponent = ({
|
|
|
35471
35931
|
const xStart = left + segment.start / SHIFT_DURATION * width;
|
|
35472
35932
|
const xEnd = left + segment.end / SHIFT_DURATION * width;
|
|
35473
35933
|
const segmentWidth = Math.max(1, xEnd - xStart);
|
|
35934
|
+
const labelPadding = segmentWidth < 48 ? 4 : 8;
|
|
35935
|
+
const inlineLabelText = formatSkuRailLabel(segment.label, segmentWidth, {
|
|
35936
|
+
horizontalPadding: labelPadding,
|
|
35937
|
+
cssTruncation: true
|
|
35938
|
+
});
|
|
35939
|
+
const badgeLabelText = formatSkuRailLabel(segment.label, 28, {
|
|
35940
|
+
horizontalPadding: 4,
|
|
35941
|
+
cssTruncation: true
|
|
35942
|
+
});
|
|
35943
|
+
const isMicroSegment = segmentWidth < 18;
|
|
35944
|
+
const labelText = isMicroSegment ? badgeLabelText : inlineLabelText;
|
|
35945
|
+
const labelClipWidth = Math.max(segmentWidth - labelPadding * 2, 0);
|
|
35474
35946
|
const isActive = !!activeSkuId && segment.skuId === activeSkuId;
|
|
35475
35947
|
const isDimmed = !!activeSkuId && segment.skuId !== activeSkuId;
|
|
35948
|
+
const hoverHitWidth = Math.max(segmentWidth + 12, isMicroSegment ? 20 : segmentWidth);
|
|
35949
|
+
const hoverHitX = Math.max(
|
|
35950
|
+
left,
|
|
35951
|
+
Math.min(xStart - (hoverHitWidth - segmentWidth) / 2, left + width - hoverHitWidth)
|
|
35952
|
+
);
|
|
35953
|
+
const hoverHitHeight = isMicroSegment ? 34 : 28;
|
|
35954
|
+
const hoverHitY = railY - (isMicroSegment ? 30 : 24);
|
|
35955
|
+
const microBadgeWidth = labelText ? Math.max(labelText.length * 6.2 + 10, 18) : 0;
|
|
35956
|
+
const microBadgeX = xStart + segmentWidth / 2 - microBadgeWidth / 2;
|
|
35957
|
+
const microBadgeY = railY - 24;
|
|
35476
35958
|
return /* @__PURE__ */ jsxs("g", { children: [
|
|
35959
|
+
/* @__PURE__ */ jsx(
|
|
35960
|
+
"rect",
|
|
35961
|
+
{
|
|
35962
|
+
x: hoverHitX,
|
|
35963
|
+
y: hoverHitY,
|
|
35964
|
+
width: hoverHitWidth,
|
|
35965
|
+
height: hoverHitHeight,
|
|
35966
|
+
fill: "transparent",
|
|
35967
|
+
onMouseEnter: () => showHoverLabel(segment.label, xStart + segmentWidth / 2, railY),
|
|
35968
|
+
onMouseLeave: () => setHoveredSkuRailLabel((current) => current?.label === segment.label ? null : current)
|
|
35969
|
+
}
|
|
35970
|
+
),
|
|
35477
35971
|
/* @__PURE__ */ jsx(
|
|
35478
35972
|
"rect",
|
|
35479
35973
|
{
|
|
@@ -35484,7 +35978,7 @@ var HourlyOutputChartComponent = ({
|
|
|
35484
35978
|
rx: 1.5,
|
|
35485
35979
|
fill: isActive ? "#3b82f6" : "#cbd5e1",
|
|
35486
35980
|
opacity: isDimmed ? 0.3 : 1,
|
|
35487
|
-
style: { transition: "all 0.3s ease" }
|
|
35981
|
+
style: { transition: "all 0.3s ease", pointerEvents: "none" }
|
|
35488
35982
|
}
|
|
35489
35983
|
),
|
|
35490
35984
|
index > 0 && /* @__PURE__ */ jsx(
|
|
@@ -35496,22 +35990,59 @@ var HourlyOutputChartComponent = ({
|
|
|
35496
35990
|
y2: railY + railHeight + 3,
|
|
35497
35991
|
stroke: "#94a3b8",
|
|
35498
35992
|
strokeWidth: 1,
|
|
35499
|
-
opacity: 0.6
|
|
35993
|
+
opacity: 0.6,
|
|
35994
|
+
style: { pointerEvents: "none" }
|
|
35500
35995
|
}
|
|
35501
35996
|
),
|
|
35502
|
-
|
|
35503
|
-
|
|
35997
|
+
isMicroSegment && labelText && /* @__PURE__ */ jsxs("g", { style: { pointerEvents: "none" }, children: [
|
|
35998
|
+
/* @__PURE__ */ jsx(
|
|
35999
|
+
"rect",
|
|
36000
|
+
{
|
|
36001
|
+
x: microBadgeX,
|
|
36002
|
+
y: microBadgeY,
|
|
36003
|
+
width: microBadgeWidth,
|
|
36004
|
+
height: 14,
|
|
36005
|
+
rx: 7,
|
|
36006
|
+
fill: "white",
|
|
36007
|
+
stroke: isActive ? "#3b82f6" : "#cbd5e1",
|
|
36008
|
+
strokeWidth: 1,
|
|
36009
|
+
opacity: isDimmed ? 0.55 : 0.98
|
|
36010
|
+
}
|
|
36011
|
+
),
|
|
36012
|
+
/* @__PURE__ */ jsx(
|
|
36013
|
+
"text",
|
|
36014
|
+
{
|
|
36015
|
+
x: xStart + segmentWidth / 2,
|
|
36016
|
+
y: microBadgeY + 10,
|
|
36017
|
+
textAnchor: "middle",
|
|
36018
|
+
fontSize: 8,
|
|
36019
|
+
fontWeight: 700,
|
|
36020
|
+
fill: isActive ? "#2563eb" : "#64748b",
|
|
36021
|
+
opacity: isDimmed ? 0.55 : 1,
|
|
36022
|
+
style: { transition: "all 0.3s ease" },
|
|
36023
|
+
children: labelText
|
|
36024
|
+
}
|
|
36025
|
+
)
|
|
36026
|
+
] }),
|
|
36027
|
+
!isMicroSegment && labelText && labelClipWidth > 0 && /* @__PURE__ */ jsx(
|
|
36028
|
+
"foreignObject",
|
|
35504
36029
|
{
|
|
35505
|
-
x: xStart +
|
|
35506
|
-
y:
|
|
35507
|
-
|
|
35508
|
-
|
|
35509
|
-
|
|
35510
|
-
|
|
35511
|
-
|
|
35512
|
-
|
|
35513
|
-
|
|
35514
|
-
|
|
36030
|
+
x: xStart + labelPadding,
|
|
36031
|
+
y: railY - 24,
|
|
36032
|
+
width: labelClipWidth,
|
|
36033
|
+
height: 18,
|
|
36034
|
+
style: { pointerEvents: "none", overflow: "visible" },
|
|
36035
|
+
children: /* @__PURE__ */ jsx(
|
|
36036
|
+
"div",
|
|
36037
|
+
{
|
|
36038
|
+
className: `w-full h-full flex items-center justify-center text-[10px] font-bold tracking-[0.02em] truncate pt-0.5 ${isActive ? "text-blue-600" : "text-slate-500"}`,
|
|
36039
|
+
style: {
|
|
36040
|
+
opacity: isDimmed ? 0.4 : 1,
|
|
36041
|
+
transition: "all 0.3s ease"
|
|
36042
|
+
},
|
|
36043
|
+
children: labelText
|
|
36044
|
+
}
|
|
36045
|
+
)
|
|
35515
36046
|
}
|
|
35516
36047
|
)
|
|
35517
36048
|
] }, `sku-rail-${segment.skuId}-${segment.start}-${index}`);
|
|
@@ -35569,14 +36100,17 @@ var HourlyOutputChartComponent = ({
|
|
|
35569
36100
|
);
|
|
35570
36101
|
}, [idleBarState.visible, idleBarState.key, idleBarState.shouldAnimate]);
|
|
35571
36102
|
const maxDataValue = Math.max(...data, 0);
|
|
35572
|
-
const
|
|
36103
|
+
const numericChartTargets = chartData.map((d) => d.target).filter((target) => target !== null && Number.isFinite(target));
|
|
36104
|
+
const maxTargetValue = Math.max(...numericChartTargets, pphThreshold, 0);
|
|
35573
36105
|
const maxYValue = Math.max(
|
|
35574
36106
|
Math.ceil(maxTargetValue * 1.5),
|
|
35575
36107
|
Math.ceil(maxDataValue * 1.15)
|
|
35576
36108
|
// Add 15% headroom above max value
|
|
35577
36109
|
);
|
|
35578
36110
|
const generateYAxisTicks = () => {
|
|
35579
|
-
const uniqueTargets = [...new Set(
|
|
36111
|
+
const uniqueTargets = [...new Set(
|
|
36112
|
+
chartData.map((d) => d.target).filter((target) => target !== null && Number.isFinite(target)).map((target) => Math.round(target))
|
|
36113
|
+
)].sort((a, b) => a - b);
|
|
35580
36114
|
const rawTicks = [0];
|
|
35581
36115
|
uniqueTargets.forEach((target) => {
|
|
35582
36116
|
if (target > 0) {
|
|
@@ -35611,14 +36145,54 @@ var HourlyOutputChartComponent = ({
|
|
|
35611
36145
|
};
|
|
35612
36146
|
const renderTargetLine = React144__default.useCallback((props) => {
|
|
35613
36147
|
const { offset, yAxisMap } = props;
|
|
35614
|
-
if (!offset || !yAxisMap || SHIFT_DURATION <= 0) return null;
|
|
36148
|
+
if (!offset || !yAxisMap || SHIFT_DURATION <= 0 || targetLineEndOffset <= 0) return null;
|
|
35615
36149
|
const { left, width } = offset;
|
|
35616
36150
|
const yAxis = yAxisMap["default"] || yAxisMap[0];
|
|
35617
36151
|
if (!yAxis || !yAxis.scale) return null;
|
|
35618
36152
|
const lines = [];
|
|
35619
36153
|
const offsetToX = (o) => left + o / SHIFT_DURATION * width;
|
|
35620
|
-
if (
|
|
35621
|
-
|
|
36154
|
+
if (hasHourlyTargetOutputProp && hourlyTargetSegments.length > 0) {
|
|
36155
|
+
hourlyTargetSegments.forEach((segment, index) => {
|
|
36156
|
+
const y = yAxis.scale(segment.value);
|
|
36157
|
+
const xStart = offsetToX(segment.start);
|
|
36158
|
+
const xEnd = offsetToX(segment.end);
|
|
36159
|
+
lines.push(
|
|
36160
|
+
/* @__PURE__ */ jsx(
|
|
36161
|
+
"line",
|
|
36162
|
+
{
|
|
36163
|
+
x1: xStart,
|
|
36164
|
+
y1: y,
|
|
36165
|
+
x2: xEnd,
|
|
36166
|
+
y2: y,
|
|
36167
|
+
stroke: "#E34329",
|
|
36168
|
+
strokeDasharray: "3 3",
|
|
36169
|
+
strokeWidth: 2
|
|
36170
|
+
},
|
|
36171
|
+
`target-hourly-h-${index}`
|
|
36172
|
+
)
|
|
36173
|
+
);
|
|
36174
|
+
const next = hourlyTargetSegments[index + 1];
|
|
36175
|
+
if (next && Math.abs(next.value - segment.value) > 1e-6) {
|
|
36176
|
+
const nextY = yAxis.scale(next.value);
|
|
36177
|
+
lines.push(
|
|
36178
|
+
/* @__PURE__ */ jsx(
|
|
36179
|
+
"line",
|
|
36180
|
+
{
|
|
36181
|
+
x1: xEnd,
|
|
36182
|
+
y1: y,
|
|
36183
|
+
x2: xEnd,
|
|
36184
|
+
y2: nextY,
|
|
36185
|
+
stroke: "#E34329",
|
|
36186
|
+
strokeDasharray: "3 3",
|
|
36187
|
+
strokeWidth: 2
|
|
36188
|
+
},
|
|
36189
|
+
`target-hourly-v-${index}`
|
|
36190
|
+
)
|
|
36191
|
+
);
|
|
36192
|
+
}
|
|
36193
|
+
});
|
|
36194
|
+
} else if (!hasHourlyTargetOutputProp && targetTimelineSegments.length > 0) {
|
|
36195
|
+
targetTimelineSegments.forEach((segment, index) => {
|
|
35622
36196
|
const target = segment.pphThreshold || pphThreshold;
|
|
35623
36197
|
const y = yAxis.scale(target);
|
|
35624
36198
|
const xStart = offsetToX(segment.start);
|
|
@@ -35638,7 +36212,7 @@ var HourlyOutputChartComponent = ({
|
|
|
35638
36212
|
`target-h-${index}`
|
|
35639
36213
|
)
|
|
35640
36214
|
);
|
|
35641
|
-
const next =
|
|
36215
|
+
const next = targetTimelineSegments[index + 1];
|
|
35642
36216
|
if (next) {
|
|
35643
36217
|
const nextTarget = next.pphThreshold || pphThreshold;
|
|
35644
36218
|
if (nextTarget !== target) {
|
|
@@ -35661,7 +36235,7 @@ var HourlyOutputChartComponent = ({
|
|
|
35661
36235
|
}
|
|
35662
36236
|
}
|
|
35663
36237
|
});
|
|
35664
|
-
} else {
|
|
36238
|
+
} else if (!hasHourlyTargetOutputProp) {
|
|
35665
36239
|
const y = yAxis.scale(pphThreshold);
|
|
35666
36240
|
lines.push(
|
|
35667
36241
|
/* @__PURE__ */ jsx(
|
|
@@ -35680,10 +36254,13 @@ var HourlyOutputChartComponent = ({
|
|
|
35680
36254
|
);
|
|
35681
36255
|
}
|
|
35682
36256
|
return /* @__PURE__ */ jsx("g", { children: lines });
|
|
35683
|
-
}, [
|
|
36257
|
+
}, [hourlyTargetSegments, targetTimelineSegments, SHIFT_DURATION, pphThreshold, targetLineEndOffset, hasHourlyTargetOutputProp]);
|
|
35684
36258
|
const renderLegend = () => {
|
|
35685
|
-
const uniqueTargets = [...new Set(
|
|
35686
|
-
|
|
36259
|
+
const uniqueTargets = [...new Set(
|
|
36260
|
+
chartData.map((d) => d.target).filter((target) => target !== null && Number.isFinite(target)).map((target) => Math.round(target))
|
|
36261
|
+
)].sort((a, b) => a - b);
|
|
36262
|
+
const unitLabel = hasHourlyTargetOutputProp ? "units" : "units/hr";
|
|
36263
|
+
const targetText = uniqueTargets.length === 0 ? `Target` : uniqueTargets.length === 1 ? `Target: ${uniqueTargets[0]} ${unitLabel}` : `Target: ${uniqueTargets[0]} - ${uniqueTargets[uniqueTargets.length - 1]} ${unitLabel}`;
|
|
35687
36264
|
return /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center text-sm text-gray-600 bg-white py-1", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border border-gray-100 rounded-full px-3 py-1", children: [
|
|
35688
36265
|
/* @__PURE__ */ jsx("div", { className: "w-8 flex items-center", children: /* @__PURE__ */ jsx("div", { className: "w-full border-t-2 border-[#E34329] border-dashed" }) }),
|
|
35689
36266
|
/* @__PURE__ */ jsx("span", { children: targetText })
|
|
@@ -35696,254 +36273,274 @@ var HourlyOutputChartComponent = ({
|
|
|
35696
36273
|
className: `w-full h-full min-w-0 flex flex-col ${className}`,
|
|
35697
36274
|
style: { minHeight: "200px", minWidth: 0 },
|
|
35698
36275
|
children: [
|
|
35699
|
-
containerReady ? /* @__PURE__ */
|
|
35700
|
-
|
|
35701
|
-
|
|
35702
|
-
|
|
35703
|
-
|
|
35704
|
-
|
|
35705
|
-
|
|
35706
|
-
|
|
35707
|
-
|
|
35708
|
-
|
|
35709
|
-
|
|
35710
|
-
|
|
35711
|
-
|
|
35712
|
-
|
|
35713
|
-
|
|
35714
|
-
|
|
35715
|
-
|
|
35716
|
-
|
|
35717
|
-
|
|
35718
|
-
|
|
35719
|
-
|
|
35720
|
-
|
|
35721
|
-
|
|
35722
|
-
|
|
35723
|
-
|
|
35724
|
-
|
|
35725
|
-
|
|
35726
|
-
|
|
35727
|
-
|
|
35728
|
-
),
|
|
35729
|
-
/* @__PURE__ */ jsx(
|
|
35730
|
-
XAxis,
|
|
35731
|
-
{
|
|
35732
|
-
xAxisId: "sku",
|
|
35733
|
-
type: "number",
|
|
35734
|
-
dataKey: "skuIndex",
|
|
35735
|
-
domain: [0, Math.max(SHIFT_DURATION, 0)],
|
|
35736
|
-
hide: true,
|
|
35737
|
-
allowDataOverflow: true
|
|
35738
|
-
}
|
|
35739
|
-
),
|
|
35740
|
-
/* @__PURE__ */ jsx(
|
|
35741
|
-
YAxis,
|
|
35742
|
-
{
|
|
35743
|
-
yAxisId: "default",
|
|
35744
|
-
tickMargin: 8,
|
|
35745
|
-
width: 48,
|
|
35746
|
-
domain: [0, maxYValue],
|
|
35747
|
-
ticks: generateYAxisTicks(),
|
|
35748
|
-
tickFormatter: (value) => value,
|
|
35749
|
-
tick: (props) => {
|
|
35750
|
-
const { x, y, payload } = props;
|
|
35751
|
-
return /* @__PURE__ */ jsx("g", { transform: `translate(${x},${y})`, children: /* @__PURE__ */ jsx(
|
|
35752
|
-
"text",
|
|
35753
|
-
{
|
|
35754
|
-
x: -2,
|
|
35755
|
-
y: 0,
|
|
35756
|
-
dy: 4,
|
|
35757
|
-
textAnchor: "end",
|
|
35758
|
-
fill: "#666",
|
|
35759
|
-
fontSize: 12,
|
|
35760
|
-
children: payload.value
|
|
35761
|
-
},
|
|
35762
|
-
`tick-${payload.value}-${x}-${y}`
|
|
35763
|
-
) });
|
|
36276
|
+
containerReady ? /* @__PURE__ */ jsxs("div", { className: "flex-1 min-h-0 relative", children: [
|
|
36277
|
+
/* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
|
|
36278
|
+
BarChart$1,
|
|
36279
|
+
{
|
|
36280
|
+
data: chartData,
|
|
36281
|
+
margin: {
|
|
36282
|
+
// Reserve headroom for the SKU timeline rail + staggered
|
|
36283
|
+
// labels only when SKU segments are rendered. Non-SKU charts
|
|
36284
|
+
// keep the original 10px top so recharts has enough vertical
|
|
36285
|
+
// space to show the target (pph) tick label on the Y-axis.
|
|
36286
|
+
top: skuTimelineSegments.length > 0 ? 40 : 10,
|
|
36287
|
+
right: 10,
|
|
36288
|
+
bottom: 10,
|
|
36289
|
+
left: 6
|
|
36290
|
+
},
|
|
36291
|
+
barCategoryGap: "25%",
|
|
36292
|
+
children: [
|
|
36293
|
+
/* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", vertical: false }),
|
|
36294
|
+
/* @__PURE__ */ jsx(
|
|
36295
|
+
XAxis,
|
|
36296
|
+
{
|
|
36297
|
+
xAxisId: "default",
|
|
36298
|
+
dataKey: "hour",
|
|
36299
|
+
tick: { fontSize: xAxisConfig.tickFont },
|
|
36300
|
+
interval: xAxisConfig.interval,
|
|
36301
|
+
angle: xAxisConfig.angle,
|
|
36302
|
+
textAnchor: "end",
|
|
36303
|
+
tickMargin: xAxisConfig.tickMargin,
|
|
36304
|
+
height: xAxisConfig.height
|
|
35764
36305
|
}
|
|
35765
|
-
|
|
35766
|
-
|
|
35767
|
-
|
|
35768
|
-
|
|
35769
|
-
|
|
35770
|
-
|
|
35771
|
-
|
|
35772
|
-
|
|
35773
|
-
|
|
35774
|
-
|
|
35775
|
-
|
|
35776
|
-
|
|
35777
|
-
|
|
35778
|
-
|
|
35779
|
-
|
|
35780
|
-
|
|
35781
|
-
|
|
35782
|
-
|
|
35783
|
-
|
|
35784
|
-
|
|
35785
|
-
|
|
35786
|
-
|
|
35787
|
-
|
|
35788
|
-
|
|
35789
|
-
|
|
35790
|
-
|
|
35791
|
-
|
|
35792
|
-
|
|
35793
|
-
|
|
35794
|
-
|
|
35795
|
-
|
|
35796
|
-
|
|
35797
|
-
|
|
35798
|
-
|
|
35799
|
-
|
|
35800
|
-
|
|
35801
|
-
|
|
35802
|
-
|
|
35803
|
-
|
|
35804
|
-
|
|
35805
|
-
|
|
35806
|
-
|
|
35807
|
-
|
|
35808
|
-
|
|
35809
|
-
|
|
35810
|
-
|
|
35811
|
-
|
|
36306
|
+
),
|
|
36307
|
+
/* @__PURE__ */ jsx(
|
|
36308
|
+
XAxis,
|
|
36309
|
+
{
|
|
36310
|
+
xAxisId: "sku",
|
|
36311
|
+
type: "number",
|
|
36312
|
+
dataKey: "skuIndex",
|
|
36313
|
+
domain: [0, Math.max(SHIFT_DURATION, 0)],
|
|
36314
|
+
hide: true,
|
|
36315
|
+
allowDataOverflow: true
|
|
36316
|
+
}
|
|
36317
|
+
),
|
|
36318
|
+
/* @__PURE__ */ jsx(
|
|
36319
|
+
YAxis,
|
|
36320
|
+
{
|
|
36321
|
+
yAxisId: "default",
|
|
36322
|
+
tickMargin: 8,
|
|
36323
|
+
width: 48,
|
|
36324
|
+
domain: [0, maxYValue],
|
|
36325
|
+
ticks: generateYAxisTicks(),
|
|
36326
|
+
tickFormatter: (value) => value,
|
|
36327
|
+
tick: (props) => {
|
|
36328
|
+
const { x, y, payload } = props;
|
|
36329
|
+
return /* @__PURE__ */ jsx("g", { transform: `translate(${x},${y})`, children: /* @__PURE__ */ jsx(
|
|
36330
|
+
"text",
|
|
36331
|
+
{
|
|
36332
|
+
x: -2,
|
|
36333
|
+
y: 0,
|
|
36334
|
+
dy: 4,
|
|
36335
|
+
textAnchor: "end",
|
|
36336
|
+
fill: "#666",
|
|
36337
|
+
fontSize: 12,
|
|
36338
|
+
children: payload.value
|
|
36339
|
+
},
|
|
36340
|
+
`tick-${payload.value}-${x}-${y}`
|
|
36341
|
+
) });
|
|
36342
|
+
}
|
|
36343
|
+
}
|
|
36344
|
+
),
|
|
36345
|
+
/* @__PURE__ */ jsx(YAxis, { yAxisId: "idle", domain: [0, 60], hide: true }),
|
|
36346
|
+
/* @__PURE__ */ jsx(
|
|
36347
|
+
Tooltip,
|
|
36348
|
+
{
|
|
36349
|
+
cursor: { fill: "#f1f5f9" },
|
|
36350
|
+
contentStyle: { backgroundColor: "transparent", border: "none", padding: 0 },
|
|
36351
|
+
content: (props) => {
|
|
36352
|
+
if (!props.active || !props.payload || props.payload.length === 0)
|
|
36353
|
+
return null;
|
|
36354
|
+
const data2 = props.payload[0].payload;
|
|
36355
|
+
const idlePeriods = showIdleTime ? getHourlyIdlePeriods({
|
|
36356
|
+
idleArray: data2.idleArray,
|
|
36357
|
+
shiftStart,
|
|
36358
|
+
hourIndex: Number.isFinite(data2.hourIndex) ? data2.hourIndex : 0
|
|
36359
|
+
}) : [];
|
|
36360
|
+
return /* @__PURE__ */ jsxs("div", { className: "bg-white/95 backdrop-blur-md border border-slate-200/60 shadow-xl shadow-slate-200/40 rounded-xl p-4 min-w-[240px] text-slate-700", children: [
|
|
36361
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-between mb-4 pb-3 border-b border-slate-100", children: /* @__PURE__ */ jsx("p", { className: "font-semibold text-slate-900 text-sm tracking-tight", children: data2.timeRange }) }),
|
|
36362
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
36363
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
36364
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm text-slate-500 font-medium tracking-wide", children: "Output" }),
|
|
36365
|
+
/* @__PURE__ */ jsxs("span", { className: "font-bold text-slate-900 text-sm", children: [
|
|
36366
|
+
Math.round(data2.output),
|
|
36367
|
+
" ",
|
|
36368
|
+
/* @__PURE__ */ jsx("span", { className: "text-slate-400 font-normal text-xs ml-0.5", children: "units" })
|
|
36369
|
+
] })
|
|
36370
|
+
] }),
|
|
36371
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
36372
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm text-slate-500 font-medium tracking-wide", children: "Target" }),
|
|
36373
|
+
/* @__PURE__ */ jsxs("span", { className: "font-bold text-slate-700 text-sm", children: [
|
|
36374
|
+
Math.round(data2.target),
|
|
36375
|
+
" ",
|
|
36376
|
+
/* @__PURE__ */ jsx("span", { className: "text-slate-400 font-normal text-xs ml-0.5", children: "units" })
|
|
36377
|
+
] })
|
|
36378
|
+
] }),
|
|
36379
|
+
showIdleTime && data2.idleMinutes > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
36380
|
+
/* @__PURE__ */ jsx("div", { className: "pt-3 mt-3 border-t border-slate-100", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
36381
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm text-slate-500 font-medium tracking-wide", children: "Idle Time" }),
|
|
36382
|
+
/* @__PURE__ */ jsxs("span", { className: "font-bold text-orange-600 text-sm flex items-center gap-1.5", children: [
|
|
36383
|
+
/* @__PURE__ */ jsx("span", { className: "w-1.5 h-1.5 rounded-full bg-orange-500 shadow-[0_0_6px_rgba(249,115,22,0.6)] animate-pulse" }),
|
|
36384
|
+
data2.idleMinutes,
|
|
36385
|
+
" ",
|
|
36386
|
+
/* @__PURE__ */ jsx("span", { className: "text-orange-500/70 font-normal text-xs ml-0.5", children: "min" })
|
|
36387
|
+
] })
|
|
36388
|
+
] }) }),
|
|
36389
|
+
idlePeriods.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mt-3 bg-slate-50/80 rounded-lg p-3 border border-slate-100/50", children: [
|
|
36390
|
+
/* @__PURE__ */ jsx("p", { className: "font-semibold text-slate-400 text-[10px] mb-2.5 uppercase tracking-wider", children: "Idle Periods" }),
|
|
36391
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-2.5 max-h-32 overflow-y-auto pr-1 custom-scrollbar", children: idlePeriods.map((period, index) => {
|
|
36392
|
+
return /* @__PURE__ */ jsxs(
|
|
36393
|
+
"div",
|
|
36394
|
+
{
|
|
36395
|
+
className: "flex items-start gap-2.5 text-xs",
|
|
36396
|
+
children: [
|
|
36397
|
+
/* @__PURE__ */ jsx("div", { className: "mt-[5px] w-1.5 h-1.5 bg-orange-400 rounded-full flex-shrink-0 shadow-[0_0_4px_rgba(251,146,60,0.5)]" }),
|
|
36398
|
+
/* @__PURE__ */ jsx("span", { className: "text-slate-700 font-medium tracking-tight", children: period.duration === 1 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
36399
|
+
period.startTime,
|
|
36400
|
+
" ",
|
|
36401
|
+
/* @__PURE__ */ jsxs("span", { className: "text-slate-400 font-normal ml-1", children: [
|
|
36402
|
+
"(",
|
|
36403
|
+
period.duration,
|
|
36404
|
+
"m)"
|
|
36405
|
+
] })
|
|
36406
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
36407
|
+
period.startTime,
|
|
36408
|
+
" ",
|
|
36409
|
+
/* @__PURE__ */ jsx("span", { className: "text-slate-400 mx-0.5", children: "\u2192" }),
|
|
36410
|
+
" ",
|
|
36411
|
+
period.endTime,
|
|
36412
|
+
" ",
|
|
36413
|
+
/* @__PURE__ */ jsxs("span", { className: "text-slate-400 font-normal ml-1", children: [
|
|
36414
|
+
"(",
|
|
36415
|
+
period.duration,
|
|
36416
|
+
"m)"
|
|
36417
|
+
] })
|
|
36418
|
+
] }) })
|
|
36419
|
+
]
|
|
36420
|
+
},
|
|
36421
|
+
index
|
|
36422
|
+
);
|
|
36423
|
+
}) })
|
|
35812
36424
|
] })
|
|
35813
|
-
] }) }),
|
|
35814
|
-
idlePeriods.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mt-3 bg-gray-50 rounded-lg p-2.5", children: [
|
|
35815
|
-
/* @__PURE__ */ jsx("p", { className: "font-medium text-gray-700 text-xs mb-2", children: "Idle periods:" }),
|
|
35816
|
-
/* @__PURE__ */ jsx("div", { className: "space-y-1 max-h-32 overflow-y-auto pr-1", children: idlePeriods.map((period, index) => {
|
|
35817
|
-
return /* @__PURE__ */ jsxs(
|
|
35818
|
-
"div",
|
|
35819
|
-
{
|
|
35820
|
-
className: "text-gray-600 flex items-center gap-2 text-xs",
|
|
35821
|
-
children: [
|
|
35822
|
-
/* @__PURE__ */ jsx("span", { className: "inline-block w-1.5 h-1.5 bg-orange-400 rounded-full flex-shrink-0" }),
|
|
35823
|
-
/* @__PURE__ */ jsx("span", { children: period.duration === 1 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
35824
|
-
period.startTime,
|
|
35825
|
-
" (",
|
|
35826
|
-
period.duration,
|
|
35827
|
-
" min)"
|
|
35828
|
-
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
35829
|
-
period.startTime,
|
|
35830
|
-
" -",
|
|
35831
|
-
" ",
|
|
35832
|
-
period.endTime,
|
|
35833
|
-
" (",
|
|
35834
|
-
period.duration,
|
|
35835
|
-
" mins)"
|
|
35836
|
-
] }) })
|
|
35837
|
-
]
|
|
35838
|
-
},
|
|
35839
|
-
index
|
|
35840
|
-
);
|
|
35841
|
-
}) })
|
|
35842
36425
|
] })
|
|
35843
36426
|
] })
|
|
35844
|
-
] })
|
|
35845
|
-
|
|
35846
|
-
|
|
35847
|
-
|
|
35848
|
-
|
|
35849
|
-
|
|
35850
|
-
|
|
35851
|
-
|
|
35852
|
-
|
|
35853
|
-
|
|
35854
|
-
|
|
35855
|
-
|
|
35856
|
-
|
|
35857
|
-
|
|
35858
|
-
|
|
35859
|
-
|
|
35860
|
-
|
|
35861
|
-
|
|
35862
|
-
|
|
35863
|
-
|
|
35864
|
-
|
|
35865
|
-
|
|
35866
|
-
|
|
35867
|
-
|
|
35868
|
-
|
|
35869
|
-
|
|
35870
|
-
|
|
35871
|
-
|
|
35872
|
-
|
|
35873
|
-
|
|
35874
|
-
|
|
35875
|
-
|
|
35876
|
-
|
|
35877
|
-
|
|
35878
|
-
|
|
35879
|
-
|
|
36427
|
+
] });
|
|
36428
|
+
},
|
|
36429
|
+
animationDuration: 200
|
|
36430
|
+
}
|
|
36431
|
+
),
|
|
36432
|
+
/* @__PURE__ */ jsx(Customized, { component: renderTargetLine }),
|
|
36433
|
+
/* @__PURE__ */ jsx(Customized, { component: renderSkuTimelineRail }),
|
|
36434
|
+
/* @__PURE__ */ jsxs(
|
|
36435
|
+
Bar,
|
|
36436
|
+
{
|
|
36437
|
+
xAxisId: "default",
|
|
36438
|
+
dataKey: "output",
|
|
36439
|
+
yAxisId: "default",
|
|
36440
|
+
maxBarSize: 35,
|
|
36441
|
+
radius: [10, 10, 0, 0],
|
|
36442
|
+
isAnimationActive: false,
|
|
36443
|
+
children: [
|
|
36444
|
+
chartData.map((entry, index) => /* @__PURE__ */ jsx(
|
|
36445
|
+
Cell,
|
|
36446
|
+
{
|
|
36447
|
+
fill: entry.color,
|
|
36448
|
+
stroke: "transparent",
|
|
36449
|
+
strokeWidth: 0,
|
|
36450
|
+
style: {
|
|
36451
|
+
filter: entry.isHighlighted ? "drop-shadow(0 4px 6px rgba(0, 0, 0, 0.12)) brightness(1.05)" : "brightness(1)",
|
|
36452
|
+
transform: entry.isHighlighted ? "translateY(-4px)" : "translateY(0)",
|
|
36453
|
+
opacity: entry.isDimmed ? 0.4 : 1,
|
|
36454
|
+
transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)",
|
|
36455
|
+
cursor: "pointer"
|
|
36456
|
+
},
|
|
36457
|
+
onMouseEnter: (e) => {
|
|
36458
|
+
const target = e.target;
|
|
36459
|
+
target.style.filter = "drop-shadow(0 4px 6px rgba(0, 0, 0, 0.12)) brightness(1.05)";
|
|
36460
|
+
target.style.transform = "translateY(-4px)";
|
|
36461
|
+
target.style.opacity = "1";
|
|
36462
|
+
},
|
|
36463
|
+
onMouseLeave: (e) => {
|
|
36464
|
+
const target = e.target;
|
|
36465
|
+
target.style.filter = entry.isHighlighted ? "drop-shadow(0 4px 6px rgba(0, 0, 0, 0.12)) brightness(1.05)" : "brightness(1)";
|
|
36466
|
+
target.style.transform = entry.isHighlighted ? "translateY(-4px)" : "translateY(0)";
|
|
36467
|
+
target.style.opacity = entry.isDimmed ? "0.4" : "1";
|
|
36468
|
+
}
|
|
35880
36469
|
},
|
|
35881
|
-
|
|
35882
|
-
|
|
35883
|
-
|
|
35884
|
-
|
|
35885
|
-
|
|
36470
|
+
`cell-${index}`
|
|
36471
|
+
)),
|
|
36472
|
+
/* @__PURE__ */ jsx(
|
|
36473
|
+
LabelList,
|
|
36474
|
+
{
|
|
36475
|
+
dataKey: "originalOutput",
|
|
36476
|
+
position: "top",
|
|
36477
|
+
content: (props) => {
|
|
36478
|
+
const { x, y, width, value, payload } = props;
|
|
36479
|
+
const actualValue = payload?.originalOutput || value;
|
|
36480
|
+
if (!actualValue || actualValue === 0) return null;
|
|
36481
|
+
return /* @__PURE__ */ jsx(
|
|
36482
|
+
"text",
|
|
36483
|
+
{
|
|
36484
|
+
x: x + width / 2,
|
|
36485
|
+
y: y - 8,
|
|
36486
|
+
textAnchor: "middle",
|
|
36487
|
+
fontSize: "12",
|
|
36488
|
+
fontWeight: "600",
|
|
36489
|
+
fill: "#374151",
|
|
36490
|
+
style: {
|
|
36491
|
+
opacity: 1,
|
|
36492
|
+
pointerEvents: "none",
|
|
36493
|
+
transition: "none"
|
|
36494
|
+
},
|
|
36495
|
+
children: Math.round(actualValue)
|
|
36496
|
+
}
|
|
36497
|
+
);
|
|
36498
|
+
}
|
|
35886
36499
|
}
|
|
35887
|
-
|
|
35888
|
-
|
|
35889
|
-
|
|
35890
|
-
|
|
35891
|
-
|
|
35892
|
-
|
|
35893
|
-
|
|
35894
|
-
|
|
35895
|
-
|
|
35896
|
-
|
|
35897
|
-
|
|
35898
|
-
|
|
35899
|
-
|
|
35900
|
-
|
|
35901
|
-
|
|
35902
|
-
|
|
35903
|
-
|
|
35904
|
-
|
|
35905
|
-
|
|
35906
|
-
|
|
35907
|
-
|
|
35908
|
-
style: {
|
|
35909
|
-
opacity: 1,
|
|
35910
|
-
pointerEvents: "none",
|
|
35911
|
-
transition: "none"
|
|
35912
|
-
},
|
|
35913
|
-
children: Math.round(actualValue)
|
|
35914
|
-
}
|
|
35915
|
-
);
|
|
36500
|
+
)
|
|
36501
|
+
]
|
|
36502
|
+
}
|
|
36503
|
+
),
|
|
36504
|
+
IdleBar,
|
|
36505
|
+
/* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs(
|
|
36506
|
+
"pattern",
|
|
36507
|
+
{
|
|
36508
|
+
id: "idlePattern",
|
|
36509
|
+
patternUnits: "userSpaceOnUse",
|
|
36510
|
+
width: "4",
|
|
36511
|
+
height: "4",
|
|
36512
|
+
children: [
|
|
36513
|
+
/* @__PURE__ */ jsx("rect", { width: "4", height: "4", fill: "#4b5563", opacity: "0.6" }),
|
|
36514
|
+
/* @__PURE__ */ jsx(
|
|
36515
|
+
"path",
|
|
36516
|
+
{
|
|
36517
|
+
d: "M 0,4 l 4,-4 M -1,1 l 2,-2 M 3,5 l 2,-2",
|
|
36518
|
+
stroke: "#374151",
|
|
36519
|
+
strokeWidth: "0.8",
|
|
36520
|
+
opacity: "0.8"
|
|
35916
36521
|
}
|
|
35917
|
-
|
|
35918
|
-
|
|
35919
|
-
|
|
35920
|
-
}
|
|
35921
|
-
|
|
35922
|
-
|
|
35923
|
-
|
|
35924
|
-
|
|
35925
|
-
|
|
35926
|
-
|
|
35927
|
-
|
|
35928
|
-
|
|
35929
|
-
|
|
35930
|
-
|
|
35931
|
-
|
|
35932
|
-
|
|
35933
|
-
|
|
35934
|
-
|
|
35935
|
-
|
|
35936
|
-
|
|
35937
|
-
|
|
35938
|
-
|
|
35939
|
-
}
|
|
35940
|
-
)
|
|
35941
|
-
]
|
|
35942
|
-
}
|
|
35943
|
-
) })
|
|
35944
|
-
]
|
|
35945
|
-
}
|
|
35946
|
-
) }) }) : /* @__PURE__ */ jsx("div", { className: "w-full h-full flex items-center justify-center bg-gray-50 rounded-lg", children: /* @__PURE__ */ jsx("div", { className: "text-gray-500 text-sm", children: "Loading chart..." }) }),
|
|
36522
|
+
)
|
|
36523
|
+
]
|
|
36524
|
+
}
|
|
36525
|
+
) })
|
|
36526
|
+
]
|
|
36527
|
+
}
|
|
36528
|
+
) }),
|
|
36529
|
+
hoveredSkuRailLabel && /* @__PURE__ */ jsx(
|
|
36530
|
+
"div",
|
|
36531
|
+
{
|
|
36532
|
+
className: "absolute z-50 pointer-events-none transform -translate-x-1/2 -translate-y-full transition-opacity duration-200",
|
|
36533
|
+
style: {
|
|
36534
|
+
left: hoveredSkuRailLabel.centerX,
|
|
36535
|
+
top: hoveredSkuRailLabel.railY - 12
|
|
36536
|
+
},
|
|
36537
|
+
children: /* @__PURE__ */ jsxs("div", { className: "bg-white/95 backdrop-blur-md border border-slate-200/80 shadow-xl shadow-slate-200/50 rounded-lg px-3 py-2 flex flex-col min-w-[100px] max-w-[280px]", children: [
|
|
36538
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] font-bold tracking-wider text-blue-500 uppercase leading-none mb-1", children: "SKU" }),
|
|
36539
|
+
/* @__PURE__ */ jsx("span", { className: "text-[13px] font-semibold text-slate-800 whitespace-normal break-words leading-snug", children: hoveredSkuRailLabel.label })
|
|
36540
|
+
] })
|
|
36541
|
+
}
|
|
36542
|
+
)
|
|
36543
|
+
] }) : /* @__PURE__ */ jsx("div", { className: "w-full h-full flex items-center justify-center bg-gray-50 rounded-lg", children: /* @__PURE__ */ jsx("div", { className: "text-gray-500 text-sm", children: "Loading chart..." }) }),
|
|
35947
36544
|
/* @__PURE__ */ jsx("div", { className: "flex-none pt-2", children: renderLegend() })
|
|
35948
36545
|
]
|
|
35949
36546
|
}
|
|
@@ -35961,6 +36558,16 @@ var HourlyOutputChart = React144__default.memo(
|
|
|
35961
36558
|
if (!prevProps.data.every((val, idx) => val === nextProps.data[idx])) {
|
|
35962
36559
|
return false;
|
|
35963
36560
|
}
|
|
36561
|
+
const prevHourlyTargets = prevProps.hourlyTargetOutput || [];
|
|
36562
|
+
const nextHourlyTargets = nextProps.hourlyTargetOutput || [];
|
|
36563
|
+
if (prevHourlyTargets.length !== nextHourlyTargets.length) {
|
|
36564
|
+
return false;
|
|
36565
|
+
}
|
|
36566
|
+
for (let i = 0; i < prevHourlyTargets.length; i += 1) {
|
|
36567
|
+
if (prevHourlyTargets[i] !== nextHourlyTargets[i]) {
|
|
36568
|
+
return false;
|
|
36569
|
+
}
|
|
36570
|
+
}
|
|
35964
36571
|
const prevIdle = prevProps.idleTimeHourly || {};
|
|
35965
36572
|
const nextIdle = nextProps.idleTimeHourly || {};
|
|
35966
36573
|
const prevKeys = Object.keys(prevIdle);
|
|
@@ -36148,7 +36755,6 @@ var VideoCard = React144__default.memo(({
|
|
|
36148
36755
|
shouldPlay,
|
|
36149
36756
|
onClick,
|
|
36150
36757
|
onFatalError,
|
|
36151
|
-
isVeryLowEfficiency = false,
|
|
36152
36758
|
legend,
|
|
36153
36759
|
cropping,
|
|
36154
36760
|
canvasFps = 30,
|
|
@@ -36220,11 +36826,6 @@ var VideoCard = React144__default.memo(({
|
|
|
36220
36826
|
}
|
|
36221
36827
|
},
|
|
36222
36828
|
children: [
|
|
36223
|
-
isVeryLowEfficiency && /* @__PURE__ */ jsx("div", { className: `absolute ${compact ? "top-0.5 left-1" : "top-1 left-2"} z-30`, children: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
36224
|
-
/* @__PURE__ */ jsx("div", { className: "absolute -inset-1 bg-red-400/50 rounded-full blur-sm animate-pulse" }),
|
|
36225
|
-
/* @__PURE__ */ jsx("div", { className: "absolute -inset-0.5 bg-red-500/30 rounded-full blur-md animate-ping [animation-duration:1.5s]" }),
|
|
36226
|
-
/* @__PURE__ */ jsx("div", { className: `bg-[#E34329] ${compact ? "w-4 h-4" : "w-5 h-5"} rounded-full flex items-center justify-center text-white font-bold ${compact ? "text-[10px]" : "text-xs"} shadow-lg ring-2 ring-red-400/40 border border-red-400/80 animate-pulse`, children: "!" })
|
|
36227
|
-
] }) }),
|
|
36228
36829
|
/* @__PURE__ */ jsxs("div", { className: "relative w-full h-full overflow-hidden bg-black", children: [
|
|
36229
36830
|
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-black z-0", children: /* @__PURE__ */ jsxs("div", { className: "animate-pulse flex flex-col items-center", children: [
|
|
36230
36831
|
/* @__PURE__ */ jsx(Camera, { className: `w-5 h-5 sm:${compact ? "w-4 h-4" : "w-6 h-6"} text-gray-500` }),
|
|
@@ -36634,7 +37235,6 @@ var VideoGridView = React144__default.memo(({
|
|
|
36634
37235
|
const workspaceId = workspace.workspace_uuid || workspace.workspace_name;
|
|
36635
37236
|
const workspaceKey = `${workspace.line_id || "unknown"}-${workspaceId}`;
|
|
36636
37237
|
const isVisible = visibleWorkspaces.has(workspaceId);
|
|
36637
|
-
const isVeryLowEfficiency = workspace.show_exclamation ?? (workspace.efficiency < 50 && workspace.efficiency >= 10);
|
|
36638
37238
|
const workspaceCropping = getWorkspaceCropping(workspaceId, workspace.workspace_name);
|
|
36639
37239
|
const workspaceStream = videoStreamsByWorkspaceId?.[workspaceId];
|
|
36640
37240
|
const lastSeenLabel = workspace.workspace_uuid ? lastSeenByWorkspaceId[workspace.workspace_uuid]?.timeSinceLastUpdate : void 0;
|
|
@@ -36651,7 +37251,6 @@ var VideoGridView = React144__default.memo(({
|
|
|
36651
37251
|
workspaceId,
|
|
36652
37252
|
workspaceKey,
|
|
36653
37253
|
isVisible,
|
|
36654
|
-
isVeryLowEfficiency,
|
|
36655
37254
|
workspaceCropping,
|
|
36656
37255
|
fallbackUrl,
|
|
36657
37256
|
hlsUrl,
|
|
@@ -36699,7 +37298,6 @@ var VideoGridView = React144__default.memo(({
|
|
|
36699
37298
|
isR2Stream: card.isR2Stream,
|
|
36700
37299
|
fallbackUrl: card.fallbackUrl
|
|
36701
37300
|
}),
|
|
36702
|
-
isVeryLowEfficiency: card.isVeryLowEfficiency,
|
|
36703
37301
|
legend: effectiveLegend,
|
|
36704
37302
|
cropping: card.workspaceCropping,
|
|
36705
37303
|
canvasFps: effectiveCanvasFps,
|
|
@@ -37619,223 +38217,6 @@ var UptimeLineChartComponent = ({ points, className = "" }) => {
|
|
|
37619
38217
|
] }) }) });
|
|
37620
38218
|
};
|
|
37621
38219
|
var UptimeLineChart = React144__default.memo(UptimeLineChartComponent);
|
|
37622
|
-
var padTime = (value) => value.toString().padStart(2, "0");
|
|
37623
|
-
var parseTime = (timeValue) => {
|
|
37624
|
-
if (!timeValue) return null;
|
|
37625
|
-
const [hourPart, minutePart] = timeValue.split(":");
|
|
37626
|
-
const hour = Number.parseInt(hourPart, 10);
|
|
37627
|
-
const minute = Number.parseInt(minutePart ?? "0", 10);
|
|
37628
|
-
if (!Number.isFinite(hour) || !Number.isFinite(minute)) return null;
|
|
37629
|
-
return { hour, minute };
|
|
37630
|
-
};
|
|
37631
|
-
var normalizeIdleTimeHourly = (idleTimeHourly) => {
|
|
37632
|
-
if (!idleTimeHourly || typeof idleTimeHourly !== "object") {
|
|
37633
|
-
return {};
|
|
37634
|
-
}
|
|
37635
|
-
return Object.fromEntries(
|
|
37636
|
-
Object.entries(idleTimeHourly).map(([key, value]) => {
|
|
37637
|
-
if (Array.isArray(value)) return [key, value];
|
|
37638
|
-
if (value && Array.isArray(value.values)) {
|
|
37639
|
-
return [key, value.values];
|
|
37640
|
-
}
|
|
37641
|
-
return [key, []];
|
|
37642
|
-
})
|
|
37643
|
-
);
|
|
37644
|
-
};
|
|
37645
|
-
var interpretIdleValue = (value) => {
|
|
37646
|
-
if (value === 1 || value === "1") return "idle";
|
|
37647
|
-
if (value === 0 || value === "0") return "active";
|
|
37648
|
-
if (value === "x" || value === null || value === void 0) return "unknown";
|
|
37649
|
-
return "unknown";
|
|
37650
|
-
};
|
|
37651
|
-
var getShiftDurationMinutes = (shiftStart, shiftEnd) => {
|
|
37652
|
-
const start = parseTime(shiftStart);
|
|
37653
|
-
const end = parseTime(shiftEnd);
|
|
37654
|
-
if (!start || !end) return null;
|
|
37655
|
-
let duration = end.hour * 60 + end.minute - (start.hour * 60 + start.minute);
|
|
37656
|
-
if (duration <= 0) {
|
|
37657
|
-
duration += 24 * 60;
|
|
37658
|
-
}
|
|
37659
|
-
return duration > 0 ? duration : null;
|
|
37660
|
-
};
|
|
37661
|
-
var getShiftElapsedMinutes = ({
|
|
37662
|
-
shiftStart,
|
|
37663
|
-
shiftEnd,
|
|
37664
|
-
shiftDate,
|
|
37665
|
-
timezone,
|
|
37666
|
-
now: now4 = /* @__PURE__ */ new Date()
|
|
37667
|
-
}) => {
|
|
37668
|
-
if (!shiftDate || !timezone) return null;
|
|
37669
|
-
const startTime = parseTime(shiftStart);
|
|
37670
|
-
const endTime = parseTime(shiftEnd);
|
|
37671
|
-
if (!startTime || !endTime) return null;
|
|
37672
|
-
const shiftStartDate = fromZonedTime(
|
|
37673
|
-
`${shiftDate}T${padTime(startTime.hour)}:${padTime(startTime.minute)}:00`,
|
|
37674
|
-
timezone
|
|
37675
|
-
);
|
|
37676
|
-
let shiftEndDate = fromZonedTime(
|
|
37677
|
-
`${shiftDate}T${padTime(endTime.hour)}:${padTime(endTime.minute)}:00`,
|
|
37678
|
-
timezone
|
|
37679
|
-
);
|
|
37680
|
-
if (shiftEndDate <= shiftStartDate) {
|
|
37681
|
-
shiftEndDate = addDays(shiftEndDate, 1);
|
|
37682
|
-
}
|
|
37683
|
-
const shiftMinutes = Math.max(differenceInMinutes(shiftEndDate, shiftStartDate), 0);
|
|
37684
|
-
if (shiftMinutes <= 0) return null;
|
|
37685
|
-
const elapsed = differenceInMinutes(now4, shiftStartDate);
|
|
37686
|
-
return Math.min(Math.max(elapsed, 0), shiftMinutes);
|
|
37687
|
-
};
|
|
37688
|
-
var maskFutureHourlySeries = ({
|
|
37689
|
-
data,
|
|
37690
|
-
shiftStart,
|
|
37691
|
-
shiftEnd,
|
|
37692
|
-
shiftDate,
|
|
37693
|
-
timezone,
|
|
37694
|
-
now: now4 = /* @__PURE__ */ new Date()
|
|
37695
|
-
}) => {
|
|
37696
|
-
if (!Array.isArray(data)) {
|
|
37697
|
-
return [];
|
|
37698
|
-
}
|
|
37699
|
-
const normalizedData = data.map((value) => typeof value === "number" && Number.isFinite(value) ? value : null);
|
|
37700
|
-
if (!normalizedData.length) {
|
|
37701
|
-
return normalizedData;
|
|
37702
|
-
}
|
|
37703
|
-
const shiftMinutes = getShiftDurationMinutes(shiftStart, shiftEnd);
|
|
37704
|
-
const elapsedMinutes = getShiftElapsedMinutes({
|
|
37705
|
-
shiftStart,
|
|
37706
|
-
shiftEnd,
|
|
37707
|
-
shiftDate,
|
|
37708
|
-
timezone,
|
|
37709
|
-
now: now4
|
|
37710
|
-
});
|
|
37711
|
-
if (shiftMinutes === null || elapsedMinutes === null || elapsedMinutes >= shiftMinutes) {
|
|
37712
|
-
return normalizedData;
|
|
37713
|
-
}
|
|
37714
|
-
return normalizedData.map((value, index) => {
|
|
37715
|
-
const slotStartMinutes = index * 60;
|
|
37716
|
-
return slotStartMinutes > elapsedMinutes ? null : value;
|
|
37717
|
-
});
|
|
37718
|
-
};
|
|
37719
|
-
var buildUptimeSeries = ({
|
|
37720
|
-
idleTimeHourly,
|
|
37721
|
-
shiftStart,
|
|
37722
|
-
shiftEnd,
|
|
37723
|
-
shiftDate,
|
|
37724
|
-
timezone,
|
|
37725
|
-
elapsedMinutes
|
|
37726
|
-
}) => {
|
|
37727
|
-
const normalizedIdle = normalizeIdleTimeHourly(idleTimeHourly || {});
|
|
37728
|
-
const hasIdleData = Object.keys(normalizedIdle).length > 0;
|
|
37729
|
-
if (!hasIdleData || !shiftDate || !timezone) {
|
|
37730
|
-
return {
|
|
37731
|
-
points: [],
|
|
37732
|
-
activeMinutes: 0,
|
|
37733
|
-
idleMinutes: 0,
|
|
37734
|
-
availableMinutes: 0,
|
|
37735
|
-
shiftMinutes: 0,
|
|
37736
|
-
elapsedMinutes: 0,
|
|
37737
|
-
hasData: false
|
|
37738
|
-
};
|
|
37739
|
-
}
|
|
37740
|
-
const startTime = parseTime(shiftStart);
|
|
37741
|
-
const endTime = parseTime(shiftEnd);
|
|
37742
|
-
if (!startTime || !endTime) {
|
|
37743
|
-
return {
|
|
37744
|
-
points: [],
|
|
37745
|
-
activeMinutes: 0,
|
|
37746
|
-
idleMinutes: 0,
|
|
37747
|
-
availableMinutes: 0,
|
|
37748
|
-
shiftMinutes: 0,
|
|
37749
|
-
elapsedMinutes: 0,
|
|
37750
|
-
hasData: false
|
|
37751
|
-
};
|
|
37752
|
-
}
|
|
37753
|
-
const shiftStartDate = fromZonedTime(
|
|
37754
|
-
`${shiftDate}T${padTime(startTime.hour)}:${padTime(startTime.minute)}:00`,
|
|
37755
|
-
timezone
|
|
37756
|
-
);
|
|
37757
|
-
let shiftEndDate = fromZonedTime(
|
|
37758
|
-
`${shiftDate}T${padTime(endTime.hour)}:${padTime(endTime.minute)}:00`,
|
|
37759
|
-
timezone
|
|
37760
|
-
);
|
|
37761
|
-
if (shiftEndDate <= shiftStartDate) {
|
|
37762
|
-
shiftEndDate = addDays(shiftEndDate, 1);
|
|
37763
|
-
}
|
|
37764
|
-
const shiftMinutes = Math.max(differenceInMinutes(shiftEndDate, shiftStartDate), 0);
|
|
37765
|
-
if (shiftMinutes <= 0) {
|
|
37766
|
-
return {
|
|
37767
|
-
points: [],
|
|
37768
|
-
activeMinutes: 0,
|
|
37769
|
-
idleMinutes: 0,
|
|
37770
|
-
availableMinutes: 0,
|
|
37771
|
-
shiftMinutes: 0,
|
|
37772
|
-
elapsedMinutes: 0,
|
|
37773
|
-
hasData: false
|
|
37774
|
-
};
|
|
37775
|
-
}
|
|
37776
|
-
const elapsedMinutesClamped = Number.isFinite(elapsedMinutes) ? Math.min(Math.max(Math.floor(elapsedMinutes ?? 0), 0), shiftMinutes) : shiftMinutes;
|
|
37777
|
-
const points = [];
|
|
37778
|
-
let activeMinutes = 0;
|
|
37779
|
-
let idleMinutes = 0;
|
|
37780
|
-
for (let minuteIndex = 0; minuteIndex < shiftMinutes; minuteIndex += 1) {
|
|
37781
|
-
const minuteDate = addMinutes(shiftStartDate, minuteIndex);
|
|
37782
|
-
const timeLabel = formatInTimeZone(minuteDate, timezone, "h:mm a");
|
|
37783
|
-
if (minuteIndex >= elapsedMinutesClamped) {
|
|
37784
|
-
points.push({
|
|
37785
|
-
minuteIndex,
|
|
37786
|
-
timeLabel,
|
|
37787
|
-
uptime: null,
|
|
37788
|
-
status: "unknown"
|
|
37789
|
-
});
|
|
37790
|
-
continue;
|
|
37791
|
-
}
|
|
37792
|
-
const hourKey = formatInTimeZone(minuteDate, timezone, "H");
|
|
37793
|
-
const minuteKey = Number.parseInt(formatInTimeZone(minuteDate, timezone, "m"), 10);
|
|
37794
|
-
const hourBucket = normalizedIdle[hourKey] || [];
|
|
37795
|
-
const value = Array.isArray(hourBucket) ? hourBucket[minuteKey] : void 0;
|
|
37796
|
-
const status = interpretIdleValue(value);
|
|
37797
|
-
if (status === "active") activeMinutes += 1;
|
|
37798
|
-
if (status === "idle") idleMinutes += 1;
|
|
37799
|
-
points.push({
|
|
37800
|
-
minuteIndex,
|
|
37801
|
-
timeLabel,
|
|
37802
|
-
uptime: status === "active" ? 1 : status === "idle" ? 0 : null,
|
|
37803
|
-
status
|
|
37804
|
-
});
|
|
37805
|
-
}
|
|
37806
|
-
return {
|
|
37807
|
-
points,
|
|
37808
|
-
activeMinutes,
|
|
37809
|
-
idleMinutes,
|
|
37810
|
-
availableMinutes: activeMinutes + idleMinutes,
|
|
37811
|
-
shiftMinutes,
|
|
37812
|
-
elapsedMinutes: elapsedMinutesClamped,
|
|
37813
|
-
hasData: activeMinutes + idleMinutes > 0
|
|
37814
|
-
};
|
|
37815
|
-
};
|
|
37816
|
-
var getUptimeUtilizationPercent = (shift) => {
|
|
37817
|
-
const efficiency = shift.efficiency;
|
|
37818
|
-
if (Number.isFinite(efficiency)) {
|
|
37819
|
-
return Math.round(Math.max(0, Math.min(100, Number(efficiency))));
|
|
37820
|
-
}
|
|
37821
|
-
const idleSeconds = Number.isFinite(shift.idleTime) ? Number(shift.idleTime) : 0;
|
|
37822
|
-
const activeSeconds = Number.isFinite(shift.activeTimeSeconds) ? Number(shift.activeTimeSeconds) : null;
|
|
37823
|
-
let availableSeconds = Number.isFinite(shift.availableTimeSeconds) ? Number(shift.availableTimeSeconds) : null;
|
|
37824
|
-
if (availableSeconds === null) {
|
|
37825
|
-
if ((activeSeconds ?? 0) > 0 || idleSeconds > 0) {
|
|
37826
|
-
availableSeconds = (activeSeconds ?? 0) + idleSeconds;
|
|
37827
|
-
} else {
|
|
37828
|
-
return 0;
|
|
37829
|
-
}
|
|
37830
|
-
}
|
|
37831
|
-
if (availableSeconds <= 0) return 0;
|
|
37832
|
-
const clampedIdleSeconds = Math.min(Math.max(idleSeconds, 0), availableSeconds);
|
|
37833
|
-
const productiveSeconds = Math.max(
|
|
37834
|
-
activeSeconds ?? availableSeconds - clampedIdleSeconds,
|
|
37835
|
-
0
|
|
37836
|
-
);
|
|
37837
|
-
return Math.round(productiveSeconds / availableSeconds * 100);
|
|
37838
|
-
};
|
|
37839
38220
|
var getTimeFromTimeString = (timeStr) => {
|
|
37840
38221
|
if (!timeStr) {
|
|
37841
38222
|
return { hour: 0, minute: 0, decimalHour: 0 };
|
|
@@ -50166,7 +50547,7 @@ var formatOperationalDateKey = (dateKey, options) => {
|
|
|
50166
50547
|
timeZone: "UTC"
|
|
50167
50548
|
});
|
|
50168
50549
|
};
|
|
50169
|
-
var
|
|
50550
|
+
var getSegmentMinutes2 = (isoString, timeZone, reportDate) => {
|
|
50170
50551
|
const date = new Date(isoString);
|
|
50171
50552
|
if (isNaN(date.getTime())) return NaN;
|
|
50172
50553
|
const formatter = new Intl.DateTimeFormat("en-US", {
|
|
@@ -50187,13 +50568,13 @@ var getSegmentMinutes = (isoString, timeZone, reportDate) => {
|
|
|
50187
50568
|
if (dateKey > reportDate) {
|
|
50188
50569
|
const d1 = new Date(dateKey);
|
|
50189
50570
|
const d2 = new Date(reportDate);
|
|
50190
|
-
const
|
|
50191
|
-
minutes +=
|
|
50571
|
+
const diffDays2 = Math.round((d1.getTime() - d2.getTime()) / (1e3 * 3600 * 24));
|
|
50572
|
+
minutes += diffDays2 * 24 * 60;
|
|
50192
50573
|
} else if (dateKey < reportDate) {
|
|
50193
50574
|
const d1 = new Date(dateKey);
|
|
50194
50575
|
const d2 = new Date(reportDate);
|
|
50195
|
-
const
|
|
50196
|
-
minutes -=
|
|
50576
|
+
const diffDays2 = Math.round((d2.getTime() - d1.getTime()) / (1e3 * 3600 * 24));
|
|
50577
|
+
minutes -= diffDays2 * 24 * 60;
|
|
50197
50578
|
}
|
|
50198
50579
|
return minutes;
|
|
50199
50580
|
};
|
|
@@ -50603,7 +50984,7 @@ var LinePdfGenerator = ({
|
|
|
50603
50984
|
const skuRemarksByIndex = {};
|
|
50604
50985
|
if (lineInfo.metrics.sku_segments && lineInfo.metrics.sku_segments.length > 0) {
|
|
50605
50986
|
lineInfo.metrics.sku_segments.forEach((segment, segmentIndex) => {
|
|
50606
|
-
const segmentMinutes =
|
|
50987
|
+
const segmentMinutes = getSegmentMinutes2(segment.start_time, reportTimezone, lineInfo.date);
|
|
50607
50988
|
if (!isNaN(segmentMinutes)) {
|
|
50608
50989
|
const intervalIndex = hourlyTimeRanges.findIndex(
|
|
50609
50990
|
(inv) => segmentMinutes >= inv.start && segmentMinutes < inv.end
|
|
@@ -52338,7 +52719,7 @@ var formatOperationalDateKey2 = (dateKey, options) => {
|
|
|
52338
52719
|
timeZone: "UTC"
|
|
52339
52720
|
});
|
|
52340
52721
|
};
|
|
52341
|
-
var
|
|
52722
|
+
var getSegmentMinutes3 = (isoString, timeZone, reportDate) => {
|
|
52342
52723
|
const date = new Date(isoString);
|
|
52343
52724
|
if (isNaN(date.getTime())) return NaN;
|
|
52344
52725
|
const formatter = new Intl.DateTimeFormat("en-US", {
|
|
@@ -52359,13 +52740,13 @@ var getSegmentMinutes2 = (isoString, timeZone, reportDate) => {
|
|
|
52359
52740
|
if (dateKey > reportDate) {
|
|
52360
52741
|
const d1 = new Date(dateKey);
|
|
52361
52742
|
const d2 = new Date(reportDate);
|
|
52362
|
-
const
|
|
52363
|
-
minutes +=
|
|
52743
|
+
const diffDays2 = Math.round((d1.getTime() - d2.getTime()) / (1e3 * 3600 * 24));
|
|
52744
|
+
minutes += diffDays2 * 24 * 60;
|
|
52364
52745
|
} else if (dateKey < reportDate) {
|
|
52365
52746
|
const d1 = new Date(dateKey);
|
|
52366
52747
|
const d2 = new Date(reportDate);
|
|
52367
|
-
const
|
|
52368
|
-
minutes -=
|
|
52748
|
+
const diffDays2 = Math.round((d2.getTime() - d1.getTime()) / (1e3 * 3600 * 24));
|
|
52749
|
+
minutes -= diffDays2 * 24 * 60;
|
|
52369
52750
|
}
|
|
52370
52751
|
return minutes;
|
|
52371
52752
|
};
|
|
@@ -52597,7 +52978,7 @@ var WorkspacePdfGenerator = ({
|
|
|
52597
52978
|
const skuRemarksByIndex = {};
|
|
52598
52979
|
if (workspace.sku_segments && workspace.sku_segments.length > 0) {
|
|
52599
52980
|
workspace.sku_segments.forEach((segment, segmentIndex) => {
|
|
52600
|
-
const segmentMinutes =
|
|
52981
|
+
const segmentMinutes = getSegmentMinutes3(segment.start_time, reportTimezone, workspace.date);
|
|
52601
52982
|
if (!isNaN(segmentMinutes)) {
|
|
52602
52983
|
const intervalIndex = hourlyIntervals.findIndex(
|
|
52603
52984
|
(inv) => segmentMinutes >= inv.start && segmentMinutes < inv.end
|
|
@@ -53439,12 +53820,10 @@ var formatPercentRange = (min, max) => {
|
|
|
53439
53820
|
return `${format10(min)}-${format10(max)}%`;
|
|
53440
53821
|
};
|
|
53441
53822
|
var Legend5 = ({
|
|
53442
|
-
useBottleneckLabel = false,
|
|
53443
53823
|
legend,
|
|
53444
53824
|
metricLabel = "Efficiency"
|
|
53445
53825
|
}) => {
|
|
53446
53826
|
const effectiveLegend = legend || DEFAULT_EFFICIENCY_LEGEND;
|
|
53447
|
-
const exclamationLabel = useBottleneckLabel ? "Bottleneck" : "<50% efficiency";
|
|
53448
53827
|
return /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2 sm:gap-4 text-xs font-medium text-slate-600", children: [
|
|
53449
53828
|
/* @__PURE__ */ jsxs("div", { className: "font-medium text-gray-700 hidden sm:block", children: [
|
|
53450
53829
|
metricLabel,
|
|
@@ -53463,11 +53842,6 @@ var Legend5 = ({
|
|
|
53463
53842
|
/* @__PURE__ */ jsx("div", { className: "w-2 h-2 sm:w-2.5 sm:h-2.5 rounded-full bg-[#E34329]" }),
|
|
53464
53843
|
/* @__PURE__ */ jsx("span", { children: formatPercentRange(effectiveLegend.red_min, effectiveLegend.red_max) })
|
|
53465
53844
|
] })
|
|
53466
|
-
] }),
|
|
53467
|
-
/* @__PURE__ */ jsx("div", { className: "hidden sm:block w-px h-4 bg-slate-200 mx-1" }),
|
|
53468
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
53469
|
-
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-center w-3 h-3 sm:w-4 sm:h-4 bg-[#E34329] rounded-full text-white font-bold text-[8px] sm:text-[10px]", children: "!" }),
|
|
53470
|
-
/* @__PURE__ */ jsx("span", { children: exclamationLabel })
|
|
53471
53845
|
] })
|
|
53472
53846
|
] });
|
|
53473
53847
|
};
|
|
@@ -53581,7 +53955,6 @@ var WorkspaceGrid = React144__default.memo(({
|
|
|
53581
53955
|
factoryView = "factory",
|
|
53582
53956
|
line2Uuid = "line-2",
|
|
53583
53957
|
className = "",
|
|
53584
|
-
hasFlowBuffers = false,
|
|
53585
53958
|
legend = DEFAULT_EFFICIENCY_LEGEND,
|
|
53586
53959
|
videoSources = {},
|
|
53587
53960
|
videoStreamsByWorkspaceId = {},
|
|
@@ -53625,7 +53998,7 @@ var WorkspaceGrid = React144__default.memo(({
|
|
|
53625
53998
|
);
|
|
53626
53999
|
return /* @__PURE__ */ jsxs("div", { className: `flex flex-col w-full h-full overflow-hidden bg-slate-50/50 ${className}`, children: [
|
|
53627
54000
|
/* @__PURE__ */ jsxs("div", { className: "flex-none px-4 py-3 z-20 flex flex-row items-center justify-between gap-4", children: [
|
|
53628
|
-
/* @__PURE__ */ jsx("div", { className: "hidden sm:block", children: /* @__PURE__ */ jsx("div", { className: "inline-flex bg-white/95 rounded-lg shadow-sm px-4 py-2 border border-slate-200/60 backdrop-blur-sm", children: /* @__PURE__ */ jsx(Legend5, { legend,
|
|
54001
|
+
/* @__PURE__ */ jsx("div", { className: "hidden sm:block", children: /* @__PURE__ */ jsx("div", { className: "inline-flex bg-white/95 rounded-lg shadow-sm px-4 py-2 border border-slate-200/60 backdrop-blur-sm", children: /* @__PURE__ */ jsx(Legend5, { legend, metricLabel: legendMetricLabel }) }) }),
|
|
53629
54002
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-3 shrink-0", children: [
|
|
53630
54003
|
toolbarRightContent,
|
|
53631
54004
|
mapViewEnabled && /* @__PURE__ */ jsx(
|
|
@@ -53645,7 +54018,7 @@ var WorkspaceGrid = React144__default.memo(({
|
|
|
53645
54018
|
)
|
|
53646
54019
|
] })
|
|
53647
54020
|
] }),
|
|
53648
|
-
/* @__PURE__ */ jsx("div", { className: "sm:hidden px-3 py-2 bg-white border-b border-slate-200/60 z-10", children: /* @__PURE__ */ jsx(Legend5, { legend,
|
|
54021
|
+
/* @__PURE__ */ jsx("div", { className: "sm:hidden px-3 py-2 bg-white border-b border-slate-200/60 z-10", children: /* @__PURE__ */ jsx(Legend5, { legend, metricLabel: legendMetricLabel }) }),
|
|
53649
54022
|
/* @__PURE__ */ jsx("div", { className: "flex-1 relative overflow-hidden", children: /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: viewMode === "video" ? /* @__PURE__ */ jsx(
|
|
53650
54023
|
motion.div,
|
|
53651
54024
|
{
|
|
@@ -64306,6 +64679,7 @@ var buildLineInfoSnapshot = (lineDetails, metrics2) => {
|
|
|
64306
64679
|
underperforming_workspace_uuids: metrics2.underperforming_workspace_uuids || [],
|
|
64307
64680
|
output_array: metrics2.output_array || [],
|
|
64308
64681
|
output_hourly: metrics2.output_hourly,
|
|
64682
|
+
hourly_target_output: metrics2.hourly_target_output ?? null,
|
|
64309
64683
|
line_threshold: metrics2.line_threshold ?? 0,
|
|
64310
64684
|
threshold_pph: metrics2.threshold_pph ?? 0,
|
|
64311
64685
|
shift_start: metrics2.shift_start || "06:00",
|
|
@@ -64392,6 +64766,7 @@ var transformLineMetrics = (lineId, detailResponse, queryDate, queryShiftId) =>
|
|
|
64392
64766
|
underperforming_workspace_names: [],
|
|
64393
64767
|
underperforming_workspace_uuids: [],
|
|
64394
64768
|
output_array: [],
|
|
64769
|
+
hourly_target_output: null,
|
|
64395
64770
|
line_threshold: 0,
|
|
64396
64771
|
threshold_pph: 0,
|
|
64397
64772
|
shift_start: "06:00",
|
|
@@ -65429,6 +65804,9 @@ var BottomSection = memo$1(({
|
|
|
65429
65804
|
workspaceDisplayNames,
|
|
65430
65805
|
hourlyOutputData,
|
|
65431
65806
|
hourlyThreshold,
|
|
65807
|
+
hourlyTargetOutput,
|
|
65808
|
+
idleTimeHourly,
|
|
65809
|
+
timezone,
|
|
65432
65810
|
urlDate,
|
|
65433
65811
|
urlShift,
|
|
65434
65812
|
navigate,
|
|
@@ -65599,8 +65977,12 @@ var BottomSection = memo$1(({
|
|
|
65599
65977
|
{
|
|
65600
65978
|
data: hourlyOutputData,
|
|
65601
65979
|
pphThreshold: hourlyThreshold,
|
|
65980
|
+
hourlyTargetOutput,
|
|
65602
65981
|
shiftStart: lineInfo.metrics.shift_start || "06:00",
|
|
65603
65982
|
shiftEnd: lineInfo.metrics.shift_end,
|
|
65983
|
+
idleTimeHourly,
|
|
65984
|
+
shiftDate: lineInfo.date,
|
|
65985
|
+
timezone,
|
|
65604
65986
|
skuSegments: skuAware ? skuSegments : void 0,
|
|
65605
65987
|
activeSkuId
|
|
65606
65988
|
}
|
|
@@ -65621,6 +66003,9 @@ var BottomSection = memo$1(({
|
|
|
65621
66003
|
if (prevProps.lineInfo.monitoring_mode !== nextProps.lineInfo.monitoring_mode) return false;
|
|
65622
66004
|
if (prevProps.skuAware !== nextProps.skuAware) return false;
|
|
65623
66005
|
if (prevProps.activeSkuId !== nextProps.activeSkuId) return false;
|
|
66006
|
+
if (JSON.stringify(prevProps.hourlyTargetOutput || []) !== JSON.stringify(nextProps.hourlyTargetOutput || [])) {
|
|
66007
|
+
return false;
|
|
66008
|
+
}
|
|
65624
66009
|
const prevSkuSegmentsSignature = JSON.stringify(
|
|
65625
66010
|
(prevProps.skuSegments || []).map((segment) => ({
|
|
65626
66011
|
sku_id: segment.sku_id,
|
|
@@ -65693,7 +66078,9 @@ var BottomSection = memo$1(({
|
|
|
65693
66078
|
);
|
|
65694
66079
|
if (prevWorkspaceSignature !== nextWorkspaceSignature) return false;
|
|
65695
66080
|
if (prevProps.lineInfo.metrics.shift_start !== nextProps.lineInfo.metrics.shift_start) return false;
|
|
66081
|
+
if (prevProps.lineInfo.metrics.shift_end !== nextProps.lineInfo.metrics.shift_end) return false;
|
|
65696
66082
|
if (prevProps.hourlyThreshold !== nextProps.hourlyThreshold) return false;
|
|
66083
|
+
if (JSON.stringify(prevProps.idleTimeHourly || {}) !== JSON.stringify(nextProps.idleTimeHourly || {})) return false;
|
|
65697
66084
|
if (prevProps.urlDate !== nextProps.urlDate || prevProps.urlShift !== nextProps.urlShift) return false;
|
|
65698
66085
|
if (prevProps.workspaceDisplayNames !== nextProps.workspaceDisplayNames) return false;
|
|
65699
66086
|
return true;
|
|
@@ -65961,6 +66348,7 @@ var KPIDetailView = ({
|
|
|
65961
66348
|
}
|
|
65962
66349
|
}, [urlDate, urlShift, urlTab]);
|
|
65963
66350
|
const { shiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(lineId);
|
|
66351
|
+
const lineTimezone = shiftConfig?.timezone || configuredTimezone;
|
|
65964
66352
|
const getShiftName = useCallback((shiftId) => {
|
|
65965
66353
|
return getShiftNameById(shiftId, configuredTimezone, shiftConfig);
|
|
65966
66354
|
}, [configuredTimezone, shiftConfig]);
|
|
@@ -66001,12 +66389,12 @@ var KPIDetailView = ({
|
|
|
66001
66389
|
operationalTodayDate.setHours(0, 0, 0, 0);
|
|
66002
66390
|
compareDateInZone.setHours(0, 0, 0, 0);
|
|
66003
66391
|
const diffTime = compareDateInZone.getTime() - operationalTodayDate.getTime();
|
|
66004
|
-
const
|
|
66005
|
-
if (
|
|
66006
|
-
if (
|
|
66007
|
-
if (
|
|
66008
|
-
if (
|
|
66009
|
-
if (
|
|
66392
|
+
const diffDays2 = Math.round(diffTime / (1e3 * 60 * 60 * 24));
|
|
66393
|
+
if (diffDays2 === 0) return "Today";
|
|
66394
|
+
if (diffDays2 === -1) return "Yesterday";
|
|
66395
|
+
if (diffDays2 === 1) return "Tomorrow";
|
|
66396
|
+
if (diffDays2 < -1) return `${Math.abs(diffDays2)} days ago`;
|
|
66397
|
+
if (diffDays2 > 1) return `${diffDays2} days ahead`;
|
|
66010
66398
|
return "Today";
|
|
66011
66399
|
}, [configuredTimezone, shiftConfig]);
|
|
66012
66400
|
const {
|
|
@@ -66216,6 +66604,7 @@ var KPIDetailView = ({
|
|
|
66216
66604
|
underperforming_workspace_uuids: metrics2.underperforming_workspace_uuids || [],
|
|
66217
66605
|
output_array: metrics2.output_array || [],
|
|
66218
66606
|
output_hourly: metrics2.output_hourly,
|
|
66607
|
+
hourly_target_output: metrics2.hourly_target_output ?? null,
|
|
66219
66608
|
line_threshold: metrics2.line_threshold ?? 0,
|
|
66220
66609
|
threshold_pph: metrics2.threshold_pph ?? 0,
|
|
66221
66610
|
shift_start: metrics2.shift_start || "06:00",
|
|
@@ -66225,7 +66614,7 @@ var KPIDetailView = ({
|
|
|
66225
66614
|
idle_time_hourly: metrics2.idle_time_hourly || null,
|
|
66226
66615
|
// Multi-SKU additive fields (Phase 6) — propagated from
|
|
66227
66616
|
// `useLineDetailPageData`. Backend authoritative; we never recompute.
|
|
66228
|
-
// The
|
|
66617
|
+
// The output-card selection below uses these to swap header KPIs per selected SKU.
|
|
66229
66618
|
sku_aware: Boolean(metrics2.sku_aware),
|
|
66230
66619
|
real_sku_count: metrics2.real_sku_count ?? 0,
|
|
66231
66620
|
sku_breakdown: Array.isArray(metrics2.sku_breakdown) ? metrics2.sku_breakdown : [],
|
|
@@ -66322,7 +66711,7 @@ var KPIDetailView = ({
|
|
|
66322
66711
|
}, [lineSkuSegments, outputChartSkuBreakdown, hasUrlDate, hasUrlShift]);
|
|
66323
66712
|
const normalizedSelectedSkuId = selectedSkuId !== "all" ? selectedSkuId : null;
|
|
66324
66713
|
const isLineSkuAware = Boolean(resolvedLineInfo?.metrics.sku_aware);
|
|
66325
|
-
const showSkuSelector = isLineSkuAware && realSkuOptions.length > 0;
|
|
66714
|
+
const showSkuSelector = isLineSkuAware && realSkuOptions.length > 0 && !isUptimeMode;
|
|
66326
66715
|
useEffect(() => {
|
|
66327
66716
|
if (selectedSkuId === "all") return;
|
|
66328
66717
|
const stillPresent = realSkuOptions.some((item) => item.sku_id === selectedSkuId);
|
|
@@ -66349,15 +66738,11 @@ var KPIDetailView = ({
|
|
|
66349
66738
|
...resolvedLineInfo.metrics,
|
|
66350
66739
|
current_output: selectedSkuRow.current_output ?? 0,
|
|
66351
66740
|
ideal_output: selectedSkuRow.ideal_output ?? 0,
|
|
66352
|
-
avg_efficiency: selectedSkuRow.avg_efficiency ?? resolvedLineInfo.metrics.avg_efficiency,
|
|
66353
66741
|
total_workspaces: selectedSkuRow.total_workspaces ?? resolvedLineInfo.metrics.total_workspaces,
|
|
66354
66742
|
underperforming_workspaces: selectedSkuRow.underperforming_workspaces ?? resolvedLineInfo.metrics.underperforming_workspaces,
|
|
66355
66743
|
underperforming_workspace_names: selectedSkuRow.underperforming_workspace_names ?? resolvedLineInfo.metrics.underperforming_workspace_names,
|
|
66356
66744
|
underperforming_workspace_uuids: selectedSkuRow.underperforming_workspace_uuids ?? resolvedLineInfo.metrics.underperforming_workspace_uuids,
|
|
66357
|
-
|
|
66358
|
-
output_hourly: selectedSkuRow.output_hourly ?? resolvedLineInfo.metrics.output_hourly,
|
|
66359
|
-
line_threshold: selectedSkuRow.line_threshold ?? resolvedLineInfo.metrics.line_threshold,
|
|
66360
|
-
poorest_performing_workspaces: selectedSkuRow.poorest_performing_workspaces ?? resolvedLineInfo.metrics.poorest_performing_workspaces
|
|
66745
|
+
line_threshold: selectedSkuRow.line_threshold ?? resolvedLineInfo.metrics.line_threshold
|
|
66361
66746
|
}
|
|
66362
66747
|
};
|
|
66363
66748
|
}, [resolvedLineInfo, selectedSkuRow]);
|
|
@@ -67136,11 +67521,9 @@ var KPIDetailView = ({
|
|
|
67136
67521
|
showIdleTime: idleTimeVlmEnabled
|
|
67137
67522
|
}
|
|
67138
67523
|
) : (
|
|
67139
|
-
//
|
|
67140
|
-
//
|
|
67141
|
-
//
|
|
67142
|
-
// cards. When `selectedSkuId === 'all'`, this is exactly
|
|
67143
|
-
// `resolvedLineInfo` (aggregate path preserved).
|
|
67524
|
+
// Keep the line output + underperforming cards SKU-aware,
|
|
67525
|
+
// while Average Efficiency stays on the aggregate line
|
|
67526
|
+
// metrics even when a specific SKU is selected.
|
|
67144
67527
|
/* @__PURE__ */ jsx(
|
|
67145
67528
|
MetricCards,
|
|
67146
67529
|
{
|
|
@@ -67185,6 +67568,9 @@ var KPIDetailView = ({
|
|
|
67185
67568
|
workspaceDisplayNames,
|
|
67186
67569
|
hourlyOutputData,
|
|
67187
67570
|
hourlyThreshold,
|
|
67571
|
+
hourlyTargetOutput: chartMetrics?.hourly_target_output ?? null,
|
|
67572
|
+
idleTimeHourly: chartMetrics?.idle_time_hourly,
|
|
67573
|
+
timezone: lineTimezone,
|
|
67188
67574
|
urlDate,
|
|
67189
67575
|
urlShift,
|
|
67190
67576
|
navigate,
|
|
@@ -67250,8 +67636,8 @@ var KPIDetailView = ({
|
|
|
67250
67636
|
showIdleTime: idleTimeVlmEnabled
|
|
67251
67637
|
}
|
|
67252
67638
|
) : (
|
|
67253
|
-
//
|
|
67254
|
-
//
|
|
67639
|
+
// Keep the line output + underperforming cards SKU-aware,
|
|
67640
|
+
// while Average Efficiency stays aggregate.
|
|
67255
67641
|
/* @__PURE__ */ jsx(
|
|
67256
67642
|
MetricCards,
|
|
67257
67643
|
{
|
|
@@ -67296,6 +67682,8 @@ var KPIDetailView = ({
|
|
|
67296
67682
|
workspaceDisplayNames,
|
|
67297
67683
|
hourlyOutputData,
|
|
67298
67684
|
hourlyThreshold,
|
|
67685
|
+
idleTimeHourly: chartMetrics?.idle_time_hourly,
|
|
67686
|
+
timezone: lineTimezone,
|
|
67299
67687
|
urlDate,
|
|
67300
67688
|
urlShift,
|
|
67301
67689
|
navigate,
|
|
@@ -73532,12 +73920,12 @@ var getDaysDifference = (date, timezone = "UTC", shiftStartTime = "06:00") => {
|
|
|
73532
73920
|
operationalTodayDate.setHours(0, 0, 0, 0);
|
|
73533
73921
|
compareDateInTz.setHours(0, 0, 0, 0);
|
|
73534
73922
|
const diffTime = compareDateInTz.getTime() - operationalTodayDate.getTime();
|
|
73535
|
-
const
|
|
73536
|
-
if (
|
|
73537
|
-
if (
|
|
73538
|
-
if (
|
|
73539
|
-
if (
|
|
73540
|
-
if (
|
|
73923
|
+
const diffDays2 = Math.round(diffTime / (1e3 * 60 * 60 * 24));
|
|
73924
|
+
if (diffDays2 === 0) return "Today";
|
|
73925
|
+
if (diffDays2 === -1) return "Yesterday";
|
|
73926
|
+
if (diffDays2 === 1) return "Tomorrow";
|
|
73927
|
+
if (diffDays2 < -1) return `${Math.abs(diffDays2)} days ago`;
|
|
73928
|
+
if (diffDays2 > 1) return `${diffDays2} days ahead`;
|
|
73541
73929
|
return "Today";
|
|
73542
73930
|
};
|
|
73543
73931
|
var getInitialTab = (sourceType, defaultTab, fromMonthly, urlDate) => {
|
|
@@ -73973,7 +74361,7 @@ var WorkspaceDetailView = ({
|
|
|
73973
74361
|
() => resolveLiveSkuId(workspace?.sku_segments),
|
|
73974
74362
|
[workspace?.sku_segments]
|
|
73975
74363
|
);
|
|
73976
|
-
const activeSkuId = selectedSkuId
|
|
74364
|
+
const activeSkuId = selectedSkuId;
|
|
73977
74365
|
const resolvedLineId = effectiveLineId || workspace?.line_id || cachedDetailedMetrics?.line_id || cachedOverviewMetrics?.line_id || overviewFallback?.line_id;
|
|
73978
74366
|
const { timezone: cycleTimeTimezone } = useTimezone({
|
|
73979
74367
|
lineId: resolvedLineId || void 0,
|
|
@@ -74941,6 +75329,7 @@ var WorkspaceDetailView = ({
|
|
|
74941
75329
|
{
|
|
74942
75330
|
data: workspace.hourly_action_counts || [],
|
|
74943
75331
|
pphThreshold: workspace.pph_threshold || 0,
|
|
75332
|
+
hourlyTargetOutput: workspace.hourly_target_output,
|
|
74944
75333
|
shiftStart: workspace.shift_start || "06:00",
|
|
74945
75334
|
shiftEnd: workspace.shift_end,
|
|
74946
75335
|
showIdleTime: showChartIdleTime,
|
|
@@ -74948,7 +75337,7 @@ var WorkspaceDetailView = ({
|
|
|
74948
75337
|
idleTimeClips,
|
|
74949
75338
|
idleTimeClipClassifications,
|
|
74950
75339
|
shiftDate: idleClipDate,
|
|
74951
|
-
timezone,
|
|
75340
|
+
timezone: effectiveCycleTimeTimezone,
|
|
74952
75341
|
skuSegments: isSkuAware ? skuSegments : void 0,
|
|
74953
75342
|
activeSkuId
|
|
74954
75343
|
}
|
|
@@ -75087,6 +75476,7 @@ var WorkspaceDetailView = ({
|
|
|
75087
75476
|
{
|
|
75088
75477
|
data: workspace.hourly_action_counts || [],
|
|
75089
75478
|
pphThreshold: workspace.pph_threshold || 0,
|
|
75479
|
+
hourlyTargetOutput: workspace.hourly_target_output,
|
|
75090
75480
|
shiftStart: workspace.shift_start || "06:00",
|
|
75091
75481
|
shiftEnd: workspace.shift_end,
|
|
75092
75482
|
showIdleTime: showChartIdleTime,
|
|
@@ -75094,7 +75484,7 @@ var WorkspaceDetailView = ({
|
|
|
75094
75484
|
idleTimeClips,
|
|
75095
75485
|
idleTimeClipClassifications,
|
|
75096
75486
|
shiftDate: idleClipDate,
|
|
75097
|
-
timezone,
|
|
75487
|
+
timezone: effectiveCycleTimeTimezone,
|
|
75098
75488
|
skuSegments: isSkuAware ? skuSegments : void 0,
|
|
75099
75489
|
activeSkuId
|
|
75100
75490
|
}
|
|
@@ -78371,8 +78761,8 @@ var ImprovementCenterView = () => {
|
|
|
78371
78761
|
const firstSeen = new Date(new Date(openedAt).toLocaleString("en-US", { timeZone: timezone }));
|
|
78372
78762
|
if (Number.isNaN(firstSeen.getTime())) return void 0;
|
|
78373
78763
|
const now4 = new Date((/* @__PURE__ */ new Date()).toLocaleString("en-US", { timeZone: timezone }));
|
|
78374
|
-
const
|
|
78375
|
-
return Math.max(1, Math.ceil(
|
|
78764
|
+
const diffDays2 = Math.max(0, Math.floor((now4.getTime() - firstSeen.getTime()) / (1e3 * 60 * 60 * 24)));
|
|
78765
|
+
return Math.max(1, Math.ceil(diffDays2 / 7));
|
|
78376
78766
|
};
|
|
78377
78767
|
const toZonedDate = (value) => {
|
|
78378
78768
|
if (!value) return void 0;
|
|
@@ -79053,12 +79443,12 @@ var ThreadSidebar = ({
|
|
|
79053
79443
|
const date = new Date(dateString);
|
|
79054
79444
|
const now4 = /* @__PURE__ */ new Date();
|
|
79055
79445
|
const diffMs = now4.getTime() - date.getTime();
|
|
79056
|
-
const
|
|
79057
|
-
if (
|
|
79446
|
+
const diffDays2 = Math.floor(diffMs / (1e3 * 60 * 60 * 24));
|
|
79447
|
+
if (diffDays2 === 0) {
|
|
79058
79448
|
return "Today";
|
|
79059
|
-
} else if (
|
|
79449
|
+
} else if (diffDays2 === 1) {
|
|
79060
79450
|
return "Yesterday";
|
|
79061
|
-
} else if (
|
|
79451
|
+
} else if (diffDays2 < 7) {
|
|
79062
79452
|
return date.toLocaleDateString("en-US", { weekday: "short" });
|
|
79063
79453
|
} else {
|
|
79064
79454
|
return date.toLocaleDateString("en-US", { month: "short", day: "numeric" });
|