Skip to content

Commit

Permalink
#233 can now fetch review threads and comments
Browse files Browse the repository at this point in the history
  • Loading branch information
maerzman committed Jul 17, 2024
1 parent 65a02db commit 71e2756
Show file tree
Hide file tree
Showing 13 changed files with 127 additions and 212 deletions.
11 changes: 11 additions & 0 deletions binocular-frontend/src/database/database.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,17 @@ export default class Database {
}
}

/**
* REVIEW THREADS
*/
static async getReviewThreadData() {
if (await this.checkBackendConnection()) {
return ServerDB.getReviewThreadData();
} else {
return LocalDB.getReviewThreadData();
}
}

/**
* MILESTONES
*/
Expand Down
5 changes: 5 additions & 0 deletions binocular-frontend/src/database/localDB.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import stakeholders from '../../db_export/stakeholders.json';
import mergeRequests from '../../db_export/mergeRequests.json';
import milestones from '../../db_export/milestones.json';
import Comments from './serverDB/comments';
import ReviewThreads from './localDB/reviewThreads';

const collections = { branches, builds, commits, files, issues, modules, stakeholders, mergeRequests, milestones };

Expand Down Expand Up @@ -218,6 +219,10 @@ export default class LocalDB {
return Comments.getCommentData(commentSpan, significantSpan);
}

static getReviewThreadData() {
return ReviewThreads.getReviewThreadData();
}

