@optifye/dashboard-core 6.3.3 → 6.3.5
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 +1 -43
- package/dist/index.d.ts +1 -43
- package/dist/index.js +294 -577
- package/dist/index.mjs +295 -577
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -424,11 +424,11 @@ var actionService = {
|
|
|
424
424
|
};
|
|
425
425
|
function createMemoizedFunction(fn, getCacheKey) {
|
|
426
426
|
const cache = /* @__PURE__ */ new Map();
|
|
427
|
-
const
|
|
427
|
+
const CACHE_DURATION = 5 * 60 * 1e3;
|
|
428
428
|
return (...args) => {
|
|
429
429
|
const key = getCacheKey(...args);
|
|
430
430
|
const cached = cache.get(key);
|
|
431
|
-
if (cached && Date.now() - cached.timestamp <
|
|
431
|
+
if (cached && Date.now() - cached.timestamp < CACHE_DURATION) {
|
|
432
432
|
return cached.result;
|
|
433
433
|
}
|
|
434
434
|
const result = fn(...args);
|
|
@@ -2479,199 +2479,6 @@ async function deleteThread(threadId) {
|
|
|
2479
2479
|
if (error) throw error;
|
|
2480
2480
|
}
|
|
2481
2481
|
|
|
2482
|
-
// src/lib/services/cacheService.ts
|
|
2483
|
-
var CacheService = class {
|
|
2484
|
-
constructor() {
|
|
2485
|
-
this.memoryCache = /* @__PURE__ */ new Map();
|
|
2486
|
-
this.DEFAULT_DURATION = 5 * 60 * 1e3;
|
|
2487
|
-
}
|
|
2488
|
-
// 5 minutes
|
|
2489
|
-
/**
|
|
2490
|
-
* Generate a cache key from multiple parts
|
|
2491
|
-
*/
|
|
2492
|
-
generateKey(...parts) {
|
|
2493
|
-
return parts.filter((p) => p !== void 0 && p !== null).join(":");
|
|
2494
|
-
}
|
|
2495
|
-
/**
|
|
2496
|
-
* Get item from cache
|
|
2497
|
-
*/
|
|
2498
|
-
get(key, options) {
|
|
2499
|
-
const storage = options?.storage || "memory";
|
|
2500
|
-
try {
|
|
2501
|
-
let cacheItem = null;
|
|
2502
|
-
if (storage === "memory") {
|
|
2503
|
-
cacheItem = this.memoryCache.get(key) || null;
|
|
2504
|
-
} else if (storage === "localStorage" || storage === "sessionStorage") {
|
|
2505
|
-
const stored = window[storage].getItem(key);
|
|
2506
|
-
if (stored) {
|
|
2507
|
-
cacheItem = JSON.parse(stored);
|
|
2508
|
-
}
|
|
2509
|
-
}
|
|
2510
|
-
if (!cacheItem) {
|
|
2511
|
-
return null;
|
|
2512
|
-
}
|
|
2513
|
-
if (Date.now() > cacheItem.expiresAt) {
|
|
2514
|
-
this.delete(key, options);
|
|
2515
|
-
return null;
|
|
2516
|
-
}
|
|
2517
|
-
return cacheItem.data;
|
|
2518
|
-
} catch (error) {
|
|
2519
|
-
console.error(`Error getting cache item ${key}:`, error);
|
|
2520
|
-
return null;
|
|
2521
|
-
}
|
|
2522
|
-
}
|
|
2523
|
-
/**
|
|
2524
|
-
* Set item in cache
|
|
2525
|
-
*/
|
|
2526
|
-
set(key, data, options) {
|
|
2527
|
-
const storage = options?.storage || "memory";
|
|
2528
|
-
const duration = options?.duration || this.DEFAULT_DURATION;
|
|
2529
|
-
const cacheItem = {
|
|
2530
|
-
data,
|
|
2531
|
-
timestamp: Date.now(),
|
|
2532
|
-
expiresAt: Date.now() + duration
|
|
2533
|
-
};
|
|
2534
|
-
try {
|
|
2535
|
-
if (storage === "memory") {
|
|
2536
|
-
this.memoryCache.set(key, cacheItem);
|
|
2537
|
-
if (this.memoryCache.size > 100) {
|
|
2538
|
-
const firstKey = this.memoryCache.keys().next().value;
|
|
2539
|
-
if (firstKey) {
|
|
2540
|
-
this.memoryCache.delete(firstKey);
|
|
2541
|
-
}
|
|
2542
|
-
}
|
|
2543
|
-
} else if (storage === "localStorage" || storage === "sessionStorage") {
|
|
2544
|
-
window[storage].setItem(key, JSON.stringify(cacheItem));
|
|
2545
|
-
}
|
|
2546
|
-
} catch (error) {
|
|
2547
|
-
console.error(`Error setting cache item ${key}:`, error);
|
|
2548
|
-
}
|
|
2549
|
-
}
|
|
2550
|
-
/**
|
|
2551
|
-
* Delete item from cache
|
|
2552
|
-
*/
|
|
2553
|
-
delete(key, options) {
|
|
2554
|
-
const storage = options?.storage || "memory";
|
|
2555
|
-
try {
|
|
2556
|
-
if (storage === "memory") {
|
|
2557
|
-
this.memoryCache.delete(key);
|
|
2558
|
-
} else if (storage === "localStorage" || storage === "sessionStorage") {
|
|
2559
|
-
window[storage].removeItem(key);
|
|
2560
|
-
}
|
|
2561
|
-
} catch (error) {
|
|
2562
|
-
console.error(`Error deleting cache item ${key}:`, error);
|
|
2563
|
-
}
|
|
2564
|
-
}
|
|
2565
|
-
/**
|
|
2566
|
-
* Clear all items from cache
|
|
2567
|
-
*/
|
|
2568
|
-
clear(options) {
|
|
2569
|
-
const storage = options?.storage || "memory";
|
|
2570
|
-
try {
|
|
2571
|
-
if (storage === "memory") {
|
|
2572
|
-
this.memoryCache.clear();
|
|
2573
|
-
} else if (storage === "localStorage" || storage === "sessionStorage") {
|
|
2574
|
-
const keys = Object.keys(window[storage]);
|
|
2575
|
-
keys.forEach((key) => {
|
|
2576
|
-
try {
|
|
2577
|
-
const item = window[storage].getItem(key);
|
|
2578
|
-
if (item) {
|
|
2579
|
-
const parsed = JSON.parse(item);
|
|
2580
|
-
if (parsed.timestamp && parsed.expiresAt && parsed.data !== void 0) {
|
|
2581
|
-
window[storage].removeItem(key);
|
|
2582
|
-
}
|
|
2583
|
-
}
|
|
2584
|
-
} catch {
|
|
2585
|
-
}
|
|
2586
|
-
});
|
|
2587
|
-
}
|
|
2588
|
-
} catch (error) {
|
|
2589
|
-
console.error("Error clearing cache:", error);
|
|
2590
|
-
}
|
|
2591
|
-
}
|
|
2592
|
-
/**
|
|
2593
|
-
* Get or set item in cache with a factory function
|
|
2594
|
-
*/
|
|
2595
|
-
async getOrSet(key, factory, options) {
|
|
2596
|
-
const cached = this.get(key, options);
|
|
2597
|
-
if (cached !== null) {
|
|
2598
|
-
return cached;
|
|
2599
|
-
}
|
|
2600
|
-
const data = await factory();
|
|
2601
|
-
this.set(key, data, options);
|
|
2602
|
-
return data;
|
|
2603
|
-
}
|
|
2604
|
-
/**
|
|
2605
|
-
* Invalidate cache entries matching a pattern
|
|
2606
|
-
*/
|
|
2607
|
-
invalidatePattern(pattern, options) {
|
|
2608
|
-
const storage = options?.storage || "memory";
|
|
2609
|
-
const regex = typeof pattern === "string" ? new RegExp(pattern) : pattern;
|
|
2610
|
-
try {
|
|
2611
|
-
if (storage === "memory") {
|
|
2612
|
-
const keysToDelete = [];
|
|
2613
|
-
this.memoryCache.forEach((_, key) => {
|
|
2614
|
-
if (regex.test(key)) {
|
|
2615
|
-
keysToDelete.push(key);
|
|
2616
|
-
}
|
|
2617
|
-
});
|
|
2618
|
-
keysToDelete.forEach((key) => this.memoryCache.delete(key));
|
|
2619
|
-
} else if (storage === "localStorage" || storage === "sessionStorage") {
|
|
2620
|
-
const keys = Object.keys(window[storage]);
|
|
2621
|
-
keys.forEach((key) => {
|
|
2622
|
-
if (regex.test(key)) {
|
|
2623
|
-
window[storage].removeItem(key);
|
|
2624
|
-
}
|
|
2625
|
-
});
|
|
2626
|
-
}
|
|
2627
|
-
} catch (error) {
|
|
2628
|
-
console.error("Error invalidating cache pattern:", error);
|
|
2629
|
-
}
|
|
2630
|
-
}
|
|
2631
|
-
/**
|
|
2632
|
-
* Clean up expired items
|
|
2633
|
-
*/
|
|
2634
|
-
cleanup(options) {
|
|
2635
|
-
const storage = options?.storage || "memory";
|
|
2636
|
-
const now2 = Date.now();
|
|
2637
|
-
try {
|
|
2638
|
-
if (storage === "memory") {
|
|
2639
|
-
const keysToDelete = [];
|
|
2640
|
-
this.memoryCache.forEach((item, key) => {
|
|
2641
|
-
if (now2 > item.expiresAt) {
|
|
2642
|
-
keysToDelete.push(key);
|
|
2643
|
-
}
|
|
2644
|
-
});
|
|
2645
|
-
keysToDelete.forEach((key) => this.memoryCache.delete(key));
|
|
2646
|
-
} else if (storage === "localStorage" || storage === "sessionStorage") {
|
|
2647
|
-
const keys = Object.keys(window[storage]);
|
|
2648
|
-
keys.forEach((key) => {
|
|
2649
|
-
try {
|
|
2650
|
-
const item = window[storage].getItem(key);
|
|
2651
|
-
if (item) {
|
|
2652
|
-
const parsed = JSON.parse(item);
|
|
2653
|
-
if (parsed.expiresAt && now2 > parsed.expiresAt) {
|
|
2654
|
-
window[storage].removeItem(key);
|
|
2655
|
-
}
|
|
2656
|
-
}
|
|
2657
|
-
} catch {
|
|
2658
|
-
}
|
|
2659
|
-
});
|
|
2660
|
-
}
|
|
2661
|
-
} catch (error) {
|
|
2662
|
-
console.error("Error cleaning up cache:", error);
|
|
2663
|
-
}
|
|
2664
|
-
}
|
|
2665
|
-
};
|
|
2666
|
-
var cacheService = new CacheService();
|
|
2667
|
-
if (typeof window !== "undefined") {
|
|
2668
|
-
setInterval(() => {
|
|
2669
|
-
cacheService.cleanup({ storage: "localStorage" });
|
|
2670
|
-
cacheService.cleanup({ storage: "sessionStorage" });
|
|
2671
|
-
cacheService.cleanup({ storage: "memory" });
|
|
2672
|
-
}, 60 * 1e3);
|
|
2673
|
-
}
|
|
2674
|
-
|
|
2675
2482
|
// src/lib/services/subscriptionManager.ts
|
|
2676
2483
|
var SubscriptionManager = class {
|
|
2677
2484
|
constructor(supabase) {
|
|
@@ -4000,6 +3807,8 @@ var S3ClipsService = class {
|
|
|
4000
3807
|
constructor(config) {
|
|
4001
3808
|
// Request deduplication cache
|
|
4002
3809
|
this.requestCache = new RequestDeduplicationCache();
|
|
3810
|
+
// Flag to prevent metadata fetching during index building
|
|
3811
|
+
this.isIndexBuilding = false;
|
|
4003
3812
|
this.config = config;
|
|
4004
3813
|
if (!config.s3Config) {
|
|
4005
3814
|
throw new Error("S3 configuration is required");
|
|
@@ -4151,6 +3960,10 @@ var S3ClipsService = class {
|
|
|
4151
3960
|
* Fetches full metadata including timestamps with deduplication
|
|
4152
3961
|
*/
|
|
4153
3962
|
async getFullMetadata(playlistUri) {
|
|
3963
|
+
if (this.isIndexBuilding) {
|
|
3964
|
+
console.warn(`[S3ClipsService] Skipping metadata fetch during index building for: ${playlistUri}`);
|
|
3965
|
+
return null;
|
|
3966
|
+
}
|
|
4154
3967
|
const deduplicationKey = `full-metadata:${playlistUri}`;
|
|
4155
3968
|
return this.requestCache.deduplicate(
|
|
4156
3969
|
deduplicationKey,
|
|
@@ -4217,141 +4030,152 @@ var S3ClipsService = class {
|
|
|
4217
4030
|
* Internal implementation of clip counts fetching
|
|
4218
4031
|
*/
|
|
4219
4032
|
async executeGetClipCounts(workspaceId, date, shiftId, buildIndex) {
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
}
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
const
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4033
|
+
if (buildIndex) {
|
|
4034
|
+
this.isIndexBuilding = true;
|
|
4035
|
+
console.log(`[S3ClipsService] Starting index building - metadata fetching disabled`);
|
|
4036
|
+
}
|
|
4037
|
+
try {
|
|
4038
|
+
const basePrefix = `sop_violations/${workspaceId}/${date}/${shiftId}/`;
|
|
4039
|
+
const counts = { total: 0 };
|
|
4040
|
+
const categoryFolders = [
|
|
4041
|
+
"idle_time",
|
|
4042
|
+
"low_value",
|
|
4043
|
+
"sop_deviation",
|
|
4044
|
+
"missing_quality_check",
|
|
4045
|
+
"best_cycle_time",
|
|
4046
|
+
"worst_cycle_time",
|
|
4047
|
+
"long_cycle_time",
|
|
4048
|
+
"cycle_completion",
|
|
4049
|
+
"bottleneck"
|
|
4050
|
+
];
|
|
4051
|
+
console.log(`[S3ClipsService] ${buildIndex ? "Building video index and counting" : "Fast counting"} clips for ${workspaceId} on ${date}, shift ${shiftId}`);
|
|
4052
|
+
const startTime = performance.now();
|
|
4053
|
+
const videoIndex = buildIndex ? {
|
|
4054
|
+
byCategory: /* @__PURE__ */ new Map(),
|
|
4055
|
+
allVideos: [],
|
|
4056
|
+
counts: {},
|
|
4057
|
+
workspaceId,
|
|
4058
|
+
date,
|
|
4059
|
+
shiftId: shiftId.toString(),
|
|
4060
|
+
lastUpdated: /* @__PURE__ */ new Date(),
|
|
4061
|
+
_debugId: `vid_${Date.now()}_${Math.random().toString(36).substring(7)}`
|
|
4062
|
+
} : null;
|
|
4063
|
+
const countPromises = categoryFolders.map(async (category) => {
|
|
4064
|
+
const categoryPrefix = `${basePrefix}${category}/videos/`;
|
|
4065
|
+
const categoryVideos = [];
|
|
4066
|
+
try {
|
|
4067
|
+
if (buildIndex) {
|
|
4068
|
+
const command = new clientS3.ListObjectsV2Command({
|
|
4069
|
+
Bucket: this.config.s3Config.bucketName,
|
|
4070
|
+
Prefix: categoryPrefix,
|
|
4071
|
+
MaxKeys: 1e3
|
|
4072
|
+
});
|
|
4073
|
+
let continuationToken;
|
|
4074
|
+
do {
|
|
4075
|
+
if (continuationToken) {
|
|
4076
|
+
command.input.ContinuationToken = continuationToken;
|
|
4077
|
+
}
|
|
4078
|
+
const response = await this.s3Client.send(command);
|
|
4079
|
+
if (response.Contents) {
|
|
4080
|
+
for (const obj of response.Contents) {
|
|
4081
|
+
if (obj.Key && obj.Key.endsWith("playlist.m3u8")) {
|
|
4082
|
+
if (obj.Key.includes("missed_qchecks")) {
|
|
4083
|
+
continue;
|
|
4084
|
+
}
|
|
4085
|
+
const s3Uri = `s3://${this.config.s3Config.bucketName}/${obj.Key}`;
|
|
4086
|
+
const sopCategories = this.getSOPCategories(workspaceId);
|
|
4087
|
+
const parsedInfo = parseS3Uri(s3Uri, sopCategories);
|
|
4088
|
+
const belongsToCategory = parsedInfo && (parsedInfo.type === category || // Handle specific mismatches between folder names and parsed types
|
|
4089
|
+
category === "cycle_completion" && parsedInfo.type === "cycle_completion" || category === "sop_deviation" && parsedInfo.type === "missing_quality_check" || category === "missing_quality_check" && parsedInfo.type === "missing_quality_check" || category === "idle_time" && parsedInfo.type === "low_value" || category === "low_value" && parsedInfo.type === "low_value");
|
|
4090
|
+
if (belongsToCategory) {
|
|
4091
|
+
const videoEntry = {
|
|
4092
|
+
uri: s3Uri,
|
|
4093
|
+
category: parsedInfo.type,
|
|
4094
|
+
// Use the parsed type, not the folder name
|
|
4095
|
+
timestamp: parsedInfo.timestamp,
|
|
4096
|
+
videoId: `${workspaceId}-${parsedInfo.timestamp}`,
|
|
4097
|
+
workspaceId,
|
|
4098
|
+
date,
|
|
4099
|
+
shiftId: shiftId.toString()
|
|
4100
|
+
};
|
|
4101
|
+
categoryVideos.push(videoEntry);
|
|
4102
|
+
}
|
|
4284
4103
|
}
|
|
4285
4104
|
}
|
|
4286
4105
|
}
|
|
4106
|
+
continuationToken = response.NextContinuationToken;
|
|
4107
|
+
} while (continuationToken);
|
|
4108
|
+
categoryVideos.sort((a, b) => b.timestamp.localeCompare(a.timestamp));
|
|
4109
|
+
if (categoryVideos.length > 0) {
|
|
4110
|
+
console.log(`[S3ClipsService] Found ${categoryVideos.length} videos for category '${category}' (parsed types: ${[...new Set(categoryVideos.map((v) => v.category))].join(", ")})`);
|
|
4287
4111
|
}
|
|
4288
|
-
|
|
4289
|
-
}
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
|
|
4112
|
+
return { category, count: categoryVideos.length, videos: categoryVideos };
|
|
4113
|
+
} else {
|
|
4114
|
+
const command = new clientS3.ListObjectsV2Command({
|
|
4115
|
+
Bucket: this.config.s3Config.bucketName,
|
|
4116
|
+
Prefix: categoryPrefix,
|
|
4117
|
+
Delimiter: "/",
|
|
4118
|
+
MaxKeys: 1e3
|
|
4119
|
+
});
|
|
4120
|
+
let folderCount = 0;
|
|
4121
|
+
let continuationToken;
|
|
4122
|
+
do {
|
|
4123
|
+
if (continuationToken) {
|
|
4124
|
+
command.input.ContinuationToken = continuationToken;
|
|
4125
|
+
}
|
|
4126
|
+
const response = await this.s3Client.send(command);
|
|
4127
|
+
if (response.CommonPrefixes) {
|
|
4128
|
+
folderCount += response.CommonPrefixes.length;
|
|
4129
|
+
}
|
|
4130
|
+
continuationToken = response.NextContinuationToken;
|
|
4131
|
+
} while (continuationToken);
|
|
4132
|
+
return { category, count: folderCount, videos: [] };
|
|
4293
4133
|
}
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
}
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4134
|
+
} catch (error) {
|
|
4135
|
+
console.error(`Error ${buildIndex ? "building index for" : "counting folders for"} category ${category}:`, error);
|
|
4136
|
+
return { category, count: 0, videos: [] };
|
|
4137
|
+
}
|
|
4138
|
+
});
|
|
4139
|
+
const results = await Promise.all(countPromises);
|
|
4140
|
+
for (const { category, count, videos } of results) {
|
|
4141
|
+
counts[category] = count;
|
|
4142
|
+
counts.total += count;
|
|
4143
|
+
if (buildIndex && videoIndex && videos) {
|
|
4144
|
+
if (videos.length > 0) {
|
|
4145
|
+
const parsedType = videos[0].category;
|
|
4146
|
+
videoIndex.byCategory.set(parsedType, videos);
|
|
4147
|
+
console.log(`[S3ClipsService] Indexed ${videos.length} videos under parsed type '${parsedType}'`);
|
|
4148
|
+
if (category !== parsedType) {
|
|
4149
|
+
videoIndex.byCategory.set(category, videos);
|
|
4150
|
+
console.log(`[S3ClipsService] Created alias: S3 folder '${category}' -> parsed type '${parsedType}' (${videos.length} videos)`);
|
|
4311
4151
|
}
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
return { category, count: folderCount, videos: [] };
|
|
4152
|
+
}
|
|
4153
|
+
videoIndex.allVideos.push(...videos);
|
|
4315
4154
|
}
|
|
4316
|
-
} catch (error) {
|
|
4317
|
-
console.error(`Error ${buildIndex ? "building index for" : "counting folders for"} category ${category}:`, error);
|
|
4318
|
-
return { category, count: 0, videos: [] };
|
|
4319
4155
|
}
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
}
|
|
4156
|
+
if (buildIndex && videoIndex) {
|
|
4157
|
+
videoIndex.allVideos.sort((a, b) => b.timestamp.localeCompare(a.timestamp));
|
|
4158
|
+
videoIndex.counts = { ...counts };
|
|
4159
|
+
}
|
|
4160
|
+
const elapsed = performance.now() - startTime;
|
|
4161
|
+
console.log(`[S3ClipsService] ${buildIndex ? "Video index and counts" : "Clip counts"} completed in ${elapsed.toFixed(2)}ms - Total: ${counts.total}`);
|
|
4162
|
+
if (buildIndex && videoIndex) {
|
|
4163
|
+
console.log(`[S3ClipsService] Final video index summary:`);
|
|
4164
|
+
console.log(` - VideoIndex ID: ${videoIndex._debugId}`);
|
|
4165
|
+
console.log(` - Total videos in allVideos: ${videoIndex.allVideos.length}`);
|
|
4166
|
+
console.log(` - Categories in byCategory Map: ${Array.from(videoIndex.byCategory.keys()).join(", ")}`);
|
|
4167
|
+
for (const [cat, vids] of videoIndex.byCategory.entries()) {
|
|
4168
|
+
console.log(` - '${cat}': ${vids.length} videos`);
|
|
4334
4169
|
}
|
|
4335
|
-
videoIndex
|
|
4170
|
+
return { counts, videoIndex };
|
|
4336
4171
|
}
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
const elapsed = performance.now() - startTime;
|
|
4343
|
-
console.log(`[S3ClipsService] ${buildIndex ? "Video index and counts" : "Clip counts"} completed in ${elapsed.toFixed(2)}ms - Total: ${counts.total}`);
|
|
4344
|
-
if (buildIndex && videoIndex) {
|
|
4345
|
-
console.log(`[S3ClipsService] Final video index summary:`);
|
|
4346
|
-
console.log(` - VideoIndex ID: ${videoIndex._debugId}`);
|
|
4347
|
-
console.log(` - Total videos in allVideos: ${videoIndex.allVideos.length}`);
|
|
4348
|
-
console.log(` - Categories in byCategory Map: ${Array.from(videoIndex.byCategory.keys()).join(", ")}`);
|
|
4349
|
-
for (const [cat, vids] of videoIndex.byCategory.entries()) {
|
|
4350
|
-
console.log(` - '${cat}': ${vids.length} videos`);
|
|
4172
|
+
return counts;
|
|
4173
|
+
} finally {
|
|
4174
|
+
if (buildIndex) {
|
|
4175
|
+
this.isIndexBuilding = false;
|
|
4176
|
+
console.log(`[S3ClipsService] Index building complete - metadata fetching re-enabled`);
|
|
4351
4177
|
}
|
|
4352
|
-
return { counts, videoIndex };
|
|
4353
4178
|
}
|
|
4354
|
-
return counts;
|
|
4355
4179
|
}
|
|
4356
4180
|
async getClipCountsCacheFirst(workspaceId, date, shiftId, buildIndex) {
|
|
4357
4181
|
const cacheKey = `clip-counts:${workspaceId}:${date}:${shiftId}`;
|
|
@@ -4445,18 +4269,18 @@ var S3ClipsService = class {
|
|
|
4445
4269
|
* Get a specific clip by index for a category with deduplication
|
|
4446
4270
|
* @deprecated Use getVideoFromIndex with a pre-built VideoIndex for better performance
|
|
4447
4271
|
*/
|
|
4448
|
-
async getClipByIndex(workspaceId, date, shiftId, category, index) {
|
|
4449
|
-
const deduplicationKey = `clip-by-index:${workspaceId}:${date}:${shiftId}:${category}:${index}`;
|
|
4272
|
+
async getClipByIndex(workspaceId, date, shiftId, category, index, includeCycleTime = true, includeMetadata = false) {
|
|
4273
|
+
const deduplicationKey = `clip-by-index:${workspaceId}:${date}:${shiftId}:${category}:${index}:${includeCycleTime}:${includeMetadata}`;
|
|
4450
4274
|
return this.requestCache.deduplicate(
|
|
4451
4275
|
deduplicationKey,
|
|
4452
|
-
() => this.executeGetClipByIndex(workspaceId, date, shiftId, category, index),
|
|
4276
|
+
() => this.executeGetClipByIndex(workspaceId, date, shiftId, category, index, includeCycleTime, includeMetadata),
|
|
4453
4277
|
"ClipByIndex"
|
|
4454
4278
|
);
|
|
4455
4279
|
}
|
|
4456
4280
|
/**
|
|
4457
4281
|
* Internal implementation of clip by index fetching
|
|
4458
4282
|
*/
|
|
4459
|
-
async executeGetClipByIndex(workspaceId, date, shiftId, category, index) {
|
|
4283
|
+
async executeGetClipByIndex(workspaceId, date, shiftId, category, index, includeCycleTime = true, includeMetadata = false) {
|
|
4460
4284
|
const categoryPrefix = `sop_violations/${workspaceId}/${date}/${shiftId}/${category}/videos/`;
|
|
4461
4285
|
try {
|
|
4462
4286
|
const command = new clientS3.ListObjectsV2Command({
|
|
@@ -4494,10 +4318,8 @@ var S3ClipsService = class {
|
|
|
4494
4318
|
workspaceId,
|
|
4495
4319
|
date,
|
|
4496
4320
|
shiftId.toString(),
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
true
|
|
4500
|
-
// includeMetadata
|
|
4321
|
+
includeCycleTime,
|
|
4322
|
+
includeMetadata
|
|
4501
4323
|
);
|
|
4502
4324
|
}
|
|
4503
4325
|
} catch (error) {
|
|
@@ -4568,7 +4390,7 @@ var S3ClipsService = class {
|
|
|
4568
4390
|
}
|
|
4569
4391
|
let cycleTimeSeconds = null;
|
|
4570
4392
|
let creationTimestamp = void 0;
|
|
4571
|
-
if (includeMetadata
|
|
4393
|
+
if (includeMetadata) {
|
|
4572
4394
|
const metadata = await this.getFullMetadata(uri);
|
|
4573
4395
|
if (metadata) {
|
|
4574
4396
|
if (metadata.original_task_metadata?.cycle_time) {
|
|
@@ -4576,6 +4398,8 @@ var S3ClipsService = class {
|
|
|
4576
4398
|
}
|
|
4577
4399
|
creationTimestamp = metadata.upload_timestamp || metadata.original_task_metadata?.timestamp || metadata.creation_timestamp || metadata[""];
|
|
4578
4400
|
}
|
|
4401
|
+
} else if (includeCycleTime && (parsedInfo.type === "bottleneck" && parsedInfo.description.toLowerCase().includes("cycle time") || parsedInfo.type === "best_cycle_time" || parsedInfo.type === "worst_cycle_time" || parsedInfo.type === "cycle_completion")) {
|
|
4402
|
+
cycleTimeSeconds = null;
|
|
4579
4403
|
}
|
|
4580
4404
|
const cloudfrontPlaylistUrl = this.s3UriToCloudfront(uri);
|
|
4581
4405
|
const { type: videoType, timestamp: videoTimestamp } = parsedInfo;
|
|
@@ -5597,7 +5421,6 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
5597
5421
|
const [error, setError] = React19.useState(null);
|
|
5598
5422
|
const updateQueueRef = React19.useRef(false);
|
|
5599
5423
|
const isFetchingRef = React19.useRef(false);
|
|
5600
|
-
const timeoutRef = React19.useRef(null);
|
|
5601
5424
|
const channelRef = React19.useRef(null);
|
|
5602
5425
|
const schema = databaseConfig.schema ?? "public";
|
|
5603
5426
|
const companyId = entityConfig.companyId || "";
|
|
@@ -5606,7 +5429,7 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
5606
5429
|
const defaultTimezone = dateTimeConfig.defaultTimezone;
|
|
5607
5430
|
const workspaceMetricsBaseTable = databaseConfig.tables?.workspaces ?? "workspace_metrics";
|
|
5608
5431
|
const workspaceActionsTable = databaseConfig.tables?.actions ?? "workspace_actions";
|
|
5609
|
-
const fetchMetrics = React19.useCallback(async (
|
|
5432
|
+
const fetchMetrics = React19.useCallback(async () => {
|
|
5610
5433
|
if (!workspaceId || isFetchingRef.current) return;
|
|
5611
5434
|
try {
|
|
5612
5435
|
isFetchingRef.current = true;
|
|
@@ -5615,28 +5438,6 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
5615
5438
|
const queryShiftId = shiftId !== void 0 ? shiftId : currentShift.shiftId;
|
|
5616
5439
|
console.log("[useWorkspaceDetailedMetrics] Using shift ID:", queryShiftId, "from input shift:", shiftId);
|
|
5617
5440
|
console.log("[useWorkspaceDetailedMetrics] Using date:", queryDate, "from input date:", date);
|
|
5618
|
-
const cacheKey = cacheService.generateKey(
|
|
5619
|
-
"workspace-detailed-metrics",
|
|
5620
|
-
workspaceId,
|
|
5621
|
-
queryDate,
|
|
5622
|
-
queryShiftId,
|
|
5623
|
-
companyId
|
|
5624
|
-
);
|
|
5625
|
-
if (!skipCache) {
|
|
5626
|
-
const cachedData = cacheService.get(cacheKey, {
|
|
5627
|
-
storage: "memory",
|
|
5628
|
-
duration: 5 * 60 * 1e3
|
|
5629
|
-
// 5 minutes
|
|
5630
|
-
});
|
|
5631
|
-
if (cachedData) {
|
|
5632
|
-
console.log("[useWorkspaceDetailedMetrics] Using cached data for:", cacheKey);
|
|
5633
|
-
setMetrics(cachedData);
|
|
5634
|
-
setIsLoading(false);
|
|
5635
|
-
updateQueueRef.current = false;
|
|
5636
|
-
isFetchingRef.current = false;
|
|
5637
|
-
return;
|
|
5638
|
-
}
|
|
5639
|
-
}
|
|
5640
5441
|
console.log(`[useWorkspaceDetailedMetrics] Querying ${metricsTable} for workspace: ${workspaceId}, date: ${queryDate}, shift: ${queryShiftId}`);
|
|
5641
5442
|
const { data, error: fetchError } = await supabase.from(metricsTable).select("*").eq("workspace_id", workspaceId).eq("date", queryDate).eq("shift_id", queryShiftId).maybeSingle();
|
|
5642
5443
|
if (fetchError) throw fetchError;
|
|
@@ -5739,18 +5540,6 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
5739
5540
|
setIsLoading(false);
|
|
5740
5541
|
updateQueueRef.current = false;
|
|
5741
5542
|
isFetchingRef.current = false;
|
|
5742
|
-
const fallbackCacheKey = cacheService.generateKey(
|
|
5743
|
-
"workspace-detailed-metrics",
|
|
5744
|
-
workspaceId,
|
|
5745
|
-
recentData.date,
|
|
5746
|
-
recentData.shift_id,
|
|
5747
|
-
companyId
|
|
5748
|
-
);
|
|
5749
|
-
cacheService.set(fallbackCacheKey, transformedData2, {
|
|
5750
|
-
storage: "memory",
|
|
5751
|
-
duration: 2 * 60 * 1e3
|
|
5752
|
-
// 2 minutes for fallback data
|
|
5753
|
-
});
|
|
5754
5543
|
return;
|
|
5755
5544
|
} else {
|
|
5756
5545
|
console.warn("[useWorkspaceDetailedMetrics] No data found for workspace:", workspaceId, "at all");
|
|
@@ -5864,11 +5653,6 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
5864
5653
|
...data.sop_check !== void 0 && { sop_check: data.sop_check }
|
|
5865
5654
|
};
|
|
5866
5655
|
setMetrics(transformedData);
|
|
5867
|
-
cacheService.set(cacheKey, transformedData, {
|
|
5868
|
-
storage: "memory",
|
|
5869
|
-
duration: 5 * 60 * 1e3
|
|
5870
|
-
// 5 minutes
|
|
5871
|
-
});
|
|
5872
5656
|
} catch (err) {
|
|
5873
5657
|
console.error("Error fetching workspace metrics:", err);
|
|
5874
5658
|
setError({ message: err.message, code: err.code });
|
|
@@ -5881,12 +5665,7 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
5881
5665
|
const queueUpdate = React19.useCallback(() => {
|
|
5882
5666
|
if (!workspaceId || updateQueueRef.current) return;
|
|
5883
5667
|
updateQueueRef.current = true;
|
|
5884
|
-
|
|
5885
|
-
clearTimeout(timeoutRef.current);
|
|
5886
|
-
}
|
|
5887
|
-
timeoutRef.current = setTimeout(() => {
|
|
5888
|
-
fetchMetrics();
|
|
5889
|
-
}, 500);
|
|
5668
|
+
fetchMetrics();
|
|
5890
5669
|
}, [fetchMetrics, workspaceId]);
|
|
5891
5670
|
const setupSubscription = React19.useCallback(() => {
|
|
5892
5671
|
if (!workspaceId) return;
|
|
@@ -5903,7 +5682,7 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
5903
5682
|
},
|
|
5904
5683
|
async (payload) => {
|
|
5905
5684
|
console.log(`Received ${metricsTablePrefix} update:`, payload);
|
|
5906
|
-
await fetchMetrics(
|
|
5685
|
+
await fetchMetrics();
|
|
5907
5686
|
}
|
|
5908
5687
|
).subscribe((status) => {
|
|
5909
5688
|
console.log(`Workspace detailed metrics subscription status:`, status);
|
|
@@ -5937,14 +5716,6 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
5937
5716
|
matches: payloadData?.date === operationalDate && payloadData?.shift_id === queryShiftId
|
|
5938
5717
|
});
|
|
5939
5718
|
if (payloadData?.date === operationalDate && payloadData?.shift_id === queryShiftId) {
|
|
5940
|
-
const cacheKey = cacheService.generateKey(
|
|
5941
|
-
"workspace-detailed-metrics",
|
|
5942
|
-
workspaceId,
|
|
5943
|
-
operationalDate,
|
|
5944
|
-
queryShiftId,
|
|
5945
|
-
companyId
|
|
5946
|
-
);
|
|
5947
|
-
cacheService.delete(cacheKey, { storage: "memory" });
|
|
5948
5719
|
queueUpdate();
|
|
5949
5720
|
}
|
|
5950
5721
|
}
|
|
@@ -5970,14 +5741,6 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
5970
5741
|
matches: payloadData?.date === operationalDate && payloadData?.shift_id === queryShiftId
|
|
5971
5742
|
});
|
|
5972
5743
|
if (payloadData?.date === operationalDate && payloadData?.shift_id === queryShiftId) {
|
|
5973
|
-
const cacheKey = cacheService.generateKey(
|
|
5974
|
-
"workspace-detailed-metrics",
|
|
5975
|
-
workspaceId,
|
|
5976
|
-
operationalDate,
|
|
5977
|
-
queryShiftId,
|
|
5978
|
-
companyId
|
|
5979
|
-
);
|
|
5980
|
-
cacheService.delete(cacheKey, { storage: "memory" });
|
|
5981
5744
|
queueUpdate();
|
|
5982
5745
|
}
|
|
5983
5746
|
}
|
|
@@ -6003,14 +5766,6 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
6003
5766
|
matches: payloadData?.date === operationalDate && payloadData?.shift_id === queryShiftId
|
|
6004
5767
|
});
|
|
6005
5768
|
if (payloadData?.date === operationalDate && payloadData?.shift_id === queryShiftId) {
|
|
6006
|
-
const cacheKey = cacheService.generateKey(
|
|
6007
|
-
"workspace-detailed-metrics",
|
|
6008
|
-
workspaceId,
|
|
6009
|
-
operationalDate,
|
|
6010
|
-
queryShiftId,
|
|
6011
|
-
companyId
|
|
6012
|
-
);
|
|
6013
|
-
cacheService.delete(cacheKey, { storage: "memory" });
|
|
6014
5769
|
queueUpdate();
|
|
6015
5770
|
}
|
|
6016
5771
|
}
|
|
@@ -6021,9 +5776,6 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
6021
5776
|
fetchMetrics();
|
|
6022
5777
|
setupSubscription();
|
|
6023
5778
|
return () => {
|
|
6024
|
-
if (timeoutRef.current) {
|
|
6025
|
-
clearTimeout(timeoutRef.current);
|
|
6026
|
-
}
|
|
6027
5779
|
channels.forEach((channel) => {
|
|
6028
5780
|
console.log("Cleaning up channel subscription");
|
|
6029
5781
|
supabase.removeChannel(channel);
|
|
@@ -6037,7 +5789,7 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
6037
5789
|
metrics: metrics2,
|
|
6038
5790
|
isLoading,
|
|
6039
5791
|
error,
|
|
6040
|
-
refetch: () => fetchMetrics(
|
|
5792
|
+
refetch: () => fetchMetrics()
|
|
6041
5793
|
// Force refresh without cache
|
|
6042
5794
|
};
|
|
6043
5795
|
};
|
|
@@ -6482,33 +6234,6 @@ var useLeaderboardMetrics = (lineId, topCount = 10) => {
|
|
|
6482
6234
|
refetch: fetchLeaderboardData
|
|
6483
6235
|
};
|
|
6484
6236
|
};
|
|
6485
|
-
var CACHE_KEY_PREFIX = "dashboard_metrics_cache_";
|
|
6486
|
-
var CACHE_DURATION = 5 * 60 * 1e3;
|
|
6487
|
-
var getCache = (lineId) => {
|
|
6488
|
-
if (typeof window === "undefined") return null;
|
|
6489
|
-
try {
|
|
6490
|
-
const cached = localStorage.getItem(`${CACHE_KEY_PREFIX}${lineId}`);
|
|
6491
|
-
if (!cached) return null;
|
|
6492
|
-
const parsedCache = JSON.parse(cached);
|
|
6493
|
-
if (!parsedCache.lastUpdated || Date.now() - parsedCache.lastUpdated > CACHE_DURATION) {
|
|
6494
|
-
localStorage.removeItem(`${CACHE_KEY_PREFIX}${lineId}`);
|
|
6495
|
-
return null;
|
|
6496
|
-
}
|
|
6497
|
-
return parsedCache;
|
|
6498
|
-
} catch {
|
|
6499
|
-
return null;
|
|
6500
|
-
}
|
|
6501
|
-
};
|
|
6502
|
-
var setCache = (lineId, metrics2) => {
|
|
6503
|
-
if (typeof window === "undefined") return;
|
|
6504
|
-
try {
|
|
6505
|
-
localStorage.setItem(`${CACHE_KEY_PREFIX}${lineId}`, JSON.stringify({
|
|
6506
|
-
...metrics2,
|
|
6507
|
-
lastUpdated: Date.now()
|
|
6508
|
-
}));
|
|
6509
|
-
} catch {
|
|
6510
|
-
}
|
|
6511
|
-
};
|
|
6512
6237
|
var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
|
|
6513
6238
|
const { supabaseUrl, supabaseKey } = useDashboardConfig();
|
|
6514
6239
|
const entityConfig = useEntityConfig();
|
|
@@ -6519,22 +6244,20 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
|
|
|
6519
6244
|
const configuredLineMetricsTable = databaseConfig?.tables?.lineMetrics ?? "line_metrics";
|
|
6520
6245
|
const schema = databaseConfig?.schema ?? "public";
|
|
6521
6246
|
const supabase = useSupabase();
|
|
6522
|
-
const [metrics2, setMetrics] = React19.useState(
|
|
6523
|
-
const [isLoading, setIsLoading] = React19.useState(
|
|
6247
|
+
const [metrics2, setMetrics] = React19.useState({ workspaceMetrics: [], lineMetrics: [] });
|
|
6248
|
+
const [isLoading, setIsLoading] = React19.useState(true);
|
|
6524
6249
|
const [error, setError] = React19.useState(null);
|
|
6525
6250
|
const lineIdRef = React19.useRef(lineId);
|
|
6526
6251
|
const isFetchingRef = React19.useRef(false);
|
|
6527
6252
|
const updateQueueRef = React19.useRef(false);
|
|
6528
|
-
const timeoutRef = React19.useRef(null);
|
|
6529
6253
|
const companySpecificMetricsTable = React19.useMemo(
|
|
6530
6254
|
() => getCompanyMetricsTableName(entityConfig.companyId, "performance_metrics"),
|
|
6531
6255
|
[entityConfig.companyId]
|
|
6532
6256
|
);
|
|
6533
6257
|
React19.useEffect(() => {
|
|
6534
6258
|
lineIdRef.current = lineId;
|
|
6535
|
-
|
|
6536
|
-
|
|
6537
|
-
setIsLoading(!cachedData);
|
|
6259
|
+
setMetrics({ workspaceMetrics: [], lineMetrics: [] });
|
|
6260
|
+
setIsLoading(true);
|
|
6538
6261
|
}, [lineId]);
|
|
6539
6262
|
const fetchAllMetrics = React19.useCallback(async () => {
|
|
6540
6263
|
const currentLineIdToUse = lineIdRef.current;
|
|
@@ -6546,9 +6269,7 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
|
|
|
6546
6269
|
return;
|
|
6547
6270
|
}
|
|
6548
6271
|
isFetchingRef.current = true;
|
|
6549
|
-
|
|
6550
|
-
setIsLoading(true);
|
|
6551
|
-
}
|
|
6272
|
+
setIsLoading(true);
|
|
6552
6273
|
setError(null);
|
|
6553
6274
|
try {
|
|
6554
6275
|
const currentShiftDetails = getCurrentShift(defaultTimezone, shiftConfig);
|
|
@@ -6573,7 +6294,6 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
|
|
|
6573
6294
|
lineMetrics: []
|
|
6574
6295
|
};
|
|
6575
6296
|
setMetrics(newMetricsState2);
|
|
6576
|
-
setCache(currentLineIdToUse, newMetricsState2);
|
|
6577
6297
|
return;
|
|
6578
6298
|
}
|
|
6579
6299
|
let workspaceQuery = supabase.from(companySpecificMetricsTable).select("company_id,line_id,shift_id,date,workspace_id,workspace_name,total_output,avg_pph,performance_score,avg_cycle_time,trend_score,ideal_output,efficiency,total_day_output").eq("date", operationalDate).eq("shift_id", currentShiftDetails.shiftId).in("workspace_id", enabledWorkspaceIds);
|
|
@@ -6625,7 +6345,6 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
|
|
|
6625
6345
|
lineMetrics: lineData || []
|
|
6626
6346
|
};
|
|
6627
6347
|
setMetrics(newMetricsState);
|
|
6628
|
-
setCache(currentLineIdToUse, newMetricsState);
|
|
6629
6348
|
} catch (err) {
|
|
6630
6349
|
setError({ message: err.message, code: err.code || "FETCH_ERROR" });
|
|
6631
6350
|
} finally {
|
|
@@ -6651,12 +6370,7 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
|
|
|
6651
6370
|
return;
|
|
6652
6371
|
}
|
|
6653
6372
|
updateQueueRef.current = true;
|
|
6654
|
-
|
|
6655
|
-
clearTimeout(timeoutRef.current);
|
|
6656
|
-
}
|
|
6657
|
-
timeoutRef.current = setTimeout(() => {
|
|
6658
|
-
fetchAllMetrics();
|
|
6659
|
-
}, 500);
|
|
6373
|
+
fetchAllMetrics();
|
|
6660
6374
|
}, [fetchAllMetrics, supabase]);
|
|
6661
6375
|
React19.useEffect(() => {
|
|
6662
6376
|
if (lineId && supabase) {
|
|
@@ -6701,9 +6415,6 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
|
|
|
6701
6415
|
onLineMetricsUpdate?.();
|
|
6702
6416
|
});
|
|
6703
6417
|
return () => {
|
|
6704
|
-
if (timeoutRef.current) {
|
|
6705
|
-
clearTimeout(timeoutRef.current);
|
|
6706
|
-
}
|
|
6707
6418
|
channels.forEach((channel) => {
|
|
6708
6419
|
supabase?.removeChannel(channel).catch((err) => console.error("[useDashboardMetrics] Error removing channel:", err.message));
|
|
6709
6420
|
});
|
|
@@ -6732,30 +6443,6 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
|
|
|
6732
6443
|
refetch: fetchAllMetrics
|
|
6733
6444
|
};
|
|
6734
6445
|
};
|
|
6735
|
-
var CACHE_KEY_PREFIX2 = "line_kpis_cache_";
|
|
6736
|
-
var CACHE_DURATION2 = 5 * 60 * 1e3;
|
|
6737
|
-
var getCache2 = (lineId) => {
|
|
6738
|
-
if (typeof window === "undefined") return null;
|
|
6739
|
-
try {
|
|
6740
|
-
const cached = localStorage.getItem(`${CACHE_KEY_PREFIX2}${lineId}`);
|
|
6741
|
-
if (!cached) return null;
|
|
6742
|
-
const parsedCache = JSON.parse(cached);
|
|
6743
|
-
if (!parsedCache.timestamp || Date.now() - parsedCache.timestamp > CACHE_DURATION2) {
|
|
6744
|
-
localStorage.removeItem(`${CACHE_KEY_PREFIX2}${lineId}`);
|
|
6745
|
-
return null;
|
|
6746
|
-
}
|
|
6747
|
-
return parsedCache.data;
|
|
6748
|
-
} catch (error) {
|
|
6749
|
-
return null;
|
|
6750
|
-
}
|
|
6751
|
-
};
|
|
6752
|
-
var setCache2 = (lineId, data) => {
|
|
6753
|
-
if (typeof window === "undefined") return;
|
|
6754
|
-
try {
|
|
6755
|
-
localStorage.setItem(`${CACHE_KEY_PREFIX2}${lineId}`, JSON.stringify({ data, timestamp: Date.now() }));
|
|
6756
|
-
} catch (error) {
|
|
6757
|
-
}
|
|
6758
|
-
};
|
|
6759
6446
|
var useLineKPIs = ({ lineId }) => {
|
|
6760
6447
|
useDashboardConfig();
|
|
6761
6448
|
const entityConfig = useEntityConfig();
|
|
@@ -6767,13 +6454,12 @@ var useLineKPIs = ({ lineId }) => {
|
|
|
6767
6454
|
const dashboardServiceInstance = React19.useMemo(() => {
|
|
6768
6455
|
return dashboardService;
|
|
6769
6456
|
}, []);
|
|
6770
|
-
const [kpis, setKPIs] = React19.useState(
|
|
6771
|
-
const [isLoading, setIsLoading] = React19.useState(
|
|
6457
|
+
const [kpis, setKPIs] = React19.useState(null);
|
|
6458
|
+
const [isLoading, setIsLoading] = React19.useState(true);
|
|
6772
6459
|
const [error, setError] = React19.useState(null);
|
|
6773
6460
|
const lineIdRef = React19.useRef(lineId);
|
|
6774
6461
|
const isFetchingRef = React19.useRef(false);
|
|
6775
6462
|
const updateQueueRef = React19.useRef(false);
|
|
6776
|
-
const timeoutRef = React19.useRef(null);
|
|
6777
6463
|
const defaultTimezone = dateTimeConfig.defaultTimezone;
|
|
6778
6464
|
const schema = databaseConfig.schema ?? "public";
|
|
6779
6465
|
const lineMetricsTable = databaseConfig.tables?.lineMetrics ?? "line_metrics";
|
|
@@ -6804,7 +6490,6 @@ var useLineKPIs = ({ lineId }) => {
|
|
|
6804
6490
|
if (lineInfo) {
|
|
6805
6491
|
const newKPIs = dashboardServiceInstance.calculateKPIs(lineInfo);
|
|
6806
6492
|
setKPIs(newKPIs);
|
|
6807
|
-
setCache2(currentLineId, newKPIs);
|
|
6808
6493
|
} else {
|
|
6809
6494
|
setKPIs(null);
|
|
6810
6495
|
}
|
|
@@ -6821,12 +6506,7 @@ var useLineKPIs = ({ lineId }) => {
|
|
|
6821
6506
|
const queueUpdate = React19.useCallback(() => {
|
|
6822
6507
|
if (updateQueueRef.current) return;
|
|
6823
6508
|
updateQueueRef.current = true;
|
|
6824
|
-
|
|
6825
|
-
clearTimeout(timeoutRef.current);
|
|
6826
|
-
}
|
|
6827
|
-
timeoutRef.current = setTimeout(() => {
|
|
6828
|
-
fetchKPIs();
|
|
6829
|
-
}, 500);
|
|
6509
|
+
fetchKPIs();
|
|
6830
6510
|
}, [fetchKPIs]);
|
|
6831
6511
|
React19.useEffect(() => {
|
|
6832
6512
|
const currentLineId = lineIdRef.current;
|
|
@@ -6884,9 +6564,6 @@ var useLineKPIs = ({ lineId }) => {
|
|
|
6884
6564
|
activeChannels.push(csChannel);
|
|
6885
6565
|
}
|
|
6886
6566
|
return () => {
|
|
6887
|
-
if (timeoutRef.current) {
|
|
6888
|
-
clearTimeout(timeoutRef.current);
|
|
6889
|
-
}
|
|
6890
6567
|
activeChannels.forEach((ch) => supabase.removeChannel(ch).catch((err) => console.error("[useLineKPIs] Error removing KPI channel:", err)));
|
|
6891
6568
|
};
|
|
6892
6569
|
}, [supabase, lineId, fetchKPIs, queueUpdate, dashboardServiceInstance, entityConfig, schema, lineMetricsTable, companySpecificMetricsTable, defaultTimezone, shiftConfig, kpis, isFactoryView]);
|
|
@@ -6915,7 +6592,6 @@ var useRealtimeLineMetrics = ({
|
|
|
6915
6592
|
const [initialized, setInitialized] = React19.useState(false);
|
|
6916
6593
|
const lineIdRef = React19.useRef(null);
|
|
6917
6594
|
const updateQueueRef = React19.useRef(false);
|
|
6918
|
-
const timeoutRef = React19.useRef(null);
|
|
6919
6595
|
const isFetchingRef = React19.useRef(false);
|
|
6920
6596
|
const channelsRef = React19.useRef([]);
|
|
6921
6597
|
const currentShift = React19.useMemo(() => getCurrentShift(dateTimeConfig.defaultTimezone || "Asia/Kolkata", shiftConfig), [dateTimeConfig.defaultTimezone, shiftConfig]);
|
|
@@ -7128,12 +6804,7 @@ var useRealtimeLineMetrics = ({
|
|
|
7128
6804
|
const queueUpdate = React19.useCallback(() => {
|
|
7129
6805
|
if (updateQueueRef.current) return;
|
|
7130
6806
|
updateQueueRef.current = true;
|
|
7131
|
-
|
|
7132
|
-
clearTimeout(timeoutRef.current);
|
|
7133
|
-
}
|
|
7134
|
-
timeoutRef.current = setTimeout(() => {
|
|
7135
|
-
fetchData();
|
|
7136
|
-
}, 500);
|
|
6807
|
+
fetchData();
|
|
7137
6808
|
}, [fetchData]);
|
|
7138
6809
|
const setupSubscriptions = React19.useCallback(() => {
|
|
7139
6810
|
if (channelsRef.current.length > 0) {
|
|
@@ -7211,9 +6882,6 @@ var useRealtimeLineMetrics = ({
|
|
|
7211
6882
|
}
|
|
7212
6883
|
setupSubscriptions();
|
|
7213
6884
|
return () => {
|
|
7214
|
-
if (timeoutRef.current) {
|
|
7215
|
-
clearTimeout(timeoutRef.current);
|
|
7216
|
-
}
|
|
7217
6885
|
if (channelsRef.current.length > 0) {
|
|
7218
6886
|
channelsRef.current.forEach((channel) => {
|
|
7219
6887
|
if (process.env.NODE_ENV === "development") {
|
|
@@ -8501,32 +8169,12 @@ var useAllWorkspaceMetrics = (options) => {
|
|
|
8501
8169
|
return `${metricsTablePrefix}_${companyId.replace(/-/g, "_")}`;
|
|
8502
8170
|
}, [entityConfig.companyId]);
|
|
8503
8171
|
const schema = databaseConfig.schema ?? "public";
|
|
8504
|
-
const fetchWorkspaceMetrics = React19.useCallback(async (
|
|
8172
|
+
const fetchWorkspaceMetrics = React19.useCallback(async () => {
|
|
8505
8173
|
if (!initialized) {
|
|
8506
8174
|
setLoading(true);
|
|
8507
8175
|
}
|
|
8508
8176
|
setError(null);
|
|
8509
8177
|
try {
|
|
8510
|
-
const cacheKey = cacheService.generateKey(
|
|
8511
|
-
"all-workspace-metrics",
|
|
8512
|
-
entityConfig.companyId,
|
|
8513
|
-
queryDate,
|
|
8514
|
-
queryShiftId
|
|
8515
|
-
);
|
|
8516
|
-
if (!skipCache && !loading) {
|
|
8517
|
-
const cachedData = cacheService.get(cacheKey, {
|
|
8518
|
-
storage: "memory",
|
|
8519
|
-
duration: 5 * 60 * 1e3
|
|
8520
|
-
// 5 minutes
|
|
8521
|
-
});
|
|
8522
|
-
if (cachedData) {
|
|
8523
|
-
console.log("[useAllWorkspaceMetrics] Using cached data for:", cacheKey);
|
|
8524
|
-
setWorkspaces(cachedData);
|
|
8525
|
-
setInitialized(true);
|
|
8526
|
-
setLoading(false);
|
|
8527
|
-
return;
|
|
8528
|
-
}
|
|
8529
|
-
}
|
|
8530
8178
|
console.log("Fetching all workspace metrics with params:", {
|
|
8531
8179
|
queryDate,
|
|
8532
8180
|
queryShiftId,
|
|
@@ -8576,11 +8224,6 @@ var useAllWorkspaceMetrics = (options) => {
|
|
|
8576
8224
|
}));
|
|
8577
8225
|
setWorkspaces(transformedData);
|
|
8578
8226
|
setInitialized(true);
|
|
8579
|
-
cacheService.set(cacheKey, transformedData, {
|
|
8580
|
-
storage: "memory",
|
|
8581
|
-
duration: 5 * 60 * 1e3
|
|
8582
|
-
// 5 minutes
|
|
8583
|
-
});
|
|
8584
8227
|
} catch (err) {
|
|
8585
8228
|
console.error("Error fetching all workspace metrics:", err);
|
|
8586
8229
|
setError({ message: err.message, code: err.code || "FETCH_ERROR" });
|
|
@@ -8605,14 +8248,7 @@ var useAllWorkspaceMetrics = (options) => {
|
|
|
8605
8248
|
},
|
|
8606
8249
|
async (payload) => {
|
|
8607
8250
|
console.log("All workspace metrics update received:", payload);
|
|
8608
|
-
|
|
8609
|
-
"all-workspace-metrics",
|
|
8610
|
-
entityConfig.companyId,
|
|
8611
|
-
queryDate,
|
|
8612
|
-
queryShiftId
|
|
8613
|
-
);
|
|
8614
|
-
cacheService.delete(cacheKey, { storage: "memory" });
|
|
8615
|
-
await fetchWorkspaceMetrics(true);
|
|
8251
|
+
await fetchWorkspaceMetrics();
|
|
8616
8252
|
}
|
|
8617
8253
|
).subscribe();
|
|
8618
8254
|
return channel2;
|
|
@@ -8627,7 +8263,7 @@ var useAllWorkspaceMetrics = (options) => {
|
|
|
8627
8263
|
React19.useEffect(() => {
|
|
8628
8264
|
setInitialized(false);
|
|
8629
8265
|
}, [queryDate, queryShiftId]);
|
|
8630
|
-
const refreshWorkspaces = React19.useCallback(() => fetchWorkspaceMetrics(
|
|
8266
|
+
const refreshWorkspaces = React19.useCallback(() => fetchWorkspaceMetrics(), [fetchWorkspaceMetrics]);
|
|
8631
8267
|
return React19.useMemo(
|
|
8632
8268
|
() => ({ workspaces, loading, error, refreshWorkspaces }),
|
|
8633
8269
|
[workspaces, loading, error, refreshWorkspaces]
|
|
@@ -12080,8 +11716,11 @@ var useHourlyTargetAchievements = ({
|
|
|
12080
11716
|
targetThreshold,
|
|
12081
11717
|
enabled
|
|
12082
11718
|
});
|
|
12083
|
-
|
|
12084
|
-
|
|
11719
|
+
let currentHourIndex = hourlyData.length - 1;
|
|
11720
|
+
while (currentHourIndex >= 0 && (hourlyData[currentHourIndex] === void 0 || hourlyData[currentHourIndex] === 0)) {
|
|
11721
|
+
currentHourIndex--;
|
|
11722
|
+
}
|
|
11723
|
+
if (currentHourIndex < 0) {
|
|
12085
11724
|
console.log("[HOURLY TARGET CHECK] No hourly data available");
|
|
12086
11725
|
return;
|
|
12087
11726
|
}
|
|
@@ -12179,8 +11818,11 @@ var useHourlyTargetMisses = ({
|
|
|
12179
11818
|
targetThreshold,
|
|
12180
11819
|
enabled
|
|
12181
11820
|
});
|
|
12182
|
-
|
|
12183
|
-
|
|
11821
|
+
let currentHourIndex = hourlyData.length - 1;
|
|
11822
|
+
while (currentHourIndex >= 0 && (hourlyData[currentHourIndex] === void 0 || hourlyData[currentHourIndex] === 0)) {
|
|
11823
|
+
currentHourIndex--;
|
|
11824
|
+
}
|
|
11825
|
+
if (currentHourIndex < 0) {
|
|
12184
11826
|
console.log("[HOURLY TARGET MISS CHECK] No hourly data available");
|
|
12185
11827
|
return;
|
|
12186
11828
|
}
|
|
@@ -26629,6 +26271,85 @@ var BottlenecksContent = ({
|
|
|
26629
26271
|
}, [workspaceId, date, s3ClipsService, shift, dashboardConfig, updateClipCounts, updateVideoIndex]);
|
|
26630
26272
|
const loadingCategoryRef = React19.useRef(null);
|
|
26631
26273
|
const videoRetryCountRef = React19.useRef(0);
|
|
26274
|
+
const loadingVideosRef = React19.useRef(/* @__PURE__ */ new Set());
|
|
26275
|
+
const loadedVideosMapRef = React19.useRef(/* @__PURE__ */ new Map());
|
|
26276
|
+
const ensureVideosLoaded = React19.useCallback(async (centerIndex) => {
|
|
26277
|
+
if (!s3ClipsService || !workspaceId || !isMountedRef.current) return;
|
|
26278
|
+
const currentFilter = activeFilterRef.current;
|
|
26279
|
+
const currentVideoIndex = videoIndexRef.current;
|
|
26280
|
+
let effectiveFilter = currentFilter;
|
|
26281
|
+
if (sopCategories && sopCategories.length > 0) {
|
|
26282
|
+
const category = sopCategories.find((cat) => cat.id === currentFilter);
|
|
26283
|
+
if (category && category.s3FolderName) {
|
|
26284
|
+
effectiveFilter = category.s3FolderName;
|
|
26285
|
+
}
|
|
26286
|
+
}
|
|
26287
|
+
const cacheKey = `${effectiveFilter}:${date}:${shift}`;
|
|
26288
|
+
if (!loadedVideosMapRef.current.has(cacheKey)) {
|
|
26289
|
+
loadedVideosMapRef.current.set(cacheKey, /* @__PURE__ */ new Set());
|
|
26290
|
+
}
|
|
26291
|
+
const loadedIndices = loadedVideosMapRef.current.get(cacheKey);
|
|
26292
|
+
const indicesToLoad = [];
|
|
26293
|
+
const rangeBefore = 1;
|
|
26294
|
+
const rangeAfter = 3;
|
|
26295
|
+
for (let i = Math.max(0, centerIndex - rangeBefore); i <= Math.min(clipCounts[effectiveFilter] - 1, centerIndex + rangeAfter); i++) {
|
|
26296
|
+
if (!loadedIndices.has(i) && !loadingVideosRef.current.has(i)) {
|
|
26297
|
+
indicesToLoad.push(i);
|
|
26298
|
+
}
|
|
26299
|
+
}
|
|
26300
|
+
if (indicesToLoad.length === 0) return;
|
|
26301
|
+
console.log(`[ensureVideosLoaded] Preloading ${indicesToLoad.length} videos around index ${centerIndex}: [${indicesToLoad.join(", ")}]`);
|
|
26302
|
+
indicesToLoad.forEach((idx) => loadingVideosRef.current.add(idx));
|
|
26303
|
+
const loadPromises = indicesToLoad.map(async (index) => {
|
|
26304
|
+
try {
|
|
26305
|
+
let video = null;
|
|
26306
|
+
if (currentVideoIndex && currentVideoIndex.byCategory && currentVideoIndex.allVideos.length > 0) {
|
|
26307
|
+
video = await s3ClipsService.getVideoFromIndex(
|
|
26308
|
+
currentVideoIndex,
|
|
26309
|
+
effectiveFilter,
|
|
26310
|
+
index,
|
|
26311
|
+
true,
|
|
26312
|
+
// includeCycleTime - OK for preloading
|
|
26313
|
+
true
|
|
26314
|
+
// includeMetadata - OK for just +3/-1 videos, not ALL videos
|
|
26315
|
+
);
|
|
26316
|
+
}
|
|
26317
|
+
if (!video) {
|
|
26318
|
+
const operationalDate = date || getOperationalDate();
|
|
26319
|
+
const shiftStr = shift?.toString() || "0";
|
|
26320
|
+
video = await s3ClipsService.getClipByIndex(
|
|
26321
|
+
workspaceId,
|
|
26322
|
+
operationalDate,
|
|
26323
|
+
shiftStr,
|
|
26324
|
+
effectiveFilter,
|
|
26325
|
+
index,
|
|
26326
|
+
true,
|
|
26327
|
+
// includeCycleTime - OK for preloading
|
|
26328
|
+
true
|
|
26329
|
+
// includeMetadata - OK for just +3/-1 videos, not ALL videos
|
|
26330
|
+
);
|
|
26331
|
+
}
|
|
26332
|
+
if (video && isMountedRef.current) {
|
|
26333
|
+
setAllVideos((prev) => {
|
|
26334
|
+
const exists = prev.some((v) => v.id === video.id);
|
|
26335
|
+
if (!exists) {
|
|
26336
|
+
return [...prev, video];
|
|
26337
|
+
}
|
|
26338
|
+
return prev;
|
|
26339
|
+
});
|
|
26340
|
+
loadedIndices.add(index);
|
|
26341
|
+
preloadVideoUrl(video.src);
|
|
26342
|
+
}
|
|
26343
|
+
} catch (error2) {
|
|
26344
|
+
console.warn(`[ensureVideosLoaded] Failed to load video at index ${index}:`, error2);
|
|
26345
|
+
} finally {
|
|
26346
|
+
loadingVideosRef.current.delete(index);
|
|
26347
|
+
}
|
|
26348
|
+
});
|
|
26349
|
+
Promise.all(loadPromises).catch((err) => {
|
|
26350
|
+
console.warn("[ensureVideosLoaded] Some videos failed to preload:", err);
|
|
26351
|
+
});
|
|
26352
|
+
}, [s3ClipsService, workspaceId, clipCounts, sopCategories, date, shift]);
|
|
26632
26353
|
const loadFirstVideoForCategory = React19.useCallback(async (category) => {
|
|
26633
26354
|
if (!workspaceId || !s3ClipsService || !isMountedRef.current) return;
|
|
26634
26355
|
const targetCategory = category || activeFilterRef.current;
|
|
@@ -26731,9 +26452,11 @@ var BottlenecksContent = ({
|
|
|
26731
26452
|
}, [prefetchData, prefetchStatus, updateClipCounts, updateVideoIndex, hasInitialLoad]);
|
|
26732
26453
|
React19.useEffect(() => {
|
|
26733
26454
|
if (s3ClipsService && videoIndex && clipCounts[activeFilter] > 0) {
|
|
26734
|
-
|
|
26455
|
+
if (allVideos.length === 0) {
|
|
26456
|
+
loadFirstVideoForCategory(activeFilter);
|
|
26457
|
+
}
|
|
26735
26458
|
}
|
|
26736
|
-
}, [activeFilter, s3ClipsService, videoIndex, clipCounts, loadFirstVideoForCategory]);
|
|
26459
|
+
}, [activeFilter, s3ClipsService, videoIndex, clipCounts, loadFirstVideoForCategory, allVideos.length]);
|
|
26737
26460
|
React19.useEffect(() => {
|
|
26738
26461
|
if (previousFilterRef.current !== activeFilter) {
|
|
26739
26462
|
console.log(`Filter changed from ${previousFilterRef.current} to ${activeFilter} - resetting to first video`);
|
|
@@ -26802,26 +26525,25 @@ var BottlenecksContent = ({
|
|
|
26802
26525
|
return new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime();
|
|
26803
26526
|
});
|
|
26804
26527
|
}, [activeFilter, allVideos, sopCategories]);
|
|
26805
|
-
React19.useEffect(() => {
|
|
26806
|
-
if (filteredVideos.length === 0) return;
|
|
26807
|
-
const upcoming = [];
|
|
26808
|
-
if (currentIndex + 1 < filteredVideos.length && filteredVideos[currentIndex + 1]) {
|
|
26809
|
-
upcoming.push(filteredVideos[currentIndex + 1].src);
|
|
26810
|
-
}
|
|
26811
|
-
if (currentIndex - 1 >= 0 && currentIndex - 1 < filteredVideos.length && filteredVideos[currentIndex - 1]) {
|
|
26812
|
-
upcoming.push(filteredVideos[currentIndex - 1].src);
|
|
26813
|
-
}
|
|
26814
|
-
if (upcoming.length > 0) {
|
|
26815
|
-
preloadVideosUrl(upcoming);
|
|
26816
|
-
}
|
|
26817
|
-
}, [currentIndex, filteredVideos]);
|
|
26818
26528
|
React19.useEffect(() => {
|
|
26819
26529
|
if (isNavigating && currentIndex < filteredVideos.length) {
|
|
26820
26530
|
setIsNavigating(false);
|
|
26821
26531
|
setError(null);
|
|
26822
26532
|
videoRetryCountRef.current = 0;
|
|
26533
|
+
ensureVideosLoaded(currentIndex);
|
|
26823
26534
|
}
|
|
26824
26535
|
}, [isNavigating, currentIndex, filteredVideos.length]);
|
|
26536
|
+
React19.useEffect(() => {
|
|
26537
|
+
if (!isPlaying || !isMountedRef.current) return;
|
|
26538
|
+
const preloadInterval = setInterval(() => {
|
|
26539
|
+
if (isMountedRef.current) {
|
|
26540
|
+
const currentIdx = currentIndexRef.current;
|
|
26541
|
+
console.log(`[Background Preloader] Ensuring videos loaded around index ${currentIdx}`);
|
|
26542
|
+
ensureVideosLoaded(currentIdx);
|
|
26543
|
+
}
|
|
26544
|
+
}, 2e3);
|
|
26545
|
+
return () => clearInterval(preloadInterval);
|
|
26546
|
+
}, [isPlaying]);
|
|
26825
26547
|
const handleNext = React19.useCallback(async () => {
|
|
26826
26548
|
if (!isMountedRef.current) return;
|
|
26827
26549
|
const currentIdx = currentIndexRef.current;
|
|
@@ -26842,6 +26564,7 @@ var BottlenecksContent = ({
|
|
|
26842
26564
|
}
|
|
26843
26565
|
if (nextIndex < filteredVideos.length) {
|
|
26844
26566
|
setIsNavigating(false);
|
|
26567
|
+
ensureVideosLoaded(nextIndex);
|
|
26845
26568
|
return;
|
|
26846
26569
|
}
|
|
26847
26570
|
if (isMountedRef.current) {
|
|
@@ -26859,8 +26582,8 @@ var BottlenecksContent = ({
|
|
|
26859
26582
|
nextIndex,
|
|
26860
26583
|
true,
|
|
26861
26584
|
// includeCycleTime
|
|
26862
|
-
|
|
26863
|
-
// includeMetadata
|
|
26585
|
+
false
|
|
26586
|
+
// includeMetadata - DON'T fetch metadata during navigation to prevent flooding!
|
|
26864
26587
|
);
|
|
26865
26588
|
} else {
|
|
26866
26589
|
console.warn(`[BottlenecksContent] Video index not ready for navigation: ID: ${currentVideoIndex?._debugId || "NO_ID"}, byCategory exists = ${!!currentVideoIndex?.byCategory}, allVideos = ${currentVideoIndex?.allVideos?.length || 0}`);
|
|
@@ -26873,7 +26596,11 @@ var BottlenecksContent = ({
|
|
|
26873
26596
|
operationalDate,
|
|
26874
26597
|
shiftStr,
|
|
26875
26598
|
effectiveFilter,
|
|
26876
|
-
nextIndex
|
|
26599
|
+
nextIndex,
|
|
26600
|
+
true,
|
|
26601
|
+
// includeCycleTime - needed for main video display
|
|
26602
|
+
false
|
|
26603
|
+
// includeMetadata - DON'T fetch metadata during navigation to prevent flooding!
|
|
26877
26604
|
);
|
|
26878
26605
|
}
|
|
26879
26606
|
if (video && isMountedRef.current) {
|
|
@@ -26886,26 +26613,7 @@ var BottlenecksContent = ({
|
|
|
26886
26613
|
return prev;
|
|
26887
26614
|
});
|
|
26888
26615
|
preloadVideoUrl(video.src);
|
|
26889
|
-
|
|
26890
|
-
setTimeout(() => {
|
|
26891
|
-
const videoIndexForPreload = videoIndexRef.current;
|
|
26892
|
-
if (videoIndexForPreload && s3ClipsService && isMountedRef.current) {
|
|
26893
|
-
s3ClipsService.getVideoFromIndex(videoIndexForPreload, effectiveFilter, nextIndex + 1, true, true).then((nextVideo) => {
|
|
26894
|
-
if (nextVideo && isMountedRef.current) {
|
|
26895
|
-
setAllVideos((prev) => {
|
|
26896
|
-
if (!prev.some((v) => v.id === nextVideo.id)) {
|
|
26897
|
-
const newVideos = [...prev, nextVideo];
|
|
26898
|
-
return newVideos;
|
|
26899
|
-
}
|
|
26900
|
-
return prev;
|
|
26901
|
-
});
|
|
26902
|
-
preloadVideoUrl(nextVideo.src);
|
|
26903
|
-
}
|
|
26904
|
-
}).catch(() => {
|
|
26905
|
-
});
|
|
26906
|
-
}
|
|
26907
|
-
}, 100);
|
|
26908
|
-
}
|
|
26616
|
+
ensureVideosLoaded(nextIndex);
|
|
26909
26617
|
}
|
|
26910
26618
|
} catch (error2) {
|
|
26911
26619
|
console.error("Error loading next video:", error2);
|
|
@@ -26927,6 +26635,7 @@ var BottlenecksContent = ({
|
|
|
26927
26635
|
if (prevIndex < filteredVideos.length) {
|
|
26928
26636
|
setCurrentIndex(prevIndex);
|
|
26929
26637
|
setError(null);
|
|
26638
|
+
ensureVideosLoaded(prevIndex);
|
|
26930
26639
|
}
|
|
26931
26640
|
}
|
|
26932
26641
|
}, [filteredVideos.length]);
|
|
@@ -26935,6 +26644,8 @@ var BottlenecksContent = ({
|
|
|
26935
26644
|
}, []);
|
|
26936
26645
|
const handleVideoPlay = React19.useCallback((player) => {
|
|
26937
26646
|
setIsPlaying(true);
|
|
26647
|
+
const currentIdx = currentIndexRef.current;
|
|
26648
|
+
ensureVideosLoaded(currentIdx);
|
|
26938
26649
|
}, []);
|
|
26939
26650
|
const handleVideoPause = React19.useCallback((player) => {
|
|
26940
26651
|
setIsPlaying(false);
|
|
@@ -35500,6 +35211,10 @@ var TargetsViewUI = ({
|
|
|
35500
35211
|
),
|
|
35501
35212
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-8 w-px bg-gray-200/80" }),
|
|
35502
35213
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-3", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ml-4 text-sm font-medium text-gray-600", children: [
|
|
35214
|
+
line.shiftStartTime,
|
|
35215
|
+
" \u2013 ",
|
|
35216
|
+
line.shiftEndTime,
|
|
35217
|
+
" \u2022 ",
|
|
35503
35218
|
line.shiftHours,
|
|
35504
35219
|
" hours"
|
|
35505
35220
|
] }) })
|
|
@@ -36162,7 +35877,7 @@ var TargetsView = ({
|
|
|
36162
35877
|
const handleShiftChange = (shiftId) => {
|
|
36163
35878
|
setSelectedShift(shiftId);
|
|
36164
35879
|
const loadShiftHours = async () => {
|
|
36165
|
-
const updatedLineWorkspaces = { ...
|
|
35880
|
+
const updatedLineWorkspaces = { ...allShiftsData[shiftId] };
|
|
36166
35881
|
let hasUpdates = false;
|
|
36167
35882
|
for (const lineId of lineIds) {
|
|
36168
35883
|
try {
|
|
@@ -36210,7 +35925,10 @@ var TargetsView = ({
|
|
|
36210
35925
|
}
|
|
36211
35926
|
}
|
|
36212
35927
|
if (hasUpdates) {
|
|
36213
|
-
|
|
35928
|
+
setAllShiftsData((prev) => ({
|
|
35929
|
+
...prev,
|
|
35930
|
+
[shiftId]: updatedLineWorkspaces
|
|
35931
|
+
}));
|
|
36214
35932
|
}
|
|
36215
35933
|
};
|
|
36216
35934
|
loadShiftHours();
|
|
@@ -38007,7 +37725,6 @@ exports.apiUtils = apiUtils;
|
|
|
38007
37725
|
exports.authCoreService = authCoreService;
|
|
38008
37726
|
exports.authOTPService = authOTPService;
|
|
38009
37727
|
exports.authRateLimitService = authRateLimitService;
|
|
38010
|
-
exports.cacheService = cacheService;
|
|
38011
37728
|
exports.checkRateLimit = checkRateLimit2;
|
|
38012
37729
|
exports.clearAllRateLimits = clearAllRateLimits2;
|
|
38013
37730
|
exports.clearRateLimit = clearRateLimit2;
|