mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-14 23:15:53 +08:00
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:
parent
9a6bcaadf8
commit
3c2173de9e
@ -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;
|
@ -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;
|
||||
`;
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
|
109
frontend/src/container/GridGraphLayout/WidgetHeader/index.tsx
Normal file
109
frontend/src/container/GridGraphLayout/WidgetHeader/index.tsx
Normal 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;
|
@ -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;
|
||||
`;
|
Loading…
x
Reference in New Issue
Block a user