From 75e2c50b0146b04077374f467ec6686401045cf5 Mon Sep 17 00:00:00 2001
From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com>
Date: Mon, 26 Jan 2026 07:05:48 +0100
Subject: [PATCH 01/11] fix
---
.../ContextMenu/ContextMenu.react.js | 4 +-
.../Data/Browser/DataBrowser.react.js | 67 +++++++++++++++++--
2 files changed, 66 insertions(+), 5 deletions(-)
diff --git a/src/components/ContextMenu/ContextMenu.react.js b/src/components/ContextMenu/ContextMenu.react.js
index 23e2e10045..385bbdff24 100644
--- a/src/components/ContextMenu/ContextMenu.react.js
+++ b/src/components/ContextMenu/ContextMenu.react.js
@@ -156,7 +156,7 @@ const MenuSection = ({ level, items, path, setPath, hide, hoveredItemOffset }) =
);
};
-const ContextMenu = ({ x, y, items }) => {
+const ContextMenu = ({ x, y, items, onHide }) => {
const [path, setPath] = useState([0]);
// Track the pixel offset of the hovered item for each level
const [hoveredOffsets, setHoveredOffsets] = useState([0]);
@@ -171,6 +171,7 @@ const ContextMenu = ({ x, y, items }) => {
setVisible(false);
setPath([0]);
setHoveredOffsets([0]);
+ onHide?.();
};
// Combined setter that updates both path and offsets
@@ -235,6 +236,7 @@ ContextMenu.propTypes = {
x: PropTypes.number.isRequired.describe('X context menu position.'),
y: PropTypes.number.isRequired.describe('Y context menu position.'),
items: PropTypes.array.isRequired.describe('Array with tree representation of context menu items.'),
+ onHide: PropTypes.func.describe('Callback when context menu is hidden.'),
};
export default ContextMenu;
diff --git a/src/dashboard/Data/Browser/DataBrowser.react.js b/src/dashboard/Data/Browser/DataBrowser.react.js
index 3168e28c75..7cf63842ab 100644
--- a/src/dashboard/Data/Browser/DataBrowser.react.js
+++ b/src/dashboard/Data/Browser/DataBrowser.react.js
@@ -190,6 +190,7 @@ export default class DataBrowser extends React.Component {
recordingScrollStart: null, // Timestamp when scroll recording started
recordingScrollEnd: null, // Timestamp when scrolling ended (before Option key release)
recordedScrollDelta: 0, // Accumulated scroll delta during recording
+ nativeContextMenuOpen: false, // Whether the browser's native context menu is open
};
this.handleResizeDiv = this.handleResizeDiv.bind(this);
@@ -245,6 +246,8 @@ export default class DataBrowser extends React.Component {
this.stopAutoScroll = this.stopAutoScroll.bind(this);
this.performAutoScrollStep = this.performAutoScrollStep.bind(this);
this.pauseAutoScrollWithResume = this.pauseAutoScrollWithResume.bind(this);
+ this.handleNativeContextMenu = this.handleNativeContextMenu.bind(this);
+ this.handleNativeContextMenuClose = this.handleNativeContextMenuClose.bind(this);
this.saveOrderTimeout = null;
this.aggregationPanelRef = React.createRef();
this.autoScrollIntervalId = null;
@@ -333,6 +336,12 @@ export default class DataBrowser extends React.Component {
// Auto-scroll event listeners
document.body.addEventListener('keydown', this.handleAutoScrollKeyDown);
document.body.addEventListener('keyup', this.handleAutoScrollKeyUp);
+ // Native context menu detection for auto-scroll pause
+ // Use capture phase to ensure we detect the event before the menu handles it
+ document.addEventListener('contextmenu', this.handleNativeContextMenu, true);
+ // Listen for click (fires after menu closes) and keydown (Escape closes menu)
+ document.addEventListener('click', this.handleNativeContextMenuClose, true);
+ document.addEventListener('keydown', this.handleNativeContextMenuClose, true);
// Load keyboard shortcuts from server
try {
@@ -371,6 +380,9 @@ export default class DataBrowser extends React.Component {
// Auto-scroll cleanup
document.body.removeEventListener('keydown', this.handleAutoScrollKeyDown);
document.body.removeEventListener('keyup', this.handleAutoScrollKeyUp);
+ document.removeEventListener('contextmenu', this.handleNativeContextMenu, true);
+ document.removeEventListener('click', this.handleNativeContextMenuClose, true);
+ document.removeEventListener('keydown', this.handleNativeContextMenuClose, true);
if (this.autoScrollTimeoutId) {
clearTimeout(this.autoScrollTimeoutId);
}
@@ -1385,6 +1397,34 @@ export default class DataBrowser extends React.Component {
});
}
+ /**
+ * Checks if auto-scroll should be blocked due to user interactions.
+ * Auto-scroll pauses when:
+ * - A modal is displayed (script confirmation, graph dialog)
+ * - A context menu is displayed (custom or native browser menu)
+ * - The user is editing a cell in the databrowser table
+ * - Manual scroll pause is active
+ */
+ isAutoScrollBlocked() {
+ const {
+ autoScrollPaused,
+ editing,
+ contextMenuItems,
+ showScriptConfirmationDialog,
+ showGraphDialog,
+ nativeContextMenuOpen,
+ } = this.state;
+
+ return (
+ autoScrollPaused ||
+ editing ||
+ (contextMenuItems && contextMenuItems.length > 0) ||
+ showScriptConfirmationDialog ||
+ showGraphDialog ||
+ nativeContextMenuOpen
+ );
+ }
+
toggleAutoScroll() {
this.setState(prevState => {
const newAutoScroll = !prevState.autoScrollEnabled;
@@ -1479,6 +1519,24 @@ export default class DataBrowser extends React.Component {
}, 500);
}
+ handleNativeContextMenu() {
+ // Pause auto-scroll when native browser context menu is opened
+ if (this.state.isAutoScrolling && !this.state.nativeContextMenuOpen) {
+ this.setState({ nativeContextMenuOpen: true });
+ }
+ }
+
+ handleNativeContextMenuClose(e) {
+ // Resume auto-scroll when native browser context menu is closed
+ // For keydown events, only handle Escape key
+ if (e.type === 'keydown' && e.key !== 'Escape') {
+ return;
+ }
+ if (this.state.nativeContextMenuOpen) {
+ this.setState({ nativeContextMenuOpen: false });
+ }
+ }
+
startAutoScroll() {
if (this.state.isAutoScrolling) {
return;
@@ -1517,8 +1575,8 @@ export default class DataBrowser extends React.Component {
return;
}
- if (this.state.autoScrollPaused) {
- // When paused, keep checking but don't scroll
+ if (this.isAutoScrollBlocked()) {
+ // When blocked (modal, context menu, editing, or manual pause), keep checking but don't scroll
this.autoScrollTimeoutId = setTimeout(() => {
this.performAutoScrollStep();
}, 100);
@@ -1554,8 +1612,8 @@ export default class DataBrowser extends React.Component {
}
const animateScroll = (currentTime) => {
- if (!this.state.isAutoScrolling || this.state.autoScrollPaused) {
- // If stopped or paused during animation, schedule next check
+ if (!this.state.isAutoScrolling || this.isAutoScrollBlocked()) {
+ // If stopped or blocked during animation, schedule next check
this.autoScrollTimeoutId = setTimeout(() => {
this.performAutoScrollStep();
}, 100);
@@ -2583,6 +2641,7 @@ export default class DataBrowser extends React.Component {
x={this.state.contextMenuX}
y={this.state.contextMenuY}
items={this.state.contextMenuItems}
+ onHide={() => this.setState({ contextMenuX: null, contextMenuY: null, contextMenuItems: null })}
/>
)}
{this.state.showScriptConfirmationDialog && (
From 578489d98c808e8ef31c2ed0f8c71c5e4f8627f4 Mon Sep 17 00:00:00 2001
From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com>
Date: Mon, 26 Jan 2026 07:29:02 +0100
Subject: [PATCH 02/11] fix
---
.../Data/Browser/DataBrowser.react.js | 54 +++++++++++++++----
1 file changed, 43 insertions(+), 11 deletions(-)
diff --git a/src/dashboard/Data/Browser/DataBrowser.react.js b/src/dashboard/Data/Browser/DataBrowser.react.js
index 7cf63842ab..487536bdfd 100644
--- a/src/dashboard/Data/Browser/DataBrowser.react.js
+++ b/src/dashboard/Data/Browser/DataBrowser.react.js
@@ -339,9 +339,15 @@ export default class DataBrowser extends React.Component {
// Native context menu detection for auto-scroll pause
// Use capture phase to ensure we detect the event before the menu handles it
document.addEventListener('contextmenu', this.handleNativeContextMenu, true);
- // Listen for click (fires after menu closes) and keydown (Escape closes menu)
- document.addEventListener('click', this.handleNativeContextMenuClose, true);
- document.addEventListener('keydown', this.handleNativeContextMenuClose, true);
+ // Listen for events that indicate the context menu was closed:
+ // - mousemove: user moved mouse after menu closed (most reliable)
+ // - keydown: Escape key closes the menu
+ // - blur: switching windows/tabs closes the menu
+ // NOTE: click/mousedown don't fire while native context menu is open
+ // NOTE: scroll is not used because auto-scroll itself triggers it
+ window.addEventListener('mousemove', this.handleNativeContextMenuClose);
+ window.addEventListener('keydown', this.handleNativeContextMenuClose, true);
+ window.addEventListener('blur', this.handleNativeContextMenuClose);
// Load keyboard shortcuts from server
try {
@@ -381,8 +387,9 @@ export default class DataBrowser extends React.Component {
document.body.removeEventListener('keydown', this.handleAutoScrollKeyDown);
document.body.removeEventListener('keyup', this.handleAutoScrollKeyUp);
document.removeEventListener('contextmenu', this.handleNativeContextMenu, true);
- document.removeEventListener('click', this.handleNativeContextMenuClose, true);
- document.removeEventListener('keydown', this.handleNativeContextMenuClose, true);
+ window.removeEventListener('mousemove', this.handleNativeContextMenuClose);
+ window.removeEventListener('keydown', this.handleNativeContextMenuClose, true);
+ window.removeEventListener('blur', this.handleNativeContextMenuClose);
if (this.autoScrollTimeoutId) {
clearTimeout(this.autoScrollTimeoutId);
}
@@ -1415,7 +1422,7 @@ export default class DataBrowser extends React.Component {
nativeContextMenuOpen,
} = this.state;
- return (
+ const blocked = (
autoScrollPaused ||
editing ||
(contextMenuItems && contextMenuItems.length > 0) ||
@@ -1423,6 +1430,19 @@ export default class DataBrowser extends React.Component {
showGraphDialog ||
nativeContextMenuOpen
);
+
+ if (blocked) {
+ console.log('[AutoScroll] isAutoScrollBlocked = true', {
+ autoScrollPaused,
+ editing,
+ contextMenuItems: contextMenuItems?.length || 0,
+ showScriptConfirmationDialog,
+ showGraphDialog,
+ nativeContextMenuOpen,
+ });
+ }
+
+ return blocked;
}
toggleAutoScroll() {
@@ -1520,21 +1540,33 @@ export default class DataBrowser extends React.Component {
}
handleNativeContextMenu() {
+ console.log('[AutoScroll] handleNativeContextMenu called', {
+ isAutoScrolling: this.state.isAutoScrolling,
+ nativeContextMenuOpen: this.state.nativeContextMenuOpen,
+ });
// Pause auto-scroll when native browser context menu is opened
if (this.state.isAutoScrolling && !this.state.nativeContextMenuOpen) {
+ console.log('[AutoScroll] Setting nativeContextMenuOpen: true');
this.setState({ nativeContextMenuOpen: true });
}
}
handleNativeContextMenuClose(e) {
- // Resume auto-scroll when native browser context menu is closed
- // For keydown events, only handle Escape key
- if (e.type === 'keydown' && e.key !== 'Escape') {
+ // Only process if native context menu is open
+ if (!this.state.nativeContextMenuOpen) {
return;
}
- if (this.state.nativeContextMenuOpen) {
- this.setState({ nativeContextMenuOpen: false });
+
+ // For keydown events, only handle Escape key
+ if (e && e.type === 'keydown' && e.key !== 'Escape') {
+ return;
}
+
+ // mousemove, Escape key, or blur all indicate the menu is closed
+ console.log('[AutoScroll] handleNativeContextMenuClose - clearing nativeContextMenuOpen', {
+ eventType: e?.type,
+ });
+ this.setState({ nativeContextMenuOpen: false });
}
startAutoScroll() {
From 5f786a10d5757d848f5bec07ad5886c87a02ecba Mon Sep 17 00:00:00 2001
From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com>
Date: Mon, 26 Jan 2026 07:44:13 +0100
Subject: [PATCH 03/11] scroll pause
---
README.md | 6 +--
.../Data/Browser/DataBrowser.react.js | 39 +++++--------------
2 files changed, 12 insertions(+), 33 deletions(-)
diff --git a/README.md b/README.md
index 3a5599cc33..59a858c3e0 100644
--- a/README.md
+++ b/README.md
@@ -1453,14 +1453,14 @@ The info panel supports automatic scrolling, which is useful for hands-free brow
**How to use:**
1. Enable auto-scroll via *Settings > Info Panel > Auto-scroll*.
-2. Hold the **Option** (Alt) key while scrolling in the panel to record the scroll amount.
-3. Release the Option key after pausing for the desired interval between scrolls.
+2. Hold the **Command** (⌘) key while scrolling in the panel to record the scroll amount.
+3. Release the Command key after pausing for the desired interval between scrolls.
4. Auto-scrolling begins automatically, repeating the recorded scroll amount and pause interval.
**Controls:**
- **Escape key**: Stop auto-scrolling.
-- **Option key**: Stop current auto-scroll and start recording a new scroll pattern.
+- **Command key**: Stop current auto-scroll and start recording a new scroll pattern.
- **Manual scroll**: Temporarily pauses auto-scrolling, which resumes after inactivity.
- **Auto-scroll button**: Click the highlighted "Auto-scroll" button in the toolbar to stop.
diff --git a/src/dashboard/Data/Browser/DataBrowser.react.js b/src/dashboard/Data/Browser/DataBrowser.react.js
index 487536bdfd..89a2dee5af 100644
--- a/src/dashboard/Data/Browser/DataBrowser.react.js
+++ b/src/dashboard/Data/Browser/DataBrowser.react.js
@@ -183,12 +183,12 @@ export default class DataBrowser extends React.Component {
// Auto-scroll feature state
autoScrollEnabled: storedAutoScroll, // Whether auto-scroll feature is enabled (menu setting)
isAutoScrolling: false, // Whether auto-scroll is currently active
- isRecordingAutoScroll: false, // Whether we're recording (Option key held during scroll)
+ isRecordingAutoScroll: false, // Whether we're recording (Command key held during scroll)
autoScrollAmount: 0, // The registered scroll amount (pixels)
autoScrollDelay: 1000, // The registered wait time (ms)
autoScrollPaused: false, // Whether auto-scroll is currently paused
recordingScrollStart: null, // Timestamp when scroll recording started
- recordingScrollEnd: null, // Timestamp when scrolling ended (before Option key release)
+ recordingScrollEnd: null, // Timestamp when scrolling ended (before Command key release)
recordedScrollDelta: 0, // Accumulated scroll delta during recording
nativeContextMenuOpen: false, // Whether the browser's native context menu is open
};
@@ -1422,7 +1422,7 @@ export default class DataBrowser extends React.Component {
nativeContextMenuOpen,
} = this.state;
- const blocked = (
+ return (
autoScrollPaused ||
editing ||
(contextMenuItems && contextMenuItems.length > 0) ||
@@ -1430,19 +1430,6 @@ export default class DataBrowser extends React.Component {
showGraphDialog ||
nativeContextMenuOpen
);
-
- if (blocked) {
- console.log('[AutoScroll] isAutoScrollBlocked = true', {
- autoScrollPaused,
- editing,
- contextMenuItems: contextMenuItems?.length || 0,
- showScriptConfirmationDialog,
- showGraphDialog,
- nativeContextMenuOpen,
- });
- }
-
- return blocked;
}
toggleAutoScroll() {
@@ -1458,9 +1445,9 @@ export default class DataBrowser extends React.Component {
}
handleAutoScrollKeyDown(e) {
- // Option/Alt key = keyCode 18
+ // Command/Meta key = keyCode 91 (left) or 93 (right)
// Only detect when panels are visible and auto-scroll is enabled
- if (e.keyCode === 18 && this.state.autoScrollEnabled && this.state.isPanelVisible && !this.state.isRecordingAutoScroll) {
+ if ((e.keyCode === 91 || e.keyCode === 93) && this.state.autoScrollEnabled && this.state.isPanelVisible && !this.state.isRecordingAutoScroll) {
// Stop any existing auto-scroll first
if (this.state.isAutoScrolling) {
this.stopAutoScroll();
@@ -1475,8 +1462,8 @@ export default class DataBrowser extends React.Component {
}
handleAutoScrollKeyUp(e) {
- // Option/Alt key = keyCode 18
- if (e.keyCode === 18 && this.state.isRecordingAutoScroll) {
+ // Command/Meta key = keyCode 91 (left) or 93 (right)
+ if ((e.keyCode === 91 || e.keyCode === 93) && this.state.isRecordingAutoScroll) {
const { recordedScrollDelta, recordingScrollStart, recordingScrollEnd } = this.state;
// Only start auto-scroll if we actually recorded some scrolling
@@ -1531,22 +1518,17 @@ export default class DataBrowser extends React.Component {
this.setState({ autoScrollPaused: true });
}
- // Schedule resume after 500ms of inactivity
+ // Schedule resume after 1000ms of inactivity
this.autoScrollResumeTimeoutId = setTimeout(() => {
if (this.state.isAutoScrolling && this.state.autoScrollPaused) {
this.setState({ autoScrollPaused: false });
}
- }, 500);
+ }, 1000);
}
handleNativeContextMenu() {
- console.log('[AutoScroll] handleNativeContextMenu called', {
- isAutoScrolling: this.state.isAutoScrolling,
- nativeContextMenuOpen: this.state.nativeContextMenuOpen,
- });
// Pause auto-scroll when native browser context menu is opened
if (this.state.isAutoScrolling && !this.state.nativeContextMenuOpen) {
- console.log('[AutoScroll] Setting nativeContextMenuOpen: true');
this.setState({ nativeContextMenuOpen: true });
}
}
@@ -1563,9 +1545,6 @@ export default class DataBrowser extends React.Component {
}
// mousemove, Escape key, or blur all indicate the menu is closed
- console.log('[AutoScroll] handleNativeContextMenuClose - clearing nativeContextMenuOpen', {
- eventType: e?.type,
- });
this.setState({ nativeContextMenuOpen: false });
}
From 975594aa918fc4d682a8225c589a09acfc848000 Mon Sep 17 00:00:00 2001
From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com>
Date: Mon, 26 Jan 2026 08:03:56 +0100
Subject: [PATCH 04/11] modal add entry
---
src/dashboard/Data/Browser/Browser.react.js | 3 ++-
src/dashboard/Data/Browser/DataBrowser.react.js | 6 +++++-
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/src/dashboard/Data/Browser/Browser.react.js b/src/dashboard/Data/Browser/Browser.react.js
index 93b6732434..80463c074c 100644
--- a/src/dashboard/Data/Browser/Browser.react.js
+++ b/src/dashboard/Data/Browser/Browser.react.js
@@ -2032,7 +2032,8 @@ class Browser extends DashboardView {
this.state.showCloneSelectedRowsDialog ||
this.state.showEditRowDialog ||
this.state.showPermissionsDialog ||
- this.state.showExportSelectedRowsDialog
+ this.state.showExportSelectedRowsDialog ||
+ this.state.showAddToConfigDialog
);
}
diff --git a/src/dashboard/Data/Browser/DataBrowser.react.js b/src/dashboard/Data/Browser/DataBrowser.react.js
index 89a2dee5af..8c3a26299a 100644
--- a/src/dashboard/Data/Browser/DataBrowser.react.js
+++ b/src/dashboard/Data/Browser/DataBrowser.react.js
@@ -1422,13 +1422,17 @@ export default class DataBrowser extends React.Component {
nativeContextMenuOpen,
} = this.state;
+ // disableKeyControls is true when parent Browser has a modal open
+ const { disableKeyControls } = this.props;
+
return (
autoScrollPaused ||
editing ||
(contextMenuItems && contextMenuItems.length > 0) ||
showScriptConfirmationDialog ||
showGraphDialog ||
- nativeContextMenuOpen
+ nativeContextMenuOpen ||
+ disableKeyControls
);
}
From 01671b70cd61904faf5eba03645055a7daf8b729 Mon Sep 17 00:00:00 2001
From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com>
Date: Mon, 26 Jan 2026 08:35:30 +0100
Subject: [PATCH 05/11] pause on header hover
---
.../Data/Browser/DataBrowser.react.js | 60 ++++++++++++++++++-
1 file changed, 58 insertions(+), 2 deletions(-)
diff --git a/src/dashboard/Data/Browser/DataBrowser.react.js b/src/dashboard/Data/Browser/DataBrowser.react.js
index 8c3a26299a..1ac49a3d42 100644
--- a/src/dashboard/Data/Browser/DataBrowser.react.js
+++ b/src/dashboard/Data/Browser/DataBrowser.react.js
@@ -191,6 +191,8 @@ export default class DataBrowser extends React.Component {
recordingScrollEnd: null, // Timestamp when scrolling ended (before Command key release)
recordedScrollDelta: 0, // Accumulated scroll delta during recording
nativeContextMenuOpen: false, // Whether the browser's native context menu is open
+ mouseOutsidePanel: true, // Whether the mouse is outside the AggregationPanel
+ mouseOverPanelHeader: false, // Whether the mouse is over the panel header row
};
this.handleResizeDiv = this.handleResizeDiv.bind(this);
@@ -248,12 +250,17 @@ export default class DataBrowser extends React.Component {
this.pauseAutoScrollWithResume = this.pauseAutoScrollWithResume.bind(this);
this.handleNativeContextMenu = this.handleNativeContextMenu.bind(this);
this.handleNativeContextMenuClose = this.handleNativeContextMenuClose.bind(this);
+ this.handlePanelMouseEnter = this.handlePanelMouseEnter.bind(this);
+ this.handlePanelMouseLeave = this.handlePanelMouseLeave.bind(this);
+ this.handlePanelHeaderMouseEnter = this.handlePanelHeaderMouseEnter.bind(this);
+ this.handlePanelHeaderMouseLeave = this.handlePanelHeaderMouseLeave.bind(this);
this.saveOrderTimeout = null;
this.aggregationPanelRef = React.createRef();
this.autoScrollIntervalId = null;
this.autoScrollTimeoutId = null;
this.autoScrollResumeTimeoutId = null;
this.autoScrollAnimationId = null;
+ this.panelHeaderLeaveTimeoutId = null;
this.panelColumnRefs = [];
this.activePanelIndex = -1;
this.isWheelScrolling = false;
@@ -399,6 +406,9 @@ export default class DataBrowser extends React.Component {
if (this.autoScrollAnimationId) {
cancelAnimationFrame(this.autoScrollAnimationId);
}
+ if (this.panelHeaderLeaveTimeoutId) {
+ clearTimeout(this.panelHeaderLeaveTimeoutId);
+ }
}
async componentDidUpdate(prevProps, prevState) {
@@ -1420,6 +1430,8 @@ export default class DataBrowser extends React.Component {
showScriptConfirmationDialog,
showGraphDialog,
nativeContextMenuOpen,
+ mouseOutsidePanel,
+ mouseOverPanelHeader,
} = this.state;
// disableKeyControls is true when parent Browser has a modal open
@@ -1432,7 +1444,9 @@ export default class DataBrowser extends React.Component {
showScriptConfirmationDialog ||
showGraphDialog ||
nativeContextMenuOpen ||
- disableKeyControls
+ disableKeyControls ||
+ mouseOutsidePanel ||
+ mouseOverPanelHeader
);
}
@@ -1552,6 +1566,42 @@ export default class DataBrowser extends React.Component {
this.setState({ nativeContextMenuOpen: false });
}
+ handlePanelMouseEnter() {
+ if (this.state.mouseOutsidePanel) {
+ this.setState({ mouseOutsidePanel: false });
+ }
+ }
+
+ handlePanelMouseLeave() {
+ if (!this.state.mouseOutsidePanel) {
+ this.setState({ mouseOutsidePanel: true });
+ }
+ }
+
+ handlePanelHeaderMouseEnter() {
+ // Cancel any pending leave timeout
+ if (this.panelHeaderLeaveTimeoutId) {
+ clearTimeout(this.panelHeaderLeaveTimeoutId);
+ this.panelHeaderLeaveTimeoutId = null;
+ }
+ if (!this.state.mouseOverPanelHeader) {
+ this.setState({ mouseOverPanelHeader: true });
+ }
+ }
+
+ handlePanelHeaderMouseLeave() {
+ // Use a small delay to allow moving between adjacent headers without resuming scroll
+ if (this.panelHeaderLeaveTimeoutId) {
+ clearTimeout(this.panelHeaderLeaveTimeoutId);
+ }
+ this.panelHeaderLeaveTimeoutId = setTimeout(() => {
+ this.panelHeaderLeaveTimeoutId = null;
+ if (this.state.mouseOverPanelHeader) {
+ this.setState({ mouseOverPanelHeader: false });
+ }
+ }, 50);
+ }
+
startAutoScroll() {
if (this.state.isAutoScrolling) {
return;
@@ -2446,6 +2496,8 @@ export default class DataBrowser extends React.Component {
className={styles.aggregationPanelContainer}
ref={this.aggregationPanelRef}
onWheel={this.handleAutoScrollWheel}
+ onMouseEnter={this.handlePanelMouseEnter}
+ onMouseLeave={this.handlePanelMouseLeave}
>
{this.state.panelCount > 1 ? (
this.onMouseEnterPanelCheckBox(objectId)}
+ onMouseEnter={() => {
+ this.onMouseEnterPanelCheckBox(objectId);
+ this.handlePanelHeaderMouseEnter();
+ }}
+ onMouseLeave={this.handlePanelHeaderMouseLeave}
onContextMenu={(e) => {
e.preventDefault();
this.handlePanelHeaderContextMenu(e, objectId);
From cbb57aa7e358bf9baf1a39067e3fd6bce572ecfb Mon Sep 17 00:00:00 2001
From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com>
Date: Mon, 26 Jan 2026 08:45:17 +0100
Subject: [PATCH 06/11] hover menu
---
.../Data/Browser/BrowserToolbar.react.js | 22 +++++++++++++++++++
.../Data/Browser/DataBrowser.react.js | 22 +++++++++++++++++--
2 files changed, 42 insertions(+), 2 deletions(-)
diff --git a/src/dashboard/Data/Browser/BrowserToolbar.react.js b/src/dashboard/Data/Browser/BrowserToolbar.react.js
index 323de52e55..423973f6b5 100644
--- a/src/dashboard/Data/Browser/BrowserToolbar.react.js
+++ b/src/dashboard/Data/Browser/BrowserToolbar.react.js
@@ -98,6 +98,8 @@ const BrowserToolbar = ({
toggleShowPanelCheckbox,
autoScrollEnabled,
toggleAutoScroll,
+ autoScrollRequireHover,
+ toggleAutoScrollRequireHover,
isAutoScrolling,
stopAutoScroll,
toggleGraphPanel,
@@ -485,6 +487,7 @@ const BrowserToolbar = ({
toggleShowPanelCheckbox();
}}
/>
+