@optifye/dashboard-core 6.12.1 → 6.12.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -1
- package/dist/index.d.mts +41 -4
- package/dist/index.d.ts +41 -4
- package/dist/index.js +887 -342
- package/dist/index.mjs +883 -343
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -2599,19 +2599,206 @@ function getSentry() {
|
|
|
2599
2599
|
return null;
|
|
2600
2600
|
}
|
|
2601
2601
|
}
|
|
2602
|
+
var SENTRY_HANDLED_EVENT_WINDOW_MS = 10 * 60 * 1e3;
|
|
2603
|
+
var SENTRY_HANDLED_EVENT_SESSION_LIMIT = 20;
|
|
2604
|
+
var SENTRY_QUOTA_STORAGE_KEY = "optifye:sentry-handled-quota:v1";
|
|
2605
|
+
var sentryFingerprintSentAt = /* @__PURE__ */ new Map();
|
|
2606
|
+
var handledSentryEventCount = 0;
|
|
2607
|
+
var UUID_PATTERN = /[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/gi;
|
|
2608
|
+
var LONG_HEX_PATTERN = /\b[0-9a-f]{24,}\b/gi;
|
|
2609
|
+
var EMAIL_PATTERN = /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi;
|
|
2610
|
+
var BEARER_PATTERN = /\bBearer\s+[A-Za-z0-9._~+/=-]+/gi;
|
|
2611
|
+
var URI_PATTERN = /\b[a-z][a-z0-9+.-]{1,31}:\/\/[^\s)]+/gi;
|
|
2612
|
+
var MEDIA_PATH_PATTERN = /\b[^\s)]+\.m3u8(?:\?[^\s)]*)?/gi;
|
|
2613
|
+
var SENSITIVE_ASSIGNMENT_PATTERN = /\b([A-Za-z0-9_.-]*(?:authorization|cookie|password|secret|token|session|email|api[_-]?key)[A-Za-z0-9_.-]*)\b\s*[:=]\s*["']?[^"'\s,;)}\]]+/gi;
|
|
2614
|
+
var SENSITIVE_KEY_PATTERN = /(authorization|cookie|password|secret|token|session|email|api[_-]?key|url|stream|playlist|media)/i;
|
|
2615
|
+
function resetSentryQuotaForTests() {
|
|
2616
|
+
sentryFingerprintSentAt.clear();
|
|
2617
|
+
handledSentryEventCount = 0;
|
|
2618
|
+
const storage = getBrowserSessionStorage();
|
|
2619
|
+
storage?.removeItem(SENTRY_QUOTA_STORAGE_KEY);
|
|
2620
|
+
}
|
|
2621
|
+
var sanitizeString = (value) => {
|
|
2622
|
+
return value.replace(BEARER_PATTERN, "Bearer [redacted]").replace(SENSITIVE_ASSIGNMENT_PATTERN, (_match, key) => `${key}=[redacted]`).replace(URI_PATTERN, "[url]").replace(MEDIA_PATH_PATTERN, "[media]").replace(EMAIL_PATTERN, "[email]").replace(UUID_PATTERN, ":uuid").replace(LONG_HEX_PATTERN, ":id").replace(/\?.*$/, "").replace(/\s+/g, " ").trim();
|
|
2623
|
+
};
|
|
2624
|
+
var sanitizeRoute = (value) => {
|
|
2625
|
+
if (typeof value !== "string" || value.trim().length === 0) return void 0;
|
|
2626
|
+
try {
|
|
2627
|
+
const parsed = new URL(value, "https://optifye.local");
|
|
2628
|
+
return sanitizeString(parsed.pathname);
|
|
2629
|
+
} catch {
|
|
2630
|
+
return sanitizeString(value.split("?")[0] || value);
|
|
2631
|
+
}
|
|
2632
|
+
};
|
|
2633
|
+
var sanitizeValue = (value, depth = 0) => {
|
|
2634
|
+
if (depth > 3) return "[truncated]";
|
|
2635
|
+
if (typeof value === "string") return sanitizeString(value);
|
|
2636
|
+
if (typeof value === "number" || typeof value === "boolean" || value === null || value === void 0) return value;
|
|
2637
|
+
if (Array.isArray(value)) {
|
|
2638
|
+
return value.slice(0, 20).map((item) => sanitizeValue(item, depth + 1));
|
|
2639
|
+
}
|
|
2640
|
+
if (typeof value === "object") {
|
|
2641
|
+
const sanitized = {};
|
|
2642
|
+
Object.entries(value).forEach(([key, item]) => {
|
|
2643
|
+
sanitized[key] = SENSITIVE_KEY_PATTERN.test(key) ? "[redacted]" : sanitizeValue(item, depth + 1);
|
|
2644
|
+
});
|
|
2645
|
+
return sanitized;
|
|
2646
|
+
}
|
|
2647
|
+
return String(value);
|
|
2648
|
+
};
|
|
2649
|
+
var sanitizeStack = (stack) => {
|
|
2650
|
+
return stack.split("\n").map((line) => sanitizeString(line)).join("\n");
|
|
2651
|
+
};
|
|
2652
|
+
var sanitizeExtras = (extras) => {
|
|
2653
|
+
if (!extras) return void 0;
|
|
2654
|
+
return sanitizeValue(extras);
|
|
2655
|
+
};
|
|
2656
|
+
var getBrowserSessionStorage = () => {
|
|
2657
|
+
if (typeof window === "undefined") return null;
|
|
2658
|
+
try {
|
|
2659
|
+
return window.sessionStorage;
|
|
2660
|
+
} catch {
|
|
2661
|
+
return null;
|
|
2662
|
+
}
|
|
2663
|
+
};
|
|
2664
|
+
var loadSentryQuotaFromStorage = (now4) => {
|
|
2665
|
+
const storage = getBrowserSessionStorage();
|
|
2666
|
+
if (!storage) return;
|
|
2667
|
+
const rawState = storage.getItem(SENTRY_QUOTA_STORAGE_KEY);
|
|
2668
|
+
if (!rawState) return;
|
|
2669
|
+
try {
|
|
2670
|
+
const parsed = JSON.parse(rawState);
|
|
2671
|
+
const persistedCount = Number(parsed.handledEventCount);
|
|
2672
|
+
handledSentryEventCount = Number.isFinite(persistedCount) && persistedCount > 0 ? Math.floor(persistedCount) : 0;
|
|
2673
|
+
sentryFingerprintSentAt.clear();
|
|
2674
|
+
if (parsed.fingerprintSentAt && typeof parsed.fingerprintSentAt === "object") {
|
|
2675
|
+
Object.entries(parsed.fingerprintSentAt).forEach(([fingerprint, sentAt]) => {
|
|
2676
|
+
const sentAtMs = Number(sentAt);
|
|
2677
|
+
if (Number.isFinite(sentAtMs) && now4 - sentAtMs < SENTRY_HANDLED_EVENT_WINDOW_MS) {
|
|
2678
|
+
sentryFingerprintSentAt.set(fingerprint, sentAtMs);
|
|
2679
|
+
}
|
|
2680
|
+
});
|
|
2681
|
+
}
|
|
2682
|
+
} catch {
|
|
2683
|
+
storage.removeItem(SENTRY_QUOTA_STORAGE_KEY);
|
|
2684
|
+
}
|
|
2685
|
+
};
|
|
2686
|
+
var persistSentryQuotaToStorage = () => {
|
|
2687
|
+
const storage = getBrowserSessionStorage();
|
|
2688
|
+
if (!storage) return;
|
|
2689
|
+
try {
|
|
2690
|
+
storage.setItem(
|
|
2691
|
+
SENTRY_QUOTA_STORAGE_KEY,
|
|
2692
|
+
JSON.stringify({
|
|
2693
|
+
handledEventCount: handledSentryEventCount,
|
|
2694
|
+
fingerprintSentAt: Object.fromEntries(sentryFingerprintSentAt)
|
|
2695
|
+
})
|
|
2696
|
+
);
|
|
2697
|
+
} catch {
|
|
2698
|
+
}
|
|
2699
|
+
};
|
|
2700
|
+
var normalizeMessage = (error) => {
|
|
2701
|
+
const message = error instanceof Error ? error.message : String(error ?? "unknown");
|
|
2702
|
+
return sanitizeString(message.toLowerCase()).slice(0, 180) || "unknown";
|
|
2703
|
+
};
|
|
2704
|
+
var getErrorName = (error) => {
|
|
2705
|
+
if (error && typeof error === "object" && "name" in error) {
|
|
2706
|
+
const name = error.name;
|
|
2707
|
+
if (typeof name === "string" && name.trim()) return sanitizeString(name);
|
|
2708
|
+
}
|
|
2709
|
+
return error instanceof Error ? error.constructor.name : typeof error;
|
|
2710
|
+
};
|
|
2711
|
+
var getStatusFromError = (error) => {
|
|
2712
|
+
const message = error instanceof Error ? error.message : String(error ?? "");
|
|
2713
|
+
const statusMatch = message.match(/\((\d{3})\)/) || message.match(/http\s+(\d{3})/i) || message.match(/status:\s*(\d{3})/i);
|
|
2714
|
+
if (!statusMatch) return null;
|
|
2715
|
+
const status = Number.parseInt(statusMatch[1], 10);
|
|
2716
|
+
return Number.isFinite(status) ? status : null;
|
|
2717
|
+
};
|
|
2718
|
+
var hasCaptureOptionShape = (value) => {
|
|
2719
|
+
return "surface" in value || "route" in value || "status" in value || "severity" in value || "quotaKey" in value || "extras" in value;
|
|
2720
|
+
};
|
|
2721
|
+
var normalizeCaptureOptions = (options) => {
|
|
2722
|
+
if (!options) return {};
|
|
2723
|
+
const optionRecord = options;
|
|
2724
|
+
if (!hasCaptureOptionShape(optionRecord)) {
|
|
2725
|
+
return { extras: optionRecord };
|
|
2726
|
+
}
|
|
2727
|
+
const {
|
|
2728
|
+
surface,
|
|
2729
|
+
route,
|
|
2730
|
+
status,
|
|
2731
|
+
severity,
|
|
2732
|
+
quotaKey,
|
|
2733
|
+
extras,
|
|
2734
|
+
...rest
|
|
2735
|
+
} = options;
|
|
2736
|
+
return {
|
|
2737
|
+
surface: typeof surface === "string" ? surface : void 0,
|
|
2738
|
+
route: typeof route === "string" ? route : void 0,
|
|
2739
|
+
status: typeof status === "number" ? status : null,
|
|
2740
|
+
severity: severity === "info" || severity === "warning" || severity === "error" ? severity : void 0,
|
|
2741
|
+
quotaKey: typeof quotaKey === "string" ? quotaKey : void 0,
|
|
2742
|
+
extras: {
|
|
2743
|
+
...rest,
|
|
2744
|
+
...extras && typeof extras === "object" && !Array.isArray(extras) ? extras : {}
|
|
2745
|
+
}
|
|
2746
|
+
};
|
|
2747
|
+
};
|
|
2748
|
+
var buildSentryFingerprint = (error, options) => {
|
|
2749
|
+
if (options.quotaKey) return sanitizeString(options.quotaKey);
|
|
2750
|
+
const surface = sanitizeString(options.surface || "frontend");
|
|
2751
|
+
const route = sanitizeRoute(options.route || options.extras?.route || options.extras?.endpoint || options.extras?.url) || "unknown-route";
|
|
2752
|
+
const status = options.status ?? getStatusFromError(error) ?? "unknown-status";
|
|
2753
|
+
return [
|
|
2754
|
+
surface,
|
|
2755
|
+
route,
|
|
2756
|
+
String(status),
|
|
2757
|
+
getErrorName(error),
|
|
2758
|
+
normalizeMessage(error)
|
|
2759
|
+
].join("|");
|
|
2760
|
+
};
|
|
2761
|
+
var shouldSendHandledSentryEvent = (fingerprint) => {
|
|
2762
|
+
const now4 = Date.now();
|
|
2763
|
+
loadSentryQuotaFromStorage(now4);
|
|
2764
|
+
const lastSentAt = sentryFingerprintSentAt.get(fingerprint);
|
|
2765
|
+
if (lastSentAt !== void 0 && now4 - lastSentAt < SENTRY_HANDLED_EVENT_WINDOW_MS) {
|
|
2766
|
+
return false;
|
|
2767
|
+
}
|
|
2768
|
+
if (handledSentryEventCount >= SENTRY_HANDLED_EVENT_SESSION_LIMIT) {
|
|
2769
|
+
return false;
|
|
2770
|
+
}
|
|
2771
|
+
sentryFingerprintSentAt.set(fingerprint, now4);
|
|
2772
|
+
handledSentryEventCount += 1;
|
|
2773
|
+
persistSentryQuotaToStorage();
|
|
2774
|
+
return true;
|
|
2775
|
+
};
|
|
2776
|
+
var createSanitizedSentryException = (error) => {
|
|
2777
|
+
if (error instanceof Error) {
|
|
2778
|
+
const sanitizedError = new Error(sanitizeString(error.message) || getErrorName(error) || "Error");
|
|
2779
|
+
sanitizedError.name = getErrorName(error) || "Error";
|
|
2780
|
+
if (typeof error.stack === "string") {
|
|
2781
|
+
sanitizedError.stack = sanitizeStack(error.stack);
|
|
2782
|
+
}
|
|
2783
|
+
return sanitizedError;
|
|
2784
|
+
}
|
|
2785
|
+
if (typeof error === "string") {
|
|
2786
|
+
return sanitizeString(error) || "unknown";
|
|
2787
|
+
}
|
|
2788
|
+
return sanitizeValue(error);
|
|
2789
|
+
};
|
|
2602
2790
|
function isIgnorableFrontendError(error) {
|
|
2603
2791
|
const name = error && typeof error === "object" ? error.name || "" : "";
|
|
2604
2792
|
const message = error instanceof Error ? error.message : String(error ?? "");
|
|
2605
2793
|
const lowerMessage = message.toLowerCase();
|
|
2606
|
-
return name === "AbortError" || lowerMessage.includes("the operation was aborted") || lowerMessage.includes("signal is aborted") || lowerMessage.includes("resizeobserver loop");
|
|
2794
|
+
return name === "AbortError" || name === "NotAllowedError" || lowerMessage.includes("the operation was aborted") || lowerMessage.includes("signal is aborted") || lowerMessage.includes("resizeobserver loop") || lowerMessage.includes("play() failed") || lowerMessage.includes("play request was interrupted") || lowerMessage.includes("autoplay") || lowerMessage.includes("not allowed by the user agent") || lowerMessage.includes("recoverable hls") || lowerMessage.includes("non-fatal hls") || lowerMessage.includes("fragloaderror") || lowerMessage.includes("frag load error") || lowerMessage.includes("fragloadtimeout") || lowerMessage.includes("bufferstallederror") || lowerMessage.includes("buffer stalled") || lowerMessage.includes("media error recovered") || lowerMessage.includes("recovermediaerror");
|
|
2607
2795
|
}
|
|
2608
2796
|
function setSentryUserContext(user) {
|
|
2609
2797
|
const sentry = getSentry();
|
|
2610
2798
|
if (!sentry) return;
|
|
2611
2799
|
if (user) {
|
|
2612
2800
|
sentry.setUser({
|
|
2613
|
-
id: user.id
|
|
2614
|
-
email: user.email
|
|
2801
|
+
id: user.id
|
|
2615
2802
|
});
|
|
2616
2803
|
sentry.setTags({
|
|
2617
2804
|
company_id: user.company_id || "unknown",
|
|
@@ -2662,28 +2849,60 @@ function applyScopeExtras(scope, extras) {
|
|
|
2662
2849
|
function captureSentryMessage(message, level = "warning", extras) {
|
|
2663
2850
|
const sentry = getSentry();
|
|
2664
2851
|
if (!sentry || !sentry.captureMessage) return;
|
|
2852
|
+
const options = normalizeCaptureOptions({ ...normalizeCaptureOptions(extras), severity: level });
|
|
2853
|
+
const fingerprint = buildSentryFingerprint(new Error(message), options);
|
|
2854
|
+
if (!shouldSendHandledSentryEvent(fingerprint)) return;
|
|
2855
|
+
const sanitizedExtras = sanitizeExtras({
|
|
2856
|
+
...options.extras,
|
|
2857
|
+
sentry_quota_key: fingerprint,
|
|
2858
|
+
sentry_capture_policy: "quota_controlled"
|
|
2859
|
+
});
|
|
2860
|
+
const route = sanitizeRoute(options.route || options.extras?.route || options.extras?.endpoint || options.extras?.url);
|
|
2861
|
+
const sanitizedMessage = sanitizeString(message) || "Sentry message";
|
|
2665
2862
|
if (sentry.withScope) {
|
|
2666
2863
|
sentry.withScope((scope) => {
|
|
2667
2864
|
scope.setLevel?.(level);
|
|
2668
|
-
|
|
2669
|
-
|
|
2865
|
+
scope.setFingerprint?.([fingerprint]);
|
|
2866
|
+
if (options.surface) scope.setTag?.("surface", sanitizeString(options.surface));
|
|
2867
|
+
if (route) scope.setTag?.("route", route);
|
|
2868
|
+
if (options.status !== void 0 && options.status !== null) scope.setTag?.("status", options.status);
|
|
2869
|
+
applyScopeExtras(scope, sanitizedExtras);
|
|
2870
|
+
sentry.captureMessage?.(sanitizedMessage);
|
|
2670
2871
|
});
|
|
2671
2872
|
return;
|
|
2672
2873
|
}
|
|
2673
|
-
sentry.captureMessage(
|
|
2874
|
+
sentry.captureMessage(sanitizedMessage, level);
|
|
2674
2875
|
}
|
|
2675
2876
|
function captureSentryException(error, extras) {
|
|
2877
|
+
if (isIgnorableFrontendError(error)) {
|
|
2878
|
+
return;
|
|
2879
|
+
}
|
|
2676
2880
|
const sentry = getSentry();
|
|
2677
2881
|
if (!sentry || !sentry.captureException) return;
|
|
2882
|
+
const options = normalizeCaptureOptions(extras);
|
|
2883
|
+
const fingerprint = buildSentryFingerprint(error, options);
|
|
2884
|
+
if (!shouldSendHandledSentryEvent(fingerprint)) return;
|
|
2885
|
+
const sanitizedExtras = sanitizeExtras({
|
|
2886
|
+
...options.extras,
|
|
2887
|
+
sentry_quota_key: fingerprint,
|
|
2888
|
+
sentry_capture_policy: "quota_controlled"
|
|
2889
|
+
});
|
|
2890
|
+
const route = sanitizeRoute(options.route || options.extras?.route || options.extras?.endpoint || options.extras?.url);
|
|
2891
|
+
const status = options.status ?? getStatusFromError(error);
|
|
2892
|
+
const sanitizedError = createSanitizedSentryException(error);
|
|
2678
2893
|
if (sentry.withScope) {
|
|
2679
2894
|
sentry.withScope((scope) => {
|
|
2680
|
-
scope.setLevel?.("error");
|
|
2681
|
-
|
|
2682
|
-
|
|
2895
|
+
scope.setLevel?.(options.severity || "error");
|
|
2896
|
+
scope.setFingerprint?.([fingerprint]);
|
|
2897
|
+
if (options.surface) scope.setTag?.("surface", sanitizeString(options.surface));
|
|
2898
|
+
if (route) scope.setTag?.("route", route);
|
|
2899
|
+
if (status !== null && status !== void 0) scope.setTag?.("status", status);
|
|
2900
|
+
applyScopeExtras(scope, sanitizedExtras);
|
|
2901
|
+
sentry.captureException?.(sanitizedError);
|
|
2683
2902
|
});
|
|
2684
2903
|
return;
|
|
2685
2904
|
}
|
|
2686
|
-
sentry.captureException(
|
|
2905
|
+
sentry.captureException(sanitizedError);
|
|
2687
2906
|
}
|
|
2688
2907
|
function captureHandledFrontendException(error, extras) {
|
|
2689
2908
|
if (isIgnorableFrontendError(error)) {
|
|
@@ -2691,6 +2910,23 @@ function captureHandledFrontendException(error, extras) {
|
|
|
2691
2910
|
}
|
|
2692
2911
|
captureSentryException(error, extras);
|
|
2693
2912
|
}
|
|
2913
|
+
function addSentryBreadcrumb(message, options = {}) {
|
|
2914
|
+
const sentry = getSentry();
|
|
2915
|
+
if (!sentry?.addBreadcrumb) return;
|
|
2916
|
+
const route = sanitizeRoute(options.route || options.extras?.route || options.extras?.endpoint || options.extras?.url);
|
|
2917
|
+
const data = sanitizeExtras({
|
|
2918
|
+
surface: options.surface,
|
|
2919
|
+
route,
|
|
2920
|
+
status: options.status,
|
|
2921
|
+
...options.extras
|
|
2922
|
+
});
|
|
2923
|
+
sentry.addBreadcrumb({
|
|
2924
|
+
category: options.category || options.surface || "frontend",
|
|
2925
|
+
message: sanitizeString(message),
|
|
2926
|
+
level: options.severity || "info",
|
|
2927
|
+
data
|
|
2928
|
+
});
|
|
2929
|
+
}
|
|
2694
2930
|
|
|
2695
2931
|
// src/lib/services/backendClient.ts
|
|
2696
2932
|
var ACCESS_TOKEN_REFRESH_BUFFER_MS = 6e4;
|
|
@@ -2758,7 +2994,7 @@ var createAbortError = () => {
|
|
|
2758
2994
|
return error;
|
|
2759
2995
|
}
|
|
2760
2996
|
};
|
|
2761
|
-
var
|
|
2997
|
+
var getStatusFromError2 = (error) => {
|
|
2762
2998
|
const message = error instanceof Error ? error.message : String(error ?? "");
|
|
2763
2999
|
const statusMatch = message.match(/\((\d{3})\)/) || message.match(/http\s+(\d{3})/i);
|
|
2764
3000
|
if (!statusMatch) {
|
|
@@ -2774,7 +3010,7 @@ var isRetryableError = (error) => {
|
|
|
2774
3010
|
if (isAbortError(error)) {
|
|
2775
3011
|
return false;
|
|
2776
3012
|
}
|
|
2777
|
-
const status =
|
|
3013
|
+
const status = getStatusFromError2(error);
|
|
2778
3014
|
if (status !== null) {
|
|
2779
3015
|
return status >= 500 || status === 408 || status === 425 || status === 429;
|
|
2780
3016
|
}
|
|
@@ -2798,6 +3034,7 @@ var fetchBackendJson = async (supabase, endpoint, options = {}) => {
|
|
|
2798
3034
|
timeoutMs = DEFAULT_TIMEOUT_MS,
|
|
2799
3035
|
retries = 0,
|
|
2800
3036
|
retryDelayMs = DEFAULT_RETRY_DELAY_MS,
|
|
3037
|
+
sentry,
|
|
2801
3038
|
signal: externalSignal,
|
|
2802
3039
|
...fetchOptions
|
|
2803
3040
|
} = options;
|
|
@@ -2835,14 +3072,22 @@ var fetchBackendJson = async (supabase, endpoint, options = {}) => {
|
|
|
2835
3072
|
} catch (error) {
|
|
2836
3073
|
const wrappedError = externalSignal?.aborted || controller.signal.aborted && !isAbortError(error) ? createAbortError() : error;
|
|
2837
3074
|
if (attempt >= retries || !isRetryableError(wrappedError)) {
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
3075
|
+
if (sentry && sentry.capture !== false) {
|
|
3076
|
+
captureHandledFrontendException(wrappedError, {
|
|
3077
|
+
surface: sentry.surface || "backend_client",
|
|
3078
|
+
route: sentry.route || endpoint,
|
|
3079
|
+
status: sentry.status ?? getStatusFromError2(wrappedError),
|
|
3080
|
+
severity: sentry.severity || "error",
|
|
3081
|
+
quotaKey: sentry.quotaKey,
|
|
3082
|
+
extras: {
|
|
3083
|
+
method,
|
|
3084
|
+
retry_attempt: attempt,
|
|
3085
|
+
retries,
|
|
3086
|
+
pathname: typeof window !== "undefined" ? window.location.pathname : "unknown",
|
|
3087
|
+
...sentry.extras
|
|
3088
|
+
}
|
|
3089
|
+
});
|
|
3090
|
+
}
|
|
2846
3091
|
throw wrappedError;
|
|
2847
3092
|
}
|
|
2848
3093
|
await new Promise((resolve) => globalThis.setTimeout(resolve, retryDelayMs));
|
|
@@ -2928,6 +3173,7 @@ var ApiClient = class {
|
|
|
2928
3173
|
retryDelay = 1e3,
|
|
2929
3174
|
silentErrors = true,
|
|
2930
3175
|
fallbackData = null,
|
|
3176
|
+
sentry,
|
|
2931
3177
|
...fetchOptions
|
|
2932
3178
|
} = options;
|
|
2933
3179
|
let lastError = null;
|
|
@@ -2961,24 +3207,36 @@ var ApiClient = class {
|
|
|
2961
3207
|
await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
2962
3208
|
continue;
|
|
2963
3209
|
}
|
|
2964
|
-
if (
|
|
3210
|
+
if (sentry && sentry.capture !== false) {
|
|
2965
3211
|
captureHandledFrontendException(lastError, {
|
|
3212
|
+
surface: sentry.surface || "api_client",
|
|
3213
|
+
route: sentry.route || url,
|
|
3214
|
+
status: sentry.status,
|
|
3215
|
+
severity: sentry.severity || "error",
|
|
3216
|
+
quotaKey: sentry.quotaKey,
|
|
3217
|
+
extras: {
|
|
3218
|
+
retries,
|
|
3219
|
+
silent_errors: silentErrors,
|
|
3220
|
+
pathname: typeof window !== "undefined" ? window.location.pathname : "unknown",
|
|
3221
|
+
...sentry.extras
|
|
3222
|
+
}
|
|
3223
|
+
});
|
|
3224
|
+
} else {
|
|
3225
|
+
addSentryBreadcrumb("API client request failed", {
|
|
2966
3226
|
surface: "api_client",
|
|
2967
|
-
url,
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
3227
|
+
route: url,
|
|
3228
|
+
severity: silentErrors ? "info" : "warning",
|
|
3229
|
+
extras: {
|
|
3230
|
+
retries,
|
|
3231
|
+
silent_errors: silentErrors,
|
|
3232
|
+
pathname: typeof window !== "undefined" ? window.location.pathname : "unknown"
|
|
3233
|
+
}
|
|
2971
3234
|
});
|
|
3235
|
+
}
|
|
3236
|
+
if (silentErrors) {
|
|
2972
3237
|
console.warn("[ApiClient] All retries exhausted, returning fallback data");
|
|
2973
3238
|
return fallbackData;
|
|
2974
3239
|
} else {
|
|
2975
|
-
captureHandledFrontendException(lastError, {
|
|
2976
|
-
surface: "api_client",
|
|
2977
|
-
url,
|
|
2978
|
-
retries,
|
|
2979
|
-
silent_errors: false,
|
|
2980
|
-
pathname: typeof window !== "undefined" ? window.location.pathname : "unknown"
|
|
2981
|
-
});
|
|
2982
3240
|
throw lastError;
|
|
2983
3241
|
}
|
|
2984
3242
|
}
|
|
@@ -3230,8 +3488,12 @@ var AuthService = class {
|
|
|
3230
3488
|
timeout: 1e4,
|
|
3231
3489
|
// 10 seconds
|
|
3232
3490
|
retries: 1,
|
|
3233
|
-
silentErrors: false
|
|
3491
|
+
silentErrors: false,
|
|
3234
3492
|
// We want to know about auth errors
|
|
3493
|
+
sentry: {
|
|
3494
|
+
surface: "auth_session_request",
|
|
3495
|
+
route: "/api/auth/session"
|
|
3496
|
+
}
|
|
3235
3497
|
}
|
|
3236
3498
|
);
|
|
3237
3499
|
console.log("[AuthService] Session loaded:", {
|
|
@@ -3301,7 +3563,11 @@ var AuthService = class {
|
|
|
3301
3563
|
timeout: 1e4,
|
|
3302
3564
|
// 10 seconds
|
|
3303
3565
|
retries: 1,
|
|
3304
|
-
silentErrors: false
|
|
3566
|
+
silentErrors: false,
|
|
3567
|
+
sentry: {
|
|
3568
|
+
surface: "auth_permissions_request",
|
|
3569
|
+
route: "/api/auth/permissions"
|
|
3570
|
+
}
|
|
3305
3571
|
}
|
|
3306
3572
|
);
|
|
3307
3573
|
console.log("[AuthService] Permissions loaded for role:", data.role);
|
|
@@ -5943,12 +6209,16 @@ var workspaceService = {
|
|
|
5943
6209
|
return displayNamesMap;
|
|
5944
6210
|
} catch (error) {
|
|
5945
6211
|
console.error("Error fetching workspace display names:", error);
|
|
5946
|
-
|
|
6212
|
+
addSentryBreadcrumb("Workspace display-name fallback failed", {
|
|
5947
6213
|
surface: "workspace_display_names",
|
|
5948
6214
|
route: "/api/workspaces/display-names",
|
|
5949
|
-
|
|
5950
|
-
|
|
5951
|
-
|
|
6215
|
+
severity: "warning",
|
|
6216
|
+
extras: {
|
|
6217
|
+
company_id: companyId || null,
|
|
6218
|
+
line_id: lineId || null,
|
|
6219
|
+
pathname: typeof window !== "undefined" ? window.location.pathname : "unknown",
|
|
6220
|
+
error_message: error instanceof Error ? error.message : String(error)
|
|
6221
|
+
}
|
|
5952
6222
|
});
|
|
5953
6223
|
throw error;
|
|
5954
6224
|
}
|
|
@@ -7552,11 +7822,28 @@ var shouldReportMixpanel = (key, isError) => {
|
|
|
7552
7822
|
};
|
|
7553
7823
|
var reportMixpanelWarning = (key, message, extras) => {
|
|
7554
7824
|
if (!shouldReportMixpanel(key, false)) return;
|
|
7555
|
-
|
|
7825
|
+
addSentryBreadcrumb(message, {
|
|
7826
|
+
surface: "mixpanel",
|
|
7827
|
+
severity: "warning",
|
|
7828
|
+
extras: {
|
|
7829
|
+
key,
|
|
7830
|
+
...baseMixpanelExtras(),
|
|
7831
|
+
...extras
|
|
7832
|
+
}
|
|
7833
|
+
});
|
|
7556
7834
|
};
|
|
7557
7835
|
var reportMixpanelError = (key, error, extras) => {
|
|
7558
7836
|
if (!shouldReportMixpanel(key, true)) return;
|
|
7559
|
-
|
|
7837
|
+
addSentryBreadcrumb("Mixpanel operation failed", {
|
|
7838
|
+
surface: "mixpanel",
|
|
7839
|
+
severity: "warning",
|
|
7840
|
+
extras: {
|
|
7841
|
+
key,
|
|
7842
|
+
error_message: error instanceof Error ? error.message : String(error ?? "unknown"),
|
|
7843
|
+
...baseMixpanelExtras(),
|
|
7844
|
+
...extras
|
|
7845
|
+
}
|
|
7846
|
+
});
|
|
7560
7847
|
};
|
|
7561
7848
|
var normalizeCoreEventName = (eventName) => {
|
|
7562
7849
|
const canonicalName = MIXPANEL_EVENT_NAME_ALIASES[eventName] || eventName;
|
|
@@ -9573,11 +9860,15 @@ var LinesService = class {
|
|
|
9573
9860
|
}));
|
|
9574
9861
|
} catch (error) {
|
|
9575
9862
|
console.error("Error fetching lines:", error);
|
|
9576
|
-
|
|
9863
|
+
addSentryBreadcrumb("Lines service request failed", {
|
|
9577
9864
|
surface: "lines_service",
|
|
9578
|
-
|
|
9579
|
-
|
|
9580
|
-
|
|
9865
|
+
route: "/api/lines",
|
|
9866
|
+
severity: "warning",
|
|
9867
|
+
extras: {
|
|
9868
|
+
operation: "getLinesByCompanyId",
|
|
9869
|
+
company_id: companyId,
|
|
9870
|
+
pathname: typeof window !== "undefined" ? window.location.pathname : "unknown"
|
|
9871
|
+
}
|
|
9581
9872
|
});
|
|
9582
9873
|
throw new Error(`Failed to fetch lines: ${error.message}`);
|
|
9583
9874
|
}
|
|
@@ -9628,10 +9919,14 @@ var LinesService = class {
|
|
|
9628
9919
|
}));
|
|
9629
9920
|
} catch (error) {
|
|
9630
9921
|
console.error("Error fetching all lines:", error);
|
|
9631
|
-
|
|
9922
|
+
addSentryBreadcrumb("Lines service request failed", {
|
|
9632
9923
|
surface: "lines_service",
|
|
9633
|
-
|
|
9634
|
-
|
|
9924
|
+
route: "/api/lines",
|
|
9925
|
+
severity: "warning",
|
|
9926
|
+
extras: {
|
|
9927
|
+
operation: "getAllLines",
|
|
9928
|
+
pathname: typeof window !== "undefined" ? window.location.pathname : "unknown"
|
|
9929
|
+
}
|
|
9635
9930
|
});
|
|
9636
9931
|
throw new Error(`Failed to fetch lines: ${error.message}`);
|
|
9637
9932
|
}
|
|
@@ -9691,11 +9986,15 @@ var LinesService = class {
|
|
|
9691
9986
|
};
|
|
9692
9987
|
} catch (error) {
|
|
9693
9988
|
console.error("Error fetching line:", error);
|
|
9694
|
-
|
|
9989
|
+
addSentryBreadcrumb("Lines service request failed", {
|
|
9695
9990
|
surface: "lines_service",
|
|
9696
|
-
|
|
9697
|
-
|
|
9698
|
-
|
|
9991
|
+
route: "/api/lines/:id",
|
|
9992
|
+
severity: "warning",
|
|
9993
|
+
extras: {
|
|
9994
|
+
operation: "getLineById",
|
|
9995
|
+
line_id: lineId,
|
|
9996
|
+
pathname: typeof window !== "undefined" ? window.location.pathname : "unknown"
|
|
9997
|
+
}
|
|
9699
9998
|
});
|
|
9700
9999
|
throw new Error(`Failed to fetch line: ${error.message}`);
|
|
9701
10000
|
}
|
|
@@ -13004,7 +13303,8 @@ var toWorkspaceDetailedMetrics = ({
|
|
|
13004
13303
|
const targetOutput = coerceNumber(data.target_output ?? data.total_day_output, 0);
|
|
13005
13304
|
const idealOutput = coerceNumber(data.ideal_output ?? data.ideal_output_until_now, 0);
|
|
13006
13305
|
const outputDifference = totalActions - idealOutput;
|
|
13007
|
-
const
|
|
13306
|
+
const hasHourlyTargetOutputField = Object.prototype.hasOwnProperty.call(data, "hourly_target_output");
|
|
13307
|
+
const hourlyTargetOutput = Array.isArray(data.hourly_target_output) ? data.hourly_target_output.map((value) => value === null || value === void 0 ? null : coerceNumber(value, 0)) : hasHourlyTargetOutputField ? null : void 0;
|
|
13008
13308
|
const hourlyCycleTimes = Array.isArray(data.hourly_cycle_times) ? data.hourly_cycle_times.map((value) => coerceNumber(value, 0)) : [];
|
|
13009
13309
|
const cycleCompletionClipCount = data.cycle_completion_clip_count === null || data.cycle_completion_clip_count === void 0 ? null : coerceNumber(data.cycle_completion_clip_count, 0);
|
|
13010
13310
|
const cycleTimeDataStatus = data.cycle_time_data_status === "missing_clips" ? "missing_clips" : data.cycle_time_data_status === "available" ? "available" : null;
|
|
@@ -13169,6 +13469,17 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId, options) => {
|
|
|
13169
13469
|
workspaceMetricsStore.setDetailed(transformedData);
|
|
13170
13470
|
} catch (err) {
|
|
13171
13471
|
console.error("Error fetching workspace metrics:", err);
|
|
13472
|
+
captureHandledFrontendException(err, {
|
|
13473
|
+
surface: "workspace_detail_metrics",
|
|
13474
|
+
route: "/api/dashboard/workspace/:workspaceId/metrics",
|
|
13475
|
+
extras: {
|
|
13476
|
+
workspace_id: workspaceId,
|
|
13477
|
+
company_id: companyId,
|
|
13478
|
+
date,
|
|
13479
|
+
shift_id: shiftId,
|
|
13480
|
+
pathname: typeof window !== "undefined" ? window.location.pathname : "unknown"
|
|
13481
|
+
}
|
|
13482
|
+
});
|
|
13172
13483
|
setError({ message: err.message, code: err.code });
|
|
13173
13484
|
} finally {
|
|
13174
13485
|
isFetchingRef.current = false;
|
|
@@ -14309,6 +14620,7 @@ var transformMonitorWorkspaceMetrics = ({
|
|
|
14309
14620
|
recent_flow_window_minutes: item.recent_flow_window_minutes ?? null,
|
|
14310
14621
|
recent_flow_effective_end_at: item.recent_flow_effective_end_at ?? null,
|
|
14311
14622
|
recent_flow_computed_at: item.recent_flow_computed_at ?? null,
|
|
14623
|
+
recent_flow_forced_zero_after_shift: item.recent_flow_forced_zero_after_shift ?? null,
|
|
14312
14624
|
scheduled_break_active: item.scheduled_break_active ?? false,
|
|
14313
14625
|
incoming_wip_current: item.incoming_wip_current ?? null,
|
|
14314
14626
|
incoming_wip_effective_at: item.incoming_wip_effective_at ?? null,
|
|
@@ -21435,20 +21747,26 @@ var apiUtils = {
|
|
|
21435
21747
|
const token = sessionResponse.data.session?.access_token;
|
|
21436
21748
|
if (!token) {
|
|
21437
21749
|
console.error("API Util: No authentication token available.");
|
|
21438
|
-
|
|
21750
|
+
addSentryBreadcrumb("API utility request skipped without auth token", {
|
|
21439
21751
|
surface: "api_utils",
|
|
21440
|
-
|
|
21441
|
-
|
|
21752
|
+
route: relativeEndpoint,
|
|
21753
|
+
severity: "warning",
|
|
21754
|
+
extras: {
|
|
21755
|
+
reason: "missing_auth_token"
|
|
21756
|
+
}
|
|
21442
21757
|
});
|
|
21443
21758
|
throw new Error("Authentication required.");
|
|
21444
21759
|
}
|
|
21445
21760
|
const baseUrl = config.apiBaseUrl;
|
|
21446
21761
|
if (!baseUrl) {
|
|
21447
21762
|
console.error("API Util: apiBaseUrl is not configured.");
|
|
21448
|
-
|
|
21763
|
+
addSentryBreadcrumb("API utility request skipped without base URL", {
|
|
21449
21764
|
surface: "api_utils",
|
|
21450
|
-
|
|
21451
|
-
|
|
21765
|
+
route: relativeEndpoint,
|
|
21766
|
+
severity: "warning",
|
|
21767
|
+
extras: {
|
|
21768
|
+
reason: "missing_api_base_url"
|
|
21769
|
+
}
|
|
21452
21770
|
});
|
|
21453
21771
|
throw new Error("API base URL is not configured.");
|
|
21454
21772
|
}
|
|
@@ -21478,11 +21796,14 @@ var apiUtils = {
|
|
|
21478
21796
|
return await response.json();
|
|
21479
21797
|
} catch (error) {
|
|
21480
21798
|
console.error(`Network or fetch error calling ${endpoint}:`, error);
|
|
21481
|
-
|
|
21799
|
+
addSentryBreadcrumb("API utility request failed", {
|
|
21482
21800
|
surface: "api_utils",
|
|
21483
|
-
endpoint,
|
|
21484
|
-
|
|
21485
|
-
|
|
21801
|
+
route: endpoint,
|
|
21802
|
+
severity: "warning",
|
|
21803
|
+
extras: {
|
|
21804
|
+
method: options.method || "GET",
|
|
21805
|
+
pathname: typeof window !== "undefined" ? window.location.pathname : "unknown"
|
|
21806
|
+
}
|
|
21486
21807
|
});
|
|
21487
21808
|
if (error instanceof Error) {
|
|
21488
21809
|
throw error;
|
|
@@ -35185,6 +35506,261 @@ var Button = React144.forwardRef(
|
|
|
35185
35506
|
}
|
|
35186
35507
|
);
|
|
35187
35508
|
Button.displayName = "Button";
|
|
35509
|
+
|
|
35510
|
+
// src/lib/utils/hourlyTargets.ts
|
|
35511
|
+
var stripSeconds2 = (timeStr) => timeStr ? timeStr.slice(0, 5) : timeStr;
|
|
35512
|
+
var MINUTES_PER_DAY = 24 * 60;
|
|
35513
|
+
var parseTimeToMinutes2 = (timeString) => {
|
|
35514
|
+
const normalized = stripSeconds2(timeString || "");
|
|
35515
|
+
if (!normalized || !/^[0-2]\d:[0-5]\d$/.test(normalized)) return Number.NaN;
|
|
35516
|
+
const [hours, minutes] = normalized.split(":").map(Number);
|
|
35517
|
+
return hours * 60 + minutes;
|
|
35518
|
+
};
|
|
35519
|
+
var normalizeBreaksOnShiftTimeline = (shiftStart, breaks) => {
|
|
35520
|
+
const shiftStartMinutes = parseTimeToMinutes2(shiftStart);
|
|
35521
|
+
if (!Number.isFinite(shiftStartMinutes)) return [];
|
|
35522
|
+
const normalizedBreaks = [];
|
|
35523
|
+
for (const entry of breaks) {
|
|
35524
|
+
const startRaw = parseTimeToMinutes2(entry.startTime);
|
|
35525
|
+
const endRaw = parseTimeToMinutes2(entry.endTime);
|
|
35526
|
+
if (!Number.isFinite(startRaw) || !Number.isFinite(endRaw)) continue;
|
|
35527
|
+
let start = startRaw;
|
|
35528
|
+
let end = endRaw;
|
|
35529
|
+
if (end <= start) {
|
|
35530
|
+
end += 24 * 60;
|
|
35531
|
+
}
|
|
35532
|
+
if (start < shiftStartMinutes) {
|
|
35533
|
+
start += 24 * 60;
|
|
35534
|
+
end += 24 * 60;
|
|
35535
|
+
}
|
|
35536
|
+
const label = entry.remarks?.trim() || "Break";
|
|
35537
|
+
normalizedBreaks.push({ start, end, label });
|
|
35538
|
+
}
|
|
35539
|
+
return normalizedBreaks;
|
|
35540
|
+
};
|
|
35541
|
+
var roundTarget = (value, mode) => {
|
|
35542
|
+
if (!Number.isFinite(value)) return 0;
|
|
35543
|
+
switch (mode) {
|
|
35544
|
+
case "floor":
|
|
35545
|
+
return Math.floor(value);
|
|
35546
|
+
case "ceil":
|
|
35547
|
+
return Math.ceil(value);
|
|
35548
|
+
case "round":
|
|
35549
|
+
default:
|
|
35550
|
+
return Math.round(value);
|
|
35551
|
+
}
|
|
35552
|
+
};
|
|
35553
|
+
var formatDateKey = (date) => {
|
|
35554
|
+
const year = date.getUTCFullYear();
|
|
35555
|
+
const month = `${date.getUTCMonth() + 1}`.padStart(2, "0");
|
|
35556
|
+
const day = `${date.getUTCDate()}`.padStart(2, "0");
|
|
35557
|
+
return `${year}-${month}-${day}`;
|
|
35558
|
+
};
|
|
35559
|
+
var shiftDateKey = (dateKey, deltaDays) => {
|
|
35560
|
+
const [yearPart, monthPart, dayPart] = dateKey.split("-").map(Number);
|
|
35561
|
+
const year = Number.isFinite(yearPart) ? yearPart : 1970;
|
|
35562
|
+
const month = Number.isFinite(monthPart) ? monthPart : 1;
|
|
35563
|
+
const day = Number.isFinite(dayPart) ? dayPart : 1;
|
|
35564
|
+
const date = new Date(Date.UTC(year, month - 1, day));
|
|
35565
|
+
date.setUTCDate(date.getUTCDate() + deltaDays);
|
|
35566
|
+
return formatDateKey(date);
|
|
35567
|
+
};
|
|
35568
|
+
var getZonedNowSnapshot = (timeZone, now4) => {
|
|
35569
|
+
const formatter = new Intl.DateTimeFormat("en-US", {
|
|
35570
|
+
timeZone,
|
|
35571
|
+
year: "numeric",
|
|
35572
|
+
month: "2-digit",
|
|
35573
|
+
day: "2-digit",
|
|
35574
|
+
hour: "2-digit",
|
|
35575
|
+
minute: "2-digit",
|
|
35576
|
+
hourCycle: "h23"
|
|
35577
|
+
});
|
|
35578
|
+
const parts = formatter.formatToParts(now4).reduce((acc, part) => {
|
|
35579
|
+
if (part.type !== "literal") {
|
|
35580
|
+
acc[part.type] = part.value;
|
|
35581
|
+
}
|
|
35582
|
+
return acc;
|
|
35583
|
+
}, {});
|
|
35584
|
+
const year = Number(parts.year);
|
|
35585
|
+
const month = Number(parts.month);
|
|
35586
|
+
const day = Number(parts.day);
|
|
35587
|
+
const hour = Number(parts.hour);
|
|
35588
|
+
const minute = Number(parts.minute);
|
|
35589
|
+
return {
|
|
35590
|
+
dateKey: `${String(year).padStart(4, "0")}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`,
|
|
35591
|
+
minutesOfDay: (Number.isFinite(hour) ? hour : 0) * 60 + (Number.isFinite(minute) ? minute : 0)
|
|
35592
|
+
};
|
|
35593
|
+
};
|
|
35594
|
+
var getDateKeyInTimeZone = (timeZone, now4 = /* @__PURE__ */ new Date()) => getZonedNowSnapshot(timeZone, now4).dateKey;
|
|
35595
|
+
var buildHourlyIntervals = ({
|
|
35596
|
+
shiftStart,
|
|
35597
|
+
shiftEnd,
|
|
35598
|
+
bucketMinutes = 60,
|
|
35599
|
+
fallbackHours = 11
|
|
35600
|
+
}) => {
|
|
35601
|
+
const startMinutes = parseTimeToMinutes2(shiftStart);
|
|
35602
|
+
if (!Number.isFinite(startMinutes)) return [];
|
|
35603
|
+
const bucket = Number.isFinite(bucketMinutes) && bucketMinutes > 0 ? Math.floor(bucketMinutes) : 60;
|
|
35604
|
+
let totalMinutes;
|
|
35605
|
+
const endRaw = shiftEnd ? parseTimeToMinutes2(shiftEnd) : Number.NaN;
|
|
35606
|
+
if (!Number.isFinite(endRaw)) {
|
|
35607
|
+
totalMinutes = Math.max(0, Math.round(fallbackHours * 60));
|
|
35608
|
+
} else {
|
|
35609
|
+
let endMinutes = endRaw;
|
|
35610
|
+
if (endMinutes <= startMinutes) {
|
|
35611
|
+
endMinutes += 24 * 60;
|
|
35612
|
+
}
|
|
35613
|
+
totalMinutes = endMinutes - startMinutes;
|
|
35614
|
+
}
|
|
35615
|
+
if (!Number.isFinite(totalMinutes) || totalMinutes <= 0) return [];
|
|
35616
|
+
const count = Math.ceil(totalMinutes / bucket);
|
|
35617
|
+
const shiftEndMinutes = startMinutes + totalMinutes;
|
|
35618
|
+
const intervals = [];
|
|
35619
|
+
for (let i = 0; i < count; i += 1) {
|
|
35620
|
+
const start = startMinutes + i * bucket;
|
|
35621
|
+
const end = Math.min(start + bucket, shiftEndMinutes);
|
|
35622
|
+
const minutes = Math.max(0, end - start);
|
|
35623
|
+
if (minutes <= 0) continue;
|
|
35624
|
+
intervals.push({ start, end, minutes });
|
|
35625
|
+
}
|
|
35626
|
+
return intervals;
|
|
35627
|
+
};
|
|
35628
|
+
var computeBreakMinutesByInterval = ({
|
|
35629
|
+
intervals,
|
|
35630
|
+
shiftStart,
|
|
35631
|
+
breaks
|
|
35632
|
+
}) => {
|
|
35633
|
+
if (!intervals.length || !breaks.length) return intervals.map(() => 0);
|
|
35634
|
+
const normalizedBreaks = normalizeBreaksOnShiftTimeline(shiftStart, breaks);
|
|
35635
|
+
return intervals.map((interval) => {
|
|
35636
|
+
if (!normalizedBreaks.length) return 0;
|
|
35637
|
+
let total = 0;
|
|
35638
|
+
for (const brk of normalizedBreaks) {
|
|
35639
|
+
const overlap = Math.max(0, Math.min(interval.end, brk.end) - Math.max(interval.start, brk.start));
|
|
35640
|
+
total += overlap;
|
|
35641
|
+
if (total >= interval.minutes) return interval.minutes;
|
|
35642
|
+
}
|
|
35643
|
+
return Math.min(interval.minutes, total);
|
|
35644
|
+
});
|
|
35645
|
+
};
|
|
35646
|
+
var computeBreakRemarksByInterval = ({
|
|
35647
|
+
intervals,
|
|
35648
|
+
shiftStart,
|
|
35649
|
+
breaks
|
|
35650
|
+
}) => {
|
|
35651
|
+
if (!intervals.length || !breaks.length) return intervals.map(() => "");
|
|
35652
|
+
const normalizedBreaks = normalizeBreaksOnShiftTimeline(shiftStart, breaks);
|
|
35653
|
+
return intervals.map((interval) => {
|
|
35654
|
+
const labels = normalizedBreaks.filter((brk) => Math.max(0, Math.min(interval.end, brk.end) - Math.max(interval.start, brk.start)) > 0).map((brk) => brk.label).filter((label, index, values) => label && values.indexOf(label) === index);
|
|
35655
|
+
return labels.join(", ");
|
|
35656
|
+
});
|
|
35657
|
+
};
|
|
35658
|
+
var computeEffectiveTargets = ({
|
|
35659
|
+
intervals,
|
|
35660
|
+
breakMinutes,
|
|
35661
|
+
pphThreshold,
|
|
35662
|
+
rounding = "round"
|
|
35663
|
+
}) => {
|
|
35664
|
+
return intervals.map((interval, idx) => {
|
|
35665
|
+
const intervalMinutes = Number(interval?.minutes) || 0;
|
|
35666
|
+
const breakMins = Number(breakMinutes?.[idx]) || 0;
|
|
35667
|
+
const plannedWorkMinutes = Math.max(0, intervalMinutes - breakMins);
|
|
35668
|
+
if (!Number.isFinite(pphThreshold) || pphThreshold <= 0) return 0;
|
|
35669
|
+
if (plannedWorkMinutes <= 0) return 0;
|
|
35670
|
+
return roundTarget(pphThreshold * plannedWorkMinutes / 60, rounding);
|
|
35671
|
+
});
|
|
35672
|
+
};
|
|
35673
|
+
var buildHourlyTargetPlan = ({
|
|
35674
|
+
shiftStart,
|
|
35675
|
+
shiftEnd,
|
|
35676
|
+
breaks = [],
|
|
35677
|
+
pphThreshold,
|
|
35678
|
+
bucketMinutes = 60,
|
|
35679
|
+
fallbackHours = 11,
|
|
35680
|
+
rounding = "round"
|
|
35681
|
+
}) => {
|
|
35682
|
+
const intervals = buildHourlyIntervals({
|
|
35683
|
+
shiftStart,
|
|
35684
|
+
shiftEnd,
|
|
35685
|
+
bucketMinutes,
|
|
35686
|
+
fallbackHours
|
|
35687
|
+
});
|
|
35688
|
+
const breakMinutes = computeBreakMinutesByInterval({
|
|
35689
|
+
intervals,
|
|
35690
|
+
shiftStart,
|
|
35691
|
+
breaks
|
|
35692
|
+
});
|
|
35693
|
+
const breakRemarks = computeBreakRemarksByInterval({
|
|
35694
|
+
intervals,
|
|
35695
|
+
shiftStart,
|
|
35696
|
+
breaks
|
|
35697
|
+
});
|
|
35698
|
+
const productiveMinutes = intervals.map((interval, idx) => Math.max(0, (Number(interval?.minutes) || 0) - (Number(breakMinutes[idx]) || 0)));
|
|
35699
|
+
const targets = computeEffectiveTargets({
|
|
35700
|
+
intervals,
|
|
35701
|
+
breakMinutes,
|
|
35702
|
+
pphThreshold,
|
|
35703
|
+
rounding
|
|
35704
|
+
});
|
|
35705
|
+
return {
|
|
35706
|
+
intervals,
|
|
35707
|
+
breakMinutes,
|
|
35708
|
+
breakRemarks,
|
|
35709
|
+
productiveMinutes,
|
|
35710
|
+
targets
|
|
35711
|
+
};
|
|
35712
|
+
};
|
|
35713
|
+
var isHourlyIntervalComplete = ({
|
|
35714
|
+
reportDate,
|
|
35715
|
+
shiftStart,
|
|
35716
|
+
shiftEnd,
|
|
35717
|
+
interval,
|
|
35718
|
+
timeZone = "Asia/Kolkata",
|
|
35719
|
+
now: now4 = /* @__PURE__ */ new Date()
|
|
35720
|
+
}) => {
|
|
35721
|
+
if (!reportDate) return true;
|
|
35722
|
+
const snapshot = getZonedNowSnapshot(timeZone, now4);
|
|
35723
|
+
const shiftStartMinutes = parseTimeToMinutes2(shiftStart);
|
|
35724
|
+
const shiftEndMinutes = shiftEnd ? parseTimeToMinutes2(shiftEnd) : Number.NaN;
|
|
35725
|
+
const wrapsMidnight = Number.isFinite(shiftStartMinutes) && Number.isFinite(shiftEndMinutes) && shiftEndMinutes <= shiftStartMinutes;
|
|
35726
|
+
if (reportDate === snapshot.dateKey) {
|
|
35727
|
+
return interval.end <= snapshot.minutesOfDay;
|
|
35728
|
+
}
|
|
35729
|
+
if (wrapsMidnight && reportDate === shiftDateKey(snapshot.dateKey, -1)) {
|
|
35730
|
+
return interval.end <= snapshot.minutesOfDay + MINUTES_PER_DAY;
|
|
35731
|
+
}
|
|
35732
|
+
return reportDate < snapshot.dateKey;
|
|
35733
|
+
};
|
|
35734
|
+
var isShiftInProgressForReportDate = ({
|
|
35735
|
+
reportDate,
|
|
35736
|
+
shiftStart,
|
|
35737
|
+
shiftEnd,
|
|
35738
|
+
timeZone = "Asia/Kolkata",
|
|
35739
|
+
now: now4 = /* @__PURE__ */ new Date()
|
|
35740
|
+
}) => {
|
|
35741
|
+
if (!reportDate || !shiftStart || !shiftEnd) return false;
|
|
35742
|
+
const shiftStartMinutes = parseTimeToMinutes2(shiftStart);
|
|
35743
|
+
const shiftEndMinutesRaw = parseTimeToMinutes2(shiftEnd);
|
|
35744
|
+
if (!Number.isFinite(shiftStartMinutes) || !Number.isFinite(shiftEndMinutesRaw)) {
|
|
35745
|
+
return false;
|
|
35746
|
+
}
|
|
35747
|
+
let shiftEndMinutes = shiftEndMinutesRaw;
|
|
35748
|
+
const wrapsMidnight = shiftEndMinutes <= shiftStartMinutes;
|
|
35749
|
+
if (wrapsMidnight) {
|
|
35750
|
+
shiftEndMinutes += MINUTES_PER_DAY;
|
|
35751
|
+
}
|
|
35752
|
+
const snapshot = getZonedNowSnapshot(timeZone, now4);
|
|
35753
|
+
let currentMinutes = null;
|
|
35754
|
+
if (reportDate === snapshot.dateKey) {
|
|
35755
|
+
currentMinutes = snapshot.minutesOfDay;
|
|
35756
|
+
} else if (wrapsMidnight && reportDate === shiftDateKey(snapshot.dateKey, -1)) {
|
|
35757
|
+
currentMinutes = snapshot.minutesOfDay + MINUTES_PER_DAY;
|
|
35758
|
+
}
|
|
35759
|
+
if (currentMinutes === null) {
|
|
35760
|
+
return false;
|
|
35761
|
+
}
|
|
35762
|
+
return shiftStartMinutes <= currentMinutes && currentMinutes < shiftEndMinutes;
|
|
35763
|
+
};
|
|
35188
35764
|
var padTime = (value) => value.toString().padStart(2, "0");
|
|
35189
35765
|
var parseTime = (timeValue) => {
|
|
35190
35766
|
if (!timeValue) return null;
|
|
@@ -35566,6 +36142,7 @@ var HourlyOutputChartComponent = ({
|
|
|
35566
36142
|
hourlyTargetOutput,
|
|
35567
36143
|
shiftStart,
|
|
35568
36144
|
shiftEnd,
|
|
36145
|
+
shiftBreaks = [],
|
|
35569
36146
|
showIdleTime = false,
|
|
35570
36147
|
idleTimeHourly,
|
|
35571
36148
|
shiftDate,
|
|
@@ -35803,13 +36380,41 @@ var HourlyOutputChartComponent = ({
|
|
|
35803
36380
|
end: index === skuTimelineSegments.length - 1 ? Math.max(segment.start, targetLineEndOffset) : segment.end
|
|
35804
36381
|
})).filter((segment) => segment.end > segment.start);
|
|
35805
36382
|
}, [skuTimelineSegments, targetLineEndOffset]);
|
|
35806
|
-
const
|
|
36383
|
+
const hasExplicitHourlyTargetOutputProp = React144__default.useMemo(
|
|
35807
36384
|
() => hourlyTargetOutput !== void 0,
|
|
35808
36385
|
[hourlyTargetOutput]
|
|
35809
36386
|
);
|
|
36387
|
+
const fallbackHourlyTargetOutput = React144__default.useMemo(() => {
|
|
36388
|
+
if (hasExplicitHourlyTargetOutputProp) return void 0;
|
|
36389
|
+
if (skuTimelineSegments.length > 0) return void 0;
|
|
36390
|
+
const plan = buildHourlyTargetPlan({
|
|
36391
|
+
shiftStart,
|
|
36392
|
+
shiftEnd,
|
|
36393
|
+
breaks: shiftBreaks,
|
|
36394
|
+
pphThreshold,
|
|
36395
|
+
rounding: "floor"
|
|
36396
|
+
});
|
|
36397
|
+
if (!plan.targets.length) return void 0;
|
|
36398
|
+
return plan.targets.map((value) => Number.isFinite(value) ? value : null);
|
|
36399
|
+
}, [
|
|
36400
|
+
hasExplicitHourlyTargetOutputProp,
|
|
36401
|
+
skuTimelineSegments.length,
|
|
36402
|
+
shiftStart,
|
|
36403
|
+
shiftEnd,
|
|
36404
|
+
shiftBreaks,
|
|
36405
|
+
pphThreshold
|
|
36406
|
+
]);
|
|
36407
|
+
const effectiveHourlyTargetOutput = React144__default.useMemo(
|
|
36408
|
+
() => hasExplicitHourlyTargetOutputProp ? hourlyTargetOutput : fallbackHourlyTargetOutput,
|
|
36409
|
+
[hasExplicitHourlyTargetOutputProp, hourlyTargetOutput, fallbackHourlyTargetOutput]
|
|
36410
|
+
);
|
|
36411
|
+
const hasHourlyTargetOutputProp = React144__default.useMemo(
|
|
36412
|
+
() => effectiveHourlyTargetOutput !== void 0,
|
|
36413
|
+
[effectiveHourlyTargetOutput]
|
|
36414
|
+
);
|
|
35810
36415
|
const hasExplicitHourlyTargets = React144__default.useMemo(
|
|
35811
|
-
() => Array.isArray(
|
|
35812
|
-
[
|
|
36416
|
+
() => Array.isArray(effectiveHourlyTargetOutput) && effectiveHourlyTargetOutput.some((value) => value !== null && value !== void 0),
|
|
36417
|
+
[effectiveHourlyTargetOutput]
|
|
35813
36418
|
);
|
|
35814
36419
|
const hourlyTargetSegments = React144__default.useMemo(() => {
|
|
35815
36420
|
if (!hasExplicitHourlyTargets) return [];
|
|
@@ -35823,7 +36428,7 @@ var HourlyOutputChartComponent = ({
|
|
|
35823
36428
|
runValue = null;
|
|
35824
36429
|
};
|
|
35825
36430
|
for (let i = 0; i < SHIFT_DURATION; i += 1) {
|
|
35826
|
-
const rawValue = Array.isArray(
|
|
36431
|
+
const rawValue = Array.isArray(effectiveHourlyTargetOutput) ? effectiveHourlyTargetOutput[i] : null;
|
|
35827
36432
|
const value = rawValue === null || rawValue === void 0 ? null : Number(rawValue);
|
|
35828
36433
|
if (value === null || !Number.isFinite(value)) {
|
|
35829
36434
|
flush(i);
|
|
@@ -35842,7 +36447,7 @@ var HourlyOutputChartComponent = ({
|
|
|
35842
36447
|
}
|
|
35843
36448
|
flush(SHIFT_DURATION);
|
|
35844
36449
|
return segments.filter((segment) => segment.end > segment.start);
|
|
35845
|
-
}, [SHIFT_DURATION, hasExplicitHourlyTargets,
|
|
36450
|
+
}, [SHIFT_DURATION, hasExplicitHourlyTargets, effectiveHourlyTargetOutput]);
|
|
35846
36451
|
const activeSkuHourIndices = React144__default.useMemo(() => {
|
|
35847
36452
|
const indices = /* @__PURE__ */ new Set();
|
|
35848
36453
|
const targets = Array(SHIFT_DURATION).fill(pphThreshold);
|
|
@@ -35880,7 +36485,7 @@ var HourlyOutputChartComponent = ({
|
|
|
35880
36485
|
const { indices, targets, hasTimeline } = activeSkuHourIndices;
|
|
35881
36486
|
return Array.from({ length: SHIFT_DURATION }, (_, i) => {
|
|
35882
36487
|
const idleSlot = idleSlots[i];
|
|
35883
|
-
const explicitTarget = hasHourlyTargetOutputProp ?
|
|
36488
|
+
const explicitTarget = hasHourlyTargetOutputProp ? effectiveHourlyTargetOutput?.[i] ?? null : void 0;
|
|
35884
36489
|
const currentTarget = hasHourlyTargetOutputProp ? explicitTarget : targets[i] || pphThreshold;
|
|
35885
36490
|
const comparisonTarget = currentTarget === null || currentTarget === void 0 ? targets[i] || pphThreshold : currentTarget;
|
|
35886
36491
|
return {
|
|
@@ -35899,7 +36504,7 @@ var HourlyOutputChartComponent = ({
|
|
|
35899
36504
|
isDimmed: hasTimeline && !!activeSkuId && !indices.has(i)
|
|
35900
36505
|
};
|
|
35901
36506
|
});
|
|
35902
|
-
}, [animatedData, data, pphThreshold, idleSlots, SHIFT_DURATION, activeSkuHourIndices, activeSkuId,
|
|
36507
|
+
}, [animatedData, data, pphThreshold, idleSlots, SHIFT_DURATION, activeSkuHourIndices, activeSkuId, effectiveHourlyTargetOutput, hasHourlyTargetOutputProp]);
|
|
35903
36508
|
const renderSkuTimelineRail = React144__default.useCallback((props) => {
|
|
35904
36509
|
if (!skuTimelineSegments.length || SHIFT_DURATION <= 0) return null;
|
|
35905
36510
|
const offset = props?.offset;
|
|
@@ -36558,6 +37163,16 @@ var HourlyOutputChart = React144__default.memo(
|
|
|
36558
37163
|
if (!prevProps.data.every((val, idx) => val === nextProps.data[idx])) {
|
|
36559
37164
|
return false;
|
|
36560
37165
|
}
|
|
37166
|
+
const prevHasHourlyTargetOutputProp = prevProps.hourlyTargetOutput !== void 0;
|
|
37167
|
+
const nextHasHourlyTargetOutputProp = nextProps.hourlyTargetOutput !== void 0;
|
|
37168
|
+
if (prevHasHourlyTargetOutputProp !== nextHasHourlyTargetOutputProp) {
|
|
37169
|
+
return false;
|
|
37170
|
+
}
|
|
37171
|
+
if (prevProps.hourlyTargetOutput === null || nextProps.hourlyTargetOutput === null) {
|
|
37172
|
+
if (prevProps.hourlyTargetOutput !== nextProps.hourlyTargetOutput) {
|
|
37173
|
+
return false;
|
|
37174
|
+
}
|
|
37175
|
+
}
|
|
36561
37176
|
const prevHourlyTargets = prevProps.hourlyTargetOutput || [];
|
|
36562
37177
|
const nextHourlyTargets = nextProps.hourlyTargetOutput || [];
|
|
36563
37178
|
if (prevHourlyTargets.length !== nextHourlyTargets.length) {
|
|
@@ -36568,6 +37183,18 @@ var HourlyOutputChart = React144__default.memo(
|
|
|
36568
37183
|
return false;
|
|
36569
37184
|
}
|
|
36570
37185
|
}
|
|
37186
|
+
const prevShiftBreaks = prevProps.shiftBreaks || [];
|
|
37187
|
+
const nextShiftBreaks = nextProps.shiftBreaks || [];
|
|
37188
|
+
if (prevShiftBreaks.length !== nextShiftBreaks.length) {
|
|
37189
|
+
return false;
|
|
37190
|
+
}
|
|
37191
|
+
for (let i = 0; i < prevShiftBreaks.length; i += 1) {
|
|
37192
|
+
const prevBreak = prevShiftBreaks[i] || {};
|
|
37193
|
+
const nextBreak = nextShiftBreaks[i] || {};
|
|
37194
|
+
if (prevBreak.startTime !== nextBreak.startTime || prevBreak.endTime !== nextBreak.endTime || prevBreak.duration !== nextBreak.duration || prevBreak.remarks !== nextBreak.remarks) {
|
|
37195
|
+
return false;
|
|
37196
|
+
}
|
|
37197
|
+
}
|
|
36571
37198
|
const prevIdle = prevProps.idleTimeHourly || {};
|
|
36572
37199
|
const nextIdle = nextProps.idleTimeHourly || {};
|
|
36573
37200
|
const prevKeys = Object.keys(prevIdle);
|
|
@@ -36660,6 +37287,9 @@ var isLowWipGreenOverride = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => {
|
|
|
36660
37287
|
if (workspace.scheduled_break_active === true) {
|
|
36661
37288
|
return false;
|
|
36662
37289
|
}
|
|
37290
|
+
if (workspace.recent_flow_forced_zero_after_shift === true) {
|
|
37291
|
+
return false;
|
|
37292
|
+
}
|
|
36663
37293
|
if (!hasVideoGridRecentFlow(workspace) || !isVideoGridWipGated(workspace)) {
|
|
36664
37294
|
return false;
|
|
36665
37295
|
}
|
|
@@ -36905,7 +37535,7 @@ var VideoCard = React144__default.memo(({
|
|
|
36905
37535
|
}
|
|
36906
37536
|
);
|
|
36907
37537
|
}, (prevProps, nextProps) => {
|
|
36908
|
-
if (prevProps.workspace.efficiency !== nextProps.workspace.efficiency || prevProps.workspace.assembly_enabled !== nextProps.workspace.assembly_enabled || prevProps.workspace.video_grid_metric_mode !== nextProps.workspace.video_grid_metric_mode || prevProps.workspace.recent_flow_percent !== nextProps.workspace.recent_flow_percent || prevProps.workspace.recent_flow_effective_end_at !== nextProps.workspace.recent_flow_effective_end_at || prevProps.workspace.scheduled_break_active !== nextProps.workspace.scheduled_break_active || prevProps.workspace.incoming_wip_current !== nextProps.workspace.incoming_wip_current || prevProps.workspace.incoming_wip_buffer_name !== nextProps.workspace.incoming_wip_buffer_name || prevProps.workspace.trend !== nextProps.workspace.trend || prevProps.workspace.performance_score !== nextProps.workspace.performance_score || prevProps.workspace.pph !== nextProps.workspace.pph) {
|
|
37538
|
+
if (prevProps.workspace.efficiency !== nextProps.workspace.efficiency || prevProps.workspace.assembly_enabled !== nextProps.workspace.assembly_enabled || prevProps.workspace.video_grid_metric_mode !== nextProps.workspace.video_grid_metric_mode || prevProps.workspace.recent_flow_percent !== nextProps.workspace.recent_flow_percent || prevProps.workspace.recent_flow_effective_end_at !== nextProps.workspace.recent_flow_effective_end_at || prevProps.workspace.recent_flow_forced_zero_after_shift !== nextProps.workspace.recent_flow_forced_zero_after_shift || prevProps.workspace.scheduled_break_active !== nextProps.workspace.scheduled_break_active || prevProps.workspace.incoming_wip_current !== nextProps.workspace.incoming_wip_current || prevProps.workspace.incoming_wip_buffer_name !== nextProps.workspace.incoming_wip_buffer_name || prevProps.workspace.trend !== nextProps.workspace.trend || prevProps.workspace.performance_score !== nextProps.workspace.performance_score || prevProps.workspace.pph !== nextProps.workspace.pph) {
|
|
36909
37539
|
return false;
|
|
36910
37540
|
}
|
|
36911
37541
|
if (prevProps.workspace.workspace_uuid !== nextProps.workspace.workspace_uuid || prevProps.workspace.workspace_name !== nextProps.workspace.workspace_name || prevProps.workspace.line_id !== nextProps.workspace.line_id) {
|
|
@@ -37224,6 +37854,15 @@ var VideoGridView = React144__default.memo(({
|
|
|
37224
37854
|
}
|
|
37225
37855
|
console.error(`[VideoGridView] Stream failed for workspace: ${workspaceId}`);
|
|
37226
37856
|
setFailedStreams((prev) => new Set(prev).add(workspaceId));
|
|
37857
|
+
captureHandledFrontendException(new Error("Video stream failed after recovery attempts"), {
|
|
37858
|
+
surface: "video_grid_stream",
|
|
37859
|
+
route: typeof window !== "undefined" ? window.location.pathname : "unknown",
|
|
37860
|
+
extras: {
|
|
37861
|
+
workspace_id: workspaceId,
|
|
37862
|
+
stream_source: isR2Stream ? "r2" : "media_config",
|
|
37863
|
+
has_fallback: hasFallback
|
|
37864
|
+
}
|
|
37865
|
+
});
|
|
37227
37866
|
trackCoreEvent("Video Stream Error", {
|
|
37228
37867
|
workspace_id: workspaceId,
|
|
37229
37868
|
view_type: "video_grid",
|
|
@@ -41891,11 +42530,14 @@ var SilentErrorBoundary = class extends React144__default.Component {
|
|
|
41891
42530
|
componentStack: errorInfo.componentStack,
|
|
41892
42531
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
41893
42532
|
});
|
|
41894
|
-
|
|
42533
|
+
captureHandledFrontendException(error, {
|
|
41895
42534
|
surface: "react_error_boundary",
|
|
41896
|
-
|
|
41897
|
-
|
|
41898
|
-
|
|
42535
|
+
route: typeof window !== "undefined" ? window.location.pathname : "unknown",
|
|
42536
|
+
severity: "error",
|
|
42537
|
+
extras: {
|
|
42538
|
+
component_stack: errorInfo.componentStack,
|
|
42539
|
+
error_count: this.state.errorCount + 1
|
|
42540
|
+
}
|
|
41899
42541
|
});
|
|
41900
42542
|
this.setState((prev) => ({
|
|
41901
42543
|
errorCount: prev.errorCount + 1,
|
|
@@ -44432,6 +45074,11 @@ var OVERLAY_ICON_COLOR_BY_PALETTE = {
|
|
|
44432
45074
|
cyan: "text-cyan-300",
|
|
44433
45075
|
slate: "text-slate-200"
|
|
44434
45076
|
};
|
|
45077
|
+
var buildPlaybackCaptureError = (recoverable) => {
|
|
45078
|
+
return new Error(
|
|
45079
|
+
recoverable ? "Clip playback failed after retry exhaustion" : "Clip playback failed with non-recoverable media error"
|
|
45080
|
+
);
|
|
45081
|
+
};
|
|
44435
45082
|
var BottlenecksContent = ({
|
|
44436
45083
|
workspaceId,
|
|
44437
45084
|
workspaceName,
|
|
@@ -44886,6 +45533,16 @@ var BottlenecksContent = ({
|
|
|
44886
45533
|
}
|
|
44887
45534
|
} catch (err) {
|
|
44888
45535
|
console.error("Error loading first video for category:", err);
|
|
45536
|
+
captureHandledFrontendException(err, {
|
|
45537
|
+
surface: "clips_initial_load",
|
|
45538
|
+
route: typeof window !== "undefined" ? window.location.pathname : "unknown",
|
|
45539
|
+
extras: {
|
|
45540
|
+
workspace_id: workspaceId,
|
|
45541
|
+
category: targetCategory,
|
|
45542
|
+
date: effectiveDateString,
|
|
45543
|
+
shift_id: effectiveShiftId
|
|
45544
|
+
}
|
|
45545
|
+
});
|
|
44889
45546
|
if (isMountedRef.current) {
|
|
44890
45547
|
setError({
|
|
44891
45548
|
type: "fatal",
|
|
@@ -45423,6 +46080,15 @@ var BottlenecksContent = ({
|
|
|
45423
46080
|
console.log(`[BottlenecksContent] Loaded clip ${clipId} (${clickedClipIndex + 1}/${metadataArray.length})`);
|
|
45424
46081
|
} catch (error2) {
|
|
45425
46082
|
console.error(`[BottlenecksContent] Error loading clip by ID (${clipId}):`, error2);
|
|
46083
|
+
captureHandledFrontendException(error2, {
|
|
46084
|
+
surface: "clips_selected_load",
|
|
46085
|
+
route: typeof window !== "undefined" ? window.location.pathname : "unknown",
|
|
46086
|
+
extras: {
|
|
46087
|
+
workspace_id: workspaceId,
|
|
46088
|
+
clip_id: clipId,
|
|
46089
|
+
category: categoryId
|
|
46090
|
+
}
|
|
46091
|
+
});
|
|
45426
46092
|
if (isMountedRef.current) {
|
|
45427
46093
|
setError({
|
|
45428
46094
|
type: "fatal",
|
|
@@ -46022,6 +46688,18 @@ var BottlenecksContent = ({
|
|
|
46022
46688
|
errorCode,
|
|
46023
46689
|
errorMessage
|
|
46024
46690
|
});
|
|
46691
|
+
captureHandledFrontendException(buildPlaybackCaptureError(false), {
|
|
46692
|
+
surface: "clips_video_playback",
|
|
46693
|
+
route: typeof window !== "undefined" ? window.location.pathname : "unknown",
|
|
46694
|
+
extras: {
|
|
46695
|
+
workspace_id: workspaceId,
|
|
46696
|
+
category: activeFilterRef.current,
|
|
46697
|
+
video_id: currentVideo?.id,
|
|
46698
|
+
error_code: errorCode,
|
|
46699
|
+
player_error_message: errorMessage,
|
|
46700
|
+
recoverable: false
|
|
46701
|
+
}
|
|
46702
|
+
});
|
|
46025
46703
|
return;
|
|
46026
46704
|
}
|
|
46027
46705
|
if (videoRetryCountRef.current < 3 && currentVideo) {
|
|
@@ -46065,6 +46743,19 @@ var BottlenecksContent = ({
|
|
|
46065
46743
|
errorMessage,
|
|
46066
46744
|
attempts: 3
|
|
46067
46745
|
});
|
|
46746
|
+
captureHandledFrontendException(buildPlaybackCaptureError(true), {
|
|
46747
|
+
surface: "clips_video_playback",
|
|
46748
|
+
route: typeof window !== "undefined" ? window.location.pathname : "unknown",
|
|
46749
|
+
extras: {
|
|
46750
|
+
workspace_id: workspaceId,
|
|
46751
|
+
category: activeFilterRef.current,
|
|
46752
|
+
video_id: currentVideo?.id,
|
|
46753
|
+
error_code: errorCode,
|
|
46754
|
+
player_error_message: errorMessage,
|
|
46755
|
+
recoverable: true,
|
|
46756
|
+
attempts: 3
|
|
46757
|
+
}
|
|
46758
|
+
});
|
|
46068
46759
|
}
|
|
46069
46760
|
}, [currentVideo, workspaceId, clearLoadingState, clearRetryTimeout, restartCurrentClipPlayback]);
|
|
46070
46761
|
useEffect(() => {
|
|
@@ -48396,6 +49087,14 @@ var LinePdfExportButton = ({
|
|
|
48396
49087
|
pdf.save(`${fileName}.pdf`);
|
|
48397
49088
|
} catch (error) {
|
|
48398
49089
|
console.error("PDF Export Error:", error);
|
|
49090
|
+
captureHandledFrontendException(error, {
|
|
49091
|
+
surface: "line_pdf_export",
|
|
49092
|
+
route: typeof window !== "undefined" ? window.location.pathname : "unknown",
|
|
49093
|
+
extras: {
|
|
49094
|
+
file_name: fileName,
|
|
49095
|
+
target_type: typeof targetElement === "string" ? "selector" : "element"
|
|
49096
|
+
}
|
|
49097
|
+
});
|
|
48399
49098
|
alert("An error occurred while exporting to PDF. Please try again.");
|
|
48400
49099
|
} finally {
|
|
48401
49100
|
setIsExporting(false);
|
|
@@ -50218,6 +50917,16 @@ var LineMonthlyPdfGenerator = ({
|
|
|
50218
50917
|
doc.save(fileName);
|
|
50219
50918
|
} catch (error) {
|
|
50220
50919
|
console.error("Line Monthly PDF generation failed:", error);
|
|
50920
|
+
captureHandledFrontendException(error, {
|
|
50921
|
+
surface: "line_monthly_pdf_generation",
|
|
50922
|
+
route: typeof window !== "undefined" ? window.location.pathname : "unknown",
|
|
50923
|
+
extras: {
|
|
50924
|
+
line_name: lineName || null,
|
|
50925
|
+
selected_month: selectedMonth,
|
|
50926
|
+
selected_year: selectedYear,
|
|
50927
|
+
selected_shift_id: selectedShiftId
|
|
50928
|
+
}
|
|
50929
|
+
});
|
|
50221
50930
|
} finally {
|
|
50222
50931
|
setIsGenerating(false);
|
|
50223
50932
|
}
|
|
@@ -50282,261 +50991,6 @@ Underperforming Workspaces: ${lineInfo.metrics.underperforming_workspaces} / ${l
|
|
|
50282
50991
|
}
|
|
50283
50992
|
);
|
|
50284
50993
|
};
|
|
50285
|
-
|
|
50286
|
-
// src/lib/utils/hourlyTargets.ts
|
|
50287
|
-
var stripSeconds2 = (timeStr) => timeStr ? timeStr.slice(0, 5) : timeStr;
|
|
50288
|
-
var MINUTES_PER_DAY = 24 * 60;
|
|
50289
|
-
var parseTimeToMinutes2 = (timeString) => {
|
|
50290
|
-
const normalized = stripSeconds2(timeString || "");
|
|
50291
|
-
if (!normalized || !/^[0-2]\d:[0-5]\d$/.test(normalized)) return Number.NaN;
|
|
50292
|
-
const [hours, minutes] = normalized.split(":").map(Number);
|
|
50293
|
-
return hours * 60 + minutes;
|
|
50294
|
-
};
|
|
50295
|
-
var normalizeBreaksOnShiftTimeline = (shiftStart, breaks) => {
|
|
50296
|
-
const shiftStartMinutes = parseTimeToMinutes2(shiftStart);
|
|
50297
|
-
if (!Number.isFinite(shiftStartMinutes)) return [];
|
|
50298
|
-
const normalizedBreaks = [];
|
|
50299
|
-
for (const entry of breaks) {
|
|
50300
|
-
const startRaw = parseTimeToMinutes2(entry.startTime);
|
|
50301
|
-
const endRaw = parseTimeToMinutes2(entry.endTime);
|
|
50302
|
-
if (!Number.isFinite(startRaw) || !Number.isFinite(endRaw)) continue;
|
|
50303
|
-
let start = startRaw;
|
|
50304
|
-
let end = endRaw;
|
|
50305
|
-
if (end <= start) {
|
|
50306
|
-
end += 24 * 60;
|
|
50307
|
-
}
|
|
50308
|
-
if (start < shiftStartMinutes) {
|
|
50309
|
-
start += 24 * 60;
|
|
50310
|
-
end += 24 * 60;
|
|
50311
|
-
}
|
|
50312
|
-
const label = entry.remarks?.trim() || "Break";
|
|
50313
|
-
normalizedBreaks.push({ start, end, label });
|
|
50314
|
-
}
|
|
50315
|
-
return normalizedBreaks;
|
|
50316
|
-
};
|
|
50317
|
-
var roundTarget = (value, mode) => {
|
|
50318
|
-
if (!Number.isFinite(value)) return 0;
|
|
50319
|
-
switch (mode) {
|
|
50320
|
-
case "floor":
|
|
50321
|
-
return Math.floor(value);
|
|
50322
|
-
case "ceil":
|
|
50323
|
-
return Math.ceil(value);
|
|
50324
|
-
case "round":
|
|
50325
|
-
default:
|
|
50326
|
-
return Math.round(value);
|
|
50327
|
-
}
|
|
50328
|
-
};
|
|
50329
|
-
var formatDateKey = (date) => {
|
|
50330
|
-
const year = date.getUTCFullYear();
|
|
50331
|
-
const month = `${date.getUTCMonth() + 1}`.padStart(2, "0");
|
|
50332
|
-
const day = `${date.getUTCDate()}`.padStart(2, "0");
|
|
50333
|
-
return `${year}-${month}-${day}`;
|
|
50334
|
-
};
|
|
50335
|
-
var shiftDateKey = (dateKey, deltaDays) => {
|
|
50336
|
-
const [yearPart, monthPart, dayPart] = dateKey.split("-").map(Number);
|
|
50337
|
-
const year = Number.isFinite(yearPart) ? yearPart : 1970;
|
|
50338
|
-
const month = Number.isFinite(monthPart) ? monthPart : 1;
|
|
50339
|
-
const day = Number.isFinite(dayPart) ? dayPart : 1;
|
|
50340
|
-
const date = new Date(Date.UTC(year, month - 1, day));
|
|
50341
|
-
date.setUTCDate(date.getUTCDate() + deltaDays);
|
|
50342
|
-
return formatDateKey(date);
|
|
50343
|
-
};
|
|
50344
|
-
var getZonedNowSnapshot = (timeZone, now4) => {
|
|
50345
|
-
const formatter = new Intl.DateTimeFormat("en-US", {
|
|
50346
|
-
timeZone,
|
|
50347
|
-
year: "numeric",
|
|
50348
|
-
month: "2-digit",
|
|
50349
|
-
day: "2-digit",
|
|
50350
|
-
hour: "2-digit",
|
|
50351
|
-
minute: "2-digit",
|
|
50352
|
-
hourCycle: "h23"
|
|
50353
|
-
});
|
|
50354
|
-
const parts = formatter.formatToParts(now4).reduce((acc, part) => {
|
|
50355
|
-
if (part.type !== "literal") {
|
|
50356
|
-
acc[part.type] = part.value;
|
|
50357
|
-
}
|
|
50358
|
-
return acc;
|
|
50359
|
-
}, {});
|
|
50360
|
-
const year = Number(parts.year);
|
|
50361
|
-
const month = Number(parts.month);
|
|
50362
|
-
const day = Number(parts.day);
|
|
50363
|
-
const hour = Number(parts.hour);
|
|
50364
|
-
const minute = Number(parts.minute);
|
|
50365
|
-
return {
|
|
50366
|
-
dateKey: `${String(year).padStart(4, "0")}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`,
|
|
50367
|
-
minutesOfDay: (Number.isFinite(hour) ? hour : 0) * 60 + (Number.isFinite(minute) ? minute : 0)
|
|
50368
|
-
};
|
|
50369
|
-
};
|
|
50370
|
-
var getDateKeyInTimeZone = (timeZone, now4 = /* @__PURE__ */ new Date()) => getZonedNowSnapshot(timeZone, now4).dateKey;
|
|
50371
|
-
var buildHourlyIntervals = ({
|
|
50372
|
-
shiftStart,
|
|
50373
|
-
shiftEnd,
|
|
50374
|
-
bucketMinutes = 60,
|
|
50375
|
-
fallbackHours = 11
|
|
50376
|
-
}) => {
|
|
50377
|
-
const startMinutes = parseTimeToMinutes2(shiftStart);
|
|
50378
|
-
if (!Number.isFinite(startMinutes)) return [];
|
|
50379
|
-
const bucket = Number.isFinite(bucketMinutes) && bucketMinutes > 0 ? Math.floor(bucketMinutes) : 60;
|
|
50380
|
-
let totalMinutes;
|
|
50381
|
-
const endRaw = shiftEnd ? parseTimeToMinutes2(shiftEnd) : Number.NaN;
|
|
50382
|
-
if (!Number.isFinite(endRaw)) {
|
|
50383
|
-
totalMinutes = Math.max(0, Math.round(fallbackHours * 60));
|
|
50384
|
-
} else {
|
|
50385
|
-
let endMinutes = endRaw;
|
|
50386
|
-
if (endMinutes <= startMinutes) {
|
|
50387
|
-
endMinutes += 24 * 60;
|
|
50388
|
-
}
|
|
50389
|
-
totalMinutes = endMinutes - startMinutes;
|
|
50390
|
-
}
|
|
50391
|
-
if (!Number.isFinite(totalMinutes) || totalMinutes <= 0) return [];
|
|
50392
|
-
const count = Math.ceil(totalMinutes / bucket);
|
|
50393
|
-
const shiftEndMinutes = startMinutes + totalMinutes;
|
|
50394
|
-
const intervals = [];
|
|
50395
|
-
for (let i = 0; i < count; i += 1) {
|
|
50396
|
-
const start = startMinutes + i * bucket;
|
|
50397
|
-
const end = Math.min(start + bucket, shiftEndMinutes);
|
|
50398
|
-
const minutes = Math.max(0, end - start);
|
|
50399
|
-
if (minutes <= 0) continue;
|
|
50400
|
-
intervals.push({ start, end, minutes });
|
|
50401
|
-
}
|
|
50402
|
-
return intervals;
|
|
50403
|
-
};
|
|
50404
|
-
var computeBreakMinutesByInterval = ({
|
|
50405
|
-
intervals,
|
|
50406
|
-
shiftStart,
|
|
50407
|
-
breaks
|
|
50408
|
-
}) => {
|
|
50409
|
-
if (!intervals.length || !breaks.length) return intervals.map(() => 0);
|
|
50410
|
-
const normalizedBreaks = normalizeBreaksOnShiftTimeline(shiftStart, breaks);
|
|
50411
|
-
return intervals.map((interval) => {
|
|
50412
|
-
if (!normalizedBreaks.length) return 0;
|
|
50413
|
-
let total = 0;
|
|
50414
|
-
for (const brk of normalizedBreaks) {
|
|
50415
|
-
const overlap = Math.max(0, Math.min(interval.end, brk.end) - Math.max(interval.start, brk.start));
|
|
50416
|
-
total += overlap;
|
|
50417
|
-
if (total >= interval.minutes) return interval.minutes;
|
|
50418
|
-
}
|
|
50419
|
-
return Math.min(interval.minutes, total);
|
|
50420
|
-
});
|
|
50421
|
-
};
|
|
50422
|
-
var computeBreakRemarksByInterval = ({
|
|
50423
|
-
intervals,
|
|
50424
|
-
shiftStart,
|
|
50425
|
-
breaks
|
|
50426
|
-
}) => {
|
|
50427
|
-
if (!intervals.length || !breaks.length) return intervals.map(() => "");
|
|
50428
|
-
const normalizedBreaks = normalizeBreaksOnShiftTimeline(shiftStart, breaks);
|
|
50429
|
-
return intervals.map((interval) => {
|
|
50430
|
-
const labels = normalizedBreaks.filter((brk) => Math.max(0, Math.min(interval.end, brk.end) - Math.max(interval.start, brk.start)) > 0).map((brk) => brk.label).filter((label, index, values) => label && values.indexOf(label) === index);
|
|
50431
|
-
return labels.join(", ");
|
|
50432
|
-
});
|
|
50433
|
-
};
|
|
50434
|
-
var computeEffectiveTargets = ({
|
|
50435
|
-
intervals,
|
|
50436
|
-
breakMinutes,
|
|
50437
|
-
pphThreshold,
|
|
50438
|
-
rounding = "round"
|
|
50439
|
-
}) => {
|
|
50440
|
-
return intervals.map((interval, idx) => {
|
|
50441
|
-
const intervalMinutes = Number(interval?.minutes) || 0;
|
|
50442
|
-
const breakMins = Number(breakMinutes?.[idx]) || 0;
|
|
50443
|
-
const plannedWorkMinutes = Math.max(0, intervalMinutes - breakMins);
|
|
50444
|
-
if (!Number.isFinite(pphThreshold) || pphThreshold <= 0) return 0;
|
|
50445
|
-
if (plannedWorkMinutes <= 0) return 0;
|
|
50446
|
-
return roundTarget(pphThreshold * plannedWorkMinutes / 60, rounding);
|
|
50447
|
-
});
|
|
50448
|
-
};
|
|
50449
|
-
var buildHourlyTargetPlan = ({
|
|
50450
|
-
shiftStart,
|
|
50451
|
-
shiftEnd,
|
|
50452
|
-
breaks = [],
|
|
50453
|
-
pphThreshold,
|
|
50454
|
-
bucketMinutes = 60,
|
|
50455
|
-
fallbackHours = 11,
|
|
50456
|
-
rounding = "round"
|
|
50457
|
-
}) => {
|
|
50458
|
-
const intervals = buildHourlyIntervals({
|
|
50459
|
-
shiftStart,
|
|
50460
|
-
shiftEnd,
|
|
50461
|
-
bucketMinutes,
|
|
50462
|
-
fallbackHours
|
|
50463
|
-
});
|
|
50464
|
-
const breakMinutes = computeBreakMinutesByInterval({
|
|
50465
|
-
intervals,
|
|
50466
|
-
shiftStart,
|
|
50467
|
-
breaks
|
|
50468
|
-
});
|
|
50469
|
-
const breakRemarks = computeBreakRemarksByInterval({
|
|
50470
|
-
intervals,
|
|
50471
|
-
shiftStart,
|
|
50472
|
-
breaks
|
|
50473
|
-
});
|
|
50474
|
-
const productiveMinutes = intervals.map((interval, idx) => Math.max(0, (Number(interval?.minutes) || 0) - (Number(breakMinutes[idx]) || 0)));
|
|
50475
|
-
const targets = computeEffectiveTargets({
|
|
50476
|
-
intervals,
|
|
50477
|
-
breakMinutes,
|
|
50478
|
-
pphThreshold,
|
|
50479
|
-
rounding
|
|
50480
|
-
});
|
|
50481
|
-
return {
|
|
50482
|
-
intervals,
|
|
50483
|
-
breakMinutes,
|
|
50484
|
-
breakRemarks,
|
|
50485
|
-
productiveMinutes,
|
|
50486
|
-
targets
|
|
50487
|
-
};
|
|
50488
|
-
};
|
|
50489
|
-
var isHourlyIntervalComplete = ({
|
|
50490
|
-
reportDate,
|
|
50491
|
-
shiftStart,
|
|
50492
|
-
shiftEnd,
|
|
50493
|
-
interval,
|
|
50494
|
-
timeZone = "Asia/Kolkata",
|
|
50495
|
-
now: now4 = /* @__PURE__ */ new Date()
|
|
50496
|
-
}) => {
|
|
50497
|
-
if (!reportDate) return true;
|
|
50498
|
-
const snapshot = getZonedNowSnapshot(timeZone, now4);
|
|
50499
|
-
const shiftStartMinutes = parseTimeToMinutes2(shiftStart);
|
|
50500
|
-
const shiftEndMinutes = shiftEnd ? parseTimeToMinutes2(shiftEnd) : Number.NaN;
|
|
50501
|
-
const wrapsMidnight = Number.isFinite(shiftStartMinutes) && Number.isFinite(shiftEndMinutes) && shiftEndMinutes <= shiftStartMinutes;
|
|
50502
|
-
if (reportDate === snapshot.dateKey) {
|
|
50503
|
-
return interval.end <= snapshot.minutesOfDay;
|
|
50504
|
-
}
|
|
50505
|
-
if (wrapsMidnight && reportDate === shiftDateKey(snapshot.dateKey, -1)) {
|
|
50506
|
-
return interval.end <= snapshot.minutesOfDay + MINUTES_PER_DAY;
|
|
50507
|
-
}
|
|
50508
|
-
return reportDate < snapshot.dateKey;
|
|
50509
|
-
};
|
|
50510
|
-
var isShiftInProgressForReportDate = ({
|
|
50511
|
-
reportDate,
|
|
50512
|
-
shiftStart,
|
|
50513
|
-
shiftEnd,
|
|
50514
|
-
timeZone = "Asia/Kolkata",
|
|
50515
|
-
now: now4 = /* @__PURE__ */ new Date()
|
|
50516
|
-
}) => {
|
|
50517
|
-
if (!reportDate || !shiftStart || !shiftEnd) return false;
|
|
50518
|
-
const shiftStartMinutes = parseTimeToMinutes2(shiftStart);
|
|
50519
|
-
const shiftEndMinutesRaw = parseTimeToMinutes2(shiftEnd);
|
|
50520
|
-
if (!Number.isFinite(shiftStartMinutes) || !Number.isFinite(shiftEndMinutesRaw)) {
|
|
50521
|
-
return false;
|
|
50522
|
-
}
|
|
50523
|
-
let shiftEndMinutes = shiftEndMinutesRaw;
|
|
50524
|
-
const wrapsMidnight = shiftEndMinutes <= shiftStartMinutes;
|
|
50525
|
-
if (wrapsMidnight) {
|
|
50526
|
-
shiftEndMinutes += MINUTES_PER_DAY;
|
|
50527
|
-
}
|
|
50528
|
-
const snapshot = getZonedNowSnapshot(timeZone, now4);
|
|
50529
|
-
let currentMinutes = null;
|
|
50530
|
-
if (reportDate === snapshot.dateKey) {
|
|
50531
|
-
currentMinutes = snapshot.minutesOfDay;
|
|
50532
|
-
} else if (wrapsMidnight && reportDate === shiftDateKey(snapshot.dateKey, -1)) {
|
|
50533
|
-
currentMinutes = snapshot.minutesOfDay + MINUTES_PER_DAY;
|
|
50534
|
-
}
|
|
50535
|
-
if (currentMinutes === null) {
|
|
50536
|
-
return false;
|
|
50537
|
-
}
|
|
50538
|
-
return shiftStartMinutes <= currentMinutes && currentMinutes < shiftEndMinutes;
|
|
50539
|
-
};
|
|
50540
50994
|
var formatOperationalDateKey = (dateKey, options) => {
|
|
50541
50995
|
const [yearPart, monthPart, dayPart] = dateKey.split("-").map(Number);
|
|
50542
50996
|
const year = Number.isFinite(yearPart) ? yearPart : 1970;
|
|
@@ -51255,6 +51709,15 @@ var LinePdfGenerator = ({
|
|
|
51255
51709
|
doc.save(fileName);
|
|
51256
51710
|
} catch (error) {
|
|
51257
51711
|
console.error("PDF generation failed:", error);
|
|
51712
|
+
captureHandledFrontendException(error, {
|
|
51713
|
+
surface: "line_pdf_generation",
|
|
51714
|
+
route: typeof window !== "undefined" ? window.location.pathname : "unknown",
|
|
51715
|
+
extras: {
|
|
51716
|
+
line_id: lineInfo.line_id,
|
|
51717
|
+
date: lineInfo.date,
|
|
51718
|
+
shift_id: lineInfo.shift_id
|
|
51719
|
+
}
|
|
51720
|
+
});
|
|
51258
51721
|
} finally {
|
|
51259
51722
|
setIsGenerating(false);
|
|
51260
51723
|
}
|
|
@@ -51327,6 +51790,14 @@ var WorkspacePdfExportButton = ({
|
|
|
51327
51790
|
pdf.save(`${fileName}.pdf`);
|
|
51328
51791
|
} catch (error) {
|
|
51329
51792
|
console.error("PDF Export Error:", error);
|
|
51793
|
+
captureHandledFrontendException(error, {
|
|
51794
|
+
surface: "workspace_pdf_export",
|
|
51795
|
+
route: typeof window !== "undefined" ? window.location.pathname : "unknown",
|
|
51796
|
+
extras: {
|
|
51797
|
+
file_name: fileName,
|
|
51798
|
+
target_type: typeof targetElement === "string" ? "selector" : "element"
|
|
51799
|
+
}
|
|
51800
|
+
});
|
|
51330
51801
|
alert("An error occurred while exporting to PDF. Please try again.");
|
|
51331
51802
|
} finally {
|
|
51332
51803
|
setIsExporting(false);
|
|
@@ -53176,6 +53647,16 @@ var WorkspacePdfGenerator = ({
|
|
|
53176
53647
|
doc.save(fileName);
|
|
53177
53648
|
} catch (error) {
|
|
53178
53649
|
console.error("PDF generation failed:", error);
|
|
53650
|
+
captureHandledFrontendException(error, {
|
|
53651
|
+
surface: "workspace_pdf_generation",
|
|
53652
|
+
route: typeof window !== "undefined" ? window.location.pathname : "unknown",
|
|
53653
|
+
extras: {
|
|
53654
|
+
workspace_id: workspace.workspace_id,
|
|
53655
|
+
line_id: workspace.line_id,
|
|
53656
|
+
date: workspace.date,
|
|
53657
|
+
shift_id: workspace.shift_id
|
|
53658
|
+
}
|
|
53659
|
+
});
|
|
53179
53660
|
} finally {
|
|
53180
53661
|
setIsGenerating(false);
|
|
53181
53662
|
}
|
|
@@ -53583,6 +54064,18 @@ var WorkspaceMonthlyPdfGenerator = ({
|
|
|
53583
54064
|
doc.save(fileName);
|
|
53584
54065
|
} catch (error) {
|
|
53585
54066
|
console.error("Monthly PDF generation failed:", error);
|
|
54067
|
+
captureHandledFrontendException(error, {
|
|
54068
|
+
surface: "workspace_monthly_pdf_generation",
|
|
54069
|
+
route: typeof window !== "undefined" ? window.location.pathname : "unknown",
|
|
54070
|
+
extras: {
|
|
54071
|
+
workspace_id: workspaceId,
|
|
54072
|
+
workspace_name: workspaceName,
|
|
54073
|
+
line_name: lineName || null,
|
|
54074
|
+
selected_month: selectedMonth,
|
|
54075
|
+
selected_year: selectedYear,
|
|
54076
|
+
selected_shift_id: selectedShiftId
|
|
54077
|
+
}
|
|
54078
|
+
});
|
|
53586
54079
|
} finally {
|
|
53587
54080
|
setIsGenerating(false);
|
|
53588
54081
|
}
|
|
@@ -62855,6 +63348,16 @@ var useLiveMonitorBootstrap = ({
|
|
|
62855
63348
|
if (requestId !== activeRequestIdRef.current) {
|
|
62856
63349
|
return;
|
|
62857
63350
|
}
|
|
63351
|
+
captureHandledFrontendException(fetchError, {
|
|
63352
|
+
surface: "live_monitor_bootstrap",
|
|
63353
|
+
route: "/api/dashboard/monitor-bootstrap",
|
|
63354
|
+
extras: {
|
|
63355
|
+
company_id: resolvedCompanyId,
|
|
63356
|
+
line_ids: normalizedLineIds,
|
|
63357
|
+
force_refresh: force,
|
|
63358
|
+
pathname: typeof window !== "undefined" ? window.location.pathname : "unknown"
|
|
63359
|
+
}
|
|
63360
|
+
});
|
|
62858
63361
|
setError(fetchError instanceof Error ? fetchError : new Error("Failed to load live monitor bootstrap"));
|
|
62859
63362
|
} finally {
|
|
62860
63363
|
if (requestId === activeRequestIdRef.current) {
|
|
@@ -63167,11 +63670,14 @@ var NotificationService = class {
|
|
|
63167
63670
|
}
|
|
63168
63671
|
return response;
|
|
63169
63672
|
} catch (error) {
|
|
63170
|
-
|
|
63673
|
+
addSentryBreadcrumb("Notification service request failed", {
|
|
63171
63674
|
surface: "notification_service",
|
|
63172
|
-
url,
|
|
63173
|
-
|
|
63174
|
-
|
|
63675
|
+
route: url,
|
|
63676
|
+
severity: "warning",
|
|
63677
|
+
extras: {
|
|
63678
|
+
method: options.method || "GET",
|
|
63679
|
+
pathname: typeof window !== "undefined" ? window.location.pathname : "unknown"
|
|
63680
|
+
}
|
|
63175
63681
|
});
|
|
63176
63682
|
throw error;
|
|
63177
63683
|
}
|
|
@@ -64679,7 +65185,7 @@ var buildLineInfoSnapshot = (lineDetails, metrics2) => {
|
|
|
64679
65185
|
underperforming_workspace_uuids: metrics2.underperforming_workspace_uuids || [],
|
|
64680
65186
|
output_array: metrics2.output_array || [],
|
|
64681
65187
|
output_hourly: metrics2.output_hourly,
|
|
64682
|
-
hourly_target_output: metrics2.hourly_target_output
|
|
65188
|
+
hourly_target_output: metrics2.hourly_target_output,
|
|
64683
65189
|
line_threshold: metrics2.line_threshold ?? 0,
|
|
64684
65190
|
threshold_pph: metrics2.threshold_pph ?? 0,
|
|
64685
65191
|
shift_start: metrics2.shift_start || "06:00",
|
|
@@ -64766,7 +65272,7 @@ var transformLineMetrics = (lineId, detailResponse, queryDate, queryShiftId) =>
|
|
|
64766
65272
|
underperforming_workspace_names: [],
|
|
64767
65273
|
underperforming_workspace_uuids: [],
|
|
64768
65274
|
output_array: [],
|
|
64769
|
-
hourly_target_output:
|
|
65275
|
+
hourly_target_output: void 0,
|
|
64770
65276
|
line_threshold: 0,
|
|
64771
65277
|
threshold_pph: 0,
|
|
64772
65278
|
shift_start: "06:00",
|
|
@@ -65805,6 +66311,7 @@ var BottomSection = memo$1(({
|
|
|
65805
66311
|
hourlyOutputData,
|
|
65806
66312
|
hourlyThreshold,
|
|
65807
66313
|
hourlyTargetOutput,
|
|
66314
|
+
shiftBreaks,
|
|
65808
66315
|
idleTimeHourly,
|
|
65809
66316
|
timezone,
|
|
65810
66317
|
urlDate,
|
|
@@ -65980,6 +66487,7 @@ var BottomSection = memo$1(({
|
|
|
65980
66487
|
hourlyTargetOutput,
|
|
65981
66488
|
shiftStart: lineInfo.metrics.shift_start || "06:00",
|
|
65982
66489
|
shiftEnd: lineInfo.metrics.shift_end,
|
|
66490
|
+
shiftBreaks,
|
|
65983
66491
|
idleTimeHourly,
|
|
65984
66492
|
shiftDate: lineInfo.date,
|
|
65985
66493
|
timezone,
|
|
@@ -66003,6 +66511,9 @@ var BottomSection = memo$1(({
|
|
|
66003
66511
|
if (prevProps.lineInfo.monitoring_mode !== nextProps.lineInfo.monitoring_mode) return false;
|
|
66004
66512
|
if (prevProps.skuAware !== nextProps.skuAware) return false;
|
|
66005
66513
|
if (prevProps.activeSkuId !== nextProps.activeSkuId) return false;
|
|
66514
|
+
if (JSON.stringify(prevProps.shiftBreaks || []) !== JSON.stringify(nextProps.shiftBreaks || [])) {
|
|
66515
|
+
return false;
|
|
66516
|
+
}
|
|
66006
66517
|
if (JSON.stringify(prevProps.hourlyTargetOutput || []) !== JSON.stringify(nextProps.hourlyTargetOutput || [])) {
|
|
66007
66518
|
return false;
|
|
66008
66519
|
}
|
|
@@ -66604,7 +67115,7 @@ var KPIDetailView = ({
|
|
|
66604
67115
|
underperforming_workspace_uuids: metrics2.underperforming_workspace_uuids || [],
|
|
66605
67116
|
output_array: metrics2.output_array || [],
|
|
66606
67117
|
output_hourly: metrics2.output_hourly,
|
|
66607
|
-
hourly_target_output: metrics2.hourly_target_output
|
|
67118
|
+
hourly_target_output: metrics2.hourly_target_output,
|
|
66608
67119
|
line_threshold: metrics2.line_threshold ?? 0,
|
|
66609
67120
|
threshold_pph: metrics2.threshold_pph ?? 0,
|
|
66610
67121
|
shift_start: metrics2.shift_start || "06:00",
|
|
@@ -67568,7 +68079,8 @@ var KPIDetailView = ({
|
|
|
67568
68079
|
workspaceDisplayNames,
|
|
67569
68080
|
hourlyOutputData,
|
|
67570
68081
|
hourlyThreshold,
|
|
67571
|
-
hourlyTargetOutput: chartMetrics?.hourly_target_output
|
|
68082
|
+
hourlyTargetOutput: chartMetrics?.hourly_target_output,
|
|
68083
|
+
shiftBreaks: shiftConfig?.shifts?.find((shift) => shift.shiftId === resolvedLineInfo.shift_id)?.breaks || [],
|
|
67572
68084
|
idleTimeHourly: chartMetrics?.idle_time_hourly,
|
|
67573
68085
|
timezone: lineTimezone,
|
|
67574
68086
|
urlDate,
|
|
@@ -75332,6 +75844,7 @@ var WorkspaceDetailView = ({
|
|
|
75332
75844
|
hourlyTargetOutput: workspace.hourly_target_output,
|
|
75333
75845
|
shiftStart: workspace.shift_start || "06:00",
|
|
75334
75846
|
shiftEnd: workspace.shift_end,
|
|
75847
|
+
shiftBreaks: shiftConfig?.shifts?.find((shift2) => shift2.shiftId === workspace.shift_id)?.breaks || [],
|
|
75335
75848
|
showIdleTime: showChartIdleTime,
|
|
75336
75849
|
idleTimeHourly: workspace.idle_time_hourly,
|
|
75337
75850
|
idleTimeClips,
|
|
@@ -75479,6 +75992,7 @@ var WorkspaceDetailView = ({
|
|
|
75479
75992
|
hourlyTargetOutput: workspace.hourly_target_output,
|
|
75480
75993
|
shiftStart: workspace.shift_start || "06:00",
|
|
75481
75994
|
shiftEnd: workspace.shift_end,
|
|
75995
|
+
shiftBreaks: shiftConfig?.shifts?.find((shift2) => shift2.shiftId === workspace.shift_id)?.breaks || [],
|
|
75482
75996
|
showIdleTime: showChartIdleTime,
|
|
75483
75997
|
idleTimeHourly: workspace.idle_time_hourly,
|
|
75484
75998
|
idleTimeClips,
|
|
@@ -77318,11 +77832,14 @@ var TicketService = class {
|
|
|
77318
77832
|
}
|
|
77319
77833
|
return response;
|
|
77320
77834
|
} catch (error) {
|
|
77321
|
-
|
|
77835
|
+
addSentryBreadcrumb("Ticket service request failed", {
|
|
77322
77836
|
surface: "ticket_service",
|
|
77323
|
-
url,
|
|
77324
|
-
|
|
77325
|
-
|
|
77837
|
+
route: url,
|
|
77838
|
+
severity: "warning",
|
|
77839
|
+
extras: {
|
|
77840
|
+
method: options.method || "GET",
|
|
77841
|
+
pathname: typeof window !== "undefined" ? window.location.pathname : "unknown"
|
|
77842
|
+
}
|
|
77326
77843
|
});
|
|
77327
77844
|
throw error;
|
|
77328
77845
|
}
|
|
@@ -83102,10 +83619,33 @@ var useOperationsOverviewRefresh = ({
|
|
|
83102
83619
|
if (controller.signal.aborted || requestIdsRef.current[section] !== requestId || isAbortError2(error)) {
|
|
83103
83620
|
return;
|
|
83104
83621
|
}
|
|
83622
|
+
const sentryContext = {
|
|
83623
|
+
surface: "operations_overview_refresh",
|
|
83624
|
+
route: `/api/dashboard/operations-overview/${section}`,
|
|
83625
|
+
extras: {
|
|
83626
|
+
section,
|
|
83627
|
+
reason,
|
|
83628
|
+
company_id: companyId,
|
|
83629
|
+
line_ids: lineIds,
|
|
83630
|
+
start_date: startKey,
|
|
83631
|
+
end_date: endKey,
|
|
83632
|
+
trend_mode: trendMode,
|
|
83633
|
+
comparison_strategy: comparisonStrategy || null
|
|
83634
|
+
}
|
|
83635
|
+
};
|
|
83636
|
+
if (section === "improvements") {
|
|
83637
|
+
addSentryBreadcrumb("Operations overview optional improvements refresh failed", {
|
|
83638
|
+
...sentryContext,
|
|
83639
|
+
severity: "warning",
|
|
83640
|
+
category: "operations_overview"
|
|
83641
|
+
});
|
|
83642
|
+
} else {
|
|
83643
|
+
captureHandledFrontendException(error, sentryContext);
|
|
83644
|
+
}
|
|
83105
83645
|
onError(error instanceof Error ? error.message : `Failed to refresh ${section}`);
|
|
83106
83646
|
}
|
|
83107
83647
|
},
|
|
83108
|
-
[companyId, enabled, lineIds
|
|
83648
|
+
[companyId, comparisonStrategy, enabled, endKey, lineIds, startKey, supabase, trendMode]
|
|
83109
83649
|
);
|
|
83110
83650
|
const refreshSnapshot = React144__default.useCallback(
|
|
83111
83651
|
async (reason) => {
|
|
@@ -84548,4 +85088,4 @@ var streamProxyConfig = {
|
|
|
84548
85088
|
}
|
|
84549
85089
|
};
|
|
84550
85090
|
|
|
84551
|
-
export { ACTION_FAMILIES, ACTION_NAMES, AIAgentView_default as AIAgentView, AcceptInvite, AcceptInviteView_default as AcceptInviteView, AdvancedFilterDialog, AdvancedFilterPanel, AudioService, AuthCallback, AuthCallbackView_default as AuthCallbackView, AuthProvider, AuthService, AuthenticatedBottleneckClipsView, AuthenticatedFactoryView, AuthenticatedHelpView, AuthenticatedHomeView, AuthenticatedShiftsView, AuthenticatedTargetsView, AuthenticatedTicketsView, AuthenticatedWorkspaceHealthView, AvatarUpload, AxelNotificationPopup, AxelOrb, BackButton, BackButtonMinimal, BarChart, BaseHistoryCalendar, BottleneckClipsModal, BottleneckClipsView_default as BottleneckClipsView, BottlenecksContent, BreakNotificationPopup, CachePrefetchStatus, Card2 as Card, CardContent2 as CardContent, CardDescription2 as CardDescription, CardFooter2 as CardFooter, CardHeader2 as CardHeader, CardTitle2 as CardTitle, ChangeRoleDialog, ClipFilterProvider, ClipsCostView_default as ClipsCostView, CompactWorkspaceHealthCard, ConfirmRemoveUserDialog, CongratulationsOverlay, CroppedHlsVideoPlayer, CroppedVideoPlayer, CycleTimeChart, CycleTimeOverTimeChart, DEFAULT_ANALYTICS_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_CONFIG, DEFAULT_DATABASE_CONFIG, DEFAULT_DATE_TIME_CONFIG, DEFAULT_ENDPOINTS_CONFIG, DEFAULT_ENTITY_CONFIG, DEFAULT_HOME_VIEW_CONFIG, DEFAULT_MAP_VIEW_CONFIG, DEFAULT_SHIFT_CONFIG, DEFAULT_SHIFT_DATA, DEFAULT_THEME_CONFIG, DEFAULT_VIDEO_CONFIG, DEFAULT_WORKSPACE_CONFIG, DEFAULT_WORKSPACE_POSITIONS, DashboardHeader, DashboardLayout, DashboardOverridesProvider, DashboardProvider, DateDisplay_default as DateDisplay, DateTimeDisplay, DebugAuth, DebugAuthView_default as DebugAuthView, DetailedHealthStatus, DiagnosisVideoModal, EFFICIENCY_ON_TRACK_THRESHOLD, EmptyStateMessage, EncouragementOverlay, FactoryAssignmentDropdown, FactoryView_default as FactoryView, FileManagerFilters, FilterDialogTrigger, FirstTimeLoginDebug, FirstTimeLoginHandler, FittingTitle, GaugeChart, GridComponentsPlaceholder, HamburgerButton, Header, HealthDateShiftSelector, HealthStatusGrid, HealthStatusIndicator, HelpView_default as HelpView, HlsVideoPlayer, HomeView_default as HomeView, HourlyOutputChart2 as HourlyOutputChart, HourlyUptimeChart, ISTTimer_default as ISTTimer, IdleTimeVlmConfigProvider, ImprovementCenterView_default as ImprovementCenterView, InlineEditableText, InteractiveOnboardingTour, InvitationService, InvitationsTable, InviteUserDialog, KPICard, KPIDetailView_default as KPIDetailView, KPIGrid, KPIHeader, KPISection, KPIsOverviewView_default as KPIsOverviewView, LINE_1_UUID, LINE_2_UUID, LargeOutputProgressChart, LeaderboardDetailView_default as LeaderboardDetailView, Legend5 as Legend, LineAssignmentDropdown, LineChart, LineHistoryCalendar, LineMonthlyHistory, LineMonthlyPdfGenerator, LinePdfExportButton, LinePdfGenerator, LineWhatsAppShareButton, LinesService, LiveTimer, LoadingInline, LoadingOverlay_default as LoadingOverlay, LoadingPage_default as LoadingPage, LoadingSkeleton, LoadingState, LoginPage, LoginView_default as LoginView, Logo, MainLayout, MapGridView, MetricCard_default as MetricCard, MinimalOnboardingPopup, MobileMenuProvider, NewClipsNotification, NoWorkspaceData, OnboardingDemo, OnboardingTour, OptifyeAgentClient, OptifyeLogoLoader_default as OptifyeLogoLoader, OutputProgressChart, PageHeader, PieChart4 as PieChart, PlantHeadView_default as PlantHeadView, PlayPauseIndicator, PrefetchConfigurationError, PrefetchError, PrefetchEvents, PrefetchStatus, PrefetchTimeoutError, ProfileView_default as ProfileView, ROOT_DASHBOARD_EVENT_NAMES, RegistryProvider, RoleBadge, S3ClipsSupabaseService as S3ClipsService, S3Service, SKUManagementView, SOPComplianceChart, SSEChatClient, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, SessionTracker, SessionTrackingContext, SessionTrackingProvider, SettingsPopup, ShiftDisplay_default as ShiftDisplay, ShiftsView_default as ShiftsView, SideNavBar, SignupWithInvitation, SilentErrorBoundary, SimpleOnboardingPopup, SingleVideoStream_default as SingleVideoStream, Skeleton, SubscriptionManager, SubscriptionManagerProvider, SupabaseProvider, SupervisorDropdown_default as SupervisorDropdown, SupervisorManagementView_default as SupervisorManagementView, SupervisorService, TargetWorkspaceGrid, TargetsView_default as TargetsView, TeamManagementView_default as TeamManagementView, ThreadSidebar, TicketHistory_default as TicketHistory, TicketHistoryService, TicketsView_default as TicketsView, TimeDisplay_default as TimeDisplay, TimePickerDropdown, Timer_default as Timer, TimezoneProvider, TimezoneService, UptimeDonutChart, UptimeLineChart, UptimeMetricCards, UserAvatar, UserManagementService, UserManagementTable, UserService, UserUsageDetailModal, UserUsageStats, VideoCard, VideoGridView, VideoPlayer, VideoPreloader, WORKSPACE_POSITIONS, WhatsAppShareButton, WorkspaceCard, WorkspaceCycleTimeMetricCards, WorkspaceDetailView_default as WorkspaceDetailView, WorkspaceDisplayNameExample, WorkspaceGrid, WorkspaceGridItem, WorkspaceHealthCard, WorkspaceHealthView_default as WorkspaceHealthView, WorkspaceHistoryCalendar, WorkspaceMetricCards, WorkspaceMetricCardsImpl, WorkspaceMonthlyDataFetcher, WorkspaceMonthlyHistory, WorkspaceMonthlyPdfGenerator, WorkspacePdfExportButton, WorkspacePdfGenerator, WorkspaceWhatsAppShareButton, actionService, aggregateKPIsFromLineMetricsRows, alertsService, apiUtils, areAllLinesOnSameShift, authCoreService, authOTPService, authRateLimitService, awardsService, buildDateKey, buildKPIsFromLineMetricsRow, buildLineSkuBreakdown, buildShiftGroupsKey, canRoleAccessDashboardPath, canRoleAccessTeamManagement, canRoleAssignFactories, canRoleAssignLines, canRoleChangeRole, canRoleInviteRole, canRoleManageCompany, canRoleManageTargets, canRoleManageUsers, canRoleRemoveUser, canRoleViewClipsCost, canRoleViewUsageStats, captureHandledFrontendException, captureSentryException, captureSentryMessage, checkRateLimit2 as checkRateLimit, clearAllRateLimits2 as clearAllRateLimits, clearRateLimit2 as clearRateLimit, clearS3VideoCache, clearS3VideoFromCache, clearSentryContext, clearWorkspaceDisplayNamesCache, cn, combineLineMetricsRows, countRealSkus, createDefaultKPIs, createInvitationService, createLinesService, createSessionTracker, createStorageService, createStreamProxyHandler, createSupabaseClient, createSupervisorService, createThrottledReload, createUserManagementService, createUserService, dashboardService, deleteThread, fetchIdleTimeReasons, fetchLineDummySkuId, fetchLineSkuCatalog, filterDataByDateKeyRange, filterRealSkuBreakdown, forceRefreshWorkspaceDisplayNames, formatAwardMonth, formatDateInZone, formatDateKeyForDisplay, formatDateTimeInZone, formatDuration2 as formatDuration, formatISTDate, formatIdleTime, formatRangeLabel, formatReasonLabel, formatRelativeTime, formatTimeInZone, fromUrlFriendlyName, getActionDisplayName, getActiveShift, getAllLineDisplayNames, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAllWorkspaceDisplayNamesSnapshot, getAnonClient, getAssignableRoles, getAssignmentColumnLabel, getAvailableShiftIds, getAwardBadgeType, getAwardDescription, getAwardTitle, getBrowserName, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getConfiguredLineIds, getCoreSessionRecordingProperties, getCoreSessionReplayUrl, getCurrentShift, getCurrentShiftForLine, getCurrentTimeInZone, getCurrentWeekFullRange, getCurrentWeekToDateRange, getDashboardHeaderTimeInZone, getDateKeyFromDate, getDateKeyFromValue, getDayDateKey, getDaysDifferenceInZone, getDefaultCameraStreamUrl, getDefaultLineId, getDefaultTabForWorkspace, getInitials, getLineDisplayName, getManufacturingInsights, getMetricsTablePrefix, getMonthKeyBounds, getMonthWeekRanges, getMonthlyTrendComparisonLabel, getNextUpdateInterval, getOperationalDate, getRoleAssignmentKind, getRoleDescription, getRoleLabel, getRoleMetadata, getRoleNavPaths, getS3SignedUrl, getS3VideoSrc, getShiftData, getShiftNameById, getShiftWorkDurationSeconds, getShortShiftName, getShortWorkspaceDisplayName, getShortWorkspaceDisplayNameAsync, getStoredWorkspaceMappings, getSubscriptionManager, getThreadMessages, getUniformShiftGroup, getUserThreads, getUserThreadsPaginated, getVisibleRolesForCurrentUser, getWorkspaceDisplayName, getWorkspaceDisplayNameAsync, getWorkspaceDisplayNamesMap, getWorkspaceFromUrl, getWorkspaceNavigationParams, groupLinesByShift, hasAnyShiftData, identifyCoreUser, initializeCoreMixpanel, isEfficiencyOnTrack, isFactoryScopedRole, isFullMonthRange, isIgnorableFrontendError, isLegacyConfiguration, isLoopbackHostname, isPrefetchError, isRealSku, isRecentFlowVideoGridMetricMode, isSafari, isSupervisorRole, isTransitionPeriod, isUrlPermanentlyFailed, isValidFactoryViewConfiguration, isValidLineInfoPayload, isValidPrefetchParams, isValidPrefetchStatus, isValidWorkspaceDetailedMetricsPayload, isValidWorkspaceMetricsPayload, isWipGatedVideoGridMetricMode, isWorkspaceDisplayNamesLoaded, isWorkspaceDisplayNamesLoading, lineLeaderboardService, linesService, mergeWithDefaultConfig, migrateLegacyConfiguration, normalizeActionFamily, normalizeDateKeyRange, normalizeRoleLevel, normalizeVideoGridMetricMode, optifyeAgentClient, parseDateKeyToDate, parseS3Uri, pickPreferredLineMetricsRow, preInitializeWorkspaceDisplayNames, preloadS3Video, preloadS3VideoUrl, preloadS3VideosUrl, preloadVideoUrl, preloadVideosUrl, qualityService, realtimeService, refreshWorkspaceDisplayNames, resetCoreMixpanel, resetFailedUrl, resetSubscriptionManager, resolveDefaultSkuId, resolveLiveSkuId, s3VideoPreloader, selectPreferredLineMetricsRow, setSentryUserContext, setSentryWorkspaceContext, shouldEnableLocalDevTestLogin, shuffleArray, simulateApiDelay, skuService, startCoreSessionRecording, stopCoreSessionRecording, storeWorkspaceMapping, streamProxyConfig, subscribeWorkspaceDisplayNames, throttledReloadDashboard, toUrlFriendlyName, trackCoreEvent, trackCorePageView, transformToChartData, updateThreadTitle, upsertWorkspaceDisplayNameInCache, useAccessControl, useActiveBreaks, useActiveLineId, useAllWorkspaceMetrics, useAnalyticsConfig, useAppTimezone, useAudioService, useAuth, useAuthConfig, useAxelNotifications, useCanSaveTargets, useClipFilter, useClipTypes, useClipTypesWithCounts, useClipsInit, useCompanyClipsCost, useCompanyFastSlowClipFiltersEnabled, useCompanyHasVlmEnabledLine, useCompanyUsersUsage, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useDynamicShiftConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHasLineAccess, useHideMobileHeader, useHistoricWorkspaceMetrics, useHlsStream, useHlsStreamWithCropping, useHookOverride, useHourEndTimer, useHourlyTargetAchievements, useHourlyTargetMisses, useIdleTimeClipClassifications, useIdleTimeReasons, useIdleTimeVlmConfig, useKpiTrends, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineShiftConfig, useLineSupervisor, useLineWorkspaceMetrics, useLines, useMessages, useMetrics, useMobileMenu, useMonthlyTrend, useMultiLineShiftConfigs, useNavigation, useOperationalShiftKey, useOptionalSupabase, useOverrides, usePageOverride, usePrefetchClipCounts, useRealtimeLineMetrics, useRegistry, useSKUs, useSessionKeepAlive, useSessionTracking, useSessionTrackingContext, useShiftConfig, useShiftGroups, useShifts, useSubscriptionManager, useSubscriptionManagerSafe, useSupabase, useSupabaseClient, useSupervisorsByLineIds, useTargets, useTeamManagementPermissions, useTheme, useThemeConfig, useThreads, useTicketHistory, useTimezoneContext, useUserLineAccess, useUserUsage, useVideoConfig, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceHealthById, useWorkspaceHealthLastSeen, useWorkspaceHealthStatus, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, useWorkspaceUptimeTimeline, useWorkspaceVideoStreams, userService, videoPrefetchManager, videoPreloader, weeklyTopPerformerService, whatsappService, withAccessControl, withAuth, withRegistry, withTimezone, workspaceHealthService, workspaceService };
|
|
85091
|
+
export { ACTION_FAMILIES, ACTION_NAMES, AIAgentView_default as AIAgentView, AcceptInvite, AcceptInviteView_default as AcceptInviteView, AdvancedFilterDialog, AdvancedFilterPanel, AudioService, AuthCallback, AuthCallbackView_default as AuthCallbackView, AuthProvider, AuthService, AuthenticatedBottleneckClipsView, AuthenticatedFactoryView, AuthenticatedHelpView, AuthenticatedHomeView, AuthenticatedShiftsView, AuthenticatedTargetsView, AuthenticatedTicketsView, AuthenticatedWorkspaceHealthView, AvatarUpload, AxelNotificationPopup, AxelOrb, BackButton, BackButtonMinimal, BarChart, BaseHistoryCalendar, BottleneckClipsModal, BottleneckClipsView_default as BottleneckClipsView, BottlenecksContent, BreakNotificationPopup, CachePrefetchStatus, Card2 as Card, CardContent2 as CardContent, CardDescription2 as CardDescription, CardFooter2 as CardFooter, CardHeader2 as CardHeader, CardTitle2 as CardTitle, ChangeRoleDialog, ClipFilterProvider, ClipsCostView_default as ClipsCostView, CompactWorkspaceHealthCard, ConfirmRemoveUserDialog, CongratulationsOverlay, CroppedHlsVideoPlayer, CroppedVideoPlayer, CycleTimeChart, CycleTimeOverTimeChart, DEFAULT_ANALYTICS_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_CONFIG, DEFAULT_DATABASE_CONFIG, DEFAULT_DATE_TIME_CONFIG, DEFAULT_ENDPOINTS_CONFIG, DEFAULT_ENTITY_CONFIG, DEFAULT_HOME_VIEW_CONFIG, DEFAULT_MAP_VIEW_CONFIG, DEFAULT_SHIFT_CONFIG, DEFAULT_SHIFT_DATA, DEFAULT_THEME_CONFIG, DEFAULT_VIDEO_CONFIG, DEFAULT_WORKSPACE_CONFIG, DEFAULT_WORKSPACE_POSITIONS, DashboardHeader, DashboardLayout, DashboardOverridesProvider, DashboardProvider, DateDisplay_default as DateDisplay, DateTimeDisplay, DebugAuth, DebugAuthView_default as DebugAuthView, DetailedHealthStatus, DiagnosisVideoModal, EFFICIENCY_ON_TRACK_THRESHOLD, EmptyStateMessage, EncouragementOverlay, FactoryAssignmentDropdown, FactoryView_default as FactoryView, FileManagerFilters, FilterDialogTrigger, FirstTimeLoginDebug, FirstTimeLoginHandler, FittingTitle, GaugeChart, GridComponentsPlaceholder, HamburgerButton, Header, HealthDateShiftSelector, HealthStatusGrid, HealthStatusIndicator, HelpView_default as HelpView, HlsVideoPlayer, HomeView_default as HomeView, HourlyOutputChart2 as HourlyOutputChart, HourlyUptimeChart, ISTTimer_default as ISTTimer, IdleTimeVlmConfigProvider, ImprovementCenterView_default as ImprovementCenterView, InlineEditableText, InteractiveOnboardingTour, InvitationService, InvitationsTable, InviteUserDialog, KPICard, KPIDetailView_default as KPIDetailView, KPIGrid, KPIHeader, KPISection, KPIsOverviewView_default as KPIsOverviewView, LINE_1_UUID, LINE_2_UUID, LargeOutputProgressChart, LeaderboardDetailView_default as LeaderboardDetailView, Legend5 as Legend, LineAssignmentDropdown, LineChart, LineHistoryCalendar, LineMonthlyHistory, LineMonthlyPdfGenerator, LinePdfExportButton, LinePdfGenerator, LineWhatsAppShareButton, LinesService, LiveTimer, LoadingInline, LoadingOverlay_default as LoadingOverlay, LoadingPage_default as LoadingPage, LoadingSkeleton, LoadingState, LoginPage, LoginView_default as LoginView, Logo, MainLayout, MapGridView, MetricCard_default as MetricCard, MinimalOnboardingPopup, MobileMenuProvider, NewClipsNotification, NoWorkspaceData, OnboardingDemo, OnboardingTour, OptifyeAgentClient, OptifyeLogoLoader_default as OptifyeLogoLoader, OutputProgressChart, PageHeader, PieChart4 as PieChart, PlantHeadView_default as PlantHeadView, PlayPauseIndicator, PrefetchConfigurationError, PrefetchError, PrefetchEvents, PrefetchStatus, PrefetchTimeoutError, ProfileView_default as ProfileView, ROOT_DASHBOARD_EVENT_NAMES, RegistryProvider, RoleBadge, S3ClipsSupabaseService as S3ClipsService, S3Service, SENTRY_HANDLED_EVENT_SESSION_LIMIT, SENTRY_HANDLED_EVENT_WINDOW_MS, SENTRY_QUOTA_STORAGE_KEY, SKUManagementView, SOPComplianceChart, SSEChatClient, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, SessionTracker, SessionTrackingContext, SessionTrackingProvider, SettingsPopup, ShiftDisplay_default as ShiftDisplay, ShiftsView_default as ShiftsView, SideNavBar, SignupWithInvitation, SilentErrorBoundary, SimpleOnboardingPopup, SingleVideoStream_default as SingleVideoStream, Skeleton, SubscriptionManager, SubscriptionManagerProvider, SupabaseProvider, SupervisorDropdown_default as SupervisorDropdown, SupervisorManagementView_default as SupervisorManagementView, SupervisorService, TargetWorkspaceGrid, TargetsView_default as TargetsView, TeamManagementView_default as TeamManagementView, ThreadSidebar, TicketHistory_default as TicketHistory, TicketHistoryService, TicketsView_default as TicketsView, TimeDisplay_default as TimeDisplay, TimePickerDropdown, Timer_default as Timer, TimezoneProvider, TimezoneService, UptimeDonutChart, UptimeLineChart, UptimeMetricCards, UserAvatar, UserManagementService, UserManagementTable, UserService, UserUsageDetailModal, UserUsageStats, VideoCard, VideoGridView, VideoPlayer, VideoPreloader, WORKSPACE_POSITIONS, WhatsAppShareButton, WorkspaceCard, WorkspaceCycleTimeMetricCards, WorkspaceDetailView_default as WorkspaceDetailView, WorkspaceDisplayNameExample, WorkspaceGrid, WorkspaceGridItem, WorkspaceHealthCard, WorkspaceHealthView_default as WorkspaceHealthView, WorkspaceHistoryCalendar, WorkspaceMetricCards, WorkspaceMetricCardsImpl, WorkspaceMonthlyDataFetcher, WorkspaceMonthlyHistory, WorkspaceMonthlyPdfGenerator, WorkspacePdfExportButton, WorkspacePdfGenerator, WorkspaceWhatsAppShareButton, actionService, addSentryBreadcrumb, aggregateKPIsFromLineMetricsRows, alertsService, apiUtils, areAllLinesOnSameShift, authCoreService, authOTPService, authRateLimitService, awardsService, buildDateKey, buildKPIsFromLineMetricsRow, buildLineSkuBreakdown, buildShiftGroupsKey, canRoleAccessDashboardPath, canRoleAccessTeamManagement, canRoleAssignFactories, canRoleAssignLines, canRoleChangeRole, canRoleInviteRole, canRoleManageCompany, canRoleManageTargets, canRoleManageUsers, canRoleRemoveUser, canRoleViewClipsCost, canRoleViewUsageStats, captureHandledFrontendException, captureSentryException, captureSentryMessage, checkRateLimit2 as checkRateLimit, clearAllRateLimits2 as clearAllRateLimits, clearRateLimit2 as clearRateLimit, clearS3VideoCache, clearS3VideoFromCache, clearSentryContext, clearWorkspaceDisplayNamesCache, cn, combineLineMetricsRows, countRealSkus, createDefaultKPIs, createInvitationService, createLinesService, createSessionTracker, createStorageService, createStreamProxyHandler, createSupabaseClient, createSupervisorService, createThrottledReload, createUserManagementService, createUserService, dashboardService, deleteThread, fetchIdleTimeReasons, fetchLineDummySkuId, fetchLineSkuCatalog, filterDataByDateKeyRange, filterRealSkuBreakdown, forceRefreshWorkspaceDisplayNames, formatAwardMonth, formatDateInZone, formatDateKeyForDisplay, formatDateTimeInZone, formatDuration2 as formatDuration, formatISTDate, formatIdleTime, formatRangeLabel, formatReasonLabel, formatRelativeTime, formatTimeInZone, fromUrlFriendlyName, getActionDisplayName, getActiveShift, getAllLineDisplayNames, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAllWorkspaceDisplayNamesSnapshot, getAnonClient, getAssignableRoles, getAssignmentColumnLabel, getAvailableShiftIds, getAwardBadgeType, getAwardDescription, getAwardTitle, getBrowserName, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getConfiguredLineIds, getCoreSessionRecordingProperties, getCoreSessionReplayUrl, getCurrentShift, getCurrentShiftForLine, getCurrentTimeInZone, getCurrentWeekFullRange, getCurrentWeekToDateRange, getDashboardHeaderTimeInZone, getDateKeyFromDate, getDateKeyFromValue, getDayDateKey, getDaysDifferenceInZone, getDefaultCameraStreamUrl, getDefaultLineId, getDefaultTabForWorkspace, getInitials, getLineDisplayName, getManufacturingInsights, getMetricsTablePrefix, getMonthKeyBounds, getMonthWeekRanges, getMonthlyTrendComparisonLabel, getNextUpdateInterval, getOperationalDate, getRoleAssignmentKind, getRoleDescription, getRoleLabel, getRoleMetadata, getRoleNavPaths, getS3SignedUrl, getS3VideoSrc, getShiftData, getShiftNameById, getShiftWorkDurationSeconds, getShortShiftName, getShortWorkspaceDisplayName, getShortWorkspaceDisplayNameAsync, getStoredWorkspaceMappings, getSubscriptionManager, getThreadMessages, getUniformShiftGroup, getUserThreads, getUserThreadsPaginated, getVisibleRolesForCurrentUser, getWorkspaceDisplayName, getWorkspaceDisplayNameAsync, getWorkspaceDisplayNamesMap, getWorkspaceFromUrl, getWorkspaceNavigationParams, groupLinesByShift, hasAnyShiftData, identifyCoreUser, initializeCoreMixpanel, isEfficiencyOnTrack, isFactoryScopedRole, isFullMonthRange, isIgnorableFrontendError, isLegacyConfiguration, isLoopbackHostname, isPrefetchError, isRealSku, isRecentFlowVideoGridMetricMode, isSafari, isSupervisorRole, isTransitionPeriod, isUrlPermanentlyFailed, isValidFactoryViewConfiguration, isValidLineInfoPayload, isValidPrefetchParams, isValidPrefetchStatus, isValidWorkspaceDetailedMetricsPayload, isValidWorkspaceMetricsPayload, isWipGatedVideoGridMetricMode, isWorkspaceDisplayNamesLoaded, isWorkspaceDisplayNamesLoading, lineLeaderboardService, linesService, mergeWithDefaultConfig, migrateLegacyConfiguration, normalizeActionFamily, normalizeDateKeyRange, normalizeRoleLevel, normalizeVideoGridMetricMode, optifyeAgentClient, parseDateKeyToDate, parseS3Uri, pickPreferredLineMetricsRow, preInitializeWorkspaceDisplayNames, preloadS3Video, preloadS3VideoUrl, preloadS3VideosUrl, preloadVideoUrl, preloadVideosUrl, qualityService, realtimeService, refreshWorkspaceDisplayNames, resetCoreMixpanel, resetFailedUrl, resetSentryQuotaForTests, resetSubscriptionManager, resolveDefaultSkuId, resolveLiveSkuId, s3VideoPreloader, selectPreferredLineMetricsRow, setSentryUserContext, setSentryWorkspaceContext, shouldEnableLocalDevTestLogin, shuffleArray, simulateApiDelay, skuService, startCoreSessionRecording, stopCoreSessionRecording, storeWorkspaceMapping, streamProxyConfig, subscribeWorkspaceDisplayNames, throttledReloadDashboard, toUrlFriendlyName, trackCoreEvent, trackCorePageView, transformToChartData, updateThreadTitle, upsertWorkspaceDisplayNameInCache, useAccessControl, useActiveBreaks, useActiveLineId, useAllWorkspaceMetrics, useAnalyticsConfig, useAppTimezone, useAudioService, useAuth, useAuthConfig, useAxelNotifications, useCanSaveTargets, useClipFilter, useClipTypes, useClipTypesWithCounts, useClipsInit, useCompanyClipsCost, useCompanyFastSlowClipFiltersEnabled, useCompanyHasVlmEnabledLine, useCompanyUsersUsage, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useDynamicShiftConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHasLineAccess, useHideMobileHeader, useHistoricWorkspaceMetrics, useHlsStream, useHlsStreamWithCropping, useHookOverride, useHourEndTimer, useHourlyTargetAchievements, useHourlyTargetMisses, useIdleTimeClipClassifications, useIdleTimeReasons, useIdleTimeVlmConfig, useKpiTrends, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineShiftConfig, useLineSupervisor, useLineWorkspaceMetrics, useLines, useMessages, useMetrics, useMobileMenu, useMonthlyTrend, useMultiLineShiftConfigs, useNavigation, useOperationalShiftKey, useOptionalSupabase, useOverrides, usePageOverride, usePrefetchClipCounts, useRealtimeLineMetrics, useRegistry, useSKUs, useSessionKeepAlive, useSessionTracking, useSessionTrackingContext, useShiftConfig, useShiftGroups, useShifts, useSubscriptionManager, useSubscriptionManagerSafe, useSupabase, useSupabaseClient, useSupervisorsByLineIds, useTargets, useTeamManagementPermissions, useTheme, useThemeConfig, useThreads, useTicketHistory, useTimezoneContext, useUserLineAccess, useUserUsage, useVideoConfig, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceHealthById, useWorkspaceHealthLastSeen, useWorkspaceHealthStatus, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, useWorkspaceUptimeTimeline, useWorkspaceVideoStreams, userService, videoPrefetchManager, videoPreloader, weeklyTopPerformerService, whatsappService, withAccessControl, withAuth, withRegistry, withTimezone, workspaceHealthService, workspaceService };
|