@optifye/dashboard-core 6.12.51 → 6.12.53
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/automation.js +2 -0
- package/dist/automation.js.map +1 -0
- package/dist/automation.mjs +2 -0
- package/dist/automation.mjs.map +1 -0
- package/dist/index.css +1 -11
- package/dist/index.css.map +1 -0
- package/dist/index.d.mts +73 -33
- package/dist/index.d.ts +73 -33
- package/dist/index.js +2660 -594
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2661 -596
- package/dist/index.mjs.map +1 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6067,7 +6067,8 @@ var getAuthToken2 = async () => {
|
|
|
6067
6067
|
var workspaceService = {
|
|
6068
6068
|
// Cache for workspace display names to avoid repeated API calls
|
|
6069
6069
|
_workspaceDisplayNamesCache: /* @__PURE__ */ new Map(),
|
|
6070
|
-
|
|
6070
|
+
_workspaceDisplayNamesInFlight: /* @__PURE__ */ new Map(),
|
|
6071
|
+
_workspaceDisplayNamesByLineInFlight: /* @__PURE__ */ new Map(),
|
|
6071
6072
|
_cacheExpiryMs: 5 * 60 * 1e3,
|
|
6072
6073
|
// 5 minutes cache
|
|
6073
6074
|
// Cache for workspace lists to avoid repeated API calls (line configuration changes infrequently)
|
|
@@ -6326,12 +6327,74 @@ var workspaceService = {
|
|
|
6326
6327
|
* Returns a map of workspace_id -> display_name
|
|
6327
6328
|
*/
|
|
6328
6329
|
async getWorkspaceDisplayNames(companyId, lineId) {
|
|
6329
|
-
|
|
6330
|
+
const cacheKey = `${companyId || "all"}::${lineId || "all"}`;
|
|
6331
|
+
const existingInFlight = this._workspaceDisplayNamesInFlight.get(cacheKey);
|
|
6332
|
+
if (existingInFlight) {
|
|
6333
|
+
return existingInFlight;
|
|
6334
|
+
}
|
|
6335
|
+
const fetchPromise = (async () => {
|
|
6336
|
+
try {
|
|
6337
|
+
const token = await getAuthToken2();
|
|
6338
|
+
const apiUrl = getBackendUrl2();
|
|
6339
|
+
const params = new URLSearchParams();
|
|
6340
|
+
if (companyId) params.append("company_id", companyId);
|
|
6341
|
+
if (lineId) params.append("line_id", lineId);
|
|
6342
|
+
const response = await fetch(`${apiUrl}/api/workspaces/display-names?${params.toString()}`, {
|
|
6343
|
+
headers: {
|
|
6344
|
+
"Authorization": `Bearer ${token}`,
|
|
6345
|
+
"Content-Type": "application/json"
|
|
6346
|
+
}
|
|
6347
|
+
});
|
|
6348
|
+
if (!response.ok) {
|
|
6349
|
+
const errorText = await response.text();
|
|
6350
|
+
throw new Error(`Backend API error (${response.status}): ${errorText}`);
|
|
6351
|
+
}
|
|
6352
|
+
const data = await response.json();
|
|
6353
|
+
const displayNamesMap = /* @__PURE__ */ new Map();
|
|
6354
|
+
if (data.display_names) {
|
|
6355
|
+
Object.entries(data.display_names).forEach(([key, value]) => {
|
|
6356
|
+
displayNamesMap.set(key, value);
|
|
6357
|
+
});
|
|
6358
|
+
}
|
|
6359
|
+
this._workspaceDisplayNamesCache.set(cacheKey, {
|
|
6360
|
+
displayNames: displayNamesMap,
|
|
6361
|
+
timestamp: Date.now()
|
|
6362
|
+
});
|
|
6363
|
+
return displayNamesMap;
|
|
6364
|
+
} catch (error) {
|
|
6365
|
+
console.error("Error fetching workspace display names:", error);
|
|
6366
|
+
addSentryBreadcrumb("Workspace display-name fallback failed", {
|
|
6367
|
+
surface: "workspace_display_names",
|
|
6368
|
+
route: "/api/workspaces/display-names",
|
|
6369
|
+
severity: "warning",
|
|
6370
|
+
extras: {
|
|
6371
|
+
company_id: companyId || null,
|
|
6372
|
+
line_id: lineId || null,
|
|
6373
|
+
pathname: typeof window !== "undefined" ? window.location.pathname : "unknown",
|
|
6374
|
+
error_message: error instanceof Error ? error.message : String(error)
|
|
6375
|
+
}
|
|
6376
|
+
});
|
|
6377
|
+
throw error;
|
|
6378
|
+
} finally {
|
|
6379
|
+
this._workspaceDisplayNamesInFlight.delete(cacheKey);
|
|
6380
|
+
}
|
|
6381
|
+
})();
|
|
6382
|
+
this._workspaceDisplayNamesInFlight.set(cacheKey, fetchPromise);
|
|
6383
|
+
return fetchPromise;
|
|
6384
|
+
},
|
|
6385
|
+
async getWorkspaceDisplayNamesByLine(companyId, lineIds) {
|
|
6386
|
+
const normalizedLineIds = Array.from(new Set((lineIds || []).filter(Boolean))).sort();
|
|
6387
|
+
const cacheKey = `${companyId || "all"}::byLine::${normalizedLineIds.join(",") || "all"}`;
|
|
6388
|
+
const existingInFlight = this._workspaceDisplayNamesByLineInFlight.get(cacheKey);
|
|
6389
|
+
if (existingInFlight) {
|
|
6390
|
+
return existingInFlight;
|
|
6391
|
+
}
|
|
6392
|
+
const fetchPromise = (async () => {
|
|
6330
6393
|
const token = await getAuthToken2();
|
|
6331
6394
|
const apiUrl = getBackendUrl2();
|
|
6332
6395
|
const params = new URLSearchParams();
|
|
6333
6396
|
if (companyId) params.append("company_id", companyId);
|
|
6334
|
-
if (
|
|
6397
|
+
if (normalizedLineIds.length > 0) params.append("line_ids", normalizedLineIds.join(","));
|
|
6335
6398
|
const response = await fetch(`${apiUrl}/api/workspaces/display-names?${params.toString()}`, {
|
|
6336
6399
|
headers: {
|
|
6337
6400
|
"Authorization": `Bearer ${token}`,
|
|
@@ -6343,39 +6406,32 @@ var workspaceService = {
|
|
|
6343
6406
|
throw new Error(`Backend API error (${response.status}): ${errorText}`);
|
|
6344
6407
|
}
|
|
6345
6408
|
const data = await response.json();
|
|
6346
|
-
const
|
|
6347
|
-
|
|
6348
|
-
|
|
6349
|
-
|
|
6409
|
+
const source = data.display_names_by_line || {};
|
|
6410
|
+
const byLine = /* @__PURE__ */ new Map();
|
|
6411
|
+
Object.entries(source).forEach(([lineId, displayNames]) => {
|
|
6412
|
+
if (normalizedLineIds.length > 0 && !normalizedLineIds.includes(lineId)) return;
|
|
6413
|
+
const lineMap = /* @__PURE__ */ new Map();
|
|
6414
|
+
Object.entries(displayNames).forEach(([workspaceId, displayName]) => {
|
|
6415
|
+
lineMap.set(workspaceId, displayName);
|
|
6350
6416
|
});
|
|
6351
|
-
|
|
6352
|
-
this._workspaceDisplayNamesCache = displayNamesMap;
|
|
6353
|
-
this._cacheTimestamp = Date.now();
|
|
6354
|
-
return displayNamesMap;
|
|
6355
|
-
} catch (error) {
|
|
6356
|
-
console.error("Error fetching workspace display names:", error);
|
|
6357
|
-
addSentryBreadcrumb("Workspace display-name fallback failed", {
|
|
6358
|
-
surface: "workspace_display_names",
|
|
6359
|
-
route: "/api/workspaces/display-names",
|
|
6360
|
-
severity: "warning",
|
|
6361
|
-
extras: {
|
|
6362
|
-
company_id: companyId || null,
|
|
6363
|
-
line_id: lineId || null,
|
|
6364
|
-
pathname: typeof window !== "undefined" ? window.location.pathname : "unknown",
|
|
6365
|
-
error_message: error instanceof Error ? error.message : String(error)
|
|
6366
|
-
}
|
|
6417
|
+
byLine.set(lineId, lineMap);
|
|
6367
6418
|
});
|
|
6368
|
-
|
|
6369
|
-
}
|
|
6419
|
+
return byLine;
|
|
6420
|
+
})().finally(() => {
|
|
6421
|
+
this._workspaceDisplayNamesByLineInFlight.delete(cacheKey);
|
|
6422
|
+
});
|
|
6423
|
+
this._workspaceDisplayNamesByLineInFlight.set(cacheKey, fetchPromise);
|
|
6424
|
+
return fetchPromise;
|
|
6370
6425
|
},
|
|
6371
6426
|
/**
|
|
6372
6427
|
* Gets cached workspace display names (with cache expiry)
|
|
6373
6428
|
*/
|
|
6374
6429
|
async getCachedWorkspaceDisplayNames(companyId, lineId) {
|
|
6375
6430
|
const now4 = Date.now();
|
|
6376
|
-
const
|
|
6377
|
-
|
|
6378
|
-
|
|
6431
|
+
const cacheKey = `${companyId || "all"}::${lineId || "all"}`;
|
|
6432
|
+
const cached = this._workspaceDisplayNamesCache.get(cacheKey);
|
|
6433
|
+
if (cached && now4 - cached.timestamp < this._cacheExpiryMs && cached.displayNames.size > 0) {
|
|
6434
|
+
return cached.displayNames;
|
|
6379
6435
|
}
|
|
6380
6436
|
return this.getWorkspaceDisplayNames(companyId, lineId);
|
|
6381
6437
|
},
|
|
@@ -6396,7 +6452,8 @@ var workspaceService = {
|
|
|
6396
6452
|
*/
|
|
6397
6453
|
clearWorkspaceDisplayNamesCache() {
|
|
6398
6454
|
this._workspaceDisplayNamesCache.clear();
|
|
6399
|
-
this.
|
|
6455
|
+
this._workspaceDisplayNamesInFlight.clear();
|
|
6456
|
+
this._workspaceDisplayNamesByLineInFlight.clear();
|
|
6400
6457
|
},
|
|
6401
6458
|
clearWorkspacesCache() {
|
|
6402
6459
|
this._workspacesCache.clear();
|
|
@@ -6902,10 +6959,16 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
|
6902
6959
|
hasBackendUrl() {
|
|
6903
6960
|
return Boolean(process.env.NEXT_PUBLIC_BACKEND_URL);
|
|
6904
6961
|
}
|
|
6962
|
+
isCanonicalDate(value) {
|
|
6963
|
+
return typeof value === "string" && /^\d{4}-\d{2}-\d{2}$/.test(value);
|
|
6964
|
+
}
|
|
6905
6965
|
async fetchBackendWorkspaceUptimeSummaries(companyId, lineIds, date, shiftId, timezone) {
|
|
6906
6966
|
if (!this.hasBackendUrl()) {
|
|
6907
6967
|
return null;
|
|
6908
6968
|
}
|
|
6969
|
+
if (!this.isCanonicalDate(date)) {
|
|
6970
|
+
return null;
|
|
6971
|
+
}
|
|
6909
6972
|
const supabase = _getSupabaseInstance();
|
|
6910
6973
|
if (!supabase) throw new Error("Supabase client not initialized");
|
|
6911
6974
|
const params = new URLSearchParams({
|
|
@@ -6955,6 +7018,9 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
|
6955
7018
|
if (!this.hasBackendUrl()) {
|
|
6956
7019
|
return null;
|
|
6957
7020
|
}
|
|
7021
|
+
if (!this.isCanonicalDate(date)) {
|
|
7022
|
+
return null;
|
|
7023
|
+
}
|
|
6958
7024
|
const supabase = _getSupabaseInstance();
|
|
6959
7025
|
if (!supabase) throw new Error("Supabase client not initialized");
|
|
6960
7026
|
const params = new URLSearchParams({
|
|
@@ -7689,6 +7755,24 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
|
7689
7755
|
const currentTiming = this.getShiftTiming(timezone, shiftConfig);
|
|
7690
7756
|
const queryDate = overrideDate ?? currentTiming.date;
|
|
7691
7757
|
const queryShiftId = overrideShiftId ?? currentTiming.shiftId;
|
|
7758
|
+
if (!this.isCanonicalDate(queryDate)) {
|
|
7759
|
+
return {
|
|
7760
|
+
shiftId: queryShiftId,
|
|
7761
|
+
shiftLabel: currentTiming.shiftLabel,
|
|
7762
|
+
shiftStart: dateFnsTz.formatInTimeZone(currentTiming.shiftStartDate, timezone, "yyyy-MM-dd'T'HH:mm:ssXXX"),
|
|
7763
|
+
shiftEnd: dateFnsTz.formatInTimeZone(currentTiming.shiftEndDate, timezone, "yyyy-MM-dd'T'HH:mm:ssXXX"),
|
|
7764
|
+
totalMinutes: currentTiming.totalMinutes,
|
|
7765
|
+
completedMinutes: currentTiming.completedMinutes,
|
|
7766
|
+
uptimeMinutes: 0,
|
|
7767
|
+
downtimeMinutes: 0,
|
|
7768
|
+
pendingMinutes: currentTiming.pendingMinutes,
|
|
7769
|
+
uptimePercentage: 0,
|
|
7770
|
+
hasData: false,
|
|
7771
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7772
|
+
points: [],
|
|
7773
|
+
downtimeSegments: []
|
|
7774
|
+
};
|
|
7775
|
+
}
|
|
7692
7776
|
if (lineId) {
|
|
7693
7777
|
const backendTimeline = await this.fetchBackendWorkspaceUptimeTimeline(
|
|
7694
7778
|
workspaceId,
|
|
@@ -7911,6 +7995,9 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
|
7911
7995
|
const defaultTimezone = dashboardConfig?.dateTimeConfig?.defaultTimezone || "UTC";
|
|
7912
7996
|
const shiftConfig = passedShiftConfig || dashboardConfig?.shiftConfig;
|
|
7913
7997
|
const effectiveTimezone = timezone || shiftConfig?.timezone || defaultTimezone;
|
|
7998
|
+
if (overrideDate !== void 0 && !this.isCanonicalDate(overrideDate)) {
|
|
7999
|
+
return /* @__PURE__ */ new Map();
|
|
8000
|
+
}
|
|
7914
8001
|
if (lineShiftConfigs && lineShiftConfigs.size > 0) {
|
|
7915
8002
|
return this.calculateWorkspaceUptimeMultiLine(
|
|
7916
8003
|
companyId,
|
|
@@ -12003,85 +12090,290 @@ function formatReasonLabel(reason) {
|
|
|
12003
12090
|
return reason.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
|
|
12004
12091
|
}
|
|
12005
12092
|
|
|
12093
|
+
// src/lib/services/sessionActivityAccumulator.ts
|
|
12094
|
+
var TRACKED_ACTIVITY_EVENTS = ["mousemove", "pointermove", "keydown", "click", "scroll", "wheel", "touchstart"];
|
|
12095
|
+
function createSessionData(sessionId, userId, companyId, now4, isVisible, isFocused) {
|
|
12096
|
+
return {
|
|
12097
|
+
sessionId,
|
|
12098
|
+
userId,
|
|
12099
|
+
companyId,
|
|
12100
|
+
startedAt: now4,
|
|
12101
|
+
lastTick: now4,
|
|
12102
|
+
cumulativeTotalMs: 0,
|
|
12103
|
+
cumulativeActiveMs: 0,
|
|
12104
|
+
cumulativePassiveMs: 0,
|
|
12105
|
+
lastActivityAt: null,
|
|
12106
|
+
isUserActive: false,
|
|
12107
|
+
isVisible,
|
|
12108
|
+
isFocused,
|
|
12109
|
+
state: "ACTIVE",
|
|
12110
|
+
currentSegment: null,
|
|
12111
|
+
pendingSegments: [],
|
|
12112
|
+
segmentCounter: 0
|
|
12113
|
+
};
|
|
12114
|
+
}
|
|
12115
|
+
var SessionActivityAccumulator = class {
|
|
12116
|
+
constructor(idleThresholdMs, getDashboardView) {
|
|
12117
|
+
this.idleThresholdMs = idleThresholdMs;
|
|
12118
|
+
this.getDashboardView = getDashboardView;
|
|
12119
|
+
}
|
|
12120
|
+
shouldTrackTime(session) {
|
|
12121
|
+
if (!session) return false;
|
|
12122
|
+
return session.state === "ACTIVE" && session.isVisible && session.isFocused;
|
|
12123
|
+
}
|
|
12124
|
+
getActivityState(session, now4) {
|
|
12125
|
+
if (!session.lastActivityAt) {
|
|
12126
|
+
return "passive";
|
|
12127
|
+
}
|
|
12128
|
+
const timeSinceActivity = now4.getTime() - session.lastActivityAt.getTime();
|
|
12129
|
+
return timeSinceActivity <= this.idleThresholdMs ? "active" : "passive";
|
|
12130
|
+
}
|
|
12131
|
+
updateTimes(session, now4 = /* @__PURE__ */ new Date()) {
|
|
12132
|
+
if (!session || session.state === "ENDED") return;
|
|
12133
|
+
const elapsed = now4.getTime() - session.lastTick.getTime();
|
|
12134
|
+
if (elapsed <= 0) return;
|
|
12135
|
+
if (!this.shouldTrackTime(session)) {
|
|
12136
|
+
this.flushCurrentSegment(session, now4);
|
|
12137
|
+
session.lastTick = now4;
|
|
12138
|
+
return;
|
|
12139
|
+
}
|
|
12140
|
+
let cursor = new Date(session.lastTick);
|
|
12141
|
+
const idleCutoff = session.lastActivityAt ? new Date(session.lastActivityAt.getTime() + this.idleThresholdMs) : null;
|
|
12142
|
+
if (idleCutoff && cursor < idleCutoff && now4 > idleCutoff) {
|
|
12143
|
+
this.addTrackedDuration(session, "active", cursor, idleCutoff);
|
|
12144
|
+
cursor = idleCutoff;
|
|
12145
|
+
}
|
|
12146
|
+
this.addTrackedDuration(session, this.getActivityState(session, now4), cursor, now4);
|
|
12147
|
+
session.lastTick = now4;
|
|
12148
|
+
}
|
|
12149
|
+
flushCurrentSegment(session, endAt) {
|
|
12150
|
+
if (!session?.currentSegment) return;
|
|
12151
|
+
const current = session.currentSegment;
|
|
12152
|
+
const currentEndMs = new Date(current.segment_end_at).getTime();
|
|
12153
|
+
if (endAt.getTime() > currentEndMs) {
|
|
12154
|
+
current.duration_ms += endAt.getTime() - currentEndMs;
|
|
12155
|
+
current.segment_end_at = endAt.toISOString();
|
|
12156
|
+
}
|
|
12157
|
+
if (current.duration_ms > 0) {
|
|
12158
|
+
session.pendingSegments.push(current);
|
|
12159
|
+
}
|
|
12160
|
+
session.currentSegment = null;
|
|
12161
|
+
}
|
|
12162
|
+
addTrackedDuration(session, state, start, end) {
|
|
12163
|
+
const durationMs = end.getTime() - start.getTime();
|
|
12164
|
+
if (durationMs <= 0) return;
|
|
12165
|
+
session.cumulativeTotalMs += durationMs;
|
|
12166
|
+
if (state === "active") {
|
|
12167
|
+
session.cumulativeActiveMs += durationMs;
|
|
12168
|
+
session.isUserActive = true;
|
|
12169
|
+
} else {
|
|
12170
|
+
session.cumulativePassiveMs += durationMs;
|
|
12171
|
+
session.isUserActive = false;
|
|
12172
|
+
}
|
|
12173
|
+
this.addSegmentDuration(session, state, start, end);
|
|
12174
|
+
}
|
|
12175
|
+
addSegmentDuration(session, state, start, end) {
|
|
12176
|
+
const durationMs = end.getTime() - start.getTime();
|
|
12177
|
+
if (durationMs <= 0) return;
|
|
12178
|
+
const dashboardView = this.getDashboardView();
|
|
12179
|
+
const current = session.currentSegment;
|
|
12180
|
+
if (current && current.state === state && current.dashboard_view === dashboardView && current.segment_end_at === start.toISOString()) {
|
|
12181
|
+
current.segment_end_at = end.toISOString();
|
|
12182
|
+
current.duration_ms += durationMs;
|
|
12183
|
+
return;
|
|
12184
|
+
}
|
|
12185
|
+
this.flushCurrentSegment(session, start);
|
|
12186
|
+
session.segmentCounter += 1;
|
|
12187
|
+
session.currentSegment = {
|
|
12188
|
+
client_segment_id: `${session.sessionId}_seg_${session.segmentCounter}`,
|
|
12189
|
+
segment_start_at: start.toISOString(),
|
|
12190
|
+
segment_end_at: end.toISOString(),
|
|
12191
|
+
state,
|
|
12192
|
+
duration_ms: durationMs,
|
|
12193
|
+
dashboard_view: dashboardView,
|
|
12194
|
+
tracker_version: 2
|
|
12195
|
+
};
|
|
12196
|
+
}
|
|
12197
|
+
};
|
|
12198
|
+
|
|
12199
|
+
// src/lib/services/sessionTrackerTransport.ts
|
|
12200
|
+
var SessionTrackerTransport = class {
|
|
12201
|
+
constructor(config, trackerVersion, maxSegmentsPerRequest) {
|
|
12202
|
+
this.config = config;
|
|
12203
|
+
this.trackerVersion = trackerVersion;
|
|
12204
|
+
this.maxSegmentsPerRequest = maxSegmentsPerRequest;
|
|
12205
|
+
}
|
|
12206
|
+
async sendStartSession(session) {
|
|
12207
|
+
const token = await this.config.getAccessToken();
|
|
12208
|
+
if (!token) {
|
|
12209
|
+
console.warn("[SessionTracker] No access token, skipping start session API call");
|
|
12210
|
+
return;
|
|
12211
|
+
}
|
|
12212
|
+
await fetch(`${this.config.apiBaseUrl}/api/sessions/start`, {
|
|
12213
|
+
method: "POST",
|
|
12214
|
+
headers: this.authHeaders(token),
|
|
12215
|
+
body: JSON.stringify({
|
|
12216
|
+
session_id: session.sessionId,
|
|
12217
|
+
user_agent: typeof navigator !== "undefined" ? navigator.userAgent : void 0,
|
|
12218
|
+
dashboard_view: this.getDashboardView(),
|
|
12219
|
+
tracker_version: this.trackerVersion
|
|
12220
|
+
})
|
|
12221
|
+
});
|
|
12222
|
+
}
|
|
12223
|
+
async sendHeartbeat(session) {
|
|
12224
|
+
const token = await this.config.getAccessToken();
|
|
12225
|
+
if (!token) return null;
|
|
12226
|
+
const segmentsToSend = session.pendingSegments.slice(0, this.maxSegmentsPerRequest);
|
|
12227
|
+
const sentSegmentIds = new Set(segmentsToSend.map((segment) => segment.client_segment_id));
|
|
12228
|
+
const response = await fetch(`${this.config.apiBaseUrl}/api/sessions/heartbeat`, {
|
|
12229
|
+
method: "POST",
|
|
12230
|
+
headers: this.authHeaders(token),
|
|
12231
|
+
body: JSON.stringify({
|
|
12232
|
+
session_id: session.sessionId,
|
|
12233
|
+
cumulative_total_ms: session.cumulativeTotalMs,
|
|
12234
|
+
cumulative_active_ms: session.cumulativeActiveMs,
|
|
12235
|
+
cumulative_passive_ms: session.cumulativePassiveMs,
|
|
12236
|
+
visibility_state: typeof document !== "undefined" ? document.visibilityState : "visible",
|
|
12237
|
+
is_user_active: session.isUserActive,
|
|
12238
|
+
dashboard_view: this.getDashboardView(),
|
|
12239
|
+
tracker_version: this.trackerVersion,
|
|
12240
|
+
activity_segments: segmentsToSend
|
|
12241
|
+
})
|
|
12242
|
+
});
|
|
12243
|
+
const payload = await response.json().catch(() => ({}));
|
|
12244
|
+
return {
|
|
12245
|
+
ok: response.ok,
|
|
12246
|
+
acknowledged: payload?.acknowledged === false ? false : payload?.acknowledged === true ? true : null,
|
|
12247
|
+
sentSegmentIds
|
|
12248
|
+
};
|
|
12249
|
+
}
|
|
12250
|
+
async sendEndSession(session, reason, keepalive) {
|
|
12251
|
+
const token = keepalive && this.config.getCachedAccessToken ? this.config.getCachedAccessToken() : await this.config.getAccessToken();
|
|
12252
|
+
if (!token) {
|
|
12253
|
+
console.warn("[SessionTracker] No access token, skipping end session API call");
|
|
12254
|
+
return false;
|
|
12255
|
+
}
|
|
12256
|
+
const response = await fetch(`${this.config.apiBaseUrl}/api/sessions/end`, {
|
|
12257
|
+
method: "POST",
|
|
12258
|
+
keepalive,
|
|
12259
|
+
headers: this.authHeaders(token),
|
|
12260
|
+
body: JSON.stringify({
|
|
12261
|
+
session_id: session.sessionId,
|
|
12262
|
+
end_reason: reason,
|
|
12263
|
+
final_total_ms: session.cumulativeTotalMs,
|
|
12264
|
+
final_active_ms: session.cumulativeActiveMs,
|
|
12265
|
+
final_passive_ms: session.cumulativePassiveMs,
|
|
12266
|
+
tracker_version: this.trackerVersion,
|
|
12267
|
+
activity_segments: session.pendingSegments.slice(0, this.maxSegmentsPerRequest)
|
|
12268
|
+
})
|
|
12269
|
+
});
|
|
12270
|
+
return response.ok;
|
|
12271
|
+
}
|
|
12272
|
+
authHeaders(token) {
|
|
12273
|
+
return {
|
|
12274
|
+
"Content-Type": "application/json",
|
|
12275
|
+
"Authorization": `Bearer ${token}`
|
|
12276
|
+
};
|
|
12277
|
+
}
|
|
12278
|
+
getDashboardView() {
|
|
12279
|
+
return typeof window !== "undefined" ? window.location.pathname : void 0;
|
|
12280
|
+
}
|
|
12281
|
+
};
|
|
12282
|
+
|
|
12006
12283
|
// src/lib/services/sessionTracker.ts
|
|
12007
12284
|
function generateSessionId() {
|
|
12008
12285
|
return `sess_${Date.now()}_${Math.random().toString(36).substring(2, 15)}`;
|
|
12009
12286
|
}
|
|
12287
|
+
function isDebugEnabled() {
|
|
12288
|
+
return typeof process !== "undefined" && process.env.NEXT_PUBLIC_DEBUG_DASHBOARD === "true";
|
|
12289
|
+
}
|
|
12290
|
+
function debugLog(message, data) {
|
|
12291
|
+
if (isDebugEnabled()) {
|
|
12292
|
+
console.log(`[SessionTracker] ${message}`, data || {});
|
|
12293
|
+
}
|
|
12294
|
+
}
|
|
12010
12295
|
var SessionTracker = class {
|
|
12011
12296
|
constructor(config) {
|
|
12012
12297
|
this.session = null;
|
|
12013
12298
|
this.heartbeatInterval = null;
|
|
12014
|
-
this.graceTimeout = null;
|
|
12015
12299
|
this.tickInterval = null;
|
|
12016
|
-
|
|
12300
|
+
this.heartbeatInFlight = false;
|
|
12301
|
+
this.pendingForcedHeartbeat = false;
|
|
12302
|
+
this.TRACKER_VERSION = 2;
|
|
12017
12303
|
this.HEARTBEAT_INTERVAL_MS = 3e4;
|
|
12018
|
-
// 30 seconds
|
|
12019
|
-
this.HIDDEN_GRACE_PERIOD_MS = 3e5;
|
|
12020
|
-
// 5 minutes
|
|
12021
12304
|
this.IDLE_THRESHOLD_MS = 3e4;
|
|
12022
|
-
// 30 seconds without activity = passive
|
|
12023
12305
|
this.TICK_INTERVAL_MS = 1e3;
|
|
12306
|
+
this.MAX_SEGMENTS_PER_REQUEST = 200;
|
|
12024
12307
|
this.config = config;
|
|
12308
|
+
this.activityAccumulator = new SessionActivityAccumulator(
|
|
12309
|
+
this.IDLE_THRESHOLD_MS,
|
|
12310
|
+
() => this.getDashboardView()
|
|
12311
|
+
);
|
|
12312
|
+
this.transport = new SessionTrackerTransport(
|
|
12313
|
+
this.config,
|
|
12314
|
+
this.TRACKER_VERSION,
|
|
12315
|
+
this.MAX_SEGMENTS_PER_REQUEST
|
|
12316
|
+
);
|
|
12025
12317
|
this.boundHandleActivity = this.handleUserActivity.bind(this);
|
|
12026
12318
|
this.boundHandleVisibility = this.handleVisibilityChange.bind(this);
|
|
12027
12319
|
this.boundHandleBeforeUnload = this.handleBeforeUnload.bind(this);
|
|
12320
|
+
this.boundHandlePageHide = this.handlePageHide.bind(this);
|
|
12321
|
+
this.boundHandlePageShow = this.handlePageShow.bind(this);
|
|
12028
12322
|
this.boundHandleFocus = this.handleWindowFocus.bind(this);
|
|
12029
12323
|
this.boundHandleBlur = this.handleWindowBlur.bind(this);
|
|
12030
12324
|
}
|
|
12031
|
-
/**
|
|
12032
|
-
* Start a new session
|
|
12033
|
-
*/
|
|
12034
12325
|
async startSession(userId, companyId) {
|
|
12035
12326
|
if (this.session && this.session.state !== "ENDED") {
|
|
12036
|
-
|
|
12327
|
+
debugLog("Session already active, ignoring start", { sessionId: this.session.sessionId });
|
|
12037
12328
|
return;
|
|
12038
12329
|
}
|
|
12039
12330
|
const sessionId = generateSessionId();
|
|
12040
12331
|
const now4 = /* @__PURE__ */ new Date();
|
|
12041
|
-
this.session =
|
|
12332
|
+
this.session = createSessionData(
|
|
12042
12333
|
sessionId,
|
|
12043
12334
|
userId,
|
|
12044
12335
|
companyId,
|
|
12045
|
-
|
|
12046
|
-
|
|
12047
|
-
|
|
12048
|
-
|
|
12049
|
-
|
|
12050
|
-
|
|
12051
|
-
|
|
12052
|
-
|
|
12053
|
-
|
|
12054
|
-
|
|
12055
|
-
|
|
12056
|
-
|
|
12336
|
+
now4,
|
|
12337
|
+
this.getDocumentVisibility(),
|
|
12338
|
+
this.getWindowFocus()
|
|
12339
|
+
);
|
|
12340
|
+
await this.sendStartSession();
|
|
12341
|
+
if (!this.session || this.session.sessionId !== sessionId) {
|
|
12342
|
+
return;
|
|
12343
|
+
}
|
|
12344
|
+
if (this.session.state === "ENDED") {
|
|
12345
|
+
await this.sendEndSession(this.session.endReason || "navigation");
|
|
12346
|
+
debugLog("Session start completed after local end", { sessionId });
|
|
12347
|
+
return;
|
|
12348
|
+
}
|
|
12349
|
+
const trackingStart = /* @__PURE__ */ new Date();
|
|
12350
|
+
this.session.lastTick = trackingStart;
|
|
12351
|
+
this.session.isVisible = this.getDocumentVisibility();
|
|
12352
|
+
this.session.isFocused = this.getWindowFocus();
|
|
12057
12353
|
this.setupActivityListeners();
|
|
12058
12354
|
this.setupVisibilityListener();
|
|
12059
12355
|
this.setupFocusListeners();
|
|
12060
|
-
this.
|
|
12356
|
+
this.setupPageLifecycleListeners();
|
|
12061
12357
|
this.startTimeTick();
|
|
12062
12358
|
this.startHeartbeat();
|
|
12063
|
-
await this.sendStartSession();
|
|
12064
12359
|
this.config.onSessionStart?.(sessionId);
|
|
12065
|
-
|
|
12360
|
+
debugLog("Session started", { sessionId });
|
|
12066
12361
|
}
|
|
12067
|
-
/**
|
|
12068
|
-
* End the current session
|
|
12069
|
-
*/
|
|
12070
12362
|
async endSession(reason) {
|
|
12071
12363
|
if (!this.session || this.session.state === "ENDED") {
|
|
12072
12364
|
return;
|
|
12073
12365
|
}
|
|
12074
12366
|
const sessionId = this.session.sessionId;
|
|
12075
12367
|
this.updateTimes();
|
|
12368
|
+
this.flushCurrentSegment(/* @__PURE__ */ new Date());
|
|
12369
|
+
this.session.endReason = reason;
|
|
12370
|
+
await this.drainPendingSegmentsBeforeEnd();
|
|
12076
12371
|
this.session.state = "ENDED";
|
|
12077
12372
|
this.cleanup();
|
|
12078
12373
|
await this.sendEndSession(reason);
|
|
12079
12374
|
this.config.onSessionEnd?.(sessionId, reason);
|
|
12080
|
-
|
|
12375
|
+
debugLog("Session ended", { sessionId, reason });
|
|
12081
12376
|
}
|
|
12082
|
-
/**
|
|
12083
|
-
* Get current session stats (for debugging/display)
|
|
12084
|
-
*/
|
|
12085
12377
|
getSessionStats() {
|
|
12086
12378
|
if (!this.session) return null;
|
|
12087
12379
|
return {
|
|
@@ -12090,11 +12382,9 @@ var SessionTracker = class {
|
|
|
12090
12382
|
passiveMs: this.session.cumulativePassiveMs
|
|
12091
12383
|
};
|
|
12092
12384
|
}
|
|
12093
|
-
// ===== Private Methods =====
|
|
12094
12385
|
setupActivityListeners() {
|
|
12095
12386
|
if (typeof window === "undefined") return;
|
|
12096
|
-
|
|
12097
|
-
events.forEach((event) => {
|
|
12387
|
+
TRACKED_ACTIVITY_EVENTS.forEach((event) => {
|
|
12098
12388
|
window.addEventListener(event, this.boundHandleActivity, { passive: true });
|
|
12099
12389
|
});
|
|
12100
12390
|
}
|
|
@@ -12107,71 +12397,100 @@ var SessionTracker = class {
|
|
|
12107
12397
|
window.addEventListener("focus", this.boundHandleFocus);
|
|
12108
12398
|
window.addEventListener("blur", this.boundHandleBlur);
|
|
12109
12399
|
}
|
|
12110
|
-
|
|
12400
|
+
setupPageLifecycleListeners() {
|
|
12111
12401
|
if (typeof window === "undefined") return;
|
|
12112
12402
|
window.addEventListener("beforeunload", this.boundHandleBeforeUnload);
|
|
12403
|
+
window.addEventListener("pagehide", this.boundHandlePageHide);
|
|
12404
|
+
window.addEventListener("pageshow", this.boundHandlePageShow);
|
|
12113
12405
|
}
|
|
12114
|
-
handleUserActivity() {
|
|
12406
|
+
handleUserActivity(event) {
|
|
12115
12407
|
if (!this.session || this.session.state === "ENDED") return;
|
|
12408
|
+
if ("isTrusted" in event && event.isTrusted === false) return;
|
|
12409
|
+
this.updateTimes();
|
|
12116
12410
|
this.session.lastActivityAt = /* @__PURE__ */ new Date();
|
|
12117
12411
|
this.session.isUserActive = true;
|
|
12118
12412
|
}
|
|
12119
12413
|
handleVisibilityChange() {
|
|
12120
12414
|
if (!this.session || this.session.state === "ENDED") return;
|
|
12415
|
+
const now4 = /* @__PURE__ */ new Date();
|
|
12416
|
+
this.updateTimes(now4);
|
|
12121
12417
|
if (document.visibilityState === "hidden") {
|
|
12122
|
-
this.
|
|
12123
|
-
this.session.state = "BACKGROUND_GRACE";
|
|
12418
|
+
this.flushCurrentSegment(now4);
|
|
12124
12419
|
this.session.isVisible = false;
|
|
12125
12420
|
this.session.isFocused = false;
|
|
12126
|
-
this.session.
|
|
12127
|
-
this.
|
|
12128
|
-
|
|
12129
|
-
|
|
12130
|
-
|
|
12131
|
-
|
|
12132
|
-
if (this.graceTimeout) {
|
|
12133
|
-
clearTimeout(this.graceTimeout);
|
|
12134
|
-
this.graceTimeout = null;
|
|
12135
|
-
}
|
|
12136
|
-
this.session.hiddenSince = null;
|
|
12137
|
-
this.session.state = "ACTIVE";
|
|
12138
|
-
this.session.isVisible = true;
|
|
12139
|
-
this.session.isFocused = typeof document !== "undefined" && typeof document.hasFocus === "function" ? document.hasFocus() : true;
|
|
12140
|
-
this.session.lastActivityAt = /* @__PURE__ */ new Date();
|
|
12141
|
-
this.session.isUserActive = true;
|
|
12142
|
-
this.session.lastTick = /* @__PURE__ */ new Date();
|
|
12143
|
-
console.log("[SessionTracker] Tab visible again");
|
|
12421
|
+
this.session.isUserActive = false;
|
|
12422
|
+
this.session.lastActivityAt = null;
|
|
12423
|
+
this.session.lastTick = now4;
|
|
12424
|
+
void this.sendHeartbeat(true);
|
|
12425
|
+
debugLog("Tab hidden");
|
|
12426
|
+
return;
|
|
12144
12427
|
}
|
|
12428
|
+
this.session.isVisible = true;
|
|
12429
|
+
this.session.isFocused = this.getWindowFocus();
|
|
12430
|
+
this.session.isUserActive = false;
|
|
12431
|
+
this.session.lastActivityAt = null;
|
|
12432
|
+
this.session.lastTick = now4;
|
|
12433
|
+
void this.sendHeartbeat(true);
|
|
12434
|
+
debugLog("Tab visible");
|
|
12145
12435
|
}
|
|
12146
12436
|
handleWindowFocus() {
|
|
12147
12437
|
if (!this.session || this.session.state === "ENDED") return;
|
|
12438
|
+
const now4 = /* @__PURE__ */ new Date();
|
|
12439
|
+
this.updateTimes(now4);
|
|
12148
12440
|
this.session.isFocused = true;
|
|
12149
|
-
this.session.
|
|
12150
|
-
this.session.
|
|
12151
|
-
this.session.lastTick =
|
|
12441
|
+
this.session.isUserActive = false;
|
|
12442
|
+
this.session.lastActivityAt = null;
|
|
12443
|
+
this.session.lastTick = now4;
|
|
12444
|
+
void this.sendHeartbeat(true);
|
|
12152
12445
|
}
|
|
12153
12446
|
handleWindowBlur() {
|
|
12154
12447
|
if (!this.session || this.session.state === "ENDED") return;
|
|
12448
|
+
const now4 = /* @__PURE__ */ new Date();
|
|
12449
|
+
this.updateTimes(now4);
|
|
12450
|
+
this.flushCurrentSegment(now4);
|
|
12155
12451
|
this.session.isFocused = false;
|
|
12156
|
-
this.session.
|
|
12452
|
+
this.session.isUserActive = false;
|
|
12453
|
+
this.session.lastActivityAt = null;
|
|
12454
|
+
this.session.lastTick = now4;
|
|
12455
|
+
void this.sendHeartbeat(true);
|
|
12157
12456
|
}
|
|
12158
|
-
handleBeforeUnload(
|
|
12159
|
-
|
|
12160
|
-
|
|
12161
|
-
|
|
12162
|
-
|
|
12163
|
-
|
|
12164
|
-
|
|
12165
|
-
|
|
12166
|
-
|
|
12167
|
-
|
|
12168
|
-
|
|
12169
|
-
|
|
12170
|
-
|
|
12171
|
-
|
|
12172
|
-
this.
|
|
12173
|
-
|
|
12457
|
+
handleBeforeUnload() {
|
|
12458
|
+
this.finalizeWithKeepalive("tab_close");
|
|
12459
|
+
}
|
|
12460
|
+
handlePageHide(event) {
|
|
12461
|
+
if (event.persisted) {
|
|
12462
|
+
if (!this.session || this.session.state === "ENDED") return;
|
|
12463
|
+
const now4 = /* @__PURE__ */ new Date();
|
|
12464
|
+
this.updateTimes(now4);
|
|
12465
|
+
this.flushCurrentSegment(now4);
|
|
12466
|
+
this.session.isVisible = false;
|
|
12467
|
+
this.session.isFocused = false;
|
|
12468
|
+
this.session.isUserActive = false;
|
|
12469
|
+
this.session.lastActivityAt = null;
|
|
12470
|
+
this.session.lastTick = now4;
|
|
12471
|
+
void this.sendHeartbeat(true);
|
|
12472
|
+
return;
|
|
12174
12473
|
}
|
|
12474
|
+
this.finalizeWithKeepalive("pagehide");
|
|
12475
|
+
}
|
|
12476
|
+
handlePageShow(event) {
|
|
12477
|
+
if (!event.persisted || !this.session || this.session.state === "ENDED") return;
|
|
12478
|
+
const now4 = /* @__PURE__ */ new Date();
|
|
12479
|
+
this.session.isVisible = this.getDocumentVisibility();
|
|
12480
|
+
this.session.isFocused = this.getWindowFocus();
|
|
12481
|
+
this.session.isUserActive = false;
|
|
12482
|
+
this.session.lastActivityAt = null;
|
|
12483
|
+
this.session.lastTick = now4;
|
|
12484
|
+
void this.sendHeartbeat(true);
|
|
12485
|
+
}
|
|
12486
|
+
finalizeWithKeepalive(reason) {
|
|
12487
|
+
if (!this.session || this.session.state === "ENDED") return;
|
|
12488
|
+
this.updateTimes();
|
|
12489
|
+
this.flushCurrentSegment(/* @__PURE__ */ new Date());
|
|
12490
|
+
this.session.endReason = reason;
|
|
12491
|
+
this.session.state = "ENDED";
|
|
12492
|
+
void this.sendEndSession(reason, true);
|
|
12493
|
+
this.cleanup();
|
|
12175
12494
|
}
|
|
12176
12495
|
startTimeTick() {
|
|
12177
12496
|
this.tickInterval = setInterval(() => {
|
|
@@ -12179,30 +12498,17 @@ var SessionTracker = class {
|
|
|
12179
12498
|
}, this.TICK_INTERVAL_MS);
|
|
12180
12499
|
}
|
|
12181
12500
|
shouldTrackTime() {
|
|
12182
|
-
|
|
12183
|
-
const stateAllowsTracking = this.session.state === "ACTIVE" || this.session.state === "BACKGROUND_GRACE";
|
|
12184
|
-
return stateAllowsTracking && this.session.isVisible && this.session.isFocused;
|
|
12501
|
+
return this.activityAccumulator.shouldTrackTime(this.session);
|
|
12185
12502
|
}
|
|
12186
|
-
|
|
12187
|
-
if (!this.session
|
|
12188
|
-
|
|
12189
|
-
|
|
12190
|
-
|
|
12191
|
-
|
|
12192
|
-
|
|
12193
|
-
|
|
12194
|
-
|
|
12195
|
-
this.session.cumulativeTotalMs += elapsed;
|
|
12196
|
-
const timeSinceActivity = now4.getTime() - this.session.lastActivityAt.getTime();
|
|
12197
|
-
if (timeSinceActivity < this.IDLE_THRESHOLD_MS) {
|
|
12198
|
-
this.session.cumulativeActiveMs += elapsed;
|
|
12199
|
-
this.session.isUserActive = true;
|
|
12200
|
-
} else {
|
|
12201
|
-
this.session.cumulativePassiveMs += elapsed;
|
|
12202
|
-
this.session.isUserActive = false;
|
|
12203
|
-
}
|
|
12204
|
-
}
|
|
12205
|
-
this.session.lastTick = now4;
|
|
12503
|
+
getActivityState(now4) {
|
|
12504
|
+
if (!this.session) return "passive";
|
|
12505
|
+
return this.activityAccumulator.getActivityState(this.session, now4);
|
|
12506
|
+
}
|
|
12507
|
+
updateTimes(now4 = /* @__PURE__ */ new Date()) {
|
|
12508
|
+
this.activityAccumulator.updateTimes(this.session, now4);
|
|
12509
|
+
}
|
|
12510
|
+
flushCurrentSegment(endAt) {
|
|
12511
|
+
this.activityAccumulator.flushCurrentSegment(this.session, endAt);
|
|
12206
12512
|
}
|
|
12207
12513
|
startHeartbeat() {
|
|
12208
12514
|
this.heartbeatInterval = setInterval(async () => {
|
|
@@ -12212,75 +12518,70 @@ var SessionTracker = class {
|
|
|
12212
12518
|
async sendStartSession() {
|
|
12213
12519
|
if (!this.session) return;
|
|
12214
12520
|
try {
|
|
12215
|
-
|
|
12216
|
-
if (!token) {
|
|
12217
|
-
console.warn("[SessionTracker] No access token, skipping start session API call");
|
|
12218
|
-
return;
|
|
12219
|
-
}
|
|
12220
|
-
await fetch(`${this.config.apiBaseUrl}/api/sessions/start`, {
|
|
12221
|
-
method: "POST",
|
|
12222
|
-
headers: {
|
|
12223
|
-
"Content-Type": "application/json",
|
|
12224
|
-
"Authorization": `Bearer ${token}`
|
|
12225
|
-
},
|
|
12226
|
-
body: JSON.stringify({
|
|
12227
|
-
session_id: this.session.sessionId,
|
|
12228
|
-
user_agent: typeof navigator !== "undefined" ? navigator.userAgent : void 0,
|
|
12229
|
-
dashboard_view: typeof window !== "undefined" ? window.location.pathname : void 0
|
|
12230
|
-
})
|
|
12231
|
-
});
|
|
12521
|
+
await this.transport.sendStartSession(this.session);
|
|
12232
12522
|
} catch (error) {
|
|
12233
12523
|
console.error("[SessionTracker] Failed to send start session:", error);
|
|
12234
12524
|
}
|
|
12235
12525
|
}
|
|
12236
|
-
async sendHeartbeat() {
|
|
12526
|
+
async sendHeartbeat(force = false, allowReplacement = true) {
|
|
12527
|
+
if (this.heartbeatInFlight) {
|
|
12528
|
+
this.pendingForcedHeartbeat || (this.pendingForcedHeartbeat = force);
|
|
12529
|
+
return;
|
|
12530
|
+
}
|
|
12237
12531
|
if (!this.session || this.session.state === "ENDED") return;
|
|
12532
|
+
this.heartbeatInFlight = true;
|
|
12238
12533
|
try {
|
|
12239
|
-
|
|
12240
|
-
|
|
12241
|
-
|
|
12242
|
-
|
|
12243
|
-
|
|
12244
|
-
|
|
12245
|
-
|
|
12246
|
-
|
|
12247
|
-
|
|
12248
|
-
|
|
12249
|
-
|
|
12250
|
-
|
|
12251
|
-
|
|
12252
|
-
|
|
12253
|
-
|
|
12254
|
-
|
|
12255
|
-
|
|
12256
|
-
});
|
|
12534
|
+
this.updateTimes();
|
|
12535
|
+
this.flushCurrentSegment(/* @__PURE__ */ new Date());
|
|
12536
|
+
if (!force && !this.shouldTrackTime()) return;
|
|
12537
|
+
const result = await this.transport.sendHeartbeat(this.session);
|
|
12538
|
+
if (!result) return;
|
|
12539
|
+
if (result.ok && result.acknowledged !== false) {
|
|
12540
|
+
debugLog("Heartbeat acknowledged", { segments: result.sentSegmentIds.size });
|
|
12541
|
+
this.session.pendingSegments = this.session.pendingSegments.filter(
|
|
12542
|
+
(segment) => !result.sentSegmentIds.has(segment.client_segment_id)
|
|
12543
|
+
);
|
|
12544
|
+
} else if (result.ok && result.acknowledged === false && allowReplacement && this.shouldTrackTime()) {
|
|
12545
|
+
const { userId, companyId, sessionId } = this.session;
|
|
12546
|
+
this.session.state = "ENDED";
|
|
12547
|
+
this.cleanup();
|
|
12548
|
+
debugLog("Heartbeat not acknowledged, starting replacement session", { sessionId });
|
|
12549
|
+
await this.startSession(userId, companyId);
|
|
12550
|
+
}
|
|
12257
12551
|
} catch (error) {
|
|
12258
12552
|
console.error("[SessionTracker] Failed to send heartbeat:", error);
|
|
12553
|
+
} finally {
|
|
12554
|
+
this.heartbeatInFlight = false;
|
|
12555
|
+
if (this.pendingForcedHeartbeat && this.session?.state !== "ENDED") {
|
|
12556
|
+
this.pendingForcedHeartbeat = false;
|
|
12557
|
+
void this.sendHeartbeat(true);
|
|
12558
|
+
}
|
|
12559
|
+
}
|
|
12560
|
+
}
|
|
12561
|
+
async drainPendingSegmentsBeforeEnd() {
|
|
12562
|
+
if (!this.session) return;
|
|
12563
|
+
let guard = 0;
|
|
12564
|
+
while (this.session.state !== "ENDED" && this.session.pendingSegments.length > this.MAX_SEGMENTS_PER_REQUEST && guard < 20) {
|
|
12565
|
+
const pendingBefore = this.session.pendingSegments.length;
|
|
12566
|
+
await this.sendHeartbeat(true, false);
|
|
12567
|
+
if (!this.session || this.session.pendingSegments.length >= pendingBefore) {
|
|
12568
|
+
break;
|
|
12569
|
+
}
|
|
12570
|
+
guard += 1;
|
|
12259
12571
|
}
|
|
12260
12572
|
}
|
|
12261
|
-
async sendEndSession(reason) {
|
|
12573
|
+
async sendEndSession(reason, keepalive = false) {
|
|
12262
12574
|
if (!this.session) return;
|
|
12263
12575
|
try {
|
|
12264
|
-
const
|
|
12265
|
-
if (
|
|
12266
|
-
|
|
12267
|
-
return;
|
|
12576
|
+
const ok = await this.transport.sendEndSession(this.session, reason, keepalive);
|
|
12577
|
+
if (ok) {
|
|
12578
|
+
this.session.pendingSegments = this.session.pendingSegments.slice(this.MAX_SEGMENTS_PER_REQUEST);
|
|
12268
12579
|
}
|
|
12269
|
-
await fetch(`${this.config.apiBaseUrl}/api/sessions/end`, {
|
|
12270
|
-
method: "POST",
|
|
12271
|
-
headers: {
|
|
12272
|
-
"Content-Type": "application/json",
|
|
12273
|
-
"Authorization": `Bearer ${token}`
|
|
12274
|
-
},
|
|
12275
|
-
body: JSON.stringify({
|
|
12276
|
-
session_id: this.session.sessionId,
|
|
12277
|
-
end_reason: reason,
|
|
12278
|
-
final_total_ms: this.session.cumulativeTotalMs,
|
|
12279
|
-
final_active_ms: this.session.cumulativeActiveMs,
|
|
12280
|
-
final_passive_ms: this.session.cumulativePassiveMs
|
|
12281
|
-
})
|
|
12282
|
-
});
|
|
12283
12580
|
} catch (error) {
|
|
12581
|
+
if (keepalive) {
|
|
12582
|
+
debugLog("Keepalive end session failed after page lifecycle transition", { reason });
|
|
12583
|
+
return;
|
|
12584
|
+
}
|
|
12284
12585
|
console.error("[SessionTracker] Failed to send end session:", error);
|
|
12285
12586
|
}
|
|
12286
12587
|
}
|
|
@@ -12293,23 +12594,29 @@ var SessionTracker = class {
|
|
|
12293
12594
|
clearInterval(this.tickInterval);
|
|
12294
12595
|
this.tickInterval = null;
|
|
12295
12596
|
}
|
|
12296
|
-
if (this.graceTimeout) {
|
|
12297
|
-
clearTimeout(this.graceTimeout);
|
|
12298
|
-
this.graceTimeout = null;
|
|
12299
|
-
}
|
|
12300
12597
|
if (typeof window !== "undefined") {
|
|
12301
|
-
|
|
12302
|
-
events.forEach((event) => {
|
|
12598
|
+
TRACKED_ACTIVITY_EVENTS.forEach((event) => {
|
|
12303
12599
|
window.removeEventListener(event, this.boundHandleActivity);
|
|
12304
12600
|
});
|
|
12305
12601
|
window.removeEventListener("focus", this.boundHandleFocus);
|
|
12306
12602
|
window.removeEventListener("blur", this.boundHandleBlur);
|
|
12307
12603
|
window.removeEventListener("beforeunload", this.boundHandleBeforeUnload);
|
|
12604
|
+
window.removeEventListener("pagehide", this.boundHandlePageHide);
|
|
12605
|
+
window.removeEventListener("pageshow", this.boundHandlePageShow);
|
|
12308
12606
|
}
|
|
12309
12607
|
if (typeof document !== "undefined") {
|
|
12310
12608
|
document.removeEventListener("visibilitychange", this.boundHandleVisibility);
|
|
12311
12609
|
}
|
|
12312
12610
|
}
|
|
12611
|
+
getDashboardView() {
|
|
12612
|
+
return typeof window !== "undefined" ? window.location.pathname : void 0;
|
|
12613
|
+
}
|
|
12614
|
+
getDocumentVisibility() {
|
|
12615
|
+
return typeof document !== "undefined" ? document.visibilityState === "visible" : true;
|
|
12616
|
+
}
|
|
12617
|
+
getWindowFocus() {
|
|
12618
|
+
return typeof document !== "undefined" && typeof document.hasFocus === "function" ? document.hasFocus() : true;
|
|
12619
|
+
}
|
|
12313
12620
|
};
|
|
12314
12621
|
function createSessionTracker(config) {
|
|
12315
12622
|
return new SessionTracker(config);
|
|
@@ -13315,15 +13622,43 @@ function useSessionTracking(options = {}) {
|
|
|
13315
13622
|
const trackerRef = React125.useRef(null);
|
|
13316
13623
|
const isTrackingRef = React125.useRef(false);
|
|
13317
13624
|
const initRef = React125.useRef(false);
|
|
13318
|
-
const
|
|
13319
|
-
|
|
13625
|
+
const accessTokenRef = React125.useRef(null);
|
|
13626
|
+
const isAuthenticatedRef = React125.useRef(isAuthenticated);
|
|
13627
|
+
const onSessionStartRef = React125.useRef(onSessionStart);
|
|
13628
|
+
const onSessionEndRef = React125.useRef(onSessionEnd);
|
|
13629
|
+
const apiBaseUrl2 = config?.apiBaseUrl || process.env.NEXT_PUBLIC_API_BASE_URL || "";
|
|
13630
|
+
isAuthenticatedRef.current = isAuthenticated;
|
|
13631
|
+
React125.useEffect(() => {
|
|
13632
|
+
if (session?.access_token) {
|
|
13633
|
+
accessTokenRef.current = session.access_token;
|
|
13634
|
+
}
|
|
13320
13635
|
}, [session?.access_token]);
|
|
13636
|
+
React125.useEffect(() => {
|
|
13637
|
+
onSessionStartRef.current = onSessionStart;
|
|
13638
|
+
}, [onSessionStart]);
|
|
13639
|
+
React125.useEffect(() => {
|
|
13640
|
+
onSessionEndRef.current = onSessionEnd;
|
|
13641
|
+
}, [onSessionEnd]);
|
|
13642
|
+
const getAccessToken2 = React125.useCallback(async () => {
|
|
13643
|
+
return accessTokenRef.current;
|
|
13644
|
+
}, []);
|
|
13645
|
+
const endCurrentTracker = React125.useCallback((reason) => {
|
|
13646
|
+
const tracker = trackerRef.current;
|
|
13647
|
+
if (!tracker) return null;
|
|
13648
|
+
const tokenForEndingSession = accessTokenRef.current;
|
|
13649
|
+
trackerRef.current = null;
|
|
13650
|
+
isTrackingRef.current = false;
|
|
13651
|
+
return tracker.endSession(reason).finally(() => {
|
|
13652
|
+
if (reason === "logout" && !isAuthenticatedRef.current && accessTokenRef.current === tokenForEndingSession) {
|
|
13653
|
+
accessTokenRef.current = null;
|
|
13654
|
+
}
|
|
13655
|
+
});
|
|
13656
|
+
}, []);
|
|
13321
13657
|
React125.useEffect(() => {
|
|
13322
13658
|
if (!enabled || !isAuthenticated || !user || !session || initRef.current) {
|
|
13323
13659
|
return;
|
|
13324
13660
|
}
|
|
13325
13661
|
initRef.current = true;
|
|
13326
|
-
const apiBaseUrl2 = config?.apiBaseUrl || process.env.NEXT_PUBLIC_API_BASE_URL || "";
|
|
13327
13662
|
if (!apiBaseUrl2) {
|
|
13328
13663
|
console.warn("[useSessionTracking] No API base URL configured, session tracking disabled");
|
|
13329
13664
|
return;
|
|
@@ -13331,41 +13666,34 @@ function useSessionTracking(options = {}) {
|
|
|
13331
13666
|
const tracker = createSessionTracker({
|
|
13332
13667
|
apiBaseUrl: apiBaseUrl2,
|
|
13333
13668
|
getAccessToken: getAccessToken2,
|
|
13669
|
+
getCachedAccessToken: () => accessTokenRef.current,
|
|
13334
13670
|
onSessionStart: (sessionId) => {
|
|
13335
13671
|
isTrackingRef.current = true;
|
|
13336
|
-
|
|
13672
|
+
onSessionStartRef.current?.(sessionId);
|
|
13337
13673
|
},
|
|
13338
13674
|
onSessionEnd: (sessionId, reason) => {
|
|
13339
13675
|
isTrackingRef.current = false;
|
|
13340
|
-
|
|
13676
|
+
onSessionEndRef.current?.(sessionId, reason);
|
|
13341
13677
|
}
|
|
13342
13678
|
});
|
|
13343
13679
|
trackerRef.current = tracker;
|
|
13344
13680
|
const companyId = user?.company_id || user?.properties?.company_id || null;
|
|
13345
13681
|
tracker.startSession(user.id, companyId);
|
|
13346
13682
|
return () => {
|
|
13347
|
-
|
|
13348
|
-
|
|
13349
|
-
trackerRef.current = null;
|
|
13350
|
-
}
|
|
13683
|
+
const reason = isAuthenticatedRef.current ? "navigation" : "logout";
|
|
13684
|
+
void endCurrentTracker(reason);
|
|
13351
13685
|
initRef.current = false;
|
|
13352
13686
|
isTrackingRef.current = false;
|
|
13353
13687
|
};
|
|
13354
|
-
}, [enabled, isAuthenticated, user?.id,
|
|
13688
|
+
}, [enabled, isAuthenticated, user?.id, apiBaseUrl2, getAccessToken2, endCurrentTracker]);
|
|
13355
13689
|
React125.useEffect(() => {
|
|
13356
13690
|
if (!isAuthenticated && trackerRef.current && isTrackingRef.current) {
|
|
13357
|
-
|
|
13358
|
-
trackerRef.current = null;
|
|
13359
|
-
isTrackingRef.current = false;
|
|
13691
|
+
void endCurrentTracker("logout");
|
|
13360
13692
|
}
|
|
13361
|
-
}, [isAuthenticated]);
|
|
13693
|
+
}, [isAuthenticated, endCurrentTracker]);
|
|
13362
13694
|
const endSession = React125.useCallback(async (reason) => {
|
|
13363
|
-
|
|
13364
|
-
|
|
13365
|
-
trackerRef.current = null;
|
|
13366
|
-
isTrackingRef.current = false;
|
|
13367
|
-
}
|
|
13368
|
-
}, []);
|
|
13695
|
+
await endCurrentTracker(reason);
|
|
13696
|
+
}, [endCurrentTracker]);
|
|
13369
13697
|
const sessionStats = trackerRef.current?.getSessionStats() || null;
|
|
13370
13698
|
return {
|
|
13371
13699
|
sessionStats,
|
|
@@ -15677,6 +16005,10 @@ var useDashboardMetrics = ({
|
|
|
15677
16005
|
}
|
|
15678
16006
|
const isFactory = currentLineIdToUse === factoryViewId;
|
|
15679
16007
|
const targetLineIds = isFactory ? targetFactoryLineIds : [currentLineIdToUse];
|
|
16008
|
+
if (isFactory && targetLineIds.length > 0 && !shiftGroupsKey) {
|
|
16009
|
+
logDebug("[useDashboardMetrics] Skipping fetch: factory shift groups are not ready");
|
|
16010
|
+
return;
|
|
16011
|
+
}
|
|
15680
16012
|
const targetLineIdsKey = targetLineIds.slice().sort().join(",");
|
|
15681
16013
|
const effectiveBlueComparisonLineIds = normalizedBlueComparisonLineIds.length ? normalizedBlueComparisonLineIds : targetLineIds;
|
|
15682
16014
|
const blueComparisonLineIdsKey = effectiveBlueComparisonLineIds.slice().sort().join(",");
|
|
@@ -15741,7 +16073,7 @@ var useDashboardMetrics = ({
|
|
|
15741
16073
|
const qaGreenStreakParams = qaGreenStreakParamString ? `&${qaGreenStreakParamString}` : "";
|
|
15742
16074
|
const buildMetricsEndpoint = (params) => {
|
|
15743
16075
|
const lineIdsParam = isFactory ? `line_ids=${params.groupLineIds.join(",")}` : `line_id=${params.groupLineIds[0]}`;
|
|
15744
|
-
const blueComparisonParam =
|
|
16076
|
+
const blueComparisonParam = normalizedBlueComparisonLineIds.length ? `&blue_comparison_line_ids=${normalizedBlueComparisonLineIds.join(",")}` : "";
|
|
15745
16077
|
const selectorParam = normalizedSelectorLineIds.length ? `&selector_line_ids=${encodeURIComponent(normalizedSelectorLineIds.join(","))}` : "";
|
|
15746
16078
|
return `/api/dashboard/metrics?${lineIdsParam}${blueComparisonParam}${selectorParam}&date=${params.date}&shift_id=${params.shiftId}&company_id=${companyId}${forceParam}${qaGreenStreakParams}`;
|
|
15747
16079
|
};
|
|
@@ -17464,7 +17796,7 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError, hlsConfig }) {
|
|
|
17464
17796
|
return Number.isFinite(parsed) ? parsed : DEFAULT_MAX_MANIFEST_AGE_MS;
|
|
17465
17797
|
})();
|
|
17466
17798
|
const manifestStaleThresholdMs = maxManifestAgeMs > 0 ? Math.min(maxManifestAgeMs, SEGMENT_MAX_AGE_MS) : SEGMENT_MAX_AGE_MS;
|
|
17467
|
-
const
|
|
17799
|
+
const debugLog2 = (...args) => {
|
|
17468
17800
|
if (debugEnabled) {
|
|
17469
17801
|
console.log(...args);
|
|
17470
17802
|
}
|
|
@@ -17646,7 +17978,7 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError, hlsConfig }) {
|
|
|
17646
17978
|
return;
|
|
17647
17979
|
}
|
|
17648
17980
|
} catch (error) {
|
|
17649
|
-
|
|
17981
|
+
debugLog2("[HLS] Stale manifest poll failed", error);
|
|
17650
17982
|
}
|
|
17651
17983
|
staleManifestPollDelayRef.current = Math.min(
|
|
17652
17984
|
staleManifestPollDelayRef.current + 5e3,
|
|
@@ -17996,7 +18328,7 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError, hlsConfig }) {
|
|
|
17996
18328
|
}
|
|
17997
18329
|
return true;
|
|
17998
18330
|
} catch (error) {
|
|
17999
|
-
|
|
18331
|
+
debugLog2("[HLS] Manifest freshness check failed", error);
|
|
18000
18332
|
{
|
|
18001
18333
|
markStaleStream("manifest freshness check failed");
|
|
18002
18334
|
return false;
|
|
@@ -18042,7 +18374,7 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError, hlsConfig }) {
|
|
|
18042
18374
|
};
|
|
18043
18375
|
const softRestart = (reason) => {
|
|
18044
18376
|
if (staleManifestTriggeredRef.current) {
|
|
18045
|
-
|
|
18377
|
+
debugLog2("[HLS] Skip soft restart while manifest is stale", reason);
|
|
18046
18378
|
return;
|
|
18047
18379
|
}
|
|
18048
18380
|
console.warn(`[HLS] Soft restart: ${reason}`);
|
|
@@ -18075,7 +18407,7 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError, hlsConfig }) {
|
|
|
18075
18407
|
};
|
|
18076
18408
|
const hardRestart = (reason) => {
|
|
18077
18409
|
if (staleManifestTriggeredRef.current) {
|
|
18078
|
-
|
|
18410
|
+
debugLog2("[HLS] Skip hard restart while manifest is stale", reason);
|
|
18079
18411
|
return;
|
|
18080
18412
|
}
|
|
18081
18413
|
console.warn(`[HLS] Hard restart: ${reason}`);
|
|
@@ -18329,7 +18661,7 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError, hlsConfig }) {
|
|
|
18329
18661
|
hls.loadSource(resolvedHlsSrc);
|
|
18330
18662
|
activeStreamUrlRef.current = resolvedHlsSrc;
|
|
18331
18663
|
hls.on(Hls__default.default.Events.ERROR, (_, data) => {
|
|
18332
|
-
|
|
18664
|
+
debugLog2("[HLS] Error", {
|
|
18333
18665
|
type: data.type,
|
|
18334
18666
|
details: data.details,
|
|
18335
18667
|
fatal: data.fatal,
|
|
@@ -18337,7 +18669,7 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError, hlsConfig }) {
|
|
|
18337
18669
|
frag: data.frag?.sn
|
|
18338
18670
|
});
|
|
18339
18671
|
if (data.type === Hls__default.default.ErrorTypes.MEDIA_ERROR && data.details === Hls__default.default.ErrorDetails.BUFFER_STALLED_ERROR) {
|
|
18340
|
-
|
|
18672
|
+
debugLog2("[HLS] Buffer stalled, waiting for next segment");
|
|
18341
18673
|
attemptPlay();
|
|
18342
18674
|
return;
|
|
18343
18675
|
}
|
|
@@ -18481,7 +18813,7 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError, hlsConfig }) {
|
|
|
18481
18813
|
}
|
|
18482
18814
|
}
|
|
18483
18815
|
}
|
|
18484
|
-
|
|
18816
|
+
debugLog2("[HLS] Level loaded", {
|
|
18485
18817
|
targetduration: details.targetduration,
|
|
18486
18818
|
edge: details.edge,
|
|
18487
18819
|
fragments: data.details?.fragments?.length
|
|
@@ -18877,6 +19209,7 @@ var isInitializing = false;
|
|
|
18877
19209
|
var initializedWithLineIds = [];
|
|
18878
19210
|
var missingLineContextWarnings = /* @__PURE__ */ new Set();
|
|
18879
19211
|
var lineLoadPromises = /* @__PURE__ */ new Map();
|
|
19212
|
+
var GLOBAL_CACHE_KEY = "global";
|
|
18880
19213
|
var initializationPromise = null;
|
|
18881
19214
|
var workspaceDisplayNamesListeners = /* @__PURE__ */ new Set();
|
|
18882
19215
|
var notifyWorkspaceDisplayNamesListeners = (changedLineId) => {
|
|
@@ -18898,6 +19231,22 @@ var storeLineDisplayNames = (lineId, lineDisplayNamesMap) => {
|
|
|
18898
19231
|
runtimeWorkspaceDisplayNames[lineId][workspaceId] = displayName;
|
|
18899
19232
|
});
|
|
18900
19233
|
};
|
|
19234
|
+
var storeGlobalDisplayNames = (displayNamesMap) => {
|
|
19235
|
+
runtimeWorkspaceDisplayNames[GLOBAL_CACHE_KEY] = {};
|
|
19236
|
+
displayNamesMap.forEach((displayName, workspaceId) => {
|
|
19237
|
+
runtimeWorkspaceDisplayNames[GLOBAL_CACHE_KEY][workspaceId] = displayName;
|
|
19238
|
+
});
|
|
19239
|
+
};
|
|
19240
|
+
var storeDisplayNamesByLine = (displayNamesByLine, requestedLineIds = []) => {
|
|
19241
|
+
displayNamesByLine.forEach((lineDisplayNamesMap, lineId) => {
|
|
19242
|
+
storeLineDisplayNames(lineId, lineDisplayNamesMap);
|
|
19243
|
+
});
|
|
19244
|
+
requestedLineIds.forEach((lineId) => {
|
|
19245
|
+
if (!runtimeWorkspaceDisplayNames[lineId]) {
|
|
19246
|
+
runtimeWorkspaceDisplayNames[lineId] = {};
|
|
19247
|
+
}
|
|
19248
|
+
});
|
|
19249
|
+
};
|
|
18901
19250
|
var ensureLineWorkspaceDisplayNamesLoaded = async (lineId) => {
|
|
18902
19251
|
if (!lineId || runtimeWorkspaceDisplayNames[lineId]) {
|
|
18903
19252
|
return;
|
|
@@ -18981,7 +19330,11 @@ async function initializeWorkspaceDisplayNames(explicitLineId) {
|
|
|
18981
19330
|
console.log("\u{1F504} Target line IDs for workspace filtering:", targetLineIds);
|
|
18982
19331
|
runtimeWorkspaceDisplayNames = {};
|
|
18983
19332
|
lineLoadPromises.clear();
|
|
18984
|
-
if (targetLineIds.length >
|
|
19333
|
+
if (targetLineIds.length > 1) {
|
|
19334
|
+
const displayNamesByLine = await workspaceService.getWorkspaceDisplayNamesByLine(void 0, targetLineIds);
|
|
19335
|
+
storeDisplayNamesByLine(displayNamesByLine, targetLineIds);
|
|
19336
|
+
console.log(`\u2705 Stored display names for ${displayNamesByLine.size} authorized lines`);
|
|
19337
|
+
} else if (targetLineIds.length === 1) {
|
|
18985
19338
|
const results = await Promise.all(
|
|
18986
19339
|
targetLineIds.map(async (lineId) => {
|
|
18987
19340
|
console.log(`\u{1F504} Fetching workspaces for line: ${lineId}`);
|
|
@@ -18996,10 +19349,7 @@ async function initializeWorkspaceDisplayNames(explicitLineId) {
|
|
|
18996
19349
|
} else {
|
|
18997
19350
|
console.warn("\u26A0\uFE0F No line IDs found, fetching all workspaces (less efficient)");
|
|
18998
19351
|
const allWorkspacesMap = await workspaceService.getWorkspaceDisplayNames();
|
|
18999
|
-
|
|
19000
|
-
allWorkspacesMap.forEach((displayName, workspaceId) => {
|
|
19001
|
-
runtimeWorkspaceDisplayNames["global"][workspaceId] = displayName;
|
|
19002
|
-
});
|
|
19352
|
+
storeGlobalDisplayNames(allWorkspacesMap);
|
|
19003
19353
|
}
|
|
19004
19354
|
isInitialized = true;
|
|
19005
19355
|
initializedWithLineIds = targetLineIds;
|
|
@@ -19015,6 +19365,37 @@ async function initializeWorkspaceDisplayNames(explicitLineId) {
|
|
|
19015
19365
|
})();
|
|
19016
19366
|
await initializationPromise;
|
|
19017
19367
|
}
|
|
19368
|
+
var preInitializeWorkspaceDisplayNamesForLines = async (lineIds) => {
|
|
19369
|
+
const uniqueLineIds = Array.from(new Set((lineIds || []).filter(Boolean)));
|
|
19370
|
+
if (uniqueLineIds.length === 0) {
|
|
19371
|
+
await preInitializeWorkspaceDisplayNames();
|
|
19372
|
+
return;
|
|
19373
|
+
}
|
|
19374
|
+
if (uniqueLineIds.length === 1) {
|
|
19375
|
+
await preInitializeWorkspaceDisplayNames(uniqueLineIds[0]);
|
|
19376
|
+
return;
|
|
19377
|
+
}
|
|
19378
|
+
if (isInitialized && uniqueLineIds.every((lineId) => Boolean(runtimeWorkspaceDisplayNames[lineId]))) {
|
|
19379
|
+
return;
|
|
19380
|
+
}
|
|
19381
|
+
if (initializationPromise) {
|
|
19382
|
+
await initializationPromise;
|
|
19383
|
+
if (uniqueLineIds.every((lineId) => Boolean(runtimeWorkspaceDisplayNames[lineId]))) {
|
|
19384
|
+
return;
|
|
19385
|
+
}
|
|
19386
|
+
}
|
|
19387
|
+
isInitializing = true;
|
|
19388
|
+
initializationPromise = workspaceService.getWorkspaceDisplayNamesByLine(void 0, uniqueLineIds).then((displayNamesByLine) => {
|
|
19389
|
+
storeDisplayNamesByLine(displayNamesByLine, uniqueLineIds);
|
|
19390
|
+
initializedWithLineIds = uniqueLineIds;
|
|
19391
|
+
isInitialized = true;
|
|
19392
|
+
notifyWorkspaceDisplayNamesListeners();
|
|
19393
|
+
}).finally(() => {
|
|
19394
|
+
isInitializing = false;
|
|
19395
|
+
initializationPromise = null;
|
|
19396
|
+
});
|
|
19397
|
+
await initializationPromise;
|
|
19398
|
+
};
|
|
19018
19399
|
var preInitializeWorkspaceDisplayNames = async (lineId) => {
|
|
19019
19400
|
console.log("\u{1F504} preInitializeWorkspaceDisplayNames called for lineId:", lineId);
|
|
19020
19401
|
if (isInitialized) {
|
|
@@ -38749,6 +39130,7 @@ var HourlyOutputChartComponent = ({
|
|
|
38749
39130
|
timeRange: data2.timeRange,
|
|
38750
39131
|
startTime,
|
|
38751
39132
|
endTime,
|
|
39133
|
+
timezone,
|
|
38752
39134
|
output: Math.round(data2.originalOutput || 0),
|
|
38753
39135
|
target: data2.target,
|
|
38754
39136
|
status: data2.status
|
|
@@ -38922,6 +39304,7 @@ var HourlyOutputChartComponent = ({
|
|
|
38922
39304
|
timeRange: entry.timeRange,
|
|
38923
39305
|
startTime,
|
|
38924
39306
|
endTime,
|
|
39307
|
+
timezone,
|
|
38925
39308
|
output: Math.round(entry.originalOutput || 0),
|
|
38926
39309
|
target: entry.target,
|
|
38927
39310
|
status: entry.status
|
|
@@ -42389,6 +42772,65 @@ var buildPrefetchedExplorerMetadata = (activeFilter, metadataCategoryId, categor
|
|
|
42389
42772
|
};
|
|
42390
42773
|
};
|
|
42391
42774
|
var shouldDeferClipPlayerRender = (cropLoading, workspaceCrop) => cropLoading && workspaceCrop === null;
|
|
42775
|
+
var parseSortableCycleTime = (value) => {
|
|
42776
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
42777
|
+
return value;
|
|
42778
|
+
}
|
|
42779
|
+
if (typeof value === "string") {
|
|
42780
|
+
const parsed = Number(value);
|
|
42781
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
42782
|
+
}
|
|
42783
|
+
return null;
|
|
42784
|
+
};
|
|
42785
|
+
var readSortableCycleTime = (clip) => {
|
|
42786
|
+
const candidate = clip;
|
|
42787
|
+
return parseSortableCycleTime(candidate?.cycleTimeSeconds) ?? parseSortableCycleTime(candidate?.cycle_time_seconds) ?? parseSortableCycleTime(candidate?.duration) ?? parseSortableCycleTime(
|
|
42788
|
+
candidate?.original_task_metadata?.cycle_time
|
|
42789
|
+
) ?? null;
|
|
42790
|
+
};
|
|
42791
|
+
var readSortableTimestamp = (clip) => {
|
|
42792
|
+
const candidate = clip;
|
|
42793
|
+
const timestamp = candidate?.creation_timestamp || candidate?.timestamp || candidate?.clip_timestamp || candidate?.clip_end_time || candidate?.clip_start_time;
|
|
42794
|
+
if (typeof timestamp !== "string") {
|
|
42795
|
+
return 0;
|
|
42796
|
+
}
|
|
42797
|
+
const parsed = new Date(timestamp).getTime();
|
|
42798
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
42799
|
+
};
|
|
42800
|
+
var sortPercentileCycleClipsForDisplay = (categoryId, clips) => {
|
|
42801
|
+
if (categoryId !== "fast-cycles" && categoryId !== "slow-cycles") {
|
|
42802
|
+
return [...clips];
|
|
42803
|
+
}
|
|
42804
|
+
return [...clips].sort((left, right) => {
|
|
42805
|
+
const leftCycleTime = readSortableCycleTime(left);
|
|
42806
|
+
const rightCycleTime = readSortableCycleTime(right);
|
|
42807
|
+
const leftMissingCycleTime = leftCycleTime === null;
|
|
42808
|
+
const rightMissingCycleTime = rightCycleTime === null;
|
|
42809
|
+
if (leftMissingCycleTime !== rightMissingCycleTime) {
|
|
42810
|
+
return leftMissingCycleTime ? 1 : -1;
|
|
42811
|
+
}
|
|
42812
|
+
if (leftCycleTime !== null && rightCycleTime !== null && leftCycleTime !== rightCycleTime) {
|
|
42813
|
+
return categoryId === "fast-cycles" ? leftCycleTime - rightCycleTime : rightCycleTime - leftCycleTime;
|
|
42814
|
+
}
|
|
42815
|
+
return readSortableTimestamp(right) - readSortableTimestamp(left);
|
|
42816
|
+
});
|
|
42817
|
+
};
|
|
42818
|
+
var resolveInitialClipCategory = (categoryCandidates, clipTypes = [], counts = {}) => {
|
|
42819
|
+
const candidates = Array.from(
|
|
42820
|
+
new Set(
|
|
42821
|
+
categoryCandidates.filter((candidate) => Boolean(candidate)).map((candidate) => candidate.trim()).filter(Boolean)
|
|
42822
|
+
)
|
|
42823
|
+
);
|
|
42824
|
+
if (candidates.length === 0) {
|
|
42825
|
+
return null;
|
|
42826
|
+
}
|
|
42827
|
+
const availableCategories = /* @__PURE__ */ new Set();
|
|
42828
|
+
clipTypes.forEach((type) => {
|
|
42829
|
+
if (type?.type) availableCategories.add(String(type.type));
|
|
42830
|
+
if (type?.id) availableCategories.add(String(type.id));
|
|
42831
|
+
});
|
|
42832
|
+
return candidates.find((candidate) => (counts[candidate] || 0) > 0) || candidates.find((candidate) => availableCategories.has(candidate)) || null;
|
|
42833
|
+
};
|
|
42392
42834
|
var getCategoryMetadataLoadPlanForFilterChange = ({
|
|
42393
42835
|
activeFilter,
|
|
42394
42836
|
currentClipId,
|
|
@@ -42400,6 +42842,12 @@ var getCategoryMetadataLoadPlanForFilterChange = ({
|
|
|
42400
42842
|
if (activeFilter === "recent_flow_red_streak" && categoryTotal > 0) {
|
|
42401
42843
|
return { shouldLoad: true, autoLoadFirstVideo: true };
|
|
42402
42844
|
}
|
|
42845
|
+
if (activeFilter === "fast-cycles" || activeFilter === "slow-cycles") {
|
|
42846
|
+
return { shouldLoad: true, autoLoadFirstVideo: true };
|
|
42847
|
+
}
|
|
42848
|
+
if (categoryTotal > 0 && activeFilter === "cycle_completion") {
|
|
42849
|
+
return { shouldLoad: true, autoLoadFirstVideo: true };
|
|
42850
|
+
}
|
|
42403
42851
|
return {
|
|
42404
42852
|
shouldLoad: Boolean(currentClipId),
|
|
42405
42853
|
autoLoadFirstVideo: false
|
|
@@ -46237,6 +46685,36 @@ var CLIP_METADATA_PAGE_SIZE = 50;
|
|
|
46237
46685
|
var RECENT_FLOW_RED_STREAK_CLIP_TYPE2 = "recent_flow_red_streak";
|
|
46238
46686
|
var RECENT_FLOW_RED_STREAK_DISPLAY_LABEL = "Low moments";
|
|
46239
46687
|
var RECENT_FLOW_RED_STREAK_DISPLAY_SUBTITLE = "Moments of low efficiency";
|
|
46688
|
+
var REQUIRED_HOURLY_HANDOFF_CATEGORIES = {
|
|
46689
|
+
cycle_completion: {
|
|
46690
|
+
id: "cycle_completion",
|
|
46691
|
+
label: "Cycle Completion",
|
|
46692
|
+
description: "Successfully completed production cycles",
|
|
46693
|
+
color: "green",
|
|
46694
|
+
icon: "check-circle"
|
|
46695
|
+
},
|
|
46696
|
+
idle_time: {
|
|
46697
|
+
id: "idle_time",
|
|
46698
|
+
label: "Idle Time",
|
|
46699
|
+
description: "Idle periods",
|
|
46700
|
+
color: "purple",
|
|
46701
|
+
icon: "clock"
|
|
46702
|
+
},
|
|
46703
|
+
[RECENT_FLOW_RED_STREAK_CLIP_TYPE2]: {
|
|
46704
|
+
id: RECENT_FLOW_RED_STREAK_CLIP_TYPE2,
|
|
46705
|
+
label: RECENT_FLOW_RED_STREAK_DISPLAY_LABEL,
|
|
46706
|
+
description: RECENT_FLOW_RED_STREAK_DISPLAY_SUBTITLE,
|
|
46707
|
+
color: "red",
|
|
46708
|
+
icon: "alert-triangle"
|
|
46709
|
+
}
|
|
46710
|
+
};
|
|
46711
|
+
var REQUIRED_HOURLY_FILTER_CATEGORY_IDS = [
|
|
46712
|
+
RECENT_FLOW_RED_STREAK_CLIP_TYPE2,
|
|
46713
|
+
"cycle_completion",
|
|
46714
|
+
"fast-cycles",
|
|
46715
|
+
"slow-cycles",
|
|
46716
|
+
"idle_time"
|
|
46717
|
+
];
|
|
46240
46718
|
var parseCycleTime = (value) => {
|
|
46241
46719
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
46242
46720
|
return value;
|
|
@@ -46265,6 +46743,21 @@ var formatDurationLabel = (seconds) => {
|
|
|
46265
46743
|
}
|
|
46266
46744
|
return `${Math.round(roundedSeconds / 60)} min`;
|
|
46267
46745
|
};
|
|
46746
|
+
var timeValueToMinutes = (value) => {
|
|
46747
|
+
const [hourValue, minuteValue] = value.substring(0, 5).split(":").map(Number);
|
|
46748
|
+
if (!Number.isInteger(hourValue) || !Number.isInteger(minuteValue) || hourValue < 0 || hourValue > 23 || minuteValue < 0 || minuteValue > 59) {
|
|
46749
|
+
return null;
|
|
46750
|
+
}
|
|
46751
|
+
return hourValue * 60 + minuteValue;
|
|
46752
|
+
};
|
|
46753
|
+
var isMinuteInTimeWindow = (minute, startValue, endValue) => {
|
|
46754
|
+
const startMinute = timeValueToMinutes(startValue);
|
|
46755
|
+
const endMinute = timeValueToMinutes(endValue);
|
|
46756
|
+
if (startMinute === null || endMinute === null) {
|
|
46757
|
+
return true;
|
|
46758
|
+
}
|
|
46759
|
+
return endMinute > startMinute ? minute >= startMinute && minute < endMinute : minute >= startMinute || minute < endMinute;
|
|
46760
|
+
};
|
|
46268
46761
|
var sortRedFlowMetadata = (clips) => {
|
|
46269
46762
|
return clips.slice().sort((left, right) => {
|
|
46270
46763
|
const getOutputShortfall = (clip) => {
|
|
@@ -46289,6 +46782,27 @@ var sortRedFlowMetadata = (clips) => {
|
|
|
46289
46782
|
return (Number.isFinite(rightTime) ? rightTime : 0) - (Number.isFinite(leftTime) ? leftTime : 0);
|
|
46290
46783
|
});
|
|
46291
46784
|
};
|
|
46785
|
+
var buildClipMetadataFromVideo = (video, index) => ({
|
|
46786
|
+
id: video.id,
|
|
46787
|
+
clipId: video.id,
|
|
46788
|
+
clip_timestamp: video.creation_timestamp || video.timestamp,
|
|
46789
|
+
description: video.description,
|
|
46790
|
+
severity: video.severity,
|
|
46791
|
+
category: video.type,
|
|
46792
|
+
duration: typeof video.duration === "number" ? video.duration : typeof video.cycle_time_seconds === "number" ? video.cycle_time_seconds : void 0,
|
|
46793
|
+
clip_start_time: video.clip_start_time,
|
|
46794
|
+
clip_end_time: video.clip_end_time,
|
|
46795
|
+
index,
|
|
46796
|
+
idle_start_time: video.idle_start_time,
|
|
46797
|
+
idle_end_time: video.idle_end_time,
|
|
46798
|
+
cycle_item_count: null,
|
|
46799
|
+
red_flow_timeline: video.red_flow_timeline,
|
|
46800
|
+
red_flow_severity_score: video.red_flow_severity_score,
|
|
46801
|
+
red_flow_output_shortfall_units: video.red_flow_output_shortfall_units,
|
|
46802
|
+
red_flow_worst_minute: video.red_flow_worst_minute,
|
|
46803
|
+
red_flow_explanation_summary: video.red_flow_explanation_summary,
|
|
46804
|
+
red_flow_explanation: video.red_flow_explanation
|
|
46805
|
+
});
|
|
46292
46806
|
var getSeverityIcon = (severity, categoryId, cycleTimeSeconds, targetCycleTime, clipId) => {
|
|
46293
46807
|
if (categoryId === "idle_time" || categoryId === "low_value" || categoryId === "longest-idles") {
|
|
46294
46808
|
return null;
|
|
@@ -46367,6 +46881,8 @@ var FileManagerFilters = ({
|
|
|
46367
46881
|
idleTimeVlmEnabled = false,
|
|
46368
46882
|
showPercentileCycleFilters = true,
|
|
46369
46883
|
prefetchedClipMetadata,
|
|
46884
|
+
prefetchedClipTotals,
|
|
46885
|
+
prefetchedPercentileClips,
|
|
46370
46886
|
externallyManagedLoadingCategories,
|
|
46371
46887
|
activeCategoryLoading,
|
|
46372
46888
|
idleClipSort = "latest",
|
|
@@ -46374,6 +46890,7 @@ var FileManagerFilters = ({
|
|
|
46374
46890
|
initialTimeFilter
|
|
46375
46891
|
}) => {
|
|
46376
46892
|
const [expandedNodes, setExpandedNodes] = React125.useState(/* @__PURE__ */ new Set());
|
|
46893
|
+
const [activeInitialTimeFilter, setActiveInitialTimeFilter] = React125.useState(initialTimeFilter ?? null);
|
|
46377
46894
|
const [startTime, setStartTime] = React125.useState(initialTimeFilter?.startTime ?? "");
|
|
46378
46895
|
const [endTime, setEndTime] = React125.useState(initialTimeFilter?.endTime ?? "");
|
|
46379
46896
|
const [isTimeFilterActive, setIsTimeFilterActive] = React125.useState(
|
|
@@ -46388,14 +46905,93 @@ var FileManagerFilters = ({
|
|
|
46388
46905
|
const [showIdleLabelFilterModal, setShowIdleLabelFilterModal] = React125.useState(false);
|
|
46389
46906
|
const [isLoadingIdleReasonOptions, setIsLoadingIdleReasonOptions] = React125.useState(false);
|
|
46390
46907
|
const timezone = useAppTimezone();
|
|
46908
|
+
const activeTimeFilterTimezone = activeInitialTimeFilter?.timezone || initialTimeFilter?.timezone || timezone;
|
|
46909
|
+
const activeTimeFilterKey = React125.useMemo(() => startTime && endTime && isTimeFilterActive ? `${startTime}-${endTime}-${activeTimeFilterTimezone}` : "none", [activeTimeFilterTimezone, endTime, isTimeFilterActive, startTime]);
|
|
46910
|
+
const initialTimeFilterCategoryIds = React125.useMemo(() => {
|
|
46911
|
+
if (!activeInitialTimeFilter) {
|
|
46912
|
+
return [];
|
|
46913
|
+
}
|
|
46914
|
+
return Array.from(new Set([
|
|
46915
|
+
activeInitialTimeFilter.categoryId,
|
|
46916
|
+
...activeInitialTimeFilter.categoryIds || []
|
|
46917
|
+
].filter((value) => typeof value === "string" && value.length > 0)));
|
|
46918
|
+
}, [activeInitialTimeFilter]);
|
|
46919
|
+
const requiredHourlyFilterCategoryIds = React125.useMemo(() => {
|
|
46920
|
+
if (initialTimeFilterCategoryIds.length > 0) {
|
|
46921
|
+
return initialTimeFilterCategoryIds;
|
|
46922
|
+
}
|
|
46923
|
+
if (!isTimeFilterActive || !startTime || !endTime) {
|
|
46924
|
+
return [];
|
|
46925
|
+
}
|
|
46926
|
+
return REQUIRED_HOURLY_FILTER_CATEGORY_IDS;
|
|
46927
|
+
}, [endTime, initialTimeFilterCategoryIds, isTimeFilterActive, startTime]);
|
|
46928
|
+
const categoriesForTree = React125.useMemo(() => {
|
|
46929
|
+
if (requiredHourlyFilterCategoryIds.length === 0) {
|
|
46930
|
+
return categories;
|
|
46931
|
+
}
|
|
46932
|
+
const existingCategoryIds = new Set(categories.map((category) => category.id));
|
|
46933
|
+
const mergedCategories = [...categories];
|
|
46934
|
+
requiredHourlyFilterCategoryIds.forEach((categoryId) => {
|
|
46935
|
+
const fallbackCategory = REQUIRED_HOURLY_HANDOFF_CATEGORIES[categoryId];
|
|
46936
|
+
if (!fallbackCategory || existingCategoryIds.has(categoryId)) {
|
|
46937
|
+
return;
|
|
46938
|
+
}
|
|
46939
|
+
mergedCategories.push(fallbackCategory);
|
|
46940
|
+
existingCategoryIds.add(categoryId);
|
|
46941
|
+
});
|
|
46942
|
+
return mergedCategories;
|
|
46943
|
+
}, [categories, requiredHourlyFilterCategoryIds]);
|
|
46391
46944
|
const supabase = useSupabase();
|
|
46392
46945
|
const [clipMetadata, setClipMetadata] = React125.useState({});
|
|
46946
|
+
const [scopedCategoryTotals, setScopedCategoryTotals] = React125.useState({});
|
|
46393
46947
|
const [loadingCategories, setLoadingCategories] = React125.useState(/* @__PURE__ */ new Set());
|
|
46948
|
+
const isCategoryScopedByTimeFilter = React125.useCallback((categoryId) => {
|
|
46949
|
+
if (!startTime || !endTime || !isTimeFilterActive) {
|
|
46950
|
+
return false;
|
|
46951
|
+
}
|
|
46952
|
+
if (!activeInitialTimeFilter) {
|
|
46953
|
+
return true;
|
|
46954
|
+
}
|
|
46955
|
+
if (activeFilter === categoryId || activeInitialTimeFilter.categoryId === categoryId) {
|
|
46956
|
+
return true;
|
|
46957
|
+
}
|
|
46958
|
+
return Boolean(activeInitialTimeFilter.categoryIds?.includes(categoryId));
|
|
46959
|
+
}, [
|
|
46960
|
+
activeFilter,
|
|
46961
|
+
activeInitialTimeFilter,
|
|
46962
|
+
endTime,
|
|
46963
|
+
isTimeFilterActive,
|
|
46964
|
+
startTime
|
|
46965
|
+
]);
|
|
46966
|
+
const isRequiredHourlyFilterCategory = React125.useCallback((categoryId) => requiredHourlyFilterCategoryIds.includes(categoryId), [requiredHourlyFilterCategoryIds]);
|
|
46967
|
+
const manualHourlySnapshotKey = React125.useMemo(() => {
|
|
46968
|
+
if (activeInitialTimeFilter || !isTimeFilterActive || !startTime || !endTime || !workspaceId || !date || shift === void 0) {
|
|
46969
|
+
return null;
|
|
46970
|
+
}
|
|
46971
|
+
return `${workspaceId}:${date}:${shift}:${startTime}:${endTime}:${activeTimeFilterTimezone}`;
|
|
46972
|
+
}, [
|
|
46973
|
+
activeInitialTimeFilter,
|
|
46974
|
+
activeTimeFilterTimezone,
|
|
46975
|
+
date,
|
|
46976
|
+
endTime,
|
|
46977
|
+
isTimeFilterActive,
|
|
46978
|
+
shift,
|
|
46979
|
+
startTime,
|
|
46980
|
+
workspaceId
|
|
46981
|
+
]);
|
|
46982
|
+
const manualHourlySnapshotAppliedKeyRef = React125.useRef(null);
|
|
46983
|
+
const manualHourlySnapshotInFlightKeyRef = React125.useRef(null);
|
|
46984
|
+
const [manualHourlySnapshotFailureKey, setManualHourlySnapshotFailureKey] = React125.useState(null);
|
|
46985
|
+
const isManualHourlySnapshotPending = Boolean(
|
|
46986
|
+
manualHourlySnapshotKey && manualHourlySnapshotAppliedKeyRef.current !== manualHourlySnapshotKey && manualHourlySnapshotFailureKey !== manualHourlySnapshotKey
|
|
46987
|
+
);
|
|
46394
46988
|
const [categoryPages, setCategoryPages] = React125.useState({});
|
|
46395
46989
|
const [categoryHasMore, setCategoryHasMore] = React125.useState({});
|
|
46396
46990
|
const [localClipClassifications, setLocalClipClassifications] = React125.useState({});
|
|
46397
46991
|
const clipMetadataRef = React125.useRef({});
|
|
46398
46992
|
const inFlightMetadataRequestsRef = React125.useRef(/* @__PURE__ */ new Set());
|
|
46993
|
+
const inFlightPercentileClipRequestsRef = React125.useRef(/* @__PURE__ */ new Set());
|
|
46994
|
+
const autoSelectedScopedClipRef = React125.useRef(null);
|
|
46399
46995
|
const previousIdleClipSortRef = React125.useRef(idleClipSort);
|
|
46400
46996
|
const mergedClipClassifications = React125.useMemo(() => ({
|
|
46401
46997
|
...clipClassifications || {},
|
|
@@ -46408,12 +47004,14 @@ var FileManagerFilters = ({
|
|
|
46408
47004
|
if (!initialTimeFilter?.startTime || !initialTimeFilter?.endTime) {
|
|
46409
47005
|
return;
|
|
46410
47006
|
}
|
|
47007
|
+
setActiveInitialTimeFilter(initialTimeFilter);
|
|
46411
47008
|
setStartTime(initialTimeFilter.startTime);
|
|
46412
47009
|
setEndTime(initialTimeFilter.endTime);
|
|
46413
47010
|
setIsTimeFilterActive(true);
|
|
46414
47011
|
setShowTimeFilterModal(false);
|
|
46415
47012
|
setStartSearchTerm("");
|
|
46416
47013
|
setEndSearchTerm("");
|
|
47014
|
+
setScopedCategoryTotals({});
|
|
46417
47015
|
}, [initialTimeFilter?.startTime, initialTimeFilter?.endTime]);
|
|
46418
47016
|
React125.useEffect(() => {
|
|
46419
47017
|
if (previousIdleClipSortRef.current === idleClipSort) {
|
|
@@ -46445,18 +47043,66 @@ var FileManagerFilters = ({
|
|
|
46445
47043
|
return next;
|
|
46446
47044
|
});
|
|
46447
47045
|
}, [idleClipSort]);
|
|
47046
|
+
React125.useEffect(() => {
|
|
47047
|
+
manualHourlySnapshotAppliedKeyRef.current = null;
|
|
47048
|
+
manualHourlySnapshotInFlightKeyRef.current = null;
|
|
47049
|
+
setManualHourlySnapshotFailureKey(null);
|
|
47050
|
+
setScopedCategoryTotals({});
|
|
47051
|
+
setClipMetadata({});
|
|
47052
|
+
setCategoryPages({});
|
|
47053
|
+
setCategoryHasMore({});
|
|
47054
|
+
setPercentileClips({});
|
|
47055
|
+
setPercentileCounts({
|
|
47056
|
+
"fast-cycles": null,
|
|
47057
|
+
"slow-cycles": null
|
|
47058
|
+
});
|
|
47059
|
+
}, [activeTimeFilterKey]);
|
|
46448
47060
|
const isCategoryExternallyManaged = React125.useCallback((categoryId) => {
|
|
46449
47061
|
if (!categoryId) {
|
|
46450
47062
|
return false;
|
|
46451
47063
|
}
|
|
46452
|
-
if (
|
|
47064
|
+
if (isManualHourlySnapshotPending && requiredHourlyFilterCategoryIds.includes(categoryId)) {
|
|
47065
|
+
return true;
|
|
47066
|
+
}
|
|
47067
|
+
if (prefetchedClipMetadata && Array.isArray(prefetchedClipMetadata[categoryId]) && (prefetchedClipMetadata[categoryId].length > 0 || typeof prefetchedClipTotals?.[categoryId] === "number")) {
|
|
47068
|
+
return true;
|
|
47069
|
+
}
|
|
47070
|
+
if (prefetchedPercentileClips && Array.isArray(prefetchedPercentileClips[categoryId]) && (prefetchedPercentileClips[categoryId].length > 0 || isCategoryScopedByTimeFilter(categoryId) && typeof prefetchedClipTotals?.[categoryId] === "number")) {
|
|
46453
47071
|
return true;
|
|
46454
47072
|
}
|
|
46455
47073
|
if (externallyManagedLoadingCategories?.[categoryId]) {
|
|
46456
47074
|
return true;
|
|
46457
47075
|
}
|
|
46458
47076
|
return false;
|
|
46459
|
-
}, [
|
|
47077
|
+
}, [
|
|
47078
|
+
externallyManagedLoadingCategories,
|
|
47079
|
+
isManualHourlySnapshotPending,
|
|
47080
|
+
isCategoryScopedByTimeFilter,
|
|
47081
|
+
prefetchedClipMetadata,
|
|
47082
|
+
prefetchedClipTotals,
|
|
47083
|
+
prefetchedPercentileClips,
|
|
47084
|
+
requiredHourlyFilterCategoryIds
|
|
47085
|
+
]);
|
|
47086
|
+
const getAvailableClipMetadata = React125.useCallback((categoryId) => {
|
|
47087
|
+
const localClips = clipMetadata[categoryId];
|
|
47088
|
+
if (Array.isArray(localClips) && localClips.length > 0) {
|
|
47089
|
+
return localClips;
|
|
47090
|
+
}
|
|
47091
|
+
const prefetchedClips = prefetchedClipMetadata?.[categoryId];
|
|
47092
|
+
if (Array.isArray(prefetchedClips) && prefetchedClips.length > 0) {
|
|
47093
|
+
return prefetchedClips;
|
|
47094
|
+
}
|
|
47095
|
+
return [];
|
|
47096
|
+
}, [clipMetadata, prefetchedClipMetadata]);
|
|
47097
|
+
const hasKnownClipMetadata = React125.useCallback((categoryId) => {
|
|
47098
|
+
if (Array.isArray(clipMetadata[categoryId])) {
|
|
47099
|
+
return true;
|
|
47100
|
+
}
|
|
47101
|
+
if (Array.isArray(prefetchedClipMetadata?.[categoryId])) {
|
|
47102
|
+
return true;
|
|
47103
|
+
}
|
|
47104
|
+
return typeof prefetchedClipTotals?.[categoryId] === "number";
|
|
47105
|
+
}, [clipMetadata, prefetchedClipMetadata, prefetchedClipTotals]);
|
|
46460
47106
|
React125.useEffect(() => {
|
|
46461
47107
|
if (!prefetchedClipMetadata) {
|
|
46462
47108
|
return;
|
|
@@ -46479,6 +47125,22 @@ var FileManagerFilters = ({
|
|
|
46479
47125
|
});
|
|
46480
47126
|
return changed ? next : prev;
|
|
46481
47127
|
});
|
|
47128
|
+
setScopedCategoryTotals((prev) => {
|
|
47129
|
+
let changed = false;
|
|
47130
|
+
const next = { ...prev };
|
|
47131
|
+
Object.entries(prefetchedClipMetadata).forEach(([categoryId, clips]) => {
|
|
47132
|
+
if (!Array.isArray(clips) || !isCategoryScopedByTimeFilter(categoryId)) {
|
|
47133
|
+
return;
|
|
47134
|
+
}
|
|
47135
|
+
const nextTotal = typeof prefetchedClipTotals?.[categoryId] === "number" ? Math.max(0, prefetchedClipTotals[categoryId]) : clips.length;
|
|
47136
|
+
if (next[categoryId] === nextTotal) {
|
|
47137
|
+
return;
|
|
47138
|
+
}
|
|
47139
|
+
next[categoryId] = nextTotal;
|
|
47140
|
+
changed = true;
|
|
47141
|
+
});
|
|
47142
|
+
return changed ? next : prev;
|
|
47143
|
+
});
|
|
46482
47144
|
setCategoryPages((prev) => {
|
|
46483
47145
|
let changed = false;
|
|
46484
47146
|
const next = { ...prev };
|
|
@@ -46503,7 +47165,7 @@ var FileManagerFilters = ({
|
|
|
46503
47165
|
return;
|
|
46504
47166
|
}
|
|
46505
47167
|
const knownTotal = typeof counts?.[categoryId] === "number" ? counts[categoryId] : null;
|
|
46506
|
-
const inferredHasMore = knownTotal !== null ? clips.length < knownTotal : prev[categoryId];
|
|
47168
|
+
const inferredHasMore = isCategoryScopedByTimeFilter(categoryId) ? false : knownTotal !== null ? clips.length < knownTotal : prev[categoryId];
|
|
46507
47169
|
if (typeof inferredHasMore !== "boolean" || next[categoryId] === inferredHasMore) {
|
|
46508
47170
|
return;
|
|
46509
47171
|
}
|
|
@@ -46512,8 +47174,68 @@ var FileManagerFilters = ({
|
|
|
46512
47174
|
});
|
|
46513
47175
|
return changed ? next : prev;
|
|
46514
47176
|
});
|
|
46515
|
-
}, [prefetchedClipMetadata, counts]);
|
|
47177
|
+
}, [prefetchedClipMetadata, prefetchedClipTotals, counts, isCategoryScopedByTimeFilter]);
|
|
47178
|
+
React125.useEffect(() => {
|
|
47179
|
+
if (!prefetchedPercentileClips) {
|
|
47180
|
+
return;
|
|
47181
|
+
}
|
|
47182
|
+
setPercentileClips((prev) => {
|
|
47183
|
+
let changed = false;
|
|
47184
|
+
const next = { ...prev };
|
|
47185
|
+
["fast-cycles", "slow-cycles"].forEach((categoryId) => {
|
|
47186
|
+
const clips = prefetchedPercentileClips[categoryId];
|
|
47187
|
+
if (!Array.isArray(clips)) {
|
|
47188
|
+
return;
|
|
47189
|
+
}
|
|
47190
|
+
const previousClips = prev[categoryId] || [];
|
|
47191
|
+
const previousSignature = previousClips.map((clip) => clip.id).join("|");
|
|
47192
|
+
const nextSignature = clips.map((clip) => clip.id).join("|");
|
|
47193
|
+
if (previousSignature === nextSignature) {
|
|
47194
|
+
return;
|
|
47195
|
+
}
|
|
47196
|
+
next[categoryId] = clips;
|
|
47197
|
+
changed = true;
|
|
47198
|
+
});
|
|
47199
|
+
return changed ? next : prev;
|
|
47200
|
+
});
|
|
47201
|
+
setPercentileCounts((prev) => {
|
|
47202
|
+
let changed = false;
|
|
47203
|
+
const next = { ...prev };
|
|
47204
|
+
["fast-cycles", "slow-cycles"].forEach((categoryId) => {
|
|
47205
|
+
const clips = prefetchedPercentileClips[categoryId];
|
|
47206
|
+
if (!Array.isArray(clips)) {
|
|
47207
|
+
return;
|
|
47208
|
+
}
|
|
47209
|
+
const nextTotal = typeof prefetchedClipTotals?.[categoryId] === "number" ? Math.max(0, prefetchedClipTotals[categoryId]) : clips.length;
|
|
47210
|
+
if (next[categoryId] === nextTotal) {
|
|
47211
|
+
return;
|
|
47212
|
+
}
|
|
47213
|
+
next[categoryId] = nextTotal;
|
|
47214
|
+
changed = true;
|
|
47215
|
+
});
|
|
47216
|
+
return changed ? next : prev;
|
|
47217
|
+
});
|
|
47218
|
+
}, [prefetchedClipTotals, prefetchedPercentileClips]);
|
|
46516
47219
|
const { state: filterState } = useClipFilter();
|
|
47220
|
+
const shouldShowCategory = React125.useCallback((categoryId) => {
|
|
47221
|
+
switch (categoryId) {
|
|
47222
|
+
case "fast-cycles":
|
|
47223
|
+
return showPercentileCycleFilters && filterState.showFastCycles;
|
|
47224
|
+
case "slow-cycles":
|
|
47225
|
+
return showPercentileCycleFilters && filterState.showSlowCycles;
|
|
47226
|
+
case "longest-idles":
|
|
47227
|
+
return false;
|
|
47228
|
+
// filterState.showLongestIdles; // Temporarily disabled
|
|
47229
|
+
case "cycle_completion":
|
|
47230
|
+
return filterState.showCycleCompletion;
|
|
47231
|
+
case "idle_time":
|
|
47232
|
+
return filterState.showIdleTime;
|
|
47233
|
+
case "sop_deviations":
|
|
47234
|
+
return filterState.showSopDeviations;
|
|
47235
|
+
default:
|
|
47236
|
+
return true;
|
|
47237
|
+
}
|
|
47238
|
+
}, [filterState, showPercentileCycleFilters]);
|
|
46517
47239
|
const [percentileCounts, setPercentileCounts] = React125.useState({
|
|
46518
47240
|
"fast-cycles": null,
|
|
46519
47241
|
"slow-cycles": null
|
|
@@ -46623,11 +47345,12 @@ var FileManagerFilters = ({
|
|
|
46623
47345
|
return null;
|
|
46624
47346
|
}
|
|
46625
47347
|
}, [supabase]);
|
|
46626
|
-
const getMetadataLoadingKey = React125.useCallback((categoryId, page) => `${categoryId}-${page}-${categoryId === RECENT_FLOW_RED_STREAK_CLIP_TYPE2 ? "red_flow_output_shortfall_desc" : categoryId === "idle_time" ? idleClipSort : "latest"}`, [idleClipSort]);
|
|
47348
|
+
const getMetadataLoadingKey = React125.useCallback((categoryId, page) => `${categoryId}-${page}-${categoryId === RECENT_FLOW_RED_STREAK_CLIP_TYPE2 ? "red_flow_output_shortfall_desc" : categoryId === "idle_time" ? idleClipSort : "latest"}-${activeTimeFilterKey}`, [activeTimeFilterKey, idleClipSort]);
|
|
46627
47349
|
const fetchClipMetadataPage = React125.useCallback(async (categoryId, page = 1) => {
|
|
46628
47350
|
if (!workspaceId || !date || shift === void 0) {
|
|
46629
47351
|
throw new Error("Missing required params for clip metadata fetch");
|
|
46630
47352
|
}
|
|
47353
|
+
const shouldScopeToTimeFilter = isCategoryScopedByTimeFilter(categoryId);
|
|
46631
47354
|
const response = await fetchWithSupabaseAuth(supabase, "/api/clips/supabase", {
|
|
46632
47355
|
method: "POST",
|
|
46633
47356
|
headers: {
|
|
@@ -46641,9 +47364,12 @@ var FileManagerFilters = ({
|
|
|
46641
47364
|
category: categoryId,
|
|
46642
47365
|
page,
|
|
46643
47366
|
limit: CLIP_METADATA_PAGE_SIZE,
|
|
46644
|
-
knownTotal: typeof counts?.[categoryId] === "number" ? counts[categoryId] : null,
|
|
47367
|
+
knownTotal: shouldScopeToTimeFilter ? null : typeof counts?.[categoryId] === "number" ? counts[categoryId] : null,
|
|
46645
47368
|
snapshotDateTime,
|
|
46646
47369
|
snapshotClipId,
|
|
47370
|
+
startTime: shouldScopeToTimeFilter ? startTime : void 0,
|
|
47371
|
+
endTime: shouldScopeToTimeFilter ? endTime : void 0,
|
|
47372
|
+
timeFilterTimezone: shouldScopeToTimeFilter ? activeTimeFilterTimezone : void 0,
|
|
46647
47373
|
sort: categoryId === RECENT_FLOW_RED_STREAK_CLIP_TYPE2 ? "red_flow_output_shortfall_desc" : categoryId === "idle_time" ? idleClipSort : "latest"
|
|
46648
47374
|
}),
|
|
46649
47375
|
redirectReason: "session_expired"
|
|
@@ -46652,7 +47378,20 @@ var FileManagerFilters = ({
|
|
|
46652
47378
|
throw new Error(`API error: ${response.status}`);
|
|
46653
47379
|
}
|
|
46654
47380
|
return response.json();
|
|
46655
|
-
}, [
|
|
47381
|
+
}, [
|
|
47382
|
+
activeTimeFilterTimezone,
|
|
47383
|
+
endTime,
|
|
47384
|
+
isCategoryScopedByTimeFilter,
|
|
47385
|
+
startTime,
|
|
47386
|
+
workspaceId,
|
|
47387
|
+
date,
|
|
47388
|
+
shift,
|
|
47389
|
+
counts,
|
|
47390
|
+
snapshotDateTime,
|
|
47391
|
+
snapshotClipId,
|
|
47392
|
+
idleClipSort,
|
|
47393
|
+
supabase
|
|
47394
|
+
]);
|
|
46656
47395
|
const seedIdleClassifications = React125.useCallback(async (clips) => {
|
|
46657
47396
|
if (!idleTimeVlmEnabled || clips.length === 0) {
|
|
46658
47397
|
return;
|
|
@@ -46720,6 +47459,12 @@ var FileManagerFilters = ({
|
|
|
46720
47459
|
...prev,
|
|
46721
47460
|
[categoryId]: page === 1 ? data.clips : [...prev[categoryId] || [], ...data.clips]
|
|
46722
47461
|
}));
|
|
47462
|
+
if (isCategoryScopedByTimeFilter(categoryId)) {
|
|
47463
|
+
setScopedCategoryTotals((prev) => ({
|
|
47464
|
+
...prev,
|
|
47465
|
+
[categoryId]: Math.max(0, Number(data.total || 0))
|
|
47466
|
+
}));
|
|
47467
|
+
}
|
|
46723
47468
|
if (categoryId === "idle_time" && idleTimeVlmEnabled) {
|
|
46724
47469
|
await seedIdleClassifications(data.clips || []);
|
|
46725
47470
|
}
|
|
@@ -46736,7 +47481,94 @@ var FileManagerFilters = ({
|
|
|
46736
47481
|
return newSet;
|
|
46737
47482
|
});
|
|
46738
47483
|
}
|
|
46739
|
-
}, [workspaceId, date, shift, fetchClipMetadataPage, idleTimeVlmEnabled, seedIdleClassifications, getMetadataLoadingKey]);
|
|
47484
|
+
}, [workspaceId, date, shift, fetchClipMetadataPage, idleTimeVlmEnabled, seedIdleClassifications, getMetadataLoadingKey, isCategoryScopedByTimeFilter]);
|
|
47485
|
+
React125.useCallback(async (categoryId) => {
|
|
47486
|
+
if (!workspaceId || !date || shift === void 0) {
|
|
47487
|
+
console.warn("[FileManager] Missing required params for full clip metadata fetch");
|
|
47488
|
+
return;
|
|
47489
|
+
}
|
|
47490
|
+
const loadingKey = `${getMetadataLoadingKey(categoryId, 1)}-all`;
|
|
47491
|
+
if (inFlightMetadataRequestsRef.current.has(loadingKey)) {
|
|
47492
|
+
return;
|
|
47493
|
+
}
|
|
47494
|
+
inFlightMetadataRequestsRef.current.add(loadingKey);
|
|
47495
|
+
setLoadingCategories((prev) => /* @__PURE__ */ new Set([...prev, loadingKey]));
|
|
47496
|
+
try {
|
|
47497
|
+
let accumulatedClips = [];
|
|
47498
|
+
let currentPage = 0;
|
|
47499
|
+
let hasMore = true;
|
|
47500
|
+
while (hasMore) {
|
|
47501
|
+
const nextPage = currentPage + 1;
|
|
47502
|
+
const pageData = await fetchClipMetadataPage(categoryId, nextPage);
|
|
47503
|
+
const pageClips = pageData.clips || [];
|
|
47504
|
+
accumulatedClips = [...accumulatedClips, ...pageClips];
|
|
47505
|
+
currentPage = nextPage;
|
|
47506
|
+
hasMore = Boolean(pageData.hasMore && pageClips.length > 0);
|
|
47507
|
+
}
|
|
47508
|
+
const dedupedClips = accumulatedClips.filter((clip, index, arr) => {
|
|
47509
|
+
const clipKey = clip.clipId || clip.id;
|
|
47510
|
+
return arr.findIndex((item) => (item.clipId || item.id) === clipKey) === index;
|
|
47511
|
+
});
|
|
47512
|
+
setClipMetadata((prev) => ({
|
|
47513
|
+
...prev,
|
|
47514
|
+
[categoryId]: dedupedClips
|
|
47515
|
+
}));
|
|
47516
|
+
setCategoryPages((prev) => ({ ...prev, [categoryId]: Math.max(currentPage, 1) }));
|
|
47517
|
+
setCategoryHasMore((prev) => ({ ...prev, [categoryId]: false }));
|
|
47518
|
+
if (categoryId === "idle_time" && idleTimeVlmEnabled) {
|
|
47519
|
+
await seedIdleClassifications(dedupedClips);
|
|
47520
|
+
}
|
|
47521
|
+
console.log(`[FileManager] Loaded all ${dedupedClips.length} clips for ${categoryId} due to chart time filter`);
|
|
47522
|
+
} catch (error) {
|
|
47523
|
+
console.error("[FileManager] Error fetching full clip metadata:", error);
|
|
47524
|
+
} finally {
|
|
47525
|
+
inFlightMetadataRequestsRef.current.delete(loadingKey);
|
|
47526
|
+
setLoadingCategories((prev) => {
|
|
47527
|
+
const newSet = new Set(prev);
|
|
47528
|
+
newSet.delete(loadingKey);
|
|
47529
|
+
return newSet;
|
|
47530
|
+
});
|
|
47531
|
+
}
|
|
47532
|
+
}, [
|
|
47533
|
+
workspaceId,
|
|
47534
|
+
date,
|
|
47535
|
+
shift,
|
|
47536
|
+
fetchClipMetadataPage,
|
|
47537
|
+
idleTimeVlmEnabled,
|
|
47538
|
+
seedIdleClassifications,
|
|
47539
|
+
getMetadataLoadingKey
|
|
47540
|
+
]);
|
|
47541
|
+
const isInitialTimeFilterCategory = React125.useCallback((categoryId) => {
|
|
47542
|
+
if (!startTime || !endTime || !activeInitialTimeFilter) {
|
|
47543
|
+
return false;
|
|
47544
|
+
}
|
|
47545
|
+
if (activeFilter === categoryId) {
|
|
47546
|
+
return true;
|
|
47547
|
+
}
|
|
47548
|
+
if (activeInitialTimeFilter.categoryId === categoryId) {
|
|
47549
|
+
return true;
|
|
47550
|
+
}
|
|
47551
|
+
return Array.isArray(activeInitialTimeFilter.categoryIds) && activeInitialTimeFilter.categoryIds.includes(categoryId);
|
|
47552
|
+
}, [
|
|
47553
|
+
activeFilter,
|
|
47554
|
+
activeInitialTimeFilter,
|
|
47555
|
+
endTime,
|
|
47556
|
+
startTime
|
|
47557
|
+
]);
|
|
47558
|
+
const hasCompleteMetadataForInitialTimeFilter = React125.useCallback((categoryId) => {
|
|
47559
|
+
if (!isInitialTimeFilterCategory(categoryId)) {
|
|
47560
|
+
return true;
|
|
47561
|
+
}
|
|
47562
|
+
const loadedClips = clipMetadataRef.current[categoryId] || [];
|
|
47563
|
+
const knownTotal = typeof scopedCategoryTotals[categoryId] === "number" ? scopedCategoryTotals[categoryId] : null;
|
|
47564
|
+
if (categoryHasMore[categoryId]) {
|
|
47565
|
+
return false;
|
|
47566
|
+
}
|
|
47567
|
+
if (knownTotal !== null && loadedClips.length < knownTotal) {
|
|
47568
|
+
return false;
|
|
47569
|
+
}
|
|
47570
|
+
return loadedClips.length > 0 || knownTotal === 0;
|
|
47571
|
+
}, [categoryHasMore, isInitialTimeFilterCategory, scopedCategoryTotals]);
|
|
46740
47572
|
const ensureAllIdleTimeClipMetadataLoaded = React125.useCallback(async () => {
|
|
46741
47573
|
if (!workspaceId || !date || shift === void 0) {
|
|
46742
47574
|
return;
|
|
@@ -46802,6 +47634,12 @@ var FileManagerFilters = ({
|
|
|
46802
47634
|
console.warn("[FileManager] Missing required params for percentile clips fetch");
|
|
46803
47635
|
return;
|
|
46804
47636
|
}
|
|
47637
|
+
const shouldScopeToTimeFilter = isCategoryScopedByTimeFilter(type);
|
|
47638
|
+
const requestKey = `${type}:${date}:${shift}:${filterState.percentile}:${shouldScopeToTimeFilter ? activeTimeFilterKey : "unscoped"}`;
|
|
47639
|
+
if (inFlightPercentileClipRequestsRef.current.has(requestKey)) {
|
|
47640
|
+
return;
|
|
47641
|
+
}
|
|
47642
|
+
inFlightPercentileClipRequestsRef.current.add(requestKey);
|
|
46805
47643
|
try {
|
|
46806
47644
|
const startDate = `${date}T00:00:00Z`;
|
|
46807
47645
|
const endDate = `${date}T23:59:59Z`;
|
|
@@ -46817,7 +47655,10 @@ var FileManagerFilters = ({
|
|
|
46817
47655
|
endDate,
|
|
46818
47656
|
percentile: filterState.percentile,
|
|
46819
47657
|
shiftId: shift,
|
|
46820
|
-
limit:
|
|
47658
|
+
limit: shouldScopeToTimeFilter ? 500 : 100,
|
|
47659
|
+
startTime: shouldScopeToTimeFilter ? startTime : void 0,
|
|
47660
|
+
endTime: shouldScopeToTimeFilter ? endTime : void 0,
|
|
47661
|
+
timeFilterTimezone: shouldScopeToTimeFilter ? activeTimeFilterTimezone : void 0,
|
|
46821
47662
|
// The actual percentile action (fast-cycles, slow-cycles, idle-times)
|
|
46822
47663
|
percentileAction: type
|
|
46823
47664
|
}),
|
|
@@ -46832,7 +47673,7 @@ var FileManagerFilters = ({
|
|
|
46832
47673
|
[type]: data.clips || []
|
|
46833
47674
|
}));
|
|
46834
47675
|
setPercentileCounts((prev) => {
|
|
46835
|
-
if (typeof prev[type] === "number") {
|
|
47676
|
+
if (!shouldScopeToTimeFilter && typeof prev[type] === "number") {
|
|
46836
47677
|
return prev;
|
|
46837
47678
|
}
|
|
46838
47679
|
return {
|
|
@@ -46843,8 +47684,206 @@ var FileManagerFilters = ({
|
|
|
46843
47684
|
console.log(`[FileManager] Loaded ${data.clips?.length || 0} ${type} clips (percentile: ${filterState.percentile}%)`);
|
|
46844
47685
|
} catch (error) {
|
|
46845
47686
|
console.error(`[FileManager] Error fetching ${type} clips:`, error);
|
|
47687
|
+
} finally {
|
|
47688
|
+
inFlightPercentileClipRequestsRef.current.delete(requestKey);
|
|
47689
|
+
}
|
|
47690
|
+
}, [
|
|
47691
|
+
activeTimeFilterTimezone,
|
|
47692
|
+
activeTimeFilterKey,
|
|
47693
|
+
endTime,
|
|
47694
|
+
isCategoryScopedByTimeFilter,
|
|
47695
|
+
startTime,
|
|
47696
|
+
workspaceId,
|
|
47697
|
+
date,
|
|
47698
|
+
shift,
|
|
47699
|
+
filterState.percentile,
|
|
47700
|
+
showPercentileCycleFilters,
|
|
47701
|
+
supabase
|
|
47702
|
+
]);
|
|
47703
|
+
React125.useEffect(() => {
|
|
47704
|
+
if (!manualHourlySnapshotKey) {
|
|
47705
|
+
return;
|
|
47706
|
+
}
|
|
47707
|
+
if (manualHourlySnapshotAppliedKeyRef.current === manualHourlySnapshotKey) {
|
|
47708
|
+
return;
|
|
47709
|
+
}
|
|
47710
|
+
if (manualHourlySnapshotInFlightKeyRef.current === manualHourlySnapshotKey) {
|
|
47711
|
+
return;
|
|
47712
|
+
}
|
|
47713
|
+
manualHourlySnapshotInFlightKeyRef.current = manualHourlySnapshotKey;
|
|
47714
|
+
setManualHourlySnapshotFailureKey((prev) => prev === manualHourlySnapshotKey ? null : prev);
|
|
47715
|
+
const applyHourlySnapshot = async () => {
|
|
47716
|
+
try {
|
|
47717
|
+
const response = await fetchWithSupabaseAuth(supabase, "/api/clips/supabase", {
|
|
47718
|
+
method: "POST",
|
|
47719
|
+
headers: {
|
|
47720
|
+
"Content-Type": "application/json"
|
|
47721
|
+
},
|
|
47722
|
+
body: JSON.stringify({
|
|
47723
|
+
action: "hourly-snapshot",
|
|
47724
|
+
workspaceId,
|
|
47725
|
+
date,
|
|
47726
|
+
shift,
|
|
47727
|
+
startTime,
|
|
47728
|
+
endTime,
|
|
47729
|
+
timeFilterTimezone: activeTimeFilterTimezone
|
|
47730
|
+
}),
|
|
47731
|
+
redirectReason: "session_expired"
|
|
47732
|
+
});
|
|
47733
|
+
if (!response.ok) {
|
|
47734
|
+
throw new Error(`API error: ${response.status}`);
|
|
47735
|
+
}
|
|
47736
|
+
const snapshot = await response.json();
|
|
47737
|
+
const metadataByCategory = snapshot?.metadataByCategory && typeof snapshot.metadataByCategory === "object" ? snapshot.metadataByCategory : {};
|
|
47738
|
+
const percentileClipsByCategory = snapshot?.percentileClipsByCategory && typeof snapshot.percentileClipsByCategory === "object" ? snapshot.percentileClipsByCategory : {};
|
|
47739
|
+
const rawTotalsByCategory = snapshot?.totalsByCategory && typeof snapshot.totalsByCategory === "object" ? snapshot.totalsByCategory : {};
|
|
47740
|
+
const totalsByCategory = requiredHourlyFilterCategoryIds.reduce((accumulator, categoryId) => {
|
|
47741
|
+
const rawTotal = rawTotalsByCategory[categoryId];
|
|
47742
|
+
if (typeof rawTotal === "number" && Number.isFinite(rawTotal)) {
|
|
47743
|
+
accumulator[categoryId] = Math.max(0, rawTotal);
|
|
47744
|
+
return accumulator;
|
|
47745
|
+
}
|
|
47746
|
+
if (categoryId === "fast-cycles" || categoryId === "slow-cycles") {
|
|
47747
|
+
accumulator[categoryId] = Array.isArray(percentileClipsByCategory[categoryId]) ? percentileClipsByCategory[categoryId].length : 0;
|
|
47748
|
+
return accumulator;
|
|
47749
|
+
}
|
|
47750
|
+
accumulator[categoryId] = Array.isArray(metadataByCategory[categoryId]) ? metadataByCategory[categoryId].length : 0;
|
|
47751
|
+
return accumulator;
|
|
47752
|
+
}, {});
|
|
47753
|
+
setClipMetadata((prev) => {
|
|
47754
|
+
const next = { ...prev };
|
|
47755
|
+
requiredHourlyFilterCategoryIds.forEach((categoryId) => {
|
|
47756
|
+
if (categoryId === "fast-cycles" || categoryId === "slow-cycles") {
|
|
47757
|
+
return;
|
|
47758
|
+
}
|
|
47759
|
+
next[categoryId] = Array.isArray(metadataByCategory[categoryId]) ? metadataByCategory[categoryId] : [];
|
|
47760
|
+
});
|
|
47761
|
+
return next;
|
|
47762
|
+
});
|
|
47763
|
+
setScopedCategoryTotals((prev) => ({
|
|
47764
|
+
...prev,
|
|
47765
|
+
...totalsByCategory
|
|
47766
|
+
}));
|
|
47767
|
+
if (showPercentileCycleFilters) {
|
|
47768
|
+
setPercentileClips((prev) => ({
|
|
47769
|
+
...prev,
|
|
47770
|
+
"fast-cycles": Array.isArray(percentileClipsByCategory["fast-cycles"]) ? percentileClipsByCategory["fast-cycles"] : [],
|
|
47771
|
+
"slow-cycles": Array.isArray(percentileClipsByCategory["slow-cycles"]) ? percentileClipsByCategory["slow-cycles"] : []
|
|
47772
|
+
}));
|
|
47773
|
+
setPercentileCounts((prev) => ({
|
|
47774
|
+
...prev,
|
|
47775
|
+
"fast-cycles": totalsByCategory["fast-cycles"] ?? 0,
|
|
47776
|
+
"slow-cycles": totalsByCategory["slow-cycles"] ?? 0
|
|
47777
|
+
}));
|
|
47778
|
+
}
|
|
47779
|
+
setCategoryPages((prev) => {
|
|
47780
|
+
const next = { ...prev };
|
|
47781
|
+
requiredHourlyFilterCategoryIds.forEach((categoryId) => {
|
|
47782
|
+
next[categoryId] = 1;
|
|
47783
|
+
});
|
|
47784
|
+
return next;
|
|
47785
|
+
});
|
|
47786
|
+
setCategoryHasMore((prev) => {
|
|
47787
|
+
const next = { ...prev };
|
|
47788
|
+
requiredHourlyFilterCategoryIds.forEach((categoryId) => {
|
|
47789
|
+
next[categoryId] = false;
|
|
47790
|
+
});
|
|
47791
|
+
return next;
|
|
47792
|
+
});
|
|
47793
|
+
const idleClips = metadataByCategory.idle_time;
|
|
47794
|
+
if (Array.isArray(idleClips) && idleClips.length > 0) {
|
|
47795
|
+
await seedIdleClassifications(idleClips);
|
|
47796
|
+
}
|
|
47797
|
+
manualHourlySnapshotAppliedKeyRef.current = manualHourlySnapshotKey;
|
|
47798
|
+
setManualHourlySnapshotFailureKey((prev) => prev === manualHourlySnapshotKey ? null : prev);
|
|
47799
|
+
} catch (error) {
|
|
47800
|
+
console.error("[FileManager] Error fetching manual hourly snapshot:", error);
|
|
47801
|
+
setManualHourlySnapshotFailureKey(manualHourlySnapshotKey);
|
|
47802
|
+
} finally {
|
|
47803
|
+
if (manualHourlySnapshotInFlightKeyRef.current === manualHourlySnapshotKey) {
|
|
47804
|
+
manualHourlySnapshotInFlightKeyRef.current = null;
|
|
47805
|
+
}
|
|
47806
|
+
}
|
|
47807
|
+
};
|
|
47808
|
+
void applyHourlySnapshot();
|
|
47809
|
+
}, [
|
|
47810
|
+
activeTimeFilterTimezone,
|
|
47811
|
+
date,
|
|
47812
|
+
endTime,
|
|
47813
|
+
manualHourlySnapshotKey,
|
|
47814
|
+
requiredHourlyFilterCategoryIds,
|
|
47815
|
+
seedIdleClassifications,
|
|
47816
|
+
shift,
|
|
47817
|
+
showPercentileCycleFilters,
|
|
47818
|
+
startTime,
|
|
47819
|
+
supabase,
|
|
47820
|
+
workspaceId
|
|
47821
|
+
]);
|
|
47822
|
+
React125.useEffect(() => {
|
|
47823
|
+
if (!startTime || !endTime || !activeInitialTimeFilter || initialTimeFilterCategoryIds.length === 0) {
|
|
47824
|
+
return;
|
|
46846
47825
|
}
|
|
46847
|
-
|
|
47826
|
+
initialTimeFilterCategoryIds.forEach((categoryId) => {
|
|
47827
|
+
if (categoryId === "fast-cycles" || categoryId === "slow-cycles") {
|
|
47828
|
+
const hasScopedPercentileResult = typeof percentileCounts[categoryId] === "number";
|
|
47829
|
+
if (!isCategoryExternallyManaged(categoryId) && !hasScopedPercentileResult && showPercentileCycleFilters) {
|
|
47830
|
+
fetchPercentileClips(categoryId);
|
|
47831
|
+
}
|
|
47832
|
+
return;
|
|
47833
|
+
}
|
|
47834
|
+
if (isCategoryExternallyManaged(categoryId)) {
|
|
47835
|
+
return;
|
|
47836
|
+
}
|
|
47837
|
+
if (!hasCompleteMetadataForInitialTimeFilter(categoryId)) {
|
|
47838
|
+
fetchClipMetadata(categoryId, 1);
|
|
47839
|
+
}
|
|
47840
|
+
});
|
|
47841
|
+
}, [
|
|
47842
|
+
activeInitialTimeFilter,
|
|
47843
|
+
endTime,
|
|
47844
|
+
fetchClipMetadata,
|
|
47845
|
+
fetchPercentileClips,
|
|
47846
|
+
hasCompleteMetadataForInitialTimeFilter,
|
|
47847
|
+
initialTimeFilterCategoryIds,
|
|
47848
|
+
isCategoryExternallyManaged,
|
|
47849
|
+
percentileCounts,
|
|
47850
|
+
showPercentileCycleFilters,
|
|
47851
|
+
startTime
|
|
47852
|
+
]);
|
|
47853
|
+
React125.useEffect(() => {
|
|
47854
|
+
if (!startTime || !endTime || !isTimeFilterActive || activeInitialTimeFilter) {
|
|
47855
|
+
return;
|
|
47856
|
+
}
|
|
47857
|
+
categoriesForTree.forEach((category) => {
|
|
47858
|
+
if (!shouldShowCategory(category.id) || isCategoryExternallyManaged(category.id)) {
|
|
47859
|
+
return;
|
|
47860
|
+
}
|
|
47861
|
+
if (typeof scopedCategoryTotals[category.id] !== "number") {
|
|
47862
|
+
fetchClipMetadata(category.id, 1);
|
|
47863
|
+
}
|
|
47864
|
+
});
|
|
47865
|
+
if (showPercentileCycleFilters) {
|
|
47866
|
+
if (!isCategoryExternallyManaged("fast-cycles") && typeof percentileCounts["fast-cycles"] !== "number") {
|
|
47867
|
+
fetchPercentileClips("fast-cycles");
|
|
47868
|
+
}
|
|
47869
|
+
if (!isCategoryExternallyManaged("slow-cycles") && typeof percentileCounts["slow-cycles"] !== "number") {
|
|
47870
|
+
fetchPercentileClips("slow-cycles");
|
|
47871
|
+
}
|
|
47872
|
+
}
|
|
47873
|
+
}, [
|
|
47874
|
+
activeInitialTimeFilter,
|
|
47875
|
+
categoriesForTree,
|
|
47876
|
+
endTime,
|
|
47877
|
+
fetchClipMetadata,
|
|
47878
|
+
fetchPercentileClips,
|
|
47879
|
+
isCategoryExternallyManaged,
|
|
47880
|
+
isTimeFilterActive,
|
|
47881
|
+
percentileCounts,
|
|
47882
|
+
scopedCategoryTotals,
|
|
47883
|
+
shouldShowCategory,
|
|
47884
|
+
showPercentileCycleFilters,
|
|
47885
|
+
startTime
|
|
47886
|
+
]);
|
|
46848
47887
|
const percentileCountsKey = React125.useMemo(() => {
|
|
46849
47888
|
if (!workspaceId || !date || shift === void 0) {
|
|
46850
47889
|
return null;
|
|
@@ -46867,12 +47906,15 @@ var FileManagerFilters = ({
|
|
|
46867
47906
|
}
|
|
46868
47907
|
percentileCountsKeyRef.current = percentileCountsKey;
|
|
46869
47908
|
percentilePrefetchRef.current = { key: null, types: /* @__PURE__ */ new Set() };
|
|
47909
|
+
if (prefetchedPercentileClips && (Array.isArray(prefetchedPercentileClips["fast-cycles"]) || Array.isArray(prefetchedPercentileClips["slow-cycles"]))) {
|
|
47910
|
+
return;
|
|
47911
|
+
}
|
|
46870
47912
|
setPercentileCounts({
|
|
46871
47913
|
"fast-cycles": null,
|
|
46872
47914
|
"slow-cycles": null
|
|
46873
47915
|
});
|
|
46874
47916
|
setPercentileClips({});
|
|
46875
|
-
}, [showPercentileCycleFilters, percentileCountsKey]);
|
|
47917
|
+
}, [prefetchedPercentileClips, showPercentileCycleFilters, percentileCountsKey]);
|
|
46876
47918
|
React125.useEffect(() => {
|
|
46877
47919
|
if (!showPercentileCycleFilters) {
|
|
46878
47920
|
return;
|
|
@@ -46928,11 +47970,20 @@ var FileManagerFilters = ({
|
|
|
46928
47970
|
const data = await response.json();
|
|
46929
47971
|
const fastCycles = data?.counts?.["fast-cycles"];
|
|
46930
47972
|
const slowCycles = data?.counts?.["slow-cycles"];
|
|
46931
|
-
|
|
46932
|
-
|
|
46933
|
-
|
|
46934
|
-
|
|
46935
|
-
|
|
47973
|
+
if (typeof fastCycles === "number" || typeof slowCycles === "number") {
|
|
47974
|
+
setPercentileCounts((prev) => {
|
|
47975
|
+
const nextFastCycles = typeof fastCycles === "number" ? fastCycles : prev["fast-cycles"];
|
|
47976
|
+
const nextSlowCycles = typeof slowCycles === "number" ? slowCycles : prev["slow-cycles"];
|
|
47977
|
+
if (prev["fast-cycles"] === nextFastCycles && prev["slow-cycles"] === nextSlowCycles) {
|
|
47978
|
+
return prev;
|
|
47979
|
+
}
|
|
47980
|
+
return {
|
|
47981
|
+
...prev,
|
|
47982
|
+
"fast-cycles": nextFastCycles,
|
|
47983
|
+
"slow-cycles": nextSlowCycles
|
|
47984
|
+
};
|
|
47985
|
+
});
|
|
47986
|
+
}
|
|
46936
47987
|
if (options?.prefetchClips) {
|
|
46937
47988
|
if (percentilePrefetchRef.current.key !== requestKey) {
|
|
46938
47989
|
percentilePrefetchRef.current = { key: requestKey, types: /* @__PURE__ */ new Set() };
|
|
@@ -46951,37 +48002,30 @@ var FileManagerFilters = ({
|
|
|
46951
48002
|
}
|
|
46952
48003
|
}, [workspaceId, date, shift, filterState.percentile, showPercentileCycleFilters, supabase, percentileCounts, percentileClips, fetchPercentileClips]);
|
|
46953
48004
|
React125.useEffect(() => {
|
|
46954
|
-
if (!showPercentileCycleFilters || !isReady || !percentileCountsKey) {
|
|
48005
|
+
if (!showPercentileCycleFilters || !isReady || !percentileCountsKey || isTimeFilterActive) {
|
|
46955
48006
|
return;
|
|
46956
48007
|
}
|
|
46957
|
-
|
|
46958
|
-
|
|
46959
|
-
|
|
46960
|
-
if (
|
|
46961
|
-
|
|
46962
|
-
} else {
|
|
46963
|
-
setTimeout(schedule, 0);
|
|
46964
|
-
}
|
|
46965
|
-
}, [showPercentileCycleFilters, isReady, percentileCountsKey, fetchPercentileCounts]);
|
|
46966
|
-
const shouldShowCategory = React125.useCallback((categoryId) => {
|
|
46967
|
-
switch (categoryId) {
|
|
46968
|
-
case "fast-cycles":
|
|
46969
|
-
return showPercentileCycleFilters && filterState.showFastCycles;
|
|
46970
|
-
case "slow-cycles":
|
|
46971
|
-
return showPercentileCycleFilters && filterState.showSlowCycles;
|
|
46972
|
-
case "longest-idles":
|
|
46973
|
-
return false;
|
|
46974
|
-
// filterState.showLongestIdles; // Temporarily disabled
|
|
46975
|
-
case "cycle_completion":
|
|
46976
|
-
return filterState.showCycleCompletion;
|
|
46977
|
-
case "idle_time":
|
|
46978
|
-
return filterState.showIdleTime;
|
|
46979
|
-
case "sop_deviations":
|
|
46980
|
-
return filterState.showSopDeviations;
|
|
46981
|
-
default:
|
|
46982
|
-
return true;
|
|
48008
|
+
fetchPercentileCounts({ prefetchClips: true });
|
|
48009
|
+
}, [showPercentileCycleFilters, isReady, percentileCountsKey, fetchPercentileCounts, isTimeFilterActive]);
|
|
48010
|
+
React125.useEffect(() => {
|
|
48011
|
+
if (!isReady || isTimeFilterActive || activeFilter !== RECENT_FLOW_RED_STREAK_CLIP_TYPE2) {
|
|
48012
|
+
return;
|
|
46983
48013
|
}
|
|
46984
|
-
|
|
48014
|
+
["cycle_completion", "idle_time"].forEach((categoryId) => {
|
|
48015
|
+
if ((counts?.[categoryId] || 0) <= 0 || hasKnownClipMetadata(categoryId) || isCategoryExternallyManaged(categoryId)) {
|
|
48016
|
+
return;
|
|
48017
|
+
}
|
|
48018
|
+
fetchClipMetadata(categoryId, 1);
|
|
48019
|
+
});
|
|
48020
|
+
}, [
|
|
48021
|
+
activeFilter,
|
|
48022
|
+
counts,
|
|
48023
|
+
fetchClipMetadata,
|
|
48024
|
+
hasKnownClipMetadata,
|
|
48025
|
+
isCategoryExternallyManaged,
|
|
48026
|
+
isReady,
|
|
48027
|
+
isTimeFilterActive
|
|
48028
|
+
]);
|
|
46985
48029
|
const getPercentileIcon = React125.useCallback((type, isExpanded, colorClasses) => {
|
|
46986
48030
|
const iconMap = {
|
|
46987
48031
|
"fast-cycles": { icon: lucideReact.TrendingUp, color: "text-green-600" },
|
|
@@ -47010,12 +48054,29 @@ var FileManagerFilters = ({
|
|
|
47010
48054
|
newExpanded.add(activeFilter);
|
|
47011
48055
|
return newExpanded;
|
|
47012
48056
|
});
|
|
47013
|
-
const category =
|
|
47014
|
-
if (category
|
|
47015
|
-
|
|
48057
|
+
const category = categoriesForTree.find((cat) => cat.id === activeFilter);
|
|
48058
|
+
if (category) {
|
|
48059
|
+
if (isInitialTimeFilterCategory(activeFilter) && !isCategoryExternallyManaged(activeFilter) && !hasCompleteMetadataForInitialTimeFilter(activeFilter)) {
|
|
48060
|
+
fetchClipMetadata(activeFilter, 1);
|
|
48061
|
+
} else if (!isCategoryExternallyManaged(activeFilter) && !clipMetadataRef.current[activeFilter]) {
|
|
48062
|
+
fetchClipMetadata(activeFilter, 1);
|
|
48063
|
+
}
|
|
47016
48064
|
}
|
|
47017
48065
|
}
|
|
47018
48066
|
}, [activeFilter]);
|
|
48067
|
+
React125.useEffect(() => {
|
|
48068
|
+
const requestedCategory = activeFilter;
|
|
48069
|
+
if (!requestedCategory || !isInitialTimeFilterCategory(requestedCategory) || isCategoryExternallyManaged(requestedCategory) || hasCompleteMetadataForInitialTimeFilter(requestedCategory)) {
|
|
48070
|
+
return;
|
|
48071
|
+
}
|
|
48072
|
+
fetchClipMetadata(requestedCategory, 1);
|
|
48073
|
+
}, [
|
|
48074
|
+
activeFilter,
|
|
48075
|
+
fetchClipMetadata,
|
|
48076
|
+
hasCompleteMetadataForInitialTimeFilter,
|
|
48077
|
+
isCategoryExternallyManaged,
|
|
48078
|
+
isInitialTimeFilterCategory
|
|
48079
|
+
]);
|
|
47019
48080
|
React125.useEffect(() => {
|
|
47020
48081
|
const handleEscape = (e) => {
|
|
47021
48082
|
if (e.key === "Escape") {
|
|
@@ -47079,25 +48140,34 @@ var FileManagerFilters = ({
|
|
|
47079
48140
|
}
|
|
47080
48141
|
try {
|
|
47081
48142
|
const clipDate = new Date(clipTimestamp);
|
|
47082
|
-
const
|
|
48143
|
+
const clipParts = new Intl.DateTimeFormat("en-US", {
|
|
47083
48144
|
hour12: false,
|
|
47084
48145
|
hour: "2-digit",
|
|
47085
48146
|
minute: "2-digit",
|
|
47086
|
-
timeZone:
|
|
47087
|
-
});
|
|
47088
|
-
|
|
48147
|
+
timeZone: activeTimeFilterTimezone
|
|
48148
|
+
}).formatToParts(clipDate);
|
|
48149
|
+
const hourValue = clipParts.find((part) => part.type === "hour")?.value;
|
|
48150
|
+
const minuteValue = clipParts.find((part) => part.type === "minute")?.value;
|
|
48151
|
+
const clipMinute = timeValueToMinutes(`${hourValue}:${minuteValue}`);
|
|
48152
|
+
return clipMinute === null ? false : isMinuteInTimeWindow(clipMinute, startTime, endTime);
|
|
47089
48153
|
} catch (error) {
|
|
47090
48154
|
console.error("[FileManager] Error parsing clip timestamp:", error);
|
|
47091
48155
|
return true;
|
|
47092
48156
|
}
|
|
47093
|
-
}, [isTimeFilterActive, startTime, endTime,
|
|
48157
|
+
}, [isTimeFilterActive, startTime, endTime, activeTimeFilterTimezone]);
|
|
47094
48158
|
const filterTree = React125.useMemo(() => {
|
|
47095
48159
|
const tree = [];
|
|
47096
48160
|
const regularCategoryNodes = [];
|
|
47097
|
-
|
|
48161
|
+
categoriesForTree.forEach((category) => {
|
|
48162
|
+
if (category.id === "fast-cycles" || category.id === "slow-cycles") {
|
|
48163
|
+
return;
|
|
48164
|
+
}
|
|
47098
48165
|
const categoryCount = counts?.[category.id] || 0;
|
|
47099
|
-
const
|
|
47100
|
-
|
|
48166
|
+
const categoryMetadataClips = getAvailableClipMetadata(category.id);
|
|
48167
|
+
const categoryVideoFallbackClips = categoryMetadataClips.length === 0 && isInitialTimeFilterCategory(category.id) ? videos.filter((video) => video.type === category.id).map(buildClipMetadataFromVideo).filter((clip) => isClipInTimeRange(clip.clip_timestamp)) : [];
|
|
48168
|
+
const categoryClips = categoryMetadataClips.length > 0 ? categoryMetadataClips : categoryVideoFallbackClips;
|
|
48169
|
+
const timeFilteredClips = categoryClips.filter((clip) => isClipInTimeRange(clip.clip_timestamp));
|
|
48170
|
+
let filteredClips = timeFilteredClips;
|
|
47101
48171
|
if (category.id === RECENT_FLOW_RED_STREAK_CLIP_TYPE2) {
|
|
47102
48172
|
filteredClips = sortRedFlowMetadata(filteredClips);
|
|
47103
48173
|
}
|
|
@@ -47107,9 +48177,22 @@ var FileManagerFilters = ({
|
|
|
47107
48177
|
return classification?.label === idleLabelFilter;
|
|
47108
48178
|
});
|
|
47109
48179
|
}
|
|
47110
|
-
const
|
|
48180
|
+
const scopedTotal = typeof scopedCategoryTotals[category.id] === "number" ? scopedCategoryTotals[category.id] : null;
|
|
48181
|
+
const isScopedByTimeFilter = isCategoryScopedByTimeFilter(category.id);
|
|
48182
|
+
const scopedPageLoaded = isScopedByTimeFilter && typeof scopedCategoryTotals[category.id] === "number";
|
|
48183
|
+
const scopedResponseHadOutOfHourClips = categoryClips.length > filteredClips.length;
|
|
48184
|
+
const shouldTrustScopedTotal = !scopedResponseHadOutOfHourClips || Boolean(categoryHasMore[category.id]);
|
|
48185
|
+
const isCategoryMetadataLoading = Array.from(loadingCategories).some((key) => key.startsWith(`${category.id}-`));
|
|
48186
|
+
const isScopedTotalPending = isTimeFilterActive && isScopedByTimeFilter && scopedTotal === null;
|
|
48187
|
+
const displayCount = isScopedTotalPending ? null : isTimeFilterActive && isScopedByTimeFilter && scopedTotal !== null ? shouldTrustScopedTotal ? scopedTotal : filteredClips.length : isTimeFilterActive || category.id === "idle_time" && idleLabelFilter ? filteredClips.length : categoryCount;
|
|
48188
|
+
const shouldShowScopedEmptyCategory = Boolean(
|
|
48189
|
+
scopedPageLoaded && !isCategoryMetadataLoading && !categoryHasMore[category.id] && filteredClips.length === 0 && (isRequiredHourlyFilterCategory(category.id) || activeFilter === category.id)
|
|
48190
|
+
);
|
|
48191
|
+
const shouldShowScopedLoadingCategory = Boolean(
|
|
48192
|
+
isScopedTotalPending && (isRequiredHourlyFilterCategory(category.id) || !activeInitialTimeFilter || activeFilter === category.id)
|
|
48193
|
+
);
|
|
47111
48194
|
const shouldShowEmptyIdleTime = category.id === "idle_time" && idleLabelFilter;
|
|
47112
|
-
if ((displayCount > 0 || shouldShowEmptyIdleTime) && shouldShowCategory(category.id)) {
|
|
48195
|
+
if ((typeof displayCount === "number" && displayCount > 0 || shouldShowEmptyIdleTime || isCategoryMetadataLoading || shouldShowScopedEmptyCategory || shouldShowScopedLoadingCategory) && shouldShowCategory(category.id)) {
|
|
47113
48196
|
const colorClasses = getColorClasses(category.color);
|
|
47114
48197
|
const clipNodes = filteredClips.map((clip, index) => {
|
|
47115
48198
|
const cycleTime = extractCycleTimeSeconds(clip);
|
|
@@ -47119,7 +48202,7 @@ var FileManagerFilters = ({
|
|
|
47119
48202
|
const baseTimeLabel = formatClipExplorerTimeLabel({
|
|
47120
48203
|
categoryId: category.id,
|
|
47121
48204
|
clipTimestamp: clip.clip_timestamp,
|
|
47122
|
-
timezone,
|
|
48205
|
+
timezone: activeTimeFilterTimezone,
|
|
47123
48206
|
durationSeconds: idleDuration ?? clip.duration,
|
|
47124
48207
|
idleStartTime: clip.idle_start_time,
|
|
47125
48208
|
idleEndTime: clip.idle_end_time,
|
|
@@ -47157,6 +48240,7 @@ var FileManagerFilters = ({
|
|
|
47157
48240
|
type: "category",
|
|
47158
48241
|
count: displayCount,
|
|
47159
48242
|
// Use filtered count when time filter is active
|
|
48243
|
+
countLoading: isScopedTotalPending || isCategoryMetadataLoading && scopedTotal === null,
|
|
47160
48244
|
children: clipNodes,
|
|
47161
48245
|
// Use clip nodes from metadata
|
|
47162
48246
|
icon: expandedNodes.has(category.id) ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FolderOpen, { className: `h-4 w-4 ${colorClasses.text}` }) : getCategoryIcon(category.icon, colorClasses),
|
|
@@ -47164,10 +48248,18 @@ var FileManagerFilters = ({
|
|
|
47164
48248
|
});
|
|
47165
48249
|
}
|
|
47166
48250
|
});
|
|
47167
|
-
const filteredFastCycles = (
|
|
47168
|
-
|
|
48251
|
+
const filteredFastCycles = sortPercentileCycleClipsForDisplay(
|
|
48252
|
+
"fast-cycles",
|
|
48253
|
+
(percentileClips["fast-cycles"] || []).filter((clip) => isClipInTimeRange(clip.creation_timestamp || ""))
|
|
48254
|
+
);
|
|
48255
|
+
const filteredSlowCycles = sortPercentileCycleClipsForDisplay(
|
|
48256
|
+
"slow-cycles",
|
|
48257
|
+
(percentileClips["slow-cycles"] || []).filter((clip) => isClipInTimeRange(clip.creation_timestamp || ""))
|
|
48258
|
+
);
|
|
47169
48259
|
const fastCount = typeof percentileCounts["fast-cycles"] === "number" ? percentileCounts["fast-cycles"] : null;
|
|
47170
48260
|
const slowCount = typeof percentileCounts["slow-cycles"] === "number" ? percentileCounts["slow-cycles"] : null;
|
|
48261
|
+
const isFastCountPending = showPercentileCycleFilters && fastCount === null;
|
|
48262
|
+
const isSlowCountPending = showPercentileCycleFilters && slowCount === null;
|
|
47171
48263
|
const percentileCategories = showPercentileCycleFilters ? [
|
|
47172
48264
|
{
|
|
47173
48265
|
id: "fast-cycles",
|
|
@@ -47176,6 +48268,7 @@ var FileManagerFilters = ({
|
|
|
47176
48268
|
description: "Top 10% fastest performance",
|
|
47177
48269
|
type: "percentile-category",
|
|
47178
48270
|
count: isTimeFilterActive ? fastCount === null && filteredFastCycles.length === 0 ? null : filteredFastCycles.length : fastCount,
|
|
48271
|
+
countLoading: isFastCountPending,
|
|
47179
48272
|
icon: getPercentileIcon("fast-cycles", expandedNodes.has("fast-cycles"), { text: "text-green-600" }),
|
|
47180
48273
|
color: "green",
|
|
47181
48274
|
percentileType: "fast-cycles",
|
|
@@ -47187,7 +48280,7 @@ var FileManagerFilters = ({
|
|
|
47187
48280
|
label: `${formatClipExplorerTimeLabel({
|
|
47188
48281
|
categoryId: "fast-cycles",
|
|
47189
48282
|
clipTimestamp: clip.creation_timestamp || clip.timestamp || "",
|
|
47190
|
-
timezone,
|
|
48283
|
+
timezone: activeTimeFilterTimezone,
|
|
47191
48284
|
durationSeconds: cycleTime
|
|
47192
48285
|
})}${clip.cycle_time_seconds ? ` - (${clip.cycle_time_seconds.toFixed(1)}s)` : ""}`,
|
|
47193
48286
|
type: "video",
|
|
@@ -47207,6 +48300,7 @@ var FileManagerFilters = ({
|
|
|
47207
48300
|
description: "Bottom 10% slowest performance",
|
|
47208
48301
|
type: "percentile-category",
|
|
47209
48302
|
count: isTimeFilterActive ? slowCount === null && filteredSlowCycles.length === 0 ? null : filteredSlowCycles.length : slowCount,
|
|
48303
|
+
countLoading: isSlowCountPending,
|
|
47210
48304
|
icon: getPercentileIcon("slow-cycles", expandedNodes.has("slow-cycles"), { text: "text-red-600" }),
|
|
47211
48305
|
color: "red",
|
|
47212
48306
|
percentileType: "slow-cycles",
|
|
@@ -47218,7 +48312,7 @@ var FileManagerFilters = ({
|
|
|
47218
48312
|
label: `${formatClipExplorerTimeLabel({
|
|
47219
48313
|
categoryId: "slow-cycles",
|
|
47220
48314
|
clipTimestamp: clip.creation_timestamp || clip.timestamp || "",
|
|
47221
|
-
timezone,
|
|
48315
|
+
timezone: activeTimeFilterTimezone,
|
|
47222
48316
|
durationSeconds: cycleTime
|
|
47223
48317
|
})}${clip.cycle_time_seconds ? ` - (${clip.cycle_time_seconds.toFixed(1)}s)` : ""}`,
|
|
47224
48318
|
type: "video",
|
|
@@ -47249,7 +48343,7 @@ var FileManagerFilters = ({
|
|
|
47249
48343
|
hour12: true,
|
|
47250
48344
|
hour: 'numeric',
|
|
47251
48345
|
minute: '2-digit',
|
|
47252
|
-
timeZone:
|
|
48346
|
+
timeZone: activeTimeFilterTimezone
|
|
47253
48347
|
});
|
|
47254
48348
|
|
|
47255
48349
|
return {
|
|
@@ -47268,7 +48362,11 @@ var FileManagerFilters = ({
|
|
|
47268
48362
|
const orderedIds = [RECENT_FLOW_RED_STREAK_CLIP_TYPE2, "cycle_completion", "fast-cycles", "slow-cycles", "idle_time"];
|
|
47269
48363
|
orderedIds.forEach((orderedId) => {
|
|
47270
48364
|
const percentileCategory = percentileCategories.find((cat) => cat.id === orderedId);
|
|
47271
|
-
const shouldIncludePercentile = percentileCategory ? typeof percentileCategory.count === "number"
|
|
48365
|
+
const shouldIncludePercentile = percentileCategory ? typeof percentileCategory.count === "number" || Boolean(
|
|
48366
|
+
isTimeFilterActive && isRequiredHourlyFilterCategory(orderedId) && typeof percentileCategory.count === "number" && percentileCategory.count === 0
|
|
48367
|
+
) || Boolean(
|
|
48368
|
+
percentileCategory.countLoading && (isRequiredHourlyFilterCategory(orderedId) || !activeInitialTimeFilter || activeFilter === orderedId)
|
|
48369
|
+
) : false;
|
|
47272
48370
|
if (percentileCategory && shouldIncludePercentile && shouldShowCategory(orderedId)) {
|
|
47273
48371
|
tree.push(percentileCategory);
|
|
47274
48372
|
}
|
|
@@ -47283,23 +48381,263 @@ var FileManagerFilters = ({
|
|
|
47283
48381
|
}
|
|
47284
48382
|
});
|
|
47285
48383
|
percentileCategories.forEach((category) => {
|
|
47286
|
-
const shouldIncludePercentile = typeof category.count === "number"
|
|
48384
|
+
const shouldIncludePercentile = typeof category.count === "number" || Boolean(
|
|
48385
|
+
isTimeFilterActive && isRequiredHourlyFilterCategory(category.id) && typeof category.count === "number" && category.count === 0
|
|
48386
|
+
) || Boolean(
|
|
48387
|
+
category.countLoading && (isRequiredHourlyFilterCategory(category.id) || !activeInitialTimeFilter || activeFilter === category.id)
|
|
48388
|
+
);
|
|
47287
48389
|
if (!orderedIds.includes(category.id) && shouldIncludePercentile && shouldShowCategory(category.id)) {
|
|
47288
48390
|
tree.push(category);
|
|
47289
48391
|
}
|
|
47290
48392
|
});
|
|
47291
48393
|
return tree;
|
|
47292
|
-
}, [
|
|
48394
|
+
}, [categoriesForTree, expandedNodes, counts, getAvailableClipMetadata, percentileCounts, percentileClips, shouldShowCategory, getPercentileIcon, isClipInTimeRange, isTimeFilterActive, showPercentileCycleFilters, loadingCategories, activeTimeFilterTimezone, isInitialTimeFilterCategory, isRequiredHourlyFilterCategory, hasCompleteMetadataForInitialTimeFilter, scopedCategoryTotals, isCategoryScopedByTimeFilter, categoryHasMore, activeFilter]);
|
|
48395
|
+
const chartHandoffVideoFallbackTree = React125.useMemo(() => {
|
|
48396
|
+
if (!startTime || !endTime || !activeInitialTimeFilter || !activeFilter) {
|
|
48397
|
+
return [];
|
|
48398
|
+
}
|
|
48399
|
+
const fallbackCategory = categoriesForTree.find((category) => category.id === activeFilter) || categoriesForTree.find((category) => videos.some((video) => video.type === category.id));
|
|
48400
|
+
if (!fallbackCategory) {
|
|
48401
|
+
return [];
|
|
48402
|
+
}
|
|
48403
|
+
const fallbackVideos = videos.filter((video) => video.type === fallbackCategory.id);
|
|
48404
|
+
const sourceVideos = fallbackVideos.map(buildClipMetadataFromVideo).filter((clip) => isClipInTimeRange(clip.clip_timestamp));
|
|
48405
|
+
if (sourceVideos.length === 0) {
|
|
48406
|
+
return [];
|
|
48407
|
+
}
|
|
48408
|
+
const colorClasses = getColorClasses(fallbackCategory.color);
|
|
48409
|
+
const clipNodes = sourceVideos.map((clip, index) => {
|
|
48410
|
+
const cycleTime = extractCycleTimeSeconds(clip);
|
|
48411
|
+
const baseTimeLabel = formatClipExplorerTimeLabel({
|
|
48412
|
+
categoryId: fallbackCategory.id,
|
|
48413
|
+
clipTimestamp: clip.clip_timestamp,
|
|
48414
|
+
timezone: activeTimeFilterTimezone,
|
|
48415
|
+
durationSeconds: clip.duration,
|
|
48416
|
+
idleStartTime: clip.idle_start_time,
|
|
48417
|
+
idleEndTime: clip.idle_end_time,
|
|
48418
|
+
clipStartTime: clip.clip_start_time,
|
|
48419
|
+
clipEndTime: clip.clip_end_time
|
|
48420
|
+
});
|
|
48421
|
+
const displayLabel = `${baseTimeLabel}${clip.duration && fallbackCategory.id !== "idle_time" && fallbackCategory.id !== "low_value" && fallbackCategory.id !== RECENT_FLOW_RED_STREAK_CLIP_TYPE2 ? ` - (${clip.duration.toFixed(1)}s)` : ""}`;
|
|
48422
|
+
return {
|
|
48423
|
+
id: clip.id,
|
|
48424
|
+
label: displayLabel,
|
|
48425
|
+
type: "video",
|
|
48426
|
+
icon: getSeverityIcon(clip.severity, fallbackCategory.id, cycleTime, resolvedTargetCycleTime, clip.clipId),
|
|
48427
|
+
timestamp: clip.clip_timestamp,
|
|
48428
|
+
severity: clip.severity,
|
|
48429
|
+
clipId: clip.clipId,
|
|
48430
|
+
categoryId: fallbackCategory.id,
|
|
48431
|
+
clipPosition: index + 1,
|
|
48432
|
+
cycleTimeSeconds: cycleTime,
|
|
48433
|
+
duration: clip.duration,
|
|
48434
|
+
cycleItemCount: null,
|
|
48435
|
+
redFlowSeverityScore: clip.red_flow_severity_score ?? null,
|
|
48436
|
+
redFlowExplanationSummary: clip.red_flow_explanation_summary ?? clip.red_flow_explanation?.summary ?? null
|
|
48437
|
+
};
|
|
48438
|
+
});
|
|
48439
|
+
return [{
|
|
48440
|
+
id: activeFilter,
|
|
48441
|
+
label: fallbackCategory.id === RECENT_FLOW_RED_STREAK_CLIP_TYPE2 ? RECENT_FLOW_RED_STREAK_DISPLAY_LABEL : fallbackCategory.label,
|
|
48442
|
+
subtitle: fallbackCategory.subtitle || fallbackCategory.description,
|
|
48443
|
+
description: fallbackCategory.description,
|
|
48444
|
+
type: "category",
|
|
48445
|
+
count: clipNodes.length,
|
|
48446
|
+
children: clipNodes,
|
|
48447
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FolderOpen, { className: `h-4 w-4 ${colorClasses.text}` }),
|
|
48448
|
+
color: fallbackCategory.color
|
|
48449
|
+
}];
|
|
48450
|
+
}, [
|
|
48451
|
+
activeFilter,
|
|
48452
|
+
activeInitialTimeFilter,
|
|
48453
|
+
activeTimeFilterTimezone,
|
|
48454
|
+
categoriesForTree,
|
|
48455
|
+
counts,
|
|
48456
|
+
currentVideoId,
|
|
48457
|
+
endTime,
|
|
48458
|
+
getDisplayValue,
|
|
48459
|
+
isClipInTimeRange,
|
|
48460
|
+
resolvedTargetCycleTime,
|
|
48461
|
+
startTime,
|
|
48462
|
+
videos
|
|
48463
|
+
]);
|
|
48464
|
+
const displayedFilterTree = React125.useMemo(() => {
|
|
48465
|
+
if (chartHandoffVideoFallbackTree.length === 0) {
|
|
48466
|
+
return filterTree;
|
|
48467
|
+
}
|
|
48468
|
+
if (filterTree.length === 0) {
|
|
48469
|
+
return chartHandoffVideoFallbackTree;
|
|
48470
|
+
}
|
|
48471
|
+
const fallbackNode = chartHandoffVideoFallbackTree[0];
|
|
48472
|
+
const activeNode = filterTree.find((node) => node.id === activeFilter);
|
|
48473
|
+
const activeNodeHasChildren = (activeNode?.children?.length || 0) > 0;
|
|
48474
|
+
const shouldReplaceActiveNode = Boolean(
|
|
48475
|
+
activeFilter && fallbackNode && activeNode && !activeNodeHasChildren && isInitialTimeFilterCategory(activeFilter)
|
|
48476
|
+
);
|
|
48477
|
+
if (!shouldReplaceActiveNode) {
|
|
48478
|
+
return filterTree;
|
|
48479
|
+
}
|
|
48480
|
+
return filterTree.map((node) => node.id === activeFilter ? fallbackNode : node);
|
|
48481
|
+
}, [activeFilter, chartHandoffVideoFallbackTree, filterTree, isInitialTimeFilterCategory]);
|
|
48482
|
+
const getSelectionContextForNodes = React125.useCallback((categoryId, clipNodes) => {
|
|
48483
|
+
const normalizeSeverity = (severity) => severity === "low" || severity === "medium" || severity === "high" ? severity : "medium";
|
|
48484
|
+
const scopedNodes = clipNodes.filter((node) => node.type === "video" && Boolean(node.clipId || node.id));
|
|
48485
|
+
const scopedNodeClips = scopedNodes.map((node, index) => ({
|
|
48486
|
+
id: node.clipId || node.id,
|
|
48487
|
+
clipId: node.clipId || node.id,
|
|
48488
|
+
clip_timestamp: node.timestamp || "",
|
|
48489
|
+
creation_timestamp: node.timestamp || "",
|
|
48490
|
+
description: node.label,
|
|
48491
|
+
severity: normalizeSeverity(node.severity),
|
|
48492
|
+
category: categoryId,
|
|
48493
|
+
duration: node.duration,
|
|
48494
|
+
cycle_time_seconds: node.cycleTimeSeconds,
|
|
48495
|
+
index
|
|
48496
|
+
}));
|
|
48497
|
+
const categoryClips = getAvailableClipMetadata(categoryId);
|
|
48498
|
+
const contextClips = isCategoryScopedByTimeFilter(categoryId) && scopedNodeClips.length > 0 ? scopedNodeClips : categoryClips.length > 0 ? categoryClips : scopedNodeClips;
|
|
48499
|
+
const scopedTotal = scopedCategoryTotals[categoryId];
|
|
48500
|
+
const total = typeof scopedTotal === "number" ? scopedTotal : counts?.[categoryId];
|
|
48501
|
+
return contextClips.length ? { clips: contextClips, total } : void 0;
|
|
48502
|
+
}, [counts, getAvailableClipMetadata, isCategoryScopedByTimeFilter, scopedCategoryTotals]);
|
|
48503
|
+
React125.useEffect(() => {
|
|
48504
|
+
if (!activeInitialTimeFilter || !startTime || !endTime || currentVideoId || !onClipSelect) {
|
|
48505
|
+
return;
|
|
48506
|
+
}
|
|
48507
|
+
const categoryPriority = Array.from(new Set([
|
|
48508
|
+
activeInitialTimeFilter.categoryId,
|
|
48509
|
+
activeFilter,
|
|
48510
|
+
...activeInitialTimeFilter.categoryIds || []
|
|
48511
|
+
].filter((value) => typeof value === "string" && value.length > 0)));
|
|
48512
|
+
const preferredCategoryId = categoryPriority[0];
|
|
48513
|
+
const orderedCategoryNodes = displayedFilterTree.filter((categoryNode) => isInitialTimeFilterCategory(categoryNode.id)).sort((left, right) => {
|
|
48514
|
+
const leftIndex = categoryPriority.indexOf(left.id);
|
|
48515
|
+
const rightIndex = categoryPriority.indexOf(right.id);
|
|
48516
|
+
const leftPriority = leftIndex === -1 ? Number.MAX_SAFE_INTEGER : leftIndex;
|
|
48517
|
+
const rightPriority = rightIndex === -1 ? Number.MAX_SAFE_INTEGER : rightIndex;
|
|
48518
|
+
return leftPriority - rightPriority;
|
|
48519
|
+
});
|
|
48520
|
+
const preferredCategoryNode = preferredCategoryId ? orderedCategoryNodes.find((categoryNode) => categoryNode.id === preferredCategoryId) : void 0;
|
|
48521
|
+
if (preferredCategoryId && !preferredCategoryNode) {
|
|
48522
|
+
const preferredKnownTotal = preferredCategoryId === "fast-cycles" || preferredCategoryId === "slow-cycles" ? percentileCounts[preferredCategoryId] : scopedCategoryTotals[preferredCategoryId];
|
|
48523
|
+
if (preferredKnownTotal !== 0) {
|
|
48524
|
+
return;
|
|
48525
|
+
}
|
|
48526
|
+
}
|
|
48527
|
+
const preferredFirstClipNode = preferredCategoryNode?.children?.find((child) => child.type === "video" && Boolean(child.clipId) && Boolean(child.categoryId));
|
|
48528
|
+
if (preferredCategoryId && preferredCategoryNode && !preferredFirstClipNode) {
|
|
48529
|
+
const preferredKnownTotal = preferredCategoryId === "fast-cycles" || preferredCategoryId === "slow-cycles" ? percentileCounts[preferredCategoryId] : scopedCategoryTotals[preferredCategoryId];
|
|
48530
|
+
if (preferredKnownTotal !== 0) {
|
|
48531
|
+
return;
|
|
48532
|
+
}
|
|
48533
|
+
}
|
|
48534
|
+
for (const categoryNode of orderedCategoryNodes) {
|
|
48535
|
+
const firstClipNode = categoryNode.children?.find((child) => child.type === "video" && Boolean(child.clipId) && Boolean(child.categoryId));
|
|
48536
|
+
if (!firstClipNode?.clipId || !firstClipNode.categoryId) {
|
|
48537
|
+
continue;
|
|
48538
|
+
}
|
|
48539
|
+
const selectionKey = `${activeTimeFilterKey}:${firstClipNode.categoryId}:${firstClipNode.clipId}:${currentVideoId || "none"}`;
|
|
48540
|
+
if (autoSelectedScopedClipRef.current === selectionKey) {
|
|
48541
|
+
return;
|
|
48542
|
+
}
|
|
48543
|
+
autoSelectedScopedClipRef.current = selectionKey;
|
|
48544
|
+
const selectionContext = getSelectionContextForNodes(firstClipNode.categoryId, categoryNode.children || []);
|
|
48545
|
+
onClipSelect(
|
|
48546
|
+
firstClipNode.categoryId,
|
|
48547
|
+
firstClipNode.clipId,
|
|
48548
|
+
firstClipNode.clipPosition,
|
|
48549
|
+
selectionContext
|
|
48550
|
+
);
|
|
48551
|
+
return;
|
|
48552
|
+
}
|
|
48553
|
+
}, [
|
|
48554
|
+
activeInitialTimeFilter,
|
|
48555
|
+
activeFilter,
|
|
48556
|
+
activeTimeFilterKey,
|
|
48557
|
+
currentVideoId,
|
|
48558
|
+
displayedFilterTree,
|
|
48559
|
+
endTime,
|
|
48560
|
+
getSelectionContextForNodes,
|
|
48561
|
+
isInitialTimeFilterCategory,
|
|
48562
|
+
onClipSelect,
|
|
48563
|
+
percentileCounts,
|
|
48564
|
+
scopedCategoryTotals,
|
|
48565
|
+
startTime
|
|
48566
|
+
]);
|
|
48567
|
+
const isChartHandoffLoading = React125.useMemo(() => {
|
|
48568
|
+
if (!startTime || !endTime || !activeInitialTimeFilter || !activeFilter || !isInitialTimeFilterCategory(activeFilter)) {
|
|
48569
|
+
return false;
|
|
48570
|
+
}
|
|
48571
|
+
const pageOneLoadingKey = getMetadataLoadingKey(activeFilter, 1);
|
|
48572
|
+
return Boolean(
|
|
48573
|
+
activeCategoryLoading || Array.from(loadingCategories).some((key) => key === pageOneLoadingKey || key.startsWith(`${pageOneLoadingKey}-all`))
|
|
48574
|
+
);
|
|
48575
|
+
}, [
|
|
48576
|
+
activeCategoryLoading,
|
|
48577
|
+
activeFilter,
|
|
48578
|
+
activeInitialTimeFilter,
|
|
48579
|
+
endTime,
|
|
48580
|
+
getMetadataLoadingKey,
|
|
48581
|
+
isInitialTimeFilterCategory,
|
|
48582
|
+
loadingCategories,
|
|
48583
|
+
startTime
|
|
48584
|
+
]);
|
|
48585
|
+
React125.useEffect(() => {
|
|
48586
|
+
if (!isTimeFilterActive || !startTime || !endTime || !activeFilter || activeFilter === "all" || !onClipSelect) {
|
|
48587
|
+
return;
|
|
48588
|
+
}
|
|
48589
|
+
const activeCategoryNode = displayedFilterTree.find((categoryNode) => categoryNode.id === activeFilter);
|
|
48590
|
+
const activeClipNodes = (activeCategoryNode?.children || []).filter((child) => child.type === "video" && Boolean(child.clipId) && Boolean(child.categoryId));
|
|
48591
|
+
if (activeClipNodes.length === 0) {
|
|
48592
|
+
return;
|
|
48593
|
+
}
|
|
48594
|
+
const currentClipIsVisible = Boolean(
|
|
48595
|
+
currentVideoId && activeClipNodes.some((child) => (child.clipId || child.id) === currentVideoId)
|
|
48596
|
+
);
|
|
48597
|
+
if (currentClipIsVisible) {
|
|
48598
|
+
return;
|
|
48599
|
+
}
|
|
48600
|
+
const firstClipNode = activeClipNodes[0];
|
|
48601
|
+
if (!firstClipNode?.clipId || !firstClipNode.categoryId) {
|
|
48602
|
+
return;
|
|
48603
|
+
}
|
|
48604
|
+
const selectionKey = `${activeTimeFilterKey}:${firstClipNode.categoryId}:${firstClipNode.clipId}:${currentVideoId || "none"}`;
|
|
48605
|
+
if (autoSelectedScopedClipRef.current === selectionKey) {
|
|
48606
|
+
return;
|
|
48607
|
+
}
|
|
48608
|
+
autoSelectedScopedClipRef.current = selectionKey;
|
|
48609
|
+
const selectionContext = getSelectionContextForNodes(firstClipNode.categoryId, activeClipNodes);
|
|
48610
|
+
onClipSelect(
|
|
48611
|
+
firstClipNode.categoryId,
|
|
48612
|
+
firstClipNode.clipId,
|
|
48613
|
+
firstClipNode.clipPosition,
|
|
48614
|
+
selectionContext
|
|
48615
|
+
);
|
|
48616
|
+
}, [
|
|
48617
|
+
activeFilter,
|
|
48618
|
+
activeTimeFilterKey,
|
|
48619
|
+
currentVideoId,
|
|
48620
|
+
displayedFilterTree,
|
|
48621
|
+
endTime,
|
|
48622
|
+
getSelectionContextForNodes,
|
|
48623
|
+
isTimeFilterActive,
|
|
48624
|
+
onClipSelect,
|
|
48625
|
+
startTime
|
|
48626
|
+
]);
|
|
47293
48627
|
const toggleExpanded = (nodeId) => {
|
|
47294
48628
|
const newExpanded = new Set(expandedNodes);
|
|
47295
48629
|
if (newExpanded.has(nodeId)) {
|
|
47296
48630
|
newExpanded.delete(nodeId);
|
|
47297
48631
|
} else {
|
|
47298
48632
|
newExpanded.add(nodeId);
|
|
47299
|
-
const category =
|
|
47300
|
-
if (category
|
|
48633
|
+
const category = categoriesForTree.find((cat) => cat.id === nodeId);
|
|
48634
|
+
if (category) {
|
|
47301
48635
|
console.log(`[FileManager] Fetching clips for expanded category: ${nodeId}`);
|
|
47302
|
-
|
|
48636
|
+
if (isInitialTimeFilterCategory(nodeId) && !hasCompleteMetadataForInitialTimeFilter(nodeId)) {
|
|
48637
|
+
fetchClipMetadata(nodeId, 1);
|
|
48638
|
+
} else if (!hasKnownClipMetadata(nodeId) && !isCategoryExternallyManaged(nodeId)) {
|
|
48639
|
+
fetchClipMetadata(nodeId, 1);
|
|
48640
|
+
}
|
|
47303
48641
|
}
|
|
47304
48642
|
if (!isCategoryExternallyManaged(nodeId) && showPercentileCycleFilters && nodeId === "fast-cycles" && (percentileClips["fast-cycles"] || []).length === 0) {
|
|
47305
48643
|
fetchPercentileClips("fast-cycles");
|
|
@@ -47317,10 +48655,14 @@ var FileManagerFilters = ({
|
|
|
47317
48655
|
newExpanded.delete(node.id);
|
|
47318
48656
|
} else {
|
|
47319
48657
|
newExpanded.add(node.id);
|
|
47320
|
-
const category =
|
|
47321
|
-
if (category
|
|
48658
|
+
const category = categoriesForTree.find((cat) => cat.id === node.id);
|
|
48659
|
+
if (category) {
|
|
47322
48660
|
console.log(`[FileManager] Fetching clips for expanded category: ${node.id}`);
|
|
47323
|
-
|
|
48661
|
+
if (isInitialTimeFilterCategory(node.id) && !hasCompleteMetadataForInitialTimeFilter(node.id)) {
|
|
48662
|
+
fetchClipMetadata(node.id, 1);
|
|
48663
|
+
} else if (!hasKnownClipMetadata(node.id) && !isCategoryExternallyManaged(node.id)) {
|
|
48664
|
+
fetchClipMetadata(node.id, 1);
|
|
48665
|
+
}
|
|
47324
48666
|
}
|
|
47325
48667
|
if (!isCategoryExternallyManaged(node.id) && showPercentileCycleFilters && node.id === "fast-cycles" && (percentileClips["fast-cycles"] || []).length === 0) {
|
|
47326
48668
|
fetchPercentileClips("fast-cycles");
|
|
@@ -47330,7 +48672,21 @@ var FileManagerFilters = ({
|
|
|
47330
48672
|
}
|
|
47331
48673
|
}
|
|
47332
48674
|
setExpandedNodes(newExpanded);
|
|
47333
|
-
|
|
48675
|
+
if (node.id !== activeFilter) {
|
|
48676
|
+
onFilterChange(node.id);
|
|
48677
|
+
}
|
|
48678
|
+
if (isCategoryScopedByTimeFilter(node.id) && onClipSelect && node.children?.length) {
|
|
48679
|
+
const firstClipNode = node.children.find((child) => child.type === "video" && Boolean(child.clipId) && Boolean(child.categoryId));
|
|
48680
|
+
if (firstClipNode?.clipId && firstClipNode.categoryId) {
|
|
48681
|
+
const selectionContext = getSelectionContextForNodes(firstClipNode.categoryId, node.children);
|
|
48682
|
+
onClipSelect(
|
|
48683
|
+
firstClipNode.categoryId,
|
|
48684
|
+
firstClipNode.clipId,
|
|
48685
|
+
firstClipNode.clipPosition,
|
|
48686
|
+
selectionContext
|
|
48687
|
+
);
|
|
48688
|
+
}
|
|
48689
|
+
}
|
|
47334
48690
|
if (node.id === "fast-cycles") {
|
|
47335
48691
|
trackCoreEvent("Fast Clips Clicked", {
|
|
47336
48692
|
workspaceId,
|
|
@@ -47368,8 +48724,11 @@ var FileManagerFilters = ({
|
|
|
47368
48724
|
} else if (node.type === "video") {
|
|
47369
48725
|
if (onClipSelect && node.categoryId !== void 0 && node.clipId !== void 0) {
|
|
47370
48726
|
console.log(`[FileManager] Selecting clip: category=${node.categoryId}, clipId=${node.clipId}, position=${node.clipPosition}`);
|
|
47371
|
-
const
|
|
47372
|
-
const selectionContext =
|
|
48727
|
+
const categoryNode = displayedFilterTree.find((candidate) => candidate.id === node.categoryId);
|
|
48728
|
+
const selectionContext = getSelectionContextForNodes(
|
|
48729
|
+
node.categoryId,
|
|
48730
|
+
categoryNode?.children || [node]
|
|
48731
|
+
);
|
|
47373
48732
|
onClipSelect(node.categoryId, node.clipId, node.clipPosition, selectionContext);
|
|
47374
48733
|
} else {
|
|
47375
48734
|
const videoIndex = videos.findIndex((v) => v.id === node.id);
|
|
@@ -47382,24 +48741,40 @@ var FileManagerFilters = ({
|
|
|
47382
48741
|
const renderNode = (node, depth = 0) => {
|
|
47383
48742
|
const isExpanded = expandedNodes.has(node.id);
|
|
47384
48743
|
const isActive = activeFilter === node.id;
|
|
47385
|
-
const
|
|
47386
|
-
const
|
|
47387
|
-
|
|
47388
|
-
|
|
48744
|
+
const nodeClipId = node.clipId || node.id;
|
|
48745
|
+
const isCurrentVideo = Boolean(
|
|
48746
|
+
node.type === "video" && currentVideoId && currentVideoId === nodeClipId
|
|
48747
|
+
);
|
|
48748
|
+
const isCountUnknown = Boolean(
|
|
48749
|
+
(node.type === "category" || node.type === "percentile-category") && (node.count === null || node.countLoading)
|
|
48750
|
+
);
|
|
48751
|
+
const hasRenderedChildren = (node.children?.length || 0) > 0;
|
|
47389
48752
|
const loadedPage = categoryPages[node.id] || 0;
|
|
47390
48753
|
const pageOneLoadingKey = getMetadataLoadingKey(node.id, 1);
|
|
47391
48754
|
const nextMetadataPage = loadedPage + 1;
|
|
47392
48755
|
const nextLoadMorePage = (categoryPages[node.id] || 1) + 1;
|
|
47393
48756
|
const isPageOneLoading = loadingCategories.has(pageOneLoadingKey);
|
|
48757
|
+
const isFullCategoryLoading = Array.from(loadingCategories).some((key) => key.startsWith(`${pageOneLoadingKey}-all`));
|
|
47394
48758
|
const isLoadMoreLoading = loadedPage > 0 && loadingCategories.has(getMetadataLoadingKey(node.id, nextMetadataPage));
|
|
48759
|
+
const isNodeLoading = Boolean(
|
|
48760
|
+
isPageOneLoading || isFullCategoryLoading || activeCategoryLoading && node.id === activeFilter
|
|
48761
|
+
);
|
|
48762
|
+
const totalForLoadMore = isCategoryScopedByTimeFilter(node.id) && typeof scopedCategoryTotals[node.id] === "number" ? scopedCategoryTotals[node.id] : counts?.[node.id] || 0;
|
|
47395
48763
|
const showInitialLoadingState = Boolean(
|
|
47396
|
-
isExpanded && !
|
|
48764
|
+
isExpanded && !hasRenderedChildren && (node.type === "category" || node.type === "percentile-category") && isNodeLoading
|
|
48765
|
+
);
|
|
48766
|
+
const showScopedEmptyState = Boolean(
|
|
48767
|
+
isExpanded && !hasRenderedChildren && !isNodeLoading && !categoryHasMore[node.id] && isCategoryScopedByTimeFilter(node.id) && (node.type === "category" || node.type === "percentile-category")
|
|
47397
48768
|
);
|
|
48769
|
+
const hasChildren = isCountUnknown || (node.count || 0) > 0 || isNodeLoading || showScopedEmptyState;
|
|
47398
48770
|
const colorClasses = node.color ? getColorClasses(node.color) : null;
|
|
47399
48771
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "select-none animate-in", children: [
|
|
47400
48772
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
47401
48773
|
"div",
|
|
47402
48774
|
{
|
|
48775
|
+
"aria-current": isCurrentVideo ? "true" : void 0,
|
|
48776
|
+
"data-qa-clips-row-clip-id": node.type === "video" ? nodeClipId : void 0,
|
|
48777
|
+
"data-qa-clips-row-category-id": node.type === "video" ? node.categoryId : void 0,
|
|
47403
48778
|
className: `flex items-center cursor-pointer transition-all duration-300 ease-out group relative overflow-hidden ${node.type === "category" && depth === 0 ? `py-3 px-4 rounded-2xl hover:bg-gradient-to-r hover:from-slate-50 hover:to-blue-50/30 hover:shadow-lg hover:shadow-blue-100/20 hover:scale-[1.02] hover:-translate-y-0.5 ${isActive ? "bg-gradient-to-r from-blue-50 via-blue-50/80 to-indigo-50/60 border border-blue-200/50 shadow-lg shadow-blue-100/30 scale-[1.02]" : "border border-transparent"}` : `py-2 px-3 rounded-xl hover:bg-gradient-to-r hover:from-slate-50 hover:to-slate-50/50 hover:shadow-sm ${isActive ? "bg-gradient-to-r from-blue-50/80 to-blue-50/40 border border-blue-200/30 shadow-sm" : "border border-transparent"} ${isCurrentVideo ? "bg-gradient-to-r from-blue-50 to-blue-50/60 border border-blue-200/50 shadow-md shadow-blue-100/20" : ""}`} ${node.type === "video" ? "ml-6" : ""}`,
|
|
47404
48779
|
onClick: () => handleNodeClick(node),
|
|
47405
48780
|
children: [
|
|
@@ -47435,7 +48810,7 @@ var FileManagerFilters = ({
|
|
|
47435
48810
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0 flex items-center justify-between", children: [
|
|
47436
48811
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
|
|
47437
48812
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `font-semibold tracking-tight ${node.type === "category" || node.type === "percentile-category" ? "text-slate-800 text-sm" : "text-slate-700 text-xs"} ${isCurrentVideo ? "text-blue-700 font-bold" : ""} group-hover:text-slate-900 transition-colors duration-200`, children: node.label }),
|
|
47438
|
-
node.type === "category" && (node.subtitle ||
|
|
48813
|
+
node.type === "category" && (node.subtitle || categoriesForTree.find((c) => c.id === node.id)?.description) && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-slate-500 mt-0.5 font-normal", children: node.subtitle || categoriesForTree.find((c) => c.id === node.id)?.description }),
|
|
47439
48814
|
node.type === "percentile-category" && node.subtitle && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-slate-500 mt-0.5 font-normal", children: node.subtitle }),
|
|
47440
48815
|
node.type === "video" && (node.severity || node.categoryId === "cycle_completion" || node.categoryId === "idle_time" || node.categoryId === "low_value" || node.categoryId === RECENT_FLOW_RED_STREAK_CLIP_TYPE2) && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs mt-0.5 font-medium", children: node.categoryId === "idle_time" ? (
|
|
47441
48816
|
// Show root cause label for idle time clips (text only, icon is on the left)
|
|
@@ -47471,7 +48846,7 @@ var FileManagerFilters = ({
|
|
|
47471
48846
|
})()
|
|
47472
48847
|
) })
|
|
47473
48848
|
] }),
|
|
47474
|
-
node.count !== void 0 && (node.type === "category" || node.type === "percentile-category") && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center ml-2", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: `px-2.5 py-1 text-sm font-bold rounded-lg shadow-sm border backdrop-blur-sm flex-shrink-0 group-hover:scale-105 transition-all duration-200 ${colorClasses ? `${colorClasses.bg} ${colorClasses.text} ${colorClasses.border} bg-opacity-80` : "bg-slate-100/80 text-slate-700 border-slate-200/60"}`, children:
|
|
48849
|
+
node.count !== void 0 && (node.type === "category" || node.type === "percentile-category") && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center ml-2", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: `px-2.5 py-1 text-sm font-bold rounded-lg shadow-sm border backdrop-blur-sm flex-shrink-0 group-hover:scale-105 transition-all duration-200 ${colorClasses ? `${colorClasses.bg} ${colorClasses.text} ${colorClasses.border} bg-opacity-80` : "bg-slate-100/80 text-slate-700 border-slate-200/60"}`, children: isCountUnknown ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-3.5 w-3.5 animate-spin" }) : node.count }) })
|
|
47475
48850
|
] })
|
|
47476
48851
|
]
|
|
47477
48852
|
}
|
|
@@ -47482,6 +48857,7 @@ var FileManagerFilters = ({
|
|
|
47482
48857
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
|
|
47483
48858
|
"Loading clips..."
|
|
47484
48859
|
] }) }),
|
|
48860
|
+
showScopedEmptyState && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-2 px-3 text-center text-sm text-slate-500", children: "No clips found" }),
|
|
47485
48861
|
isLoadMoreLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-2 px-3 text-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center text-sm text-slate-500", children: [
|
|
47486
48862
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "animate-spin mr-2 h-4 w-4 border-2 border-slate-300 border-t-blue-500 rounded-full" }),
|
|
47487
48863
|
"Loading more clips..."
|
|
@@ -47496,7 +48872,7 @@ var FileManagerFilters = ({
|
|
|
47496
48872
|
className: "w-full py-2 px-3 text-sm text-blue-600 hover:bg-blue-50 rounded-lg transition-colors duration-200 text-center",
|
|
47497
48873
|
children: [
|
|
47498
48874
|
"Load more clips (",
|
|
47499
|
-
(
|
|
48875
|
+
Math.max(0, totalForLoadMore - getAvailableClipMetadata(node.id).length),
|
|
47500
48876
|
" remaining)"
|
|
47501
48877
|
]
|
|
47502
48878
|
}
|
|
@@ -47559,6 +48935,8 @@ var FileManagerFilters = ({
|
|
|
47559
48935
|
e.stopPropagation();
|
|
47560
48936
|
setStartTime("");
|
|
47561
48937
|
setEndTime("");
|
|
48938
|
+
setActiveInitialTimeFilter(null);
|
|
48939
|
+
setScopedCategoryTotals({});
|
|
47562
48940
|
setIsTimeFilterActive(false);
|
|
47563
48941
|
},
|
|
47564
48942
|
className: "rounded-full p-0.5 transition-colors hover:bg-blue-100",
|
|
@@ -47692,6 +49070,8 @@ var FileManagerFilters = ({
|
|
|
47692
49070
|
onClick: () => {
|
|
47693
49071
|
setStartTime("");
|
|
47694
49072
|
setEndTime("");
|
|
49073
|
+
setActiveInitialTimeFilter(null);
|
|
49074
|
+
setScopedCategoryTotals({});
|
|
47695
49075
|
setStartSearchTerm("");
|
|
47696
49076
|
setEndSearchTerm("");
|
|
47697
49077
|
setIsTimeFilterActive(false);
|
|
@@ -47780,8 +49160,13 @@ var FileManagerFilters = ({
|
|
|
47780
49160
|
)
|
|
47781
49161
|
] }),
|
|
47782
49162
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-4 py-3 flex-1 min-h-0 overflow-y-auto scrollbar-thin", children: [
|
|
47783
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2", children:
|
|
47784
|
-
|
|
49163
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2", children: displayedFilterTree.map((node) => renderNode(node)) }),
|
|
49164
|
+
displayedFilterTree.length === 0 && isChartHandoffLoading && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center py-12", children: [
|
|
49165
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center justify-center mb-4", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-8 w-8 animate-spin text-blue-500" }) }),
|
|
49166
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold text-slate-700 mb-2", children: "Loading clips..." }),
|
|
49167
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-slate-500", children: "Finding clips from the selected hour" })
|
|
49168
|
+
] }),
|
|
49169
|
+
displayedFilterTree.length === 0 && !isChartHandoffLoading && (startTime || endTime) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center py-12", children: [
|
|
47785
49170
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-slate-300 mb-4", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: "h-12 w-12 mx-auto" }) }),
|
|
47786
49171
|
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold text-slate-700 mb-2", children: "No clips found" }),
|
|
47787
49172
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-slate-500 mb-4", children: "No clips match the selected time range" }),
|
|
@@ -47791,6 +49176,8 @@ var FileManagerFilters = ({
|
|
|
47791
49176
|
onClick: () => {
|
|
47792
49177
|
setStartTime("");
|
|
47793
49178
|
setEndTime("");
|
|
49179
|
+
setActiveInitialTimeFilter(null);
|
|
49180
|
+
setScopedCategoryTotals({});
|
|
47794
49181
|
setIsTimeFilterActive(false);
|
|
47795
49182
|
},
|
|
47796
49183
|
className: "inline-flex items-center px-4 py-2 bg-blue-50 text-blue-600 text-sm font-medium rounded-lg hover:bg-blue-100 transition-colors duration-200",
|
|
@@ -47798,12 +49185,12 @@ var FileManagerFilters = ({
|
|
|
47798
49185
|
}
|
|
47799
49186
|
)
|
|
47800
49187
|
] }),
|
|
47801
|
-
|
|
49188
|
+
displayedFilterTree.length === 0 && !startTime && !endTime && categories.length === 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center py-12", children: [
|
|
47802
49189
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-slate-300 mb-4", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.HelpCircle, { className: "h-12 w-12 mx-auto" }) }),
|
|
47803
49190
|
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold text-slate-700 mb-2", children: "No clip types available" }),
|
|
47804
49191
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-slate-500", children: "Loading clip categories..." })
|
|
47805
49192
|
] }),
|
|
47806
|
-
|
|
49193
|
+
displayedFilterTree.length === 0 && !startTime && !endTime && categories.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center py-12", children: [
|
|
47807
49194
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-slate-300 mb-4", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Play, { className: "h-12 w-12 mx-auto" }) }),
|
|
47808
49195
|
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold text-slate-700 mb-2", children: "No clips available" }),
|
|
47809
49196
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-slate-500", children: "No clips found for the selected time period" })
|
|
@@ -48210,6 +49597,65 @@ function useClipsRealtimeUpdates({
|
|
|
48210
49597
|
}
|
|
48211
49598
|
var LOW_EFFICIENCY_CATEGORY_ID = "recent_flow_red_streak";
|
|
48212
49599
|
var LOW_EFFICIENCY_AI_SUMMARY_ENABLED = process.env.NEXT_PUBLIC_LOW_EFFICIENCY_AI_SUMMARY_ENABLED === "true";
|
|
49600
|
+
var timeValueToMinutes2 = (value) => {
|
|
49601
|
+
const [hourValue, minuteValue] = value.substring(0, 5).split(":").map(Number);
|
|
49602
|
+
if (!Number.isInteger(hourValue) || !Number.isInteger(minuteValue) || hourValue < 0 || hourValue > 23 || minuteValue < 0 || minuteValue > 59) {
|
|
49603
|
+
return null;
|
|
49604
|
+
}
|
|
49605
|
+
return hourValue * 60 + minuteValue;
|
|
49606
|
+
};
|
|
49607
|
+
var isMinuteInTimeWindow2 = (minute, startValue, endValue) => {
|
|
49608
|
+
const startMinute = timeValueToMinutes2(startValue);
|
|
49609
|
+
const endMinute = timeValueToMinutes2(endValue);
|
|
49610
|
+
if (startMinute === null || endMinute === null) {
|
|
49611
|
+
return true;
|
|
49612
|
+
}
|
|
49613
|
+
return endMinute > startMinute ? minute >= startMinute && minute < endMinute : minute >= startMinute || minute < endMinute;
|
|
49614
|
+
};
|
|
49615
|
+
var CHART_HANDOFF_CATEGORY_FALLBACKS = {
|
|
49616
|
+
cycle_completion: {
|
|
49617
|
+
label: "Cycle Completion",
|
|
49618
|
+
description: "Successfully completed production cycles",
|
|
49619
|
+
color: "blue",
|
|
49620
|
+
icon: "check-circle"
|
|
49621
|
+
},
|
|
49622
|
+
"fast-cycles": {
|
|
49623
|
+
label: "Fast Cycles",
|
|
49624
|
+
description: "Fastest cycle clips",
|
|
49625
|
+
color: "green",
|
|
49626
|
+
icon: "trending-up"
|
|
49627
|
+
},
|
|
49628
|
+
"slow-cycles": {
|
|
49629
|
+
label: "Slow Cycles",
|
|
49630
|
+
description: "Slowest cycle clips",
|
|
49631
|
+
color: "red",
|
|
49632
|
+
icon: "trending-down"
|
|
49633
|
+
},
|
|
49634
|
+
idle_time: {
|
|
49635
|
+
label: "Idle Time",
|
|
49636
|
+
description: "Low value activities and idle moments",
|
|
49637
|
+
color: "amber",
|
|
49638
|
+
icon: "clock"
|
|
49639
|
+
},
|
|
49640
|
+
recent_flow_red_streak: {
|
|
49641
|
+
label: "Low moments",
|
|
49642
|
+
description: "Moments of low efficiency",
|
|
49643
|
+
color: "rose",
|
|
49644
|
+
icon: "alert-triangle"
|
|
49645
|
+
},
|
|
49646
|
+
worst_cycle_time: {
|
|
49647
|
+
label: "Slow Cycles",
|
|
49648
|
+
description: "Slowest cycle clips",
|
|
49649
|
+
color: "red",
|
|
49650
|
+
icon: "trending-down"
|
|
49651
|
+
},
|
|
49652
|
+
best_cycle_time: {
|
|
49653
|
+
label: "Fast Cycles",
|
|
49654
|
+
description: "Fastest cycle clips",
|
|
49655
|
+
color: "green",
|
|
49656
|
+
icon: "trending-up"
|
|
49657
|
+
}
|
|
49658
|
+
};
|
|
48213
49659
|
var parseFiniteNumber2 = (value) => {
|
|
48214
49660
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
48215
49661
|
return value;
|
|
@@ -48257,6 +49703,7 @@ var BottlenecksContent = ({
|
|
|
48257
49703
|
ticketId,
|
|
48258
49704
|
prefetchedPercentileCounts,
|
|
48259
49705
|
lowMomentsPrefetch,
|
|
49706
|
+
initialTimePrefetch,
|
|
48260
49707
|
initialTimeFilter
|
|
48261
49708
|
}) => {
|
|
48262
49709
|
console.log("\u{1F3AB} [BottlenecksContent] Rendered with ticketId:", ticketId || "NONE", "workspaceId:", workspaceId, "date:", date, "shift:", shift);
|
|
@@ -48469,6 +49916,108 @@ var BottlenecksContent = ({
|
|
|
48469
49916
|
enabled: isEffectiveShiftReady
|
|
48470
49917
|
});
|
|
48471
49918
|
const isLowMomentsCategoryAvailable = React125.useMemo(() => Array.isArray(clipTypes) && clipTypes.some((type) => type?.type === LOW_EFFICIENCY_CATEGORY_ID || type?.id === LOW_EFFICIENCY_CATEGORY_ID), [clipTypes]);
|
|
49919
|
+
const requestedInitialCategoryCandidates = React125.useMemo(() => {
|
|
49920
|
+
const requestedCategories = [
|
|
49921
|
+
...Array.isArray(initialTimeFilter?.categoryIds) ? initialTimeFilter.categoryIds : [],
|
|
49922
|
+
initialTimeFilter?.categoryId
|
|
49923
|
+
];
|
|
49924
|
+
return Array.from(
|
|
49925
|
+
new Set(
|
|
49926
|
+
requestedCategories.filter((category) => Boolean(category)).map((category) => category.trim()).filter(Boolean)
|
|
49927
|
+
)
|
|
49928
|
+
);
|
|
49929
|
+
}, [initialTimeFilter?.categoryId, initialTimeFilter?.categoryIds]);
|
|
49930
|
+
const hasInitialTimeHandoff = Boolean(initialTimeFilter?.startTime && initialTimeFilter?.endTime);
|
|
49931
|
+
const initialTimeHandoffCategorySet = React125.useMemo(() => new Set(requestedInitialCategoryCandidates), [requestedInitialCategoryCandidates]);
|
|
49932
|
+
const isInitialTimeHandoffCategory = React125.useCallback((categoryId) => Boolean(
|
|
49933
|
+
hasInitialTimeHandoff && categoryId && (initialTimeHandoffCategorySet.size === 0 || initialTimeHandoffCategorySet.has(categoryId))
|
|
49934
|
+
), [hasInitialTimeHandoff, initialTimeHandoffCategorySet]);
|
|
49935
|
+
const isTimestampInInitialTimeHandoff = React125.useCallback((timestamp) => {
|
|
49936
|
+
if (!hasInitialTimeHandoff || !initialTimeFilter?.startTime || !initialTimeFilter?.endTime || !timestamp) {
|
|
49937
|
+
return true;
|
|
49938
|
+
}
|
|
49939
|
+
try {
|
|
49940
|
+
const clipDate = new Date(timestamp);
|
|
49941
|
+
if (Number.isNaN(clipDate.getTime())) {
|
|
49942
|
+
return false;
|
|
49943
|
+
}
|
|
49944
|
+
const clipParts = new Intl.DateTimeFormat("en-US", {
|
|
49945
|
+
hour12: false,
|
|
49946
|
+
hour: "2-digit",
|
|
49947
|
+
minute: "2-digit",
|
|
49948
|
+
timeZone: initialTimeFilter.timezone || timezone
|
|
49949
|
+
}).formatToParts(clipDate);
|
|
49950
|
+
const hourValue = clipParts.find((part) => part.type === "hour")?.value;
|
|
49951
|
+
const minuteValue = clipParts.find((part) => part.type === "minute")?.value;
|
|
49952
|
+
const clipMinute = timeValueToMinutes2(`${hourValue}:${minuteValue}`);
|
|
49953
|
+
return clipMinute === null ? false : isMinuteInTimeWindow2(clipMinute, initialTimeFilter.startTime, initialTimeFilter.endTime);
|
|
49954
|
+
} catch {
|
|
49955
|
+
return false;
|
|
49956
|
+
}
|
|
49957
|
+
}, [
|
|
49958
|
+
hasInitialTimeHandoff,
|
|
49959
|
+
initialTimeFilter?.endTime,
|
|
49960
|
+
initialTimeFilter?.startTime,
|
|
49961
|
+
initialTimeFilter?.timezone,
|
|
49962
|
+
timezone
|
|
49963
|
+
]);
|
|
49964
|
+
const resolvedInitialCategory = React125.useMemo(() => resolveInitialClipCategory(requestedInitialCategoryCandidates, clipTypes, dynamicCounts), [clipTypes, dynamicCounts, requestedInitialCategoryCandidates]);
|
|
49965
|
+
const initialTimeFilterKey = React125.useMemo(() => hasInitialTimeHandoff ? [
|
|
49966
|
+
initialTimeFilter?.startTime,
|
|
49967
|
+
initialTimeFilter?.endTime,
|
|
49968
|
+
initialTimeFilter?.timezone || timezone,
|
|
49969
|
+
initialTimeFilter?.categoryId || "",
|
|
49970
|
+
...initialTimeFilter?.categoryIds || []
|
|
49971
|
+
].join("|") : "", [
|
|
49972
|
+
hasInitialTimeHandoff,
|
|
49973
|
+
initialTimeFilter?.categoryId,
|
|
49974
|
+
initialTimeFilter?.categoryIds,
|
|
49975
|
+
initialTimeFilter?.endTime,
|
|
49976
|
+
initialTimeFilter?.startTime,
|
|
49977
|
+
initialTimeFilter?.timezone,
|
|
49978
|
+
timezone
|
|
49979
|
+
]);
|
|
49980
|
+
const preferredInitialTimeCategory = resolvedInitialCategory || requestedInitialCategoryCandidates[0] || "";
|
|
49981
|
+
React125.useEffect(() => {
|
|
49982
|
+
if (!initialTimeFilterKey) {
|
|
49983
|
+
return;
|
|
49984
|
+
}
|
|
49985
|
+
setPendingVideo(null);
|
|
49986
|
+
setAllVideos([]);
|
|
49987
|
+
setCurrentIndex(0);
|
|
49988
|
+
setCurrentClipId(null);
|
|
49989
|
+
currentClipIdRef.current = null;
|
|
49990
|
+
setCurrentMetadataIndex(0);
|
|
49991
|
+
currentMetadataIndexRef.current = 0;
|
|
49992
|
+
setCurrentPosition(0);
|
|
49993
|
+
currentPositionRef.current = 0;
|
|
49994
|
+
setCurrentTotal(0);
|
|
49995
|
+
currentTotalRef.current = 0;
|
|
49996
|
+
setCategoryMetadata([]);
|
|
49997
|
+
categoryMetadataRef.current = [];
|
|
49998
|
+
setCategoryMetadataCategoryId(null);
|
|
49999
|
+
setCategoryMetadataSort(null);
|
|
50000
|
+
clearRetryTimeout();
|
|
50001
|
+
navigationLockRef.current = false;
|
|
50002
|
+
loadingCategoryRef.current = null;
|
|
50003
|
+
if (loadingTimeoutRef.current) {
|
|
50004
|
+
clearTimeout(loadingTimeoutRef.current);
|
|
50005
|
+
loadingTimeoutRef.current = null;
|
|
50006
|
+
}
|
|
50007
|
+
setIsTransitioning(false);
|
|
50008
|
+
setIsNavigating(false);
|
|
50009
|
+
setIsCategoryLoading(false);
|
|
50010
|
+
if (preferredInitialTimeCategory) {
|
|
50011
|
+
setInitialFilter(preferredInitialTimeCategory);
|
|
50012
|
+
updateActiveFilter(preferredInitialTimeCategory);
|
|
50013
|
+
previousFilterRef.current = "";
|
|
50014
|
+
}
|
|
50015
|
+
}, [
|
|
50016
|
+
clearRetryTimeout,
|
|
50017
|
+
initialTimeFilterKey,
|
|
50018
|
+
preferredInitialTimeCategory,
|
|
50019
|
+
updateActiveFilter
|
|
50020
|
+
]);
|
|
48472
50021
|
console.log("[BottlenecksContent] Clip types data:", {
|
|
48473
50022
|
clipTypes,
|
|
48474
50023
|
clipTypesLength: clipTypes?.length,
|
|
@@ -48516,6 +50065,15 @@ var BottlenecksContent = ({
|
|
|
48516
50065
|
}
|
|
48517
50066
|
});
|
|
48518
50067
|
React125.useEffect(() => {
|
|
50068
|
+
if (resolvedInitialCategory) {
|
|
50069
|
+
if (initialFilter !== resolvedInitialCategory) {
|
|
50070
|
+
setInitialFilter(resolvedInitialCategory);
|
|
50071
|
+
}
|
|
50072
|
+
if (activeFilterRef.current !== resolvedInitialCategory) {
|
|
50073
|
+
updateActiveFilter(resolvedInitialCategory);
|
|
50074
|
+
}
|
|
50075
|
+
return;
|
|
50076
|
+
}
|
|
48519
50077
|
if (initialFilter) {
|
|
48520
50078
|
return;
|
|
48521
50079
|
}
|
|
@@ -48532,7 +50090,15 @@ var BottlenecksContent = ({
|
|
|
48532
50090
|
activeFilterRef.current = defaultCategory;
|
|
48533
50091
|
return;
|
|
48534
50092
|
}
|
|
48535
|
-
}, [
|
|
50093
|
+
}, [
|
|
50094
|
+
clipTypes,
|
|
50095
|
+
dynamicCounts,
|
|
50096
|
+
defaultCategory,
|
|
50097
|
+
initialFilter,
|
|
50098
|
+
isLowMomentsCategoryAvailable,
|
|
50099
|
+
resolvedInitialCategory,
|
|
50100
|
+
updateActiveFilter
|
|
50101
|
+
]);
|
|
48536
50102
|
const mergedCounts = React125.useMemo(() => {
|
|
48537
50103
|
return { ...dynamicCounts };
|
|
48538
50104
|
}, [dynamicCounts]);
|
|
@@ -48581,6 +50147,9 @@ var BottlenecksContent = ({
|
|
|
48581
50147
|
const loadFirstVideoForCategory = React125.useCallback(async (category) => {
|
|
48582
50148
|
if (!workspaceId || !s3ClipsService || !isMountedRef.current || !isEffectiveShiftReady) return;
|
|
48583
50149
|
const targetCategory = category || activeFilterRef.current;
|
|
50150
|
+
if (targetCategory === "fast-cycles" || targetCategory === "slow-cycles") {
|
|
50151
|
+
return;
|
|
50152
|
+
}
|
|
48584
50153
|
const operationKey = `loadFirstVideo:${targetCategory}:${effectiveDateString}:${effectiveShiftId}`;
|
|
48585
50154
|
if (loadingCategoryRef.current === targetCategory || fetchInProgressRef.current.has(operationKey)) {
|
|
48586
50155
|
console.log(`[BottlenecksContent] Load first video already in progress for ${targetCategory}`);
|
|
@@ -49026,8 +50595,9 @@ var BottlenecksContent = ({
|
|
|
49026
50595
|
});
|
|
49027
50596
|
}
|
|
49028
50597
|
setVisibleCategoryMetadata(categoryId, cachedMetadata);
|
|
49029
|
-
|
|
49030
|
-
|
|
50598
|
+
const cachedAutoloadCandidates = isInitialTimeHandoffCategory(categoryId) ? cachedMetadata.filter((clip) => isTimestampInInitialTimeHandoff(clip.clip_timestamp || clip.creation_timestamp || clip.timestamp)) : cachedMetadata;
|
|
50599
|
+
if (autoLoadFirstVideo && cachedAutoloadCandidates.length > 0 && s3ClipsService) {
|
|
50600
|
+
const firstClipMeta = cachedAutoloadCandidates[0];
|
|
49031
50601
|
const firstClipId = firstClipMeta.clipId || firstClipMeta.id;
|
|
49032
50602
|
const prefetchedFirstVideo = matchingLowMomentsPrefetch?.firstVideo ?? null;
|
|
49033
50603
|
try {
|
|
@@ -49066,7 +50636,10 @@ var BottlenecksContent = ({
|
|
|
49066
50636
|
endDate: `${resolvedDate}T23:59:59Z`,
|
|
49067
50637
|
percentile: 10,
|
|
49068
50638
|
shiftId: effectiveShiftId,
|
|
49069
|
-
limit: 100
|
|
50639
|
+
limit: isInitialTimeHandoffCategory(categoryId) ? 500 : 100,
|
|
50640
|
+
startTime: isInitialTimeHandoffCategory(categoryId) ? initialTimeFilter?.startTime : void 0,
|
|
50641
|
+
endTime: isInitialTimeHandoffCategory(categoryId) ? initialTimeFilter?.endTime : void 0,
|
|
50642
|
+
timeFilterTimezone: isInitialTimeHandoffCategory(categoryId) ? initialTimeFilter?.timezone || timezone : void 0
|
|
49070
50643
|
}),
|
|
49071
50644
|
redirectReason: "session_expired"
|
|
49072
50645
|
});
|
|
@@ -49083,10 +50656,13 @@ var BottlenecksContent = ({
|
|
|
49083
50656
|
shift: effectiveShiftId,
|
|
49084
50657
|
category: categoryId,
|
|
49085
50658
|
page: 1,
|
|
49086
|
-
limit: 100,
|
|
49087
|
-
knownTotal: mergedCounts[categoryId] ?? null,
|
|
50659
|
+
limit: isInitialTimeHandoffCategory(categoryId) ? 500 : 100,
|
|
50660
|
+
knownTotal: isInitialTimeHandoffCategory(categoryId) ? null : mergedCounts[categoryId] ?? null,
|
|
49088
50661
|
snapshotDateTime,
|
|
49089
50662
|
snapshotClipId,
|
|
50663
|
+
startTime: isInitialTimeHandoffCategory(categoryId) ? initialTimeFilter?.startTime : void 0,
|
|
50664
|
+
endTime: isInitialTimeHandoffCategory(categoryId) ? initialTimeFilter?.endTime : void 0,
|
|
50665
|
+
timeFilterTimezone: isInitialTimeHandoffCategory(categoryId) ? initialTimeFilter?.timezone || timezone : void 0,
|
|
49090
50666
|
sort: categoryId === LOW_EFFICIENCY_CATEGORY_ID ? "red_flow_output_shortfall_desc" : categoryId === "idle_time" ? idleClipSort : "latest"
|
|
49091
50667
|
}),
|
|
49092
50668
|
redirectReason: "session_expired"
|
|
@@ -49099,7 +50675,8 @@ var BottlenecksContent = ({
|
|
|
49099
50675
|
if (categoryData.clips && isMountedRef.current) {
|
|
49100
50676
|
let metadataClips;
|
|
49101
50677
|
if (isPercentileCategory(categoryId)) {
|
|
49102
|
-
|
|
50678
|
+
const sortedPercentileClips = sortPercentileCycleClipsForDisplay(categoryId, categoryData.clips);
|
|
50679
|
+
metadataClips = sortedPercentileClips.map((clip, index) => ({
|
|
49103
50680
|
id: clip.id,
|
|
49104
50681
|
clipId: clip.id,
|
|
49105
50682
|
clip_timestamp: clip.creation_timestamp || clip.timestamp,
|
|
@@ -49146,8 +50723,9 @@ var BottlenecksContent = ({
|
|
|
49146
50723
|
}));
|
|
49147
50724
|
setVisibleCategoryMetadata(categoryId, metadataClips);
|
|
49148
50725
|
console.log(`[BottlenecksContent] Loaded metadata for ${categoryId}: ${metadataClips.length} clips`);
|
|
49149
|
-
|
|
49150
|
-
|
|
50726
|
+
const autoloadCandidates = isInitialTimeHandoffCategory(categoryId) ? metadataClips.filter((clip) => isTimestampInInitialTimeHandoff(clip.clip_timestamp || clip.creation_timestamp || clip.timestamp)) : metadataClips;
|
|
50727
|
+
if (autoLoadFirstVideo && autoloadCandidates.length > 0 && s3ClipsService) {
|
|
50728
|
+
const firstClipMeta = autoloadCandidates[0];
|
|
49151
50729
|
const firstClipId = firstClipMeta.clipId || firstClipMeta.id;
|
|
49152
50730
|
try {
|
|
49153
50731
|
const video = await s3ClipsService.getClipById(firstClipId);
|
|
@@ -49181,7 +50759,7 @@ var BottlenecksContent = ({
|
|
|
49181
50759
|
setIsCategoryLoading(false);
|
|
49182
50760
|
}
|
|
49183
50761
|
}
|
|
49184
|
-
}, [workspaceId, effectiveDateString, effectiveShiftId, getMetadataCacheKey, isPercentileCategory, isFastSlowClipFiltersEnabled, metadataCache, s3ClipsService, clearLoadingState, isEffectiveShiftReady, snapshotDateTime, snapshotClipId, idleClipSort, supabase, setVisibleCategoryMetadata, lowMomentsPrefetch, applyPrefetchedFirstVideo, applyMetadataSnapshot, isLowMomentsCategoryAvailable]);
|
|
50762
|
+
}, [workspaceId, effectiveDateString, effectiveShiftId, getMetadataCacheKey, isPercentileCategory, isFastSlowClipFiltersEnabled, metadataCache, s3ClipsService, clearLoadingState, isEffectiveShiftReady, snapshotDateTime, snapshotClipId, idleClipSort, supabase, setVisibleCategoryMetadata, lowMomentsPrefetch, applyPrefetchedFirstVideo, applyMetadataSnapshot, isLowMomentsCategoryAvailable, isInitialTimeHandoffCategory, isTimestampInInitialTimeHandoff, initialTimeFilter?.endTime, initialTimeFilter?.startTime, initialTimeFilter?.timezone, timezone]);
|
|
49185
50763
|
React125.useEffect(() => {
|
|
49186
50764
|
if (activeFilter !== LOW_EFFICIENCY_CATEGORY_ID || !isLowMomentsCategoryAvailable) {
|
|
49187
50765
|
return;
|
|
@@ -49213,6 +50791,37 @@ var BottlenecksContent = ({
|
|
|
49213
50791
|
applyMetadataSnapshot,
|
|
49214
50792
|
isLowMomentsCategoryAvailable
|
|
49215
50793
|
]);
|
|
50794
|
+
React125.useEffect(() => {
|
|
50795
|
+
if (!initialTimeFilter?.startTime || !initialTimeFilter?.endTime || !initialTimePrefetch || initialTimePrefetch.loading || initialTimePrefetch.categoryId !== activeFilter) {
|
|
50796
|
+
return;
|
|
50797
|
+
}
|
|
50798
|
+
if (initialTimePrefetch.metadata.length > 0) {
|
|
50799
|
+
applyMetadataSnapshot(
|
|
50800
|
+
initialTimePrefetch.categoryId,
|
|
50801
|
+
initialTimePrefetch.metadata,
|
|
50802
|
+
initialTimePrefetch.total
|
|
50803
|
+
);
|
|
50804
|
+
}
|
|
50805
|
+
if (initialTimePrefetch.firstVideo && isTimestampInInitialTimeHandoff(
|
|
50806
|
+
initialTimePrefetch.firstVideo.creation_timestamp || initialTimePrefetch.firstVideo.timestamp
|
|
50807
|
+
)) {
|
|
50808
|
+
applyPrefetchedFirstVideo(initialTimePrefetch.firstVideo);
|
|
50809
|
+
if (isMountedRef.current) {
|
|
50810
|
+
setIsCategoryLoading(false);
|
|
50811
|
+
setIsInitialLoading(false);
|
|
50812
|
+
setIsTransitioning(false);
|
|
50813
|
+
setIsNavigating(false);
|
|
50814
|
+
}
|
|
50815
|
+
}
|
|
50816
|
+
}, [
|
|
50817
|
+
activeFilter,
|
|
50818
|
+
applyMetadataSnapshot,
|
|
50819
|
+
applyPrefetchedFirstVideo,
|
|
50820
|
+
initialTimeFilter?.endTime,
|
|
50821
|
+
initialTimeFilter?.startTime,
|
|
50822
|
+
initialTimePrefetch,
|
|
50823
|
+
isTimestampInInitialTimeHandoff
|
|
50824
|
+
]);
|
|
49216
50825
|
React125.useEffect(() => {
|
|
49217
50826
|
if (previousIdleClipSortRef.current === idleClipSort) {
|
|
49218
50827
|
return;
|
|
@@ -49252,7 +50861,7 @@ var BottlenecksContent = ({
|
|
|
49252
50861
|
currentTotalRef.current = total;
|
|
49253
50862
|
setCurrentTotal(total);
|
|
49254
50863
|
previousFilterRef.current = activeFilter;
|
|
49255
|
-
const metadataLoadPlan = getCategoryMetadataLoadPlanForFilterChange({
|
|
50864
|
+
const metadataLoadPlan = isInitialTimeHandoffCategory(activeFilter) ? { shouldLoad: false, autoLoadFirstVideo: false } : getCategoryMetadataLoadPlanForFilterChange({
|
|
49256
50865
|
activeFilter,
|
|
49257
50866
|
currentClipId,
|
|
49258
50867
|
categoryTotal: total
|
|
@@ -49276,7 +50885,7 @@ var BottlenecksContent = ({
|
|
|
49276
50885
|
}
|
|
49277
50886
|
}
|
|
49278
50887
|
}
|
|
49279
|
-
}, [activeFilter, allVideos, mergedCounts, currentClipId, loadCategoryMetadata]);
|
|
50888
|
+
}, [activeFilter, allVideos, mergedCounts, currentClipId, loadCategoryMetadata, isInitialTimeHandoffCategory]);
|
|
49280
50889
|
React125.useEffect(() => {
|
|
49281
50890
|
if (!currentClipId || activeFilter === "all") {
|
|
49282
50891
|
return;
|
|
@@ -49304,10 +50913,19 @@ var BottlenecksContent = ({
|
|
|
49304
50913
|
console.warn("[BottlenecksContent] Error disposing player:", e);
|
|
49305
50914
|
}
|
|
49306
50915
|
}
|
|
49307
|
-
loadingTimeoutRef.current
|
|
50916
|
+
if (loadingTimeoutRef.current) {
|
|
50917
|
+
clearTimeout(loadingTimeoutRef.current);
|
|
50918
|
+
loadingTimeoutRef.current = null;
|
|
50919
|
+
}
|
|
50920
|
+
const loadingTimeout = setTimeout(() => {
|
|
50921
|
+
if (loadingTimeoutRef.current !== loadingTimeout) {
|
|
50922
|
+
return;
|
|
50923
|
+
}
|
|
50924
|
+
loadingTimeoutRef.current = null;
|
|
49308
50925
|
console.warn("[BottlenecksContent] Loading timeout - clearing stuck loading state");
|
|
49309
50926
|
clearLoadingState();
|
|
49310
50927
|
}, 2e3);
|
|
50928
|
+
loadingTimeoutRef.current = loadingTimeout;
|
|
49311
50929
|
if (activeFilterRef.current !== categoryId) {
|
|
49312
50930
|
updateActiveFilter(categoryId);
|
|
49313
50931
|
}
|
|
@@ -49327,17 +50945,20 @@ var BottlenecksContent = ({
|
|
|
49327
50945
|
setCurrentClipId(clipId);
|
|
49328
50946
|
setAllVideos([video]);
|
|
49329
50947
|
setCurrentIndex(0);
|
|
50948
|
+
clearLoadingState();
|
|
49330
50949
|
} else {
|
|
49331
50950
|
throw new Error(`Failed to load video data for clip ${clipId}`);
|
|
49332
50951
|
}
|
|
49333
50952
|
await metadataPromise;
|
|
49334
50953
|
let metadataArray = categoryMetadataRef.current;
|
|
49335
|
-
const
|
|
49336
|
-
|
|
50954
|
+
const getMetadataClipId = (clip) => clip?.clipId || clip?.id;
|
|
50955
|
+
const metadataHasClip = (clips) => clips.some((clip) => getMetadataClipId(clip) === clipId);
|
|
50956
|
+
const fallbackHasClip = fallbackMetadata?.some((clip) => getMetadataClipId(clip) === clipId);
|
|
50957
|
+
if ((metadataArray.length === 0 || !metadataHasClip(metadataArray)) && fallbackHasClip) {
|
|
49337
50958
|
applyMetadataSnapshot(categoryId, fallbackMetadata, fallbackTotal);
|
|
49338
50959
|
metadataArray = fallbackMetadata;
|
|
49339
50960
|
}
|
|
49340
|
-
if (metadataArray.length === 0 || !metadataArray
|
|
50961
|
+
if (metadataArray.length === 0 || !metadataHasClip(metadataArray)) {
|
|
49341
50962
|
if (!fallbackHasClip) {
|
|
49342
50963
|
console.warn(`[BottlenecksContent] Clip ${clipId} not found in metadata for ${categoryId} (cache hit: ${metadataArray.length > 0}) - forcing refresh`);
|
|
49343
50964
|
await loadCategoryMetadata(categoryId, false, true);
|
|
@@ -49356,7 +50977,7 @@ var BottlenecksContent = ({
|
|
|
49356
50977
|
}
|
|
49357
50978
|
return;
|
|
49358
50979
|
}
|
|
49359
|
-
const clickedClipIndex = metadataArray.findIndex((clip) => clip
|
|
50980
|
+
const clickedClipIndex = metadataArray.findIndex((clip) => getMetadataClipId(clip) === clipId);
|
|
49360
50981
|
if (clickedClipIndex === -1) {
|
|
49361
50982
|
console.warn(`[BottlenecksContent] Clip ${clipId} not found after metadata refresh`);
|
|
49362
50983
|
if (!shouldUseMetadataNavigation(categoryId)) {
|
|
@@ -49744,6 +51365,32 @@ var BottlenecksContent = ({
|
|
|
49744
51365
|
}
|
|
49745
51366
|
return filteredVideos[currentIndex];
|
|
49746
51367
|
}, [filteredVideos, currentIndex]);
|
|
51368
|
+
const currentVideoMatchesInitialTimeHandoff = React125.useMemo(() => {
|
|
51369
|
+
if (!hasInitialTimeHandoff) {
|
|
51370
|
+
return true;
|
|
51371
|
+
}
|
|
51372
|
+
if (!currentVideo) {
|
|
51373
|
+
return false;
|
|
51374
|
+
}
|
|
51375
|
+
if (!isInitialTimeHandoffCategory(activeFilter) || !isInitialTimeHandoffCategory(currentVideo.type)) {
|
|
51376
|
+
return false;
|
|
51377
|
+
}
|
|
51378
|
+
return isTimestampInInitialTimeHandoff(
|
|
51379
|
+
currentVideo.creation_timestamp || currentVideo.timestamp || currentVideo.clip_end_time || currentVideo.clip_start_time
|
|
51380
|
+
);
|
|
51381
|
+
}, [
|
|
51382
|
+
activeFilter,
|
|
51383
|
+
currentVideo,
|
|
51384
|
+
hasInitialTimeHandoff,
|
|
51385
|
+
isInitialTimeHandoffCategory,
|
|
51386
|
+
isTimestampInInitialTimeHandoff
|
|
51387
|
+
]);
|
|
51388
|
+
const shouldHoldInitialTimeHandoffVideo = Boolean(
|
|
51389
|
+
hasInitialTimeHandoff && !currentVideoMatchesInitialTimeHandoff && (isCategoryLoading || filteredVideos.length > 0 || (mergedCounts[activeFilter] || 0) > 0)
|
|
51390
|
+
);
|
|
51391
|
+
const canRenderCurrentVideo = Boolean(
|
|
51392
|
+
filteredVideos.length > 0 && currentVideo && !isFullscreen && !shouldHoldInitialTimeHandoffVideo
|
|
51393
|
+
);
|
|
49747
51394
|
const currentLowEfficiencyClipId = currentVideo?.id || currentClipId || null;
|
|
49748
51395
|
const isCurrentLowEfficiencyClip = Boolean(
|
|
49749
51396
|
currentVideo?.type === "recent_flow_red_streak" || currentVideo?.red_flow_timeline
|
|
@@ -49910,11 +51557,111 @@ var BottlenecksContent = ({
|
|
|
49910
51557
|
}
|
|
49911
51558
|
return currentPosition;
|
|
49912
51559
|
}, [activeFilter, categoryMetadata.length, currentMetadataIndex, currentPosition, shouldUseMetadataNavigation]);
|
|
49913
|
-
const
|
|
51560
|
+
const initialTimePrefetchedMetadata = React125.useMemo(() => {
|
|
51561
|
+
if (!initialTimeFilter?.startTime || !initialTimeFilter?.endTime || !initialTimePrefetch || initialTimePrefetch.loading) {
|
|
51562
|
+
return void 0;
|
|
51563
|
+
}
|
|
51564
|
+
if (initialTimePrefetch.metadataByCategory) {
|
|
51565
|
+
return initialTimePrefetch.metadataByCategory;
|
|
51566
|
+
}
|
|
51567
|
+
if (initialTimePrefetch.categoryId === activeFilter && initialTimePrefetch.metadata.length > 0) {
|
|
51568
|
+
return { [activeFilter]: initialTimePrefetch.metadata };
|
|
51569
|
+
}
|
|
51570
|
+
return void 0;
|
|
51571
|
+
}, [
|
|
49914
51572
|
activeFilter,
|
|
51573
|
+
initialTimePrefetch,
|
|
51574
|
+
initialTimeFilter?.endTime,
|
|
51575
|
+
initialTimeFilter?.startTime
|
|
51576
|
+
]);
|
|
51577
|
+
const prefetchedExplorerMetadata = React125.useMemo(() => {
|
|
51578
|
+
if (initialTimePrefetchedMetadata) {
|
|
51579
|
+
return initialTimePrefetchedMetadata;
|
|
51580
|
+
}
|
|
51581
|
+
if (activeFilter === LOW_EFFICIENCY_CATEGORY_ID && isLowMomentsCategoryAvailable && lowMomentsPrefetch?.key?.startsWith(`${LOW_EFFICIENCY_CATEGORY_ID}-${workspaceId}-${effectiveDateString}-${effectiveShiftId}-`) && !lowMomentsPrefetch.loading && lowMomentsPrefetch.metadata.length > 0) {
|
|
51582
|
+
return { [LOW_EFFICIENCY_CATEGORY_ID]: lowMomentsPrefetch.metadata };
|
|
51583
|
+
}
|
|
51584
|
+
if (activeFilter === "idle_time" && categoryMetadataSort !== idleClipSort) {
|
|
51585
|
+
return void 0;
|
|
51586
|
+
}
|
|
51587
|
+
const metadataSnapshot = buildPrefetchedExplorerMetadata(
|
|
51588
|
+
activeFilter,
|
|
51589
|
+
categoryMetadataCategoryId,
|
|
51590
|
+
categoryMetadata
|
|
51591
|
+
);
|
|
51592
|
+
if (metadataSnapshot) {
|
|
51593
|
+
return metadataSnapshot;
|
|
51594
|
+
}
|
|
51595
|
+
if (initialTimeFilter?.startTime && initialTimeFilter?.endTime && currentVideo && currentVideo.type === activeFilter) {
|
|
51596
|
+
return {
|
|
51597
|
+
[activeFilter]: [{
|
|
51598
|
+
id: currentVideo.id,
|
|
51599
|
+
clipId: currentVideo.id,
|
|
51600
|
+
clip_timestamp: currentVideo.creation_timestamp || currentVideo.timestamp,
|
|
51601
|
+
description: currentVideo.description,
|
|
51602
|
+
severity: currentVideo.severity,
|
|
51603
|
+
category: activeFilter,
|
|
51604
|
+
duration: typeof currentVideo.duration === "number" ? currentVideo.duration : typeof currentVideo.cycle_time_seconds === "number" ? currentVideo.cycle_time_seconds : void 0,
|
|
51605
|
+
clip_start_time: currentVideo.clip_start_time,
|
|
51606
|
+
clip_end_time: currentVideo.clip_end_time,
|
|
51607
|
+
index: 0,
|
|
51608
|
+
idle_start_time: currentVideo.idle_start_time,
|
|
51609
|
+
idle_end_time: currentVideo.idle_end_time,
|
|
51610
|
+
cycle_item_count: null,
|
|
51611
|
+
red_flow_timeline: currentVideo.red_flow_timeline,
|
|
51612
|
+
red_flow_severity_score: currentVideo.red_flow_severity_score,
|
|
51613
|
+
red_flow_output_shortfall_units: currentVideo.red_flow_output_shortfall_units,
|
|
51614
|
+
red_flow_worst_minute: currentVideo.red_flow_worst_minute,
|
|
51615
|
+
red_flow_explanation_summary: currentVideo.red_flow_explanation_summary,
|
|
51616
|
+
red_flow_explanation: currentVideo.red_flow_explanation
|
|
51617
|
+
}]
|
|
51618
|
+
};
|
|
51619
|
+
}
|
|
51620
|
+
return void 0;
|
|
51621
|
+
}, [
|
|
51622
|
+
activeFilter,
|
|
51623
|
+
categoryMetadata,
|
|
49915
51624
|
categoryMetadataCategoryId,
|
|
49916
|
-
|
|
49917
|
-
|
|
51625
|
+
categoryMetadataSort,
|
|
51626
|
+
currentVideo,
|
|
51627
|
+
idleClipSort,
|
|
51628
|
+
initialTimePrefetchedMetadata,
|
|
51629
|
+
initialTimePrefetch,
|
|
51630
|
+
initialTimeFilter?.endTime,
|
|
51631
|
+
initialTimeFilter?.startTime,
|
|
51632
|
+
lowMomentsPrefetch,
|
|
51633
|
+
workspaceId,
|
|
51634
|
+
effectiveDateString,
|
|
51635
|
+
effectiveShiftId,
|
|
51636
|
+
isLowMomentsCategoryAvailable
|
|
51637
|
+
]);
|
|
51638
|
+
const externallyManagedLoadingCategories = React125.useMemo(() => {
|
|
51639
|
+
const managedCategories = {
|
|
51640
|
+
recent_flow_red_streak: Boolean(
|
|
51641
|
+
activeFilter === LOW_EFFICIENCY_CATEGORY_ID && isLowMomentsCategoryAvailable && lowMomentsPrefetch?.key?.startsWith(`${LOW_EFFICIENCY_CATEGORY_ID}-${workspaceId}-${effectiveDateString}-${effectiveShiftId}-`) && lowMomentsPrefetch.loading
|
|
51642
|
+
)
|
|
51643
|
+
};
|
|
51644
|
+
const isInitialTimeHandoffPending = Boolean(
|
|
51645
|
+
initialTimeFilter?.startTime && initialTimeFilter?.endTime && requestedInitialCategoryCandidates.length > 0 && (!initialTimePrefetch || initialTimePrefetch.loading)
|
|
51646
|
+
);
|
|
51647
|
+
if (isInitialTimeHandoffPending) {
|
|
51648
|
+
requestedInitialCategoryCandidates.forEach((categoryId) => {
|
|
51649
|
+
managedCategories[categoryId] = true;
|
|
51650
|
+
});
|
|
51651
|
+
}
|
|
51652
|
+
return managedCategories;
|
|
51653
|
+
}, [
|
|
51654
|
+
activeFilter,
|
|
51655
|
+
effectiveDateString,
|
|
51656
|
+
effectiveShiftId,
|
|
51657
|
+
initialTimeFilter?.endTime,
|
|
51658
|
+
initialTimeFilter?.startTime,
|
|
51659
|
+
initialTimePrefetch,
|
|
51660
|
+
isLowMomentsCategoryAvailable,
|
|
51661
|
+
lowMomentsPrefetch,
|
|
51662
|
+
requestedInitialCategoryCandidates,
|
|
51663
|
+
workspaceId
|
|
51664
|
+
]);
|
|
49918
51665
|
const classificationClipIds = React125.useMemo(() => {
|
|
49919
51666
|
if (!idleTimeVlmEnabled) {
|
|
49920
51667
|
return [];
|
|
@@ -50324,7 +52071,7 @@ var BottlenecksContent = ({
|
|
|
50324
52071
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-gray-600 max-w-md", children: "S3 configuration is required to load video clips. Please check your dashboard configuration." })
|
|
50325
52072
|
] });
|
|
50326
52073
|
}
|
|
50327
|
-
if (clipTypesLoading && allVideos.length === 0 && Object.keys(mergedCounts).length === 0) {
|
|
52074
|
+
if (!hasInitialTimeHandoff && clipTypesLoading && allVideos.length === 0 && Object.keys(mergedCounts).length === 0) {
|
|
50328
52075
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-grow p-4 flex items-center justify-center min-h-[calc(100dvh-12rem)]", children: /* @__PURE__ */ jsxRuntime.jsx(OptifyeLogoLoader_default, { size: "lg", message: "Loading clips..." }) });
|
|
50329
52076
|
}
|
|
50330
52077
|
if (error && error.type === "fatal" && !hasInitialLoad || clipTypesError) {
|
|
@@ -50334,7 +52081,30 @@ var BottlenecksContent = ({
|
|
|
50334
52081
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-gray-600 max-w-md", children: error?.message || clipTypesError })
|
|
50335
52082
|
] });
|
|
50336
52083
|
}
|
|
50337
|
-
const categoriesToShow =
|
|
52084
|
+
const categoriesToShow = (() => {
|
|
52085
|
+
const categories = clipTypes.length > 0 ? [...clipTypes] : [];
|
|
52086
|
+
const existingTypes = new Set(categories.map((category) => category.type));
|
|
52087
|
+
requestedInitialCategoryCandidates.forEach((categoryType) => {
|
|
52088
|
+
if (existingTypes.has(categoryType) || !hasInitialTimeHandoff && (mergedCounts[categoryType] || 0) <= 0) {
|
|
52089
|
+
return;
|
|
52090
|
+
}
|
|
52091
|
+
const fallback = CHART_HANDOFF_CATEGORY_FALLBACKS[categoryType];
|
|
52092
|
+
if (!fallback) {
|
|
52093
|
+
return;
|
|
52094
|
+
}
|
|
52095
|
+
categories.push({
|
|
52096
|
+
id: categoryType,
|
|
52097
|
+
type: categoryType,
|
|
52098
|
+
label: fallback.label,
|
|
52099
|
+
description: fallback.description,
|
|
52100
|
+
color: fallback.color,
|
|
52101
|
+
icon: fallback.icon,
|
|
52102
|
+
sort_order: 50
|
|
52103
|
+
});
|
|
52104
|
+
existingTypes.add(categoryType);
|
|
52105
|
+
});
|
|
52106
|
+
return categories;
|
|
52107
|
+
})();
|
|
50338
52108
|
console.log("[BottlenecksContent] Categories to show:", {
|
|
50339
52109
|
categoriesToShow,
|
|
50340
52110
|
categoriesToShowLength: categoriesToShow?.length,
|
|
@@ -50353,190 +52123,204 @@ var BottlenecksContent = ({
|
|
|
50353
52123
|
}
|
|
50354
52124
|
),
|
|
50355
52125
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4 lg:flex-row lg:h-full", children: [
|
|
50356
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
50357
|
-
|
|
50358
|
-
|
|
50359
|
-
|
|
50360
|
-
|
|
50361
|
-
|
|
50362
|
-
|
|
50363
|
-
|
|
50364
|
-
|
|
50365
|
-
|
|
50366
|
-
|
|
52126
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
52127
|
+
"div",
|
|
52128
|
+
{
|
|
52129
|
+
className: "min-w-0 w-full lg:flex-[3] lg:h-full",
|
|
52130
|
+
"data-qa-clips-active-filter": activeFilter || "",
|
|
52131
|
+
"data-qa-clips-current-video-type": currentVideo?.type || "",
|
|
52132
|
+
"data-qa-clips-current-video-id": currentVideo?.id || "",
|
|
52133
|
+
"data-qa-clips-current-clip-id": currentClipId || "",
|
|
52134
|
+
"data-qa-clips-filtered-count": filteredVideos.length,
|
|
52135
|
+
"data-qa-clips-all-count": allVideos.length,
|
|
52136
|
+
"data-qa-clips-current-video-matches-hour": String(currentVideoMatchesInitialTimeHandoff),
|
|
52137
|
+
"data-qa-clips-hold-hour-video": String(shouldHoldInitialTimeHandoffVideo),
|
|
52138
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-white rounded-lg shadow-sm overflow-hidden lg:h-full", children: canRenderCurrentVideo && currentVideo ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 lg:h-full", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative group lg:h-full", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full aspect-video lg:aspect-auto lg:h-full overflow-hidden rounded-md shadow-inner bg-gray-900", children: [
|
|
52139
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
52140
|
+
"div",
|
|
50367
52141
|
{
|
|
50368
|
-
ref: videoRef,
|
|
50369
|
-
src: currentVideo.src,
|
|
50370
|
-
poster: "",
|
|
50371
52142
|
className: "w-full h-full",
|
|
50372
|
-
|
|
50373
|
-
|
|
50374
|
-
|
|
50375
|
-
loop: false,
|
|
50376
|
-
externalLoadingControl: true,
|
|
50377
|
-
onReady: handleVideoReady,
|
|
50378
|
-
onPlay: handleVideoPlay,
|
|
50379
|
-
onPause: handleVideoPause,
|
|
50380
|
-
onTimeUpdate: handleTimeUpdate,
|
|
50381
|
-
onDurationChange: handleDurationChange,
|
|
50382
|
-
onEnded: handleVideoEnded,
|
|
50383
|
-
onError: handleVideoError,
|
|
50384
|
-
onLoadedData: handleLoadedData,
|
|
50385
|
-
onPlaying: handleVideoPlaying,
|
|
50386
|
-
onLoadingChange: handleVideoLoadingChange,
|
|
50387
|
-
onShare: handleShareClip,
|
|
50388
|
-
isShareLoading,
|
|
50389
|
-
isShareCopied,
|
|
50390
|
-
timelineAnnotations: currentVideo.red_flow_timeline,
|
|
50391
|
-
timelineExplanation: currentVideo.red_flow_explanation,
|
|
50392
|
-
timelineTimezone: timezone,
|
|
50393
|
-
options: videoPlayerOptions
|
|
50394
|
-
},
|
|
50395
|
-
`${currentVideo.id}-${playerInstanceNonce}-inline`
|
|
50396
|
-
)
|
|
50397
|
-
}
|
|
50398
|
-
),
|
|
50399
|
-
currentVideo.type === "recent_flow_red_streak" && !shouldDeferPlayerRenderForCrop ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
50400
|
-
RedFlowDiagnosticOverlay,
|
|
50401
|
-
{
|
|
50402
|
-
timeline: currentVideo.red_flow_timeline,
|
|
50403
|
-
explanation: currentVideo.red_flow_explanation,
|
|
50404
|
-
aiSummary: currentLowEfficiencyAiSummary,
|
|
50405
|
-
aiSummaryLoading: isCurrentLowEfficiencyAiSummaryLoading,
|
|
50406
|
-
aiSummaryError: currentLowEfficiencyAiSummaryError,
|
|
50407
|
-
className: "right-4 top-4"
|
|
50408
|
-
}
|
|
50409
|
-
) : null,
|
|
50410
|
-
showBlockingVideoLoader && !error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 z-30 flex items-center justify-center bg-black", children: /* @__PURE__ */ jsxRuntime.jsx(OptifyeLogoLoader_default, { size: "md", message: "Loading video..." }) }),
|
|
50411
|
-
!shouldDeferPlayerRenderForCrop && !isTransitioning && isVideoBuffering && !isInitialLoading && !error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 z-30 flex items-center justify-center bg-black/60", children: /* @__PURE__ */ jsxRuntime.jsx(OptifyeLogoLoader_default, { size: "md", message: "Loading video..." }) }),
|
|
50412
|
-
error && error.type === "retrying" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 z-40 flex items-center justify-center bg-black/60", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
|
|
50413
|
-
/* @__PURE__ */ jsxRuntime.jsx(OptifyeLogoLoader_default, { size: "md" }),
|
|
50414
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-white text-sm mt-4 font-medium", children: error.message })
|
|
50415
|
-
] }) }),
|
|
50416
|
-
error && error.type === "fatal" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 z-50 flex items-center justify-center bg-black/90 text-white p-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center max-w-md", children: [
|
|
50417
|
-
/* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-16 h-16 mx-auto mb-4 text-red-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.732-.833-2.5 0L4.268 16.5c-.77.833.192 2.5 1.732 2.5z" }) }),
|
|
50418
|
-
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold mb-2", children: error.code === 3 ? "Stream Corrupted" : error.code === 4 ? "Format Not Supported" : error.code === 2 ? "Network Error" : error.code === 1 ? "Loading Interrupted" : "Playback Error" }),
|
|
50419
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-300 mb-6", children: error.message }),
|
|
50420
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-3 justify-center", children: [
|
|
50421
|
-
error.canSkip && /* @__PURE__ */ jsxRuntime.jsx(
|
|
50422
|
-
"button",
|
|
50423
|
-
{
|
|
50424
|
-
onClick: () => {
|
|
50425
|
-
setError(null);
|
|
50426
|
-
videoRetryCountRef.current = 0;
|
|
50427
|
-
handleNext();
|
|
52143
|
+
style: {
|
|
52144
|
+
opacity: isTransitioning ? 0 : 1,
|
|
52145
|
+
transition: "opacity 0.1s ease-in-out"
|
|
50428
52146
|
},
|
|
50429
|
-
|
|
50430
|
-
|
|
52147
|
+
children: !shouldDeferPlayerRenderForCrop && /* @__PURE__ */ jsxRuntime.jsx(
|
|
52148
|
+
CroppedVideoPlayer,
|
|
52149
|
+
{
|
|
52150
|
+
ref: videoRef,
|
|
52151
|
+
src: currentVideo.src,
|
|
52152
|
+
poster: "",
|
|
52153
|
+
className: "w-full h-full",
|
|
52154
|
+
crop: workspaceCrop?.crop,
|
|
52155
|
+
autoplay: true,
|
|
52156
|
+
playsInline: true,
|
|
52157
|
+
loop: false,
|
|
52158
|
+
externalLoadingControl: true,
|
|
52159
|
+
onReady: handleVideoReady,
|
|
52160
|
+
onPlay: handleVideoPlay,
|
|
52161
|
+
onPause: handleVideoPause,
|
|
52162
|
+
onTimeUpdate: handleTimeUpdate,
|
|
52163
|
+
onDurationChange: handleDurationChange,
|
|
52164
|
+
onEnded: handleVideoEnded,
|
|
52165
|
+
onError: handleVideoError,
|
|
52166
|
+
onLoadedData: handleLoadedData,
|
|
52167
|
+
onPlaying: handleVideoPlaying,
|
|
52168
|
+
onLoadingChange: handleVideoLoadingChange,
|
|
52169
|
+
onShare: handleShareClip,
|
|
52170
|
+
isShareLoading,
|
|
52171
|
+
isShareCopied,
|
|
52172
|
+
timelineAnnotations: currentVideo.red_flow_timeline,
|
|
52173
|
+
timelineExplanation: currentVideo.red_flow_explanation,
|
|
52174
|
+
timelineTimezone: timezone,
|
|
52175
|
+
options: videoPlayerOptions
|
|
52176
|
+
},
|
|
52177
|
+
`${currentVideo.id}-${playerInstanceNonce}-inline`
|
|
52178
|
+
)
|
|
50431
52179
|
}
|
|
50432
52180
|
),
|
|
50433
|
-
|
|
50434
|
-
|
|
52181
|
+
currentVideo.type === "recent_flow_red_streak" && !shouldDeferPlayerRenderForCrop ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
52182
|
+
RedFlowDiagnosticOverlay,
|
|
50435
52183
|
{
|
|
50436
|
-
|
|
50437
|
-
|
|
50438
|
-
|
|
50439
|
-
|
|
50440
|
-
|
|
50441
|
-
|
|
52184
|
+
timeline: currentVideo.red_flow_timeline,
|
|
52185
|
+
explanation: currentVideo.red_flow_explanation,
|
|
52186
|
+
aiSummary: currentLowEfficiencyAiSummary,
|
|
52187
|
+
aiSummaryLoading: isCurrentLowEfficiencyAiSummaryLoading,
|
|
52188
|
+
aiSummaryError: currentLowEfficiencyAiSummaryError,
|
|
52189
|
+
className: "right-4 top-4"
|
|
50442
52190
|
}
|
|
50443
|
-
)
|
|
50444
|
-
|
|
50445
|
-
|
|
50446
|
-
|
|
50447
|
-
|
|
50448
|
-
|
|
50449
|
-
|
|
50450
|
-
|
|
50451
|
-
|
|
50452
|
-
|
|
50453
|
-
|
|
50454
|
-
|
|
50455
|
-
|
|
50456
|
-
|
|
50457
|
-
|
|
50458
|
-
|
|
50459
|
-
|
|
50460
|
-
|
|
50461
|
-
|
|
50462
|
-
|
|
50463
|
-
|
|
50464
|
-
|
|
50465
|
-
|
|
50466
|
-
|
|
50467
|
-
|
|
50468
|
-
|
|
50469
|
-
|
|
50470
|
-
|
|
50471
|
-
|
|
50472
|
-
|
|
50473
|
-
|
|
52191
|
+
) : null,
|
|
52192
|
+
showBlockingVideoLoader && !error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 z-30 flex items-center justify-center bg-black", children: /* @__PURE__ */ jsxRuntime.jsx(OptifyeLogoLoader_default, { size: "md", message: "Loading video..." }) }),
|
|
52193
|
+
!shouldDeferPlayerRenderForCrop && !isTransitioning && isVideoBuffering && !isInitialLoading && !error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 z-30 flex items-center justify-center bg-black/60", children: /* @__PURE__ */ jsxRuntime.jsx(OptifyeLogoLoader_default, { size: "md", message: "Loading video..." }) }),
|
|
52194
|
+
error && error.type === "retrying" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 z-40 flex items-center justify-center bg-black/60", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
|
|
52195
|
+
/* @__PURE__ */ jsxRuntime.jsx(OptifyeLogoLoader_default, { size: "md" }),
|
|
52196
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-white text-sm mt-4 font-medium", children: error.message })
|
|
52197
|
+
] }) }),
|
|
52198
|
+
error && error.type === "fatal" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 z-50 flex items-center justify-center bg-black/90 text-white p-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center max-w-md", children: [
|
|
52199
|
+
/* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-16 h-16 mx-auto mb-4 text-red-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.732-.833-2.5 0L4.268 16.5c-.77.833.192 2.5 1.732 2.5z" }) }),
|
|
52200
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold mb-2", children: error.code === 3 ? "Stream Corrupted" : error.code === 4 ? "Format Not Supported" : error.code === 2 ? "Network Error" : error.code === 1 ? "Loading Interrupted" : "Playback Error" }),
|
|
52201
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-300 mb-6", children: error.message }),
|
|
52202
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-3 justify-center", children: [
|
|
52203
|
+
error.canSkip && /* @__PURE__ */ jsxRuntime.jsx(
|
|
52204
|
+
"button",
|
|
52205
|
+
{
|
|
52206
|
+
onClick: () => {
|
|
52207
|
+
setError(null);
|
|
52208
|
+
videoRetryCountRef.current = 0;
|
|
52209
|
+
handleNext();
|
|
52210
|
+
},
|
|
52211
|
+
className: "px-5 py-2.5 bg-blue-600 hover:bg-blue-700 rounded-md text-sm font-medium transition-colors",
|
|
52212
|
+
children: "Skip to Next Clip"
|
|
52213
|
+
}
|
|
52214
|
+
),
|
|
52215
|
+
error.canRetry && /* @__PURE__ */ jsxRuntime.jsx(
|
|
52216
|
+
"button",
|
|
52217
|
+
{
|
|
52218
|
+
onClick: () => {
|
|
52219
|
+
videoRetryCountRef.current = 0;
|
|
52220
|
+
restartCurrentClipPlayback();
|
|
52221
|
+
},
|
|
52222
|
+
className: "px-5 py-2.5 bg-gray-600 hover:bg-gray-700 rounded-md text-sm font-medium transition-colors",
|
|
52223
|
+
children: "Retry"
|
|
52224
|
+
}
|
|
52225
|
+
)
|
|
52226
|
+
] })
|
|
52227
|
+
] }) }),
|
|
52228
|
+
(currentVideo.type === "cycle_completion" || currentVideo.type === "bottleneck" && currentVideo.description.toLowerCase().includes("cycle time")) && currentVideo.cycle_time_seconds || currentVideo.type === "idle_time" || currentVideo.type === "low_value" ? currentVideo.type === "idle_time" ? (
|
|
52229
|
+
// Show full colored badge for idle time
|
|
52230
|
+
(() => {
|
|
52231
|
+
const classification = getIdleTimeClassification(currentVideo);
|
|
52232
|
+
const confidence = getIdleTimeConfidence(currentVideo);
|
|
52233
|
+
const config = getRootCauseConfig(classification);
|
|
52234
|
+
if (!config) return null;
|
|
52235
|
+
const IconComponent = config.Icon;
|
|
52236
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
52237
|
+
idleTimeVlmEnabled && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-3 left-3 z-10", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `inline-flex max-w-[18rem] items-center gap-1.5 rounded-md border px-2.5 py-1.5 shadow-lg ${config.bgColor} ${config.borderColor}`, children: [
|
|
52238
|
+
/* @__PURE__ */ jsxRuntime.jsx(IconComponent, { className: `h-3.5 w-3.5 flex-shrink-0 ${config.iconColor}`, strokeWidth: 2.5 }),
|
|
52239
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: `truncate font-medium text-xs ${config.color}`, children: config.displayName || "Analyzing..." })
|
|
52240
|
+
] }) }),
|
|
52241
|
+
idleTimeVlmEnabled && confidence !== null && (() => {
|
|
52242
|
+
const confidencePercent = confidence * 100;
|
|
52243
|
+
let confidenceLabel = "Low";
|
|
52244
|
+
let confidenceColor = "text-red-500";
|
|
52245
|
+
if (confidencePercent > 95) {
|
|
52246
|
+
confidenceLabel = "High";
|
|
52247
|
+
confidenceColor = "text-green-500";
|
|
52248
|
+
} else if (confidencePercent >= 91) {
|
|
52249
|
+
confidenceLabel = "Medium";
|
|
52250
|
+
confidenceColor = "text-yellow-500";
|
|
52251
|
+
}
|
|
52252
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-3 right-3 z-10", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center gap-1.5 px-2.5 py-1.5 rounded-lg bg-black/70 backdrop-blur-sm shadow-lg border border-white/10", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-medium text-xs text-white", children: [
|
|
52253
|
+
"AI Confidence: ",
|
|
52254
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: confidenceColor, children: confidenceLabel })
|
|
52255
|
+
] }) }) });
|
|
52256
|
+
})()
|
|
52257
|
+
] });
|
|
50474
52258
|
})()
|
|
50475
|
-
|
|
50476
|
-
|
|
50477
|
-
|
|
50478
|
-
|
|
50479
|
-
|
|
50480
|
-
|
|
50481
|
-
|
|
50482
|
-
|
|
50483
|
-
|
|
50484
|
-
|
|
50485
|
-
|
|
50486
|
-
|
|
50487
|
-
|
|
50488
|
-
|
|
50489
|
-
|
|
50490
|
-
|
|
50491
|
-
|
|
50492
|
-
|
|
50493
|
-
|
|
50494
|
-
|
|
50495
|
-
|
|
50496
|
-
|
|
50497
|
-
|
|
50498
|
-
|
|
50499
|
-
|
|
50500
|
-
|
|
50501
|
-
|
|
50502
|
-
|
|
50503
|
-
|
|
50504
|
-
|
|
50505
|
-
|
|
50506
|
-
|
|
50507
|
-
|
|
50508
|
-
|
|
50509
|
-
|
|
50510
|
-
|
|
50511
|
-
|
|
50512
|
-
|
|
50513
|
-
] }) })
|
|
50514
|
-
|
|
50515
|
-
|
|
50516
|
-
/* Priority 5: Show "no clips found" only if we have counts and there are truly no clips for workspace */
|
|
50517
|
-
hasInitialLoad && Object.keys(mergedCounts).length > 0 && Object.values(mergedCounts).every((count) => count === 0) ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center min-h-[220px] sm:min-h-[320px] lg:h-full", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center p-8", children: [
|
|
50518
|
-
/* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-16 h-16 text-gray-300 mx-auto mb-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M15 10l4.553-2.276A1 1 0 0121 8.618v6.764a1 1 0 01-1.447.894L15 14M5 18h8a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z" }) }),
|
|
50519
|
-
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-xl font-medium text-gray-700 mb-2", children: "No Clips Found" }),
|
|
50520
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-gray-500", children: "There were no video clips found for this workspace today." })
|
|
50521
|
-
] }) }) : (
|
|
50522
|
-
/* Priority 5.5: Show "no folder selected" if activeFilter is empty */
|
|
50523
|
-
hasInitialLoad && !activeFilter ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center min-h-[220px] sm:min-h-[320px] lg:h-full", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center p-8", children: [
|
|
50524
|
-
/* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-16 h-16 text-gray-300 mx-auto mb-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M15 10l4.553-2.276A1 1 0 0121 8.618v6.764a1 1 0 01-1.447.894L15 14M5 18h8a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z" }) }),
|
|
50525
|
-
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-xl font-medium text-gray-700 mb-2", children: "No Folder Selected" }),
|
|
50526
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-gray-500", children: "Please select a folder to view clips." })
|
|
50527
|
-
] }) }) : (
|
|
50528
|
-
/* Priority 6: Show "no matching clips" only if we have data loaded and specifically no clips for this filter */
|
|
50529
|
-
hasInitialLoad && (mergedCounts[activeFilter] || 0) === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center min-h-[220px] sm:min-h-[320px] lg:h-full", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center p-8", children: [
|
|
52259
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-3 left-3 z-10 bg-black/60 backdrop-blur-sm px-3 py-1.5 rounded-lg text-white shadow-lg text-xs", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center", children: [
|
|
52260
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `flex-shrink-0 h-2.5 w-2.5 rounded-full ${currentVideo.type === "low_value" ? "bg-purple-400" : isPercentileCategory(activeFilterRef.current) ? activeFilterRef.current === "fast-cycles" ? "bg-green-600" : activeFilterRef.current === "slow-cycles" ? "bg-red-700" : "bg-orange-500" : currentVideo.type === "cycle_completion" ? "bg-blue-600" : "bg-gray-500"} mr-2 animate-pulse` }),
|
|
52261
|
+
(currentVideo.type === "cycle_completion" || currentVideo.type === "bottleneck" && currentVideo.description.toLowerCase().includes("cycle time")) && currentVideo.cycle_time_seconds ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "opacity-90 font-mono bg-black/30 px-2 py-0.5 rounded", children: [
|
|
52262
|
+
"Cycle time: ",
|
|
52263
|
+
currentVideo.cycle_time_seconds.toFixed(1),
|
|
52264
|
+
"s"
|
|
52265
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
52266
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium mr-2", children: getClipTypeLabel(currentVideo) }),
|
|
52267
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-80 hidden sm:inline", children: currentVideo.description })
|
|
52268
|
+
] })
|
|
52269
|
+
] }) }) : (
|
|
52270
|
+
/* Right side display for other video types */
|
|
52271
|
+
currentVideo.type === "idle_time" ? (
|
|
52272
|
+
// Show full colored badge for idle time
|
|
52273
|
+
(() => {
|
|
52274
|
+
const classification = getIdleTimeClassification(currentVideo);
|
|
52275
|
+
const confidence = getIdleTimeConfidence(currentVideo);
|
|
52276
|
+
const config = getRootCauseConfig(classification);
|
|
52277
|
+
if (!config) return null;
|
|
52278
|
+
const IconComponent = config.Icon;
|
|
52279
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
52280
|
+
idleTimeVlmEnabled && confidence !== null && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-3 left-3 z-10", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center gap-1.5 px-2.5 py-1.5 rounded-lg bg-black/70 backdrop-blur-sm shadow-lg border border-white/10", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-medium text-xs text-white", children: [
|
|
52281
|
+
"AI Confidence: ",
|
|
52282
|
+
(confidence * 100).toFixed(0),
|
|
52283
|
+
"%"
|
|
52284
|
+
] }) }) }),
|
|
52285
|
+
idleTimeVlmEnabled && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-3 right-3 z-10", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `inline-flex max-w-[18rem] items-center gap-1.5 rounded-md border px-2.5 py-1.5 shadow-lg ${config.bgColor} ${config.borderColor}`, children: [
|
|
52286
|
+
/* @__PURE__ */ jsxRuntime.jsx(IconComponent, { className: `h-3.5 w-3.5 flex-shrink-0 ${config.iconColor}`, strokeWidth: 2.5 }),
|
|
52287
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: `truncate font-medium text-xs ${config.color}`, children: config.displayName || "Analyzing..." })
|
|
52288
|
+
] }) })
|
|
52289
|
+
] });
|
|
52290
|
+
})()
|
|
52291
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: `absolute top-3 z-10 bg-black/60 backdrop-blur-sm px-3 py-1.5 rounded-lg text-white shadow-lg text-xs ${currentVideo.type === "recent_flow_red_streak" ? "left-3" : "right-3"}`, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center", children: [
|
|
52292
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `flex-shrink-0 h-2.5 w-2.5 rounded-full ${getSeverityColor(currentVideo.severity)} mr-2 animate-pulse` }),
|
|
52293
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium mr-2", children: getClipTypeLabel(currentVideo) }),
|
|
52294
|
+
currentVideo.type !== "recent_flow_red_streak" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-80 hidden sm:inline", children: currentVideo.description })
|
|
52295
|
+
] }) })
|
|
52296
|
+
)
|
|
52297
|
+
] }) }) }) : shouldHoldInitialTimeHandoffVideo ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 lg:h-full", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative lg:h-full", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative w-full min-h-[220px] sm:min-h-[320px] lg:min-h-0 lg:h-full overflow-hidden rounded-md shadow-inner bg-gray-900 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(OptifyeLogoLoader_default, { size: "md", message: "Loading clips..." }) }) }) }) : (
|
|
52298
|
+
/* Priority 5: Show "no clips found" only if we have counts and there are truly no clips for workspace */
|
|
52299
|
+
hasInitialLoad && Object.keys(mergedCounts).length > 0 && Object.values(mergedCounts).every((count) => count === 0) ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center min-h-[220px] sm:min-h-[320px] lg:h-full", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center p-8", children: [
|
|
50530
52300
|
/* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-16 h-16 text-gray-300 mx-auto mb-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M15 10l4.553-2.276A1 1 0 0121 8.618v6.764a1 1 0 01-1.447.894L15 14M5 18h8a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z" }) }),
|
|
50531
|
-
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-xl font-medium text-gray-700 mb-2", children: "No
|
|
50532
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-gray-500", children: "There
|
|
52301
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-xl font-medium text-gray-700 mb-2", children: "No Clips Found" }),
|
|
52302
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-gray-500", children: "There were no video clips found for this workspace today." })
|
|
50533
52303
|
] }) }) : (
|
|
50534
|
-
/* Priority
|
|
50535
|
-
|
|
52304
|
+
/* Priority 5.5: Show "no folder selected" if activeFilter is empty */
|
|
52305
|
+
hasInitialLoad && !activeFilter ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center min-h-[220px] sm:min-h-[320px] lg:h-full", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center p-8", children: [
|
|
52306
|
+
/* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-16 h-16 text-gray-300 mx-auto mb-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M15 10l4.553-2.276A1 1 0 0121 8.618v6.764a1 1 0 01-1.447.894L15 14M5 18h8a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z" }) }),
|
|
52307
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-xl font-medium text-gray-700 mb-2", children: "No Folder Selected" }),
|
|
52308
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-gray-500", children: "Please select a folder to view clips." })
|
|
52309
|
+
] }) }) : (
|
|
52310
|
+
/* Priority 6: Show "no matching clips" only if we have data loaded and specifically no clips for this filter */
|
|
52311
|
+
hasInitialLoad && (mergedCounts[activeFilter] || 0) === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center min-h-[220px] sm:min-h-[320px] lg:h-full", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center p-8", children: [
|
|
52312
|
+
/* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-16 h-16 text-gray-300 mx-auto mb-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M15 10l4.553-2.276A1 1 0 0121 8.618v6.764a1 1 0 01-1.447.894L15 14M5 18h8a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z" }) }),
|
|
52313
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-xl font-medium text-gray-700 mb-2", children: "No Matching Clips" }),
|
|
52314
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-gray-500", children: "There are no clips matching the selected filter." })
|
|
52315
|
+
] }) }) : (
|
|
52316
|
+
/* Priority 7: Default loading state for any other case */
|
|
52317
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 lg:h-full", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative lg:h-full", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative w-full min-h-[220px] sm:min-h-[320px] lg:min-h-0 lg:h-full overflow-hidden rounded-md shadow-inner bg-gray-900 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(OptifyeLogoLoader_default, { size: "md", message: "Loading..." }) }) }) })
|
|
52318
|
+
)
|
|
52319
|
+
)
|
|
50536
52320
|
)
|
|
50537
|
-
)
|
|
50538
|
-
|
|
50539
|
-
)
|
|
52321
|
+
) })
|
|
52322
|
+
}
|
|
52323
|
+
),
|
|
50540
52324
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full lg:flex-shrink-0 lg:flex-[1] lg:min-w-[280px] lg:max-w-[320px] lg:h-full", children: triageMode ? (
|
|
50541
52325
|
/* Triage Mode - Direct tile view for cycle completions and idle time */
|
|
50542
52326
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-lg shadow-sm h-full overflow-hidden flex flex-col", children: [
|
|
@@ -50671,7 +52455,7 @@ var BottlenecksContent = ({
|
|
|
50671
52455
|
})),
|
|
50672
52456
|
videos: allVideos || [],
|
|
50673
52457
|
activeFilter,
|
|
50674
|
-
currentVideoId: currentVideo?.id,
|
|
52458
|
+
currentVideoId: currentVideo?.id || currentClipId || void 0,
|
|
50675
52459
|
counts: mergedCounts,
|
|
50676
52460
|
isReady: hasInitialLoad,
|
|
50677
52461
|
prefetchedPercentileCounts: isFastSlowClipFiltersEnabled ? prefetchedPercentileCounts || void 0 : void 0,
|
|
@@ -50685,11 +52469,9 @@ var BottlenecksContent = ({
|
|
|
50685
52469
|
idleTimeVlmEnabled,
|
|
50686
52470
|
showPercentileCycleFilters: isFastSlowClipFiltersEnabled,
|
|
50687
52471
|
prefetchedClipMetadata: prefetchedExplorerMetadata,
|
|
50688
|
-
|
|
50689
|
-
|
|
50690
|
-
|
|
50691
|
-
)
|
|
50692
|
-
},
|
|
52472
|
+
prefetchedClipTotals: initialTimePrefetch?.loading ? void 0 : initialTimePrefetch?.totalsByCategory,
|
|
52473
|
+
prefetchedPercentileClips: initialTimePrefetch?.loading ? void 0 : initialTimePrefetch?.percentileClipsByCategory,
|
|
52474
|
+
externallyManagedLoadingCategories,
|
|
50693
52475
|
activeCategoryLoading: isCategoryLoading,
|
|
50694
52476
|
idleClipSort,
|
|
50695
52477
|
onIdleClipSortChange: setIdleClipSort,
|
|
@@ -68482,17 +70264,7 @@ var setSessionSeenValue = (key) => {
|
|
|
68482
70264
|
};
|
|
68483
70265
|
var buildAllGreenCelebrationSeenKey = (identity) => `${ALL_GREEN_CELEBRATION_SEEN_PREFIX}${identity}`;
|
|
68484
70266
|
var buildAllGreenMilestoneSeenKey = (identity, milestoneSeconds) => `${ALL_GREEN_MILESTONE_SEEN_PREFIX}${identity}:${milestoneSeconds}`;
|
|
68485
|
-
var LINE_SELECTOR_INDICATOR_VERSION = "
|
|
68486
|
-
var LineSelectorIncidentIcon = ({ lineId }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
68487
|
-
"span",
|
|
68488
|
-
{
|
|
68489
|
-
"data-testid": `line-selector-incident-icon-${lineId}`,
|
|
68490
|
-
"aria-label": "Line needs attention",
|
|
68491
|
-
role: "img",
|
|
68492
|
-
className: "inline-flex h-5 w-5 flex-shrink-0 items-center justify-center rounded-full border border-rose-200 bg-white text-[13px] font-semibold leading-none text-rose-600 shadow-[0_1px_2px_rgba(15,23,42,0.06)]",
|
|
68493
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", className: "-mt-px", children: "!" })
|
|
68494
|
-
}
|
|
68495
|
-
);
|
|
70267
|
+
var LINE_SELECTOR_INDICATOR_VERSION = "line_signal_dots_v1";
|
|
68496
70268
|
var LoadingPageCmp = LoadingPage_default;
|
|
68497
70269
|
var LoadingOverlayCmp = LoadingOverlay_default;
|
|
68498
70270
|
function HomeView({
|
|
@@ -68832,8 +70604,8 @@ function HomeView({
|
|
|
68832
70604
|
const currentIsCurrentScopeResolved = isBootstrapMonitorMode ? bootstrapMonitor.isCurrentScopeResolved : legacyIsCurrentScopeResolved;
|
|
68833
70605
|
const currentMetricsError = isBootstrapMonitorMode ? bootstrapMonitor.error : legacyMetricsError;
|
|
68834
70606
|
const currentRefetchMetrics = isBootstrapMonitorMode ? bootstrapMonitor.refetch : refetchLegacyMetrics;
|
|
68835
|
-
const
|
|
68836
|
-
const
|
|
70607
|
+
const lineSelectorSignalStatusByLine = React125.useMemo(() => {
|
|
70608
|
+
const statusByLine = /* @__PURE__ */ new Map();
|
|
68837
70609
|
const legend = currentEfficiencyLegend || DEFAULT_EFFICIENCY_LEGEND;
|
|
68838
70610
|
const addRows = (rows) => {
|
|
68839
70611
|
(rows || []).forEach((row) => {
|
|
@@ -68841,40 +70613,36 @@ function HomeView({
|
|
|
68841
70613
|
if (!lineId) {
|
|
68842
70614
|
return;
|
|
68843
70615
|
}
|
|
68844
|
-
if (row?.red_flow_incident?.active === true) {
|
|
68845
|
-
indicatorByLine.set(lineId, "incident");
|
|
68846
|
-
return;
|
|
68847
|
-
}
|
|
68848
|
-
if (indicatorByLine.get(lineId) === "incident") {
|
|
68849
|
-
return;
|
|
68850
|
-
}
|
|
68851
70616
|
const status = getKpiSignalStatus(row?.line_signal, legend);
|
|
68852
|
-
if (status
|
|
68853
|
-
|
|
70617
|
+
if (status) {
|
|
70618
|
+
statusByLine.set(lineId, status);
|
|
68854
70619
|
}
|
|
68855
70620
|
});
|
|
68856
70621
|
};
|
|
68857
70622
|
addRows(currentSelectorLineMetrics);
|
|
68858
70623
|
addRows(currentLineMetrics);
|
|
68859
|
-
return
|
|
70624
|
+
return statusByLine;
|
|
68860
70625
|
}, [currentEfficiencyLegend, currentLineMetrics, currentSelectorLineMetrics]);
|
|
68861
|
-
const
|
|
68862
|
-
let
|
|
68863
|
-
let
|
|
70626
|
+
const lineSelectorSignalDotStats = React125.useMemo(() => {
|
|
70627
|
+
let stableSignalLineCount = 0;
|
|
70628
|
+
let warningSignalLineCount = 0;
|
|
70629
|
+
let attentionSignalLineCount = 0;
|
|
68864
70630
|
visibleLineIds.forEach((lineId) => {
|
|
68865
|
-
const
|
|
68866
|
-
if (
|
|
68867
|
-
|
|
68868
|
-
} else if (
|
|
68869
|
-
|
|
70631
|
+
const status = lineSelectorSignalStatusByLine.get(lineId);
|
|
70632
|
+
if (status === "stable") {
|
|
70633
|
+
stableSignalLineCount += 1;
|
|
70634
|
+
} else if (status === "warning") {
|
|
70635
|
+
warningSignalLineCount += 1;
|
|
70636
|
+
} else if (status === "attention") {
|
|
70637
|
+
attentionSignalLineCount += 1;
|
|
68870
70638
|
}
|
|
68871
70639
|
});
|
|
68872
70640
|
return {
|
|
68873
|
-
|
|
68874
|
-
|
|
68875
|
-
|
|
70641
|
+
stableSignalLineCount,
|
|
70642
|
+
warningSignalLineCount,
|
|
70643
|
+
attentionSignalLineCount
|
|
68876
70644
|
};
|
|
68877
|
-
}, [
|
|
70645
|
+
}, [lineSelectorSignalStatusByLine, visibleLineIds]);
|
|
68878
70646
|
const metricsDisplayNames = React125.useMemo(() => {
|
|
68879
70647
|
const nextDisplayNames = {};
|
|
68880
70648
|
currentWorkspaceMetrics.forEach((workspace) => {
|
|
@@ -69731,12 +71499,13 @@ function HomeView({
|
|
|
69731
71499
|
new_line_ids: normalizedLineIds,
|
|
69732
71500
|
selected_line_count: normalizedLineIds.length,
|
|
69733
71501
|
selection_mode: isAllLinesSelection(normalizedLineIds) ? "all" : normalizedLineIds.length === 1 ? "single" : "custom",
|
|
69734
|
-
|
|
69735
|
-
|
|
71502
|
+
stable_signal_line_count: lineSelectorSignalDotStats.stableSignalLineCount,
|
|
71503
|
+
warning_signal_line_count: lineSelectorSignalDotStats.warningSignalLineCount,
|
|
71504
|
+
attention_signal_line_count: lineSelectorSignalDotStats.attentionSignalLineCount,
|
|
69736
71505
|
selector_indicator_version: LINE_SELECTOR_INDICATOR_VERSION,
|
|
69737
71506
|
line_name: getLineSelectionLabel(normalizedLineIds)
|
|
69738
71507
|
});
|
|
69739
|
-
}, [factoryViewId, getLineSelectionLabel, getTrackedLineScope,
|
|
71508
|
+
}, [factoryViewId, getLineSelectionLabel, getTrackedLineScope, lineSelectorSignalDotStats, selectedLineIds, selectedLineIdsKey, visibleLineIds]);
|
|
69740
71509
|
React125.useCallback(() => {
|
|
69741
71510
|
updateSelectedLineIds(visibleLineIds);
|
|
69742
71511
|
}, [updateSelectedLineIds, visibleLineIds]);
|
|
@@ -69795,8 +71564,9 @@ function HomeView({
|
|
|
69795
71564
|
selected_line_ids: selectedLineIds,
|
|
69796
71565
|
selected_line_count: selectedLineIds.length,
|
|
69797
71566
|
is_all_lines: isAllLinesSelection(selectedLineIds),
|
|
69798
|
-
|
|
69799
|
-
|
|
71567
|
+
stable_signal_line_count: lineSelectorSignalDotStats.stableSignalLineCount,
|
|
71568
|
+
warning_signal_line_count: lineSelectorSignalDotStats.warningSignalLineCount,
|
|
71569
|
+
attention_signal_line_count: lineSelectorSignalDotStats.attentionSignalLineCount,
|
|
69800
71570
|
selector_indicator_version: LINE_SELECTOR_INDICATOR_VERSION
|
|
69801
71571
|
});
|
|
69802
71572
|
}
|
|
@@ -69838,7 +71608,8 @@ function HomeView({
|
|
|
69838
71608
|
] }),
|
|
69839
71609
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-h-56 space-y-0.5 overflow-y-auto pr-1", children: visibleLineIds.map((lineId) => {
|
|
69840
71610
|
const isChecked = pendingSelectedLineIds.includes(lineId);
|
|
69841
|
-
const
|
|
71611
|
+
const signalStatus = lineSelectorSignalStatusByLine.get(lineId);
|
|
71612
|
+
const signalDotClass = signalStatus === "stable" ? "bg-green-500" : signalStatus === "warning" ? "bg-yellow-400" : signalStatus === "attention" ? "bg-red-500" : "";
|
|
69842
71613
|
const lineLabel = mergedLineNames[lineId] || `Line ${lineId.substring(0, 4)}`;
|
|
69843
71614
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
69844
71615
|
"label",
|
|
@@ -69866,11 +71637,11 @@ function HomeView({
|
|
|
69866
71637
|
}
|
|
69867
71638
|
),
|
|
69868
71639
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", children: lineLabel }),
|
|
69869
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-5 w-5 flex-shrink-0 items-center justify-center", children:
|
|
71640
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-2.5 w-2.5 flex-shrink-0 items-center justify-center", children: signalStatus ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
69870
71641
|
"span",
|
|
69871
71642
|
{
|
|
69872
71643
|
"data-testid": `line-selector-signal-dot-${lineId}`,
|
|
69873
|
-
className:
|
|
71644
|
+
className: `h-2 w-2 rounded-full ${signalDotClass}`,
|
|
69874
71645
|
"aria-hidden": "true"
|
|
69875
71646
|
}
|
|
69876
71647
|
) : null })
|
|
@@ -69902,8 +71673,8 @@ function HomeView({
|
|
|
69902
71673
|
mergedLineNames,
|
|
69903
71674
|
selectedLineIds,
|
|
69904
71675
|
pendingSelectedLineIds,
|
|
69905
|
-
|
|
69906
|
-
|
|
71676
|
+
lineSelectorSignalStatusByLine,
|
|
71677
|
+
lineSelectorSignalDotStats,
|
|
69907
71678
|
displayMode,
|
|
69908
71679
|
slideshowActiveLineId,
|
|
69909
71680
|
visibleLineIds,
|
|
@@ -70503,9 +72274,7 @@ function withWorkspaceDisplayNames(Component3, options = {}) {
|
|
|
70503
72274
|
await preInitializeWorkspaceDisplayNames(selectedLineId);
|
|
70504
72275
|
}
|
|
70505
72276
|
} else if (lineIdArray.length > 0) {
|
|
70506
|
-
await
|
|
70507
|
-
lineIdArray.map((lineId) => preInitializeWorkspaceDisplayNames(lineId))
|
|
70508
|
-
);
|
|
72277
|
+
await preInitializeWorkspaceDisplayNamesForLines(lineIdArray);
|
|
70509
72278
|
} else {
|
|
70510
72279
|
await preInitializeWorkspaceDisplayNames();
|
|
70511
72280
|
}
|
|
@@ -80969,7 +82738,6 @@ var TargetsViewUI = ({
|
|
|
80969
82738
|
skuRequired = false,
|
|
80970
82739
|
onUpdateWorkspaceSelectedSku
|
|
80971
82740
|
}) => {
|
|
80972
|
-
const { displayNames: workspaceDisplayNames } = useWorkspaceDisplayNames();
|
|
80973
82741
|
const mobileMenuContext = useMobileMenu();
|
|
80974
82742
|
useHideMobileHeader(!!mobileMenuContext);
|
|
80975
82743
|
if (isLoading) {
|
|
@@ -81151,7 +82919,7 @@ var TargetsViewUI = ({
|
|
|
81151
82919
|
] })
|
|
81152
82920
|
] }) }),
|
|
81153
82921
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y divide-gray-100", children: line.workspaces.map((workspace) => {
|
|
81154
|
-
const formattedName =
|
|
82922
|
+
const formattedName = workspace.displayName || formatWorkspaceName(workspace.name, lineId);
|
|
81155
82923
|
const realSkuOptions = (workspace.skuRows || []).filter((r2) => !r2.is_dummy);
|
|
81156
82924
|
const showSkuDropdown = !!onUpdateWorkspaceSelectedSku && realSkuOptions.length >= 1;
|
|
81157
82925
|
const isPlanLocked = !!workspace.productionPlanLock?.locked;
|
|
@@ -81702,6 +83470,7 @@ var TargetsView = ({
|
|
|
81702
83470
|
return {
|
|
81703
83471
|
id: ws.id,
|
|
81704
83472
|
name: ws.workspace_id,
|
|
83473
|
+
displayName: ws.display_name || ws.workspace_id,
|
|
81705
83474
|
targetPPH: selectedRow?.pph_threshold ?? (threshold?.pph_threshold ? Math.round(threshold.pph_threshold) : ""),
|
|
81706
83475
|
targetCycleTime: selectedRow?.ideal_cycle_time ?? (threshold?.ideal_cycle_time ?? ""),
|
|
81707
83476
|
targetDayOutput: selectedRow?.total_day_output ?? (threshold?.total_day_output ?? ""),
|
|
@@ -81760,6 +83529,7 @@ var TargetsView = ({
|
|
|
81760
83529
|
return {
|
|
81761
83530
|
id: ws.id,
|
|
81762
83531
|
name: ws.workspace_id,
|
|
83532
|
+
displayName: ws.display_name || ws.workspace_id,
|
|
81763
83533
|
targetPPH: "",
|
|
81764
83534
|
targetCycleTime: "",
|
|
81765
83535
|
targetDayOutput: "",
|
|
@@ -82240,15 +84010,31 @@ var TargetsView = ({
|
|
|
82240
84010
|
const handleUpdateWorkspaceDisplayName = React125.useCallback(async (workspaceId, displayName) => {
|
|
82241
84011
|
try {
|
|
82242
84012
|
const updated = await workspaceService.updateWorkspaceDisplayName(workspaceId, displayName);
|
|
84013
|
+
const nextDisplayName = updated?.display_name || displayName;
|
|
84014
|
+
setAllShiftsData((prev) => {
|
|
84015
|
+
const next = { ...prev };
|
|
84016
|
+
Object.entries(prev).forEach(([shiftId, shiftData]) => {
|
|
84017
|
+
const numericShiftId = Number(shiftId);
|
|
84018
|
+
const updatedShiftData = {};
|
|
84019
|
+
Object.entries(shiftData).forEach(([lineId, line]) => {
|
|
84020
|
+
updatedShiftData[lineId] = {
|
|
84021
|
+
...line,
|
|
84022
|
+
workspaces: line.workspaces.map(
|
|
84023
|
+
(ws) => ws.id === workspaceId ? { ...ws, displayName: nextDisplayName } : ws
|
|
84024
|
+
)
|
|
84025
|
+
};
|
|
84026
|
+
});
|
|
84027
|
+
next[numericShiftId] = updatedShiftData;
|
|
84028
|
+
});
|
|
84029
|
+
return next;
|
|
84030
|
+
});
|
|
82243
84031
|
if (updated?.line_id && updated?.workspace_id) {
|
|
82244
84032
|
upsertWorkspaceDisplayNameInCache({
|
|
82245
84033
|
lineId: updated.line_id,
|
|
82246
84034
|
workspaceId: updated.workspace_id,
|
|
82247
|
-
displayName:
|
|
84035
|
+
displayName: nextDisplayName,
|
|
82248
84036
|
enabled: updated?.enable
|
|
82249
84037
|
});
|
|
82250
|
-
} else {
|
|
82251
|
-
await forceRefreshWorkspaceDisplayNames();
|
|
82252
84038
|
}
|
|
82253
84039
|
sonner.toast.success("Workspace name updated successfully");
|
|
82254
84040
|
} catch (error) {
|
|
@@ -82292,9 +84078,8 @@ var TargetsView = ({
|
|
|
82292
84078
|
}
|
|
82293
84079
|
);
|
|
82294
84080
|
};
|
|
82295
|
-
var
|
|
82296
|
-
var
|
|
82297
|
-
var AuthenticatedTargetsView = withAuth(React125__namespace.default.memo(TargetsViewWithDisplayNames));
|
|
84081
|
+
var TargetsView_default = TargetsView;
|
|
84082
|
+
var AuthenticatedTargetsView = withAuth(React125__namespace.default.memo(TargetsView));
|
|
82298
84083
|
function useTimezone(options = {}) {
|
|
82299
84084
|
const dashboardConfig = useDashboardConfig();
|
|
82300
84085
|
const workspaceConfig = useWorkspaceConfig();
|
|
@@ -82474,17 +84259,22 @@ var WorkspaceHourSummaryPanel = ({
|
|
|
82474
84259
|
return;
|
|
82475
84260
|
}
|
|
82476
84261
|
autoSummaryKeyRef.current = requestKey;
|
|
82477
|
-
|
|
82478
|
-
|
|
82479
|
-
|
|
82480
|
-
|
|
82481
|
-
|
|
82482
|
-
|
|
82483
|
-
|
|
82484
|
-
|
|
82485
|
-
|
|
82486
|
-
|
|
82487
|
-
|
|
84262
|
+
const summaryTimer = window.setTimeout(() => {
|
|
84263
|
+
void summarize({
|
|
84264
|
+
workspaceId,
|
|
84265
|
+
companyId,
|
|
84266
|
+
date,
|
|
84267
|
+
shiftId,
|
|
84268
|
+
hourIndex: selectedHour.hourIndex,
|
|
84269
|
+
hourStart: selectedHour.startTime,
|
|
84270
|
+
hourEnd: selectedHour.endTime,
|
|
84271
|
+
forceRefresh: false,
|
|
84272
|
+
selectionSource: selectedHour.source ?? "unknown"
|
|
84273
|
+
}).catch(() => void 0);
|
|
84274
|
+
}, 1500);
|
|
84275
|
+
return () => {
|
|
84276
|
+
window.clearTimeout(summaryTimer);
|
|
84277
|
+
};
|
|
82488
84278
|
}, [canSummarize, companyId, date, selectedHour, selectedKey, shiftId, summarize, workspaceId]);
|
|
82489
84279
|
if (!selectedHour) {
|
|
82490
84280
|
return null;
|
|
@@ -82668,10 +84458,18 @@ var WorkspaceDetailView = ({
|
|
|
82668
84458
|
setSelectedHour(null);
|
|
82669
84459
|
}, [workspaceId, date, shift]);
|
|
82670
84460
|
const dashboardConfig = useDashboardConfig();
|
|
84461
|
+
const isClipsEnabled = dashboardConfig?.clipsConfig?.enabled ?? true;
|
|
82671
84462
|
const { legend: efficiencyLegend } = useEfficiencyLegend();
|
|
82672
84463
|
const prewarmedClipsRef = React125.useRef(/* @__PURE__ */ new Set());
|
|
82673
84464
|
const prewarmInFlightRef = React125.useRef(/* @__PURE__ */ new Set());
|
|
82674
84465
|
const [lowMomentsPrefetch, setLowMomentsPrefetch] = React125.useState(null);
|
|
84466
|
+
const selectedHourClipPrefetchInFlightRef = React125.useRef(/* @__PURE__ */ new Set());
|
|
84467
|
+
const selectedHourClipPrefetchAbortRef = React125.useRef(null);
|
|
84468
|
+
const [initialTimePrefetch, setInitialTimePrefetch] = React125.useState(null);
|
|
84469
|
+
const {
|
|
84470
|
+
isFastSlowClipFiltersEnabled,
|
|
84471
|
+
isResolved: isFastSlowClipFiltersResolved
|
|
84472
|
+
} = useCompanyFastSlowClipFiltersEnabled();
|
|
82675
84473
|
const [aiSummaryHour, setAiSummaryHour] = React125.useState(null);
|
|
82676
84474
|
const buildHourlyOutputActionTrackingProps = React125.useCallback((payload) => ({
|
|
82677
84475
|
workspace_id: workspaceId,
|
|
@@ -82701,24 +84499,286 @@ var WorkspaceDetailView = ({
|
|
|
82701
84499
|
timezone,
|
|
82702
84500
|
workspaceId
|
|
82703
84501
|
]);
|
|
84502
|
+
const prefetchClipsForSelectedHour = React125.useCallback((hour) => {
|
|
84503
|
+
if (!isClipsEnabled || !dashboardConfig?.s3Config || !workspaceId || !supabase) {
|
|
84504
|
+
return;
|
|
84505
|
+
}
|
|
84506
|
+
const resolvedDate = date || getOperationalDate(timezone);
|
|
84507
|
+
const resolvedShiftId = parsedShiftId ?? selectedShift;
|
|
84508
|
+
if (!resolvedDate || resolvedShiftId === null || resolvedShiftId === void 0) {
|
|
84509
|
+
return;
|
|
84510
|
+
}
|
|
84511
|
+
const categoryId = "cycle_completion";
|
|
84512
|
+
const regularCategoryIds = ["cycle_completion", "idle_time", "recent_flow_red_streak"];
|
|
84513
|
+
const percentileCategoryIds = isFastSlowClipFiltersEnabled ? ["fast-cycles", "slow-cycles"] : [];
|
|
84514
|
+
const allPrefetchCategoryIds = [...regularCategoryIds, ...percentileCategoryIds];
|
|
84515
|
+
const effectiveTimezone = hour.timezone || timezone;
|
|
84516
|
+
const prefetchKey = [
|
|
84517
|
+
workspaceId,
|
|
84518
|
+
resolvedDate,
|
|
84519
|
+
resolvedShiftId,
|
|
84520
|
+
hour.startTime,
|
|
84521
|
+
hour.endTime,
|
|
84522
|
+
effectiveTimezone || "",
|
|
84523
|
+
allPrefetchCategoryIds.join(",")
|
|
84524
|
+
].join("|");
|
|
84525
|
+
if (initialTimePrefetch?.key === prefetchKey && !initialTimePrefetch.loading) {
|
|
84526
|
+
return;
|
|
84527
|
+
}
|
|
84528
|
+
if (selectedHourClipPrefetchInFlightRef.current.has(prefetchKey)) {
|
|
84529
|
+
return;
|
|
84530
|
+
}
|
|
84531
|
+
selectedHourClipPrefetchAbortRef.current?.abort();
|
|
84532
|
+
const controller = new AbortController();
|
|
84533
|
+
selectedHourClipPrefetchAbortRef.current = controller;
|
|
84534
|
+
selectedHourClipPrefetchInFlightRef.current.add(prefetchKey);
|
|
84535
|
+
const existingSnapshot = initialTimePrefetch?.key === prefetchKey ? initialTimePrefetch : null;
|
|
84536
|
+
setInitialTimePrefetch({
|
|
84537
|
+
key: prefetchKey,
|
|
84538
|
+
categoryId,
|
|
84539
|
+
metadata: existingSnapshot?.metadata || [],
|
|
84540
|
+
metadataByCategory: existingSnapshot?.metadataByCategory || {},
|
|
84541
|
+
totalsByCategory: existingSnapshot?.totalsByCategory || {},
|
|
84542
|
+
percentileClipsByCategory: existingSnapshot?.percentileClipsByCategory || {},
|
|
84543
|
+
firstVideo: existingSnapshot?.firstVideo || null,
|
|
84544
|
+
total: existingSnapshot?.total || 0,
|
|
84545
|
+
loading: true,
|
|
84546
|
+
error: null
|
|
84547
|
+
});
|
|
84548
|
+
const s3Service = videoPrefetchManager.getS3Service(dashboardConfig);
|
|
84549
|
+
const fetchHourlySnapshot = async () => {
|
|
84550
|
+
try {
|
|
84551
|
+
const response = await fetchWithSupabaseAuth(supabase, "/api/clips/supabase", {
|
|
84552
|
+
method: "POST",
|
|
84553
|
+
headers: {
|
|
84554
|
+
"Content-Type": "application/json"
|
|
84555
|
+
},
|
|
84556
|
+
body: JSON.stringify({
|
|
84557
|
+
action: "hourly-snapshot",
|
|
84558
|
+
workspaceId,
|
|
84559
|
+
date: resolvedDate,
|
|
84560
|
+
shift: resolvedShiftId,
|
|
84561
|
+
startTime: hour.startTime,
|
|
84562
|
+
endTime: hour.endTime,
|
|
84563
|
+
timeFilterTimezone: effectiveTimezone
|
|
84564
|
+
}),
|
|
84565
|
+
signal: controller.signal,
|
|
84566
|
+
redirectReason: "session_expired"
|
|
84567
|
+
});
|
|
84568
|
+
if (!response.ok) {
|
|
84569
|
+
return false;
|
|
84570
|
+
}
|
|
84571
|
+
const snapshot = await response.json();
|
|
84572
|
+
const metadataByCategory = snapshot?.metadataByCategory && typeof snapshot.metadataByCategory === "object" ? snapshot.metadataByCategory : {};
|
|
84573
|
+
const percentileClipsByCategory = snapshot?.percentileClipsByCategory && typeof snapshot.percentileClipsByCategory === "object" ? snapshot.percentileClipsByCategory : {};
|
|
84574
|
+
const totalsByCategory = snapshot?.totalsByCategory && typeof snapshot.totalsByCategory === "object" ? Object.entries(snapshot.totalsByCategory).reduce((accumulator, [key, value]) => {
|
|
84575
|
+
const total = Number(value);
|
|
84576
|
+
accumulator[key] = Number.isFinite(total) ? Math.max(0, total) : 0;
|
|
84577
|
+
return accumulator;
|
|
84578
|
+
}, {}) : {};
|
|
84579
|
+
const snapshotCategoryId = typeof snapshot?.categoryId === "string" ? snapshot.categoryId : categoryId;
|
|
84580
|
+
const metadata = Array.isArray(snapshot?.metadata) ? snapshot.metadata : Array.isArray(metadataByCategory[snapshotCategoryId]) ? metadataByCategory[snapshotCategoryId] : [];
|
|
84581
|
+
if (controller.signal.aborted) {
|
|
84582
|
+
return true;
|
|
84583
|
+
}
|
|
84584
|
+
setInitialTimePrefetch({
|
|
84585
|
+
key: prefetchKey,
|
|
84586
|
+
categoryId: snapshotCategoryId,
|
|
84587
|
+
metadata,
|
|
84588
|
+
metadataByCategory,
|
|
84589
|
+
totalsByCategory,
|
|
84590
|
+
percentileClipsByCategory,
|
|
84591
|
+
firstVideo: snapshot?.firstVideo || null,
|
|
84592
|
+
total: typeof totalsByCategory[snapshotCategoryId] === "number" ? totalsByCategory[snapshotCategoryId] : metadata.length,
|
|
84593
|
+
loading: false,
|
|
84594
|
+
error: null
|
|
84595
|
+
});
|
|
84596
|
+
return true;
|
|
84597
|
+
} catch (error2) {
|
|
84598
|
+
if (error2.name === "AbortError") {
|
|
84599
|
+
return true;
|
|
84600
|
+
}
|
|
84601
|
+
console.warn("[WorkspaceDetailView] Hourly clips snapshot failed; falling back to category prefetch:", error2);
|
|
84602
|
+
return false;
|
|
84603
|
+
}
|
|
84604
|
+
};
|
|
84605
|
+
const fetchRegularCategory = async (prefetchCategoryId) => {
|
|
84606
|
+
const metadataResponse = await fetchWithSupabaseAuth(supabase, "/api/clips/supabase", {
|
|
84607
|
+
method: "POST",
|
|
84608
|
+
headers: {
|
|
84609
|
+
"Content-Type": "application/json"
|
|
84610
|
+
},
|
|
84611
|
+
body: JSON.stringify({
|
|
84612
|
+
action: "clip-metadata",
|
|
84613
|
+
workspaceId,
|
|
84614
|
+
date: resolvedDate,
|
|
84615
|
+
shift: resolvedShiftId,
|
|
84616
|
+
category: prefetchCategoryId,
|
|
84617
|
+
page: 1,
|
|
84618
|
+
limit: 500,
|
|
84619
|
+
knownTotal: null,
|
|
84620
|
+
startTime: hour.startTime,
|
|
84621
|
+
endTime: hour.endTime,
|
|
84622
|
+
timeFilterTimezone: effectiveTimezone,
|
|
84623
|
+
sort: prefetchCategoryId === "recent_flow_red_streak" ? "red_flow_output_shortfall_desc" : "latest"
|
|
84624
|
+
}),
|
|
84625
|
+
signal: controller.signal,
|
|
84626
|
+
redirectReason: "session_expired"
|
|
84627
|
+
});
|
|
84628
|
+
if (!metadataResponse.ok) {
|
|
84629
|
+
throw new Error(`Hourly clips metadata prefetch failed for ${prefetchCategoryId}: ${metadataResponse.status}`);
|
|
84630
|
+
}
|
|
84631
|
+
const metadataData = await metadataResponse.json();
|
|
84632
|
+
return {
|
|
84633
|
+
categoryId: prefetchCategoryId,
|
|
84634
|
+
clips: Array.isArray(metadataData?.clips) ? metadataData.clips : [],
|
|
84635
|
+
total: typeof metadataData?.total === "number" ? metadataData.total : 0
|
|
84636
|
+
};
|
|
84637
|
+
};
|
|
84638
|
+
const fetchPercentileCategory = async (prefetchCategoryId) => {
|
|
84639
|
+
const response = await fetchWithSupabaseAuth(supabase, "/api/clips/supabase", {
|
|
84640
|
+
method: "POST",
|
|
84641
|
+
headers: {
|
|
84642
|
+
"Content-Type": "application/json"
|
|
84643
|
+
},
|
|
84644
|
+
body: JSON.stringify({
|
|
84645
|
+
action: "percentile-clips",
|
|
84646
|
+
workspaceId,
|
|
84647
|
+
startDate: `${resolvedDate}T00:00:00Z`,
|
|
84648
|
+
endDate: `${resolvedDate}T23:59:59Z`,
|
|
84649
|
+
percentile: 10,
|
|
84650
|
+
shiftId: resolvedShiftId,
|
|
84651
|
+
limit: 500,
|
|
84652
|
+
startTime: hour.startTime,
|
|
84653
|
+
endTime: hour.endTime,
|
|
84654
|
+
timeFilterTimezone: effectiveTimezone,
|
|
84655
|
+
percentileAction: prefetchCategoryId
|
|
84656
|
+
}),
|
|
84657
|
+
signal: controller.signal,
|
|
84658
|
+
redirectReason: "session_expired"
|
|
84659
|
+
});
|
|
84660
|
+
if (!response.ok) {
|
|
84661
|
+
throw new Error(`Hourly percentile clips prefetch failed for ${prefetchCategoryId}: ${response.status}`);
|
|
84662
|
+
}
|
|
84663
|
+
const data = await response.json();
|
|
84664
|
+
return {
|
|
84665
|
+
categoryId: prefetchCategoryId,
|
|
84666
|
+
clips: Array.isArray(data?.clips) ? data.clips : [],
|
|
84667
|
+
total: typeof data?.total === "number" ? data.total : 0
|
|
84668
|
+
};
|
|
84669
|
+
};
|
|
84670
|
+
const runPrefetch = async () => {
|
|
84671
|
+
try {
|
|
84672
|
+
const snapshotLoaded = await fetchHourlySnapshot();
|
|
84673
|
+
if (snapshotLoaded) {
|
|
84674
|
+
return;
|
|
84675
|
+
}
|
|
84676
|
+
const cycleCompletionPromise = fetchRegularCategory("cycle_completion");
|
|
84677
|
+
let resolvedFirstVideo = null;
|
|
84678
|
+
const firstVideoPromise = cycleCompletionPromise.then(async (cycleResponse) => {
|
|
84679
|
+
const firstClipId = cycleResponse.clips[0]?.clipId || cycleResponse.clips[0]?.id || null;
|
|
84680
|
+
if (!firstClipId) {
|
|
84681
|
+
return null;
|
|
84682
|
+
}
|
|
84683
|
+
const video = await s3Service.getClipById(firstClipId);
|
|
84684
|
+
resolvedFirstVideo = video;
|
|
84685
|
+
if (!controller.signal.aborted) {
|
|
84686
|
+
setInitialTimePrefetch((prev) => prev?.key === prefetchKey ? {
|
|
84687
|
+
...prev,
|
|
84688
|
+
firstVideo: video
|
|
84689
|
+
} : prev);
|
|
84690
|
+
}
|
|
84691
|
+
return video;
|
|
84692
|
+
}).catch((error2) => {
|
|
84693
|
+
if (error2.name !== "AbortError") {
|
|
84694
|
+
console.warn("[WorkspaceDetailView] Hourly first clip prefetch failed:", error2);
|
|
84695
|
+
}
|
|
84696
|
+
return null;
|
|
84697
|
+
});
|
|
84698
|
+
const percentileResponsesPromise = Promise.all(percentileCategoryIds.map(fetchPercentileCategory));
|
|
84699
|
+
const regularResponses = await Promise.all([
|
|
84700
|
+
cycleCompletionPromise,
|
|
84701
|
+
fetchRegularCategory("idle_time"),
|
|
84702
|
+
fetchRegularCategory("recent_flow_red_streak")
|
|
84703
|
+
]);
|
|
84704
|
+
const percentileResponses = await percentileResponsesPromise;
|
|
84705
|
+
const metadataByCategory = regularResponses.reduce((accumulator, response) => {
|
|
84706
|
+
accumulator[response.categoryId] = response.clips;
|
|
84707
|
+
return accumulator;
|
|
84708
|
+
}, {});
|
|
84709
|
+
const percentileClipsByCategory = percentileResponses.reduce((accumulator, response) => {
|
|
84710
|
+
accumulator[response.categoryId] = response.clips;
|
|
84711
|
+
return accumulator;
|
|
84712
|
+
}, {});
|
|
84713
|
+
const totalsByCategory = [...regularResponses, ...percentileResponses].reduce((accumulator, response) => {
|
|
84714
|
+
accumulator[response.categoryId] = Math.max(0, Number(response.total || 0));
|
|
84715
|
+
return accumulator;
|
|
84716
|
+
}, {});
|
|
84717
|
+
const metadata = metadataByCategory[categoryId] || [];
|
|
84718
|
+
if (controller.signal.aborted) {
|
|
84719
|
+
return;
|
|
84720
|
+
}
|
|
84721
|
+
setInitialTimePrefetch({
|
|
84722
|
+
key: prefetchKey,
|
|
84723
|
+
categoryId,
|
|
84724
|
+
metadata,
|
|
84725
|
+
metadataByCategory,
|
|
84726
|
+
totalsByCategory,
|
|
84727
|
+
percentileClipsByCategory,
|
|
84728
|
+
firstVideo: resolvedFirstVideo,
|
|
84729
|
+
total: typeof totalsByCategory[categoryId] === "number" ? totalsByCategory[categoryId] : metadata.length,
|
|
84730
|
+
loading: false,
|
|
84731
|
+
error: null
|
|
84732
|
+
});
|
|
84733
|
+
void firstVideoPromise;
|
|
84734
|
+
} catch (error2) {
|
|
84735
|
+
if (error2.name === "AbortError") {
|
|
84736
|
+
return;
|
|
84737
|
+
}
|
|
84738
|
+
console.warn("[WorkspaceDetailView] Hourly clips prefetch failed:", error2);
|
|
84739
|
+
setInitialTimePrefetch((prev) => prev?.key === prefetchKey ? {
|
|
84740
|
+
...prev,
|
|
84741
|
+
loading: false,
|
|
84742
|
+
error: error2 instanceof Error ? error2.message : "Hourly clips prefetch failed"
|
|
84743
|
+
} : prev);
|
|
84744
|
+
} finally {
|
|
84745
|
+
selectedHourClipPrefetchInFlightRef.current.delete(prefetchKey);
|
|
84746
|
+
}
|
|
84747
|
+
};
|
|
84748
|
+
void runPrefetch();
|
|
84749
|
+
}, [
|
|
84750
|
+
dashboardConfig,
|
|
84751
|
+
date,
|
|
84752
|
+
initialTimePrefetch,
|
|
84753
|
+
isFastSlowClipFiltersEnabled,
|
|
84754
|
+
isClipsEnabled,
|
|
84755
|
+
parsedShiftId,
|
|
84756
|
+
selectedShift,
|
|
84757
|
+
supabase,
|
|
84758
|
+
timezone,
|
|
84759
|
+
workspaceId
|
|
84760
|
+
]);
|
|
82704
84761
|
const handleOutputHourSelect = React125.useCallback((payload) => {
|
|
82705
|
-
|
|
84762
|
+
const hour = {
|
|
82706
84763
|
source: "output",
|
|
82707
84764
|
hourIndex: payload.hourIndex,
|
|
82708
84765
|
timeRange: payload.timeRange,
|
|
82709
84766
|
startTime: payload.startTime,
|
|
82710
84767
|
endTime: payload.endTime,
|
|
84768
|
+
timezone: payload.timezone,
|
|
82711
84769
|
status: payload.status,
|
|
82712
84770
|
output: payload.output,
|
|
82713
84771
|
target: payload.target
|
|
82714
|
-
}
|
|
82715
|
-
|
|
84772
|
+
};
|
|
84773
|
+
setSelectedHour(hour);
|
|
84774
|
+
prefetchClipsForSelectedHour(hour);
|
|
84775
|
+
}, [prefetchClipsForSelectedHour]);
|
|
82716
84776
|
const handleAiSummaryClick = React125.useCallback((payload) => {
|
|
82717
84777
|
trackCoreEvent("Hourly Output Ask AI Clicked", buildHourlyOutputActionTrackingProps(payload));
|
|
82718
84778
|
setAiSummaryHour(payload);
|
|
82719
84779
|
}, [buildHourlyOutputActionTrackingProps]);
|
|
82720
84780
|
const handleCycleHourSelect = React125.useCallback((payload) => {
|
|
82721
|
-
|
|
84781
|
+
const hour = {
|
|
82722
84782
|
source: "cycle",
|
|
82723
84783
|
hourIndex: payload.hourIndex,
|
|
82724
84784
|
timeRange: payload.timeRange,
|
|
@@ -82728,17 +84788,23 @@ var WorkspaceDetailView = ({
|
|
|
82728
84788
|
cycleTime: payload.cycleTime,
|
|
82729
84789
|
idealCycleTime: payload.idealCycleTime,
|
|
82730
84790
|
idleMinutes: payload.idleMinutes
|
|
82731
|
-
}
|
|
82732
|
-
|
|
84791
|
+
};
|
|
84792
|
+
setSelectedHour(hour);
|
|
84793
|
+
prefetchClipsForSelectedHour(hour);
|
|
84794
|
+
}, [prefetchClipsForSelectedHour]);
|
|
82733
84795
|
const handleOpenClipsForHour = React125.useCallback((hour) => {
|
|
84796
|
+
prefetchClipsForSelectedHour(hour);
|
|
82734
84797
|
setPendingClipHourFilter({
|
|
82735
84798
|
startTime: hour.startTime,
|
|
82736
84799
|
endTime: hour.endTime,
|
|
82737
84800
|
sourceLabel: hour.timeRange,
|
|
82738
|
-
status: hour.status === "below_target" || hour.status === "above_standard" ? "below_target" : "met_target"
|
|
84801
|
+
status: hour.status === "below_target" || hour.status === "above_standard" ? "below_target" : "met_target",
|
|
84802
|
+
timezone: hour.timezone,
|
|
84803
|
+
categoryId: "cycle_completion",
|
|
84804
|
+
categoryIds: ["cycle_completion", "fast-cycles", "slow-cycles", "idle_time", "recent_flow_red_streak"]
|
|
82739
84805
|
});
|
|
82740
84806
|
setActiveTab("bottlenecks");
|
|
82741
|
-
}, []);
|
|
84807
|
+
}, [prefetchClipsForSelectedHour]);
|
|
82742
84808
|
const handleWatchClipsFromChart = React125.useCallback((payload) => {
|
|
82743
84809
|
trackCoreEvent("Hourly Output Watch Clips Clicked", buildHourlyOutputActionTrackingProps(payload));
|
|
82744
84810
|
handleOpenClipsForHour({
|
|
@@ -82747,6 +84813,7 @@ var WorkspaceDetailView = ({
|
|
|
82747
84813
|
timeRange: payload.timeRange,
|
|
82748
84814
|
startTime: payload.startTime,
|
|
82749
84815
|
endTime: payload.endTime,
|
|
84816
|
+
timezone: payload.timezone,
|
|
82750
84817
|
status: payload.status,
|
|
82751
84818
|
output: payload.output,
|
|
82752
84819
|
target: payload.target
|
|
@@ -82769,11 +84836,6 @@ var WorkspaceDetailView = ({
|
|
|
82769
84836
|
startDate: isFullRange ? void 0 : rangeStart,
|
|
82770
84837
|
endDate: isFullRange ? void 0 : rangeEnd
|
|
82771
84838
|
});
|
|
82772
|
-
const {
|
|
82773
|
-
isFastSlowClipFiltersEnabled,
|
|
82774
|
-
isResolved: isFastSlowClipFiltersResolved
|
|
82775
|
-
} = useCompanyFastSlowClipFiltersEnabled();
|
|
82776
|
-
const isClipsEnabled = dashboardConfig?.clipsConfig?.enabled ?? true;
|
|
82777
84839
|
dashboardConfig?.supervisorConfig?.enabled || false;
|
|
82778
84840
|
const routedLineId = lineId || selectedLineId;
|
|
82779
84841
|
const latestCachedDetailedMetrics = React125.useMemo(() => {
|
|
@@ -84520,6 +86582,7 @@ var WorkspaceDetailView = ({
|
|
|
84520
86582
|
workspaceMetrics: detailedWorkspaceMetrics || void 0,
|
|
84521
86583
|
prefetchedPercentileCounts: isFastSlowClipFiltersEnabled ? prefetchedPercentileCounts : null,
|
|
84522
86584
|
lowMomentsPrefetch,
|
|
86585
|
+
initialTimePrefetch,
|
|
84523
86586
|
initialTimeFilter: pendingClipHourFilter,
|
|
84524
86587
|
className: "h-[calc(100vh-10rem)]"
|
|
84525
86588
|
}
|
|
@@ -94507,6 +96570,7 @@ exports.parseDateKeyToDate = parseDateKeyToDate;
|
|
|
94507
96570
|
exports.parseS3Uri = parseS3Uri;
|
|
94508
96571
|
exports.pickPreferredLineMetricsRow = pickPreferredLineMetricsRow;
|
|
94509
96572
|
exports.preInitializeWorkspaceDisplayNames = preInitializeWorkspaceDisplayNames;
|
|
96573
|
+
exports.preInitializeWorkspaceDisplayNamesForLines = preInitializeWorkspaceDisplayNamesForLines;
|
|
94510
96574
|
exports.preloadS3Video = preloadS3Video;
|
|
94511
96575
|
exports.preloadS3VideoUrl = preloadS3VideoUrl;
|
|
94512
96576
|
exports.preloadS3VideosUrl = preloadS3VideosUrl;
|
|
@@ -94657,3 +96721,5 @@ exports.withRegistry = withRegistry;
|
|
|
94657
96721
|
exports.withTimezone = withTimezone;
|
|
94658
96722
|
exports.workspaceHealthService = workspaceHealthService;
|
|
94659
96723
|
exports.workspaceService = workspaceService;
|
|
96724
|
+
//# sourceMappingURL=index.js.map
|
|
96725
|
+
//# sourceMappingURL=index.js.map
|