Como parte de nosso esforço contínuo para melhorar a base de código do Discourse, estamos removendo o uso do sistema de renderização legado “widget” e substituindo-o por componentes Glimmer.
Recentemente, modernizamos o menu de postagem, e ele já está disponível no Discourse por meio da configuração glimmer_post_menu_mode.
Essa configuração aceita três valores possíveis:
disabled: usa o sistema legado “widget”auto: detectará a compatibilidade dos seus plugins e temas atuais. Se houver algum incompatível, usará o sistema legado; caso contrário, usará o novo menu.enabled: usará o novo menu. Se você tiver algum plugin ou tema incompatível, seu site pode quebrar.
Já atualizamos nossos plugins oficiais para serem compatíveis com o novo menu, mas se você ainda tiver algum plugin, tema ou componente de tema de terceiros incompatível com o novo menu, será necessário atualizá-los.
Avisos serão exibidos no console do navegador, identificando a origem da incompatibilidade.
Cronograma de Implantação
Estas são estimativas aproximadas, sujeitas a alterações
Q4 2024:
implementação principal concluída
plugins oficiais atualizados
ativado no Meta
glimmer_post_menu_modepadrão definido comoauto; mensagens de depreciação no console ativadas
conselho de atualização publicado
Q1 2025:
plugins e temas de terceiros devem ser atualizados
mensagens de depreciação começam, acionando um banner de aviso para administradores sobre quaisquer problemas remanescentes
novo menu de postagem ativado por padrão
Q2 2025
1º de abril - remoção da configuração de recurso (feature flag) e do código legado
O que isso significa para mim?
Se o seu plugin ou tema usa alguma API de “widget” para personalizar o menu de postagem, eles precisarão ser atualizados para serem compatíveis com a nova versão.
Como posso testar o novo Menu de Postagem?
Na versão mais recente do Discourse, o novo menu de postagem será ativado se você não tiver nenhum plugin ou tema incompatível.
Se você tiver extensões incompatíveis instaladas, como administrador, ainda pode alterar a configuração para enabled para forçar o uso do novo menu. Use isso com cautela, pois seu site pode quebrar dependendo das personalizações que você instalou.
No improvável caso de esse sistema automático não funcionar como esperado, você pode substituir temporariamente essa “feature flag automática” usando a configuração acima. Se precisar fazer isso, por favor, nos avise neste tópico.
Preciso atualizar meu plugin ou tema?
Você precisará atualizar seus plugins ou temas se eles realizarem alguma das personalizações abaixo:
-
Usar
decorateWidget,changeWidgetSetting,reopenWidgetouattachWidgetActionnos seguintes widgets:post-menupost-user-tip-shimsmall-user-list
-
Usar qualquer um dos métodos de API abaixo:
addPostMenuButtonremovePostMenuButtonreplacePostMenuButton
Caso você tenha extensões que realizam uma das personalizações acima, um aviso será exibido no console identificando o plugin ou componente que precisa ser atualizado ao acessar uma página de tópico.
O ID de depreciação é:
discourse.post-menu-widget-overrides
Se você usar mais de um tema na sua instância, verifique todos eles, pois os avisos serão exibidos apenas para os plugins ativos e os temas e componentes de tema atualmente em uso.
Quais são as substituições?
Introduzimos o transformador de valor post-menu-buttons como a nova API para personalizar o menu de postagem.
O transformador de valor fornece um objeto DAG que permite adicionar, substituir, remover ou reordenar os botões. Ele também fornece informações de contexto, como a postagem associada ao menu, o estado da postagem exibida e as chaves dos botões para facilitar o posicionamento dos itens.
As APIs do DAG esperam receber componentes Ember se a API precisar de uma nova definição de botão, como .add e .replace.
Cada personalização é diferente, mas aqui estão algumas orientações para os casos de uso mais comuns:
addPostMenuButton
Antes:
withPluginApi("1.34.0", (api) => {
api.addPostMenuButton("solved", (attrs) => {
if (attrs.can_accept_answer) {
const isOp = currentUser?.id === attrs.topicCreatedById;
return {
action: "acceptAnswer",
icon: "far-check-square",
className: "unaccepted",
title: "solved.accept_answer",
label: isOp ? "solved.solution" : null,
position: attrs.topic_accepted_answer ? "second-last-hidden" : "first",
};
}
});
});
Depois:
Os exemplos abaixo usam o Formato de Tag de Template (gjs) do Ember.
// components/solved-accept-answer-button.gjs
import Component from "@glimmer/component";
import { action } from "@ember/object";
import { inject as service } from "@ember/service";
import DButton from "discourse/components/d_button";
import { ajax } from "discourse/lib/ajax";
import { popupAjaxError } from "discourse/lib/ajax-error";
export default class SolvedAcceptAnswerButton extends Component {
// indica se o botão será exibido imediatamente ou oculto atrás do botão "mostrar mais"
static hidden(args) {
return args.post.topic_accepted_answer;
}
...
<template>
<DButton
class="post-action-menu__solved-unaccepted unaccepted"
...attributes
@action={{this.acceptAnswer}}
@icon="far-check-square"
@label={{if this.showLabel "solved.solution"}}
@title="solved.accept_answer"
/>
</template>
}
// initializer.js
import SolvedAcceptAnswerButton from "../components/solved-accept-answer-button";
...
withPluginApi("1.34.0", (api) => {
api.registerValueTransformer(
"post-menu-buttons",
({
value: dag,
context: {
post,
firstButtonKey, // chave do primeiro botão
secondLastHiddenButtonKey, // chave do segundo último botão oculto
lastHiddenButtonKey, // chave do último botão oculto
},
}) => {
dag.add(
"solved",
SolvedAcceptAnswerButton,
post.topic_accepted_answer
? {
before: lastHiddenButtonKey,
after: secondLastHiddenButtonKey,
}
: {
before: [
"assign", // botão adicionado pelo plugin assign
firstButtonKey,
],
}
);
}
);
});
Estilizando seus botões
É recomendado incluir
...attributesconforme mostrado no exemplo acima em seu componente.Quando combinado com o uso dos componentes
DButtonouDMenu, isso cuidará das classes de boilerplate e garantirá que seu botão siga o formato dos outros botões no menu de postagem.Formatações adicionais podem ser especificadas usando suas classes personalizadas.
replacePostMenuButton
- Antes:
withPluginApi("1.34.0", (api) => {
api.replacePostMenuButton("like", {
name: "discourse-reactions-actions",
buildAttrs: (widget) => {
return { post: widget.findAncestorModel() };
},
shouldRender: (widget) => {
const post = widget.findAncestorModel();
return post && !post.deleted_at;
},
});
});
- Depois:
import ReactionsActionButton from "../components/discourse-reactions-actions-button";
...
withPluginApi("1.34.0", (api) => {
api.registerValueTransformer(
"post-menu-buttons",
({ value: dag, context: { buttonKeys } }) => {
// ReactionsActionButton é o novo componente de botão
dag.replace(buttonKeys.LIKE, ReactionsActionButton);
}
);
});
removePostMenuButton
- Antes:
withPluginApi("1.34.0", (api) => {
api.removePostMenuButton('like', (attrs, state, siteSettings, settings, currentUser) => {
if (attrs.post_number === 1) {
return true;
}
});
});
- Depois:
withPluginApi("1.34.0", (api) => {
api.registerValueTransformer(
"post-menu-buttons",
({ value: dag, context: { post, buttonKeys } }) => {
if (post.post_number === 1) {
dag.delete(buttonKeys.LIKE);
}
}
);
});
E quanto a outras personalizações?
Se sua personalização não puder ser realizada usando a nova API que introduzimos, por favor, nos avise criando um novo tópico de desenvolvimento para discutir.
Sou autor de plugin/tema. Como atualizo um tema/plugin para suportar tanto o menu de postagem antigo quanto o novo durante a transição?
Usamos o padrão abaixo para suportar ambas as versões antiga e nova do menu de postagem em nossos plugins:
function customizePostMenu(api) {
const transformerRegistered = api.registerValueTransformer(
"post-menu-buttons",
({ value: dag, context }) => {
// personalizações do novo menu de postagem
...
}
);
const silencedKey =
transformerRegistered && "discourse.post-menu-widget-overrides";
withSilencedDeprecations(silencedKey, () => customizeWidgetPostMenu(api));
}
function customizeWidgetPostMenu(api) {
// personalização do código antigo "widget" aqui
...
}
export default {
name: "my-plugin",
initialize(container) {
withPluginApi("1.34.0", customizePostMenu);
}
};
Mais exemplos
Você pode verificar nossos plugins oficiais para exemplos de como usar a nova API: