DEV: Add APIs in the post menu to handle collapsed buttons (#31734) (#31837)

- backport of #31734 to stable branch

---------

Co-authored-by: Sérgio Saquetim <1108771+megothss@users.noreply.github.com>
This commit is contained in:
Amanda Alves Branquinho 2025-03-17 22:07:11 -03:00 committed by GitHub
parent 32d4426f7e
commit fd450a6494
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 160 additions and 24 deletions

View File

@ -15,7 +15,10 @@ import SmallUserList, {
import UserTip from "discourse/components/user-tip";
import concatClass from "discourse/helpers/concat-class";
import DAG from "discourse/lib/dag";
import { applyMutableValueTransformer } from "discourse/lib/transformer";
import {
applyMutableValueTransformer,
applyValueTransformer,
} from "discourse/lib/transformer";
import { i18n } from "discourse-i18n";
import PostMenuButtonConfig from "./menu/button-config";
import PostMenuButtonWrapper from "./menu/button-wrapper";
@ -81,7 +84,11 @@ export default class PostMenu extends Component {
@service siteSettings;
@service store;
@tracked collapsed = true; // TODO (glimmer-post-menu): Some plugins will need a value transformer
@tracked collapsed = applyValueTransformer(
"post-menu-collapsed",
true,
this.#prepareStaticMethodsState({ collapsed: true })
);
@tracked isWhoLikedVisible = false;
@tracked likedUsers = [];
@tracked totalLikedUsers;
@ -113,23 +120,7 @@ export default class PostMenu extends Component {
@cached
get staticMethodsState() {
return Object.freeze({
canCreatePost: this.args.canCreatePost,
collapsed: this.collapsed,
currentUser: this.currentUser,
filteredRepliesView: this.args.filteredRepliesView,
isWhoLikedVisible: this.isWhoLikedVisible,
isWhoReadVisible: this.isWhoReadVisible,
isWikiMode: this.isWikiMode,
repliesShown: this.args.repliesShown,
replyDirectlyBelow:
this.args.nextPost?.reply_to_post_number ===
this.args.post.post_number &&
this.args.post.post_number !== this.args.post.filteredRepliesPostNumber,
showReadIndicator: this.args.showReadIndicator,
suppressReplyDirectlyBelow:
this.siteSettings.suppress_reply_directly_below,
});
return this.#prepareStaticMethodsState();
}
@cached
@ -205,6 +196,8 @@ export default class PostMenu extends Component {
// map to keep track of the labels that should be shown for each button if the plugins wants to override the default
const buttonLabels = new Map();
// map to keep track of the collapsed state of each button if the plugins wants to override the default
const collapsedButtons = new Map();
const showMoreButtonPosition = configuredItems.indexOf(
buttonKeys.SHOW_MORE
@ -232,6 +225,17 @@ export default class PostMenu extends Component {
return buttonLabels.delete(key);
},
},
collapsedButtons: {
hide(key) {
collapsedButtons.set(key, true);
},
show(key) {
collapsedButtons.set(key, false);
},
default(key) {
return collapsedButtons.delete(key);
},
},
buttonKeys,
firstButtonKey: this.configuredItems[0],
lastHiddenButtonKey: hiddenButtonKeys.length
@ -254,6 +258,7 @@ export default class PostMenu extends Component {
key,
Component: ButtonComponent,
apiAdded: addedKeys.has(key), // flag indicating if the button was added using the API
hidden: collapsedButtons.get(key),
owner: getOwner(this), // to be passed as argument to the static methods
position,
replacementMap,
@ -571,6 +576,26 @@ export default class PostMenu extends Component {
this.isWhoReadVisible = true;
}
#prepareStaticMethodsState({ collapsed } = {}) {
return Object.freeze({
canCreatePost: this.args.canCreatePost,
collapsed: collapsed ?? this.collapsed,
currentUser: this.currentUser,
filteredRepliesView: this.args.filteredRepliesView,
isWhoLikedVisible: this.isWhoLikedVisible,
isWhoReadVisible: this.isWhoReadVisible,
isWikiMode: this.isWikiMode,
repliesShown: this.args.repliesShown,
replyDirectlyBelow:
this.args.nextPost?.reply_to_post_number ===
this.args.post.post_number &&
this.args.post.post_number !== this.args.post.filteredRepliesPostNumber,
showReadIndicator: this.args.showReadIndicator,
suppressReplyDirectlyBelow:
this.siteSettings.suppress_reply_directly_below,
});
}
<template>
{{! The section tag can't be include while we're still using the widget shim }}
{{! <section class="post-menu-area clearfix"> }}

View File

@ -4,6 +4,7 @@ import { helperContext } from "discourse/lib/helpers";
export default class PostMenuButtonConfig {
#Component;
#apiAdded;
#hidden;
#key;
#owner;
#position;
@ -14,6 +15,7 @@ export default class PostMenuButtonConfig {
key,
Component,
apiAdded,
hidden,
owner,
position,
replacementMap,
@ -21,6 +23,7 @@ export default class PostMenuButtonConfig {
}) {
this.#Component = Component;
this.#apiAdded = apiAdded;
this.#hidden = hidden;
this.#key = key;
this.#owner = owner;
this.#position = position;
@ -38,11 +41,14 @@ export default class PostMenuButtonConfig {
@bind
hidden(args) {
return this.#staticPropertyWithReplacementFallback({
property: "hidden",
args,
defaultValue: null,
});
return (
this.#hidden ??
this.#staticPropertyWithReplacementFallback({
property: "hidden",
args,
defaultValue: null,
})
);
}
@bind

View File

@ -25,6 +25,7 @@ export const VALUE_TRANSFORMERS = Object.freeze([
"parent-category-row-class",
"parent-category-row-class-mobile",
"post-menu-buttons",
"post-menu-collapsed",
"small-user-attrs",
"topic-list-class",
"topic-list-columns",

View File

@ -0,0 +1,104 @@
import { getOwner } from "@ember/owner";
import { render } from "@ember/test-helpers";
import { module, test } from "qunit";
import PostMenu from "discourse/components/post/menu";
import { withPluginApi } from "discourse/lib/plugin-api";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
module("Unit | Component | post-menu", function (hooks) {
setupRenderingTest(hooks);
hooks.beforeEach(function () {
this.siteSettings.glimmer_post_menu_mode = "enabled";
this.siteSettings.post_menu =
"read|like|copyLink|share|flag|edit|bookmark|delete|admin|reply";
this.siteSettings.post_menu_hidden_items = "";
const store = getOwner(this).lookup("service:store");
const topic = store.createRecord("topic", { id: 123 });
this.post = store.createRecord("post", {
id: 1,
post_number: 1,
topic,
like_count: 3,
actions_summary: [{ id: 2, count: 1, hidden: false, can_act: true }],
});
});
test("post-menu-collapsed value transformer", async function (assert) {
this.siteSettings.post_menu_hidden_items = "bookmark|copyLink";
// without the transformer
const post = this.post; // using this inside the template does not correspond to the test `this` context
await render(<template><PostMenu @post={{post}} /></template>);
assert.dom(".post-action-menu__show-more").exists("show more is displayed");
assert
.dom(".post-action-menu__bookmark")
.doesNotExist("bookmark is hidden");
assert
.dom(".post-action-menu__copy-link")
.doesNotExist("copyLink is hidden");
// with the transformer
withPluginApi((api) => {
api.registerValueTransformer("post-menu-collapsed", () => false);
});
await render(<template><PostMenu @post={{post}} /></template>);
assert
.dom(".post-action-menu__show-more")
.doesNotExist("show more is hidden");
assert.dom(".post-action-menu__bookmark").exists("bookmark is displayed");
assert.dom(".post-action-menu__copy-link").exists("copyLink is displayed");
});
module("post-menu value transformer", function () {
test("context/collapsedButtons: allows handling which buttons are collapsed", async function (assert) {
this.siteSettings.post_menu_hidden_items = "bookmark|copyLink";
// without the transformer
const post = this.post; // using this inside the template does not correspond to the test `this` context
await render(<template><PostMenu @post={{post}} /></template>);
assert
.dom(".post-action-menu__show-more")
.exists("show more is displayed");
assert.dom(".post-action-menu__like").exists("like is displayed");
assert
.dom(".post-action-menu__bookmark")
.doesNotExist("bookmark is hidden");
assert
.dom(".post-action-menu__copy-link")
.doesNotExist("copyLink is hidden");
assert.dom(".post-action-menu__share").exists("share is displayed");
// with the transformer
withPluginApi((api) => {
api.registerValueTransformer(
"post-menu-buttons",
({ context: { collapsedButtons } }) => {
collapsedButtons.default("like");
collapsedButtons.show("bookmark");
collapsedButtons.hide("share");
collapsedButtons.default("copy-link");
}
);
});
await render(<template><PostMenu @post={{post}} /></template>);
assert
.dom(".post-action-menu__show-more")
.exists("show more is displayed");
assert.dom(".post-action-menu__like").exists("like still is displayed");
assert
.dom(".post-action-menu__bookmark")
.exists("bookmark is now displayed");
assert
.dom(".post-action-menu__copy-link")
.doesNotExist("copyLink is still hidden");
assert
.dom(".post-action-menu__share")
.doesNotExist("share is now hidden");
});
});
});