Preparation for first deployment-test

This commit is contained in:
2025-09-03 19:47:16 +00:00
parent 4e74f72c9f
commit e30723da0a
14 changed files with 3612 additions and 245 deletions

3105
dashboard/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,25 +1,56 @@
import React from 'react';
interface CustomMediaInfoPanelProps {
mediaId: string;
title: string;
description: string;
eventId?: string;
onSave: (data: { title: string; description: string; eventId?: string }) => void;
name: string;
size: number;
type: string;
dateModified: number;
description?: string | null;
}
const CustomMediaInfoPanel: React.FC<CustomMediaInfoPanelProps> = ({
mediaId,
title,
name,
size,
type,
dateModified,
description,
eventId,
onSave,
}) => {
// Hier kannst du Formularfelder und Logik für die Bearbeitung einbauen
function formatLocalDate(timestamp: number | undefined | null) {
if (!timestamp || isNaN(timestamp)) return '-';
const date = new Date(timestamp * 1000);
return date.toLocaleString('de-DE');
}
return (
<div>
<h3>Medien-Informationen bearbeiten</h3>
{/* Formularfelder für Titel, Beschreibung, Event-Zuordnung */}
<div
style={{
padding: 16,
border: '1px solid #eee',
borderRadius: 8,
background: '#fafafa',
maxWidth: 400,
}}
>
<h3 style={{ marginBottom: 12 }}>Datei-Eigenschaften</h3>
<div>
<b>Name:</b> {name || '-'}
</div>
<div>
<b>Typ:</b> {type || '-'}
</div>
<div>
<b>Größe:</b> {typeof size === 'number' && !isNaN(size) ? size + ' Bytes' : '-'}
</div>
<div>
<b>Geändert:</b> {formatLocalDate(dateModified)}
</div>
<div>
<b>Beschreibung:</b>{' '}
{description && description !== 'null' ? (
description
) : (
<span style={{ color: '#888' }}>Keine Beschreibung</span>
)}
</div>
</div>
);
};

View File

@@ -19,33 +19,43 @@ interface MediaItem {
}
const Media: React.FC = () => {
const [mediaList, setMediaList] = useState<MediaItem[]>([]);
const [selectedMedia, setSelectedMedia] = useState<MediaItem | null>(null);
// State für die angezeigten Dateidetails
const [fileDetails, setFileDetails] = useState<null | {
name: string;
size: number;
type: string;
dateModified: number;
description?: string | null;
}>(null);
// Ansicht: 'LargeIcons', 'Details'
const [viewMode, setViewMode] = useState<'LargeIcons' | 'Details'>('LargeIcons');
// Medien vom Server laden
useEffect(() => {
fetch('/api/eventmedia')
.then(res => res.json())
.then(setMediaList);
}, []);
// Speichern von Metadaten/Event-Zuordnung
const handleSave = async (data: { title: string; description: string; eventId?: string }) => {
if (!selectedMedia) return;
await fetch(`/api/eventmedia/${selectedMedia.id}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});
// Nach dem Speichern neu laden
const res = await fetch('/api/eventmedia');
setMediaList(await res.json());
};
// Hilfsfunktion für Datum in Browser-Zeitzone
function formatLocalDate(timestamp: number) {
if (!timestamp) return '';
const date = new Date(timestamp * 1000);
return date.toLocaleString('de-DE'); // Zeigt lokale Zeit des Browsers
}
return (
<div>
<h2 className="text-xl font-bold mb-4">Medien</h2>
{/* Ansicht-Umschalter */}
<div style={{ marginBottom: 12 }}>
<button
className={viewMode === 'LargeIcons' ? 'e-btn e-active' : 'e-btn'}
onClick={() => setViewMode('LargeIcons')}
style={{ marginRight: 8 }}
>
Icons
</button>
<button
className={viewMode === 'Details' ? 'e-btn e-active' : 'e-btn'}
onClick={() => setViewMode('Details')}
>
Details
</button>
</div>
<FileManagerComponent
ajaxSettings={{
url: hostUrl + 'operations',
@@ -71,18 +81,29 @@ const Media: React.FC = () => {
layout: ['SortBy', 'Refresh', '|', 'View', 'Details'],
}}
allowMultiSelection={false}
view={viewMode}
detailsViewSettings={{
columns: [
{ field: 'name', headerText: 'Name', minWidth: '120', width: '200' },
{ field: 'size', headerText: 'Größe', minWidth: '80', width: '100' },
{
field: 'dateModified',
headerText: 'Upload-Datum',
minWidth: '120',
width: '180',
template: (data: { dateModified: number }) => formatLocalDate(data.dateModified),
},
{ field: 'type', headerText: 'Typ', minWidth: '80', width: '100' },
],
}}
menuClick={(args: any) => {
console.log('FileManager popupOpen:', args);
}}
>
<Inject services={[NavigationPane, DetailsView, Toolbar]} />
</FileManagerComponent>
{selectedMedia && (
<CustomMediaInfoPanel
mediaId={selectedMedia.id}
title={selectedMedia.url}
description={selectedMedia.description}
eventId={selectedMedia.eventId}
onSave={handleSave}
/>
)}
{/* Details-Panel anzeigen, wenn Details verfügbar sind */}
{fileDetails && <CustomMediaInfoPanel {...fileDetails} />}
</div>
);
};