diff --git a/frontend/src/container/GridGraphLayout/Graph/Bar/index.tsx b/frontend/src/container/GridGraphLayout/Graph/Bar/index.tsx
deleted file mode 100644
index 7214d4839e..0000000000
--- a/frontend/src/container/GridGraphLayout/Graph/Bar/index.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-import {
- DeleteOutlined,
- EditFilled,
- FullscreenOutlined,
-} from '@ant-design/icons';
-import history from 'lib/history';
-import React from 'react';
-import { Widgets } from 'types/api/dashboard/getAll';
-
-import { Container } from './styles';
-
-function Bar({
- widget,
- onViewFullScreenHandler,
- onDeleteHandler,
-}: BarProps): JSX.Element {
- const onEditHandler = (): void => {
- const widgetId = widget.id;
- history.push(
- `${window.location.pathname}/new?widgetId=${widgetId}&graphType=${widget.panelTypes}`,
- );
- };
-
- return (
-
-
-
-
-
- );
-}
-
-interface BarProps {
- widget: Widgets;
- onViewFullScreenHandler: () => void;
- onDeleteHandler: () => void;
-}
-
-export default Bar;
diff --git a/frontend/src/container/GridGraphLayout/Graph/Bar/styles.ts b/frontend/src/container/GridGraphLayout/Graph/Bar/styles.ts
deleted file mode 100644
index ca8073a672..0000000000
--- a/frontend/src/container/GridGraphLayout/Graph/Bar/styles.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import styled from 'styled-components';
-
-export const Container = styled.div`
- height: 15%;
- align-items: center;
- justify-content: flex-end;
- display: flex;
- gap: 1rem;
- padding-right: 1rem;
- padding-left: 1rem;
- padding-top: 0.5rem;
- position: absolute;
- top: 0;
- right: 0;
-`;
diff --git a/frontend/src/container/GridGraphLayout/Graph/index.tsx b/frontend/src/container/GridGraphLayout/Graph/index.tsx
index 0447cfca94..eb1ed0e2d6 100644
--- a/frontend/src/container/GridGraphLayout/Graph/index.tsx
+++ b/frontend/src/container/GridGraphLayout/Graph/index.tsx
@@ -20,7 +20,7 @@ import AppActions from 'types/actions';
import { GlobalTime } from 'types/actions/globalTime';
import { Widgets } from 'types/api/dashboard/getAll';
-import Bar from './Bar';
+import WidgetHeader from '../WidgetHeader';
import FullView from './FullView';
import { ErrorContainer, FullViewContainer, Modal } from './styles';
@@ -37,6 +37,7 @@ function GridCardGraph({
error: false,
payload: undefined,
});
+ const [hovered, setHovered] = useState(false);
const [modal, setModal] = useState(false);
const { minTime, maxTime } = useSelector(
(state) => state.globalTime,
@@ -171,10 +172,12 @@ function GridCardGraph({
return (
<>
{getModals()}
- onToggleModal(setModal)}
+ onToggleModal(setDeletModal)}
+ onView={(): void => onToggleModal(setModal)}
+ onDelete={(): void => onToggleModal(setDeletModal)}
/>
{state.errorMessage}
@@ -187,11 +190,26 @@ function GridCardGraph({
}
return (
- <>
- onToggleModal(setModal)}
+ {
+ setHovered(true);
+ }}
+ onFocus={(): void => {
+ setHovered(true);
+ }}
+ onMouseOut={(): void => {
+ setHovered(false);
+ }}
+ onBlur={(): void => {
+ setHovered(false);
+ }}
+ >
+ onToggleModal(setDeletModal)}
+ onView={(): void => onToggleModal(setModal)}
+ onDelete={(): void => onToggleModal(setDeletModal)}
/>
{getModals()}
@@ -202,12 +220,12 @@ function GridCardGraph({
data: state.payload,
isStacked: widget.isStacked,
opacity: widget.opacity,
- title: widget.title,
+ title: ' ', // empty title to accommodate absolutely positioned widget header
name,
yAxisUnit,
}}
/>
- >
+
);
}
diff --git a/frontend/src/container/GridGraphLayout/WidgetHeader/index.tsx b/frontend/src/container/GridGraphLayout/WidgetHeader/index.tsx
new file mode 100644
index 0000000000..ce9478d264
--- /dev/null
+++ b/frontend/src/container/GridGraphLayout/WidgetHeader/index.tsx
@@ -0,0 +1,109 @@
+import {
+ DeleteOutlined,
+ DownOutlined,
+ EditFilled,
+ FullscreenOutlined,
+} from '@ant-design/icons';
+import { Dropdown, Menu, Typography } from 'antd';
+import history from 'lib/history';
+import React, { useState } from 'react';
+import { Widgets } from 'types/api/dashboard/getAll';
+
+import {
+ ArrowContainer,
+ HeaderContainer,
+ HeaderContentContainer,
+ MenuItemContainer,
+} from './styles';
+
+type TWidgetOptions = 'view' | 'edit' | 'delete' | string;
+interface IWidgetHeaderProps {
+ title: string;
+ widget: Widgets;
+ onView: VoidFunction;
+ onDelete: VoidFunction;
+ parentHover: boolean;
+}
+function WidgetHeader({
+ title,
+ widget,
+ onView,
+ onDelete,
+ parentHover,
+}: IWidgetHeaderProps): JSX.Element {
+ const [localHover, setLocalHover] = useState(false);
+
+ const onEditHandler = (): void => {
+ const widgetId = widget.id;
+ history.push(
+ `${window.location.pathname}/new?widgetId=${widgetId}&graphType=${widget.panelTypes}`,
+ );
+ };
+
+ const keyMethodMapping: {
+ [K in TWidgetOptions]: { key: TWidgetOptions; method: VoidFunction };
+ } = {
+ view: {
+ key: 'view',
+ method: onView,
+ },
+ edit: {
+ key: 'edit',
+ method: onEditHandler,
+ },
+ delete: {
+ key: 'delete',
+ method: onDelete,
+ },
+ };
+ const onMenuItemSelectHandler = ({ key }: { key: TWidgetOptions }): void => {
+ keyMethodMapping[key]?.method();
+ };
+
+ const menu = (
+
+ );
+
+ return (
+
+ setLocalHover(true)}
+ onMouseOut={(): void => setLocalHover(false)}
+ hover={localHover}
+ >
+ e.preventDefault()}>
+
+ {title}
+
+
+
+
+
+
+
+ );
+}
+
+export default WidgetHeader;
diff --git a/frontend/src/container/GridGraphLayout/WidgetHeader/styles.ts b/frontend/src/container/GridGraphLayout/WidgetHeader/styles.ts
new file mode 100644
index 0000000000..9600a6bcb4
--- /dev/null
+++ b/frontend/src/container/GridGraphLayout/WidgetHeader/styles.ts
@@ -0,0 +1,30 @@
+import { grey } from '@ant-design/colors';
+import styled from 'styled-components';
+
+export const MenuItemContainer = styled.div`
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+`;
+
+export const HeaderContainer = styled.div<{ hover: boolean }>`
+ width: 100%;
+ text-align: center;
+ background: ${({ hover }): string => (hover ? `${grey[0]}66` : 'inherit')};
+ padding: 0.25rem 0;
+ font-size: 0.8rem;
+ cursor: all-scroll;
+ position: absolute;
+`;
+
+export const HeaderContentContainer = styled.span`
+ cursor: pointer;
+ position: relative;
+ text-align: center;
+`;
+
+export const ArrowContainer = styled.span<{ hover: boolean }>`
+ visibility: ${({ hover }): string => (hover ? 'visible' : 'hidden')};
+ position: absolute;
+ right: -1rem;
+`;