diff --git a/app/assets/javascripts/discourse/app/components/d-modal-legacy.hbs b/app/assets/javascripts/discourse/app/components/d-modal-legacy.hbs
index 725ae76127f..c1dfef988b1 100644
--- a/app/assets/javascripts/discourse/app/components/d-modal-legacy.hbs
+++ b/app/assets/javascripts/discourse/app/components/d-modal-legacy.hbs
@@ -76,7 +76,7 @@
{{~this.flash.text~}}
- {{yield}}
+ {{outlet "modalBody"}}
{{#each this.errors as |error|}}
diff --git a/app/assets/javascripts/discourse/app/components/modal-container.hbs b/app/assets/javascripts/discourse/app/components/modal-container.hbs
index 24ad1d2563b..8fbc159fc07 100644
--- a/app/assets/javascripts/discourse/app/components/modal-container.hbs
+++ b/app/assets/javascripts/discourse/app/components/modal-container.hbs
@@ -11,26 +11,24 @@
{{/each}}
{{/if}}
-{{! Legacy modals depend on this wrapper being in the DOM at all times. Eventually this will be dropped.
-For now, we mitigate the potential impact on things like tests by removing the `modal` and `d-modal` classes when inactive }}
-
- {{outlet "modalBody"}}
-
\ No newline at end of file
+{{#if this.renderLegacy}}
+
+{{/if}}
\ No newline at end of file
diff --git a/app/assets/javascripts/discourse/app/components/modal-container.js b/app/assets/javascripts/discourse/app/components/modal-container.js
index a9fb2bd052e..7078b4936db 100644
--- a/app/assets/javascripts/discourse/app/components/modal-container.js
+++ b/app/assets/javascripts/discourse/app/components/modal-container.js
@@ -1,6 +1,7 @@
import Component from "@glimmer/component";
import { action } from "@ember/object";
import { inject as service } from "@ember/service";
+import { EMBER_MAJOR_VERSION } from "discourse/lib/ember-version";
export default class ModalContainer extends Component {
@service modal;
@@ -9,4 +10,8 @@ export default class ModalContainer extends Component {
closeModal(data) {
this.modal.close(data);
}
+
+ get renderLegacy() {
+ return EMBER_MAJOR_VERSION < 4;
+ }
}
diff --git a/app/assets/javascripts/discourse/app/lib/ember-version.js b/app/assets/javascripts/discourse/app/lib/ember-version.js
new file mode 100644
index 00000000000..cde7ff34043
--- /dev/null
+++ b/app/assets/javascripts/discourse/app/lib/ember-version.js
@@ -0,0 +1,5 @@
+import { VERSION } from "@ember/version";
+
+const parts = VERSION.split(".");
+
+export const EMBER_MAJOR_VERSION = parseInt(parts[0], 10);
diff --git a/app/assets/javascripts/discourse/app/services/modal.js b/app/assets/javascripts/discourse/app/services/modal.js
index 19c2c7777b6..70df71c401e 100644
--- a/app/assets/javascripts/discourse/app/services/modal.js
+++ b/app/assets/javascripts/discourse/app/services/modal.js
@@ -5,6 +5,7 @@ import Service, { inject as service } from "@ember/service";
import { dasherize } from "@ember/string";
import $ from "jquery";
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 deprecated, {
withSilencedDeprecations,
@@ -23,6 +24,8 @@ const LEGACY_OPTS = new Set([
@disableImplicitInjections
class ModalService extends Service {
+ @service dialog;
+
@tracked activeModal;
@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
*/
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 });
let resolveShowPromise;
@@ -50,7 +70,7 @@ class ModalService extends Service {
resolveShowPromise = resolve;
});
- this.opts = opts || {};
+ this.opts = opts ??= {};
this.activeModal = { component: modal, opts, resolveShowPromise };
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)
-export default class ModalServiceWithLegacySupport extends ModalService {
+class ModalServiceWithLegacySupport extends ModalService {
@service appEvents;
@tracked name;
@@ -261,3 +281,7 @@ export default class ModalServiceWithLegacySupport extends ModalService {
return this.name && !this.activeModal;
}
}
+
+export default EMBER_MAJOR_VERSION >= 4
+ ? ModalService
+ : ModalServiceWithLegacySupport;
diff --git a/app/assets/javascripts/discourse/ember-cli-build.js b/app/assets/javascripts/discourse/ember-cli-build.js
index 85b91f46959..c7667f23dd1 100644
--- a/app/assets/javascripts/discourse/ember-cli-build.js
+++ b/app/assets/javascripts/discourse/ember-cli-build.js
@@ -17,8 +17,25 @@ const { StatsWriterPlugin } = require("webpack-stats-plugin");
const withSideWatch = require("./lib/with-side-watch");
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;
+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) {
const discourseRoot = path.resolve("../../../..");
const vendorJs = discourseRoot + "/vendor/assets/javascripts/";
@@ -74,8 +91,10 @@ module.exports = function (defaults) {
},
trees: {
- app: RawHandlebarsCompiler(
- withSideWatch("app", { watching: ["../discourse-markdown-it"] })
+ app: filterForEmberVersion(
+ RawHandlebarsCompiler(
+ withSideWatch("app", { watching: ["../discourse-markdown-it"] })
+ )
),
},
});