frontend-app-api: remove .createRoot
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
---
|
||||
'@backstage/frontend-app-api': minor
|
||||
---
|
||||
|
||||
**BREAKING**: The returned object from `createSpecializedApp` no longer contains a `createRoot()` method, and it instead now contains `apis` and `tree`.
|
||||
|
||||
You can replace existing usage of `app.createRoot()` with the following:
|
||||
|
||||
```ts
|
||||
const root = tree.root.instance?.getData(coreExtensionData.reactEleme
|
||||
nt);
|
||||
```
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/frontend-defaults': patch
|
||||
'@backstage/frontend-test-utils': patch
|
||||
---
|
||||
|
||||
Internal refactor to match updated `createSpecializedApp`.
|
||||
@@ -10,7 +10,6 @@ import { ExtensionDefinition } from '@backstage/frontend-plugin-api';
|
||||
import { ExternalRouteRef } from '@backstage/frontend-plugin-api';
|
||||
import { FrontendModule } from '@backstage/frontend-plugin-api';
|
||||
import { FrontendPlugin } from '@backstage/frontend-plugin-api';
|
||||
import { JSX as JSX_2 } from 'react';
|
||||
import { RouteRef } from '@backstage/frontend-plugin-api';
|
||||
import { SubRouteRef } from '@backstage/frontend-plugin-api';
|
||||
|
||||
@@ -36,7 +35,6 @@ export function createSpecializedApp(options?: {
|
||||
extensionFactoryMiddleware?: ExtensionFactoryMiddleware;
|
||||
}): {
|
||||
apis: ApiHolder;
|
||||
createRoot(): JSX_2.Element;
|
||||
tree: AppTree;
|
||||
};
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ describe('createSpecializedApp', () => {
|
||||
],
|
||||
});
|
||||
|
||||
render(app.createRoot());
|
||||
render(app.tree.root.instance!.getData(coreExtensionData.reactElement));
|
||||
|
||||
expect(screen.getByText('Test')).toBeInTheDocument();
|
||||
});
|
||||
@@ -91,7 +91,7 @@ describe('createSpecializedApp', () => {
|
||||
],
|
||||
});
|
||||
|
||||
render(app.createRoot());
|
||||
render(app.tree.root.instance!.getData(coreExtensionData.reactElement));
|
||||
|
||||
expect(screen.getByText('Test 2')).toBeInTheDocument();
|
||||
});
|
||||
@@ -117,7 +117,7 @@ describe('createSpecializedApp', () => {
|
||||
],
|
||||
});
|
||||
|
||||
render(app.createRoot());
|
||||
render(app.tree.root.instance!.getData(coreExtensionData.reactElement));
|
||||
|
||||
expect(screen.getByText('Test foo')).toBeInTheDocument();
|
||||
});
|
||||
@@ -163,7 +163,7 @@ describe('createSpecializedApp', () => {
|
||||
],
|
||||
});
|
||||
|
||||
render(app.createRoot());
|
||||
render(app.tree.root.instance!.getData(coreExtensionData.reactElement));
|
||||
|
||||
expect(screen.getByText('flags:test=a,test=b')).toBeInTheDocument();
|
||||
|
||||
@@ -307,7 +307,7 @@ describe('createSpecializedApp', () => {
|
||||
],
|
||||
});
|
||||
|
||||
render(app.createRoot());
|
||||
render(app.tree.root.instance!.getData(coreExtensionData.reactElement));
|
||||
|
||||
expect(mockAnalyticsApi).toHaveBeenCalled();
|
||||
});
|
||||
@@ -339,7 +339,7 @@ describe('createSpecializedApp', () => {
|
||||
],
|
||||
});
|
||||
|
||||
render(app.createRoot());
|
||||
render(app.tree.root.instance!.getData(coreExtensionData.reactElement));
|
||||
|
||||
expect(screen.getByText('providedApis:config')).toBeInTheDocument();
|
||||
|
||||
@@ -518,7 +518,7 @@ describe('createSpecializedApp', () => {
|
||||
bindRoutes({ bind }) {
|
||||
bind(pluginA.externalRoutes, { ext: pluginB.routes.root });
|
||||
},
|
||||
}).createRoot(),
|
||||
}).tree.root.instance!.getData(coreExtensionData.reactElement),
|
||||
);
|
||||
|
||||
expect(screen.getByText('link: /test')).toBeInTheDocument();
|
||||
|
||||
@@ -14,14 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { JSX } from 'react';
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import {
|
||||
ApiBlueprint,
|
||||
AppTree,
|
||||
AppTreeApi,
|
||||
appTreeApiRef,
|
||||
coreExtensionData,
|
||||
RouteRef,
|
||||
ExternalRouteRef,
|
||||
SubRouteRef,
|
||||
@@ -191,6 +189,7 @@ class RouteResolutionApiProxy implements RouteResolutionApi {
|
||||
return this.#routeObjects;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty app without any default features. This is a low-level API is
|
||||
* intended for use in tests or specialized setups. Typically wou want to use
|
||||
@@ -204,7 +203,7 @@ export function createSpecializedApp(options?: {
|
||||
bindRoutes?(context: { bind: CreateAppRouteBinder }): void;
|
||||
apis?: ApiHolder;
|
||||
extensionFactoryMiddleware?: ExtensionFactoryMiddleware;
|
||||
}): { apis: ApiHolder; createRoot(): JSX.Element; tree: AppTree } {
|
||||
}): { apis: ApiHolder; tree: AppTree } {
|
||||
const config = options?.config ?? new ConfigReader({}, 'empty-config');
|
||||
const features = deduplicateFeatures(options?.features ?? []);
|
||||
|
||||
@@ -233,7 +232,7 @@ export function createSpecializedApp(options?: {
|
||||
);
|
||||
|
||||
const appIdentityProxy = new AppIdentityProxy();
|
||||
const apiHolder =
|
||||
const apis =
|
||||
options?.apis ??
|
||||
createApiHolder({
|
||||
factories,
|
||||
@@ -245,7 +244,7 @@ export function createSpecializedApp(options?: {
|
||||
],
|
||||
});
|
||||
|
||||
const featureFlagApi = apiHolder.get(featureFlagsApiRef);
|
||||
const featureFlagApi = apis.get(featureFlagsApiRef);
|
||||
if (featureFlagApi) {
|
||||
for (const feature of features) {
|
||||
if (OpaqueFrontendPlugin.isType(feature)) {
|
||||
@@ -268,28 +267,14 @@ export function createSpecializedApp(options?: {
|
||||
}
|
||||
|
||||
// Now instantiate the entire tree, which will skip anything that's already been instantiated
|
||||
instantiateAppNodeTree(
|
||||
tree.root,
|
||||
apiHolder,
|
||||
options?.extensionFactoryMiddleware,
|
||||
);
|
||||
instantiateAppNodeTree(tree.root, apis, options?.extensionFactoryMiddleware);
|
||||
|
||||
const routeInfo = extractRouteInfoFromAppNode(tree.root);
|
||||
|
||||
routeResolutionApi.initialize(routeInfo);
|
||||
appTreeApi.initialize(routeInfo);
|
||||
|
||||
const rootEl = tree.root.instance!.getData(coreExtensionData.reactElement);
|
||||
|
||||
const AppComponent = () => rootEl;
|
||||
|
||||
return {
|
||||
apis: apiHolder,
|
||||
tree,
|
||||
createRoot() {
|
||||
return <AppComponent />;
|
||||
},
|
||||
};
|
||||
return { apis, tree };
|
||||
}
|
||||
|
||||
function createApiFactories(options: { tree: AppTree }): AnyApiFactory[] {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import React, { JSX, ReactNode } from 'react';
|
||||
import { ConfigApi } from '@backstage/frontend-plugin-api';
|
||||
import { ConfigApi, coreExtensionData } from '@backstage/frontend-plugin-api';
|
||||
import { stringifyError } from '@backstage/errors';
|
||||
// eslint-disable-next-line @backstage/no-relative-monorepo-imports
|
||||
import { defaultConfigLoaderSync } from '../../core-app-api/src/app/defaultConfigLoader';
|
||||
@@ -114,9 +114,13 @@ export function createApp(options?: CreateAppOptions): {
|
||||
features: [appPlugin, ...discoveredFeatures, ...providedFeatures],
|
||||
bindRoutes: options?.bindRoutes,
|
||||
extensionFactoryMiddleware: options?.extensionFactoryMiddleware,
|
||||
}).createRoot();
|
||||
});
|
||||
|
||||
return { default: () => app };
|
||||
const rootEl = app.tree.root.instance!.getData(
|
||||
coreExtensionData.reactElement,
|
||||
);
|
||||
|
||||
return { default: () => rootEl };
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -201,5 +201,7 @@ export function renderInTestApp(
|
||||
]),
|
||||
});
|
||||
|
||||
return render(app.createRoot());
|
||||
return render(
|
||||
app.tree.root.instance!.getData(coreExtensionData.reactElement),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user