feat: 7 Vorbereitungs-Module auf 100% — Frontend, Proxy-Routen, Backend-Fixes
All checks were successful
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-ai-compliance (push) Successful in 35s
CI / test-python-backend-compliance (push) Successful in 30s
CI / test-python-document-crawler (push) Successful in 22s
CI / test-python-dsms-gateway (push) Successful in 19s
All checks were successful
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-ai-compliance (push) Successful in 35s
CI / test-python-backend-compliance (push) Successful in 30s
CI / test-python-document-crawler (push) Successful in 22s
CI / test-python-dsms-gateway (push) Successful in 19s
Profil: machineBuilder-Felder im POST-Body, PATCH-Handler Scope: API-Route (GET/POST), ScopeDecisionTab Props + Buttons, Export-Druckansicht HTML Anwendung: PUT-Handler, Bearbeiten-Button, Pagination/Search Import: Verlauf laden, DELETE-Route, Offline-Badge, ObjectURL Memory-Leak fix Screening: Security-Backlog Button verdrahtet, Scan-Verlauf Module: Detail-Seite, GET-Proxy, Konfigurieren-Button, Modul-erstellen-Modal, Error-Toast Quellen: 10 Proxy-Routen, Tab-Komponenten umgestellt, Dashboard-Tab, blocked_today Bug fix, Datum-Filter Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -140,6 +140,12 @@ export default function AssessmentDetailPage() {
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Link
|
||||
href={`/sdk/use-cases/new?edit=${assessmentId}`}
|
||||
className="px-4 py-2 text-sm bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition-colors"
|
||||
>
|
||||
Bearbeiten
|
||||
</Link>
|
||||
<button
|
||||
onClick={handleDelete}
|
||||
className="px-4 py-2 text-sm text-red-600 hover:bg-red-50 rounded-lg transition-colors"
|
||||
|
||||
@@ -26,20 +26,31 @@ export default function UseCasesPage() {
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
const [filterFeasibility, setFilterFeasibility] = useState<string>('all')
|
||||
const [filterRisk, setFilterRisk] = useState<string>('all')
|
||||
const [searchQuery, setSearchQuery] = useState('')
|
||||
const [page, setPage] = useState(0)
|
||||
const [totalCount, setTotalCount] = useState(0)
|
||||
const PAGE_SIZE = 20
|
||||
|
||||
useEffect(() => {
|
||||
fetchAssessments()
|
||||
}, [])
|
||||
}, [page, searchQuery])
|
||||
|
||||
async function fetchAssessments() {
|
||||
try {
|
||||
setLoading(true)
|
||||
const response = await fetch('/api/sdk/v1/ucca/assessments')
|
||||
const params = new URLSearchParams({
|
||||
limit: String(PAGE_SIZE),
|
||||
offset: String(page * PAGE_SIZE),
|
||||
})
|
||||
if (searchQuery) params.set('search', searchQuery)
|
||||
|
||||
const response = await fetch(`/api/sdk/v1/ucca/assessments?${params}`)
|
||||
if (!response.ok) {
|
||||
throw new Error('Fehler beim Laden der Assessments')
|
||||
}
|
||||
const data = await response.json()
|
||||
setAssessments(data.assessments || [])
|
||||
setTotalCount(data.total || data.assessments?.length || 0)
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Unbekannter Fehler')
|
||||
} finally {
|
||||
@@ -101,6 +112,20 @@ export default function UseCasesPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Search */}
|
||||
<div className="relative">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Assessments durchsuchen..."
|
||||
value={searchQuery}
|
||||
onChange={e => { setSearchQuery(e.target.value); setPage(0) }}
|
||||
className="w-full px-4 py-2 pl-10 bg-white border border-gray-200 rounded-lg text-sm focus:ring-2 focus:ring-purple-500 focus:border-purple-500"
|
||||
/>
|
||||
<svg className="absolute left-3 top-2.5 w-4 h-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
{/* Filters */}
|
||||
<div className="flex items-center gap-4 flex-wrap">
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -185,6 +210,31 @@ export default function UseCasesPage() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Pagination */}
|
||||
{!loading && totalCount > PAGE_SIZE && (
|
||||
<div className="flex items-center justify-between">
|
||||
<p className="text-sm text-gray-500">
|
||||
{page * PAGE_SIZE + 1}–{Math.min((page + 1) * PAGE_SIZE, totalCount)} von {totalCount}
|
||||
</p>
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
onClick={() => setPage(p => Math.max(0, p - 1))}
|
||||
disabled={page === 0}
|
||||
className="px-3 py-1 text-sm bg-gray-100 rounded-lg hover:bg-gray-200 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
Zurueck
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setPage(p => p + 1)}
|
||||
disabled={(page + 1) * PAGE_SIZE >= totalCount}
|
||||
className="px-3 py-1 text-sm bg-gray-100 rounded-lg hover:bg-gray-200 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
Weiter
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Empty State */}
|
||||
{!loading && filtered.length === 0 && !error && (
|
||||
<div className="bg-white rounded-xl border border-gray-200 p-12 text-center">
|
||||
|
||||
Reference in New Issue
Block a user