Skip to content
This repository was archived by the owner on Apr 12, 2023. It is now read-only.

Commit c138949

Browse files
committed
Added GitHub dashboard with CRUD
CRUD fix
1 parent c981bf2 commit c138949

11 files changed

+737
-20
lines changed

package.json

+7
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,14 @@
33
"version": "0.1.0",
44
"private": true,
55
"dependencies": {
6+
"@patternfly/react-core": "^3.129.3",
7+
"@patternfly/react-table": "^2.24.64",
8+
"apollo-boost": "^0.4.7",
9+
"bootstrap": "^4.4.1",
10+
"graphql": "^14.5.8",
11+
"graphql-tag": "^2.10.1",
612
"react": "^16.12.0",
13+
"react-bootstrap": "^1.0.0-beta.16",
714
"react-dom": "^16.12.0",
815
"react-scripts": "3.2.0"
916
},

src/App.css

+14-10
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,26 @@
1-
.App {
2-
text-align: center;
3-
}
4-
51
.App-logo {
6-
height: 40vmin;
2+
height: 100px;
73
}
84

95
.App-header {
10-
background-color: #282c34;
11-
min-height: 100vh;
6+
background-color: white;
7+
height: 120px;
128
display: flex;
139
flex-direction: column;
1410
align-items: center;
1511
justify-content: center;
16-
font-size: calc(10px + 2vmin);
12+
flex: 1;
1713
color: white;
14+
flex-direction: row;
1815
}
1916

