Skip to content

Feat #199: Kurs-Filter (Course Filters API) – dynamische Chip-Leiste + Admin-Verwaltung - #229

Merged
Gree44 merged 1 commit into
stagingfrom
feat/199-course-filters
Jul 25, 2026
Merged

Feat #199: Kurs-Filter (Course Filters API) – dynamische Chip-Leiste + Admin-Verwaltung#229
Gree44 merged 1 commit into
stagingfrom
feat/199-course-filters

Conversation

@Gree44

@Gree44 Gree44 commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Closes #199

Was gebaut wurde

Frontend für die Backend Course Filters API (/api/v1/course-filters, live auf staging). Admin-verwaltete Filter-Strings werden als Chip-Leiste über der Kursliste angezeigt; das Filtern selbst läuft client-seitig.

  • Neues API-Modul src/api/courseFilters.ts (modelliert nach courses.ts / http.ts):
    • listCourseFilters() → GET, entpackt .data, page_size=100 (holt alles in einem Rutsch)
    • createCourseFilter(name) → POST {name} ausschließlich (striktes extra="forbid"-Schema — nie id/color/…)
    • updateCourseFilter(id, name) → PATCH {name}
    • deleteCourseFilter(id) → DELETE
    • ApiError-Status (409/422/403/404) wird an die UI durchgereicht
  • src/pages/Courses.tsx: hartkodierte Präfix-Liste (["WWI","WI","INF","WIN"]) durch dynamisch geladene Chips ersetzt (Mount-Fetch mit loading/empty/error-States). Chip-Leiste über der Kursliste; aktive Chips teal-gefüllt, "Alle anzeigen"-Reset.
  • Admin-CRUD (gate auf isAdmin aus useCurrentUser): Inline-Add (Input + Hinzufügen), Umbenennen (Stift-Icon / Doppelklick, inline), Löschen (X-Icon). Nicht-Admins sehen read-only Chips (GET ist für alle offen). 409 → "…already exists", 422 → Validierungshinweis. Nach jeder Mutation Refetch. Toasts via sonner.

Matching-Änderung (before/after)

  • Vorher: case-SENSITIVES startsWith gegen hartkodierte Präfixe:
    (c.keycloakGroupName || c.name).toUpperCase().startsWith(q)
  • Nachher: case-INSENSITIVES Substring, OR über aktive Chips:
    terms.some(t => [keycloakGroupName, name].some(h => h.toLowerCase().includes(t.toLowerCase())))

Admin-Gating

useCurrentUser().isAdmin (realm-role admin) blendet Add-Input, Stift- und Löschen-Icons ein. Lecturer/andere sehen nur klickbare Read-only-Chips. Schreib-Endpoints sind zusätzlich backendseitig Admin-only (403 wird als Toast abgefangen).

Verifikation

  • Visuell mit Playwright verifiziert (Stubs admin.json + lecturer.json, gemockte course-filters/courses/openstack-projects):
    • Admin: Chip-Leiste + Add-Input + Stift/Löschen pro Chip, Toggle filtert korrekt (SQL-Chip → nur "SQL Grundlagen")
    • Lecturer: identische Chips, keine Verwaltungs-Controls (read-only)
  • npm run build grün.

Backend-Contract

Gegen appstore-backend (staging) geprüft: src/api/course_filters.py + src/schemas/course_filter.py — Routen, Methoden, striktes {name}-Schema und Fehlercodes stimmen mit dem Briefing überein. Keine Abweichung gefunden.

…+ Admin-Verwaltung

Ersetzt die hartkodierte Präfix-Liste auf der Kurse-Seite durch die
Admin-verwalteten Kurs-Filter aus dem Backend (/api/v1/course-filters).

- Neues API-Modul src/api/courseFilters.ts (modelliert nach courses.ts):
  listCourseFilters (GET, entpackt .data, page_size=100), createCourseFilter
  (POST {name} strikt), updateCourseFilter (PATCH {name}), deleteCourseFilter
  (DELETE). ApiError-Codes (409/422/403/404) werden an die UI durchgereicht.
- Courses.tsx: Chip-Leiste über der Kursliste, geladen via listCourseFilters
  (einmal beim Mount, mit loading/empty/error-States). Matching von
  case-sensitivem startsWith auf case-INSENSITIVES includes umgestellt
  (Substring auf keycloakGroupName + name), OR-Semantik über aktive Chips.
- Admin-only Verwaltung (gate auf isAdmin): Inline-Add (Input + Hinzufügen),
  Umbenennen (Stift / Doppelklick, inline), Löschen (X-Icon). Nicht-Admins
  sehen read-only Chips. 409 zeigt "…already exists", 422 Validierungshinweis;
  nach jeder Mutation Refetch der Liste. Toasts via sonner.

Visuell verifiziert (Playwright, admin.json + lecturer.json Stubs).
Build grün.
@RamonaKT
RamonaKT self-requested a review July 24, 2026 21:45
@Gree44
Gree44 merged commit a487e33 into staging Jul 25, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants