enhancement
major
major
major
#29812
TL Views: a table column declares its own comparator; enumeration columns follow the enumeration's order
tl-layout-view / tl-layout-react 8.0.0-alpha10, table grouping (#29544).
Problem
ListRowSource orders the groups of a grouped table with the comparator of the grouping column, and every column a view can declare has one (a <computed-column> sorts by its value), so the groups always appear alphabetically. A table grouped by a value that has an order of its own, in E-Home the pages of an application program's structure ("0: Generic › Allgemein", "… › Wippe 1", … in the order of the structure), cannot keep that order; the user sees the pages sorted by name.
The column declarations of a <table> (<column>, <computed-column>, <dynamic-columns>, <embedded-columns>) offer no way to state how a column sorts: the comparator is always derived from the type of the values. A column over an enumeration sorts by the labels of the classifiers, although an enumeration declares its order (the classifier order is the presentation order unless the enumeration is annotated <unordered-enum/>, see TLEnumeration#isOrdered()), so the ticket demo grouped by status shows "Closed, In progress, Open" instead of the workflow order.
Workaround in E-Home
de.haumacher.ehome.view.RowOrderColumn, a <row-order-column> extending <computed-column> that drops the sorting from the built column; the row source then keeps the groups in the order of their first rows. This only holds as long as nobody sorts the table: the rows reach the row source sorted by the user's sort, so "row order" of the groups is the order of each group's first member after that sort.
Lösung
Column comparator. Every column declaration (<column>, <computed-column>, <dynamic-columns>) takes a <comparator> function in the contract of the TL-Script sort function: a function of two cell values yielding a negative number, zero or a positive number. The column sorts its rows and orders its groups by this function instead of the comparator derived from its type. The function is never passed an empty value; rows without a value are ordered apart from it and a group without a value comes last. The usual case orders by a key and is written with the TL-Script comparator(key) function:
<computed-column name="page" type="ehome:Page"> <value>param -> $param.get(`ehome:Parameter#page`)</value> <comparator>comparator(page -> $page.get(`ehome:Page#position`))</comparator> </computed-column>
A grouping by that column then keeps the pages in structure order, whatever the user sorts by, and sorting the column itself orders by the structure as well. In <dynamic-columns> the values of the declared inputs precede the two compared values, as in its other functions, and every column of the set shares the function. An embedded column (<embedded-columns>) keeps the comparator of the column it embeds; where the reference path reaches several objects, the collected values are compared element by element with it. A column with a scripted <filter> compares the cell values the filter wraps.
Enumeration order. A column over an enumeration sorts by the enumeration's own order: by the classifier order for an ordered enumeration, by the classifier labels only for an enumeration annotated <unordered-enum/> - the order the classic UI applies to classifiers everywhere (FastListElementComparator). Groups by such a column follow suit; the options filter of the column already offers the classifiers in declaration order.
Demo. tl-demo-react: Demos → Table columns → tab "Group order" groups contributors by a computed load class (none, few, many) ordered by a declared comparator; the ticket list grouped by status reads Open, In progress without configuration.
The option requested originally (group-order="rows", keeping the groups in the order of their first rows) is not built, see the workaround section for why it is not a stable order.