@optifye/dashboard-core 6.9.6 → 6.9.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +308 -98
- package/dist/index.mjs +309 -99
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -9606,9 +9606,6 @@ var getAllWorkspaceDisplayNamesAsync = async (companyId, lineId) => {
|
|
|
9606
9606
|
Object.entries(runtimeWorkspaceDisplayNames).forEach(([lineId2, lineNames]) => {
|
|
9607
9607
|
Object.entries(lineNames).forEach(([workspaceId, displayName]) => {
|
|
9608
9608
|
allNames[`${lineId2}_${workspaceId}`] = displayName;
|
|
9609
|
-
if (!allNames[workspaceId]) {
|
|
9610
|
-
allNames[workspaceId] = displayName;
|
|
9611
|
-
}
|
|
9612
9609
|
});
|
|
9613
9610
|
});
|
|
9614
9611
|
return allNames;
|
|
@@ -24737,7 +24734,8 @@ var VideoGridView = React23__namespace.default.memo(({
|
|
|
24737
24734
|
displayName: (
|
|
24738
24735
|
// Create line-aware lookup key: lineId_workspaceName
|
|
24739
24736
|
// This ensures correct mapping when multiple lines have same workspace names
|
|
24740
|
-
displayNames[`${workspace.line_id}_${workspace.workspace_name}`] ||
|
|
24737
|
+
displayNames[`${workspace.line_id}_${workspace.workspace_name}`] || // Always pass line_id to fallback to ensure correct mapping per line
|
|
24738
|
+
getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id)
|
|
24741
24739
|
),
|
|
24742
24740
|
useRAF: canvasConfig?.useRAF,
|
|
24743
24741
|
compact: !selectedLine,
|
|
@@ -24787,7 +24785,8 @@ var MapGridView = React23__namespace.default.memo(({
|
|
|
24787
24785
|
efficiency: workspace.efficiency,
|
|
24788
24786
|
action_count: workspace.action_count
|
|
24789
24787
|
});
|
|
24790
|
-
const displayName = displayNames[`${workspace.line_id}_${workspace.workspace_name}`] ||
|
|
24788
|
+
const displayName = displayNames[`${workspace.line_id}_${workspace.workspace_name}`] || // Always pass line_id to fallback to ensure correct mapping per line
|
|
24789
|
+
getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
|
|
24791
24790
|
const navParams = getWorkspaceNavigationParams(workspaceId, displayName, workspace.line_id);
|
|
24792
24791
|
router$1.push(`/workspace/${workspaceId}${navParams}`);
|
|
24793
24792
|
}, [router$1, displayNames]);
|
|
@@ -24816,7 +24815,8 @@ var MapGridView = React23__namespace.default.memo(({
|
|
|
24816
24815
|
if (!workspace) return null;
|
|
24817
24816
|
const workspaceId = workspace.workspace_uuid || workspace.workspace_name;
|
|
24818
24817
|
getPerformanceColor(workspace.efficiency);
|
|
24819
|
-
const workspaceDisplayName = displayNames[`${workspace.line_id}_${workspace.workspace_name}`] ||
|
|
24818
|
+
const workspaceDisplayName = displayNames[`${workspace.line_id}_${workspace.workspace_name}`] || // Always pass line_id to fallback to ensure correct mapping per line
|
|
24819
|
+
getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
|
|
24820
24820
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
24821
24821
|
motion.div,
|
|
24822
24822
|
{
|
|
@@ -25662,18 +25662,30 @@ var BreakNotificationPopup = ({
|
|
|
25662
25662
|
className = "",
|
|
25663
25663
|
lineNames = {}
|
|
25664
25664
|
}) => {
|
|
25665
|
-
const [
|
|
25665
|
+
const [currentIndex, setCurrentIndex] = React23.useState(0);
|
|
25666
|
+
const [visibleBreaks, setVisibleBreaks] = React23.useState(activeBreaks);
|
|
25666
25667
|
const [currentTime, setCurrentTime] = React23.useState(/* @__PURE__ */ new Date());
|
|
25668
|
+
React23.useEffect(() => {
|
|
25669
|
+
setVisibleBreaks(activeBreaks);
|
|
25670
|
+
if (currentIndex >= activeBreaks.length) {
|
|
25671
|
+
setCurrentIndex(Math.max(0, activeBreaks.length - 1));
|
|
25672
|
+
}
|
|
25673
|
+
}, [activeBreaks, currentIndex]);
|
|
25667
25674
|
React23.useEffect(() => {
|
|
25668
25675
|
const timer = setInterval(() => {
|
|
25669
25676
|
setCurrentTime(/* @__PURE__ */ new Date());
|
|
25670
25677
|
}, 6e4);
|
|
25671
25678
|
return () => clearInterval(timer);
|
|
25672
25679
|
}, []);
|
|
25673
|
-
const
|
|
25674
|
-
setIsDismissed(true);
|
|
25680
|
+
const handleDismissAll = () => {
|
|
25675
25681
|
onDismiss?.();
|
|
25676
25682
|
};
|
|
25683
|
+
const handleNext = () => {
|
|
25684
|
+
setCurrentIndex((prev) => (prev + 1) % visibleBreaks.length);
|
|
25685
|
+
};
|
|
25686
|
+
const handlePrevious = () => {
|
|
25687
|
+
setCurrentIndex((prev) => (prev - 1 + visibleBreaks.length) % visibleBreaks.length);
|
|
25688
|
+
};
|
|
25677
25689
|
const formatTime3 = (minutes) => {
|
|
25678
25690
|
const hours = Math.floor(minutes / 60);
|
|
25679
25691
|
const mins = minutes % 60;
|
|
@@ -25682,69 +25694,130 @@ var BreakNotificationPopup = ({
|
|
|
25682
25694
|
}
|
|
25683
25695
|
return `${mins}m`;
|
|
25684
25696
|
};
|
|
25685
|
-
|
|
25697
|
+
const formatTo12Hour = (time24) => {
|
|
25698
|
+
const [hours, minutes] = time24.split(":").map(Number);
|
|
25699
|
+
if (isNaN(hours) || isNaN(minutes)) {
|
|
25700
|
+
return time24;
|
|
25701
|
+
}
|
|
25702
|
+
const period = hours >= 12 ? "PM" : "AM";
|
|
25703
|
+
const hours12 = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours;
|
|
25704
|
+
return `${hours12}:${minutes.toString().padStart(2, "0")} ${period}`;
|
|
25705
|
+
};
|
|
25706
|
+
if (!isVisible || visibleBreaks.length === 0) {
|
|
25686
25707
|
return null;
|
|
25687
25708
|
}
|
|
25688
|
-
|
|
25689
|
-
|
|
25690
|
-
{
|
|
25691
|
-
|
|
25692
|
-
|
|
25693
|
-
|
|
25694
|
-
|
|
25695
|
-
|
|
25696
|
-
|
|
25697
|
-
|
|
25698
|
-
|
|
25699
|
-
|
|
25700
|
-
|
|
25701
|
-
|
|
25702
|
-
|
|
25703
|
-
|
|
25704
|
-
|
|
25705
|
-
|
|
25706
|
-
|
|
25707
|
-
|
|
25709
|
+
const currentBreak = visibleBreaks[currentIndex];
|
|
25710
|
+
return /* @__PURE__ */ jsxRuntime.jsx(AnimatePresence, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `fixed right-4 top-24 z-50 max-w-xs w-full ${className}`, children: [
|
|
25711
|
+
visibleBreaks.length > 1 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
25712
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
25713
|
+
"div",
|
|
25714
|
+
{
|
|
25715
|
+
className: "absolute inset-0 bg-white rounded-lg border border-gray-300 shadow-lg",
|
|
25716
|
+
style: {
|
|
25717
|
+
transform: "translateY(12px) scale(0.94)",
|
|
25718
|
+
opacity: 0.6,
|
|
25719
|
+
zIndex: -2
|
|
25720
|
+
}
|
|
25721
|
+
}
|
|
25722
|
+
),
|
|
25723
|
+
visibleBreaks.length > 2 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
25724
|
+
"div",
|
|
25725
|
+
{
|
|
25726
|
+
className: "absolute inset-0 bg-white rounded-lg border border-gray-200 shadow-md",
|
|
25727
|
+
style: {
|
|
25728
|
+
transform: "translateY(6px) scale(0.97)",
|
|
25729
|
+
opacity: 0.8,
|
|
25730
|
+
zIndex: -1
|
|
25731
|
+
}
|
|
25732
|
+
}
|
|
25733
|
+
)
|
|
25734
|
+
] }),
|
|
25735
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
25736
|
+
motion.div,
|
|
25737
|
+
{
|
|
25738
|
+
initial: { opacity: 0, x: 100, y: -20 },
|
|
25739
|
+
animate: { opacity: 1, x: 0, y: 0 },
|
|
25740
|
+
exit: { opacity: 0, x: -100, y: -20 },
|
|
25741
|
+
transition: { duration: 0.3, ease: "easeOut" },
|
|
25742
|
+
className: "relative z-10",
|
|
25743
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-white text-gray-900 rounded-lg border border-gray-200 shadow-xl overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-3", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between", children: [
|
|
25744
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start space-x-3 flex-1", children: [
|
|
25745
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(AxelOrb, { size: "md" }) }),
|
|
25746
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
25747
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-1.5", children: [
|
|
25748
|
+
/* @__PURE__ */ jsxRuntime.jsxs("h4", { className: "font-semibold text-sm text-gray-900", children: [
|
|
25749
|
+
currentBreak.remarks || "Break",
|
|
25750
|
+
lineNames[currentBreak.lineId] && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-gray-500 ml-1", children: [
|
|
25751
|
+
"\u2022 ",
|
|
25752
|
+
lineNames[currentBreak.lineId]
|
|
25753
|
+
] })
|
|
25754
|
+
] }),
|
|
25755
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Coffee, { className: "w-4 h-4 text-amber-500" })
|
|
25708
25756
|
] }),
|
|
25709
|
-
/* @__PURE__ */ jsxRuntime.
|
|
25710
|
-
|
|
25711
|
-
|
|
25712
|
-
|
|
25713
|
-
|
|
25714
|
-
"
|
|
25715
|
-
|
|
25716
|
-
|
|
25717
|
-
|
|
25718
|
-
|
|
25719
|
-
|
|
25720
|
-
"
|
|
25721
|
-
|
|
25722
|
-
|
|
25723
|
-
|
|
25724
|
-
|
|
25725
|
-
|
|
25726
|
-
|
|
25727
|
-
width: `${Math.min(100, Math.max(0, breakItem.elapsedMinutes / breakItem.duration * 100))}%`
|
|
25757
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-gray-600 mb-1", children: [
|
|
25758
|
+
formatTo12Hour(currentBreak.startTime),
|
|
25759
|
+
" - ",
|
|
25760
|
+
formatTo12Hour(currentBreak.endTime)
|
|
25761
|
+
] }),
|
|
25762
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-gray-500 mb-2", children: [
|
|
25763
|
+
formatTime3(currentBreak.elapsedMinutes),
|
|
25764
|
+
" elapsed of ",
|
|
25765
|
+
formatTime3(currentBreak.duration),
|
|
25766
|
+
" total"
|
|
25767
|
+
] }),
|
|
25768
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full bg-gray-200 rounded-full h-1.5", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
25769
|
+
"div",
|
|
25770
|
+
{
|
|
25771
|
+
className: "h-1.5 bg-blue-500 rounded-full transition-all duration-1000",
|
|
25772
|
+
style: {
|
|
25773
|
+
width: `${Math.min(100, Math.max(0, currentBreak.elapsedMinutes / currentBreak.duration * 100))}%`
|
|
25774
|
+
}
|
|
25728
25775
|
}
|
|
25729
|
-
}
|
|
25730
|
-
|
|
25731
|
-
|
|
25732
|
-
|
|
25733
|
-
|
|
25734
|
-
|
|
25735
|
-
|
|
25736
|
-
|
|
25737
|
-
|
|
25738
|
-
|
|
25739
|
-
|
|
25740
|
-
|
|
25741
|
-
|
|
25742
|
-
|
|
25743
|
-
|
|
25744
|
-
|
|
25745
|
-
|
|
25746
|
-
|
|
25747
|
-
|
|
25776
|
+
) }),
|
|
25777
|
+
visibleBreaks.length > 1 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 pt-2 border-t border-gray-100", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
25778
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
25779
|
+
"button",
|
|
25780
|
+
{
|
|
25781
|
+
onClick: handlePrevious,
|
|
25782
|
+
className: "p-1 text-gray-400 hover:text-gray-600 hover:bg-gray-100 rounded-full transition-colors",
|
|
25783
|
+
"aria-label": "Previous break",
|
|
25784
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { className: "w-4 h-4" })
|
|
25785
|
+
}
|
|
25786
|
+
),
|
|
25787
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-gray-500", children: [
|
|
25788
|
+
currentIndex + 1,
|
|
25789
|
+
" of ",
|
|
25790
|
+
visibleBreaks.length,
|
|
25791
|
+
" breaks"
|
|
25792
|
+
] }),
|
|
25793
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
25794
|
+
"button",
|
|
25795
|
+
{
|
|
25796
|
+
onClick: handleNext,
|
|
25797
|
+
className: "p-1 text-gray-400 hover:text-gray-600 hover:bg-gray-100 rounded-full transition-colors",
|
|
25798
|
+
"aria-label": "Next break",
|
|
25799
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "w-4 h-4" })
|
|
25800
|
+
}
|
|
25801
|
+
)
|
|
25802
|
+
] }) })
|
|
25803
|
+
] })
|
|
25804
|
+
] }),
|
|
25805
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
25806
|
+
"button",
|
|
25807
|
+
{
|
|
25808
|
+
onClick: handleDismissAll,
|
|
25809
|
+
onTouchStart: () => {
|
|
25810
|
+
},
|
|
25811
|
+
className: "ml-2 text-gray-400 hover:text-gray-600 transition-colors p-2 sm:p-1 rounded-full hover:bg-gray-100 active:bg-gray-200 touch-manipulation min-h-[44px] min-w-[44px] sm:min-h-0 sm:min-w-0 flex items-center justify-center flex-shrink-0",
|
|
25812
|
+
"aria-label": "Dismiss all breaks",
|
|
25813
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-4 h-4 sm:w-3 sm:h-3" })
|
|
25814
|
+
}
|
|
25815
|
+
)
|
|
25816
|
+
] }) }) })
|
|
25817
|
+
},
|
|
25818
|
+
currentIndex
|
|
25819
|
+
)
|
|
25820
|
+
] }) });
|
|
25748
25821
|
};
|
|
25749
25822
|
async function fetchAxelNotifications() {
|
|
25750
25823
|
try {
|
|
@@ -26708,8 +26781,11 @@ var VideoPlayer = React23__namespace.default.forwardRef(({
|
|
|
26708
26781
|
experimentalLLHLS: false,
|
|
26709
26782
|
// Disable Low Latency HLS for VOD
|
|
26710
26783
|
// Connection settings
|
|
26711
|
-
|
|
26712
|
-
//
|
|
26784
|
+
// Chrome 130+ started throwing "Cannot perform Construct on a detached ArrayBuffer"
|
|
26785
|
+
// whenever the transmux worker tried to rehydrate transferred buffers that originated
|
|
26786
|
+
// from Blob-based playlists. Disabling the worker keeps playback stable at the cost
|
|
26787
|
+
// of slightly higher main-thread usage, which is acceptable for the dashboard usage.
|
|
26788
|
+
enableWorker: false,
|
|
26713
26789
|
progressive: true,
|
|
26714
26790
|
// Progressive download
|
|
26715
26791
|
// Adaptive bitrate settings (if multi-quality available)
|
|
@@ -27719,10 +27795,30 @@ function useWorkspaceCrop(workspaceId) {
|
|
|
27719
27795
|
}, [workspaceId]);
|
|
27720
27796
|
return { crop, isLoading, error };
|
|
27721
27797
|
}
|
|
27722
|
-
var
|
|
27798
|
+
var parseCycleTime = (value) => {
|
|
27799
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
27800
|
+
return value;
|
|
27801
|
+
}
|
|
27802
|
+
if (typeof value === "string") {
|
|
27803
|
+
const parsed = Number(value);
|
|
27804
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
27805
|
+
}
|
|
27806
|
+
return null;
|
|
27807
|
+
};
|
|
27808
|
+
var extractCycleTimeSeconds = (clip) => {
|
|
27809
|
+
return parseCycleTime(clip?.cycleTimeSeconds) ?? parseCycleTime(clip?.cycle_time_seconds) ?? parseCycleTime(clip?.duration) ?? parseCycleTime(clip?.original_task_metadata?.cycle_time) ?? null;
|
|
27810
|
+
};
|
|
27811
|
+
var getSeverityIcon = (severity, categoryId, cycleTimeSeconds, targetCycleTime) => {
|
|
27723
27812
|
if (categoryId === "idle_time" || categoryId === "low_value" || categoryId === "longest-idles") {
|
|
27724
27813
|
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "h-3 w-3 text-red-500" });
|
|
27725
27814
|
}
|
|
27815
|
+
if (categoryId === "cycle_completion" && targetCycleTime && targetCycleTime > 0 && cycleTimeSeconds !== null && cycleTimeSeconds !== void 0) {
|
|
27816
|
+
if (cycleTimeSeconds <= targetCycleTime) {
|
|
27817
|
+
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircle, { className: "h-3 w-3 text-green-500" });
|
|
27818
|
+
} else {
|
|
27819
|
+
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "h-3 w-3 text-red-500" });
|
|
27820
|
+
}
|
|
27821
|
+
}
|
|
27726
27822
|
switch (severity) {
|
|
27727
27823
|
case "high":
|
|
27728
27824
|
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "h-3 w-3 text-red-500" });
|
|
@@ -27777,7 +27873,8 @@ var FileManagerFilters = ({
|
|
|
27777
27873
|
workspaceId,
|
|
27778
27874
|
date,
|
|
27779
27875
|
shift,
|
|
27780
|
-
className = ""
|
|
27876
|
+
className = "",
|
|
27877
|
+
targetCycleTime = null
|
|
27781
27878
|
}) => {
|
|
27782
27879
|
const [expandedNodes, setExpandedNodes] = React23.useState(/* @__PURE__ */ new Set());
|
|
27783
27880
|
const [startTime, setStartTime] = React23.useState("");
|
|
@@ -27797,6 +27894,26 @@ var FileManagerFilters = ({
|
|
|
27797
27894
|
const [percentileCounts, setPercentileCounts] = React23.useState({});
|
|
27798
27895
|
const [percentileClips, setPercentileClips] = React23.useState({});
|
|
27799
27896
|
const [loadingPercentile, setLoadingPercentile] = React23.useState(false);
|
|
27897
|
+
const resolvedTargetCycleTime = targetCycleTime && targetCycleTime > 0 ? targetCycleTime : null;
|
|
27898
|
+
const getClipBadge = React23.useCallback((node) => {
|
|
27899
|
+
if (node.categoryId === "idle_time" || node.categoryId === "low_value") {
|
|
27900
|
+
return { text: "Idle", className: "bg-red-100 text-red-700" };
|
|
27901
|
+
}
|
|
27902
|
+
if (node.categoryId === "cycle_completion" && resolvedTargetCycleTime && node.cycleTimeSeconds !== void 0 && node.cycleTimeSeconds !== null) {
|
|
27903
|
+
const isFast = node.cycleTimeSeconds <= resolvedTargetCycleTime;
|
|
27904
|
+
return {
|
|
27905
|
+
text: isFast ? "Fast" : "Slow",
|
|
27906
|
+
className: isFast ? "bg-green-100 text-green-700" : "bg-red-100 text-red-700"
|
|
27907
|
+
};
|
|
27908
|
+
}
|
|
27909
|
+
if (node.severity === "high") {
|
|
27910
|
+
return { text: "Slow", className: "bg-red-100 text-red-700" };
|
|
27911
|
+
}
|
|
27912
|
+
if (node.severity === "medium") {
|
|
27913
|
+
return { text: "Average", className: "bg-yellow-100 text-yellow-700" };
|
|
27914
|
+
}
|
|
27915
|
+
return { text: "Fast", className: "bg-green-100 text-green-700" };
|
|
27916
|
+
}, [resolvedTargetCycleTime]);
|
|
27800
27917
|
const fetchClipMetadata = React23.useCallback(async (categoryId, page = 1) => {
|
|
27801
27918
|
if (!workspaceId || !date || shift === void 0) {
|
|
27802
27919
|
console.warn("[FileManager] Missing required params for clip metadata fetch");
|
|
@@ -28034,18 +28151,20 @@ var FileManagerFilters = ({
|
|
|
28034
28151
|
timeZone: timezone
|
|
28035
28152
|
// Use database timezone for display
|
|
28036
28153
|
});
|
|
28154
|
+
const cycleTime = extractCycleTimeSeconds(clip);
|
|
28037
28155
|
return {
|
|
28038
28156
|
id: clip.id,
|
|
28039
28157
|
label: `${timeString}${clip.duration && category.id !== "idle_time" ? ` - (${clip.duration.toFixed(1)}s)` : ""}`,
|
|
28040
28158
|
type: "video",
|
|
28041
|
-
icon: getSeverityIcon(clip.severity, category.id),
|
|
28159
|
+
icon: getSeverityIcon(clip.severity, category.id, cycleTime, resolvedTargetCycleTime),
|
|
28042
28160
|
timestamp: clip.clip_timestamp,
|
|
28043
28161
|
severity: clip.severity,
|
|
28044
28162
|
clipId: clip.clipId,
|
|
28045
28163
|
// Store stable UUID for navigation
|
|
28046
28164
|
categoryId: category.id,
|
|
28047
|
-
clipPosition: index + 1
|
|
28165
|
+
clipPosition: index + 1,
|
|
28048
28166
|
// Store 1-based position
|
|
28167
|
+
cycleTimeSeconds: cycleTime
|
|
28049
28168
|
};
|
|
28050
28169
|
});
|
|
28051
28170
|
regularCategoryNodes.push({
|
|
@@ -28084,15 +28203,17 @@ var FileManagerFilters = ({
|
|
|
28084
28203
|
minute: "2-digit",
|
|
28085
28204
|
timeZone: timezone
|
|
28086
28205
|
});
|
|
28206
|
+
const cycleTime = extractCycleTimeSeconds(clip);
|
|
28087
28207
|
return {
|
|
28088
28208
|
id: clip.id,
|
|
28089
28209
|
label: `${timeString}${clip.cycle_time_seconds ? ` - (${clip.cycle_time_seconds.toFixed(1)}s)` : ""}`,
|
|
28090
28210
|
type: "video",
|
|
28091
|
-
icon: getSeverityIcon(clip.severity, "fast-cycles"),
|
|
28211
|
+
icon: getSeverityIcon(clip.severity, "fast-cycles", cycleTime, resolvedTargetCycleTime),
|
|
28092
28212
|
timestamp: clip.creation_timestamp,
|
|
28093
28213
|
severity: clip.severity,
|
|
28094
28214
|
clipId: clip.id,
|
|
28095
|
-
categoryId: "fast-cycles"
|
|
28215
|
+
categoryId: "fast-cycles",
|
|
28216
|
+
cycleTimeSeconds: cycleTime
|
|
28096
28217
|
};
|
|
28097
28218
|
})
|
|
28098
28219
|
},
|
|
@@ -28114,15 +28235,17 @@ var FileManagerFilters = ({
|
|
|
28114
28235
|
minute: "2-digit",
|
|
28115
28236
|
timeZone: timezone
|
|
28116
28237
|
});
|
|
28238
|
+
const cycleTime = extractCycleTimeSeconds(clip);
|
|
28117
28239
|
return {
|
|
28118
28240
|
id: clip.id,
|
|
28119
28241
|
label: `${timeString}${clip.cycle_time_seconds ? ` - (${clip.cycle_time_seconds.toFixed(1)}s)` : ""}`,
|
|
28120
28242
|
type: "video",
|
|
28121
|
-
icon: getSeverityIcon(clip.severity, "slow-cycles"),
|
|
28243
|
+
icon: getSeverityIcon(clip.severity, "slow-cycles", cycleTime, resolvedTargetCycleTime),
|
|
28122
28244
|
timestamp: clip.creation_timestamp,
|
|
28123
28245
|
severity: clip.severity,
|
|
28124
28246
|
clipId: clip.id,
|
|
28125
|
-
categoryId: "slow-cycles"
|
|
28247
|
+
categoryId: "slow-cycles",
|
|
28248
|
+
cycleTimeSeconds: cycleTime
|
|
28126
28249
|
};
|
|
28127
28250
|
})
|
|
28128
28251
|
}
|
|
@@ -28243,7 +28366,10 @@ var FileManagerFilters = ({
|
|
|
28243
28366
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `font-semibold tracking-tight ${node.type === "category" || node.type === "percentile-category" ? "text-slate-800 text-sm" : "text-slate-700 text-xs"} ${isCurrentVideo ? "text-blue-700 font-bold" : ""} group-hover:text-slate-900 transition-colors duration-200`, children: node.label }),
|
|
28244
28367
|
node.type === "category" && categories.find((c) => c.id === node.id)?.description && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-slate-500 mt-0.5 font-normal", children: categories.find((c) => c.id === node.id)?.description }),
|
|
28245
28368
|
node.type === "percentile-category" && node.subtitle && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-slate-500 mt-0.5 font-normal", children: node.subtitle }),
|
|
28246
|
-
node.type === "video" && node.severity
|
|
28369
|
+
node.type === "video" && (node.severity || node.categoryId === "cycle_completion" || node.categoryId === "idle_time" || node.categoryId === "low_value") && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-slate-500 capitalize mt-0.5 font-medium", children: (() => {
|
|
28370
|
+
const badge = getClipBadge(node);
|
|
28371
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: `inline-flex items-center px-1.5 py-0.5 rounded-md text-xs font-medium ${badge.className}`, children: badge.text });
|
|
28372
|
+
})() })
|
|
28247
28373
|
] }),
|
|
28248
28374
|
node.count !== void 0 && (node.type === "category" || node.type === "percentile-category") && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center ml-2", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: `px-2.5 py-1 text-sm font-bold rounded-lg shadow-sm border backdrop-blur-sm flex-shrink-0 group-hover:scale-105 transition-all duration-200 ${colorClasses ? `${colorClasses.bg} ${colorClasses.text} ${colorClasses.border} bg-opacity-80` : "bg-slate-100/80 text-slate-700 border-slate-200/60"}`, children: node.count }) })
|
|
28249
28375
|
] })
|
|
@@ -28910,6 +29036,19 @@ var BottlenecksContent = ({
|
|
|
28910
29036
|
}
|
|
28911
29037
|
}, [shift, date, timezone, shiftConfig, workspaceId]);
|
|
28912
29038
|
const { crop: workspaceCrop} = useWorkspaceCrop(workspaceId);
|
|
29039
|
+
const { metrics: workspaceMetrics } = useWorkspaceDetailedMetrics(
|
|
29040
|
+
workspaceId,
|
|
29041
|
+
date,
|
|
29042
|
+
shift !== void 0 && shift !== null ? Number(shift) : void 0
|
|
29043
|
+
);
|
|
29044
|
+
const workspaceTargetCycleTimeRaw = workspaceMetrics?.ideal_cycle_time;
|
|
29045
|
+
const workspaceTargetCycleTime = (() => {
|
|
29046
|
+
if (workspaceTargetCycleTimeRaw === void 0 || workspaceTargetCycleTimeRaw === null) {
|
|
29047
|
+
return null;
|
|
29048
|
+
}
|
|
29049
|
+
const numericValue = typeof workspaceTargetCycleTimeRaw === "number" ? workspaceTargetCycleTimeRaw : Number(workspaceTargetCycleTimeRaw);
|
|
29050
|
+
return Number.isFinite(numericValue) ? numericValue : null;
|
|
29051
|
+
})();
|
|
28913
29052
|
const videoRef = React23.useRef(null);
|
|
28914
29053
|
const [initialFilter, setInitialFilter] = React23.useState("");
|
|
28915
29054
|
const currentIndexRef = React23.useRef(0);
|
|
@@ -29852,21 +29991,33 @@ var BottlenecksContent = ({
|
|
|
29852
29991
|
return () => window.removeEventListener("keydown", handleEscape);
|
|
29853
29992
|
}
|
|
29854
29993
|
}, [isFullscreen, exitFullscreen]);
|
|
29855
|
-
const getClipTypeLabel = (video) => {
|
|
29994
|
+
const getClipTypeLabel = React23.useCallback((video) => {
|
|
29856
29995
|
if (!video) return "";
|
|
29857
29996
|
const currentFilter = activeFilterRef.current;
|
|
29997
|
+
const targetCycleTime = workspaceTargetCycleTime || 0;
|
|
29858
29998
|
if (isPercentileCategory(currentFilter)) {
|
|
29859
29999
|
const percentileValue = video.percentile?.toFixed(1);
|
|
29860
|
-
|
|
29861
|
-
|
|
29862
|
-
|
|
29863
|
-
|
|
29864
|
-
|
|
29865
|
-
|
|
29866
|
-
|
|
29867
|
-
|
|
29868
|
-
|
|
30000
|
+
const cycleTime = video.cycle_time_seconds || 0;
|
|
30001
|
+
if (currentFilter === "fast-cycles" || currentFilter === "slow-cycles") {
|
|
30002
|
+
if (targetCycleTime > 0 && cycleTime > 0) {
|
|
30003
|
+
if (cycleTime < targetCycleTime) {
|
|
30004
|
+
return `\u26A1 Fast Cycle ${percentileValue ? `(${percentileValue}%)` : ""}`;
|
|
30005
|
+
} else {
|
|
30006
|
+
return `\u{1F40C} Slow Cycle ${percentileValue ? `(${percentileValue}%)` : ""}`;
|
|
30007
|
+
}
|
|
30008
|
+
} else {
|
|
30009
|
+
switch (currentFilter) {
|
|
30010
|
+
case "fast-cycles":
|
|
30011
|
+
return `\u26A1 Fast Cycle ${percentileValue ? `(${percentileValue}%)` : ""}`;
|
|
30012
|
+
case "slow-cycles":
|
|
30013
|
+
return `\u{1F40C} Slow Cycle ${percentileValue ? `(${percentileValue}%)` : ""}`;
|
|
30014
|
+
}
|
|
30015
|
+
}
|
|
29869
30016
|
}
|
|
30017
|
+
if (currentFilter === "longest-idles") {
|
|
30018
|
+
return `\u23F0 Long Idle ${percentileValue ? `(${percentileValue}%)` : ""}`;
|
|
30019
|
+
}
|
|
30020
|
+
return video.description || "Performance Clip";
|
|
29870
30021
|
}
|
|
29871
30022
|
switch (video.type) {
|
|
29872
30023
|
case "low_value":
|
|
@@ -29885,7 +30036,7 @@ var BottlenecksContent = ({
|
|
|
29885
30036
|
default:
|
|
29886
30037
|
return video.description || "";
|
|
29887
30038
|
}
|
|
29888
|
-
};
|
|
30039
|
+
}, [workspaceTargetCycleTime]);
|
|
29889
30040
|
if (!dashboardConfig?.s3Config) {
|
|
29890
30041
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-grow p-4 flex flex-col items-center justify-center h-[calc(100vh-12rem)] text-center", children: [
|
|
29891
30042
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.XCircle, { className: "w-12 h-12 text-red-400 mb-3" }),
|
|
@@ -30157,12 +30308,32 @@ var BottlenecksContent = ({
|
|
|
30157
30308
|
badgeText = "Idle";
|
|
30158
30309
|
badgeColor = "bg-red-100 text-red-700";
|
|
30159
30310
|
} else {
|
|
30160
|
-
|
|
30161
|
-
|
|
30162
|
-
|
|
30311
|
+
const parseCycleTime2 = (value) => {
|
|
30312
|
+
if (typeof value === "number") return isNaN(value) ? null : value;
|
|
30313
|
+
if (typeof value === "string") {
|
|
30314
|
+
const parsed = parseFloat(value);
|
|
30315
|
+
return isNaN(parsed) ? null : parsed;
|
|
30316
|
+
}
|
|
30317
|
+
return null;
|
|
30318
|
+
};
|
|
30319
|
+
const clipCycleTime = parseCycleTime2(clip.cycle_time_seconds) ?? parseCycleTime2(clip.duration) ?? parseCycleTime2(clip.original_task_metadata?.cycle_time);
|
|
30320
|
+
const targetCycleTime = workspaceTargetCycleTime && workspaceTargetCycleTime > 0 ? workspaceTargetCycleTime : null;
|
|
30321
|
+
if (clipCycleTime && targetCycleTime) {
|
|
30322
|
+
if (clipCycleTime <= targetCycleTime) {
|
|
30323
|
+
badgeText = "Fast";
|
|
30324
|
+
badgeColor = "bg-green-100 text-green-700";
|
|
30325
|
+
} else {
|
|
30326
|
+
badgeText = "Slow";
|
|
30327
|
+
badgeColor = "bg-red-100 text-red-700";
|
|
30328
|
+
}
|
|
30163
30329
|
} else {
|
|
30164
|
-
|
|
30165
|
-
|
|
30330
|
+
if (clip.severity === "high" || clip.duration && clip.duration > 60) {
|
|
30331
|
+
badgeText = "Slow";
|
|
30332
|
+
badgeColor = "bg-red-100 text-red-700";
|
|
30333
|
+
} else {
|
|
30334
|
+
badgeText = "Average";
|
|
30335
|
+
badgeColor = "bg-yellow-100 text-yellow-700";
|
|
30336
|
+
}
|
|
30166
30337
|
}
|
|
30167
30338
|
}
|
|
30168
30339
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -30205,6 +30376,7 @@ var BottlenecksContent = ({
|
|
|
30205
30376
|
workspaceId,
|
|
30206
30377
|
date: date || getOperationalDate(timezone),
|
|
30207
30378
|
shift: effectiveShift,
|
|
30379
|
+
targetCycleTime: workspaceTargetCycleTime,
|
|
30208
30380
|
onFilterChange: (filterId) => {
|
|
30209
30381
|
updateActiveFilter(filterId);
|
|
30210
30382
|
const category = categoriesToShow.find((cat) => cat.type === filterId);
|
|
@@ -41492,7 +41664,6 @@ function HomeView({
|
|
|
41492
41664
|
factoryName = "Simba Beer - Line 1"
|
|
41493
41665
|
}) {
|
|
41494
41666
|
const [isHydrated, setIsHydrated] = React23.useState(false);
|
|
41495
|
-
const [selectedLineId, setSelectedLineId] = React23.useState(factoryViewId);
|
|
41496
41667
|
const [isChangingFilter, setIsChangingFilter] = React23.useState(false);
|
|
41497
41668
|
const [errorMessage, setErrorMessage] = React23.useState(null);
|
|
41498
41669
|
const [displayNamesInitialized, setDisplayNamesInitialized] = React23.useState(false);
|
|
@@ -41509,9 +41680,36 @@ function HomeView({
|
|
|
41509
41680
|
}
|
|
41510
41681
|
return [factoryViewId, ...allLineIds];
|
|
41511
41682
|
}, [factoryViewId, allLineIds, isSupervisor, hasMultipleLines]);
|
|
41683
|
+
const LINE_FILTER_STORAGE_KEY = "optifye_home_line_filter";
|
|
41684
|
+
const [selectedLineId, setSelectedLineId] = React23.useState(() => {
|
|
41685
|
+
if (typeof window === "undefined") {
|
|
41686
|
+
return factoryViewId;
|
|
41687
|
+
}
|
|
41688
|
+
try {
|
|
41689
|
+
const savedLineId = sessionStorage.getItem(LINE_FILTER_STORAGE_KEY);
|
|
41690
|
+
if (savedLineId) {
|
|
41691
|
+
const allAvailableIds = [factoryViewId, ...allLineIds];
|
|
41692
|
+
if (allAvailableIds.includes(savedLineId)) {
|
|
41693
|
+
return savedLineId;
|
|
41694
|
+
}
|
|
41695
|
+
}
|
|
41696
|
+
} catch (error) {
|
|
41697
|
+
console.warn("Failed to read line filter from sessionStorage:", error);
|
|
41698
|
+
}
|
|
41699
|
+
return factoryViewId;
|
|
41700
|
+
});
|
|
41512
41701
|
React23.useEffect(() => {
|
|
41513
41702
|
if (user) {
|
|
41514
41703
|
if (isSupervisor && allLineIds.length > 0) {
|
|
41704
|
+
try {
|
|
41705
|
+
const savedLineId = sessionStorage.getItem(LINE_FILTER_STORAGE_KEY);
|
|
41706
|
+
if (savedLineId && allLineIds.includes(savedLineId)) {
|
|
41707
|
+
setSelectedLineId(savedLineId);
|
|
41708
|
+
return;
|
|
41709
|
+
}
|
|
41710
|
+
} catch (error) {
|
|
41711
|
+
console.warn("Failed to read line filter from sessionStorage:", error);
|
|
41712
|
+
}
|
|
41515
41713
|
setSelectedLineId(allLineIds[0]);
|
|
41516
41714
|
}
|
|
41517
41715
|
}
|
|
@@ -41592,6 +41790,12 @@ function HomeView({
|
|
|
41592
41790
|
}
|
|
41593
41791
|
return allActiveBreaks.filter((breakItem) => breakItem.lineId === selectedLineId);
|
|
41594
41792
|
}, [allActiveBreaks, selectedLineId, factoryViewId]);
|
|
41793
|
+
const [breakNotificationsDismissed, setBreakNotificationsDismissed] = React23.useState(false);
|
|
41794
|
+
React23.useEffect(() => {
|
|
41795
|
+
if (activeBreaks.length > 0) {
|
|
41796
|
+
setBreakNotificationsDismissed(false);
|
|
41797
|
+
}
|
|
41798
|
+
}, [activeBreaks.length]);
|
|
41595
41799
|
const showBottleneckNotification = React23.useCallback(async (bottleneck) => {
|
|
41596
41800
|
try {
|
|
41597
41801
|
console.log("\u{1F514} [Notification] Raw bottleneck data:", bottleneck);
|
|
@@ -41890,7 +42094,12 @@ function HomeView({
|
|
|
41890
42094
|
const handleLineChange = React23.useCallback((value) => {
|
|
41891
42095
|
setIsChangingFilter(true);
|
|
41892
42096
|
setSelectedLineId(value);
|
|
41893
|
-
|
|
42097
|
+
try {
|
|
42098
|
+
sessionStorage.setItem(LINE_FILTER_STORAGE_KEY, value);
|
|
42099
|
+
} catch (error) {
|
|
42100
|
+
console.warn("Failed to save line filter to sessionStorage:", error);
|
|
42101
|
+
}
|
|
42102
|
+
}, [LINE_FILTER_STORAGE_KEY]);
|
|
41894
42103
|
React23.useEffect(() => {
|
|
41895
42104
|
if (!metricsLoading && !kpisLoading && isChangingFilter) {
|
|
41896
42105
|
if (workspaceMetrics.length > 0 || selectedLineId === factoryViewId) {
|
|
@@ -42003,7 +42212,8 @@ function HomeView({
|
|
|
42003
42212
|
{
|
|
42004
42213
|
activeBreaks,
|
|
42005
42214
|
lineNames,
|
|
42006
|
-
isVisible: !breaksLoading && !breaksError
|
|
42215
|
+
isVisible: !breaksLoading && !breaksError && !breakNotificationsDismissed,
|
|
42216
|
+
onDismiss: () => setBreakNotificationsDismissed(true)
|
|
42007
42217
|
}
|
|
42008
42218
|
),
|
|
42009
42219
|
/* @__PURE__ */ jsxRuntime.jsx(
|
package/dist/index.mjs
CHANGED
|
@@ -11,7 +11,7 @@ import Hls2 from 'hls.js';
|
|
|
11
11
|
import useSWR from 'swr';
|
|
12
12
|
import { noop, warning, invariant, progress, secondsToMilliseconds, millisecondsToSeconds, memo as memo$1 } from 'motion-utils';
|
|
13
13
|
import { getValueTransition, hover, press, isPrimaryPointer, GroupPlaybackControls, setDragLock, supportsLinearEasing, attachTimeline, isGenerator, calcGeneratorDuration, isWaapiSupportedEasing, mapEasingToNativeEasing, maxGeneratorDuration, generateLinearEasing, isBezierDefinition } from 'motion-dom';
|
|
14
|
-
import { Camera, ChevronDown, ChevronUp, Check, Map as Map$1, Video, ShieldCheck, Star, Award, ArrowLeft, X, Coffee, Plus, Clock, Calendar, Save, AlertCircle, Loader2, Minus, ArrowDown, ArrowUp,
|
|
14
|
+
import { Camera, ChevronDown, ChevronUp, Check, Map as Map$1, Video, ShieldCheck, Star, Award, ArrowLeft, X, Coffee, Plus, Clock, Calendar, Save, AlertCircle, Loader2, Minus, ArrowDown, ArrowUp, ChevronLeft, ChevronRight, Pause, Play, XCircle, Maximize2, Sparkles, TrendingUp, Settings2, CheckCircle2, RefreshCw, TrendingDown, FolderOpen, Folder, HelpCircle, Sliders, Activity, Layers, Filter, Search, Edit2, AlertTriangle, CheckCircle, Building2, Mail, Users, User, Lock, ArrowRight, Info, Share2, Trophy, Target, Download, Sun, Moon, MousePointer, MessageSquare, Trash2, Menu, Send, Copy, UserCheck, LogOut, Package, UserPlus, Settings, LifeBuoy, EyeOff, Eye, MoreVertical, UserCog, Zap, Shield, UserCircle } from 'lucide-react';
|
|
15
15
|
import { toast } from 'sonner';
|
|
16
16
|
import { BarChart as BarChart$1, CartesianGrid, XAxis, YAxis, Tooltip, Legend, Bar, LabelList, ResponsiveContainer, LineChart as LineChart$1, Line, PieChart, Pie, Cell, ReferenceLine, ComposedChart, Area, ScatterChart, Scatter } from 'recharts';
|
|
17
17
|
import { Slot } from '@radix-ui/react-slot';
|
|
@@ -9576,9 +9576,6 @@ var getAllWorkspaceDisplayNamesAsync = async (companyId, lineId) => {
|
|
|
9576
9576
|
Object.entries(runtimeWorkspaceDisplayNames).forEach(([lineId2, lineNames]) => {
|
|
9577
9577
|
Object.entries(lineNames).forEach(([workspaceId, displayName]) => {
|
|
9578
9578
|
allNames[`${lineId2}_${workspaceId}`] = displayName;
|
|
9579
|
-
if (!allNames[workspaceId]) {
|
|
9580
|
-
allNames[workspaceId] = displayName;
|
|
9581
|
-
}
|
|
9582
9579
|
});
|
|
9583
9580
|
});
|
|
9584
9581
|
return allNames;
|
|
@@ -24707,7 +24704,8 @@ var VideoGridView = React23__default.memo(({
|
|
|
24707
24704
|
displayName: (
|
|
24708
24705
|
// Create line-aware lookup key: lineId_workspaceName
|
|
24709
24706
|
// This ensures correct mapping when multiple lines have same workspace names
|
|
24710
|
-
displayNames[`${workspace.line_id}_${workspace.workspace_name}`] ||
|
|
24707
|
+
displayNames[`${workspace.line_id}_${workspace.workspace_name}`] || // Always pass line_id to fallback to ensure correct mapping per line
|
|
24708
|
+
getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id)
|
|
24711
24709
|
),
|
|
24712
24710
|
useRAF: canvasConfig?.useRAF,
|
|
24713
24711
|
compact: !selectedLine,
|
|
@@ -24757,7 +24755,8 @@ var MapGridView = React23__default.memo(({
|
|
|
24757
24755
|
efficiency: workspace.efficiency,
|
|
24758
24756
|
action_count: workspace.action_count
|
|
24759
24757
|
});
|
|
24760
|
-
const displayName = displayNames[`${workspace.line_id}_${workspace.workspace_name}`] ||
|
|
24758
|
+
const displayName = displayNames[`${workspace.line_id}_${workspace.workspace_name}`] || // Always pass line_id to fallback to ensure correct mapping per line
|
|
24759
|
+
getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
|
|
24761
24760
|
const navParams = getWorkspaceNavigationParams(workspaceId, displayName, workspace.line_id);
|
|
24762
24761
|
router.push(`/workspace/${workspaceId}${navParams}`);
|
|
24763
24762
|
}, [router, displayNames]);
|
|
@@ -24786,7 +24785,8 @@ var MapGridView = React23__default.memo(({
|
|
|
24786
24785
|
if (!workspace) return null;
|
|
24787
24786
|
const workspaceId = workspace.workspace_uuid || workspace.workspace_name;
|
|
24788
24787
|
getPerformanceColor(workspace.efficiency);
|
|
24789
|
-
const workspaceDisplayName = displayNames[`${workspace.line_id}_${workspace.workspace_name}`] ||
|
|
24788
|
+
const workspaceDisplayName = displayNames[`${workspace.line_id}_${workspace.workspace_name}`] || // Always pass line_id to fallback to ensure correct mapping per line
|
|
24789
|
+
getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
|
|
24790
24790
|
return /* @__PURE__ */ jsx(
|
|
24791
24791
|
motion.div,
|
|
24792
24792
|
{
|
|
@@ -25632,18 +25632,30 @@ var BreakNotificationPopup = ({
|
|
|
25632
25632
|
className = "",
|
|
25633
25633
|
lineNames = {}
|
|
25634
25634
|
}) => {
|
|
25635
|
-
const [
|
|
25635
|
+
const [currentIndex, setCurrentIndex] = useState(0);
|
|
25636
|
+
const [visibleBreaks, setVisibleBreaks] = useState(activeBreaks);
|
|
25636
25637
|
const [currentTime, setCurrentTime] = useState(/* @__PURE__ */ new Date());
|
|
25638
|
+
useEffect(() => {
|
|
25639
|
+
setVisibleBreaks(activeBreaks);
|
|
25640
|
+
if (currentIndex >= activeBreaks.length) {
|
|
25641
|
+
setCurrentIndex(Math.max(0, activeBreaks.length - 1));
|
|
25642
|
+
}
|
|
25643
|
+
}, [activeBreaks, currentIndex]);
|
|
25637
25644
|
useEffect(() => {
|
|
25638
25645
|
const timer = setInterval(() => {
|
|
25639
25646
|
setCurrentTime(/* @__PURE__ */ new Date());
|
|
25640
25647
|
}, 6e4);
|
|
25641
25648
|
return () => clearInterval(timer);
|
|
25642
25649
|
}, []);
|
|
25643
|
-
const
|
|
25644
|
-
setIsDismissed(true);
|
|
25650
|
+
const handleDismissAll = () => {
|
|
25645
25651
|
onDismiss?.();
|
|
25646
25652
|
};
|
|
25653
|
+
const handleNext = () => {
|
|
25654
|
+
setCurrentIndex((prev) => (prev + 1) % visibleBreaks.length);
|
|
25655
|
+
};
|
|
25656
|
+
const handlePrevious = () => {
|
|
25657
|
+
setCurrentIndex((prev) => (prev - 1 + visibleBreaks.length) % visibleBreaks.length);
|
|
25658
|
+
};
|
|
25647
25659
|
const formatTime3 = (minutes) => {
|
|
25648
25660
|
const hours = Math.floor(minutes / 60);
|
|
25649
25661
|
const mins = minutes % 60;
|
|
@@ -25652,69 +25664,130 @@ var BreakNotificationPopup = ({
|
|
|
25652
25664
|
}
|
|
25653
25665
|
return `${mins}m`;
|
|
25654
25666
|
};
|
|
25655
|
-
|
|
25667
|
+
const formatTo12Hour = (time24) => {
|
|
25668
|
+
const [hours, minutes] = time24.split(":").map(Number);
|
|
25669
|
+
if (isNaN(hours) || isNaN(minutes)) {
|
|
25670
|
+
return time24;
|
|
25671
|
+
}
|
|
25672
|
+
const period = hours >= 12 ? "PM" : "AM";
|
|
25673
|
+
const hours12 = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours;
|
|
25674
|
+
return `${hours12}:${minutes.toString().padStart(2, "0")} ${period}`;
|
|
25675
|
+
};
|
|
25676
|
+
if (!isVisible || visibleBreaks.length === 0) {
|
|
25656
25677
|
return null;
|
|
25657
25678
|
}
|
|
25658
|
-
|
|
25659
|
-
|
|
25660
|
-
{
|
|
25661
|
-
|
|
25662
|
-
|
|
25663
|
-
|
|
25664
|
-
|
|
25665
|
-
|
|
25666
|
-
|
|
25667
|
-
|
|
25668
|
-
|
|
25669
|
-
|
|
25670
|
-
|
|
25671
|
-
|
|
25672
|
-
|
|
25673
|
-
|
|
25674
|
-
|
|
25675
|
-
|
|
25676
|
-
|
|
25677
|
-
|
|
25679
|
+
const currentBreak = visibleBreaks[currentIndex];
|
|
25680
|
+
return /* @__PURE__ */ jsx(AnimatePresence, { children: /* @__PURE__ */ jsxs("div", { className: `fixed right-4 top-24 z-50 max-w-xs w-full ${className}`, children: [
|
|
25681
|
+
visibleBreaks.length > 1 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
25682
|
+
/* @__PURE__ */ jsx(
|
|
25683
|
+
"div",
|
|
25684
|
+
{
|
|
25685
|
+
className: "absolute inset-0 bg-white rounded-lg border border-gray-300 shadow-lg",
|
|
25686
|
+
style: {
|
|
25687
|
+
transform: "translateY(12px) scale(0.94)",
|
|
25688
|
+
opacity: 0.6,
|
|
25689
|
+
zIndex: -2
|
|
25690
|
+
}
|
|
25691
|
+
}
|
|
25692
|
+
),
|
|
25693
|
+
visibleBreaks.length > 2 && /* @__PURE__ */ jsx(
|
|
25694
|
+
"div",
|
|
25695
|
+
{
|
|
25696
|
+
className: "absolute inset-0 bg-white rounded-lg border border-gray-200 shadow-md",
|
|
25697
|
+
style: {
|
|
25698
|
+
transform: "translateY(6px) scale(0.97)",
|
|
25699
|
+
opacity: 0.8,
|
|
25700
|
+
zIndex: -1
|
|
25701
|
+
}
|
|
25702
|
+
}
|
|
25703
|
+
)
|
|
25704
|
+
] }),
|
|
25705
|
+
/* @__PURE__ */ jsx(
|
|
25706
|
+
motion.div,
|
|
25707
|
+
{
|
|
25708
|
+
initial: { opacity: 0, x: 100, y: -20 },
|
|
25709
|
+
animate: { opacity: 1, x: 0, y: 0 },
|
|
25710
|
+
exit: { opacity: 0, x: -100, y: -20 },
|
|
25711
|
+
transition: { duration: 0.3, ease: "easeOut" },
|
|
25712
|
+
className: "relative z-10",
|
|
25713
|
+
children: /* @__PURE__ */ jsx("div", { className: "bg-white text-gray-900 rounded-lg border border-gray-200 shadow-xl overflow-hidden", children: /* @__PURE__ */ jsx("div", { className: "p-3", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between", children: [
|
|
25714
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-start space-x-3 flex-1", children: [
|
|
25715
|
+
/* @__PURE__ */ jsx("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsx(AxelOrb, { size: "md" }) }),
|
|
25716
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
25717
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-1.5", children: [
|
|
25718
|
+
/* @__PURE__ */ jsxs("h4", { className: "font-semibold text-sm text-gray-900", children: [
|
|
25719
|
+
currentBreak.remarks || "Break",
|
|
25720
|
+
lineNames[currentBreak.lineId] && /* @__PURE__ */ jsxs("span", { className: "text-xs text-gray-500 ml-1", children: [
|
|
25721
|
+
"\u2022 ",
|
|
25722
|
+
lineNames[currentBreak.lineId]
|
|
25723
|
+
] })
|
|
25724
|
+
] }),
|
|
25725
|
+
/* @__PURE__ */ jsx(Coffee, { className: "w-4 h-4 text-amber-500" })
|
|
25678
25726
|
] }),
|
|
25679
|
-
/* @__PURE__ */
|
|
25680
|
-
|
|
25681
|
-
|
|
25682
|
-
|
|
25683
|
-
|
|
25684
|
-
"
|
|
25685
|
-
|
|
25686
|
-
|
|
25687
|
-
|
|
25688
|
-
|
|
25689
|
-
|
|
25690
|
-
"
|
|
25691
|
-
|
|
25692
|
-
|
|
25693
|
-
|
|
25694
|
-
|
|
25695
|
-
|
|
25696
|
-
|
|
25697
|
-
width: `${Math.min(100, Math.max(0, breakItem.elapsedMinutes / breakItem.duration * 100))}%`
|
|
25727
|
+
/* @__PURE__ */ jsxs("p", { className: "text-xs text-gray-600 mb-1", children: [
|
|
25728
|
+
formatTo12Hour(currentBreak.startTime),
|
|
25729
|
+
" - ",
|
|
25730
|
+
formatTo12Hour(currentBreak.endTime)
|
|
25731
|
+
] }),
|
|
25732
|
+
/* @__PURE__ */ jsxs("p", { className: "text-xs text-gray-500 mb-2", children: [
|
|
25733
|
+
formatTime3(currentBreak.elapsedMinutes),
|
|
25734
|
+
" elapsed of ",
|
|
25735
|
+
formatTime3(currentBreak.duration),
|
|
25736
|
+
" total"
|
|
25737
|
+
] }),
|
|
25738
|
+
/* @__PURE__ */ jsx("div", { className: "w-full bg-gray-200 rounded-full h-1.5", children: /* @__PURE__ */ jsx(
|
|
25739
|
+
"div",
|
|
25740
|
+
{
|
|
25741
|
+
className: "h-1.5 bg-blue-500 rounded-full transition-all duration-1000",
|
|
25742
|
+
style: {
|
|
25743
|
+
width: `${Math.min(100, Math.max(0, currentBreak.elapsedMinutes / currentBreak.duration * 100))}%`
|
|
25744
|
+
}
|
|
25698
25745
|
}
|
|
25699
|
-
}
|
|
25700
|
-
|
|
25701
|
-
|
|
25702
|
-
|
|
25703
|
-
|
|
25704
|
-
|
|
25705
|
-
|
|
25706
|
-
|
|
25707
|
-
|
|
25708
|
-
|
|
25709
|
-
|
|
25710
|
-
|
|
25711
|
-
|
|
25712
|
-
|
|
25713
|
-
|
|
25714
|
-
|
|
25715
|
-
|
|
25716
|
-
|
|
25717
|
-
|
|
25746
|
+
) }),
|
|
25747
|
+
visibleBreaks.length > 1 && /* @__PURE__ */ jsx("div", { className: "mt-3 pt-2 border-t border-gray-100", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
25748
|
+
/* @__PURE__ */ jsx(
|
|
25749
|
+
"button",
|
|
25750
|
+
{
|
|
25751
|
+
onClick: handlePrevious,
|
|
25752
|
+
className: "p-1 text-gray-400 hover:text-gray-600 hover:bg-gray-100 rounded-full transition-colors",
|
|
25753
|
+
"aria-label": "Previous break",
|
|
25754
|
+
children: /* @__PURE__ */ jsx(ChevronLeft, { className: "w-4 h-4" })
|
|
25755
|
+
}
|
|
25756
|
+
),
|
|
25757
|
+
/* @__PURE__ */ jsxs("p", { className: "text-xs text-gray-500", children: [
|
|
25758
|
+
currentIndex + 1,
|
|
25759
|
+
" of ",
|
|
25760
|
+
visibleBreaks.length,
|
|
25761
|
+
" breaks"
|
|
25762
|
+
] }),
|
|
25763
|
+
/* @__PURE__ */ jsx(
|
|
25764
|
+
"button",
|
|
25765
|
+
{
|
|
25766
|
+
onClick: handleNext,
|
|
25767
|
+
className: "p-1 text-gray-400 hover:text-gray-600 hover:bg-gray-100 rounded-full transition-colors",
|
|
25768
|
+
"aria-label": "Next break",
|
|
25769
|
+
children: /* @__PURE__ */ jsx(ChevronRight, { className: "w-4 h-4" })
|
|
25770
|
+
}
|
|
25771
|
+
)
|
|
25772
|
+
] }) })
|
|
25773
|
+
] })
|
|
25774
|
+
] }),
|
|
25775
|
+
/* @__PURE__ */ jsx(
|
|
25776
|
+
"button",
|
|
25777
|
+
{
|
|
25778
|
+
onClick: handleDismissAll,
|
|
25779
|
+
onTouchStart: () => {
|
|
25780
|
+
},
|
|
25781
|
+
className: "ml-2 text-gray-400 hover:text-gray-600 transition-colors p-2 sm:p-1 rounded-full hover:bg-gray-100 active:bg-gray-200 touch-manipulation min-h-[44px] min-w-[44px] sm:min-h-0 sm:min-w-0 flex items-center justify-center flex-shrink-0",
|
|
25782
|
+
"aria-label": "Dismiss all breaks",
|
|
25783
|
+
children: /* @__PURE__ */ jsx(X, { className: "w-4 h-4 sm:w-3 sm:h-3" })
|
|
25784
|
+
}
|
|
25785
|
+
)
|
|
25786
|
+
] }) }) })
|
|
25787
|
+
},
|
|
25788
|
+
currentIndex
|
|
25789
|
+
)
|
|
25790
|
+
] }) });
|
|
25718
25791
|
};
|
|
25719
25792
|
async function fetchAxelNotifications() {
|
|
25720
25793
|
try {
|
|
@@ -26678,8 +26751,11 @@ var VideoPlayer = React23__default.forwardRef(({
|
|
|
26678
26751
|
experimentalLLHLS: false,
|
|
26679
26752
|
// Disable Low Latency HLS for VOD
|
|
26680
26753
|
// Connection settings
|
|
26681
|
-
|
|
26682
|
-
//
|
|
26754
|
+
// Chrome 130+ started throwing "Cannot perform Construct on a detached ArrayBuffer"
|
|
26755
|
+
// whenever the transmux worker tried to rehydrate transferred buffers that originated
|
|
26756
|
+
// from Blob-based playlists. Disabling the worker keeps playback stable at the cost
|
|
26757
|
+
// of slightly higher main-thread usage, which is acceptable for the dashboard usage.
|
|
26758
|
+
enableWorker: false,
|
|
26683
26759
|
progressive: true,
|
|
26684
26760
|
// Progressive download
|
|
26685
26761
|
// Adaptive bitrate settings (if multi-quality available)
|
|
@@ -27689,10 +27765,30 @@ function useWorkspaceCrop(workspaceId) {
|
|
|
27689
27765
|
}, [workspaceId]);
|
|
27690
27766
|
return { crop, isLoading, error };
|
|
27691
27767
|
}
|
|
27692
|
-
var
|
|
27768
|
+
var parseCycleTime = (value) => {
|
|
27769
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
27770
|
+
return value;
|
|
27771
|
+
}
|
|
27772
|
+
if (typeof value === "string") {
|
|
27773
|
+
const parsed = Number(value);
|
|
27774
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
27775
|
+
}
|
|
27776
|
+
return null;
|
|
27777
|
+
};
|
|
27778
|
+
var extractCycleTimeSeconds = (clip) => {
|
|
27779
|
+
return parseCycleTime(clip?.cycleTimeSeconds) ?? parseCycleTime(clip?.cycle_time_seconds) ?? parseCycleTime(clip?.duration) ?? parseCycleTime(clip?.original_task_metadata?.cycle_time) ?? null;
|
|
27780
|
+
};
|
|
27781
|
+
var getSeverityIcon = (severity, categoryId, cycleTimeSeconds, targetCycleTime) => {
|
|
27693
27782
|
if (categoryId === "idle_time" || categoryId === "low_value" || categoryId === "longest-idles") {
|
|
27694
27783
|
return /* @__PURE__ */ jsx(AlertTriangle, { className: "h-3 w-3 text-red-500" });
|
|
27695
27784
|
}
|
|
27785
|
+
if (categoryId === "cycle_completion" && targetCycleTime && targetCycleTime > 0 && cycleTimeSeconds !== null && cycleTimeSeconds !== void 0) {
|
|
27786
|
+
if (cycleTimeSeconds <= targetCycleTime) {
|
|
27787
|
+
return /* @__PURE__ */ jsx(CheckCircle, { className: "h-3 w-3 text-green-500" });
|
|
27788
|
+
} else {
|
|
27789
|
+
return /* @__PURE__ */ jsx(AlertTriangle, { className: "h-3 w-3 text-red-500" });
|
|
27790
|
+
}
|
|
27791
|
+
}
|
|
27696
27792
|
switch (severity) {
|
|
27697
27793
|
case "high":
|
|
27698
27794
|
return /* @__PURE__ */ jsx(AlertTriangle, { className: "h-3 w-3 text-red-500" });
|
|
@@ -27747,7 +27843,8 @@ var FileManagerFilters = ({
|
|
|
27747
27843
|
workspaceId,
|
|
27748
27844
|
date,
|
|
27749
27845
|
shift,
|
|
27750
|
-
className = ""
|
|
27846
|
+
className = "",
|
|
27847
|
+
targetCycleTime = null
|
|
27751
27848
|
}) => {
|
|
27752
27849
|
const [expandedNodes, setExpandedNodes] = useState(/* @__PURE__ */ new Set());
|
|
27753
27850
|
const [startTime, setStartTime] = useState("");
|
|
@@ -27767,6 +27864,26 @@ var FileManagerFilters = ({
|
|
|
27767
27864
|
const [percentileCounts, setPercentileCounts] = useState({});
|
|
27768
27865
|
const [percentileClips, setPercentileClips] = useState({});
|
|
27769
27866
|
const [loadingPercentile, setLoadingPercentile] = useState(false);
|
|
27867
|
+
const resolvedTargetCycleTime = targetCycleTime && targetCycleTime > 0 ? targetCycleTime : null;
|
|
27868
|
+
const getClipBadge = useCallback((node) => {
|
|
27869
|
+
if (node.categoryId === "idle_time" || node.categoryId === "low_value") {
|
|
27870
|
+
return { text: "Idle", className: "bg-red-100 text-red-700" };
|
|
27871
|
+
}
|
|
27872
|
+
if (node.categoryId === "cycle_completion" && resolvedTargetCycleTime && node.cycleTimeSeconds !== void 0 && node.cycleTimeSeconds !== null) {
|
|
27873
|
+
const isFast = node.cycleTimeSeconds <= resolvedTargetCycleTime;
|
|
27874
|
+
return {
|
|
27875
|
+
text: isFast ? "Fast" : "Slow",
|
|
27876
|
+
className: isFast ? "bg-green-100 text-green-700" : "bg-red-100 text-red-700"
|
|
27877
|
+
};
|
|
27878
|
+
}
|
|
27879
|
+
if (node.severity === "high") {
|
|
27880
|
+
return { text: "Slow", className: "bg-red-100 text-red-700" };
|
|
27881
|
+
}
|
|
27882
|
+
if (node.severity === "medium") {
|
|
27883
|
+
return { text: "Average", className: "bg-yellow-100 text-yellow-700" };
|
|
27884
|
+
}
|
|
27885
|
+
return { text: "Fast", className: "bg-green-100 text-green-700" };
|
|
27886
|
+
}, [resolvedTargetCycleTime]);
|
|
27770
27887
|
const fetchClipMetadata = useCallback(async (categoryId, page = 1) => {
|
|
27771
27888
|
if (!workspaceId || !date || shift === void 0) {
|
|
27772
27889
|
console.warn("[FileManager] Missing required params for clip metadata fetch");
|
|
@@ -28004,18 +28121,20 @@ var FileManagerFilters = ({
|
|
|
28004
28121
|
timeZone: timezone
|
|
28005
28122
|
// Use database timezone for display
|
|
28006
28123
|
});
|
|
28124
|
+
const cycleTime = extractCycleTimeSeconds(clip);
|
|
28007
28125
|
return {
|
|
28008
28126
|
id: clip.id,
|
|
28009
28127
|
label: `${timeString}${clip.duration && category.id !== "idle_time" ? ` - (${clip.duration.toFixed(1)}s)` : ""}`,
|
|
28010
28128
|
type: "video",
|
|
28011
|
-
icon: getSeverityIcon(clip.severity, category.id),
|
|
28129
|
+
icon: getSeverityIcon(clip.severity, category.id, cycleTime, resolvedTargetCycleTime),
|
|
28012
28130
|
timestamp: clip.clip_timestamp,
|
|
28013
28131
|
severity: clip.severity,
|
|
28014
28132
|
clipId: clip.clipId,
|
|
28015
28133
|
// Store stable UUID for navigation
|
|
28016
28134
|
categoryId: category.id,
|
|
28017
|
-
clipPosition: index + 1
|
|
28135
|
+
clipPosition: index + 1,
|
|
28018
28136
|
// Store 1-based position
|
|
28137
|
+
cycleTimeSeconds: cycleTime
|
|
28019
28138
|
};
|
|
28020
28139
|
});
|
|
28021
28140
|
regularCategoryNodes.push({
|
|
@@ -28054,15 +28173,17 @@ var FileManagerFilters = ({
|
|
|
28054
28173
|
minute: "2-digit",
|
|
28055
28174
|
timeZone: timezone
|
|
28056
28175
|
});
|
|
28176
|
+
const cycleTime = extractCycleTimeSeconds(clip);
|
|
28057
28177
|
return {
|
|
28058
28178
|
id: clip.id,
|
|
28059
28179
|
label: `${timeString}${clip.cycle_time_seconds ? ` - (${clip.cycle_time_seconds.toFixed(1)}s)` : ""}`,
|
|
28060
28180
|
type: "video",
|
|
28061
|
-
icon: getSeverityIcon(clip.severity, "fast-cycles"),
|
|
28181
|
+
icon: getSeverityIcon(clip.severity, "fast-cycles", cycleTime, resolvedTargetCycleTime),
|
|
28062
28182
|
timestamp: clip.creation_timestamp,
|
|
28063
28183
|
severity: clip.severity,
|
|
28064
28184
|
clipId: clip.id,
|
|
28065
|
-
categoryId: "fast-cycles"
|
|
28185
|
+
categoryId: "fast-cycles",
|
|
28186
|
+
cycleTimeSeconds: cycleTime
|
|
28066
28187
|
};
|
|
28067
28188
|
})
|
|
28068
28189
|
},
|
|
@@ -28084,15 +28205,17 @@ var FileManagerFilters = ({
|
|
|
28084
28205
|
minute: "2-digit",
|
|
28085
28206
|
timeZone: timezone
|
|
28086
28207
|
});
|
|
28208
|
+
const cycleTime = extractCycleTimeSeconds(clip);
|
|
28087
28209
|
return {
|
|
28088
28210
|
id: clip.id,
|
|
28089
28211
|
label: `${timeString}${clip.cycle_time_seconds ? ` - (${clip.cycle_time_seconds.toFixed(1)}s)` : ""}`,
|
|
28090
28212
|
type: "video",
|
|
28091
|
-
icon: getSeverityIcon(clip.severity, "slow-cycles"),
|
|
28213
|
+
icon: getSeverityIcon(clip.severity, "slow-cycles", cycleTime, resolvedTargetCycleTime),
|
|
28092
28214
|
timestamp: clip.creation_timestamp,
|
|
28093
28215
|
severity: clip.severity,
|
|
28094
28216
|
clipId: clip.id,
|
|
28095
|
-
categoryId: "slow-cycles"
|
|
28217
|
+
categoryId: "slow-cycles",
|
|
28218
|
+
cycleTimeSeconds: cycleTime
|
|
28096
28219
|
};
|
|
28097
28220
|
})
|
|
28098
28221
|
}
|
|
@@ -28213,7 +28336,10 @@ var FileManagerFilters = ({
|
|
|
28213
28336
|
/* @__PURE__ */ jsx("div", { className: `font-semibold tracking-tight ${node.type === "category" || node.type === "percentile-category" ? "text-slate-800 text-sm" : "text-slate-700 text-xs"} ${isCurrentVideo ? "text-blue-700 font-bold" : ""} group-hover:text-slate-900 transition-colors duration-200`, children: node.label }),
|
|
28214
28337
|
node.type === "category" && categories.find((c) => c.id === node.id)?.description && /* @__PURE__ */ jsx("div", { className: "text-xs text-slate-500 mt-0.5 font-normal", children: categories.find((c) => c.id === node.id)?.description }),
|
|
28215
28338
|
node.type === "percentile-category" && node.subtitle && /* @__PURE__ */ jsx("div", { className: "text-xs text-slate-500 mt-0.5 font-normal", children: node.subtitle }),
|
|
28216
|
-
node.type === "video" && node.severity
|
|
28339
|
+
node.type === "video" && (node.severity || node.categoryId === "cycle_completion" || node.categoryId === "idle_time" || node.categoryId === "low_value") && /* @__PURE__ */ jsx("div", { className: "text-xs text-slate-500 capitalize mt-0.5 font-medium", children: (() => {
|
|
28340
|
+
const badge = getClipBadge(node);
|
|
28341
|
+
return /* @__PURE__ */ jsx("span", { className: `inline-flex items-center px-1.5 py-0.5 rounded-md text-xs font-medium ${badge.className}`, children: badge.text });
|
|
28342
|
+
})() })
|
|
28217
28343
|
] }),
|
|
28218
28344
|
node.count !== void 0 && (node.type === "category" || node.type === "percentile-category") && /* @__PURE__ */ jsx("div", { className: "flex items-center ml-2", children: /* @__PURE__ */ jsx("span", { className: `px-2.5 py-1 text-sm font-bold rounded-lg shadow-sm border backdrop-blur-sm flex-shrink-0 group-hover:scale-105 transition-all duration-200 ${colorClasses ? `${colorClasses.bg} ${colorClasses.text} ${colorClasses.border} bg-opacity-80` : "bg-slate-100/80 text-slate-700 border-slate-200/60"}`, children: node.count }) })
|
|
28219
28345
|
] })
|
|
@@ -28880,6 +29006,19 @@ var BottlenecksContent = ({
|
|
|
28880
29006
|
}
|
|
28881
29007
|
}, [shift, date, timezone, shiftConfig, workspaceId]);
|
|
28882
29008
|
const { crop: workspaceCrop} = useWorkspaceCrop(workspaceId);
|
|
29009
|
+
const { metrics: workspaceMetrics } = useWorkspaceDetailedMetrics(
|
|
29010
|
+
workspaceId,
|
|
29011
|
+
date,
|
|
29012
|
+
shift !== void 0 && shift !== null ? Number(shift) : void 0
|
|
29013
|
+
);
|
|
29014
|
+
const workspaceTargetCycleTimeRaw = workspaceMetrics?.ideal_cycle_time;
|
|
29015
|
+
const workspaceTargetCycleTime = (() => {
|
|
29016
|
+
if (workspaceTargetCycleTimeRaw === void 0 || workspaceTargetCycleTimeRaw === null) {
|
|
29017
|
+
return null;
|
|
29018
|
+
}
|
|
29019
|
+
const numericValue = typeof workspaceTargetCycleTimeRaw === "number" ? workspaceTargetCycleTimeRaw : Number(workspaceTargetCycleTimeRaw);
|
|
29020
|
+
return Number.isFinite(numericValue) ? numericValue : null;
|
|
29021
|
+
})();
|
|
28883
29022
|
const videoRef = useRef(null);
|
|
28884
29023
|
const [initialFilter, setInitialFilter] = useState("");
|
|
28885
29024
|
const currentIndexRef = useRef(0);
|
|
@@ -29822,21 +29961,33 @@ var BottlenecksContent = ({
|
|
|
29822
29961
|
return () => window.removeEventListener("keydown", handleEscape);
|
|
29823
29962
|
}
|
|
29824
29963
|
}, [isFullscreen, exitFullscreen]);
|
|
29825
|
-
const getClipTypeLabel = (video) => {
|
|
29964
|
+
const getClipTypeLabel = useCallback((video) => {
|
|
29826
29965
|
if (!video) return "";
|
|
29827
29966
|
const currentFilter = activeFilterRef.current;
|
|
29967
|
+
const targetCycleTime = workspaceTargetCycleTime || 0;
|
|
29828
29968
|
if (isPercentileCategory(currentFilter)) {
|
|
29829
29969
|
const percentileValue = video.percentile?.toFixed(1);
|
|
29830
|
-
|
|
29831
|
-
|
|
29832
|
-
|
|
29833
|
-
|
|
29834
|
-
|
|
29835
|
-
|
|
29836
|
-
|
|
29837
|
-
|
|
29838
|
-
|
|
29970
|
+
const cycleTime = video.cycle_time_seconds || 0;
|
|
29971
|
+
if (currentFilter === "fast-cycles" || currentFilter === "slow-cycles") {
|
|
29972
|
+
if (targetCycleTime > 0 && cycleTime > 0) {
|
|
29973
|
+
if (cycleTime < targetCycleTime) {
|
|
29974
|
+
return `\u26A1 Fast Cycle ${percentileValue ? `(${percentileValue}%)` : ""}`;
|
|
29975
|
+
} else {
|
|
29976
|
+
return `\u{1F40C} Slow Cycle ${percentileValue ? `(${percentileValue}%)` : ""}`;
|
|
29977
|
+
}
|
|
29978
|
+
} else {
|
|
29979
|
+
switch (currentFilter) {
|
|
29980
|
+
case "fast-cycles":
|
|
29981
|
+
return `\u26A1 Fast Cycle ${percentileValue ? `(${percentileValue}%)` : ""}`;
|
|
29982
|
+
case "slow-cycles":
|
|
29983
|
+
return `\u{1F40C} Slow Cycle ${percentileValue ? `(${percentileValue}%)` : ""}`;
|
|
29984
|
+
}
|
|
29985
|
+
}
|
|
29839
29986
|
}
|
|
29987
|
+
if (currentFilter === "longest-idles") {
|
|
29988
|
+
return `\u23F0 Long Idle ${percentileValue ? `(${percentileValue}%)` : ""}`;
|
|
29989
|
+
}
|
|
29990
|
+
return video.description || "Performance Clip";
|
|
29840
29991
|
}
|
|
29841
29992
|
switch (video.type) {
|
|
29842
29993
|
case "low_value":
|
|
@@ -29855,7 +30006,7 @@ var BottlenecksContent = ({
|
|
|
29855
30006
|
default:
|
|
29856
30007
|
return video.description || "";
|
|
29857
30008
|
}
|
|
29858
|
-
};
|
|
30009
|
+
}, [workspaceTargetCycleTime]);
|
|
29859
30010
|
if (!dashboardConfig?.s3Config) {
|
|
29860
30011
|
return /* @__PURE__ */ jsxs("div", { className: "flex-grow p-4 flex flex-col items-center justify-center h-[calc(100vh-12rem)] text-center", children: [
|
|
29861
30012
|
/* @__PURE__ */ jsx(XCircle, { className: "w-12 h-12 text-red-400 mb-3" }),
|
|
@@ -30127,12 +30278,32 @@ var BottlenecksContent = ({
|
|
|
30127
30278
|
badgeText = "Idle";
|
|
30128
30279
|
badgeColor = "bg-red-100 text-red-700";
|
|
30129
30280
|
} else {
|
|
30130
|
-
|
|
30131
|
-
|
|
30132
|
-
|
|
30281
|
+
const parseCycleTime2 = (value) => {
|
|
30282
|
+
if (typeof value === "number") return isNaN(value) ? null : value;
|
|
30283
|
+
if (typeof value === "string") {
|
|
30284
|
+
const parsed = parseFloat(value);
|
|
30285
|
+
return isNaN(parsed) ? null : parsed;
|
|
30286
|
+
}
|
|
30287
|
+
return null;
|
|
30288
|
+
};
|
|
30289
|
+
const clipCycleTime = parseCycleTime2(clip.cycle_time_seconds) ?? parseCycleTime2(clip.duration) ?? parseCycleTime2(clip.original_task_metadata?.cycle_time);
|
|
30290
|
+
const targetCycleTime = workspaceTargetCycleTime && workspaceTargetCycleTime > 0 ? workspaceTargetCycleTime : null;
|
|
30291
|
+
if (clipCycleTime && targetCycleTime) {
|
|
30292
|
+
if (clipCycleTime <= targetCycleTime) {
|
|
30293
|
+
badgeText = "Fast";
|
|
30294
|
+
badgeColor = "bg-green-100 text-green-700";
|
|
30295
|
+
} else {
|
|
30296
|
+
badgeText = "Slow";
|
|
30297
|
+
badgeColor = "bg-red-100 text-red-700";
|
|
30298
|
+
}
|
|
30133
30299
|
} else {
|
|
30134
|
-
|
|
30135
|
-
|
|
30300
|
+
if (clip.severity === "high" || clip.duration && clip.duration > 60) {
|
|
30301
|
+
badgeText = "Slow";
|
|
30302
|
+
badgeColor = "bg-red-100 text-red-700";
|
|
30303
|
+
} else {
|
|
30304
|
+
badgeText = "Average";
|
|
30305
|
+
badgeColor = "bg-yellow-100 text-yellow-700";
|
|
30306
|
+
}
|
|
30136
30307
|
}
|
|
30137
30308
|
}
|
|
30138
30309
|
return /* @__PURE__ */ jsx(
|
|
@@ -30175,6 +30346,7 @@ var BottlenecksContent = ({
|
|
|
30175
30346
|
workspaceId,
|
|
30176
30347
|
date: date || getOperationalDate(timezone),
|
|
30177
30348
|
shift: effectiveShift,
|
|
30349
|
+
targetCycleTime: workspaceTargetCycleTime,
|
|
30178
30350
|
onFilterChange: (filterId) => {
|
|
30179
30351
|
updateActiveFilter(filterId);
|
|
30180
30352
|
const category = categoriesToShow.find((cat) => cat.type === filterId);
|
|
@@ -41462,7 +41634,6 @@ function HomeView({
|
|
|
41462
41634
|
factoryName = "Simba Beer - Line 1"
|
|
41463
41635
|
}) {
|
|
41464
41636
|
const [isHydrated, setIsHydrated] = useState(false);
|
|
41465
|
-
const [selectedLineId, setSelectedLineId] = useState(factoryViewId);
|
|
41466
41637
|
const [isChangingFilter, setIsChangingFilter] = useState(false);
|
|
41467
41638
|
const [errorMessage, setErrorMessage] = useState(null);
|
|
41468
41639
|
const [displayNamesInitialized, setDisplayNamesInitialized] = useState(false);
|
|
@@ -41479,9 +41650,36 @@ function HomeView({
|
|
|
41479
41650
|
}
|
|
41480
41651
|
return [factoryViewId, ...allLineIds];
|
|
41481
41652
|
}, [factoryViewId, allLineIds, isSupervisor, hasMultipleLines]);
|
|
41653
|
+
const LINE_FILTER_STORAGE_KEY = "optifye_home_line_filter";
|
|
41654
|
+
const [selectedLineId, setSelectedLineId] = useState(() => {
|
|
41655
|
+
if (typeof window === "undefined") {
|
|
41656
|
+
return factoryViewId;
|
|
41657
|
+
}
|
|
41658
|
+
try {
|
|
41659
|
+
const savedLineId = sessionStorage.getItem(LINE_FILTER_STORAGE_KEY);
|
|
41660
|
+
if (savedLineId) {
|
|
41661
|
+
const allAvailableIds = [factoryViewId, ...allLineIds];
|
|
41662
|
+
if (allAvailableIds.includes(savedLineId)) {
|
|
41663
|
+
return savedLineId;
|
|
41664
|
+
}
|
|
41665
|
+
}
|
|
41666
|
+
} catch (error) {
|
|
41667
|
+
console.warn("Failed to read line filter from sessionStorage:", error);
|
|
41668
|
+
}
|
|
41669
|
+
return factoryViewId;
|
|
41670
|
+
});
|
|
41482
41671
|
useEffect(() => {
|
|
41483
41672
|
if (user) {
|
|
41484
41673
|
if (isSupervisor && allLineIds.length > 0) {
|
|
41674
|
+
try {
|
|
41675
|
+
const savedLineId = sessionStorage.getItem(LINE_FILTER_STORAGE_KEY);
|
|
41676
|
+
if (savedLineId && allLineIds.includes(savedLineId)) {
|
|
41677
|
+
setSelectedLineId(savedLineId);
|
|
41678
|
+
return;
|
|
41679
|
+
}
|
|
41680
|
+
} catch (error) {
|
|
41681
|
+
console.warn("Failed to read line filter from sessionStorage:", error);
|
|
41682
|
+
}
|
|
41485
41683
|
setSelectedLineId(allLineIds[0]);
|
|
41486
41684
|
}
|
|
41487
41685
|
}
|
|
@@ -41562,6 +41760,12 @@ function HomeView({
|
|
|
41562
41760
|
}
|
|
41563
41761
|
return allActiveBreaks.filter((breakItem) => breakItem.lineId === selectedLineId);
|
|
41564
41762
|
}, [allActiveBreaks, selectedLineId, factoryViewId]);
|
|
41763
|
+
const [breakNotificationsDismissed, setBreakNotificationsDismissed] = useState(false);
|
|
41764
|
+
useEffect(() => {
|
|
41765
|
+
if (activeBreaks.length > 0) {
|
|
41766
|
+
setBreakNotificationsDismissed(false);
|
|
41767
|
+
}
|
|
41768
|
+
}, [activeBreaks.length]);
|
|
41565
41769
|
const showBottleneckNotification = useCallback(async (bottleneck) => {
|
|
41566
41770
|
try {
|
|
41567
41771
|
console.log("\u{1F514} [Notification] Raw bottleneck data:", bottleneck);
|
|
@@ -41860,7 +42064,12 @@ function HomeView({
|
|
|
41860
42064
|
const handleLineChange = useCallback((value) => {
|
|
41861
42065
|
setIsChangingFilter(true);
|
|
41862
42066
|
setSelectedLineId(value);
|
|
41863
|
-
|
|
42067
|
+
try {
|
|
42068
|
+
sessionStorage.setItem(LINE_FILTER_STORAGE_KEY, value);
|
|
42069
|
+
} catch (error) {
|
|
42070
|
+
console.warn("Failed to save line filter to sessionStorage:", error);
|
|
42071
|
+
}
|
|
42072
|
+
}, [LINE_FILTER_STORAGE_KEY]);
|
|
41864
42073
|
useEffect(() => {
|
|
41865
42074
|
if (!metricsLoading && !kpisLoading && isChangingFilter) {
|
|
41866
42075
|
if (workspaceMetrics.length > 0 || selectedLineId === factoryViewId) {
|
|
@@ -41973,7 +42182,8 @@ function HomeView({
|
|
|
41973
42182
|
{
|
|
41974
42183
|
activeBreaks,
|
|
41975
42184
|
lineNames,
|
|
41976
|
-
isVisible: !breaksLoading && !breaksError
|
|
42185
|
+
isVisible: !breaksLoading && !breaksError && !breakNotificationsDismissed,
|
|
42186
|
+
onDismiss: () => setBreakNotificationsDismissed(true)
|
|
41977
42187
|
}
|
|
41978
42188
|
),
|
|
41979
42189
|
/* @__PURE__ */ jsx(
|