feat: Filter und Paginierung für den Werkzeugkatalog, Claude Code als Katalogeintrag
Beide Katalog-Ansichten (Betreiber + Mandant) haben jetzt eine Filterleiste (Freitext über Name/Anbieter/Verarbeitungsländer, Zweck-Dropdown) und serverseitige Paginierung (20/Seite) über ein GET-Formular, kein JavaScript. pagination.go ist generisch gehalten (Go-Generics) für Wiederverwendung in weiteren Listen. Claude Code als eigener Katalogeintrag ergänzt (nicht identisch mit Claude for Work: läuft lokal, hat Dateizugriff, lokale Sitzungs- protokolle mit eigenem Aufbewahrungsrisiko).
This commit is contained in:
@@ -14,6 +14,51 @@ import (
|
||||
"github.com/netcell-it/deklarix/internal/store"
|
||||
)
|
||||
|
||||
// werkzeugFilter bündelt die Filterkriterien für die Katalog-Listen
|
||||
// (Betreiber wie Mandant) — ein einziges GET-Formular setzt "q"
|
||||
// (Freitext über Name/Anbieter/Länder) und optional "zweck".
|
||||
type werkzeugFilter struct {
|
||||
Suche string
|
||||
Zweck string
|
||||
}
|
||||
|
||||
func werkzeugFilterFromRequest(r *http.Request) werkzeugFilter {
|
||||
return werkzeugFilter{
|
||||
Suche: strings.TrimSpace(r.URL.Query().Get("q")),
|
||||
Zweck: r.URL.Query().Get("zweck"),
|
||||
}
|
||||
}
|
||||
|
||||
// Aktiv meldet, ob mindestens ein Filter gesetzt ist — steuert, ob ein
|
||||
// "Zurücksetzen"-Link angezeigt wird. Exportiert, weil html/template
|
||||
// nur exportierte Methoden per Reflection aufrufen kann.
|
||||
func (f werkzeugFilter) Aktiv() bool {
|
||||
return f.Suche != "" || f.Zweck != ""
|
||||
}
|
||||
|
||||
func (f werkzeugFilter) matches(wz store.Werkzeug) bool {
|
||||
if f.Zweck != "" {
|
||||
gefunden := false
|
||||
for _, z := range wz.GeeigneteZwecke {
|
||||
if z == f.Zweck {
|
||||
gefunden = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !gefunden {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if f.Suche != "" {
|
||||
q := strings.ToLower(f.Suche)
|
||||
heuhaufen := strings.ToLower(wz.Name + " " + wz.Anbieter + " " + strings.Join(wz.Verarbeitungslaender, " "))
|
||||
if !strings.Contains(heuhaufen, q) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// istGueltigesLand validiert gegen weltLaenderliste (laenderliste.go)
|
||||
// — dieselbe kontrollierte-Vokabular-Logik wie bei istGueltigerZweck,
|
||||
// nur für Verarbeitungsländer statt Zwecke.
|
||||
@@ -92,9 +137,12 @@ func formatAufbewahrung(tage *int) string {
|
||||
}
|
||||
|
||||
type werkzeugListeData struct {
|
||||
Title string
|
||||
Nav navData
|
||||
Werkzeuge []werkzeugListItem
|
||||
Title string
|
||||
Nav navData
|
||||
Werkzeuge []werkzeugListItem
|
||||
Filter werkzeugFilter
|
||||
ZweckeOptionen []string
|
||||
Pagination pagination
|
||||
}
|
||||
|
||||
// werkzeugPruefungVeraltetNach ist die Schwelle, ab der ein
|
||||
@@ -132,8 +180,21 @@ func (s *Server) handleBetreiberWerkzeugListe(w http.ResponseWriter, r *http.Req
|
||||
http.Error(w, "Werkzeugkatalog konnte nicht geladen werden: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
data := werkzeugListeData{Title: "Werkzeugkatalog", Nav: navFor(r)}
|
||||
filter := werkzeugFilterFromRequest(r)
|
||||
var gefiltert []store.Werkzeug
|
||||
for _, wz := range werkzeuge {
|
||||
if filter.matches(wz) {
|
||||
gefiltert = append(gefiltert, wz)
|
||||
}
|
||||
}
|
||||
pag := paginationFromRequest(r, len(gefiltert))
|
||||
seite := paginate(gefiltert, pag)
|
||||
|
||||
data := werkzeugListeData{
|
||||
Title: "Werkzeugkatalog", Nav: navFor(r),
|
||||
Filter: filter, ZweckeOptionen: gueltigeZwecke, Pagination: pag,
|
||||
}
|
||||
for _, wz := range seite {
|
||||
label, css := pruefStatus(wz.LetztePruefung)
|
||||
data.Werkzeuge = append(data.Werkzeuge, werkzeugListItem{
|
||||
ID: wz.ID, Name: wz.Name, Anbieter: wz.Anbieter, Verarbeitungslaender: strings.Join(wz.Verarbeitungslaender, ", "),
|
||||
|
||||
Reference in New Issue
Block a user