TopLogic - the automated application engine
  • Releases
  • Dokumentation
  • Github
  • Discord
  1. Home
  2. Releases
  3. TL_8.0.0-alpha9
  4. #29525

8.0.0-alpha9
TopLogic Release

2026-10-01

enhancement

major
#27490
Historie begrenzen/abschneiden/aufräumen
#29004
Allow to use a virus scanner for uploads
#29006
Uniqueness-Constraint
#29421
Add a React calendar view control and declarative <calendar> UIElement.
#29429
Complete the view designer so a view can be built with it end to end
#29462
React: Generisches Formularelement zum Bearbeiten von Konfigurationen
#29487
React view: <form> exposes neither column count nor label position, and there is no <group> element
#29499
Hinweis auf den Wartungsmodus in der React-Oberfläche
#29507
Hinweis auf den bevorstehenden Session-Timeout in der React-Oberfläche
#29523
<sidebar> exposes two of the five sidebar item kinds ReactSidebarControl renders, and none of the badge
#29525
Offer the app-bar user menu in the core view layer
#29528
Let the UI theme follow the system's dark/light preference
#29529
Stellvertreter als explizite Sicherheitsaktion im Einstellungsdialog der TL Views benennen (mit Passwortbestätigung, auch für die Passwortänderung)
#29530
URL routing in TL Views: model objects in route parameters, drill-down path in the URL, query bindings
#29531
Filterleiste für Tabellen: Presets, Freitextsuche über die sichtbaren Spalten und benutzereigene gespeicherte Filter
#29532
Object navigation in TL Views: display targets, a reveal protocol for containers, and a show-object action
#29540
Usability feedback on the user menu and the personal settings dialog
#29542
TL Views: channel-bound value inputs for every primitive and reference type, with a submit hook
#29543
TL Views: conditional branches in a generic-command action chain
#29544
TL Views table: row activation by double-click or Enter, and a grouping UI over the existing table model
#29545
TL Views table: drag and drop of rows between tables and onto rows
#29546
TL Views: colors for enumeration literals and classifier objects rendered as pills, and a progress control
#29547
Generierte React-Bundles nicht mehr einchecken
#29548
React view UI: URL, e-mail and phone attributes are edited as typed inputs and displayed as links
#29551
TL Views: only registered entry points may be loaded top-level via URL
#29557
React view commands: the ExecutableState reason of a disabled command never reaches the client, and there is no disabled-if rule beside visible-if
#29567
TL Views: Mehrfachauswahl für Tabellen und Bäume (selection-mode="multi")
#29575
TL Views: UI-Inspektor – Zustand eines Elements der React-Oberfläche einsehen (z. B. durch Zugriffsrechte ausgeblendete Tabellenzeilen) und als Skript-Zusicherung aufzeichnen
#29596
TL Views: Gestaltungsoptionen für app-spezifische Oberflächen (css-class, Text-Varianten, Layout-Optionen, Anzeigevarianten für Eingaben, Theme-Tokens)
#29597
TL Views: object-list als generischer Repeater (Elemente ohne Container, Raster-Layout, Index für gestaffelte Animation)
#29598
TL Views: image mit URL-/Ressourcen-Quelle, Seitenverhältnis, Füllmodus und überlagerten Inhalten; avatar mit Foto
#29599
TL Views: Wizard-/Stepper-Element für mehrstufige Dialogflüsse (statische und dynamische Schritte, Fortschritt, Übergänge, Auto-Weiter)
#29600
TL Views: Anzeige lang laufender Server-Aufträge (Phasen, Fortschritt, unbestimmter Fortschritt, verstrichene Zeit)
#29601
TL Views: Anzeige von HTML-Inhalten und HTML-Dokumenten (Agenten-Antworten, Exposés) mit Vorschau und Druck/PDF
#29603
Physisches Löschen gelöschter Objekte aus versionierten Tabellen (Purge): Abschlussmenge über Pflichtreferenzen und Inhalte, optionale Verweise werden geleert
#29605
TL Views table filter bar: an initially active preset, and the active preset and search term as channels for query bindings
#29607
TL Views: a display target reveals a tab inside a pushed frame (a <show> is located within the view shown before it)
#29608
TL Views: value-input mit Platzhalter, zugänglicher Name bei verborgenem Label, bedingte Anzeige von Elementen mit visible-if
#29615
TL Views: a <form> spanning a page does not take part in the fill contract, so a split panel or filling panel inside it is sized by its content
#29617
Design System: Tokens and base classes as own package (wave 0)
#29625
TL Views: a page layout of weighted columns (main 2/3, side 1/3) that reflows to one column on a narrow viewport; the split-panel keeps its sashes and clips the side pane at 400 px
#29629
TL Views: `<show-view>` / `<show-views>` actions reveal a mounted view by name and write its channels from a command chain without a model object
#29630
TL Views: a chunked, transactional job body for <start-job> - scripted init / elements / steps / finish, one transaction per chunk, per-item retry and skip, phases and progress derived from the steps
#29637
Modellbasierte Berechtigungsdefinition: Zugriffselternobjekt (Delegation der Zugriffsentscheidung an Container oder Referenz, Standard für Kompositionsteile, Entscheidungs-Cache je Interaktion), Rollenelternobjekt statt Security-Parent, Vollständigkeitsprüfung und Assistent
#29640
TL Views: Gruppen einer gruppierten Tabelle werden nach dem Komparator der Gruppierungsspalte sortiert, nicht in zufälliger Reihenfolge
#29641
TL Views: Der React-TL-Script-Editor zeigt Hilfetexte zu Funktionen und Modellelementen an (Kontexthilfe zur Vervollständigung, Hover-Tooltips) und springt beim Tippen nicht mehr an den Textanfang
#29643
TL Views: Anpassung der React-Oberfläche an das Corporate Design eines Kunden mit eigener React-Komponentenbibliothek (Leitfaden und fehlende Erweiterungspunkte)
#29671
TL Views: Drag & Drop in Tabellen nach Regeln einschränken, mit Rückmeldung pro Ziel während des Ziehens
#29681
TL-Script modifiedRevision() berücksichtigt Referenz- und Übersetzungsänderungen; Attribut-Storages "touchen" das Besitzerobjekt nicht mehr
#29690
Option zum Deaktivieren des Browserstarts beim Hochfahren
#29706
Speed up slow unit tests in tl-core and tl-element
minor
#28324
Dokumentation zu Layout Overlays erstellen
#29500
No way to show a master-detail as an overlay: the detail always costs the list half its width
#29506
A dashboard tile cannot be the entry point it looks like: neither <tile> nor <card> carries an action
#29550
React controls do not consume the theme's radius and surface tokens consistently; a flat theme needs per-component CSS overrides
#29553
React view <table>: <column> has no width, every column defaults to 150 px, so a table with more than six columns overflows a 940 px pane
#29611
TL Views: `<notify>` action shows a translated notice in a generic-command chain (snackbar or OK dialog, optionally stopping the chain); `<throw-error>` removed
#29624
SSO-Login ohne registrierten Benutzeraccount: konfigurierbare Hinweisseite (ApplicationPages.unknownAccountPage) statt Login-Maske, mit Standardseiten für die klassische und die React-Oberfläche
#29670
TL-Script: Funktionen trim, trimStart und trimEnd entfernen Leerraum am Anfang und Ende einer Zeichenkette
#29675
TL Views: Anlegen und Löschen richten sich nach den Modell-Zugriffsrechten, statt erst nach dem Ausfüllen mit „Kopieren nicht erlaubt“ abgelehnt zu werden
#29683
TL-Script: htmlText(html) cannot carry images, so an HTML text with <img> referencing files cannot become a structured text

