Merge pull request #14 from RandellDawson/feat/create-search-component
[feature] created Search component
This commit is contained in:
committed by
mrugesh mohapatra
parent
c1c1154bc3
commit
db0fd603a5
@ -2,8 +2,7 @@ import React, { Component } from 'react';
|
|||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
import Tabs from './components/Tabs';
|
import Tabs from './components/Tabs';
|
||||||
import Input from './components/Input';
|
import Search from './components/Search';
|
||||||
import Results from './components/Results';
|
|
||||||
import Pareto from './components/Pareto';
|
import Pareto from './components/Pareto';
|
||||||
|
|
||||||
const Container = styled.div`
|
const Container = styled.div`
|
||||||
@ -11,79 +10,34 @@ const Container = styled.div`
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
max-width: 960px;
|
||||||
|
width: 90vw;
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
box-shadow: 0 0 4px 0 #777;
|
box-shadow: 0 0 4px 0 #777;
|
||||||
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
class App extends Component {
|
class App extends Component {
|
||||||
state = {
|
state = {
|
||||||
number: '',
|
|
||||||
foundPRs: [],
|
|
||||||
pareto: [],
|
|
||||||
view: 'search'
|
view: 'search'
|
||||||
};
|
};
|
||||||
|
|
||||||
clearObj = { number: '', foundPRs: [] };
|
|
||||||
|
|
||||||
inputRef = React.createRef();
|
|
||||||
|
|
||||||
handleInputEvent = (event) => {
|
|
||||||
const { type, key, target: { value } } = event;
|
|
||||||
|
|
||||||
if (type === 'change') {
|
|
||||||
if (Number(value) || value === '') {
|
|
||||||
this.setState((prevState) => ({ number: value, foundPRs: [] }));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (type === 'keypress' && key === 'Enter') {
|
|
||||||
this.searchPRs(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleButtonClick = () => {
|
|
||||||
const { number } = this.state;
|
|
||||||
this.searchPRs(number);
|
|
||||||
}
|
|
||||||
|
|
||||||
searchPRs = (number) => {
|
|
||||||
fetch(`https://pr-relations.glitch.me/pr/${number}`)
|
|
||||||
.then((response) => response.json())
|
|
||||||
.then(({ ok, foundPRs }) => {
|
|
||||||
if (ok) {
|
|
||||||
if (!foundPRs.length) {
|
|
||||||
foundPRs.push({ number: 'No PRs with matching files', filenames: [] });
|
|
||||||
}
|
|
||||||
this.setState((prevState) => ({ foundPRs }));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.inputRef.current.focus();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
this.setState((prevState) => (this.clearObj));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleViewChange = ( { target: { id } }) => {
|
handleViewChange = ( { target: { id } }) => {
|
||||||
const view = id.replace('tabs-', '');
|
const view = id.replace('tabs-', '');
|
||||||
this.setState((prevState) => ({ ...this.clearObj, view }));
|
this.setState((prevState) => ({ ...this.clearObj, view }));
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { handleButtonClick, handleViewChange, handleInputEvent, inputRef, state } = this;
|
const { handleViewChange, state: { view } } = this;
|
||||||
const { number, foundPRs, view } = state;
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<>
|
||||||
<Tabs view={view} onViewChange={handleViewChange}/>
|
<Tabs view={view} onViewChange={handleViewChange}/>
|
||||||
<Input ref={inputRef} value={number} onInputEvent={handleInputEvent} />
|
<Container>
|
||||||
<button onClick={handleButtonClick}>Search</button>
|
{ view === 'search' && <Search /> }
|
||||||
{ view === 'search' && <Results foundPRs={foundPRs} /> }
|
{ view === 'reports' && <Pareto /> }
|
||||||
{ view === 'reports' && <Pareto /> }
|
</Container>
|
||||||
</Container>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
const Container = styled.input`
|
||||||
|
margin-bottom: 10px;
|
||||||
|
`;
|
||||||
|
|
||||||
const Input = React.forwardRef((props, ref) => (
|
const Input = React.forwardRef((props, ref) => (
|
||||||
<input
|
<Container
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="PR #"
|
placeholder="PR #"
|
||||||
onChange={props.onInputEvent}
|
onChange={props.onInputEvent}
|
||||||
|
@ -54,7 +54,7 @@ class Pareto extends React.Component {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{elements}
|
{data.length ? elements : 'Report Loading...'}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
const List = styled.ul`
|
||||||
|
margin: 5px;
|
||||||
|
`;
|
||||||
|
|
||||||
const Results = ({ foundPRs }) => {
|
const Results = ({ foundPRs }) => {
|
||||||
const elements = foundPRs.map((foundPR) => {
|
const elements = foundPRs.map((foundPR) => {
|
||||||
@ -10,18 +15,16 @@ const Results = ({ foundPRs }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={number}>
|
<div key={number}>
|
||||||
<h5>
|
{!Number(number)
|
||||||
{!Number(number)
|
? number
|
||||||
? number
|
: <>
|
||||||
: <>
|
<a href={prUrl} rel="noopener noreferrer" target="_blank">{number}</a>
|
||||||
<a href={prUrl} rel="noopener noreferrer" target="_blank">{number}</a>
|
<span> {username}</span>
|
||||||
<span> {username}</span>
|
</>
|
||||||
</>
|
}
|
||||||
}
|
<List>
|
||||||
</h5>
|
|
||||||
<ul>
|
|
||||||
{files}
|
{files}
|
||||||
</ul>
|
</List>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
66
dashboard-client/app/app/src/components/Search.js
Normal file
66
dashboard-client/app/app/src/components/Search.js
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
|
import Input from './Input';
|
||||||
|
import Results from './Results';
|
||||||
|
|
||||||
|
class Search extends Component {
|
||||||
|
state = {
|
||||||
|
number: '',
|
||||||
|
foundPRs: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
clearObj = { number: '', foundPRs: [] };
|
||||||
|
|
||||||
|
inputRef = React.createRef();
|
||||||
|
|
||||||
|
handleInputEvent = (event) => {
|
||||||
|
const { type, key, target: { value } } = event;
|
||||||
|
|
||||||
|
if (type === 'change') {
|
||||||
|
if (Number(value) || value === '') {
|
||||||
|
this.setState((prevState) => ({ number: value, foundPRs: [] }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (type === 'keypress' && key === 'Enter') {
|
||||||
|
this.searchPRs(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleButtonClick = () => {
|
||||||
|
const { number } = this.state;
|
||||||
|
this.searchPRs(number);
|
||||||
|
}
|
||||||
|
|
||||||
|
searchPRs = (number) => {
|
||||||
|
fetch(`https://pr-relations.glitch.me/pr/${number}`)
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then(({ ok, foundPRs }) => {
|
||||||
|
if (ok) {
|
||||||
|
if (!foundPRs.length) {
|
||||||
|
foundPRs.push({ number: 'No PRs with matching files', filenames: [] });
|
||||||
|
}
|
||||||
|
this.setState((prevState) => ({ foundPRs }));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.inputRef.current.focus();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
this.setState((prevState) => (this.clearObj));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { handleButtonClick, handleInputEvent, inputRef, state } = this;
|
||||||
|
const { number, foundPRs } = state;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Input ref={inputRef} value={number} onInputEvent={handleInputEvent} />
|
||||||
|
<button onClick={handleButtonClick}>Search</button>
|
||||||
|
<Results foundPRs={foundPRs} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Search;
|
@ -5,6 +5,7 @@ const Container = styled.div`
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
|
margin: 10px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Tab = styled.div`
|
const Tab = styled.div`
|
||||||
@ -14,10 +15,12 @@ const Tab = styled.div`
|
|||||||
padding: 5px;
|
padding: 5px;
|
||||||
border: 2px solid ${({ theme }) => theme.primary};
|
border: 2px solid ${({ theme }) => theme.primary};
|
||||||
border-left: none;
|
border-left: none;
|
||||||
|
flex-basis: 200px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
background: ${({ theme }) => theme.primary};
|
background: rgba(0, 0, 255, 0.8);
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,7 +33,7 @@ const Tabs = ({ view, onViewChange }) => {
|
|||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<Tab id="tabs-search" onClick={onViewChange} active={view === 'search'}>Search</Tab>
|
<Tab id="tabs-search" onClick={onViewChange} active={view === 'search'}>Search</Tab>
|
||||||
<Tab id="tabs-reports" onClick={onViewChange} active={view === 'reports'}>Reports</Tab>
|
<Tab id="tabs-reports" onClick={onViewChange} active={view === 'reports'}>Pareto</Tab>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -6,7 +6,7 @@ body {
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
/* height: 100vh; */
|
min-height: 100vh;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
|
||||||
|
Reference in New Issue
Block a user