Migrating a TopLogic application from 8.0.0-alpha10 to 8.0.0-alpha11
Audience: an AI coding agent (or developer) upgrading a TopLogic application project.
Sources: release notes https://dev.top-logic.com/tl/content/releases/TL_8.0.0-alpha11/ and the
TopLogic Trac tickets of milestone TL_8.0.0-alpha11 (ticket numbers given as #NNNNN; the
per-ticket page is https://dev.top-logic.com/tl/content/releases/TL_8.0.0-alpha11/NNNNN/).
How to use this document
- Work through the sections in order. Section 1 first (the project must build); the rest in any order.
- Every step has a Detect line: run the search in the application's source tree. No hit → the step does not apply, skip it. Do not invent changes for steps that do not apply.
- Many changes surface only as configuration errors at application start or when a view is loaded. After migrating, start the application, log in, open every view, and read the log.
- The engine ships developer articles in its jars (
META-INF/tl-docs/**/*.md). If thetl-mcptools are available, read them withread_doc(names given asdoc:<name>). - If the application comes from TopLogic 7.10 / 7.11, follow the upgrade guide
doc:upgrade-7.11-to-8.0first (#29790); it covers all 8.0 changes in the required order and needs Maven 3.8.9 or newer. - If you continue to 8.0.0-alpha12 afterwards: alpha12 changes view scripts again (named arguments, no lambda heads, see the alpha11→alpha12 guide). Still do the alpha11 steps first; they are the basis of the alpha12 rules.
Search commands assume the project root as working directory and GNU grep.
1. Build, wrapper generation, Java API
1.1 Version bump
Set the TopLogic version to 8.0.0-alpha11 (parent tl-parent-app / tl-parent-core version, or
the tl.version property).
1.2 Snapshot repository (#29789) — only for SNAPSHOT versions
tl-parent-all no longer declares the TopLogic snapshot repository. An application inheriting the
TopLogic parent POMs and building against a TopLogic SNAPSHOT from the TopLogic Nexus must declare it
itself (archetype-generated applications already do). Released versions need no change.
<repositories>
<repository>
<id>tl-snapshots</id>
<url>https://dev.top-logic.com/nexus/repository/toplogic-snapshots/</url>
<releases><enabled>false</enabled></releases>
<snapshots><enabled>true</enabled></snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>tl-snapshots</id>
<url>https://dev.top-logic.com/nexus/repository/toplogic-snapshots/</url>
<releases><enabled>false</enabled></releases>
<snapshots><enabled>true</enabled></snapshots>
</pluginRepository>
</pluginRepositories>
Detect: grep -n -e 'SNAPSHOT' -e 'tl-snapshots' pom.xml */pom.xml
1.3 Regenerate the Java wrappers (#29806, #29807) — mandatory if the app uses generated wrappers
Run the wrapper generation (tl:generate-java / the module's generate step) for all application modules,
then fix compile errors:
- #29806: after regeneration, a class that does not specialize
tl.element:StructuredElementgetsAttributedWrapperas implementation base (before: every top-level class of a module with a singleton extendedStructuredElement). Code treating such objects asStructuredElement(casts,getParent(),getChildren()) no longer compiles → correct the code, or let the model class declare thetl.element:StructuredElementgeneralization it relied on. TheXImplof a class whose primary generalization is a concrete or bound type now extends that type's implementation class (hand-written code unaffected). - #29807: factory members for classifier constants are deprecated (still compile). After regenerating, replace their uses (optional, recommended):
| Old (deprecated) | New |
|---|---|
MyFactory.MY_MODULE_STRUCTURE |
MyFactory.MY_MODULE_MODULE |
MyFactory.KO_NAME_A |
A.TABLE_NAME |
MyFactory.MY_ENUM_ENUM |
MyEnum.TYPE_NAME |
MyFactory.FIRST_MY_ENUM_CLASSIFIER |
MyEnum.FIRST_CLASSIFIER |
MyFactory.getMyEnumEnum() |
MyEnum.type() |
MyFactory.getFirstMyEnumClassifier() |
MyEnum.firstClassifier() |
A factory that did not compile because of colliding classifier names compiles after regeneration (colliding legacy aliases are not generated).
Detect: grep -rln -e 'StructuredElement' -e 'getParent()' -e 'getChildren()' --include=*.java src and
grep -rn -E '[A-Z][A-Za-z]*Factory\.(KO_NAME_|[A-Z_]+_(ENUM|STRUCTURE|CLASSIFIER)\b|get[A-Za-z]+(Enum|Classifier)\()' --include=*.java src
1.4 Wrapper hierarchy clean-up (#29840) — Java
- Calls to deleted members of
AbstractWrapper,StructuredElementWrapper,WrapperFactoryno longer compile (they had no engine callers) → use the replacement or remove. touch()→TLObject.tTouch().handleLoad(),handleDelete(),notifyUpcomingDeletion()are public interface methods ofWrapperLifecycle: overrides in application code must be declaredpublic.resolveWrappers,resolveWrappersTyped,resolveLinks,updateOrderedLinkSetare publicWrapperdefaults; typed accessors (getString(String), …) and theAbstractBoundWrappermethods are no longerfinal. Overrides ofgetValue(String)/setValue(String, Object)ortValue/tUpdatekeep working.instanceof AbstractBoundWrapper→BoundObject/BoundWrapper;instanceof AbstractWrapper→Wrapper.
Detect:
grep -rn -e 'touch()' -e 'handleLoad()' -e 'handleDelete()' -e 'notifyUpcomingDeletion' \
-e 'instanceof AbstractBoundWrapper' -e 'instanceof AbstractWrapper' --include=*.java src
1.5 SimpleDBExecutor (#29838) — Java, rare
The unused methods beginTransaction(CommitHandler), releaseCommitContext(), beginWithDefaultKB() are
removed; a SimpleDBExecutor only works with its own transaction started by beginTransaction().
Detect: grep -rn -e 'releaseCommitContext' -e 'beginWithDefaultKB' -e 'SimpleDBExecutor' --include=*.java src
2. Server configuration
2.1 Access parent in the security configuration (#29760) — mandatory if used
(Has a migration section in Trac but is not listed on the release-notes website.)
The access parent of a type is no longer set by the attributes access-parent / access-reference of a
<class> entry of SecurityConfigurationService, but by an element <access-parent> with exactly one
definition. The old attributes are rejected at startup.
| Old | New |
|---|---|
access-parent="container" |
<access-parent><container/></access-parent> |
access-parent="container" access-reference="X" |
<access-parent><container reference="X"/></access-parent> |
access-parent="target" access-reference="X" |
<access-parent><target reference="X"/></access-parent> |
access-parent="self" |
<access-parent><self/></access-parent> |
access-parent="auto" |
remove the attribute |
Also check WEB-INF/autoconf/com.top_logic.model.security.SecurityConfigurationService.config.xml (the
"Access rights…" dialog of the coverage view writes there). Java: record TypeCoverage holds the origin
of the marks (withoutSecurityOrigin, internalOrigin) instead of booleans; withoutSecurity() and
internal() remain. New in this release: a TL-Script function can determine the access parent.
Detect: grep -rn -e 'access-parent=' -e 'access-reference=' -e 'TypeCoverage' .
2.2 OpenAPI server: request body validation (#29785)
Requests whose body does not match the declared schema (incomplete properties with
additionalProperties: false, wrong required lists, wrong types) are now answered with 400. A schema
that cannot be translated prevents the OpenAPI server from starting. Fix the schema in the OpenAPI
server's service configuration to match the actual values, or remove the schema from the parameter if no
validation is wanted. Test every operation with real requests.
Detect: grep -rln -e 'OpenApiServer' -e 'request-body' -e 'additionalProperties' --include=*.xml .
2.3 OpenAPI server: empty passwords / API keys (#29784) — no RequiresMigration flag
Basic authentication (technical user) and API-key authentication now ignore a secret with an empty
password / key (error in the log naming domain and user/parameter) and always reject requests with an
empty password/key. If an environment variable behind an alias is unset (e.g. ${env:api_passwd}), the
operation is no longer reachable (500, missing-secret message) instead of being open. Make sure all
deployment environments set these variables.
Detect: grep -rn -e 'basic-auth-server-secret' -e 'api-key-server-secret' -e '\${env:' .
2.4 Encrypted configuration values (#29788, #29849) — check, no mandatory step
- A plain-text value in an
@Encryptedproperty without the prefixunencrypted:fails as before, but the error message no longer contains the value. - New encrypted values are written in a new format (prefix
{gcm}); an invalid value in this format is a configuration error. Values without prefix are still read with the old method — no migration needed. - If startup now fails with an "undecodable value" error for a property, add
unencrypted:to plain-text values (typically passwords coming from an environment variable via an alias) or encrypt them properly.
3. React views (*.view.xml)
3.1 Unified drag and drop (#29776) — mandatory if the views use <drag>/<drop>
<drag type="module:Type">no longer exists →<drag kind="…">with a freely chosen name (e.g.ticket).<drop accept="…">names drag kinds, not model types: replaceaccept="module:Type"by the kind of the matching<drag kind>, or omitacceptto accept every drag. A restriction to a model type (before: including subtypes) moves intorefuse-if, e.g.objects -> !$objects.filter(o -> !$o.instanceOf(`module:Type`)).isEmpty()(the type literal needs both backticks; the published release notes lost the closing one).refuse-ifreceives the dragged objects as first argument:target -> objects -> …becomesobjects -> target -> …. Per drop kind (targetattribute of<drop>):
| Element | target |
Meaning | refuse-if arguments |
Channels |
|---|---|---|---|---|
<table> |
table |
onto the table as a whole | objects -> target -> reason (target = null) |
target-channel |
<table> |
row |
onto a row | objects -> target -> reason |
target-channel |
<table> |
ordered |
between rows (insertion line); beside the rows = at the end | objects -> before -> reason |
before-channel |
<tree> |
tree / node / ordered |
as above; ordered = between siblings or as child |
objects -> parent -> before -> reason (ordered) |
parent-channel, before-channel |
<tree-table> |
table / row / ordered |
as for the tree | as for the tree | as for the tree |
A script with fewer parameters ignores the rest (objects -> reason is enough). Misplaced options
(e.g. target-channel with ordered, parent-channel in a flat table, target-executability outside
row/node) are configuration errors.
- Several
<drop>on one element are checked in declared order (before: row drops before table drops) → reorder mixed drops if needed. - Java:
DropTarget#dropOnRows()→dropModes(),acceptedTypes()→acceptedKinds(),check(DropEvent)→check(DropRequest),DragSourceControl#dragType()→dragKind()/isDragEnabled();DropEventcarries aDropLocationinstead of target andDropPosition(DropPositionremoved).
Detect:
grep -rn --include=*.view.xml -e '<drag' -e '<drop' -e 'refuse-if' .
grep -rn --include=*.java -e 'dropOnRows' -e 'acceptedTypes' -e 'DropEvent' -e 'dragType()' -e 'DropPosition' .
3.2 <adaptive-detail> (#29801)
- Attribute
detail-sizeof<adaptive-detail>is renameddrawer-size. - Content inside
<selector>/<detail>that stores personalization (e.g. table column widths) uses a new personalization key; stored values are lost once (inform the user, nothing to migrate).
Detect: grep -rn --include=*.view.xml -e 'detail-size' .
3.3 <text> tone and text classes (#29821)
<text tone="accent">no longer loads (ConfigurationException listing allowed values) → usecss-class="tl-type-body-strong".css-class="tlText--strong"has no effect →tl-type-body-strong(label variant:tl-type-label-strong).
Detect: grep -rn --include=*.view.xml -e 'tone="accent"' -e 'tlText--strong' .
3.4 <value-input> with <on-submit> (#29808) — behavior change, no RequiresMigration flag
New attribute submit-on decides when the <on-submit> command of a typed input runs. Text and number
inputs are unchanged (Enter). Multi-line text, password and I18N text inputs with <on-submit> ran on
every value change before; without submit-on="change" they now run only on their Enter gesture
(password) or not at all (multi-line text, I18N text). Add submit-on="change" where the old behavior is
needed (the "Apply with Enter" placeholder then disappears).
Detect: grep -rn --include=*.view.xml -B3 -A3 '<on-submit' . (check the input type of each hit)
3.5 Column selection state (#29825) — custom code only
The state of ReactColumnSelectControl changed. Only relevant for code/adapters reading that state;
opening the dialog is unaffected. Note: the published migration text ("grouping is one value instead of a
flag per entry") describes a superseded design. According to the Trac comments, the dialog that shipped is
a layer panel: a row is handle · name · lock · eye (no checkbox), hidden columns stay in place (dimmed),
the lock freezes a column (same frozenColumnCount as the freeze handle in the header), and grouping is
no longer in the dialog — it is in the column header's context menu. Inspect the actual state contract
in the engine source before adapting custom code.
Detect: grep -rn -e 'ReactColumnSelectControl' -e 'TLColumnSelect' .
4. Custom React components / component library (#29787)
Only relevant if the application customizes the React client (e.g. installMui, own adapter modules).
installMui({ replace })selects atomic parts by part name, not control name. An old name fails at startup (unknown component). Withreplace: 'all'nothing to do.
| Old name | New part name |
|---|---|
'TLButton', 'TLToggleButton' |
'Button' |
'TLCheckbox' |
'Checkbox' |
'TLTextInput', 'TLPasswordInput', 'TLNumberInput' |
'TextInput' (read-only values: 'FieldValue') |
'TLOptionChips' |
'Chip' |
'TLProgress' |
'ProgressBar' |
| — (new) | 'MenuTrigger', 'DisclosureToggle', 'Badge', 'Divider', 'Spinner' |
- Own modules replacing
TLButton,TLToggleButton,TLCheckbox,TLTextInput,TLPasswordInput,TLNumberInput,TLOptionChipsorTLProgresswithreplace()must instead replace the part withreplacePart()and implement its props contract (ButtonPartProps,CheckboxPartProps, …; seedoc:view-layer/parts). Command, keyboard and visibility logic stay in the control. - The configured CSS class of text, password and number fields now sits on the outermost element of the
field (
tl-field-group), not on the<input>: CSSinput.myClass→.myClass input. - (#29808) The bridge hook
useTLTypingField()replacesuseTLSubmitOnEnter()and the MUI-internaluseTypingField(); custom typed inputs using the old hooks must switch.
Detect:
grep -rn -e 'installMui' -e 'replace(' -e "'TL\(Button\|ToggleButton\|Checkbox\|TextInput\|PasswordInput\|NumberInput\|OptionChips\|Progress\)'" \
-e 'useTLSubmitOnEnter' -e 'useTypingField' --include=*.ts --include=*.tsx --include=*.js .
grep -rn -E 'input\.[a-zA-Z_-]+' --include=*.css .
5. Stylesheets: design system waves 3b, 4a, 4b, 4c (#29821, #29836, #29866, #29870)
Only relevant if the application has own CSS (or code) addressing the old tl* classes of React
controls. General rule: states are attributes, not classes (aria-selected, aria-sort,
aria-expanded, aria-current, data-tl-state, data-tl-role, data-tl-tone). The complete old→new
tables are in the design system repository, docs/migration/altlast.md, sections "Welle 3b", "Welle 4a",
"Welle 4b", "Welle 4c". Rewrite affected rules against the package classes; do not reintroduce old names.
5.1 Table, tree, column selection, text (#29821)
Removed: tlTableView*, tlTreeView*, tlColumnSelect*, tlColumns*, tlText*, tlRelativeTime,
tl-pill--<role>, tl-avatar--category-<n>, tl-alert--<status>, tl-alert--closable,
tl-select__status. Stylesheets reading --tl-status-error-border / --tl-status-warning-border see a
darker line in light mode.
5.2 Dialog, window, drawer, snackbar, notice bar (#29836)
Removed: tlDialog*, tlWindow*, tlDrawer*, tlSnackbar*, tlNoticeBar*, tlOverlay*,
tlPhotoCapture__overlay*.
- Dialog animations:
.tlDialog__backdrop--entering/--exiting→.tl-dialog[data-tl-state~="entering"]/[data-tl-state~="exiting"](the package ships a fade; override on the same state). --tlSnackbar-bg/--tlSnackbar-fgare gone (snackbar is a tinted alert,data-tl-role)..tlOverlay__layer--<anchor>→.tl-overlay__layer--<anchor>.
5.3 App shell, app bar, sidebar, bottom bar (#29866)
Removed: tlAppShell*, tlAppBar*, tlSidebar*, tlBottomBar*, tlDrawerToggle. Small-screen rules read
[data-tl-display~="compact"] on .tl-app-shell instead of @media (max-width: 768px). Visible: app bar
48px (40 compact), sidebar a modal drawer on small screens, hamburger only on small screens.
5.4 Layout containers (#29870)
Removed classes tlPanel*, tlCard*, tlStack*, tlGrid*, tlInset, tlBounded, tlItem, tlDeckPane,
tlSplitPanel*, tlTileStack*, tlWizard*, tlAdaptiveDetail*, tlViewError*, tlHtml__error; dialog
footer tl-dialog__footer is now tl-button-bar. Removed custom properties --page-inset (insets come from
tl-inset, tl-inset--panel, tl-inset--card) and --tlGrid-gap; --tl-item-index → --item-index.
States: panel [data-tl-state~="minimized"|"maximized"]; split pane [data-tl-state~="collapsed"], all
[data-tl-state~="all-collapsed"]; tile stack/wizard transitions [data-tl-state~="entering"|"exiting"|"covered"|"backward"];
wizard steps [data-tl-state~="done"], current [aria-current="step"]; selected item [aria-selected="true"].
| Old | New |
|---|---|
.tlPanel |
.tl-panel |
.tlPanel--card |
.tl-panel.tl-card |
.tlPanel__header, __title, __toolbar, __actions |
.tl-titlebar, __title (h2), __actions, __buttons |
.tlPanel__content |
.tl-panel__body |
.tlPanel__buttonBar, .tl-dialog__footer |
.tl-button-bar |
.tlCard, --outlined, --elevated |
.tl-card (surface by nesting: --nested, --overlay; no shadow) |
.tlStack, .tlGrid, --gap-* |
.tl-stack, .tl-grid, --gap-compact/default/loose |
.tlInset |
.tl-inset |
.tlBounded, .tlItem, .tlDeckPane |
.tl-bounded, .tl-item, .tl-deck |
.tlSplitPanel, __child, __splitter |
.tl-split, __pane, __handle (role="separator") |
.tlTileStack, __frame |
.tl-tile-stack, __frame |
.tlWizard* |
.tl-wizard* |
.tlAdaptiveDetail, __breadcrumb |
.tl-adaptive-detail, __bar > .tl-breadcrumb |
.tlViewError, .tlHtml__error |
.tl-alert[data-tl-role="error"] |
Visible changes (expect, do not "fix"): narrower gaps (1rem), untinted panel heads with non-bold 40px titles, card bodies padded 1rem, no card shadows, split handle as a line (keyboard-movable).
Detect (all of section 5, including css-class values in views):
grep -rn -E 'tl(TableView|TreeView|ColumnSelect|Columns|Text|RelativeTime|Dialog|Window|Drawer|Snackbar|NoticeBar|Overlay|AppShell|AppBar|Sidebar|BottomBar|DrawerToggle|Panel|Card|Stack|Grid|Inset|Bounded|Item|DeckPane|SplitPanel|TileStack|Wizard|AdaptiveDetail|ViewError)|tlHtml__error|tlPhotoCapture__overlay|tl-pill--|tl-avatar--category-|tl-alert--|tl-select__status|tl-dialog__footer|--page-inset|--tlGrid-gap|--tl-item-index|--tlSnackbar-' \
--include=*.css --include=*.java --include=*.ts --include=*.tsx --include=*.xml --include=*.html .
6. Further notes (no RequiresMigration flag, but possibly relevant)
-
Known regression in alpha11 (#29870 → fixed by #29933 in alpha12): dragging the handle of a
<split-panel>with the mouse "runs away" (movement accumulates). Keyboard and double-click reset work. Probably also affects the split of<adaptive-detail>. Not a migration step — do not try to fix it in the application; mention it to the user, or move on to alpha12. -
Maven (#29790, #29789): Maven 3.8.9 or newer is required. A POM that does not inherit the TopLogic parents should pin its build plugins (e.g.
maven-compiler-plugin,maven-resources-plugin); otherwise Maven 3.8.x may bind ancient plugin versions. -
Model patch (#29800): a class may gain a generalization and override attributes in the same change; the generated SQL migration processors now apply
add-generalizationbefore the overrides. If the application worked around this with split migrations, they can stay but are no longer needed. -
Column type changes (#29846):
AlterColumnProcessor/RecollateStringColumnsProcessornow work on Oracle for columns with content and on MS SQL Server for indexed columns — migrations that failed there before can be retried. -
Table
row-class(#29815): new<table row-class="row -> …">/<composition-table row-class=…>; with<inputs>the input channel values come first and the row object last. (In alpha12 these scripts lose their lambda head.)
7. Verification checklist
- Regenerate wrappers, then
mvn clean install(enable tests if possible). - Start the application; read the startup log for configuration errors (
access-parent, OpenAPI schemas, unknown MUI part names,<text tone>,detail-size, drop configuration). - Log in, open every React view; try every drag-and-drop interaction (kinds, order,
refuse-if). - Call every OpenAPI operation with realistic request bodies (400 = schema mismatch); check that technical users have non-empty passwords in every environment.
- Check custom styling visually (tables, trees, dialogs, app shell, panels, cards, split panes, wizard).
- Report to the user every skipped step and every user-visible effect (lost personalization of
<adaptive-detail>content, changed<on-submit>behavior, visual changes).