feat: TDR Meldungen DateRangePicker
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.886
|
NEXT_PUBLIC_APP_VERSION=1.6.887
|
||||||
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.886
|
NEXT_PUBLIC_APP_VERSION=1.6.887
|
||||||
NEXT_PUBLIC_CPL_MODE=production
|
NEXT_PUBLIC_CPL_MODE=production
|
||||||
@@ -1,3 +1,8 @@
|
|||||||
|
## [1.6.887] – 2025-09-10
|
||||||
|
|
||||||
|
- style: actionbar in RSL und ISO
|
||||||
|
|
||||||
|
---
|
||||||
## [1.6.886] – 2025-09-10
|
## [1.6.886] – 2025-09-10
|
||||||
|
|
||||||
- WIP: von bis Zeitraum in ISO und TDR, aber TDR ist WIP
|
- WIP: von bis Zeitraum in ISO und TDR, aber TDR ist WIP
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import { AppDispatch } from "../../../../../../redux/store";
|
|||||||
import { Chart, registerables } from "chart.js";
|
import { Chart, registerables } from "chart.js";
|
||||||
import "chartjs-adapter-date-fns";
|
import "chartjs-adapter-date-fns";
|
||||||
import { getColor } from "../../../../../../utils/colors";
|
import { getColor } from "../../../../../../utils/colors";
|
||||||
import TDRChartActionBar from "./TDRChartActionBar";
|
|
||||||
import { getReferenceCurveBySlotThunk } from "../../../../../../redux/thunks/getReferenceCurveBySlotThunk";
|
import { getReferenceCurveBySlotThunk } from "../../../../../../redux/thunks/getReferenceCurveBySlotThunk";
|
||||||
|
|
||||||
const TDRChart: React.FC<{ isFullScreen: boolean }> = ({ isFullScreen }) => {
|
const TDRChart: React.FC<{ isFullScreen: boolean }> = ({ isFullScreen }) => {
|
||||||
@@ -212,8 +211,7 @@ const TDRChart: React.FC<{ isFullScreen: boolean }> = ({ isFullScreen }) => {
|
|||||||
//--------------------------------------
|
//--------------------------------------
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ width: "100%", height: isFullScreen ? "90%" : "28rem" }}>
|
<div style={{ width: "100%", height: isFullScreen ? "90%" : "28rem" }}>
|
||||||
<TDRChartActionBar />
|
|
||||||
|
|
||||||
{tdrChartData.length === 0 ? (
|
{tdrChartData.length === 0 ? (
|
||||||
<div className="flex items-center justify-center h-full text-gray-500 italic">
|
<div className="flex items-center justify-center h-full text-gray-500 italic">
|
||||||
|
|||||||
@@ -153,7 +153,8 @@ const TDRChartActionBar: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="toolbar w-full flex items-center gap-3 flex-wrap">
|
<div className="toolbar w-full justify-between flex-wrap">
|
||||||
|
{/* KÜ number left, controls right, like IsoChartActionBar */}
|
||||||
<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Ü
|
||||||
@@ -162,141 +163,145 @@ const TDRChartActionBar: React.FC = () => {
|
|||||||
{selectedSlot !== null ? selectedSlot + 1 : "-"}
|
{selectedSlot !== null ? selectedSlot + 1 : "-"}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{/* Date range only in Meldungen (requirement) */}
|
<div className="flex items-center gap-3 flex-1 justify-end">
|
||||||
{isMeldungen && <DateRangePicker />}
|
{isMeldungen ? (
|
||||||
{isMeldungen ? (
|
<>
|
||||||
<button
|
<DateRangePicker />
|
||||||
type="button"
|
|
||||||
onClick={handleFetchMessages}
|
|
||||||
className="btn-primary h-8 font-medium px-4"
|
|
||||||
disabled={selectedSlot === null}
|
|
||||||
>
|
|
||||||
Anzeigen
|
|
||||||
</button>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
{selectedId !== null && (
|
|
||||||
<button
|
<button
|
||||||
onClick={handleSetReference}
|
|
||||||
type="button"
|
type="button"
|
||||||
className="btn-primary h-8 px-3 font-medium"
|
onClick={handleFetchMessages}
|
||||||
|
className="btn-primary h-8 font-medium px-4"
|
||||||
disabled={selectedSlot === null}
|
disabled={selectedSlot === null}
|
||||||
>
|
>
|
||||||
TDR-Kurve als Referenz speichern
|
Anzeigen
|
||||||
</button>
|
</button>
|
||||||
)}
|
</>
|
||||||
<button
|
) : (
|
||||||
onClick={handleStartTDR}
|
<>
|
||||||
type="button"
|
{selectedId !== null && (
|
||||||
disabled={selectedSlot === null || tdrRunning}
|
<button
|
||||||
className={`btn-primary h-8 px-4 whitespace-nowrap ${
|
onClick={handleSetReference}
|
||||||
tdrRunning ? "opacity-90" : ""
|
type="button"
|
||||||
}`}
|
className="btn-primary h-8 px-3 font-medium"
|
||||||
>
|
disabled={selectedSlot === null}
|
||||||
{tdrRunning
|
>
|
||||||
? `TDR läuft... (${Math.min(
|
TDR-Kurve als Referenz speichern
|
||||||
100,
|
</button>
|
||||||
Math.round((tdrProgress / TDR_TOTAL_DURATION) * 100)
|
)}
|
||||||
)}%)`
|
<button
|
||||||
: "TDR-Messung starten"}
|
onClick={handleStartTDR}
|
||||||
</button>
|
type="button"
|
||||||
<div className="ml-auto flex-1 min-w-[14rem] max-w-[30rem]">
|
disabled={selectedSlot === null || tdrRunning}
|
||||||
<Listbox
|
className={`btn-primary h-8 px-4 whitespace-nowrap ${
|
||||||
value={selectedId}
|
tdrRunning ? "opacity-90" : ""
|
||||||
onChange={(id) => {
|
}`}
|
||||||
setSelectedId(id);
|
|
||||||
if (id !== null) dispatch(getTDRChartDataByIdThunk(id));
|
|
||||||
}}
|
|
||||||
disabled={idsForSlot.length === 0}
|
|
||||||
>
|
>
|
||||||
<div className="relative w-full">
|
{tdrRunning
|
||||||
<Listbox.Button className="dropdown-surface w-full flex items-center justify-between h-8 disabled:opacity-50 disabled:cursor-not-allowed">
|
? `TDR läuft... (${Math.min(
|
||||||
<span className="dropdown-text-fix whitespace-nowrap overflow-hidden text-ellipsis pr-2">
|
100,
|
||||||
{selectedId
|
Math.round((tdrProgress / TDR_TOTAL_DURATION) * 100)
|
||||||
? (() => {
|
)}%)`
|
||||||
const selected = idsForSlot.find(
|
: "TDR-Messung starten"}
|
||||||
(e) => e.id === selectedId
|
</button>
|
||||||
);
|
<div className="ml-auto flex-1 min-w-[14rem] max-w-[30rem]">
|
||||||
return selected
|
<Listbox
|
||||||
? `${new Date(selected.t).toLocaleString(
|
value={selectedId}
|
||||||
"de-DE",
|
onChange={(id) => {
|
||||||
{
|
setSelectedId(id);
|
||||||
day: "2-digit",
|
if (id !== null) dispatch(getTDRChartDataByIdThunk(id));
|
||||||
month: "2-digit",
|
}}
|
||||||
year: "numeric",
|
disabled={idsForSlot.length === 0}
|
||||||
hour: "2-digit",
|
>
|
||||||
minute: "2-digit",
|
<div className="relative w-full">
|
||||||
second: "2-digit",
|
<Listbox.Button className="dropdown-surface w-full flex items-center justify-between h-8 disabled:opacity-50 disabled:cursor-not-allowed">
|
||||||
}
|
<span className="dropdown-text-fix whitespace-nowrap overflow-hidden text-ellipsis pr-2">
|
||||||
)} – Fehlerstelle: ${selected.d} m`
|
{selectedId
|
||||||
: "Wähle Messung";
|
? (() => {
|
||||||
})()
|
const selected = idsForSlot.find(
|
||||||
: "Wähle Messung"}
|
(e) => e.id === selectedId
|
||||||
</span>
|
);
|
||||||
<i className="bi bi-chevron-down text-sm opacity-70" />
|
return selected
|
||||||
</Listbox.Button>
|
? `${new Date(selected.t).toLocaleString(
|
||||||
<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">
|
"de-DE",
|
||||||
{idsForSlot.map((entry) => {
|
{
|
||||||
const dateLabel = new Date(entry.t).toLocaleString(
|
day: "2-digit",
|
||||||
"de-DE",
|
month: "2-digit",
|
||||||
{
|
year: "numeric",
|
||||||
day: "2-digit",
|
hour: "2-digit",
|
||||||
month: "2-digit",
|
minute: "2-digit",
|
||||||
year: "numeric",
|
second: "2-digit",
|
||||||
hour: "2-digit",
|
}
|
||||||
minute: "2-digit",
|
)} – Fehlerstelle: ${selected.d} m`
|
||||||
second: "2-digit",
|
: "Wähle Messung";
|
||||||
}
|
})()
|
||||||
);
|
: "Wähle Messung"}
|
||||||
const fullText = `${dateLabel} – Fehlerstelle: ${entry.d} m`;
|
</span>
|
||||||
return (
|
<i className="bi bi-chevron-down text-sm opacity-70" />
|
||||||
<Listbox.Option
|
</Listbox.Button>
|
||||||
key={entry.id}
|
<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">
|
||||||
value={entry.id}
|
{idsForSlot.map((entry) => {
|
||||||
title={fullText}
|
const dateLabel = new Date(entry.t).toLocaleString(
|
||||||
className={({ selected, active }) => {
|
"de-DE",
|
||||||
const base =
|
{
|
||||||
"px-3 h-8 cursor-pointer rounded-sm m-0.5 flex items-center justify-start transition-colors text-[13px]";
|
day: "2-digit",
|
||||||
if (selected)
|
month: "2-digit",
|
||||||
return `${base} dropdown-option-active font-medium`;
|
year: "numeric",
|
||||||
if (active) return `${base} dropdown-option-hover`;
|
hour: "2-digit",
|
||||||
return `${base}`;
|
minute: "2-digit",
|
||||||
}}
|
second: "2-digit",
|
||||||
>
|
}
|
||||||
<span className="truncate w-full">{fullText}</span>
|
);
|
||||||
</Listbox.Option>
|
const fullText = `${dateLabel} – Fehlerstelle: ${entry.d} m`;
|
||||||
);
|
return (
|
||||||
})}
|
<Listbox.Option
|
||||||
</Listbox.Options>
|
key={entry.id}
|
||||||
</div>
|
value={entry.id}
|
||||||
</Listbox>
|
title={fullText}
|
||||||
|
className={({ selected, active }) => {
|
||||||
|
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}`;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span className="truncate w-full">{fullText}</span>
|
||||||
|
</Listbox.Option>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Listbox.Options>
|
||||||
|
</div>
|
||||||
|
</Listbox>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{/* Progress Overlay */}
|
||||||
|
{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="mb-4 text-center space-y-1">
|
||||||
|
<p className="text-lg font-semibold text-white">
|
||||||
|
TDR Messung läuft... kann bis zu zwei Minuten dauern
|
||||||
|
</p>
|
||||||
|
<p className="text-sm text-white/80">
|
||||||
|
Bitte warten…{" "}
|
||||||
|
{Math.min(
|
||||||
|
100,
|
||||||
|
Math.round((tdrProgress / TDR_TOTAL_DURATION) * 100)
|
||||||
|
)}
|
||||||
|
%
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</>
|
<div className="w-2/3 max-w-xl h-3 bg-white/20 rounded overflow-hidden shadow-inner">
|
||||||
|
<div
|
||||||
|
className="h-full bg-accent transition-all ease-linear"
|
||||||
|
style={{ width: `${(tdrProgress / TDR_TOTAL_DURATION) * 100}%` }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{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="mb-4 text-center space-y-1">
|
|
||||||
<p className="text-lg font-semibold text-white">
|
|
||||||
TDR Messung läuft... kann bis zu zwei Minuten dauern
|
|
||||||
</p>
|
|
||||||
<p className="text-sm text-white/80">
|
|
||||||
Bitte warten…{" "}
|
|
||||||
{Math.min(
|
|
||||||
100,
|
|
||||||
Math.round((tdrProgress / TDR_TOTAL_DURATION) * 100)
|
|
||||||
)}
|
|
||||||
%
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div className="w-2/3 max-w-xl h-3 bg-white/20 rounded overflow-hidden shadow-inner">
|
|
||||||
<div
|
|
||||||
className="h-full bg-accent transition-all ease-linear"
|
|
||||||
style={{ width: `${(tdrProgress / TDR_TOTAL_DURATION) * 100}%` }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import ReactModal from "react-modal";
|
import ReactModal from "react-modal";
|
||||||
import TDRChart from "./TDRChart";
|
import TDRChart from "./TDRChart";
|
||||||
|
import TDRChartActionBar from "./TDRChartActionBar";
|
||||||
import { useSelector, useDispatch } from "react-redux";
|
import { useSelector, useDispatch } from "react-redux";
|
||||||
import { AppDispatch, RootState } from "@/redux/store";
|
import { AppDispatch, RootState } from "@/redux/store";
|
||||||
import {
|
import {
|
||||||
@@ -166,6 +167,8 @@ const TDRChartView: React.FC<TDRChartViewProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<div className="flex flex-col flex-1 p-3 gap-3">
|
<div className="flex flex-col flex-1 p-3 gap-3">
|
||||||
|
{/* Action Bar (wie bei ISO / Loop) */}
|
||||||
|
<TDRChartActionBar />
|
||||||
<div className="flex-1 relative">
|
<div className="flex-1 relative">
|
||||||
{chartTitle === "Messkurve" ? (
|
{chartTitle === "Messkurve" ? (
|
||||||
<TDRChart isFullScreen={isFullScreen} />
|
<TDRChart isFullScreen={isFullScreen} />
|
||||||
|
|||||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "cpl-v4",
|
"name": "cpl-v4",
|
||||||
"version": "1.6.886",
|
"version": "1.6.887",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "cpl-v4",
|
"name": "cpl-v4",
|
||||||
"version": "1.6.886",
|
"version": "1.6.887",
|
||||||
"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.886",
|
"version": "1.6.887",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev -p 3000",
|
"dev": "next dev -p 3000",
|
||||||
|
|||||||
Reference in New Issue
Block a user