@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.js
CHANGED
|
@@ -4234,6 +4234,22 @@ var isDummyRow = (row, dummySet) => {
|
|
|
4234
4234
|
if (typeof skuId !== "string" || skuId.length === 0) return false;
|
|
4235
4235
|
return dummySet.has(skuId);
|
|
4236
4236
|
};
|
|
4237
|
+
var isActiveOutputRow = (row) => {
|
|
4238
|
+
const currentOutput = coerceOptionalNumber(row.current_output) ?? 0;
|
|
4239
|
+
const idealOutput = coerceOptionalNumber(row.ideal_output) ?? 0;
|
|
4240
|
+
return currentOutput > 0 || idealOutput > 0;
|
|
4241
|
+
};
|
|
4242
|
+
var roundHalfUpInt = (value) => Math.floor(value + 0.5);
|
|
4243
|
+
var dedupeStringsPreserveOrder = (values) => {
|
|
4244
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4245
|
+
const ordered = [];
|
|
4246
|
+
for (const value of values) {
|
|
4247
|
+
if (!value || seen.has(value)) continue;
|
|
4248
|
+
seen.add(value);
|
|
4249
|
+
ordered.push(value);
|
|
4250
|
+
}
|
|
4251
|
+
return ordered;
|
|
4252
|
+
};
|
|
4237
4253
|
var emptyAggregate = () => ({
|
|
4238
4254
|
current_output: 0,
|
|
4239
4255
|
ideal_output: 0,
|
|
@@ -4352,10 +4368,7 @@ var combineLineMetricsRows = (rows, dummySkuId) => {
|
|
|
4352
4368
|
);
|
|
4353
4369
|
const dummyLineMetricsRow = rows.find((row) => isDummyRow(row, dummySet));
|
|
4354
4370
|
const lineThresholdValue = dummyLineMetricsRow ? safeFloat(dummyLineMetricsRow.line_threshold) : safeFloat(rowsForAggregation[0]?.line_threshold ?? 0);
|
|
4355
|
-
const
|
|
4356
|
-
(acc, row) => acc + safeInt(row.underperforming_workspaces),
|
|
4357
|
-
0
|
|
4358
|
-
);
|
|
4371
|
+
const activeRealRows = rowsForAggregation.filter(isActiveOutputRow);
|
|
4359
4372
|
const weighted = (field) => {
|
|
4360
4373
|
const pairs = [];
|
|
4361
4374
|
rowsForAggregation.forEach((row, idx) => {
|
|
@@ -4377,6 +4390,12 @@ var combineLineMetricsRows = (rows, dummySkuId) => {
|
|
|
4377
4390
|
const avgEfficiency = weighted("avg_efficiency");
|
|
4378
4391
|
const avgCycleTime = weighted("avg_cycle_time");
|
|
4379
4392
|
const thresholdPph = weighted("threshold_pph");
|
|
4393
|
+
const underperformingWorkspaces = activeRealRows.length > 0 ? roundHalfUpInt(
|
|
4394
|
+
activeRealRows.reduce(
|
|
4395
|
+
(acc, row) => acc + safeInt(row.underperforming_workspaces),
|
|
4396
|
+
0
|
|
4397
|
+
) / activeRealRows.length
|
|
4398
|
+
) : 0;
|
|
4380
4399
|
const merged = mergeHourlyFields(rows);
|
|
4381
4400
|
const outputArrays = [];
|
|
4382
4401
|
for (const row of rowsForAggregation) {
|
|
@@ -4399,7 +4418,7 @@ var combineLineMetricsRows = (rows, dummySkuId) => {
|
|
|
4399
4418
|
}
|
|
4400
4419
|
const underperformingNames = [];
|
|
4401
4420
|
const underperformingUuids = [];
|
|
4402
|
-
for (const row of
|
|
4421
|
+
for (const row of activeRealRows) {
|
|
4403
4422
|
const names = row.underperforming_workspace_names;
|
|
4404
4423
|
if (Array.isArray(names)) {
|
|
4405
4424
|
for (const n of names) {
|
|
@@ -4413,6 +4432,8 @@ var combineLineMetricsRows = (rows, dummySkuId) => {
|
|
|
4413
4432
|
}
|
|
4414
4433
|
}
|
|
4415
4434
|
}
|
|
4435
|
+
const dedupedUnderperformingNames = dedupeStringsPreserveOrder(underperformingNames);
|
|
4436
|
+
const dedupedUnderperformingUuids = dedupeStringsPreserveOrder(underperformingUuids);
|
|
4416
4437
|
let totalWorkspacesValue = null;
|
|
4417
4438
|
const primaryTotal = coerceOptionalNumber(primary.total_workspaces);
|
|
4418
4439
|
if (primaryTotal !== null) {
|
|
@@ -4434,9 +4455,9 @@ var combineLineMetricsRows = (rows, dummySkuId) => {
|
|
|
4434
4455
|
line_threshold: lineThresholdValue,
|
|
4435
4456
|
threshold_pph: thresholdPph,
|
|
4436
4457
|
total_workspaces: safeInt(totalWorkspacesValue ?? 0),
|
|
4437
|
-
underperforming_workspaces:
|
|
4438
|
-
underperforming_workspace_names:
|
|
4439
|
-
underperforming_workspace_uuids:
|
|
4458
|
+
underperforming_workspaces: underperformingWorkspaces,
|
|
4459
|
+
underperforming_workspace_names: dedupedUnderperformingNames,
|
|
4460
|
+
underperforming_workspace_uuids: dedupedUnderperformingUuids,
|
|
4440
4461
|
output_array: outputArray,
|
|
4441
4462
|
output_hourly: merged.output_hourly,
|
|
4442
4463
|
idle_time_hourly: merged.idle_time_hourly,
|
|
@@ -5561,11 +5582,11 @@ var getDaysDifferenceInZone = (compareDate, timezone) => {
|
|
|
5561
5582
|
todayInZone.setHours(0, 0, 0, 0);
|
|
5562
5583
|
compareDateInZone.setHours(0, 0, 0, 0);
|
|
5563
5584
|
const diffTime = todayInZone.getTime() - compareDateInZone.getTime();
|
|
5564
|
-
const
|
|
5565
|
-
if (
|
|
5566
|
-
if (
|
|
5567
|
-
if (
|
|
5568
|
-
return `${
|
|
5585
|
+
const diffDays2 = Math.ceil(diffTime / (1e3 * 60 * 60 * 24));
|
|
5586
|
+
if (diffDays2 < 0) return "In the future";
|
|
5587
|
+
if (diffDays2 === 0) return "Today";
|
|
5588
|
+
if (diffDays2 === 1) return "Yesterday";
|
|
5589
|
+
return `${diffDays2} days ago`;
|
|
5569
5590
|
};
|
|
5570
5591
|
var getDashboardHeaderTimeInZone = (date = /* @__PURE__ */ new Date(), timezone, timeOptions, locale = DEFAULT_LOCALE) => {
|
|
5571
5592
|
const defaultOptions = {
|
|
@@ -13012,6 +13033,7 @@ var toWorkspaceDetailedMetrics = ({
|
|
|
13012
13033
|
const targetOutput = coerceNumber(data.target_output ?? data.total_day_output, 0);
|
|
13013
13034
|
const idealOutput = coerceNumber(data.ideal_output ?? data.ideal_output_until_now, 0);
|
|
13014
13035
|
const outputDifference = totalActions - idealOutput;
|
|
13036
|
+
const hourlyTargetOutput = Array.isArray(data.hourly_target_output) ? data.hourly_target_output.map((value) => value === null || value === void 0 ? null : coerceNumber(value, 0)) : null;
|
|
13015
13037
|
const hourlyCycleTimes = Array.isArray(data.hourly_cycle_times) ? data.hourly_cycle_times.map((value) => coerceNumber(value, 0)) : [];
|
|
13016
13038
|
const cycleCompletionClipCount = data.cycle_completion_clip_count === null || data.cycle_completion_clip_count === void 0 ? null : coerceNumber(data.cycle_completion_clip_count, 0);
|
|
13017
13039
|
const cycleTimeDataStatus = data.cycle_time_data_status === "missing_clips" ? "missing_clips" : data.cycle_time_data_status === "available" ? "available" : null;
|
|
@@ -13063,6 +13085,7 @@ var toWorkspaceDetailedMetrics = ({
|
|
|
13063
13085
|
avg_efficiency: coerceNumber(data.efficiency ?? data.avg_efficiency, 0),
|
|
13064
13086
|
total_actions: totalActions,
|
|
13065
13087
|
hourly_action_counts: hourlyActionCounts,
|
|
13088
|
+
hourly_target_output: hourlyTargetOutput,
|
|
13066
13089
|
hourly_cycle_times: hourlyCycleTimes,
|
|
13067
13090
|
cycle_completion_clip_count: cycleCompletionClipCount,
|
|
13068
13091
|
cycle_time_data_status: cycleTimeDataStatus,
|
|
@@ -19679,7 +19702,7 @@ function formatRelativeTime(timestamp) {
|
|
|
19679
19702
|
const diffSeconds = Math.floor(diffMs / 1e3);
|
|
19680
19703
|
const diffMinutes = Math.floor(diffSeconds / 60);
|
|
19681
19704
|
const diffHours = Math.floor(diffMinutes / 60);
|
|
19682
|
-
const
|
|
19705
|
+
const diffDays2 = Math.floor(diffHours / 24);
|
|
19683
19706
|
if (diffSeconds < 60) {
|
|
19684
19707
|
return "Less than a minute ago";
|
|
19685
19708
|
}
|
|
@@ -19691,8 +19714,8 @@ function formatRelativeTime(timestamp) {
|
|
|
19691
19714
|
const hourLabel = diffHours === 1 ? "hour" : "hours";
|
|
19692
19715
|
return `${diffHours} ${hourLabel} ago`;
|
|
19693
19716
|
}
|
|
19694
|
-
const dayLabel =
|
|
19695
|
-
return `${
|
|
19717
|
+
const dayLabel = diffDays2 === 1 ? "day" : "days";
|
|
19718
|
+
return `${diffDays2} ${dayLabel} ago`;
|
|
19696
19719
|
} catch (error) {
|
|
19697
19720
|
console.error("[formatRelativeTime] Error formatting timestamp:", error);
|
|
19698
19721
|
return "Unknown";
|
|
@@ -35191,6 +35214,223 @@ var Button = React144__namespace.forwardRef(
|
|
|
35191
35214
|
}
|
|
35192
35215
|
);
|
|
35193
35216
|
Button.displayName = "Button";
|
|
35217
|
+
var padTime = (value) => value.toString().padStart(2, "0");
|
|
35218
|
+
var parseTime = (timeValue) => {
|
|
35219
|
+
if (!timeValue) return null;
|
|
35220
|
+
const [hourPart, minutePart] = timeValue.split(":");
|
|
35221
|
+
const hour = Number.parseInt(hourPart, 10);
|
|
35222
|
+
const minute = Number.parseInt(minutePart ?? "0", 10);
|
|
35223
|
+
if (!Number.isFinite(hour) || !Number.isFinite(minute)) return null;
|
|
35224
|
+
return { hour, minute };
|
|
35225
|
+
};
|
|
35226
|
+
var normalizeIdleTimeHourly = (idleTimeHourly) => {
|
|
35227
|
+
if (!idleTimeHourly || typeof idleTimeHourly !== "object") {
|
|
35228
|
+
return {};
|
|
35229
|
+
}
|
|
35230
|
+
return Object.fromEntries(
|
|
35231
|
+
Object.entries(idleTimeHourly).map(([key, value]) => {
|
|
35232
|
+
if (Array.isArray(value)) return [key, value];
|
|
35233
|
+
if (value && Array.isArray(value.values)) {
|
|
35234
|
+
return [key, value.values];
|
|
35235
|
+
}
|
|
35236
|
+
return [key, []];
|
|
35237
|
+
})
|
|
35238
|
+
);
|
|
35239
|
+
};
|
|
35240
|
+
var interpretIdleValue = (value) => {
|
|
35241
|
+
if (value === 1 || value === "1") return "idle";
|
|
35242
|
+
if (value === 0 || value === "0") return "active";
|
|
35243
|
+
if (value === "x" || value === null || value === void 0) return "unknown";
|
|
35244
|
+
return "unknown";
|
|
35245
|
+
};
|
|
35246
|
+
var getShiftDurationMinutes = (shiftStart, shiftEnd) => {
|
|
35247
|
+
const start = parseTime(shiftStart);
|
|
35248
|
+
const end = parseTime(shiftEnd);
|
|
35249
|
+
if (!start || !end) return null;
|
|
35250
|
+
let duration = end.hour * 60 + end.minute - (start.hour * 60 + start.minute);
|
|
35251
|
+
if (duration <= 0) {
|
|
35252
|
+
duration += 24 * 60;
|
|
35253
|
+
}
|
|
35254
|
+
return duration > 0 ? duration : null;
|
|
35255
|
+
};
|
|
35256
|
+
var getShiftElapsedMinutes = ({
|
|
35257
|
+
shiftStart,
|
|
35258
|
+
shiftEnd,
|
|
35259
|
+
shiftDate,
|
|
35260
|
+
timezone,
|
|
35261
|
+
now: now4 = /* @__PURE__ */ new Date()
|
|
35262
|
+
}) => {
|
|
35263
|
+
if (!shiftDate || !timezone) return null;
|
|
35264
|
+
const startTime = parseTime(shiftStart);
|
|
35265
|
+
const endTime = parseTime(shiftEnd);
|
|
35266
|
+
if (!startTime || !endTime) return null;
|
|
35267
|
+
const shiftStartDate = dateFnsTz.fromZonedTime(
|
|
35268
|
+
`${shiftDate}T${padTime(startTime.hour)}:${padTime(startTime.minute)}:00`,
|
|
35269
|
+
timezone
|
|
35270
|
+
);
|
|
35271
|
+
let shiftEndDate = dateFnsTz.fromZonedTime(
|
|
35272
|
+
`${shiftDate}T${padTime(endTime.hour)}:${padTime(endTime.minute)}:00`,
|
|
35273
|
+
timezone
|
|
35274
|
+
);
|
|
35275
|
+
if (shiftEndDate <= shiftStartDate) {
|
|
35276
|
+
shiftEndDate = dateFns.addDays(shiftEndDate, 1);
|
|
35277
|
+
}
|
|
35278
|
+
const shiftMinutes = Math.max(dateFns.differenceInMinutes(shiftEndDate, shiftStartDate), 0);
|
|
35279
|
+
if (shiftMinutes <= 0) return null;
|
|
35280
|
+
const elapsed = dateFns.differenceInMinutes(now4, shiftStartDate);
|
|
35281
|
+
return Math.min(Math.max(elapsed, 0), shiftMinutes);
|
|
35282
|
+
};
|
|
35283
|
+
var maskFutureHourlySeries = ({
|
|
35284
|
+
data,
|
|
35285
|
+
shiftStart,
|
|
35286
|
+
shiftEnd,
|
|
35287
|
+
shiftDate,
|
|
35288
|
+
timezone,
|
|
35289
|
+
now: now4 = /* @__PURE__ */ new Date()
|
|
35290
|
+
}) => {
|
|
35291
|
+
if (!Array.isArray(data)) {
|
|
35292
|
+
return [];
|
|
35293
|
+
}
|
|
35294
|
+
const normalizedData = data.map((value) => typeof value === "number" && Number.isFinite(value) ? value : null);
|
|
35295
|
+
if (!normalizedData.length) {
|
|
35296
|
+
return normalizedData;
|
|
35297
|
+
}
|
|
35298
|
+
const shiftMinutes = getShiftDurationMinutes(shiftStart, shiftEnd);
|
|
35299
|
+
const elapsedMinutes = getShiftElapsedMinutes({
|
|
35300
|
+
shiftStart,
|
|
35301
|
+
shiftEnd,
|
|
35302
|
+
shiftDate,
|
|
35303
|
+
timezone,
|
|
35304
|
+
now: now4
|
|
35305
|
+
});
|
|
35306
|
+
if (shiftMinutes === null || elapsedMinutes === null || elapsedMinutes >= shiftMinutes) {
|
|
35307
|
+
return normalizedData;
|
|
35308
|
+
}
|
|
35309
|
+
return normalizedData.map((value, index) => {
|
|
35310
|
+
const slotStartMinutes = index * 60;
|
|
35311
|
+
return slotStartMinutes > elapsedMinutes ? null : value;
|
|
35312
|
+
});
|
|
35313
|
+
};
|
|
35314
|
+
var buildUptimeSeries = ({
|
|
35315
|
+
idleTimeHourly,
|
|
35316
|
+
shiftStart,
|
|
35317
|
+
shiftEnd,
|
|
35318
|
+
shiftDate,
|
|
35319
|
+
timezone,
|
|
35320
|
+
elapsedMinutes
|
|
35321
|
+
}) => {
|
|
35322
|
+
const normalizedIdle = normalizeIdleTimeHourly(idleTimeHourly || {});
|
|
35323
|
+
const hasIdleData = Object.keys(normalizedIdle).length > 0;
|
|
35324
|
+
if (!hasIdleData || !shiftDate || !timezone) {
|
|
35325
|
+
return {
|
|
35326
|
+
points: [],
|
|
35327
|
+
activeMinutes: 0,
|
|
35328
|
+
idleMinutes: 0,
|
|
35329
|
+
availableMinutes: 0,
|
|
35330
|
+
shiftMinutes: 0,
|
|
35331
|
+
elapsedMinutes: 0,
|
|
35332
|
+
hasData: false
|
|
35333
|
+
};
|
|
35334
|
+
}
|
|
35335
|
+
const startTime = parseTime(shiftStart);
|
|
35336
|
+
const endTime = parseTime(shiftEnd);
|
|
35337
|
+
if (!startTime || !endTime) {
|
|
35338
|
+
return {
|
|
35339
|
+
points: [],
|
|
35340
|
+
activeMinutes: 0,
|
|
35341
|
+
idleMinutes: 0,
|
|
35342
|
+
availableMinutes: 0,
|
|
35343
|
+
shiftMinutes: 0,
|
|
35344
|
+
elapsedMinutes: 0,
|
|
35345
|
+
hasData: false
|
|
35346
|
+
};
|
|
35347
|
+
}
|
|
35348
|
+
const shiftStartDate = dateFnsTz.fromZonedTime(
|
|
35349
|
+
`${shiftDate}T${padTime(startTime.hour)}:${padTime(startTime.minute)}:00`,
|
|
35350
|
+
timezone
|
|
35351
|
+
);
|
|
35352
|
+
let shiftEndDate = dateFnsTz.fromZonedTime(
|
|
35353
|
+
`${shiftDate}T${padTime(endTime.hour)}:${padTime(endTime.minute)}:00`,
|
|
35354
|
+
timezone
|
|
35355
|
+
);
|
|
35356
|
+
if (shiftEndDate <= shiftStartDate) {
|
|
35357
|
+
shiftEndDate = dateFns.addDays(shiftEndDate, 1);
|
|
35358
|
+
}
|
|
35359
|
+
const shiftMinutes = Math.max(dateFns.differenceInMinutes(shiftEndDate, shiftStartDate), 0);
|
|
35360
|
+
if (shiftMinutes <= 0) {
|
|
35361
|
+
return {
|
|
35362
|
+
points: [],
|
|
35363
|
+
activeMinutes: 0,
|
|
35364
|
+
idleMinutes: 0,
|
|
35365
|
+
availableMinutes: 0,
|
|
35366
|
+
shiftMinutes: 0,
|
|
35367
|
+
elapsedMinutes: 0,
|
|
35368
|
+
hasData: false
|
|
35369
|
+
};
|
|
35370
|
+
}
|
|
35371
|
+
const elapsedMinutesClamped = Number.isFinite(elapsedMinutes) ? Math.min(Math.max(Math.floor(elapsedMinutes ?? 0), 0), shiftMinutes) : shiftMinutes;
|
|
35372
|
+
const points = [];
|
|
35373
|
+
let activeMinutes = 0;
|
|
35374
|
+
let idleMinutes = 0;
|
|
35375
|
+
for (let minuteIndex = 0; minuteIndex < shiftMinutes; minuteIndex += 1) {
|
|
35376
|
+
const minuteDate = dateFns.addMinutes(shiftStartDate, minuteIndex);
|
|
35377
|
+
const timeLabel = dateFnsTz.formatInTimeZone(minuteDate, timezone, "h:mm a");
|
|
35378
|
+
if (minuteIndex >= elapsedMinutesClamped) {
|
|
35379
|
+
points.push({
|
|
35380
|
+
minuteIndex,
|
|
35381
|
+
timeLabel,
|
|
35382
|
+
uptime: null,
|
|
35383
|
+
status: "unknown"
|
|
35384
|
+
});
|
|
35385
|
+
continue;
|
|
35386
|
+
}
|
|
35387
|
+
const hourKey = dateFnsTz.formatInTimeZone(minuteDate, timezone, "H");
|
|
35388
|
+
const minuteKey = Number.parseInt(dateFnsTz.formatInTimeZone(minuteDate, timezone, "m"), 10);
|
|
35389
|
+
const hourBucket = normalizedIdle[hourKey] || [];
|
|
35390
|
+
const value = Array.isArray(hourBucket) ? hourBucket[minuteKey] : void 0;
|
|
35391
|
+
const status = interpretIdleValue(value);
|
|
35392
|
+
if (status === "active") activeMinutes += 1;
|
|
35393
|
+
if (status === "idle") idleMinutes += 1;
|
|
35394
|
+
points.push({
|
|
35395
|
+
minuteIndex,
|
|
35396
|
+
timeLabel,
|
|
35397
|
+
uptime: status === "active" ? 1 : status === "idle" ? 0 : null,
|
|
35398
|
+
status
|
|
35399
|
+
});
|
|
35400
|
+
}
|
|
35401
|
+
return {
|
|
35402
|
+
points,
|
|
35403
|
+
activeMinutes,
|
|
35404
|
+
idleMinutes,
|
|
35405
|
+
availableMinutes: activeMinutes + idleMinutes,
|
|
35406
|
+
shiftMinutes,
|
|
35407
|
+
elapsedMinutes: elapsedMinutesClamped,
|
|
35408
|
+
hasData: activeMinutes + idleMinutes > 0
|
|
35409
|
+
};
|
|
35410
|
+
};
|
|
35411
|
+
var getUptimeUtilizationPercent = (shift) => {
|
|
35412
|
+
const efficiency = shift.efficiency;
|
|
35413
|
+
if (Number.isFinite(efficiency)) {
|
|
35414
|
+
return Math.round(Math.max(0, Math.min(100, Number(efficiency))));
|
|
35415
|
+
}
|
|
35416
|
+
const idleSeconds = Number.isFinite(shift.idleTime) ? Number(shift.idleTime) : 0;
|
|
35417
|
+
const activeSeconds = Number.isFinite(shift.activeTimeSeconds) ? Number(shift.activeTimeSeconds) : null;
|
|
35418
|
+
let availableSeconds = Number.isFinite(shift.availableTimeSeconds) ? Number(shift.availableTimeSeconds) : null;
|
|
35419
|
+
if (availableSeconds === null) {
|
|
35420
|
+
if ((activeSeconds ?? 0) > 0 || idleSeconds > 0) {
|
|
35421
|
+
availableSeconds = (activeSeconds ?? 0) + idleSeconds;
|
|
35422
|
+
} else {
|
|
35423
|
+
return 0;
|
|
35424
|
+
}
|
|
35425
|
+
}
|
|
35426
|
+
if (availableSeconds <= 0) return 0;
|
|
35427
|
+
const clampedIdleSeconds = Math.min(Math.max(idleSeconds, 0), availableSeconds);
|
|
35428
|
+
const productiveSeconds = Math.max(
|
|
35429
|
+
activeSeconds ?? availableSeconds - clampedIdleSeconds,
|
|
35430
|
+
0
|
|
35431
|
+
);
|
|
35432
|
+
return Math.round(productiveSeconds / availableSeconds * 100);
|
|
35433
|
+
};
|
|
35194
35434
|
|
|
35195
35435
|
// src/components/charts/skuDividerUtils.ts
|
|
35196
35436
|
var HOURLY_TIME_RE = /^(\d{1,2}):(\d{2})/;
|
|
@@ -35203,37 +35443,162 @@ var parseTimeOfDay = (timeValue) => {
|
|
|
35203
35443
|
if (hour < 0 || hour > 23 || minute < 0 || minute > 59) return null;
|
|
35204
35444
|
return { hour, minute };
|
|
35205
35445
|
};
|
|
35206
|
-
var
|
|
35207
|
-
|
|
35446
|
+
var parseDateKey = (value) => {
|
|
35447
|
+
const [yearPart, monthPart, dayPart] = value.split("-").map(Number);
|
|
35448
|
+
if (!Number.isFinite(yearPart) || !Number.isFinite(monthPart) || !Number.isFinite(dayPart)) {
|
|
35449
|
+
return null;
|
|
35450
|
+
}
|
|
35451
|
+
return Date.UTC(yearPart, monthPart - 1, dayPart);
|
|
35452
|
+
};
|
|
35453
|
+
var diffDays = (left, right) => {
|
|
35454
|
+
const leftUtc = parseDateKey(left);
|
|
35455
|
+
const rightUtc = parseDateKey(right);
|
|
35456
|
+
if (leftUtc === null || rightUtc === null) return null;
|
|
35457
|
+
return Math.round((leftUtc - rightUtc) / (24 * 60 * 60 * 1e3));
|
|
35458
|
+
};
|
|
35459
|
+
var getSegmentMinutes = (isoString, timeZone, reportDate) => {
|
|
35460
|
+
const date = new Date(isoString);
|
|
35461
|
+
if (Number.isNaN(date.getTime())) return Number.NaN;
|
|
35462
|
+
const formatter = new Intl.DateTimeFormat("en-US", {
|
|
35463
|
+
timeZone,
|
|
35464
|
+
year: "numeric",
|
|
35465
|
+
month: "2-digit",
|
|
35466
|
+
day: "2-digit",
|
|
35467
|
+
hour: "2-digit",
|
|
35468
|
+
minute: "2-digit",
|
|
35469
|
+
hourCycle: "h23"
|
|
35470
|
+
});
|
|
35471
|
+
const parts = formatter.formatToParts(date).reduce((acc, part) => {
|
|
35472
|
+
if (part.type !== "literal") {
|
|
35473
|
+
acc[part.type] = part.value;
|
|
35474
|
+
}
|
|
35475
|
+
return acc;
|
|
35476
|
+
}, {});
|
|
35477
|
+
const dateKey = `${parts.year}-${parts.month}-${parts.day}`;
|
|
35478
|
+
let minutes = Number(parts.hour) * 60 + Number(parts.minute);
|
|
35479
|
+
const dayDelta = diffDays(dateKey, reportDate);
|
|
35480
|
+
if (dayDelta === null) return Number.NaN;
|
|
35481
|
+
minutes += dayDelta * 24 * 60;
|
|
35482
|
+
return minutes;
|
|
35483
|
+
};
|
|
35484
|
+
var computeSegmentOffsetUtc = (segment, shift) => {
|
|
35208
35485
|
const parsedMs = Date.parse(segment.start_time);
|
|
35209
35486
|
if (Number.isNaN(parsedMs)) return null;
|
|
35210
35487
|
const date = new Date(parsedMs);
|
|
35211
35488
|
const segHour = date.getUTCHours();
|
|
35212
35489
|
const segMinute = date.getUTCMinutes();
|
|
35213
35490
|
const segMinutes = segHour * 60 + segMinute;
|
|
35214
|
-
|
|
35491
|
+
const shiftStartMinutes = shift.startHour * 60 + shift.startMinute;
|
|
35215
35492
|
let deltaMinutes = segMinutes - shiftStartMinutes;
|
|
35216
35493
|
if (deltaMinutes < 0) deltaMinutes += 24 * 60;
|
|
35217
35494
|
const offsetHours = deltaMinutes / 60;
|
|
35218
35495
|
if (offsetHours < 0 || offsetHours > shift.slotCount) return null;
|
|
35219
35496
|
return offsetHours;
|
|
35220
35497
|
};
|
|
35498
|
+
var computeSegmentOffset = (segment, shift) => {
|
|
35499
|
+
if (!segment?.start_time) return null;
|
|
35500
|
+
if (shift.shiftDate && shift.timezone) {
|
|
35501
|
+
const segmentMinutes = getSegmentMinutes(
|
|
35502
|
+
segment.start_time,
|
|
35503
|
+
shift.timezone,
|
|
35504
|
+
shift.shiftDate
|
|
35505
|
+
);
|
|
35506
|
+
if (!Number.isFinite(segmentMinutes)) return null;
|
|
35507
|
+
const shiftStartMinutes = shift.startHour * 60 + shift.startMinute;
|
|
35508
|
+
const deltaMinutes = segmentMinutes - shiftStartMinutes;
|
|
35509
|
+
const offsetHours = deltaMinutes / 60;
|
|
35510
|
+
if (offsetHours < 0 || offsetHours > shift.slotCount) return null;
|
|
35511
|
+
return offsetHours;
|
|
35512
|
+
}
|
|
35513
|
+
return computeSegmentOffsetUtc(segment, shift);
|
|
35514
|
+
};
|
|
35221
35515
|
var resolveShiftWindow2 = (params) => {
|
|
35222
35516
|
const startTime = parseTimeOfDay(params.shiftStart);
|
|
35223
35517
|
if (!startTime) return null;
|
|
35224
35518
|
return {
|
|
35225
35519
|
startHour: startTime.hour,
|
|
35226
35520
|
startMinute: startTime.minute,
|
|
35227
|
-
slotCount: params.slotCount
|
|
35521
|
+
slotCount: params.slotCount,
|
|
35522
|
+
...params.shiftDate ? { shiftDate: params.shiftDate } : {},
|
|
35523
|
+
...params.timezone ? { timezone: params.timezone } : {}
|
|
35228
35524
|
};
|
|
35229
35525
|
};
|
|
35526
|
+
var resolveTimelineEndOffset = ({
|
|
35527
|
+
shiftStart,
|
|
35528
|
+
shiftEnd,
|
|
35529
|
+
slotCount,
|
|
35530
|
+
shiftDate,
|
|
35531
|
+
timezone,
|
|
35532
|
+
now: now4
|
|
35533
|
+
}) => {
|
|
35534
|
+
const normalizedSlotCount = Number.isFinite(slotCount) && slotCount > 0 ? slotCount : 0;
|
|
35535
|
+
if (!shiftDate || !timezone) {
|
|
35536
|
+
return normalizedSlotCount;
|
|
35537
|
+
}
|
|
35538
|
+
const shiftMinutes = getShiftDurationMinutes(shiftStart, shiftEnd);
|
|
35539
|
+
const elapsedMinutes = getShiftElapsedMinutes({
|
|
35540
|
+
shiftStart,
|
|
35541
|
+
shiftEnd,
|
|
35542
|
+
shiftDate,
|
|
35543
|
+
timezone,
|
|
35544
|
+
now: now4
|
|
35545
|
+
});
|
|
35546
|
+
if (shiftMinutes === null || elapsedMinutes === null) {
|
|
35547
|
+
return normalizedSlotCount;
|
|
35548
|
+
}
|
|
35549
|
+
if (elapsedMinutes >= shiftMinutes) {
|
|
35550
|
+
return normalizedSlotCount;
|
|
35551
|
+
}
|
|
35552
|
+
return Math.max(0, Math.min(elapsedMinutes / 60, normalizedSlotCount));
|
|
35553
|
+
};
|
|
35554
|
+
var formatSkuRailLabel = (label, segmentWidth, options = {}) => {
|
|
35555
|
+
const horizontalPadding = options.horizontalPadding ?? 8;
|
|
35556
|
+
const minVisibleChars = options.minVisibleChars ?? 4;
|
|
35557
|
+
const averageCharacterWidth = options.averageCharacterWidth ?? 6.6;
|
|
35558
|
+
const compactAverageCharacterWidth = options.compactAverageCharacterWidth ?? 5;
|
|
35559
|
+
const cssTruncation = options.cssTruncation ?? false;
|
|
35560
|
+
const fullLabelThreshold = 6;
|
|
35561
|
+
if (!label) return null;
|
|
35562
|
+
if (!Number.isFinite(segmentWidth) || segmentWidth <= horizontalPadding * 2) return null;
|
|
35563
|
+
const usableWidth = Math.max(segmentWidth - horizontalPadding * 2, 0);
|
|
35564
|
+
const maxChars = Math.floor(usableWidth / averageCharacterWidth);
|
|
35565
|
+
if (maxChars >= Math.max(minVisibleChars, fullLabelThreshold)) {
|
|
35566
|
+
if (label.length <= maxChars || cssTruncation) return label;
|
|
35567
|
+
if (maxChars <= 1) return null;
|
|
35568
|
+
return `${label.slice(0, Math.max(maxChars - 1, 1)).trimEnd()}\u2026`;
|
|
35569
|
+
}
|
|
35570
|
+
const compactLabel = buildCompactSkuRailLabel(label, Math.max(maxChars, 1));
|
|
35571
|
+
const compactMaxChars = Math.floor(usableWidth / compactAverageCharacterWidth);
|
|
35572
|
+
if (compactMaxChars < 1) return null;
|
|
35573
|
+
if (compactLabel.length <= compactMaxChars || cssTruncation) return compactLabel;
|
|
35574
|
+
if (compactMaxChars <= 2) {
|
|
35575
|
+
return compactLabel.slice(0, compactMaxChars);
|
|
35576
|
+
}
|
|
35577
|
+
return `${compactLabel.slice(0, Math.max(compactMaxChars - 1, 1)).trimEnd()}\u2026`;
|
|
35578
|
+
};
|
|
35579
|
+
var buildCompactSkuRailLabel = (label, maxChars) => {
|
|
35580
|
+
const words = label.trim().split(/\s+/).filter(Boolean);
|
|
35581
|
+
if (words.length === 0) return label;
|
|
35582
|
+
const [firstWord] = words;
|
|
35583
|
+
const acronym = words.map((word) => word[0]).join("").toUpperCase();
|
|
35584
|
+
if (maxChars <= 3 && acronym) {
|
|
35585
|
+
return acronym;
|
|
35586
|
+
}
|
|
35587
|
+
if (firstWord.length >= 4) {
|
|
35588
|
+
return firstWord;
|
|
35589
|
+
}
|
|
35590
|
+
return acronym || firstWord;
|
|
35591
|
+
};
|
|
35230
35592
|
var HourlyOutputChartComponent = ({
|
|
35231
35593
|
data,
|
|
35232
35594
|
pphThreshold,
|
|
35595
|
+
hourlyTargetOutput,
|
|
35233
35596
|
shiftStart,
|
|
35234
35597
|
shiftEnd,
|
|
35235
35598
|
showIdleTime = false,
|
|
35236
35599
|
idleTimeHourly,
|
|
35600
|
+
shiftDate,
|
|
35601
|
+
timezone,
|
|
35237
35602
|
skuSegments,
|
|
35238
35603
|
activeSkuId,
|
|
35239
35604
|
className = ""
|
|
@@ -35241,6 +35606,7 @@ var HourlyOutputChartComponent = ({
|
|
|
35241
35606
|
const containerRef = React144__namespace.default.useRef(null);
|
|
35242
35607
|
const [containerReady, setContainerReady] = React144__namespace.default.useState(false);
|
|
35243
35608
|
const [containerWidth, setContainerWidth] = React144__namespace.default.useState(0);
|
|
35609
|
+
const [hoveredSkuRailLabel, setHoveredSkuRailLabel] = React144__namespace.default.useState(null);
|
|
35244
35610
|
const idleSlots = React144__namespace.default.useMemo(
|
|
35245
35611
|
() => buildHourlyIdleSlots({
|
|
35246
35612
|
idleTimeHourly,
|
|
@@ -35386,14 +35752,54 @@ var HourlyOutputChartComponent = ({
|
|
|
35386
35752
|
}, [containerWidth]);
|
|
35387
35753
|
const shiftWindow = React144__namespace.default.useMemo(() => resolveShiftWindow2({
|
|
35388
35754
|
shiftStart,
|
|
35389
|
-
slotCount: SHIFT_DURATION
|
|
35390
|
-
|
|
35755
|
+
slotCount: SHIFT_DURATION,
|
|
35756
|
+
shiftDate,
|
|
35757
|
+
timezone
|
|
35758
|
+
}), [shiftStart, shiftEnd, SHIFT_DURATION, shiftDate, timezone]);
|
|
35759
|
+
const fallbackTimelineEndOffset = React144__namespace.default.useMemo(
|
|
35760
|
+
() => resolveTimelineEndOffset({
|
|
35761
|
+
shiftStart,
|
|
35762
|
+
shiftEnd,
|
|
35763
|
+
slotCount: SHIFT_DURATION,
|
|
35764
|
+
shiftDate,
|
|
35765
|
+
timezone
|
|
35766
|
+
}),
|
|
35767
|
+
[shiftStart, shiftEnd, SHIFT_DURATION, shiftDate, timezone]
|
|
35768
|
+
);
|
|
35769
|
+
const observedTimelineEndOffset = React144__namespace.default.useMemo(() => {
|
|
35770
|
+
let lastObservedMinute = -1;
|
|
35771
|
+
idleSlots.forEach((slot) => {
|
|
35772
|
+
slot.idleArray.forEach((value, minuteIndex) => {
|
|
35773
|
+
if (value !== "x" && value !== null && value !== void 0) {
|
|
35774
|
+
lastObservedMinute = Math.max(
|
|
35775
|
+
lastObservedMinute,
|
|
35776
|
+
slot.hourIndex * 60 + minuteIndex
|
|
35777
|
+
);
|
|
35778
|
+
}
|
|
35779
|
+
});
|
|
35780
|
+
});
|
|
35781
|
+
if (lastObservedMinute < 0) return null;
|
|
35782
|
+
return Math.min((lastObservedMinute + 1) / 60, SHIFT_DURATION);
|
|
35783
|
+
}, [idleSlots, SHIFT_DURATION]);
|
|
35784
|
+
const timelineEndOffset = observedTimelineEndOffset ?? fallbackTimelineEndOffset;
|
|
35785
|
+
const targetLineEndOffset = React144__namespace.default.useMemo(() => {
|
|
35786
|
+
if (timelineEndOffset >= SHIFT_DURATION) {
|
|
35787
|
+
return SHIFT_DURATION;
|
|
35788
|
+
}
|
|
35789
|
+
if (Number.isInteger(timelineEndOffset)) {
|
|
35790
|
+
return timelineEndOffset;
|
|
35791
|
+
}
|
|
35792
|
+
return Math.min(Math.floor(timelineEndOffset) + 1, SHIFT_DURATION);
|
|
35793
|
+
}, [timelineEndOffset, SHIFT_DURATION]);
|
|
35391
35794
|
const skuTimelineSegments = React144__namespace.default.useMemo(() => {
|
|
35392
|
-
if (!skuSegments || skuSegments.length === 0 || !shiftWindow)
|
|
35393
|
-
|
|
35394
|
-
|
|
35395
|
-
|
|
35396
|
-
|
|
35795
|
+
if (!skuSegments || skuSegments.length === 0 || !shiftWindow || timelineEndOffset <= 0) {
|
|
35796
|
+
return [];
|
|
35797
|
+
}
|
|
35798
|
+
const withOffsets = skuSegments.flatMap((segment) => {
|
|
35799
|
+
const offset = computeSegmentOffset(segment, shiftWindow);
|
|
35800
|
+
if (offset === null) return [];
|
|
35801
|
+
return [{ segment, offset }];
|
|
35802
|
+
}).sort((a, b) => a.offset - b.offset);
|
|
35397
35803
|
if (withOffsets.length === 0) return [];
|
|
35398
35804
|
const deduped = [];
|
|
35399
35805
|
const DUPLICATE_OFFSET_THRESHOLD = 1 / 60;
|
|
@@ -35407,9 +35813,9 @@ var HourlyOutputChartComponent = ({
|
|
|
35407
35813
|
deduped[0] = { ...deduped[0], offset: 0 };
|
|
35408
35814
|
}
|
|
35409
35815
|
return deduped.map((entry, index) => {
|
|
35410
|
-
const nextOffset = index < deduped.length - 1 ? deduped[index + 1].offset :
|
|
35411
|
-
const start = Math.max(0, Math.min(entry.offset,
|
|
35412
|
-
const end = Math.max(start, Math.min(nextOffset,
|
|
35816
|
+
const nextOffset = index < deduped.length - 1 ? deduped[index + 1].offset : timelineEndOffset;
|
|
35817
|
+
const start = Math.max(0, Math.min(entry.offset, timelineEndOffset));
|
|
35818
|
+
const end = Math.max(start, Math.min(nextOffset, timelineEndOffset));
|
|
35413
35819
|
return {
|
|
35414
35820
|
skuId: entry.segment.sku_id,
|
|
35415
35821
|
label: entry.segment.sku_code,
|
|
@@ -35418,15 +35824,66 @@ var HourlyOutputChartComponent = ({
|
|
|
35418
35824
|
pphThreshold: entry.segment.pph_threshold ?? pphThreshold
|
|
35419
35825
|
};
|
|
35420
35826
|
}).filter((segment) => segment.end > segment.start);
|
|
35421
|
-
}, [skuSegments, shiftWindow,
|
|
35827
|
+
}, [skuSegments, shiftWindow, timelineEndOffset, pphThreshold]);
|
|
35828
|
+
const targetTimelineSegments = React144__namespace.default.useMemo(() => {
|
|
35829
|
+
if (skuTimelineSegments.length === 0) return [];
|
|
35830
|
+
return skuTimelineSegments.map((segment, index) => ({
|
|
35831
|
+
...segment,
|
|
35832
|
+
end: index === skuTimelineSegments.length - 1 ? Math.max(segment.start, targetLineEndOffset) : segment.end
|
|
35833
|
+
})).filter((segment) => segment.end > segment.start);
|
|
35834
|
+
}, [skuTimelineSegments, targetLineEndOffset]);
|
|
35835
|
+
const hasHourlyTargetOutputProp = React144__namespace.default.useMemo(
|
|
35836
|
+
() => hourlyTargetOutput !== void 0,
|
|
35837
|
+
[hourlyTargetOutput]
|
|
35838
|
+
);
|
|
35839
|
+
const hasExplicitHourlyTargets = React144__namespace.default.useMemo(
|
|
35840
|
+
() => Array.isArray(hourlyTargetOutput) && hourlyTargetOutput.some((value) => value !== null && value !== void 0),
|
|
35841
|
+
[hourlyTargetOutput]
|
|
35842
|
+
);
|
|
35843
|
+
const hourlyTargetSegments = React144__namespace.default.useMemo(() => {
|
|
35844
|
+
if (!hasExplicitHourlyTargets) return [];
|
|
35845
|
+
const segments = [];
|
|
35846
|
+
let runStart = null;
|
|
35847
|
+
let runValue = null;
|
|
35848
|
+
const flush = (endIndex) => {
|
|
35849
|
+
if (runStart === null || runValue === null) return;
|
|
35850
|
+
segments.push({ start: runStart, end: endIndex, value: runValue });
|
|
35851
|
+
runStart = null;
|
|
35852
|
+
runValue = null;
|
|
35853
|
+
};
|
|
35854
|
+
for (let i = 0; i < SHIFT_DURATION; i += 1) {
|
|
35855
|
+
const rawValue = Array.isArray(hourlyTargetOutput) ? hourlyTargetOutput[i] : null;
|
|
35856
|
+
const value = rawValue === null || rawValue === void 0 ? null : Number(rawValue);
|
|
35857
|
+
if (value === null || !Number.isFinite(value)) {
|
|
35858
|
+
flush(i);
|
|
35859
|
+
continue;
|
|
35860
|
+
}
|
|
35861
|
+
if (runStart === null || runValue === null) {
|
|
35862
|
+
runStart = i;
|
|
35863
|
+
runValue = value;
|
|
35864
|
+
continue;
|
|
35865
|
+
}
|
|
35866
|
+
if (Math.abs(runValue - value) > 1e-6) {
|
|
35867
|
+
flush(i);
|
|
35868
|
+
runStart = i;
|
|
35869
|
+
runValue = value;
|
|
35870
|
+
}
|
|
35871
|
+
}
|
|
35872
|
+
flush(SHIFT_DURATION);
|
|
35873
|
+
return segments.filter((segment) => segment.end > segment.start);
|
|
35874
|
+
}, [SHIFT_DURATION, hasExplicitHourlyTargets, hourlyTargetOutput]);
|
|
35422
35875
|
const activeSkuHourIndices = React144__namespace.default.useMemo(() => {
|
|
35423
35876
|
const indices = /* @__PURE__ */ new Set();
|
|
35424
35877
|
const targets = Array(SHIFT_DURATION).fill(pphThreshold);
|
|
35425
|
-
if (!skuSegments || !shiftWindow) return { indices, targets };
|
|
35426
|
-
const segmentsWithOffsets = skuSegments.
|
|
35427
|
-
|
|
35428
|
-
|
|
35429
|
-
|
|
35878
|
+
if (!skuSegments || !shiftWindow) return { indices, targets, hasTimeline: false };
|
|
35879
|
+
const segmentsWithOffsets = skuSegments.flatMap((segment) => {
|
|
35880
|
+
const offset = computeSegmentOffset(segment, shiftWindow);
|
|
35881
|
+
if (offset === null) return [];
|
|
35882
|
+
return [{ ...segment, offset }];
|
|
35883
|
+
}).sort((a, b) => a.offset - b.offset);
|
|
35884
|
+
if (segmentsWithOffsets.length === 0) {
|
|
35885
|
+
return { indices, targets, hasTimeline: false };
|
|
35886
|
+
}
|
|
35430
35887
|
for (let i = 0; i < SHIFT_DURATION; i++) {
|
|
35431
35888
|
const midpoint = i + 0.5;
|
|
35432
35889
|
let activeSeg = segmentsWithOffsets[0];
|
|
@@ -35446,13 +35903,15 @@ var HourlyOutputChartComponent = ({
|
|
|
35446
35903
|
}
|
|
35447
35904
|
}
|
|
35448
35905
|
}
|
|
35449
|
-
return { indices, targets };
|
|
35906
|
+
return { indices, targets, hasTimeline: true };
|
|
35450
35907
|
}, [skuSegments, activeSkuId, shiftWindow, SHIFT_DURATION, pphThreshold]);
|
|
35451
35908
|
const chartData = React144__namespace.default.useMemo(() => {
|
|
35452
|
-
const { indices, targets } = activeSkuHourIndices;
|
|
35909
|
+
const { indices, targets, hasTimeline } = activeSkuHourIndices;
|
|
35453
35910
|
return Array.from({ length: SHIFT_DURATION }, (_, i) => {
|
|
35454
35911
|
const idleSlot = idleSlots[i];
|
|
35455
|
-
const
|
|
35912
|
+
const explicitTarget = hasHourlyTargetOutputProp ? hourlyTargetOutput?.[i] ?? null : void 0;
|
|
35913
|
+
const currentTarget = hasHourlyTargetOutputProp ? explicitTarget : targets[i] || pphThreshold;
|
|
35914
|
+
const comparisonTarget = currentTarget === null || currentTarget === void 0 ? targets[i] || pphThreshold : currentTarget;
|
|
35456
35915
|
return {
|
|
35457
35916
|
hourIndex: idleSlot?.hourIndex ?? i,
|
|
35458
35917
|
hour: idleSlot?.hour || "",
|
|
@@ -35460,16 +35919,16 @@ var HourlyOutputChartComponent = ({
|
|
|
35460
35919
|
output: animatedData[i] || 0,
|
|
35461
35920
|
originalOutput: data[i] || 0,
|
|
35462
35921
|
// Keep original data for labels
|
|
35463
|
-
target: currentTarget,
|
|
35464
|
-
color: (animatedData[i] || 0) >=
|
|
35922
|
+
target: currentTarget ?? null,
|
|
35923
|
+
color: (animatedData[i] || 0) >= comparisonTarget ? "#00AB45" : "#E34329",
|
|
35465
35924
|
idleMinutes: idleSlot?.idleMinutes || 0,
|
|
35466
35925
|
idleArray: idleSlot?.idleArray || [],
|
|
35467
35926
|
skuIndex: i,
|
|
35468
35927
|
isHighlighted: indices.has(i),
|
|
35469
|
-
isDimmed: !!activeSkuId && !indices.has(i)
|
|
35928
|
+
isDimmed: hasTimeline && !!activeSkuId && !indices.has(i)
|
|
35470
35929
|
};
|
|
35471
35930
|
});
|
|
35472
|
-
}, [animatedData, data, pphThreshold, idleSlots, SHIFT_DURATION, activeSkuHourIndices, activeSkuId]);
|
|
35931
|
+
}, [animatedData, data, pphThreshold, idleSlots, SHIFT_DURATION, activeSkuHourIndices, activeSkuId, hourlyTargetOutput, hasHourlyTargetOutputProp]);
|
|
35473
35932
|
const renderSkuTimelineRail = React144__namespace.default.useCallback((props) => {
|
|
35474
35933
|
if (!skuTimelineSegments.length || SHIFT_DURATION <= 0) return null;
|
|
35475
35934
|
const offset = props?.offset;
|
|
@@ -35481,8 +35940,9 @@ var HourlyOutputChartComponent = ({
|
|
|
35481
35940
|
const railHeight = 3;
|
|
35482
35941
|
const railY = top - 10;
|
|
35483
35942
|
const baselineY = railY + railHeight / 2;
|
|
35484
|
-
const
|
|
35485
|
-
|
|
35943
|
+
const showHoverLabel = (label, centerX, rY) => {
|
|
35944
|
+
setHoveredSkuRailLabel({ label, centerX, railY: rY });
|
|
35945
|
+
};
|
|
35486
35946
|
return /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
|
|
35487
35947
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
35488
35948
|
"line",
|
|
@@ -35500,9 +35960,43 @@ var HourlyOutputChartComponent = ({
|
|
|
35500
35960
|
const xStart = left + segment.start / SHIFT_DURATION * width;
|
|
35501
35961
|
const xEnd = left + segment.end / SHIFT_DURATION * width;
|
|
35502
35962
|
const segmentWidth = Math.max(1, xEnd - xStart);
|
|
35963
|
+
const labelPadding = segmentWidth < 48 ? 4 : 8;
|
|
35964
|
+
const inlineLabelText = formatSkuRailLabel(segment.label, segmentWidth, {
|
|
35965
|
+
horizontalPadding: labelPadding,
|
|
35966
|
+
cssTruncation: true
|
|
35967
|
+
});
|
|
35968
|
+
const badgeLabelText = formatSkuRailLabel(segment.label, 28, {
|
|
35969
|
+
horizontalPadding: 4,
|
|
35970
|
+
cssTruncation: true
|
|
35971
|
+
});
|
|
35972
|
+
const isMicroSegment = segmentWidth < 18;
|
|
35973
|
+
const labelText = isMicroSegment ? badgeLabelText : inlineLabelText;
|
|
35974
|
+
const labelClipWidth = Math.max(segmentWidth - labelPadding * 2, 0);
|
|
35503
35975
|
const isActive = !!activeSkuId && segment.skuId === activeSkuId;
|
|
35504
35976
|
const isDimmed = !!activeSkuId && segment.skuId !== activeSkuId;
|
|
35977
|
+
const hoverHitWidth = Math.max(segmentWidth + 12, isMicroSegment ? 20 : segmentWidth);
|
|
35978
|
+
const hoverHitX = Math.max(
|
|
35979
|
+
left,
|
|
35980
|
+
Math.min(xStart - (hoverHitWidth - segmentWidth) / 2, left + width - hoverHitWidth)
|
|
35981
|
+
);
|
|
35982
|
+
const hoverHitHeight = isMicroSegment ? 34 : 28;
|
|
35983
|
+
const hoverHitY = railY - (isMicroSegment ? 30 : 24);
|
|
35984
|
+
const microBadgeWidth = labelText ? Math.max(labelText.length * 6.2 + 10, 18) : 0;
|
|
35985
|
+
const microBadgeX = xStart + segmentWidth / 2 - microBadgeWidth / 2;
|
|
35986
|
+
const microBadgeY = railY - 24;
|
|
35505
35987
|
return /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
|
|
35988
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
35989
|
+
"rect",
|
|
35990
|
+
{
|
|
35991
|
+
x: hoverHitX,
|
|
35992
|
+
y: hoverHitY,
|
|
35993
|
+
width: hoverHitWidth,
|
|
35994
|
+
height: hoverHitHeight,
|
|
35995
|
+
fill: "transparent",
|
|
35996
|
+
onMouseEnter: () => showHoverLabel(segment.label, xStart + segmentWidth / 2, railY),
|
|
35997
|
+
onMouseLeave: () => setHoveredSkuRailLabel((current) => current?.label === segment.label ? null : current)
|
|
35998
|
+
}
|
|
35999
|
+
),
|
|
35506
36000
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
35507
36001
|
"rect",
|
|
35508
36002
|
{
|
|
@@ -35513,7 +36007,7 @@ var HourlyOutputChartComponent = ({
|
|
|
35513
36007
|
rx: 1.5,
|
|
35514
36008
|
fill: isActive ? "#3b82f6" : "#cbd5e1",
|
|
35515
36009
|
opacity: isDimmed ? 0.3 : 1,
|
|
35516
|
-
style: { transition: "all 0.3s ease" }
|
|
36010
|
+
style: { transition: "all 0.3s ease", pointerEvents: "none" }
|
|
35517
36011
|
}
|
|
35518
36012
|
),
|
|
35519
36013
|
index > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -35525,22 +36019,59 @@ var HourlyOutputChartComponent = ({
|
|
|
35525
36019
|
y2: railY + railHeight + 3,
|
|
35526
36020
|
stroke: "#94a3b8",
|
|
35527
36021
|
strokeWidth: 1,
|
|
35528
|
-
opacity: 0.6
|
|
36022
|
+
opacity: 0.6,
|
|
36023
|
+
style: { pointerEvents: "none" }
|
|
35529
36024
|
}
|
|
35530
36025
|
),
|
|
35531
|
-
|
|
35532
|
-
|
|
36026
|
+
isMicroSegment && labelText && /* @__PURE__ */ jsxRuntime.jsxs("g", { style: { pointerEvents: "none" }, children: [
|
|
36027
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
36028
|
+
"rect",
|
|
36029
|
+
{
|
|
36030
|
+
x: microBadgeX,
|
|
36031
|
+
y: microBadgeY,
|
|
36032
|
+
width: microBadgeWidth,
|
|
36033
|
+
height: 14,
|
|
36034
|
+
rx: 7,
|
|
36035
|
+
fill: "white",
|
|
36036
|
+
stroke: isActive ? "#3b82f6" : "#cbd5e1",
|
|
36037
|
+
strokeWidth: 1,
|
|
36038
|
+
opacity: isDimmed ? 0.55 : 0.98
|
|
36039
|
+
}
|
|
36040
|
+
),
|
|
36041
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
36042
|
+
"text",
|
|
36043
|
+
{
|
|
36044
|
+
x: xStart + segmentWidth / 2,
|
|
36045
|
+
y: microBadgeY + 10,
|
|
36046
|
+
textAnchor: "middle",
|
|
36047
|
+
fontSize: 8,
|
|
36048
|
+
fontWeight: 700,
|
|
36049
|
+
fill: isActive ? "#2563eb" : "#64748b",
|
|
36050
|
+
opacity: isDimmed ? 0.55 : 1,
|
|
36051
|
+
style: { transition: "all 0.3s ease" },
|
|
36052
|
+
children: labelText
|
|
36053
|
+
}
|
|
36054
|
+
)
|
|
36055
|
+
] }),
|
|
36056
|
+
!isMicroSegment && labelText && labelClipWidth > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
36057
|
+
"foreignObject",
|
|
35533
36058
|
{
|
|
35534
|
-
x: xStart +
|
|
35535
|
-
y:
|
|
35536
|
-
|
|
35537
|
-
|
|
35538
|
-
|
|
35539
|
-
|
|
35540
|
-
|
|
35541
|
-
|
|
35542
|
-
|
|
35543
|
-
|
|
36059
|
+
x: xStart + labelPadding,
|
|
36060
|
+
y: railY - 24,
|
|
36061
|
+
width: labelClipWidth,
|
|
36062
|
+
height: 18,
|
|
36063
|
+
style: { pointerEvents: "none", overflow: "visible" },
|
|
36064
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
36065
|
+
"div",
|
|
36066
|
+
{
|
|
36067
|
+
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"}`,
|
|
36068
|
+
style: {
|
|
36069
|
+
opacity: isDimmed ? 0.4 : 1,
|
|
36070
|
+
transition: "all 0.3s ease"
|
|
36071
|
+
},
|
|
36072
|
+
children: labelText
|
|
36073
|
+
}
|
|
36074
|
+
)
|
|
35544
36075
|
}
|
|
35545
36076
|
)
|
|
35546
36077
|
] }, `sku-rail-${segment.skuId}-${segment.start}-${index}`);
|
|
@@ -35598,14 +36129,17 @@ var HourlyOutputChartComponent = ({
|
|
|
35598
36129
|
);
|
|
35599
36130
|
}, [idleBarState.visible, idleBarState.key, idleBarState.shouldAnimate]);
|
|
35600
36131
|
const maxDataValue = Math.max(...data, 0);
|
|
35601
|
-
const
|
|
36132
|
+
const numericChartTargets = chartData.map((d) => d.target).filter((target) => target !== null && Number.isFinite(target));
|
|
36133
|
+
const maxTargetValue = Math.max(...numericChartTargets, pphThreshold, 0);
|
|
35602
36134
|
const maxYValue = Math.max(
|
|
35603
36135
|
Math.ceil(maxTargetValue * 1.5),
|
|
35604
36136
|
Math.ceil(maxDataValue * 1.15)
|
|
35605
36137
|
// Add 15% headroom above max value
|
|
35606
36138
|
);
|
|
35607
36139
|
const generateYAxisTicks = () => {
|
|
35608
|
-
const uniqueTargets = [...new Set(
|
|
36140
|
+
const uniqueTargets = [...new Set(
|
|
36141
|
+
chartData.map((d) => d.target).filter((target) => target !== null && Number.isFinite(target)).map((target) => Math.round(target))
|
|
36142
|
+
)].sort((a, b) => a - b);
|
|
35609
36143
|
const rawTicks = [0];
|
|
35610
36144
|
uniqueTargets.forEach((target) => {
|
|
35611
36145
|
if (target > 0) {
|
|
@@ -35640,14 +36174,54 @@ var HourlyOutputChartComponent = ({
|
|
|
35640
36174
|
};
|
|
35641
36175
|
const renderTargetLine = React144__namespace.default.useCallback((props) => {
|
|
35642
36176
|
const { offset, yAxisMap } = props;
|
|
35643
|
-
if (!offset || !yAxisMap || SHIFT_DURATION <= 0) return null;
|
|
36177
|
+
if (!offset || !yAxisMap || SHIFT_DURATION <= 0 || targetLineEndOffset <= 0) return null;
|
|
35644
36178
|
const { left, width } = offset;
|
|
35645
36179
|
const yAxis = yAxisMap["default"] || yAxisMap[0];
|
|
35646
36180
|
if (!yAxis || !yAxis.scale) return null;
|
|
35647
36181
|
const lines = [];
|
|
35648
36182
|
const offsetToX = (o) => left + o / SHIFT_DURATION * width;
|
|
35649
|
-
if (
|
|
35650
|
-
|
|
36183
|
+
if (hasHourlyTargetOutputProp && hourlyTargetSegments.length > 0) {
|
|
36184
|
+
hourlyTargetSegments.forEach((segment, index) => {
|
|
36185
|
+
const y = yAxis.scale(segment.value);
|
|
36186
|
+
const xStart = offsetToX(segment.start);
|
|
36187
|
+
const xEnd = offsetToX(segment.end);
|
|
36188
|
+
lines.push(
|
|
36189
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
36190
|
+
"line",
|
|
36191
|
+
{
|
|
36192
|
+
x1: xStart,
|
|
36193
|
+
y1: y,
|
|
36194
|
+
x2: xEnd,
|
|
36195
|
+
y2: y,
|
|
36196
|
+
stroke: "#E34329",
|
|
36197
|
+
strokeDasharray: "3 3",
|
|
36198
|
+
strokeWidth: 2
|
|
36199
|
+
},
|
|
36200
|
+
`target-hourly-h-${index}`
|
|
36201
|
+
)
|
|
36202
|
+
);
|
|
36203
|
+
const next = hourlyTargetSegments[index + 1];
|
|
36204
|
+
if (next && Math.abs(next.value - segment.value) > 1e-6) {
|
|
36205
|
+
const nextY = yAxis.scale(next.value);
|
|
36206
|
+
lines.push(
|
|
36207
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
36208
|
+
"line",
|
|
36209
|
+
{
|
|
36210
|
+
x1: xEnd,
|
|
36211
|
+
y1: y,
|
|
36212
|
+
x2: xEnd,
|
|
36213
|
+
y2: nextY,
|
|
36214
|
+
stroke: "#E34329",
|
|
36215
|
+
strokeDasharray: "3 3",
|
|
36216
|
+
strokeWidth: 2
|
|
36217
|
+
},
|
|
36218
|
+
`target-hourly-v-${index}`
|
|
36219
|
+
)
|
|
36220
|
+
);
|
|
36221
|
+
}
|
|
36222
|
+
});
|
|
36223
|
+
} else if (!hasHourlyTargetOutputProp && targetTimelineSegments.length > 0) {
|
|
36224
|
+
targetTimelineSegments.forEach((segment, index) => {
|
|
35651
36225
|
const target = segment.pphThreshold || pphThreshold;
|
|
35652
36226
|
const y = yAxis.scale(target);
|
|
35653
36227
|
const xStart = offsetToX(segment.start);
|
|
@@ -35667,7 +36241,7 @@ var HourlyOutputChartComponent = ({
|
|
|
35667
36241
|
`target-h-${index}`
|
|
35668
36242
|
)
|
|
35669
36243
|
);
|
|
35670
|
-
const next =
|
|
36244
|
+
const next = targetTimelineSegments[index + 1];
|
|
35671
36245
|
if (next) {
|
|
35672
36246
|
const nextTarget = next.pphThreshold || pphThreshold;
|
|
35673
36247
|
if (nextTarget !== target) {
|
|
@@ -35690,7 +36264,7 @@ var HourlyOutputChartComponent = ({
|
|
|
35690
36264
|
}
|
|
35691
36265
|
}
|
|
35692
36266
|
});
|
|
35693
|
-
} else {
|
|
36267
|
+
} else if (!hasHourlyTargetOutputProp) {
|
|
35694
36268
|
const y = yAxis.scale(pphThreshold);
|
|
35695
36269
|
lines.push(
|
|
35696
36270
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -35709,10 +36283,13 @@ var HourlyOutputChartComponent = ({
|
|
|
35709
36283
|
);
|
|
35710
36284
|
}
|
|
35711
36285
|
return /* @__PURE__ */ jsxRuntime.jsx("g", { children: lines });
|
|
35712
|
-
}, [
|
|
36286
|
+
}, [hourlyTargetSegments, targetTimelineSegments, SHIFT_DURATION, pphThreshold, targetLineEndOffset, hasHourlyTargetOutputProp]);
|
|
35713
36287
|
const renderLegend = () => {
|
|
35714
|
-
const uniqueTargets = [...new Set(
|
|
35715
|
-
|
|
36288
|
+
const uniqueTargets = [...new Set(
|
|
36289
|
+
chartData.map((d) => d.target).filter((target) => target !== null && Number.isFinite(target)).map((target) => Math.round(target))
|
|
36290
|
+
)].sort((a, b) => a - b);
|
|
36291
|
+
const unitLabel = hasHourlyTargetOutputProp ? "units" : "units/hr";
|
|
36292
|
+
const targetText = uniqueTargets.length === 0 ? `Target` : uniqueTargets.length === 1 ? `Target: ${uniqueTargets[0]} ${unitLabel}` : `Target: ${uniqueTargets[0]} - ${uniqueTargets[uniqueTargets.length - 1]} ${unitLabel}`;
|
|
35716
36293
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center text-sm text-gray-600 bg-white py-1", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 border border-gray-100 rounded-full px-3 py-1", children: [
|
|
35717
36294
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-8 flex items-center", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full border-t-2 border-[#E34329] border-dashed" }) }),
|
|
35718
36295
|
/* @__PURE__ */ jsxRuntime.jsx("span", { children: targetText })
|
|
@@ -35725,254 +36302,274 @@ var HourlyOutputChartComponent = ({
|
|
|
35725
36302
|
className: `w-full h-full min-w-0 flex flex-col ${className}`,
|
|
35726
36303
|
style: { minHeight: "200px", minWidth: 0 },
|
|
35727
36304
|
children: [
|
|
35728
|
-
containerReady ? /* @__PURE__ */ jsxRuntime.
|
|
35729
|
-
recharts.
|
|
35730
|
-
|
|
35731
|
-
|
|
35732
|
-
|
|
35733
|
-
|
|
35734
|
-
|
|
35735
|
-
|
|
35736
|
-
|
|
35737
|
-
|
|
35738
|
-
|
|
35739
|
-
|
|
35740
|
-
|
|
35741
|
-
|
|
35742
|
-
|
|
35743
|
-
|
|
35744
|
-
|
|
35745
|
-
|
|
35746
|
-
|
|
35747
|
-
|
|
35748
|
-
|
|
35749
|
-
|
|
35750
|
-
|
|
35751
|
-
|
|
35752
|
-
|
|
35753
|
-
|
|
35754
|
-
|
|
35755
|
-
|
|
35756
|
-
|
|
35757
|
-
),
|
|
35758
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
35759
|
-
recharts.XAxis,
|
|
35760
|
-
{
|
|
35761
|
-
xAxisId: "sku",
|
|
35762
|
-
type: "number",
|
|
35763
|
-
dataKey: "skuIndex",
|
|
35764
|
-
domain: [0, Math.max(SHIFT_DURATION, 0)],
|
|
35765
|
-
hide: true,
|
|
35766
|
-
allowDataOverflow: true
|
|
35767
|
-
}
|
|
35768
|
-
),
|
|
35769
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
35770
|
-
recharts.YAxis,
|
|
35771
|
-
{
|
|
35772
|
-
yAxisId: "default",
|
|
35773
|
-
tickMargin: 8,
|
|
35774
|
-
width: 48,
|
|
35775
|
-
domain: [0, maxYValue],
|
|
35776
|
-
ticks: generateYAxisTicks(),
|
|
35777
|
-
tickFormatter: (value) => value,
|
|
35778
|
-
tick: (props) => {
|
|
35779
|
-
const { x, y, payload } = props;
|
|
35780
|
-
return /* @__PURE__ */ jsxRuntime.jsx("g", { transform: `translate(${x},${y})`, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
35781
|
-
"text",
|
|
35782
|
-
{
|
|
35783
|
-
x: -2,
|
|
35784
|
-
y: 0,
|
|
35785
|
-
dy: 4,
|
|
35786
|
-
textAnchor: "end",
|
|
35787
|
-
fill: "#666",
|
|
35788
|
-
fontSize: 12,
|
|
35789
|
-
children: payload.value
|
|
35790
|
-
},
|
|
35791
|
-
`tick-${payload.value}-${x}-${y}`
|
|
35792
|
-
) });
|
|
36305
|
+
containerReady ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-h-0 relative", children: [
|
|
36306
|
+
/* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
36307
|
+
recharts.BarChart,
|
|
36308
|
+
{
|
|
36309
|
+
data: chartData,
|
|
36310
|
+
margin: {
|
|
36311
|
+
// Reserve headroom for the SKU timeline rail + staggered
|
|
36312
|
+
// labels only when SKU segments are rendered. Non-SKU charts
|
|
36313
|
+
// keep the original 10px top so recharts has enough vertical
|
|
36314
|
+
// space to show the target (pph) tick label on the Y-axis.
|
|
36315
|
+
top: skuTimelineSegments.length > 0 ? 40 : 10,
|
|
36316
|
+
right: 10,
|
|
36317
|
+
bottom: 10,
|
|
36318
|
+
left: 6
|
|
36319
|
+
},
|
|
36320
|
+
barCategoryGap: "25%",
|
|
36321
|
+
children: [
|
|
36322
|
+
/* @__PURE__ */ jsxRuntime.jsx(recharts.CartesianGrid, { strokeDasharray: "3 3", vertical: false }),
|
|
36323
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
36324
|
+
recharts.XAxis,
|
|
36325
|
+
{
|
|
36326
|
+
xAxisId: "default",
|
|
36327
|
+
dataKey: "hour",
|
|
36328
|
+
tick: { fontSize: xAxisConfig.tickFont },
|
|
36329
|
+
interval: xAxisConfig.interval,
|
|
36330
|
+
angle: xAxisConfig.angle,
|
|
36331
|
+
textAnchor: "end",
|
|
36332
|
+
tickMargin: xAxisConfig.tickMargin,
|
|
36333
|
+
height: xAxisConfig.height
|
|
35793
36334
|
}
|
|
35794
|
-
|
|
35795
|
-
|
|
35796
|
-
|
|
35797
|
-
|
|
35798
|
-
|
|
35799
|
-
|
|
35800
|
-
|
|
35801
|
-
|
|
35802
|
-
|
|
35803
|
-
|
|
35804
|
-
|
|
35805
|
-
|
|
35806
|
-
|
|
35807
|
-
|
|
35808
|
-
|
|
35809
|
-
|
|
35810
|
-
|
|
35811
|
-
|
|
35812
|
-
|
|
35813
|
-
|
|
35814
|
-
|
|
35815
|
-
|
|
35816
|
-
|
|
35817
|
-
|
|
35818
|
-
|
|
35819
|
-
|
|
35820
|
-
|
|
35821
|
-
|
|
35822
|
-
|
|
35823
|
-
|
|
35824
|
-
|
|
35825
|
-
|
|
35826
|
-
|
|
35827
|
-
|
|
35828
|
-
|
|
35829
|
-
|
|
35830
|
-
|
|
35831
|
-
|
|
35832
|
-
|
|
35833
|
-
|
|
35834
|
-
|
|
35835
|
-
|
|
35836
|
-
|
|
35837
|
-
|
|
35838
|
-
|
|
35839
|
-
|
|
35840
|
-
|
|
36335
|
+
),
|
|
36336
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
36337
|
+
recharts.XAxis,
|
|
36338
|
+
{
|
|
36339
|
+
xAxisId: "sku",
|
|
36340
|
+
type: "number",
|
|
36341
|
+
dataKey: "skuIndex",
|
|
36342
|
+
domain: [0, Math.max(SHIFT_DURATION, 0)],
|
|
36343
|
+
hide: true,
|
|
36344
|
+
allowDataOverflow: true
|
|
36345
|
+
}
|
|
36346
|
+
),
|
|
36347
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
36348
|
+
recharts.YAxis,
|
|
36349
|
+
{
|
|
36350
|
+
yAxisId: "default",
|
|
36351
|
+
tickMargin: 8,
|
|
36352
|
+
width: 48,
|
|
36353
|
+
domain: [0, maxYValue],
|
|
36354
|
+
ticks: generateYAxisTicks(),
|
|
36355
|
+
tickFormatter: (value) => value,
|
|
36356
|
+
tick: (props) => {
|
|
36357
|
+
const { x, y, payload } = props;
|
|
36358
|
+
return /* @__PURE__ */ jsxRuntime.jsx("g", { transform: `translate(${x},${y})`, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
36359
|
+
"text",
|
|
36360
|
+
{
|
|
36361
|
+
x: -2,
|
|
36362
|
+
y: 0,
|
|
36363
|
+
dy: 4,
|
|
36364
|
+
textAnchor: "end",
|
|
36365
|
+
fill: "#666",
|
|
36366
|
+
fontSize: 12,
|
|
36367
|
+
children: payload.value
|
|
36368
|
+
},
|
|
36369
|
+
`tick-${payload.value}-${x}-${y}`
|
|
36370
|
+
) });
|
|
36371
|
+
}
|
|
36372
|
+
}
|
|
36373
|
+
),
|
|
36374
|
+
/* @__PURE__ */ jsxRuntime.jsx(recharts.YAxis, { yAxisId: "idle", domain: [0, 60], hide: true }),
|
|
36375
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
36376
|
+
recharts.Tooltip,
|
|
36377
|
+
{
|
|
36378
|
+
cursor: { fill: "#f1f5f9" },
|
|
36379
|
+
contentStyle: { backgroundColor: "transparent", border: "none", padding: 0 },
|
|
36380
|
+
content: (props) => {
|
|
36381
|
+
if (!props.active || !props.payload || props.payload.length === 0)
|
|
36382
|
+
return null;
|
|
36383
|
+
const data2 = props.payload[0].payload;
|
|
36384
|
+
const idlePeriods = showIdleTime ? getHourlyIdlePeriods({
|
|
36385
|
+
idleArray: data2.idleArray,
|
|
36386
|
+
shiftStart,
|
|
36387
|
+
hourIndex: Number.isFinite(data2.hourIndex) ? data2.hourIndex : 0
|
|
36388
|
+
}) : [];
|
|
36389
|
+
return /* @__PURE__ */ jsxRuntime.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: [
|
|
36390
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-between mb-4 pb-3 border-b border-slate-100", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-semibold text-slate-900 text-sm tracking-tight", children: data2.timeRange }) }),
|
|
36391
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
|
|
36392
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
36393
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-slate-500 font-medium tracking-wide", children: "Output" }),
|
|
36394
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-bold text-slate-900 text-sm", children: [
|
|
36395
|
+
Math.round(data2.output),
|
|
36396
|
+
" ",
|
|
36397
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-slate-400 font-normal text-xs ml-0.5", children: "units" })
|
|
36398
|
+
] })
|
|
36399
|
+
] }),
|
|
36400
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
36401
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-slate-500 font-medium tracking-wide", children: "Target" }),
|
|
36402
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-bold text-slate-700 text-sm", children: [
|
|
36403
|
+
Math.round(data2.target),
|
|
36404
|
+
" ",
|
|
36405
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-slate-400 font-normal text-xs ml-0.5", children: "units" })
|
|
36406
|
+
] })
|
|
36407
|
+
] }),
|
|
36408
|
+
showIdleTime && data2.idleMinutes > 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
36409
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pt-3 mt-3 border-t border-slate-100", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
36410
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-slate-500 font-medium tracking-wide", children: "Idle Time" }),
|
|
36411
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-bold text-orange-600 text-sm flex items-center gap-1.5", children: [
|
|
36412
|
+
/* @__PURE__ */ jsxRuntime.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" }),
|
|
36413
|
+
data2.idleMinutes,
|
|
36414
|
+
" ",
|
|
36415
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-orange-500/70 font-normal text-xs ml-0.5", children: "min" })
|
|
36416
|
+
] })
|
|
36417
|
+
] }) }),
|
|
36418
|
+
idlePeriods.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 bg-slate-50/80 rounded-lg p-3 border border-slate-100/50", children: [
|
|
36419
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-semibold text-slate-400 text-[10px] mb-2.5 uppercase tracking-wider", children: "Idle Periods" }),
|
|
36420
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2.5 max-h-32 overflow-y-auto pr-1 custom-scrollbar", children: idlePeriods.map((period, index) => {
|
|
36421
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
36422
|
+
"div",
|
|
36423
|
+
{
|
|
36424
|
+
className: "flex items-start gap-2.5 text-xs",
|
|
36425
|
+
children: [
|
|
36426
|
+
/* @__PURE__ */ jsxRuntime.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)]" }),
|
|
36427
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-slate-700 font-medium tracking-tight", children: period.duration === 1 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
36428
|
+
period.startTime,
|
|
36429
|
+
" ",
|
|
36430
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-slate-400 font-normal ml-1", children: [
|
|
36431
|
+
"(",
|
|
36432
|
+
period.duration,
|
|
36433
|
+
"m)"
|
|
36434
|
+
] })
|
|
36435
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
36436
|
+
period.startTime,
|
|
36437
|
+
" ",
|
|
36438
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-slate-400 mx-0.5", children: "\u2192" }),
|
|
36439
|
+
" ",
|
|
36440
|
+
period.endTime,
|
|
36441
|
+
" ",
|
|
36442
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-slate-400 font-normal ml-1", children: [
|
|
36443
|
+
"(",
|
|
36444
|
+
period.duration,
|
|
36445
|
+
"m)"
|
|
36446
|
+
] })
|
|
36447
|
+
] }) })
|
|
36448
|
+
]
|
|
36449
|
+
},
|
|
36450
|
+
index
|
|
36451
|
+
);
|
|
36452
|
+
}) })
|
|
35841
36453
|
] })
|
|
35842
|
-
] }) }),
|
|
35843
|
-
idlePeriods.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 bg-gray-50 rounded-lg p-2.5", children: [
|
|
35844
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium text-gray-700 text-xs mb-2", children: "Idle periods:" }),
|
|
35845
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1 max-h-32 overflow-y-auto pr-1", children: idlePeriods.map((period, index) => {
|
|
35846
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
35847
|
-
"div",
|
|
35848
|
-
{
|
|
35849
|
-
className: "text-gray-600 flex items-center gap-2 text-xs",
|
|
35850
|
-
children: [
|
|
35851
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-block w-1.5 h-1.5 bg-orange-400 rounded-full flex-shrink-0" }),
|
|
35852
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: period.duration === 1 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
35853
|
-
period.startTime,
|
|
35854
|
-
" (",
|
|
35855
|
-
period.duration,
|
|
35856
|
-
" min)"
|
|
35857
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
35858
|
-
period.startTime,
|
|
35859
|
-
" -",
|
|
35860
|
-
" ",
|
|
35861
|
-
period.endTime,
|
|
35862
|
-
" (",
|
|
35863
|
-
period.duration,
|
|
35864
|
-
" mins)"
|
|
35865
|
-
] }) })
|
|
35866
|
-
]
|
|
35867
|
-
},
|
|
35868
|
-
index
|
|
35869
|
-
);
|
|
35870
|
-
}) })
|
|
35871
36454
|
] })
|
|
35872
36455
|
] })
|
|
35873
|
-
] })
|
|
35874
|
-
|
|
35875
|
-
|
|
35876
|
-
|
|
35877
|
-
|
|
35878
|
-
|
|
35879
|
-
|
|
35880
|
-
|
|
35881
|
-
|
|
35882
|
-
|
|
35883
|
-
|
|
35884
|
-
|
|
35885
|
-
|
|
35886
|
-
|
|
35887
|
-
|
|
35888
|
-
|
|
35889
|
-
|
|
35890
|
-
|
|
35891
|
-
|
|
35892
|
-
|
|
35893
|
-
|
|
35894
|
-
|
|
35895
|
-
|
|
35896
|
-
|
|
35897
|
-
|
|
35898
|
-
|
|
35899
|
-
|
|
35900
|
-
|
|
35901
|
-
|
|
35902
|
-
|
|
35903
|
-
|
|
35904
|
-
|
|
35905
|
-
|
|
35906
|
-
|
|
35907
|
-
|
|
35908
|
-
|
|
36456
|
+
] });
|
|
36457
|
+
},
|
|
36458
|
+
animationDuration: 200
|
|
36459
|
+
}
|
|
36460
|
+
),
|
|
36461
|
+
/* @__PURE__ */ jsxRuntime.jsx(recharts.Customized, { component: renderTargetLine }),
|
|
36462
|
+
/* @__PURE__ */ jsxRuntime.jsx(recharts.Customized, { component: renderSkuTimelineRail }),
|
|
36463
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
36464
|
+
recharts.Bar,
|
|
36465
|
+
{
|
|
36466
|
+
xAxisId: "default",
|
|
36467
|
+
dataKey: "output",
|
|
36468
|
+
yAxisId: "default",
|
|
36469
|
+
maxBarSize: 35,
|
|
36470
|
+
radius: [10, 10, 0, 0],
|
|
36471
|
+
isAnimationActive: false,
|
|
36472
|
+
children: [
|
|
36473
|
+
chartData.map((entry, index) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
36474
|
+
recharts.Cell,
|
|
36475
|
+
{
|
|
36476
|
+
fill: entry.color,
|
|
36477
|
+
stroke: "transparent",
|
|
36478
|
+
strokeWidth: 0,
|
|
36479
|
+
style: {
|
|
36480
|
+
filter: entry.isHighlighted ? "drop-shadow(0 4px 6px rgba(0, 0, 0, 0.12)) brightness(1.05)" : "brightness(1)",
|
|
36481
|
+
transform: entry.isHighlighted ? "translateY(-4px)" : "translateY(0)",
|
|
36482
|
+
opacity: entry.isDimmed ? 0.4 : 1,
|
|
36483
|
+
transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)",
|
|
36484
|
+
cursor: "pointer"
|
|
36485
|
+
},
|
|
36486
|
+
onMouseEnter: (e) => {
|
|
36487
|
+
const target = e.target;
|
|
36488
|
+
target.style.filter = "drop-shadow(0 4px 6px rgba(0, 0, 0, 0.12)) brightness(1.05)";
|
|
36489
|
+
target.style.transform = "translateY(-4px)";
|
|
36490
|
+
target.style.opacity = "1";
|
|
36491
|
+
},
|
|
36492
|
+
onMouseLeave: (e) => {
|
|
36493
|
+
const target = e.target;
|
|
36494
|
+
target.style.filter = entry.isHighlighted ? "drop-shadow(0 4px 6px rgba(0, 0, 0, 0.12)) brightness(1.05)" : "brightness(1)";
|
|
36495
|
+
target.style.transform = entry.isHighlighted ? "translateY(-4px)" : "translateY(0)";
|
|
36496
|
+
target.style.opacity = entry.isDimmed ? "0.4" : "1";
|
|
36497
|
+
}
|
|
35909
36498
|
},
|
|
35910
|
-
|
|
35911
|
-
|
|
35912
|
-
|
|
35913
|
-
|
|
35914
|
-
|
|
36499
|
+
`cell-${index}`
|
|
36500
|
+
)),
|
|
36501
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
36502
|
+
recharts.LabelList,
|
|
36503
|
+
{
|
|
36504
|
+
dataKey: "originalOutput",
|
|
36505
|
+
position: "top",
|
|
36506
|
+
content: (props) => {
|
|
36507
|
+
const { x, y, width, value, payload } = props;
|
|
36508
|
+
const actualValue = payload?.originalOutput || value;
|
|
36509
|
+
if (!actualValue || actualValue === 0) return null;
|
|
36510
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
36511
|
+
"text",
|
|
36512
|
+
{
|
|
36513
|
+
x: x + width / 2,
|
|
36514
|
+
y: y - 8,
|
|
36515
|
+
textAnchor: "middle",
|
|
36516
|
+
fontSize: "12",
|
|
36517
|
+
fontWeight: "600",
|
|
36518
|
+
fill: "#374151",
|
|
36519
|
+
style: {
|
|
36520
|
+
opacity: 1,
|
|
36521
|
+
pointerEvents: "none",
|
|
36522
|
+
transition: "none"
|
|
36523
|
+
},
|
|
36524
|
+
children: Math.round(actualValue)
|
|
36525
|
+
}
|
|
36526
|
+
);
|
|
36527
|
+
}
|
|
35915
36528
|
}
|
|
35916
|
-
|
|
35917
|
-
|
|
35918
|
-
|
|
35919
|
-
|
|
35920
|
-
|
|
35921
|
-
|
|
35922
|
-
|
|
35923
|
-
|
|
35924
|
-
|
|
35925
|
-
|
|
35926
|
-
|
|
35927
|
-
|
|
35928
|
-
|
|
35929
|
-
|
|
35930
|
-
|
|
35931
|
-
|
|
35932
|
-
|
|
35933
|
-
|
|
35934
|
-
|
|
35935
|
-
|
|
35936
|
-
|
|
35937
|
-
style: {
|
|
35938
|
-
opacity: 1,
|
|
35939
|
-
pointerEvents: "none",
|
|
35940
|
-
transition: "none"
|
|
35941
|
-
},
|
|
35942
|
-
children: Math.round(actualValue)
|
|
35943
|
-
}
|
|
35944
|
-
);
|
|
36529
|
+
)
|
|
36530
|
+
]
|
|
36531
|
+
}
|
|
36532
|
+
),
|
|
36533
|
+
IdleBar,
|
|
36534
|
+
/* @__PURE__ */ jsxRuntime.jsx("defs", { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
36535
|
+
"pattern",
|
|
36536
|
+
{
|
|
36537
|
+
id: "idlePattern",
|
|
36538
|
+
patternUnits: "userSpaceOnUse",
|
|
36539
|
+
width: "4",
|
|
36540
|
+
height: "4",
|
|
36541
|
+
children: [
|
|
36542
|
+
/* @__PURE__ */ jsxRuntime.jsx("rect", { width: "4", height: "4", fill: "#4b5563", opacity: "0.6" }),
|
|
36543
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
36544
|
+
"path",
|
|
36545
|
+
{
|
|
36546
|
+
d: "M 0,4 l 4,-4 M -1,1 l 2,-2 M 3,5 l 2,-2",
|
|
36547
|
+
stroke: "#374151",
|
|
36548
|
+
strokeWidth: "0.8",
|
|
36549
|
+
opacity: "0.8"
|
|
35945
36550
|
}
|
|
35946
|
-
|
|
35947
|
-
|
|
35948
|
-
|
|
35949
|
-
}
|
|
35950
|
-
|
|
35951
|
-
|
|
35952
|
-
|
|
35953
|
-
|
|
35954
|
-
|
|
35955
|
-
|
|
35956
|
-
|
|
35957
|
-
|
|
35958
|
-
|
|
35959
|
-
|
|
35960
|
-
|
|
35961
|
-
|
|
35962
|
-
|
|
35963
|
-
|
|
35964
|
-
|
|
35965
|
-
|
|
35966
|
-
|
|
35967
|
-
|
|
35968
|
-
}
|
|
35969
|
-
)
|
|
35970
|
-
]
|
|
35971
|
-
}
|
|
35972
|
-
) })
|
|
35973
|
-
]
|
|
35974
|
-
}
|
|
35975
|
-
) }) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center bg-gray-50 rounded-lg", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-500 text-sm", children: "Loading chart..." }) }),
|
|
36551
|
+
)
|
|
36552
|
+
]
|
|
36553
|
+
}
|
|
36554
|
+
) })
|
|
36555
|
+
]
|
|
36556
|
+
}
|
|
36557
|
+
) }),
|
|
36558
|
+
hoveredSkuRailLabel && /* @__PURE__ */ jsxRuntime.jsx(
|
|
36559
|
+
"div",
|
|
36560
|
+
{
|
|
36561
|
+
className: "absolute z-50 pointer-events-none transform -translate-x-1/2 -translate-y-full transition-opacity duration-200",
|
|
36562
|
+
style: {
|
|
36563
|
+
left: hoveredSkuRailLabel.centerX,
|
|
36564
|
+
top: hoveredSkuRailLabel.railY - 12
|
|
36565
|
+
},
|
|
36566
|
+
children: /* @__PURE__ */ jsxRuntime.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: [
|
|
36567
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-bold tracking-wider text-blue-500 uppercase leading-none mb-1", children: "SKU" }),
|
|
36568
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[13px] font-semibold text-slate-800 whitespace-normal break-words leading-snug", children: hoveredSkuRailLabel.label })
|
|
36569
|
+
] })
|
|
36570
|
+
}
|
|
36571
|
+
)
|
|
36572
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center bg-gray-50 rounded-lg", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-500 text-sm", children: "Loading chart..." }) }),
|
|
35976
36573
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-none pt-2", children: renderLegend() })
|
|
35977
36574
|
]
|
|
35978
36575
|
}
|
|
@@ -35990,6 +36587,16 @@ var HourlyOutputChart = React144__namespace.default.memo(
|
|
|
35990
36587
|
if (!prevProps.data.every((val, idx) => val === nextProps.data[idx])) {
|
|
35991
36588
|
return false;
|
|
35992
36589
|
}
|
|
36590
|
+
const prevHourlyTargets = prevProps.hourlyTargetOutput || [];
|
|
36591
|
+
const nextHourlyTargets = nextProps.hourlyTargetOutput || [];
|
|
36592
|
+
if (prevHourlyTargets.length !== nextHourlyTargets.length) {
|
|
36593
|
+
return false;
|
|
36594
|
+
}
|
|
36595
|
+
for (let i = 0; i < prevHourlyTargets.length; i += 1) {
|
|
36596
|
+
if (prevHourlyTargets[i] !== nextHourlyTargets[i]) {
|
|
36597
|
+
return false;
|
|
36598
|
+
}
|
|
36599
|
+
}
|
|
35993
36600
|
const prevIdle = prevProps.idleTimeHourly || {};
|
|
35994
36601
|
const nextIdle = nextProps.idleTimeHourly || {};
|
|
35995
36602
|
const prevKeys = Object.keys(prevIdle);
|
|
@@ -36177,7 +36784,6 @@ var VideoCard = React144__namespace.default.memo(({
|
|
|
36177
36784
|
shouldPlay,
|
|
36178
36785
|
onClick,
|
|
36179
36786
|
onFatalError,
|
|
36180
|
-
isVeryLowEfficiency = false,
|
|
36181
36787
|
legend,
|
|
36182
36788
|
cropping,
|
|
36183
36789
|
canvasFps = 30,
|
|
@@ -36249,11 +36855,6 @@ var VideoCard = React144__namespace.default.memo(({
|
|
|
36249
36855
|
}
|
|
36250
36856
|
},
|
|
36251
36857
|
children: [
|
|
36252
|
-
isVeryLowEfficiency && /* @__PURE__ */ jsxRuntime.jsx("div", { className: `absolute ${compact ? "top-0.5 left-1" : "top-1 left-2"} z-30`, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
36253
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute -inset-1 bg-red-400/50 rounded-full blur-sm animate-pulse" }),
|
|
36254
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute -inset-0.5 bg-red-500/30 rounded-full blur-md animate-ping [animation-duration:1.5s]" }),
|
|
36255
|
-
/* @__PURE__ */ jsxRuntime.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: "!" })
|
|
36256
|
-
] }) }),
|
|
36257
36858
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full h-full overflow-hidden bg-black", children: [
|
|
36258
36859
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-black z-0", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "animate-pulse flex flex-col items-center", children: [
|
|
36259
36860
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Camera, { className: `w-5 h-5 sm:${compact ? "w-4 h-4" : "w-6 h-6"} text-gray-500` }),
|
|
@@ -36663,7 +37264,6 @@ var VideoGridView = React144__namespace.default.memo(({
|
|
|
36663
37264
|
const workspaceId = workspace.workspace_uuid || workspace.workspace_name;
|
|
36664
37265
|
const workspaceKey = `${workspace.line_id || "unknown"}-${workspaceId}`;
|
|
36665
37266
|
const isVisible = visibleWorkspaces.has(workspaceId);
|
|
36666
|
-
const isVeryLowEfficiency = workspace.show_exclamation ?? (workspace.efficiency < 50 && workspace.efficiency >= 10);
|
|
36667
37267
|
const workspaceCropping = getWorkspaceCropping(workspaceId, workspace.workspace_name);
|
|
36668
37268
|
const workspaceStream = videoStreamsByWorkspaceId?.[workspaceId];
|
|
36669
37269
|
const lastSeenLabel = workspace.workspace_uuid ? lastSeenByWorkspaceId[workspace.workspace_uuid]?.timeSinceLastUpdate : void 0;
|
|
@@ -36680,7 +37280,6 @@ var VideoGridView = React144__namespace.default.memo(({
|
|
|
36680
37280
|
workspaceId,
|
|
36681
37281
|
workspaceKey,
|
|
36682
37282
|
isVisible,
|
|
36683
|
-
isVeryLowEfficiency,
|
|
36684
37283
|
workspaceCropping,
|
|
36685
37284
|
fallbackUrl,
|
|
36686
37285
|
hlsUrl,
|
|
@@ -36728,7 +37327,6 @@ var VideoGridView = React144__namespace.default.memo(({
|
|
|
36728
37327
|
isR2Stream: card.isR2Stream,
|
|
36729
37328
|
fallbackUrl: card.fallbackUrl
|
|
36730
37329
|
}),
|
|
36731
|
-
isVeryLowEfficiency: card.isVeryLowEfficiency,
|
|
36732
37330
|
legend: effectiveLegend,
|
|
36733
37331
|
cropping: card.workspaceCropping,
|
|
36734
37332
|
canvasFps: effectiveCanvasFps,
|
|
@@ -37648,223 +38246,6 @@ var UptimeLineChartComponent = ({ points, className = "" }) => {
|
|
|
37648
38246
|
] }) }) });
|
|
37649
38247
|
};
|
|
37650
38248
|
var UptimeLineChart = React144__namespace.default.memo(UptimeLineChartComponent);
|
|
37651
|
-
var padTime = (value) => value.toString().padStart(2, "0");
|
|
37652
|
-
var parseTime = (timeValue) => {
|
|
37653
|
-
if (!timeValue) return null;
|
|
37654
|
-
const [hourPart, minutePart] = timeValue.split(":");
|
|
37655
|
-
const hour = Number.parseInt(hourPart, 10);
|
|
37656
|
-
const minute = Number.parseInt(minutePart ?? "0", 10);
|
|
37657
|
-
if (!Number.isFinite(hour) || !Number.isFinite(minute)) return null;
|
|
37658
|
-
return { hour, minute };
|
|
37659
|
-
};
|
|
37660
|
-
var normalizeIdleTimeHourly = (idleTimeHourly) => {
|
|
37661
|
-
if (!idleTimeHourly || typeof idleTimeHourly !== "object") {
|
|
37662
|
-
return {};
|
|
37663
|
-
}
|
|
37664
|
-
return Object.fromEntries(
|
|
37665
|
-
Object.entries(idleTimeHourly).map(([key, value]) => {
|
|
37666
|
-
if (Array.isArray(value)) return [key, value];
|
|
37667
|
-
if (value && Array.isArray(value.values)) {
|
|
37668
|
-
return [key, value.values];
|
|
37669
|
-
}
|
|
37670
|
-
return [key, []];
|
|
37671
|
-
})
|
|
37672
|
-
);
|
|
37673
|
-
};
|
|
37674
|
-
var interpretIdleValue = (value) => {
|
|
37675
|
-
if (value === 1 || value === "1") return "idle";
|
|
37676
|
-
if (value === 0 || value === "0") return "active";
|
|
37677
|
-
if (value === "x" || value === null || value === void 0) return "unknown";
|
|
37678
|
-
return "unknown";
|
|
37679
|
-
};
|
|
37680
|
-
var getShiftDurationMinutes = (shiftStart, shiftEnd) => {
|
|
37681
|
-
const start = parseTime(shiftStart);
|
|
37682
|
-
const end = parseTime(shiftEnd);
|
|
37683
|
-
if (!start || !end) return null;
|
|
37684
|
-
let duration = end.hour * 60 + end.minute - (start.hour * 60 + start.minute);
|
|
37685
|
-
if (duration <= 0) {
|
|
37686
|
-
duration += 24 * 60;
|
|
37687
|
-
}
|
|
37688
|
-
return duration > 0 ? duration : null;
|
|
37689
|
-
};
|
|
37690
|
-
var getShiftElapsedMinutes = ({
|
|
37691
|
-
shiftStart,
|
|
37692
|
-
shiftEnd,
|
|
37693
|
-
shiftDate,
|
|
37694
|
-
timezone,
|
|
37695
|
-
now: now4 = /* @__PURE__ */ new Date()
|
|
37696
|
-
}) => {
|
|
37697
|
-
if (!shiftDate || !timezone) return null;
|
|
37698
|
-
const startTime = parseTime(shiftStart);
|
|
37699
|
-
const endTime = parseTime(shiftEnd);
|
|
37700
|
-
if (!startTime || !endTime) return null;
|
|
37701
|
-
const shiftStartDate = dateFnsTz.fromZonedTime(
|
|
37702
|
-
`${shiftDate}T${padTime(startTime.hour)}:${padTime(startTime.minute)}:00`,
|
|
37703
|
-
timezone
|
|
37704
|
-
);
|
|
37705
|
-
let shiftEndDate = dateFnsTz.fromZonedTime(
|
|
37706
|
-
`${shiftDate}T${padTime(endTime.hour)}:${padTime(endTime.minute)}:00`,
|
|
37707
|
-
timezone
|
|
37708
|
-
);
|
|
37709
|
-
if (shiftEndDate <= shiftStartDate) {
|
|
37710
|
-
shiftEndDate = dateFns.addDays(shiftEndDate, 1);
|
|
37711
|
-
}
|
|
37712
|
-
const shiftMinutes = Math.max(dateFns.differenceInMinutes(shiftEndDate, shiftStartDate), 0);
|
|
37713
|
-
if (shiftMinutes <= 0) return null;
|
|
37714
|
-
const elapsed = dateFns.differenceInMinutes(now4, shiftStartDate);
|
|
37715
|
-
return Math.min(Math.max(elapsed, 0), shiftMinutes);
|
|
37716
|
-
};
|
|
37717
|
-
var maskFutureHourlySeries = ({
|
|
37718
|
-
data,
|
|
37719
|
-
shiftStart,
|
|
37720
|
-
shiftEnd,
|
|
37721
|
-
shiftDate,
|
|
37722
|
-
timezone,
|
|
37723
|
-
now: now4 = /* @__PURE__ */ new Date()
|
|
37724
|
-
}) => {
|
|
37725
|
-
if (!Array.isArray(data)) {
|
|
37726
|
-
return [];
|
|
37727
|
-
}
|
|
37728
|
-
const normalizedData = data.map((value) => typeof value === "number" && Number.isFinite(value) ? value : null);
|
|
37729
|
-
if (!normalizedData.length) {
|
|
37730
|
-
return normalizedData;
|
|
37731
|
-
}
|
|
37732
|
-
const shiftMinutes = getShiftDurationMinutes(shiftStart, shiftEnd);
|
|
37733
|
-
const elapsedMinutes = getShiftElapsedMinutes({
|
|
37734
|
-
shiftStart,
|
|
37735
|
-
shiftEnd,
|
|
37736
|
-
shiftDate,
|
|
37737
|
-
timezone,
|
|
37738
|
-
now: now4
|
|
37739
|
-
});
|
|
37740
|
-
if (shiftMinutes === null || elapsedMinutes === null || elapsedMinutes >= shiftMinutes) {
|
|
37741
|
-
return normalizedData;
|
|
37742
|
-
}
|
|
37743
|
-
return normalizedData.map((value, index) => {
|
|
37744
|
-
const slotStartMinutes = index * 60;
|
|
37745
|
-
return slotStartMinutes > elapsedMinutes ? null : value;
|
|
37746
|
-
});
|
|
37747
|
-
};
|
|
37748
|
-
var buildUptimeSeries = ({
|
|
37749
|
-
idleTimeHourly,
|
|
37750
|
-
shiftStart,
|
|
37751
|
-
shiftEnd,
|
|
37752
|
-
shiftDate,
|
|
37753
|
-
timezone,
|
|
37754
|
-
elapsedMinutes
|
|
37755
|
-
}) => {
|
|
37756
|
-
const normalizedIdle = normalizeIdleTimeHourly(idleTimeHourly || {});
|
|
37757
|
-
const hasIdleData = Object.keys(normalizedIdle).length > 0;
|
|
37758
|
-
if (!hasIdleData || !shiftDate || !timezone) {
|
|
37759
|
-
return {
|
|
37760
|
-
points: [],
|
|
37761
|
-
activeMinutes: 0,
|
|
37762
|
-
idleMinutes: 0,
|
|
37763
|
-
availableMinutes: 0,
|
|
37764
|
-
shiftMinutes: 0,
|
|
37765
|
-
elapsedMinutes: 0,
|
|
37766
|
-
hasData: false
|
|
37767
|
-
};
|
|
37768
|
-
}
|
|
37769
|
-
const startTime = parseTime(shiftStart);
|
|
37770
|
-
const endTime = parseTime(shiftEnd);
|
|
37771
|
-
if (!startTime || !endTime) {
|
|
37772
|
-
return {
|
|
37773
|
-
points: [],
|
|
37774
|
-
activeMinutes: 0,
|
|
37775
|
-
idleMinutes: 0,
|
|
37776
|
-
availableMinutes: 0,
|
|
37777
|
-
shiftMinutes: 0,
|
|
37778
|
-
elapsedMinutes: 0,
|
|
37779
|
-
hasData: false
|
|
37780
|
-
};
|
|
37781
|
-
}
|
|
37782
|
-
const shiftStartDate = dateFnsTz.fromZonedTime(
|
|
37783
|
-
`${shiftDate}T${padTime(startTime.hour)}:${padTime(startTime.minute)}:00`,
|
|
37784
|
-
timezone
|
|
37785
|
-
);
|
|
37786
|
-
let shiftEndDate = dateFnsTz.fromZonedTime(
|
|
37787
|
-
`${shiftDate}T${padTime(endTime.hour)}:${padTime(endTime.minute)}:00`,
|
|
37788
|
-
timezone
|
|
37789
|
-
);
|
|
37790
|
-
if (shiftEndDate <= shiftStartDate) {
|
|
37791
|
-
shiftEndDate = dateFns.addDays(shiftEndDate, 1);
|
|
37792
|
-
}
|
|
37793
|
-
const shiftMinutes = Math.max(dateFns.differenceInMinutes(shiftEndDate, shiftStartDate), 0);
|
|
37794
|
-
if (shiftMinutes <= 0) {
|
|
37795
|
-
return {
|
|
37796
|
-
points: [],
|
|
37797
|
-
activeMinutes: 0,
|
|
37798
|
-
idleMinutes: 0,
|
|
37799
|
-
availableMinutes: 0,
|
|
37800
|
-
shiftMinutes: 0,
|
|
37801
|
-
elapsedMinutes: 0,
|
|
37802
|
-
hasData: false
|
|
37803
|
-
};
|
|
37804
|
-
}
|
|
37805
|
-
const elapsedMinutesClamped = Number.isFinite(elapsedMinutes) ? Math.min(Math.max(Math.floor(elapsedMinutes ?? 0), 0), shiftMinutes) : shiftMinutes;
|
|
37806
|
-
const points = [];
|
|
37807
|
-
let activeMinutes = 0;
|
|
37808
|
-
let idleMinutes = 0;
|
|
37809
|
-
for (let minuteIndex = 0; minuteIndex < shiftMinutes; minuteIndex += 1) {
|
|
37810
|
-
const minuteDate = dateFns.addMinutes(shiftStartDate, minuteIndex);
|
|
37811
|
-
const timeLabel = dateFnsTz.formatInTimeZone(minuteDate, timezone, "h:mm a");
|
|
37812
|
-
if (minuteIndex >= elapsedMinutesClamped) {
|
|
37813
|
-
points.push({
|
|
37814
|
-
minuteIndex,
|
|
37815
|
-
timeLabel,
|
|
37816
|
-
uptime: null,
|
|
37817
|
-
status: "unknown"
|
|
37818
|
-
});
|
|
37819
|
-
continue;
|
|
37820
|
-
}
|
|
37821
|
-
const hourKey = dateFnsTz.formatInTimeZone(minuteDate, timezone, "H");
|
|
37822
|
-
const minuteKey = Number.parseInt(dateFnsTz.formatInTimeZone(minuteDate, timezone, "m"), 10);
|
|
37823
|
-
const hourBucket = normalizedIdle[hourKey] || [];
|
|
37824
|
-
const value = Array.isArray(hourBucket) ? hourBucket[minuteKey] : void 0;
|
|
37825
|
-
const status = interpretIdleValue(value);
|
|
37826
|
-
if (status === "active") activeMinutes += 1;
|
|
37827
|
-
if (status === "idle") idleMinutes += 1;
|
|
37828
|
-
points.push({
|
|
37829
|
-
minuteIndex,
|
|
37830
|
-
timeLabel,
|
|
37831
|
-
uptime: status === "active" ? 1 : status === "idle" ? 0 : null,
|
|
37832
|
-
status
|
|
37833
|
-
});
|
|
37834
|
-
}
|
|
37835
|
-
return {
|
|
37836
|
-
points,
|
|
37837
|
-
activeMinutes,
|
|
37838
|
-
idleMinutes,
|
|
37839
|
-
availableMinutes: activeMinutes + idleMinutes,
|
|
37840
|
-
shiftMinutes,
|
|
37841
|
-
elapsedMinutes: elapsedMinutesClamped,
|
|
37842
|
-
hasData: activeMinutes + idleMinutes > 0
|
|
37843
|
-
};
|
|
37844
|
-
};
|
|
37845
|
-
var getUptimeUtilizationPercent = (shift) => {
|
|
37846
|
-
const efficiency = shift.efficiency;
|
|
37847
|
-
if (Number.isFinite(efficiency)) {
|
|
37848
|
-
return Math.round(Math.max(0, Math.min(100, Number(efficiency))));
|
|
37849
|
-
}
|
|
37850
|
-
const idleSeconds = Number.isFinite(shift.idleTime) ? Number(shift.idleTime) : 0;
|
|
37851
|
-
const activeSeconds = Number.isFinite(shift.activeTimeSeconds) ? Number(shift.activeTimeSeconds) : null;
|
|
37852
|
-
let availableSeconds = Number.isFinite(shift.availableTimeSeconds) ? Number(shift.availableTimeSeconds) : null;
|
|
37853
|
-
if (availableSeconds === null) {
|
|
37854
|
-
if ((activeSeconds ?? 0) > 0 || idleSeconds > 0) {
|
|
37855
|
-
availableSeconds = (activeSeconds ?? 0) + idleSeconds;
|
|
37856
|
-
} else {
|
|
37857
|
-
return 0;
|
|
37858
|
-
}
|
|
37859
|
-
}
|
|
37860
|
-
if (availableSeconds <= 0) return 0;
|
|
37861
|
-
const clampedIdleSeconds = Math.min(Math.max(idleSeconds, 0), availableSeconds);
|
|
37862
|
-
const productiveSeconds = Math.max(
|
|
37863
|
-
activeSeconds ?? availableSeconds - clampedIdleSeconds,
|
|
37864
|
-
0
|
|
37865
|
-
);
|
|
37866
|
-
return Math.round(productiveSeconds / availableSeconds * 100);
|
|
37867
|
-
};
|
|
37868
38249
|
var getTimeFromTimeString = (timeStr) => {
|
|
37869
38250
|
if (!timeStr) {
|
|
37870
38251
|
return { hour: 0, minute: 0, decimalHour: 0 };
|
|
@@ -50195,7 +50576,7 @@ var formatOperationalDateKey = (dateKey, options) => {
|
|
|
50195
50576
|
timeZone: "UTC"
|
|
50196
50577
|
});
|
|
50197
50578
|
};
|
|
50198
|
-
var
|
|
50579
|
+
var getSegmentMinutes2 = (isoString, timeZone, reportDate) => {
|
|
50199
50580
|
const date = new Date(isoString);
|
|
50200
50581
|
if (isNaN(date.getTime())) return NaN;
|
|
50201
50582
|
const formatter = new Intl.DateTimeFormat("en-US", {
|
|
@@ -50216,13 +50597,13 @@ var getSegmentMinutes = (isoString, timeZone, reportDate) => {
|
|
|
50216
50597
|
if (dateKey > reportDate) {
|
|
50217
50598
|
const d1 = new Date(dateKey);
|
|
50218
50599
|
const d2 = new Date(reportDate);
|
|
50219
|
-
const
|
|
50220
|
-
minutes +=
|
|
50600
|
+
const diffDays2 = Math.round((d1.getTime() - d2.getTime()) / (1e3 * 3600 * 24));
|
|
50601
|
+
minutes += diffDays2 * 24 * 60;
|
|
50221
50602
|
} else if (dateKey < reportDate) {
|
|
50222
50603
|
const d1 = new Date(dateKey);
|
|
50223
50604
|
const d2 = new Date(reportDate);
|
|
50224
|
-
const
|
|
50225
|
-
minutes -=
|
|
50605
|
+
const diffDays2 = Math.round((d2.getTime() - d1.getTime()) / (1e3 * 3600 * 24));
|
|
50606
|
+
minutes -= diffDays2 * 24 * 60;
|
|
50226
50607
|
}
|
|
50227
50608
|
return minutes;
|
|
50228
50609
|
};
|
|
@@ -50632,7 +51013,7 @@ var LinePdfGenerator = ({
|
|
|
50632
51013
|
const skuRemarksByIndex = {};
|
|
50633
51014
|
if (lineInfo.metrics.sku_segments && lineInfo.metrics.sku_segments.length > 0) {
|
|
50634
51015
|
lineInfo.metrics.sku_segments.forEach((segment, segmentIndex) => {
|
|
50635
|
-
const segmentMinutes =
|
|
51016
|
+
const segmentMinutes = getSegmentMinutes2(segment.start_time, reportTimezone, lineInfo.date);
|
|
50636
51017
|
if (!isNaN(segmentMinutes)) {
|
|
50637
51018
|
const intervalIndex = hourlyTimeRanges.findIndex(
|
|
50638
51019
|
(inv) => segmentMinutes >= inv.start && segmentMinutes < inv.end
|
|
@@ -52367,7 +52748,7 @@ var formatOperationalDateKey2 = (dateKey, options) => {
|
|
|
52367
52748
|
timeZone: "UTC"
|
|
52368
52749
|
});
|
|
52369
52750
|
};
|
|
52370
|
-
var
|
|
52751
|
+
var getSegmentMinutes3 = (isoString, timeZone, reportDate) => {
|
|
52371
52752
|
const date = new Date(isoString);
|
|
52372
52753
|
if (isNaN(date.getTime())) return NaN;
|
|
52373
52754
|
const formatter = new Intl.DateTimeFormat("en-US", {
|
|
@@ -52388,13 +52769,13 @@ var getSegmentMinutes2 = (isoString, timeZone, reportDate) => {
|
|
|
52388
52769
|
if (dateKey > reportDate) {
|
|
52389
52770
|
const d1 = new Date(dateKey);
|
|
52390
52771
|
const d2 = new Date(reportDate);
|
|
52391
|
-
const
|
|
52392
|
-
minutes +=
|
|
52772
|
+
const diffDays2 = Math.round((d1.getTime() - d2.getTime()) / (1e3 * 3600 * 24));
|
|
52773
|
+
minutes += diffDays2 * 24 * 60;
|
|
52393
52774
|
} else if (dateKey < reportDate) {
|
|
52394
52775
|
const d1 = new Date(dateKey);
|
|
52395
52776
|
const d2 = new Date(reportDate);
|
|
52396
|
-
const
|
|
52397
|
-
minutes -=
|
|
52777
|
+
const diffDays2 = Math.round((d2.getTime() - d1.getTime()) / (1e3 * 3600 * 24));
|
|
52778
|
+
minutes -= diffDays2 * 24 * 60;
|
|
52398
52779
|
}
|
|
52399
52780
|
return minutes;
|
|
52400
52781
|
};
|
|
@@ -52626,7 +53007,7 @@ var WorkspacePdfGenerator = ({
|
|
|
52626
53007
|
const skuRemarksByIndex = {};
|
|
52627
53008
|
if (workspace.sku_segments && workspace.sku_segments.length > 0) {
|
|
52628
53009
|
workspace.sku_segments.forEach((segment, segmentIndex) => {
|
|
52629
|
-
const segmentMinutes =
|
|
53010
|
+
const segmentMinutes = getSegmentMinutes3(segment.start_time, reportTimezone, workspace.date);
|
|
52630
53011
|
if (!isNaN(segmentMinutes)) {
|
|
52631
53012
|
const intervalIndex = hourlyIntervals.findIndex(
|
|
52632
53013
|
(inv) => segmentMinutes >= inv.start && segmentMinutes < inv.end
|
|
@@ -53468,12 +53849,10 @@ var formatPercentRange = (min, max) => {
|
|
|
53468
53849
|
return `${format10(min)}-${format10(max)}%`;
|
|
53469
53850
|
};
|
|
53470
53851
|
var Legend5 = ({
|
|
53471
|
-
useBottleneckLabel = false,
|
|
53472
53852
|
legend,
|
|
53473
53853
|
metricLabel = "Efficiency"
|
|
53474
53854
|
}) => {
|
|
53475
53855
|
const effectiveLegend = legend || DEFAULT_EFFICIENCY_LEGEND;
|
|
53476
|
-
const exclamationLabel = useBottleneckLabel ? "Bottleneck" : "<50% efficiency";
|
|
53477
53856
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2 sm:gap-4 text-xs font-medium text-slate-600", children: [
|
|
53478
53857
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "font-medium text-gray-700 hidden sm:block", children: [
|
|
53479
53858
|
metricLabel,
|
|
@@ -53492,11 +53871,6 @@ var Legend5 = ({
|
|
|
53492
53871
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-2 h-2 sm:w-2.5 sm:h-2.5 rounded-full bg-[#E34329]" }),
|
|
53493
53872
|
/* @__PURE__ */ jsxRuntime.jsx("span", { children: formatPercentRange(effectiveLegend.red_min, effectiveLegend.red_max) })
|
|
53494
53873
|
] })
|
|
53495
|
-
] }),
|
|
53496
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:block w-px h-4 bg-slate-200 mx-1" }),
|
|
53497
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
53498
|
-
/* @__PURE__ */ jsxRuntime.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: "!" }),
|
|
53499
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: exclamationLabel })
|
|
53500
53874
|
] })
|
|
53501
53875
|
] });
|
|
53502
53876
|
};
|
|
@@ -53610,7 +53984,6 @@ var WorkspaceGrid = React144__namespace.default.memo(({
|
|
|
53610
53984
|
factoryView = "factory",
|
|
53611
53985
|
line2Uuid = "line-2",
|
|
53612
53986
|
className = "",
|
|
53613
|
-
hasFlowBuffers = false,
|
|
53614
53987
|
legend = DEFAULT_EFFICIENCY_LEGEND,
|
|
53615
53988
|
videoSources = {},
|
|
53616
53989
|
videoStreamsByWorkspaceId = {},
|
|
@@ -53654,7 +54027,7 @@ var WorkspaceGrid = React144__namespace.default.memo(({
|
|
|
53654
54027
|
);
|
|
53655
54028
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex flex-col w-full h-full overflow-hidden bg-slate-50/50 ${className}`, children: [
|
|
53656
54029
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-none px-4 py-3 z-20 flex flex-row items-center justify-between gap-4", children: [
|
|
53657
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:block", children: /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx(Legend5, { legend,
|
|
54030
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:block", children: /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx(Legend5, { legend, metricLabel: legendMetricLabel }) }) }),
|
|
53658
54031
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-3 shrink-0", children: [
|
|
53659
54032
|
toolbarRightContent,
|
|
53660
54033
|
mapViewEnabled && /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -53674,7 +54047,7 @@ var WorkspaceGrid = React144__namespace.default.memo(({
|
|
|
53674
54047
|
)
|
|
53675
54048
|
] })
|
|
53676
54049
|
] }),
|
|
53677
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "sm:hidden px-3 py-2 bg-white border-b border-slate-200/60 z-10", children: /* @__PURE__ */ jsxRuntime.jsx(Legend5, { legend,
|
|
54050
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "sm:hidden px-3 py-2 bg-white border-b border-slate-200/60 z-10", children: /* @__PURE__ */ jsxRuntime.jsx(Legend5, { legend, metricLabel: legendMetricLabel }) }),
|
|
53678
54051
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 relative overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(AnimatePresence, { mode: "wait", children: viewMode === "video" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
53679
54052
|
motion.div,
|
|
53680
54053
|
{
|
|
@@ -64335,6 +64708,7 @@ var buildLineInfoSnapshot = (lineDetails, metrics2) => {
|
|
|
64335
64708
|
underperforming_workspace_uuids: metrics2.underperforming_workspace_uuids || [],
|
|
64336
64709
|
output_array: metrics2.output_array || [],
|
|
64337
64710
|
output_hourly: metrics2.output_hourly,
|
|
64711
|
+
hourly_target_output: metrics2.hourly_target_output ?? null,
|
|
64338
64712
|
line_threshold: metrics2.line_threshold ?? 0,
|
|
64339
64713
|
threshold_pph: metrics2.threshold_pph ?? 0,
|
|
64340
64714
|
shift_start: metrics2.shift_start || "06:00",
|
|
@@ -64421,6 +64795,7 @@ var transformLineMetrics = (lineId, detailResponse, queryDate, queryShiftId) =>
|
|
|
64421
64795
|
underperforming_workspace_names: [],
|
|
64422
64796
|
underperforming_workspace_uuids: [],
|
|
64423
64797
|
output_array: [],
|
|
64798
|
+
hourly_target_output: null,
|
|
64424
64799
|
line_threshold: 0,
|
|
64425
64800
|
threshold_pph: 0,
|
|
64426
64801
|
shift_start: "06:00",
|
|
@@ -65458,6 +65833,9 @@ var BottomSection = React144.memo(({
|
|
|
65458
65833
|
workspaceDisplayNames,
|
|
65459
65834
|
hourlyOutputData,
|
|
65460
65835
|
hourlyThreshold,
|
|
65836
|
+
hourlyTargetOutput,
|
|
65837
|
+
idleTimeHourly,
|
|
65838
|
+
timezone,
|
|
65461
65839
|
urlDate,
|
|
65462
65840
|
urlShift,
|
|
65463
65841
|
navigate,
|
|
@@ -65628,8 +66006,12 @@ var BottomSection = React144.memo(({
|
|
|
65628
66006
|
{
|
|
65629
66007
|
data: hourlyOutputData,
|
|
65630
66008
|
pphThreshold: hourlyThreshold,
|
|
66009
|
+
hourlyTargetOutput,
|
|
65631
66010
|
shiftStart: lineInfo.metrics.shift_start || "06:00",
|
|
65632
66011
|
shiftEnd: lineInfo.metrics.shift_end,
|
|
66012
|
+
idleTimeHourly,
|
|
66013
|
+
shiftDate: lineInfo.date,
|
|
66014
|
+
timezone,
|
|
65633
66015
|
skuSegments: skuAware ? skuSegments : void 0,
|
|
65634
66016
|
activeSkuId
|
|
65635
66017
|
}
|
|
@@ -65650,6 +66032,9 @@ var BottomSection = React144.memo(({
|
|
|
65650
66032
|
if (prevProps.lineInfo.monitoring_mode !== nextProps.lineInfo.monitoring_mode) return false;
|
|
65651
66033
|
if (prevProps.skuAware !== nextProps.skuAware) return false;
|
|
65652
66034
|
if (prevProps.activeSkuId !== nextProps.activeSkuId) return false;
|
|
66035
|
+
if (JSON.stringify(prevProps.hourlyTargetOutput || []) !== JSON.stringify(nextProps.hourlyTargetOutput || [])) {
|
|
66036
|
+
return false;
|
|
66037
|
+
}
|
|
65653
66038
|
const prevSkuSegmentsSignature = JSON.stringify(
|
|
65654
66039
|
(prevProps.skuSegments || []).map((segment) => ({
|
|
65655
66040
|
sku_id: segment.sku_id,
|
|
@@ -65722,7 +66107,9 @@ var BottomSection = React144.memo(({
|
|
|
65722
66107
|
);
|
|
65723
66108
|
if (prevWorkspaceSignature !== nextWorkspaceSignature) return false;
|
|
65724
66109
|
if (prevProps.lineInfo.metrics.shift_start !== nextProps.lineInfo.metrics.shift_start) return false;
|
|
66110
|
+
if (prevProps.lineInfo.metrics.shift_end !== nextProps.lineInfo.metrics.shift_end) return false;
|
|
65725
66111
|
if (prevProps.hourlyThreshold !== nextProps.hourlyThreshold) return false;
|
|
66112
|
+
if (JSON.stringify(prevProps.idleTimeHourly || {}) !== JSON.stringify(nextProps.idleTimeHourly || {})) return false;
|
|
65726
66113
|
if (prevProps.urlDate !== nextProps.urlDate || prevProps.urlShift !== nextProps.urlShift) return false;
|
|
65727
66114
|
if (prevProps.workspaceDisplayNames !== nextProps.workspaceDisplayNames) return false;
|
|
65728
66115
|
return true;
|
|
@@ -65990,6 +66377,7 @@ var KPIDetailView = ({
|
|
|
65990
66377
|
}
|
|
65991
66378
|
}, [urlDate, urlShift, urlTab]);
|
|
65992
66379
|
const { shiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(lineId);
|
|
66380
|
+
const lineTimezone = shiftConfig?.timezone || configuredTimezone;
|
|
65993
66381
|
const getShiftName = React144.useCallback((shiftId) => {
|
|
65994
66382
|
return getShiftNameById(shiftId, configuredTimezone, shiftConfig);
|
|
65995
66383
|
}, [configuredTimezone, shiftConfig]);
|
|
@@ -66030,12 +66418,12 @@ var KPIDetailView = ({
|
|
|
66030
66418
|
operationalTodayDate.setHours(0, 0, 0, 0);
|
|
66031
66419
|
compareDateInZone.setHours(0, 0, 0, 0);
|
|
66032
66420
|
const diffTime = compareDateInZone.getTime() - operationalTodayDate.getTime();
|
|
66033
|
-
const
|
|
66034
|
-
if (
|
|
66035
|
-
if (
|
|
66036
|
-
if (
|
|
66037
|
-
if (
|
|
66038
|
-
if (
|
|
66421
|
+
const diffDays2 = Math.round(diffTime / (1e3 * 60 * 60 * 24));
|
|
66422
|
+
if (diffDays2 === 0) return "Today";
|
|
66423
|
+
if (diffDays2 === -1) return "Yesterday";
|
|
66424
|
+
if (diffDays2 === 1) return "Tomorrow";
|
|
66425
|
+
if (diffDays2 < -1) return `${Math.abs(diffDays2)} days ago`;
|
|
66426
|
+
if (diffDays2 > 1) return `${diffDays2} days ahead`;
|
|
66039
66427
|
return "Today";
|
|
66040
66428
|
}, [configuredTimezone, shiftConfig]);
|
|
66041
66429
|
const {
|
|
@@ -66245,6 +66633,7 @@ var KPIDetailView = ({
|
|
|
66245
66633
|
underperforming_workspace_uuids: metrics2.underperforming_workspace_uuids || [],
|
|
66246
66634
|
output_array: metrics2.output_array || [],
|
|
66247
66635
|
output_hourly: metrics2.output_hourly,
|
|
66636
|
+
hourly_target_output: metrics2.hourly_target_output ?? null,
|
|
66248
66637
|
line_threshold: metrics2.line_threshold ?? 0,
|
|
66249
66638
|
threshold_pph: metrics2.threshold_pph ?? 0,
|
|
66250
66639
|
shift_start: metrics2.shift_start || "06:00",
|
|
@@ -66254,7 +66643,7 @@ var KPIDetailView = ({
|
|
|
66254
66643
|
idle_time_hourly: metrics2.idle_time_hourly || null,
|
|
66255
66644
|
// Multi-SKU additive fields (Phase 6) — propagated from
|
|
66256
66645
|
// `useLineDetailPageData`. Backend authoritative; we never recompute.
|
|
66257
|
-
// The
|
|
66646
|
+
// The output-card selection below uses these to swap header KPIs per selected SKU.
|
|
66258
66647
|
sku_aware: Boolean(metrics2.sku_aware),
|
|
66259
66648
|
real_sku_count: metrics2.real_sku_count ?? 0,
|
|
66260
66649
|
sku_breakdown: Array.isArray(metrics2.sku_breakdown) ? metrics2.sku_breakdown : [],
|
|
@@ -66351,7 +66740,7 @@ var KPIDetailView = ({
|
|
|
66351
66740
|
}, [lineSkuSegments, outputChartSkuBreakdown, hasUrlDate, hasUrlShift]);
|
|
66352
66741
|
const normalizedSelectedSkuId = selectedSkuId !== "all" ? selectedSkuId : null;
|
|
66353
66742
|
const isLineSkuAware = Boolean(resolvedLineInfo?.metrics.sku_aware);
|
|
66354
|
-
const showSkuSelector = isLineSkuAware && realSkuOptions.length > 0;
|
|
66743
|
+
const showSkuSelector = isLineSkuAware && realSkuOptions.length > 0 && !isUptimeMode;
|
|
66355
66744
|
React144.useEffect(() => {
|
|
66356
66745
|
if (selectedSkuId === "all") return;
|
|
66357
66746
|
const stillPresent = realSkuOptions.some((item) => item.sku_id === selectedSkuId);
|
|
@@ -66378,15 +66767,11 @@ var KPIDetailView = ({
|
|
|
66378
66767
|
...resolvedLineInfo.metrics,
|
|
66379
66768
|
current_output: selectedSkuRow.current_output ?? 0,
|
|
66380
66769
|
ideal_output: selectedSkuRow.ideal_output ?? 0,
|
|
66381
|
-
avg_efficiency: selectedSkuRow.avg_efficiency ?? resolvedLineInfo.metrics.avg_efficiency,
|
|
66382
66770
|
total_workspaces: selectedSkuRow.total_workspaces ?? resolvedLineInfo.metrics.total_workspaces,
|
|
66383
66771
|
underperforming_workspaces: selectedSkuRow.underperforming_workspaces ?? resolvedLineInfo.metrics.underperforming_workspaces,
|
|
66384
66772
|
underperforming_workspace_names: selectedSkuRow.underperforming_workspace_names ?? resolvedLineInfo.metrics.underperforming_workspace_names,
|
|
66385
66773
|
underperforming_workspace_uuids: selectedSkuRow.underperforming_workspace_uuids ?? resolvedLineInfo.metrics.underperforming_workspace_uuids,
|
|
66386
|
-
|
|
66387
|
-
output_hourly: selectedSkuRow.output_hourly ?? resolvedLineInfo.metrics.output_hourly,
|
|
66388
|
-
line_threshold: selectedSkuRow.line_threshold ?? resolvedLineInfo.metrics.line_threshold,
|
|
66389
|
-
poorest_performing_workspaces: selectedSkuRow.poorest_performing_workspaces ?? resolvedLineInfo.metrics.poorest_performing_workspaces
|
|
66774
|
+
line_threshold: selectedSkuRow.line_threshold ?? resolvedLineInfo.metrics.line_threshold
|
|
66390
66775
|
}
|
|
66391
66776
|
};
|
|
66392
66777
|
}, [resolvedLineInfo, selectedSkuRow]);
|
|
@@ -67165,11 +67550,9 @@ var KPIDetailView = ({
|
|
|
67165
67550
|
showIdleTime: idleTimeVlmEnabled
|
|
67166
67551
|
}
|
|
67167
67552
|
) : (
|
|
67168
|
-
//
|
|
67169
|
-
//
|
|
67170
|
-
//
|
|
67171
|
-
// cards. When `selectedSkuId === 'all'`, this is exactly
|
|
67172
|
-
// `resolvedLineInfo` (aggregate path preserved).
|
|
67553
|
+
// Keep the line output + underperforming cards SKU-aware,
|
|
67554
|
+
// while Average Efficiency stays on the aggregate line
|
|
67555
|
+
// metrics even when a specific SKU is selected.
|
|
67173
67556
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
67174
67557
|
MetricCards,
|
|
67175
67558
|
{
|
|
@@ -67214,6 +67597,9 @@ var KPIDetailView = ({
|
|
|
67214
67597
|
workspaceDisplayNames,
|
|
67215
67598
|
hourlyOutputData,
|
|
67216
67599
|
hourlyThreshold,
|
|
67600
|
+
hourlyTargetOutput: chartMetrics?.hourly_target_output ?? null,
|
|
67601
|
+
idleTimeHourly: chartMetrics?.idle_time_hourly,
|
|
67602
|
+
timezone: lineTimezone,
|
|
67217
67603
|
urlDate,
|
|
67218
67604
|
urlShift,
|
|
67219
67605
|
navigate,
|
|
@@ -67279,8 +67665,8 @@ var KPIDetailView = ({
|
|
|
67279
67665
|
showIdleTime: idleTimeVlmEnabled
|
|
67280
67666
|
}
|
|
67281
67667
|
) : (
|
|
67282
|
-
//
|
|
67283
|
-
//
|
|
67668
|
+
// Keep the line output + underperforming cards SKU-aware,
|
|
67669
|
+
// while Average Efficiency stays aggregate.
|
|
67284
67670
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
67285
67671
|
MetricCards,
|
|
67286
67672
|
{
|
|
@@ -67325,6 +67711,8 @@ var KPIDetailView = ({
|
|
|
67325
67711
|
workspaceDisplayNames,
|
|
67326
67712
|
hourlyOutputData,
|
|
67327
67713
|
hourlyThreshold,
|
|
67714
|
+
idleTimeHourly: chartMetrics?.idle_time_hourly,
|
|
67715
|
+
timezone: lineTimezone,
|
|
67328
67716
|
urlDate,
|
|
67329
67717
|
urlShift,
|
|
67330
67718
|
navigate,
|
|
@@ -73561,12 +73949,12 @@ var getDaysDifference = (date, timezone = "UTC", shiftStartTime = "06:00") => {
|
|
|
73561
73949
|
operationalTodayDate.setHours(0, 0, 0, 0);
|
|
73562
73950
|
compareDateInTz.setHours(0, 0, 0, 0);
|
|
73563
73951
|
const diffTime = compareDateInTz.getTime() - operationalTodayDate.getTime();
|
|
73564
|
-
const
|
|
73565
|
-
if (
|
|
73566
|
-
if (
|
|
73567
|
-
if (
|
|
73568
|
-
if (
|
|
73569
|
-
if (
|
|
73952
|
+
const diffDays2 = Math.round(diffTime / (1e3 * 60 * 60 * 24));
|
|
73953
|
+
if (diffDays2 === 0) return "Today";
|
|
73954
|
+
if (diffDays2 === -1) return "Yesterday";
|
|
73955
|
+
if (diffDays2 === 1) return "Tomorrow";
|
|
73956
|
+
if (diffDays2 < -1) return `${Math.abs(diffDays2)} days ago`;
|
|
73957
|
+
if (diffDays2 > 1) return `${diffDays2} days ahead`;
|
|
73570
73958
|
return "Today";
|
|
73571
73959
|
};
|
|
73572
73960
|
var getInitialTab = (sourceType, defaultTab, fromMonthly, urlDate) => {
|
|
@@ -74002,7 +74390,7 @@ var WorkspaceDetailView = ({
|
|
|
74002
74390
|
() => resolveLiveSkuId(workspace?.sku_segments),
|
|
74003
74391
|
[workspace?.sku_segments]
|
|
74004
74392
|
);
|
|
74005
|
-
const activeSkuId = selectedSkuId
|
|
74393
|
+
const activeSkuId = selectedSkuId;
|
|
74006
74394
|
const resolvedLineId = effectiveLineId || workspace?.line_id || cachedDetailedMetrics?.line_id || cachedOverviewMetrics?.line_id || overviewFallback?.line_id;
|
|
74007
74395
|
const { timezone: cycleTimeTimezone } = useTimezone({
|
|
74008
74396
|
lineId: resolvedLineId || void 0,
|
|
@@ -74970,6 +75358,7 @@ var WorkspaceDetailView = ({
|
|
|
74970
75358
|
{
|
|
74971
75359
|
data: workspace.hourly_action_counts || [],
|
|
74972
75360
|
pphThreshold: workspace.pph_threshold || 0,
|
|
75361
|
+
hourlyTargetOutput: workspace.hourly_target_output,
|
|
74973
75362
|
shiftStart: workspace.shift_start || "06:00",
|
|
74974
75363
|
shiftEnd: workspace.shift_end,
|
|
74975
75364
|
showIdleTime: showChartIdleTime,
|
|
@@ -74977,7 +75366,7 @@ var WorkspaceDetailView = ({
|
|
|
74977
75366
|
idleTimeClips,
|
|
74978
75367
|
idleTimeClipClassifications,
|
|
74979
75368
|
shiftDate: idleClipDate,
|
|
74980
|
-
timezone,
|
|
75369
|
+
timezone: effectiveCycleTimeTimezone,
|
|
74981
75370
|
skuSegments: isSkuAware ? skuSegments : void 0,
|
|
74982
75371
|
activeSkuId
|
|
74983
75372
|
}
|
|
@@ -75116,6 +75505,7 @@ var WorkspaceDetailView = ({
|
|
|
75116
75505
|
{
|
|
75117
75506
|
data: workspace.hourly_action_counts || [],
|
|
75118
75507
|
pphThreshold: workspace.pph_threshold || 0,
|
|
75508
|
+
hourlyTargetOutput: workspace.hourly_target_output,
|
|
75119
75509
|
shiftStart: workspace.shift_start || "06:00",
|
|
75120
75510
|
shiftEnd: workspace.shift_end,
|
|
75121
75511
|
showIdleTime: showChartIdleTime,
|
|
@@ -75123,7 +75513,7 @@ var WorkspaceDetailView = ({
|
|
|
75123
75513
|
idleTimeClips,
|
|
75124
75514
|
idleTimeClipClassifications,
|
|
75125
75515
|
shiftDate: idleClipDate,
|
|
75126
|
-
timezone,
|
|
75516
|
+
timezone: effectiveCycleTimeTimezone,
|
|
75127
75517
|
skuSegments: isSkuAware ? skuSegments : void 0,
|
|
75128
75518
|
activeSkuId
|
|
75129
75519
|
}
|
|
@@ -78400,8 +78790,8 @@ var ImprovementCenterView = () => {
|
|
|
78400
78790
|
const firstSeen = new Date(new Date(openedAt).toLocaleString("en-US", { timeZone: timezone }));
|
|
78401
78791
|
if (Number.isNaN(firstSeen.getTime())) return void 0;
|
|
78402
78792
|
const now4 = new Date((/* @__PURE__ */ new Date()).toLocaleString("en-US", { timeZone: timezone }));
|
|
78403
|
-
const
|
|
78404
|
-
return Math.max(1, Math.ceil(
|
|
78793
|
+
const diffDays2 = Math.max(0, Math.floor((now4.getTime() - firstSeen.getTime()) / (1e3 * 60 * 60 * 24)));
|
|
78794
|
+
return Math.max(1, Math.ceil(diffDays2 / 7));
|
|
78405
78795
|
};
|
|
78406
78796
|
const toZonedDate = (value) => {
|
|
78407
78797
|
if (!value) return void 0;
|
|
@@ -79082,12 +79472,12 @@ var ThreadSidebar = ({
|
|
|
79082
79472
|
const date = new Date(dateString);
|
|
79083
79473
|
const now4 = /* @__PURE__ */ new Date();
|
|
79084
79474
|
const diffMs = now4.getTime() - date.getTime();
|
|
79085
|
-
const
|
|
79086
|
-
if (
|
|
79475
|
+
const diffDays2 = Math.floor(diffMs / (1e3 * 60 * 60 * 24));
|
|
79476
|
+
if (diffDays2 === 0) {
|
|
79087
79477
|
return "Today";
|
|
79088
|
-
} else if (
|
|
79478
|
+
} else if (diffDays2 === 1) {
|
|
79089
79479
|
return "Yesterday";
|
|
79090
|
-
} else if (
|
|
79480
|
+
} else if (diffDays2 < 7) {
|
|
79091
79481
|
return date.toLocaleDateString("en-US", { weekday: "short" });
|
|
79092
79482
|
} else {
|
|
79093
79483
|
return date.toLocaleDateString("en-US", { month: "short", day: "numeric" });
|