From 7b38b49598254ef06436b18aea370e1e9cc04e96 Mon Sep 17 00:00:00 2001 From: RobbStarkAustria Date: Thu, 16 Oct 2025 17:57:06 +0000 Subject: [PATCH] rename benutzer to users add role management to media page --- dashboard/public/program-info.json | 1 + dashboard/src/App.tsx | 2 +- .../CustomSelectUploadEventModal.tsx | 25 ++++++++++- dashboard/src/index.css | 2 + dashboard/src/login.tsx | 5 ++- dashboard/src/main.tsx | 1 + dashboard/src/media.tsx | 27 +++++++++++- dashboard/src/theme-overrides.css | 15 +++++++ dashboard/src/{benutzer.tsx => users.tsx} | 0 server/routes/eventmedia.py | 43 ++++++++++++++++++- 10 files changed, 116 insertions(+), 5 deletions(-) create mode 100644 dashboard/src/theme-overrides.css rename dashboard/src/{benutzer.tsx => users.tsx} (100%) diff --git a/dashboard/public/program-info.json b/dashboard/public/program-info.json index df46a27..e9ee1af 100644 --- a/dashboard/public/program-info.json +++ b/dashboard/public/program-info.json @@ -34,6 +34,7 @@ "version": "2025.1.0-alpha.10", "date": "2025-10-15", "changes": [ + "🔐 Auth: Login und Benutzerverwaltung implementiert (rollenbasiert, persistente Sitzungen).", "✨ UI: Benutzer-Menü oben rechts – DropDownButton mit Benutzername/Rolle; Einträge: ‘Profil’ und ‘Abmelden’.", "🧩 Frontend: Syncfusion SplitButtons integriert (react-splitbuttons) und Vite-Konfiguration für Pre-Bundling ergänzt.", "🐛 Fix: Import-Fehler ‘@syncfusion/ej2-react-splitbuttons’ – Anleitung in README hinzugefügt (optimizeDeps + Volume-Reset)." diff --git a/dashboard/src/App.tsx b/dashboard/src/App.tsx index fef4bc2..aed3976 100644 --- a/dashboard/src/App.tsx +++ b/dashboard/src/App.tsx @@ -44,7 +44,7 @@ import Ressourcen from './ressourcen'; import Infoscreens from './clients'; import Infoscreen_groups from './infoscreen_groups'; import Media from './media'; -import Benutzer from './benutzer'; +import Benutzer from './users'; import Einstellungen from './settings'; import SetupMode from './SetupMode'; import Programminfo from './programminfo'; diff --git a/dashboard/src/components/CustomSelectUploadEventModal.tsx b/dashboard/src/components/CustomSelectUploadEventModal.tsx index 7a3f122..9092bcf 100644 --- a/dashboard/src/components/CustomSelectUploadEventModal.tsx +++ b/dashboard/src/components/CustomSelectUploadEventModal.tsx @@ -1,4 +1,5 @@ -import React, { useState } from 'react'; +import React, { useMemo, useState } from 'react'; +import { useAuth } from '../useAuth'; import { DialogComponent } from '@syncfusion/ej2-react-popups'; import { FileManagerComponent, @@ -19,6 +20,8 @@ type CustomSelectUploadEventModalProps = { const CustomSelectUploadEventModal: React.FC = props => { const { open, onClose, onSelect } = props; + const { user } = useAuth(); + const isSuperadmin = useMemo(() => user?.role === 'superadmin', [user]); const [selectedFile, setSelectedFile] = useState<{ id: string; @@ -63,6 +66,23 @@ const CustomSelectUploadEventModal: React.FC } }; + type FileItem = { name: string; isFile: boolean }; + type ReadSuccessArgs = { action: string; result?: { files?: FileItem[] } }; + type FileOpenArgs = { fileDetails?: FileItem; cancel?: boolean }; + + const handleSuccess = (args: ReadSuccessArgs) => { + if (isSuperadmin) return; + if (args && args.action === 'read' && args.result && Array.isArray(args.result.files)) { + args.result.files = args.result.files.filter((f: FileItem) => !(f.name === 'converted' && !f.isFile)); + } + }; + + const handleFileOpen = (args: FileOpenArgs) => { + if (!isSuperadmin && args && args.fileDetails && args.fileDetails.name === 'converted' && !args.fileDetails.isFile) { + args.cancel = true; + } + }; + return ( )} > (null); const isDev = import.meta.env.MODE !== 'production'; + const navigate = useNavigate(); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setMessage(null); try { await login(username, password); - // Browser will stay on /login; App's route gate will redirect to '/' setMessage('Login erfolgreich'); + // Redirect to dashboard after successful login + navigate('/'); } catch (err) { setMessage(err instanceof Error ? err.message : 'Login fehlgeschlagen'); } diff --git a/dashboard/src/main.tsx b/dashboard/src/main.tsx index 6a71cc0..b7fc7ad 100644 --- a/dashboard/src/main.tsx +++ b/dashboard/src/main.tsx @@ -21,6 +21,7 @@ import '@syncfusion/ej2-lists/styles/material3.css'; import '@syncfusion/ej2-calendars/styles/material3.css'; import '@syncfusion/ej2-splitbuttons/styles/material3.css'; import '@syncfusion/ej2-icons/styles/material3.css'; +import './theme-overrides.css'; // Setze hier deinen Lizenzschlüssel ein registerLicense( diff --git a/dashboard/src/media.tsx b/dashboard/src/media.tsx index 12d8b61..2f71d9b 100644 --- a/dashboard/src/media.tsx +++ b/dashboard/src/media.tsx @@ -1,4 +1,4 @@ -import React, { useState, useRef } from 'react'; +import React, { useState, useRef, useMemo } from 'react'; import CustomMediaInfoPanel from './components/CustomMediaInfoPanel'; import { FileManagerComponent, @@ -7,10 +7,13 @@ import { DetailsView, Toolbar, } from '@syncfusion/ej2-react-filemanager'; +import { useAuth } from './useAuth'; const hostUrl = '/api/eventmedia/filemanager/'; // Dein Backend-Endpunkt für FileManager const Media: React.FC = () => { + const { user } = useAuth(); + const isSuperadmin = useMemo(() => user?.role === 'superadmin', [user]); // State für die angezeigten Dateidetails const [fileDetails] = useState { } }, [viewMode]); + type FileItem = { name: string; isFile: boolean }; + type ReadSuccessArgs = { action: string; result?: { files?: FileItem[] } }; + type FileOpenArgs = { fileDetails?: FileItem; cancel?: boolean }; + + // Hide "converted" for non-superadmins after data load + const handleSuccess = (args: ReadSuccessArgs) => { + if (isSuperadmin) return; + if (args && args.action === 'read' && args.result && Array.isArray(args.result.files)) { + args.result.files = args.result.files.filter((f: FileItem) => !(f.name === 'converted' && !f.isFile)); + } + }; + + // Prevent opening the "converted" folder for non-superadmins + const handleFileOpen = (args: FileOpenArgs) => { + if (!isSuperadmin && args && args.fileDetails && args.fileDetails.name === 'converted' && !args.fileDetails.isFile) { + args.cancel = true; + } + }; + return (

Medien

@@ -65,6 +87,9 @@ const Media: React.FC = () => { {/* Debug-Ausgabe entfernt, da ReactNode erwartet wird */}