Plugin support: Plugins unter Settings aktivieren und deaktivieren #114

Closed
opened 2026-09-17 17:57:04 +02:00 by meleki · 2 comments
Owner

Aus #113, Entscheidung 1: v1 lädt alles, was in data/plugins/ liegt.

Zu bauen:

  • Unter Settings eine Liste „Plugins“: Name, Version, Datei, und ob das Plugin beim Laden einen Fehler hatte – je mit Schalter aktiv/inaktiv.
  • Zustand serverweit (Entscheidung 2) in data/plugins/plugins.json; die Route plugins liefert nur aktive Plugins zum Laden aus, die Liste für Settings aber alle.
  • Tests: Unit für den gespeicherten Zustand, e2e: Demo-Plugin deaktivieren → Tab weg, aktivieren → Tab wieder da.

Offen:

  • Ist ein neu abgelegtes Plugin standardmäßig aktiv oder inaktiv? (Mit Upload und #115 spricht mehr für inaktiv.)
  • Wirkt Deaktivieren sofort (deactivate() + Tabs entfernen) oder erst nach dem Neuladen des Editors?
Aus #113, Entscheidung 1: v1 lädt alles, was in `data/plugins/` liegt. **Zu bauen:** - Unter *Settings* eine Liste „Plugins“: Name, Version, Datei, und ob das Plugin beim Laden einen Fehler hatte – je mit Schalter aktiv/inaktiv. - Zustand **serverweit** (Entscheidung 2) in `data/plugins/plugins.json`; die Route `plugins` liefert nur aktive Plugins zum Laden aus, die Liste für Settings aber alle. - Tests: Unit für den gespeicherten Zustand, e2e: Demo-Plugin deaktivieren → Tab weg, aktivieren → Tab wieder da. **Offen:** - Ist ein neu abgelegtes Plugin standardmäßig aktiv oder inaktiv? (Mit Upload und #115 spricht mehr für inaktiv.) - Wirkt Deaktivieren sofort (`deactivate()` + Tabs entfernen) oder erst nach dem Neuladen des Editors?
admin added this to the Development project 2026-09-17 18:32:35 +02:00
admin moved this to Next in Development on 2026-09-17 19:32:44 +02:00
Author
Owner

Umgesetzt in c17b2b5.

Entscheidungen

  • Eigener Tab „Plugins" statt eines Settings-Dialogs — einen Bereich Settings gibt es im Editor nicht. Der Tab listet pro Datei: Name, Version, Dateiname, Zustand, Schalter.
  • Neue Dateien sind aus. Geladen wird nur, was in data/plugins/plugins.json steht. Ein ausgeschaltetes Plugin wird nie geholt, es läuft also kein Zeilencode daraus. Deshalb steht in seiner Zeile kein Name, bis es einmal lief — den Namen auszulesen hieße, es auszuführen.
  • Der Schalter wirkt sofort. Aus: deactivate(), danach nimmt der Editor zurück, was das Plugin über die API angelegt hat (Tabs samt Inhalt, change-Listener); wer auf so einem Tab war, landet auf Scene. An: laden und aktivieren, hinter allen laufenden Plugins.

Gebaut

  • Server: GET ?r=plugins liefert jetzt auch active und listet alles. PUT ?r=plugins/{file} mit {active} schaltet serverweit, unter einem Lock und mit atomarem Schreiben. Ein ausgeschaltetes Modul wird nicht mehr ausgeliefert (403).
  • PluginManager (aus dem einmaligen activatePlugins): hält pro Plugin einen PluginScope mit den Aufräum-Funktionen und führt Schaltvorgänge nacheinander aus, damit ein schnelles Aus-Ein sich nicht überholt.
  • Nebenbei ein Mangel aus #113 behoben: Wirft activate nach dem Anlegen eines Tabs, bleibt der Tab nicht mehr stehen.
  • Build und Seeder teilen sich tools/lib/plugins.mjs: kopieren, Demo einschalten (Build nur, wenn der Zustand die Datei noch nicht nennt — ein bewusst ausgeschaltetes Plugin bleibt über Deployments aus; der Seeder schaltet immer ein) und data/plugins dem Besitzer von data/ übergeben, damit PHP dort schreiben darf.

Tests (lokal)

npm run check                                   -> 93 Files, 1256 Tests (vorher 1246), CHECK EXIT 0
npm run build                                   -> BUILD EXIT 0
GM_STEPS=38 (frisch geseedet)                   -> ALL PASSED - 23 checks (vorher 17)
GM_STEPS=1-16,19,23,26,36,38 (frisch geseedet)  -> ALL PASSED - 606 checks (vorher 600)
  • 10 neue Unit-Tests: nur Eingeschaltetes wird geladen, Schalten speichert erst und wirkt dann, Ausschalten räumt Tab und Listener weg, ein Serverfehler lässt alles wie es war, ein halb gebautes Plugin hinterlässt nichts, ein werfendes deactivate verhindert das Ausschalten nicht, Schaltvorgänge laufen in der Reihenfolge der Klicks, Listener, Scope-Reihenfolge, Zeilentexte.
  • Gegenprobe mit 4 absichtlichen Fehlern: Schalter beim Start ignorieren (2 rot), nach fehlgeschlagenem activate nicht aufräumen (1 rot), Schalter anwenden bevor er gespeichert ist (1 rot), Tab beim Abschalten stehen lassen (3 rot). Danach Originale zurück und per cmp geprüft.
  • 6 neue e2e-Checks in Modul 38: Zeile mit Namen und Schalter, Ausschalten stoppt das Plugin, sein Tab verschwindet samt Board, der Server meldet es als aus, Einschalten aktiviert sofort, das Board ist mit allen Assets zurück.
  • Route direkt am PHP geprüft (kurzer php -S im Container, danach beendet): Liste 200, PUT an/aus 200, Modul im Aus-Zustand 403, active: "yes" 422, unbekannte Datei / Traversal / plugins.json je 404, DELETE und POST 405.
  • Zwei e2e-Fehlversuche waren meine: Ich wollte den 403 im Browser messen — die Antwort kommt dort nie an, weil die Brandmauer Fehlerantworten ersetzt. Der Check belegt den Serverzustand jetzt über die Liste.

Check-Summe 969 (963 + 6) in README und Wiki, gerechnet — CI ist nicht abgewartet, die Logs zu 57a97ba und c17b2b5 sind ungelesen.

Wiki: Plugins.md (neuer Abschnitt Switching a plugin on and off), API.md, Architecture.md, Home.md, Development.md.

Umgesetzt in `c17b2b5`. ## Entscheidungen - **Eigener Tab „Plugins"** statt eines Settings-Dialogs — einen Bereich *Settings* gibt es im Editor nicht. Der Tab listet pro Datei: Name, Version, Dateiname, Zustand, Schalter. - **Neue Dateien sind aus.** Geladen wird nur, was in `data/plugins/plugins.json` steht. Ein ausgeschaltetes Plugin wird nie geholt, es läuft also kein Zeilencode daraus. Deshalb steht in seiner Zeile kein Name, bis es einmal lief — den Namen auszulesen hieße, es auszuführen. - **Der Schalter wirkt sofort.** Aus: `deactivate()`, danach nimmt der Editor zurück, was das Plugin über die API angelegt hat (Tabs samt Inhalt, `change`-Listener); wer auf so einem Tab war, landet auf Scene. An: laden und aktivieren, hinter allen laufenden Plugins. ## Gebaut - **Server:** `GET ?r=plugins` liefert jetzt auch `active` und listet alles. `PUT ?r=plugins/{file}` mit `{active}` schaltet serverweit, unter einem Lock und mit atomarem Schreiben. Ein ausgeschaltetes Modul wird nicht mehr ausgeliefert (403). - **`PluginManager`** (aus dem einmaligen `activatePlugins`): hält pro Plugin einen `PluginScope` mit den Aufräum-Funktionen und führt Schaltvorgänge nacheinander aus, damit ein schnelles Aus-Ein sich nicht überholt. - **Nebenbei ein Mangel aus #113 behoben:** Wirft `activate` nach dem Anlegen eines Tabs, bleibt der Tab nicht mehr stehen. - **Build und Seeder** teilen sich `tools/lib/plugins.mjs`: kopieren, Demo einschalten (Build nur, wenn der Zustand die Datei noch nicht nennt — ein bewusst ausgeschaltetes Plugin bleibt über Deployments aus; der Seeder schaltet immer ein) und `data/plugins` dem Besitzer von `data/` übergeben, damit PHP dort schreiben darf. ## Tests (lokal) ``` npm run check -> 93 Files, 1256 Tests (vorher 1246), CHECK EXIT 0 npm run build -> BUILD EXIT 0 GM_STEPS=38 (frisch geseedet) -> ALL PASSED - 23 checks (vorher 17) GM_STEPS=1-16,19,23,26,36,38 (frisch geseedet) -> ALL PASSED - 606 checks (vorher 600) ``` - **10 neue Unit-Tests:** nur Eingeschaltetes wird geladen, Schalten speichert erst und wirkt dann, Ausschalten räumt Tab und Listener weg, ein Serverfehler lässt alles wie es war, ein halb gebautes Plugin hinterlässt nichts, ein werfendes `deactivate` verhindert das Ausschalten nicht, Schaltvorgänge laufen in der Reihenfolge der Klicks, Listener, Scope-Reihenfolge, Zeilentexte. - **Gegenprobe mit 4 absichtlichen Fehlern:** Schalter beim Start ignorieren (2 rot), nach fehlgeschlagenem `activate` nicht aufräumen (1 rot), Schalter anwenden bevor er gespeichert ist (1 rot), Tab beim Abschalten stehen lassen (3 rot). Danach Originale zurück und per `cmp` geprüft. - **6 neue e2e-Checks** in Modul 38: Zeile mit Namen und Schalter, Ausschalten stoppt das Plugin, sein Tab verschwindet samt Board, der Server meldet es als aus, Einschalten aktiviert sofort, das Board ist mit allen Assets zurück. - **Route direkt am PHP geprüft** (kurzer `php -S` im Container, danach beendet): Liste 200, `PUT` an/aus 200, Modul im Aus-Zustand 403, `active: "yes"` 422, unbekannte Datei / Traversal / `plugins.json` je 404, `DELETE` und `POST` 405. - Zwei e2e-Fehlversuche waren meine: Ich wollte den 403 im Browser messen — die Antwort kommt dort nie an, weil die Brandmauer Fehlerantworten ersetzt. Der Check belegt den Serverzustand jetzt über die Liste. **Check-Summe 969** (963 + 6) in README und Wiki, gerechnet — **CI ist nicht abgewartet**, die Logs zu `57a97ba` und `c17b2b5` sind ungelesen. Wiki: `Plugins.md` (neuer Abschnitt *Switching a plugin on and off*), `API.md`, `Architecture.md`, `Home.md`, `Development.md`.
admin moved this to Done in Development on 2026-09-17 20:17:05 +02:00
Author
Owner

Nachtrag: Der serverweite Schalter aus diesem Issue wird durch #119 ersetzt. Nach der Entscheidung in #117 entscheidet künftig das Projekt, welche Plugins laufen; data/plugins/plugins.json und die Route PUT ?r=plugins/{file} entfallen dabei. Der Plugins-Tab selbst bleibt, sein Schalter schreibt dann ins Projekt.

Nachtrag: Der serverweite Schalter aus diesem Issue wird durch **#119** ersetzt. Nach der Entscheidung in #117 entscheidet künftig das Projekt, welche Plugins laufen; `data/plugins/plugins.json` und die Route `PUT ?r=plugins/{file}` entfallen dabei. Der Plugins-Tab selbst bleibt, sein Schalter schreibt dann ins Projekt.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: meleki/feuerwerk#114