Add search bar for user name

This commit is contained in:
Narek Amirbekian
2022-03-11 15:12:53 -08:00
parent 6c5e5452bc
commit b3f04e7c66
6 changed files with 1157 additions and 1132 deletions

View File

@@ -40,6 +40,7 @@
"eslint-plugin-unused-imports": "^1.1.1", "eslint-plugin-unused-imports": "^1.1.1",
"file-loader": "^6.2.0", "file-loader": "^6.2.0",
"history": "^5.0.0", "history": "^5.0.0",
"lodash.debounce": "^4.0.8",
"prop-types": "^15.7.2", "prop-types": "^15.7.2",
"react": "^17.0.1", "react": "^17.0.1",
"react-bootstrap": "^1.4.0", "react-bootstrap": "^1.4.0",
@@ -51,6 +52,7 @@
"react-router-dom": "^5.2.0", "react-router-dom": "^5.2.0",
"recompose": "^0.30.0", "recompose": "^0.30.0",
"redux": "^4.0.5", "redux": "^4.0.5",
"regenerator-runtime": "^0.13.9",
"style-loader": "^2.0.0", "style-loader": "^2.0.0",
"webpack": "^5.6.0", "webpack": "^5.6.0",
"webpack-cli": "^3.3.4", "webpack-cli": "^3.3.4",

View File

@@ -1,8 +1,9 @@
import React, { useState } from "react"; import React, { useState } from "react";
import regeneratorRuntime from "regenerator-runtime";
import { useSelector, useDispatch } from "react-redux"; import { useSelector, useDispatch } from "react-redux";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import { Button } from "react-bootstrap"; import { Button, Col, Row, FormControl } from "react-bootstrap";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { FaSort, FaSortUp, FaSortDown } from "react-icons/fa"; import { FaSort, FaSortUp, FaSortDown } from "react-icons/fa";
@@ -37,6 +38,7 @@ const ServerDashboard = (props) => {
var [errorAlert, setErrorAlert] = useState(null); var [errorAlert, setErrorAlert] = useState(null);
var [sortMethod, setSortMethod] = useState(null); var [sortMethod, setSortMethod] = useState(null);
var [name_filter, setNameFilter] = useState("");
var [disabledButtons, setDisabledButtons] = useState({}); var [disabledButtons, setDisabledButtons] = useState({});
var user_data = useSelector((state) => state.user_data), var user_data = useSelector((state) => state.user_data),
@@ -45,7 +47,7 @@ const ServerDashboard = (props) => {
page = parseInt(new URLSearchParams(props.location.search).get("page")); page = parseInt(new URLSearchParams(props.location.search).get("page"));
page = isNaN(page) ? 0 : page; page = isNaN(page) ? 0 : page;
var slice = [page * limit, limit]; var slice = [page * limit, limit, name_filter];
const dispatch = useDispatch(); const dispatch = useDispatch();
@@ -77,6 +79,14 @@ const ServerDashboard = (props) => {
updateUsers(...slice).then((data) => dispatchPageUpdate(data, page)); updateUsers(...slice).then((data) => dispatchPageUpdate(data, page));
} }
var debounce = require("lodash.debounce");
const handleSearch = debounce(async (event) => {
setNameFilter(event.target.value);
updateUsers(page * limit, limit, event.target.value).then((data) =>
dispatchPageUpdate(data, page)
);
}, 300);
if (sortMethod != null) { if (sortMethod != null) {
user_data = sortMethod(user_data); user_data = sortMethod(user_data);
} }
@@ -203,10 +213,22 @@ const ServerDashboard = (props) => {
) : ( ) : (
<></> <></>
)} )}
<div className="manage-groups" style={{ float: "right", margin: "20px" }}>
<Link to="/groups">{"> Manage Groups"}</Link>
</div>
<div className="server-dashboard-container"> <div className="server-dashboard-container">
<Row>
<Col md={4}>
<FormControl
type="text"
name="user_search"
placeholder="Search users"
defaultValue={name_filter}
onChange={handleSearch}
/>
</Col>
<Col md="auto" style={{ float: "right", margin: 15 }}>
<Link to="/groups">{"> Manage Groups"}</Link>
</Col>
</Row>
<table className="table table-striped table-bordered table-hover"> <table className="table table-striped table-bordered table-hover">
<thead className="admin-table-head"> <thead className="admin-table-head">
<tr> <tr>

View File

@@ -2,10 +2,11 @@ import { withProps } from "recompose";
import { jhapiRequest } from "./jhapiUtil"; import { jhapiRequest } from "./jhapiUtil";
const withAPI = withProps(() => ({ const withAPI = withProps(() => ({
updateUsers: (offset, limit) => updateUsers: (offset, limit, name_filter) =>
jhapiRequest(`/users?offset=${offset}&limit=${limit}`, "GET").then((data) => jhapiRequest(
data.json() `/users?offset=${offset}&limit=${limit}&name_filter=${name_filter}`,
), "GET"
).then((data) => data.json()),
updateGroups: (offset, limit) => updateGroups: (offset, limit) =>
jhapiRequest(`/groups?offset=${offset}&limit=${limit}`, "GET").then( jhapiRequest(`/groups?offset=${offset}&limit=${limit}`, "GET").then(
(data) => data.json() (data) => data.json()

File diff suppressed because it is too large Load Diff

View File

@@ -84,6 +84,7 @@ class UserListAPIHandler(APIHandler):
@needs_scope('list:users') @needs_scope('list:users')
def get(self): def get(self):
state_filter = self.get_argument("state", None) state_filter = self.get_argument("state", None)
name_filter = self.get_argument("name_filter", None)
offset, limit = self.get_api_pagination() offset, limit = self.get_api_pagination()
# post_filter # post_filter
@@ -148,6 +149,9 @@ class UserListAPIHandler(APIHandler):
else: else:
query = query.filter(or_(*filters)) query = query.filter(or_(*filters))
if name_filter:
query = query.filter(orm.User.name.ilike(f'%{name_filter}%'))
full_query = query full_query = query
query = query.order_by(orm.User.id.asc()).offset(offset).limit(limit) query = query.order_by(orm.User.id.asc()).offset(offset).limit(limit)

File diff suppressed because one or more lines are too long