Skip to content

Commit f9fe894

Browse files
authored
Merge pull request #59 from jackw/add-version-to-nav
Add version to side navbar. CLoses#59
2 parents a5c715a + bcb77ce commit f9fe894

File tree

8 files changed

+135
-59
lines changed

8 files changed

+135
-59
lines changed

src/actions/types.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
export const FETCH_STATUS = 'FETCH_STATUS';
22
export const GET_PROVIDERS = 'GET_PROVIDERS';
3+
export const GET_VERSION = 'GET_VERSION';
34
export const GET_CONFIG_FOR_REMOTE = 'GET_CONFIG_FOR_REMOTE';
45
export const GET_REMOTE_LIST = 'GET_REMOTE_LIST';
56
export const GET_CONFIG_DUMP = 'GET_CONFIG_DUMP';

src/actions/versionActions.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import axiosInstance from '../utils/API/API';
2+
import urls from '../utils/API/endpoint';
3+
import { GET_VERSION, REQUEST_SUCCESS, REQUEST_ERROR } from './types';
4+
5+
export const getVersion = () => {
6+
return dispatch => {
7+
axiosInstance.post(urls.getRcloneVersion).then(
8+
res =>
9+
dispatch({
10+
type: GET_VERSION,
11+
status: REQUEST_SUCCESS,
12+
payload: res.data
13+
}),
14+
error =>
15+
dispatch({
16+
type: GET_VERSION,
17+
status: REQUEST_ERROR,
18+
payload: error
19+
})
20+
);
21+
};
22+
};

src/containers/DefaultLayout/DefaultLayout.js

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React, {Component, Suspense} from 'react';
22
import {Redirect, Route, Switch} from 'react-router-dom';
33
import {Container} from 'reactstrap';
4+
import {getVersion} from "../../actions/versionActions";
45

56
import {
67
AppAside,
@@ -26,14 +27,34 @@ const DefaultAside = React.lazy(() => import('./DefaultAside'));
2627
const DefaultFooter = React.lazy(() => import('./DefaultFooter'));
2728
const DefaultHeader = React.lazy(() => import('./DefaultHeader'));
2829

30+
const VERSION_NAV_ITEM_ATTRS = {
31+
attributes: { target: '_blank' },
32+
class: 'mt-auto',
33+
icon: 'cui-cog',
34+
url: 'https://rclone.org/changelog',
35+
variant: 'success'
36+
}
2937
class DefaultLayout extends Component {
3038

3139
loading = () => <div className="animated fadeIn pt-1 text-center">Loading...</div>;
3240

41+
get navConfig() {
42+
return {
43+
items: [
44+
...navigation.items,
45+
{
46+
name: this.props.version.version,
47+
...VERSION_NAV_ITEM_ATTRS
48+
}
49+
]
50+
}
51+
}
3352

3453
componentWillMount() {
3554
if (!localStorage.getItem(AUTH_KEY)) {
3655
this.props.history.push('/login');
56+
} else {
57+
this.props.getVersion();
3758
}
3859
}
3960

@@ -54,7 +75,7 @@ class DefaultLayout extends Component {
5475
<AppSidebarHeader/>
5576
<AppSidebarForm/>
5677
<Suspense fallback={this.loading()}>
57-
<AppSidebarNav navConfig={navigation} {...this.props} />
78+
<AppSidebarNav navConfig={this.navConfig} />
5879
</Suspense>
5980
<AppSidebarFooter/>
6081
<AppSidebarMinimizer/>
@@ -102,6 +123,7 @@ class DefaultLayout extends Component {
102123

103124
const mapStateToProps = (state) => ({
104125
isConnected: state.status.isConnected,
126+
version: state.version,
105127
});
106128

107-
export default connect(mapStateToProps, {})(DefaultLayout);
129+
export default connect(mapStateToProps, { getVersion })(DefaultLayout);

src/containers/DefaultLayout/__snapshots__/DefaultLayout.test.js.snap

Lines changed: 10 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -52,24 +52,6 @@ exports[`Remote Explorer renders should match snapshot 1`] = `
5252
}
5353
>
5454
<AppSidebarNav
55-
history={
56-
Object {
57-
"push": [MockFunction] {
58-
"calls": Array [
59-
Array [
60-
"/login",
61-
],
62-
],
63-
"results": Array [
64-
Object {
65-
"type": "return",
66-
"value": undefined,
67-
},
68-
],
69-
},
70-
}
71-
}
72-
isConnected={true}
7355
isOpen={false}
7456
navConfig={
7557
Object {
@@ -99,18 +81,19 @@ exports[`Remote Explorer renders should match snapshot 1`] = `
9981
"name": "Log Out",
10082
"url": "/login",
10183
},
84+
Object {
85+
"attributes": Object {
86+
"target": "_blank",
87+
},
88+
"class": "mt-auto",
89+
"icon": "cui-cog",
90+
"name": "",
91+
"url": "https://rclone.org/changelog",
92+
"variant": "success",
93+
},
10294
],
10395
}
10496
}
105-
store={
106-
Object {
107-
"dispatch": [Function],
108-
"getState": [Function],
109-
"replaceReducer": [Function],
110-
"subscribe": [Function],
111-
Symbol(observable): [Function],
112-
}
113-
}
11497
tag="nav"
11598
/>
11699
</Suspense>

src/reducers/index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {SIGNOUT_REQUEST} from "../actions/types";
88
import providerStatusReducer from "./providerStatusReducer";
99
import userActionsReducer from "./userActionsReducer";
1010
import imagesReducer from "./imagesReducer";
11+
import versionReducer from "./versionReducer";
1112

