@conorheffron/ironoc-frontend 5.5.9 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +9 -4
- package/src/App.css +21 -0
- package/src/App.js +2 -0
- package/src/App.test.js +90 -1
- package/src/AppNavbar.js +1 -0
- package/src/LoadingSpinner.js +15 -0
- package/src/components/About.js +3 -2
- package/src/components/CoffeeCarousel.js +21 -0
- package/src/components/CoffeeHome.js +39 -0
- package/src/components/ControlledCarousel.js +8 -8
- package/src/components/Home.js +7 -6
- package/src/components/RepoDetails.js +11 -1
- package/src/components/RepoIssues.js +12 -1
package/package.json
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@conorheffron/ironoc-frontend",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"dependencies": {
|
|
6
|
-
"@testing-library/jest-dom": "^5.17.0",
|
|
7
|
-
"@testing-library/react": "^13.4.0",
|
|
8
6
|
"@testing-library/user-event": "^13.5.0",
|
|
7
|
+
"axios": "^0.28.0",
|
|
9
8
|
"bootstrap": "5.1",
|
|
10
9
|
"react": "^18.3.1",
|
|
11
10
|
"react-bootstrap": "^2.10.5",
|
|
@@ -15,7 +14,6 @@
|
|
|
15
14
|
"react-cookie": "^7.2.2",
|
|
16
15
|
"react-dom": "^18.3.1",
|
|
17
16
|
"react-router-dom": "^5.3.0",
|
|
18
|
-
"react-scripts": "^5.0.1",
|
|
19
17
|
"reactstrap": "^8.10.0",
|
|
20
18
|
"web-vitals": "^4.2.3"
|
|
21
19
|
},
|
|
@@ -45,6 +43,13 @@
|
|
|
45
43
|
},
|
|
46
44
|
"devDependencies": {
|
|
47
45
|
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
|
46
|
+
"@testing-library/jest-dom": "^6.6.3",
|
|
47
|
+
"@testing-library/react": "^16.1.0",
|
|
48
|
+
"jest": "^27.5.1",
|
|
49
|
+
"react-scripts": "^5.0.1",
|
|
48
50
|
"web-vitals": "^4.2.3"
|
|
51
|
+
},
|
|
52
|
+
"resolutions": {
|
|
53
|
+
"react-scripts/@svgr/webpack": "^6.2.1"
|
|
49
54
|
}
|
|
50
55
|
}
|
package/src/App.css
CHANGED
|
@@ -73,3 +73,24 @@
|
|
|
73
73
|
height: 13;
|
|
74
74
|
width: 51;
|
|
75
75
|
}
|
|
76
|
+
|
|
77
|
+
.carousel-caption h3, h5 {
|
|
78
|
+
color: navy;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
p a {
|
|
82
|
+
color: yellow;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.carousel-caption h3, h5 {
|
|
86
|
+
background-color:yellow;
|
|
87
|
+
width: 50%;
|
|
88
|
+
height: auto;
|
|
89
|
+
margin: 0 auto;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.carousel-item img {
|
|
93
|
+
width: 50%;
|
|
94
|
+
height: auto;
|
|
95
|
+
margin: 0 auto;
|
|
96
|
+
}
|
package/src/App.js
CHANGED
|
@@ -2,6 +2,7 @@ import React, { Component } from 'react';
|
|
|
2
2
|
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
|
|
3
3
|
import './App.css';
|
|
4
4
|
import Home from './components/Home';
|
|
5
|
+
import CoffeeHome from './components/CoffeeHome';
|
|
5
6
|
import NotFound from './components/NotFound';
|
|
6
7
|
import About from './components/About';
|
|
7
8
|
import RepoDetails from './components/RepoDetails';
|
|
@@ -19,6 +20,7 @@ class App extends Component {
|
|
|
19
20
|
<Route path='/projects' exact={true} component={RepoDetails}/>
|
|
20
21
|
<Route path='/projects/:id' component={RepoDetails}/>
|
|
21
22
|
<Route path='/issues/:id/:repo' component={RepoIssues}/>
|
|
23
|
+
<Route path='/brews' exact={true} component={CoffeeHome}/>
|
|
22
24
|
<Route path="*" component={NotFound} />
|
|
23
25
|
</Switch>
|
|
24
26
|
</Router>
|
package/src/App.test.js
CHANGED
|
@@ -1,8 +1,97 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen, waitFor } from '@testing-library/react';
|
|
3
|
+
import '@testing-library/jest-dom';
|
|
2
4
|
import Home from './components/Home';
|
|
5
|
+
import axios from 'axios';
|
|
6
|
+
import App from './App';
|
|
7
|
+
import CoffeeCarousel from './components/CoffeeCarousel';
|
|
8
|
+
import CoffeeHome from './components/CoffeeHome';
|
|
9
|
+
import NotFound from './components/NotFound';
|
|
10
|
+
|
|
11
|
+
// Mocking axios
|
|
12
|
+
jest.mock('axios');
|
|
3
13
|
|
|
4
14
|
test('renders learn react link', () => {
|
|
5
15
|
render(<Home />);
|
|
6
16
|
const element = screen.getByText(/Home/i);
|
|
7
17
|
expect(element).toBeInTheDocument();
|
|
8
18
|
});
|
|
19
|
+
|
|
20
|
+
// Sample data for testing
|
|
21
|
+
const coffeeItems = [
|
|
22
|
+
{
|
|
23
|
+
title: 'Espresso',
|
|
24
|
+
ingredients: ['Water', 'Coffee beans'],
|
|
25
|
+
image: 'https://example.com/espresso.jpg',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
title: 'Cappuccino',
|
|
29
|
+
ingredients: ['Espresso', 'Steamed milk', 'Foam milk'],
|
|
30
|
+
image: 'https://example.com/cappuccino.jpg',
|
|
31
|
+
},
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
describe('CoffeeCarousel', () => {
|
|
35
|
+
test('renders carousel with coffee items', () => {
|
|
36
|
+
render(<CoffeeCarousel items={coffeeItems} />);
|
|
37
|
+
|
|
38
|
+
// Check that the carousel items are rendered
|
|
39
|
+
coffeeItems.forEach((item) => {
|
|
40
|
+
expect(screen.getByText(item.title)).toBeInTheDocument();
|
|
41
|
+
expect(screen.getByAltText(item.title)).toBeInTheDocument();
|
|
42
|
+
expect(screen.getByText(item.ingredients.join(', '))).toBeInTheDocument();
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test('renders carousel with correct number of items', () => {
|
|
47
|
+
render(<CoffeeCarousel items={coffeeItems} />);
|
|
48
|
+
|
|
49
|
+
// Check that the correct number of carousel items are rendered
|
|
50
|
+
const carouselItems = screen.getAllByRole('img');
|
|
51
|
+
|
|
52
|
+
expect(carouselItems.length).toBe(coffeeItems.length);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
describe('CoffeeHome', () => {
|
|
57
|
+
beforeEach(() => {
|
|
58
|
+
axios.get.mockResolvedValue({ data: coffeeItems });
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test('renders AppNavbar component', () => {
|
|
62
|
+
render(<App />);
|
|
63
|
+
expect(screen.getByRole('banner')).toBeInTheDocument();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test('displays loading state initially', () => {
|
|
67
|
+
render(<CoffeeHome />);
|
|
68
|
+
expect(screen.getByText('Loading...')).toBeInTheDocument();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test('renders CoffeeCarousel component with coffee items', async () => {
|
|
72
|
+
render(<CoffeeHome />);
|
|
73
|
+
|
|
74
|
+
// Wait for the coffee items to be fetched and rendered
|
|
75
|
+
await waitFor(() => {
|
|
76
|
+
expect(screen.getByText('Espresso')).toBeInTheDocument();
|
|
77
|
+
expect(screen.getByText('Cappuccino')).toBeInTheDocument();
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
describe('NotFound', () => {
|
|
83
|
+
test('renders AppNavbar component', () => {
|
|
84
|
+
render(<NotFound />);
|
|
85
|
+
expect(screen.getByRole('banner')).toBeInTheDocument();
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test('displays 404 error message', () => {
|
|
89
|
+
render(<NotFound />);
|
|
90
|
+
expect(screen.getByText('404 - Page Not Found')).toBeInTheDocument();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test('displays the apology message', () => {
|
|
94
|
+
render(<NotFound />);
|
|
95
|
+
expect(screen.getByText('Sorry, the page you are looking for could not be found.')).toBeInTheDocument();
|
|
96
|
+
});
|
|
97
|
+
});
|
package/src/AppNavbar.js
CHANGED
|
@@ -18,6 +18,7 @@ export default function AppNavBar() {
|
|
|
18
18
|
<DropdownMenu end>
|
|
19
19
|
<DropdownItem href="/about">About</DropdownItem>
|
|
20
20
|
<DropdownItem href="/portfolio">Portfolio</DropdownItem>
|
|
21
|
+
<DropdownItem href="/brews">Brews</DropdownItem>
|
|
21
22
|
<DropdownItem divider />
|
|
22
23
|
<DropdownItem href="https://linktr.ee/conorheffron" target="_blank" rel="noreferrer">Link Tree</DropdownItem>
|
|
23
24
|
</DropdownMenu>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import Button from 'react-bootstrap/Button';
|
|
2
|
+
import Spinner from 'react-bootstrap/Spinner';
|
|
3
|
+
import { Container } from 'reactstrap';
|
|
4
|
+
import AppNavbar from './AppNavbar';
|
|
5
|
+
|
|
6
|
+
function LoadingSpinner() {
|
|
7
|
+
return (
|
|
8
|
+
<Container fluid>
|
|
9
|
+
<Button variant="primary" disabled>
|
|
10
|
+
<Spinner as="span" animation="grow" size="sm" role="status" aria-hidden="true"/>Loading...</Button>
|
|
11
|
+
</Container>
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default LoadingSpinner;
|
package/src/components/About.js
CHANGED
|
@@ -27,7 +27,8 @@ class About extends Component {
|
|
|
27
27
|
<br /><br />
|
|
28
28
|
I believe in continuous learning & practical skills that can be demonstrated in a positive & collaborative
|
|
29
29
|
manner (open source is great!). When not learning or working, I like jogging/cycling, music, cooking,
|
|
30
|
-
pretending to be a caffeine connoisseur
|
|
30
|
+
pretending to be a <a href="/brews">caffeine connoisseur</a>, & searching for new forms of
|
|
31
|
+
salsa verde / green sauce!
|
|
31
32
|
<br /><br />
|
|
32
33
|
Let's connect and explore exciting
|
|
33
34
|
opportunities together! See above & beyond for contact details and further information.
|
|
@@ -35,7 +36,7 @@ class About extends Component {
|
|
|
35
36
|
<a class="strava-badge" href='https://strava.com/athletes/2582329' target="_clean">
|
|
36
37
|
Follow me on
|
|
37
38
|
<img class="strava-badge-img" src='https://badges.strava.com/logo-strava.png' alt='Strava' />
|
|
38
|
-
</a
|
|
39
|
+
</a><br />
|
|
39
40
|
</header>
|
|
40
41
|
</Container>
|
|
41
42
|
<Footer/>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Carousel } from 'react-bootstrap';
|
|
3
|
+
import '.././App.css';
|
|
4
|
+
|
|
5
|
+
const CoffeeCarousel = ({ items }) => {
|
|
6
|
+
return (
|
|
7
|
+
<Carousel className="App-header">
|
|
8
|
+
{items.map((item, index) => (
|
|
9
|
+
<Carousel.Item key={index}>
|
|
10
|
+
<img src={item.image} alt={item.title}/>
|
|
11
|
+
<Carousel.Caption>
|
|
12
|
+
<h3>{item.title}</h3>
|
|
13
|
+
<h5>{item.ingredients.join(', ')}</h5>
|
|
14
|
+
</Carousel.Caption>
|
|
15
|
+
</Carousel.Item>
|
|
16
|
+
))}
|
|
17
|
+
</Carousel>
|
|
18
|
+
);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export default CoffeeCarousel;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
|
+
import { Button, Container, InputGroup, Table } from 'reactstrap';
|
|
3
|
+
import axios from 'axios';
|
|
4
|
+
import AppNavbar from '.././AppNavbar';
|
|
5
|
+
import CoffeeCarousel from './CoffeeCarousel';
|
|
6
|
+
import Footer from '.././Footer';
|
|
7
|
+
import LoadingSpinner from '.././LoadingSpinner';
|
|
8
|
+
|
|
9
|
+
function CoffeeHome() {
|
|
10
|
+
const [coffeeItems, setCoffeeItems] = useState([]);
|
|
11
|
+
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
axios.get('/coffees')
|
|
14
|
+
.then(response => setCoffeeItems(response.data))
|
|
15
|
+
.catch(error => console.error('Error fetching coffee details:', error));
|
|
16
|
+
}, []);
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<div className="App">
|
|
20
|
+
<AppNavbar/>
|
|
21
|
+
<Container>
|
|
22
|
+
{coffeeItems.length > 0 ? (
|
|
23
|
+
<>
|
|
24
|
+
<br /><br />
|
|
25
|
+
<CoffeeCarousel items={coffeeItems} />
|
|
26
|
+
</>
|
|
27
|
+
) : (
|
|
28
|
+
<>
|
|
29
|
+
<br /><br /><br />
|
|
30
|
+
<LoadingSpinner/>
|
|
31
|
+
</>
|
|
32
|
+
)}
|
|
33
|
+
</Container>
|
|
34
|
+
<Footer/>
|
|
35
|
+
</div>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export default CoffeeHome;
|
|
@@ -24,7 +24,7 @@ class ControlledCarousel extends Component {
|
|
|
24
24
|
<h1><u>ironoc-db</u></h1>
|
|
25
25
|
<h2>Sample Data Manager Service with UI</h2>
|
|
26
26
|
<br /><br />
|
|
27
|
-
<
|
|
27
|
+
<h4>Tech Stack:</h4>
|
|
28
28
|
<h4>Java & Spring Boot, Thymeleaf Templating Engine, & MySQL.</h4>
|
|
29
29
|
</Carousel.Caption>
|
|
30
30
|
</a>
|
|
@@ -36,19 +36,19 @@ class ControlledCarousel extends Component {
|
|
|
36
36
|
<h1><u>booking-sys</u></h1>
|
|
37
37
|
<h2>Sample Reservations & Viewer System</h2>
|
|
38
38
|
<br /><br />
|
|
39
|
-
<
|
|
39
|
+
<h4>Tech Stack:</h4>
|
|
40
40
|
<h4>Python & Django Web App, JavaScript, SQLite3 or MySQL database.</h4>
|
|
41
41
|
</Carousel.Caption>
|
|
42
42
|
</a>
|
|
43
43
|
</Carousel.Item>
|
|
44
44
|
<Carousel.Item interval={500}>
|
|
45
|
-
<a href="https://github.com/
|
|
45
|
+
<a href="https://github.com/conorheffron/nba-stats" target="_blank" rel="noreferrer">
|
|
46
46
|
<img className="d-block w-100" src={navy} alt="navy3" />
|
|
47
47
|
<Carousel.Caption>
|
|
48
48
|
<h1><u>nba-stats</u></h1>
|
|
49
49
|
<h2>NBA Analytics (Seasons 2015 - 2023): Player Statistics</h2>
|
|
50
50
|
<br /><br />
|
|
51
|
-
<
|
|
51
|
+
<h4>Tech Stack:</h4>
|
|
52
52
|
<h4>Jupyter Notebooks, Python, Pandas, & Requests / JSON API.</h4>
|
|
53
53
|
</Carousel.Caption>
|
|
54
54
|
</a>
|
|
@@ -60,7 +60,7 @@ class ControlledCarousel extends Component {
|
|
|
60
60
|
<h1><u>cbio-skin-canc</u></h1>
|
|
61
61
|
<h2>Skin Cancer Dataset Analysis</h2>
|
|
62
62
|
<br /><br />
|
|
63
|
-
<
|
|
63
|
+
<h4>Tech Stack:</h4>
|
|
64
64
|
<h4>R, dplyr, plotly, knitr, testthat, covr, GIT.</h4>
|
|
65
65
|
</Carousel.Caption>
|
|
66
66
|
</a>
|
|
@@ -72,7 +72,7 @@ class ControlledCarousel extends Component {
|
|
|
72
72
|
<h1><u>gene-expr</u></h1>
|
|
73
73
|
<h2>Breast Cancer Dataset Analysis</h2>
|
|
74
74
|
<br /><br />
|
|
75
|
-
<
|
|
75
|
+
<h4>Tech Stack:</h4>
|
|
76
76
|
<h4>R, ggplot2, dplyr, deseq2-analysis, & R markdown.</h4>
|
|
77
77
|
</Carousel.Caption>
|
|
78
78
|
</a>
|
|
@@ -84,7 +84,7 @@ class ControlledCarousel extends Component {
|
|
|
84
84
|
<h1><u>bio-cell-red-edge</u></h1>
|
|
85
85
|
<h2>Edge Detection of Biological Cell (Image Processing Script)</h2>
|
|
86
86
|
<br /><br />
|
|
87
|
-
<
|
|
87
|
+
<h4>Tech Stack:</h4>
|
|
88
88
|
<h4>Python, sci-kit-image, matplotlib.pyplot, & scipy.ndimage.</h4>
|
|
89
89
|
</Carousel.Caption>
|
|
90
90
|
</a>
|
|
@@ -96,7 +96,7 @@ class ControlledCarousel extends Component {
|
|
|
96
96
|
<h1><u>global-max-sim-matrix</u></h1>
|
|
97
97
|
<h2>Compute Global Maximum Similarity Matrix</h2>
|
|
98
98
|
<br /><br />
|
|
99
|
-
<
|
|
99
|
+
<h4>Tech Stack:</h4>
|
|
100
100
|
<h4>R Package, testthat, stringr, & devtools.
|
|
101
101
|
</h4>
|
|
102
102
|
</Carousel.Caption>
|
package/src/components/Home.js
CHANGED
|
@@ -16,18 +16,19 @@ class Home extends Component {
|
|
|
16
16
|
<br /><br />
|
|
17
17
|
<a href="/"><img src={logo} className="App-logo" alt="iRonoc"/></a>
|
|
18
18
|
<p id="my-intro"> Welcome to my personal portfolio site.<br />
|
|
19
|
-
Please use the navigation bar to view different features such as about me, my
|
|
20
|
-
|
|
19
|
+
Please use the navigation bar to view different features such as <a href="/about">about</a> me, my
|
|
20
|
+
<a href="https://linktr.ee/conorheffron">link tree</a>, a <a href="/portfolio">carousel</a>
|
|
21
|
+
that scrolls through highlighted projects & the GitHub project manager (PM) tool which is built
|
|
21
22
|
against the iRonoc API.
|
|
22
23
|
<br /><br />
|
|
23
24
|
The GitHub PM tool allows you to view & navigate the backlog of issues & bugs for a given project
|
|
24
25
|
repository for the corresponding user or organisation account. There is an option to search by user ID
|
|
25
26
|
or to drill down to a specific repository name via search or 'List Issues' icon in the 'Actions' column
|
|
26
|
-
of the <a href="
|
|
27
|
+
of the <a href="/projects/conorheffron">projects component view</a>.
|
|
27
28
|
<br /><br />
|
|
28
|
-
The ironoc API is documented with
|
|
29
|
-
& sample GET requests that return raw JSON responses are available for demonstration
|
|
30
|
-
|
|
29
|
+
The ironoc API is documented with <a href="/swagger-ui-ironoc.html">Open API</a>
|
|
30
|
+
& sample GET requests that return raw JSON responses are available for demonstration
|
|
31
|
+
purposes only i.e. <a href="/get-repo-issue/conorheffron/ironoc/">Issues JSON Sample</a>.</p>
|
|
31
32
|
</header>
|
|
32
33
|
</Container>
|
|
33
34
|
<Footer/>
|
|
@@ -5,6 +5,7 @@ import Form from 'react-bootstrap/Form';
|
|
|
5
5
|
import AppNavbar from '.././AppNavbar';
|
|
6
6
|
import Footer from '.././Footer';
|
|
7
7
|
import { Link } from 'react-router-dom';
|
|
8
|
+
import LoadingSpinner from '.././LoadingSpinner';
|
|
8
9
|
|
|
9
10
|
class RepoDetails extends Component {
|
|
10
11
|
|
|
@@ -39,7 +40,16 @@ class RepoDetails extends Component {
|
|
|
39
40
|
const {repoDetailList, isLoading} = this.state;
|
|
40
41
|
|
|
41
42
|
if (isLoading) {
|
|
42
|
-
return
|
|
43
|
+
return (
|
|
44
|
+
<div className="App">
|
|
45
|
+
<AppNavbar/>
|
|
46
|
+
<Container>
|
|
47
|
+
<br /><br /><br />
|
|
48
|
+
<LoadingSpinner/>
|
|
49
|
+
</Container>
|
|
50
|
+
<Footer/>
|
|
51
|
+
</div>
|
|
52
|
+
);
|
|
43
53
|
}
|
|
44
54
|
|
|
45
55
|
let gitUser = this.props.match.params.id;
|
|
@@ -4,6 +4,7 @@ import '.././App.css';
|
|
|
4
4
|
import Form from 'react-bootstrap/Form';
|
|
5
5
|
import AppNavbar from '.././AppNavbar';
|
|
6
6
|
import Footer from '.././Footer';
|
|
7
|
+
import LoadingSpinner from '.././LoadingSpinner';
|
|
7
8
|
|
|
8
9
|
class RepoIssues extends Component {
|
|
9
10
|
|
|
@@ -39,8 +40,18 @@ class RepoIssues extends Component {
|
|
|
39
40
|
render() {
|
|
40
41
|
const {repoIssueList, isLoading} = this.state;
|
|
41
42
|
if (isLoading) {
|
|
42
|
-
return
|
|
43
|
+
return (
|
|
44
|
+
<div className="App">
|
|
45
|
+
<AppNavbar/>
|
|
46
|
+
<Container>
|
|
47
|
+
<br /><br /><br />
|
|
48
|
+
<LoadingSpinner/>
|
|
49
|
+
</Container>
|
|
50
|
+
<Footer/>
|
|
51
|
+
</div>
|
|
52
|
+
);
|
|
43
53
|
}
|
|
54
|
+
|
|
44
55
|
const repoList = repoIssueList.map(issue => {
|
|
45
56
|
let username = this.props.match.params.id
|
|
46
57
|
let repository = this.props.match.params.repo
|