diff --git a/packages/app/src/components/DynamicRoot/DynamicRoot.test.tsx b/packages/app/src/components/DynamicRoot/DynamicRoot.test.tsx
index 62ad243bb0..12650eee20 100644
--- a/packages/app/src/components/DynamicRoot/DynamicRoot.test.tsx
+++ b/packages/app/src/components/DynamicRoot/DynamicRoot.test.tsx
@@ -16,7 +16,6 @@ import {
import { Entity } from '@backstage/catalog-model';
import * as appDefaults from '@backstage/app-defaults';
import { AppRouteBinder, defaultConfigLoader } from '@backstage/core-app-api';
-import { AppConfig } from '@backstage/config';
const DynamicRoot = React.lazy(() => import('./DynamicRoot'));
@@ -68,9 +67,11 @@ const MockPage = () => {
);
};
-const loadAppConfig = async () => await defaultConfigLoader();
-
-const MockApp = ({ appConfig }: { appConfig: AppConfig[] }) => (
+const MockApp = ({
+ dynamicPlugins,
+}: {
+ dynamicPlugins: any; // allow tests to supply specific values for specific use cases
+}) => (
(
},
})
}
- appConfig={appConfig}
- baseFrontendConfig={{
- context: '',
- data: {},
- }}
+ dynamicPlugins={dynamicPlugins}
scalprumConfig={{}}
/>
@@ -124,25 +121,26 @@ jest.mock('../../utils/dynamicUI/initializeRemotePlugins', () => ({
__esModule: true,
}));
-const mockProcessEnv = (dynamicPluginsConfig: { [key: string]: any }) => ({
- NODE_ENV: 'test',
- APP_CONFIG: [
- {
- data: {
- app: { title: 'Test' },
- backend: { baseUrl: 'http://localhost:7007' },
- techdocs: {
- storageUrl: 'http://localhost:7007/api/techdocs/static/docs',
- },
- auth: { environment: 'development' },
- dynamicPlugins: {
- frontend: dynamicPluginsConfig,
+const loadTestConfig = async (dynamicPlugins: any) => {
+ process.env = {
+ NODE_ENV: 'test',
+ APP_CONFIG: [
+ {
+ data: {
+ app: { title: 'Test' },
+ backend: { baseUrl: 'http://localhost:7007' },
+ techdocs: {
+ storageUrl: 'http://localhost:7007/api/techdocs/static/docs',
+ },
+ auth: { environment: 'development' },
+ dynamicPlugins,
},
+ context: 'test',
},
- context: 'test',
- },
- ] as any,
-});
+ ] as any,
+ };
+ await defaultConfigLoader();
+};
const consoleSpy = jest.spyOn(console, 'warn');
@@ -190,11 +188,15 @@ describe('DynamicRoot', () => {
});
it('should render with one dynamicRoute', async () => {
- process.env = mockProcessEnv({
- 'foo.bar': { dynamicRoutes: [{ path: '/foo' }] },
- });
- const appConfig = await loadAppConfig();
- const rendered = await renderWithEffects();
+ const dynamicPlugins = {
+ frontend: {
+ 'foo.bar': { dynamicRoutes: [{ path: '/foo' }] },
+ },
+ };
+ await loadTestConfig(dynamicPlugins);
+ const rendered = await renderWithEffects(
+ ,
+ );
await waitFor(async () => {
expect(rendered.baseElement).toBeInTheDocument();
expect(rendered.getByTestId('isLoadingFinished')).toBeInTheDocument();
@@ -205,11 +207,17 @@ describe('DynamicRoot', () => {
});
it('should render with two dynamicRoutes', async () => {
- process.env = mockProcessEnv({
- 'foo.bar': { dynamicRoutes: [{ path: '/foo' }, { path: '/bar' }] },
- });
- const appConfig = await loadAppConfig();
- const rendered = await renderWithEffects();
+ const dynamicPlugins = {
+ frontend: {
+ 'foo.bar': {
+ dynamicRoutes: [{ path: '/foo' }, { path: '/bar' }],
+ },
+ },
+ };
+ await loadTestConfig(dynamicPlugins);
+ const rendered = await renderWithEffects(
+ ,
+ );
await waitFor(async () => {
expect(rendered.baseElement).toBeInTheDocument();
expect(rendered.getByTestId('isLoadingFinished')).toBeInTheDocument();
@@ -220,11 +228,17 @@ describe('DynamicRoot', () => {
});
it('should render with one dynamicRoute from nonexistent plugin', async () => {
- process.env = mockProcessEnv({
- 'doesnt.exist': { dynamicRoutes: [{ path: '/foo' }] },
- });
- const appConfig = await loadAppConfig();
- const rendered = await renderWithEffects();
+ const dynamicPlugins = {
+ frontend: {
+ 'doesnt.exist': {
+ dynamicRoutes: [{ path: '/foo' }],
+ },
+ },
+ };
+ await loadTestConfig(dynamicPlugins);
+ const rendered = await renderWithEffects(
+ ,
+ );
await waitFor(async () => {
expect(rendered.baseElement).toBeInTheDocument();
expect(rendered.getByTestId('isLoadingFinished')).toBeInTheDocument();
@@ -238,13 +252,17 @@ describe('DynamicRoot', () => {
});
it('should render with one dynamicRoute with nonexistent importName', async () => {
- process.env = mockProcessEnv({
- 'foo.bar': {
- dynamicRoutes: [{ path: '/foo', importName: 'BarComponent' }],
+ const dynamicPlugins = {
+ frontend: {
+ 'foo.bar': {
+ dynamicRoutes: [{ path: '/foo', importName: 'BarComponent' }],
+ },
},
- });
- const appConfig = await loadAppConfig();
- const rendered = await renderWithEffects();
+ };
+ await loadTestConfig(dynamicPlugins);
+ const rendered = await renderWithEffects(
+ ,
+ );
await waitFor(async () => {
expect(rendered.baseElement).toBeInTheDocument();
expect(rendered.getByTestId('isLoadingFinished')).toBeInTheDocument();
@@ -258,11 +276,17 @@ describe('DynamicRoot', () => {
});
it('should render with one dynamicRoute with nonexistent module', async () => {
- process.env = mockProcessEnv({
- 'foo.bar': { dynamicRoutes: [{ path: '/foo', module: 'BarPlugin' }] },
- });
- const appConfig = await loadAppConfig();
- const rendered = await renderWithEffects();
+ const dynamicPlugins = {
+ frontend: {
+ 'foo.bar': {
+ dynamicRoutes: [{ path: '/foo', module: 'BarPlugin' }],
+ },
+ },
+ };
+ await loadTestConfig(dynamicPlugins);
+ const rendered = await renderWithEffects(
+ ,
+ );
await waitFor(async () => {
expect(rendered.baseElement).toBeInTheDocument();
expect(rendered.getByTestId('isLoadingFinished')).toBeInTheDocument();
@@ -276,15 +300,22 @@ describe('DynamicRoot', () => {
});
it('should render with one dynamicRoute with staticJSXContent', async () => {
- process.env = mockProcessEnv({
- 'foo.bar': {
- dynamicRoutes: [
- { path: '/foo', importName: 'FooComponentWithStaticJSX' },
- ],
+ const dynamicPlugins = {
+ frontend: {
+ 'foo.bar': {
+ dynamicRoutes: [
+ {
+ path: '/foo',
+ importName: 'FooComponentWithStaticJSX',
+ },
+ ],
+ },
},
- });
- const appConfig = await loadAppConfig();
- const rendered = await renderWithEffects();
+ };
+ await loadTestConfig(dynamicPlugins);
+ const rendered = await renderWithEffects(
+ ,
+ );
await waitFor(async () => {
expect(rendered.baseElement).toBeInTheDocument();
expect(rendered.getByTestId('isLoadingFinished')).toBeInTheDocument();
@@ -297,11 +328,21 @@ describe('DynamicRoot', () => {
});
it('should render with one mountPoint with single component', async () => {
- process.env = mockProcessEnv({
- 'foo.bar': { mountPoints: [{ mountPoint: 'a.b.c/cards' }] },
- });
- const appConfig = await loadAppConfig();
- const rendered = await renderWithEffects();
+ const dynamicPlugins = {
+ frontend: {
+ 'foo.bar': {
+ mountPoints: [
+ {
+ mountPoint: 'a.b.c/cards',
+ },
+ ],
+ },
+ },
+ };
+ await loadTestConfig(dynamicPlugins);
+ const rendered = await renderWithEffects(
+ ,
+ );
await waitFor(async () => {
expect(rendered.baseElement).toBeInTheDocument();
expect(rendered.getByTestId('isLoadingFinished')).toBeInTheDocument();
@@ -312,16 +353,24 @@ describe('DynamicRoot', () => {
});
it('should render with one mountPoint with two components', async () => {
- process.env = mockProcessEnv({
- 'foo.bar': {
- mountPoints: [
- { mountPoint: 'a.b.c/cards' },
- { mountPoint: 'a.b.c/cards' },
- ],
+ const dynamicPlugins = {
+ frontend: {
+ 'foo.bar': {
+ mountPoints: [
+ {
+ mountPoint: 'a.b.c/cards',
+ },
+ {
+ mountPoint: 'a.b.c/cards',
+ },
+ ],
+ },
},
- });
- const appConfig = await loadAppConfig();
- const rendered = await renderWithEffects();
+ };
+ await loadTestConfig(dynamicPlugins);
+ const rendered = await renderWithEffects(
+ ,
+ );
await waitFor(async () => {
expect(rendered.baseElement).toBeInTheDocument();
expect(rendered.getByTestId('isLoadingFinished')).toBeInTheDocument();
@@ -332,16 +381,25 @@ describe('DynamicRoot', () => {
});
it("should render with one mountPoint with two components where one importName doesn't exist", async () => {
- process.env = mockProcessEnv({
- 'foo.bar': {
- mountPoints: [
- { mountPoint: 'a.b.c/cards' },
- { mountPoint: 'a.b.c/cards', importName: 'BarComponent' },
- ],
+ const dynamicPlugins = {
+ frontend: {
+ 'foo.bar': {
+ mountPoints: [
+ {
+ mountPoint: 'a.b.c/cards',
+ },
+ {
+ mountPoint: 'a.b.c/cards',
+ importName: 'BarComponent',
+ },
+ ],
+ },
},
- });
- const appConfig = await loadAppConfig();
- const rendered = await renderWithEffects();
+ };
+ await loadTestConfig(dynamicPlugins);
+ const rendered = await renderWithEffects(
+ ,
+ );
await waitFor(async () => {
expect(rendered.baseElement).toBeInTheDocument();
expect(rendered.getByTestId('isLoadingFinished')).toBeInTheDocument();
@@ -355,18 +413,22 @@ describe('DynamicRoot', () => {
});
it('should render with one mountPoint with config.if === true', async () => {
- process.env = mockProcessEnv({
- 'foo.bar': {
- mountPoints: [
- {
- mountPoint: 'a.b.c/cards',
- config: { if: { allOf: ['isFooConditionTrue'] } },
- },
- ],
+ const dynamicPlugins = {
+ frontend: {
+ 'foo.bar': {
+ mountPoints: [
+ {
+ mountPoint: 'a.b.c/cards',
+ config: { if: { allOf: ['isFooConditionTrue'] } },
+ },
+ ],
+ },
},
- });
- const appConfig = await loadAppConfig();
- const rendered = await renderWithEffects();
+ };
+ await loadTestConfig(dynamicPlugins);
+ const rendered = await renderWithEffects(
+ ,
+ );
await waitFor(async () => {
expect(rendered.baseElement).toBeInTheDocument();
expect(rendered.getByTestId('isLoadingFinished')).toBeInTheDocument();
@@ -379,18 +441,22 @@ describe('DynamicRoot', () => {
});
it('should render with one mountPoint with config.if === false', async () => {
- process.env = mockProcessEnv({
- 'foo.bar': {
- mountPoints: [
- {
- mountPoint: 'a.b.c/cards',
- config: { if: { allOf: ['isFooConditionFalse'] } },
- },
- ],
+ const dynamicPlugins = {
+ frontend: {
+ 'foo.bar': {
+ mountPoints: [
+ {
+ mountPoint: 'a.b.c/cards',
+ config: { if: { allOf: ['isFooConditionFalse'] } },
+ },
+ ],
+ },
},
- });
- const appConfig = await loadAppConfig();
- const rendered = await renderWithEffects();
+ };
+ await loadTestConfig(dynamicPlugins);
+ const rendered = await renderWithEffects(
+ ,
+ );
await waitFor(async () => {
expect(rendered.baseElement).toBeInTheDocument();
expect(rendered.getByTestId('isLoadingFinished')).toBeInTheDocument();
@@ -403,18 +469,22 @@ describe('DynamicRoot', () => {
});
it("should render with one mountPoint with config.if where importName doesn't exist", async () => {
- process.env = mockProcessEnv({
- 'foo.bar': {
- mountPoints: [
- {
- mountPoint: 'a.b.c/cards',
- config: { if: { allOf: ['isBarConditionTrue'] } },
- },
- ],
+ const dynamicPlugins = {
+ frontend: {
+ 'foo.bar': {
+ mountPoints: [
+ {
+ mountPoint: 'a.b.c/cards',
+ config: { if: { allOf: ['isBarConditionTrue'] } },
+ },
+ ],
+ },
},
- });
- const appConfig = await loadAppConfig();
- const rendered = await renderWithEffects();
+ };
+ await loadTestConfig(dynamicPlugins);
+ const rendered = await renderWithEffects(
+ ,
+ );
await waitFor(async () => {
expect(rendered.baseElement).toBeInTheDocument();
expect(rendered.getByTestId('isLoadingFinished')).toBeInTheDocument();
@@ -427,16 +497,20 @@ describe('DynamicRoot', () => {
});
it('should render with two mountPoints with one component each', async () => {
- process.env = mockProcessEnv({
- 'foo.bar': {
- mountPoints: [
- { mountPoint: 'a.b.c/cards' },
- { mountPoint: 'x.y.z/cards' },
- ],
+ const dynamicPlugins = {
+ frontend: {
+ 'foo.bar': {
+ mountPoints: [
+ { mountPoint: 'a.b.c/cards' },
+ { mountPoint: 'x.y.z/cards' },
+ ],
+ },
},
- });
- const appConfig = await loadAppConfig();
- const rendered = await renderWithEffects();
+ };
+ await loadTestConfig(dynamicPlugins);
+ const rendered = await renderWithEffects(
+ ,
+ );
await waitFor(async () => {
expect(rendered.baseElement).toBeInTheDocument();
expect(rendered.getByTestId('isLoadingFinished')).toBeInTheDocument();
@@ -449,11 +523,15 @@ describe('DynamicRoot', () => {
});
it('should render with one mountPoint from nonexistent plugin', async () => {
- process.env = mockProcessEnv({
- 'doesnt.exist': { mountPoints: [{ mountPoint: 'a.b.c/cards' }] },
- });
- const appConfig = await loadAppConfig();
- const rendered = await renderWithEffects();
+ const dynamicPlugins = {
+ frontend: {
+ 'doesnt.exist': { mountPoints: [{ mountPoint: 'a.b.c/cards' }] },
+ },
+ };
+ await loadTestConfig(dynamicPlugins);
+ const rendered = await renderWithEffects(
+ ,
+ );
await waitFor(async () => {
expect(rendered.baseElement).toBeInTheDocument();
expect(rendered.getByTestId('isLoadingFinished')).toBeInTheDocument();
@@ -467,15 +545,19 @@ describe('DynamicRoot', () => {
});
it('should render with one mountPoint with nonexistent importName', async () => {
- process.env = mockProcessEnv({
- 'doesnt.exist': {
- mountPoints: [
- { mountPoint: 'a.b.c/cards', importName: 'BarComponent' },
- ],
+ const dynamicPlugins = {
+ frontend: {
+ 'doesnt.exist': {
+ mountPoints: [
+ { mountPoint: 'a.b.c/cards', importName: 'BarComponent' },
+ ],
+ },
},
- });
- const appConfig = await loadAppConfig();
- const rendered = await renderWithEffects();
+ };
+ await loadTestConfig(dynamicPlugins);
+ const rendered = await renderWithEffects(
+ ,
+ );
await waitFor(async () => {
expect(rendered.baseElement).toBeInTheDocument();
expect(rendered.getByTestId('isLoadingFinished')).toBeInTheDocument();
@@ -489,13 +571,17 @@ describe('DynamicRoot', () => {
});
it('should render with one mountPoint with nonexistent module', async () => {
- process.env = mockProcessEnv({
- 'doesnt.exist': {
- mountPoints: [{ mountPoint: 'a.b.c/cards', module: 'BarPlugin' }],
+ const dynamicPlugins = {
+ frontend: {
+ 'doesnt.exist': {
+ mountPoints: [{ mountPoint: 'a.b.c/cards', module: 'BarPlugin' }],
+ },
},
- });
- const appConfig = await loadAppConfig();
- const rendered = await renderWithEffects();
+ };
+ await loadTestConfig(dynamicPlugins);
+ const rendered = await renderWithEffects(
+ ,
+ );
await waitFor(async () => {
expect(rendered.baseElement).toBeInTheDocument();
expect(rendered.getByTestId('isLoadingFinished')).toBeInTheDocument();
@@ -509,18 +595,22 @@ describe('DynamicRoot', () => {
});
it('should render with one mountPoint with staticJSXContent', async () => {
- process.env = mockProcessEnv({
- 'foo.bar': {
- mountPoints: [
- {
- mountPoint: 'a.b.c/cards',
- importName: 'FooComponentWithStaticJSX',
- },
- ],
+ const dynamicPlugins = {
+ frontend: {
+ 'foo.bar': {
+ mountPoints: [
+ {
+ mountPoint: 'a.b.c/cards',
+ importName: 'FooComponentWithStaticJSX',
+ },
+ ],
+ },
},
- });
- const appConfig = await loadAppConfig();
- const rendered = await renderWithEffects();
+ };
+ await loadTestConfig(dynamicPlugins);
+ const rendered = await renderWithEffects(
+ ,
+ );
await waitFor(async () => {
expect(rendered.baseElement).toBeInTheDocument();
expect(rendered.getByTestId('isLoadingFinished')).toBeInTheDocument();
@@ -533,11 +623,15 @@ describe('DynamicRoot', () => {
});
it('should render with one appIcon', async () => {
- process.env = mockProcessEnv({
- 'foo.bar': { appIcons: [{ name: 'fooIcon' }] },
- });
- const appConfig = await loadAppConfig();
- const rendered = await renderWithEffects();
+ const dynamicPlugins = {
+ frontend: {
+ 'foo.bar': { appIcons: [{ name: 'fooIcon' }] },
+ },
+ };
+ await loadTestConfig(dynamicPlugins);
+ const rendered = await renderWithEffects(
+ ,
+ );
await waitFor(async () => {
expect(rendered.baseElement).toBeInTheDocument();
expect(rendered.getByTestId('isLoadingFinished')).toBeInTheDocument();
@@ -548,11 +642,15 @@ describe('DynamicRoot', () => {
});
it('should render with two appIcons', async () => {
- process.env = mockProcessEnv({
- 'foo.bar': { appIcons: [{ name: 'fooIcon' }, { name: 'foo2Icon' }] },
- });
- const appConfig = await loadAppConfig();
- const rendered = await renderWithEffects();
+ const dynamicPlugins = {
+ frontend: {
+ 'foo.bar': { appIcons: [{ name: 'fooIcon' }, { name: 'foo2Icon' }] },
+ },
+ };
+ await loadTestConfig(dynamicPlugins);
+ const rendered = await renderWithEffects(
+ ,
+ );
await waitFor(async () => {
expect(rendered.baseElement).toBeInTheDocument();
expect(rendered.getByTestId('isLoadingFinished')).toBeInTheDocument();
@@ -566,11 +664,15 @@ describe('DynamicRoot', () => {
});
it('should render with one appIcon from nonexistent plugin', async () => {
- process.env = mockProcessEnv({
- 'doesnt.exist': { appIcons: [{ name: 'fooIcon' }] },
- });
- const appConfig = await loadAppConfig();
- const rendered = await renderWithEffects();
+ const dynamicPlugins = {
+ frontend: {
+ 'doesnt.exist': { appIcons: [{ name: 'fooIcon' }] },
+ },
+ };
+ await loadTestConfig(dynamicPlugins);
+ const rendered = await renderWithEffects(
+ ,
+ );
await waitFor(async () => {
expect(rendered.baseElement).toBeInTheDocument();
expect(rendered.getByTestId('isLoadingFinished')).toBeInTheDocument();
@@ -585,24 +687,28 @@ describe('DynamicRoot', () => {
it('should bind routes on routeBindings target', async () => {
const createAppSpy = jest.spyOn(appDefaults, 'createApp');
- process.env = mockProcessEnv({
- 'foo.bar': {
- routeBindings: {
- targets: [
- { importName: 'fooPluginTarget' },
- { importName: 'fooPlugin' },
- ],
- bindings: [
- {
- bindTarget: 'fooPluginTarget.externalRoutes',
- bindMap: { barTarget: 'fooPlugin.routes.bar' },
- },
- ],
+ const dynamicPlugins = {
+ frontend: {
+ 'foo.bar': {
+ routeBindings: {
+ targets: [
+ { importName: 'fooPluginTarget' },
+ { importName: 'fooPlugin' },
+ ],
+ bindings: [
+ {
+ bindTarget: 'fooPluginTarget.externalRoutes',
+ bindMap: { barTarget: 'fooPlugin.routes.bar' },
+ },
+ ],
+ },
},
},
- });
- const appConfig = await loadAppConfig();
- const rendered = await renderWithEffects();
+ };
+ await loadTestConfig(dynamicPlugins);
+ const rendered = await renderWithEffects(
+ ,
+ );
await waitFor(async () => {
expect(rendered.baseElement).toBeInTheDocument();
expect(rendered.getByTestId('isLoadingFinished')).toBeInTheDocument();
@@ -623,27 +729,31 @@ describe('DynamicRoot', () => {
it('should bind routes on routeBindings target with a custom name', async () => {
const createAppSpy = jest.spyOn(appDefaults, 'createApp');
- process.env = mockProcessEnv({
- 'foo.bar': {
- routeBindings: {
- targets: [
- {
- importName: 'fooPluginTarget',
- name: 'fooPluginTargetWithCustomName',
- },
- { importName: 'fooPlugin' },
- ],
- bindings: [
- {
- bindTarget: 'fooPluginTargetWithCustomName.externalRoutes',
- bindMap: { barTarget: 'fooPlugin.routes.bar' },
- },
- ],
+ const dynamicPlugins = {
+ frontend: {
+ 'foo.bar': {
+ routeBindings: {
+ targets: [
+ {
+ importName: 'fooPluginTarget',
+ name: 'fooPluginTargetWithCustomName',
+ },
+ { importName: 'fooPlugin' },
+ ],
+ bindings: [
+ {
+ bindTarget: 'fooPluginTargetWithCustomName.externalRoutes',
+ bindMap: { barTarget: 'fooPlugin.routes.bar' },
+ },
+ ],
+ },
},
},
- });
- const appConfig = await loadAppConfig();
- const rendered = await renderWithEffects();
+ };
+ await loadTestConfig(dynamicPlugins);
+ const rendered = await renderWithEffects(
+ ,
+ );
await waitFor(async () => {
expect(rendered.baseElement).toBeInTheDocument();
expect(rendered.getByTestId('isLoadingFinished')).toBeInTheDocument();
@@ -663,26 +773,30 @@ describe('DynamicRoot', () => {
});
it('should not bind routes on routeBindings target with nonexistent importName', async () => {
- process.env = mockProcessEnv({
- 'foo.bar': {
- routeBindings: {
- targets: [
- {
- importName: 'barPlugin',
- },
- { importName: 'fooPlugin' },
- ],
- bindings: [
- {
- bindTarget: 'barPlugin.externalRoutes',
- bindMap: { barTarget: 'fooPlugin.routes.bar' },
- },
- ],
+ const dynamicPlugins = {
+ frontend: {
+ 'foo.bar': {
+ routeBindings: {
+ targets: [
+ {
+ importName: 'barPlugin',
+ },
+ { importName: 'fooPlugin' },
+ ],
+ bindings: [
+ {
+ bindTarget: 'barPlugin.externalRoutes',
+ bindMap: { barTarget: 'fooPlugin.routes.bar' },
+ },
+ ],
+ },
},
},
- });
- const appConfig = await loadAppConfig();
- const rendered = await renderWithEffects();
+ };
+ await loadTestConfig(dynamicPlugins);
+ const rendered = await renderWithEffects(
+ ,
+ );
await waitFor(async () => {
expect(rendered.baseElement).toBeInTheDocument();
expect(rendered.getByTestId('isLoadingFinished')).toBeInTheDocument();
@@ -694,13 +808,17 @@ describe('DynamicRoot', () => {
it('should add custom ApiFactory', async () => {
const createAppSpy = jest.spyOn(appDefaults, 'createApp');
- process.env = mockProcessEnv({
- 'foo.bar': {
- apiFactories: [{ importName: 'fooPluginApi' }],
+ const dynamicPlugins = {
+ frontend: {
+ 'foo.bar': {
+ apiFactories: [{ importName: 'fooPluginApi' }],
+ },
},
- });
- const appConfig = await loadAppConfig();
- const rendered = await renderWithEffects();
+ };
+ await loadTestConfig(dynamicPlugins);
+ const rendered = await renderWithEffects(
+ ,
+ );
await waitFor(async () => {
expect(rendered.baseElement).toBeInTheDocument();
expect(rendered.getByTestId('isLoadingFinished')).toBeInTheDocument();
@@ -715,13 +833,17 @@ describe('DynamicRoot', () => {
it('should not add custom ApiFactory with nonexistent importName', async () => {
const createAppSpy = jest.spyOn(appDefaults, 'createApp');
- process.env = mockProcessEnv({
- 'foo.bar': {
- apiFactories: [{ importName: 'barPluginApi' }],
+ const dynamicPlugins = {
+ frontend: {
+ 'foo.bar': {
+ apiFactories: [{ importName: 'barPluginApi' }],
+ },
},
- });
- const appConfig = await loadAppConfig();
- const rendered = await renderWithEffects();
+ };
+ await loadTestConfig(dynamicPlugins);
+ const rendered = await renderWithEffects(
+ ,
+ );
await waitFor(async () => {
expect(rendered.baseElement).toBeInTheDocument();
expect(rendered.getByTestId('isLoadingFinished')).toBeInTheDocument();
@@ -735,13 +857,17 @@ describe('DynamicRoot', () => {
it('should not add custom ApiFactory with nonexistent module', async () => {
const createAppSpy = jest.spyOn(appDefaults, 'createApp');
- process.env = mockProcessEnv({
- 'foo.bar': {
- apiFactories: [{ importName: 'fooPluginApi', module: 'BarPlugin' }],
+ const dynamicPlugins = {
+ frontend: {
+ 'foo.bar': {
+ apiFactories: [{ importName: 'fooPluginApi', module: 'BarPlugin' }],
+ },
},
- });
- const appConfig = await loadAppConfig();
- const rendered = await renderWithEffects();
+ };
+ await loadTestConfig(dynamicPlugins);
+ const rendered = await renderWithEffects(
+ ,
+ );
await waitFor(async () => {
expect(rendered.baseElement).toBeInTheDocument();
expect(rendered.getByTestId('isLoadingFinished')).toBeInTheDocument();
diff --git a/packages/app/src/components/DynamicRoot/DynamicRoot.tsx b/packages/app/src/components/DynamicRoot/DynamicRoot.tsx
index fdf07c91ae..85db9a26ac 100644
--- a/packages/app/src/components/DynamicRoot/DynamicRoot.tsx
+++ b/packages/app/src/components/DynamicRoot/DynamicRoot.tsx
@@ -15,13 +15,13 @@ import DynamicRootContext, {
ScalprumMountPointConfig,
} from './DynamicRootContext';
import extractDynamicConfig, {
+ DynamicPluginConfig,
configIfToCallable,
} from '../../utils/dynamicUI/extractDynamicConfig';
import initializeRemotePlugins from '../../utils/dynamicUI/initializeRemotePlugins';
import defaultAppComponents from './defaultAppComponents';
import bindAppRoutes from '../../utils/dynamicUI/bindAppRoutes';
import Loader from './Loader';
-import { AppConfig } from '@backstage/config';
export type StaticPlugins = Record<
string,
@@ -38,16 +38,14 @@ type EntityTabMap = Record;
export const DynamicRoot = ({
afterInit,
apis: staticApis,
- appConfig,
- baseFrontendConfig,
+ dynamicPlugins,
staticPluginStore = {},
scalprumConfig,
}: {
afterInit: () => Promise<{ default: React.ComponentType }>;
// Static APIs
apis: AnyApiFactory[];
- appConfig: AppConfig[];
- baseFrontendConfig: AppConfig;
+ dynamicPlugins: DynamicPluginConfig;
staticPluginStore?: StaticPlugins;
scalprumConfig: AppsConfig;
}) => {
@@ -71,10 +69,7 @@ export const DynamicRoot = ({
mountPoints,
routeBindings,
routeBindingTargets,
- } = await extractDynamicConfig({
- frontendAppConfig: baseFrontendConfig,
- appConfig,
- });
+ } = await extractDynamicConfig(dynamicPlugins);
const requiredModules = [
...routeBindingTargets.map(({ scope, module }) => ({
@@ -283,7 +278,6 @@ export const DynamicRoot = ({
{} as EntityTabMap,
);
if (!app.current) {
- const fullConfig = [baseFrontendConfig, ...appConfig];
app.current = createApp({
apis: [...staticApis, ...remoteApis],
bindRoutes({ bind }) {
@@ -293,7 +287,6 @@ export const DynamicRoot = ({
plugins: Object.values(staticPluginStore).map(entry => entry.plugin),
themes,
components: defaultAppComponents,
- configLoader: async () => Promise.resolve(fullConfig),
});
}
@@ -310,8 +303,7 @@ export const DynamicRoot = ({
});
}, [
afterInit,
- appConfig,
- baseFrontendConfig,
+ dynamicPlugins,
pluginStore,
scalprumConfig,
staticApis,
diff --git a/packages/app/src/components/DynamicRoot/ScalprumRoot.tsx b/packages/app/src/components/DynamicRoot/ScalprumRoot.tsx
index d4946a031c..d55ddfa085 100644
--- a/packages/app/src/components/DynamicRoot/ScalprumRoot.tsx
+++ b/packages/app/src/components/DynamicRoot/ScalprumRoot.tsx
@@ -12,6 +12,7 @@ import useAsync from 'react-use/lib/useAsync';
import Loader from './Loader';
import { AppConfig } from '@backstage/config';
import { DynamicRoot, StaticPlugins } from './DynamicRoot';
+import { DynamicPluginConfig } from '../../utils/dynamicUI/extractDynamicConfig';
const ScalprumRoot = ({
apis,
@@ -27,19 +28,23 @@ const ScalprumRoot = ({
}) => {
const { loading, value } = useAsync(
async (): Promise<{
- appConfig: AppConfig[];
+ dynamicPlugins: DynamicPluginConfig;
baseUrl: string;
scalprumConfig?: AppsConfig;
}> => {
const appConfig = overrideBaseUrlConfigs(await defaultConfigLoader());
- const reader = ConfigReader.fromConfigs(appConfig);
+ const reader = ConfigReader.fromConfigs([
+ ...appConfig,
+ baseFrontendConfig ? baseFrontendConfig : { context: '', data: {} },
+ ]);
const baseUrl = reader.getString('backend.baseUrl');
+ const dynamicPlugins = reader.get('dynamicPlugins');
try {
const scalprumConfig: AppsConfig = await fetch(
`${baseUrl}/api/scalprum/plugins`,
).then(r => r.json());
return {
- appConfig,
+ dynamicPlugins,
baseUrl,
scalprumConfig,
};
@@ -49,7 +54,7 @@ const ScalprumRoot = ({
`Failed to fetch scalprum configuration: ${JSON.stringify(err)}`,
);
return {
- appConfig,
+ dynamicPlugins,
baseUrl,
scalprumConfig: {},
};
@@ -59,7 +64,7 @@ const ScalprumRoot = ({
if (loading && !value) {
return ;
}
- const { appConfig, baseUrl, scalprumConfig } = value || {};
+ const { dynamicPlugins, baseUrl, scalprumConfig } = value || {};
return (
diff --git a/packages/app/src/components/admin/AdminTabs.test.tsx b/packages/app/src/components/admin/AdminTabs.test.tsx
index db83fc58d1..dad1dbf225 100644
--- a/packages/app/src/components/admin/AdminTabs.test.tsx
+++ b/packages/app/src/components/admin/AdminTabs.test.tsx
@@ -5,13 +5,13 @@ import { removeScalprum } from '@scalprum/core';
import { renderWithEffects } from '@backstage/test-utils';
import AppBase from '../AppBase/AppBase';
import { act } from 'react-dom/test-utils';
-import { AppConfig } from '@backstage/config';
import * as useAsync from 'react-use/lib/useAsync';
import initializeRemotePlugins from '../../utils/dynamicUI/initializeRemotePlugins';
+import { defaultConfigLoader } from '@backstage/core-app-api';
const DynamicRoot = React.lazy(() => import('../DynamicRoot/DynamicRoot'));
const mockAppInner = () => ;
-const MockApp = ({ appConfig }: { appConfig: AppConfig[] }) => (
+const MockApp = ({ dynamicPlugins }: { dynamicPlugins: any }) => (
(
default: mockAppInner,
})
}
- appConfig={appConfig}
- baseFrontendConfig={{ context: 'frontend', data: {} }}
+ dynamicPlugins={dynamicPlugins}
scalprumConfig={{}}
/>
@@ -78,30 +77,6 @@ jest.mock('../home/HomePage', () => ({
__esModule: true,
}));
-// Ensure the correct configuration is picked up by the rendered app
-jest.mock('@backstage/config', () => {
- const oldModule = jest.requireActual('@backstage/config');
- const OldConfigReader = oldModule.ConfigReader;
- const FakeConfigReader = class {
- _instance: any = undefined;
- constructor(args: any) {
- this._instance = new OldConfigReader(args);
- }
- static fromConfigs(args: any) {
- const answer = OldConfigReader.fromConfigs([
- ...[Array.isArray(args) ? args : []],
- ...(JSON.parse(process.env.APP_CONFIG || '[]') as Array),
- ]);
- return answer;
- }
- };
- return {
- ...oldModule,
- ConfigReader: FakeConfigReader,
- __esModule: true,
- };
-});
-
const mockInitializeRemotePlugins = jest.fn() as jest.MockedFunction<
typeof initializeRemotePlugins
>;
@@ -110,22 +85,26 @@ jest.mock('../../utils/dynamicUI/initializeRemotePlugins', () => ({
__esModule: true,
}));
-const createAppConfig = (dynamicPluginsConfig: { [key: string]: any }) => [
- {
- data: {
- app: { title: 'Test' },
- backend: { baseUrl: 'http://localhost:7007' },
- techdocs: {
- storageUrl: 'http://localhost:7007/api/techdocs/static/docs',
- },
- auth: { environment: 'development' },
- dynamicPlugins: {
- frontend: dynamicPluginsConfig,
+const loadTestConfig = async (dynamicPlugins: any) => {
+ process.env = {
+ NODE_ENV: 'test',
+ APP_CONFIG: [
+ {
+ data: {
+ app: { title: 'Test' },
+ backend: { baseUrl: 'http://localhost:7007' },
+ techdocs: {
+ storageUrl: 'http://localhost:7007/api/techdocs/static/docs',
+ },
+ auth: { environment: 'development' },
+ dynamicPlugins,
+ },
+ context: 'test',
},
- },
- context: 'test',
- },
-];
+ ] as any,
+ };
+ await defaultConfigLoader();
+};
const consoleSpy = jest.spyOn(console, 'warn');
@@ -162,15 +141,19 @@ describe('AdminTabs', () => {
});
it('Should not be available when not configured', async () => {
- const appConfig = createAppConfig({
- 'test-plugin': {
- dynamicRoutes: [],
- mountPoints: [],
+ const dynamicPlugins = {
+ frontend: {
+ 'test-plugin': {
+ dynamicRoutes: [],
+ mountPoints: [],
+ },
},
- });
- process.env = { NODE_ENV: 'test', APP_CONFIG: JSON.stringify(appConfig) };
+ };
initialEntries = ['/'];
- const rendered = await renderWithEffects();
+ await loadTestConfig(dynamicPlugins);
+ const rendered = await renderWithEffects(
+ ,
+ );
expect(rendered.baseElement).toBeInTheDocument();
const home = rendered.queryByText('Home');
const administration = rendered.queryByText('Administration');
@@ -179,15 +162,19 @@ describe('AdminTabs', () => {
});
it('Should be available when configured', async () => {
- const appConfig = createAppConfig({
- 'test-plugin': {
- dynamicRoutes: [{ path: '/admin/plugins' }],
- mountPoints: [{ mountPoint: 'admin.page.plugins/cards' }],
+ const dynamicPlugins = {
+ frontend: {
+ 'test-plugin': {
+ dynamicRoutes: [{ path: '/admin/plugins' }],
+ mountPoints: [{ mountPoint: 'admin.page.plugins/cards' }],
+ },
},
- });
+ };
initialEntries = ['/'];
- process.env = { NODE_ENV: 'test', APP_CONFIG: JSON.stringify(appConfig) };
- const rendered = await renderWithEffects();
+ await loadTestConfig(dynamicPlugins);
+ const rendered = await renderWithEffects(
+ ,
+ );
expect(rendered.baseElement).toBeInTheDocument();
const home = rendered.queryByText('Home');
const administration = rendered.queryByText('Administration');
@@ -196,15 +183,19 @@ describe('AdminTabs', () => {
});
it('Should route to the plugin tab when configured', async () => {
- const appConfig = createAppConfig({
- 'test-plugin': {
- dynamicRoutes: [{ path: '/admin/plugins' }],
- mountPoints: [{ mountPoint: 'admin.page.plugins/cards' }],
+ const dynamicPlugins = {
+ frontend: {
+ 'test-plugin': {
+ dynamicRoutes: [{ path: '/admin/plugins' }],
+ mountPoints: [{ mountPoint: 'admin.page.plugins/cards' }],
+ },
},
- });
+ };
initialEntries = ['/'];
- process.env = { NODE_ENV: 'test', APP_CONFIG: JSON.stringify(appConfig) };
- const rendered = await renderWithEffects();
+ await loadTestConfig(dynamicPlugins);
+ const rendered = await renderWithEffects(
+ ,
+ );
expect(rendered.baseElement).toBeInTheDocument();
await act(() => {
rendered.getByText('Administration').click();
@@ -214,15 +205,19 @@ describe('AdminTabs', () => {
});
it('Should route to the rbac tab when configured', async () => {
- const appConfig = createAppConfig({
- 'test-plugin': {
- dynamicRoutes: [{ path: '/admin/rbac' }],
- mountPoints: [{ mountPoint: 'admin.page.rbac/cards' }],
+ const dynamicPlugins = {
+ frontend: {
+ 'test-plugin': {
+ dynamicRoutes: [{ path: '/admin/rbac' }],
+ mountPoints: [{ mountPoint: 'admin.page.rbac/cards' }],
+ },
},
- });
+ };
initialEntries = ['/'];
- process.env = { NODE_ENV: 'test', APP_CONFIG: JSON.stringify(appConfig) };
- const rendered = await renderWithEffects();
+ await loadTestConfig(dynamicPlugins);
+ const rendered = await renderWithEffects(
+ ,
+ );
expect(rendered.baseElement).toBeInTheDocument();
await act(() => {
rendered.getByText('Administration').click();
@@ -232,15 +227,19 @@ describe('AdminTabs', () => {
});
it("Should fail back to the default tab if the currently routed tab doesn't match the configuration", async () => {
- const appConfig = createAppConfig({
- 'test-plugin': {
- dynamicRoutes: [{ path: '/admin/rbac' }],
- mountPoints: [{ mountPoint: 'admin.page.rbac/cards' }],
+ const dynamicPlugins = {
+ frontend: {
+ 'test-plugin': {
+ dynamicRoutes: [{ path: '/admin/rbac' }],
+ mountPoints: [{ mountPoint: 'admin.page.rbac/cards' }],
+ },
},
- });
+ };
initialEntries = ['/admin/plugins'];
- process.env = { NODE_ENV: 'test', APP_CONFIG: JSON.stringify(appConfig) };
- const rendered = await renderWithEffects();
+ await loadTestConfig(dynamicPlugins);
+ const rendered = await renderWithEffects(
+ ,
+ );
// When debugging this test it can be handy to see the entire rendered output
// process.stdout.write(`${prettyDOM(rendered.baseElement, 900000)}`);
expect(rendered.baseElement).toBeInTheDocument();
@@ -248,15 +247,19 @@ describe('AdminTabs', () => {
});
it('Should fail with an error page if routed to but no configuration is defined', async () => {
- const appConfig = createAppConfig({
- 'test-plugin': {
- dynamicRoutes: [],
- mountPoints: [],
+ const dynamicPlugins = {
+ frontend: {
+ 'test-plugin': {
+ dynamicRoutes: [],
+ mountPoints: [],
+ },
},
- });
+ };
initialEntries = ['/admin/plugins'];
- process.env = { NODE_ENV: 'test', APP_CONFIG: JSON.stringify(appConfig) };
- const rendered = await renderWithEffects();
+ await loadTestConfig(dynamicPlugins);
+ const rendered = await renderWithEffects(
+ ,
+ );
// When debugging this test it can be handy to see the entire rendered output
// process.stdout.write(`${prettyDOM(rendered.baseElement, 900000)}`);
expect(rendered.baseElement).toBeInTheDocument();
diff --git a/packages/app/src/utils/dynamicUI/extractDynamicConfig.test.ts b/packages/app/src/utils/dynamicUI/extractDynamicConfig.test.ts
index 02d86a9e89..35387d7475 100644
--- a/packages/app/src/utils/dynamicUI/extractDynamicConfig.test.ts
+++ b/packages/app/src/utils/dynamicUI/extractDynamicConfig.test.ts
@@ -1,5 +1,5 @@
-import { AppConfig } from '@backstage/config';
import extractDynamicConfig, {
+ DynamicPluginConfig,
conditionsArrayMapper,
configIfToCallable,
} from './extractDynamicConfig';
@@ -143,10 +143,8 @@ describe('extractDynamicConfig', () => {
'no frontend dynamic plugins are defined',
{ dynamicPlugins: { frontend: {} } },
],
- ])('returns empty data when %s', async (_, source) => {
- const config = await extractDynamicConfig({
- appConfig: [source] as AppConfig[],
- });
+ ])('returns empty data when %s', (_, source) => {
+ const config = extractDynamicConfig(source as DynamicPluginConfig);
expect(config).toEqual({
routeBindings: [],
dynamicRoutes: [],
@@ -430,16 +428,9 @@ describe('extractDynamicConfig', () => {
],
},
],
- ])('parses %s', async (_, source, output) => {
- const config = await extractDynamicConfig({
- appConfig: [
- {
- context: 'foo',
- data: {
- dynamicPlugins: { frontend: { 'janus-idp.plugin-foo': source } },
- },
- },
- ] as AppConfig[],
+ ])('parses %s', (_, source: any, output) => {
+ const config = extractDynamicConfig({
+ frontend: { 'janus-idp.plugin-foo': source },
});
expect(config).toEqual({
routeBindings: [],
diff --git a/packages/app/src/utils/dynamicUI/extractDynamicConfig.ts b/packages/app/src/utils/dynamicUI/extractDynamicConfig.ts
index f517c647a1..9dc064596d 100644
--- a/packages/app/src/utils/dynamicUI/extractDynamicConfig.ts
+++ b/packages/app/src/utils/dynamicUI/extractDynamicConfig.ts
@@ -77,20 +77,12 @@ type CustomProperties = {
apiFactories?: ApiFactory[];
};
-type AppConfig = {
- context: string;
- data: {
- dynamicPlugins?: {
- frontend?: {
- [key: string]: CustomProperties;
- };
- };
- };
+type FrontendConfig = {
+ [key: string]: CustomProperties;
};
-type ExtractDynamicConfigProps = {
- appConfig?: AppConfig[];
- frontendAppConfig?: AppConfig;
+export type DynamicPluginConfig = {
+ frontend?: FrontendConfig;
};
type DynamicConfig = {
@@ -104,44 +96,14 @@ type DynamicConfig = {
};
/**
- * Converts all available configuration sources into the data structures
- * needed by the DynamicRoot component to wire the app together. Accepts
- * an initial configuration for any statically linked frontend plugins that
- * need to display UI elements on dynamic frontend pages.
- *
- * @param frontendAppConfig
- */
-async function extractDynamicConfig({
- appConfig = [],
- frontendAppConfig = { context: '', data: {} },
-}: ExtractDynamicConfigProps) {
- const initialDynamicConfig = appConfigsToDynamicConfig([frontendAppConfig]);
- const dynamicConfig = appConfigsToDynamicConfig(appConfig, {
- apiFactories: initialDynamicConfig.apiFactories,
- appIcons: initialDynamicConfig.appIcons,
- dynamicRoutes: initialDynamicConfig.dynamicRoutes.filter(dynamicRoute =>
- doesConfigContain(dynamicRoute, 'dynamicRoutes', appConfig),
- ),
- entityTabs: initialDynamicConfig.entityTabs,
- mountPoints: initialDynamicConfig.mountPoints.filter(mountPoint =>
- doesConfigContain(mountPoint, 'mountPoints', appConfig),
- ),
- routeBindings: initialDynamicConfig.routeBindings,
- routeBindingTargets: initialDynamicConfig.routeBindingTargets,
- });
- return dynamicConfig;
-}
-
-/**
- * Converts an array of AppConfig objects to a dynamic frontend
- * configuration structure
- * @param appConfigs
- * @param initialDynamicConfig
- * @returns
+ * Converts the dynamic plugin configuration structure to the data structure
+ * required by the dynamic UI, substituting in any defaults as needed
*/
-function appConfigsToDynamicConfig(
- appConfigs: AppConfig[],
- initialDynamicConfig: DynamicConfig = {
+function extractDynamicConfig(
+ dynamicPlugins: DynamicPluginConfig = { frontend: {} },
+) {
+ const frontend = dynamicPlugins.frontend || {};
+ const config: DynamicConfig = {
apiFactories: [],
appIcons: [],
dynamicRoutes: [],
@@ -149,146 +111,96 @@ function appConfigsToDynamicConfig(
mountPoints: [],
routeBindings: [],
routeBindingTargets: [],
- },
-) {
- return appConfigs.reduce((acc, { data }) => {
- if (data?.dynamicPlugins?.frontend) {
- acc.dynamicRoutes.push(
- ...Object.entries(data.dynamicPlugins.frontend).reduce(
- (pluginSet, [scope, customProperties]) => {
- pluginSet.push(
- ...(customProperties.dynamicRoutes ?? []).map(route => ({
- ...route,
- module: route.module ?? 'PluginRoot',
- importName: route.importName ?? 'default',
- scope,
- })),
- );
- return pluginSet;
- },
- [],
- ),
+ };
+ config.dynamicRoutes = Object.entries(frontend).reduce(
+ (pluginSet, [scope, customProperties]) => {
+ pluginSet.push(
+ ...(customProperties.dynamicRoutes ?? []).map(route => ({
+ ...route,
+ module: route.module ?? 'PluginRoot',
+ importName: route.importName ?? 'default',
+ scope,
+ })),
);
- acc.routeBindings.push(
- ...Object.entries(data.dynamicPlugins.frontend).reduce(
- (pluginSet, [_, customProperties]) => {
- pluginSet.push(...(customProperties.routeBindings?.bindings ?? []));
- return pluginSet;
- },
- [],
- ),
+ return pluginSet;
+ },
+ [],
+ );
+ config.routeBindings = Object.entries(frontend).reduce(
+ (pluginSet, [_, customProperties]) => {
+ pluginSet.push(...(customProperties.routeBindings?.bindings ?? []));
+ return pluginSet;
+ },
+ [],
+ );
+ config.routeBindingTargets = Object.entries(frontend).reduce(
+ (pluginSet, [scope, customProperties]) => {
+ pluginSet.push(
+ ...(customProperties.routeBindings?.targets ?? []).map(target => ({
+ ...target,
+ module: target.module ?? 'PluginRoot',
+ name: target.name ?? target.importName,
+ scope,
+ })),
);
- acc.routeBindingTargets.push(
- ...Object.entries(data.dynamicPlugins.frontend).reduce(
- (pluginSet, [scope, customProperties]) => {
- pluginSet.push(
- ...(customProperties.routeBindings?.targets ?? []).map(
- target => ({
- ...target,
- module: target.module ?? 'PluginRoot',
- name: target.name ?? target.importName,
- scope,
- }),
- ),
- );
- return pluginSet;
- },
- [],
- ),
+ return pluginSet;
+ },
+ [],
+ );
+ config.mountPoints = Object.entries(frontend).reduce(
+ (accMountPoints, [scope, { mountPoints }]) => {
+ accMountPoints.push(
+ ...(mountPoints ?? []).map(mountPoint => ({
+ ...mountPoint,
+ module: mountPoint.module ?? 'PluginRoot',
+ importName: mountPoint.importName ?? 'default',
+ scope,
+ })),
);
-
- acc.mountPoints.push(
- ...Object.entries(data.dynamicPlugins.frontend).reduce(
- (accMountPoints, [scope, { mountPoints }]) => {
- accMountPoints.push(
- ...(mountPoints ?? []).map(point => ({
- ...point,
- module: point.module ?? 'PluginRoot',
- importName: point.importName ?? 'default',
- scope,
- })),
- );
- return accMountPoints;
- },
- [],
- ),
+ return accMountPoints;
+ },
+ [],
+ );
+ config.appIcons = Object.entries(frontend).reduce(
+ (accAppIcons, [scope, { appIcons }]) => {
+ accAppIcons.push(
+ ...(appIcons ?? []).map(icon => ({
+ ...icon,
+ module: icon.module ?? 'PluginRoot',
+ importName: icon.importName ?? 'default',
+ scope,
+ })),
);
-
- acc.appIcons.push(
- ...Object.entries(data.dynamicPlugins.frontend).reduce(
- (accAppIcons, [scope, { appIcons }]) => {
- accAppIcons.push(
- ...(appIcons ?? []).map(icon => ({
- ...icon,
- module: icon.module ?? 'PluginRoot',
- importName: icon.importName ?? 'default',
- scope,
- })),
- );
- return accAppIcons;
- },
- [],
- ),
+ return accAppIcons;
+ },
+ [],
+ );
+ config.apiFactories = Object.entries(frontend).reduce(
+ (accApiFactories, [scope, { apiFactories }]) => {
+ accApiFactories.push(
+ ...(apiFactories ?? []).map(api => ({
+ module: api.module ?? 'PluginRoot',
+ importName: api.importName ?? 'default',
+ scope,
+ })),
);
-
- acc.apiFactories.push(
- ...Object.entries(data.dynamicPlugins.frontend).reduce(
- (accApiFactories, [scope, { apiFactories }]) => {
- accApiFactories.push(
- ...(apiFactories ?? []).map(api => ({
- module: api.module ?? 'PluginRoot',
- importName: api.importName ?? 'default',
- scope,
- })),
- );
- return accApiFactories;
- },
- [],
- ),
- );
-
- acc.entityTabs.push(
- ...Object.entries(data.dynamicPlugins.frontend).reduce<
- EntityTabEntry[]
- >((accEntityTabs, [scope, { entityTabs }]) => {
- accEntityTabs.push(
- ...(entityTabs ?? []).map(entityTab => ({
- ...entityTab,
- scope,
- })),
- );
- return accEntityTabs;
- }, []),
+ return accApiFactories;
+ },
+ [],
+ );
+ config.entityTabs = Object.entries(frontend).reduce(
+ (accEntityTabs, [scope, { entityTabs }]) => {
+ accEntityTabs.push(
+ ...(entityTabs ?? []).map(entityTab => ({
+ ...entityTab,
+ scope,
+ })),
);
- }
- return acc;
- }, initialDynamicConfig);
-}
-
-/**
- * Check the app config to see if the given entry has been configured in an
- * app-config.yaml file. Used to override static plugin configuration.
- *
- * @param entry
- * @param attribute
- * @param appConfigs
- * @returns
- */
-function doesConfigContain(
- entry: DynamicRoute | MountPoint,
- attribute: string,
- appConfigs: AppConfig[],
-) {
- return appConfigs
- .map(
- (appConfig: AppConfig) => appConfig.data.dynamicPlugins?.frontend || {},
- )
- .filter(pluginConfig => {
- return Object.keys(pluginConfig).find(scope => scope === entry.scope);
- })
- .reduce((_acc, curr: any) => {
- return curr[entry.scope][attribute] === undefined;
- }, true);
+ return accEntityTabs;
+ },
+ [],
+ );
+ return config;
}
/**