diff --git a/app/assets/javascripts/discourse/app/components/topic-footer-buttons.js b/app/assets/javascripts/discourse/app/components/topic-footer-buttons.js index e65a85aeb8e..5f91ecca8e2 100644 --- a/app/assets/javascripts/discourse/app/components/topic-footer-buttons.js +++ b/app/assets/javascripts/discourse/app/components/topic-footer-buttons.js @@ -2,6 +2,7 @@ import { alias, or } from "@ember/object/computed"; import { computed } from "@ember/object"; import Component from "@ember/component"; import discourseComputed from "discourse-common/utils/decorators"; +import { NotificationLevels } from "discourse/lib/notification-levels"; import { getTopicFooterButtons } from "discourse/lib/register-topic-footer-button"; import { getTopicFooterDropdowns } from "discourse/lib/register-topic-footer-dropdown"; @@ -46,6 +47,11 @@ export default Component.extend({ return !isPM || this.canSendPms; }, + @discourseComputed("topic.details.notification_level") + showNotificationUserTip(notificationLevel) { + return notificationLevel >= NotificationLevels.TRACKING; + }, + canSendPms: alias("currentUser.can_send_private_messages"), canInviteTo: alias("topic.details.can_invite_to"), diff --git a/app/assets/javascripts/discourse/app/components/user-tip.hbs b/app/assets/javascripts/discourse/app/components/user-tip.hbs new file mode 100644 index 00000000000..dc4b3e55d50 --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/user-tip.hbs @@ -0,0 +1 @@ + diff --git a/app/assets/javascripts/discourse/app/components/user-tip.js b/app/assets/javascripts/discourse/app/components/user-tip.js new file mode 100644 index 00000000000..d85656f898d --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/user-tip.js @@ -0,0 +1,35 @@ +import { action } from "@ember/object"; +import { inject as service } from "@ember/service"; +import Component from "@glimmer/component"; +import { hideUserTip } from "discourse/lib/user-tips"; +import I18n from "I18n"; + +export default class UserTip extends Component { + @service currentUser; + + @action + showUserTip(element) { + if (!this.currentUser) { + return; + } + + const { id, selector, content, placement } = this.args; + this.currentUser.showUserTip({ + id, + + titleText: I18n.t(`user_tips.${id}.title`), + contentText: content || I18n.t(`user_tips.${id}.content`), + + reference: selector + ? element.parentElement.querySelector(selector) || element.parentElement + : element, + appendTo: element.parentElement, + + placement: placement || "top", + }); + } + + willDestroy() { + hideUserTip(this.args.id); + } +} diff --git a/app/assets/javascripts/discourse/app/controllers/topic.js b/app/assets/javascripts/discourse/app/controllers/topic.js index 7e473e321cd..56a5b6ba4b8 100644 --- a/app/assets/javascripts/discourse/app/controllers/topic.js +++ b/app/assets/javascripts/discourse/app/controllers/topic.js @@ -611,6 +611,10 @@ export default Controller.extend(bufferedProperty("model"), { // Post related methods replyToPost(post) { + if (this.currentUser) { + this.currentUser.hideUserTipForever("post_menu"); + } + const composerController = this.composer; const topic = post ? post.get("topic") : this.model; const quoteState = this.quoteState; diff --git a/app/assets/javascripts/discourse/app/lib/user-tips.js b/app/assets/javascripts/discourse/app/lib/user-tips.js index 3eefac3bdea..df27654a90e 100644 --- a/app/assets/javascripts/discourse/app/lib/user-tips.js +++ b/app/assets/javascripts/discourse/app/lib/user-tips.js @@ -30,6 +30,7 @@ export function showUserTip(options) { arrow: iconHTML("tippy-rounded-arrow"), placement: options.placement, + appendTo: options.appendTo, // It often happens for the reference element to be rerendered. In this // case, tippy must be rerendered too. Having an animation means that the @@ -77,6 +78,15 @@ export function hideUserTip(userTipId) { instance.destroy(); } delete instances[userTipId]; + + const index = queue.findIndex((userTip) => userTip.id === userTipId); + if (index > -1) { + queue.splice(index, 1); + } +} + +export function hideAllUserTips() { + Object.keys(instances).forEach(hideUserTip); } function addToQueue(options) { diff --git a/app/assets/javascripts/discourse/app/models/user.js b/app/assets/javascripts/discourse/app/models/user.js index 89ae1f2fbd7..c12ea209f89 100644 --- a/app/assets/javascripts/discourse/app/models/user.js +++ b/app/assets/javascripts/discourse/app/models/user.js @@ -44,6 +44,7 @@ import { cancel } from "@ember/runloop"; import discourseLater from "discourse-common/lib/later"; import { isTesting } from "discourse-common/config/environment"; import { + hideAllUserTips, hideUserTip, showNextUserTip, showUserTip, @@ -1101,8 +1102,10 @@ const User = RestModel.extend({ } if (!userTips[options.id]) { - // eslint-disable-next-line no-console - console.warn("Cannot show user tip with type =", options.id); + if (!isTesting()) { + // eslint-disable-next-line no-console + console.warn("Cannot show user tip with type =", options.id); + } return; } @@ -1142,7 +1145,7 @@ const User = RestModel.extend({ seenUserTips.push(userTips[userTipId]); } } else { - Object.keys(userTips).forEach(hideUserTip); + hideAllUserTips(); seenUserTips = [-1]; } diff --git a/app/assets/javascripts/discourse/app/templates/components/suggested-topics.hbs b/app/assets/javascripts/discourse/app/templates/components/suggested-topics.hbs index 77ad43678b3..0725c3d6edc 100644 --- a/app/assets/javascripts/discourse/app/templates/components/suggested-topics.hbs +++ b/app/assets/javascripts/discourse/app/templates/components/suggested-topics.hbs @@ -1,4 +1,6 @@