survos/tree-bundle

incorporate jstree, using twig and stimulus and api-platform

Maintainers

Package info

github.com/survos/tree-bundle

Language:JavaScript

Type:symfony-bundle

pkg:composer/survos/tree-bundle

Fund package maintenance!

kbond

Statistics

Installs: 2 374

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

2.0.175 2026-03-24 17:28 UTC

This package is auto-updated.

Last update: 2026-03-24 17:31:13 UTC


README

Tree UI + API editing for Symfony UX Twig Components.

This bundle provides:

  • apiTreeBrowser / api_tree Twig components (jsTree-backed)
  • @survos/tree-bundle/api_tree Stimulus controller
  • {% tree %} Twig tag for recursive rendering

Install

composer require survos/tree-bundle

Required JS modules (important)

apiTreeBrowser can render embedded Twig blocks in the browser (via js-twig). For this to work reliably, your importmap must include:

  • @survos/js-twig-bundle/twig_blocks
  • @survos/js-twig-bundle/twig_api
  • @survos/js-twig/generated/fos_routes.js (for path() in client-side twig)

If these are missing or incompatible, the controller now fails fast with a clear error instead of silently falling back.

Minimal Example

<twig:apiTreeBrowser
    :resourceClass="topicClass"
    :filter="{ tenantId: tenant.code }"
    :editable="true"
    :openAll="true"
    :caller="_self"
>
    <twig:block name="nodeLabel">
        {{ node.name ?? node.title ?? node.code ?? node.id }}
    </twig:block>

    <twig:block name="api_tree_content">
        {% set item = record ?? node %}
        <h5>{{ item.name ?? item.title ?? item.id }}</h5>
    </twig:block>
</twig:apiTreeBrowser>

Variables available inside client-side Twig blocks

Inside nodeLabel / api_tree_content, these render vars are available:

  • node - selected jsTree node payload
  • record - full fetched API record for selected node
  • item - alias of record ?? node
  • hydra - alias of item
  • globals - values passed from component :globals="..."

If you pass tenant info via globals, reference globals.tenantId (not tenantId directly).

Example:

{% set params = { tenantId: globals.tenantId, instanceId: item.id } %}
<a href="{{ path('instance_browse', params) }}">Browse</a>

Styling hooks (Tabler/Bootstrap/custom)

Use component class options:

  • browserClass
  • treePaneClass
  • contentPaneClass
  • style="plain" to avoid the built-in bootstrap grid wrapper

Wrapper includes api-tree-browser--themeable for easy theming.

Example:

<twig:apiTreeBrowser
    style="plain"
    browserClass="my-tree-layout"
    treePaneClass="my-tree-column"
    contentPaneClass="my-content-column"
    ...
/>

Toolbar buttons

Built-in toolbar includes search and clear.

Optional slideshow button appears when you pass:

:globals="{ slideshowUrl: '/my/slideshow/url' }"

API controller defaults

Bundle config now supports separate controllers:

survos_tree:
  tree_stimulus_controller: '@survos/tree-bundle/tree'
  api_tree_stimulus_controller: '@survos/tree-bundle/api_tree'

Legacy stimulus_controller is deprecated.

Performance behavior

  • Tree list loads from collection endpoint once.
  • Full detail GET {id} fetch happens on explicit node selection.
  • Label rendering uses already-loaded collection data.

Troubleshooting

  • Error: Twig function path is not configured

    • Ensure @survos/js-twig/generated/fos_routes.js is mapped in importmap.
    • Ensure var/js_twig_bundle/generated/fos_routes.js exists (cache warmer).
    • Ensure @survos/js-twig-bundle/twig_api + twig_blocks are mapped.
  • Detail block cannot see tenantId

    • Use globals.tenantId unless you explicitly flatten into top-level context.