@optifye/dashboard-core 4.2.7 → 4.2.9
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 +77 -25
- package/dist/index.d.ts +77 -25
- package/dist/index.js +715 -499
- package/dist/index.mjs +713 -500
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7,8 +7,8 @@ var dateFnsTz = require('date-fns-tz');
|
|
|
7
7
|
var dateFns = require('date-fns');
|
|
8
8
|
var mixpanel = require('mixpanel-browser');
|
|
9
9
|
var supabaseJs = require('@supabase/supabase-js');
|
|
10
|
-
var useSWR = require('swr');
|
|
11
10
|
var Hls2 = require('hls.js');
|
|
11
|
+
var useSWR = require('swr');
|
|
12
12
|
var motionUtils = require('motion-utils');
|
|
13
13
|
var motionDom = require('motion-dom');
|
|
14
14
|
var recharts = require('recharts');
|
|
@@ -46,8 +46,8 @@ function _interopNamespace(e) {
|
|
|
46
46
|
|
|
47
47
|
var React14__namespace = /*#__PURE__*/_interopNamespace(React14);
|
|
48
48
|
var mixpanel__default = /*#__PURE__*/_interopDefault(mixpanel);
|
|
49
|
-
var useSWR__default = /*#__PURE__*/_interopDefault(useSWR);
|
|
50
49
|
var Hls2__default = /*#__PURE__*/_interopDefault(Hls2);
|
|
50
|
+
var useSWR__default = /*#__PURE__*/_interopDefault(useSWR);
|
|
51
51
|
var html2canvas__default = /*#__PURE__*/_interopDefault(html2canvas);
|
|
52
52
|
var jsPDF__default = /*#__PURE__*/_interopDefault(jsPDF);
|
|
53
53
|
var SelectPrimitive__namespace = /*#__PURE__*/_interopNamespace(SelectPrimitive);
|
|
@@ -154,6 +154,12 @@ var DEFAULT_ANALYTICS_CONFIG = {
|
|
|
154
154
|
var DEFAULT_AUTH_CONFIG = {
|
|
155
155
|
// Defaults related to auth providers, redirects etc.
|
|
156
156
|
};
|
|
157
|
+
var DEFAULT_VIDEO_CONFIG = {
|
|
158
|
+
canvasConfig: {
|
|
159
|
+
fps: 30,
|
|
160
|
+
useRAF: true
|
|
161
|
+
}
|
|
162
|
+
};
|
|
157
163
|
var LINE_1_UUID = "910a224b-0abc-459a-babb-4c899824cfe7";
|
|
158
164
|
var DEFAULT_CONFIG = {
|
|
159
165
|
apiBaseUrl: void 0,
|
|
@@ -167,7 +173,8 @@ var DEFAULT_CONFIG = {
|
|
|
167
173
|
// Add entity config here
|
|
168
174
|
shiftConfig: DEFAULT_SHIFT_CONFIG,
|
|
169
175
|
workspaceConfig: DEFAULT_WORKSPACE_CONFIG,
|
|
170
|
-
endpoints: DEFAULT_ENDPOINTS_CONFIG
|
|
176
|
+
endpoints: DEFAULT_ENDPOINTS_CONFIG,
|
|
177
|
+
videoConfig: DEFAULT_VIDEO_CONFIG
|
|
171
178
|
};
|
|
172
179
|
|
|
173
180
|
// src/lib/utils/config.ts
|
|
@@ -299,6 +306,10 @@ function useCustomConfig() {
|
|
|
299
306
|
const { customConfig } = useDashboardConfig();
|
|
300
307
|
return customConfig ?? {};
|
|
301
308
|
}
|
|
309
|
+
function useVideoConfig() {
|
|
310
|
+
const { videoConfig } = useDashboardConfig();
|
|
311
|
+
return videoConfig ?? DEFAULT_VIDEO_CONFIG;
|
|
312
|
+
}
|
|
302
313
|
|
|
303
314
|
// src/lib/internal/supabaseClientInstance.ts
|
|
304
315
|
var supabaseInstance = null;
|
|
@@ -1009,7 +1020,7 @@ var dashboardService = {
|
|
|
1009
1020
|
const formattedStartDate = formatDate(startDate);
|
|
1010
1021
|
const formattedEndDate = formatDate(endDate);
|
|
1011
1022
|
try {
|
|
1012
|
-
const { data, error } = await supabase.from(metricsTable).select("date, shift_id, efficiency, total_output, avg_cycle_time,
|
|
1023
|
+
const { data, error } = await supabase.from(metricsTable).select("date, shift_id, efficiency, total_output, avg_cycle_time, ideal_output, avg_pph, pph_threshold, workspace_rank").eq("workspace_id", workspaceUuid).gte("date", formattedStartDate).lte("date", formattedEndDate).order("date", { ascending: true }).order("shift_id", { ascending: true });
|
|
1013
1024
|
if (error) throw error;
|
|
1014
1025
|
if (!data) return [];
|
|
1015
1026
|
const transformedData = data.map((item) => ({
|
|
@@ -1022,8 +1033,7 @@ var dashboardService = {
|
|
|
1022
1033
|
ideal_output: item.ideal_output || 0,
|
|
1023
1034
|
avg_pph: item.avg_pph || 0,
|
|
1024
1035
|
pph_threshold: item.pph_threshold || 0,
|
|
1025
|
-
workspace_rank: item.workspace_rank || 0
|
|
1026
|
-
idle_time: item.idle_time || 0
|
|
1036
|
+
workspace_rank: item.workspace_rank || 0
|
|
1027
1037
|
}));
|
|
1028
1038
|
return transformedData;
|
|
1029
1039
|
} catch (err) {
|
|
@@ -4247,6 +4257,351 @@ var useWorkspaceOperators = (workspaceId, options) => {
|
|
|
4247
4257
|
refetch: fetchData
|
|
4248
4258
|
};
|
|
4249
4259
|
};
|
|
4260
|
+
|
|
4261
|
+
// src/lib/utils/dashboardReload.ts
|
|
4262
|
+
var createThrottledReload = (interval = 5e3) => {
|
|
4263
|
+
let last = 0;
|
|
4264
|
+
let queued = false;
|
|
4265
|
+
const doReload = () => {
|
|
4266
|
+
if (typeof window !== "undefined") {
|
|
4267
|
+
window.location.reload();
|
|
4268
|
+
}
|
|
4269
|
+
};
|
|
4270
|
+
return () => {
|
|
4271
|
+
const now2 = Date.now();
|
|
4272
|
+
if (now2 - last >= interval) {
|
|
4273
|
+
last = now2;
|
|
4274
|
+
doReload();
|
|
4275
|
+
} else if (!queued) {
|
|
4276
|
+
queued = true;
|
|
4277
|
+
setTimeout(() => {
|
|
4278
|
+
queued = false;
|
|
4279
|
+
last = Date.now();
|
|
4280
|
+
doReload();
|
|
4281
|
+
}, interval - (now2 - last));
|
|
4282
|
+
}
|
|
4283
|
+
};
|
|
4284
|
+
};
|
|
4285
|
+
var throttledReloadDashboard = createThrottledReload(5e3);
|
|
4286
|
+
|
|
4287
|
+
// src/lib/hooks/useHlsStream.ts
|
|
4288
|
+
var HLS_CONFIG = {
|
|
4289
|
+
maxBufferLength: 8,
|
|
4290
|
+
maxMaxBufferLength: 15,
|
|
4291
|
+
lowLatencyMode: false,
|
|
4292
|
+
enableWorker: true,
|
|
4293
|
+
// Retry + timeout tuned for quick recovery
|
|
4294
|
+
manifestLoadingMaxRetry: 4,
|
|
4295
|
+
levelLoadingMaxRetry: 3,
|
|
4296
|
+
fragLoadingMaxRetry: 4,
|
|
4297
|
+
manifestLoadingRetryDelay: 500,
|
|
4298
|
+
levelLoadingRetryDelay: 500,
|
|
4299
|
+
fragLoadingRetryDelay: 500,
|
|
4300
|
+
manifestLoadingTimeOut: 1e4,
|
|
4301
|
+
levelLoadingTimeOut: 8e3,
|
|
4302
|
+
fragLoadingTimeOut: 1e4,
|
|
4303
|
+
liveSyncDurationCount: 2
|
|
4304
|
+
// Follow live edge aggressively
|
|
4305
|
+
};
|
|
4306
|
+
function useHlsStream(videoRef, { src, shouldPlay, onFatalError }) {
|
|
4307
|
+
const [restartKey, setRestartKey] = React14.useState(0);
|
|
4308
|
+
const hlsRef = React14.useRef(null);
|
|
4309
|
+
const stallCheckIntervalRef = React14.useRef(null);
|
|
4310
|
+
const noProgressTimerRef = React14.useRef(null);
|
|
4311
|
+
const lastTimeUpdateRef = React14.useRef(0);
|
|
4312
|
+
const softRestartCountRef = React14.useRef(0);
|
|
4313
|
+
const isNativeHlsRef = React14.useRef(false);
|
|
4314
|
+
const waitingTimerRef = React14.useRef(null);
|
|
4315
|
+
const cleanup = () => {
|
|
4316
|
+
if (stallCheckIntervalRef.current) {
|
|
4317
|
+
clearInterval(stallCheckIntervalRef.current);
|
|
4318
|
+
stallCheckIntervalRef.current = null;
|
|
4319
|
+
}
|
|
4320
|
+
if (noProgressTimerRef.current) {
|
|
4321
|
+
clearTimeout(noProgressTimerRef.current);
|
|
4322
|
+
noProgressTimerRef.current = null;
|
|
4323
|
+
}
|
|
4324
|
+
if (waitingTimerRef.current) {
|
|
4325
|
+
clearTimeout(waitingTimerRef.current);
|
|
4326
|
+
waitingTimerRef.current = null;
|
|
4327
|
+
}
|
|
4328
|
+
if (hlsRef.current) {
|
|
4329
|
+
hlsRef.current.destroy();
|
|
4330
|
+
hlsRef.current = null;
|
|
4331
|
+
}
|
|
4332
|
+
const video = videoRef.current;
|
|
4333
|
+
if (video) {
|
|
4334
|
+
video.pause();
|
|
4335
|
+
video.removeAttribute("src");
|
|
4336
|
+
video.load();
|
|
4337
|
+
video.removeEventListener("waiting", handleWaiting);
|
|
4338
|
+
video.removeEventListener("timeupdate", handleTimeUpdate);
|
|
4339
|
+
video.removeEventListener("error", handleNativeError);
|
|
4340
|
+
}
|
|
4341
|
+
lastTimeUpdateRef.current = 0;
|
|
4342
|
+
softRestartCountRef.current = 0;
|
|
4343
|
+
};
|
|
4344
|
+
const seekToLiveEdge = () => {
|
|
4345
|
+
const hls = hlsRef.current;
|
|
4346
|
+
const video = videoRef.current;
|
|
4347
|
+
if (!hls || !video) return;
|
|
4348
|
+
if (hls.liveSyncPosition !== null && hls.liveSyncPosition !== void 0) {
|
|
4349
|
+
video.currentTime = hls.liveSyncPosition;
|
|
4350
|
+
} else if (hls.levels?.[hls.currentLevel]?.details) {
|
|
4351
|
+
const levelDetails = hls.levels[hls.currentLevel].details;
|
|
4352
|
+
if (levelDetails && levelDetails.edge !== void 0) {
|
|
4353
|
+
video.currentTime = Math.max(0, levelDetails.edge - 5);
|
|
4354
|
+
}
|
|
4355
|
+
}
|
|
4356
|
+
};
|
|
4357
|
+
const softRestart = (reason) => {
|
|
4358
|
+
console.warn(`[HLS] Soft restart: ${reason}`);
|
|
4359
|
+
const hls = hlsRef.current;
|
|
4360
|
+
if (!hls) return;
|
|
4361
|
+
try {
|
|
4362
|
+
hls.stopLoad();
|
|
4363
|
+
hls.startLoad(-1);
|
|
4364
|
+
seekToLiveEdge();
|
|
4365
|
+
softRestartCountRef.current++;
|
|
4366
|
+
if (softRestartCountRef.current >= 5) {
|
|
4367
|
+
hardRestart(`${reason} (escalated after ${softRestartCountRef.current} soft restarts)`);
|
|
4368
|
+
}
|
|
4369
|
+
} catch (error) {
|
|
4370
|
+
console.error("[HLS] Soft restart failed:", error);
|
|
4371
|
+
hardRestart(`${reason} (soft restart error)`);
|
|
4372
|
+
}
|
|
4373
|
+
};
|
|
4374
|
+
const hardRestart = (reason) => {
|
|
4375
|
+
console.warn(`[HLS] Hard restart: ${reason}`);
|
|
4376
|
+
cleanup();
|
|
4377
|
+
setRestartKey((k) => k + 1);
|
|
4378
|
+
softRestartCountRef.current = 0;
|
|
4379
|
+
if (reason.includes("hard restart") || reason.includes("native video error")) {
|
|
4380
|
+
if (onFatalError) {
|
|
4381
|
+
onFatalError();
|
|
4382
|
+
} else {
|
|
4383
|
+
throttledReloadDashboard();
|
|
4384
|
+
}
|
|
4385
|
+
}
|
|
4386
|
+
};
|
|
4387
|
+
const handleWaiting = () => {
|
|
4388
|
+
if (isNativeHlsRef.current) return;
|
|
4389
|
+
console.log("[HLS] Video waiting (buffer underrun)");
|
|
4390
|
+
if (waitingTimerRef.current) {
|
|
4391
|
+
clearTimeout(waitingTimerRef.current);
|
|
4392
|
+
}
|
|
4393
|
+
waitingTimerRef.current = setTimeout(() => {
|
|
4394
|
+
const video = videoRef.current;
|
|
4395
|
+
if (video && video.readyState < 3) {
|
|
4396
|
+
softRestart("waiting timeout");
|
|
4397
|
+
}
|
|
4398
|
+
}, 1e4);
|
|
4399
|
+
};
|
|
4400
|
+
const handleTimeUpdate = () => {
|
|
4401
|
+
const video = videoRef.current;
|
|
4402
|
+
if (!video) return;
|
|
4403
|
+
lastTimeUpdateRef.current = video.currentTime;
|
|
4404
|
+
if (waitingTimerRef.current) {
|
|
4405
|
+
clearTimeout(waitingTimerRef.current);
|
|
4406
|
+
waitingTimerRef.current = null;
|
|
4407
|
+
}
|
|
4408
|
+
};
|
|
4409
|
+
const handleNativeError = () => {
|
|
4410
|
+
console.error("[HLS] Native video error");
|
|
4411
|
+
hardRestart("native video error");
|
|
4412
|
+
};
|
|
4413
|
+
const startStallDetection = () => {
|
|
4414
|
+
if (isNativeHlsRef.current) return;
|
|
4415
|
+
stallCheckIntervalRef.current = setInterval(() => {
|
|
4416
|
+
const video = videoRef.current;
|
|
4417
|
+
if (!video || video.paused || video.ended) return;
|
|
4418
|
+
const currentTime = video.currentTime;
|
|
4419
|
+
const lastTime = lastTimeUpdateRef.current;
|
|
4420
|
+
if (Math.abs(currentTime - lastTime) < 0.1 && video.readyState >= 2) {
|
|
4421
|
+
console.warn("[HLS] Playback stall detected");
|
|
4422
|
+
if (!noProgressTimerRef.current) {
|
|
4423
|
+
noProgressTimerRef.current = setTimeout(() => {
|
|
4424
|
+
softRestart("playback stall");
|
|
4425
|
+
noProgressTimerRef.current = null;
|
|
4426
|
+
}, 8e3);
|
|
4427
|
+
}
|
|
4428
|
+
} else {
|
|
4429
|
+
if (noProgressTimerRef.current) {
|
|
4430
|
+
clearTimeout(noProgressTimerRef.current);
|
|
4431
|
+
noProgressTimerRef.current = null;
|
|
4432
|
+
}
|
|
4433
|
+
}
|
|
4434
|
+
}, 7e3);
|
|
4435
|
+
};
|
|
4436
|
+
React14.useEffect(() => {
|
|
4437
|
+
if (!src || !shouldPlay) {
|
|
4438
|
+
cleanup();
|
|
4439
|
+
return;
|
|
4440
|
+
}
|
|
4441
|
+
const video = videoRef.current;
|
|
4442
|
+
if (!video) return;
|
|
4443
|
+
isNativeHlsRef.current = video.canPlayType("application/vnd.apple.mpegurl") === "probably";
|
|
4444
|
+
if (Hls2__default.default.isSupported() && !isNativeHlsRef.current) {
|
|
4445
|
+
const hls = new Hls2__default.default(HLS_CONFIG);
|
|
4446
|
+
hlsRef.current = hls;
|
|
4447
|
+
hls.attachMedia(video);
|
|
4448
|
+
hls.loadSource(src);
|
|
4449
|
+
hls.on(Hls2__default.default.Events.ERROR, (_, data) => {
|
|
4450
|
+
if (!data.fatal) return;
|
|
4451
|
+
console.error("[HLS] Fatal error:", data.type, data.details);
|
|
4452
|
+
if (data.response?.code === 404) {
|
|
4453
|
+
hardRestart("404 hard restart");
|
|
4454
|
+
return;
|
|
4455
|
+
}
|
|
4456
|
+
switch (data.type) {
|
|
4457
|
+
case Hls2__default.default.ErrorTypes.NETWORK_ERROR:
|
|
4458
|
+
case Hls2__default.default.ErrorTypes.MEDIA_ERROR:
|
|
4459
|
+
softRestart(`${data.type}: ${data.details}`);
|
|
4460
|
+
break;
|
|
4461
|
+
default:
|
|
4462
|
+
hardRestart(`Fatal ${data.type}: ${data.details}`);
|
|
4463
|
+
break;
|
|
4464
|
+
}
|
|
4465
|
+
});
|
|
4466
|
+
hls.on(Hls2__default.default.Events.MANIFEST_PARSED, () => {
|
|
4467
|
+
video.play().catch((err) => {
|
|
4468
|
+
console.error("[HLS] Play failed:", err);
|
|
4469
|
+
});
|
|
4470
|
+
});
|
|
4471
|
+
video.addEventListener("waiting", handleWaiting);
|
|
4472
|
+
video.addEventListener("timeupdate", handleTimeUpdate);
|
|
4473
|
+
startStallDetection();
|
|
4474
|
+
} else if (isNativeHlsRef.current) {
|
|
4475
|
+
console.log("[HLS] Using native HLS");
|
|
4476
|
+
video.src = src;
|
|
4477
|
+
video.addEventListener("error", handleNativeError);
|
|
4478
|
+
video.play().catch((err) => {
|
|
4479
|
+
console.error("[HLS] Native play failed:", err);
|
|
4480
|
+
});
|
|
4481
|
+
} else {
|
|
4482
|
+
console.error("[HLS] HLS not supported");
|
|
4483
|
+
}
|
|
4484
|
+
return cleanup;
|
|
4485
|
+
}, [src, shouldPlay, restartKey, onFatalError]);
|
|
4486
|
+
return {
|
|
4487
|
+
restartKey,
|
|
4488
|
+
isNativeHls: isNativeHlsRef.current
|
|
4489
|
+
};
|
|
4490
|
+
}
|
|
4491
|
+
function useHlsStreamWithCropping(videoRef, canvasRef, options) {
|
|
4492
|
+
const { src, shouldPlay, cropping, canvasFps = 30, useRAF = true, onFatalError } = options;
|
|
4493
|
+
const animationFrameRef = React14.useRef(null);
|
|
4494
|
+
const intervalRef = React14.useRef(null);
|
|
4495
|
+
const isDrawingRef = React14.useRef(false);
|
|
4496
|
+
const hlsState = useHlsStream(videoRef, { src, shouldPlay, onFatalError });
|
|
4497
|
+
const calculateCropRect = React14.useCallback((video, cropping2) => {
|
|
4498
|
+
const videoWidth = video.videoWidth;
|
|
4499
|
+
const videoHeight = video.videoHeight;
|
|
4500
|
+
const sx = cropping2.x / 100 * videoWidth;
|
|
4501
|
+
const sy = cropping2.y / 100 * videoHeight;
|
|
4502
|
+
const sw = cropping2.width / 100 * videoWidth;
|
|
4503
|
+
const sh = cropping2.height / 100 * videoHeight;
|
|
4504
|
+
return { sx, sy, sw, sh };
|
|
4505
|
+
}, []);
|
|
4506
|
+
const drawFrame = React14.useCallback(() => {
|
|
4507
|
+
const video = videoRef.current;
|
|
4508
|
+
const canvas = canvasRef.current;
|
|
4509
|
+
if (!video || !canvas || !cropping) return;
|
|
4510
|
+
const ctx = canvas.getContext("2d");
|
|
4511
|
+
if (!ctx) return;
|
|
4512
|
+
if (video.readyState < 2) return;
|
|
4513
|
+
try {
|
|
4514
|
+
const videoWidth = video.videoWidth;
|
|
4515
|
+
const videoHeight = video.videoHeight;
|
|
4516
|
+
if (!videoWidth || !videoHeight) return;
|
|
4517
|
+
const { sx, sy, sw, sh } = calculateCropRect(video, cropping);
|
|
4518
|
+
const canvasContainer = canvas.parentElement;
|
|
4519
|
+
if (canvasContainer) {
|
|
4520
|
+
const containerWidth = canvasContainer.clientWidth;
|
|
4521
|
+
const containerHeight = canvasContainer.clientHeight;
|
|
4522
|
+
if (canvas.width !== containerWidth || canvas.height !== containerHeight) {
|
|
4523
|
+
canvas.width = containerWidth;
|
|
4524
|
+
canvas.height = containerHeight;
|
|
4525
|
+
}
|
|
4526
|
+
}
|
|
4527
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
4528
|
+
ctx.drawImage(
|
|
4529
|
+
video,
|
|
4530
|
+
sx,
|
|
4531
|
+
sy,
|
|
4532
|
+
sw,
|
|
4533
|
+
sh,
|
|
4534
|
+
// Source rectangle (cropped portion)
|
|
4535
|
+
0,
|
|
4536
|
+
0,
|
|
4537
|
+
canvas.width,
|
|
4538
|
+
canvas.height
|
|
4539
|
+
// Destination rectangle (full canvas)
|
|
4540
|
+
);
|
|
4541
|
+
} catch (err) {
|
|
4542
|
+
console.warn("Canvas drawing error:", err);
|
|
4543
|
+
}
|
|
4544
|
+
}, [videoRef, canvasRef, cropping, calculateCropRect]);
|
|
4545
|
+
const startCanvasRendering = React14.useCallback(() => {
|
|
4546
|
+
if (isDrawingRef.current) return;
|
|
4547
|
+
isDrawingRef.current = true;
|
|
4548
|
+
if (useRAF) {
|
|
4549
|
+
const animate = () => {
|
|
4550
|
+
drawFrame();
|
|
4551
|
+
animationFrameRef.current = requestAnimationFrame(animate);
|
|
4552
|
+
};
|
|
4553
|
+
animate();
|
|
4554
|
+
} else {
|
|
4555
|
+
const frameInterval = 1e3 / canvasFps;
|
|
4556
|
+
intervalRef.current = setInterval(drawFrame, frameInterval);
|
|
4557
|
+
}
|
|
4558
|
+
}, [drawFrame, canvasFps, useRAF]);
|
|
4559
|
+
const stopCanvasRendering = React14.useCallback(() => {
|
|
4560
|
+
isDrawingRef.current = false;
|
|
4561
|
+
if (animationFrameRef.current) {
|
|
4562
|
+
cancelAnimationFrame(animationFrameRef.current);
|
|
4563
|
+
animationFrameRef.current = null;
|
|
4564
|
+
}
|
|
4565
|
+
if (intervalRef.current) {
|
|
4566
|
+
clearInterval(intervalRef.current);
|
|
4567
|
+
intervalRef.current = null;
|
|
4568
|
+
}
|
|
4569
|
+
}, []);
|
|
4570
|
+
React14.useEffect(() => {
|
|
4571
|
+
const video = videoRef.current;
|
|
4572
|
+
if (!video || !cropping || !shouldPlay) {
|
|
4573
|
+
stopCanvasRendering();
|
|
4574
|
+
return;
|
|
4575
|
+
}
|
|
4576
|
+
const handlePlay = () => {
|
|
4577
|
+
if (cropping) {
|
|
4578
|
+
startCanvasRendering();
|
|
4579
|
+
}
|
|
4580
|
+
};
|
|
4581
|
+
const handlePause = () => {
|
|
4582
|
+
stopCanvasRendering();
|
|
4583
|
+
};
|
|
4584
|
+
const handleEnded = () => {
|
|
4585
|
+
stopCanvasRendering();
|
|
4586
|
+
};
|
|
4587
|
+
video.addEventListener("play", handlePlay);
|
|
4588
|
+
video.addEventListener("pause", handlePause);
|
|
4589
|
+
video.addEventListener("ended", handleEnded);
|
|
4590
|
+
if (!video.paused && video.readyState >= 2) {
|
|
4591
|
+
startCanvasRendering();
|
|
4592
|
+
}
|
|
4593
|
+
return () => {
|
|
4594
|
+
stopCanvasRendering();
|
|
4595
|
+
video.removeEventListener("play", handlePlay);
|
|
4596
|
+
video.removeEventListener("pause", handlePause);
|
|
4597
|
+
video.removeEventListener("ended", handleEnded);
|
|
4598
|
+
};
|
|
4599
|
+
}, [videoRef, cropping, shouldPlay, startCanvasRendering, stopCanvasRendering]);
|
|
4600
|
+
return {
|
|
4601
|
+
...hlsState,
|
|
4602
|
+
isCanvasRendering: isDrawingRef.current
|
|
4603
|
+
};
|
|
4604
|
+
}
|
|
4250
4605
|
function useThreads() {
|
|
4251
4606
|
const supabase = _getSupabaseInstance();
|
|
4252
4607
|
const fetcher = async (key) => {
|
|
@@ -4926,327 +5281,96 @@ function useNavigation(customNavigate) {
|
|
|
4926
5281
|
goToProfile,
|
|
4927
5282
|
navigate
|
|
4928
5283
|
};
|
|
4929
|
-
}
|
|
4930
|
-
function useWorkspaceNavigation() {
|
|
4931
|
-
const { defaultTimezone } = useDateTimeConfig();
|
|
4932
|
-
const getWorkspaceNavigationParams3 = React14.useCallback(
|
|
4933
|
-
(workspaceId, options) => {
|
|
4934
|
-
let dateToUse = options?.date;
|
|
4935
|
-
if (!dateToUse && options?.useCurrentDate) {
|
|
4936
|
-
dateToUse = getOperationalDate(defaultTimezone || "UTC");
|
|
4937
|
-
}
|
|
4938
|
-
return {
|
|
4939
|
-
workspaceId,
|
|
4940
|
-
date: dateToUse,
|
|
4941
|
-
shift: options?.shift,
|
|
4942
|
-
sourceType: options?.sourceType
|
|
4943
|
-
};
|
|
4944
|
-
},
|
|
4945
|
-
[defaultTimezone]
|
|
4946
|
-
);
|
|
4947
|
-
return {
|
|
4948
|
-
getWorkspaceNavigationParams: getWorkspaceNavigationParams3
|
|
4949
|
-
};
|
|
4950
|
-
}
|
|
4951
|
-
function useDateFormatter() {
|
|
4952
|
-
const { defaultTimezone, defaultLocale, dateFormatOptions, timeFormatOptions, dateTimeFormatOptions } = useDateTimeConfig();
|
|
4953
|
-
const formatDate = React14.useCallback(
|
|
4954
|
-
(date, formatString) => {
|
|
4955
|
-
const dateObj = typeof date === "string" ? dateFns.parseISO(date) : date;
|
|
4956
|
-
if (!dateFns.isValid(dateObj)) return "Invalid Date";
|
|
4957
|
-
const tz = defaultTimezone || "UTC";
|
|
4958
|
-
if (formatString) {
|
|
4959
|
-
return dateFnsTz.formatInTimeZone(dateObj, tz, formatString);
|
|
4960
|
-
}
|
|
4961
|
-
const effectiveOptions = dateFormatOptions || { year: "numeric", month: "short", day: "numeric" };
|
|
4962
|
-
return new Intl.DateTimeFormat(defaultLocale || "en-US", effectiveOptions).format(dateObj);
|
|
4963
|
-
},
|
|
4964
|
-
[defaultTimezone, defaultLocale, dateFormatOptions]
|
|
4965
|
-
);
|
|
4966
|
-
const formatTime2 = React14.useCallback(
|
|
4967
|
-
(date, formatString) => {
|
|
4968
|
-
const dateObj = typeof date === "string" ? dateFns.parseISO(date) : date;
|
|
4969
|
-
if (!dateFns.isValid(dateObj)) return "Invalid Time";
|
|
4970
|
-
const tz = defaultTimezone || "UTC";
|
|
4971
|
-
if (formatString) {
|
|
4972
|
-
return dateFnsTz.formatInTimeZone(dateObj, tz, formatString);
|
|
4973
|
-
}
|
|
4974
|
-
const effectiveOptions = timeFormatOptions || { hour: "numeric", minute: "numeric" };
|
|
4975
|
-
return new Intl.DateTimeFormat(defaultLocale || "en-US", effectiveOptions).format(dateObj);
|
|
4976
|
-
},
|
|
4977
|
-
[defaultTimezone, defaultLocale, timeFormatOptions]
|
|
4978
|
-
);
|
|
4979
|
-
const formatDateTime = React14.useCallback(
|
|
4980
|
-
(date, formatString) => {
|
|
4981
|
-
const dateObj = typeof date === "string" ? dateFns.parseISO(date) : date;
|
|
4982
|
-
if (!dateFns.isValid(dateObj)) return "Invalid Date/Time";
|
|
4983
|
-
const tz = defaultTimezone || "UTC";
|
|
4984
|
-
if (formatString) {
|
|
4985
|
-
return dateFnsTz.formatInTimeZone(dateObj, tz, formatString);
|
|
4986
|
-
}
|
|
4987
|
-
const effectiveOptions = dateTimeFormatOptions || { year: "numeric", month: "short", day: "numeric", hour: "numeric", minute: "numeric" };
|
|
4988
|
-
return new Intl.DateTimeFormat(defaultLocale || "en-US", effectiveOptions).format(dateObj);
|
|
4989
|
-
},
|
|
4990
|
-
[defaultTimezone, defaultLocale, dateTimeFormatOptions]
|
|
4991
|
-
);
|
|
4992
|
-
const getNow = React14.useCallback(() => {
|
|
4993
|
-
return /* @__PURE__ */ new Date();
|
|
4994
|
-
}, []);
|
|
4995
|
-
return {
|
|
4996
|
-
formatDate,
|
|
4997
|
-
formatTime: formatTime2,
|
|
4998
|
-
formatDateTime,
|
|
4999
|
-
getNow,
|
|
5000
|
-
timezone: defaultTimezone || "UTC",
|
|
5001
|
-
locale: defaultLocale || "en-US"
|
|
5002
|
-
};
|
|
5003
|
-
}
|
|
5004
|
-
var useFormatNumber = () => {
|
|
5005
|
-
const { defaultLocale } = useDateTimeConfig();
|
|
5006
|
-
const formatNumber = React14.useCallback(
|
|
5007
|
-
(value, options) => {
|
|
5008
|
-
try {
|
|
5009
|
-
return new Intl.NumberFormat(defaultLocale || "en-US", options).format(value);
|
|
5010
|
-
} catch (error) {
|
|
5011
|
-
console.error("Error formatting number:", error);
|
|
5012
|
-
return String(value);
|
|
5013
|
-
}
|
|
5014
|
-
},
|
|
5015
|
-
[defaultLocale]
|
|
5016
|
-
);
|
|
5017
|
-
return { formatNumber };
|
|
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
|
-
var HLS_CONFIG = {
|
|
5048
|
-
maxBufferLength: 8,
|
|
5049
|
-
maxMaxBufferLength: 15,
|
|
5050
|
-
lowLatencyMode: false,
|
|
5051
|
-
enableWorker: true,
|
|
5052
|
-
// Retry + timeout tuned for quick recovery
|
|
5053
|
-
manifestLoadingMaxRetry: 4,
|
|
5054
|
-
levelLoadingMaxRetry: 3,
|
|
5055
|
-
fragLoadingMaxRetry: 4,
|
|
5056
|
-
manifestLoadingRetryDelay: 500,
|
|
5057
|
-
levelLoadingRetryDelay: 500,
|
|
5058
|
-
fragLoadingRetryDelay: 500,
|
|
5059
|
-
manifestLoadingTimeOut: 1e4,
|
|
5060
|
-
levelLoadingTimeOut: 8e3,
|
|
5061
|
-
fragLoadingTimeOut: 1e4,
|
|
5062
|
-
liveSyncDurationCount: 2
|
|
5063
|
-
// Follow live edge aggressively
|
|
5064
|
-
};
|
|
5065
|
-
function useHlsStream(videoRef, { src, shouldPlay, onFatalError }) {
|
|
5066
|
-
const [restartKey, setRestartKey] = React14.useState(0);
|
|
5067
|
-
const hlsRef = React14.useRef(null);
|
|
5068
|
-
const stallCheckIntervalRef = React14.useRef(null);
|
|
5069
|
-
const noProgressTimerRef = React14.useRef(null);
|
|
5070
|
-
const lastTimeUpdateRef = React14.useRef(0);
|
|
5071
|
-
const softRestartCountRef = React14.useRef(0);
|
|
5072
|
-
const isNativeHlsRef = React14.useRef(false);
|
|
5073
|
-
const waitingTimerRef = React14.useRef(null);
|
|
5074
|
-
const cleanup = () => {
|
|
5075
|
-
if (stallCheckIntervalRef.current) {
|
|
5076
|
-
clearInterval(stallCheckIntervalRef.current);
|
|
5077
|
-
stallCheckIntervalRef.current = null;
|
|
5078
|
-
}
|
|
5079
|
-
if (noProgressTimerRef.current) {
|
|
5080
|
-
clearTimeout(noProgressTimerRef.current);
|
|
5081
|
-
noProgressTimerRef.current = null;
|
|
5082
|
-
}
|
|
5083
|
-
if (waitingTimerRef.current) {
|
|
5084
|
-
clearTimeout(waitingTimerRef.current);
|
|
5085
|
-
waitingTimerRef.current = null;
|
|
5086
|
-
}
|
|
5087
|
-
if (hlsRef.current) {
|
|
5088
|
-
hlsRef.current.destroy();
|
|
5089
|
-
hlsRef.current = null;
|
|
5090
|
-
}
|
|
5091
|
-
const video = videoRef.current;
|
|
5092
|
-
if (video) {
|
|
5093
|
-
video.pause();
|
|
5094
|
-
video.removeAttribute("src");
|
|
5095
|
-
video.load();
|
|
5096
|
-
video.removeEventListener("waiting", handleWaiting);
|
|
5097
|
-
video.removeEventListener("timeupdate", handleTimeUpdate);
|
|
5098
|
-
video.removeEventListener("error", handleNativeError);
|
|
5099
|
-
}
|
|
5100
|
-
lastTimeUpdateRef.current = 0;
|
|
5101
|
-
softRestartCountRef.current = 0;
|
|
5102
|
-
};
|
|
5103
|
-
const seekToLiveEdge = () => {
|
|
5104
|
-
const hls = hlsRef.current;
|
|
5105
|
-
const video = videoRef.current;
|
|
5106
|
-
if (!hls || !video) return;
|
|
5107
|
-
if (hls.liveSyncPosition !== null && hls.liveSyncPosition !== void 0) {
|
|
5108
|
-
video.currentTime = hls.liveSyncPosition;
|
|
5109
|
-
} else if (hls.levels?.[hls.currentLevel]?.details) {
|
|
5110
|
-
const levelDetails = hls.levels[hls.currentLevel].details;
|
|
5111
|
-
if (levelDetails && levelDetails.edge !== void 0) {
|
|
5112
|
-
video.currentTime = Math.max(0, levelDetails.edge - 5);
|
|
5113
|
-
}
|
|
5114
|
-
}
|
|
5115
|
-
};
|
|
5116
|
-
const softRestart = (reason) => {
|
|
5117
|
-
console.warn(`[HLS] Soft restart: ${reason}`);
|
|
5118
|
-
const hls = hlsRef.current;
|
|
5119
|
-
if (!hls) return;
|
|
5120
|
-
try {
|
|
5121
|
-
hls.stopLoad();
|
|
5122
|
-
hls.startLoad(-1);
|
|
5123
|
-
seekToLiveEdge();
|
|
5124
|
-
softRestartCountRef.current++;
|
|
5125
|
-
if (softRestartCountRef.current >= 5) {
|
|
5126
|
-
hardRestart(`${reason} (escalated after ${softRestartCountRef.current} soft restarts)`);
|
|
5127
|
-
}
|
|
5128
|
-
} catch (error) {
|
|
5129
|
-
console.error("[HLS] Soft restart failed:", error);
|
|
5130
|
-
hardRestart(`${reason} (soft restart error)`);
|
|
5131
|
-
}
|
|
5132
|
-
};
|
|
5133
|
-
const hardRestart = (reason) => {
|
|
5134
|
-
console.warn(`[HLS] Hard restart: ${reason}`);
|
|
5135
|
-
cleanup();
|
|
5136
|
-
setRestartKey((k) => k + 1);
|
|
5137
|
-
softRestartCountRef.current = 0;
|
|
5138
|
-
if (reason.includes("hard restart") || reason.includes("native video error")) {
|
|
5139
|
-
if (onFatalError) {
|
|
5140
|
-
onFatalError();
|
|
5141
|
-
} else {
|
|
5142
|
-
throttledReloadDashboard();
|
|
5143
|
-
}
|
|
5144
|
-
}
|
|
5145
|
-
};
|
|
5146
|
-
const handleWaiting = () => {
|
|
5147
|
-
if (isNativeHlsRef.current) return;
|
|
5148
|
-
console.log("[HLS] Video waiting (buffer underrun)");
|
|
5149
|
-
if (waitingTimerRef.current) {
|
|
5150
|
-
clearTimeout(waitingTimerRef.current);
|
|
5151
|
-
}
|
|
5152
|
-
waitingTimerRef.current = setTimeout(() => {
|
|
5153
|
-
const video = videoRef.current;
|
|
5154
|
-
if (video && video.readyState < 3) {
|
|
5155
|
-
softRestart("waiting timeout");
|
|
5156
|
-
}
|
|
5157
|
-
}, 1e4);
|
|
5158
|
-
};
|
|
5159
|
-
const handleTimeUpdate = () => {
|
|
5160
|
-
const video = videoRef.current;
|
|
5161
|
-
if (!video) return;
|
|
5162
|
-
lastTimeUpdateRef.current = video.currentTime;
|
|
5163
|
-
if (waitingTimerRef.current) {
|
|
5164
|
-
clearTimeout(waitingTimerRef.current);
|
|
5165
|
-
waitingTimerRef.current = null;
|
|
5166
|
-
}
|
|
5167
|
-
};
|
|
5168
|
-
const handleNativeError = () => {
|
|
5169
|
-
console.error("[HLS] Native video error");
|
|
5170
|
-
hardRestart("native video error");
|
|
5171
|
-
};
|
|
5172
|
-
const startStallDetection = () => {
|
|
5173
|
-
if (isNativeHlsRef.current) return;
|
|
5174
|
-
stallCheckIntervalRef.current = setInterval(() => {
|
|
5175
|
-
const video = videoRef.current;
|
|
5176
|
-
if (!video || video.paused || video.ended) return;
|
|
5177
|
-
const currentTime = video.currentTime;
|
|
5178
|
-
const lastTime = lastTimeUpdateRef.current;
|
|
5179
|
-
if (Math.abs(currentTime - lastTime) < 0.1 && video.readyState >= 2) {
|
|
5180
|
-
console.warn("[HLS] Playback stall detected");
|
|
5181
|
-
if (!noProgressTimerRef.current) {
|
|
5182
|
-
noProgressTimerRef.current = setTimeout(() => {
|
|
5183
|
-
softRestart("playback stall");
|
|
5184
|
-
noProgressTimerRef.current = null;
|
|
5185
|
-
}, 8e3);
|
|
5186
|
-
}
|
|
5187
|
-
} else {
|
|
5188
|
-
if (noProgressTimerRef.current) {
|
|
5189
|
-
clearTimeout(noProgressTimerRef.current);
|
|
5190
|
-
noProgressTimerRef.current = null;
|
|
5191
|
-
}
|
|
5284
|
+
}
|
|
5285
|
+
function useWorkspaceNavigation() {
|
|
5286
|
+
const { defaultTimezone } = useDateTimeConfig();
|
|
5287
|
+
const getWorkspaceNavigationParams3 = React14.useCallback(
|
|
5288
|
+
(workspaceId, options) => {
|
|
5289
|
+
let dateToUse = options?.date;
|
|
5290
|
+
if (!dateToUse && options?.useCurrentDate) {
|
|
5291
|
+
dateToUse = getOperationalDate(defaultTimezone || "UTC");
|
|
5192
5292
|
}
|
|
5193
|
-
|
|
5293
|
+
return {
|
|
5294
|
+
workspaceId,
|
|
5295
|
+
date: dateToUse,
|
|
5296
|
+
shift: options?.shift,
|
|
5297
|
+
sourceType: options?.sourceType
|
|
5298
|
+
};
|
|
5299
|
+
},
|
|
5300
|
+
[defaultTimezone]
|
|
5301
|
+
);
|
|
5302
|
+
return {
|
|
5303
|
+
getWorkspaceNavigationParams: getWorkspaceNavigationParams3
|
|
5194
5304
|
};
|
|
5195
|
-
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
|
|
5204
|
-
|
|
5205
|
-
|
|
5206
|
-
|
|
5207
|
-
|
|
5208
|
-
|
|
5209
|
-
|
|
5210
|
-
|
|
5211
|
-
|
|
5212
|
-
|
|
5213
|
-
|
|
5214
|
-
|
|
5215
|
-
|
|
5216
|
-
|
|
5217
|
-
|
|
5218
|
-
|
|
5219
|
-
|
|
5220
|
-
|
|
5221
|
-
|
|
5222
|
-
|
|
5223
|
-
|
|
5224
|
-
|
|
5225
|
-
|
|
5226
|
-
|
|
5227
|
-
|
|
5228
|
-
|
|
5229
|
-
|
|
5230
|
-
|
|
5231
|
-
|
|
5232
|
-
|
|
5233
|
-
|
|
5234
|
-
|
|
5235
|
-
|
|
5236
|
-
|
|
5237
|
-
|
|
5238
|
-
|
|
5239
|
-
|
|
5240
|
-
} else {
|
|
5241
|
-
console.error("[HLS] HLS not supported");
|
|
5242
|
-
}
|
|
5243
|
-
return cleanup;
|
|
5244
|
-
}, [src, shouldPlay, restartKey, onFatalError]);
|
|
5305
|
+
}
|
|
5306
|
+
function useDateFormatter() {
|
|
5307
|
+
const { defaultTimezone, defaultLocale, dateFormatOptions, timeFormatOptions, dateTimeFormatOptions } = useDateTimeConfig();
|
|
5308
|
+
const formatDate = React14.useCallback(
|
|
5309
|
+
(date, formatString) => {
|
|
5310
|
+
const dateObj = typeof date === "string" ? dateFns.parseISO(date) : date;
|
|
5311
|
+
if (!dateFns.isValid(dateObj)) return "Invalid Date";
|
|
5312
|
+
const tz = defaultTimezone || "UTC";
|
|
5313
|
+
if (formatString) {
|
|
5314
|
+
return dateFnsTz.formatInTimeZone(dateObj, tz, formatString);
|
|
5315
|
+
}
|
|
5316
|
+
const effectiveOptions = dateFormatOptions || { year: "numeric", month: "short", day: "numeric" };
|
|
5317
|
+
return new Intl.DateTimeFormat(defaultLocale || "en-US", effectiveOptions).format(dateObj);
|
|
5318
|
+
},
|
|
5319
|
+
[defaultTimezone, defaultLocale, dateFormatOptions]
|
|
5320
|
+
);
|
|
5321
|
+
const formatTime2 = React14.useCallback(
|
|
5322
|
+
(date, formatString) => {
|
|
5323
|
+
const dateObj = typeof date === "string" ? dateFns.parseISO(date) : date;
|
|
5324
|
+
if (!dateFns.isValid(dateObj)) return "Invalid Time";
|
|
5325
|
+
const tz = defaultTimezone || "UTC";
|
|
5326
|
+
if (formatString) {
|
|
5327
|
+
return dateFnsTz.formatInTimeZone(dateObj, tz, formatString);
|
|
5328
|
+
}
|
|
5329
|
+
const effectiveOptions = timeFormatOptions || { hour: "numeric", minute: "numeric" };
|
|
5330
|
+
return new Intl.DateTimeFormat(defaultLocale || "en-US", effectiveOptions).format(dateObj);
|
|
5331
|
+
},
|
|
5332
|
+
[defaultTimezone, defaultLocale, timeFormatOptions]
|
|
5333
|
+
);
|
|
5334
|
+
const formatDateTime = React14.useCallback(
|
|
5335
|
+
(date, formatString) => {
|
|
5336
|
+
const dateObj = typeof date === "string" ? dateFns.parseISO(date) : date;
|
|
5337
|
+
if (!dateFns.isValid(dateObj)) return "Invalid Date/Time";
|
|
5338
|
+
const tz = defaultTimezone || "UTC";
|
|
5339
|
+
if (formatString) {
|
|
5340
|
+
return dateFnsTz.formatInTimeZone(dateObj, tz, formatString);
|
|
5341
|
+
}
|
|
5342
|
+
const effectiveOptions = dateTimeFormatOptions || { year: "numeric", month: "short", day: "numeric", hour: "numeric", minute: "numeric" };
|
|
5343
|
+
return new Intl.DateTimeFormat(defaultLocale || "en-US", effectiveOptions).format(dateObj);
|
|
5344
|
+
},
|
|
5345
|
+
[defaultTimezone, defaultLocale, dateTimeFormatOptions]
|
|
5346
|
+
);
|
|
5347
|
+
const getNow = React14.useCallback(() => {
|
|
5348
|
+
return /* @__PURE__ */ new Date();
|
|
5349
|
+
}, []);
|
|
5245
5350
|
return {
|
|
5246
|
-
|
|
5247
|
-
|
|
5351
|
+
formatDate,
|
|
5352
|
+
formatTime: formatTime2,
|
|
5353
|
+
formatDateTime,
|
|
5354
|
+
getNow,
|
|
5355
|
+
timezone: defaultTimezone || "UTC",
|
|
5356
|
+
locale: defaultLocale || "en-US"
|
|
5248
5357
|
};
|
|
5249
5358
|
}
|
|
5359
|
+
var useFormatNumber = () => {
|
|
5360
|
+
const { defaultLocale } = useDateTimeConfig();
|
|
5361
|
+
const formatNumber = React14.useCallback(
|
|
5362
|
+
(value, options) => {
|
|
5363
|
+
try {
|
|
5364
|
+
return new Intl.NumberFormat(defaultLocale || "en-US", options).format(value);
|
|
5365
|
+
} catch (error) {
|
|
5366
|
+
console.error("Error formatting number:", error);
|
|
5367
|
+
return String(value);
|
|
5368
|
+
}
|
|
5369
|
+
},
|
|
5370
|
+
[defaultLocale]
|
|
5371
|
+
);
|
|
5372
|
+
return { formatNumber };
|
|
5373
|
+
};
|
|
5250
5374
|
|
|
5251
5375
|
// src/lib/utils/api.ts
|
|
5252
5376
|
var apiUtils = {
|
|
@@ -14606,16 +14730,16 @@ function createProjectionNode2({ attachResizeListener, defaultParent, measureScr
|
|
|
14606
14730
|
if (!this.isVisible) {
|
|
14607
14731
|
return hiddenVisibility;
|
|
14608
14732
|
}
|
|
14609
|
-
const
|
|
14733
|
+
const styles2 = {
|
|
14610
14734
|
visibility: ""
|
|
14611
14735
|
};
|
|
14612
14736
|
const transformTemplate = this.getTransformTemplate();
|
|
14613
14737
|
if (this.needsReset) {
|
|
14614
14738
|
this.needsReset = false;
|
|
14615
|
-
|
|
14616
|
-
|
|
14617
|
-
|
|
14618
|
-
return
|
|
14739
|
+
styles2.opacity = "";
|
|
14740
|
+
styles2.pointerEvents = resolveMotionValue(styleProp === null || styleProp === void 0 ? void 0 : styleProp.pointerEvents) || "";
|
|
14741
|
+
styles2.transform = transformTemplate ? transformTemplate(this.latestValues, "") : "none";
|
|
14742
|
+
return styles2;
|
|
14619
14743
|
}
|
|
14620
14744
|
const lead = this.getLead();
|
|
14621
14745
|
if (!this.projectionDelta || !this.layout || !lead.target) {
|
|
@@ -14632,35 +14756,35 @@ function createProjectionNode2({ attachResizeListener, defaultParent, measureScr
|
|
|
14632
14756
|
}
|
|
14633
14757
|
const valuesToRender = lead.animationValues || lead.latestValues;
|
|
14634
14758
|
this.applyTransformsToTarget();
|
|
14635
|
-
|
|
14759
|
+
styles2.transform = buildProjectionTransform(this.projectionDeltaWithTransform, this.treeScale, valuesToRender);
|
|
14636
14760
|
if (transformTemplate) {
|
|
14637
|
-
|
|
14761
|
+
styles2.transform = transformTemplate(valuesToRender, styles2.transform);
|
|
14638
14762
|
}
|
|
14639
14763
|
const { x, y } = this.projectionDelta;
|
|
14640
|
-
|
|
14764
|
+
styles2.transformOrigin = `${x.origin * 100}% ${y.origin * 100}% 0`;
|
|
14641
14765
|
if (lead.animationValues) {
|
|
14642
|
-
|
|
14766
|
+
styles2.opacity = lead === this ? (_b = (_a = valuesToRender.opacity) !== null && _a !== void 0 ? _a : this.latestValues.opacity) !== null && _b !== void 0 ? _b : 1 : this.preserveOpacity ? this.latestValues.opacity : valuesToRender.opacityExit;
|
|
14643
14767
|
} else {
|
|
14644
|
-
|
|
14768
|
+
styles2.opacity = lead === this ? valuesToRender.opacity !== void 0 ? valuesToRender.opacity : "" : valuesToRender.opacityExit !== void 0 ? valuesToRender.opacityExit : 0;
|
|
14645
14769
|
}
|
|
14646
14770
|
for (const key in scaleCorrectors) {
|
|
14647
14771
|
if (valuesToRender[key] === void 0)
|
|
14648
14772
|
continue;
|
|
14649
14773
|
const { correct, applyTo } = scaleCorrectors[key];
|
|
14650
|
-
const corrected =
|
|
14774
|
+
const corrected = styles2.transform === "none" ? valuesToRender[key] : correct(valuesToRender[key], lead);
|
|
14651
14775
|
if (applyTo) {
|
|
14652
14776
|
const num = applyTo.length;
|
|
14653
14777
|
for (let i = 0; i < num; i++) {
|
|
14654
|
-
|
|
14778
|
+
styles2[applyTo[i]] = corrected;
|
|
14655
14779
|
}
|
|
14656
14780
|
} else {
|
|
14657
|
-
|
|
14781
|
+
styles2[key] = corrected;
|
|
14658
14782
|
}
|
|
14659
14783
|
}
|
|
14660
14784
|
if (this.options.layoutId) {
|
|
14661
|
-
|
|
14785
|
+
styles2.pointerEvents = lead === this ? resolveMotionValue(styleProp === null || styleProp === void 0 ? void 0 : styleProp.pointerEvents) || "" : "none";
|
|
14662
14786
|
}
|
|
14663
|
-
return
|
|
14787
|
+
return styles2;
|
|
14664
14788
|
}
|
|
14665
14789
|
clearSnapshot() {
|
|
14666
14790
|
this.resumeFrom = this.snapshot = void 0;
|
|
@@ -16767,23 +16891,35 @@ var HourlyOutputChart = ({
|
|
|
16767
16891
|
const [animatedData, setAnimatedData] = React14__namespace.default.useState(Array(SHIFT_DURATION).fill(0));
|
|
16768
16892
|
const prevDataRef = React14__namespace.default.useRef(Array(SHIFT_DURATION).fill(0));
|
|
16769
16893
|
const animationFrameRef = React14__namespace.default.useRef(null);
|
|
16770
|
-
const [
|
|
16894
|
+
const [idleBarState, setIdleBarState] = React14__namespace.default.useState({
|
|
16895
|
+
visible: showIdleTime,
|
|
16896
|
+
key: 0,
|
|
16897
|
+
shouldAnimate: false
|
|
16898
|
+
});
|
|
16771
16899
|
const prevShowIdleTimeRef = React14__namespace.default.useRef(showIdleTime);
|
|
16772
|
-
const
|
|
16900
|
+
const stateUpdateTimeoutRef = React14__namespace.default.useRef(null);
|
|
16773
16901
|
React14__namespace.default.useEffect(() => {
|
|
16902
|
+
if (stateUpdateTimeoutRef.current) {
|
|
16903
|
+
clearTimeout(stateUpdateTimeoutRef.current);
|
|
16904
|
+
}
|
|
16774
16905
|
if (showIdleTime && !prevShowIdleTimeRef.current) {
|
|
16775
|
-
|
|
16776
|
-
|
|
16777
|
-
|
|
16778
|
-
|
|
16779
|
-
|
|
16780
|
-
|
|
16781
|
-
|
|
16906
|
+
requestAnimationFrame(() => {
|
|
16907
|
+
setIdleBarState({
|
|
16908
|
+
visible: true,
|
|
16909
|
+
key: Date.now(),
|
|
16910
|
+
shouldAnimate: true
|
|
16911
|
+
});
|
|
16912
|
+
stateUpdateTimeoutRef.current = setTimeout(() => {
|
|
16913
|
+
setIdleBarState((prev) => ({ ...prev, shouldAnimate: false }));
|
|
16914
|
+
}, 1100);
|
|
16915
|
+
});
|
|
16916
|
+
} else if (!showIdleTime && prevShowIdleTimeRef.current) {
|
|
16917
|
+
setIdleBarState((prev) => ({ ...prev, visible: false }));
|
|
16782
16918
|
}
|
|
16783
16919
|
prevShowIdleTimeRef.current = showIdleTime;
|
|
16784
16920
|
return () => {
|
|
16785
|
-
if (
|
|
16786
|
-
clearTimeout(
|
|
16921
|
+
if (stateUpdateTimeoutRef.current) {
|
|
16922
|
+
clearTimeout(stateUpdateTimeoutRef.current);
|
|
16787
16923
|
}
|
|
16788
16924
|
};
|
|
16789
16925
|
}, [showIdleTime]);
|
|
@@ -16876,6 +17012,55 @@ var HourlyOutputChart = ({
|
|
|
16876
17012
|
};
|
|
16877
17013
|
});
|
|
16878
17014
|
}, [animatedData, data, pphThreshold, idleTimeHourly, shiftStartTime.hour, formatHour, formatTimeRange]);
|
|
17015
|
+
const IdleBar = React14__namespace.default.useMemo(() => {
|
|
17016
|
+
if (!idleBarState.visible) return null;
|
|
17017
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
17018
|
+
recharts.Bar,
|
|
17019
|
+
{
|
|
17020
|
+
dataKey: "idleMinutes",
|
|
17021
|
+
yAxisId: "idle",
|
|
17022
|
+
maxBarSize: 35,
|
|
17023
|
+
radius: [10, 10, 0, 0],
|
|
17024
|
+
fill: "url(#idlePattern)",
|
|
17025
|
+
opacity: 0.7,
|
|
17026
|
+
isAnimationActive: idleBarState.shouldAnimate,
|
|
17027
|
+
animationBegin: 0,
|
|
17028
|
+
animationDuration: 1e3,
|
|
17029
|
+
animationEasing: "ease-out",
|
|
17030
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
17031
|
+
recharts.LabelList,
|
|
17032
|
+
{
|
|
17033
|
+
dataKey: "idleMinutes",
|
|
17034
|
+
position: "top",
|
|
17035
|
+
content: (props) => {
|
|
17036
|
+
const { x, y, width, value } = props;
|
|
17037
|
+
if (!value || value === 0) return null;
|
|
17038
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
17039
|
+
"text",
|
|
17040
|
+
{
|
|
17041
|
+
x: x + width / 2,
|
|
17042
|
+
y: y - 2,
|
|
17043
|
+
textAnchor: "middle",
|
|
17044
|
+
fontSize: "9",
|
|
17045
|
+
fontWeight: "600",
|
|
17046
|
+
fill: "#6b7280",
|
|
17047
|
+
style: {
|
|
17048
|
+
opacity: 1,
|
|
17049
|
+
pointerEvents: "none"
|
|
17050
|
+
},
|
|
17051
|
+
children: [
|
|
17052
|
+
value,
|
|
17053
|
+
"m"
|
|
17054
|
+
]
|
|
17055
|
+
}
|
|
17056
|
+
);
|
|
17057
|
+
}
|
|
17058
|
+
}
|
|
17059
|
+
)
|
|
17060
|
+
},
|
|
17061
|
+
`idle-bar-${idleBarState.key}`
|
|
17062
|
+
);
|
|
17063
|
+
}, [idleBarState.visible, idleBarState.key, idleBarState.shouldAnimate]);
|
|
16879
17064
|
const maxYValue = Math.ceil(pphThreshold * 1.5);
|
|
16880
17065
|
const generateYAxisTicks = () => {
|
|
16881
17066
|
const targetValue = Math.round(pphThreshold);
|
|
@@ -17133,51 +17318,7 @@ var HourlyOutputChart = ({
|
|
|
17133
17318
|
]
|
|
17134
17319
|
}
|
|
17135
17320
|
),
|
|
17136
|
-
|
|
17137
|
-
recharts.Bar,
|
|
17138
|
-
{
|
|
17139
|
-
dataKey: "idleMinutes",
|
|
17140
|
-
yAxisId: "idle",
|
|
17141
|
-
maxBarSize: 35,
|
|
17142
|
-
radius: [10, 10, 0, 0],
|
|
17143
|
-
fill: "url(#idlePattern)",
|
|
17144
|
-
opacity: 0.7,
|
|
17145
|
-
isAnimationActive: shouldAnimateIdle,
|
|
17146
|
-
animationBegin: shouldAnimateIdle ? 200 : 0,
|
|
17147
|
-
animationDuration: shouldAnimateIdle ? 800 : 0,
|
|
17148
|
-
animationEasing: "ease-out",
|
|
17149
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
17150
|
-
recharts.LabelList,
|
|
17151
|
-
{
|
|
17152
|
-
dataKey: "idleMinutes",
|
|
17153
|
-
position: "top",
|
|
17154
|
-
content: (props) => {
|
|
17155
|
-
const { x, y, width, value } = props;
|
|
17156
|
-
if (!value || value === 0) return null;
|
|
17157
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
17158
|
-
"text",
|
|
17159
|
-
{
|
|
17160
|
-
x: x + width / 2,
|
|
17161
|
-
y: y - 2,
|
|
17162
|
-
textAnchor: "middle",
|
|
17163
|
-
fontSize: "9",
|
|
17164
|
-
fontWeight: "600",
|
|
17165
|
-
fill: "#6b7280",
|
|
17166
|
-
style: {
|
|
17167
|
-
opacity: 1,
|
|
17168
|
-
pointerEvents: "none"
|
|
17169
|
-
},
|
|
17170
|
-
children: [
|
|
17171
|
-
value,
|
|
17172
|
-
"m"
|
|
17173
|
-
]
|
|
17174
|
-
}
|
|
17175
|
-
);
|
|
17176
|
-
}
|
|
17177
|
-
}
|
|
17178
|
-
)
|
|
17179
|
-
}
|
|
17180
|
-
),
|
|
17321
|
+
IdleBar,
|
|
17181
17322
|
/* @__PURE__ */ jsxRuntime.jsx("defs", { children: /* @__PURE__ */ jsxRuntime.jsxs("pattern", { id: "idlePattern", patternUnits: "userSpaceOnUse", width: "4", height: "4", children: [
|
|
17182
17323
|
/* @__PURE__ */ jsxRuntime.jsx("rect", { width: "4", height: "4", fill: "#9ca3af", opacity: "0.2" }),
|
|
17183
17324
|
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M 0,4 l 4,-4 M -1,1 l 2,-2 M 3,5 l 2,-2", stroke: "#6b7280", strokeWidth: "0.5", opacity: "0.3" })
|
|
@@ -17188,15 +17329,15 @@ var HourlyOutputChart = ({
|
|
|
17188
17329
|
renderLegend()
|
|
17189
17330
|
] });
|
|
17190
17331
|
};
|
|
17191
|
-
|
|
17192
|
-
|
|
17193
|
-
|
|
17194
|
-
|
|
17195
|
-
|
|
17196
|
-
|
|
17197
|
-
|
|
17198
|
-
}
|
|
17199
|
-
|
|
17332
|
+
function getTrendArrowAndColor(trend) {
|
|
17333
|
+
if (trend > 0) {
|
|
17334
|
+
return { arrow: "\u2191", color: "text-green-400" };
|
|
17335
|
+
} else if (trend < 0) {
|
|
17336
|
+
return { arrow: "\u2193", color: "text-red-400" };
|
|
17337
|
+
} else {
|
|
17338
|
+
return { arrow: "\u2192", color: "text-gray-400" };
|
|
17339
|
+
}
|
|
17340
|
+
}
|
|
17200
17341
|
var VideoCard = React14__namespace.default.memo(({
|
|
17201
17342
|
workspace,
|
|
17202
17343
|
hlsUrl,
|
|
@@ -17204,14 +17345,29 @@ var VideoCard = React14__namespace.default.memo(({
|
|
|
17204
17345
|
onClick,
|
|
17205
17346
|
onFatalError,
|
|
17206
17347
|
isVeryLowEfficiency = false,
|
|
17348
|
+
cropping,
|
|
17349
|
+
canvasFps = 30,
|
|
17350
|
+
useRAF = true,
|
|
17207
17351
|
className = ""
|
|
17208
17352
|
}) => {
|
|
17209
17353
|
const videoRef = React14.useRef(null);
|
|
17210
|
-
|
|
17211
|
-
|
|
17212
|
-
|
|
17213
|
-
|
|
17214
|
-
|
|
17354
|
+
const canvasRef = React14.useRef(null);
|
|
17355
|
+
if (cropping) {
|
|
17356
|
+
useHlsStreamWithCropping(videoRef, canvasRef, {
|
|
17357
|
+
src: hlsUrl,
|
|
17358
|
+
shouldPlay,
|
|
17359
|
+
cropping,
|
|
17360
|
+
canvasFps,
|
|
17361
|
+
useRAF,
|
|
17362
|
+
onFatalError: onFatalError ?? (() => throttledReloadDashboard())
|
|
17363
|
+
});
|
|
17364
|
+
} else {
|
|
17365
|
+
useHlsStream(videoRef, {
|
|
17366
|
+
src: hlsUrl,
|
|
17367
|
+
shouldPlay,
|
|
17368
|
+
onFatalError: onFatalError ?? (() => throttledReloadDashboard())
|
|
17369
|
+
});
|
|
17370
|
+
}
|
|
17215
17371
|
const displayName = getWorkspaceDisplayName(workspace.workspace_name);
|
|
17216
17372
|
workspace.workspace_uuid || workspace.workspace_name;
|
|
17217
17373
|
const getEfficiencyOverlayColor = (efficiency) => {
|
|
@@ -17266,17 +17422,26 @@ var VideoCard = React14__namespace.default.memo(({
|
|
|
17266
17422
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Camera, { className: "w-6 h-6 text-gray-500" }),
|
|
17267
17423
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-gray-500 mt-1", children: "Loading..." })
|
|
17268
17424
|
] }) }),
|
|
17269
|
-
/* @__PURE__ */ jsxRuntime.
|
|
17270
|
-
|
|
17271
|
-
|
|
17272
|
-
|
|
17273
|
-
|
|
17274
|
-
|
|
17275
|
-
|
|
17276
|
-
|
|
17277
|
-
|
|
17278
|
-
|
|
17279
|
-
|
|
17425
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute inset-0 z-10", children: [
|
|
17426
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
17427
|
+
"video",
|
|
17428
|
+
{
|
|
17429
|
+
ref: videoRef,
|
|
17430
|
+
className: `h-full w-full object-cover ${cropping ? "hidden" : ""}`,
|
|
17431
|
+
playsInline: true,
|
|
17432
|
+
muted: true,
|
|
17433
|
+
disablePictureInPicture: true,
|
|
17434
|
+
controlsList: "nodownload noplaybackrate"
|
|
17435
|
+
}
|
|
17436
|
+
),
|
|
17437
|
+
cropping && /* @__PURE__ */ jsxRuntime.jsx(
|
|
17438
|
+
"canvas",
|
|
17439
|
+
{
|
|
17440
|
+
ref: canvasRef,
|
|
17441
|
+
className: "h-full w-full object-cover"
|
|
17442
|
+
}
|
|
17443
|
+
)
|
|
17444
|
+
] }),
|
|
17280
17445
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `absolute inset-0 z-20 pointer-events-none ${efficiencyOverlayClass}` }),
|
|
17281
17446
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute top-2 right-2 z-30 bg-black/70 backdrop-blur-sm rounded px-2 py-0.5 text-white text-xs font-semibold border border-white/10", children: [
|
|
17282
17447
|
Math.round(workspace.efficiency),
|
|
@@ -17312,7 +17477,7 @@ var VideoCard = React14__namespace.default.memo(({
|
|
|
17312
17477
|
}
|
|
17313
17478
|
);
|
|
17314
17479
|
}, (prevProps, nextProps) => {
|
|
17315
|
-
return prevProps.workspace.workspace_uuid === nextProps.workspace.workspace_uuid && prevProps.workspace.workspace_name === nextProps.workspace.workspace_name && Math.abs(prevProps.workspace.efficiency - nextProps.workspace.efficiency) < 1 && prevProps.hlsUrl === nextProps.hlsUrl && prevProps.shouldPlay === nextProps.shouldPlay;
|
|
17480
|
+
return prevProps.workspace.workspace_uuid === nextProps.workspace.workspace_uuid && prevProps.workspace.workspace_name === nextProps.workspace.workspace_name && Math.abs(prevProps.workspace.efficiency - nextProps.workspace.efficiency) < 1 && prevProps.hlsUrl === nextProps.hlsUrl && prevProps.shouldPlay === nextProps.shouldPlay && prevProps.cropping?.x === nextProps.cropping?.x && prevProps.cropping?.y === nextProps.cropping?.y && prevProps.cropping?.width === nextProps.cropping?.width && prevProps.cropping?.height === nextProps.cropping?.height;
|
|
17316
17481
|
});
|
|
17317
17482
|
VideoCard.displayName = "VideoCard";
|
|
17318
17483
|
var DEFAULT_WORKSPACE_HLS_URLS = {
|
|
@@ -17340,6 +17505,8 @@ var VideoGridView = React14__namespace.default.memo(({
|
|
|
17340
17505
|
const observerRef = React14.useRef(null);
|
|
17341
17506
|
const [gridCols, setGridCols] = React14.useState(4);
|
|
17342
17507
|
const [visibleWorkspaces, setVisibleWorkspaces] = React14.useState(/* @__PURE__ */ new Set());
|
|
17508
|
+
const videoConfig = useVideoConfig();
|
|
17509
|
+
const { cropping, canvasConfig } = videoConfig;
|
|
17343
17510
|
const mergedVideoSources = {
|
|
17344
17511
|
defaultHlsUrl: videoSources.defaultHlsUrl || DEFAULT_HLS_URL,
|
|
17345
17512
|
workspaceHlsUrls: { ...DEFAULT_WORKSPACE_HLS_URLS, ...videoSources.workspaceHlsUrls }
|
|
@@ -17348,6 +17515,13 @@ var VideoGridView = React14__namespace.default.memo(({
|
|
|
17348
17515
|
const wsName = workspaceName.toUpperCase();
|
|
17349
17516
|
return mergedVideoSources.workspaceHlsUrls[wsName] || mergedVideoSources.defaultHlsUrl;
|
|
17350
17517
|
}, [mergedVideoSources]);
|
|
17518
|
+
const getWorkspaceCropping = React14.useCallback((workspaceName) => {
|
|
17519
|
+
if (!cropping) return void 0;
|
|
17520
|
+
if (cropping.workspaceOverrides?.[workspaceName]) {
|
|
17521
|
+
return cropping.workspaceOverrides[workspaceName];
|
|
17522
|
+
}
|
|
17523
|
+
return cropping.default;
|
|
17524
|
+
}, [cropping]);
|
|
17351
17525
|
const veryLowEfficiencyWorkspaces = React14.useMemo(() => {
|
|
17352
17526
|
return new Set(
|
|
17353
17527
|
workspaces.filter((w) => w.efficiency < 50 && w.efficiency >= 10).map((w) => w.workspace_name)
|
|
@@ -17486,6 +17660,7 @@ var VideoGridView = React14__namespace.default.memo(({
|
|
|
17486
17660
|
const workspaceId = workspace.workspace_uuid || workspace.workspace_name;
|
|
17487
17661
|
const isVisible = visibleWorkspaces.has(workspaceId);
|
|
17488
17662
|
const isVeryLowEfficiency = veryLowEfficiencyWorkspaces.has(workspace.workspace_name);
|
|
17663
|
+
const workspaceCropping = getWorkspaceCropping(workspace.workspace_name);
|
|
17489
17664
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
17490
17665
|
"div",
|
|
17491
17666
|
{
|
|
@@ -17500,7 +17675,10 @@ var VideoGridView = React14__namespace.default.memo(({
|
|
|
17500
17675
|
shouldPlay: isVisible,
|
|
17501
17676
|
onClick: () => handleWorkspaceClick(workspace),
|
|
17502
17677
|
onFatalError: throttledReloadDashboard,
|
|
17503
|
-
isVeryLowEfficiency
|
|
17678
|
+
isVeryLowEfficiency,
|
|
17679
|
+
cropping: workspaceCropping,
|
|
17680
|
+
canvasFps: canvasConfig?.fps,
|
|
17681
|
+
useRAF: canvasConfig?.useRAF
|
|
17504
17682
|
}
|
|
17505
17683
|
)
|
|
17506
17684
|
},
|
|
@@ -19613,6 +19791,32 @@ var WorkspaceCard = ({
|
|
|
19613
19791
|
}
|
|
19614
19792
|
);
|
|
19615
19793
|
};
|
|
19794
|
+
var styles = `
|
|
19795
|
+
@keyframes fadeIn {
|
|
19796
|
+
from {
|
|
19797
|
+
opacity: 0;
|
|
19798
|
+
transform: translateY(-10px);
|
|
19799
|
+
}
|
|
19800
|
+
to {
|
|
19801
|
+
opacity: 1;
|
|
19802
|
+
transform: translateY(0);
|
|
19803
|
+
}
|
|
19804
|
+
}
|
|
19805
|
+
|
|
19806
|
+
.calendar-container {
|
|
19807
|
+
will-change: transform, opacity;
|
|
19808
|
+
animation: fadeIn 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
|
|
19809
|
+
}
|
|
19810
|
+
|
|
19811
|
+
.calendar-wrapper:not(.animation-complete) * {
|
|
19812
|
+
transition: none !important;
|
|
19813
|
+
}
|
|
19814
|
+
|
|
19815
|
+
.calendar-wrapper:not(.animation-complete) .group:hover {
|
|
19816
|
+
opacity: 1 !important;
|
|
19817
|
+
transform: scale(1) !important;
|
|
19818
|
+
}
|
|
19819
|
+
`;
|
|
19616
19820
|
var WEEKDAYS2 = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
|
|
19617
19821
|
var getTimeInZoneAsDate = (timezone) => {
|
|
19618
19822
|
const time2 = getCurrentTimeInZone(timezone);
|
|
@@ -19631,20 +19835,20 @@ var WorkspaceHistoryCalendar = ({
|
|
|
19631
19835
|
}) => {
|
|
19632
19836
|
const { dateTimeConfig } = useDashboardConfig();
|
|
19633
19837
|
const configuredTimezone = dateTimeConfig?.defaultTimezone || "Asia/Kolkata";
|
|
19838
|
+
const [animationComplete, setAnimationComplete] = React14.useState(false);
|
|
19839
|
+
React14.useEffect(() => {
|
|
19840
|
+
setAnimationComplete(false);
|
|
19841
|
+
const timer = setTimeout(() => {
|
|
19842
|
+
setAnimationComplete(true);
|
|
19843
|
+
}, 600);
|
|
19844
|
+
return () => clearTimeout(timer);
|
|
19845
|
+
}, [month, year]);
|
|
19634
19846
|
const calendarData = React14.useMemo(() => {
|
|
19635
19847
|
const startOfMonth = dateFnsTz.toZonedTime(new Date(year, month, 1), configuredTimezone);
|
|
19636
19848
|
const endOfMonth = dateFnsTz.toZonedTime(new Date(year, month + 1, 0), configuredTimezone);
|
|
19637
19849
|
const totalDays = endOfMonth.getDate();
|
|
19638
19850
|
let startOffset = startOfMonth.getDay() - 1;
|
|
19639
19851
|
if (startOffset === -1) startOffset = 6;
|
|
19640
|
-
console.log("Calendar generation for:", {
|
|
19641
|
-
month: month + 1,
|
|
19642
|
-
year,
|
|
19643
|
-
startOffset,
|
|
19644
|
-
totalDays,
|
|
19645
|
-
configuredTimezone
|
|
19646
|
-
});
|
|
19647
|
-
console.log("Data points received:", data);
|
|
19648
19852
|
const calendar = Array(startOffset).fill(null);
|
|
19649
19853
|
for (let day = 1; day <= totalDays; day++) {
|
|
19650
19854
|
const currentDate = new Date(year, month, day);
|
|
@@ -19658,15 +19862,6 @@ var WorkspaceHistoryCalendar = ({
|
|
|
19658
19862
|
const dataDate = new Date(d.date);
|
|
19659
19863
|
const dataDateStr = dataDate.toISOString().split("T")[0];
|
|
19660
19864
|
const matches = dataDateStr === dateToMatch;
|
|
19661
|
-
if (day <= 3 && matches) {
|
|
19662
|
-
console.log(`Found data match for day ${day}:`, {
|
|
19663
|
-
dataDate: dataDate.toISOString(),
|
|
19664
|
-
currentDate: currentTimezoneDate.toISOString(),
|
|
19665
|
-
dataDateStr,
|
|
19666
|
-
dateToMatch,
|
|
19667
|
-
data: d
|
|
19668
|
-
});
|
|
19669
|
-
}
|
|
19670
19865
|
return matches;
|
|
19671
19866
|
});
|
|
19672
19867
|
if (matchingData.length > 0) {
|
|
@@ -19677,32 +19872,10 @@ var WorkspaceHistoryCalendar = ({
|
|
|
19677
19872
|
// Use the timezone-adjusted date for display
|
|
19678
19873
|
});
|
|
19679
19874
|
} else {
|
|
19680
|
-
calendar.push(
|
|
19681
|
-
date: currentTimezoneDate,
|
|
19682
|
-
dayShift: {
|
|
19683
|
-
efficiency: 0,
|
|
19684
|
-
output: 0,
|
|
19685
|
-
cycleTime: 0,
|
|
19686
|
-
pph: 0,
|
|
19687
|
-
pphThreshold: 0,
|
|
19688
|
-
idealOutput: 0,
|
|
19689
|
-
rank: 0,
|
|
19690
|
-
idleTime: 0
|
|
19691
|
-
},
|
|
19692
|
-
nightShift: {
|
|
19693
|
-
efficiency: 0,
|
|
19694
|
-
output: 0,
|
|
19695
|
-
cycleTime: 0,
|
|
19696
|
-
pph: 0,
|
|
19697
|
-
pphThreshold: 0,
|
|
19698
|
-
idealOutput: 0,
|
|
19699
|
-
rank: 0,
|
|
19700
|
-
idleTime: 0
|
|
19701
|
-
}
|
|
19702
|
-
});
|
|
19875
|
+
calendar.push(null);
|
|
19703
19876
|
}
|
|
19704
19877
|
}
|
|
19705
|
-
return calendar;
|
|
19878
|
+
return { calendar, startOffset };
|
|
19706
19879
|
}, [data, month, year, configuredTimezone]);
|
|
19707
19880
|
const monthlyMetrics = React14.useMemo(() => {
|
|
19708
19881
|
const validDays = data.filter((day) => {
|
|
@@ -19719,15 +19892,17 @@ var WorkspaceHistoryCalendar = ({
|
|
|
19719
19892
|
return [];
|
|
19720
19893
|
}
|
|
19721
19894
|
return [day.dayShift, day.nightShift];
|
|
19722
|
-
})
|
|
19895
|
+
});
|
|
19723
19896
|
if (validShifts.length === 0) return null;
|
|
19724
19897
|
const badShiftsCount = validShifts.filter((shift) => shift.efficiency < 75).length;
|
|
19898
|
+
const totalIdleTime = validShifts.reduce((sum, shift) => sum + shift.idleTime, 0);
|
|
19899
|
+
const avgIdleTime = Math.round(totalIdleTime / validShifts.length);
|
|
19725
19900
|
return {
|
|
19726
19901
|
avgEfficiency: Math.round(validShifts.reduce((sum, shift) => sum + shift.efficiency, 0) / validShifts.length),
|
|
19727
19902
|
avgCycleTime: Math.round(validShifts.reduce((sum, shift) => sum + shift.cycleTime, 0) / validShifts.length),
|
|
19903
|
+
avgIdleTime,
|
|
19728
19904
|
badDaysCount: badShiftsCount,
|
|
19729
|
-
totalDays: validShifts.length
|
|
19730
|
-
avgIdleTime: Math.round(validShifts.reduce((sum, shift) => sum + (shift.idleTime || 0), 0) / validShifts.length)
|
|
19905
|
+
totalDays: validShifts.length
|
|
19731
19906
|
};
|
|
19732
19907
|
}, [data, month, year, configuredTimezone]);
|
|
19733
19908
|
const handleDayClick = React14.useCallback((day, shift) => {
|
|
@@ -19775,7 +19950,6 @@ var WorkspaceHistoryCalendar = ({
|
|
|
19775
19950
|
compareDate.setHours(0, 0, 0, 0);
|
|
19776
19951
|
if (compareDate.getDay() === 0) return "bg-gray-300";
|
|
19777
19952
|
if (compareDate > istNow) return "bg-gray-200";
|
|
19778
|
-
if (efficiency < 10) return "bg-gray-300";
|
|
19779
19953
|
if (efficiency >= 80) return "bg-[#00AB45]/90";
|
|
19780
19954
|
if (efficiency >= 70) return "bg-[#FFB020]/90";
|
|
19781
19955
|
return "bg-[#E34329]/90";
|
|
@@ -19814,38 +19988,55 @@ var WorkspaceHistoryCalendar = ({
|
|
|
19814
19988
|
] })
|
|
19815
19989
|
] }) });
|
|
19816
19990
|
};
|
|
19817
|
-
const renderDayCell = React14.useCallback((day) => {
|
|
19818
|
-
if (
|
|
19991
|
+
const renderDayCell = React14.useCallback((day, dayNumber, index) => {
|
|
19992
|
+
if (dayNumber === null) {
|
|
19993
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full" });
|
|
19994
|
+
}
|
|
19995
|
+
const cellDate = dateFnsTz.toZonedTime(new Date(year, month, dayNumber), configuredTimezone);
|
|
19996
|
+
const isToday = isCurrentDate(cellDate);
|
|
19997
|
+
const isFuture = isFutureDate(cellDate);
|
|
19998
|
+
const isSunday = cellDate.getDay() === 0;
|
|
19999
|
+
if (!day) {
|
|
20000
|
+
let bgColor = "bg-gray-100";
|
|
20001
|
+
let textColor = "text-gray-400";
|
|
20002
|
+
if (isSunday) {
|
|
20003
|
+
bgColor = "bg-gray-200";
|
|
20004
|
+
textColor = "text-gray-500";
|
|
20005
|
+
}
|
|
20006
|
+
if (isFuture) {
|
|
20007
|
+
bgColor = "bg-gray-50";
|
|
20008
|
+
textColor = "text-gray-300";
|
|
20009
|
+
}
|
|
20010
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `h-full border border-gray-200 rounded-lg ${bgColor} ${animationComplete ? "transition-all duration-300 ease-in-out" : ""} cursor-not-allowed opacity-60`, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: `text-base font-medium ${textColor} ${isToday ? "text-blue-500" : ""}`, children: dayNumber }) }) });
|
|
20011
|
+
}
|
|
19819
20012
|
const shiftData = selectedShift === "day" ? day.dayShift : day.nightShift;
|
|
19820
|
-
const isToday = isCurrentDate(day.date);
|
|
19821
|
-
const isFuture = isFutureDate(day.date);
|
|
19822
|
-
const isInactive = shiftData.efficiency < 10;
|
|
19823
20013
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
19824
20014
|
"div",
|
|
19825
20015
|
{
|
|
19826
|
-
className: `group h-full transition-all duration-
|
|
19827
|
-
onClick: () => !isFuture &&
|
|
20016
|
+
className: `group h-full ${animationComplete ? "transition-all duration-300 ease-in-out" : ""} ${!isFuture && animationComplete ? "cursor-pointer hover:opacity-90 hover:scale-105" : "cursor-not-allowed"}`,
|
|
20017
|
+
onClick: () => !isFuture && handleDayClick(day, selectedShift),
|
|
19828
20018
|
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `
|
|
19829
20019
|
${getPerformanceColor(shiftData.efficiency, day.date)}
|
|
19830
|
-
rounded-lg h-full p-2 relative transition-all duration-
|
|
20020
|
+
rounded-lg h-full p-2 relative ${animationComplete ? "transition-all duration-300 ease-in-out" : ""} shadow-sm
|
|
19831
20021
|
${isToday ? "ring-2 ring-blue-500 ring-offset-2 shadow-md" : ""}
|
|
19832
20022
|
`, children: [
|
|
19833
20023
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `
|
|
19834
|
-
text-base font-medium text-white flex items-center transition-all duration-
|
|
20024
|
+
text-base font-medium text-white flex items-center ${animationComplete ? "transition-all duration-300 ease-in-out" : ""}
|
|
19835
20025
|
${isToday ? "bg-blue-500 rounded-full w-7 h-7 justify-center" : ""}
|
|
19836
20026
|
`, children: day.date.getDate() }),
|
|
19837
|
-
!isFuture &&
|
|
20027
|
+
!isFuture && animationComplete && renderStats(shiftData, day.date)
|
|
19838
20028
|
] })
|
|
19839
20029
|
}
|
|
19840
20030
|
);
|
|
19841
|
-
}, [selectedShift, isCurrentDate, isFutureDate, getPerformanceColor, handleDayClick]);
|
|
19842
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `space-y-6 ${className || ""}`, children: [
|
|
20031
|
+
}, [selectedShift, isCurrentDate, isFutureDate, getPerformanceColor, handleDayClick, year, month, configuredTimezone, animationComplete]);
|
|
20032
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `calendar-wrapper space-y-6 ${className || ""} ${animationComplete ? "animation-complete" : ""}`, children: [
|
|
20033
|
+
/* @__PURE__ */ jsxRuntime.jsx("style", { dangerouslySetInnerHTML: { __html: styles } }),
|
|
19843
20034
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-1 border border-gray-200 rounded-lg p-1 bg-gray-50", children: [
|
|
19844
20035
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
19845
20036
|
"button",
|
|
19846
20037
|
{
|
|
19847
20038
|
onClick: () => handleShiftChange("day"),
|
|
19848
|
-
className: `px-4 py-2 text-sm font-medium rounded-md transition-all duration-200 ${selectedShift === "day" ? "bg-white text-blue-600 shadow-sm ring-1 ring-gray-200" :
|
|
20039
|
+
className: `px-4 py-2 text-sm font-medium rounded-md ${animationComplete ? "transition-all duration-200" : ""} ${selectedShift === "day" ? "bg-white text-blue-600 shadow-sm ring-1 ring-gray-200" : `text-gray-600 ${animationComplete ? "hover:text-gray-900 hover:bg-gray-100" : ""}`}`,
|
|
19849
20040
|
children: "Day Shift"
|
|
19850
20041
|
}
|
|
19851
20042
|
),
|
|
@@ -19853,23 +20044,27 @@ var WorkspaceHistoryCalendar = ({
|
|
|
19853
20044
|
"button",
|
|
19854
20045
|
{
|
|
19855
20046
|
onClick: () => handleShiftChange("night"),
|
|
19856
|
-
className: `px-4 py-2 text-sm font-medium rounded-md transition-all duration-200 ${selectedShift === "night" ? "bg-white text-blue-600 shadow-sm ring-1 ring-gray-200" :
|
|
20047
|
+
className: `px-4 py-2 text-sm font-medium rounded-md ${animationComplete ? "transition-all duration-200" : ""} ${selectedShift === "night" ? "bg-white text-blue-600 shadow-sm ring-1 ring-gray-200" : `text-gray-600 ${animationComplete ? "hover:text-gray-900 hover:bg-gray-100" : ""}`}`,
|
|
19857
20048
|
children: "Night Shift"
|
|
19858
20049
|
}
|
|
19859
20050
|
)
|
|
19860
20051
|
] }) }),
|
|
19861
20052
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-8", children: [
|
|
19862
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-xl shadow-sm border border-gray-100 p-6 transition-all duration-200 ease-in-out", children: [
|
|
20053
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "calendar-container bg-white rounded-xl shadow-sm border border-gray-100 p-6 transition-all duration-200 ease-in-out", children: [
|
|
19863
20054
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-6", children: [
|
|
19864
20055
|
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-semibold text-gray-900 text-lg", children: selectedShift === "day" ? "Day Shifts" : "Night Shifts" }),
|
|
19865
20056
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500 mt-1", children: "Calendar view of daily performance" })
|
|
19866
20057
|
] }),
|
|
19867
20058
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-6", children: [
|
|
19868
20059
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-7 gap-2", children: WEEKDAYS2.map((day) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium text-gray-600 text-center", children: day }, day)) }),
|
|
19869
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-7 gap-2", children: calendarData.map((day, index) =>
|
|
20060
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-7 gap-2", children: calendarData.calendar.map((day, index) => {
|
|
20061
|
+
const startOffset = calendarData.startOffset;
|
|
20062
|
+
const dayNumber = index >= startOffset ? index - startOffset + 1 : null;
|
|
20063
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "aspect-square relative transition-all duration-200 ease-in-out", children: renderDayCell(day, dayNumber && dayNumber <= new Date(year, month + 1, 0).getDate() ? dayNumber : null, index) }, index);
|
|
20064
|
+
}) })
|
|
19870
20065
|
] })
|
|
19871
20066
|
] }),
|
|
19872
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-xl shadow-sm border border-gray-100 p-6 transition-all duration-200 ease-in-out", children: [
|
|
20067
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "calendar-container bg-white rounded-xl shadow-sm border border-gray-100 p-6 transition-all duration-200 ease-in-out", children: [
|
|
19873
20068
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-6", children: [
|
|
19874
20069
|
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-semibold text-gray-900 text-lg", children: "Monthly Summary" }),
|
|
19875
20070
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500 mt-1", children: "Overview of monthly performance metrics" })
|
|
@@ -22327,12 +22522,12 @@ var getEfficiencyColor = (efficiency) => {
|
|
|
22327
22522
|
return "bg-[#E34329]/90 hover:bg-[#E34329]/95";
|
|
22328
22523
|
}
|
|
22329
22524
|
};
|
|
22330
|
-
var
|
|
22525
|
+
var TREND_STYLES = {
|
|
22331
22526
|
0: { arrow: "\u2193", color: "text-red-500 font-bold text-shadow" },
|
|
22332
22527
|
1: { arrow: "=", color: "text-gray-500 font-bold text-shadow" },
|
|
22333
22528
|
2: { arrow: "\u2191", color: "text-green-500 font-bold text-shadow" }
|
|
22334
22529
|
};
|
|
22335
|
-
var getTrendArrowAndColor2 = (trend) =>
|
|
22530
|
+
var getTrendArrowAndColor2 = (trend) => TREND_STYLES[trend] || { arrow: "", color: "" };
|
|
22336
22531
|
var ARROW_POSITIONS = {
|
|
22337
22532
|
top: "-bottom-6",
|
|
22338
22533
|
"middle-top": "-bottom-6",
|
|
@@ -22440,7 +22635,7 @@ var WorkspaceGridItem = React14__namespace.default.memo(({
|
|
|
22440
22635
|
}, [data.efficiency, isInactive, position.size, position.orientation]);
|
|
22441
22636
|
const { arrow, color: arrowColor } = React14.useMemo(() => getTrendArrowAndColor2(data.trend_score), [data.trend_score]);
|
|
22442
22637
|
const workspaceNumber = React14.useMemo(() => getWorkspaceNumber(data.workspace_name), [data.workspace_name]);
|
|
22443
|
-
const
|
|
22638
|
+
const styles2 = React14.useMemo(() => getWorkspaceStyles(position, isInactive), [position, isInactive]);
|
|
22444
22639
|
const arrowPosition = React14.useMemo(() => getArrowPositionClass(position), [position]);
|
|
22445
22640
|
const handleClick = React14.useCallback((e) => {
|
|
22446
22641
|
e.preventDefault();
|
|
@@ -22491,7 +22686,7 @@ var WorkspaceGridItem = React14__namespace.default.memo(({
|
|
|
22491
22686
|
"button",
|
|
22492
22687
|
{
|
|
22493
22688
|
onClick: handleClick,
|
|
22494
|
-
className: `${
|
|
22689
|
+
className: `${styles2} ${colorClass} ${isBottleneck ? "ring-2 ring-red-500/70" : ""} ${isVeryLowEfficiency ? "ring-2 ring-red-500/50" : ""} ${isInactive ? "bg-gray-200" : ""} shadow-lg`,
|
|
22495
22690
|
"aria-label": isInactive ? `Inactive workspace ${workspaceNumber}` : `View details for workspace ${workspaceNumber}`,
|
|
22496
22691
|
title: isInactive ? `Inactive: ${getWorkspaceDisplayName(data.workspace_name)}` : getWorkspaceDisplayName(data.workspace_name),
|
|
22497
22692
|
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: `font-semibold tracking-wide text-[min(4vw,2rem)] uppercase ${isInactive ? "text-gray-400" : "text-white"} drop-shadow-sm`, children: workspaceNumber })
|
|
@@ -30002,6 +30197,11 @@ var WorkspaceDetailView = ({
|
|
|
30002
30197
|
return getOperationalDate();
|
|
30003
30198
|
}, [isHistoricView, date]);
|
|
30004
30199
|
const handleMonthlyDataLoaded = React14.useCallback((data) => {
|
|
30200
|
+
console.log("[handleMonthlyDataLoaded] Received data:", {
|
|
30201
|
+
dataLength: data?.length,
|
|
30202
|
+
isArray: Array.isArray(data),
|
|
30203
|
+
sample: data?.[0]
|
|
30204
|
+
});
|
|
30005
30205
|
if (!data || !Array.isArray(data)) {
|
|
30006
30206
|
console.error("Invalid monthly metrics data received:", data);
|
|
30007
30207
|
setMonthlyData([]);
|
|
@@ -30019,22 +30219,35 @@ var WorkspaceDetailView = ({
|
|
|
30019
30219
|
if (!dayEntry) {
|
|
30020
30220
|
dayEntry = {
|
|
30021
30221
|
date: dateObj,
|
|
30022
|
-
dayShift:
|
|
30023
|
-
|
|
30222
|
+
dayShift: null,
|
|
30223
|
+
// Start with null instead of zeros
|
|
30224
|
+
nightShift: null
|
|
30225
|
+
// Start with null instead of zeros
|
|
30024
30226
|
};
|
|
30025
30227
|
dayDataMap.set(dateKey, dayEntry);
|
|
30026
30228
|
}
|
|
30027
|
-
const
|
|
30028
|
-
|
|
30029
|
-
|
|
30030
|
-
|
|
30031
|
-
|
|
30032
|
-
|
|
30033
|
-
|
|
30034
|
-
|
|
30035
|
-
|
|
30229
|
+
const shiftData = {
|
|
30230
|
+
efficiency: metric.avg_efficiency || 0,
|
|
30231
|
+
output: metric.total_output || 0,
|
|
30232
|
+
cycleTime: metric.avg_cycle_time || 0,
|
|
30233
|
+
pph: metric.avg_pph || 0,
|
|
30234
|
+
pphThreshold: metric.pph_threshold || 0,
|
|
30235
|
+
idealOutput: metric.ideal_output || 0,
|
|
30236
|
+
rank: metric.workspace_rank || 0,
|
|
30237
|
+
idleTime: metric.idle_time || 0
|
|
30238
|
+
};
|
|
30239
|
+
if (metric.shift_id === 0) {
|
|
30240
|
+
dayEntry.dayShift = shiftData;
|
|
30241
|
+
} else {
|
|
30242
|
+
dayEntry.nightShift = shiftData;
|
|
30243
|
+
}
|
|
30036
30244
|
});
|
|
30037
|
-
const processedData = Array.from(dayDataMap.values())
|
|
30245
|
+
const processedData = Array.from(dayDataMap.values()).filter((entry) => entry.dayShift !== null || entry.nightShift !== null).map((entry) => ({
|
|
30246
|
+
date: entry.date,
|
|
30247
|
+
// If a shift is null (no data), provide zeros for compatibility
|
|
30248
|
+
dayShift: entry.dayShift || { efficiency: 0, output: 0, cycleTime: 0, pph: 0, pphThreshold: 0, idealOutput: 0, rank: 0, idleTime: 0 },
|
|
30249
|
+
nightShift: entry.nightShift || { efficiency: 0, output: 0, cycleTime: 0, pph: 0, pphThreshold: 0, idealOutput: 0, rank: 0, idleTime: 0 }
|
|
30250
|
+
}));
|
|
30038
30251
|
console.log(`[handleMonthlyDataLoaded] Transformed data for calendar:`, {
|
|
30039
30252
|
count: processedData.length,
|
|
30040
30253
|
sample: processedData.slice(0, 1)
|
|
@@ -30494,7 +30707,7 @@ var WorkspaceDetailView = ({
|
|
|
30494
30707
|
}
|
|
30495
30708
|
)
|
|
30496
30709
|
] }),
|
|
30497
|
-
|
|
30710
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
30498
30711
|
WorkspaceHistoryCalendar,
|
|
30499
30712
|
{
|
|
30500
30713
|
data: monthlyData,
|
|
@@ -30803,6 +31016,7 @@ exports.DEFAULT_ENDPOINTS_CONFIG = DEFAULT_ENDPOINTS_CONFIG;
|
|
|
30803
31016
|
exports.DEFAULT_ENTITY_CONFIG = DEFAULT_ENTITY_CONFIG;
|
|
30804
31017
|
exports.DEFAULT_SHIFT_CONFIG = DEFAULT_SHIFT_CONFIG;
|
|
30805
31018
|
exports.DEFAULT_THEME_CONFIG = DEFAULT_THEME_CONFIG;
|
|
31019
|
+
exports.DEFAULT_VIDEO_CONFIG = DEFAULT_VIDEO_CONFIG;
|
|
30806
31020
|
exports.DEFAULT_WORKSPACE_CONFIG = DEFAULT_WORKSPACE_CONFIG;
|
|
30807
31021
|
exports.DEFAULT_WORKSPACE_POSITIONS = DEFAULT_WORKSPACE_POSITIONS;
|
|
30808
31022
|
exports.DashboardHeader = DashboardHeader;
|
|
@@ -30992,6 +31206,7 @@ exports.useFeatureFlags = useFeatureFlags;
|
|
|
30992
31206
|
exports.useFormatNumber = useFormatNumber;
|
|
30993
31207
|
exports.useHistoricWorkspaceMetrics = useHistoricWorkspaceMetrics;
|
|
30994
31208
|
exports.useHlsStream = useHlsStream;
|
|
31209
|
+
exports.useHlsStreamWithCropping = useHlsStreamWithCropping;
|
|
30995
31210
|
exports.useHookOverride = useHookOverride;
|
|
30996
31211
|
exports.useLeaderboardMetrics = useLeaderboardMetrics;
|
|
30997
31212
|
exports.useLineDetailedMetrics = useLineDetailedMetrics;
|
|
@@ -31013,6 +31228,7 @@ exports.useTargets = useTargets;
|
|
|
31013
31228
|
exports.useTheme = useTheme;
|
|
31014
31229
|
exports.useThemeConfig = useThemeConfig;
|
|
31015
31230
|
exports.useThreads = useThreads;
|
|
31231
|
+
exports.useVideoConfig = useVideoConfig;
|
|
31016
31232
|
exports.useWorkspaceConfig = useWorkspaceConfig;
|
|
31017
31233
|
exports.useWorkspaceDetailedMetrics = useWorkspaceDetailedMetrics;
|
|
31018
31234
|
exports.useWorkspaceDisplayName = useWorkspaceDisplayName;
|