From 1337a6684f56a388b04cb9441bb9072b0722c501 Mon Sep 17 00:00:00 2001 From: David Taylor Date: Thu, 15 May 2025 10:52:05 +0100 Subject: [PATCH 1/4] DEV: Make outletArgs available as regular arguments in PluginOutlet Historically, plugin outlet arguments had to be accessed like `@outletArgs.foo` in templates, or `this.args.outletArgs.foo` in javascript. Following this commit, outletArgs will be passed to connector components at the top level, so they can be accessed like `@foo` in templates or `this.args.foo` in JS. `@outletArgs` remains available for compatibility, and there are no plans to remove it. For custom classic component connectors, these new arguments may clash with functions/fields defined on the component class. This rare case will be automatically detected, protected against, and a deprecation will be shown. --- .../app/components/plugin-outlet.gjs | 38 ++++++++- .../services/deprecation-warning-handler.js | 1 + .../plugin-outlet-debug/args-table.gjs | 4 +- .../components/plugin-outlet-test.gjs | 78 +++++++++++++++++++ 4 files changed, 116 insertions(+), 5 deletions(-) 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(".gjs-test").hasText("Hello world from gjs"); + }); + + 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("makes arguments available at top level 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"); + }); + } +); From 1c9ab9456790baa2ad84cbadee373436cb1774cd Mon Sep 17 00:00:00 2001 From: David Taylor Date: Fri, 16 May 2025 17:44:38 +0100 Subject: [PATCH 2/4] gjs != glimmer --- .../tests/integration/components/plugin-outlet-test.gjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/discourse/tests/integration/components/plugin-outlet-test.gjs b/app/assets/javascripts/discourse/tests/integration/components/plugin-outlet-test.gjs index cb8ba696a8ae3..f6cda1d374d1c 100644 --- a/app/assets/javascripts/discourse/tests/integration/components/plugin-outlet-test.gjs +++ b/app/assets/javascripts/discourse/tests/integration/components/plugin-outlet-test.gjs @@ -1067,7 +1067,7 @@ module( extraConnectorComponent( "test-name", ); @@ -1079,7 +1079,7 @@ module( /> ); - assert.dom(".gjs-test").hasText("Hello world from gjs"); + assert.dom(".glimmer-test").hasText("Hello world from glimmer"); }); test("makes arguments available at top level in classic components", async function (assert) { From 6938740ccd9d07adcd3f0b51ba2b9b85c5890122 Mon Sep 17 00:00:00 2001 From: David Taylor Date: Fri, 16 May 2025 17:46:58 +0100 Subject: [PATCH 3/4] test name --- .../tests/integration/components/plugin-outlet-test.gjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/tests/integration/components/plugin-outlet-test.gjs b/app/assets/javascripts/discourse/tests/integration/components/plugin-outlet-test.gjs index f6cda1d374d1c..ea9eb591c7ba3 100644 --- a/app/assets/javascripts/discourse/tests/integration/components/plugin-outlet-test.gjs +++ b/app/assets/javascripts/discourse/tests/integration/components/plugin-outlet-test.gjs @@ -1103,7 +1103,7 @@ module( assert.dom(".classic-test").hasText("Hello world from classic"); }); - test("makes arguments available at top level in classic components", async function (assert) { + test("guards against name clashes in classic components", async function (assert) { extraConnectorComponent( "test-name", class extends ClassicComponent { From 393a0934764cf60e538304c7b06c047c3abe88dc Mon Sep 17 00:00:00 2001 From: David Taylor Date: Fri, 16 May 2025 17:59:19 +0100 Subject: [PATCH 4/4] Update app/assets/javascripts/discourse/tests/integration/components/plugin-outlet-test.gjs Co-authored-by: Jarek Radosz --- .../tests/integration/components/plugin-outlet-test.gjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/tests/integration/components/plugin-outlet-test.gjs b/app/assets/javascripts/discourse/tests/integration/components/plugin-outlet-test.gjs index ea9eb591c7ba3..9e9711b50604e 100644 --- a/app/assets/javascripts/discourse/tests/integration/components/plugin-outlet-test.gjs +++ b/app/assets/javascripts/discourse/tests/integration/components/plugin-outlet-test.gjs @@ -1067,7 +1067,7 @@ module( extraConnectorComponent( "test-name", );