FIX: Avoid possible rendering infinite-loop in post-menu (#30873)

ff815384 introduced a modifier which changes tracked state. If the
conditions are correct, this can cause an infinite re-rendering loop.
One example is [here](https://meta.discourse.org/t/346215/4), although
there are other non-dev-tools things which could trigger this kind of
loop. As a general rule, modifiers should not change tracked state.

This commit changes the approach to match the rest of the new-post-menu
assumptions: instead of trying to modify `collapsed` at runtime, the
rendering of individual buttons has the `>1` logic. That matches the
existing logic
[here](https://github.com/discourse/discourse/blob/89ff7d51e6/app/assets/javascripts/discourse/app/components/post/menu.gjs#L392C18-L394C6).
This commit is contained in:
David Taylor 2025-01-20 15:16:53 +00:00 committed by GitHub
parent 98943a5a1f
commit 89df65e843
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 8 additions and 11 deletions

View File

@ -3,7 +3,6 @@ import { cached, tracked } from "@glimmer/tracking";
import { hash } from "@ember/helper"; import { hash } from "@ember/helper";
import { action } from "@ember/object"; import { action } from "@ember/object";
import { getOwner } from "@ember/owner"; import { getOwner } from "@ember/owner";
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
import { service } from "@ember/service"; import { service } from "@ember/service";
import { isEmpty, isPresent } from "@ember/utils"; import { isEmpty, isPresent } from "@ember/utils";
import { and, eq } from "truth-helpers"; import { and, eq } from "truth-helpers";
@ -396,11 +395,6 @@ export default class PostMenu extends Component {
return items; return items;
} }
@action
expandIfOnlyOneHiddenButton() {
this.collapsed = this.renderableCollapsedButtons.length > 1;
}
@cached @cached
get renderableCollapsedButtons() { get renderableCollapsedButtons() {
return this.availableCollapsedButtons.filter((button) => return this.availableCollapsedButtons.filter((button) =>
@ -410,9 +404,13 @@ export default class PostMenu extends Component {
@cached @cached
get visibleButtons() { get visibleButtons() {
const nonCollapsed = this.availableButtons.filter((button) => { let nonCollapsed = this.availableButtons;
return !this.availableCollapsedButtons.includes(button);
}); if (this.renderableCollapsedButtons.length > 1) {
nonCollapsed = nonCollapsed.filter((button) => {
return !this.renderableCollapsedButtons.includes(button);
});
}
return DAG.from( return DAG.from(
nonCollapsed.map((button) => [button.key, button, button.position]), nonCollapsed.map((button) => [button.key, button, button.position]),
@ -609,7 +607,6 @@ export default class PostMenu extends Component {
"replies-button-visible" "replies-button-visible"
) )
}} }}
{{didInsert this.expandIfOnlyOneHiddenButton}}
> >
{{! do not include PluginOutlets here, use the PostMenu DAG API instead }} {{! do not include PluginOutlets here, use the PostMenu DAG API instead }}
{{#each this.extraControls key="key" as |extraControl|}} {{#each this.extraControls key="key" as |extraControl|}}

View File

@ -3,7 +3,7 @@ import DButton from "discourse/components/d-button";
export default class PostMenuShowMoreButton extends Component { export default class PostMenuShowMoreButton extends Component {
static shouldRender(args) { static shouldRender(args) {
return args.state.collapsedButtons.length && args.state.collapsed; return args.state.collapsedButtons.length > 1 && args.state.collapsed;
} }
<template> <template>