@optifye/dashboard-core 6.11.43 → 6.11.45
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.css +5 -0
- package/dist/index.d.mts +14 -1
- package/dist/index.d.ts +14 -1
- package/dist/index.js +948 -328
- package/dist/index.mjs +948 -328
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -5088,6 +5088,27 @@ var workspaceService = {
|
|
|
5088
5088
|
this._workspaceVideoStreamsInFlight.set(cacheKey, fetchPromise);
|
|
5089
5089
|
return fetchPromise;
|
|
5090
5090
|
},
|
|
5091
|
+
primeWorkspaceVideoStreamsCache(params) {
|
|
5092
|
+
const streams = params.streams || {};
|
|
5093
|
+
const workspaceIds = (params.workspaceIds || []).filter(Boolean);
|
|
5094
|
+
const lineIds = (params.lineIds || []).filter(Boolean);
|
|
5095
|
+
if (!Object.keys(streams).length || !workspaceIds.length && !lineIds.length) {
|
|
5096
|
+
return;
|
|
5097
|
+
}
|
|
5098
|
+
const timestamp = Date.now();
|
|
5099
|
+
const entry = {
|
|
5100
|
+
streams,
|
|
5101
|
+
timestamp
|
|
5102
|
+
};
|
|
5103
|
+
if (workspaceIds.length) {
|
|
5104
|
+
const workspaceKey = workspaceIds.slice().sort().join(",");
|
|
5105
|
+
this._workspaceVideoStreamsCache.set(`workspaces:${workspaceKey}`, entry);
|
|
5106
|
+
}
|
|
5107
|
+
if (lineIds.length) {
|
|
5108
|
+
const lineKey = lineIds.slice().sort().join(",");
|
|
5109
|
+
this._workspaceVideoStreamsCache.set(`lines:${lineKey}`, entry);
|
|
5110
|
+
}
|
|
5111
|
+
},
|
|
5091
5112
|
async getWorkspaceCameraIps(params) {
|
|
5092
5113
|
const workspaceIds = (params.workspaceIds || []).filter(Boolean);
|
|
5093
5114
|
const lineIds = (params.lineIds || []).filter(Boolean);
|
|
@@ -11959,8 +11980,8 @@ var useOperationalShiftKey = ({
|
|
|
11959
11980
|
};
|
|
11960
11981
|
|
|
11961
11982
|
// src/lib/stores/workspaceMetricsStore.ts
|
|
11962
|
-
var OVERVIEW_TTL_MS =
|
|
11963
|
-
var DETAILED_TTL_MS =
|
|
11983
|
+
var OVERVIEW_TTL_MS = 12e4;
|
|
11984
|
+
var DETAILED_TTL_MS = 12e4;
|
|
11964
11985
|
var overviewByKey = /* @__PURE__ */ new Map();
|
|
11965
11986
|
var detailedByKey = /* @__PURE__ */ new Map();
|
|
11966
11987
|
var latestOverviewByWorkspace = /* @__PURE__ */ new Map();
|
|
@@ -13456,12 +13477,124 @@ function getEfficiencyTextColorClasses(efficiency, legend = DEFAULT_EFFICIENCY_L
|
|
|
13456
13477
|
}
|
|
13457
13478
|
}
|
|
13458
13479
|
|
|
13480
|
+
// src/lib/utils/monitorWorkspaceMetrics.ts
|
|
13481
|
+
var sortWorkspaceMetrics = (left, right) => {
|
|
13482
|
+
if (left.line_id !== right.line_id) {
|
|
13483
|
+
return left.line_id.localeCompare(right.line_id);
|
|
13484
|
+
}
|
|
13485
|
+
return left.workspace_name.localeCompare(right.workspace_name, void 0, { numeric: true });
|
|
13486
|
+
};
|
|
13487
|
+
var buildLineMetricsById = (lineMetrics) => (lineMetrics || []).reduce((acc, lineMetric) => {
|
|
13488
|
+
const lineId = lineMetric?.line_id;
|
|
13489
|
+
if (!lineId) {
|
|
13490
|
+
return acc;
|
|
13491
|
+
}
|
|
13492
|
+
acc[lineId] = { total_workspaces: lineMetric?.total_workspaces };
|
|
13493
|
+
return acc;
|
|
13494
|
+
}, {});
|
|
13495
|
+
var transformMonitorWorkspaceMetrics = ({
|
|
13496
|
+
rows,
|
|
13497
|
+
companyId,
|
|
13498
|
+
workspaceConfig,
|
|
13499
|
+
appTimezone,
|
|
13500
|
+
lineMetrics,
|
|
13501
|
+
resolveShiftConfig,
|
|
13502
|
+
shouldOverrideShiftType,
|
|
13503
|
+
fallbackShiftConfig = null
|
|
13504
|
+
}) => {
|
|
13505
|
+
const effectiveWorkspaceConfig = workspaceConfig || DEFAULT_WORKSPACE_CONFIG;
|
|
13506
|
+
const detailTimezone = appTimezone || "Asia/Kolkata";
|
|
13507
|
+
const lineMetricsById = buildLineMetricsById(lineMetrics);
|
|
13508
|
+
return (rows || []).map((item) => {
|
|
13509
|
+
const lineId = String(item?.line_id || "");
|
|
13510
|
+
const lineShiftConfig = resolveShiftConfig?.(lineId) || fallbackShiftConfig || void 0;
|
|
13511
|
+
const detailedMetrics = toWorkspaceDetailedMetrics({
|
|
13512
|
+
data: item,
|
|
13513
|
+
companyId,
|
|
13514
|
+
workspaceConfig: effectiveWorkspaceConfig,
|
|
13515
|
+
shiftConfig: lineShiftConfig,
|
|
13516
|
+
appTimezone: detailTimezone,
|
|
13517
|
+
lineMetricsById,
|
|
13518
|
+
overrideShiftType: shouldOverrideShiftType?.(lineId) ?? false
|
|
13519
|
+
});
|
|
13520
|
+
if (detailedMetrics) {
|
|
13521
|
+
workspaceMetricsStore.setDetailed(detailedMetrics);
|
|
13522
|
+
}
|
|
13523
|
+
const idleTimeValue = typeof item.idle_time === "number" ? item.idle_time : Number(item.idle_time);
|
|
13524
|
+
const idleTimeSeconds = Number.isFinite(idleTimeValue) ? idleTimeValue : void 0;
|
|
13525
|
+
const pphThresholdValue = typeof item.pph_threshold === "number" ? item.pph_threshold : Number(item.pph_threshold);
|
|
13526
|
+
const actionFamily = normalizeActionFamily({
|
|
13527
|
+
actionFamily: item.action_family,
|
|
13528
|
+
actionType: item.action_type,
|
|
13529
|
+
actionName: item.action_name
|
|
13530
|
+
});
|
|
13531
|
+
const actionType = actionFamily === "assembly" || actionFamily === "output" ? actionFamily : null;
|
|
13532
|
+
const metric = {
|
|
13533
|
+
company_id: item.company_id || companyId,
|
|
13534
|
+
line_id: lineId,
|
|
13535
|
+
shift_id: item.shift_id,
|
|
13536
|
+
date: item.date,
|
|
13537
|
+
workspace_uuid: item.workspace_id,
|
|
13538
|
+
workspace_name: item.workspace_name,
|
|
13539
|
+
displayName: item.workspace_display_name || item.display_name || void 0,
|
|
13540
|
+
action_count: item.total_output || 0,
|
|
13541
|
+
pph: item.avg_pph || 0,
|
|
13542
|
+
pph_threshold: Number.isFinite(pphThresholdValue) ? pphThresholdValue : void 0,
|
|
13543
|
+
performance_score: item.performance_score || 0,
|
|
13544
|
+
avg_cycle_time: item.avg_cycle_time || 0,
|
|
13545
|
+
ideal_cycle_time: item.ideal_cycle_time || void 0,
|
|
13546
|
+
trend: item.trend_score === 1 ? 2 : 0,
|
|
13547
|
+
predicted_output: item.ideal_output || 0,
|
|
13548
|
+
efficiency: item.efficiency || 0,
|
|
13549
|
+
action_threshold: item.total_day_output || 0,
|
|
13550
|
+
monitoring_mode: item.monitoring_mode ?? void 0,
|
|
13551
|
+
idle_time: idleTimeSeconds,
|
|
13552
|
+
idle_time_hourly: item.idle_time_hourly ?? null,
|
|
13553
|
+
shift_start: item.shift_start ?? void 0,
|
|
13554
|
+
shift_end: item.shift_end ?? void 0,
|
|
13555
|
+
assembly_enabled: item.assembly_enabled ?? false,
|
|
13556
|
+
video_grid_metric_mode: normalizeVideoGridMetricMode(
|
|
13557
|
+
item.video_grid_metric_mode,
|
|
13558
|
+
item.assembly_enabled ?? false
|
|
13559
|
+
),
|
|
13560
|
+
action_type: actionType,
|
|
13561
|
+
action_family: actionFamily,
|
|
13562
|
+
action_display_name: getActionDisplayName({
|
|
13563
|
+
displayName: item.action_display_name,
|
|
13564
|
+
actionFamily: item.action_family,
|
|
13565
|
+
actionType: item.action_type,
|
|
13566
|
+
actionName: item.action_name
|
|
13567
|
+
}),
|
|
13568
|
+
recent_flow_percent: item.recent_flow_percent ?? null,
|
|
13569
|
+
recent_flow_window_minutes: item.recent_flow_window_minutes ?? null,
|
|
13570
|
+
recent_flow_effective_end_at: item.recent_flow_effective_end_at ?? null,
|
|
13571
|
+
recent_flow_computed_at: item.recent_flow_computed_at ?? null,
|
|
13572
|
+
scheduled_break_active: item.scheduled_break_active ?? false,
|
|
13573
|
+
incoming_wip_current: item.incoming_wip_current ?? null,
|
|
13574
|
+
incoming_wip_effective_at: item.incoming_wip_effective_at ?? null,
|
|
13575
|
+
incoming_wip_buffer_name: item.incoming_wip_buffer_name ?? null,
|
|
13576
|
+
show_exclamation: item.show_exclamation ?? void 0
|
|
13577
|
+
};
|
|
13578
|
+
workspaceMetricsStore.setOverview(metric);
|
|
13579
|
+
return metric;
|
|
13580
|
+
}).sort(sortWorkspaceMetrics);
|
|
13581
|
+
};
|
|
13582
|
+
|
|
13459
13583
|
// src/lib/hooks/useDashboardMetrics.ts
|
|
13460
13584
|
var DEBUG_DASHBOARD_LOGS = process.env.NEXT_PUBLIC_DEBUG_DASHBOARD === "true";
|
|
13585
|
+
var REALTIME_REFRESH_DEBOUNCE_MS = 1500;
|
|
13586
|
+
var REALTIME_REFRESH_MIN_INTERVAL_MS = 5e3;
|
|
13461
13587
|
var logDebug = (...args) => {
|
|
13462
13588
|
if (!DEBUG_DASHBOARD_LOGS) return;
|
|
13463
13589
|
console.log(...args);
|
|
13464
13590
|
};
|
|
13591
|
+
var buildMetricsScopeKey = (lineId, lineIds) => {
|
|
13592
|
+
const normalizedLineIds = Array.from(new Set((lineIds || []).filter(Boolean))).sort();
|
|
13593
|
+
if (normalizedLineIds.length > 0) {
|
|
13594
|
+
return `${lineId}|${normalizedLineIds.join(",")}`;
|
|
13595
|
+
}
|
|
13596
|
+
return lineId;
|
|
13597
|
+
};
|
|
13465
13598
|
var parseEfficiencyLegend = (legend) => {
|
|
13466
13599
|
if (!legend) return null;
|
|
13467
13600
|
const coerce = (value, fallback) => {
|
|
@@ -13541,6 +13674,7 @@ var useDashboardMetrics = ({
|
|
|
13541
13674
|
const supabase = useSupabase();
|
|
13542
13675
|
const [metrics2, setMetrics] = useState({ workspaceMetrics: [], lineMetrics: [] });
|
|
13543
13676
|
const [metricsLineId, setMetricsLineId] = useState(lineId ?? null);
|
|
13677
|
+
const [metricsScopeKey, setMetricsScopeKey] = useState(() => buildMetricsScopeKey(lineId, lineIds));
|
|
13544
13678
|
const [isLoading, setIsLoading] = useState(true);
|
|
13545
13679
|
const [error, setError] = useState(null);
|
|
13546
13680
|
const lineIdRef = useRef(lineId);
|
|
@@ -13550,8 +13684,10 @@ var useDashboardMetrics = ({
|
|
|
13550
13684
|
const abortControllerRef = useRef(null);
|
|
13551
13685
|
const lastFetchKeyRef = useRef(null);
|
|
13552
13686
|
const inFlightFetchKeyRef = useRef(null);
|
|
13553
|
-
const updateQueueRef = useRef(false);
|
|
13554
13687
|
const onLineMetricsUpdateRef = useRef(onLineMetricsUpdate);
|
|
13688
|
+
const pendingRealtimeRefreshRef = useRef(false);
|
|
13689
|
+
const realtimeRefreshTimerRef = useRef(null);
|
|
13690
|
+
const lastRealtimeRefreshStartedAtRef = useRef(0);
|
|
13555
13691
|
const shiftGroupsRef = useRef(shiftGroups);
|
|
13556
13692
|
const operationalShiftKeyRef = useRef(operationalShiftKey);
|
|
13557
13693
|
const configuredLineIdsRef = useRef(configuredLineIds);
|
|
@@ -13579,15 +13715,17 @@ var useDashboardMetrics = ({
|
|
|
13579
13715
|
() => getCompanyMetricsTableName(entityConfig.companyId, "performance_metrics"),
|
|
13580
13716
|
[entityConfig.companyId]
|
|
13581
13717
|
);
|
|
13718
|
+
const requestedScopeKey = useMemo(
|
|
13719
|
+
() => buildMetricsScopeKey(lineId, isFactoryView ? targetFactoryLineIds : void 0),
|
|
13720
|
+
[isFactoryView, lineId, targetFactoryLineIds]
|
|
13721
|
+
);
|
|
13582
13722
|
useEffect(() => {
|
|
13583
13723
|
lineIdRef.current = lineId;
|
|
13584
|
-
setMetrics({ workspaceMetrics: [], lineMetrics: [], metadata: void 0, efficiencyLegend: DEFAULT_EFFICIENCY_LEGEND });
|
|
13585
|
-
setMetricsLineId(null);
|
|
13586
13724
|
setIsLoading(true);
|
|
13587
13725
|
setError(null);
|
|
13588
13726
|
lastFetchKeyRef.current = null;
|
|
13589
13727
|
inFlightFetchKeyRef.current = null;
|
|
13590
|
-
}, [lineId]);
|
|
13728
|
+
}, [lineId, requestedScopeKey]);
|
|
13591
13729
|
const fetchAllMetrics = useCallback(async (options = {}) => {
|
|
13592
13730
|
const { force = false } = options;
|
|
13593
13731
|
const currentLineIdToUse = lineIdRef.current;
|
|
@@ -13600,7 +13738,6 @@ var useDashboardMetrics = ({
|
|
|
13600
13738
|
companySpecificMetricsTable
|
|
13601
13739
|
});
|
|
13602
13740
|
if (!currentLineIdToUse || !supabase || !enabled || shiftLoading || isTimezoneLoading || companySpecificMetricsTable.includes("unknown_company")) {
|
|
13603
|
-
updateQueueRef.current = false;
|
|
13604
13741
|
if (!metrics2?.workspaceMetrics?.length && !metrics2?.lineMetrics?.length && !shiftLoading) setIsLoading(false);
|
|
13605
13742
|
if (companySpecificMetricsTable.includes("unknown_company") && !error) {
|
|
13606
13743
|
setError({ message: "Company ID not configured for metrics table.", code: "CONFIG_ERROR" });
|
|
@@ -13613,6 +13750,10 @@ var useDashboardMetrics = ({
|
|
|
13613
13750
|
const usesShiftGroups = isFactory && shiftGroups.length > 0;
|
|
13614
13751
|
const singleShiftDetails = usesShiftGroups ? null : shiftConfig ? getCurrentShift(defaultTimezone, shiftConfig) : shiftGroups.length === 1 ? { date: shiftGroups[0].date, shiftId: shiftGroups[0].shiftId } : getCurrentShift(defaultTimezone, staticShiftConfig);
|
|
13615
13752
|
const fetchKey = usesShiftGroups ? `factory|${companyId || "unknown"}|${shiftGroupsKey}` : isFactory ? `factory|${companyId || "unknown"}|${singleShiftDetails?.date}|${singleShiftDetails?.shiftId}|${targetLineIdsKey}` : `${currentLineIdToUse}|${companyId || "unknown"}|${singleShiftDetails?.date}|${singleShiftDetails?.shiftId}`;
|
|
13753
|
+
const responseScopeKey = buildMetricsScopeKey(
|
|
13754
|
+
currentLineIdToUse,
|
|
13755
|
+
isFactory ? targetLineIds : void 0
|
|
13756
|
+
);
|
|
13616
13757
|
logDebug("[useDashboardMetrics] Fetch key details:", {
|
|
13617
13758
|
isFactory,
|
|
13618
13759
|
usesShiftGroups,
|
|
@@ -13622,14 +13763,8 @@ var useDashboardMetrics = ({
|
|
|
13622
13763
|
singleShiftDetails,
|
|
13623
13764
|
fetchKey
|
|
13624
13765
|
});
|
|
13625
|
-
if (inFlightFetchKeyRef.current === fetchKey)
|
|
13626
|
-
|
|
13627
|
-
return;
|
|
13628
|
-
}
|
|
13629
|
-
if (!force && lastFetchKeyRef.current === fetchKey) {
|
|
13630
|
-
updateQueueRef.current = false;
|
|
13631
|
-
return;
|
|
13632
|
-
}
|
|
13766
|
+
if (inFlightFetchKeyRef.current === fetchKey) return;
|
|
13767
|
+
if (!force && lastFetchKeyRef.current === fetchKey) return;
|
|
13633
13768
|
const requestId = ++activeRequestIdRef.current;
|
|
13634
13769
|
const requestLineId = currentLineIdToUse;
|
|
13635
13770
|
isFetchingRef.current = true;
|
|
@@ -13652,6 +13787,7 @@ var useDashboardMetrics = ({
|
|
|
13652
13787
|
efficiencyLegend: DEFAULT_EFFICIENCY_LEGEND
|
|
13653
13788
|
});
|
|
13654
13789
|
setMetricsLineId(requestLineId);
|
|
13790
|
+
setMetricsScopeKey(responseScopeKey);
|
|
13655
13791
|
lastFetchKeyRef.current = inFlightFetchKeyRef.current;
|
|
13656
13792
|
return;
|
|
13657
13793
|
}
|
|
@@ -13761,89 +13897,16 @@ var useDashboardMetrics = ({
|
|
|
13761
13897
|
}
|
|
13762
13898
|
efficiencyLegend = parseEfficiencyLegend(backendData?.efficiency_legend) ?? DEFAULT_EFFICIENCY_LEGEND;
|
|
13763
13899
|
}
|
|
13764
|
-
const lineMetricsById = (allLineMetrics || []).reduce(
|
|
13765
|
-
(acc, line) => {
|
|
13766
|
-
const lineId2 = line?.line_id;
|
|
13767
|
-
if (lineId2) {
|
|
13768
|
-
acc[lineId2] = { total_workspaces: line?.total_workspaces };
|
|
13769
|
-
}
|
|
13770
|
-
return acc;
|
|
13771
|
-
},
|
|
13772
|
-
{}
|
|
13773
|
-
);
|
|
13774
13900
|
const detailTimezone = appTimezone || "Asia/Kolkata";
|
|
13775
|
-
|
|
13776
|
-
|
|
13777
|
-
|
|
13778
|
-
|
|
13779
|
-
|
|
13780
|
-
|
|
13781
|
-
|
|
13782
|
-
|
|
13783
|
-
|
|
13784
|
-
overrideShiftType: Boolean(lineShiftConfig)
|
|
13785
|
-
});
|
|
13786
|
-
if (detailedMetrics) {
|
|
13787
|
-
workspaceMetricsStore.setDetailed(detailedMetrics);
|
|
13788
|
-
}
|
|
13789
|
-
});
|
|
13790
|
-
const transformedWorkspaceData = allWorkspaceMetrics.map((item) => {
|
|
13791
|
-
const idleTimeValue = typeof item.idle_time === "number" ? item.idle_time : Number(item.idle_time);
|
|
13792
|
-
const idleTimeSeconds = Number.isFinite(idleTimeValue) ? idleTimeValue : void 0;
|
|
13793
|
-
const actionFamily = normalizeActionFamily({
|
|
13794
|
-
actionFamily: item.action_family,
|
|
13795
|
-
actionType: item.action_type,
|
|
13796
|
-
actionName: item.action_name
|
|
13797
|
-
});
|
|
13798
|
-
const actionType = actionFamily === "assembly" || actionFamily === "output" ? actionFamily : null;
|
|
13799
|
-
return {
|
|
13800
|
-
company_id: item.company_id || companyId,
|
|
13801
|
-
line_id: item.line_id,
|
|
13802
|
-
shift_id: item.shift_id,
|
|
13803
|
-
date: item.date,
|
|
13804
|
-
workspace_uuid: item.workspace_id,
|
|
13805
|
-
workspace_name: item.workspace_name,
|
|
13806
|
-
displayName: item.workspace_display_name || item.display_name || void 0,
|
|
13807
|
-
action_count: item.total_output || 0,
|
|
13808
|
-
pph: item.avg_pph || 0,
|
|
13809
|
-
performance_score: item.performance_score || 0,
|
|
13810
|
-
avg_cycle_time: item.avg_cycle_time || 0,
|
|
13811
|
-
trend: item.trend_score === 1 ? 2 : 0,
|
|
13812
|
-
predicted_output: item.ideal_output || 0,
|
|
13813
|
-
efficiency: item.efficiency || 0,
|
|
13814
|
-
action_threshold: item.total_day_output || 0,
|
|
13815
|
-
show_exclamation: item.show_exclamation ?? void 0,
|
|
13816
|
-
monitoring_mode: item.monitoring_mode ?? void 0,
|
|
13817
|
-
idle_time: idleTimeSeconds,
|
|
13818
|
-
assembly_enabled: item.assembly_enabled ?? false,
|
|
13819
|
-
video_grid_metric_mode: normalizeVideoGridMetricMode(
|
|
13820
|
-
item.video_grid_metric_mode,
|
|
13821
|
-
item.assembly_enabled ?? false
|
|
13822
|
-
),
|
|
13823
|
-
action_type: actionType,
|
|
13824
|
-
action_family: actionFamily,
|
|
13825
|
-
action_display_name: getActionDisplayName({
|
|
13826
|
-
displayName: item.action_display_name,
|
|
13827
|
-
actionFamily: item.action_family,
|
|
13828
|
-
actionType: item.action_type,
|
|
13829
|
-
actionName: item.action_name
|
|
13830
|
-
}),
|
|
13831
|
-
recent_flow_percent: item.recent_flow_percent ?? null,
|
|
13832
|
-
recent_flow_window_minutes: item.recent_flow_window_minutes ?? null,
|
|
13833
|
-
recent_flow_effective_end_at: item.recent_flow_effective_end_at ?? null,
|
|
13834
|
-
recent_flow_computed_at: item.recent_flow_computed_at ?? null,
|
|
13835
|
-
incoming_wip_current: item.incoming_wip_current ?? null,
|
|
13836
|
-
incoming_wip_effective_at: item.incoming_wip_effective_at ?? null,
|
|
13837
|
-
incoming_wip_buffer_name: item.incoming_wip_buffer_name ?? null
|
|
13838
|
-
};
|
|
13839
|
-
}).sort((a, b) => {
|
|
13840
|
-
if (a.line_id !== b.line_id) return a.line_id.localeCompare(b.line_id);
|
|
13841
|
-
const wsNumA = parseInt(a.workspace_name?.replace(/[^0-9]/g, "") || "0");
|
|
13842
|
-
const wsNumB = parseInt(b.workspace_name?.replace(/[^0-9]/g, "") || "0");
|
|
13843
|
-
return wsNumA - wsNumB;
|
|
13844
|
-
});
|
|
13845
|
-
transformedWorkspaceData.forEach((metric) => {
|
|
13846
|
-
workspaceMetricsStore.setOverview(metric);
|
|
13901
|
+
const transformedWorkspaceData = transformMonitorWorkspaceMetrics({
|
|
13902
|
+
rows: allWorkspaceMetrics,
|
|
13903
|
+
companyId: companyId || "",
|
|
13904
|
+
workspaceConfig: effectiveWorkspaceConfig,
|
|
13905
|
+
appTimezone: detailTimezone,
|
|
13906
|
+
lineMetrics: allLineMetrics,
|
|
13907
|
+
resolveShiftConfig: (metricLineId) => isFactoryView ? multiLineShiftConfigMap.get(metricLineId) || staticShiftConfig : shiftConfig || staticShiftConfig,
|
|
13908
|
+
shouldOverrideShiftType: (metricLineId) => isFactoryView ? Boolean(multiLineShiftConfigMap.get(metricLineId)) : Boolean(shiftConfig),
|
|
13909
|
+
fallbackShiftConfig: staticShiftConfig
|
|
13847
13910
|
});
|
|
13848
13911
|
const newMetricsState = {
|
|
13849
13912
|
workspaceMetrics: transformedWorkspaceData,
|
|
@@ -13861,6 +13924,7 @@ var useDashboardMetrics = ({
|
|
|
13861
13924
|
hydrateFromBackend(idleTimeVlmByLine);
|
|
13862
13925
|
setMetrics(newMetricsState);
|
|
13863
13926
|
setMetricsLineId(requestLineId);
|
|
13927
|
+
setMetricsScopeKey(responseScopeKey);
|
|
13864
13928
|
lastFetchKeyRef.current = inFlightFetchKeyRef.current;
|
|
13865
13929
|
} catch (err) {
|
|
13866
13930
|
if (abortController.signal.aborted || err?.name === "AbortError") {
|
|
@@ -13883,9 +13947,24 @@ var useDashboardMetrics = ({
|
|
|
13883
13947
|
if (requestId === activeRequestIdRef.current) {
|
|
13884
13948
|
setIsLoading(false);
|
|
13885
13949
|
isFetchingRef.current = false;
|
|
13886
|
-
updateQueueRef.current = false;
|
|
13887
13950
|
activeFetchLineIdRef.current = null;
|
|
13888
13951
|
inFlightFetchKeyRef.current = null;
|
|
13952
|
+
if (pendingRealtimeRefreshRef.current) {
|
|
13953
|
+
const elapsedSinceLastRealtimeRefresh = Date.now() - lastRealtimeRefreshStartedAtRef.current;
|
|
13954
|
+
const minIntervalRemaining = Math.max(0, REALTIME_REFRESH_MIN_INTERVAL_MS - elapsedSinceLastRealtimeRefresh);
|
|
13955
|
+
const nextDelay = Math.max(REALTIME_REFRESH_DEBOUNCE_MS, minIntervalRemaining);
|
|
13956
|
+
if (realtimeRefreshTimerRef.current === null) {
|
|
13957
|
+
realtimeRefreshTimerRef.current = window.setTimeout(() => {
|
|
13958
|
+
realtimeRefreshTimerRef.current = null;
|
|
13959
|
+
if (!pendingRealtimeRefreshRef.current || isFetchingRef.current || inFlightFetchKeyRef.current) {
|
|
13960
|
+
return;
|
|
13961
|
+
}
|
|
13962
|
+
pendingRealtimeRefreshRef.current = false;
|
|
13963
|
+
lastRealtimeRefreshStartedAtRef.current = Date.now();
|
|
13964
|
+
fetchAllMetricsRef.current({ force: true, reason: "subscription" });
|
|
13965
|
+
}, nextDelay);
|
|
13966
|
+
}
|
|
13967
|
+
}
|
|
13889
13968
|
}
|
|
13890
13969
|
}
|
|
13891
13970
|
}, [
|
|
@@ -13915,20 +13994,59 @@ var useDashboardMetrics = ({
|
|
|
13915
13994
|
useEffect(() => {
|
|
13916
13995
|
fetchAllMetricsRef.current = fetchAllMetrics;
|
|
13917
13996
|
}, [fetchAllMetrics]);
|
|
13918
|
-
const
|
|
13919
|
-
if (
|
|
13920
|
-
|
|
13921
|
-
|
|
13997
|
+
const clearRealtimeRefreshTimer = useCallback(() => {
|
|
13998
|
+
if (realtimeRefreshTimerRef.current !== null) {
|
|
13999
|
+
window.clearTimeout(realtimeRefreshTimerRef.current);
|
|
14000
|
+
realtimeRefreshTimerRef.current = null;
|
|
14001
|
+
}
|
|
14002
|
+
}, []);
|
|
14003
|
+
const scheduleRealtimeRefresh = useCallback(() => {
|
|
14004
|
+
if (!enabled || !supabase) {
|
|
14005
|
+
pendingRealtimeRefreshRef.current = false;
|
|
14006
|
+
clearRealtimeRefreshTimer();
|
|
14007
|
+
return;
|
|
14008
|
+
}
|
|
14009
|
+
if (!pendingRealtimeRefreshRef.current || realtimeRefreshTimerRef.current !== null) {
|
|
14010
|
+
return;
|
|
14011
|
+
}
|
|
14012
|
+
const elapsedSinceLastRealtimeRefresh = Date.now() - lastRealtimeRefreshStartedAtRef.current;
|
|
14013
|
+
const minIntervalRemaining = Math.max(0, REALTIME_REFRESH_MIN_INTERVAL_MS - elapsedSinceLastRealtimeRefresh);
|
|
14014
|
+
const nextDelay = Math.max(REALTIME_REFRESH_DEBOUNCE_MS, minIntervalRemaining);
|
|
14015
|
+
realtimeRefreshTimerRef.current = window.setTimeout(() => {
|
|
14016
|
+
realtimeRefreshTimerRef.current = null;
|
|
14017
|
+
if (!pendingRealtimeRefreshRef.current) {
|
|
14018
|
+
return;
|
|
14019
|
+
}
|
|
14020
|
+
if (isFetchingRef.current || inFlightFetchKeyRef.current) {
|
|
14021
|
+
scheduleRealtimeRefresh();
|
|
14022
|
+
return;
|
|
13922
14023
|
}
|
|
14024
|
+
pendingRealtimeRefreshRef.current = false;
|
|
14025
|
+
lastRealtimeRefreshStartedAtRef.current = Date.now();
|
|
14026
|
+
fetchAllMetricsRef.current({ force: true, reason: "subscription" });
|
|
14027
|
+
}, nextDelay);
|
|
14028
|
+
}, [clearRealtimeRefreshTimer, enabled, supabase]);
|
|
14029
|
+
useEffect(() => {
|
|
14030
|
+
return () => {
|
|
14031
|
+
clearRealtimeRefreshTimer();
|
|
14032
|
+
pendingRealtimeRefreshRef.current = false;
|
|
14033
|
+
};
|
|
14034
|
+
}, [clearRealtimeRefreshTimer]);
|
|
14035
|
+
const queueUpdate = useCallback(() => {
|
|
14036
|
+
if (!enabled) {
|
|
14037
|
+
logDebug("[useDashboardMetrics] queueUpdate skipped: metrics disabled");
|
|
14038
|
+
return;
|
|
14039
|
+
}
|
|
14040
|
+
if (!supabase) {
|
|
13923
14041
|
if (!supabase) {
|
|
13924
14042
|
logDebug("[useDashboardMetrics] queueUpdate skipped: supabase not ready");
|
|
13925
14043
|
}
|
|
13926
14044
|
return;
|
|
13927
14045
|
}
|
|
13928
|
-
|
|
13929
|
-
|
|
13930
|
-
|
|
13931
|
-
}, [
|
|
14046
|
+
pendingRealtimeRefreshRef.current = true;
|
|
14047
|
+
logDebug("[useDashboardMetrics] queueUpdate queued realtime refresh");
|
|
14048
|
+
scheduleRealtimeRefresh();
|
|
14049
|
+
}, [enabled, scheduleRealtimeRefresh, supabase]);
|
|
13932
14050
|
useEffect(() => {
|
|
13933
14051
|
if (enabled && lineId && supabase && !shiftLoading && !isTimezoneLoading) {
|
|
13934
14052
|
fetchAllMetrics({ reason: "line-change" });
|
|
@@ -14048,7 +14166,7 @@ var useDashboardMetrics = ({
|
|
|
14048
14166
|
{ event: "*", schema, table: companySpecificMetricsTable, filter: filter2 },
|
|
14049
14167
|
(payload) => {
|
|
14050
14168
|
const payloadData = payload.new || payload.old;
|
|
14051
|
-
|
|
14169
|
+
logDebug("[useDashboardMetrics] \u{1F4E1} WS_METRICS payload received:", {
|
|
14052
14170
|
eventType: payload.eventType,
|
|
14053
14171
|
lineId: payloadData?.line_id,
|
|
14054
14172
|
workspaceId: payloadData?.workspace_id,
|
|
@@ -14070,14 +14188,14 @@ var useDashboardMetrics = ({
|
|
|
14070
14188
|
shiftId: payloadData?.shift_id
|
|
14071
14189
|
});
|
|
14072
14190
|
if (payloadData?.date === group.date && payloadData?.shift_id === group.shiftId) {
|
|
14073
|
-
|
|
14191
|
+
logDebug("[useDashboardMetrics] \u2705 WS Date/shift match - triggering update");
|
|
14074
14192
|
queueUpdate();
|
|
14075
14193
|
} else {
|
|
14076
|
-
|
|
14194
|
+
logDebug("[useDashboardMetrics] \u274C WS Date/shift mismatch - update SKIPPED");
|
|
14077
14195
|
}
|
|
14078
14196
|
}
|
|
14079
14197
|
).subscribe((status) => {
|
|
14080
|
-
|
|
14198
|
+
logDebug("[useDashboardMetrics] \u{1F4F6} WS metrics subscription:", {
|
|
14081
14199
|
channel: wsChannelName,
|
|
14082
14200
|
status,
|
|
14083
14201
|
table: companySpecificMetricsTable,
|
|
@@ -14095,7 +14213,7 @@ var useDashboardMetrics = ({
|
|
|
14095
14213
|
{ event: "*", schema, table: configuredLineMetricsTable, filter: filter2 },
|
|
14096
14214
|
(payload) => {
|
|
14097
14215
|
const payloadData = payload.new || payload.old;
|
|
14098
|
-
|
|
14216
|
+
logDebug("[useDashboardMetrics] \u{1F4E1} LINE_METRICS payload received:", {
|
|
14099
14217
|
eventType: payload.eventType,
|
|
14100
14218
|
lineId: payloadData?.line_id,
|
|
14101
14219
|
date: payloadData?.date,
|
|
@@ -14115,15 +14233,15 @@ var useDashboardMetrics = ({
|
|
|
14115
14233
|
shiftId: payloadData?.shift_id
|
|
14116
14234
|
});
|
|
14117
14235
|
if (payloadData?.date === group.date && payloadData?.shift_id === group.shiftId) {
|
|
14118
|
-
|
|
14236
|
+
logDebug("[useDashboardMetrics] \u2705 Date/shift match - triggering update");
|
|
14119
14237
|
queueUpdate();
|
|
14120
14238
|
onLineMetricsUpdateRef.current?.();
|
|
14121
14239
|
} else {
|
|
14122
|
-
|
|
14240
|
+
logDebug("[useDashboardMetrics] \u274C Date/shift mismatch - update SKIPPED");
|
|
14123
14241
|
}
|
|
14124
14242
|
}
|
|
14125
14243
|
).subscribe((status) => {
|
|
14126
|
-
|
|
14244
|
+
logDebug("[useDashboardMetrics] \u{1F4F6} Line metrics subscription:", {
|
|
14127
14245
|
channel: lmChannelName,
|
|
14128
14246
|
status,
|
|
14129
14247
|
table: configuredLineMetricsTable,
|
|
@@ -14219,7 +14337,7 @@ var useDashboardMetrics = ({
|
|
|
14219
14337
|
{ event: "*", schema, table, filter: filter2 },
|
|
14220
14338
|
(payload) => {
|
|
14221
14339
|
const payloadData = payload.new || payload.old;
|
|
14222
|
-
|
|
14340
|
+
logDebug(`[useDashboardMetrics] \u{1F4E1} ${table.toUpperCase()} payload received (single-line):`, {
|
|
14223
14341
|
eventType: payload.eventType,
|
|
14224
14342
|
table: payload.table,
|
|
14225
14343
|
lineId: payloadData?.line_id,
|
|
@@ -14243,14 +14361,14 @@ var useDashboardMetrics = ({
|
|
|
14243
14361
|
shiftId: payloadData?.shift_id
|
|
14244
14362
|
});
|
|
14245
14363
|
if (payloadData?.date === operationalDateForSubscription && payloadData?.shift_id === currentShiftDetails.shiftId) {
|
|
14246
|
-
|
|
14364
|
+
logDebug(`[useDashboardMetrics] \u2705 ${table} Date/shift match - triggering update`);
|
|
14247
14365
|
callback();
|
|
14248
14366
|
} else {
|
|
14249
|
-
|
|
14367
|
+
logDebug(`[useDashboardMetrics] \u274C ${table} Date/shift mismatch - update SKIPPED`);
|
|
14250
14368
|
}
|
|
14251
14369
|
}
|
|
14252
14370
|
).subscribe((status) => {
|
|
14253
|
-
|
|
14371
|
+
logDebug(`[useDashboardMetrics] \u{1F4F6} ${table} subscription:`, {
|
|
14254
14372
|
channel: channelName,
|
|
14255
14373
|
status,
|
|
14256
14374
|
table,
|
|
@@ -14299,14 +14417,17 @@ var useDashboardMetrics = ({
|
|
|
14299
14417
|
lineId
|
|
14300
14418
|
// NOTE: userAccessibleLineIds removed - accessed via ref
|
|
14301
14419
|
]);
|
|
14302
|
-
const
|
|
14303
|
-
const
|
|
14420
|
+
const isCurrentScopeResolved = metricsScopeKey === requestedScopeKey;
|
|
14421
|
+
const hasLastGoodMetrics = metrics2.workspaceMetrics.length > 0 || metrics2.lineMetrics.length > 0;
|
|
14422
|
+
const canReuseLastGoodMetrics = hasLastGoodMetrics && !isCurrentScopeResolved && (isLoading || !!error);
|
|
14423
|
+
const safeMetrics = isCurrentScopeResolved || canReuseLastGoodMetrics ? metrics2 : { workspaceMetrics: [], lineMetrics: [], metadata: void 0, efficiencyLegend: DEFAULT_EFFICIENCY_LEGEND };
|
|
14304
14424
|
return {
|
|
14305
14425
|
workspaceMetrics: safeMetrics?.workspaceMetrics || [],
|
|
14306
14426
|
lineMetrics: safeMetrics?.lineMetrics || [],
|
|
14307
14427
|
efficiencyLegend: safeMetrics?.efficiencyLegend || DEFAULT_EFFICIENCY_LEGEND,
|
|
14308
14428
|
metadata: safeMetrics?.metadata,
|
|
14309
|
-
isLoading: enabled ? isLoading || !
|
|
14429
|
+
isLoading: enabled ? isLoading || !isCurrentScopeResolved && !canReuseLastGoodMetrics : false,
|
|
14430
|
+
isCurrentScopeResolved,
|
|
14310
14431
|
error,
|
|
14311
14432
|
refetch: () => {
|
|
14312
14433
|
if (!enabled) {
|
|
@@ -16754,6 +16875,7 @@ var isInitialized = false;
|
|
|
16754
16875
|
var isInitializing = false;
|
|
16755
16876
|
var initializedWithLineIds = [];
|
|
16756
16877
|
var missingLineContextWarnings = /* @__PURE__ */ new Set();
|
|
16878
|
+
var lineLoadPromises = /* @__PURE__ */ new Map();
|
|
16757
16879
|
var initializationPromise = null;
|
|
16758
16880
|
var workspaceDisplayNamesListeners = /* @__PURE__ */ new Set();
|
|
16759
16881
|
var notifyWorkspaceDisplayNamesListeners = (changedLineId) => {
|
|
@@ -16769,6 +16891,30 @@ var subscribeWorkspaceDisplayNames = (listener) => {
|
|
|
16769
16891
|
workspaceDisplayNamesListeners.add(listener);
|
|
16770
16892
|
return () => workspaceDisplayNamesListeners.delete(listener);
|
|
16771
16893
|
};
|
|
16894
|
+
var storeLineDisplayNames = (lineId, lineDisplayNamesMap) => {
|
|
16895
|
+
runtimeWorkspaceDisplayNames[lineId] = {};
|
|
16896
|
+
lineDisplayNamesMap.forEach((displayName, workspaceId) => {
|
|
16897
|
+
runtimeWorkspaceDisplayNames[lineId][workspaceId] = displayName;
|
|
16898
|
+
});
|
|
16899
|
+
};
|
|
16900
|
+
var ensureLineWorkspaceDisplayNamesLoaded = async (lineId) => {
|
|
16901
|
+
if (!lineId || runtimeWorkspaceDisplayNames[lineId]) {
|
|
16902
|
+
return;
|
|
16903
|
+
}
|
|
16904
|
+
const existingPromise = lineLoadPromises.get(lineId);
|
|
16905
|
+
if (existingPromise) {
|
|
16906
|
+
await existingPromise;
|
|
16907
|
+
return;
|
|
16908
|
+
}
|
|
16909
|
+
const loadPromise = workspaceService.getWorkspaceDisplayNames(void 0, lineId).then((lineDisplayNamesMap) => {
|
|
16910
|
+
storeLineDisplayNames(lineId, lineDisplayNamesMap);
|
|
16911
|
+
notifyWorkspaceDisplayNamesListeners(lineId);
|
|
16912
|
+
}).finally(() => {
|
|
16913
|
+
lineLoadPromises.delete(lineId);
|
|
16914
|
+
});
|
|
16915
|
+
lineLoadPromises.set(lineId, loadPromise);
|
|
16916
|
+
await loadPromise;
|
|
16917
|
+
};
|
|
16772
16918
|
var getAllWorkspaceDisplayNamesSnapshot = (lineId) => {
|
|
16773
16919
|
if (lineId && runtimeWorkspaceDisplayNames[lineId]) {
|
|
16774
16920
|
return { ...runtimeWorkspaceDisplayNames[lineId] };
|
|
@@ -16833,6 +16979,7 @@ async function initializeWorkspaceDisplayNames(explicitLineId) {
|
|
|
16833
16979
|
}
|
|
16834
16980
|
console.log("\u{1F504} Target line IDs for workspace filtering:", targetLineIds);
|
|
16835
16981
|
runtimeWorkspaceDisplayNames = {};
|
|
16982
|
+
lineLoadPromises.clear();
|
|
16836
16983
|
if (targetLineIds.length > 0) {
|
|
16837
16984
|
const results = await Promise.all(
|
|
16838
16985
|
targetLineIds.map(async (lineId) => {
|
|
@@ -16842,10 +16989,7 @@ async function initializeWorkspaceDisplayNames(explicitLineId) {
|
|
|
16842
16989
|
})
|
|
16843
16990
|
);
|
|
16844
16991
|
results.forEach(({ lineId, lineDisplayNamesMap }) => {
|
|
16845
|
-
|
|
16846
|
-
lineDisplayNamesMap.forEach((displayName, workspaceId) => {
|
|
16847
|
-
runtimeWorkspaceDisplayNames[lineId][workspaceId] = displayName;
|
|
16848
|
-
});
|
|
16992
|
+
storeLineDisplayNames(lineId, lineDisplayNamesMap);
|
|
16849
16993
|
console.log(`\u2705 Stored ${lineDisplayNamesMap.size} workspaces for line ${lineId}`);
|
|
16850
16994
|
});
|
|
16851
16995
|
} else {
|
|
@@ -16877,13 +17021,8 @@ var preInitializeWorkspaceDisplayNames = async (lineId) => {
|
|
|
16877
17021
|
if (lineId && !runtimeWorkspaceDisplayNames[lineId]) {
|
|
16878
17022
|
console.log(`\u{1F504} Line ${lineId} not in cache, fetching...`);
|
|
16879
17023
|
try {
|
|
16880
|
-
|
|
16881
|
-
|
|
16882
|
-
lineDisplayNamesMap.forEach((displayName, workspaceId) => {
|
|
16883
|
-
runtimeWorkspaceDisplayNames[lineId][workspaceId] = displayName;
|
|
16884
|
-
});
|
|
16885
|
-
console.log(`\u2705 Added ${lineDisplayNamesMap.size} workspaces for line ${lineId}`);
|
|
16886
|
-
notifyWorkspaceDisplayNamesListeners(lineId);
|
|
17024
|
+
await ensureLineWorkspaceDisplayNamesLoaded(lineId);
|
|
17025
|
+
console.log(`\u2705 Added workspaces for line ${lineId}`);
|
|
16887
17026
|
} catch (error) {
|
|
16888
17027
|
console.error(`\u274C Failed to fetch workspaces for line ${lineId}:`, error);
|
|
16889
17028
|
}
|
|
@@ -16896,13 +17035,8 @@ var preInitializeWorkspaceDisplayNames = async (lineId) => {
|
|
|
16896
17035
|
if (lineId && !runtimeWorkspaceDisplayNames[lineId]) {
|
|
16897
17036
|
console.log(`\u{1F504} Line ${lineId} not in cache after init, fetching...`);
|
|
16898
17037
|
try {
|
|
16899
|
-
|
|
16900
|
-
|
|
16901
|
-
lineDisplayNamesMap.forEach((displayName, workspaceId) => {
|
|
16902
|
-
runtimeWorkspaceDisplayNames[lineId][workspaceId] = displayName;
|
|
16903
|
-
});
|
|
16904
|
-
console.log(`\u2705 Added ${lineDisplayNamesMap.size} workspaces for line ${lineId}`);
|
|
16905
|
-
notifyWorkspaceDisplayNamesListeners(lineId);
|
|
17038
|
+
await ensureLineWorkspaceDisplayNamesLoaded(lineId);
|
|
17039
|
+
console.log(`\u2705 Added workspaces for line ${lineId}`);
|
|
16906
17040
|
} catch (error) {
|
|
16907
17041
|
console.error(`\u274C Failed to fetch workspaces for line ${lineId}:`, error);
|
|
16908
17042
|
}
|
|
@@ -16939,13 +17073,8 @@ var getWorkspaceDisplayName = (workspaceId, lineId) => {
|
|
|
16939
17073
|
}
|
|
16940
17074
|
if (isInitialized && lineId && !runtimeWorkspaceDisplayNames[lineId]) {
|
|
16941
17075
|
console.log(`\u{1F504} Line ${lineId} not in cache, fetching its workspaces...`);
|
|
16942
|
-
|
|
16943
|
-
|
|
16944
|
-
lineDisplayNamesMap.forEach((displayName2, workspaceId2) => {
|
|
16945
|
-
runtimeWorkspaceDisplayNames[lineId][workspaceId2] = displayName2;
|
|
16946
|
-
});
|
|
16947
|
-
console.log(`\u2705 Added ${lineDisplayNamesMap.size} workspaces for line ${lineId} to cache`);
|
|
16948
|
-
notifyWorkspaceDisplayNamesListeners(lineId);
|
|
17076
|
+
ensureLineWorkspaceDisplayNamesLoaded(lineId).then(() => {
|
|
17077
|
+
console.log(`\u2705 Added workspaces for line ${lineId} to cache`);
|
|
16949
17078
|
}).catch((error) => {
|
|
16950
17079
|
console.error(`\u274C Failed to fetch workspaces for line ${lineId}:`, error);
|
|
16951
17080
|
});
|
|
@@ -16987,13 +17116,8 @@ var getShortWorkspaceDisplayName = (workspaceId, lineId) => {
|
|
|
16987
17116
|
}
|
|
16988
17117
|
if (isInitialized && lineId && !runtimeWorkspaceDisplayNames[lineId]) {
|
|
16989
17118
|
console.log(`\u{1F504} Line ${lineId} not in cache, fetching its workspaces...`);
|
|
16990
|
-
|
|
16991
|
-
|
|
16992
|
-
lineDisplayNamesMap.forEach((displayName2, workspaceId2) => {
|
|
16993
|
-
runtimeWorkspaceDisplayNames[lineId][workspaceId2] = displayName2;
|
|
16994
|
-
});
|
|
16995
|
-
console.log(`\u2705 Added ${lineDisplayNamesMap.size} workspaces for line ${lineId} to cache`);
|
|
16996
|
-
notifyWorkspaceDisplayNamesListeners(lineId);
|
|
17119
|
+
ensureLineWorkspaceDisplayNamesLoaded(lineId).then(() => {
|
|
17120
|
+
console.log(`\u2705 Added workspaces for line ${lineId} to cache`);
|
|
16997
17121
|
}).catch((error) => {
|
|
16998
17122
|
console.error(`\u274C Failed to fetch workspaces for line ${lineId}:`, error);
|
|
16999
17123
|
});
|
|
@@ -17073,6 +17197,7 @@ var refreshWorkspaceDisplayNames = async (companyId) => {
|
|
|
17073
17197
|
workspaceService.clearWorkspaceDisplayNamesCache();
|
|
17074
17198
|
runtimeWorkspaceDisplayNames = {};
|
|
17075
17199
|
isInitialized = false;
|
|
17200
|
+
lineLoadPromises.clear();
|
|
17076
17201
|
await initializeWorkspaceDisplayNames();
|
|
17077
17202
|
notifyWorkspaceDisplayNamesListeners();
|
|
17078
17203
|
};
|
|
@@ -17082,6 +17207,7 @@ var clearWorkspaceDisplayNamesCache = () => {
|
|
|
17082
17207
|
isInitialized = false;
|
|
17083
17208
|
isInitializing = false;
|
|
17084
17209
|
initializedWithLineIds = [];
|
|
17210
|
+
lineLoadPromises.clear();
|
|
17085
17211
|
initializationPromise = null;
|
|
17086
17212
|
notifyWorkspaceDisplayNamesListeners();
|
|
17087
17213
|
};
|
|
@@ -17211,7 +17337,16 @@ var useWorkspaceDisplayNamesMap = (workspaceIds, lineId, companyId) => {
|
|
|
17211
17337
|
refetch: fetchDisplayNames
|
|
17212
17338
|
};
|
|
17213
17339
|
};
|
|
17214
|
-
var useWorkspaceVideoStreams = (workspaces) => {
|
|
17340
|
+
var useWorkspaceVideoStreams = (workspaces, options = {}) => {
|
|
17341
|
+
const explicitLineIdsKey = useMemo(() => {
|
|
17342
|
+
const ids = /* @__PURE__ */ new Set();
|
|
17343
|
+
for (const lineId of options.lineIds || []) {
|
|
17344
|
+
if (lineId) {
|
|
17345
|
+
ids.add(lineId);
|
|
17346
|
+
}
|
|
17347
|
+
}
|
|
17348
|
+
return Array.from(ids).sort().join(",");
|
|
17349
|
+
}, [options.lineIds]);
|
|
17215
17350
|
const workspaceIdsKey = useMemo(() => {
|
|
17216
17351
|
const ids = /* @__PURE__ */ new Set();
|
|
17217
17352
|
for (const workspace of workspaces) {
|
|
@@ -17221,7 +17356,7 @@ var useWorkspaceVideoStreams = (workspaces) => {
|
|
|
17221
17356
|
}
|
|
17222
17357
|
return Array.from(ids).sort().join(",");
|
|
17223
17358
|
}, [workspaces]);
|
|
17224
|
-
const
|
|
17359
|
+
const inferredLineIdsKey = useMemo(() => {
|
|
17225
17360
|
const ids = /* @__PURE__ */ new Set();
|
|
17226
17361
|
for (const workspace of workspaces) {
|
|
17227
17362
|
if (workspace.line_id) {
|
|
@@ -17230,18 +17365,19 @@ var useWorkspaceVideoStreams = (workspaces) => {
|
|
|
17230
17365
|
}
|
|
17231
17366
|
return Array.from(ids).sort().join(",");
|
|
17232
17367
|
}, [workspaces]);
|
|
17368
|
+
const lineIdsKey = explicitLineIdsKey || inferredLineIdsKey;
|
|
17233
17369
|
const requestKey = useMemo(() => {
|
|
17234
|
-
if (workspaceIdsKey) {
|
|
17235
|
-
return `workspaces:${workspaceIdsKey}`;
|
|
17236
|
-
}
|
|
17237
17370
|
if (lineIdsKey) {
|
|
17238
17371
|
return `lines:${lineIdsKey}`;
|
|
17239
17372
|
}
|
|
17373
|
+
if (workspaceIdsKey) {
|
|
17374
|
+
return `workspaces:${workspaceIdsKey}`;
|
|
17375
|
+
}
|
|
17240
17376
|
return "";
|
|
17241
17377
|
}, [workspaceIdsKey, lineIdsKey]);
|
|
17242
17378
|
const workspaceIds = useMemo(
|
|
17243
|
-
() => workspaceIdsKey ? workspaceIdsKey.split(",") : [],
|
|
17244
|
-
[workspaceIdsKey]
|
|
17379
|
+
() => lineIdsKey ? [] : workspaceIdsKey ? workspaceIdsKey.split(",") : [],
|
|
17380
|
+
[lineIdsKey, workspaceIdsKey]
|
|
17245
17381
|
);
|
|
17246
17382
|
const lineIds = useMemo(
|
|
17247
17383
|
() => lineIdsKey ? lineIdsKey.split(",") : [],
|
|
@@ -18785,6 +18921,7 @@ var useWorkspaceHealthLastSeen = (workspaceIds, options = {}) => {
|
|
|
18785
18921
|
const supabase = useSupabase();
|
|
18786
18922
|
const databaseConfig = useDatabaseConfig();
|
|
18787
18923
|
const refreshInterval = options.refreshInterval ?? DEFAULT_REFRESH_INTERVAL_MS;
|
|
18924
|
+
const enabled = options.enabled ?? true;
|
|
18788
18925
|
const workspaceIdsKey = useMemo(() => {
|
|
18789
18926
|
const ids = Array.from(new Set(workspaceIds.filter(Boolean)));
|
|
18790
18927
|
return ids.sort().join(",");
|
|
@@ -18795,7 +18932,7 @@ var useWorkspaceHealthLastSeen = (workspaceIds, options = {}) => {
|
|
|
18795
18932
|
const isFetchingRef = useRef(false);
|
|
18796
18933
|
const refreshIntervalRef = useRef(null);
|
|
18797
18934
|
const fetchLastSeen = useCallback(async () => {
|
|
18798
|
-
if (!supabase || !workspaceIdsKey || isFetchingRef.current) return;
|
|
18935
|
+
if (!enabled || !supabase || !workspaceIdsKey || isFetchingRef.current) return;
|
|
18799
18936
|
const healthTable = databaseConfig?.tables?.workspace_health || "workspace_health_status";
|
|
18800
18937
|
try {
|
|
18801
18938
|
isFetchingRef.current = true;
|
|
@@ -18827,12 +18964,18 @@ var useWorkspaceHealthLastSeen = (workspaceIds, options = {}) => {
|
|
|
18827
18964
|
setIsLoading(false);
|
|
18828
18965
|
isFetchingRef.current = false;
|
|
18829
18966
|
}
|
|
18830
|
-
}, [
|
|
18967
|
+
}, [databaseConfig?.tables?.workspace_health, enabled, supabase, workspaceIdsKey]);
|
|
18831
18968
|
useEffect(() => {
|
|
18969
|
+
if (!enabled) {
|
|
18970
|
+
setIsLoading(false);
|
|
18971
|
+
setError(null);
|
|
18972
|
+
setLastSeenByWorkspaceId({});
|
|
18973
|
+
return;
|
|
18974
|
+
}
|
|
18832
18975
|
fetchLastSeen();
|
|
18833
|
-
}, [fetchLastSeen]);
|
|
18976
|
+
}, [enabled, fetchLastSeen]);
|
|
18834
18977
|
useEffect(() => {
|
|
18835
|
-
if (!refreshInterval || !workspaceIdsKey) return;
|
|
18978
|
+
if (!enabled || !refreshInterval || !workspaceIdsKey) return;
|
|
18836
18979
|
refreshIntervalRef.current = setInterval(() => {
|
|
18837
18980
|
fetchLastSeen();
|
|
18838
18981
|
}, refreshInterval);
|
|
@@ -18842,7 +18985,7 @@ var useWorkspaceHealthLastSeen = (workspaceIds, options = {}) => {
|
|
|
18842
18985
|
refreshIntervalRef.current = null;
|
|
18843
18986
|
}
|
|
18844
18987
|
};
|
|
18845
|
-
}, [fetchLastSeen, refreshInterval, workspaceIdsKey]);
|
|
18988
|
+
}, [enabled, fetchLastSeen, refreshInterval, workspaceIdsKey]);
|
|
18846
18989
|
return {
|
|
18847
18990
|
lastSeenByWorkspaceId,
|
|
18848
18991
|
isLoading,
|
|
@@ -34675,7 +34818,7 @@ var VideoCard = React143__default.memo(({
|
|
|
34675
34818
|
});
|
|
34676
34819
|
const showOffline = Boolean(isStreamStale);
|
|
34677
34820
|
const lastSeenText = lastSeenLabel || "Unknown";
|
|
34678
|
-
const workspaceDisplayName = displayName ||
|
|
34821
|
+
const workspaceDisplayName = displayName || workspace.displayName || workspace.workspace_name;
|
|
34679
34822
|
const videoGridMetricValue = getVideoGridMetricValue(workspace);
|
|
34680
34823
|
const videoGridDisplayValue = getVideoGridDisplayValue(workspace, effectiveLegend, displayMinuteBucket);
|
|
34681
34824
|
const videoGridColorState = getVideoGridColorState(workspace, effectiveLegend);
|
|
@@ -34888,7 +35031,10 @@ var VideoGridView = React143__default.memo(({
|
|
|
34888
35031
|
}
|
|
34889
35032
|
return Array.from(ids);
|
|
34890
35033
|
}, [workspaces]);
|
|
34891
|
-
const
|
|
35034
|
+
const healthFetchEnabled = !videoStreamsLoading && workspaces.length > 0;
|
|
35035
|
+
const { lastSeenByWorkspaceId } = useWorkspaceHealthLastSeen(workspaceHealthIds, {
|
|
35036
|
+
enabled: healthFetchEnabled
|
|
35037
|
+
});
|
|
34892
35038
|
useEffect(() => {
|
|
34893
35039
|
const sample = workspaces.slice(0, 3).map((workspace) => ({
|
|
34894
35040
|
id: workspace.workspace_uuid || workspace.workspace_name,
|
|
@@ -34987,6 +35133,9 @@ var VideoGridView = React143__default.memo(({
|
|
|
34987
35133
|
}, [sortedWorkspaces, lineOrder, lineNames]);
|
|
34988
35134
|
lineGroups.length > 1;
|
|
34989
35135
|
const streamsReady = !videoStreamsLoading;
|
|
35136
|
+
const resolveWorkspaceDisplayName = useCallback((workspace) => {
|
|
35137
|
+
return workspace.displayName || displayNames[`${workspace.line_id}_${workspace.workspace_name}`] || workspace.workspace_name;
|
|
35138
|
+
}, [displayNames]);
|
|
34990
35139
|
const calculateOptimalGrid = useCallback(() => {
|
|
34991
35140
|
if (!containerRef.current) return;
|
|
34992
35141
|
const containerPadding = 16;
|
|
@@ -35117,11 +35266,11 @@ var VideoGridView = React143__default.memo(({
|
|
|
35117
35266
|
efficiency: workspace.efficiency,
|
|
35118
35267
|
action_count: workspace.action_count
|
|
35119
35268
|
});
|
|
35120
|
-
const displayName =
|
|
35269
|
+
const displayName = resolveWorkspaceDisplayName(workspace);
|
|
35121
35270
|
const currentPath = (router.asPath || "/").split("#")[0];
|
|
35122
35271
|
const navParams = getWorkspaceNavigationParams(workspaceId, displayName, workspace.line_id, currentPath);
|
|
35123
35272
|
router.push(`/workspace/${workspaceId}${navParams}`);
|
|
35124
|
-
}, [router, prewarmClipsInit]);
|
|
35273
|
+
}, [resolveWorkspaceDisplayName, router, prewarmClipsInit]);
|
|
35125
35274
|
const handleStreamError = useCallback((workspaceId, options) => {
|
|
35126
35275
|
const isR2Stream = options?.isR2Stream ?? false;
|
|
35127
35276
|
const hasFallback = Boolean(options?.fallbackUrl);
|
|
@@ -35230,7 +35379,7 @@ var VideoGridView = React143__default.memo(({
|
|
|
35230
35379
|
legend: effectiveLegend,
|
|
35231
35380
|
cropping: card.workspaceCropping,
|
|
35232
35381
|
canvasFps: effectiveCanvasFps,
|
|
35233
|
-
displayName:
|
|
35382
|
+
displayName: resolveWorkspaceDisplayName(card.workspace),
|
|
35234
35383
|
lastSeenLabel: card.lastSeenLabel,
|
|
35235
35384
|
useRAF: effectiveUseRAF,
|
|
35236
35385
|
displayMinuteBucket,
|
|
@@ -35242,16 +35391,15 @@ var VideoGridView = React143__default.memo(({
|
|
|
35242
35391
|
},
|
|
35243
35392
|
card.workspaceKey
|
|
35244
35393
|
), [
|
|
35245
|
-
displayNames,
|
|
35246
35394
|
displayMinuteBucket,
|
|
35247
35395
|
effectiveCanvasFps,
|
|
35248
35396
|
effectiveLegend,
|
|
35249
35397
|
effectiveUseRAF,
|
|
35250
|
-
getWorkspaceDisplayName,
|
|
35251
35398
|
handleStreamError,
|
|
35252
35399
|
handleWorkspaceClick,
|
|
35253
35400
|
onWorkspaceHover,
|
|
35254
35401
|
onWorkspaceHoverEnd,
|
|
35402
|
+
resolveWorkspaceDisplayName,
|
|
35255
35403
|
selectedLine
|
|
35256
35404
|
]);
|
|
35257
35405
|
return /* @__PURE__ */ jsx("div", { className: `relative overflow-hidden h-full w-full bg-slate-50/30 ${className}`, children: /* @__PURE__ */ jsx(
|
|
@@ -35337,6 +35485,9 @@ var MapGridView = React143__default.memo(({
|
|
|
35337
35485
|
prewarmInFlightRef.current.delete(workspaceId);
|
|
35338
35486
|
});
|
|
35339
35487
|
}, [dashboardConfig, timezone, supabase]);
|
|
35488
|
+
const resolveWorkspaceDisplayName = useCallback((workspace) => {
|
|
35489
|
+
return workspace.displayName || displayNames[`${workspace.line_id}_${workspace.workspace_name}`] || workspace.workspace_name;
|
|
35490
|
+
}, [displayNames]);
|
|
35340
35491
|
const handleWorkspaceClick = useCallback((workspace) => {
|
|
35341
35492
|
const workspaceId = workspace.workspace_uuid || workspace.workspace_name;
|
|
35342
35493
|
prewarmClipsInit(workspace);
|
|
@@ -35348,12 +35499,11 @@ var MapGridView = React143__default.memo(({
|
|
|
35348
35499
|
efficiency: workspace.efficiency,
|
|
35349
35500
|
action_count: workspace.action_count
|
|
35350
35501
|
});
|
|
35351
|
-
const displayName =
|
|
35352
|
-
getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
|
|
35502
|
+
const displayName = resolveWorkspaceDisplayName(workspace);
|
|
35353
35503
|
const currentPath = (router.asPath || "/").split("#")[0];
|
|
35354
35504
|
const navParams = getWorkspaceNavigationParams(workspaceId, displayName, workspace.line_id, currentPath);
|
|
35355
35505
|
router.push(`/workspace/${workspaceId}${navParams}`);
|
|
35356
|
-
}, [
|
|
35506
|
+
}, [resolveWorkspaceDisplayName, router, prewarmClipsInit]);
|
|
35357
35507
|
const activePositions = useMemo(() => {
|
|
35358
35508
|
return workspacePositions.filter((pos) => {
|
|
35359
35509
|
const wsKey = pos.id.toUpperCase();
|
|
@@ -35383,7 +35533,18 @@ var MapGridView = React143__default.memo(({
|
|
|
35383
35533
|
workspace_uuid: position.id,
|
|
35384
35534
|
// Use config ID as temporary UUID
|
|
35385
35535
|
line_id: "",
|
|
35536
|
+
// Empty line ID
|
|
35537
|
+
company_id: "",
|
|
35538
|
+
shift_id: 0,
|
|
35539
|
+
date: "",
|
|
35386
35540
|
efficiency: 0,
|
|
35541
|
+
performance_score: 0,
|
|
35542
|
+
action_count: 0,
|
|
35543
|
+
pph: 0,
|
|
35544
|
+
avg_cycle_time: 0,
|
|
35545
|
+
trend: 0,
|
|
35546
|
+
predicted_output: 0,
|
|
35547
|
+
action_threshold: 0,
|
|
35387
35548
|
show_exclamation: false
|
|
35388
35549
|
};
|
|
35389
35550
|
const workspaceId = effectiveWorkspace.workspace_uuid || effectiveWorkspace.workspace_name;
|
|
@@ -35392,7 +35553,7 @@ var MapGridView = React143__default.memo(({
|
|
|
35392
35553
|
const performanceColor = isInactivePlaceholder || isConveyorRow ? "bg-slate-200 border-slate-300 text-slate-500" : getPerformanceColor(effectiveWorkspace.efficiency);
|
|
35393
35554
|
!isInactivePlaceholder && !isConveyorRow && (effectiveWorkspace.show_exclamation ?? (effectiveWorkspace.efficiency < 50 && effectiveWorkspace.efficiency >= 10));
|
|
35394
35555
|
const configLabel = position.label;
|
|
35395
|
-
const workspaceDisplayName = configLabel || (isInactivePlaceholder ? "INACTIVE" :
|
|
35556
|
+
const workspaceDisplayName = configLabel || (isInactivePlaceholder ? "INACTIVE" : resolveWorkspaceDisplayName(effectiveWorkspace) || position.id);
|
|
35396
35557
|
return /* @__PURE__ */ jsx(
|
|
35397
35558
|
motion.div,
|
|
35398
35559
|
{
|
|
@@ -39359,9 +39520,12 @@ SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
|
|
|
39359
39520
|
var LoadingOverlay = ({
|
|
39360
39521
|
isVisible,
|
|
39361
39522
|
message = "Loading...",
|
|
39362
|
-
className
|
|
39523
|
+
className,
|
|
39524
|
+
contentClassName,
|
|
39525
|
+
contentVariant = "card"
|
|
39363
39526
|
}) => {
|
|
39364
39527
|
if (!isVisible) return null;
|
|
39528
|
+
const contentClasses = contentVariant === "plain" ? "flex flex-col items-center justify-center" : "flex flex-col items-center space-y-3 rounded-lg bg-white p-8 shadow-xl";
|
|
39365
39529
|
return /* @__PURE__ */ jsx(
|
|
39366
39530
|
motion.div,
|
|
39367
39531
|
{
|
|
@@ -39372,7 +39536,7 @@ var LoadingOverlay = ({
|
|
|
39372
39536
|
className: `fixed inset-0 z-[100] flex items-center justify-center bg-black/30 backdrop-blur-sm ${className || ""}`,
|
|
39373
39537
|
"aria-modal": "true",
|
|
39374
39538
|
role: "dialog",
|
|
39375
|
-
children: /* @__PURE__ */ jsx("div", { className:
|
|
39539
|
+
children: /* @__PURE__ */ jsx("div", { className: `${contentClasses} ${contentClassName || ""}`, children: /* @__PURE__ */ jsx(OptifyeLogoLoader_default, { size: "md", message }) })
|
|
39376
39540
|
}
|
|
39377
39541
|
);
|
|
39378
39542
|
};
|
|
@@ -60702,6 +60866,325 @@ var HelpView = ({
|
|
|
60702
60866
|
};
|
|
60703
60867
|
var AuthenticatedHelpView = withAuth(HelpView);
|
|
60704
60868
|
var HelpView_default = HelpView;
|
|
60869
|
+
var transformActiveBreaks = (activeBreaksByLine) => {
|
|
60870
|
+
if (!activeBreaksByLine) return [];
|
|
60871
|
+
return Object.values(activeBreaksByLine).flat().map((item) => ({
|
|
60872
|
+
lineId: item.line_id,
|
|
60873
|
+
shiftName: item.shift_name || "",
|
|
60874
|
+
startTime: item.start_time,
|
|
60875
|
+
endTime: item.end_time,
|
|
60876
|
+
duration: item.duration || 0,
|
|
60877
|
+
remarks: item.remarks || "",
|
|
60878
|
+
elapsedMinutes: item.elapsed_minutes || 0,
|
|
60879
|
+
remainingMinutes: item.remaining_minutes || 0
|
|
60880
|
+
})).sort((left, right) => {
|
|
60881
|
+
if (left.lineId !== right.lineId) return left.lineId.localeCompare(right.lineId);
|
|
60882
|
+
if (left.shiftName !== right.shiftName) return left.shiftName.localeCompare(right.shiftName);
|
|
60883
|
+
return left.startTime.localeCompare(right.startTime);
|
|
60884
|
+
});
|
|
60885
|
+
};
|
|
60886
|
+
var createEmptyState = () => ({
|
|
60887
|
+
requestKey: null,
|
|
60888
|
+
resolvedScope: [],
|
|
60889
|
+
scopeKey: null,
|
|
60890
|
+
lines: [],
|
|
60891
|
+
workspaceMetrics: [],
|
|
60892
|
+
lineMetrics: [],
|
|
60893
|
+
kpiTrend: null,
|
|
60894
|
+
activeBreaks: [],
|
|
60895
|
+
videoStreamsByWorkspaceId: {},
|
|
60896
|
+
efficiencyLegend: null,
|
|
60897
|
+
metadata: {}
|
|
60898
|
+
});
|
|
60899
|
+
var normalizeMetadata = (metadata) => ({
|
|
60900
|
+
hasFlowBuffers: Boolean(metadata?.has_flow_buffers),
|
|
60901
|
+
idleTimeVlmByLine: metadata?.idle_time_vlm_by_line ?? {},
|
|
60902
|
+
generatedAt: metadata?.generated_at,
|
|
60903
|
+
cacheStatus: metadata?.cache_status,
|
|
60904
|
+
warnings: metadata?.warnings ?? []
|
|
60905
|
+
});
|
|
60906
|
+
var useLiveMonitorBootstrap = ({
|
|
60907
|
+
lineIds,
|
|
60908
|
+
companyId,
|
|
60909
|
+
enabled = true,
|
|
60910
|
+
appTimezone,
|
|
60911
|
+
workspaceConfig,
|
|
60912
|
+
fallbackShiftConfig,
|
|
60913
|
+
lineShiftConfigs
|
|
60914
|
+
}) => {
|
|
60915
|
+
const supabase = useSupabase();
|
|
60916
|
+
const entityConfig = useEntityConfig();
|
|
60917
|
+
const { hydrateFromBackend } = useIdleTimeVlmConfig();
|
|
60918
|
+
const resolvedCompanyId = companyId || entityConfig?.companyId;
|
|
60919
|
+
const effectiveWorkspaceConfig = workspaceConfig || DEFAULT_WORKSPACE_CONFIG;
|
|
60920
|
+
const effectiveTimezone = appTimezone || "Asia/Kolkata";
|
|
60921
|
+
const rawLineIdsKey = (lineIds || []).filter(Boolean).join(",");
|
|
60922
|
+
const normalizedLineIds = useMemo(
|
|
60923
|
+
() => Array.from(new Set(rawLineIdsKey ? rawLineIdsKey.split(",") : [])),
|
|
60924
|
+
[rawLineIdsKey]
|
|
60925
|
+
);
|
|
60926
|
+
const requestKey = useMemo(
|
|
60927
|
+
() => normalizedLineIds.slice().sort().join(","),
|
|
60928
|
+
[normalizedLineIds]
|
|
60929
|
+
);
|
|
60930
|
+
const [state, setState] = useState(() => createEmptyState());
|
|
60931
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
60932
|
+
const [error, setError] = useState(null);
|
|
60933
|
+
const activeRequestIdRef = useRef(0);
|
|
60934
|
+
const fetchBootstrap = useCallback(async (force = false) => {
|
|
60935
|
+
if (!enabled || !supabase || !resolvedCompanyId || normalizedLineIds.length === 0) {
|
|
60936
|
+
return;
|
|
60937
|
+
}
|
|
60938
|
+
const requestId = ++activeRequestIdRef.current;
|
|
60939
|
+
setIsLoading(true);
|
|
60940
|
+
setError(null);
|
|
60941
|
+
try {
|
|
60942
|
+
const searchParams = new URLSearchParams();
|
|
60943
|
+
searchParams.set("company_id", resolvedCompanyId);
|
|
60944
|
+
searchParams.set("line_ids", normalizedLineIds.join(","));
|
|
60945
|
+
if (force) {
|
|
60946
|
+
searchParams.set("force_refresh", "true");
|
|
60947
|
+
}
|
|
60948
|
+
const response = await fetchBackendJson(
|
|
60949
|
+
supabase,
|
|
60950
|
+
`/api/dashboard/monitor-bootstrap?${searchParams.toString()}`,
|
|
60951
|
+
{
|
|
60952
|
+
method: "GET",
|
|
60953
|
+
timeoutMs: 2e4,
|
|
60954
|
+
retries: 0,
|
|
60955
|
+
dedupeKey: `monitor-bootstrap::${requestKey}::${force ? "force" : "cached"}`
|
|
60956
|
+
}
|
|
60957
|
+
);
|
|
60958
|
+
if (requestId !== activeRequestIdRef.current) {
|
|
60959
|
+
return;
|
|
60960
|
+
}
|
|
60961
|
+
const workspaceMetrics = transformMonitorWorkspaceMetrics({
|
|
60962
|
+
rows: response.workspace_metrics || [],
|
|
60963
|
+
companyId: resolvedCompanyId,
|
|
60964
|
+
workspaceConfig: effectiveWorkspaceConfig,
|
|
60965
|
+
appTimezone: effectiveTimezone,
|
|
60966
|
+
lineMetrics: response.line_metrics || [],
|
|
60967
|
+
resolveShiftConfig: (lineId) => lineShiftConfigs?.get(lineId) || fallbackShiftConfig,
|
|
60968
|
+
shouldOverrideShiftType: (lineId) => Boolean(lineShiftConfigs?.get(lineId)),
|
|
60969
|
+
fallbackShiftConfig
|
|
60970
|
+
});
|
|
60971
|
+
const activeBreaks = transformActiveBreaks(response.active_breaks_by_line);
|
|
60972
|
+
const metadata = normalizeMetadata(response.metadata);
|
|
60973
|
+
const workspaceIds = workspaceMetrics.map((metric) => metric.workspace_uuid).filter((workspaceId) => Boolean(workspaceId));
|
|
60974
|
+
const videoStreamsByWorkspaceId = response.video_streams_by_workspace_id || {};
|
|
60975
|
+
if (metadata.idleTimeVlmByLine) {
|
|
60976
|
+
hydrateFromBackend(metadata.idleTimeVlmByLine);
|
|
60977
|
+
}
|
|
60978
|
+
workspaceService.primeWorkspaceVideoStreamsCache({
|
|
60979
|
+
streams: videoStreamsByWorkspaceId,
|
|
60980
|
+
workspaceIds,
|
|
60981
|
+
lineIds: normalizedLineIds
|
|
60982
|
+
});
|
|
60983
|
+
setState({
|
|
60984
|
+
requestKey,
|
|
60985
|
+
resolvedScope: response.resolved_scope || [],
|
|
60986
|
+
scopeKey: response.scope_key || null,
|
|
60987
|
+
lines: response.lines || [],
|
|
60988
|
+
workspaceMetrics,
|
|
60989
|
+
lineMetrics: response.line_metrics || [],
|
|
60990
|
+
kpiTrend: response.kpi_trend || null,
|
|
60991
|
+
activeBreaks,
|
|
60992
|
+
videoStreamsByWorkspaceId,
|
|
60993
|
+
efficiencyLegend: response.efficiency_legend || null,
|
|
60994
|
+
metadata
|
|
60995
|
+
});
|
|
60996
|
+
} catch (fetchError) {
|
|
60997
|
+
if (requestId !== activeRequestIdRef.current) {
|
|
60998
|
+
return;
|
|
60999
|
+
}
|
|
61000
|
+
setError(fetchError instanceof Error ? fetchError : new Error("Failed to load live monitor bootstrap"));
|
|
61001
|
+
} finally {
|
|
61002
|
+
if (requestId === activeRequestIdRef.current) {
|
|
61003
|
+
setIsLoading(false);
|
|
61004
|
+
}
|
|
61005
|
+
}
|
|
61006
|
+
}, [
|
|
61007
|
+
enabled,
|
|
61008
|
+
supabase,
|
|
61009
|
+
resolvedCompanyId,
|
|
61010
|
+
normalizedLineIds,
|
|
61011
|
+
requestKey,
|
|
61012
|
+
hydrateFromBackend,
|
|
61013
|
+
effectiveWorkspaceConfig,
|
|
61014
|
+
effectiveTimezone,
|
|
61015
|
+
lineShiftConfigs,
|
|
61016
|
+
fallbackShiftConfig
|
|
61017
|
+
]);
|
|
61018
|
+
useEffect(() => {
|
|
61019
|
+
if (!enabled) {
|
|
61020
|
+
setIsLoading(false);
|
|
61021
|
+
return;
|
|
61022
|
+
}
|
|
61023
|
+
if (!resolvedCompanyId || normalizedLineIds.length === 0 || !supabase) {
|
|
61024
|
+
setState(createEmptyState());
|
|
61025
|
+
setIsLoading(false);
|
|
61026
|
+
setError(null);
|
|
61027
|
+
return;
|
|
61028
|
+
}
|
|
61029
|
+
void fetchBootstrap(false);
|
|
61030
|
+
}, [enabled, resolvedCompanyId, normalizedLineIds, supabase, fetchBootstrap]);
|
|
61031
|
+
useEffect(() => {
|
|
61032
|
+
if (!enabled || !resolvedCompanyId || normalizedLineIds.length === 0 || !supabase) {
|
|
61033
|
+
return void 0;
|
|
61034
|
+
}
|
|
61035
|
+
let intervalId = null;
|
|
61036
|
+
let timeoutId = null;
|
|
61037
|
+
const runMinuteTick = () => {
|
|
61038
|
+
void fetchBootstrap(true);
|
|
61039
|
+
};
|
|
61040
|
+
const startInterval = () => {
|
|
61041
|
+
runMinuteTick();
|
|
61042
|
+
intervalId = window.setInterval(runMinuteTick, 6e4);
|
|
61043
|
+
};
|
|
61044
|
+
const msUntilNextMinute = (() => {
|
|
61045
|
+
const remainder = Date.now() % 6e4;
|
|
61046
|
+
return remainder === 0 ? 6e4 : 6e4 - remainder;
|
|
61047
|
+
})();
|
|
61048
|
+
timeoutId = window.setTimeout(startInterval, msUntilNextMinute);
|
|
61049
|
+
return () => {
|
|
61050
|
+
if (timeoutId !== null) {
|
|
61051
|
+
window.clearTimeout(timeoutId);
|
|
61052
|
+
}
|
|
61053
|
+
if (intervalId !== null) {
|
|
61054
|
+
window.clearInterval(intervalId);
|
|
61055
|
+
}
|
|
61056
|
+
};
|
|
61057
|
+
}, [enabled, resolvedCompanyId, normalizedLineIds, supabase, fetchBootstrap]);
|
|
61058
|
+
const isCurrentScopeResolved = state.requestKey === requestKey;
|
|
61059
|
+
return {
|
|
61060
|
+
resolvedScope: state.resolvedScope,
|
|
61061
|
+
scopeKey: state.scopeKey,
|
|
61062
|
+
lines: state.lines,
|
|
61063
|
+
workspaceMetrics: state.workspaceMetrics,
|
|
61064
|
+
lineMetrics: state.lineMetrics,
|
|
61065
|
+
kpiTrend: state.kpiTrend,
|
|
61066
|
+
activeBreaks: state.activeBreaks,
|
|
61067
|
+
videoStreamsByWorkspaceId: state.videoStreamsByWorkspaceId,
|
|
61068
|
+
efficiencyLegend: state.efficiencyLegend,
|
|
61069
|
+
metadata: state.metadata,
|
|
61070
|
+
isLoading: enabled ? isLoading || !isCurrentScopeResolved : false,
|
|
61071
|
+
isCurrentScopeResolved,
|
|
61072
|
+
error,
|
|
61073
|
+
refetch: () => fetchBootstrap(true)
|
|
61074
|
+
};
|
|
61075
|
+
};
|
|
61076
|
+
|
|
61077
|
+
// src/lib/utils/liveMonitorBootstrap.ts
|
|
61078
|
+
var toNumber3 = (value) => {
|
|
61079
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
61080
|
+
if (typeof value === "string" && value.trim() !== "") {
|
|
61081
|
+
const parsed = Number(value);
|
|
61082
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
61083
|
+
}
|
|
61084
|
+
return 0;
|
|
61085
|
+
};
|
|
61086
|
+
var normalizeNullableNumber = (value) => {
|
|
61087
|
+
if (value === null || value === void 0 || value === "") return null;
|
|
61088
|
+
return toNumber3(value);
|
|
61089
|
+
};
|
|
61090
|
+
var getLiveMonitorBootstrapMode = () => {
|
|
61091
|
+
const rawMode = (process.env.NEXT_PUBLIC_MONITOR_BOOTSTRAP_MODE || "").trim().toLowerCase();
|
|
61092
|
+
if (rawMode === "legacy" || rawMode === "shadow" || rawMode === "bootstrap") {
|
|
61093
|
+
return rawMode;
|
|
61094
|
+
}
|
|
61095
|
+
return "bootstrap";
|
|
61096
|
+
};
|
|
61097
|
+
var normalizeMonitorShadowSnapshot = (input) => {
|
|
61098
|
+
const sortedSelectedLineIds = Array.from(new Set((input.selectedLineIds || []).filter(Boolean))).sort();
|
|
61099
|
+
const resolvedScope = (input.resolvedScope || []).filter((entry) => entry?.line_id && entry?.date && entry?.shift_id !== void 0 && entry?.shift_id !== null).map((entry) => ({
|
|
61100
|
+
line_id: entry.line_id,
|
|
61101
|
+
date: entry.date,
|
|
61102
|
+
shift_id: entry.shift_id
|
|
61103
|
+
})).sort((left, right) => {
|
|
61104
|
+
if (left.line_id !== right.line_id) return left.line_id.localeCompare(right.line_id);
|
|
61105
|
+
if (left.date !== right.date) return left.date.localeCompare(right.date);
|
|
61106
|
+
return left.shift_id - right.shift_id;
|
|
61107
|
+
});
|
|
61108
|
+
const lines = (input.lines || []).filter((entry) => entry?.line_id).map((entry) => ({
|
|
61109
|
+
line_id: entry.line_id,
|
|
61110
|
+
line_name: entry.line_name || "Unknown Line"
|
|
61111
|
+
})).sort((left, right) => left.line_id.localeCompare(right.line_id));
|
|
61112
|
+
const workspaces = (input.workspaces || []).map((workspace) => {
|
|
61113
|
+
const workspaceId = workspace.workspace_uuid || null;
|
|
61114
|
+
const stream = workspaceId ? input.videoStreamsByWorkspaceId?.[workspaceId] || null : null;
|
|
61115
|
+
return {
|
|
61116
|
+
workspace_id: workspaceId,
|
|
61117
|
+
line_id: workspace.line_id,
|
|
61118
|
+
workspace_name: workspace.workspace_name,
|
|
61119
|
+
display_name: workspace.displayName || null,
|
|
61120
|
+
efficiency: toNumber3(workspace.efficiency),
|
|
61121
|
+
trend: toNumber3(workspace.trend),
|
|
61122
|
+
show_exclamation: Boolean(workspace.show_exclamation),
|
|
61123
|
+
scheduled_break_active: Boolean(workspace.scheduled_break_active),
|
|
61124
|
+
action_count: toNumber3(workspace.action_count),
|
|
61125
|
+
action_threshold: toNumber3(workspace.action_threshold),
|
|
61126
|
+
predicted_output: toNumber3(workspace.predicted_output),
|
|
61127
|
+
avg_cycle_time: toNumber3(workspace.avg_cycle_time),
|
|
61128
|
+
pph: toNumber3(workspace.pph),
|
|
61129
|
+
recent_flow_percent: normalizeNullableNumber(workspace.recent_flow_percent),
|
|
61130
|
+
incoming_wip_current: normalizeNullableNumber(workspace.incoming_wip_current),
|
|
61131
|
+
video_stream: stream ? {
|
|
61132
|
+
workspace_id: stream.workspace_id,
|
|
61133
|
+
camera_uuid: stream.camera_uuid,
|
|
61134
|
+
stream_camera_uuid: stream.stream_camera_uuid,
|
|
61135
|
+
hls_url: stream.hls_url,
|
|
61136
|
+
crop: stream.crop
|
|
61137
|
+
} : null
|
|
61138
|
+
};
|
|
61139
|
+
}).sort((left, right) => {
|
|
61140
|
+
if (left.line_id !== right.line_id) return left.line_id.localeCompare(right.line_id);
|
|
61141
|
+
return left.workspace_name.localeCompare(right.workspace_name, void 0, { numeric: true });
|
|
61142
|
+
});
|
|
61143
|
+
const activeBreaks = (input.activeBreaks || []).map((activeBreak) => ({
|
|
61144
|
+
lineId: activeBreak.lineId,
|
|
61145
|
+
shiftName: activeBreak.shiftName,
|
|
61146
|
+
startTime: activeBreak.startTime,
|
|
61147
|
+
endTime: activeBreak.endTime,
|
|
61148
|
+
remainingMinutes: toNumber3(activeBreak.remainingMinutes)
|
|
61149
|
+
})).sort((left, right) => {
|
|
61150
|
+
if (left.lineId !== right.lineId) return left.lineId.localeCompare(right.lineId);
|
|
61151
|
+
if (left.shiftName !== right.shiftName) return left.shiftName.localeCompare(right.shiftName);
|
|
61152
|
+
return left.startTime.localeCompare(right.startTime);
|
|
61153
|
+
});
|
|
61154
|
+
return {
|
|
61155
|
+
selectedLineIds: sortedSelectedLineIds,
|
|
61156
|
+
resolvedScope,
|
|
61157
|
+
lines,
|
|
61158
|
+
workspaces,
|
|
61159
|
+
activeBreaks,
|
|
61160
|
+
kpis: input.kpis || null,
|
|
61161
|
+
kpiTrend: input.kpiTrend || null,
|
|
61162
|
+
efficiencyLegend: input.efficiencyLegend || null
|
|
61163
|
+
};
|
|
61164
|
+
};
|
|
61165
|
+
var diffMonitorShadowSnapshots = (legacySnapshot, bootstrapSnapshot) => {
|
|
61166
|
+
const mismatches = [];
|
|
61167
|
+
const compareSection = (section) => {
|
|
61168
|
+
const legacyValue = legacySnapshot[section];
|
|
61169
|
+
const bootstrapValue = bootstrapSnapshot[section];
|
|
61170
|
+
if (JSON.stringify(legacyValue) !== JSON.stringify(bootstrapValue)) {
|
|
61171
|
+
mismatches.push({
|
|
61172
|
+
section,
|
|
61173
|
+
legacy: legacyValue,
|
|
61174
|
+
bootstrap: bootstrapValue
|
|
61175
|
+
});
|
|
61176
|
+
}
|
|
61177
|
+
};
|
|
61178
|
+
compareSection("selectedLineIds");
|
|
61179
|
+
compareSection("resolvedScope");
|
|
61180
|
+
compareSection("lines");
|
|
61181
|
+
compareSection("workspaces");
|
|
61182
|
+
compareSection("activeBreaks");
|
|
61183
|
+
compareSection("kpis");
|
|
61184
|
+
compareSection("kpiTrend");
|
|
61185
|
+
compareSection("efficiencyLegend");
|
|
61186
|
+
return mismatches;
|
|
61187
|
+
};
|
|
60705
61188
|
|
|
60706
61189
|
// src/lib/services/notificationService.ts
|
|
60707
61190
|
var API_BASE_URL = process.env.NEXT_PUBLIC_BACKEND_URL;
|
|
@@ -60843,7 +61326,10 @@ var logDebug3 = (...args) => {
|
|
|
60843
61326
|
if (!DEBUG_DASHBOARD_LOGS3) return;
|
|
60844
61327
|
console.log(...args);
|
|
60845
61328
|
};
|
|
61329
|
+
var EMPTY_LINE_IDS = [];
|
|
61330
|
+
var EMPTY_WORKSPACES = [];
|
|
60846
61331
|
var LoadingPageCmp = LoadingPage_default;
|
|
61332
|
+
var LoadingOverlayCmp = LoadingOverlay_default;
|
|
60847
61333
|
function HomeView({
|
|
60848
61334
|
defaultLineId,
|
|
60849
61335
|
factoryViewId,
|
|
@@ -60991,6 +61477,7 @@ function HomeView({
|
|
|
60991
61477
|
return createNotificationService(supabaseClient);
|
|
60992
61478
|
}, [supabaseClient]);
|
|
60993
61479
|
const [bottleneckNotification, setBottleneckNotification] = useState(null);
|
|
61480
|
+
const showBottleneckNotificationRef = useRef(null);
|
|
60994
61481
|
const [bottleneckModalOpen, setBottleneckModalOpen] = useState(false);
|
|
60995
61482
|
const [bottleneckModalData, setBottleneckModalData] = useState(null);
|
|
60996
61483
|
const [diagnosisModalOpen, setDiagnosisModalOpen] = useState(false);
|
|
@@ -61001,6 +61488,11 @@ function HomeView({
|
|
|
61001
61488
|
dashboardConfig?.shiftConfig
|
|
61002
61489
|
);
|
|
61003
61490
|
const shouldEnableMetricsFetch = authStatus === "ready";
|
|
61491
|
+
const liveMonitorMode = useMemo(() => getLiveMonitorBootstrapMode(), []);
|
|
61492
|
+
const isLegacyMonitorMode = liveMonitorMode === "legacy";
|
|
61493
|
+
const isShadowMonitorMode = liveMonitorMode === "shadow";
|
|
61494
|
+
const isBootstrapMonitorMode = liveMonitorMode === "bootstrap";
|
|
61495
|
+
const lastShadowMismatchSignatureRef = useRef(null);
|
|
61004
61496
|
const handleLineMetricsUpdate = useCallback(() => {
|
|
61005
61497
|
if (trendRefreshTimerRef.current) {
|
|
61006
61498
|
window.clearTimeout(trendRefreshTimerRef.current);
|
|
@@ -61016,45 +61508,24 @@ function HomeView({
|
|
|
61016
61508
|
}
|
|
61017
61509
|
}, []);
|
|
61018
61510
|
const {
|
|
61019
|
-
workspaceMetrics,
|
|
61020
|
-
lineMetrics,
|
|
61021
|
-
efficiencyLegend,
|
|
61022
|
-
metadata:
|
|
61023
|
-
isLoading:
|
|
61024
|
-
|
|
61025
|
-
|
|
61511
|
+
workspaceMetrics: legacyWorkspaceMetrics,
|
|
61512
|
+
lineMetrics: legacyLineMetrics,
|
|
61513
|
+
efficiencyLegend: legacyEfficiencyLegend,
|
|
61514
|
+
metadata: legacyMetricsMetadata,
|
|
61515
|
+
isLoading: legacyMetricsLoading,
|
|
61516
|
+
isCurrentScopeResolved: legacyIsCurrentScopeResolved,
|
|
61517
|
+
error: legacyMetricsError,
|
|
61518
|
+
refetch: refetchLegacyMetrics
|
|
61026
61519
|
} = useDashboardMetrics({
|
|
61027
61520
|
lineId: metricsScopeLineId,
|
|
61028
61521
|
lineIds: selectedLineIds,
|
|
61029
61522
|
onLineMetricsUpdate: handleLineMetricsUpdate,
|
|
61030
61523
|
userAccessibleLineIds: visibleLineIds,
|
|
61031
|
-
|
|
61032
|
-
enabled: shouldEnableMetricsFetch
|
|
61524
|
+
enabled: shouldEnableMetricsFetch && !isBootstrapMonitorMode
|
|
61033
61525
|
});
|
|
61034
|
-
const
|
|
61035
|
-
|
|
61036
|
-
|
|
61037
|
-
if (!workspace.displayName) {
|
|
61038
|
-
return;
|
|
61039
|
-
}
|
|
61040
|
-
nextDisplayNames[`${workspace.line_id}_${workspace.workspace_name}`] = workspace.displayName;
|
|
61041
|
-
});
|
|
61042
|
-
return nextDisplayNames;
|
|
61043
|
-
}, [workspaceMetrics]);
|
|
61044
|
-
useEffect(() => {
|
|
61045
|
-
workspaceMetrics.forEach((workspace) => {
|
|
61046
|
-
if (!workspace.displayName) {
|
|
61047
|
-
return;
|
|
61048
|
-
}
|
|
61049
|
-
upsertWorkspaceDisplayNameInCache({
|
|
61050
|
-
lineId: workspace.line_id,
|
|
61051
|
-
workspaceId: workspace.workspace_name,
|
|
61052
|
-
displayName: workspace.displayName
|
|
61053
|
-
});
|
|
61054
|
-
});
|
|
61055
|
-
}, [workspaceMetrics]);
|
|
61056
|
-
const trendGroups = useMemo(() => {
|
|
61057
|
-
const lineMetricsRows = lineMetrics || [];
|
|
61526
|
+
const legacyTrendGroups = useMemo(() => {
|
|
61527
|
+
if (isBootstrapMonitorMode) return null;
|
|
61528
|
+
const lineMetricsRows = legacyLineMetrics || [];
|
|
61058
61529
|
if (!lineMetricsRows.length) return null;
|
|
61059
61530
|
if (selectedLineIds.length > 1) {
|
|
61060
61531
|
const rowsForLines = lineMetricsRows.filter((row2) => selectedLineIdSet.has(row2?.line_id));
|
|
@@ -61080,7 +61551,7 @@ function HomeView({
|
|
|
61080
61551
|
shiftId: group.shiftId
|
|
61081
61552
|
}));
|
|
61082
61553
|
}
|
|
61083
|
-
const row = lineMetricsRows.find((
|
|
61554
|
+
const row = lineMetricsRows.find((candidate) => candidate?.line_id === primarySelectedLineId);
|
|
61084
61555
|
if (!row?.date || row?.shift_id === void 0 || row?.shift_id === null) {
|
|
61085
61556
|
return null;
|
|
61086
61557
|
}
|
|
@@ -61089,69 +61560,119 @@ function HomeView({
|
|
|
61089
61560
|
date: row.date,
|
|
61090
61561
|
shiftId: row.shift_id
|
|
61091
61562
|
}];
|
|
61092
|
-
}, [
|
|
61093
|
-
const
|
|
61094
|
-
if (!
|
|
61563
|
+
}, [isBootstrapMonitorMode, legacyLineMetrics, primarySelectedLineId, selectedLineIdSet, selectedLineIds.length]);
|
|
61564
|
+
const legacyTrendOptions = useMemo(() => {
|
|
61565
|
+
if (isBootstrapMonitorMode || !legacyTrendGroups || !userCompanyId) return null;
|
|
61095
61566
|
return {
|
|
61096
|
-
groups:
|
|
61567
|
+
groups: legacyTrendGroups,
|
|
61097
61568
|
companyId: userCompanyId,
|
|
61098
61569
|
refreshKey: trendRefreshKey,
|
|
61099
61570
|
forceRefresh: trendRefreshKey > 0
|
|
61100
61571
|
};
|
|
61101
|
-
}, [
|
|
61102
|
-
const { trend:
|
|
61103
|
-
const
|
|
61572
|
+
}, [isBootstrapMonitorMode, legacyTrendGroups, userCompanyId, trendRefreshKey]);
|
|
61573
|
+
const { trend: legacyKpiTrend } = useKpiTrends(legacyTrendOptions);
|
|
61574
|
+
const bootstrapMonitor = useLiveMonitorBootstrap({
|
|
61575
|
+
lineIds: selectedLineIds,
|
|
61576
|
+
companyId: userCompanyId,
|
|
61577
|
+
enabled: shouldEnableMetricsFetch && !isLegacyMonitorMode,
|
|
61578
|
+
appTimezone: timezone,
|
|
61579
|
+
workspaceConfig: dashboardConfig?.workspaceConfig,
|
|
61580
|
+
fallbackShiftConfig: dashboardConfig?.shiftConfig,
|
|
61581
|
+
lineShiftConfigs
|
|
61582
|
+
});
|
|
61583
|
+
const currentWorkspaceMetrics = isBootstrapMonitorMode ? bootstrapMonitor.workspaceMetrics : legacyWorkspaceMetrics;
|
|
61584
|
+
const currentLineMetrics = isBootstrapMonitorMode ? bootstrapMonitor.lineMetrics : legacyLineMetrics;
|
|
61585
|
+
const currentEfficiencyLegend = isBootstrapMonitorMode ? bootstrapMonitor.efficiencyLegend : legacyEfficiencyLegend;
|
|
61586
|
+
const currentMetricsMetadata = isBootstrapMonitorMode ? bootstrapMonitor.metadata : legacyMetricsMetadata;
|
|
61587
|
+
const currentMetricsLoading = isBootstrapMonitorMode ? bootstrapMonitor.isLoading : legacyMetricsLoading;
|
|
61588
|
+
const currentIsCurrentScopeResolved = isBootstrapMonitorMode ? bootstrapMonitor.isCurrentScopeResolved : legacyIsCurrentScopeResolved;
|
|
61589
|
+
const currentMetricsError = isBootstrapMonitorMode ? bootstrapMonitor.error : legacyMetricsError;
|
|
61590
|
+
const currentRefetchMetrics = isBootstrapMonitorMode ? bootstrapMonitor.refetch : refetchLegacyMetrics;
|
|
61591
|
+
const metricsDisplayNames = useMemo(() => {
|
|
61592
|
+
const nextDisplayNames = {};
|
|
61593
|
+
currentWorkspaceMetrics.forEach((workspace) => {
|
|
61594
|
+
if (!workspace.displayName) {
|
|
61595
|
+
return;
|
|
61596
|
+
}
|
|
61597
|
+
nextDisplayNames[`${workspace.line_id}_${workspace.workspace_name}`] = workspace.displayName;
|
|
61598
|
+
});
|
|
61599
|
+
return nextDisplayNames;
|
|
61600
|
+
}, [currentWorkspaceMetrics]);
|
|
61104
61601
|
useEffect(() => {
|
|
61105
|
-
|
|
61602
|
+
currentWorkspaceMetrics.forEach((workspace) => {
|
|
61603
|
+
if (!workspace.displayName) {
|
|
61604
|
+
return;
|
|
61605
|
+
}
|
|
61606
|
+
upsertWorkspaceDisplayNameInCache({
|
|
61607
|
+
lineId: workspace.line_id,
|
|
61608
|
+
workspaceId: workspace.workspace_name,
|
|
61609
|
+
displayName: workspace.displayName
|
|
61610
|
+
});
|
|
61611
|
+
});
|
|
61612
|
+
}, [currentWorkspaceMetrics]);
|
|
61613
|
+
const hasFlowBuffers = Boolean(currentMetricsMetadata?.hasFlowBuffers);
|
|
61614
|
+
useEffect(() => {
|
|
61615
|
+
const sample = currentWorkspaceMetrics.slice(0, 3).map((workspace) => ({
|
|
61106
61616
|
id: workspace.workspace_uuid || workspace.workspace_name,
|
|
61107
61617
|
efficiency: workspace.efficiency,
|
|
61108
61618
|
trend: workspace.trend,
|
|
61109
61619
|
lineId: workspace.line_id
|
|
61110
61620
|
}));
|
|
61111
61621
|
logDebug3("[HomeView] workspaceMetrics update:", {
|
|
61112
|
-
count:
|
|
61113
|
-
isLoading:
|
|
61114
|
-
error:
|
|
61622
|
+
count: currentWorkspaceMetrics.length,
|
|
61623
|
+
isLoading: currentMetricsLoading,
|
|
61624
|
+
error: currentMetricsError?.message,
|
|
61115
61625
|
sample
|
|
61116
61626
|
});
|
|
61117
|
-
}, [
|
|
61118
|
-
const
|
|
61119
|
-
const lineMetricsRows =
|
|
61627
|
+
}, [currentWorkspaceMetrics, currentMetricsLoading, currentMetricsError]);
|
|
61628
|
+
const buildDisplayKpis = useCallback((sourceLineMetrics, sourceIsLoading, sourceKpiTrend) => {
|
|
61629
|
+
const lineMetricsRows = sourceLineMetrics || [];
|
|
61630
|
+
let baseKpis = null;
|
|
61120
61631
|
if (selectedLineIds.length > 1) {
|
|
61121
|
-
const rowsForSelectedLines = lineMetricsRows.filter((
|
|
61122
|
-
if (
|
|
61123
|
-
|
|
61124
|
-
}
|
|
61125
|
-
|
|
61126
|
-
|
|
61127
|
-
|
|
61128
|
-
|
|
61129
|
-
|
|
61130
|
-
|
|
61131
|
-
|
|
61132
|
-
|
|
61133
|
-
if (!
|
|
61134
|
-
|
|
61632
|
+
const rowsForSelectedLines = lineMetricsRows.filter((row) => selectedLineIdSet.has(row?.line_id));
|
|
61633
|
+
if (sourceIsLoading && rowsForSelectedLines.length === 0) return null;
|
|
61634
|
+
baseKpis = aggregateKPIsFromLineMetricsRows(rowsForSelectedLines);
|
|
61635
|
+
} else {
|
|
61636
|
+
const row = lineMetricsRows.find((candidate) => candidate?.line_id === primarySelectedLineId);
|
|
61637
|
+
if (!row) {
|
|
61638
|
+
if (sourceIsLoading) return null;
|
|
61639
|
+
baseKpis = buildKPIsFromLineMetricsRow(null);
|
|
61640
|
+
} else {
|
|
61641
|
+
baseKpis = buildKPIsFromLineMetricsRow(row);
|
|
61642
|
+
}
|
|
61643
|
+
}
|
|
61644
|
+
if (!baseKpis || !sourceKpiTrend) {
|
|
61645
|
+
return baseKpis;
|
|
61646
|
+
}
|
|
61135
61647
|
return {
|
|
61136
|
-
...
|
|
61648
|
+
...baseKpis,
|
|
61137
61649
|
efficiency: {
|
|
61138
|
-
...
|
|
61139
|
-
change:
|
|
61650
|
+
...baseKpis.efficiency,
|
|
61651
|
+
change: sourceKpiTrend.efficiency?.delta_pp ?? baseKpis.efficiency.change
|
|
61140
61652
|
},
|
|
61141
61653
|
outputProgress: {
|
|
61142
|
-
...
|
|
61143
|
-
change:
|
|
61654
|
+
...baseKpis.outputProgress,
|
|
61655
|
+
change: sourceKpiTrend.outputProgress?.delta_pp ?? baseKpis.outputProgress.change
|
|
61144
61656
|
},
|
|
61145
61657
|
underperformingWorkers: {
|
|
61146
|
-
...
|
|
61147
|
-
change:
|
|
61658
|
+
...baseKpis.underperformingWorkers,
|
|
61659
|
+
change: sourceKpiTrend.underperformingWorkers?.delta_count ?? baseKpis.underperformingWorkers.change
|
|
61148
61660
|
},
|
|
61149
61661
|
avgCycleTime: {
|
|
61150
|
-
...
|
|
61151
|
-
change:
|
|
61662
|
+
...baseKpis.avgCycleTime,
|
|
61663
|
+
change: sourceKpiTrend.avgCycleTime?.delta_seconds ?? baseKpis.avgCycleTime.change
|
|
61152
61664
|
}
|
|
61153
61665
|
};
|
|
61154
|
-
}, [
|
|
61666
|
+
}, [primarySelectedLineId, selectedLineIdSet, selectedLineIds.length]);
|
|
61667
|
+
const legacyKpisWithTrend = useMemo(
|
|
61668
|
+
() => buildDisplayKpis(legacyLineMetrics, legacyMetricsLoading, legacyKpiTrend),
|
|
61669
|
+
[buildDisplayKpis, legacyLineMetrics, legacyMetricsLoading, legacyKpiTrend]
|
|
61670
|
+
);
|
|
61671
|
+
const bootstrapKpisWithTrend = useMemo(
|
|
61672
|
+
() => buildDisplayKpis(bootstrapMonitor.lineMetrics, bootstrapMonitor.isLoading, bootstrapMonitor.kpiTrend),
|
|
61673
|
+
[buildDisplayKpis, bootstrapMonitor.lineMetrics, bootstrapMonitor.isLoading, bootstrapMonitor.kpiTrend]
|
|
61674
|
+
);
|
|
61675
|
+
const currentKpisWithTrend = isBootstrapMonitorMode ? bootstrapKpisWithTrend : legacyKpisWithTrend;
|
|
61155
61676
|
const selectedLineMeta = useMemo(
|
|
61156
61677
|
() => selectedLineIds.length === 1 ? dbLines.find((line) => line.id === primarySelectedLineId) : void 0,
|
|
61157
61678
|
[dbLines, primarySelectedLineId, selectedLineIds.length]
|
|
@@ -61160,40 +61681,121 @@ function HomeView({
|
|
|
61160
61681
|
const isUptimeMode = selectedMonitoringMode === "uptime";
|
|
61161
61682
|
const averageIdleTimeSeconds = useMemo(() => {
|
|
61162
61683
|
if (!isUptimeMode) return null;
|
|
61163
|
-
const targetWorkspaces =
|
|
61684
|
+
const targetWorkspaces = currentWorkspaceMetrics.filter((ws) => ws.line_id === primarySelectedLineId);
|
|
61164
61685
|
const idleValues = targetWorkspaces.map((ws) => ws.idle_time).filter((value) => Number.isFinite(value));
|
|
61165
61686
|
if (idleValues.length === 0) return 0;
|
|
61166
61687
|
const totalIdle = idleValues.reduce((sum, value) => sum + value, 0);
|
|
61167
61688
|
return totalIdle / idleValues.length;
|
|
61168
|
-
}, [isUptimeMode, primarySelectedLineId,
|
|
61689
|
+
}, [isUptimeMode, primarySelectedLineId, currentWorkspaceMetrics]);
|
|
61169
61690
|
const {
|
|
61170
|
-
activeBreaks:
|
|
61171
|
-
isLoading:
|
|
61172
|
-
error:
|
|
61173
|
-
} = useActiveBreaks(visibleLineIds);
|
|
61174
|
-
const
|
|
61691
|
+
activeBreaks: legacyAllActiveBreaks,
|
|
61692
|
+
isLoading: legacyBreaksLoading,
|
|
61693
|
+
error: legacyBreaksError
|
|
61694
|
+
} = useActiveBreaks(isBootstrapMonitorMode ? EMPTY_LINE_IDS : visibleLineIds);
|
|
61695
|
+
const legacyActiveBreaks = useMemo(() => {
|
|
61175
61696
|
if (isAllLinesSelection(selectedLineIds)) {
|
|
61176
|
-
return
|
|
61697
|
+
return legacyAllActiveBreaks;
|
|
61177
61698
|
}
|
|
61178
|
-
return
|
|
61179
|
-
}, [
|
|
61699
|
+
return legacyAllActiveBreaks.filter((breakItem) => selectedLineIdSet.has(breakItem.lineId));
|
|
61700
|
+
}, [legacyAllActiveBreaks, selectedLineIdSet, selectedLineIds]);
|
|
61701
|
+
const currentActiveBreaks = isBootstrapMonitorMode ? bootstrapMonitor.activeBreaks : legacyActiveBreaks;
|
|
61702
|
+
const currentBreaksLoading = isBootstrapMonitorMode ? bootstrapMonitor.isLoading : legacyBreaksLoading;
|
|
61703
|
+
const currentBreaksError = isBootstrapMonitorMode ? bootstrapMonitor.error?.message || null : legacyBreaksError;
|
|
61180
61704
|
const activeBreakLineIds = useMemo(
|
|
61181
|
-
() => new Set(
|
|
61182
|
-
[
|
|
61705
|
+
() => new Set(currentActiveBreaks.map((breakItem) => breakItem.lineId)),
|
|
61706
|
+
[currentActiveBreaks]
|
|
61183
61707
|
);
|
|
61184
61708
|
const workspaceMetricsWithBreakState = useMemo(
|
|
61185
|
-
() =>
|
|
61709
|
+
() => currentWorkspaceMetrics.map((workspace) => ({
|
|
61186
61710
|
...workspace,
|
|
61187
61711
|
scheduled_break_active: activeBreakLineIds.has(workspace.line_id)
|
|
61188
61712
|
})),
|
|
61189
|
-
[
|
|
61713
|
+
[currentWorkspaceMetrics, activeBreakLineIds]
|
|
61190
61714
|
);
|
|
61191
61715
|
const [breakNotificationsDismissed, setBreakNotificationsDismissed] = useState(false);
|
|
61192
61716
|
useEffect(() => {
|
|
61193
|
-
if (
|
|
61717
|
+
if (currentActiveBreaks.length > 0) {
|
|
61194
61718
|
setBreakNotificationsDismissed(false);
|
|
61195
61719
|
}
|
|
61196
|
-
}, [
|
|
61720
|
+
}, [currentActiveBreaks.length]);
|
|
61721
|
+
const {
|
|
61722
|
+
streamsByWorkspaceId: legacyVideoStreamsByWorkspaceId,
|
|
61723
|
+
isLoading: legacyVideoStreamsLoading
|
|
61724
|
+
} = useWorkspaceVideoStreams(isBootstrapMonitorMode ? EMPTY_WORKSPACES : legacyWorkspaceMetrics, {
|
|
61725
|
+
lineIds: isBootstrapMonitorMode ? EMPTY_LINE_IDS : selectedLineIds
|
|
61726
|
+
});
|
|
61727
|
+
const currentVideoStreamsByWorkspaceId = isBootstrapMonitorMode ? bootstrapMonitor.videoStreamsByWorkspaceId : legacyVideoStreamsByWorkspaceId;
|
|
61728
|
+
const currentVideoStreamsLoading = isBootstrapMonitorMode ? bootstrapMonitor.isLoading : legacyVideoStreamsLoading;
|
|
61729
|
+
useEffect(() => {
|
|
61730
|
+
if (!isShadowMonitorMode) {
|
|
61731
|
+
lastShadowMismatchSignatureRef.current = null;
|
|
61732
|
+
return;
|
|
61733
|
+
}
|
|
61734
|
+
if (!shouldEnableMetricsFetch || legacyMetricsLoading || !legacyIsCurrentScopeResolved || bootstrapMonitor.isLoading || !bootstrapMonitor.isCurrentScopeResolved) {
|
|
61735
|
+
return;
|
|
61736
|
+
}
|
|
61737
|
+
const legacySnapshot = normalizeMonitorShadowSnapshot({
|
|
61738
|
+
selectedLineIds,
|
|
61739
|
+
workspaces: workspaceMetricsWithBreakState,
|
|
61740
|
+
kpis: legacyKpisWithTrend,
|
|
61741
|
+
kpiTrend: legacyKpiTrend,
|
|
61742
|
+
activeBreaks: legacyActiveBreaks,
|
|
61743
|
+
videoStreamsByWorkspaceId: legacyVideoStreamsByWorkspaceId,
|
|
61744
|
+
efficiencyLegend: legacyEfficiencyLegend
|
|
61745
|
+
});
|
|
61746
|
+
const bootstrapSnapshot = normalizeMonitorShadowSnapshot({
|
|
61747
|
+
selectedLineIds,
|
|
61748
|
+
resolvedScope: bootstrapMonitor.resolvedScope,
|
|
61749
|
+
lines: bootstrapMonitor.lines,
|
|
61750
|
+
workspaces: bootstrapMonitor.workspaceMetrics.map((workspace) => ({
|
|
61751
|
+
...workspace,
|
|
61752
|
+
scheduled_break_active: bootstrapMonitor.activeBreaks.some((activeBreak) => activeBreak.lineId === workspace.line_id)
|
|
61753
|
+
})),
|
|
61754
|
+
kpis: bootstrapKpisWithTrend,
|
|
61755
|
+
kpiTrend: bootstrapMonitor.kpiTrend,
|
|
61756
|
+
activeBreaks: bootstrapMonitor.activeBreaks,
|
|
61757
|
+
videoStreamsByWorkspaceId: bootstrapMonitor.videoStreamsByWorkspaceId,
|
|
61758
|
+
efficiencyLegend: bootstrapMonitor.efficiencyLegend
|
|
61759
|
+
});
|
|
61760
|
+
const mismatches = diffMonitorShadowSnapshots(legacySnapshot, bootstrapSnapshot);
|
|
61761
|
+
const signature = JSON.stringify(mismatches);
|
|
61762
|
+
if (mismatches.length === 0) {
|
|
61763
|
+
lastShadowMismatchSignatureRef.current = null;
|
|
61764
|
+
return;
|
|
61765
|
+
}
|
|
61766
|
+
if (lastShadowMismatchSignatureRef.current === signature) {
|
|
61767
|
+
return;
|
|
61768
|
+
}
|
|
61769
|
+
lastShadowMismatchSignatureRef.current = signature;
|
|
61770
|
+
console.error("[HomeView][monitor-shadow-mismatch]", {
|
|
61771
|
+
selectedLineIds,
|
|
61772
|
+
mismatches,
|
|
61773
|
+
legacySnapshot,
|
|
61774
|
+
bootstrapSnapshot
|
|
61775
|
+
});
|
|
61776
|
+
}, [
|
|
61777
|
+
bootstrapKpisWithTrend,
|
|
61778
|
+
bootstrapMonitor.activeBreaks,
|
|
61779
|
+
bootstrapMonitor.efficiencyLegend,
|
|
61780
|
+
bootstrapMonitor.isCurrentScopeResolved,
|
|
61781
|
+
bootstrapMonitor.isLoading,
|
|
61782
|
+
bootstrapMonitor.kpiTrend,
|
|
61783
|
+
bootstrapMonitor.lines,
|
|
61784
|
+
bootstrapMonitor.resolvedScope,
|
|
61785
|
+
bootstrapMonitor.videoStreamsByWorkspaceId,
|
|
61786
|
+
bootstrapMonitor.workspaceMetrics,
|
|
61787
|
+
isShadowMonitorMode,
|
|
61788
|
+
legacyActiveBreaks,
|
|
61789
|
+
legacyEfficiencyLegend,
|
|
61790
|
+
legacyIsCurrentScopeResolved,
|
|
61791
|
+
legacyKpiTrend,
|
|
61792
|
+
legacyKpisWithTrend,
|
|
61793
|
+
legacyMetricsLoading,
|
|
61794
|
+
legacyVideoStreamsByWorkspaceId,
|
|
61795
|
+
selectedLineIds,
|
|
61796
|
+
shouldEnableMetricsFetch,
|
|
61797
|
+
workspaceMetricsWithBreakState
|
|
61798
|
+
]);
|
|
61197
61799
|
const showBottleneckNotification = useCallback(async (bottleneck) => {
|
|
61198
61800
|
try {
|
|
61199
61801
|
logDebug3("\u{1F514} [Notification] Raw bottleneck data:", bottleneck);
|
|
@@ -61371,6 +61973,9 @@ function HomeView({
|
|
|
61371
61973
|
setBottleneckNotification(errorNotification);
|
|
61372
61974
|
}
|
|
61373
61975
|
}, [notificationService, timezone, dashboardConfig, lineShiftConfigs]);
|
|
61976
|
+
useEffect(() => {
|
|
61977
|
+
showBottleneckNotificationRef.current = showBottleneckNotification;
|
|
61978
|
+
}, [showBottleneckNotification]);
|
|
61374
61979
|
useEffect(() => {
|
|
61375
61980
|
const ticketsEnabled = dashboardConfig?.ticketsConfig?.enabled ?? true;
|
|
61376
61981
|
if (!ticketsEnabled) {
|
|
@@ -61440,7 +62045,7 @@ function HomeView({
|
|
|
61440
62045
|
});
|
|
61441
62046
|
if (latestTicket.event_type === "bottleneck") {
|
|
61442
62047
|
logDebug3("\u{1F514} [Polling] Showing bottleneck notification for:", latestTicket.log_number);
|
|
61443
|
-
|
|
62048
|
+
await showBottleneckNotificationRef.current?.(latestTicket);
|
|
61444
62049
|
} else {
|
|
61445
62050
|
logDebug3("\u26A0\uFE0F [Polling] Non-bottleneck ticket found but no handler configured:", latestTicket.event_type);
|
|
61446
62051
|
}
|
|
@@ -61460,29 +62065,30 @@ function HomeView({
|
|
|
61460
62065
|
clearInterval(pollInterval);
|
|
61461
62066
|
clearTimeout(initialPollTimer);
|
|
61462
62067
|
};
|
|
61463
|
-
}, [
|
|
62068
|
+
}, [
|
|
62069
|
+
dashboardConfig?.ticketsConfig?.enabled,
|
|
62070
|
+
notificationService,
|
|
62071
|
+
user?.email,
|
|
62072
|
+
user?.role_level,
|
|
62073
|
+
userCompanyId
|
|
62074
|
+
]);
|
|
61464
62075
|
const handleWorkspaceHover = useCallback((workspaceId) => {
|
|
61465
62076
|
}, []);
|
|
61466
62077
|
const handleWorkspaceHoverEnd = useCallback((workspaceId) => {
|
|
61467
62078
|
}, []);
|
|
61468
|
-
const
|
|
61469
|
-
streamsByWorkspaceId: videoStreamsByWorkspaceId,
|
|
61470
|
-
isLoading: videoStreamsLoading
|
|
61471
|
-
} = useWorkspaceVideoStreams(workspaceMetrics);
|
|
61472
|
-
const memoizedKPIs = useMemo(() => kpisWithTrend, [
|
|
62079
|
+
const memoizedKPIs = useMemo(() => currentKpisWithTrend, [
|
|
61473
62080
|
// Only update reference when values change by at least 1%
|
|
61474
|
-
|
|
61475
|
-
|
|
61476
|
-
|
|
61477
|
-
|
|
61478
|
-
|
|
61479
|
-
|
|
61480
|
-
|
|
61481
|
-
|
|
61482
|
-
|
|
61483
|
-
|
|
61484
|
-
|
|
61485
|
-
kpisWithTrend?.qualityCompliance?.value ? Math.round(kpisWithTrend.qualityCompliance.value) : null,
|
|
62081
|
+
currentKpisWithTrend?.efficiency?.value ? Math.round(currentKpisWithTrend.efficiency.value) : null,
|
|
62082
|
+
currentKpisWithTrend?.efficiency?.change,
|
|
62083
|
+
currentKpisWithTrend?.underperformingWorkers?.current,
|
|
62084
|
+
currentKpisWithTrend?.underperformingWorkers?.total,
|
|
62085
|
+
currentKpisWithTrend?.underperformingWorkers?.change,
|
|
62086
|
+
currentKpisWithTrend?.outputProgress?.current,
|
|
62087
|
+
currentKpisWithTrend?.outputProgress?.target,
|
|
62088
|
+
currentKpisWithTrend?.outputProgress?.change,
|
|
62089
|
+
currentKpisWithTrend?.avgCycleTime?.value ? Math.round(currentKpisWithTrend.avgCycleTime.value * 10) / 10 : null,
|
|
62090
|
+
currentKpisWithTrend?.avgCycleTime?.change,
|
|
62091
|
+
currentKpisWithTrend?.qualityCompliance?.value ? Math.round(currentKpisWithTrend.qualityCompliance.value) : null,
|
|
61486
62092
|
selectedLineIdsKey
|
|
61487
62093
|
]);
|
|
61488
62094
|
useEffect(() => {
|
|
@@ -61493,13 +62099,13 @@ function HomeView({
|
|
|
61493
62099
|
dashboard_surface: "monitor"
|
|
61494
62100
|
});
|
|
61495
62101
|
}, []);
|
|
61496
|
-
const metricsErrorMessage =
|
|
62102
|
+
const metricsErrorMessage = currentMetricsError?.message || null;
|
|
61497
62103
|
const handleRetryDashboardData = useCallback(async () => {
|
|
61498
62104
|
if (isRecoveringSession) {
|
|
61499
62105
|
await retrySessionHydration();
|
|
61500
62106
|
}
|
|
61501
|
-
|
|
61502
|
-
}, [
|
|
62107
|
+
await currentRefetchMetrics();
|
|
62108
|
+
}, [currentRefetchMetrics, isRecoveringSession, retrySessionHydration]);
|
|
61503
62109
|
const getTrackedLineScope = useCallback((lineIdsForScope) => {
|
|
61504
62110
|
if (isAllLinesSelection(lineIdsForScope)) {
|
|
61505
62111
|
return factoryViewId;
|
|
@@ -61552,12 +62158,15 @@ function HomeView({
|
|
|
61552
62158
|
updateSelectedLineIds(Array.from(currentSelection));
|
|
61553
62159
|
}, [selectedLineIds, updateSelectedLineIds]);
|
|
61554
62160
|
useEffect(() => {
|
|
61555
|
-
if (!
|
|
62161
|
+
if (!isChangingFilter) {
|
|
62162
|
+
return;
|
|
62163
|
+
}
|
|
62164
|
+
if (!currentMetricsLoading && currentIsCurrentScopeResolved || currentMetricsError) {
|
|
61556
62165
|
setIsChangingFilter(false);
|
|
61557
62166
|
}
|
|
61558
|
-
}, [
|
|
62167
|
+
}, [currentIsCurrentScopeResolved, currentMetricsError, currentMetricsLoading, isChangingFilter]);
|
|
61559
62168
|
useEffect(() => {
|
|
61560
|
-
if (shouldEnableMetricsFetch && !
|
|
62169
|
+
if (shouldEnableMetricsFetch && !currentMetricsLoading && !currentMetricsError && !hasInitialDataLoaded) {
|
|
61561
62170
|
setHasInitialDataLoaded(true);
|
|
61562
62171
|
trackCoreEvent("monitor page loaded", {
|
|
61563
62172
|
default_line_id: defaultLineId,
|
|
@@ -61566,7 +62175,7 @@ function HomeView({
|
|
|
61566
62175
|
dashboard_surface: "monitor"
|
|
61567
62176
|
});
|
|
61568
62177
|
}
|
|
61569
|
-
}, [shouldEnableMetricsFetch,
|
|
62178
|
+
}, [shouldEnableMetricsFetch, currentMetricsLoading, currentMetricsError, hasInitialDataLoaded, defaultLineId, factoryViewId, isSupervisor]);
|
|
61570
62179
|
const lineTitle = useMemo(() => {
|
|
61571
62180
|
return factoryName;
|
|
61572
62181
|
}, [factoryName]);
|
|
@@ -61717,15 +62326,15 @@ function HomeView({
|
|
|
61717
62326
|
return showLoading;
|
|
61718
62327
|
};
|
|
61719
62328
|
const isAuthBootstrapping = authStatus === "loading";
|
|
61720
|
-
const isInitialLoading = !isHydrated || !hasInitialDataLoaded && (isAuthBootstrapping || shouldEnableMetricsFetch &&
|
|
61721
|
-
const isDataLoading =
|
|
62329
|
+
const isInitialLoading = !isHydrated || !hasInitialDataLoaded && (isAuthBootstrapping || shouldEnableMetricsFetch && currentMetricsLoading);
|
|
62330
|
+
const isDataLoading = currentMetricsLoading;
|
|
61722
62331
|
const hasKpiDataReady = useMemo(() => {
|
|
61723
|
-
const lineMetricsRows =
|
|
62332
|
+
const lineMetricsRows = currentLineMetrics || [];
|
|
61724
62333
|
if (selectedLineIds.length > 1) {
|
|
61725
62334
|
return lineMetricsRows.some((row) => selectedLineIdSet.has(row?.line_id));
|
|
61726
62335
|
}
|
|
61727
62336
|
return lineMetricsRows.some((row) => row?.line_id === primarySelectedLineId);
|
|
61728
|
-
}, [
|
|
62337
|
+
}, [currentLineMetrics, primarySelectedLineId, selectedLineIdSet, selectedLineIds.length]);
|
|
61729
62338
|
const isKpiLoading = !hasKpiDataReady;
|
|
61730
62339
|
const shouldShowReconnectScreen = !hasInitialDataLoaded && (isRecoveringSession || !shouldEnableMetricsFetch && authStatus !== "failed" || !!metricsErrorMessage && authStatus !== "failed");
|
|
61731
62340
|
const shouldShowFatalLoadFailure = !hasInitialDataLoaded && !!metricsErrorMessage && authStatus === "failed";
|
|
@@ -61753,6 +62362,7 @@ function HomeView({
|
|
|
61753
62362
|
return () => clearTimeout(timer);
|
|
61754
62363
|
}, [isDataLoading]);
|
|
61755
62364
|
const shouldShowDataLoading = showDataLoading || isDataLoading;
|
|
62365
|
+
const shouldShowFilterChangeLoader = isChangingFilter && !currentIsCurrentScopeResolved;
|
|
61756
62366
|
const shouldShowKpiLoading = useSmoothLoading(isKpiLoading, 400);
|
|
61757
62367
|
const displayKpis = shouldShowKpiLoading ? null : memoizedKPIs;
|
|
61758
62368
|
const kpiSectionControl = useMemo(() => /* @__PURE__ */ jsx(
|
|
@@ -61837,7 +62447,7 @@ function HomeView({
|
|
|
61837
62447
|
}
|
|
61838
62448
|
)
|
|
61839
62449
|
] }) }) : null,
|
|
61840
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto sm:overflow-hidden relative flex flex-col", children: /* @__PURE__ */ jsx("div", { className: "flex-1 min-h-[calc(100vh-100px)] sm:min-h-0", children: workspaceMetricsWithBreakState.length > 0 ? /* @__PURE__ */ jsx(
|
|
62450
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto sm:overflow-hidden relative flex flex-col", children: /* @__PURE__ */ jsx("div", { className: "relative flex-1 min-h-[calc(100vh-100px)] sm:min-h-0", children: workspaceMetricsWithBreakState.length > 0 ? /* @__PURE__ */ jsx(
|
|
61841
62451
|
motion.div,
|
|
61842
62452
|
{
|
|
61843
62453
|
initial: { opacity: 0, scale: 0.98 },
|
|
@@ -61849,10 +62459,10 @@ function HomeView({
|
|
|
61849
62459
|
lineNames: mergedLineNames,
|
|
61850
62460
|
lineOrder: selectedLineIds,
|
|
61851
62461
|
factoryView: factoryViewId,
|
|
61852
|
-
legend:
|
|
62462
|
+
legend: currentEfficiencyLegend,
|
|
61853
62463
|
videoSources,
|
|
61854
|
-
videoStreamsByWorkspaceId,
|
|
61855
|
-
videoStreamsLoading,
|
|
62464
|
+
videoStreamsByWorkspaceId: currentVideoStreamsByWorkspaceId,
|
|
62465
|
+
videoStreamsLoading: currentVideoStreamsLoading,
|
|
61856
62466
|
displayNames: metricsDisplayNames,
|
|
61857
62467
|
hasFlowBuffers,
|
|
61858
62468
|
className: "h-full",
|
|
@@ -61860,8 +62470,7 @@ function HomeView({
|
|
|
61860
62470
|
onWorkspaceHover: handleWorkspaceHover,
|
|
61861
62471
|
onWorkspaceHoverEnd: handleWorkspaceHoverEnd
|
|
61862
62472
|
})
|
|
61863
|
-
}
|
|
61864
|
-
selectedLineIdsKey
|
|
62473
|
+
}
|
|
61865
62474
|
) : !shouldShowDataLoading && hasInitialDataLoaded ? /* @__PURE__ */ jsx(
|
|
61866
62475
|
motion.div,
|
|
61867
62476
|
{
|
|
@@ -61883,10 +62492,10 @@ function HomeView({
|
|
|
61883
62492
|
lineNames: mergedLineNames,
|
|
61884
62493
|
lineOrder: selectedLineIds,
|
|
61885
62494
|
factoryView: factoryViewId,
|
|
61886
|
-
legend:
|
|
62495
|
+
legend: currentEfficiencyLegend,
|
|
61887
62496
|
videoSources,
|
|
61888
|
-
videoStreamsByWorkspaceId,
|
|
61889
|
-
videoStreamsLoading,
|
|
62497
|
+
videoStreamsByWorkspaceId: currentVideoStreamsByWorkspaceId,
|
|
62498
|
+
videoStreamsLoading: currentVideoStreamsLoading,
|
|
61890
62499
|
displayNames: metricsDisplayNames,
|
|
61891
62500
|
hasFlowBuffers,
|
|
61892
62501
|
className: "h-full",
|
|
@@ -61894,16 +62503,15 @@ function HomeView({
|
|
|
61894
62503
|
onWorkspaceHover: handleWorkspaceHover,
|
|
61895
62504
|
onWorkspaceHoverEnd: handleWorkspaceHoverEnd
|
|
61896
62505
|
})
|
|
61897
|
-
}
|
|
61898
|
-
selectedLineIdsKey
|
|
62506
|
+
}
|
|
61899
62507
|
) }) })
|
|
61900
62508
|
] }),
|
|
61901
62509
|
/* @__PURE__ */ jsx(
|
|
61902
62510
|
BreakNotificationPopup,
|
|
61903
62511
|
{
|
|
61904
|
-
activeBreaks,
|
|
62512
|
+
activeBreaks: currentActiveBreaks,
|
|
61905
62513
|
lineNames: mergedLineNames,
|
|
61906
|
-
isVisible: !
|
|
62514
|
+
isVisible: !currentBreaksLoading && !currentBreaksError && !breakNotificationsDismissed,
|
|
61907
62515
|
onDismiss: () => setBreakNotificationsDismissed(true)
|
|
61908
62516
|
}
|
|
61909
62517
|
),
|
|
@@ -61915,6 +62523,15 @@ function HomeView({
|
|
|
61915
62523
|
onDismiss: () => setBottleneckNotification(null)
|
|
61916
62524
|
}
|
|
61917
62525
|
),
|
|
62526
|
+
/* @__PURE__ */ jsx(
|
|
62527
|
+
LoadingOverlayCmp,
|
|
62528
|
+
{
|
|
62529
|
+
isVisible: shouldShowFilterChangeLoader,
|
|
62530
|
+
message: "Loading Dashboard...",
|
|
62531
|
+
className: "bg-slate-50/30 backdrop-blur-[3px]",
|
|
62532
|
+
contentVariant: "plain"
|
|
62533
|
+
}
|
|
62534
|
+
),
|
|
61918
62535
|
diagnosisModalOpen && bottleneckModalData?.clipId && /* @__PURE__ */ jsx(
|
|
61919
62536
|
DiagnosisVideoModal,
|
|
61920
62537
|
{
|
|
@@ -71471,6 +72088,8 @@ var WorkspaceDetailView = ({
|
|
|
71471
72088
|
const totalActions = Number(cachedOverviewMetrics.action_count || 0);
|
|
71472
72089
|
const targetOutput = Number(cachedOverviewMetrics.action_threshold || 0);
|
|
71473
72090
|
const idealOutput = Number(cachedOverviewMetrics.predicted_output ?? targetOutput ?? 0);
|
|
72091
|
+
const pphThreshold = Number(cachedOverviewMetrics.pph_threshold || 0);
|
|
72092
|
+
const idealCycleTime = Number(cachedOverviewMetrics.ideal_cycle_time || 0);
|
|
71474
72093
|
return {
|
|
71475
72094
|
line_id: cachedOverviewMetrics.line_id,
|
|
71476
72095
|
line_name: "",
|
|
@@ -71489,11 +72108,11 @@ var WorkspaceDetailView = ({
|
|
|
71489
72108
|
shift_start: shiftDefinition?.startTime || "",
|
|
71490
72109
|
shift_end: shiftDefinition?.endTime || "",
|
|
71491
72110
|
shift_type: shiftType,
|
|
71492
|
-
pph_threshold:
|
|
72111
|
+
pph_threshold: pphThreshold,
|
|
71493
72112
|
target_output: targetOutput,
|
|
71494
72113
|
avg_pph: Number(cachedOverviewMetrics.pph || 0),
|
|
71495
72114
|
avg_cycle_time: avgCycleTime,
|
|
71496
|
-
ideal_cycle_time:
|
|
72115
|
+
ideal_cycle_time: idealCycleTime,
|
|
71497
72116
|
avg_efficiency: Number(cachedOverviewMetrics.efficiency || 0),
|
|
71498
72117
|
total_actions: totalActions,
|
|
71499
72118
|
hourly_action_counts: [],
|
|
@@ -74025,7 +74644,8 @@ var TeamManagementView = ({
|
|
|
74025
74644
|
const bootstrapData = await bootstrapResponse.json();
|
|
74026
74645
|
setAvailableFactories((bootstrapData.factories || []).map((factory) => ({
|
|
74027
74646
|
id: factory.id,
|
|
74028
|
-
factory_name: factory.factory_name
|
|
74647
|
+
factory_name: factory.factory_name,
|
|
74648
|
+
company_id: factory.company_id
|
|
74029
74649
|
})));
|
|
74030
74650
|
setAvailableLines(bootstrapData.lines || []);
|
|
74031
74651
|
setUsers(bootstrapData.users || []);
|
|
@@ -78993,7 +79613,7 @@ var efficiencyLineConfig = [
|
|
|
78993
79613
|
var bumpRenderCounter = (key) => {
|
|
78994
79614
|
if (process.env.NODE_ENV === "test") ;
|
|
78995
79615
|
};
|
|
78996
|
-
var
|
|
79616
|
+
var toNumber4 = (value) => {
|
|
78997
79617
|
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
78998
79618
|
if (typeof value === "string" && value.trim().length > 0) {
|
|
78999
79619
|
const parsed = Number(value);
|
|
@@ -79528,7 +80148,7 @@ var OverviewSummaryCards = React143__default.memo(({ store }) => {
|
|
|
79528
80148
|
workspaceId: item.workspace_id || "",
|
|
79529
80149
|
workspaceName: item.workspace_name?.trim() || item.workspace_id || "Unknown",
|
|
79530
80150
|
lineName: item.line_name?.trim() || "Unknown Line",
|
|
79531
|
-
avgIdleSeconds:
|
|
80151
|
+
avgIdleSeconds: toNumber4(item.avg_idle_seconds)
|
|
79532
80152
|
})).slice(0, 5);
|
|
79533
80153
|
}, [snapshot.data.summary.avg_idle_per_workstation?.top_contributors]);
|
|
79534
80154
|
const showIdleContributorLineNames = React143__default.useMemo(() => {
|
|
@@ -79743,9 +80363,9 @@ var PoorestPerformersCard = React143__default.memo(({
|
|
|
79743
80363
|
return {
|
|
79744
80364
|
id: lineId,
|
|
79745
80365
|
name: line.line_name?.trim() || "Unknown Line",
|
|
79746
|
-
efficiency: roundOne(
|
|
79747
|
-
previousEfficiency:
|
|
79748
|
-
delta:
|
|
80366
|
+
efficiency: roundOne(toNumber4(line.avg_efficiency) || 0),
|
|
80367
|
+
previousEfficiency: toNumber4(line.previous_avg_efficiency),
|
|
80368
|
+
delta: toNumber4(line.delta_pp),
|
|
79749
80369
|
supervisor: supervisor?.displayName || "Unassigned",
|
|
79750
80370
|
supervisorImage: supervisor?.profilePhotoUrl ?? null
|
|
79751
80371
|
};
|
|
@@ -79854,14 +80474,14 @@ var IdleBreakdownCard = React143__default.memo(({
|
|
|
79854
80474
|
paletteToken: item.palette_token?.trim(),
|
|
79855
80475
|
iconToken: item.icon_token?.trim(),
|
|
79856
80476
|
isKnown: item.is_known ?? void 0,
|
|
79857
|
-
value:
|
|
79858
|
-
totalDurationSeconds:
|
|
79859
|
-
efficiencyLossPercentage:
|
|
80477
|
+
value: toNumber4(item.percentage) || 0,
|
|
80478
|
+
totalDurationSeconds: toNumber4(item.total_duration_seconds),
|
|
80479
|
+
efficiencyLossPercentage: toNumber4(item.efficiency_loss_percentage),
|
|
79860
80480
|
contributors: (item.contributors || []).map((contributor) => ({
|
|
79861
80481
|
workspaceId: contributor.workspace_id || "",
|
|
79862
80482
|
workspaceName: contributor.workspace_name?.trim() || "Unknown",
|
|
79863
|
-
totalDurationSeconds:
|
|
79864
|
-
percentageWithinReason:
|
|
80483
|
+
totalDurationSeconds: toNumber4(contributor.total_duration_seconds),
|
|
80484
|
+
percentageWithinReason: toNumber4(contributor.percentage_within_reason)
|
|
79865
80485
|
}))
|
|
79866
80486
|
})).filter((item) => item.value > 0);
|
|
79867
80487
|
}, [idle.data]);
|
|
@@ -79930,7 +80550,7 @@ var EfficiencyTrendCard = React143__default.memo(({
|
|
|
79930
80550
|
return `${hour12}:${minutes.toString().padStart(2, "0")} ${suffix}`;
|
|
79931
80551
|
})(),
|
|
79932
80552
|
efficiency: (() => {
|
|
79933
|
-
const value =
|
|
80553
|
+
const value = toNumber4(point.avg_efficiency);
|
|
79934
80554
|
return value === null ? void 0 : value;
|
|
79935
80555
|
})()
|
|
79936
80556
|
}));
|
|
@@ -79943,7 +80563,7 @@ var EfficiencyTrendCard = React143__default.memo(({
|
|
|
79943
80563
|
name: format(pointDate, "MMM d"),
|
|
79944
80564
|
dayOfWeek: format(pointDate, "EEEE"),
|
|
79945
80565
|
efficiency: (() => {
|
|
79946
|
-
const value =
|
|
80566
|
+
const value = toNumber4(point.avg_efficiency);
|
|
79947
80567
|
return value === null ? void 0 : value;
|
|
79948
80568
|
})()
|
|
79949
80569
|
}]];
|
|
@@ -79967,7 +80587,7 @@ var EfficiencyTrendCard = React143__default.memo(({
|
|
|
79967
80587
|
name: pointDate ? format(pointDate, "MMM d") : "",
|
|
79968
80588
|
dayOfWeek: pointDate ? format(pointDate, "EEEE") : "",
|
|
79969
80589
|
efficiency: (() => {
|
|
79970
|
-
const value =
|
|
80590
|
+
const value = toNumber4(point.avg_efficiency);
|
|
79971
80591
|
return value === null ? void 0 : value;
|
|
79972
80592
|
})()
|
|
79973
80593
|
};
|
|
@@ -80091,7 +80711,7 @@ var debugRefreshLog = (message, payload) => {
|
|
|
80091
80711
|
var isAbortError2 = (error) => {
|
|
80092
80712
|
return error instanceof DOMException && error.name === "AbortError";
|
|
80093
80713
|
};
|
|
80094
|
-
var
|
|
80714
|
+
var toNumber5 = (value) => {
|
|
80095
80715
|
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
80096
80716
|
if (typeof value === "string" && value.trim().length > 0) {
|
|
80097
80717
|
const parsed = Number(value);
|
|
@@ -80100,11 +80720,11 @@ var toNumber4 = (value) => {
|
|
|
80100
80720
|
return null;
|
|
80101
80721
|
};
|
|
80102
80722
|
var formatImprovementMetric = (recommendation) => {
|
|
80103
|
-
const estimatedGain =
|
|
80723
|
+
const estimatedGain = toNumber5(recommendation.estimated_gain_pieces);
|
|
80104
80724
|
if (estimatedGain !== null && estimatedGain > 0) {
|
|
80105
80725
|
return `+${Math.round(estimatedGain).toLocaleString()} pcs / day`;
|
|
80106
80726
|
}
|
|
80107
|
-
const idleMinutes =
|
|
80727
|
+
const idleMinutes = toNumber5(recommendation.metrics?.idle_minutes);
|
|
80108
80728
|
if (idleMinutes !== null) {
|
|
80109
80729
|
return `-${Math.round(idleMinutes)}m Idle`;
|
|
80110
80730
|
}
|