@optifye/dashboard-core 6.11.14 → 6.11.16
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 +36 -3
- package/dist/index.d.mts +40 -4
- package/dist/index.d.ts +40 -4
- package/dist/index.js +1437 -603
- package/dist/index.mjs +1437 -605
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -11771,6 +11771,9 @@ var toWorkspaceDetailedMetrics = ({
|
|
|
11771
11771
|
const idealOutput = coerceNumber(data.ideal_output ?? data.ideal_output_until_now, 0);
|
|
11772
11772
|
const outputDifference = totalActions - idealOutput;
|
|
11773
11773
|
const hourlyCycleTimes = Array.isArray(data.hourly_cycle_times) ? data.hourly_cycle_times.map((value) => coerceNumber(value, 0)) : [];
|
|
11774
|
+
const cycleCompletionClipCount = data.cycle_completion_clip_count === null || data.cycle_completion_clip_count === void 0 ? null : coerceNumber(data.cycle_completion_clip_count, 0);
|
|
11775
|
+
const cycleTimeDataStatus = data.cycle_time_data_status === "missing_clips" ? "missing_clips" : data.cycle_time_data_status === "available" ? "available" : null;
|
|
11776
|
+
const cycleTimeTimezone = typeof data.cycle_time_timezone === "string" ? data.cycle_time_timezone : null;
|
|
11774
11777
|
const totalWorkspacesValue = coerceNumber(
|
|
11775
11778
|
data.total_workspaces ?? lineMetricsById?.[data.line_id || ""]?.total_workspaces ?? workspaceConfig.totalWorkspaces,
|
|
11776
11779
|
0
|
|
@@ -11818,6 +11821,9 @@ var toWorkspaceDetailedMetrics = ({
|
|
|
11818
11821
|
total_actions: totalActions,
|
|
11819
11822
|
hourly_action_counts: hourlyActionCounts,
|
|
11820
11823
|
hourly_cycle_times: hourlyCycleTimes,
|
|
11824
|
+
cycle_completion_clip_count: cycleCompletionClipCount,
|
|
11825
|
+
cycle_time_data_status: cycleTimeDataStatus,
|
|
11826
|
+
cycle_time_timezone: cycleTimeTimezone,
|
|
11821
11827
|
workspace_rank: coerceNumber(data.workspace_rank, 0),
|
|
11822
11828
|
total_workspaces: totalWorkspacesValue,
|
|
11823
11829
|
ideal_output_until_now: idealOutput,
|
|
@@ -12858,6 +12864,7 @@ var useShiftGroups = ({
|
|
|
12858
12864
|
}) => {
|
|
12859
12865
|
const [shiftGroups, setShiftGroups] = React141.useState([]);
|
|
12860
12866
|
const [shiftGroupsKey, setShiftGroupsKey] = React141.useState("");
|
|
12867
|
+
const [hasComputed, setHasComputed] = React141.useState(false);
|
|
12861
12868
|
const lastKeyRef = React141.useRef("");
|
|
12862
12869
|
const mapRef = React141.useRef(shiftConfigMap);
|
|
12863
12870
|
React141.useEffect(() => {
|
|
@@ -12868,6 +12875,7 @@ var useShiftGroups = ({
|
|
|
12868
12875
|
lastKeyRef.current = "";
|
|
12869
12876
|
setShiftGroups([]);
|
|
12870
12877
|
setShiftGroupsKey("");
|
|
12878
|
+
setHasComputed(false);
|
|
12871
12879
|
return;
|
|
12872
12880
|
}
|
|
12873
12881
|
let isMounted = true;
|
|
@@ -12880,6 +12888,7 @@ var useShiftGroups = ({
|
|
|
12880
12888
|
setShiftGroups(groups);
|
|
12881
12889
|
setShiftGroupsKey(key);
|
|
12882
12890
|
}
|
|
12891
|
+
setHasComputed(true);
|
|
12883
12892
|
};
|
|
12884
12893
|
compute();
|
|
12885
12894
|
const intervalId = setInterval(compute, pollIntervalMs);
|
|
@@ -12888,7 +12897,7 @@ var useShiftGroups = ({
|
|
|
12888
12897
|
clearInterval(intervalId);
|
|
12889
12898
|
};
|
|
12890
12899
|
}, [enabled, shiftConfigMap.size, timezone, pollIntervalMs]);
|
|
12891
|
-
return { shiftGroups, shiftGroupsKey };
|
|
12900
|
+
return { shiftGroups, shiftGroupsKey, hasComputed };
|
|
12892
12901
|
};
|
|
12893
12902
|
|
|
12894
12903
|
// src/lib/types/efficiencyLegend.ts
|
|
@@ -12950,52 +12959,6 @@ function getEfficiencyTextColorClasses(efficiency, legend = DEFAULT_EFFICIENCY_L
|
|
|
12950
12959
|
}
|
|
12951
12960
|
}
|
|
12952
12961
|
|
|
12953
|
-
// src/lib/hooks/useDashboardMetrics.recentFlow.ts
|
|
12954
|
-
var isFiniteNumber = (value) => typeof value === "number" && Number.isFinite(value);
|
|
12955
|
-
var getWorkspaceRecentFlowCacheKey = (workspace) => {
|
|
12956
|
-
const workspaceKey = workspace.workspace_uuid || workspace.workspace_name || "unknown";
|
|
12957
|
-
return `${workspaceKey}|${workspace.date}|${workspace.shift_id}`;
|
|
12958
|
-
};
|
|
12959
|
-
var toRecentFlowSnapshot = (workspace) => {
|
|
12960
|
-
if (!isFiniteNumber(workspace.recent_flow_percent)) {
|
|
12961
|
-
return null;
|
|
12962
|
-
}
|
|
12963
|
-
return {
|
|
12964
|
-
recent_flow_percent: workspace.recent_flow_percent,
|
|
12965
|
-
recent_flow_actual_rate_pph: workspace.recent_flow_actual_rate_pph ?? null,
|
|
12966
|
-
recent_flow_healthy_rate_pph: workspace.recent_flow_healthy_rate_pph ?? null,
|
|
12967
|
-
recent_flow_window_minutes: workspace.recent_flow_window_minutes ?? null,
|
|
12968
|
-
recent_flow_effective_end_at: workspace.recent_flow_effective_end_at ?? null
|
|
12969
|
-
};
|
|
12970
|
-
};
|
|
12971
|
-
var mergeWorkspaceRecentFlowMetrics = (workspaces, previousCache) => {
|
|
12972
|
-
const nextCache = /* @__PURE__ */ new Map();
|
|
12973
|
-
const mergedWorkspaces = workspaces.map((workspace) => {
|
|
12974
|
-
const cacheKey = getWorkspaceRecentFlowCacheKey(workspace);
|
|
12975
|
-
const currentSnapshot = toRecentFlowSnapshot(workspace);
|
|
12976
|
-
if (workspace.recent_flow_mode === "computed" && currentSnapshot) {
|
|
12977
|
-
nextCache.set(cacheKey, currentSnapshot);
|
|
12978
|
-
return workspace;
|
|
12979
|
-
}
|
|
12980
|
-
if (workspace.recent_flow_mode === "hold") {
|
|
12981
|
-
const cachedSnapshot = previousCache.get(cacheKey);
|
|
12982
|
-
if (cachedSnapshot) {
|
|
12983
|
-
nextCache.set(cacheKey, cachedSnapshot);
|
|
12984
|
-
return {
|
|
12985
|
-
...workspace,
|
|
12986
|
-
...cachedSnapshot,
|
|
12987
|
-
recent_flow_mode: "hold"
|
|
12988
|
-
};
|
|
12989
|
-
}
|
|
12990
|
-
}
|
|
12991
|
-
return workspace;
|
|
12992
|
-
});
|
|
12993
|
-
return {
|
|
12994
|
-
workspaces: mergedWorkspaces,
|
|
12995
|
-
cache: nextCache
|
|
12996
|
-
};
|
|
12997
|
-
};
|
|
12998
|
-
|
|
12999
12962
|
// src/lib/hooks/useDashboardMetrics.ts
|
|
13000
12963
|
var DEBUG_DASHBOARD_LOGS = process.env.NEXT_PUBLIC_DEBUG_DASHBOARD === "true";
|
|
13001
12964
|
var logDebug = (...args) => {
|
|
@@ -13084,7 +13047,6 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
13084
13047
|
const abortControllerRef = React141.useRef(null);
|
|
13085
13048
|
const lastFetchKeyRef = React141.useRef(null);
|
|
13086
13049
|
const inFlightFetchKeyRef = React141.useRef(null);
|
|
13087
|
-
const recentFlowCacheRef = React141.useRef(/* @__PURE__ */ new Map());
|
|
13088
13050
|
const updateQueueRef = React141.useRef(false);
|
|
13089
13051
|
const onLineMetricsUpdateRef = React141.useRef(onLineMetricsUpdate);
|
|
13090
13052
|
const shiftGroupsRef = React141.useRef(shiftGroups);
|
|
@@ -13118,7 +13080,6 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
13118
13080
|
setError(null);
|
|
13119
13081
|
lastFetchKeyRef.current = null;
|
|
13120
13082
|
inFlightFetchKeyRef.current = null;
|
|
13121
|
-
recentFlowCacheRef.current = /* @__PURE__ */ new Map();
|
|
13122
13083
|
}, [lineId]);
|
|
13123
13084
|
const fetchAllMetrics = React141.useCallback(async (options = {}) => {
|
|
13124
13085
|
const { force = false } = options;
|
|
@@ -13393,12 +13354,9 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
13393
13354
|
actionType: item.action_type,
|
|
13394
13355
|
actionName: item.action_name
|
|
13395
13356
|
}),
|
|
13396
|
-
recent_flow_mode: item.recent_flow_mode ?? void 0,
|
|
13397
13357
|
recent_flow_percent: item.recent_flow_percent ?? null,
|
|
13398
|
-
recent_flow_actual_rate_pph: item.recent_flow_actual_rate_pph ?? null,
|
|
13399
|
-
recent_flow_healthy_rate_pph: item.recent_flow_healthy_rate_pph ?? null,
|
|
13400
|
-
recent_flow_window_minutes: item.recent_flow_window_minutes ?? null,
|
|
13401
13358
|
recent_flow_effective_end_at: item.recent_flow_effective_end_at ?? null,
|
|
13359
|
+
recent_flow_computed_at: item.recent_flow_computed_at ?? null,
|
|
13402
13360
|
incoming_wip_current: item.incoming_wip_current ?? null,
|
|
13403
13361
|
incoming_wip_effective_at: item.incoming_wip_effective_at ?? null,
|
|
13404
13362
|
incoming_wip_buffer_name: item.incoming_wip_buffer_name ?? null
|
|
@@ -13409,16 +13367,11 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
13409
13367
|
const wsNumB = parseInt(b.workspace_name?.replace(/[^0-9]/g, "") || "0");
|
|
13410
13368
|
return wsNumA - wsNumB;
|
|
13411
13369
|
});
|
|
13412
|
-
|
|
13413
|
-
workspaces: mergedWorkspaceData,
|
|
13414
|
-
cache: nextRecentFlowCache
|
|
13415
|
-
} = mergeWorkspaceRecentFlowMetrics(transformedWorkspaceData, recentFlowCacheRef.current);
|
|
13416
|
-
recentFlowCacheRef.current = nextRecentFlowCache;
|
|
13417
|
-
mergedWorkspaceData.forEach((metric) => {
|
|
13370
|
+
transformedWorkspaceData.forEach((metric) => {
|
|
13418
13371
|
workspaceMetricsStore.setOverview(metric);
|
|
13419
13372
|
});
|
|
13420
13373
|
const newMetricsState = {
|
|
13421
|
-
workspaceMetrics:
|
|
13374
|
+
workspaceMetrics: transformedWorkspaceData,
|
|
13422
13375
|
lineMetrics: allLineMetrics || [],
|
|
13423
13376
|
metadata: { hasFlowBuffers, idleTimeVlmByLine },
|
|
13424
13377
|
efficiencyLegend: efficiencyLegend ?? DEFAULT_EFFICIENCY_LEGEND
|
|
@@ -16843,7 +16796,7 @@ var useActiveBreaks = (lineIds) => {
|
|
|
16843
16796
|
const [isLoading, setIsLoading] = React141.useState(true);
|
|
16844
16797
|
const [error, setError] = React141.useState(null);
|
|
16845
16798
|
const supabase = useSupabase();
|
|
16846
|
-
const
|
|
16799
|
+
const parseTimeToMinutes4 = (timeStr) => {
|
|
16847
16800
|
const [hours, minutes] = timeStr.split(":").map(Number);
|
|
16848
16801
|
return hours * 60 + minutes;
|
|
16849
16802
|
};
|
|
@@ -16852,8 +16805,8 @@ var useActiveBreaks = (lineIds) => {
|
|
|
16852
16805
|
return now4.getHours() * 60 + now4.getMinutes();
|
|
16853
16806
|
};
|
|
16854
16807
|
const isTimeInBreak = (breakStart, breakEnd, currentMinutes) => {
|
|
16855
|
-
const startMinutes =
|
|
16856
|
-
const endMinutes =
|
|
16808
|
+
const startMinutes = parseTimeToMinutes4(breakStart);
|
|
16809
|
+
const endMinutes = parseTimeToMinutes4(breakEnd);
|
|
16857
16810
|
if (endMinutes < startMinutes) {
|
|
16858
16811
|
return currentMinutes >= startMinutes || currentMinutes < endMinutes;
|
|
16859
16812
|
} else {
|
|
@@ -16861,8 +16814,8 @@ var useActiveBreaks = (lineIds) => {
|
|
|
16861
16814
|
}
|
|
16862
16815
|
};
|
|
16863
16816
|
const calculateBreakProgress = (breakStart, breakEnd, currentMinutes) => {
|
|
16864
|
-
const startMinutes =
|
|
16865
|
-
const endMinutes =
|
|
16817
|
+
const startMinutes = parseTimeToMinutes4(breakStart);
|
|
16818
|
+
const endMinutes = parseTimeToMinutes4(breakEnd);
|
|
16866
16819
|
let elapsedMinutes = 0;
|
|
16867
16820
|
let remainingMinutes = 0;
|
|
16868
16821
|
if (endMinutes < startMinutes) {
|
|
@@ -16880,8 +16833,8 @@ var useActiveBreaks = (lineIds) => {
|
|
|
16880
16833
|
return { elapsedMinutes, remainingMinutes };
|
|
16881
16834
|
};
|
|
16882
16835
|
const isTimeInShift = (startTime, endTime, currentMinutes) => {
|
|
16883
|
-
const startMinutes =
|
|
16884
|
-
const endMinutes =
|
|
16836
|
+
const startMinutes = parseTimeToMinutes4(startTime);
|
|
16837
|
+
const endMinutes = parseTimeToMinutes4(endTime);
|
|
16885
16838
|
if (endMinutes < startMinutes) {
|
|
16886
16839
|
return currentMinutes >= startMinutes || currentMinutes < endMinutes;
|
|
16887
16840
|
} else {
|
|
@@ -16941,8 +16894,8 @@ var useActiveBreaks = (lineIds) => {
|
|
|
16941
16894
|
const endTime = breakItem.end || breakItem.endTime || "00:00";
|
|
16942
16895
|
let duration = breakItem.duration || 0;
|
|
16943
16896
|
if (!duration || duration === 0) {
|
|
16944
|
-
const startMinutes =
|
|
16945
|
-
const endMinutes =
|
|
16897
|
+
const startMinutes = parseTimeToMinutes4(startTime);
|
|
16898
|
+
const endMinutes = parseTimeToMinutes4(endTime);
|
|
16946
16899
|
duration = endMinutes < startMinutes ? endMinutes + 24 * 60 - startMinutes : endMinutes - startMinutes;
|
|
16947
16900
|
}
|
|
16948
16901
|
return {
|
|
@@ -16958,8 +16911,8 @@ var useActiveBreaks = (lineIds) => {
|
|
|
16958
16911
|
const endTime = breakItem.end || breakItem.endTime || "00:00";
|
|
16959
16912
|
let duration = breakItem.duration || 0;
|
|
16960
16913
|
if (!duration || duration === 0) {
|
|
16961
|
-
const startMinutes =
|
|
16962
|
-
const endMinutes =
|
|
16914
|
+
const startMinutes = parseTimeToMinutes4(startTime);
|
|
16915
|
+
const endMinutes = parseTimeToMinutes4(endTime);
|
|
16963
16916
|
duration = endMinutes < startMinutes ? endMinutes + 24 * 60 - startMinutes : endMinutes - startMinutes;
|
|
16964
16917
|
}
|
|
16965
16918
|
return {
|
|
@@ -23040,6 +22993,16 @@ var createThrottledReload = (interval = 5e3, maxReloads = 3) => {
|
|
|
23040
22993
|
};
|
|
23041
22994
|
var throttledReloadDashboard = createThrottledReload(5e3, 3);
|
|
23042
22995
|
|
|
22996
|
+
// src/lib/utils/dev/localDevTestLogin.ts
|
|
22997
|
+
var isLoopbackHostname = (hostname) => {
|
|
22998
|
+
const normalized = String(hostname || "").trim().toLowerCase();
|
|
22999
|
+
return normalized === "localhost" || normalized === "127.0.0.1" || normalized === "::1";
|
|
23000
|
+
};
|
|
23001
|
+
var shouldEnableLocalDevTestLogin = ({
|
|
23002
|
+
enabledFlag,
|
|
23003
|
+
hostname
|
|
23004
|
+
}) => enabledFlag && isLoopbackHostname(hostname);
|
|
23005
|
+
|
|
23043
23006
|
// src/lib/utils/index.ts
|
|
23044
23007
|
var formatIdleTime = (idleTimeInSeconds) => {
|
|
23045
23008
|
if (!idleTimeInSeconds || idleTimeInSeconds <= 0) {
|
|
@@ -31224,12 +31187,16 @@ var LoginPage = ({
|
|
|
31224
31187
|
onRateLimitCheck,
|
|
31225
31188
|
logoSrc = optifye_logo_default,
|
|
31226
31189
|
logoAlt = "Optifye",
|
|
31227
|
-
brandName = "Optifye"
|
|
31190
|
+
brandName = "Optifye",
|
|
31191
|
+
showDevTestLogin = false,
|
|
31192
|
+
devTestLoginLabel = "Sign in as Test User",
|
|
31193
|
+
onDevTestLogin
|
|
31228
31194
|
}) => {
|
|
31229
31195
|
const [email, setEmail] = React141.useState("");
|
|
31230
31196
|
const [otp, setOtp] = React141.useState("");
|
|
31231
31197
|
const [step, setStep] = React141.useState("email");
|
|
31232
31198
|
const [loading, setLoading] = React141.useState(false);
|
|
31199
|
+
const [devLoginLoading, setDevLoginLoading] = React141.useState(false);
|
|
31233
31200
|
const [error, setError] = React141.useState(null);
|
|
31234
31201
|
const [countdown, setCountdown] = React141.useState(0);
|
|
31235
31202
|
const supabase = useSupabase();
|
|
@@ -31293,6 +31260,25 @@ var LoginPage = ({
|
|
|
31293
31260
|
startCountdown();
|
|
31294
31261
|
}
|
|
31295
31262
|
};
|
|
31263
|
+
const handleDevTestLogin = async () => {
|
|
31264
|
+
if (!onDevTestLogin) {
|
|
31265
|
+
return;
|
|
31266
|
+
}
|
|
31267
|
+
setDevLoginLoading(true);
|
|
31268
|
+
setError(null);
|
|
31269
|
+
try {
|
|
31270
|
+
const result = await onDevTestLogin();
|
|
31271
|
+
const nextError = typeof result === "object" && result !== null && "error" in result ? result.error : null;
|
|
31272
|
+
if (typeof nextError === "string" && nextError.trim()) {
|
|
31273
|
+
setError(nextError);
|
|
31274
|
+
}
|
|
31275
|
+
} catch (err) {
|
|
31276
|
+
console.error("Dev test login failed:", err);
|
|
31277
|
+
setError("Dev test login unavailable.");
|
|
31278
|
+
} finally {
|
|
31279
|
+
setDevLoginLoading(false);
|
|
31280
|
+
}
|
|
31281
|
+
};
|
|
31296
31282
|
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: [
|
|
31297
31283
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-2xl shadow-xl border border-slate-200 p-8", children: [
|
|
31298
31284
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center mb-8", children: [
|
|
@@ -31333,7 +31319,7 @@ var LoginPage = ({
|
|
|
31333
31319
|
"button",
|
|
31334
31320
|
{
|
|
31335
31321
|
type: "submit",
|
|
31336
|
-
disabled: loading,
|
|
31322
|
+
disabled: loading || devLoginLoading,
|
|
31337
31323
|
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",
|
|
31338
31324
|
children: loading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
31339
31325
|
/* @__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: [
|
|
@@ -31343,7 +31329,31 @@ var LoginPage = ({
|
|
|
31343
31329
|
"Sending..."
|
|
31344
31330
|
] }) : "Continue with Email"
|
|
31345
31331
|
}
|
|
31346
|
-
)
|
|
31332
|
+
),
|
|
31333
|
+
showDevTestLogin && onDevTestLogin ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
|
|
31334
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
31335
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-px flex-1 bg-slate-200" }),
|
|
31336
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium uppercase tracking-[0.2em] text-slate-400", children: "Local Dev" }),
|
|
31337
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-px flex-1 bg-slate-200" })
|
|
31338
|
+
] }),
|
|
31339
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
31340
|
+
"button",
|
|
31341
|
+
{
|
|
31342
|
+
type: "button",
|
|
31343
|
+
disabled: loading || devLoginLoading,
|
|
31344
|
+
onClick: () => void handleDevTestLogin(),
|
|
31345
|
+
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",
|
|
31346
|
+
children: devLoginLoading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
31347
|
+
/* @__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: [
|
|
31348
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
|
|
31349
|
+
/* @__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" })
|
|
31350
|
+
] }),
|
|
31351
|
+
"Signing In..."
|
|
31352
|
+
] }) : devTestLoginLabel
|
|
31353
|
+
}
|
|
31354
|
+
),
|
|
31355
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-center text-xs text-slate-500", children: "Localhost-only convenience login for the shared test account." })
|
|
31356
|
+
] }) : null
|
|
31347
31357
|
] }) : /* @__PURE__ */ jsxRuntime.jsxs("form", { className: "space-y-6", onSubmit: handleVerifyOTP, children: [
|
|
31348
31358
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
31349
31359
|
/* @__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" }),
|
|
@@ -31368,7 +31378,7 @@ var LoginPage = ({
|
|
|
31368
31378
|
"button",
|
|
31369
31379
|
{
|
|
31370
31380
|
type: "submit",
|
|
31371
|
-
disabled: loading || otp.length !== 6,
|
|
31381
|
+
disabled: loading || devLoginLoading || otp.length !== 6,
|
|
31372
31382
|
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",
|
|
31373
31383
|
children: loading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
31374
31384
|
/* @__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: [
|
|
@@ -32209,31 +32219,35 @@ var LineChartComponent = ({
|
|
|
32209
32219
|
...restOfChartProps
|
|
32210
32220
|
}) => {
|
|
32211
32221
|
const containerRef = React141__namespace.default.useRef(null);
|
|
32212
|
-
const [
|
|
32213
|
-
const
|
|
32214
|
-
const { formatNumber } = useFormatNumber();
|
|
32222
|
+
const [dimensions, setDimensions] = React141__namespace.default.useState({ width: 0, height: 0 });
|
|
32223
|
+
const [hasValidData, setHasValidData] = React141__namespace.default.useState(false);
|
|
32215
32224
|
React141__namespace.default.useEffect(() => {
|
|
32216
|
-
const
|
|
32217
|
-
|
|
32218
|
-
const
|
|
32219
|
-
|
|
32220
|
-
|
|
32221
|
-
|
|
32222
|
-
|
|
32223
|
-
|
|
32224
|
-
checkContainerDimensions();
|
|
32225
|
-
const resizeObserver = new ResizeObserver(checkContainerDimensions);
|
|
32226
|
-
if (containerRef.current) {
|
|
32227
|
-
resizeObserver.observe(containerRef.current);
|
|
32225
|
+
const currentHasValidData = data && lines && lines.length > 0 && data.some(
|
|
32226
|
+
(item) => lines.some((line) => {
|
|
32227
|
+
const val = item[line.dataKey];
|
|
32228
|
+
return typeof val === "number" && val > 0;
|
|
32229
|
+
})
|
|
32230
|
+
);
|
|
32231
|
+
if (currentHasValidData && !hasValidData) {
|
|
32232
|
+
setHasValidData(true);
|
|
32228
32233
|
}
|
|
32229
|
-
|
|
32230
|
-
|
|
32231
|
-
|
|
32232
|
-
|
|
32233
|
-
|
|
32234
|
-
|
|
32235
|
-
|
|
32234
|
+
}, [data, lines, hasValidData]);
|
|
32235
|
+
React141__namespace.default.useEffect(() => {
|
|
32236
|
+
if (!containerRef.current) return;
|
|
32237
|
+
const observer = new ResizeObserver((entries) => {
|
|
32238
|
+
const entry = entries[0];
|
|
32239
|
+
if (entry) {
|
|
32240
|
+
setDimensions({
|
|
32241
|
+
width: entry.contentRect.width,
|
|
32242
|
+
height: entry.contentRect.height
|
|
32243
|
+
});
|
|
32244
|
+
}
|
|
32245
|
+
});
|
|
32246
|
+
observer.observe(containerRef.current);
|
|
32247
|
+
return () => observer.disconnect();
|
|
32236
32248
|
}, []);
|
|
32249
|
+
const themeConfig = useThemeConfig();
|
|
32250
|
+
const { formatNumber } = useFormatNumber();
|
|
32237
32251
|
const yAxisTickFormatter = (value) => {
|
|
32238
32252
|
return `${formatNumber(value)}${yAxisUnit || ""}`;
|
|
32239
32253
|
};
|
|
@@ -32255,57 +32269,71 @@ var LineChartComponent = ({
|
|
|
32255
32269
|
const gridStrokeColor = themeConfig?.gray?.["300"] || "#ccc";
|
|
32256
32270
|
const axisTickFillColor = themeConfig?.gray?.["600"] || "#666";
|
|
32257
32271
|
const axisStrokeColor = themeConfig?.gray?.["400"] || "#999";
|
|
32258
|
-
const
|
|
32259
|
-
|
|
32260
|
-
|
|
32261
|
-
|
|
32262
|
-
|
|
32263
|
-
|
|
32264
|
-
|
|
32265
|
-
|
|
32266
|
-
|
|
32267
|
-
stroke:
|
|
32268
|
-
|
|
32269
|
-
|
|
32270
|
-
|
|
32271
|
-
|
|
32272
|
-
|
|
32273
|
-
|
|
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
|
-
|
|
32272
|
+
const renderChartContent = (chartWidth, chartHeight) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
32273
|
+
recharts.LineChart,
|
|
32274
|
+
{
|
|
32275
|
+
width: chartWidth,
|
|
32276
|
+
height: chartHeight,
|
|
32277
|
+
data,
|
|
32278
|
+
margin: { top: 5, right: 30, left: 20, bottom: 20 },
|
|
32279
|
+
...restOfChartProps,
|
|
32280
|
+
children: [
|
|
32281
|
+
showGrid && /* @__PURE__ */ jsxRuntime.jsx(recharts.CartesianGrid, { strokeDasharray: "3 3", stroke: gridStrokeColor }),
|
|
32282
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
32283
|
+
recharts.XAxis,
|
|
32284
|
+
{
|
|
32285
|
+
dataKey: xAxisDataKey,
|
|
32286
|
+
label: xAxisLabel ? { value: xAxisLabel, position: "insideBottom", offset: -10 } : void 0,
|
|
32287
|
+
tickFormatter: xAxisTickFormatter,
|
|
32288
|
+
tick: { fontSize: 12, fill: axisTickFillColor },
|
|
32289
|
+
stroke: axisStrokeColor
|
|
32290
|
+
}
|
|
32291
|
+
),
|
|
32292
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
32293
|
+
recharts.YAxis,
|
|
32294
|
+
{
|
|
32295
|
+
label: yAxisLabel ? { value: yAxisLabel, angle: -90, position: "insideLeft" } : void 0,
|
|
32296
|
+
tickFormatter: yAxisTickFormatter,
|
|
32297
|
+
domain: yAxisDomain,
|
|
32298
|
+
tick: { fontSize: 12, fill: axisTickFillColor },
|
|
32299
|
+
stroke: axisStrokeColor
|
|
32300
|
+
}
|
|
32301
|
+
),
|
|
32302
|
+
showTooltip && /* @__PURE__ */ jsxRuntime.jsx(
|
|
32303
|
+
recharts.Tooltip,
|
|
32304
|
+
{
|
|
32305
|
+
formatter: tooltipFormatter || defaultTooltipFormatter,
|
|
32306
|
+
labelFormatter: tooltipLabelFormatter,
|
|
32307
|
+
itemStyle: { color: "#111827" },
|
|
32308
|
+
cursor: { strokeDasharray: "3 3" }
|
|
32309
|
+
}
|
|
32310
|
+
),
|
|
32311
|
+
showLegend && /* @__PURE__ */ jsxRuntime.jsx(recharts.Legend, { payload: legendPayload }),
|
|
32312
|
+
lines.map((lineConfig, index) => {
|
|
32313
|
+
const lineProps = {
|
|
32314
|
+
...lineConfig,
|
|
32315
|
+
key: lineConfig.dataKey,
|
|
32316
|
+
type: lineConfig.type || "monotone",
|
|
32317
|
+
stroke: lineConfig.stroke || defaultColors[index % defaultColors.length],
|
|
32318
|
+
activeDot: lineConfig.activeDot !== void 0 ? lineConfig.activeDot : { r: 6 },
|
|
32319
|
+
isAnimationActive: true,
|
|
32320
|
+
animationDuration: 1500,
|
|
32321
|
+
animationBegin: 300
|
|
32322
|
+
};
|
|
32323
|
+
return /* @__PURE__ */ jsxRuntime.jsx(recharts.Line, { ...lineProps, children: lineConfig.labelList && /* @__PURE__ */ jsxRuntime.jsx(
|
|
32324
|
+
recharts.LabelList,
|
|
32325
|
+
{
|
|
32326
|
+
dataKey: lineConfig.dataKey,
|
|
32327
|
+
position: "top",
|
|
32328
|
+
formatter: (value) => formatNumber(value),
|
|
32329
|
+
...typeof lineConfig.labelList === "object" ? lineConfig.labelList : {}
|
|
32330
|
+
}
|
|
32331
|
+
) });
|
|
32332
|
+
})
|
|
32333
|
+
]
|
|
32334
|
+
},
|
|
32335
|
+
hasValidData ? "valid" : "empty"
|
|
32336
|
+
);
|
|
32309
32337
|
if (responsive) {
|
|
32310
32338
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
32311
32339
|
"div",
|
|
@@ -32313,11 +32341,20 @@ var LineChartComponent = ({
|
|
|
32313
32341
|
ref: containerRef,
|
|
32314
32342
|
className: clsx(fillContainer ? "w-full h-full" : "w-full h-auto", className),
|
|
32315
32343
|
style: fillContainer ? { height: "100%", minHeight: "50px", minWidth: "100px" } : { aspectRatio: `${aspect}/1`, minHeight: "50px", minWidth: "100px" },
|
|
32316
|
-
children:
|
|
32344
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
32345
|
+
motion.div,
|
|
32346
|
+
{
|
|
32347
|
+
initial: { opacity: 0 },
|
|
32348
|
+
animate: { opacity: 1 },
|
|
32349
|
+
transition: { duration: 0.5 },
|
|
32350
|
+
className: "w-full h-full",
|
|
32351
|
+
children: dimensions.width > 0 && dimensions.height > 0 && renderChartContent(dimensions.width, dimensions.height)
|
|
32352
|
+
}
|
|
32353
|
+
)
|
|
32317
32354
|
}
|
|
32318
32355
|
);
|
|
32319
32356
|
}
|
|
32320
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: clsx("w-full", className), children:
|
|
32357
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: clsx("w-full", className), children: renderChartContent(restOfChartProps.width, restOfChartProps.height) });
|
|
32321
32358
|
};
|
|
32322
32359
|
var LineChart = React141__namespace.default.memo(LineChartComponent, (prevProps, nextProps) => {
|
|
32323
32360
|
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)) {
|
|
@@ -32585,14 +32622,35 @@ var CycleTimeOverTimeChart = ({
|
|
|
32585
32622
|
}) => {
|
|
32586
32623
|
const MAX_DATA_POINTS = 40;
|
|
32587
32624
|
const containerRef = React141__namespace.default.useRef(null);
|
|
32588
|
-
const [
|
|
32589
|
-
const
|
|
32625
|
+
const [dimensions, setDimensions] = React141__namespace.default.useState({ width: 0, height: 0 });
|
|
32626
|
+
const [hasValidData, setHasValidData] = React141__namespace.default.useState(false);
|
|
32627
|
+
React141__namespace.default.useEffect(() => {
|
|
32628
|
+
const currentHasValidData = data && data.some((val) => val !== null && val > 0);
|
|
32629
|
+
if (currentHasValidData && !hasValidData) {
|
|
32630
|
+
setHasValidData(true);
|
|
32631
|
+
}
|
|
32632
|
+
}, [data, hasValidData]);
|
|
32633
|
+
React141__namespace.default.useEffect(() => {
|
|
32634
|
+
if (!containerRef.current) return;
|
|
32635
|
+
const observer = new ResizeObserver((entries) => {
|
|
32636
|
+
const entry = entries[0];
|
|
32637
|
+
if (entry) {
|
|
32638
|
+
setDimensions({
|
|
32639
|
+
width: entry.contentRect.width,
|
|
32640
|
+
height: entry.contentRect.height
|
|
32641
|
+
});
|
|
32642
|
+
}
|
|
32643
|
+
});
|
|
32644
|
+
observer.observe(containerRef.current);
|
|
32645
|
+
return () => observer.disconnect();
|
|
32646
|
+
}, []);
|
|
32647
|
+
const parseTimeToMinutes4 = (value) => {
|
|
32590
32648
|
const [hours, minutes] = value.split(":").map(Number);
|
|
32591
32649
|
if (!Number.isFinite(hours) || !Number.isFinite(minutes)) return 0;
|
|
32592
32650
|
return hours * 60 + minutes;
|
|
32593
32651
|
};
|
|
32594
32652
|
const formatHourLabel = (slotIndex) => {
|
|
32595
|
-
const baseMinutes =
|
|
32653
|
+
const baseMinutes = parseTimeToMinutes4(shiftStart);
|
|
32596
32654
|
const absoluteMinutes = baseMinutes + slotIndex * 60;
|
|
32597
32655
|
const hour24 = Math.floor(absoluteMinutes % (24 * 60) / 60);
|
|
32598
32656
|
const ampm = hour24 >= 12 ? "PM" : "AM";
|
|
@@ -32611,52 +32669,7 @@ var CycleTimeOverTimeChart = ({
|
|
|
32611
32669
|
const displayData = getDisplayData(data);
|
|
32612
32670
|
const DURATION = displayData.length;
|
|
32613
32671
|
const effectiveDatasetKey = datasetKey || `cycle-time:${xAxisMode}`;
|
|
32614
|
-
const [animatedDatasetKey, setAnimatedDatasetKey] = React141__namespace.default.useState(null);
|
|
32615
|
-
const shouldAnimate = animatedDatasetKey !== effectiveDatasetKey;
|
|
32616
|
-
const handleAnimationEnd = React141__namespace.default.useCallback(() => {
|
|
32617
|
-
setAnimatedDatasetKey((currentValue) => currentValue === effectiveDatasetKey ? currentValue : effectiveDatasetKey);
|
|
32618
|
-
}, [effectiveDatasetKey]);
|
|
32619
32672
|
const finalData = displayData;
|
|
32620
|
-
React141__namespace.default.useEffect(() => {
|
|
32621
|
-
const containerNode = containerRef.current;
|
|
32622
|
-
if (!containerNode) {
|
|
32623
|
-
setContainerReady(true);
|
|
32624
|
-
return void 0;
|
|
32625
|
-
}
|
|
32626
|
-
let frameId = null;
|
|
32627
|
-
let resizeObserver = null;
|
|
32628
|
-
const checkContainerDimensions = () => {
|
|
32629
|
-
const rect = containerNode.getBoundingClientRect();
|
|
32630
|
-
const isReady = rect.width > 0 && rect.height > 0;
|
|
32631
|
-
if (isReady) {
|
|
32632
|
-
setContainerReady(true);
|
|
32633
|
-
}
|
|
32634
|
-
return isReady;
|
|
32635
|
-
};
|
|
32636
|
-
if (checkContainerDimensions()) {
|
|
32637
|
-
return void 0;
|
|
32638
|
-
}
|
|
32639
|
-
frameId = window.requestAnimationFrame(() => {
|
|
32640
|
-
checkContainerDimensions();
|
|
32641
|
-
});
|
|
32642
|
-
if (typeof ResizeObserver !== "undefined") {
|
|
32643
|
-
resizeObserver = new ResizeObserver(() => {
|
|
32644
|
-
if (checkContainerDimensions() && resizeObserver) {
|
|
32645
|
-
resizeObserver.disconnect();
|
|
32646
|
-
resizeObserver = null;
|
|
32647
|
-
}
|
|
32648
|
-
});
|
|
32649
|
-
resizeObserver.observe(containerNode);
|
|
32650
|
-
} else {
|
|
32651
|
-
setContainerReady(true);
|
|
32652
|
-
}
|
|
32653
|
-
return () => {
|
|
32654
|
-
if (frameId !== null) {
|
|
32655
|
-
window.cancelAnimationFrame(frameId);
|
|
32656
|
-
}
|
|
32657
|
-
resizeObserver?.disconnect();
|
|
32658
|
-
};
|
|
32659
|
-
}, []);
|
|
32660
32673
|
const labelInterval = React141__namespace.default.useMemo(() => {
|
|
32661
32674
|
if (xAxisMode === "hourly") {
|
|
32662
32675
|
return Math.max(1, Math.ceil(DURATION / 8));
|
|
@@ -32698,16 +32711,162 @@ var CycleTimeOverTimeChart = ({
|
|
|
32698
32711
|
return `${minutes} minutes ${seconds} seconds ago`;
|
|
32699
32712
|
}
|
|
32700
32713
|
};
|
|
32714
|
+
const getNumericValue = React141__namespace.default.useCallback((value) => typeof value === "number" && Number.isFinite(value) ? value : null, []);
|
|
32715
|
+
const renderChartTooltip = React141__namespace.default.useCallback((tooltipProps) => {
|
|
32716
|
+
const { active, payload } = tooltipProps;
|
|
32717
|
+
if (!active || !Array.isArray(payload) || payload.length === 0) {
|
|
32718
|
+
return null;
|
|
32719
|
+
}
|
|
32720
|
+
const visibleEntries = payload.filter((entry) => getNumericValue(entry.value) !== null);
|
|
32721
|
+
if (!visibleEntries.length) {
|
|
32722
|
+
return null;
|
|
32723
|
+
}
|
|
32724
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
32725
|
+
"div",
|
|
32726
|
+
{
|
|
32727
|
+
style: {
|
|
32728
|
+
backgroundColor: "white",
|
|
32729
|
+
border: "none",
|
|
32730
|
+
borderRadius: "8px",
|
|
32731
|
+
boxShadow: "0 4px 12px rgba(0,0,0,0.1)",
|
|
32732
|
+
padding: "8px 12px",
|
|
32733
|
+
fontSize: "13px"
|
|
32734
|
+
},
|
|
32735
|
+
children: [
|
|
32736
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
32737
|
+
"div",
|
|
32738
|
+
{
|
|
32739
|
+
style: {
|
|
32740
|
+
color: "#374151",
|
|
32741
|
+
fontWeight: 600,
|
|
32742
|
+
marginBottom: "4px"
|
|
32743
|
+
},
|
|
32744
|
+
children: payload[0]?.payload?.tooltip || ""
|
|
32745
|
+
}
|
|
32746
|
+
),
|
|
32747
|
+
visibleEntries.map((entry) => {
|
|
32748
|
+
const numericValue = getNumericValue(entry.value);
|
|
32749
|
+
if (numericValue === null) {
|
|
32750
|
+
return null;
|
|
32751
|
+
}
|
|
32752
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
32753
|
+
"div",
|
|
32754
|
+
{
|
|
32755
|
+
style: {
|
|
32756
|
+
color: "#4B5563",
|
|
32757
|
+
padding: "2px 0"
|
|
32758
|
+
},
|
|
32759
|
+
children: entry.name === "idleMinutes" ? `Idle Time: ${numericValue.toFixed(0)} minutes` : `Cycle Time: ${numericValue.toFixed(1)} seconds`
|
|
32760
|
+
},
|
|
32761
|
+
`${entry.name}-${numericValue}`
|
|
32762
|
+
);
|
|
32763
|
+
})
|
|
32764
|
+
]
|
|
32765
|
+
}
|
|
32766
|
+
);
|
|
32767
|
+
}, [getNumericValue]);
|
|
32768
|
+
const renderCycleDot = React141__namespace.default.useCallback((props) => {
|
|
32769
|
+
const { cx: cx2, cy, payload } = props;
|
|
32770
|
+
const cycleTime = getNumericValue(payload?.cycleTime);
|
|
32771
|
+
if (cycleTime === null) {
|
|
32772
|
+
return /* @__PURE__ */ jsxRuntime.jsx("g", {});
|
|
32773
|
+
}
|
|
32774
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
32775
|
+
"circle",
|
|
32776
|
+
{
|
|
32777
|
+
cx: cx2,
|
|
32778
|
+
cy,
|
|
32779
|
+
r: 4,
|
|
32780
|
+
fill: cycleTime <= idealCycleTime ? "#00AB45" : "#E34329",
|
|
32781
|
+
stroke: "#fff",
|
|
32782
|
+
strokeWidth: 1,
|
|
32783
|
+
style: {
|
|
32784
|
+
filter: "brightness(1)",
|
|
32785
|
+
transition: "filter 0.3s ease, transform 0.3s ease",
|
|
32786
|
+
cursor: "pointer"
|
|
32787
|
+
},
|
|
32788
|
+
onMouseEnter: (e) => {
|
|
32789
|
+
const target = e.target;
|
|
32790
|
+
target.style.filter = "brightness(1.2)";
|
|
32791
|
+
target.style.transform = "scale(1.2)";
|
|
32792
|
+
},
|
|
32793
|
+
onMouseLeave: (e) => {
|
|
32794
|
+
const target = e.target;
|
|
32795
|
+
target.style.filter = "brightness(1)";
|
|
32796
|
+
target.style.transform = "scale(1)";
|
|
32797
|
+
}
|
|
32798
|
+
}
|
|
32799
|
+
);
|
|
32800
|
+
}, [getNumericValue, idealCycleTime]);
|
|
32801
|
+
const renderCycleActiveDot = React141__namespace.default.useCallback((props) => {
|
|
32802
|
+
const { cx: cx2, cy, payload } = props;
|
|
32803
|
+
const cycleTime = getNumericValue(payload?.cycleTime);
|
|
32804
|
+
if (cycleTime === null) {
|
|
32805
|
+
return /* @__PURE__ */ jsxRuntime.jsx("g", {});
|
|
32806
|
+
}
|
|
32807
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
32808
|
+
"circle",
|
|
32809
|
+
{
|
|
32810
|
+
cx: cx2,
|
|
32811
|
+
cy,
|
|
32812
|
+
r: 6,
|
|
32813
|
+
fill: cycleTime <= idealCycleTime ? "#00AB45" : "#E34329",
|
|
32814
|
+
stroke: "#fff",
|
|
32815
|
+
strokeWidth: 2,
|
|
32816
|
+
style: {
|
|
32817
|
+
filter: "drop-shadow(0 0 2px rgba(0,0,0,0.2))"
|
|
32818
|
+
}
|
|
32819
|
+
}
|
|
32820
|
+
);
|
|
32821
|
+
}, [getNumericValue, idealCycleTime]);
|
|
32822
|
+
const renderIdleDot = React141__namespace.default.useCallback((props) => {
|
|
32823
|
+
const { cx: cx2, cy, payload } = props;
|
|
32824
|
+
const idleMinutes = getNumericValue(payload?.idleMinutes);
|
|
32825
|
+
if (idleMinutes === null) {
|
|
32826
|
+
return /* @__PURE__ */ jsxRuntime.jsx("g", {});
|
|
32827
|
+
}
|
|
32828
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
32829
|
+
"circle",
|
|
32830
|
+
{
|
|
32831
|
+
cx: cx2,
|
|
32832
|
+
cy,
|
|
32833
|
+
r: 4,
|
|
32834
|
+
fill: "#f59e0b",
|
|
32835
|
+
stroke: "#fff",
|
|
32836
|
+
strokeWidth: 1
|
|
32837
|
+
}
|
|
32838
|
+
);
|
|
32839
|
+
}, [getNumericValue]);
|
|
32840
|
+
const renderIdleActiveDot = React141__namespace.default.useCallback((props) => {
|
|
32841
|
+
const { cx: cx2, cy, payload } = props;
|
|
32842
|
+
const idleMinutes = getNumericValue(payload?.idleMinutes);
|
|
32843
|
+
if (idleMinutes === null) {
|
|
32844
|
+
return /* @__PURE__ */ jsxRuntime.jsx("g", {});
|
|
32845
|
+
}
|
|
32846
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
32847
|
+
"circle",
|
|
32848
|
+
{
|
|
32849
|
+
cx: cx2,
|
|
32850
|
+
cy,
|
|
32851
|
+
r: 6,
|
|
32852
|
+
fill: "#f59e0b",
|
|
32853
|
+
stroke: "#fff",
|
|
32854
|
+
strokeWidth: 2
|
|
32855
|
+
}
|
|
32856
|
+
);
|
|
32857
|
+
}, [getNumericValue]);
|
|
32701
32858
|
const chartData = React141__namespace.default.useMemo(() => Array.from({ length: DURATION }, (_, i) => {
|
|
32859
|
+
const cycleTime = getNumericValue(finalData[i]);
|
|
32860
|
+
const idleMinutes = showIdleTime ? getNumericValue(idleTimeData[i]) : null;
|
|
32702
32861
|
return {
|
|
32703
32862
|
timeIndex: i,
|
|
32704
32863
|
label: formatTimeLabel(i),
|
|
32705
32864
|
tooltip: formatTooltipTime(i),
|
|
32706
|
-
cycleTime
|
|
32707
|
-
idleMinutes
|
|
32708
|
-
color:
|
|
32865
|
+
cycleTime,
|
|
32866
|
+
idleMinutes,
|
|
32867
|
+
color: cycleTime !== null && cycleTime <= idealCycleTime ? "#00AB45" : "#E34329"
|
|
32709
32868
|
};
|
|
32710
|
-
}), [DURATION, finalData, showIdleTime, idleTimeData, idealCycleTime]);
|
|
32869
|
+
}), [DURATION, finalData, showIdleTime, idleTimeData, idealCycleTime, getNumericValue]);
|
|
32711
32870
|
const renderLegend = () => {
|
|
32712
32871
|
if (!showIdleTime) return null;
|
|
32713
32872
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-start text-[10px] font-bold text-gray-500 mb-6 tracking-[0.05em] gap-5", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
@@ -32718,215 +32877,154 @@ var CycleTimeOverTimeChart = ({
|
|
|
32718
32877
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
32719
32878
|
"div",
|
|
32720
32879
|
{
|
|
32721
|
-
ref: containerRef,
|
|
32722
32880
|
className: `w-full h-full min-w-0 flex flex-col relative pb-2 ${className}`,
|
|
32723
32881
|
style: { minHeight: "200px", minWidth: 0 },
|
|
32724
32882
|
children: [
|
|
32725
32883
|
renderLegend(),
|
|
32726
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-h-0 w-full",
|
|
32727
|
-
|
|
32884
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-h-0 w-full", ref: containerRef, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
32885
|
+
motion.div,
|
|
32728
32886
|
{
|
|
32729
|
-
|
|
32730
|
-
|
|
32731
|
-
|
|
32732
|
-
|
|
32733
|
-
|
|
32734
|
-
|
|
32735
|
-
|
|
32736
|
-
|
|
32737
|
-
|
|
32738
|
-
|
|
32739
|
-
|
|
32740
|
-
|
|
32741
|
-
|
|
32742
|
-
|
|
32743
|
-
|
|
32744
|
-
|
|
32745
|
-
|
|
32746
|
-
|
|
32747
|
-
|
|
32748
|
-
|
|
32749
|
-
|
|
32750
|
-
|
|
32751
|
-
|
|
32752
|
-
|
|
32753
|
-
|
|
32754
|
-
|
|
32755
|
-
|
|
32756
|
-
|
|
32757
|
-
ticks: [0, idealCycleTime, ...Array.from({ length: 4 }, (_, i) => (i + 1) * Math.ceil(idealCycleTime / 2))].sort((a, b) => a - b),
|
|
32758
|
-
tickFormatter: (value) => String(value),
|
|
32759
|
-
tick: (props) => {
|
|
32760
|
-
const { x, y, payload } = props;
|
|
32761
|
-
const displayValue = typeof payload.value === "number" ? payload.value.toFixed(1) : String(payload.value);
|
|
32762
|
-
return /* @__PURE__ */ jsxRuntime.jsx("g", { transform: `translate(${x},${y})`, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
32763
|
-
"text",
|
|
32764
|
-
{
|
|
32765
|
-
x: 0,
|
|
32766
|
-
y: 0,
|
|
32767
|
-
dy: 4,
|
|
32768
|
-
textAnchor: "end",
|
|
32769
|
-
fill: payload.value === idealCycleTime ? "#E34329" : "#666",
|
|
32770
|
-
fontSize: 12,
|
|
32771
|
-
fontWeight: payload.value === idealCycleTime ? "bold" : "normal",
|
|
32772
|
-
children: displayValue
|
|
32773
|
-
},
|
|
32774
|
-
`tick-${payload.value}-${x}-${y}`
|
|
32775
|
-
) });
|
|
32776
|
-
}
|
|
32777
|
-
}
|
|
32778
|
-
),
|
|
32779
|
-
showIdleTime && /* @__PURE__ */ jsxRuntime.jsx(
|
|
32780
|
-
recharts.YAxis,
|
|
32781
|
-
{
|
|
32782
|
-
yAxisId: "idle",
|
|
32783
|
-
orientation: "right",
|
|
32784
|
-
tickMargin: 8,
|
|
32785
|
-
width: 35,
|
|
32786
|
-
domain: [0, 60],
|
|
32787
|
-
tickFormatter: (value) => `${value}m`,
|
|
32788
|
-
tick: { fontSize: 11, fill: "#f59e0b" },
|
|
32789
|
-
axisLine: false,
|
|
32790
|
-
tickLine: false
|
|
32791
|
-
}
|
|
32792
|
-
),
|
|
32793
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
32794
|
-
recharts.Tooltip,
|
|
32795
|
-
{
|
|
32796
|
-
cursor: { stroke: "#E5E7EB", strokeWidth: 1 },
|
|
32797
|
-
contentStyle: {
|
|
32798
|
-
backgroundColor: "white",
|
|
32799
|
-
border: "none",
|
|
32800
|
-
borderRadius: "8px",
|
|
32801
|
-
boxShadow: "0 4px 12px rgba(0,0,0,0.1)",
|
|
32802
|
-
padding: "8px 12px",
|
|
32803
|
-
fontSize: "13px"
|
|
32804
|
-
},
|
|
32805
|
-
labelStyle: {
|
|
32806
|
-
color: "#374151",
|
|
32807
|
-
fontWeight: 600,
|
|
32808
|
-
marginBottom: "4px"
|
|
32809
|
-
},
|
|
32810
|
-
itemStyle: {
|
|
32811
|
-
color: "#4B5563",
|
|
32812
|
-
padding: "2px 0"
|
|
32813
|
-
},
|
|
32814
|
-
labelFormatter: (label, payload) => {
|
|
32815
|
-
if (payload && payload[0]) {
|
|
32816
|
-
return payload[0].payload.tooltip;
|
|
32817
|
-
}
|
|
32818
|
-
return label;
|
|
32819
|
-
},
|
|
32820
|
-
formatter: (value, name) => {
|
|
32821
|
-
const numValue = typeof value === "number" ? value : Number(value);
|
|
32822
|
-
if (name === "idleMinutes") {
|
|
32823
|
-
return [`${numValue.toFixed(0)} minutes`, "Idle Time"];
|
|
32887
|
+
initial: { opacity: 0 },
|
|
32888
|
+
animate: { opacity: 1 },
|
|
32889
|
+
transition: { duration: 0.5 },
|
|
32890
|
+
className: "w-full h-full",
|
|
32891
|
+
children: dimensions.width > 0 && dimensions.height > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
32892
|
+
recharts.LineChart,
|
|
32893
|
+
{
|
|
32894
|
+
width: dimensions.width,
|
|
32895
|
+
height: dimensions.height,
|
|
32896
|
+
data: chartData,
|
|
32897
|
+
margin: {
|
|
32898
|
+
top: 5,
|
|
32899
|
+
right: 30,
|
|
32900
|
+
bottom: 25,
|
|
32901
|
+
left: 10
|
|
32902
|
+
},
|
|
32903
|
+
children: [
|
|
32904
|
+
/* @__PURE__ */ jsxRuntime.jsx(recharts.CartesianGrid, { strokeDasharray: "3 3", vertical: false }),
|
|
32905
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
32906
|
+
recharts.XAxis,
|
|
32907
|
+
{
|
|
32908
|
+
dataKey: "label",
|
|
32909
|
+
tick: { fontSize: 11 },
|
|
32910
|
+
interval: 0,
|
|
32911
|
+
angle: xAxisMode === "hourly" ? 0 : -30,
|
|
32912
|
+
textAnchor: xAxisMode === "hourly" ? "middle" : "end",
|
|
32913
|
+
tickMargin: xAxisMode === "hourly" ? 8 : 15,
|
|
32914
|
+
height: xAxisMode === "hourly" ? 40 : 60
|
|
32824
32915
|
}
|
|
32825
|
-
|
|
32826
|
-
|
|
32827
|
-
|
|
32828
|
-
|
|
32829
|
-
|
|
32830
|
-
|
|
32831
|
-
|
|
32832
|
-
|
|
32833
|
-
|
|
32834
|
-
|
|
32835
|
-
|
|
32836
|
-
|
|
32837
|
-
|
|
32838
|
-
|
|
32839
|
-
|
|
32840
|
-
|
|
32841
|
-
|
|
32842
|
-
|
|
32843
|
-
|
|
32844
|
-
|
|
32845
|
-
|
|
32846
|
-
|
|
32847
|
-
|
|
32848
|
-
|
|
32849
|
-
|
|
32850
|
-
|
|
32851
|
-
|
|
32852
|
-
dataKey: "cycleTime",
|
|
32853
|
-
stroke: "#3B82F6",
|
|
32854
|
-
strokeWidth: 2,
|
|
32855
|
-
dot: (props) => {
|
|
32856
|
-
const { cx: cx2, cy, payload } = props;
|
|
32857
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
32858
|
-
"circle",
|
|
32859
|
-
{
|
|
32860
|
-
cx: cx2,
|
|
32861
|
-
cy,
|
|
32862
|
-
r: 4,
|
|
32863
|
-
fill: payload.cycleTime <= idealCycleTime ? "#00AB45" : "#E34329",
|
|
32864
|
-
stroke: "#fff",
|
|
32865
|
-
strokeWidth: 1,
|
|
32866
|
-
style: {
|
|
32867
|
-
filter: "brightness(1)",
|
|
32868
|
-
transition: "filter 0.3s ease, transform 0.3s ease",
|
|
32869
|
-
cursor: "pointer"
|
|
32870
|
-
},
|
|
32871
|
-
onMouseEnter: (e) => {
|
|
32872
|
-
const target = e.target;
|
|
32873
|
-
target.style.filter = "brightness(1.2)";
|
|
32874
|
-
target.style.transform = "scale(1.2)";
|
|
32875
|
-
},
|
|
32876
|
-
onMouseLeave: (e) => {
|
|
32877
|
-
const target = e.target;
|
|
32878
|
-
target.style.filter = "brightness(1)";
|
|
32879
|
-
target.style.transform = "scale(1)";
|
|
32880
|
-
}
|
|
32916
|
+
),
|
|
32917
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
32918
|
+
recharts.YAxis,
|
|
32919
|
+
{
|
|
32920
|
+
tickMargin: 8,
|
|
32921
|
+
width: 45,
|
|
32922
|
+
yAxisId: "cycle",
|
|
32923
|
+
domain: ["auto", "auto"],
|
|
32924
|
+
ticks: [0, idealCycleTime, ...Array.from({ length: 4 }, (_, i) => (i + 1) * Math.ceil(idealCycleTime / 2))].sort((a, b) => a - b),
|
|
32925
|
+
tickFormatter: (value) => String(value),
|
|
32926
|
+
tick: (props) => {
|
|
32927
|
+
const { x, y, payload } = props;
|
|
32928
|
+
const displayValue = typeof payload.value === "number" ? payload.value.toFixed(1) : String(payload.value);
|
|
32929
|
+
return /* @__PURE__ */ jsxRuntime.jsx("g", { transform: `translate(${x},${y})`, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
32930
|
+
"text",
|
|
32931
|
+
{
|
|
32932
|
+
x: 0,
|
|
32933
|
+
y: 0,
|
|
32934
|
+
dy: 4,
|
|
32935
|
+
textAnchor: "end",
|
|
32936
|
+
fill: payload.value === idealCycleTime ? "#E34329" : "#666",
|
|
32937
|
+
fontSize: 12,
|
|
32938
|
+
fontWeight: payload.value === idealCycleTime ? "bold" : "normal",
|
|
32939
|
+
children: displayValue
|
|
32940
|
+
},
|
|
32941
|
+
`tick-${payload.value}-${x}-${y}`
|
|
32942
|
+
) });
|
|
32881
32943
|
}
|
|
32882
|
-
|
|
32883
|
-
|
|
32884
|
-
|
|
32885
|
-
|
|
32886
|
-
|
|
32887
|
-
"
|
|
32888
|
-
|
|
32889
|
-
|
|
32890
|
-
|
|
32891
|
-
|
|
32892
|
-
|
|
32893
|
-
|
|
32894
|
-
|
|
32895
|
-
|
|
32896
|
-
|
|
32897
|
-
|
|
32944
|
+
}
|
|
32945
|
+
),
|
|
32946
|
+
showIdleTime && /* @__PURE__ */ jsxRuntime.jsx(
|
|
32947
|
+
recharts.YAxis,
|
|
32948
|
+
{
|
|
32949
|
+
yAxisId: "idle",
|
|
32950
|
+
orientation: "right",
|
|
32951
|
+
tickMargin: 8,
|
|
32952
|
+
width: 35,
|
|
32953
|
+
domain: [0, 60],
|
|
32954
|
+
tickFormatter: (value) => `${value}m`,
|
|
32955
|
+
tick: { fontSize: 11, fill: "#f59e0b" },
|
|
32956
|
+
axisLine: false,
|
|
32957
|
+
tickLine: false
|
|
32958
|
+
}
|
|
32959
|
+
),
|
|
32960
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
32961
|
+
recharts.Tooltip,
|
|
32962
|
+
{
|
|
32963
|
+
cursor: { stroke: "#E5E7EB", strokeWidth: 1 },
|
|
32964
|
+
content: renderChartTooltip,
|
|
32965
|
+
animationDuration: 200
|
|
32966
|
+
}
|
|
32967
|
+
),
|
|
32968
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
32969
|
+
recharts.ReferenceLine,
|
|
32970
|
+
{
|
|
32971
|
+
y: idealCycleTime,
|
|
32972
|
+
yAxisId: "cycle",
|
|
32973
|
+
stroke: "#E34329",
|
|
32974
|
+
strokeDasharray: "3 3",
|
|
32975
|
+
strokeWidth: 2,
|
|
32976
|
+
label: {
|
|
32977
|
+
position: "right",
|
|
32978
|
+
value: `${idealCycleTime.toFixed(1)}s`,
|
|
32979
|
+
fill: "#E34329",
|
|
32980
|
+
fontSize: 12,
|
|
32981
|
+
fontWeight: 500
|
|
32898
32982
|
}
|
|
32899
|
-
|
|
32900
|
-
|
|
32901
|
-
|
|
32902
|
-
|
|
32903
|
-
|
|
32904
|
-
|
|
32905
|
-
|
|
32906
|
-
|
|
32907
|
-
|
|
32908
|
-
|
|
32909
|
-
|
|
32910
|
-
|
|
32911
|
-
|
|
32912
|
-
|
|
32913
|
-
|
|
32914
|
-
|
|
32915
|
-
|
|
32916
|
-
|
|
32917
|
-
|
|
32918
|
-
|
|
32919
|
-
|
|
32920
|
-
|
|
32921
|
-
|
|
32922
|
-
|
|
32923
|
-
|
|
32924
|
-
|
|
32925
|
-
|
|
32926
|
-
|
|
32927
|
-
|
|
32983
|
+
}
|
|
32984
|
+
),
|
|
32985
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
32986
|
+
recharts.Line,
|
|
32987
|
+
{
|
|
32988
|
+
type: "monotone",
|
|
32989
|
+
yAxisId: "cycle",
|
|
32990
|
+
dataKey: "cycleTime",
|
|
32991
|
+
stroke: "#3B82F6",
|
|
32992
|
+
strokeWidth: 2,
|
|
32993
|
+
connectNulls: false,
|
|
32994
|
+
dot: renderCycleDot,
|
|
32995
|
+
activeDot: renderCycleActiveDot,
|
|
32996
|
+
isAnimationActive: true,
|
|
32997
|
+
animationBegin: 300,
|
|
32998
|
+
animationDuration: 1500,
|
|
32999
|
+
animationEasing: "ease-out"
|
|
33000
|
+
},
|
|
33001
|
+
`${effectiveDatasetKey}:cycle`
|
|
33002
|
+
),
|
|
33003
|
+
showIdleTime && /* @__PURE__ */ jsxRuntime.jsx(
|
|
33004
|
+
recharts.Line,
|
|
33005
|
+
{
|
|
33006
|
+
type: "monotone",
|
|
33007
|
+
yAxisId: "idle",
|
|
33008
|
+
dataKey: "idleMinutes",
|
|
33009
|
+
stroke: "#f59e0b",
|
|
33010
|
+
strokeWidth: 2,
|
|
33011
|
+
strokeDasharray: "4 4",
|
|
33012
|
+
connectNulls: false,
|
|
33013
|
+
dot: renderIdleDot,
|
|
33014
|
+
activeDot: renderIdleActiveDot,
|
|
33015
|
+
isAnimationActive: true,
|
|
33016
|
+
animationBegin: 300,
|
|
33017
|
+
animationDuration: 1500,
|
|
33018
|
+
animationEasing: "ease-out"
|
|
33019
|
+
},
|
|
33020
|
+
`${effectiveDatasetKey}:idle`
|
|
33021
|
+
)
|
|
33022
|
+
]
|
|
33023
|
+
},
|
|
33024
|
+
hasValidData ? "valid" : "empty"
|
|
33025
|
+
)
|
|
32928
33026
|
}
|
|
32929
|
-
) })
|
|
33027
|
+
) })
|
|
32930
33028
|
]
|
|
32931
33029
|
}
|
|
32932
33030
|
);
|
|
@@ -33776,10 +33874,10 @@ var HourlyOutputChart = React141__namespace.default.memo(HourlyOutputChartCompon
|
|
|
33776
33874
|
HourlyOutputChart.displayName = "HourlyOutputChart";
|
|
33777
33875
|
|
|
33778
33876
|
// src/components/dashboard/grid/videoGridMetricUtils.ts
|
|
33779
|
-
var VIDEO_GRID_LEGEND_LABEL = "
|
|
33877
|
+
var VIDEO_GRID_LEGEND_LABEL = "7 Minute Efficiency";
|
|
33780
33878
|
var MAP_GRID_LEGEND_LABEL = "Efficiency";
|
|
33781
|
-
var MIXED_VIDEO_GRID_LEGEND_LABEL = "
|
|
33782
|
-
var
|
|
33879
|
+
var MIXED_VIDEO_GRID_LEGEND_LABEL = "Efficiency";
|
|
33880
|
+
var isFiniteNumber = (value) => typeof value === "number" && Number.isFinite(value);
|
|
33783
33881
|
var isVideoGridRecentFlowEnabled = (workspace) => isRecentFlowVideoGridMetricMode(
|
|
33784
33882
|
workspace.video_grid_metric_mode,
|
|
33785
33883
|
workspace.assembly_enabled === true
|
|
@@ -33788,11 +33886,11 @@ var isVideoGridWipGated = (workspace) => isWipGatedVideoGridMetricMode(
|
|
|
33788
33886
|
workspace.video_grid_metric_mode,
|
|
33789
33887
|
workspace.assembly_enabled === true
|
|
33790
33888
|
);
|
|
33791
|
-
var hasVideoGridRecentFlow = (workspace) => isVideoGridRecentFlowEnabled(workspace) &&
|
|
33889
|
+
var hasVideoGridRecentFlow = (workspace) => isVideoGridRecentFlowEnabled(workspace) && isFiniteNumber(workspace.recent_flow_percent);
|
|
33792
33890
|
var isVideoGridRecentFlowUnavailable = (workspace) => isVideoGridRecentFlowEnabled(workspace) && !hasVideoGridRecentFlow(workspace);
|
|
33793
33891
|
var getVideoGridMetricValue = (workspace) => {
|
|
33794
33892
|
const recentFlowPercent = workspace.recent_flow_percent;
|
|
33795
|
-
if (hasVideoGridRecentFlow(workspace) &&
|
|
33893
|
+
if (hasVideoGridRecentFlow(workspace) && isFiniteNumber(recentFlowPercent)) {
|
|
33796
33894
|
return recentFlowPercent;
|
|
33797
33895
|
}
|
|
33798
33896
|
if (isVideoGridRecentFlowUnavailable(workspace)) {
|
|
@@ -33803,7 +33901,7 @@ var getVideoGridMetricValue = (workspace) => {
|
|
|
33803
33901
|
var hasIncomingWipMapping = (workspace) => Boolean(workspace.incoming_wip_buffer_name);
|
|
33804
33902
|
var getVideoGridBaseColorState = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => {
|
|
33805
33903
|
const metricValue = getVideoGridMetricValue(workspace);
|
|
33806
|
-
if (!
|
|
33904
|
+
if (!isFiniteNumber(metricValue)) {
|
|
33807
33905
|
return "neutral";
|
|
33808
33906
|
}
|
|
33809
33907
|
return getEfficiencyColor(metricValue, legend);
|
|
@@ -33818,7 +33916,7 @@ var isLowWipGreenOverride = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => {
|
|
|
33818
33916
|
if (!hasIncomingWipMapping(workspace)) {
|
|
33819
33917
|
return false;
|
|
33820
33918
|
}
|
|
33821
|
-
return
|
|
33919
|
+
return isFiniteNumber(workspace.incoming_wip_current) && workspace.incoming_wip_current <= 1;
|
|
33822
33920
|
};
|
|
33823
33921
|
var toMinuteBucket = (minuteBucket) => Number.isFinite(minuteBucket) ? Math.floor(minuteBucket) : Math.floor(Date.now() / 6e4);
|
|
33824
33922
|
var getEffectiveFlowMinuteBucket = (workspace) => {
|
|
@@ -33860,7 +33958,7 @@ var getVideoGridColorState = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) =>
|
|
|
33860
33958
|
if (!hasIncomingWipMapping(workspace)) {
|
|
33861
33959
|
return baseColor;
|
|
33862
33960
|
}
|
|
33863
|
-
if (!
|
|
33961
|
+
if (!isFiniteNumber(workspace.incoming_wip_current)) {
|
|
33864
33962
|
return "neutral";
|
|
33865
33963
|
}
|
|
33866
33964
|
if (isLowWipGreenOverride(workspace, legend)) {
|
|
@@ -34052,7 +34150,7 @@ var VideoCard = React141__namespace.default.memo(({
|
|
|
34052
34150
|
}
|
|
34053
34151
|
);
|
|
34054
34152
|
}, (prevProps, nextProps) => {
|
|
34055
|
-
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.
|
|
34153
|
+
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) {
|
|
34056
34154
|
return false;
|
|
34057
34155
|
}
|
|
34058
34156
|
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) {
|
|
@@ -34644,8 +34742,20 @@ var CardFooter2 = (props) => {
|
|
|
34644
34742
|
return /* @__PURE__ */ jsxRuntime.jsx(RegisteredCardFooter, { ...props });
|
|
34645
34743
|
};
|
|
34646
34744
|
|
|
34745
|
+
// src/lib/utils/workspaceDetailCycleTime.ts
|
|
34746
|
+
var resolveWorkspaceDetailActionFamily = (workspace) => {
|
|
34747
|
+
if (workspace?.action_family === "assembly" || workspace?.action_family === "output" || workspace?.action_family === "other") {
|
|
34748
|
+
return workspace.action_family;
|
|
34749
|
+
}
|
|
34750
|
+
if (workspace?.action_type === "assembly" || workspace?.action_type === "output") {
|
|
34751
|
+
return workspace.action_type;
|
|
34752
|
+
}
|
|
34753
|
+
return null;
|
|
34754
|
+
};
|
|
34755
|
+
var shouldUseAssemblyCycleTimeLayout = (workspace) => workspace?.line_assembly_enabled === true && resolveWorkspaceDetailActionFamily(workspace) === "assembly";
|
|
34756
|
+
|
|
34647
34757
|
// src/components/dashboard/workspace/workspaceDetailCardRules.ts
|
|
34648
|
-
var shouldHideWorkspaceEfficiencyCard = (workspace) => workspace
|
|
34758
|
+
var shouldHideWorkspaceEfficiencyCard = (workspace) => shouldUseAssemblyCycleTimeLayout(workspace);
|
|
34649
34759
|
var WorkspaceMetricCardsImpl = ({
|
|
34650
34760
|
workspace,
|
|
34651
34761
|
className,
|
|
@@ -35354,6 +35464,37 @@ var getShiftElapsedMinutes = ({
|
|
|
35354
35464
|
const elapsed = dateFns.differenceInMinutes(now4, shiftStartDate);
|
|
35355
35465
|
return Math.min(Math.max(elapsed, 0), shiftMinutes);
|
|
35356
35466
|
};
|
|
35467
|
+
var maskFutureHourlySeries = ({
|
|
35468
|
+
data,
|
|
35469
|
+
shiftStart,
|
|
35470
|
+
shiftEnd,
|
|
35471
|
+
shiftDate,
|
|
35472
|
+
timezone,
|
|
35473
|
+
now: now4 = /* @__PURE__ */ new Date()
|
|
35474
|
+
}) => {
|
|
35475
|
+
if (!Array.isArray(data)) {
|
|
35476
|
+
return [];
|
|
35477
|
+
}
|
|
35478
|
+
const normalizedData = data.map((value) => typeof value === "number" && Number.isFinite(value) ? value : null);
|
|
35479
|
+
if (!normalizedData.length) {
|
|
35480
|
+
return normalizedData;
|
|
35481
|
+
}
|
|
35482
|
+
const shiftMinutes = getShiftDurationMinutes(shiftStart, shiftEnd);
|
|
35483
|
+
const elapsedMinutes = getShiftElapsedMinutes({
|
|
35484
|
+
shiftStart,
|
|
35485
|
+
shiftEnd,
|
|
35486
|
+
shiftDate,
|
|
35487
|
+
timezone,
|
|
35488
|
+
now: now4
|
|
35489
|
+
});
|
|
35490
|
+
if (shiftMinutes === null || elapsedMinutes === null || elapsedMinutes >= shiftMinutes) {
|
|
35491
|
+
return normalizedData;
|
|
35492
|
+
}
|
|
35493
|
+
return normalizedData.map((value, index) => {
|
|
35494
|
+
const slotStartMinutes = index * 60;
|
|
35495
|
+
return slotStartMinutes > elapsedMinutes ? null : value;
|
|
35496
|
+
});
|
|
35497
|
+
};
|
|
35357
35498
|
var buildUptimeSeries = ({
|
|
35358
35499
|
idleTimeHourly,
|
|
35359
35500
|
shiftStart,
|
|
@@ -44477,7 +44618,7 @@ var ShiftDisplay = React141.memo(({ className, variant = "default", lineId }) =>
|
|
|
44477
44618
|
return null;
|
|
44478
44619
|
}
|
|
44479
44620
|
};
|
|
44480
|
-
const
|
|
44621
|
+
const getShiftIcon2 = (shift) => {
|
|
44481
44622
|
if (shift === "Day") {
|
|
44482
44623
|
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" }) });
|
|
44483
44624
|
} else {
|
|
@@ -44503,7 +44644,7 @@ var ShiftDisplay = React141.memo(({ className, variant = "default", lineId }) =>
|
|
|
44503
44644
|
}
|
|
44504
44645
|
if (variant === "enhanced") {
|
|
44505
44646
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `inline-flex items-center gap-2 bg-blue-50 rounded-lg px-3 py-1.5 ${className ?? ""}`, children: [
|
|
44506
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-800", children:
|
|
44647
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-800", children: getShiftIcon2(currentShiftText) }),
|
|
44507
44648
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-base font-medium text-blue-800", children: [
|
|
44508
44649
|
currentShiftText,
|
|
44509
44650
|
" Shift"
|
|
@@ -44511,7 +44652,7 @@ var ShiftDisplay = React141.memo(({ className, variant = "default", lineId }) =>
|
|
|
44511
44652
|
] });
|
|
44512
44653
|
}
|
|
44513
44654
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `inline-flex items-center gap-2 bg-blue-50 rounded-lg px-3 py-1.5 ${className ?? ""}`, children: [
|
|
44514
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-800", children:
|
|
44655
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-800", children: getShiftIcon2(currentShiftText) }),
|
|
44515
44656
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-base font-medium text-blue-800", children: [
|
|
44516
44657
|
currentShiftText,
|
|
44517
44658
|
" Shift"
|
|
@@ -47148,7 +47289,7 @@ var LinePdfGenerator = ({
|
|
|
47148
47289
|
doc.setLineWidth(0.8);
|
|
47149
47290
|
doc.line(20, 123, 190, 123);
|
|
47150
47291
|
const hourlyOverviewStartY = 128;
|
|
47151
|
-
const
|
|
47292
|
+
const parseTimeToMinutes4 = (timeStr) => {
|
|
47152
47293
|
const [hours, minutes] = timeStr.split(":");
|
|
47153
47294
|
const hour = parseInt(hours, 10);
|
|
47154
47295
|
const minute = parseInt(minutes || "0", 10);
|
|
@@ -47181,7 +47322,7 @@ var LinePdfGenerator = ({
|
|
|
47181
47322
|
};
|
|
47182
47323
|
};
|
|
47183
47324
|
const getHourlyTimeRanges = (startTimeStr, endTimeStr) => {
|
|
47184
|
-
const startMinutes =
|
|
47325
|
+
const startMinutes = parseTimeToMinutes4(startTimeStr);
|
|
47185
47326
|
if (Number.isNaN(startMinutes)) {
|
|
47186
47327
|
return [];
|
|
47187
47328
|
}
|
|
@@ -47189,7 +47330,7 @@ var LinePdfGenerator = ({
|
|
|
47189
47330
|
const defaultHours = 11;
|
|
47190
47331
|
return Array.from({ length: defaultHours }, (_, i) => buildRange(startMinutes + i * 60, 60));
|
|
47191
47332
|
}
|
|
47192
|
-
const endMinutes =
|
|
47333
|
+
const endMinutes = parseTimeToMinutes4(endTimeStr);
|
|
47193
47334
|
if (Number.isNaN(endMinutes)) {
|
|
47194
47335
|
const fallbackHours = 11;
|
|
47195
47336
|
return Array.from({ length: fallbackHours }, (_, i) => buildRange(startMinutes + i * 60, 60));
|
|
@@ -48892,7 +49033,7 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
|
|
|
48892
49033
|
setIsGenerating(true);
|
|
48893
49034
|
try {
|
|
48894
49035
|
const isUptimeMode = workspace.monitoring_mode === "uptime";
|
|
48895
|
-
const isAssemblyCycleMode = !isUptimeMode && workspace
|
|
49036
|
+
const isAssemblyCycleMode = !isUptimeMode && shouldUseAssemblyCycleTimeLayout(workspace);
|
|
48896
49037
|
const shiftMinutes = getShiftDurationMinutes(workspace.shift_start, workspace.shift_end);
|
|
48897
49038
|
const shiftSeconds = shiftMinutes ? shiftMinutes * 60 : 0;
|
|
48898
49039
|
const idleSeconds = Math.max(workspace.idle_time || 0, 0);
|
|
@@ -48958,7 +49099,7 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
|
|
|
48958
49099
|
minute: "2-digit",
|
|
48959
49100
|
hour12: true
|
|
48960
49101
|
});
|
|
48961
|
-
const
|
|
49102
|
+
const parseTimeToMinutes4 = (timeValue) => {
|
|
48962
49103
|
const [hourPart, minutePart] = timeValue.split(":").map(Number);
|
|
48963
49104
|
const hour = Number.isFinite(hourPart) ? hourPart : 0;
|
|
48964
49105
|
const minute = Number.isFinite(minutePart) ? minutePart : 0;
|
|
@@ -48975,8 +49116,8 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
|
|
|
48975
49116
|
const IST_OFFSET_MINUTES = 330;
|
|
48976
49117
|
return Date.UTC(year, month - 1, day, hour, minute) - IST_OFFSET_MINUTES * 60 * 1e3;
|
|
48977
49118
|
};
|
|
48978
|
-
const shiftStartMinutes =
|
|
48979
|
-
const shiftEndMinutes =
|
|
49119
|
+
const shiftStartMinutes = parseTimeToMinutes4(workspace.shift_start);
|
|
49120
|
+
const shiftEndMinutes = parseTimeToMinutes4(workspace.shift_end);
|
|
48980
49121
|
const wrapsMidnight = shiftEndMinutes <= shiftStartMinutes;
|
|
48981
49122
|
const shiftStartUtcMs = toShiftUtcMs(workspace.date, workspace.shift_start);
|
|
48982
49123
|
const shiftEndUtcMs = toShiftUtcMs(workspace.date, workspace.shift_end) + (wrapsMidnight ? 24 * 60 * 60 * 1e3 : 0);
|
|
@@ -51283,7 +51424,7 @@ var DashboardHeader = React141.memo(({ lineTitle, className = "", headerControls
|
|
|
51283
51424
|
const rawName = currentShift.shiftName || "Day";
|
|
51284
51425
|
return rawName.toLowerCase().includes("shift") ? rawName : `${rawName} Shift`;
|
|
51285
51426
|
};
|
|
51286
|
-
const
|
|
51427
|
+
const getShiftIcon2 = () => {
|
|
51287
51428
|
const currentShift = getCurrentShift(timezone, shiftConfig);
|
|
51288
51429
|
const shiftName = (currentShift.shiftName || "").toLowerCase();
|
|
51289
51430
|
if (shiftName.includes("day") || shiftName.includes("morning") || currentShift.shiftId === 0) {
|
|
@@ -51317,7 +51458,7 @@ var DashboardHeader = React141.memo(({ lineTitle, className = "", headerControls
|
|
|
51317
51458
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: /* @__PURE__ */ jsxRuntime.jsx(Timer2, {}) }),
|
|
51318
51459
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-300", children: "|" }),
|
|
51319
51460
|
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: [
|
|
51320
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-75", children:
|
|
51461
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-75", children: getShiftIcon2() }),
|
|
51321
51462
|
getShiftName()
|
|
51322
51463
|
] })
|
|
51323
51464
|
] })
|
|
@@ -51334,7 +51475,7 @@ var DashboardHeader = React141.memo(({ lineTitle, className = "", headerControls
|
|
|
51334
51475
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 inline-flex flex-wrap items-center gap-3", children: [
|
|
51335
51476
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs md:text-sm font-medium text-gray-600 whitespace-nowrap", children: /* @__PURE__ */ jsxRuntime.jsx(Timer2, {}) }),
|
|
51336
51477
|
/* @__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: [
|
|
51337
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-600", children:
|
|
51478
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-600", children: getShiftIcon2() }),
|
|
51338
51479
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs md:text-sm font-medium text-gray-600 whitespace-nowrap", children: getShiftName() })
|
|
51339
51480
|
] }) })
|
|
51340
51481
|
] })
|
|
@@ -58305,7 +58446,7 @@ var FactoryView = ({
|
|
|
58305
58446
|
const currentShift = getCurrentShiftInfo();
|
|
58306
58447
|
return (currentShift.shiftName || "Day").replace(/ Shift$/i, "");
|
|
58307
58448
|
};
|
|
58308
|
-
const
|
|
58449
|
+
const getShiftIcon2 = () => {
|
|
58309
58450
|
const currentShift = getCurrentShiftInfo();
|
|
58310
58451
|
const shiftNameLower = (currentShift.shiftName || "").toLowerCase();
|
|
58311
58452
|
if (shiftNameLower.includes("day") || shiftNameLower.includes("morning") || currentShift.shiftId === 0) {
|
|
@@ -58351,7 +58492,7 @@ var FactoryView = ({
|
|
|
58351
58492
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex items-center justify-center gap-2", children: [
|
|
58352
58493
|
/* @__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, {}) }) }),
|
|
58353
58494
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
|
|
58354
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children:
|
|
58495
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon2() }),
|
|
58355
58496
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs font-medium text-gray-700", children: [
|
|
58356
58497
|
getShiftName(),
|
|
58357
58498
|
" Shift"
|
|
@@ -58370,7 +58511,7 @@ var FactoryView = ({
|
|
|
58370
58511
|
" IST"
|
|
58371
58512
|
] }),
|
|
58372
58513
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-1", children: [
|
|
58373
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-600", children:
|
|
58514
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-600", children: getShiftIcon2() }),
|
|
58374
58515
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm font-medium text-gray-600", children: [
|
|
58375
58516
|
getShiftName(),
|
|
58376
58517
|
" Shift"
|
|
@@ -61082,7 +61223,7 @@ var KPIDetailView = ({
|
|
|
61082
61223
|
const getShiftName = React141.useCallback((shiftId) => {
|
|
61083
61224
|
return getShiftNameById(shiftId, configuredTimezone, shiftConfig);
|
|
61084
61225
|
}, [configuredTimezone, shiftConfig]);
|
|
61085
|
-
const
|
|
61226
|
+
const getShiftIcon2 = React141.useCallback((shiftId) => {
|
|
61086
61227
|
if (shiftId === 0) {
|
|
61087
61228
|
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" }) });
|
|
61088
61229
|
}
|
|
@@ -61962,7 +62103,7 @@ var KPIDetailView = ({
|
|
|
61962
62103
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sm:hidden mt-3 flex items-center justify-center gap-2", children: [
|
|
61963
62104
|
/* @__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)) }) }),
|
|
61964
62105
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
|
|
61965
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children:
|
|
62106
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon2(chartMetrics.shift_id ?? 0) }),
|
|
61966
62107
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs font-medium text-gray-700", children: [
|
|
61967
62108
|
getShiftName(chartMetrics.shift_id ?? 0).replace(/ Shift$/i, ""),
|
|
61968
62109
|
" Shift"
|
|
@@ -61988,7 +62129,7 @@ var KPIDetailView = ({
|
|
|
61988
62129
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-200" })
|
|
61989
62130
|
] }),
|
|
61990
62131
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
|
|
61991
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "opacity-70", children:
|
|
62132
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "opacity-70", children: getShiftIcon2(chartMetrics.shift_id ?? 0) }),
|
|
61992
62133
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm md:text-base font-semibold uppercase tracking-wider", children: [
|
|
61993
62134
|
getShiftName(chartMetrics.shift_id ?? 0).replace(/ Shift$/i, ""),
|
|
61994
62135
|
" Shift"
|
|
@@ -62006,7 +62147,7 @@ var KPIDetailView = ({
|
|
|
62006
62147
|
return `${startDate.toLocaleDateString("en-US", { month: "short", day: "numeric" })} - ${endDate.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })}`;
|
|
62007
62148
|
})() }) }),
|
|
62008
62149
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
|
|
62009
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children:
|
|
62150
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon2(selectedShiftId) }),
|
|
62010
62151
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: getShiftName(selectedShiftId) })
|
|
62011
62152
|
] })
|
|
62012
62153
|
] }),
|
|
@@ -62023,7 +62164,7 @@ var KPIDetailView = ({
|
|
|
62023
62164
|
] }),
|
|
62024
62165
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-200" }),
|
|
62025
62166
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
|
|
62026
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "opacity-70", children:
|
|
62167
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "opacity-70", children: getShiftIcon2(selectedShiftId) }),
|
|
62027
62168
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm md:text-base font-semibold uppercase tracking-wider", children: [
|
|
62028
62169
|
getShiftName(selectedShiftId).replace(/ Shift$/i, ""),
|
|
62029
62170
|
" Shift"
|
|
@@ -63399,7 +63540,7 @@ var KPIsOverviewView = ({
|
|
|
63399
63540
|
const headerShiftId = showHistoricalLeaderboardHeader ? effectiveLeaderboardShiftId : currentShiftDetails.shiftId;
|
|
63400
63541
|
const headerShiftName = getShiftNameById(headerShiftId, configuredTimezone, shiftConfig).replace(/ Shift$/i, "");
|
|
63401
63542
|
const headerDateLabel = isMonthlyMode ? getMonthRange() : formatLocalDate2(headerDateKey);
|
|
63402
|
-
const
|
|
63543
|
+
const getShiftIcon2 = (shiftId) => {
|
|
63403
63544
|
const shiftNameLower = getShiftNameById(shiftId, configuredTimezone, shiftConfig).toLowerCase();
|
|
63404
63545
|
if (shiftNameLower.includes("day") || shiftNameLower.includes("morning") || shiftId === 0) {
|
|
63405
63546
|
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" }) });
|
|
@@ -63516,7 +63657,7 @@ var KPIsOverviewView = ({
|
|
|
63516
63657
|
/* @__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 }) }),
|
|
63517
63658
|
!isMonthlyMode && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
63518
63659
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
|
|
63519
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children:
|
|
63660
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon2(headerShiftId) }),
|
|
63520
63661
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: headerShiftName })
|
|
63521
63662
|
] }),
|
|
63522
63663
|
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: [
|
|
@@ -63712,7 +63853,7 @@ var KPIsOverviewView = ({
|
|
|
63712
63853
|
!isMonthlyMode && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
63713
63854
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-200" }),
|
|
63714
63855
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
|
|
63715
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "opacity-70", children:
|
|
63856
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "opacity-70", children: getShiftIcon2(headerShiftId) }),
|
|
63716
63857
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm font-semibold uppercase tracking-wider", children: [
|
|
63717
63858
|
headerShiftName,
|
|
63718
63859
|
" Shift"
|
|
@@ -63856,6 +63997,52 @@ var KPIsOverviewView = ({
|
|
|
63856
63997
|
] });
|
|
63857
63998
|
};
|
|
63858
63999
|
var KPIsOverviewView_default = KPIsOverviewView;
|
|
64000
|
+
var toFiniteNumber = (value) => {
|
|
64001
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
64002
|
+
if (typeof value === "string" && value.trim() !== "") {
|
|
64003
|
+
const parsed = Number(value);
|
|
64004
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
64005
|
+
}
|
|
64006
|
+
return null;
|
|
64007
|
+
};
|
|
64008
|
+
var getCycleRatio = (workspace) => {
|
|
64009
|
+
const idealCycleTime = toFiniteNumber(workspace.ideal_cycle_time);
|
|
64010
|
+
const avgCycleTime = toFiniteNumber(workspace.avg_cycle_time);
|
|
64011
|
+
if (idealCycleTime === null || avgCycleTime === null || idealCycleTime <= 0 || avgCycleTime <= 0) {
|
|
64012
|
+
return null;
|
|
64013
|
+
}
|
|
64014
|
+
return idealCycleTime / avgCycleTime;
|
|
64015
|
+
};
|
|
64016
|
+
var formatCycleTimeValue = (value) => {
|
|
64017
|
+
const numericValue = toFiniteNumber(value);
|
|
64018
|
+
if (numericValue === null || numericValue <= 0) return "--";
|
|
64019
|
+
return `${numericValue.toFixed(1)}s`;
|
|
64020
|
+
};
|
|
64021
|
+
var CycleTimeComparison = React141.memo(({
|
|
64022
|
+
workspace,
|
|
64023
|
+
variant = "table"
|
|
64024
|
+
}) => {
|
|
64025
|
+
const averageValue = formatCycleTimeValue(workspace.avg_cycle_time);
|
|
64026
|
+
const standardValue = formatCycleTimeValue(workspace.ideal_cycle_time);
|
|
64027
|
+
if (variant === "mobile") {
|
|
64028
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex items-center justify-between py-2 border-t border-gray-100", children: [
|
|
64029
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-500 uppercase tracking-wider", children: "Standard Cycle Time" }),
|
|
64030
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium tabular-nums text-gray-500", children: standardValue })
|
|
64031
|
+
] });
|
|
64032
|
+
}
|
|
64033
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
64034
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
|
|
64035
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-medium uppercase tracking-wider text-gray-500", children: "Average" }),
|
|
64036
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold tabular-nums text-gray-900", children: averageValue })
|
|
64037
|
+
] }),
|
|
64038
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-6 w-px bg-gray-200" }),
|
|
64039
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
|
|
64040
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-medium uppercase tracking-wider text-gray-500", children: "Standard" }),
|
|
64041
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium tabular-nums text-gray-500", children: standardValue })
|
|
64042
|
+
] })
|
|
64043
|
+
] });
|
|
64044
|
+
}, (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);
|
|
64045
|
+
CycleTimeComparison.displayName = "CycleTimeComparison";
|
|
63859
64046
|
var IsolatedTimer = React141.memo(() => {
|
|
63860
64047
|
return /* @__PURE__ */ jsxRuntime.jsx(ISTTimer_default, {});
|
|
63861
64048
|
});
|
|
@@ -63873,11 +64060,11 @@ var HeaderRibbon = React141.memo(({
|
|
|
63873
64060
|
currentDate,
|
|
63874
64061
|
currentMobileDate,
|
|
63875
64062
|
shiftId,
|
|
63876
|
-
getShiftIcon,
|
|
64063
|
+
getShiftIcon: getShiftIcon2,
|
|
63877
64064
|
getShiftName,
|
|
63878
64065
|
showTimer = true
|
|
63879
64066
|
}) => {
|
|
63880
|
-
const shiftIcon = React141.useMemo(() =>
|
|
64067
|
+
const shiftIcon = React141.useMemo(() => getShiftIcon2(shiftId), [getShiftIcon2, shiftId]);
|
|
63881
64068
|
const shiftName = React141.useMemo(() => getShiftName(shiftId), [getShiftName, shiftId]);
|
|
63882
64069
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
63883
64070
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sm:hidden mt-3 flex items-center justify-center gap-2", children: [
|
|
@@ -63919,8 +64106,9 @@ var MobileWorkspaceCard = React141.memo(({
|
|
|
63919
64106
|
isClickable,
|
|
63920
64107
|
onWorkspaceClick,
|
|
63921
64108
|
getMedalIcon,
|
|
63922
|
-
|
|
63923
|
-
|
|
64109
|
+
metricLabel,
|
|
64110
|
+
isAssemblyMode
|
|
64111
|
+
}) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
63924
64112
|
motion.div,
|
|
63925
64113
|
{
|
|
63926
64114
|
layout: true,
|
|
@@ -63931,28 +64119,31 @@ var MobileWorkspaceCard = React141.memo(({
|
|
|
63931
64119
|
},
|
|
63932
64120
|
onClick: isClickable ? () => onWorkspaceClick(workspace, rank) : void 0,
|
|
63933
64121
|
className: `${cardClass} p-3 rounded-lg border shadow-sm active:scale-[0.98] ${isClickable ? "cursor-pointer" : "cursor-not-allowed opacity-75"}`,
|
|
63934
|
-
children:
|
|
63935
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
63936
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-
|
|
63937
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "
|
|
63938
|
-
"
|
|
63939
|
-
|
|
64122
|
+
children: [
|
|
64123
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-2 gap-3", children: [
|
|
64124
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
64125
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
64126
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-2xl font-bold text-gray-700", children: [
|
|
64127
|
+
"#",
|
|
64128
|
+
rank
|
|
64129
|
+
] }),
|
|
64130
|
+
getMedalIcon(rank)
|
|
63940
64131
|
] }),
|
|
63941
|
-
|
|
64132
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
64133
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-semibold text-gray-900", children: workspace.displayName }),
|
|
64134
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-gray-500", children: workspace.lineName })
|
|
64135
|
+
] })
|
|
63942
64136
|
] }),
|
|
63943
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
63944
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-
|
|
63945
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-gray-500", children:
|
|
64137
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-right", children: [
|
|
64138
|
+
/* @__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 }) }),
|
|
64139
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-gray-500", children: metricLabel })
|
|
63946
64140
|
] })
|
|
63947
64141
|
] }),
|
|
63948
|
-
/* @__PURE__ */ jsxRuntime.
|
|
63949
|
-
|
|
63950
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-gray-500", children: efficiencyLabel })
|
|
63951
|
-
] })
|
|
63952
|
-
] })
|
|
64142
|
+
isAssemblyMode && /* @__PURE__ */ jsxRuntime.jsx(CycleTimeComparison, { workspace, variant: "mobile" })
|
|
64143
|
+
]
|
|
63953
64144
|
}
|
|
63954
64145
|
), (prevProps, nextProps) => {
|
|
63955
|
-
return prevProps.
|
|
64146
|
+
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;
|
|
63956
64147
|
});
|
|
63957
64148
|
MobileWorkspaceCard.displayName = "MobileWorkspaceCard";
|
|
63958
64149
|
var DesktopWorkspaceRow = React141.memo(({
|
|
@@ -63961,7 +64152,8 @@ var DesktopWorkspaceRow = React141.memo(({
|
|
|
63961
64152
|
rowClass,
|
|
63962
64153
|
isClickable,
|
|
63963
64154
|
onWorkspaceClick,
|
|
63964
|
-
getMedalIcon
|
|
64155
|
+
getMedalIcon,
|
|
64156
|
+
isAssemblyMode
|
|
63965
64157
|
}) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
63966
64158
|
motion.tr,
|
|
63967
64159
|
{
|
|
@@ -63978,11 +64170,11 @@ var DesktopWorkspaceRow = React141.memo(({
|
|
|
63978
64170
|
] }) }),
|
|
63979
64171
|
/* @__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 }) }),
|
|
63980
64172
|
/* @__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 }) }),
|
|
63981
|
-
/* @__PURE__ */ jsxRuntime.jsx("td", { className:
|
|
64173
|
+
/* @__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 }) })
|
|
63982
64174
|
]
|
|
63983
64175
|
}
|
|
63984
64176
|
), (prevProps, nextProps) => {
|
|
63985
|
-
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;
|
|
64177
|
+
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;
|
|
63986
64178
|
});
|
|
63987
64179
|
DesktopWorkspaceRow.displayName = "DesktopWorkspaceRow";
|
|
63988
64180
|
var LeaderboardDetailView = React141.memo(({
|
|
@@ -64004,6 +64196,7 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64004
64196
|
const supabase = useSupabase();
|
|
64005
64197
|
const [sortAscending, setSortAscending] = React141.useState(false);
|
|
64006
64198
|
const [viewType, setViewType] = React141.useState("operator");
|
|
64199
|
+
const [outputCategory, setOutputCategory] = React141.useState("standard");
|
|
64007
64200
|
const [activeTab, setActiveTab] = React141.useState("today");
|
|
64008
64201
|
const timezone = useAppTimezone();
|
|
64009
64202
|
const staticShiftConfig = useShiftConfig();
|
|
@@ -64082,6 +64275,7 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64082
64275
|
const monthlyRequestKeyRef = React141.useRef(null);
|
|
64083
64276
|
const leaderboardUpdateQueuedRef = React141.useRef(false);
|
|
64084
64277
|
const leaderboardUpdateTimerRef = React141.useRef(null);
|
|
64278
|
+
const leaderboardViewTrackedRef = React141.useRef(null);
|
|
64085
64279
|
const filterRef = React141.useRef(null);
|
|
64086
64280
|
const filterButtonRef = React141.useRef(null);
|
|
64087
64281
|
const mobileFilterButtonRef = React141.useRef(null);
|
|
@@ -64214,6 +64408,17 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64214
64408
|
}
|
|
64215
64409
|
return Array.from(uniqueLines.entries()).map(([id3, name]) => ({ id: id3, label: name }));
|
|
64216
64410
|
}, [configuredLineIds, lines, getLineName]);
|
|
64411
|
+
const scopedLines = React141.useMemo(() => {
|
|
64412
|
+
const configuredLineIdSet = new Set(configuredLineIds);
|
|
64413
|
+
return lines.filter((line) => configuredLineIds.length === 0 || configuredLineIdSet.has(line.id));
|
|
64414
|
+
}, [configuredLineIds, lines]);
|
|
64415
|
+
const scopedLineAssemblyMap = React141.useMemo(() => {
|
|
64416
|
+
const map = /* @__PURE__ */ new Map();
|
|
64417
|
+
scopedLines.forEach((line) => {
|
|
64418
|
+
map.set(line.id, line.assembly === true);
|
|
64419
|
+
});
|
|
64420
|
+
return map;
|
|
64421
|
+
}, [scopedLines]);
|
|
64217
64422
|
const shiftOptions = React141.useMemo(() => {
|
|
64218
64423
|
if (activeShiftConfig?.shifts && activeShiftConfig.shifts.length > 0) {
|
|
64219
64424
|
return activeShiftConfig.shifts.map((shift2) => ({
|
|
@@ -64237,6 +64442,33 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64237
64442
|
const parsed = Number(selectedShiftFilter);
|
|
64238
64443
|
return Number.isFinite(parsed) ? parsed : void 0;
|
|
64239
64444
|
}, [selectedShiftFilter]);
|
|
64445
|
+
const outputScopeLines = React141.useMemo(() => {
|
|
64446
|
+
const outputLines = scopedLines.filter((line) => (line.monitoring_mode ?? "output") !== "uptime");
|
|
64447
|
+
if (selectedLineFilter === "all") {
|
|
64448
|
+
return outputLines;
|
|
64449
|
+
}
|
|
64450
|
+
return outputLines.filter((line) => line.id === selectedLineFilter);
|
|
64451
|
+
}, [scopedLines, selectedLineFilter]);
|
|
64452
|
+
const hasAssemblyOutputScope = React141.useMemo(
|
|
64453
|
+
() => outputScopeLines.some((line) => line.assembly === true),
|
|
64454
|
+
[outputScopeLines]
|
|
64455
|
+
);
|
|
64456
|
+
const hasStandardOutputScope = React141.useMemo(
|
|
64457
|
+
() => outputScopeLines.some((line) => line.assembly !== true),
|
|
64458
|
+
[outputScopeLines]
|
|
64459
|
+
);
|
|
64460
|
+
const showOutputCategoryDropdown = viewType === "operator" && hasAssemblyOutputScope && hasStandardOutputScope;
|
|
64461
|
+
const isAssemblyMode = viewType === "operator" && outputCategory === "assembly";
|
|
64462
|
+
React141.useEffect(() => {
|
|
64463
|
+
if (viewType !== "operator") return;
|
|
64464
|
+
if (hasAssemblyOutputScope && !hasStandardOutputScope && outputCategory !== "assembly") {
|
|
64465
|
+
setOutputCategory("assembly");
|
|
64466
|
+
return;
|
|
64467
|
+
}
|
|
64468
|
+
if (hasStandardOutputScope && !hasAssemblyOutputScope && outputCategory !== "standard") {
|
|
64469
|
+
setOutputCategory("standard");
|
|
64470
|
+
}
|
|
64471
|
+
}, [viewType, hasAssemblyOutputScope, hasStandardOutputScope, outputCategory]);
|
|
64240
64472
|
const handleLineFilterChange = React141.useCallback((value) => {
|
|
64241
64473
|
setSelectedLineFilter(value);
|
|
64242
64474
|
}, []);
|
|
@@ -64246,17 +64478,19 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64246
64478
|
const clearFilters = React141.useCallback(() => {
|
|
64247
64479
|
setSortAscending(false);
|
|
64248
64480
|
setSelectedLineFilter("all");
|
|
64481
|
+
setOutputCategory("standard");
|
|
64249
64482
|
setSelectedShiftFilter(currentShiftInfo.shiftId.toString());
|
|
64250
64483
|
}, [currentShiftInfo.shiftId]);
|
|
64251
64484
|
const activeFiltersCount = React141.useMemo(() => {
|
|
64252
64485
|
let count = 0;
|
|
64253
64486
|
if (sortAscending) count++;
|
|
64254
64487
|
if (selectedLineFilter !== "all") count++;
|
|
64488
|
+
if (showOutputCategoryDropdown && outputCategory !== "standard") count++;
|
|
64255
64489
|
if (selectedShiftFilter !== currentShiftInfo.shiftId.toString()) {
|
|
64256
64490
|
count++;
|
|
64257
64491
|
}
|
|
64258
64492
|
return count;
|
|
64259
|
-
}, [sortAscending, selectedLineFilter, selectedShiftFilter, currentShiftInfo.shiftId]);
|
|
64493
|
+
}, [sortAscending, selectedLineFilter, outputCategory, showOutputCategoryDropdown, selectedShiftFilter, currentShiftInfo.shiftId]);
|
|
64260
64494
|
const shouldFetchShiftConfigs = !date && shiftId === void 0;
|
|
64261
64495
|
const {
|
|
64262
64496
|
shiftConfigMap: multiLineShiftConfigMap,
|
|
@@ -64308,7 +64542,8 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64308
64542
|
action_count: entry.total_output || 0,
|
|
64309
64543
|
pph: entry.avg_pph || 0,
|
|
64310
64544
|
performance_score: entry.performance_score ?? 0,
|
|
64311
|
-
avg_cycle_time: entry.avg_cycle_time
|
|
64545
|
+
avg_cycle_time: toFiniteNumber(entry.avg_cycle_time) ?? 0,
|
|
64546
|
+
ideal_cycle_time: toFiniteNumber(entry.ideal_cycle_time) ?? void 0,
|
|
64312
64547
|
trend: 0,
|
|
64313
64548
|
predicted_output: 0,
|
|
64314
64549
|
efficiency: entry.efficiency || 0,
|
|
@@ -64486,7 +64721,7 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64486
64721
|
const currentShift = getCurrentShift(timezone || "Asia/Kolkata", activeShiftConfig);
|
|
64487
64722
|
return currentShift.shiftName || getShiftNameById(currentShift.shiftId, timezone || "Asia/Kolkata", activeShiftConfig);
|
|
64488
64723
|
}, [timezone, activeShiftConfig, shiftGroups]);
|
|
64489
|
-
const
|
|
64724
|
+
const getShiftIcon2 = React141.useCallback((shiftId2) => {
|
|
64490
64725
|
if (shiftId2 === void 0 && shiftGroups.length > 1) {
|
|
64491
64726
|
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" }) });
|
|
64492
64727
|
}
|
|
@@ -64552,15 +64787,20 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64552
64787
|
if (!canOpenWorkspace(workspace.line_id)) {
|
|
64553
64788
|
return;
|
|
64554
64789
|
}
|
|
64790
|
+
const cycleRatio = getCycleRatio(workspace);
|
|
64555
64791
|
trackCoreEvent("Workspace from Leaderboard Clicked", {
|
|
64556
64792
|
workspace_name: workspace.workspace_name,
|
|
64557
64793
|
workspace_id: workspace.workspace_uuid,
|
|
64558
64794
|
rank,
|
|
64559
64795
|
total_workspaces: workspacesLengthRef.current,
|
|
64560
64796
|
// Use ref instead of state to avoid dependency
|
|
64797
|
+
metric_context: viewType === "machine" ? "machine" : outputCategory,
|
|
64561
64798
|
efficiency: workspace.efficiency,
|
|
64562
64799
|
action_count: workspace.action_count,
|
|
64563
|
-
action_threshold: workspace.action_threshold
|
|
64800
|
+
action_threshold: workspace.action_threshold,
|
|
64801
|
+
avg_cycle_time: workspace.avg_cycle_time,
|
|
64802
|
+
ideal_cycle_time: workspace.ideal_cycle_time ?? null,
|
|
64803
|
+
cycle_ratio: cycleRatio
|
|
64564
64804
|
});
|
|
64565
64805
|
const displayName = workspace.displayName || getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
|
|
64566
64806
|
const navParams = workspace.workspace_uuid ? getWorkspaceNavigationParams(workspace.workspace_uuid, displayName, workspace.line_id) : "";
|
|
@@ -64584,7 +64824,7 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64584
64824
|
const combinedParams = navParams ? `${navParams}&${contextParamString}` : `?${contextParamString}`;
|
|
64585
64825
|
navigation.navigate(`/workspace/${workspace.workspace_uuid}${combinedParams}`);
|
|
64586
64826
|
}
|
|
64587
|
-
}, [canOpenWorkspace, onWorkspaceClick, navigation, date, shiftId]);
|
|
64827
|
+
}, [canOpenWorkspace, onWorkspaceClick, navigation, date, shiftId, outputCategory, viewType]);
|
|
64588
64828
|
React141.useEffect(() => {
|
|
64589
64829
|
workspacesLengthRef.current = activeEntries.length || 0;
|
|
64590
64830
|
}, [activeEntries.length]);
|
|
@@ -64605,16 +64845,20 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64605
64845
|
return activeEntries.map((ws) => ({
|
|
64606
64846
|
...ws,
|
|
64607
64847
|
displayName: ws.displayName || getWorkspaceDisplayName(ws.workspace_name, ws.line_id),
|
|
64608
|
-
lineName: getLineName(ws.line_id)
|
|
64848
|
+
lineName: getLineName(ws.line_id),
|
|
64849
|
+
isAssemblyLine: scopedLineAssemblyMap.get(ws.line_id) === true
|
|
64609
64850
|
}));
|
|
64610
|
-
}, [activeEntries, getLineName]);
|
|
64851
|
+
}, [activeEntries, getLineName, scopedLineAssemblyMap]);
|
|
64611
64852
|
const sortedWorkspaces = React141.useMemo(() => {
|
|
64612
64853
|
let filtered = [...workspaceDisplayData];
|
|
64613
64854
|
filtered = filtered.filter((ws) => {
|
|
64614
64855
|
if (viewType === "machine") {
|
|
64615
64856
|
return ws.monitoring_mode === "uptime";
|
|
64616
64857
|
}
|
|
64617
|
-
|
|
64858
|
+
if (ws.monitoring_mode === "uptime") {
|
|
64859
|
+
return false;
|
|
64860
|
+
}
|
|
64861
|
+
return isAssemblyMode ? ws.isAssemblyLine : !ws.isAssemblyLine;
|
|
64618
64862
|
});
|
|
64619
64863
|
if (selectedLineFilter !== "all") {
|
|
64620
64864
|
filtered = filtered.filter((ws) => ws.line_id === selectedLineFilter);
|
|
@@ -64623,13 +64867,61 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64623
64867
|
filtered = filtered.filter((ws) => ws.shift_id?.toString() === selectedShiftFilter);
|
|
64624
64868
|
}
|
|
64625
64869
|
return filtered.sort((a, b) => {
|
|
64870
|
+
if (isAssemblyMode) {
|
|
64871
|
+
const ratioA = getCycleRatio(a);
|
|
64872
|
+
const ratioB = getCycleRatio(b);
|
|
64873
|
+
if (ratioA === null && ratioB === null) return 0;
|
|
64874
|
+
if (ratioA === null) return 1;
|
|
64875
|
+
if (ratioB === null) return -1;
|
|
64876
|
+
return sortAscending ? ratioA - ratioB : ratioB - ratioA;
|
|
64877
|
+
}
|
|
64626
64878
|
const effA = a.efficiency || 0;
|
|
64627
64879
|
const effB = b.efficiency || 0;
|
|
64628
64880
|
return sortAscending ? effA - effB : effB - effA;
|
|
64629
64881
|
});
|
|
64630
|
-
}, [workspaceDisplayData, sortAscending, selectedLineFilter, selectedShiftFilter, activeTab, viewType]);
|
|
64882
|
+
}, [workspaceDisplayData, sortAscending, selectedLineFilter, selectedShiftFilter, activeTab, viewType, isAssemblyMode]);
|
|
64631
64883
|
const loading = activeTab === "today" ? todayLoading : monthlyLoading;
|
|
64632
64884
|
const error = activeTab === "today" ? todayError : monthlyError;
|
|
64885
|
+
React141.useEffect(() => {
|
|
64886
|
+
if (loading || error || sortedWorkspaces.length === 0) return;
|
|
64887
|
+
const trackingKey = [
|
|
64888
|
+
activeTab,
|
|
64889
|
+
viewType,
|
|
64890
|
+
outputCategory,
|
|
64891
|
+
selectedLineFilter,
|
|
64892
|
+
selectedShiftFilter,
|
|
64893
|
+
sortAscending ? "asc" : "desc",
|
|
64894
|
+
sortedWorkspaces.length
|
|
64895
|
+
].join("|");
|
|
64896
|
+
if (leaderboardViewTrackedRef.current === trackingKey) return;
|
|
64897
|
+
leaderboardViewTrackedRef.current = trackingKey;
|
|
64898
|
+
const topWorkspace = sortedWorkspaces[0];
|
|
64899
|
+
trackCoreEvent("Workspace Leaderboard View Loaded", {
|
|
64900
|
+
time_range: activeTab,
|
|
64901
|
+
view_type: viewType,
|
|
64902
|
+
metric_context: viewType === "machine" ? "machine" : outputCategory,
|
|
64903
|
+
line_filter: selectedLineFilter,
|
|
64904
|
+
shift_filter: selectedShiftFilter,
|
|
64905
|
+
sort_direction: sortAscending ? "asc" : "desc",
|
|
64906
|
+
workspace_count: sortedWorkspaces.length,
|
|
64907
|
+
top_workspace_id: topWorkspace?.workspace_uuid ?? null,
|
|
64908
|
+
top_workspace_name: topWorkspace?.workspace_name ?? null,
|
|
64909
|
+
top_efficiency: topWorkspace?.efficiency ?? null,
|
|
64910
|
+
top_avg_cycle_time: topWorkspace?.avg_cycle_time ?? null,
|
|
64911
|
+
top_ideal_cycle_time: topWorkspace?.ideal_cycle_time ?? null,
|
|
64912
|
+
top_cycle_ratio: topWorkspace ? getCycleRatio(topWorkspace) : null
|
|
64913
|
+
});
|
|
64914
|
+
}, [
|
|
64915
|
+
loading,
|
|
64916
|
+
error,
|
|
64917
|
+
sortedWorkspaces,
|
|
64918
|
+
activeTab,
|
|
64919
|
+
viewType,
|
|
64920
|
+
outputCategory,
|
|
64921
|
+
selectedLineFilter,
|
|
64922
|
+
selectedShiftFilter,
|
|
64923
|
+
sortAscending
|
|
64924
|
+
]);
|
|
64633
64925
|
const currentDateFormatted = React141.useMemo(() => {
|
|
64634
64926
|
const dateStr = (/* @__PURE__ */ new Date()).toDateString();
|
|
64635
64927
|
return formatDate2(new Date(dateStr));
|
|
@@ -64647,7 +64939,9 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64647
64939
|
error.message
|
|
64648
64940
|
] }) });
|
|
64649
64941
|
}
|
|
64650
|
-
const
|
|
64942
|
+
const metricLabel = viewType === "machine" ? "Utilization" : isAssemblyMode ? "Cycle Time" : "Efficiency";
|
|
64943
|
+
const descendingSortLabel = "Highest to Lowest";
|
|
64944
|
+
const ascendingSortLabel = "Lowest to Highest";
|
|
64651
64945
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `min-h-screen bg-slate-50 flex flex-col ${className}`, style: { willChange: "contents" }, children: [
|
|
64652
64946
|
/* @__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: [
|
|
64653
64947
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "sm:hidden", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center", children: [
|
|
@@ -64697,7 +64991,7 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64697
64991
|
] }),
|
|
64698
64992
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
|
|
64699
64993
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
|
|
64700
|
-
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-xs font-medium text-gray-500 uppercase tracking-wide ml-1", children:
|
|
64994
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-xs font-medium text-gray-500 uppercase tracking-wide ml-1", children: metricLabel }),
|
|
64701
64995
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
64702
64996
|
"select",
|
|
64703
64997
|
{
|
|
@@ -64706,8 +65000,25 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64706
65000
|
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",
|
|
64707
65001
|
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` },
|
|
64708
65002
|
children: [
|
|
64709
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "desc", children:
|
|
64710
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "asc", children:
|
|
65003
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "desc", children: descendingSortLabel }),
|
|
65004
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "asc", children: ascendingSortLabel })
|
|
65005
|
+
]
|
|
65006
|
+
}
|
|
65007
|
+
) })
|
|
65008
|
+
] }),
|
|
65009
|
+
showOutputCategoryDropdown && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1 sm:hidden", children: [
|
|
65010
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-xs font-medium text-gray-500 uppercase tracking-wide ml-1", children: "Output Type" }),
|
|
65011
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
65012
|
+
"select",
|
|
65013
|
+
{
|
|
65014
|
+
"aria-label": "Output leaderboard category",
|
|
65015
|
+
value: outputCategory,
|
|
65016
|
+
onChange: (e) => setOutputCategory(e.target.value),
|
|
65017
|
+
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",
|
|
65018
|
+
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` },
|
|
65019
|
+
children: [
|
|
65020
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "standard", children: "Standard" }),
|
|
65021
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "assembly", children: "Assembly" })
|
|
64711
65022
|
]
|
|
64712
65023
|
}
|
|
64713
65024
|
) })
|
|
@@ -64749,7 +65060,7 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64749
65060
|
currentDate: activeTab === "monthly" ? monthlyRangeText : currentDateFormatted,
|
|
64750
65061
|
currentMobileDate: activeTab === "monthly" ? monthlyRangeText : currentMobileDateFormatted,
|
|
64751
65062
|
shiftId: activeTab === "monthly" ? monthlyShiftId : todayShiftId,
|
|
64752
|
-
getShiftIcon,
|
|
65063
|
+
getShiftIcon: getShiftIcon2,
|
|
64753
65064
|
getShiftName,
|
|
64754
65065
|
showTimer: activeTab === "today"
|
|
64755
65066
|
}
|
|
@@ -64847,6 +65158,20 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64847
65158
|
]
|
|
64848
65159
|
}
|
|
64849
65160
|
) }),
|
|
65161
|
+
showOutputCategoryDropdown && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
65162
|
+
"select",
|
|
65163
|
+
{
|
|
65164
|
+
"aria-label": "Output leaderboard category",
|
|
65165
|
+
value: outputCategory,
|
|
65166
|
+
onChange: (e) => setOutputCategory(e.target.value),
|
|
65167
|
+
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",
|
|
65168
|
+
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` },
|
|
65169
|
+
children: [
|
|
65170
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "standard", children: "Standard" }),
|
|
65171
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "assembly", children: "Assembly" })
|
|
65172
|
+
]
|
|
65173
|
+
}
|
|
65174
|
+
) }),
|
|
64850
65175
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
64851
65176
|
"button",
|
|
64852
65177
|
{
|
|
@@ -64878,7 +65203,8 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64878
65203
|
isClickable: canOpenWorkspace(ws.line_id),
|
|
64879
65204
|
onWorkspaceClick: stableHandleWorkspaceClick,
|
|
64880
65205
|
getMedalIcon: stableGetMedalIcon,
|
|
64881
|
-
|
|
65206
|
+
metricLabel,
|
|
65207
|
+
isAssemblyMode
|
|
64882
65208
|
},
|
|
64883
65209
|
ws.workspace_uuid
|
|
64884
65210
|
);
|
|
@@ -64889,7 +65215,7 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64889
65215
|
/* @__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" }),
|
|
64890
65216
|
/* @__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" }),
|
|
64891
65217
|
/* @__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" }),
|
|
64892
|
-
/* @__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:
|
|
65218
|
+
/* @__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 })
|
|
64893
65219
|
] }) }),
|
|
64894
65220
|
/* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-gray-100", children: sortedWorkspaces.map((ws, index) => {
|
|
64895
65221
|
const isTopThree = index < 3;
|
|
@@ -64902,7 +65228,8 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64902
65228
|
rowClass,
|
|
64903
65229
|
isClickable: canOpenWorkspace(ws.line_id),
|
|
64904
65230
|
onWorkspaceClick: stableHandleWorkspaceClick,
|
|
64905
|
-
getMedalIcon: stableGetMedalIcon
|
|
65231
|
+
getMedalIcon: stableGetMedalIcon,
|
|
65232
|
+
isAssemblyMode
|
|
64906
65233
|
},
|
|
64907
65234
|
ws.workspace_uuid
|
|
64908
65235
|
);
|
|
@@ -64920,7 +65247,10 @@ function LoginView({
|
|
|
64920
65247
|
logoSrc = optifye_logo_default,
|
|
64921
65248
|
logoAlt = "Optifye",
|
|
64922
65249
|
brandName = "Optifye",
|
|
64923
|
-
onRateLimitCheck
|
|
65250
|
+
onRateLimitCheck,
|
|
65251
|
+
showDevTestLogin = false,
|
|
65252
|
+
devTestLoginLabel,
|
|
65253
|
+
onDevTestLogin
|
|
64924
65254
|
}) {
|
|
64925
65255
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
64926
65256
|
LoginPage,
|
|
@@ -64928,7 +65258,10 @@ function LoginView({
|
|
|
64928
65258
|
logoSrc,
|
|
64929
65259
|
logoAlt,
|
|
64930
65260
|
brandName,
|
|
64931
|
-
onRateLimitCheck
|
|
65261
|
+
onRateLimitCheck,
|
|
65262
|
+
showDevTestLogin,
|
|
65263
|
+
devTestLoginLabel,
|
|
65264
|
+
onDevTestLogin
|
|
64932
65265
|
}
|
|
64933
65266
|
);
|
|
64934
65267
|
}
|
|
@@ -68063,8 +68396,84 @@ var TargetsView = ({
|
|
|
68063
68396
|
var TargetsViewWithDisplayNames = withAllWorkspaceDisplayNames(TargetsView);
|
|
68064
68397
|
var TargetsView_default = TargetsViewWithDisplayNames;
|
|
68065
68398
|
var AuthenticatedTargetsView = withAuth(React141__namespace.default.memo(TargetsViewWithDisplayNames));
|
|
68399
|
+
function useTimezone(options = {}) {
|
|
68400
|
+
const dashboardConfig = useDashboardConfig();
|
|
68401
|
+
const workspaceConfig = useWorkspaceConfig();
|
|
68402
|
+
const defaultTimezone = dashboardConfig?.dateTimeConfig?.defaultTimezone || "Asia/Kolkata";
|
|
68403
|
+
const [timezone, setTimezone] = React141.useState(defaultTimezone);
|
|
68404
|
+
const [isLoading, setIsLoading] = React141.useState(true);
|
|
68405
|
+
const [error, setError] = React141.useState(null);
|
|
68406
|
+
const fetchTimezone = React141.useCallback(async () => {
|
|
68407
|
+
setIsLoading(true);
|
|
68408
|
+
setError(null);
|
|
68409
|
+
try {
|
|
68410
|
+
let fetchedTimezone = defaultTimezone;
|
|
68411
|
+
if (options.lineId) {
|
|
68412
|
+
fetchedTimezone = await timezoneService.getTimezoneForLine(options.lineId, defaultTimezone);
|
|
68413
|
+
} else if (options.workspaceId || workspaceConfig && "id" in workspaceConfig) {
|
|
68414
|
+
const wsId = options.workspaceId || (workspaceConfig && "id" in workspaceConfig ? workspaceConfig.id : void 0);
|
|
68415
|
+
if (wsId) {
|
|
68416
|
+
fetchedTimezone = await timezoneService.getTimezoneForWorkspace(wsId, defaultTimezone);
|
|
68417
|
+
}
|
|
68418
|
+
} else if (options.companyId || dashboardConfig && "company" in dashboardConfig) {
|
|
68419
|
+
const compId = options.companyId || (dashboardConfig && "company" in dashboardConfig ? dashboardConfig.company?.id : void 0);
|
|
68420
|
+
if (compId) {
|
|
68421
|
+
fetchedTimezone = await timezoneService.getTimezoneForCompany(compId, defaultTimezone);
|
|
68422
|
+
}
|
|
68423
|
+
}
|
|
68424
|
+
setTimezone(fetchedTimezone);
|
|
68425
|
+
} catch (err) {
|
|
68426
|
+
console.error("Error fetching timezone:", err);
|
|
68427
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch timezone"));
|
|
68428
|
+
setTimezone(defaultTimezone);
|
|
68429
|
+
} finally {
|
|
68430
|
+
setIsLoading(false);
|
|
68431
|
+
}
|
|
68432
|
+
}, [
|
|
68433
|
+
options.lineId,
|
|
68434
|
+
options.workspaceId,
|
|
68435
|
+
options.companyId,
|
|
68436
|
+
workspaceConfig,
|
|
68437
|
+
dashboardConfig,
|
|
68438
|
+
defaultTimezone
|
|
68439
|
+
]);
|
|
68440
|
+
React141.useEffect(() => {
|
|
68441
|
+
fetchTimezone();
|
|
68442
|
+
}, [fetchTimezone]);
|
|
68443
|
+
return {
|
|
68444
|
+
timezone,
|
|
68445
|
+
isLoading,
|
|
68446
|
+
error,
|
|
68447
|
+
refetch: fetchTimezone
|
|
68448
|
+
};
|
|
68449
|
+
}
|
|
68066
68450
|
|
|
68067
68451
|
// src/views/workspace-detail-view.utils.ts
|
|
68452
|
+
var getWorkspaceDetailLayoutMode = ({
|
|
68453
|
+
workspace,
|
|
68454
|
+
showCycleTimeChart
|
|
68455
|
+
}) => {
|
|
68456
|
+
if (workspace?.monitoring_mode === "uptime") {
|
|
68457
|
+
return "uptime";
|
|
68458
|
+
}
|
|
68459
|
+
if (showCycleTimeChart === false) {
|
|
68460
|
+
return "output";
|
|
68461
|
+
}
|
|
68462
|
+
return shouldUseAssemblyCycleTimeLayout(workspace) ? "assembly_cycle" : "output";
|
|
68463
|
+
};
|
|
68464
|
+
var getCycleTimeRenderState = ({
|
|
68465
|
+
workspace,
|
|
68466
|
+
authoritativeMetrics,
|
|
68467
|
+
showCycleTimeChart
|
|
68468
|
+
}) => {
|
|
68469
|
+
if (getWorkspaceDetailLayoutMode({ workspace, showCycleTimeChart }) !== "assembly_cycle") {
|
|
68470
|
+
return "output";
|
|
68471
|
+
}
|
|
68472
|
+
if (!authoritativeMetrics) {
|
|
68473
|
+
return "chart_loading";
|
|
68474
|
+
}
|
|
68475
|
+
return authoritativeMetrics.cycle_time_data_status === "missing_clips" ? "cycle_unavailable" : "cycle_chart";
|
|
68476
|
+
};
|
|
68068
68477
|
var formatDateInTimezone = (date = /* @__PURE__ */ new Date(), timezone, options) => {
|
|
68069
68478
|
const defaultOptions = {
|
|
68070
68479
|
day: "numeric",
|
|
@@ -68448,6 +68857,7 @@ var WorkspaceDetailView = ({
|
|
|
68448
68857
|
date: cachedOverviewMetrics.date,
|
|
68449
68858
|
shift_id: cachedOverviewMetrics.shift_id,
|
|
68450
68859
|
action_name: "",
|
|
68860
|
+
action_family: cachedOverviewMetrics.action_family ?? null,
|
|
68451
68861
|
action_type: cachedOverviewMetrics.action_type ?? null,
|
|
68452
68862
|
monitoring_mode: cachedOverviewMetrics.monitoring_mode ?? "output",
|
|
68453
68863
|
shift_start: shiftDefinition?.startTime || "",
|
|
@@ -68470,23 +68880,48 @@ var WorkspaceDetailView = ({
|
|
|
68470
68880
|
idle_time_hourly: void 0
|
|
68471
68881
|
};
|
|
68472
68882
|
}, [cachedOverviewMetrics, shiftConfig?.shifts]);
|
|
68473
|
-
const
|
|
68474
|
-
const
|
|
68883
|
+
const authoritativeCycleMetrics = isHistoricView ? historicMetrics : liveMetrics;
|
|
68884
|
+
const workspace = authoritativeCycleMetrics || cachedDetailedMetrics || overviewFallback;
|
|
68885
|
+
const { timezone: cycleTimeTimezone } = useTimezone({
|
|
68886
|
+
lineId: effectiveLineId || workspace?.line_id || void 0,
|
|
68887
|
+
workspaceId: workspaceId || void 0
|
|
68888
|
+
});
|
|
68889
|
+
const effectiveCycleTimeTimezone = cycleTimeTimezone || timezone;
|
|
68890
|
+
const detailedWorkspaceMetrics = authoritativeCycleMetrics || cachedDetailedMetrics;
|
|
68475
68891
|
const cycleTimeChartData = React141.useMemo(
|
|
68476
|
-
() => Array.isArray(
|
|
68892
|
+
() => Array.isArray(authoritativeCycleMetrics?.hourly_cycle_times) ? authoritativeCycleMetrics.hourly_cycle_times.map((value) => {
|
|
68477
68893
|
const numericValue = Number(value);
|
|
68478
68894
|
return Number.isFinite(numericValue) ? numericValue : 0;
|
|
68479
68895
|
}) : [],
|
|
68480
|
-
[
|
|
68896
|
+
[authoritativeCycleMetrics?.hourly_cycle_times]
|
|
68897
|
+
);
|
|
68898
|
+
const maskedCycleTimeChartData = React141.useMemo(
|
|
68899
|
+
() => maskFutureHourlySeries({
|
|
68900
|
+
data: cycleTimeChartData,
|
|
68901
|
+
shiftStart: authoritativeCycleMetrics?.shift_start,
|
|
68902
|
+
shiftEnd: authoritativeCycleMetrics?.shift_end,
|
|
68903
|
+
shiftDate: authoritativeCycleMetrics?.date || date || calculatedOperationalDate || null,
|
|
68904
|
+
timezone: effectiveCycleTimeTimezone
|
|
68905
|
+
}),
|
|
68906
|
+
[
|
|
68907
|
+
cycleTimeChartData,
|
|
68908
|
+
authoritativeCycleMetrics?.shift_start,
|
|
68909
|
+
authoritativeCycleMetrics?.shift_end,
|
|
68910
|
+
authoritativeCycleMetrics?.date,
|
|
68911
|
+
date,
|
|
68912
|
+
calculatedOperationalDate,
|
|
68913
|
+
effectiveCycleTimeTimezone
|
|
68914
|
+
]
|
|
68481
68915
|
);
|
|
68482
68916
|
const cycleTimeDatasetKey = React141.useMemo(
|
|
68483
68917
|
() => [
|
|
68484
|
-
|
|
68485
|
-
date ||
|
|
68486
|
-
parsedShiftId ??
|
|
68487
|
-
"hourly"
|
|
68918
|
+
authoritativeCycleMetrics?.workspace_id || workspaceId || "workspace",
|
|
68919
|
+
date || authoritativeCycleMetrics?.date || "live",
|
|
68920
|
+
parsedShiftId ?? authoritativeCycleMetrics?.shift_id ?? "current",
|
|
68921
|
+
"hourly",
|
|
68922
|
+
"backend"
|
|
68488
68923
|
].join(":"),
|
|
68489
|
-
[
|
|
68924
|
+
[authoritativeCycleMetrics?.workspace_id, workspaceId, date, authoritativeCycleMetrics?.date, parsedShiftId, authoritativeCycleMetrics?.shift_id]
|
|
68490
68925
|
);
|
|
68491
68926
|
const hasWorkspaceSnapshot = Boolean(workspace);
|
|
68492
68927
|
const loading = ((isHistoricView ? historicLoading : liveLoading) || isShiftConfigLoading) && !hasWorkspaceSnapshot;
|
|
@@ -68729,22 +69164,52 @@ var WorkspaceDetailView = ({
|
|
|
68729
69164
|
return filterDataByDateKeyRange(monthlyData, range);
|
|
68730
69165
|
}, [monthlyData, range]);
|
|
68731
69166
|
const formattedWorkspaceName = displayName || formatWorkspaceName3(workspace?.workspace_name || "", effectiveLineId);
|
|
68732
|
-
const
|
|
68733
|
-
|
|
68734
|
-
|
|
68735
|
-
|
|
68736
|
-
|
|
69167
|
+
const workspaceCycleTimeEligibility = workspace ? {
|
|
69168
|
+
line_assembly_enabled: workspace.line_assembly_enabled,
|
|
69169
|
+
action_family: workspace.action_family,
|
|
69170
|
+
action_type: workspace.action_type
|
|
69171
|
+
} : null;
|
|
69172
|
+
const isAssemblyWorkspace = shouldUseAssemblyCycleTimeLayout(workspaceCycleTimeEligibility);
|
|
69173
|
+
const layoutMode = getWorkspaceDetailLayoutMode({
|
|
69174
|
+
workspace: workspace ? {
|
|
69175
|
+
monitoring_mode: workspace.monitoring_mode,
|
|
69176
|
+
line_assembly_enabled: workspace.line_assembly_enabled,
|
|
69177
|
+
action_family: workspace.action_family,
|
|
69178
|
+
action_type: workspace.action_type
|
|
69179
|
+
} : null,
|
|
69180
|
+
showCycleTimeChart
|
|
69181
|
+
});
|
|
69182
|
+
const isAssemblyCycleLayout = layoutMode === "assembly_cycle";
|
|
69183
|
+
const isOutputLayout = layoutMode === "output";
|
|
69184
|
+
const cycleTimePresentation = getCycleTimeRenderState({
|
|
69185
|
+
workspace: workspace ? {
|
|
69186
|
+
monitoring_mode: workspace.monitoring_mode,
|
|
69187
|
+
line_assembly_enabled: workspace.line_assembly_enabled,
|
|
69188
|
+
action_family: workspace.action_family,
|
|
69189
|
+
action_type: workspace.action_type
|
|
69190
|
+
} : null,
|
|
69191
|
+
authoritativeMetrics: authoritativeCycleMetrics ? {
|
|
69192
|
+
cycle_time_data_status: authoritativeCycleMetrics.cycle_time_data_status
|
|
69193
|
+
} : null,
|
|
69194
|
+
showCycleTimeChart
|
|
69195
|
+
});
|
|
69196
|
+
const shouldShowCycleTimeChart = cycleTimePresentation === "cycle_chart";
|
|
69197
|
+
const shouldShowCycleTimeUnavailableState = cycleTimePresentation === "cycle_unavailable";
|
|
69198
|
+
const shouldShowCycleTimeLoadingState = cycleTimePresentation === "chart_loading";
|
|
69199
|
+
const shouldShowAssemblyOverviewLoadingState = isAssemblyCycleLayout && shouldShowCycleTimeLoadingState && hasWorkspaceSnapshot;
|
|
69200
|
+
const showIdleBreakdownChart = !isAssemblyCycleLayout && idleTimeVlmEnabled;
|
|
69201
|
+
const canToggleChartIdleTime = !isUptimeMode && !shouldShowCycleTimeLoadingState && !shouldShowCycleTimeUnavailableState;
|
|
68737
69202
|
const idleClipDate = date || workspace?.date || calculatedOperationalDate || getOperationalDate(timezone);
|
|
68738
69203
|
const idleClipShiftId = parsedShiftId ?? workspace?.shift_id;
|
|
68739
|
-
const
|
|
69204
|
+
const rawHourlyIdleMinutes = React141.useMemo(() => {
|
|
68740
69205
|
if (!shouldShowCycleTimeChart || !workspace?.idle_time_hourly || !workspace?.shift_start) return [];
|
|
68741
|
-
const
|
|
69206
|
+
const parseTimeToMinutes4 = (time2) => {
|
|
68742
69207
|
const [h, m] = time2.split(":").map(Number);
|
|
68743
69208
|
if (!Number.isFinite(h) || !Number.isFinite(m)) return 0;
|
|
68744
69209
|
return h * 60 + m;
|
|
68745
69210
|
};
|
|
68746
|
-
const startTotal =
|
|
68747
|
-
const endTotalRaw = workspace.shift_end ?
|
|
69211
|
+
const startTotal = parseTimeToMinutes4(workspace.shift_start);
|
|
69212
|
+
const endTotalRaw = workspace.shift_end ? parseTimeToMinutes4(workspace.shift_end) : startTotal + 11 * 60;
|
|
68748
69213
|
const endTotal = endTotalRaw <= startTotal ? endTotalRaw + 24 * 60 : endTotalRaw;
|
|
68749
69214
|
const shiftDuration = Math.max(60, endTotal - startTotal);
|
|
68750
69215
|
const totalHourSlots = Math.max(1, Math.ceil(shiftDuration / 60));
|
|
@@ -68770,6 +69235,42 @@ var WorkspaceDetailView = ({
|
|
|
68770
69235
|
}
|
|
68771
69236
|
return result;
|
|
68772
69237
|
}, [shouldShowCycleTimeChart, workspace?.idle_time_hourly, workspace?.shift_start, workspace?.shift_end]);
|
|
69238
|
+
const hourlyIdleMinutes = React141.useMemo(
|
|
69239
|
+
() => maskFutureHourlySeries({
|
|
69240
|
+
data: rawHourlyIdleMinutes,
|
|
69241
|
+
shiftStart: workspace?.shift_start,
|
|
69242
|
+
shiftEnd: workspace?.shift_end,
|
|
69243
|
+
shiftDate: idleClipDate,
|
|
69244
|
+
timezone: effectiveCycleTimeTimezone
|
|
69245
|
+
}),
|
|
69246
|
+
[
|
|
69247
|
+
rawHourlyIdleMinutes,
|
|
69248
|
+
workspace?.shift_start,
|
|
69249
|
+
workspace?.shift_end,
|
|
69250
|
+
idleClipDate,
|
|
69251
|
+
effectiveCycleTimeTimezone
|
|
69252
|
+
]
|
|
69253
|
+
);
|
|
69254
|
+
const cycleTimeUnavailableView = React141.useMemo(() => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full h-full rounded-lg border border-amber-200 bg-amber-50/70 px-6 py-5 text-center flex flex-col items-center justify-center", children: [
|
|
69255
|
+
/* @__PURE__ */ jsxRuntime.jsx("h4", { className: "text-base font-semibold text-amber-900", children: "Cycle data unavailable" }),
|
|
69256
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 max-w-md text-sm text-amber-800", children: "This workstation has cycle-time metrics for the selected shift, but no matching `cycle_completion` clips were found for the chart." }),
|
|
69257
|
+
typeof workspace?.cycle_completion_clip_count === "number" && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-3 text-xs font-medium uppercase tracking-[0.08em] text-amber-700", children: [
|
|
69258
|
+
"matched cycle clips: ",
|
|
69259
|
+
workspace.cycle_completion_clip_count
|
|
69260
|
+
] })
|
|
69261
|
+
] }), [workspace?.cycle_completion_clip_count]);
|
|
69262
|
+
const assemblyOverviewLoadingView = React141.useMemo(() => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4 pb-4", "data-testid": "assembly-overview-loading-state", children: [
|
|
69263
|
+
/* @__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: [
|
|
69264
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3 bg-gray-200 rounded-full w-3/4 mx-auto" }),
|
|
69265
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3 bg-gray-100 rounded-full w-full" }),
|
|
69266
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3 bg-gray-100 rounded-full w-5/6 mx-auto" })
|
|
69267
|
+
] }) }) }),
|
|
69268
|
+
/* @__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: [
|
|
69269
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 w-24 bg-gray-200 rounded" }),
|
|
69270
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-10 w-20 bg-gray-100 rounded" }),
|
|
69271
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3 w-28 bg-gray-100 rounded" })
|
|
69272
|
+
] }) }, index)) })
|
|
69273
|
+
] }), []);
|
|
68773
69274
|
const shiftDurationMinutes = React141.useMemo(
|
|
68774
69275
|
() => getShiftDurationMinutes(workspace?.shift_start, workspace?.shift_end),
|
|
68775
69276
|
[workspace?.shift_start, workspace?.shift_end]
|
|
@@ -68824,7 +69325,7 @@ var WorkspaceDetailView = ({
|
|
|
68824
69325
|
}, [isUptimeMode, uptimeSeries, shiftDurationMinutes, elapsedShiftMinutes, workspace?.idle_time]);
|
|
68825
69326
|
const overviewTabLabel = isUptimeMode ? "Utilization" : "Efficiency";
|
|
68826
69327
|
const idleClipFetchEnabled = Boolean(
|
|
68827
|
-
workspaceId && idleClipDate && idleClipShiftId !== void 0 && activeTab === "overview" && idleTimeVlmEnabled &&
|
|
69328
|
+
workspaceId && idleClipDate && idleClipShiftId !== void 0 && activeTab === "overview" && idleTimeVlmEnabled && isOutputLayout
|
|
68828
69329
|
);
|
|
68829
69330
|
const {
|
|
68830
69331
|
idleClips: idleTimeClips,
|
|
@@ -68895,7 +69396,7 @@ var WorkspaceDetailView = ({
|
|
|
68895
69396
|
}
|
|
68896
69397
|
}
|
|
68897
69398
|
};
|
|
68898
|
-
const
|
|
69399
|
+
const getShiftIcon2 = (shiftType) => {
|
|
68899
69400
|
const shiftTypeLower = shiftType?.toLowerCase() || "";
|
|
68900
69401
|
if (shiftTypeLower.includes("day") || shiftTypeLower.includes("morning")) {
|
|
68901
69402
|
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" }) });
|
|
@@ -69044,7 +69545,7 @@ var WorkspaceDetailView = ({
|
|
|
69044
69545
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children: (() => {
|
|
69045
69546
|
const shift2 = shiftConfig?.shifts?.find((s) => s.shiftId === selectedShift);
|
|
69046
69547
|
const shiftName = shift2?.shiftName || (selectedShift === 0 ? "Day Shift" : "Night Shift");
|
|
69047
|
-
return
|
|
69548
|
+
return getShiftIcon2(shiftName);
|
|
69048
69549
|
})() }),
|
|
69049
69550
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: (() => {
|
|
69050
69551
|
const shift2 = shiftConfig?.shifts?.find((s) => s.shiftId === selectedShift);
|
|
@@ -69072,7 +69573,7 @@ var WorkspaceDetailView = ({
|
|
|
69072
69573
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "opacity-70", children: (() => {
|
|
69073
69574
|
const shift2 = shiftConfig?.shifts?.find((s) => s.shiftId === selectedShift);
|
|
69074
69575
|
const shiftName = shift2?.shiftName || (selectedShift === 0 ? "Day Shift" : "Night Shift");
|
|
69075
|
-
return
|
|
69576
|
+
return getShiftIcon2(shiftName);
|
|
69076
69577
|
})() }),
|
|
69077
69578
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm md:text-base font-semibold uppercase tracking-wider", children: (() => {
|
|
69078
69579
|
const shift2 = shiftConfig?.shifts?.find((s) => s.shiftId === selectedShift);
|
|
@@ -69085,7 +69586,7 @@ var WorkspaceDetailView = ({
|
|
|
69085
69586
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sm:hidden mt-3 flex items-center justify-center gap-2", children: [
|
|
69086
69587
|
/* @__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)) }) }),
|
|
69087
69588
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
|
|
69088
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children:
|
|
69589
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon2(workspace.shift_type) }),
|
|
69089
69590
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: workspace.shift_type })
|
|
69090
69591
|
] }),
|
|
69091
69592
|
!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
|
|
@@ -69116,7 +69617,7 @@ var WorkspaceDetailView = ({
|
|
|
69116
69617
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-200" })
|
|
69117
69618
|
] }),
|
|
69118
69619
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
|
|
69119
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "opacity-70", children:
|
|
69620
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "opacity-70", children: getShiftIcon2(workspace.shift_type) }),
|
|
69120
69621
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm md:text-base font-semibold uppercase tracking-wider", children: [
|
|
69121
69622
|
workspace.shift_type.replace(/ Shift$/i, ""),
|
|
69122
69623
|
" Shift"
|
|
@@ -69235,9 +69736,9 @@ var WorkspaceDetailView = ({
|
|
|
69235
69736
|
] })
|
|
69236
69737
|
] }),
|
|
69237
69738
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-grow p-1.5 sm:p-2 lg:p-4", children: [
|
|
69238
|
-
activeTab === "overview" && /* @__PURE__ */ jsxRuntime.
|
|
69739
|
+
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: [
|
|
69239
69740
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "block lg:hidden space-y-6 pb-6", children: [
|
|
69240
|
-
|
|
69741
|
+
isOutputLayout && !isUptimeMode && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
69241
69742
|
motion.div,
|
|
69242
69743
|
{
|
|
69243
69744
|
className: "bg-white rounded-lg shadow-sm p-6 h-[300px]",
|
|
@@ -69265,8 +69766,8 @@ var WorkspaceDetailView = ({
|
|
|
69265
69766
|
animate: "animate",
|
|
69266
69767
|
children: [
|
|
69267
69768
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between items-center mb-4", children: [
|
|
69268
|
-
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-bold text-gray-700", children: isUptimeMode ? "Machine Utilization" :
|
|
69269
|
-
|
|
69769
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-bold text-gray-700", children: isUptimeMode ? "Machine Utilization" : isAssemblyCycleLayout ? "Cycle time trend" : "Hourly Output" }),
|
|
69770
|
+
canToggleChartIdleTime && /* @__PURE__ */ jsxRuntime.jsx(
|
|
69270
69771
|
"button",
|
|
69271
69772
|
{
|
|
69272
69773
|
onClick: () => setShowChartIdleTime(!showChartIdleTime),
|
|
@@ -69295,19 +69796,19 @@ var WorkspaceDetailView = ({
|
|
|
69295
69796
|
timezone,
|
|
69296
69797
|
elapsedMinutes: elapsedShiftMinutes
|
|
69297
69798
|
}
|
|
69298
|
-
) : shouldShowCycleTimeChart ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
69799
|
+
) : isAssemblyCycleLayout ? shouldShowCycleTimeUnavailableState ? cycleTimeUnavailableView : shouldShowCycleTimeChart ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
69299
69800
|
CycleTimeOverTimeChart,
|
|
69300
69801
|
{
|
|
69301
|
-
data:
|
|
69302
|
-
idealCycleTime:
|
|
69303
|
-
shiftStart:
|
|
69304
|
-
shiftEnd:
|
|
69802
|
+
data: maskedCycleTimeChartData,
|
|
69803
|
+
idealCycleTime: authoritativeCycleMetrics?.ideal_cycle_time || 0,
|
|
69804
|
+
shiftStart: authoritativeCycleMetrics?.shift_start || "",
|
|
69805
|
+
shiftEnd: authoritativeCycleMetrics?.shift_end || "",
|
|
69305
69806
|
xAxisMode: "hourly",
|
|
69306
69807
|
datasetKey: cycleTimeDatasetKey,
|
|
69307
69808
|
showIdleTime: showChartIdleTime,
|
|
69308
69809
|
idleTimeData: hourlyIdleMinutes
|
|
69309
69810
|
}
|
|
69310
|
-
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
69811
|
+
) : null : /* @__PURE__ */ jsxRuntime.jsx(
|
|
69311
69812
|
HourlyOutputChart2,
|
|
69312
69813
|
{
|
|
69313
69814
|
data: workspace.hourly_action_counts || [],
|
|
@@ -69327,7 +69828,7 @@ var WorkspaceDetailView = ({
|
|
|
69327
69828
|
]
|
|
69328
69829
|
}
|
|
69329
69830
|
),
|
|
69330
|
-
|
|
69831
|
+
showIdleBreakdownChart && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
69331
69832
|
motion.div,
|
|
69332
69833
|
{
|
|
69333
69834
|
className: "bg-white rounded-lg shadow-sm p-4 h-[300px]",
|
|
@@ -69347,7 +69848,7 @@ var WorkspaceDetailView = ({
|
|
|
69347
69848
|
]
|
|
69348
69849
|
}
|
|
69349
69850
|
),
|
|
69350
|
-
isUptimeMode ? /* @__PURE__ */ jsxRuntime.jsx(UptimeMetricCards, { workspace, uptimePieData }) :
|
|
69851
|
+
isUptimeMode ? /* @__PURE__ */ jsxRuntime.jsx(UptimeMetricCards, { workspace, uptimePieData }) : isAssemblyCycleLayout ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
69351
69852
|
WorkspaceCycleTimeMetricCards,
|
|
69352
69853
|
{
|
|
69353
69854
|
workspace,
|
|
@@ -69367,7 +69868,7 @@ var WorkspaceDetailView = ({
|
|
|
69367
69868
|
desktopTopSectionClass
|
|
69368
69869
|
),
|
|
69369
69870
|
children: [
|
|
69370
|
-
|
|
69871
|
+
isOutputLayout && !isUptimeMode && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
69371
69872
|
motion.div,
|
|
69372
69873
|
{
|
|
69373
69874
|
className: "bg-white rounded-lg shadow-sm p-4 lg:col-span-2 flex flex-col min-h-0",
|
|
@@ -69391,15 +69892,15 @@ var WorkspaceDetailView = ({
|
|
|
69391
69892
|
{
|
|
69392
69893
|
className: clsx(
|
|
69393
69894
|
"bg-white rounded-lg shadow-sm p-4 flex flex-col min-h-0",
|
|
69394
|
-
isUptimeMode && showIdleBreakdownChart ? "lg:col-span-2" :
|
|
69895
|
+
isUptimeMode && showIdleBreakdownChart ? "lg:col-span-2" : isAssemblyCycleLayout || isUptimeMode ? "lg:col-span-10" : idleTimeVlmEnabled ? "lg:col-span-6" : "lg:col-span-8"
|
|
69395
69896
|
),
|
|
69396
69897
|
variants: chartCardVariants,
|
|
69397
69898
|
initial: "initial",
|
|
69398
69899
|
animate: "animate",
|
|
69399
69900
|
children: [
|
|
69400
69901
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-3 mb-4 flex-none", children: [
|
|
69401
|
-
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-bold text-gray-700", children: isUptimeMode ? "Machine Utilization" :
|
|
69402
|
-
|
|
69902
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-bold text-gray-700", children: isUptimeMode ? "Machine Utilization" : isAssemblyCycleLayout ? "Cycle time trend" : "Hourly Output" }),
|
|
69903
|
+
canToggleChartIdleTime && /* @__PURE__ */ jsxRuntime.jsx(
|
|
69403
69904
|
"button",
|
|
69404
69905
|
{
|
|
69405
69906
|
onClick: () => setShowChartIdleTime(!showChartIdleTime),
|
|
@@ -69424,19 +69925,19 @@ var WorkspaceDetailView = ({
|
|
|
69424
69925
|
timezone,
|
|
69425
69926
|
elapsedMinutes: elapsedShiftMinutes
|
|
69426
69927
|
}
|
|
69427
|
-
) : shouldShowCycleTimeChart ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
69928
|
+
) : isAssemblyCycleLayout ? shouldShowCycleTimeUnavailableState ? cycleTimeUnavailableView : shouldShowCycleTimeChart ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
69428
69929
|
CycleTimeOverTimeChart,
|
|
69429
69930
|
{
|
|
69430
|
-
data:
|
|
69431
|
-
idealCycleTime:
|
|
69432
|
-
shiftStart:
|
|
69433
|
-
shiftEnd:
|
|
69931
|
+
data: maskedCycleTimeChartData,
|
|
69932
|
+
idealCycleTime: authoritativeCycleMetrics?.ideal_cycle_time || 0,
|
|
69933
|
+
shiftStart: authoritativeCycleMetrics?.shift_start || "",
|
|
69934
|
+
shiftEnd: authoritativeCycleMetrics?.shift_end || "",
|
|
69434
69935
|
xAxisMode: "hourly",
|
|
69435
69936
|
datasetKey: cycleTimeDatasetKey,
|
|
69436
69937
|
showIdleTime: showChartIdleTime,
|
|
69437
69938
|
idleTimeData: hourlyIdleMinutes
|
|
69438
69939
|
}
|
|
69439
|
-
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
69940
|
+
) : null : /* @__PURE__ */ jsxRuntime.jsx(
|
|
69440
69941
|
HourlyOutputChart2,
|
|
69441
69942
|
{
|
|
69442
69943
|
data: workspace.hourly_action_counts || [],
|
|
@@ -69454,7 +69955,7 @@ var WorkspaceDetailView = ({
|
|
|
69454
69955
|
]
|
|
69455
69956
|
}
|
|
69456
69957
|
),
|
|
69457
|
-
|
|
69958
|
+
showIdleBreakdownChart && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
69458
69959
|
motion.div,
|
|
69459
69960
|
{
|
|
69460
69961
|
className: clsx(
|
|
@@ -69480,7 +69981,7 @@ var WorkspaceDetailView = ({
|
|
|
69480
69981
|
]
|
|
69481
69982
|
}
|
|
69482
69983
|
),
|
|
69483
|
-
isUptimeMode ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: clsx("flex min-h-0", desktopBottomSectionClass), children: /* @__PURE__ */ jsxRuntime.jsx(UptimeMetricCards, { workspace, uptimePieData, className: "flex-1" }) }) :
|
|
69984
|
+
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(
|
|
69484
69985
|
WorkspaceCycleTimeMetricCards,
|
|
69485
69986
|
{
|
|
69486
69987
|
workspace,
|
|
@@ -69491,7 +69992,7 @@ var WorkspaceDetailView = ({
|
|
|
69491
69992
|
}
|
|
69492
69993
|
) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: clsx("flex min-h-0", desktopBottomSectionClass), children: /* @__PURE__ */ jsxRuntime.jsx(WorkspaceMetricCards, { workspace, legend: efficiencyLegend, className: "flex-1" }) })
|
|
69493
69994
|
] })
|
|
69494
|
-
] }),
|
|
69995
|
+
] }) }),
|
|
69495
69996
|
activeTab === "monthly_history" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-[calc(100vh-10rem)] overflow-y-auto px-2 sm:px-4 lg:px-0", children: [
|
|
69496
69997
|
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: [
|
|
69497
69998
|
/* @__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" }) }),
|
|
@@ -72123,7 +72624,7 @@ var normalizeLabel = (value) => {
|
|
|
72123
72624
|
const trimmed = value.trim();
|
|
72124
72625
|
return trimmed.length > 0 ? trimmed : void 0;
|
|
72125
72626
|
};
|
|
72126
|
-
var
|
|
72627
|
+
var toFiniteNumber2 = (value) => {
|
|
72127
72628
|
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
72128
72629
|
if (typeof value === "string" && value.trim().length > 0) {
|
|
72129
72630
|
const parsed = Number(value);
|
|
@@ -72157,7 +72658,7 @@ var formatImprovementPieceGain = (pcsGain) => {
|
|
|
72157
72658
|
var getPositiveImprovementGain = ({
|
|
72158
72659
|
estimated_gain_pieces
|
|
72159
72660
|
}) => {
|
|
72160
|
-
const issueGain =
|
|
72661
|
+
const issueGain = toFiniteNumber2(estimated_gain_pieces);
|
|
72161
72662
|
return {
|
|
72162
72663
|
pcsGain: issueGain !== null && issueGain > 0 ? issueGain : null
|
|
72163
72664
|
};
|
|
@@ -72165,7 +72666,7 @@ var getPositiveImprovementGain = ({
|
|
|
72165
72666
|
var getImprovementPcsGainSortValue = (input) => {
|
|
72166
72667
|
const { pcsGain } = getPositiveImprovementGain(input);
|
|
72167
72668
|
if (pcsGain !== null) return pcsGain;
|
|
72168
|
-
const raw =
|
|
72669
|
+
const raw = toFiniteNumber2(input.estimated_gain_pieces);
|
|
72169
72670
|
return raw ?? null;
|
|
72170
72671
|
};
|
|
72171
72672
|
var getImprovementDisplayMetadata = ({
|
|
@@ -72185,7 +72686,7 @@ var getImprovementDisplayMetadata = ({
|
|
|
72185
72686
|
metadataLabel: [workstationLabel, lineLabel, supervisorLabel].join(" \xB7 ")
|
|
72186
72687
|
};
|
|
72187
72688
|
};
|
|
72188
|
-
var
|
|
72689
|
+
var toFiniteNumber3 = (value) => {
|
|
72189
72690
|
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
72190
72691
|
if (typeof value === "string" && value.trim().length > 0) {
|
|
72191
72692
|
const parsed = Number(value);
|
|
@@ -72213,15 +72714,15 @@ var compareImprovementRecommendationPriority = (left, right) => {
|
|
|
72213
72714
|
if (leftIndustrial !== rightIndustrial) {
|
|
72214
72715
|
return rightIndustrial - leftIndustrial;
|
|
72215
72716
|
}
|
|
72216
|
-
const leftGain =
|
|
72217
|
-
const rightGain =
|
|
72717
|
+
const leftGain = toFiniteNumber3(left.estimated_gain_pieces);
|
|
72718
|
+
const rightGain = toFiniteNumber3(right.estimated_gain_pieces);
|
|
72218
72719
|
if (leftGain !== rightGain) {
|
|
72219
72720
|
if (leftGain === null) return 1;
|
|
72220
72721
|
if (rightGain === null) return -1;
|
|
72221
72722
|
return rightGain - leftGain;
|
|
72222
72723
|
}
|
|
72223
|
-
const leftRatio =
|
|
72224
|
-
const rightRatio =
|
|
72724
|
+
const leftRatio = toFiniteNumber3(left.gain_to_target_ratio);
|
|
72725
|
+
const rightRatio = toFiniteNumber3(right.gain_to_target_ratio);
|
|
72225
72726
|
if (leftRatio !== rightRatio) {
|
|
72226
72727
|
if (leftRatio === null) return 1;
|
|
72227
72728
|
if (rightRatio === null) return -1;
|
|
@@ -75526,6 +76027,7 @@ var EMPTY_OVERVIEW_POOREST_LINES = {
|
|
|
75526
76027
|
};
|
|
75527
76028
|
var EMPTY_OVERVIEW_TREND = {
|
|
75528
76029
|
shift_mode: "all",
|
|
76030
|
+
granularity: "day",
|
|
75529
76031
|
points: []
|
|
75530
76032
|
};
|
|
75531
76033
|
var EMPTY_IDLE_BREAKDOWN = [];
|
|
@@ -75598,8 +76100,11 @@ var normalizePoorestLines = (value) => ({
|
|
|
75598
76100
|
});
|
|
75599
76101
|
var normalizeTrend = (value) => ({
|
|
75600
76102
|
shift_mode: value?.shift_mode || "all",
|
|
76103
|
+
granularity: value?.granularity === "hour" ? "hour" : "day",
|
|
75601
76104
|
points: (value?.points || []).map((point) => ({
|
|
75602
76105
|
date: point?.date,
|
|
76106
|
+
label: point?.label,
|
|
76107
|
+
hour_index: normalizeNumber(point?.hour_index),
|
|
75603
76108
|
avg_efficiency: normalizeNumber(point?.avg_efficiency)
|
|
75604
76109
|
}))
|
|
75605
76110
|
});
|
|
@@ -75941,17 +76446,25 @@ var formatSignedIdleDuration = (seconds) => {
|
|
|
75941
76446
|
const sign = seconds > 0 ? "+" : "-";
|
|
75942
76447
|
return `${sign}${formatIdleDuration(Math.abs(seconds))}`;
|
|
75943
76448
|
};
|
|
75944
|
-
var formatComparisonWindow = (
|
|
76449
|
+
var formatComparisonWindow = ({
|
|
76450
|
+
currentDayCount,
|
|
76451
|
+
previousDayCount,
|
|
76452
|
+
comparisonStrategy,
|
|
76453
|
+
shiftMode
|
|
76454
|
+
}) => {
|
|
75945
76455
|
if (comparisonStrategy === "previous_full_week") return "last week";
|
|
75946
|
-
if (
|
|
75947
|
-
|
|
76456
|
+
if (comparisonStrategy === "matched_range" && shiftMode !== "all" && currentDayCount === 1 && previousDayCount === 1) {
|
|
76457
|
+
return "previous day";
|
|
76458
|
+
}
|
|
76459
|
+
if (!previousDayCount || !Number.isFinite(previousDayCount)) return "previous range";
|
|
76460
|
+
return `previous ${previousDayCount} ${previousDayCount === 1 ? "day" : "days"}`;
|
|
75948
76461
|
};
|
|
75949
76462
|
var buildDeltaBadge = (delta, options) => {
|
|
75950
76463
|
if (delta === null || delta === void 0 || !Number.isFinite(delta)) {
|
|
75951
76464
|
return {
|
|
75952
76465
|
icon: null,
|
|
75953
|
-
className: "bg-slate-100 text-slate-
|
|
75954
|
-
text:
|
|
76466
|
+
className: "bg-slate-100 text-slate-400",
|
|
76467
|
+
text: "\u2014"
|
|
75955
76468
|
};
|
|
75956
76469
|
}
|
|
75957
76470
|
const direction = delta >= 0 ? "up" : "down";
|
|
@@ -75962,6 +76475,25 @@ var buildDeltaBadge = (delta, options) => {
|
|
|
75962
76475
|
text: `${options.formatter(delta)} vs ${options.comparisonLabel}`
|
|
75963
76476
|
};
|
|
75964
76477
|
};
|
|
76478
|
+
var normalizeShiftLabel = (shiftName, shiftMode) => {
|
|
76479
|
+
const trimmedName = shiftName?.trim();
|
|
76480
|
+
if (trimmedName) {
|
|
76481
|
+
return /shift/i.test(trimmedName) ? trimmedName : `${trimmedName} Shift`;
|
|
76482
|
+
}
|
|
76483
|
+
if (shiftMode === "night") return "Night Shift";
|
|
76484
|
+
return "Day Shift";
|
|
76485
|
+
};
|
|
76486
|
+
var getShiftIcon = (shiftName, shiftMode) => {
|
|
76487
|
+
const normalizedName = (shiftName || "").toLowerCase();
|
|
76488
|
+
const normalizedMode = shiftMode || "day";
|
|
76489
|
+
if (normalizedName.includes("day") || normalizedName.includes("morning") || normalizedMode === "day") {
|
|
76490
|
+
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" }) });
|
|
76491
|
+
}
|
|
76492
|
+
if (normalizedName.includes("night") || normalizedName.includes("evening") || normalizedMode === "night") {
|
|
76493
|
+
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" }) });
|
|
76494
|
+
}
|
|
76495
|
+
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" }) });
|
|
76496
|
+
};
|
|
75965
76497
|
var buildLineDeltaTone = (delta, comparisonLabel) => {
|
|
75966
76498
|
if (delta === null || delta === void 0 || !Number.isFinite(delta)) {
|
|
75967
76499
|
return {
|
|
@@ -76017,6 +76549,8 @@ var OperationsOverviewHeader = React141__namespace.default.memo(({
|
|
|
76017
76549
|
dateRange,
|
|
76018
76550
|
displayDateRange,
|
|
76019
76551
|
trendMode,
|
|
76552
|
+
isLiveScope,
|
|
76553
|
+
liveShiftName,
|
|
76020
76554
|
lineOptions,
|
|
76021
76555
|
supervisorOptions,
|
|
76022
76556
|
selectedSupervisorId,
|
|
@@ -76030,6 +76564,14 @@ var OperationsOverviewHeader = React141__namespace.default.memo(({
|
|
|
76030
76564
|
}) => {
|
|
76031
76565
|
bumpRenderCounter();
|
|
76032
76566
|
const subtitleRange = displayDateRange || dateRange;
|
|
76567
|
+
const liveShiftLabel = React141__namespace.default.useMemo(
|
|
76568
|
+
() => normalizeShiftLabel(liveShiftName, trendMode),
|
|
76569
|
+
[liveShiftName, trendMode]
|
|
76570
|
+
);
|
|
76571
|
+
const liveShiftIcon = React141__namespace.default.useMemo(
|
|
76572
|
+
() => getShiftIcon(liveShiftName, trendMode),
|
|
76573
|
+
[liveShiftName, trendMode]
|
|
76574
|
+
);
|
|
76033
76575
|
const [isFilterOpen, setIsFilterOpen] = React141__namespace.default.useState(false);
|
|
76034
76576
|
const [isLinesDropdownOpen, setIsLinesDropdownOpen] = React141__namespace.default.useState(false);
|
|
76035
76577
|
const filterRef = React141__namespace.default.useRef(null);
|
|
@@ -76146,9 +76688,25 @@ var OperationsOverviewHeader = React141__namespace.default.memo(({
|
|
|
76146
76688
|
className: "flex-shrink-0 -ml-1"
|
|
76147
76689
|
}
|
|
76148
76690
|
) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-8 flex-shrink-0" }),
|
|
76149
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex flex-col items-center justify-center", children: [
|
|
76150
|
-
/* @__PURE__ */ jsxRuntime.
|
|
76151
|
-
|
|
76691
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex flex-col items-center justify-center min-w-0", children: [
|
|
76692
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center gap-1.5 min-w-0 max-w-[240px]", children: [
|
|
76693
|
+
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-lg font-semibold text-gray-900 leading-tight text-center truncate", children: "Operations Overview" }),
|
|
76694
|
+
isLiveScope ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
76695
|
+
"div",
|
|
76696
|
+
{
|
|
76697
|
+
"data-testid": "operations-overview-live-indicator",
|
|
76698
|
+
className: "h-2 w-2 rounded-full bg-emerald-500 animate-pulse ring-2 ring-emerald-500/20 flex-shrink-0"
|
|
76699
|
+
}
|
|
76700
|
+
) : null
|
|
76701
|
+
] }),
|
|
76702
|
+
/* @__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: [
|
|
76703
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-center", children: mobileSubtitle }),
|
|
76704
|
+
isLiveScope ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-slate-300", children: "|" }) : null,
|
|
76705
|
+
isLiveScope ? /* @__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: [
|
|
76706
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-75 shrink-0", children: liveShiftIcon }),
|
|
76707
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: liveShiftLabel })
|
|
76708
|
+
] }) }) : null
|
|
76709
|
+
] })
|
|
76152
76710
|
] }),
|
|
76153
76711
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-shrink-0 flex items-center gap-1.5", children: [
|
|
76154
76712
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -76167,22 +76725,40 @@ var OperationsOverviewHeader = React141__namespace.default.memo(({
|
|
|
76167
76725
|
{
|
|
76168
76726
|
ref: mobileFilterButtonRef,
|
|
76169
76727
|
onClick: handleFilterToggle,
|
|
76170
|
-
className: `p-2 rounded-full transition-colors relative ${isFilterOpen || activeFilterCount > 0 ? "bg-
|
|
76728
|
+
className: `p-2 rounded-full transition-colors relative ${isFilterOpen || activeFilterCount > 0 ? "bg-slate-100 text-slate-700" : "active:bg-gray-100 text-slate-600"}`,
|
|
76171
76729
|
"aria-label": "Open filters",
|
|
76172
76730
|
children: [
|
|
76173
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Filter, { className:
|
|
76174
|
-
activeFilterCount > 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute -top-1 -right-1 flex items-center justify-center w-4 h-4 bg-
|
|
76731
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Filter, { className: "w-5 h-5" }),
|
|
76732
|
+
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
|
|
76175
76733
|
]
|
|
76176
76734
|
}
|
|
76177
76735
|
)
|
|
76178
76736
|
] })
|
|
76179
76737
|
] }) }),
|
|
76180
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:block", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center relative min-h-[
|
|
76181
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute left-1/2 -translate-x-1/2 flex flex-col items-center
|
|
76182
|
-
/* @__PURE__ */ jsxRuntime.
|
|
76183
|
-
|
|
76738
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:block", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center relative min-h-[64px]", children: [
|
|
76739
|
+
/* @__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: [
|
|
76740
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center gap-2 min-w-0 max-w-full", children: [
|
|
76741
|
+
/* @__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" }),
|
|
76742
|
+
isLiveScope ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
76743
|
+
"div",
|
|
76744
|
+
{
|
|
76745
|
+
"data-testid": "operations-overview-live-indicator",
|
|
76746
|
+
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"
|
|
76747
|
+
}
|
|
76748
|
+
) : null
|
|
76749
|
+
] }),
|
|
76750
|
+
/* @__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: [
|
|
76751
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: desktopSubtitle }),
|
|
76752
|
+
isLiveScope ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
76753
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-slate-300", children: "|" }),
|
|
76754
|
+
/* @__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: [
|
|
76755
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-75", children: liveShiftIcon }),
|
|
76756
|
+
liveShiftLabel
|
|
76757
|
+
] }) })
|
|
76758
|
+
] }) : null
|
|
76759
|
+
] })
|
|
76184
76760
|
] }),
|
|
76185
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute right-0 flex items-center gap-3", children: [
|
|
76761
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute right-0 flex items-center gap-3 shrink-0", children: [
|
|
76186
76762
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
76187
76763
|
MonthlyRangeFilter_default,
|
|
76188
76764
|
{
|
|
@@ -76199,12 +76775,12 @@ var OperationsOverviewHeader = React141__namespace.default.memo(({
|
|
|
76199
76775
|
{
|
|
76200
76776
|
ref: filterButtonRef,
|
|
76201
76777
|
onClick: handleFilterToggle,
|
|
76202
|
-
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-
|
|
76778
|
+
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"}`,
|
|
76203
76779
|
"aria-label": "Open filters",
|
|
76204
76780
|
children: [
|
|
76205
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Filter, { className: `w-[18px] h-[18px] ${activeFilterCount > 0 ? "text-
|
|
76781
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Filter, { className: `w-[18px] h-[18px] ${isFilterOpen || activeFilterCount > 0 ? "text-slate-500" : "text-slate-400"}` }),
|
|
76206
76782
|
"Filters",
|
|
76207
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: `w-4 h-4 ml-0.5 transition-transform duration-200 ${isFilterOpen ? "rotate-180" : ""}` })
|
|
76783
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: `w-4 h-4 ml-0.5 text-slate-400 transition-transform duration-200 ${isFilterOpen ? "rotate-180" : ""}` })
|
|
76208
76784
|
]
|
|
76209
76785
|
}
|
|
76210
76786
|
)
|
|
@@ -76332,11 +76908,18 @@ var OverviewSummaryCards = React141__namespace.default.memo(({ store }) => {
|
|
|
76332
76908
|
const snapshot = useOperationsOverviewSnapshot(store);
|
|
76333
76909
|
const showSnapshotSkeleton = snapshot.loading && !snapshot.hasLoadedOnce;
|
|
76334
76910
|
const comparisonLabel = React141__namespace.default.useMemo(() => {
|
|
76335
|
-
return formatComparisonWindow(
|
|
76336
|
-
scope.
|
|
76337
|
-
scope.
|
|
76338
|
-
|
|
76339
|
-
|
|
76911
|
+
return formatComparisonWindow({
|
|
76912
|
+
currentDayCount: scope.current_range?.day_count ?? null,
|
|
76913
|
+
previousDayCount: scope.previous_range?.day_count ?? null,
|
|
76914
|
+
comparisonStrategy: scope.comparison_strategy,
|
|
76915
|
+
shiftMode: scope.shift_mode
|
|
76916
|
+
});
|
|
76917
|
+
}, [
|
|
76918
|
+
scope.comparison_strategy,
|
|
76919
|
+
scope.current_range?.day_count,
|
|
76920
|
+
scope.previous_range?.day_count,
|
|
76921
|
+
scope.shift_mode
|
|
76922
|
+
]);
|
|
76340
76923
|
const [isIdleContributorsOpen, setIsIdleContributorsOpen] = React141__namespace.default.useState(false);
|
|
76341
76924
|
const [isIdleContributorsPinned, setIsIdleContributorsPinned] = React141__namespace.default.useState(false);
|
|
76342
76925
|
const idleContributorsRef = React141__namespace.default.useRef(null);
|
|
@@ -76426,10 +77009,17 @@ var OverviewSummaryCards = React141__namespace.default.memo(({ store }) => {
|
|
|
76426
77009
|
roundOne(snapshot.data.summary.plant_efficiency.current),
|
|
76427
77010
|
"%"
|
|
76428
77011
|
] }),
|
|
76429
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
76430
|
-
|
|
76431
|
-
|
|
76432
|
-
|
|
77012
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
77013
|
+
"div",
|
|
77014
|
+
{
|
|
77015
|
+
"data-testid": "operations-overview-efficiency-delta",
|
|
77016
|
+
className: `flex items-center gap-1 px-2.5 py-1 rounded-full ${plantEfficiencyBadge.className}`,
|
|
77017
|
+
children: [
|
|
77018
|
+
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,
|
|
77019
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-sm font-medium", children: plantEfficiencyBadge.text })
|
|
77020
|
+
]
|
|
77021
|
+
}
|
|
77022
|
+
)
|
|
76433
77023
|
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 text-sm text-slate-400", children: "No efficiency data available" })
|
|
76434
77024
|
] }),
|
|
76435
77025
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -76475,10 +77065,17 @@ var OverviewSummaryCards = React141__namespace.default.memo(({ store }) => {
|
|
|
76475
77065
|
/* @__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" }) }),
|
|
76476
77066
|
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: [
|
|
76477
77067
|
/* @__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) }),
|
|
76478
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
76479
|
-
|
|
76480
|
-
|
|
76481
|
-
|
|
77068
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
77069
|
+
"div",
|
|
77070
|
+
{
|
|
77071
|
+
"data-testid": "operations-overview-idle-delta",
|
|
77072
|
+
className: `flex items-center gap-1 px-2.5 py-1 rounded-full ${idleBadge.className}`,
|
|
77073
|
+
children: [
|
|
77074
|
+
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,
|
|
77075
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-sm font-medium", children: idleBadge.text })
|
|
77076
|
+
]
|
|
77077
|
+
}
|
|
77078
|
+
)
|
|
76482
77079
|
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 text-sm text-slate-400", children: "No idle time data available" })
|
|
76483
77080
|
]
|
|
76484
77081
|
}
|
|
@@ -76541,11 +77138,18 @@ var PoorestPerformersCard = React141__namespace.default.memo(({
|
|
|
76541
77138
|
}
|
|
76542
77139
|
}, [availableLineModes?.has_output, availableLineModes?.has_uptime, poorestLineMode]);
|
|
76543
77140
|
const comparisonLabel = React141__namespace.default.useMemo(() => {
|
|
76544
|
-
return formatComparisonWindow(
|
|
76545
|
-
scope.
|
|
76546
|
-
scope.
|
|
76547
|
-
|
|
76548
|
-
|
|
77141
|
+
return formatComparisonWindow({
|
|
77142
|
+
currentDayCount: scope.current_range?.day_count ?? null,
|
|
77143
|
+
previousDayCount: scope.previous_range?.day_count ?? null,
|
|
77144
|
+
comparisonStrategy: scope.comparison_strategy,
|
|
77145
|
+
shiftMode: scope.shift_mode
|
|
77146
|
+
});
|
|
77147
|
+
}, [
|
|
77148
|
+
scope.comparison_strategy,
|
|
77149
|
+
scope.current_range?.day_count,
|
|
77150
|
+
scope.previous_range?.day_count,
|
|
77151
|
+
scope.shift_mode
|
|
77152
|
+
]);
|
|
76549
77153
|
const showSnapshotSkeleton = snapshot.loading && !snapshot.hasLoadedOnce;
|
|
76550
77154
|
const mergedPoorestLines = React141__namespace.default.useMemo(() => {
|
|
76551
77155
|
const rows = snapshot.data.poorest_lines?.[poorestLineMode] || [];
|
|
@@ -76702,7 +77306,8 @@ IdleBreakdownCard.displayName = "IdleBreakdownCard";
|
|
|
76702
77306
|
var EfficiencyTrendCard = React141__namespace.default.memo(({
|
|
76703
77307
|
store,
|
|
76704
77308
|
dateRange,
|
|
76705
|
-
appTimezone
|
|
77309
|
+
appTimezone,
|
|
77310
|
+
hourlyLabelStartTime
|
|
76706
77311
|
}) => {
|
|
76707
77312
|
bumpRenderCounter();
|
|
76708
77313
|
const trend = useOperationsOverviewTrend(store);
|
|
@@ -76712,7 +77317,41 @@ var EfficiencyTrendCard = React141__namespace.default.memo(({
|
|
|
76712
77317
|
);
|
|
76713
77318
|
const isCurrentWeekToDateRange = dateRange.startKey === currentWeekRange.startKey && dateRange.endKey === currentWeekRange.endKey;
|
|
76714
77319
|
const showInitialSkeleton = trend.loading && trend.lastUpdated === null;
|
|
77320
|
+
const isHourlyTrend = trend.data.granularity === "hour";
|
|
76715
77321
|
const trendData = React141__namespace.default.useMemo(() => {
|
|
77322
|
+
if (isHourlyTrend) {
|
|
77323
|
+
return (trend.data.points || []).map((point, index) => ({
|
|
77324
|
+
name: (() => {
|
|
77325
|
+
const rawLabel = point.label?.trim() || "";
|
|
77326
|
+
if (!hourlyLabelStartTime) {
|
|
77327
|
+
return rawLabel || `Hour ${index + 1}`;
|
|
77328
|
+
}
|
|
77329
|
+
if (rawLabel && !/^Hour\s+\d+$/i.test(rawLabel)) {
|
|
77330
|
+
return rawLabel;
|
|
77331
|
+
}
|
|
77332
|
+
const hourIndex = typeof point.hour_index === "number" ? point.hour_index : index;
|
|
77333
|
+
const [hoursPart, minutesPart] = hourlyLabelStartTime.split(":");
|
|
77334
|
+
const startHours = Number(hoursPart);
|
|
77335
|
+
const startMinutes = Number(minutesPart);
|
|
77336
|
+
if (!Number.isFinite(startHours) || !Number.isFinite(startMinutes)) {
|
|
77337
|
+
return rawLabel || `Hour ${index + 1}`;
|
|
77338
|
+
}
|
|
77339
|
+
const totalMinutes = startHours * 60 + startMinutes + hourIndex * 60;
|
|
77340
|
+
const hour24 = Math.floor(totalMinutes / 60) % 24;
|
|
77341
|
+
const minutes = totalMinutes % 60;
|
|
77342
|
+
const suffix = hour24 < 12 ? "AM" : "PM";
|
|
77343
|
+
const hour12 = hour24 % 12 || 12;
|
|
77344
|
+
if (minutes === 0) {
|
|
77345
|
+
return `${hour12} ${suffix}`;
|
|
77346
|
+
}
|
|
77347
|
+
return `${hour12}:${minutes.toString().padStart(2, "0")} ${suffix}`;
|
|
77348
|
+
})(),
|
|
77349
|
+
efficiency: (() => {
|
|
77350
|
+
const value = toNumber3(point.avg_efficiency);
|
|
77351
|
+
return value === null ? void 0 : value;
|
|
77352
|
+
})()
|
|
77353
|
+
}));
|
|
77354
|
+
}
|
|
76716
77355
|
const pointsByDate = new Map(
|
|
76717
77356
|
(trend.data.points || []).flatMap((point) => {
|
|
76718
77357
|
if (!point.date) return [];
|
|
@@ -76750,12 +77389,13 @@ var EfficiencyTrendCard = React141__namespace.default.memo(({
|
|
|
76750
77389
|
})()
|
|
76751
77390
|
};
|
|
76752
77391
|
});
|
|
76753
|
-
}, [currentWeekRange.startKey, isCurrentWeekToDateRange, trend.data.points]);
|
|
77392
|
+
}, [currentWeekRange.startKey, hourlyLabelStartTime, isCurrentWeekToDateRange, isHourlyTrend, trend.data.points]);
|
|
76754
77393
|
const trendTooltipLabelFormatter = React141__namespace.default.useCallback((label, payload) => {
|
|
77394
|
+
if (isHourlyTrend) return label;
|
|
76755
77395
|
const dayOfWeek = payload?.[0]?.payload?.dayOfWeek;
|
|
76756
77396
|
if (!dayOfWeek || typeof label !== "string") return label;
|
|
76757
77397
|
return `${label} (${dayOfWeek})`;
|
|
76758
|
-
}, []);
|
|
77398
|
+
}, [isHourlyTrend]);
|
|
76759
77399
|
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: [
|
|
76760
77400
|
/* @__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" }) }),
|
|
76761
77401
|
/* @__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(
|
|
@@ -76909,7 +77549,8 @@ var useOperationsOverviewRefresh = ({
|
|
|
76909
77549
|
endKey,
|
|
76910
77550
|
trendMode,
|
|
76911
77551
|
comparisonStrategy,
|
|
76912
|
-
isLiveScope
|
|
77552
|
+
isLiveScope,
|
|
77553
|
+
enabled = true
|
|
76913
77554
|
}) => {
|
|
76914
77555
|
const lineIdsKey = React141__namespace.default.useMemo(() => lineIds.join(","), [lineIds]);
|
|
76915
77556
|
const scopeSignature = React141__namespace.default.useMemo(
|
|
@@ -76955,7 +77596,7 @@ var useOperationsOverviewRefresh = ({
|
|
|
76955
77596
|
}, []);
|
|
76956
77597
|
const runRefresh = React141__namespace.default.useCallback(
|
|
76957
77598
|
async (section, begin, onSuccess, onError, request, reason) => {
|
|
76958
|
-
if (!supabase || !companyId || lineIds.length === 0) return;
|
|
77599
|
+
if (!enabled || !supabase || !companyId || lineIds.length === 0) return;
|
|
76959
77600
|
const requestId = requestIdsRef.current[section] + 1;
|
|
76960
77601
|
requestIdsRef.current[section] = requestId;
|
|
76961
77602
|
controllersRef.current[section]?.abort();
|
|
@@ -76975,7 +77616,7 @@ var useOperationsOverviewRefresh = ({
|
|
|
76975
77616
|
onError(error instanceof Error ? error.message : `Failed to refresh ${section}`);
|
|
76976
77617
|
}
|
|
76977
77618
|
},
|
|
76978
|
-
[companyId, lineIds.length, supabase]
|
|
77619
|
+
[companyId, enabled, lineIds.length, supabase]
|
|
76979
77620
|
);
|
|
76980
77621
|
const refreshSnapshot = React141__namespace.default.useCallback(
|
|
76981
77622
|
async (reason) => {
|
|
@@ -77145,6 +77786,12 @@ var useOperationsOverviewRefresh = ({
|
|
|
77145
77786
|
});
|
|
77146
77787
|
}, [refreshAll, startPolling, stopPolling]);
|
|
77147
77788
|
React141__namespace.default.useEffect(() => {
|
|
77789
|
+
if (!enabled) {
|
|
77790
|
+
stopPolling("disabled");
|
|
77791
|
+
abortAll();
|
|
77792
|
+
store.reset();
|
|
77793
|
+
return;
|
|
77794
|
+
}
|
|
77148
77795
|
if (!supabase || !companyId || lineIds.length === 0) {
|
|
77149
77796
|
stopPolling("scope_invalid");
|
|
77150
77797
|
abortAll();
|
|
@@ -77152,9 +77799,9 @@ var useOperationsOverviewRefresh = ({
|
|
|
77152
77799
|
return;
|
|
77153
77800
|
}
|
|
77154
77801
|
void refreshAll("scope_change");
|
|
77155
|
-
}, [abortAll, companyId, lineIds.length, refreshAll, scopeSignature, stopPolling, store, supabase]);
|
|
77802
|
+
}, [abortAll, companyId, enabled, lineIds.length, refreshAll, scopeSignature, stopPolling, store, supabase]);
|
|
77156
77803
|
React141__namespace.default.useEffect(() => {
|
|
77157
|
-
if (!isLiveScope || !supabase || !companyId || lineIds.length === 0) {
|
|
77804
|
+
if (!enabled || !isLiveScope || !supabase || !companyId || lineIds.length === 0) {
|
|
77158
77805
|
isPageActiveRef.current = false;
|
|
77159
77806
|
stopPolling("live_scope_disabled");
|
|
77160
77807
|
return;
|
|
@@ -77210,11 +77857,63 @@ var useOperationsOverviewRefresh = ({
|
|
|
77210
77857
|
window.removeEventListener("pageshow", handlePageShow);
|
|
77211
77858
|
window.removeEventListener("pagehide", handlePageHide);
|
|
77212
77859
|
};
|
|
77213
|
-
}, [companyId, getIsPageActive, isLiveScope, lineIds.length, refreshFromResume, startPolling, stopPolling, supabase]);
|
|
77860
|
+
}, [companyId, enabled, getIsPageActive, isLiveScope, lineIds.length, refreshFromResume, startPolling, stopPolling, supabase]);
|
|
77861
|
+
};
|
|
77862
|
+
var parseTimeToMinutes3 = (value) => {
|
|
77863
|
+
if (!value) return null;
|
|
77864
|
+
const parts = value.split(":");
|
|
77865
|
+
if (parts.length < 2) return null;
|
|
77866
|
+
const hours = Number(parts[0]);
|
|
77867
|
+
const minutes = Number(parts[1]);
|
|
77868
|
+
if (!Number.isFinite(hours) || !Number.isFinite(minutes)) return null;
|
|
77869
|
+
if (hours < 0 || hours > 23 || minutes < 0 || minutes > 59) return null;
|
|
77870
|
+
return hours * 60 + minutes;
|
|
77871
|
+
};
|
|
77872
|
+
var normalizeShiftId = (value) => {
|
|
77873
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
77874
|
+
return value;
|
|
77875
|
+
}
|
|
77876
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
77877
|
+
const parsed = Number(value);
|
|
77878
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
77879
|
+
}
|
|
77880
|
+
return null;
|
|
77881
|
+
};
|
|
77882
|
+
var classifyShiftBucket = ({
|
|
77883
|
+
shiftName,
|
|
77884
|
+
shiftId,
|
|
77885
|
+
startTime,
|
|
77886
|
+
endTime
|
|
77887
|
+
}) => {
|
|
77888
|
+
const normalizedName = (shiftName || "").trim().toLowerCase();
|
|
77889
|
+
if (normalizedName) {
|
|
77890
|
+
if (["night", "graveyard", "evening"].some((keyword) => normalizedName.includes(keyword))) {
|
|
77891
|
+
return "night";
|
|
77892
|
+
}
|
|
77893
|
+
if (["day", "morning"].some((keyword) => normalizedName.includes(keyword))) {
|
|
77894
|
+
return "day";
|
|
77895
|
+
}
|
|
77896
|
+
}
|
|
77897
|
+
const startMinutes = parseTimeToMinutes3(startTime);
|
|
77898
|
+
const endMinutes = parseTimeToMinutes3(endTime);
|
|
77899
|
+
if (startMinutes !== null) {
|
|
77900
|
+
if (startMinutes >= 4 * 60 && startMinutes < 18 * 60) return "day";
|
|
77901
|
+
return "night";
|
|
77902
|
+
}
|
|
77903
|
+
if (endMinutes !== null) {
|
|
77904
|
+
if (endMinutes >= 6 * 60 && endMinutes <= 21 * 60) return "day";
|
|
77905
|
+
return "night";
|
|
77906
|
+
}
|
|
77907
|
+
const normalizedShiftId = normalizeShiftId(shiftId);
|
|
77908
|
+
if (normalizedShiftId === 0) return "day";
|
|
77909
|
+
if (normalizedShiftId === 1) return "night";
|
|
77910
|
+
return null;
|
|
77214
77911
|
};
|
|
77215
77912
|
var PlantHeadView = () => {
|
|
77216
77913
|
const supabase = useSupabase();
|
|
77217
77914
|
const entityConfig = useEntityConfig();
|
|
77915
|
+
const factoryViewId = entityConfig.factoryViewId || "factory";
|
|
77916
|
+
const staticShiftConfig = useShiftConfig();
|
|
77218
77917
|
const appTimezone = useAppTimezone() || "UTC";
|
|
77219
77918
|
const { navigate } = useNavigation();
|
|
77220
77919
|
const { accessibleLineIds } = useUserLineAccess();
|
|
@@ -77222,11 +77921,21 @@ var PlantHeadView = () => {
|
|
|
77222
77921
|
useHideMobileHeader(!!mobileMenuContext);
|
|
77223
77922
|
const storeRef = React141__namespace.default.useRef(createOperationsOverviewStore());
|
|
77224
77923
|
const store = storeRef.current;
|
|
77225
|
-
const
|
|
77226
|
-
|
|
77924
|
+
const fallbackOperationalDate = React141__namespace.default.useMemo(
|
|
77925
|
+
() => getOperationalDate(appTimezone),
|
|
77926
|
+
[appTimezone]
|
|
77927
|
+
);
|
|
77928
|
+
const [dateRange, setDateRange] = React141__namespace.default.useState(() => ({
|
|
77929
|
+
startKey: fallbackOperationalDate,
|
|
77930
|
+
endKey: fallbackOperationalDate
|
|
77931
|
+
}));
|
|
77932
|
+
const [usesThisWeekComparison, setUsesThisWeekComparison] = React141__namespace.default.useState(false);
|
|
77227
77933
|
const [trendMode, setTrendMode] = React141__namespace.default.useState("all");
|
|
77228
77934
|
const [selectedSupervisorId, setSelectedSupervisorId] = React141__namespace.default.useState("all");
|
|
77229
77935
|
const [selectedLineIds, setSelectedLineIds] = React141__namespace.default.useState([]);
|
|
77936
|
+
const [isInitialScopeReady, setIsInitialScopeReady] = React141__namespace.default.useState(false);
|
|
77937
|
+
const hasAutoInitializedScopeRef = React141__namespace.default.useRef(false);
|
|
77938
|
+
const hasUserAdjustedScopeRef = React141__namespace.default.useRef(false);
|
|
77230
77939
|
React141__namespace.default.useEffect(() => {
|
|
77231
77940
|
trackCorePageView("Operations Overview", {
|
|
77232
77941
|
dashboard_surface: "operations_overview"
|
|
@@ -77248,8 +77957,10 @@ var PlantHeadView = () => {
|
|
|
77248
77957
|
return dateRange;
|
|
77249
77958
|
}, [currentWeekDisplayRange, dateRange, isCurrentWeekToDateRange, usesThisWeekComparison]);
|
|
77250
77959
|
const normalizedLineIds = React141__namespace.default.useMemo(
|
|
77251
|
-
() => Array.from(new Set(
|
|
77252
|
-
|
|
77960
|
+
() => Array.from(new Set(
|
|
77961
|
+
(accessibleLineIds || []).filter(Boolean).filter((lineId) => lineId !== factoryViewId)
|
|
77962
|
+
)).sort(),
|
|
77963
|
+
[accessibleLineIds, factoryViewId]
|
|
77253
77964
|
);
|
|
77254
77965
|
const lineIdsKey = React141__namespace.default.useMemo(
|
|
77255
77966
|
() => normalizedLineIds.join(","),
|
|
@@ -77323,14 +78034,81 @@ var PlantHeadView = () => {
|
|
|
77323
78034
|
() => selectedLineIds.length > 0 ? selectedLineIds : normalizedLineIds,
|
|
77324
78035
|
[normalizedLineIds, selectedLineIds]
|
|
77325
78036
|
);
|
|
78037
|
+
const {
|
|
78038
|
+
shiftConfigMap,
|
|
78039
|
+
isLoading: isShiftConfigLoading
|
|
78040
|
+
} = useMultiLineShiftConfigs(scopedLineIds, staticShiftConfig);
|
|
78041
|
+
const { shiftGroups, hasComputed: hasComputedShiftGroups } = useShiftGroups({
|
|
78042
|
+
enabled: scopedLineIds.length > 0 && !isShiftConfigLoading,
|
|
78043
|
+
shiftConfigMap,
|
|
78044
|
+
timezone: appTimezone
|
|
78045
|
+
});
|
|
78046
|
+
const currentShiftScope = React141__namespace.default.useMemo(() => {
|
|
78047
|
+
if (shiftGroups.length !== 1) return null;
|
|
78048
|
+
const group = shiftGroups[0];
|
|
78049
|
+
const referenceLineId = group.lineIds[0];
|
|
78050
|
+
const referenceShiftConfig = referenceLineId ? shiftConfigMap.get(referenceLineId) : null;
|
|
78051
|
+
const normalizedGroupShiftId = normalizeShiftId(group.shiftId);
|
|
78052
|
+
const shiftDefinition = referenceShiftConfig?.shifts?.find((shift) => normalizeShiftId(shift.shiftId) === normalizedGroupShiftId);
|
|
78053
|
+
const resolvedMode = classifyShiftBucket({
|
|
78054
|
+
shiftName: group.shiftName,
|
|
78055
|
+
shiftId: normalizedGroupShiftId,
|
|
78056
|
+
startTime: shiftDefinition?.startTime,
|
|
78057
|
+
endTime: shiftDefinition?.endTime
|
|
78058
|
+
});
|
|
78059
|
+
if (!resolvedMode || resolvedMode === "all") return null;
|
|
78060
|
+
return {
|
|
78061
|
+
date: group.date,
|
|
78062
|
+
trendMode: resolvedMode,
|
|
78063
|
+
shiftName: shiftDefinition?.shiftName || group.shiftName || null
|
|
78064
|
+
};
|
|
78065
|
+
}, [shiftConfigMap, shiftGroups]);
|
|
78066
|
+
const isShiftScopeResolved = React141__namespace.default.useMemo(
|
|
78067
|
+
() => !isShiftConfigLoading && hasComputedShiftGroups,
|
|
78068
|
+
[hasComputedShiftGroups, isShiftConfigLoading]
|
|
78069
|
+
);
|
|
77326
78070
|
const initializedTimezoneRef = React141__namespace.default.useRef(appTimezone);
|
|
77327
78071
|
React141__namespace.default.useEffect(() => {
|
|
77328
78072
|
if (initializedTimezoneRef.current === appTimezone) return;
|
|
77329
|
-
|
|
77330
|
-
|
|
78073
|
+
hasAutoInitializedScopeRef.current = false;
|
|
78074
|
+
hasUserAdjustedScopeRef.current = false;
|
|
78075
|
+
setDateRange({
|
|
78076
|
+
startKey: fallbackOperationalDate,
|
|
78077
|
+
endKey: fallbackOperationalDate
|
|
78078
|
+
});
|
|
78079
|
+
setTrendMode("all");
|
|
78080
|
+
setUsesThisWeekComparison(false);
|
|
78081
|
+
setIsInitialScopeReady(false);
|
|
77331
78082
|
initializedTimezoneRef.current = appTimezone;
|
|
77332
|
-
}, [appTimezone]);
|
|
78083
|
+
}, [appTimezone, fallbackOperationalDate]);
|
|
78084
|
+
React141__namespace.default.useEffect(() => {
|
|
78085
|
+
if (hasAutoInitializedScopeRef.current || hasUserAdjustedScopeRef.current) {
|
|
78086
|
+
return;
|
|
78087
|
+
}
|
|
78088
|
+
if (scopedLineIds.length === 0) {
|
|
78089
|
+
return;
|
|
78090
|
+
}
|
|
78091
|
+
if (!isShiftScopeResolved) {
|
|
78092
|
+
return;
|
|
78093
|
+
}
|
|
78094
|
+
setDateRange((previous) => {
|
|
78095
|
+
const nextStartKey = currentShiftScope?.date || fallbackOperationalDate;
|
|
78096
|
+
if (previous.startKey === nextStartKey && previous.endKey === nextStartKey) {
|
|
78097
|
+
return previous;
|
|
78098
|
+
}
|
|
78099
|
+
return {
|
|
78100
|
+
startKey: nextStartKey,
|
|
78101
|
+
endKey: nextStartKey
|
|
78102
|
+
};
|
|
78103
|
+
});
|
|
78104
|
+
setTrendMode(currentShiftScope?.trendMode || "all");
|
|
78105
|
+
setUsesThisWeekComparison(false);
|
|
78106
|
+
hasAutoInitializedScopeRef.current = true;
|
|
78107
|
+
setIsInitialScopeReady(true);
|
|
78108
|
+
}, [currentShiftScope, fallbackOperationalDate, isShiftScopeResolved, scopedLineIds.length]);
|
|
77333
78109
|
const handleDateRangeChange = React141__namespace.default.useCallback((range, meta) => {
|
|
78110
|
+
hasUserAdjustedScopeRef.current = true;
|
|
78111
|
+
setIsInitialScopeReady(true);
|
|
77334
78112
|
trackCoreEvent("Operations Overview Date Range Changed", {
|
|
77335
78113
|
start_date: range.startKey,
|
|
77336
78114
|
end_date: range.endKey
|
|
@@ -77347,6 +78125,8 @@ var PlantHeadView = () => {
|
|
|
77347
78125
|
});
|
|
77348
78126
|
}, []);
|
|
77349
78127
|
const handleTrendModeChange = React141__namespace.default.useCallback((mode) => {
|
|
78128
|
+
hasUserAdjustedScopeRef.current = true;
|
|
78129
|
+
setIsInitialScopeReady(true);
|
|
77350
78130
|
setTrendMode(mode);
|
|
77351
78131
|
}, []);
|
|
77352
78132
|
const handleSelectedLineIdsChange = React141__namespace.default.useCallback((lineIds) => {
|
|
@@ -77373,15 +78153,6 @@ var PlantHeadView = () => {
|
|
|
77373
78153
|
params.set("rangeEnd", dateRange.endKey);
|
|
77374
78154
|
return `/kpis/${lineId}?${params.toString()}`;
|
|
77375
78155
|
}, [dateRange.endKey, dateRange.startKey]);
|
|
77376
|
-
const handleOpenLineMonthlyHistory = React141__namespace.default.useCallback((lineId, lineName) => {
|
|
77377
|
-
trackCoreEvent("Operations Overview Line Clicked", {
|
|
77378
|
-
line_id: lineId,
|
|
77379
|
-
line_name: lineName,
|
|
77380
|
-
range_start: dateRange.startKey,
|
|
77381
|
-
range_end: dateRange.endKey
|
|
77382
|
-
});
|
|
77383
|
-
navigate(buildLineMonthlyHistoryUrl(lineId));
|
|
77384
|
-
}, [buildLineMonthlyHistoryUrl, dateRange.endKey, dateRange.startKey, navigate]);
|
|
77385
78156
|
const handleViewAllPoorestPerformers = React141__namespace.default.useCallback(() => {
|
|
77386
78157
|
trackCoreEvent("Operations Overview View All Clicked", { section: "poorest_performers" });
|
|
77387
78158
|
navigate("/kpis?tab=leaderboard");
|
|
@@ -77407,16 +78178,74 @@ var PlantHeadView = () => {
|
|
|
77407
78178
|
}
|
|
77408
78179
|
return void 0;
|
|
77409
78180
|
}, [isCurrentWeekToDateRange, usesThisWeekComparison]);
|
|
78181
|
+
const effectiveDateRange = React141__namespace.default.useMemo(() => {
|
|
78182
|
+
if (isInitialScopeReady) {
|
|
78183
|
+
return dateRange;
|
|
78184
|
+
}
|
|
78185
|
+
const nextStartKey = currentShiftScope?.date || fallbackOperationalDate;
|
|
78186
|
+
return {
|
|
78187
|
+
startKey: nextStartKey,
|
|
78188
|
+
endKey: nextStartKey
|
|
78189
|
+
};
|
|
78190
|
+
}, [currentShiftScope, dateRange, fallbackOperationalDate, isInitialScopeReady]);
|
|
78191
|
+
const effectiveTrendMode = React141__namespace.default.useMemo(
|
|
78192
|
+
() => isInitialScopeReady ? trendMode : currentShiftScope?.trendMode || "all",
|
|
78193
|
+
[currentShiftScope, isInitialScopeReady, trendMode]
|
|
78194
|
+
);
|
|
78195
|
+
const hourlyLabelStartTime = React141__namespace.default.useMemo(() => {
|
|
78196
|
+
if (effectiveTrendMode === "all" || scopedLineIds.length === 0) {
|
|
78197
|
+
return null;
|
|
78198
|
+
}
|
|
78199
|
+
const shiftStartTimes = /* @__PURE__ */ new Set();
|
|
78200
|
+
scopedLineIds.forEach((lineId) => {
|
|
78201
|
+
const shiftConfig = shiftConfigMap.get(lineId);
|
|
78202
|
+
const matchingShift = shiftConfig?.shifts?.find((shift) => classifyShiftBucket({
|
|
78203
|
+
shiftName: shift.shiftName,
|
|
78204
|
+
shiftId: shift.shiftId,
|
|
78205
|
+
startTime: shift.startTime,
|
|
78206
|
+
endTime: shift.endTime
|
|
78207
|
+
}) === effectiveTrendMode);
|
|
78208
|
+
if (matchingShift?.startTime) {
|
|
78209
|
+
shiftStartTimes.add(matchingShift.startTime);
|
|
78210
|
+
}
|
|
78211
|
+
});
|
|
78212
|
+
if (shiftStartTimes.size !== 1) {
|
|
78213
|
+
return null;
|
|
78214
|
+
}
|
|
78215
|
+
return Array.from(shiftStartTimes)[0] || null;
|
|
78216
|
+
}, [effectiveTrendMode, scopedLineIds, shiftConfigMap]);
|
|
78217
|
+
const isSingleDayShiftScope = React141__namespace.default.useMemo(
|
|
78218
|
+
() => effectiveDateRange.startKey === effectiveDateRange.endKey && effectiveTrendMode !== "all",
|
|
78219
|
+
[effectiveDateRange.endKey, effectiveDateRange.startKey, effectiveTrendMode]
|
|
78220
|
+
);
|
|
78221
|
+
const isLiveScope = React141__namespace.default.useMemo(
|
|
78222
|
+
() => isSingleDayShiftScope && currentShiftScope !== null && effectiveDateRange.startKey === currentShiftScope.date && effectiveTrendMode === currentShiftScope.trendMode,
|
|
78223
|
+
[currentShiftScope, effectiveDateRange.startKey, effectiveTrendMode, isSingleDayShiftScope]
|
|
78224
|
+
);
|
|
78225
|
+
const handleOpenLineDetails = React141__namespace.default.useCallback((lineId, lineName) => {
|
|
78226
|
+
trackCoreEvent("Operations Overview Line Clicked", {
|
|
78227
|
+
line_id: lineId,
|
|
78228
|
+
line_name: lineName,
|
|
78229
|
+
range_start: dateRange.startKey,
|
|
78230
|
+
range_end: dateRange.endKey
|
|
78231
|
+
});
|
|
78232
|
+
if (isLiveScope) {
|
|
78233
|
+
navigate(`/kpis/${lineId}?returnTo=${encodeURIComponent("/")}`);
|
|
78234
|
+
return;
|
|
78235
|
+
}
|
|
78236
|
+
navigate(buildLineMonthlyHistoryUrl(lineId));
|
|
78237
|
+
}, [buildLineMonthlyHistoryUrl, dateRange.endKey, dateRange.startKey, isLiveScope, navigate]);
|
|
77410
78238
|
useOperationsOverviewRefresh({
|
|
77411
78239
|
store,
|
|
77412
78240
|
supabase,
|
|
77413
78241
|
companyId: entityConfig.companyId,
|
|
77414
78242
|
lineIds: scopedLineIds,
|
|
77415
|
-
startKey:
|
|
77416
|
-
endKey:
|
|
77417
|
-
trendMode,
|
|
78243
|
+
startKey: effectiveDateRange.startKey,
|
|
78244
|
+
endKey: effectiveDateRange.endKey,
|
|
78245
|
+
trendMode: effectiveTrendMode,
|
|
77418
78246
|
comparisonStrategy,
|
|
77419
|
-
isLiveScope
|
|
78247
|
+
isLiveScope,
|
|
78248
|
+
enabled: scopedLineIds.length > 0 && isShiftScopeResolved
|
|
77420
78249
|
});
|
|
77421
78250
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col min-h-screen bg-slate-50 w-full font-sans", children: [
|
|
77422
78251
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -77425,6 +78254,8 @@ var PlantHeadView = () => {
|
|
|
77425
78254
|
dateRange,
|
|
77426
78255
|
displayDateRange: headerDateRange,
|
|
77427
78256
|
trendMode,
|
|
78257
|
+
isLiveScope,
|
|
78258
|
+
liveShiftName: currentShiftScope?.shiftName || null,
|
|
77428
78259
|
lineOptions,
|
|
77429
78260
|
supervisorOptions,
|
|
77430
78261
|
selectedSupervisorId,
|
|
@@ -77447,7 +78278,7 @@ var PlantHeadView = () => {
|
|
|
77447
78278
|
store,
|
|
77448
78279
|
supervisorsByLineId,
|
|
77449
78280
|
onViewAll: handleViewAllPoorestPerformers,
|
|
77450
|
-
onLineClick:
|
|
78281
|
+
onLineClick: handleOpenLineDetails
|
|
77451
78282
|
}
|
|
77452
78283
|
),
|
|
77453
78284
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -77464,7 +78295,8 @@ var PlantHeadView = () => {
|
|
|
77464
78295
|
{
|
|
77465
78296
|
store,
|
|
77466
78297
|
dateRange,
|
|
77467
|
-
appTimezone
|
|
78298
|
+
appTimezone,
|
|
78299
|
+
hourlyLabelStartTime
|
|
77468
78300
|
}
|
|
77469
78301
|
),
|
|
77470
78302
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -78325,6 +79157,7 @@ exports.isEfficiencyOnTrack = isEfficiencyOnTrack;
|
|
|
78325
79157
|
exports.isFactoryScopedRole = isFactoryScopedRole;
|
|
78326
79158
|
exports.isFullMonthRange = isFullMonthRange;
|
|
78327
79159
|
exports.isLegacyConfiguration = isLegacyConfiguration;
|
|
79160
|
+
exports.isLoopbackHostname = isLoopbackHostname;
|
|
78328
79161
|
exports.isPrefetchError = isPrefetchError;
|
|
78329
79162
|
exports.isRecentFlowVideoGridMetricMode = isRecentFlowVideoGridMetricMode;
|
|
78330
79163
|
exports.isSafari = isSafari;
|
|
@@ -78366,6 +79199,7 @@ exports.resetSubscriptionManager = resetSubscriptionManager;
|
|
|
78366
79199
|
exports.s3VideoPreloader = s3VideoPreloader;
|
|
78367
79200
|
exports.setSentryUserContext = setSentryUserContext;
|
|
78368
79201
|
exports.setSentryWorkspaceContext = setSentryWorkspaceContext;
|
|
79202
|
+
exports.shouldEnableLocalDevTestLogin = shouldEnableLocalDevTestLogin;
|
|
78369
79203
|
exports.shuffleArray = shuffleArray;
|
|
78370
79204
|
exports.simulateApiDelay = simulateApiDelay;
|
|
78371
79205
|
exports.skuService = skuService;
|