Add update script, enhance admin features, and improve styles

- Created a PowerShell script (update.ps1) for automating the process of pulling the latest repository changes, stopping, building, and starting the Docker Compose stack.
- Updated App.jsx to include new admin sections for alarms and integrations, added state management for runner jobs, and enhanced permission checks.
- Extended the API module (api.js) with new endpoints for managing integrations and runner jobs.
- Improved CSS styles for a more compact and responsive layout in the admin interface, focusing on source and datapoint cards.
This commit is contained in:
jhartworks
2026-07-09 15:24:58 +02:00
parent f247d2827d
commit 19d27f9de9
14 changed files with 1077 additions and 54 deletions
+37 -1
View File
@@ -278,6 +278,9 @@ function parseModbusCsv(payload) {
dataType: get("datatype", "holding-register"),
kind: normalizePointKind(get("kind", get("type", "analog"))),
enabled: payload.enabled === true,
alarmEnabled: payload.alarmEnabled === true,
alarmCondition: normalizeText(payload.alarmCondition),
alarmGroupId: normalizeText(payload.alarmGroupId),
writeMode: normalizeWriteMode(get("writemode", payload.writeMode || "")),
condition: get("condition", payload.condition || ""),
scale: Number(get("scale", 1)) || 1,
@@ -328,6 +331,9 @@ function parseKnxXml(payload) {
dataType: dpt || "group-address",
kind: dpt.startsWith("1.") ? "digital" : "analog",
enabled: payload.enabled === true,
alarmEnabled: payload.alarmEnabled === true,
alarmCondition: normalizeText(payload.alarmCondition),
alarmGroupId: normalizeText(payload.alarmGroupId),
writeMode: normalizeWriteMode(payload.writeMode || ""),
condition: payload.condition || "",
host: payload.host || "",
@@ -364,6 +370,9 @@ function createManualDatapoint(store, payload) {
unit: normalizePointUnit(payload.unit, payload.kind),
kind: normalizePointKind(payload.kind),
enabled: payload.enabled !== false,
alarmEnabled: payload.alarmEnabled === true,
alarmCondition: normalizeText(payload.alarmCondition),
alarmGroupId: normalizeText(payload.alarmGroupId),
writeMode: normalizeWriteMode(payload.writeMode || source.writeMode),
condition: normalizeText(payload.condition),
dataType: normalizeText(payload.dataType || (protocol === "knx-ip" ? "group-address" : "holding-register")),
@@ -398,6 +407,9 @@ function createScanDatapoint(source, payload, index) {
unit: normalizePointUnit(payload.unit, payload.kind),
kind: normalizePointKind(payload.kind),
enabled: payload.enabled === true,
alarmEnabled: payload.alarmEnabled === true,
alarmCondition: normalizeText(payload.alarmCondition),
alarmGroupId: normalizeText(payload.alarmGroupId),
writeMode: normalizeWriteMode(payload.writeMode || source.writeMode),
condition: normalizeText(payload.condition),
dataType: normalizeText(payload.dataType),
@@ -446,7 +458,7 @@ function buildScannedDatapoints(store, source, rawPoints, toPayload) {
pointIndex: existing.pointIndex,
alias: !existingAlias || existingLooksLikeScanDefault ? scanned.alias : existing.alias,
name: scanned.name || existing.name,
unit: normalizePointUnit(existing.unit || scanned.unit, existing.kind || scanned.kind),
unit: existing.enabled === true ? normalizePointUnit(existing.unit || scanned.unit, existing.kind || scanned.kind) : normalizePointUnit(scanned.unit || existing.unit, scanned.kind || existing.kind),
kind: existing.kind || scanned.kind,
enabled: existing.enabled === true,
writeMode: normalizeWriteMode(existing.writeMode || scanned.writeMode),
@@ -1066,6 +1078,11 @@ function sendBacnetWhoIs(client, routing, deviceId) {
throw new Error("Who-Is konnte nicht ausgel?st werden.");
}
function bacnetUnitSymbol(value) {
const unit = Number(value);
const map = { 3: "A", 5: "V", 53: "Pa", 62: "°C", 63: "K", 95: "", 98: "%" };
return Object.prototype.hasOwnProperty.call(map, unit) ? map[unit] : "";
}
function readBacnetProperty(client, host, objectId, propertyId) {
return new Promise((resolve) => {
client.readProperty(host, objectId, propertyId, (error, value) => {
@@ -1092,6 +1109,7 @@ async function scanBacnetObjects(client, device, portNumber) {
const objectName = await readBacnetProperty(client, host, objectId, 77);
const description = await readBacnetProperty(client, host, objectId, 28);
const presentValue = await readBacnetProperty(client, host, objectId, 85);
const units = await readBacnetProperty(client, host, objectId, 117);
const raw = presentValue?.values?.[0]?.value ?? null;
const label = bacnetObjectLabel(objectId);
const name = normalizeText(objectName?.values?.[0]?.value) || label;
@@ -1100,6 +1118,8 @@ async function scanBacnetObjects(client, device, portNumber) {
id: host + "-" + objectId.type + "-" + objectId.instance,
host,
port: portNumber,
deviceId: device.deviceId,
deviceName: device.name || "BACnet Gerät " + device.deviceId,
objectType: objectId.type,
objectInstance: objectId.instance,
propertyId: 85,
@@ -1109,6 +1129,7 @@ async function scanBacnetObjects(client, device, portNumber) {
description: alias,
alias,
kind: typeof raw === "boolean" || objectId.type >= 3 && objectId.type <= 5 ? "digital" : "analog",
unit: typeof raw === "boolean" || objectId.type >= 3 && objectId.type <= 5 ? "bool" : bacnetUnitSymbol(units?.values?.[0]?.value),
currentValue: raw,
hasValue: raw !== null,
});
@@ -1947,9 +1968,11 @@ const server = createServer(async (req, res) => {
updatedAt: store.updatedAt,
sourceCount: store.sources.length,
datapointCount: store.datapoints.length,
alarmDatapointCount: store.datapoints.filter((item) => item.alarmEnabled === true).length,
sources: store.sources.map((source) => ({
...source,
datapointCount: store.datapoints.filter((item) => item.sourceId === source.id).length,
alarmDatapointCount: store.datapoints.filter((item) => item.sourceId === source.id && item.alarmEnabled === true).length,
})),
latestScans: {
opcua: store.scans.opcua[0] || null,
@@ -2046,6 +2069,9 @@ const server = createServer(async (req, res) => {
store.datapoints[index] = {
...store.datapoints[index],
enabled: typeof body.enabled === "boolean" ? body.enabled : store.datapoints[index].enabled,
alarmEnabled: typeof body.alarmEnabled === "boolean" ? body.alarmEnabled : store.datapoints[index].alarmEnabled === true,
alarmCondition: typeof body.alarmCondition === "string" ? body.alarmCondition.trim() : store.datapoints[index].alarmCondition,
alarmGroupId: typeof body.alarmGroupId === "string" ? body.alarmGroupId.trim() : store.datapoints[index].alarmGroupId,
writeMode: typeof body.writeMode === "string" ? normalizeWriteMode(body.writeMode) : store.datapoints[index].writeMode,
condition: typeof body.condition === "string" ? body.condition.trim() : store.datapoints[index].condition,
pointIndex: body.pointIndex ? normalizePointIndex(body.pointIndex, store.datapoints[index].pointIndex) : store.datapoints[index].pointIndex,
@@ -2222,3 +2248,13 @@ server.listen(port, () => {