docs: Zusatzfunktionen (Kai, 25.06.2025) in TODO.md ergänzt

This commit is contained in:
ISA
2025-06-25 11:42:42 +02:00
parent ca2a0cb00d
commit 2fcd0755a4
29 changed files with 369 additions and 122 deletions

View File

@@ -18,7 +18,13 @@ import handleAdminLogin from "./handlers/handleAdminLogin";
ReactModal.setAppElement("#__next");
function SettingModal({ showModal, onClose }) {
function SettingModal({
showModal,
onClose,
}: {
showModal: boolean;
onClose: () => void;
}) {
const { isAdminLoggedIn, logoutAdmin } = useAdminAuth(showModal);
const { formValues, setFormValues } = useSystemSettings(showModal);
@@ -72,9 +78,21 @@ function SettingModal({ showModal, onClose }) {
const [ntp2, setNtp2] = useState(ntp2_Redux || "");
const [ntp3, setNtp3] = useState(ntp3_Redux || "");
const [ntpTimezone, setNtpTimezone] = useState(ntpTimezone_Redux || "");
const [active, setActive] = useState(active_Redux || "");
const [active, setActive] = useState<boolean>(
typeof active_Redux === "boolean" ? active_Redux : active_Redux === "true"
);
const [originalValues, setOriginalValues] = useState({});
const [originalValues, setOriginalValues] = useState({
name: name,
ip: ip,
subnet: subnet,
gateway: gateway,
ntp1: ntp1,
ntp2: ntp2,
ntp3: ntp3,
ntpTimezone: ntpTimezone,
active: active,
});
const currentValues = {
name,
ip,
@@ -228,12 +246,14 @@ function SettingModal({ showModal, onClose }) {
</div>
<div>
<label className="block font-medium">NTP Active:</label>
<input
type="text"
<select
className="border border-gray-300 rounded p-1 xl:p-2 w-full"
value={active}
onChange={(e) => setActive(e.target.value)}
/>
value={active ? "true" : "false"}
onChange={(e) => setActive(e.target.value === "true")}
>
<option value="true">true</option>
<option value="false">false</option>
</select>
</div>
</div>
@@ -241,13 +261,13 @@ function SettingModal({ showModal, onClose }) {
<div className="flex flex-col md:flex-row justify-between mt-4 gap-2">
<button
className="bg-littwin-blue text-white px-3 py-1 xl:px-4 xl:py-2 rounded w-full md:w-auto"
onClick={handleReboot}
onClick={() => handleReboot()}
>
Neustart CPL
</button>
<button
onClick={() =>
isAdminLoggedIn ? handleAdminLogout() : setShowLoginForm(true)
isAdminLoggedIn ? logoutAdmin() : setShowLoginForm(true)
}
className="bg-littwin-blue text-white px-3 py-1 xl:px-4 xl:py-2 rounded w-full md:w-auto"
>

View File

@@ -3,7 +3,7 @@ import { useState, useEffect } from "react";
import { useSelector } from "react-redux";
import { RootState } from "../../../../redux/store";
export function useSystemSettings(showModal: boolean) {
const settings = useSelector((state: RootState) => state.systemSettings);
const settings = useSelector((state: RootState) => state.systemSettingsSlice);
const [formValues, setFormValues] = useState(settings);
const [originalValues, setOriginalValues] = useState({});

View File

@@ -16,13 +16,24 @@ export function generateKeyAndIV() {
}
// Generiert einen verschlüsselten Token
export function generateToken(user) {
const payload = {
interface User {
username: string;
role: string;
}
interface TokenPayload {
username: string;
role: string;
exp: number;
}
export function generateToken(user: User): string {
const payload: TokenPayload = {
username: user.username,
role: user.role,
exp: Date.now() + 5 * 60 * 1000, // Ablaufzeit: 5 Minuten
};
const token = JSON.stringify(payload);
const token: string = JSON.stringify(payload);
const { key, iv } = generateKeyAndIV();
return CryptoJS.AES.encrypt(token, key, { iv }).toString();
}

View File

@@ -38,7 +38,11 @@ export default function AnalogInputsChart({
const dispatch = useDispatch<AppDispatch>();
const { data, isLoading, error } = useSelector(
(state: RootState) => state.analogInputsHistory
);
) as {
data: { [key: string]: any[] };
isLoading: boolean;
error: any;
};
useEffect(() => {
dispatch(getAnalogInputsHistoryThunk());
@@ -95,7 +99,7 @@ export default function AnalogInputsChart({
x: {
type: "time" as const,
time: {
unit: "hour",
unit: "hour" as const,
tooltipFormat: "HH:mm 'Uhr' dd.MM.",
displayFormats: {
hour: "HH:mm",

View File

@@ -1,4 +1,16 @@
"use client"; // /components/main/analogInputs/AnalogInputsTable.tsx
export type AnalogInput = {
id: number;
value: number;
label: string;
unit?: string; // Make unit optional if it may not exist
offset: number;
factor: number;
loggerInterval: number;
weighting: number;
};
import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { RootState, AppDispatch } from "@/redux/store";

View File

@@ -9,7 +9,13 @@ import outputIcon from "@iconify/icons-mdi/output";
import switchIcon from "@iconify/icons-ion/switch";
import { setDigitalOutputs } from "@/redux/slices/digitalOutputsSlice";
export default function DigitalOutputsWidget({ openOutputModal }) {
interface DigitalOutputsWidgetProps {
openOutputModal: (output: any) => void;
}
export default function DigitalOutputsWidget({
openOutputModal,
}: DigitalOutputsWidgetProps) {
const dispatch = useDispatch<AppDispatch>();
const digitalOutputs = useSelector(
(state: RootState) => state.digitalOutputsSlice.outputs

View File

@@ -3,7 +3,7 @@ import { useState, useEffect } from "react";
import { useSelector } from "react-redux";
import { RootState } from "../../../../redux/store";
export function useSystemSettings(showModal: boolean) {
const settings = useSelector((state: RootState) => state.systemSettings);
const settings = useSelector((state: RootState) => state.systemSettingsSlice);
const [formValues, setFormValues] = useState(settings);
const [originalValues, setOriginalValues] = useState({});

View File

@@ -16,13 +16,22 @@ export function generateKeyAndIV() {
}
// Generiert einen verschlüsselten Token
export function generateToken(user) {
const payload = {
interface UserPayload {
username: string;
role: string;
}
interface TokenPayload extends UserPayload {
exp: number;
}
export function generateToken(user: UserPayload): string {
const payload: TokenPayload = {
username: user.username,
role: user.role,
exp: Date.now() + 5 * 60 * 1000, // Ablaufzeit: 5 Minuten
};
const token = JSON.stringify(payload);
const token: string = JSON.stringify(payload);
const { key, iv } = generateKeyAndIV();
return CryptoJS.AES.encrypt(token, key, { iv }).toString();
}

View File

@@ -4,16 +4,22 @@ import { Icon } from "@iconify/react";
import { useSelector } from "react-redux";
import { RootState } from "../../../redux/store";
const VersionInfo: React.FC = () => {
type VersionInfoProps = {
className?: string;
};
const VersionInfo: React.FC<VersionInfoProps> = ({ className = "" }) => {
const appVersion =
useSelector((state: RootState) => state.systemSettingsSlice.appVersion) ||
"Unbekannt";
const webVersion = useSelector(
(state: RootState) => state.webVersionSlice.appVersion
); // Webversion aus Redux holen
);
return (
<div className="bg-gray-50 p-4 rounded-lg shadow-sm border border-gray-200 w-full laptop:p-2">
<div
className={`bg-gray-50 rounded-lg shadow-sm border border-gray-200 w-full laptop:p-2 ${className}`}
>
<h2 className="text-lg font-semibold text-gray-700 mb-2">
Versionsinformationen
</h2>