fix: widget options are now opening (#2141)

This commit is contained in:
Palash Gupta 2023-01-30 18:06:49 +05:30 committed by GitHub
parent b72815ca2f
commit b336a6cb45
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 109 additions and 71 deletions

View File

@ -10,4 +10,13 @@ export const tooltipStyles = {
right: '0.313rem', right: '0.313rem',
color: themeColors.errorColor, color: themeColors.errorColor,
}; };
export const errorTooltipPosition = 'top'; export const errorTooltipPosition = 'top';
export const overlayStyles: React.CSSProperties = {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
position: 'absolute',
};

View File

@ -5,11 +5,12 @@ import {
ExclamationCircleOutlined, ExclamationCircleOutlined,
FullscreenOutlined, FullscreenOutlined,
} from '@ant-design/icons'; } from '@ant-design/icons';
import { Dropdown, Menu, Tooltip, Typography } from 'antd'; import { Dropdown, MenuProps, Tooltip, Typography } from 'antd';
import { MenuItemType } from 'antd/es/menu/hooks/useItems';
import Spinner from 'components/Spinner'; import Spinner from 'components/Spinner';
import useComponentPermission from 'hooks/useComponentPermission'; import useComponentPermission from 'hooks/useComponentPermission';
import history from 'lib/history'; import history from 'lib/history';
import React, { useState } from 'react'; import React, { useCallback, useMemo, useState } from 'react';
import { UseQueryResult } from 'react-query'; import { UseQueryResult } from 'react-query';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { AppState } from 'store/reducers'; import { AppState } from 'store/reducers';
@ -18,12 +19,16 @@ import { Widgets } from 'types/api/dashboard/getAll';
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange'; import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
import AppReducer from 'types/reducer/app'; import AppReducer from 'types/reducer/app';
import { errorTooltipPosition, spinnerStyles, tooltipStyles } from './config'; import {
errorTooltipPosition,
overlayStyles,
spinnerStyles,
tooltipStyles,
} from './config';
import { import {
ArrowContainer, ArrowContainer,
HeaderContainer, HeaderContainer,
HeaderContentContainer, HeaderContentContainer,
MenuItemContainer,
} from './styles'; } from './styles';
type TWidgetOptions = 'view' | 'edit' | 'delete' | string; type TWidgetOptions = 'view' | 'edit' | 'delete' | string;
@ -48,17 +53,19 @@ function WidgetHeader({
errorMessage, errorMessage,
}: IWidgetHeaderProps): JSX.Element { }: IWidgetHeaderProps): JSX.Element {
const [localHover, setLocalHover] = useState(false); const [localHover, setLocalHover] = useState(false);
const [isOpen, setIsOpen] = useState<boolean>(false);
const onEditHandler = (): void => { const onEditHandler = useCallback((): void => {
const widgetId = widget.id; const widgetId = widget.id;
history.push( history.push(
`${window.location.pathname}/new?widgetId=${widgetId}&graphType=${widget.panelTypes}`, `${window.location.pathname}/new?widgetId=${widgetId}&graphType=${widget.panelTypes}`,
); );
}; }, [widget.id, widget.panelTypes]);
const keyMethodMapping: { const keyMethodMapping: {
[K in TWidgetOptions]: { key: TWidgetOptions; method: VoidFunction }; [K in TWidgetOptions]: { key: TWidgetOptions; method: VoidFunction };
} = { } = useMemo(
() => ({
view: { view: {
key: 'view', key: 'view',
method: onView, method: onView,
@ -71,10 +78,20 @@ function WidgetHeader({
key: 'delete', key: 'delete',
method: onDelete, method: onDelete,
}, },
}; }),
const onMenuItemSelectHandler = ({ key }: { key: TWidgetOptions }): void => { [onDelete, onEditHandler, onView],
keyMethodMapping[key]?.method(); );
};
const onMenuItemSelectHandler: MenuProps['onClick'] = useCallback(
({ key }: { key: TWidgetOptions }): void => {
const functionToCall = keyMethodMapping[key]?.method;
if (functionToCall) {
functionToCall();
setIsOpen(false);
}
},
[keyMethodMapping],
);
const { role } = useSelector<AppState, AppReducer>((state) => state.app); const { role } = useSelector<AppState, AppReducer>((state) => state.app);
const [deleteWidget, editWidget] = useComponentPermission( const [deleteWidget, editWidget] = useComponentPermission(
@ -82,49 +99,67 @@ function WidgetHeader({
role, role,
); );
const menu = ( const menuList: MenuItemType[] = useMemo(
<Menu onClick={onMenuItemSelectHandler}> () => [
<Menu.Item key={keyMethodMapping.view.key}> {
<MenuItemContainer> key: keyMethodMapping.view.key,
<span>View</span> <FullscreenOutlined /> icon: <FullscreenOutlined />,
</MenuItemContainer> disabled: queryResponse.isLoading,
</Menu.Item> label: 'View',
},
{
key: keyMethodMapping.edit.key,
icon: <EditFilled />,
disabled: !editWidget,
label: 'Edit',
},
{
key: keyMethodMapping.delete.key,
icon: <DeleteOutlined />,
disabled: !deleteWidget,
danger: true,
label: 'Delete',
},
],
[
deleteWidget,
editWidget,
keyMethodMapping.delete.key,
keyMethodMapping.edit.key,
keyMethodMapping.view.key,
queryResponse.isLoading,
],
);
{editWidget && ( const onClickHandler = useCallback(() => {
<Menu.Item key={keyMethodMapping.edit.key}> setIsOpen((open) => !open);
<MenuItemContainer> }, []);
<span>Edit</span> <EditFilled />
</MenuItemContainer>
</Menu.Item>
)}
{deleteWidget && ( const menu = useMemo(
<> () => ({
<Menu.Divider /> items: menuList,
<Menu.Item key={keyMethodMapping.delete.key} danger> onClick: onMenuItemSelectHandler,
<MenuItemContainer> }),
<span>Delete</span> <DeleteOutlined /> [menuList, onMenuItemSelectHandler],
</MenuItemContainer>
</Menu.Item>
</>
)}
</Menu>
); );
return ( return (
<div>
<Dropdown <Dropdown
overlay={menu} destroyPopupOnHide
open={isOpen}
onOpenChange={setIsOpen}
menu={menu}
trigger={['click']} trigger={['click']}
overlayStyle={{ minWidth: 100 }} overlayStyle={overlayStyles}
placement="bottom"
> >
<>
<HeaderContainer <HeaderContainer
onMouseOver={(): void => setLocalHover(true)} onMouseOver={(): void => setLocalHover(true)}
onMouseOut={(): void => setLocalHover(false)} onMouseOut={(): void => setLocalHover(false)}
hover={localHover} hover={localHover}
onClick={onClickHandler}
> >
<HeaderContentContainer onClick={(e): void => e.preventDefault()}> <HeaderContentContainer>
<Typography.Text style={{ maxWidth: '80%' }} ellipsis> <Typography.Text style={{ maxWidth: '80%' }} ellipsis>
{title} {title}
</Typography.Text> </Typography.Text>
@ -133,6 +168,7 @@ function WidgetHeader({
</ArrowContainer> </ArrowContainer>
</HeaderContentContainer> </HeaderContentContainer>
</HeaderContainer> </HeaderContainer>
</Dropdown>
{queryResponse.isFetching && !queryResponse.isError && ( {queryResponse.isFetching && !queryResponse.isError && (
<Spinner height="5vh" style={spinnerStyles} /> <Spinner height="5vh" style={spinnerStyles} />
)} )}
@ -141,8 +177,7 @@ function WidgetHeader({
<ExclamationCircleOutlined style={tooltipStyles} /> <ExclamationCircleOutlined style={tooltipStyles} />
</Tooltip> </Tooltip>
)} )}
</> </div>
</Dropdown>
); );
} }

View File

@ -1,12 +1,6 @@
import { grey } from '@ant-design/colors'; import { grey } from '@ant-design/colors';
import styled from 'styled-components'; 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 }>` export const HeaderContainer = styled.div<{ hover: boolean }>`
width: 100%; width: 100%;
text-align: center; text-align: center;