Rules: view logic
Forms
Form rules
-
To place several objects in one table at once, the assistant SHOULD combine them into one object group using brackets.
-
In a
FORM ... ORDERSclause, the assistant MUST use only form properties that were already added to the form via aPROPERTIESblock.In
ORDERS, the assistant MUST specify either:- the form property name with its parameters, if no explicit alias was given
- the explicit form property alias, if such an alias was specified
Raw expressions, objects, or properties not added to the form MUST NOT be placed into
ORDERS. -
The assistant MUST NOT use
INPUTinside actions added directly to a form throughPROPERTIES, unless that action is used in anON CHANGEhandler: a built-in-class value is entered in the editor of the property whose change is being handled, so outside a change handler there is nowhere to render it. The exceptions are file and color values, which are entered through a separate dialog and MAY be requested from any form action.To request values from a button instead, the assistant SHOULD either place the input properties on the form itself (data properties, including local ones, in a panel) and read them in the action, or open a dialog form returning the entered values (
DIALOGwithINPUT-marked objects). -
The assistant MUST NOT display internal object identifiers on a form, including through object-valued properties: an object value is displayed as its internal identifier — a number that tells the user nothing.
Meaningful primitive or derived primitive / text properties MUST be exposed instead.
The most common case is a link to a static object of an enumeration class (
status = DATA Status (Project)): the platform does NOT substitute the static object's caption by itself. The form exposes the caption composition —captionStatus 'Status' = caption(status(p)): a write through the composition goes into the link, not into the static object's caption (see rule 7), and with a small number of options, as enumerations have, the web client shows it as a selection element (button group / list / dropdown — by the number of options and the length of the captions). -
A
PANELobject of a user-defined class is NOT user-selectable by default.If such an object is meant to be chosen by the user (for example, a filter parameter shown on the form), the assistant MUST mark a displayed property of that object with
SELECTORin thePROPERTIESblock.Without
SELECTOR, the panel cell does not open a selection dialog and the object cannot be changed. The assistant MUST NOT assume a panel cell is editable by analogy with grid editing. -
In a form
PROPERTIESblock, the parameter style on the property or action being added to the form MUST match the block header:- With a common-parameter header
PROPERTIES(p1, ..., pN), each entry MUST be specified by its ID only — the common parameters are bound implicitly. WritingpropName(p1, ..., pN)after the ID is a parse error. - With no common-parameter header (just
PROPERTIES), each entry MUST carry explicit parentheses, e.g.propName(t)with parameters, orpropName()/actionName()for parameterless properties and actions. Parentheses are MANDATORY even when there are no parameters — empty parentheses MUST still be written. Writing the bare name without parentheses is a parse error.
The assistant MUST NOT mix the two styles in one block, and MUST NOT repeat the common parameters after the property name when a common-parameter header is in use.
This rule applies only to the entry being added to the form. Argument lists inside option clauses such as
ON CHANGE actionName(...),READONLYIF expr,BACKGROUND expr, etc. are regular action calls / expressions and ALWAYS use explicit parameters, regardless of the block header.An entry whose expression carries a comma not enclosed in brackets of its own needs a form this block accepts: with no common-parameter header, write it as
alias = (expr), since a bare(expr)is a parse error; withPROPERTIES(o), an entry is a property usage even afteralias =, so no expression is accepted at all and the only remedy is a named property added by its ID. - With a common-parameter header
-
The default
CHANGEhandling of a property shown on a form is derived not from what its expression looks like, but from the property's write path: changeable properties are data properties, the selection operator, and compositions of changeable properties — a write is passed through the composition into the underlying changeable property. The write path is not visible at the usage site, so the assistant MUST NOT assume that a computed-looking property is non-editable.Outwardly similar entries are edited differently:
- a composition through an object link (
name(customer(o))) — the user is offered a choice of the linked object, and the link (customer(o)) is written; this is the usual way of entering data; - an attribute of the row object itself (
name(c)) — the entered value is written in place, that is, the object is renamed; - a property of a static object (
caption(st)) — the write goes into the stored caption of the static object and lasts until the next synchronization of the database with the code (normally at server startup), which restores the caption from the code.
Every property displayed for reading only MUST be explicitly marked
READONLY— in all form contexts: not only in the grids of list forms, but also in panels, dialogs, dashboards, and charts. When the whole block is displayed for reading only, the block SHOULD be marked as a whole (PROPERTIES(o) READONLY ...) rather than every entry; marking an individual entry remains for blocks where some entries are meant for input. In browsing and selection contexts every entry carries an explicitREADONLYexcept the ones deliberately meant for input. The explicit mark also documents intent for the code reader. - a composition through an object link (
Flow rules (WAIT, NOWAIT)
-
With neither option given, the platform picks the mode itself: the operator works synchronously when the form opens in a modal location, when the form it is opened from is modal, or when the current session may still be used afterwards, and asynchronously otherwise.
Two calls that look the same can therefore behave differently. Where the code after the call depends on the form having been closed, or must run without waiting for it, the assistant MUST say so explicitly — with
WAITorNOWAITonSHOW, which is the only operator whose syntax takes them.DIALOGhas no such option: it is synchronous whenever its result is consumed, and left to the same heuristic otherwise. When a dialog must block, the assistant makes it block by using what it returns.
Form design
-
These design rules do NOT cover the
DESIGNlayout model — the default container tree, the flexboxfill/ alignment model, or the container idioms. They give only placement meta-advice. Before writing or modifying anyDESIGN, the assistant MUST retrieve theForm_designdocumentation; it MUST NOT rely on these rules as if they described the layout model.The complete tables of the properties of components of every kind (containers, components of properties and actions on the form, toolbars, grids) live in the
DESIGNstatement documentation (DESIGN_statement). When setting a component property, the assistant MUST check its name and allowed values against those tables, and MUST NOT guess them by analogy. -
The assistant SHOULD specify a
DESIGNfor all interactive forms containing more than four properties. -
Exception: for a trivial form with only one or two objects in
GRIDmode and no other properties displayed inPANELmode, omittingDESIGNis acceptable. -
In
DESIGN, the assistant SHOULD prefer movingBOX(...)containers for tables first.GRID(...)SHOULD be used only when absolutely necessary. -
If possible, the assistant SHOULD avoid form designs with more than two tables stacked vertically and more than two tables placed horizontally.
-
Custom actions added to a grid form (status changes, document generation, bulk operations) MUST be given an explicit
TOOLBARview, e.g.PROPERTIES(o) confirmDoc TOOLBAR. Actions default to thePANELview, so withoutTOOLBARthe custom button is drawn as a separate group below the table instead of in the grid toolbar next to the predefinedNEW/EDIT/DELETE, to which the platform gives that sameTOOLBARview — so they share theTOOLBARcontainer with it, not theTOOLBARSYSTEMone, which is where aMOVEorREMOVEof the wrong container goes astray. The property / action views areGRID,TOOLBAR,PANEL, andPOPUP. -
A
TEXT-typed property displayed as a grid column is rendered as a multi-line row four lines tall by default, degrading list density. Such columns commonly result from the standard string properties (lpad[TEXT, INTEGER, TEXT],substr[TEXT, INTEGER, INTEGER],trim[TEXT]and the rest): they, as a rule, returnTEXTregardless of the argument classes, and concatenating aTEXToperand with a bounded string keepsTEXTas well. On list forms, the assistant SHOULD instead expose the value cast toSTRING[n]. The cast entry follows the expression-entry rules: in aPROPERTIESblock without a common-parameter header, with an explicit alias (shortNote = STRING[100](note(o))). A bare cast without an alias, like any expression inside a common-parameter header blockPROPERTIES(o), is a parse error — there, declare a named property with the cast and add it by its ID. -
To display data, the assistant MUST first consider the standard object group view types: the table, the pivot table with its charts (
PIVOT), the calendar (CALENDAR), the map (MAP). A custom view on a React component — aDESIGNcontainer with thecustomattribute; web client only, the desktop client renders the container's regular subtree — is used when something beyond a simple table, a simple calendar, a simple chart, or a pivot table is needed: a kanban board, a timetable, a card feed, a seating chart, drag-and-drop the standard views do not provide, a nonstandard layout or interactivity. Before creating such a view, the assistant MUST retrieve theHow-to_Custom_React_viewsdocumentation. -
FALSEis valid in the logical attributes of aDESIGNblock —defaultComponent,activatedand the like — because their values are literals, not expressions. The core rule that bansFALSEcovers expressions only, and MUST NOT be applied here by rewriting it asNULL.
Navigator
- A folder whose children should appear only when the folder
is selected MUST place those children in a different window
than the folder itself (typically
WINDOW toolbar). In a horizontal toolbar such asSystem.root, a folder that keeps its children in its own window cannot switch anything — they are shown flattened next to it and selecting the folder does nothing. A vertical toolbar instead renders same-window children as a nested group under the folder, so there the separate window is not required.
Reports
-
Before designing or editing jrxml report templates, or reasoning about report structure or template naming, the assistant MUST retrieve the
Report_designdocumentation; it MUST NOT rely on these rules as a template-format or layout reference. -
When a form has no object groups independent of each other (all groups form a single dependency chain), only ONE jrxml template is created by default, named by the form's canonical name (namespace + form name, each
.replaced by_) WITHOUT a postfix — a group's only child is merged into it.The merge is what produces the single template, so it is also what the developer can switch off: the
SUBREPORToption on a child object group keeps that group out of its parent, and it then needs a template of its own with the_<group>postfix. The assistant MUST therefore read the object blocks of the form, not just its dependency shape: a linear chain with aSUBREPORTin it needs more than one template, and a missing one silently discards all of them (rule 3). -
The assistant MUST name every template exactly: the top report by the canonical form name without a postfix, and each subreport by the canonical form name plus the
_<group>postfix of its first non-empty object group. If even one template name is wrong (not found from the platform's point of view), the platform silently falls back to a fully automatic design for the WHOLE report, with no error in the logs — so a single mismatch silently discards all custom templates.
Internationalization
-
The assistant MUST use
*ResourceBundle.propertiesfiles for UI localization.The value inside
{...}MUST be treated as the lookup key that lsFusion resolves according to the current locale. -
The assistant MUST first determine whether reverse translation is used in the current project area.
If it is used, the assistant MUST continue using it in that area and MUST follow the existing project policy.
The assistant MUST keep id selection consistent with the established pattern already used there.
The assistant MUST NOT introduce a new explicit id policy unless the user requests it.
-
Reverse translation means translating in the opposite direction of normal UI localization: not
key -> localized text, butlocalized text -> key, and then, if needed, to another locale.If ids are not specified explicitly in code, this canonical value is the source-language text itself. It is what the platform LOOKS UP, not what it stores as the key: the entry stays
id = source text, and the dictionary built for the lookup is the reversed one,value -> id. An assistant writing the bundle the other way round produces entries reverse translation never matches. -
Reverse translation is turned on by the launch parameter that sets the language of lsf string literals (
logics.lsfStrLiteralsLanguage). When it is active, ANY plain'...'literal in a localizable position — including a constant literal in any expression — that matches a ResourceBundle entry value is silently replaced at code parse time with its key{id}and is substituted in the current locale at runtime:'position'can become'pozycja'. Leading and trailing spaces take no part in the match and are kept around the substitution; a literal that is empty or made of spaces alone is never replaced.Therefore the assistant MUST write technical literals — JSON keys, URLs, formats, canonical names, external identifiers — as raw literals
r'...', which take part neither in localization nor in reverse translation. Plain'...'literals are meant for user-visible text.