Skip to content

Commit

Permalink
feat: add popover for bar chart item hover state (#217)
Browse files Browse the repository at this point in the history
Signed-off-by: csirius <[email protected]>
  • Loading branch information
govalt authored Sep 24, 2021
1 parent dba3df1 commit 46a7823
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 13 deletions.
40 changes: 33 additions & 7 deletions src/components/Entities/EntityExecutionsBarChart.tsx
Original file line number Diff line number Diff line change
@@ -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: {
Expand All @@ -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: (
<div style={{ display: 'flex', flexDirection: 'column' }}>
<span>
Execution Id: <strong>{execution.id.name}</strong>
</span>
<span>Running time: {millisecondsToHMS(duration)}</span>
<span>
Started at:{' '}
{formatDateUTC(
timestampToDate(execution.closure.startedAt!)
)}
</span>
</div>
)
};
});
if (newExecutions.length >= fillSize) {
Expand Down Expand Up @@ -88,6 +106,13 @@ export const EntityExecutionsBarChart: React.FC<EntityExecutionsBarChartProps> =
}
);

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;
Expand All @@ -102,6 +127,7 @@ export const EntityExecutionsBarChart: React.FC<EntityExecutionsBarChartProps> =
<BarChart
data={getExecutionTimeData(executions.value)}
startDate={getStartExecutionTime(executions.value)}
onClickItem={handleClickItem}
/>
</div>
</WaitForData>
Expand Down
70 changes: 64 additions & 6 deletions src/components/common/BarChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down Expand Up @@ -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;
}

/**
Expand All @@ -56,15 +64,50 @@ interface BarChartProps {
* @param color
* @constructor
*/
const BarChartItem: React.FC<BarChartData> = ({ value, color }) => {
const BarChartItem: React.FC<BarChartItemProps> = ({
value,
color,
tooltip,
onClick
}) => {
const styles = useStyles();
const [position, setPosition] = React.useState({ x: 0, y: 0 });

const content = (
<div
className={styles.itemBar}
style={{ backgroundColor: color, height: `${value}%` }}
onClick={onClick}
/>
);

return (
<div className={styles.item}>
<div
className={styles.itemBar}
style={{ backgroundColor: color, height: `${value}%` }}
></div>
{tooltip ? (
<Tooltip
title={tooltip}
TransitionComponent={Zoom}
onMouseMove={e => 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}
</Tooltip>
) : (
content
)}
</div>
);
};
Expand All @@ -75,13 +118,26 @@ const BarChartItem: React.FC<BarChartData> = ({ value, color }) => {
* @param startDate
* @constructor
*/
export const BarChart: React.FC<BarChartProps> = ({ data, startDate }) => {
export const BarChart: React.FC<BarChartProps> = ({
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 (
<div className={styles.container}>
<div className={styles.header}>
Expand All @@ -93,6 +149,8 @@ export const BarChart: React.FC<BarChartProps> = ({ data, startDate }) => {
<BarChartItem
value={(Math.log2(item.value) / maxHeight) * 100}
color={item.color}
tooltip={item.tooltip}
onClick={handleClickItem(item)}
key={`bar-chart-item-${index}`}
/>
))}
Expand Down

0 comments on commit 46a7823

Please sign in to comment.