feat: new dashboard widget's option selection (#982)

* feat: new dashboard widget's option selection

* fix: overflowing legend

* feat: delete menu item is of type danger

* feat: added keyboard events onFocus and onBlur
This commit is contained in:
Pranshu Chittora 2022-04-19 10:57:56 +05:30 committed by GitHub
parent 9a6bcaadf8
commit 3c2173de9e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 167 additions and 64 deletions

View File

@ -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 (
<Container>
<FullscreenOutlined onClick={onViewFullScreenHandler} />
<EditFilled onClick={onEditHandler} />
<DeleteOutlined onClick={onDeleteHandler} />
</Container>
);
}
interface BarProps {
widget: Widgets;
onViewFullScreenHandler: () => void;
onDeleteHandler: () => void;
}
export default Bar;

View File

@ -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;
`;

View File

@ -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<AppState, GlobalTime>(
(state) => state.globalTime,
@ -171,10 +172,12 @@ function GridCardGraph({
return (
<>
{getModals()}
<Bar
onViewFullScreenHandler={(): void => onToggleModal(setModal)}
<WidgetHeader
parentHover={hovered}
title={widget?.title}
widget={widget}
onDeleteHandler={(): void => onToggleModal(setDeletModal)}
onView={(): void => onToggleModal(setModal)}
onDelete={(): void => onToggleModal(setDeletModal)}
/>
<ErrorContainer>{state.errorMessage}</ErrorContainer>
@ -187,11 +190,26 @@ function GridCardGraph({
}
return (
<>
<Bar
onViewFullScreenHandler={(): void => onToggleModal(setModal)}
<span
onMouseOver={(): void => {
setHovered(true);
}}
onFocus={(): void => {
setHovered(true);
}}
onMouseOut={(): void => {
setHovered(false);
}}
onBlur={(): void => {
setHovered(false);
}}
>
<WidgetHeader
parentHover={hovered}
title={widget.title}
widget={widget}
onDeleteHandler={(): void => 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,
}}
/>
</>
</span>
);
}

View File

@ -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 = (
<Menu onClick={onMenuItemSelectHandler}>
<Menu.Item key={keyMethodMapping.view.key}>
<MenuItemContainer>
<span>View</span> <FullscreenOutlined />
</MenuItemContainer>
</Menu.Item>
<Menu.Item key={keyMethodMapping.edit.key}>
<MenuItemContainer>
<span>Edit</span> <EditFilled />
</MenuItemContainer>
</Menu.Item>
<Menu.Divider />
<Menu.Item key={keyMethodMapping.delete.key} danger>
<MenuItemContainer>
<span>Delete</span> <DeleteOutlined />
</MenuItemContainer>
</Menu.Item>
</Menu>
);
return (
<Dropdown
overlay={menu}
trigger={['click']}
overlayStyle={{ minWidth: 100 }}
placement="bottomCenter"
>
<HeaderContainer
onMouseOver={(): void => setLocalHover(true)}
onMouseOut={(): void => setLocalHover(false)}
hover={localHover}
>
<HeaderContentContainer onClick={(e): void => e.preventDefault()}>
<Typography.Text style={{ maxWidth: '80%' }} ellipsis>
{title}
</Typography.Text>
<ArrowContainer hover={parentHover}>
<DownOutlined />
</ArrowContainer>
</HeaderContentContainer>
</HeaderContainer>
</Dropdown>
);
}
export default WidgetHeader;

View File

@ -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;
`;