@optifye/dashboard-core 6.11.15 → 6.11.17
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 +26 -3
- package/dist/index.d.mts +35 -2
- package/dist/index.d.ts +35 -2
- package/dist/index.js +1338 -558
- package/dist/index.mjs +1337 -560
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3295,11 +3295,9 @@ var normalizeShiftDefinitions = (timezone, shiftConfig) => {
|
|
|
3295
3295
|
}
|
|
3296
3296
|
return { shifts: legacyShifts, timezone: fallbackTimezone };
|
|
3297
3297
|
};
|
|
3298
|
-
var
|
|
3298
|
+
var determineActiveShiftFromDefinitions = (timezone, shifts, now4 = /* @__PURE__ */ new Date()) => {
|
|
3299
3299
|
const zonedNow = dateFnsTz.toZonedTime(now4, timezone);
|
|
3300
3300
|
const currentMinutes = zonedNow.getHours() * 60 + zonedNow.getMinutes();
|
|
3301
|
-
let chosen;
|
|
3302
|
-
let operationalDate = getOperationalDate(timezone, now4, shifts[0].startTime);
|
|
3303
3301
|
for (const shift of shifts) {
|
|
3304
3302
|
const start = parseTimeToMinutes(shift.startTime);
|
|
3305
3303
|
const endRaw = parseTimeToMinutes(shift.endTime);
|
|
@@ -3307,32 +3305,47 @@ var determineShiftFromDefinitions = (timezone, shifts, now4 = /* @__PURE__ */ ne
|
|
|
3307
3305
|
const wraps = end <= start;
|
|
3308
3306
|
if (wraps) end += 1440;
|
|
3309
3307
|
if (start <= currentMinutes && currentMinutes < end) {
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3308
|
+
return {
|
|
3309
|
+
shiftId: shift.shiftId,
|
|
3310
|
+
shiftName: shift.shiftName,
|
|
3311
|
+
startTime: shift.startTime,
|
|
3312
|
+
endTime: shift.endTime,
|
|
3313
|
+
timezone,
|
|
3314
|
+
date: getOperationalDate(timezone, now4, shift.startTime)
|
|
3315
|
+
};
|
|
3313
3316
|
}
|
|
3314
3317
|
if (start <= currentMinutes + 1440 && currentMinutes + 1440 < end) {
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
+
return {
|
|
3319
|
+
shiftId: shift.shiftId,
|
|
3320
|
+
shiftName: shift.shiftName,
|
|
3321
|
+
startTime: shift.startTime,
|
|
3322
|
+
endTime: shift.endTime,
|
|
3323
|
+
timezone,
|
|
3324
|
+
date: getOperationalDate(timezone, now4, shift.startTime)
|
|
3325
|
+
};
|
|
3318
3326
|
}
|
|
3319
3327
|
}
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3328
|
+
return null;
|
|
3329
|
+
};
|
|
3330
|
+
var getCurrentShift = (timezone, shiftConfig, now4 = /* @__PURE__ */ new Date()) => {
|
|
3331
|
+
const { shifts, timezone: effectiveTz } = normalizeShiftDefinitions(timezone, shiftConfig);
|
|
3332
|
+
const activeShift = determineActiveShiftFromDefinitions(effectiveTz, shifts, now4);
|
|
3333
|
+
if (activeShift) {
|
|
3334
|
+
return activeShift;
|
|
3323
3335
|
}
|
|
3336
|
+
const fallbackShift = shifts[0];
|
|
3324
3337
|
return {
|
|
3325
|
-
shiftId:
|
|
3326
|
-
shiftName:
|
|
3327
|
-
startTime:
|
|
3328
|
-
endTime:
|
|
3329
|
-
timezone,
|
|
3330
|
-
date:
|
|
3338
|
+
shiftId: fallbackShift.shiftId,
|
|
3339
|
+
shiftName: fallbackShift.shiftName,
|
|
3340
|
+
startTime: fallbackShift.startTime,
|
|
3341
|
+
endTime: fallbackShift.endTime,
|
|
3342
|
+
timezone: effectiveTz,
|
|
3343
|
+
date: getOperationalDate(effectiveTz, now4, fallbackShift.startTime)
|
|
3331
3344
|
};
|
|
3332
3345
|
};
|
|
3333
|
-
var
|
|
3346
|
+
var getActiveShift = (timezone, shiftConfig, now4 = /* @__PURE__ */ new Date()) => {
|
|
3334
3347
|
const { shifts, timezone: effectiveTz } = normalizeShiftDefinitions(timezone, shiftConfig);
|
|
3335
|
-
return
|
|
3348
|
+
return determineActiveShiftFromDefinitions(effectiveTz, shifts, now4);
|
|
3336
3349
|
};
|
|
3337
3350
|
var isTransitionPeriod = (timezone, shiftConfig, now4 = /* @__PURE__ */ new Date()) => {
|
|
3338
3351
|
const transitionMinutes = shiftConfig?.transitionPeriodMinutes ?? DEFAULT_TRANSITION_MINUTES;
|
|
@@ -12864,6 +12877,7 @@ var useShiftGroups = ({
|
|
|
12864
12877
|
}) => {
|
|
12865
12878
|
const [shiftGroups, setShiftGroups] = React141.useState([]);
|
|
12866
12879
|
const [shiftGroupsKey, setShiftGroupsKey] = React141.useState("");
|
|
12880
|
+
const [hasComputed, setHasComputed] = React141.useState(false);
|
|
12867
12881
|
const lastKeyRef = React141.useRef("");
|
|
12868
12882
|
const mapRef = React141.useRef(shiftConfigMap);
|
|
12869
12883
|
React141.useEffect(() => {
|
|
@@ -12874,6 +12888,7 @@ var useShiftGroups = ({
|
|
|
12874
12888
|
lastKeyRef.current = "";
|
|
12875
12889
|
setShiftGroups([]);
|
|
12876
12890
|
setShiftGroupsKey("");
|
|
12891
|
+
setHasComputed(false);
|
|
12877
12892
|
return;
|
|
12878
12893
|
}
|
|
12879
12894
|
let isMounted = true;
|
|
@@ -12886,6 +12901,7 @@ var useShiftGroups = ({
|
|
|
12886
12901
|
setShiftGroups(groups);
|
|
12887
12902
|
setShiftGroupsKey(key);
|
|
12888
12903
|
}
|
|
12904
|
+
setHasComputed(true);
|
|
12889
12905
|
};
|
|
12890
12906
|
compute();
|
|
12891
12907
|
const intervalId = setInterval(compute, pollIntervalMs);
|
|
@@ -12894,7 +12910,7 @@ var useShiftGroups = ({
|
|
|
12894
12910
|
clearInterval(intervalId);
|
|
12895
12911
|
};
|
|
12896
12912
|
}, [enabled, shiftConfigMap.size, timezone, pollIntervalMs]);
|
|
12897
|
-
return { shiftGroups, shiftGroupsKey };
|
|
12913
|
+
return { shiftGroups, shiftGroupsKey, hasComputed };
|
|
12898
12914
|
};
|
|
12899
12915
|
|
|
12900
12916
|
// src/lib/types/efficiencyLegend.ts
|
|
@@ -12956,52 +12972,6 @@ function getEfficiencyTextColorClasses(efficiency, legend = DEFAULT_EFFICIENCY_L
|
|
|
12956
12972
|
}
|
|
12957
12973
|
}
|
|
12958
12974
|
|
|
12959
|
-
// src/lib/hooks/useDashboardMetrics.recentFlow.ts
|
|
12960
|
-
var isFiniteNumber = (value) => typeof value === "number" && Number.isFinite(value);
|
|
12961
|
-
var getWorkspaceRecentFlowCacheKey = (workspace) => {
|
|
12962
|
-
const workspaceKey = workspace.workspace_uuid || workspace.workspace_name || "unknown";
|
|
12963
|
-
return `${workspaceKey}|${workspace.date}|${workspace.shift_id}`;
|
|
12964
|
-
};
|
|
12965
|
-
var toRecentFlowSnapshot = (workspace) => {
|
|
12966
|
-
if (!isFiniteNumber(workspace.recent_flow_percent)) {
|
|
12967
|
-
return null;
|
|
12968
|
-
}
|
|
12969
|
-
return {
|
|
12970
|
-
recent_flow_percent: workspace.recent_flow_percent,
|
|
12971
|
-
recent_flow_actual_rate_pph: workspace.recent_flow_actual_rate_pph ?? null,
|
|
12972
|
-
recent_flow_healthy_rate_pph: workspace.recent_flow_healthy_rate_pph ?? null,
|
|
12973
|
-
recent_flow_window_minutes: workspace.recent_flow_window_minutes ?? null,
|
|
12974
|
-
recent_flow_effective_end_at: workspace.recent_flow_effective_end_at ?? null
|
|
12975
|
-
};
|
|
12976
|
-
};
|
|
12977
|
-
var mergeWorkspaceRecentFlowMetrics = (workspaces, previousCache) => {
|
|
12978
|
-
const nextCache = /* @__PURE__ */ new Map();
|
|
12979
|
-
const mergedWorkspaces = workspaces.map((workspace) => {
|
|
12980
|
-
const cacheKey = getWorkspaceRecentFlowCacheKey(workspace);
|
|
12981
|
-
const currentSnapshot = toRecentFlowSnapshot(workspace);
|
|
12982
|
-
if (workspace.recent_flow_mode === "computed" && currentSnapshot) {
|
|
12983
|
-
nextCache.set(cacheKey, currentSnapshot);
|
|
12984
|
-
return workspace;
|
|
12985
|
-
}
|
|
12986
|
-
if (workspace.recent_flow_mode === "hold") {
|
|
12987
|
-
const cachedSnapshot = previousCache.get(cacheKey);
|
|
12988
|
-
if (cachedSnapshot) {
|
|
12989
|
-
nextCache.set(cacheKey, cachedSnapshot);
|
|
12990
|
-
return {
|
|
12991
|
-
...workspace,
|
|
12992
|
-
...cachedSnapshot,
|
|
12993
|
-
recent_flow_mode: "hold"
|
|
12994
|
-
};
|
|
12995
|
-
}
|
|
12996
|
-
}
|
|
12997
|
-
return workspace;
|
|
12998
|
-
});
|
|
12999
|
-
return {
|
|
13000
|
-
workspaces: mergedWorkspaces,
|
|
13001
|
-
cache: nextCache
|
|
13002
|
-
};
|
|
13003
|
-
};
|
|
13004
|
-
|
|
13005
12975
|
// src/lib/hooks/useDashboardMetrics.ts
|
|
13006
12976
|
var DEBUG_DASHBOARD_LOGS = process.env.NEXT_PUBLIC_DEBUG_DASHBOARD === "true";
|
|
13007
12977
|
var logDebug = (...args) => {
|
|
@@ -13090,7 +13060,6 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
13090
13060
|
const abortControllerRef = React141.useRef(null);
|
|
13091
13061
|
const lastFetchKeyRef = React141.useRef(null);
|
|
13092
13062
|
const inFlightFetchKeyRef = React141.useRef(null);
|
|
13093
|
-
const recentFlowCacheRef = React141.useRef(/* @__PURE__ */ new Map());
|
|
13094
13063
|
const updateQueueRef = React141.useRef(false);
|
|
13095
13064
|
const onLineMetricsUpdateRef = React141.useRef(onLineMetricsUpdate);
|
|
13096
13065
|
const shiftGroupsRef = React141.useRef(shiftGroups);
|
|
@@ -13124,7 +13093,6 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
13124
13093
|
setError(null);
|
|
13125
13094
|
lastFetchKeyRef.current = null;
|
|
13126
13095
|
inFlightFetchKeyRef.current = null;
|
|
13127
|
-
recentFlowCacheRef.current = /* @__PURE__ */ new Map();
|
|
13128
13096
|
}, [lineId]);
|
|
13129
13097
|
const fetchAllMetrics = React141.useCallback(async (options = {}) => {
|
|
13130
13098
|
const { force = false } = options;
|
|
@@ -13399,12 +13367,9 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
13399
13367
|
actionType: item.action_type,
|
|
13400
13368
|
actionName: item.action_name
|
|
13401
13369
|
}),
|
|
13402
|
-
recent_flow_mode: item.recent_flow_mode ?? void 0,
|
|
13403
13370
|
recent_flow_percent: item.recent_flow_percent ?? null,
|
|
13404
|
-
recent_flow_actual_rate_pph: item.recent_flow_actual_rate_pph ?? null,
|
|
13405
|
-
recent_flow_healthy_rate_pph: item.recent_flow_healthy_rate_pph ?? null,
|
|
13406
|
-
recent_flow_window_minutes: item.recent_flow_window_minutes ?? null,
|
|
13407
13371
|
recent_flow_effective_end_at: item.recent_flow_effective_end_at ?? null,
|
|
13372
|
+
recent_flow_computed_at: item.recent_flow_computed_at ?? null,
|
|
13408
13373
|
incoming_wip_current: item.incoming_wip_current ?? null,
|
|
13409
13374
|
incoming_wip_effective_at: item.incoming_wip_effective_at ?? null,
|
|
13410
13375
|
incoming_wip_buffer_name: item.incoming_wip_buffer_name ?? null
|
|
@@ -13415,16 +13380,11 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
13415
13380
|
const wsNumB = parseInt(b.workspace_name?.replace(/[^0-9]/g, "") || "0");
|
|
13416
13381
|
return wsNumA - wsNumB;
|
|
13417
13382
|
});
|
|
13418
|
-
|
|
13419
|
-
workspaces: mergedWorkspaceData,
|
|
13420
|
-
cache: nextRecentFlowCache
|
|
13421
|
-
} = mergeWorkspaceRecentFlowMetrics(transformedWorkspaceData, recentFlowCacheRef.current);
|
|
13422
|
-
recentFlowCacheRef.current = nextRecentFlowCache;
|
|
13423
|
-
mergedWorkspaceData.forEach((metric) => {
|
|
13383
|
+
transformedWorkspaceData.forEach((metric) => {
|
|
13424
13384
|
workspaceMetricsStore.setOverview(metric);
|
|
13425
13385
|
});
|
|
13426
13386
|
const newMetricsState = {
|
|
13427
|
-
workspaceMetrics:
|
|
13387
|
+
workspaceMetrics: transformedWorkspaceData,
|
|
13428
13388
|
lineMetrics: allLineMetrics || [],
|
|
13429
13389
|
metadata: { hasFlowBuffers, idleTimeVlmByLine },
|
|
13430
13390
|
efficiencyLegend: efficiencyLegend ?? DEFAULT_EFFICIENCY_LEGEND
|
|
@@ -16849,7 +16809,7 @@ var useActiveBreaks = (lineIds) => {
|
|
|
16849
16809
|
const [isLoading, setIsLoading] = React141.useState(true);
|
|
16850
16810
|
const [error, setError] = React141.useState(null);
|
|
16851
16811
|
const supabase = useSupabase();
|
|
16852
|
-
const
|
|
16812
|
+
const parseTimeToMinutes4 = (timeStr) => {
|
|
16853
16813
|
const [hours, minutes] = timeStr.split(":").map(Number);
|
|
16854
16814
|
return hours * 60 + minutes;
|
|
16855
16815
|
};
|
|
@@ -16858,8 +16818,8 @@ var useActiveBreaks = (lineIds) => {
|
|
|
16858
16818
|
return now4.getHours() * 60 + now4.getMinutes();
|
|
16859
16819
|
};
|
|
16860
16820
|
const isTimeInBreak = (breakStart, breakEnd, currentMinutes) => {
|
|
16861
|
-
const startMinutes =
|
|
16862
|
-
const endMinutes =
|
|
16821
|
+
const startMinutes = parseTimeToMinutes4(breakStart);
|
|
16822
|
+
const endMinutes = parseTimeToMinutes4(breakEnd);
|
|
16863
16823
|
if (endMinutes < startMinutes) {
|
|
16864
16824
|
return currentMinutes >= startMinutes || currentMinutes < endMinutes;
|
|
16865
16825
|
} else {
|
|
@@ -16867,8 +16827,8 @@ var useActiveBreaks = (lineIds) => {
|
|
|
16867
16827
|
}
|
|
16868
16828
|
};
|
|
16869
16829
|
const calculateBreakProgress = (breakStart, breakEnd, currentMinutes) => {
|
|
16870
|
-
const startMinutes =
|
|
16871
|
-
const endMinutes =
|
|
16830
|
+
const startMinutes = parseTimeToMinutes4(breakStart);
|
|
16831
|
+
const endMinutes = parseTimeToMinutes4(breakEnd);
|
|
16872
16832
|
let elapsedMinutes = 0;
|
|
16873
16833
|
let remainingMinutes = 0;
|
|
16874
16834
|
if (endMinutes < startMinutes) {
|
|
@@ -16886,8 +16846,8 @@ var useActiveBreaks = (lineIds) => {
|
|
|
16886
16846
|
return { elapsedMinutes, remainingMinutes };
|
|
16887
16847
|
};
|
|
16888
16848
|
const isTimeInShift = (startTime, endTime, currentMinutes) => {
|
|
16889
|
-
const startMinutes =
|
|
16890
|
-
const endMinutes =
|
|
16849
|
+
const startMinutes = parseTimeToMinutes4(startTime);
|
|
16850
|
+
const endMinutes = parseTimeToMinutes4(endTime);
|
|
16891
16851
|
if (endMinutes < startMinutes) {
|
|
16892
16852
|
return currentMinutes >= startMinutes || currentMinutes < endMinutes;
|
|
16893
16853
|
} else {
|
|
@@ -16947,8 +16907,8 @@ var useActiveBreaks = (lineIds) => {
|
|
|
16947
16907
|
const endTime = breakItem.end || breakItem.endTime || "00:00";
|
|
16948
16908
|
let duration = breakItem.duration || 0;
|
|
16949
16909
|
if (!duration || duration === 0) {
|
|
16950
|
-
const startMinutes =
|
|
16951
|
-
const endMinutes =
|
|
16910
|
+
const startMinutes = parseTimeToMinutes4(startTime);
|
|
16911
|
+
const endMinutes = parseTimeToMinutes4(endTime);
|
|
16952
16912
|
duration = endMinutes < startMinutes ? endMinutes + 24 * 60 - startMinutes : endMinutes - startMinutes;
|
|
16953
16913
|
}
|
|
16954
16914
|
return {
|
|
@@ -16964,8 +16924,8 @@ var useActiveBreaks = (lineIds) => {
|
|
|
16964
16924
|
const endTime = breakItem.end || breakItem.endTime || "00:00";
|
|
16965
16925
|
let duration = breakItem.duration || 0;
|
|
16966
16926
|
if (!duration || duration === 0) {
|
|
16967
|
-
const startMinutes =
|
|
16968
|
-
const endMinutes =
|
|
16927
|
+
const startMinutes = parseTimeToMinutes4(startTime);
|
|
16928
|
+
const endMinutes = parseTimeToMinutes4(endTime);
|
|
16969
16929
|
duration = endMinutes < startMinutes ? endMinutes + 24 * 60 - startMinutes : endMinutes - startMinutes;
|
|
16970
16930
|
}
|
|
16971
16931
|
return {
|
|
@@ -23046,6 +23006,16 @@ var createThrottledReload = (interval = 5e3, maxReloads = 3) => {
|
|
|
23046
23006
|
};
|
|
23047
23007
|
var throttledReloadDashboard = createThrottledReload(5e3, 3);
|
|
23048
23008
|
|
|
23009
|
+
// src/lib/utils/dev/localDevTestLogin.ts
|
|
23010
|
+
var isLoopbackHostname = (hostname) => {
|
|
23011
|
+
const normalized = String(hostname || "").trim().toLowerCase();
|
|
23012
|
+
return normalized === "localhost" || normalized === "127.0.0.1" || normalized === "::1";
|
|
23013
|
+
};
|
|
23014
|
+
var shouldEnableLocalDevTestLogin = ({
|
|
23015
|
+
enabledFlag,
|
|
23016
|
+
hostname
|
|
23017
|
+
}) => enabledFlag && isLoopbackHostname(hostname);
|
|
23018
|
+
|
|
23049
23019
|
// src/lib/utils/index.ts
|
|
23050
23020
|
var formatIdleTime = (idleTimeInSeconds) => {
|
|
23051
23021
|
if (!idleTimeInSeconds || idleTimeInSeconds <= 0) {
|
|
@@ -31230,12 +31200,16 @@ var LoginPage = ({
|
|
|
31230
31200
|
onRateLimitCheck,
|
|
31231
31201
|
logoSrc = optifye_logo_default,
|
|
31232
31202
|
logoAlt = "Optifye",
|
|
31233
|
-
brandName = "Optifye"
|
|
31203
|
+
brandName = "Optifye",
|
|
31204
|
+
showDevTestLogin = false,
|
|
31205
|
+
devTestLoginLabel = "Sign in as Test User",
|
|
31206
|
+
onDevTestLogin
|
|
31234
31207
|
}) => {
|
|
31235
31208
|
const [email, setEmail] = React141.useState("");
|
|
31236
31209
|
const [otp, setOtp] = React141.useState("");
|
|
31237
31210
|
const [step, setStep] = React141.useState("email");
|
|
31238
31211
|
const [loading, setLoading] = React141.useState(false);
|
|
31212
|
+
const [devLoginLoading, setDevLoginLoading] = React141.useState(false);
|
|
31239
31213
|
const [error, setError] = React141.useState(null);
|
|
31240
31214
|
const [countdown, setCountdown] = React141.useState(0);
|
|
31241
31215
|
const supabase = useSupabase();
|
|
@@ -31299,6 +31273,25 @@ var LoginPage = ({
|
|
|
31299
31273
|
startCountdown();
|
|
31300
31274
|
}
|
|
31301
31275
|
};
|
|
31276
|
+
const handleDevTestLogin = async () => {
|
|
31277
|
+
if (!onDevTestLogin) {
|
|
31278
|
+
return;
|
|
31279
|
+
}
|
|
31280
|
+
setDevLoginLoading(true);
|
|
31281
|
+
setError(null);
|
|
31282
|
+
try {
|
|
31283
|
+
const result = await onDevTestLogin();
|
|
31284
|
+
const nextError = typeof result === "object" && result !== null && "error" in result ? result.error : null;
|
|
31285
|
+
if (typeof nextError === "string" && nextError.trim()) {
|
|
31286
|
+
setError(nextError);
|
|
31287
|
+
}
|
|
31288
|
+
} catch (err) {
|
|
31289
|
+
console.error("Dev test login failed:", err);
|
|
31290
|
+
setError("Dev test login unavailable.");
|
|
31291
|
+
} finally {
|
|
31292
|
+
setDevLoginLoading(false);
|
|
31293
|
+
}
|
|
31294
|
+
};
|
|
31302
31295
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-screen flex items-center justify-center bg-gradient-to-br from-slate-50 to-slate-100", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-md w-full mx-4", children: [
|
|
31303
31296
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-2xl shadow-xl border border-slate-200 p-8", children: [
|
|
31304
31297
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center mb-8", children: [
|
|
@@ -31339,7 +31332,7 @@ var LoginPage = ({
|
|
|
31339
31332
|
"button",
|
|
31340
31333
|
{
|
|
31341
31334
|
type: "submit",
|
|
31342
|
-
disabled: loading,
|
|
31335
|
+
disabled: loading || devLoginLoading,
|
|
31343
31336
|
className: "w-full py-3 px-4 bg-slate-900 hover:bg-slate-800 focus:ring-2 focus:ring-slate-600 focus:ring-offset-2 text-white font-medium rounded-xl transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center",
|
|
31344
31337
|
children: loading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
31345
31338
|
/* @__PURE__ */ jsxRuntime.jsxs("svg", { className: "animate-spin -ml-1 mr-3 h-4 w-4 text-white", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [
|
|
@@ -31349,7 +31342,31 @@ var LoginPage = ({
|
|
|
31349
31342
|
"Sending..."
|
|
31350
31343
|
] }) : "Continue with Email"
|
|
31351
31344
|
}
|
|
31352
|
-
)
|
|
31345
|
+
),
|
|
31346
|
+
showDevTestLogin && onDevTestLogin ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
|
|
31347
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
31348
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-px flex-1 bg-slate-200" }),
|
|
31349
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium uppercase tracking-[0.2em] text-slate-400", children: "Local Dev" }),
|
|
31350
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-px flex-1 bg-slate-200" })
|
|
31351
|
+
] }),
|
|
31352
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
31353
|
+
"button",
|
|
31354
|
+
{
|
|
31355
|
+
type: "button",
|
|
31356
|
+
disabled: loading || devLoginLoading,
|
|
31357
|
+
onClick: () => void handleDevTestLogin(),
|
|
31358
|
+
className: "w-full py-3 px-4 bg-white hover:bg-slate-50 focus:ring-2 focus:ring-slate-400 focus:ring-offset-2 text-slate-700 font-medium rounded-xl border border-slate-200 transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center",
|
|
31359
|
+
children: devLoginLoading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
31360
|
+
/* @__PURE__ */ jsxRuntime.jsxs("svg", { className: "animate-spin -ml-1 mr-3 h-4 w-4 text-slate-700", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [
|
|
31361
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
|
|
31362
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" })
|
|
31363
|
+
] }),
|
|
31364
|
+
"Signing In..."
|
|
31365
|
+
] }) : devTestLoginLabel
|
|
31366
|
+
}
|
|
31367
|
+
),
|
|
31368
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-center text-xs text-slate-500", children: "Localhost-only convenience login for the shared test account." })
|
|
31369
|
+
] }) : null
|
|
31353
31370
|
] }) : /* @__PURE__ */ jsxRuntime.jsxs("form", { className: "space-y-6", onSubmit: handleVerifyOTP, children: [
|
|
31354
31371
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
31355
31372
|
/* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "otp", className: "block text-sm font-medium text-slate-700 mb-2 text-center", children: "Enter the 6-digit code sent to" }),
|
|
@@ -31374,7 +31391,7 @@ var LoginPage = ({
|
|
|
31374
31391
|
"button",
|
|
31375
31392
|
{
|
|
31376
31393
|
type: "submit",
|
|
31377
|
-
disabled: loading || otp.length !== 6,
|
|
31394
|
+
disabled: loading || devLoginLoading || otp.length !== 6,
|
|
31378
31395
|
className: "w-full py-3 px-4 bg-slate-900 hover:bg-slate-800 focus:ring-2 focus:ring-slate-600 focus:ring-offset-2 text-white font-medium rounded-xl transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center",
|
|
31379
31396
|
children: loading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
31380
31397
|
/* @__PURE__ */ jsxRuntime.jsxs("svg", { className: "animate-spin -ml-1 mr-3 h-4 w-4 text-white", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [
|
|
@@ -32199,6 +32216,7 @@ var LineChartComponent = ({
|
|
|
32199
32216
|
xAxisLabel,
|
|
32200
32217
|
xAxisTickFormatter,
|
|
32201
32218
|
// Pass through for X-axis tick formatting
|
|
32219
|
+
xAxisInterval,
|
|
32202
32220
|
yAxisLabel,
|
|
32203
32221
|
yAxisUnit,
|
|
32204
32222
|
yAxisDomain,
|
|
@@ -32215,31 +32233,35 @@ var LineChartComponent = ({
|
|
|
32215
32233
|
...restOfChartProps
|
|
32216
32234
|
}) => {
|
|
32217
32235
|
const containerRef = React141__namespace.default.useRef(null);
|
|
32218
|
-
const [
|
|
32219
|
-
const
|
|
32220
|
-
const { formatNumber } = useFormatNumber();
|
|
32236
|
+
const [dimensions, setDimensions] = React141__namespace.default.useState({ width: 0, height: 0 });
|
|
32237
|
+
const [hasValidData, setHasValidData] = React141__namespace.default.useState(false);
|
|
32221
32238
|
React141__namespace.default.useEffect(() => {
|
|
32222
|
-
const
|
|
32223
|
-
|
|
32224
|
-
const
|
|
32225
|
-
|
|
32226
|
-
|
|
32227
|
-
|
|
32228
|
-
|
|
32229
|
-
|
|
32230
|
-
checkContainerDimensions();
|
|
32231
|
-
const resizeObserver = new ResizeObserver(checkContainerDimensions);
|
|
32232
|
-
if (containerRef.current) {
|
|
32233
|
-
resizeObserver.observe(containerRef.current);
|
|
32239
|
+
const currentHasValidData = data && lines && lines.length > 0 && data.some(
|
|
32240
|
+
(item) => lines.some((line) => {
|
|
32241
|
+
const val = item[line.dataKey];
|
|
32242
|
+
return typeof val === "number" && val > 0;
|
|
32243
|
+
})
|
|
32244
|
+
);
|
|
32245
|
+
if (currentHasValidData && !hasValidData) {
|
|
32246
|
+
setHasValidData(true);
|
|
32234
32247
|
}
|
|
32235
|
-
|
|
32236
|
-
|
|
32237
|
-
|
|
32238
|
-
|
|
32239
|
-
|
|
32240
|
-
|
|
32241
|
-
|
|
32248
|
+
}, [data, lines, hasValidData]);
|
|
32249
|
+
React141__namespace.default.useEffect(() => {
|
|
32250
|
+
if (!containerRef.current) return;
|
|
32251
|
+
const observer = new ResizeObserver((entries) => {
|
|
32252
|
+
const entry = entries[0];
|
|
32253
|
+
if (entry) {
|
|
32254
|
+
setDimensions({
|
|
32255
|
+
width: entry.contentRect.width,
|
|
32256
|
+
height: entry.contentRect.height
|
|
32257
|
+
});
|
|
32258
|
+
}
|
|
32259
|
+
});
|
|
32260
|
+
observer.observe(containerRef.current);
|
|
32261
|
+
return () => observer.disconnect();
|
|
32242
32262
|
}, []);
|
|
32263
|
+
const themeConfig = useThemeConfig();
|
|
32264
|
+
const { formatNumber } = useFormatNumber();
|
|
32243
32265
|
const yAxisTickFormatter = (value) => {
|
|
32244
32266
|
return `${formatNumber(value)}${yAxisUnit || ""}`;
|
|
32245
32267
|
};
|
|
@@ -32261,57 +32283,72 @@ var LineChartComponent = ({
|
|
|
32261
32283
|
const gridStrokeColor = themeConfig?.gray?.["300"] || "#ccc";
|
|
32262
32284
|
const axisTickFillColor = themeConfig?.gray?.["600"] || "#666";
|
|
32263
32285
|
const axisStrokeColor = themeConfig?.gray?.["400"] || "#999";
|
|
32264
|
-
const
|
|
32265
|
-
|
|
32266
|
-
|
|
32267
|
-
|
|
32268
|
-
|
|
32269
|
-
|
|
32270
|
-
|
|
32271
|
-
|
|
32272
|
-
|
|
32273
|
-
stroke:
|
|
32274
|
-
|
|
32275
|
-
|
|
32276
|
-
|
|
32277
|
-
|
|
32278
|
-
|
|
32279
|
-
|
|
32280
|
-
|
|
32281
|
-
|
|
32282
|
-
|
|
32283
|
-
|
|
32284
|
-
|
|
32285
|
-
|
|
32286
|
-
|
|
32287
|
-
|
|
32288
|
-
|
|
32289
|
-
|
|
32290
|
-
|
|
32291
|
-
|
|
32292
|
-
|
|
32293
|
-
|
|
32294
|
-
|
|
32295
|
-
|
|
32296
|
-
|
|
32297
|
-
|
|
32298
|
-
|
|
32299
|
-
|
|
32300
|
-
|
|
32301
|
-
|
|
32302
|
-
|
|
32303
|
-
|
|
32304
|
-
|
|
32305
|
-
|
|
32306
|
-
|
|
32307
|
-
|
|
32308
|
-
|
|
32309
|
-
|
|
32310
|
-
|
|
32311
|
-
|
|
32312
|
-
|
|
32313
|
-
|
|
32314
|
-
|
|
32286
|
+
const renderChartContent = (chartWidth, chartHeight) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
32287
|
+
recharts.LineChart,
|
|
32288
|
+
{
|
|
32289
|
+
width: chartWidth,
|
|
32290
|
+
height: chartHeight,
|
|
32291
|
+
data,
|
|
32292
|
+
margin: { top: 5, right: 30, left: 20, bottom: 20 },
|
|
32293
|
+
...restOfChartProps,
|
|
32294
|
+
children: [
|
|
32295
|
+
showGrid && /* @__PURE__ */ jsxRuntime.jsx(recharts.CartesianGrid, { strokeDasharray: "3 3", stroke: gridStrokeColor }),
|
|
32296
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
32297
|
+
recharts.XAxis,
|
|
32298
|
+
{
|
|
32299
|
+
dataKey: xAxisDataKey,
|
|
32300
|
+
label: xAxisLabel ? { value: xAxisLabel, position: "insideBottom", offset: -10 } : void 0,
|
|
32301
|
+
tickFormatter: xAxisTickFormatter,
|
|
32302
|
+
interval: xAxisInterval,
|
|
32303
|
+
tick: { fontSize: 12, fill: axisTickFillColor },
|
|
32304
|
+
stroke: axisStrokeColor
|
|
32305
|
+
}
|
|
32306
|
+
),
|
|
32307
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
32308
|
+
recharts.YAxis,
|
|
32309
|
+
{
|
|
32310
|
+
label: yAxisLabel ? { value: yAxisLabel, angle: -90, position: "insideLeft" } : void 0,
|
|
32311
|
+
tickFormatter: yAxisTickFormatter,
|
|
32312
|
+
domain: yAxisDomain,
|
|
32313
|
+
tick: { fontSize: 12, fill: axisTickFillColor },
|
|
32314
|
+
stroke: axisStrokeColor
|
|
32315
|
+
}
|
|
32316
|
+
),
|
|
32317
|
+
showTooltip && /* @__PURE__ */ jsxRuntime.jsx(
|
|
32318
|
+
recharts.Tooltip,
|
|
32319
|
+
{
|
|
32320
|
+
formatter: tooltipFormatter || defaultTooltipFormatter,
|
|
32321
|
+
labelFormatter: tooltipLabelFormatter,
|
|
32322
|
+
itemStyle: { color: "#111827" },
|
|
32323
|
+
cursor: { strokeDasharray: "3 3" }
|
|
32324
|
+
}
|
|
32325
|
+
),
|
|
32326
|
+
showLegend && /* @__PURE__ */ jsxRuntime.jsx(recharts.Legend, { payload: legendPayload }),
|
|
32327
|
+
lines.map((lineConfig, index) => {
|
|
32328
|
+
const lineProps = {
|
|
32329
|
+
...lineConfig,
|
|
32330
|
+
key: lineConfig.dataKey,
|
|
32331
|
+
type: lineConfig.type || "monotone",
|
|
32332
|
+
stroke: lineConfig.stroke || defaultColors[index % defaultColors.length],
|
|
32333
|
+
activeDot: lineConfig.activeDot !== void 0 ? lineConfig.activeDot : { r: 6 },
|
|
32334
|
+
isAnimationActive: true,
|
|
32335
|
+
animationDuration: 1500,
|
|
32336
|
+
animationBegin: 300
|
|
32337
|
+
};
|
|
32338
|
+
return /* @__PURE__ */ jsxRuntime.jsx(recharts.Line, { ...lineProps, children: lineConfig.labelList && /* @__PURE__ */ jsxRuntime.jsx(
|
|
32339
|
+
recharts.LabelList,
|
|
32340
|
+
{
|
|
32341
|
+
dataKey: lineConfig.dataKey,
|
|
32342
|
+
position: "top",
|
|
32343
|
+
formatter: (value) => formatNumber(value),
|
|
32344
|
+
...typeof lineConfig.labelList === "object" ? lineConfig.labelList : {}
|
|
32345
|
+
}
|
|
32346
|
+
) });
|
|
32347
|
+
})
|
|
32348
|
+
]
|
|
32349
|
+
},
|
|
32350
|
+
hasValidData ? "valid" : "empty"
|
|
32351
|
+
);
|
|
32315
32352
|
if (responsive) {
|
|
32316
32353
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
32317
32354
|
"div",
|
|
@@ -32319,11 +32356,20 @@ var LineChartComponent = ({
|
|
|
32319
32356
|
ref: containerRef,
|
|
32320
32357
|
className: clsx(fillContainer ? "w-full h-full" : "w-full h-auto", className),
|
|
32321
32358
|
style: fillContainer ? { height: "100%", minHeight: "50px", minWidth: "100px" } : { aspectRatio: `${aspect}/1`, minHeight: "50px", minWidth: "100px" },
|
|
32322
|
-
children:
|
|
32359
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
32360
|
+
motion.div,
|
|
32361
|
+
{
|
|
32362
|
+
initial: { opacity: 0 },
|
|
32363
|
+
animate: { opacity: 1 },
|
|
32364
|
+
transition: { duration: 0.5 },
|
|
32365
|
+
className: "w-full h-full",
|
|
32366
|
+
children: dimensions.width > 0 && dimensions.height > 0 && renderChartContent(dimensions.width, dimensions.height)
|
|
32367
|
+
}
|
|
32368
|
+
)
|
|
32323
32369
|
}
|
|
32324
32370
|
);
|
|
32325
32371
|
}
|
|
32326
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: clsx("w-full", className), children:
|
|
32372
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: clsx("w-full", className), children: renderChartContent(restOfChartProps.width, restOfChartProps.height) });
|
|
32327
32373
|
};
|
|
32328
32374
|
var LineChart = React141__namespace.default.memo(LineChartComponent, (prevProps, nextProps) => {
|
|
32329
32375
|
if (prevProps.xAxisDataKey !== nextProps.xAxisDataKey || prevProps.xAxisLabel !== nextProps.xAxisLabel || prevProps.yAxisLabel !== nextProps.yAxisLabel || prevProps.yAxisUnit !== nextProps.yAxisUnit || prevProps.className !== nextProps.className || prevProps.showGrid !== nextProps.showGrid || prevProps.showLegend !== nextProps.showLegend || prevProps.showTooltip !== nextProps.showTooltip || prevProps.responsive !== nextProps.responsive || prevProps.aspect !== nextProps.aspect || JSON.stringify(prevProps.yAxisDomain) !== JSON.stringify(nextProps.yAxisDomain)) {
|
|
@@ -32591,14 +32637,35 @@ var CycleTimeOverTimeChart = ({
|
|
|
32591
32637
|
}) => {
|
|
32592
32638
|
const MAX_DATA_POINTS = 40;
|
|
32593
32639
|
const containerRef = React141__namespace.default.useRef(null);
|
|
32594
|
-
const [
|
|
32595
|
-
const
|
|
32640
|
+
const [dimensions, setDimensions] = React141__namespace.default.useState({ width: 0, height: 0 });
|
|
32641
|
+
const [hasValidData, setHasValidData] = React141__namespace.default.useState(false);
|
|
32642
|
+
React141__namespace.default.useEffect(() => {
|
|
32643
|
+
const currentHasValidData = data && data.some((val) => val !== null && val > 0);
|
|
32644
|
+
if (currentHasValidData && !hasValidData) {
|
|
32645
|
+
setHasValidData(true);
|
|
32646
|
+
}
|
|
32647
|
+
}, [data, hasValidData]);
|
|
32648
|
+
React141__namespace.default.useEffect(() => {
|
|
32649
|
+
if (!containerRef.current) return;
|
|
32650
|
+
const observer = new ResizeObserver((entries) => {
|
|
32651
|
+
const entry = entries[0];
|
|
32652
|
+
if (entry) {
|
|
32653
|
+
setDimensions({
|
|
32654
|
+
width: entry.contentRect.width,
|
|
32655
|
+
height: entry.contentRect.height
|
|
32656
|
+
});
|
|
32657
|
+
}
|
|
32658
|
+
});
|
|
32659
|
+
observer.observe(containerRef.current);
|
|
32660
|
+
return () => observer.disconnect();
|
|
32661
|
+
}, []);
|
|
32662
|
+
const parseTimeToMinutes4 = (value) => {
|
|
32596
32663
|
const [hours, minutes] = value.split(":").map(Number);
|
|
32597
32664
|
if (!Number.isFinite(hours) || !Number.isFinite(minutes)) return 0;
|
|
32598
32665
|
return hours * 60 + minutes;
|
|
32599
32666
|
};
|
|
32600
32667
|
const formatHourLabel = (slotIndex) => {
|
|
32601
|
-
const baseMinutes =
|
|
32668
|
+
const baseMinutes = parseTimeToMinutes4(shiftStart);
|
|
32602
32669
|
const absoluteMinutes = baseMinutes + slotIndex * 60;
|
|
32603
32670
|
const hour24 = Math.floor(absoluteMinutes % (24 * 60) / 60);
|
|
32604
32671
|
const ampm = hour24 >= 12 ? "PM" : "AM";
|
|
@@ -32617,52 +32684,7 @@ var CycleTimeOverTimeChart = ({
|
|
|
32617
32684
|
const displayData = getDisplayData(data);
|
|
32618
32685
|
const DURATION = displayData.length;
|
|
32619
32686
|
const effectiveDatasetKey = datasetKey || `cycle-time:${xAxisMode}`;
|
|
32620
|
-
const [animatedDatasetKey, setAnimatedDatasetKey] = React141__namespace.default.useState(null);
|
|
32621
|
-
const shouldAnimate = animatedDatasetKey !== effectiveDatasetKey;
|
|
32622
|
-
const handleAnimationEnd = React141__namespace.default.useCallback(() => {
|
|
32623
|
-
setAnimatedDatasetKey((currentValue) => currentValue === effectiveDatasetKey ? currentValue : effectiveDatasetKey);
|
|
32624
|
-
}, [effectiveDatasetKey]);
|
|
32625
32687
|
const finalData = displayData;
|
|
32626
|
-
React141__namespace.default.useEffect(() => {
|
|
32627
|
-
const containerNode = containerRef.current;
|
|
32628
|
-
if (!containerNode) {
|
|
32629
|
-
setContainerReady(true);
|
|
32630
|
-
return void 0;
|
|
32631
|
-
}
|
|
32632
|
-
let frameId = null;
|
|
32633
|
-
let resizeObserver = null;
|
|
32634
|
-
const checkContainerDimensions = () => {
|
|
32635
|
-
const rect = containerNode.getBoundingClientRect();
|
|
32636
|
-
const isReady = rect.width > 0 && rect.height > 0;
|
|
32637
|
-
if (isReady) {
|
|
32638
|
-
setContainerReady(true);
|
|
32639
|
-
}
|
|
32640
|
-
return isReady;
|
|
32641
|
-
};
|
|
32642
|
-
if (checkContainerDimensions()) {
|
|
32643
|
-
return void 0;
|
|
32644
|
-
}
|
|
32645
|
-
frameId = window.requestAnimationFrame(() => {
|
|
32646
|
-
checkContainerDimensions();
|
|
32647
|
-
});
|
|
32648
|
-
if (typeof ResizeObserver !== "undefined") {
|
|
32649
|
-
resizeObserver = new ResizeObserver(() => {
|
|
32650
|
-
if (checkContainerDimensions() && resizeObserver) {
|
|
32651
|
-
resizeObserver.disconnect();
|
|
32652
|
-
resizeObserver = null;
|
|
32653
|
-
}
|
|
32654
|
-
});
|
|
32655
|
-
resizeObserver.observe(containerNode);
|
|
32656
|
-
} else {
|
|
32657
|
-
setContainerReady(true);
|
|
32658
|
-
}
|
|
32659
|
-
return () => {
|
|
32660
|
-
if (frameId !== null) {
|
|
32661
|
-
window.cancelAnimationFrame(frameId);
|
|
32662
|
-
}
|
|
32663
|
-
resizeObserver?.disconnect();
|
|
32664
|
-
};
|
|
32665
|
-
}, []);
|
|
32666
32688
|
const labelInterval = React141__namespace.default.useMemo(() => {
|
|
32667
32689
|
if (xAxisMode === "hourly") {
|
|
32668
32690
|
return Math.max(1, Math.ceil(DURATION / 8));
|
|
@@ -32870,144 +32892,154 @@ var CycleTimeOverTimeChart = ({
|
|
|
32870
32892
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
32871
32893
|
"div",
|
|
32872
32894
|
{
|
|
32873
|
-
ref: containerRef,
|
|
32874
32895
|
className: `w-full h-full min-w-0 flex flex-col relative pb-2 ${className}`,
|
|
32875
32896
|
style: { minHeight: "200px", minWidth: 0 },
|
|
32876
32897
|
children: [
|
|
32877
32898
|
renderLegend(),
|
|
32878
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-h-0 w-full",
|
|
32879
|
-
|
|
32899
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-h-0 w-full", ref: containerRef, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
32900
|
+
motion.div,
|
|
32880
32901
|
{
|
|
32881
|
-
|
|
32882
|
-
|
|
32883
|
-
|
|
32884
|
-
|
|
32885
|
-
|
|
32886
|
-
|
|
32887
|
-
|
|
32888
|
-
|
|
32889
|
-
|
|
32890
|
-
|
|
32891
|
-
|
|
32892
|
-
|
|
32893
|
-
|
|
32894
|
-
|
|
32895
|
-
|
|
32896
|
-
angle: xAxisMode === "hourly" ? 0 : -30,
|
|
32897
|
-
textAnchor: xAxisMode === "hourly" ? "middle" : "end",
|
|
32898
|
-
tickMargin: xAxisMode === "hourly" ? 8 : 15,
|
|
32899
|
-
height: xAxisMode === "hourly" ? 40 : 60
|
|
32900
|
-
}
|
|
32901
|
-
),
|
|
32902
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
32903
|
-
recharts.YAxis,
|
|
32904
|
-
{
|
|
32905
|
-
tickMargin: 8,
|
|
32906
|
-
width: 45,
|
|
32907
|
-
yAxisId: "cycle",
|
|
32908
|
-
domain: ["auto", "auto"],
|
|
32909
|
-
ticks: [0, idealCycleTime, ...Array.from({ length: 4 }, (_, i) => (i + 1) * Math.ceil(idealCycleTime / 2))].sort((a, b) => a - b),
|
|
32910
|
-
tickFormatter: (value) => String(value),
|
|
32911
|
-
tick: (props) => {
|
|
32912
|
-
const { x, y, payload } = props;
|
|
32913
|
-
const displayValue = typeof payload.value === "number" ? payload.value.toFixed(1) : String(payload.value);
|
|
32914
|
-
return /* @__PURE__ */ jsxRuntime.jsx("g", { transform: `translate(${x},${y})`, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
32915
|
-
"text",
|
|
32916
|
-
{
|
|
32917
|
-
x: 0,
|
|
32918
|
-
y: 0,
|
|
32919
|
-
dy: 4,
|
|
32920
|
-
textAnchor: "end",
|
|
32921
|
-
fill: payload.value === idealCycleTime ? "#E34329" : "#666",
|
|
32922
|
-
fontSize: 12,
|
|
32923
|
-
fontWeight: payload.value === idealCycleTime ? "bold" : "normal",
|
|
32924
|
-
children: displayValue
|
|
32925
|
-
},
|
|
32926
|
-
`tick-${payload.value}-${x}-${y}`
|
|
32927
|
-
) });
|
|
32928
|
-
}
|
|
32929
|
-
}
|
|
32930
|
-
),
|
|
32931
|
-
showIdleTime && /* @__PURE__ */ jsxRuntime.jsx(
|
|
32932
|
-
recharts.YAxis,
|
|
32933
|
-
{
|
|
32934
|
-
yAxisId: "idle",
|
|
32935
|
-
orientation: "right",
|
|
32936
|
-
tickMargin: 8,
|
|
32937
|
-
width: 35,
|
|
32938
|
-
domain: [0, 60],
|
|
32939
|
-
tickFormatter: (value) => `${value}m`,
|
|
32940
|
-
tick: { fontSize: 11, fill: "#f59e0b" },
|
|
32941
|
-
axisLine: false,
|
|
32942
|
-
tickLine: false
|
|
32943
|
-
}
|
|
32944
|
-
),
|
|
32945
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
32946
|
-
recharts.Tooltip,
|
|
32947
|
-
{
|
|
32948
|
-
cursor: { stroke: "#E5E7EB", strokeWidth: 1 },
|
|
32949
|
-
content: renderChartTooltip,
|
|
32950
|
-
animationDuration: 200
|
|
32951
|
-
}
|
|
32952
|
-
),
|
|
32953
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
32954
|
-
recharts.ReferenceLine,
|
|
32955
|
-
{
|
|
32956
|
-
y: idealCycleTime,
|
|
32957
|
-
yAxisId: "cycle",
|
|
32958
|
-
stroke: "#E34329",
|
|
32959
|
-
strokeDasharray: "3 3",
|
|
32960
|
-
strokeWidth: 2,
|
|
32961
|
-
label: {
|
|
32962
|
-
position: "right",
|
|
32963
|
-
value: `${idealCycleTime.toFixed(1)}s`,
|
|
32964
|
-
fill: "#E34329",
|
|
32965
|
-
fontSize: 12,
|
|
32966
|
-
fontWeight: 500
|
|
32967
|
-
}
|
|
32968
|
-
}
|
|
32969
|
-
),
|
|
32970
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
32971
|
-
recharts.Line,
|
|
32972
|
-
{
|
|
32973
|
-
type: "monotone",
|
|
32974
|
-
yAxisId: "cycle",
|
|
32975
|
-
dataKey: "cycleTime",
|
|
32976
|
-
stroke: "#3B82F6",
|
|
32977
|
-
strokeWidth: 2,
|
|
32978
|
-
connectNulls: false,
|
|
32979
|
-
dot: renderCycleDot,
|
|
32980
|
-
activeDot: renderCycleActiveDot,
|
|
32981
|
-
isAnimationActive: shouldAnimate,
|
|
32982
|
-
animationBegin: 0,
|
|
32983
|
-
animationDuration: 1200,
|
|
32984
|
-
animationEasing: "ease-out",
|
|
32985
|
-
onAnimationEnd: handleAnimationEnd
|
|
32986
|
-
},
|
|
32987
|
-
`${effectiveDatasetKey}:cycle`
|
|
32988
|
-
),
|
|
32989
|
-
showIdleTime && /* @__PURE__ */ jsxRuntime.jsx(
|
|
32990
|
-
recharts.Line,
|
|
32991
|
-
{
|
|
32992
|
-
type: "monotone",
|
|
32993
|
-
yAxisId: "idle",
|
|
32994
|
-
dataKey: "idleMinutes",
|
|
32995
|
-
stroke: "#f59e0b",
|
|
32996
|
-
strokeWidth: 2,
|
|
32997
|
-
strokeDasharray: "4 4",
|
|
32998
|
-
connectNulls: false,
|
|
32999
|
-
dot: renderIdleDot,
|
|
33000
|
-
activeDot: renderIdleActiveDot,
|
|
33001
|
-
isAnimationActive: shouldAnimate,
|
|
33002
|
-
animationBegin: 0,
|
|
33003
|
-
animationDuration: 1200,
|
|
33004
|
-
animationEasing: "ease-out"
|
|
32902
|
+
initial: { opacity: 0 },
|
|
32903
|
+
animate: { opacity: 1 },
|
|
32904
|
+
transition: { duration: 0.5 },
|
|
32905
|
+
className: "w-full h-full",
|
|
32906
|
+
children: dimensions.width > 0 && dimensions.height > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
32907
|
+
recharts.LineChart,
|
|
32908
|
+
{
|
|
32909
|
+
width: dimensions.width,
|
|
32910
|
+
height: dimensions.height,
|
|
32911
|
+
data: chartData,
|
|
32912
|
+
margin: {
|
|
32913
|
+
top: 5,
|
|
32914
|
+
right: 30,
|
|
32915
|
+
bottom: 25,
|
|
32916
|
+
left: 10
|
|
33005
32917
|
},
|
|
33006
|
-
|
|
33007
|
-
|
|
33008
|
-
|
|
32918
|
+
children: [
|
|
32919
|
+
/* @__PURE__ */ jsxRuntime.jsx(recharts.CartesianGrid, { strokeDasharray: "3 3", vertical: false }),
|
|
32920
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
32921
|
+
recharts.XAxis,
|
|
32922
|
+
{
|
|
32923
|
+
dataKey: "label",
|
|
32924
|
+
tick: { fontSize: 11 },
|
|
32925
|
+
interval: 0,
|
|
32926
|
+
angle: xAxisMode === "hourly" ? 0 : -30,
|
|
32927
|
+
textAnchor: xAxisMode === "hourly" ? "middle" : "end",
|
|
32928
|
+
tickMargin: xAxisMode === "hourly" ? 8 : 15,
|
|
32929
|
+
height: xAxisMode === "hourly" ? 40 : 60
|
|
32930
|
+
}
|
|
32931
|
+
),
|
|
32932
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
32933
|
+
recharts.YAxis,
|
|
32934
|
+
{
|
|
32935
|
+
tickMargin: 8,
|
|
32936
|
+
width: 45,
|
|
32937
|
+
yAxisId: "cycle",
|
|
32938
|
+
domain: ["auto", "auto"],
|
|
32939
|
+
ticks: [0, idealCycleTime, ...Array.from({ length: 4 }, (_, i) => (i + 1) * Math.ceil(idealCycleTime / 2))].sort((a, b) => a - b),
|
|
32940
|
+
tickFormatter: (value) => String(value),
|
|
32941
|
+
tick: (props) => {
|
|
32942
|
+
const { x, y, payload } = props;
|
|
32943
|
+
const displayValue = typeof payload.value === "number" ? payload.value.toFixed(1) : String(payload.value);
|
|
32944
|
+
return /* @__PURE__ */ jsxRuntime.jsx("g", { transform: `translate(${x},${y})`, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
32945
|
+
"text",
|
|
32946
|
+
{
|
|
32947
|
+
x: 0,
|
|
32948
|
+
y: 0,
|
|
32949
|
+
dy: 4,
|
|
32950
|
+
textAnchor: "end",
|
|
32951
|
+
fill: payload.value === idealCycleTime ? "#E34329" : "#666",
|
|
32952
|
+
fontSize: 12,
|
|
32953
|
+
fontWeight: payload.value === idealCycleTime ? "bold" : "normal",
|
|
32954
|
+
children: displayValue
|
|
32955
|
+
},
|
|
32956
|
+
`tick-${payload.value}-${x}-${y}`
|
|
32957
|
+
) });
|
|
32958
|
+
}
|
|
32959
|
+
}
|
|
32960
|
+
),
|
|
32961
|
+
showIdleTime && /* @__PURE__ */ jsxRuntime.jsx(
|
|
32962
|
+
recharts.YAxis,
|
|
32963
|
+
{
|
|
32964
|
+
yAxisId: "idle",
|
|
32965
|
+
orientation: "right",
|
|
32966
|
+
tickMargin: 8,
|
|
32967
|
+
width: 35,
|
|
32968
|
+
domain: [0, 60],
|
|
32969
|
+
tickFormatter: (value) => `${value}m`,
|
|
32970
|
+
tick: { fontSize: 11, fill: "#f59e0b" },
|
|
32971
|
+
axisLine: false,
|
|
32972
|
+
tickLine: false
|
|
32973
|
+
}
|
|
32974
|
+
),
|
|
32975
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
32976
|
+
recharts.Tooltip,
|
|
32977
|
+
{
|
|
32978
|
+
cursor: { stroke: "#E5E7EB", strokeWidth: 1 },
|
|
32979
|
+
content: renderChartTooltip,
|
|
32980
|
+
animationDuration: 200
|
|
32981
|
+
}
|
|
32982
|
+
),
|
|
32983
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
32984
|
+
recharts.ReferenceLine,
|
|
32985
|
+
{
|
|
32986
|
+
y: idealCycleTime,
|
|
32987
|
+
yAxisId: "cycle",
|
|
32988
|
+
stroke: "#E34329",
|
|
32989
|
+
strokeDasharray: "3 3",
|
|
32990
|
+
strokeWidth: 2,
|
|
32991
|
+
label: {
|
|
32992
|
+
position: "right",
|
|
32993
|
+
value: `${idealCycleTime.toFixed(1)}s`,
|
|
32994
|
+
fill: "#E34329",
|
|
32995
|
+
fontSize: 12,
|
|
32996
|
+
fontWeight: 500
|
|
32997
|
+
}
|
|
32998
|
+
}
|
|
32999
|
+
),
|
|
33000
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
33001
|
+
recharts.Line,
|
|
33002
|
+
{
|
|
33003
|
+
type: "monotone",
|
|
33004
|
+
yAxisId: "cycle",
|
|
33005
|
+
dataKey: "cycleTime",
|
|
33006
|
+
stroke: "#3B82F6",
|
|
33007
|
+
strokeWidth: 2,
|
|
33008
|
+
connectNulls: false,
|
|
33009
|
+
dot: renderCycleDot,
|
|
33010
|
+
activeDot: renderCycleActiveDot,
|
|
33011
|
+
isAnimationActive: true,
|
|
33012
|
+
animationBegin: 300,
|
|
33013
|
+
animationDuration: 1500,
|
|
33014
|
+
animationEasing: "ease-out"
|
|
33015
|
+
},
|
|
33016
|
+
`${effectiveDatasetKey}:cycle`
|
|
33017
|
+
),
|
|
33018
|
+
showIdleTime && /* @__PURE__ */ jsxRuntime.jsx(
|
|
33019
|
+
recharts.Line,
|
|
33020
|
+
{
|
|
33021
|
+
type: "monotone",
|
|
33022
|
+
yAxisId: "idle",
|
|
33023
|
+
dataKey: "idleMinutes",
|
|
33024
|
+
stroke: "#f59e0b",
|
|
33025
|
+
strokeWidth: 2,
|
|
33026
|
+
strokeDasharray: "4 4",
|
|
33027
|
+
connectNulls: false,
|
|
33028
|
+
dot: renderIdleDot,
|
|
33029
|
+
activeDot: renderIdleActiveDot,
|
|
33030
|
+
isAnimationActive: true,
|
|
33031
|
+
animationBegin: 300,
|
|
33032
|
+
animationDuration: 1500,
|
|
33033
|
+
animationEasing: "ease-out"
|
|
33034
|
+
},
|
|
33035
|
+
`${effectiveDatasetKey}:idle`
|
|
33036
|
+
)
|
|
33037
|
+
]
|
|
33038
|
+
},
|
|
33039
|
+
hasValidData ? "valid" : "empty"
|
|
33040
|
+
)
|
|
33009
33041
|
}
|
|
33010
|
-
) })
|
|
33042
|
+
) })
|
|
33011
33043
|
]
|
|
33012
33044
|
}
|
|
33013
33045
|
);
|
|
@@ -33857,10 +33889,10 @@ var HourlyOutputChart = React141__namespace.default.memo(HourlyOutputChartCompon
|
|
|
33857
33889
|
HourlyOutputChart.displayName = "HourlyOutputChart";
|
|
33858
33890
|
|
|
33859
33891
|
// src/components/dashboard/grid/videoGridMetricUtils.ts
|
|
33860
|
-
var VIDEO_GRID_LEGEND_LABEL = "
|
|
33892
|
+
var VIDEO_GRID_LEGEND_LABEL = "7 Minute Efficiency";
|
|
33861
33893
|
var MAP_GRID_LEGEND_LABEL = "Efficiency";
|
|
33862
|
-
var MIXED_VIDEO_GRID_LEGEND_LABEL = "
|
|
33863
|
-
var
|
|
33894
|
+
var MIXED_VIDEO_GRID_LEGEND_LABEL = "Efficiency";
|
|
33895
|
+
var isFiniteNumber = (value) => typeof value === "number" && Number.isFinite(value);
|
|
33864
33896
|
var isVideoGridRecentFlowEnabled = (workspace) => isRecentFlowVideoGridMetricMode(
|
|
33865
33897
|
workspace.video_grid_metric_mode,
|
|
33866
33898
|
workspace.assembly_enabled === true
|
|
@@ -33869,11 +33901,11 @@ var isVideoGridWipGated = (workspace) => isWipGatedVideoGridMetricMode(
|
|
|
33869
33901
|
workspace.video_grid_metric_mode,
|
|
33870
33902
|
workspace.assembly_enabled === true
|
|
33871
33903
|
);
|
|
33872
|
-
var hasVideoGridRecentFlow = (workspace) => isVideoGridRecentFlowEnabled(workspace) &&
|
|
33904
|
+
var hasVideoGridRecentFlow = (workspace) => isVideoGridRecentFlowEnabled(workspace) && isFiniteNumber(workspace.recent_flow_percent);
|
|
33873
33905
|
var isVideoGridRecentFlowUnavailable = (workspace) => isVideoGridRecentFlowEnabled(workspace) && !hasVideoGridRecentFlow(workspace);
|
|
33874
33906
|
var getVideoGridMetricValue = (workspace) => {
|
|
33875
33907
|
const recentFlowPercent = workspace.recent_flow_percent;
|
|
33876
|
-
if (hasVideoGridRecentFlow(workspace) &&
|
|
33908
|
+
if (hasVideoGridRecentFlow(workspace) && isFiniteNumber(recentFlowPercent)) {
|
|
33877
33909
|
return recentFlowPercent;
|
|
33878
33910
|
}
|
|
33879
33911
|
if (isVideoGridRecentFlowUnavailable(workspace)) {
|
|
@@ -33884,7 +33916,7 @@ var getVideoGridMetricValue = (workspace) => {
|
|
|
33884
33916
|
var hasIncomingWipMapping = (workspace) => Boolean(workspace.incoming_wip_buffer_name);
|
|
33885
33917
|
var getVideoGridBaseColorState = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => {
|
|
33886
33918
|
const metricValue = getVideoGridMetricValue(workspace);
|
|
33887
|
-
if (!
|
|
33919
|
+
if (!isFiniteNumber(metricValue)) {
|
|
33888
33920
|
return "neutral";
|
|
33889
33921
|
}
|
|
33890
33922
|
return getEfficiencyColor(metricValue, legend);
|
|
@@ -33899,7 +33931,7 @@ var isLowWipGreenOverride = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => {
|
|
|
33899
33931
|
if (!hasIncomingWipMapping(workspace)) {
|
|
33900
33932
|
return false;
|
|
33901
33933
|
}
|
|
33902
|
-
return
|
|
33934
|
+
return isFiniteNumber(workspace.incoming_wip_current) && workspace.incoming_wip_current <= 1;
|
|
33903
33935
|
};
|
|
33904
33936
|
var toMinuteBucket = (minuteBucket) => Number.isFinite(minuteBucket) ? Math.floor(minuteBucket) : Math.floor(Date.now() / 6e4);
|
|
33905
33937
|
var getEffectiveFlowMinuteBucket = (workspace) => {
|
|
@@ -33941,7 +33973,7 @@ var getVideoGridColorState = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) =>
|
|
|
33941
33973
|
if (!hasIncomingWipMapping(workspace)) {
|
|
33942
33974
|
return baseColor;
|
|
33943
33975
|
}
|
|
33944
|
-
if (!
|
|
33976
|
+
if (!isFiniteNumber(workspace.incoming_wip_current)) {
|
|
33945
33977
|
return "neutral";
|
|
33946
33978
|
}
|
|
33947
33979
|
if (isLowWipGreenOverride(workspace, legend)) {
|
|
@@ -34011,8 +34043,9 @@ var VideoCard = React141__namespace.default.memo(({
|
|
|
34011
34043
|
const isRecentFlowCard = isVideoGridRecentFlowEnabled(workspace);
|
|
34012
34044
|
const hasDisplayMetric = typeof videoGridDisplayValue === "number" && Number.isFinite(videoGridDisplayValue);
|
|
34013
34045
|
const hasBarMetric = typeof videoGridMetricValue === "number" && Number.isFinite(videoGridMetricValue);
|
|
34046
|
+
const shouldRenderMetricBadge = hasDisplayMetric;
|
|
34014
34047
|
const badgeTitle = hasVideoGridRecentFlow(workspace) ? `Flow ${Math.round(videoGridDisplayValue ?? 0)}%` : isRecentFlowCard ? "Flow unavailable" : `Efficiency ${Math.round(videoGridDisplayValue ?? 0)}%`;
|
|
34015
|
-
const badgeLabel =
|
|
34048
|
+
const badgeLabel = `${Math.round(videoGridDisplayValue ?? 0)}%`;
|
|
34016
34049
|
const efficiencyOverlayClass = videoGridColorState === "green" ? "bg-[#00D654]/25" : videoGridColorState === "yellow" ? "bg-[#FFD700]/30" : videoGridColorState === "red" ? "bg-[#FF2D0A]/30" : "bg-transparent";
|
|
34017
34050
|
const efficiencyBarClass = videoGridColorState === "green" ? "bg-[#00AB45]" : videoGridColorState === "yellow" ? "bg-[#FFB020]" : videoGridColorState === "red" ? "bg-[#E34329]" : "bg-gray-500/70";
|
|
34018
34051
|
const efficiencyStatus = videoGridColorState === "green" ? "High" : videoGridColorState === "yellow" ? "Medium" : videoGridColorState === "red" ? "Low" : "Neutral";
|
|
@@ -34088,7 +34121,7 @@ var VideoCard = React141__namespace.default.memo(({
|
|
|
34088
34121
|
lastSeenText
|
|
34089
34122
|
] })
|
|
34090
34123
|
] }) }),
|
|
34091
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `absolute ${compact ? "top-1 right-1" : "top-2 right-2"} z-30`, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
34124
|
+
shouldRenderMetricBadge && /* @__PURE__ */ jsxRuntime.jsx("div", { className: `absolute ${compact ? "top-1 right-1" : "top-2 right-2"} z-30`, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
34092
34125
|
"div",
|
|
34093
34126
|
{
|
|
34094
34127
|
"data-testid": "video-card-metric-badge",
|
|
@@ -34133,7 +34166,7 @@ var VideoCard = React141__namespace.default.memo(({
|
|
|
34133
34166
|
}
|
|
34134
34167
|
);
|
|
34135
34168
|
}, (prevProps, nextProps) => {
|
|
34136
|
-
if (prevProps.workspace.efficiency !== nextProps.workspace.efficiency || prevProps.workspace.assembly_enabled !== nextProps.workspace.assembly_enabled || prevProps.workspace.video_grid_metric_mode !== nextProps.workspace.video_grid_metric_mode || prevProps.workspace.
|
|
34169
|
+
if (prevProps.workspace.efficiency !== nextProps.workspace.efficiency || prevProps.workspace.assembly_enabled !== nextProps.workspace.assembly_enabled || prevProps.workspace.video_grid_metric_mode !== nextProps.workspace.video_grid_metric_mode || prevProps.workspace.recent_flow_percent !== nextProps.workspace.recent_flow_percent || prevProps.workspace.recent_flow_effective_end_at !== nextProps.workspace.recent_flow_effective_end_at || prevProps.workspace.incoming_wip_current !== nextProps.workspace.incoming_wip_current || prevProps.workspace.incoming_wip_buffer_name !== nextProps.workspace.incoming_wip_buffer_name || prevProps.workspace.trend !== nextProps.workspace.trend || prevProps.workspace.performance_score !== nextProps.workspace.performance_score || prevProps.workspace.pph !== nextProps.workspace.pph) {
|
|
34137
34170
|
return false;
|
|
34138
34171
|
}
|
|
34139
34172
|
if (prevProps.workspace.workspace_uuid !== nextProps.workspace.workspace_uuid || prevProps.workspace.workspace_name !== nextProps.workspace.workspace_name || prevProps.workspace.line_id !== nextProps.workspace.line_id) {
|
|
@@ -44601,7 +44634,7 @@ var ShiftDisplay = React141.memo(({ className, variant = "default", lineId }) =>
|
|
|
44601
44634
|
return null;
|
|
44602
44635
|
}
|
|
44603
44636
|
};
|
|
44604
|
-
const
|
|
44637
|
+
const getShiftIcon2 = (shift) => {
|
|
44605
44638
|
if (shift === "Day") {
|
|
44606
44639
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsxRuntime.jsx("path", { fillRule: "evenodd", d: "M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z", clipRule: "evenodd" }) });
|
|
44607
44640
|
} else {
|
|
@@ -44627,7 +44660,7 @@ var ShiftDisplay = React141.memo(({ className, variant = "default", lineId }) =>
|
|
|
44627
44660
|
}
|
|
44628
44661
|
if (variant === "enhanced") {
|
|
44629
44662
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `inline-flex items-center gap-2 bg-blue-50 rounded-lg px-3 py-1.5 ${className ?? ""}`, children: [
|
|
44630
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-800", children:
|
|
44663
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-800", children: getShiftIcon2(currentShiftText) }),
|
|
44631
44664
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-base font-medium text-blue-800", children: [
|
|
44632
44665
|
currentShiftText,
|
|
44633
44666
|
" Shift"
|
|
@@ -44635,7 +44668,7 @@ var ShiftDisplay = React141.memo(({ className, variant = "default", lineId }) =>
|
|
|
44635
44668
|
] });
|
|
44636
44669
|
}
|
|
44637
44670
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `inline-flex items-center gap-2 bg-blue-50 rounded-lg px-3 py-1.5 ${className ?? ""}`, children: [
|
|
44638
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-800", children:
|
|
44671
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-800", children: getShiftIcon2(currentShiftText) }),
|
|
44639
44672
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-base font-medium text-blue-800", children: [
|
|
44640
44673
|
currentShiftText,
|
|
44641
44674
|
" Shift"
|
|
@@ -47272,7 +47305,7 @@ var LinePdfGenerator = ({
|
|
|
47272
47305
|
doc.setLineWidth(0.8);
|
|
47273
47306
|
doc.line(20, 123, 190, 123);
|
|
47274
47307
|
const hourlyOverviewStartY = 128;
|
|
47275
|
-
const
|
|
47308
|
+
const parseTimeToMinutes4 = (timeStr) => {
|
|
47276
47309
|
const [hours, minutes] = timeStr.split(":");
|
|
47277
47310
|
const hour = parseInt(hours, 10);
|
|
47278
47311
|
const minute = parseInt(minutes || "0", 10);
|
|
@@ -47305,7 +47338,7 @@ var LinePdfGenerator = ({
|
|
|
47305
47338
|
};
|
|
47306
47339
|
};
|
|
47307
47340
|
const getHourlyTimeRanges = (startTimeStr, endTimeStr) => {
|
|
47308
|
-
const startMinutes =
|
|
47341
|
+
const startMinutes = parseTimeToMinutes4(startTimeStr);
|
|
47309
47342
|
if (Number.isNaN(startMinutes)) {
|
|
47310
47343
|
return [];
|
|
47311
47344
|
}
|
|
@@ -47313,7 +47346,7 @@ var LinePdfGenerator = ({
|
|
|
47313
47346
|
const defaultHours = 11;
|
|
47314
47347
|
return Array.from({ length: defaultHours }, (_, i) => buildRange(startMinutes + i * 60, 60));
|
|
47315
47348
|
}
|
|
47316
|
-
const endMinutes =
|
|
47349
|
+
const endMinutes = parseTimeToMinutes4(endTimeStr);
|
|
47317
47350
|
if (Number.isNaN(endMinutes)) {
|
|
47318
47351
|
const fallbackHours = 11;
|
|
47319
47352
|
return Array.from({ length: fallbackHours }, (_, i) => buildRange(startMinutes + i * 60, 60));
|
|
@@ -49082,7 +49115,7 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
|
|
|
49082
49115
|
minute: "2-digit",
|
|
49083
49116
|
hour12: true
|
|
49084
49117
|
});
|
|
49085
|
-
const
|
|
49118
|
+
const parseTimeToMinutes4 = (timeValue) => {
|
|
49086
49119
|
const [hourPart, minutePart] = timeValue.split(":").map(Number);
|
|
49087
49120
|
const hour = Number.isFinite(hourPart) ? hourPart : 0;
|
|
49088
49121
|
const minute = Number.isFinite(minutePart) ? minutePart : 0;
|
|
@@ -49099,8 +49132,8 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
|
|
|
49099
49132
|
const IST_OFFSET_MINUTES = 330;
|
|
49100
49133
|
return Date.UTC(year, month - 1, day, hour, minute) - IST_OFFSET_MINUTES * 60 * 1e3;
|
|
49101
49134
|
};
|
|
49102
|
-
const shiftStartMinutes =
|
|
49103
|
-
const shiftEndMinutes =
|
|
49135
|
+
const shiftStartMinutes = parseTimeToMinutes4(workspace.shift_start);
|
|
49136
|
+
const shiftEndMinutes = parseTimeToMinutes4(workspace.shift_end);
|
|
49104
49137
|
const wrapsMidnight = shiftEndMinutes <= shiftStartMinutes;
|
|
49105
49138
|
const shiftStartUtcMs = toShiftUtcMs(workspace.date, workspace.shift_start);
|
|
49106
49139
|
const shiftEndUtcMs = toShiftUtcMs(workspace.date, workspace.shift_end) + (wrapsMidnight ? 24 * 60 * 60 * 1e3 : 0);
|
|
@@ -49815,8 +49848,7 @@ var WorkspaceCycleTimeMetricCards = ({
|
|
|
49815
49848
|
{
|
|
49816
49849
|
data: idleTimeData.chartData,
|
|
49817
49850
|
isLoading: idleTimeData.isLoading,
|
|
49818
|
-
error: idleTimeData.error
|
|
49819
|
-
variant: "bar"
|
|
49851
|
+
error: idleTimeData.error
|
|
49820
49852
|
}
|
|
49821
49853
|
) })
|
|
49822
49854
|
] })
|
|
@@ -51407,7 +51439,7 @@ var DashboardHeader = React141.memo(({ lineTitle, className = "", headerControls
|
|
|
51407
51439
|
const rawName = currentShift.shiftName || "Day";
|
|
51408
51440
|
return rawName.toLowerCase().includes("shift") ? rawName : `${rawName} Shift`;
|
|
51409
51441
|
};
|
|
51410
|
-
const
|
|
51442
|
+
const getShiftIcon2 = () => {
|
|
51411
51443
|
const currentShift = getCurrentShift(timezone, shiftConfig);
|
|
51412
51444
|
const shiftName = (currentShift.shiftName || "").toLowerCase();
|
|
51413
51445
|
if (shiftName.includes("day") || shiftName.includes("morning") || currentShift.shiftId === 0) {
|
|
@@ -51441,7 +51473,7 @@ var DashboardHeader = React141.memo(({ lineTitle, className = "", headerControls
|
|
|
51441
51473
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: /* @__PURE__ */ jsxRuntime.jsx(Timer2, {}) }),
|
|
51442
51474
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-300", children: "|" }),
|
|
51443
51475
|
isShiftConfigLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3.5 w-16 bg-gray-200 rounded animate-pulse" }) : /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 font-medium", children: [
|
|
51444
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-75", children:
|
|
51476
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-75", children: getShiftIcon2() }),
|
|
51445
51477
|
getShiftName()
|
|
51446
51478
|
] })
|
|
51447
51479
|
] })
|
|
@@ -51458,7 +51490,7 @@ var DashboardHeader = React141.memo(({ lineTitle, className = "", headerControls
|
|
|
51458
51490
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 inline-flex flex-wrap items-center gap-3", children: [
|
|
51459
51491
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs md:text-sm font-medium text-gray-600 whitespace-nowrap", children: /* @__PURE__ */ jsxRuntime.jsx(Timer2, {}) }),
|
|
51460
51492
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center gap-1", children: isShiftConfigLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 w-20 bg-gray-200 rounded animate-pulse" }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
51461
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-600", children:
|
|
51493
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-600", children: getShiftIcon2() }),
|
|
51462
51494
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs md:text-sm font-medium text-gray-600 whitespace-nowrap", children: getShiftName() })
|
|
51463
51495
|
] }) })
|
|
51464
51496
|
] })
|
|
@@ -58429,7 +58461,7 @@ var FactoryView = ({
|
|
|
58429
58461
|
const currentShift = getCurrentShiftInfo();
|
|
58430
58462
|
return (currentShift.shiftName || "Day").replace(/ Shift$/i, "");
|
|
58431
58463
|
};
|
|
58432
|
-
const
|
|
58464
|
+
const getShiftIcon2 = () => {
|
|
58433
58465
|
const currentShift = getCurrentShiftInfo();
|
|
58434
58466
|
const shiftNameLower = (currentShift.shiftName || "").toLowerCase();
|
|
58435
58467
|
if (shiftNameLower.includes("day") || shiftNameLower.includes("morning") || currentShift.shiftId === 0) {
|
|
@@ -58475,7 +58507,7 @@ var FactoryView = ({
|
|
|
58475
58507
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex items-center justify-center gap-2", children: [
|
|
58476
58508
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-gray-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: /* @__PURE__ */ jsxRuntime.jsx(ISTTimer_default, {}) }) }),
|
|
58477
58509
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
|
|
58478
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children:
|
|
58510
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon2() }),
|
|
58479
58511
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs font-medium text-gray-700", children: [
|
|
58480
58512
|
getShiftName(),
|
|
58481
58513
|
" Shift"
|
|
@@ -58494,7 +58526,7 @@ var FactoryView = ({
|
|
|
58494
58526
|
" IST"
|
|
58495
58527
|
] }),
|
|
58496
58528
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-1", children: [
|
|
58497
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-600", children:
|
|
58529
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-600", children: getShiftIcon2() }),
|
|
58498
58530
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm font-medium text-gray-600", children: [
|
|
58499
58531
|
getShiftName(),
|
|
58500
58532
|
" Shift"
|
|
@@ -61206,7 +61238,7 @@ var KPIDetailView = ({
|
|
|
61206
61238
|
const getShiftName = React141.useCallback((shiftId) => {
|
|
61207
61239
|
return getShiftNameById(shiftId, configuredTimezone, shiftConfig);
|
|
61208
61240
|
}, [configuredTimezone, shiftConfig]);
|
|
61209
|
-
const
|
|
61241
|
+
const getShiftIcon2 = React141.useCallback((shiftId) => {
|
|
61210
61242
|
if (shiftId === 0) {
|
|
61211
61243
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
|
|
61212
61244
|
}
|
|
@@ -62086,7 +62118,7 @@ var KPIDetailView = ({
|
|
|
62086
62118
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sm:hidden mt-3 flex items-center justify-center gap-2", children: [
|
|
62087
62119
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-gray-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: chartMetrics && formatLocalDate(new Date(chartMetrics.date)) }) }),
|
|
62088
62120
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
|
|
62089
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children:
|
|
62121
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon2(chartMetrics.shift_id ?? 0) }),
|
|
62090
62122
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs font-medium text-gray-700", children: [
|
|
62091
62123
|
getShiftName(chartMetrics.shift_id ?? 0).replace(/ Shift$/i, ""),
|
|
62092
62124
|
" Shift"
|
|
@@ -62112,7 +62144,7 @@ var KPIDetailView = ({
|
|
|
62112
62144
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-200" })
|
|
62113
62145
|
] }),
|
|
62114
62146
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
|
|
62115
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "opacity-70", children:
|
|
62147
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "opacity-70", children: getShiftIcon2(chartMetrics.shift_id ?? 0) }),
|
|
62116
62148
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm md:text-base font-semibold uppercase tracking-wider", children: [
|
|
62117
62149
|
getShiftName(chartMetrics.shift_id ?? 0).replace(/ Shift$/i, ""),
|
|
62118
62150
|
" Shift"
|
|
@@ -62130,7 +62162,7 @@ var KPIDetailView = ({
|
|
|
62130
62162
|
return `${startDate.toLocaleDateString("en-US", { month: "short", day: "numeric" })} - ${endDate.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })}`;
|
|
62131
62163
|
})() }) }),
|
|
62132
62164
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
|
|
62133
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children:
|
|
62165
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon2(selectedShiftId) }),
|
|
62134
62166
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: getShiftName(selectedShiftId) })
|
|
62135
62167
|
] })
|
|
62136
62168
|
] }),
|
|
@@ -62147,7 +62179,7 @@ var KPIDetailView = ({
|
|
|
62147
62179
|
] }),
|
|
62148
62180
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-200" }),
|
|
62149
62181
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
|
|
62150
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "opacity-70", children:
|
|
62182
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "opacity-70", children: getShiftIcon2(selectedShiftId) }),
|
|
62151
62183
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm md:text-base font-semibold uppercase tracking-wider", children: [
|
|
62152
62184
|
getShiftName(selectedShiftId).replace(/ Shift$/i, ""),
|
|
62153
62185
|
" Shift"
|
|
@@ -63523,7 +63555,7 @@ var KPIsOverviewView = ({
|
|
|
63523
63555
|
const headerShiftId = showHistoricalLeaderboardHeader ? effectiveLeaderboardShiftId : currentShiftDetails.shiftId;
|
|
63524
63556
|
const headerShiftName = getShiftNameById(headerShiftId, configuredTimezone, shiftConfig).replace(/ Shift$/i, "");
|
|
63525
63557
|
const headerDateLabel = isMonthlyMode ? getMonthRange() : formatLocalDate2(headerDateKey);
|
|
63526
|
-
const
|
|
63558
|
+
const getShiftIcon2 = (shiftId) => {
|
|
63527
63559
|
const shiftNameLower = getShiftNameById(shiftId, configuredTimezone, shiftConfig).toLowerCase();
|
|
63528
63560
|
if (shiftNameLower.includes("day") || shiftNameLower.includes("morning") || shiftId === 0) {
|
|
63529
63561
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
|
|
@@ -63640,7 +63672,7 @@ var KPIsOverviewView = ({
|
|
|
63640
63672
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `inline-flex items-center bg-gray-100 rounded-full ${isMonthlyMode ? "px-4 py-1.5 ring-1 ring-gray-200 shadow-sm" : "px-2.5 py-1"}`, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: `font-medium text-gray-700 ${isMonthlyMode ? "text-sm" : "text-xs"}`, children: headerDateLabel }) }),
|
|
63641
63673
|
!isMonthlyMode && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
63642
63674
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
|
|
63643
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children:
|
|
63675
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon2(headerShiftId) }),
|
|
63644
63676
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: headerShiftName })
|
|
63645
63677
|
] }),
|
|
63646
63678
|
showHistoricalLeaderboardHeader ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-amber-50 text-amber-700 rounded-full", children: [
|
|
@@ -63836,7 +63868,7 @@ var KPIsOverviewView = ({
|
|
|
63836
63868
|
!isMonthlyMode && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
63837
63869
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-200" }),
|
|
63838
63870
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
|
|
63839
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "opacity-70", children:
|
|
63871
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "opacity-70", children: getShiftIcon2(headerShiftId) }),
|
|
63840
63872
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm font-semibold uppercase tracking-wider", children: [
|
|
63841
63873
|
headerShiftName,
|
|
63842
63874
|
" Shift"
|
|
@@ -63980,6 +64012,52 @@ var KPIsOverviewView = ({
|
|
|
63980
64012
|
] });
|
|
63981
64013
|
};
|
|
63982
64014
|
var KPIsOverviewView_default = KPIsOverviewView;
|
|
64015
|
+
var toFiniteNumber = (value) => {
|
|
64016
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
64017
|
+
if (typeof value === "string" && value.trim() !== "") {
|
|
64018
|
+
const parsed = Number(value);
|
|
64019
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
64020
|
+
}
|
|
64021
|
+
return null;
|
|
64022
|
+
};
|
|
64023
|
+
var getCycleRatio = (workspace) => {
|
|
64024
|
+
const idealCycleTime = toFiniteNumber(workspace.ideal_cycle_time);
|
|
64025
|
+
const avgCycleTime = toFiniteNumber(workspace.avg_cycle_time);
|
|
64026
|
+
if (idealCycleTime === null || avgCycleTime === null || idealCycleTime <= 0 || avgCycleTime <= 0) {
|
|
64027
|
+
return null;
|
|
64028
|
+
}
|
|
64029
|
+
return idealCycleTime / avgCycleTime;
|
|
64030
|
+
};
|
|
64031
|
+
var formatCycleTimeValue = (value) => {
|
|
64032
|
+
const numericValue = toFiniteNumber(value);
|
|
64033
|
+
if (numericValue === null || numericValue <= 0) return "--";
|
|
64034
|
+
return `${numericValue.toFixed(1)}s`;
|
|
64035
|
+
};
|
|
64036
|
+
var CycleTimeComparison = React141.memo(({
|
|
64037
|
+
workspace,
|
|
64038
|
+
variant = "table"
|
|
64039
|
+
}) => {
|
|
64040
|
+
const averageValue = formatCycleTimeValue(workspace.avg_cycle_time);
|
|
64041
|
+
const standardValue = formatCycleTimeValue(workspace.ideal_cycle_time);
|
|
64042
|
+
if (variant === "mobile") {
|
|
64043
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex items-center justify-between py-2 border-t border-gray-100", children: [
|
|
64044
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-500 uppercase tracking-wider", children: "Standard Cycle Time" }),
|
|
64045
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium tabular-nums text-gray-500", children: standardValue })
|
|
64046
|
+
] });
|
|
64047
|
+
}
|
|
64048
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
64049
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
|
|
64050
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-medium uppercase tracking-wider text-gray-500", children: "Average" }),
|
|
64051
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold tabular-nums text-gray-900", children: averageValue })
|
|
64052
|
+
] }),
|
|
64053
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-6 w-px bg-gray-200" }),
|
|
64054
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
|
|
64055
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-medium uppercase tracking-wider text-gray-500", children: "Standard" }),
|
|
64056
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium tabular-nums text-gray-500", children: standardValue })
|
|
64057
|
+
] })
|
|
64058
|
+
] });
|
|
64059
|
+
}, (prevProps, nextProps) => prevProps.variant === nextProps.variant && prevProps.workspace.avg_cycle_time === nextProps.workspace.avg_cycle_time && prevProps.workspace.ideal_cycle_time === nextProps.workspace.ideal_cycle_time);
|
|
64060
|
+
CycleTimeComparison.displayName = "CycleTimeComparison";
|
|
63983
64061
|
var IsolatedTimer = React141.memo(() => {
|
|
63984
64062
|
return /* @__PURE__ */ jsxRuntime.jsx(ISTTimer_default, {});
|
|
63985
64063
|
});
|
|
@@ -63997,11 +64075,11 @@ var HeaderRibbon = React141.memo(({
|
|
|
63997
64075
|
currentDate,
|
|
63998
64076
|
currentMobileDate,
|
|
63999
64077
|
shiftId,
|
|
64000
|
-
getShiftIcon,
|
|
64078
|
+
getShiftIcon: getShiftIcon2,
|
|
64001
64079
|
getShiftName,
|
|
64002
64080
|
showTimer = true
|
|
64003
64081
|
}) => {
|
|
64004
|
-
const shiftIcon = React141.useMemo(() =>
|
|
64082
|
+
const shiftIcon = React141.useMemo(() => getShiftIcon2(shiftId), [getShiftIcon2, shiftId]);
|
|
64005
64083
|
const shiftName = React141.useMemo(() => getShiftName(shiftId), [getShiftName, shiftId]);
|
|
64006
64084
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
64007
64085
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sm:hidden mt-3 flex items-center justify-center gap-2", children: [
|
|
@@ -64043,8 +64121,9 @@ var MobileWorkspaceCard = React141.memo(({
|
|
|
64043
64121
|
isClickable,
|
|
64044
64122
|
onWorkspaceClick,
|
|
64045
64123
|
getMedalIcon,
|
|
64046
|
-
|
|
64047
|
-
|
|
64124
|
+
metricLabel,
|
|
64125
|
+
isAssemblyMode
|
|
64126
|
+
}) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
64048
64127
|
motion.div,
|
|
64049
64128
|
{
|
|
64050
64129
|
layout: true,
|
|
@@ -64055,28 +64134,31 @@ var MobileWorkspaceCard = React141.memo(({
|
|
|
64055
64134
|
},
|
|
64056
64135
|
onClick: isClickable ? () => onWorkspaceClick(workspace, rank) : void 0,
|
|
64057
64136
|
className: `${cardClass} p-3 rounded-lg border shadow-sm active:scale-[0.98] ${isClickable ? "cursor-pointer" : "cursor-not-allowed opacity-75"}`,
|
|
64058
|
-
children:
|
|
64059
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
64060
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-
|
|
64061
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "
|
|
64062
|
-
"
|
|
64063
|
-
|
|
64137
|
+
children: [
|
|
64138
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-2 gap-3", children: [
|
|
64139
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
64140
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
64141
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-2xl font-bold text-gray-700", children: [
|
|
64142
|
+
"#",
|
|
64143
|
+
rank
|
|
64144
|
+
] }),
|
|
64145
|
+
getMedalIcon(rank)
|
|
64064
64146
|
] }),
|
|
64065
|
-
|
|
64147
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
64148
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-semibold text-gray-900", children: workspace.displayName }),
|
|
64149
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-gray-500", children: workspace.lineName })
|
|
64150
|
+
] })
|
|
64066
64151
|
] }),
|
|
64067
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
64068
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-
|
|
64069
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-gray-500", children:
|
|
64152
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-right", children: [
|
|
64153
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-bold text-gray-900 text-lg", children: isAssemblyMode ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums", children: formatCycleTimeValue(workspace.avg_cycle_time) }) : /* @__PURE__ */ jsxRuntime.jsx(AnimatedEfficiency, { value: workspace.efficiency || 0 }) }),
|
|
64154
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-gray-500", children: metricLabel })
|
|
64070
64155
|
] })
|
|
64071
64156
|
] }),
|
|
64072
|
-
/* @__PURE__ */ jsxRuntime.
|
|
64073
|
-
|
|
64074
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-gray-500", children: efficiencyLabel })
|
|
64075
|
-
] })
|
|
64076
|
-
] })
|
|
64157
|
+
isAssemblyMode && /* @__PURE__ */ jsxRuntime.jsx(CycleTimeComparison, { workspace, variant: "mobile" })
|
|
64158
|
+
]
|
|
64077
64159
|
}
|
|
64078
64160
|
), (prevProps, nextProps) => {
|
|
64079
|
-
return prevProps.
|
|
64161
|
+
return prevProps.metricLabel === nextProps.metricLabel && prevProps.isAssemblyMode === nextProps.isAssemblyMode && prevProps.rank === nextProps.rank && prevProps.cardClass === nextProps.cardClass && prevProps.isClickable === nextProps.isClickable && prevProps.workspace.workspace_uuid === nextProps.workspace.workspace_uuid && prevProps.workspace.efficiency === nextProps.workspace.efficiency && prevProps.workspace.ideal_cycle_time === nextProps.workspace.ideal_cycle_time && prevProps.workspace.action_count === nextProps.workspace.action_count && prevProps.workspace.action_threshold === nextProps.workspace.action_threshold && prevProps.workspace.avg_cycle_time === nextProps.workspace.avg_cycle_time && prevProps.workspace.displayName === nextProps.workspace.displayName && prevProps.workspace.lineName === nextProps.workspace.lineName;
|
|
64080
64162
|
});
|
|
64081
64163
|
MobileWorkspaceCard.displayName = "MobileWorkspaceCard";
|
|
64082
64164
|
var DesktopWorkspaceRow = React141.memo(({
|
|
@@ -64085,7 +64167,8 @@ var DesktopWorkspaceRow = React141.memo(({
|
|
|
64085
64167
|
rowClass,
|
|
64086
64168
|
isClickable,
|
|
64087
64169
|
onWorkspaceClick,
|
|
64088
|
-
getMedalIcon
|
|
64170
|
+
getMedalIcon,
|
|
64171
|
+
isAssemblyMode
|
|
64089
64172
|
}) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
64090
64173
|
motion.tr,
|
|
64091
64174
|
{
|
|
@@ -64102,11 +64185,11 @@ var DesktopWorkspaceRow = React141.memo(({
|
|
|
64102
64185
|
] }) }),
|
|
64103
64186
|
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-3 py-2.5 sm:p-4 text-sm sm:text-base whitespace-nowrap", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium", children: workspace.displayName }) }),
|
|
64104
64187
|
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-3 py-2.5 sm:p-4 text-sm sm:text-base whitespace-nowrap", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium", children: workspace.lineName }) }),
|
|
64105
|
-
/* @__PURE__ */ jsxRuntime.jsx("td", { className:
|
|
64188
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: `px-3 py-2.5 sm:p-4 text-sm sm:text-base font-medium ${isAssemblyMode ? "" : "whitespace-nowrap"}`, children: isAssemblyMode ? /* @__PURE__ */ jsxRuntime.jsx(CycleTimeComparison, { workspace, variant: "table" }) : /* @__PURE__ */ jsxRuntime.jsx(AnimatedEfficiency, { value: workspace.efficiency || 0 }) })
|
|
64106
64189
|
]
|
|
64107
64190
|
}
|
|
64108
64191
|
), (prevProps, nextProps) => {
|
|
64109
|
-
return prevProps.index === nextProps.index && prevProps.rowClass === nextProps.rowClass && prevProps.isClickable === nextProps.isClickable && prevProps.workspace.workspace_uuid === nextProps.workspace.workspace_uuid && prevProps.workspace.efficiency === nextProps.workspace.efficiency && prevProps.workspace.displayName === nextProps.workspace.displayName && prevProps.workspace.lineName === nextProps.workspace.lineName;
|
|
64192
|
+
return prevProps.index === nextProps.index && prevProps.rowClass === nextProps.rowClass && prevProps.isClickable === nextProps.isClickable && prevProps.isAssemblyMode === nextProps.isAssemblyMode && prevProps.workspace.workspace_uuid === nextProps.workspace.workspace_uuid && prevProps.workspace.efficiency === nextProps.workspace.efficiency && prevProps.workspace.ideal_cycle_time === nextProps.workspace.ideal_cycle_time && prevProps.workspace.avg_cycle_time === nextProps.workspace.avg_cycle_time && prevProps.workspace.displayName === nextProps.workspace.displayName && prevProps.workspace.lineName === nextProps.workspace.lineName;
|
|
64110
64193
|
});
|
|
64111
64194
|
DesktopWorkspaceRow.displayName = "DesktopWorkspaceRow";
|
|
64112
64195
|
var LeaderboardDetailView = React141.memo(({
|
|
@@ -64128,6 +64211,7 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64128
64211
|
const supabase = useSupabase();
|
|
64129
64212
|
const [sortAscending, setSortAscending] = React141.useState(false);
|
|
64130
64213
|
const [viewType, setViewType] = React141.useState("operator");
|
|
64214
|
+
const [outputCategory, setOutputCategory] = React141.useState("standard");
|
|
64131
64215
|
const [activeTab, setActiveTab] = React141.useState("today");
|
|
64132
64216
|
const timezone = useAppTimezone();
|
|
64133
64217
|
const staticShiftConfig = useShiftConfig();
|
|
@@ -64206,6 +64290,7 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64206
64290
|
const monthlyRequestKeyRef = React141.useRef(null);
|
|
64207
64291
|
const leaderboardUpdateQueuedRef = React141.useRef(false);
|
|
64208
64292
|
const leaderboardUpdateTimerRef = React141.useRef(null);
|
|
64293
|
+
const leaderboardViewTrackedRef = React141.useRef(null);
|
|
64209
64294
|
const filterRef = React141.useRef(null);
|
|
64210
64295
|
const filterButtonRef = React141.useRef(null);
|
|
64211
64296
|
const mobileFilterButtonRef = React141.useRef(null);
|
|
@@ -64338,6 +64423,17 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64338
64423
|
}
|
|
64339
64424
|
return Array.from(uniqueLines.entries()).map(([id3, name]) => ({ id: id3, label: name }));
|
|
64340
64425
|
}, [configuredLineIds, lines, getLineName]);
|
|
64426
|
+
const scopedLines = React141.useMemo(() => {
|
|
64427
|
+
const configuredLineIdSet = new Set(configuredLineIds);
|
|
64428
|
+
return lines.filter((line) => configuredLineIds.length === 0 || configuredLineIdSet.has(line.id));
|
|
64429
|
+
}, [configuredLineIds, lines]);
|
|
64430
|
+
const scopedLineAssemblyMap = React141.useMemo(() => {
|
|
64431
|
+
const map = /* @__PURE__ */ new Map();
|
|
64432
|
+
scopedLines.forEach((line) => {
|
|
64433
|
+
map.set(line.id, line.assembly === true);
|
|
64434
|
+
});
|
|
64435
|
+
return map;
|
|
64436
|
+
}, [scopedLines]);
|
|
64341
64437
|
const shiftOptions = React141.useMemo(() => {
|
|
64342
64438
|
if (activeShiftConfig?.shifts && activeShiftConfig.shifts.length > 0) {
|
|
64343
64439
|
return activeShiftConfig.shifts.map((shift2) => ({
|
|
@@ -64361,6 +64457,33 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64361
64457
|
const parsed = Number(selectedShiftFilter);
|
|
64362
64458
|
return Number.isFinite(parsed) ? parsed : void 0;
|
|
64363
64459
|
}, [selectedShiftFilter]);
|
|
64460
|
+
const outputScopeLines = React141.useMemo(() => {
|
|
64461
|
+
const outputLines = scopedLines.filter((line) => (line.monitoring_mode ?? "output") !== "uptime");
|
|
64462
|
+
if (selectedLineFilter === "all") {
|
|
64463
|
+
return outputLines;
|
|
64464
|
+
}
|
|
64465
|
+
return outputLines.filter((line) => line.id === selectedLineFilter);
|
|
64466
|
+
}, [scopedLines, selectedLineFilter]);
|
|
64467
|
+
const hasAssemblyOutputScope = React141.useMemo(
|
|
64468
|
+
() => outputScopeLines.some((line) => line.assembly === true),
|
|
64469
|
+
[outputScopeLines]
|
|
64470
|
+
);
|
|
64471
|
+
const hasStandardOutputScope = React141.useMemo(
|
|
64472
|
+
() => outputScopeLines.some((line) => line.assembly !== true),
|
|
64473
|
+
[outputScopeLines]
|
|
64474
|
+
);
|
|
64475
|
+
const showOutputCategoryDropdown = viewType === "operator" && hasAssemblyOutputScope && hasStandardOutputScope;
|
|
64476
|
+
const isAssemblyMode = viewType === "operator" && outputCategory === "assembly";
|
|
64477
|
+
React141.useEffect(() => {
|
|
64478
|
+
if (viewType !== "operator") return;
|
|
64479
|
+
if (hasAssemblyOutputScope && !hasStandardOutputScope && outputCategory !== "assembly") {
|
|
64480
|
+
setOutputCategory("assembly");
|
|
64481
|
+
return;
|
|
64482
|
+
}
|
|
64483
|
+
if (hasStandardOutputScope && !hasAssemblyOutputScope && outputCategory !== "standard") {
|
|
64484
|
+
setOutputCategory("standard");
|
|
64485
|
+
}
|
|
64486
|
+
}, [viewType, hasAssemblyOutputScope, hasStandardOutputScope, outputCategory]);
|
|
64364
64487
|
const handleLineFilterChange = React141.useCallback((value) => {
|
|
64365
64488
|
setSelectedLineFilter(value);
|
|
64366
64489
|
}, []);
|
|
@@ -64370,17 +64493,19 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64370
64493
|
const clearFilters = React141.useCallback(() => {
|
|
64371
64494
|
setSortAscending(false);
|
|
64372
64495
|
setSelectedLineFilter("all");
|
|
64496
|
+
setOutputCategory("standard");
|
|
64373
64497
|
setSelectedShiftFilter(currentShiftInfo.shiftId.toString());
|
|
64374
64498
|
}, [currentShiftInfo.shiftId]);
|
|
64375
64499
|
const activeFiltersCount = React141.useMemo(() => {
|
|
64376
64500
|
let count = 0;
|
|
64377
64501
|
if (sortAscending) count++;
|
|
64378
64502
|
if (selectedLineFilter !== "all") count++;
|
|
64503
|
+
if (showOutputCategoryDropdown && outputCategory !== "standard") count++;
|
|
64379
64504
|
if (selectedShiftFilter !== currentShiftInfo.shiftId.toString()) {
|
|
64380
64505
|
count++;
|
|
64381
64506
|
}
|
|
64382
64507
|
return count;
|
|
64383
|
-
}, [sortAscending, selectedLineFilter, selectedShiftFilter, currentShiftInfo.shiftId]);
|
|
64508
|
+
}, [sortAscending, selectedLineFilter, outputCategory, showOutputCategoryDropdown, selectedShiftFilter, currentShiftInfo.shiftId]);
|
|
64384
64509
|
const shouldFetchShiftConfigs = !date && shiftId === void 0;
|
|
64385
64510
|
const {
|
|
64386
64511
|
shiftConfigMap: multiLineShiftConfigMap,
|
|
@@ -64432,7 +64557,8 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64432
64557
|
action_count: entry.total_output || 0,
|
|
64433
64558
|
pph: entry.avg_pph || 0,
|
|
64434
64559
|
performance_score: entry.performance_score ?? 0,
|
|
64435
|
-
avg_cycle_time: entry.avg_cycle_time
|
|
64560
|
+
avg_cycle_time: toFiniteNumber(entry.avg_cycle_time) ?? 0,
|
|
64561
|
+
ideal_cycle_time: toFiniteNumber(entry.ideal_cycle_time) ?? void 0,
|
|
64436
64562
|
trend: 0,
|
|
64437
64563
|
predicted_output: 0,
|
|
64438
64564
|
efficiency: entry.efficiency || 0,
|
|
@@ -64610,7 +64736,7 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64610
64736
|
const currentShift = getCurrentShift(timezone || "Asia/Kolkata", activeShiftConfig);
|
|
64611
64737
|
return currentShift.shiftName || getShiftNameById(currentShift.shiftId, timezone || "Asia/Kolkata", activeShiftConfig);
|
|
64612
64738
|
}, [timezone, activeShiftConfig, shiftGroups]);
|
|
64613
|
-
const
|
|
64739
|
+
const getShiftIcon2 = React141.useCallback((shiftId2) => {
|
|
64614
64740
|
if (shiftId2 === void 0 && shiftGroups.length > 1) {
|
|
64615
64741
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
|
|
64616
64742
|
}
|
|
@@ -64676,15 +64802,20 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64676
64802
|
if (!canOpenWorkspace(workspace.line_id)) {
|
|
64677
64803
|
return;
|
|
64678
64804
|
}
|
|
64805
|
+
const cycleRatio = getCycleRatio(workspace);
|
|
64679
64806
|
trackCoreEvent("Workspace from Leaderboard Clicked", {
|
|
64680
64807
|
workspace_name: workspace.workspace_name,
|
|
64681
64808
|
workspace_id: workspace.workspace_uuid,
|
|
64682
64809
|
rank,
|
|
64683
64810
|
total_workspaces: workspacesLengthRef.current,
|
|
64684
64811
|
// Use ref instead of state to avoid dependency
|
|
64812
|
+
metric_context: viewType === "machine" ? "machine" : outputCategory,
|
|
64685
64813
|
efficiency: workspace.efficiency,
|
|
64686
64814
|
action_count: workspace.action_count,
|
|
64687
|
-
action_threshold: workspace.action_threshold
|
|
64815
|
+
action_threshold: workspace.action_threshold,
|
|
64816
|
+
avg_cycle_time: workspace.avg_cycle_time,
|
|
64817
|
+
ideal_cycle_time: workspace.ideal_cycle_time ?? null,
|
|
64818
|
+
cycle_ratio: cycleRatio
|
|
64688
64819
|
});
|
|
64689
64820
|
const displayName = workspace.displayName || getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
|
|
64690
64821
|
const navParams = workspace.workspace_uuid ? getWorkspaceNavigationParams(workspace.workspace_uuid, displayName, workspace.line_id) : "";
|
|
@@ -64708,7 +64839,7 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64708
64839
|
const combinedParams = navParams ? `${navParams}&${contextParamString}` : `?${contextParamString}`;
|
|
64709
64840
|
navigation.navigate(`/workspace/${workspace.workspace_uuid}${combinedParams}`);
|
|
64710
64841
|
}
|
|
64711
|
-
}, [canOpenWorkspace, onWorkspaceClick, navigation, date, shiftId]);
|
|
64842
|
+
}, [canOpenWorkspace, onWorkspaceClick, navigation, date, shiftId, outputCategory, viewType]);
|
|
64712
64843
|
React141.useEffect(() => {
|
|
64713
64844
|
workspacesLengthRef.current = activeEntries.length || 0;
|
|
64714
64845
|
}, [activeEntries.length]);
|
|
@@ -64729,16 +64860,20 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64729
64860
|
return activeEntries.map((ws) => ({
|
|
64730
64861
|
...ws,
|
|
64731
64862
|
displayName: ws.displayName || getWorkspaceDisplayName(ws.workspace_name, ws.line_id),
|
|
64732
|
-
lineName: getLineName(ws.line_id)
|
|
64863
|
+
lineName: getLineName(ws.line_id),
|
|
64864
|
+
isAssemblyLine: scopedLineAssemblyMap.get(ws.line_id) === true
|
|
64733
64865
|
}));
|
|
64734
|
-
}, [activeEntries, getLineName]);
|
|
64866
|
+
}, [activeEntries, getLineName, scopedLineAssemblyMap]);
|
|
64735
64867
|
const sortedWorkspaces = React141.useMemo(() => {
|
|
64736
64868
|
let filtered = [...workspaceDisplayData];
|
|
64737
64869
|
filtered = filtered.filter((ws) => {
|
|
64738
64870
|
if (viewType === "machine") {
|
|
64739
64871
|
return ws.monitoring_mode === "uptime";
|
|
64740
64872
|
}
|
|
64741
|
-
|
|
64873
|
+
if (ws.monitoring_mode === "uptime") {
|
|
64874
|
+
return false;
|
|
64875
|
+
}
|
|
64876
|
+
return isAssemblyMode ? ws.isAssemblyLine : !ws.isAssemblyLine;
|
|
64742
64877
|
});
|
|
64743
64878
|
if (selectedLineFilter !== "all") {
|
|
64744
64879
|
filtered = filtered.filter((ws) => ws.line_id === selectedLineFilter);
|
|
@@ -64747,13 +64882,61 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64747
64882
|
filtered = filtered.filter((ws) => ws.shift_id?.toString() === selectedShiftFilter);
|
|
64748
64883
|
}
|
|
64749
64884
|
return filtered.sort((a, b) => {
|
|
64885
|
+
if (isAssemblyMode) {
|
|
64886
|
+
const ratioA = getCycleRatio(a);
|
|
64887
|
+
const ratioB = getCycleRatio(b);
|
|
64888
|
+
if (ratioA === null && ratioB === null) return 0;
|
|
64889
|
+
if (ratioA === null) return 1;
|
|
64890
|
+
if (ratioB === null) return -1;
|
|
64891
|
+
return sortAscending ? ratioA - ratioB : ratioB - ratioA;
|
|
64892
|
+
}
|
|
64750
64893
|
const effA = a.efficiency || 0;
|
|
64751
64894
|
const effB = b.efficiency || 0;
|
|
64752
64895
|
return sortAscending ? effA - effB : effB - effA;
|
|
64753
64896
|
});
|
|
64754
|
-
}, [workspaceDisplayData, sortAscending, selectedLineFilter, selectedShiftFilter, activeTab, viewType]);
|
|
64897
|
+
}, [workspaceDisplayData, sortAscending, selectedLineFilter, selectedShiftFilter, activeTab, viewType, isAssemblyMode]);
|
|
64755
64898
|
const loading = activeTab === "today" ? todayLoading : monthlyLoading;
|
|
64756
64899
|
const error = activeTab === "today" ? todayError : monthlyError;
|
|
64900
|
+
React141.useEffect(() => {
|
|
64901
|
+
if (loading || error || sortedWorkspaces.length === 0) return;
|
|
64902
|
+
const trackingKey = [
|
|
64903
|
+
activeTab,
|
|
64904
|
+
viewType,
|
|
64905
|
+
outputCategory,
|
|
64906
|
+
selectedLineFilter,
|
|
64907
|
+
selectedShiftFilter,
|
|
64908
|
+
sortAscending ? "asc" : "desc",
|
|
64909
|
+
sortedWorkspaces.length
|
|
64910
|
+
].join("|");
|
|
64911
|
+
if (leaderboardViewTrackedRef.current === trackingKey) return;
|
|
64912
|
+
leaderboardViewTrackedRef.current = trackingKey;
|
|
64913
|
+
const topWorkspace = sortedWorkspaces[0];
|
|
64914
|
+
trackCoreEvent("Workspace Leaderboard View Loaded", {
|
|
64915
|
+
time_range: activeTab,
|
|
64916
|
+
view_type: viewType,
|
|
64917
|
+
metric_context: viewType === "machine" ? "machine" : outputCategory,
|
|
64918
|
+
line_filter: selectedLineFilter,
|
|
64919
|
+
shift_filter: selectedShiftFilter,
|
|
64920
|
+
sort_direction: sortAscending ? "asc" : "desc",
|
|
64921
|
+
workspace_count: sortedWorkspaces.length,
|
|
64922
|
+
top_workspace_id: topWorkspace?.workspace_uuid ?? null,
|
|
64923
|
+
top_workspace_name: topWorkspace?.workspace_name ?? null,
|
|
64924
|
+
top_efficiency: topWorkspace?.efficiency ?? null,
|
|
64925
|
+
top_avg_cycle_time: topWorkspace?.avg_cycle_time ?? null,
|
|
64926
|
+
top_ideal_cycle_time: topWorkspace?.ideal_cycle_time ?? null,
|
|
64927
|
+
top_cycle_ratio: topWorkspace ? getCycleRatio(topWorkspace) : null
|
|
64928
|
+
});
|
|
64929
|
+
}, [
|
|
64930
|
+
loading,
|
|
64931
|
+
error,
|
|
64932
|
+
sortedWorkspaces,
|
|
64933
|
+
activeTab,
|
|
64934
|
+
viewType,
|
|
64935
|
+
outputCategory,
|
|
64936
|
+
selectedLineFilter,
|
|
64937
|
+
selectedShiftFilter,
|
|
64938
|
+
sortAscending
|
|
64939
|
+
]);
|
|
64757
64940
|
const currentDateFormatted = React141.useMemo(() => {
|
|
64758
64941
|
const dateStr = (/* @__PURE__ */ new Date()).toDateString();
|
|
64759
64942
|
return formatDate2(new Date(dateStr));
|
|
@@ -64771,7 +64954,9 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64771
64954
|
error.message
|
|
64772
64955
|
] }) });
|
|
64773
64956
|
}
|
|
64774
|
-
const
|
|
64957
|
+
const metricLabel = viewType === "machine" ? "Utilization" : isAssemblyMode ? "Cycle Time" : "Efficiency";
|
|
64958
|
+
const descendingSortLabel = "Highest to Lowest";
|
|
64959
|
+
const ascendingSortLabel = "Lowest to Highest";
|
|
64775
64960
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `min-h-screen bg-slate-50 flex flex-col ${className}`, style: { willChange: "contents" }, children: [
|
|
64776
64961
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-0 z-20 bg-white shadow-sm border-b border-gray-200/80", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 sm:px-6 md:px-8 py-2 sm:py-2.5", children: [
|
|
64777
64962
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "sm:hidden", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center", children: [
|
|
@@ -64821,7 +65006,7 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64821
65006
|
] }),
|
|
64822
65007
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
|
|
64823
65008
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
|
|
64824
|
-
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-xs font-medium text-gray-500 uppercase tracking-wide ml-1", children:
|
|
65009
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-xs font-medium text-gray-500 uppercase tracking-wide ml-1", children: metricLabel }),
|
|
64825
65010
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
64826
65011
|
"select",
|
|
64827
65012
|
{
|
|
@@ -64830,8 +65015,25 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64830
65015
|
className: "w-full appearance-none pl-3 pr-8 py-2 text-sm bg-gray-50 border border-gray-200 hover:border-gray-300 rounded-lg text-gray-900 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:bg-white transition-all cursor-pointer",
|
|
64831
65016
|
style: { backgroundImage: `url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e")`, backgroundPosition: `right 0.75rem center`, backgroundRepeat: `no-repeat`, backgroundSize: `1.2em 1.2em` },
|
|
64832
65017
|
children: [
|
|
64833
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "desc", children:
|
|
64834
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "asc", children:
|
|
65018
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "desc", children: descendingSortLabel }),
|
|
65019
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "asc", children: ascendingSortLabel })
|
|
65020
|
+
]
|
|
65021
|
+
}
|
|
65022
|
+
) })
|
|
65023
|
+
] }),
|
|
65024
|
+
showOutputCategoryDropdown && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1 sm:hidden", children: [
|
|
65025
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-xs font-medium text-gray-500 uppercase tracking-wide ml-1", children: "Output Type" }),
|
|
65026
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
65027
|
+
"select",
|
|
65028
|
+
{
|
|
65029
|
+
"aria-label": "Output leaderboard category",
|
|
65030
|
+
value: outputCategory,
|
|
65031
|
+
onChange: (e) => setOutputCategory(e.target.value),
|
|
65032
|
+
className: "w-full appearance-none pl-3 pr-8 py-2 text-sm bg-gray-50 border border-gray-200 hover:border-gray-300 rounded-lg text-gray-900 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:bg-white transition-all cursor-pointer",
|
|
65033
|
+
style: { backgroundImage: `url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e")`, backgroundPosition: `right 0.75rem center`, backgroundRepeat: `no-repeat`, backgroundSize: `1.2em 1.2em` },
|
|
65034
|
+
children: [
|
|
65035
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "standard", children: "Standard" }),
|
|
65036
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "assembly", children: "Assembly" })
|
|
64835
65037
|
]
|
|
64836
65038
|
}
|
|
64837
65039
|
) })
|
|
@@ -64873,7 +65075,7 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64873
65075
|
currentDate: activeTab === "monthly" ? monthlyRangeText : currentDateFormatted,
|
|
64874
65076
|
currentMobileDate: activeTab === "monthly" ? monthlyRangeText : currentMobileDateFormatted,
|
|
64875
65077
|
shiftId: activeTab === "monthly" ? monthlyShiftId : todayShiftId,
|
|
64876
|
-
getShiftIcon,
|
|
65078
|
+
getShiftIcon: getShiftIcon2,
|
|
64877
65079
|
getShiftName,
|
|
64878
65080
|
showTimer: activeTab === "today"
|
|
64879
65081
|
}
|
|
@@ -64971,6 +65173,20 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64971
65173
|
]
|
|
64972
65174
|
}
|
|
64973
65175
|
) }),
|
|
65176
|
+
showOutputCategoryDropdown && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
65177
|
+
"select",
|
|
65178
|
+
{
|
|
65179
|
+
"aria-label": "Output leaderboard category",
|
|
65180
|
+
value: outputCategory,
|
|
65181
|
+
onChange: (e) => setOutputCategory(e.target.value),
|
|
65182
|
+
className: "appearance-none pl-3 pr-8 py-1.5 text-sm font-medium bg-white border border-gray-200 hover:border-gray-300 rounded-lg text-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500 transition-all cursor-pointer shadow-sm",
|
|
65183
|
+
style: { backgroundImage: `url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e")`, backgroundPosition: `right 0.5rem center`, backgroundRepeat: `no-repeat`, backgroundSize: `1.2em 1.2em` },
|
|
65184
|
+
children: [
|
|
65185
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "standard", children: "Standard" }),
|
|
65186
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "assembly", children: "Assembly" })
|
|
65187
|
+
]
|
|
65188
|
+
}
|
|
65189
|
+
) }),
|
|
64974
65190
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
64975
65191
|
"button",
|
|
64976
65192
|
{
|
|
@@ -65002,7 +65218,8 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
65002
65218
|
isClickable: canOpenWorkspace(ws.line_id),
|
|
65003
65219
|
onWorkspaceClick: stableHandleWorkspaceClick,
|
|
65004
65220
|
getMedalIcon: stableGetMedalIcon,
|
|
65005
|
-
|
|
65221
|
+
metricLabel,
|
|
65222
|
+
isAssemblyMode
|
|
65006
65223
|
},
|
|
65007
65224
|
ws.workspace_uuid
|
|
65008
65225
|
);
|
|
@@ -65013,7 +65230,7 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
65013
65230
|
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-3 py-2.5 sm:p-4 text-left text-xs sm:text-sm font-semibold text-gray-600 whitespace-nowrap", children: "Rank" }),
|
|
65014
65231
|
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-3 py-2.5 sm:p-4 text-left text-xs sm:text-sm font-semibold text-gray-600 whitespace-nowrap", children: "Workspace" }),
|
|
65015
65232
|
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-3 py-2.5 sm:p-4 text-left text-xs sm:text-sm font-semibold text-gray-600 whitespace-nowrap", children: "Line" }),
|
|
65016
|
-
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-3 py-2.5 sm:p-4 text-left text-xs sm:text-sm font-semibold text-gray-600 whitespace-nowrap", children:
|
|
65233
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-3 py-2.5 sm:p-4 text-left text-xs sm:text-sm font-semibold text-gray-600 whitespace-nowrap", children: metricLabel })
|
|
65017
65234
|
] }) }),
|
|
65018
65235
|
/* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-gray-100", children: sortedWorkspaces.map((ws, index) => {
|
|
65019
65236
|
const isTopThree = index < 3;
|
|
@@ -65026,7 +65243,8 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
65026
65243
|
rowClass,
|
|
65027
65244
|
isClickable: canOpenWorkspace(ws.line_id),
|
|
65028
65245
|
onWorkspaceClick: stableHandleWorkspaceClick,
|
|
65029
|
-
getMedalIcon: stableGetMedalIcon
|
|
65246
|
+
getMedalIcon: stableGetMedalIcon,
|
|
65247
|
+
isAssemblyMode
|
|
65030
65248
|
},
|
|
65031
65249
|
ws.workspace_uuid
|
|
65032
65250
|
);
|
|
@@ -65044,7 +65262,10 @@ function LoginView({
|
|
|
65044
65262
|
logoSrc = optifye_logo_default,
|
|
65045
65263
|
logoAlt = "Optifye",
|
|
65046
65264
|
brandName = "Optifye",
|
|
65047
|
-
onRateLimitCheck
|
|
65265
|
+
onRateLimitCheck,
|
|
65266
|
+
showDevTestLogin = false,
|
|
65267
|
+
devTestLoginLabel,
|
|
65268
|
+
onDevTestLogin
|
|
65048
65269
|
}) {
|
|
65049
65270
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
65050
65271
|
LoginPage,
|
|
@@ -65052,7 +65273,10 @@ function LoginView({
|
|
|
65052
65273
|
logoSrc,
|
|
65053
65274
|
logoAlt,
|
|
65054
65275
|
brandName,
|
|
65055
|
-
onRateLimitCheck
|
|
65276
|
+
onRateLimitCheck,
|
|
65277
|
+
showDevTestLogin,
|
|
65278
|
+
devTestLoginLabel,
|
|
65279
|
+
onDevTestLogin
|
|
65056
65280
|
}
|
|
65057
65281
|
);
|
|
65058
65282
|
}
|
|
@@ -68240,20 +68464,30 @@ function useTimezone(options = {}) {
|
|
|
68240
68464
|
}
|
|
68241
68465
|
|
|
68242
68466
|
// src/views/workspace-detail-view.utils.ts
|
|
68243
|
-
var
|
|
68467
|
+
var getWorkspaceDetailLayoutMode = ({
|
|
68244
68468
|
workspace,
|
|
68245
68469
|
showCycleTimeChart
|
|
68246
68470
|
}) => {
|
|
68247
68471
|
if (workspace?.monitoring_mode === "uptime") {
|
|
68248
|
-
return "
|
|
68472
|
+
return "uptime";
|
|
68249
68473
|
}
|
|
68250
68474
|
if (showCycleTimeChart === false) {
|
|
68251
68475
|
return "output";
|
|
68252
68476
|
}
|
|
68253
|
-
|
|
68477
|
+
return shouldUseAssemblyCycleTimeLayout(workspace) ? "assembly_cycle" : "output";
|
|
68478
|
+
};
|
|
68479
|
+
var getCycleTimeRenderState = ({
|
|
68480
|
+
workspace,
|
|
68481
|
+
authoritativeMetrics,
|
|
68482
|
+
showCycleTimeChart
|
|
68483
|
+
}) => {
|
|
68484
|
+
if (getWorkspaceDetailLayoutMode({ workspace, showCycleTimeChart }) !== "assembly_cycle") {
|
|
68254
68485
|
return "output";
|
|
68255
68486
|
}
|
|
68256
|
-
|
|
68487
|
+
if (!authoritativeMetrics) {
|
|
68488
|
+
return "chart_loading";
|
|
68489
|
+
}
|
|
68490
|
+
return authoritativeMetrics.cycle_time_data_status === "missing_clips" ? "cycle_unavailable" : "cycle_chart";
|
|
68257
68491
|
};
|
|
68258
68492
|
var formatDateInTimezone = (date = /* @__PURE__ */ new Date(), timezone, options) => {
|
|
68259
68493
|
const defaultOptions = {
|
|
@@ -68661,33 +68895,34 @@ var WorkspaceDetailView = ({
|
|
|
68661
68895
|
idle_time_hourly: void 0
|
|
68662
68896
|
};
|
|
68663
68897
|
}, [cachedOverviewMetrics, shiftConfig?.shifts]);
|
|
68664
|
-
const
|
|
68898
|
+
const authoritativeCycleMetrics = isHistoricView ? historicMetrics : liveMetrics;
|
|
68899
|
+
const workspace = authoritativeCycleMetrics || cachedDetailedMetrics || overviewFallback;
|
|
68665
68900
|
const { timezone: cycleTimeTimezone } = useTimezone({
|
|
68666
68901
|
lineId: effectiveLineId || workspace?.line_id || void 0,
|
|
68667
68902
|
workspaceId: workspaceId || void 0
|
|
68668
68903
|
});
|
|
68669
68904
|
const effectiveCycleTimeTimezone = cycleTimeTimezone || timezone;
|
|
68670
|
-
const detailedWorkspaceMetrics =
|
|
68905
|
+
const detailedWorkspaceMetrics = authoritativeCycleMetrics || cachedDetailedMetrics;
|
|
68671
68906
|
const cycleTimeChartData = React141.useMemo(
|
|
68672
|
-
() => Array.isArray(
|
|
68907
|
+
() => Array.isArray(authoritativeCycleMetrics?.hourly_cycle_times) ? authoritativeCycleMetrics.hourly_cycle_times.map((value) => {
|
|
68673
68908
|
const numericValue = Number(value);
|
|
68674
68909
|
return Number.isFinite(numericValue) ? numericValue : 0;
|
|
68675
68910
|
}) : [],
|
|
68676
|
-
[
|
|
68911
|
+
[authoritativeCycleMetrics?.hourly_cycle_times]
|
|
68677
68912
|
);
|
|
68678
68913
|
const maskedCycleTimeChartData = React141.useMemo(
|
|
68679
68914
|
() => maskFutureHourlySeries({
|
|
68680
68915
|
data: cycleTimeChartData,
|
|
68681
|
-
shiftStart:
|
|
68682
|
-
shiftEnd:
|
|
68683
|
-
shiftDate:
|
|
68916
|
+
shiftStart: authoritativeCycleMetrics?.shift_start,
|
|
68917
|
+
shiftEnd: authoritativeCycleMetrics?.shift_end,
|
|
68918
|
+
shiftDate: authoritativeCycleMetrics?.date || date || calculatedOperationalDate || null,
|
|
68684
68919
|
timezone: effectiveCycleTimeTimezone
|
|
68685
68920
|
}),
|
|
68686
68921
|
[
|
|
68687
68922
|
cycleTimeChartData,
|
|
68688
|
-
|
|
68689
|
-
|
|
68690
|
-
|
|
68923
|
+
authoritativeCycleMetrics?.shift_start,
|
|
68924
|
+
authoritativeCycleMetrics?.shift_end,
|
|
68925
|
+
authoritativeCycleMetrics?.date,
|
|
68691
68926
|
date,
|
|
68692
68927
|
calculatedOperationalDate,
|
|
68693
68928
|
effectiveCycleTimeTimezone
|
|
@@ -68695,13 +68930,13 @@ var WorkspaceDetailView = ({
|
|
|
68695
68930
|
);
|
|
68696
68931
|
const cycleTimeDatasetKey = React141.useMemo(
|
|
68697
68932
|
() => [
|
|
68698
|
-
|
|
68699
|
-
date ||
|
|
68700
|
-
parsedShiftId ??
|
|
68933
|
+
authoritativeCycleMetrics?.workspace_id || workspaceId || "workspace",
|
|
68934
|
+
date || authoritativeCycleMetrics?.date || "live",
|
|
68935
|
+
parsedShiftId ?? authoritativeCycleMetrics?.shift_id ?? "current",
|
|
68701
68936
|
"hourly",
|
|
68702
68937
|
"backend"
|
|
68703
68938
|
].join(":"),
|
|
68704
|
-
[
|
|
68939
|
+
[authoritativeCycleMetrics?.workspace_id, workspaceId, date, authoritativeCycleMetrics?.date, parsedShiftId, authoritativeCycleMetrics?.shift_id]
|
|
68705
68940
|
);
|
|
68706
68941
|
const hasWorkspaceSnapshot = Boolean(workspace);
|
|
68707
68942
|
const loading = ((isHistoricView ? historicLoading : liveLoading) || isShiftConfigLoading) && !hasWorkspaceSnapshot;
|
|
@@ -68950,30 +69185,46 @@ var WorkspaceDetailView = ({
|
|
|
68950
69185
|
action_type: workspace.action_type
|
|
68951
69186
|
} : null;
|
|
68952
69187
|
const isAssemblyWorkspace = shouldUseAssemblyCycleTimeLayout(workspaceCycleTimeEligibility);
|
|
68953
|
-
const
|
|
69188
|
+
const layoutMode = getWorkspaceDetailLayoutMode({
|
|
68954
69189
|
workspace: workspace ? {
|
|
68955
69190
|
monitoring_mode: workspace.monitoring_mode,
|
|
68956
69191
|
line_assembly_enabled: workspace.line_assembly_enabled,
|
|
68957
69192
|
action_family: workspace.action_family,
|
|
68958
|
-
action_type: workspace.action_type
|
|
68959
|
-
cycle_time_data_status: workspace.cycle_time_data_status
|
|
69193
|
+
action_type: workspace.action_type
|
|
68960
69194
|
} : null,
|
|
68961
69195
|
showCycleTimeChart
|
|
68962
69196
|
});
|
|
68963
|
-
const
|
|
69197
|
+
const isAssemblyCycleLayout = layoutMode === "assembly_cycle";
|
|
69198
|
+
const isOutputLayout = layoutMode === "output";
|
|
69199
|
+
const cycleTimePresentation = getCycleTimeRenderState({
|
|
69200
|
+
workspace: workspace ? {
|
|
69201
|
+
monitoring_mode: workspace.monitoring_mode,
|
|
69202
|
+
line_assembly_enabled: workspace.line_assembly_enabled,
|
|
69203
|
+
action_family: workspace.action_family,
|
|
69204
|
+
action_type: workspace.action_type
|
|
69205
|
+
} : null,
|
|
69206
|
+
authoritativeMetrics: authoritativeCycleMetrics ? {
|
|
69207
|
+
cycle_time_data_status: authoritativeCycleMetrics.cycle_time_data_status
|
|
69208
|
+
} : null,
|
|
69209
|
+
showCycleTimeChart
|
|
69210
|
+
});
|
|
69211
|
+
const shouldShowCycleTimeChart = cycleTimePresentation === "cycle_chart";
|
|
68964
69212
|
const shouldShowCycleTimeUnavailableState = cycleTimePresentation === "cycle_unavailable";
|
|
68965
|
-
const
|
|
69213
|
+
const shouldShowCycleTimeLoadingState = cycleTimePresentation === "chart_loading";
|
|
69214
|
+
const shouldShowAssemblyOverviewLoadingState = isAssemblyCycleLayout && shouldShowCycleTimeLoadingState && hasWorkspaceSnapshot;
|
|
69215
|
+
const showIdleBreakdownChart = !isAssemblyCycleLayout && idleTimeVlmEnabled;
|
|
69216
|
+
const canToggleChartIdleTime = !isUptimeMode && !shouldShowCycleTimeLoadingState && !shouldShowCycleTimeUnavailableState;
|
|
68966
69217
|
const idleClipDate = date || workspace?.date || calculatedOperationalDate || getOperationalDate(timezone);
|
|
68967
69218
|
const idleClipShiftId = parsedShiftId ?? workspace?.shift_id;
|
|
68968
69219
|
const rawHourlyIdleMinutes = React141.useMemo(() => {
|
|
68969
69220
|
if (!shouldShowCycleTimeChart || !workspace?.idle_time_hourly || !workspace?.shift_start) return [];
|
|
68970
|
-
const
|
|
69221
|
+
const parseTimeToMinutes4 = (time2) => {
|
|
68971
69222
|
const [h, m] = time2.split(":").map(Number);
|
|
68972
69223
|
if (!Number.isFinite(h) || !Number.isFinite(m)) return 0;
|
|
68973
69224
|
return h * 60 + m;
|
|
68974
69225
|
};
|
|
68975
|
-
const startTotal =
|
|
68976
|
-
const endTotalRaw = workspace.shift_end ?
|
|
69226
|
+
const startTotal = parseTimeToMinutes4(workspace.shift_start);
|
|
69227
|
+
const endTotalRaw = workspace.shift_end ? parseTimeToMinutes4(workspace.shift_end) : startTotal + 11 * 60;
|
|
68977
69228
|
const endTotal = endTotalRaw <= startTotal ? endTotalRaw + 24 * 60 : endTotalRaw;
|
|
68978
69229
|
const shiftDuration = Math.max(60, endTotal - startTotal);
|
|
68979
69230
|
const totalHourSlots = Math.max(1, Math.ceil(shiftDuration / 60));
|
|
@@ -69023,6 +69274,18 @@ var WorkspaceDetailView = ({
|
|
|
69023
69274
|
workspace.cycle_completion_clip_count
|
|
69024
69275
|
] })
|
|
69025
69276
|
] }), [workspace?.cycle_completion_clip_count]);
|
|
69277
|
+
const assemblyOverviewLoadingView = React141.useMemo(() => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4 pb-4", "data-testid": "assembly-overview-loading-state", children: [
|
|
69278
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-white rounded-lg shadow-sm p-6 lg:p-8", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-[280px] lg:min-h-[340px] flex flex-col justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full max-w-xl mx-auto animate-pulse space-y-3", children: [
|
|
69279
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3 bg-gray-200 rounded-full w-3/4 mx-auto" }),
|
|
69280
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3 bg-gray-100 rounded-full w-full" }),
|
|
69281
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3 bg-gray-100 rounded-full w-5/6 mx-auto" })
|
|
69282
|
+
] }) }) }),
|
|
69283
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4", children: [0, 1, 2].map((index) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-white rounded-lg shadow-sm p-5", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "animate-pulse space-y-3", children: [
|
|
69284
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 w-24 bg-gray-200 rounded" }),
|
|
69285
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-10 w-20 bg-gray-100 rounded" }),
|
|
69286
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3 w-28 bg-gray-100 rounded" })
|
|
69287
|
+
] }) }, index)) })
|
|
69288
|
+
] }), []);
|
|
69026
69289
|
const shiftDurationMinutes = React141.useMemo(
|
|
69027
69290
|
() => getShiftDurationMinutes(workspace?.shift_start, workspace?.shift_end),
|
|
69028
69291
|
[workspace?.shift_start, workspace?.shift_end]
|
|
@@ -69077,7 +69340,7 @@ var WorkspaceDetailView = ({
|
|
|
69077
69340
|
}, [isUptimeMode, uptimeSeries, shiftDurationMinutes, elapsedShiftMinutes, workspace?.idle_time]);
|
|
69078
69341
|
const overviewTabLabel = isUptimeMode ? "Utilization" : "Efficiency";
|
|
69079
69342
|
const idleClipFetchEnabled = Boolean(
|
|
69080
|
-
workspaceId && idleClipDate && idleClipShiftId !== void 0 && activeTab === "overview" && idleTimeVlmEnabled &&
|
|
69343
|
+
workspaceId && idleClipDate && idleClipShiftId !== void 0 && activeTab === "overview" && idleTimeVlmEnabled && isOutputLayout
|
|
69081
69344
|
);
|
|
69082
69345
|
const {
|
|
69083
69346
|
idleClips: idleTimeClips,
|
|
@@ -69148,7 +69411,7 @@ var WorkspaceDetailView = ({
|
|
|
69148
69411
|
}
|
|
69149
69412
|
}
|
|
69150
69413
|
};
|
|
69151
|
-
const
|
|
69414
|
+
const getShiftIcon2 = (shiftType) => {
|
|
69152
69415
|
const shiftTypeLower = shiftType?.toLowerCase() || "";
|
|
69153
69416
|
if (shiftTypeLower.includes("day") || shiftTypeLower.includes("morning")) {
|
|
69154
69417
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
|
|
@@ -69297,7 +69560,7 @@ var WorkspaceDetailView = ({
|
|
|
69297
69560
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children: (() => {
|
|
69298
69561
|
const shift2 = shiftConfig?.shifts?.find((s) => s.shiftId === selectedShift);
|
|
69299
69562
|
const shiftName = shift2?.shiftName || (selectedShift === 0 ? "Day Shift" : "Night Shift");
|
|
69300
|
-
return
|
|
69563
|
+
return getShiftIcon2(shiftName);
|
|
69301
69564
|
})() }),
|
|
69302
69565
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: (() => {
|
|
69303
69566
|
const shift2 = shiftConfig?.shifts?.find((s) => s.shiftId === selectedShift);
|
|
@@ -69325,7 +69588,7 @@ var WorkspaceDetailView = ({
|
|
|
69325
69588
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "opacity-70", children: (() => {
|
|
69326
69589
|
const shift2 = shiftConfig?.shifts?.find((s) => s.shiftId === selectedShift);
|
|
69327
69590
|
const shiftName = shift2?.shiftName || (selectedShift === 0 ? "Day Shift" : "Night Shift");
|
|
69328
|
-
return
|
|
69591
|
+
return getShiftIcon2(shiftName);
|
|
69329
69592
|
})() }),
|
|
69330
69593
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm md:text-base font-semibold uppercase tracking-wider", children: (() => {
|
|
69331
69594
|
const shift2 = shiftConfig?.shifts?.find((s) => s.shiftId === selectedShift);
|
|
@@ -69338,7 +69601,7 @@ var WorkspaceDetailView = ({
|
|
|
69338
69601
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sm:hidden mt-3 flex items-center justify-center gap-2", children: [
|
|
69339
69602
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-gray-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: formatISTDate2(new Date(workspace.date)) }) }),
|
|
69340
69603
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
|
|
69341
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children:
|
|
69604
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon2(workspace.shift_type) }),
|
|
69342
69605
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: workspace.shift_type })
|
|
69343
69606
|
] }),
|
|
69344
69607
|
!date && !shift && !usingFallbackData ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-green-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-green-700", children: /* @__PURE__ */ jsxRuntime.jsx(LiveTimer, {}) }) }) : date ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-blue-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-blue-700", children: getDaysDifference(workspace.date, timezone, dashboardConfig?.shiftConfig?.dayShift?.startTime || "06:00") }) }) : usingFallbackData ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-amber-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-amber-700", children: getDaysDifference(workspace.date, timezone, dashboardConfig?.shiftConfig?.dayShift?.startTime || "06:00") }) }) : null
|
|
@@ -69369,7 +69632,7 @@ var WorkspaceDetailView = ({
|
|
|
69369
69632
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-200" })
|
|
69370
69633
|
] }),
|
|
69371
69634
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
|
|
69372
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "opacity-70", children:
|
|
69635
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "opacity-70", children: getShiftIcon2(workspace.shift_type) }),
|
|
69373
69636
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm md:text-base font-semibold uppercase tracking-wider", children: [
|
|
69374
69637
|
workspace.shift_type.replace(/ Shift$/i, ""),
|
|
69375
69638
|
" Shift"
|
|
@@ -69488,9 +69751,9 @@ var WorkspaceDetailView = ({
|
|
|
69488
69751
|
] })
|
|
69489
69752
|
] }),
|
|
69490
69753
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-grow p-1.5 sm:p-2 lg:p-4", children: [
|
|
69491
|
-
activeTab === "overview" && /* @__PURE__ */ jsxRuntime.
|
|
69754
|
+
activeTab === "overview" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col h-full lg:h-[calc(100vh-12rem)] overflow-y-auto lg:min-h-0 pb-4", children: shouldShowAssemblyOverviewLoadingState ? assemblyOverviewLoadingView : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
69492
69755
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "block lg:hidden space-y-6 pb-6", children: [
|
|
69493
|
-
|
|
69756
|
+
isOutputLayout && !isUptimeMode && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
69494
69757
|
motion.div,
|
|
69495
69758
|
{
|
|
69496
69759
|
className: "bg-white rounded-lg shadow-sm p-6 h-[300px]",
|
|
@@ -69518,8 +69781,8 @@ var WorkspaceDetailView = ({
|
|
|
69518
69781
|
animate: "animate",
|
|
69519
69782
|
children: [
|
|
69520
69783
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between items-center mb-4", children: [
|
|
69521
|
-
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-bold text-gray-700", children: isUptimeMode ? "Machine Utilization" :
|
|
69522
|
-
|
|
69784
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-bold text-gray-700", children: isUptimeMode ? "Machine Utilization" : isAssemblyCycleLayout ? "Cycle time trend" : "Hourly Output" }),
|
|
69785
|
+
canToggleChartIdleTime && /* @__PURE__ */ jsxRuntime.jsx(
|
|
69523
69786
|
"button",
|
|
69524
69787
|
{
|
|
69525
69788
|
onClick: () => setShowChartIdleTime(!showChartIdleTime),
|
|
@@ -69548,19 +69811,19 @@ var WorkspaceDetailView = ({
|
|
|
69548
69811
|
timezone,
|
|
69549
69812
|
elapsedMinutes: elapsedShiftMinutes
|
|
69550
69813
|
}
|
|
69551
|
-
) : shouldShowCycleTimeUnavailableState ? cycleTimeUnavailableView : shouldShowCycleTimeChart ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
69814
|
+
) : isAssemblyCycleLayout ? shouldShowCycleTimeUnavailableState ? cycleTimeUnavailableView : shouldShowCycleTimeChart ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
69552
69815
|
CycleTimeOverTimeChart,
|
|
69553
69816
|
{
|
|
69554
69817
|
data: maskedCycleTimeChartData,
|
|
69555
|
-
idealCycleTime:
|
|
69556
|
-
shiftStart:
|
|
69557
|
-
shiftEnd:
|
|
69818
|
+
idealCycleTime: authoritativeCycleMetrics?.ideal_cycle_time || 0,
|
|
69819
|
+
shiftStart: authoritativeCycleMetrics?.shift_start || "",
|
|
69820
|
+
shiftEnd: authoritativeCycleMetrics?.shift_end || "",
|
|
69558
69821
|
xAxisMode: "hourly",
|
|
69559
69822
|
datasetKey: cycleTimeDatasetKey,
|
|
69560
69823
|
showIdleTime: showChartIdleTime,
|
|
69561
69824
|
idleTimeData: hourlyIdleMinutes
|
|
69562
69825
|
}
|
|
69563
|
-
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
69826
|
+
) : null : /* @__PURE__ */ jsxRuntime.jsx(
|
|
69564
69827
|
HourlyOutputChart2,
|
|
69565
69828
|
{
|
|
69566
69829
|
data: workspace.hourly_action_counts || [],
|
|
@@ -69580,7 +69843,7 @@ var WorkspaceDetailView = ({
|
|
|
69580
69843
|
]
|
|
69581
69844
|
}
|
|
69582
69845
|
),
|
|
69583
|
-
|
|
69846
|
+
showIdleBreakdownChart && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
69584
69847
|
motion.div,
|
|
69585
69848
|
{
|
|
69586
69849
|
className: "bg-white rounded-lg shadow-sm p-4 h-[300px]",
|
|
@@ -69600,7 +69863,7 @@ var WorkspaceDetailView = ({
|
|
|
69600
69863
|
]
|
|
69601
69864
|
}
|
|
69602
69865
|
),
|
|
69603
|
-
isUptimeMode ? /* @__PURE__ */ jsxRuntime.jsx(UptimeMetricCards, { workspace, uptimePieData }) :
|
|
69866
|
+
isUptimeMode ? /* @__PURE__ */ jsxRuntime.jsx(UptimeMetricCards, { workspace, uptimePieData }) : isAssemblyCycleLayout ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
69604
69867
|
WorkspaceCycleTimeMetricCards,
|
|
69605
69868
|
{
|
|
69606
69869
|
workspace,
|
|
@@ -69620,7 +69883,7 @@ var WorkspaceDetailView = ({
|
|
|
69620
69883
|
desktopTopSectionClass
|
|
69621
69884
|
),
|
|
69622
69885
|
children: [
|
|
69623
|
-
|
|
69886
|
+
isOutputLayout && !isUptimeMode && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
69624
69887
|
motion.div,
|
|
69625
69888
|
{
|
|
69626
69889
|
className: "bg-white rounded-lg shadow-sm p-4 lg:col-span-2 flex flex-col min-h-0",
|
|
@@ -69644,15 +69907,15 @@ var WorkspaceDetailView = ({
|
|
|
69644
69907
|
{
|
|
69645
69908
|
className: clsx(
|
|
69646
69909
|
"bg-white rounded-lg shadow-sm p-4 flex flex-col min-h-0",
|
|
69647
|
-
isUptimeMode && showIdleBreakdownChart ? "lg:col-span-2" :
|
|
69910
|
+
isUptimeMode && showIdleBreakdownChart ? "lg:col-span-2" : isAssemblyCycleLayout || isUptimeMode ? "lg:col-span-10" : idleTimeVlmEnabled ? "lg:col-span-6" : "lg:col-span-8"
|
|
69648
69911
|
),
|
|
69649
69912
|
variants: chartCardVariants,
|
|
69650
69913
|
initial: "initial",
|
|
69651
69914
|
animate: "animate",
|
|
69652
69915
|
children: [
|
|
69653
69916
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-3 mb-4 flex-none", children: [
|
|
69654
|
-
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-bold text-gray-700", children: isUptimeMode ? "Machine Utilization" :
|
|
69655
|
-
|
|
69917
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-bold text-gray-700", children: isUptimeMode ? "Machine Utilization" : isAssemblyCycleLayout ? "Cycle time trend" : "Hourly Output" }),
|
|
69918
|
+
canToggleChartIdleTime && /* @__PURE__ */ jsxRuntime.jsx(
|
|
69656
69919
|
"button",
|
|
69657
69920
|
{
|
|
69658
69921
|
onClick: () => setShowChartIdleTime(!showChartIdleTime),
|
|
@@ -69677,19 +69940,19 @@ var WorkspaceDetailView = ({
|
|
|
69677
69940
|
timezone,
|
|
69678
69941
|
elapsedMinutes: elapsedShiftMinutes
|
|
69679
69942
|
}
|
|
69680
|
-
) : shouldShowCycleTimeUnavailableState ? cycleTimeUnavailableView : shouldShowCycleTimeChart ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
69943
|
+
) : isAssemblyCycleLayout ? shouldShowCycleTimeUnavailableState ? cycleTimeUnavailableView : shouldShowCycleTimeChart ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
69681
69944
|
CycleTimeOverTimeChart,
|
|
69682
69945
|
{
|
|
69683
69946
|
data: maskedCycleTimeChartData,
|
|
69684
|
-
idealCycleTime:
|
|
69685
|
-
shiftStart:
|
|
69686
|
-
shiftEnd:
|
|
69947
|
+
idealCycleTime: authoritativeCycleMetrics?.ideal_cycle_time || 0,
|
|
69948
|
+
shiftStart: authoritativeCycleMetrics?.shift_start || "",
|
|
69949
|
+
shiftEnd: authoritativeCycleMetrics?.shift_end || "",
|
|
69687
69950
|
xAxisMode: "hourly",
|
|
69688
69951
|
datasetKey: cycleTimeDatasetKey,
|
|
69689
69952
|
showIdleTime: showChartIdleTime,
|
|
69690
69953
|
idleTimeData: hourlyIdleMinutes
|
|
69691
69954
|
}
|
|
69692
|
-
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
69955
|
+
) : null : /* @__PURE__ */ jsxRuntime.jsx(
|
|
69693
69956
|
HourlyOutputChart2,
|
|
69694
69957
|
{
|
|
69695
69958
|
data: workspace.hourly_action_counts || [],
|
|
@@ -69707,7 +69970,7 @@ var WorkspaceDetailView = ({
|
|
|
69707
69970
|
]
|
|
69708
69971
|
}
|
|
69709
69972
|
),
|
|
69710
|
-
|
|
69973
|
+
showIdleBreakdownChart && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
69711
69974
|
motion.div,
|
|
69712
69975
|
{
|
|
69713
69976
|
className: clsx(
|
|
@@ -69733,7 +69996,7 @@ var WorkspaceDetailView = ({
|
|
|
69733
69996
|
]
|
|
69734
69997
|
}
|
|
69735
69998
|
),
|
|
69736
|
-
isUptimeMode ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: clsx("flex min-h-0", desktopBottomSectionClass), children: /* @__PURE__ */ jsxRuntime.jsx(UptimeMetricCards, { workspace, uptimePieData, className: "flex-1" }) }) :
|
|
69999
|
+
isUptimeMode ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: clsx("flex min-h-0", desktopBottomSectionClass), children: /* @__PURE__ */ jsxRuntime.jsx(UptimeMetricCards, { workspace, uptimePieData, className: "flex-1" }) }) : isAssemblyCycleLayout ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
69737
70000
|
WorkspaceCycleTimeMetricCards,
|
|
69738
70001
|
{
|
|
69739
70002
|
workspace,
|
|
@@ -69744,7 +70007,7 @@ var WorkspaceDetailView = ({
|
|
|
69744
70007
|
}
|
|
69745
70008
|
) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: clsx("flex min-h-0", desktopBottomSectionClass), children: /* @__PURE__ */ jsxRuntime.jsx(WorkspaceMetricCards, { workspace, legend: efficiencyLegend, className: "flex-1" }) })
|
|
69746
70009
|
] })
|
|
69747
|
-
] }),
|
|
70010
|
+
] }) }),
|
|
69748
70011
|
activeTab === "monthly_history" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-[calc(100vh-10rem)] overflow-y-auto px-2 sm:px-4 lg:px-0", children: [
|
|
69749
70012
|
usingFallbackData && !date && !shift && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-3 sm:mb-4 bg-amber-50 border border-amber-200 rounded-lg px-3 sm:px-4 py-2 sm:py-3 text-amber-800", children: /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs sm:text-sm font-medium flex items-center", children: [
|
|
69750
70013
|
/* @__PURE__ */ jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-4 w-4 sm:h-5 sm:w-5 mr-2", viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { fillRule: "evenodd", d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z", clipRule: "evenodd" }) }),
|
|
@@ -72376,7 +72639,7 @@ var normalizeLabel = (value) => {
|
|
|
72376
72639
|
const trimmed = value.trim();
|
|
72377
72640
|
return trimmed.length > 0 ? trimmed : void 0;
|
|
72378
72641
|
};
|
|
72379
|
-
var
|
|
72642
|
+
var toFiniteNumber2 = (value) => {
|
|
72380
72643
|
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
72381
72644
|
if (typeof value === "string" && value.trim().length > 0) {
|
|
72382
72645
|
const parsed = Number(value);
|
|
@@ -72410,7 +72673,7 @@ var formatImprovementPieceGain = (pcsGain) => {
|
|
|
72410
72673
|
var getPositiveImprovementGain = ({
|
|
72411
72674
|
estimated_gain_pieces
|
|
72412
72675
|
}) => {
|
|
72413
|
-
const issueGain =
|
|
72676
|
+
const issueGain = toFiniteNumber2(estimated_gain_pieces);
|
|
72414
72677
|
return {
|
|
72415
72678
|
pcsGain: issueGain !== null && issueGain > 0 ? issueGain : null
|
|
72416
72679
|
};
|
|
@@ -72418,7 +72681,7 @@ var getPositiveImprovementGain = ({
|
|
|
72418
72681
|
var getImprovementPcsGainSortValue = (input) => {
|
|
72419
72682
|
const { pcsGain } = getPositiveImprovementGain(input);
|
|
72420
72683
|
if (pcsGain !== null) return pcsGain;
|
|
72421
|
-
const raw =
|
|
72684
|
+
const raw = toFiniteNumber2(input.estimated_gain_pieces);
|
|
72422
72685
|
return raw ?? null;
|
|
72423
72686
|
};
|
|
72424
72687
|
var getImprovementDisplayMetadata = ({
|
|
@@ -72438,7 +72701,7 @@ var getImprovementDisplayMetadata = ({
|
|
|
72438
72701
|
metadataLabel: [workstationLabel, lineLabel, supervisorLabel].join(" \xB7 ")
|
|
72439
72702
|
};
|
|
72440
72703
|
};
|
|
72441
|
-
var
|
|
72704
|
+
var toFiniteNumber3 = (value) => {
|
|
72442
72705
|
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
72443
72706
|
if (typeof value === "string" && value.trim().length > 0) {
|
|
72444
72707
|
const parsed = Number(value);
|
|
@@ -72466,15 +72729,15 @@ var compareImprovementRecommendationPriority = (left, right) => {
|
|
|
72466
72729
|
if (leftIndustrial !== rightIndustrial) {
|
|
72467
72730
|
return rightIndustrial - leftIndustrial;
|
|
72468
72731
|
}
|
|
72469
|
-
const leftGain =
|
|
72470
|
-
const rightGain =
|
|
72732
|
+
const leftGain = toFiniteNumber3(left.estimated_gain_pieces);
|
|
72733
|
+
const rightGain = toFiniteNumber3(right.estimated_gain_pieces);
|
|
72471
72734
|
if (leftGain !== rightGain) {
|
|
72472
72735
|
if (leftGain === null) return 1;
|
|
72473
72736
|
if (rightGain === null) return -1;
|
|
72474
72737
|
return rightGain - leftGain;
|
|
72475
72738
|
}
|
|
72476
|
-
const leftRatio =
|
|
72477
|
-
const rightRatio =
|
|
72739
|
+
const leftRatio = toFiniteNumber3(left.gain_to_target_ratio);
|
|
72740
|
+
const rightRatio = toFiniteNumber3(right.gain_to_target_ratio);
|
|
72478
72741
|
if (leftRatio !== rightRatio) {
|
|
72479
72742
|
if (leftRatio === null) return 1;
|
|
72480
72743
|
if (rightRatio === null) return -1;
|
|
@@ -75779,6 +76042,7 @@ var EMPTY_OVERVIEW_POOREST_LINES = {
|
|
|
75779
76042
|
};
|
|
75780
76043
|
var EMPTY_OVERVIEW_TREND = {
|
|
75781
76044
|
shift_mode: "all",
|
|
76045
|
+
granularity: "day",
|
|
75782
76046
|
points: []
|
|
75783
76047
|
};
|
|
75784
76048
|
var EMPTY_IDLE_BREAKDOWN = [];
|
|
@@ -75851,8 +76115,11 @@ var normalizePoorestLines = (value) => ({
|
|
|
75851
76115
|
});
|
|
75852
76116
|
var normalizeTrend = (value) => ({
|
|
75853
76117
|
shift_mode: value?.shift_mode || "all",
|
|
76118
|
+
granularity: value?.granularity === "hour" ? "hour" : "day",
|
|
75854
76119
|
points: (value?.points || []).map((point) => ({
|
|
75855
76120
|
date: point?.date,
|
|
76121
|
+
label: point?.label,
|
|
76122
|
+
hour_index: normalizeNumber(point?.hour_index),
|
|
75856
76123
|
avg_efficiency: normalizeNumber(point?.avg_efficiency)
|
|
75857
76124
|
}))
|
|
75858
76125
|
});
|
|
@@ -76194,17 +76461,25 @@ var formatSignedIdleDuration = (seconds) => {
|
|
|
76194
76461
|
const sign = seconds > 0 ? "+" : "-";
|
|
76195
76462
|
return `${sign}${formatIdleDuration(Math.abs(seconds))}`;
|
|
76196
76463
|
};
|
|
76197
|
-
var formatComparisonWindow = (
|
|
76464
|
+
var formatComparisonWindow = ({
|
|
76465
|
+
currentDayCount,
|
|
76466
|
+
previousDayCount,
|
|
76467
|
+
comparisonStrategy,
|
|
76468
|
+
shiftMode
|
|
76469
|
+
}) => {
|
|
76198
76470
|
if (comparisonStrategy === "previous_full_week") return "last week";
|
|
76199
|
-
if (
|
|
76200
|
-
|
|
76471
|
+
if (comparisonStrategy === "matched_range" && currentDayCount === 1 && previousDayCount === 1) {
|
|
76472
|
+
return "previous day";
|
|
76473
|
+
}
|
|
76474
|
+
if (!previousDayCount || !Number.isFinite(previousDayCount)) return "previous range";
|
|
76475
|
+
return `previous ${previousDayCount} ${previousDayCount === 1 ? "day" : "days"}`;
|
|
76201
76476
|
};
|
|
76202
76477
|
var buildDeltaBadge = (delta, options) => {
|
|
76203
76478
|
if (delta === null || delta === void 0 || !Number.isFinite(delta)) {
|
|
76204
76479
|
return {
|
|
76205
76480
|
icon: null,
|
|
76206
|
-
className: "bg-slate-100 text-slate-
|
|
76207
|
-
text:
|
|
76481
|
+
className: "bg-slate-100 text-slate-400",
|
|
76482
|
+
text: "\u2014"
|
|
76208
76483
|
};
|
|
76209
76484
|
}
|
|
76210
76485
|
const direction = delta >= 0 ? "up" : "down";
|
|
@@ -76215,6 +76490,34 @@ var buildDeltaBadge = (delta, options) => {
|
|
|
76215
76490
|
text: `${options.formatter(delta)} vs ${options.comparisonLabel}`
|
|
76216
76491
|
};
|
|
76217
76492
|
};
|
|
76493
|
+
var normalizeShiftLabel = (shiftName, shiftMode) => {
|
|
76494
|
+
if (shiftMode === "all") {
|
|
76495
|
+
return "All Shifts";
|
|
76496
|
+
}
|
|
76497
|
+
const trimmedName = shiftName?.trim();
|
|
76498
|
+
if (trimmedName) {
|
|
76499
|
+
const normalizedName = trimmedName.toLowerCase();
|
|
76500
|
+
if (normalizedName === "day") return "Day Shift";
|
|
76501
|
+
if (normalizedName === "night") return "Night Shift";
|
|
76502
|
+
return /shift/i.test(trimmedName) ? trimmedName : `${trimmedName} Shift`;
|
|
76503
|
+
}
|
|
76504
|
+
if (shiftMode === "night") return "Night Shift";
|
|
76505
|
+
return "Day Shift";
|
|
76506
|
+
};
|
|
76507
|
+
var getShiftIcon = (shiftName, shiftMode) => {
|
|
76508
|
+
const normalizedName = (shiftName || "").toLowerCase();
|
|
76509
|
+
const normalizedMode = shiftMode || "day";
|
|
76510
|
+
if (normalizedMode === "all") {
|
|
76511
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
|
|
76512
|
+
}
|
|
76513
|
+
if (normalizedName.includes("day") || normalizedName.includes("morning") || normalizedMode === "day") {
|
|
76514
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
|
|
76515
|
+
}
|
|
76516
|
+
if (normalizedName.includes("night") || normalizedName.includes("evening") || normalizedMode === "night") {
|
|
76517
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" }) });
|
|
76518
|
+
}
|
|
76519
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
|
|
76520
|
+
};
|
|
76218
76521
|
var buildLineDeltaTone = (delta, comparisonLabel) => {
|
|
76219
76522
|
if (delta === null || delta === void 0 || !Number.isFinite(delta)) {
|
|
76220
76523
|
return {
|
|
@@ -76270,6 +76573,8 @@ var OperationsOverviewHeader = React141__namespace.default.memo(({
|
|
|
76270
76573
|
dateRange,
|
|
76271
76574
|
displayDateRange,
|
|
76272
76575
|
trendMode,
|
|
76576
|
+
isLiveScope,
|
|
76577
|
+
liveShiftName,
|
|
76273
76578
|
lineOptions,
|
|
76274
76579
|
supervisorOptions,
|
|
76275
76580
|
selectedSupervisorId,
|
|
@@ -76283,6 +76588,15 @@ var OperationsOverviewHeader = React141__namespace.default.memo(({
|
|
|
76283
76588
|
}) => {
|
|
76284
76589
|
bumpRenderCounter();
|
|
76285
76590
|
const subtitleRange = displayDateRange || dateRange;
|
|
76591
|
+
const showLiveShiftMeta = isLiveScope && trendMode !== "all";
|
|
76592
|
+
const liveShiftLabel = React141__namespace.default.useMemo(
|
|
76593
|
+
() => normalizeShiftLabel(liveShiftName, trendMode),
|
|
76594
|
+
[liveShiftName, trendMode]
|
|
76595
|
+
);
|
|
76596
|
+
const liveShiftIcon = React141__namespace.default.useMemo(
|
|
76597
|
+
() => getShiftIcon(liveShiftName, trendMode),
|
|
76598
|
+
[liveShiftName, trendMode]
|
|
76599
|
+
);
|
|
76286
76600
|
const [isFilterOpen, setIsFilterOpen] = React141__namespace.default.useState(false);
|
|
76287
76601
|
const [isLinesDropdownOpen, setIsLinesDropdownOpen] = React141__namespace.default.useState(false);
|
|
76288
76602
|
const filterRef = React141__namespace.default.useRef(null);
|
|
@@ -76399,9 +76713,25 @@ var OperationsOverviewHeader = React141__namespace.default.memo(({
|
|
|
76399
76713
|
className: "flex-shrink-0 -ml-1"
|
|
76400
76714
|
}
|
|
76401
76715
|
) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-8 flex-shrink-0" }),
|
|
76402
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex flex-col items-center justify-center", children: [
|
|
76403
|
-
/* @__PURE__ */ jsxRuntime.
|
|
76404
|
-
|
|
76716
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex flex-col items-center justify-center min-w-0", children: [
|
|
76717
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center gap-1.5 min-w-0 max-w-[240px]", children: [
|
|
76718
|
+
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-lg font-semibold text-gray-900 leading-tight text-center truncate", children: "Operations Overview" }),
|
|
76719
|
+
isLiveScope ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
76720
|
+
"div",
|
|
76721
|
+
{
|
|
76722
|
+
"data-testid": "operations-overview-live-indicator",
|
|
76723
|
+
className: "h-2 w-2 rounded-full bg-emerald-500 animate-pulse ring-2 ring-emerald-500/20 flex-shrink-0"
|
|
76724
|
+
}
|
|
76725
|
+
) : null
|
|
76726
|
+
] }),
|
|
76727
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1 flex flex-wrap items-center justify-center gap-x-2 gap-y-1 text-[11px] font-medium text-slate-500 min-w-0", children: [
|
|
76728
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-center", children: mobileSubtitle }),
|
|
76729
|
+
showLiveShiftMeta ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-slate-300", children: "|" }) : null,
|
|
76730
|
+
showLiveShiftMeta ? /* @__PURE__ */ jsxRuntime.jsx("span", { "data-testid": "operations-overview-live-meta", className: "inline-flex items-center gap-1.5 text-gray-600 min-w-0", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 justify-center truncate", children: [
|
|
76731
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-75 shrink-0", children: liveShiftIcon }),
|
|
76732
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: liveShiftLabel })
|
|
76733
|
+
] }) }) : null
|
|
76734
|
+
] })
|
|
76405
76735
|
] }),
|
|
76406
76736
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-shrink-0 flex items-center gap-1.5", children: [
|
|
76407
76737
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -76420,22 +76750,40 @@ var OperationsOverviewHeader = React141__namespace.default.memo(({
|
|
|
76420
76750
|
{
|
|
76421
76751
|
ref: mobileFilterButtonRef,
|
|
76422
76752
|
onClick: handleFilterToggle,
|
|
76423
|
-
className: `p-2 rounded-full transition-colors relative ${isFilterOpen || activeFilterCount > 0 ? "bg-
|
|
76753
|
+
className: `p-2 rounded-full transition-colors relative ${isFilterOpen || activeFilterCount > 0 ? "bg-slate-100 text-slate-700" : "active:bg-gray-100 text-slate-600"}`,
|
|
76424
76754
|
"aria-label": "Open filters",
|
|
76425
76755
|
children: [
|
|
76426
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Filter, { className:
|
|
76427
|
-
activeFilterCount > 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute -top-1 -right-1 flex items-center justify-center w-4 h-4 bg-
|
|
76756
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Filter, { className: "w-5 h-5" }),
|
|
76757
|
+
activeFilterCount > 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute -top-1 -right-1 flex items-center justify-center w-4 h-4 bg-slate-700 text-white text-[10px] rounded-full font-bold", children: activeFilterCount }) : null
|
|
76428
76758
|
]
|
|
76429
76759
|
}
|
|
76430
76760
|
)
|
|
76431
76761
|
] })
|
|
76432
76762
|
] }) }),
|
|
76433
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:block", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center relative min-h-[
|
|
76434
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute left-1/2 -translate-x-1/2 flex flex-col items-center
|
|
76435
|
-
/* @__PURE__ */ jsxRuntime.
|
|
76436
|
-
|
|
76763
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:block", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center relative min-h-[64px]", children: [
|
|
76764
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute left-1/2 -translate-x-1/2 flex flex-col items-center min-w-0 max-w-[min(70vw,720px)]", children: [
|
|
76765
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center gap-2 min-w-0 max-w-full", children: [
|
|
76766
|
+
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-2xl md:text-3xl lg:text-4xl font-semibold text-gray-900 tracking-tight leading-tight text-center truncate max-w-full", children: "Operations Overview" }),
|
|
76767
|
+
isLiveScope ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
76768
|
+
"div",
|
|
76769
|
+
{
|
|
76770
|
+
"data-testid": "operations-overview-live-indicator",
|
|
76771
|
+
className: "h-1.5 w-1.5 md:h-2 md:w-2 rounded-full bg-green-500 animate-pulse ring-2 ring-green-500/30 ring-offset-1 flex-shrink-0"
|
|
76772
|
+
}
|
|
76773
|
+
) : null
|
|
76774
|
+
] }),
|
|
76775
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex flex-wrap items-center justify-center gap-x-3 gap-y-1 text-xs sm:text-sm font-medium text-slate-500 text-center", children: [
|
|
76776
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: desktopSubtitle }),
|
|
76777
|
+
showLiveShiftMeta ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
76778
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-slate-300", children: "|" }),
|
|
76779
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { "data-testid": "operations-overview-live-meta", className: "inline-flex items-center gap-1.5 text-gray-600", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1.5 justify-center", children: [
|
|
76780
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-75", children: liveShiftIcon }),
|
|
76781
|
+
liveShiftLabel
|
|
76782
|
+
] }) })
|
|
76783
|
+
] }) : null
|
|
76784
|
+
] })
|
|
76437
76785
|
] }),
|
|
76438
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute right-0 flex items-center gap-3", children: [
|
|
76786
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute right-0 flex items-center gap-3 shrink-0", children: [
|
|
76439
76787
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
76440
76788
|
MonthlyRangeFilter_default,
|
|
76441
76789
|
{
|
|
@@ -76452,12 +76800,12 @@ var OperationsOverviewHeader = React141__namespace.default.memo(({
|
|
|
76452
76800
|
{
|
|
76453
76801
|
ref: filterButtonRef,
|
|
76454
76802
|
onClick: handleFilterToggle,
|
|
76455
|
-
className: `flex items-center gap-2 px-3 py-1.5 rounded-lg border text-sm font-medium transition-all shadow-sm ${isFilterOpen || activeFilterCount > 0 ? "border-
|
|
76803
|
+
className: `flex items-center gap-2 px-3 py-1.5 rounded-lg border text-sm font-medium transition-all shadow-sm ${isFilterOpen || activeFilterCount > 0 ? "border-slate-300 bg-slate-50 text-slate-700" : "border-slate-200 bg-white text-slate-600 hover:bg-slate-50 hover:text-slate-700"}`,
|
|
76456
76804
|
"aria-label": "Open filters",
|
|
76457
76805
|
children: [
|
|
76458
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Filter, { className: `w-[18px] h-[18px] ${activeFilterCount > 0 ? "text-
|
|
76806
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Filter, { className: `w-[18px] h-[18px] ${isFilterOpen || activeFilterCount > 0 ? "text-slate-500" : "text-slate-400"}` }),
|
|
76459
76807
|
"Filters",
|
|
76460
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: `w-4 h-4 ml-0.5 transition-transform duration-200 ${isFilterOpen ? "rotate-180" : ""}` })
|
|
76808
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: `w-4 h-4 ml-0.5 text-slate-400 transition-transform duration-200 ${isFilterOpen ? "rotate-180" : ""}` })
|
|
76461
76809
|
]
|
|
76462
76810
|
}
|
|
76463
76811
|
)
|
|
@@ -76585,11 +76933,18 @@ var OverviewSummaryCards = React141__namespace.default.memo(({ store }) => {
|
|
|
76585
76933
|
const snapshot = useOperationsOverviewSnapshot(store);
|
|
76586
76934
|
const showSnapshotSkeleton = snapshot.loading && !snapshot.hasLoadedOnce;
|
|
76587
76935
|
const comparisonLabel = React141__namespace.default.useMemo(() => {
|
|
76588
|
-
return formatComparisonWindow(
|
|
76589
|
-
scope.
|
|
76590
|
-
scope.
|
|
76591
|
-
|
|
76592
|
-
|
|
76936
|
+
return formatComparisonWindow({
|
|
76937
|
+
currentDayCount: scope.current_range?.day_count ?? null,
|
|
76938
|
+
previousDayCount: scope.previous_range?.day_count ?? null,
|
|
76939
|
+
comparisonStrategy: scope.comparison_strategy,
|
|
76940
|
+
shiftMode: scope.shift_mode
|
|
76941
|
+
});
|
|
76942
|
+
}, [
|
|
76943
|
+
scope.comparison_strategy,
|
|
76944
|
+
scope.current_range?.day_count,
|
|
76945
|
+
scope.previous_range?.day_count,
|
|
76946
|
+
scope.shift_mode
|
|
76947
|
+
]);
|
|
76593
76948
|
const [isIdleContributorsOpen, setIsIdleContributorsOpen] = React141__namespace.default.useState(false);
|
|
76594
76949
|
const [isIdleContributorsPinned, setIsIdleContributorsPinned] = React141__namespace.default.useState(false);
|
|
76595
76950
|
const idleContributorsRef = React141__namespace.default.useRef(null);
|
|
@@ -76679,10 +77034,17 @@ var OverviewSummaryCards = React141__namespace.default.memo(({ store }) => {
|
|
|
76679
77034
|
roundOne(snapshot.data.summary.plant_efficiency.current),
|
|
76680
77035
|
"%"
|
|
76681
77036
|
] }),
|
|
76682
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
76683
|
-
|
|
76684
|
-
|
|
76685
|
-
|
|
77037
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
77038
|
+
"div",
|
|
77039
|
+
{
|
|
77040
|
+
"data-testid": "operations-overview-efficiency-delta",
|
|
77041
|
+
className: `flex items-center gap-1 px-2.5 py-1 rounded-full ${plantEfficiencyBadge.className}`,
|
|
77042
|
+
children: [
|
|
77043
|
+
plantEfficiencyBadge.icon === "up" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : plantEfficiencyBadge.icon === "down" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDown, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : null,
|
|
77044
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-sm font-medium", children: plantEfficiencyBadge.text })
|
|
77045
|
+
]
|
|
77046
|
+
}
|
|
77047
|
+
)
|
|
76686
77048
|
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 text-sm text-slate-400", children: "No efficiency data available" })
|
|
76687
77049
|
] }),
|
|
76688
77050
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -76728,10 +77090,17 @@ var OverviewSummaryCards = React141__namespace.default.memo(({ store }) => {
|
|
|
76728
77090
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-1", children: /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-semibold text-gray-700", children: "Idle Time per Workstation" }) }),
|
|
76729
77091
|
showSnapshotSkeleton ? /* @__PURE__ */ jsxRuntime.jsx(OverviewMetricCardSkeleton, {}) : snapshot.data.summary.avg_idle_per_workstation?.current_seconds !== null && snapshot.data.summary.avg_idle_per_workstation?.current_seconds !== void 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2 sm:gap-3 mt-1", children: [
|
|
76730
77092
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-2xl sm:text-3xl font-bold text-slate-800 tracking-tight", children: formatIdleDuration(snapshot.data.summary.avg_idle_per_workstation.current_seconds) }),
|
|
76731
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
76732
|
-
|
|
76733
|
-
|
|
76734
|
-
|
|
77093
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
77094
|
+
"div",
|
|
77095
|
+
{
|
|
77096
|
+
"data-testid": "operations-overview-idle-delta",
|
|
77097
|
+
className: `flex items-center gap-1 px-2.5 py-1 rounded-full ${idleBadge.className}`,
|
|
77098
|
+
children: [
|
|
77099
|
+
idleBadge.icon === "up" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : idleBadge.icon === "down" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDown, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : null,
|
|
77100
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-sm font-medium", children: idleBadge.text })
|
|
77101
|
+
]
|
|
77102
|
+
}
|
|
77103
|
+
)
|
|
76735
77104
|
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 text-sm text-slate-400", children: "No idle time data available" })
|
|
76736
77105
|
]
|
|
76737
77106
|
}
|
|
@@ -76794,11 +77163,18 @@ var PoorestPerformersCard = React141__namespace.default.memo(({
|
|
|
76794
77163
|
}
|
|
76795
77164
|
}, [availableLineModes?.has_output, availableLineModes?.has_uptime, poorestLineMode]);
|
|
76796
77165
|
const comparisonLabel = React141__namespace.default.useMemo(() => {
|
|
76797
|
-
return formatComparisonWindow(
|
|
76798
|
-
scope.
|
|
76799
|
-
scope.
|
|
76800
|
-
|
|
76801
|
-
|
|
77166
|
+
return formatComparisonWindow({
|
|
77167
|
+
currentDayCount: scope.current_range?.day_count ?? null,
|
|
77168
|
+
previousDayCount: scope.previous_range?.day_count ?? null,
|
|
77169
|
+
comparisonStrategy: scope.comparison_strategy,
|
|
77170
|
+
shiftMode: scope.shift_mode
|
|
77171
|
+
});
|
|
77172
|
+
}, [
|
|
77173
|
+
scope.comparison_strategy,
|
|
77174
|
+
scope.current_range?.day_count,
|
|
77175
|
+
scope.previous_range?.day_count,
|
|
77176
|
+
scope.shift_mode
|
|
77177
|
+
]);
|
|
76802
77178
|
const showSnapshotSkeleton = snapshot.loading && !snapshot.hasLoadedOnce;
|
|
76803
77179
|
const mergedPoorestLines = React141__namespace.default.useMemo(() => {
|
|
76804
77180
|
const rows = snapshot.data.poorest_lines?.[poorestLineMode] || [];
|
|
@@ -76955,7 +77331,8 @@ IdleBreakdownCard.displayName = "IdleBreakdownCard";
|
|
|
76955
77331
|
var EfficiencyTrendCard = React141__namespace.default.memo(({
|
|
76956
77332
|
store,
|
|
76957
77333
|
dateRange,
|
|
76958
|
-
appTimezone
|
|
77334
|
+
appTimezone,
|
|
77335
|
+
hourlyLabelStartTime
|
|
76959
77336
|
}) => {
|
|
76960
77337
|
bumpRenderCounter();
|
|
76961
77338
|
const trend = useOperationsOverviewTrend(store);
|
|
@@ -76965,7 +77342,41 @@ var EfficiencyTrendCard = React141__namespace.default.memo(({
|
|
|
76965
77342
|
);
|
|
76966
77343
|
const isCurrentWeekToDateRange = dateRange.startKey === currentWeekRange.startKey && dateRange.endKey === currentWeekRange.endKey;
|
|
76967
77344
|
const showInitialSkeleton = trend.loading && trend.lastUpdated === null;
|
|
77345
|
+
const isHourlyTrend = trend.data.granularity === "hour";
|
|
76968
77346
|
const trendData = React141__namespace.default.useMemo(() => {
|
|
77347
|
+
if (isHourlyTrend) {
|
|
77348
|
+
return (trend.data.points || []).map((point, index) => ({
|
|
77349
|
+
name: (() => {
|
|
77350
|
+
const rawLabel = point.label?.trim() || "";
|
|
77351
|
+
if (rawLabel) {
|
|
77352
|
+
return rawLabel;
|
|
77353
|
+
}
|
|
77354
|
+
if (!hourlyLabelStartTime) {
|
|
77355
|
+
return "";
|
|
77356
|
+
}
|
|
77357
|
+
const hourIndex = typeof point.hour_index === "number" ? point.hour_index : index;
|
|
77358
|
+
const [hoursPart, minutesPart] = hourlyLabelStartTime.split(":");
|
|
77359
|
+
const startHours = Number(hoursPart);
|
|
77360
|
+
const startMinutes = Number(minutesPart);
|
|
77361
|
+
if (!Number.isFinite(startHours) || !Number.isFinite(startMinutes)) {
|
|
77362
|
+
return "";
|
|
77363
|
+
}
|
|
77364
|
+
const totalMinutes = startHours * 60 + startMinutes + hourIndex * 60;
|
|
77365
|
+
const hour24 = Math.floor(totalMinutes / 60) % 24;
|
|
77366
|
+
const minutes = totalMinutes % 60;
|
|
77367
|
+
const suffix = hour24 < 12 ? "AM" : "PM";
|
|
77368
|
+
const hour12 = hour24 % 12 || 12;
|
|
77369
|
+
if (minutes === 0) {
|
|
77370
|
+
return `${hour12} ${suffix}`;
|
|
77371
|
+
}
|
|
77372
|
+
return `${hour12}:${minutes.toString().padStart(2, "0")} ${suffix}`;
|
|
77373
|
+
})(),
|
|
77374
|
+
efficiency: (() => {
|
|
77375
|
+
const value = toNumber3(point.avg_efficiency);
|
|
77376
|
+
return value === null ? void 0 : value;
|
|
77377
|
+
})()
|
|
77378
|
+
}));
|
|
77379
|
+
}
|
|
76969
77380
|
const pointsByDate = new Map(
|
|
76970
77381
|
(trend.data.points || []).flatMap((point) => {
|
|
76971
77382
|
if (!point.date) return [];
|
|
@@ -77003,12 +77414,19 @@ var EfficiencyTrendCard = React141__namespace.default.memo(({
|
|
|
77003
77414
|
})()
|
|
77004
77415
|
};
|
|
77005
77416
|
});
|
|
77006
|
-
}, [currentWeekRange.startKey, isCurrentWeekToDateRange, trend.data.points]);
|
|
77417
|
+
}, [currentWeekRange.startKey, hourlyLabelStartTime, isCurrentWeekToDateRange, isHourlyTrend, trend.data.points]);
|
|
77007
77418
|
const trendTooltipLabelFormatter = React141__namespace.default.useCallback((label, payload) => {
|
|
77419
|
+
if (isHourlyTrend) return label;
|
|
77008
77420
|
const dayOfWeek = payload?.[0]?.payload?.dayOfWeek;
|
|
77009
77421
|
if (!dayOfWeek || typeof label !== "string") return label;
|
|
77010
77422
|
return `${label} (${dayOfWeek})`;
|
|
77011
|
-
}, []);
|
|
77423
|
+
}, [isHourlyTrend]);
|
|
77424
|
+
const trendXAxisTickFormatter = React141__namespace.default.useCallback((value, index) => {
|
|
77425
|
+
if (!isHourlyTrend) {
|
|
77426
|
+
return typeof value === "string" ? value : String(value ?? "");
|
|
77427
|
+
}
|
|
77428
|
+
return index % 2 === 0 ? typeof value === "string" ? value : String(value ?? "") : "";
|
|
77429
|
+
}, [isHourlyTrend]);
|
|
77012
77430
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-xl shadow-[0_2px_10px_-3px_rgba(6,81,237,0.1)] border border-slate-100 flex flex-col overflow-hidden text-left", children: [
|
|
77013
77431
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-5 flex-none flex justify-between items-center border-b border-slate-50/50", children: /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-semibold text-gray-700", children: "Efficiency Trend" }) }),
|
|
77014
77432
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-h-[250px] w-full p-4 pt-4 relative", children: showInitialSkeleton ? /* @__PURE__ */ jsxRuntime.jsx(OverviewChartSkeleton, {}) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 pb-2 pr-4 pl-1", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -77017,6 +77435,8 @@ var EfficiencyTrendCard = React141__namespace.default.memo(({
|
|
|
77017
77435
|
data: trendData,
|
|
77018
77436
|
lines: efficiencyLineConfig,
|
|
77019
77437
|
xAxisDataKey: "name",
|
|
77438
|
+
xAxisInterval: isHourlyTrend ? 0 : void 0,
|
|
77439
|
+
xAxisTickFormatter: trendXAxisTickFormatter,
|
|
77020
77440
|
yAxisUnit: "%",
|
|
77021
77441
|
yAxisDomain: [0, 100],
|
|
77022
77442
|
showLegend: false,
|
|
@@ -77162,7 +77582,8 @@ var useOperationsOverviewRefresh = ({
|
|
|
77162
77582
|
endKey,
|
|
77163
77583
|
trendMode,
|
|
77164
77584
|
comparisonStrategy,
|
|
77165
|
-
isLiveScope
|
|
77585
|
+
isLiveScope,
|
|
77586
|
+
enabled = true
|
|
77166
77587
|
}) => {
|
|
77167
77588
|
const lineIdsKey = React141__namespace.default.useMemo(() => lineIds.join(","), [lineIds]);
|
|
77168
77589
|
const scopeSignature = React141__namespace.default.useMemo(
|
|
@@ -77208,7 +77629,7 @@ var useOperationsOverviewRefresh = ({
|
|
|
77208
77629
|
}, []);
|
|
77209
77630
|
const runRefresh = React141__namespace.default.useCallback(
|
|
77210
77631
|
async (section, begin, onSuccess, onError, request, reason) => {
|
|
77211
|
-
if (!supabase || !companyId || lineIds.length === 0) return;
|
|
77632
|
+
if (!enabled || !supabase || !companyId || lineIds.length === 0) return;
|
|
77212
77633
|
const requestId = requestIdsRef.current[section] + 1;
|
|
77213
77634
|
requestIdsRef.current[section] = requestId;
|
|
77214
77635
|
controllersRef.current[section]?.abort();
|
|
@@ -77228,7 +77649,7 @@ var useOperationsOverviewRefresh = ({
|
|
|
77228
77649
|
onError(error instanceof Error ? error.message : `Failed to refresh ${section}`);
|
|
77229
77650
|
}
|
|
77230
77651
|
},
|
|
77231
|
-
[companyId, lineIds.length, supabase]
|
|
77652
|
+
[companyId, enabled, lineIds.length, supabase]
|
|
77232
77653
|
);
|
|
77233
77654
|
const refreshSnapshot = React141__namespace.default.useCallback(
|
|
77234
77655
|
async (reason) => {
|
|
@@ -77398,6 +77819,12 @@ var useOperationsOverviewRefresh = ({
|
|
|
77398
77819
|
});
|
|
77399
77820
|
}, [refreshAll, startPolling, stopPolling]);
|
|
77400
77821
|
React141__namespace.default.useEffect(() => {
|
|
77822
|
+
if (!enabled) {
|
|
77823
|
+
stopPolling("disabled");
|
|
77824
|
+
abortAll();
|
|
77825
|
+
store.reset();
|
|
77826
|
+
return;
|
|
77827
|
+
}
|
|
77401
77828
|
if (!supabase || !companyId || lineIds.length === 0) {
|
|
77402
77829
|
stopPolling("scope_invalid");
|
|
77403
77830
|
abortAll();
|
|
@@ -77405,9 +77832,9 @@ var useOperationsOverviewRefresh = ({
|
|
|
77405
77832
|
return;
|
|
77406
77833
|
}
|
|
77407
77834
|
void refreshAll("scope_change");
|
|
77408
|
-
}, [abortAll, companyId, lineIds.length, refreshAll, scopeSignature, stopPolling, store, supabase]);
|
|
77835
|
+
}, [abortAll, companyId, enabled, lineIds.length, refreshAll, scopeSignature, stopPolling, store, supabase]);
|
|
77409
77836
|
React141__namespace.default.useEffect(() => {
|
|
77410
|
-
if (!isLiveScope || !supabase || !companyId || lineIds.length === 0) {
|
|
77837
|
+
if (!enabled || !isLiveScope || !supabase || !companyId || lineIds.length === 0) {
|
|
77411
77838
|
isPageActiveRef.current = false;
|
|
77412
77839
|
stopPolling("live_scope_disabled");
|
|
77413
77840
|
return;
|
|
@@ -77463,11 +77890,119 @@ var useOperationsOverviewRefresh = ({
|
|
|
77463
77890
|
window.removeEventListener("pageshow", handlePageShow);
|
|
77464
77891
|
window.removeEventListener("pagehide", handlePageHide);
|
|
77465
77892
|
};
|
|
77466
|
-
}, [companyId, getIsPageActive, isLiveScope, lineIds.length, refreshFromResume, startPolling, stopPolling, supabase]);
|
|
77893
|
+
}, [companyId, enabled, getIsPageActive, isLiveScope, lineIds.length, refreshFromResume, startPolling, stopPolling, supabase]);
|
|
77894
|
+
};
|
|
77895
|
+
var parseTimeToMinutes3 = (value) => {
|
|
77896
|
+
if (!value) return null;
|
|
77897
|
+
const parts = value.split(":");
|
|
77898
|
+
if (parts.length < 2) return null;
|
|
77899
|
+
const hours = Number(parts[0]);
|
|
77900
|
+
const minutes = Number(parts[1]);
|
|
77901
|
+
if (!Number.isFinite(hours) || !Number.isFinite(minutes)) return null;
|
|
77902
|
+
if (hours < 0 || hours > 23 || minutes < 0 || minutes > 59) return null;
|
|
77903
|
+
return hours * 60 + minutes;
|
|
77904
|
+
};
|
|
77905
|
+
var normalizeShiftId = (value) => {
|
|
77906
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
77907
|
+
return value;
|
|
77908
|
+
}
|
|
77909
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
77910
|
+
const parsed = Number(value);
|
|
77911
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
77912
|
+
}
|
|
77913
|
+
return null;
|
|
77914
|
+
};
|
|
77915
|
+
var classifyShiftBucket = ({
|
|
77916
|
+
shiftName,
|
|
77917
|
+
shiftId,
|
|
77918
|
+
startTime,
|
|
77919
|
+
endTime
|
|
77920
|
+
}) => {
|
|
77921
|
+
const normalizedName = (shiftName || "").trim().toLowerCase();
|
|
77922
|
+
if (normalizedName) {
|
|
77923
|
+
if (["night", "graveyard", "evening"].some((keyword) => normalizedName.includes(keyword))) {
|
|
77924
|
+
return "night";
|
|
77925
|
+
}
|
|
77926
|
+
if (["day", "morning"].some((keyword) => normalizedName.includes(keyword))) {
|
|
77927
|
+
return "day";
|
|
77928
|
+
}
|
|
77929
|
+
}
|
|
77930
|
+
const startMinutes = parseTimeToMinutes3(startTime);
|
|
77931
|
+
const endMinutes = parseTimeToMinutes3(endTime);
|
|
77932
|
+
if (startMinutes !== null) {
|
|
77933
|
+
if (startMinutes >= 4 * 60 && startMinutes < 18 * 60) return "day";
|
|
77934
|
+
return "night";
|
|
77935
|
+
}
|
|
77936
|
+
if (endMinutes !== null) {
|
|
77937
|
+
if (endMinutes >= 6 * 60 && endMinutes <= 21 * 60) return "day";
|
|
77938
|
+
return "night";
|
|
77939
|
+
}
|
|
77940
|
+
const normalizedShiftId = normalizeShiftId(shiftId);
|
|
77941
|
+
if (normalizedShiftId === 0) return "day";
|
|
77942
|
+
if (normalizedShiftId === 1) return "night";
|
|
77943
|
+
return null;
|
|
77944
|
+
};
|
|
77945
|
+
var getShiftWindowsForConfig = (shiftConfig, timezone) => {
|
|
77946
|
+
if (shiftConfig?.shifts && shiftConfig.shifts.length > 0) {
|
|
77947
|
+
return shiftConfig.shifts.map((shift) => ({
|
|
77948
|
+
shiftId: shift.shiftId,
|
|
77949
|
+
shiftName: shift.shiftName,
|
|
77950
|
+
startTime: shift.startTime,
|
|
77951
|
+
endTime: shift.endTime
|
|
77952
|
+
}));
|
|
77953
|
+
}
|
|
77954
|
+
const windows = [];
|
|
77955
|
+
if (shiftConfig?.dayShift) {
|
|
77956
|
+
windows.push({
|
|
77957
|
+
shiftId: shiftConfig.dayShift.id ?? 0,
|
|
77958
|
+
shiftName: shiftConfig.dayShift.name || "Day Shift",
|
|
77959
|
+
startTime: shiftConfig.dayShift.startTime || "06:00",
|
|
77960
|
+
endTime: shiftConfig.dayShift.endTime || "18:00"
|
|
77961
|
+
});
|
|
77962
|
+
}
|
|
77963
|
+
if (shiftConfig?.nightShift) {
|
|
77964
|
+
windows.push({
|
|
77965
|
+
shiftId: shiftConfig.nightShift.id ?? 1,
|
|
77966
|
+
shiftName: shiftConfig.nightShift.name || "Night Shift",
|
|
77967
|
+
startTime: shiftConfig.nightShift.startTime || "18:00",
|
|
77968
|
+
endTime: shiftConfig.nightShift.endTime || "06:00"
|
|
77969
|
+
});
|
|
77970
|
+
}
|
|
77971
|
+
if (windows.length > 0) {
|
|
77972
|
+
return windows;
|
|
77973
|
+
}
|
|
77974
|
+
return [
|
|
77975
|
+
{
|
|
77976
|
+
shiftId: 0,
|
|
77977
|
+
shiftName: "Day Shift",
|
|
77978
|
+
startTime: "06:00",
|
|
77979
|
+
endTime: "18:00"
|
|
77980
|
+
},
|
|
77981
|
+
{
|
|
77982
|
+
shiftId: 1,
|
|
77983
|
+
shiftName: "Night Shift",
|
|
77984
|
+
startTime: "18:00",
|
|
77985
|
+
endTime: "06:00"
|
|
77986
|
+
}
|
|
77987
|
+
];
|
|
77988
|
+
};
|
|
77989
|
+
var normalizeShiftWindowMinutes = (startTime, endTime) => {
|
|
77990
|
+
const startMinutes = parseTimeToMinutes3(startTime);
|
|
77991
|
+
const endMinutesRaw = parseTimeToMinutes3(endTime);
|
|
77992
|
+
if (startMinutes === null || endMinutesRaw === null) {
|
|
77993
|
+
return null;
|
|
77994
|
+
}
|
|
77995
|
+
let endMinutes = endMinutesRaw;
|
|
77996
|
+
if (endMinutes <= startMinutes) {
|
|
77997
|
+
endMinutes += 24 * 60;
|
|
77998
|
+
}
|
|
77999
|
+
return { startMinutes, endMinutes };
|
|
77467
78000
|
};
|
|
77468
78001
|
var PlantHeadView = () => {
|
|
77469
78002
|
const supabase = useSupabase();
|
|
77470
78003
|
const entityConfig = useEntityConfig();
|
|
78004
|
+
const factoryViewId = entityConfig.factoryViewId || "factory";
|
|
78005
|
+
const staticShiftConfig = useShiftConfig();
|
|
77471
78006
|
const appTimezone = useAppTimezone() || "UTC";
|
|
77472
78007
|
const { navigate } = useNavigation();
|
|
77473
78008
|
const { accessibleLineIds } = useUserLineAccess();
|
|
@@ -77475,11 +78010,22 @@ var PlantHeadView = () => {
|
|
|
77475
78010
|
useHideMobileHeader(!!mobileMenuContext);
|
|
77476
78011
|
const storeRef = React141__namespace.default.useRef(createOperationsOverviewStore());
|
|
77477
78012
|
const store = storeRef.current;
|
|
77478
|
-
const
|
|
77479
|
-
|
|
78013
|
+
const fallbackOperationalDate = React141__namespace.default.useMemo(
|
|
78014
|
+
() => getOperationalDate(appTimezone),
|
|
78015
|
+
[appTimezone]
|
|
78016
|
+
);
|
|
78017
|
+
const [dateRange, setDateRange] = React141__namespace.default.useState(() => ({
|
|
78018
|
+
startKey: fallbackOperationalDate,
|
|
78019
|
+
endKey: fallbackOperationalDate
|
|
78020
|
+
}));
|
|
78021
|
+
const [usesThisWeekComparison, setUsesThisWeekComparison] = React141__namespace.default.useState(false);
|
|
77480
78022
|
const [trendMode, setTrendMode] = React141__namespace.default.useState("all");
|
|
77481
78023
|
const [selectedSupervisorId, setSelectedSupervisorId] = React141__namespace.default.useState("all");
|
|
77482
78024
|
const [selectedLineIds, setSelectedLineIds] = React141__namespace.default.useState([]);
|
|
78025
|
+
const [isInitialScopeReady, setIsInitialScopeReady] = React141__namespace.default.useState(false);
|
|
78026
|
+
const [shiftResolutionTick, setShiftResolutionTick] = React141__namespace.default.useState(0);
|
|
78027
|
+
const hasAutoInitializedScopeRef = React141__namespace.default.useRef(false);
|
|
78028
|
+
const hasUserAdjustedScopeRef = React141__namespace.default.useRef(false);
|
|
77483
78029
|
React141__namespace.default.useEffect(() => {
|
|
77484
78030
|
trackCorePageView("Operations Overview", {
|
|
77485
78031
|
dashboard_surface: "operations_overview"
|
|
@@ -77501,8 +78047,10 @@ var PlantHeadView = () => {
|
|
|
77501
78047
|
return dateRange;
|
|
77502
78048
|
}, [currentWeekDisplayRange, dateRange, isCurrentWeekToDateRange, usesThisWeekComparison]);
|
|
77503
78049
|
const normalizedLineIds = React141__namespace.default.useMemo(
|
|
77504
|
-
() => Array.from(new Set(
|
|
77505
|
-
|
|
78050
|
+
() => Array.from(new Set(
|
|
78051
|
+
(accessibleLineIds || []).filter(Boolean).filter((lineId) => lineId !== factoryViewId)
|
|
78052
|
+
)).sort(),
|
|
78053
|
+
[accessibleLineIds, factoryViewId]
|
|
77506
78054
|
);
|
|
77507
78055
|
const lineIdsKey = React141__namespace.default.useMemo(
|
|
77508
78056
|
() => normalizedLineIds.join(","),
|
|
@@ -77576,14 +78124,198 @@ var PlantHeadView = () => {
|
|
|
77576
78124
|
() => selectedLineIds.length > 0 ? selectedLineIds : normalizedLineIds,
|
|
77577
78125
|
[normalizedLineIds, selectedLineIds]
|
|
77578
78126
|
);
|
|
78127
|
+
const {
|
|
78128
|
+
shiftConfigMap,
|
|
78129
|
+
isLoading: isShiftConfigLoading
|
|
78130
|
+
} = useMultiLineShiftConfigs(scopedLineIds, staticShiftConfig);
|
|
78131
|
+
React141__namespace.default.useEffect(() => {
|
|
78132
|
+
if (scopedLineIds.length === 0 || isShiftConfigLoading) {
|
|
78133
|
+
return;
|
|
78134
|
+
}
|
|
78135
|
+
const intervalId = window.setInterval(() => {
|
|
78136
|
+
setShiftResolutionTick((previous) => previous + 1);
|
|
78137
|
+
}, 6e4);
|
|
78138
|
+
return () => {
|
|
78139
|
+
clearInterval(intervalId);
|
|
78140
|
+
};
|
|
78141
|
+
}, [isShiftConfigLoading, scopedLineIds.length]);
|
|
78142
|
+
const shiftResolutionNow = React141__namespace.default.useMemo(
|
|
78143
|
+
() => /* @__PURE__ */ new Date(),
|
|
78144
|
+
[shiftResolutionTick]
|
|
78145
|
+
);
|
|
78146
|
+
const earliestDayShiftStartTime = React141__namespace.default.useMemo(() => {
|
|
78147
|
+
const candidateStarts = [];
|
|
78148
|
+
scopedLineIds.forEach((lineId) => {
|
|
78149
|
+
const shiftConfig = shiftConfigMap.get(lineId) || staticShiftConfig;
|
|
78150
|
+
getShiftWindowsForConfig(shiftConfig).forEach((shift) => {
|
|
78151
|
+
const bucket = classifyShiftBucket({
|
|
78152
|
+
shiftName: shift.shiftName,
|
|
78153
|
+
shiftId: shift.shiftId,
|
|
78154
|
+
startTime: shift.startTime,
|
|
78155
|
+
endTime: shift.endTime
|
|
78156
|
+
});
|
|
78157
|
+
const startMinutes = parseTimeToMinutes3(shift.startTime);
|
|
78158
|
+
if (bucket === "day" && startMinutes !== null) {
|
|
78159
|
+
candidateStarts.push(startMinutes);
|
|
78160
|
+
}
|
|
78161
|
+
});
|
|
78162
|
+
});
|
|
78163
|
+
if (candidateStarts.length === 0) {
|
|
78164
|
+
scopedLineIds.forEach((lineId) => {
|
|
78165
|
+
const shiftConfig = shiftConfigMap.get(lineId) || staticShiftConfig;
|
|
78166
|
+
getShiftWindowsForConfig(shiftConfig).forEach((shift) => {
|
|
78167
|
+
const startMinutes = parseTimeToMinutes3(shift.startTime);
|
|
78168
|
+
if (startMinutes !== null) {
|
|
78169
|
+
candidateStarts.push(startMinutes);
|
|
78170
|
+
}
|
|
78171
|
+
});
|
|
78172
|
+
});
|
|
78173
|
+
}
|
|
78174
|
+
if (candidateStarts.length === 0) {
|
|
78175
|
+
return "06:00";
|
|
78176
|
+
}
|
|
78177
|
+
const earliestMinutes = Math.min(...candidateStarts);
|
|
78178
|
+
const hours = Math.floor(earliestMinutes / 60);
|
|
78179
|
+
const minutes = earliestMinutes % 60;
|
|
78180
|
+
return `${hours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}`;
|
|
78181
|
+
}, [appTimezone, scopedLineIds, shiftConfigMap, staticShiftConfig]);
|
|
78182
|
+
const resolvedOperationalToday = React141__namespace.default.useMemo(
|
|
78183
|
+
() => getOperationalDate(appTimezone, shiftResolutionNow, earliestDayShiftStartTime),
|
|
78184
|
+
[appTimezone, earliestDayShiftStartTime, shiftResolutionNow]
|
|
78185
|
+
);
|
|
78186
|
+
const activeLineShiftStates = React141__namespace.default.useMemo(() => {
|
|
78187
|
+
return scopedLineIds.flatMap((lineId) => {
|
|
78188
|
+
const shiftConfig = shiftConfigMap.get(lineId) || staticShiftConfig;
|
|
78189
|
+
const activeShift = getActiveShift(appTimezone, shiftConfig, shiftResolutionNow);
|
|
78190
|
+
if (!activeShift) {
|
|
78191
|
+
return [];
|
|
78192
|
+
}
|
|
78193
|
+
const trendBucket = classifyShiftBucket({
|
|
78194
|
+
shiftName: activeShift.shiftName,
|
|
78195
|
+
shiftId: activeShift.shiftId,
|
|
78196
|
+
startTime: activeShift.startTime,
|
|
78197
|
+
endTime: activeShift.endTime
|
|
78198
|
+
});
|
|
78199
|
+
if (!trendBucket || trendBucket === "all") {
|
|
78200
|
+
return [];
|
|
78201
|
+
}
|
|
78202
|
+
return [{
|
|
78203
|
+
lineId,
|
|
78204
|
+
trendMode: trendBucket,
|
|
78205
|
+
shiftId: activeShift.shiftId,
|
|
78206
|
+
shiftName: activeShift.shiftName || null,
|
|
78207
|
+
startTime: activeShift.startTime || null,
|
|
78208
|
+
endTime: activeShift.endTime || null,
|
|
78209
|
+
date: activeShift.date
|
|
78210
|
+
}];
|
|
78211
|
+
});
|
|
78212
|
+
}, [appTimezone, scopedLineIds, shiftConfigMap, shiftResolutionNow, staticShiftConfig]);
|
|
78213
|
+
const hasActiveDayShiftLine = React141__namespace.default.useMemo(
|
|
78214
|
+
() => activeLineShiftStates.some((shift) => shift.trendMode === "day" && shift.date === resolvedOperationalToday),
|
|
78215
|
+
[activeLineShiftStates, resolvedOperationalToday]
|
|
78216
|
+
);
|
|
78217
|
+
const hasActiveNightShiftLine = React141__namespace.default.useMemo(
|
|
78218
|
+
() => activeLineShiftStates.some((shift) => shift.trendMode === "night" && shift.date === resolvedOperationalToday),
|
|
78219
|
+
[activeLineShiftStates, resolvedOperationalToday]
|
|
78220
|
+
);
|
|
78221
|
+
const resolvedTrendMode = isInitialScopeReady ? trendMode : "all";
|
|
78222
|
+
const hourlyWindowStartTime = React141__namespace.default.useMemo(() => {
|
|
78223
|
+
if (scopedLineIds.length === 0) {
|
|
78224
|
+
return null;
|
|
78225
|
+
}
|
|
78226
|
+
const startCandidates = [];
|
|
78227
|
+
const endCandidates = [];
|
|
78228
|
+
scopedLineIds.forEach((lineId) => {
|
|
78229
|
+
const shiftConfig = shiftConfigMap.get(lineId) || staticShiftConfig;
|
|
78230
|
+
getShiftWindowsForConfig(shiftConfig).forEach((shift) => {
|
|
78231
|
+
const bucket = classifyShiftBucket({
|
|
78232
|
+
shiftName: shift.shiftName,
|
|
78233
|
+
shiftId: shift.shiftId,
|
|
78234
|
+
startTime: shift.startTime,
|
|
78235
|
+
endTime: shift.endTime
|
|
78236
|
+
});
|
|
78237
|
+
if (resolvedTrendMode !== "all" && bucket !== resolvedTrendMode) {
|
|
78238
|
+
return;
|
|
78239
|
+
}
|
|
78240
|
+
const normalizedWindow = normalizeShiftWindowMinutes(shift.startTime, shift.endTime);
|
|
78241
|
+
if (!normalizedWindow) {
|
|
78242
|
+
return;
|
|
78243
|
+
}
|
|
78244
|
+
startCandidates.push(normalizedWindow.startMinutes);
|
|
78245
|
+
endCandidates.push(normalizedWindow.endMinutes);
|
|
78246
|
+
});
|
|
78247
|
+
});
|
|
78248
|
+
if (resolvedTrendMode === "all") {
|
|
78249
|
+
const dayStartCandidates = startCandidates.length > 0 ? scopedLineIds.flatMap((lineId) => {
|
|
78250
|
+
const shiftConfig = shiftConfigMap.get(lineId) || staticShiftConfig;
|
|
78251
|
+
return getShiftWindowsForConfig(shiftConfig).map((shift) => {
|
|
78252
|
+
const bucket = classifyShiftBucket({
|
|
78253
|
+
shiftName: shift.shiftName,
|
|
78254
|
+
shiftId: shift.shiftId,
|
|
78255
|
+
startTime: shift.startTime,
|
|
78256
|
+
endTime: shift.endTime
|
|
78257
|
+
});
|
|
78258
|
+
return bucket === "day" ? parseTimeToMinutes3(shift.startTime) : null;
|
|
78259
|
+
}).filter((value) => value !== null);
|
|
78260
|
+
}) : [];
|
|
78261
|
+
if (dayStartCandidates.length > 0) {
|
|
78262
|
+
startCandidates.splice(0, startCandidates.length, ...dayStartCandidates);
|
|
78263
|
+
}
|
|
78264
|
+
}
|
|
78265
|
+
if (startCandidates.length === 0 || endCandidates.length === 0) {
|
|
78266
|
+
return null;
|
|
78267
|
+
}
|
|
78268
|
+
const earliestMinutes = Math.min(...startCandidates);
|
|
78269
|
+
const hours = Math.floor(earliestMinutes / 60);
|
|
78270
|
+
const minutes = earliestMinutes % 60;
|
|
78271
|
+
return `${hours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}`;
|
|
78272
|
+
}, [appTimezone, resolvedTrendMode, scopedLineIds, shiftConfigMap, staticShiftConfig]);
|
|
78273
|
+
const isShiftScopeResolved = React141__namespace.default.useMemo(
|
|
78274
|
+
() => !isShiftConfigLoading,
|
|
78275
|
+
[isShiftConfigLoading]
|
|
78276
|
+
);
|
|
77579
78277
|
const initializedTimezoneRef = React141__namespace.default.useRef(appTimezone);
|
|
77580
78278
|
React141__namespace.default.useEffect(() => {
|
|
77581
78279
|
if (initializedTimezoneRef.current === appTimezone) return;
|
|
77582
|
-
|
|
77583
|
-
|
|
78280
|
+
hasAutoInitializedScopeRef.current = false;
|
|
78281
|
+
hasUserAdjustedScopeRef.current = false;
|
|
78282
|
+
setDateRange({
|
|
78283
|
+
startKey: fallbackOperationalDate,
|
|
78284
|
+
endKey: fallbackOperationalDate
|
|
78285
|
+
});
|
|
78286
|
+
setTrendMode("all");
|
|
78287
|
+
setUsesThisWeekComparison(false);
|
|
78288
|
+
setIsInitialScopeReady(false);
|
|
77584
78289
|
initializedTimezoneRef.current = appTimezone;
|
|
77585
|
-
}, [appTimezone]);
|
|
78290
|
+
}, [appTimezone, fallbackOperationalDate]);
|
|
78291
|
+
React141__namespace.default.useEffect(() => {
|
|
78292
|
+
if (hasAutoInitializedScopeRef.current || hasUserAdjustedScopeRef.current) {
|
|
78293
|
+
return;
|
|
78294
|
+
}
|
|
78295
|
+
if (scopedLineIds.length === 0) {
|
|
78296
|
+
return;
|
|
78297
|
+
}
|
|
78298
|
+
if (!isShiftScopeResolved) {
|
|
78299
|
+
return;
|
|
78300
|
+
}
|
|
78301
|
+
setDateRange((previous) => {
|
|
78302
|
+
const nextStartKey = resolvedOperationalToday || fallbackOperationalDate;
|
|
78303
|
+
if (previous.startKey === nextStartKey && previous.endKey === nextStartKey) {
|
|
78304
|
+
return previous;
|
|
78305
|
+
}
|
|
78306
|
+
return {
|
|
78307
|
+
startKey: nextStartKey,
|
|
78308
|
+
endKey: nextStartKey
|
|
78309
|
+
};
|
|
78310
|
+
});
|
|
78311
|
+
setTrendMode("all");
|
|
78312
|
+
setUsesThisWeekComparison(false);
|
|
78313
|
+
hasAutoInitializedScopeRef.current = true;
|
|
78314
|
+
setIsInitialScopeReady(true);
|
|
78315
|
+
}, [fallbackOperationalDate, isShiftScopeResolved, resolvedOperationalToday, scopedLineIds.length]);
|
|
77586
78316
|
const handleDateRangeChange = React141__namespace.default.useCallback((range, meta) => {
|
|
78317
|
+
hasUserAdjustedScopeRef.current = true;
|
|
78318
|
+
setIsInitialScopeReady(true);
|
|
77587
78319
|
trackCoreEvent("Operations Overview Date Range Changed", {
|
|
77588
78320
|
start_date: range.startKey,
|
|
77589
78321
|
end_date: range.endKey
|
|
@@ -77600,6 +78332,8 @@ var PlantHeadView = () => {
|
|
|
77600
78332
|
});
|
|
77601
78333
|
}, []);
|
|
77602
78334
|
const handleTrendModeChange = React141__namespace.default.useCallback((mode) => {
|
|
78335
|
+
hasUserAdjustedScopeRef.current = true;
|
|
78336
|
+
setIsInitialScopeReady(true);
|
|
77603
78337
|
setTrendMode(mode);
|
|
77604
78338
|
}, []);
|
|
77605
78339
|
const handleSelectedLineIdsChange = React141__namespace.default.useCallback((lineIds) => {
|
|
@@ -77626,15 +78360,6 @@ var PlantHeadView = () => {
|
|
|
77626
78360
|
params.set("rangeEnd", dateRange.endKey);
|
|
77627
78361
|
return `/kpis/${lineId}?${params.toString()}`;
|
|
77628
78362
|
}, [dateRange.endKey, dateRange.startKey]);
|
|
77629
|
-
const handleOpenLineMonthlyHistory = React141__namespace.default.useCallback((lineId, lineName) => {
|
|
77630
|
-
trackCoreEvent("Operations Overview Line Clicked", {
|
|
77631
|
-
line_id: lineId,
|
|
77632
|
-
line_name: lineName,
|
|
77633
|
-
range_start: dateRange.startKey,
|
|
77634
|
-
range_end: dateRange.endKey
|
|
77635
|
-
});
|
|
77636
|
-
navigate(buildLineMonthlyHistoryUrl(lineId));
|
|
77637
|
-
}, [buildLineMonthlyHistoryUrl, dateRange.endKey, dateRange.startKey, navigate]);
|
|
77638
78363
|
const handleViewAllPoorestPerformers = React141__namespace.default.useCallback(() => {
|
|
77639
78364
|
trackCoreEvent("Operations Overview View All Clicked", { section: "poorest_performers" });
|
|
77640
78365
|
navigate("/kpis?tab=leaderboard");
|
|
@@ -77660,16 +78385,65 @@ var PlantHeadView = () => {
|
|
|
77660
78385
|
}
|
|
77661
78386
|
return void 0;
|
|
77662
78387
|
}, [isCurrentWeekToDateRange, usesThisWeekComparison]);
|
|
78388
|
+
const effectiveDateRange = React141__namespace.default.useMemo(() => {
|
|
78389
|
+
if (isInitialScopeReady) {
|
|
78390
|
+
return dateRange;
|
|
78391
|
+
}
|
|
78392
|
+
const nextStartKey = resolvedOperationalToday || fallbackOperationalDate;
|
|
78393
|
+
return {
|
|
78394
|
+
startKey: nextStartKey,
|
|
78395
|
+
endKey: nextStartKey
|
|
78396
|
+
};
|
|
78397
|
+
}, [dateRange, fallbackOperationalDate, isInitialScopeReady, resolvedOperationalToday]);
|
|
78398
|
+
const effectiveTrendMode = React141__namespace.default.useMemo(
|
|
78399
|
+
() => resolvedTrendMode,
|
|
78400
|
+
[resolvedTrendMode]
|
|
78401
|
+
);
|
|
78402
|
+
const hourlyLabelStartTime = React141__namespace.default.useMemo(() => {
|
|
78403
|
+
if (scopedLineIds.length === 0) {
|
|
78404
|
+
return null;
|
|
78405
|
+
}
|
|
78406
|
+
return hourlyWindowStartTime;
|
|
78407
|
+
}, [hourlyWindowStartTime, scopedLineIds.length]);
|
|
78408
|
+
const isSingleDayScope = React141__namespace.default.useMemo(
|
|
78409
|
+
() => effectiveDateRange.startKey === effectiveDateRange.endKey,
|
|
78410
|
+
[effectiveDateRange.endKey, effectiveDateRange.startKey]
|
|
78411
|
+
);
|
|
78412
|
+
const isLiveScope = React141__namespace.default.useMemo(
|
|
78413
|
+
() => isSingleDayScope && effectiveDateRange.startKey === resolvedOperationalToday && (effectiveTrendMode === "all" || effectiveTrendMode === "day" && hasActiveDayShiftLine || effectiveTrendMode === "night" && hasActiveNightShiftLine),
|
|
78414
|
+
[
|
|
78415
|
+
effectiveDateRange.startKey,
|
|
78416
|
+
effectiveTrendMode,
|
|
78417
|
+
hasActiveDayShiftLine,
|
|
78418
|
+
hasActiveNightShiftLine,
|
|
78419
|
+
isSingleDayScope,
|
|
78420
|
+
resolvedOperationalToday
|
|
78421
|
+
]
|
|
78422
|
+
);
|
|
78423
|
+
const handleOpenLineDetails = React141__namespace.default.useCallback((lineId, lineName) => {
|
|
78424
|
+
trackCoreEvent("Operations Overview Line Clicked", {
|
|
78425
|
+
line_id: lineId,
|
|
78426
|
+
line_name: lineName,
|
|
78427
|
+
range_start: dateRange.startKey,
|
|
78428
|
+
range_end: dateRange.endKey
|
|
78429
|
+
});
|
|
78430
|
+
if (isLiveScope) {
|
|
78431
|
+
navigate(`/kpis/${lineId}?returnTo=${encodeURIComponent("/")}`);
|
|
78432
|
+
return;
|
|
78433
|
+
}
|
|
78434
|
+
navigate(buildLineMonthlyHistoryUrl(lineId));
|
|
78435
|
+
}, [buildLineMonthlyHistoryUrl, dateRange.endKey, dateRange.startKey, isLiveScope, navigate]);
|
|
77663
78436
|
useOperationsOverviewRefresh({
|
|
77664
78437
|
store,
|
|
77665
78438
|
supabase,
|
|
77666
78439
|
companyId: entityConfig.companyId,
|
|
77667
78440
|
lineIds: scopedLineIds,
|
|
77668
|
-
startKey:
|
|
77669
|
-
endKey:
|
|
77670
|
-
trendMode,
|
|
78441
|
+
startKey: effectiveDateRange.startKey,
|
|
78442
|
+
endKey: effectiveDateRange.endKey,
|
|
78443
|
+
trendMode: effectiveTrendMode,
|
|
77671
78444
|
comparisonStrategy,
|
|
77672
|
-
isLiveScope
|
|
78445
|
+
isLiveScope,
|
|
78446
|
+
enabled: scopedLineIds.length > 0 && isShiftScopeResolved
|
|
77673
78447
|
});
|
|
77674
78448
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col min-h-screen bg-slate-50 w-full font-sans", children: [
|
|
77675
78449
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -77678,6 +78452,8 @@ var PlantHeadView = () => {
|
|
|
77678
78452
|
dateRange,
|
|
77679
78453
|
displayDateRange: headerDateRange,
|
|
77680
78454
|
trendMode,
|
|
78455
|
+
isLiveScope,
|
|
78456
|
+
liveShiftName: isLiveScope && trendMode !== "all" ? trendMode : null,
|
|
77681
78457
|
lineOptions,
|
|
77682
78458
|
supervisorOptions,
|
|
77683
78459
|
selectedSupervisorId,
|
|
@@ -77700,7 +78476,7 @@ var PlantHeadView = () => {
|
|
|
77700
78476
|
store,
|
|
77701
78477
|
supervisorsByLineId,
|
|
77702
78478
|
onViewAll: handleViewAllPoorestPerformers,
|
|
77703
|
-
onLineClick:
|
|
78479
|
+
onLineClick: handleOpenLineDetails
|
|
77704
78480
|
}
|
|
77705
78481
|
),
|
|
77706
78482
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -77717,7 +78493,8 @@ var PlantHeadView = () => {
|
|
|
77717
78493
|
{
|
|
77718
78494
|
store,
|
|
77719
78495
|
dateRange,
|
|
77720
|
-
appTimezone
|
|
78496
|
+
appTimezone,
|
|
78497
|
+
hourlyLabelStartTime
|
|
77721
78498
|
}
|
|
77722
78499
|
),
|
|
77723
78500
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -78507,6 +79284,7 @@ exports.formatRelativeTime = formatRelativeTime;
|
|
|
78507
79284
|
exports.formatTimeInZone = formatTimeInZone;
|
|
78508
79285
|
exports.fromUrlFriendlyName = fromUrlFriendlyName;
|
|
78509
79286
|
exports.getActionDisplayName = getActionDisplayName;
|
|
79287
|
+
exports.getActiveShift = getActiveShift;
|
|
78510
79288
|
exports.getAllLineDisplayNames = getAllLineDisplayNames;
|
|
78511
79289
|
exports.getAllThreadMessages = getAllThreadMessages;
|
|
78512
79290
|
exports.getAllWorkspaceDisplayNamesAsync = getAllWorkspaceDisplayNamesAsync;
|
|
@@ -78578,6 +79356,7 @@ exports.isEfficiencyOnTrack = isEfficiencyOnTrack;
|
|
|
78578
79356
|
exports.isFactoryScopedRole = isFactoryScopedRole;
|
|
78579
79357
|
exports.isFullMonthRange = isFullMonthRange;
|
|
78580
79358
|
exports.isLegacyConfiguration = isLegacyConfiguration;
|
|
79359
|
+
exports.isLoopbackHostname = isLoopbackHostname;
|
|
78581
79360
|
exports.isPrefetchError = isPrefetchError;
|
|
78582
79361
|
exports.isRecentFlowVideoGridMetricMode = isRecentFlowVideoGridMetricMode;
|
|
78583
79362
|
exports.isSafari = isSafari;
|
|
@@ -78619,6 +79398,7 @@ exports.resetSubscriptionManager = resetSubscriptionManager;
|
|
|
78619
79398
|
exports.s3VideoPreloader = s3VideoPreloader;
|
|
78620
79399
|
exports.setSentryUserContext = setSentryUserContext;
|
|
78621
79400
|
exports.setSentryWorkspaceContext = setSentryWorkspaceContext;
|
|
79401
|
+
exports.shouldEnableLocalDevTestLogin = shouldEnableLocalDevTestLogin;
|
|
78622
79402
|
exports.shuffleArray = shuffleArray;
|
|
78623
79403
|
exports.simulateApiDelay = simulateApiDelay;
|
|
78624
79404
|
exports.skuService = skuService;
|