From 56410384b2eadba3c481c8ddde94bac94926cc78 Mon Sep 17 00:00:00 2001 From: csirius <85753828+csirius@users.noreply.github.com> Date: Fri, 24 Sep 2021 12:34:19 -0400 Subject: [PATCH] feat: add popover for bar chart item hover state Signed-off-by: csirius <85753828+csirius@users.noreply.github.com> --- .../Entities/EntityExecutionsBarChart.tsx | 40 +++++++++-- src/components/common/BarChart.tsx | 70 +++++++++++++++++-- 2 files changed, 97 insertions(+), 13 deletions(-) diff --git a/src/components/Entities/EntityExecutionsBarChart.tsx b/src/components/Entities/EntityExecutionsBarChart.tsx index 2825cd6e7..b43103059 100644 --- a/src/components/Entities/EntityExecutionsBarChart.tsx +++ b/src/components/Entities/EntityExecutionsBarChart.tsx @@ -1,21 +1,23 @@ +import * as React from 'react'; import Typography from '@material-ui/core/Typography'; import { makeStyles, Theme } from '@material-ui/core/styles'; +import { formatDateUTC, millisecondsToHMS } from 'common/formatters'; +import { timestampToDate } from 'common/utils'; +import { BarChart } from 'components/common/BarChart'; import { WaitForData } from 'components/common/WaitForData'; import { useWorkflowExecutionFiltersState } from 'components/Executions/filters/useExecutionFiltersState'; import { useWorkflowExecutions } from 'components/hooks/useWorkflowExecutions'; import { SortDirection } from 'models/AdminEntity/types'; import { ResourceIdentifier } from 'models/Common/types'; -import { Execution } from 'models/Execution/types'; +import { Execution, WorkflowExecutionIdentifier } from 'models/Execution/types'; import { executionSortFields } from 'models/Execution/constants'; -import * as React from 'react'; +import { Routes } from 'routes/routes'; +import { history } from 'routes/history'; import { executionFilterGenerator } from './generators'; -import { BarChart } from 'components/common/BarChart'; import { getWorkflowExecutionPhaseConstants, getWorkflowExecutionTimingMS } from '../Executions/utils'; -import { formatDateUTC } from 'common/formatters'; -import { timestampToDate } from 'common/utils'; const useStyles = makeStyles((theme: Theme) => ({ header: { @@ -34,10 +36,26 @@ export interface EntityExecutionsBarChartProps { const getExecutionTimeData = (exectuions: Execution[], fillSize = 100) => { const newExecutions = exectuions.map(execution => { + const duration = getWorkflowExecutionTimingMS(execution)?.duration || 1; return { - value: getWorkflowExecutionTimingMS(execution)?.duration || 1, + value: duration, color: getWorkflowExecutionPhaseConstants(execution.closure.phase) - .badgeColor + .badgeColor, + metadata: execution.id, + tooltip: ( +
+ + Execution Id: {execution.id.name} + + Running time: {millisecondsToHMS(duration)} + + Started at:{' '} + {formatDateUTC( + timestampToDate(execution.closure.startedAt!) + )} + +
+ ) }; }); if (newExecutions.length >= fillSize) { @@ -88,6 +106,13 @@ export const EntityExecutionsBarChart: React.FC = } ); + const handleClickItem = React.useCallback(item => { + if (item.metadata) { + // const executionId = item.metadata as WorkflowExecutionIdentifier; + // history.push(Routes.ExecutionDetails.makeUrl(executionId)); + } + }, []); + /** Don't render component until finish fetching user profile */ if (filtersState.filters[4].status !== 'LOADED') { return null; @@ -102,6 +127,7 @@ export const EntityExecutionsBarChart: React.FC = diff --git a/src/components/common/BarChart.tsx b/src/components/common/BarChart.tsx index 5a068f5ed..73b4abc55 100644 --- a/src/components/common/BarChart.tsx +++ b/src/components/common/BarChart.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import { makeStyles, Theme } from '@material-ui/core/styles'; import { smallFontSize } from 'components/Theme/constants'; import { COLOR_SPECTRUM } from 'components/Theme/colorSpectrum'; +import { Tooltip, Zoom } from '@material-ui/core'; const useStyles = makeStyles((theme: Theme) => ({ container: { @@ -43,11 +44,18 @@ const useStyles = makeStyles((theme: Theme) => ({ interface BarChartData { value: number; color: string; + metadata?: any; + tooltip?: string; +} + +interface BarChartItemProps extends BarChartData { + onClick?: () => void; } interface BarChartProps { data: BarChartData[]; startDate?: string; + onClickItem?: (item: any) => void; } /** @@ -56,15 +64,50 @@ interface BarChartProps { * @param color * @constructor */ -const BarChartItem: React.FC = ({ value, color }) => { +const BarChartItem: React.FC = ({ + value, + color, + tooltip, + onClick +}) => { const styles = useStyles(); + const [position, setPosition] = React.useState({ x: 0, y: 0 }); + + const content = ( +
+ ); return (
-
+ {tooltip ? ( + setPosition({ x: e.pageX, y: e.pageY })} + PopperProps={{ + anchorEl: { + clientHeight: 0, + clientWidth: 0, + getBoundingClientRect: () => ({ + top: position.y, + left: position.x, + right: position.x, + bottom: position.y, + width: 0, + height: 0 + }) + } + }} + > + {content} + + ) : ( + content + )}
); }; @@ -75,13 +118,26 @@ const BarChartItem: React.FC = ({ value, color }) => { * @param startDate * @constructor */ -export const BarChart: React.FC = ({ data, startDate }) => { +export const BarChart: React.FC = ({ + data, + startDate, + onClickItem +}) => { const styles = useStyles(); const maxHeight = React.useMemo(() => { return Math.max(...data.map(x => Math.log2(x.value))); }, [data]); + const handleClickItem = React.useCallback( + item => () => { + if (onClickItem) { + onClickItem(item); + } + }, + [onClickItem] + ); + return (
@@ -93,6 +149,8 @@ export const BarChart: React.FC = ({ data, startDate }) => { ))}