197 lines
5.9 KiB
TypeScript
197 lines
5.9 KiB
TypeScript
/**
|
||
* TrusteeRolesView
|
||
*
|
||
* Rollen-Verwaltung für eine Trustee-Instanz.
|
||
* Rollen definieren Berechtigungen (admin, operate, userreport).
|
||
* Hinweis: Nur SysAdmin kann Rollen verwalten.
|
||
*/
|
||
|
||
import React, { useState, useMemo } from 'react';
|
||
import { useTrusteeRoles, useTrusteeRoleOperations, TrusteeRole } from '../../../hooks/useTrustee';
|
||
import { useTablePermission } from '../../../hooks/useInstancePermissions';
|
||
import { Popup } from '../../../components/UiComponents/Popup/Popup';
|
||
import { TrusteeEditForm, FieldConfig } from './components';
|
||
import styles from './TrusteeViews.module.css';
|
||
|
||
export const TrusteeRolesView: React.FC = () => {
|
||
const { items: roles, loading, error, refetch } = useTrusteeRoles();
|
||
const { handleDelete, handleCreate, handleUpdate, deletingItems, creatingItem } = useTrusteeRoleOperations();
|
||
const { canCreate, canUpdate, canDelete } = useTablePermission('TrusteeRole');
|
||
|
||
// Modal State
|
||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||
const [editingRole, setEditingRole] = useState<TrusteeRole | null>(null);
|
||
const [formError, setFormError] = useState<string | null>(null);
|
||
|
||
// Feld-Konfiguration für das Formular
|
||
const fields: FieldConfig[] = useMemo(() => [
|
||
{
|
||
key: 'id',
|
||
label: 'Rollen-ID',
|
||
type: 'string',
|
||
required: true,
|
||
editable: !editingRole, // Nur bei Create editierbar
|
||
placeholder: 'z.B. admin, operate, userreport',
|
||
helpText: 'Eindeutige Rollen-ID (nicht änderbar nach Erstellung)',
|
||
},
|
||
{
|
||
key: 'desc',
|
||
label: 'Beschreibung',
|
||
type: 'textarea',
|
||
required: true,
|
||
placeholder: 'Beschreibung der Rolle und ihrer Berechtigungen',
|
||
},
|
||
], [editingRole]);
|
||
|
||
if (loading) {
|
||
return <div className={styles.loading}>Lade Rollen...</div>;
|
||
}
|
||
|
||
if (error) {
|
||
return <div className={styles.error}>Fehler: {error}</div>;
|
||
}
|
||
|
||
const onDelete = async (roleId: string) => {
|
||
if (window.confirm('Rolle wirklich löschen? Dies ist nur möglich, wenn die Rolle nicht in Verwendung ist.')) {
|
||
const success = await handleDelete(roleId);
|
||
if (success) {
|
||
refetch();
|
||
}
|
||
}
|
||
};
|
||
|
||
const onEdit = (role: TrusteeRole) => {
|
||
setEditingRole(role);
|
||
setFormError(null);
|
||
setIsModalOpen(true);
|
||
};
|
||
|
||
const onCreate = () => {
|
||
setEditingRole(null);
|
||
setFormError(null);
|
||
setIsModalOpen(true);
|
||
};
|
||
|
||
const onCloseModal = () => {
|
||
setIsModalOpen(false);
|
||
setEditingRole(null);
|
||
setFormError(null);
|
||
};
|
||
|
||
const onSave = async (data: Partial<TrusteeRole>) => {
|
||
setFormError(null);
|
||
|
||
try {
|
||
if (editingRole) {
|
||
const result = await handleUpdate(editingRole.id, data);
|
||
if (!result.success) {
|
||
setFormError(result.error || 'Fehler beim Aktualisieren');
|
||
return;
|
||
}
|
||
} else {
|
||
const result = await handleCreate(data);
|
||
if (!result.success) {
|
||
setFormError(result.error || 'Fehler beim Erstellen');
|
||
return;
|
||
}
|
||
}
|
||
|
||
onCloseModal();
|
||
refetch();
|
||
} catch (err: any) {
|
||
setFormError(err.message || 'Ein Fehler ist aufgetreten');
|
||
}
|
||
};
|
||
|
||
return (
|
||
<div className={styles.listView}>
|
||
{/* Toolbar */}
|
||
<div className={styles.toolbar}>
|
||
{canCreate && (
|
||
<button className={styles.primaryButton} onClick={onCreate}>
|
||
+ Neue Rolle
|
||
</button>
|
||
)}
|
||
<button className={styles.secondaryButton} onClick={() => refetch()}>
|
||
Aktualisieren
|
||
</button>
|
||
</div>
|
||
|
||
{/* Info */}
|
||
<div className={styles.muted} style={{ fontSize: '0.8125rem', padding: '0.5rem 0' }}>
|
||
Rollen definieren Berechtigungen für Trustee-Zugriffe. Standard-Rollen: admin, operate, userreport.
|
||
</div>
|
||
|
||
{/* Tabelle */}
|
||
{roles.length === 0 ? (
|
||
<div className={styles.emptyState}>
|
||
<p>Keine Rollen vorhanden.</p>
|
||
</div>
|
||
) : (
|
||
<table className={styles.dataTable}>
|
||
<thead>
|
||
<tr>
|
||
<th>ID</th>
|
||
<th>Beschreibung</th>
|
||
<th>Aktionen</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{roles.map((role) => (
|
||
<tr key={role.id}>
|
||
<td className={styles.monospace}>{role.id}</td>
|
||
<td>{role.desc}</td>
|
||
<td className={styles.actions}>
|
||
{canUpdate && (
|
||
<button
|
||
className={styles.iconButton}
|
||
title="Bearbeiten"
|
||
onClick={() => onEdit(role)}
|
||
>
|
||
✏️
|
||
</button>
|
||
)}
|
||
{canDelete && (
|
||
<button
|
||
className={styles.iconButton}
|
||
title="Löschen"
|
||
onClick={() => onDelete(role.id)}
|
||
disabled={deletingItems.has(role.id)}
|
||
>
|
||
{deletingItems.has(role.id) ? '...' : '🗑️'}
|
||
</button>
|
||
)}
|
||
</td>
|
||
</tr>
|
||
))}
|
||
</tbody>
|
||
</table>
|
||
)}
|
||
|
||
{/* Create/Edit Modal */}
|
||
<Popup
|
||
isOpen={isModalOpen}
|
||
title={editingRole ? 'Rolle bearbeiten' : 'Neue Rolle'}
|
||
onClose={onCloseModal}
|
||
size="medium"
|
||
>
|
||
{formError && (
|
||
<div className={styles.formError} style={{ marginBottom: '1rem' }}>
|
||
{formError}
|
||
</div>
|
||
)}
|
||
<TrusteeEditForm<TrusteeRole>
|
||
initialData={editingRole || {}}
|
||
fields={fields}
|
||
onSave={onSave}
|
||
onCancel={onCloseModal}
|
||
isSaving={creatingItem}
|
||
isEdit={!!editingRole}
|
||
saveLabel={editingRole ? 'Aktualisieren' : 'Erstellen'}
|
||
/>
|
||
</Popup>
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default TrusteeRolesView;
|