Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,18 @@
"@types/material-ui": "^0.21.7",
"@types/node": "^12.12.27",
"@types/react": "^16.9.20",
"@types/react-csv": "^1.1.1",
"@types/react-dom": "^16.9.5",
"@types/react-router-dom": "^5.1.3",
"ag-grid-community": "^22.1.1",
"ag-grid-enterprise": "^22.1.1",
"ag-grid-react": "^22.1.1",
"axios": "^0.19.2",
"react": "^16.12.0",
"react-cookie": "^4.0.3",
"react-csv": "^2.0.1",
"react-dom": "^16.12.0",
"react-dom-factories": "^1.0.2",
"react-router-dom": "^5.1.2",
"react-scripts": "3.4.0",
"typescript": "^3.7.5"
Expand Down
4 changes: 4 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import Typography from '@material-ui/core/Typography';
import IconButton from '@material-ui/core/IconButton';
import MenuIcon from '@material-ui/icons/Menu';

import Issue from "./containers/Issue";
import Issues from "./containers/Issues";
import Home from './containers/Home';

Expand Down Expand Up @@ -60,6 +61,9 @@ const App: React.FC<Props> = () => {
<Route path="/issues">
<Issues />
</Route>
<Route path="/issue">
<Issue />
</Route>
</Switch>
</div>
</Router >
Expand Down
11 changes: 11 additions & 0 deletions src/constants/Issues.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const HEADERS = [
{ label: "Issue Number", key: "number" },
{ label: "Issue Title", key: "title" },
{ label: "Description", key: "body" },
{ label: "Reported By", key: "reporter" },
{ label: "Issue Type", key: "issueType" },
{ label: "Issue Status", key: "issueStatus" },
{ label: "Component", key: "component" }
];
export const ISSUE_TYPES = ["bug", "requirement"];
export const ISSUE_STATUS = ["low", "high", "medium", "critical"];
18 changes: 13 additions & 5 deletions src/containers/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import GitHubIcon from '@material-ui/icons/GitHub';
import { useLocation } from "react-router-dom";
import axios from 'axios';
import { Octokit } from "@octokit/rest";

import {
Link
} from "react-router-dom";
interface Props {
cookies: any;
}
Expand Down Expand Up @@ -93,16 +97,20 @@ const Home: React.FC<Props> = ({ cookies }) => {

const renderHome = () => {
return (
<p>Welcom Home, {user.name}</p>
<div>
<p>Welcom Home, {user.name}</p>

<Link to="/issues">Issues</Link>
</div>
)
}


if (!code && !cookeieToken) {
return renderLoginButton();
}
if (!code && !cookeieToken) {
return renderLoginButton();
}

return renderHome();
return renderHome();


}
Expand Down
187 changes: 187 additions & 0 deletions src/containers/Issue.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
import React, { useEffect, useState } from 'react'
import { withCookies } from 'react-cookie';
import { Octokit } from "@octokit/rest";
import { CSVDownload } from "react-csv";
import { HEADERS, ISSUE_TYPES, ISSUE_STATUS } from "../constants/Issues";
import { AgGridReact } from 'ag-grid-react';
import 'ag-grid-community/dist/styles/ag-grid.css';
import 'ag-grid-community/dist/styles/ag-theme-balham.css';

import {
BrowserRouter as Router,
Link,
useLocation
} from "react-router-dom";

interface Props {
cookies: any;
}

interface Issue {
number: number;
title: string;
state:string;
body: string;
reporter: string;
issueType: string;
issueStatus: string;
component: string;
createdAt: string;
updatedAt: string;
closedAt: string;
}

const Issue: React.FC<Props> = ({ cookies }) => {

let cookeieToken = cookies.get("token");
cookeieToken = cookeieToken === "undefined" ? undefined : cookeieToken;
let issuesArr: Issue[] = [],
octokit: Octokit = new Octokit({
auth: cookeieToken
});
const columnDefs = [
{ headerName: "Issue Number", field: "number" },
{ headerName: "Issue Title", field: "title" },
{ headerName: "Issue Status", field: "state" },
{ headerName: "Description", field: "body" },
{ headerName: "Reported By", field: "reporter" },
{ headerName: "Issue Type", field: "issueType" },
{ headerName: "Issue Status", field: "issueStatus" },
{ headerName: "Component", field: "component" },
{ headerName: "Created At", field: "createdAt" },
{ headerName: "updated At", field: "updatedAt" },
{ headerName: "Closed At", field: "closedAt" },

];

let gridOptions: any = null;

const [issues, setIssues] = useState({
rowData: issuesArr,
columnDefs: columnDefs,
gridOptions: gridOptions
});


// A custom hook that builds on useLocation to parse
// the query string for you.
const useQuery = () => {
return new URLSearchParams(useLocation().search);
}

let query = useQuery();

let rowData = [
{ make: "Toyota", model: "Celica", price: 35000 },
{ make: "Ford", model: "Mondeo", price: 32000 },
{ make: "Porsche", model: "Boxter", price: 72000 }
];

useEffect(() => {
const getRepoData = async () => {

let repoFullName = query.get('full_name');

if (octokit !== undefined && repoFullName !== null) {

let result: Issue[] = [];
let hasNextPage = true;
let currPage = 1;
let pageSize = 100;
while (hasNextPage) {

const repoFullNameArr = repoFullName.split("/"),
response = await octokit.issues.listForRepo({
owner: repoFullNameArr[0],
repo: repoFullNameArr[1],
state: "all",
sort: "updated",
direction: "desc",
per_page: pageSize,
page: currPage
});
console.log("Issue API Response ", response, "currPage ", currPage, " pageSize", pageSize);
if (response && response.status === 200) {
if (response.data.length < pageSize) {

hasNextPage = false;
} {
currPage++
}
response.data.forEach(data => {
let issueType = "",
issueStatus = "",
component = "";

if (data.labels) {
data.labels.forEach((label) => {
if (label.name.toLowerCase().indexOf("xviz") !== -1) {
component = label.name;
}
if (ISSUE_STATUS.indexOf(label.name.toLowerCase()) !== -1) {
issueStatus = label.name;
}
if (ISSUE_TYPES.indexOf(label.name.toLowerCase()) !== -1) {
issueType = label.name;
}
})
}

result.push({
number: data.number,
title: data.title,
state: data.state,
body: data.body,
reporter: data.user.login,
issueType: issueType,
issueStatus: issueStatus,
component: component,
createdAt: data.created_at ? new Date(data.created_at).toLocaleDateString() : "",
updatedAt: data.updated_at ? new Date(data.updated_at).toLocaleDateString() : "",
closedAt: data.closed_at ? new Date(`${data.closed_at}`).toLocaleDateString() : ""
})
});
} else {
hasNextPage = false;
}

}

setIssues({
rowData: result,
columnDefs: columnDefs,
gridOptions: issues.gridOptions
})

}
}

getRepoData();
// eslint-disable-next-line
}, []);
return (
<div className="ag-theme-balham" style={{ height: '650px' }}>
<button
onClick={() => {
if (issues.gridOptions !== null && issues.gridOptions.api) {
issues.gridOptions.api.exportDataAsCsv({
fileName: 'xViz',
sheetName: 'xViz',
allColumns: true
})
}
}
}>
Download CSV
</button>
<AgGridReact
columnDefs={issues.columnDefs}
rowData={issues.rowData}
onGridReady={(e) => { issues.gridOptions = e; }}>
</AgGridReact>

</div>
)
}

export default withCookies(Issue)
Loading