feat(analogInputs): automatisches Laden der Chart-Daten bei Tabellenklick via Redux
- analogInputsHistorySlice um `autoLoad` erweitert, um automatisches Laden zu triggern - handleSelect in AnalogInputsTable dispatcht jetzt `setAutoLoad(true)` - AnalogInputsChart lauscht auf `autoLoad` + `selectedId` und lädt Daten automatisch - `autoLoad` wird nach dem Laden wieder auf false zurückgesetzt
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.599
|
NEXT_PUBLIC_APP_VERSION=1.6.601
|
||||||
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.599
|
NEXT_PUBLIC_APP_VERSION=1.6.601
|
||||||
NEXT_PUBLIC_CPL_MODE=production
|
NEXT_PUBLIC_CPL_MODE=production
|
||||||
10
CHANGELOG.md
10
CHANGELOG.md
@@ -1,3 +1,13 @@
|
|||||||
|
## [1.6.601] – 2025-07-15
|
||||||
|
|
||||||
|
- uninstall redux-persist, weil nimmt viel Performance weg
|
||||||
|
|
||||||
|
---
|
||||||
|
## [1.6.600] – 2025-07-15
|
||||||
|
|
||||||
|
- uninstall redux-persist, weil nimmt viel Performance weg
|
||||||
|
|
||||||
|
---
|
||||||
## [1.6.599] – 2025-07-14
|
## [1.6.599] – 2025-07-14
|
||||||
|
|
||||||
- feat: AnalogInputsChart mit DateRangePicker und vollständiger Redux-Integration erweitert
|
- feat: AnalogInputsChart mit DateRangePicker und vollständiger Redux-Integration erweitert
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import {
|
|||||||
setVonDatum,
|
setVonDatum,
|
||||||
setBisDatum,
|
setBisDatum,
|
||||||
setZeitraum,
|
setZeitraum,
|
||||||
|
setAutoLoad,
|
||||||
} from "@/redux/slices/analogInputs/analogInputsHistorySlice";
|
} from "@/redux/slices/analogInputs/analogInputsHistorySlice";
|
||||||
import DateRangePicker from "@/components/common/DateRangePicker";
|
import DateRangePicker from "@/components/common/DateRangePicker";
|
||||||
import { Listbox } from "@headlessui/react";
|
import { Listbox } from "@headlessui/react";
|
||||||
@@ -43,17 +44,12 @@ type AnalogInputHistoryPoint = {
|
|||||||
m: number;
|
m: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function AnalogInputsChart({
|
export default function AnalogInputsChart() {
|
||||||
selectedId,
|
|
||||||
}: {
|
|
||||||
selectedId: number | null;
|
|
||||||
}) {
|
|
||||||
const dispatch = useDispatch<AppDispatch>();
|
const dispatch = useDispatch<AppDispatch>();
|
||||||
const chartRef = useRef<any>(null);
|
const chartRef = useRef<any>(null);
|
||||||
|
|
||||||
const { zeitraum, vonDatum, bisDatum, data, isLoading } = useSelector(
|
const { zeitraum, vonDatum, bisDatum, data, autoLoad, selectedId } =
|
||||||
(state: RootState) => state.analogInputsHistory
|
useSelector((state: RootState) => state.analogInputsHistory);
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
@@ -128,6 +124,19 @@ export default function AnalogInputsChart({
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (autoLoad && selectedId) {
|
||||||
|
dispatch(
|
||||||
|
getAnalogInputsHistoryThunk({
|
||||||
|
eingang: selectedId,
|
||||||
|
zeitraum,
|
||||||
|
vonDatum,
|
||||||
|
bisDatum,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
dispatch(setAutoLoad(false)); // ✅ zurücksetzen, sonst endlose Schleife
|
||||||
|
}
|
||||||
|
}, [autoLoad, selectedId, dispatch, zeitraum, vonDatum, bisDatum]);
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-3">
|
<div className="flex flex-col gap-3">
|
||||||
<div className="flex flex-wrap items-center gap-4 mb-2">
|
<div className="flex flex-wrap items-center gap-4 mb-2">
|
||||||
|
|||||||
@@ -9,7 +9,10 @@ import settingsIcon from "@iconify/icons-mdi/settings";
|
|||||||
import waveformIcon from "@iconify/icons-mdi/waveform";
|
import waveformIcon from "@iconify/icons-mdi/waveform";
|
||||||
import { setSelectedAnalogInput } from "@/redux/slices/analogInputs/selectedAnalogInputSlice";
|
import { setSelectedAnalogInput } from "@/redux/slices/analogInputs/selectedAnalogInputSlice";
|
||||||
import { setIsSettingsModalOpen } from "@/redux/slices/analogInputs/analogInputsUiSlice";
|
import { setIsSettingsModalOpen } from "@/redux/slices/analogInputs/analogInputsUiSlice";
|
||||||
import { setSelectedId } from "@/redux/slices/analogInputs/analogInputsHistorySlice";
|
import {
|
||||||
|
setSelectedId,
|
||||||
|
setAutoLoad,
|
||||||
|
} from "@/redux/slices/analogInputs/analogInputsHistorySlice";
|
||||||
|
|
||||||
export default function AnalogInputsTable() {
|
export default function AnalogInputsTable() {
|
||||||
const dispatch = useDispatch<AppDispatch>();
|
const dispatch = useDispatch<AppDispatch>();
|
||||||
@@ -25,10 +28,10 @@ export default function AnalogInputsTable() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const handleSelect = (id: number, input: AnalogInput) => {
|
const handleSelect = (id: number, input: AnalogInput) => {
|
||||||
dispatch(setIsSettingsModalOpen(true));
|
|
||||||
dispatch(setSelectedId(id));
|
dispatch(setSelectedId(id));
|
||||||
setActiveId(id);
|
setActiveId(id);
|
||||||
dispatch(setSelectedAnalogInput(input));
|
dispatch(setSelectedAnalogInput(input));
|
||||||
|
dispatch(setAutoLoad(true));
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -54,48 +57,60 @@ export default function AnalogInputsTable() {
|
|||||||
<tbody>
|
<tbody>
|
||||||
{Object.values(analogInputs)
|
{Object.values(analogInputs)
|
||||||
.filter(
|
.filter(
|
||||||
(e) =>
|
(analogInput) =>
|
||||||
e && typeof e.id === "number" && typeof e.label === "string"
|
analogInput &&
|
||||||
|
typeof analogInput.id === "number" &&
|
||||||
|
typeof analogInput.label === "string"
|
||||||
)
|
)
|
||||||
.slice(0, 8)
|
.slice(0, 8)
|
||||||
.map((e, index) => (
|
.map((analogInput, index) => (
|
||||||
<tr
|
<tr
|
||||||
key={index}
|
key={index}
|
||||||
className={`transition cursor-pointer ${
|
className={`transition cursor-pointer ${
|
||||||
e.id === activeId ? "bg-blue-100" : "hover:bg-gray-100"
|
analogInput.id === activeId
|
||||||
|
? "bg-blue-100"
|
||||||
|
: "hover:bg-gray-100"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<td
|
<td
|
||||||
className="border p-2"
|
className="border p-2"
|
||||||
onClick={() => handleSelect(e.id!, e)}
|
onClick={() => handleSelect(analogInput.id!, analogInput)}
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-1 ">
|
<div className="flex items-center gap-1 ">
|
||||||
<Icon
|
<Icon
|
||||||
icon={waveformIcon}
|
icon={waveformIcon}
|
||||||
className="text-gray-600 text-base laptop:text-sm xl:text-sm 2xl:text-lg"
|
className="text-gray-600 text-base laptop:text-sm xl:text-sm 2xl:text-lg"
|
||||||
/>
|
/>
|
||||||
{e.id ?? "-"}
|
{analogInput.id ?? "-"}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td
|
<td
|
||||||
className="border p-2 text-right"
|
className="border p-2 text-right"
|
||||||
onClick={() => handleSelect(e.id!, e)}
|
onClick={() => handleSelect(analogInput.id!, analogInput)}
|
||||||
>
|
>
|
||||||
{typeof e.value === "number" ? e.value.toFixed(2) : "-"}
|
{typeof analogInput.value === "number"
|
||||||
|
? analogInput.value.toFixed(2)
|
||||||
|
: "-"}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td className="border p-2">{e.unit || "-"}</td>
|
|
||||||
<td
|
<td
|
||||||
className="border p-2"
|
className="border p-2"
|
||||||
onClick={() => handleSelect(e.id!, e)}
|
onClick={() => handleSelect(analogInput.id!, analogInput)}
|
||||||
>
|
>
|
||||||
{e.label || "----"}
|
{analogInput.unit || "-"}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
className="border p-2"
|
||||||
|
onClick={() => handleSelect(analogInput.id!, analogInput)}
|
||||||
|
>
|
||||||
|
{analogInput.label || "----"}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td className="border p-2 text-center">
|
<td className="border p-2 text-center">
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
handleSelect(e.id!, e);
|
handleSelect(analogInput.id!, analogInput);
|
||||||
|
dispatch(setIsSettingsModalOpen(true));
|
||||||
}}
|
}}
|
||||||
className="text-gray-400 hover:text-gray-500"
|
className="text-gray-400 hover:text-gray-500"
|
||||||
>
|
>
|
||||||
|
|||||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "cpl-v4",
|
"name": "cpl-v4",
|
||||||
"version": "1.6.599",
|
"version": "1.6.601",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "cpl-v4",
|
"name": "cpl-v4",
|
||||||
"version": "1.6.599",
|
"version": "1.6.601",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fontsource/roboto": "^5.1.0",
|
"@fontsource/roboto": "^5.1.0",
|
||||||
"@headlessui/react": "^2.2.4",
|
"@headlessui/react": "^2.2.4",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "cpl-v4",
|
"name": "cpl-v4",
|
||||||
"version": "1.6.599",
|
"version": "1.6.601",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ export interface InputHistoryState {
|
|||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
error: string | null;
|
error: string | null;
|
||||||
data: Record<string, AnalogInputsHistoryEntry[]>;
|
data: Record<string, AnalogInputsHistoryEntry[]>;
|
||||||
|
autoLoad: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialState: InputHistoryState = {
|
const initialState: InputHistoryState = {
|
||||||
@@ -25,6 +26,7 @@ const initialState: InputHistoryState = {
|
|||||||
isLoading: false,
|
isLoading: false,
|
||||||
error: null,
|
error: null,
|
||||||
data: {},
|
data: {},
|
||||||
|
autoLoad: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const analogInputsHistorySlice = createSlice({
|
export const analogInputsHistorySlice = createSlice({
|
||||||
@@ -34,6 +36,9 @@ export const analogInputsHistorySlice = createSlice({
|
|||||||
setSelectedId: (state, action: PayloadAction<number | null>) => {
|
setSelectedId: (state, action: PayloadAction<number | null>) => {
|
||||||
state.selectedId = action.payload;
|
state.selectedId = action.payload;
|
||||||
},
|
},
|
||||||
|
setAutoLoad: (state, action: PayloadAction<boolean>) => {
|
||||||
|
state.autoLoad = action.payload; // ✅ AutoLoad steuern
|
||||||
|
},
|
||||||
setZeitraum: (state, action: PayloadAction<string>) => {
|
setZeitraum: (state, action: PayloadAction<string>) => {
|
||||||
state.zeitraum = action.payload;
|
state.zeitraum = action.payload;
|
||||||
},
|
},
|
||||||
@@ -64,6 +69,7 @@ export const analogInputsHistorySlice = createSlice({
|
|||||||
|
|
||||||
export const {
|
export const {
|
||||||
setSelectedId,
|
setSelectedId,
|
||||||
|
setAutoLoad,
|
||||||
setZeitraum,
|
setZeitraum,
|
||||||
setVonDatum,
|
setVonDatum,
|
||||||
setBisDatum,
|
setBisDatum,
|
||||||
|
|||||||
Reference in New Issue
Block a user