Added Roles and Permissions. Some minor UI fixes

This commit is contained in:
2026-02-18 13:12:55 +02:00
parent f54cdd525d
commit dbd15c00f8
31 changed files with 1825 additions and 331 deletions

View File

@@ -108,10 +108,11 @@ export default function DeviceList() {
const [deleteTarget, setDeleteTarget] = useState(null);
const [visibleColumns, setVisibleColumns] = useState(getDefaultVisibleColumns);
const [showColumnPicker, setShowColumnPicker] = useState(false);
const [mqttStatusMap, setMqttStatusMap] = useState({});
const columnPickerRef = useRef(null);
const navigate = useNavigate();
const { hasRole } = useAuth();
const canEdit = hasRole("superadmin", "device_manager");
const { hasPermission } = useAuth();
const canEdit = hasPermission("devices", "edit");
// Close column picker on outside click
useEffect(() => {
@@ -136,8 +137,20 @@ export default function DeviceList() {
if (onlineFilter === "false") params.set("online", "false");
if (tierFilter) params.set("tier", tierFilter);
const qs = params.toString();
const data = await api.get(`/devices${qs ? `?${qs}` : ""}`);
const [data, mqttData] = await Promise.all([
api.get(`/devices${qs ? `?${qs}` : ""}`),
api.get("/mqtt/status").catch(() => null),
]);
setDevices(data.devices);
// Build MQTT status lookup by device serial
if (mqttData?.devices) {
const map = {};
for (const s of mqttData.devices) {
map[s.device_serial] = s;
}
setMqttStatusMap(map);
}
} catch (err) {
setError(err.message);
} finally {
@@ -182,14 +195,17 @@ export default function DeviceList() {
const stats = device.device_stats || {};
switch (key) {
case "status":
case "status": {
const mqtt = mqttStatusMap[device.device_id];
const isOnline = mqtt ? mqtt.online : device.is_Online;
return (
<span
className={`inline-block w-2.5 h-2.5 rounded-full ${device.is_Online ? "bg-green-500" : ""}`}
style={!device.is_Online ? { backgroundColor: "var(--border-primary)" } : undefined}
title={device.is_Online ? "Online" : "Offline"}
className={`inline-block w-2.5 h-2.5 rounded-full ${isOnline ? "bg-green-500" : ""}`}
style={!isOnline ? { backgroundColor: "var(--border-primary)" } : undefined}
title={isOnline ? "Online" : "Offline"}
/>
);
}
case "name":
return (
<span className="font-medium" style={{ color: "var(--text-heading)" }}>