diff --git a/.env.development b/.env.development index cb60699..e1ac53f 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.884 +NEXT_PUBLIC_APP_VERSION=1.6.885 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 7feeb27..95069da 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.884 +NEXT_PUBLIC_APP_VERSION=1.6.885 NEXT_PUBLIC_CPL_MODE=production \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 04ddba2..e4c4150 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## [1.6.885] – 2025-09-09 + +- test: rename test files *.test.ts + +--- ## [1.6.884] – 2025-09-09 - Tests: TDR ISO und RSL diff --git a/components/main/kabelueberwachung/kue705FO/Charts/IsoMeasurementChart/IsoChartActionBar.tsx b/components/main/kabelueberwachung/kue705FO/Charts/IsoMeasurementChart/IsoChartActionBar.tsx index a45583f..d844faa 100644 --- a/components/main/kabelueberwachung/kue705FO/Charts/IsoMeasurementChart/IsoChartActionBar.tsx +++ b/components/main/kabelueberwachung/kue705FO/Charts/IsoMeasurementChart/IsoChartActionBar.tsx @@ -271,7 +271,7 @@ const IsoChartActionBar = forwardRef((_props, ref) => { useImperativeHandle(ref, () => ({ handleFetchData })); - const hiddenWhenMeldungen = chartTitle !== "Messkurve"; + const isMeldungen = chartTitle === "Meldungen"; return (
@@ -283,80 +283,76 @@ const IsoChartActionBar = forwardRef((_props, ref) => { {slotNumber !== null ? slotNumber + 1 : "-"}
-
-
- -
-
- { - dispatch(setSelectedMode(value)); - dispatch(setBrushRange({ startIndex: 0, endIndex: 0 })); - }} - > -
- - - { - { - DIA0: "Alle Messwerte", - DIA1: "Stündlich", - DIA2: "Täglich", - }[selectedMode] - } - - - - - {["DIA0", "DIA1", "DIA2"].map((mode) => ( - - `px-3 py-1.5 cursor-pointer rounded-sm m-0.5 ${ - selected - ? "dropdown-option-active" - : active - ? "dropdown-option-hover" - : "" - }` - } - > +
+ {/* Always show date range; requirement: in Meldungen only Von/Bis + Anzeigen */} + + {!isMeldungen && ( + <> + { + dispatch(setSelectedMode(value)); + dispatch(setBrushRange({ startIndex: 0, endIndex: 0 })); + }} + > +
+ + { { DIA0: "Alle Messwerte", DIA1: "Stündlich", DIA2: "Täglich", - }[mode as "DIA0" | "DIA1" | "DIA2"] + }[selectedMode] } - - ))} - -
-
-
- + + + + + {["DIA0", "DIA1", "DIA2"].map((mode) => ( + + `px-3 py-1.5 cursor-pointer rounded-sm m-0.5 ${ + selected + ? "dropdown-option-active" + : active + ? "dropdown-option-hover" + : "" + }` + } + > + { + { + DIA0: "Alle Messwerte", + DIA1: "Stündlich", + DIA2: "Täglich", + }[mode as "DIA0" | "DIA1" | "DIA2"] + } + + ))} + +
+
+ + + )} + {isMeldungen && ( + + )}
); diff --git a/components/main/kabelueberwachung/kue705FO/Charts/LoopMeasurementChart/LoopChartActionBar.tsx b/components/main/kabelueberwachung/kue705FO/Charts/LoopMeasurementChart/LoopChartActionBar.tsx index 08028c3..4e15b46 100644 --- a/components/main/kabelueberwachung/kue705FO/Charts/LoopMeasurementChart/LoopChartActionBar.tsx +++ b/components/main/kabelueberwachung/kue705FO/Charts/LoopMeasurementChart/LoopChartActionBar.tsx @@ -283,6 +283,7 @@ const LoopChartActionBar = forwardRef((_props, ref) => { // Sichtbarkeits-Flags const isMesskurve = chartTitle === "Messkurve"; + const isMeldungen = chartTitle === "Meldungen"; return (
@@ -347,25 +348,37 @@ const LoopChartActionBar = forwardRef((_props, ref) => {
- {/* Buttons nur für Messkurve */} -
- + {/* Buttons */} + {isMesskurve && ( +
+ + +
+ )} + {isMeldungen && ( -
+ )} {rslRunning && ( diff --git a/components/main/kabelueberwachung/kue705FO/Charts/TDRChart/TDRChartActionBar.tsx b/components/main/kabelueberwachung/kue705FO/Charts/TDRChart/TDRChartActionBar.tsx index c0bf980..82d0dce 100644 --- a/components/main/kabelueberwachung/kue705FO/Charts/TDRChart/TDRChartActionBar.tsx +++ b/components/main/kabelueberwachung/kue705FO/Charts/TDRChart/TDRChartActionBar.tsx @@ -1,49 +1,57 @@ +"use client"; // /components/main/kabelueberwachung/kue705FO/Charts/TDRChart/TDRChartActionBar.tsx - -import React, { useState, useEffect } from "react"; -import { useSelector } from "react-redux"; +import React, { useEffect, useState } from "react"; +import DateRangePicker from "@/components/common/DateRangePicker"; import { useAppDispatch } from "@/redux/store"; +import { useSelector } from "react-redux"; import { RootState } from "@/redux/store"; +import { Listbox } from "@headlessui/react"; +import { getMessagesThunk } from "@/redux/thunks/getMessagesThunk"; +import { setLoading } from "@/redux/slices/kabelueberwachungChartSlice"; import { fetchTDMDataBySlotThunk } from "@/redux/thunks/getTDMListBySlotThunk"; import { getTDRChartDataByIdThunk } from "@/redux/thunks/getTDRChartDataByIdThunk"; -import { getReferenceCurveBySlotThunk } from "@/redux/thunks/getReferenceCurveBySlotThunk"; // ⬅ import ergänzen -import { Listbox } from "@headlessui/react"; +import { getReferenceCurveBySlotThunk } from "@/redux/thunks/getReferenceCurveBySlotThunk"; const TDRChartActionBar: React.FC = () => { const dispatch = useAppDispatch(); - // ✅ Redux: selectedSlot aus kueChartMode (0-basiert) + const { vonDatum, bisDatum, chartTitle } = useSelector( + (s: RootState) => s.kabelueberwachungChartSlice + ); + const { vonDatum: pickerVon, bisDatum: pickerBis } = useSelector( + (s: RootState) => s.dateRangePicker + ); + const selectedSlot = useSelector( - (state: RootState) => state.kueChartModeSlice.selectedSlot + (s: RootState) => s.kueChartModeSlice.selectedSlot ); - const tdmChartData = useSelector( - (state: RootState) => state.tdmSingleChartSlice.data + (s: RootState) => s.tdmSingleChartSlice.data ); - const idsForSlot = selectedSlot !== null ? tdmChartData[selectedSlot] ?? [] : []; - const tdrDataById = useSelector( - (state: RootState) => state.tdrDataByIdSlice.dataById + (s: RootState) => s.tdrDataByIdSlice.dataById ); const [selectedId, setSelectedId] = useState(null); const currentChartData = selectedId !== null ? tdrDataById[selectedId] : []; - // ▶ Fortschrittsanzeige für laufende TDR-Messung (max. 120s bzw. konfigurierbar) + const isMeldungen = chartTitle === "Meldungen"; + + // Progress for running TDR measurement const TDR_TOTAL_DURATION = parseInt( process.env.NEXT_PUBLIC_TDR_DURATION_SECONDS || "120", 10 ); const [tdrRunning, setTdrRunning] = useState(false); - const [tdrProgress, setTdrProgress] = useState(0); // Sekunden + const [tdrProgress, setTdrProgress] = useState(0); useEffect(() => { if (!tdrRunning) return; setTdrProgress(0); - const startedAt = Date.now(); + const started = Date.now(); const interval = setInterval(() => { - const elapsed = Math.floor((Date.now() - startedAt) / 1000); + const elapsed = Math.floor((Date.now() - started) / 1000); if (elapsed >= TDR_TOTAL_DURATION) { setTdrProgress(TDR_TOTAL_DURATION); setTdrRunning(false); @@ -60,102 +68,82 @@ const TDRChartActionBar: React.FC = () => { setTdrProgress(0); }; - // 📌 Referenz setzen (nutzt Slotnummer + 1 für die API) + const handleFetchMessages = async () => { + const fromDate = pickerVon ?? vonDatum; + const toDate = pickerBis ?? bisDatum; + try { + dispatch(setLoading(true)); + await dispatch(getMessagesThunk({ fromDate, toDate })).unwrap(); + } catch (e) { + console.error("❌ Fehler beim Laden der Meldungen", e); + alert("❌ Fehler beim Laden der Meldungen."); + } finally { + dispatch(setLoading(false)); + } + }; + const handleSetReference = async () => { if ( selectedSlot === null || selectedId === null || - !currentChartData?.length + !currentChartData.length ) return; - + const isDev = process.env.NEXT_PUBLIC_NODE_ENV === "development"; try { - const slotNumber = selectedSlot + 1; // Slot ist 0-basiert, API will 1-basiert - const isDev = process.env.NEXT_PUBLIC_NODE_ENV === "development"; - - if (isDev) { - await fetch("/api/cpl/updateTdrReferenceCurveAPIHandler", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - slot: slotNumber, - data: currentChartData, - }), - }); - } else { - const url = `/CPL?/${window.location.pathname}&KTR${slotNumber}=${selectedId}`; - await fetch(url, { method: "GET" }); - } if (!isDev) { - const url = `/CPL?KTR${slotNumber}=${selectedId}`; + const url = `/CPL?KTR${selectedSlot + 1}=${selectedId}`; const response = await fetch(url, { method: "GET" }); - - if (!response.ok) { + if (!response.ok) throw new Error( `Fehler beim Setzen der Referenz: ${response.statusText}` ); - } } - - // Optional: lokale Speicherung und Redux-Update localStorage.setItem( `ref-curve-slot${selectedSlot}`, JSON.stringify(currentChartData) ); - dispatch(getReferenceCurveBySlotThunk(selectedSlot)); - alert("Referenzkurve wurde erfolgreich gesetzt!"); - } catch (error) { - console.error("Fehler beim Setzen der Referenzkurve:", error); + } catch (err) { + console.error("Fehler beim Setzen der Referenzkurve", err); alert("Fehler beim Setzen der Referenzkurve."); } }; - // 📌 TDR Messung starten const handleStartTDR = async () => { if (selectedSlot === null) { alert("⚠️ Bitte zuerst einen KÜ auswählen!"); return; } - const cgiUrl = `${window.location.origin}/CPL?/${window.location.pathname}&KTT${selectedSlot}=1`; - try { - console.log("🚀 Starte TDR Messung für Slot:", selectedSlot); - console.log("📡 CGI URL:", cgiUrl); const isDev = process.env.NEXT_PUBLIC_NODE_ENV === "development"; if (isDev) { - // Dev / Simulator: sofort starten & Progress anzeigen await new Promise((r) => setTimeout(r, 150)); - console.log("✅ [DEV] TDR Mock-Start ok für Slot", selectedSlot); startTdrProgress(); return; } - const response = await fetch(cgiUrl); if (!response.ok) throw new Error(`CGI-Fehler: ${response.status}`); - console.log("✅ TDR Messung gestartet für Slot", selectedSlot); startTdrProgress(); } catch (err) { - console.error("❌ Fehler beim Starten der TDR Messung:", err); - //alert("❌ Fehler beim Starten der TDR Messung."); + console.error("❌ Fehler beim Starten der TDR Messung", err); } }; - // 📥 Beim Slot-Wechsel TDM-Liste + letzte ID laden + // Load TDM list when slot changes useEffect(() => { if (selectedSlot !== null) { dispatch(fetchTDMDataBySlotThunk(selectedSlot)).then((action) => { - // action can be a PayloadAction with payload or a rejected action const payload = ( action as { payload?: { data?: { id: number; t: string; d: number }[] }; } ).payload; - const slotData = payload?.data; - if ((slotData ?? []).length > 0) { - const lastId = (slotData ?? [])[0].id; + const slotData = payload?.data ?? []; + if (slotData.length > 0) { + const lastId = slotData[0].id; // latest first setSelectedId(lastId); dispatch(getTDRChartDataByIdThunk(lastId)); } @@ -166,7 +154,6 @@ const TDRChartActionBar: React.FC = () => { return ( <>
- {/* Slot Badge */}
KÜ @@ -175,98 +162,117 @@ const TDRChartActionBar: React.FC = () => { {selectedSlot !== null ? selectedSlot + 1 : "-"}
- {/* Referenz speichern */} - {selectedId !== null && ( + {/* Date range always visible */} + + {isMeldungen ? ( - )} - {/* Start TDR */} - - {/* Messung Dropdown */} -
- { - setSelectedId(id); - if (id !== null) dispatch(getTDRChartDataByIdThunk(id)); - }} - disabled={idsForSlot.length === 0} - > -
- - - {selectedId - ? (() => { - const selected = idsForSlot.find( - (e) => e.id === selectedId - ); - return selected - ? `${new Date(selected.t).toLocaleString("de-DE", { - day: "2-digit", - month: "2-digit", - year: "numeric", - hour: "2-digit", - minute: "2-digit", - second: "2-digit", - })} – Fehlerstelle: ${selected.d} m` - : "Wähle Messung"; - })() - : "Wähle Messung"} - - - - - {idsForSlot.map((entry) => { - const dateLabel = new Date(entry.t).toLocaleString("de-DE", { - day: "2-digit", - month: "2-digit", - year: "numeric", - hour: "2-digit", - minute: "2-digit", - second: "2-digit", - }); - const fullText = `${dateLabel} – Fehlerstelle: ${entry.d} m`; - return ( - { - const base = - "px-3 h-8 cursor-pointer rounded-sm m-0.5 flex items-center justify-start transition-colors text-[13px]"; - if (selected) - return `${base} dropdown-option-active font-medium`; - if (active) return `${base} dropdown-option-hover`; - return `${base}`; // neutral text color comes from parent/theme - }} - > - {fullText} - - ); - })} - + ) : ( + <> + {selectedId !== null && ( + + )} + +
+ { + setSelectedId(id); + if (id !== null) dispatch(getTDRChartDataByIdThunk(id)); + }} + disabled={idsForSlot.length === 0} + > +
+ + + {selectedId + ? (() => { + const selected = idsForSlot.find( + (e) => e.id === selectedId + ); + return selected + ? `${new Date(selected.t).toLocaleString( + "de-DE", + { + day: "2-digit", + month: "2-digit", + year: "numeric", + hour: "2-digit", + minute: "2-digit", + second: "2-digit", + } + )} – Fehlerstelle: ${selected.d} m` + : "Wähle Messung"; + })() + : "Wähle Messung"} + + + + + {idsForSlot.map((entry) => { + const dateLabel = new Date(entry.t).toLocaleString( + "de-DE", + { + day: "2-digit", + month: "2-digit", + year: "numeric", + hour: "2-digit", + minute: "2-digit", + second: "2-digit", + } + ); + const fullText = `${dateLabel} – Fehlerstelle: ${entry.d} m`; + return ( + { + const base = + "px-3 h-8 cursor-pointer rounded-sm m-0.5 flex items-center justify-start transition-colors text-[13px]"; + if (selected) + return `${base} dropdown-option-active font-medium`; + if (active) return `${base} dropdown-option-hover`; + return `${base}`; + }} + > + {fullText} + + ); + })} + +
+
- -
+ + )}
{tdrRunning && (
diff --git a/package-lock.json b/package-lock.json index 20a7a3b..326854e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cpl-v4", - "version": "1.6.884", + "version": "1.6.885", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "cpl-v4", - "version": "1.6.884", + "version": "1.6.885", "dependencies": { "@emotion/react": "^11.13.0", "@emotion/styled": "^11.13.0", diff --git a/package.json b/package.json index 466d897..f0fefc6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cpl-v4", - "version": "1.6.884", + "version": "1.6.885", "private": true, "scripts": { "dev": "next dev -p 3000", diff --git a/playwright/tests/components/main/kabelueberwachung/isoModal.test.ts b/playwright/tests/components/main/kabelueberwachung/isoModal.test.ts index 141e711..1862cbb 100644 --- a/playwright/tests/components/main/kabelueberwachung/isoModal.test.ts +++ b/playwright/tests/components/main/kabelueberwachung/isoModal.test.ts @@ -78,9 +78,12 @@ test.describe("ISO Modal", () => { dialog.getByRole("cell", { name: header }) ); } - - await expect(dialog.getByText("Von")).not.toBeVisible(); - await expect(dialog.getByText("Bis")).not.toBeVisible(); + // In Meldungen view only Von/Bis + Anzeigen (no mode dropdown) + await expect(dialog.getByText("Von")).toBeVisible(); + await expect(dialog.getByText("Bis")).toBeVisible(); + await expect( + dialog.getByRole("button", { name: "Anzeigen" }) + ).toBeVisible(); await viewToggle.click(); await page.getByRole("option", { name: "Messkurve" }).click();