@optifye/dashboard-core 6.0.1 → 6.0.3
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 +26 -2
- package/dist/index.d.ts +26 -2
- package/dist/index.js +79 -68
- package/dist/index.mjs +79 -68
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -201,7 +201,10 @@ interface ShiftConfig {
|
|
|
201
201
|
transitionPeriodMinutes?: number;
|
|
202
202
|
}
|
|
203
203
|
interface WorkspaceConfig {
|
|
204
|
+
/** @deprecated Use lineDisplayNames for multi-line support */
|
|
204
205
|
displayNames?: Record<string, string>;
|
|
206
|
+
/** Line-aware display names: lineId -> workspaceId -> displayName */
|
|
207
|
+
lineDisplayNames?: Record<string, Record<string, string>>;
|
|
205
208
|
specialWorkspaces?: {
|
|
206
209
|
startId?: number;
|
|
207
210
|
endId?: number;
|
|
@@ -254,6 +257,17 @@ interface S3Config {
|
|
|
254
257
|
/** Workspace-specific category overrides by UUID */
|
|
255
258
|
workspaceOverrides?: Record<string, SOPCategory[]>;
|
|
256
259
|
};
|
|
260
|
+
/** Processing configuration for S3 clips */
|
|
261
|
+
processing?: {
|
|
262
|
+
/** Default limit per category when fetching clips (default: 30) */
|
|
263
|
+
defaultLimitPerCategory?: number;
|
|
264
|
+
/** Maximum allowed limit per category (default: 1000) */
|
|
265
|
+
maxLimitPerCategory?: number;
|
|
266
|
+
/** Number of concurrent video processing operations (default: 10) */
|
|
267
|
+
concurrencyLimit?: number;
|
|
268
|
+
/** Maximum initial fetch limit for S3 listing (default: 60) */
|
|
269
|
+
maxInitialFetch?: number;
|
|
270
|
+
};
|
|
257
271
|
}
|
|
258
272
|
interface VideoCroppingRect {
|
|
259
273
|
/** X offset as percentage (0-100) from left */
|
|
@@ -275,7 +289,10 @@ interface VideoConfig {
|
|
|
275
289
|
/** HLS stream URLs for workspaces */
|
|
276
290
|
hlsUrls?: {
|
|
277
291
|
defaultHlsUrl?: string;
|
|
292
|
+
/** @deprecated Use lineWorkspaceHlsUrls for multi-line support */
|
|
278
293
|
workspaceHlsUrls?: Record<string, string>;
|
|
294
|
+
/** Line-aware workspace HLS URLs: lineId -> workspaceName -> URL */
|
|
295
|
+
lineWorkspaceHlsUrls?: Record<string, Record<string, string>>;
|
|
279
296
|
};
|
|
280
297
|
/** Video cropping configuration */
|
|
281
298
|
cropping?: VideoCroppingConfig;
|
|
@@ -830,6 +847,10 @@ interface LeaderboardDetailViewProps {
|
|
|
830
847
|
* Second line ID reference (Line 2)
|
|
831
848
|
*/
|
|
832
849
|
line2Id?: string;
|
|
850
|
+
/**
|
|
851
|
+
* Mapping of line IDs to their display names
|
|
852
|
+
*/
|
|
853
|
+
lineNames?: Record<string, string>;
|
|
833
854
|
/**
|
|
834
855
|
* Optional className for custom styling
|
|
835
856
|
*/
|
|
@@ -2603,18 +2624,20 @@ locale?: string) => string;
|
|
|
2603
2624
|
*
|
|
2604
2625
|
* @param workspaceId - The workspace ID (e.g., 'WS01').
|
|
2605
2626
|
* @param workspaceConfig - The WorkspaceConfig object from the dashboard configuration.
|
|
2627
|
+
* @param lineId - Optional line ID for line-aware display names.
|
|
2606
2628
|
* @returns The display name from the config, or a fallback based on the ID.
|
|
2607
2629
|
*/
|
|
2608
|
-
declare const getConfigurableWorkspaceDisplayName: (workspaceId: string, workspaceConfig?: WorkspaceConfig) => string;
|
|
2630
|
+
declare const getConfigurableWorkspaceDisplayName: (workspaceId: string, workspaceConfig?: WorkspaceConfig, lineId?: string) => string;
|
|
2609
2631
|
/**
|
|
2610
2632
|
* Gets a potentially shortened or specific part of the workspace display name.
|
|
2611
2633
|
* (The logic here might need adjustment based on actual naming conventions used).
|
|
2612
2634
|
*
|
|
2613
2635
|
* @param workspaceId - The workspace ID (e.g., 'WS01').
|
|
2614
2636
|
* @param workspaceConfig - The WorkspaceConfig object from the dashboard configuration.
|
|
2637
|
+
* @param lineId - Optional line ID for line-aware display names.
|
|
2615
2638
|
* @returns A potentially shortened name, or the full display name, or a fallback.
|
|
2616
2639
|
*/
|
|
2617
|
-
declare const getConfigurableShortWorkspaceDisplayName: (workspaceId: string, workspaceConfig?: WorkspaceConfig) => string;
|
|
2640
|
+
declare const getConfigurableShortWorkspaceDisplayName: (workspaceId: string, workspaceConfig?: WorkspaceConfig, lineId?: string) => string;
|
|
2618
2641
|
|
|
2619
2642
|
/**
|
|
2620
2643
|
* @internal
|
|
@@ -2642,6 +2665,7 @@ interface WorkspaceUrlMapping {
|
|
|
2642
2665
|
urlName: string;
|
|
2643
2666
|
workspaceId: string;
|
|
2644
2667
|
workspaceName: string;
|
|
2668
|
+
lineId?: string;
|
|
2645
2669
|
}
|
|
2646
2670
|
declare const toUrlFriendlyName: (workspaceName: string | undefined) => string;
|
|
2647
2671
|
declare const fromUrlFriendlyName: (urlName: string) => string;
|
package/dist/index.d.ts
CHANGED
|
@@ -201,7 +201,10 @@ interface ShiftConfig {
|
|
|
201
201
|
transitionPeriodMinutes?: number;
|
|
202
202
|
}
|
|
203
203
|
interface WorkspaceConfig {
|
|
204
|
+
/** @deprecated Use lineDisplayNames for multi-line support */
|
|
204
205
|
displayNames?: Record<string, string>;
|
|
206
|
+
/** Line-aware display names: lineId -> workspaceId -> displayName */
|
|
207
|
+
lineDisplayNames?: Record<string, Record<string, string>>;
|
|
205
208
|
specialWorkspaces?: {
|
|
206
209
|
startId?: number;
|
|
207
210
|
endId?: number;
|
|
@@ -254,6 +257,17 @@ interface S3Config {
|
|
|
254
257
|
/** Workspace-specific category overrides by UUID */
|
|
255
258
|
workspaceOverrides?: Record<string, SOPCategory[]>;
|
|
256
259
|
};
|
|
260
|
+
/** Processing configuration for S3 clips */
|
|
261
|
+
processing?: {
|
|
262
|
+
/** Default limit per category when fetching clips (default: 30) */
|
|
263
|
+
defaultLimitPerCategory?: number;
|
|
264
|
+
/** Maximum allowed limit per category (default: 1000) */
|
|
265
|
+
maxLimitPerCategory?: number;
|
|
266
|
+
/** Number of concurrent video processing operations (default: 10) */
|
|
267
|
+
concurrencyLimit?: number;
|
|
268
|
+
/** Maximum initial fetch limit for S3 listing (default: 60) */
|
|
269
|
+
maxInitialFetch?: number;
|
|
270
|
+
};
|
|
257
271
|
}
|
|
258
272
|
interface VideoCroppingRect {
|
|
259
273
|
/** X offset as percentage (0-100) from left */
|
|
@@ -275,7 +289,10 @@ interface VideoConfig {
|
|
|
275
289
|
/** HLS stream URLs for workspaces */
|
|
276
290
|
hlsUrls?: {
|
|
277
291
|
defaultHlsUrl?: string;
|
|
292
|
+
/** @deprecated Use lineWorkspaceHlsUrls for multi-line support */
|
|
278
293
|
workspaceHlsUrls?: Record<string, string>;
|
|
294
|
+
/** Line-aware workspace HLS URLs: lineId -> workspaceName -> URL */
|
|
295
|
+
lineWorkspaceHlsUrls?: Record<string, Record<string, string>>;
|
|
279
296
|
};
|
|
280
297
|
/** Video cropping configuration */
|
|
281
298
|
cropping?: VideoCroppingConfig;
|
|
@@ -830,6 +847,10 @@ interface LeaderboardDetailViewProps {
|
|
|
830
847
|
* Second line ID reference (Line 2)
|
|
831
848
|
*/
|
|
832
849
|
line2Id?: string;
|
|
850
|
+
/**
|
|
851
|
+
* Mapping of line IDs to their display names
|
|
852
|
+
*/
|
|
853
|
+
lineNames?: Record<string, string>;
|
|
833
854
|
/**
|
|
834
855
|
* Optional className for custom styling
|
|
835
856
|
*/
|
|
@@ -2603,18 +2624,20 @@ locale?: string) => string;
|
|
|
2603
2624
|
*
|
|
2604
2625
|
* @param workspaceId - The workspace ID (e.g., 'WS01').
|
|
2605
2626
|
* @param workspaceConfig - The WorkspaceConfig object from the dashboard configuration.
|
|
2627
|
+
* @param lineId - Optional line ID for line-aware display names.
|
|
2606
2628
|
* @returns The display name from the config, or a fallback based on the ID.
|
|
2607
2629
|
*/
|
|
2608
|
-
declare const getConfigurableWorkspaceDisplayName: (workspaceId: string, workspaceConfig?: WorkspaceConfig) => string;
|
|
2630
|
+
declare const getConfigurableWorkspaceDisplayName: (workspaceId: string, workspaceConfig?: WorkspaceConfig, lineId?: string) => string;
|
|
2609
2631
|
/**
|
|
2610
2632
|
* Gets a potentially shortened or specific part of the workspace display name.
|
|
2611
2633
|
* (The logic here might need adjustment based on actual naming conventions used).
|
|
2612
2634
|
*
|
|
2613
2635
|
* @param workspaceId - The workspace ID (e.g., 'WS01').
|
|
2614
2636
|
* @param workspaceConfig - The WorkspaceConfig object from the dashboard configuration.
|
|
2637
|
+
* @param lineId - Optional line ID for line-aware display names.
|
|
2615
2638
|
* @returns A potentially shortened name, or the full display name, or a fallback.
|
|
2616
2639
|
*/
|
|
2617
|
-
declare const getConfigurableShortWorkspaceDisplayName: (workspaceId: string, workspaceConfig?: WorkspaceConfig) => string;
|
|
2640
|
+
declare const getConfigurableShortWorkspaceDisplayName: (workspaceId: string, workspaceConfig?: WorkspaceConfig, lineId?: string) => string;
|
|
2618
2641
|
|
|
2619
2642
|
/**
|
|
2620
2643
|
* @internal
|
|
@@ -2642,6 +2665,7 @@ interface WorkspaceUrlMapping {
|
|
|
2642
2665
|
urlName: string;
|
|
2643
2666
|
workspaceId: string;
|
|
2644
2667
|
workspaceName: string;
|
|
2668
|
+
lineId?: string;
|
|
2645
2669
|
}
|
|
2646
2670
|
declare const toUrlFriendlyName: (workspaceName: string | undefined) => string;
|
|
2647
2671
|
declare const fromUrlFriendlyName: (urlName: string) => string;
|
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
|
|
@@ -890,17 +893,18 @@ var dashboardService = {
|
|
|
890
893
|
const queryShiftId = shiftProp !== void 0 ? shiftProp : currentShiftResult.shiftId;
|
|
891
894
|
try {
|
|
892
895
|
if (lineIdToQuery === factoryViewId) {
|
|
893
|
-
if (!defaultLineId || !
|
|
894
|
-
throw new Error("Factory View requires defaultLineId
|
|
896
|
+
if (!defaultLineId || !companyId) {
|
|
897
|
+
throw new Error("Factory View requires at least defaultLineId and companyId to be configured.");
|
|
895
898
|
}
|
|
896
899
|
const { data: line1Data, error: line1Error } = await supabase.from(linesTable).select("id, line_name, factory_id, factories!lines_factory_id_fkey(factory_name), company_id, companies!lines_company_id_fkey(company_name:name)").eq("id", defaultLineId).single();
|
|
897
900
|
if (line1Error) throw line1Error;
|
|
898
901
|
if (!line1Data) {
|
|
899
902
|
throw new Error(`Default line ${defaultLineId} for Factory View not found.`);
|
|
900
903
|
}
|
|
901
|
-
const
|
|
904
|
+
const lineIdsToQuery = [defaultLineId, secondaryLineId].filter((id3) => id3 !== void 0 && id3 !== null);
|
|
905
|
+
const { data: metricsData, error: metricsError2 } = await supabase.from(lineMetricsTable).select("*").in("line_id", lineIdsToQuery).eq("shift_id", queryShiftId).eq("date", queryDate);
|
|
902
906
|
if (metricsError2) throw metricsError2;
|
|
903
|
-
const { data: performanceData2, error: performanceError2 } = await supabase.from(metricsTable).select("efficiency").in("line_id",
|
|
907
|
+
const { data: performanceData2, error: performanceError2 } = await supabase.from(metricsTable).select("efficiency").in("line_id", lineIdsToQuery).eq("shift_id", queryShiftId).eq("date", queryDate);
|
|
904
908
|
if (performanceError2) throw performanceError2;
|
|
905
909
|
const underperformingCount2 = performanceData2?.filter((w) => w.efficiency >= 10 && w.efficiency < 70).length || 0;
|
|
906
910
|
const totalValidWorkspaces2 = performanceData2?.filter((w) => w.efficiency >= 10).length || 0;
|
|
@@ -5125,19 +5129,23 @@ var useActiveBreaks = (lineIds) => {
|
|
|
5125
5129
|
const checkActiveBreaks = React14.useCallback(async () => {
|
|
5126
5130
|
try {
|
|
5127
5131
|
setError(null);
|
|
5128
|
-
|
|
5132
|
+
const validLineIds = lineIds.filter(
|
|
5133
|
+
(id3) => id3 && id3 !== "factory" && id3 !== "all" && // Basic UUID format check
|
|
5134
|
+
id3.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i)
|
|
5135
|
+
);
|
|
5136
|
+
if (!validLineIds || validLineIds.length === 0) {
|
|
5129
5137
|
setActiveBreaks([]);
|
|
5130
5138
|
setIsLoading(false);
|
|
5131
5139
|
return;
|
|
5132
5140
|
}
|
|
5133
5141
|
const currentMinutes = getCurrentTimeInMinutes();
|
|
5134
|
-
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",
|
|
5135
|
-
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",
|
|
5142
|
+
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);
|
|
5143
|
+
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);
|
|
5136
5144
|
if (dayError || nightError) {
|
|
5137
5145
|
throw new Error("Failed to fetch shift configurations");
|
|
5138
5146
|
}
|
|
5139
5147
|
const foundActiveBreaks = [];
|
|
5140
|
-
for (const lineId of
|
|
5148
|
+
for (const lineId of validLineIds) {
|
|
5141
5149
|
const dayShift = dayShifts?.find((s) => s.line_id === lineId);
|
|
5142
5150
|
const nightShift = nightShifts?.find((s) => s.line_id === lineId);
|
|
5143
5151
|
if (!dayShift || !nightShift) continue;
|
|
@@ -5621,12 +5629,18 @@ var FALLBACK_DISPLAY_NAMES = {
|
|
|
5621
5629
|
"WS03": "Filling station"
|
|
5622
5630
|
// ... Add others if known defaults are useful
|
|
5623
5631
|
};
|
|
5624
|
-
var getConfigurableWorkspaceDisplayName = (workspaceId, workspaceConfig) => {
|
|
5632
|
+
var getConfigurableWorkspaceDisplayName = (workspaceId, workspaceConfig, lineId) => {
|
|
5633
|
+
if (lineId && workspaceConfig?.lineDisplayNames?.[lineId]) {
|
|
5634
|
+
const lineDisplayNames = workspaceConfig.lineDisplayNames[lineId];
|
|
5635
|
+
if (lineDisplayNames[workspaceId]) {
|
|
5636
|
+
return lineDisplayNames[workspaceId];
|
|
5637
|
+
}
|
|
5638
|
+
}
|
|
5625
5639
|
const displayNames = workspaceConfig?.displayNames || FALLBACK_DISPLAY_NAMES;
|
|
5626
5640
|
return displayNames[workspaceId] || workspaceId.replace(/^WS/i, "") || workspaceId;
|
|
5627
5641
|
};
|
|
5628
|
-
var getConfigurableShortWorkspaceDisplayName = (workspaceId, workspaceConfig) => {
|
|
5629
|
-
const fullName = getConfigurableWorkspaceDisplayName(workspaceId, workspaceConfig);
|
|
5642
|
+
var getConfigurableShortWorkspaceDisplayName = (workspaceId, workspaceConfig, lineId) => {
|
|
5643
|
+
const fullName = getConfigurableWorkspaceDisplayName(workspaceId, workspaceConfig, lineId);
|
|
5630
5644
|
const match = fullName.match(/([A-Z]\d+(?:-\w+)?)/i);
|
|
5631
5645
|
if (match && match[0]) {
|
|
5632
5646
|
return match[0];
|
|
@@ -17631,18 +17645,6 @@ var VideoCard = React14__namespace.default.memo(({
|
|
|
17631
17645
|
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
17646
|
});
|
|
17633
17647
|
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
17648
|
var DEFAULT_HLS_URL = "https://192.168.5.9:8443/cam1.m3u8";
|
|
17647
17649
|
var VideoGridView = React14__namespace.default.memo(({
|
|
17648
17650
|
workspaces,
|
|
@@ -17656,13 +17658,20 @@ var VideoGridView = React14__namespace.default.memo(({
|
|
|
17656
17658
|
const [gridCols, setGridCols] = React14.useState(4);
|
|
17657
17659
|
const [visibleWorkspaces, setVisibleWorkspaces] = React14.useState(/* @__PURE__ */ new Set());
|
|
17658
17660
|
const videoConfig = useVideoConfig();
|
|
17659
|
-
const { cropping, canvasConfig } = videoConfig;
|
|
17661
|
+
const { cropping, canvasConfig, hlsUrls } = videoConfig;
|
|
17660
17662
|
const mergedVideoSources = {
|
|
17661
|
-
defaultHlsUrl: videoSources.defaultHlsUrl || DEFAULT_HLS_URL,
|
|
17662
|
-
workspaceHlsUrls: { ...
|
|
17663
|
+
defaultHlsUrl: videoSources.defaultHlsUrl || hlsUrls?.defaultHlsUrl || DEFAULT_HLS_URL,
|
|
17664
|
+
workspaceHlsUrls: { ...videoSources.workspaceHlsUrls, ...hlsUrls?.workspaceHlsUrls },
|
|
17665
|
+
lineWorkspaceHlsUrls: hlsUrls?.lineWorkspaceHlsUrls || {}
|
|
17663
17666
|
};
|
|
17664
|
-
const getWorkspaceHlsUrl = React14.useCallback((workspaceName) => {
|
|
17667
|
+
const getWorkspaceHlsUrl = React14.useCallback((workspaceName, lineId) => {
|
|
17665
17668
|
const wsName = workspaceName.toUpperCase();
|
|
17669
|
+
if (lineId && mergedVideoSources.lineWorkspaceHlsUrls[lineId]) {
|
|
17670
|
+
const lineUrls = mergedVideoSources.lineWorkspaceHlsUrls[lineId];
|
|
17671
|
+
if (lineUrls[wsName]) {
|
|
17672
|
+
return lineUrls[wsName];
|
|
17673
|
+
}
|
|
17674
|
+
}
|
|
17666
17675
|
return mergedVideoSources.workspaceHlsUrls[wsName] || mergedVideoSources.defaultHlsUrl;
|
|
17667
17676
|
}, [mergedVideoSources]);
|
|
17668
17677
|
const getWorkspaceCropping = React14.useCallback((workspaceName) => {
|
|
@@ -17822,7 +17831,7 @@ var VideoGridView = React14__namespace.default.memo(({
|
|
|
17822
17831
|
VideoCard,
|
|
17823
17832
|
{
|
|
17824
17833
|
workspace,
|
|
17825
|
-
hlsUrl: getWorkspaceHlsUrl(workspace.workspace_name),
|
|
17834
|
+
hlsUrl: getWorkspaceHlsUrl(workspace.workspace_name, workspace.line_id),
|
|
17826
17835
|
shouldPlay: isVisible,
|
|
17827
17836
|
onClick: () => handleWorkspaceClick(workspace),
|
|
17828
17837
|
onFatalError: throttledReloadDashboard,
|
|
@@ -21475,7 +21484,7 @@ function parseS3Uri(s3Uri, sopCategories) {
|
|
|
21475
21484
|
break;
|
|
21476
21485
|
case "long_cycle_time":
|
|
21477
21486
|
severity = "high";
|
|
21478
|
-
type = "
|
|
21487
|
+
type = "long_cycle_time";
|
|
21479
21488
|
description = "Long Cycle Time Detected";
|
|
21480
21489
|
break;
|
|
21481
21490
|
case "best_cycle_time":
|
|
@@ -21519,7 +21528,7 @@ function parseS3Uri(s3Uri, sopCategories) {
|
|
|
21519
21528
|
severity = "low";
|
|
21520
21529
|
description = "Best Cycle Time Performance";
|
|
21521
21530
|
} else if (normalizedViolationType.includes("long") && normalizedViolationType.includes("cycle")) {
|
|
21522
|
-
type = "
|
|
21531
|
+
type = "long_cycle_time";
|
|
21523
21532
|
severity = "high";
|
|
21524
21533
|
description = "Long Cycle Time Detected";
|
|
21525
21534
|
} else if (normalizedViolationType.includes("cycle") && (normalizedViolationType.includes("completion") || normalizedViolationType.includes("complete"))) {
|
|
@@ -21546,6 +21555,11 @@ var S3ClipsService = class {
|
|
|
21546
21555
|
if (!config.s3Config) {
|
|
21547
21556
|
throw new Error("S3 configuration is required");
|
|
21548
21557
|
}
|
|
21558
|
+
const processing = config.s3Config.processing || {};
|
|
21559
|
+
this.defaultLimitPerCategory = processing.defaultLimitPerCategory || 30;
|
|
21560
|
+
this.maxLimitPerCategory = processing.maxLimitPerCategory || 1e3;
|
|
21561
|
+
this.concurrencyLimit = processing.concurrencyLimit || 10;
|
|
21562
|
+
this.maxInitialFetch = processing.maxInitialFetch || 60;
|
|
21549
21563
|
const region = this.validateAndSanitizeRegion(config.s3Config.region);
|
|
21550
21564
|
console.log(`S3ClipsService: Using AWS region: ${region}`);
|
|
21551
21565
|
this.s3Client = new clientS3.S3Client({
|
|
@@ -21830,9 +21844,9 @@ var S3ClipsService = class {
|
|
|
21830
21844
|
}
|
|
21831
21845
|
return summary;
|
|
21832
21846
|
}
|
|
21833
|
-
const limitPerCategory = limit ? Math.min(Math.max(limit, 1),
|
|
21847
|
+
const limitPerCategory = limit ? Math.min(Math.max(limit, 1), this.maxLimitPerCategory) : this.defaultLimitPerCategory;
|
|
21834
21848
|
const shouldFetchAll = category === "missing_quality_check" || category === "low_value";
|
|
21835
|
-
const initialFetchLimit = shouldFetchAll ? void 0 : category ? limitPerCategory * 3 : void 0;
|
|
21849
|
+
const initialFetchLimit = shouldFetchAll ? void 0 : category ? Math.min(limitPerCategory * 3, this.maxInitialFetch) : void 0;
|
|
21836
21850
|
const s3Uris = await this.listS3Clips({ workspaceId, date, shiftId, maxKeys: initialFetchLimit });
|
|
21837
21851
|
if (s3Uris.length === 0) {
|
|
21838
21852
|
console.log(`S3ClipsService: No HLS playlists found for workspace ${workspaceId} on date ${date}, shift ${shiftId}`);
|
|
@@ -21900,12 +21914,11 @@ var S3ClipsService = class {
|
|
|
21900
21914
|
}
|
|
21901
21915
|
console.log(`S3ClipsService: Total filtered URIs across all categories: ${filteredUris.length}`);
|
|
21902
21916
|
}
|
|
21903
|
-
const concurrencyLimit = 10;
|
|
21904
21917
|
let processedCount = 0;
|
|
21905
21918
|
const videoResults = [];
|
|
21906
21919
|
console.log(`S3ClipsService: Processing ${filteredUris.length} URIs for ${category || "all categories"} with limit ${limitPerCategory} per category`);
|
|
21907
|
-
for (let i = 0; i < filteredUris.length; i += concurrencyLimit) {
|
|
21908
|
-
const batch = filteredUris.slice(i, i + concurrencyLimit);
|
|
21920
|
+
for (let i = 0; i < filteredUris.length; i += this.concurrencyLimit) {
|
|
21921
|
+
const batch = filteredUris.slice(i, i + this.concurrencyLimit);
|
|
21909
21922
|
const batchPromises = batch.map(async (uri, batchIndex) => {
|
|
21910
21923
|
const index = i + batchIndex;
|
|
21911
21924
|
const result = await this.processFullVideo(uri, index, workspaceId, date, shiftId, includeCycleTime || false, includeMetadata || (!!timestampStart || !!timestampEnd));
|
|
@@ -22064,6 +22077,7 @@ var BottlenecksContent = ({
|
|
|
22064
22077
|
const firstWorstCycle = videos.find((v) => v.type === "worst_cycle_time");
|
|
22065
22078
|
const firstSOPDeviation = videos.find((v) => v.type === "missing_quality_check");
|
|
22066
22079
|
const firstCycleCompletion = videos.find((v) => v.type === "cycle_completions");
|
|
22080
|
+
const firstLongCycleTime = videos.find((v) => v.type === "long_cycle_time");
|
|
22067
22081
|
preloadVideosUrl2([
|
|
22068
22082
|
firstHigh?.src,
|
|
22069
22083
|
firstMed?.src,
|
|
@@ -22072,7 +22086,8 @@ var BottlenecksContent = ({
|
|
|
22072
22086
|
firstBestCycle?.src,
|
|
22073
22087
|
firstWorstCycle?.src,
|
|
22074
22088
|
firstSOPDeviation?.src,
|
|
22075
|
-
firstCycleCompletion?.src
|
|
22089
|
+
firstCycleCompletion?.src,
|
|
22090
|
+
firstLongCycleTime?.src
|
|
22076
22091
|
].filter(Boolean));
|
|
22077
22092
|
}
|
|
22078
22093
|
setAllVideos(videos);
|
|
@@ -22098,7 +22113,7 @@ var BottlenecksContent = ({
|
|
|
22098
22113
|
if (activeFilter === "worst_cycle_time") return video.type === "worst_cycle_time";
|
|
22099
22114
|
if (activeFilter === "cycle_completions") return video.type === "cycle_completions";
|
|
22100
22115
|
if (activeFilter === "long_cycle_time") {
|
|
22101
|
-
return video.type === "
|
|
22116
|
+
return video.type === "long_cycle_time";
|
|
22102
22117
|
}
|
|
22103
22118
|
return video.type === "bottleneck" && video.severity === activeFilter;
|
|
22104
22119
|
});
|
|
@@ -22116,11 +22131,6 @@ var BottlenecksContent = ({
|
|
|
22116
22131
|
const selectedCategory = sopCategories.find((cat) => cat.id === activeFilter);
|
|
22117
22132
|
if (selectedCategory) {
|
|
22118
22133
|
filtered = allVideos.filter((video) => video.type === selectedCategory.id);
|
|
22119
|
-
if (selectedCategory.id === "long_cycle_time") {
|
|
22120
|
-
filtered = allVideos.filter(
|
|
22121
|
-
(video) => video.type === "bottleneck" && video.description.toLowerCase().includes("cycle time")
|
|
22122
|
-
);
|
|
22123
|
-
}
|
|
22124
22134
|
}
|
|
22125
22135
|
} else {
|
|
22126
22136
|
if (activeFilter === "low_value") {
|
|
@@ -22134,9 +22144,7 @@ var BottlenecksContent = ({
|
|
|
22134
22144
|
} else if (activeFilter === "cycle_completions") {
|
|
22135
22145
|
filtered = allVideos.filter((video) => video.type === "cycle_completions");
|
|
22136
22146
|
} else if (activeFilter === "long_cycle_time") {
|
|
22137
|
-
filtered = allVideos.filter(
|
|
22138
|
-
(video) => video.type === "bottleneck" && video.description.toLowerCase().includes("cycle time")
|
|
22139
|
-
);
|
|
22147
|
+
filtered = allVideos.filter((video) => video.type === "long_cycle_time");
|
|
22140
22148
|
} else {
|
|
22141
22149
|
filtered = allVideos.filter((video) => video.type === "bottleneck" && video.severity === activeFilter);
|
|
22142
22150
|
}
|
|
@@ -22423,13 +22431,7 @@ var BottlenecksContent = ({
|
|
|
22423
22431
|
const counts = { total: allVideos.length };
|
|
22424
22432
|
if (sopCategories && sopCategories.length > 0) {
|
|
22425
22433
|
sopCategories.forEach((category) => {
|
|
22426
|
-
|
|
22427
|
-
counts[category.id] = allVideos.filter(
|
|
22428
|
-
(video) => video.type === "bottleneck" && video.description.toLowerCase().includes("cycle time")
|
|
22429
|
-
).length;
|
|
22430
|
-
} else {
|
|
22431
|
-
counts[category.id] = allVideos.filter((video) => video.type === category.id).length;
|
|
22432
|
-
}
|
|
22434
|
+
counts[category.id] = allVideos.filter((video) => video.type === category.id).length;
|
|
22433
22435
|
});
|
|
22434
22436
|
} else {
|
|
22435
22437
|
counts.bottlenecks = allVideos.filter((video) => video.type === "bottleneck").length;
|
|
@@ -22440,9 +22442,7 @@ var BottlenecksContent = ({
|
|
|
22440
22442
|
counts.sopDeviations = allVideos.filter((video) => video.type === "missing_quality_check").length;
|
|
22441
22443
|
counts.bestCycleTimes = allVideos.filter((video) => video.type === "best_cycle_time").length;
|
|
22442
22444
|
counts.worstCycleTimes = allVideos.filter((video) => video.type === "worst_cycle_time").length;
|
|
22443
|
-
counts.longCycleTimes = allVideos.filter(
|
|
22444
|
-
(video) => video.type === "bottleneck" && video.description.toLowerCase().includes("cycle time")
|
|
22445
|
-
).length;
|
|
22445
|
+
counts.longCycleTimes = allVideos.filter((video) => video.type === "long_cycle_time").length;
|
|
22446
22446
|
counts.cycleCompletions = allVideos.filter((video) => video.type === "cycle_completions").length;
|
|
22447
22447
|
}
|
|
22448
22448
|
return counts;
|
|
@@ -22468,7 +22468,7 @@ var BottlenecksContent = ({
|
|
|
22468
22468
|
return "Cycle Completion";
|
|
22469
22469
|
case "bottleneck":
|
|
22470
22470
|
default:
|
|
22471
|
-
return "
|
|
22471
|
+
return "";
|
|
22472
22472
|
}
|
|
22473
22473
|
};
|
|
22474
22474
|
const getColorClasses = (color2) => {
|
|
@@ -27386,11 +27386,17 @@ function HomeView({
|
|
|
27386
27386
|
lineId: selectedLineId,
|
|
27387
27387
|
onLineMetricsUpdate
|
|
27388
27388
|
});
|
|
27389
|
+
const lineIdsForBreaks = React14.useMemo(() => {
|
|
27390
|
+
if (selectedLineId === factoryViewId) {
|
|
27391
|
+
return allLineIds;
|
|
27392
|
+
}
|
|
27393
|
+
return [selectedLineId];
|
|
27394
|
+
}, [selectedLineId, factoryViewId, allLineIds]);
|
|
27389
27395
|
const {
|
|
27390
27396
|
activeBreaks,
|
|
27391
27397
|
isLoading: breaksLoading,
|
|
27392
27398
|
error: breaksError
|
|
27393
|
-
} = useActiveBreaks(
|
|
27399
|
+
} = useActiveBreaks(lineIdsForBreaks);
|
|
27394
27400
|
const memoizedWorkspaceMetrics = React14.useMemo(() => workspaceMetrics, [
|
|
27395
27401
|
// Only update reference if meaningful properties change
|
|
27396
27402
|
workspaceMetrics.length,
|
|
@@ -28657,8 +28663,7 @@ var MobileWorkspaceCard = React14.memo(({
|
|
|
28657
28663
|
cardClass,
|
|
28658
28664
|
onWorkspaceClick,
|
|
28659
28665
|
getMedalIcon,
|
|
28660
|
-
|
|
28661
|
-
line2Id
|
|
28666
|
+
getLineName
|
|
28662
28667
|
}) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
28663
28668
|
"div",
|
|
28664
28669
|
{
|
|
@@ -28676,7 +28681,7 @@ var MobileWorkspaceCard = React14.memo(({
|
|
|
28676
28681
|
] }),
|
|
28677
28682
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
28678
28683
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-semibold text-gray-900", children: getWorkspaceDisplayName(workspace.workspace_name) }),
|
|
28679
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-gray-500", children: workspace.line_id
|
|
28684
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-gray-500", children: getLineName(workspace.line_id) })
|
|
28680
28685
|
] })
|
|
28681
28686
|
] }),
|
|
28682
28687
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-right", children: [
|
|
@@ -28714,8 +28719,7 @@ var DesktopWorkspaceRow = React14.memo(({
|
|
|
28714
28719
|
rowClass,
|
|
28715
28720
|
onWorkspaceClick,
|
|
28716
28721
|
getMedalIcon,
|
|
28717
|
-
|
|
28718
|
-
line2Id
|
|
28722
|
+
getLineName
|
|
28719
28723
|
}) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
28720
28724
|
"tr",
|
|
28721
28725
|
{
|
|
@@ -28727,7 +28731,7 @@ var DesktopWorkspaceRow = React14.memo(({
|
|
|
28727
28731
|
getMedalIcon(index + 1)
|
|
28728
28732
|
] }) }),
|
|
28729
28733
|
/* @__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) }) }),
|
|
28730
|
-
/* @__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
|
|
28734
|
+
/* @__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) }) }),
|
|
28731
28735
|
/* @__PURE__ */ jsxRuntime.jsxs("td", { className: "px-3 py-2.5 sm:p-4 text-sm sm:text-base font-medium whitespace-nowrap", children: [
|
|
28732
28736
|
(workspace.efficiency || 0).toFixed(1),
|
|
28733
28737
|
"%"
|
|
@@ -28755,10 +28759,19 @@ var LeaderboardDetailView = React14.memo(({
|
|
|
28755
28759
|
onWorkspaceClick,
|
|
28756
28760
|
line1Id = "",
|
|
28757
28761
|
line2Id = "",
|
|
28762
|
+
lineNames = {},
|
|
28758
28763
|
className = ""
|
|
28759
28764
|
}) => {
|
|
28760
28765
|
const navigation = useNavigation();
|
|
28761
28766
|
const [sortAscending, setSortAscending] = React14.useState(false);
|
|
28767
|
+
const getLineName = React14.useCallback((lineId2) => {
|
|
28768
|
+
if (lineNames[lineId2]) {
|
|
28769
|
+
return lineNames[lineId2];
|
|
28770
|
+
}
|
|
28771
|
+
if (lineId2 === line1Id) return "Line 1";
|
|
28772
|
+
if (lineId2 === line2Id) return "Line 2";
|
|
28773
|
+
return lineId2;
|
|
28774
|
+
}, [lineNames, line1Id, line2Id]);
|
|
28762
28775
|
const handleSortToggle = React14.useCallback(() => {
|
|
28763
28776
|
setSortAscending(!sortAscending);
|
|
28764
28777
|
}, [sortAscending]);
|
|
@@ -28932,8 +28945,7 @@ var LeaderboardDetailView = React14.memo(({
|
|
|
28932
28945
|
cardClass,
|
|
28933
28946
|
onWorkspaceClick: handleWorkspaceClick,
|
|
28934
28947
|
getMedalIcon,
|
|
28935
|
-
|
|
28936
|
-
line2Id
|
|
28948
|
+
getLineName
|
|
28937
28949
|
},
|
|
28938
28950
|
ws.workspace_uuid
|
|
28939
28951
|
);
|
|
@@ -28958,8 +28970,7 @@ var LeaderboardDetailView = React14.memo(({
|
|
|
28958
28970
|
rowClass,
|
|
28959
28971
|
onWorkspaceClick: handleWorkspaceClick,
|
|
28960
28972
|
getMedalIcon,
|
|
28961
|
-
|
|
28962
|
-
line2Id
|
|
28973
|
+
getLineName
|
|
28963
28974
|
},
|
|
28964
28975
|
ws.workspace_uuid
|
|
28965
28976
|
);
|
|
@@ -28968,7 +28979,7 @@ var LeaderboardDetailView = React14.memo(({
|
|
|
28968
28979
|
] })
|
|
28969
28980
|
] });
|
|
28970
28981
|
}, (prevProps, nextProps) => {
|
|
28971
|
-
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;
|
|
28982
|
+
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;
|
|
28972
28983
|
});
|
|
28973
28984
|
LeaderboardDetailView.displayName = "LeaderboardDetailView";
|
|
28974
28985
|
var LeaderboardDetailView_default = LeaderboardDetailView;
|
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
|
|
@@ -861,17 +864,18 @@ var dashboardService = {
|
|
|
861
864
|
const queryShiftId = shiftProp !== void 0 ? shiftProp : currentShiftResult.shiftId;
|
|
862
865
|
try {
|
|
863
866
|
if (lineIdToQuery === factoryViewId) {
|
|
864
|
-
if (!defaultLineId || !
|
|
865
|
-
throw new Error("Factory View requires defaultLineId
|
|
867
|
+
if (!defaultLineId || !companyId) {
|
|
868
|
+
throw new Error("Factory View requires at least defaultLineId and companyId to be configured.");
|
|
866
869
|
}
|
|
867
870
|
const { data: line1Data, error: line1Error } = await supabase.from(linesTable).select("id, line_name, factory_id, factories!lines_factory_id_fkey(factory_name), company_id, companies!lines_company_id_fkey(company_name:name)").eq("id", defaultLineId).single();
|
|
868
871
|
if (line1Error) throw line1Error;
|
|
869
872
|
if (!line1Data) {
|
|
870
873
|
throw new Error(`Default line ${defaultLineId} for Factory View not found.`);
|
|
871
874
|
}
|
|
872
|
-
const
|
|
875
|
+
const lineIdsToQuery = [defaultLineId, secondaryLineId].filter((id3) => id3 !== void 0 && id3 !== null);
|
|
876
|
+
const { data: metricsData, error: metricsError2 } = await supabase.from(lineMetricsTable).select("*").in("line_id", lineIdsToQuery).eq("shift_id", queryShiftId).eq("date", queryDate);
|
|
873
877
|
if (metricsError2) throw metricsError2;
|
|
874
|
-
const { data: performanceData2, error: performanceError2 } = await supabase.from(metricsTable).select("efficiency").in("line_id",
|
|
878
|
+
const { data: performanceData2, error: performanceError2 } = await supabase.from(metricsTable).select("efficiency").in("line_id", lineIdsToQuery).eq("shift_id", queryShiftId).eq("date", queryDate);
|
|
875
879
|
if (performanceError2) throw performanceError2;
|
|
876
880
|
const underperformingCount2 = performanceData2?.filter((w) => w.efficiency >= 10 && w.efficiency < 70).length || 0;
|
|
877
881
|
const totalValidWorkspaces2 = performanceData2?.filter((w) => w.efficiency >= 10).length || 0;
|
|
@@ -5096,19 +5100,23 @@ var useActiveBreaks = (lineIds) => {
|
|
|
5096
5100
|
const checkActiveBreaks = useCallback(async () => {
|
|
5097
5101
|
try {
|
|
5098
5102
|
setError(null);
|
|
5099
|
-
|
|
5103
|
+
const validLineIds = lineIds.filter(
|
|
5104
|
+
(id3) => id3 && id3 !== "factory" && id3 !== "all" && // Basic UUID format check
|
|
5105
|
+
id3.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i)
|
|
5106
|
+
);
|
|
5107
|
+
if (!validLineIds || validLineIds.length === 0) {
|
|
5100
5108
|
setActiveBreaks([]);
|
|
5101
5109
|
setIsLoading(false);
|
|
5102
5110
|
return;
|
|
5103
5111
|
}
|
|
5104
5112
|
const currentMinutes = getCurrentTimeInMinutes();
|
|
5105
|
-
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",
|
|
5106
|
-
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",
|
|
5113
|
+
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);
|
|
5114
|
+
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);
|
|
5107
5115
|
if (dayError || nightError) {
|
|
5108
5116
|
throw new Error("Failed to fetch shift configurations");
|
|
5109
5117
|
}
|
|
5110
5118
|
const foundActiveBreaks = [];
|
|
5111
|
-
for (const lineId of
|
|
5119
|
+
for (const lineId of validLineIds) {
|
|
5112
5120
|
const dayShift = dayShifts?.find((s) => s.line_id === lineId);
|
|
5113
5121
|
const nightShift = nightShifts?.find((s) => s.line_id === lineId);
|
|
5114
5122
|
if (!dayShift || !nightShift) continue;
|
|
@@ -5592,12 +5600,18 @@ var FALLBACK_DISPLAY_NAMES = {
|
|
|
5592
5600
|
"WS03": "Filling station"
|
|
5593
5601
|
// ... Add others if known defaults are useful
|
|
5594
5602
|
};
|
|
5595
|
-
var getConfigurableWorkspaceDisplayName = (workspaceId, workspaceConfig) => {
|
|
5603
|
+
var getConfigurableWorkspaceDisplayName = (workspaceId, workspaceConfig, lineId) => {
|
|
5604
|
+
if (lineId && workspaceConfig?.lineDisplayNames?.[lineId]) {
|
|
5605
|
+
const lineDisplayNames = workspaceConfig.lineDisplayNames[lineId];
|
|
5606
|
+
if (lineDisplayNames[workspaceId]) {
|
|
5607
|
+
return lineDisplayNames[workspaceId];
|
|
5608
|
+
}
|
|
5609
|
+
}
|
|
5596
5610
|
const displayNames = workspaceConfig?.displayNames || FALLBACK_DISPLAY_NAMES;
|
|
5597
5611
|
return displayNames[workspaceId] || workspaceId.replace(/^WS/i, "") || workspaceId;
|
|
5598
5612
|
};
|
|
5599
|
-
var getConfigurableShortWorkspaceDisplayName = (workspaceId, workspaceConfig) => {
|
|
5600
|
-
const fullName = getConfigurableWorkspaceDisplayName(workspaceId, workspaceConfig);
|
|
5613
|
+
var getConfigurableShortWorkspaceDisplayName = (workspaceId, workspaceConfig, lineId) => {
|
|
5614
|
+
const fullName = getConfigurableWorkspaceDisplayName(workspaceId, workspaceConfig, lineId);
|
|
5601
5615
|
const match = fullName.match(/([A-Z]\d+(?:-\w+)?)/i);
|
|
5602
5616
|
if (match && match[0]) {
|
|
5603
5617
|
return match[0];
|
|
@@ -17602,18 +17616,6 @@ var VideoCard = React14__default.memo(({
|
|
|
17602
17616
|
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
17617
|
});
|
|
17604
17618
|
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
17619
|
var DEFAULT_HLS_URL = "https://192.168.5.9:8443/cam1.m3u8";
|
|
17618
17620
|
var VideoGridView = React14__default.memo(({
|
|
17619
17621
|
workspaces,
|
|
@@ -17627,13 +17629,20 @@ var VideoGridView = React14__default.memo(({
|
|
|
17627
17629
|
const [gridCols, setGridCols] = useState(4);
|
|
17628
17630
|
const [visibleWorkspaces, setVisibleWorkspaces] = useState(/* @__PURE__ */ new Set());
|
|
17629
17631
|
const videoConfig = useVideoConfig();
|
|
17630
|
-
const { cropping, canvasConfig } = videoConfig;
|
|
17632
|
+
const { cropping, canvasConfig, hlsUrls } = videoConfig;
|
|
17631
17633
|
const mergedVideoSources = {
|
|
17632
|
-
defaultHlsUrl: videoSources.defaultHlsUrl || DEFAULT_HLS_URL,
|
|
17633
|
-
workspaceHlsUrls: { ...
|
|
17634
|
+
defaultHlsUrl: videoSources.defaultHlsUrl || hlsUrls?.defaultHlsUrl || DEFAULT_HLS_URL,
|
|
17635
|
+
workspaceHlsUrls: { ...videoSources.workspaceHlsUrls, ...hlsUrls?.workspaceHlsUrls },
|
|
17636
|
+
lineWorkspaceHlsUrls: hlsUrls?.lineWorkspaceHlsUrls || {}
|
|
17634
17637
|
};
|
|
17635
|
-
const getWorkspaceHlsUrl = useCallback((workspaceName) => {
|
|
17638
|
+
const getWorkspaceHlsUrl = useCallback((workspaceName, lineId) => {
|
|
17636
17639
|
const wsName = workspaceName.toUpperCase();
|
|
17640
|
+
if (lineId && mergedVideoSources.lineWorkspaceHlsUrls[lineId]) {
|
|
17641
|
+
const lineUrls = mergedVideoSources.lineWorkspaceHlsUrls[lineId];
|
|
17642
|
+
if (lineUrls[wsName]) {
|
|
17643
|
+
return lineUrls[wsName];
|
|
17644
|
+
}
|
|
17645
|
+
}
|
|
17637
17646
|
return mergedVideoSources.workspaceHlsUrls[wsName] || mergedVideoSources.defaultHlsUrl;
|
|
17638
17647
|
}, [mergedVideoSources]);
|
|
17639
17648
|
const getWorkspaceCropping = useCallback((workspaceName) => {
|
|
@@ -17793,7 +17802,7 @@ var VideoGridView = React14__default.memo(({
|
|
|
17793
17802
|
VideoCard,
|
|
17794
17803
|
{
|
|
17795
17804
|
workspace,
|
|
17796
|
-
hlsUrl: getWorkspaceHlsUrl(workspace.workspace_name),
|
|
17805
|
+
hlsUrl: getWorkspaceHlsUrl(workspace.workspace_name, workspace.line_id),
|
|
17797
17806
|
shouldPlay: isVisible,
|
|
17798
17807
|
onClick: () => handleWorkspaceClick(workspace),
|
|
17799
17808
|
onFatalError: throttledReloadDashboard,
|
|
@@ -21446,7 +21455,7 @@ function parseS3Uri(s3Uri, sopCategories) {
|
|
|
21446
21455
|
break;
|
|
21447
21456
|
case "long_cycle_time":
|
|
21448
21457
|
severity = "high";
|
|
21449
|
-
type = "
|
|
21458
|
+
type = "long_cycle_time";
|
|
21450
21459
|
description = "Long Cycle Time Detected";
|
|
21451
21460
|
break;
|
|
21452
21461
|
case "best_cycle_time":
|
|
@@ -21490,7 +21499,7 @@ function parseS3Uri(s3Uri, sopCategories) {
|
|
|
21490
21499
|
severity = "low";
|
|
21491
21500
|
description = "Best Cycle Time Performance";
|
|
21492
21501
|
} else if (normalizedViolationType.includes("long") && normalizedViolationType.includes("cycle")) {
|
|
21493
|
-
type = "
|
|
21502
|
+
type = "long_cycle_time";
|
|
21494
21503
|
severity = "high";
|
|
21495
21504
|
description = "Long Cycle Time Detected";
|
|
21496
21505
|
} else if (normalizedViolationType.includes("cycle") && (normalizedViolationType.includes("completion") || normalizedViolationType.includes("complete"))) {
|
|
@@ -21517,6 +21526,11 @@ var S3ClipsService = class {
|
|
|
21517
21526
|
if (!config.s3Config) {
|
|
21518
21527
|
throw new Error("S3 configuration is required");
|
|
21519
21528
|
}
|
|
21529
|
+
const processing = config.s3Config.processing || {};
|
|
21530
|
+
this.defaultLimitPerCategory = processing.defaultLimitPerCategory || 30;
|
|
21531
|
+
this.maxLimitPerCategory = processing.maxLimitPerCategory || 1e3;
|
|
21532
|
+
this.concurrencyLimit = processing.concurrencyLimit || 10;
|
|
21533
|
+
this.maxInitialFetch = processing.maxInitialFetch || 60;
|
|
21520
21534
|
const region = this.validateAndSanitizeRegion(config.s3Config.region);
|
|
21521
21535
|
console.log(`S3ClipsService: Using AWS region: ${region}`);
|
|
21522
21536
|
this.s3Client = new S3Client({
|
|
@@ -21801,9 +21815,9 @@ var S3ClipsService = class {
|
|
|
21801
21815
|
}
|
|
21802
21816
|
return summary;
|
|
21803
21817
|
}
|
|
21804
|
-
const limitPerCategory = limit ? Math.min(Math.max(limit, 1),
|
|
21818
|
+
const limitPerCategory = limit ? Math.min(Math.max(limit, 1), this.maxLimitPerCategory) : this.defaultLimitPerCategory;
|
|
21805
21819
|
const shouldFetchAll = category === "missing_quality_check" || category === "low_value";
|
|
21806
|
-
const initialFetchLimit = shouldFetchAll ? void 0 : category ? limitPerCategory * 3 : void 0;
|
|
21820
|
+
const initialFetchLimit = shouldFetchAll ? void 0 : category ? Math.min(limitPerCategory * 3, this.maxInitialFetch) : void 0;
|
|
21807
21821
|
const s3Uris = await this.listS3Clips({ workspaceId, date, shiftId, maxKeys: initialFetchLimit });
|
|
21808
21822
|
if (s3Uris.length === 0) {
|
|
21809
21823
|
console.log(`S3ClipsService: No HLS playlists found for workspace ${workspaceId} on date ${date}, shift ${shiftId}`);
|
|
@@ -21871,12 +21885,11 @@ var S3ClipsService = class {
|
|
|
21871
21885
|
}
|
|
21872
21886
|
console.log(`S3ClipsService: Total filtered URIs across all categories: ${filteredUris.length}`);
|
|
21873
21887
|
}
|
|
21874
|
-
const concurrencyLimit = 10;
|
|
21875
21888
|
let processedCount = 0;
|
|
21876
21889
|
const videoResults = [];
|
|
21877
21890
|
console.log(`S3ClipsService: Processing ${filteredUris.length} URIs for ${category || "all categories"} with limit ${limitPerCategory} per category`);
|
|
21878
|
-
for (let i = 0; i < filteredUris.length; i += concurrencyLimit) {
|
|
21879
|
-
const batch = filteredUris.slice(i, i + concurrencyLimit);
|
|
21891
|
+
for (let i = 0; i < filteredUris.length; i += this.concurrencyLimit) {
|
|
21892
|
+
const batch = filteredUris.slice(i, i + this.concurrencyLimit);
|
|
21880
21893
|
const batchPromises = batch.map(async (uri, batchIndex) => {
|
|
21881
21894
|
const index = i + batchIndex;
|
|
21882
21895
|
const result = await this.processFullVideo(uri, index, workspaceId, date, shiftId, includeCycleTime || false, includeMetadata || (!!timestampStart || !!timestampEnd));
|
|
@@ -22035,6 +22048,7 @@ var BottlenecksContent = ({
|
|
|
22035
22048
|
const firstWorstCycle = videos.find((v) => v.type === "worst_cycle_time");
|
|
22036
22049
|
const firstSOPDeviation = videos.find((v) => v.type === "missing_quality_check");
|
|
22037
22050
|
const firstCycleCompletion = videos.find((v) => v.type === "cycle_completions");
|
|
22051
|
+
const firstLongCycleTime = videos.find((v) => v.type === "long_cycle_time");
|
|
22038
22052
|
preloadVideosUrl2([
|
|
22039
22053
|
firstHigh?.src,
|
|
22040
22054
|
firstMed?.src,
|
|
@@ -22043,7 +22057,8 @@ var BottlenecksContent = ({
|
|
|
22043
22057
|
firstBestCycle?.src,
|
|
22044
22058
|
firstWorstCycle?.src,
|
|
22045
22059
|
firstSOPDeviation?.src,
|
|
22046
|
-
firstCycleCompletion?.src
|
|
22060
|
+
firstCycleCompletion?.src,
|
|
22061
|
+
firstLongCycleTime?.src
|
|
22047
22062
|
].filter(Boolean));
|
|
22048
22063
|
}
|
|
22049
22064
|
setAllVideos(videos);
|
|
@@ -22069,7 +22084,7 @@ var BottlenecksContent = ({
|
|
|
22069
22084
|
if (activeFilter === "worst_cycle_time") return video.type === "worst_cycle_time";
|
|
22070
22085
|
if (activeFilter === "cycle_completions") return video.type === "cycle_completions";
|
|
22071
22086
|
if (activeFilter === "long_cycle_time") {
|
|
22072
|
-
return video.type === "
|
|
22087
|
+
return video.type === "long_cycle_time";
|
|
22073
22088
|
}
|
|
22074
22089
|
return video.type === "bottleneck" && video.severity === activeFilter;
|
|
22075
22090
|
});
|
|
@@ -22087,11 +22102,6 @@ var BottlenecksContent = ({
|
|
|
22087
22102
|
const selectedCategory = sopCategories.find((cat) => cat.id === activeFilter);
|
|
22088
22103
|
if (selectedCategory) {
|
|
22089
22104
|
filtered = allVideos.filter((video) => video.type === selectedCategory.id);
|
|
22090
|
-
if (selectedCategory.id === "long_cycle_time") {
|
|
22091
|
-
filtered = allVideos.filter(
|
|
22092
|
-
(video) => video.type === "bottleneck" && video.description.toLowerCase().includes("cycle time")
|
|
22093
|
-
);
|
|
22094
|
-
}
|
|
22095
22105
|
}
|
|
22096
22106
|
} else {
|
|
22097
22107
|
if (activeFilter === "low_value") {
|
|
@@ -22105,9 +22115,7 @@ var BottlenecksContent = ({
|
|
|
22105
22115
|
} else if (activeFilter === "cycle_completions") {
|
|
22106
22116
|
filtered = allVideos.filter((video) => video.type === "cycle_completions");
|
|
22107
22117
|
} else if (activeFilter === "long_cycle_time") {
|
|
22108
|
-
filtered = allVideos.filter(
|
|
22109
|
-
(video) => video.type === "bottleneck" && video.description.toLowerCase().includes("cycle time")
|
|
22110
|
-
);
|
|
22118
|
+
filtered = allVideos.filter((video) => video.type === "long_cycle_time");
|
|
22111
22119
|
} else {
|
|
22112
22120
|
filtered = allVideos.filter((video) => video.type === "bottleneck" && video.severity === activeFilter);
|
|
22113
22121
|
}
|
|
@@ -22394,13 +22402,7 @@ var BottlenecksContent = ({
|
|
|
22394
22402
|
const counts = { total: allVideos.length };
|
|
22395
22403
|
if (sopCategories && sopCategories.length > 0) {
|
|
22396
22404
|
sopCategories.forEach((category) => {
|
|
22397
|
-
|
|
22398
|
-
counts[category.id] = allVideos.filter(
|
|
22399
|
-
(video) => video.type === "bottleneck" && video.description.toLowerCase().includes("cycle time")
|
|
22400
|
-
).length;
|
|
22401
|
-
} else {
|
|
22402
|
-
counts[category.id] = allVideos.filter((video) => video.type === category.id).length;
|
|
22403
|
-
}
|
|
22405
|
+
counts[category.id] = allVideos.filter((video) => video.type === category.id).length;
|
|
22404
22406
|
});
|
|
22405
22407
|
} else {
|
|
22406
22408
|
counts.bottlenecks = allVideos.filter((video) => video.type === "bottleneck").length;
|
|
@@ -22411,9 +22413,7 @@ var BottlenecksContent = ({
|
|
|
22411
22413
|
counts.sopDeviations = allVideos.filter((video) => video.type === "missing_quality_check").length;
|
|
22412
22414
|
counts.bestCycleTimes = allVideos.filter((video) => video.type === "best_cycle_time").length;
|
|
22413
22415
|
counts.worstCycleTimes = allVideos.filter((video) => video.type === "worst_cycle_time").length;
|
|
22414
|
-
counts.longCycleTimes = allVideos.filter(
|
|
22415
|
-
(video) => video.type === "bottleneck" && video.description.toLowerCase().includes("cycle time")
|
|
22416
|
-
).length;
|
|
22416
|
+
counts.longCycleTimes = allVideos.filter((video) => video.type === "long_cycle_time").length;
|
|
22417
22417
|
counts.cycleCompletions = allVideos.filter((video) => video.type === "cycle_completions").length;
|
|
22418
22418
|
}
|
|
22419
22419
|
return counts;
|
|
@@ -22439,7 +22439,7 @@ var BottlenecksContent = ({
|
|
|
22439
22439
|
return "Cycle Completion";
|
|
22440
22440
|
case "bottleneck":
|
|
22441
22441
|
default:
|
|
22442
|
-
return "
|
|
22442
|
+
return "";
|
|
22443
22443
|
}
|
|
22444
22444
|
};
|
|
22445
22445
|
const getColorClasses = (color2) => {
|
|
@@ -27357,11 +27357,17 @@ function HomeView({
|
|
|
27357
27357
|
lineId: selectedLineId,
|
|
27358
27358
|
onLineMetricsUpdate
|
|
27359
27359
|
});
|
|
27360
|
+
const lineIdsForBreaks = useMemo(() => {
|
|
27361
|
+
if (selectedLineId === factoryViewId) {
|
|
27362
|
+
return allLineIds;
|
|
27363
|
+
}
|
|
27364
|
+
return [selectedLineId];
|
|
27365
|
+
}, [selectedLineId, factoryViewId, allLineIds]);
|
|
27360
27366
|
const {
|
|
27361
27367
|
activeBreaks,
|
|
27362
27368
|
isLoading: breaksLoading,
|
|
27363
27369
|
error: breaksError
|
|
27364
|
-
} = useActiveBreaks(
|
|
27370
|
+
} = useActiveBreaks(lineIdsForBreaks);
|
|
27365
27371
|
const memoizedWorkspaceMetrics = useMemo(() => workspaceMetrics, [
|
|
27366
27372
|
// Only update reference if meaningful properties change
|
|
27367
27373
|
workspaceMetrics.length,
|
|
@@ -28628,8 +28634,7 @@ var MobileWorkspaceCard = memo(({
|
|
|
28628
28634
|
cardClass,
|
|
28629
28635
|
onWorkspaceClick,
|
|
28630
28636
|
getMedalIcon,
|
|
28631
|
-
|
|
28632
|
-
line2Id
|
|
28637
|
+
getLineName
|
|
28633
28638
|
}) => /* @__PURE__ */ jsxs(
|
|
28634
28639
|
"div",
|
|
28635
28640
|
{
|
|
@@ -28647,7 +28652,7 @@ var MobileWorkspaceCard = memo(({
|
|
|
28647
28652
|
] }),
|
|
28648
28653
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
28649
28654
|
/* @__PURE__ */ jsx("div", { className: "font-semibold text-gray-900", children: getWorkspaceDisplayName(workspace.workspace_name) }),
|
|
28650
|
-
/* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500", children: workspace.line_id
|
|
28655
|
+
/* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500", children: getLineName(workspace.line_id) })
|
|
28651
28656
|
] })
|
|
28652
28657
|
] }),
|
|
28653
28658
|
/* @__PURE__ */ jsxs("div", { className: "text-right", children: [
|
|
@@ -28685,8 +28690,7 @@ var DesktopWorkspaceRow = memo(({
|
|
|
28685
28690
|
rowClass,
|
|
28686
28691
|
onWorkspaceClick,
|
|
28687
28692
|
getMedalIcon,
|
|
28688
|
-
|
|
28689
|
-
line2Id
|
|
28693
|
+
getLineName
|
|
28690
28694
|
}) => /* @__PURE__ */ jsxs(
|
|
28691
28695
|
"tr",
|
|
28692
28696
|
{
|
|
@@ -28698,7 +28702,7 @@ var DesktopWorkspaceRow = memo(({
|
|
|
28698
28702
|
getMedalIcon(index + 1)
|
|
28699
28703
|
] }) }),
|
|
28700
28704
|
/* @__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) }) }),
|
|
28701
|
-
/* @__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
|
|
28705
|
+
/* @__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) }) }),
|
|
28702
28706
|
/* @__PURE__ */ jsxs("td", { className: "px-3 py-2.5 sm:p-4 text-sm sm:text-base font-medium whitespace-nowrap", children: [
|
|
28703
28707
|
(workspace.efficiency || 0).toFixed(1),
|
|
28704
28708
|
"%"
|
|
@@ -28726,10 +28730,19 @@ var LeaderboardDetailView = memo(({
|
|
|
28726
28730
|
onWorkspaceClick,
|
|
28727
28731
|
line1Id = "",
|
|
28728
28732
|
line2Id = "",
|
|
28733
|
+
lineNames = {},
|
|
28729
28734
|
className = ""
|
|
28730
28735
|
}) => {
|
|
28731
28736
|
const navigation = useNavigation();
|
|
28732
28737
|
const [sortAscending, setSortAscending] = useState(false);
|
|
28738
|
+
const getLineName = useCallback((lineId2) => {
|
|
28739
|
+
if (lineNames[lineId2]) {
|
|
28740
|
+
return lineNames[lineId2];
|
|
28741
|
+
}
|
|
28742
|
+
if (lineId2 === line1Id) return "Line 1";
|
|
28743
|
+
if (lineId2 === line2Id) return "Line 2";
|
|
28744
|
+
return lineId2;
|
|
28745
|
+
}, [lineNames, line1Id, line2Id]);
|
|
28733
28746
|
const handleSortToggle = useCallback(() => {
|
|
28734
28747
|
setSortAscending(!sortAscending);
|
|
28735
28748
|
}, [sortAscending]);
|
|
@@ -28903,8 +28916,7 @@ var LeaderboardDetailView = memo(({
|
|
|
28903
28916
|
cardClass,
|
|
28904
28917
|
onWorkspaceClick: handleWorkspaceClick,
|
|
28905
28918
|
getMedalIcon,
|
|
28906
|
-
|
|
28907
|
-
line2Id
|
|
28919
|
+
getLineName
|
|
28908
28920
|
},
|
|
28909
28921
|
ws.workspace_uuid
|
|
28910
28922
|
);
|
|
@@ -28929,8 +28941,7 @@ var LeaderboardDetailView = memo(({
|
|
|
28929
28941
|
rowClass,
|
|
28930
28942
|
onWorkspaceClick: handleWorkspaceClick,
|
|
28931
28943
|
getMedalIcon,
|
|
28932
|
-
|
|
28933
|
-
line2Id
|
|
28944
|
+
getLineName
|
|
28934
28945
|
},
|
|
28935
28946
|
ws.workspace_uuid
|
|
28936
28947
|
);
|
|
@@ -28939,7 +28950,7 @@ var LeaderboardDetailView = memo(({
|
|
|
28939
28950
|
] })
|
|
28940
28951
|
] });
|
|
28941
28952
|
}, (prevProps, nextProps) => {
|
|
28942
|
-
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;
|
|
28953
|
+
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;
|
|
28943
28954
|
});
|
|
28944
28955
|
LeaderboardDetailView.displayName = "LeaderboardDetailView";
|
|
28945
28956
|
var LeaderboardDetailView_default = LeaderboardDetailView;
|