chore: make more things swoppable
Signed-off-by: benjdlambert <ben@blam.sh> Signed-off-by: benjdlambert <ben@blam.sh>
This commit is contained in:
@@ -350,34 +350,6 @@ export { bitbucketAuthApiRef };
|
||||
|
||||
export { bitbucketServerAuthApiRef };
|
||||
|
||||
// @public (undocumented)
|
||||
export type ComponentRef<
|
||||
TInnerComponentProps extends {} = {},
|
||||
TExternalComponentProps extends {} = TInnerComponentProps,
|
||||
> = {
|
||||
id: string;
|
||||
TProps: TInnerComponentProps;
|
||||
TExternalProps: TExternalComponentProps;
|
||||
$$type: '@backstage/ComponentRef';
|
||||
};
|
||||
|
||||
// @public
|
||||
export interface ComponentsApi {
|
||||
// (undocumented)
|
||||
getComponent<
|
||||
TInnerComponentProps extends {},
|
||||
TExternalComponentProps extends {} = TInnerComponentProps,
|
||||
>(
|
||||
ref: ComponentRef<TInnerComponentProps, TExternalComponentProps>,
|
||||
):
|
||||
| (() => (props: TInnerComponentProps) => JSX.Element | null)
|
||||
| (() => Promise<(props: TInnerComponentProps) => JSX.Element | null>)
|
||||
| undefined;
|
||||
}
|
||||
|
||||
// @public
|
||||
export const componentsApiRef: ApiRef<ComponentsApi>;
|
||||
|
||||
export { ConfigApi };
|
||||
|
||||
export { configApiRef };
|
||||
@@ -832,8 +804,8 @@ export function createSwappableComponent<
|
||||
TInnerComponentProps,
|
||||
TExternalComponentProps
|
||||
>,
|
||||
): ((props: TExternalComponentProps) => JSX.Element) & {
|
||||
ref: ComponentRef<TInnerComponentProps, TExternalComponentProps>;
|
||||
): ((props: TExternalComponentProps) => JSX.Element | null) & {
|
||||
ref: SwappableComponentRef<TInnerComponentProps, TExternalComponentProps>;
|
||||
};
|
||||
|
||||
// @public
|
||||
@@ -901,8 +873,8 @@ export { errorApiRef };
|
||||
// @public (undocumented)
|
||||
export const ErrorBoundary: ((
|
||||
props: CoreErrorBoundaryFallbackProps,
|
||||
) => JSX.Element) & {
|
||||
ref: ComponentRef<
|
||||
) => JSX.Element | null) & {
|
||||
ref: SwappableComponentRef<
|
||||
CoreErrorBoundaryFallbackProps,
|
||||
CoreErrorBoundaryFallbackProps
|
||||
>;
|
||||
@@ -1566,8 +1538,11 @@ export const NavItemBlueprint: ExtensionBlueprint<{
|
||||
// @public (undocumented)
|
||||
export const NotFoundErrorPage: ((
|
||||
props: CoreNotFoundErrorPageProps,
|
||||
) => JSX.Element) & {
|
||||
ref: ComponentRef<CoreNotFoundErrorPageProps, CoreNotFoundErrorPageProps>;
|
||||
) => JSX.Element | null) & {
|
||||
ref: SwappableComponentRef<
|
||||
CoreNotFoundErrorPageProps,
|
||||
CoreNotFoundErrorPageProps
|
||||
>;
|
||||
};
|
||||
|
||||
export { OAuthApi };
|
||||
@@ -1655,8 +1630,8 @@ export { ProfileInfo };
|
||||
export { ProfileInfoApi };
|
||||
|
||||
// @public (undocumented)
|
||||
export const Progress: ((props: CoreProgressProps) => JSX.Element) & {
|
||||
ref: ComponentRef<CoreProgressProps, CoreProgressProps>;
|
||||
export const Progress: ((props: CoreProgressProps) => JSX.Element | null) & {
|
||||
ref: SwappableComponentRef<CoreProgressProps, CoreProgressProps>;
|
||||
};
|
||||
|
||||
// @public
|
||||
@@ -1854,24 +1829,30 @@ export interface SubRouteRef<
|
||||
// @public
|
||||
export const SwappableComponentBlueprint: ExtensionBlueprint<{
|
||||
kind: 'component';
|
||||
params: <Ref extends ComponentRef<any>>(params: {
|
||||
component: Ref extends ComponentRef<any, infer IExternalComponentProps>
|
||||
params: <Ref extends SwappableComponentRef<any>>(params: {
|
||||
component: Ref extends SwappableComponentRef<
|
||||
any,
|
||||
infer IExternalComponentProps
|
||||
>
|
||||
? {
|
||||
ref: Ref;
|
||||
} & ((props: IExternalComponentProps) => JSX.Element)
|
||||
} & ((props: IExternalComponentProps) => JSX.Element | null)
|
||||
: never;
|
||||
loader: Ref extends ComponentRef<infer IInnerComponentProps, any>
|
||||
loader: Ref extends SwappableComponentRef<infer IInnerComponentProps, any>
|
||||
?
|
||||
| (() => (props: IInnerComponentProps) => JSX.Element | null)
|
||||
| (() => Promise<(props: IInnerComponentProps) => JSX.Element | null>)
|
||||
: never;
|
||||
}) => ExtensionBlueprintParams<{
|
||||
component: Ref extends ComponentRef<any, infer IExternalComponentProps>
|
||||
component: Ref extends SwappableComponentRef<
|
||||
any,
|
||||
infer IExternalComponentProps
|
||||
>
|
||||
? {
|
||||
ref: Ref;
|
||||
} & ((props: IExternalComponentProps) => JSX.Element)
|
||||
} & ((props: IExternalComponentProps) => JSX.Element | null)
|
||||
: never;
|
||||
loader: Ref extends ComponentRef<infer IInnerComponentProps, any>
|
||||
loader: Ref extends SwappableComponentRef<infer IInnerComponentProps, any>
|
||||
?
|
||||
| (() => (props: IInnerComponentProps) => JSX.Element | null)
|
||||
| (() => Promise<(props: IInnerComponentProps) => JSX.Element | null>)
|
||||
@@ -1879,7 +1860,7 @@ export const SwappableComponentBlueprint: ExtensionBlueprint<{
|
||||
}>;
|
||||
output: ExtensionDataRef<
|
||||
{
|
||||
ref: ComponentRef;
|
||||
ref: SwappableComponentRef;
|
||||
loader:
|
||||
| (() => (props: {}) => JSX.Element | null)
|
||||
| (() => Promise<(props: {}) => JSX.Element | null>);
|
||||
@@ -1893,7 +1874,7 @@ export const SwappableComponentBlueprint: ExtensionBlueprint<{
|
||||
dataRefs: {
|
||||
component: ConfigurableExtensionDataRef<
|
||||
{
|
||||
ref: ComponentRef;
|
||||
ref: SwappableComponentRef;
|
||||
loader:
|
||||
| (() => (props: {}) => JSX.Element | null)
|
||||
| (() => Promise<(props: {}) => JSX.Element | null>);
|
||||
@@ -1904,6 +1885,34 @@ export const SwappableComponentBlueprint: ExtensionBlueprint<{
|
||||
};
|
||||
}>;
|
||||
|
||||
// @public (undocumented)
|
||||
export type SwappableComponentRef<
|
||||
TInnerComponentProps extends {} = {},
|
||||
TExternalComponentProps extends {} = TInnerComponentProps,
|
||||
> = {
|
||||
id: string;
|
||||
TProps: TInnerComponentProps;
|
||||
TExternalProps: TExternalComponentProps;
|
||||
$$type: '@backstage/SwappableComponentRef';
|
||||
};
|
||||
|
||||
// @public
|
||||
export interface SwappableComponentsApi {
|
||||
// (undocumented)
|
||||
getComponentLoader<
|
||||
TInnerComponentProps extends {},
|
||||
TExternalComponentProps extends {} = TInnerComponentProps,
|
||||
>(
|
||||
ref: SwappableComponentRef<TInnerComponentProps, TExternalComponentProps>,
|
||||
):
|
||||
| (() => (props: TInnerComponentProps) => JSX.Element | null)
|
||||
| (() => Promise<(props: TInnerComponentProps) => JSX.Element | null>)
|
||||
| undefined;
|
||||
}
|
||||
|
||||
// @public
|
||||
export const swappableComponentsApiRef: ApiRef<SwappableComponentsApi>;
|
||||
|
||||
// @public
|
||||
export const ThemeBlueprint: ExtensionBlueprint<{
|
||||
kind: 'theme';
|
||||
|
||||
+7
-7
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ComponentRef } from '../../components';
|
||||
import { SwappableComponentRef } from '../../components';
|
||||
import { createApiRef } from '@backstage/core-plugin-api';
|
||||
|
||||
/**
|
||||
@@ -22,12 +22,12 @@ import { createApiRef } from '@backstage/core-plugin-api';
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface ComponentsApi {
|
||||
getComponent<
|
||||
export interface SwappableComponentsApi {
|
||||
getComponentLoader<
|
||||
TInnerComponentProps extends {},
|
||||
TExternalComponentProps extends {} = TInnerComponentProps,
|
||||
>(
|
||||
ref: ComponentRef<TInnerComponentProps, TExternalComponentProps>,
|
||||
ref: SwappableComponentRef<TInnerComponentProps, TExternalComponentProps>,
|
||||
):
|
||||
| (() => (props: TInnerComponentProps) => JSX.Element | null)
|
||||
| (() => Promise<(props: TInnerComponentProps) => JSX.Element | null>)
|
||||
@@ -35,10 +35,10 @@ export interface ComponentsApi {
|
||||
}
|
||||
|
||||
/**
|
||||
* The `ApiRef` of {@link ComponentsApi}.
|
||||
* The `ApiRef` of {@link SwappableComponentsApi}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const componentsApiRef = createApiRef<ComponentsApi>({
|
||||
id: 'core.components',
|
||||
export const swappableComponentsApiRef = createApiRef<SwappableComponentsApi>({
|
||||
id: 'core.swappableComponents',
|
||||
});
|
||||
@@ -34,7 +34,7 @@ export * from './auth';
|
||||
|
||||
export * from './AlertApi';
|
||||
export * from './AppThemeApi';
|
||||
export * from './ComponentsApi';
|
||||
export * from './SwappableComponentsApi';
|
||||
export * from './ConfigApi';
|
||||
export * from './DiscoveryApi';
|
||||
export * from './ErrorApi';
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { ComponentRef } from '../components';
|
||||
import { SwappableComponentRef } from '../components';
|
||||
import {
|
||||
createExtensionBlueprint,
|
||||
createExtensionBlueprintParams,
|
||||
@@ -21,14 +21,14 @@ import {
|
||||
} from '../wiring';
|
||||
|
||||
export const componentDataRef = createExtensionDataRef<{
|
||||
ref: ComponentRef;
|
||||
ref: SwappableComponentRef;
|
||||
loader:
|
||||
| (() => (props: {}) => JSX.Element | null)
|
||||
| (() => Promise<(props: {}) => JSX.Element | null>);
|
||||
}>().with({ id: 'core.component.component' });
|
||||
|
||||
/**
|
||||
* Blueprint for creating swappable components from a componentRef and a loader
|
||||
* Blueprint for creating swappable components from a SwappableComponentRef and a loader
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
@@ -39,11 +39,14 @@ export const SwappableComponentBlueprint = createExtensionBlueprint({
|
||||
dataRefs: {
|
||||
component: componentDataRef,
|
||||
},
|
||||
defineParams<Ref extends ComponentRef<any>>(params: {
|
||||
component: Ref extends ComponentRef<any, infer IExternalComponentProps>
|
||||
? { ref: Ref } & ((props: IExternalComponentProps) => JSX.Element)
|
||||
defineParams<Ref extends SwappableComponentRef<any>>(params: {
|
||||
component: Ref extends SwappableComponentRef<
|
||||
any,
|
||||
infer IExternalComponentProps
|
||||
>
|
||||
? { ref: Ref } & ((props: IExternalComponentProps) => JSX.Element | null)
|
||||
: never;
|
||||
loader: Ref extends ComponentRef<infer IInnerComponentProps, any>
|
||||
loader: Ref extends SwappableComponentRef<infer IInnerComponentProps, any>
|
||||
?
|
||||
| (() => (props: IInnerComponentProps) => JSX.Element | null)
|
||||
| (() => Promise<(props: IInnerComponentProps) => JSX.Element | null>)
|
||||
|
||||
@@ -14,19 +14,19 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { OpaqueComponentRef } from '@internal/frontend';
|
||||
import { componentsApiRef, useApi } from '../apis';
|
||||
import { OpaqueSwappableComponentRef } from '@internal/frontend';
|
||||
import { swappableComponentsApiRef, useApi } from '../apis';
|
||||
import { lazy, Suspense } from 'react';
|
||||
|
||||
/** @public */
|
||||
export type ComponentRef<
|
||||
export type SwappableComponentRef<
|
||||
TInnerComponentProps extends {} = {},
|
||||
TExternalComponentProps extends {} = TInnerComponentProps,
|
||||
> = {
|
||||
id: string;
|
||||
TProps: TInnerComponentProps;
|
||||
TExternalProps: TExternalComponentProps;
|
||||
$$type: '@backstage/ComponentRef';
|
||||
$$type: '@backstage/SwappableComponentRef';
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -47,7 +47,7 @@ export type CreateSwappableComponentOptions<
|
||||
|
||||
const useComponentRefApi = () => {
|
||||
try {
|
||||
return useApi(componentsApiRef);
|
||||
return useApi(swappableComponentsApiRef);
|
||||
} catch (e) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -59,9 +59,9 @@ function makeComponentFromRef<
|
||||
>({
|
||||
ref,
|
||||
}: {
|
||||
ref: ComponentRef<InternalComponentProps, ExternalComponentProps>;
|
||||
ref: SwappableComponentRef<InternalComponentProps, ExternalComponentProps>;
|
||||
}): (props: ExternalComponentProps) => JSX.Element {
|
||||
const internalRef = OpaqueComponentRef.toInternal(ref);
|
||||
const internalRef = OpaqueSwappableComponentRef.toInternal(ref);
|
||||
const FallbackComponent = (p: JSX.IntrinsicAttributes) => (
|
||||
<div data-testid={ref.id} {...p} />
|
||||
);
|
||||
@@ -69,7 +69,7 @@ function makeComponentFromRef<
|
||||
const ComponentRefImpl = (props: ExternalComponentProps) => {
|
||||
const api = useComponentRefApi();
|
||||
const ComponentOrPromise =
|
||||
api?.getComponent<any>(ref)?.() ??
|
||||
api?.getComponentLoader<any>(ref)?.() ??
|
||||
internalRef.loader?.() ??
|
||||
FallbackComponent;
|
||||
|
||||
@@ -108,25 +108,26 @@ export function createSwappableComponent<
|
||||
TInnerComponentProps,
|
||||
TExternalComponentProps
|
||||
>,
|
||||
): ((props: TExternalComponentProps) => JSX.Element) & {
|
||||
ref: ComponentRef<TInnerComponentProps, TExternalComponentProps>;
|
||||
): ((props: TExternalComponentProps) => JSX.Element | null) & {
|
||||
ref: SwappableComponentRef<TInnerComponentProps, TExternalComponentProps>;
|
||||
} {
|
||||
const ref = OpaqueComponentRef.createInstance('v1', {
|
||||
const ref = OpaqueSwappableComponentRef.createInstance('v1', {
|
||||
id: options.id,
|
||||
TProps: null as unknown as TInnerComponentProps,
|
||||
TExternalProps: null as unknown as TExternalComponentProps,
|
||||
toString() {
|
||||
return `ComponentRef{id=${options.id}}`;
|
||||
return `SwappableComponentRef{id=${options.id}}`;
|
||||
},
|
||||
loader: options.loader as (typeof OpaqueComponentRef.TInternal)['loader'],
|
||||
loader:
|
||||
options.loader as (typeof OpaqueSwappableComponentRef.TInternal)['loader'],
|
||||
transformProps:
|
||||
options.transformProps as (typeof OpaqueComponentRef.TInternal)['transformProps'],
|
||||
options.transformProps as (typeof OpaqueSwappableComponentRef.TInternal)['transformProps'],
|
||||
});
|
||||
|
||||
const component = makeComponentFromRef({ ref });
|
||||
Object.assign(component, { ref });
|
||||
|
||||
return component as {
|
||||
ref: ComponentRef<TInnerComponentProps, TExternalComponentProps>;
|
||||
} & ((props: object) => JSX.Element);
|
||||
ref: SwappableComponentRef<TInnerComponentProps, TExternalComponentProps>;
|
||||
} & ((props: object) => JSX.Element | null);
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ export {
|
||||
export {
|
||||
createSwappableComponent,
|
||||
type CreateSwappableComponentOptions,
|
||||
type ComponentRef,
|
||||
type SwappableComponentRef,
|
||||
} from './createSwappableComponent';
|
||||
export { useAppNode } from './AppNodeProvider';
|
||||
export * from './DefaultSwappableComponents';
|
||||
|
||||
Reference in New Issue
Block a user