frontend-plugin-api: support predicate overrides
Allow plugin and extension overrides to replace or remove existing if predicates. This makes conditional plugin and extension behavior overrideable through both plugin overrides and module-installed extension overrides. Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com> Made-with: Cursor
This commit is contained in:
@@ -567,6 +567,42 @@ describe('resolveAppNodeSpecs', () => {
|
||||
expect(specs[1].if).toEqual(pluginIf);
|
||||
});
|
||||
|
||||
it('should allow plugin overrides to replace or remove plugin if predicates', () => {
|
||||
const dataRef = createExtensionDataRef<string>().with({ id: 'test.data' });
|
||||
const pluginIf = { featureFlags: { $contains: 'plugin-flag' } };
|
||||
const overrideIf = { permissions: { $contains: 'override.permission' } };
|
||||
const plugin = createFrontendPlugin({
|
||||
pluginId: 'test-plugin',
|
||||
if: pluginIf,
|
||||
extensions: [
|
||||
createExtension({
|
||||
name: 'one',
|
||||
attachTo: { id: 'app', input: 'root' },
|
||||
output: [dataRef],
|
||||
factory: () => [dataRef('one')],
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
const overriddenSpecs = resolveAppNodeSpecs({
|
||||
features: [plugin.withOverrides({ if: overrideIf })],
|
||||
builtinExtensions: [],
|
||||
parameters: [],
|
||||
collector,
|
||||
});
|
||||
const clearedSpecs = resolveAppNodeSpecs({
|
||||
features: [plugin.withOverrides({ if: undefined })],
|
||||
builtinExtensions: [],
|
||||
parameters: [],
|
||||
collector,
|
||||
});
|
||||
|
||||
expect(overriddenSpecs).toHaveLength(1);
|
||||
expect(overriddenSpecs[0].if).toEqual(overrideIf);
|
||||
expect(clearedSpecs).toHaveLength(1);
|
||||
expect(clearedSpecs[0].if).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should merge plugin and module if predicates with extension predicates', () => {
|
||||
const dataRef = createExtensionDataRef<string>().with({ id: 'test.data' });
|
||||
const pluginIf = { featureFlags: { $contains: 'plugin-flag' } };
|
||||
@@ -616,4 +652,60 @@ describe('resolveAppNodeSpecs', () => {
|
||||
expect(specs[1].id).toBe('test-plugin/module-extension');
|
||||
expect(specs[1].if).toEqual({ $all: [moduleIf, moduleExtensionIf] });
|
||||
});
|
||||
|
||||
it('should allow module extension overrides to replace or remove extension if predicates', () => {
|
||||
const dataRef = createExtensionDataRef<string>().with({ id: 'test.data' });
|
||||
const extensionIf = { featureFlags: { $contains: 'extension-flag' } };
|
||||
const overrideIf = { permissions: { $contains: 'override.permission' } };
|
||||
const plugin = createFrontendPlugin({
|
||||
pluginId: 'test-plugin',
|
||||
extensions: [
|
||||
createExtension({
|
||||
name: 'extension',
|
||||
attachTo: { id: 'app', input: 'root' },
|
||||
if: extensionIf,
|
||||
output: [dataRef],
|
||||
factory: () => [dataRef('base')],
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
const overriddenSpecs = resolveAppNodeSpecs({
|
||||
features: [
|
||||
plugin,
|
||||
createFrontendModule({
|
||||
pluginId: 'test-plugin',
|
||||
extensions: [
|
||||
plugin.getExtension('test-plugin/extension').override({
|
||||
if: overrideIf,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
builtinExtensions: [],
|
||||
parameters: [],
|
||||
collector,
|
||||
});
|
||||
const clearedSpecs = resolveAppNodeSpecs({
|
||||
features: [
|
||||
plugin,
|
||||
createFrontendModule({
|
||||
pluginId: 'test-plugin',
|
||||
extensions: [
|
||||
plugin.getExtension('test-plugin/extension').override({
|
||||
if: undefined,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
builtinExtensions: [],
|
||||
parameters: [],
|
||||
collector,
|
||||
});
|
||||
|
||||
expect(overriddenSpecs).toHaveLength(1);
|
||||
expect(overriddenSpecs[0].if).toEqual(overrideIf);
|
||||
expect(clearedSpecs).toHaveLength(1);
|
||||
expect(clearedSpecs[0].if).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -549,13 +549,18 @@ export function createExtension<
|
||||
);
|
||||
}
|
||||
|
||||
let ifPredicate = options.if;
|
||||
if ('if' in overrideOptions) {
|
||||
ifPredicate = overrideOptions.if;
|
||||
}
|
||||
|
||||
return createExtension({
|
||||
kind: options.kind,
|
||||
name: options.name,
|
||||
attachTo: (overrideOptions.attachTo ??
|
||||
options.attachTo) as ExtensionDefinitionAttachTo,
|
||||
disabled: overrideOptions.disabled ?? options.disabled,
|
||||
if: overrideOptions.if ?? options.if,
|
||||
if: ifPredicate,
|
||||
inputs: bindInputs(
|
||||
{
|
||||
...(options.inputs ?? {}),
|
||||
|
||||
@@ -116,6 +116,11 @@ export interface OverridableFrontendPlugin<
|
||||
withOverrides(options: {
|
||||
extensions?: Array<ExtensionDefinition>;
|
||||
|
||||
/**
|
||||
* Overrides the shared condition that applies to all extensions in the plugin.
|
||||
*/
|
||||
if?: FilterPredicate;
|
||||
|
||||
/**
|
||||
* Overrides the display title of the plugin.
|
||||
*/
|
||||
@@ -329,6 +334,10 @@ export function createFrontendPlugin<
|
||||
return `Plugin{id=${pluginId}}`;
|
||||
},
|
||||
withOverrides(overrides) {
|
||||
let ifPredicate = options.if;
|
||||
if ('if' in overrides) {
|
||||
ifPredicate = overrides.if;
|
||||
}
|
||||
const overrideExtensions = overrides.extensions ?? [];
|
||||
const overriddenExtensionIds = new Set(
|
||||
overrideExtensions.map(
|
||||
@@ -344,6 +353,7 @@ export function createFrontendPlugin<
|
||||
return createFrontendPlugin({
|
||||
...options,
|
||||
pluginId,
|
||||
if: ifPredicate,
|
||||
title: overrides.title ?? options.title,
|
||||
icon: overrides.icon ?? options.icon,
|
||||
extensions: [...nonOverriddenExtensions, ...overrideExtensions],
|
||||
|
||||
Reference in New Issue
Block a user