@optifye/dashboard-core 6.12.23 → 6.12.25
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.js +185 -13
- package/dist/index.mjs +185 -13
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -14615,6 +14615,32 @@ function getEfficiencyTextColorClasses(efficiency, legend = DEFAULT_EFFICIENCY_L
|
|
|
14615
14615
|
}
|
|
14616
14616
|
}
|
|
14617
14617
|
|
|
14618
|
+
// src/lib/utils/qaGreenStreakParams.ts
|
|
14619
|
+
var QA_GREEN_STREAK_QUERY_PARAM_NAMES = [
|
|
14620
|
+
"qa_green_streak_started_at",
|
|
14621
|
+
"qa_green_streak_elapsed_seconds",
|
|
14622
|
+
"qa_green_streak_status"
|
|
14623
|
+
];
|
|
14624
|
+
var isTruthyEnv = (value) => ["1", "true", "yes", "on"].includes(String(value || "").trim().toLowerCase());
|
|
14625
|
+
var isQaGreenStreakForwardingEnabled = () => isTruthyEnv(process.env.NEXT_PUBLIC_DASHBOARD_QA_GREEN_STREAK_OVERRIDE_ENABLED);
|
|
14626
|
+
var appendQaGreenStreakSearchParams = (targetParams) => {
|
|
14627
|
+
if (!isQaGreenStreakForwardingEnabled() || typeof window === "undefined") {
|
|
14628
|
+
return;
|
|
14629
|
+
}
|
|
14630
|
+
const sourceParams = new URLSearchParams(window.location.search);
|
|
14631
|
+
QA_GREEN_STREAK_QUERY_PARAM_NAMES.forEach((paramName) => {
|
|
14632
|
+
const value = sourceParams.get(paramName);
|
|
14633
|
+
if (value !== null) {
|
|
14634
|
+
targetParams.set(paramName, value);
|
|
14635
|
+
}
|
|
14636
|
+
});
|
|
14637
|
+
};
|
|
14638
|
+
var getQaGreenStreakQueryString = () => {
|
|
14639
|
+
const params = new URLSearchParams();
|
|
14640
|
+
appendQaGreenStreakSearchParams(params);
|
|
14641
|
+
return params.toString();
|
|
14642
|
+
};
|
|
14643
|
+
|
|
14618
14644
|
// src/lib/utils/monitorWorkspaceMetrics.ts
|
|
14619
14645
|
var sortWorkspaceMetrics = (left, right) => {
|
|
14620
14646
|
if (left.line_id !== right.line_id) {
|
|
@@ -14961,10 +14987,12 @@ var useDashboardMetrics = ({
|
|
|
14961
14987
|
let idleTimeVlmByLine = {};
|
|
14962
14988
|
let efficiencyLegend;
|
|
14963
14989
|
const forceParam = force ? "&force_refresh=true" : "";
|
|
14990
|
+
const qaGreenStreakParamString = getQaGreenStreakQueryString();
|
|
14991
|
+
const qaGreenStreakParams = qaGreenStreakParamString ? `&${qaGreenStreakParamString}` : "";
|
|
14964
14992
|
const buildMetricsEndpoint = (params) => {
|
|
14965
14993
|
const lineIdsParam = isFactory ? `line_ids=${params.groupLineIds.join(",")}` : `line_id=${params.groupLineIds[0]}`;
|
|
14966
14994
|
const blueComparisonParam = effectiveBlueComparisonLineIds.length ? `&blue_comparison_line_ids=${effectiveBlueComparisonLineIds.join(",")}` : "";
|
|
14967
|
-
return `/api/dashboard/metrics?${lineIdsParam}${blueComparisonParam}&date=${params.date}&shift_id=${params.shiftId}&company_id=${companyId}${forceParam}`;
|
|
14995
|
+
return `/api/dashboard/metrics?${lineIdsParam}${blueComparisonParam}&date=${params.date}&shift_id=${params.shiftId}&company_id=${companyId}${forceParam}${qaGreenStreakParams}`;
|
|
14968
14996
|
};
|
|
14969
14997
|
if (usesShiftGroups) {
|
|
14970
14998
|
logDebug("[useDashboardMetrics] Factory view shift groups fetch:", {
|
|
@@ -37820,12 +37848,10 @@ var getAllVideoGridGreenStreakDisplay = (workspaces, legend = DEFAULT_EFFICIENCY
|
|
|
37820
37848
|
const startedAt = workspace.video_grid_green_streak_started_at;
|
|
37821
37849
|
const anchorAt = workspace.video_grid_green_streak_anchor_at;
|
|
37822
37850
|
const streakMinutes = workspace.video_grid_green_streak_minutes;
|
|
37823
|
-
const computedAt = workspace.recent_flow_computed_at;
|
|
37824
37851
|
const startedAtMs = parseTimestampMs(startedAt);
|
|
37825
37852
|
const anchorAtMs = parseTimestampMs(anchorAt);
|
|
37826
|
-
const computedAtMs = typeof computedAt === "string" && computedAt.trim() ? parseTimestampMs(computedAt) : Number.NaN;
|
|
37827
37853
|
const isFresh = isAllGreenStreakFresh(workspace, anchorAtMs, nowMs2);
|
|
37828
|
-
const tickOriginAtMs =
|
|
37854
|
+
const tickOriginAtMs = anchorAtMs + CONFIRMED_MINUTE_DURATION_MS;
|
|
37829
37855
|
if (workspace.video_grid_green_streak_active === true && isFiniteNumber3(streakMinutes) && streakMinutes > 0 && startedAt && anchorAt && Number.isFinite(startedAtMs) && isFresh) {
|
|
37830
37856
|
return {
|
|
37831
37857
|
startedAt,
|
|
@@ -63964,6 +63990,8 @@ var HelpView = ({
|
|
|
63964
63990
|
};
|
|
63965
63991
|
var AuthenticatedHelpView = withAuth(HelpView);
|
|
63966
63992
|
var HelpView_default = HelpView;
|
|
63993
|
+
var REALTIME_REFRESH_DEBOUNCE_MS2 = 1500;
|
|
63994
|
+
var REALTIME_REFRESH_MIN_INTERVAL_MS2 = 5e3;
|
|
63967
63995
|
var transformActiveBreaks = (activeBreaksByLine) => {
|
|
63968
63996
|
if (!activeBreaksByLine) return [];
|
|
63969
63997
|
return Object.values(activeBreaksByLine).flat().map((item) => ({
|
|
@@ -64002,6 +64030,17 @@ var normalizeMetadata = (metadata) => ({
|
|
|
64002
64030
|
cacheStatus: metadata?.cache_status,
|
|
64003
64031
|
warnings: metadata?.warnings ?? []
|
|
64004
64032
|
});
|
|
64033
|
+
var createResolvedScopeLookup = (resolvedScope, workspaces, blueComparisonWorkspaces) => {
|
|
64034
|
+
const lookup = /* @__PURE__ */ new Set();
|
|
64035
|
+
const addEntry = (lineId, date, shiftId) => {
|
|
64036
|
+
if (!lineId || !date || shiftId === void 0 || shiftId === null) return;
|
|
64037
|
+
lookup.add(`${lineId}|${date}|${shiftId}`);
|
|
64038
|
+
};
|
|
64039
|
+
resolvedScope.forEach((entry) => addEntry(entry.line_id, entry.date, entry.shift_id));
|
|
64040
|
+
workspaces.forEach((workspace) => addEntry(workspace.line_id, workspace.date, workspace.shift_id));
|
|
64041
|
+
blueComparisonWorkspaces.forEach((workspace) => addEntry(workspace.line_id, workspace.date, workspace.shift_id));
|
|
64042
|
+
return lookup;
|
|
64043
|
+
};
|
|
64005
64044
|
var useLiveMonitorBootstrap = ({
|
|
64006
64045
|
lineIds,
|
|
64007
64046
|
blueComparisonLineIds,
|
|
@@ -64028,20 +64067,34 @@ var useLiveMonitorBootstrap = ({
|
|
|
64028
64067
|
() => Array.from(new Set(rawBlueComparisonLineIdsKey ? rawBlueComparisonLineIdsKey.split(",") : [])),
|
|
64029
64068
|
[rawBlueComparisonLineIdsKey]
|
|
64030
64069
|
);
|
|
64070
|
+
const realtimeLineIds = React144.useMemo(
|
|
64071
|
+
() => Array.from(new Set([...normalizedLineIds, ...normalizedBlueComparisonLineIds].filter(Boolean))).sort(),
|
|
64072
|
+
[normalizedLineIds, normalizedBlueComparisonLineIds]
|
|
64073
|
+
);
|
|
64031
64074
|
const requestKey = React144.useMemo(
|
|
64032
64075
|
() => `${normalizedLineIds.slice().sort().join(",")}|blue:${normalizedBlueComparisonLineIds.slice().sort().join(",")}`,
|
|
64033
64076
|
[normalizedLineIds, normalizedBlueComparisonLineIds]
|
|
64034
64077
|
);
|
|
64078
|
+
const realtimeLineIdsKey = React144.useMemo(() => realtimeLineIds.join(","), [realtimeLineIds]);
|
|
64079
|
+
const companySpecificMetricsTable = React144.useMemo(
|
|
64080
|
+
() => getCompanyMetricsTableName(resolvedCompanyId, "performance_metrics"),
|
|
64081
|
+
[resolvedCompanyId]
|
|
64082
|
+
);
|
|
64035
64083
|
const [state, setState] = React144.useState(() => createEmptyState());
|
|
64036
64084
|
const [rawState, setRawState] = React144.useState(null);
|
|
64037
64085
|
const [isLoading, setIsLoading] = React144.useState(false);
|
|
64038
64086
|
const [error, setError] = React144.useState(null);
|
|
64039
64087
|
const activeRequestIdRef = React144.useRef(0);
|
|
64088
|
+
const isFetchingRef = React144.useRef(false);
|
|
64089
|
+
const pendingRealtimeRefreshRef = React144.useRef(false);
|
|
64090
|
+
const realtimeRefreshTimerRef = React144.useRef(null);
|
|
64091
|
+
const lastRealtimeRefreshStartedAtRef = React144.useRef(0);
|
|
64040
64092
|
const fetchBootstrap = React144.useCallback(async (force = false) => {
|
|
64041
64093
|
if (!enabled || !supabase || !resolvedCompanyId || normalizedLineIds.length === 0) {
|
|
64042
64094
|
return;
|
|
64043
64095
|
}
|
|
64044
64096
|
const requestId = ++activeRequestIdRef.current;
|
|
64097
|
+
isFetchingRef.current = true;
|
|
64045
64098
|
setIsLoading(true);
|
|
64046
64099
|
setError(null);
|
|
64047
64100
|
try {
|
|
@@ -64054,6 +64107,7 @@ var useLiveMonitorBootstrap = ({
|
|
|
64054
64107
|
if (force) {
|
|
64055
64108
|
searchParams.set("force_refresh", "true");
|
|
64056
64109
|
}
|
|
64110
|
+
appendQaGreenStreakSearchParams(searchParams);
|
|
64057
64111
|
const response = await fetchBackendJson(
|
|
64058
64112
|
supabase,
|
|
64059
64113
|
`/api/dashboard/monitor-bootstrap?${searchParams.toString()}`,
|
|
@@ -64091,6 +64145,7 @@ var useLiveMonitorBootstrap = ({
|
|
|
64091
64145
|
} finally {
|
|
64092
64146
|
if (requestId === activeRequestIdRef.current) {
|
|
64093
64147
|
setIsLoading(false);
|
|
64148
|
+
isFetchingRef.current = false;
|
|
64094
64149
|
}
|
|
64095
64150
|
}
|
|
64096
64151
|
}, [
|
|
@@ -64101,6 +64156,52 @@ var useLiveMonitorBootstrap = ({
|
|
|
64101
64156
|
normalizedBlueComparisonLineIds,
|
|
64102
64157
|
requestKey
|
|
64103
64158
|
]);
|
|
64159
|
+
const fetchBootstrapRef = React144.useRef(fetchBootstrap);
|
|
64160
|
+
React144.useEffect(() => {
|
|
64161
|
+
fetchBootstrapRef.current = fetchBootstrap;
|
|
64162
|
+
}, [fetchBootstrap]);
|
|
64163
|
+
const clearRealtimeRefreshTimer = React144.useCallback(() => {
|
|
64164
|
+
if (realtimeRefreshTimerRef.current !== null) {
|
|
64165
|
+
window.clearTimeout(realtimeRefreshTimerRef.current);
|
|
64166
|
+
realtimeRefreshTimerRef.current = null;
|
|
64167
|
+
}
|
|
64168
|
+
}, []);
|
|
64169
|
+
const scheduleRealtimeRefresh = React144.useCallback(() => {
|
|
64170
|
+
if (!enabled || !supabase || realtimeRefreshTimerRef.current !== null) {
|
|
64171
|
+
return;
|
|
64172
|
+
}
|
|
64173
|
+
const elapsedSinceLastRealtimeRefresh = Date.now() - lastRealtimeRefreshStartedAtRef.current;
|
|
64174
|
+
const minIntervalRemaining = Math.max(0, REALTIME_REFRESH_MIN_INTERVAL_MS2 - elapsedSinceLastRealtimeRefresh);
|
|
64175
|
+
const nextDelay = Math.max(REALTIME_REFRESH_DEBOUNCE_MS2, minIntervalRemaining);
|
|
64176
|
+
realtimeRefreshTimerRef.current = window.setTimeout(() => {
|
|
64177
|
+
realtimeRefreshTimerRef.current = null;
|
|
64178
|
+
if (!pendingRealtimeRefreshRef.current) {
|
|
64179
|
+
return;
|
|
64180
|
+
}
|
|
64181
|
+
if (isFetchingRef.current) {
|
|
64182
|
+
scheduleRealtimeRefresh();
|
|
64183
|
+
return;
|
|
64184
|
+
}
|
|
64185
|
+
pendingRealtimeRefreshRef.current = false;
|
|
64186
|
+
lastRealtimeRefreshStartedAtRef.current = Date.now();
|
|
64187
|
+
void fetchBootstrapRef.current(true);
|
|
64188
|
+
}, nextDelay);
|
|
64189
|
+
}, [enabled, supabase]);
|
|
64190
|
+
const queueRealtimeRefresh = React144.useCallback(() => {
|
|
64191
|
+
if (!enabled || !supabase) {
|
|
64192
|
+
pendingRealtimeRefreshRef.current = false;
|
|
64193
|
+
clearRealtimeRefreshTimer();
|
|
64194
|
+
return;
|
|
64195
|
+
}
|
|
64196
|
+
pendingRealtimeRefreshRef.current = true;
|
|
64197
|
+
scheduleRealtimeRefresh();
|
|
64198
|
+
}, [clearRealtimeRefreshTimer, enabled, scheduleRealtimeRefresh, supabase]);
|
|
64199
|
+
React144.useEffect(() => {
|
|
64200
|
+
return () => {
|
|
64201
|
+
pendingRealtimeRefreshRef.current = false;
|
|
64202
|
+
clearRealtimeRefreshTimer();
|
|
64203
|
+
};
|
|
64204
|
+
}, [clearRealtimeRefreshTimer]);
|
|
64104
64205
|
React144.useEffect(() => {
|
|
64105
64206
|
if (!enabled || !rawState || !resolvedCompanyId) {
|
|
64106
64207
|
return;
|
|
@@ -64179,6 +64280,83 @@ var useLiveMonitorBootstrap = ({
|
|
|
64179
64280
|
}
|
|
64180
64281
|
void fetchBootstrap(false);
|
|
64181
64282
|
}, [enabled, resolvedCompanyId, normalizedLineIds, supabase, fetchBootstrap]);
|
|
64283
|
+
const realtimeScopeKey = React144.useMemo(() => Array.from(createResolvedScopeLookup(
|
|
64284
|
+
state.resolvedScope,
|
|
64285
|
+
state.workspaceMetrics,
|
|
64286
|
+
state.blueComparisonWorkspaceMetrics
|
|
64287
|
+
)).sort().join("||"), [state.resolvedScope, state.workspaceMetrics, state.blueComparisonWorkspaceMetrics]);
|
|
64288
|
+
React144.useEffect(() => {
|
|
64289
|
+
if (!enabled || !resolvedCompanyId || !realtimeLineIdsKey || !supabase) {
|
|
64290
|
+
return void 0;
|
|
64291
|
+
}
|
|
64292
|
+
const scopeLookup = new Set(realtimeScopeKey ? realtimeScopeKey.split("||") : []);
|
|
64293
|
+
if (scopeLookup.size === 0) {
|
|
64294
|
+
return void 0;
|
|
64295
|
+
}
|
|
64296
|
+
const realtimeLineIdsForFilter = realtimeLineIdsKey.split(",").filter(Boolean);
|
|
64297
|
+
if (realtimeLineIdsForFilter.length === 0) {
|
|
64298
|
+
return void 0;
|
|
64299
|
+
}
|
|
64300
|
+
const lineIdFilter = `line_id=in.(${realtimeLineIdsForFilter.join(",")})`;
|
|
64301
|
+
const channels = [];
|
|
64302
|
+
const shouldRefreshForPayload = (payload) => {
|
|
64303
|
+
const payloadData = payload.new || payload.old;
|
|
64304
|
+
return scopeLookup.has(`${payloadData?.line_id}|${payloadData?.date}|${payloadData?.shift_id}`);
|
|
64305
|
+
};
|
|
64306
|
+
const createSubscription = (table, channelNameBase) => {
|
|
64307
|
+
const channelName = `${channelNameBase}-${state.scopeKey || requestKey}`.replace(/[^a-zA-Z0-9_-]/g, "");
|
|
64308
|
+
const channel = supabase.channel(channelName).on(
|
|
64309
|
+
"postgres_changes",
|
|
64310
|
+
{ event: "*", schema: "public", table, filter: lineIdFilter },
|
|
64311
|
+
(payload) => {
|
|
64312
|
+
if (shouldRefreshForPayload(payload)) {
|
|
64313
|
+
queueRealtimeRefresh();
|
|
64314
|
+
}
|
|
64315
|
+
}
|
|
64316
|
+
).subscribe();
|
|
64317
|
+
channels.push(channel);
|
|
64318
|
+
};
|
|
64319
|
+
createSubscription(companySpecificMetricsTable, "monitor-bootstrap-ws");
|
|
64320
|
+
createSubscription("line_metrics", "monitor-bootstrap-lm");
|
|
64321
|
+
createSubscription("wip_buffer_metrics", "monitor-bootstrap-wip-metrics");
|
|
64322
|
+
createSubscription("wip_buffer_alerts", "monitor-bootstrap-wip-alerts");
|
|
64323
|
+
return () => {
|
|
64324
|
+
channels.forEach((channel) => {
|
|
64325
|
+
supabase.removeChannel(channel);
|
|
64326
|
+
});
|
|
64327
|
+
};
|
|
64328
|
+
}, [
|
|
64329
|
+
enabled,
|
|
64330
|
+
resolvedCompanyId,
|
|
64331
|
+
realtimeLineIdsKey,
|
|
64332
|
+
supabase,
|
|
64333
|
+
realtimeScopeKey,
|
|
64334
|
+
state.scopeKey,
|
|
64335
|
+
requestKey,
|
|
64336
|
+
companySpecificMetricsTable,
|
|
64337
|
+
queueRealtimeRefresh
|
|
64338
|
+
]);
|
|
64339
|
+
React144.useEffect(() => {
|
|
64340
|
+
if (!enabled || !resolvedCompanyId || normalizedLineIds.length === 0 || !supabase) {
|
|
64341
|
+
return void 0;
|
|
64342
|
+
}
|
|
64343
|
+
const forceRefreshOnResume = () => {
|
|
64344
|
+
void fetchBootstrapRef.current(true);
|
|
64345
|
+
};
|
|
64346
|
+
const handleVisibilityChange = () => {
|
|
64347
|
+
if (document.visibilityState === "visible") {
|
|
64348
|
+
forceRefreshOnResume();
|
|
64349
|
+
}
|
|
64350
|
+
};
|
|
64351
|
+
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
64352
|
+
window.addEventListener("focus", forceRefreshOnResume);
|
|
64353
|
+
window.addEventListener("online", forceRefreshOnResume);
|
|
64354
|
+
return () => {
|
|
64355
|
+
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
64356
|
+
window.removeEventListener("focus", forceRefreshOnResume);
|
|
64357
|
+
window.removeEventListener("online", forceRefreshOnResume);
|
|
64358
|
+
};
|
|
64359
|
+
}, [enabled, normalizedLineIds.length, resolvedCompanyId, supabase]);
|
|
64182
64360
|
React144.useEffect(() => {
|
|
64183
64361
|
if (!enabled || !resolvedCompanyId || normalizedLineIds.length === 0 || !supabase) {
|
|
64184
64362
|
return void 0;
|
|
@@ -64933,7 +65111,6 @@ function HomeView({
|
|
|
64933
65111
|
const allGreenMilestoneTrackingRef = React144.useRef({ identity: null, lastMilestoneSeconds: null });
|
|
64934
65112
|
const allGreenStreakTimerBaselineRef = React144.useRef(null);
|
|
64935
65113
|
const [showAllGreenCelebration, setShowAllGreenCelebration] = React144.useState(false);
|
|
64936
|
-
const [allGreenCelebrationStartedAtMs, setAllGreenCelebrationStartedAtMs] = React144.useState(null);
|
|
64937
65114
|
const [greenStreakMilestoneBanner, setGreenStreakMilestoneBanner] = React144.useState(null);
|
|
64938
65115
|
const [allGreenStreakNowMs, setAllGreenStreakNowMs] = React144.useState(() => Date.now());
|
|
64939
65116
|
const currentAllGreenStreakNowMs = Math.max(allGreenStreakNowMs, Date.now());
|
|
@@ -64996,13 +65173,11 @@ function HomeView({
|
|
|
64996
65173
|
};
|
|
64997
65174
|
}, [allGreenMilestoneIdentity, allGreenStreakDisplay, currentAllGreenStreakNowMs]);
|
|
64998
65175
|
const allGreenCelebrationTimerText = React144.useMemo(() => {
|
|
64999
|
-
if (!showAllGreenCelebration ||
|
|
65176
|
+
if (!showAllGreenCelebration || !visibleAllGreenStreakDisplay) {
|
|
65000
65177
|
return null;
|
|
65001
65178
|
}
|
|
65002
|
-
return formatAllGreenCelebrationTimer(
|
|
65003
|
-
|
|
65004
|
-
);
|
|
65005
|
-
}, [allGreenCelebrationStartedAtMs, currentAllGreenStreakNowMs, showAllGreenCelebration]);
|
|
65179
|
+
return formatAllGreenCelebrationTimer(visibleAllGreenStreakDisplay.elapsedSeconds);
|
|
65180
|
+
}, [showAllGreenCelebration, visibleAllGreenStreakDisplay]);
|
|
65006
65181
|
React144.useEffect(() => {
|
|
65007
65182
|
const hasPossibleStreakTimer = showAllGreenCelebration || Boolean(allGreenStreakDisplay) || workspaceMetricsWithBreakState.some((workspace) => workspace.video_grid_green_streak_active === true);
|
|
65008
65183
|
if (!hasPossibleStreakTimer) {
|
|
@@ -65021,17 +65196,14 @@ function HomeView({
|
|
|
65021
65196
|
allGreenCelebrationTimerRef.current = null;
|
|
65022
65197
|
}
|
|
65023
65198
|
setShowAllGreenCelebration(false);
|
|
65024
|
-
setAllGreenCelebrationStartedAtMs(null);
|
|
65025
65199
|
}, []);
|
|
65026
65200
|
const triggerAllGreenCelebration = React144.useCallback(() => {
|
|
65027
|
-
setAllGreenCelebrationStartedAtMs(Date.now());
|
|
65028
65201
|
setShowAllGreenCelebration(true);
|
|
65029
65202
|
if (allGreenCelebrationTimerRef.current) {
|
|
65030
65203
|
clearTimeout(allGreenCelebrationTimerRef.current);
|
|
65031
65204
|
}
|
|
65032
65205
|
allGreenCelebrationTimerRef.current = setTimeout(() => {
|
|
65033
65206
|
setShowAllGreenCelebration(false);
|
|
65034
|
-
setAllGreenCelebrationStartedAtMs(null);
|
|
65035
65207
|
allGreenCelebrationTimerRef.current = null;
|
|
65036
65208
|
}, ALL_GREEN_CELEBRATION_DURATION_MS);
|
|
65037
65209
|
}, []);
|
package/dist/index.mjs
CHANGED
|
@@ -14586,6 +14586,32 @@ function getEfficiencyTextColorClasses(efficiency, legend = DEFAULT_EFFICIENCY_L
|
|
|
14586
14586
|
}
|
|
14587
14587
|
}
|
|
14588
14588
|
|
|
14589
|
+
// src/lib/utils/qaGreenStreakParams.ts
|
|
14590
|
+
var QA_GREEN_STREAK_QUERY_PARAM_NAMES = [
|
|
14591
|
+
"qa_green_streak_started_at",
|
|
14592
|
+
"qa_green_streak_elapsed_seconds",
|
|
14593
|
+
"qa_green_streak_status"
|
|
14594
|
+
];
|
|
14595
|
+
var isTruthyEnv = (value) => ["1", "true", "yes", "on"].includes(String(value || "").trim().toLowerCase());
|
|
14596
|
+
var isQaGreenStreakForwardingEnabled = () => isTruthyEnv(process.env.NEXT_PUBLIC_DASHBOARD_QA_GREEN_STREAK_OVERRIDE_ENABLED);
|
|
14597
|
+
var appendQaGreenStreakSearchParams = (targetParams) => {
|
|
14598
|
+
if (!isQaGreenStreakForwardingEnabled() || typeof window === "undefined") {
|
|
14599
|
+
return;
|
|
14600
|
+
}
|
|
14601
|
+
const sourceParams = new URLSearchParams(window.location.search);
|
|
14602
|
+
QA_GREEN_STREAK_QUERY_PARAM_NAMES.forEach((paramName) => {
|
|
14603
|
+
const value = sourceParams.get(paramName);
|
|
14604
|
+
if (value !== null) {
|
|
14605
|
+
targetParams.set(paramName, value);
|
|
14606
|
+
}
|
|
14607
|
+
});
|
|
14608
|
+
};
|
|
14609
|
+
var getQaGreenStreakQueryString = () => {
|
|
14610
|
+
const params = new URLSearchParams();
|
|
14611
|
+
appendQaGreenStreakSearchParams(params);
|
|
14612
|
+
return params.toString();
|
|
14613
|
+
};
|
|
14614
|
+
|
|
14589
14615
|
// src/lib/utils/monitorWorkspaceMetrics.ts
|
|
14590
14616
|
var sortWorkspaceMetrics = (left, right) => {
|
|
14591
14617
|
if (left.line_id !== right.line_id) {
|
|
@@ -14932,10 +14958,12 @@ var useDashboardMetrics = ({
|
|
|
14932
14958
|
let idleTimeVlmByLine = {};
|
|
14933
14959
|
let efficiencyLegend;
|
|
14934
14960
|
const forceParam = force ? "&force_refresh=true" : "";
|
|
14961
|
+
const qaGreenStreakParamString = getQaGreenStreakQueryString();
|
|
14962
|
+
const qaGreenStreakParams = qaGreenStreakParamString ? `&${qaGreenStreakParamString}` : "";
|
|
14935
14963
|
const buildMetricsEndpoint = (params) => {
|
|
14936
14964
|
const lineIdsParam = isFactory ? `line_ids=${params.groupLineIds.join(",")}` : `line_id=${params.groupLineIds[0]}`;
|
|
14937
14965
|
const blueComparisonParam = effectiveBlueComparisonLineIds.length ? `&blue_comparison_line_ids=${effectiveBlueComparisonLineIds.join(",")}` : "";
|
|
14938
|
-
return `/api/dashboard/metrics?${lineIdsParam}${blueComparisonParam}&date=${params.date}&shift_id=${params.shiftId}&company_id=${companyId}${forceParam}`;
|
|
14966
|
+
return `/api/dashboard/metrics?${lineIdsParam}${blueComparisonParam}&date=${params.date}&shift_id=${params.shiftId}&company_id=${companyId}${forceParam}${qaGreenStreakParams}`;
|
|
14939
14967
|
};
|
|
14940
14968
|
if (usesShiftGroups) {
|
|
14941
14969
|
logDebug("[useDashboardMetrics] Factory view shift groups fetch:", {
|
|
@@ -37791,12 +37819,10 @@ var getAllVideoGridGreenStreakDisplay = (workspaces, legend = DEFAULT_EFFICIENCY
|
|
|
37791
37819
|
const startedAt = workspace.video_grid_green_streak_started_at;
|
|
37792
37820
|
const anchorAt = workspace.video_grid_green_streak_anchor_at;
|
|
37793
37821
|
const streakMinutes = workspace.video_grid_green_streak_minutes;
|
|
37794
|
-
const computedAt = workspace.recent_flow_computed_at;
|
|
37795
37822
|
const startedAtMs = parseTimestampMs(startedAt);
|
|
37796
37823
|
const anchorAtMs = parseTimestampMs(anchorAt);
|
|
37797
|
-
const computedAtMs = typeof computedAt === "string" && computedAt.trim() ? parseTimestampMs(computedAt) : Number.NaN;
|
|
37798
37824
|
const isFresh = isAllGreenStreakFresh(workspace, anchorAtMs, nowMs2);
|
|
37799
|
-
const tickOriginAtMs =
|
|
37825
|
+
const tickOriginAtMs = anchorAtMs + CONFIRMED_MINUTE_DURATION_MS;
|
|
37800
37826
|
if (workspace.video_grid_green_streak_active === true && isFiniteNumber3(streakMinutes) && streakMinutes > 0 && startedAt && anchorAt && Number.isFinite(startedAtMs) && isFresh) {
|
|
37801
37827
|
return {
|
|
37802
37828
|
startedAt,
|
|
@@ -63935,6 +63961,8 @@ var HelpView = ({
|
|
|
63935
63961
|
};
|
|
63936
63962
|
var AuthenticatedHelpView = withAuth(HelpView);
|
|
63937
63963
|
var HelpView_default = HelpView;
|
|
63964
|
+
var REALTIME_REFRESH_DEBOUNCE_MS2 = 1500;
|
|
63965
|
+
var REALTIME_REFRESH_MIN_INTERVAL_MS2 = 5e3;
|
|
63938
63966
|
var transformActiveBreaks = (activeBreaksByLine) => {
|
|
63939
63967
|
if (!activeBreaksByLine) return [];
|
|
63940
63968
|
return Object.values(activeBreaksByLine).flat().map((item) => ({
|
|
@@ -63973,6 +64001,17 @@ var normalizeMetadata = (metadata) => ({
|
|
|
63973
64001
|
cacheStatus: metadata?.cache_status,
|
|
63974
64002
|
warnings: metadata?.warnings ?? []
|
|
63975
64003
|
});
|
|
64004
|
+
var createResolvedScopeLookup = (resolvedScope, workspaces, blueComparisonWorkspaces) => {
|
|
64005
|
+
const lookup = /* @__PURE__ */ new Set();
|
|
64006
|
+
const addEntry = (lineId, date, shiftId) => {
|
|
64007
|
+
if (!lineId || !date || shiftId === void 0 || shiftId === null) return;
|
|
64008
|
+
lookup.add(`${lineId}|${date}|${shiftId}`);
|
|
64009
|
+
};
|
|
64010
|
+
resolvedScope.forEach((entry) => addEntry(entry.line_id, entry.date, entry.shift_id));
|
|
64011
|
+
workspaces.forEach((workspace) => addEntry(workspace.line_id, workspace.date, workspace.shift_id));
|
|
64012
|
+
blueComparisonWorkspaces.forEach((workspace) => addEntry(workspace.line_id, workspace.date, workspace.shift_id));
|
|
64013
|
+
return lookup;
|
|
64014
|
+
};
|
|
63976
64015
|
var useLiveMonitorBootstrap = ({
|
|
63977
64016
|
lineIds,
|
|
63978
64017
|
blueComparisonLineIds,
|
|
@@ -63999,20 +64038,34 @@ var useLiveMonitorBootstrap = ({
|
|
|
63999
64038
|
() => Array.from(new Set(rawBlueComparisonLineIdsKey ? rawBlueComparisonLineIdsKey.split(",") : [])),
|
|
64000
64039
|
[rawBlueComparisonLineIdsKey]
|
|
64001
64040
|
);
|
|
64041
|
+
const realtimeLineIds = useMemo(
|
|
64042
|
+
() => Array.from(new Set([...normalizedLineIds, ...normalizedBlueComparisonLineIds].filter(Boolean))).sort(),
|
|
64043
|
+
[normalizedLineIds, normalizedBlueComparisonLineIds]
|
|
64044
|
+
);
|
|
64002
64045
|
const requestKey = useMemo(
|
|
64003
64046
|
() => `${normalizedLineIds.slice().sort().join(",")}|blue:${normalizedBlueComparisonLineIds.slice().sort().join(",")}`,
|
|
64004
64047
|
[normalizedLineIds, normalizedBlueComparisonLineIds]
|
|
64005
64048
|
);
|
|
64049
|
+
const realtimeLineIdsKey = useMemo(() => realtimeLineIds.join(","), [realtimeLineIds]);
|
|
64050
|
+
const companySpecificMetricsTable = useMemo(
|
|
64051
|
+
() => getCompanyMetricsTableName(resolvedCompanyId, "performance_metrics"),
|
|
64052
|
+
[resolvedCompanyId]
|
|
64053
|
+
);
|
|
64006
64054
|
const [state, setState] = useState(() => createEmptyState());
|
|
64007
64055
|
const [rawState, setRawState] = useState(null);
|
|
64008
64056
|
const [isLoading, setIsLoading] = useState(false);
|
|
64009
64057
|
const [error, setError] = useState(null);
|
|
64010
64058
|
const activeRequestIdRef = useRef(0);
|
|
64059
|
+
const isFetchingRef = useRef(false);
|
|
64060
|
+
const pendingRealtimeRefreshRef = useRef(false);
|
|
64061
|
+
const realtimeRefreshTimerRef = useRef(null);
|
|
64062
|
+
const lastRealtimeRefreshStartedAtRef = useRef(0);
|
|
64011
64063
|
const fetchBootstrap = useCallback(async (force = false) => {
|
|
64012
64064
|
if (!enabled || !supabase || !resolvedCompanyId || normalizedLineIds.length === 0) {
|
|
64013
64065
|
return;
|
|
64014
64066
|
}
|
|
64015
64067
|
const requestId = ++activeRequestIdRef.current;
|
|
64068
|
+
isFetchingRef.current = true;
|
|
64016
64069
|
setIsLoading(true);
|
|
64017
64070
|
setError(null);
|
|
64018
64071
|
try {
|
|
@@ -64025,6 +64078,7 @@ var useLiveMonitorBootstrap = ({
|
|
|
64025
64078
|
if (force) {
|
|
64026
64079
|
searchParams.set("force_refresh", "true");
|
|
64027
64080
|
}
|
|
64081
|
+
appendQaGreenStreakSearchParams(searchParams);
|
|
64028
64082
|
const response = await fetchBackendJson(
|
|
64029
64083
|
supabase,
|
|
64030
64084
|
`/api/dashboard/monitor-bootstrap?${searchParams.toString()}`,
|
|
@@ -64062,6 +64116,7 @@ var useLiveMonitorBootstrap = ({
|
|
|
64062
64116
|
} finally {
|
|
64063
64117
|
if (requestId === activeRequestIdRef.current) {
|
|
64064
64118
|
setIsLoading(false);
|
|
64119
|
+
isFetchingRef.current = false;
|
|
64065
64120
|
}
|
|
64066
64121
|
}
|
|
64067
64122
|
}, [
|
|
@@ -64072,6 +64127,52 @@ var useLiveMonitorBootstrap = ({
|
|
|
64072
64127
|
normalizedBlueComparisonLineIds,
|
|
64073
64128
|
requestKey
|
|
64074
64129
|
]);
|
|
64130
|
+
const fetchBootstrapRef = useRef(fetchBootstrap);
|
|
64131
|
+
useEffect(() => {
|
|
64132
|
+
fetchBootstrapRef.current = fetchBootstrap;
|
|
64133
|
+
}, [fetchBootstrap]);
|
|
64134
|
+
const clearRealtimeRefreshTimer = useCallback(() => {
|
|
64135
|
+
if (realtimeRefreshTimerRef.current !== null) {
|
|
64136
|
+
window.clearTimeout(realtimeRefreshTimerRef.current);
|
|
64137
|
+
realtimeRefreshTimerRef.current = null;
|
|
64138
|
+
}
|
|
64139
|
+
}, []);
|
|
64140
|
+
const scheduleRealtimeRefresh = useCallback(() => {
|
|
64141
|
+
if (!enabled || !supabase || realtimeRefreshTimerRef.current !== null) {
|
|
64142
|
+
return;
|
|
64143
|
+
}
|
|
64144
|
+
const elapsedSinceLastRealtimeRefresh = Date.now() - lastRealtimeRefreshStartedAtRef.current;
|
|
64145
|
+
const minIntervalRemaining = Math.max(0, REALTIME_REFRESH_MIN_INTERVAL_MS2 - elapsedSinceLastRealtimeRefresh);
|
|
64146
|
+
const nextDelay = Math.max(REALTIME_REFRESH_DEBOUNCE_MS2, minIntervalRemaining);
|
|
64147
|
+
realtimeRefreshTimerRef.current = window.setTimeout(() => {
|
|
64148
|
+
realtimeRefreshTimerRef.current = null;
|
|
64149
|
+
if (!pendingRealtimeRefreshRef.current) {
|
|
64150
|
+
return;
|
|
64151
|
+
}
|
|
64152
|
+
if (isFetchingRef.current) {
|
|
64153
|
+
scheduleRealtimeRefresh();
|
|
64154
|
+
return;
|
|
64155
|
+
}
|
|
64156
|
+
pendingRealtimeRefreshRef.current = false;
|
|
64157
|
+
lastRealtimeRefreshStartedAtRef.current = Date.now();
|
|
64158
|
+
void fetchBootstrapRef.current(true);
|
|
64159
|
+
}, nextDelay);
|
|
64160
|
+
}, [enabled, supabase]);
|
|
64161
|
+
const queueRealtimeRefresh = useCallback(() => {
|
|
64162
|
+
if (!enabled || !supabase) {
|
|
64163
|
+
pendingRealtimeRefreshRef.current = false;
|
|
64164
|
+
clearRealtimeRefreshTimer();
|
|
64165
|
+
return;
|
|
64166
|
+
}
|
|
64167
|
+
pendingRealtimeRefreshRef.current = true;
|
|
64168
|
+
scheduleRealtimeRefresh();
|
|
64169
|
+
}, [clearRealtimeRefreshTimer, enabled, scheduleRealtimeRefresh, supabase]);
|
|
64170
|
+
useEffect(() => {
|
|
64171
|
+
return () => {
|
|
64172
|
+
pendingRealtimeRefreshRef.current = false;
|
|
64173
|
+
clearRealtimeRefreshTimer();
|
|
64174
|
+
};
|
|
64175
|
+
}, [clearRealtimeRefreshTimer]);
|
|
64075
64176
|
useEffect(() => {
|
|
64076
64177
|
if (!enabled || !rawState || !resolvedCompanyId) {
|
|
64077
64178
|
return;
|
|
@@ -64150,6 +64251,83 @@ var useLiveMonitorBootstrap = ({
|
|
|
64150
64251
|
}
|
|
64151
64252
|
void fetchBootstrap(false);
|
|
64152
64253
|
}, [enabled, resolvedCompanyId, normalizedLineIds, supabase, fetchBootstrap]);
|
|
64254
|
+
const realtimeScopeKey = useMemo(() => Array.from(createResolvedScopeLookup(
|
|
64255
|
+
state.resolvedScope,
|
|
64256
|
+
state.workspaceMetrics,
|
|
64257
|
+
state.blueComparisonWorkspaceMetrics
|
|
64258
|
+
)).sort().join("||"), [state.resolvedScope, state.workspaceMetrics, state.blueComparisonWorkspaceMetrics]);
|
|
64259
|
+
useEffect(() => {
|
|
64260
|
+
if (!enabled || !resolvedCompanyId || !realtimeLineIdsKey || !supabase) {
|
|
64261
|
+
return void 0;
|
|
64262
|
+
}
|
|
64263
|
+
const scopeLookup = new Set(realtimeScopeKey ? realtimeScopeKey.split("||") : []);
|
|
64264
|
+
if (scopeLookup.size === 0) {
|
|
64265
|
+
return void 0;
|
|
64266
|
+
}
|
|
64267
|
+
const realtimeLineIdsForFilter = realtimeLineIdsKey.split(",").filter(Boolean);
|
|
64268
|
+
if (realtimeLineIdsForFilter.length === 0) {
|
|
64269
|
+
return void 0;
|
|
64270
|
+
}
|
|
64271
|
+
const lineIdFilter = `line_id=in.(${realtimeLineIdsForFilter.join(",")})`;
|
|
64272
|
+
const channels = [];
|
|
64273
|
+
const shouldRefreshForPayload = (payload) => {
|
|
64274
|
+
const payloadData = payload.new || payload.old;
|
|
64275
|
+
return scopeLookup.has(`${payloadData?.line_id}|${payloadData?.date}|${payloadData?.shift_id}`);
|
|
64276
|
+
};
|
|
64277
|
+
const createSubscription = (table, channelNameBase) => {
|
|
64278
|
+
const channelName = `${channelNameBase}-${state.scopeKey || requestKey}`.replace(/[^a-zA-Z0-9_-]/g, "");
|
|
64279
|
+
const channel = supabase.channel(channelName).on(
|
|
64280
|
+
"postgres_changes",
|
|
64281
|
+
{ event: "*", schema: "public", table, filter: lineIdFilter },
|
|
64282
|
+
(payload) => {
|
|
64283
|
+
if (shouldRefreshForPayload(payload)) {
|
|
64284
|
+
queueRealtimeRefresh();
|
|
64285
|
+
}
|
|
64286
|
+
}
|
|
64287
|
+
).subscribe();
|
|
64288
|
+
channels.push(channel);
|
|
64289
|
+
};
|
|
64290
|
+
createSubscription(companySpecificMetricsTable, "monitor-bootstrap-ws");
|
|
64291
|
+
createSubscription("line_metrics", "monitor-bootstrap-lm");
|
|
64292
|
+
createSubscription("wip_buffer_metrics", "monitor-bootstrap-wip-metrics");
|
|
64293
|
+
createSubscription("wip_buffer_alerts", "monitor-bootstrap-wip-alerts");
|
|
64294
|
+
return () => {
|
|
64295
|
+
channels.forEach((channel) => {
|
|
64296
|
+
supabase.removeChannel(channel);
|
|
64297
|
+
});
|
|
64298
|
+
};
|
|
64299
|
+
}, [
|
|
64300
|
+
enabled,
|
|
64301
|
+
resolvedCompanyId,
|
|
64302
|
+
realtimeLineIdsKey,
|
|
64303
|
+
supabase,
|
|
64304
|
+
realtimeScopeKey,
|
|
64305
|
+
state.scopeKey,
|
|
64306
|
+
requestKey,
|
|
64307
|
+
companySpecificMetricsTable,
|
|
64308
|
+
queueRealtimeRefresh
|
|
64309
|
+
]);
|
|
64310
|
+
useEffect(() => {
|
|
64311
|
+
if (!enabled || !resolvedCompanyId || normalizedLineIds.length === 0 || !supabase) {
|
|
64312
|
+
return void 0;
|
|
64313
|
+
}
|
|
64314
|
+
const forceRefreshOnResume = () => {
|
|
64315
|
+
void fetchBootstrapRef.current(true);
|
|
64316
|
+
};
|
|
64317
|
+
const handleVisibilityChange = () => {
|
|
64318
|
+
if (document.visibilityState === "visible") {
|
|
64319
|
+
forceRefreshOnResume();
|
|
64320
|
+
}
|
|
64321
|
+
};
|
|
64322
|
+
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
64323
|
+
window.addEventListener("focus", forceRefreshOnResume);
|
|
64324
|
+
window.addEventListener("online", forceRefreshOnResume);
|
|
64325
|
+
return () => {
|
|
64326
|
+
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
64327
|
+
window.removeEventListener("focus", forceRefreshOnResume);
|
|
64328
|
+
window.removeEventListener("online", forceRefreshOnResume);
|
|
64329
|
+
};
|
|
64330
|
+
}, [enabled, normalizedLineIds.length, resolvedCompanyId, supabase]);
|
|
64153
64331
|
useEffect(() => {
|
|
64154
64332
|
if (!enabled || !resolvedCompanyId || normalizedLineIds.length === 0 || !supabase) {
|
|
64155
64333
|
return void 0;
|
|
@@ -64904,7 +65082,6 @@ function HomeView({
|
|
|
64904
65082
|
const allGreenMilestoneTrackingRef = useRef({ identity: null, lastMilestoneSeconds: null });
|
|
64905
65083
|
const allGreenStreakTimerBaselineRef = useRef(null);
|
|
64906
65084
|
const [showAllGreenCelebration, setShowAllGreenCelebration] = useState(false);
|
|
64907
|
-
const [allGreenCelebrationStartedAtMs, setAllGreenCelebrationStartedAtMs] = useState(null);
|
|
64908
65085
|
const [greenStreakMilestoneBanner, setGreenStreakMilestoneBanner] = useState(null);
|
|
64909
65086
|
const [allGreenStreakNowMs, setAllGreenStreakNowMs] = useState(() => Date.now());
|
|
64910
65087
|
const currentAllGreenStreakNowMs = Math.max(allGreenStreakNowMs, Date.now());
|
|
@@ -64967,13 +65144,11 @@ function HomeView({
|
|
|
64967
65144
|
};
|
|
64968
65145
|
}, [allGreenMilestoneIdentity, allGreenStreakDisplay, currentAllGreenStreakNowMs]);
|
|
64969
65146
|
const allGreenCelebrationTimerText = useMemo(() => {
|
|
64970
|
-
if (!showAllGreenCelebration ||
|
|
65147
|
+
if (!showAllGreenCelebration || !visibleAllGreenStreakDisplay) {
|
|
64971
65148
|
return null;
|
|
64972
65149
|
}
|
|
64973
|
-
return formatAllGreenCelebrationTimer(
|
|
64974
|
-
|
|
64975
|
-
);
|
|
64976
|
-
}, [allGreenCelebrationStartedAtMs, currentAllGreenStreakNowMs, showAllGreenCelebration]);
|
|
65150
|
+
return formatAllGreenCelebrationTimer(visibleAllGreenStreakDisplay.elapsedSeconds);
|
|
65151
|
+
}, [showAllGreenCelebration, visibleAllGreenStreakDisplay]);
|
|
64977
65152
|
useEffect(() => {
|
|
64978
65153
|
const hasPossibleStreakTimer = showAllGreenCelebration || Boolean(allGreenStreakDisplay) || workspaceMetricsWithBreakState.some((workspace) => workspace.video_grid_green_streak_active === true);
|
|
64979
65154
|
if (!hasPossibleStreakTimer) {
|
|
@@ -64992,17 +65167,14 @@ function HomeView({
|
|
|
64992
65167
|
allGreenCelebrationTimerRef.current = null;
|
|
64993
65168
|
}
|
|
64994
65169
|
setShowAllGreenCelebration(false);
|
|
64995
|
-
setAllGreenCelebrationStartedAtMs(null);
|
|
64996
65170
|
}, []);
|
|
64997
65171
|
const triggerAllGreenCelebration = useCallback(() => {
|
|
64998
|
-
setAllGreenCelebrationStartedAtMs(Date.now());
|
|
64999
65172
|
setShowAllGreenCelebration(true);
|
|
65000
65173
|
if (allGreenCelebrationTimerRef.current) {
|
|
65001
65174
|
clearTimeout(allGreenCelebrationTimerRef.current);
|
|
65002
65175
|
}
|
|
65003
65176
|
allGreenCelebrationTimerRef.current = setTimeout(() => {
|
|
65004
65177
|
setShowAllGreenCelebration(false);
|
|
65005
|
-
setAllGreenCelebrationStartedAtMs(null);
|
|
65006
65178
|
allGreenCelebrationTimerRef.current = null;
|
|
65007
65179
|
}, ALL_GREEN_CELEBRATION_DURATION_MS);
|
|
65008
65180
|
}, []);
|