@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.mjs
CHANGED
|
@@ -394,11 +394,11 @@ var actionService = {
|
|
|
394
394
|
};
|
|
395
395
|
function createMemoizedFunction(fn, getCacheKey) {
|
|
396
396
|
const cache = /* @__PURE__ */ new Map();
|
|
397
|
-
const
|
|
397
|
+
const CACHE_DURATION = 5 * 60 * 1e3;
|
|
398
398
|
return (...args) => {
|
|
399
399
|
const key = getCacheKey(...args);
|
|
400
400
|
const cached = cache.get(key);
|
|
401
|
-
if (cached && Date.now() - cached.timestamp <
|
|
401
|
+
if (cached && Date.now() - cached.timestamp < CACHE_DURATION) {
|
|
402
402
|
return cached.result;
|
|
403
403
|
}
|
|
404
404
|
const result = fn(...args);
|
|
@@ -2449,199 +2449,6 @@ async function deleteThread(threadId) {
|
|
|
2449
2449
|
if (error) throw error;
|
|
2450
2450
|
}
|
|
2451
2451
|
|
|
2452
|
-
// src/lib/services/cacheService.ts
|
|
2453
|
-
var CacheService = class {
|
|
2454
|
-
constructor() {
|
|
2455
|
-
this.memoryCache = /* @__PURE__ */ new Map();
|
|
2456
|
-
this.DEFAULT_DURATION = 5 * 60 * 1e3;
|
|
2457
|
-
}
|
|
2458
|
-
// 5 minutes
|
|
2459
|
-
/**
|
|
2460
|
-
* Generate a cache key from multiple parts
|
|
2461
|
-
*/
|
|
2462
|
-
generateKey(...parts) {
|
|
2463
|
-
return parts.filter((p) => p !== void 0 && p !== null).join(":");
|
|
2464
|
-
}
|
|
2465
|
-
/**
|
|
2466
|
-
* Get item from cache
|
|
2467
|
-
*/
|
|
2468
|
-
get(key, options) {
|
|
2469
|
-
const storage = options?.storage || "memory";
|
|
2470
|
-
try {
|
|
2471
|
-
let cacheItem = null;
|
|
2472
|
-
if (storage === "memory") {
|
|
2473
|
-
cacheItem = this.memoryCache.get(key) || null;
|
|
2474
|
-
} else if (storage === "localStorage" || storage === "sessionStorage") {
|
|
2475
|
-
const stored = window[storage].getItem(key);
|
|
2476
|
-
if (stored) {
|
|
2477
|
-
cacheItem = JSON.parse(stored);
|
|
2478
|
-
}
|
|
2479
|
-
}
|
|
2480
|
-
if (!cacheItem) {
|
|
2481
|
-
return null;
|
|
2482
|
-
}
|
|
2483
|
-
if (Date.now() > cacheItem.expiresAt) {
|
|
2484
|
-
this.delete(key, options);
|
|
2485
|
-
return null;
|
|
2486
|
-
}
|
|
2487
|
-
return cacheItem.data;
|
|
2488
|
-
} catch (error) {
|
|
2489
|
-
console.error(`Error getting cache item ${key}:`, error);
|
|
2490
|
-
return null;
|
|
2491
|
-
}
|
|
2492
|
-
}
|
|
2493
|
-
/**
|
|
2494
|
-
* Set item in cache
|
|
2495
|
-
*/
|
|
2496
|
-
set(key, data, options) {
|
|
2497
|
-
const storage = options?.storage || "memory";
|
|
2498
|
-
const duration = options?.duration || this.DEFAULT_DURATION;
|
|
2499
|
-
const cacheItem = {
|
|
2500
|
-
data,
|
|
2501
|
-
timestamp: Date.now(),
|
|
2502
|
-
expiresAt: Date.now() + duration
|
|
2503
|
-
};
|
|
2504
|
-
try {
|
|
2505
|
-
if (storage === "memory") {
|
|
2506
|
-
this.memoryCache.set(key, cacheItem);
|
|
2507
|
-
if (this.memoryCache.size > 100) {
|
|
2508
|
-
const firstKey = this.memoryCache.keys().next().value;
|
|
2509
|
-
if (firstKey) {
|
|
2510
|
-
this.memoryCache.delete(firstKey);
|
|
2511
|
-
}
|
|
2512
|
-
}
|
|
2513
|
-
} else if (storage === "localStorage" || storage === "sessionStorage") {
|
|
2514
|
-
window[storage].setItem(key, JSON.stringify(cacheItem));
|
|
2515
|
-
}
|
|
2516
|
-
} catch (error) {
|
|
2517
|
-
console.error(`Error setting cache item ${key}:`, error);
|
|
2518
|
-
}
|
|
2519
|
-
}
|
|
2520
|
-
/**
|
|
2521
|
-
* Delete item from cache
|
|
2522
|
-
*/
|
|
2523
|
-
delete(key, options) {
|
|
2524
|
-
const storage = options?.storage || "memory";
|
|
2525
|
-
try {
|
|
2526
|
-
if (storage === "memory") {
|
|
2527
|
-
this.memoryCache.delete(key);
|
|
2528
|
-
} else if (storage === "localStorage" || storage === "sessionStorage") {
|
|
2529
|
-
window[storage].removeItem(key);
|
|
2530
|
-
}
|
|
2531
|
-
} catch (error) {
|
|
2532
|
-
console.error(`Error deleting cache item ${key}:`, error);
|
|
2533
|
-
}
|
|
2534
|
-
}
|
|
2535
|
-
/**
|
|
2536
|
-
* Clear all items from cache
|
|
2537
|
-
*/
|
|
2538
|
-
clear(options) {
|
|
2539
|
-
const storage = options?.storage || "memory";
|
|
2540
|
-
try {
|
|
2541
|
-
if (storage === "memory") {
|
|
2542
|
-
this.memoryCache.clear();
|
|
2543
|
-
} else if (storage === "localStorage" || storage === "sessionStorage") {
|
|
2544
|
-
const keys = Object.keys(window[storage]);
|
|
2545
|
-
keys.forEach((key) => {
|
|
2546
|
-
try {
|
|
2547
|
-
const item = window[storage].getItem(key);
|
|
2548
|
-
if (item) {
|
|
2549
|
-
const parsed = JSON.parse(item);
|
|
2550
|
-
if (parsed.timestamp && parsed.expiresAt && parsed.data !== void 0) {
|
|
2551
|
-
window[storage].removeItem(key);
|
|
2552
|
-
}
|
|
2553
|
-
}
|
|
2554
|
-
} catch {
|
|
2555
|
-
}
|
|
2556
|
-
});
|
|
2557
|
-
}
|
|
2558
|
-
} catch (error) {
|
|
2559
|
-
console.error("Error clearing cache:", error);
|
|
2560
|
-
}
|
|
2561
|
-
}
|
|
2562
|
-
/**
|
|
2563
|
-
* Get or set item in cache with a factory function
|
|
2564
|
-
*/
|
|
2565
|
-
async getOrSet(key, factory, options) {
|
|
2566
|
-
const cached = this.get(key, options);
|
|
2567
|
-
if (cached !== null) {
|
|
2568
|
-
return cached;
|
|
2569
|
-
}
|
|
2570
|
-
const data = await factory();
|
|
2571
|
-
this.set(key, data, options);
|
|
2572
|
-
return data;
|
|
2573
|
-
}
|
|
2574
|
-
/**
|
|
2575
|
-
* Invalidate cache entries matching a pattern
|
|
2576
|
-
*/
|
|
2577
|
-
invalidatePattern(pattern, options) {
|
|
2578
|
-
const storage = options?.storage || "memory";
|
|
2579
|
-
const regex = typeof pattern === "string" ? new RegExp(pattern) : pattern;
|
|
2580
|
-
try {
|
|
2581
|
-
if (storage === "memory") {
|
|
2582
|
-
const keysToDelete = [];
|
|
2583
|
-
this.memoryCache.forEach((_, key) => {
|
|
2584
|
-
if (regex.test(key)) {
|
|
2585
|
-
keysToDelete.push(key);
|
|
2586
|
-
}
|
|
2587
|
-
});
|
|
2588
|
-
keysToDelete.forEach((key) => this.memoryCache.delete(key));
|
|
2589
|
-
} else if (storage === "localStorage" || storage === "sessionStorage") {
|
|
2590
|
-
const keys = Object.keys(window[storage]);
|
|
2591
|
-
keys.forEach((key) => {
|
|
2592
|
-
if (regex.test(key)) {
|
|
2593
|
-
window[storage].removeItem(key);
|
|
2594
|
-
}
|
|
2595
|
-
});
|
|
2596
|
-
}
|
|
2597
|
-
} catch (error) {
|
|
2598
|
-
console.error("Error invalidating cache pattern:", error);
|
|
2599
|
-
}
|
|
2600
|
-
}
|
|
2601
|
-
/**
|
|
2602
|
-
* Clean up expired items
|
|
2603
|
-
*/
|
|
2604
|
-
cleanup(options) {
|
|
2605
|
-
const storage = options?.storage || "memory";
|
|
2606
|
-
const now2 = Date.now();
|
|
2607
|
-
try {
|
|
2608
|
-
if (storage === "memory") {
|
|
2609
|
-
const keysToDelete = [];
|
|
2610
|
-
this.memoryCache.forEach((item, key) => {
|
|
2611
|
-
if (now2 > item.expiresAt) {
|
|
2612
|
-
keysToDelete.push(key);
|
|
2613
|
-
}
|
|
2614
|
-
});
|
|
2615
|
-
keysToDelete.forEach((key) => this.memoryCache.delete(key));
|
|
2616
|
-
} else if (storage === "localStorage" || storage === "sessionStorage") {
|
|
2617
|
-
const keys = Object.keys(window[storage]);
|
|
2618
|
-
keys.forEach((key) => {
|
|
2619
|
-
try {
|
|
2620
|
-
const item = window[storage].getItem(key);
|
|
2621
|
-
if (item) {
|
|
2622
|
-
const parsed = JSON.parse(item);
|
|
2623
|
-
if (parsed.expiresAt && now2 > parsed.expiresAt) {
|
|
2624
|
-
window[storage].removeItem(key);
|
|
2625
|
-
}
|
|
2626
|
-
}
|
|
2627
|
-
} catch {
|
|
2628
|
-
}
|
|
2629
|
-
});
|
|
2630
|
-
}
|
|
2631
|
-
} catch (error) {
|
|
2632
|
-
console.error("Error cleaning up cache:", error);
|
|
2633
|
-
}
|
|
2634
|
-
}
|
|
2635
|
-
};
|
|
2636
|
-
var cacheService = new CacheService();
|
|
2637
|
-
if (typeof window !== "undefined") {
|
|
2638
|
-
setInterval(() => {
|
|
2639
|
-
cacheService.cleanup({ storage: "localStorage" });
|
|
2640
|
-
cacheService.cleanup({ storage: "sessionStorage" });
|
|
2641
|
-
cacheService.cleanup({ storage: "memory" });
|
|
2642
|
-
}, 60 * 1e3);
|
|
2643
|
-
}
|
|
2644
|
-
|
|
2645
2452
|
// src/lib/services/subscriptionManager.ts
|
|
2646
2453
|
var SubscriptionManager = class {
|
|
2647
2454
|
constructor(supabase) {
|
|
@@ -3970,6 +3777,8 @@ var S3ClipsService = class {
|
|
|
3970
3777
|
constructor(config) {
|
|
3971
3778
|
// Request deduplication cache
|
|
3972
3779
|
this.requestCache = new RequestDeduplicationCache();
|
|
3780
|
+
// Flag to prevent metadata fetching during index building
|
|
3781
|
+
this.isIndexBuilding = false;
|
|
3973
3782
|
this.config = config;
|
|
3974
3783
|
if (!config.s3Config) {
|
|
3975
3784
|
throw new Error("S3 configuration is required");
|
|
@@ -4121,6 +3930,10 @@ var S3ClipsService = class {
|
|
|
4121
3930
|
* Fetches full metadata including timestamps with deduplication
|
|
4122
3931
|
*/
|
|
4123
3932
|
async getFullMetadata(playlistUri) {
|
|
3933
|
+
if (this.isIndexBuilding) {
|
|
3934
|
+
console.warn(`[S3ClipsService] Skipping metadata fetch during index building for: ${playlistUri}`);
|
|
3935
|
+
return null;
|
|
3936
|
+
}
|
|
4124
3937
|
const deduplicationKey = `full-metadata:${playlistUri}`;
|
|
4125
3938
|
return this.requestCache.deduplicate(
|
|
4126
3939
|
deduplicationKey,
|
|
@@ -4187,141 +4000,152 @@ var S3ClipsService = class {
|
|
|
4187
4000
|
* Internal implementation of clip counts fetching
|
|
4188
4001
|
*/
|
|
4189
4002
|
async executeGetClipCounts(workspaceId, date, shiftId, buildIndex) {
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
}
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
const
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4003
|
+
if (buildIndex) {
|
|
4004
|
+
this.isIndexBuilding = true;
|
|
4005
|
+
console.log(`[S3ClipsService] Starting index building - metadata fetching disabled`);
|
|
4006
|
+
}
|
|
4007
|
+
try {
|
|
4008
|
+
const basePrefix = `sop_violations/${workspaceId}/${date}/${shiftId}/`;
|
|
4009
|
+
const counts = { total: 0 };
|
|
4010
|
+
const categoryFolders = [
|
|
4011
|
+
"idle_time",
|
|
4012
|
+
"low_value",
|
|
4013
|
+
"sop_deviation",
|
|
4014
|
+
"missing_quality_check",
|
|
4015
|
+
"best_cycle_time",
|
|
4016
|
+
"worst_cycle_time",
|
|
4017
|
+
"long_cycle_time",
|
|
4018
|
+
"cycle_completion",
|
|
4019
|
+
"bottleneck"
|
|
4020
|
+
];
|
|
4021
|
+
console.log(`[S3ClipsService] ${buildIndex ? "Building video index and counting" : "Fast counting"} clips for ${workspaceId} on ${date}, shift ${shiftId}`);
|
|
4022
|
+
const startTime = performance.now();
|
|
4023
|
+
const videoIndex = buildIndex ? {
|
|
4024
|
+
byCategory: /* @__PURE__ */ new Map(),
|
|
4025
|
+
allVideos: [],
|
|
4026
|
+
counts: {},
|
|
4027
|
+
workspaceId,
|
|
4028
|
+
date,
|
|
4029
|
+
shiftId: shiftId.toString(),
|
|
4030
|
+
lastUpdated: /* @__PURE__ */ new Date(),
|
|
4031
|
+
_debugId: `vid_${Date.now()}_${Math.random().toString(36).substring(7)}`
|
|
4032
|
+
} : null;
|
|
4033
|
+
const countPromises = categoryFolders.map(async (category) => {
|
|
4034
|
+
const categoryPrefix = `${basePrefix}${category}/videos/`;
|
|
4035
|
+
const categoryVideos = [];
|
|
4036
|
+
try {
|
|
4037
|
+
if (buildIndex) {
|
|
4038
|
+
const command = new ListObjectsV2Command({
|
|
4039
|
+
Bucket: this.config.s3Config.bucketName,
|
|
4040
|
+
Prefix: categoryPrefix,
|
|
4041
|
+
MaxKeys: 1e3
|
|
4042
|
+
});
|
|
4043
|
+
let continuationToken;
|
|
4044
|
+
do {
|
|
4045
|
+
if (continuationToken) {
|
|
4046
|
+
command.input.ContinuationToken = continuationToken;
|
|
4047
|
+
}
|
|
4048
|
+
const response = await this.s3Client.send(command);
|
|
4049
|
+
if (response.Contents) {
|
|
4050
|
+
for (const obj of response.Contents) {
|
|
4051
|
+
if (obj.Key && obj.Key.endsWith("playlist.m3u8")) {
|
|
4052
|
+
if (obj.Key.includes("missed_qchecks")) {
|
|
4053
|
+
continue;
|
|
4054
|
+
}
|
|
4055
|
+
const s3Uri = `s3://${this.config.s3Config.bucketName}/${obj.Key}`;
|
|
4056
|
+
const sopCategories = this.getSOPCategories(workspaceId);
|
|
4057
|
+
const parsedInfo = parseS3Uri(s3Uri, sopCategories);
|
|
4058
|
+
const belongsToCategory = parsedInfo && (parsedInfo.type === category || // Handle specific mismatches between folder names and parsed types
|
|
4059
|
+
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");
|
|
4060
|
+
if (belongsToCategory) {
|
|
4061
|
+
const videoEntry = {
|
|
4062
|
+
uri: s3Uri,
|
|
4063
|
+
category: parsedInfo.type,
|
|
4064
|
+
// Use the parsed type, not the folder name
|
|
4065
|
+
timestamp: parsedInfo.timestamp,
|
|
4066
|
+
videoId: `${workspaceId}-${parsedInfo.timestamp}`,
|
|
4067
|
+
workspaceId,
|
|
4068
|
+
date,
|
|
4069
|
+
shiftId: shiftId.toString()
|
|
4070
|
+
};
|
|
4071
|
+
categoryVideos.push(videoEntry);
|
|
4072
|
+
}
|
|
4254
4073
|
}
|
|
4255
4074
|
}
|
|
4256
4075
|
}
|
|
4076
|
+
continuationToken = response.NextContinuationToken;
|
|
4077
|
+
} while (continuationToken);
|
|
4078
|
+
categoryVideos.sort((a, b) => b.timestamp.localeCompare(a.timestamp));
|
|
4079
|
+
if (categoryVideos.length > 0) {
|
|
4080
|
+
console.log(`[S3ClipsService] Found ${categoryVideos.length} videos for category '${category}' (parsed types: ${[...new Set(categoryVideos.map((v) => v.category))].join(", ")})`);
|
|
4257
4081
|
}
|
|
4258
|
-
|
|
4259
|
-
}
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4082
|
+
return { category, count: categoryVideos.length, videos: categoryVideos };
|
|
4083
|
+
} else {
|
|
4084
|
+
const command = new ListObjectsV2Command({
|
|
4085
|
+
Bucket: this.config.s3Config.bucketName,
|
|
4086
|
+
Prefix: categoryPrefix,
|
|
4087
|
+
Delimiter: "/",
|
|
4088
|
+
MaxKeys: 1e3
|
|
4089
|
+
});
|
|
4090
|
+
let folderCount = 0;
|
|
4091
|
+
let continuationToken;
|
|
4092
|
+
do {
|
|
4093
|
+
if (continuationToken) {
|
|
4094
|
+
command.input.ContinuationToken = continuationToken;
|
|
4095
|
+
}
|
|
4096
|
+
const response = await this.s3Client.send(command);
|
|
4097
|
+
if (response.CommonPrefixes) {
|
|
4098
|
+
folderCount += response.CommonPrefixes.length;
|
|
4099
|
+
}
|
|
4100
|
+
continuationToken = response.NextContinuationToken;
|
|
4101
|
+
} while (continuationToken);
|
|
4102
|
+
return { category, count: folderCount, videos: [] };
|
|
4263
4103
|
}
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
}
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
|
|
4104
|
+
} catch (error) {
|
|
4105
|
+
console.error(`Error ${buildIndex ? "building index for" : "counting folders for"} category ${category}:`, error);
|
|
4106
|
+
return { category, count: 0, videos: [] };
|
|
4107
|
+
}
|
|
4108
|
+
});
|
|
4109
|
+
const results = await Promise.all(countPromises);
|
|
4110
|
+
for (const { category, count, videos } of results) {
|
|
4111
|
+
counts[category] = count;
|
|
4112
|
+
counts.total += count;
|
|
4113
|
+
if (buildIndex && videoIndex && videos) {
|
|
4114
|
+
if (videos.length > 0) {
|
|
4115
|
+
const parsedType = videos[0].category;
|
|
4116
|
+
videoIndex.byCategory.set(parsedType, videos);
|
|
4117
|
+
console.log(`[S3ClipsService] Indexed ${videos.length} videos under parsed type '${parsedType}'`);
|
|
4118
|
+
if (category !== parsedType) {
|
|
4119
|
+
videoIndex.byCategory.set(category, videos);
|
|
4120
|
+
console.log(`[S3ClipsService] Created alias: S3 folder '${category}' -> parsed type '${parsedType}' (${videos.length} videos)`);
|
|
4281
4121
|
}
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
return { category, count: folderCount, videos: [] };
|
|
4122
|
+
}
|
|
4123
|
+
videoIndex.allVideos.push(...videos);
|
|
4285
4124
|
}
|
|
4286
|
-
} catch (error) {
|
|
4287
|
-
console.error(`Error ${buildIndex ? "building index for" : "counting folders for"} category ${category}:`, error);
|
|
4288
|
-
return { category, count: 0, videos: [] };
|
|
4289
4125
|
}
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
}
|
|
4126
|
+
if (buildIndex && videoIndex) {
|
|
4127
|
+
videoIndex.allVideos.sort((a, b) => b.timestamp.localeCompare(a.timestamp));
|
|
4128
|
+
videoIndex.counts = { ...counts };
|
|
4129
|
+
}
|
|
4130
|
+
const elapsed = performance.now() - startTime;
|
|
4131
|
+
console.log(`[S3ClipsService] ${buildIndex ? "Video index and counts" : "Clip counts"} completed in ${elapsed.toFixed(2)}ms - Total: ${counts.total}`);
|
|
4132
|
+
if (buildIndex && videoIndex) {
|
|
4133
|
+
console.log(`[S3ClipsService] Final video index summary:`);
|
|
4134
|
+
console.log(` - VideoIndex ID: ${videoIndex._debugId}`);
|
|
4135
|
+
console.log(` - Total videos in allVideos: ${videoIndex.allVideos.length}`);
|
|
4136
|
+
console.log(` - Categories in byCategory Map: ${Array.from(videoIndex.byCategory.keys()).join(", ")}`);
|
|
4137
|
+
for (const [cat, vids] of videoIndex.byCategory.entries()) {
|
|
4138
|
+
console.log(` - '${cat}': ${vids.length} videos`);
|
|
4304
4139
|
}
|
|
4305
|
-
videoIndex
|
|
4140
|
+
return { counts, videoIndex };
|
|
4306
4141
|
}
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
const elapsed = performance.now() - startTime;
|
|
4313
|
-
console.log(`[S3ClipsService] ${buildIndex ? "Video index and counts" : "Clip counts"} completed in ${elapsed.toFixed(2)}ms - Total: ${counts.total}`);
|
|
4314
|
-
if (buildIndex && videoIndex) {
|
|
4315
|
-
console.log(`[S3ClipsService] Final video index summary:`);
|
|
4316
|
-
console.log(` - VideoIndex ID: ${videoIndex._debugId}`);
|
|
4317
|
-
console.log(` - Total videos in allVideos: ${videoIndex.allVideos.length}`);
|
|
4318
|
-
console.log(` - Categories in byCategory Map: ${Array.from(videoIndex.byCategory.keys()).join(", ")}`);
|
|
4319
|
-
for (const [cat, vids] of videoIndex.byCategory.entries()) {
|
|
4320
|
-
console.log(` - '${cat}': ${vids.length} videos`);
|
|
4142
|
+
return counts;
|
|
4143
|
+
} finally {
|
|
4144
|
+
if (buildIndex) {
|
|
4145
|
+
this.isIndexBuilding = false;
|
|
4146
|
+
console.log(`[S3ClipsService] Index building complete - metadata fetching re-enabled`);
|
|
4321
4147
|
}
|
|
4322
|
-
return { counts, videoIndex };
|
|
4323
4148
|
}
|
|
4324
|
-
return counts;
|
|
4325
4149
|
}
|
|
4326
4150
|
async getClipCountsCacheFirst(workspaceId, date, shiftId, buildIndex) {
|
|
4327
4151
|
const cacheKey = `clip-counts:${workspaceId}:${date}:${shiftId}`;
|
|
@@ -4415,18 +4239,18 @@ var S3ClipsService = class {
|
|
|
4415
4239
|
* Get a specific clip by index for a category with deduplication
|
|
4416
4240
|
* @deprecated Use getVideoFromIndex with a pre-built VideoIndex for better performance
|
|
4417
4241
|
*/
|
|
4418
|
-
async getClipByIndex(workspaceId, date, shiftId, category, index) {
|
|
4419
|
-
const deduplicationKey = `clip-by-index:${workspaceId}:${date}:${shiftId}:${category}:${index}`;
|
|
4242
|
+
async getClipByIndex(workspaceId, date, shiftId, category, index, includeCycleTime = true, includeMetadata = false) {
|
|
4243
|
+
const deduplicationKey = `clip-by-index:${workspaceId}:${date}:${shiftId}:${category}:${index}:${includeCycleTime}:${includeMetadata}`;
|
|
4420
4244
|
return this.requestCache.deduplicate(
|
|
4421
4245
|
deduplicationKey,
|
|
4422
|
-
() => this.executeGetClipByIndex(workspaceId, date, shiftId, category, index),
|
|
4246
|
+
() => this.executeGetClipByIndex(workspaceId, date, shiftId, category, index, includeCycleTime, includeMetadata),
|
|
4423
4247
|
"ClipByIndex"
|
|
4424
4248
|
);
|
|
4425
4249
|
}
|
|
4426
4250
|
/**
|
|
4427
4251
|
* Internal implementation of clip by index fetching
|
|
4428
4252
|
*/
|
|
4429
|
-
async executeGetClipByIndex(workspaceId, date, shiftId, category, index) {
|
|
4253
|
+
async executeGetClipByIndex(workspaceId, date, shiftId, category, index, includeCycleTime = true, includeMetadata = false) {
|
|
4430
4254
|
const categoryPrefix = `sop_violations/${workspaceId}/${date}/${shiftId}/${category}/videos/`;
|
|
4431
4255
|
try {
|
|
4432
4256
|
const command = new ListObjectsV2Command({
|
|
@@ -4464,10 +4288,8 @@ var S3ClipsService = class {
|
|
|
4464
4288
|
workspaceId,
|
|
4465
4289
|
date,
|
|
4466
4290
|
shiftId.toString(),
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
true
|
|
4470
|
-
// includeMetadata
|
|
4291
|
+
includeCycleTime,
|
|
4292
|
+
includeMetadata
|
|
4471
4293
|
);
|
|
4472
4294
|
}
|
|
4473
4295
|
} catch (error) {
|
|
@@ -4538,7 +4360,7 @@ var S3ClipsService = class {
|
|
|
4538
4360
|
}
|
|
4539
4361
|
let cycleTimeSeconds = null;
|
|
4540
4362
|
let creationTimestamp = void 0;
|
|
4541
|
-
if (includeMetadata
|
|
4363
|
+
if (includeMetadata) {
|
|
4542
4364
|
const metadata = await this.getFullMetadata(uri);
|
|
4543
4365
|
if (metadata) {
|
|
4544
4366
|
if (metadata.original_task_metadata?.cycle_time) {
|
|
@@ -4546,6 +4368,8 @@ var S3ClipsService = class {
|
|
|
4546
4368
|
}
|
|
4547
4369
|
creationTimestamp = metadata.upload_timestamp || metadata.original_task_metadata?.timestamp || metadata.creation_timestamp || metadata[""];
|
|
4548
4370
|
}
|
|
4371
|
+
} 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")) {
|
|
4372
|
+
cycleTimeSeconds = null;
|
|
4549
4373
|
}
|
|
4550
4374
|
const cloudfrontPlaylistUrl = this.s3UriToCloudfront(uri);
|
|
4551
4375
|
const { type: videoType, timestamp: videoTimestamp } = parsedInfo;
|
|
@@ -5567,7 +5391,6 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
5567
5391
|
const [error, setError] = useState(null);
|
|
5568
5392
|
const updateQueueRef = useRef(false);
|
|
5569
5393
|
const isFetchingRef = useRef(false);
|
|
5570
|
-
const timeoutRef = useRef(null);
|
|
5571
5394
|
const channelRef = useRef(null);
|
|
5572
5395
|
const schema = databaseConfig.schema ?? "public";
|
|
5573
5396
|
const companyId = entityConfig.companyId || "";
|
|
@@ -5576,7 +5399,7 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
5576
5399
|
const defaultTimezone = dateTimeConfig.defaultTimezone;
|
|
5577
5400
|
const workspaceMetricsBaseTable = databaseConfig.tables?.workspaces ?? "workspace_metrics";
|
|
5578
5401
|
const workspaceActionsTable = databaseConfig.tables?.actions ?? "workspace_actions";
|
|
5579
|
-
const fetchMetrics = useCallback(async (
|
|
5402
|
+
const fetchMetrics = useCallback(async () => {
|
|
5580
5403
|
if (!workspaceId || isFetchingRef.current) return;
|
|
5581
5404
|
try {
|
|
5582
5405
|
isFetchingRef.current = true;
|
|
@@ -5585,28 +5408,6 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
5585
5408
|
const queryShiftId = shiftId !== void 0 ? shiftId : currentShift.shiftId;
|
|
5586
5409
|
console.log("[useWorkspaceDetailedMetrics] Using shift ID:", queryShiftId, "from input shift:", shiftId);
|
|
5587
5410
|
console.log("[useWorkspaceDetailedMetrics] Using date:", queryDate, "from input date:", date);
|
|
5588
|
-
const cacheKey = cacheService.generateKey(
|
|
5589
|
-
"workspace-detailed-metrics",
|
|
5590
|
-
workspaceId,
|
|
5591
|
-
queryDate,
|
|
5592
|
-
queryShiftId,
|
|
5593
|
-
companyId
|
|
5594
|
-
);
|
|
5595
|
-
if (!skipCache) {
|
|
5596
|
-
const cachedData = cacheService.get(cacheKey, {
|
|
5597
|
-
storage: "memory",
|
|
5598
|
-
duration: 5 * 60 * 1e3
|
|
5599
|
-
// 5 minutes
|
|
5600
|
-
});
|
|
5601
|
-
if (cachedData) {
|
|
5602
|
-
console.log("[useWorkspaceDetailedMetrics] Using cached data for:", cacheKey);
|
|
5603
|
-
setMetrics(cachedData);
|
|
5604
|
-
setIsLoading(false);
|
|
5605
|
-
updateQueueRef.current = false;
|
|
5606
|
-
isFetchingRef.current = false;
|
|
5607
|
-
return;
|
|
5608
|
-
}
|
|
5609
|
-
}
|
|
5610
5411
|
console.log(`[useWorkspaceDetailedMetrics] Querying ${metricsTable} for workspace: ${workspaceId}, date: ${queryDate}, shift: ${queryShiftId}`);
|
|
5611
5412
|
const { data, error: fetchError } = await supabase.from(metricsTable).select("*").eq("workspace_id", workspaceId).eq("date", queryDate).eq("shift_id", queryShiftId).maybeSingle();
|
|
5612
5413
|
if (fetchError) throw fetchError;
|
|
@@ -5709,18 +5510,6 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
5709
5510
|
setIsLoading(false);
|
|
5710
5511
|
updateQueueRef.current = false;
|
|
5711
5512
|
isFetchingRef.current = false;
|
|
5712
|
-
const fallbackCacheKey = cacheService.generateKey(
|
|
5713
|
-
"workspace-detailed-metrics",
|
|
5714
|
-
workspaceId,
|
|
5715
|
-
recentData.date,
|
|
5716
|
-
recentData.shift_id,
|
|
5717
|
-
companyId
|
|
5718
|
-
);
|
|
5719
|
-
cacheService.set(fallbackCacheKey, transformedData2, {
|
|
5720
|
-
storage: "memory",
|
|
5721
|
-
duration: 2 * 60 * 1e3
|
|
5722
|
-
// 2 minutes for fallback data
|
|
5723
|
-
});
|
|
5724
5513
|
return;
|
|
5725
5514
|
} else {
|
|
5726
5515
|
console.warn("[useWorkspaceDetailedMetrics] No data found for workspace:", workspaceId, "at all");
|
|
@@ -5834,11 +5623,6 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
5834
5623
|
...data.sop_check !== void 0 && { sop_check: data.sop_check }
|
|
5835
5624
|
};
|
|
5836
5625
|
setMetrics(transformedData);
|
|
5837
|
-
cacheService.set(cacheKey, transformedData, {
|
|
5838
|
-
storage: "memory",
|
|
5839
|
-
duration: 5 * 60 * 1e3
|
|
5840
|
-
// 5 minutes
|
|
5841
|
-
});
|
|
5842
5626
|
} catch (err) {
|
|
5843
5627
|
console.error("Error fetching workspace metrics:", err);
|
|
5844
5628
|
setError({ message: err.message, code: err.code });
|
|
@@ -5851,12 +5635,7 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
5851
5635
|
const queueUpdate = useCallback(() => {
|
|
5852
5636
|
if (!workspaceId || updateQueueRef.current) return;
|
|
5853
5637
|
updateQueueRef.current = true;
|
|
5854
|
-
|
|
5855
|
-
clearTimeout(timeoutRef.current);
|
|
5856
|
-
}
|
|
5857
|
-
timeoutRef.current = setTimeout(() => {
|
|
5858
|
-
fetchMetrics();
|
|
5859
|
-
}, 500);
|
|
5638
|
+
fetchMetrics();
|
|
5860
5639
|
}, [fetchMetrics, workspaceId]);
|
|
5861
5640
|
const setupSubscription = useCallback(() => {
|
|
5862
5641
|
if (!workspaceId) return;
|
|
@@ -5873,7 +5652,7 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
5873
5652
|
},
|
|
5874
5653
|
async (payload) => {
|
|
5875
5654
|
console.log(`Received ${metricsTablePrefix} update:`, payload);
|
|
5876
|
-
await fetchMetrics(
|
|
5655
|
+
await fetchMetrics();
|
|
5877
5656
|
}
|
|
5878
5657
|
).subscribe((status) => {
|
|
5879
5658
|
console.log(`Workspace detailed metrics subscription status:`, status);
|
|
@@ -5907,14 +5686,6 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
5907
5686
|
matches: payloadData?.date === operationalDate && payloadData?.shift_id === queryShiftId
|
|
5908
5687
|
});
|
|
5909
5688
|
if (payloadData?.date === operationalDate && payloadData?.shift_id === queryShiftId) {
|
|
5910
|
-
const cacheKey = cacheService.generateKey(
|
|
5911
|
-
"workspace-detailed-metrics",
|
|
5912
|
-
workspaceId,
|
|
5913
|
-
operationalDate,
|
|
5914
|
-
queryShiftId,
|
|
5915
|
-
companyId
|
|
5916
|
-
);
|
|
5917
|
-
cacheService.delete(cacheKey, { storage: "memory" });
|
|
5918
5689
|
queueUpdate();
|
|
5919
5690
|
}
|
|
5920
5691
|
}
|
|
@@ -5940,14 +5711,6 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
5940
5711
|
matches: payloadData?.date === operationalDate && payloadData?.shift_id === queryShiftId
|
|
5941
5712
|
});
|
|
5942
5713
|
if (payloadData?.date === operationalDate && payloadData?.shift_id === queryShiftId) {
|
|
5943
|
-
const cacheKey = cacheService.generateKey(
|
|
5944
|
-
"workspace-detailed-metrics",
|
|
5945
|
-
workspaceId,
|
|
5946
|
-
operationalDate,
|
|
5947
|
-
queryShiftId,
|
|
5948
|
-
companyId
|
|
5949
|
-
);
|
|
5950
|
-
cacheService.delete(cacheKey, { storage: "memory" });
|
|
5951
5714
|
queueUpdate();
|
|
5952
5715
|
}
|
|
5953
5716
|
}
|
|
@@ -5973,14 +5736,6 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
5973
5736
|
matches: payloadData?.date === operationalDate && payloadData?.shift_id === queryShiftId
|
|
5974
5737
|
});
|
|
5975
5738
|
if (payloadData?.date === operationalDate && payloadData?.shift_id === queryShiftId) {
|
|
5976
|
-
const cacheKey = cacheService.generateKey(
|
|
5977
|
-
"workspace-detailed-metrics",
|
|
5978
|
-
workspaceId,
|
|
5979
|
-
operationalDate,
|
|
5980
|
-
queryShiftId,
|
|
5981
|
-
companyId
|
|
5982
|
-
);
|
|
5983
|
-
cacheService.delete(cacheKey, { storage: "memory" });
|
|
5984
5739
|
queueUpdate();
|
|
5985
5740
|
}
|
|
5986
5741
|
}
|
|
@@ -5991,9 +5746,6 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
5991
5746
|
fetchMetrics();
|
|
5992
5747
|
setupSubscription();
|
|
5993
5748
|
return () => {
|
|
5994
|
-
if (timeoutRef.current) {
|
|
5995
|
-
clearTimeout(timeoutRef.current);
|
|
5996
|
-
}
|
|
5997
5749
|
channels.forEach((channel) => {
|
|
5998
5750
|
console.log("Cleaning up channel subscription");
|
|
5999
5751
|
supabase.removeChannel(channel);
|
|
@@ -6007,7 +5759,7 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
6007
5759
|
metrics: metrics2,
|
|
6008
5760
|
isLoading,
|
|
6009
5761
|
error,
|
|
6010
|
-
refetch: () => fetchMetrics(
|
|
5762
|
+
refetch: () => fetchMetrics()
|
|
6011
5763
|
// Force refresh without cache
|
|
6012
5764
|
};
|
|
6013
5765
|
};
|
|
@@ -6452,33 +6204,6 @@ var useLeaderboardMetrics = (lineId, topCount = 10) => {
|
|
|
6452
6204
|
refetch: fetchLeaderboardData
|
|
6453
6205
|
};
|
|
6454
6206
|
};
|
|
6455
|
-
var CACHE_KEY_PREFIX = "dashboard_metrics_cache_";
|
|
6456
|
-
var CACHE_DURATION = 5 * 60 * 1e3;
|
|
6457
|
-
var getCache = (lineId) => {
|
|
6458
|
-
if (typeof window === "undefined") return null;
|
|
6459
|
-
try {
|
|
6460
|
-
const cached = localStorage.getItem(`${CACHE_KEY_PREFIX}${lineId}`);
|
|
6461
|
-
if (!cached) return null;
|
|
6462
|
-
const parsedCache = JSON.parse(cached);
|
|
6463
|
-
if (!parsedCache.lastUpdated || Date.now() - parsedCache.lastUpdated > CACHE_DURATION) {
|
|
6464
|
-
localStorage.removeItem(`${CACHE_KEY_PREFIX}${lineId}`);
|
|
6465
|
-
return null;
|
|
6466
|
-
}
|
|
6467
|
-
return parsedCache;
|
|
6468
|
-
} catch {
|
|
6469
|
-
return null;
|
|
6470
|
-
}
|
|
6471
|
-
};
|
|
6472
|
-
var setCache = (lineId, metrics2) => {
|
|
6473
|
-
if (typeof window === "undefined") return;
|
|
6474
|
-
try {
|
|
6475
|
-
localStorage.setItem(`${CACHE_KEY_PREFIX}${lineId}`, JSON.stringify({
|
|
6476
|
-
...metrics2,
|
|
6477
|
-
lastUpdated: Date.now()
|
|
6478
|
-
}));
|
|
6479
|
-
} catch {
|
|
6480
|
-
}
|
|
6481
|
-
};
|
|
6482
6207
|
var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
|
|
6483
6208
|
const { supabaseUrl, supabaseKey } = useDashboardConfig();
|
|
6484
6209
|
const entityConfig = useEntityConfig();
|
|
@@ -6489,22 +6214,20 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
|
|
|
6489
6214
|
const configuredLineMetricsTable = databaseConfig?.tables?.lineMetrics ?? "line_metrics";
|
|
6490
6215
|
const schema = databaseConfig?.schema ?? "public";
|
|
6491
6216
|
const supabase = useSupabase();
|
|
6492
|
-
const [metrics2, setMetrics] = useState(
|
|
6493
|
-
const [isLoading, setIsLoading] = useState(
|
|
6217
|
+
const [metrics2, setMetrics] = useState({ workspaceMetrics: [], lineMetrics: [] });
|
|
6218
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
6494
6219
|
const [error, setError] = useState(null);
|
|
6495
6220
|
const lineIdRef = useRef(lineId);
|
|
6496
6221
|
const isFetchingRef = useRef(false);
|
|
6497
6222
|
const updateQueueRef = useRef(false);
|
|
6498
|
-
const timeoutRef = useRef(null);
|
|
6499
6223
|
const companySpecificMetricsTable = useMemo(
|
|
6500
6224
|
() => getCompanyMetricsTableName(entityConfig.companyId, "performance_metrics"),
|
|
6501
6225
|
[entityConfig.companyId]
|
|
6502
6226
|
);
|
|
6503
6227
|
useEffect(() => {
|
|
6504
6228
|
lineIdRef.current = lineId;
|
|
6505
|
-
|
|
6506
|
-
|
|
6507
|
-
setIsLoading(!cachedData);
|
|
6229
|
+
setMetrics({ workspaceMetrics: [], lineMetrics: [] });
|
|
6230
|
+
setIsLoading(true);
|
|
6508
6231
|
}, [lineId]);
|
|
6509
6232
|
const fetchAllMetrics = useCallback(async () => {
|
|
6510
6233
|
const currentLineIdToUse = lineIdRef.current;
|
|
@@ -6516,9 +6239,7 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
|
|
|
6516
6239
|
return;
|
|
6517
6240
|
}
|
|
6518
6241
|
isFetchingRef.current = true;
|
|
6519
|
-
|
|
6520
|
-
setIsLoading(true);
|
|
6521
|
-
}
|
|
6242
|
+
setIsLoading(true);
|
|
6522
6243
|
setError(null);
|
|
6523
6244
|
try {
|
|
6524
6245
|
const currentShiftDetails = getCurrentShift(defaultTimezone, shiftConfig);
|
|
@@ -6543,7 +6264,6 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
|
|
|
6543
6264
|
lineMetrics: []
|
|
6544
6265
|
};
|
|
6545
6266
|
setMetrics(newMetricsState2);
|
|
6546
|
-
setCache(currentLineIdToUse, newMetricsState2);
|
|
6547
6267
|
return;
|
|
6548
6268
|
}
|
|
6549
6269
|
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);
|
|
@@ -6595,7 +6315,6 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
|
|
|
6595
6315
|
lineMetrics: lineData || []
|
|
6596
6316
|
};
|
|
6597
6317
|
setMetrics(newMetricsState);
|
|
6598
|
-
setCache(currentLineIdToUse, newMetricsState);
|
|
6599
6318
|
} catch (err) {
|
|
6600
6319
|
setError({ message: err.message, code: err.code || "FETCH_ERROR" });
|
|
6601
6320
|
} finally {
|
|
@@ -6621,12 +6340,7 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
|
|
|
6621
6340
|
return;
|
|
6622
6341
|
}
|
|
6623
6342
|
updateQueueRef.current = true;
|
|
6624
|
-
|
|
6625
|
-
clearTimeout(timeoutRef.current);
|
|
6626
|
-
}
|
|
6627
|
-
timeoutRef.current = setTimeout(() => {
|
|
6628
|
-
fetchAllMetrics();
|
|
6629
|
-
}, 500);
|
|
6343
|
+
fetchAllMetrics();
|
|
6630
6344
|
}, [fetchAllMetrics, supabase]);
|
|
6631
6345
|
useEffect(() => {
|
|
6632
6346
|
if (lineId && supabase) {
|
|
@@ -6671,9 +6385,6 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
|
|
|
6671
6385
|
onLineMetricsUpdate?.();
|
|
6672
6386
|
});
|
|
6673
6387
|
return () => {
|
|
6674
|
-
if (timeoutRef.current) {
|
|
6675
|
-
clearTimeout(timeoutRef.current);
|
|
6676
|
-
}
|
|
6677
6388
|
channels.forEach((channel) => {
|
|
6678
6389
|
supabase?.removeChannel(channel).catch((err) => console.error("[useDashboardMetrics] Error removing channel:", err.message));
|
|
6679
6390
|
});
|
|
@@ -6702,30 +6413,6 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
|
|
|
6702
6413
|
refetch: fetchAllMetrics
|
|
6703
6414
|
};
|
|
6704
6415
|
};
|
|
6705
|
-
var CACHE_KEY_PREFIX2 = "line_kpis_cache_";
|
|
6706
|
-
var CACHE_DURATION2 = 5 * 60 * 1e3;
|
|
6707
|
-
var getCache2 = (lineId) => {
|
|
6708
|
-
if (typeof window === "undefined") return null;
|
|
6709
|
-
try {
|
|
6710
|
-
const cached = localStorage.getItem(`${CACHE_KEY_PREFIX2}${lineId}`);
|
|
6711
|
-
if (!cached) return null;
|
|
6712
|
-
const parsedCache = JSON.parse(cached);
|
|
6713
|
-
if (!parsedCache.timestamp || Date.now() - parsedCache.timestamp > CACHE_DURATION2) {
|
|
6714
|
-
localStorage.removeItem(`${CACHE_KEY_PREFIX2}${lineId}`);
|
|
6715
|
-
return null;
|
|
6716
|
-
}
|
|
6717
|
-
return parsedCache.data;
|
|
6718
|
-
} catch (error) {
|
|
6719
|
-
return null;
|
|
6720
|
-
}
|
|
6721
|
-
};
|
|
6722
|
-
var setCache2 = (lineId, data) => {
|
|
6723
|
-
if (typeof window === "undefined") return;
|
|
6724
|
-
try {
|
|
6725
|
-
localStorage.setItem(`${CACHE_KEY_PREFIX2}${lineId}`, JSON.stringify({ data, timestamp: Date.now() }));
|
|
6726
|
-
} catch (error) {
|
|
6727
|
-
}
|
|
6728
|
-
};
|
|
6729
6416
|
var useLineKPIs = ({ lineId }) => {
|
|
6730
6417
|
useDashboardConfig();
|
|
6731
6418
|
const entityConfig = useEntityConfig();
|
|
@@ -6737,13 +6424,12 @@ var useLineKPIs = ({ lineId }) => {
|
|
|
6737
6424
|
const dashboardServiceInstance = useMemo(() => {
|
|
6738
6425
|
return dashboardService;
|
|
6739
6426
|
}, []);
|
|
6740
|
-
const [kpis, setKPIs] = useState(
|
|
6741
|
-
const [isLoading, setIsLoading] = useState(
|
|
6427
|
+
const [kpis, setKPIs] = useState(null);
|
|
6428
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
6742
6429
|
const [error, setError] = useState(null);
|
|
6743
6430
|
const lineIdRef = useRef(lineId);
|
|
6744
6431
|
const isFetchingRef = useRef(false);
|
|
6745
6432
|
const updateQueueRef = useRef(false);
|
|
6746
|
-
const timeoutRef = useRef(null);
|
|
6747
6433
|
const defaultTimezone = dateTimeConfig.defaultTimezone;
|
|
6748
6434
|
const schema = databaseConfig.schema ?? "public";
|
|
6749
6435
|
const lineMetricsTable = databaseConfig.tables?.lineMetrics ?? "line_metrics";
|
|
@@ -6774,7 +6460,6 @@ var useLineKPIs = ({ lineId }) => {
|
|
|
6774
6460
|
if (lineInfo) {
|
|
6775
6461
|
const newKPIs = dashboardServiceInstance.calculateKPIs(lineInfo);
|
|
6776
6462
|
setKPIs(newKPIs);
|
|
6777
|
-
setCache2(currentLineId, newKPIs);
|
|
6778
6463
|
} else {
|
|
6779
6464
|
setKPIs(null);
|
|
6780
6465
|
}
|
|
@@ -6791,12 +6476,7 @@ var useLineKPIs = ({ lineId }) => {
|
|
|
6791
6476
|
const queueUpdate = useCallback(() => {
|
|
6792
6477
|
if (updateQueueRef.current) return;
|
|
6793
6478
|
updateQueueRef.current = true;
|
|
6794
|
-
|
|
6795
|
-
clearTimeout(timeoutRef.current);
|
|
6796
|
-
}
|
|
6797
|
-
timeoutRef.current = setTimeout(() => {
|
|
6798
|
-
fetchKPIs();
|
|
6799
|
-
}, 500);
|
|
6479
|
+
fetchKPIs();
|
|
6800
6480
|
}, [fetchKPIs]);
|
|
6801
6481
|
useEffect(() => {
|
|
6802
6482
|
const currentLineId = lineIdRef.current;
|
|
@@ -6854,9 +6534,6 @@ var useLineKPIs = ({ lineId }) => {
|
|
|
6854
6534
|
activeChannels.push(csChannel);
|
|
6855
6535
|
}
|
|
6856
6536
|
return () => {
|
|
6857
|
-
if (timeoutRef.current) {
|
|
6858
|
-
clearTimeout(timeoutRef.current);
|
|
6859
|
-
}
|
|
6860
6537
|
activeChannels.forEach((ch) => supabase.removeChannel(ch).catch((err) => console.error("[useLineKPIs] Error removing KPI channel:", err)));
|
|
6861
6538
|
};
|
|
6862
6539
|
}, [supabase, lineId, fetchKPIs, queueUpdate, dashboardServiceInstance, entityConfig, schema, lineMetricsTable, companySpecificMetricsTable, defaultTimezone, shiftConfig, kpis, isFactoryView]);
|
|
@@ -6885,7 +6562,6 @@ var useRealtimeLineMetrics = ({
|
|
|
6885
6562
|
const [initialized, setInitialized] = useState(false);
|
|
6886
6563
|
const lineIdRef = useRef(null);
|
|
6887
6564
|
const updateQueueRef = useRef(false);
|
|
6888
|
-
const timeoutRef = useRef(null);
|
|
6889
6565
|
const isFetchingRef = useRef(false);
|
|
6890
6566
|
const channelsRef = useRef([]);
|
|
6891
6567
|
const currentShift = useMemo(() => getCurrentShift(dateTimeConfig.defaultTimezone || "Asia/Kolkata", shiftConfig), [dateTimeConfig.defaultTimezone, shiftConfig]);
|
|
@@ -7098,12 +6774,7 @@ var useRealtimeLineMetrics = ({
|
|
|
7098
6774
|
const queueUpdate = useCallback(() => {
|
|
7099
6775
|
if (updateQueueRef.current) return;
|
|
7100
6776
|
updateQueueRef.current = true;
|
|
7101
|
-
|
|
7102
|
-
clearTimeout(timeoutRef.current);
|
|
7103
|
-
}
|
|
7104
|
-
timeoutRef.current = setTimeout(() => {
|
|
7105
|
-
fetchData();
|
|
7106
|
-
}, 500);
|
|
6777
|
+
fetchData();
|
|
7107
6778
|
}, [fetchData]);
|
|
7108
6779
|
const setupSubscriptions = useCallback(() => {
|
|
7109
6780
|
if (channelsRef.current.length > 0) {
|
|
@@ -7181,9 +6852,6 @@ var useRealtimeLineMetrics = ({
|
|
|
7181
6852
|
}
|
|
7182
6853
|
setupSubscriptions();
|
|
7183
6854
|
return () => {
|
|
7184
|
-
if (timeoutRef.current) {
|
|
7185
|
-
clearTimeout(timeoutRef.current);
|
|
7186
|
-
}
|
|
7187
6855
|
if (channelsRef.current.length > 0) {
|
|
7188
6856
|
channelsRef.current.forEach((channel) => {
|
|
7189
6857
|
if (process.env.NODE_ENV === "development") {
|
|
@@ -8471,32 +8139,12 @@ var useAllWorkspaceMetrics = (options) => {
|
|
|
8471
8139
|
return `${metricsTablePrefix}_${companyId.replace(/-/g, "_")}`;
|
|
8472
8140
|
}, [entityConfig.companyId]);
|
|
8473
8141
|
const schema = databaseConfig.schema ?? "public";
|
|
8474
|
-
const fetchWorkspaceMetrics = useCallback(async (
|
|
8142
|
+
const fetchWorkspaceMetrics = useCallback(async () => {
|
|
8475
8143
|
if (!initialized) {
|
|
8476
8144
|
setLoading(true);
|
|
8477
8145
|
}
|
|
8478
8146
|
setError(null);
|
|
8479
8147
|
try {
|
|
8480
|
-
const cacheKey = cacheService.generateKey(
|
|
8481
|
-
"all-workspace-metrics",
|
|
8482
|
-
entityConfig.companyId,
|
|
8483
|
-
queryDate,
|
|
8484
|
-
queryShiftId
|
|
8485
|
-
);
|
|
8486
|
-
if (!skipCache && !loading) {
|
|
8487
|
-
const cachedData = cacheService.get(cacheKey, {
|
|
8488
|
-
storage: "memory",
|
|
8489
|
-
duration: 5 * 60 * 1e3
|
|
8490
|
-
// 5 minutes
|
|
8491
|
-
});
|
|
8492
|
-
if (cachedData) {
|
|
8493
|
-
console.log("[useAllWorkspaceMetrics] Using cached data for:", cacheKey);
|
|
8494
|
-
setWorkspaces(cachedData);
|
|
8495
|
-
setInitialized(true);
|
|
8496
|
-
setLoading(false);
|
|
8497
|
-
return;
|
|
8498
|
-
}
|
|
8499
|
-
}
|
|
8500
8148
|
console.log("Fetching all workspace metrics with params:", {
|
|
8501
8149
|
queryDate,
|
|
8502
8150
|
queryShiftId,
|
|
@@ -8546,11 +8194,6 @@ var useAllWorkspaceMetrics = (options) => {
|
|
|
8546
8194
|
}));
|
|
8547
8195
|
setWorkspaces(transformedData);
|
|
8548
8196
|
setInitialized(true);
|
|
8549
|
-
cacheService.set(cacheKey, transformedData, {
|
|
8550
|
-
storage: "memory",
|
|
8551
|
-
duration: 5 * 60 * 1e3
|
|
8552
|
-
// 5 minutes
|
|
8553
|
-
});
|
|
8554
8197
|
} catch (err) {
|
|
8555
8198
|
console.error("Error fetching all workspace metrics:", err);
|
|
8556
8199
|
setError({ message: err.message, code: err.code || "FETCH_ERROR" });
|
|
@@ -8575,14 +8218,7 @@ var useAllWorkspaceMetrics = (options) => {
|
|
|
8575
8218
|
},
|
|
8576
8219
|
async (payload) => {
|
|
8577
8220
|
console.log("All workspace metrics update received:", payload);
|
|
8578
|
-
|
|
8579
|
-
"all-workspace-metrics",
|
|
8580
|
-
entityConfig.companyId,
|
|
8581
|
-
queryDate,
|
|
8582
|
-
queryShiftId
|
|
8583
|
-
);
|
|
8584
|
-
cacheService.delete(cacheKey, { storage: "memory" });
|
|
8585
|
-
await fetchWorkspaceMetrics(true);
|
|
8221
|
+
await fetchWorkspaceMetrics();
|
|
8586
8222
|
}
|
|
8587
8223
|
).subscribe();
|
|
8588
8224
|
return channel2;
|
|
@@ -8597,7 +8233,7 @@ var useAllWorkspaceMetrics = (options) => {
|
|
|
8597
8233
|
useEffect(() => {
|
|
8598
8234
|
setInitialized(false);
|
|
8599
8235
|
}, [queryDate, queryShiftId]);
|
|
8600
|
-
const refreshWorkspaces = useCallback(() => fetchWorkspaceMetrics(
|
|
8236
|
+
const refreshWorkspaces = useCallback(() => fetchWorkspaceMetrics(), [fetchWorkspaceMetrics]);
|
|
8601
8237
|
return useMemo(
|
|
8602
8238
|
() => ({ workspaces, loading, error, refreshWorkspaces }),
|
|
8603
8239
|
[workspaces, loading, error, refreshWorkspaces]
|
|
@@ -12050,8 +11686,11 @@ var useHourlyTargetAchievements = ({
|
|
|
12050
11686
|
targetThreshold,
|
|
12051
11687
|
enabled
|
|
12052
11688
|
});
|
|
12053
|
-
|
|
12054
|
-
|
|
11689
|
+
let currentHourIndex = hourlyData.length - 1;
|
|
11690
|
+
while (currentHourIndex >= 0 && (hourlyData[currentHourIndex] === void 0 || hourlyData[currentHourIndex] === 0)) {
|
|
11691
|
+
currentHourIndex--;
|
|
11692
|
+
}
|
|
11693
|
+
if (currentHourIndex < 0) {
|
|
12055
11694
|
console.log("[HOURLY TARGET CHECK] No hourly data available");
|
|
12056
11695
|
return;
|
|
12057
11696
|
}
|
|
@@ -12149,8 +11788,11 @@ var useHourlyTargetMisses = ({
|
|
|
12149
11788
|
targetThreshold,
|
|
12150
11789
|
enabled
|
|
12151
11790
|
});
|
|
12152
|
-
|
|
12153
|
-
|
|
11791
|
+
let currentHourIndex = hourlyData.length - 1;
|
|
11792
|
+
while (currentHourIndex >= 0 && (hourlyData[currentHourIndex] === void 0 || hourlyData[currentHourIndex] === 0)) {
|
|
11793
|
+
currentHourIndex--;
|
|
11794
|
+
}
|
|
11795
|
+
if (currentHourIndex < 0) {
|
|
12154
11796
|
console.log("[HOURLY TARGET MISS CHECK] No hourly data available");
|
|
12155
11797
|
return;
|
|
12156
11798
|
}
|
|
@@ -26599,6 +26241,85 @@ var BottlenecksContent = ({
|
|
|
26599
26241
|
}, [workspaceId, date, s3ClipsService, shift, dashboardConfig, updateClipCounts, updateVideoIndex]);
|
|
26600
26242
|
const loadingCategoryRef = useRef(null);
|
|
26601
26243
|
const videoRetryCountRef = useRef(0);
|
|
26244
|
+
const loadingVideosRef = useRef(/* @__PURE__ */ new Set());
|
|
26245
|
+
const loadedVideosMapRef = useRef(/* @__PURE__ */ new Map());
|
|
26246
|
+
const ensureVideosLoaded = useCallback(async (centerIndex) => {
|
|
26247
|
+
if (!s3ClipsService || !workspaceId || !isMountedRef.current) return;
|
|
26248
|
+
const currentFilter = activeFilterRef.current;
|
|
26249
|
+
const currentVideoIndex = videoIndexRef.current;
|
|
26250
|
+
let effectiveFilter = currentFilter;
|
|
26251
|
+
if (sopCategories && sopCategories.length > 0) {
|
|
26252
|
+
const category = sopCategories.find((cat) => cat.id === currentFilter);
|
|
26253
|
+
if (category && category.s3FolderName) {
|
|
26254
|
+
effectiveFilter = category.s3FolderName;
|
|
26255
|
+
}
|
|
26256
|
+
}
|
|
26257
|
+
const cacheKey = `${effectiveFilter}:${date}:${shift}`;
|
|
26258
|
+
if (!loadedVideosMapRef.current.has(cacheKey)) {
|
|
26259
|
+
loadedVideosMapRef.current.set(cacheKey, /* @__PURE__ */ new Set());
|
|
26260
|
+
}
|
|
26261
|
+
const loadedIndices = loadedVideosMapRef.current.get(cacheKey);
|
|
26262
|
+
const indicesToLoad = [];
|
|
26263
|
+
const rangeBefore = 1;
|
|
26264
|
+
const rangeAfter = 3;
|
|
26265
|
+
for (let i = Math.max(0, centerIndex - rangeBefore); i <= Math.min(clipCounts[effectiveFilter] - 1, centerIndex + rangeAfter); i++) {
|
|
26266
|
+
if (!loadedIndices.has(i) && !loadingVideosRef.current.has(i)) {
|
|
26267
|
+
indicesToLoad.push(i);
|
|
26268
|
+
}
|
|
26269
|
+
}
|
|
26270
|
+
if (indicesToLoad.length === 0) return;
|
|
26271
|
+
console.log(`[ensureVideosLoaded] Preloading ${indicesToLoad.length} videos around index ${centerIndex}: [${indicesToLoad.join(", ")}]`);
|
|
26272
|
+
indicesToLoad.forEach((idx) => loadingVideosRef.current.add(idx));
|
|
26273
|
+
const loadPromises = indicesToLoad.map(async (index) => {
|
|
26274
|
+
try {
|
|
26275
|
+
let video = null;
|
|
26276
|
+
if (currentVideoIndex && currentVideoIndex.byCategory && currentVideoIndex.allVideos.length > 0) {
|
|
26277
|
+
video = await s3ClipsService.getVideoFromIndex(
|
|
26278
|
+
currentVideoIndex,
|
|
26279
|
+
effectiveFilter,
|
|
26280
|
+
index,
|
|
26281
|
+
true,
|
|
26282
|
+
// includeCycleTime - OK for preloading
|
|
26283
|
+
true
|
|
26284
|
+
// includeMetadata - OK for just +3/-1 videos, not ALL videos
|
|
26285
|
+
);
|
|
26286
|
+
}
|
|
26287
|
+
if (!video) {
|
|
26288
|
+
const operationalDate = date || getOperationalDate();
|
|
26289
|
+
const shiftStr = shift?.toString() || "0";
|
|
26290
|
+
video = await s3ClipsService.getClipByIndex(
|
|
26291
|
+
workspaceId,
|
|
26292
|
+
operationalDate,
|
|
26293
|
+
shiftStr,
|
|
26294
|
+
effectiveFilter,
|
|
26295
|
+
index,
|
|
26296
|
+
true,
|
|
26297
|
+
// includeCycleTime - OK for preloading
|
|
26298
|
+
true
|
|
26299
|
+
// includeMetadata - OK for just +3/-1 videos, not ALL videos
|
|
26300
|
+
);
|
|
26301
|
+
}
|
|
26302
|
+
if (video && isMountedRef.current) {
|
|
26303
|
+
setAllVideos((prev) => {
|
|
26304
|
+
const exists = prev.some((v) => v.id === video.id);
|
|
26305
|
+
if (!exists) {
|
|
26306
|
+
return [...prev, video];
|
|
26307
|
+
}
|
|
26308
|
+
return prev;
|
|
26309
|
+
});
|
|
26310
|
+
loadedIndices.add(index);
|
|
26311
|
+
preloadVideoUrl(video.src);
|
|
26312
|
+
}
|
|
26313
|
+
} catch (error2) {
|
|
26314
|
+
console.warn(`[ensureVideosLoaded] Failed to load video at index ${index}:`, error2);
|
|
26315
|
+
} finally {
|
|
26316
|
+
loadingVideosRef.current.delete(index);
|
|
26317
|
+
}
|
|
26318
|
+
});
|
|
26319
|
+
Promise.all(loadPromises).catch((err) => {
|
|
26320
|
+
console.warn("[ensureVideosLoaded] Some videos failed to preload:", err);
|
|
26321
|
+
});
|
|
26322
|
+
}, [s3ClipsService, workspaceId, clipCounts, sopCategories, date, shift]);
|
|
26602
26323
|
const loadFirstVideoForCategory = useCallback(async (category) => {
|
|
26603
26324
|
if (!workspaceId || !s3ClipsService || !isMountedRef.current) return;
|
|
26604
26325
|
const targetCategory = category || activeFilterRef.current;
|
|
@@ -26701,9 +26422,11 @@ var BottlenecksContent = ({
|
|
|
26701
26422
|
}, [prefetchData, prefetchStatus, updateClipCounts, updateVideoIndex, hasInitialLoad]);
|
|
26702
26423
|
useEffect(() => {
|
|
26703
26424
|
if (s3ClipsService && videoIndex && clipCounts[activeFilter] > 0) {
|
|
26704
|
-
|
|
26425
|
+
if (allVideos.length === 0) {
|
|
26426
|
+
loadFirstVideoForCategory(activeFilter);
|
|
26427
|
+
}
|
|
26705
26428
|
}
|
|
26706
|
-
}, [activeFilter, s3ClipsService, videoIndex, clipCounts, loadFirstVideoForCategory]);
|
|
26429
|
+
}, [activeFilter, s3ClipsService, videoIndex, clipCounts, loadFirstVideoForCategory, allVideos.length]);
|
|
26707
26430
|
useEffect(() => {
|
|
26708
26431
|
if (previousFilterRef.current !== activeFilter) {
|
|
26709
26432
|
console.log(`Filter changed from ${previousFilterRef.current} to ${activeFilter} - resetting to first video`);
|
|
@@ -26772,26 +26495,25 @@ var BottlenecksContent = ({
|
|
|
26772
26495
|
return new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime();
|
|
26773
26496
|
});
|
|
26774
26497
|
}, [activeFilter, allVideos, sopCategories]);
|
|
26775
|
-
useEffect(() => {
|
|
26776
|
-
if (filteredVideos.length === 0) return;
|
|
26777
|
-
const upcoming = [];
|
|
26778
|
-
if (currentIndex + 1 < filteredVideos.length && filteredVideos[currentIndex + 1]) {
|
|
26779
|
-
upcoming.push(filteredVideos[currentIndex + 1].src);
|
|
26780
|
-
}
|
|
26781
|
-
if (currentIndex - 1 >= 0 && currentIndex - 1 < filteredVideos.length && filteredVideos[currentIndex - 1]) {
|
|
26782
|
-
upcoming.push(filteredVideos[currentIndex - 1].src);
|
|
26783
|
-
}
|
|
26784
|
-
if (upcoming.length > 0) {
|
|
26785
|
-
preloadVideosUrl(upcoming);
|
|
26786
|
-
}
|
|
26787
|
-
}, [currentIndex, filteredVideos]);
|
|
26788
26498
|
useEffect(() => {
|
|
26789
26499
|
if (isNavigating && currentIndex < filteredVideos.length) {
|
|
26790
26500
|
setIsNavigating(false);
|
|
26791
26501
|
setError(null);
|
|
26792
26502
|
videoRetryCountRef.current = 0;
|
|
26503
|
+
ensureVideosLoaded(currentIndex);
|
|
26793
26504
|
}
|
|
26794
26505
|
}, [isNavigating, currentIndex, filteredVideos.length]);
|
|
26506
|
+
useEffect(() => {
|
|
26507
|
+
if (!isPlaying || !isMountedRef.current) return;
|
|
26508
|
+
const preloadInterval = setInterval(() => {
|
|
26509
|
+
if (isMountedRef.current) {
|
|
26510
|
+
const currentIdx = currentIndexRef.current;
|
|
26511
|
+
console.log(`[Background Preloader] Ensuring videos loaded around index ${currentIdx}`);
|
|
26512
|
+
ensureVideosLoaded(currentIdx);
|
|
26513
|
+
}
|
|
26514
|
+
}, 2e3);
|
|
26515
|
+
return () => clearInterval(preloadInterval);
|
|
26516
|
+
}, [isPlaying]);
|
|
26795
26517
|
const handleNext = useCallback(async () => {
|
|
26796
26518
|
if (!isMountedRef.current) return;
|
|
26797
26519
|
const currentIdx = currentIndexRef.current;
|
|
@@ -26812,6 +26534,7 @@ var BottlenecksContent = ({
|
|
|
26812
26534
|
}
|
|
26813
26535
|
if (nextIndex < filteredVideos.length) {
|
|
26814
26536
|
setIsNavigating(false);
|
|
26537
|
+
ensureVideosLoaded(nextIndex);
|
|
26815
26538
|
return;
|
|
26816
26539
|
}
|
|
26817
26540
|
if (isMountedRef.current) {
|
|
@@ -26829,8 +26552,8 @@ var BottlenecksContent = ({
|
|
|
26829
26552
|
nextIndex,
|
|
26830
26553
|
true,
|
|
26831
26554
|
// includeCycleTime
|
|
26832
|
-
|
|
26833
|
-
// includeMetadata
|
|
26555
|
+
false
|
|
26556
|
+
// includeMetadata - DON'T fetch metadata during navigation to prevent flooding!
|
|
26834
26557
|
);
|
|
26835
26558
|
} else {
|
|
26836
26559
|
console.warn(`[BottlenecksContent] Video index not ready for navigation: ID: ${currentVideoIndex?._debugId || "NO_ID"}, byCategory exists = ${!!currentVideoIndex?.byCategory}, allVideos = ${currentVideoIndex?.allVideos?.length || 0}`);
|
|
@@ -26843,7 +26566,11 @@ var BottlenecksContent = ({
|
|
|
26843
26566
|
operationalDate,
|
|
26844
26567
|
shiftStr,
|
|
26845
26568
|
effectiveFilter,
|
|
26846
|
-
nextIndex
|
|
26569
|
+
nextIndex,
|
|
26570
|
+
true,
|
|
26571
|
+
// includeCycleTime - needed for main video display
|
|
26572
|
+
false
|
|
26573
|
+
// includeMetadata - DON'T fetch metadata during navigation to prevent flooding!
|
|
26847
26574
|
);
|
|
26848
26575
|
}
|
|
26849
26576
|
if (video && isMountedRef.current) {
|
|
@@ -26856,26 +26583,7 @@ var BottlenecksContent = ({
|
|
|
26856
26583
|
return prev;
|
|
26857
26584
|
});
|
|
26858
26585
|
preloadVideoUrl(video.src);
|
|
26859
|
-
|
|
26860
|
-
setTimeout(() => {
|
|
26861
|
-
const videoIndexForPreload = videoIndexRef.current;
|
|
26862
|
-
if (videoIndexForPreload && s3ClipsService && isMountedRef.current) {
|
|
26863
|
-
s3ClipsService.getVideoFromIndex(videoIndexForPreload, effectiveFilter, nextIndex + 1, true, true).then((nextVideo) => {
|
|
26864
|
-
if (nextVideo && isMountedRef.current) {
|
|
26865
|
-
setAllVideos((prev) => {
|
|
26866
|
-
if (!prev.some((v) => v.id === nextVideo.id)) {
|
|
26867
|
-
const newVideos = [...prev, nextVideo];
|
|
26868
|
-
return newVideos;
|
|
26869
|
-
}
|
|
26870
|
-
return prev;
|
|
26871
|
-
});
|
|
26872
|
-
preloadVideoUrl(nextVideo.src);
|
|
26873
|
-
}
|
|
26874
|
-
}).catch(() => {
|
|
26875
|
-
});
|
|
26876
|
-
}
|
|
26877
|
-
}, 100);
|
|
26878
|
-
}
|
|
26586
|
+
ensureVideosLoaded(nextIndex);
|
|
26879
26587
|
}
|
|
26880
26588
|
} catch (error2) {
|
|
26881
26589
|
console.error("Error loading next video:", error2);
|
|
@@ -26897,6 +26605,7 @@ var BottlenecksContent = ({
|
|
|
26897
26605
|
if (prevIndex < filteredVideos.length) {
|
|
26898
26606
|
setCurrentIndex(prevIndex);
|
|
26899
26607
|
setError(null);
|
|
26608
|
+
ensureVideosLoaded(prevIndex);
|
|
26900
26609
|
}
|
|
26901
26610
|
}
|
|
26902
26611
|
}, [filteredVideos.length]);
|
|
@@ -26905,6 +26614,8 @@ var BottlenecksContent = ({
|
|
|
26905
26614
|
}, []);
|
|
26906
26615
|
const handleVideoPlay = useCallback((player) => {
|
|
26907
26616
|
setIsPlaying(true);
|
|
26617
|
+
const currentIdx = currentIndexRef.current;
|
|
26618
|
+
ensureVideosLoaded(currentIdx);
|
|
26908
26619
|
}, []);
|
|
26909
26620
|
const handleVideoPause = useCallback((player) => {
|
|
26910
26621
|
setIsPlaying(false);
|
|
@@ -35470,6 +35181,10 @@ var TargetsViewUI = ({
|
|
|
35470
35181
|
),
|
|
35471
35182
|
/* @__PURE__ */ jsx("div", { className: "h-8 w-px bg-gray-200/80" }),
|
|
35472
35183
|
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-3", children: /* @__PURE__ */ jsxs("div", { className: "ml-4 text-sm font-medium text-gray-600", children: [
|
|
35184
|
+
line.shiftStartTime,
|
|
35185
|
+
" \u2013 ",
|
|
35186
|
+
line.shiftEndTime,
|
|
35187
|
+
" \u2022 ",
|
|
35473
35188
|
line.shiftHours,
|
|
35474
35189
|
" hours"
|
|
35475
35190
|
] }) })
|
|
@@ -36132,7 +35847,7 @@ var TargetsView = ({
|
|
|
36132
35847
|
const handleShiftChange = (shiftId) => {
|
|
36133
35848
|
setSelectedShift(shiftId);
|
|
36134
35849
|
const loadShiftHours = async () => {
|
|
36135
|
-
const updatedLineWorkspaces = { ...
|
|
35850
|
+
const updatedLineWorkspaces = { ...allShiftsData[shiftId] };
|
|
36136
35851
|
let hasUpdates = false;
|
|
36137
35852
|
for (const lineId of lineIds) {
|
|
36138
35853
|
try {
|
|
@@ -36180,7 +35895,10 @@ var TargetsView = ({
|
|
|
36180
35895
|
}
|
|
36181
35896
|
}
|
|
36182
35897
|
if (hasUpdates) {
|
|
36183
|
-
|
|
35898
|
+
setAllShiftsData((prev) => ({
|
|
35899
|
+
...prev,
|
|
35900
|
+
[shiftId]: updatedLineWorkspaces
|
|
35901
|
+
}));
|
|
36184
35902
|
}
|
|
36185
35903
|
};
|
|
36186
35904
|
loadShiftHours();
|
|
@@ -37829,4 +37547,4 @@ var streamProxyConfig = {
|
|
|
37829
37547
|
}
|
|
37830
37548
|
};
|
|
37831
37549
|
|
|
37832
|
-
export { ACTION_NAMES, AIAgentView_default as AIAgentView, AudioService, AuthCallback, AuthCallbackView_default as AuthCallbackView, AuthProvider, AuthenticatedFactoryView, AuthenticatedHelpView, AuthenticatedHomeView, AuthenticatedTargetsView, BarChart, BaseHistoryCalendar, BottlenecksContent, BreakNotificationPopup, CachePrefetchStatus, Card2 as Card, CardContent2 as CardContent, CardDescription2 as CardDescription, CardFooter2 as CardFooter, CardHeader2 as CardHeader, CardTitle2 as CardTitle, CongratulationsOverlay, CycleTimeChart, CycleTimeOverTimeChart, DEFAULT_ANALYTICS_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_CONFIG, DEFAULT_DATABASE_CONFIG, DEFAULT_DATE_TIME_CONFIG, DEFAULT_ENDPOINTS_CONFIG, DEFAULT_ENTITY_CONFIG, DEFAULT_SHIFT_CONFIG, DEFAULT_THEME_CONFIG, DEFAULT_VIDEO_CONFIG, DEFAULT_WORKSPACE_CONFIG, DEFAULT_WORKSPACE_POSITIONS, DashboardHeader, DashboardLayout, DashboardOverridesProvider, DashboardProvider, DateDisplay_default as DateDisplay, DateTimeDisplay, DebugAuth, DebugAuthView_default as DebugAuthView, EmptyStateMessage, EncouragementOverlay, FactoryView_default as FactoryView, GaugeChart, GridComponentsPlaceholder, HamburgerButton, Header, HelpView_default as HelpView, HomeView_default as HomeView, HourlyOutputChart2 as HourlyOutputChart, ISTTimer_default as ISTTimer, KPICard, KPIDetailView_default as KPIDetailView, KPIGrid, KPIHeader, KPISection, KPIsOverviewView_default as KPIsOverviewView, LINE_1_UUID, LINE_2_UUID, LargeOutputProgressChart, LeaderboardDetailView_default as LeaderboardDetailView, Legend6 as Legend, LineChart, LineHistoryCalendar, LineMonthlyHistory, LineMonthlyPdfGenerator, LinePdfExportButton, LinePdfGenerator, LineWhatsAppShareButton, LiveTimer, LoadingInline, LoadingOverlay_default as LoadingOverlay, LoadingPage_default as LoadingPage, LoadingSkeleton, LoadingState, LoginPage, LoginView_default as LoginView, MainLayout, MetricCard_default as MetricCard, NoWorkspaceData, OptifyeAgentClient, OptifyeLogoLoader_default as OptifyeLogoLoader, OutputProgressChart, PageHeader, PieChart4 as PieChart, PrefetchConfigurationError, PrefetchError, PrefetchEvents, PrefetchStatus, PrefetchTimeoutError, ProfileView_default as ProfileView, RegistryProvider, S3Service, SKUManagementView, SOPComplianceChart, SSEChatClient, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, ShiftDisplay_default as ShiftDisplay, ShiftsView_default as ShiftsView, SideNavBar, SingleVideoStream_default as SingleVideoStream, Skeleton, SubscriptionManager, SubscriptionManagerProvider, SupabaseProvider, TargetWorkspaceGrid, TargetsView_default as TargetsView, ThreadSidebar, TicketHistory_default as TicketHistory, TicketHistoryService, TimeDisplay_default as TimeDisplay, TimePickerDropdown, VideoCard, VideoGridView, VideoPlayer, VideoPreloader, WORKSPACE_POSITIONS, WhatsAppShareButton, WorkspaceCard, WorkspaceDetailView_default as WorkspaceDetailView, WorkspaceDisplayNameExample, WorkspaceGrid, WorkspaceGridItem, WorkspaceHistoryCalendar, WorkspaceMetricCards, WorkspaceMonthlyDataFetcher, WorkspaceMonthlyPdfGenerator, WorkspacePdfExportButton, WorkspacePdfGenerator, WorkspaceWhatsAppShareButton, actionService, apiUtils, authCoreService, authOTPService, authRateLimitService,
|
|
37550
|
+
export { ACTION_NAMES, AIAgentView_default as AIAgentView, AudioService, AuthCallback, AuthCallbackView_default as AuthCallbackView, AuthProvider, AuthenticatedFactoryView, AuthenticatedHelpView, AuthenticatedHomeView, AuthenticatedTargetsView, BarChart, BaseHistoryCalendar, BottlenecksContent, BreakNotificationPopup, CachePrefetchStatus, Card2 as Card, CardContent2 as CardContent, CardDescription2 as CardDescription, CardFooter2 as CardFooter, CardHeader2 as CardHeader, CardTitle2 as CardTitle, CongratulationsOverlay, CycleTimeChart, CycleTimeOverTimeChart, DEFAULT_ANALYTICS_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_CONFIG, DEFAULT_DATABASE_CONFIG, DEFAULT_DATE_TIME_CONFIG, DEFAULT_ENDPOINTS_CONFIG, DEFAULT_ENTITY_CONFIG, DEFAULT_SHIFT_CONFIG, DEFAULT_THEME_CONFIG, DEFAULT_VIDEO_CONFIG, DEFAULT_WORKSPACE_CONFIG, DEFAULT_WORKSPACE_POSITIONS, DashboardHeader, DashboardLayout, DashboardOverridesProvider, DashboardProvider, DateDisplay_default as DateDisplay, DateTimeDisplay, DebugAuth, DebugAuthView_default as DebugAuthView, EmptyStateMessage, EncouragementOverlay, FactoryView_default as FactoryView, GaugeChart, GridComponentsPlaceholder, HamburgerButton, Header, HelpView_default as HelpView, HomeView_default as HomeView, HourlyOutputChart2 as HourlyOutputChart, ISTTimer_default as ISTTimer, KPICard, KPIDetailView_default as KPIDetailView, KPIGrid, KPIHeader, KPISection, KPIsOverviewView_default as KPIsOverviewView, LINE_1_UUID, LINE_2_UUID, LargeOutputProgressChart, LeaderboardDetailView_default as LeaderboardDetailView, Legend6 as Legend, LineChart, LineHistoryCalendar, LineMonthlyHistory, LineMonthlyPdfGenerator, LinePdfExportButton, LinePdfGenerator, LineWhatsAppShareButton, LiveTimer, LoadingInline, LoadingOverlay_default as LoadingOverlay, LoadingPage_default as LoadingPage, LoadingSkeleton, LoadingState, LoginPage, LoginView_default as LoginView, MainLayout, MetricCard_default as MetricCard, NoWorkspaceData, OptifyeAgentClient, OptifyeLogoLoader_default as OptifyeLogoLoader, OutputProgressChart, PageHeader, PieChart4 as PieChart, PrefetchConfigurationError, PrefetchError, PrefetchEvents, PrefetchStatus, PrefetchTimeoutError, ProfileView_default as ProfileView, RegistryProvider, S3Service, SKUManagementView, SOPComplianceChart, SSEChatClient, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, ShiftDisplay_default as ShiftDisplay, ShiftsView_default as ShiftsView, SideNavBar, SingleVideoStream_default as SingleVideoStream, Skeleton, SubscriptionManager, SubscriptionManagerProvider, SupabaseProvider, TargetWorkspaceGrid, TargetsView_default as TargetsView, ThreadSidebar, TicketHistory_default as TicketHistory, TicketHistoryService, TimeDisplay_default as TimeDisplay, TimePickerDropdown, VideoCard, VideoGridView, VideoPlayer, VideoPreloader, WORKSPACE_POSITIONS, WhatsAppShareButton, WorkspaceCard, WorkspaceDetailView_default as WorkspaceDetailView, WorkspaceDisplayNameExample, WorkspaceGrid, WorkspaceGridItem, WorkspaceHistoryCalendar, WorkspaceMetricCards, WorkspaceMonthlyDataFetcher, WorkspaceMonthlyPdfGenerator, WorkspacePdfExportButton, WorkspacePdfGenerator, WorkspaceWhatsAppShareButton, actionService, apiUtils, authCoreService, authOTPService, authRateLimitService, checkRateLimit2 as checkRateLimit, clearAllRateLimits2 as clearAllRateLimits, clearRateLimit2 as clearRateLimit, clearS3VideoCache, clearS3VideoFromCache, clearWorkspaceDisplayNamesCache, cn, createStreamProxyHandler, createSupabaseClient, createThrottledReload, dashboardService, deleteThread, forceRefreshWorkspaceDisplayNames, formatDateInZone, formatDateTimeInZone, formatISTDate, formatIdleTime, formatTimeInZone, fromUrlFriendlyName, getAllLineDisplayNames, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAnonClient, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getConfiguredLineIds, getCoreSessionRecordingProperties, getCoreSessionReplayUrl, getCurrentShift, getCurrentTimeInZone, getDashboardHeaderTimeInZone, getDaysDifferenceInZone, getDefaultCameraStreamUrl, getDefaultLineId, getDefaultTabForWorkspace, getLineDisplayName, getManufacturingInsights, getMetricsTablePrefix, getOperationalDate, getS3SignedUrl, getS3VideoSrc, getShortWorkspaceDisplayName, getShortWorkspaceDisplayNameAsync, getStoredWorkspaceMappings, getSubscriptionManager, getThreadMessages, getUserThreads, getUserThreadsPaginated, getWorkspaceDisplayName, getWorkspaceDisplayNameAsync, getWorkspaceDisplayNamesMap, getWorkspaceFromUrl, getWorkspaceNavigationParams, identifyCoreUser, initializeCoreMixpanel, isLegacyConfiguration, isPrefetchError, isTransitionPeriod, isUrlPermanentlyFailed, isValidFactoryViewConfiguration, isValidLineInfoPayload, isValidPrefetchParams, isValidPrefetchStatus, isValidWorkspaceDetailedMetricsPayload, isValidWorkspaceMetricsPayload, isWorkspaceDisplayNamesLoaded, isWorkspaceDisplayNamesLoading, mergeWithDefaultConfig, migrateLegacyConfiguration, optifyeAgentClient, preInitializeWorkspaceDisplayNames, preloadS3Video, preloadS3VideoUrl, preloadS3VideosUrl, preloadVideoUrl, preloadVideosUrl, qualityService, realtimeService, refreshWorkspaceDisplayNames, resetCoreMixpanel, resetFailedUrl, resetSubscriptionManager, s3VideoPreloader, skuService, startCoreSessionRecording, stopCoreSessionRecording, storeWorkspaceMapping, streamProxyConfig, throttledReloadDashboard, toUrlFriendlyName, trackCoreEvent, trackCorePageView, updateThreadTitle, useActiveBreaks, useAllWorkspaceMetrics, useAnalyticsConfig, useAudioService, useAuth, useAuthConfig, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHistoricWorkspaceMetrics, useHlsStream, useHlsStreamWithCropping, useHookOverride, useHourEndTimer, useHourlyTargetAchievements, useHourlyTargetMisses, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineWorkspaceMetrics, useMessages, useMetrics, useNavigation, useOverrides, usePageOverride, usePrefetchClipCounts, useRealtimeLineMetrics, useRegistry, useSKUs, useShiftConfig, useShifts, useSubscriptionManager, useSubscriptionManagerSafe, useSupabase, useSupabaseClient, useTargets, useTheme, useThemeConfig, useThreads, useTicketHistory, useVideoConfig, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, videoPrefetchManager, videoPreloader, whatsappService, withAuth, withRegistry, workspaceService };
|