diff --git a/app/assets/javascripts/discourse/app/components/plugin-outlet.gjs b/app/assets/javascripts/discourse/app/components/plugin-outlet.gjs index 152d0dbefbbaf..b6b52e0ff0b84 100644 --- a/app/assets/javascripts/discourse/app/components/plugin-outlet.gjs +++ b/app/assets/javascripts/discourse/app/components/plugin-outlet.gjs @@ -1,9 +1,11 @@ import Component from "@glimmer/component"; import { cached } from "@glimmer/tracking"; +import ClassicComponent from "@ember/component"; import { concat } from "@ember/helper"; import { get } from "@ember/object"; import { getOwner } from "@ember/owner"; import { service } from "@ember/service"; +import curryComponent from "ember-curry-component"; import { or } from "truth-helpers"; import PluginConnector from "discourse/components/plugin-connector"; import PluginOutlet from "discourse/components/plugin-outlet"; @@ -124,6 +126,29 @@ export default class PluginOutletComponent extends Component { ); } + @bind + safeCurryComponent(component, args) { + if (component.prototype instanceof ClassicComponent) { + for (const arg of Object.keys(args)) { + if (component.prototype.hasOwnProperty(arg)) { + deprecated( + `Unable to set @${arg} on connector for ${this.args.name}, because a property on the component class clashes with the argument name. Resolve the clash, or convert to a glimmer component.`, + { + id: "discourse.plugin-outlet-classic-args-clash", + } + ); + + // Build a clone of `args`, without the offending key, while preserving getters + const descriptors = Object.getOwnPropertyDescriptors(args); + delete descriptors[arg]; + args = Object.defineProperties({}, descriptors); + } + } + } + + return curryComponent(component, args, getOwner(this)); + } + + ); + + await render( + + ); + assert.dom(".glimmer-test").hasText("Hello world from glimmer"); + }); + + test("makes arguments available at top level in classic components", async function (assert) { + extraConnectorComponent( + "test-name", + class extends ClassicComponent { + + } + ); + + await render( + + ); + assert.dom(".classic-test").hasText("Hello world from classic"); + }); + + test("guards against name clashes in classic components", async function (assert) { + extraConnectorComponent( + "test-name", + class extends ClassicComponent { + get arg1() { + return "overridden"; + } + + + } + ); + + await withSilencedDeprecationsAsync( + "discourse.plugin-outlet-classic-args-clash", + async () => { + await render( + + ); + } + ); + assert.dom(".classic-test").hasText("overridden from classic"); + }); + } +);