From 201e7ca3d863f8f2a44d9d906268cd1e075be458 Mon Sep 17 00:00:00 2001 From: Min RK Date: Mon, 28 Mar 2022 09:03:26 +0200 Subject: [PATCH] Backport PR #3834: Admin Dashboard - Collapsible Details View I made this PR to see if this feature would be useful for other people. Right now, you can't see all of a user or server's details in the admin page so I added a collapsible view which will let you see the entire server and user objects. I'm open to ideas about how the information is displayed. Will add more tests if this feature is accepted. ![improved-collapse](https://user-images.githubusercontent.com/737367/158468531-1efc28e6-a229-4383-b5f9-b301898d929f.gif) Signed-off-by: Min RK --- jsx/build/admin-react.js.LICENSE.txt | 9 + jsx/package.json | 7 +- jsx/src/Store.js | 2 +- .../ServerDashboard/ServerDashboard.jsx | 198 ++++++++++++------ .../ServerDashboard/ServerDashboard.test.js | 57 ++++- jsx/src/util/withAPI.js | 2 +- jsx/yarn.lock | 93 ++++---- share/jupyterhub/static/js/admin-react.js | 2 +- 8 files changed, 256 insertions(+), 114 deletions(-) diff --git a/jsx/build/admin-react.js.LICENSE.txt b/jsx/build/admin-react.js.LICENSE.txt index 493c5041..9e7087bc 100644 --- a/jsx/build/admin-react.js.LICENSE.txt +++ b/jsx/build/admin-react.js.LICENSE.txt @@ -37,6 +37,15 @@ object-assign * LICENSE file in the root directory of this source tree. */ +/** @license React v17.0.2 + * react-jsx-runtime.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + /** @license React v17.0.2 * react.production.min.js * diff --git a/jsx/package.json b/jsx/package.json index 2488dbe8..4442d169 100644 --- a/jsx/package.json +++ b/jsx/package.json @@ -43,10 +43,11 @@ "lodash.debounce": "^4.0.8", "prop-types": "^15.7.2", "react": "^17.0.1", - "react-bootstrap": "^1.4.0", + "react-bootstrap": "^2.1.1", "react-dom": "^17.0.1", "react-icons": "^4.1.0", "react-multi-select-component": "^3.0.7", + "react-object-table-viewer": "^1.0.7", "react-redux": "^7.2.2", "react-router": "^5.2.0", "react-router-dom": "^5.2.0", @@ -60,7 +61,6 @@ }, "devDependencies": { "@wojtekmaj/enzyme-adapter-react-17": "^0.6.5", - "sinon": "^13.0.1", "babel-jest": "^26.6.3", "enzyme": "^3.11.0", "eslint": "^7.18.0", @@ -68,6 +68,7 @@ "eslint-plugin-react": "^7.22.0", "identity-obj-proxy": "^3.0.0", "jest": "^26.6.3", - "prettier": "^2.2.1" + "prettier": "^2.2.1", + "sinon": "^13.0.1" } } diff --git a/jsx/src/Store.js b/jsx/src/Store.js index 0dadda20..d5194df1 100644 --- a/jsx/src/Store.js +++ b/jsx/src/Store.js @@ -14,7 +14,7 @@ export const reducers = (state = initialState, action) => { return Object.assign({}, state, { user_page: action.value.page, user_data: action.value.data, - name_filter: action.value.name_filter, + name_filter: action.value.name_filter || "", }); // Updates the client group model data and stores the page diff --git a/jsx/src/components/ServerDashboard/ServerDashboard.jsx b/jsx/src/components/ServerDashboard/ServerDashboard.jsx index 9087ee2b..9ba4720f 100644 --- a/jsx/src/components/ServerDashboard/ServerDashboard.jsx +++ b/jsx/src/components/ServerDashboard/ServerDashboard.jsx @@ -3,7 +3,17 @@ import regeneratorRuntime from "regenerator-runtime"; import { useSelector, useDispatch } from "react-redux"; import PropTypes from "prop-types"; -import { Button, Col, Row, FormControl } from "react-bootstrap"; +import { + Button, + Col, + Row, + FormControl, + Card, + CardGroup, + Collapse, +} from "react-bootstrap"; +import ReactObjectTableViewer from "react-object-table-viewer"; + import { Link } from "react-router-dom"; import { FaSort, FaSortUp, FaSortDown } from "react-icons/fa"; @@ -40,6 +50,7 @@ const ServerDashboard = (props) => { var [errorAlert, setErrorAlert] = useState(null); var [sortMethod, setSortMethod] = useState(null); var [disabledButtons, setDisabledButtons] = useState({}); + const [collapseStates, setCollapseStates] = useState({}); var user_data = useSelector((state) => state.user_data), user_page = useSelector((state) => state.user_page), @@ -189,6 +200,131 @@ const ServerDashboard = (props) => { ); }; + const serverRow = (user, server) => { + const { servers, ...userNoServers } = user; + const serverNameDash = server.name ? `-${server.name}` : ""; + const userServerName = user.name + serverNameDash; + const open = collapseStates[userServerName] || false; + return [ + + + + {" "} + + + {user.name} + + + {user.admin ? "admin" : ""} + + + {server.name ? ( +

{server.name}

