Tasks, eigene Typen und Metadaten pro Editor-Aufruf laden und an den Aufrufer zurückgeben. MongoDB-Persistenz entfernen und Header auf Rückgängig, Abbrechen und Fertig umstellen. Python-Testserver und Regressionstests ergänzen; Verbindungslinien nach Import und Layoutänderungen neu berechnen.
159 lines
6.2 KiB
Markdown
159 lines
6.2 KiB
Markdown
# Workflow Editor (TaskList Editor)
|
|
|
|
n8n-inspirierter Editor zum Erstellen von Aufgabenlisten (Tasks) für die
|
|
stadtbote-App. Funktionsblöcke werden per Drag & Drop auf einem Canvas
|
|
angeordnet und verbunden; daraus wird das app-konforme `tasks`-JSON erzeugt.
|
|
|
|
## Funktionen
|
|
|
|
- Funktionsblöcke für die stadtbote-Task-Typen (Ankunft, Unterschrift, Fotos,
|
|
Quittungsgeber, Stationshinweis, Kommissionsnummer, Abhol-/Lieferstatus)
|
|
- Erzeugen des app-konformen Task-JSON
|
|
- Eigene Typen mit konfigurierbaren Vorgaben
|
|
- Aufruf per Deep-Link mit Übergabe von Tasks, eigenen Typen und Metadaten als JSON-Body
|
|
- Rückgabe der bearbeiteten Tasks und des vollständigen eigenen Typkatalogs an den Aufrufer
|
|
|
|
## Technik
|
|
|
|
- Java 21, Spring Boot 3, Vaadin 24
|
|
- Drawflow als Canvas-/Node-Editor
|
|
|
|
## Konfiguration
|
|
|
|
Für den Editor ist keine Datenbank erforderlich. Tasks und eigene Typen werden
|
|
beim Aufruf übergeben und bei **Fertig** an den Aufrufer zurückgegeben. Der
|
|
Aufrufer ist für deren dauerhafte Speicherung verantwortlich.
|
|
|
|
Optionale Einstellungen sind in `.env.example` beschrieben.
|
|
|
|
## Start
|
|
|
|
```bash
|
|
mvn spring-boot:run
|
|
```
|
|
|
|
Die Anwendung läuft anschließend unter http://localhost:8080/.
|
|
|
|
## Aufruf und Rückgabe mit dem Python-Testserver
|
|
|
|
Die Webapp muss mit dem aktuellen Code auf Port 8080 laufen. In einem zweiten
|
|
Terminal den Testserver starten (Python 3, keine zusätzlichen Pakete):
|
|
|
|
```bash
|
|
python3 tools/editor_test_server.py
|
|
```
|
|
|
|
Der Testserver öffnet seine Aufruferseite unter `http://127.0.0.1:8090`.
|
|
Dort das Beispiel bearbeiten oder eigenes JSON einfügen und den Editor öffnen.
|
|
Der Editor erscheint eingebettet in der Seite. **Fertig** gibt die validierten
|
|
Tasks und den vollständigen Katalog eigener Typen zurück; **Abbrechen** meldet
|
|
den Abbruch ohne bearbeitete Tasks oder Typen.
|
|
Beide Ergebnisse werden im Python-Terminal als JSON ausgegeben und auf der
|
|
Testseite angezeigt. Nach **Fertig** enthält das JSON-Eingabefeld die Rückgabe
|
|
für den nächsten Editor-Aufruf. **Neue Liste** leert die Tasks und behält den
|
|
aktuellen eigenen Typkatalog. Nach **Abbrechen** bleibt die Eingabe unverändert.
|
|
Die Testseite hält diese Daten nur bis zum Neuladen; die Konsolenausgabe bleibt
|
|
im Terminal verfügbar.
|
|
|
|
Eine Datei vorgeben oder andere Ports verwenden:
|
|
|
|
```bash
|
|
python3 tools/editor_test_server.py --json tools/example_tasks.json
|
|
python3 tools/editor_test_server.py --editor-url http://127.0.0.1:8080 --port 8090 --no-browser
|
|
```
|
|
|
|
Als Eingabe ist ein Task-Array oder ein Objekt erlaubt:
|
|
|
|
```json
|
|
{
|
|
"name": "Testauftrag",
|
|
"tasks": [{ "type": 3, "topic": "Ankunft melden", "track": true }],
|
|
"customTypes": [],
|
|
"metadata": { "auftragId": "TEST-4711", "revision": 2 }
|
|
}
|
|
```
|
|
|
|
Für eine neue Liste `tasks` weglassen oder `[]` übergeben. Die Metadaten werden
|
|
unverändert zurückgegeben. Zum Abschließen eines neu aufgebauten Workflows
|
|
müssen Start, Aufgaben und Abschluss vollständig verbunden sein. Beim Import
|
|
vorhandener Tasks ergänzt der Editor die internen Start-/Abschlussmarkierungen;
|
|
sie sind nicht Teil des zurückgegebenen Task-Arrays.
|
|
|
|
### Eigene Typen
|
|
|
|
`customTypes` enthält den vollständigen Katalog für diesen Editor-Aufruf.
|
|
Ohne dieses Feld oder mit `[]` stehen nur die eingebauten Typen zur Verfügung.
|
|
Eigene Typen werden vor den Tasks geladen. Ein Task verweist mit `type` auf die
|
|
`taskType`-Nummer seines eigenen Typs (ab 1000), beispielsweise:
|
|
|
|
```json
|
|
{
|
|
"name": "Zustellnachweis",
|
|
"tasks": [{ "type": 1000, "topic": "Zustellung fotografieren", "min": 1, "max": 3 }],
|
|
"customTypes": [{
|
|
"typeId": "custom-1000",
|
|
"taskType": 1000,
|
|
"baseTypeId": "fotos-aufnehmen",
|
|
"label": "Zustellnachweis",
|
|
"description": "Fotos zur Dokumentation einer Zustellung.",
|
|
"icon": "vaadin:camera",
|
|
"color": "#059669",
|
|
"inputs": 1,
|
|
"outputs": 1,
|
|
"properties": [
|
|
{ "id": "min", "label": "Mindestanzahl Fotos", "type": "NUMBER", "defaultValue": 1 },
|
|
{ "id": "max", "label": "Maximale Anzahl Fotos", "type": "NUMBER", "defaultValue": 3 },
|
|
{ "id": "opt", "label": "Optionale Aufgabe", "type": "BOOLEAN", "defaultValue": false },
|
|
{ "id": "reenter", "label": "Erneut bearbeitbar", "type": "BOOLEAN", "defaultValue": true }
|
|
]
|
|
}],
|
|
"metadata": { "auftragId": "TEST-4711" }
|
|
}
|
|
```
|
|
|
|
`properties` beschreibt die Eigenschaften samt Vorgabewerten; `type` ist dabei
|
|
einer der Werte `TEXT`, `TEXTAREA`, `NUMBER`, `BOOLEAN`, `FIELD_LIST`, `NAME_LIST`
|
|
oder `CHOICE_LIST`. Das mitgelieferte Beispiel `tools/example_tasks.json`
|
|
enthält einen eigenen Foto-Typ und einen zugehörigen Task.
|
|
|
|
Bei **Fertig** wird `customTypes` immer vollständig zurückgegeben, einschließlich
|
|
unveränderter und neu angelegter Typen. Der Aufrufer ersetzt seinen bisherigen
|
|
Katalog durch dieses Array, damit auch gelöschte Typen berücksichtigt werden.
|
|
`[]` bedeutet, dass keine eigenen Typen mehr vorhanden sind. Bei **Abbrechen**
|
|
übernimmt der Aufrufer keine Änderungen.
|
|
|
|
### Übergabeprotokoll
|
|
|
|
Die Python-Seite ruft serverseitig `POST /api/editor/import` auf und ergänzt
|
|
`returnOrigin`, z. B. `http://127.0.0.1:8090`. Die Antwort enthält `token` und
|
|
`deepLink`. Der Aufrufer öffnet den Deep-Link in einem iframe oder Popup.
|
|
Der Import bleibt für 30 Minuten im Speicher der Webapp verfügbar, sodass ein
|
|
Neuladen während dieser Zeit möglich ist.
|
|
|
|
Der Editor sendet das Ergebnis per `postMessage` ausschließlich an diese Origin:
|
|
|
|
```json
|
|
{
|
|
"type": "tasklist-editor:result",
|
|
"token": "<Token aus der Importantwort>",
|
|
"status": "completed",
|
|
"name": "Testauftrag",
|
|
"metadata": { "auftragId": "TEST-4711", "revision": 2 },
|
|
"tasks": [{ "s_id": 1, "type": 3, "topic": "Ankunft melden", "track": true }],
|
|
"customTypes": []
|
|
}
|
|
```
|
|
|
|
Bei Abbruch ist `status` gleich `cancelled`; die Felder `tasks` und `customTypes`
|
|
entfallen.
|
|
Die Testseite prüft Absender-Origin, Fenster und Token und leitet das Ergebnis
|
|
an `POST /api/result` des Python-Servers weiter. Erst nach dessen Bestätigung
|
|
wird der iframe geschlossen. Ohne `returnOrigin` zeigt der Editor einen
|
|
schreibgeschützten JSON-Dialog zum Kopieren mit `name`, `metadata`, `tasks`
|
|
und `customTypes`.
|
|
|
|
Der Testserver ist ein lokales Entwicklungswerkzeug und bindet an `127.0.0.1`.
|
|
Er übernimmt bekannte Task-Felder des Editors; unbekannte Task-Typen werden vom
|
|
bestehenden Importer übersprungen. Beliebige zusätzliche Daten daher in
|
|
`metadata` übergeben.
|