major
#29860
Konfigurationsformulare: Eingabefelder werden über fachliche Annotationen (@MultiLine, @Code, @Html, @Inline, …) gewählt, in klassischer und React-Oberfläche gleich; @ControlProvider und @ConfigControl entfallen
Kontext
In der React-Oberfläche werden Formulare auf zwei Wegen aufgebaut: modellbasierte Formulare (Attribute eines TL-Modell-Typs, FieldControlService) und Konfigurationsformulare (Eigenschaften eines ConfigurationItem, ConfigControlService, z.B. <config-form>, Einstellungsdialoge von Diensten und Komponenten). Beide Wege wählen das Eingabefeld für einen Wert unabhängig voneinander, und an mehreren Stellen kommt für dieselbe Art von Wert ein anderes, schlechteres Feld heraus.
Dazu kommt: Konfigurationseigenschaften legten ihr Eingabefeld bisher über die Annotation @ControlProvider fest, die eine Control-Klasse der klassischen Oberfläche nennt, und in der React-Oberfläche über die eigene Annotation @ConfigControl. Eine Konfiguration beschrieb damit nicht, was ein Wert ist, sondern womit eine bestimmte Oberfläche ihn bearbeitet - und war so zwischen beiden Oberflächen nicht übertragbar. Parameter wie die Zeilenzahl eines mehrzeiligen Textes ließen sich über die Annotation gar nicht angeben.
Verhalten vorher
- Einfachauswahl: Ein Modellattribut mit Auswahl (Referenz, Aufzählung) bekommt immer die durchsuchbare Auswahlliste (TLDropdownSelect). Eine Konfigurationseigenschaft vom Typ einer Java-Aufzählung oder mit @Options bekam dagegen das native HTML-<select> ohne Suche, ebenso die Auswahl des Implementierungstyps einer polymorphen Eigenschaft.
- Mehrzeiliger Text: Mit @ControlProvider(MultiLineText.class) markierte Konfigurationseigenschaften wurden im React-Konfigurationsformular einzeilig bearbeitet.
- Datum: Eine Date-Konfigurationseigenschaft speichert Datum und Uhrzeit, das Formular bot nur eine Datumsauswahl an; beim Speichern ging die Uhrzeit verloren. Die Datums-/Zeitauswahl der React-Oberfläche verwarf zudem die Sekunden eines eingegebenen Werts.
- Weitere Darstellungen (Quelltext-Editor, HTML-Editor, CommonMark-Text, eingebettete Untergruppen, Beschriftung von Konfigurationsklassen) wertete nur die klassische Oberfläche aus.
- Der WYSIWYG-Editor der React-Oberfläche verwarf beim Bearbeiten jedes Markup, das sein Schema nicht kennt (z.B. ein div mit Klassen um TL-Script-Makros).
- Der CommonMark-Darstellung der klassischen Oberfläche ließ javascript:-Linkziele durch.
Verhalten nachher
- Jede Auswahl in einem React-Konfigurationsformular (Aufzählung, @Options, Einfach- und Mehrfachauswahl, Typauswahl polymorpher Eigenschaften) verwendet dieselbe durchsuchbare Auswahlliste wie modellbasierte Formulare, nach Beschriftung sortiert.
- In der klassischen Oberfläche bekommt eine Einfachauswahl mit mehr als 20 Optionen (konfigurierbar: selection-dialog-threshold der EditorFactory) oder mit baumförmigen Optionen automatisch den Auswahldialog mit Suche; kleinere flache Auswahlen bleiben Klapplisten.
- Eine Date-Konfigurationseigenschaft wird mit Datum und Uhrzeit bearbeitet; eine Tageszeit-Eigenschaft behält die Zeitauswahl. Sekunden bleiben erhalten.
- Konfigurationseigenschaften beschreiben ihre Darstellung über fachliche Annotationen (Paket com.top_logic.layout.form.values.edit.annotation), die beide Oberflächen gleich auswerten:
- @MultiLine(rows=…) - mehrzeiliger Text mit der angegebenen Zeilenzahl (auch für mehrsprachige Texte: mehrzeilige Eingabe je Sprache).
- @CommonMark - mehrzeiliger Text in CommonMark-Syntax, im Lesemodus formatiert angezeigt (sicher gerendert: rohes HTML maskiert, javascript:-Links entfernt, SafeHTML-Prüfung).
- @Code(language=…) - Quelltext einer Sprache (CodeLanguage: PLAIN, XML, HTML, JSON, CSS, JAVASCRIPT, MARKDOWN), bearbeitet im Code-Editor (klassisch Ace, React CodeMirror), ohne Code-Editor-Modul als mehrzeiliger Text. HTML-Vorlagen (HTMLTemplate, HTMLTemplateFragment) tragen @Code(language=HTML) am Typ.
- @Html(features=…) - HTML-Text, bearbeitet im WYSIWYG-Editor mit dem angegebenen Funktionsumfang (z.B. macro), ohne WYSIWYG-Modul als HTML-Quelltext. Der React-Editor bietet für den Funktionsumfang macro eine Quelltextansicht.
- @Inline - eine geschachtelte Konfiguration erscheint ohne eigene Gruppe direkt im umgebenden Formular.
- @OptionLabels(…) - beschriftet auch den angezeigten Wert einer nicht setzbaren Eigenschaft (z.B. die Art eines Attributs im Modell-Editor).
- @Encrypted - immer das Passwortfeld, in beiden Oberflächen vor allen konfigurierten Abbildungen.
- TL-Script-Ausdrücke (Expr) und Skriptfunktionen (ScriptFunction0..4) bekommen in beiden Oberflächen den TL-Script-Editor über ihren Werttyp, ohne Annotation.
- Der React-WYSIWYG-Editor behält Markup, das sein Schema nicht kennt (unbekannte Elemente und Attribute); Inhalte, die im Editor wirken würden (Skripte, Event-Handler, iframes, …), erscheinen als nicht ausgeführter Quelltextblock. Jeder React-WYSIWYG-Editor prüft das HTML beim Speichern mit SafeHTML und lehnt unzulässiges HTML mit einer Feldmeldung ab, wie der klassische Editor.
- SafeHTML erlaubt beliebige data-*-Attribute sowie colwidth und akzeptiert nicht geschlossene leere HTML-Elemente (<br>, <img …>).
- Ein Feld, das zwischen Eingabe und Anzeige umschaltet (z.B. CommonMark), ist in der React-Oberfläche mit seiner Beschriftung verknüpft (Barrierefreiheit).
Technische Hinweise
- Abbildungen: Beide Formularfabriken haben je eine konfigurierbare Abbildung von einem Annotationstyp auf einen Control-Provider (<annotation-controls>) und eine von einem Werttyp auf einen Control-Provider (klassisch <type-controls> der EditorFactory, React <providers> von ConfigControlService). Der Provider bekommt die gefundene Annotation (AnnotationControlProvider bzw. ConfigAnnotationControlProvider) und kann mit null ablehnen. Gesucht wird an der Eigenschaft, dann an ihrem Werttyp; bei mehreren abgebildeten Annotationen entscheidet die Reihenfolge der Einträge. Module oberhalb überschreiben Einträge (gleicher Schlüssel bleibt an seiner Position, neue werden angehängt), z.B. ersetzt das Code-Editor-Modul den Textfeld-Eintrag für @Code.
- Meta-Annotation @ControlAnnotation: Jede Annotation, die Schlüssel von <annotation-controls> sein kann, ist mit @ControlAnnotation gekennzeichnet; deren Verwendungen listen alle solchen Annotationen einer Anwendung. Ein Eintrag für eine nicht gekennzeichnete Annotation wird beim Laden der Konfiguration abgelehnt (ControlAnnotationFormat), ein Konfigurationsformular bietet die gekennzeichneten Annotationen der Anwendung zur Auswahl an. Die Tests TestControlAnnotationCoverage in tl-demo (klassisch) und tl-demo-react (React, mit begründeter Ausnahmeliste) schlagen fehl, wenn eine gekennzeichnete Annotation in einer Oberfläche keinen Eintrag hat.
- Reihenfolge klassisch: @Encrypted → Annotationsabbildung → Typabbildung → Control des Editors; die Typabbildung gilt auch für Eigenschaften mit @PropertyEditor. React: @Encrypted → Annotationsabbildung → Auswahl → Typabbildung → Formatabbildung → eingebautes Feld. Die Annotationsabbildung bestimmt nur das Control, nicht die Wertform (typisiert, Auswahl, Formattext).
- Darstellungen einzelner Module ohne React-Oberfläche haben modul-eigene Annotationen: @ScriptTemplateParameters (Parametertabelle der Skript-Vorlagen) und @ApplicationRelativeURL (Basis-URL des OpenAPI-Servers als vollständiger Link).
- Entfernt: @ControlProvider (Konfigurationseigenschaften), @ConfigControl, die Abbildung <control-providers> von ConfigControlService, EditorControlConfig, DefaultCodeEditor, MacroControlProvider (wysiwyg), CodeEditorControl.CPXml/CPHtml/CPText, ConfigXMLEditor.CP, TLStructuredTypePartFormBuilder.ConfigLabel, die Konfiguration von MultiLineText/`CommonMarkText` (Zeilenzahl ist Konstruktorparameter).
- ReactDropdownSelectControl nimmt Werte vom Client nur noch an, wenn das Feld Client-Werte akzeptiert. ReactDatePickerControl schreibt einen Wert mit Sekunden als HH:mm:ss. Bekannte Lücke: der Datums-Adapter des MUI-Themes schreibt weiterhin HH:mm.
- Entwicklerdokumentation: Artikel config-form-controls (tl-docs in com.top_logic).
- Die Vereinheitlichung mit den Annotationen an TL-Modell-Attributen ist ein späterer Schritt.
Migration
Die Annotation com.top_logic.layout.form.values.edit.annotation.ControlProvider und die React-Annotation com.top_logic.layout.configedit.ConfigControl existieren nicht mehr. Verwendungen in Java-Code (@ControlProvider(…)) und in Formular-Anpassungen in Layout-/Konfigurations-XML (<annotation config:interface="com.top_logic.layout.form.values.edit.annotation.ControlProvider" value="…"/> bzw. <control-provider value="…"/> in <customizations>) sind zu ersetzen:
| = bisher = | = neu = |
| @ControlProvider(MultiLineText.class) | @MultiLine (optional rows = …) |
| @ControlProvider(CommonMarkText.class) | @CommonMark |
| @ControlProvider(CodeEditorControl.CPHtml.class) / CPXml / CPText | @Code(language = CodeLanguage.HTML) / XML / PLAIN |
| @ControlProvider(ConfigXMLEditor.CP.class) (mit @PropertyEditor(ConfigXMLEditor.class)) | @Code(language = CodeLanguage.XML) (Property-Editor bleibt) |
| @EditorControlConfig(language = "ace/mode/json") und @PropertyEditor(DefaultCodeEditor.class) | @Code(language = CodeLanguage.JSON) (beides entfällt) |
| @ControlProvider(StructuredTextControlProvider.class) | @Html |
| @ControlProvider(MacroControlProvider.class) | @Html(features = StructuredTextConfigService.FEATURE_SET_MACRO) |
| @ControlProvider(TLScriptCodeEditorControl.PlainCP.class) / CP.class an einer Expr-Eigenschaft | entfällt ersatzlos (Werttyp Expr) |
| @ControlProvider(GroupInlineControlProvider.class) | @Inline |
| @ControlProvider(SelectionControlProvider.class) an einer Auswahl | entfällt ersatzlos (Auswahldialog ab 20 Optionen bzw. bei Baumoptionen) |
| @ControlProvider(PasswordInputControlProvider.class) | @Encrypted |
| @ConfigControl(X.class) | eigene fachliche Annotation mit @ControlAnnotation und ein Eintrag in <annotation-controls> von ConfigControlService (SPI ConfigAnnotationControlProvider) |
| anwendungseigene ControlProvider-Klasse per @ControlProvider | eigene fachliche Annotation mit @ControlAnnotation; Eintrag in <annotation-controls> der EditorFactory (SPI AnnotationControlProvider) und - falls die Eigenschaft auch in der React-Oberfläche bearbeitet wird - in <annotation-controls> von ConfigControlService |
In XML-Anpassungen entsprechen die neuen Annotationen den Tags <multi-line rows="…"/>, <common-mark/>, <code language="json"/>, <html features="…"/>, <inline/>.
Weitere Anpassungen:
- Eine anwendungseigene Konfiguration <control-providers> von ConfigControlService entfällt; Einträge werden zu <annotation-controls>.
- Ein Eintrag in <annotation-controls> (klassisch oder React) für eine anwendungseigene Annotation setzt voraus, dass die Annotation mit @ControlAnnotation gekennzeichnet ist; sonst bricht das Laden der Konfiguration ab.
- Eine Konfiguration von MultiLineText mit rows entfällt; die Zeilenzahl steht an @MultiLine(rows = …).
- Wer CodeEditorControl.CPXml/CPHtml/CPText, ConfigXMLEditor.CP, MacroControlProvider (wysiwyg), EditorControlConfig oder DefaultCodeEditor direkt referenziert, verwendet @Code/`@Html` bzw. CodeEditorControl.CP/`StructuredTextControlProvider`.
- React-WYSIWYG-Attribute (tl.model.wysiwyg:Html) werden beim Speichern mit SafeHTML geprüft; gespeicherte Inhalte mit Markup außerhalb der Whitelist (z.B. <section>, eigene Elemente) lassen sich erst nach Entfernen dieses Markups wieder speichern.