🚧 WIP
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
import { FormEvent, useState } from "react";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { api, type Group } from "../api";
|
||||
|
||||
export function GroupsPage() {
|
||||
const queryClient = useQueryClient();
|
||||
const [name, setName] = useState("");
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const groups = useQuery({
|
||||
queryKey: ["groups"],
|
||||
queryFn: () => api.get<Group[]>("/mqtt/groups"),
|
||||
});
|
||||
|
||||
const create = useMutation({
|
||||
mutationFn: (groupname: string) => api.post("/mqtt/groups", { groupname }),
|
||||
onSuccess: () => {
|
||||
setName("");
|
||||
queryClient.invalidateQueries({ queryKey: ["groups"] });
|
||||
},
|
||||
onError: (e: Error) => setError(e.message),
|
||||
});
|
||||
|
||||
const remove = useMutation({
|
||||
mutationFn: (groupname: string) => api.delete(`/mqtt/groups/${groupname}`),
|
||||
onSuccess: () => queryClient.invalidateQueries({ queryKey: ["groups"] }),
|
||||
onError: (e: Error) => setError(e.message),
|
||||
});
|
||||
|
||||
const submit = (e: FormEvent) => {
|
||||
e.preventDefault();
|
||||
if (name) create.mutate(name);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2>Groups</h2>
|
||||
<p>Assign roles to collections of clients (dynamic security groups).</p>
|
||||
{error && <div className="banner error">{error}</div>}
|
||||
|
||||
<form className="stack" onSubmit={submit}>
|
||||
<label htmlFor="group-name">New group name</label>
|
||||
<input
|
||||
id="group-name"
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
placeholder="e.g. sensors"
|
||||
/>
|
||||
<p />
|
||||
<button className="primary" disabled={!name || create.isPending}>
|
||||
Create group
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<table style={{ marginTop: "1.5rem" }}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Group</th>
|
||||
<th>Roles</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{(groups.data ?? []).map((g) => (
|
||||
<tr key={g.groupname}>
|
||||
<td className="mono">{g.groupname}</td>
|
||||
<td>{(g.roles ?? []).map((r) => r.rolename).join(", ") || "—"}</td>
|
||||
<td>
|
||||
<button
|
||||
className="danger"
|
||||
onClick={() => {
|
||||
if (confirm(`Delete group ${g.groupname}?`)) remove.mutate(g.groupname);
|
||||
}}
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user