Skip to content

Fix: refresh RzAside tree depending on page tree action#396

Open
timothejoubert wants to merge 17 commits intodevelopfrom
feature/rz-tree-refresh
Open

Fix: refresh RzAside tree depending on page tree action#396
timothejoubert wants to merge 17 commits intodevelopfrom
feature/rz-tree-refresh

Conversation

@timothejoubert
Copy link
Contributor

No description provided.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates Rozier’s tree refresh behavior so node tree actions can trigger refreshes across trees, while also refactoring session message toast dispatching and adjusting tree rendering/layout options.

Changes:

  • Add a global requestAllNodeTreeChange event listener to rz-tree and refresh other trees after node operations.
  • Extract session message fetching/toast dispatching into a dedicated module and wire it into Rozier.getMessages().
  • Update Twig tree templates to support a layout option (e.g. condensed) and adjust contextual menu identifiers / attributes.

Reviewed changes

Copilot reviewed 11 out of 12 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
templates/admin/article/add.html.twig Updates admin article add form markup and submit button rendering.
lib/Rozier/app/session-message.ts Introduces shared helpers to fetch session messages and dispatch toast events.
lib/Rozier/app/custom-elements/RzTree.ts Adds global refresh event handling, refactors fetch/refresh logic, and refreshes other trees after actions.
lib/Rozier/app/custom-elements/RzNodeTreeContextualMenu.ts Updates DOM selectors/attributes and dispatches requestAllNodeTreeChange with details.
lib/Rozier/app/custom-elements/RzAside.ts Simplifies aside event wiring and refactors tree content refresh + translation tracking.
lib/Rozier/app/Rozier.ts Switches message handling to the extracted session-toast dispatcher.
lib/RoadizRozierBundle/templates/widgets/tree/rz_tree_wrapper_auto.html.twig Passes layout: condensed and refines isMainTree computation for auto wrappers.
lib/RoadizRozierBundle/templates/widgets/nodeTree/singleNode.html.twig Makes selection/contextual menu ID/layout behavior dependent on layout and main tree state.
lib/RoadizRozierBundle/templates/widgets/nodeTree/nodeTree.html.twig Propagates layout into per-node includes.
lib/RoadizRozierBundle/templates/nodes/tree.html.twig Renders a condensed non-main tree for specific node trees.
lib/RoadizRozierBundle/templates/macros/rz_page_header.html.twig Fixes link attribute construction for aria-current.

@timothejoubert timothejoubert self-assigned this Feb 12, 2026
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 22 out of 23 changed files in this pull request and generated 7 comments.

}) }}
{% endapply %}
</fieldset>
{{ form_start(form) }}
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previous form_start passed explicit id (articles-form) and a rz-form class, and the submit button referenced that id via data-action-save. These attributes were removed, which can break existing JS hooks and/or styling tied to the form id/class. If those hooks are still expected, keep the attributes on form_start (or update any dependent logic to rely on the new structure).

Suggested change
{{ form_start(form) }}
{{ form_start(form, {'attr': {'id': 'articles-form', 'class': 'rz-form'}}) }}

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 23 out of 24 changed files in this pull request and generated 12 comments.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 23 out of 24 changed files in this pull request and generated 5 comments.

Comment on lines +85 to 100
async refreshAsideMainTree(
baseUrl: string | null = null,
query: Record<string, string> = {},
) {
try {
await this.refreshMainTree(baseUrl, query)
} catch {
console.debug(
'[RzAside.refreshAsideMainTree] Retrying in 3 seconds',
)
await sleep(3000)
await this.refreshMainTree(baseUrl, query)
}

return Promise.all(promises)
window.dispatchEvent(new CustomEvent('requestLoaderHide'))
}
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

refreshAsideMainTree() always dispatches requestLoaderHide after the try/catch, but if the second refreshMainTree() attempt throws, the function exits early and the loader may remain visible. Wrap the loader hide in a finally block (and optionally show the loader at the start of this method) to guarantee cleanup on failure.

Copilot uses AI. Check for mistakes.
Comment on lines 14 to 44
@@ -21,7 +21,11 @@

{% if tree is defined %}
{% set button_data = button_data|merge({ selected: translation.id == tree.translation.id }) %}
{% set button_attr = { 'data-translation-id': translation.id } %}
{% set button_attr = {
'data-translation-id': translation.id,
'command': '--update-translation',
'type': 'button',
} %}

