WIP: von bis Zeitraum in ISO und TDR, aber TDR ist WIP
This commit is contained in:
@@ -6,6 +6,6 @@ NEXT_PUBLIC_USE_MOCK_BACKEND_LOOP_START=false
|
|||||||
NEXT_PUBLIC_EXPORT_STATIC=false
|
NEXT_PUBLIC_EXPORT_STATIC=false
|
||||||
NEXT_PUBLIC_USE_CGI=false
|
NEXT_PUBLIC_USE_CGI=false
|
||||||
# App-Versionsnummer
|
# 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)
|
NEXT_PUBLIC_CPL_MODE=json # json (Entwicklungsumgebung) oder jsSimulatedProd (CPL ->CGI-Interface-Simulator) oder production (CPL-> CGI-Interface Platzhalter)
|
||||||
|
|
||||||
|
|||||||
@@ -5,5 +5,5 @@ NEXT_PUBLIC_CPL_API_PATH=/CPL
|
|||||||
NEXT_PUBLIC_EXPORT_STATIC=true
|
NEXT_PUBLIC_EXPORT_STATIC=true
|
||||||
NEXT_PUBLIC_USE_CGI=true
|
NEXT_PUBLIC_USE_CGI=true
|
||||||
# App-Versionsnummer
|
# App-Versionsnummer
|
||||||
NEXT_PUBLIC_APP_VERSION=1.6.884
|
NEXT_PUBLIC_APP_VERSION=1.6.885
|
||||||
NEXT_PUBLIC_CPL_MODE=production
|
NEXT_PUBLIC_CPL_MODE=production
|
||||||
@@ -1,3 +1,8 @@
|
|||||||
|
## [1.6.885] – 2025-09-09
|
||||||
|
|
||||||
|
- test: rename test files *.test.ts
|
||||||
|
|
||||||
|
---
|
||||||
## [1.6.884] – 2025-09-09
|
## [1.6.884] – 2025-09-09
|
||||||
|
|
||||||
- Tests: TDR ISO und RSL
|
- Tests: TDR ISO und RSL
|
||||||
|
|||||||
@@ -271,7 +271,7 @@ const IsoChartActionBar = forwardRef((_props, ref) => {
|
|||||||
|
|
||||||
useImperativeHandle(ref, () => ({ handleFetchData }));
|
useImperativeHandle(ref, () => ({ handleFetchData }));
|
||||||
|
|
||||||
const hiddenWhenMeldungen = chartTitle !== "Messkurve";
|
const isMeldungen = chartTitle === "Meldungen";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="toolbar w-full justify-between flex-wrap">
|
<div className="toolbar w-full justify-between flex-wrap">
|
||||||
@@ -283,23 +283,11 @@ const IsoChartActionBar = forwardRef((_props, ref) => {
|
|||||||
{slotNumber !== null ? slotNumber + 1 : "-"}
|
{slotNumber !== null ? slotNumber + 1 : "-"}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2 flex-1 justify-end">
|
<div className="flex items-center gap-3 flex-1 justify-end">
|
||||||
<div
|
{/* Always show date range; requirement: in Meldungen only Von/Bis + Anzeigen */}
|
||||||
className={
|
|
||||||
hiddenWhenMeldungen
|
|
||||||
? "opacity-0 pointer-events-none"
|
|
||||||
: "opacity-100"
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<DateRangePicker />
|
<DateRangePicker />
|
||||||
</div>
|
{!isMeldungen && (
|
||||||
<div
|
<>
|
||||||
className={`transition-opacity ${
|
|
||||||
hiddenWhenMeldungen
|
|
||||||
? "opacity-0 pointer-events-none"
|
|
||||||
: "opacity-100"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<Listbox
|
<Listbox
|
||||||
value={selectedMode}
|
value={selectedMode}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
@@ -347,16 +335,24 @@ const IsoChartActionBar = forwardRef((_props, ref) => {
|
|||||||
</Listbox.Options>
|
</Listbox.Options>
|
||||||
</div>
|
</div>
|
||||||
</Listbox>
|
</Listbox>
|
||||||
</div>
|
|
||||||
<button
|
<button
|
||||||
onClick={handleFetchData}
|
onClick={handleFetchData}
|
||||||
className={`btn-primary h-8 font-medium px-3 ${
|
className="btn-primary h-8 font-medium px-3"
|
||||||
hiddenWhenMeldungen ? "invisible" : "visible"
|
|
||||||
}`}
|
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
Daten laden
|
Daten laden
|
||||||
</button>
|
</button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{isMeldungen && (
|
||||||
|
<button
|
||||||
|
onClick={handleFetchData}
|
||||||
|
className="btn-primary h-8 font-medium px-4"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
Anzeigen
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -283,6 +283,7 @@ const LoopChartActionBar = forwardRef((_props, ref) => {
|
|||||||
|
|
||||||
// Sichtbarkeits-Flags
|
// Sichtbarkeits-Flags
|
||||||
const isMesskurve = chartTitle === "Messkurve";
|
const isMesskurve = chartTitle === "Messkurve";
|
||||||
|
const isMeldungen = chartTitle === "Meldungen";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="toolbar w-full flex flex-wrap items-center gap-2">
|
<div className="toolbar w-full flex flex-wrap items-center gap-2">
|
||||||
@@ -347,8 +348,9 @@ const LoopChartActionBar = forwardRef((_props, ref) => {
|
|||||||
</Listbox>
|
</Listbox>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Buttons nur für Messkurve */}
|
{/* Buttons */}
|
||||||
<div className={isMesskurve ? "flex items-center gap-2" : "hidden"}>
|
{isMesskurve && (
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
<button
|
<button
|
||||||
onClick={handleStartRSL}
|
onClick={handleStartRSL}
|
||||||
className="btn-primary h-8 font-medium px-3"
|
className="btn-primary h-8 font-medium px-3"
|
||||||
@@ -366,6 +368,17 @@ const LoopChartActionBar = forwardRef((_props, ref) => {
|
|||||||
Daten laden
|
Daten laden
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
{isMeldungen && (
|
||||||
|
<button
|
||||||
|
onClick={handleFetchData}
|
||||||
|
className="btn-primary h-8 font-medium px-4"
|
||||||
|
disabled={rslRunning}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
Anzeigen
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{rslRunning && (
|
{rslRunning && (
|
||||||
|
|||||||
@@ -1,49 +1,57 @@
|
|||||||
|
"use client";
|
||||||
// /components/main/kabelueberwachung/kue705FO/Charts/TDRChart/TDRChartActionBar.tsx
|
// /components/main/kabelueberwachung/kue705FO/Charts/TDRChart/TDRChartActionBar.tsx
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
import React, { useState, useEffect } from "react";
|
import DateRangePicker from "@/components/common/DateRangePicker";
|
||||||
import { useSelector } from "react-redux";
|
|
||||||
import { useAppDispatch } from "@/redux/store";
|
import { useAppDispatch } from "@/redux/store";
|
||||||
|
import { useSelector } from "react-redux";
|
||||||
import { RootState } from "@/redux/store";
|
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 { fetchTDMDataBySlotThunk } from "@/redux/thunks/getTDMListBySlotThunk";
|
||||||
import { getTDRChartDataByIdThunk } from "@/redux/thunks/getTDRChartDataByIdThunk";
|
import { getTDRChartDataByIdThunk } from "@/redux/thunks/getTDRChartDataByIdThunk";
|
||||||
import { getReferenceCurveBySlotThunk } from "@/redux/thunks/getReferenceCurveBySlotThunk"; // ⬅ import ergänzen
|
import { getReferenceCurveBySlotThunk } from "@/redux/thunks/getReferenceCurveBySlotThunk";
|
||||||
import { Listbox } from "@headlessui/react";
|
|
||||||
|
|
||||||
const TDRChartActionBar: React.FC = () => {
|
const TDRChartActionBar: React.FC = () => {
|
||||||
const dispatch = useAppDispatch();
|
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(
|
const selectedSlot = useSelector(
|
||||||
(state: RootState) => state.kueChartModeSlice.selectedSlot
|
(s: RootState) => s.kueChartModeSlice.selectedSlot
|
||||||
);
|
);
|
||||||
|
|
||||||
const tdmChartData = useSelector(
|
const tdmChartData = useSelector(
|
||||||
(state: RootState) => state.tdmSingleChartSlice.data
|
(s: RootState) => s.tdmSingleChartSlice.data
|
||||||
);
|
);
|
||||||
|
|
||||||
const idsForSlot =
|
const idsForSlot =
|
||||||
selectedSlot !== null ? tdmChartData[selectedSlot] ?? [] : [];
|
selectedSlot !== null ? tdmChartData[selectedSlot] ?? [] : [];
|
||||||
|
|
||||||
const tdrDataById = useSelector(
|
const tdrDataById = useSelector(
|
||||||
(state: RootState) => state.tdrDataByIdSlice.dataById
|
(s: RootState) => s.tdrDataByIdSlice.dataById
|
||||||
);
|
);
|
||||||
const [selectedId, setSelectedId] = useState<number | null>(null);
|
const [selectedId, setSelectedId] = useState<number | null>(null);
|
||||||
const currentChartData = selectedId !== null ? tdrDataById[selectedId] : [];
|
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(
|
const TDR_TOTAL_DURATION = parseInt(
|
||||||
process.env.NEXT_PUBLIC_TDR_DURATION_SECONDS || "120",
|
process.env.NEXT_PUBLIC_TDR_DURATION_SECONDS || "120",
|
||||||
10
|
10
|
||||||
);
|
);
|
||||||
const [tdrRunning, setTdrRunning] = useState(false);
|
const [tdrRunning, setTdrRunning] = useState(false);
|
||||||
const [tdrProgress, setTdrProgress] = useState(0); // Sekunden
|
const [tdrProgress, setTdrProgress] = useState(0);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!tdrRunning) return;
|
if (!tdrRunning) return;
|
||||||
setTdrProgress(0);
|
setTdrProgress(0);
|
||||||
const startedAt = Date.now();
|
const started = Date.now();
|
||||||
const interval = setInterval(() => {
|
const interval = setInterval(() => {
|
||||||
const elapsed = Math.floor((Date.now() - startedAt) / 1000);
|
const elapsed = Math.floor((Date.now() - started) / 1000);
|
||||||
if (elapsed >= TDR_TOTAL_DURATION) {
|
if (elapsed >= TDR_TOTAL_DURATION) {
|
||||||
setTdrProgress(TDR_TOTAL_DURATION);
|
setTdrProgress(TDR_TOTAL_DURATION);
|
||||||
setTdrRunning(false);
|
setTdrRunning(false);
|
||||||
@@ -60,102 +68,82 @@ const TDRChartActionBar: React.FC = () => {
|
|||||||
setTdrProgress(0);
|
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 () => {
|
const handleSetReference = async () => {
|
||||||
if (
|
if (
|
||||||
selectedSlot === null ||
|
selectedSlot === null ||
|
||||||
selectedId === null ||
|
selectedId === null ||
|
||||||
!currentChartData?.length
|
!currentChartData.length
|
||||||
)
|
)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
try {
|
|
||||||
const slotNumber = selectedSlot + 1; // Slot ist 0-basiert, API will 1-basiert
|
|
||||||
const isDev = process.env.NEXT_PUBLIC_NODE_ENV === "development";
|
const isDev = process.env.NEXT_PUBLIC_NODE_ENV === "development";
|
||||||
|
try {
|
||||||
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) {
|
if (!isDev) {
|
||||||
const url = `/CPL?KTR${slotNumber}=${selectedId}`;
|
const url = `/CPL?KTR${selectedSlot + 1}=${selectedId}`;
|
||||||
const response = await fetch(url, { method: "GET" });
|
const response = await fetch(url, { method: "GET" });
|
||||||
|
if (!response.ok)
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Fehler beim Setzen der Referenz: ${response.statusText}`
|
`Fehler beim Setzen der Referenz: ${response.statusText}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Optional: lokale Speicherung und Redux-Update
|
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
`ref-curve-slot${selectedSlot}`,
|
`ref-curve-slot${selectedSlot}`,
|
||||||
JSON.stringify(currentChartData)
|
JSON.stringify(currentChartData)
|
||||||
);
|
);
|
||||||
|
|
||||||
dispatch(getReferenceCurveBySlotThunk(selectedSlot));
|
dispatch(getReferenceCurveBySlotThunk(selectedSlot));
|
||||||
|
|
||||||
alert("Referenzkurve wurde erfolgreich gesetzt!");
|
alert("Referenzkurve wurde erfolgreich gesetzt!");
|
||||||
} catch (error) {
|
} catch (err) {
|
||||||
console.error("Fehler beim Setzen der Referenzkurve:", error);
|
console.error("Fehler beim Setzen der Referenzkurve", err);
|
||||||
alert("Fehler beim Setzen der Referenzkurve.");
|
alert("Fehler beim Setzen der Referenzkurve.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 📌 TDR Messung starten
|
|
||||||
const handleStartTDR = async () => {
|
const handleStartTDR = async () => {
|
||||||
if (selectedSlot === null) {
|
if (selectedSlot === null) {
|
||||||
alert("⚠️ Bitte zuerst einen KÜ auswählen!");
|
alert("⚠️ Bitte zuerst einen KÜ auswählen!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const cgiUrl = `${window.location.origin}/CPL?/${window.location.pathname}&KTT${selectedSlot}=1`;
|
const cgiUrl = `${window.location.origin}/CPL?/${window.location.pathname}&KTT${selectedSlot}=1`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log("🚀 Starte TDR Messung für Slot:", selectedSlot);
|
|
||||||
console.log("📡 CGI URL:", cgiUrl);
|
|
||||||
const isDev = process.env.NEXT_PUBLIC_NODE_ENV === "development";
|
const isDev = process.env.NEXT_PUBLIC_NODE_ENV === "development";
|
||||||
if (isDev) {
|
if (isDev) {
|
||||||
// Dev / Simulator: sofort starten & Progress anzeigen
|
|
||||||
await new Promise((r) => setTimeout(r, 150));
|
await new Promise((r) => setTimeout(r, 150));
|
||||||
console.log("✅ [DEV] TDR Mock-Start ok für Slot", selectedSlot);
|
|
||||||
startTdrProgress();
|
startTdrProgress();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await fetch(cgiUrl);
|
const response = await fetch(cgiUrl);
|
||||||
if (!response.ok) throw new Error(`CGI-Fehler: ${response.status}`);
|
if (!response.ok) throw new Error(`CGI-Fehler: ${response.status}`);
|
||||||
console.log("✅ TDR Messung gestartet für Slot", selectedSlot);
|
|
||||||
startTdrProgress();
|
startTdrProgress();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("❌ Fehler beim Starten der TDR Messung:", err);
|
console.error("❌ Fehler beim Starten der TDR Messung", err);
|
||||||
//alert("❌ Fehler beim Starten der TDR Messung.");
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 📥 Beim Slot-Wechsel TDM-Liste + letzte ID laden
|
// Load TDM list when slot changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedSlot !== null) {
|
if (selectedSlot !== null) {
|
||||||
dispatch(fetchTDMDataBySlotThunk(selectedSlot)).then((action) => {
|
dispatch(fetchTDMDataBySlotThunk(selectedSlot)).then((action) => {
|
||||||
// action can be a PayloadAction with payload or a rejected action
|
|
||||||
const payload = (
|
const payload = (
|
||||||
action as {
|
action as {
|
||||||
payload?: { data?: { id: number; t: string; d: number }[] };
|
payload?: { data?: { id: number; t: string; d: number }[] };
|
||||||
}
|
}
|
||||||
).payload;
|
).payload;
|
||||||
const slotData = payload?.data;
|
const slotData = payload?.data ?? [];
|
||||||
if ((slotData ?? []).length > 0) {
|
if (slotData.length > 0) {
|
||||||
const lastId = (slotData ?? [])[0].id;
|
const lastId = slotData[0].id; // latest first
|
||||||
setSelectedId(lastId);
|
setSelectedId(lastId);
|
||||||
dispatch(getTDRChartDataByIdThunk(lastId));
|
dispatch(getTDRChartDataByIdThunk(lastId));
|
||||||
}
|
}
|
||||||
@@ -166,7 +154,6 @@ const TDRChartActionBar: React.FC = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="toolbar w-full flex items-center gap-3 flex-wrap">
|
<div className="toolbar w-full flex items-center gap-3 flex-wrap">
|
||||||
{/* Slot Badge */}
|
|
||||||
<div className="flex items-center gap-2 pr-4">
|
<div className="flex items-center gap-2 pr-4">
|
||||||
<span className="font-semibold uppercase tracking-wide text-muted">
|
<span className="font-semibold uppercase tracking-wide text-muted">
|
||||||
KÜ
|
KÜ
|
||||||
@@ -175,17 +162,29 @@ const TDRChartActionBar: React.FC = () => {
|
|||||||
{selectedSlot !== null ? selectedSlot + 1 : "-"}
|
{selectedSlot !== null ? selectedSlot + 1 : "-"}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{/* Referenz speichern */}
|
{/* Date range always visible */}
|
||||||
|
<DateRangePicker />
|
||||||
|
{isMeldungen ? (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={handleFetchMessages}
|
||||||
|
className="btn-primary h-8 font-medium px-4"
|
||||||
|
disabled={selectedSlot === null}
|
||||||
|
>
|
||||||
|
Anzeigen
|
||||||
|
</button>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
{selectedId !== null && (
|
{selectedId !== null && (
|
||||||
<button
|
<button
|
||||||
onClick={handleSetReference}
|
onClick={handleSetReference}
|
||||||
type="button"
|
type="button"
|
||||||
className="btn-primary h-8 px-3 font-medium"
|
className="btn-primary h-8 px-3 font-medium"
|
||||||
|
disabled={selectedSlot === null}
|
||||||
>
|
>
|
||||||
TDR-Kurve als Referenz speichern
|
TDR-Kurve als Referenz speichern
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
{/* Start TDR */}
|
|
||||||
<button
|
<button
|
||||||
onClick={handleStartTDR}
|
onClick={handleStartTDR}
|
||||||
type="button"
|
type="button"
|
||||||
@@ -201,7 +200,6 @@ const TDRChartActionBar: React.FC = () => {
|
|||||||
)}%)`
|
)}%)`
|
||||||
: "TDR-Messung starten"}
|
: "TDR-Messung starten"}
|
||||||
</button>
|
</button>
|
||||||
{/* Messung Dropdown */}
|
|
||||||
<div className="ml-auto flex-1 min-w-[14rem] max-w-[30rem]">
|
<div className="ml-auto flex-1 min-w-[14rem] max-w-[30rem]">
|
||||||
<Listbox
|
<Listbox
|
||||||
value={selectedId}
|
value={selectedId}
|
||||||
@@ -220,14 +218,17 @@ const TDRChartActionBar: React.FC = () => {
|
|||||||
(e) => e.id === selectedId
|
(e) => e.id === selectedId
|
||||||
);
|
);
|
||||||
return selected
|
return selected
|
||||||
? `${new Date(selected.t).toLocaleString("de-DE", {
|
? `${new Date(selected.t).toLocaleString(
|
||||||
|
"de-DE",
|
||||||
|
{
|
||||||
day: "2-digit",
|
day: "2-digit",
|
||||||
month: "2-digit",
|
month: "2-digit",
|
||||||
year: "numeric",
|
year: "numeric",
|
||||||
hour: "2-digit",
|
hour: "2-digit",
|
||||||
minute: "2-digit",
|
minute: "2-digit",
|
||||||
second: "2-digit",
|
second: "2-digit",
|
||||||
})} – Fehlerstelle: ${selected.d} m`
|
}
|
||||||
|
)} – Fehlerstelle: ${selected.d} m`
|
||||||
: "Wähle Messung";
|
: "Wähle Messung";
|
||||||
})()
|
})()
|
||||||
: "Wähle Messung"}
|
: "Wähle Messung"}
|
||||||
@@ -236,14 +237,17 @@ const TDRChartActionBar: React.FC = () => {
|
|||||||
</Listbox.Button>
|
</Listbox.Button>
|
||||||
<Listbox.Options className="dropdown-options absolute z-50 mt-1 w-full max-h-72 overflow-auto text-sm bg-[var(--color-surface)] border border-base rounded-md shadow-lg p-1">
|
<Listbox.Options className="dropdown-options absolute z-50 mt-1 w-full max-h-72 overflow-auto text-sm bg-[var(--color-surface)] border border-base rounded-md shadow-lg p-1">
|
||||||
{idsForSlot.map((entry) => {
|
{idsForSlot.map((entry) => {
|
||||||
const dateLabel = new Date(entry.t).toLocaleString("de-DE", {
|
const dateLabel = new Date(entry.t).toLocaleString(
|
||||||
|
"de-DE",
|
||||||
|
{
|
||||||
day: "2-digit",
|
day: "2-digit",
|
||||||
month: "2-digit",
|
month: "2-digit",
|
||||||
year: "numeric",
|
year: "numeric",
|
||||||
hour: "2-digit",
|
hour: "2-digit",
|
||||||
minute: "2-digit",
|
minute: "2-digit",
|
||||||
second: "2-digit",
|
second: "2-digit",
|
||||||
});
|
}
|
||||||
|
);
|
||||||
const fullText = `${dateLabel} – Fehlerstelle: ${entry.d} m`;
|
const fullText = `${dateLabel} – Fehlerstelle: ${entry.d} m`;
|
||||||
return (
|
return (
|
||||||
<Listbox.Option
|
<Listbox.Option
|
||||||
@@ -256,7 +260,7 @@ const TDRChartActionBar: React.FC = () => {
|
|||||||
if (selected)
|
if (selected)
|
||||||
return `${base} dropdown-option-active font-medium`;
|
return `${base} dropdown-option-active font-medium`;
|
||||||
if (active) return `${base} dropdown-option-hover`;
|
if (active) return `${base} dropdown-option-hover`;
|
||||||
return `${base}`; // neutral text color comes from parent/theme
|
return `${base}`;
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span className="truncate w-full">{fullText}</span>
|
<span className="truncate w-full">{fullText}</span>
|
||||||
@@ -267,6 +271,8 @@ const TDRChartActionBar: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
</Listbox>
|
</Listbox>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{tdrRunning && (
|
{tdrRunning && (
|
||||||
<div className="fixed inset-0 z-[1000] flex flex-col items-center justify-center bg-[rgba(0,0,0,0.55)] backdrop-blur-sm">
|
<div className="fixed inset-0 z-[1000] flex flex-col items-center justify-center bg-[rgba(0,0,0,0.55)] backdrop-blur-sm">
|
||||||
|
|||||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "cpl-v4",
|
"name": "cpl-v4",
|
||||||
"version": "1.6.884",
|
"version": "1.6.885",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "cpl-v4",
|
"name": "cpl-v4",
|
||||||
"version": "1.6.884",
|
"version": "1.6.885",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "^11.13.0",
|
"@emotion/react": "^11.13.0",
|
||||||
"@emotion/styled": "^11.13.0",
|
"@emotion/styled": "^11.13.0",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "cpl-v4",
|
"name": "cpl-v4",
|
||||||
"version": "1.6.884",
|
"version": "1.6.885",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev -p 3000",
|
"dev": "next dev -p 3000",
|
||||||
|
|||||||
@@ -78,9 +78,12 @@ test.describe("ISO Modal", () => {
|
|||||||
dialog.getByRole("cell", { name: header })
|
dialog.getByRole("cell", { name: header })
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// In Meldungen view only Von/Bis + Anzeigen (no mode dropdown)
|
||||||
await expect(dialog.getByText("Von")).not.toBeVisible();
|
await expect(dialog.getByText("Von")).toBeVisible();
|
||||||
await expect(dialog.getByText("Bis")).not.toBeVisible();
|
await expect(dialog.getByText("Bis")).toBeVisible();
|
||||||
|
await expect(
|
||||||
|
dialog.getByRole("button", { name: "Anzeigen" })
|
||||||
|
).toBeVisible();
|
||||||
|
|
||||||
await viewToggle.click();
|
await viewToggle.click();
|
||||||
await page.getByRole("option", { name: "Messkurve" }).click();
|
await page.getByRole("option", { name: "Messkurve" }).click();
|
||||||
|
|||||||
Reference in New Issue
Block a user