update
This commit is contained in:
+85
-52
@@ -1,4 +1,4 @@
|
||||
|
||||
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { api } from "./api.js";
|
||||
import Gauge from "./components/Gauge.jsx";
|
||||
@@ -13,8 +13,10 @@ const views = [
|
||||
|
||||
const adminSections = [
|
||||
{ id: "aliases", label: "Aliase" },
|
||||
{ id: "users", label: "Benutzer" },
|
||||
{ id: "sources", label: "Quellen" },
|
||||
{ id: "users", label: "Benutzer" },
|
||||
{ id: "roles", label: "Rollen" },
|
||||
{ id: "debug", label: "Debug" },
|
||||
];
|
||||
|
||||
const emptyTrendRange = {
|
||||
@@ -95,6 +97,32 @@ function getDefaultProtocolPort(protocol) {
|
||||
return PROTOCOL_DEFAULT_PORTS[protocol] || "";
|
||||
}
|
||||
|
||||
function getDefaultPointDataType(protocol) {
|
||||
if (protocol === "knx-ip") {
|
||||
return "group-address";
|
||||
}
|
||||
if (protocol === "opc-ua") {
|
||||
return "node-id";
|
||||
}
|
||||
if (protocol === "bacnet-ip") {
|
||||
return "analogInput";
|
||||
}
|
||||
return "holding-register";
|
||||
}
|
||||
|
||||
function getManualAddressLabel(protocol) {
|
||||
if (protocol === "knx-ip") {
|
||||
return "Gruppenadresse";
|
||||
}
|
||||
if (protocol === "opc-ua") {
|
||||
return "NodeId";
|
||||
}
|
||||
if (protocol === "bacnet-ip") {
|
||||
return "Objekt-Instanz / Adresse";
|
||||
}
|
||||
return "Adresse / Register";
|
||||
}
|
||||
|
||||
function formatValue(value) {
|
||||
return Number.isFinite(Number(value)) ? Number(value).toFixed(2) : "--";
|
||||
}
|
||||
@@ -488,16 +516,21 @@ export default function App() {
|
||||
const [selectedSourceId, setSelectedSourceId] = useState("");
|
||||
const [isCreatingSource, setIsCreatingSource] = useState(false);
|
||||
const [sourceDraft, setSourceDraft] = useState(defaultSourceDraft);
|
||||
const [manualDatapointDraft, setManualDatapointDraft] = useState({ alias: "", address: "", pointIndex: "", unit: "°C", dataType: "holding-register", kind: "analog" });
|
||||
const [manualDatapointDraft, setManualDatapointDraft] = useState({ alias: "", address: "", pointIndex: "", unit: "°C", dataType: getDefaultPointDataType(defaultSourceDraft.protocol), kind: "analog" });
|
||||
const [scanResults, setScanResults] = useState({ opcua: null, bacnet: null });
|
||||
const [debugSnapshot, setDebugSnapshot] = useState(null);
|
||||
|
||||
const trendIsps = useMemo(() => isps.filter((isp) => Number(isp.rowCount) > 0), [isps]);
|
||||
const selectedMetadata = selectedIsp ? metadataCache[selectedIsp] : null;
|
||||
const canViewDashboard = hasPermission(user, "view_dashboard");
|
||||
const canViewTrends = hasPermission(user, "view_trends");
|
||||
const canEditAliases = hasPermission(user, "edit_aliases");
|
||||
const canManageSources = hasPermission(user, "manage_sources");
|
||||
const canManageUsers = hasPermission(user, "manage_users");
|
||||
const canManageRoles = hasPermission(user, "manage_roles");
|
||||
const canViewDebug = hasPermission(user, "view_debug");
|
||||
const canAccessAdmin = canEditAliases || canManageSources || canManageUsers || canManageRoles || canViewDebug;
|
||||
const firstAdminSection = canEditAliases ? "aliases" : canManageSources ? "sources" : canManageUsers ? "users" : canManageRoles ? "roles" : canViewDebug ? "debug" : "aliases";
|
||||
const sidebarCollapsed = !sidebarPinned && !sidebarHover;
|
||||
const currentView = views.find((view) => view.id === activeView) || views[0];
|
||||
const selectionListClassName = selections.length <= 2 ? "selection-list compact" : "selection-list";
|
||||
@@ -529,6 +562,10 @@ export default function App() {
|
||||
return () => media.removeEventListener("change", applyTheme);
|
||||
}, [themeMode]);
|
||||
|
||||
useEffect(() => {
|
||||
resetFlash();
|
||||
}, [activeView, adminSection]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!token) {
|
||||
setSessionReady(true);
|
||||
@@ -748,25 +785,50 @@ export default function App() {
|
||||
});
|
||||
setManualDatapointDraft((current) => ({
|
||||
...current,
|
||||
dataType: currentSource.protocol === "knx-ip" ? "group-address" : "holding-register",
|
||||
dataType: getDefaultPointDataType(currentSource.protocol || "modbus-tcp"),
|
||||
}));
|
||||
}, [currentSource]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!canViewDashboard && activeView === "dashboard") {
|
||||
setActiveView(canViewTrends ? "trends" : canAccessAdmin ? "admin" : "settings");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!canViewTrends && activeView === "trends") {
|
||||
setActiveView(canViewDashboard ? "dashboard" : canAccessAdmin ? "admin" : "settings");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!canAccessAdmin && activeView === "admin") {
|
||||
setActiveView(canViewDashboard ? "dashboard" : canViewTrends ? "trends" : "settings");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!canEditAliases && adminSection === "aliases") {
|
||||
setAdminSection(firstAdminSection);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(canManageSources || canEditAliases) && adminSection === "sources") {
|
||||
setAdminSection(firstAdminSection);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!canManageUsers && adminSection === "users") {
|
||||
setAdminSection("aliases");
|
||||
setAdminSection(firstAdminSection);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!canManageRoles && adminSection === "roles") {
|
||||
setAdminSection("aliases");
|
||||
setAdminSection(firstAdminSection);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!canViewDebug && adminSection === "debug") {
|
||||
setAdminSection("aliases");
|
||||
setAdminSection(firstAdminSection);
|
||||
}
|
||||
}, [activeView, adminSection, canAccessAdmin, canManageRoles, canManageUsers, canViewDashboard, canViewDebug, canViewTrends]);
|
||||
}, [activeView, adminSection, canAccessAdmin, canEditAliases, canManageRoles, canManageSources, canManageUsers, canViewDashboard, canViewDebug, canViewTrends, firstAdminSection]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!selectedSelectionId) {
|
||||
@@ -1108,7 +1170,7 @@ export default function App() {
|
||||
const startNewSource = () => {
|
||||
setIsCreatingSource(true);
|
||||
setSelectedSourceId("");
|
||||
setManualDatapointDraft({ alias: "", address: "", pointIndex: "", unit: "°C", dataType: "holding-register", kind: "analog" });
|
||||
setManualDatapointDraft({ alias: "", address: "", pointIndex: "", unit: "°C", dataType: getDefaultPointDataType(defaultSourceDraft.protocol), kind: "analog" });
|
||||
setSourceDraft({
|
||||
...defaultSourceDraft,
|
||||
port: getDefaultProtocolPort(defaultSourceDraft.protocol),
|
||||
@@ -1128,6 +1190,10 @@ export default function App() {
|
||||
tableName: current.id ? current.tableName : buildCollectorTableName(current.name, nextProtocol),
|
||||
};
|
||||
});
|
||||
setManualDatapointDraft((current) => ({
|
||||
...current,
|
||||
dataType: getDefaultPointDataType(nextProtocol),
|
||||
}));
|
||||
};
|
||||
|
||||
const saveCollectorSource = async () => {
|
||||
@@ -1212,11 +1278,12 @@ export default function App() {
|
||||
pointIndex: manualDatapointDraft.pointIndex,
|
||||
unit: manualDatapointDraft.unit || "°C",
|
||||
dataType: manualDatapointDraft.dataType,
|
||||
nodeId: sourceDraft.protocol === "opc-ua" ? manualDatapointDraft.address : "",
|
||||
kind: manualDatapointDraft.kind,
|
||||
});
|
||||
await refreshCollectorData();
|
||||
await refreshCollectorDebug().catch(() => undefined);
|
||||
setManualDatapointDraft({ alias: "", address: "", pointIndex: "", unit: "°C", dataType: sourceDraft.protocol === "knx-ip" ? "group-address" : "holding-register", kind: "analog" });
|
||||
setManualDatapointDraft({ alias: "", address: "", pointIndex: "", unit: "°C", dataType: getDefaultPointDataType(sourceDraft.protocol), kind: "analog" });
|
||||
setSuccessMessage("Datenpunkt angelegt.");
|
||||
} catch (error) {
|
||||
setBootError(error.message);
|
||||
@@ -1753,6 +1820,12 @@ export default function App() {
|
||||
<section className="admin-section">
|
||||
<div className="admin-subnav">
|
||||
{adminSections.filter((section) => {
|
||||
if (section.id === "aliases") {
|
||||
return canEditAliases;
|
||||
}
|
||||
if (section.id === "sources") {
|
||||
return canManageSources || canEditAliases;
|
||||
}
|
||||
if (section.id === "users") {
|
||||
return canManageUsers;
|
||||
}
|
||||
@@ -1975,7 +2048,7 @@ export default function App() {
|
||||
<small className="muted">Zuletzt ausgewählte Quelle: {currentSource?.name || "noch keine"}</small>
|
||||
</div>
|
||||
|
||||
{(sourceDraft.protocol === "modbus-tcp" || sourceDraft.protocol === "knx-ip") ? (
|
||||
{canManageSources ? (
|
||||
<div className="protocol-block">
|
||||
<strong>Einzelner Datenpunkt</strong>
|
||||
<div className="form-grid compact-forms">
|
||||
@@ -1984,7 +2057,7 @@ export default function App() {
|
||||
<input value={manualDatapointDraft.alias} onChange={(event) => setManualDatapointDraft((current) => ({ ...current, alias: event.target.value }))} />
|
||||
</label>
|
||||
<label>
|
||||
<span>{sourceDraft.protocol === "knx-ip" ? "Gruppenadresse" : "Adresse / Register"}</span>
|
||||
<span>{getManualAddressLabel(sourceDraft.protocol)}</span>
|
||||
<input value={manualDatapointDraft.address} onChange={(event) => setManualDatapointDraft((current) => ({ ...current, address: event.target.value }))} />
|
||||
</label>
|
||||
<label>
|
||||
@@ -2273,43 +2346,3 @@ export default function App() {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user