@optifye/dashboard-core 6.0.9 → 6.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +29 -43
- package/dist/index.d.ts +29 -43
- package/dist/index.js +495 -214
- package/dist/index.mjs +495 -216
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5016,34 +5016,6 @@ var useWorkspaceOperators = (workspaceId, options) => {
|
|
|
5016
5016
|
refetch: fetchData
|
|
5017
5017
|
};
|
|
5018
5018
|
};
|
|
5019
|
-
|
|
5020
|
-
// src/lib/utils/dashboardReload.ts
|
|
5021
|
-
var createThrottledReload = (interval = 5e3) => {
|
|
5022
|
-
let last = 0;
|
|
5023
|
-
let queued = false;
|
|
5024
|
-
const doReload = () => {
|
|
5025
|
-
if (typeof window !== "undefined") {
|
|
5026
|
-
window.location.reload();
|
|
5027
|
-
}
|
|
5028
|
-
};
|
|
5029
|
-
return () => {
|
|
5030
|
-
const now2 = Date.now();
|
|
5031
|
-
if (now2 - last >= interval) {
|
|
5032
|
-
last = now2;
|
|
5033
|
-
doReload();
|
|
5034
|
-
} else if (!queued) {
|
|
5035
|
-
queued = true;
|
|
5036
|
-
setTimeout(() => {
|
|
5037
|
-
queued = false;
|
|
5038
|
-
last = Date.now();
|
|
5039
|
-
doReload();
|
|
5040
|
-
}, interval - (now2 - last));
|
|
5041
|
-
}
|
|
5042
|
-
};
|
|
5043
|
-
};
|
|
5044
|
-
var throttledReloadDashboard = createThrottledReload(5e3);
|
|
5045
|
-
|
|
5046
|
-
// src/lib/hooks/useHlsStream.ts
|
|
5047
5019
|
var HLS_CONFIG = {
|
|
5048
5020
|
maxBufferLength: 8,
|
|
5049
5021
|
maxMaxBufferLength: 15,
|
|
@@ -5062,7 +5034,35 @@ var HLS_CONFIG = {
|
|
|
5062
5034
|
liveSyncDurationCount: 2
|
|
5063
5035
|
// Follow live edge aggressively
|
|
5064
5036
|
};
|
|
5037
|
+
var failedUrls = /* @__PURE__ */ new Map();
|
|
5038
|
+
var MAX_FAILURES_PER_URL = 3;
|
|
5039
|
+
var FAILURE_EXPIRY_MS = 5 * 60 * 1e3;
|
|
5040
|
+
function resetFailedUrl(url) {
|
|
5041
|
+
if (failedUrls.has(url)) {
|
|
5042
|
+
console.log(`[HLS] Manually resetting failed URL: ${url}`);
|
|
5043
|
+
failedUrls.delete(url);
|
|
5044
|
+
}
|
|
5045
|
+
}
|
|
5046
|
+
function isUrlPermanentlyFailed(url) {
|
|
5047
|
+
const failure = failedUrls.get(url);
|
|
5048
|
+
return failure?.permanentlyFailed || false;
|
|
5049
|
+
}
|
|
5065
5050
|
function useHlsStream(videoRef, { src, shouldPlay, onFatalError }) {
|
|
5051
|
+
const urlFailure = failedUrls.get(src);
|
|
5052
|
+
const isPermanentlyFailed = urlFailure?.permanentlyFailed || false;
|
|
5053
|
+
const cleanupFailedUrls = () => {
|
|
5054
|
+
const now2 = Date.now();
|
|
5055
|
+
const expiredUrls = [];
|
|
5056
|
+
failedUrls.forEach((failure, url) => {
|
|
5057
|
+
if (now2 - failure.timestamp > FAILURE_EXPIRY_MS) {
|
|
5058
|
+
expiredUrls.push(url);
|
|
5059
|
+
}
|
|
5060
|
+
});
|
|
5061
|
+
expiredUrls.forEach((url) => {
|
|
5062
|
+
console.log(`[HLS] Removing expired failure entry for: ${url}`);
|
|
5063
|
+
failedUrls.delete(url);
|
|
5064
|
+
});
|
|
5065
|
+
};
|
|
5066
5066
|
const [restartKey, setRestartKey] = React19.useState(0);
|
|
5067
5067
|
const hlsRef = React19.useRef(null);
|
|
5068
5068
|
const stallCheckIntervalRef = React19.useRef(null);
|
|
@@ -5132,14 +5132,33 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError }) {
|
|
|
5132
5132
|
};
|
|
5133
5133
|
const hardRestart = (reason) => {
|
|
5134
5134
|
console.warn(`[HLS] Hard restart: ${reason}`);
|
|
5135
|
+
cleanupFailedUrls();
|
|
5136
|
+
const failure = failedUrls.get(src);
|
|
5137
|
+
const failureCount = failure ? failure.count : 0;
|
|
5138
|
+
if (failureCount >= MAX_FAILURES_PER_URL) {
|
|
5139
|
+
console.error(`[HLS] URL has failed ${failureCount} times. Marking as permanently failed: ${src}`);
|
|
5140
|
+
failedUrls.set(src, {
|
|
5141
|
+
count: failureCount,
|
|
5142
|
+
timestamp: Date.now(),
|
|
5143
|
+
permanentlyFailed: true
|
|
5144
|
+
});
|
|
5145
|
+
cleanup();
|
|
5146
|
+
if (onFatalError) {
|
|
5147
|
+
onFatalError();
|
|
5148
|
+
}
|
|
5149
|
+
return;
|
|
5150
|
+
}
|
|
5151
|
+
failedUrls.set(src, {
|
|
5152
|
+
count: failureCount + 1,
|
|
5153
|
+
timestamp: Date.now(),
|
|
5154
|
+
permanentlyFailed: false
|
|
5155
|
+
});
|
|
5135
5156
|
cleanup();
|
|
5136
5157
|
setRestartKey((k) => k + 1);
|
|
5137
5158
|
softRestartCountRef.current = 0;
|
|
5138
|
-
if (reason.includes("hard restart")
|
|
5159
|
+
if (reason.includes("404 hard restart")) {
|
|
5139
5160
|
if (onFatalError) {
|
|
5140
5161
|
onFatalError();
|
|
5141
|
-
} else {
|
|
5142
|
-
throttledReloadDashboard();
|
|
5143
5162
|
}
|
|
5144
5163
|
}
|
|
5145
5164
|
};
|
|
@@ -5193,6 +5212,13 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError }) {
|
|
|
5193
5212
|
}, 7e3);
|
|
5194
5213
|
};
|
|
5195
5214
|
React19.useEffect(() => {
|
|
5215
|
+
if (isPermanentlyFailed) {
|
|
5216
|
+
console.warn(`[HLS] URL is permanently failed, not attempting to load: ${src}`);
|
|
5217
|
+
if (onFatalError) {
|
|
5218
|
+
onFatalError();
|
|
5219
|
+
}
|
|
5220
|
+
return;
|
|
5221
|
+
}
|
|
5196
5222
|
if (!src || !shouldPlay) {
|
|
5197
5223
|
cleanup();
|
|
5198
5224
|
return;
|
|
@@ -5223,6 +5249,10 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError }) {
|
|
|
5223
5249
|
}
|
|
5224
5250
|
});
|
|
5225
5251
|
hls.on(Hls2__default.default.Events.MANIFEST_PARSED, () => {
|
|
5252
|
+
if (failedUrls.has(src)) {
|
|
5253
|
+
console.log(`[HLS] Stream loaded successfully, resetting failure count for: ${src}`);
|
|
5254
|
+
failedUrls.delete(src);
|
|
5255
|
+
}
|
|
5226
5256
|
video.play().catch((err) => {
|
|
5227
5257
|
console.error("[HLS] Play failed:", err);
|
|
5228
5258
|
});
|
|
@@ -5241,7 +5271,7 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError }) {
|
|
|
5241
5271
|
console.error("[HLS] HLS not supported");
|
|
5242
5272
|
}
|
|
5243
5273
|
return cleanup;
|
|
5244
|
-
}, [src, shouldPlay, restartKey, onFatalError]);
|
|
5274
|
+
}, [src, shouldPlay, restartKey, onFatalError, isPermanentlyFailed]);
|
|
5245
5275
|
return {
|
|
5246
5276
|
restartKey,
|
|
5247
5277
|
isNativeHls: isNativeHlsRef.current
|
|
@@ -6346,7 +6376,7 @@ function useNavigation(customNavigate) {
|
|
|
6346
6376
|
}
|
|
6347
6377
|
function useWorkspaceNavigation() {
|
|
6348
6378
|
const { defaultTimezone } = useDateTimeConfig();
|
|
6349
|
-
const
|
|
6379
|
+
const getWorkspaceNavigationParams2 = React19.useCallback(
|
|
6350
6380
|
(workspaceId, options) => {
|
|
6351
6381
|
let dateToUse = options?.date;
|
|
6352
6382
|
if (!dateToUse && options?.useCurrentDate) {
|
|
@@ -6362,7 +6392,7 @@ function useWorkspaceNavigation() {
|
|
|
6362
6392
|
[defaultTimezone]
|
|
6363
6393
|
);
|
|
6364
6394
|
return {
|
|
6365
|
-
getWorkspaceNavigationParams:
|
|
6395
|
+
getWorkspaceNavigationParams: getWorkspaceNavigationParams2
|
|
6366
6396
|
};
|
|
6367
6397
|
}
|
|
6368
6398
|
function useDateFormatter() {
|
|
@@ -9060,9 +9090,15 @@ var getStoredWorkspaceMappings = () => {
|
|
|
9060
9090
|
var getDefaultTabForWorkspace = (workspaceId, displayName) => {
|
|
9061
9091
|
return "overview";
|
|
9062
9092
|
};
|
|
9063
|
-
var getWorkspaceNavigationParams = (workspaceId, displayName) => {
|
|
9093
|
+
var getWorkspaceNavigationParams = (workspaceId, displayName, lineId) => {
|
|
9064
9094
|
const defaultTab = getDefaultTabForWorkspace();
|
|
9065
|
-
|
|
9095
|
+
const params = new URLSearchParams();
|
|
9096
|
+
params.set("displayName", displayName);
|
|
9097
|
+
params.set("defaultTab", defaultTab);
|
|
9098
|
+
if (lineId) {
|
|
9099
|
+
params.set("lineId", lineId);
|
|
9100
|
+
}
|
|
9101
|
+
return `?${params.toString()}`;
|
|
9066
9102
|
};
|
|
9067
9103
|
|
|
9068
9104
|
// src/lib/utils/videoPreloader.ts
|
|
@@ -9383,6 +9419,115 @@ var clearS3VideoCache = () => {
|
|
|
9383
9419
|
var preloadS3VideoUrl = s3VideoPreloader.preloadVideo;
|
|
9384
9420
|
var preloadS3VideosUrl = s3VideoPreloader.preloadVideos;
|
|
9385
9421
|
|
|
9422
|
+
// src/lib/utils/dashboardReload.ts
|
|
9423
|
+
var reloadAttempts = [];
|
|
9424
|
+
var createThrottledReload = (interval = 5e3, maxReloads = 3) => {
|
|
9425
|
+
const circuitBreakerWindow = 1e4;
|
|
9426
|
+
const circuitBreakerThreshold = 5;
|
|
9427
|
+
let last = 0;
|
|
9428
|
+
let queued = false;
|
|
9429
|
+
let reloadCount = 0;
|
|
9430
|
+
let firstReloadTime = 0;
|
|
9431
|
+
const resetWindow = 6e4;
|
|
9432
|
+
const doReload = () => {
|
|
9433
|
+
if (typeof window !== "undefined") {
|
|
9434
|
+
const now2 = Date.now();
|
|
9435
|
+
reloadAttempts.push(now2);
|
|
9436
|
+
const cutoff = now2 - circuitBreakerWindow;
|
|
9437
|
+
const recentAttempts = reloadAttempts.filter((t) => t > cutoff);
|
|
9438
|
+
reloadAttempts.length = 0;
|
|
9439
|
+
reloadAttempts.push(...recentAttempts);
|
|
9440
|
+
if (recentAttempts.length >= circuitBreakerThreshold) {
|
|
9441
|
+
console.error(`[Dashboard Reload] Circuit breaker triggered! ${recentAttempts.length} reload attempts in ${circuitBreakerWindow}ms`);
|
|
9442
|
+
const errorDiv = document.createElement("div");
|
|
9443
|
+
errorDiv.id = "reload-circuit-breaker";
|
|
9444
|
+
errorDiv.style.cssText = `
|
|
9445
|
+
position: fixed;
|
|
9446
|
+
top: 20px;
|
|
9447
|
+
left: 50%;
|
|
9448
|
+
transform: translateX(-50%);
|
|
9449
|
+
background: #dc2626;
|
|
9450
|
+
color: white;
|
|
9451
|
+
padding: 20px 32px;
|
|
9452
|
+
border-radius: 12px;
|
|
9453
|
+
z-index: 99999;
|
|
9454
|
+
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3);
|
|
9455
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
9456
|
+
`;
|
|
9457
|
+
errorDiv.innerHTML = `
|
|
9458
|
+
<div style="display: flex; align-items: center; gap: 16px;">
|
|
9459
|
+
<svg width="24" height="24" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
9460
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path>
|
|
9461
|
+
</svg>
|
|
9462
|
+
<div>
|
|
9463
|
+
<div style="font-weight: 600; font-size: 16px; margin-bottom: 4px;">Too many reload attempts detected</div>
|
|
9464
|
+
<div style="font-size: 14px; opacity: 0.9;">Please check your network connection and refresh manually.</div>
|
|
9465
|
+
</div>
|
|
9466
|
+
</div>
|
|
9467
|
+
`;
|
|
9468
|
+
const existing = document.getElementById("reload-circuit-breaker");
|
|
9469
|
+
if (existing) existing.remove();
|
|
9470
|
+
document.body.appendChild(errorDiv);
|
|
9471
|
+
return;
|
|
9472
|
+
}
|
|
9473
|
+
if (now2 - firstReloadTime > resetWindow) {
|
|
9474
|
+
reloadCount = 0;
|
|
9475
|
+
firstReloadTime = now2;
|
|
9476
|
+
}
|
|
9477
|
+
if (reloadCount === 0) {
|
|
9478
|
+
firstReloadTime = now2;
|
|
9479
|
+
}
|
|
9480
|
+
reloadCount++;
|
|
9481
|
+
if (reloadCount > maxReloads) {
|
|
9482
|
+
console.error(`[Dashboard Reload] Maximum reload attempts (${maxReloads}) reached. Stopping to prevent infinite loop.`);
|
|
9483
|
+
const errorDiv = document.createElement("div");
|
|
9484
|
+
errorDiv.style.cssText = `
|
|
9485
|
+
position: fixed;
|
|
9486
|
+
top: 20px;
|
|
9487
|
+
left: 50%;
|
|
9488
|
+
transform: translateX(-50%);
|
|
9489
|
+
background: #ef4444;
|
|
9490
|
+
color: white;
|
|
9491
|
+
padding: 16px 24px;
|
|
9492
|
+
border-radius: 8px;
|
|
9493
|
+
z-index: 9999;
|
|
9494
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
9495
|
+
`;
|
|
9496
|
+
errorDiv.innerHTML = `
|
|
9497
|
+
<div style="display: flex; align-items: center; gap: 12px;">
|
|
9498
|
+
<svg width="20" height="20" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
9499
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
|
9500
|
+
</svg>
|
|
9501
|
+
<span>Stream connection failed. Please refresh the page manually.</span>
|
|
9502
|
+
</div>
|
|
9503
|
+
`;
|
|
9504
|
+
document.body.appendChild(errorDiv);
|
|
9505
|
+
setTimeout(() => {
|
|
9506
|
+
document.body.removeChild(errorDiv);
|
|
9507
|
+
}, 1e4);
|
|
9508
|
+
return;
|
|
9509
|
+
}
|
|
9510
|
+
console.warn(`[Dashboard Reload] Reloading dashboard (attempt ${reloadCount}/${maxReloads})`);
|
|
9511
|
+
window.location.reload();
|
|
9512
|
+
}
|
|
9513
|
+
};
|
|
9514
|
+
return () => {
|
|
9515
|
+
const now2 = Date.now();
|
|
9516
|
+
if (now2 - last >= interval) {
|
|
9517
|
+
last = now2;
|
|
9518
|
+
doReload();
|
|
9519
|
+
} else if (!queued) {
|
|
9520
|
+
queued = true;
|
|
9521
|
+
setTimeout(() => {
|
|
9522
|
+
queued = false;
|
|
9523
|
+
last = Date.now();
|
|
9524
|
+
doReload();
|
|
9525
|
+
}, interval - (now2 - last));
|
|
9526
|
+
}
|
|
9527
|
+
};
|
|
9528
|
+
};
|
|
9529
|
+
var throttledReloadDashboard = createThrottledReload(5e3, 3);
|
|
9530
|
+
|
|
9386
9531
|
// src/lib/utils/index.ts
|
|
9387
9532
|
var formatIdleTime = (idleTimeInSeconds) => {
|
|
9388
9533
|
if (!idleTimeInSeconds || idleTimeInSeconds <= 0) {
|
|
@@ -18669,6 +18814,7 @@ var VideoGridView = React19__namespace.default.memo(({
|
|
|
18669
18814
|
const [gridRows, setGridRows] = React19.useState(1);
|
|
18670
18815
|
const [visibleWorkspaces, setVisibleWorkspaces] = React19.useState(/* @__PURE__ */ new Set());
|
|
18671
18816
|
const [cardDimensions, setCardDimensions] = React19.useState({ width: 0, height: 0 });
|
|
18817
|
+
const [failedStreams, setFailedStreams] = React19.useState(/* @__PURE__ */ new Set());
|
|
18672
18818
|
const videoConfig = useVideoConfig();
|
|
18673
18819
|
const { cropping, canvasConfig, hlsUrls } = videoConfig;
|
|
18674
18820
|
const mergedVideoSources = {
|
|
@@ -18820,9 +18966,17 @@ var VideoGridView = React19__namespace.default.memo(({
|
|
|
18820
18966
|
action_count: workspace.action_count
|
|
18821
18967
|
});
|
|
18822
18968
|
const displayName = getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
|
|
18823
|
-
const navParams = getWorkspaceNavigationParams(workspaceId, displayName);
|
|
18969
|
+
const navParams = getWorkspaceNavigationParams(workspaceId, displayName, workspace.line_id);
|
|
18824
18970
|
router$1.push(`/workspace/${workspaceId}${navParams}`);
|
|
18825
18971
|
}, [router$1]);
|
|
18972
|
+
const handleStreamError = React19.useCallback((workspaceId) => {
|
|
18973
|
+
console.error(`[VideoGridView] Stream failed for workspace: ${workspaceId}`);
|
|
18974
|
+
setFailedStreams((prev) => new Set(prev).add(workspaceId));
|
|
18975
|
+
trackCoreEvent("Video Stream Error", {
|
|
18976
|
+
workspace_id: workspaceId,
|
|
18977
|
+
view_type: "video_grid"
|
|
18978
|
+
});
|
|
18979
|
+
}, []);
|
|
18826
18980
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `relative overflow-hidden h-full w-full ${className}`, children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, className: "h-full w-full p-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
18827
18981
|
"div",
|
|
18828
18982
|
{
|
|
@@ -18859,9 +19013,9 @@ var VideoGridView = React19__namespace.default.memo(({
|
|
|
18859
19013
|
{
|
|
18860
19014
|
workspace,
|
|
18861
19015
|
hlsUrl: getWorkspaceHlsUrl(workspace.workspace_name, workspace.line_id),
|
|
18862
|
-
shouldPlay: isVisible,
|
|
19016
|
+
shouldPlay: isVisible && !failedStreams.has(workspaceId),
|
|
18863
19017
|
onClick: () => handleWorkspaceClick(workspace),
|
|
18864
|
-
onFatalError:
|
|
19018
|
+
onFatalError: () => handleStreamError(workspaceId),
|
|
18865
19019
|
isVeryLowEfficiency,
|
|
18866
19020
|
cropping: workspaceCropping,
|
|
18867
19021
|
canvasFps: canvasConfig?.fps,
|
|
@@ -24028,7 +24182,7 @@ var WorkspaceGridItem = React19__namespace.default.memo(({
|
|
|
24028
24182
|
e.preventDefault();
|
|
24029
24183
|
if (isInactive) return;
|
|
24030
24184
|
const displayName = getWorkspaceDisplayName(data.workspace_name, data.line_id);
|
|
24031
|
-
const navParams = getWorkspaceNavigationParams(data.workspace_id, displayName);
|
|
24185
|
+
const navParams = getWorkspaceNavigationParams(data.workspace_id, displayName, data.line_id);
|
|
24032
24186
|
navigate(`/workspace/${data.workspace_id}${navParams}`, {
|
|
24033
24187
|
trackingEvent: {
|
|
24034
24188
|
name: "Workspace Detail Clicked",
|
|
@@ -28769,6 +28923,73 @@ function HomeView({
|
|
|
28769
28923
|
}
|
|
28770
28924
|
var AuthenticatedHomeView = withAuth(React19__namespace.default.memo(HomeView));
|
|
28771
28925
|
var HomeView_default = HomeView;
|
|
28926
|
+
function withWorkspaceDisplayNames(Component3, options = {}) {
|
|
28927
|
+
const {
|
|
28928
|
+
showLoading = true,
|
|
28929
|
+
loadingMessage = "Initializing workspace data...",
|
|
28930
|
+
initializeFor = "all"
|
|
28931
|
+
} = options;
|
|
28932
|
+
return function WithWorkspaceDisplayNamesWrapper(props) {
|
|
28933
|
+
const [isInitialized2, setIsInitialized] = React19.useState(false);
|
|
28934
|
+
const [error, setError] = React19.useState(null);
|
|
28935
|
+
React19.useEffect(() => {
|
|
28936
|
+
setIsInitialized(false);
|
|
28937
|
+
setError(null);
|
|
28938
|
+
const initializeDisplayNames = async () => {
|
|
28939
|
+
try {
|
|
28940
|
+
const { lineIds, selectedLineId, factoryViewId } = props;
|
|
28941
|
+
let lineIdArray = [];
|
|
28942
|
+
if (Array.isArray(lineIds)) {
|
|
28943
|
+
lineIdArray = lineIds;
|
|
28944
|
+
} else if (lineIds && typeof lineIds === "object") {
|
|
28945
|
+
lineIdArray = Object.values(lineIds).filter((id3) => !!id3);
|
|
28946
|
+
}
|
|
28947
|
+
if (initializeFor === "specific" && selectedLineId) {
|
|
28948
|
+
if (selectedLineId === factoryViewId && lineIdArray.length > 0) {
|
|
28949
|
+
await Promise.all(
|
|
28950
|
+
lineIdArray.map((lineId) => preInitializeWorkspaceDisplayNames(lineId))
|
|
28951
|
+
);
|
|
28952
|
+
} else {
|
|
28953
|
+
await preInitializeWorkspaceDisplayNames(selectedLineId);
|
|
28954
|
+
}
|
|
28955
|
+
} else if (lineIdArray.length > 0) {
|
|
28956
|
+
await Promise.all(
|
|
28957
|
+
lineIdArray.map((lineId) => preInitializeWorkspaceDisplayNames(lineId))
|
|
28958
|
+
);
|
|
28959
|
+
} else {
|
|
28960
|
+
await preInitializeWorkspaceDisplayNames();
|
|
28961
|
+
}
|
|
28962
|
+
setIsInitialized(true);
|
|
28963
|
+
} catch (err) {
|
|
28964
|
+
console.error("Failed to initialize workspace display names:", err);
|
|
28965
|
+
setError(err);
|
|
28966
|
+
setIsInitialized(true);
|
|
28967
|
+
}
|
|
28968
|
+
};
|
|
28969
|
+
initializeDisplayNames();
|
|
28970
|
+
}, [
|
|
28971
|
+
Array.isArray(props.lineIds) ? props.lineIds.join(",") : JSON.stringify(props.lineIds),
|
|
28972
|
+
props.selectedLineId,
|
|
28973
|
+
props.factoryViewId,
|
|
28974
|
+
initializeFor
|
|
28975
|
+
]);
|
|
28976
|
+
if (!isInitialized2 && showLoading) {
|
|
28977
|
+
return /* @__PURE__ */ jsxRuntime.jsx(LoadingPage, { message: loadingMessage });
|
|
28978
|
+
}
|
|
28979
|
+
if (error && showLoading) {
|
|
28980
|
+
console.warn("Workspace display names initialization failed, proceeding anyway:", error);
|
|
28981
|
+
}
|
|
28982
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Component3, { ...props });
|
|
28983
|
+
};
|
|
28984
|
+
}
|
|
28985
|
+
var withAllWorkspaceDisplayNames = (Component3) => withWorkspaceDisplayNames(Component3, {
|
|
28986
|
+
initializeFor: "all",
|
|
28987
|
+
showLoading: true
|
|
28988
|
+
});
|
|
28989
|
+
var withSelectedLineDisplayNames = (Component3) => withWorkspaceDisplayNames(Component3, {
|
|
28990
|
+
initializeFor: "specific",
|
|
28991
|
+
showLoading: true
|
|
28992
|
+
});
|
|
28772
28993
|
|
|
28773
28994
|
// src/views/kpi-detail-view.types.ts
|
|
28774
28995
|
var pageVariants = {
|
|
@@ -28829,11 +29050,6 @@ var itemVariants = {
|
|
|
28829
29050
|
}
|
|
28830
29051
|
}
|
|
28831
29052
|
};
|
|
28832
|
-
|
|
28833
|
-
// src/lib/utils/navigation.ts
|
|
28834
|
-
function getWorkspaceNavigationParams2(workspaceUuid, displayName) {
|
|
28835
|
-
return `?name=${encodeURIComponent(displayName || "")}`;
|
|
28836
|
-
}
|
|
28837
29053
|
var formatLocalDate = (date) => {
|
|
28838
29054
|
const options = {
|
|
28839
29055
|
year: "numeric",
|
|
@@ -28949,7 +29165,7 @@ var BottomSection = React19.memo(({
|
|
|
28949
29165
|
}
|
|
28950
29166
|
const clickHandler = () => handleWorkspaceClick(ws, index);
|
|
28951
29167
|
const displayName = getWorkspaceDisplayName(ws.workspace_name, lineId);
|
|
28952
|
-
const navParams = wsUuid ?
|
|
29168
|
+
const navParams = wsUuid ? getWorkspaceNavigationParams(wsUuid, displayName, lineId) : "";
|
|
28953
29169
|
const dateShiftParams = urlDate ? `&date=${urlDate}&shift=${urlShift || "0"}` : "";
|
|
28954
29170
|
const returnToParam = `&returnTo=${encodeURIComponent(`/kpis/${lineInfo?.line_id}`)}`;
|
|
28955
29171
|
const fullUrl = `/workspace/${wsUuid}${navParams}${dateShiftParams}${returnToParam}`;
|
|
@@ -28983,7 +29199,7 @@ var BottomSection = React19.memo(({
|
|
|
28983
29199
|
sortedByEfficiency.map((ws, index) => {
|
|
28984
29200
|
const clickHandler = () => handleWorkspaceClick(ws, index);
|
|
28985
29201
|
const displayName = getWorkspaceDisplayName(ws.workspace_name, lineId);
|
|
28986
|
-
const navParams = ws.workspace_uuid ?
|
|
29202
|
+
const navParams = ws.workspace_uuid ? getWorkspaceNavigationParams(ws.workspace_uuid, displayName, lineId) : "";
|
|
28987
29203
|
const dateShiftParams = urlDate ? `&date=${urlDate}&shift=${urlShift || "0"}` : "";
|
|
28988
29204
|
const returnToParam = `&returnTo=${encodeURIComponent(`/kpis/${lineInfo?.line_id}`)}`;
|
|
28989
29205
|
const fullUrl = `/workspace/${ws.workspace_uuid}${navParams}${dateShiftParams}${returnToParam}`;
|
|
@@ -29598,7 +29814,8 @@ var KPIDetailView = ({
|
|
|
29598
29814
|
) }) })
|
|
29599
29815
|
] });
|
|
29600
29816
|
};
|
|
29601
|
-
var
|
|
29817
|
+
var KPIDetailViewWithDisplayNames = withSelectedLineDisplayNames(KPIDetailView);
|
|
29818
|
+
var KPIDetailView_default = KPIDetailViewWithDisplayNames;
|
|
29602
29819
|
var LineCard = ({ line, onClick }) => {
|
|
29603
29820
|
const { kpis, isLoading, error } = useLineKPIs({ lineId: line.id });
|
|
29604
29821
|
const isOnTrack = React19__namespace.default.useMemo(() => {
|
|
@@ -30088,7 +30305,7 @@ var LeaderboardDetailView = React19.memo(({
|
|
|
30088
30305
|
action_threshold: workspace.action_threshold
|
|
30089
30306
|
});
|
|
30090
30307
|
const displayName = getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
|
|
30091
|
-
const navParams = workspace.workspace_uuid ? getWorkspaceNavigationParams(workspace.workspace_uuid, displayName) : "";
|
|
30308
|
+
const navParams = workspace.workspace_uuid ? getWorkspaceNavigationParams(workspace.workspace_uuid, displayName, workspace.line_id) : "";
|
|
30092
30309
|
const returnToParam = `&returnTo=${encodeURIComponent(`/leaderboard`)}`;
|
|
30093
30310
|
if (onWorkspaceClick) {
|
|
30094
30311
|
onWorkspaceClick(workspace, rank);
|
|
@@ -30222,7 +30439,8 @@ var LeaderboardDetailView = React19.memo(({
|
|
|
30222
30439
|
return prevProps.lineId === nextProps.lineId && prevProps.date === nextProps.date && prevProps.shift === nextProps.shift && prevProps.line1Id === nextProps.line1Id && prevProps.line2Id === nextProps.line2Id && JSON.stringify(prevProps.lineNames) === JSON.stringify(nextProps.lineNames) && prevProps.className === nextProps.className && prevProps.onBackClick === nextProps.onBackClick && prevProps.onWorkspaceClick === nextProps.onWorkspaceClick;
|
|
30223
30440
|
});
|
|
30224
30441
|
LeaderboardDetailView.displayName = "LeaderboardDetailView";
|
|
30225
|
-
var
|
|
30442
|
+
var LeaderboardDetailViewWithDisplayNames = withAllWorkspaceDisplayNames(LeaderboardDetailView);
|
|
30443
|
+
var LeaderboardDetailView_default = LeaderboardDetailViewWithDisplayNames;
|
|
30226
30444
|
function LoginView({
|
|
30227
30445
|
logoSrc = "/optifye-logo.png",
|
|
30228
30446
|
logoAlt = "Optifye",
|
|
@@ -32342,7 +32560,12 @@ var TargetsView = ({
|
|
|
32342
32560
|
}
|
|
32343
32561
|
}), {});
|
|
32344
32562
|
}, [lineIds]);
|
|
32345
|
-
const [
|
|
32563
|
+
const [allShiftsData, setAllShiftsData] = React19.useState({
|
|
32564
|
+
0: initialLineWorkspaces,
|
|
32565
|
+
// Day shift
|
|
32566
|
+
1: initialLineWorkspaces
|
|
32567
|
+
// Night shift (will be populated on first load)
|
|
32568
|
+
});
|
|
32346
32569
|
const [actionIds, setActionIds] = React19.useState(null);
|
|
32347
32570
|
const [savingLines, setSavingLines] = React19.useState(
|
|
32348
32571
|
() => lineIds.reduce((acc, id3) => ({ ...acc, [id3]: false }), {})
|
|
@@ -32354,6 +32577,13 @@ var TargetsView = ({
|
|
|
32354
32577
|
const [isBulkConfigureOpen, setIsBulkConfigureOpen] = React19.useState(false);
|
|
32355
32578
|
const [selectedWorkspaces, setSelectedWorkspaces] = React19.useState([]);
|
|
32356
32579
|
const [selectedShift, setSelectedShift] = React19.useState(0);
|
|
32580
|
+
const lineWorkspaces = allShiftsData[selectedShift] || initialLineWorkspaces;
|
|
32581
|
+
const setLineWorkspaces = React19.useCallback((updater) => {
|
|
32582
|
+
setAllShiftsData((prev) => ({
|
|
32583
|
+
...prev,
|
|
32584
|
+
[selectedShift]: typeof updater === "function" ? updater(prev[selectedShift]) : updater
|
|
32585
|
+
}));
|
|
32586
|
+
}, [selectedShift]);
|
|
32357
32587
|
const supabase = useSupabase();
|
|
32358
32588
|
const auth = useAuth();
|
|
32359
32589
|
userId || auth?.user?.id;
|
|
@@ -32361,70 +32591,120 @@ var TargetsView = ({
|
|
|
32361
32591
|
const { skus, isLoading: skusLoading } = useSKUs(companyId);
|
|
32362
32592
|
const skuEnabled = dashboardConfig?.skuConfig?.enabled || false;
|
|
32363
32593
|
React19.useEffect(() => {
|
|
32364
|
-
|
|
32594
|
+
let timeoutId;
|
|
32595
|
+
let retryCount = 0;
|
|
32596
|
+
const MAX_RETRIES2 = 2;
|
|
32597
|
+
const LOADING_TIMEOUT = 15e3;
|
|
32598
|
+
const fetchInitialData = async () => {
|
|
32365
32599
|
if (!supabase || lineIds.length === 0) return;
|
|
32366
|
-
|
|
32367
|
-
|
|
32368
|
-
|
|
32369
|
-
|
|
32370
|
-
|
|
32371
|
-
|
|
32372
|
-
|
|
32373
|
-
|
|
32374
|
-
}
|
|
32375
|
-
|
|
32376
|
-
|
|
32600
|
+
setIsLoading(true);
|
|
32601
|
+
timeoutId = setTimeout(() => {
|
|
32602
|
+
console.error("Loading timeout reached");
|
|
32603
|
+
if (retryCount < MAX_RETRIES2) {
|
|
32604
|
+
retryCount++;
|
|
32605
|
+
console.log(`Retrying... (attempt ${retryCount + 1}/${MAX_RETRIES2 + 1})`);
|
|
32606
|
+
sonner.toast.warning("Loading is taking longer than expected. Retrying...");
|
|
32607
|
+
fetchInitialData();
|
|
32608
|
+
} else {
|
|
32609
|
+
setIsLoading(false);
|
|
32610
|
+
sonner.toast.error("Failed to load data. Please refresh the page.");
|
|
32377
32611
|
}
|
|
32378
|
-
});
|
|
32379
|
-
const results = await Promise.all(detailsPromises);
|
|
32380
|
-
setLineWorkspaces((prev) => {
|
|
32381
|
-
const newWorkspaces = { ...prev };
|
|
32382
|
-
let needsUpdate = false;
|
|
32383
|
-
results.forEach((result) => {
|
|
32384
|
-
if (result.factoryId && newWorkspaces[result.lineId] && newWorkspaces[result.lineId].factoryId !== result.factoryId) {
|
|
32385
|
-
newWorkspaces[result.lineId].factoryId = result.factoryId;
|
|
32386
|
-
needsUpdate = true;
|
|
32387
|
-
}
|
|
32388
|
-
});
|
|
32389
|
-
return needsUpdate ? newWorkspaces : prev;
|
|
32390
|
-
});
|
|
32391
|
-
};
|
|
32392
|
-
fetchLineDetails();
|
|
32393
|
-
}, [supabase, lineIds]);
|
|
32394
|
-
React19.useEffect(() => {
|
|
32395
|
-
const fetchActions = async () => {
|
|
32396
|
-
if (!supabase) {
|
|
32397
|
-
console.error("Supabase client not available in fetchActions");
|
|
32398
|
-
sonner.toast.error("Initialization error, please refresh.");
|
|
32399
|
-
return;
|
|
32400
|
-
}
|
|
32612
|
+
}, LOADING_TIMEOUT);
|
|
32401
32613
|
try {
|
|
32402
|
-
const actions = await
|
|
32403
|
-
|
|
32404
|
-
|
|
32405
|
-
|
|
32614
|
+
const [factoryResults, actions] = await Promise.all([
|
|
32615
|
+
// Fetch factory IDs
|
|
32616
|
+
Promise.all(lineIds.map(async (lineId) => {
|
|
32617
|
+
try {
|
|
32618
|
+
const { data, error } = await supabase.from("lines").select("factory_id").eq("id", lineId).single();
|
|
32619
|
+
if (error) {
|
|
32620
|
+
console.error(`Error fetching factory_id for line ${lineId}:`, error);
|
|
32621
|
+
return { lineId, factoryId: void 0 };
|
|
32622
|
+
}
|
|
32623
|
+
return { lineId, factoryId: data?.factory_id };
|
|
32624
|
+
} catch (err) {
|
|
32625
|
+
console.error(`Exception fetching factory_id for line ${lineId}:`, err);
|
|
32626
|
+
return { lineId, factoryId: void 0 };
|
|
32627
|
+
}
|
|
32628
|
+
})),
|
|
32629
|
+
// Fetch action IDs
|
|
32630
|
+
actionService.getActionsByName(
|
|
32631
|
+
[ACTION_NAMES.ASSEMBLY, ACTION_NAMES.PACKAGING],
|
|
32632
|
+
companyId
|
|
32633
|
+
)
|
|
32634
|
+
]);
|
|
32406
32635
|
const assemblyAction = actions.find((a) => a.action_name === ACTION_NAMES.ASSEMBLY);
|
|
32407
32636
|
const packagingAction = actions.find((a) => a.action_name === ACTION_NAMES.PACKAGING);
|
|
32408
32637
|
if (!assemblyAction || !packagingAction) {
|
|
32409
32638
|
throw new Error("Could not find required actions");
|
|
32410
32639
|
}
|
|
32411
|
-
const
|
|
32640
|
+
const actionIdsData = {
|
|
32412
32641
|
assembly: assemblyAction.id,
|
|
32413
32642
|
packaging: packagingAction.id
|
|
32414
32643
|
};
|
|
32415
|
-
|
|
32416
|
-
|
|
32417
|
-
|
|
32644
|
+
setActionIds(actionIdsData);
|
|
32645
|
+
const updatedLineWorkspaces = { ...initialLineWorkspaces };
|
|
32646
|
+
factoryResults.forEach((result) => {
|
|
32647
|
+
if (result.factoryId && updatedLineWorkspaces[result.lineId]) {
|
|
32648
|
+
updatedLineWorkspaces[result.lineId].factoryId = result.factoryId;
|
|
32649
|
+
}
|
|
32418
32650
|
});
|
|
32419
|
-
|
|
32651
|
+
const currentDate = getOperationalDate();
|
|
32652
|
+
for (const lineId of lineIds) {
|
|
32653
|
+
if (!updatedLineWorkspaces[lineId]?.factoryId) {
|
|
32654
|
+
console.warn(`Skipping workspace fetch for line ${lineId} - no factory ID`);
|
|
32655
|
+
continue;
|
|
32656
|
+
}
|
|
32657
|
+
try {
|
|
32658
|
+
const workspacesData = await workspaceService.getWorkspaces(lineId);
|
|
32659
|
+
const actionThresholds = await workspaceService.getActionThresholds(
|
|
32660
|
+
lineId,
|
|
32661
|
+
currentDate,
|
|
32662
|
+
selectedShift
|
|
32663
|
+
);
|
|
32664
|
+
const mappedWorkspaces = workspacesData.map((ws) => {
|
|
32665
|
+
const threshold = actionThresholds.find((t) => t.workspace_id === ws.id);
|
|
32666
|
+
return {
|
|
32667
|
+
id: ws.id,
|
|
32668
|
+
name: ws.workspace_id,
|
|
32669
|
+
targetPPH: threshold?.pph_threshold ?? (ws.action_pph_threshold === null ? "" : ws.action_pph_threshold),
|
|
32670
|
+
targetCycleTime: threshold?.ideal_cycle_time ?? (ws.action_cycle_time === null ? "" : ws.action_cycle_time),
|
|
32671
|
+
targetDayOutput: threshold?.total_day_output ?? (ws.action_total_day_output === null ? "" : ws.action_total_day_output),
|
|
32672
|
+
actionType: ws.action_id === actionIdsData.assembly ? "assembly" : ws.action_id === actionIdsData.packaging ? "packaging" : "assembly",
|
|
32673
|
+
actionId: ws.action_id === actionIdsData.assembly ? actionIdsData.assembly : ws.action_id === actionIdsData.packaging ? actionIdsData.packaging : actionIdsData.assembly
|
|
32674
|
+
};
|
|
32675
|
+
}).sort((a, b) => a.name.localeCompare(b.name, void 0, { numeric: true }));
|
|
32676
|
+
updatedLineWorkspaces[lineId].workspaces = mappedWorkspaces;
|
|
32677
|
+
} catch (error) {
|
|
32678
|
+
console.error(`Error fetching workspace data for line ${lineId}:`, error);
|
|
32679
|
+
}
|
|
32680
|
+
}
|
|
32681
|
+
setLineWorkspaces(updatedLineWorkspaces);
|
|
32682
|
+
await fetchAllShiftsData(updatedLineWorkspaces);
|
|
32420
32683
|
} catch (error) {
|
|
32421
|
-
console.error("Error fetching
|
|
32422
|
-
|
|
32684
|
+
console.error("Error fetching initial data:", error);
|
|
32685
|
+
clearTimeout(timeoutId);
|
|
32686
|
+
if (retryCount < MAX_RETRIES2) {
|
|
32687
|
+
retryCount++;
|
|
32688
|
+
console.log(`Error occurred, retrying... (attempt ${retryCount + 1}/${MAX_RETRIES2 + 1})`);
|
|
32689
|
+
sonner.toast.warning("Error loading data. Retrying...");
|
|
32690
|
+
setTimeout(() => fetchInitialData(), 1e3);
|
|
32691
|
+
} else {
|
|
32692
|
+
sonner.toast.error("Failed to load initial data");
|
|
32693
|
+
setIsLoading(false);
|
|
32694
|
+
}
|
|
32695
|
+
} finally {
|
|
32696
|
+
clearTimeout(timeoutId);
|
|
32697
|
+
if (retryCount === 0 || retryCount >= MAX_RETRIES2) {
|
|
32698
|
+
setIsLoading(false);
|
|
32699
|
+
}
|
|
32423
32700
|
}
|
|
32424
32701
|
};
|
|
32425
|
-
|
|
32426
|
-
|
|
32427
|
-
|
|
32702
|
+
fetchInitialData();
|
|
32703
|
+
return () => {
|
|
32704
|
+
clearTimeout(timeoutId);
|
|
32705
|
+
};
|
|
32706
|
+
}, [supabase, lineIds, companyId]);
|
|
32707
|
+
React19.useCallback(async (shiftId) => {
|
|
32428
32708
|
try {
|
|
32429
32709
|
if (!supabase) return;
|
|
32430
32710
|
const currentDate = getOperationalDate();
|
|
@@ -32492,15 +32772,7 @@ var TargetsView = ({
|
|
|
32492
32772
|
shiftEndTime: endTime,
|
|
32493
32773
|
breaks,
|
|
32494
32774
|
shiftHours: Number(shiftHours),
|
|
32495
|
-
workspaces:
|
|
32496
|
-
...ws,
|
|
32497
|
-
targetPPH: ws.targetCycleTime !== "" ? calculatePPH(ws.targetCycleTime, breaks, Number(shiftHours)) : ws.targetPPH,
|
|
32498
|
-
targetDayOutput: calculateDayOutput(
|
|
32499
|
-
ws.targetCycleTime !== "" ? calculatePPH(ws.targetCycleTime, breaks, Number(shiftHours)) : ws.targetPPH,
|
|
32500
|
-
Number(shiftHours),
|
|
32501
|
-
breaks
|
|
32502
|
-
)
|
|
32503
|
-
}))
|
|
32775
|
+
workspaces: currentLineStateFromLoop?.workspaces || []
|
|
32504
32776
|
};
|
|
32505
32777
|
hasUpdates = true;
|
|
32506
32778
|
}
|
|
@@ -32514,7 +32786,71 @@ var TargetsView = ({
|
|
|
32514
32786
|
} catch (error) {
|
|
32515
32787
|
console.error("Error in fetchLineThresholds outer try-catch:", error);
|
|
32516
32788
|
}
|
|
32517
|
-
}, [selectedShift, supabase, lineIds, lineWorkspaces]);
|
|
32789
|
+
}, [selectedShift, supabase, lineIds, lineWorkspaces, allShiftsData]);
|
|
32790
|
+
const fetchAllShiftsData = React19.useCallback(async (currentWorkspaces) => {
|
|
32791
|
+
if (!supabase) return;
|
|
32792
|
+
const currentDate = getOperationalDate();
|
|
32793
|
+
const newAllShiftsData = {
|
|
32794
|
+
0: JSON.parse(JSON.stringify(currentWorkspaces)),
|
|
32795
|
+
// Deep clone for day shift
|
|
32796
|
+
1: JSON.parse(JSON.stringify(currentWorkspaces))
|
|
32797
|
+
// Deep clone for night shift
|
|
32798
|
+
};
|
|
32799
|
+
for (const shiftId of [0, 1]) {
|
|
32800
|
+
for (const lineId of lineIds) {
|
|
32801
|
+
try {
|
|
32802
|
+
const { data: operatingHours, error: hoursError } = await supabase.from("line_operating_hours").select("start_time, end_time, breaks").eq("line_id", lineId).eq("shift_id", shiftId).maybeSingle();
|
|
32803
|
+
if (hoursError) {
|
|
32804
|
+
console.error(`Error fetching operating hours for line ${lineId}, shift ${shiftId}:`, hoursError);
|
|
32805
|
+
continue;
|
|
32806
|
+
}
|
|
32807
|
+
let breaks = [];
|
|
32808
|
+
if (operatingHours?.breaks) {
|
|
32809
|
+
if (Array.isArray(operatingHours.breaks)) {
|
|
32810
|
+
breaks = operatingHours.breaks.map((breakItem) => ({
|
|
32811
|
+
startTime: breakItem.start || breakItem.startTime || "00:00",
|
|
32812
|
+
endTime: breakItem.end || breakItem.endTime || "00:00",
|
|
32813
|
+
duration: breakItem.duration || calculateShiftHours2(breakItem.start || breakItem.startTime || "00:00", breakItem.end || breakItem.endTime || "00:00", []) * 60
|
|
32814
|
+
}));
|
|
32815
|
+
}
|
|
32816
|
+
}
|
|
32817
|
+
const startTime = operatingHours?.start_time || "08:00";
|
|
32818
|
+
const endTime = operatingHours?.end_time || "19:00";
|
|
32819
|
+
const shiftHours = calculateShiftHours2(startTime, endTime, breaks);
|
|
32820
|
+
const actionThresholds = await workspaceService.getActionThresholds(
|
|
32821
|
+
lineId,
|
|
32822
|
+
currentDate,
|
|
32823
|
+
shiftId
|
|
32824
|
+
);
|
|
32825
|
+
const existingLine = newAllShiftsData[shiftId][lineId];
|
|
32826
|
+
if (existingLine) {
|
|
32827
|
+
newAllShiftsData[shiftId][lineId] = {
|
|
32828
|
+
...existingLine,
|
|
32829
|
+
shiftStartTime: startTime,
|
|
32830
|
+
shiftEndTime: endTime,
|
|
32831
|
+
breaks,
|
|
32832
|
+
shiftHours: Number(shiftHours),
|
|
32833
|
+
workspaces: existingLine.workspaces.map((ws) => {
|
|
32834
|
+
const threshold = actionThresholds.find((t) => t.workspace_id === ws.id);
|
|
32835
|
+
if (threshold) {
|
|
32836
|
+
return {
|
|
32837
|
+
...ws,
|
|
32838
|
+
targetPPH: threshold.pph_threshold,
|
|
32839
|
+
targetCycleTime: threshold.ideal_cycle_time,
|
|
32840
|
+
targetDayOutput: threshold.total_day_output
|
|
32841
|
+
};
|
|
32842
|
+
}
|
|
32843
|
+
return ws;
|
|
32844
|
+
})
|
|
32845
|
+
};
|
|
32846
|
+
}
|
|
32847
|
+
} catch (error) {
|
|
32848
|
+
console.error(`Error fetching data for line ${lineId}, shift ${shiftId}:`, error);
|
|
32849
|
+
}
|
|
32850
|
+
}
|
|
32851
|
+
}
|
|
32852
|
+
setAllShiftsData(newAllShiftsData);
|
|
32853
|
+
}, [supabase, lineIds]);
|
|
32518
32854
|
const loadOperatingHours = React19.useCallback(async (lineId, shiftId) => {
|
|
32519
32855
|
try {
|
|
32520
32856
|
if (!supabase) return null;
|
|
@@ -32610,99 +32946,6 @@ var TargetsView = ({
|
|
|
32610
32946
|
};
|
|
32611
32947
|
}
|
|
32612
32948
|
}, [supabase]);
|
|
32613
|
-
React19.useEffect(() => {
|
|
32614
|
-
const allFactoryIdsLoaded = lineIds.every((lineId) => lineWorkspaces[lineId]?.factoryId);
|
|
32615
|
-
if (!actionIds || !allFactoryIdsLoaded) {
|
|
32616
|
-
return;
|
|
32617
|
-
}
|
|
32618
|
-
const workspacesAlreadyLoadedForAnyLine = Object.values(lineWorkspaces).some(
|
|
32619
|
-
(line) => line.workspaces && line.workspaces.length > 0
|
|
32620
|
-
);
|
|
32621
|
-
if (workspacesAlreadyLoadedForAnyLine) {
|
|
32622
|
-
fetchLineThresholds();
|
|
32623
|
-
return;
|
|
32624
|
-
}
|
|
32625
|
-
const fetchWorkspacesAndThenThresholds = async () => {
|
|
32626
|
-
setIsLoading(true);
|
|
32627
|
-
try {
|
|
32628
|
-
if (!supabase) {
|
|
32629
|
-
sonner.toast.error("Supabase client not available");
|
|
32630
|
-
setIsLoading(false);
|
|
32631
|
-
return;
|
|
32632
|
-
}
|
|
32633
|
-
console.log("Starting workspace fetch with actionIds and loaded factoryIds.");
|
|
32634
|
-
const newUpdatedLineWorkspaces = { ...lineWorkspaces };
|
|
32635
|
-
let workspacesHaveBeenUpdated = false;
|
|
32636
|
-
for (const lineId of lineIds) {
|
|
32637
|
-
if (!newUpdatedLineWorkspaces[lineId]?.factoryId) {
|
|
32638
|
-
console.warn(`FactoryId for line ${lineId} missing during workspace fetch. Skipping its workspaces.`);
|
|
32639
|
-
continue;
|
|
32640
|
-
}
|
|
32641
|
-
try {
|
|
32642
|
-
const fetchedLineWorkspacesData = await workspaceService.getWorkspaces(lineId);
|
|
32643
|
-
const mappedWorkspaces = fetchedLineWorkspacesData.map((ws) => ({
|
|
32644
|
-
id: ws.id,
|
|
32645
|
-
name: ws.workspace_id,
|
|
32646
|
-
targetPPH: ws.action_pph_threshold === null ? "" : ws.action_pph_threshold,
|
|
32647
|
-
targetCycleTime: ws.action_cycle_time === null ? "" : ws.action_cycle_time,
|
|
32648
|
-
targetDayOutput: ws.action_total_day_output === null ? "" : ws.action_total_day_output,
|
|
32649
|
-
actionType: ws.action_id === actionIds.assembly ? "assembly" : ws.action_id === actionIds.packaging ? "packaging" : "assembly",
|
|
32650
|
-
actionId: ws.action_id === actionIds.assembly ? actionIds.assembly : ws.action_id === actionIds.packaging ? actionIds.packaging : actionIds.assembly
|
|
32651
|
-
})).sort((a, b) => a.name.localeCompare(b.name, void 0, { numeric: true }));
|
|
32652
|
-
if (JSON.stringify(mappedWorkspaces) !== JSON.stringify(newUpdatedLineWorkspaces[lineId].workspaces)) {
|
|
32653
|
-
newUpdatedLineWorkspaces[lineId] = {
|
|
32654
|
-
...newUpdatedLineWorkspaces[lineId],
|
|
32655
|
-
workspaces: mappedWorkspaces
|
|
32656
|
-
};
|
|
32657
|
-
workspacesHaveBeenUpdated = true;
|
|
32658
|
-
}
|
|
32659
|
-
} catch (error) {
|
|
32660
|
-
console.error(`Error fetching workspaces for line ${lineId}:`, error);
|
|
32661
|
-
}
|
|
32662
|
-
}
|
|
32663
|
-
if (workspacesHaveBeenUpdated) {
|
|
32664
|
-
setLineWorkspaces(newUpdatedLineWorkspaces);
|
|
32665
|
-
}
|
|
32666
|
-
await fetchLineThresholds();
|
|
32667
|
-
} catch (error) {
|
|
32668
|
-
console.error("Error in fetchWorkspacesAndThenThresholds:", error);
|
|
32669
|
-
sonner.toast.error("Failed to load workspace data");
|
|
32670
|
-
} finally {
|
|
32671
|
-
setIsLoading(false);
|
|
32672
|
-
}
|
|
32673
|
-
};
|
|
32674
|
-
fetchWorkspacesAndThenThresholds();
|
|
32675
|
-
}, [actionIds, supabase, lineIds, lineWorkspaces, fetchLineThresholds]);
|
|
32676
|
-
React19.useEffect(() => {
|
|
32677
|
-
if (Object.keys(lineWorkspaces).length > 0) {
|
|
32678
|
-
const updatedLineWorkspaces = { ...lineWorkspaces };
|
|
32679
|
-
let hasChanges = false;
|
|
32680
|
-
Object.keys(updatedLineWorkspaces).forEach((lineId) => {
|
|
32681
|
-
const line = updatedLineWorkspaces[lineId];
|
|
32682
|
-
const shiftHours = calculateShiftHours2(line.shiftStartTime, line.shiftEndTime, line.breaks);
|
|
32683
|
-
if (shiftHours !== line.shiftHours) {
|
|
32684
|
-
hasChanges = true;
|
|
32685
|
-
updatedLineWorkspaces[lineId] = {
|
|
32686
|
-
...line,
|
|
32687
|
-
shiftHours,
|
|
32688
|
-
workspaces: line.workspaces.map((ws) => {
|
|
32689
|
-
const targetDayOutput = calculateDayOutput(ws.targetPPH, shiftHours, line.breaks);
|
|
32690
|
-
if (targetDayOutput !== ws.targetDayOutput) {
|
|
32691
|
-
return {
|
|
32692
|
-
...ws,
|
|
32693
|
-
targetDayOutput
|
|
32694
|
-
};
|
|
32695
|
-
}
|
|
32696
|
-
return ws;
|
|
32697
|
-
})
|
|
32698
|
-
};
|
|
32699
|
-
}
|
|
32700
|
-
});
|
|
32701
|
-
if (hasChanges) {
|
|
32702
|
-
setLineWorkspaces(updatedLineWorkspaces);
|
|
32703
|
-
}
|
|
32704
|
-
}
|
|
32705
|
-
}, [selectedShift]);
|
|
32706
32949
|
const toggleLineDropdown = React19.useCallback((lineId) => {
|
|
32707
32950
|
setLineWorkspaces((prev) => {
|
|
32708
32951
|
const newIsOpen = !prev[lineId].isOpen;
|
|
@@ -32786,6 +33029,16 @@ var TargetsView = ({
|
|
|
32786
33029
|
updates.targetDayOutput = calculateDayOutput(value, shiftHours, prev[lineId].breaks);
|
|
32787
33030
|
} else if (field === "targetDayOutput") {
|
|
32788
33031
|
updates.targetDayOutput = value;
|
|
33032
|
+
if (value !== "") {
|
|
33033
|
+
const breaks = prev[lineId].breaks;
|
|
33034
|
+
const totalBreakMinutes = breaks.reduce((total, b) => total + b.duration, 0);
|
|
33035
|
+
const totalBreakHours = totalBreakMinutes / 60;
|
|
33036
|
+
const realWorkHours = shiftHours - totalBreakHours;
|
|
33037
|
+
const calculatedPPH = Math.round(value / realWorkHours);
|
|
33038
|
+
updates.targetPPH = calculatedPPH;
|
|
33039
|
+
} else {
|
|
33040
|
+
updates.targetPPH = "";
|
|
33041
|
+
}
|
|
32789
33042
|
}
|
|
32790
33043
|
updates[field] = value;
|
|
32791
33044
|
return updates;
|
|
@@ -32919,14 +33172,15 @@ var TargetsView = ({
|
|
|
32919
33172
|
console.log(`[handleSaveLine] workspaceThresholdUpdates for ${lineId}:`, workspaceThresholdUpdates);
|
|
32920
33173
|
await workspaceService.updateActionThresholds(workspaceThresholdUpdates);
|
|
32921
33174
|
console.log(`[handleSaveLine] Successfully updated action thresholds for ${lineId}`);
|
|
33175
|
+
const packagingWorkspaces = lineDataToSave.workspaces.filter((ws) => ws.actionType === "packaging");
|
|
32922
33176
|
const lineThresholdData = {
|
|
32923
33177
|
factory_id: currentFactoryId,
|
|
32924
33178
|
line_id: lineId,
|
|
32925
33179
|
date: currentDate,
|
|
32926
33180
|
shift_id: selectedShift,
|
|
32927
33181
|
product_code: lineDataToSave.productId,
|
|
32928
|
-
threshold_day_output:
|
|
32929
|
-
threshold_pph:
|
|
33182
|
+
threshold_day_output: packagingWorkspaces.reduce((acc, ws) => acc + (Number(ws.targetDayOutput) || 0), 0),
|
|
33183
|
+
threshold_pph: packagingWorkspaces.reduce((acc, ws) => acc + (Number(ws.targetPPH) || 0), 0),
|
|
32930
33184
|
...skuEnabled && lineDataToSave.selectedSKU ? { sku_id: lineDataToSave.selectedSKU.id } : {}
|
|
32931
33185
|
};
|
|
32932
33186
|
console.log(`[handleSaveLine] lineThresholdData for upsert on ${lineId}:`, lineThresholdData);
|
|
@@ -33047,8 +33301,9 @@ var TargetsView = ({
|
|
|
33047
33301
|
}
|
|
33048
33302
|
);
|
|
33049
33303
|
};
|
|
33050
|
-
var
|
|
33051
|
-
var
|
|
33304
|
+
var TargetsViewWithDisplayNames = withAllWorkspaceDisplayNames(TargetsView);
|
|
33305
|
+
var TargetsView_default = TargetsViewWithDisplayNames;
|
|
33306
|
+
var AuthenticatedTargetsView = withAuth(TargetsViewWithDisplayNames);
|
|
33052
33307
|
|
|
33053
33308
|
// src/views/workspace-detail-view.utils.ts
|
|
33054
33309
|
var formatISTDate2 = (date = /* @__PURE__ */ new Date(), options) => {
|
|
@@ -33064,8 +33319,8 @@ var formatISTDate2 = (date = /* @__PURE__ */ new Date(), options) => {
|
|
|
33064
33319
|
});
|
|
33065
33320
|
return formatter.format(date);
|
|
33066
33321
|
};
|
|
33067
|
-
var formatWorkspaceName3 = (name) => {
|
|
33068
|
-
return getWorkspaceDisplayName(name);
|
|
33322
|
+
var formatWorkspaceName3 = (name, lineId) => {
|
|
33323
|
+
return getWorkspaceDisplayName(name, lineId);
|
|
33069
33324
|
};
|
|
33070
33325
|
var getDaysDifference = (date) => {
|
|
33071
33326
|
const today = /* @__PURE__ */ new Date();
|
|
@@ -33102,9 +33357,11 @@ var WorkspaceDetailView = ({
|
|
|
33102
33357
|
fromMonthly = false,
|
|
33103
33358
|
sourceType,
|
|
33104
33359
|
displayName,
|
|
33360
|
+
lineId,
|
|
33105
33361
|
defaultTab,
|
|
33106
33362
|
returnUrl,
|
|
33107
33363
|
lineIds = { line1: "", line2: "" },
|
|
33364
|
+
selectedLineId,
|
|
33108
33365
|
onNavigate,
|
|
33109
33366
|
onTabChange,
|
|
33110
33367
|
onDateSelect,
|
|
@@ -33267,7 +33524,8 @@ var WorkspaceDetailView = ({
|
|
|
33267
33524
|
setSelectedMonth(newMonth);
|
|
33268
33525
|
setSelectedYear(newYear);
|
|
33269
33526
|
};
|
|
33270
|
-
const
|
|
33527
|
+
const effectiveLineId = lineId || selectedLineId;
|
|
33528
|
+
const formattedWorkspaceName = displayName || formatWorkspaceName3(workspace?.workspace_name || "", effectiveLineId);
|
|
33271
33529
|
const shouldShowCycleTimeChart = showCycleTimeChart ?? formattedWorkspaceName.startsWith("FINAL ASSY");
|
|
33272
33530
|
const handleBackNavigation = () => {
|
|
33273
33531
|
if (returnUrl) {
|
|
@@ -33279,13 +33537,23 @@ var WorkspaceDetailView = ({
|
|
|
33279
33537
|
if (date || shift) {
|
|
33280
33538
|
setActiveTab("monthly_history");
|
|
33281
33539
|
if (onNavigate) {
|
|
33282
|
-
|
|
33540
|
+
const params = new URLSearchParams();
|
|
33541
|
+
params.set("fromMonthly", "true");
|
|
33542
|
+
if (effectiveLineId) {
|
|
33543
|
+
params.set("lineId", effectiveLineId);
|
|
33544
|
+
}
|
|
33545
|
+
onNavigate(`/workspace/${workspaceId}?${params.toString()}`);
|
|
33283
33546
|
}
|
|
33284
33547
|
} else {
|
|
33285
33548
|
if (previousView === "line_monthly_history") {
|
|
33286
33549
|
setActiveTab("monthly_history");
|
|
33287
33550
|
if (onNavigate) {
|
|
33288
|
-
|
|
33551
|
+
const params = new URLSearchParams();
|
|
33552
|
+
params.set("fromMonthly", "true");
|
|
33553
|
+
if (effectiveLineId) {
|
|
33554
|
+
params.set("lineId", effectiveLineId);
|
|
33555
|
+
}
|
|
33556
|
+
onNavigate(`/workspace/${workspaceId}?${params.toString()}`);
|
|
33289
33557
|
}
|
|
33290
33558
|
} else {
|
|
33291
33559
|
if (onNavigate) {
|
|
@@ -33743,7 +34011,13 @@ var WorkspaceDetailView = ({
|
|
|
33743
34011
|
if (onDateSelect) {
|
|
33744
34012
|
onDateSelect(selectedDate, selectedShift);
|
|
33745
34013
|
} else if (onNavigate) {
|
|
33746
|
-
|
|
34014
|
+
const params = new URLSearchParams();
|
|
34015
|
+
params.set("date", selectedDate);
|
|
34016
|
+
params.set("shift", selectedShift === "day" ? "0" : "1");
|
|
34017
|
+
if (effectiveLineId) {
|
|
34018
|
+
params.set("lineId", effectiveLineId);
|
|
34019
|
+
}
|
|
34020
|
+
onNavigate(`/workspace/${workspaceId}?${params.toString()}`);
|
|
33747
34021
|
}
|
|
33748
34022
|
},
|
|
33749
34023
|
onMonthNavigate: (newMonth, newYear) => {
|
|
@@ -33770,7 +34044,12 @@ var WorkspaceDetailView = ({
|
|
|
33770
34044
|
}
|
|
33771
34045
|
);
|
|
33772
34046
|
};
|
|
33773
|
-
var
|
|
34047
|
+
var WorkspaceDetailViewWithDisplayNames = withSelectedLineDisplayNames(WorkspaceDetailView);
|
|
34048
|
+
var WorkspaceDetailViewFinal = (props) => {
|
|
34049
|
+
const componentKey = `${props.date || "live"}_${props.shift || "current"}`;
|
|
34050
|
+
return /* @__PURE__ */ jsxRuntime.jsx(WorkspaceDetailViewWithDisplayNames, { ...props }, componentKey);
|
|
34051
|
+
};
|
|
34052
|
+
var WrappedComponent = withAuth(WorkspaceDetailViewFinal);
|
|
33774
34053
|
var WorkspaceDetailView_default = WrappedComponent;
|
|
33775
34054
|
var SKUManagementView = () => {
|
|
33776
34055
|
const config = useDashboardConfig();
|
|
@@ -34344,6 +34623,7 @@ exports.identifyCoreUser = identifyCoreUser;
|
|
|
34344
34623
|
exports.initializeCoreMixpanel = initializeCoreMixpanel;
|
|
34345
34624
|
exports.isLegacyConfiguration = isLegacyConfiguration;
|
|
34346
34625
|
exports.isTransitionPeriod = isTransitionPeriod;
|
|
34626
|
+
exports.isUrlPermanentlyFailed = isUrlPermanentlyFailed;
|
|
34347
34627
|
exports.isValidFactoryViewConfiguration = isValidFactoryViewConfiguration;
|
|
34348
34628
|
exports.isValidLineInfoPayload = isValidLineInfoPayload;
|
|
34349
34629
|
exports.isValidWorkspaceDetailedMetricsPayload = isValidWorkspaceDetailedMetricsPayload;
|
|
@@ -34363,6 +34643,7 @@ exports.qualityService = qualityService;
|
|
|
34363
34643
|
exports.realtimeService = realtimeService;
|
|
34364
34644
|
exports.refreshWorkspaceDisplayNames = refreshWorkspaceDisplayNames;
|
|
34365
34645
|
exports.resetCoreMixpanel = resetCoreMixpanel;
|
|
34646
|
+
exports.resetFailedUrl = resetFailedUrl;
|
|
34366
34647
|
exports.resetSubscriptionManager = resetSubscriptionManager;
|
|
34367
34648
|
exports.s3VideoPreloader = s3VideoPreloader;
|
|
34368
34649
|
exports.skuService = skuService;
|