This is an automated email from the ASF dual-hosted git repository.

michaelsmolina pushed a commit to branch 4.0
in repository https://gitbox.apache.org/repos/asf/superset.git

commit ecc6ced4d40c930af04cba89e5da3159cfd7468b
Author: Ross Mabbett <[email protected]>
AuthorDate: Thu Apr 4 19:31:07 2024 -0400

    fix(Dashboard): Add border to row when hovering HoverMenu in edit mode 
(#27593)
    
    (cherry picked from commit 265390c2436e9d03a0bd9c697961930205bcdc19)
---
 .../components/DashboardBuilder/DashboardBuilder.tsx  |  5 +++++
 .../src/dashboard/components/gridComponents/Row.jsx   | 16 ++++++++++++++--
 .../src/dashboard/components/menu/HoverMenu.test.tsx  | 16 +++++++++++++++-
 .../src/dashboard/components/menu/HoverMenu.tsx       | 19 +++++++++++++++++++
 4 files changed, 53 insertions(+), 3 deletions(-)

diff --git 
a/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx
 
b/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx
index e86d924b21..ba21420394 100644
--- 
a/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx
+++ 
b/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx
@@ -186,6 +186,11 @@ const DashboardContentWrapper = styled.div`
         pointer-events: none;
       }
 
+      .grid-row.grid-row--hovered:after,
+      .dashboard-component-tabs > .grid-row--hovered:after {
+        border: 2px dashed ${theme.colors.primary.base};
+      }
+
       .resizable-container {
         & .dashboard-component-chart-holder {
           .dashboard-chart {
diff --git a/superset-frontend/src/dashboard/components/gridComponents/Row.jsx 
b/superset-frontend/src/dashboard/components/gridComponents/Row.jsx
index 95560e3b59..b6dc042a2b 100644
--- a/superset-frontend/src/dashboard/components/gridComponents/Row.jsx
+++ b/superset-frontend/src/dashboard/components/gridComponents/Row.jsx
@@ -135,6 +135,7 @@ class Row extends React.PureComponent {
     this.state = {
       isFocused: false,
       isInView: false,
+      hoverMenuHovered: false,
     };
     this.handleDeleteComponent = this.handleDeleteComponent.bind(this);
     this.handleUpdateMeta = this.handleUpdateMeta.bind(this);
@@ -143,6 +144,7 @@ class Row extends React.PureComponent {
       'background',
     );
     this.handleChangeFocus = this.handleChangeFocus.bind(this);
+    this.handleMenuHover = this.handleMenuHover.bind(this);
     this.setVerticalEmptyContainerHeight = debounce(
       this.setVerticalEmptyContainerHeight.bind(this),
       FAST_DEBOUNCE,
@@ -235,6 +237,11 @@ class Row extends React.PureComponent {
     deleteComponent(component.id, parentId);
   }
 
+  handleMenuHover = hovered => {
+    const { isHovered } = hovered;
+    this.setState(() => ({ hoverMenuHovered: isHovered }));
+  };
+
   render() {
     const {
       component: rowComponent,
@@ -252,7 +259,7 @@ class Row extends React.PureComponent {
       onChangeTab,
       isComponentVisible,
     } = this.props;
-    const { containerHeight } = this.state;
+    const { containerHeight, hoverMenuHovered } = this.state;
 
     const rowItems = rowComponent.children || [];
 
@@ -287,7 +294,11 @@ class Row extends React.PureComponent {
             editMode={editMode}
           >
             {editMode && (
-              <HoverMenu innerRef={dragSourceRef} position="left">
+              <HoverMenu
+                onHover={this.handleMenuHover}
+                innerRef={dragSourceRef}
+                position="left"
+              >
                 <DragHandle position="left" />
                 <DeleteComponentButton onDelete={this.handleDeleteComponent} />
                 <IconButton
@@ -300,6 +311,7 @@ class Row extends React.PureComponent {
               className={cx(
                 'grid-row',
                 rowItems.length === 0 && 'grid-row--empty',
+                hoverMenuHovered && 'grid-row--hovered',
                 backgroundStyle.className,
               )}
               data-test={`grid-row-${backgroundStyle.className}`}
diff --git a/superset-frontend/src/dashboard/components/menu/HoverMenu.test.tsx 
b/superset-frontend/src/dashboard/components/menu/HoverMenu.test.tsx
index adf34938f5..5b7a64e64f 100644
--- a/superset-frontend/src/dashboard/components/menu/HoverMenu.test.tsx
+++ b/superset-frontend/src/dashboard/components/menu/HoverMenu.test.tsx
@@ -17,7 +17,8 @@
  * under the License.
  */
 import React from 'react';
-import { render } from 'spec/helpers/testing-library';
+import { render, screen } from 'spec/helpers/testing-library';
+import userEvent from '@testing-library/user-event';
 
 import HoverMenu from 'src/dashboard/components/menu/HoverMenu';
 
@@ -25,3 +26,16 @@ test('should render a div.hover-menu', () => {
   const { container } = render(<HoverMenu />);
   expect(container.querySelector('.hover-menu')).toBeInTheDocument();
 });
+
+test('should call onHover when mouse enters and leaves', () => {
+  const onHover = jest.fn();
+  render(<HoverMenu onHover={onHover} />);
+
+  const hoverMenu = screen.getByTestId('hover-menu');
+
+  userEvent.hover(hoverMenu);
+  expect(onHover).toBeCalledWith({ isHovered: true });
+
+  userEvent.unhover(hoverMenu);
+  expect(onHover).toBeCalledWith({ isHovered: false });
+});
diff --git a/superset-frontend/src/dashboard/components/menu/HoverMenu.tsx 
b/superset-frontend/src/dashboard/components/menu/HoverMenu.tsx
index 5fbc37cbbf..43d7683ce3 100644
--- a/superset-frontend/src/dashboard/components/menu/HoverMenu.tsx
+++ b/superset-frontend/src/dashboard/components/menu/HoverMenu.tsx
@@ -1,3 +1,4 @@
+/* eslint-disable react/no-unused-state */
 /**
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -24,6 +25,7 @@ interface HoverMenuProps {
   position: 'left' | 'top';
   innerRef: RefObject<HTMLDivElement>;
   children: React.ReactNode;
+  onHover?: (data: { isHovered: boolean }) => void;
 }
 
 const HoverStyleOverrides = styled.div`
@@ -70,6 +72,20 @@ export default class HoverMenu extends 
React.PureComponent<HoverMenuProps> {
     children: null,
   };
 
+  handleMouseEnter = () => {
+    const { onHover } = this.props;
+    if (onHover) {
+      onHover({ isHovered: true });
+    }
+  };
+
+  handleMouseLeave = () => {
+    const { onHover } = this.props;
+    if (onHover) {
+      onHover({ isHovered: false });
+    }
+  };
+
   render() {
     const { innerRef, position, children } = this.props;
     return (
@@ -81,6 +97,9 @@ export default class HoverMenu extends 
React.PureComponent<HoverMenuProps> {
             position === 'left' && 'hover-menu--left',
             position === 'top' && 'hover-menu--top',
           )}
+          onMouseEnter={this.handleMouseEnter}
+          onMouseLeave={this.handleMouseLeave}
+          data-test="hover-menu"
         >
           {children}
         </div>

Reply via email to