@optifye/dashboard-core 6.0.0 → 6.0.2
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 +54 -9
- package/dist/index.d.ts +54 -9
- package/dist/index.js +275 -275
- package/dist/index.mjs +275 -275
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -132,6 +132,9 @@ var DEFAULT_AUTH_CONFIG = {
|
|
|
132
132
|
// Defaults related to auth providers, redirects etc.
|
|
133
133
|
};
|
|
134
134
|
var DEFAULT_VIDEO_CONFIG = {
|
|
135
|
+
hlsUrls: {
|
|
136
|
+
lineWorkspaceHlsUrls: {}
|
|
137
|
+
},
|
|
135
138
|
canvasConfig: {
|
|
136
139
|
fps: 30,
|
|
137
140
|
useRAF: true
|
|
@@ -998,7 +1001,7 @@ var dashboardService = {
|
|
|
998
1001
|
const formattedStartDate = formatDate(startDate);
|
|
999
1002
|
const formattedEndDate = formatDate(endDate);
|
|
1000
1003
|
try {
|
|
1001
|
-
const { data, error } = await supabase.from(metricsTable).select("date, shift_id, efficiency, total_output, avg_cycle_time, ideal_output, avg_pph, pph_threshold, workspace_rank").eq("workspace_id", workspaceUuid).gte("date", formattedStartDate).lte("date", formattedEndDate).order("date", { ascending: true }).order("shift_id", { ascending: true });
|
|
1004
|
+
const { data, error } = await supabase.from(metricsTable).select("date, shift_id, efficiency, total_output, avg_cycle_time, ideal_output, avg_pph, pph_threshold, workspace_rank, idle_time").eq("workspace_id", workspaceUuid).gte("date", formattedStartDate).lte("date", formattedEndDate).order("date", { ascending: true }).order("shift_id", { ascending: true });
|
|
1002
1005
|
if (error) throw error;
|
|
1003
1006
|
if (!data) return [];
|
|
1004
1007
|
const transformedData = data.map((item) => ({
|
|
@@ -1011,7 +1014,8 @@ var dashboardService = {
|
|
|
1011
1014
|
ideal_output: item.ideal_output || 0,
|
|
1012
1015
|
avg_pph: item.avg_pph || 0,
|
|
1013
1016
|
pph_threshold: item.pph_threshold || 0,
|
|
1014
|
-
workspace_rank: item.workspace_rank || 0
|
|
1017
|
+
workspace_rank: item.workspace_rank || 0,
|
|
1018
|
+
idle_time: item.idle_time || 0
|
|
1015
1019
|
}));
|
|
1016
1020
|
return transformedData;
|
|
1017
1021
|
} catch (err) {
|
|
@@ -5095,19 +5099,23 @@ var useActiveBreaks = (lineIds) => {
|
|
|
5095
5099
|
const checkActiveBreaks = useCallback(async () => {
|
|
5096
5100
|
try {
|
|
5097
5101
|
setError(null);
|
|
5098
|
-
|
|
5102
|
+
const validLineIds = lineIds.filter(
|
|
5103
|
+
(id3) => id3 && id3 !== "factory" && id3 !== "all" && // Basic UUID format check
|
|
5104
|
+
id3.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i)
|
|
5105
|
+
);
|
|
5106
|
+
if (!validLineIds || validLineIds.length === 0) {
|
|
5099
5107
|
setActiveBreaks([]);
|
|
5100
5108
|
setIsLoading(false);
|
|
5101
5109
|
return;
|
|
5102
5110
|
}
|
|
5103
5111
|
const currentMinutes = getCurrentTimeInMinutes();
|
|
5104
|
-
const { data: dayShifts, error: dayError } = await supabase.from("line_operating_hours").select("line_id, start_time, end_time, breaks").eq("shift_id", 0).in("line_id",
|
|
5105
|
-
const { data: nightShifts, error: nightError } = await supabase.from("line_operating_hours").select("line_id, start_time, end_time, breaks").eq("shift_id", 1).in("line_id",
|
|
5112
|
+
const { data: dayShifts, error: dayError } = await supabase.from("line_operating_hours").select("line_id, start_time, end_time, breaks").eq("shift_id", 0).in("line_id", validLineIds);
|
|
5113
|
+
const { data: nightShifts, error: nightError } = await supabase.from("line_operating_hours").select("line_id, start_time, end_time, breaks").eq("shift_id", 1).in("line_id", validLineIds);
|
|
5106
5114
|
if (dayError || nightError) {
|
|
5107
5115
|
throw new Error("Failed to fetch shift configurations");
|
|
5108
5116
|
}
|
|
5109
5117
|
const foundActiveBreaks = [];
|
|
5110
|
-
for (const lineId of
|
|
5118
|
+
for (const lineId of validLineIds) {
|
|
5111
5119
|
const dayShift = dayShifts?.find((s) => s.line_id === lineId);
|
|
5112
5120
|
const nightShift = nightShifts?.find((s) => s.line_id === lineId);
|
|
5113
5121
|
if (!dayShift || !nightShift) continue;
|
|
@@ -5591,12 +5599,18 @@ var FALLBACK_DISPLAY_NAMES = {
|
|
|
5591
5599
|
"WS03": "Filling station"
|
|
5592
5600
|
// ... Add others if known defaults are useful
|
|
5593
5601
|
};
|
|
5594
|
-
var getConfigurableWorkspaceDisplayName = (workspaceId, workspaceConfig) => {
|
|
5602
|
+
var getConfigurableWorkspaceDisplayName = (workspaceId, workspaceConfig, lineId) => {
|
|
5603
|
+
if (lineId && workspaceConfig?.lineDisplayNames?.[lineId]) {
|
|
5604
|
+
const lineDisplayNames = workspaceConfig.lineDisplayNames[lineId];
|
|
5605
|
+
if (lineDisplayNames[workspaceId]) {
|
|
5606
|
+
return lineDisplayNames[workspaceId];
|
|
5607
|
+
}
|
|
5608
|
+
}
|
|
5595
5609
|
const displayNames = workspaceConfig?.displayNames || FALLBACK_DISPLAY_NAMES;
|
|
5596
5610
|
return displayNames[workspaceId] || workspaceId.replace(/^WS/i, "") || workspaceId;
|
|
5597
5611
|
};
|
|
5598
|
-
var getConfigurableShortWorkspaceDisplayName = (workspaceId, workspaceConfig) => {
|
|
5599
|
-
const fullName = getConfigurableWorkspaceDisplayName(workspaceId, workspaceConfig);
|
|
5612
|
+
var getConfigurableShortWorkspaceDisplayName = (workspaceId, workspaceConfig, lineId) => {
|
|
5613
|
+
const fullName = getConfigurableWorkspaceDisplayName(workspaceId, workspaceConfig, lineId);
|
|
5600
5614
|
const match = fullName.match(/([A-Z]\d+(?:-\w+)?)/i);
|
|
5601
5615
|
if (match && match[0]) {
|
|
5602
5616
|
return match[0];
|
|
@@ -17491,7 +17505,6 @@ var VideoCard = React14__default.memo(({
|
|
|
17491
17505
|
});
|
|
17492
17506
|
}
|
|
17493
17507
|
const displayName = getWorkspaceDisplayName(workspace.workspace_name);
|
|
17494
|
-
workspace.workspace_uuid || workspace.workspace_name;
|
|
17495
17508
|
const getEfficiencyOverlayColor = (efficiency) => {
|
|
17496
17509
|
if (efficiency >= 80) {
|
|
17497
17510
|
return "bg-[#00D654]/25";
|
|
@@ -17602,24 +17615,11 @@ var VideoCard = React14__default.memo(({
|
|
|
17602
17615
|
return prevProps.workspace.workspace_uuid === nextProps.workspace.workspace_uuid && prevProps.workspace.workspace_name === nextProps.workspace.workspace_name && Math.abs(prevProps.workspace.efficiency - nextProps.workspace.efficiency) < 1 && prevProps.hlsUrl === nextProps.hlsUrl && prevProps.shouldPlay === nextProps.shouldPlay && prevProps.cropping?.x === nextProps.cropping?.x && prevProps.cropping?.y === nextProps.cropping?.y && prevProps.cropping?.width === nextProps.cropping?.width && prevProps.cropping?.height === nextProps.cropping?.height;
|
|
17603
17616
|
});
|
|
17604
17617
|
VideoCard.displayName = "VideoCard";
|
|
17605
|
-
var DEFAULT_WORKSPACE_HLS_URLS = {
|
|
17606
|
-
"WS1": "https://dnh-hls.optifye.ai/cam1/index.m3u8",
|
|
17607
|
-
"WS2": "https://dnh-hls.optifye.ai/cam2/index.m3u8",
|
|
17608
|
-
"WS3": "https://dnh-hls.optifye.ai/cam3/index.m3u8",
|
|
17609
|
-
"WS4": "https://dnh-hls.optifye.ai/cam3/index.m3u8",
|
|
17610
|
-
"WS01": "https://59.144.218.58:8443/camera6.m3u8",
|
|
17611
|
-
"WS02": "https://59.144.218.58:8443/camera2.m3u8",
|
|
17612
|
-
"WS03": "https://59.144.218.58:8443/camera3.m3u8",
|
|
17613
|
-
"WS04": "https://59.144.218.58:8443/camera4.m3u8",
|
|
17614
|
-
"WS05": "https://59.144.218.58:8443/camera1.m3u8",
|
|
17615
|
-
"WS06": "https://59.144.218.58:8443/camera5.m3u8"
|
|
17616
|
-
};
|
|
17617
17618
|
var DEFAULT_HLS_URL = "https://192.168.5.9:8443/cam1.m3u8";
|
|
17618
17619
|
var VideoGridView = React14__default.memo(({
|
|
17619
17620
|
workspaces,
|
|
17620
17621
|
selectedLine,
|
|
17621
17622
|
className = "",
|
|
17622
|
-
lineIdMapping = {},
|
|
17623
17623
|
videoSources = {}
|
|
17624
17624
|
}) => {
|
|
17625
17625
|
const router = useRouter();
|
|
@@ -17628,13 +17628,20 @@ var VideoGridView = React14__default.memo(({
|
|
|
17628
17628
|
const [gridCols, setGridCols] = useState(4);
|
|
17629
17629
|
const [visibleWorkspaces, setVisibleWorkspaces] = useState(/* @__PURE__ */ new Set());
|
|
17630
17630
|
const videoConfig = useVideoConfig();
|
|
17631
|
-
const { cropping, canvasConfig } = videoConfig;
|
|
17631
|
+
const { cropping, canvasConfig, hlsUrls } = videoConfig;
|
|
17632
17632
|
const mergedVideoSources = {
|
|
17633
|
-
defaultHlsUrl: videoSources.defaultHlsUrl || DEFAULT_HLS_URL,
|
|
17634
|
-
workspaceHlsUrls: { ...
|
|
17633
|
+
defaultHlsUrl: videoSources.defaultHlsUrl || hlsUrls?.defaultHlsUrl || DEFAULT_HLS_URL,
|
|
17634
|
+
workspaceHlsUrls: { ...videoSources.workspaceHlsUrls, ...hlsUrls?.workspaceHlsUrls },
|
|
17635
|
+
lineWorkspaceHlsUrls: hlsUrls?.lineWorkspaceHlsUrls || {}
|
|
17635
17636
|
};
|
|
17636
|
-
const getWorkspaceHlsUrl = useCallback((workspaceName) => {
|
|
17637
|
+
const getWorkspaceHlsUrl = useCallback((workspaceName, lineId) => {
|
|
17637
17638
|
const wsName = workspaceName.toUpperCase();
|
|
17639
|
+
if (lineId && mergedVideoSources.lineWorkspaceHlsUrls[lineId]) {
|
|
17640
|
+
const lineUrls = mergedVideoSources.lineWorkspaceHlsUrls[lineId];
|
|
17641
|
+
if (lineUrls[wsName]) {
|
|
17642
|
+
return lineUrls[wsName];
|
|
17643
|
+
}
|
|
17644
|
+
}
|
|
17638
17645
|
return mergedVideoSources.workspaceHlsUrls[wsName] || mergedVideoSources.defaultHlsUrl;
|
|
17639
17646
|
}, [mergedVideoSources]);
|
|
17640
17647
|
const getWorkspaceCropping = useCallback((workspaceName) => {
|
|
@@ -17768,16 +17775,17 @@ var VideoGridView = React14__default.memo(({
|
|
|
17768
17775
|
minHeight: "100%"
|
|
17769
17776
|
},
|
|
17770
17777
|
children: filteredWorkspaces.sort((a, b) => {
|
|
17771
|
-
|
|
17772
|
-
|
|
17773
|
-
|
|
17774
|
-
|
|
17775
|
-
|
|
17776
|
-
|
|
17777
|
-
|
|
17778
|
-
|
|
17778
|
+
if (a.line_id !== b.line_id) {
|
|
17779
|
+
return (a.line_id || "").localeCompare(b.line_id || "");
|
|
17780
|
+
}
|
|
17781
|
+
const aMatch = a.workspace_name.match(/WS(\d+)/);
|
|
17782
|
+
const bMatch = b.workspace_name.match(/WS(\d+)/);
|
|
17783
|
+
if (aMatch && bMatch) {
|
|
17784
|
+
const aNum = parseInt(aMatch[1]);
|
|
17785
|
+
const bNum = parseInt(bMatch[1]);
|
|
17786
|
+
return aNum - bNum;
|
|
17779
17787
|
}
|
|
17780
|
-
return
|
|
17788
|
+
return a.workspace_name.localeCompare(b.workspace_name);
|
|
17781
17789
|
}).map((workspace) => {
|
|
17782
17790
|
const workspaceId = workspace.workspace_uuid || workspace.workspace_name;
|
|
17783
17791
|
const isVisible = visibleWorkspaces.has(workspaceId);
|
|
@@ -17793,7 +17801,7 @@ var VideoGridView = React14__default.memo(({
|
|
|
17793
17801
|
VideoCard,
|
|
17794
17802
|
{
|
|
17795
17803
|
workspace,
|
|
17796
|
-
hlsUrl: getWorkspaceHlsUrl(workspace.workspace_name),
|
|
17804
|
+
hlsUrl: getWorkspaceHlsUrl(workspace.workspace_name, workspace.line_id),
|
|
17797
17805
|
shouldPlay: isVisible,
|
|
17798
17806
|
onClick: () => handleWorkspaceClick(workspace),
|
|
17799
17807
|
onFatalError: throttledReloadDashboard,
|
|
@@ -21365,7 +21373,7 @@ function isValidShiftId(shiftId) {
|
|
|
21365
21373
|
}
|
|
21366
21374
|
|
|
21367
21375
|
// src/lib/api/s3-clips-parser.ts
|
|
21368
|
-
function parseS3Uri(s3Uri) {
|
|
21376
|
+
function parseS3Uri(s3Uri, sopCategories) {
|
|
21369
21377
|
const path = new URL(s3Uri).pathname;
|
|
21370
21378
|
const parts = path.split("/").filter((p) => p);
|
|
21371
21379
|
console.log("S3 URI:", s3Uri);
|
|
@@ -21405,6 +21413,27 @@ function parseS3Uri(s3Uri) {
|
|
|
21405
21413
|
let description = "Analysis Clip";
|
|
21406
21414
|
const normalizedViolationType = violationType.toLowerCase().trim();
|
|
21407
21415
|
console.log(`Parsing violation type: "${violationType}" (normalized: "${normalizedViolationType}") from path: ${s3Uri}`);
|
|
21416
|
+
if (sopCategories && sopCategories.length > 0) {
|
|
21417
|
+
const matchedCategory = sopCategories.find((category) => {
|
|
21418
|
+
const categoryId = category.id.toLowerCase();
|
|
21419
|
+
const s3FolderName = (category.s3FolderName || category.id).toLowerCase();
|
|
21420
|
+
return categoryId === normalizedViolationType || s3FolderName === normalizedViolationType || // Also check for partial matches for flexibility
|
|
21421
|
+
normalizedViolationType.includes(categoryId) || normalizedViolationType.includes(s3FolderName);
|
|
21422
|
+
});
|
|
21423
|
+
if (matchedCategory) {
|
|
21424
|
+
type = matchedCategory.id;
|
|
21425
|
+
description = matchedCategory.description || matchedCategory.label;
|
|
21426
|
+
if (matchedCategory.color.includes("red")) {
|
|
21427
|
+
severity = "high";
|
|
21428
|
+
} else if (matchedCategory.color.includes("yellow") || matchedCategory.color.includes("orange")) {
|
|
21429
|
+
severity = "medium";
|
|
21430
|
+
} else {
|
|
21431
|
+
severity = "low";
|
|
21432
|
+
}
|
|
21433
|
+
console.log(`Matched SOP category: ${matchedCategory.id} for violation type: ${violationType}`);
|
|
21434
|
+
return { timestamp, severity, description, type, originalUri: s3Uri };
|
|
21435
|
+
}
|
|
21436
|
+
}
|
|
21408
21437
|
switch (normalizedViolationType) {
|
|
21409
21438
|
case "idle_time":
|
|
21410
21439
|
case "idle":
|
|
@@ -21496,6 +21525,11 @@ var S3ClipsService = class {
|
|
|
21496
21525
|
if (!config.s3Config) {
|
|
21497
21526
|
throw new Error("S3 configuration is required");
|
|
21498
21527
|
}
|
|
21528
|
+
const processing = config.s3Config.processing || {};
|
|
21529
|
+
this.defaultLimitPerCategory = processing.defaultLimitPerCategory || 30;
|
|
21530
|
+
this.maxLimitPerCategory = processing.maxLimitPerCategory || 1e3;
|
|
21531
|
+
this.concurrencyLimit = processing.concurrencyLimit || 10;
|
|
21532
|
+
this.maxInitialFetch = processing.maxInitialFetch || 60;
|
|
21499
21533
|
const region = this.validateAndSanitizeRegion(config.s3Config.region);
|
|
21500
21534
|
console.log(`S3ClipsService: Using AWS region: ${region}`);
|
|
21501
21535
|
this.s3Client = new S3Client({
|
|
@@ -21644,11 +21678,23 @@ var S3ClipsService = class {
|
|
|
21644
21678
|
const key = url.pathname.startsWith("/") ? url.pathname.substring(1) : url.pathname;
|
|
21645
21679
|
return `${this.config.s3Config.cloudFrontDomain}/${key}`;
|
|
21646
21680
|
}
|
|
21681
|
+
/**
|
|
21682
|
+
* Gets SOP categories for a specific workspace
|
|
21683
|
+
*/
|
|
21684
|
+
getSOPCategories(workspaceId) {
|
|
21685
|
+
const sopConfig = this.config.s3Config?.sopCategories;
|
|
21686
|
+
if (!sopConfig) return void 0;
|
|
21687
|
+
if (sopConfig.workspaceOverrides && sopConfig.workspaceOverrides[workspaceId]) {
|
|
21688
|
+
return sopConfig.workspaceOverrides[workspaceId];
|
|
21689
|
+
}
|
|
21690
|
+
return sopConfig.default;
|
|
21691
|
+
}
|
|
21647
21692
|
/**
|
|
21648
21693
|
* Processes a single video completely
|
|
21649
21694
|
*/
|
|
21650
21695
|
async processFullVideo(uri, index, workspaceId, date, shiftId, includeCycleTime, includeMetadata = false) {
|
|
21651
|
-
const
|
|
21696
|
+
const sopCategories = this.getSOPCategories(workspaceId);
|
|
21697
|
+
const parsedInfo = parseS3Uri(uri, sopCategories);
|
|
21652
21698
|
if (!parsedInfo) {
|
|
21653
21699
|
console.warn(`Skipping URI due to parsing failure: ${uri}`);
|
|
21654
21700
|
return null;
|
|
@@ -21681,27 +21727,32 @@ var S3ClipsService = class {
|
|
|
21681
21727
|
async getVideoSummary(workspaceId, date, shiftId) {
|
|
21682
21728
|
const s3Uris = await this.listS3Clips({ workspaceId, date, shiftId });
|
|
21683
21729
|
console.log(`S3ClipsService getVideoSummary: Processing ${s3Uris.length} total URIs for accurate category counts`);
|
|
21684
|
-
const
|
|
21685
|
-
|
|
21686
|
-
|
|
21687
|
-
|
|
21688
|
-
|
|
21689
|
-
|
|
21690
|
-
|
|
21691
|
-
|
|
21692
|
-
|
|
21693
|
-
|
|
21694
|
-
|
|
21695
|
-
|
|
21696
|
-
|
|
21697
|
-
|
|
21698
|
-
|
|
21699
|
-
|
|
21700
|
-
|
|
21701
|
-
|
|
21702
|
-
|
|
21730
|
+
const sopCategories = this.getSOPCategories(workspaceId);
|
|
21731
|
+
const counts = { total: 0 };
|
|
21732
|
+
const samples = {};
|
|
21733
|
+
if (sopCategories && sopCategories.length > 0) {
|
|
21734
|
+
sopCategories.forEach((category) => {
|
|
21735
|
+
counts[category.id] = 0;
|
|
21736
|
+
samples[category.id] = null;
|
|
21737
|
+
});
|
|
21738
|
+
} else {
|
|
21739
|
+
counts.best_cycle_time = 0;
|
|
21740
|
+
counts.worst_cycle_time = 0;
|
|
21741
|
+
counts.bottleneck = 0;
|
|
21742
|
+
counts.low_value = 0;
|
|
21743
|
+
counts.long_cycle_time = 0;
|
|
21744
|
+
counts.missing_quality_check = 0;
|
|
21745
|
+
counts.cycle_completions = 0;
|
|
21746
|
+
samples.best_cycle_time = null;
|
|
21747
|
+
samples.worst_cycle_time = null;
|
|
21748
|
+
samples.bottleneck = null;
|
|
21749
|
+
samples.low_value = null;
|
|
21750
|
+
samples.long_cycle_time = null;
|
|
21751
|
+
samples.missing_quality_check = null;
|
|
21752
|
+
samples.cycle_completions = null;
|
|
21753
|
+
}
|
|
21703
21754
|
for (const uri of s3Uris) {
|
|
21704
|
-
const parsedInfo = parseS3Uri(uri);
|
|
21755
|
+
const parsedInfo = parseS3Uri(uri, sopCategories);
|
|
21705
21756
|
if (parsedInfo) {
|
|
21706
21757
|
const { type } = parsedInfo;
|
|
21707
21758
|
counts[type] = (counts[type] || 0) + 1;
|
|
@@ -21763,9 +21814,9 @@ var S3ClipsService = class {
|
|
|
21763
21814
|
}
|
|
21764
21815
|
return summary;
|
|
21765
21816
|
}
|
|
21766
|
-
const limitPerCategory = limit ? Math.min(Math.max(limit, 1),
|
|
21817
|
+
const limitPerCategory = limit ? Math.min(Math.max(limit, 1), this.maxLimitPerCategory) : this.defaultLimitPerCategory;
|
|
21767
21818
|
const shouldFetchAll = category === "missing_quality_check" || category === "low_value";
|
|
21768
|
-
const initialFetchLimit = shouldFetchAll ? void 0 : category ? limitPerCategory * 3 : void 0;
|
|
21819
|
+
const initialFetchLimit = shouldFetchAll ? void 0 : category ? Math.min(limitPerCategory * 3, this.maxInitialFetch) : void 0;
|
|
21769
21820
|
const s3Uris = await this.listS3Clips({ workspaceId, date, shiftId, maxKeys: initialFetchLimit });
|
|
21770
21821
|
if (s3Uris.length === 0) {
|
|
21771
21822
|
console.log(`S3ClipsService: No HLS playlists found for workspace ${workspaceId} on date ${date}, shift ${shiftId}`);
|
|
@@ -21833,12 +21884,11 @@ var S3ClipsService = class {
|
|
|
21833
21884
|
}
|
|
21834
21885
|
console.log(`S3ClipsService: Total filtered URIs across all categories: ${filteredUris.length}`);
|
|
21835
21886
|
}
|
|
21836
|
-
const concurrencyLimit = 10;
|
|
21837
21887
|
let processedCount = 0;
|
|
21838
21888
|
const videoResults = [];
|
|
21839
21889
|
console.log(`S3ClipsService: Processing ${filteredUris.length} URIs for ${category || "all categories"} with limit ${limitPerCategory} per category`);
|
|
21840
|
-
for (let i = 0; i < filteredUris.length; i += concurrencyLimit) {
|
|
21841
|
-
const batch = filteredUris.slice(i, i + concurrencyLimit);
|
|
21890
|
+
for (let i = 0; i < filteredUris.length; i += this.concurrencyLimit) {
|
|
21891
|
+
const batch = filteredUris.slice(i, i + this.concurrencyLimit);
|
|
21842
21892
|
const batchPromises = batch.map(async (uri, batchIndex) => {
|
|
21843
21893
|
const index = i + batchIndex;
|
|
21844
21894
|
const result = await this.processFullVideo(uri, index, workspaceId, date, shiftId, includeCycleTime || false, includeMetadata || (!!timestampStart || !!timestampEnd));
|
|
@@ -21914,6 +21964,14 @@ var BottlenecksContent = ({
|
|
|
21914
21964
|
className
|
|
21915
21965
|
}) => {
|
|
21916
21966
|
const dashboardConfig = useDashboardConfig();
|
|
21967
|
+
const sopCategories = React14__default.useMemo(() => {
|
|
21968
|
+
const sopConfig = dashboardConfig?.s3Config?.sopCategories;
|
|
21969
|
+
if (!sopConfig) return null;
|
|
21970
|
+
if (sopConfig.workspaceOverrides && sopConfig.workspaceOverrides[workspaceId]) {
|
|
21971
|
+
return sopConfig.workspaceOverrides[workspaceId];
|
|
21972
|
+
}
|
|
21973
|
+
return sopConfig.default;
|
|
21974
|
+
}, [dashboardConfig, workspaceId]);
|
|
21917
21975
|
const videoRef = useRef(null);
|
|
21918
21976
|
const fullscreenContainerRef = useRef(null);
|
|
21919
21977
|
const timestampFilterRef = useRef(null);
|
|
@@ -21922,7 +21980,9 @@ var BottlenecksContent = ({
|
|
|
21922
21980
|
const [duration, setDuration] = useState(0);
|
|
21923
21981
|
const [isFullscreen, setIsFullscreen] = useState(false);
|
|
21924
21982
|
const [currentIndex, setCurrentIndex] = useState(0);
|
|
21925
|
-
const [activeFilter, setActiveFilter] = useState(
|
|
21983
|
+
const [activeFilter, setActiveFilter] = useState(
|
|
21984
|
+
sopCategories && sopCategories.length > 0 ? sopCategories[0].id : "low_value"
|
|
21985
|
+
);
|
|
21926
21986
|
const [allVideos, setAllVideos] = useState([]);
|
|
21927
21987
|
const [isLoading, setIsLoading] = useState(true);
|
|
21928
21988
|
const [error, setError] = useState(null);
|
|
@@ -22034,27 +22094,41 @@ var BottlenecksContent = ({
|
|
|
22034
22094
|
let filtered = [];
|
|
22035
22095
|
if (activeFilter === "all") {
|
|
22036
22096
|
filtered = [...allVideos];
|
|
22037
|
-
} else if (activeFilter === "low_value") {
|
|
22038
|
-
filtered = allVideos.filter((video) => video.type === "low_value");
|
|
22039
|
-
} else if (activeFilter === "sop_deviations") {
|
|
22040
|
-
filtered = allVideos.filter((video) => video.type === "missing_quality_check");
|
|
22041
|
-
} else if (activeFilter === "best_cycle_time") {
|
|
22042
|
-
filtered = allVideos.filter((video) => video.type === "best_cycle_time");
|
|
22043
|
-
} else if (activeFilter === "worst_cycle_time") {
|
|
22044
|
-
filtered = allVideos.filter((video) => video.type === "worst_cycle_time");
|
|
22045
|
-
} else if (activeFilter === "cycle_completions") {
|
|
22046
|
-
filtered = allVideos.filter((video) => video.type === "cycle_completions");
|
|
22047
|
-
} else if (activeFilter === "long_cycle_time") {
|
|
22048
|
-
filtered = allVideos.filter(
|
|
22049
|
-
(video) => video.type === "bottleneck" && video.description.toLowerCase().includes("cycle time")
|
|
22050
|
-
);
|
|
22051
22097
|
} else {
|
|
22052
|
-
|
|
22098
|
+
if (sopCategories && sopCategories.length > 0) {
|
|
22099
|
+
const selectedCategory = sopCategories.find((cat) => cat.id === activeFilter);
|
|
22100
|
+
if (selectedCategory) {
|
|
22101
|
+
filtered = allVideos.filter((video) => video.type === selectedCategory.id);
|
|
22102
|
+
if (selectedCategory.id === "long_cycle_time") {
|
|
22103
|
+
filtered = allVideos.filter(
|
|
22104
|
+
(video) => video.type === "bottleneck" && video.description.toLowerCase().includes("cycle time")
|
|
22105
|
+
);
|
|
22106
|
+
}
|
|
22107
|
+
}
|
|
22108
|
+
} else {
|
|
22109
|
+
if (activeFilter === "low_value") {
|
|
22110
|
+
filtered = allVideos.filter((video) => video.type === "low_value");
|
|
22111
|
+
} else if (activeFilter === "sop_deviations") {
|
|
22112
|
+
filtered = allVideos.filter((video) => video.type === "missing_quality_check");
|
|
22113
|
+
} else if (activeFilter === "best_cycle_time") {
|
|
22114
|
+
filtered = allVideos.filter((video) => video.type === "best_cycle_time");
|
|
22115
|
+
} else if (activeFilter === "worst_cycle_time") {
|
|
22116
|
+
filtered = allVideos.filter((video) => video.type === "worst_cycle_time");
|
|
22117
|
+
} else if (activeFilter === "cycle_completions") {
|
|
22118
|
+
filtered = allVideos.filter((video) => video.type === "cycle_completions");
|
|
22119
|
+
} else if (activeFilter === "long_cycle_time") {
|
|
22120
|
+
filtered = allVideos.filter(
|
|
22121
|
+
(video) => video.type === "bottleneck" && video.description.toLowerCase().includes("cycle time")
|
|
22122
|
+
);
|
|
22123
|
+
} else {
|
|
22124
|
+
filtered = allVideos.filter((video) => video.type === "bottleneck" && video.severity === activeFilter);
|
|
22125
|
+
}
|
|
22126
|
+
}
|
|
22053
22127
|
}
|
|
22054
22128
|
return filtered.sort((a, b) => {
|
|
22055
22129
|
return new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime();
|
|
22056
22130
|
});
|
|
22057
|
-
}, [activeFilter, allVideos]);
|
|
22131
|
+
}, [activeFilter, allVideos, sopCategories]);
|
|
22058
22132
|
useEffect(() => {
|
|
22059
22133
|
if (filteredVideos.length === 0) return;
|
|
22060
22134
|
const upcoming = [];
|
|
@@ -22328,35 +22402,34 @@ var BottlenecksContent = ({
|
|
|
22328
22402
|
}
|
|
22329
22403
|
};
|
|
22330
22404
|
const clipCounts = useMemo(() => {
|
|
22331
|
-
if (!allVideos) return {
|
|
22332
|
-
|
|
22333
|
-
|
|
22334
|
-
|
|
22335
|
-
|
|
22336
|
-
|
|
22337
|
-
|
|
22338
|
-
|
|
22339
|
-
|
|
22340
|
-
|
|
22341
|
-
|
|
22342
|
-
|
|
22343
|
-
}
|
|
22344
|
-
|
|
22345
|
-
|
|
22346
|
-
|
|
22347
|
-
|
|
22348
|
-
|
|
22349
|
-
|
|
22350
|
-
|
|
22351
|
-
|
|
22352
|
-
|
|
22353
|
-
longCycleTimes: allVideos.filter(
|
|
22405
|
+
if (!allVideos) return {};
|
|
22406
|
+
const counts = { total: allVideos.length };
|
|
22407
|
+
if (sopCategories && sopCategories.length > 0) {
|
|
22408
|
+
sopCategories.forEach((category) => {
|
|
22409
|
+
if (category.id === "long_cycle_time") {
|
|
22410
|
+
counts[category.id] = allVideos.filter(
|
|
22411
|
+
(video) => video.type === "bottleneck" && video.description.toLowerCase().includes("cycle time")
|
|
22412
|
+
).length;
|
|
22413
|
+
} else {
|
|
22414
|
+
counts[category.id] = allVideos.filter((video) => video.type === category.id).length;
|
|
22415
|
+
}
|
|
22416
|
+
});
|
|
22417
|
+
} else {
|
|
22418
|
+
counts.bottlenecks = allVideos.filter((video) => video.type === "bottleneck").length;
|
|
22419
|
+
counts.lowValue = allVideos.filter((video) => video.type === "low_value").length;
|
|
22420
|
+
counts.highSeverity = allVideos.filter((video) => video.severity === "high" && video.type === "bottleneck").length;
|
|
22421
|
+
counts.mediumSeverity = allVideos.filter((video) => video.severity === "medium" && video.type === "bottleneck").length;
|
|
22422
|
+
counts.lowSeverity = allVideos.filter((video) => video.severity === "low" && video.type === "bottleneck").length;
|
|
22423
|
+
counts.sopDeviations = allVideos.filter((video) => video.type === "missing_quality_check").length;
|
|
22424
|
+
counts.bestCycleTimes = allVideos.filter((video) => video.type === "best_cycle_time").length;
|
|
22425
|
+
counts.worstCycleTimes = allVideos.filter((video) => video.type === "worst_cycle_time").length;
|
|
22426
|
+
counts.longCycleTimes = allVideos.filter(
|
|
22354
22427
|
(video) => video.type === "bottleneck" && video.description.toLowerCase().includes("cycle time")
|
|
22355
|
-
).length
|
|
22356
|
-
cycleCompletions
|
|
22357
|
-
|
|
22358
|
-
|
|
22359
|
-
}, [allVideos]);
|
|
22428
|
+
).length;
|
|
22429
|
+
counts.cycleCompletions = allVideos.filter((video) => video.type === "cycle_completions").length;
|
|
22430
|
+
}
|
|
22431
|
+
return counts;
|
|
22432
|
+
}, [allVideos, sopCategories]);
|
|
22360
22433
|
const currentVideo = useMemo(() => {
|
|
22361
22434
|
if (!filteredVideos || filteredVideos.length === 0 || currentIndex >= filteredVideos.length) {
|
|
22362
22435
|
return null;
|
|
@@ -22378,9 +22451,22 @@ var BottlenecksContent = ({
|
|
|
22378
22451
|
return "Cycle Completion";
|
|
22379
22452
|
case "bottleneck":
|
|
22380
22453
|
default:
|
|
22381
|
-
return "
|
|
22454
|
+
return "";
|
|
22382
22455
|
}
|
|
22383
22456
|
};
|
|
22457
|
+
const getColorClasses = (color2) => {
|
|
22458
|
+
const colorMap = {
|
|
22459
|
+
purple: { text: "text-purple-500", bg: "bg-purple-500", dot: "bg-purple-500" },
|
|
22460
|
+
green: { text: "text-green-600", bg: "bg-green-600", dot: "bg-green-600" },
|
|
22461
|
+
red: { text: "text-red-700", bg: "bg-red-700", dot: "bg-red-700" },
|
|
22462
|
+
"red-dark": { text: "text-red-500", bg: "bg-red-500", dot: "bg-red-500" },
|
|
22463
|
+
blue: { text: "text-blue-600", bg: "bg-blue-600", dot: "bg-blue-600" },
|
|
22464
|
+
orange: { text: "text-orange-600", bg: "bg-orange-600", dot: "bg-orange-600" },
|
|
22465
|
+
yellow: { text: "text-yellow-600", bg: "bg-yellow-600", dot: "bg-yellow-600" },
|
|
22466
|
+
gray: { text: "text-gray-600", bg: "bg-gray-600", dot: "bg-gray-600" }
|
|
22467
|
+
};
|
|
22468
|
+
return colorMap[color2] || colorMap.gray;
|
|
22469
|
+
};
|
|
22384
22470
|
const formatTimeOnly = (time2) => {
|
|
22385
22471
|
if (!time2) return "";
|
|
22386
22472
|
try {
|
|
@@ -22410,162 +22496,62 @@ var BottlenecksContent = ({
|
|
|
22410
22496
|
/* @__PURE__ */ jsx("p", { className: "text-gray-600 max-w-md", children: error })
|
|
22411
22497
|
] });
|
|
22412
22498
|
}
|
|
22499
|
+
const categoriesToShow = sopCategories && sopCategories.length > 0 ? sopCategories : [
|
|
22500
|
+
// Default hardcoded categories if no configuration
|
|
22501
|
+
{ id: "low_value", label: "Idle Moments", color: "purple", subtitle: "Idle time detected" },
|
|
22502
|
+
{ id: "best_cycle_time", label: "Best Cycle Time", color: "green", subtitle: "Fastest cycle today" },
|
|
22503
|
+
{ id: "worst_cycle_time", label: "Worst Cycle Time", color: "red", subtitle: "Slowest cycle today" },
|
|
22504
|
+
{ id: "long_cycle_time", label: "Long Cycle Time", color: "red-dark", subtitle: "Above standard cycle times" },
|
|
22505
|
+
{ id: "cycle_completions", label: "Cycle Completions", color: "blue", subtitle: "Completed production cycles" }
|
|
22506
|
+
];
|
|
22413
22507
|
return /* @__PURE__ */ jsxs("div", { className: "flex-grow p-1.5 sm:p-2 lg:p-4 h-[calc(100vh-12rem)]", children: [
|
|
22414
|
-
/* @__PURE__ */
|
|
22415
|
-
|
|
22416
|
-
|
|
22417
|
-
|
|
22418
|
-
onClick: () => {
|
|
22419
|
-
setActiveFilter("low_value");
|
|
22420
|
-
trackCoreEvent("Idle Moments Filter Clicked", {
|
|
22421
|
-
workspaceId,
|
|
22422
|
-
workspaceName,
|
|
22423
|
-
date,
|
|
22424
|
-
filterType: "low_value",
|
|
22425
|
-
clipCount: clipCounts.lowValue
|
|
22426
|
-
});
|
|
22427
|
-
},
|
|
22428
|
-
className: `bg-white shadow-sm cursor-pointer transition-all duration-200 hover:bg-gray-50 ${activeFilter === "low_value" ? "bg-blue-50 shadow-md ring-1 ring-blue-200" : ""}`,
|
|
22429
|
-
"aria-label": `Filter by Idle Moments (${clipCounts.lowValue} clips)`,
|
|
22430
|
-
role: "button",
|
|
22431
|
-
tabIndex: 0,
|
|
22432
|
-
onKeyDown: (e) => e.key === "Enter" && setActiveFilter("low_value"),
|
|
22433
|
-
children: [
|
|
22434
|
-
/* @__PURE__ */ jsx(CardHeader2, { className: "pb-2", children: /* @__PURE__ */ jsx(CardTitle2, { className: `text-lg ${activeFilter === "low_value" ? "text-blue-600" : ""}`, children: "Idle Moments" }) }),
|
|
22435
|
-
/* @__PURE__ */ jsx(CardContent2, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col justify-center", children: [
|
|
22436
|
-
/* @__PURE__ */ jsx("p", { className: "text-3xl font-bold text-purple-500", children: clipCounts.lowValue }),
|
|
22437
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center text-sm text-gray-500 mt-1", children: [
|
|
22438
|
-
/* @__PURE__ */ jsx("div", { className: "h-2 w-2 rounded-full bg-purple-500 mr-1.5" }),
|
|
22439
|
-
/* @__PURE__ */ jsx("span", { children: "Idle time detected" })
|
|
22440
|
-
] })
|
|
22441
|
-
] }) })
|
|
22442
|
-
]
|
|
22443
|
-
}
|
|
22444
|
-
),
|
|
22445
|
-
/* @__PURE__ */ jsxs(
|
|
22446
|
-
Card2,
|
|
22447
|
-
{
|
|
22448
|
-
onClick: () => {
|
|
22449
|
-
setActiveFilter("best_cycle_time");
|
|
22450
|
-
trackCoreEvent("Best Cycle Time Filter Clicked", {
|
|
22451
|
-
workspaceId,
|
|
22452
|
-
workspaceName,
|
|
22453
|
-
date,
|
|
22454
|
-
filterType: "best_cycle_time",
|
|
22455
|
-
clipCount: clipCounts.bestCycleTimes
|
|
22456
|
-
});
|
|
22457
|
-
},
|
|
22458
|
-
className: `bg-white shadow-sm cursor-pointer transition-all duration-200 hover:bg-gray-50 ${activeFilter === "best_cycle_time" ? "bg-blue-50 shadow-md ring-1 ring-blue-200" : ""}`,
|
|
22459
|
-
"aria-label": `Filter by Best Cycle Time (${clipCounts.bestCycleTimes} clips)`,
|
|
22460
|
-
role: "button",
|
|
22461
|
-
tabIndex: 0,
|
|
22462
|
-
onKeyDown: (e) => e.key === "Enter" && setActiveFilter("best_cycle_time"),
|
|
22463
|
-
children: [
|
|
22464
|
-
/* @__PURE__ */ jsx(CardHeader2, { className: "pb-2", children: /* @__PURE__ */ jsx(CardTitle2, { className: `text-lg ${activeFilter === "best_cycle_time" ? "text-blue-600" : ""}`, children: "Best Cycle Time" }) }),
|
|
22465
|
-
/* @__PURE__ */ jsx(CardContent2, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col justify-center", children: [
|
|
22466
|
-
/* @__PURE__ */ jsx("p", { className: "text-3xl font-bold text-green-600", children: clipCounts.bestCycleTimes }),
|
|
22467
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center text-sm text-gray-500 mt-1", children: [
|
|
22468
|
-
/* @__PURE__ */ jsx("div", { className: "h-2 w-2 rounded-full bg-green-600 mr-1.5" }),
|
|
22469
|
-
/* @__PURE__ */ jsx("span", { children: "Fastest cycle today" })
|
|
22470
|
-
] })
|
|
22471
|
-
] }) })
|
|
22472
|
-
]
|
|
22473
|
-
}
|
|
22474
|
-
),
|
|
22475
|
-
/* @__PURE__ */ jsxs(
|
|
22476
|
-
Card2,
|
|
22477
|
-
{
|
|
22478
|
-
onClick: () => {
|
|
22479
|
-
setActiveFilter("worst_cycle_time");
|
|
22480
|
-
trackCoreEvent("Worst Cycle Time Filter Clicked", {
|
|
22481
|
-
workspaceId,
|
|
22482
|
-
workspaceName,
|
|
22483
|
-
date,
|
|
22484
|
-
filterType: "worst_cycle_time",
|
|
22485
|
-
clipCount: clipCounts.worstCycleTimes
|
|
22486
|
-
});
|
|
22487
|
-
},
|
|
22488
|
-
className: `bg-white shadow-sm cursor-pointer transition-all duration-200 hover:bg-gray-50 ${activeFilter === "worst_cycle_time" ? "bg-blue-50 shadow-md ring-1 ring-blue-200" : ""}`,
|
|
22489
|
-
"aria-label": `Filter by Worst Cycle Time (${clipCounts.worstCycleTimes} clips)`,
|
|
22490
|
-
role: "button",
|
|
22491
|
-
tabIndex: 0,
|
|
22492
|
-
onKeyDown: (e) => e.key === "Enter" && setActiveFilter("worst_cycle_time"),
|
|
22493
|
-
children: [
|
|
22494
|
-
/* @__PURE__ */ jsx(CardHeader2, { className: "pb-2", children: /* @__PURE__ */ jsx(CardTitle2, { className: `text-lg ${activeFilter === "worst_cycle_time" ? "text-blue-600" : ""}`, children: "Worst Cycle Time" }) }),
|
|
22495
|
-
/* @__PURE__ */ jsx(CardContent2, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col justify-center", children: [
|
|
22496
|
-
/* @__PURE__ */ jsx("p", { className: "text-3xl font-bold text-red-700", children: clipCounts.worstCycleTimes }),
|
|
22497
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center text-sm text-gray-500 mt-1", children: [
|
|
22498
|
-
/* @__PURE__ */ jsx("div", { className: "h-2 w-2 rounded-full bg-red-700 mr-1.5" }),
|
|
22499
|
-
/* @__PURE__ */ jsx("span", { children: "Slowest cycle today" })
|
|
22500
|
-
] })
|
|
22501
|
-
] }) })
|
|
22502
|
-
]
|
|
22503
|
-
}
|
|
22504
|
-
),
|
|
22505
|
-
/* @__PURE__ */ jsxs(
|
|
22508
|
+
/* @__PURE__ */ jsx("div", { className: `grid grid-cols-1 sm:grid-cols-2 ${categoriesToShow.length <= 5 ? "lg:grid-cols-5" : "lg:grid-cols-6"} gap-3 mb-4`, children: categoriesToShow.map((category) => {
|
|
22509
|
+
const colorClasses = getColorClasses(category.color);
|
|
22510
|
+
const count = clipCounts[category.id] || 0;
|
|
22511
|
+
return /* @__PURE__ */ jsxs(
|
|
22506
22512
|
Card2,
|
|
22507
22513
|
{
|
|
22508
22514
|
onClick: () => {
|
|
22509
|
-
setActiveFilter(
|
|
22510
|
-
trackCoreEvent(
|
|
22515
|
+
setActiveFilter(category.id);
|
|
22516
|
+
trackCoreEvent(`${category.label} Filter Clicked`, {
|
|
22511
22517
|
workspaceId,
|
|
22512
22518
|
workspaceName,
|
|
22513
22519
|
date,
|
|
22514
|
-
filterType:
|
|
22515
|
-
clipCount:
|
|
22520
|
+
filterType: category.id,
|
|
22521
|
+
clipCount: count
|
|
22516
22522
|
});
|
|
22517
22523
|
},
|
|
22518
|
-
className: `bg-white shadow-sm cursor-pointer transition-all duration-200 hover:bg-gray-50 ${activeFilter ===
|
|
22519
|
-
"aria-label": `Filter by
|
|
22524
|
+
className: `bg-white shadow-sm cursor-pointer transition-all duration-200 hover:bg-gray-50 ${activeFilter === category.id ? "bg-blue-50 shadow-md ring-1 ring-blue-200" : ""}`,
|
|
22525
|
+
"aria-label": `Filter by ${category.label} (${count} clips)`,
|
|
22520
22526
|
role: "button",
|
|
22521
22527
|
tabIndex: 0,
|
|
22522
|
-
onKeyDown: (e) => e.key === "Enter" && setActiveFilter(
|
|
22528
|
+
onKeyDown: (e) => e.key === "Enter" && setActiveFilter(category.id),
|
|
22523
22529
|
children: [
|
|
22524
|
-
/* @__PURE__ */ jsx(CardHeader2, { className: "pb-2", children: /* @__PURE__ */ jsx(CardTitle2, { className: `text-lg ${activeFilter ===
|
|
22530
|
+
/* @__PURE__ */ jsx(CardHeader2, { className: "pb-2", children: /* @__PURE__ */ jsx(CardTitle2, { className: `text-lg ${activeFilter === category.id ? "text-blue-600" : ""}`, children: category.label }) }),
|
|
22525
22531
|
/* @__PURE__ */ jsx(CardContent2, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col justify-center", children: [
|
|
22526
|
-
/* @__PURE__ */ jsx("p", { className:
|
|
22532
|
+
/* @__PURE__ */ jsx("p", { className: `text-3xl font-bold ${colorClasses.text}`, children: count }),
|
|
22527
22533
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center text-sm text-gray-500 mt-1", children: [
|
|
22528
|
-
/* @__PURE__ */ jsx("div", { className:
|
|
22529
|
-
/* @__PURE__ */ jsx("span", { children:
|
|
22534
|
+
/* @__PURE__ */ jsx("div", { className: `h-2 w-2 rounded-full ${colorClasses.dot} mr-1.5` }),
|
|
22535
|
+
/* @__PURE__ */ jsx("span", { children: category.subtitle || category.description || category.label })
|
|
22530
22536
|
] })
|
|
22531
22537
|
] }) })
|
|
22532
22538
|
]
|
|
22533
|
-
}
|
|
22534
|
-
|
|
22535
|
-
|
|
22536
|
-
|
|
22537
|
-
{
|
|
22538
|
-
onClick: () => {
|
|
22539
|
-
setActiveFilter("cycle_completions");
|
|
22540
|
-
trackCoreEvent("Cycle Completions Filter Clicked", {
|
|
22541
|
-
workspaceId,
|
|
22542
|
-
workspaceName,
|
|
22543
|
-
date,
|
|
22544
|
-
filterType: "cycle_completions",
|
|
22545
|
-
clipCount: clipCounts.cycleCompletions
|
|
22546
|
-
});
|
|
22547
|
-
},
|
|
22548
|
-
className: `bg-white shadow-sm cursor-pointer transition-all duration-200 hover:bg-gray-50 ${activeFilter === "cycle_completions" ? "bg-blue-50 shadow-md ring-1 ring-blue-200" : ""}`,
|
|
22549
|
-
"aria-label": `Filter by Cycle Completions (${clipCounts.cycleCompletions} clips)`,
|
|
22550
|
-
role: "button",
|
|
22551
|
-
tabIndex: 0,
|
|
22552
|
-
onKeyDown: (e) => e.key === "Enter" && setActiveFilter("cycle_completions"),
|
|
22553
|
-
children: [
|
|
22554
|
-
/* @__PURE__ */ jsx(CardHeader2, { className: "pb-2", children: /* @__PURE__ */ jsx(CardTitle2, { className: `text-lg ${activeFilter === "cycle_completions" ? "text-blue-600" : ""}`, children: "Cycle Completions" }) }),
|
|
22555
|
-
/* @__PURE__ */ jsx(CardContent2, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col justify-center", children: [
|
|
22556
|
-
/* @__PURE__ */ jsx("p", { className: "text-3xl font-bold text-blue-600", children: clipCounts.cycleCompletions }),
|
|
22557
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center text-sm text-gray-500 mt-1", children: [
|
|
22558
|
-
/* @__PURE__ */ jsx("div", { className: "h-2 w-2 rounded-full bg-blue-600 mr-1.5" }),
|
|
22559
|
-
/* @__PURE__ */ jsx("span", { children: "Completed production cycles" })
|
|
22560
|
-
] })
|
|
22561
|
-
] }) })
|
|
22562
|
-
]
|
|
22563
|
-
}
|
|
22564
|
-
)
|
|
22565
|
-
] }),
|
|
22539
|
+
},
|
|
22540
|
+
category.id
|
|
22541
|
+
);
|
|
22542
|
+
}) }),
|
|
22566
22543
|
/* @__PURE__ */ jsxs("div", { className: "bg-white rounded-lg shadow-sm overflow-hidden", style: { height: "calc(100% - 8.5rem)" }, children: [
|
|
22567
22544
|
/* @__PURE__ */ jsx("div", { className: "px-4 py-3 border-b border-gray-100", children: /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center", children: [
|
|
22568
|
-
/* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold text-gray-800", children:
|
|
22545
|
+
/* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold text-gray-800", children: (() => {
|
|
22546
|
+
if (activeFilter === "all") {
|
|
22547
|
+
return `All Clips (${clipCounts.total || 0})`;
|
|
22548
|
+
}
|
|
22549
|
+
const activeCategory = categoriesToShow.find((cat) => cat.id === activeFilter);
|
|
22550
|
+
if (activeCategory) {
|
|
22551
|
+
return `${activeCategory.label} (${clipCounts[activeCategory.id] || 0})`;
|
|
22552
|
+
}
|
|
22553
|
+
return activeFilter === "low_value" ? `Idle Moments (${clipCounts.lowValue || 0})` : activeFilter === "best_cycle_time" ? `Best Cycle Time (${clipCounts.bestCycleTimes || 0})` : activeFilter === "worst_cycle_time" ? `Worst Cycle Time (${clipCounts.worstCycleTimes || 0})` : activeFilter === "long_cycle_time" ? `Long Cycle Time (${clipCounts.longCycleTimes || 0})` : activeFilter === "cycle_completions" ? `Cycle Completions (${clipCounts.cycleCompletions || 0})` : `All Clips (${clipCounts.total || 0})`;
|
|
22554
|
+
})() }),
|
|
22569
22555
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2", children: [
|
|
22570
22556
|
/* @__PURE__ */ jsxs("div", { className: "relative", ref: timestampFilterRef, children: [
|
|
22571
22557
|
/* @__PURE__ */ jsx(
|
|
@@ -24941,14 +24927,6 @@ var AIAgentView = () => {
|
|
|
24941
24927
|
return newMap;
|
|
24942
24928
|
});
|
|
24943
24929
|
},
|
|
24944
|
-
onReasoning: (text) => {
|
|
24945
|
-
setStreamingStates((prev) => {
|
|
24946
|
-
const newMap = new Map(prev);
|
|
24947
|
-
const current = newMap.get(currentThreadId) || { message: "", reasoning: "" };
|
|
24948
|
-
newMap.set(currentThreadId, { ...current, reasoning: current.reasoning + text });
|
|
24949
|
-
return newMap;
|
|
24950
|
-
});
|
|
24951
|
-
},
|
|
24952
24930
|
onComplete: async (messageId) => {
|
|
24953
24931
|
if (currentThreadId && !currentThreadId.startsWith("temp-")) {
|
|
24954
24932
|
const updatedMessages = await getAllThreadMessages(currentThreadId);
|
|
@@ -27337,14 +27315,20 @@ function HomeView({
|
|
|
27337
27315
|
}) {
|
|
27338
27316
|
const [isHydrated, setIsHydrated] = useState(false);
|
|
27339
27317
|
const availableLineIds = useMemo(() => [factoryViewId, ...allLineIds], [factoryViewId, allLineIds]);
|
|
27340
|
-
const [selectedLineId, setSelectedLineId] = useState(
|
|
27318
|
+
const [selectedLineId, setSelectedLineId] = useState(factoryViewId);
|
|
27341
27319
|
const [isChangingFilter, setIsChangingFilter] = useState(false);
|
|
27342
27320
|
const [errorMessage, setErrorMessage] = useState(null);
|
|
27343
27321
|
const [displayNamesInitialized, setDisplayNamesInitialized] = useState(false);
|
|
27344
27322
|
useEffect(() => {
|
|
27345
27323
|
const initDisplayNames = async () => {
|
|
27346
27324
|
try {
|
|
27347
|
-
|
|
27325
|
+
if (selectedLineId === factoryViewId) {
|
|
27326
|
+
for (const lineId of allLineIds) {
|
|
27327
|
+
await preInitializeWorkspaceDisplayNames(lineId);
|
|
27328
|
+
}
|
|
27329
|
+
} else {
|
|
27330
|
+
await preInitializeWorkspaceDisplayNames(selectedLineId);
|
|
27331
|
+
}
|
|
27348
27332
|
setDisplayNamesInitialized(true);
|
|
27349
27333
|
} catch (error) {
|
|
27350
27334
|
console.error("Failed to pre-initialize workspace display names:", error);
|
|
@@ -27352,7 +27336,7 @@ function HomeView({
|
|
|
27352
27336
|
}
|
|
27353
27337
|
};
|
|
27354
27338
|
initDisplayNames();
|
|
27355
|
-
}, [selectedLineId]);
|
|
27339
|
+
}, [selectedLineId, factoryViewId, allLineIds]);
|
|
27356
27340
|
const {
|
|
27357
27341
|
displayNames: workspaceDisplayNames,
|
|
27358
27342
|
loading: displayNamesLoading,
|
|
@@ -27385,11 +27369,17 @@ function HomeView({
|
|
|
27385
27369
|
lineId: selectedLineId,
|
|
27386
27370
|
onLineMetricsUpdate
|
|
27387
27371
|
});
|
|
27372
|
+
const lineIdsForBreaks = useMemo(() => {
|
|
27373
|
+
if (selectedLineId === factoryViewId) {
|
|
27374
|
+
return allLineIds;
|
|
27375
|
+
}
|
|
27376
|
+
return [selectedLineId];
|
|
27377
|
+
}, [selectedLineId, factoryViewId, allLineIds]);
|
|
27388
27378
|
const {
|
|
27389
27379
|
activeBreaks,
|
|
27390
27380
|
isLoading: breaksLoading,
|
|
27391
27381
|
error: breaksError
|
|
27392
|
-
} = useActiveBreaks(
|
|
27382
|
+
} = useActiveBreaks(lineIdsForBreaks);
|
|
27393
27383
|
const memoizedWorkspaceMetrics = useMemo(() => workspaceMetrics, [
|
|
27394
27384
|
// Only update reference if meaningful properties change
|
|
27395
27385
|
workspaceMetrics.length,
|
|
@@ -27432,10 +27422,15 @@ function HomeView({
|
|
|
27432
27422
|
const lineTitle = useMemo(() => {
|
|
27433
27423
|
return factoryName;
|
|
27434
27424
|
}, [factoryName]);
|
|
27435
|
-
const lineSelectorComponent = useMemo(() =>
|
|
27436
|
-
|
|
27437
|
-
|
|
27438
|
-
|
|
27425
|
+
const lineSelectorComponent = useMemo(() => {
|
|
27426
|
+
if (allLineIds.length <= 1) {
|
|
27427
|
+
return null;
|
|
27428
|
+
}
|
|
27429
|
+
return /* @__PURE__ */ jsxs(Select, { onValueChange: handleLineChange, defaultValue: selectedLineId, children: [
|
|
27430
|
+
/* @__PURE__ */ jsx(SelectTrigger, { className: "w-full sm:w-[200px] bg-white border border-gray-200 shadow-sm rounded-md h-9 text-sm", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Select a line" }) }),
|
|
27431
|
+
/* @__PURE__ */ jsx(SelectContent, { className: "z-50 bg-white shadow-lg border border-gray-200 rounded-md", children: availableLineIds.map((id3) => /* @__PURE__ */ jsx(SelectItem, { value: id3, children: lineNames[id3] || (id3 === factoryViewId ? "All Lines" : `Line ${id3.substring(0, 4)}`) }, id3)) })
|
|
27432
|
+
] });
|
|
27433
|
+
}, [availableLineIds, handleLineChange, selectedLineId, lineNames, factoryViewId, allLineIds.length]);
|
|
27439
27434
|
const isLoading = !isHydrated || metricsLoading || kpisLoading || isChangingFilter || displayNamesLoading || !displayNamesInitialized;
|
|
27440
27435
|
if (isLoading) {
|
|
27441
27436
|
return /* @__PURE__ */ jsx("div", { className: "min-h-screen bg-slate-50", children: /* @__PURE__ */ jsx(LoadingPageCmp, { message: "Loading dashboard..." }) });
|
|
@@ -27471,7 +27466,7 @@ function HomeView({
|
|
|
27471
27466
|
}
|
|
27472
27467
|
) }) }),
|
|
27473
27468
|
/* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto sm:overflow-hidden relative", children: [
|
|
27474
|
-
/* @__PURE__ */ jsx("div", { className: "absolute right-3 top-2 sm:right-6 sm:top-3 z-30", children: lineSelectorComponent }),
|
|
27469
|
+
lineSelectorComponent && /* @__PURE__ */ jsx("div", { className: "absolute right-3 top-2 sm:right-6 sm:top-3 z-30", children: lineSelectorComponent }),
|
|
27475
27470
|
memoizedWorkspaceMetrics.length > 0 ? /* @__PURE__ */ jsx("div", { className: "h-full sm:h-full min-h-[calc(100vh-80px)] sm:min-h-0", children: React14__default.createElement(WorkspaceGrid, {
|
|
27476
27471
|
workspaces: memoizedWorkspaceMetrics,
|
|
27477
27472
|
lineNames,
|
|
@@ -28651,8 +28646,7 @@ var MobileWorkspaceCard = memo(({
|
|
|
28651
28646
|
cardClass,
|
|
28652
28647
|
onWorkspaceClick,
|
|
28653
28648
|
getMedalIcon,
|
|
28654
|
-
|
|
28655
|
-
line2Id
|
|
28649
|
+
getLineName
|
|
28656
28650
|
}) => /* @__PURE__ */ jsxs(
|
|
28657
28651
|
"div",
|
|
28658
28652
|
{
|
|
@@ -28670,7 +28664,7 @@ var MobileWorkspaceCard = memo(({
|
|
|
28670
28664
|
] }),
|
|
28671
28665
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
28672
28666
|
/* @__PURE__ */ jsx("div", { className: "font-semibold text-gray-900", children: getWorkspaceDisplayName(workspace.workspace_name) }),
|
|
28673
|
-
/* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500", children: workspace.line_id
|
|
28667
|
+
/* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500", children: getLineName(workspace.line_id) })
|
|
28674
28668
|
] })
|
|
28675
28669
|
] }),
|
|
28676
28670
|
/* @__PURE__ */ jsxs("div", { className: "text-right", children: [
|
|
@@ -28708,8 +28702,7 @@ var DesktopWorkspaceRow = memo(({
|
|
|
28708
28702
|
rowClass,
|
|
28709
28703
|
onWorkspaceClick,
|
|
28710
28704
|
getMedalIcon,
|
|
28711
|
-
|
|
28712
|
-
line2Id
|
|
28705
|
+
getLineName
|
|
28713
28706
|
}) => /* @__PURE__ */ jsxs(
|
|
28714
28707
|
"tr",
|
|
28715
28708
|
{
|
|
@@ -28721,7 +28714,7 @@ var DesktopWorkspaceRow = memo(({
|
|
|
28721
28714
|
getMedalIcon(index + 1)
|
|
28722
28715
|
] }) }),
|
|
28723
28716
|
/* @__PURE__ */ jsx("td", { className: "px-3 py-2.5 sm:p-4 text-sm sm:text-base whitespace-nowrap", children: /* @__PURE__ */ jsx("div", { className: "font-medium", children: getWorkspaceDisplayName(workspace.workspace_name) }) }),
|
|
28724
|
-
/* @__PURE__ */ jsx("td", { className: "px-3 py-2.5 sm:p-4 text-sm sm:text-base whitespace-nowrap", children: /* @__PURE__ */ jsx("div", { className: "font-medium", children: workspace.line_id
|
|
28717
|
+
/* @__PURE__ */ jsx("td", { className: "px-3 py-2.5 sm:p-4 text-sm sm:text-base whitespace-nowrap", children: /* @__PURE__ */ jsx("div", { className: "font-medium", children: getLineName(workspace.line_id) }) }),
|
|
28725
28718
|
/* @__PURE__ */ jsxs("td", { className: "px-3 py-2.5 sm:p-4 text-sm sm:text-base font-medium whitespace-nowrap", children: [
|
|
28726
28719
|
(workspace.efficiency || 0).toFixed(1),
|
|
28727
28720
|
"%"
|
|
@@ -28749,10 +28742,19 @@ var LeaderboardDetailView = memo(({
|
|
|
28749
28742
|
onWorkspaceClick,
|
|
28750
28743
|
line1Id = "",
|
|
28751
28744
|
line2Id = "",
|
|
28745
|
+
lineNames = {},
|
|
28752
28746
|
className = ""
|
|
28753
28747
|
}) => {
|
|
28754
28748
|
const navigation = useNavigation();
|
|
28755
28749
|
const [sortAscending, setSortAscending] = useState(false);
|
|
28750
|
+
const getLineName = useCallback((lineId2) => {
|
|
28751
|
+
if (lineNames[lineId2]) {
|
|
28752
|
+
return lineNames[lineId2];
|
|
28753
|
+
}
|
|
28754
|
+
if (lineId2 === line1Id) return "Line 1";
|
|
28755
|
+
if (lineId2 === line2Id) return "Line 2";
|
|
28756
|
+
return lineId2;
|
|
28757
|
+
}, [lineNames, line1Id, line2Id]);
|
|
28756
28758
|
const handleSortToggle = useCallback(() => {
|
|
28757
28759
|
setSortAscending(!sortAscending);
|
|
28758
28760
|
}, [sortAscending]);
|
|
@@ -28926,8 +28928,7 @@ var LeaderboardDetailView = memo(({
|
|
|
28926
28928
|
cardClass,
|
|
28927
28929
|
onWorkspaceClick: handleWorkspaceClick,
|
|
28928
28930
|
getMedalIcon,
|
|
28929
|
-
|
|
28930
|
-
line2Id
|
|
28931
|
+
getLineName
|
|
28931
28932
|
},
|
|
28932
28933
|
ws.workspace_uuid
|
|
28933
28934
|
);
|
|
@@ -28952,8 +28953,7 @@ var LeaderboardDetailView = memo(({
|
|
|
28952
28953
|
rowClass,
|
|
28953
28954
|
onWorkspaceClick: handleWorkspaceClick,
|
|
28954
28955
|
getMedalIcon,
|
|
28955
|
-
|
|
28956
|
-
line2Id
|
|
28956
|
+
getLineName
|
|
28957
28957
|
},
|
|
28958
28958
|
ws.workspace_uuid
|
|
28959
28959
|
);
|
|
@@ -28962,7 +28962,7 @@ var LeaderboardDetailView = memo(({
|
|
|
28962
28962
|
] })
|
|
28963
28963
|
] });
|
|
28964
28964
|
}, (prevProps, nextProps) => {
|
|
28965
|
-
return prevProps.lineId === nextProps.lineId && prevProps.date === nextProps.date && prevProps.shift === nextProps.shift && prevProps.line1Id === nextProps.line1Id && prevProps.line2Id === nextProps.line2Id && prevProps.className === nextProps.className && prevProps.onBackClick === nextProps.onBackClick && prevProps.onWorkspaceClick === nextProps.onWorkspaceClick;
|
|
28965
|
+
return prevProps.lineId === nextProps.lineId && prevProps.date === nextProps.date && prevProps.shift === nextProps.shift && prevProps.line1Id === nextProps.line1Id && prevProps.line2Id === nextProps.line2Id && JSON.stringify(prevProps.lineNames) === JSON.stringify(nextProps.lineNames) && prevProps.className === nextProps.className && prevProps.onBackClick === nextProps.onBackClick && prevProps.onWorkspaceClick === nextProps.onWorkspaceClick;
|
|
28966
28966
|
});
|
|
28967
28967
|
LeaderboardDetailView.displayName = "LeaderboardDetailView";
|
|
28968
28968
|
var LeaderboardDetailView_default = LeaderboardDetailView;
|