Skip to content

Commit c57b929

Browse files
committed
mount: Add mount dashboard.
1 parent da8e596 commit c57b929

File tree

23 files changed

+3451
-4062
lines changed

23 files changed

+3451
-4062
lines changed

package-lock.json

Lines changed: 2709 additions & 4019 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
2-
"name": "@rclone/rclone-webui",
3-
"version": "0.0.6",
2+
"name": "@rclone/rclone-webui-react",
3+
"version": "2.0.1",
44
"description": "A web interface for r-clone",
55
"author": "Chaitanya Bankanhal",
66
"copyright": "",
@@ -23,12 +23,12 @@
2323
"core-js": "^3.6.5",
2424
"flag-icon-css": "^3.4.6",
2525
"font-awesome": "^4.7.0",
26-
"jquery": "^3.4.1",
26+
"jquery": "^3.5.1",
2727
"lodash": "^4.17.14",
28-
"node-sass": "^4.13.1",
28+
"node-sass": "^4.14.1",
2929
"package.json": "^2.0.1",
3030
"prop-types": "^15.7.2",
31-
"rclone-api": "^1.0.0",
31+
"rclone-api": "^1.0.7",
3232
"react": "^16.12.0",
3333
"react-app-polyfill": "^1.0.6",
3434
"react-autosuggest": "^10.0.0",
@@ -51,6 +51,7 @@
5151
"typescript": "^3.7.5"
5252
},
5353
"devDependencies": {
54+
"@babel/core": "^7.10.2",
5455
"check-prop-types": "^1.1.2",
5556
"coveralls": "^3.0.9",
5657
"enzyme": "^3.11.0",

src/_nav.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ export default {
2020
url: '/rcloneBackend',
2121
icon: 'icon-star',
2222
},
23+
{
24+
name: 'Mounts',
25+
url: '/mountDashboard',
26+
icon: 'fa fa-hdd-o'
27+
},
2328
{
2429
name: 'Log Out',
2530
url: '/login',

src/actions/mountActions.js

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import axiosInstance from "../utils/API/API";
2+
import urls from "../utils/API/endpoint";
3+
import {CREATE_MOUNT, GET_MOUNT_LIST, REMOVE_MOUNT, REQUEST_ERROR, REQUEST_SUCCESS} from "./types";
4+
5+
/**
6+
* Get the current mount lists and load into state
7+
* @returns {function(...[*]=)}
8+
*/
9+
export const getMountList = () => {
10+
return (dispatch) => {
11+
axiosInstance.post(urls.listMounts).then(res => {
12+
console.log(res);
13+
dispatch({
14+
type: GET_MOUNT_LIST,
15+
status: REQUEST_SUCCESS,
16+
payload: res.data
17+
})
18+
}, (error) => {
19+
dispatch({
20+
type: GET_MOUNT_LIST,
21+
status: REQUEST_ERROR,
22+
payload: error
23+
})
24+
})
25+
}
26+
}
27+
28+
/**
29+
* Add a new mount location
30+
* @param fs {string} Name of the remote eg mydrive:
31+
* @param mountPoint {string} Path to mount on the local filesystem where rclone is running
32+
* @param mountType {string} One of "cmount", "mount", "mount2": Specifies what mountType rclone should use
33+
* @returns {function(...[*]=)}
34+
*/
35+
export const addMount = (fs, mountPoint, mountType) => {
36+
if (!fs.endsWith(":")) fs = fs + ":";
37+
const type = CREATE_MOUNT
38+
return (dispatch) => {
39+
axiosInstance.post(urls.createMount, {fs, mountPoint, mountType}).then(res => {
40+
dispatch({
41+
type,
42+
status: REQUEST_SUCCESS,
43+
payload: res.data
44+
})
45+
}, (error) => {
46+
dispatch({
47+
type,
48+
status: REQUEST_ERROR,
49+
payload: error
50+
})
51+
})
52+
dispatch(getMountList());
53+
54+
}
55+
}
56+
57+
/**
58+
* unmount removes an mounted location "mountPoint"
59+
* @param mountPoint {string} Path to location where the mount was created.
60+
* @returns {function(...[*]=)}
61+
*/
62+
export const unmount = (mountPoint) => {
63+
const type = REMOVE_MOUNT;
64+
return (dispatch) => {
65+
axiosInstance.post(urls.removeMount, {mountPoint}).then(res => {
66+
dispatch({
67+
type,
68+
status: REQUEST_SUCCESS,
69+
payload: res.data
70+
})
71+
72+
}, (error) => {
73+
dispatch({
74+
type,
75+
status: REQUEST_ERROR,
76+
payload: error
77+
})
78+
})
79+
dispatch(getMountList());
80+
}
81+
}
82+
83+
84+
/**
85+
* unmountAll removes all mounts created by mount/mount
86+
* @returns {function(...[*]=)}
87+
*/
88+
export const unmountAll = () => {
89+
const type = REMOVE_MOUNT;
90+
return (dispatch) => {
91+
axiosInstance.post(urls.unmountAll).then(res => {
92+
dispatch({
93+
type,
94+
status: REQUEST_SUCCESS,
95+
payload: res.data
96+
})
97+
98+
}, (error) => {
99+
dispatch({
100+
type,
101+
status: REQUEST_ERROR,
102+
payload: error
103+
})
104+
})
105+
dispatch(getMountList());
106+
}
107+
}

src/actions/types.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ export const CHANGE_DISTRACTION_FREE_MODE = "CHANGE_DISTRACTION_FREE_MODE";
3838
export const CHANGE_SORT_FILTER = "CHANGE_SORT_FILTER";
3939

4040

41+
export const GET_MOUNT_LIST = "GET_MOUNT_LIST";
42+
export const REMOVE_MOUNT = "REMOVE_MOUNT";
43+
export const CREATE_MOUNT = "CREATE_MOUNT";
44+
4145
export const REQUEST_ERROR = 'ERROR';
4246
export const REQUEST_SUCCESS = 'SUCCESS';
4347
export const REQUEST_LOADING = 'LOADING';

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

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ exports[`Remote Explorer renders should match snapshot 1`] = `
7676
"name": "Backend",
7777
"url": "/rcloneBackend",
7878
},
79+
Object {
80+
"icon": "fa fa-hdd-o",
81+
"name": "Mounts",
82+
"url": "/mountDashboard",
83+
},
7984
Object {
8085
"icon": "icon-logout",
8186
"name": "Log Out",
@@ -199,6 +204,16 @@ exports[`Remote Explorer renders should match snapshot 1`] = `
199204
"name": "Rclone Backend",
200205
"path": "/rcloneBackend",
201206
},
207+
Object {
208+
"component": Object {
209+
"$$typeof": Symbol(react.lazy),
210+
"_ctor": [Function],
211+
"_result": null,
212+
"_status": -1,
213+
},
214+
"name": "Mount Dashboard",
215+
"path": "/mountDashboard",
216+
},
202217
]
203218
}
204219
className=""
@@ -269,9 +284,15 @@ exports[`Remote Explorer renders should match snapshot 1`] = `
269284
path="/rcloneBackend"
270285
render={[Function]}
271286
/>
287+
<Route
288+
key="9"
289+
name="Mount Dashboard"
290+
path="/mountDashboard"
291+
render={[Function]}
292+
/>
272293
<Redirect
273294
from="/"
274-
to="/login"
295+
to="/dashboard"
275296
/>
276297
</Switch>
277298
</Suspense>

src/reducers/index.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import providerStatusReducer from "./providerStatusReducer";
99
import userActionsReducer from "./userActionsReducer";
1010
import imagesReducer from "./imagesReducer";
1111
import versionReducer from "./versionReducer";
12+
import mountReducer from "./mountReducer";
1213

1314
/**
1415
* Configures the root reducer to be executed before any other reducers configured in the system.
@@ -38,8 +39,9 @@ const appReducer = combineReducers({
3839
providerStatus: providerStatusReducer,
3940
user: userActionsReducer,
4041
imageLoader: imagesReducer,
41-
version: versionReducer
42+
version: versionReducer,
43+
mount: mountReducer,
4244
// remoteOps: remoteOpsReducer
4345
});
4446

45-
export default rootReducer;
47+
export default rootReducer;

src/reducers/mountReducer.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import {CREATE_MOUNT, GET_MOUNT_LIST, REMOVE_MOUNT, REQUEST_ERROR, REQUEST_SUCCESS} from "../actions/types";
2+
import {toast} from "react-toastify";
3+
4+
const initialState = {
5+
currentMounts: [],
6+
mountError: null
7+
};
8+
9+
export default function (state = initialState, action) {
10+
switch (action.type) {
11+
case CREATE_MOUNT:
12+
if (action.status === REQUEST_SUCCESS) {
13+
toast.info('Mount Success');
14+
} else if (action.status === REQUEST_ERROR) {
15+
toast.error('Error creating mount ' + action.payload);
16+
}
17+
break;
18+
case GET_MOUNT_LIST:
19+
if (action.status === REQUEST_SUCCESS) {
20+
return {
21+
...state,
22+
currentMounts: action.payload.mountPoints
23+
}
24+
} else if (action.status === REQUEST_ERROR) {
25+
return {
26+
...state,
27+
currentMounts: [],
28+
mountError: action.payload
29+
}
30+
}
31+
break;
32+
case REMOVE_MOUNT:
33+
if (action.status === REQUEST_SUCCESS) {
34+
toast.info('Unmount success');
35+
} else if (action.status === REQUEST_ERROR) {
36+
toast.error("Couldn't remove mount");
37+
}
38+
break;
39+
default:
40+
return state;
41+
}
42+
return state
43+
}

src/routes.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const ShowConfig = React.lazy(() => import('./views/RemoteManagement/ShowConfig'
66
const RemoteExplorerLayout = React.lazy(() => import("./views/Explorer/RemoteExplorerLayout"));
77
const Login = React.lazy(() => import("./views/Pages/Login"));
88
const RCloneDashboard = React.lazy(() => import("./views/RCloneDashboard"));
9+
const MountDashboard = React.lazy(() => import("./views/MountDashboard"));
910

1011
// https://github.com/ReactTraining/react-router/tree/master/packages/react-router-config
1112
// Define the routes as required
@@ -19,6 +20,7 @@ const routes = [
1920
{path: '/remoteExplorer/:remoteName/:remotePath', exact: true, name: 'Explorer', component: RemoteExplorerLayout},
2021
{path: '/remoteExplorer', name: 'Explorer', component: RemoteExplorerLayout},
2122
{path: '/rcloneBackend', name: 'Rclone Backend', component: RCloneDashboard},
23+
{path: '/mountDashboard', name: 'Mount Dashboard', component: MountDashboard},
2224

2325
];
2426

src/utils/API/endpoint.js

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -97,25 +97,46 @@ const urls = {
9797
/**
9898
* List the remote names of created remotes.
9999
*/
100-
listRemotes: "config/listremotes",
101-
/**
102-
* Get the files for given remoteName and path.
103-
*/
104-
getFilesList: "operations/list",
100+
listRemotes: "config/listremotes",
101+
/**
102+
* Get the files for given remoteName and path.
103+
*/
104+
getFilesList: "operations/list",
105+
106+
/**
107+
* Get information about the rclone backend.
108+
*/
109+
getAbout: "operations/about",
110+
/**
111+
* Delete a config with config name.
112+
*/
113+
deleteConfig: "config/delete",
114+
115+
/**
116+
* Stop a running job by job id
117+
*/
118+
stopJob: "job/stop",
119+
120+
121+
/**
122+
* List all the current mounts
123+
*/
124+
listMounts: "mount/listmounts",
105125

106126
/**
107-
* Get information about the rclone backend.
127+
* Create a new mount (mount)
108128
*/
109-
getAbout: "operations/about",
129+
createMount: "mount/mount",
130+
110131
/**
111-
* Delete a config with config name.
132+
* Delete a created mount(unmount)
112133
*/
113-
deleteConfig: "config/delete",
134+
removeMount: "mount/unmount",
114135

115136
/**
116-
* Stop a running job by job id
137+
* Delete all created mounts(unmount)
117138
*/
118-
stopJob: "job/stop",
139+
unmountAll: "mount/unmountall",
119140

120141
};
121142
export default urls;

0 commit comments

Comments
 (0)