Skip to content

Commit

Permalink
Merge pull request #50 from Fgerthoffert/develop
Browse files Browse the repository at this point in the history
Added a breakdown by ticket type and project to the completed heatmap
  • Loading branch information
Fgerthoffert committed Oct 17, 2019
2 parents bb31670 + fc5034e commit 7def2ff
Show file tree
Hide file tree
Showing 6 changed files with 210 additions and 58 deletions.
2 changes: 1 addition & 1 deletion cli/src/utils/data/fetchCompleted.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const fetchCompleted = async (
const issuesJira = await jiraSearchIssues(
config.jira,
jqlQuery,
'labels,summary,' +
'labels,summary,issuetype,assignee,' +
config.jira.fields.points +
',' +
config.jira.fields.originalPoints
Expand Down
5 changes: 5 additions & 0 deletions ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,30 @@
"@types/colornames": "^1.1.1",
"@types/cytoscape": "^3.8.2",
"@types/jest": "24.0.18",
"@types/lodash": "^4.14.144",
"@types/node": "12.7.2",
"@types/randomcolor": "^0.5.3",
"@types/react": "16.9.2",
"@types/react-dom": "16.9.0",
"@types/react-redux": "^7.1.2",
"@types/react-router-dom": "^4.3.5",
"@types/socket.io-client": "^1.4.32",
"axios": "^0.19.0",
"chart.js": "^2.8.0",
"chartjs-plugin-datalabels": "^0.7.0",
"colornames": "^1.1.1",
"cytoscape": "^3.10.0",
"cytoscape-cose-bilkent": "^4.1.0",
"cytoscape-popper": "^1.0.4",
"date-fns": "^2.2.1",
"font-color-contrast": "^1.0.3",
"install": "^0.13.0",
"lodash": "^4.17.15",
"loglevel": "^1.6.3",
"material-color-hash": "^0.1.6",
"material-table": "^1.50.0",
"npm": "^6.11.3",
"randomcolor": "^0.5.4",
"react": "^16.9.0",
"react-bootstrap": "^1.0.0-beta.12",
"react-cytoscapejs": "^1.2.0",
Expand Down
5 changes: 3 additions & 2 deletions ui/src/components/Charts/Nivo/RoadmapCompletionChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { Component } from 'react'; // let's also import Component
import { Theme, createStyles, withStyles } from '@material-ui/core/styles';
import { ResponsiveHeatMap } from '@nivo/heatmap';

import RoadmapTooltip from './RoadmapTooltip';
import RoadmapTooltip from './RoadmapTooltip/index';

import {
getInitiativeTitle,
Expand Down Expand Up @@ -37,12 +37,13 @@ class RoadmapCompletionChart extends Component<any, any> {
dataset: any = {};

getTooltip = (data: any) => {
const { roadmap } = this.props;
const { roadmap, defaultPoints } = this.props;
return (
<RoadmapTooltip
data={data}
roadmap={roadmap}
completionWeeks={this.completionWeeks}
defaultPoints={defaultPoints}
/>
);
};
Expand Down
55 changes: 0 additions & 55 deletions ui/src/components/Charts/Nivo/RoadmapTooltip.tsx

This file was deleted.

78 changes: 78 additions & 0 deletions ui/src/components/Charts/Nivo/RoadmapTooltip/DataBreakdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import React, { Component } from 'react'; // let's also import Component
import { Theme, createStyles, withStyles } from '@material-ui/core/styles';
import Chart from 'chart.js';
import randomColor from 'randomcolor';
import ChartDataLabels from 'chartjs-plugin-datalabels';

const styles = (theme: Theme) =>
createStyles({
root: {
// height: 200
}
});

class DataBreakdown extends Component<any, any> {
chartRef: any = React.createRef();
chart: any = {};
allowClick: boolean = true;

componentDidMount() {
this.buildChart();
}

componentDidUpdate() {
this.buildChart();
}

resetAllowClick = () => {
this.allowClick = true;
};

buildChart = () => {
const { dataset, defaultPoints } = this.props;
const myChartRef = this.chartRef.current.getContext('2d');
let metric = 'points';
if (!defaultPoints) {
metric = 'issues';
}

if (this.chart.destroy !== undefined) {
this.chart.destroy();
}
this.chart = new Chart(myChartRef, {
type: 'pie',
plugins: [ChartDataLabels],
data: {
datasets: [
{
data: dataset.map((value: any) => value[metric].count),
backgroundColor: dataset.map((value: any) =>
randomColor({ seed: value.name })
)
}
],
labels: dataset.map((value: any) => value.name)
},
options: {
responsive: true,
legend: {
position: 'left'
},
animation: {
animateRotate: false
}
}
});
};

render() {
const { classes } = this.props;
return (
<div className={classes.root}>
<canvas id='myChart' ref={this.chartRef} height='200' />
</div>
);
}
}

export default withStyles(styles)(DataBreakdown);
123 changes: 123 additions & 0 deletions ui/src/components/Charts/Nivo/RoadmapTooltip/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import React from 'react';
import Grid from '@material-ui/core/Grid';
import _ from 'lodash';

import { getCellDataInitiatives } from '../utils';

import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow';
import Typography from '@material-ui/core/Typography';

import DataBreakdown from './DataBreakdown';

export interface TooltipProps {
data: any;
roadmap: any;
completionWeeks: any;
defaultPoints: boolean;
}

export default function RoadmapTooltip(props: TooltipProps) {
const { data, roadmap, completionWeeks, defaultPoints } = props;
const initiatives = getCellDataInitiatives(
data.yKey,
data.xKey,
roadmap,
completionWeeks
);

const typesGroup = _.groupBy(initiatives, (value: any) => {
if (value.fields.issuetype !== undefined) {
return value.fields.issuetype.name;
} else {
return null;
}
});

const types: any = [];
Object.keys(typesGroup).forEach((key: any) => {
types.push({
name: key,
list: typesGroup[key],
issues: {
count: typesGroup[key].length
},
points: {
count: typesGroup[key]
.map(issue => issue.points)
.reduce((acc, count) => acc + count, 0)
}
});
});

const projectsGroup = _.groupBy(initiatives, value =>
value.key.replace(/[^a-z+]+/gi, '')
);
const projects: any = [];
Object.keys(projectsGroup).forEach((key: any) => {
projects.push({
name: key,
list: projectsGroup[key],
issues: {
count: projectsGroup[key].length
},
points: {
count: projectsGroup[key]
.map((issue: any) => {
return issue.points;
})
.reduce((acc: number, count: number) => acc + count, 0)
}
});
});
return (
<React.Fragment>
<Table size='small'>
<TableHead>
<TableRow>
<TableCell>Key</TableCell>
<TableCell align='right'>Summary</TableCell>
<TableCell align='right'>Points</TableCell>
</TableRow>
</TableHead>
<TableBody>
{initiatives.slice(0, 5).map((i: any) => (
<TableRow key={i.key}>
<TableCell component='th' scope='row'>
{i.key}
</TableCell>
<TableCell align='right'>{i.fields.summary}</TableCell>
<TableCell align='right'>{i.points}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
{initiatives.length > 5 && (
<span>
<b>Caution:</b>{' '}
<i>
This table only displays the first 5 results (out of{' '}
{initiatives.length}).
</i>
</span>
)}
<Grid container direction='row' justify='center' alignItems='center'>
<Grid item xs={6}>
<Typography variant='h6' component='h6'>
Projects
</Typography>
<DataBreakdown dataset={projects} defaultPoints={defaultPoints} />
</Grid>
<Grid item xs={6}>
<Typography variant='h6' component='h6'>
Types
</Typography>
<DataBreakdown dataset={types} defaultPoints={defaultPoints} />
</Grid>
</Grid>
</React.Fragment>
);
}

0 comments on commit 7def2ff

Please sign in to comment.