20-
.App-link {
21-
color: #09d3ac;
17+
.dashHead{
18+
color: lightseagreen;
19+
font-size: xx-large;
2220
}
21+
22+
.head{
23+
text-align: center;
24+
color: lightseagreen;
25+
font-size: xx-large;
26+
}

src/App.js

+9-10
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,23 @@
11
import React from 'react';
22
import logo from './logo.svg';
33
import './App.css';
4+
import MainPage from './components/MainPage'
45

56
function App() {
67
return (
78
<div className="App">
89
<header className="App-header">
910
<img src={logo} className="App-logo" alt="logo" />
10-
<p>
11-
Edit <code>src/App.js</code> and save to reload.
11+
<p className="dashHead">
12+
<b> git </b>
1213
</p>
13-
<a
14-
className="App-link"
15-
href="https://reactjs.org"
16-
target="_blank"
17-
rel="noopener noreferrer"
18-
>
19-
Learn React
20-
</a>
2114
</header>
15+
<hr/>
16+
<br/>
17+
<p className="head">
18+
<b style={{textAlign:"center"}}>Repo: {localStorage.getItem('repoName')}</b>
19+
</p>
20+
<MainPage/>
2221
</div>
2322
);
2423
}

src/components/HeaderTabs.js

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import React from 'react';
2+
import { Tabs, Tab } from '@patternfly/react-core';
3+
import '@patternfly/react-core/dist/styles/base.css';
4+
import Repos from './sets/Repos'
5+
import Issues from './sets/Issues'
6+
import Comments from './sets/Comments'
7+
8+
9+
class HeaderTabs extends React.Component {
10+
tabNumber = localStorage.getItem('tabNumber');
11+
constructor(props) {
12+
super(props);
13+
this.state = {
14+
activeTabKey: Number.parseInt(localStorage.getItem('tabNumber'))
15+
};
16+
// Toggle currently active tab
17+
this.handleTabClick = (event, tabIndex) => {
18+
this.setState({
19+
activeTabKey: tabIndex
20+
});
21+
if(tabIndex==0){
22+
localStorage.clear();
23+
window.location.reload();
24+
}
25+
26+
localStorage.setItem('tabNumber', tabIndex);
27+
};
28+
}
29+
30+
render() {
31+
return (
32+
<Tabs style={{padding:32}} isFilled activeKey={this.state.activeTabKey} onSelect={this.handleTabClick}>
33+
<Tab eventKey={0} title="Repositories">
34+
<Repos/>
35+
</Tab>
36+
<Tab eventKey={1} title="Issues">
37+
<Issues/>
38+
</Tab>
39+
<Tab eventKey={2} title="Comments">
40+
<Comments/>
41+
</Tab>
42+
</Tabs>
43+
);
44+
}
45+
}
46+
export default HeaderTabs;

src/components/MainPage.js

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import React from 'react';
2+
import '@patternfly/react-core/dist/styles/base.css';
3+
import HeaderTabs from './HeaderTabs';
4+
5+
const MainPage = () => {
6+
const tabNumber = localStorage.getItem('tabNumber');
7+
if(tabNumber==null){
8+
localStorage.setItem('tabNumber', 0);
9+
}
10+
return <HeaderTabs/>;
11+
};
12+
export default MainPage;

src/components/Pagination.js

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import React from 'react';
2+
import 'bootstrap/dist/css/bootstrap.min.css';
3+
4+
const Pagination = ({active, perPage, total, paginate}) => {
5+
const pageNumbers=[];
6+
for(let i=1; i<= Math.ceil(total/perPage);i++){
7+
pageNumbers.push(i);
8+
}
9+
return(
10+
<nav className="pagination">
11+
{pageNumbers.map(number=>{
12+
if(number==active){
13+
return (<li key={number} className="page-item active">
14+
<a onClick={()=>paginate(number)} href='!#' className='page-link'>
15+
{number}
16+
</a>
17+
</li>);
18+
} else {
19+
return(<li key={number} className="page-item">
20+
<a onClick={()=>paginate(number)} href='!#' className='page-link'>
21+
{number}
22+
</a>
23+
</li>
24+
);
25+
}
26+
})}
27+
</nav>
28+
)
29+
}
30+
export default Pagination;

src/components/sets/Comments.js

+185
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
import React, {useState, useEffect} from 'react';
2+
import ApolloClient from 'apollo-boost'
3+
import gql from 'graphql-tag'
4+
import {TextInput} from '@patternfly/react-core'
5+
import {TableHeader, TableBody, Table} from '@patternfly/react-table';
6+
import Button from 'react-bootstrap/Button';
7+
import '@patternfly/react-core/dist/styles/base.css';
8+
9+
const Comments = () => {
10+
const [comments, setComments] = useState([]);
11+
const [loading, setLoading] = useState(false);
12+
const [body, setBody] = useState("")
13+
const [mode, setMode] = useState("")
14+
let token = '';
15+
const client = new ApolloClient({
16+
uri: 'https://api.github.com/graphql',
17+
18+
request: (operation) => {
19+
operation.setContext({
20+
headers: {
21+
authorization: token? `bearer ${token}` : ''
22+
}
23+
})
24+
}
25+
})
26+
useEffect(() => {
27+
const fetchRepos = async () => {
28+
setMode("Create")
29+
setLoading(true)
30+
let isn = localStorage.getItem('issueTitle')
31+
if(localStorage.getItem(isn+'Comments')!=null){
32+
let is = localStorage.getItem(isn+'Comments')
33+
console.log(is)
34+
setComments(JSON.parse(is))
35+
setLoading(false)
36+
}
37+
};
38+
fetchRepos();
39+
}, []);
40+
const columns = [
41+
'Author Username',
42+
'Comment',
43+
'Edit Comment',
44+
'Delete Comment',
45+
];
46+
const rows = comments.map(cmt => {
47+
let login = localStorage.getItem('viewer-login')
48+
if(cmt.node.author.login==login){
49+
return ({cells: [
50+
cmt.node.author.login,
51+
cmt.node.bodyText,
52+
(
53+
<div>
54+
<Button onClick={()=>{
55+
setMode("Edit")
56+
localStorage.setItem('commentId', cmt.node.id)
57+
setBody(cmt.node.bodyText)
58+
}} variant="success">Edit</Button>
59+
</div>
60+
),
61+
(
62+
<div>
63+
<Button onClick={()=>{
64+
deleteCommentSubmit(cmt.node.id)
65+
}} variant="danger">Delete</Button>
66+
</div>
67+
),
68+
]});
69+
} else {
70+
return ({cells: [
71+
cmt.node.author.login,
72+
cmt.node.bodyText,
73+
'N/A',
74+
'N/A'
75+
]});
76+
}
77+
});
78+
79+
const handleBodyChange = (e) =>{
80+
setBody(e)
81+
}
82+
83+
const creatCommentSubmit = async(event, id, body) =>{
84+
event.preventDefault();
85+
let nId = '"'+id+'"';
86+
let nBody = '"'+body+'"'
87+
await client.mutate({
88+
mutation: gql`
89+
mutation{
90+
addComment(input:{subjectId:${nId}, body:${nBody}}){
91+
clientMutationId
92+
}
93+
}
94+
`
95+
}).then(result => {
96+
console.log(result)
97+
localStorage.clear();
98+
window.location.reload();
99+
alert("Created Comment");
100+
})
101+
}
102+
103+
const deleteCommentSubmit = async (id) =>{
104+
let nId = '"'+id+'"';
105+
await client.mutate({
106+
mutation: gql`
107+
mutation{
108+
deleteIssueComment(input:{id:${nId}}){
109+
clientMutationId
110+
}
111+
}
112+
`
113+
}).then(result => {
114+
alert("Successfully Deleted")
115+
localStorage.setItem('tabNumber', 0)
116+
localStorage.setItem('repoName', '')
117+
window.location.reload();
118+
})
119+
}
120+
121+
const updateCommentSubmit = async (event,id, body) =>{
122+
event.preventDefault();
123+
let nId = '"' + id + '"'
124+
let nTitle = '"' + body + '"'
125+
126+
await client.mutate({
127+
mutation: gql`
128+
mutation{
129+
updateIssueComment(input:{id:${nId}, body:${nTitle}}){
130+
issueComment{
131+
id
132+
}
133+
}
134+
}
135+
`
136+
}).then(result => {
137+
alert("Successfully Updated")
138+
localStorage.setItem('tabNumber', 0)
139+
localStorage.setItem('repoName', '')
140+
window.location.reload();
141+
})
142+
}
143+
144+
if((loading)&&(localStorage.getItem('issueTitle')!=null)) {
145+
return(
146+
<div>
147+
<h1>Comment</h1>
148+
<TextInput style={{margin: 8}} value={body} onChange={(event)=>handleBodyChange(event)} placeholder="Message"/>
149+
<Button type="submit" style={{margin: 8}} onClick={(event)=>{
150+
if(mode=="Create")
151+
creatCommentSubmit(event, localStorage.getItem('issueTitle'), body)
152+
else
153+
updateCommentSubmit(event, localStorage.getItem('commentId'), body)
154+
}}>{mode}</Button>
155+
156+
</div>
157+
)
158+
}
159+
160+
161+
if(loading){
162+
return ( <h2>No Comments Available</h2>);
163+
}
164+
165+
return(
166+
<div style={{margin: 16, padding: 16}}>
167+
<div>
168+
<h1>Comment</h1>
169+
<TextInput style={{margin: 8}} value={body} onChange={(event)=>handleBodyChange(event)} placeholder="Message"/>
170+
<Button type="submit" style={{margin: 8}} onClick={(event)=>{
171+
if(mode=="Create")
172+
creatCommentSubmit(event, localStorage.getItem('issueTitle'), body)
173+
else
174+
updateCommentSubmit(event, localStorage.getItem('commentId'), body)
175+
}}>{mode}</Button>
176+
</div>
177+
<Table cells={columns} rows={rows}>
178+
<TableHeader/>
179+
<TableBody />
180+
</Table>
181+
<br/>
182+
</div>
183+
);
184+
}
185+
export default Comments;

0 commit comments

Comments
 (0)