/**
* Admin Panel: User Management. Lists real accounts (GET /admin/users),
* creates them (POST, with a bcrypt-hashed password server-side -- this
* page only ever sends plaintext over the wire once, at creation/reset
* time, and never displays a password hash anywhere), edits profiles,
* enables/disables accounts, and assigns roles.
*
* Every action below is a real network call to a real, backend-enforced
* endpoint (see azure-functions/api_blueprint.py's require_permission()
* calls on each admin/users* route) -- this page itself only decides what
* to SHOW, never what's actually ALLOWED; a disabled button here is a
* convenience, not the security boundary (the server would refuse the
* call either way, see the 403s surfaced below when it does).
*/
function UserManagement(props) {
var api = props.api;
var currentUser = props.currentUser;
// Snapshot-cached, per the "no loading flash on revisit" requirement --
// every mutation handler below (create/edit/status/roles) still calls
// `load` (now snapshot.refresh) on success, so your own change is
// never hidden behind a stale cached list; only an idle REvisit with
// no changes skips the reload.
var snapshot = CDPI_REPORT_SNAPSHOT.useReportSnapshot("user_management", function () {
return Promise.all([api.listUsers(), api.listRoles()])
.then(function (results) { return { users: results[0].users, roles: results[1].roles }; });
});
var data = {
loading: snapshot.state.loading && !snapshot.state.data, error: snapshot.state.error,
users: (snapshot.state.data && snapshot.state.data.users) || [],
roles: (snapshot.state.data && snapshot.state.data.roles) || [],
};
var load = snapshot.refresh;
var formState = React.useState(null); // { mode: "create"|"edit"|"roles", user } | null
var form = formState[0];
var setForm = formState[1];
var actionError = React.useState(null);
var errorMsg = actionError[0];
var setErrorMsg = actionError[1];
function roleLabel(roleKey) {
var role = data.roles.filter(function (r) { return r.role_key === roleKey; })[0];
return role ? role.display_name : roleKey;
}
function handleToggleStatus(user) {
var next = user.status === "active" ? "disabled" : "active";
setErrorMsg(null);
api.setUserStatus(user.id, next)
.then(load)
.catch(function (err) { setErrorMsg(err.message); });
}
return (
User Management
Real accounts, real bcrypt-hashed passwords, real backend-enforced permissions -- not the old
client-side demo login. See auth.py and azure-functions/api_blueprint.py.
Snapshot from {snapshot.state.lastUpdated ? new Date(snapshot.state.lastUpdated).toLocaleString() : "just now"}