diff --git a/dashboard/public/program-info.json b/dashboard/public/program-info.json new file mode 100644 index 0000000..48c155e --- /dev/null +++ b/dashboard/public/program-info.json @@ -0,0 +1,58 @@ +{ + "appName": "Infoscreen-Management", + "version": "2025.1.0-alpha.3", + "copyright": "© 2025 Third-Age-Applications", + "supportContact": "support@third-age-applications.com", + "description": "Eine zentrale Verwaltungsoberfläche für digitale Informationsbildschirme.", + "techStack": { + "frontend": "React, Vite, TypeScript, Tailwind CSS", + "backend": "Python (Flask), SQLAlchemy", + "database": "MariaDB", + "realtime": "Mosquitto (MQTT)", + "containerization": "Docker" + }, + "openSourceComponents": { + "frontend": [ + { "name": "React", "license": "MIT" }, + { "name": "Vite", "license": "MIT" }, + { "name": "Tailwind CSS", "license": "MIT" }, + { "name": "Lucide Icons", "license": "ISC" }, + { "name": "Syncfusion UI Components", "license": "Kommerziell / Community" } + ], + "backend": [ + { "name": "Flask", "license": "BSD" }, + { "name": "SQLAlchemy", "license": "MIT" }, + { "name": "Paho-MQTT", "license": "EPL/EDL" }, + { "name": "Alembic", "license": "MIT" } + ] + }, + "buildInfo": { + "buildDate": "2025-08-30T12:00:00Z", + "commitId": "a1b2c3d4e5f6" + }, + "changelog": [ + { + "version": "2025.1.0-alpha.3", + "date": "2025-08-30", + "changes": [ + "NEU: Programminfo-Seite mit dynamischen Daten, Build-Infos und Changelog.", + "NEU: Logout-Funktionalität implementiert.", + "FIX: Breite der Sidebar im eingeklappten Zustand korrigiert." + ] + }, + { + "version": "2025.1.0-alpha.2", + "date": "2025-08-29", + "changes": [ + "INFO: Analyse und Anzeige der verwendeten Open-Source-Bibliotheken." + ] + }, + { + "version": "2025.1.0-alpha.1", + "date": "2025-08-28", + "changes": [ + "Initiales Setup des Projekts und der Grundstruktur." + ] + } + ] +} diff --git a/dashboard/src/App.css b/dashboard/src/App.css index de1d541..bf101df 100644 --- a/dashboard/src/App.css +++ b/dashboard/src/App.css @@ -28,7 +28,7 @@ body { /* Layout-Container für Sidebar und Content */ .layout-container { display: flex; - min-height: 100vh; + height: 100vh; /* Feste Höhe auf die des Viewports setzen */ overflow: hidden; /* Verhindert, dass der Scrollbalken den gesamten Container betrifft */ } @@ -38,7 +38,6 @@ body { color: var(--sidebar-fg); font-size: 1.15rem; font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif; - width: 240px; /* Feste Breite für die Sidebar */ flex-shrink: 0; overflow: hidden; } diff --git a/dashboard/src/App.tsx b/dashboard/src/App.tsx index 1800ae1..5e26fbc 100644 --- a/dashboard/src/App.tsx +++ b/dashboard/src/App.tsx @@ -1,11 +1,5 @@ import React, { useState } from 'react'; -import { - BrowserRouter as Router, - Routes, - Route, - Link, - Outlet, -} from 'react-router-dom'; +import { BrowserRouter as Router, Routes, Route, Link, Outlet } from 'react-router-dom'; import logo from './assets/logo.png'; import './App.css'; @@ -21,6 +15,7 @@ import { MonitorDotIcon, LogOut, Wrench, + Info, } from 'lucide-react'; import { ToastProvider } from './components/ToastProvider'; @@ -34,6 +29,7 @@ const sidebarItems = [ { name: 'Medien', path: '/medien', icon: Image }, { name: 'Benutzer', path: '/benutzer', icon: User }, { name: 'Einstellungen', path: '/einstellungen', icon: Settings }, + { name: 'Programminfo', path: '/programminfo', icon: Info }, ]; // Dummy Components (können in eigene Dateien ausgelagert werden) @@ -46,18 +42,28 @@ import Media from './media'; import Benutzer from './benutzer'; import Einstellungen from './einstellungen'; import SetupMode from './SetupMode'; +import Programminfo from './programminfo'; +import Logout from './logout'; // ENV aus .env holen (Platzhalter, im echten Projekt über process.env oder API) // const ENV = import.meta.env.VITE_ENV || 'development'; const Layout: React.FC = () => { const [collapsed, setCollapsed] = useState(false); + const [version, setVersion] = useState(''); + + React.useEffect(() => { + fetch('/program-info.json') + .then(res => res.json()) + .then(data => setVersion(data.version)) + .catch(err => console.error('Failed to load version info:', err)); + }, []); return (
{/* Sidebar */} {/* Main Content */} @@ -143,9 +148,7 @@ const Layout: React.FC = () => { ); }; - const App: React.FC = () => { - // Automatische Navigation zu /clients bei leerer Beschreibung entfernt return ( @@ -161,7 +164,9 @@ const App: React.FC = () => { } /> } /> } /> + } /> + } /> ); diff --git a/dashboard/src/logout.tsx b/dashboard/src/logout.tsx new file mode 100644 index 0000000..2aecbe1 --- /dev/null +++ b/dashboard/src/logout.tsx @@ -0,0 +1,12 @@ +import React from 'react'; + +const Logout: React.FC = () => ( +
+
+

Abmeldung

+

Sie haben sich erfolgreich abgemeldet.

+
+
+); + +export default Logout; diff --git a/dashboard/src/programminfo.tsx b/dashboard/src/programminfo.tsx new file mode 100644 index 0000000..23a96d3 --- /dev/null +++ b/dashboard/src/programminfo.tsx @@ -0,0 +1,168 @@ +import React, { useState, useEffect } from 'react'; + +interface ProgramInfo { + appName: string; + version: string; + copyright: string; + supportContact: string; + description: string; + techStack: { + [key: string]: string; + }; + openSourceComponents: { + frontend: { name: string; license: string }[]; + backend: { name: string; license: string }[]; + }; + buildInfo: { + buildDate: string; + commitId: string; + }; + changelog: { + version: string; + date: string; + changes: string[]; + }[]; +} + +const Programminfo: React.FC = () => { + const [info, setInfo] = useState(null); + const [error, setError] = useState(null); + + useEffect(() => { + fetch('/program-info.json') + .then(response => { + if (!response.ok) { + throw new Error('Netzwerk-Antwort war nicht ok'); + } + return response.json(); + }) + .then(data => setInfo(data)) + .catch(error => { + console.error('Fehler beim Laden der Programminformationen:', error); + setError('Informationen konnten nicht geladen werden.'); + }); + }, []); + + if (error) { + return ( +
+

Fehler

+

{error}

+
+ ); + } + + if (!info) { + return ( +
+

Programminfo

+

Lade Informationen...

+
+ ); + } + + return ( +
+
+

{info.appName}

+

{info.description}

+
+ +
+ {/* Allgemeine Infos & Build */} +
+

Allgemein

+
+

+ Version: {info.version} +

+

+ Copyright: {info.copyright} +

+

+ Support:{' '} + + {info.supportContact} + +

+
+

Build-Informationen

+

+ Build-Datum:{' '} + {new Date(info.buildInfo.buildDate).toLocaleString('de-DE')} +

+

+ Commit-ID:{' '} + + {info.buildInfo.commitId} + +

+
+
+ + {/* Technischer Stack */} +
+

Technologie-Stack

+
    + {Object.entries(info.techStack).map(([key, value]) => ( +
  • + {key}: {value} +
  • + ))} +
+
+
+ + {/* Changelog */} +
+

Änderungsprotokoll (Changelog)

+
+ {info.changelog.map(log => ( +
+

+ Version {log.version}{' '} + + - {new Date(log.date).toLocaleDateString('de-DE')} + +

+
    + {log.changes.map((change, index) => ( +
  • {change}
  • + ))} +
+
+ ))} +
+
+ + {/* Open Source Komponenten */} +
+

Verwendete Open-Source-Komponenten

+
+
+

Frontend

+
    + {info.openSourceComponents.frontend.map(item => ( +
  • + {item.name} ({item.license}-Lizenz) +
  • + ))} +
+
+
+

Backend

+
    + {info.openSourceComponents.backend.map(item => ( +
  • + {item.name} ({item.license}-Lizenz) +
  • + ))} +
+
+
+
+
+ ); +}; + +export default Programminfo;