@optifye/dashboard-core 6.1.6 → 6.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +134 -29
- package/dist/index.mjs +134 -29
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -948,8 +948,9 @@ var dashboardService = {
|
|
|
948
948
|
factory_id,
|
|
949
949
|
factories!lines_factory_id_fkey(factory_name),
|
|
950
950
|
company_id,
|
|
951
|
-
companies!lines_company_id_fkey(company_name:name)
|
|
952
|
-
|
|
951
|
+
companies!lines_company_id_fkey(company_name:name),
|
|
952
|
+
enable
|
|
953
|
+
`).eq("enable", true);
|
|
953
954
|
if (companyId) {
|
|
954
955
|
query = query.eq("company_id", companyId);
|
|
955
956
|
}
|
|
@@ -965,7 +966,9 @@ var dashboardService = {
|
|
|
965
966
|
factory_id: line.factory_id,
|
|
966
967
|
factory_name: line.factories?.factory_name ?? "N/A",
|
|
967
968
|
company_id: line.company_id,
|
|
968
|
-
company_name: line.companies?.company_name ?? "N/A"
|
|
969
|
+
company_name: line.companies?.company_name ?? "N/A",
|
|
970
|
+
enable: line.enable ?? true
|
|
971
|
+
// Default to true if not specified
|
|
969
972
|
}));
|
|
970
973
|
return transformedLines;
|
|
971
974
|
} catch (err) {
|
|
@@ -4057,7 +4060,14 @@ var useLeaderboardMetrics = (lineId, topCount = 10) => {
|
|
|
4057
4060
|
try {
|
|
4058
4061
|
const currentShiftDetails = getCurrentShift(defaultTimezone, shiftConfig);
|
|
4059
4062
|
const operationalDate = getOperationalDate(defaultTimezone, new Date(currentShiftDetails.date));
|
|
4060
|
-
const
|
|
4063
|
+
const workspaces = await workspaceService.getWorkspaces(lineId);
|
|
4064
|
+
const enabledWorkspaceIds = workspaces.filter((ws) => ws.enable === true).map((ws) => ws.id);
|
|
4065
|
+
if (enabledWorkspaceIds.length === 0) {
|
|
4066
|
+
setTopPerformers([]);
|
|
4067
|
+
setIsLoading(false);
|
|
4068
|
+
return;
|
|
4069
|
+
}
|
|
4070
|
+
const { data, error: fetchError } = await supabase.from(companySpecificMetricsTable).select(`workspace_name,total_output,avg_pph,efficiency,workspace_id`).eq("date", operationalDate).eq("shift_id", currentShiftDetails.shiftId).eq("line_id", lineId).in("workspace_id", enabledWorkspaceIds).gt("efficiency", 0).order("efficiency", { ascending: false }).limit(topCount);
|
|
4061
4071
|
if (fetchError) throw fetchError;
|
|
4062
4072
|
const rankedData = (data || []).map((entry, index) => ({
|
|
4063
4073
|
workspace_name: entry.workspace_name,
|
|
@@ -4610,14 +4620,20 @@ var useRealtimeLineMetrics = ({
|
|
|
4610
4620
|
const companyId = entityConfig.companyId;
|
|
4611
4621
|
const metricsTablePrefix = getMetricsTablePrefix(companyId || "");
|
|
4612
4622
|
const metricsTable = `${metricsTablePrefix}_${(companyId || "").replace(/-/g, "_")}`;
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
4623
|
+
let enabledWorkspaceIds = [];
|
|
4624
|
+
for (const lineId2 of targetLineIds) {
|
|
4625
|
+
const workspaces = await workspaceService.getWorkspaces(lineId2);
|
|
4626
|
+
const enabledIds = workspaces.filter((ws) => ws.enable === true).map((ws) => ws.id);
|
|
4627
|
+
enabledWorkspaceIds.push(...enabledIds);
|
|
4628
|
+
}
|
|
4629
|
+
const { data: workspaceData, error: workspaceError } = enabledWorkspaceIds.length > 0 ? await supabase.from(metricsTable).select(`
|
|
4630
|
+
line_id,
|
|
4631
|
+
workspace_id,
|
|
4632
|
+
workspace_name,
|
|
4633
|
+
efficiency,
|
|
4634
|
+
total_output,
|
|
4635
|
+
total_day_output
|
|
4636
|
+
`).in("line_id", targetLineIds).in("workspace_id", enabledWorkspaceIds).eq("shift_id", shiftId).eq("date", date) : { data: [], error: null };
|
|
4621
4637
|
if (workspaceError) {
|
|
4622
4638
|
console.error("Error fetching workspace metrics for factory view:", workspaceError);
|
|
4623
4639
|
}
|
|
@@ -4669,13 +4685,15 @@ var useRealtimeLineMetrics = ({
|
|
|
4669
4685
|
const companyId = entityConfig.companyId;
|
|
4670
4686
|
const metricsTablePrefix = getMetricsTablePrefix(companyId || "");
|
|
4671
4687
|
const metricsTable = `${metricsTablePrefix}_${(companyId || "").replace(/-/g, "_")}`;
|
|
4672
|
-
const
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4688
|
+
const workspaces = await workspaceService.getWorkspaces(lineIdRef.current);
|
|
4689
|
+
const enabledWorkspaceIds = workspaces.filter((ws) => ws.enable === true).map((ws) => ws.id);
|
|
4690
|
+
const { data: workspaceData, error: workspaceError } = enabledWorkspaceIds.length > 0 ? await supabase.from(metricsTable).select(`
|
|
4691
|
+
workspace_id,
|
|
4692
|
+
workspace_name,
|
|
4693
|
+
efficiency,
|
|
4694
|
+
total_output,
|
|
4695
|
+
total_day_output
|
|
4696
|
+
`).eq("line_id", lineIdRef.current).in("workspace_id", enabledWorkspaceIds).eq("shift_id", shiftId).eq("date", date) : { data: [], error: null };
|
|
4679
4697
|
if (workspaceError) {
|
|
4680
4698
|
console.error("Error fetching workspace metrics:", workspaceError);
|
|
4681
4699
|
}
|
|
@@ -6124,6 +6142,19 @@ var useAllWorkspaceMetrics = (options) => {
|
|
|
6124
6142
|
queryShiftId,
|
|
6125
6143
|
metricsTable
|
|
6126
6144
|
});
|
|
6145
|
+
const configuredLineIds = getConfiguredLineIds(entityConfig);
|
|
6146
|
+
let enabledWorkspaceIds = [];
|
|
6147
|
+
for (const lineId of configuredLineIds) {
|
|
6148
|
+
const workspaces2 = await workspaceService.getWorkspaces(lineId);
|
|
6149
|
+
const enabledIds = workspaces2.filter((ws) => ws.enable === true).map((ws) => ws.id);
|
|
6150
|
+
enabledWorkspaceIds.push(...enabledIds);
|
|
6151
|
+
}
|
|
6152
|
+
if (enabledWorkspaceIds.length === 0) {
|
|
6153
|
+
setWorkspaces([]);
|
|
6154
|
+
setInitialized(true);
|
|
6155
|
+
setLoading(false);
|
|
6156
|
+
return;
|
|
6157
|
+
}
|
|
6127
6158
|
const { data, error: fetchError } = await supabase.from(metricsTable).select(`
|
|
6128
6159
|
workspace_name,
|
|
6129
6160
|
total_output,
|
|
@@ -6135,7 +6166,7 @@ var useAllWorkspaceMetrics = (options) => {
|
|
|
6135
6166
|
trend_score,
|
|
6136
6167
|
line_id,
|
|
6137
6168
|
total_day_output
|
|
6138
|
-
`).eq("date", queryDate).eq("shift_id", queryShiftId).order("efficiency", { ascending: false });
|
|
6169
|
+
`).eq("date", queryDate).eq("shift_id", queryShiftId).in("workspace_id", enabledWorkspaceIds).order("efficiency", { ascending: false });
|
|
6139
6170
|
if (fetchError) throw fetchError;
|
|
6140
6171
|
const transformedData = (data || []).map((item) => ({
|
|
6141
6172
|
company_id: entityConfig.companyId || "unknown",
|
|
@@ -23064,7 +23095,14 @@ var S3ClipsService = class {
|
|
|
23064
23095
|
}
|
|
23065
23096
|
const limitPerCategory = limit ? Math.min(Math.max(limit, 1), this.maxLimitPerCategory) : this.defaultLimitPerCategory;
|
|
23066
23097
|
const shouldFetchAll = category === "missing_quality_check" || category === "low_value";
|
|
23067
|
-
|
|
23098
|
+
let initialFetchLimit;
|
|
23099
|
+
if (shouldFetchAll) {
|
|
23100
|
+
initialFetchLimit = void 0;
|
|
23101
|
+
} else if (category) {
|
|
23102
|
+
initialFetchLimit = Math.min(limitPerCategory * 3, this.maxInitialFetch);
|
|
23103
|
+
} else {
|
|
23104
|
+
initialFetchLimit = this.maxInitialFetch;
|
|
23105
|
+
}
|
|
23068
23106
|
const s3Uris = await this.listS3Clips({ workspaceId, date, shiftId, maxKeys: initialFetchLimit });
|
|
23069
23107
|
if (s3Uris.length === 0) {
|
|
23070
23108
|
console.log(`S3ClipsService: No HLS playlists found for workspace ${workspaceId} on date ${date}, shift ${shiftId}`);
|
|
@@ -23190,6 +23228,9 @@ var S3ClipsService = class {
|
|
|
23190
23228
|
return videos;
|
|
23191
23229
|
}
|
|
23192
23230
|
};
|
|
23231
|
+
|
|
23232
|
+
// src/lib/cache/clipsCache.ts
|
|
23233
|
+
var clipsCache = {};
|
|
23193
23234
|
var BottlenecksContent = ({
|
|
23194
23235
|
workspaceId,
|
|
23195
23236
|
workspaceName,
|
|
@@ -23209,6 +23250,7 @@ var BottlenecksContent = ({
|
|
|
23209
23250
|
const videoRef = React19.useRef(null);
|
|
23210
23251
|
const fullscreenContainerRef = React19.useRef(null);
|
|
23211
23252
|
const timestampFilterRef = React19.useRef(null);
|
|
23253
|
+
const hlsRef = React19.useRef(null);
|
|
23212
23254
|
const [isPlaying, setIsPlaying] = React19.useState(false);
|
|
23213
23255
|
const [currentTime, setCurrentTime] = React19.useState(0);
|
|
23214
23256
|
const [duration, setDuration] = React19.useState(0);
|
|
@@ -23257,21 +23299,36 @@ var BottlenecksContent = ({
|
|
|
23257
23299
|
if (timestampEnd) {
|
|
23258
23300
|
timestampEndFull = `${operationalDate}T${timestampEnd}:00`;
|
|
23259
23301
|
}
|
|
23260
|
-
const
|
|
23302
|
+
const cacheKey = `${workspaceId}-${operationalDate}-${shift || "all"}-all-meta-1000-${timestampStartFull || ""}-${timestampEndFull || ""}`;
|
|
23303
|
+
const existingEntry = clipsCache[cacheKey];
|
|
23304
|
+
if (existingEntry?.status === "resolved" && existingEntry.data) {
|
|
23305
|
+
setAllVideos(existingEntry.data);
|
|
23306
|
+
return;
|
|
23307
|
+
}
|
|
23308
|
+
if (existingEntry?.status === "pending" && existingEntry.promise) {
|
|
23309
|
+
setIsLoading(true);
|
|
23310
|
+
existingEntry.promise.then((data) => {
|
|
23311
|
+
setAllVideos(data);
|
|
23312
|
+
setIsLoading(false);
|
|
23313
|
+
}).catch(() => setIsLoading(false));
|
|
23314
|
+
return;
|
|
23315
|
+
}
|
|
23316
|
+
setIsLoading(true);
|
|
23317
|
+
const fetchPromise = s3ClipsService.fetchClips({
|
|
23261
23318
|
workspaceId,
|
|
23262
23319
|
date: operationalDate,
|
|
23263
23320
|
shift: shift?.toString(),
|
|
23264
|
-
// Pass the shift parameter
|
|
23265
23321
|
mode: "full",
|
|
23266
23322
|
includeCycleTime: true,
|
|
23267
23323
|
includeMetadata: true,
|
|
23268
|
-
// Always include metadata for timestamp info
|
|
23269
23324
|
limit: 1e3,
|
|
23270
|
-
// Reasonable limit for UI performance
|
|
23271
23325
|
timestampStart: timestampStartFull,
|
|
23272
23326
|
timestampEnd: timestampEndFull
|
|
23273
23327
|
});
|
|
23274
|
-
|
|
23328
|
+
clipsCache[cacheKey] = { status: "pending", promise: fetchPromise };
|
|
23329
|
+
const videos = await fetchPromise;
|
|
23330
|
+
clipsCache[cacheKey] = { status: "resolved", data: videos };
|
|
23331
|
+
if (videos.length > 0) {
|
|
23275
23332
|
preloadVideoUrl2(videos[0].src);
|
|
23276
23333
|
const firstHigh = videos.find((v) => v.type === "bottleneck" && v.severity === "high");
|
|
23277
23334
|
const firstMed = videos.find((v) => v.type === "bottleneck" && v.severity === "medium");
|
|
@@ -23295,6 +23352,8 @@ var BottlenecksContent = ({
|
|
|
23295
23352
|
].filter(Boolean));
|
|
23296
23353
|
}
|
|
23297
23354
|
setAllVideos(videos);
|
|
23355
|
+
setIsLoading(false);
|
|
23356
|
+
return;
|
|
23298
23357
|
} catch (err) {
|
|
23299
23358
|
console.error("Error fetching HLS clips from S3:", err);
|
|
23300
23359
|
setError("Failed to load clips from storage. Please try again.");
|
|
@@ -23414,6 +23473,14 @@ var BottlenecksContent = ({
|
|
|
23414
23473
|
} else {
|
|
23415
23474
|
import('hls.js').then(({ default: Hls3 }) => {
|
|
23416
23475
|
if (Hls3.isSupported()) {
|
|
23476
|
+
if (hlsRef.current) {
|
|
23477
|
+
try {
|
|
23478
|
+
hlsRef.current.destroy();
|
|
23479
|
+
} catch (err) {
|
|
23480
|
+
console.warn("Failed to destroy previous HLS instance", err);
|
|
23481
|
+
}
|
|
23482
|
+
hlsRef.current = null;
|
|
23483
|
+
}
|
|
23417
23484
|
const hls = new Hls3({
|
|
23418
23485
|
// Add CORS and error handling configuration
|
|
23419
23486
|
xhrSetup: (xhr, url) => {
|
|
@@ -23456,7 +23523,8 @@ var BottlenecksContent = ({
|
|
|
23456
23523
|
testBandwidth: false,
|
|
23457
23524
|
// Error recovery configuration
|
|
23458
23525
|
capLevelOnFPSDrop: false,
|
|
23459
|
-
capLevelToPlayerSize:
|
|
23526
|
+
capLevelToPlayerSize: true,
|
|
23527
|
+
abrEwmaDefaultEstimate: 5e5
|
|
23460
23528
|
});
|
|
23461
23529
|
hls.on(Hls3.Events.ERROR, (event, data) => {
|
|
23462
23530
|
console.error("HLS.js error:", data);
|
|
@@ -23584,6 +23652,13 @@ var BottlenecksContent = ({
|
|
|
23584
23652
|
video.removeEventListener("loadedmetadata", onLoadedMetadata);
|
|
23585
23653
|
video.removeEventListener("ended", onEnded);
|
|
23586
23654
|
video.removeEventListener("error", onError);
|
|
23655
|
+
if (hlsRef.current) {
|
|
23656
|
+
try {
|
|
23657
|
+
hlsRef.current.destroy();
|
|
23658
|
+
} catch (e) {
|
|
23659
|
+
}
|
|
23660
|
+
hlsRef.current = null;
|
|
23661
|
+
}
|
|
23587
23662
|
};
|
|
23588
23663
|
} else if (videoRef.current) {
|
|
23589
23664
|
videoRef.current.pause();
|
|
@@ -30243,15 +30318,22 @@ var LeaderboardDetailView = React19.memo(({
|
|
|
30243
30318
|
className = ""
|
|
30244
30319
|
}) => {
|
|
30245
30320
|
const navigation = useNavigation();
|
|
30321
|
+
const entityConfig = useEntityConfig();
|
|
30246
30322
|
const [sortAscending, setSortAscending] = React19.useState(false);
|
|
30323
|
+
const configuredLineNames = React19.useMemo(() => {
|
|
30324
|
+
return getAllLineDisplayNames(entityConfig);
|
|
30325
|
+
}, [entityConfig]);
|
|
30247
30326
|
const getLineName = React19.useCallback((lineId2) => {
|
|
30327
|
+
if (configuredLineNames[lineId2]) {
|
|
30328
|
+
return configuredLineNames[lineId2];
|
|
30329
|
+
}
|
|
30248
30330
|
if (lineNames[lineId2]) {
|
|
30249
30331
|
return lineNames[lineId2];
|
|
30250
30332
|
}
|
|
30251
30333
|
if (lineId2 === line1Id) return "Line 1";
|
|
30252
30334
|
if (lineId2 === line2Id) return "Line 2";
|
|
30253
|
-
return lineId2
|
|
30254
|
-
}, [lineNames, line1Id, line2Id]);
|
|
30335
|
+
return `Line ${lineId2.substring(0, 8)}`;
|
|
30336
|
+
}, [configuredLineNames, lineNames, line1Id, line2Id]);
|
|
30255
30337
|
const handleSortToggle = React19.useCallback(() => {
|
|
30256
30338
|
setSortAscending(!sortAscending);
|
|
30257
30339
|
}, [sortAscending]);
|
|
@@ -33385,6 +33467,29 @@ var WorkspaceDetailView = ({
|
|
|
33385
33467
|
const isHistoricView = Boolean(date && parsedShiftId !== void 0);
|
|
33386
33468
|
const initialTab = getInitialTab(sourceType, defaultTab, fromMonthly, date);
|
|
33387
33469
|
const [activeTab, setActiveTab] = React19.useState(initialTab);
|
|
33470
|
+
const dashboardConfig = useDashboardConfig();
|
|
33471
|
+
React19.useEffect(() => {
|
|
33472
|
+
if (!dashboardConfig?.s3Config) return;
|
|
33473
|
+
const operationalDate2 = date || getOperationalDate();
|
|
33474
|
+
const cacheKey = `${workspaceId}-${operationalDate2}-${shift || "all"}-all-meta-1000--`;
|
|
33475
|
+
if (clipsCache[cacheKey]?.status) return;
|
|
33476
|
+
const service = new S3ClipsService(dashboardConfig);
|
|
33477
|
+
const promise = service.fetchClips({
|
|
33478
|
+
workspaceId,
|
|
33479
|
+
date: operationalDate2,
|
|
33480
|
+
shift: shift?.toString(),
|
|
33481
|
+
mode: "full",
|
|
33482
|
+
includeCycleTime: true,
|
|
33483
|
+
includeMetadata: true,
|
|
33484
|
+
limit: 1e3
|
|
33485
|
+
});
|
|
33486
|
+
clipsCache[cacheKey] = { status: "pending", promise };
|
|
33487
|
+
promise.then((videos) => {
|
|
33488
|
+
clipsCache[cacheKey] = { status: "resolved", data: videos };
|
|
33489
|
+
}).catch((err) => {
|
|
33490
|
+
clipsCache[cacheKey] = { status: "rejected", error: err };
|
|
33491
|
+
});
|
|
33492
|
+
}, [workspaceId, date, shift, dashboardConfig]);
|
|
33388
33493
|
const [isTransitioning, setIsTransitioning] = React19.useState(false);
|
|
33389
33494
|
const [usingFallbackData, setUsingFallbackData] = React19.useState(false);
|
|
33390
33495
|
const [showIdleTime, setShowIdleTime] = React19.useState(false);
|
package/dist/index.mjs
CHANGED
|
@@ -919,8 +919,9 @@ var dashboardService = {
|
|
|
919
919
|
factory_id,
|
|
920
920
|
factories!lines_factory_id_fkey(factory_name),
|
|
921
921
|
company_id,
|
|
922
|
-
companies!lines_company_id_fkey(company_name:name)
|
|
923
|
-
|
|
922
|
+
companies!lines_company_id_fkey(company_name:name),
|
|
923
|
+
enable
|
|
924
|
+
`).eq("enable", true);
|
|
924
925
|
if (companyId) {
|
|
925
926
|
query = query.eq("company_id", companyId);
|
|
926
927
|
}
|
|
@@ -936,7 +937,9 @@ var dashboardService = {
|
|
|
936
937
|
factory_id: line.factory_id,
|
|
937
938
|
factory_name: line.factories?.factory_name ?? "N/A",
|
|
938
939
|
company_id: line.company_id,
|
|
939
|
-
company_name: line.companies?.company_name ?? "N/A"
|
|
940
|
+
company_name: line.companies?.company_name ?? "N/A",
|
|
941
|
+
enable: line.enable ?? true
|
|
942
|
+
// Default to true if not specified
|
|
940
943
|
}));
|
|
941
944
|
return transformedLines;
|
|
942
945
|
} catch (err) {
|
|
@@ -4028,7 +4031,14 @@ var useLeaderboardMetrics = (lineId, topCount = 10) => {
|
|
|
4028
4031
|
try {
|
|
4029
4032
|
const currentShiftDetails = getCurrentShift(defaultTimezone, shiftConfig);
|
|
4030
4033
|
const operationalDate = getOperationalDate(defaultTimezone, new Date(currentShiftDetails.date));
|
|
4031
|
-
const
|
|
4034
|
+
const workspaces = await workspaceService.getWorkspaces(lineId);
|
|
4035
|
+
const enabledWorkspaceIds = workspaces.filter((ws) => ws.enable === true).map((ws) => ws.id);
|
|
4036
|
+
if (enabledWorkspaceIds.length === 0) {
|
|
4037
|
+
setTopPerformers([]);
|
|
4038
|
+
setIsLoading(false);
|
|
4039
|
+
return;
|
|
4040
|
+
}
|
|
4041
|
+
const { data, error: fetchError } = await supabase.from(companySpecificMetricsTable).select(`workspace_name,total_output,avg_pph,efficiency,workspace_id`).eq("date", operationalDate).eq("shift_id", currentShiftDetails.shiftId).eq("line_id", lineId).in("workspace_id", enabledWorkspaceIds).gt("efficiency", 0).order("efficiency", { ascending: false }).limit(topCount);
|
|
4032
4042
|
if (fetchError) throw fetchError;
|
|
4033
4043
|
const rankedData = (data || []).map((entry, index) => ({
|
|
4034
4044
|
workspace_name: entry.workspace_name,
|
|
@@ -4581,14 +4591,20 @@ var useRealtimeLineMetrics = ({
|
|
|
4581
4591
|
const companyId = entityConfig.companyId;
|
|
4582
4592
|
const metricsTablePrefix = getMetricsTablePrefix(companyId || "");
|
|
4583
4593
|
const metricsTable = `${metricsTablePrefix}_${(companyId || "").replace(/-/g, "_")}`;
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
|
|
4591
|
-
|
|
4594
|
+
let enabledWorkspaceIds = [];
|
|
4595
|
+
for (const lineId2 of targetLineIds) {
|
|
4596
|
+
const workspaces = await workspaceService.getWorkspaces(lineId2);
|
|
4597
|
+
const enabledIds = workspaces.filter((ws) => ws.enable === true).map((ws) => ws.id);
|
|
4598
|
+
enabledWorkspaceIds.push(...enabledIds);
|
|
4599
|
+
}
|
|
4600
|
+
const { data: workspaceData, error: workspaceError } = enabledWorkspaceIds.length > 0 ? await supabase.from(metricsTable).select(`
|
|
4601
|
+
line_id,
|
|
4602
|
+
workspace_id,
|
|
4603
|
+
workspace_name,
|
|
4604
|
+
efficiency,
|
|
4605
|
+
total_output,
|
|
4606
|
+
total_day_output
|
|
4607
|
+
`).in("line_id", targetLineIds).in("workspace_id", enabledWorkspaceIds).eq("shift_id", shiftId).eq("date", date) : { data: [], error: null };
|
|
4592
4608
|
if (workspaceError) {
|
|
4593
4609
|
console.error("Error fetching workspace metrics for factory view:", workspaceError);
|
|
4594
4610
|
}
|
|
@@ -4640,13 +4656,15 @@ var useRealtimeLineMetrics = ({
|
|
|
4640
4656
|
const companyId = entityConfig.companyId;
|
|
4641
4657
|
const metricsTablePrefix = getMetricsTablePrefix(companyId || "");
|
|
4642
4658
|
const metricsTable = `${metricsTablePrefix}_${(companyId || "").replace(/-/g, "_")}`;
|
|
4643
|
-
const
|
|
4644
|
-
|
|
4645
|
-
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
|
|
4659
|
+
const workspaces = await workspaceService.getWorkspaces(lineIdRef.current);
|
|
4660
|
+
const enabledWorkspaceIds = workspaces.filter((ws) => ws.enable === true).map((ws) => ws.id);
|
|
4661
|
+
const { data: workspaceData, error: workspaceError } = enabledWorkspaceIds.length > 0 ? await supabase.from(metricsTable).select(`
|
|
4662
|
+
workspace_id,
|
|
4663
|
+
workspace_name,
|
|
4664
|
+
efficiency,
|
|
4665
|
+
total_output,
|
|
4666
|
+
total_day_output
|
|
4667
|
+
`).eq("line_id", lineIdRef.current).in("workspace_id", enabledWorkspaceIds).eq("shift_id", shiftId).eq("date", date) : { data: [], error: null };
|
|
4650
4668
|
if (workspaceError) {
|
|
4651
4669
|
console.error("Error fetching workspace metrics:", workspaceError);
|
|
4652
4670
|
}
|
|
@@ -6095,6 +6113,19 @@ var useAllWorkspaceMetrics = (options) => {
|
|
|
6095
6113
|
queryShiftId,
|
|
6096
6114
|
metricsTable
|
|
6097
6115
|
});
|
|
6116
|
+
const configuredLineIds = getConfiguredLineIds(entityConfig);
|
|
6117
|
+
let enabledWorkspaceIds = [];
|
|
6118
|
+
for (const lineId of configuredLineIds) {
|
|
6119
|
+
const workspaces2 = await workspaceService.getWorkspaces(lineId);
|
|
6120
|
+
const enabledIds = workspaces2.filter((ws) => ws.enable === true).map((ws) => ws.id);
|
|
6121
|
+
enabledWorkspaceIds.push(...enabledIds);
|
|
6122
|
+
}
|
|
6123
|
+
if (enabledWorkspaceIds.length === 0) {
|
|
6124
|
+
setWorkspaces([]);
|
|
6125
|
+
setInitialized(true);
|
|
6126
|
+
setLoading(false);
|
|
6127
|
+
return;
|
|
6128
|
+
}
|
|
6098
6129
|
const { data, error: fetchError } = await supabase.from(metricsTable).select(`
|
|
6099
6130
|
workspace_name,
|
|
6100
6131
|
total_output,
|
|
@@ -6106,7 +6137,7 @@ var useAllWorkspaceMetrics = (options) => {
|
|
|
6106
6137
|
trend_score,
|
|
6107
6138
|
line_id,
|
|
6108
6139
|
total_day_output
|
|
6109
|
-
`).eq("date", queryDate).eq("shift_id", queryShiftId).order("efficiency", { ascending: false });
|
|
6140
|
+
`).eq("date", queryDate).eq("shift_id", queryShiftId).in("workspace_id", enabledWorkspaceIds).order("efficiency", { ascending: false });
|
|
6110
6141
|
if (fetchError) throw fetchError;
|
|
6111
6142
|
const transformedData = (data || []).map((item) => ({
|
|
6112
6143
|
company_id: entityConfig.companyId || "unknown",
|
|
@@ -23035,7 +23066,14 @@ var S3ClipsService = class {
|
|
|
23035
23066
|
}
|
|
23036
23067
|
const limitPerCategory = limit ? Math.min(Math.max(limit, 1), this.maxLimitPerCategory) : this.defaultLimitPerCategory;
|
|
23037
23068
|
const shouldFetchAll = category === "missing_quality_check" || category === "low_value";
|
|
23038
|
-
|
|
23069
|
+
let initialFetchLimit;
|
|
23070
|
+
if (shouldFetchAll) {
|
|
23071
|
+
initialFetchLimit = void 0;
|
|
23072
|
+
} else if (category) {
|
|
23073
|
+
initialFetchLimit = Math.min(limitPerCategory * 3, this.maxInitialFetch);
|
|
23074
|
+
} else {
|
|
23075
|
+
initialFetchLimit = this.maxInitialFetch;
|
|
23076
|
+
}
|
|
23039
23077
|
const s3Uris = await this.listS3Clips({ workspaceId, date, shiftId, maxKeys: initialFetchLimit });
|
|
23040
23078
|
if (s3Uris.length === 0) {
|
|
23041
23079
|
console.log(`S3ClipsService: No HLS playlists found for workspace ${workspaceId} on date ${date}, shift ${shiftId}`);
|
|
@@ -23161,6 +23199,9 @@ var S3ClipsService = class {
|
|
|
23161
23199
|
return videos;
|
|
23162
23200
|
}
|
|
23163
23201
|
};
|
|
23202
|
+
|
|
23203
|
+
// src/lib/cache/clipsCache.ts
|
|
23204
|
+
var clipsCache = {};
|
|
23164
23205
|
var BottlenecksContent = ({
|
|
23165
23206
|
workspaceId,
|
|
23166
23207
|
workspaceName,
|
|
@@ -23180,6 +23221,7 @@ var BottlenecksContent = ({
|
|
|
23180
23221
|
const videoRef = useRef(null);
|
|
23181
23222
|
const fullscreenContainerRef = useRef(null);
|
|
23182
23223
|
const timestampFilterRef = useRef(null);
|
|
23224
|
+
const hlsRef = useRef(null);
|
|
23183
23225
|
const [isPlaying, setIsPlaying] = useState(false);
|
|
23184
23226
|
const [currentTime, setCurrentTime] = useState(0);
|
|
23185
23227
|
const [duration, setDuration] = useState(0);
|
|
@@ -23228,21 +23270,36 @@ var BottlenecksContent = ({
|
|
|
23228
23270
|
if (timestampEnd) {
|
|
23229
23271
|
timestampEndFull = `${operationalDate}T${timestampEnd}:00`;
|
|
23230
23272
|
}
|
|
23231
|
-
const
|
|
23273
|
+
const cacheKey = `${workspaceId}-${operationalDate}-${shift || "all"}-all-meta-1000-${timestampStartFull || ""}-${timestampEndFull || ""}`;
|
|
23274
|
+
const existingEntry = clipsCache[cacheKey];
|
|
23275
|
+
if (existingEntry?.status === "resolved" && existingEntry.data) {
|
|
23276
|
+
setAllVideos(existingEntry.data);
|
|
23277
|
+
return;
|
|
23278
|
+
}
|
|
23279
|
+
if (existingEntry?.status === "pending" && existingEntry.promise) {
|
|
23280
|
+
setIsLoading(true);
|
|
23281
|
+
existingEntry.promise.then((data) => {
|
|
23282
|
+
setAllVideos(data);
|
|
23283
|
+
setIsLoading(false);
|
|
23284
|
+
}).catch(() => setIsLoading(false));
|
|
23285
|
+
return;
|
|
23286
|
+
}
|
|
23287
|
+
setIsLoading(true);
|
|
23288
|
+
const fetchPromise = s3ClipsService.fetchClips({
|
|
23232
23289
|
workspaceId,
|
|
23233
23290
|
date: operationalDate,
|
|
23234
23291
|
shift: shift?.toString(),
|
|
23235
|
-
// Pass the shift parameter
|
|
23236
23292
|
mode: "full",
|
|
23237
23293
|
includeCycleTime: true,
|
|
23238
23294
|
includeMetadata: true,
|
|
23239
|
-
// Always include metadata for timestamp info
|
|
23240
23295
|
limit: 1e3,
|
|
23241
|
-
// Reasonable limit for UI performance
|
|
23242
23296
|
timestampStart: timestampStartFull,
|
|
23243
23297
|
timestampEnd: timestampEndFull
|
|
23244
23298
|
});
|
|
23245
|
-
|
|
23299
|
+
clipsCache[cacheKey] = { status: "pending", promise: fetchPromise };
|
|
23300
|
+
const videos = await fetchPromise;
|
|
23301
|
+
clipsCache[cacheKey] = { status: "resolved", data: videos };
|
|
23302
|
+
if (videos.length > 0) {
|
|
23246
23303
|
preloadVideoUrl2(videos[0].src);
|
|
23247
23304
|
const firstHigh = videos.find((v) => v.type === "bottleneck" && v.severity === "high");
|
|
23248
23305
|
const firstMed = videos.find((v) => v.type === "bottleneck" && v.severity === "medium");
|
|
@@ -23266,6 +23323,8 @@ var BottlenecksContent = ({
|
|
|
23266
23323
|
].filter(Boolean));
|
|
23267
23324
|
}
|
|
23268
23325
|
setAllVideos(videos);
|
|
23326
|
+
setIsLoading(false);
|
|
23327
|
+
return;
|
|
23269
23328
|
} catch (err) {
|
|
23270
23329
|
console.error("Error fetching HLS clips from S3:", err);
|
|
23271
23330
|
setError("Failed to load clips from storage. Please try again.");
|
|
@@ -23385,6 +23444,14 @@ var BottlenecksContent = ({
|
|
|
23385
23444
|
} else {
|
|
23386
23445
|
import('hls.js').then(({ default: Hls3 }) => {
|
|
23387
23446
|
if (Hls3.isSupported()) {
|
|
23447
|
+
if (hlsRef.current) {
|
|
23448
|
+
try {
|
|
23449
|
+
hlsRef.current.destroy();
|
|
23450
|
+
} catch (err) {
|
|
23451
|
+
console.warn("Failed to destroy previous HLS instance", err);
|
|
23452
|
+
}
|
|
23453
|
+
hlsRef.current = null;
|
|
23454
|
+
}
|
|
23388
23455
|
const hls = new Hls3({
|
|
23389
23456
|
// Add CORS and error handling configuration
|
|
23390
23457
|
xhrSetup: (xhr, url) => {
|
|
@@ -23427,7 +23494,8 @@ var BottlenecksContent = ({
|
|
|
23427
23494
|
testBandwidth: false,
|
|
23428
23495
|
// Error recovery configuration
|
|
23429
23496
|
capLevelOnFPSDrop: false,
|
|
23430
|
-
capLevelToPlayerSize:
|
|
23497
|
+
capLevelToPlayerSize: true,
|
|
23498
|
+
abrEwmaDefaultEstimate: 5e5
|
|
23431
23499
|
});
|
|
23432
23500
|
hls.on(Hls3.Events.ERROR, (event, data) => {
|
|
23433
23501
|
console.error("HLS.js error:", data);
|
|
@@ -23555,6 +23623,13 @@ var BottlenecksContent = ({
|
|
|
23555
23623
|
video.removeEventListener("loadedmetadata", onLoadedMetadata);
|
|
23556
23624
|
video.removeEventListener("ended", onEnded);
|
|
23557
23625
|
video.removeEventListener("error", onError);
|
|
23626
|
+
if (hlsRef.current) {
|
|
23627
|
+
try {
|
|
23628
|
+
hlsRef.current.destroy();
|
|
23629
|
+
} catch (e) {
|
|
23630
|
+
}
|
|
23631
|
+
hlsRef.current = null;
|
|
23632
|
+
}
|
|
23558
23633
|
};
|
|
23559
23634
|
} else if (videoRef.current) {
|
|
23560
23635
|
videoRef.current.pause();
|
|
@@ -30214,15 +30289,22 @@ var LeaderboardDetailView = memo(({
|
|
|
30214
30289
|
className = ""
|
|
30215
30290
|
}) => {
|
|
30216
30291
|
const navigation = useNavigation();
|
|
30292
|
+
const entityConfig = useEntityConfig();
|
|
30217
30293
|
const [sortAscending, setSortAscending] = useState(false);
|
|
30294
|
+
const configuredLineNames = useMemo(() => {
|
|
30295
|
+
return getAllLineDisplayNames(entityConfig);
|
|
30296
|
+
}, [entityConfig]);
|
|
30218
30297
|
const getLineName = useCallback((lineId2) => {
|
|
30298
|
+
if (configuredLineNames[lineId2]) {
|
|
30299
|
+
return configuredLineNames[lineId2];
|
|
30300
|
+
}
|
|
30219
30301
|
if (lineNames[lineId2]) {
|
|
30220
30302
|
return lineNames[lineId2];
|
|
30221
30303
|
}
|
|
30222
30304
|
if (lineId2 === line1Id) return "Line 1";
|
|
30223
30305
|
if (lineId2 === line2Id) return "Line 2";
|
|
30224
|
-
return lineId2
|
|
30225
|
-
}, [lineNames, line1Id, line2Id]);
|
|
30306
|
+
return `Line ${lineId2.substring(0, 8)}`;
|
|
30307
|
+
}, [configuredLineNames, lineNames, line1Id, line2Id]);
|
|
30226
30308
|
const handleSortToggle = useCallback(() => {
|
|
30227
30309
|
setSortAscending(!sortAscending);
|
|
30228
30310
|
}, [sortAscending]);
|
|
@@ -33356,6 +33438,29 @@ var WorkspaceDetailView = ({
|
|
|
33356
33438
|
const isHistoricView = Boolean(date && parsedShiftId !== void 0);
|
|
33357
33439
|
const initialTab = getInitialTab(sourceType, defaultTab, fromMonthly, date);
|
|
33358
33440
|
const [activeTab, setActiveTab] = useState(initialTab);
|
|
33441
|
+
const dashboardConfig = useDashboardConfig();
|
|
33442
|
+
useEffect(() => {
|
|
33443
|
+
if (!dashboardConfig?.s3Config) return;
|
|
33444
|
+
const operationalDate2 = date || getOperationalDate();
|
|
33445
|
+
const cacheKey = `${workspaceId}-${operationalDate2}-${shift || "all"}-all-meta-1000--`;
|
|
33446
|
+
if (clipsCache[cacheKey]?.status) return;
|
|
33447
|
+
const service = new S3ClipsService(dashboardConfig);
|
|
33448
|
+
const promise = service.fetchClips({
|
|
33449
|
+
workspaceId,
|
|
33450
|
+
date: operationalDate2,
|
|
33451
|
+
shift: shift?.toString(),
|
|
33452
|
+
mode: "full",
|
|
33453
|
+
includeCycleTime: true,
|
|
33454
|
+
includeMetadata: true,
|
|
33455
|
+
limit: 1e3
|
|
33456
|
+
});
|
|
33457
|
+
clipsCache[cacheKey] = { status: "pending", promise };
|
|
33458
|
+
promise.then((videos) => {
|
|
33459
|
+
clipsCache[cacheKey] = { status: "resolved", data: videos };
|
|
33460
|
+
}).catch((err) => {
|
|
33461
|
+
clipsCache[cacheKey] = { status: "rejected", error: err };
|
|
33462
|
+
});
|
|
33463
|
+
}, [workspaceId, date, shift, dashboardConfig]);
|
|
33359
33464
|
const [isTransitioning, setIsTransitioning] = useState(false);
|
|
33360
33465
|
const [usingFallbackData, setUsingFallbackData] = useState(false);
|
|
33361
33466
|
const [showIdleTime, setShowIdleTime] = useState(false);
|