DEV: Prepare modal implementation for Ember upgrade (#24564)

- Skip rendering DModalLegacy when running Ember 5
- Move named outlet inside the DModalLegacy component file
- Exclude that DModalLegacy template from the build when running Ember 5
- Skip LegacySupport version of modal service when running Ember 5
- Add error popup for legacy modals when running Ember 5

Extracted from https://github.com/discourse/discourse/pull/21720. This is a no-op under our current Ember 3.28 version.
This commit is contained in:
David Taylor 2023-11-27 13:50:25 +00:00 committed by GitHub
parent 59bae95190
commit 056898c55f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 79 additions and 28 deletions

View File

@ -76,7 +76,7 @@
{{~this.flash.text~}} {{~this.flash.text~}}
</div> </div>
{{yield}} {{outlet "modalBody"}}
{{#each this.errors as |error|}} {{#each this.errors as |error|}}
<div class="alert alert-error"> <div class="alert alert-error">

View File

@ -11,8 +11,7 @@
{{/each}} {{/each}}
{{/if}} {{/if}}
{{! Legacy modals depend on this wrapper being in the DOM at all times. Eventually this will be dropped. {{#if this.renderLegacy}}
For now, we mitigate the potential impact on things like tests by removing the `modal` and `d-modal` classes when inactive }}
<DModalLegacy <DModalLegacy
@modalClass={{if @modalClass={{if
this.modal.isLegacy this.modal.isLegacy
@ -31,6 +30,5 @@ For now, we mitigate the potential impact on things like tests by removing the `
@hidden={{this.modal.hidden}} @hidden={{this.modal.hidden}}
@errors={{this.modal.errors}} @errors={{this.modal.errors}}
@closeModal={{this.closeModal}} @closeModal={{this.closeModal}}
> />
{{outlet "modalBody"}} {{/if}}
</DModalLegacy>

View File

@ -1,6 +1,7 @@
import Component from "@glimmer/component"; import Component from "@glimmer/component";
import { action } from "@ember/object"; import { action } from "@ember/object";
import { inject as service } from "@ember/service"; import { inject as service } from "@ember/service";
import { EMBER_MAJOR_VERSION } from "discourse/lib/ember-version";
export default class ModalContainer extends Component { export default class ModalContainer extends Component {
@service modal; @service modal;
@ -9,4 +10,8 @@ export default class ModalContainer extends Component {
closeModal(data) { closeModal(data) {
this.modal.close(data); this.modal.close(data);
} }
get renderLegacy() {
return EMBER_MAJOR_VERSION < 4;
}
} }

View File

@ -0,0 +1,5 @@
import { VERSION } from "@ember/version";
const parts = VERSION.split(".");
export const EMBER_MAJOR_VERSION = parseInt(parts[0], 10);

View File

@ -5,6 +5,7 @@ import Service, { inject as service } from "@ember/service";
import { dasherize } from "@ember/string"; import { dasherize } from "@ember/string";
import $ from "jquery"; import $ from "jquery";
import { CLOSE_INITIATED_BY_MODAL_SHOW } from "discourse/components/d-modal"; import { CLOSE_INITIATED_BY_MODAL_SHOW } from "discourse/components/d-modal";
import { EMBER_MAJOR_VERSION } from "discourse/lib/ember-version";
import { disableImplicitInjections } from "discourse/lib/implicit-injections"; import { disableImplicitInjections } from "discourse/lib/implicit-injections";
import deprecated, { import deprecated, {
withSilencedDeprecations, withSilencedDeprecations,
@ -23,6 +24,8 @@ const LEGACY_OPTS = new Set([
@disableImplicitInjections @disableImplicitInjections
class ModalService extends Service { class ModalService extends Service {
@service dialog;
@tracked activeModal; @tracked activeModal;
@tracked opts = {}; @tracked opts = {};
@ -43,6 +46,23 @@ class ModalService extends Service {
* @returns {Promise} A promise that resolves when the modal is closed, with any data passed to closeModal * @returns {Promise} A promise that resolves when the modal is closed, with any data passed to closeModal
*/ */
show(modal, opts) { show(modal, opts) {
if (typeof modal === "string") {
this.dialog.alert(
`Error: the '${modal}' modal needs updating to work with the latest version of Discourse. See https://meta.discourse.org/t/268057.`
);
deprecated(
`Defining modals using a controller is no longer supported. Use the component-based API instead. (modal: ${modal})`,
{
id: "discourse.modal-controllers",
since: "3.1",
dropFrom: "3.2",
url: "https://meta.discourse.org/t/268057",
raiseError: true,
}
);
return;
}
this.close({ initiatedBy: CLOSE_INITIATED_BY_MODAL_SHOW }); this.close({ initiatedBy: CLOSE_INITIATED_BY_MODAL_SHOW });
let resolveShowPromise; let resolveShowPromise;
@ -50,7 +70,7 @@ class ModalService extends Service {
resolveShowPromise = resolve; resolveShowPromise = resolve;
}); });
this.opts = opts || {}; this.opts = opts ??= {};
this.activeModal = { component: modal, opts, resolveShowPromise }; this.activeModal = { component: modal, opts, resolveShowPromise };
const unsupportedOpts = Object.keys(opts).filter((key) => const unsupportedOpts = Object.keys(opts).filter((key) =>
@ -75,7 +95,7 @@ class ModalService extends Service {
} }
// Remove all logic below when legacy modals are dropped (deprecation: discourse.modal-controllers) // Remove all logic below when legacy modals are dropped (deprecation: discourse.modal-controllers)
export default class ModalServiceWithLegacySupport extends ModalService { class ModalServiceWithLegacySupport extends ModalService {
@service appEvents; @service appEvents;
@tracked name; @tracked name;
@ -261,3 +281,7 @@ export default class ModalServiceWithLegacySupport extends ModalService {
return this.name && !this.activeModal; return this.name && !this.activeModal;
} }
} }
export default EMBER_MAJOR_VERSION >= 4
? ModalService
: ModalServiceWithLegacySupport;

View File

@ -17,8 +17,25 @@ const { StatsWriterPlugin } = require("webpack-stats-plugin");
const withSideWatch = require("./lib/with-side-watch"); const withSideWatch = require("./lib/with-side-watch");
const RawHandlebarsCompiler = require("discourse-hbr/raw-handlebars-compiler"); const RawHandlebarsCompiler = require("discourse-hbr/raw-handlebars-compiler");
const EMBER_MAJOR_VERSION = parseInt(
require("ember-source/package.json").version.split(".")[0],
10
);
process.env.BROCCOLI_ENABLED_MEMOIZE = true; process.env.BROCCOLI_ENABLED_MEMOIZE = true;
function filterForEmberVersion(tree) {
if (EMBER_MAJOR_VERSION < 4) {
return tree;
}
return funnel(tree, {
// d-modal-legacy includes a named outlet which would cause
// a build failure in modern Ember
exclude: ["**/components/d-modal-legacy.hbs"],
});
}
module.exports = function (defaults) { module.exports = function (defaults) {
const discourseRoot = path.resolve("../../../.."); const discourseRoot = path.resolve("../../../..");
const vendorJs = discourseRoot + "/vendor/assets/javascripts/"; const vendorJs = discourseRoot + "/vendor/assets/javascripts/";
@ -74,8 +91,10 @@ module.exports = function (defaults) {
}, },
trees: { trees: {
app: RawHandlebarsCompiler( app: filterForEmberVersion(
RawHandlebarsCompiler(
withSideWatch("app", { watching: ["../discourse-markdown-it"] }) withSideWatch("app", { watching: ["../discourse-markdown-it"] })
)
), ),
}, },
}); });