feat(wrapComponents): new chain configuration option (#7236)
This commit provides a backward compatible mechanism to chain wrap an individual component multiple times `Chain` mode: allow chaining of plugins on a given component `Legacy` mode: last plugin to wrap a given component will supercede others * chore: Add unit test for wrapComponent wrapping * doc: Add documentation about the new pluginsOptions configuration * doc: Add a sidenote on plugin-api page Co-authored-by: Tim Lai <timothy.lai@gmail.com>
This commit is contained in:
@@ -388,6 +388,10 @@ const MyWrapComponentPlugin = function(system) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Note:**
|
||||||
|
|
||||||
|
If you have multiple plugins wrapping the same component, you may want to change the [`pluginsOptions.pluginLoadType`](/docs/usage/configuration.md#Plugins-options) parameter to `chain`.
|
||||||
|
|
||||||
#### `rootInjects`
|
#### `rootInjects`
|
||||||
|
|
||||||
The `rootInjects` interface allows you to inject values at the top level of the system.
|
The `rootInjects` interface allows you to inject values at the top level of the system.
|
||||||
|
|||||||
@@ -39,9 +39,16 @@ Read more about the plugin system in the [Customization documentation](/docs/cus
|
|||||||
Parameter name | Docker variable | Description
|
Parameter name | Docker variable | Description
|
||||||
--- | --- | -----
|
--- | --- | -----
|
||||||
<a name="layout"></a>`layout` | _Unavailable_ | `String="BaseLayout"`. The name of a component available via the plugin system to use as the top-level layout for Swagger UI.
|
<a name="layout"></a>`layout` | _Unavailable_ | `String="BaseLayout"`. The name of a component available via the plugin system to use as the top-level layout for Swagger UI.
|
||||||
|
<a name="pluginsOptions"></a>`pluginsOptions` | _Unavailable_ | `Object`. A Javascript object to configure plugin integration and behaviors (see below).
|
||||||
<a name="plugins"></a>`plugins` | _Unavailable_ | `Array=[]`. An array of plugin functions to use in Swagger UI.
|
<a name="plugins"></a>`plugins` | _Unavailable_ | `Array=[]`. An array of plugin functions to use in Swagger UI.
|
||||||
<a name="presets"></a>`presets` | _Unavailable_ | `Array=[SwaggerUI.presets.ApisPreset]`. An array of presets to use in Swagger UI. Usually, you'll want to include `ApisPreset` if you use this option.
|
<a name="presets"></a>`presets` | _Unavailable_ | `Array=[SwaggerUI.presets.ApisPreset]`. An array of presets to use in Swagger UI. Usually, you'll want to include `ApisPreset` if you use this option.
|
||||||
|
|
||||||
|
##### Plugins options
|
||||||
|
|
||||||
|
Parameter name | Docker variable | Description
|
||||||
|
--- | --- | -----
|
||||||
|
<a name="pluginLoadType"></a>`pluginLoadType` | _Unavailable_ | `String=["legacy", "chain"]`. Control behavior of plugins when targeting the same component with wrapComponent.<br/>- `legacy` (default) : last plugin takes precedence over the others<br/>- `chain` : chain wrapComponents when targeting the same core component, allowing multiple plugins to wrap the same component
|
||||||
|
|
||||||
##### Display
|
##### Display
|
||||||
|
|
||||||
Parameter name | Docker variable | Description
|
Parameter name | Docker variable | Description
|
||||||
|
|||||||
@@ -93,6 +93,13 @@ export default function SwaggerUI(opts) {
|
|||||||
plugins: [
|
plugins: [
|
||||||
],
|
],
|
||||||
|
|
||||||
|
pluginsOptions: {
|
||||||
|
// Behavior during plugin registration. Can be :
|
||||||
|
// - legacy (default) : the current behavior for backward compatibility – last plugin takes precedence over the others
|
||||||
|
// - chain : chain wrapComponents when targeting the same core component
|
||||||
|
pluginLoadType: "legacy"
|
||||||
|
},
|
||||||
|
|
||||||
// Initial state
|
// Initial state
|
||||||
initialState: { },
|
initialState: { },
|
||||||
|
|
||||||
@@ -118,6 +125,7 @@ export default function SwaggerUI(opts) {
|
|||||||
configs: constructorConfig.configs
|
configs: constructorConfig.configs
|
||||||
},
|
},
|
||||||
plugins: constructorConfig.presets,
|
plugins: constructorConfig.presets,
|
||||||
|
pluginsOptions: constructorConfig.pluginsOptions,
|
||||||
state: deepExtend({
|
state: deepExtend({
|
||||||
layout: {
|
layout: {
|
||||||
layout: constructorConfig.layout,
|
layout: constructorConfig.layout,
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ export default class Store {
|
|||||||
deepExtend(this, {
|
deepExtend(this, {
|
||||||
state: {},
|
state: {},
|
||||||
plugins: [],
|
plugins: [],
|
||||||
|
pluginsOptions: {},
|
||||||
system: {
|
system: {
|
||||||
configs: {},
|
configs: {},
|
||||||
fn: {},
|
fn: {},
|
||||||
@@ -63,7 +64,7 @@ export default class Store {
|
|||||||
}
|
}
|
||||||
|
|
||||||
register(plugins, rebuild=true) {
|
register(plugins, rebuild=true) {
|
||||||
var pluginSystem = combinePlugins(plugins, this.getSystem())
|
var pluginSystem = combinePlugins(plugins, this.getSystem(), this.pluginsOptions)
|
||||||
systemExtend(this.system, pluginSystem)
|
systemExtend(this.system, pluginSystem)
|
||||||
if(rebuild) {
|
if(rebuild) {
|
||||||
this.buildSystem()
|
this.buildSystem()
|
||||||
@@ -310,19 +311,21 @@ export default class Store {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function combinePlugins(plugins, toolbox) {
|
function combinePlugins(plugins, toolbox, pluginOptions) {
|
||||||
if(isObject(plugins) && !isArray(plugins)) {
|
if(isObject(plugins) && !isArray(plugins)) {
|
||||||
return assignDeep({}, plugins)
|
return assignDeep({}, plugins)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isFunc(plugins)) {
|
if(isFunc(plugins)) {
|
||||||
return combinePlugins(plugins(toolbox), toolbox)
|
return combinePlugins(plugins(toolbox), toolbox, pluginOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isArray(plugins)) {
|
if(isArray(plugins)) {
|
||||||
|
const dest = pluginOptions.pluginLoadType === "chain" ? toolbox.getComponents() : {}
|
||||||
|
|
||||||
return plugins
|
return plugins
|
||||||
.map(plugin => combinePlugins(plugin, toolbox))
|
.map(plugin => combinePlugins(plugin, toolbox, pluginOptions))
|
||||||
.reduce(systemExtend, {})
|
.reduce(systemExtend, dest)
|
||||||
}
|
}
|
||||||
|
|
||||||
return {}
|
return {}
|
||||||
|
|||||||
@@ -191,6 +191,72 @@ describe("wrapComponents", () => {
|
|||||||
expect(children.eq(1).text()).toEqual("WOW much data")
|
expect(children.eq(1).text()).toEqual("WOW much data")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("should wrap correctly when registering multiple plugins targeting the same component", function () {
|
||||||
|
|
||||||
|
// Given
|
||||||
|
|
||||||
|
const mySystem = new System({
|
||||||
|
pluginsOptions: {
|
||||||
|
pluginLoadType: "chain"
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
() => {
|
||||||
|
return {
|
||||||
|
components: {
|
||||||
|
wow: () => <div>Original component</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
mySystem.register([
|
||||||
|
() => {
|
||||||
|
return {
|
||||||
|
wrapComponents: {
|
||||||
|
wow: (OriginalComponent, system) => (props) => {
|
||||||
|
return <container1>
|
||||||
|
<OriginalComponent {...props}></OriginalComponent>
|
||||||
|
<div>Injected after</div>
|
||||||
|
</container1>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
return {
|
||||||
|
wrapComponents: {
|
||||||
|
wow: (OriginalComponent, system) => (props) => {
|
||||||
|
return <container2>
|
||||||
|
<div>Injected before</div>
|
||||||
|
<OriginalComponent {...props}></OriginalComponent>
|
||||||
|
</container2>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
// Then
|
||||||
|
let Component = mySystem.getSystem().getComponents("wow")
|
||||||
|
const wrapper = render(<Component name="Normal" />)
|
||||||
|
|
||||||
|
const container2 = wrapper.children().first()
|
||||||
|
expect(container2[0].name).toEqual("container2")
|
||||||
|
|
||||||
|
const children2 = container2.children()
|
||||||
|
expect(children2.length).toEqual(2)
|
||||||
|
expect(children2[0].name).toEqual("div")
|
||||||
|
expect(children2.eq(0).text()).toEqual("Injected before")
|
||||||
|
expect(children2[1].name).toEqual("container1")
|
||||||
|
|
||||||
|
const children1 = children2.children()
|
||||||
|
expect(children1.length).toEqual(2)
|
||||||
|
expect(children1.eq(0).text()).toEqual("Original component")
|
||||||
|
expect(children1[0].name).toEqual("div")
|
||||||
|
expect(children1.eq(1).text()).toEqual("Injected after")
|
||||||
|
})
|
||||||
|
|
||||||
it("should wrap correctly when building a system twice", function () {
|
it("should wrap correctly when building a system twice", function () {
|
||||||
|
|
||||||
// Given
|
// Given
|
||||||
|
|||||||
Reference in New Issue
Block a user