Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/plugins/PluginSlot.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ function BasePluginSlot({
as = React.Fragment,
children = null,
id,
idAliases = [],
pluginProps = {},
slotOptions = {},
slotErrorFallbackComponent,
Expand All @@ -23,7 +24,7 @@ function BasePluginSlot({
for an example of how PluginSlot is populated, and example/src/index.jsx for a dummy JS config that holds all plugins
*/

const { keepDefault, plugins } = usePluginSlot(id);
const { keepDefault, plugins } = usePluginSlot(id, idAliases);
const { formatMessage } = useIntl();

const defaultContents = React.useMemo(() => {
Expand Down Expand Up @@ -118,6 +119,8 @@ BasePluginSlot.propTypes = {
children: PropTypes.node,
/** ID of the PluginSlot configuration */
id: PropTypes.string.isRequired,
/** Aliases (additional IDs for the PluginSlot) */
idAliases: PropTypes.arrayOf(PropTypes.string),
/** Props that are passed down to each Plugin in the Slot */
pluginProps: PropTypes.shape(),
/** Options passed to the PluginSlot */
Expand Down
36 changes: 31 additions & 5 deletions src/plugins/data/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,38 @@ import { PLUGIN_MOUNTED, PLUGIN_READY, PLUGIN_UNMOUNTED } from './constants';
* @param {String} id - Name of PluginSlot
* @returns {Object} - JS configuration for the PluginSlot
*/
export function usePluginSlot(id) {
const configSlots = getConfigSlots()?.[id];
if (configSlots) {
return configSlots;
export function usePluginSlot(id, idAliases = []) {
const notFound = { keepDefault: true, plugins: [] };

const allConfigSlots = getConfigSlots();

if (!allConfigSlots) {
return notFound;
}

// When defining a JS object with multiple entries
// that have the same key, only the last one is kept
//
// We want to treat all entries in the pluginSlots object
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: what is "the pluginSlots object" referring to specifically? allConfigSlots?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the line break made this less clear than it should be, it's "the pluginSlots object in env.config.jsx"

// in env.config.jsx that have either "id" or any of the
// "idAliases" as if they have the same id
//
// To do so, we grab the last entry in the object that with
// a key that matches either the "id" or any of the "idAliases"
const allSlotIds = [id].concat(idAliases);
const lastMatchingId = Object.keys(allConfigSlots).findLast(slotId => allSlotIds.includes(slotId));

if (!lastMatchingId) {
return notFound;
}
return { keepDefault: true, plugins: [] };

const configSlot = allConfigSlots[lastMatchingId];

if (!configSlot) {
return notFound;
}

return configSlot;
}

/* Listening for events */
Expand Down
54 changes: 54 additions & 0 deletions src/plugins/data/hooks.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,58 @@ describe('usePluginSlots', () => {
expect(slotConfig.plugins).toStrictEqual([]);
});
});

describe('when the plugin slot is defined via alias', () => {
it('returns keepDefault and plugin changes', () => {
getConfig.mockImplementation(() => (
{
pluginSlots: {
example_plugin_slot_alias: {
plugins: mockSlotChanges,
keepDefault: true,
},
},
}
));

const slotConfig = usePluginSlot('example_plugin_slot', ['example_plugin_slot_alias']);
expect(slotConfig.keepDefault).toBe(true);
expect(slotConfig.plugins).toBe(mockSlotChanges);
});
});

describe('when no matching plugin slot is found', () => {
it('returns true for keepDefault and no plugin changes', () => {
getConfig.mockImplementation(() => (
{
pluginSlots: {
wrong_plugin_slot_alias: {
plugins: mockSlotChanges,
keepDefault: true,
},
},
}
));

const slotConfig = usePluginSlot('example_plugin_slot', ['example_plugin_slot_alias']);
expect(slotConfig.keepDefault).toBe(true);
expect(slotConfig.plugins).toStrictEqual([]);
});
});

describe('when the defined plugin is null', () => {
it('returns true for keepDefault and no plugin changes', () => {
getConfig.mockImplementation(() => (
{
pluginSlots: {
example_plugin_slot_alias: null,
},
}
));

const slotConfig = usePluginSlot('example_plugin_slot', ['example_plugin_slot_alias']);
expect(slotConfig.keepDefault).toBe(true);
expect(slotConfig.plugins).toStrictEqual([]);
});
});
});