defect

critical
#29665
TL Views: a click into a rich-text field with a hidden label focuses the editor's Bold button, so the typed text is lost
#29682
TL Views: ConcurrentModificationException in ReactToolbarControl.replaceGroups on a page reload shows the "Internal error" page
major
#25723
Fehlende Prüfung gegen Attribut-Name-Clashes bei Vererbung
#29438
React view layer displays date attributes in a hard-wired format instead of the annotated one
#29474
Neither React drag handle shields the page (or locks the cursor) while dragging
#29502
<tree> does not follow model changes: a delete never arrives, a create collapses the whole tree
#29504
Zwangsabmeldung erreicht die React-Oberfläche nicht
#29509
Die Cookie-Prüfung weist den erneuten Aufruf ihrer eigenen URL ab und meldet dabei die Sitzung ab
#29512
Attribute in tl.model, die de-facto mandatory sind, auch als mandatory deklarieren
#29533
TL Views: executability rules and derived channels must follow changes of the object on a channel, not only of the channel value
#29534
TL Views tile-stack: frames get no definite height, and a frame that is uncovered again is rebuilt from scratch
#29535
TL Views table: a selection channel value that is not among the rows must not be cleared by the table
#29541
Single-valued drop-down select shows two clear buttons
#29554
React view <table>: Spalten für beliebige Zeilenobjekte – berechnete Spalten, eingebettete Spalten referenzierter Objekte, dynamische Spalten; transiente Zeilen
#29556
react-api/tooltip runs without a TLSubSessionContext: a cell tooltip over a derived attribute using label() answers HTTP 500 (NullPointerException in Label.eval)
#29560
React view <upload-command>: Fehler beim Upload (Ausnahme in der Aktionskette, überschrittenes Größenlimit) erreichen den Benutzer nicht; Upload-Größenlimit konfigurierbar
#29562
security.xml grants for a SecurityScopeService scope are lost on the start that introduces the scope: AccessConfigurationSetupService imports before the scope exists and stores the file hash anyway
#29564
SecurityConfigurationService: an application cannot add a role to a framework type's grant — a <class> grant is keyed by operation and replaces the earlier entry, silently revoking the framework's roles
#29568
TL Views: Eine ohne Anmeldung aufgerufene Route geht beim Login verloren
#29573
TestReactStylesheetTokens fails on master: the pill and progress rules of tlReactControls.css do not keep the theme-token contract
#29574
TL Views: Veto eines verschachtelten Channel-Schreibzugriffs bricht die Benachrichtigung des äußeren Channels ab (Tabelle und Detailbereich bleiben nach "Verwerfen" auf dem alten Objekt)
#29576
React-Controls-Bundle enthält eine zweite React-Instanz (createPortal-Import in TLDropdownSelect)
#29586
tl-layout-react test compilation fails on master: TestSelectValueObservation and TestResourceCellObservation use the DefaultReactContext constructor that #29552 removed
#29590
React view: Mehrwertige String-Werte werden in Tabellenzellen und Anzeigefeldern ohne Trennzeichen aneinandergehängt
#29602
TL Views: a URL adopted into an existing session keeps the slot content of the sidebar item that was active before
#29604
ElementSecurityUpdateManager: quadratic collection diff on commit (AbstractSet.removeAll over a List) makes appending to a large reference take seconds
#29609
TL Views: a `<progress>` (ChannelObjectObserver) evaluates its expression on a deleted object and logs an ERROR when an observed object is deleted
#29610
TL Views: a table on an inactive tab shows stale cell values after the displayed objects changed, until its rows are refreshed
#29613
TL Views: a `<dashboard>` tile gets no definite height, so a table in a tile grows with its rows instead of scrolling
#29618
TL Views: a URL switches the sidebar away from an item with unsaved changes without asking
#29619
TL Views: a warning-level configuration constraint is dropped, so the model editor shows nothing
#29620
TL Views: a tree node is never a link to where its object is displayed, although the display targets declare one
#29622
TL Views: a `<flow-diagram selection="ch">` writes its channel but does not follow it, so a node selected elsewhere is not marked in the diagram
#29623
Build: the translate goal re-translates committed German messages after a pull or branch switch when the doclet did not run in the same build
#29626
TL Views: a panel toolbar has no overflow mode; at 400 px width the ticket page's six commands run 908 px wide, three of them unreachable, and the panel title is pushed out
#29627
TL Views table: an I18NString cell wraps its text and is clipped mid-glyph by the 36 px row instead of ending in an ellipsis; header labels are cut without an ellipsis
#29631
TL Views: Escape closes a <window> dialog while a <start-job> it started is still running; the job runs on with nothing left to show or cancel it
#29634
TL Views: the configuration editor builds a text field for a property whose format is parse-only, so selecting a derived attribute in the model editor fails with "There is no normative way to serialize a locator configuration"
#29635
TL Views: a <tree> renders every node as a link, so a click on the label navigates away instead of just selecting the node
#29639
TL-Script objectResolve(id, typeOrTable): resolution via a type including its subtypes or via a table name, objectTable delivers the table of an object, and an object the current user may not read is not resolved
#29644
Inkrementelle Security unvollständig bei Verwendung von scripted-steps
#29648
TL Views: Die über ClientResources ausgelieferten Skripte und Stylesheets tragen keine Version in der URL, der Browser verwendet nach einer Aktualisierung veraltete Client-Dateien
#29649
TL Views: a job's final state is overwritten by a stale "running" snapshot, so <job-status> shows a completed job as running
#29666
TL Views: leaving a frame by breadcrumb, Back, navigate-pop, show-object or logout discards a form's unsaved changes without asking
#29667
TL Views: a form in edit mode keeps showing stale values after a command committed a change to the same object
#29672
TL Views: initial-edit-mode, an object switch and the edit-mode channel enter edit mode without asking <edit-executability>
#29674
TL Views: after a page load, app-bar command labels appear in the browser's language instead of the user's ("Record" in a German session)
#29677
TL Views: a card in a content-sized column stack shrinks below its content; a table beside it takes more height than it reports
#29678
BoundHelper: Einstellung use-default-security-parent entfernen – ohne konfigurierte Security-Parent-Regel hat ein Objekt keinen Security-Parent
#29680
Classic UI: the anonymous session is offered the developer options and can run "Ressourcen neu laden"
#29698
CollectionUtil.removeDuplicates() verliert die Reihenfolge der Elemente
#29705
Workspace/PathInfo: web-fragment.war eines Moduls wird nicht gefunden, wenn Jar und Fragment aus verschiedenen lokalen Maven-Repositories aufgelöst werden (maven.repo.local.tail)
minor
#27889
Switch auf SNAPSHOT-Version funktioniert nicht
#28474
Hintergrundfarben der Knöpfe sind nicht konsistent
#29496
React table: a column resize is rejected with "Integer value expected" and the new width is lost when the client sends a fractional width
#29497
React UI tooltips: clipped table cells and column headers, compact toolbar buttons and attribute descriptions get tooltips; native title attributes replaced by bridge tooltips
#29503
TLResourceCell ships no CSS: icon and label touch wherever a resource cell shows both
#29505
Panel header changes height when its toolbar has no commands, so master-detail headers do not line up
#29508
Weitere QueryExecutor bedürfen keiner Security
#29552
TLPhotoViewer fetches its image after the control was disposed when a <switch> replaces it (404 on react-api/data, "Command target NOT FOUND" WARN)
#29555
TL-Script label(<constant>) is folded at compile time: the result is fixed to the compiling thread's locale instead of the reading user's
#29558
XMLInstanceImporter silently imports an internationalized attribute given as value="…" as empty, even when the attribute is mandatory
#29561
TL Views: display of a referenced object does not follow a change of its label (table cell, form field)
#29563
Standardgruppe: das persistierte Gruppen-Flag "defaultGroup" wird aus der Konfiguration abgeleitet statt in der Datenbank gespeichert; Semantik der Standardgruppe dokumentiert
#29591
ResKey.decode akzeptiert in #(…)-Literalen nur doppelt gequotete Übersetzungen — #('Travel'@en) schlägt fehl, obwohl TL-Script beide Quote-Arten erlaubt
#29606
TL Views: a `<color token>` naming a token the React theme does not emit renders the pill untinted, silently
#29628
TL Views: "Reset personal settings" clears the stored configuration, but the running session keeps its table state and writes it back; the declared column widths return only after a new login
#29636
TL Views: a click on a <tree> node clears the selection channel before setting it, so every dependent display and command flips to empty and back
#29663
TL Views: a <form> no longer insets itself; a <fields> grid inside a form got the page inset twice
#29664
TL Views: the form's Edit, Save, Cancel and Apply commands are labelled with a trailing period ("Bearbeiten.", "Speichern.")
#29668
TL Views: the rich-text editor's toolbar overflows a narrow field; table and undo/redo buttons are cut off
#29669
A request with a malformed query string ("?q=50%") is answered with an "Internal error" page (HTTP 500) instead of 400
#29673
TL Views: personalization commands ("Layout bearbeiten", "Diesen Filter speichern") are offered to the anonymous session
#29676
TL Views admin: deleting an account logs "Target object is deleted" from the still-open account form; delete asks for no confirmation
#29679
TL Views: a command refused by its executability rule is reported with the title "Interner Fehler"

