From 6c0964d8efc3112881b8cf40634e357da533224f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Saquetim?= Date: Fri, 13 Jun 2025 19:04:59 -0300 Subject: [PATCH] DEV: Add compatibility with the Glimmer Post Stream Refactored the user notes plugin by splitting logic into multiple files, introducing value transformers, and adopting Glimmer components. Added a new setting `user_notes_icon_placement` to control icon placement (options: `name` or `avatar`). [skip ci] --- .../components/post-metadata-user-notes.gjs | 9 + .../initializers/enable-user-notes.gjs | 166 ++++++++++++++++++ .../initializers/enable-user-notes.js | 114 ------------ .../pre-initializers/transformers.js | 11 ++ config/settings.yml | 7 + 5 files changed, 193 insertions(+), 114 deletions(-) create mode 100644 assets/javascripts/discourse/components/post-metadata-user-notes.gjs create mode 100644 assets/javascripts/discourse/initializers/enable-user-notes.gjs delete mode 100644 assets/javascripts/discourse/initializers/enable-user-notes.js create mode 100644 assets/javascripts/discourse/pre-initializers/transformers.js diff --git a/assets/javascripts/discourse/components/post-metadata-user-notes.gjs b/assets/javascripts/discourse/components/post-metadata-user-notes.gjs new file mode 100644 index 0000000..da22b1a --- /dev/null +++ b/assets/javascripts/discourse/components/post-metadata-user-notes.gjs @@ -0,0 +1,9 @@ +import Component from "@glimmer/component"; +import { service } from "@ember/service"; +import icon from "discourse/helpers/d-icon"; + +export default class PostMetadataUserNotes extends Component { + @service siteSettings; + + +} diff --git a/assets/javascripts/discourse/initializers/enable-user-notes.gjs b/assets/javascripts/discourse/initializers/enable-user-notes.gjs new file mode 100644 index 0000000..3a5b7f6 --- /dev/null +++ b/assets/javascripts/discourse/initializers/enable-user-notes.gjs @@ -0,0 +1,166 @@ +import Component from "@glimmer/component"; +import { withSilencedDeprecations } from "discourse/lib/deprecated"; +import { iconNode } from "discourse/lib/icon-library"; +import { withPluginApi } from "discourse/lib/plugin-api"; +import { applyValueTransformer } from "discourse/lib/transformer"; +import PostMetadataUserNotes from "../components/post-metadata-user-notes"; +import { showUserNotes } from "../lib/user-notes"; + +export default { + name: "enable-user-notes", + initialize(container) { + const siteSettings = container.lookup("service:site-settings"); + const currentUser = container.lookup("service:current-user"); + + if (!siteSettings.user_notes_enabled || !currentUser?.staff) { + return; + } + + withPluginApi((api) => { + customizePost(api, container); + customizePostMenu(api, container); + }); + }, +}; + +function customizePost(api, container) { + const siteSettings = container.lookup("service:site-settings"); + + const iconPlacement = applyValueTransformer( + "user-notes-icon-placement", + siteSettings.user_notes_icon_placement + ); + + if (iconPlacement === "name") { + api.renderBeforeWrapperOutlet( + "post-meta-data-poster-name", + class extends Component { + static shouldRender(args, context) { + return context.site.mobileView; + } + + + } + ); + + api.renderAfterWrapperOutlet( + "post-meta-data-poster-name", + class extends Component { + static shouldRender(args, context) { + return !context.site.mobileView; + } + + + } + ); + } else if (iconPlacement === "avatar") { + api.renderAfterWrapperOutlet("poster-avatar", PostMetadataUserNotes); + } + + withSilencedDeprecations("discourse.post-stream-widget-overrides", () => + customizeWidgetPost(api) + ); +} + +function customizeWidgetPost(api) { + function widgetShowUserNotes() { + showUserNotes( + this.store, + this.attrs.user_id, + (count) => { + this.sendWidgetAction("refreshUserNotes", count); + }, + { + postId: this.attrs.id, + } + ); + } + + api.attachWidgetAction("post", "refreshUserNotes", function (count) { + const cfs = this.model.user_custom_fields || {}; + cfs.user_notes_count = count; + this.model.set("user_custom_fields", cfs); + }); + + const mobileView = api.container.lookup("service:site").mobileView; + const loc = mobileView ? "before" : "after"; + + api.decorateWidget(`poster-name:${loc}`, (dec) => { + if (dec.widget.settings.hideNotes) { + return; + } + + const post = dec.getModel(); + if (!post) { + return; + } + + const ucf = post.user_custom_fields || {}; + if (ucf.user_notes_count > 0) { + return dec.attach("user-notes-icon"); + } + }); + + api.decorateWidget(`post-avatar:after`, (dec) => { + if (!dec.widget.settings.showNotes) { + return; + } + + const post = dec.getModel(); + if (!post) { + return; + } + + const ucf = post.user_custom_fields || {}; + if (ucf.user_notes_count > 0) { + return dec.attach("user-notes-icon"); + } + }); + + api.attachWidgetAction("post", "showUserNotes", widgetShowUserNotes); + + api.createWidget("user-notes-icon", { + services: ["site-settings"], + + tagName: "span.user-notes-icon", + click: widgetShowUserNotes, + + html() { + if (this.siteSettings.enable_emoji) { + return this.attach("emoji", { name: "memo" }); + } else { + return iconNode("pen-to-square"); + } + }, + }); +} + +function customizePostMenu(api, container) { + const appEvents = container.lookup("service:app-events"); + const store = container.lookup("service:store"); + + api.addPostAdminMenuButton((attrs) => { + return { + icon: "pen-to-square", + label: "user_notes.attach", + action: (post) => { + showUserNotes( + store, + attrs.user_id, + (count) => { + const ucf = post.user_custom_fields || {}; + ucf.user_notes_count = count; + post.set("user_custom_fields", ucf); + + appEvents.trigger("post-stream:refresh", { + id: post.id, + }); + }, + { postId: attrs.id } + ); + }, + secondaryAction: "closeAdminMenu", + className: "add-user-note", + }; + }); +} diff --git a/assets/javascripts/discourse/initializers/enable-user-notes.js b/assets/javascripts/discourse/initializers/enable-user-notes.js deleted file mode 100644 index b23ad64..0000000 --- a/assets/javascripts/discourse/initializers/enable-user-notes.js +++ /dev/null @@ -1,114 +0,0 @@ -import { iconNode } from "discourse/lib/icon-library"; -import { withPluginApi } from "discourse/lib/plugin-api"; -import { showUserNotes } from "../lib/user-notes"; - -export default { - name: "enable-user-notes", - initialize(container) { - const siteSettings = container.lookup("service:site-settings"); - const currentUser = container.lookup("service:current-user"); - const appEvents = container.lookup("service:app-events"); - - if (!siteSettings.user_notes_enabled || !currentUser?.staff) { - return; - } - - const store = container.lookup("service:store"); - - withPluginApi("0.8.15", (api) => { - function widgetShowUserNotes() { - showUserNotes( - this.store, - this.attrs.user_id, - (count) => { - this.sendWidgetAction("refreshUserNotes", count); - }, - { - postId: this.attrs.id, - } - ); - } - - api.attachWidgetAction("post", "refreshUserNotes", function (count) { - const cfs = this.model.user_custom_fields || {}; - cfs.user_notes_count = count; - this.model.set("user_custom_fields", cfs); - }); - - const mobileView = api.container.lookup("service:site").mobileView; - const loc = mobileView ? "before" : "after"; - api.decorateWidget(`poster-name:${loc}`, (dec) => { - if (dec.widget.settings.hideNotes) { - return; - } - - const post = dec.getModel(); - if (!post) { - return; - } - - const ucf = post.user_custom_fields || {}; - if (ucf.user_notes_count > 0) { - return dec.attach("user-notes-icon"); - } - }); - - api.decorateWidget(`post-avatar:after`, (dec) => { - if (!dec.widget.settings.showNotes) { - return; - } - - const post = dec.getModel(); - if (!post) { - return; - } - - const ucf = post.user_custom_fields || {}; - if (ucf.user_notes_count > 0) { - return dec.attach("user-notes-icon"); - } - }); - api.addPostAdminMenuButton((attrs) => { - return { - icon: "pen-to-square", - label: "user_notes.attach", - action: (post) => { - showUserNotes( - store, - attrs.user_id, - (count) => { - const ucf = post.user_custom_fields || {}; - ucf.user_notes_count = count; - post.set("user_custom_fields", ucf); - - appEvents.trigger("post-stream:refresh", { - id: post.id, - }); - }, - { postId: attrs.id } - ); - }, - secondaryAction: "closeAdminMenu", - className: "add-user-note", - }; - }); - - api.attachWidgetAction("post", "showUserNotes", widgetShowUserNotes); - - api.createWidget("user-notes-icon", { - services: ["site-settings"], - - tagName: "span.user-notes-icon", - click: widgetShowUserNotes, - - html() { - if (this.siteSettings.enable_emoji) { - return this.attach("emoji", { name: "memo" }); - } else { - return iconNode("pen-to-square"); - } - }, - }); - }); - }, -}; diff --git a/assets/javascripts/discourse/pre-initializers/transformers.js b/assets/javascripts/discourse/pre-initializers/transformers.js new file mode 100644 index 0000000..6117a6f --- /dev/null +++ b/assets/javascripts/discourse/pre-initializers/transformers.js @@ -0,0 +1,11 @@ +import { withPluginApi } from "discourse/lib/plugin-api"; + +export default { + before: "freeze-valid-transformers", + + initialize() { + withPluginApi("1.33.0", (api) => { + api.addValueTransformerName("user-notes-icon-placement"); + }); + }, +}; diff --git a/config/settings.yml b/config/settings.yml index 5f6a42a..d2beb64 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -2,6 +2,13 @@ plugins: user_notes_enabled: default: false client: true + user_notes_icon_placement: + client: true + type: enum + default: "name" + choices: + - name + - avatar user_notes_moderators_delete: default: true client: false