@optifye/dashboard-core 6.9.5 → 6.9.7
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 +319 -99
- package/dist/index.mjs +320 -100
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -9603,8 +9603,13 @@ var getAllWorkspaceDisplayNamesAsync = async (companyId, lineId) => {
|
|
|
9603
9603
|
return { ...runtimeWorkspaceDisplayNames[lineId] };
|
|
9604
9604
|
}
|
|
9605
9605
|
const allNames = {};
|
|
9606
|
-
Object.
|
|
9607
|
-
Object.
|
|
9606
|
+
Object.entries(runtimeWorkspaceDisplayNames).forEach(([lineId2, lineNames]) => {
|
|
9607
|
+
Object.entries(lineNames).forEach(([workspaceId, displayName]) => {
|
|
9608
|
+
allNames[`${lineId2}_${workspaceId}`] = displayName;
|
|
9609
|
+
if (!allNames[workspaceId]) {
|
|
9610
|
+
allNames[workspaceId] = displayName;
|
|
9611
|
+
}
|
|
9612
|
+
});
|
|
9608
9613
|
});
|
|
9609
9614
|
return allNames;
|
|
9610
9615
|
};
|
|
@@ -24729,7 +24734,11 @@ var VideoGridView = React23__namespace.default.memo(({
|
|
|
24729
24734
|
isVeryLowEfficiency,
|
|
24730
24735
|
cropping: workspaceCropping,
|
|
24731
24736
|
canvasFps: canvasConfig?.fps,
|
|
24732
|
-
displayName:
|
|
24737
|
+
displayName: (
|
|
24738
|
+
// Create line-aware lookup key: lineId_workspaceName
|
|
24739
|
+
// This ensures correct mapping when multiple lines have same workspace names
|
|
24740
|
+
displayNames[`${workspace.line_id}_${workspace.workspace_name}`] || displayNames[workspace.workspace_name] || getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id)
|
|
24741
|
+
),
|
|
24733
24742
|
useRAF: canvasConfig?.useRAF,
|
|
24734
24743
|
compact: !selectedLine,
|
|
24735
24744
|
onMouseEnter: onWorkspaceHover ? () => onWorkspaceHover(workspaceId) : void 0,
|
|
@@ -24778,7 +24787,7 @@ var MapGridView = React23__namespace.default.memo(({
|
|
|
24778
24787
|
efficiency: workspace.efficiency,
|
|
24779
24788
|
action_count: workspace.action_count
|
|
24780
24789
|
});
|
|
24781
|
-
const displayName = displayNames[workspace.workspace_name] || getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
|
|
24790
|
+
const displayName = displayNames[`${workspace.line_id}_${workspace.workspace_name}`] || displayNames[workspace.workspace_name] || getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
|
|
24782
24791
|
const navParams = getWorkspaceNavigationParams(workspaceId, displayName, workspace.line_id);
|
|
24783
24792
|
router$1.push(`/workspace/${workspaceId}${navParams}`);
|
|
24784
24793
|
}, [router$1, displayNames]);
|
|
@@ -24807,7 +24816,7 @@ var MapGridView = React23__namespace.default.memo(({
|
|
|
24807
24816
|
if (!workspace) return null;
|
|
24808
24817
|
const workspaceId = workspace.workspace_uuid || workspace.workspace_name;
|
|
24809
24818
|
getPerformanceColor(workspace.efficiency);
|
|
24810
|
-
const workspaceDisplayName = displayNames[workspace.workspace_name] || getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
|
|
24819
|
+
const workspaceDisplayName = displayNames[`${workspace.line_id}_${workspace.workspace_name}`] || displayNames[workspace.workspace_name] || getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
|
|
24811
24820
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
24812
24821
|
motion.div,
|
|
24813
24822
|
{
|
|
@@ -25653,18 +25662,30 @@ var BreakNotificationPopup = ({
|
|
|
25653
25662
|
className = "",
|
|
25654
25663
|
lineNames = {}
|
|
25655
25664
|
}) => {
|
|
25656
|
-
const [
|
|
25665
|
+
const [currentIndex, setCurrentIndex] = React23.useState(0);
|
|
25666
|
+
const [visibleBreaks, setVisibleBreaks] = React23.useState(activeBreaks);
|
|
25657
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]);
|
|
25658
25674
|
React23.useEffect(() => {
|
|
25659
25675
|
const timer = setInterval(() => {
|
|
25660
25676
|
setCurrentTime(/* @__PURE__ */ new Date());
|
|
25661
25677
|
}, 6e4);
|
|
25662
25678
|
return () => clearInterval(timer);
|
|
25663
25679
|
}, []);
|
|
25664
|
-
const
|
|
25665
|
-
setIsDismissed(true);
|
|
25680
|
+
const handleDismissAll = () => {
|
|
25666
25681
|
onDismiss?.();
|
|
25667
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
|
+
};
|
|
25668
25689
|
const formatTime3 = (minutes) => {
|
|
25669
25690
|
const hours = Math.floor(minutes / 60);
|
|
25670
25691
|
const mins = minutes % 60;
|
|
@@ -25673,69 +25694,130 @@ var BreakNotificationPopup = ({
|
|
|
25673
25694
|
}
|
|
25674
25695
|
return `${mins}m`;
|
|
25675
25696
|
};
|
|
25676
|
-
|
|
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) {
|
|
25677
25707
|
return null;
|
|
25678
25708
|
}
|
|
25679
|
-
|
|
25680
|
-
|
|
25681
|
-
{
|
|
25682
|
-
|
|
25683
|
-
|
|
25684
|
-
|
|
25685
|
-
|
|
25686
|
-
|
|
25687
|
-
|
|
25688
|
-
|
|
25689
|
-
|
|
25690
|
-
|
|
25691
|
-
|
|
25692
|
-
|
|
25693
|
-
|
|
25694
|
-
|
|
25695
|
-
|
|
25696
|
-
|
|
25697
|
-
|
|
25698
|
-
|
|
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" })
|
|
25699
25756
|
] }),
|
|
25700
|
-
/* @__PURE__ */ jsxRuntime.
|
|
25701
|
-
|
|
25702
|
-
|
|
25703
|
-
|
|
25704
|
-
|
|
25705
|
-
"
|
|
25706
|
-
|
|
25707
|
-
|
|
25708
|
-
|
|
25709
|
-
|
|
25710
|
-
|
|
25711
|
-
"
|
|
25712
|
-
|
|
25713
|
-
|
|
25714
|
-
|
|
25715
|
-
|
|
25716
|
-
|
|
25717
|
-
|
|
25718
|
-
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
|
+
}
|
|
25719
25775
|
}
|
|
25720
|
-
}
|
|
25721
|
-
|
|
25722
|
-
|
|
25723
|
-
|
|
25724
|
-
|
|
25725
|
-
|
|
25726
|
-
|
|
25727
|
-
|
|
25728
|
-
|
|
25729
|
-
|
|
25730
|
-
|
|
25731
|
-
|
|
25732
|
-
|
|
25733
|
-
|
|
25734
|
-
|
|
25735
|
-
|
|
25736
|
-
|
|
25737
|
-
|
|
25738
|
-
|
|
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
|
+
] }) });
|
|
25739
25821
|
};
|
|
25740
25822
|
async function fetchAxelNotifications() {
|
|
25741
25823
|
try {
|
|
@@ -26699,8 +26781,11 @@ var VideoPlayer = React23__namespace.default.forwardRef(({
|
|
|
26699
26781
|
experimentalLLHLS: false,
|
|
26700
26782
|
// Disable Low Latency HLS for VOD
|
|
26701
26783
|
// Connection settings
|
|
26702
|
-
|
|
26703
|
-
//
|
|
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,
|
|
26704
26789
|
progressive: true,
|
|
26705
26790
|
// Progressive download
|
|
26706
26791
|
// Adaptive bitrate settings (if multi-quality available)
|
|
@@ -27710,10 +27795,30 @@ function useWorkspaceCrop(workspaceId) {
|
|
|
27710
27795
|
}, [workspaceId]);
|
|
27711
27796
|
return { crop, isLoading, error };
|
|
27712
27797
|
}
|
|
27713
|
-
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) => {
|
|
27714
27812
|
if (categoryId === "idle_time" || categoryId === "low_value" || categoryId === "longest-idles") {
|
|
27715
27813
|
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "h-3 w-3 text-red-500" });
|
|
27716
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
|
+
}
|
|
27717
27822
|
switch (severity) {
|
|
27718
27823
|
case "high":
|
|
27719
27824
|
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "h-3 w-3 text-red-500" });
|
|
@@ -27768,7 +27873,8 @@ var FileManagerFilters = ({
|
|
|
27768
27873
|
workspaceId,
|
|
27769
27874
|
date,
|
|
27770
27875
|
shift,
|
|
27771
|
-
className = ""
|
|
27876
|
+
className = "",
|
|
27877
|
+
targetCycleTime = null
|
|
27772
27878
|
}) => {
|
|
27773
27879
|
const [expandedNodes, setExpandedNodes] = React23.useState(/* @__PURE__ */ new Set());
|
|
27774
27880
|
const [startTime, setStartTime] = React23.useState("");
|
|
@@ -27788,6 +27894,26 @@ var FileManagerFilters = ({
|
|
|
27788
27894
|
const [percentileCounts, setPercentileCounts] = React23.useState({});
|
|
27789
27895
|
const [percentileClips, setPercentileClips] = React23.useState({});
|
|
27790
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]);
|
|
27791
27917
|
const fetchClipMetadata = React23.useCallback(async (categoryId, page = 1) => {
|
|
27792
27918
|
if (!workspaceId || !date || shift === void 0) {
|
|
27793
27919
|
console.warn("[FileManager] Missing required params for clip metadata fetch");
|
|
@@ -28025,18 +28151,20 @@ var FileManagerFilters = ({
|
|
|
28025
28151
|
timeZone: timezone
|
|
28026
28152
|
// Use database timezone for display
|
|
28027
28153
|
});
|
|
28154
|
+
const cycleTime = extractCycleTimeSeconds(clip);
|
|
28028
28155
|
return {
|
|
28029
28156
|
id: clip.id,
|
|
28030
28157
|
label: `${timeString}${clip.duration && category.id !== "idle_time" ? ` - (${clip.duration.toFixed(1)}s)` : ""}`,
|
|
28031
28158
|
type: "video",
|
|
28032
|
-
icon: getSeverityIcon(clip.severity, category.id),
|
|
28159
|
+
icon: getSeverityIcon(clip.severity, category.id, cycleTime, resolvedTargetCycleTime),
|
|
28033
28160
|
timestamp: clip.clip_timestamp,
|
|
28034
28161
|
severity: clip.severity,
|
|
28035
28162
|
clipId: clip.clipId,
|
|
28036
28163
|
// Store stable UUID for navigation
|
|
28037
28164
|
categoryId: category.id,
|
|
28038
|
-
clipPosition: index + 1
|
|
28165
|
+
clipPosition: index + 1,
|
|
28039
28166
|
// Store 1-based position
|
|
28167
|
+
cycleTimeSeconds: cycleTime
|
|
28040
28168
|
};
|
|
28041
28169
|
});
|
|
28042
28170
|
regularCategoryNodes.push({
|
|
@@ -28075,15 +28203,17 @@ var FileManagerFilters = ({
|
|
|
28075
28203
|
minute: "2-digit",
|
|
28076
28204
|
timeZone: timezone
|
|
28077
28205
|
});
|
|
28206
|
+
const cycleTime = extractCycleTimeSeconds(clip);
|
|
28078
28207
|
return {
|
|
28079
28208
|
id: clip.id,
|
|
28080
28209
|
label: `${timeString}${clip.cycle_time_seconds ? ` - (${clip.cycle_time_seconds.toFixed(1)}s)` : ""}`,
|
|
28081
28210
|
type: "video",
|
|
28082
|
-
icon: getSeverityIcon(clip.severity, "fast-cycles"),
|
|
28211
|
+
icon: getSeverityIcon(clip.severity, "fast-cycles", cycleTime, resolvedTargetCycleTime),
|
|
28083
28212
|
timestamp: clip.creation_timestamp,
|
|
28084
28213
|
severity: clip.severity,
|
|
28085
28214
|
clipId: clip.id,
|
|
28086
|
-
categoryId: "fast-cycles"
|
|
28215
|
+
categoryId: "fast-cycles",
|
|
28216
|
+
cycleTimeSeconds: cycleTime
|
|
28087
28217
|
};
|
|
28088
28218
|
})
|
|
28089
28219
|
},
|
|
@@ -28105,15 +28235,17 @@ var FileManagerFilters = ({
|
|
|
28105
28235
|
minute: "2-digit",
|
|
28106
28236
|
timeZone: timezone
|
|
28107
28237
|
});
|
|
28238
|
+
const cycleTime = extractCycleTimeSeconds(clip);
|
|
28108
28239
|
return {
|
|
28109
28240
|
id: clip.id,
|
|
28110
28241
|
label: `${timeString}${clip.cycle_time_seconds ? ` - (${clip.cycle_time_seconds.toFixed(1)}s)` : ""}`,
|
|
28111
28242
|
type: "video",
|
|
28112
|
-
icon: getSeverityIcon(clip.severity, "slow-cycles"),
|
|
28243
|
+
icon: getSeverityIcon(clip.severity, "slow-cycles", cycleTime, resolvedTargetCycleTime),
|
|
28113
28244
|
timestamp: clip.creation_timestamp,
|
|
28114
28245
|
severity: clip.severity,
|
|
28115
28246
|
clipId: clip.id,
|
|
28116
|
-
categoryId: "slow-cycles"
|
|
28247
|
+
categoryId: "slow-cycles",
|
|
28248
|
+
cycleTimeSeconds: cycleTime
|
|
28117
28249
|
};
|
|
28118
28250
|
})
|
|
28119
28251
|
}
|
|
@@ -28234,7 +28366,10 @@ var FileManagerFilters = ({
|
|
|
28234
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 }),
|
|
28235
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 }),
|
|
28236
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 }),
|
|
28237
|
-
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
|
+
})() })
|
|
28238
28373
|
] }),
|
|
28239
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 }) })
|
|
28240
28375
|
] })
|
|
@@ -28901,6 +29036,19 @@ var BottlenecksContent = ({
|
|
|
28901
29036
|
}
|
|
28902
29037
|
}, [shift, date, timezone, shiftConfig, workspaceId]);
|
|
28903
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
|
+
})();
|
|
28904
29052
|
const videoRef = React23.useRef(null);
|
|
28905
29053
|
const [initialFilter, setInitialFilter] = React23.useState("");
|
|
28906
29054
|
const currentIndexRef = React23.useRef(0);
|
|
@@ -29843,21 +29991,33 @@ var BottlenecksContent = ({
|
|
|
29843
29991
|
return () => window.removeEventListener("keydown", handleEscape);
|
|
29844
29992
|
}
|
|
29845
29993
|
}, [isFullscreen, exitFullscreen]);
|
|
29846
|
-
const getClipTypeLabel = (video) => {
|
|
29994
|
+
const getClipTypeLabel = React23.useCallback((video) => {
|
|
29847
29995
|
if (!video) return "";
|
|
29848
29996
|
const currentFilter = activeFilterRef.current;
|
|
29997
|
+
const targetCycleTime = workspaceTargetCycleTime || 0;
|
|
29849
29998
|
if (isPercentileCategory(currentFilter)) {
|
|
29850
29999
|
const percentileValue = video.percentile?.toFixed(1);
|
|
29851
|
-
|
|
29852
|
-
|
|
29853
|
-
|
|
29854
|
-
|
|
29855
|
-
|
|
29856
|
-
|
|
29857
|
-
|
|
29858
|
-
|
|
29859
|
-
|
|
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
|
+
}
|
|
29860
30016
|
}
|
|
30017
|
+
if (currentFilter === "longest-idles") {
|
|
30018
|
+
return `\u23F0 Long Idle ${percentileValue ? `(${percentileValue}%)` : ""}`;
|
|
30019
|
+
}
|
|
30020
|
+
return video.description || "Performance Clip";
|
|
29861
30021
|
}
|
|
29862
30022
|
switch (video.type) {
|
|
29863
30023
|
case "low_value":
|
|
@@ -29876,7 +30036,7 @@ var BottlenecksContent = ({
|
|
|
29876
30036
|
default:
|
|
29877
30037
|
return video.description || "";
|
|
29878
30038
|
}
|
|
29879
|
-
};
|
|
30039
|
+
}, [workspaceTargetCycleTime]);
|
|
29880
30040
|
if (!dashboardConfig?.s3Config) {
|
|
29881
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: [
|
|
29882
30042
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.XCircle, { className: "w-12 h-12 text-red-400 mb-3" }),
|
|
@@ -30148,12 +30308,32 @@ var BottlenecksContent = ({
|
|
|
30148
30308
|
badgeText = "Idle";
|
|
30149
30309
|
badgeColor = "bg-red-100 text-red-700";
|
|
30150
30310
|
} else {
|
|
30151
|
-
|
|
30152
|
-
|
|
30153
|
-
|
|
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
|
+
}
|
|
30154
30329
|
} else {
|
|
30155
|
-
|
|
30156
|
-
|
|
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
|
+
}
|
|
30157
30337
|
}
|
|
30158
30338
|
}
|
|
30159
30339
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -30196,6 +30376,7 @@ var BottlenecksContent = ({
|
|
|
30196
30376
|
workspaceId,
|
|
30197
30377
|
date: date || getOperationalDate(timezone),
|
|
30198
30378
|
shift: effectiveShift,
|
|
30379
|
+
targetCycleTime: workspaceTargetCycleTime,
|
|
30199
30380
|
onFilterChange: (filterId) => {
|
|
30200
30381
|
updateActiveFilter(filterId);
|
|
30201
30382
|
const category = categoriesToShow.find((cat) => cat.type === filterId);
|
|
@@ -41483,7 +41664,6 @@ function HomeView({
|
|
|
41483
41664
|
factoryName = "Simba Beer - Line 1"
|
|
41484
41665
|
}) {
|
|
41485
41666
|
const [isHydrated, setIsHydrated] = React23.useState(false);
|
|
41486
|
-
const [selectedLineId, setSelectedLineId] = React23.useState(factoryViewId);
|
|
41487
41667
|
const [isChangingFilter, setIsChangingFilter] = React23.useState(false);
|
|
41488
41668
|
const [errorMessage, setErrorMessage] = React23.useState(null);
|
|
41489
41669
|
const [displayNamesInitialized, setDisplayNamesInitialized] = React23.useState(false);
|
|
@@ -41500,9 +41680,36 @@ function HomeView({
|
|
|
41500
41680
|
}
|
|
41501
41681
|
return [factoryViewId, ...allLineIds];
|
|
41502
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
|
+
});
|
|
41503
41701
|
React23.useEffect(() => {
|
|
41504
41702
|
if (user) {
|
|
41505
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
|
+
}
|
|
41506
41713
|
setSelectedLineId(allLineIds[0]);
|
|
41507
41714
|
}
|
|
41508
41715
|
}
|
|
@@ -41537,11 +41744,12 @@ function HomeView({
|
|
|
41537
41744
|
};
|
|
41538
41745
|
initDisplayNames();
|
|
41539
41746
|
}, [selectedLineId, factoryViewId, allLineIds]);
|
|
41747
|
+
const displayNameLineId = selectedLineId === factoryViewId ? void 0 : selectedLineId;
|
|
41540
41748
|
const {
|
|
41541
41749
|
displayNames: workspaceDisplayNames,
|
|
41542
41750
|
loading: displayNamesLoading,
|
|
41543
41751
|
error: displayNamesError
|
|
41544
|
-
} = useWorkspaceDisplayNames(
|
|
41752
|
+
} = useWorkspaceDisplayNames(displayNameLineId, void 0);
|
|
41545
41753
|
React23.useCallback(() => {
|
|
41546
41754
|
console.log("Refetching KPIs after line metrics update");
|
|
41547
41755
|
}, []);
|
|
@@ -41582,6 +41790,12 @@ function HomeView({
|
|
|
41582
41790
|
}
|
|
41583
41791
|
return allActiveBreaks.filter((breakItem) => breakItem.lineId === selectedLineId);
|
|
41584
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]);
|
|
41585
41799
|
const showBottleneckNotification = React23.useCallback(async (bottleneck) => {
|
|
41586
41800
|
try {
|
|
41587
41801
|
console.log("\u{1F514} [Notification] Raw bottleneck data:", bottleneck);
|
|
@@ -41880,7 +42094,12 @@ function HomeView({
|
|
|
41880
42094
|
const handleLineChange = React23.useCallback((value) => {
|
|
41881
42095
|
setIsChangingFilter(true);
|
|
41882
42096
|
setSelectedLineId(value);
|
|
41883
|
-
|
|
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]);
|
|
41884
42103
|
React23.useEffect(() => {
|
|
41885
42104
|
if (!metricsLoading && !kpisLoading && isChangingFilter) {
|
|
41886
42105
|
if (workspaceMetrics.length > 0 || selectedLineId === factoryViewId) {
|
|
@@ -41905,7 +42124,7 @@ function HomeView({
|
|
|
41905
42124
|
/* @__PURE__ */ jsxRuntime.jsx(SelectContent, { className: "z-50 bg-white shadow-lg border border-gray-200 rounded-md text-xs sm:text-sm", children: availableLineIds.map((id3) => /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: id3, children: lineNames[id3] || (id3 === factoryViewId ? "All Lines" : `Line ${id3.substring(0, 4)}`) }, id3)) })
|
|
41906
42125
|
] });
|
|
41907
42126
|
}, [availableLineIds, handleLineChange, selectedLineId, lineNames, factoryViewId, allLineIds.length]);
|
|
41908
|
-
const isInitialLoading = !isHydrated || displayNamesLoading || !displayNamesInitialized
|
|
42127
|
+
const isInitialLoading = !isHydrated || displayNamesLoading || !displayNamesInitialized;
|
|
41909
42128
|
const isDataLoading = metricsLoading || kpisLoading;
|
|
41910
42129
|
if (isInitialLoading) {
|
|
41911
42130
|
return /* @__PURE__ */ jsxRuntime.jsx(LoadingPageCmp, { message: "Loading Dashboard..." });
|
|
@@ -41993,7 +42212,8 @@ function HomeView({
|
|
|
41993
42212
|
{
|
|
41994
42213
|
activeBreaks,
|
|
41995
42214
|
lineNames,
|
|
41996
|
-
isVisible: !breaksLoading && !breaksError
|
|
42215
|
+
isVisible: !breaksLoading && !breaksError && !breakNotificationsDismissed,
|
|
42216
|
+
onDismiss: () => setBreakNotificationsDismissed(true)
|
|
41997
42217
|
}
|
|
41998
42218
|
),
|
|
41999
42219
|
/* @__PURE__ */ jsxRuntime.jsx(
|