chore: updating api reports

Signed-off-by: benjdlambert <ben@blam.sh>
This commit is contained in:
benjdlambert
2025-08-06 10:17:16 +02:00
parent 9c7ec669cf
commit 233a4eddf1
10 changed files with 254 additions and 41 deletions
@@ -27,6 +27,9 @@ import {
iconsApiRef,
useApi,
routeResolutionApiRef,
ErrorBoundary,
NotFoundErrorPage,
Progress,
} from '@backstage/frontend-plugin-api';
import {
AppComponents,
@@ -42,9 +45,6 @@ import {
} from '@backstage/version-bridge';
import { convertLegacyRouteRef } from '../convertLegacyRouteRef';
import { ErrorBoundary, NotFoundErrorPage } from '@backstage/plugin-app';
import { Progress } from '@backstage/core-components';
// Make sure that we only convert each new plugin instance to its legacy equivalent once
const legacyPluginStore = getOrCreateGlobalSingleton(
'legacy-plugin-compatibility-store',
@@ -37,6 +37,9 @@ import {
componentsApiRef,
iconsApiRef,
routeResolutionApiRef,
Progress,
NotFoundErrorPage,
ErrorBoundary,
} from '@backstage/frontend-plugin-api';
import { ComponentType, useMemo } from 'react';
import { ReactNode } from 'react';
@@ -66,14 +69,28 @@ class CompatComponentsApi implements ComponentsApi {
this.#ErrorBoundaryFallback = ErrorBoundaryFallback;
}
getComponent<T extends {}>(ref: ComponentRef<T>): ComponentType<T> {
getComponent<
TInnerComponentProps extends {},
TExternalComponentProps extends {} = TInnerComponentProps,
>(
ref: ComponentRef<TInnerComponentProps, TExternalComponentProps>,
):
| (() => (props: TInnerComponentProps) => JSX.Element | null)
| (() => Promise<(props: TInnerComponentProps) => JSX.Element | null>)
| undefined {
switch (ref.id) {
case coreComponentRefs.progress.id:
return this.#Progress as ComponentType<any>;
case coreComponentRefs.notFoundErrorPage.id:
return this.#NotFoundErrorPage as ComponentType<any>;
case coreComponentRefs.errorBoundaryFallback.id:
return this.#ErrorBoundaryFallback as ComponentType<any>;
case Progress.ref.id:
return (() => this.#Progress) as () => (
props: object,
) => JSX.Element | null;
case NotFoundErrorPage.ref.id:
return (() => this.#NotFoundErrorPage) as () => (
props: object,
) => JSX.Element | null;
case ErrorBoundary.ref.id:
return (() => this.#ErrorBoundaryFallback) as () => (
props: object,
) => JSX.Element | null;
default:
throw new Error(
`No backwards compatible component is available for ref '${ref.id}'`,
@@ -16,13 +16,15 @@
import {
componentsApiRef,
coreComponentRefs,
coreExtensionData,
createExtension,
iconsApiRef,
useRouteRef as useNewRouteRef,
createRouteRef as createNewRouteRef,
useApi,
NotFoundErrorPage,
ErrorBoundary,
Progress,
} from '@backstage/frontend-plugin-api';
import {
createExtensionTester,
@@ -97,13 +99,19 @@ describe('BackwardsCompatProvider', () => {
describe('ForwardsCompatProvider', () => {
it('should convert the app context', async () => {
const defaultComponentRefs = {
progress: Progress.ref,
notFoundErrorPage: NotFoundErrorPage.ref,
errorBoundary: ErrorBoundary.ref,
};
function Component() {
const components = useApi(componentsApiRef);
const icons = useApi(iconsApiRef);
return (
<div data-testid="ctx">
components:{' '}
{Object.entries(coreComponentRefs)
{Object.entries(defaultComponentRefs)
.map(
([name, ref]) =>
`${name}=${Boolean(components.getComponent(ref))}`,
@@ -27,6 +27,11 @@ export const componentDataRef = createExtensionDataRef<{
| (() => Promise<(props: {}) => JSX.Element | null>);
}>().with({ id: 'core.component.component' });
/**
* Blueprint for creating adaptable components from a componentRef and a loader
*
* @public
*/
export const AdaptableComponentBlueprint = createExtensionBlueprint({
kind: 'component',
attachTo: { id: 'api:app/components', input: 'components' },
@@ -13,16 +13,32 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { createAdaptableComponent } from '@backstage/frontend-plugin-api';
import {
CoreErrorBoundaryFallbackProps,
CoreNotFoundErrorPageProps,
CoreProgressProps,
createAdaptableComponent,
} from '@backstage/frontend-plugin-api';
export const Progress = createAdaptableComponent({
/**
* @public
*/
export const Progress = createAdaptableComponent<CoreProgressProps>({
id: 'core.components.progress',
});
export const NotFoundErrorPage = createAdaptableComponent({
id: 'core.components.notFoundErrorPage',
});
/**
* @public
*/
export const NotFoundErrorPage =
createAdaptableComponent<CoreNotFoundErrorPageProps>({
id: 'core.components.notFoundErrorPage',
});
export const ErrorBoundary = createAdaptableComponent({
id: 'core.components.errorBoundary',
});
/**
* @public
*/
export const ErrorBoundary =
createAdaptableComponent<CoreErrorBoundaryFallbackProps>({
id: 'core.components.errorBoundary',
});
@@ -29,7 +29,12 @@ export type ComponentRef<
$$type: '@backstage/ComponentRef';
};
export type ComponentRefOptions<
/**
* Options for creating an AdaptableComponent.
*
* @public
*/
export type CreateAdaptableComponentOptions<
TInnerComponentProps extends {},
TExternalComponentProps extends {} = TInnerComponentProps,
> = {
@@ -90,11 +95,19 @@ function makeComponentFromRef<
return ComponentRefImpl;
}
/**
* Creates a AdaptableComponent that can be used to render the component, optionally overriden by the app.
*
* @public
*/
export function createAdaptableComponent<
TInnerComponentProps extends {},
TExternalComponentProps extends {} = TInnerComponentProps,
>(
options: ComponentRefOptions<TInnerComponentProps, TExternalComponentProps>,
options: CreateAdaptableComponentOptions<
TInnerComponentProps,
TExternalComponentProps
>,
): ((props: TExternalComponentProps) => JSX.Element) & {
ref: ComponentRef<TInnerComponentProps, TExternalComponentProps>;
} {
@@ -20,6 +20,7 @@ export {
} from './ExtensionBoundary';
export {
createAdaptableComponent,
type CreateAdaptableComponentOptions,
type ComponentRef,
} from './createAdaptableComponent';
export { useAppNode } from './AppNodeProvider';
+135 -1
View File
@@ -324,7 +324,9 @@ const appPlugin: FrontendPlugin<
ConfigurableExtensionDataRef<
{
ref: ComponentRef;
impl: ComponentType;
loader:
| (() => (props: {}) => JSX.Element | null)
| (() => Promise<(props: {}) => JSX.Element | null>);
},
'core.component.component',
{}
@@ -726,6 +728,138 @@ const appPlugin: FrontendPlugin<
element: JSX.Element;
};
}>;
'component:app/core.components.errorBoundary': ExtensionDefinition<{
kind: 'component';
name: 'core.components.errorBoundary';
config: {};
configInput: {};
output: ConfigurableExtensionDataRef<
{
ref: ComponentRef;
loader:
| (() => (props: {}) => JSX.Element | null)
| (() => Promise<(props: {}) => JSX.Element | null>);
},
'core.component.component',
{}
>;
inputs: {};
params: <Ref extends ComponentRef<any>>(params: {
component: Ref extends ComponentRef<any, infer IExternalComponentProps>
? {
ref: Ref;
} & ((props: IExternalComponentProps) => JSX.Element)
: never;
loader: Ref extends ComponentRef<infer IInnerComponentProps, any>
?
| (() => (props: IInnerComponentProps) => JSX.Element | null)
| (() => Promise<
(props: IInnerComponentProps) => JSX.Element | null
>)
: never;
}) => ExtensionBlueprintParams<{
component: Ref extends ComponentRef<any, infer IExternalComponentProps>
? {
ref: Ref;
} & ((props: IExternalComponentProps) => JSX.Element)
: never;
loader: Ref extends ComponentRef<infer IInnerComponentProps, any>
?
| (() => (props: IInnerComponentProps) => JSX.Element | null)
| (() => Promise<
(props: IInnerComponentProps) => JSX.Element | null
>)
: never;
}>;
}>;
'component:app/core.components.notFoundErrorPage': ExtensionDefinition<{
kind: 'component';
name: 'core.components.notFoundErrorPage';
config: {};
configInput: {};
output: ConfigurableExtensionDataRef<
{
ref: ComponentRef;
loader:
| (() => (props: {}) => JSX.Element | null)
| (() => Promise<(props: {}) => JSX.Element | null>);
},
'core.component.component',
{}
>;
inputs: {};
params: <Ref extends ComponentRef<any>>(params: {
component: Ref extends ComponentRef<any, infer IExternalComponentProps>
? {
ref: Ref;
} & ((props: IExternalComponentProps) => JSX.Element)
: never;
loader: Ref extends ComponentRef<infer IInnerComponentProps, any>
?
| (() => (props: IInnerComponentProps) => JSX.Element | null)
| (() => Promise<
(props: IInnerComponentProps) => JSX.Element | null
>)
: never;
}) => ExtensionBlueprintParams<{
component: Ref extends ComponentRef<any, infer IExternalComponentProps>
? {
ref: Ref;
} & ((props: IExternalComponentProps) => JSX.Element)
: never;
loader: Ref extends ComponentRef<infer IInnerComponentProps, any>
?
| (() => (props: IInnerComponentProps) => JSX.Element | null)
| (() => Promise<
(props: IInnerComponentProps) => JSX.Element | null
>)
: never;
}>;
}>;
'component:app/core.components.progress': ExtensionDefinition<{
kind: 'component';
name: 'core.components.progress';
config: {};
configInput: {};
output: ConfigurableExtensionDataRef<
{
ref: ComponentRef;
loader:
| (() => (props: {}) => JSX.Element | null)
| (() => Promise<(props: {}) => JSX.Element | null>);
},
'core.component.component',
{}
>;
inputs: {};
params: <Ref extends ComponentRef<any>>(params: {
component: Ref extends ComponentRef<any, infer IExternalComponentProps>
? {
ref: Ref;
} & ((props: IExternalComponentProps) => JSX.Element)
: never;
loader: Ref extends ComponentRef<infer IInnerComponentProps, any>
?
| (() => (props: IInnerComponentProps) => JSX.Element | null)
| (() => Promise<
(props: IInnerComponentProps) => JSX.Element | null
>)
: never;
}) => ExtensionBlueprintParams<{
component: Ref extends ComponentRef<any, infer IExternalComponentProps>
? {
ref: Ref;
} & ((props: IExternalComponentProps) => JSX.Element)
: never;
loader: Ref extends ComponentRef<infer IInnerComponentProps, any>
?
| (() => (props: IInnerComponentProps) => JSX.Element | null)
| (() => Promise<
(props: IInnerComponentProps) => JSX.Element | null
>)
: never;
}>;
}>;
'sign-in-page:app': ExtensionDefinition<{
kind: 'sign-in-page';
name: undefined;
+19 -3
View File
@@ -20,7 +20,12 @@ import {
AdaptableComponentBlueprint,
} from '@backstage/frontend-plugin-api';
import { Progress as ProgressComponent } from '@backstage/core-components';
import {
ErrorPage,
ErrorPanel,
Progress as ProgressComponent,
} from '@backstage/core-components';
import Button from '@material-ui/core/Button';
export const Progress = AdaptableComponentBlueprint.make({
name: 'core.components.progress',
@@ -36,7 +41,8 @@ export const NotFoundErrorPage = AdaptableComponentBlueprint.make({
params: define =>
define({
component: AdaptableNotFoundErrorPage,
loader: () => NotFoundErrorPageComponent,
loader: () => () =>
<ErrorPage status="404" statusMessage="PAGE NOT FOUND" />,
}),
});
@@ -45,6 +51,16 @@ export const ErrorBoundary = AdaptableComponentBlueprint.make({
params: define =>
define({
component: AdaptableErrorBoundary,
loader: () => ErrorBoundaryComponent,
loader: () => props => {
const { plugin, error, resetError } = props;
const title = `Error in ${plugin?.id}`;
return (
<ErrorPanel title={title} error={error} defaultExpanded>
<Button variant="outlined" onClick={resetError}>
Retry
</Button>
</ErrorPanel>
);
},
}),
});
+18 -15
View File
@@ -32295,12 +32295,12 @@ __metadata:
languageName: node
linkType: hard
"for-each@npm:^0.3.3":
version: 0.3.3
resolution: "for-each@npm:0.3.3"
"for-each@npm:^0.3.3, for-each@npm:^0.3.5":
version: 0.3.5
resolution: "for-each@npm:0.3.5"
dependencies:
is-callable: "npm:^1.1.3"
checksum: 10/fdac0cde1be35610bd635ae958422e8ce0cc1313e8d32ea6d34cfda7b60850940c1fd07c36456ad76bd9c24aef6ff5e03b02beb58c83af5ef6c968a64eada676
is-callable: "npm:^1.2.7"
checksum: 10/330cc2439f85c94f4609de3ee1d32c5693ae15cdd7fe3d112c4fd9efd4ce7143f2c64ef6c2c9e0cfdb0058437f33ef05b5bdae5b98fcc903fb2143fbaf0fea0f
languageName: node
linkType: hard
@@ -34907,7 +34907,7 @@ __metadata:
languageName: node
linkType: hard
"is-callable@npm:^1.1.3, is-callable@npm:^1.1.5, is-callable@npm:^1.2.7":
"is-callable@npm:^1.1.5, is-callable@npm:^1.2.7":
version: 1.2.7
resolution: "is-callable@npm:1.2.7"
checksum: 10/48a9297fb92c99e9df48706241a189da362bff3003354aea4048bd5f7b2eb0d823cd16d0a383cece3d76166ba16d85d9659165ac6fcce1ac12e6c649d66dbdb9
@@ -45108,14 +45108,16 @@ __metadata:
linkType: hard
"regexp.prototype.flags@npm:^1.5.3":
version: 1.5.3
resolution: "regexp.prototype.flags@npm:1.5.3"
version: 1.5.4
resolution: "regexp.prototype.flags@npm:1.5.4"
dependencies:
call-bind: "npm:^1.0.7"
call-bind: "npm:^1.0.8"
define-properties: "npm:^1.2.1"
es-errors: "npm:^1.3.0"
get-proto: "npm:^1.0.1"
gopd: "npm:^1.2.0"
set-function-name: "npm:^2.0.2"
checksum: 10/fe17bc4eebbc72945aaf9dd059eb7784a5ca453a67cc4b5b3e399ab08452c9a05befd92063e2c52e7b24d9238c60031656af32dd57c555d1ba6330dbf8c23b43
checksum: 10/8ab897ca445968e0b96f6237641510f3243e59c180ee2ee8d83889c52ff735dd1bf3657fcd36db053e35e1d823dd53f2565d0b8021ea282c9fe62401c6c3bd6d
languageName: node
linkType: hard
@@ -50789,16 +50791,17 @@ __metadata:
linkType: hard
"which-typed-array@npm:^1.1.16, which-typed-array@npm:^1.1.18, which-typed-array@npm:^1.1.2":
version: 1.1.18
resolution: "which-typed-array@npm:1.1.18"
version: 1.1.19
resolution: "which-typed-array@npm:1.1.19"
dependencies:
available-typed-arrays: "npm:^1.0.7"
call-bind: "npm:^1.0.8"
call-bound: "npm:^1.0.3"
for-each: "npm:^0.3.3"
call-bound: "npm:^1.0.4"
for-each: "npm:^0.3.5"
get-proto: "npm:^1.0.1"
gopd: "npm:^1.2.0"
has-tostringtag: "npm:^1.0.2"
checksum: 10/11eed801b2bd08cdbaecb17aff381e0fb03526532f61acc06e6c7b9370e08062c33763a51f27825f13fdf34aabd0df6104007f4e8f96e6eaef7db0ce17a26d6e
checksum: 10/12be30fb88567f9863186bee1777f11bea09dd59ed8b3ce4afa7dd5cade75e2f4cc56191a2da165113cc7cf79987ba021dac1e22b5b62aa7e5c56949f2469a68
languageName: node
linkType: hard