feat: per-widget action menu (refresh, maximize, duplicate, remove) (#27) #37

Merged
pitfriedrich merged 1 commits from ai/issue-27-widget-action-menu into main 2026-07-28 19:29:07 +00:00
Collaborator

Closes #27

Was drin ist

GridStackItem bekommt als dritten Geschwister-Knoten neben Griff und Close-Button ein Overflow-Menü (GridStackItem.Action: REFRESH, MAXIMIZE, DUPLICATE, REMOVE).

  • Kein Drag beim Öffnen — das Menü liegt außerhalb des DRAG_HANDLE_CLASS-Selektors, genau wie der Close-Button.
  • Tastatur — ein MenuBar statt eines handgebauten Popups: der Trigger ist ein echter Button, Öffnen/Navigieren/Auswählen kommt vom Web-Component.
  • Maximieren stellt exakt wieder her — gesetzt wird nur die Klasse dialect-maximized; die gs-*-Attribute und der gridstack-Node bleiben unangetastet, das Zurücksetzen ist damit per Definition die alte Position. Nach dem Umschalten wird ein resize gefeuert, damit die ApexCharts im Widget neu layouten.
  • Pro Widget einzeln schaltbar (setActions(...) / setActionEnabled(...)): Default sind MAXIMIZE + REMOVE (kann das Item selbst), Registry-Widgets schalten zusätzlich REFRESH + DUPLICATE frei, KPI-Kacheln nur REFRESH — eine zweite Kopie derselben Kennzahl wäre dieselbe Zahl doppelt.
  • Refresh trifft nur ein Widget: WidgetRegistry hängt den Feed des Widgets per ComponentUtil an die Chart-Komponente, WidgetRegistry.refresh(component) löst genau diesen aus. Widgets ohne Refresher (statische Karte) werden still übergangen.
  • Copy in allen drei Bundles (de/en/es), inkl. erweitertem gridstack.hint.

Tests

./mvnw test — 55 Tests grün.

  • DashboardViewTest: Menü-Angebot pro Widget-Typ, Remove, Maximize-Toggle inkl. unveränderter Grid-Position, Duplicate, Refresh.
  • WidgetActionMenuPlaywrightTest (neu, e2e): Ziehen am Menü-Button bewegt das Widget nicht, Menü öffnet mit allen Einträgen, Maximieren/Wiederherstellen landet exakt im selben Slot.

Anmerkungen

  • Export ist bewusst nicht dabei — gehört laut Issue in das eigene Export-Issue.
  • Der Diff liegt mit ~310 Zeilen Produktivcode leicht über der ~200-Zeilen-Marke aus CLAUDE.md; das Issue war im Scope aber eindeutig beschrieben ("Scope: Medium"), daher umgesetzt statt geblockt.
  • src/main/bundles/dev.bundle (generiertes Build-Artefakt, war schon vor der Bearbeitung dirty) ist bewusst nicht Teil des Commits.
Closes #27 ## Was drin ist `GridStackItem` bekommt als dritten Geschwister-Knoten neben Griff und Close-Button ein Overflow-Menü (`GridStackItem.Action`: `REFRESH`, `MAXIMIZE`, `DUPLICATE`, `REMOVE`). - **Kein Drag beim Öffnen** — das Menü liegt außerhalb des `DRAG_HANDLE_CLASS`-Selektors, genau wie der Close-Button. - **Tastatur** — ein `MenuBar` statt eines handgebauten Popups: der Trigger ist ein echter Button, Öffnen/Navigieren/Auswählen kommt vom Web-Component. - **Maximieren stellt exakt wieder her** — gesetzt wird nur die Klasse `dialect-maximized`; die `gs-*`-Attribute und der gridstack-Node bleiben unangetastet, das Zurücksetzen ist damit per Definition die alte Position. Nach dem Umschalten wird ein `resize` gefeuert, damit die ApexCharts im Widget neu layouten. - **Pro Widget einzeln schaltbar** (`setActions(...)` / `setActionEnabled(...)`): Default sind `MAXIMIZE` + `REMOVE` (kann das Item selbst), Registry-Widgets schalten zusätzlich `REFRESH` + `DUPLICATE` frei, KPI-Kacheln nur `REFRESH` — eine zweite Kopie derselben Kennzahl wäre dieselbe Zahl doppelt. - **Refresh trifft nur ein Widget**: `WidgetRegistry` hängt den Feed des Widgets per `ComponentUtil` an die Chart-Komponente, `WidgetRegistry.refresh(component)` löst genau diesen aus. Widgets ohne Refresher (statische Karte) werden still übergangen. - **Copy** in allen drei Bundles (de/en/es), inkl. erweitertem `gridstack.hint`. ## Tests `./mvnw test` — 55 Tests grün. - `DashboardViewTest`: Menü-Angebot pro Widget-Typ, Remove, Maximize-Toggle inkl. unveränderter Grid-Position, Duplicate, Refresh. - `WidgetActionMenuPlaywrightTest` (neu, e2e): Ziehen am Menü-Button bewegt das Widget nicht, Menü öffnet mit allen Einträgen, Maximieren/Wiederherstellen landet exakt im selben Slot. ## Anmerkungen - Export ist bewusst **nicht** dabei — gehört laut Issue in das eigene Export-Issue. - Der Diff liegt mit ~310 Zeilen Produktivcode leicht über der ~200-Zeilen-Marke aus `CLAUDE.md`; das Issue war im Scope aber eindeutig beschrieben ("Scope: Medium"), daher umgesetzt statt geblockt. - `src/main/bundles/dev.bundle` (generiertes Build-Artefakt, war schon vor der Bearbeitung dirty) ist bewusst nicht Teil des Commits.
claude-bot added 1 commit 2026-07-28 19:26:31 +00:00
fix: add a per-widget action menu (#27)
CI / build-and-test (pull_request) Successful in 2m25s
8545b06f41
A GridStackItem now carries an overflow menu next to the grip and the
close button: refresh, maximize, duplicate, remove. Maximize and remove
are handled by the item itself; refresh and duplicate are only reported,
since what they mean depends on the widget.

Maximizing only sets a class — the item's gs-* attributes and its
gridstack node are untouched, so restoring is by definition the position
it had.

The menu sits outside the drag-handle selector, like the close button, so
opening it never starts a drag; a Playwright test drags it to prove it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0124BiJikbhbiEsNfJxdWM69
pitfriedrich merged commit bb9b89a8d8 into main 2026-07-28 19:29:07 +00:00
pitfriedrich deleted branch ai/issue-27-widget-action-menu 2026-07-28 19:29:07 +00:00
Sign in to join this conversation.