shared frontend, UserAPI invalidate sessions, bugfixes, stuff
This commit is contained in:
@@ -1,17 +1,22 @@
|
||||
import {Link, Navigate, useNavigate} from "react-router-dom";
|
||||
import {useCallback, useContext, useEffect} from "react";
|
||||
import {useCallback, useContext, useEffect, useState} from "react";
|
||||
import {LocaleContext} from "shared/locale";
|
||||
import {DataColumn, DataTable, NumericColumn, StringColumn} from "shared/elements/data-table";
|
||||
import {Button, IconButton} from "@material-ui/core";
|
||||
import EditIcon from '@mui/icons-material/Edit';
|
||||
import {Chip} from "@mui/material";
|
||||
import AddIcon from "@mui/icons-material/Add";
|
||||
import usePagination from "shared/hooks/pagination";
|
||||
|
||||
|
||||
export default function UserListView(props) {
|
||||
|
||||
const api = props.api;
|
||||
const showDialog = props.showDialog;
|
||||
const {translate: L, requestModules, currentLocale} = useContext(LocaleContext);
|
||||
const navigate = useNavigate();
|
||||
const pagination = usePagination();
|
||||
const [users, setUsers] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
requestModules(props.api, ["general", "account"], currentLocale).then(data => {
|
||||
@@ -21,15 +26,17 @@ export default function UserListView(props) {
|
||||
});
|
||||
}, [currentLocale]);
|
||||
|
||||
const onFetchUsers = useCallback(async (page, count, orderBy, sortOrder) => {
|
||||
let res = await props.api.fetchUsers(page, count, orderBy, sortOrder);
|
||||
if (res.success) {
|
||||
return Promise.resolve([res.users, res.pagination]);
|
||||
} else {
|
||||
props.showDialog(res.msg, "Error fetching users");
|
||||
return null;
|
||||
}
|
||||
}, []);
|
||||
const onFetchUsers = useCallback((page, count, orderBy, sortOrder) => {
|
||||
api.fetchUsers(page, count, orderBy, sortOrder).then((res) => {
|
||||
if (res.success) {
|
||||
setUsers(res.users);
|
||||
pagination.update(res.pagination);
|
||||
} else {
|
||||
showDialog(res.msg, "Error fetching users");
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}, [api, showDialog]);
|
||||
|
||||
const groupColumn = (() => {
|
||||
let column = new DataColumn(L("account.groups"), "groups");
|
||||
@@ -80,9 +87,13 @@ export default function UserListView(props) {
|
||||
{L("general.create_new")}
|
||||
</Button>
|
||||
</Link>
|
||||
<DataTable className={"table table-striped"}
|
||||
fetchData={onFetchUsers}
|
||||
placeholder={"No users to display"} columns={columnDefinitions} />
|
||||
<DataTable
|
||||
data={users}
|
||||
pagination={pagination}
|
||||
className={"table table-striped"}
|
||||
fetchData={onFetchUsers}
|
||||
placeholder={"No users to display"}
|
||||
columns={columnDefinitions} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -49,6 +49,7 @@ export default class API {
|
||||
let res = await response.json();
|
||||
if (!res.success && res.msg === "You are not logged in.") {
|
||||
this.loggedIn = false;
|
||||
this.user = null;
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
@@ -5,7 +5,7 @@ import React, {useCallback, useContext, useEffect, useState} from "react";
|
||||
import "./data-table.css";
|
||||
import {LocaleContext} from "../locale";
|
||||
import clsx from "clsx";
|
||||
import {Box, IconButton, TextField} from "@mui/material";
|
||||
import {Box, IconButton, Select, TextField} from "@mui/material";
|
||||
import {formatDate, formatDateTime} from "../util";
|
||||
import CachedIcon from "@material-ui/icons/Cached";
|
||||
|
||||
@@ -195,7 +195,7 @@ export class NumericColumn extends DataColumn {
|
||||
}
|
||||
|
||||
renderData(L, entry, index) {
|
||||
let number = super.renderData(L, entry).toString();
|
||||
let number = super.renderData(L, entry, index).toString();
|
||||
|
||||
if (this.decimalDigits !== null) {
|
||||
number = number.toFixed(this.decimalDigits);
|
||||
@@ -223,8 +223,8 @@ export class DateTimeColumn extends DataColumn {
|
||||
}
|
||||
|
||||
renderData(L, entry, index) {
|
||||
let date = super.renderData(L, entry);
|
||||
return formatDateTime(L, date, this.precise);
|
||||
let date = super.renderData(L, entry, index);
|
||||
return date ? formatDateTime(L, date, this.precise) : "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,8 +234,8 @@ export class DateColumn extends DataColumn {
|
||||
}
|
||||
|
||||
renderData(L, entry, index) {
|
||||
let date = super.renderData(L, entry);
|
||||
return formatDate(L, date);
|
||||
let date = super.renderData(L, entry, index);
|
||||
return date ? formatDate(L, date) : "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,7 +245,7 @@ export class BoolColumn extends DataColumn {
|
||||
}
|
||||
|
||||
renderData(L, entry, index) {
|
||||
let data = super.renderData(L, entry);
|
||||
let data = super.renderData(L, entry, index);
|
||||
return L(data ? "general.yes" : "general.no");
|
||||
}
|
||||
}
|
||||
@@ -260,9 +260,17 @@ export class InputColumn extends DataColumn {
|
||||
|
||||
renderData(L, entry, index) {
|
||||
let value = super.renderData(L, entry, index);
|
||||
let inputProps = typeof this.props === 'function' ? this.props(entry, index) : this.props;
|
||||
if (this.type === 'text') {
|
||||
return <TextField {...this.props} size={"small"} fullWidth={true}
|
||||
return <TextField {...inputProps} size={"small"} fullWidth={true}
|
||||
value={value} onChange={(e) => this.onChange(entry, index, e.target.value)} />
|
||||
} else if (this.type === "select") {
|
||||
let options = Object.entries(this.params.options || {}).map(([value, label]) =>
|
||||
<option key={"option-" + value} value={value}>{label}</option>);
|
||||
return <Select native {...inputProps} size={"small"} fullWidth={true} value={value}
|
||||
onChange={(e) => this.onChange(entry, index, e.target.value)}>
|
||||
{options}
|
||||
</Select>
|
||||
}
|
||||
|
||||
return <>[Invalid type: {this.type}]</>
|
||||
@@ -292,15 +300,19 @@ export class ControlsColumn extends DataColumn {
|
||||
let props = {
|
||||
...buttonProps,
|
||||
key: "button-" + index,
|
||||
onClick: (e) => { e.stopPropagation(); button.onClick(entry, index); },
|
||||
}
|
||||
|
||||
// TODO: icon button!
|
||||
if (button.hasOwnProperty("disabled")) {
|
||||
props.disabled = typeof button.disabled === 'function'
|
||||
? button.disabled(entry, index)
|
||||
: button.disabled;
|
||||
}
|
||||
|
||||
if (!props.disabled) {
|
||||
props.onClick = (e) => { e.stopPropagation(); button.onClick(entry, index); }
|
||||
}
|
||||
|
||||
if ((!button.hasOwnProperty("hidden")) ||
|
||||
(typeof button.hidden === 'function' && !button.hidden(entry, index)) ||
|
||||
(!button.hidden)) {
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
DialogContent,
|
||||
DialogContentText,
|
||||
DialogTitle,
|
||||
Input, List, ListItem, TextField
|
||||
Input, List, ListItem, Select, TextField
|
||||
} from "@mui/material";
|
||||
|
||||
export default function Dialog(props) {
|
||||
|
||||
@@ -7,7 +7,6 @@ export default function useAsyncSearch(callback, minLength = 1) {
|
||||
const [results, setResults] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
console.log("searchString:", searchString);
|
||||
if (minLength > 0 && (!searchString || searchString.length < minLength)) {
|
||||
setResults([]);
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user