Skip to content
Snippets Groups Projects
Commit aa54a734 authored by Ulrik Røsby's avatar Ulrik Røsby
Browse files

Merge branch '13-create-page-for-visualizing-commits-per-branch' into 'master'

Resolve "Create page for visualizing commits per branch"

Closes #13

See merge request it2810-h21/team-24/project2-it2810!10
parents 11e193cf 2af07887
No related branches found
No related tags found
No related merge requests found
......@@ -9,6 +9,7 @@ import { themes } from './helpers/themes';
import Home from './pages/Home/index';
import SettingsPage from './pages/SettingsPage/index';
import FeatsVsFixesPage from './pages/FeatsVsFixesPage';
import CommitsPerBranchPage from './pages/CommitsPerBranch';
import TimePerIssueLabelPage from './pages/TimePerIssueLabelPage/index';
import { Theme } from '@material-ui/core';
import { useLocalStorage } from './helpers/hooks';
......@@ -46,6 +47,9 @@ function App() {
<Route exact path={'/commits'}>
<FeatsVsFixesPage />
</Route>
<Route exact path={'/mergerequests'}>
<CommitsPerBranchPage />
</Route>
<Route exact path={'/timeperissuelabel'}>
<TimePerIssueLabelPage />
</Route>
......
import { ChartBarIcon, ChartPieIcon, CogIcon } from '@heroicons/react/outline';
import { MenuIcon } from '@heroicons/react/solid';
import { MenuIcon, InboxInIcon } from '@heroicons/react/solid';
import {
AppBar,
IconButton,
......@@ -65,6 +65,9 @@ export default function NavBar(props: MenuProps) {
<Link underline="none" href={'/commits'}>
<MenuItem className={classes.menuItem}>Commits</MenuItem>
</Link>
<Link underline="none" href={'/mergerequests'}>
<MenuItem className={classes.menuItem}>Merge Requests</MenuItem>
</Link>
<Link underline="none" href={'/timeperissuelabel'}>
<MenuItem className={classes.menuItem}>Issue-label</MenuItem>
</Link>
......@@ -77,6 +80,7 @@ export default function NavBar(props: MenuProps) {
<div className={classes.linkContainer}>
<IconLink url={'commits'} title={'Commits'} icon={<ChartPieIcon />} />
<IconLink url={'timeperissuelabel'} title={'Issue-label'} icon={<ChartBarIcon />} />
<IconLink url={'mergerequests'} title={'Merge requests'} icon={<InboxInIcon />} />
<IconLink
title={'settings'}
icon={<CogIcon />}
......
import { PROJECT_ID } from './constants';
import { APIRequestMethods, APIResponse, Commit, Issue } from './types';
import { APIRequestMethods, APIResponse, Commit, Issue, MergeRequest } from './types';
import { getEnv } from './utils';
/**
......@@ -55,3 +55,53 @@ export const getAllCommitsFromAPI = async () => {
const data: Commit[] = [];
return getCommitsFromAPIRecursive(data, 1);
};
const getMergeRequestsFromAPI = async (data: Array<MergeRequest>, page: number) => {
return fromAPI('/merge_requests?state=all', 'GET').then(async (res) => {
if (res.ok) {
data = data.concat(res.data as Array<MergeRequest>);
if (res.headers.get('x-next-page')) {
await getMergeRequestsFromAPI(data, page + 1);
} else {
return data;
}
}
});
};
export const getAllMergeRequestsFromAPI = async () => {
const data: MergeRequest[] = [];
return getMergeRequestsFromAPI(data, 1);
};
const getCommitByMergeRequestFromAPI = async (
data: Array<Commit>,
page: number,
requestiid: number,
) => {
return fromAPI(
'/merge_requests/' + requestiid + '/commits?per_page=101000&page=' + page,
'GET',
).then(async (res) => {
if (res.ok) {
data = data.concat(res.data as Array<Commit>);
if (res.headers.get('x-next-page')) {
await getCommitByMergeRequestFromAPI(data, page + 1, requestiid);
} else {
return data;
}
}
});
};
export const getAllCommitsByMergeRequestFromAPI = async (merges: Array<MergeRequest>) => {
const commitsByRequest = new Map<number, Array<Commit>>();
for (let i = 0; i < merges.length; i++) {
const data: Commit[] = [];
const something = await getCommitByMergeRequestFromAPI(data, 1, merges[i].iid);
if (Array.isArray(something)) {
commitsByRequest.set(merges[i].iid, something);
}
}
return commitsByRequest;
};
......@@ -137,3 +137,48 @@ export type Issue = {
moved_to_id: null;
service_desk_reply_to: null;
};
export type MergeRequest = {
id: number;
iid: number;
project_id: number;
title: string;
description: string;
state: string;
merged_by: IssueAuthor;
merged_at: string;
closed_by: IssueAuthor;
closed_at: string;
created_at: string;
updated_at: string;
target_branch: string;
source_branch: string;
upvotes: number;
downvotes: number;
author: IssueAuthor;
assignee: IssueAuthor;
assignees: IssueAuthor[];
reviewers: IssueAuthor[];
source_project_id: number;
target_project_id: number;
labels: string[];
draft: boolean;
work_in_progress: boolean;
milestone: Milestone;
merge_when_pipeline_succeeds: boolean;
merge_status: string;
sha: string;
merge_commit_sha: string;
squash_commit_sha: string;
user_notes_count: string;
discussion_locked: boolean;
should_remove_source_branch: boolean;
force_remove_source_branch: boolean;
web_url: string;
references: References;
time_stats: TimeStats;
squash: boolean;
task_completion_status: TaskCompletionStatus;
has_conflicts: boolean;
blocking_discussions_resolved: boolean;
};
import PageContainer from '../../components/PageContainer/index';
import ChartBar from '../../components/ChartBar';
import {
getAllMergeRequestsFromAPI,
getAllCommitsByMergeRequestFromAPI,
} from '../../helpers/api-calls';
import { useCallback, useEffect, useState } from 'react';
import { Commit, BarDataItem } from '../../helpers/types';
import { Switch } from '@material-ui/core/';
import useStyles from './styles';
export default function CommitsPerBranchPage() {
const [data, setData] = useState<Array<BarDataItem> | null>(null);
const [trueData, setTrueData] = useState<Array<BarDataItem> | null>(null);
const [activeBranch, setActiveBranch] = useState<Map<string, boolean> | null>(null);
const classes = useStyles();
const getCommitsPerRequest = useCallback(() => {
const commitsByBranch: Array<BarDataItem> = [];
getAllMergeRequestsFromAPI().then((res) => {
if (res) {
getAllCommitsByMergeRequestFromAPI(res).then((res2) => {
if (res2) {
const activeBranches = new Map<string, boolean>();
res2.forEach((value: Array<Commit>, key: number) => {
activeBranches.set(String(key), true);
if (
!commitsByBranch.includes({
barLabel: String(key),
barValue: value.length,
})
) {
commitsByBranch.push({
barLabel: String(key),
barValue: value.length,
});
}
});
commitsByBranch.reverse();
setData(commitsByBranch);
setTrueData(commitsByBranch);
setActiveBranch(activeBranches);
}
});
}
});
}, [setData, setTrueData, setActiveBranch]);
useEffect(() => {
getCommitsPerRequest();
}, []);
return (
<PageContainer>
<header />
{data && <ChartBar data={data} title={'Commits by merge request iid'} />}
<div className={classes.switchcontainer}>
{trueData &&
activeBranch &&
trueData.map((m, i) => {
if (m.barLabel || m.barValue) {
return (
<div key={i}>
<Switch
className={classes.switch}
checked={activeBranch.get(m.barLabel)}
onChange={() => {
activeBranch.set(m.barLabel, !activeBranch.get(m.barLabel));
const tempList = trueData.filter((data) => activeBranch.get(data.barLabel));
setData(tempList);
}}
/>
Merge Request no. {m.barLabel}
</div>
);
}
})}
</div>
</PageContainer>
);
}
import { createStyles, makeStyles, Theme } from '@material-ui/core';
const useStyles = makeStyles((theme: Theme) =>
createStyles({
switch: {
display: 'flex',
color: theme.palette.primary.contrastText + '!important',
},
switchcontainer: {
display: 'grid',
width: '100%',
gridTemplateColumns: '1fr 1fr 1fr 1fr',
},
}),
);
export default useStyles;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment