Skip to content

Tree panel

Purpose and problems it solves

tree loads one root object and follows configured links to build a hierarchy. Use it to navigate equipment, orders and operations, organizational structures, or any object graph where each parent type determines which descendant links are available.

When to use it

Use Tree when parent-child context and progressive expansion matter. Use Table for a flat result set, or a Table plus linked request when only one parent-to-list step is needed.

Decide first how the root is obtained, then define one link rule for every parent type that can have children.

Prerequisites, inputs, and ownership

Tree calls the object-by-GUID endpoint for its root and linked-objects endpoint for descendants. The configured link names, parent meta-type names, requested attributes, filters, sorting, and pagination must exist in the current API/data model.

Every rendered row needs a stable object GUID. tree.columns defines visible display columns; the root and every link rule provide the value/template mapping for those column keys.

Capability map

Root sources

  • Fixed root: root.objectId is a GUID string.
  • Event-selected root: root.objectId is { "getSelectedObjectForEventId": "..." }.
  • User-selected root: root.selectPanels declares picker content. In the active UI it is reached through a panelActions action with method: "selectRoot"; the standalone picker buttons in PanelTree are commented out.

The current picker reads only the first selectPanels entry. root.ui.selectRootLabel replaces the button label for that picker. When it is omitted, runtime combines the localized “Select tree root” text with the first select panel's localized label, for example Select tree root (Orders).

Descendant acquisition

tree.links is a set of branch rules. For an expanded node, runtime reads the node's actual meta type, selects every rule whose parentType matches it, and performs each rule's linked-object request with the node GUID supplied at runtime.

Each descendant request supports linkName, reverse, findAttributes, sortParams, and pagination. Results from all matching rules are appended in rule order.

Display and templates

tree.columns[].key addresses the corresponding entry in root.columns or links[].columns. A direct identity template such as "" for key status uses the typed attribute renderer. Composite or aliased templates such as " — " are evaluated to plain display text.

The first visible column owns the expansion control. It also receives the object icon when one is available.

Selection, events, and actions

selectionMode supports single and multiple, defaulting to single. Selection stores object selectors and runs the selected node's events, plus common panel events. Root events come from root.events; descendant events come from the matching link rule.

panelActions uses the common panel toolbar. Root and descendant itemActions use the Tree-specific row handler. That handler currently implements create, deleteLink for link nodes, runMethod, and reloadEntities. Its update branch is empty. Other methods do not gain generic row behavior automatically.

Expansion and collapse

root.expandOnLoad marks the root expanded and immediately loads its descendants. Otherwise, children load on the first expansion. Collapsing a node removes its loaded children; expanding it again fetches them again. Expansion keys that no longer address loaded non-leaf nodes are cleaned up.

Width and header behavior

Tree fills the panel width. fixedWidth fixes and truncates a display column; minWidth sets a lower bound and enables horizontal overflow; legacy width is a browser table-layout hint. minWidth wins over fixedWidth and logs a configuration error when both are present. tree.ui.hideHeader hides the header row.

Behavioral model and important interactions

  1. Resolve the root from a direct GUID or selection event.
  2. Fetch only attributes referenced by the root column mappings.
  3. Render one root node.
  4. On expansion, match link rules to the node's runtime meta type.
  5. Fetch linked objects with the node GUID and each rule's query state.
  6. Mark a child as a leaf only when no rule matches that child's type.
  7. Route selection events and actions through the rule that created each node.

Column mappings therefore affect both display and response projection. A template that references an attribute must be present in that root/link mapping. Descendant filters, sort, and page limits are applied independently per matching link rule.

For multiple selection, the store emits event context from the last processed selected node. Do not assume one event per selected node.

Alternatives, defaults, ordering, and precedence

  • An object ID explicitly supplied by the user-selection action wins for that root load. Otherwise the configured fixed/event root is resolved.
  • reverse defaults to false at request serialization.
  • Link rules are evaluated in configured order; all rules matching parentType run.
  • selectionMode defaults to single.
  • itemActionsMaxVisible defaults to 2; remaining actions move to overflow.
  • columns is optional in the type, but without display columns the hierarchy has no useful visible value.
  • For widths: minWidth > fixedWidth > legacy width > flexible layout.

Limitations and declaration/runtime drift

  • root.selectPanels does not render picker buttons by itself. Use a selectRoot panel action, and expect only the first picker entry to be used.
  • links[].linkType is required by the declared type but has no confirmed active Tree consumer; descendant fetching uses request.linkName.
  • ColumnValue.colspan is declared but not consumed by the renderer.
  • tree.columns[].header is declared but the renderer uses label.
  • Tree display columns are not sortable and there is no Tree filter UI. Descendant request filters/sorts are configured on each link.
  • Collapse discards children rather than preserving a client-side subtree.
  • Root-load failures are logged; descendant-load failures also show a request error toast. There is no configured Tree empty/error message.
  • A descendant action configured as update currently does nothing.

Minimal valid configuration

Replace the GUID and type/link names with real data-model values.

json
{
  "id": "asset-tree",
  "type": "tree",
  "tree": {
    "root": {
      "objectId": "00000000-0000-0000-0000-000000000001",
      "columns": {
        "name": "{{name}}"
      }
    },
    "links": [],
    "columns": [
      {
        "key": "name",
        "label": "Наименование"
      }
    ]
  }
}

Realistic end-to-end scenarios

Fixed root with typed display, filtering, sorting, and eager expansion

This hierarchy loads one ProductionOrder, then its OrderOperation links. The link request returns at most 50 non-archived operations in ascending sequence order. Selection publishes the chosen root or operation under one stable event ID.

json
{
  "id": "order-operations-tree",
  "type": "tree",
  "selectionMode": "single",
  "tree": {
    "root": {
      "objectId": "11111111-1111-1111-1111-111111111111",
      "expandOnLoad": true,
      "events": [
        {
          "id": "order-tree-node-selected",
          "name": "onObjectSelect",
          "actions": [
            {
              "name": "addSelectedObjectToRequest"
            }
          ]
        }
      ],
      "columns": {
        "name": "{{itemId}} — {{name}}",
        "status": "{{status}}"
      }
    },
    "links": [
      {
        "id": "order-to-operations",
        "parentType": "ProductionOrder",
        "linkType": "OrderOperation",
        "request": {
          "linkName": "OrderOperation",
          "reverse": false,
          "findAttributes": [
            {
              "attribute": {
                "name": "archived",
                "value": "false"
              },
              "compare": "EQUAL"
            }
          ],
          "sortParams": [
            {
              "attribute": "sequence",
              "sortDirection": "ASC"
            }
          ],
          "pagination": {
            "limit": 50,
            "offset": 0
          }
        },
        "events": [
          {
            "id": "order-tree-node-selected",
            "name": "onObjectSelect",
            "actions": [
              {
                "name": "addSelectedObjectToRequest"
              }
            ]
          }
        ],
        "columns": {
          "name": "{{sequence}}. {{name}}",
          "status": "{{status}}"
        }
      }
    ],
    "columns": [
      {
        "key": "name",
        "label": "Узел",
        "minWidth": "22rem"
      },
      {
        "key": "status",
        "label": "Статус",
        "fixedWidth": "10rem"
      }
    ]
  }
}

Root from another panel's selection

Use this shape inside a Group after a Table emits work-center-selected. Until that event exists, Tree cannot resolve a root and renders no hierarchy.

json
{
  "id": "selected-work-center-tree",
  "type": "tree",
  "tree": {
    "root": {
      "objectId": {
        "getSelectedObjectForEventId": "work-center-selected"
      },
      "columns": {
        "name": "{{name}}"
      }
    },
    "links": [
      {
        "id": "work-center-to-machines",
        "parentType": "WorkCenter",
        "linkType": "WorkCenterMachine",
        "request": {
          "linkName": "WorkCenterMachine",
          "reverse": false
        },
        "columns": {
          "name": "{{itemId}} — {{name}}"
        }
      }
    ],
    "columns": [
      {
        "key": "name",
        "label": "Рабочий центр / оборудование"
      }
    ]
  }
}

For a user-driven root picker, configure root.selectPanels[0] with a Table selection panel and add a selectRoot action to panelActions. Treat that path as a current compatibility surface: the inline picker entry is disabled and additional picker entries are ignored.

json
{
  "tree": {
    "root": {
      "ui": {
        "selectRootLabel": "Choose an order"
      },
      "columns": {
        "name": "{{name}}"
      },
      "selectPanels": [
        {
          "label": "Orders",
          "panel": {
            "id": "order-picker",
            "type": "table",
            "columns": [
              {
                "attribute": "name",
                "label": "Order"
              }
            ],
            "request": {
              "metaTypeName": "ProductionOrder"
            }
          }
        }
      ]
    },
    "links": []
  },
  "panelActions": [
    {
      "id": "choose-root",
      "method": "selectRoot",
      "label": "Choose root"
    }
  ]
}

Verified demos

Open fixed-root trees with descendant loading, templates, widths, and row actions Open a fixed-root typed-value tree with selection events

No verified local fixture currently demonstrates the event-selected or user-selected root paths.

Exact parameter reference

Root and hierarchy:

Display and panel behavior:

Descendant request fields:

Define selection consumers with panel events. Use values and renderers for typed direct attributes and the actions guide before adding panel or node actions.