В рамках наших непрерывных усилий по улучшению кодовой базы Discourse мы удаляем использование устаревшей системы рендеринга «widget» и заменяем её компонентами Glimmer.
Недавно мы модернизировали меню постов, и теперь оно доступно в Discourse при включении настройки glimmer_post_menu_mode.
Эта настройка принимает три возможных значения:
disabled: использовать устаревшую систему «widget»auto: автоматически определяет совместимость ваших текущих плагинов и тем. Если какие-либо из них несовместимы, будет использована устаревшая система; в противном случае — новое меню.enabled: использовать новое меню. Если у вас есть несовместимый плагин или тема, ваш сайт может перестать работать корректно.
Мы уже обновили наши официальные плагины для совместимости с новым меню, но если у вас всё ещё есть сторонние плагины, темы или компоненты тем, несовместимые с новым меню, потребуется их обновление.
В консоли браузера будут выводиться предупреждения, указывающие источник несовместимости.
План внедрения
Эти сроки являются приблизительными и могут быть изменены
IV квартал 2024 года:
реализация в ядре завершена
официальные плагины обновлены
включено на Meta
glimmer_post_menu_modeпо умолчанию установлено вauto; включены сообщения об устаревании в консоли
опубликованы рекомендации по обновлению
I квартал 2025 года:
сторонние плагины и темы должны быть обновлены
начнут выводиться сообщения об устаревании, вызывающие предупреждающий баннер для администратора при наличии оставшихся проблем
новое меню постов включено по умолчанию
II квартал 2025 года
1 апреля — удаление настройки флага функции и устаревшего кода
Что это значит для меня?
Если ваш плагин или тема использует какие-либо API «widget» для кастомизации меню постов, их необходимо обновить для совместимости с новой версией.
Как попробовать новое меню постов?
В последней версии Discourse новое меню постов будет включено, если у вас нет несовместимых плагинов или тем.
Если у вас установлены несовместимые расширения, вы как администратор всё ещё можете изменить настройку на enabled, чтобы принудительно использовать новое меню. Используйте это с осторожностью, так как ваш сайт может перестать работать корректно в зависимости от установленных кастомизаций.
В маловероятном случае, если эта автоматическая система не работает как ожидалось, вы можете временно переопределить этот «автоматический флаг функции» с помощью указанной выше настройки. Если вам потребуется это сделать, пожалуйста, сообщите нам в этой теме.
Нужно ли мне обновлять мой плагин или тему?
Вам потребуется обновить ваши плагины или темы, если они выполняют любую из следующих кастомизаций:
-
Используют
decorateWidget,changeWidgetSetting,reopenWidgetилиattachWidgetActionдля следующих виджетов:post-menupost-user-tip-shimsmall-user-list
-
Используют любые из следующих методов API:
addPostMenuButtonremovePostMenuButtonreplacePostMenuButton
Если у вас есть расширения, выполняющие одну из указанных выше кастомизаций, при доступе к странице темы в консоли будет выведено предупреждение, указывающее плагин или компонент, требующий обновления.
ID устаревания:
discourse.post-menu-widget-overrides
Если вы используете более одной темы в вашем экземпляре, обязательно проверьте все из них, так как предупреждения будут выводиться только для активных плагинов и в настоящее время используемых тем и компонентов тем.
Какие существуют замены?
Мы внедрили трансформатор значений post-menu-buttons как новый API для кастомизации меню постов.
Трансформатор значений предоставляет объект DAG, который позволяет добавлять, заменять, удалять или изменять порядок кнопок. Он также предоставляет контекстную информацию, такую как пост, связанный с меню, состояние отображаемого поста и ключи кнопок для упрощения размещения элементов.
API DAG ожидает получение компонентов Ember, если API требует новое определение кнопки, например .add и .replace.
Каждая кастомизация уникальна, но вот некоторые рекомендации для наиболее распространенных случаев использования:
addPostMenuButton
До:
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",
};
}
});
});
После:
Приведенные ниже примеры используют формат шаблонов (gjs) в 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 {
// указывает, будет ли кнопка отображаться немедленно или скрыта за кнопкой «показать ещё»
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, // ключ первой кнопки
secondLastHiddenButtonKey, // ключ второй последней скрытой кнопки
lastHiddenButtonKey, // ключ последней скрытой кнопки
},
}) => {
dag.add(
"solved",
SolvedAcceptAnswerButton,
post.topic_accepted_answer
? {
before: lastHiddenButtonKey,
after: secondLastHiddenButtonKey,
}
: {
before: [
"assign", // кнопка, добавленная плагином assign
firstButtonKey,
],
}
);
}
);
});
Стилизация ваших кнопок
Рекомендуется включать
...attributes, как показано в примере выше, в ваш компонент.В сочетании с использованием компонентов
DButtonилиDMenuэто обеспечит базовые классы и гарантирует, что ваша кнопка будет соответствовать форматированию других кнопок в меню постов.Дополнительное форматирование можно указать с помощью ваших собственных классов.
replacePostMenuButton
- До:
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;
},
});
});
- После:
import ReactionsActionButton from "../components/discourse-reactions-actions-button";
...
withPluginApi("1.34.0", (api) => {
api.registerValueTransformer(
"post-menu-buttons",
({ value: dag, context: { buttonKeys } }) => {
// ReactionsActionButton — это новый компонент кнопки
dag.replace(buttonKeys.LIKE, ReactionsActionButton);
}
);
});
removePostMenuButton
- До:
withPluginApi("1.34.0", (api) => {
api.removePostMenuButton('like', (attrs, state, siteSettings, settings, currentUser) => {
if (attrs.post_number === 1) {
return true;
}
});
});
- После:
withPluginApi("1.34.0", (api) => {
api.registerValueTransformer(
"post-menu-buttons",
({ value: dag, context: { post, buttonKeys } }) => {
if (post.post_number === 1) {
dag.delete(buttonKeys.LIKE);
}
}
);
});
А что насчет других кастомизаций?
Если ваша кастомизация не может быть реализована с помощью нового API, который мы внедрили, пожалуйста, сообщите нам, создав новую тему для разработчиков для обсуждения.
Я автор плагина/темы. Как обновить тему/плагин для поддержки как старого, так и нового меню постов в период перехода?
Мы использовали следующую схему для поддержки обеих версий меню постов в наших плагинах:
function customizePostMenu(api) {
const transformerRegistered = api.registerValueTransformer(
"post-menu-buttons",
({ value: dag, context }) => {
// новые кастомизации меню постов
...
}
);
const silencedKey =
transformerRegistered && "discourse.post-menu-widget-overrides";
withSilencedDeprecations(silencedKey, () => customizeWidgetPostMenu(api));
}
function customizeWidgetPostMenu(api) {
// здесь старая кастомизация кода «widget»
...
}
export default {
name: "my-plugin",
initialize(container) {
withPluginApi("1.34.0", customizePostMenu);
}
};
Дополнительные примеры
Вы можете проверить наши официальные плагины, чтобы увидеть примеры использования нового API: