diff --git a/.env.development b/.env.development index 2f96af3..37897ea 100644 --- a/.env.development +++ b/.env.development @@ -6,6 +6,6 @@ NEXT_PUBLIC_USE_MOCK_BACKEND_LOOP_START=false NEXT_PUBLIC_EXPORT_STATIC=false NEXT_PUBLIC_USE_CGI=false # App-Versionsnummer -NEXT_PUBLIC_APP_VERSION=1.6.844 +NEXT_PUBLIC_APP_VERSION=1.6.845 NEXT_PUBLIC_CPL_MODE=json # json (Entwicklungsumgebung) oder jsSimulatedProd (CPL ->CGI-Interface-Simulator) oder production (CPL-> CGI-Interface Platzhalter) diff --git a/.env.production b/.env.production index bacec2a..532def8 100644 --- a/.env.production +++ b/.env.production @@ -5,5 +5,5 @@ NEXT_PUBLIC_CPL_API_PATH=/CPL NEXT_PUBLIC_EXPORT_STATIC=true NEXT_PUBLIC_USE_CGI=true # App-Versionsnummer -NEXT_PUBLIC_APP_VERSION=1.6.844 +NEXT_PUBLIC_APP_VERSION=1.6.845 NEXT_PUBLIC_CPL_MODE=production \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 8663a56..afd09ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## [1.6.845] – 2025-09-05 + +- feat: prepare KÜ 8 for scrolling text + +--- ## [1.6.844] – 2025-09-05 - test: woodpecker diff --git a/components/main/kabelueberwachung/kue705FO/Kue705FO.tsx b/components/main/kabelueberwachung/kue705FO/Kue705FO.tsx index bd303a6..f6d9f57 100644 --- a/components/main/kabelueberwachung/kue705FO/Kue705FO.tsx +++ b/components/main/kabelueberwachung/kue705FO/Kue705FO.tsx @@ -1,5 +1,10 @@ "use client"; // components/modules/kue705FO/Kue705FO.tsx -import React, { useState, useMemo } from "react"; +import React, { useState, useMemo, useEffect, useRef } from "react"; +import dynamic from "next/dynamic"; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const Marquee: any = dynamic(() => import("react-fast-marquee"), { + ssr: false, +}); import { useSelector } from "react-redux"; import KueModal from "./modals/SettingsModalWrapper"; // import FallSensors from "../../fall-detection-sensors/FallSensors"; @@ -54,6 +59,19 @@ const Kue705FO: React.FC = ({ // Admin authentication hook for security - using showModal as true for continuous auth check const { isAdminLoggedIn } = useAdminAuth(true); + // Modulname (max 48 Zeichen) vorbereiten + const moduleNameRaw = useMemo( + () => kueName?.[slotIndex] || `Modul ${slotIndex + 1}`, + [kueName, slotIndex] + ); + const moduleName48 = useMemo( + () => + typeof moduleNameRaw === "string" + ? moduleNameRaw.slice(0, 48) + : String(moduleNameRaw), + [moduleNameRaw] + ); + const [activeButton, setActiveButton] = useState<"Schleife" | "TDR" | "ISO">( "Schleife" ); @@ -206,6 +224,53 @@ const Kue705FO: React.FC = ({ ); const { setCurrentModulName } = useModulName(slotIndex, modulName); //--------------------------------- + // Version-gate für Laufschrift: erst ab V4.30 aktiv + const parseVersion = (v?: string): [number, number, number] => { + if (!v) return [0, 0, 0]; + const m = String(v).match(/(\d+)(?:\.(\d+))?(?:\.(\d+))?/); + if (!m) return [0, 0, 0]; + const major = parseInt(m[1] || "0", 10) || 0; + const minor = parseInt(m[2] || "0", 10) || 0; + const patch = parseInt(m[3] || "0", 10) || 0; + return [major, minor, patch]; + }; + const gte = (a: [number, number, number], b: [number, number, number]) => { + if (a[0] !== b[0]) return a[0] > b[0]; + if (a[1] !== b[1]) return a[1] > b[1]; + return a[2] >= b[2]; + }; + const marqueeOverride = + process.env.NEXT_PUBLIC_ENABLE_KUE_MARQUEE === "1" || + process.env.NEXT_PUBLIC_ENABLE_KUE_MARQUEE === "true"; + const scrollFeatureEnabled = useMemo( + () => marqueeOverride || gte(parseVersion(kueVersion), [4, 30, 0]), + [kueVersion, marqueeOverride] + ); + + // Überlängen-Erkennung für Laufschrift + const nameContainerRef = useRef(null); + const measureTextRef = useRef(null); + const [shouldScroll, setShouldScroll] = useState(false); + + useEffect(() => { + const measure = () => { + if (!scrollFeatureEnabled) { + setShouldScroll(false); + return; + } + const container = nameContainerRef.current; + const text = measureTextRef.current; + if (!container || !text) { + setShouldScroll(false); + return; + } + const needs = text.scrollWidth > container.clientWidth + 2; + setShouldScroll(needs); + }; + measure(); + window.addEventListener("resize", measure); + return () => window.removeEventListener("resize", measure); + }, [moduleName48, scrollFeatureEnabled]); //--------------------------------- const tdmChartData = useSelector( (state: RootState) => state.tdmChartSlice.data @@ -360,8 +425,38 @@ const Kue705FO: React.FC = ({
-
- {kueName?.[slotIndex] || `Modul ${slotIndex + 1}`} + {/* Hidden measuring span for overflow detection (kept measurable) */} + + {moduleName48} + + +
+ {shouldScroll && scrollFeatureEnabled ? ( + + + {moduleName48} + + + ) : ( + + {moduleName48} + + )}
diff --git a/docs/TODO.md b/docs/TODO.md index 2f484dc..6ef9f43 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -94,9 +94,9 @@ in Rot, wenn Schleifenfehler ansteht # Folgende Erweiterung / Neuerungen: -[ ] TODO: Messverlauf bei Systemwerten (Temperatur und Spannungen) mit Datumsauswahl +[x] TODO: Messverlauf bei Systemwerten (Temperatur und Spannungen) mit Datumsauswahl -[ ] TODO: Formatierung der Kabelüberwachungswerten in den visuellen Einschüben (Isowert mit Komma und 2 Nachkommastellen; RSL mit Komma und 3 Noachkommastellen) Nachkommastellen immer anzeigen und mit Nullen auffüllen. +[x] TODO: Formatierung der Kabelüberwachungswerten in den visuellen Einschüben (Isowert mit Komma und 2 Nachkommastellen; RSL mit Komma und 3 Noachkommastellen) Nachkommastellen immer anzeigen und mit Nullen auffüllen. [ ] TODO: Admin User nach einer Zeit von einer Stunde löschen (Cookie oder Local Storrage) diff --git a/mocks/device-cgi-simulator/SERVICE/kabelueberwachungMockData.js b/mocks/device-cgi-simulator/SERVICE/kabelueberwachungMockData.js index 18a6062..b6538ee 100644 --- a/mocks/device-cgi-simulator/SERVICE/kabelueberwachungMockData.js +++ b/mocks/device-cgi-simulator/SERVICE/kabelueberwachungMockData.js @@ -92,7 +92,7 @@ var win_kueLoopInterval = [ //--------------------------------------------------- //KÜ Modul Version soll /100 und davor V angezeigt werden z.B. 4.19V var win_kueVersion = [ - 420, 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + 420, 419, 419, 419, 419, 419, 419, 430, 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, ]; diff --git a/package-lock.json b/package-lock.json index 5b9956b..03ddfea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cpl-v4", - "version": "1.6.844", + "version": "1.6.845", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "cpl-v4", - "version": "1.6.844", + "version": "1.6.845", "dependencies": { "@fontsource/roboto": "^5.1.0", "@headlessui/react": "^2.2.4", @@ -39,6 +39,7 @@ "react-datepicker": "^8.0.0", "react-day-picker": "^9.6.7", "react-dom": "^18.3.1", + "react-fast-marquee": "^1.6.0", "react-modal": "^3.16.1", "react-redux": "^9.1.2", "react-spinners": "^0.14.1", @@ -9161,6 +9162,16 @@ "react": "^18.3.1" } }, + "node_modules/react-fast-marquee": { + "version": "1.6.5", + "resolved": "https://registry.npmjs.org/react-fast-marquee/-/react-fast-marquee-1.6.5.tgz", + "integrity": "sha512-swDnPqrT2XISAih0o74zQVE2wQJFMvkx+9VZXYYNSLb/CUcAzU9pNj637Ar2+hyRw6b4tP6xh4GQZip2ZCpQpg==", + "license": "MIT", + "peerDependencies": { + "react": ">= 16.8.0 || ^18.0.0", + "react-dom": ">= 16.8.0 || ^18.0.0" + } + }, "node_modules/react-fit": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/react-fit/-/react-fit-2.0.1.tgz", diff --git a/package.json b/package.json index 72fdfce..10f228d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cpl-v4", - "version": "1.6.844", + "version": "1.6.845", "private": true, "scripts": { "dev": "next dev -p 3000", @@ -60,6 +60,7 @@ "next": "^14.2.23", "node-fetch": "^3.3.2", "react": "^18.3.1", + "react-fast-marquee": "^1.6.0", "react-chartjs-2": "^5.3.0", "react-date-picker": "^11.0.0", "react-datepicker": "^8.0.0", diff --git a/types/react-fast-marquee.d.ts b/types/react-fast-marquee.d.ts new file mode 100644 index 0000000..2e16663 --- /dev/null +++ b/types/react-fast-marquee.d.ts @@ -0,0 +1,17 @@ +declare module "react-fast-marquee" { + import * as React from "react"; + interface MarqueeProps { + speed?: number; + pauseOnHover?: boolean; + gradient?: boolean; + gradientColor?: [number, number, number]; + gradientWidth?: number | string; + direction?: "left" | "right"; + play?: boolean; + className?: string; + style?: React.CSSProperties; + children?: React.ReactNode; + } + const Marquee: React.FC; + export default Marquee; +}