task

minor
#29612
FAQ: Migration guide for upgrading an application from TL 7.11 to 8.0
#29702
Mindestversion von Maven im Build auf 3.8.9 anheben
enhancement

major

#29525

Offer the app-bar user menu in the core view layer

MigrationReactUI

Goal

An application built on the com.top_logic.layout.view layer has to assemble its app-bar account area by hand: a <derived-channel expr="currentUser()">, an <avatar> in the bar's <children>, and one flat placement="TOOLBAR" button per account action. The Consulting application does exactly that, and props it up with CSS that selects the buttons by their icon glyph because no per-command styling reaches the DOM.

The account area is offered here as a core view an application references, and extends through a same-path overlay - the way the administration view is already offered. What a user changes with a single decision is an entry of that menu; what wants a form is a dialog the menu opens. Everything found along the way is covered here.

A user menu, composed rather than built

An earlier attempt (ticket #29108) added a bespoke UserMenuElement with its own UserMenuControl and TLUserMenu React component, and was withdrawn in the same ticket because it reimplemented forms and buttons that the view layer already composes. The concept returns as a composition of existing parts:

  • WEB-INF/views/user-menu.view.xml in tl-layout-view, declaring its own currentUser channel, so an application adds the menu with a single <view-ref view="user-menu.view.xml"/> in the app bar and wires nothing.
  • An application adds, repositions or removes entries with a same-path overlay merged by the ViewLoader in dependency order, as tl-model-search-react already extends admin/admin.view.xml. The core module needs no knowledge of the contributor.

Its entries are Login (anonymous only), Change password, Settings and Logout (authenticated only), plus one per language and one per theme.

A generic menu carrier

ContextMenuElement already turns the commands declared inside it into a popup, filters them by visibility, groups them by clique and dispatches the selection - but only through a contextmenu event over the content it wraps. The single missing piece is a menu opened by clicking a trigger.

Rather than a second implementation, the contribution-building part of ContextMenuElement moved into AbstractMenuElement, and ContextMenuRegionControl together with TLContextMenuRegion became MenuRegionControl / TLMenuRegion, parameterized by a MenuTrigger: contextmenu places the menu at the pointer, click anchors it below the region's bounding box. Both report the viewport coordinates the menu appears at, so ContextMenuOpener needed no change.

The new <menu> element takes its trigger from its children - the same content property <context-menu> uses for its right-click region - so the two elements have one shape and differ only in the gesture. Every command declared inside a <menu> becomes an entry whatever its CommandPlacement: a command written inside a menu is an entry of that menu by construction, and CommandPlacement therefore needs no new value.

A menu builds one contribution per group of entries rather than one flat list, because ContextMenuOpener separates the entries of one contribution from those of the next. The commands written in the view are one group and each command source another, so the account actions, the languages and the themes are divided by separators, and a group with nothing to offer drops out together with its separator.

Commands derived at runtime

Feeding a menu from state rather than from configuration needed a seam: ViewCommandSource is a configured source of commands whose number and identity are known only at runtime, contributed through a menu's <command-sources> property and appended after the declared commands. Two of them are offered.

<theme-commands> contributes one entry per theme configured in UIThemeService, labelled and iconed by the theme itself, with the active one offered as disabled - which is both what it means and how the menu shows which theme is in effect. UITheme gains an icon property, since the theme is what knows how it looks, and SetThemeCommand exposes applyTheme so the source reuses the activation instead of copying it. A single SetThemeCommand cannot do this: it names one static theme id, so a view using it must spell out every theme it knows and can never tell which is active.

<language-commands> contributes one entry per supported locale of the ResourcesModule, labelled with the language's own name in that language - "Deutsch", "English" - which is what a reader looking for their language recognises and needs no translation of its own. Unlike a theme, a language cannot be applied to a rendered page, so the switch stores it on the account, tells the session and reloads. Neither source offers anything while there is only one choice, and the language source offers nothing to an anonymous session, which has no account to store a choice on.

A password is changed the same way from either side

ChangePasswordApplyAction read the account to change from LoginAction#ACCOUNT_CHANNEL and always ended by calling LoginAction.proceedAfterPassword, so change-password.view.xml could only continue a login. The coupling was incidental: the classic ChangePasswordComponent changes the password of a Person without any login in progress.

The account now falls back to the session's own when no login is waiting, and only a pending login - which is what the presence of that channel means - continues afterwards. change-password.view.xml shows its "your password has expired" hint only on that path, through a <switch> over the account channel, and is therefore one dialog serving both.

Personal settings

WEB-INF/views/settings.view.xml is a form over the account carrying what a single menu entry cannot express: the timezone and the country. It is over tl.accounts:Person, so the view module needs nothing of the Contacts model; a module that has it - or the application - contributes the profile fields through a same-path overlay, which tl-layout-view-contact does.

A user also sets their own second factor up here and drops it again, in the same enrolment dialog the login flow uses. The account keeps its requirement, since a factor the user chose is one they may drop again; each button is offered only in the state where it means something, decided by whether a secret is stored.

The account area closes the app bar

The account area was placed among the bar's inline children, which put it right of the title and left of everything else. Where it belongs is the other end, past the buttons of toolbar-placed commands - and the bar had no way to say so: its actions area is built from commands, and its leading area is the wrong end.

An app bar now takes a <trailing> region beside its <leading> one, and both compose the same way, because an app bar is horizontal and several elements at one of its ends stand side by side rather than stacked, which is what the generic content combination would do with them. An actions area ahead of the trailing one has already claimed the free space, so the trailing one does not claim it a second time and strand the command buttons in the middle of the bar.

One button bar in the settings dialog

The account tab wrapped its form in a <panel> to keep Save out of the other tabs, which gave that tab a button bar of its own beside the dialog's - Save in one, Close in the other - and the profile tab of tl-layout-view-contact did the same. A form contributes its commands to the enclosing scope only for as long as it is displayed, and a tab that is not the active one is not, so the panels are gone and Save joins Close in the single bar the dialog already has.

That holds only if the form exists when the bar is built. ReactTabBarControl created its active tab's content at the first write, by which time the enclosing button bar had been rendered without it: Save appeared only after leaving the tab and coming back. The content is now created when the tab bar attaches, ahead of the render, where the attach propagation that follows the hook reaches it.

The security tab lists buttons rather than fields, so nothing brought along the padding a form carries by itself and the buttons glued to the dialog border. An <inset> gives the list the same page inset, so both tabs hold their content at the same distance from it.

Leaving the session stands apart in the account menu

A menu draws a separator between the groups of entries it is composed of, and everything a view wrote was one group: the entry for leaving sat directly above the entries for settling in. A menu now takes further groups after the entries written in <commands>, through a <groups> property, each set off from the one before it.

This is the mechanism the separator already belongs to rather than an entry that draws a line: a group none of whose entries are currently available is left out together with its separator, so the account menu of an anonymous session - which offers Login and nothing else from the first group - still opens without a line above or below it. The account menu puts entering and leaving in the first group and what the account carries in the second; the two directions are one group because exactly one of them is ever offered.

A language and a country under their flag

The languages of the account menu were told apart by their own names alone, and a country field was 249 lines of text. Each now carries a flag.

The images come from the flag-icons stylesheet, which a webjar supplies and which offers one per ISO 3166-1 country code and a handful beyond it: the flag of a region, of a union, and of a language area that is no country. A flag is therefore an ordinary CSS-class icon and needs no plumbing of its own.

A country is an ISO 3166-1 code, so its flag needs no convention - only a resource provider saying so. The type had none registered at all and fell through to the default one, whose label for a country is the debugging form of the object; the contact module made up for that with a provider whose whole content was to label a country by its name. That labelling is what com.top_logic.util.CountryResourceProvider now does beside the type, so one provider answers for the label and the flag together.

Which flag stands for a language is a convention rather than a fact, so it is configuration: LanguageFlags states it for the well-known language tags - the flag of the country the language is most widely associated with, of the area it is spoken across where no single country carries it, and the fallback flag where neither applies. An application that disagrees overrides the entry it disagrees with. Entries are consulted most specific first, so a region carries its own flag only where the application supports that region as a language in its own right. A language no entry covers is given the fallback flag rather than nothing: a list in which some entries carry a flag and others do not reads worse than one in which they all do.

Both live beside the country type rather than in the view layer, so what presents a language or a country anywhere can name its flag.

A session begins where its own user begins

Logging in left the session on whatever page had been reached before it. The redirect that carries out the session swap points back at the URL the request came in on, and a URL naming a page asks for that page - so the start page of the user logging in never applied, because someone else's navigation had already answered the question for them.

A session that has just replaced another one is marked as such, and its first view request drops the route the URL still carries. The page then comes from the start page of whoever took the session over, or from the application's default when they have chosen none. Logging out is the same swap in the other direction and is treated the same way.

Defect: an option of a drop-down could not carry an image

A drop-down asked its label provider for an option's image and dropped it unless that provider happened to be a ResourceProvider - which the one it is handed never is. The client has carried the image of an option all along, in the option rows, the chips and the read-only values alike, and none of it could ever be reached: a select is built with the meta label provider, so the branch writing the image was dead for every drop-down in the application. The provider handed in is now the resource one, which answers for an image as well as for a label; the two registries of LabelProviderService fall back to each other, so a type registered only for its label is labelled exactly as before.

Two things the image then ran into, both of them the encoded form reaching a reader that could not read it. The image was encoded without being resolved, unlike the one of a button, so a reference - the icon a theme configures for a type - arrived as the reference, which the client has no theme to look up, and the whole encoded string became a CSS class: one containing a colon, naming nothing. And the invisible image encodes as a form of its own, which became an element carrying a class that draws nothing and still occupies the width of an icon, so every option of an enumeration was indented by an icon it does not have. It is now left out of the descriptor altogether, and both of the client's decoders answer it with nothing rather than with an element - it belongs to the vocabulary they decode, and one of them documented it while falling through to its CSS-class fallback. The drop-down also reads an option's image through the decoder the buttons, the menus and the sidebar use, rather than through the one that knew two of the prefixes.

Defect: per-command presentation does not reach the button

ViewCommand.Config declares css-classes, documented as additional CSS classes to apply to the command's UI element. It parses, it survives instantiation, and ViewCommandModel exposes it - and nothing reads it. The React CommandModel that ReactButtonControl serializes has no member for it, so no state key is written and the client has nothing to apply. A view author styling a command through the property gets no error, no warning and no effect. Reported against 8.0.0-alpha7 by the Consulting application, whose finding mark destructive actions better is exactly what the property is for; it works around the gap with

{{{#!css .tlReactButton:has(> .bi-trash) { color: var(--text-error); } }}}

a convention held by hand, which silently stops covering a delete button given a different icon and silently starts covering a harmless command given the trash one.

display is dead on the same path, for a narrower reason. ToolbarBuilder honours CommandModel#getDisplayMode(), so display="icon-only" works on a panel toolbar; the app bar builds its action buttons itself in AppBarElement, straight through new ReactButtonControl(context, model), and is therefore the path on which it is dropped.

Both are one omission: the constructor that wires a button from a CommandModel syncs label, executability, visibility, image, tooltip and key gesture, but neither of the two remaining presentation properties. The fix belongs there rather than in the app bar, so every call site is covered at once. A container now contributes only its default, through ReactButtonControl#setDefaultDisplayMode, which applies to a command requesting no mode of its own - keeping the icon-only-without-image guard in one place and reporting it once, as an author error about that command rather than about a container default that happens not to fit it. A MenuEntry carries the classes too, so the property behaves the same way on a command rendered as a menu entry.

Defect: a menu entry rendered no icon

TLMenu spliced an entry's icon into a class attribute in the encoded form that ContextMenuOpener produces. For css:bi bi-sun that yields the two classes css:bi and bi-sun, dropping the icon font's own base class, so no icon rendered; a /icons/... or theme:... entry rendered nothing either. Menu entries now go through ThemeIcon, which decodes the form, as buttons already did. Every context menu in the application was affected, not only the new one.

Defect: text on the accent app bar was unreadable

A text element brings the primary text colour along, which is near-black, and the accent bar it sits on is dark grey: the account name beside the avatar could not be read on a light theme. The bar already re-mapped foregrounds to its on-accent colour, but for a class nothing produces any more - the account area is a menu region, while the rule still named the element it replaced. It now matches the text elements actually rendered, so anything textual raised onto the bar is legible. The account area also hovered in the generic light hover colour, which left that on-accent text unreadable at the moment of pointing at it; on the accent bar it now hovers and opens in the accent's own darker shades.

Defect: an overlay was indistinguishable from the page on a dark theme

A popup floating above the page painted itself in the page's own surface colour, edged it with the subtle border and shadowed it with a literal rgba the theme never saw. On a light theme that passes; on a dark one the popup and the page behind it differ by four steps of grey and the shadow is invisible, so a menu had no discernible edge.

Popups now take the elevated surface, the strong border and the theme's own menu shadow - a token that was configured and unused. The elevated surface equals the page's on a light theme, so nothing changes there. Swept across the menu, the toolbar drop-down, the sidebar's group flyout and a field's option list, the last of which keeps the field colour it shares with the input it belongs to; the convention is written down beside the spacing model rather than in each rule.

Defect: every image was announced as a photograph

The image element announced whatever it displayed as a photograph - the case the underlying photo viewer was written for. The QR code enrolling an authenticator is not a photograph, and a reader who cannot see it learns nothing from being told it is one. An image element now takes an alt text, which the photo viewer prefers over its own default; left unset, the default stands.

Defect: a base view naming an overlay operation was unloadable

ViewLoader classified a view as an overlay fragment by searching the raw file text for config:operation, so a base view naming that attribute in a comment was taken for an overlay of itself, had no base to extend, and every dialog opening it failed - silently, because no ErrorSink is available on that path, leaving a dead menu entry. That is what settings.view.xml did by documenting, in its own header, the overlay it expects contributors to write. The decision now comes from the parsed document, where only an actual attribute in the configuration namespace counts, named through the existing ConfigurationSchemaConstants.

Defect: a language change did not reach the running session

Changing the language stored the choice and had no visible effect until the next login - which is why the classic UI offers no way to switch at all, only a form field that takes effect the next time you log in. Two layers were responsible.

Resources caches the bundles of one locale on the sub-session and reused them while isValid() held - and that tracks a reload of the resources module, not the locale the session asks in. So a session kept answering out of the bundles it was entered with, and setCurrentLocale changed nothing. The cached value is the bundles of one locale, so the cache check now validates the locale as well. Only Resources itself writes that cache, in getInstance and in withLocale, and both store the bundles of the sub-session's current locale, so the check follows what the cache already meant.

That alone left everything created after a switch following it - a dialog, a snackbar, the client's own strings - while the labels of the tree already on screen stayed as they were: a control resolves its labels when it is created, and a reload renders the tree the tab still holds rather than building a new one. A rendered tree is therefore a rendering of a view in a language, which is what RenderedView now records: the reuse check compares the locale beside the view path and the loaded element, so a language change rebuilds where an ordinary reload keeps what the user produced. Losing a scroll position to a language change is the point at which those two interests part.

ViewServlet also wrote lang="en" on the document however the page was rendered; it now names the language the page is actually rendered in.

Defect: a tab was labelled in whichever language loaded the view first

TabBarElement and BottomBarElement resolved their labels in the constructor. An element is parsed once and cached for the life of the JVM, shared by every session, so the text was the one language whichever session happened to load the view first asked in - the demo's tabs read German to an English user, and no language switch could move them. The entries keep the ResKey and resolve it where SidebarElement already did, when a control is built for the session being served.

Defect: a switch of sidebar entries composed a URL of no page

The sidebar reported the new item before the page being left was detached, so between the two the routing participant of the old page - the tab bar naming the tab it showed - was still registered and read as belonging to the new one. The wrong composition reached the address bar, not only the log. The page being left now goes first, and nothing observes the two together.

Verification

Verified in the browser on the React demo application, which the change also converts from a flat user label plus Login/Logout toolbar buttons to the user menu.

  • Anonymous: Login offered, no Change password / Settings / Logout, and no language entries. Logged in: the account name and avatar closing the app bar, the entries grouped by separators into leaving, the account's own settings, the languages and the themes - and the anonymous menu opens with no stray separator.
  • Theme: switching applies instantly with no reload, in both directions, the active theme offered as disabled each time; the entry icons render.
  • Language: switching applies within the session, in both directions, without a re-login - sidebar navigation, panel title, table toolbar, column headers, menu entry labels and date formatting all follow, and the choice survives a reload and a re-login. A plain reload still keeps a table's selection; only an actual language change resets it.
  • Flags: each language entry carries its own flag, and each of the 249 options of the country field carries the flag of that country, as does the selected one; every code resolves against the stylesheet. An enumeration's options carry no icon and are not indented by one, and an account option carries the icon its type is configured with.
  • Settings: one button bar per dialog, carrying Save beside Close on the account and profile tabs and Close alone on the security tab, on a freshly opened dialog as well as after switching tabs; the security buttons are inset like a form. Timezone and country persist to the account.
  • Start page: logging in from an anonymous session sitting on another page lands on the start page of the account logging in.
  • App bar: the account area closes the bar at both a wide and a narrow viewport, with the drawer toggle leading it, and the command buttons stay flush against it rather than mid-bar.
  • Right-click context menus still work, checked on the View Designer tree, including per-node executability.
  • No JavaScript errors and no server-side errors throughout.

Migration

Renamed. An application referring to these must follow:

com.top_logic.layout.view.command.ContextMenuRegionControl com.top_logic.layout.view.command.MenuRegionControl
React module TLContextMenuRegion TLMenuRegion
ContextMenuElement.DEFAULT_TARGET_CHANNEL AbstractMenuElement.DEFAULT_TARGET_CHANNEL

MenuRegionControl also takes a list of ContextMenuContributions instead of a single one, and a MenuTrigger. The <context-menu> element and its configuration are unchanged, so no view file needs editing.

Removed. com.top_logic.contact.layout.CountryResourceProvider is gone, together with the two contactConf.config.xml registrations of it. An application referring to the class must drop the reference: a country is served by com.top_logic.util.CountryResourceProvider, registered in top-logic.config.xml, which produces the same label and adds the flag. An application that registered the removed class for a type of its own must name the new one instead.

Signatures changed. ReactMenuControl.MenuEntry gained a cssClasses component, so a call of its canonical constructor needs the extra argument; the item(...) and separator() factories are unchanged and are the intended way to build one. UITheme gained an icon constructor parameter. ReactAppBarControl gained a trailing control parameter; the shorter constructors are unchanged and place nothing at that end.

Behaviour changed, no code change needed.

  • display and css-classes on a view command now take effect wherever the command is rendered. An application that relied on them being ignored will see its app-bar buttons change presentation, and one that worked around the gap in CSS (selecting a command's button by its icon) should drop the workaround in favour of css-classes.
  • An option of a drop-down now shows the image its type registers a ResourceProvider for, in the option list, the chips and the read-only display. An application whose types carry an icon will see it appear in every select; one that does not want an icon on a particular type registers ThemeImage.none() for it, which is rendered as no icon rather than as an empty one.
  • The language of a session is no longer fixed at login. An application caching locale-dependent state per session must invalidate it when SubSessionContext#getCurrentLocale() changes, and one resolving a ResKey while constructing a shared object (a UIElement, a cached model) must move that resolution to where the object is rendered for a session.
  • A language change rebuilds the control tree of the browser tab, discarding transient view state (scroll position, expansion, unsubmitted form input) that is neither in a channel nor in the personalization. An ordinary reload keeps it, as before.
  • Logging in or out no longer keeps the page the session was on. The account taking the session over starts on its own start page, or on the application's default where it has chosen none.
  • A popup - a menu, a toolbar drop-down, a sidebar group flyout, a field's option list - is painted from the elevated surface, the strong border and the theme's menu shadow. A theme that defines layer-02, border-strong or shadow-menu differently from the standard themes will see its popups follow those values.
  • Get Started
  • Github
  • Discord
  • Das Unternehmen hinter TopLogic
  • Softwareentwicklung heute
  • Kontakt

© Copyright – Business Operation Systems GmbH

  • top-logic.com
  • Nutzungsbedingungen
  • Impressum
  • Rechtlicher Hinweis
  • Datenschutz
  • EN
  • Login