@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.js
CHANGED
|
@@ -161,6 +161,9 @@ var DEFAULT_AUTH_CONFIG = {
|
|
|
161
161
|
// Defaults related to auth providers, redirects etc.
|
|
162
162
|
};
|
|
163
163
|
var DEFAULT_VIDEO_CONFIG = {
|
|
164
|
+
hlsUrls: {
|
|
165
|
+
lineWorkspaceHlsUrls: {}
|
|
166
|
+
},
|
|
164
167
|
canvasConfig: {
|
|
165
168
|
fps: 30,
|
|
166
169
|
useRAF: true
|
|
@@ -1027,7 +1030,7 @@ var dashboardService = {
|
|
|
1027
1030
|
const formattedStartDate = formatDate(startDate);
|
|
1028
1031
|
const formattedEndDate = formatDate(endDate);
|
|
1029
1032
|
try {
|
|
1030
|
-
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 });
|
|
1033
|
+
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 });
|
|
1031
1034
|
if (error) throw error;
|
|
1032
1035
|
if (!data) return [];
|
|
1033
1036
|
const transformedData = data.map((item) => ({
|
|
@@ -1040,7 +1043,8 @@ var dashboardService = {
|
|
|
1040
1043
|
ideal_output: item.ideal_output || 0,
|
|
1041
1044
|
avg_pph: item.avg_pph || 0,
|
|
1042
1045
|
pph_threshold: item.pph_threshold || 0,
|
|
1043
|
-
workspace_rank: item.workspace_rank || 0
|
|
1046
|
+
workspace_rank: item.workspace_rank || 0,
|
|
1047
|
+
idle_time: item.idle_time || 0
|
|
1044
1048
|
}));
|
|
1045
1049
|
return transformedData;
|
|
1046
1050
|
} catch (err) {
|
|
@@ -5124,19 +5128,23 @@ var useActiveBreaks = (lineIds) => {
|
|
|
5124
5128
|
const checkActiveBreaks = React14.useCallback(async () => {
|
|
5125
5129
|
try {
|
|
5126
5130
|
setError(null);
|
|
5127
|
-
|
|
5131
|
+
const validLineIds = lineIds.filter(
|
|
5132
|
+
(id3) => id3 && id3 !== "factory" && id3 !== "all" && // Basic UUID format check
|
|
5133
|
+
id3.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i)
|
|
5134
|
+
);
|
|
5135
|
+
if (!validLineIds || validLineIds.length === 0) {
|
|
5128
5136
|
setActiveBreaks([]);
|
|
5129
5137
|
setIsLoading(false);
|
|
5130
5138
|
return;
|
|
5131
5139
|
}
|
|
5132
5140
|
const currentMinutes = getCurrentTimeInMinutes();
|
|
5133
|
-
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",
|
|
5134
|
-
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",
|
|
5141
|
+
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);
|
|
5142
|
+
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);
|
|
5135
5143
|
if (dayError || nightError) {
|
|
5136
5144
|
throw new Error("Failed to fetch shift configurations");
|
|
5137
5145
|
}
|
|
5138
5146
|
const foundActiveBreaks = [];
|
|
5139
|
-
for (const lineId of
|
|
5147
|
+
for (const lineId of validLineIds) {
|
|
5140
5148
|
const dayShift = dayShifts?.find((s) => s.line_id === lineId);
|
|
5141
5149
|
const nightShift = nightShifts?.find((s) => s.line_id === lineId);
|
|
5142
5150
|
if (!dayShift || !nightShift) continue;
|
|
@@ -5620,12 +5628,18 @@ var FALLBACK_DISPLAY_NAMES = {
|
|
|
5620
5628
|
"WS03": "Filling station"
|
|
5621
5629
|
// ... Add others if known defaults are useful
|
|
5622
5630
|
};
|
|
5623
|
-
var getConfigurableWorkspaceDisplayName = (workspaceId, workspaceConfig) => {
|
|
5631
|
+
var getConfigurableWorkspaceDisplayName = (workspaceId, workspaceConfig, lineId) => {
|
|
5632
|
+
if (lineId && workspaceConfig?.lineDisplayNames?.[lineId]) {
|
|
5633
|
+
const lineDisplayNames = workspaceConfig.lineDisplayNames[lineId];
|
|
5634
|
+
if (lineDisplayNames[workspaceId]) {
|
|
5635
|
+
return lineDisplayNames[workspaceId];
|
|
5636
|
+
}
|
|
5637
|
+
}
|
|
5624
5638
|
const displayNames = workspaceConfig?.displayNames || FALLBACK_DISPLAY_NAMES;
|
|
5625
5639
|
return displayNames[workspaceId] || workspaceId.replace(/^WS/i, "") || workspaceId;
|
|
5626
5640
|
};
|
|
5627
|
-
var getConfigurableShortWorkspaceDisplayName = (workspaceId, workspaceConfig) => {
|
|
5628
|
-
const fullName = getConfigurableWorkspaceDisplayName(workspaceId, workspaceConfig);
|
|
5641
|
+
var getConfigurableShortWorkspaceDisplayName = (workspaceId, workspaceConfig, lineId) => {
|
|
5642
|
+
const fullName = getConfigurableWorkspaceDisplayName(workspaceId, workspaceConfig, lineId);
|
|
5629
5643
|
const match = fullName.match(/([A-Z]\d+(?:-\w+)?)/i);
|
|
5630
5644
|
if (match && match[0]) {
|
|
5631
5645
|
return match[0];
|
|
@@ -17520,7 +17534,6 @@ var VideoCard = React14__namespace.default.memo(({
|
|
|
17520
17534
|
});
|
|
17521
17535
|
}
|
|
17522
17536
|
const displayName = getWorkspaceDisplayName(workspace.workspace_name);
|
|
17523
|
-
workspace.workspace_uuid || workspace.workspace_name;
|
|
17524
17537
|
const getEfficiencyOverlayColor = (efficiency) => {
|
|
17525
17538
|
if (efficiency >= 80) {
|
|
17526
17539
|
return "bg-[#00D654]/25";
|
|
@@ -17631,24 +17644,11 @@ var VideoCard = React14__namespace.default.memo(({
|
|
|
17631
17644
|
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;
|
|
17632
17645
|
});
|
|
17633
17646
|
VideoCard.displayName = "VideoCard";
|
|
17634
|
-
var DEFAULT_WORKSPACE_HLS_URLS = {
|
|
17635
|
-
"WS1": "https://dnh-hls.optifye.ai/cam1/index.m3u8",
|
|
17636
|
-
"WS2": "https://dnh-hls.optifye.ai/cam2/index.m3u8",
|
|
17637
|
-
"WS3": "https://dnh-hls.optifye.ai/cam3/index.m3u8",
|
|
17638
|
-
"WS4": "https://dnh-hls.optifye.ai/cam3/index.m3u8",
|
|
17639
|
-
"WS01": "https://59.144.218.58:8443/camera6.m3u8",
|
|
17640
|
-
"WS02": "https://59.144.218.58:8443/camera2.m3u8",
|
|
17641
|
-
"WS03": "https://59.144.218.58:8443/camera3.m3u8",
|
|
17642
|
-
"WS04": "https://59.144.218.58:8443/camera4.m3u8",
|
|
17643
|
-
"WS05": "https://59.144.218.58:8443/camera1.m3u8",
|
|
17644
|
-
"WS06": "https://59.144.218.58:8443/camera5.m3u8"
|
|
17645
|
-
};
|
|
17646
17647
|
var DEFAULT_HLS_URL = "https://192.168.5.9:8443/cam1.m3u8";
|
|
17647
17648
|
var VideoGridView = React14__namespace.default.memo(({
|
|
17648
17649
|
workspaces,
|
|
17649
17650
|
selectedLine,
|
|
17650
17651
|
className = "",
|
|
17651
|
-
lineIdMapping = {},
|
|
17652
17652
|
videoSources = {}
|
|
17653
17653
|
}) => {
|
|
17654
17654
|
const router$1 = router.useRouter();
|
|
@@ -17657,13 +17657,20 @@ var VideoGridView = React14__namespace.default.memo(({
|
|
|
17657
17657
|
const [gridCols, setGridCols] = React14.useState(4);
|
|
17658
17658
|
const [visibleWorkspaces, setVisibleWorkspaces] = React14.useState(/* @__PURE__ */ new Set());
|
|
17659
17659
|
const videoConfig = useVideoConfig();
|
|
17660
|
-
const { cropping, canvasConfig } = videoConfig;
|
|
17660
|
+
const { cropping, canvasConfig, hlsUrls } = videoConfig;
|
|
17661
17661
|
const mergedVideoSources = {
|
|
17662
|
-
defaultHlsUrl: videoSources.defaultHlsUrl || DEFAULT_HLS_URL,
|
|
17663
|
-
workspaceHlsUrls: { ...
|
|
17662
|
+
defaultHlsUrl: videoSources.defaultHlsUrl || hlsUrls?.defaultHlsUrl || DEFAULT_HLS_URL,
|
|
17663
|
+
workspaceHlsUrls: { ...videoSources.workspaceHlsUrls, ...hlsUrls?.workspaceHlsUrls },
|
|
17664
|
+
lineWorkspaceHlsUrls: hlsUrls?.lineWorkspaceHlsUrls || {}
|
|
17664
17665
|
};
|
|
17665
|
-
const getWorkspaceHlsUrl = React14.useCallback((workspaceName) => {
|
|
17666
|
+
const getWorkspaceHlsUrl = React14.useCallback((workspaceName, lineId) => {
|
|
17666
17667
|
const wsName = workspaceName.toUpperCase();
|
|
17668
|
+
if (lineId && mergedVideoSources.lineWorkspaceHlsUrls[lineId]) {
|
|
17669
|
+
const lineUrls = mergedVideoSources.lineWorkspaceHlsUrls[lineId];
|
|
17670
|
+
if (lineUrls[wsName]) {
|
|
17671
|
+
return lineUrls[wsName];
|
|
17672
|
+
}
|
|
17673
|
+
}
|
|
17667
17674
|
return mergedVideoSources.workspaceHlsUrls[wsName] || mergedVideoSources.defaultHlsUrl;
|
|
17668
17675
|
}, [mergedVideoSources]);
|
|
17669
17676
|
const getWorkspaceCropping = React14.useCallback((workspaceName) => {
|
|
@@ -17797,16 +17804,17 @@ var VideoGridView = React14__namespace.default.memo(({
|
|
|
17797
17804
|
minHeight: "100%"
|
|
17798
17805
|
},
|
|
17799
17806
|
children: filteredWorkspaces.sort((a, b) => {
|
|
17800
|
-
|
|
17801
|
-
|
|
17802
|
-
|
|
17803
|
-
|
|
17804
|
-
|
|
17805
|
-
|
|
17806
|
-
|
|
17807
|
-
|
|
17807
|
+
if (a.line_id !== b.line_id) {
|
|
17808
|
+
return (a.line_id || "").localeCompare(b.line_id || "");
|
|
17809
|
+
}
|
|
17810
|
+
const aMatch = a.workspace_name.match(/WS(\d+)/);
|
|
17811
|
+
const bMatch = b.workspace_name.match(/WS(\d+)/);
|
|
17812
|
+
if (aMatch && bMatch) {
|
|
17813
|
+
const aNum = parseInt(aMatch[1]);
|
|
17814
|
+
const bNum = parseInt(bMatch[1]);
|
|
17815
|
+
return aNum - bNum;
|
|
17808
17816
|
}
|
|
17809
|
-
return
|
|
17817
|
+
return a.workspace_name.localeCompare(b.workspace_name);
|
|
17810
17818
|
}).map((workspace) => {
|
|
17811
17819
|
const workspaceId = workspace.workspace_uuid || workspace.workspace_name;
|
|
17812
17820
|
const isVisible = visibleWorkspaces.has(workspaceId);
|
|
@@ -17822,7 +17830,7 @@ var VideoGridView = React14__namespace.default.memo(({
|
|
|
17822
17830
|
VideoCard,
|
|
17823
17831
|
{
|
|
17824
17832
|
workspace,
|
|
17825
|
-
hlsUrl: getWorkspaceHlsUrl(workspace.workspace_name),
|
|
17833
|
+
hlsUrl: getWorkspaceHlsUrl(workspace.workspace_name, workspace.line_id),
|
|
17826
17834
|
shouldPlay: isVisible,
|
|
17827
17835
|
onClick: () => handleWorkspaceClick(workspace),
|
|
17828
17836
|
onFatalError: throttledReloadDashboard,
|
|
@@ -21394,7 +21402,7 @@ function isValidShiftId(shiftId) {
|
|
|
21394
21402
|
}
|
|
21395
21403
|
|
|
21396
21404
|
// src/lib/api/s3-clips-parser.ts
|
|
21397
|
-
function parseS3Uri(s3Uri) {
|
|
21405
|
+
function parseS3Uri(s3Uri, sopCategories) {
|
|
21398
21406
|
const path = new URL(s3Uri).pathname;
|
|
21399
21407
|
const parts = path.split("/").filter((p) => p);
|
|
21400
21408
|
console.log("S3 URI:", s3Uri);
|
|
@@ -21434,6 +21442,27 @@ function parseS3Uri(s3Uri) {
|
|
|
21434
21442
|
let description = "Analysis Clip";
|
|
21435
21443
|
const normalizedViolationType = violationType.toLowerCase().trim();
|
|
21436
21444
|
console.log(`Parsing violation type: "${violationType}" (normalized: "${normalizedViolationType}") from path: ${s3Uri}`);
|
|
21445
|
+
if (sopCategories && sopCategories.length > 0) {
|
|
21446
|
+
const matchedCategory = sopCategories.find((category) => {
|
|
21447
|
+
const categoryId = category.id.toLowerCase();
|
|
21448
|
+
const s3FolderName = (category.s3FolderName || category.id).toLowerCase();
|
|
21449
|
+
return categoryId === normalizedViolationType || s3FolderName === normalizedViolationType || // Also check for partial matches for flexibility
|
|
21450
|
+
normalizedViolationType.includes(categoryId) || normalizedViolationType.includes(s3FolderName);
|
|
21451
|
+
});
|
|
21452
|
+
if (matchedCategory) {
|
|
21453
|
+
type = matchedCategory.id;
|
|
21454
|
+
description = matchedCategory.description || matchedCategory.label;
|
|
21455
|
+
if (matchedCategory.color.includes("red")) {
|
|
21456
|
+
severity = "high";
|
|
21457
|
+
} else if (matchedCategory.color.includes("yellow") || matchedCategory.color.includes("orange")) {
|
|
21458
|
+
severity = "medium";
|
|
21459
|
+
} else {
|
|
21460
|
+
severity = "low";
|
|
21461
|
+
}
|
|
21462
|
+
console.log(`Matched SOP category: ${matchedCategory.id} for violation type: ${violationType}`);
|
|
21463
|
+
return { timestamp, severity, description, type, originalUri: s3Uri };
|
|
21464
|
+
}
|
|
21465
|
+
}
|
|
21437
21466
|
switch (normalizedViolationType) {
|
|
21438
21467
|
case "idle_time":
|
|
21439
21468
|
case "idle":
|
|
@@ -21525,6 +21554,11 @@ var S3ClipsService = class {
|
|
|
21525
21554
|
if (!config.s3Config) {
|
|
21526
21555
|
throw new Error("S3 configuration is required");
|
|
21527
21556
|
}
|
|
21557
|
+
const processing = config.s3Config.processing || {};
|
|
21558
|
+
this.defaultLimitPerCategory = processing.defaultLimitPerCategory || 30;
|
|
21559
|
+
this.maxLimitPerCategory = processing.maxLimitPerCategory || 1e3;
|
|
21560
|
+
this.concurrencyLimit = processing.concurrencyLimit || 10;
|
|
21561
|
+
this.maxInitialFetch = processing.maxInitialFetch || 60;
|
|
21528
21562
|
const region = this.validateAndSanitizeRegion(config.s3Config.region);
|
|
21529
21563
|
console.log(`S3ClipsService: Using AWS region: ${region}`);
|
|
21530
21564
|
this.s3Client = new clientS3.S3Client({
|
|
@@ -21673,11 +21707,23 @@ var S3ClipsService = class {
|
|
|
21673
21707
|
const key = url.pathname.startsWith("/") ? url.pathname.substring(1) : url.pathname;
|
|
21674
21708
|
return `${this.config.s3Config.cloudFrontDomain}/${key}`;
|
|
21675
21709
|
}
|
|
21710
|
+
/**
|
|
21711
|
+
* Gets SOP categories for a specific workspace
|
|
21712
|
+
*/
|
|
21713
|
+
getSOPCategories(workspaceId) {
|
|
21714
|
+
const sopConfig = this.config.s3Config?.sopCategories;
|
|
21715
|
+
if (!sopConfig) return void 0;
|
|
21716
|
+
if (sopConfig.workspaceOverrides && sopConfig.workspaceOverrides[workspaceId]) {
|
|
21717
|
+
return sopConfig.workspaceOverrides[workspaceId];
|
|
21718
|
+
}
|
|
21719
|
+
return sopConfig.default;
|
|
21720
|
+
}
|
|
21676
21721
|
/**
|
|
21677
21722
|
* Processes a single video completely
|
|
21678
21723
|
*/
|
|
21679
21724
|
async processFullVideo(uri, index, workspaceId, date, shiftId, includeCycleTime, includeMetadata = false) {
|
|
21680
|
-
const
|
|
21725
|
+
const sopCategories = this.getSOPCategories(workspaceId);
|
|
21726
|
+
const parsedInfo = parseS3Uri(uri, sopCategories);
|
|
21681
21727
|
if (!parsedInfo) {
|
|
21682
21728
|
console.warn(`Skipping URI due to parsing failure: ${uri}`);
|
|
21683
21729
|
return null;
|
|
@@ -21710,27 +21756,32 @@ var S3ClipsService = class {
|
|
|
21710
21756
|
async getVideoSummary(workspaceId, date, shiftId) {
|
|
21711
21757
|
const s3Uris = await this.listS3Clips({ workspaceId, date, shiftId });
|
|
21712
21758
|
console.log(`S3ClipsService getVideoSummary: Processing ${s3Uris.length} total URIs for accurate category counts`);
|
|
21713
|
-
const
|
|
21714
|
-
|
|
21715
|
-
|
|
21716
|
-
|
|
21717
|
-
|
|
21718
|
-
|
|
21719
|
-
|
|
21720
|
-
|
|
21721
|
-
|
|
21722
|
-
|
|
21723
|
-
|
|
21724
|
-
|
|
21725
|
-
|
|
21726
|
-
|
|
21727
|
-
|
|
21728
|
-
|
|
21729
|
-
|
|
21730
|
-
|
|
21731
|
-
|
|
21759
|
+
const sopCategories = this.getSOPCategories(workspaceId);
|
|
21760
|
+
const counts = { total: 0 };
|
|
21761
|
+
const samples = {};
|
|
21762
|
+
if (sopCategories && sopCategories.length > 0) {
|
|
21763
|
+
sopCategories.forEach((category) => {
|
|
21764
|
+
counts[category.id] = 0;
|
|
21765
|
+
samples[category.id] = null;
|
|
21766
|
+
});
|
|
21767
|
+
} else {
|
|
21768
|
+
counts.best_cycle_time = 0;
|
|
21769
|
+
counts.worst_cycle_time = 0;
|
|
21770
|
+
counts.bottleneck = 0;
|
|
21771
|
+
counts.low_value = 0;
|
|
21772
|
+
counts.long_cycle_time = 0;
|
|
21773
|
+
counts.missing_quality_check = 0;
|
|
21774
|
+
counts.cycle_completions = 0;
|
|
21775
|
+
samples.best_cycle_time = null;
|
|
21776
|
+
samples.worst_cycle_time = null;
|
|
21777
|
+
samples.bottleneck = null;
|
|
21778
|
+
samples.low_value = null;
|
|
21779
|
+
samples.long_cycle_time = null;
|
|
21780
|
+
samples.missing_quality_check = null;
|
|
21781
|
+
samples.cycle_completions = null;
|
|
21782
|
+
}
|
|
21732
21783
|
for (const uri of s3Uris) {
|
|
21733
|
-
const parsedInfo = parseS3Uri(uri);
|
|
21784
|
+
const parsedInfo = parseS3Uri(uri, sopCategories);
|
|
21734
21785
|
if (parsedInfo) {
|
|
21735
21786
|
const { type } = parsedInfo;
|
|
21736
21787
|
counts[type] = (counts[type] || 0) + 1;
|
|
@@ -21792,9 +21843,9 @@ var S3ClipsService = class {
|
|
|
21792
21843
|
}
|
|
21793
21844
|
return summary;
|
|
21794
21845
|
}
|
|
21795
|
-
const limitPerCategory = limit ? Math.min(Math.max(limit, 1),
|
|
21846
|
+
const limitPerCategory = limit ? Math.min(Math.max(limit, 1), this.maxLimitPerCategory) : this.defaultLimitPerCategory;
|
|
21796
21847
|
const shouldFetchAll = category === "missing_quality_check" || category === "low_value";
|
|
21797
|
-
const initialFetchLimit = shouldFetchAll ? void 0 : category ? limitPerCategory * 3 : void 0;
|
|
21848
|
+
const initialFetchLimit = shouldFetchAll ? void 0 : category ? Math.min(limitPerCategory * 3, this.maxInitialFetch) : void 0;
|
|
21798
21849
|
const s3Uris = await this.listS3Clips({ workspaceId, date, shiftId, maxKeys: initialFetchLimit });
|
|
21799
21850
|
if (s3Uris.length === 0) {
|
|
21800
21851
|
console.log(`S3ClipsService: No HLS playlists found for workspace ${workspaceId} on date ${date}, shift ${shiftId}`);
|
|
@@ -21862,12 +21913,11 @@ var S3ClipsService = class {
|
|
|
21862
21913
|
}
|
|
21863
21914
|
console.log(`S3ClipsService: Total filtered URIs across all categories: ${filteredUris.length}`);
|
|
21864
21915
|
}
|
|
21865
|
-
const concurrencyLimit = 10;
|
|
21866
21916
|
let processedCount = 0;
|
|
21867
21917
|
const videoResults = [];
|
|
21868
21918
|
console.log(`S3ClipsService: Processing ${filteredUris.length} URIs for ${category || "all categories"} with limit ${limitPerCategory} per category`);
|
|
21869
|
-
for (let i = 0; i < filteredUris.length; i += concurrencyLimit) {
|
|
21870
|
-
const batch = filteredUris.slice(i, i + concurrencyLimit);
|
|
21919
|
+
for (let i = 0; i < filteredUris.length; i += this.concurrencyLimit) {
|
|
21920
|
+
const batch = filteredUris.slice(i, i + this.concurrencyLimit);
|
|
21871
21921
|
const batchPromises = batch.map(async (uri, batchIndex) => {
|
|
21872
21922
|
const index = i + batchIndex;
|
|
21873
21923
|
const result = await this.processFullVideo(uri, index, workspaceId, date, shiftId, includeCycleTime || false, includeMetadata || (!!timestampStart || !!timestampEnd));
|
|
@@ -21943,6 +21993,14 @@ var BottlenecksContent = ({
|
|
|
21943
21993
|
className
|
|
21944
21994
|
}) => {
|
|
21945
21995
|
const dashboardConfig = useDashboardConfig();
|
|
21996
|
+
const sopCategories = React14__namespace.default.useMemo(() => {
|
|
21997
|
+
const sopConfig = dashboardConfig?.s3Config?.sopCategories;
|
|
21998
|
+
if (!sopConfig) return null;
|
|
21999
|
+
if (sopConfig.workspaceOverrides && sopConfig.workspaceOverrides[workspaceId]) {
|
|
22000
|
+
return sopConfig.workspaceOverrides[workspaceId];
|
|
22001
|
+
}
|
|
22002
|
+
return sopConfig.default;
|
|
22003
|
+
}, [dashboardConfig, workspaceId]);
|
|
21946
22004
|
const videoRef = React14.useRef(null);
|
|
21947
22005
|
const fullscreenContainerRef = React14.useRef(null);
|
|
21948
22006
|
const timestampFilterRef = React14.useRef(null);
|
|
@@ -21951,7 +22009,9 @@ var BottlenecksContent = ({
|
|
|
21951
22009
|
const [duration, setDuration] = React14.useState(0);
|
|
21952
22010
|
const [isFullscreen, setIsFullscreen] = React14.useState(false);
|
|
21953
22011
|
const [currentIndex, setCurrentIndex] = React14.useState(0);
|
|
21954
|
-
const [activeFilter, setActiveFilter] = React14.useState(
|
|
22012
|
+
const [activeFilter, setActiveFilter] = React14.useState(
|
|
22013
|
+
sopCategories && sopCategories.length > 0 ? sopCategories[0].id : "low_value"
|
|
22014
|
+
);
|
|
21955
22015
|
const [allVideos, setAllVideos] = React14.useState([]);
|
|
21956
22016
|
const [isLoading, setIsLoading] = React14.useState(true);
|
|
21957
22017
|
const [error, setError] = React14.useState(null);
|
|
@@ -22063,27 +22123,41 @@ var BottlenecksContent = ({
|
|
|
22063
22123
|
let filtered = [];
|
|
22064
22124
|
if (activeFilter === "all") {
|
|
22065
22125
|
filtered = [...allVideos];
|
|
22066
|
-
} else if (activeFilter === "low_value") {
|
|
22067
|
-
filtered = allVideos.filter((video) => video.type === "low_value");
|
|
22068
|
-
} else if (activeFilter === "sop_deviations") {
|
|
22069
|
-
filtered = allVideos.filter((video) => video.type === "missing_quality_check");
|
|
22070
|
-
} else if (activeFilter === "best_cycle_time") {
|
|
22071
|
-
filtered = allVideos.filter((video) => video.type === "best_cycle_time");
|
|
22072
|
-
} else if (activeFilter === "worst_cycle_time") {
|
|
22073
|
-
filtered = allVideos.filter((video) => video.type === "worst_cycle_time");
|
|
22074
|
-
} else if (activeFilter === "cycle_completions") {
|
|
22075
|
-
filtered = allVideos.filter((video) => video.type === "cycle_completions");
|
|
22076
|
-
} else if (activeFilter === "long_cycle_time") {
|
|
22077
|
-
filtered = allVideos.filter(
|
|
22078
|
-
(video) => video.type === "bottleneck" && video.description.toLowerCase().includes("cycle time")
|
|
22079
|
-
);
|
|
22080
22126
|
} else {
|
|
22081
|
-
|
|
22127
|
+
if (sopCategories && sopCategories.length > 0) {
|
|
22128
|
+
const selectedCategory = sopCategories.find((cat) => cat.id === activeFilter);
|
|
22129
|
+
if (selectedCategory) {
|
|
22130
|
+
filtered = allVideos.filter((video) => video.type === selectedCategory.id);
|
|
22131
|
+
if (selectedCategory.id === "long_cycle_time") {
|
|
22132
|
+
filtered = allVideos.filter(
|
|
22133
|
+
(video) => video.type === "bottleneck" && video.description.toLowerCase().includes("cycle time")
|
|
22134
|
+
);
|
|
22135
|
+
}
|
|
22136
|
+
}
|
|
22137
|
+
} else {
|
|
22138
|
+
if (activeFilter === "low_value") {
|
|
22139
|
+
filtered = allVideos.filter((video) => video.type === "low_value");
|
|
22140
|
+
} else if (activeFilter === "sop_deviations") {
|
|
22141
|
+
filtered = allVideos.filter((video) => video.type === "missing_quality_check");
|
|
22142
|
+
} else if (activeFilter === "best_cycle_time") {
|
|
22143
|
+
filtered = allVideos.filter((video) => video.type === "best_cycle_time");
|
|
22144
|
+
} else if (activeFilter === "worst_cycle_time") {
|
|
22145
|
+
filtered = allVideos.filter((video) => video.type === "worst_cycle_time");
|
|
22146
|
+
} else if (activeFilter === "cycle_completions") {
|
|
22147
|
+
filtered = allVideos.filter((video) => video.type === "cycle_completions");
|
|
22148
|
+
} else if (activeFilter === "long_cycle_time") {
|
|
22149
|
+
filtered = allVideos.filter(
|
|
22150
|
+
(video) => video.type === "bottleneck" && video.description.toLowerCase().includes("cycle time")
|
|
22151
|
+
);
|
|
22152
|
+
} else {
|
|
22153
|
+
filtered = allVideos.filter((video) => video.type === "bottleneck" && video.severity === activeFilter);
|
|
22154
|
+
}
|
|
22155
|
+
}
|
|
22082
22156
|
}
|
|
22083
22157
|
return filtered.sort((a, b) => {
|
|
22084
22158
|
return new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime();
|
|
22085
22159
|
});
|
|
22086
|
-
}, [activeFilter, allVideos]);
|
|
22160
|
+
}, [activeFilter, allVideos, sopCategories]);
|
|
22087
22161
|
React14.useEffect(() => {
|
|
22088
22162
|
if (filteredVideos.length === 0) return;
|
|
22089
22163
|
const upcoming = [];
|
|
@@ -22357,35 +22431,34 @@ var BottlenecksContent = ({
|
|
|
22357
22431
|
}
|
|
22358
22432
|
};
|
|
22359
22433
|
const clipCounts = React14.useMemo(() => {
|
|
22360
|
-
if (!allVideos) return {
|
|
22361
|
-
|
|
22362
|
-
|
|
22363
|
-
|
|
22364
|
-
|
|
22365
|
-
|
|
22366
|
-
|
|
22367
|
-
|
|
22368
|
-
|
|
22369
|
-
|
|
22370
|
-
|
|
22371
|
-
|
|
22372
|
-
}
|
|
22373
|
-
|
|
22374
|
-
|
|
22375
|
-
|
|
22376
|
-
|
|
22377
|
-
|
|
22378
|
-
|
|
22379
|
-
|
|
22380
|
-
|
|
22381
|
-
|
|
22382
|
-
longCycleTimes: allVideos.filter(
|
|
22434
|
+
if (!allVideos) return {};
|
|
22435
|
+
const counts = { total: allVideos.length };
|
|
22436
|
+
if (sopCategories && sopCategories.length > 0) {
|
|
22437
|
+
sopCategories.forEach((category) => {
|
|
22438
|
+
if (category.id === "long_cycle_time") {
|
|
22439
|
+
counts[category.id] = allVideos.filter(
|
|
22440
|
+
(video) => video.type === "bottleneck" && video.description.toLowerCase().includes("cycle time")
|
|
22441
|
+
).length;
|
|
22442
|
+
} else {
|
|
22443
|
+
counts[category.id] = allVideos.filter((video) => video.type === category.id).length;
|
|
22444
|
+
}
|
|
22445
|
+
});
|
|
22446
|
+
} else {
|
|
22447
|
+
counts.bottlenecks = allVideos.filter((video) => video.type === "bottleneck").length;
|
|
22448
|
+
counts.lowValue = allVideos.filter((video) => video.type === "low_value").length;
|
|
22449
|
+
counts.highSeverity = allVideos.filter((video) => video.severity === "high" && video.type === "bottleneck").length;
|
|
22450
|
+
counts.mediumSeverity = allVideos.filter((video) => video.severity === "medium" && video.type === "bottleneck").length;
|
|
22451
|
+
counts.lowSeverity = allVideos.filter((video) => video.severity === "low" && video.type === "bottleneck").length;
|
|
22452
|
+
counts.sopDeviations = allVideos.filter((video) => video.type === "missing_quality_check").length;
|
|
22453
|
+
counts.bestCycleTimes = allVideos.filter((video) => video.type === "best_cycle_time").length;
|
|
22454
|
+
counts.worstCycleTimes = allVideos.filter((video) => video.type === "worst_cycle_time").length;
|
|
22455
|
+
counts.longCycleTimes = allVideos.filter(
|
|
22383
22456
|
(video) => video.type === "bottleneck" && video.description.toLowerCase().includes("cycle time")
|
|
22384
|
-
).length
|
|
22385
|
-
cycleCompletions
|
|
22386
|
-
|
|
22387
|
-
|
|
22388
|
-
}, [allVideos]);
|
|
22457
|
+
).length;
|
|
22458
|
+
counts.cycleCompletions = allVideos.filter((video) => video.type === "cycle_completions").length;
|
|
22459
|
+
}
|
|
22460
|
+
return counts;
|
|
22461
|
+
}, [allVideos, sopCategories]);
|
|
22389
22462
|
const currentVideo = React14.useMemo(() => {
|
|
22390
22463
|
if (!filteredVideos || filteredVideos.length === 0 || currentIndex >= filteredVideos.length) {
|
|
22391
22464
|
return null;
|
|
@@ -22407,9 +22480,22 @@ var BottlenecksContent = ({
|
|
|
22407
22480
|
return "Cycle Completion";
|
|
22408
22481
|
case "bottleneck":
|
|
22409
22482
|
default:
|
|
22410
|
-
return "
|
|
22483
|
+
return "";
|
|
22411
22484
|
}
|
|
22412
22485
|
};
|
|
22486
|
+
const getColorClasses = (color2) => {
|
|
22487
|
+
const colorMap = {
|
|
22488
|
+
purple: { text: "text-purple-500", bg: "bg-purple-500", dot: "bg-purple-500" },
|
|
22489
|
+
green: { text: "text-green-600", bg: "bg-green-600", dot: "bg-green-600" },
|
|
22490
|
+
red: { text: "text-red-700", bg: "bg-red-700", dot: "bg-red-700" },
|
|
22491
|
+
"red-dark": { text: "text-red-500", bg: "bg-red-500", dot: "bg-red-500" },
|
|
22492
|
+
blue: { text: "text-blue-600", bg: "bg-blue-600", dot: "bg-blue-600" },
|
|
22493
|
+
orange: { text: "text-orange-600", bg: "bg-orange-600", dot: "bg-orange-600" },
|
|
22494
|
+
yellow: { text: "text-yellow-600", bg: "bg-yellow-600", dot: "bg-yellow-600" },
|
|
22495
|
+
gray: { text: "text-gray-600", bg: "bg-gray-600", dot: "bg-gray-600" }
|
|
22496
|
+
};
|
|
22497
|
+
return colorMap[color2] || colorMap.gray;
|
|
22498
|
+
};
|
|
22413
22499
|
const formatTimeOnly = (time2) => {
|
|
22414
22500
|
if (!time2) return "";
|
|
22415
22501
|
try {
|
|
@@ -22439,162 +22525,62 @@ var BottlenecksContent = ({
|
|
|
22439
22525
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-gray-600 max-w-md", children: error })
|
|
22440
22526
|
] });
|
|
22441
22527
|
}
|
|
22528
|
+
const categoriesToShow = sopCategories && sopCategories.length > 0 ? sopCategories : [
|
|
22529
|
+
// Default hardcoded categories if no configuration
|
|
22530
|
+
{ id: "low_value", label: "Idle Moments", color: "purple", subtitle: "Idle time detected" },
|
|
22531
|
+
{ id: "best_cycle_time", label: "Best Cycle Time", color: "green", subtitle: "Fastest cycle today" },
|
|
22532
|
+
{ id: "worst_cycle_time", label: "Worst Cycle Time", color: "red", subtitle: "Slowest cycle today" },
|
|
22533
|
+
{ id: "long_cycle_time", label: "Long Cycle Time", color: "red-dark", subtitle: "Above standard cycle times" },
|
|
22534
|
+
{ id: "cycle_completions", label: "Cycle Completions", color: "blue", subtitle: "Completed production cycles" }
|
|
22535
|
+
];
|
|
22442
22536
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-grow p-1.5 sm:p-2 lg:p-4 h-[calc(100vh-12rem)]", children: [
|
|
22443
|
-
/* @__PURE__ */ jsxRuntime.
|
|
22444
|
-
|
|
22445
|
-
|
|
22446
|
-
|
|
22447
|
-
onClick: () => {
|
|
22448
|
-
setActiveFilter("low_value");
|
|
22449
|
-
trackCoreEvent("Idle Moments Filter Clicked", {
|
|
22450
|
-
workspaceId,
|
|
22451
|
-
workspaceName,
|
|
22452
|
-
date,
|
|
22453
|
-
filterType: "low_value",
|
|
22454
|
-
clipCount: clipCounts.lowValue
|
|
22455
|
-
});
|
|
22456
|
-
},
|
|
22457
|
-
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" : ""}`,
|
|
22458
|
-
"aria-label": `Filter by Idle Moments (${clipCounts.lowValue} clips)`,
|
|
22459
|
-
role: "button",
|
|
22460
|
-
tabIndex: 0,
|
|
22461
|
-
onKeyDown: (e) => e.key === "Enter" && setActiveFilter("low_value"),
|
|
22462
|
-
children: [
|
|
22463
|
-
/* @__PURE__ */ jsxRuntime.jsx(CardHeader2, { className: "pb-2", children: /* @__PURE__ */ jsxRuntime.jsx(CardTitle2, { className: `text-lg ${activeFilter === "low_value" ? "text-blue-600" : ""}`, children: "Idle Moments" }) }),
|
|
22464
|
-
/* @__PURE__ */ jsxRuntime.jsx(CardContent2, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col justify-center", children: [
|
|
22465
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-3xl font-bold text-purple-500", children: clipCounts.lowValue }),
|
|
22466
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center text-sm text-gray-500 mt-1", children: [
|
|
22467
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 w-2 rounded-full bg-purple-500 mr-1.5" }),
|
|
22468
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Idle time detected" })
|
|
22469
|
-
] })
|
|
22470
|
-
] }) })
|
|
22471
|
-
]
|
|
22472
|
-
}
|
|
22473
|
-
),
|
|
22474
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
22475
|
-
Card2,
|
|
22476
|
-
{
|
|
22477
|
-
onClick: () => {
|
|
22478
|
-
setActiveFilter("best_cycle_time");
|
|
22479
|
-
trackCoreEvent("Best Cycle Time Filter Clicked", {
|
|
22480
|
-
workspaceId,
|
|
22481
|
-
workspaceName,
|
|
22482
|
-
date,
|
|
22483
|
-
filterType: "best_cycle_time",
|
|
22484
|
-
clipCount: clipCounts.bestCycleTimes
|
|
22485
|
-
});
|
|
22486
|
-
},
|
|
22487
|
-
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" : ""}`,
|
|
22488
|
-
"aria-label": `Filter by Best Cycle Time (${clipCounts.bestCycleTimes} clips)`,
|
|
22489
|
-
role: "button",
|
|
22490
|
-
tabIndex: 0,
|
|
22491
|
-
onKeyDown: (e) => e.key === "Enter" && setActiveFilter("best_cycle_time"),
|
|
22492
|
-
children: [
|
|
22493
|
-
/* @__PURE__ */ jsxRuntime.jsx(CardHeader2, { className: "pb-2", children: /* @__PURE__ */ jsxRuntime.jsx(CardTitle2, { className: `text-lg ${activeFilter === "best_cycle_time" ? "text-blue-600" : ""}`, children: "Best Cycle Time" }) }),
|
|
22494
|
-
/* @__PURE__ */ jsxRuntime.jsx(CardContent2, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col justify-center", children: [
|
|
22495
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-3xl font-bold text-green-600", children: clipCounts.bestCycleTimes }),
|
|
22496
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center text-sm text-gray-500 mt-1", children: [
|
|
22497
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 w-2 rounded-full bg-green-600 mr-1.5" }),
|
|
22498
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Fastest cycle today" })
|
|
22499
|
-
] })
|
|
22500
|
-
] }) })
|
|
22501
|
-
]
|
|
22502
|
-
}
|
|
22503
|
-
),
|
|
22504
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
22505
|
-
Card2,
|
|
22506
|
-
{
|
|
22507
|
-
onClick: () => {
|
|
22508
|
-
setActiveFilter("worst_cycle_time");
|
|
22509
|
-
trackCoreEvent("Worst Cycle Time Filter Clicked", {
|
|
22510
|
-
workspaceId,
|
|
22511
|
-
workspaceName,
|
|
22512
|
-
date,
|
|
22513
|
-
filterType: "worst_cycle_time",
|
|
22514
|
-
clipCount: clipCounts.worstCycleTimes
|
|
22515
|
-
});
|
|
22516
|
-
},
|
|
22517
|
-
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" : ""}`,
|
|
22518
|
-
"aria-label": `Filter by Worst Cycle Time (${clipCounts.worstCycleTimes} clips)`,
|
|
22519
|
-
role: "button",
|
|
22520
|
-
tabIndex: 0,
|
|
22521
|
-
onKeyDown: (e) => e.key === "Enter" && setActiveFilter("worst_cycle_time"),
|
|
22522
|
-
children: [
|
|
22523
|
-
/* @__PURE__ */ jsxRuntime.jsx(CardHeader2, { className: "pb-2", children: /* @__PURE__ */ jsxRuntime.jsx(CardTitle2, { className: `text-lg ${activeFilter === "worst_cycle_time" ? "text-blue-600" : ""}`, children: "Worst Cycle Time" }) }),
|
|
22524
|
-
/* @__PURE__ */ jsxRuntime.jsx(CardContent2, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col justify-center", children: [
|
|
22525
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-3xl font-bold text-red-700", children: clipCounts.worstCycleTimes }),
|
|
22526
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center text-sm text-gray-500 mt-1", children: [
|
|
22527
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 w-2 rounded-full bg-red-700 mr-1.5" }),
|
|
22528
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Slowest cycle today" })
|
|
22529
|
-
] })
|
|
22530
|
-
] }) })
|
|
22531
|
-
]
|
|
22532
|
-
}
|
|
22533
|
-
),
|
|
22534
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
22537
|
+
/* @__PURE__ */ jsxRuntime.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) => {
|
|
22538
|
+
const colorClasses = getColorClasses(category.color);
|
|
22539
|
+
const count = clipCounts[category.id] || 0;
|
|
22540
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
22535
22541
|
Card2,
|
|
22536
22542
|
{
|
|
22537
22543
|
onClick: () => {
|
|
22538
|
-
setActiveFilter(
|
|
22539
|
-
trackCoreEvent(
|
|
22544
|
+
setActiveFilter(category.id);
|
|
22545
|
+
trackCoreEvent(`${category.label} Filter Clicked`, {
|
|
22540
22546
|
workspaceId,
|
|
22541
22547
|
workspaceName,
|
|
22542
22548
|
date,
|
|
22543
|
-
filterType:
|
|
22544
|
-
clipCount:
|
|
22549
|
+
filterType: category.id,
|
|
22550
|
+
clipCount: count
|
|
22545
22551
|
});
|
|
22546
22552
|
},
|
|
22547
|
-
className: `bg-white shadow-sm cursor-pointer transition-all duration-200 hover:bg-gray-50 ${activeFilter ===
|
|
22548
|
-
"aria-label": `Filter by
|
|
22553
|
+
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" : ""}`,
|
|
22554
|
+
"aria-label": `Filter by ${category.label} (${count} clips)`,
|
|
22549
22555
|
role: "button",
|
|
22550
22556
|
tabIndex: 0,
|
|
22551
|
-
onKeyDown: (e) => e.key === "Enter" && setActiveFilter(
|
|
22557
|
+
onKeyDown: (e) => e.key === "Enter" && setActiveFilter(category.id),
|
|
22552
22558
|
children: [
|
|
22553
|
-
/* @__PURE__ */ jsxRuntime.jsx(CardHeader2, { className: "pb-2", children: /* @__PURE__ */ jsxRuntime.jsx(CardTitle2, { className: `text-lg ${activeFilter ===
|
|
22559
|
+
/* @__PURE__ */ jsxRuntime.jsx(CardHeader2, { className: "pb-2", children: /* @__PURE__ */ jsxRuntime.jsx(CardTitle2, { className: `text-lg ${activeFilter === category.id ? "text-blue-600" : ""}`, children: category.label }) }),
|
|
22554
22560
|
/* @__PURE__ */ jsxRuntime.jsx(CardContent2, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col justify-center", children: [
|
|
22555
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className:
|
|
22561
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: `text-3xl font-bold ${colorClasses.text}`, children: count }),
|
|
22556
22562
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center text-sm text-gray-500 mt-1", children: [
|
|
22557
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className:
|
|
22558
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children:
|
|
22563
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `h-2 w-2 rounded-full ${colorClasses.dot} mr-1.5` }),
|
|
22564
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: category.subtitle || category.description || category.label })
|
|
22559
22565
|
] })
|
|
22560
22566
|
] }) })
|
|
22561
22567
|
]
|
|
22562
|
-
}
|
|
22563
|
-
|
|
22564
|
-
|
|
22565
|
-
|
|
22566
|
-
{
|
|
22567
|
-
onClick: () => {
|
|
22568
|
-
setActiveFilter("cycle_completions");
|
|
22569
|
-
trackCoreEvent("Cycle Completions Filter Clicked", {
|
|
22570
|
-
workspaceId,
|
|
22571
|
-
workspaceName,
|
|
22572
|
-
date,
|
|
22573
|
-
filterType: "cycle_completions",
|
|
22574
|
-
clipCount: clipCounts.cycleCompletions
|
|
22575
|
-
});
|
|
22576
|
-
},
|
|
22577
|
-
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" : ""}`,
|
|
22578
|
-
"aria-label": `Filter by Cycle Completions (${clipCounts.cycleCompletions} clips)`,
|
|
22579
|
-
role: "button",
|
|
22580
|
-
tabIndex: 0,
|
|
22581
|
-
onKeyDown: (e) => e.key === "Enter" && setActiveFilter("cycle_completions"),
|
|
22582
|
-
children: [
|
|
22583
|
-
/* @__PURE__ */ jsxRuntime.jsx(CardHeader2, { className: "pb-2", children: /* @__PURE__ */ jsxRuntime.jsx(CardTitle2, { className: `text-lg ${activeFilter === "cycle_completions" ? "text-blue-600" : ""}`, children: "Cycle Completions" }) }),
|
|
22584
|
-
/* @__PURE__ */ jsxRuntime.jsx(CardContent2, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col justify-center", children: [
|
|
22585
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-3xl font-bold text-blue-600", children: clipCounts.cycleCompletions }),
|
|
22586
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center text-sm text-gray-500 mt-1", children: [
|
|
22587
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 w-2 rounded-full bg-blue-600 mr-1.5" }),
|
|
22588
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Completed production cycles" })
|
|
22589
|
-
] })
|
|
22590
|
-
] }) })
|
|
22591
|
-
]
|
|
22592
|
-
}
|
|
22593
|
-
)
|
|
22594
|
-
] }),
|
|
22568
|
+
},
|
|
22569
|
+
category.id
|
|
22570
|
+
);
|
|
22571
|
+
}) }),
|
|
22595
22572
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-lg shadow-sm overflow-hidden", style: { height: "calc(100% - 8.5rem)" }, children: [
|
|
22596
22573
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 py-3 border-b border-gray-100", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between items-center", children: [
|
|
22597
|
-
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold text-gray-800", children:
|
|
22574
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold text-gray-800", children: (() => {
|
|
22575
|
+
if (activeFilter === "all") {
|
|
22576
|
+
return `All Clips (${clipCounts.total || 0})`;
|
|
22577
|
+
}
|
|
22578
|
+
const activeCategory = categoriesToShow.find((cat) => cat.id === activeFilter);
|
|
22579
|
+
if (activeCategory) {
|
|
22580
|
+
return `${activeCategory.label} (${clipCounts[activeCategory.id] || 0})`;
|
|
22581
|
+
}
|
|
22582
|
+
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})`;
|
|
22583
|
+
})() }),
|
|
22598
22584
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center space-x-2", children: [
|
|
22599
22585
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", ref: timestampFilterRef, children: [
|
|
22600
22586
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -24970,14 +24956,6 @@ var AIAgentView = () => {
|
|
|
24970
24956
|
return newMap;
|
|
24971
24957
|
});
|
|
24972
24958
|
},
|
|
24973
|
-
onReasoning: (text) => {
|
|
24974
|
-
setStreamingStates((prev) => {
|
|
24975
|
-
const newMap = new Map(prev);
|
|
24976
|
-
const current = newMap.get(currentThreadId) || { message: "", reasoning: "" };
|
|
24977
|
-
newMap.set(currentThreadId, { ...current, reasoning: current.reasoning + text });
|
|
24978
|
-
return newMap;
|
|
24979
|
-
});
|
|
24980
|
-
},
|
|
24981
24959
|
onComplete: async (messageId) => {
|
|
24982
24960
|
if (currentThreadId && !currentThreadId.startsWith("temp-")) {
|
|
24983
24961
|
const updatedMessages = await getAllThreadMessages(currentThreadId);
|
|
@@ -27366,14 +27344,20 @@ function HomeView({
|
|
|
27366
27344
|
}) {
|
|
27367
27345
|
const [isHydrated, setIsHydrated] = React14.useState(false);
|
|
27368
27346
|
const availableLineIds = React14.useMemo(() => [factoryViewId, ...allLineIds], [factoryViewId, allLineIds]);
|
|
27369
|
-
const [selectedLineId, setSelectedLineId] = React14.useState(
|
|
27347
|
+
const [selectedLineId, setSelectedLineId] = React14.useState(factoryViewId);
|
|
27370
27348
|
const [isChangingFilter, setIsChangingFilter] = React14.useState(false);
|
|
27371
27349
|
const [errorMessage, setErrorMessage] = React14.useState(null);
|
|
27372
27350
|
const [displayNamesInitialized, setDisplayNamesInitialized] = React14.useState(false);
|
|
27373
27351
|
React14.useEffect(() => {
|
|
27374
27352
|
const initDisplayNames = async () => {
|
|
27375
27353
|
try {
|
|
27376
|
-
|
|
27354
|
+
if (selectedLineId === factoryViewId) {
|
|
27355
|
+
for (const lineId of allLineIds) {
|
|
27356
|
+
await preInitializeWorkspaceDisplayNames(lineId);
|
|
27357
|
+
}
|
|
27358
|
+
} else {
|
|
27359
|
+
await preInitializeWorkspaceDisplayNames(selectedLineId);
|
|
27360
|
+
}
|
|
27377
27361
|
setDisplayNamesInitialized(true);
|
|
27378
27362
|
} catch (error) {
|
|
27379
27363
|
console.error("Failed to pre-initialize workspace display names:", error);
|
|
@@ -27381,7 +27365,7 @@ function HomeView({
|
|
|
27381
27365
|
}
|
|
27382
27366
|
};
|
|
27383
27367
|
initDisplayNames();
|
|
27384
|
-
}, [selectedLineId]);
|
|
27368
|
+
}, [selectedLineId, factoryViewId, allLineIds]);
|
|
27385
27369
|
const {
|
|
27386
27370
|
displayNames: workspaceDisplayNames,
|
|
27387
27371
|
loading: displayNamesLoading,
|
|
@@ -27414,11 +27398,17 @@ function HomeView({
|
|
|
27414
27398
|
lineId: selectedLineId,
|
|
27415
27399
|
onLineMetricsUpdate
|
|
27416
27400
|
});
|
|
27401
|
+
const lineIdsForBreaks = React14.useMemo(() => {
|
|
27402
|
+
if (selectedLineId === factoryViewId) {
|
|
27403
|
+
return allLineIds;
|
|
27404
|
+
}
|
|
27405
|
+
return [selectedLineId];
|
|
27406
|
+
}, [selectedLineId, factoryViewId, allLineIds]);
|
|
27417
27407
|
const {
|
|
27418
27408
|
activeBreaks,
|
|
27419
27409
|
isLoading: breaksLoading,
|
|
27420
27410
|
error: breaksError
|
|
27421
|
-
} = useActiveBreaks(
|
|
27411
|
+
} = useActiveBreaks(lineIdsForBreaks);
|
|
27422
27412
|
const memoizedWorkspaceMetrics = React14.useMemo(() => workspaceMetrics, [
|
|
27423
27413
|
// Only update reference if meaningful properties change
|
|
27424
27414
|
workspaceMetrics.length,
|
|
@@ -27461,10 +27451,15 @@ function HomeView({
|
|
|
27461
27451
|
const lineTitle = React14.useMemo(() => {
|
|
27462
27452
|
return factoryName;
|
|
27463
27453
|
}, [factoryName]);
|
|
27464
|
-
const lineSelectorComponent = React14.useMemo(() =>
|
|
27465
|
-
|
|
27466
|
-
|
|
27467
|
-
|
|
27454
|
+
const lineSelectorComponent = React14.useMemo(() => {
|
|
27455
|
+
if (allLineIds.length <= 1) {
|
|
27456
|
+
return null;
|
|
27457
|
+
}
|
|
27458
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Select, { onValueChange: handleLineChange, defaultValue: selectedLineId, children: [
|
|
27459
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { className: "w-full sm:w-[200px] bg-white border border-gray-200 shadow-sm rounded-md h-9 text-sm", children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder: "Select a line" }) }),
|
|
27460
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectContent, { className: "z-50 bg-white shadow-lg border border-gray-200 rounded-md", children: availableLineIds.map((id3) => /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: id3, children: lineNames[id3] || (id3 === factoryViewId ? "All Lines" : `Line ${id3.substring(0, 4)}`) }, id3)) })
|
|
27461
|
+
] });
|
|
27462
|
+
}, [availableLineIds, handleLineChange, selectedLineId, lineNames, factoryViewId, allLineIds.length]);
|
|
27468
27463
|
const isLoading = !isHydrated || metricsLoading || kpisLoading || isChangingFilter || displayNamesLoading || !displayNamesInitialized;
|
|
27469
27464
|
if (isLoading) {
|
|
27470
27465
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-screen bg-slate-50", children: /* @__PURE__ */ jsxRuntime.jsx(LoadingPageCmp, { message: "Loading dashboard..." }) });
|
|
@@ -27500,7 +27495,7 @@ function HomeView({
|
|
|
27500
27495
|
}
|
|
27501
27496
|
) }) }),
|
|
27502
27497
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 overflow-y-auto sm:overflow-hidden relative", children: [
|
|
27503
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute right-3 top-2 sm:right-6 sm:top-3 z-30", children: lineSelectorComponent }),
|
|
27498
|
+
lineSelectorComponent && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute right-3 top-2 sm:right-6 sm:top-3 z-30", children: lineSelectorComponent }),
|
|
27504
27499
|
memoizedWorkspaceMetrics.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full sm:h-full min-h-[calc(100vh-80px)] sm:min-h-0", children: React14__namespace.default.createElement(WorkspaceGrid, {
|
|
27505
27500
|
workspaces: memoizedWorkspaceMetrics,
|
|
27506
27501
|
lineNames,
|
|
@@ -28680,8 +28675,7 @@ var MobileWorkspaceCard = React14.memo(({
|
|
|
28680
28675
|
cardClass,
|
|
28681
28676
|
onWorkspaceClick,
|
|
28682
28677
|
getMedalIcon,
|
|
28683
|
-
|
|
28684
|
-
line2Id
|
|
28678
|
+
getLineName
|
|
28685
28679
|
}) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
28686
28680
|
"div",
|
|
28687
28681
|
{
|
|
@@ -28699,7 +28693,7 @@ var MobileWorkspaceCard = React14.memo(({
|
|
|
28699
28693
|
] }),
|
|
28700
28694
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
28701
28695
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-semibold text-gray-900", children: getWorkspaceDisplayName(workspace.workspace_name) }),
|
|
28702
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-gray-500", children: workspace.line_id
|
|
28696
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-gray-500", children: getLineName(workspace.line_id) })
|
|
28703
28697
|
] })
|
|
28704
28698
|
] }),
|
|
28705
28699
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-right", children: [
|
|
@@ -28737,8 +28731,7 @@ var DesktopWorkspaceRow = React14.memo(({
|
|
|
28737
28731
|
rowClass,
|
|
28738
28732
|
onWorkspaceClick,
|
|
28739
28733
|
getMedalIcon,
|
|
28740
|
-
|
|
28741
|
-
line2Id
|
|
28734
|
+
getLineName
|
|
28742
28735
|
}) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
28743
28736
|
"tr",
|
|
28744
28737
|
{
|
|
@@ -28750,7 +28743,7 @@ var DesktopWorkspaceRow = React14.memo(({
|
|
|
28750
28743
|
getMedalIcon(index + 1)
|
|
28751
28744
|
] }) }),
|
|
28752
28745
|
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-3 py-2.5 sm:p-4 text-sm sm:text-base whitespace-nowrap", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium", children: getWorkspaceDisplayName(workspace.workspace_name) }) }),
|
|
28753
|
-
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-3 py-2.5 sm:p-4 text-sm sm:text-base whitespace-nowrap", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium", children: workspace.line_id
|
|
28746
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-3 py-2.5 sm:p-4 text-sm sm:text-base whitespace-nowrap", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium", children: getLineName(workspace.line_id) }) }),
|
|
28754
28747
|
/* @__PURE__ */ jsxRuntime.jsxs("td", { className: "px-3 py-2.5 sm:p-4 text-sm sm:text-base font-medium whitespace-nowrap", children: [
|
|
28755
28748
|
(workspace.efficiency || 0).toFixed(1),
|
|
28756
28749
|
"%"
|
|
@@ -28778,10 +28771,19 @@ var LeaderboardDetailView = React14.memo(({
|
|
|
28778
28771
|
onWorkspaceClick,
|
|
28779
28772
|
line1Id = "",
|
|
28780
28773
|
line2Id = "",
|
|
28774
|
+
lineNames = {},
|
|
28781
28775
|
className = ""
|
|
28782
28776
|
}) => {
|
|
28783
28777
|
const navigation = useNavigation();
|
|
28784
28778
|
const [sortAscending, setSortAscending] = React14.useState(false);
|
|
28779
|
+
const getLineName = React14.useCallback((lineId2) => {
|
|
28780
|
+
if (lineNames[lineId2]) {
|
|
28781
|
+
return lineNames[lineId2];
|
|
28782
|
+
}
|
|
28783
|
+
if (lineId2 === line1Id) return "Line 1";
|
|
28784
|
+
if (lineId2 === line2Id) return "Line 2";
|
|
28785
|
+
return lineId2;
|
|
28786
|
+
}, [lineNames, line1Id, line2Id]);
|
|
28785
28787
|
const handleSortToggle = React14.useCallback(() => {
|
|
28786
28788
|
setSortAscending(!sortAscending);
|
|
28787
28789
|
}, [sortAscending]);
|
|
@@ -28955,8 +28957,7 @@ var LeaderboardDetailView = React14.memo(({
|
|
|
28955
28957
|
cardClass,
|
|
28956
28958
|
onWorkspaceClick: handleWorkspaceClick,
|
|
28957
28959
|
getMedalIcon,
|
|
28958
|
-
|
|
28959
|
-
line2Id
|
|
28960
|
+
getLineName
|
|
28960
28961
|
},
|
|
28961
28962
|
ws.workspace_uuid
|
|
28962
28963
|
);
|
|
@@ -28981,8 +28982,7 @@ var LeaderboardDetailView = React14.memo(({
|
|
|
28981
28982
|
rowClass,
|
|
28982
28983
|
onWorkspaceClick: handleWorkspaceClick,
|
|
28983
28984
|
getMedalIcon,
|
|
28984
|
-
|
|
28985
|
-
line2Id
|
|
28985
|
+
getLineName
|
|
28986
28986
|
},
|
|
28987
28987
|
ws.workspace_uuid
|
|
28988
28988
|
);
|
|
@@ -28991,7 +28991,7 @@ var LeaderboardDetailView = React14.memo(({
|
|
|
28991
28991
|
] })
|
|
28992
28992
|
] });
|
|
28993
28993
|
}, (prevProps, nextProps) => {
|
|
28994
|
-
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;
|
|
28994
|
+
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;
|
|
28995
28995
|
});
|
|
28996
28996
|
LeaderboardDetailView.displayName = "LeaderboardDetailView";
|
|
28997
28997
|
var LeaderboardDetailView_default = LeaderboardDetailView;
|