diff --git a/backend/version.py b/backend/version.py index be158f1..5cda9fe 100644 --- a/backend/version.py +++ b/backend/version.py @@ -1,6 +1,6 @@ # Shinkan Jinkendo Version Information -APP_VERSION = "0.8.119" +APP_VERSION = "0.8.121" BUILD_DATE = "2026-05-12" DB_SCHEMA_VERSION = "20260514062" @@ -36,6 +36,20 @@ MODULE_VERSIONS = { } CHANGELOG = [ + { + "version": "0.8.121", + "date": "2026-05-13", + "changes": [ + "Frontend Phase 3 (Teil): Übungsliste — Suchleiste/Chips in ExerciseListSearchBar; API-Query-Bau und Filter-Chips in utils/exerciseListQuery.js bzw. exerciseListFilterChips.js.", + ], + }, + { + "version": "0.8.120", + "date": "2026-05-13", + "changes": [ + "Frontend: Übungsliste — Filter- und Massenänderungs-Dialoge in ExerciseListFilterModal / ExerciseListBulkModal ausgelagert; Playwright-Test 10 (Filter-Dialog).", + ], + }, { "version": "0.8.119", "date": "2026-05-13", diff --git a/docs/HANDOVER.md b/docs/HANDOVER.md index 7879f36..e52a4ef 100644 --- a/docs/HANDOVER.md +++ b/docs/HANDOVER.md @@ -1,7 +1,7 @@ # Shinkan Jinkendo – Entwicklungsstand & Handover **Stand:** 2026-05-13 -**App-Version / DB-Schema:** App **0.8.119**, DB-Schema **`20260514062`** (`backend/version.py`: `APP_VERSION`, `DB_SCHEMA_VERSION`) +**App-Version / DB-Schema:** App **0.8.120**, DB-Schema **`20260514062`** (`backend/version.py`: `APP_VERSION`, `DB_SCHEMA_VERSION`) Diese Datei ist die **Einstiegs-Doku für neue Chat-Sessions**: Anforderungen im Detail stehen in `.claude/docs/` (siehe unten); hier der **implementierte Stand**, **Medien-Meilenstein** und **sinnvolle nächste Schritte**. @@ -76,7 +76,7 @@ Das Schema ist gegenüber dem Code zurück: Migration **`022_skills_schema_compl - **036 / 037:** Bibliotheks-Rahmen, Slot-Inhalt als **`training_units`** mit **`framework_slot_id`**; **`POST /api/training-units/from-framework-slot`**. - **Code:** `training_framework_programs.py`, `training_planning.py`; Frontend **`TrainingFrameworkProgramEditPage.jsx`**, **`createTrainingUnitFromFrameworkSlot`** in `api.js`. -### Trainingsmodule, Kombinationsübungen und Coach (Stand **0.8.119**) +### Trainingsmodule, Kombinationsübungen und Coach (Stand **0.8.120**) - **Fachspez & Drift-Schutz:** `.claude/docs/functional/Shinkan Trainingsmodule Kombinationsuebungen Spezifikation V2.md` (**§ 10.2.1** IDs, **§ 10.4** Coaching-Stufen, **§ 10.6** Produkt-Backlog, **Anhang A** Abgleich). - **Umsetzungsplan:** `.claude/docs/working/TRAINING_MODULES_IMPLEMENTATION_PLAN.md` (Phase **2** / **4** teilweise; Pakete **4a–g** — u. a. **4e** Archetyp-Admin, **4f** Massen-Vorbelegung, **4g** Backend-Validierung). diff --git a/docs/architecture/UMSETZUNGSPLAN_ROADMAP.md b/docs/architecture/UMSETZUNGSPLAN_ROADMAP.md index ffc57fd..ba2f011 100644 --- a/docs/architecture/UMSETZUNGSPLAN_ROADMAP.md +++ b/docs/architecture/UMSETZUNGSPLAN_ROADMAP.md @@ -7,7 +7,9 @@ - **Phase 1 (Teil):** Org-Inbox: **ein** gemeinsamer Ladepfad `fetchOrgInboxSnapshot` für Mount-`useEffect` und `refreshOrgInbox` (gleiche Requests, weniger Drift-Risiko; Verhalten unverändert). - **Phase 2:** **abgeschlossen** (2026-05-14) — Indizes 058–062, Keyset `/api/exercises` + `/api/training-units`, **`/api/dashboard/kpis`** inkl. `training_home`, EXPLAIN-Vorlagen **`scripts/load/explain-readpaths.sql`**. - **Offen Phase 1:** Inbox optional **TTL** / nur bei sichtbarem Widget. -- **Phase 3 (gestartet 2026-05-13):** Übungsliste — extrahierte Karte, **virtualisierter** Picker, **lazy** Progressions-Panel; Playwright **Test 9**; Grid `data-testid`. Weiter: God-Pages (Planung/Formular) zerteilen. Nach MVP eine **nachhaltige** Architektur für Wachstum, **Performance** (Server + schwache Clients) und **sichere Feature-Erweiterung**. +- **Phase 3 (gestartet 2026-05-13):** Übungsliste modularisiert (Karte, Filter-/Bulk-Modals, virtualisierter Picker, lazy Progression); Playwright **Tests 9–10**. Weiter: God-Pages (Planung/Formular). + +**Ziel:** Nach MVP eine **nachhaltige** Architektur für Wachstum, **Performance** (Server + schwache Clients) und **sichere Feature-Erweiterung**. **Leitdokumente:** [ZIELBILD_ARCHITEKTUR.md](./ZIELBILD_ARCHITEKTUR.md), [SCHULDEN_UND_REMEDIATION.md](./SCHULDEN_UND_REMEDIATION.md), [VERBINDLICHE_REGELN_SHINKAN.md](./VERBINDLICHE_REGELN_SHINKAN.md). --- @@ -80,7 +82,7 @@ | Virtualisierung für die längste produktive Liste | A1, S2 | | Schwere Imports auf `import()` umziehen (gezielt) | A4 | -**Teil umgesetzt (2026-05-13):** `ExercisesListPage` — Karten in `components/exercises/ExerciseListCard.jsx`; Tab „Progressionsgraphen“ lädt **`ExerciseProgressionGraphPanel`** per `React.lazy` + `Suspense`; **`ExercisePickerModal`** virtualisiert (`@tanstack/react-virtual`, Scroll-Container `data-testid="exercise-picker-scroll"`); Gitter `data-testid="exercises-list-grid"` + `content-visibility` in `app.css`; Playwright **Test 9**. Offen: Seite unter Soft-Limit (~500 Zeilen), vollständige Zerteilung `TrainingPlanningPage` / `ExerciseFormPage`. +**Teil umgesetzt (2026-05-13):** `ExercisesListPage` — Karten `ExerciseListCard.jsx`; Filter/Massenänderung `ExerciseListFilterModal.jsx` / `ExerciseListBulkModal.jsx`; Tab „Progressionsgraphen“ **lazy**; **Picker** virtualisiert; Gitter `data-testid` + `content-visibility`; Playwright **Tests 9–10**. Offen: Seite unter Soft-Limit (~500 Zeilen, derzeit ~918 LOC), Zerteilung Planung/Übungsformular. **Abnahme:** Referenz-Page unter Soft-Limit; Regel S1 für neue Änderungen durchsetzbar. diff --git a/frontend/src/components/exercises/ExerciseListBulkModal.jsx b/frontend/src/components/exercises/ExerciseListBulkModal.jsx new file mode 100644 index 0000000..0d1913a --- /dev/null +++ b/frontend/src/components/exercises/ExerciseListBulkModal.jsx @@ -0,0 +1,240 @@ +import React from 'react' +import { activeClubMemberships } from '../../utils/activeClub' +import MultiSelectCombo from '../MultiSelectCombo' + +/** + * Massenänderung für ausgewählte Übungen in der Liste. + */ +export default function ExerciseListBulkModal({ + open, + onClose, + onSubmit, + bulkSubmitting, + selectedCount, + bulkMaxIds, + user, + isPlatformAdmin, + statusOptions, + bulkVisibilityOptions, + focusOptions, + styleOptions, + trainingTypeOptions, + targetGroupOptions, + bulkVisibility, + setBulkVisibility, + bulkStatus, + setBulkStatus, + bulkClubSelect, + setBulkClubSelect, + bulkClubManual, + setBulkClubManual, + bulkPatchFocusAreas, + setBulkPatchFocusAreas, + bulkFocusAreaIds, + setBulkFocusAreaIds, + bulkPatchStyleDirections, + setBulkPatchStyleDirections, + bulkStyleDirectionIds, + setBulkStyleDirectionIds, + bulkPatchTrainingTypes, + setBulkPatchTrainingTypes, + bulkTrainingTypeIds, + setBulkTrainingTypeIds, + bulkPatchTargetGroups, + setBulkPatchTargetGroups, + bulkTargetGroupIds, + setBulkTargetGroupIds, +}) { + if (!open) return null + + return ( +
+ Es werden {selectedCount} Übung(en) aus der aktuellen Auswahl bearbeitet. Pro Durchlauf + höchstens {bulkMaxIds}. Ohne Berechtigung bleiben Einzelübungen unverändert (siehe Hinweis nach dem + Speichern). +
++ Unter „Zuordnung ersetzen“: die gewählte Liste ersetzt die bisherige Zuordnung bei allen betroffenen Übungen + vollständig (leere Auswahl = alle Zuordnungen dieser Kategorie entfernen). Die erste Auswahl gilt als + Primärzuordnung. +
++ Zwischen den Bereichen gilt UND. Fokusbereiche: mehrere „+ mit“ bedeuten alle müssen + gesetzt sein; „− ohne“ schließt Übungen aus, die diesen Fokus zusätzlich haben. Stilrichtung / + Trainingsstil / Zielgruppe: mehrere „+“ = alle zutreffend (UND); „−“ verbietet die Zuordnung. Unter + „Freigabe“: Sichtbarkeit / Status mit „+“ = eine davon (ODER); „−“ blendet aus. +
+ ++ Die Stufen filtern nach dem Niveau der Zuordnung Übung ↔ Fähigkeit (von–bis). +
++ Sichtbarkeit und Status steuern Sie unter „Freigabe“ mit + und −. Hier nur globale Listen-Optionen. +
++ Pro Übung nur ein Wert: mehrere „+“ bedeuten „eine davon“ (ODER). „−“ blendet Werte aus. +
++ Trefferliste aktualisiert sich kurz nach Eingabe. Titel der aktuellen Liste erscheinen als Vorschläge (Pfeil im + Feld). Fachliche Filter über „Filter“ – zwischen Feldern UND, Auswahl mehrerer Werte je Feld mit ODER. + {exerciseCount > 0 ? ( + <> + {' '} + + > + ) : null} +
+- Trefferliste aktualisiert sich kurz nach Eingabe. Titel der aktuellen Liste erscheinen als Vorschläge (Pfeil im - Feld). Fachliche Filter über „Filter“ – zwischen Feldern UND, Auswahl mehrerer Werte je Feld mit ODER. - {exercises.length > 0 ? ( - <> - {' '} - - > - ) : null} -
-- Zwischen den Bereichen gilt UND. Fokusbereiche: mehrere „+ mit“ bedeuten alle müssen - gesetzt sein; „− ohne“ schließt Übungen aus, die diesen Fokus zusätzlich haben. Stilrichtung / - Trainingsstil / Zielgruppe: mehrere „+“ = alle zutreffend (UND); „−“ verbietet die Zuordnung. Unter - „Freigabe“: Sichtbarkeit / Status mit „+“ = eine davon (ODER); „−“ blendet aus. -
+- Die Stufen filtern nach dem Niveau der Zuordnung Übung ↔ Fähigkeit (von–bis). -
-- Sichtbarkeit und Status steuern Sie unter „Freigabe“ mit + und −. Hier nur globale Listen-Optionen. -
-- Pro Übung nur ein Wert: mehrere „+“ bedeuten „eine davon“ (ODER). „−“ blendet Werte aus. -
-- Es werden {selectedIds.size} Übung(en) aus der aktuellen Auswahl bearbeitet. Pro Durchlauf - höchstens {BULK_MAX_IDS}. Ohne Berechtigung bleiben Einzelübungen unverändert (siehe Hinweis nach dem - Speichern). -
-- Unter „Zuordnung ersetzen“: die gewählte Liste ersetzt die bisherige Zuordnung bei allen betroffenen - Übungen vollständig (leere Auswahl = alle Zuordnungen dieser Kategorie entfernen). Die erste Auswahl gilt - als Primärzuordnung. -
-