1213
/**
1314
* Configures the root reducer to be executed before any other reducers configured in the system.
@@ -36,7 +37,8 @@ const appReducer = combineReducers({
3637
explorer: explorerState,
3738
providerStatus: providerStatusReducer,
3839
user: userActionsReducer,
39-
imageLoader: imagesReducer
40+
imageLoader: imagesReducer,
41+
version: versionReducer
4042
// remoteOps: remoteOpsReducer
4143
});
4244

src/reducers/versionReducer.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { GET_VERSION, REQUEST_ERROR, REQUEST_SUCCESS } from '../actions/types';
2+
3+
export const initialState = {
4+
arch: '',
5+
decomposed: [],
6+
goVersion: '',
7+
isGit: false,
8+
os: '',
9+
version: '',
10+
hasError: false
11+
};
12+
13+
export default (state = initialState, action) => {
14+
if (action.type === GET_VERSION) {
15+
if (action.status === REQUEST_SUCCESS) {
16+
return {
17+
...state,
18+
...action.payload,
19+
hasError: false
20+
};
21+
}
22+
if (action.status === REQUEST_ERROR) {
23+
return {
24+
...state,
25+
error: action.payload,
26+
hasError: true
27+
};
28+
}
29+
}
30+
31+
return state;
32+
};

src/reducers/versionReducer.test.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import versionReducer, { initialState } from './versionReducer';
2+
import { GET_VERSION, REQUEST_SUCCESS } from '../actions/types';
3+
4+
describe('Explorer Reducer', function() {
5+
it('should return default state', function() {
6+
const newState = versionReducer(undefined, {});
7+
expect(newState).toEqual(initialState);
8+
});
9+
10+
it('should return version information', function() {
11+
const payload = {
12+
arch: 'amd64',
13+
decomposed: [1, 50, 2],
14+
goVersion: 'go1.13.4',
15+
isGit: false,
16+
os: 'darwin',
17+
version: 'v1.50.2',
18+
hasError: false
19+
};
20+
const newState = versionReducer(undefined, {
21+
type: GET_VERSION,
22+
status: REQUEST_SUCCESS,
23+
payload: payload
24+
});
25+
expect(newState).toEqual(payload);
26+
});
27+
28+
});

src/views/RCloneDashboard/RCloneDashboard.js

Lines changed: 15 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,25 @@
11
import React from 'react';
2+
import {connect} from "react-redux";
23
import {Card, CardBody, CardHeader, Col, Container, Form, FormGroup, Input, Label, Row} from "reactstrap";
34
import axiosInstance from "../../utils/API/API";
45
import ErrorBoundary from "../../ErrorHandling/ErrorBoundary";
56
import urls from "../../utils/API/endpoint";
67

7-
8-
function RCloneVersion({data, hasError}) {
9-
if (hasError) {
8+
function RCloneVersion({data}) {
9+
if (data.hasError) {
1010
return (<p>Error loading.</p>);
1111
}
12+
1213
return (
1314
<Col sm={12} lg={4} md={6}>
1415
<Card>
1516
<CardHeader>Version</CardHeader>
1617
<CardBody>
17-
<p><strong>Arch:</strong>{data.arch}</p>
18-
<p><strong>goVersion:</strong>{data.goVersion}</p>
19-
<p><strong>OS:</strong>{data.os}</p>
20-
<p><strong>Rclone version:</strong>{data.version}</p>
21-
<p><strong>isGit:</strong>{data.isGit}</p>
18+
<p><strong>Arch: </strong>{data.arch}</p>
19+
<p><strong>goVersion: </strong>{data.goVersion}</p>
20+
<p><strong>OS: </strong>{data.os}</p>
21+
<p><strong>Rclone version: </strong>{data.version}</p>
22+
<p><strong>isGit: </strong>{`${data.isGit}`}</p>
2223
</CardBody>
2324
</Card>
2425
</Col>
@@ -27,19 +28,6 @@ function RCloneVersion({data, hasError}) {
2728

2829

2930
class RCloneDashboard extends React.Component {
30-
31-
getRcloneStatus = () => {
32-
axiosInstance.post(urls.getRcloneVersion).then((res) => {
33-
this.setState({
34-
version: res.data,
35-
hasError: false
36-
})
37-
}, () => {
38-
this.setState({
39-
hasError: true
40-
})
41-
})
42-
};
4331
getMemStats = () => {
4432
axiosInstance.post(urls.getRcloneMemStats).then((res) => {
4533
this.setState({
@@ -124,14 +112,12 @@ class RCloneDashboard extends React.Component {
124112
};
125113

126114
componentDidMount() {
127-
this.getRcloneStatus();
128115
this.getOptions();
129116
}
130117

131118
constructor(props, context) {
132119
super(props, context);
133120
this.state = {
134-
version: {},
135121
hasError: false,
136122
memStats: {},
137123
options: {}
@@ -145,8 +131,7 @@ class RCloneDashboard extends React.Component {
145131
<ErrorBoundary>
146132
<Container fluid={true}>
147133
<Row>
148-
<RCloneVersion data={this.state.version} hasError={this.state.hasError}/>
149-
134+
<RCloneVersion data={this.props.version} />
150135
</Row>
151136
{this.getOptionsView()}
152137
</Container>
@@ -155,8 +140,9 @@ class RCloneDashboard extends React.Component {
155140
}
156141
}
157142

158-
// const mapStateToProps = state => ({
159-
//
160-
// });
143+
const mapStateToProps = state => ({
144+
version: state.version,
145+
});
146+
147+
export default connect(mapStateToProps)(RCloneDashboard);
161148

162-
export default RCloneDashboard;

0 commit comments

Comments
 (0)