Merge pull request #8 from RandellDawson/feat/report-improvements
Feature: Added Pareto Report and Tabs Navigation
This commit is contained in:
committed by
mrugesh mohapatra
parent
e8aa30162a
commit
e31396931e
14974
dashboard-client/app/app/package-lock.json
generated
Normal file
14974
dashboard-client/app/app/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,8 +1,10 @@
|
||||
import React, { Component } from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import Tabs from './components/Tabs';
|
||||
import Input from './components/Input';
|
||||
import Results from './components/Results';
|
||||
import Pareto from './components/Pareto';
|
||||
|
||||
const Container = styled.div`
|
||||
display: flex;
|
||||
@ -12,14 +14,19 @@ const Container = styled.div`
|
||||
padding: 15px;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 4px 0 #777;
|
||||
|
||||
`;
|
||||
|
||||
class App extends Component {
|
||||
state = {
|
||||
number: '',
|
||||
foundPRs: []
|
||||
foundPRs: [],
|
||||
pareto: [],
|
||||
view: 'search'
|
||||
};
|
||||
|
||||
clearObj = { number: '', foundPRs: [] };
|
||||
|
||||
inputRef = React.createRef();
|
||||
|
||||
handleInputEvent = (event) => {
|
||||
@ -37,7 +44,6 @@ class App extends Component {
|
||||
|
||||
handleButtonClick = () => {
|
||||
const { number } = this.state;
|
||||
|
||||
this.searchPRs(number);
|
||||
}
|
||||
|
||||
@ -56,19 +62,25 @@ class App extends Component {
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.setState((prevState) => ({ number: '', foundPRs: [] }));
|
||||
this.setState((prevState) => (this.clearObj));
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { handleButtonClick, handleInputEvent, inputRef, state } = this;
|
||||
const { number, foundPRs } = state;
|
||||
handleViewChange = ( { target: { id } }) => {
|
||||
const view = id.replace('tabs-', '');
|
||||
this.setState((prevState) => ({ ...this.clearObj, view }));
|
||||
}
|
||||
|
||||
render() {
|
||||
const { handleButtonClick, handleViewChange, handleInputEvent, inputRef, state } = this;
|
||||
const { number, foundPRs, view } = state;
|
||||
return (
|
||||
<Container>
|
||||
<Tabs view={view} onViewChange={handleViewChange}/>
|
||||
<Input ref={inputRef} value={number} onInputEvent={handleInputEvent} />
|
||||
<button onClick={handleButtonClick}>Search</button>
|
||||
<Results foundPRs={foundPRs} />
|
||||
{ view === 'search' && <Results foundPRs={foundPRs} /> }
|
||||
{ view === 'reports' && <Pareto /> }
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
63
dashboard-client/app/app/src/components/Pareto.js
Normal file
63
dashboard-client/app/app/src/components/Pareto.js
Normal file
@ -0,0 +1,63 @@
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
const Result = styled.div`
|
||||
word-wrap: break-word;
|
||||
margin: 10px 0;
|
||||
&:nth-child(odd) {
|
||||
background: #eee;
|
||||
}
|
||||
`;
|
||||
|
||||
class Pareto extends React.Component {
|
||||
state = {
|
||||
data: []
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
fetch(`https://pr-relations.glitch.me/pareto`)
|
||||
.then((response) => response.json())
|
||||
.then(({ ok, pareto }) => {
|
||||
if (ok) {
|
||||
if (!pareto.length) {
|
||||
pareto.push({ filename: 'Nothing to show in Pareto Report', count: 0, prs: [] });
|
||||
}
|
||||
this.setState((prevState) => ({ data: pareto }));
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
const pareto = [{ filename: 'Nothing to show in Pareto Report', count: 0, prs: [] }];
|
||||
this.setState((prevState) => ({ data: pareto }));
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { data } = this.state;
|
||||
|
||||
const elements = data.map((entry) => {
|
||||
const { filename, count, prs } = entry;
|
||||
const prsList = prs.reduce((html, { number, username }) => {
|
||||
const prUrl = `https://github.com/freeCodeCamp/freeCodeCamp/pull/${number}`;
|
||||
return html += `
|
||||
<a href=${prUrl} rel="noopener noreferrer" target="_blank">#${number} <span>${username}</span></a>, `;
|
||||
}, '');
|
||||
return (
|
||||
<Result key={filename}>
|
||||
{filename}<br />
|
||||
<details>
|
||||
<summary># of PRs: {count}</summary>
|
||||
<div dangerouslySetInnerHTML={{__html: prsList}} />
|
||||
</details>
|
||||
</Result>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
{elements}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Pareto;
|
32
dashboard-client/app/app/src/components/Tabs.js
Normal file
32
dashboard-client/app/app/src/components/Tabs.js
Normal file
@ -0,0 +1,32 @@
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
const Container = styled.div`
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
height: 40px;
|
||||
`;
|
||||
|
||||
const Tab = styled.div`
|
||||
background: ${({ active }) => active ? 'blue' : 'white'};
|
||||
color: ${({ active }) => active ? 'white' : 'blue'};
|
||||
font-size: 18px;
|
||||
padding: 5px;
|
||||
border: 2px solid blue;
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
background: blue;
|
||||
color: white;
|
||||
}
|
||||
`;
|
||||
|
||||
const Tabs = ({ view, onViewChange }) => {
|
||||
return (
|
||||
<Container>
|
||||
<Tab id="tabs-search" onClick={onViewChange} active={view === 'search'}>Search</Tab>
|
||||
<Tab id="tabs-reports" onClick={onViewChange} active={view === 'reports'}>Reports</Tab>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
export default Tabs;
|
@ -6,7 +6,7 @@ body {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
/* height: 100vh; */
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
|
||||
@ -19,4 +19,4 @@ body {
|
||||
code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
|
||||
monospace;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user