static getDatabase() {
const database = collections;

Expand Down
2 changes: 1 addition & 1 deletion binocular-frontend/src/database/localDB/comments.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import { findAll } from './utils';

export default class Comments {
static getIssueData(db, relations, issueSpan, significantSpan) {
static getCommentData(db, relations, issueSpan, significantSpan) {
return findAll(db, 'comments').then((res) => {
res.docs = res.docs
.sort((a, b) => {
Expand Down
10 changes: 4 additions & 6 deletions binocular-frontend/src/database/localDB/reviewThreads.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@
import { findAll } from './utils';

export default class ReviewThreads {
static getIssueData(db, relations, issueSpan, significantSpan) {
static getReviewThreadData(db, relations) {
return findAll(db, 'reviewThreads').then((res) => {
res.docs = res.docs
.sort((a, b) => {
return new Date(a.createdAt) - new Date(b.createdAt);
})
.filter((rt) => new Date(rt.createdAt) >= new Date(significantSpan[0]) && new Date(rt.createdAt) <= new Date(significantSpan[1]));
res.docs = res.docs.sort((a, b) => {
return new Date(a.createdAt) - new Date(b.createdAt);
});
return res.docs;
});
}
Expand Down
5 changes: 5 additions & 0 deletions binocular-frontend/src/database/serverDB.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import Branches from './serverDB/branches';
import Modules from './serverDB/modules';
import Stakeholders from './serverDB/stakeholders';
import Comments from './serverDB/comments';
import ReviewThreads from './serverDB/reviewThreads';

export default class ServerDB {
static getBounds() {
Expand Down Expand Up @@ -121,6 +122,10 @@ export default class ServerDB {
return Comments.getCommentData(commentSpan, significantSpan);
}

static getReviewThreadData() {
return ReviewThreads.getReviewThreadData();
}

static getDatabase() {
const xhr = new XMLHttpRequest();
xhr.open('GET', window.location.protocol + '//' + window.location.hostname + ':48763/api/db-export', false);
Expand Down
12 changes: 0 additions & 12 deletions binocular-frontend/src/database/serverDB/comments.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,6 @@ export default class Comments {
lastEditedAt
path
bodyText
comments {
id
author {
login
name
}
createdAt
updatedAt
lastEditedAt
path
bodyText
}
}
}
}`,
Expand Down
45 changes: 45 additions & 0 deletions binocular-frontend/src/database/serverDB/reviewThreads.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
'use strict';

import { graphQl, traversePages } from '../../utils';
import _ from 'lodash';

export default class ReviewThreads {
static getReviewThreadData() {
console.log('TEST');

const reviewThreadList = [];
const getReviewThreadsPage = () => (page, perPage) => {
return graphQl
.query(
`
query($page: Int, $perPage: Int) {
reviewThreads(page: $page, perPage: $perPage) {
count
page
perPage
count
data {
id
isResolved
path
resolvedBy {
login
}
comments {
id
}
}
}
}`,
{ page, perPage },
)
.then((resp) => resp.reviewThreads);
};

return traversePages(getReviewThreadsPage(), (reviewThread) => {
reviewThreadList.push(reviewThread);
}).then(function () {
return reviewThreadList;
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,142 +74,12 @@ class ChartComponent extends React.Component<Props, State> {
const mergeRequests = props.mergeRequests;
const metricsData: Bubble[] = [];

_.each(mergeRequests, (mergeRequest: MergeRequest) => {
const referenceDate = mergeRequest.closedAt ? Date.parse(mergeRequest.closedAt) : Date.now();
let color: string;
switch (mergeRequest.state) {
case 'OPEN':
color = 'green';
break;
case 'CLOSED':
color = 'red';
break;
case 'MERGED':
color = 'purple';
break;
default:
color = 'yellow';
break;
}

const bubble: Bubble = {
x: Math.round((referenceDate - Date.parse(mergeRequest.createdAt)) / this.getTimeConversionFactor(props)),
y: 10 + Math.random(),
size: 3,
color: color,
};
metricsData.push(bubble);
});
console.log(props.codeReviewMetricsState);

if (props.codeReviewMetricsState.config.showMergeRequests === 'cumulative') {
const groupedData: Bubble[] = this.getGroupedDataCumulative(metricsData);
return { metricsData: groupedData };
} else if (props.codeReviewMetricsState.config.showMergeRequests === 'category') {
const groupedData: Bubble[] = this.getGroupedDataCategory(metricsData);
return { metricsData: groupedData };
}
_.each(mergeRequests, (mergeRequest: MergeRequest) => {});

return { metricsData };
}

getGroupedDataCumulative(metricsData: Bubble[]): Bubble[] {
const groupedData = this.groupData(metricsData);
console.log(groupedData);
const cumulativeData: Bubble[] = [];

for (const color in groupedData) {
for (const x in groupedData[color]) {
const bubble: Bubble = {
x: parseInt(x),
y: 10 + Math.random(),
color: color,
size: 10 + groupedData[color][x].length / 10,
};

cumulativeData.push(bubble);
}
}

return cumulativeData;
}

getGroupedDataCategory(metricsData: Bubble[]): Bubble[] {
const groupedData = this.groupData(metricsData);
const categoryData: Bubble[] = [];

for (const color in groupedData) {
let size = 0;
for (const x in groupedData[color]) {
size += groupedData[color][x].length;
}
const bubble: Bubble = {
x: 0,
y: 0,
size: 10 + size / 10,
color: color,
};

categoryData.push(bubble);
}

return categoryData;
}

/**
* groups the data by its color and its x-value and returns it as an object of the form
* { 'color1': {'value1': [{...}:Bubble, ...]}, 'color2': {'value2': [{...}:Bubble, ...]}}
* @param metricsData the data to be grouped
* @returns the grouped data as an object
*/
groupData(metricsData: Bubble[]) {
const groupedData = {};
metricsData.forEach((item) => {
const { x, color } = item;
if (!groupedData[color]) {
groupedData[color] = {};
}

if (!groupedData[color][x]) {
groupedData[color][x] = [];
}

groupedData[color][x].push(item);
});

return groupedData;
}

/**
* provides the conversion rate for millis according to the 'group' property of the component
* this will always return the default value of days unless 'showMergeRequests' is set to 'cumulative'
* @param props props of the component
* @returns the conversion rate for millis
*/
getTimeConversionFactor(props): number {
const CONVERT_MILLIS_TO_HOURS = 3600000;
const CONVERT_MILLIS_TO_DAYS = CONVERT_MILLIS_TO_HOURS * 24;
// 365.25 => avg days in a year
const CONVERT_MILLIS_TO_MONTHS = CONVERT_MILLIS_TO_DAYS * (365.25 / 12);
const CONVERT_MILLIS_TO_YEARS = CONVERT_MILLIS_TO_DAYS * 365.25;

// grouping is only available for cumulative display setting
if (props.codeReviewMetricsState.config.showMergeRequests !== 'cumulative') {
return CONVERT_MILLIS_TO_DAYS;
}

switch (props.codeReviewMetricsState.config.group) {
case 'hour':
return CONVERT_MILLIS_TO_HOURS;
case 'day':
return CONVERT_MILLIS_TO_DAYS;
case 'month':
return CONVERT_MILLIS_TO_MONTHS;
case 'year':
return CONVERT_MILLIS_TO_YEARS;
default:
return CONVERT_MILLIS_TO_DAYS;
}
}
}

const mapStateToProps = (state) => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,56 +8,11 @@ import { setGroup, setMergeRequests } from './sagas';

interface Props {
codeReviewMetricsState: any;
setMergeRequests: (settings: any) => void;
setGroup: (settings: any) => void;
}

class ConfigComponent extends React.Component<Props> {
onClickMergeRequests = (settings) => {
this.props.setMergeRequests(settings);
};

onClickGroup = (settings) => {
this.props.setGroup(settings);
};

render() {
return (
<div className={styles.configContainer}>
<div className={styles.field}>
<h2>Grouping</h2>
<div className="control">
<TabCombo
options={[
{ label: 'Category', icon: 'folder', value: 'category' },
{ label: 'Single', icon: 'cube', value: 'single' },
{ label: 'Cumulative', icon: 'cubes', value: 'cumulative' },
]}
value={this.props.codeReviewMetricsState.config.showMergeRequests}
onChange={(value) => this.onClickMergeRequests(value)}
/>
</div>
</div>

{this.props.codeReviewMetricsState.config.showMergeRequests === 'cumulative' && (
<div className={styles.field}>
<h2>Granularity</h2>
<div className="control">
<TabCombo
options={[
{ label: 'Hour', icon: 'h', value: 'hour' },
{ label: 'Day', icon: 'd', value: 'day' },
{ label: 'Month', icon: 'm', value: 'month' },
{ label: 'Year', icon: 'y', value: 'year' },
]}
value={this.props.codeReviewMetricsState.config.group}
onChange={(value) => this.onClickGroup(value)}
/>
</div>
</div>
)}
</div>
);
return <div className={styles.configContainer}>Config</div>;
}
}

Expand All @@ -66,7 +21,7 @@ const mapStateToProps = (state) => ({
});

const mapDispatchToProps = (dispatch /*, ownProps*/) => {
return { setMergeRequests: (mergeRequest) => dispatch(setMergeRequests(mergeRequest)), setGroup: (group) => dispatch(setGroup(group)) };
return {};
};

export default connect(mapStateToProps, mapDispatchToProps)(ConfigComponent);
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import _ from 'lodash';
export default handleActions(
{
SET_ACTIVE_VISUALIZATIONS: (state, action) => _.assign({}, state, { visualizations: action.payload }),
SET_SHOW_MERGE_REQUESTS: (state, action) => _.assign({}, state, { showMergeRequests: action.payload }),
CRM_SET_GROUP: (state, action) => _.assign({}, state, { group: action.payload }),
},
{ visualizations: [], showMergeRequests: 'category', group: 'hour' },
{ visualizations: [] },
);
Loading

0 comments on commit 71e2756

Please sign in to comment.