{% if tree.rootNode is defined %}
{% set button_attr = button_attr|merge({'data-children-parent-node': tree.rootNode.id }) %}
@@ -31,10 +35,12 @@
{% set button_attr = button_attr|merge({'data-filter-tag': tree.tag.id}) %}
{% endif %}

{% set button_data = button_data|merge({attributes: button_attr}) %}
{% endif %}

{% import "@RoadizRozier/macros/rz_button.html.twig" as rz_button %}
{{ rz_button.root(button_data) }}
{{ rz_button.root(button_data|merge({
attributes: button_attr|merge(btn_attr)
}))
}}
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In item(), button_attr is only defined inside {% if tree is defined %}, but it is later used unconditionally in button_attr|merge(btn_attr). If this macro is ever used without a tree argument, Twig will raise an undefined variable error. Initialize button_attr to {} before the if so the macro is safe.

Copilot uses AI. Check for mistakes.
Comment on lines 19 to 24
connectedCallback() {
this.listen(this, 'click', this.onLangButtonClick)
this.refreshAsideMainTree()

window.addEventListener('pageshowend', this.onPageShowEnd)
window.addEventListener(
'requestAllNodeTreeChange',
this.onAllNodeTreeChange,
)
window.addEventListener(
'requestAllNodeTreeRefresh',
this.onAllNodeTreeChange,
)
window.addEventListener(
'requestMainTreeRefresh',
this.onMainTreeRefresh,
)
window.addEventListener(
'requestBindMainTrees',
this.onBindMainTreesRequest,
)
window.addEventListener(
'requestAjaxLinkBind',
this.onAjaxLinkBindRequest,
)
window.addEventListener(
'requestMessagesRefresh',
this.onMessagesRefresh,
this.currentTranslationId = this.getAttribute(
'data-default-translation-id',
)
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

refreshAsideMainTree() is called before currentTranslationId is initialized from data-default-translation-id. This means the first AJAX refresh can run without any translationId, and then currentTranslationId can end up being set to null in refreshMainTree(). Initialize currentTranslationId (and any other required state) before calling refreshAsideMainTree() in connectedCallback() to keep the initial tree request consistent.

Copilot uses AI. Check for mistakes.
Comment on lines +25 to 32
window.addEventListener('pageshowend', this.onPageShowEnd)
this.addEventListener('command', this.onCommand)
}

disconnectedCallback() {
super.disconnectedCallback()

window.removeEventListener('pageshowend', this.onPageShowEnd)
window.removeEventListener(
'requestAllNodeTreeChange',
this.onAllNodeTreeChange,
)
window.removeEventListener(
'requestAllNodeTreeRefresh',
this.onAllNodeTreeChange,
)
window.removeEventListener(
'requestMainTreeRefresh',
this.onMainTreeRefresh,
)
window.removeEventListener(
'requestBindMainTrees',
this.onBindMainTreesRequest,
)
window.removeEventListener(
'requestAjaxLinkBind',
this.onAjaxLinkBindRequest,
)
window.removeEventListener(
'requestMessagesRefresh',
this.onMessagesRefresh,
)
this.removeEventListener('command', this.onCommand)
}
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

requestMainTreeRefresh listener was removed from RzAside, but RzTree.onQuickAddNode() still dispatches requestMainTreeRefresh (see lib/Rozier/app/custom-elements/RzTree.ts). As a result, quick-add actions will no longer trigger an aside refresh. Either re-add the listener here or migrate the emitter to the new refresh mechanism (requestAllNodeTreeChange / refreshOtherTrees) so events remain consistent.

Copilot uses AI. Check for mistakes.
Comment on lines +134 to +137
return (
this.getAttribute('data-translation-id') ||
this.innerElement
.querySelector('.rz-tree__list')
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getDisplayedTreeTranslationId() can throw if .rz-aside__body is missing because it calls this.innerElement.querySelector(...) without guarding for null. Use optional chaining (or reuse innerElement local var) so this method is safe when the element is not yet fully rendered / is being disconnected.

Suggested change
return (
this.getAttribute('data-translation-id') ||
this.innerElement
.querySelector('.rz-tree__list')
const innerElement = this.innerElement
return (
this.getAttribute('data-translation-id') ||
innerElement
?.querySelector('.rz-tree__list')

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant