Add persistent URL / stateful pagination for users

This commit is contained in:
Nathan Barber
2021-05-05 12:55:36 -04:00
parent 144a018705
commit f1ddb58d7d
5 changed files with 65 additions and 12 deletions

View File

@@ -21,12 +21,13 @@ const store = createStore(reducers, initialState);
const App = (props) => { const App = (props) => {
useEffect(() => { useEffect(() => {
jhapiRequest("/users", "GET") let { limit, user_page, groups_page } = initialState;
jhapiRequest(`/users?offset=${user_page * limit}&limit=${limit}`, "GET")
.then((data) => data.json()) .then((data) => data.json())
.then((data) => store.dispatch({ type: "USER_DATA", value: data })) .then((data) => store.dispatch({ type: "USER_DATA", value: data }))
.catch((err) => console.log(err)); .catch((err) => console.log(err));
jhapiRequest("/groups", "GET") jhapiRequest(`/groups?offset=${groups_page * limit}&limit=${limit}`, "GET")
.then((data) => data.json()) .then((data) => data.json())
.then((data) => store.dispatch({ type: "GROUPS_DATA", value: data })) .then((data) => store.dispatch({ type: "GROUPS_DATA", value: data }))
.catch((err) => console.log(err)); .catch((err) => console.log(err));

View File

@@ -2,7 +2,10 @@ import { combineReducers } from "redux";
export const initialState = { export const initialState = {
user_data: undefined, user_data: undefined,
user_page: 0,
groups_data: undefined, groups_data: undefined,
groups_page: 0,
limit: 50,
manage_groups_modal: false, manage_groups_modal: false,
}; };
@@ -10,6 +13,11 @@ export const reducers = (state = initialState, action) => {
switch (action.type) { switch (action.type) {
case "USER_DATA": case "USER_DATA":
return Object.assign({}, state, { user_data: action.value }); return Object.assign({}, state, { user_data: action.value });
case "USER_PAGE":
return Object.assign({}, state, {
user_page: action.value.page,
user_data: action.value.data,
});
case "GROUPS_DATA": case "GROUPS_DATA":
return Object.assign({}, state, { groups_data: action.value }); return Object.assign({}, state, { groups_data: action.value });
case "TOGGLE_MANAGE_GROUPS_MODAL": case "TOGGLE_MANAGE_GROUPS_MODAL":

View File

@@ -31,6 +31,11 @@ const ServerDashboard = (props) => {
var [sortMethod, setSortMethod] = useState(null); var [sortMethod, setSortMethod] = useState(null);
var user_data = useSelector((state) => state.user_data); var user_data = useSelector((state) => state.user_data);
var user_page = useSelector((state) => state.user_page);
var limit = useSelector((state) => state.limit);
var page = parseInt(new URLSearchParams(props.location.search).get("page"));
page = isNaN(page) ? 0 : page;
var slice = [page * limit, limit];
const dispatch = useDispatch(); const dispatch = useDispatch();
@@ -51,10 +56,26 @@ const ServerDashboard = (props) => {
}); });
}; };
var dispatchPageChange = (data, page) => {
dispatch({
type: "USER_PAGE",
value: {
data: data,
page: page,
},
});
};
if (!user_data) { if (!user_data) {
return <div></div>; return <div></div>;
} }
if (page != user_page) {
updateUsers(...slice)
.then((data) => data.json())
.then((data) => dispatchPageChange(data, page));
}
if (sortMethod != null) { if (sortMethod != null) {
user_data = sortMethod(user_data); user_data = sortMethod(user_data);
} }
@@ -116,7 +137,7 @@ const ServerDashboard = (props) => {
onClick={() => { onClick={() => {
Promise.all(startAll(user_data.map((e) => e.name))) Promise.all(startAll(user_data.map((e) => e.name)))
.then((res) => { .then((res) => {
updateUsers() updateUsers(...slice)
.then((data) => data.json()) .then((data) => data.json())
.then((data) => { .then((data) => {
dispatchUserUpdate(data); dispatchUserUpdate(data);
@@ -137,7 +158,7 @@ const ServerDashboard = (props) => {
onClick={() => { onClick={() => {
Promise.all(stopAll(user_data.map((e) => e.name))) Promise.all(stopAll(user_data.map((e) => e.name)))
.then((res) => { .then((res) => {
updateUsers() updateUsers(...slice)
.then((data) => data.json()) .then((data) => data.json())
.then((data) => { .then((data) => {
dispatchUserUpdate(data); dispatchUserUpdate(data);
@@ -177,7 +198,7 @@ const ServerDashboard = (props) => {
onClick={() => onClick={() =>
stopServer(e.name) stopServer(e.name)
.then((res) => { .then((res) => {
updateUsers() updateUsers(...slice)
.then((data) => data.json()) .then((data) => data.json())
.then((data) => { .then((data) => {
dispatchUserUpdate(data); dispatchUserUpdate(data);
@@ -196,7 +217,7 @@ const ServerDashboard = (props) => {
onClick={() => onClick={() =>
startServer(e.name) startServer(e.name)
.then((res) => { .then((res) => {
updateUsers() updateUsers(...slice)
.then((data) => data.json()) .then((data) => data.json())
.then((data) => { .then((data) => {
dispatchUserUpdate(data); dispatchUserUpdate(data);
@@ -232,6 +253,25 @@ const ServerDashboard = (props) => {
))} ))}
</tbody> </tbody>
</table> </table>
<br></br>
<p>
Displaying users {slice[0]}-{slice[0] + user_data.length}
{user_data.length >= limit ? (
<button className="btn btn-link">
<Link to={`/?page=${page + 1}`}>Next</Link>
</button>
) : (
<></>
)}
{page >= 1 ? (
<button className="btn btn-link">
<Link to={`/?page=${page - 1}`}>Previous</Link>
</button>
) : (
<></>
)}
</p>
<br></br>
</div> </div>
</div> </div>
); );
@@ -249,6 +289,9 @@ ServerDashboard.propTypes = {
history: PropTypes.shape({ history: PropTypes.shape({
push: PropTypes.func, push: PropTypes.func,
}), }),
location: PropTypes.shape({
search: PropTypes.string,
}),
}; };
const SortHandler = (props) => { const SortHandler = (props) => {

View File

@@ -2,7 +2,8 @@ import { withProps } from "recompose";
import { jhapiRequest } from "./jhapiUtil"; import { jhapiRequest } from "./jhapiUtil";
const withAPI = withProps((props) => ({ const withAPI = withProps((props) => ({
updateUsers: (cb) => jhapiRequest("/users", "GET"), updateUsers: (offset, limit) =>
jhapiRequest(`/users?offset=${offset}&limit=${limit}`, "GET"),
shutdownHub: () => jhapiRequest("/shutdown", "POST"), shutdownHub: () => jhapiRequest("/shutdown", "POST"),
startServer: (name) => jhapiRequest("/users/" + name + "/server", "POST"), startServer: (name) => jhapiRequest("/users/" + name + "/server", "POST"),
stopServer: (name) => jhapiRequest("/users/" + name + "/server", "DELETE"), stopServer: (name) => jhapiRequest("/users/" + name + "/server", "DELETE"),

File diff suppressed because one or more lines are too long