docs: Zusatzfunktionen (Kai, 25.06.2025) in TODO.md ergänzt
This commit is contained in:
@@ -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"
|
||||
>
|
||||
|
||||
@@ -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({});
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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({});
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user