From b8adb70973a133eaa053f33424240afea86af83a Mon Sep 17 00:00:00 2001 From: Penar Musaraj Date: Tue, 13 Sep 2022 12:30:52 -0400 Subject: [PATCH] DEV: Refactor composer and logout dialogs (#18156) --- .../discourse/app/controllers/composer.js | 115 +++++++++--------- .../discourse/app/initializers/logout.js | 35 +++--- .../discourse/app/models/composer.js | 42 +++---- .../tests/acceptance/composer-test.js | 17 +-- .../discourse/tests/acceptance/user-test.js | 27 ++++ .../stylesheets/common/base/dialog.scss | 1 + app/assets/stylesheets/common/base/modal.scss | 10 +- 7 files changed, 136 insertions(+), 111 deletions(-) diff --git a/app/assets/javascripts/discourse/app/controllers/composer.js b/app/assets/javascripts/discourse/app/controllers/composer.js index 7aa93052ead..14017465546 100644 --- a/app/assets/javascripts/discourse/app/controllers/composer.js +++ b/app/assets/javascripts/discourse/app/controllers/composer.js @@ -18,9 +18,7 @@ import discourseComputed, { import DiscourseURL from "discourse/lib/url"; import Draft from "discourse/models/draft"; import I18n from "I18n"; -import { iconHTML } from "discourse-common/lib/icon-library"; import { Promise } from "rsvp"; -import bootbox from "bootbox"; import { buildQuote } from "discourse/lib/quote"; import deprecated from "discourse-common/lib/deprecated"; import discourseDebounce from "discourse-common/lib/debounce"; @@ -87,6 +85,7 @@ export function addPopupMenuOptionsCallback(callback) { export default Controller.extend({ topicController: controller("topic"), router: service(), + dialog: service(), checkedMessages: false, messageCount: null, @@ -858,7 +857,7 @@ export default Controller.extend({ timeLeft: durationTextFromSeconds(timeLeft), }); - bootbox.alert(message); + this.dialog.alert(message); return; } else { // Edge case where the user tries to post again immediately. @@ -885,40 +884,37 @@ export default Controller.extend({ currentTopic.id !== composer.get("topic.id") && (this.isStaffUser || !currentTopic.closed) ) { - const message = - "

" + I18n.t("composer.posting_not_on_topic") + "

"; - - let buttons = [ - { - label: I18n.t("composer.cancel"), - class: "btn-flat btn-text btn-reply-where-cancel", - }, - ]; - - buttons.push({ - label: - I18n.t("composer.reply_here") + - "
" + - currentTopic.get("fancyTitle") + - "
", - class: "btn-reply-here", - callback: () => { - composer.setProperties({ topic: currentTopic, post: null }); - this.save(true); - }, + this.dialog.alert({ + title: I18n.t("composer.posting_not_on_topic"), + buttons: [ + { + label: + I18n.t("composer.reply_original") + + "
" + + this.get("model.topic.fancyTitle") + + "
", + class: "btn-primary btn-reply-on-original", + action: () => this.save(true), + }, + { + label: + I18n.t("composer.reply_here") + + "
" + + currentTopic.get("fancyTitle") + + "
", + class: "btn-reply-here", + action: () => { + composer.setProperties({ topic: currentTopic, post: null }); + this.save(true); + }, + }, + { + label: I18n.t("composer.cancel"), + class: "btn-flat btn-text btn-reply-where-cancel", + }, + ], + class: "reply-where-modal", }); - - buttons.push({ - label: - I18n.t("composer.reply_original") + - "
" + - this.get("model.topic.fancyTitle") + - "
", - class: "btn-primary btn-reply-on-original", - callback: () => this.save(true), - }); - - bootbox.dialog(message, buttons, { classes: "reply-where-modal" }); return; } } @@ -987,8 +983,11 @@ export default Controller.extend({ // TODO: await this: this.destroyDraft(); if (result.responseJson.message) { - return bootbox.alert(result.responseJson.message, () => { - DiscourseURL.routeTo(result.responseJson.route_to); + return this.dialog.alert({ + message: result.responseJson.message, + didConfirm: () => { + DiscourseURL.routeTo(result.responseJson.route_to); + }, }); } return DiscourseURL.routeTo(result.responseJson.route_to); @@ -1010,7 +1009,9 @@ export default Controller.extend({ .catch((error) => { composer.set("disableDrafts", false); if (error) { - this.appEvents.one("composer:will-open", () => bootbox.alert(error)); + this.appEvents.one("composer:will-open", () => + this.dialog.alert(error) + ); } }); @@ -1295,23 +1296,27 @@ export default Controller.extend({ } return new Promise((resolve) => { - bootbox.dialog(I18n.t("drafts.abandon.confirm"), [ - { - label: I18n.t("drafts.abandon.no_value"), - callback: () => resolve(data), - }, - { - label: I18n.t("drafts.abandon.yes_value"), - class: "btn-danger", - icon: iconHTML("far-trash-alt"), - callback: () => { - this.destroyDraft(data.draft_sequence).finally(() => { - data.draft = null; - resolve(data); - }); + this.dialog.alert({ + message: I18n.t("drafts.abandon.confirm"), + buttons: [ + { + label: I18n.t("drafts.abandon.yes_value"), + class: "btn-danger", + icon: "far-trash-alt", + action: () => { + this.destroyDraft(data.draft_sequence).finally(() => { + data.draft = null; + resolve(data); + }); + }, }, - }, - ]); + { + label: I18n.t("drafts.abandon.no_value"), + class: "btn-resume-editing", + action: () => resolve(data), + }, + ], + }); }); }, diff --git a/app/assets/javascripts/discourse/app/initializers/logout.js b/app/assets/javascripts/discourse/app/initializers/logout.js index 2bc7a3822fc..70eb8068da1 100644 --- a/app/assets/javascripts/discourse/app/initializers/logout.js +++ b/app/assets/javascripts/discourse/app/initializers/logout.js @@ -1,5 +1,4 @@ import I18n from "I18n"; -import bootbox from "bootbox"; import logout from "discourse/lib/logout"; let _showingLogout = false; @@ -10,25 +9,27 @@ export default { after: "message-bus", initialize(container) { - const messageBus = container.lookup("service:message-bus"); - messageBus.subscribe("/logout", () => { - if (_showingLogout) { - return; + const messageBus = container.lookup("service:message-bus"), + dialog = container.lookup("service:dialog"); + + if (!messageBus) { + return; + } + + messageBus.subscribe("/logout", function () { + if (!_showingLogout) { + _showingLogout = true; + + dialog.alert({ + message: I18n.t("logout"), + confirmButtonLabel: "home", + didConfirm: logout, + didCancel: logout, + shouldDisplayCancel: false, + }); } _showingLogout = true; - - bootbox.dialog( - I18n.t("logout"), - { - label: I18n.t("home"), - callback: logout, - }, - { - onEscape: logout, - backdrop: "static", - } - ); }); }, }; diff --git a/app/assets/javascripts/discourse/app/models/composer.js b/app/assets/javascripts/discourse/app/models/composer.js index 9b4854a638c..2c365f47f25 100644 --- a/app/assets/javascripts/discourse/app/models/composer.js +++ b/app/assets/javascripts/discourse/app/models/composer.js @@ -18,7 +18,7 @@ import RestModel from "discourse/models/rest"; import Site from "discourse/models/site"; import Topic from "discourse/models/topic"; import User from "discourse/models/user"; -import bootbox from "bootbox"; +import { inject as service } from "@ember/service"; import deprecated from "discourse-common/lib/deprecated"; import { isEmpty } from "@ember/utils"; import { propertyNotEqual } from "discourse/lib/computed"; @@ -119,6 +119,7 @@ export const SAVE_ICONS = { }; const Composer = RestModel.extend({ + dialog: service(), _categoryId: null, unlistTopic: false, noBump: false, @@ -453,7 +454,9 @@ const Composer = RestModel.extend({ const category = this.category; if (category && category.topic_template) { if (this.reply.trim() === category.topic_template.trim()) { - bootbox.alert(I18n.t("composer.error.topic_template_not_modified")); + this.dialog.alert( + I18n.t("composer.error.topic_template_not_modified") + ); return true; } } @@ -1277,28 +1280,23 @@ const Composer = RestModel.extend({ ) { const json = e.jqXHR.responseJSON; draftStatus = json.errors[0]; - if (json.extras && json.extras.description) { - const buttons = []; - // ignore and force save draft - buttons.push({ - label: I18n.t("composer.ignore"), - class: "btn", - callback: () => { - this.set("draftForceSave", true); - }, + if (json.extras?.description) { + this.dialog.alert({ + message: json.extras.description, + buttons: [ + { + label: I18n.t("composer.reload"), + class: "btn-primary", + action: () => window.location.reload(), + }, + { + label: I18n.t("composer.ignore"), + class: "btn", + action: () => this.set("draftForceSave", true), + }, + ], }); - - // reload - buttons.push({ - label: I18n.t("composer.reload"), - class: "btn btn-primary", - callback: () => { - window.location.reload(); - }, - }); - - bootbox.dialog(json.extras.description, buttons); } } this.setProperties({ diff --git a/app/assets/javascripts/discourse/tests/acceptance/composer-test.js b/app/assets/javascripts/discourse/tests/acceptance/composer-test.js index 422b64a7545..7ebab8402c1 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/composer-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/composer-test.js @@ -182,9 +182,9 @@ acceptance("Composer", function (needs) { await fillIn("#reply-title", "this title triggers an error"); await fillIn(".d-editor-input", "this is the *content* of a post"); await click("#reply-control button.create"); - assert.ok(exists(".bootbox.modal"), "it pops up an error message"); - await click(".bootbox.modal a.btn-primary"); - assert.ok(!exists(".bootbox.modal"), "it dismisses the error"); + assert.ok(exists(".dialog-body"), "it pops up an error message"); + await click(".dialog-footer .btn-primary"); + assert.ok(!exists(".dialog-body"), "it dismisses the error"); assert.ok(exists(".d-editor-input"), "the composer input is visible"); }); @@ -223,13 +223,14 @@ acceptance("Composer", function (needs) { await fillIn("#reply-title", "This title doesn't matter"); await fillIn(".d-editor-input", "custom message"); await click("#reply-control button.create"); + assert.strictEqual( - query(".bootbox .modal-body").innerText, + query("#dialog-holder .dialog-body").innerText, "This is a custom response" ); assert.strictEqual(currentURL(), "/", "it doesn't change routes"); - await click(".bootbox .btn-primary"); + await click(".dialog-footer .btn-primary"); assert.strictEqual( currentURL(), "/faq", @@ -764,11 +765,11 @@ acceptance("Composer", function (needs) { await click(".topic-post:nth-of-type(1) button.edit"); assert.strictEqual( - query(".modal-body").innerText, + query(".dialog-body").innerText, I18n.t("drafts.abandon.confirm") ); - await click(".modal-footer .btn.btn-default"); + await click(".dialog-footer .btn-resume-editing"); }); test("Can switch states without abandon popup", async function (assert) { @@ -826,7 +827,7 @@ acceptance("Composer", function (needs) { await visit("/u/charlie"); await click("button.compose-pm"); - await click(".modal .btn-default"); + await click(".dialog-footer .btn-resume-editing"); const privateMessageUsers = selectKit("#private-message-users"); assert.strictEqual(privateMessageUsers.header().value(), "codinghorror"); diff --git a/app/assets/javascripts/discourse/tests/acceptance/user-test.js b/app/assets/javascripts/discourse/tests/acceptance/user-test.js index 54711f0aff1..e54642d5fee 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/user-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/user-test.js @@ -1,3 +1,4 @@ +import I18n from "I18n"; import EmberObject from "@ember/object"; import User from "discourse/models/user"; import selectKit from "discourse/tests/helpers/select-kit-helper"; @@ -6,10 +7,12 @@ import userFixtures from "discourse/tests/fixtures/user-fixtures"; import { acceptance, exists, + publishToMessageBus, query, queryAll, updateCurrentUser, } from "discourse/tests/helpers/qunit-helpers"; +import * as logout from "discourse/lib/logout"; import { click, currentRouteName, visit } from "@ember/test-helpers"; import { cloneJSON } from "discourse-common/lib/object"; import { test } from "qunit"; @@ -305,3 +308,27 @@ acceptance( }); } ); + +acceptance("User - Logout", function (needs) { + needs.user({ username: "eviltrout" }); + + test("Dialog works", async function (assert) { + sinon.stub(logout, "default"); + await visit("/u/eviltrout"); + await publishToMessageBus("/logout"); + + assert.ok(exists(".dialog-body")); + assert.ok( + !exists(".dialog-footer .btn-default"), + "no cancel button present" + ); + assert.strictEqual( + query(".dialog-footer .btn-primary").innerText, + I18n.t("home"), + "primary dialog button is present" + ); + + await click(".dialog-overlay"); + assert.ok(logout.default.called, "logout helper was called"); + }); +}); diff --git a/app/assets/stylesheets/common/base/dialog.scss b/app/assets/stylesheets/common/base/dialog.scss index 566ea39bdec..d5e60bf7c2e 100644 --- a/app/assets/stylesheets/common/base/dialog.scss +++ b/app/assets/stylesheets/common/base/dialog.scss @@ -59,6 +59,7 @@ .dialog-close { margin-left: auto; + flex-basis: content; .d-icon { color: var(--primary-high); } diff --git a/app/assets/stylesheets/common/base/modal.scss b/app/assets/stylesheets/common/base/modal.scss index e0872b274fe..f067f904989 100644 --- a/app/assets/stylesheets/common/base/modal.scss +++ b/app/assets/stylesheets/common/base/modal.scss @@ -278,15 +278,7 @@ } } -.bootbox.modal.reply-where-modal { - max-width: 400px; - margin-left: -200px; - - h1 { - margin: 0; - font-size: var(--font-up-2); - } - +.reply-where-modal { .btn { display: block; text-align: left;