+ ) : ( +

[MAIN]

+ )} + + + {server.last_activity ? timeSince(server.last_activity) : "Never"} + + + {server.started ? ( + // Stop Single-user server + <> + + + + ) : ( + // Start Single-user server + <> + + + + + + )} + + + , + + + + + + User + + + + Server + + + + + + , + ]; + }; + let servers = user_data.flatMap((user) => { let userServers = Object.values({ "": user.server || {}, @@ -234,7 +370,7 @@ const ServerDashboard = (props) => { {"> Manage Groups"} - +
- {servers.map(([user, server], i) => { - server.name = server.name || ""; - return ( - - - - - - - - - - ); - })} + {servers.flatMap(([user, server]) => serverRow(user, server))}
@@ -373,63 +509,7 @@ const ServerDashboard = (props) => {
{user.name} - {user.admin ? "admin" : ""} - - {server.name ? ( -

{server.name}

- ) : ( -

[MAIN]

- )} -
- {server.last_activity - ? timeSince(server.last_activity) - : "Never"} - - {server.started ? ( - // Stop Single-user server - <> - - - - ) : ( - // Start Single-user server - <> - - - - - - )} -
{ render(serverDashboardJsx(callbackSpy)); }); - let foo = screen.getByText("foo"); - let bar = screen.getByText("bar"); + let foo = screen.getByTestId("user-name-div-foo"); + let bar = screen.getByTestId("user-name-div-bar"); expect(foo).toBeVisible(); expect(bar).toBeVisible(); @@ -156,12 +156,12 @@ test("Sorts according to username", async () => { fireEvent.click(handler); let first = screen.getAllByTestId("user-row-name")[0]; - expect(first.textContent).toBe("bar"); + expect(first.textContent).toContain("bar"); fireEvent.click(handler); first = screen.getAllByTestId("user-row-name")[0]; - expect(first.textContent).toBe("foo"); + expect(first.textContent).toContain("foo"); }); test("Sorts according to admin", async () => { @@ -194,12 +194,12 @@ test("Sorts according to last activity", async () => { fireEvent.click(handler); let first = screen.getAllByTestId("user-row-name")[0]; - expect(first.textContent).toBe("foo"); + expect(first.textContent).toContain("foo"); fireEvent.click(handler); first = screen.getAllByTestId("user-row-name")[0]; - expect(first.textContent).toBe("bar"); + expect(first.textContent).toContain("bar"); }); test("Sorts according to server status (running/not running)", async () => { @@ -213,12 +213,53 @@ test("Sorts according to server status (running/not running)", async () => { fireEvent.click(handler); let first = screen.getAllByTestId("user-row-name")[0]; - expect(first.textContent).toBe("foo"); + expect(first.textContent).toContain("foo"); fireEvent.click(handler); first = screen.getAllByTestId("user-row-name")[0]; - expect(first.textContent).toBe("bar"); + expect(first.textContent).toContain("bar"); +}); + +test("Shows server details with button click", async () => { + let callbackSpy = mockAsync(); + + await act(async () => { + render(serverDashboardJsx(callbackSpy)); + }); + let button = screen.getByTestId("foo-collapse-button"); + let collapse = screen.getByTestId("foo-collapse"); + let collapseBar = screen.getByTestId("bar-collapse"); + + // expect().toBeVisible does not work here with collapse. + expect(collapse).toHaveClass("collapse"); + expect(collapse).not.toHaveClass("show"); + expect(collapseBar).not.toHaveClass("show"); + + await act(async () => { + fireEvent.click(button); + }); + clock.tick(400); + + expect(collapse).toHaveClass("collapse show"); + expect(collapseBar).not.toHaveClass("show"); + + await act(async () => { + fireEvent.click(button); + }); + clock.tick(400); + + expect(collapse).toHaveClass("collapse"); + expect(collapse).not.toHaveClass("show"); + expect(collapseBar).not.toHaveClass("show"); + + await act(async () => { + fireEvent.click(button); + }); + clock.tick(400); + + expect(collapse).toHaveClass("collapse show"); + expect(collapseBar).not.toHaveClass("show"); }); test("Renders nothing if required data is not available", async () => { diff --git a/jsx/src/util/withAPI.js b/jsx/src/util/withAPI.js index 69a525bb..1e6f680e 100644 --- a/jsx/src/util/withAPI.js +++ b/jsx/src/util/withAPI.js @@ -4,7 +4,7 @@ import { jhapiRequest } from "./jhapiUtil"; const withAPI = withProps(() => ({ updateUsers: (offset, limit, name_filter) => jhapiRequest( - `/users?offset=${offset}&limit=${limit}&name_filter=${name_filter}`, + `/users?offset=${offset}&limit=${limit}&name_filter=${name_filter || ""}`, "GET" ).then((data) => data.json()), updateGroups: (offset, limit) => diff --git a/jsx/yarn.lock b/jsx/yarn.lock index eb04145d..31a46af8 100644 --- a/jsx/yarn.lock +++ b/jsx/yarn.lock @@ -928,7 +928,7 @@ "@babel/plugin-transform-react-jsx-development" "^7.16.7" "@babel/plugin-transform-react-pure-annotations" "^7.16.7" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.8", "@babel/runtime@^7.14.0", "@babel/runtime@^7.15.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.16", "@babel/runtime@^7.15.4", "@babel/runtime@^7.17.2", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": version "7.17.7" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.7.tgz#a5f3328dc41ff39d803f311cfe17703418cf9825" integrity sha512-L6rvG9GDxaLgFjg41K+5Yv9OMrU98sWe+Ykmc6FDJW/+vYZMhdOMKkISgzptMaERHvS2Y2lw9MDRm2gHhlQQoA== @@ -1215,23 +1215,41 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" -"@popperjs/core@^2.8.6": +"@popperjs/core@^2.10.1": version "2.11.4" resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.4.tgz#d8c7b8db9226d2d7664553a0741ad7d0397ee503" integrity sha512-q/ytXxO5NKvyT37pmisQAItCFqA7FD/vNb8dgaJy3/630Fsc+Mz9/9f2SziBoIZ30TJooXyTwZmhi1zjXmObYg== -"@restart/context@^2.1.4": - version "2.1.4" - resolved "https://registry.yarnpkg.com/@restart/context/-/context-2.1.4.tgz#a99d87c299a34c28bd85bb489cb07bfd23149c02" - integrity sha512-INJYZQJP7g+IoDUh/475NlGiTeMfwTXUEr3tmRneckHIxNolGOW9CTq83S8cxq0CgJwwcMzMJFchxvlwe7Rk8Q== +"@react-aria/ssr@^3.0.1": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@react-aria/ssr/-/ssr-3.1.2.tgz#665a6fd56385068c7417922af2d0d71b0618e52d" + integrity sha512-amXY11ImpokvkTMeKRHjsSsG7v1yzzs6yeqArCyBIk60J3Yhgxwx9Cah+Uu/804ATFwqzN22AXIo7SdtIaMP+g== + dependencies: + "@babel/runtime" "^7.6.2" -"@restart/hooks@^0.3.26": - version "0.3.27" - resolved "https://registry.yarnpkg.com/@restart/hooks/-/hooks-0.3.27.tgz#91f356d66d4699a8cd8b3d008402708b6a9dc505" - integrity sha512-s984xV/EapUIfkjlf8wz9weP2O9TNKR96C68FfMEy2bE69+H4cNv3RD4Mf97lW7Htt7PjZrYTjSC8f3SB9VCXw== +"@restart/hooks@^0.4.0", "@restart/hooks@^0.4.5": + version "0.4.5" + resolved "https://registry.yarnpkg.com/@restart/hooks/-/hooks-0.4.5.tgz#e7acbea237bfc9e479970500cf87538b41a1ed02" + integrity sha512-tLGtY0aHeIfT7aPwUkvQuhIy3+q3w4iqmUzFLPlOAf/vNUacLaBt1j/S//jv/dQhenRh8jvswyMojCwmLvJw8A== dependencies: dequal "^2.0.2" +"@restart/ui@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@restart/ui/-/ui-1.0.2.tgz#009a06ae698d624672c5e6a776efd0e8a6017842" + integrity sha512-vKGe0UBJLnbvNAjr8ljlDvphf2HkpjBjXsblmgKPvKdZBDn/mtAz89wmznaomIaEJ9VNoSEY0vA5T5MDi2jIcQ== + dependencies: + "@babel/runtime" "^7.13.16" + "@popperjs/core" "^2.10.1" + "@react-aria/ssr" "^3.0.1" + "@restart/hooks" "^0.4.0" + "@types/warning" "^3.0.0" + dequal "^2.0.2" + dom-helpers "^5.2.0" + prop-types "^15.7.2" + uncontrollable "^7.2.1" + warning "^4.0.3" + "@sinonjs/commons@^1.6.0", "@sinonjs/commons@^1.7.0", "@sinonjs/commons@^1.8.3": version "1.8.3" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d" @@ -1399,7 +1417,7 @@ "@types/react" "*" hoist-non-react-statics "^3.3.0" -"@types/invariant@^2.2.33": +"@types/invariant@^2.2.35": version "2.2.35" resolved "https://registry.yarnpkg.com/@types/invariant/-/invariant-2.2.35.tgz#cd3ebf581a6557452735688d8daba6cf0bd5a3be" integrity sha512-DxX1V9P8zdJPYQat1gHyY0xj3efl8gnMVjiM9iCY6y27lj+PoQWkgjt8jDqmovPqULkKVpKRg8J36iQiA+EtEg== @@ -1456,7 +1474,7 @@ resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.4.4.tgz#5d9b63132df54d8909fce1c3f8ca260fdd693e17" integrity sha512-ReVR2rLTV1kvtlWFyuot+d1pkpG2Fw/XKE3PDAdj57rbM97ttSp9JZ2UsP+2EHTylra9cUf6JA7tGwW1INzUrA== -"@types/prop-types@*", "@types/prop-types@^15.7.3": +"@types/prop-types@*", "@types/prop-types@^15.7.4": version "15.7.4" resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11" integrity sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ== @@ -1478,7 +1496,7 @@ hoist-non-react-statics "^3.3.0" redux "^4.0.0" -"@types/react-transition-group@^4.4.1": +"@types/react-transition-group@^4.4.4": version "4.4.4" resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.4.tgz#acd4cceaa2be6b757db61ed7b432e103242d163e" integrity sha512-7gAPz7anVK5xzbeQW9wFBDg7G++aPLAFY0QaSMOou9rJZpbuI58WAuJrgu+qR92l61grlnCUe7AFX8KGahAgug== @@ -6167,30 +6185,29 @@ raw-body@2.4.3: iconv-lite "0.4.24" unpipe "1.0.0" -react-bootstrap@^1.4.0: - version "1.6.4" - resolved "https://registry.yarnpkg.com/react-bootstrap/-/react-bootstrap-1.6.4.tgz#94d5d2422e26bba277656d3529128e14f838b7ca" - integrity sha512-z3BhBD4bEZuLP8VrYqAD7OT7axdcSkkyvWBWnS2U/4MhyabUihrUyucPWkan7aMI1XIHbmH4LCpEtzWGfx/yfA== +react-bootstrap@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/react-bootstrap/-/react-bootstrap-2.2.1.tgz#2a6ad0931e9367882ec3fc88a70ed0b8ace90b26" + integrity sha512-x8lpVQflsbevphuWbTnTNCatcbKyPJNrP2WyQ1MJYmFEcVjbTbai1yZhdlXr0QUxLQLxA8g5hQWb5TwJtaZoCA== dependencies: - "@babel/runtime" "^7.14.0" - "@restart/context" "^2.1.4" - "@restart/hooks" "^0.3.26" - "@types/invariant" "^2.2.33" - "@types/prop-types" "^15.7.3" + "@babel/runtime" "^7.17.2" + "@restart/hooks" "^0.4.5" + "@restart/ui" "^1.0.2" + "@types/invariant" "^2.2.35" + "@types/prop-types" "^15.7.4" "@types/react" ">=16.14.8" - "@types/react-transition-group" "^4.4.1" + "@types/react-transition-group" "^4.4.4" "@types/warning" "^3.0.0" classnames "^2.3.1" dom-helpers "^5.2.1" invariant "^2.2.4" - prop-types "^15.7.2" + prop-types "^15.8.1" prop-types-extra "^1.1.0" - react-overlays "^5.1.1" - react-transition-group "^4.4.1" + react-transition-group "^4.4.2" uncontrollable "^7.2.1" warning "^4.0.3" -react-dom@^17.0.1: +react-dom@17.0.2, react-dom@^17.0.1: version "17.0.2" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== @@ -6226,19 +6243,13 @@ react-multi-select-component@^3.0.7: dependencies: goober "^2.0.30" -react-overlays@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/react-overlays/-/react-overlays-5.1.1.tgz#2e7cf49744b56537c7828ccb94cfc63dd778ae4f" - integrity sha512-eCN2s2/+GVZzpnId4XVWtvDPYYBD2EtOGP74hE+8yDskPzFy9+pV1H3ZZihxuRdEbQzzacySaaDkR7xE0ydl4Q== +react-object-table-viewer@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/react-object-table-viewer/-/react-object-table-viewer-1.0.7.tgz#31816021fa4526641c6b66bd9433ec9b78c2e472" + integrity sha512-OezCet8+BmEdJJHO5WGPFPRWXxw4Ls6HsV4Uh1kRPlmRXLOTNqWt/ZHmH8NhTl1BA9HkdhEegKVqc2b61wDMLg== dependencies: - "@babel/runtime" "^7.13.8" - "@popperjs/core" "^2.8.6" - "@restart/hooks" "^0.3.26" - "@types/warning" "^3.0.0" - dom-helpers "^5.2.0" - prop-types "^15.7.2" - uncontrollable "^7.2.1" - warning "^4.0.3" + react "^17.0.2" + react-dom "17.0.2" react-redux@^7.2.2: version "7.2.6" @@ -6299,7 +6310,7 @@ react-test-renderer@^17.0.0: react-shallow-renderer "^16.13.1" scheduler "^0.20.2" -react-transition-group@^4.4.1: +react-transition-group@^4.4.2: version "4.4.2" resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.2.tgz#8b59a56f09ced7b55cbd53c36768b922890d5470" integrity sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg== @@ -6309,7 +6320,7 @@ react-transition-group@^4.4.1: loose-envify "^1.4.0" prop-types "^15.6.2" -react@^17.0.1: +react@^17.0.1, react@^17.0.2: version "17.0.2" resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== diff --git a/share/jupyterhub/static/js/admin-react.js b/share/jupyterhub/static/js/admin-react.js index 6bc10471..0cf7ccc8 100644 --- a/share/jupyterhub/static/js/admin-react.js +++ b/share/jupyterhub/static/js/admin-react.js @@ -1,2 +1,2 @@ /*! For license information please see admin-react.js.LICENSE.txt */ -(()=>{var e,t,n={966:(e,t,n)=>{"use strict";var r=n(294),a=n(935),o=r.createContext(null),l=function(e){e()},i=function(){return l},u={notify:function(){},get:function(){return[]}};function c(e,t){var n,r=u;function a(){l.onStateChange&&l.onStateChange()}function o(){n||(n=t?t.addNestedSub(a):e.subscribe(a),r=function(){var e=i(),t=null,n=null;return{clear:function(){t=null,n=null},notify:function(){e((function(){for(var e=t;e;)e.callback(),e=e.next}))},get:function(){for(var e=[],n=t;n;)e.push(n),n=n.next;return e},subscribe:function(e){var r=!0,a=n={callback:e,next:null,prev:n};return a.prev?a.prev.next=a:t=a,function(){r&&null!==t&&(r=!1,a.next?a.next.prev=a.prev:n=a.prev,a.prev?a.prev.next=a.next:t=a.next)}}}}())}var l={addNestedSub:function(e){return o(),r.subscribe(e)},notifyNestedSubs:function(){r.notify()},handleChangeWrapper:a,isSubscribed:function(){return Boolean(n)},trySubscribe:o,tryUnsubscribe:function(){n&&(n(),n=void 0,r.clear(),r=u)},getListeners:function(){return r}};return l}var s="undefined"!=typeof window&&void 0!==window.document&&void 0!==window.document.createElement?r.useLayoutEffect:r.useEffect;const f=function(e){var t=e.store,n=e.context,a=e.children,l=(0,r.useMemo)((function(){var e=c(t);return e.onStateChange=e.notifyNestedSubs,{store:t,subscription:e}}),[t]),i=(0,r.useMemo)((function(){return t.getState()}),[t]);s((function(){var e=l.subscription;return e.trySubscribe(),i!==t.getState()&&e.notifyNestedSubs(),function(){e.tryUnsubscribe(),e.onStateChange=null}}),[l,i]);var u=n||o;return r.createElement(u.Provider,{value:l},a)};function d(){return d=Object.assign||function(e){for(var t=1;t1&&void 0!==arguments[1]?arguments[1]:"";return R("/users/"+e+"/servers/"+(t||""),"POST")},stopServer:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return R("/users/"+e+"/servers/"+(t||""),"DELETE")},startAll:function(e){return e.map((function(e){return R("/users/"+e+"/server","POST")}))},stopAll:function(e){return e.map((function(e){return R("/users/"+e+"/server","DELETE")}))},addToGroup:function(e,t){return R("/groups/"+t+"/users","POST",{users:e})},removeFromGroup:function(e,t){return R("/groups/"+t+"/users","DELETE",{users:e})},createGroup:function(e){return R("/groups/"+e,"POST")},deleteGroup:function(e){return R("/groups/"+e,"DELETE")},addUsers:function(e,t){return R("/users","POST",{usernames:e,admin:t})},editUser:function(e,t,n){return R("/users/"+e,"PATCH",{name:t,admin:n})},deleteUser:function(e){return R("/users/"+e,"DELETE")},findUser:function(e){return R("/users/"+e,"GET")},validateUser:function(e){return R("/users/"+e,"GET").then((function(e){return e.status})).then((function(e){return!(e>200)}))},failRegexEvent:function(){return null},noChangeEvent:function(){return null},refreshGroupsData:function(){return R("/groups","GET").then((function(e){return e.json()}))},refreshUserData:function(){return R("/users","GET").then((function(e){return e.json()}))}}},I=function(e){return d({},e,O())},function(e){var t=(0,r.createFactory)(e);return function(e){return t(I(e))}});var I;function M(e){return"/"===e.charAt(0)}function z(e,t){for(var n=t,r=n+1,a=e.length;r=0;s--){var f=a[s];"."===f?z(a,s):".."===f?(z(a,s),c++):c&&(z(a,s),c--)}if(!i)for(;c--;c)a.unshift("..");!i||""===a[0]||a[0]&&M(a[0])||a.unshift("");var d=a.join("/");return n&&"/"!==d.substr(-1)&&(d+="/"),d};"undefined"==typeof window||!window.document||window.document.createElement;var D=n(697),U=n.n(D),$=1073741823,B="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:void 0!==n.g?n.g:{};function H(e){var t=[];return{on:function(e){t.push(e)},off:function(e){t=t.filter((function(t){return t!==e}))},get:function(){return e},set:function(n,r){e=n,t.forEach((function(t){return t(e,r)}))}}}const V=r.createContext||function(e,t){var n,a,o,l="__create-react-context-"+((B[o="__global_unique_id__"]=(B[o]||0)+1)+"__"),i=function(e){function n(){var t;return(t=e.apply(this,arguments)||this).emitter=H(t.props.value),t}P(n,e);var r=n.prototype;return r.getChildContext=function(){var e;return(e={})[l]=this.emitter,e},r.componentWillReceiveProps=function(e){if(this.props.value!==e.value){var n,r=this.props.value,a=e.value;((o=r)===(l=a)?0!==o||1/o==1/l:o!=o&&l!=l)?n=0:(n="function"==typeof t?t(r,a):$,0!=(n|=0)&&this.emitter.set(e.value,n))}var o,l},r.render=function(){return this.props.children},n}(r.Component);i.childContextTypes=((n={})[l]=U().object.isRequired,n);var u=function(t){function n(){var e;return(e=t.apply(this,arguments)||this).state={value:e.getValue()},e.onUpdate=function(t,n){0!=((0|e.observedBits)&n)&&e.setState({value:e.getValue()})},e}P(n,t);var r=n.prototype;return r.componentWillReceiveProps=function(e){var t=e.observedBits;this.observedBits=null==t?$:t},r.componentDidMount=function(){this.context[l]&&this.context[l].on(this.onUpdate);var e=this.props.observedBits;this.observedBits=null==e?$:e},r.componentWillUnmount=function(){this.context[l]&&this.context[l].off(this.onUpdate)},r.getValue=function(){return this.context[l]?this.context[l].get():e},r.render=function(){return(e=this.props.children,Array.isArray(e)?e[0]:e)(this.state.value);var e},n}(r.Component);return u.contextTypes=((a={})[l]=U().object,a),{Provider:i,Consumer:u}};function W(e,t){if(!e)throw new Error("Invariant failed")}var G=n(779),Q=n.n(G);function q(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r=0||(a[n]=e[n]);return a}n(663);var K=function(e){var t=V();return t.displayName=e,t},Y=K("Router-History"),X=K("Router"),J=function(e){function t(t){var n;return(n=e.call(this,t)||this).state={location:t.history.location},n._isMounted=!1,n._pendingLocation=null,t.staticContext||(n.unlisten=t.history.listen((function(e){n._isMounted?n.setState({location:e}):n._pendingLocation=e}))),n}P(t,e),t.computeRootMatch=function(e){return{path:"/",url:"/",params:{},isExact:"/"===e}};var n=t.prototype;return n.componentDidMount=function(){this._isMounted=!0,this._pendingLocation&&this.setState({location:this._pendingLocation})},n.componentWillUnmount=function(){this.unlisten&&(this.unlisten(),this._isMounted=!1,this._pendingLocation=null)},n.render=function(){return r.createElement(X.Provider,{value:{history:this.props.history,location:this.state.location,match:t.computeRootMatch(this.state.location.pathname),staticContext:this.props.staticContext}},r.createElement(Y.Provider,{children:this.props.children||null,value:this.props.history}))},t}(r.Component);r.Component,r.Component;var Z={},ee=0;function te(e,t){void 0===t&&(t={}),("string"==typeof t||Array.isArray(t))&&(t={path:t});var n=t,r=n.path,a=n.exact,o=void 0!==a&&a,l=n.strict,i=void 0!==l&&l,u=n.sensitive,c=void 0!==u&&u;return[].concat(r).reduce((function(t,n){if(!n&&""!==n)return null;if(t)return t;var r=function(e,t){var n=""+t.end+t.strict+t.sensitive,r=Z[n]||(Z[n]={});if(r[e])return r[e];var a=[],o={regexp:Q()(e,a,t),keys:a};return ee<1e4&&(r[e]=o,ee++),o}(n,{end:o,strict:i,sensitive:c}),a=r.regexp,l=r.keys,u=a.exec(e);if(!u)return null;var s=u[0],f=u.slice(1),d=e===s;return o&&!d?null:{path:n,url:"/"===n&&""===s?"/":s,isExact:d,params:l.reduce((function(e,t,n){return e[t.name]=f[n],e}),{})}}),null)}var ne=function(e){function t(){return e.apply(this,arguments)||this}return P(t,e),t.prototype.render=function(){var e=this;return r.createElement(X.Consumer,null,(function(t){t||W(!1);var n=e.props.location||t.location,a=d({},t,{location:n,match:e.props.computedMatch?e.props.computedMatch:e.props.path?te(n.pathname,e.props):t.match}),o=e.props,l=o.children,i=o.component,u=o.render;return Array.isArray(l)&&function(e){return 0===r.Children.count(e)}(l)&&(l=null),r.createElement(X.Provider,{value:a},a.match?l?"function"==typeof l?l(a):l:i?r.createElement(i,a):u?u(a):null:"function"==typeof l?l(a):null)}))},t}(r.Component);r.Component;var re=function(e){function t(){return e.apply(this,arguments)||this}return P(t,e),t.prototype.render=function(){var e=this;return r.createElement(X.Consumer,null,(function(t){t||W(!1);var n,a,o=e.props.location||t.location;return r.Children.forEach(e.props.children,(function(e){if(null==a&&r.isValidElement(e)){n=e;var l=e.props.path||e.props.from;a=l?te(o.pathname,d({},e.props,{path:l})):t.match}})),a?r.cloneElement(n,{location:o,computedMatch:a}):null}))},t}(r.Component);function ae(e){return"/"===e.charAt(0)?e:"/"+e}function oe(e){return"/"===e.charAt(0)?e.substr(1):e}function le(e,t){return function(e,t){return 0===e.toLowerCase().indexOf(t.toLowerCase())&&-1!=="/?#".indexOf(e.charAt(t.length))}(e,t)?e.substr(t.length):e}function ie(e){return"/"===e.charAt(e.length-1)?e.slice(0,-1):e}function ue(e){var t=e.pathname,n=e.search,r=e.hash,a=t||"/";return n&&"?"!==n&&(a+="?"===n.charAt(0)?n:"?"+n),r&&"#"!==r&&(a+="#"===r.charAt(0)?r:"#"+r),a}function ce(e,t,n,r){var a;"string"==typeof e?(a=function(e){var t=e||"/",n="",r="",a=t.indexOf("#");-1!==a&&(r=t.substr(a),t=t.substr(0,a));var o=t.indexOf("?");return-1!==o&&(n=t.substr(o),t=t.substr(0,o)),{pathname:t,search:"?"===n?"":n,hash:"#"===r?"":r}}(e),a.state=t):(void 0===(a=d({},e)).pathname&&(a.pathname=""),a.search?"?"!==a.search.charAt(0)&&(a.search="?"+a.search):a.search="",a.hash?"#"!==a.hash.charAt(0)&&(a.hash="#"+a.hash):a.hash="",void 0!==t&&void 0===a.state&&(a.state=t));try{a.pathname=decodeURI(a.pathname)}catch(e){throw e instanceof URIError?new URIError('Pathname "'+a.pathname+'" could not be decoded. This is likely caused by an invalid percent-encoding.'):e}return n&&(a.key=n),r?a.pathname?"/"!==a.pathname.charAt(0)&&(a.pathname=F(a.pathname,r.pathname)):a.pathname=r.pathname:a.pathname||(a.pathname="/"),a}function se(){var e=null,t=[];return{setPrompt:function(t){return e=t,function(){e===t&&(e=null)}},confirmTransitionTo:function(t,n,r,a){if(null!=e){var o="function"==typeof e?e(t,n):e;"string"==typeof o?"function"==typeof r?r(o,a):a(!0):a(!1!==o)}else a(!0)},appendListener:function(e){var n=!0;function r(){n&&e.apply(void 0,arguments)}return t.push(r),function(){n=!1,t=t.filter((function(e){return e!==r}))}},notifyListeners:function(){for(var e=arguments.length,n=new Array(e),r=0;r=1?r.createElement("button",{className:"btn btn-sm btn-light spaced"},r.createElement(_e,{to:"".concat(t,"?page=").concat(n-1)},r.createElement("span",{className:"active-pagination"},"Previous"))):r.createElement("button",{className:"btn btn-sm btn-light spaced"},r.createElement("span",{className:"inactive-pagination"},"Previous")),l>=a?r.createElement("button",{className:"btn btn-sm btn-light spaced"},r.createElement(_e,{to:"".concat(t,"?page=").concat(n+1)},r.createElement("span",{className:"active-pagination"},"Next"))):r.createElement("button",{className:"btn btn-sm btn-light spaced"},r.createElement("span",{className:"inactive-pagination"},"Next"))))};pt.propTypes={endpoint:U().string,page:U().number,limit:U().number,numOffset:U().number,numElements:U().number};const mt=pt;function ht(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function vt(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function yt(e,t,n,r,a,o,l){try{var i=e[o](l),u=i.value}catch(e){return void n(e)}i.done?t(u):Promise.resolve(u).then(r,a)}function gt(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=n){var r,a,o=[],l=!0,i=!1;try{for(n=n.call(e);!(l=(r=n.next()).done)&&(o.push(r.value),!t||o.length!==t);l=!0);}catch(e){i=!0,a=e}finally{try{l||null==n.return||n.return()}finally{if(i)throw a}}return o}}(e,t)||function(e,t){if(e){if("string"==typeof e)return bt(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?bt(e,t):void 0}}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function bt(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);nt.name?1:-1}))},o=function(e){return e.sort((function(e,t){return e.name Manage Groups"))),r.createElement("table",{className:"table table-striped table-bordered table-hover"},r.createElement("thead",{className:"admin-table-head"},r.createElement("tr",null,r.createElement("th",{id:"user-header"},"User"," ",r.createElement(kt,{sorts:{asc:o,desc:a},callback:function(e){return f((function(){return e}))},testid:"user-sort"})),r.createElement("th",{id:"admin-header"},"Admin"," ",r.createElement(kt,{sorts:{asc:function(e){return e.sort((function(e){return e.admin?1:-1}))},desc:function(e){return e.sort((function(e){return e.admin?-1:1}))}},callback:function(e){return f((function(){return e}))},testid:"admin-sort"})),r.createElement("th",{id:"server-header"},"Server"," ",r.createElement(kt,{sorts:{asc:o,desc:a},callback:function(e){return f((function(){return e}))},testid:"server-sort"})),r.createElement("th",{id:"last-activity-header"},"Last Activity"," ",r.createElement(kt,{sorts:{asc:function(e){return e.sort((function(e,t){return new Date(e.last_activity)-new Date(t.last_activity)>0?1:-1}))},desc:function(e){return e.sort((function(e,t){return new Date(e.last_activity)-new Date(t.last_activity)>0?-1:1}))}},callback:function(e){return f((function(){return e}))},testid:"last-activity-sort"})),r.createElement("th",{id:"running-status-header"},"Running"," ",r.createElement(kt,{sorts:{asc:function(e){return e.sort((function(e){return null==e.server?-1:1}))},desc:function(e){return e.sort((function(e){return null==e.server?1:-1}))}},callback:function(e){return f((function(){return e}))},testid:"running-status-sort"})),r.createElement("th",{id:"actions-header"},"Actions"))),r.createElement("tbody",null,r.createElement("tr",{className:"noborder"},r.createElement("td",null,r.createElement(rt,{variant:"light",className:"add-users-button"},r.createElement(_e,{to:"/add-users"},"Add Users"))),r.createElement("td",null),r.createElement("td",null),r.createElement("td",null,r.createElement(rt,{variant:"primary",className:"start-all","data-testid":"start-all",onClick:function(){Promise.all(C(p.map((function(e){return e.name})))).then((function(e){var t=e.filter((function(e){return!e.ok}));return t.length>0&&u("Failed to start ".concat(t.length," ").concat(t.length>1?"servers":"server",". ").concat(t.length>1?"Are they ":"Is it "," already running?")),e})).then((function(e){return k.apply(void 0,b).then((function(e){O(e,g,v)})).catch((function(){return u("Failed to update users list.")})),e})).catch((function(){return u("Failed to start servers.")}))}},"Start All"),r.createElement("span",null," "),r.createElement(rt,{variant:"danger",className:"stop-all","data-testid":"stop-all",onClick:function(){Promise.all(N(p.map((function(e){return e.name})))).then((function(e){var t=e.filter((function(e){return!e.ok}));return t.length>0&&u("Failed to stop ".concat(t.length," ").concat(t.length>1?"servers":"server",". ").concat(t.length>1?"Are they ":"Is it "," already stopped?")),e})).then((function(e){return k.apply(void 0,b).then((function(e){O(e,g,v)})).catch((function(){return u("Failed to update users list.")})),e})).catch((function(){return u("Failed to stop servers.")}))}},"Stop All")),r.createElement("td",null,r.createElement(rt,{variant:"danger",id:"shutdown-button",onClick:S},"Shutdown Hub"))),A.map((function(e,n){var a,o,l,i,u,c,s=gt(e,2),f=s[0],d=s[1];return d.name=d.name||"",r.createElement("tr",{key:n+"row",className:"user-row"},r.createElement("td",{"data-testid":"user-row-name"},f.name),r.createElement("td",{"data-testid":"user-row-admin"},f.admin?"admin":""),r.createElement("td",{"data-testid":"user-row-server"},d.name?r.createElement("p",{class:"text-secondary"},d.name):r.createElement("p",{style:{color:"lightgrey"}},"[MAIN]")),r.createElement("td",{"data-testid":"user-row-last-activity"},d.last_activity?(a=d.last_activity,6e4,o=36e5,l=864e5,i=2592e6,u=31536e6,(c=Date.now()-Date.parse(a))<6e4?Math.round(c/1e3)+" seconds ago":c0?n.map((function(e,n){return r.createElement("li",{className:"list-group-item",key:"group-item"+n},r.createElement("span",{className:"badge badge-pill badge-success"},e.users.length+" users"),r.createElement(_e,{to:{pathname:"/group-edit",state:{group_data:e,user_data:t}}},e.name))})):r.createElement("div",null,r.createElement("h4",null,"no groups created..."))),r.createElement(mt,{endpoint:"/groups",page:i,limit:o,numOffset:u[0],numElements:n.length})),r.createElement("div",{className:"panel-footer"},r.createElement("button",{className:"btn btn-light adjacent-span-spacing"},r.createElement(_e,{to:"/"},"Back")),r.createElement("button",{className:"btn btn-primary adjacent-span-spacing",onClick:function(){s.push("/create-group")}},"New Group"))))))):r.createElement("div",{"data-testid":"no-show"})};xt.propTypes={user_data:U().array,groups_data:U().array,updateUsers:U().func,updateGroups:U().func,history:U().shape({push:U().func}),location:U().shape({search:U().string})};const _t=xt;function Ct(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=n){var r,a,o=[],l=!0,i=!1;try{for(n=n.call(e);!(l=(r=n.next()).done)&&(o.push(r.value),!t||o.length!==t);l=!0);}catch(e){i=!0,a=e}finally{try{l||null==n.return||n.return()}finally{if(i)throw a}}return o}}(e,t)||function(e,t){if(e){if("string"==typeof e)return Nt(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?Nt(e,t):void 0}}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Nt(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);ne.length)&&(t=e.length);for(var n=0,r=new Array(t);n0&&r.push(m(e,S.name)),t.length>0&&r.push(h(t,S.name)),Promise.all(r).then((function(e){0==e.map((function(e){return e.status})).filter((function(e){return e>=300})).length?g(0,f).then((function(e){return p(e,0)})).then((function(){return w.push("/groups")})):s("Failed to edit group.")})).catch((function(){console.log("outer"),s("Failed to edit group.")}))}else w.push("/groups")}},"Apply"),r.createElement("button",{id:"delete-group","data-testid":"delete-group",className:"btn btn-danger",style:{float:"right"},onClick:function(){var e=S.name;v(e).then((function(e){e.status<300?g(0,f).then((function(e){return p(e,0)})).then((function(){return w.push("/groups")})):s("Failed to delete group.")})).catch((function(){return s("Failed to delete group.")}))}},"Delete Group"),r.createElement("br",null),r.createElement("br",null)))):r.createElement("div",null)};jt.propTypes={location:U().shape({state:U().shape({group_data:U().object,callback:U().func})}),history:U().shape({push:U().func}),addToGroup:U().func,removeFromGroup:U().func,deleteGroup:U().func,updateGroups:U().func,validateUser:U().func};const Rt=jt;function At(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=n){var r,a,o=[],l=!0,i=!1;try{for(n=n.call(e);!(l=(r=n.next()).done)&&(o.push(r.value),!t||o.length!==t);l=!0);}catch(e){i=!0,a=e}finally{try{l||null==n.return||n.return()}finally{if(i)throw a}}return o}}(e,t)||function(e,t){if(e){if("string"==typeof e)return It(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?It(e,t):void 0}}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function It(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);ne.length)&&(t=e.length);for(var n=0,r=new Array(t);n2&&0==/[!@#$%^&*(),.?":{}|<>]/g.test(e)}));e.lengthe.length)&&(t=e.length);for(var n=0,r=new Array(t);n2&&0==/[!@#$%^&*(),.?":{}|<>]/g.test(g)?u(m,""!=g?g:m,k).then((function(e){e.status<300?f(0,t).then((function(e){return i(e,0)})).then((function(){return d.push("/")})).catch((function(){return o("Could not update users list.")})):o("Failed to edit user.")})).catch((function(){o("Failed to edit user.")})):o("Failed to edit user. Make sure the username does not contain special characters."):u(m,m,k).then((function(e){e.status<300?f(0,t).then((function(e){return i(e,0)})).then((function(){return d.push("/")})).catch((function(){return o("Could not update users list.")})):o("Failed to edit user.")})).catch((function(){o("Failed to edit user.")})):s()}},"Apply")))))))};Vt.propTypes={location:U().shape({state:U().shape({username:U().string,has_admin:U().bool})}),history:U().shape({push:U().func}),editUser:U().func,deleteUser:U().func,failRegexEvent:U().func,noChangeEvent:U().func,updateUsers:U().func};const Wt=Vt;n(137);var Gt=function e(t,n,r){var a;if("function"==typeof n&&"function"==typeof r||"function"==typeof r&&"function"==typeof arguments[3])throw new Error(k(0));if("function"==typeof n&&void 0===r&&(r=n,n=void 0),void 0!==r){if("function"!=typeof r)throw new Error(k(1));return r(e)(t,n)}if("function"!=typeof t)throw new Error(k(2));var o=t,l=n,i=[],u=i,c=!1;function s(){u===i&&(u=i.slice())}function f(){if(c)throw new Error(k(3));return l}function d(e){if("function"!=typeof e)throw new Error(k(4));if(c)throw new Error(k(5));var t=!0;return s(),u.push(e),function(){if(t){if(c)throw new Error(k(6));t=!1,s();var n=u.indexOf(e);u.splice(n,1),i=null}}}function p(e){if(!C(e))throw new Error(k(7));if(void 0===e.type)throw new Error(k(8));if(c)throw new Error(k(9));try{c=!0,l=o(l,e)}finally{c=!1}for(var t=i=u,n=0;n0&&void 0!==arguments[0]?arguments[0]:j,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case"USER_PAGE":return Object.assign({},e,{user_page:t.value.page,user_data:t.value.data,name_filter:t.value.name_filter});case"GROUPS_PAGE":return Object.assign({},e,{groups_page:t.value.page,groups_data:t.value.data});default:return e}}),j),Qt=function(){return(0,r.useEffect)((function(){var e=j.limit,t=j.groups_page;R("/users?offset=".concat(j.user_page*e,"&limit=").concat(e),"GET").then((function(e){return e.json()})).then((function(e){return Gt.dispatch({type:"USER_PAGE",value:{data:e,page:0}})})).catch((function(e){return console.log(e)})),R("/groups?offset=".concat(t*e,"&limit=").concat(e),"GET").then((function(e){return e.json()})).then((function(e){return Gt.dispatch({type:"GROUPS_PAGE",value:{data:e,page:0}})})).catch((function(e){return console.log(e)}))})),r.createElement("div",{className:"resets"},r.createElement(f,{store:Gt},r.createElement(be,null,r.createElement(re,null,r.createElement(ne,{exact:!0,path:"/",component:T(A)(St)}),r.createElement(ne,{exact:!0,path:"/groups",component:T(A)(_t)}),r.createElement(ne,{exact:!0,path:"/group-edit",component:T(A)(Rt)}),r.createElement(ne,{exact:!0,path:"/create-group",component:T(A)(zt)}),r.createElement(ne,{exact:!0,path:"/add-users",component:T(A)($t)}),r.createElement(ne,{exact:!0,path:"/edit-user",component:T(A)(Wt)})))))};a.render(r.createElement(Qt,null),document.getElementById("react-admin-hook"))},790:(e,t)=>{"use strict";t.E=function(){var e=[],t=e;function n(){t===e&&(t=e.slice())}return{listen:function(e){if("function"!=typeof e)throw new Error("Expected listener to be a function.");var r=!0;return n(),t.push(e),function(){if(r){r=!1,n();var a=t.indexOf(e);t.splice(a,1)}}},emit:function(){for(var n=e=t,r=0;r{var n;!function(){"use strict";var r={}.hasOwnProperty;function a(){for(var e=[],t=0;t{"use strict";n.r(t),n.d(t,{default:()=>i});var r=n(645),a=n.n(r),o=n(223),l=a()((function(e){return e[1]}));l.i(o.default),l.push([e.id,".users-container {\n width: 100%;\n position: relative;\n padding: 5px;\n overflow-x: scroll;\n}\n\n.users-container div {\n display: inline-block;\n}\n\n.users-container .item {\n padding: 3px;\n padding-left: 6px;\n padding-right: 6px;\n border-radius: 3px;\n font-size: 14px;\n margin-left: 4px;\n margin-right: 4px;\n transition: 30ms ease-in all;\n cursor: pointer;\n user-select: none;\n border: solid 1px #dfdfdf;\n}\n\n.users-container .item.unselected {\n background-color: #f7f7f7;\n color: #777;\n}\n\n.users-container .item.selected {\n background-color: orange;\n color: white;\n}\n\n.users-container .item:hover {\n opacity: 0.7;\n}\n",""]);const i=l},457:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>i});var r=n(645),a=n.n(r),o=n(223),l=a()((function(e){return e[1]}));l.i(o.default),l.push([e.id,".pagination-footer * button {\n margin-right: 10px;\n}\n\n.pagination-footer * .inactive-pagination {\n color: gray;\n cursor: not-allowed;\n}\n\n.pagination-footer * button.spaced {\n color: var(--blue);\n}\n",""]);const i=l},642:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>i});var r=n(645),a=n.n(r),o=n(223),l=a()((function(e){return e[1]}));l.i(o.default),l.push([e.id,".server-dashboard-container {\n padding-right: 15px;\n padding-left: 15px;\n margin-right: auto;\n margin-left: auto;\n}\n\n.server-dashboard-container .add-users-button {\n border: 1px solid #ddd;\n}\n\n.server-dashboard-container tbody {\n color: #626262;\n}\n\n.admin-table-head {\n user-select: none;\n}\n\n.sort-icon {\n display: inline-block;\n top: 0.125em;\n position: relative;\n user-select: none;\n cursor: pointer;\n}\n\ntr.noborder > td {\n border: none !important;\n}\n",""]);const i=l},223:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>o});var r=n(645),a=n.n(r)()((function(e){return e[1]}));a.push([e.id,":root {\n --red: #d7191e;\n --orange: #f1ad4e;\n --blue: #2e7ab6;\n --white: #ffffff;\n --gray: #f7f7f7;\n}\n\n/* Color Classes */\n.red {\n background-color: var(--red);\n}\n.orange {\n background-color: var(--orange);\n}\n.blue {\n background-color: var(--blue);\n}\n.white {\n background-color: var(--white);\n}\n\n/* Resets */\n\n.resets .modal {\n display: block;\n visibility: visible;\n z-index: 2000;\n}\n\n/* Global Util Classes */\n.adjacent-span-spacing {\n margin-right: 5px;\n margin-left: 5px;\n}\n",""]);const o=a},645:e=>{"use strict";e.exports=function(e){var t=[];return t.toString=function(){return this.map((function(t){var n=e(t);return t[2]?"@media ".concat(t[2]," {").concat(n,"}"):n})).join("")},t.i=function(e,n,r){"string"==typeof e&&(e=[[null,e,""]]);var a={};if(r)for(var o=0;o{"use strict";var t=Object.prototype.hasOwnProperty;function n(e,t){return e===t?0!==e||0!==t||1/e==1/t:e!=e&&t!=t}e.exports=function(e,r){if(n(e,r))return!0;if("object"!=typeof e||null===e||"object"!=typeof r||null===r)return!1;var a=Object.keys(e),o=Object.keys(r);if(a.length!==o.length)return!1;for(var l=0;l{"use strict";var r=n(296),a={childContextTypes:!0,contextType:!0,contextTypes:!0,defaultProps:!0,displayName:!0,getDefaultProps:!0,getDerivedStateFromError:!0,getDerivedStateFromProps:!0,mixins:!0,propTypes:!0,type:!0},o={name:!0,length:!0,prototype:!0,caller:!0,callee:!0,arguments:!0,arity:!0},l={$$typeof:!0,compare:!0,defaultProps:!0,displayName:!0,propTypes:!0,type:!0},i={};function u(e){return r.isMemo(e)?l:i[e.$$typeof]||a}i[r.ForwardRef]={$$typeof:!0,render:!0,defaultProps:!0,displayName:!0,propTypes:!0},i[r.Memo]=l;var c=Object.defineProperty,s=Object.getOwnPropertyNames,f=Object.getOwnPropertySymbols,d=Object.getOwnPropertyDescriptor,p=Object.getPrototypeOf,m=Object.prototype;e.exports=function e(t,n,r){if("string"!=typeof n){if(m){var a=p(n);a&&a!==m&&e(t,a,r)}var l=s(n);f&&(l=l.concat(f(n)));for(var i=u(t),h=u(n),v=0;v{"use strict";var n="function"==typeof Symbol&&Symbol.for,r=n?Symbol.for("react.element"):60103,a=n?Symbol.for("react.portal"):60106,o=n?Symbol.for("react.fragment"):60107,l=n?Symbol.for("react.strict_mode"):60108,i=n?Symbol.for("react.profiler"):60114,u=n?Symbol.for("react.provider"):60109,c=n?Symbol.for("react.context"):60110,s=n?Symbol.for("react.async_mode"):60111,f=n?Symbol.for("react.concurrent_mode"):60111,d=n?Symbol.for("react.forward_ref"):60112,p=n?Symbol.for("react.suspense"):60113,m=n?Symbol.for("react.suspense_list"):60120,h=n?Symbol.for("react.memo"):60115,v=n?Symbol.for("react.lazy"):60116,y=n?Symbol.for("react.block"):60121,g=n?Symbol.for("react.fundamental"):60117,b=n?Symbol.for("react.responder"):60118,w=n?Symbol.for("react.scope"):60119;function E(e){if("object"==typeof e&&null!==e){var t=e.$$typeof;switch(t){case r:switch(e=e.type){case s:case f:case o:case i:case l:case p:return e;default:switch(e=e&&e.$$typeof){case c:case d:case v:case h:case u:return e;default:return t}}case a:return t}}}function k(e){return E(e)===f}t.AsyncMode=s,t.ConcurrentMode=f,t.ContextConsumer=c,t.ContextProvider=u,t.Element=r,t.ForwardRef=d,t.Fragment=o,t.Lazy=v,t.Memo=h,t.Portal=a,t.Profiler=i,t.StrictMode=l,t.Suspense=p,t.isAsyncMode=function(e){return k(e)||E(e)===s},t.isConcurrentMode=k,t.isContextConsumer=function(e){return E(e)===c},t.isContextProvider=function(e){return E(e)===u},t.isElement=function(e){return"object"==typeof e&&null!==e&&e.$$typeof===r},t.isForwardRef=function(e){return E(e)===d},t.isFragment=function(e){return E(e)===o},t.isLazy=function(e){return E(e)===v},t.isMemo=function(e){return E(e)===h},t.isPortal=function(e){return E(e)===a},t.isProfiler=function(e){return E(e)===i},t.isStrictMode=function(e){return E(e)===l},t.isSuspense=function(e){return E(e)===p},t.isValidElementType=function(e){return"string"==typeof e||"function"==typeof e||e===o||e===f||e===i||e===l||e===p||e===m||"object"==typeof e&&null!==e&&(e.$$typeof===v||e.$$typeof===h||e.$$typeof===u||e.$$typeof===c||e.$$typeof===d||e.$$typeof===g||e.$$typeof===b||e.$$typeof===w||e.$$typeof===y)},t.typeOf=E},296:(e,t,n)=>{"use strict";e.exports=n(103)},954:(e,t,n)=>{var r=/^\s+|\s+$/g,a=/^[-+]0x[0-9a-f]+$/i,o=/^0b[01]+$/i,l=/^0o[0-7]+$/i,i=parseInt,u="object"==typeof n.g&&n.g&&n.g.Object===Object&&n.g,c="object"==typeof self&&self&&self.Object===Object&&self,s=u||c||Function("return this")(),f=Object.prototype.toString,d=Math.max,p=Math.min,m=function(){return s.Date.now()};function h(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}function v(e){if("number"==typeof e)return e;if(function(e){return"symbol"==typeof e||function(e){return!!e&&"object"==typeof e}(e)&&"[object Symbol]"==f.call(e)}(e))return NaN;if(h(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=h(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(r,"");var n=o.test(e);return n||l.test(e)?i(e.slice(2),n?2:8):a.test(e)?NaN:+e}e.exports=function(e,t,n){var r,a,o,l,i,u,c=0,s=!1,f=!1,y=!0;if("function"!=typeof e)throw new TypeError("Expected a function");function g(t){var n=r,o=a;return r=a=void 0,c=t,l=e.apply(o,n)}function b(e){return c=e,i=setTimeout(E,t),s?g(e):l}function w(e){var n=e-u;return void 0===u||n>=t||n<0||f&&e-c>=o}function E(){var e=m();if(w(e))return k(e);i=setTimeout(E,function(e){var n=t-(e-u);return f?p(n,o-(e-c)):n}(e))}function k(e){return i=void 0,y&&r?g(e):(r=a=void 0,l)}function S(){var e=m(),n=w(e);if(r=arguments,a=this,u=e,n){if(void 0===i)return b(u);if(f)return i=setTimeout(E,t),g(u)}return void 0===i&&(i=setTimeout(E,t)),l}return t=v(t)||0,h(n)&&(s=!!n.leading,o=(f="maxWait"in n)?d(v(n.maxWait)||0,t):o,y="trailing"in n?!!n.trailing:y),S.cancel=function(){void 0!==i&&clearTimeout(i),c=0,r=u=a=i=void 0},S.flush=function(){return void 0===i?l:k(m())},S}},418:e=>{"use strict";var t=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable;function a(e){if(null==e)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(e)}e.exports=function(){try{if(!Object.assign)return!1;var e=new String("abc");if(e[5]="de","5"===Object.getOwnPropertyNames(e)[0])return!1;for(var t={},n=0;n<10;n++)t["_"+String.fromCharCode(n)]=n;if("0123456789"!==Object.getOwnPropertyNames(t).map((function(e){return t[e]})).join(""))return!1;var r={};return"abcdefghijklmnopqrst".split("").forEach((function(e){r[e]=e})),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},r)).join("")}catch(e){return!1}}()?Object.assign:function(e,o){for(var l,i,u=a(e),c=1;c{var r=n(173);e.exports=function e(t,n,a){return r(n)||(a=n||a,n=[]),a=a||{},t instanceof RegExp?function(e,t){var n=e.source.match(/\((?!\?)/g);if(n)for(var r=0;r{e.exports=Array.isArray||function(e){return"[object Array]"==Object.prototype.toString.call(e)}},391:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(){for(var e=arguments.length,t=Array(e),n=0;n{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e){function t(t,n,r,a,o,l){var i=a||"<>",u=l||r;if(null==n[r])return t?new Error("Required "+o+" `"+u+"` was not specified in `"+i+"`."):null;for(var c=arguments.length,s=Array(c>6?c-6:0),f=6;f{"use strict";var r=n(414);function a(){}function o(){}o.resetWarningCache=a,e.exports=function(){function e(e,t,n,a,o,l){if(l!==r){var i=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw i.name="Invariant Violation",i}}function t(){return e}e.isRequired=e;var n={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:o,resetWarningCache:a};return n.PropTypes=n,n}},697:(e,t,n)=>{e.exports=n(703)()},414:e=>{"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},448:(e,t,n)=>{"use strict";var r=n(294),a=n(418),o=n(840);function l(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n