mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-09 11:03:00 +00:00
Combine API props, update tests for redux hooks
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -29,3 +29,4 @@ htmlcov
|
|||||||
pip-wheel-metadata
|
pip-wheel-metadata
|
||||||
docs/source/reference/metrics.rst
|
docs/source/reference/metrics.rst
|
||||||
oldest-requirements.txt
|
oldest-requirements.txt
|
||||||
|
jupyterhub-proxy.pid
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"extends": ["plugin:react/recommended"],
|
"extends": ["plugin:react/recommended"],
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"ecmaVersion": 6,
|
"ecmaVersion": 2018,
|
||||||
"sourceType": "module",
|
"sourceType": "module",
|
||||||
"ecmaFeatures": {
|
"ecmaFeatures": {
|
||||||
"jsx": true
|
"jsx": true
|
||||||
|
@@ -2,11 +2,11 @@ import React, { Component, useEffect } from "react";
|
|||||||
import ReactDOM from "react-dom";
|
import ReactDOM from "react-dom";
|
||||||
import { Provider } from "react-redux";
|
import { Provider } from "react-redux";
|
||||||
import { createStore } from "redux";
|
import { createStore } from "redux";
|
||||||
import { Button } from "react-bootstrap";
|
import { compose } from "recompose";
|
||||||
import { initialState, reducers } from "./Store";
|
import { initialState, reducers } from "./Store";
|
||||||
import { jhapiRequest } from "./util/jhapiUtil";
|
import { jhapiRequest } from "./util/jhapiUtil";
|
||||||
|
import withAPI from "./util/withAPI";
|
||||||
import { HashRouter, Switch, Route, Link } from "react-router-dom";
|
import { HashRouter, Switch, Route, Link } from "react-router-dom";
|
||||||
import { createBrowserHistory } from "history";
|
|
||||||
|
|
||||||
import ServerDashboard from "./components/ServerDashboard/ServerDashboard";
|
import ServerDashboard from "./components/ServerDashboard/ServerDashboard";
|
||||||
import Groups from "./components/Groups/Groups";
|
import Groups from "./components/Groups/Groups";
|
||||||
@@ -37,12 +37,32 @@ const App = (props) => {
|
|||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<HashRouter>
|
<HashRouter>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route exact path="/" component={ServerDashboard} />
|
<Route
|
||||||
<Route exact path="/groups" component={Groups} />
|
exact
|
||||||
<Route exact path="/group-edit" component={GroupEdit} />
|
path="/"
|
||||||
<Route exact path="/create-group" component={CreateGroup} />
|
component={compose(withAPI)(ServerDashboard)}
|
||||||
<Route exact path="/add-users" component={AddUser} />
|
/>
|
||||||
<Route exact path="/edit-user" component={EditUser} />
|
<Route exact path="/groups" component={compose(withAPI)(Groups)} />
|
||||||
|
<Route
|
||||||
|
exact
|
||||||
|
path="/group-edit"
|
||||||
|
component={compose(withAPI)(GroupEdit)}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
exact
|
||||||
|
path="/create-group"
|
||||||
|
component={compose(withAPI)(CreateGroup)}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
exact
|
||||||
|
path="/add-users"
|
||||||
|
component={compose(withAPI)(AddUser)}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
exact
|
||||||
|
path="/edit-user"
|
||||||
|
component={compose(withAPI)(EditUser)}
|
||||||
|
/>
|
||||||
</Switch>
|
</Switch>
|
||||||
</HashRouter>
|
</HashRouter>
|
||||||
</Provider>
|
</Provider>
|
||||||
|
@@ -107,17 +107,4 @@ AddUser.propTypes = {
|
|||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
const withUserAPI = withProps((props) => ({
|
export default AddUser;
|
||||||
addUsers: (usernames, admin) =>
|
|
||||||
jhapiRequest("/users", "POST", { usernames, admin }),
|
|
||||||
failRegexEvent: () =>
|
|
||||||
alert(
|
|
||||||
"Removed " +
|
|
||||||
JSON.stringify(removed_users) +
|
|
||||||
" for either containing special characters or being too short."
|
|
||||||
),
|
|
||||||
refreshUserData: () =>
|
|
||||||
jhapiRequest("/users", "GET").then((data) => data.json()),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export default compose(withUserAPI)(AddUser);
|
|
||||||
|
@@ -1,31 +1,53 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Enzyme, { shallow } from "enzyme";
|
import Enzyme, { mount } from "enzyme";
|
||||||
import AddUser from "./AddUser.pre";
|
import AddUser from "./AddUser";
|
||||||
import Adapter from "@wojtekmaj/enzyme-adapter-react-17";
|
import Adapter from "@wojtekmaj/enzyme-adapter-react-17";
|
||||||
|
import { Provider, useDispatch } from "react-redux";
|
||||||
|
import { createStore } from "redux";
|
||||||
|
import { HashRouter } from "react-router-dom";
|
||||||
|
|
||||||
Enzyme.configure({ adapter: new Adapter() });
|
Enzyme.configure({ adapter: new Adapter() });
|
||||||
|
|
||||||
|
jest.mock("react-redux", () => ({
|
||||||
|
...jest.requireActual("react-redux"),
|
||||||
|
useDispatch: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
describe("AddUser Component: ", () => {
|
describe("AddUser Component: ", () => {
|
||||||
var mockAsync = () =>
|
var mockAsync = () =>
|
||||||
jest.fn().mockImplementation(() => Promise.resolve({ key: "value" }));
|
jest.fn().mockImplementation(() => Promise.resolve({ key: "value" }));
|
||||||
|
|
||||||
var addUserJsx = (callbackSpy) => (
|
var addUserJsx = (callbackSpy) => (
|
||||||
<AddUser
|
<Provider store={createStore(() => {}, {})}>
|
||||||
addUsers={callbackSpy}
|
<HashRouter>
|
||||||
failRegexEvent={callbackSpy}
|
<AddUser
|
||||||
refreshUserData={callbackSpy}
|
addUsers={callbackSpy}
|
||||||
history={{ push: (a) => {} }}
|
failRegexEvent={callbackSpy}
|
||||||
/>
|
refreshUserData={callbackSpy}
|
||||||
|
history={{ push: (a) => {} }}
|
||||||
|
/>
|
||||||
|
</HashRouter>
|
||||||
|
</Provider>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
useDispatch.mockImplementation((callback) => {
|
||||||
|
return () => {};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
useDispatch.mockClear();
|
||||||
|
});
|
||||||
|
|
||||||
it("Renders", () => {
|
it("Renders", () => {
|
||||||
let component = shallow(addUserJsx(mockAsync()));
|
let component = mount(addUserJsx(mockAsync()));
|
||||||
expect(component.find(".container").length).toBe(1);
|
expect(component.find(".container").length).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Removes users when they fail Regex", () => {
|
it("Removes users when they fail Regex", () => {
|
||||||
let callbackSpy = mockAsync(),
|
let callbackSpy = mockAsync(),
|
||||||
component = shallow(addUserJsx(callbackSpy)),
|
component = mount(addUserJsx(callbackSpy)),
|
||||||
textarea = component.find("textarea").first();
|
textarea = component.find("textarea").first();
|
||||||
textarea.simulate("blur", { target: { value: "foo\nbar\n!!*&*" } });
|
textarea.simulate("blur", { target: { value: "foo\nbar\n!!*&*" } });
|
||||||
let submit = component.find("#submit");
|
let submit = component.find("#submit");
|
||||||
@@ -35,7 +57,7 @@ describe("AddUser Component: ", () => {
|
|||||||
|
|
||||||
it("Correctly submits admin", () => {
|
it("Correctly submits admin", () => {
|
||||||
let callbackSpy = mockAsync(),
|
let callbackSpy = mockAsync(),
|
||||||
component = shallow(addUserJsx(callbackSpy)),
|
component = mount(addUserJsx(callbackSpy)),
|
||||||
input = component.find("input").first();
|
input = component.find("input").first();
|
||||||
input.simulate("change", { target: { checked: true } });
|
input.simulate("change", { target: { checked: true } });
|
||||||
let submit = component.find("#submit");
|
let submit = component.find("#submit");
|
||||||
|
@@ -81,16 +81,4 @@ CreateGroup.propTypes = {
|
|||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
const withGroupsAPI = withProps((props) => ({
|
export default CreateGroup;
|
||||||
createGroup: (groupName) => jhapiRequest("/groups/" + groupName, "POST"),
|
|
||||||
failRegexEvent: () =>
|
|
||||||
alert(
|
|
||||||
"Removed " +
|
|
||||||
JSON.stringify(removed_users) +
|
|
||||||
" for either containing special characters or being too short."
|
|
||||||
),
|
|
||||||
refreshGroupsData: () =>
|
|
||||||
jhapiRequest("/groups", "GET").then((data) => data.json()),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export default compose(withGroupsAPI)(CreateGroup);
|
|
||||||
|
@@ -1,30 +1,52 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Enzyme, { mount, shallow } from "enzyme";
|
import Enzyme, { mount } from "enzyme";
|
||||||
import CreateGroup from "./CreateGroup.pre";
|
import CreateGroup from "./CreateGroup";
|
||||||
import Adapter from "@wojtekmaj/enzyme-adapter-react-17";
|
import Adapter from "@wojtekmaj/enzyme-adapter-react-17";
|
||||||
|
import { Provider, useDispatch } from "react-redux";
|
||||||
|
import { createStore } from "redux";
|
||||||
|
import { HashRouter } from "react-router-dom";
|
||||||
|
|
||||||
Enzyme.configure({ adapter: new Adapter() });
|
Enzyme.configure({ adapter: new Adapter() });
|
||||||
|
|
||||||
|
jest.mock("react-redux", () => ({
|
||||||
|
...jest.requireActual("react-redux"),
|
||||||
|
useDispatch: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
describe("CreateGroup Component: ", () => {
|
describe("CreateGroup Component: ", () => {
|
||||||
var mockAsync = () =>
|
var mockAsync = () =>
|
||||||
jest.fn().mockImplementation(() => Promise.resolve({ key: "value" }));
|
jest.fn().mockImplementation(() => Promise.resolve({ key: "value" }));
|
||||||
|
|
||||||
var createGroupJsx = (callbackSpy) => (
|
var createGroupJsx = (callbackSpy) => (
|
||||||
<CreateGroup
|
<Provider store={createStore(() => {}, {})}>
|
||||||
createGroup={callbackSpy}
|
<HashRouter>
|
||||||
refreshGroupsData={callbackSpy}
|
<CreateGroup
|
||||||
history={{ push: () => {} }}
|
createGroup={callbackSpy}
|
||||||
/>
|
refreshGroupsData={callbackSpy}
|
||||||
|
history={{ push: () => {} }}
|
||||||
|
/>
|
||||||
|
</HashRouter>
|
||||||
|
</Provider>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
useDispatch.mockImplementation((callback) => {
|
||||||
|
return () => {};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
useDispatch.mockClear();
|
||||||
|
});
|
||||||
|
|
||||||
it("Renders", () => {
|
it("Renders", () => {
|
||||||
let component = shallow(createGroupJsx());
|
let component = mount(createGroupJsx());
|
||||||
expect(component.find(".container").length).toBe(1);
|
expect(component.find(".container").length).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Calls createGroup and refreshGroupsData on submit", () => {
|
it("Calls createGroup and refreshGroupsData on submit", () => {
|
||||||
let callbackSpy = mockAsync(),
|
let callbackSpy = mockAsync(),
|
||||||
component = shallow(createGroupJsx(callbackSpy)),
|
component = mount(createGroupJsx(callbackSpy)),
|
||||||
input = component.find("input").first(),
|
input = component.find("input").first(),
|
||||||
submit = component.find("#submit").first();
|
submit = component.find("#submit").first();
|
||||||
input.simulate("change", { target: { value: "" } });
|
input.simulate("change", { target: { value: "" } });
|
||||||
|
@@ -1,12 +1,8 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useSelector, useDispatch } from "react-redux";
|
import { useDispatch } from "react-redux";
|
||||||
import { compose, withProps } from "recompose";
|
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
|
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
import { jhapiRequest } from "../../util/jhapiUtil";
|
|
||||||
|
|
||||||
const EditUser = (props) => {
|
const EditUser = (props) => {
|
||||||
var dispatch = useDispatch();
|
var dispatch = useDispatch();
|
||||||
|
|
||||||
@@ -160,22 +156,4 @@ EditUser.propTypes = {
|
|||||||
refreshUserData: PropTypes.func,
|
refreshUserData: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
const withUserAPI = withProps((props) => ({
|
export default EditUser;
|
||||||
editUser: (username, updated_username, admin) =>
|
|
||||||
jhapiRequest("/users/" + username, "PATCH", {
|
|
||||||
name: updated_username,
|
|
||||||
admin,
|
|
||||||
}),
|
|
||||||
deleteUser: (username) => jhapiRequest("/users/" + username, "DELETE"),
|
|
||||||
failRegexEvent: () =>
|
|
||||||
alert(
|
|
||||||
"Cannot change username - either contains special characters or is too short."
|
|
||||||
),
|
|
||||||
noChangeEvent: () => {
|
|
||||||
returns;
|
|
||||||
},
|
|
||||||
refreshUserData: () =>
|
|
||||||
jhapiRequest("/users", "GET").then((data) => data.json()),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export default compose(withUserAPI)(EditUser);
|
|
||||||
|
@@ -1,30 +1,54 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Enzyme, { shallow } from "enzyme";
|
import Enzyme, { mount } from "enzyme";
|
||||||
import EditUser from "./EditUser.pre";
|
import EditUser from "./EditUser";
|
||||||
import Adapter from "@wojtekmaj/enzyme-adapter-react-17";
|
import Adapter from "@wojtekmaj/enzyme-adapter-react-17";
|
||||||
|
import { Provider, useDispatch } from "react-redux";
|
||||||
|
import { createStore } from "redux";
|
||||||
|
import { HashRouter } from "react-router-dom";
|
||||||
|
|
||||||
Enzyme.configure({ adapter: new Adapter() });
|
Enzyme.configure({ adapter: new Adapter() });
|
||||||
|
|
||||||
|
jest.mock("react-redux", () => ({
|
||||||
|
...jest.requireActual("react-redux"),
|
||||||
|
useDispatch: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
describe("EditUser Component: ", () => {
|
describe("EditUser Component: ", () => {
|
||||||
var mockAsync = () =>
|
var mockAsync = () =>
|
||||||
jest.fn().mockImplementation(() => Promise.resolve({ key: "value" }));
|
jest.fn().mockImplementation(() => Promise.resolve({ key: "value" }));
|
||||||
var mockSync = () => jest.fn();
|
var mockSync = () => jest.fn();
|
||||||
|
|
||||||
var editUserJsx = (callbackSpy) => (
|
var editUserJsx = (callbackSpy, empty) => (
|
||||||
<EditUser
|
<Provider store={createStore(() => {}, {})}>
|
||||||
location={{ state: { username: "foo", has_admin: false } }}
|
<HashRouter>
|
||||||
deleteUser={callbackSpy}
|
<EditUser
|
||||||
editUser={callbackSpy}
|
location={
|
||||||
refreshUserData={mockSync()}
|
empty ? {} : { state: { username: "foo", has_admin: false } }
|
||||||
history={{ push: (a) => {} }}
|
}
|
||||||
failRegexEvent={callbackSpy}
|
deleteUser={callbackSpy}
|
||||||
noChangeEvent={callbackSpy}
|
editUser={callbackSpy}
|
||||||
/>
|
refreshUserData={callbackSpy}
|
||||||
|
history={{ push: (a) => {} }}
|
||||||
|
failRegexEvent={callbackSpy}
|
||||||
|
noChangeEvent={callbackSpy}
|
||||||
|
/>
|
||||||
|
</HashRouter>
|
||||||
|
</Provider>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
useDispatch.mockImplementation((callback) => {
|
||||||
|
return () => {};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
useDispatch.mockClear();
|
||||||
|
});
|
||||||
|
|
||||||
it("Calls the delete user function when the button is pressed", () => {
|
it("Calls the delete user function when the button is pressed", () => {
|
||||||
let callbackSpy = mockAsync(),
|
let callbackSpy = mockAsync(),
|
||||||
component = shallow(editUserJsx(callbackSpy)),
|
component = mount(editUserJsx(callbackSpy)),
|
||||||
deleteUser = component.find("#delete-user");
|
deleteUser = component.find("#delete-user");
|
||||||
deleteUser.simulate("click");
|
deleteUser.simulate("click");
|
||||||
expect(callbackSpy).toHaveBeenCalled();
|
expect(callbackSpy).toHaveBeenCalled();
|
||||||
@@ -32,9 +56,15 @@ describe("EditUser Component: ", () => {
|
|||||||
|
|
||||||
it("Submits the edits when the button is pressed", () => {
|
it("Submits the edits when the button is pressed", () => {
|
||||||
let callbackSpy = mockSync(),
|
let callbackSpy = mockSync(),
|
||||||
component = shallow(editUserJsx(callbackSpy)),
|
component = mount(editUserJsx(callbackSpy)),
|
||||||
submit = component.find("#submit");
|
submit = component.find("#submit");
|
||||||
submit.simulate("click");
|
submit.simulate("click");
|
||||||
expect(callbackSpy).toHaveBeenCalled();
|
expect(callbackSpy).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Doesn't render when no data is provided", () => {
|
||||||
|
let callbackSpy = mockSync(),
|
||||||
|
component = mount(editUserJsx(callbackSpy, true));
|
||||||
|
expect(component.find(".container").length).toBe(0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@@ -137,14 +137,4 @@ GroupEdit.propTypes = {
|
|||||||
refreshGroupsData: PropTypes.func,
|
refreshGroupsData: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
const withGroupsAPI = withProps((props) => ({
|
export default GroupEdit;
|
||||||
addToGroup: (users, groupname) =>
|
|
||||||
jhapiRequest("/groups/" + groupname + "/users", "POST", { users }),
|
|
||||||
removeFromGroup: (users, groupname) =>
|
|
||||||
jhapiRequest("/groups/" + groupname + "/users", "DELETE", { users }),
|
|
||||||
deleteGroup: (name) => jhapiRequest("/groups/" + name, "DELETE"),
|
|
||||||
refreshGroupsData: () =>
|
|
||||||
jhapiRequest("/groups", "GET").then((data) => data.json()),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export default compose(withGroupsAPI)(GroupEdit);
|
|
||||||
|
@@ -1,39 +1,62 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Enzyme, { mount, shallow } from "enzyme";
|
import Enzyme, { mount, shallow } from "enzyme";
|
||||||
import GroupEdit from "./GroupEdit.pre";
|
import GroupEdit from "./GroupEdit";
|
||||||
import Adapter from "@wojtekmaj/enzyme-adapter-react-17";
|
import Adapter from "@wojtekmaj/enzyme-adapter-react-17";
|
||||||
|
import { Provider, useSelector } from "react-redux";
|
||||||
|
import { createStore } from "redux";
|
||||||
import { HashRouter } from "react-router-dom";
|
import { HashRouter } from "react-router-dom";
|
||||||
|
|
||||||
Enzyme.configure({ adapter: new Adapter() });
|
Enzyme.configure({ adapter: new Adapter() });
|
||||||
|
|
||||||
|
jest.mock("react-redux", () => ({
|
||||||
|
...jest.requireActual("react-redux"),
|
||||||
|
useSelector: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
describe("GroupEdit Component: ", () => {
|
describe("GroupEdit Component: ", () => {
|
||||||
var mockAsync = () =>
|
var mockAsync = () =>
|
||||||
jest.fn().mockImplementation(() => Promise.resolve({ key: "value" }));
|
jest.fn().mockImplementation(() => Promise.resolve({ key: "value" }));
|
||||||
|
|
||||||
var groupEditJsx = (callbackSpy) => (
|
var groupEditJsx = (callbackSpy) => (
|
||||||
<GroupEdit
|
<Provider store={createStore(() => {}, {})}>
|
||||||
location={{
|
<HashRouter>
|
||||||
state: {
|
<GroupEdit
|
||||||
user_data: [{ name: "foo" }, { name: "bar" }],
|
location={{
|
||||||
group_data: { users: ["foo"], name: "group" },
|
state: {
|
||||||
callback: () => {},
|
user_data: [{ name: "foo" }, { name: "bar" }],
|
||||||
},
|
group_data: { users: ["foo"], name: "group" },
|
||||||
}}
|
callback: () => {},
|
||||||
addToGroup={callbackSpy}
|
},
|
||||||
removeFromGroup={callbackSpy}
|
}}
|
||||||
deleteGroup={callbackSpy}
|
addToGroup={callbackSpy}
|
||||||
history={{ push: (a) => callbackSpy }}
|
removeFromGroup={callbackSpy}
|
||||||
refreshGroupsData={() => {}}
|
deleteGroup={callbackSpy}
|
||||||
/>
|
history={{ push: (a) => callbackSpy }}
|
||||||
|
refreshGroupsData={callbackSpy}
|
||||||
|
/>
|
||||||
|
</HashRouter>
|
||||||
|
</Provider>
|
||||||
);
|
);
|
||||||
|
|
||||||
var deepGroupEditJsx = (callbackSpy) => (
|
var mockAppState = () => ({
|
||||||
<HashRouter>{groupEditJsx(callbackSpy)}</HashRouter>
|
user_data: JSON.parse(
|
||||||
);
|
'[{"kind":"user","name":"foo","admin":true,"groups":[],"server":"/user/foo/","pending":null,"created":"2020-12-07T18:46:27.112695Z","last_activity":"2020-12-07T21:00:33.336354Z","servers":{"":{"name":"","last_activity":"2020-12-07T20:58:02.437408Z","started":"2020-12-07T20:58:01.508266Z","pending":null,"ready":true,"state":{"pid":28085},"url":"/user/foo/","user_options":{},"progress_url":"/hub/api/users/foo/server/progress"}}},{"kind":"user","name":"bar","admin":false,"groups":[],"server":null,"pending":null,"created":"2020-12-07T18:46:27.115528Z","last_activity":"2020-12-07T20:43:51.013613Z","servers":{}}]'
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
useSelector.mockImplementation((callback) => {
|
||||||
|
return callback(mockAppState());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
useSelector.mockClear();
|
||||||
|
});
|
||||||
|
|
||||||
it("Adds a newly selected user to group on submit", () => {
|
it("Adds a newly selected user to group on submit", () => {
|
||||||
let callbackSpy = mockAsync(),
|
let callbackSpy = mockAsync(),
|
||||||
component = mount(deepGroupEditJsx(callbackSpy)),
|
component = mount(groupEditJsx(callbackSpy)),
|
||||||
unselected = component.find(".unselected"),
|
unselected = component.find(".unselected"),
|
||||||
submit = component.find("#submit");
|
submit = component.find("#submit");
|
||||||
unselected.simulate("click");
|
unselected.simulate("click");
|
||||||
@@ -43,7 +66,7 @@ describe("GroupEdit Component: ", () => {
|
|||||||
|
|
||||||
it("Removes a user from group on submit", () => {
|
it("Removes a user from group on submit", () => {
|
||||||
let callbackSpy = mockAsync(),
|
let callbackSpy = mockAsync(),
|
||||||
component = mount(deepGroupEditJsx(callbackSpy)),
|
component = mount(groupEditJsx(callbackSpy)),
|
||||||
selected = component.find(".selected"),
|
selected = component.find(".selected"),
|
||||||
submit = component.find("#submit");
|
submit = component.find("#submit");
|
||||||
selected.simulate("click");
|
selected.simulate("click");
|
||||||
@@ -53,9 +76,10 @@ describe("GroupEdit Component: ", () => {
|
|||||||
|
|
||||||
it("Calls deleteGroup on button click", () => {
|
it("Calls deleteGroup on button click", () => {
|
||||||
let callbackSpy = mockAsync(),
|
let callbackSpy = mockAsync(),
|
||||||
component = shallow(groupEditJsx(callbackSpy)),
|
component = mount(groupEditJsx(callbackSpy)),
|
||||||
deleteGroup = component.find("#delete-group").first();
|
deleteGroup = component.find("#delete-group").first();
|
||||||
deleteGroup.simulate("click");
|
deleteGroup.simulate("click");
|
||||||
expect(callbackSpy).toHaveBeenCalled();
|
expect(callbackSpy).toHaveBeenNthCalledWith(1, "group");
|
||||||
|
expect(callbackSpy).toHaveBeenNthCalledWith(2);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -102,21 +102,4 @@ Groups.propTypes = {
|
|||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
const withGroupsAPI = withProps((props) => ({
|
export default Groups;
|
||||||
refreshGroupsData: () =>
|
|
||||||
jhapiRequest("/groups", "GET").then((data) => data.json()),
|
|
||||||
refreshUserData: () =>
|
|
||||||
jhapiRequest("/users", "GET").then((data) => data.json()),
|
|
||||||
addUsersToGroup: (name, new_users) =>
|
|
||||||
jhapiRequest("/groups/" + name + "/users", "POST", {
|
|
||||||
body: { users: new_users },
|
|
||||||
json: true,
|
|
||||||
}),
|
|
||||||
removeUsersFromGroup: (name, removed_users) =>
|
|
||||||
jhapiRequest("/groups/" + name + "/users", "DELETE", {
|
|
||||||
body: { users: removed_users },
|
|
||||||
json: true,
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export default compose(withGroupsAPI)(Groups);
|
|
||||||
|
@@ -1,30 +1,58 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Enzyme, { shallow } from "enzyme";
|
import Enzyme, { mount } from "enzyme";
|
||||||
import Groups from "./Groups.pre";
|
import Groups from "./Groups";
|
||||||
import Adapter from "@wojtekmaj/enzyme-adapter-react-17";
|
import Adapter from "@wojtekmaj/enzyme-adapter-react-17";
|
||||||
|
import { Provider, useSelector } from "react-redux";
|
||||||
|
import { createStore } from "redux";
|
||||||
|
import { HashRouter } from "react-router-dom";
|
||||||
|
|
||||||
Enzyme.configure({ adapter: new Adapter() });
|
Enzyme.configure({ adapter: new Adapter() });
|
||||||
|
|
||||||
|
jest.mock("react-redux", () => ({
|
||||||
|
...jest.requireActual("react-redux"),
|
||||||
|
useSelector: jest.fn(),
|
||||||
|
useDispatch: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
describe("Groups Component: ", () => {
|
describe("Groups Component: ", () => {
|
||||||
var groupsJsx = () => (
|
var groupsJsx = () => (
|
||||||
<Groups
|
<Provider store={createStore(() => {}, {})}>
|
||||||
user_data={JSON.parse(
|
<HashRouter>
|
||||||
'[{"kind":"user","name":"foo","admin":true,"groups":[],"server":"/user/foo/","pending":null,"created":"2020-12-07T18:46:27.112695Z","last_activity":"2020-12-07T21:00:33.336354Z","servers":{"":{"name":"","last_activity":"2020-12-07T20:58:02.437408Z","started":"2020-12-07T20:58:01.508266Z","pending":null,"ready":true,"state":{"pid":28085},"url":"/user/foo/","user_options":{},"progress_url":"/hub/api/users/foo/server/progress"}}},{"kind":"user","name":"bar","admin":false,"groups":[],"server":null,"pending":null,"created":"2020-12-07T18:46:27.115528Z","last_activity":"2020-12-07T20:43:51.013613Z","servers":{}}]'
|
<Groups />
|
||||||
)}
|
</HashRouter>
|
||||||
groups_data={JSON.parse(
|
</Provider>
|
||||||
'[{"kind":"group","name":"testgroup","users":[]}, {"kind":"group","name":"testgroup2","users":["foo", "bar"]}]'
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
var mockAppState = () => ({
|
||||||
|
user_data: JSON.parse(
|
||||||
|
'[{"kind":"user","name":"foo","admin":true,"groups":[],"server":"/user/foo/","pending":null,"created":"2020-12-07T18:46:27.112695Z","last_activity":"2020-12-07T21:00:33.336354Z","servers":{"":{"name":"","last_activity":"2020-12-07T20:58:02.437408Z","started":"2020-12-07T20:58:01.508266Z","pending":null,"ready":true,"state":{"pid":28085},"url":"/user/foo/","user_options":{},"progress_url":"/hub/api/users/foo/server/progress"}}},{"kind":"user","name":"bar","admin":false,"groups":[],"server":null,"pending":null,"created":"2020-12-07T18:46:27.115528Z","last_activity":"2020-12-07T20:43:51.013613Z","servers":{}}]'
|
||||||
|
),
|
||||||
|
groups_data: JSON.parse(
|
||||||
|
'[{"kind":"group","name":"testgroup","users":[]}, {"kind":"group","name":"testgroup2","users":["foo", "bar"]}]'
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
useSelector.mockImplementation((callback) => {
|
||||||
|
return callback(mockAppState());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
useSelector.mockClear();
|
||||||
|
});
|
||||||
|
|
||||||
it("Renders groups_data prop into links", () => {
|
it("Renders groups_data prop into links", () => {
|
||||||
let component = shallow(groupsJsx()),
|
let component = mount(groupsJsx()),
|
||||||
links = component.find(".group-edit-link");
|
links = component.find(".group-edit-link");
|
||||||
expect(links.length).toBe(2);
|
expect(links.length).toBe(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Renders nothing if required data is not available", () => {
|
it("Renders nothing if required data is not available", () => {
|
||||||
let component = shallow(<Groups />);
|
useSelector.mockImplementation((callback) => {
|
||||||
|
return callback({});
|
||||||
|
});
|
||||||
|
let component = mount(groupsJsx());
|
||||||
expect(component.html()).toBe("<div></div>");
|
expect(component.html()).toBe("<div></div>");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -155,7 +155,7 @@ const ServerDashboard = (props) => {
|
|||||||
{/* Shutdown Jupyterhub */}
|
{/* Shutdown Jupyterhub */}
|
||||||
<Button
|
<Button
|
||||||
variant="danger"
|
variant="danger"
|
||||||
className="shutdown-button"
|
id="shutdown-button"
|
||||||
onClick={shutdownHub}
|
onClick={shutdownHub}
|
||||||
>
|
>
|
||||||
Shutdown Hub
|
Shutdown Hub
|
||||||
@@ -288,15 +288,4 @@ SortHandler.propTypes = {
|
|||||||
callback: PropTypes.func,
|
callback: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
const withHubActions = withProps((props) => ({
|
export default ServerDashboard;
|
||||||
updateUsers: (cb) => jhapiRequest("/users", "GET"),
|
|
||||||
shutdownHub: () => jhapiRequest("/shutdown", "POST"),
|
|
||||||
startServer: (name) => jhapiRequest("/users/" + name + "/server", "POST"),
|
|
||||||
stopServer: (name) => jhapiRequest("/users/" + name + "/server", "DELETE"),
|
|
||||||
startAll: (names) =>
|
|
||||||
names.map((e) => jhapiRequest("/users/" + e + "/server", "POST")),
|
|
||||||
stopAll: (names) =>
|
|
||||||
names.map((e) => jhapiRequest("/users/" + e + "/server", "DELETE")),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export default compose(withHubActions)(ServerDashboard);
|
|
||||||
|
@@ -1,44 +1,34 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Enzyme, { shallow, mount } from "enzyme";
|
import Enzyme, { shallow, mount } from "enzyme";
|
||||||
import ServerDashboard from "./ServerDashboard.pre";
|
import ServerDashboard from "./ServerDashboard";
|
||||||
import Adapter from "@wojtekmaj/enzyme-adapter-react-17";
|
import Adapter from "@wojtekmaj/enzyme-adapter-react-17";
|
||||||
import { HashRouter, Switch } from "react-router-dom";
|
import { HashRouter, Switch } from "react-router-dom";
|
||||||
|
import { Provider, useSelector } from "react-redux";
|
||||||
|
import { createStore } from "redux";
|
||||||
|
|
||||||
Enzyme.configure({ adapter: new Adapter() });
|
Enzyme.configure({ adapter: new Adapter() });
|
||||||
|
|
||||||
|
jest.mock("react-redux", () => ({
|
||||||
|
...jest.requireActual("react-redux"),
|
||||||
|
useSelector: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
describe("ServerDashboard Component: ", () => {
|
describe("ServerDashboard Component: ", () => {
|
||||||
var serverDashboardJsx = (callbackSpy) => (
|
var serverDashboardJsx = (callbackSpy) => (
|
||||||
<ServerDashboard
|
<Provider store={createStore(() => {}, {})}>
|
||||||
user_data={JSON.parse(
|
<HashRouter>
|
||||||
'[{"kind":"user","name":"foo","admin":true,"groups":[],"server":"/user/foo/","pending":null,"created":"2020-12-07T18:46:27.112695Z","last_activity":"2020-12-07T21:00:33.336354Z","servers":{"":{"name":"","last_activity":"2020-12-07T20:58:02.437408Z","started":"2020-12-07T20:58:01.508266Z","pending":null,"ready":true,"state":{"pid":28085},"url":"/user/foo/","user_options":{},"progress_url":"/hub/api/users/foo/server/progress"}}},{"kind":"user","name":"bar","admin":false,"groups":[],"server":null,"pending":null,"created":"2020-12-07T18:46:27.115528Z","last_activity":"2020-12-07T20:43:51.013613Z","servers":{}}]'
|
<Switch>
|
||||||
)}
|
<ServerDashboard
|
||||||
updateUsers={callbackSpy}
|
updateUsers={callbackSpy}
|
||||||
shutdownHub={callbackSpy}
|
shutdownHub={callbackSpy}
|
||||||
startServer={callbackSpy}
|
startServer={callbackSpy}
|
||||||
stopServer={callbackSpy}
|
stopServer={callbackSpy}
|
||||||
startAll={callbackSpy}
|
startAll={callbackSpy}
|
||||||
stopAll={callbackSpy}
|
stopAll={callbackSpy}
|
||||||
dispatch={callbackSpy}
|
/>
|
||||||
/>
|
</Switch>
|
||||||
);
|
</HashRouter>
|
||||||
|
</Provider>
|
||||||
var deepServerDashboardJsx = (callbackSpy) => (
|
|
||||||
<HashRouter>
|
|
||||||
<Switch>
|
|
||||||
<ServerDashboard
|
|
||||||
user_data={JSON.parse(
|
|
||||||
'[{"kind":"user","name":"foo","admin":true,"groups":[],"server":"/user/foo/","pending":null,"created":"2020-12-07T18:46:27.112695Z","last_activity":"2020-12-07T21:00:33.336354Z","servers":{"":{"name":"","last_activity":"2020-12-07T20:58:02.437408Z","started":"2020-12-07T20:58:01.508266Z","pending":null,"ready":true,"state":{"pid":28085},"url":"/user/foo/","user_options":{},"progress_url":"/hub/api/users/foo/server/progress"}}},{"kind":"user","name":"bar","admin":false,"groups":[],"server":null,"pending":null,"created":"2020-12-07T18:46:27.115528Z","last_activity":"2020-12-07T20:43:51.013613Z","servers":{}}]'
|
|
||||||
)}
|
|
||||||
updateUsers={callbackSpy}
|
|
||||||
shutdownHub={callbackSpy}
|
|
||||||
startServer={callbackSpy}
|
|
||||||
stopServer={callbackSpy}
|
|
||||||
startAll={callbackSpy}
|
|
||||||
stopAll={callbackSpy}
|
|
||||||
dispatch={callbackSpy}
|
|
||||||
/>
|
|
||||||
</Switch>
|
|
||||||
</HashRouter>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
var mockAsync = () =>
|
var mockAsync = () =>
|
||||||
@@ -48,14 +38,30 @@ describe("ServerDashboard Component: ", () => {
|
|||||||
Promise.resolve({ json: () => Promise.resolve({ k: "v" }) })
|
Promise.resolve({ json: () => Promise.resolve({ k: "v" }) })
|
||||||
);
|
);
|
||||||
|
|
||||||
|
var mockAppState = () => ({
|
||||||
|
user_data: JSON.parse(
|
||||||
|
'[{"kind":"user","name":"foo","admin":true,"groups":[],"server":"/user/foo/","pending":null,"created":"2020-12-07T18:46:27.112695Z","last_activity":"2020-12-07T21:00:33.336354Z","servers":{"":{"name":"","last_activity":"2020-12-07T20:58:02.437408Z","started":"2020-12-07T20:58:01.508266Z","pending":null,"ready":true,"state":{"pid":28085},"url":"/user/foo/","user_options":{},"progress_url":"/hub/api/users/foo/server/progress"}}},{"kind":"user","name":"bar","admin":false,"groups":[],"server":null,"pending":null,"created":"2020-12-07T18:46:27.115528Z","last_activity":"2020-12-07T20:43:51.013613Z","servers":{}}]'
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
useSelector.mockImplementation((callback) => {
|
||||||
|
return callback(mockAppState());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
useSelector.mockClear();
|
||||||
|
});
|
||||||
|
|
||||||
it("Renders users from props.user_data into table", () => {
|
it("Renders users from props.user_data into table", () => {
|
||||||
let component = shallow(serverDashboardJsx(jest.fn())),
|
let component = mount(serverDashboardJsx(jest.fn())),
|
||||||
userRows = component.find(".user-row");
|
userRows = component.find(".user-row");
|
||||||
expect(userRows.length).toBe(2);
|
expect(userRows.length).toBe(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Renders correctly the status of a single-user server", () => {
|
it("Renders correctly the status of a single-user server", () => {
|
||||||
let component = shallow(serverDashboardJsx(jest.fn())),
|
let component = mount(serverDashboardJsx(jest.fn())),
|
||||||
userRows = component.find(".user-row");
|
userRows = component.find(".user-row");
|
||||||
// Renders .stop-button when server is started
|
// Renders .stop-button when server is started
|
||||||
// Should be 1 since user foo is started
|
// Should be 1 since user foo is started
|
||||||
@@ -67,7 +73,7 @@ describe("ServerDashboard Component: ", () => {
|
|||||||
|
|
||||||
it("Invokes the startServer event on button click", () => {
|
it("Invokes the startServer event on button click", () => {
|
||||||
let callbackSpy = mockAsync(),
|
let callbackSpy = mockAsync(),
|
||||||
component = shallow(serverDashboardJsx(callbackSpy)),
|
component = mount(serverDashboardJsx(callbackSpy)),
|
||||||
startBtn = component.find(".start-button");
|
startBtn = component.find(".start-button");
|
||||||
startBtn.simulate("click");
|
startBtn.simulate("click");
|
||||||
expect(callbackSpy).toHaveBeenCalled();
|
expect(callbackSpy).toHaveBeenCalled();
|
||||||
@@ -75,7 +81,7 @@ describe("ServerDashboard Component: ", () => {
|
|||||||
|
|
||||||
it("Invokes the stopServer event on button click", () => {
|
it("Invokes the stopServer event on button click", () => {
|
||||||
let callbackSpy = mockAsync(),
|
let callbackSpy = mockAsync(),
|
||||||
component = shallow(serverDashboardJsx(callbackSpy)),
|
component = mount(serverDashboardJsx(callbackSpy)),
|
||||||
stopBtn = component.find(".stop-button");
|
stopBtn = component.find(".stop-button");
|
||||||
stopBtn.simulate("click");
|
stopBtn.simulate("click");
|
||||||
expect(callbackSpy).toHaveBeenCalled();
|
expect(callbackSpy).toHaveBeenCalled();
|
||||||
@@ -83,14 +89,14 @@ describe("ServerDashboard Component: ", () => {
|
|||||||
|
|
||||||
it("Invokes the shutdownHub event on button click", () => {
|
it("Invokes the shutdownHub event on button click", () => {
|
||||||
let callbackSpy = mockAsync(),
|
let callbackSpy = mockAsync(),
|
||||||
component = shallow(serverDashboardJsx(callbackSpy)),
|
component = mount(serverDashboardJsx(callbackSpy)),
|
||||||
shutdownBtn = component.find(".shutdown-button");
|
shutdownBtn = component.find("#shutdown-button").first();
|
||||||
shutdownBtn.simulate("click");
|
shutdownBtn.simulate("click");
|
||||||
expect(callbackSpy).toHaveBeenCalled();
|
expect(callbackSpy).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Sorts according to username", () => {
|
it("Sorts according to username", () => {
|
||||||
let component = mount(deepServerDashboardJsx(jest.fn())).find(
|
let component = mount(serverDashboardJsx(jest.fn())).find(
|
||||||
"ServerDashboard"
|
"ServerDashboard"
|
||||||
),
|
),
|
||||||
handler = component.find("SortHandler").first();
|
handler = component.find("SortHandler").first();
|
||||||
@@ -103,7 +109,7 @@ describe("ServerDashboard Component: ", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("Sorts according to admin", () => {
|
it("Sorts according to admin", () => {
|
||||||
let component = mount(deepServerDashboardJsx(jest.fn())).find(
|
let component = mount(serverDashboardJsx(jest.fn())).find(
|
||||||
"ServerDashboard"
|
"ServerDashboard"
|
||||||
),
|
),
|
||||||
handler = component.find("SortHandler").at(1);
|
handler = component.find("SortHandler").at(1);
|
||||||
@@ -116,7 +122,7 @@ describe("ServerDashboard Component: ", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("Sorts according to last activity", () => {
|
it("Sorts according to last activity", () => {
|
||||||
let component = mount(deepServerDashboardJsx(jest.fn())).find(
|
let component = mount(serverDashboardJsx(jest.fn())).find(
|
||||||
"ServerDashboard"
|
"ServerDashboard"
|
||||||
),
|
),
|
||||||
handler = component.find("SortHandler").at(2);
|
handler = component.find("SortHandler").at(2);
|
||||||
@@ -131,7 +137,7 @@ describe("ServerDashboard Component: ", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("Sorts according to server status (running/not running)", () => {
|
it("Sorts according to server status (running/not running)", () => {
|
||||||
let component = mount(deepServerDashboardJsx(jest.fn())).find(
|
let component = mount(serverDashboardJsx(jest.fn())).find(
|
||||||
"ServerDashboard"
|
"ServerDashboard"
|
||||||
),
|
),
|
||||||
handler = component.find("SortHandler").at(3);
|
handler = component.find("SortHandler").at(3);
|
||||||
@@ -146,7 +152,10 @@ describe("ServerDashboard Component: ", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("Renders nothing if required data is not available", () => {
|
it("Renders nothing if required data is not available", () => {
|
||||||
let component = shallow(<ServerDashboard />);
|
useSelector.mockImplementation((callback) => {
|
||||||
|
return callback({});
|
||||||
|
});
|
||||||
|
let component = mount(serverDashboardJsx(jest.fn()));
|
||||||
expect(component.html()).toBe("<div></div>");
|
expect(component.html()).toBe("<div></div>");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
40
jsx/src/util/withAPI.js
Normal file
40
jsx/src/util/withAPI.js
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import { withProps } from "recompose";
|
||||||
|
import { jhapiRequest } from "./jhapiUtil";
|
||||||
|
|
||||||
|
const withAPI = withProps((props) => ({
|
||||||
|
updateUsers: (cb) => jhapiRequest("/users", "GET"),
|
||||||
|
shutdownHub: () => jhapiRequest("/shutdown", "POST"),
|
||||||
|
startServer: (name) => jhapiRequest("/users/" + name + "/server", "POST"),
|
||||||
|
stopServer: (name) => jhapiRequest("/users/" + name + "/server", "DELETE"),
|
||||||
|
startAll: (names) =>
|
||||||
|
names.map((e) => jhapiRequest("/users/" + e + "/server", "POST")),
|
||||||
|
stopAll: (names) =>
|
||||||
|
names.map((e) => jhapiRequest("/users/" + e + "/server", "DELETE")),
|
||||||
|
addToGroup: (users, groupname) =>
|
||||||
|
jhapiRequest("/groups/" + groupname + "/users", "POST", { users }),
|
||||||
|
removeFromGroup: (users, groupname) =>
|
||||||
|
jhapiRequest("/groups/" + groupname + "/users", "DELETE", { users }),
|
||||||
|
createGroup: (groupName) => jhapiRequest("/groups/" + groupName, "POST"),
|
||||||
|
deleteGroup: (name) => jhapiRequest("/groups/" + name, "DELETE"),
|
||||||
|
addUsers: (usernames, admin) =>
|
||||||
|
jhapiRequest("/users", "POST", { usernames, admin }),
|
||||||
|
editUser: (username, updated_username, admin) =>
|
||||||
|
jhapiRequest("/users/" + username, "PATCH", {
|
||||||
|
name: updated_username,
|
||||||
|
admin,
|
||||||
|
}),
|
||||||
|
deleteUser: (username) => jhapiRequest("/users/" + username, "DELETE"),
|
||||||
|
failRegexEvent: () =>
|
||||||
|
alert(
|
||||||
|
"Cannot change username - either contains special characters or is too short."
|
||||||
|
),
|
||||||
|
noChangeEvent: () => {
|
||||||
|
returns;
|
||||||
|
},
|
||||||
|
refreshGroupsData: () =>
|
||||||
|
jhapiRequest("/groups", "GET").then((data) => data.json()),
|
||||||
|
refreshUserData: () =>
|
||||||
|
jhapiRequest("/users", "GET").then((data) => data.json()),
|
||||||
|
}));
|
||||||
|
|
||||||
|
export default withAPI;
|
@@ -1 +0,0 @@
|
|||||||
38441
|
|
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user