Polish up clients ui

This commit is contained in:
RobbStarkAustria
2025-10-12 05:23:10 +00:00
parent 4d807be6f8
commit 7ab4ea14c4
7 changed files with 131 additions and 144 deletions

View File

@@ -1,5 +1,9 @@
# Copilot instructions for infoscreen_2025
# Purpose
These instructions tell Copilot Chat how to reason about this codebase.
Prefer explanations and refactors that align with these structures.
Use this as your shared context when proposing changes. Keep edits minimal and match existing patterns referenced below.
## Big picture

View File

@@ -387,7 +387,7 @@ const Appointments: React.FC = () => {
return (
<div>
<h1 className="text-2xl font-bold mb-4">Terminmanagement</h1>
<h1 style={{ fontSize: '1.5rem', fontWeight: 700, marginBottom: 16 }}>Terminmanagement</h1>
<div
style={{
marginBottom: 16,

View File

@@ -15,43 +15,15 @@ import {
Edit,
} from '@syncfusion/ej2-react-grids';
import { DialogComponent } from '@syncfusion/ej2-react-popups';
import { ButtonComponent } from '@syncfusion/ej2-react-buttons';
// Raumgruppen werden dynamisch aus der API geladen
interface DetailsModalProps {
open: boolean;
client: Client | null;
groupIdToName: Record<string | number, string>;
onClose: () => void;
}
function DetailsModal({ open, client, groupIdToName, onClose }: DetailsModalProps) {
if (!open || !client) return null;
// Details dialog renders via Syncfusion Dialog for consistent look & feel
function DetailsContent({ client, groupIdToName }: { client: Client; groupIdToName: Record<string | number, string> }) {
return (
<div
style={{
position: 'fixed',
top: 0,
left: 0,
right: 0,
bottom: 0,
background: 'rgba(0,0,0,0.3)',
zIndex: 1000,
}}
>
<div
style={{
background: 'white',
padding: 0,
margin: '100px auto',
maxWidth: 500,
borderRadius: 12,
boxShadow: '0 4px 24px rgba(0,0,0,0.12)',
}}
>
<div style={{ padding: 32 }}>
<h3 style={{ fontSize: '1.25rem', fontWeight: 700, marginBottom: 18 }}>Client-Details</h3>
<table style={{ width: '100%', borderCollapse: 'collapse', marginBottom: 24 }}>
<div className="e-card-content">
<table style={{ width: '100%', borderCollapse: 'collapse' }}>
<tbody>
{Object.entries(client)
.filter(
@@ -68,7 +40,7 @@ function DetailsModal({ open, client, groupIdToName, onClose }: DetailsModalProp
)
.map(([key, value]) => (
<tr key={key}>
<td style={{ fontWeight: 'bold', padding: '6px 8px' }}>
<td style={{ fontWeight: 600, padding: '6px 8px', width: '40%' }}>
{key === 'group_id'
? 'Raumgruppe'
: key === 'ip'
@@ -83,39 +55,33 @@ function DetailsModal({ open, client, groupIdToName, onClose }: DetailsModalProp
? 'Modell'
: key === 'uuid'
? 'Client-Code'
: key === "os_version"
: key === 'os_version'
? 'Betriebssystem'
: key === 'software_version'
? 'Clientsoftware'
: key === 'macs'
? 'MAC-Adressen'
: key.charAt(0).toUpperCase() + key.slice(1)}
:
</td>
<td style={{ padding: '6px 8px' }}>
{key === 'group_id'
? value !== undefined
? groupIdToName[value as string | number] || value
? groupIdToName[value as string | number] || String(value)
: ''
: key === 'registration_time' && value
? new Date(
(value as string).endsWith('Z') ? (value as string) : value + 'Z'
(value as string).endsWith('Z') ? (value as string) : String(value) + 'Z'
).toLocaleString()
: key === 'last_alive' && value
? String(value) // Wert direkt anzeigen, nicht erneut parsen
? String(value)
: key === 'macs' && typeof value === 'string'
? value.replace(/,\s*/g, ', ')
: String(value)}
</td>
</tr>
))}
</tbody>
</table>
<div style={{ textAlign: 'right' }}>
<button className="e-btn e-outline" onClick={onClose}>
Schließen
</button>
</div>
</div>
</div>
</div>
);
}
@@ -154,31 +120,38 @@ const Clients: React.FC = () => {
// DataGrid row template für Details- und Entfernen-Button
const detailsButtonTemplate = (props: Client) => (
<div style={{ display: 'flex', gap: '8px' }}>
<button
className="e-btn e-primary"
onClick={() => setDetailsClient(props)}
style={{ minWidth: 80 }}
>
<div style={{ display: 'flex', gap: 8, justifyContent: 'center' }}>
<ButtonComponent cssClass="e-primary" onClick={() => setDetailsClient(props)}>
Details
</button>
<button
className="e-btn e-danger"
</ButtonComponent>
<ButtonComponent
cssClass="e-danger"
onClick={e => {
e.preventDefault();
e.stopPropagation();
handleDelete(props.uuid);
}}
style={{ minWidth: 80 }}
>
Entfernen
</button>
</ButtonComponent>
</div>
);
return (
<div>
<div className="flex justify-between items-center mb-4">
<h2 className="text-xl font-bold">Client-Übersicht</h2>
<div id="dialog-target">
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
marginBottom: 16,
gap: 12,
flexWrap: 'wrap',
}}
>
<h2 style={{ margin: 0, fontSize: '1.25rem', fontWeight: 700 }}>
Client-Übersicht
</h2>
<SetupModeButton />
</div>
{groups.length > 0 ? (
@@ -190,7 +163,7 @@ const Clients: React.FC = () => {
toolbar={['Search', 'Edit', 'Update', 'Cancel']}
allowSorting={true}
allowFiltering={true}
height={400}
height={420}
editSettings={{
allowEditing: true,
allowAdding: false,
@@ -228,17 +201,17 @@ const Clients: React.FC = () => {
width="140"
/>
<ColumnDirective field="uuid" headerText="UUID" allowEditing={false} width="160" />
<ColumnDirective field="ip" headerText="IP-Adresse" allowEditing={false} width="80" />
<ColumnDirective field="ip" headerText="IP-Adresse" allowEditing={false} width="100" />
<ColumnDirective
field="last_alive"
headerText="Last Alive"
allowEditing={false}
width="120"
width="150"
/>
<ColumnDirective field="model" headerText="Model" allowEditing={true} width="120" />
<ColumnDirective field="model" headerText="Model" allowEditing={true} width="140" />
<ColumnDirective
headerText="Aktion"
width="190"
width="210"
template={detailsButtonTemplate}
textAlign="Center"
allowEditing={false}
@@ -246,17 +219,31 @@ const Clients: React.FC = () => {
</ColumnsDirective>
<Inject services={[Page, Toolbar, Search, Sort, Edit]} />
</GridComponent>
<DetailsModal
open={!!detailsClient}
client={detailsClient}
groupIdToName={groupIdToName}
onClose={() => setDetailsClient(null)}
/>
</>
) : (
<div className="text-gray-500">Raumgruppen werden geladen ...</div>
<span style={{ color: '#6b7280' }}>Raumgruppen werden geladen ...</span>
)}
{/* DialogComponent für Bestätigung */}
{/* Details-Dialog */}
{detailsClient && (
<DialogComponent
visible={!!detailsClient}
header="Client-Details"
showCloseIcon={true}
target="#dialog-target"
width="560px"
close={() => setDetailsClient(null)}
footerTemplate={() => (
<div style={{ display: 'flex', justifyContent: 'flex-end', gap: 8 }}>
<ButtonComponent onClick={() => setDetailsClient(null)}>{'Schließen'}</ButtonComponent>
</div>
)}
>
<DetailsContent client={detailsClient} groupIdToName={groupIdToName} />
</DialogComponent>
)}
{/* Bestätigungs-Dialog für Löschen */}
{showDialog && deleteClientId && (
<DialogComponent
visible={showDialog}
@@ -264,6 +251,7 @@ const Clients: React.FC = () => {
content="Möchten Sie diesen Client wirklich entfernen?"
showCloseIcon={true}
width="400px"
target="#dialog-target"
buttons={[
{ click: confirmDelete, buttonModel: { content: 'Ja', isPrimary: true } },
{ click: cancelDelete, buttonModel: { content: 'Abbrechen' } },

View File

@@ -1,18 +1,21 @@
import React from 'react';
import { useNavigate } from 'react-router-dom';
import { Wrench } from 'lucide-react';
import { ButtonComponent } from '@syncfusion/ej2-react-buttons';
const SetupModeButton: React.FC = () => {
const navigate = useNavigate();
return (
<button
className="setupmode-btn flex items-center gap-2 px-4 py-2 bg-yellow-200 hover:bg-yellow-300 rounded"
<ButtonComponent
cssClass="e-warning"
onClick={() => navigate('/setup')}
title="Erweiterungsmodus starten"
>
<Wrench size={18} />
<span style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
<Wrench size={14.4} />
Erweiterungsmodus
</button>
</span>
</ButtonComponent>
);
};

View File

@@ -171,10 +171,12 @@ const Dashboard: React.FC = () => {
return (
<div>
<header className="mb-8 pb-4 border-b-2 border-[#d6c3a6]">
<h2 className="text-3xl font-extrabold mb-2">Dashboard</h2>
<header style={{ marginBottom: 32, paddingBottom: 16, borderBottom: '2px solid #d6c3a6' }}>
<h2 style={{ fontSize: '1.75rem', fontWeight: 800, margin: 0, marginBottom: 8 }}>Dashboard</h2>
</header>
<h3 className="text-lg font-semibold mt-6 mb-4">Raumgruppen Übersicht</h3>
<h3 style={{ fontSize: '1.125rem', fontWeight: 600, marginTop: 24, marginBottom: 16 }}>
Raumgruppen Übersicht
</h3>
<GridComponent
dataSource={groups}
allowPaging={true}

View File

@@ -335,7 +335,7 @@ const Infoscreen_groups: React.FC = () => {
return (
<div id="dialog-target">
<h2 className="text-xl font-bold mb-4">{de.title}</h2>
<h2 style={{ fontSize: '1.25rem', fontWeight: 700, marginBottom: 16 }}>{de.title}</h2>
<div
style={{
display: 'flex',

View File

@@ -1,10 +0,0 @@
module.exports = {
content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
corePlugins: {
preflight: false,
},
theme: {
extend: {},
},
plugins: [],
};