Security & UX Release v7
Security: - H1: Stored-XSS-Fix — Upload-Pfad-Whitelist (Server + Frontend-Guard safeFileUrl) - H2: Transaktionen repariert — txDb-Contract in db.js (PG + SQLite), Rollback funktioniert - H3-Vorbereitung: SESSION_SECRET wird in Compose durchgereicht (Fix M3) - registerLimiter exportiert (Crash-Bug: Route.post ohne Callback) - LDAP-Sync: PG-Transaktionsabbruch bei UNIQUE-Verstoß behoben (Precheck-Selects) - LDAP-Filter: nur echte Benutzerkonten (keine Computer/Service-Accounts, Bit 512) - Rollen app-seitig: Sync ändert nie role/status, neue User immer user+inaktiv - DB-Cleanup: 82 Computer-/Service-Accounts aus lokaler User-Tabelle entfernt UX: - Dashboard: Vorlagen als Table-Liste + Column-Chart (Top 5 in %), 2 gleich große Spalten - Table-Listen (Dashboard/Vorlageneditor/Aufgaben) scrollbar bis Seitenende - Pagination 10/Seite im Dashboard, Sidebar-Label Dashboard
This commit is contained in:
@@ -2,7 +2,7 @@ import React, { useState, useEffect, useCallback } from 'react';
|
||||
import { useAuth } from '../context/AuthContext';
|
||||
import { useToast, ConfirmModal } from '../components/Toast';
|
||||
import TaskModal from '../components/TaskModal';
|
||||
import { apiFetch, FILE_BASE } from '../utils/api';
|
||||
import { apiFetch, safeFileUrl } from '../utils/api';
|
||||
|
||||
export default function TasksPage() {
|
||||
const { user } = useAuth();
|
||||
@@ -107,7 +107,7 @@ export default function TasksPage() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="p-4 md:p-6">
|
||||
<div className="p-4 md:p-6 h-full flex flex-col min-h-0">
|
||||
<div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4 mb-6">
|
||||
<h2 className="text-2xl font-bold">Aufgaben</h2>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
@@ -146,9 +146,11 @@ export default function TasksPage() {
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="card bg-base-200 shadow-sm rounded-xl overflow-hidden">
|
||||
<div className="divide-y divide-base-300">
|
||||
{filtered.map((task) => (
|
||||
<>
|
||||
{/* Scrollbare Table-Liste — füllt die restliche Seitenhöhe */}
|
||||
<div className="card bg-base-200 shadow-sm rounded-xl overflow-hidden flex-1 min-h-0 flex flex-col">
|
||||
<div className="divide-y divide-base-300 flex-1 min-h-0 overflow-y-auto">
|
||||
{filtered.map((task) => (
|
||||
<div
|
||||
key={task.id}
|
||||
className="p-4 sm:p-5 hover:bg-base-300/40 transition-colors cursor-pointer"
|
||||
@@ -168,11 +170,11 @@ export default function TasksPage() {
|
||||
<span className="text-sm opacity-70">{task.template_name}</span>
|
||||
)}
|
||||
</div>
|
||||
{/* File attachments in row */}
|
||||
{task.file_path && (
|
||||
{/* File attachments in row — H1: nur validierte Upload-Pfade als Link */}
|
||||
{safeFileUrl(task.file_path) && (
|
||||
<div className="mt-2">
|
||||
<a
|
||||
href={`${FILE_BASE}${task.file_path}`}
|
||||
href={safeFileUrl(task.file_path)}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="inline-flex items-center gap-1 text-sm text-primary hover:underline"
|
||||
@@ -183,13 +185,13 @@ export default function TasksPage() {
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
{/* File attachments from task values */}
|
||||
{task.values?.filter(v => v.step_type === 'file_upload' && v.value).length > 0 && (
|
||||
{/* File attachments from task values — H1: nur validierte Upload-Pfade als Link */}
|
||||
{task.values?.filter(v => v.step_type === 'file_upload' && safeFileUrl(v.value)).length > 0 && (
|
||||
<div className="mt-2 flex flex-wrap gap-2">
|
||||
{task.values.filter(v => v.step_type === 'file_upload' && v.value).map(v => (
|
||||
{task.values.filter(v => v.step_type === 'file_upload' && safeFileUrl(v.value)).map(v => (
|
||||
<a
|
||||
key={v.id}
|
||||
href={`${FILE_BASE}${v.value}`}
|
||||
href={safeFileUrl(v.value)}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="inline-flex items-center gap-1 text-sm text-primary hover:underline"
|
||||
@@ -223,8 +225,9 @@ export default function TasksPage() {
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{selectedTask && (
|
||||
|
||||
Reference in New Issue
Block a user