enhancement
major
minor
defect
critical
major
minor
major
#30250
TL-Ansichten: <start-job> / <job-status> – Schließen-Schaltfläche für einen abgeschlossenen Job, „Point of No Return“, Teilergebnis eines abgebrochenen Jobs, Schließen des Dialogs aus dem Folgejob heraus, der Folgejob sieht die Commits des Jobs
tl-layout-view 8.0.0-alpha12.819. Fasst die Tickets #30193, #30194, #30195, #30249 und #30250 zusammen (Lange Aufträge der TL Views: <start-job> und <job-status>).
Probleme
Anzeige eines beendeten Auftrags lässt sich nicht schließen (#30250)
Ein fehlgeschlagener oder abgebrochener <start-job> bricht sein Kommando ab; der Fehler bleibt bewusst im letzten Zustand des Auftrags sichtbar. Die übliche Seite zeigt die Anzeige, solange der Kanal einen Auftrag hält:
<visible-if expr="$importJob != null" input="importJob"> <inset><job-status input="importJob"/></inset> </visible-if> <table …/>
Ein erfolgreicher Auftrag wird von seinem Folgeschritt geleert (<write-channel name="importJob" clear="true"/> im <with-result>). Ein fehlgeschlagener oder abgebrochener überspringt den Folgeschritt, seine Anzeige (Status, Schritte, Balken, Fehler) bleibt dauerhaft über der Tabelle stehen; <job-status> bietet nichts zum Schließen. Erst der nächste Auftrag entfernt sie. (E-Home: ETS-Import, Projekt-Update, Produktimport.)
Abbrechen während des abschließenden Commits (#30194)
Ein abbrechbarer Auftrag, der in einer eigenen Transaktion importiert und zuletzt committet, bietet während des Commits weiter Abbrechen an. Ein Abbruch in diesem Moment hält den Commit nicht mehr auf - die Daten sind gespeichert -, aber JobRunner.run entscheidet allein nach dem Abbruch-Flag: der Auftrag endet als abgebrochen, sein Ergebnis wird verworfen, das wartende Kommando abgebrochen. Der Benutzer liest "abgebrochen", obwohl der Import vorhanden ist.
Abgebrochener Auftrag liefert kein Teilergebnis (#30195)
Ein Import mehrerer Dateien committet jede Datei einzeln; ein Abbruch rollt nur die laufende Datei zurück. Ein Body, der die AbortExecutionException fängt und den Bericht über die bereits importierten Dateien zurückgibt, endet trotzdem als abgebrochen ohne Ergebnis, und StartJobAction bricht das Kommando ab. Der Benutzer erfährt nicht, dass zwei von drei Dateien importiert wurden.
`<close-dialog>` im `<with-result>` eines `<start-job>` wird ignoriert (#30193)
Ein <window>-Dialog startet einen Auftrag und soll sich nach dessen Ende schließen (<with-result><close-dialog/><open-dialog …/>…</with-result>). Seit #29631 ist ein Dialog mit einem ausgesetzten Kommando nicht schließbar; der <with-result> läuft aber noch als Fortsetzung genau dieses Kommandos, das daher weiter als ausgesetzt zählt. Das <close-dialog> wird zurückgestellt, der Berichtsdialog öffnet sich darüber und verschwindet wieder, der Auftragsdialog bleibt offen.
Der `<with-result>` sieht die Commits des Auftrags nicht (#30249)
Seit #30216 läuft der Body in einer vom Fenster abgeleiteten Sub-Session. Das Fenster erfährt von den Commits des Auftrags erst durch Modell-Events, die beim nächsten Betreten des Fensters synthetisiert werden. Der <with-result> läuft davor: ein <write-channel>, der das vom Auftrag erzeugte Objekt in einer Tabelle selektiert, findet die Zeile noch nicht, die Selektion geht verloren - reproduzierbar, wenn das Fenster während des Auftrags selbst committet hat.
Lösung
Schließen-Knopf (#30250): <job-status> bietet für einen beendeten Auftrag (abgeschlossen, fehlgeschlagen oder abgebrochen) einen Schließen-Knopf (×) am Ende der Kopfzeile an. Ein Klick leert den Eingabekanal; die Anzeige verschwindet, ebenso ein umgebendes <visible-if expr="$importJob != null">. Solange der Auftrag läuft, gibt es den Knopf nicht. Das Attribut closable (Vorgabe true) schaltet ihn ab. Angeboten wird er nur auf einem beschreibbaren Kanal: ViewChannel erhält dafür isWritable() (ein abgeleiteter Kanal ohne Umkehrfunktion ist nicht beschreibbar). Ein Klick, der den Start eines neuen Auftrags kreuzt, wird ignoriert.
Punkt ohne Wiederkehr (#30194): JobMonitor.uncancelable() (TL-Script: jobUncancelable($job)) erklärt, dass der Body seine Arbeit ab jetzt zu Ende führt: war der Auftrag schon abgebrochen, endet er sofort als abgebrochen; andernfalls verschwindet der Abbrechen-Knopf, cancel() wird abgelehnt und der Auftrag endet mit dem, was der Body zurückgibt. Ob ein Abbruch angenommen ist, entscheidet JobRunner unter derselben Sperre wie den Punkt ohne Wiederkehr; JobState hält die Abbrechbarkeit als Komponente des Snapshots.
Teilergebnis eines abgebrochenen Auftrags (#30195): Gibt ein Body nach einem Abbruch regulär einen Wert zurück, behält der abgebrochene Auftrag diesen als Ergebnis (JobState.result(), jobResult($s), in der Anzeige). <start-job> erhält die optionale Folgekette <on-cancel as="…">, die mit diesem (ggf. leeren) Ergebnis läuft, statt das Kommando abzubrechen; danach läuft die Kette wie nach <with-result> weiter. Ohne <on-cancel> bricht ein Abbruch das Kommando wie bisher ab; ein fehlgeschlagener Auftrag bricht immer ab.
Ausgesetzte Kommandos (#30193): Ein Kommando zählt nur so lange als ausgesetzt, wie eine Aktion seine Kette hält. Gibt die Aktion die Kette zurück (fortsetzen oder abbrechen), endet die Aussetzung, bevor die Fortsetzung läuft; ein <close-dialog> in der Fortsetzung schließt seinen Dialog sofort. Setzt die Fortsetzung erneut aus (weiterer <start-job>, <confirm>), zählt sie wieder. Ein <close-dialog> eines anderen Kommandos, während ein Auftrag läuft, wartet weiter bis zu dessen Ende und schließt dann seinen eigenen Dialog (nicht den gerade obersten). ViewActionChain meldet das Halten und Zurückgeben der Kette über ViewActionChain.HoldObserver.
Commits des Auftrags vor der Fortsetzung (#30249): Das Betreten eines Fensters aus einem anderen Thread (ReactWindowReplay.inWindow, auch über den Fensternamen, wie ihn ChannelPublisher für die Snapshots eines Auftrags und <source-channel> nutzt) synthetisiert die Modell-Events des Fensters auch vor der Aktion. Die Fortsetzung eines beendeten Auftrags sieht damit die Objekte des Auftrags wie nach einem synchronen Kommando.
Dokumentation und Demo: commands.md (Abschnitt zu <start-job> / <job-status>), Vertrag job-status.contract.md; die Demo "Long-running job" von tl-demo-react zeigt Schließen, Punkt ohne Wiederkehr, Teilergebnis bei Abbruch mit <on-cancel> und einen Auftragsdialog, der sich nach dem Auftrag selbst schließt.
Migration
- <job-status> bietet für einen beendeten Auftrag standardmäßig einen Schließen-Knopf an, der den Eingabekanal leert. Wo die Anzeige eines beendeten Auftrags stehen bleiben soll, closable="false" setzen.
- Eigene Implementierungen von JobMonitor müssen die Methode uncancelable() implementieren (eine delegierende Implementierung reicht sie an den umhüllten Monitor weiter).
- Der Record JobState hat die zusätzliche Komponente cancelable (vor control); Code, der JobState selbst konstruiert (z.B. in Tests), übergibt sie.
- ViewActionChain.run(..., Consumer onComplete, Runnable onSettled) entfällt; statt des onSettled-Callbacks nimmt ViewActionChain.run(context, actions, arguments, after, onComplete, holds) einen ViewActionChain.HoldObserver.
- Ein abgebrochener Auftrag, dessen Body nach dem Abbruch regulär einen Wert zurückgibt, liefert diesen Wert als jobResult(...).