@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.js
CHANGED
|
@@ -5117,6 +5117,27 @@ var workspaceService = {
|
|
|
5117
5117
|
this._workspaceVideoStreamsInFlight.set(cacheKey, fetchPromise);
|
|
5118
5118
|
return fetchPromise;
|
|
5119
5119
|
},
|
|
5120
|
+
primeWorkspaceVideoStreamsCache(params) {
|
|
5121
|
+
const streams = params.streams || {};
|
|
5122
|
+
const workspaceIds = (params.workspaceIds || []).filter(Boolean);
|
|
5123
|
+
const lineIds = (params.lineIds || []).filter(Boolean);
|
|
5124
|
+
if (!Object.keys(streams).length || !workspaceIds.length && !lineIds.length) {
|
|
5125
|
+
return;
|
|
5126
|
+
}
|
|
5127
|
+
const timestamp = Date.now();
|
|
5128
|
+
const entry = {
|
|
5129
|
+
streams,
|
|
5130
|
+
timestamp
|
|
5131
|
+
};
|
|
5132
|
+
if (workspaceIds.length) {
|
|
5133
|
+
const workspaceKey = workspaceIds.slice().sort().join(",");
|
|
5134
|
+
this._workspaceVideoStreamsCache.set(`workspaces:${workspaceKey}`, entry);
|
|
5135
|
+
}
|
|
5136
|
+
if (lineIds.length) {
|
|
5137
|
+
const lineKey = lineIds.slice().sort().join(",");
|
|
5138
|
+
this._workspaceVideoStreamsCache.set(`lines:${lineKey}`, entry);
|
|
5139
|
+
}
|
|
5140
|
+
},
|
|
5120
5141
|
async getWorkspaceCameraIps(params) {
|
|
5121
5142
|
const workspaceIds = (params.workspaceIds || []).filter(Boolean);
|
|
5122
5143
|
const lineIds = (params.lineIds || []).filter(Boolean);
|
|
@@ -11988,8 +12009,8 @@ var useOperationalShiftKey = ({
|
|
|
11988
12009
|
};
|
|
11989
12010
|
|
|
11990
12011
|
// src/lib/stores/workspaceMetricsStore.ts
|
|
11991
|
-
var OVERVIEW_TTL_MS =
|
|
11992
|
-
var DETAILED_TTL_MS =
|
|
12012
|
+
var OVERVIEW_TTL_MS = 12e4;
|
|
12013
|
+
var DETAILED_TTL_MS = 12e4;
|
|
11993
12014
|
var overviewByKey = /* @__PURE__ */ new Map();
|
|
11994
12015
|
var detailedByKey = /* @__PURE__ */ new Map();
|
|
11995
12016
|
var latestOverviewByWorkspace = /* @__PURE__ */ new Map();
|
|
@@ -13485,12 +13506,124 @@ function getEfficiencyTextColorClasses(efficiency, legend = DEFAULT_EFFICIENCY_L
|
|
|
13485
13506
|
}
|
|
13486
13507
|
}
|
|
13487
13508
|
|
|
13509
|
+
// src/lib/utils/monitorWorkspaceMetrics.ts
|
|
13510
|
+
var sortWorkspaceMetrics = (left, right) => {
|
|
13511
|
+
if (left.line_id !== right.line_id) {
|
|
13512
|
+
return left.line_id.localeCompare(right.line_id);
|
|
13513
|
+
}
|
|
13514
|
+
return left.workspace_name.localeCompare(right.workspace_name, void 0, { numeric: true });
|
|
13515
|
+
};
|
|
13516
|
+
var buildLineMetricsById = (lineMetrics) => (lineMetrics || []).reduce((acc, lineMetric) => {
|
|
13517
|
+
const lineId = lineMetric?.line_id;
|
|
13518
|
+
if (!lineId) {
|
|
13519
|
+
return acc;
|
|
13520
|
+
}
|
|
13521
|
+
acc[lineId] = { total_workspaces: lineMetric?.total_workspaces };
|
|
13522
|
+
return acc;
|
|
13523
|
+
}, {});
|
|
13524
|
+
var transformMonitorWorkspaceMetrics = ({
|
|
13525
|
+
rows,
|
|
13526
|
+
companyId,
|
|
13527
|
+
workspaceConfig,
|
|
13528
|
+
appTimezone,
|
|
13529
|
+
lineMetrics,
|
|
13530
|
+
resolveShiftConfig,
|
|
13531
|
+
shouldOverrideShiftType,
|
|
13532
|
+
fallbackShiftConfig = null
|
|
13533
|
+
}) => {
|
|
13534
|
+
const effectiveWorkspaceConfig = workspaceConfig || DEFAULT_WORKSPACE_CONFIG;
|
|
13535
|
+
const detailTimezone = appTimezone || "Asia/Kolkata";
|
|
13536
|
+
const lineMetricsById = buildLineMetricsById(lineMetrics);
|
|
13537
|
+
return (rows || []).map((item) => {
|
|
13538
|
+
const lineId = String(item?.line_id || "");
|
|
13539
|
+
const lineShiftConfig = resolveShiftConfig?.(lineId) || fallbackShiftConfig || void 0;
|
|
13540
|
+
const detailedMetrics = toWorkspaceDetailedMetrics({
|
|
13541
|
+
data: item,
|
|
13542
|
+
companyId,
|
|
13543
|
+
workspaceConfig: effectiveWorkspaceConfig,
|
|
13544
|
+
shiftConfig: lineShiftConfig,
|
|
13545
|
+
appTimezone: detailTimezone,
|
|
13546
|
+
lineMetricsById,
|
|
13547
|
+
overrideShiftType: shouldOverrideShiftType?.(lineId) ?? false
|
|
13548
|
+
});
|
|
13549
|
+
if (detailedMetrics) {
|
|
13550
|
+
workspaceMetricsStore.setDetailed(detailedMetrics);
|
|
13551
|
+
}
|
|
13552
|
+
const idleTimeValue = typeof item.idle_time === "number" ? item.idle_time : Number(item.idle_time);
|
|
13553
|
+
const idleTimeSeconds = Number.isFinite(idleTimeValue) ? idleTimeValue : void 0;
|
|
13554
|
+
const pphThresholdValue = typeof item.pph_threshold === "number" ? item.pph_threshold : Number(item.pph_threshold);
|
|
13555
|
+
const actionFamily = normalizeActionFamily({
|
|
13556
|
+
actionFamily: item.action_family,
|
|
13557
|
+
actionType: item.action_type,
|
|
13558
|
+
actionName: item.action_name
|
|
13559
|
+
});
|
|
13560
|
+
const actionType = actionFamily === "assembly" || actionFamily === "output" ? actionFamily : null;
|
|
13561
|
+
const metric = {
|
|
13562
|
+
company_id: item.company_id || companyId,
|
|
13563
|
+
line_id: lineId,
|
|
13564
|
+
shift_id: item.shift_id,
|
|
13565
|
+
date: item.date,
|
|
13566
|
+
workspace_uuid: item.workspace_id,
|
|
13567
|
+
workspace_name: item.workspace_name,
|
|
13568
|
+
displayName: item.workspace_display_name || item.display_name || void 0,
|
|
13569
|
+
action_count: item.total_output || 0,
|
|
13570
|
+
pph: item.avg_pph || 0,
|
|
13571
|
+
pph_threshold: Number.isFinite(pphThresholdValue) ? pphThresholdValue : void 0,
|
|
13572
|
+
performance_score: item.performance_score || 0,
|
|
13573
|
+
avg_cycle_time: item.avg_cycle_time || 0,
|
|
13574
|
+
ideal_cycle_time: item.ideal_cycle_time || void 0,
|
|
13575
|
+
trend: item.trend_score === 1 ? 2 : 0,
|
|
13576
|
+
predicted_output: item.ideal_output || 0,
|
|
13577
|
+
efficiency: item.efficiency || 0,
|
|
13578
|
+
action_threshold: item.total_day_output || 0,
|
|
13579
|
+
monitoring_mode: item.monitoring_mode ?? void 0,
|
|
13580
|
+
idle_time: idleTimeSeconds,
|
|
13581
|
+
idle_time_hourly: item.idle_time_hourly ?? null,
|
|
13582
|
+
shift_start: item.shift_start ?? void 0,
|
|
13583
|
+
shift_end: item.shift_end ?? void 0,
|
|
13584
|
+
assembly_enabled: item.assembly_enabled ?? false,
|
|
13585
|
+
video_grid_metric_mode: normalizeVideoGridMetricMode(
|
|
13586
|
+
item.video_grid_metric_mode,
|
|
13587
|
+
item.assembly_enabled ?? false
|
|
13588
|
+
),
|
|
13589
|
+
action_type: actionType,
|
|
13590
|
+
action_family: actionFamily,
|
|
13591
|
+
action_display_name: getActionDisplayName({
|
|
13592
|
+
displayName: item.action_display_name,
|
|
13593
|
+
actionFamily: item.action_family,
|
|
13594
|
+
actionType: item.action_type,
|
|
13595
|
+
actionName: item.action_name
|
|
13596
|
+
}),
|
|
13597
|
+
recent_flow_percent: item.recent_flow_percent ?? null,
|
|
13598
|
+
recent_flow_window_minutes: item.recent_flow_window_minutes ?? null,
|
|
13599
|
+
recent_flow_effective_end_at: item.recent_flow_effective_end_at ?? null,
|
|
13600
|
+
recent_flow_computed_at: item.recent_flow_computed_at ?? null,
|
|
13601
|
+
scheduled_break_active: item.scheduled_break_active ?? false,
|
|
13602
|
+
incoming_wip_current: item.incoming_wip_current ?? null,
|
|
13603
|
+
incoming_wip_effective_at: item.incoming_wip_effective_at ?? null,
|
|
13604
|
+
incoming_wip_buffer_name: item.incoming_wip_buffer_name ?? null,
|
|
13605
|
+
show_exclamation: item.show_exclamation ?? void 0
|
|
13606
|
+
};
|
|
13607
|
+
workspaceMetricsStore.setOverview(metric);
|
|
13608
|
+
return metric;
|
|
13609
|
+
}).sort(sortWorkspaceMetrics);
|
|
13610
|
+
};
|
|
13611
|
+
|
|
13488
13612
|
// src/lib/hooks/useDashboardMetrics.ts
|
|
13489
13613
|
var DEBUG_DASHBOARD_LOGS = process.env.NEXT_PUBLIC_DEBUG_DASHBOARD === "true";
|
|
13614
|
+
var REALTIME_REFRESH_DEBOUNCE_MS = 1500;
|
|
13615
|
+
var REALTIME_REFRESH_MIN_INTERVAL_MS = 5e3;
|
|
13490
13616
|
var logDebug = (...args) => {
|
|
13491
13617
|
if (!DEBUG_DASHBOARD_LOGS) return;
|
|
13492
13618
|
console.log(...args);
|
|
13493
13619
|
};
|
|
13620
|
+
var buildMetricsScopeKey = (lineId, lineIds) => {
|
|
13621
|
+
const normalizedLineIds = Array.from(new Set((lineIds || []).filter(Boolean))).sort();
|
|
13622
|
+
if (normalizedLineIds.length > 0) {
|
|
13623
|
+
return `${lineId}|${normalizedLineIds.join(",")}`;
|
|
13624
|
+
}
|
|
13625
|
+
return lineId;
|
|
13626
|
+
};
|
|
13494
13627
|
var parseEfficiencyLegend = (legend) => {
|
|
13495
13628
|
if (!legend) return null;
|
|
13496
13629
|
const coerce = (value, fallback) => {
|
|
@@ -13570,6 +13703,7 @@ var useDashboardMetrics = ({
|
|
|
13570
13703
|
const supabase = useSupabase();
|
|
13571
13704
|
const [metrics2, setMetrics] = React143.useState({ workspaceMetrics: [], lineMetrics: [] });
|
|
13572
13705
|
const [metricsLineId, setMetricsLineId] = React143.useState(lineId ?? null);
|
|
13706
|
+
const [metricsScopeKey, setMetricsScopeKey] = React143.useState(() => buildMetricsScopeKey(lineId, lineIds));
|
|
13573
13707
|
const [isLoading, setIsLoading] = React143.useState(true);
|
|
13574
13708
|
const [error, setError] = React143.useState(null);
|
|
13575
13709
|
const lineIdRef = React143.useRef(lineId);
|
|
@@ -13579,8 +13713,10 @@ var useDashboardMetrics = ({
|
|
|
13579
13713
|
const abortControllerRef = React143.useRef(null);
|
|
13580
13714
|
const lastFetchKeyRef = React143.useRef(null);
|
|
13581
13715
|
const inFlightFetchKeyRef = React143.useRef(null);
|
|
13582
|
-
const updateQueueRef = React143.useRef(false);
|
|
13583
13716
|
const onLineMetricsUpdateRef = React143.useRef(onLineMetricsUpdate);
|
|
13717
|
+
const pendingRealtimeRefreshRef = React143.useRef(false);
|
|
13718
|
+
const realtimeRefreshTimerRef = React143.useRef(null);
|
|
13719
|
+
const lastRealtimeRefreshStartedAtRef = React143.useRef(0);
|
|
13584
13720
|
const shiftGroupsRef = React143.useRef(shiftGroups);
|
|
13585
13721
|
const operationalShiftKeyRef = React143.useRef(operationalShiftKey);
|
|
13586
13722
|
const configuredLineIdsRef = React143.useRef(configuredLineIds);
|
|
@@ -13608,15 +13744,17 @@ var useDashboardMetrics = ({
|
|
|
13608
13744
|
() => getCompanyMetricsTableName(entityConfig.companyId, "performance_metrics"),
|
|
13609
13745
|
[entityConfig.companyId]
|
|
13610
13746
|
);
|
|
13747
|
+
const requestedScopeKey = React143.useMemo(
|
|
13748
|
+
() => buildMetricsScopeKey(lineId, isFactoryView ? targetFactoryLineIds : void 0),
|
|
13749
|
+
[isFactoryView, lineId, targetFactoryLineIds]
|
|
13750
|
+
);
|
|
13611
13751
|
React143.useEffect(() => {
|
|
13612
13752
|
lineIdRef.current = lineId;
|
|
13613
|
-
setMetrics({ workspaceMetrics: [], lineMetrics: [], metadata: void 0, efficiencyLegend: DEFAULT_EFFICIENCY_LEGEND });
|
|
13614
|
-
setMetricsLineId(null);
|
|
13615
13753
|
setIsLoading(true);
|
|
13616
13754
|
setError(null);
|
|
13617
13755
|
lastFetchKeyRef.current = null;
|
|
13618
13756
|
inFlightFetchKeyRef.current = null;
|
|
13619
|
-
}, [lineId]);
|
|
13757
|
+
}, [lineId, requestedScopeKey]);
|
|
13620
13758
|
const fetchAllMetrics = React143.useCallback(async (options = {}) => {
|
|
13621
13759
|
const { force = false } = options;
|
|
13622
13760
|
const currentLineIdToUse = lineIdRef.current;
|
|
@@ -13629,7 +13767,6 @@ var useDashboardMetrics = ({
|
|
|
13629
13767
|
companySpecificMetricsTable
|
|
13630
13768
|
});
|
|
13631
13769
|
if (!currentLineIdToUse || !supabase || !enabled || shiftLoading || isTimezoneLoading || companySpecificMetricsTable.includes("unknown_company")) {
|
|
13632
|
-
updateQueueRef.current = false;
|
|
13633
13770
|
if (!metrics2?.workspaceMetrics?.length && !metrics2?.lineMetrics?.length && !shiftLoading) setIsLoading(false);
|
|
13634
13771
|
if (companySpecificMetricsTable.includes("unknown_company") && !error) {
|
|
13635
13772
|
setError({ message: "Company ID not configured for metrics table.", code: "CONFIG_ERROR" });
|
|
@@ -13642,6 +13779,10 @@ var useDashboardMetrics = ({
|
|
|
13642
13779
|
const usesShiftGroups = isFactory && shiftGroups.length > 0;
|
|
13643
13780
|
const singleShiftDetails = usesShiftGroups ? null : shiftConfig ? getCurrentShift(defaultTimezone, shiftConfig) : shiftGroups.length === 1 ? { date: shiftGroups[0].date, shiftId: shiftGroups[0].shiftId } : getCurrentShift(defaultTimezone, staticShiftConfig);
|
|
13644
13781
|
const fetchKey = usesShiftGroups ? `factory|${companyId || "unknown"}|${shiftGroupsKey}` : isFactory ? `factory|${companyId || "unknown"}|${singleShiftDetails?.date}|${singleShiftDetails?.shiftId}|${targetLineIdsKey}` : `${currentLineIdToUse}|${companyId || "unknown"}|${singleShiftDetails?.date}|${singleShiftDetails?.shiftId}`;
|
|
13782
|
+
const responseScopeKey = buildMetricsScopeKey(
|
|
13783
|
+
currentLineIdToUse,
|
|
13784
|
+
isFactory ? targetLineIds : void 0
|
|
13785
|
+
);
|
|
13645
13786
|
logDebug("[useDashboardMetrics] Fetch key details:", {
|
|
13646
13787
|
isFactory,
|
|
13647
13788
|
usesShiftGroups,
|
|
@@ -13651,14 +13792,8 @@ var useDashboardMetrics = ({
|
|
|
13651
13792
|
singleShiftDetails,
|
|
13652
13793
|
fetchKey
|
|
13653
13794
|
});
|
|
13654
|
-
if (inFlightFetchKeyRef.current === fetchKey)
|
|
13655
|
-
|
|
13656
|
-
return;
|
|
13657
|
-
}
|
|
13658
|
-
if (!force && lastFetchKeyRef.current === fetchKey) {
|
|
13659
|
-
updateQueueRef.current = false;
|
|
13660
|
-
return;
|
|
13661
|
-
}
|
|
13795
|
+
if (inFlightFetchKeyRef.current === fetchKey) return;
|
|
13796
|
+
if (!force && lastFetchKeyRef.current === fetchKey) return;
|
|
13662
13797
|
const requestId = ++activeRequestIdRef.current;
|
|
13663
13798
|
const requestLineId = currentLineIdToUse;
|
|
13664
13799
|
isFetchingRef.current = true;
|
|
@@ -13681,6 +13816,7 @@ var useDashboardMetrics = ({
|
|
|
13681
13816
|
efficiencyLegend: DEFAULT_EFFICIENCY_LEGEND
|
|
13682
13817
|
});
|
|
13683
13818
|
setMetricsLineId(requestLineId);
|
|
13819
|
+
setMetricsScopeKey(responseScopeKey);
|
|
13684
13820
|
lastFetchKeyRef.current = inFlightFetchKeyRef.current;
|
|
13685
13821
|
return;
|
|
13686
13822
|
}
|
|
@@ -13790,89 +13926,16 @@ var useDashboardMetrics = ({
|
|
|
13790
13926
|
}
|
|
13791
13927
|
efficiencyLegend = parseEfficiencyLegend(backendData?.efficiency_legend) ?? DEFAULT_EFFICIENCY_LEGEND;
|
|
13792
13928
|
}
|
|
13793
|
-
const lineMetricsById = (allLineMetrics || []).reduce(
|
|
13794
|
-
(acc, line) => {
|
|
13795
|
-
const lineId2 = line?.line_id;
|
|
13796
|
-
if (lineId2) {
|
|
13797
|
-
acc[lineId2] = { total_workspaces: line?.total_workspaces };
|
|
13798
|
-
}
|
|
13799
|
-
return acc;
|
|
13800
|
-
},
|
|
13801
|
-
{}
|
|
13802
|
-
);
|
|
13803
13929
|
const detailTimezone = appTimezone || "Asia/Kolkata";
|
|
13804
|
-
|
|
13805
|
-
|
|
13806
|
-
|
|
13807
|
-
|
|
13808
|
-
|
|
13809
|
-
|
|
13810
|
-
|
|
13811
|
-
|
|
13812
|
-
|
|
13813
|
-
overrideShiftType: Boolean(lineShiftConfig)
|
|
13814
|
-
});
|
|
13815
|
-
if (detailedMetrics) {
|
|
13816
|
-
workspaceMetricsStore.setDetailed(detailedMetrics);
|
|
13817
|
-
}
|
|
13818
|
-
});
|
|
13819
|
-
const transformedWorkspaceData = allWorkspaceMetrics.map((item) => {
|
|
13820
|
-
const idleTimeValue = typeof item.idle_time === "number" ? item.idle_time : Number(item.idle_time);
|
|
13821
|
-
const idleTimeSeconds = Number.isFinite(idleTimeValue) ? idleTimeValue : void 0;
|
|
13822
|
-
const actionFamily = normalizeActionFamily({
|
|
13823
|
-
actionFamily: item.action_family,
|
|
13824
|
-
actionType: item.action_type,
|
|
13825
|
-
actionName: item.action_name
|
|
13826
|
-
});
|
|
13827
|
-
const actionType = actionFamily === "assembly" || actionFamily === "output" ? actionFamily : null;
|
|
13828
|
-
return {
|
|
13829
|
-
company_id: item.company_id || companyId,
|
|
13830
|
-
line_id: item.line_id,
|
|
13831
|
-
shift_id: item.shift_id,
|
|
13832
|
-
date: item.date,
|
|
13833
|
-
workspace_uuid: item.workspace_id,
|
|
13834
|
-
workspace_name: item.workspace_name,
|
|
13835
|
-
displayName: item.workspace_display_name || item.display_name || void 0,
|
|
13836
|
-
action_count: item.total_output || 0,
|
|
13837
|
-
pph: item.avg_pph || 0,
|
|
13838
|
-
performance_score: item.performance_score || 0,
|
|
13839
|
-
avg_cycle_time: item.avg_cycle_time || 0,
|
|
13840
|
-
trend: item.trend_score === 1 ? 2 : 0,
|
|
13841
|
-
predicted_output: item.ideal_output || 0,
|
|
13842
|
-
efficiency: item.efficiency || 0,
|
|
13843
|
-
action_threshold: item.total_day_output || 0,
|
|
13844
|
-
show_exclamation: item.show_exclamation ?? void 0,
|
|
13845
|
-
monitoring_mode: item.monitoring_mode ?? void 0,
|
|
13846
|
-
idle_time: idleTimeSeconds,
|
|
13847
|
-
assembly_enabled: item.assembly_enabled ?? false,
|
|
13848
|
-
video_grid_metric_mode: normalizeVideoGridMetricMode(
|
|
13849
|
-
item.video_grid_metric_mode,
|
|
13850
|
-
item.assembly_enabled ?? false
|
|
13851
|
-
),
|
|
13852
|
-
action_type: actionType,
|
|
13853
|
-
action_family: actionFamily,
|
|
13854
|
-
action_display_name: getActionDisplayName({
|
|
13855
|
-
displayName: item.action_display_name,
|
|
13856
|
-
actionFamily: item.action_family,
|
|
13857
|
-
actionType: item.action_type,
|
|
13858
|
-
actionName: item.action_name
|
|
13859
|
-
}),
|
|
13860
|
-
recent_flow_percent: item.recent_flow_percent ?? null,
|
|
13861
|
-
recent_flow_window_minutes: item.recent_flow_window_minutes ?? null,
|
|
13862
|
-
recent_flow_effective_end_at: item.recent_flow_effective_end_at ?? null,
|
|
13863
|
-
recent_flow_computed_at: item.recent_flow_computed_at ?? null,
|
|
13864
|
-
incoming_wip_current: item.incoming_wip_current ?? null,
|
|
13865
|
-
incoming_wip_effective_at: item.incoming_wip_effective_at ?? null,
|
|
13866
|
-
incoming_wip_buffer_name: item.incoming_wip_buffer_name ?? null
|
|
13867
|
-
};
|
|
13868
|
-
}).sort((a, b) => {
|
|
13869
|
-
if (a.line_id !== b.line_id) return a.line_id.localeCompare(b.line_id);
|
|
13870
|
-
const wsNumA = parseInt(a.workspace_name?.replace(/[^0-9]/g, "") || "0");
|
|
13871
|
-
const wsNumB = parseInt(b.workspace_name?.replace(/[^0-9]/g, "") || "0");
|
|
13872
|
-
return wsNumA - wsNumB;
|
|
13873
|
-
});
|
|
13874
|
-
transformedWorkspaceData.forEach((metric) => {
|
|
13875
|
-
workspaceMetricsStore.setOverview(metric);
|
|
13930
|
+
const transformedWorkspaceData = transformMonitorWorkspaceMetrics({
|
|
13931
|
+
rows: allWorkspaceMetrics,
|
|
13932
|
+
companyId: companyId || "",
|
|
13933
|
+
workspaceConfig: effectiveWorkspaceConfig,
|
|
13934
|
+
appTimezone: detailTimezone,
|
|
13935
|
+
lineMetrics: allLineMetrics,
|
|
13936
|
+
resolveShiftConfig: (metricLineId) => isFactoryView ? multiLineShiftConfigMap.get(metricLineId) || staticShiftConfig : shiftConfig || staticShiftConfig,
|
|
13937
|
+
shouldOverrideShiftType: (metricLineId) => isFactoryView ? Boolean(multiLineShiftConfigMap.get(metricLineId)) : Boolean(shiftConfig),
|
|
13938
|
+
fallbackShiftConfig: staticShiftConfig
|
|
13876
13939
|
});
|
|
13877
13940
|
const newMetricsState = {
|
|
13878
13941
|
workspaceMetrics: transformedWorkspaceData,
|
|
@@ -13890,6 +13953,7 @@ var useDashboardMetrics = ({
|
|
|
13890
13953
|
hydrateFromBackend(idleTimeVlmByLine);
|
|
13891
13954
|
setMetrics(newMetricsState);
|
|
13892
13955
|
setMetricsLineId(requestLineId);
|
|
13956
|
+
setMetricsScopeKey(responseScopeKey);
|
|
13893
13957
|
lastFetchKeyRef.current = inFlightFetchKeyRef.current;
|
|
13894
13958
|
} catch (err) {
|
|
13895
13959
|
if (abortController.signal.aborted || err?.name === "AbortError") {
|
|
@@ -13912,9 +13976,24 @@ var useDashboardMetrics = ({
|
|
|
13912
13976
|
if (requestId === activeRequestIdRef.current) {
|
|
13913
13977
|
setIsLoading(false);
|
|
13914
13978
|
isFetchingRef.current = false;
|
|
13915
|
-
updateQueueRef.current = false;
|
|
13916
13979
|
activeFetchLineIdRef.current = null;
|
|
13917
13980
|
inFlightFetchKeyRef.current = null;
|
|
13981
|
+
if (pendingRealtimeRefreshRef.current) {
|
|
13982
|
+
const elapsedSinceLastRealtimeRefresh = Date.now() - lastRealtimeRefreshStartedAtRef.current;
|
|
13983
|
+
const minIntervalRemaining = Math.max(0, REALTIME_REFRESH_MIN_INTERVAL_MS - elapsedSinceLastRealtimeRefresh);
|
|
13984
|
+
const nextDelay = Math.max(REALTIME_REFRESH_DEBOUNCE_MS, minIntervalRemaining);
|
|
13985
|
+
if (realtimeRefreshTimerRef.current === null) {
|
|
13986
|
+
realtimeRefreshTimerRef.current = window.setTimeout(() => {
|
|
13987
|
+
realtimeRefreshTimerRef.current = null;
|
|
13988
|
+
if (!pendingRealtimeRefreshRef.current || isFetchingRef.current || inFlightFetchKeyRef.current) {
|
|
13989
|
+
return;
|
|
13990
|
+
}
|
|
13991
|
+
pendingRealtimeRefreshRef.current = false;
|
|
13992
|
+
lastRealtimeRefreshStartedAtRef.current = Date.now();
|
|
13993
|
+
fetchAllMetricsRef.current({ force: true, reason: "subscription" });
|
|
13994
|
+
}, nextDelay);
|
|
13995
|
+
}
|
|
13996
|
+
}
|
|
13918
13997
|
}
|
|
13919
13998
|
}
|
|
13920
13999
|
}, [
|
|
@@ -13944,20 +14023,59 @@ var useDashboardMetrics = ({
|
|
|
13944
14023
|
React143.useEffect(() => {
|
|
13945
14024
|
fetchAllMetricsRef.current = fetchAllMetrics;
|
|
13946
14025
|
}, [fetchAllMetrics]);
|
|
13947
|
-
const
|
|
13948
|
-
if (
|
|
13949
|
-
|
|
13950
|
-
|
|
14026
|
+
const clearRealtimeRefreshTimer = React143.useCallback(() => {
|
|
14027
|
+
if (realtimeRefreshTimerRef.current !== null) {
|
|
14028
|
+
window.clearTimeout(realtimeRefreshTimerRef.current);
|
|
14029
|
+
realtimeRefreshTimerRef.current = null;
|
|
14030
|
+
}
|
|
14031
|
+
}, []);
|
|
14032
|
+
const scheduleRealtimeRefresh = React143.useCallback(() => {
|
|
14033
|
+
if (!enabled || !supabase) {
|
|
14034
|
+
pendingRealtimeRefreshRef.current = false;
|
|
14035
|
+
clearRealtimeRefreshTimer();
|
|
14036
|
+
return;
|
|
14037
|
+
}
|
|
14038
|
+
if (!pendingRealtimeRefreshRef.current || realtimeRefreshTimerRef.current !== null) {
|
|
14039
|
+
return;
|
|
14040
|
+
}
|
|
14041
|
+
const elapsedSinceLastRealtimeRefresh = Date.now() - lastRealtimeRefreshStartedAtRef.current;
|
|
14042
|
+
const minIntervalRemaining = Math.max(0, REALTIME_REFRESH_MIN_INTERVAL_MS - elapsedSinceLastRealtimeRefresh);
|
|
14043
|
+
const nextDelay = Math.max(REALTIME_REFRESH_DEBOUNCE_MS, minIntervalRemaining);
|
|
14044
|
+
realtimeRefreshTimerRef.current = window.setTimeout(() => {
|
|
14045
|
+
realtimeRefreshTimerRef.current = null;
|
|
14046
|
+
if (!pendingRealtimeRefreshRef.current) {
|
|
14047
|
+
return;
|
|
14048
|
+
}
|
|
14049
|
+
if (isFetchingRef.current || inFlightFetchKeyRef.current) {
|
|
14050
|
+
scheduleRealtimeRefresh();
|
|
14051
|
+
return;
|
|
13951
14052
|
}
|
|
14053
|
+
pendingRealtimeRefreshRef.current = false;
|
|
14054
|
+
lastRealtimeRefreshStartedAtRef.current = Date.now();
|
|
14055
|
+
fetchAllMetricsRef.current({ force: true, reason: "subscription" });
|
|
14056
|
+
}, nextDelay);
|
|
14057
|
+
}, [clearRealtimeRefreshTimer, enabled, supabase]);
|
|
14058
|
+
React143.useEffect(() => {
|
|
14059
|
+
return () => {
|
|
14060
|
+
clearRealtimeRefreshTimer();
|
|
14061
|
+
pendingRealtimeRefreshRef.current = false;
|
|
14062
|
+
};
|
|
14063
|
+
}, [clearRealtimeRefreshTimer]);
|
|
14064
|
+
const queueUpdate = React143.useCallback(() => {
|
|
14065
|
+
if (!enabled) {
|
|
14066
|
+
logDebug("[useDashboardMetrics] queueUpdate skipped: metrics disabled");
|
|
14067
|
+
return;
|
|
14068
|
+
}
|
|
14069
|
+
if (!supabase) {
|
|
13952
14070
|
if (!supabase) {
|
|
13953
14071
|
logDebug("[useDashboardMetrics] queueUpdate skipped: supabase not ready");
|
|
13954
14072
|
}
|
|
13955
14073
|
return;
|
|
13956
14074
|
}
|
|
13957
|
-
|
|
13958
|
-
|
|
13959
|
-
|
|
13960
|
-
}, [
|
|
14075
|
+
pendingRealtimeRefreshRef.current = true;
|
|
14076
|
+
logDebug("[useDashboardMetrics] queueUpdate queued realtime refresh");
|
|
14077
|
+
scheduleRealtimeRefresh();
|
|
14078
|
+
}, [enabled, scheduleRealtimeRefresh, supabase]);
|
|
13961
14079
|
React143.useEffect(() => {
|
|
13962
14080
|
if (enabled && lineId && supabase && !shiftLoading && !isTimezoneLoading) {
|
|
13963
14081
|
fetchAllMetrics({ reason: "line-change" });
|
|
@@ -14077,7 +14195,7 @@ var useDashboardMetrics = ({
|
|
|
14077
14195
|
{ event: "*", schema, table: companySpecificMetricsTable, filter: filter2 },
|
|
14078
14196
|
(payload) => {
|
|
14079
14197
|
const payloadData = payload.new || payload.old;
|
|
14080
|
-
|
|
14198
|
+
logDebug("[useDashboardMetrics] \u{1F4E1} WS_METRICS payload received:", {
|
|
14081
14199
|
eventType: payload.eventType,
|
|
14082
14200
|
lineId: payloadData?.line_id,
|
|
14083
14201
|
workspaceId: payloadData?.workspace_id,
|
|
@@ -14099,14 +14217,14 @@ var useDashboardMetrics = ({
|
|
|
14099
14217
|
shiftId: payloadData?.shift_id
|
|
14100
14218
|
});
|
|
14101
14219
|
if (payloadData?.date === group.date && payloadData?.shift_id === group.shiftId) {
|
|
14102
|
-
|
|
14220
|
+
logDebug("[useDashboardMetrics] \u2705 WS Date/shift match - triggering update");
|
|
14103
14221
|
queueUpdate();
|
|
14104
14222
|
} else {
|
|
14105
|
-
|
|
14223
|
+
logDebug("[useDashboardMetrics] \u274C WS Date/shift mismatch - update SKIPPED");
|
|
14106
14224
|
}
|
|
14107
14225
|
}
|
|
14108
14226
|
).subscribe((status) => {
|
|
14109
|
-
|
|
14227
|
+
logDebug("[useDashboardMetrics] \u{1F4F6} WS metrics subscription:", {
|
|
14110
14228
|
channel: wsChannelName,
|
|
14111
14229
|
status,
|
|
14112
14230
|
table: companySpecificMetricsTable,
|
|
@@ -14124,7 +14242,7 @@ var useDashboardMetrics = ({
|
|
|
14124
14242
|
{ event: "*", schema, table: configuredLineMetricsTable, filter: filter2 },
|
|
14125
14243
|
(payload) => {
|
|
14126
14244
|
const payloadData = payload.new || payload.old;
|
|
14127
|
-
|
|
14245
|
+
logDebug("[useDashboardMetrics] \u{1F4E1} LINE_METRICS payload received:", {
|
|
14128
14246
|
eventType: payload.eventType,
|
|
14129
14247
|
lineId: payloadData?.line_id,
|
|
14130
14248
|
date: payloadData?.date,
|
|
@@ -14144,15 +14262,15 @@ var useDashboardMetrics = ({
|
|
|
14144
14262
|
shiftId: payloadData?.shift_id
|
|
14145
14263
|
});
|
|
14146
14264
|
if (payloadData?.date === group.date && payloadData?.shift_id === group.shiftId) {
|
|
14147
|
-
|
|
14265
|
+
logDebug("[useDashboardMetrics] \u2705 Date/shift match - triggering update");
|
|
14148
14266
|
queueUpdate();
|
|
14149
14267
|
onLineMetricsUpdateRef.current?.();
|
|
14150
14268
|
} else {
|
|
14151
|
-
|
|
14269
|
+
logDebug("[useDashboardMetrics] \u274C Date/shift mismatch - update SKIPPED");
|
|
14152
14270
|
}
|
|
14153
14271
|
}
|
|
14154
14272
|
).subscribe((status) => {
|
|
14155
|
-
|
|
14273
|
+
logDebug("[useDashboardMetrics] \u{1F4F6} Line metrics subscription:", {
|
|
14156
14274
|
channel: lmChannelName,
|
|
14157
14275
|
status,
|
|
14158
14276
|
table: configuredLineMetricsTable,
|
|
@@ -14248,7 +14366,7 @@ var useDashboardMetrics = ({
|
|
|
14248
14366
|
{ event: "*", schema, table, filter: filter2 },
|
|
14249
14367
|
(payload) => {
|
|
14250
14368
|
const payloadData = payload.new || payload.old;
|
|
14251
|
-
|
|
14369
|
+
logDebug(`[useDashboardMetrics] \u{1F4E1} ${table.toUpperCase()} payload received (single-line):`, {
|
|
14252
14370
|
eventType: payload.eventType,
|
|
14253
14371
|
table: payload.table,
|
|
14254
14372
|
lineId: payloadData?.line_id,
|
|
@@ -14272,14 +14390,14 @@ var useDashboardMetrics = ({
|
|
|
14272
14390
|
shiftId: payloadData?.shift_id
|
|
14273
14391
|
});
|
|
14274
14392
|
if (payloadData?.date === operationalDateForSubscription && payloadData?.shift_id === currentShiftDetails.shiftId) {
|
|
14275
|
-
|
|
14393
|
+
logDebug(`[useDashboardMetrics] \u2705 ${table} Date/shift match - triggering update`);
|
|
14276
14394
|
callback();
|
|
14277
14395
|
} else {
|
|
14278
|
-
|
|
14396
|
+
logDebug(`[useDashboardMetrics] \u274C ${table} Date/shift mismatch - update SKIPPED`);
|
|
14279
14397
|
}
|
|
14280
14398
|
}
|
|
14281
14399
|
).subscribe((status) => {
|
|
14282
|
-
|
|
14400
|
+
logDebug(`[useDashboardMetrics] \u{1F4F6} ${table} subscription:`, {
|
|
14283
14401
|
channel: channelName,
|
|
14284
14402
|
status,
|
|
14285
14403
|
table,
|
|
@@ -14328,14 +14446,17 @@ var useDashboardMetrics = ({
|
|
|
14328
14446
|
lineId
|
|
14329
14447
|
// NOTE: userAccessibleLineIds removed - accessed via ref
|
|
14330
14448
|
]);
|
|
14331
|
-
const
|
|
14332
|
-
const
|
|
14449
|
+
const isCurrentScopeResolved = metricsScopeKey === requestedScopeKey;
|
|
14450
|
+
const hasLastGoodMetrics = metrics2.workspaceMetrics.length > 0 || metrics2.lineMetrics.length > 0;
|
|
14451
|
+
const canReuseLastGoodMetrics = hasLastGoodMetrics && !isCurrentScopeResolved && (isLoading || !!error);
|
|
14452
|
+
const safeMetrics = isCurrentScopeResolved || canReuseLastGoodMetrics ? metrics2 : { workspaceMetrics: [], lineMetrics: [], metadata: void 0, efficiencyLegend: DEFAULT_EFFICIENCY_LEGEND };
|
|
14333
14453
|
return {
|
|
14334
14454
|
workspaceMetrics: safeMetrics?.workspaceMetrics || [],
|
|
14335
14455
|
lineMetrics: safeMetrics?.lineMetrics || [],
|
|
14336
14456
|
efficiencyLegend: safeMetrics?.efficiencyLegend || DEFAULT_EFFICIENCY_LEGEND,
|
|
14337
14457
|
metadata: safeMetrics?.metadata,
|
|
14338
|
-
isLoading: enabled ? isLoading || !
|
|
14458
|
+
isLoading: enabled ? isLoading || !isCurrentScopeResolved && !canReuseLastGoodMetrics : false,
|
|
14459
|
+
isCurrentScopeResolved,
|
|
14339
14460
|
error,
|
|
14340
14461
|
refetch: () => {
|
|
14341
14462
|
if (!enabled) {
|
|
@@ -16783,6 +16904,7 @@ var isInitialized = false;
|
|
|
16783
16904
|
var isInitializing = false;
|
|
16784
16905
|
var initializedWithLineIds = [];
|
|
16785
16906
|
var missingLineContextWarnings = /* @__PURE__ */ new Set();
|
|
16907
|
+
var lineLoadPromises = /* @__PURE__ */ new Map();
|
|
16786
16908
|
var initializationPromise = null;
|
|
16787
16909
|
var workspaceDisplayNamesListeners = /* @__PURE__ */ new Set();
|
|
16788
16910
|
var notifyWorkspaceDisplayNamesListeners = (changedLineId) => {
|
|
@@ -16798,6 +16920,30 @@ var subscribeWorkspaceDisplayNames = (listener) => {
|
|
|
16798
16920
|
workspaceDisplayNamesListeners.add(listener);
|
|
16799
16921
|
return () => workspaceDisplayNamesListeners.delete(listener);
|
|
16800
16922
|
};
|
|
16923
|
+
var storeLineDisplayNames = (lineId, lineDisplayNamesMap) => {
|
|
16924
|
+
runtimeWorkspaceDisplayNames[lineId] = {};
|
|
16925
|
+
lineDisplayNamesMap.forEach((displayName, workspaceId) => {
|
|
16926
|
+
runtimeWorkspaceDisplayNames[lineId][workspaceId] = displayName;
|
|
16927
|
+
});
|
|
16928
|
+
};
|
|
16929
|
+
var ensureLineWorkspaceDisplayNamesLoaded = async (lineId) => {
|
|
16930
|
+
if (!lineId || runtimeWorkspaceDisplayNames[lineId]) {
|
|
16931
|
+
return;
|
|
16932
|
+
}
|
|
16933
|
+
const existingPromise = lineLoadPromises.get(lineId);
|
|
16934
|
+
if (existingPromise) {
|
|
16935
|
+
await existingPromise;
|
|
16936
|
+
return;
|
|
16937
|
+
}
|
|
16938
|
+
const loadPromise = workspaceService.getWorkspaceDisplayNames(void 0, lineId).then((lineDisplayNamesMap) => {
|
|
16939
|
+
storeLineDisplayNames(lineId, lineDisplayNamesMap);
|
|
16940
|
+
notifyWorkspaceDisplayNamesListeners(lineId);
|
|
16941
|
+
}).finally(() => {
|
|
16942
|
+
lineLoadPromises.delete(lineId);
|
|
16943
|
+
});
|
|
16944
|
+
lineLoadPromises.set(lineId, loadPromise);
|
|
16945
|
+
await loadPromise;
|
|
16946
|
+
};
|
|
16801
16947
|
var getAllWorkspaceDisplayNamesSnapshot = (lineId) => {
|
|
16802
16948
|
if (lineId && runtimeWorkspaceDisplayNames[lineId]) {
|
|
16803
16949
|
return { ...runtimeWorkspaceDisplayNames[lineId] };
|
|
@@ -16862,6 +17008,7 @@ async function initializeWorkspaceDisplayNames(explicitLineId) {
|
|
|
16862
17008
|
}
|
|
16863
17009
|
console.log("\u{1F504} Target line IDs for workspace filtering:", targetLineIds);
|
|
16864
17010
|
runtimeWorkspaceDisplayNames = {};
|
|
17011
|
+
lineLoadPromises.clear();
|
|
16865
17012
|
if (targetLineIds.length > 0) {
|
|
16866
17013
|
const results = await Promise.all(
|
|
16867
17014
|
targetLineIds.map(async (lineId) => {
|
|
@@ -16871,10 +17018,7 @@ async function initializeWorkspaceDisplayNames(explicitLineId) {
|
|
|
16871
17018
|
})
|
|
16872
17019
|
);
|
|
16873
17020
|
results.forEach(({ lineId, lineDisplayNamesMap }) => {
|
|
16874
|
-
|
|
16875
|
-
lineDisplayNamesMap.forEach((displayName, workspaceId) => {
|
|
16876
|
-
runtimeWorkspaceDisplayNames[lineId][workspaceId] = displayName;
|
|
16877
|
-
});
|
|
17021
|
+
storeLineDisplayNames(lineId, lineDisplayNamesMap);
|
|
16878
17022
|
console.log(`\u2705 Stored ${lineDisplayNamesMap.size} workspaces for line ${lineId}`);
|
|
16879
17023
|
});
|
|
16880
17024
|
} else {
|
|
@@ -16906,13 +17050,8 @@ var preInitializeWorkspaceDisplayNames = async (lineId) => {
|
|
|
16906
17050
|
if (lineId && !runtimeWorkspaceDisplayNames[lineId]) {
|
|
16907
17051
|
console.log(`\u{1F504} Line ${lineId} not in cache, fetching...`);
|
|
16908
17052
|
try {
|
|
16909
|
-
|
|
16910
|
-
|
|
16911
|
-
lineDisplayNamesMap.forEach((displayName, workspaceId) => {
|
|
16912
|
-
runtimeWorkspaceDisplayNames[lineId][workspaceId] = displayName;
|
|
16913
|
-
});
|
|
16914
|
-
console.log(`\u2705 Added ${lineDisplayNamesMap.size} workspaces for line ${lineId}`);
|
|
16915
|
-
notifyWorkspaceDisplayNamesListeners(lineId);
|
|
17053
|
+
await ensureLineWorkspaceDisplayNamesLoaded(lineId);
|
|
17054
|
+
console.log(`\u2705 Added workspaces for line ${lineId}`);
|
|
16916
17055
|
} catch (error) {
|
|
16917
17056
|
console.error(`\u274C Failed to fetch workspaces for line ${lineId}:`, error);
|
|
16918
17057
|
}
|
|
@@ -16925,13 +17064,8 @@ var preInitializeWorkspaceDisplayNames = async (lineId) => {
|
|
|
16925
17064
|
if (lineId && !runtimeWorkspaceDisplayNames[lineId]) {
|
|
16926
17065
|
console.log(`\u{1F504} Line ${lineId} not in cache after init, fetching...`);
|
|
16927
17066
|
try {
|
|
16928
|
-
|
|
16929
|
-
|
|
16930
|
-
lineDisplayNamesMap.forEach((displayName, workspaceId) => {
|
|
16931
|
-
runtimeWorkspaceDisplayNames[lineId][workspaceId] = displayName;
|
|
16932
|
-
});
|
|
16933
|
-
console.log(`\u2705 Added ${lineDisplayNamesMap.size} workspaces for line ${lineId}`);
|
|
16934
|
-
notifyWorkspaceDisplayNamesListeners(lineId);
|
|
17067
|
+
await ensureLineWorkspaceDisplayNamesLoaded(lineId);
|
|
17068
|
+
console.log(`\u2705 Added workspaces for line ${lineId}`);
|
|
16935
17069
|
} catch (error) {
|
|
16936
17070
|
console.error(`\u274C Failed to fetch workspaces for line ${lineId}:`, error);
|
|
16937
17071
|
}
|
|
@@ -16968,13 +17102,8 @@ var getWorkspaceDisplayName = (workspaceId, lineId) => {
|
|
|
16968
17102
|
}
|
|
16969
17103
|
if (isInitialized && lineId && !runtimeWorkspaceDisplayNames[lineId]) {
|
|
16970
17104
|
console.log(`\u{1F504} Line ${lineId} not in cache, fetching its workspaces...`);
|
|
16971
|
-
|
|
16972
|
-
|
|
16973
|
-
lineDisplayNamesMap.forEach((displayName2, workspaceId2) => {
|
|
16974
|
-
runtimeWorkspaceDisplayNames[lineId][workspaceId2] = displayName2;
|
|
16975
|
-
});
|
|
16976
|
-
console.log(`\u2705 Added ${lineDisplayNamesMap.size} workspaces for line ${lineId} to cache`);
|
|
16977
|
-
notifyWorkspaceDisplayNamesListeners(lineId);
|
|
17105
|
+
ensureLineWorkspaceDisplayNamesLoaded(lineId).then(() => {
|
|
17106
|
+
console.log(`\u2705 Added workspaces for line ${lineId} to cache`);
|
|
16978
17107
|
}).catch((error) => {
|
|
16979
17108
|
console.error(`\u274C Failed to fetch workspaces for line ${lineId}:`, error);
|
|
16980
17109
|
});
|
|
@@ -17016,13 +17145,8 @@ var getShortWorkspaceDisplayName = (workspaceId, lineId) => {
|
|
|
17016
17145
|
}
|
|
17017
17146
|
if (isInitialized && lineId && !runtimeWorkspaceDisplayNames[lineId]) {
|
|
17018
17147
|
console.log(`\u{1F504} Line ${lineId} not in cache, fetching its workspaces...`);
|
|
17019
|
-
|
|
17020
|
-
|
|
17021
|
-
lineDisplayNamesMap.forEach((displayName2, workspaceId2) => {
|
|
17022
|
-
runtimeWorkspaceDisplayNames[lineId][workspaceId2] = displayName2;
|
|
17023
|
-
});
|
|
17024
|
-
console.log(`\u2705 Added ${lineDisplayNamesMap.size} workspaces for line ${lineId} to cache`);
|
|
17025
|
-
notifyWorkspaceDisplayNamesListeners(lineId);
|
|
17148
|
+
ensureLineWorkspaceDisplayNamesLoaded(lineId).then(() => {
|
|
17149
|
+
console.log(`\u2705 Added workspaces for line ${lineId} to cache`);
|
|
17026
17150
|
}).catch((error) => {
|
|
17027
17151
|
console.error(`\u274C Failed to fetch workspaces for line ${lineId}:`, error);
|
|
17028
17152
|
});
|
|
@@ -17102,6 +17226,7 @@ var refreshWorkspaceDisplayNames = async (companyId) => {
|
|
|
17102
17226
|
workspaceService.clearWorkspaceDisplayNamesCache();
|
|
17103
17227
|
runtimeWorkspaceDisplayNames = {};
|
|
17104
17228
|
isInitialized = false;
|
|
17229
|
+
lineLoadPromises.clear();
|
|
17105
17230
|
await initializeWorkspaceDisplayNames();
|
|
17106
17231
|
notifyWorkspaceDisplayNamesListeners();
|
|
17107
17232
|
};
|
|
@@ -17111,6 +17236,7 @@ var clearWorkspaceDisplayNamesCache = () => {
|
|
|
17111
17236
|
isInitialized = false;
|
|
17112
17237
|
isInitializing = false;
|
|
17113
17238
|
initializedWithLineIds = [];
|
|
17239
|
+
lineLoadPromises.clear();
|
|
17114
17240
|
initializationPromise = null;
|
|
17115
17241
|
notifyWorkspaceDisplayNamesListeners();
|
|
17116
17242
|
};
|
|
@@ -17240,7 +17366,16 @@ var useWorkspaceDisplayNamesMap = (workspaceIds, lineId, companyId) => {
|
|
|
17240
17366
|
refetch: fetchDisplayNames
|
|
17241
17367
|
};
|
|
17242
17368
|
};
|
|
17243
|
-
var useWorkspaceVideoStreams = (workspaces) => {
|
|
17369
|
+
var useWorkspaceVideoStreams = (workspaces, options = {}) => {
|
|
17370
|
+
const explicitLineIdsKey = React143.useMemo(() => {
|
|
17371
|
+
const ids = /* @__PURE__ */ new Set();
|
|
17372
|
+
for (const lineId of options.lineIds || []) {
|
|
17373
|
+
if (lineId) {
|
|
17374
|
+
ids.add(lineId);
|
|
17375
|
+
}
|
|
17376
|
+
}
|
|
17377
|
+
return Array.from(ids).sort().join(",");
|
|
17378
|
+
}, [options.lineIds]);
|
|
17244
17379
|
const workspaceIdsKey = React143.useMemo(() => {
|
|
17245
17380
|
const ids = /* @__PURE__ */ new Set();
|
|
17246
17381
|
for (const workspace of workspaces) {
|
|
@@ -17250,7 +17385,7 @@ var useWorkspaceVideoStreams = (workspaces) => {
|
|
|
17250
17385
|
}
|
|
17251
17386
|
return Array.from(ids).sort().join(",");
|
|
17252
17387
|
}, [workspaces]);
|
|
17253
|
-
const
|
|
17388
|
+
const inferredLineIdsKey = React143.useMemo(() => {
|
|
17254
17389
|
const ids = /* @__PURE__ */ new Set();
|
|
17255
17390
|
for (const workspace of workspaces) {
|
|
17256
17391
|
if (workspace.line_id) {
|
|
@@ -17259,18 +17394,19 @@ var useWorkspaceVideoStreams = (workspaces) => {
|
|
|
17259
17394
|
}
|
|
17260
17395
|
return Array.from(ids).sort().join(",");
|
|
17261
17396
|
}, [workspaces]);
|
|
17397
|
+
const lineIdsKey = explicitLineIdsKey || inferredLineIdsKey;
|
|
17262
17398
|
const requestKey = React143.useMemo(() => {
|
|
17263
|
-
if (workspaceIdsKey) {
|
|
17264
|
-
return `workspaces:${workspaceIdsKey}`;
|
|
17265
|
-
}
|
|
17266
17399
|
if (lineIdsKey) {
|
|
17267
17400
|
return `lines:${lineIdsKey}`;
|
|
17268
17401
|
}
|
|
17402
|
+
if (workspaceIdsKey) {
|
|
17403
|
+
return `workspaces:${workspaceIdsKey}`;
|
|
17404
|
+
}
|
|
17269
17405
|
return "";
|
|
17270
17406
|
}, [workspaceIdsKey, lineIdsKey]);
|
|
17271
17407
|
const workspaceIds = React143.useMemo(
|
|
17272
|
-
() => workspaceIdsKey ? workspaceIdsKey.split(",") : [],
|
|
17273
|
-
[workspaceIdsKey]
|
|
17408
|
+
() => lineIdsKey ? [] : workspaceIdsKey ? workspaceIdsKey.split(",") : [],
|
|
17409
|
+
[lineIdsKey, workspaceIdsKey]
|
|
17274
17410
|
);
|
|
17275
17411
|
const lineIds = React143.useMemo(
|
|
17276
17412
|
() => lineIdsKey ? lineIdsKey.split(",") : [],
|
|
@@ -18814,6 +18950,7 @@ var useWorkspaceHealthLastSeen = (workspaceIds, options = {}) => {
|
|
|
18814
18950
|
const supabase = useSupabase();
|
|
18815
18951
|
const databaseConfig = useDatabaseConfig();
|
|
18816
18952
|
const refreshInterval = options.refreshInterval ?? DEFAULT_REFRESH_INTERVAL_MS;
|
|
18953
|
+
const enabled = options.enabled ?? true;
|
|
18817
18954
|
const workspaceIdsKey = React143.useMemo(() => {
|
|
18818
18955
|
const ids = Array.from(new Set(workspaceIds.filter(Boolean)));
|
|
18819
18956
|
return ids.sort().join(",");
|
|
@@ -18824,7 +18961,7 @@ var useWorkspaceHealthLastSeen = (workspaceIds, options = {}) => {
|
|
|
18824
18961
|
const isFetchingRef = React143.useRef(false);
|
|
18825
18962
|
const refreshIntervalRef = React143.useRef(null);
|
|
18826
18963
|
const fetchLastSeen = React143.useCallback(async () => {
|
|
18827
|
-
if (!supabase || !workspaceIdsKey || isFetchingRef.current) return;
|
|
18964
|
+
if (!enabled || !supabase || !workspaceIdsKey || isFetchingRef.current) return;
|
|
18828
18965
|
const healthTable = databaseConfig?.tables?.workspace_health || "workspace_health_status";
|
|
18829
18966
|
try {
|
|
18830
18967
|
isFetchingRef.current = true;
|
|
@@ -18856,12 +18993,18 @@ var useWorkspaceHealthLastSeen = (workspaceIds, options = {}) => {
|
|
|
18856
18993
|
setIsLoading(false);
|
|
18857
18994
|
isFetchingRef.current = false;
|
|
18858
18995
|
}
|
|
18859
|
-
}, [
|
|
18996
|
+
}, [databaseConfig?.tables?.workspace_health, enabled, supabase, workspaceIdsKey]);
|
|
18860
18997
|
React143.useEffect(() => {
|
|
18998
|
+
if (!enabled) {
|
|
18999
|
+
setIsLoading(false);
|
|
19000
|
+
setError(null);
|
|
19001
|
+
setLastSeenByWorkspaceId({});
|
|
19002
|
+
return;
|
|
19003
|
+
}
|
|
18861
19004
|
fetchLastSeen();
|
|
18862
|
-
}, [fetchLastSeen]);
|
|
19005
|
+
}, [enabled, fetchLastSeen]);
|
|
18863
19006
|
React143.useEffect(() => {
|
|
18864
|
-
if (!refreshInterval || !workspaceIdsKey) return;
|
|
19007
|
+
if (!enabled || !refreshInterval || !workspaceIdsKey) return;
|
|
18865
19008
|
refreshIntervalRef.current = setInterval(() => {
|
|
18866
19009
|
fetchLastSeen();
|
|
18867
19010
|
}, refreshInterval);
|
|
@@ -18871,7 +19014,7 @@ var useWorkspaceHealthLastSeen = (workspaceIds, options = {}) => {
|
|
|
18871
19014
|
refreshIntervalRef.current = null;
|
|
18872
19015
|
}
|
|
18873
19016
|
};
|
|
18874
|
-
}, [fetchLastSeen, refreshInterval, workspaceIdsKey]);
|
|
19017
|
+
}, [enabled, fetchLastSeen, refreshInterval, workspaceIdsKey]);
|
|
18875
19018
|
return {
|
|
18876
19019
|
lastSeenByWorkspaceId,
|
|
18877
19020
|
isLoading,
|
|
@@ -34704,7 +34847,7 @@ var VideoCard = React143__namespace.default.memo(({
|
|
|
34704
34847
|
});
|
|
34705
34848
|
const showOffline = Boolean(isStreamStale);
|
|
34706
34849
|
const lastSeenText = lastSeenLabel || "Unknown";
|
|
34707
|
-
const workspaceDisplayName = displayName ||
|
|
34850
|
+
const workspaceDisplayName = displayName || workspace.displayName || workspace.workspace_name;
|
|
34708
34851
|
const videoGridMetricValue = getVideoGridMetricValue(workspace);
|
|
34709
34852
|
const videoGridDisplayValue = getVideoGridDisplayValue(workspace, effectiveLegend, displayMinuteBucket);
|
|
34710
34853
|
const videoGridColorState = getVideoGridColorState(workspace, effectiveLegend);
|
|
@@ -34917,7 +35060,10 @@ var VideoGridView = React143__namespace.default.memo(({
|
|
|
34917
35060
|
}
|
|
34918
35061
|
return Array.from(ids);
|
|
34919
35062
|
}, [workspaces]);
|
|
34920
|
-
const
|
|
35063
|
+
const healthFetchEnabled = !videoStreamsLoading && workspaces.length > 0;
|
|
35064
|
+
const { lastSeenByWorkspaceId } = useWorkspaceHealthLastSeen(workspaceHealthIds, {
|
|
35065
|
+
enabled: healthFetchEnabled
|
|
35066
|
+
});
|
|
34921
35067
|
React143.useEffect(() => {
|
|
34922
35068
|
const sample = workspaces.slice(0, 3).map((workspace) => ({
|
|
34923
35069
|
id: workspace.workspace_uuid || workspace.workspace_name,
|
|
@@ -35016,6 +35162,9 @@ var VideoGridView = React143__namespace.default.memo(({
|
|
|
35016
35162
|
}, [sortedWorkspaces, lineOrder, lineNames]);
|
|
35017
35163
|
lineGroups.length > 1;
|
|
35018
35164
|
const streamsReady = !videoStreamsLoading;
|
|
35165
|
+
const resolveWorkspaceDisplayName = React143.useCallback((workspace) => {
|
|
35166
|
+
return workspace.displayName || displayNames[`${workspace.line_id}_${workspace.workspace_name}`] || workspace.workspace_name;
|
|
35167
|
+
}, [displayNames]);
|
|
35019
35168
|
const calculateOptimalGrid = React143.useCallback(() => {
|
|
35020
35169
|
if (!containerRef.current) return;
|
|
35021
35170
|
const containerPadding = 16;
|
|
@@ -35146,11 +35295,11 @@ var VideoGridView = React143__namespace.default.memo(({
|
|
|
35146
35295
|
efficiency: workspace.efficiency,
|
|
35147
35296
|
action_count: workspace.action_count
|
|
35148
35297
|
});
|
|
35149
|
-
const displayName =
|
|
35298
|
+
const displayName = resolveWorkspaceDisplayName(workspace);
|
|
35150
35299
|
const currentPath = (router$1.asPath || "/").split("#")[0];
|
|
35151
35300
|
const navParams = getWorkspaceNavigationParams(workspaceId, displayName, workspace.line_id, currentPath);
|
|
35152
35301
|
router$1.push(`/workspace/${workspaceId}${navParams}`);
|
|
35153
|
-
}, [router$1, prewarmClipsInit]);
|
|
35302
|
+
}, [resolveWorkspaceDisplayName, router$1, prewarmClipsInit]);
|
|
35154
35303
|
const handleStreamError = React143.useCallback((workspaceId, options) => {
|
|
35155
35304
|
const isR2Stream = options?.isR2Stream ?? false;
|
|
35156
35305
|
const hasFallback = Boolean(options?.fallbackUrl);
|
|
@@ -35259,7 +35408,7 @@ var VideoGridView = React143__namespace.default.memo(({
|
|
|
35259
35408
|
legend: effectiveLegend,
|
|
35260
35409
|
cropping: card.workspaceCropping,
|
|
35261
35410
|
canvasFps: effectiveCanvasFps,
|
|
35262
|
-
displayName:
|
|
35411
|
+
displayName: resolveWorkspaceDisplayName(card.workspace),
|
|
35263
35412
|
lastSeenLabel: card.lastSeenLabel,
|
|
35264
35413
|
useRAF: effectiveUseRAF,
|
|
35265
35414
|
displayMinuteBucket,
|
|
@@ -35271,16 +35420,15 @@ var VideoGridView = React143__namespace.default.memo(({
|
|
|
35271
35420
|
},
|
|
35272
35421
|
card.workspaceKey
|
|
35273
35422
|
), [
|
|
35274
|
-
displayNames,
|
|
35275
35423
|
displayMinuteBucket,
|
|
35276
35424
|
effectiveCanvasFps,
|
|
35277
35425
|
effectiveLegend,
|
|
35278
35426
|
effectiveUseRAF,
|
|
35279
|
-
getWorkspaceDisplayName,
|
|
35280
35427
|
handleStreamError,
|
|
35281
35428
|
handleWorkspaceClick,
|
|
35282
35429
|
onWorkspaceHover,
|
|
35283
35430
|
onWorkspaceHoverEnd,
|
|
35431
|
+
resolveWorkspaceDisplayName,
|
|
35284
35432
|
selectedLine
|
|
35285
35433
|
]);
|
|
35286
35434
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `relative overflow-hidden h-full w-full bg-slate-50/30 ${className}`, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -35366,6 +35514,9 @@ var MapGridView = React143__namespace.default.memo(({
|
|
|
35366
35514
|
prewarmInFlightRef.current.delete(workspaceId);
|
|
35367
35515
|
});
|
|
35368
35516
|
}, [dashboardConfig, timezone, supabase]);
|
|
35517
|
+
const resolveWorkspaceDisplayName = React143.useCallback((workspace) => {
|
|
35518
|
+
return workspace.displayName || displayNames[`${workspace.line_id}_${workspace.workspace_name}`] || workspace.workspace_name;
|
|
35519
|
+
}, [displayNames]);
|
|
35369
35520
|
const handleWorkspaceClick = React143.useCallback((workspace) => {
|
|
35370
35521
|
const workspaceId = workspace.workspace_uuid || workspace.workspace_name;
|
|
35371
35522
|
prewarmClipsInit(workspace);
|
|
@@ -35377,12 +35528,11 @@ var MapGridView = React143__namespace.default.memo(({
|
|
|
35377
35528
|
efficiency: workspace.efficiency,
|
|
35378
35529
|
action_count: workspace.action_count
|
|
35379
35530
|
});
|
|
35380
|
-
const displayName =
|
|
35381
|
-
getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
|
|
35531
|
+
const displayName = resolveWorkspaceDisplayName(workspace);
|
|
35382
35532
|
const currentPath = (router$1.asPath || "/").split("#")[0];
|
|
35383
35533
|
const navParams = getWorkspaceNavigationParams(workspaceId, displayName, workspace.line_id, currentPath);
|
|
35384
35534
|
router$1.push(`/workspace/${workspaceId}${navParams}`);
|
|
35385
|
-
}, [router$1,
|
|
35535
|
+
}, [resolveWorkspaceDisplayName, router$1, prewarmClipsInit]);
|
|
35386
35536
|
const activePositions = React143.useMemo(() => {
|
|
35387
35537
|
return workspacePositions.filter((pos) => {
|
|
35388
35538
|
const wsKey = pos.id.toUpperCase();
|
|
@@ -35412,7 +35562,18 @@ var MapGridView = React143__namespace.default.memo(({
|
|
|
35412
35562
|
workspace_uuid: position.id,
|
|
35413
35563
|
// Use config ID as temporary UUID
|
|
35414
35564
|
line_id: "",
|
|
35565
|
+
// Empty line ID
|
|
35566
|
+
company_id: "",
|
|
35567
|
+
shift_id: 0,
|
|
35568
|
+
date: "",
|
|
35415
35569
|
efficiency: 0,
|
|
35570
|
+
performance_score: 0,
|
|
35571
|
+
action_count: 0,
|
|
35572
|
+
pph: 0,
|
|
35573
|
+
avg_cycle_time: 0,
|
|
35574
|
+
trend: 0,
|
|
35575
|
+
predicted_output: 0,
|
|
35576
|
+
action_threshold: 0,
|
|
35416
35577
|
show_exclamation: false
|
|
35417
35578
|
};
|
|
35418
35579
|
const workspaceId = effectiveWorkspace.workspace_uuid || effectiveWorkspace.workspace_name;
|
|
@@ -35421,7 +35582,7 @@ var MapGridView = React143__namespace.default.memo(({
|
|
|
35421
35582
|
const performanceColor = isInactivePlaceholder || isConveyorRow ? "bg-slate-200 border-slate-300 text-slate-500" : getPerformanceColor(effectiveWorkspace.efficiency);
|
|
35422
35583
|
!isInactivePlaceholder && !isConveyorRow && (effectiveWorkspace.show_exclamation ?? (effectiveWorkspace.efficiency < 50 && effectiveWorkspace.efficiency >= 10));
|
|
35423
35584
|
const configLabel = position.label;
|
|
35424
|
-
const workspaceDisplayName = configLabel || (isInactivePlaceholder ? "INACTIVE" :
|
|
35585
|
+
const workspaceDisplayName = configLabel || (isInactivePlaceholder ? "INACTIVE" : resolveWorkspaceDisplayName(effectiveWorkspace) || position.id);
|
|
35425
35586
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
35426
35587
|
motion.div,
|
|
35427
35588
|
{
|
|
@@ -39388,9 +39549,12 @@ SelectSeparator.displayName = SelectPrimitive__namespace.Separator.displayName;
|
|
|
39388
39549
|
var LoadingOverlay = ({
|
|
39389
39550
|
isVisible,
|
|
39390
39551
|
message = "Loading...",
|
|
39391
|
-
className
|
|
39552
|
+
className,
|
|
39553
|
+
contentClassName,
|
|
39554
|
+
contentVariant = "card"
|
|
39392
39555
|
}) => {
|
|
39393
39556
|
if (!isVisible) return null;
|
|
39557
|
+
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";
|
|
39394
39558
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
39395
39559
|
motion.div,
|
|
39396
39560
|
{
|
|
@@ -39401,7 +39565,7 @@ var LoadingOverlay = ({
|
|
|
39401
39565
|
className: `fixed inset-0 z-[100] flex items-center justify-center bg-black/30 backdrop-blur-sm ${className || ""}`,
|
|
39402
39566
|
"aria-modal": "true",
|
|
39403
39567
|
role: "dialog",
|
|
39404
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className:
|
|
39568
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: `${contentClasses} ${contentClassName || ""}`, children: /* @__PURE__ */ jsxRuntime.jsx(OptifyeLogoLoader_default, { size: "md", message }) })
|
|
39405
39569
|
}
|
|
39406
39570
|
);
|
|
39407
39571
|
};
|
|
@@ -60731,6 +60895,325 @@ var HelpView = ({
|
|
|
60731
60895
|
};
|
|
60732
60896
|
var AuthenticatedHelpView = withAuth(HelpView);
|
|
60733
60897
|
var HelpView_default = HelpView;
|
|
60898
|
+
var transformActiveBreaks = (activeBreaksByLine) => {
|
|
60899
|
+
if (!activeBreaksByLine) return [];
|
|
60900
|
+
return Object.values(activeBreaksByLine).flat().map((item) => ({
|
|
60901
|
+
lineId: item.line_id,
|
|
60902
|
+
shiftName: item.shift_name || "",
|
|
60903
|
+
startTime: item.start_time,
|
|
60904
|
+
endTime: item.end_time,
|
|
60905
|
+
duration: item.duration || 0,
|
|
60906
|
+
remarks: item.remarks || "",
|
|
60907
|
+
elapsedMinutes: item.elapsed_minutes || 0,
|
|
60908
|
+
remainingMinutes: item.remaining_minutes || 0
|
|
60909
|
+
})).sort((left, right) => {
|
|
60910
|
+
if (left.lineId !== right.lineId) return left.lineId.localeCompare(right.lineId);
|
|
60911
|
+
if (left.shiftName !== right.shiftName) return left.shiftName.localeCompare(right.shiftName);
|
|
60912
|
+
return left.startTime.localeCompare(right.startTime);
|
|
60913
|
+
});
|
|
60914
|
+
};
|
|
60915
|
+
var createEmptyState = () => ({
|
|
60916
|
+
requestKey: null,
|
|
60917
|
+
resolvedScope: [],
|
|
60918
|
+
scopeKey: null,
|
|
60919
|
+
lines: [],
|
|
60920
|
+
workspaceMetrics: [],
|
|
60921
|
+
lineMetrics: [],
|
|
60922
|
+
kpiTrend: null,
|
|
60923
|
+
activeBreaks: [],
|
|
60924
|
+
videoStreamsByWorkspaceId: {},
|
|
60925
|
+
efficiencyLegend: null,
|
|
60926
|
+
metadata: {}
|
|
60927
|
+
});
|
|
60928
|
+
var normalizeMetadata = (metadata) => ({
|
|
60929
|
+
hasFlowBuffers: Boolean(metadata?.has_flow_buffers),
|
|
60930
|
+
idleTimeVlmByLine: metadata?.idle_time_vlm_by_line ?? {},
|
|
60931
|
+
generatedAt: metadata?.generated_at,
|
|
60932
|
+
cacheStatus: metadata?.cache_status,
|
|
60933
|
+
warnings: metadata?.warnings ?? []
|
|
60934
|
+
});
|
|
60935
|
+
var useLiveMonitorBootstrap = ({
|
|
60936
|
+
lineIds,
|
|
60937
|
+
companyId,
|
|
60938
|
+
enabled = true,
|
|
60939
|
+
appTimezone,
|
|
60940
|
+
workspaceConfig,
|
|
60941
|
+
fallbackShiftConfig,
|
|
60942
|
+
lineShiftConfigs
|
|
60943
|
+
}) => {
|
|
60944
|
+
const supabase = useSupabase();
|
|
60945
|
+
const entityConfig = useEntityConfig();
|
|
60946
|
+
const { hydrateFromBackend } = useIdleTimeVlmConfig();
|
|
60947
|
+
const resolvedCompanyId = companyId || entityConfig?.companyId;
|
|
60948
|
+
const effectiveWorkspaceConfig = workspaceConfig || DEFAULT_WORKSPACE_CONFIG;
|
|
60949
|
+
const effectiveTimezone = appTimezone || "Asia/Kolkata";
|
|
60950
|
+
const rawLineIdsKey = (lineIds || []).filter(Boolean).join(",");
|
|
60951
|
+
const normalizedLineIds = React143.useMemo(
|
|
60952
|
+
() => Array.from(new Set(rawLineIdsKey ? rawLineIdsKey.split(",") : [])),
|
|
60953
|
+
[rawLineIdsKey]
|
|
60954
|
+
);
|
|
60955
|
+
const requestKey = React143.useMemo(
|
|
60956
|
+
() => normalizedLineIds.slice().sort().join(","),
|
|
60957
|
+
[normalizedLineIds]
|
|
60958
|
+
);
|
|
60959
|
+
const [state, setState] = React143.useState(() => createEmptyState());
|
|
60960
|
+
const [isLoading, setIsLoading] = React143.useState(false);
|
|
60961
|
+
const [error, setError] = React143.useState(null);
|
|
60962
|
+
const activeRequestIdRef = React143.useRef(0);
|
|
60963
|
+
const fetchBootstrap = React143.useCallback(async (force = false) => {
|
|
60964
|
+
if (!enabled || !supabase || !resolvedCompanyId || normalizedLineIds.length === 0) {
|
|
60965
|
+
return;
|
|
60966
|
+
}
|
|
60967
|
+
const requestId = ++activeRequestIdRef.current;
|
|
60968
|
+
setIsLoading(true);
|
|
60969
|
+
setError(null);
|
|
60970
|
+
try {
|
|
60971
|
+
const searchParams = new URLSearchParams();
|
|
60972
|
+
searchParams.set("company_id", resolvedCompanyId);
|
|
60973
|
+
searchParams.set("line_ids", normalizedLineIds.join(","));
|
|
60974
|
+
if (force) {
|
|
60975
|
+
searchParams.set("force_refresh", "true");
|
|
60976
|
+
}
|
|
60977
|
+
const response = await fetchBackendJson(
|
|
60978
|
+
supabase,
|
|
60979
|
+
`/api/dashboard/monitor-bootstrap?${searchParams.toString()}`,
|
|
60980
|
+
{
|
|
60981
|
+
method: "GET",
|
|
60982
|
+
timeoutMs: 2e4,
|
|
60983
|
+
retries: 0,
|
|
60984
|
+
dedupeKey: `monitor-bootstrap::${requestKey}::${force ? "force" : "cached"}`
|
|
60985
|
+
}
|
|
60986
|
+
);
|
|
60987
|
+
if (requestId !== activeRequestIdRef.current) {
|
|
60988
|
+
return;
|
|
60989
|
+
}
|
|
60990
|
+
const workspaceMetrics = transformMonitorWorkspaceMetrics({
|
|
60991
|
+
rows: response.workspace_metrics || [],
|
|
60992
|
+
companyId: resolvedCompanyId,
|
|
60993
|
+
workspaceConfig: effectiveWorkspaceConfig,
|
|
60994
|
+
appTimezone: effectiveTimezone,
|
|
60995
|
+
lineMetrics: response.line_metrics || [],
|
|
60996
|
+
resolveShiftConfig: (lineId) => lineShiftConfigs?.get(lineId) || fallbackShiftConfig,
|
|
60997
|
+
shouldOverrideShiftType: (lineId) => Boolean(lineShiftConfigs?.get(lineId)),
|
|
60998
|
+
fallbackShiftConfig
|
|
60999
|
+
});
|
|
61000
|
+
const activeBreaks = transformActiveBreaks(response.active_breaks_by_line);
|
|
61001
|
+
const metadata = normalizeMetadata(response.metadata);
|
|
61002
|
+
const workspaceIds = workspaceMetrics.map((metric) => metric.workspace_uuid).filter((workspaceId) => Boolean(workspaceId));
|
|
61003
|
+
const videoStreamsByWorkspaceId = response.video_streams_by_workspace_id || {};
|
|
61004
|
+
if (metadata.idleTimeVlmByLine) {
|
|
61005
|
+
hydrateFromBackend(metadata.idleTimeVlmByLine);
|
|
61006
|
+
}
|
|
61007
|
+
workspaceService.primeWorkspaceVideoStreamsCache({
|
|
61008
|
+
streams: videoStreamsByWorkspaceId,
|
|
61009
|
+
workspaceIds,
|
|
61010
|
+
lineIds: normalizedLineIds
|
|
61011
|
+
});
|
|
61012
|
+
setState({
|
|
61013
|
+
requestKey,
|
|
61014
|
+
resolvedScope: response.resolved_scope || [],
|
|
61015
|
+
scopeKey: response.scope_key || null,
|
|
61016
|
+
lines: response.lines || [],
|
|
61017
|
+
workspaceMetrics,
|
|
61018
|
+
lineMetrics: response.line_metrics || [],
|
|
61019
|
+
kpiTrend: response.kpi_trend || null,
|
|
61020
|
+
activeBreaks,
|
|
61021
|
+
videoStreamsByWorkspaceId,
|
|
61022
|
+
efficiencyLegend: response.efficiency_legend || null,
|
|
61023
|
+
metadata
|
|
61024
|
+
});
|
|
61025
|
+
} catch (fetchError) {
|
|
61026
|
+
if (requestId !== activeRequestIdRef.current) {
|
|
61027
|
+
return;
|
|
61028
|
+
}
|
|
61029
|
+
setError(fetchError instanceof Error ? fetchError : new Error("Failed to load live monitor bootstrap"));
|
|
61030
|
+
} finally {
|
|
61031
|
+
if (requestId === activeRequestIdRef.current) {
|
|
61032
|
+
setIsLoading(false);
|
|
61033
|
+
}
|
|
61034
|
+
}
|
|
61035
|
+
}, [
|
|
61036
|
+
enabled,
|
|
61037
|
+
supabase,
|
|
61038
|
+
resolvedCompanyId,
|
|
61039
|
+
normalizedLineIds,
|
|
61040
|
+
requestKey,
|
|
61041
|
+
hydrateFromBackend,
|
|
61042
|
+
effectiveWorkspaceConfig,
|
|
61043
|
+
effectiveTimezone,
|
|
61044
|
+
lineShiftConfigs,
|
|
61045
|
+
fallbackShiftConfig
|
|
61046
|
+
]);
|
|
61047
|
+
React143.useEffect(() => {
|
|
61048
|
+
if (!enabled) {
|
|
61049
|
+
setIsLoading(false);
|
|
61050
|
+
return;
|
|
61051
|
+
}
|
|
61052
|
+
if (!resolvedCompanyId || normalizedLineIds.length === 0 || !supabase) {
|
|
61053
|
+
setState(createEmptyState());
|
|
61054
|
+
setIsLoading(false);
|
|
61055
|
+
setError(null);
|
|
61056
|
+
return;
|
|
61057
|
+
}
|
|
61058
|
+
void fetchBootstrap(false);
|
|
61059
|
+
}, [enabled, resolvedCompanyId, normalizedLineIds, supabase, fetchBootstrap]);
|
|
61060
|
+
React143.useEffect(() => {
|
|
61061
|
+
if (!enabled || !resolvedCompanyId || normalizedLineIds.length === 0 || !supabase) {
|
|
61062
|
+
return void 0;
|
|
61063
|
+
}
|
|
61064
|
+
let intervalId = null;
|
|
61065
|
+
let timeoutId = null;
|
|
61066
|
+
const runMinuteTick = () => {
|
|
61067
|
+
void fetchBootstrap(true);
|
|
61068
|
+
};
|
|
61069
|
+
const startInterval = () => {
|
|
61070
|
+
runMinuteTick();
|
|
61071
|
+
intervalId = window.setInterval(runMinuteTick, 6e4);
|
|
61072
|
+
};
|
|
61073
|
+
const msUntilNextMinute = (() => {
|
|
61074
|
+
const remainder = Date.now() % 6e4;
|
|
61075
|
+
return remainder === 0 ? 6e4 : 6e4 - remainder;
|
|
61076
|
+
})();
|
|
61077
|
+
timeoutId = window.setTimeout(startInterval, msUntilNextMinute);
|
|
61078
|
+
return () => {
|
|
61079
|
+
if (timeoutId !== null) {
|
|
61080
|
+
window.clearTimeout(timeoutId);
|
|
61081
|
+
}
|
|
61082
|
+
if (intervalId !== null) {
|
|
61083
|
+
window.clearInterval(intervalId);
|
|
61084
|
+
}
|
|
61085
|
+
};
|
|
61086
|
+
}, [enabled, resolvedCompanyId, normalizedLineIds, supabase, fetchBootstrap]);
|
|
61087
|
+
const isCurrentScopeResolved = state.requestKey === requestKey;
|
|
61088
|
+
return {
|
|
61089
|
+
resolvedScope: state.resolvedScope,
|
|
61090
|
+
scopeKey: state.scopeKey,
|
|
61091
|
+
lines: state.lines,
|
|
61092
|
+
workspaceMetrics: state.workspaceMetrics,
|
|
61093
|
+
lineMetrics: state.lineMetrics,
|
|
61094
|
+
kpiTrend: state.kpiTrend,
|
|
61095
|
+
activeBreaks: state.activeBreaks,
|
|
61096
|
+
videoStreamsByWorkspaceId: state.videoStreamsByWorkspaceId,
|
|
61097
|
+
efficiencyLegend: state.efficiencyLegend,
|
|
61098
|
+
metadata: state.metadata,
|
|
61099
|
+
isLoading: enabled ? isLoading || !isCurrentScopeResolved : false,
|
|
61100
|
+
isCurrentScopeResolved,
|
|
61101
|
+
error,
|
|
61102
|
+
refetch: () => fetchBootstrap(true)
|
|
61103
|
+
};
|
|
61104
|
+
};
|
|
61105
|
+
|
|
61106
|
+
// src/lib/utils/liveMonitorBootstrap.ts
|
|
61107
|
+
var toNumber3 = (value) => {
|
|
61108
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
61109
|
+
if (typeof value === "string" && value.trim() !== "") {
|
|
61110
|
+
const parsed = Number(value);
|
|
61111
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
61112
|
+
}
|
|
61113
|
+
return 0;
|
|
61114
|
+
};
|
|
61115
|
+
var normalizeNullableNumber = (value) => {
|
|
61116
|
+
if (value === null || value === void 0 || value === "") return null;
|
|
61117
|
+
return toNumber3(value);
|
|
61118
|
+
};
|
|
61119
|
+
var getLiveMonitorBootstrapMode = () => {
|
|
61120
|
+
const rawMode = (process.env.NEXT_PUBLIC_MONITOR_BOOTSTRAP_MODE || "").trim().toLowerCase();
|
|
61121
|
+
if (rawMode === "legacy" || rawMode === "shadow" || rawMode === "bootstrap") {
|
|
61122
|
+
return rawMode;
|
|
61123
|
+
}
|
|
61124
|
+
return "bootstrap";
|
|
61125
|
+
};
|
|
61126
|
+
var normalizeMonitorShadowSnapshot = (input) => {
|
|
61127
|
+
const sortedSelectedLineIds = Array.from(new Set((input.selectedLineIds || []).filter(Boolean))).sort();
|
|
61128
|
+
const resolvedScope = (input.resolvedScope || []).filter((entry) => entry?.line_id && entry?.date && entry?.shift_id !== void 0 && entry?.shift_id !== null).map((entry) => ({
|
|
61129
|
+
line_id: entry.line_id,
|
|
61130
|
+
date: entry.date,
|
|
61131
|
+
shift_id: entry.shift_id
|
|
61132
|
+
})).sort((left, right) => {
|
|
61133
|
+
if (left.line_id !== right.line_id) return left.line_id.localeCompare(right.line_id);
|
|
61134
|
+
if (left.date !== right.date) return left.date.localeCompare(right.date);
|
|
61135
|
+
return left.shift_id - right.shift_id;
|
|
61136
|
+
});
|
|
61137
|
+
const lines = (input.lines || []).filter((entry) => entry?.line_id).map((entry) => ({
|
|
61138
|
+
line_id: entry.line_id,
|
|
61139
|
+
line_name: entry.line_name || "Unknown Line"
|
|
61140
|
+
})).sort((left, right) => left.line_id.localeCompare(right.line_id));
|
|
61141
|
+
const workspaces = (input.workspaces || []).map((workspace) => {
|
|
61142
|
+
const workspaceId = workspace.workspace_uuid || null;
|
|
61143
|
+
const stream = workspaceId ? input.videoStreamsByWorkspaceId?.[workspaceId] || null : null;
|
|
61144
|
+
return {
|
|
61145
|
+
workspace_id: workspaceId,
|
|
61146
|
+
line_id: workspace.line_id,
|
|
61147
|
+
workspace_name: workspace.workspace_name,
|
|
61148
|
+
display_name: workspace.displayName || null,
|
|
61149
|
+
efficiency: toNumber3(workspace.efficiency),
|
|
61150
|
+
trend: toNumber3(workspace.trend),
|
|
61151
|
+
show_exclamation: Boolean(workspace.show_exclamation),
|
|
61152
|
+
scheduled_break_active: Boolean(workspace.scheduled_break_active),
|
|
61153
|
+
action_count: toNumber3(workspace.action_count),
|
|
61154
|
+
action_threshold: toNumber3(workspace.action_threshold),
|
|
61155
|
+
predicted_output: toNumber3(workspace.predicted_output),
|
|
61156
|
+
avg_cycle_time: toNumber3(workspace.avg_cycle_time),
|
|
61157
|
+
pph: toNumber3(workspace.pph),
|
|
61158
|
+
recent_flow_percent: normalizeNullableNumber(workspace.recent_flow_percent),
|
|
61159
|
+
incoming_wip_current: normalizeNullableNumber(workspace.incoming_wip_current),
|
|
61160
|
+
video_stream: stream ? {
|
|
61161
|
+
workspace_id: stream.workspace_id,
|
|
61162
|
+
camera_uuid: stream.camera_uuid,
|
|
61163
|
+
stream_camera_uuid: stream.stream_camera_uuid,
|
|
61164
|
+
hls_url: stream.hls_url,
|
|
61165
|
+
crop: stream.crop
|
|
61166
|
+
} : null
|
|
61167
|
+
};
|
|
61168
|
+
}).sort((left, right) => {
|
|
61169
|
+
if (left.line_id !== right.line_id) return left.line_id.localeCompare(right.line_id);
|
|
61170
|
+
return left.workspace_name.localeCompare(right.workspace_name, void 0, { numeric: true });
|
|
61171
|
+
});
|
|
61172
|
+
const activeBreaks = (input.activeBreaks || []).map((activeBreak) => ({
|
|
61173
|
+
lineId: activeBreak.lineId,
|
|
61174
|
+
shiftName: activeBreak.shiftName,
|
|
61175
|
+
startTime: activeBreak.startTime,
|
|
61176
|
+
endTime: activeBreak.endTime,
|
|
61177
|
+
remainingMinutes: toNumber3(activeBreak.remainingMinutes)
|
|
61178
|
+
})).sort((left, right) => {
|
|
61179
|
+
if (left.lineId !== right.lineId) return left.lineId.localeCompare(right.lineId);
|
|
61180
|
+
if (left.shiftName !== right.shiftName) return left.shiftName.localeCompare(right.shiftName);
|
|
61181
|
+
return left.startTime.localeCompare(right.startTime);
|
|
61182
|
+
});
|
|
61183
|
+
return {
|
|
61184
|
+
selectedLineIds: sortedSelectedLineIds,
|
|
61185
|
+
resolvedScope,
|
|
61186
|
+
lines,
|
|
61187
|
+
workspaces,
|
|
61188
|
+
activeBreaks,
|
|
61189
|
+
kpis: input.kpis || null,
|
|
61190
|
+
kpiTrend: input.kpiTrend || null,
|
|
61191
|
+
efficiencyLegend: input.efficiencyLegend || null
|
|
61192
|
+
};
|
|
61193
|
+
};
|
|
61194
|
+
var diffMonitorShadowSnapshots = (legacySnapshot, bootstrapSnapshot) => {
|
|
61195
|
+
const mismatches = [];
|
|
61196
|
+
const compareSection = (section) => {
|
|
61197
|
+
const legacyValue = legacySnapshot[section];
|
|
61198
|
+
const bootstrapValue = bootstrapSnapshot[section];
|
|
61199
|
+
if (JSON.stringify(legacyValue) !== JSON.stringify(bootstrapValue)) {
|
|
61200
|
+
mismatches.push({
|
|
61201
|
+
section,
|
|
61202
|
+
legacy: legacyValue,
|
|
61203
|
+
bootstrap: bootstrapValue
|
|
61204
|
+
});
|
|
61205
|
+
}
|
|
61206
|
+
};
|
|
61207
|
+
compareSection("selectedLineIds");
|
|
61208
|
+
compareSection("resolvedScope");
|
|
61209
|
+
compareSection("lines");
|
|
61210
|
+
compareSection("workspaces");
|
|
61211
|
+
compareSection("activeBreaks");
|
|
61212
|
+
compareSection("kpis");
|
|
61213
|
+
compareSection("kpiTrend");
|
|
61214
|
+
compareSection("efficiencyLegend");
|
|
61215
|
+
return mismatches;
|
|
61216
|
+
};
|
|
60734
61217
|
|
|
60735
61218
|
// src/lib/services/notificationService.ts
|
|
60736
61219
|
var API_BASE_URL = process.env.NEXT_PUBLIC_BACKEND_URL;
|
|
@@ -60872,7 +61355,10 @@ var logDebug3 = (...args) => {
|
|
|
60872
61355
|
if (!DEBUG_DASHBOARD_LOGS3) return;
|
|
60873
61356
|
console.log(...args);
|
|
60874
61357
|
};
|
|
61358
|
+
var EMPTY_LINE_IDS = [];
|
|
61359
|
+
var EMPTY_WORKSPACES = [];
|
|
60875
61360
|
var LoadingPageCmp = LoadingPage_default;
|
|
61361
|
+
var LoadingOverlayCmp = LoadingOverlay_default;
|
|
60876
61362
|
function HomeView({
|
|
60877
61363
|
defaultLineId,
|
|
60878
61364
|
factoryViewId,
|
|
@@ -61020,6 +61506,7 @@ function HomeView({
|
|
|
61020
61506
|
return createNotificationService(supabaseClient);
|
|
61021
61507
|
}, [supabaseClient]);
|
|
61022
61508
|
const [bottleneckNotification, setBottleneckNotification] = React143.useState(null);
|
|
61509
|
+
const showBottleneckNotificationRef = React143.useRef(null);
|
|
61023
61510
|
const [bottleneckModalOpen, setBottleneckModalOpen] = React143.useState(false);
|
|
61024
61511
|
const [bottleneckModalData, setBottleneckModalData] = React143.useState(null);
|
|
61025
61512
|
const [diagnosisModalOpen, setDiagnosisModalOpen] = React143.useState(false);
|
|
@@ -61030,6 +61517,11 @@ function HomeView({
|
|
|
61030
61517
|
dashboardConfig?.shiftConfig
|
|
61031
61518
|
);
|
|
61032
61519
|
const shouldEnableMetricsFetch = authStatus === "ready";
|
|
61520
|
+
const liveMonitorMode = React143.useMemo(() => getLiveMonitorBootstrapMode(), []);
|
|
61521
|
+
const isLegacyMonitorMode = liveMonitorMode === "legacy";
|
|
61522
|
+
const isShadowMonitorMode = liveMonitorMode === "shadow";
|
|
61523
|
+
const isBootstrapMonitorMode = liveMonitorMode === "bootstrap";
|
|
61524
|
+
const lastShadowMismatchSignatureRef = React143.useRef(null);
|
|
61033
61525
|
const handleLineMetricsUpdate = React143.useCallback(() => {
|
|
61034
61526
|
if (trendRefreshTimerRef.current) {
|
|
61035
61527
|
window.clearTimeout(trendRefreshTimerRef.current);
|
|
@@ -61045,45 +61537,24 @@ function HomeView({
|
|
|
61045
61537
|
}
|
|
61046
61538
|
}, []);
|
|
61047
61539
|
const {
|
|
61048
|
-
workspaceMetrics,
|
|
61049
|
-
lineMetrics,
|
|
61050
|
-
efficiencyLegend,
|
|
61051
|
-
metadata:
|
|
61052
|
-
isLoading:
|
|
61053
|
-
|
|
61054
|
-
|
|
61540
|
+
workspaceMetrics: legacyWorkspaceMetrics,
|
|
61541
|
+
lineMetrics: legacyLineMetrics,
|
|
61542
|
+
efficiencyLegend: legacyEfficiencyLegend,
|
|
61543
|
+
metadata: legacyMetricsMetadata,
|
|
61544
|
+
isLoading: legacyMetricsLoading,
|
|
61545
|
+
isCurrentScopeResolved: legacyIsCurrentScopeResolved,
|
|
61546
|
+
error: legacyMetricsError,
|
|
61547
|
+
refetch: refetchLegacyMetrics
|
|
61055
61548
|
} = useDashboardMetrics({
|
|
61056
61549
|
lineId: metricsScopeLineId,
|
|
61057
61550
|
lineIds: selectedLineIds,
|
|
61058
61551
|
onLineMetricsUpdate: handleLineMetricsUpdate,
|
|
61059
61552
|
userAccessibleLineIds: visibleLineIds,
|
|
61060
|
-
|
|
61061
|
-
enabled: shouldEnableMetricsFetch
|
|
61553
|
+
enabled: shouldEnableMetricsFetch && !isBootstrapMonitorMode
|
|
61062
61554
|
});
|
|
61063
|
-
const
|
|
61064
|
-
|
|
61065
|
-
|
|
61066
|
-
if (!workspace.displayName) {
|
|
61067
|
-
return;
|
|
61068
|
-
}
|
|
61069
|
-
nextDisplayNames[`${workspace.line_id}_${workspace.workspace_name}`] = workspace.displayName;
|
|
61070
|
-
});
|
|
61071
|
-
return nextDisplayNames;
|
|
61072
|
-
}, [workspaceMetrics]);
|
|
61073
|
-
React143.useEffect(() => {
|
|
61074
|
-
workspaceMetrics.forEach((workspace) => {
|
|
61075
|
-
if (!workspace.displayName) {
|
|
61076
|
-
return;
|
|
61077
|
-
}
|
|
61078
|
-
upsertWorkspaceDisplayNameInCache({
|
|
61079
|
-
lineId: workspace.line_id,
|
|
61080
|
-
workspaceId: workspace.workspace_name,
|
|
61081
|
-
displayName: workspace.displayName
|
|
61082
|
-
});
|
|
61083
|
-
});
|
|
61084
|
-
}, [workspaceMetrics]);
|
|
61085
|
-
const trendGroups = React143.useMemo(() => {
|
|
61086
|
-
const lineMetricsRows = lineMetrics || [];
|
|
61555
|
+
const legacyTrendGroups = React143.useMemo(() => {
|
|
61556
|
+
if (isBootstrapMonitorMode) return null;
|
|
61557
|
+
const lineMetricsRows = legacyLineMetrics || [];
|
|
61087
61558
|
if (!lineMetricsRows.length) return null;
|
|
61088
61559
|
if (selectedLineIds.length > 1) {
|
|
61089
61560
|
const rowsForLines = lineMetricsRows.filter((row2) => selectedLineIdSet.has(row2?.line_id));
|
|
@@ -61109,7 +61580,7 @@ function HomeView({
|
|
|
61109
61580
|
shiftId: group.shiftId
|
|
61110
61581
|
}));
|
|
61111
61582
|
}
|
|
61112
|
-
const row = lineMetricsRows.find((
|
|
61583
|
+
const row = lineMetricsRows.find((candidate) => candidate?.line_id === primarySelectedLineId);
|
|
61113
61584
|
if (!row?.date || row?.shift_id === void 0 || row?.shift_id === null) {
|
|
61114
61585
|
return null;
|
|
61115
61586
|
}
|
|
@@ -61118,69 +61589,119 @@ function HomeView({
|
|
|
61118
61589
|
date: row.date,
|
|
61119
61590
|
shiftId: row.shift_id
|
|
61120
61591
|
}];
|
|
61121
|
-
}, [
|
|
61122
|
-
const
|
|
61123
|
-
if (!
|
|
61592
|
+
}, [isBootstrapMonitorMode, legacyLineMetrics, primarySelectedLineId, selectedLineIdSet, selectedLineIds.length]);
|
|
61593
|
+
const legacyTrendOptions = React143.useMemo(() => {
|
|
61594
|
+
if (isBootstrapMonitorMode || !legacyTrendGroups || !userCompanyId) return null;
|
|
61124
61595
|
return {
|
|
61125
|
-
groups:
|
|
61596
|
+
groups: legacyTrendGroups,
|
|
61126
61597
|
companyId: userCompanyId,
|
|
61127
61598
|
refreshKey: trendRefreshKey,
|
|
61128
61599
|
forceRefresh: trendRefreshKey > 0
|
|
61129
61600
|
};
|
|
61130
|
-
}, [
|
|
61131
|
-
const { trend:
|
|
61132
|
-
const
|
|
61601
|
+
}, [isBootstrapMonitorMode, legacyTrendGroups, userCompanyId, trendRefreshKey]);
|
|
61602
|
+
const { trend: legacyKpiTrend } = useKpiTrends(legacyTrendOptions);
|
|
61603
|
+
const bootstrapMonitor = useLiveMonitorBootstrap({
|
|
61604
|
+
lineIds: selectedLineIds,
|
|
61605
|
+
companyId: userCompanyId,
|
|
61606
|
+
enabled: shouldEnableMetricsFetch && !isLegacyMonitorMode,
|
|
61607
|
+
appTimezone: timezone,
|
|
61608
|
+
workspaceConfig: dashboardConfig?.workspaceConfig,
|
|
61609
|
+
fallbackShiftConfig: dashboardConfig?.shiftConfig,
|
|
61610
|
+
lineShiftConfigs
|
|
61611
|
+
});
|
|
61612
|
+
const currentWorkspaceMetrics = isBootstrapMonitorMode ? bootstrapMonitor.workspaceMetrics : legacyWorkspaceMetrics;
|
|
61613
|
+
const currentLineMetrics = isBootstrapMonitorMode ? bootstrapMonitor.lineMetrics : legacyLineMetrics;
|
|
61614
|
+
const currentEfficiencyLegend = isBootstrapMonitorMode ? bootstrapMonitor.efficiencyLegend : legacyEfficiencyLegend;
|
|
61615
|
+
const currentMetricsMetadata = isBootstrapMonitorMode ? bootstrapMonitor.metadata : legacyMetricsMetadata;
|
|
61616
|
+
const currentMetricsLoading = isBootstrapMonitorMode ? bootstrapMonitor.isLoading : legacyMetricsLoading;
|
|
61617
|
+
const currentIsCurrentScopeResolved = isBootstrapMonitorMode ? bootstrapMonitor.isCurrentScopeResolved : legacyIsCurrentScopeResolved;
|
|
61618
|
+
const currentMetricsError = isBootstrapMonitorMode ? bootstrapMonitor.error : legacyMetricsError;
|
|
61619
|
+
const currentRefetchMetrics = isBootstrapMonitorMode ? bootstrapMonitor.refetch : refetchLegacyMetrics;
|
|
61620
|
+
const metricsDisplayNames = React143.useMemo(() => {
|
|
61621
|
+
const nextDisplayNames = {};
|
|
61622
|
+
currentWorkspaceMetrics.forEach((workspace) => {
|
|
61623
|
+
if (!workspace.displayName) {
|
|
61624
|
+
return;
|
|
61625
|
+
}
|
|
61626
|
+
nextDisplayNames[`${workspace.line_id}_${workspace.workspace_name}`] = workspace.displayName;
|
|
61627
|
+
});
|
|
61628
|
+
return nextDisplayNames;
|
|
61629
|
+
}, [currentWorkspaceMetrics]);
|
|
61133
61630
|
React143.useEffect(() => {
|
|
61134
|
-
|
|
61631
|
+
currentWorkspaceMetrics.forEach((workspace) => {
|
|
61632
|
+
if (!workspace.displayName) {
|
|
61633
|
+
return;
|
|
61634
|
+
}
|
|
61635
|
+
upsertWorkspaceDisplayNameInCache({
|
|
61636
|
+
lineId: workspace.line_id,
|
|
61637
|
+
workspaceId: workspace.workspace_name,
|
|
61638
|
+
displayName: workspace.displayName
|
|
61639
|
+
});
|
|
61640
|
+
});
|
|
61641
|
+
}, [currentWorkspaceMetrics]);
|
|
61642
|
+
const hasFlowBuffers = Boolean(currentMetricsMetadata?.hasFlowBuffers);
|
|
61643
|
+
React143.useEffect(() => {
|
|
61644
|
+
const sample = currentWorkspaceMetrics.slice(0, 3).map((workspace) => ({
|
|
61135
61645
|
id: workspace.workspace_uuid || workspace.workspace_name,
|
|
61136
61646
|
efficiency: workspace.efficiency,
|
|
61137
61647
|
trend: workspace.trend,
|
|
61138
61648
|
lineId: workspace.line_id
|
|
61139
61649
|
}));
|
|
61140
61650
|
logDebug3("[HomeView] workspaceMetrics update:", {
|
|
61141
|
-
count:
|
|
61142
|
-
isLoading:
|
|
61143
|
-
error:
|
|
61651
|
+
count: currentWorkspaceMetrics.length,
|
|
61652
|
+
isLoading: currentMetricsLoading,
|
|
61653
|
+
error: currentMetricsError?.message,
|
|
61144
61654
|
sample
|
|
61145
61655
|
});
|
|
61146
|
-
}, [
|
|
61147
|
-
const
|
|
61148
|
-
const lineMetricsRows =
|
|
61656
|
+
}, [currentWorkspaceMetrics, currentMetricsLoading, currentMetricsError]);
|
|
61657
|
+
const buildDisplayKpis = React143.useCallback((sourceLineMetrics, sourceIsLoading, sourceKpiTrend) => {
|
|
61658
|
+
const lineMetricsRows = sourceLineMetrics || [];
|
|
61659
|
+
let baseKpis = null;
|
|
61149
61660
|
if (selectedLineIds.length > 1) {
|
|
61150
|
-
const rowsForSelectedLines = lineMetricsRows.filter((
|
|
61151
|
-
if (
|
|
61152
|
-
|
|
61153
|
-
}
|
|
61154
|
-
|
|
61155
|
-
|
|
61156
|
-
|
|
61157
|
-
|
|
61158
|
-
|
|
61159
|
-
|
|
61160
|
-
|
|
61161
|
-
|
|
61162
|
-
if (!
|
|
61163
|
-
|
|
61661
|
+
const rowsForSelectedLines = lineMetricsRows.filter((row) => selectedLineIdSet.has(row?.line_id));
|
|
61662
|
+
if (sourceIsLoading && rowsForSelectedLines.length === 0) return null;
|
|
61663
|
+
baseKpis = aggregateKPIsFromLineMetricsRows(rowsForSelectedLines);
|
|
61664
|
+
} else {
|
|
61665
|
+
const row = lineMetricsRows.find((candidate) => candidate?.line_id === primarySelectedLineId);
|
|
61666
|
+
if (!row) {
|
|
61667
|
+
if (sourceIsLoading) return null;
|
|
61668
|
+
baseKpis = buildKPIsFromLineMetricsRow(null);
|
|
61669
|
+
} else {
|
|
61670
|
+
baseKpis = buildKPIsFromLineMetricsRow(row);
|
|
61671
|
+
}
|
|
61672
|
+
}
|
|
61673
|
+
if (!baseKpis || !sourceKpiTrend) {
|
|
61674
|
+
return baseKpis;
|
|
61675
|
+
}
|
|
61164
61676
|
return {
|
|
61165
|
-
...
|
|
61677
|
+
...baseKpis,
|
|
61166
61678
|
efficiency: {
|
|
61167
|
-
...
|
|
61168
|
-
change:
|
|
61679
|
+
...baseKpis.efficiency,
|
|
61680
|
+
change: sourceKpiTrend.efficiency?.delta_pp ?? baseKpis.efficiency.change
|
|
61169
61681
|
},
|
|
61170
61682
|
outputProgress: {
|
|
61171
|
-
...
|
|
61172
|
-
change:
|
|
61683
|
+
...baseKpis.outputProgress,
|
|
61684
|
+
change: sourceKpiTrend.outputProgress?.delta_pp ?? baseKpis.outputProgress.change
|
|
61173
61685
|
},
|
|
61174
61686
|
underperformingWorkers: {
|
|
61175
|
-
...
|
|
61176
|
-
change:
|
|
61687
|
+
...baseKpis.underperformingWorkers,
|
|
61688
|
+
change: sourceKpiTrend.underperformingWorkers?.delta_count ?? baseKpis.underperformingWorkers.change
|
|
61177
61689
|
},
|
|
61178
61690
|
avgCycleTime: {
|
|
61179
|
-
...
|
|
61180
|
-
change:
|
|
61691
|
+
...baseKpis.avgCycleTime,
|
|
61692
|
+
change: sourceKpiTrend.avgCycleTime?.delta_seconds ?? baseKpis.avgCycleTime.change
|
|
61181
61693
|
}
|
|
61182
61694
|
};
|
|
61183
|
-
}, [
|
|
61695
|
+
}, [primarySelectedLineId, selectedLineIdSet, selectedLineIds.length]);
|
|
61696
|
+
const legacyKpisWithTrend = React143.useMemo(
|
|
61697
|
+
() => buildDisplayKpis(legacyLineMetrics, legacyMetricsLoading, legacyKpiTrend),
|
|
61698
|
+
[buildDisplayKpis, legacyLineMetrics, legacyMetricsLoading, legacyKpiTrend]
|
|
61699
|
+
);
|
|
61700
|
+
const bootstrapKpisWithTrend = React143.useMemo(
|
|
61701
|
+
() => buildDisplayKpis(bootstrapMonitor.lineMetrics, bootstrapMonitor.isLoading, bootstrapMonitor.kpiTrend),
|
|
61702
|
+
[buildDisplayKpis, bootstrapMonitor.lineMetrics, bootstrapMonitor.isLoading, bootstrapMonitor.kpiTrend]
|
|
61703
|
+
);
|
|
61704
|
+
const currentKpisWithTrend = isBootstrapMonitorMode ? bootstrapKpisWithTrend : legacyKpisWithTrend;
|
|
61184
61705
|
const selectedLineMeta = React143.useMemo(
|
|
61185
61706
|
() => selectedLineIds.length === 1 ? dbLines.find((line) => line.id === primarySelectedLineId) : void 0,
|
|
61186
61707
|
[dbLines, primarySelectedLineId, selectedLineIds.length]
|
|
@@ -61189,40 +61710,121 @@ function HomeView({
|
|
|
61189
61710
|
const isUptimeMode = selectedMonitoringMode === "uptime";
|
|
61190
61711
|
const averageIdleTimeSeconds = React143.useMemo(() => {
|
|
61191
61712
|
if (!isUptimeMode) return null;
|
|
61192
|
-
const targetWorkspaces =
|
|
61713
|
+
const targetWorkspaces = currentWorkspaceMetrics.filter((ws) => ws.line_id === primarySelectedLineId);
|
|
61193
61714
|
const idleValues = targetWorkspaces.map((ws) => ws.idle_time).filter((value) => Number.isFinite(value));
|
|
61194
61715
|
if (idleValues.length === 0) return 0;
|
|
61195
61716
|
const totalIdle = idleValues.reduce((sum, value) => sum + value, 0);
|
|
61196
61717
|
return totalIdle / idleValues.length;
|
|
61197
|
-
}, [isUptimeMode, primarySelectedLineId,
|
|
61718
|
+
}, [isUptimeMode, primarySelectedLineId, currentWorkspaceMetrics]);
|
|
61198
61719
|
const {
|
|
61199
|
-
activeBreaks:
|
|
61200
|
-
isLoading:
|
|
61201
|
-
error:
|
|
61202
|
-
} = useActiveBreaks(visibleLineIds);
|
|
61203
|
-
const
|
|
61720
|
+
activeBreaks: legacyAllActiveBreaks,
|
|
61721
|
+
isLoading: legacyBreaksLoading,
|
|
61722
|
+
error: legacyBreaksError
|
|
61723
|
+
} = useActiveBreaks(isBootstrapMonitorMode ? EMPTY_LINE_IDS : visibleLineIds);
|
|
61724
|
+
const legacyActiveBreaks = React143.useMemo(() => {
|
|
61204
61725
|
if (isAllLinesSelection(selectedLineIds)) {
|
|
61205
|
-
return
|
|
61726
|
+
return legacyAllActiveBreaks;
|
|
61206
61727
|
}
|
|
61207
|
-
return
|
|
61208
|
-
}, [
|
|
61728
|
+
return legacyAllActiveBreaks.filter((breakItem) => selectedLineIdSet.has(breakItem.lineId));
|
|
61729
|
+
}, [legacyAllActiveBreaks, selectedLineIdSet, selectedLineIds]);
|
|
61730
|
+
const currentActiveBreaks = isBootstrapMonitorMode ? bootstrapMonitor.activeBreaks : legacyActiveBreaks;
|
|
61731
|
+
const currentBreaksLoading = isBootstrapMonitorMode ? bootstrapMonitor.isLoading : legacyBreaksLoading;
|
|
61732
|
+
const currentBreaksError = isBootstrapMonitorMode ? bootstrapMonitor.error?.message || null : legacyBreaksError;
|
|
61209
61733
|
const activeBreakLineIds = React143.useMemo(
|
|
61210
|
-
() => new Set(
|
|
61211
|
-
[
|
|
61734
|
+
() => new Set(currentActiveBreaks.map((breakItem) => breakItem.lineId)),
|
|
61735
|
+
[currentActiveBreaks]
|
|
61212
61736
|
);
|
|
61213
61737
|
const workspaceMetricsWithBreakState = React143.useMemo(
|
|
61214
|
-
() =>
|
|
61738
|
+
() => currentWorkspaceMetrics.map((workspace) => ({
|
|
61215
61739
|
...workspace,
|
|
61216
61740
|
scheduled_break_active: activeBreakLineIds.has(workspace.line_id)
|
|
61217
61741
|
})),
|
|
61218
|
-
[
|
|
61742
|
+
[currentWorkspaceMetrics, activeBreakLineIds]
|
|
61219
61743
|
);
|
|
61220
61744
|
const [breakNotificationsDismissed, setBreakNotificationsDismissed] = React143.useState(false);
|
|
61221
61745
|
React143.useEffect(() => {
|
|
61222
|
-
if (
|
|
61746
|
+
if (currentActiveBreaks.length > 0) {
|
|
61223
61747
|
setBreakNotificationsDismissed(false);
|
|
61224
61748
|
}
|
|
61225
|
-
}, [
|
|
61749
|
+
}, [currentActiveBreaks.length]);
|
|
61750
|
+
const {
|
|
61751
|
+
streamsByWorkspaceId: legacyVideoStreamsByWorkspaceId,
|
|
61752
|
+
isLoading: legacyVideoStreamsLoading
|
|
61753
|
+
} = useWorkspaceVideoStreams(isBootstrapMonitorMode ? EMPTY_WORKSPACES : legacyWorkspaceMetrics, {
|
|
61754
|
+
lineIds: isBootstrapMonitorMode ? EMPTY_LINE_IDS : selectedLineIds
|
|
61755
|
+
});
|
|
61756
|
+
const currentVideoStreamsByWorkspaceId = isBootstrapMonitorMode ? bootstrapMonitor.videoStreamsByWorkspaceId : legacyVideoStreamsByWorkspaceId;
|
|
61757
|
+
const currentVideoStreamsLoading = isBootstrapMonitorMode ? bootstrapMonitor.isLoading : legacyVideoStreamsLoading;
|
|
61758
|
+
React143.useEffect(() => {
|
|
61759
|
+
if (!isShadowMonitorMode) {
|
|
61760
|
+
lastShadowMismatchSignatureRef.current = null;
|
|
61761
|
+
return;
|
|
61762
|
+
}
|
|
61763
|
+
if (!shouldEnableMetricsFetch || legacyMetricsLoading || !legacyIsCurrentScopeResolved || bootstrapMonitor.isLoading || !bootstrapMonitor.isCurrentScopeResolved) {
|
|
61764
|
+
return;
|
|
61765
|
+
}
|
|
61766
|
+
const legacySnapshot = normalizeMonitorShadowSnapshot({
|
|
61767
|
+
selectedLineIds,
|
|
61768
|
+
workspaces: workspaceMetricsWithBreakState,
|
|
61769
|
+
kpis: legacyKpisWithTrend,
|
|
61770
|
+
kpiTrend: legacyKpiTrend,
|
|
61771
|
+
activeBreaks: legacyActiveBreaks,
|
|
61772
|
+
videoStreamsByWorkspaceId: legacyVideoStreamsByWorkspaceId,
|
|
61773
|
+
efficiencyLegend: legacyEfficiencyLegend
|
|
61774
|
+
});
|
|
61775
|
+
const bootstrapSnapshot = normalizeMonitorShadowSnapshot({
|
|
61776
|
+
selectedLineIds,
|
|
61777
|
+
resolvedScope: bootstrapMonitor.resolvedScope,
|
|
61778
|
+
lines: bootstrapMonitor.lines,
|
|
61779
|
+
workspaces: bootstrapMonitor.workspaceMetrics.map((workspace) => ({
|
|
61780
|
+
...workspace,
|
|
61781
|
+
scheduled_break_active: bootstrapMonitor.activeBreaks.some((activeBreak) => activeBreak.lineId === workspace.line_id)
|
|
61782
|
+
})),
|
|
61783
|
+
kpis: bootstrapKpisWithTrend,
|
|
61784
|
+
kpiTrend: bootstrapMonitor.kpiTrend,
|
|
61785
|
+
activeBreaks: bootstrapMonitor.activeBreaks,
|
|
61786
|
+
videoStreamsByWorkspaceId: bootstrapMonitor.videoStreamsByWorkspaceId,
|
|
61787
|
+
efficiencyLegend: bootstrapMonitor.efficiencyLegend
|
|
61788
|
+
});
|
|
61789
|
+
const mismatches = diffMonitorShadowSnapshots(legacySnapshot, bootstrapSnapshot);
|
|
61790
|
+
const signature = JSON.stringify(mismatches);
|
|
61791
|
+
if (mismatches.length === 0) {
|
|
61792
|
+
lastShadowMismatchSignatureRef.current = null;
|
|
61793
|
+
return;
|
|
61794
|
+
}
|
|
61795
|
+
if (lastShadowMismatchSignatureRef.current === signature) {
|
|
61796
|
+
return;
|
|
61797
|
+
}
|
|
61798
|
+
lastShadowMismatchSignatureRef.current = signature;
|
|
61799
|
+
console.error("[HomeView][monitor-shadow-mismatch]", {
|
|
61800
|
+
selectedLineIds,
|
|
61801
|
+
mismatches,
|
|
61802
|
+
legacySnapshot,
|
|
61803
|
+
bootstrapSnapshot
|
|
61804
|
+
});
|
|
61805
|
+
}, [
|
|
61806
|
+
bootstrapKpisWithTrend,
|
|
61807
|
+
bootstrapMonitor.activeBreaks,
|
|
61808
|
+
bootstrapMonitor.efficiencyLegend,
|
|
61809
|
+
bootstrapMonitor.isCurrentScopeResolved,
|
|
61810
|
+
bootstrapMonitor.isLoading,
|
|
61811
|
+
bootstrapMonitor.kpiTrend,
|
|
61812
|
+
bootstrapMonitor.lines,
|
|
61813
|
+
bootstrapMonitor.resolvedScope,
|
|
61814
|
+
bootstrapMonitor.videoStreamsByWorkspaceId,
|
|
61815
|
+
bootstrapMonitor.workspaceMetrics,
|
|
61816
|
+
isShadowMonitorMode,
|
|
61817
|
+
legacyActiveBreaks,
|
|
61818
|
+
legacyEfficiencyLegend,
|
|
61819
|
+
legacyIsCurrentScopeResolved,
|
|
61820
|
+
legacyKpiTrend,
|
|
61821
|
+
legacyKpisWithTrend,
|
|
61822
|
+
legacyMetricsLoading,
|
|
61823
|
+
legacyVideoStreamsByWorkspaceId,
|
|
61824
|
+
selectedLineIds,
|
|
61825
|
+
shouldEnableMetricsFetch,
|
|
61826
|
+
workspaceMetricsWithBreakState
|
|
61827
|
+
]);
|
|
61226
61828
|
const showBottleneckNotification = React143.useCallback(async (bottleneck) => {
|
|
61227
61829
|
try {
|
|
61228
61830
|
logDebug3("\u{1F514} [Notification] Raw bottleneck data:", bottleneck);
|
|
@@ -61400,6 +62002,9 @@ function HomeView({
|
|
|
61400
62002
|
setBottleneckNotification(errorNotification);
|
|
61401
62003
|
}
|
|
61402
62004
|
}, [notificationService, timezone, dashboardConfig, lineShiftConfigs]);
|
|
62005
|
+
React143.useEffect(() => {
|
|
62006
|
+
showBottleneckNotificationRef.current = showBottleneckNotification;
|
|
62007
|
+
}, [showBottleneckNotification]);
|
|
61403
62008
|
React143.useEffect(() => {
|
|
61404
62009
|
const ticketsEnabled = dashboardConfig?.ticketsConfig?.enabled ?? true;
|
|
61405
62010
|
if (!ticketsEnabled) {
|
|
@@ -61469,7 +62074,7 @@ function HomeView({
|
|
|
61469
62074
|
});
|
|
61470
62075
|
if (latestTicket.event_type === "bottleneck") {
|
|
61471
62076
|
logDebug3("\u{1F514} [Polling] Showing bottleneck notification for:", latestTicket.log_number);
|
|
61472
|
-
|
|
62077
|
+
await showBottleneckNotificationRef.current?.(latestTicket);
|
|
61473
62078
|
} else {
|
|
61474
62079
|
logDebug3("\u26A0\uFE0F [Polling] Non-bottleneck ticket found but no handler configured:", latestTicket.event_type);
|
|
61475
62080
|
}
|
|
@@ -61489,29 +62094,30 @@ function HomeView({
|
|
|
61489
62094
|
clearInterval(pollInterval);
|
|
61490
62095
|
clearTimeout(initialPollTimer);
|
|
61491
62096
|
};
|
|
61492
|
-
}, [
|
|
62097
|
+
}, [
|
|
62098
|
+
dashboardConfig?.ticketsConfig?.enabled,
|
|
62099
|
+
notificationService,
|
|
62100
|
+
user?.email,
|
|
62101
|
+
user?.role_level,
|
|
62102
|
+
userCompanyId
|
|
62103
|
+
]);
|
|
61493
62104
|
const handleWorkspaceHover = React143.useCallback((workspaceId) => {
|
|
61494
62105
|
}, []);
|
|
61495
62106
|
const handleWorkspaceHoverEnd = React143.useCallback((workspaceId) => {
|
|
61496
62107
|
}, []);
|
|
61497
|
-
const
|
|
61498
|
-
streamsByWorkspaceId: videoStreamsByWorkspaceId,
|
|
61499
|
-
isLoading: videoStreamsLoading
|
|
61500
|
-
} = useWorkspaceVideoStreams(workspaceMetrics);
|
|
61501
|
-
const memoizedKPIs = React143.useMemo(() => kpisWithTrend, [
|
|
62108
|
+
const memoizedKPIs = React143.useMemo(() => currentKpisWithTrend, [
|
|
61502
62109
|
// Only update reference when values change by at least 1%
|
|
61503
|
-
|
|
61504
|
-
|
|
61505
|
-
|
|
61506
|
-
|
|
61507
|
-
|
|
61508
|
-
|
|
61509
|
-
|
|
61510
|
-
|
|
61511
|
-
|
|
61512
|
-
|
|
61513
|
-
|
|
61514
|
-
kpisWithTrend?.qualityCompliance?.value ? Math.round(kpisWithTrend.qualityCompliance.value) : null,
|
|
62110
|
+
currentKpisWithTrend?.efficiency?.value ? Math.round(currentKpisWithTrend.efficiency.value) : null,
|
|
62111
|
+
currentKpisWithTrend?.efficiency?.change,
|
|
62112
|
+
currentKpisWithTrend?.underperformingWorkers?.current,
|
|
62113
|
+
currentKpisWithTrend?.underperformingWorkers?.total,
|
|
62114
|
+
currentKpisWithTrend?.underperformingWorkers?.change,
|
|
62115
|
+
currentKpisWithTrend?.outputProgress?.current,
|
|
62116
|
+
currentKpisWithTrend?.outputProgress?.target,
|
|
62117
|
+
currentKpisWithTrend?.outputProgress?.change,
|
|
62118
|
+
currentKpisWithTrend?.avgCycleTime?.value ? Math.round(currentKpisWithTrend.avgCycleTime.value * 10) / 10 : null,
|
|
62119
|
+
currentKpisWithTrend?.avgCycleTime?.change,
|
|
62120
|
+
currentKpisWithTrend?.qualityCompliance?.value ? Math.round(currentKpisWithTrend.qualityCompliance.value) : null,
|
|
61515
62121
|
selectedLineIdsKey
|
|
61516
62122
|
]);
|
|
61517
62123
|
React143.useEffect(() => {
|
|
@@ -61522,13 +62128,13 @@ function HomeView({
|
|
|
61522
62128
|
dashboard_surface: "monitor"
|
|
61523
62129
|
});
|
|
61524
62130
|
}, []);
|
|
61525
|
-
const metricsErrorMessage =
|
|
62131
|
+
const metricsErrorMessage = currentMetricsError?.message || null;
|
|
61526
62132
|
const handleRetryDashboardData = React143.useCallback(async () => {
|
|
61527
62133
|
if (isRecoveringSession) {
|
|
61528
62134
|
await retrySessionHydration();
|
|
61529
62135
|
}
|
|
61530
|
-
|
|
61531
|
-
}, [
|
|
62136
|
+
await currentRefetchMetrics();
|
|
62137
|
+
}, [currentRefetchMetrics, isRecoveringSession, retrySessionHydration]);
|
|
61532
62138
|
const getTrackedLineScope = React143.useCallback((lineIdsForScope) => {
|
|
61533
62139
|
if (isAllLinesSelection(lineIdsForScope)) {
|
|
61534
62140
|
return factoryViewId;
|
|
@@ -61581,12 +62187,15 @@ function HomeView({
|
|
|
61581
62187
|
updateSelectedLineIds(Array.from(currentSelection));
|
|
61582
62188
|
}, [selectedLineIds, updateSelectedLineIds]);
|
|
61583
62189
|
React143.useEffect(() => {
|
|
61584
|
-
if (!
|
|
62190
|
+
if (!isChangingFilter) {
|
|
62191
|
+
return;
|
|
62192
|
+
}
|
|
62193
|
+
if (!currentMetricsLoading && currentIsCurrentScopeResolved || currentMetricsError) {
|
|
61585
62194
|
setIsChangingFilter(false);
|
|
61586
62195
|
}
|
|
61587
|
-
}, [
|
|
62196
|
+
}, [currentIsCurrentScopeResolved, currentMetricsError, currentMetricsLoading, isChangingFilter]);
|
|
61588
62197
|
React143.useEffect(() => {
|
|
61589
|
-
if (shouldEnableMetricsFetch && !
|
|
62198
|
+
if (shouldEnableMetricsFetch && !currentMetricsLoading && !currentMetricsError && !hasInitialDataLoaded) {
|
|
61590
62199
|
setHasInitialDataLoaded(true);
|
|
61591
62200
|
trackCoreEvent("monitor page loaded", {
|
|
61592
62201
|
default_line_id: defaultLineId,
|
|
@@ -61595,7 +62204,7 @@ function HomeView({
|
|
|
61595
62204
|
dashboard_surface: "monitor"
|
|
61596
62205
|
});
|
|
61597
62206
|
}
|
|
61598
|
-
}, [shouldEnableMetricsFetch,
|
|
62207
|
+
}, [shouldEnableMetricsFetch, currentMetricsLoading, currentMetricsError, hasInitialDataLoaded, defaultLineId, factoryViewId, isSupervisor]);
|
|
61599
62208
|
const lineTitle = React143.useMemo(() => {
|
|
61600
62209
|
return factoryName;
|
|
61601
62210
|
}, [factoryName]);
|
|
@@ -61746,15 +62355,15 @@ function HomeView({
|
|
|
61746
62355
|
return showLoading;
|
|
61747
62356
|
};
|
|
61748
62357
|
const isAuthBootstrapping = authStatus === "loading";
|
|
61749
|
-
const isInitialLoading = !isHydrated || !hasInitialDataLoaded && (isAuthBootstrapping || shouldEnableMetricsFetch &&
|
|
61750
|
-
const isDataLoading =
|
|
62358
|
+
const isInitialLoading = !isHydrated || !hasInitialDataLoaded && (isAuthBootstrapping || shouldEnableMetricsFetch && currentMetricsLoading);
|
|
62359
|
+
const isDataLoading = currentMetricsLoading;
|
|
61751
62360
|
const hasKpiDataReady = React143.useMemo(() => {
|
|
61752
|
-
const lineMetricsRows =
|
|
62361
|
+
const lineMetricsRows = currentLineMetrics || [];
|
|
61753
62362
|
if (selectedLineIds.length > 1) {
|
|
61754
62363
|
return lineMetricsRows.some((row) => selectedLineIdSet.has(row?.line_id));
|
|
61755
62364
|
}
|
|
61756
62365
|
return lineMetricsRows.some((row) => row?.line_id === primarySelectedLineId);
|
|
61757
|
-
}, [
|
|
62366
|
+
}, [currentLineMetrics, primarySelectedLineId, selectedLineIdSet, selectedLineIds.length]);
|
|
61758
62367
|
const isKpiLoading = !hasKpiDataReady;
|
|
61759
62368
|
const shouldShowReconnectScreen = !hasInitialDataLoaded && (isRecoveringSession || !shouldEnableMetricsFetch && authStatus !== "failed" || !!metricsErrorMessage && authStatus !== "failed");
|
|
61760
62369
|
const shouldShowFatalLoadFailure = !hasInitialDataLoaded && !!metricsErrorMessage && authStatus === "failed";
|
|
@@ -61782,6 +62391,7 @@ function HomeView({
|
|
|
61782
62391
|
return () => clearTimeout(timer);
|
|
61783
62392
|
}, [isDataLoading]);
|
|
61784
62393
|
const shouldShowDataLoading = showDataLoading || isDataLoading;
|
|
62394
|
+
const shouldShowFilterChangeLoader = isChangingFilter && !currentIsCurrentScopeResolved;
|
|
61785
62395
|
const shouldShowKpiLoading = useSmoothLoading(isKpiLoading, 400);
|
|
61786
62396
|
const displayKpis = shouldShowKpiLoading ? null : memoizedKPIs;
|
|
61787
62397
|
const kpiSectionControl = React143.useMemo(() => /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -61866,7 +62476,7 @@ function HomeView({
|
|
|
61866
62476
|
}
|
|
61867
62477
|
)
|
|
61868
62478
|
] }) }) : null,
|
|
61869
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-y-auto sm:overflow-hidden relative flex flex-col", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-h-[calc(100vh-100px)] sm:min-h-0", children: workspaceMetricsWithBreakState.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
62479
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-y-auto sm:overflow-hidden relative flex flex-col", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative flex-1 min-h-[calc(100vh-100px)] sm:min-h-0", children: workspaceMetricsWithBreakState.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
61870
62480
|
motion.div,
|
|
61871
62481
|
{
|
|
61872
62482
|
initial: { opacity: 0, scale: 0.98 },
|
|
@@ -61878,10 +62488,10 @@ function HomeView({
|
|
|
61878
62488
|
lineNames: mergedLineNames,
|
|
61879
62489
|
lineOrder: selectedLineIds,
|
|
61880
62490
|
factoryView: factoryViewId,
|
|
61881
|
-
legend:
|
|
62491
|
+
legend: currentEfficiencyLegend,
|
|
61882
62492
|
videoSources,
|
|
61883
|
-
videoStreamsByWorkspaceId,
|
|
61884
|
-
videoStreamsLoading,
|
|
62493
|
+
videoStreamsByWorkspaceId: currentVideoStreamsByWorkspaceId,
|
|
62494
|
+
videoStreamsLoading: currentVideoStreamsLoading,
|
|
61885
62495
|
displayNames: metricsDisplayNames,
|
|
61886
62496
|
hasFlowBuffers,
|
|
61887
62497
|
className: "h-full",
|
|
@@ -61889,8 +62499,7 @@ function HomeView({
|
|
|
61889
62499
|
onWorkspaceHover: handleWorkspaceHover,
|
|
61890
62500
|
onWorkspaceHoverEnd: handleWorkspaceHoverEnd
|
|
61891
62501
|
})
|
|
61892
|
-
}
|
|
61893
|
-
selectedLineIdsKey
|
|
62502
|
+
}
|
|
61894
62503
|
) : !shouldShowDataLoading && hasInitialDataLoaded ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
61895
62504
|
motion.div,
|
|
61896
62505
|
{
|
|
@@ -61912,10 +62521,10 @@ function HomeView({
|
|
|
61912
62521
|
lineNames: mergedLineNames,
|
|
61913
62522
|
lineOrder: selectedLineIds,
|
|
61914
62523
|
factoryView: factoryViewId,
|
|
61915
|
-
legend:
|
|
62524
|
+
legend: currentEfficiencyLegend,
|
|
61916
62525
|
videoSources,
|
|
61917
|
-
videoStreamsByWorkspaceId,
|
|
61918
|
-
videoStreamsLoading,
|
|
62526
|
+
videoStreamsByWorkspaceId: currentVideoStreamsByWorkspaceId,
|
|
62527
|
+
videoStreamsLoading: currentVideoStreamsLoading,
|
|
61919
62528
|
displayNames: metricsDisplayNames,
|
|
61920
62529
|
hasFlowBuffers,
|
|
61921
62530
|
className: "h-full",
|
|
@@ -61923,16 +62532,15 @@ function HomeView({
|
|
|
61923
62532
|
onWorkspaceHover: handleWorkspaceHover,
|
|
61924
62533
|
onWorkspaceHoverEnd: handleWorkspaceHoverEnd
|
|
61925
62534
|
})
|
|
61926
|
-
}
|
|
61927
|
-
selectedLineIdsKey
|
|
62535
|
+
}
|
|
61928
62536
|
) }) })
|
|
61929
62537
|
] }),
|
|
61930
62538
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
61931
62539
|
BreakNotificationPopup,
|
|
61932
62540
|
{
|
|
61933
|
-
activeBreaks,
|
|
62541
|
+
activeBreaks: currentActiveBreaks,
|
|
61934
62542
|
lineNames: mergedLineNames,
|
|
61935
|
-
isVisible: !
|
|
62543
|
+
isVisible: !currentBreaksLoading && !currentBreaksError && !breakNotificationsDismissed,
|
|
61936
62544
|
onDismiss: () => setBreakNotificationsDismissed(true)
|
|
61937
62545
|
}
|
|
61938
62546
|
),
|
|
@@ -61944,6 +62552,15 @@ function HomeView({
|
|
|
61944
62552
|
onDismiss: () => setBottleneckNotification(null)
|
|
61945
62553
|
}
|
|
61946
62554
|
),
|
|
62555
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
62556
|
+
LoadingOverlayCmp,
|
|
62557
|
+
{
|
|
62558
|
+
isVisible: shouldShowFilterChangeLoader,
|
|
62559
|
+
message: "Loading Dashboard...",
|
|
62560
|
+
className: "bg-slate-50/30 backdrop-blur-[3px]",
|
|
62561
|
+
contentVariant: "plain"
|
|
62562
|
+
}
|
|
62563
|
+
),
|
|
61947
62564
|
diagnosisModalOpen && bottleneckModalData?.clipId && /* @__PURE__ */ jsxRuntime.jsx(
|
|
61948
62565
|
DiagnosisVideoModal,
|
|
61949
62566
|
{
|
|
@@ -71500,6 +72117,8 @@ var WorkspaceDetailView = ({
|
|
|
71500
72117
|
const totalActions = Number(cachedOverviewMetrics.action_count || 0);
|
|
71501
72118
|
const targetOutput = Number(cachedOverviewMetrics.action_threshold || 0);
|
|
71502
72119
|
const idealOutput = Number(cachedOverviewMetrics.predicted_output ?? targetOutput ?? 0);
|
|
72120
|
+
const pphThreshold = Number(cachedOverviewMetrics.pph_threshold || 0);
|
|
72121
|
+
const idealCycleTime = Number(cachedOverviewMetrics.ideal_cycle_time || 0);
|
|
71503
72122
|
return {
|
|
71504
72123
|
line_id: cachedOverviewMetrics.line_id,
|
|
71505
72124
|
line_name: "",
|
|
@@ -71518,11 +72137,11 @@ var WorkspaceDetailView = ({
|
|
|
71518
72137
|
shift_start: shiftDefinition?.startTime || "",
|
|
71519
72138
|
shift_end: shiftDefinition?.endTime || "",
|
|
71520
72139
|
shift_type: shiftType,
|
|
71521
|
-
pph_threshold:
|
|
72140
|
+
pph_threshold: pphThreshold,
|
|
71522
72141
|
target_output: targetOutput,
|
|
71523
72142
|
avg_pph: Number(cachedOverviewMetrics.pph || 0),
|
|
71524
72143
|
avg_cycle_time: avgCycleTime,
|
|
71525
|
-
ideal_cycle_time:
|
|
72144
|
+
ideal_cycle_time: idealCycleTime,
|
|
71526
72145
|
avg_efficiency: Number(cachedOverviewMetrics.efficiency || 0),
|
|
71527
72146
|
total_actions: totalActions,
|
|
71528
72147
|
hourly_action_counts: [],
|
|
@@ -74054,7 +74673,8 @@ var TeamManagementView = ({
|
|
|
74054
74673
|
const bootstrapData = await bootstrapResponse.json();
|
|
74055
74674
|
setAvailableFactories((bootstrapData.factories || []).map((factory) => ({
|
|
74056
74675
|
id: factory.id,
|
|
74057
|
-
factory_name: factory.factory_name
|
|
74676
|
+
factory_name: factory.factory_name,
|
|
74677
|
+
company_id: factory.company_id
|
|
74058
74678
|
})));
|
|
74059
74679
|
setAvailableLines(bootstrapData.lines || []);
|
|
74060
74680
|
setUsers(bootstrapData.users || []);
|
|
@@ -79022,7 +79642,7 @@ var efficiencyLineConfig = [
|
|
|
79022
79642
|
var bumpRenderCounter = (key) => {
|
|
79023
79643
|
if (process.env.NODE_ENV === "test") ;
|
|
79024
79644
|
};
|
|
79025
|
-
var
|
|
79645
|
+
var toNumber4 = (value) => {
|
|
79026
79646
|
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
79027
79647
|
if (typeof value === "string" && value.trim().length > 0) {
|
|
79028
79648
|
const parsed = Number(value);
|
|
@@ -79557,7 +80177,7 @@ var OverviewSummaryCards = React143__namespace.default.memo(({ store }) => {
|
|
|
79557
80177
|
workspaceId: item.workspace_id || "",
|
|
79558
80178
|
workspaceName: item.workspace_name?.trim() || item.workspace_id || "Unknown",
|
|
79559
80179
|
lineName: item.line_name?.trim() || "Unknown Line",
|
|
79560
|
-
avgIdleSeconds:
|
|
80180
|
+
avgIdleSeconds: toNumber4(item.avg_idle_seconds)
|
|
79561
80181
|
})).slice(0, 5);
|
|
79562
80182
|
}, [snapshot.data.summary.avg_idle_per_workstation?.top_contributors]);
|
|
79563
80183
|
const showIdleContributorLineNames = React143__namespace.default.useMemo(() => {
|
|
@@ -79772,9 +80392,9 @@ var PoorestPerformersCard = React143__namespace.default.memo(({
|
|
|
79772
80392
|
return {
|
|
79773
80393
|
id: lineId,
|
|
79774
80394
|
name: line.line_name?.trim() || "Unknown Line",
|
|
79775
|
-
efficiency: roundOne(
|
|
79776
|
-
previousEfficiency:
|
|
79777
|
-
delta:
|
|
80395
|
+
efficiency: roundOne(toNumber4(line.avg_efficiency) || 0),
|
|
80396
|
+
previousEfficiency: toNumber4(line.previous_avg_efficiency),
|
|
80397
|
+
delta: toNumber4(line.delta_pp),
|
|
79778
80398
|
supervisor: supervisor?.displayName || "Unassigned",
|
|
79779
80399
|
supervisorImage: supervisor?.profilePhotoUrl ?? null
|
|
79780
80400
|
};
|
|
@@ -79883,14 +80503,14 @@ var IdleBreakdownCard = React143__namespace.default.memo(({
|
|
|
79883
80503
|
paletteToken: item.palette_token?.trim(),
|
|
79884
80504
|
iconToken: item.icon_token?.trim(),
|
|
79885
80505
|
isKnown: item.is_known ?? void 0,
|
|
79886
|
-
value:
|
|
79887
|
-
totalDurationSeconds:
|
|
79888
|
-
efficiencyLossPercentage:
|
|
80506
|
+
value: toNumber4(item.percentage) || 0,
|
|
80507
|
+
totalDurationSeconds: toNumber4(item.total_duration_seconds),
|
|
80508
|
+
efficiencyLossPercentage: toNumber4(item.efficiency_loss_percentage),
|
|
79889
80509
|
contributors: (item.contributors || []).map((contributor) => ({
|
|
79890
80510
|
workspaceId: contributor.workspace_id || "",
|
|
79891
80511
|
workspaceName: contributor.workspace_name?.trim() || "Unknown",
|
|
79892
|
-
totalDurationSeconds:
|
|
79893
|
-
percentageWithinReason:
|
|
80512
|
+
totalDurationSeconds: toNumber4(contributor.total_duration_seconds),
|
|
80513
|
+
percentageWithinReason: toNumber4(contributor.percentage_within_reason)
|
|
79894
80514
|
}))
|
|
79895
80515
|
})).filter((item) => item.value > 0);
|
|
79896
80516
|
}, [idle.data]);
|
|
@@ -79959,7 +80579,7 @@ var EfficiencyTrendCard = React143__namespace.default.memo(({
|
|
|
79959
80579
|
return `${hour12}:${minutes.toString().padStart(2, "0")} ${suffix}`;
|
|
79960
80580
|
})(),
|
|
79961
80581
|
efficiency: (() => {
|
|
79962
|
-
const value =
|
|
80582
|
+
const value = toNumber4(point.avg_efficiency);
|
|
79963
80583
|
return value === null ? void 0 : value;
|
|
79964
80584
|
})()
|
|
79965
80585
|
}));
|
|
@@ -79972,7 +80592,7 @@ var EfficiencyTrendCard = React143__namespace.default.memo(({
|
|
|
79972
80592
|
name: dateFns.format(pointDate, "MMM d"),
|
|
79973
80593
|
dayOfWeek: dateFns.format(pointDate, "EEEE"),
|
|
79974
80594
|
efficiency: (() => {
|
|
79975
|
-
const value =
|
|
80595
|
+
const value = toNumber4(point.avg_efficiency);
|
|
79976
80596
|
return value === null ? void 0 : value;
|
|
79977
80597
|
})()
|
|
79978
80598
|
}]];
|
|
@@ -79996,7 +80616,7 @@ var EfficiencyTrendCard = React143__namespace.default.memo(({
|
|
|
79996
80616
|
name: pointDate ? dateFns.format(pointDate, "MMM d") : "",
|
|
79997
80617
|
dayOfWeek: pointDate ? dateFns.format(pointDate, "EEEE") : "",
|
|
79998
80618
|
efficiency: (() => {
|
|
79999
|
-
const value =
|
|
80619
|
+
const value = toNumber4(point.avg_efficiency);
|
|
80000
80620
|
return value === null ? void 0 : value;
|
|
80001
80621
|
})()
|
|
80002
80622
|
};
|
|
@@ -80120,7 +80740,7 @@ var debugRefreshLog = (message, payload) => {
|
|
|
80120
80740
|
var isAbortError2 = (error) => {
|
|
80121
80741
|
return error instanceof DOMException && error.name === "AbortError";
|
|
80122
80742
|
};
|
|
80123
|
-
var
|
|
80743
|
+
var toNumber5 = (value) => {
|
|
80124
80744
|
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
80125
80745
|
if (typeof value === "string" && value.trim().length > 0) {
|
|
80126
80746
|
const parsed = Number(value);
|
|
@@ -80129,11 +80749,11 @@ var toNumber4 = (value) => {
|
|
|
80129
80749
|
return null;
|
|
80130
80750
|
};
|
|
80131
80751
|
var formatImprovementMetric = (recommendation) => {
|
|
80132
|
-
const estimatedGain =
|
|
80752
|
+
const estimatedGain = toNumber5(recommendation.estimated_gain_pieces);
|
|
80133
80753
|
if (estimatedGain !== null && estimatedGain > 0) {
|
|
80134
80754
|
return `+${Math.round(estimatedGain).toLocaleString()} pcs / day`;
|
|
80135
80755
|
}
|
|
80136
|
-
const idleMinutes =
|
|
80756
|
+
const idleMinutes = toNumber5(recommendation.metrics?.idle_minutes);
|
|
80137
80757
|
if (idleMinutes !== null) {
|
|
80138
80758
|
return `-${Math.round(idleMinutes)}m Idle`;
|
|
80139
80759
|
}
|