mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-09-21 01:33:14 +08:00
fix: widget options are now opening (#2141)
This commit is contained in:
parent
b72815ca2f
commit
b336a6cb45
@ -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',
|
||||||
|
};
|
||||||
|
@ -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,33 +53,45 @@ 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: {
|
() => ({
|
||||||
key: 'view',
|
view: {
|
||||||
method: onView,
|
key: 'view',
|
||||||
|
method: onView,
|
||||||
|
},
|
||||||
|
edit: {
|
||||||
|
key: 'edit',
|
||||||
|
method: onEditHandler,
|
||||||
|
},
|
||||||
|
delete: {
|
||||||
|
key: 'delete',
|
||||||
|
method: onDelete,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
[onDelete, onEditHandler, onView],
|
||||||
|
);
|
||||||
|
|
||||||
|
const onMenuItemSelectHandler: MenuProps['onClick'] = useCallback(
|
||||||
|
({ key }: { key: TWidgetOptions }): void => {
|
||||||
|
const functionToCall = keyMethodMapping[key]?.method;
|
||||||
|
if (functionToCall) {
|
||||||
|
functionToCall();
|
||||||
|
setIsOpen(false);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
edit: {
|
[keyMethodMapping],
|
||||||
key: 'edit',
|
);
|
||||||
method: onEditHandler,
|
|
||||||
},
|
|
||||||
delete: {
|
|
||||||
key: 'delete',
|
|
||||||
method: onDelete,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const onMenuItemSelectHandler = ({ key }: { key: TWidgetOptions }): void => {
|
|
||||||
keyMethodMapping[key]?.method();
|
|
||||||
};
|
|
||||||
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 (
|
||||||
<Dropdown
|
<div>
|
||||||
overlay={menu}
|
<Dropdown
|
||||||
trigger={['click']}
|
destroyPopupOnHide
|
||||||
overlayStyle={{ minWidth: 100 }}
|
open={isOpen}
|
||||||
placement="bottom"
|
onOpenChange={setIsOpen}
|
||||||
>
|
menu={menu}
|
||||||
<>
|
trigger={['click']}
|
||||||
|
overlayStyle={overlayStyles}
|
||||||
|
>
|
||||||
<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,16 +168,16 @@ function WidgetHeader({
|
|||||||
</ArrowContainer>
|
</ArrowContainer>
|
||||||
</HeaderContentContainer>
|
</HeaderContentContainer>
|
||||||
</HeaderContainer>
|
</HeaderContainer>
|
||||||
{queryResponse.isFetching && !queryResponse.isError && (
|
</Dropdown>
|
||||||
<Spinner height="5vh" style={spinnerStyles} />
|
{queryResponse.isFetching && !queryResponse.isError && (
|
||||||
)}
|
<Spinner height="5vh" style={spinnerStyles} />
|
||||||
{queryResponse.isError && (
|
)}
|
||||||
<Tooltip title={errorMessage} placement={errorTooltipPosition}>
|
{queryResponse.isError && (
|
||||||
<ExclamationCircleOutlined style={tooltipStyles} />
|
<Tooltip title={errorMessage} placement={errorTooltipPosition}>
|
||||||
</Tooltip>
|
<ExclamationCircleOutlined style={tooltipStyles} />
|
||||||
)}
|
</Tooltip>
|
||||||
</>
|
)}
|
||||||
</Dropdown>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user