@backstage/frontend-plugin-api 0.14.0-next.2 → 0.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +42 -0
- package/dist/analytics/useAnalytics.esm.js +1 -0
- package/dist/analytics/useAnalytics.esm.js.map +1 -1
- package/dist/apis/definitions/IconsApi.esm.js.map +1 -1
- package/dist/apis/definitions/PluginHeaderActionsApi.esm.js +11 -0
- package/dist/apis/definitions/PluginHeaderActionsApi.esm.js.map +1 -0
- package/dist/blueprints/PageBlueprint.esm.js +97 -9
- package/dist/blueprints/PageBlueprint.esm.js.map +1 -1
- package/dist/blueprints/PluginHeaderActionBlueprint.esm.js +52 -0
- package/dist/blueprints/PluginHeaderActionBlueprint.esm.js.map +1 -0
- package/dist/blueprints/SubPageBlueprint.esm.js +66 -0
- package/dist/blueprints/SubPageBlueprint.esm.js.map +1 -0
- package/dist/components/ExtensionBoundary.esm.js +1 -0
- package/dist/components/ExtensionBoundary.esm.js.map +1 -1
- package/dist/components/PageLayout.esm.js +99 -0
- package/dist/components/PageLayout.esm.js.map +1 -0
- package/dist/components/createSwappableComponent.esm.js +1 -0
- package/dist/components/createSwappableComponent.esm.js.map +1 -1
- package/dist/frontend-internal/src/wiring/InternalFrontendPlugin.esm.js.map +1 -1
- package/dist/index.d.ts +245 -26
- package/dist/index.esm.js +4 -0
- package/dist/index.esm.js.map +1 -1
- package/dist/routing/useRouteRef.esm.js +1 -0
- package/dist/routing/useRouteRef.esm.js.map +1 -1
- package/dist/translation/useTranslationRef.esm.js +1 -0
- package/dist/translation/useTranslationRef.esm.js.map +1 -1
- package/dist/wiring/coreExtensionData.esm.js +2 -0
- package/dist/wiring/coreExtensionData.esm.js.map +1 -1
- package/dist/wiring/createFrontendPlugin.esm.js +7 -2
- package/dist/wiring/createFrontendPlugin.esm.js.map +1 -1
- package/package.json +9 -9
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InternalFrontendPlugin.esm.js","sources":["../../../../../frontend-internal/src/wiring/InternalFrontendPlugin.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n Extension,\n FeatureFlagConfig,\n OverridableFrontendPlugin,\n} from '@backstage/frontend-plugin-api';\nimport { JsonObject } from '@backstage/types';\nimport { OpaqueType } from '@internal/opaque';\n\nexport const OpaqueFrontendPlugin = OpaqueType.create<{\n public: OverridableFrontendPlugin;\n versions: {\n readonly version: 'v1';\n readonly extensions: Extension<unknown>[];\n readonly featureFlags: FeatureFlagConfig[];\n readonly infoOptions?: {\n packageJson?: () => Promise<JsonObject>;\n manifest?: () => Promise<JsonObject>;\n };\n };\n}>({\n type: '@backstage/FrontendPlugin',\n versions: ['v1'],\n});\n"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"InternalFrontendPlugin.esm.js","sources":["../../../../../frontend-internal/src/wiring/InternalFrontendPlugin.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n Extension,\n FeatureFlagConfig,\n IconElement,\n OverridableFrontendPlugin,\n} from '@backstage/frontend-plugin-api';\nimport { JsonObject } from '@backstage/types';\nimport { OpaqueType } from '@internal/opaque';\n\nexport const OpaqueFrontendPlugin = OpaqueType.create<{\n public: OverridableFrontendPlugin;\n versions: {\n readonly version: 'v1';\n readonly title?: string;\n readonly icon?: IconElement;\n readonly extensions: Extension<unknown>[];\n readonly featureFlags: FeatureFlagConfig[];\n readonly infoOptions?: {\n packageJson?: () => Promise<JsonObject>;\n manifest?: () => Promise<JsonObject>;\n };\n };\n}>({\n type: '@backstage/FrontendPlugin',\n versions: ['v1'],\n});\n"],"names":[],"mappings":";;AAyBO,MAAM,oBAAA,GAAuB,WAAW,MAAA,CAa5C;AAAA,EACD,IAAA,EAAM,2BAAA;AAAA,EACN,QAAA,EAAU,CAAC,IAAI;AACjB,CAAC;;;;"}
|
package/dist/index.d.ts
CHANGED
|
@@ -39,6 +39,37 @@ declare const AnalyticsContext: (options: {
|
|
|
39
39
|
children: ReactNode;
|
|
40
40
|
}) => react_jsx_runtime.JSX.Element;
|
|
41
41
|
|
|
42
|
+
/**
|
|
43
|
+
* IconComponent is the common icon type used throughout Backstage when
|
|
44
|
+
* working with and rendering generic icons, including the app system icons.
|
|
45
|
+
*
|
|
46
|
+
* @remarks
|
|
47
|
+
*
|
|
48
|
+
* The type is based on SvgIcon from Material UI, but we do not want the plugin-api
|
|
49
|
+
* package to have a dependency on Material UI, nor do we want the props to be as broad
|
|
50
|
+
* as the SvgIconProps interface.
|
|
51
|
+
*
|
|
52
|
+
* If you have the need to forward additional props from SvgIconProps, you can
|
|
53
|
+
* open an issue or submit a PR to the main Backstage repo. When doing so please
|
|
54
|
+
* also describe your use-case and reasoning of the addition.
|
|
55
|
+
*
|
|
56
|
+
* @public
|
|
57
|
+
* @deprecated Use {@link IconElement} instead, passing `<MyIcon />` rather than `MyIcon`.
|
|
58
|
+
*/
|
|
59
|
+
type IconComponent = ComponentType<{
|
|
60
|
+
fontSize?: 'medium' | 'large' | 'small' | 'inherit';
|
|
61
|
+
}>;
|
|
62
|
+
/**
|
|
63
|
+
* The type used for icon elements throughout Backstage.
|
|
64
|
+
*
|
|
65
|
+
* @remarks
|
|
66
|
+
*
|
|
67
|
+
* Icons should be exactly 24x24 pixels in size.
|
|
68
|
+
*
|
|
69
|
+
* @public
|
|
70
|
+
*/
|
|
71
|
+
type IconElement = JSX$1.Element | null;
|
|
72
|
+
|
|
42
73
|
/**
|
|
43
74
|
* Catch-all type for route params.
|
|
44
75
|
*
|
|
@@ -80,6 +111,8 @@ declare function createRouteRef<TParams extends {
|
|
|
80
111
|
/** @public */
|
|
81
112
|
declare const coreExtensionData: {
|
|
82
113
|
title: _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<string, "core.title", {}>;
|
|
114
|
+
/** An icon element for the extension. Should be exactly 24x24 pixels. */
|
|
115
|
+
icon: _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<IconElement, "core.icon", {}>;
|
|
83
116
|
reactElement: _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<JSX$1.Element, "core.reactElement", {}>;
|
|
84
117
|
routePath: _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<string, "core.routing.path", {}>;
|
|
85
118
|
routeRef: _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<RouteRef<_backstage_frontend_plugin_api.AnyRouteRefParams>, "core.routing.ref", {}>;
|
|
@@ -564,7 +597,15 @@ interface OverridableFrontendPlugin<TRoutes extends {
|
|
|
564
597
|
}> extends FrontendPlugin<TRoutes, TExternalRoutes> {
|
|
565
598
|
getExtension<TId extends keyof TExtensionMap>(id: TId): OverridableExtensionDefinition<TExtensionMap[TId]['T']>;
|
|
566
599
|
withOverrides(options: {
|
|
567
|
-
extensions
|
|
600
|
+
extensions?: Array<ExtensionDefinition>;
|
|
601
|
+
/**
|
|
602
|
+
* Overrides the display title of the plugin.
|
|
603
|
+
*/
|
|
604
|
+
title?: string;
|
|
605
|
+
/**
|
|
606
|
+
* Overrides the display icon of the plugin.
|
|
607
|
+
*/
|
|
608
|
+
icon?: IconElement;
|
|
568
609
|
/**
|
|
569
610
|
* Overrides the original info loaders of the plugin one by one.
|
|
570
611
|
*/
|
|
@@ -592,6 +633,15 @@ interface FrontendPlugin<TRoutes extends {
|
|
|
592
633
|
* @deprecated Use `pluginId` instead.
|
|
593
634
|
*/
|
|
594
635
|
readonly id: string;
|
|
636
|
+
/**
|
|
637
|
+
* The display title of the plugin, used in page headers and navigation.
|
|
638
|
+
* Falls back to the plugin ID if not provided.
|
|
639
|
+
*/
|
|
640
|
+
readonly title?: string;
|
|
641
|
+
/**
|
|
642
|
+
* The display icon of the plugin, used in page headers and navigation.
|
|
643
|
+
*/
|
|
644
|
+
readonly icon?: IconElement;
|
|
595
645
|
readonly routes: TRoutes;
|
|
596
646
|
readonly externalRoutes: TExternalRoutes;
|
|
597
647
|
/**
|
|
@@ -606,6 +656,15 @@ interface PluginOptions<TId extends string, TRoutes extends {
|
|
|
606
656
|
[name in string]: ExternalRouteRef;
|
|
607
657
|
}, TExtensions extends readonly ExtensionDefinition[]> {
|
|
608
658
|
pluginId: TId;
|
|
659
|
+
/**
|
|
660
|
+
* The display title of the plugin, used in page headers and navigation.
|
|
661
|
+
* Falls back to the plugin ID if not provided.
|
|
662
|
+
*/
|
|
663
|
+
title?: string;
|
|
664
|
+
/**
|
|
665
|
+
* The display icon of the plugin, used in page headers and navigation.
|
|
666
|
+
*/
|
|
667
|
+
icon?: IconElement;
|
|
609
668
|
routes?: TRoutes;
|
|
610
669
|
externalRoutes?: TExternalRoutes;
|
|
611
670
|
extensions?: TExtensions;
|
|
@@ -670,7 +729,9 @@ type ExtensionFactoryMiddleware = (originalFactory: (contextOverrides?: {
|
|
|
670
729
|
config?: JsonObject;
|
|
671
730
|
}) => Iterable<ExtensionDataValue<any, any>>;
|
|
672
731
|
/** @public */
|
|
673
|
-
type FrontendFeature = FrontendPlugin
|
|
732
|
+
type FrontendFeature = (Omit<FrontendPlugin, 'pluginId'> & {
|
|
733
|
+
pluginId?: string;
|
|
734
|
+
}) | FrontendModule;
|
|
674
735
|
|
|
675
736
|
/**
|
|
676
737
|
* A function used to define a parameter mapping function in order to facilitate
|
|
@@ -1406,26 +1467,6 @@ declare function createApiFactory<Api, Impl extends Api, Deps extends {
|
|
|
1406
1467
|
*/
|
|
1407
1468
|
declare function createApiFactory<Api, Impl extends Api>(api: ApiRef<Api>, instance: Impl): ApiFactory<Api, Impl, {}>;
|
|
1408
1469
|
|
|
1409
|
-
/**
|
|
1410
|
-
* IconComponent is the common icon type used throughout Backstage when
|
|
1411
|
-
* working with and rendering generic icons, including the app system icons.
|
|
1412
|
-
*
|
|
1413
|
-
* @remarks
|
|
1414
|
-
*
|
|
1415
|
-
* The type is based on SvgIcon from Material UI, but we do not want the plugin-api
|
|
1416
|
-
* package to have a dependency on Material UI, nor do we want the props to be as broad
|
|
1417
|
-
* as the SvgIconProps interface.
|
|
1418
|
-
*
|
|
1419
|
-
* If you have the need to forward additional props from SvgIconProps, you can
|
|
1420
|
-
* open an issue or submit a PR to the main Backstage repo. When doing so please
|
|
1421
|
-
* also describe your use-case and reasoning of the addition.
|
|
1422
|
-
*
|
|
1423
|
-
* @public
|
|
1424
|
-
*/
|
|
1425
|
-
type IconComponent = ComponentType<{
|
|
1426
|
-
fontSize?: 'medium' | 'large' | 'small' | 'inherit';
|
|
1427
|
-
}>;
|
|
1428
|
-
|
|
1429
1470
|
/**
|
|
1430
1471
|
* This file contains declarations for common interfaces of auth-related APIs.
|
|
1431
1472
|
* The declarations should be used to signal which type of authentication and
|
|
@@ -2003,6 +2044,40 @@ declare const ErrorDisplay: {
|
|
|
2003
2044
|
ref: _backstage_frontend_plugin_api.SwappableComponentRef<ErrorDisplayProps, ErrorDisplayProps>;
|
|
2004
2045
|
};
|
|
2005
2046
|
|
|
2047
|
+
/**
|
|
2048
|
+
* Tab configuration for page navigation
|
|
2049
|
+
* @public
|
|
2050
|
+
*/
|
|
2051
|
+
interface PageTab {
|
|
2052
|
+
id: string;
|
|
2053
|
+
label: string;
|
|
2054
|
+
icon?: IconElement;
|
|
2055
|
+
href: string;
|
|
2056
|
+
}
|
|
2057
|
+
/**
|
|
2058
|
+
* Props for the PageLayout component
|
|
2059
|
+
* @public
|
|
2060
|
+
*/
|
|
2061
|
+
interface PageLayoutProps {
|
|
2062
|
+
title?: string;
|
|
2063
|
+
icon?: IconElement;
|
|
2064
|
+
noHeader?: boolean;
|
|
2065
|
+
headerActions?: Array<JSX.Element | null>;
|
|
2066
|
+
tabs?: PageTab[];
|
|
2067
|
+
children?: ReactNode;
|
|
2068
|
+
}
|
|
2069
|
+
/**
|
|
2070
|
+
* Swappable component for laying out page content with header and navigation.
|
|
2071
|
+
* The default implementation uses plain HTML elements.
|
|
2072
|
+
* Apps can override this with a custom implementation (e.g., using \@backstage/ui).
|
|
2073
|
+
*
|
|
2074
|
+
* @public
|
|
2075
|
+
*/
|
|
2076
|
+
declare const PageLayout: {
|
|
2077
|
+
(props: PageLayoutProps): JSX.Element | null;
|
|
2078
|
+
ref: _backstage_frontend_plugin_api.SwappableComponentRef<PageLayoutProps, PageLayoutProps>;
|
|
2079
|
+
};
|
|
2080
|
+
|
|
2006
2081
|
/**
|
|
2007
2082
|
* API for looking up components based on component refs.
|
|
2008
2083
|
*
|
|
@@ -2266,6 +2341,13 @@ declare const fetchApiRef: ApiRef<FetchApi>;
|
|
|
2266
2341
|
* @public
|
|
2267
2342
|
*/
|
|
2268
2343
|
interface IconsApi {
|
|
2344
|
+
/**
|
|
2345
|
+
* Look up an icon element by key.
|
|
2346
|
+
*/
|
|
2347
|
+
icon(key: string): IconElement | undefined;
|
|
2348
|
+
/**
|
|
2349
|
+
* @deprecated Use {@link IconsApi.icon} instead.
|
|
2350
|
+
*/
|
|
2269
2351
|
getIcon(key: string): IconComponent | undefined;
|
|
2270
2352
|
listIconKeys(): string[];
|
|
2271
2353
|
}
|
|
@@ -3168,6 +3250,30 @@ type TranslationApi = {
|
|
|
3168
3250
|
*/
|
|
3169
3251
|
declare const translationApiRef: ApiRef<TranslationApi>;
|
|
3170
3252
|
|
|
3253
|
+
/**
|
|
3254
|
+
* API for retrieving plugin-scoped header actions.
|
|
3255
|
+
*
|
|
3256
|
+
* @remarks
|
|
3257
|
+
*
|
|
3258
|
+
* Header actions are provided via
|
|
3259
|
+
* {@link @backstage/frontend-plugin-api#PluginHeaderActionBlueprint}
|
|
3260
|
+
* and automatically scoped to the providing plugin.
|
|
3261
|
+
*
|
|
3262
|
+
* @public
|
|
3263
|
+
*/
|
|
3264
|
+
type PluginHeaderActionsApi = {
|
|
3265
|
+
/**
|
|
3266
|
+
* Returns the header actions for a given plugin.
|
|
3267
|
+
*/
|
|
3268
|
+
getPluginHeaderActions(pluginId: string): Array<JSX$1.Element | null>;
|
|
3269
|
+
};
|
|
3270
|
+
/**
|
|
3271
|
+
* The `ApiRef` of {@link PluginHeaderActionsApi}.
|
|
3272
|
+
*
|
|
3273
|
+
* @public
|
|
3274
|
+
*/
|
|
3275
|
+
declare const pluginHeaderActionsApiRef: _backstage_frontend_plugin_api.ApiRef<PluginHeaderActionsApi>;
|
|
3276
|
+
|
|
3171
3277
|
/**
|
|
3172
3278
|
* Gets a pre-configured analytics tracker.
|
|
3173
3279
|
*
|
|
@@ -3264,7 +3370,7 @@ declare const NavItemBlueprint: _backstage_frontend_plugin_api.ExtensionBlueprin
|
|
|
3264
3370
|
}>;
|
|
3265
3371
|
|
|
3266
3372
|
/**
|
|
3267
|
-
*
|
|
3373
|
+
* Creates extensions that are routable React page components.
|
|
3268
3374
|
*
|
|
3269
3375
|
* @public
|
|
3270
3376
|
*/
|
|
@@ -3276,21 +3382,134 @@ declare const PageBlueprint: _backstage_frontend_plugin_api.ExtensionBlueprint<{
|
|
|
3276
3382
|
*/
|
|
3277
3383
|
defaultPath?: [Error: `Use the 'path' param instead`];
|
|
3278
3384
|
path: string;
|
|
3385
|
+
title?: string;
|
|
3386
|
+
icon?: IconElement;
|
|
3387
|
+
loader?: () => Promise<JSX$1.Element>;
|
|
3388
|
+
routeRef?: RouteRef;
|
|
3389
|
+
/**
|
|
3390
|
+
* Hide the default plugin page header, making the page fill up all available space.
|
|
3391
|
+
*/
|
|
3392
|
+
noHeader?: boolean;
|
|
3393
|
+
};
|
|
3394
|
+
output: _backstage_frontend_plugin_api.ExtensionDataRef<string, "core.routing.path", {}> | _backstage_frontend_plugin_api.ExtensionDataRef<RouteRef<_backstage_frontend_plugin_api.AnyRouteRefParams>, "core.routing.ref", {
|
|
3395
|
+
optional: true;
|
|
3396
|
+
}> | _backstage_frontend_plugin_api.ExtensionDataRef<JSX$1.Element, "core.reactElement", {}> | _backstage_frontend_plugin_api.ExtensionDataRef<string, "core.title", {
|
|
3397
|
+
optional: true;
|
|
3398
|
+
}> | _backstage_frontend_plugin_api.ExtensionDataRef<IconElement, "core.icon", {
|
|
3399
|
+
optional: true;
|
|
3400
|
+
}>;
|
|
3401
|
+
inputs: {
|
|
3402
|
+
pages: _backstage_frontend_plugin_api.ExtensionInput<_backstage_frontend_plugin_api.ConfigurableExtensionDataRef<JSX$1.Element, "core.reactElement", {}> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<string, "core.routing.path", {}> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<RouteRef<_backstage_frontend_plugin_api.AnyRouteRefParams>, "core.routing.ref", {
|
|
3403
|
+
optional: true;
|
|
3404
|
+
}> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<string, "core.title", {
|
|
3405
|
+
optional: true;
|
|
3406
|
+
}> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<IconElement, "core.icon", {
|
|
3407
|
+
optional: true;
|
|
3408
|
+
}>, {
|
|
3409
|
+
singleton: false;
|
|
3410
|
+
optional: false;
|
|
3411
|
+
internal: false;
|
|
3412
|
+
}>;
|
|
3413
|
+
};
|
|
3414
|
+
config: {
|
|
3415
|
+
path: string | undefined;
|
|
3416
|
+
title: string | undefined;
|
|
3417
|
+
};
|
|
3418
|
+
configInput: {
|
|
3419
|
+
title?: string | undefined;
|
|
3420
|
+
path?: string | undefined;
|
|
3421
|
+
};
|
|
3422
|
+
dataRefs: never;
|
|
3423
|
+
}>;
|
|
3424
|
+
|
|
3425
|
+
/**
|
|
3426
|
+
* Creates extensions that are sub-page React components attached to a parent page.
|
|
3427
|
+
* Sub-pages are rendered as tabs within the parent page's header.
|
|
3428
|
+
*
|
|
3429
|
+
* @public
|
|
3430
|
+
* @example
|
|
3431
|
+
* ```tsx
|
|
3432
|
+
* const overviewRouteRef = createRouteRef();
|
|
3433
|
+
*
|
|
3434
|
+
* const mySubPage = SubPageBlueprint.make({
|
|
3435
|
+
* attachTo: { id: 'page:my-plugin', input: 'pages' },
|
|
3436
|
+
* name: 'overview',
|
|
3437
|
+
* params: {
|
|
3438
|
+
* path: 'overview',
|
|
3439
|
+
* title: 'Overview',
|
|
3440
|
+
* routeRef: overviewRouteRef,
|
|
3441
|
+
* loader: () => import('./components/Overview').then(m => <m.Overview />),
|
|
3442
|
+
* },
|
|
3443
|
+
* });
|
|
3444
|
+
* ```
|
|
3445
|
+
*/
|
|
3446
|
+
declare const SubPageBlueprint: _backstage_frontend_plugin_api.ExtensionBlueprint<{
|
|
3447
|
+
kind: "sub-page";
|
|
3448
|
+
params: {
|
|
3449
|
+
/**
|
|
3450
|
+
* The path for this sub-page, relative to the parent page. Must **not** start with '/'.
|
|
3451
|
+
*
|
|
3452
|
+
* @example 'overview', 'settings', 'details'
|
|
3453
|
+
*/
|
|
3454
|
+
path: string;
|
|
3455
|
+
/**
|
|
3456
|
+
* The title displayed in the tab for this sub-page.
|
|
3457
|
+
*/
|
|
3458
|
+
title: string;
|
|
3459
|
+
/**
|
|
3460
|
+
* Optional icon for this sub-page, displayed in the tab.
|
|
3461
|
+
*/
|
|
3462
|
+
icon?: IconElement;
|
|
3463
|
+
/**
|
|
3464
|
+
* A function that returns a promise resolving to the React element to render.
|
|
3465
|
+
* This enables lazy loading of the sub-page content.
|
|
3466
|
+
*/
|
|
3279
3467
|
loader: () => Promise<JSX.Element>;
|
|
3468
|
+
/**
|
|
3469
|
+
* Optional route reference for this sub-page.
|
|
3470
|
+
*/
|
|
3280
3471
|
routeRef?: RouteRef;
|
|
3281
3472
|
};
|
|
3282
|
-
output: _backstage_frontend_plugin_api.ExtensionDataRef<string, "core.routing.path", {}> | _backstage_frontend_plugin_api.ExtensionDataRef<
|
|
3473
|
+
output: _backstage_frontend_plugin_api.ExtensionDataRef<string, "core.routing.path", {}> | _backstage_frontend_plugin_api.ExtensionDataRef<RouteRef<_backstage_frontend_plugin_api.AnyRouteRefParams>, "core.routing.ref", {
|
|
3474
|
+
optional: true;
|
|
3475
|
+
}> | _backstage_frontend_plugin_api.ExtensionDataRef<react.JSX.Element, "core.reactElement", {}> | _backstage_frontend_plugin_api.ExtensionDataRef<string, "core.title", {}> | _backstage_frontend_plugin_api.ExtensionDataRef<IconElement, "core.icon", {
|
|
3283
3476
|
optional: true;
|
|
3284
3477
|
}>;
|
|
3285
3478
|
inputs: {};
|
|
3286
3479
|
config: {
|
|
3287
3480
|
path: string | undefined;
|
|
3481
|
+
title: string | undefined;
|
|
3288
3482
|
};
|
|
3289
3483
|
configInput: {
|
|
3484
|
+
title?: string | undefined;
|
|
3290
3485
|
path?: string | undefined;
|
|
3291
3486
|
};
|
|
3292
3487
|
dataRefs: never;
|
|
3293
3488
|
}>;
|
|
3294
3489
|
|
|
3295
|
-
|
|
3296
|
-
|
|
3490
|
+
/**
|
|
3491
|
+
* Creates extensions that provide plugin-scoped header actions.
|
|
3492
|
+
*
|
|
3493
|
+
* @remarks
|
|
3494
|
+
*
|
|
3495
|
+
* These actions are automatically scoped to the plugin that provides them
|
|
3496
|
+
* and will appear in the header of all pages belonging to that plugin.
|
|
3497
|
+
*
|
|
3498
|
+
* @public
|
|
3499
|
+
*/
|
|
3500
|
+
declare const PluginHeaderActionBlueprint: _backstage_frontend_plugin_api.ExtensionBlueprint<{
|
|
3501
|
+
kind: "plugin-header-action";
|
|
3502
|
+
params: (params: {
|
|
3503
|
+
loader: () => Promise<JSX.Element>;
|
|
3504
|
+
}) => _backstage_frontend_plugin_api.ExtensionBlueprintParams<{
|
|
3505
|
+
loader: () => Promise<JSX.Element>;
|
|
3506
|
+
}>;
|
|
3507
|
+
output: _backstage_frontend_plugin_api.ExtensionDataRef<react.JSX.Element, "core.reactElement", {}>;
|
|
3508
|
+
inputs: {};
|
|
3509
|
+
config: {};
|
|
3510
|
+
configInput: {};
|
|
3511
|
+
dataRefs: never;
|
|
3512
|
+
}>;
|
|
3513
|
+
|
|
3514
|
+
export { AnalyticsContext, AnalyticsImplementationBlueprint, ApiBlueprint, AppRootElementBlueprint, ErrorDisplay, ExtensionBoundary, FeatureFlagState, NavItemBlueprint, NotFoundErrorPage, PageBlueprint, PageLayout, PluginHeaderActionBlueprint, Progress, SessionState, SubPageBlueprint, alertApiRef, analyticsApiRef, appLanguageApiRef, appThemeApiRef, appTreeApiRef, atlassianAuthApiRef, bitbucketAuthApiRef, bitbucketServerAuthApiRef, configApiRef, coreExtensionData, createApiFactory, createApiRef, createExtension, createExtensionBlueprint, createExtensionBlueprintParams, createExtensionDataRef, createExtensionInput, createExternalRouteRef, createFrontendFeatureLoader, createFrontendModule, createFrontendPlugin, createRouteRef, createSubRouteRef, createSwappableComponent, createTranslationMessages, createTranslationRef, createTranslationResource, dialogApiRef, discoveryApiRef, errorApiRef, featureFlagsApiRef, fetchApiRef, githubAuthApiRef, gitlabAuthApiRef, googleAuthApiRef, iconsApiRef, identityApiRef, microsoftAuthApiRef, oauthRequestApiRef, oktaAuthApiRef, oneloginAuthApiRef, openshiftAuthApiRef, pluginHeaderActionsApiRef, routeResolutionApiRef, storageApiRef, swappableComponentsApiRef, translationApiRef, useAnalytics, useApi, useApiHolder, useAppNode, useRouteRef, useRouteRefParams, useTranslationRef, vmwareCloudAuthApiRef, withApis };
|
|
3515
|
+
export type { AlertApi, AlertMessage, AnalyticsApi, AnalyticsContextValue, AnalyticsEvent, AnalyticsEventAttributes, AnalyticsImplementation, AnalyticsImplementationFactory, AnalyticsTracker, AnyApiFactory, AnyApiRef, AnyExtensionDataRef, AnyRouteRefParams, ApiFactory, ApiHolder, ApiRef, ApiRefConfig, AppLanguageApi, AppNode, AppNodeEdges, AppNodeInstance, AppNodeSpec, AppTheme, AppThemeApi, AppTree, AppTreeApi, AuthProviderInfo, AuthRequestOptions, BackstageIdentityApi, BackstageIdentityResponse, BackstageUserIdentity, ConfigApi, ConfigurableExtensionDataRef, CreateExtensionBlueprintOptions, CreateExtensionOptions, CreateFrontendFeatureLoaderOptions, CreateFrontendModuleOptions, CreateSwappableComponentOptions, DialogApi, DialogApiDialog, DiscoveryApi, ErrorApi, ErrorApiError, ErrorApiErrorContext, ErrorDisplayProps, Extension, ExtensionAttachTo, ExtensionAttachToSpec, ExtensionBlueprint, ExtensionBlueprintDefineParams, ExtensionBlueprintParameters, ExtensionBlueprintParams, ExtensionBoundaryProps, ExtensionDataContainer, ExtensionDataRef, ExtensionDataRefToValue, ExtensionDataValue, ExtensionDefinition, ExtensionDefinitionAttachTo, ExtensionDefinitionParameters, ExtensionFactoryMiddleware, ExtensionInput, ExternalRouteRef, FeatureFlag, FeatureFlagConfig, FeatureFlagsApi, FeatureFlagsSaveOptions, FetchApi, FrontendFeature, FrontendFeatureLoader, FrontendModule, FrontendPlugin, FrontendPluginInfo, FrontendPluginInfoOptions, IconComponent, IconElement, IconsApi, IdentityApi, NotFoundErrorPageProps, OAuthApi, OAuthRequestApi, OAuthRequester, OAuthRequesterOptions, OAuthScope, OpenIdConnectApi, OverridableExtensionDefinition, OverridableFrontendPlugin, PageLayoutProps, PageTab, PendingOAuthRequest, PluginHeaderActionsApi, PluginOptions, PortableSchema, ProfileInfo, ProfileInfoApi, ProgressProps, ResolvedExtensionInput, ResolvedExtensionInputs, RouteFunc, RouteRef, RouteResolutionApi, SessionApi, StorageApi, StorageValueSnapshot, SubRouteRef, SwappableComponentRef, SwappableComponentsApi, TranslationApi, TranslationFunction, TranslationMessages, TranslationMessagesOptions, TranslationRef, TranslationRefOptions, TranslationResource, TranslationResourceOptions, TranslationSnapshot, TypesToApiRefs };
|
package/dist/index.esm.js
CHANGED
|
@@ -19,6 +19,7 @@ export { routeResolutionApiRef } from './apis/definitions/RouteResolutionApi.esm
|
|
|
19
19
|
export { storageApiRef } from './apis/definitions/StorageApi.esm.js';
|
|
20
20
|
export { analyticsApiRef } from './apis/definitions/AnalyticsApi.esm.js';
|
|
21
21
|
export { translationApiRef } from './apis/definitions/TranslationApi.esm.js';
|
|
22
|
+
export { pluginHeaderActionsApiRef } from './apis/definitions/PluginHeaderActionsApi.esm.js';
|
|
22
23
|
export { useApi, useApiHolder, withApis } from './apis/system/useApi.esm.js';
|
|
23
24
|
export { createApiRef } from './apis/system/ApiRef.esm.js';
|
|
24
25
|
export { createApiFactory } from './apis/system/helpers.esm.js';
|
|
@@ -27,10 +28,13 @@ export { ApiBlueprint } from './blueprints/ApiBlueprint.esm.js';
|
|
|
27
28
|
export { AppRootElementBlueprint } from './blueprints/AppRootElementBlueprint.esm.js';
|
|
28
29
|
export { NavItemBlueprint } from './blueprints/NavItemBlueprint.esm.js';
|
|
29
30
|
export { PageBlueprint } from './blueprints/PageBlueprint.esm.js';
|
|
31
|
+
export { SubPageBlueprint } from './blueprints/SubPageBlueprint.esm.js';
|
|
32
|
+
export { PluginHeaderActionBlueprint } from './blueprints/PluginHeaderActionBlueprint.esm.js';
|
|
30
33
|
export { ExtensionBoundary } from './components/ExtensionBoundary.esm.js';
|
|
31
34
|
export { createSwappableComponent } from './components/createSwappableComponent.esm.js';
|
|
32
35
|
export { useAppNode } from './components/AppNodeProvider.esm.js';
|
|
33
36
|
export { ErrorDisplay, NotFoundErrorPage, Progress } from './components/DefaultSwappableComponents.esm.js';
|
|
37
|
+
export { PageLayout } from './components/PageLayout.esm.js';
|
|
34
38
|
export { createRouteRef } from './routing/RouteRef.esm.js';
|
|
35
39
|
export { createSubRouteRef } from './routing/SubRouteRef.esm.js';
|
|
36
40
|
export { createExternalRouteRef } from './routing/ExternalRouteRef.esm.js';
|
package/dist/index.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -19,6 +19,7 @@ import { routeResolutionApiRef } from '../apis/definitions/RouteResolutionApi.es
|
|
|
19
19
|
import '../apis/definitions/StorageApi.esm.js';
|
|
20
20
|
import '../apis/definitions/AnalyticsApi.esm.js';
|
|
21
21
|
import '../apis/definitions/TranslationApi.esm.js';
|
|
22
|
+
import '../apis/definitions/PluginHeaderActionsApi.esm.js';
|
|
22
23
|
import { useApi } from '../apis/system/useApi.esm.js';
|
|
23
24
|
|
|
24
25
|
function useRouteRef(routeRef) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useRouteRef.esm.js","sources":["../../src/routing/useRouteRef.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useMemo } from 'react';\nimport { useLocation } from 'react-router-dom';\nimport { AnyRouteRefParams } from './types';\nimport { RouteRef } from './RouteRef';\nimport { SubRouteRef } from './SubRouteRef';\nimport { ExternalRouteRef } from './ExternalRouteRef';\nimport { RouteFunc, routeResolutionApiRef, useApi } from '../apis';\n\n/**\n * React hook for constructing URLs to routes.\n *\n * @remarks\n *\n * See {@link https://backstage.io/docs/plugins/composability#routing-system}\n *\n * @param routeRef - The ref to route that should be converted to URL.\n * @returns A function that will in turn return the concrete URL of the `routeRef`, or `undefined` if the route is not available.\n * @public\n */\nexport function useRouteRef<TParams extends AnyRouteRefParams>(\n routeRef:\n | RouteRef<TParams>\n | SubRouteRef<TParams>\n | ExternalRouteRef<TParams>,\n): RouteFunc<TParams> | undefined {\n const { pathname } = useLocation();\n const routeResolutionApi = useApi(routeResolutionApiRef);\n\n const routeFunc = useMemo(\n () => routeResolutionApi.resolve(routeRef, { sourcePath: pathname }),\n [routeResolutionApi, routeRef, pathname],\n );\n\n return routeFunc;\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useRouteRef.esm.js","sources":["../../src/routing/useRouteRef.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useMemo } from 'react';\nimport { useLocation } from 'react-router-dom';\nimport { AnyRouteRefParams } from './types';\nimport { RouteRef } from './RouteRef';\nimport { SubRouteRef } from './SubRouteRef';\nimport { ExternalRouteRef } from './ExternalRouteRef';\nimport { RouteFunc, routeResolutionApiRef, useApi } from '../apis';\n\n/**\n * React hook for constructing URLs to routes.\n *\n * @remarks\n *\n * See {@link https://backstage.io/docs/plugins/composability#routing-system}\n *\n * @param routeRef - The ref to route that should be converted to URL.\n * @returns A function that will in turn return the concrete URL of the `routeRef`, or `undefined` if the route is not available.\n * @public\n */\nexport function useRouteRef<TParams extends AnyRouteRefParams>(\n routeRef:\n | RouteRef<TParams>\n | SubRouteRef<TParams>\n | ExternalRouteRef<TParams>,\n): RouteFunc<TParams> | undefined {\n const { pathname } = useLocation();\n const routeResolutionApi = useApi(routeResolutionApiRef);\n\n const routeFunc = useMemo(\n () => routeResolutionApi.resolve(routeRef, { sourcePath: pathname }),\n [routeResolutionApi, routeRef, pathname],\n );\n\n return routeFunc;\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAmCO,SAAS,YACd,QAAA,EAIgC;AAChC,EAAA,MAAM,EAAE,QAAA,EAAS,GAAI,WAAA,EAAY;AACjC,EAAA,MAAM,kBAAA,GAAqB,OAAO,qBAAqB,CAAA;AAEvD,EAAA,MAAM,SAAA,GAAY,OAAA;AAAA,IAChB,MAAM,kBAAA,CAAmB,OAAA,CAAQ,UAAU,EAAE,UAAA,EAAY,UAAU,CAAA;AAAA,IACnE,CAAC,kBAAA,EAAoB,QAAA,EAAU,QAAQ;AAAA,GACzC;AAEA,EAAA,OAAO,SAAA;AACT;;;;"}
|
|
@@ -18,6 +18,7 @@ import '../apis/definitions/RouteResolutionApi.esm.js';
|
|
|
18
18
|
import '../apis/definitions/StorageApi.esm.js';
|
|
19
19
|
import '../apis/definitions/AnalyticsApi.esm.js';
|
|
20
20
|
import { translationApiRef } from '../apis/definitions/TranslationApi.esm.js';
|
|
21
|
+
import '../apis/definitions/PluginHeaderActionsApi.esm.js';
|
|
21
22
|
import { useApi } from '../apis/system/useApi.esm.js';
|
|
22
23
|
|
|
23
24
|
const loggedRefs = /* @__PURE__ */ new WeakSet();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useTranslationRef.esm.js","sources":["../../src/translation/useTranslationRef.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { errorApiRef, useApi } from '../apis';\nimport {\n translationApiRef,\n TranslationFunction,\n TranslationSnapshot,\n} from '../apis/definitions/TranslationApi';\nimport { TranslationRef } from './TranslationRef';\n\n// Make sure we don't fill the logs with loading errors for the same ref\nconst loggedRefs = new WeakSet<TranslationRef<string, {}>>();\n\n/** @public */\nexport const useTranslationRef = <\n TMessages extends { [key in string]: string },\n>(\n translationRef: TranslationRef<string, TMessages>,\n): { t: TranslationFunction<TMessages> } => {\n const errorApi = useApi(errorApiRef);\n const translationApi = useApi(translationApiRef);\n\n const [snapshot, setSnapshot] = useState<TranslationSnapshot<TMessages>>(() =>\n translationApi.getTranslation(translationRef),\n );\n const observable = useMemo(\n () => translationApi.translation$(translationRef),\n [translationApi, translationRef],\n );\n\n const onError = useCallback(\n (error: Error) => {\n if (!loggedRefs.has(translationRef)) {\n const errMsg = `Failed to load translation resource '${translationRef.id}'; caused by ${error}`;\n // eslint-disable-next-line no-console\n console.error(errMsg);\n errorApi.post(new Error(errMsg));\n loggedRefs.add(translationRef);\n }\n },\n [errorApi, translationRef],\n );\n\n useEffect(() => {\n const subscription = observable.subscribe({\n next(next) {\n if (next.ready) {\n setSnapshot(next);\n }\n },\n error(error) {\n onError(error);\n },\n });\n\n return () => {\n subscription.unsubscribe();\n };\n }, [observable, onError]);\n\n // Keep track of if the provided translation ref changes, and in that case update the snapshot\n const initialRenderRef = useRef(true);\n useEffect(() => {\n if (initialRenderRef.current) {\n initialRenderRef.current = false;\n } else {\n setSnapshot(translationApi.getTranslation(translationRef));\n }\n }, [translationApi, translationRef]);\n\n if (!snapshot.ready) {\n throw new Promise<void>(resolve => {\n const subscription = observable.subscribe({\n next(next) {\n if (next.ready) {\n subscription.unsubscribe();\n resolve();\n }\n },\n error(error) {\n subscription.unsubscribe();\n onError(error);\n resolve();\n },\n });\n });\n }\n\n return { t: snapshot.t };\n};\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useTranslationRef.esm.js","sources":["../../src/translation/useTranslationRef.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { errorApiRef, useApi } from '../apis';\nimport {\n translationApiRef,\n TranslationFunction,\n TranslationSnapshot,\n} from '../apis/definitions/TranslationApi';\nimport { TranslationRef } from './TranslationRef';\n\n// Make sure we don't fill the logs with loading errors for the same ref\nconst loggedRefs = new WeakSet<TranslationRef<string, {}>>();\n\n/** @public */\nexport const useTranslationRef = <\n TMessages extends { [key in string]: string },\n>(\n translationRef: TranslationRef<string, TMessages>,\n): { t: TranslationFunction<TMessages> } => {\n const errorApi = useApi(errorApiRef);\n const translationApi = useApi(translationApiRef);\n\n const [snapshot, setSnapshot] = useState<TranslationSnapshot<TMessages>>(() =>\n translationApi.getTranslation(translationRef),\n );\n const observable = useMemo(\n () => translationApi.translation$(translationRef),\n [translationApi, translationRef],\n );\n\n const onError = useCallback(\n (error: Error) => {\n if (!loggedRefs.has(translationRef)) {\n const errMsg = `Failed to load translation resource '${translationRef.id}'; caused by ${error}`;\n // eslint-disable-next-line no-console\n console.error(errMsg);\n errorApi.post(new Error(errMsg));\n loggedRefs.add(translationRef);\n }\n },\n [errorApi, translationRef],\n );\n\n useEffect(() => {\n const subscription = observable.subscribe({\n next(next) {\n if (next.ready) {\n setSnapshot(next);\n }\n },\n error(error) {\n onError(error);\n },\n });\n\n return () => {\n subscription.unsubscribe();\n };\n }, [observable, onError]);\n\n // Keep track of if the provided translation ref changes, and in that case update the snapshot\n const initialRenderRef = useRef(true);\n useEffect(() => {\n if (initialRenderRef.current) {\n initialRenderRef.current = false;\n } else {\n setSnapshot(translationApi.getTranslation(translationRef));\n }\n }, [translationApi, translationRef]);\n\n if (!snapshot.ready) {\n throw new Promise<void>(resolve => {\n const subscription = observable.subscribe({\n next(next) {\n if (next.ready) {\n subscription.unsubscribe();\n resolve();\n }\n },\n error(error) {\n subscription.unsubscribe();\n onError(error);\n resolve();\n },\n });\n });\n }\n\n return { t: snapshot.t };\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AA0BA,MAAM,UAAA,uBAAiB,OAAA,EAAoC;AAGpD,MAAM,iBAAA,GAAoB,CAG/B,cAAA,KAC0C;AAC1C,EAAA,MAAM,QAAA,GAAW,OAAO,WAAW,CAAA;AACnC,EAAA,MAAM,cAAA,GAAiB,OAAO,iBAAiB,CAAA;AAE/C,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAI,QAAA;AAAA,IAAyC,MACvE,cAAA,CAAe,cAAA,CAAe,cAAc;AAAA,GAC9C;AACA,EAAA,MAAM,UAAA,GAAa,OAAA;AAAA,IACjB,MAAM,cAAA,CAAe,YAAA,CAAa,cAAc,CAAA;AAAA,IAChD,CAAC,gBAAgB,cAAc;AAAA,GACjC;AAEA,EAAA,MAAM,OAAA,GAAU,WAAA;AAAA,IACd,CAAC,KAAA,KAAiB;AAChB,MAAA,IAAI,CAAC,UAAA,CAAW,GAAA,CAAI,cAAc,CAAA,EAAG;AACnC,QAAA,MAAM,MAAA,GAAS,CAAA,qCAAA,EAAwC,cAAA,CAAe,EAAE,gBAAgB,KAAK,CAAA,CAAA;AAE7F,QAAA,OAAA,CAAQ,MAAM,MAAM,CAAA;AACpB,QAAA,QAAA,CAAS,IAAA,CAAK,IAAI,KAAA,CAAM,MAAM,CAAC,CAAA;AAC/B,QAAA,UAAA,CAAW,IAAI,cAAc,CAAA;AAAA,MAC/B;AAAA,IACF,CAAA;AAAA,IACA,CAAC,UAAU,cAAc;AAAA,GAC3B;AAEA,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,YAAA,GAAe,WAAW,SAAA,CAAU;AAAA,MACxC,KAAK,IAAA,EAAM;AACT,QAAA,IAAI,KAAK,KAAA,EAAO;AACd,UAAA,WAAA,CAAY,IAAI,CAAA;AAAA,QAClB;AAAA,MACF,CAAA;AAAA,MACA,MAAM,KAAA,EAAO;AACX,QAAA,OAAA,CAAQ,KAAK,CAAA;AAAA,MACf;AAAA,KACD,CAAA;AAED,IAAA,OAAO,MAAM;AACX,MAAA,YAAA,CAAa,WAAA,EAAY;AAAA,IAC3B,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,UAAA,EAAY,OAAO,CAAC,CAAA;AAGxB,EAAA,MAAM,gBAAA,GAAmB,OAAO,IAAI,CAAA;AACpC,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,iBAAiB,OAAA,EAAS;AAC5B,MAAA,gBAAA,CAAiB,OAAA,GAAU,KAAA;AAAA,IAC7B,CAAA,MAAO;AACL,MAAA,WAAA,CAAY,cAAA,CAAe,cAAA,CAAe,cAAc,CAAC,CAAA;AAAA,IAC3D;AAAA,EACF,CAAA,EAAG,CAAC,cAAA,EAAgB,cAAc,CAAC,CAAA;AAEnC,EAAA,IAAI,CAAC,SAAS,KAAA,EAAO;AACnB,IAAA,MAAM,IAAI,QAAc,CAAA,OAAA,KAAW;AACjC,MAAA,MAAM,YAAA,GAAe,WAAW,SAAA,CAAU;AAAA,QACxC,KAAK,IAAA,EAAM;AACT,UAAA,IAAI,KAAK,KAAA,EAAO;AACd,YAAA,YAAA,CAAa,WAAA,EAAY;AACzB,YAAA,OAAA,EAAQ;AAAA,UACV;AAAA,QACF,CAAA;AAAA,QACA,MAAM,KAAA,EAAO;AACX,UAAA,YAAA,CAAa,WAAA,EAAY;AACzB,UAAA,OAAA,CAAQ,KAAK,CAAA;AACb,UAAA,OAAA,EAAQ;AAAA,QACV;AAAA,OACD,CAAA;AAAA,IACH,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,OAAO,EAAE,CAAA,EAAG,QAAA,CAAS,CAAA,EAAE;AACzB;;;;"}
|
|
@@ -2,6 +2,8 @@ import { createExtensionDataRef } from './createExtensionDataRef.esm.js';
|
|
|
2
2
|
|
|
3
3
|
const coreExtensionData = {
|
|
4
4
|
title: createExtensionDataRef().with({ id: "core.title" }),
|
|
5
|
+
/** An icon element for the extension. Should be exactly 24x24 pixels. */
|
|
6
|
+
icon: createExtensionDataRef().with({ id: "core.icon" }),
|
|
5
7
|
reactElement: createExtensionDataRef().with({
|
|
6
8
|
id: "core.reactElement"
|
|
7
9
|
}),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"coreExtensionData.esm.js","sources":["../../src/wiring/coreExtensionData.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { JSX } from 'react';\nimport { RouteRef } from '../routing/RouteRef';\nimport { createExtensionDataRef } from './createExtensionDataRef';\n\n/** @public */\nexport const coreExtensionData = {\n title: createExtensionDataRef<string>().with({ id: 'core.title' }),\n reactElement: createExtensionDataRef<JSX.Element>().with({\n id: 'core.reactElement',\n }),\n routePath: createExtensionDataRef<string>().with({ id: 'core.routing.path' }),\n routeRef: createExtensionDataRef<RouteRef>().with({ id: 'core.routing.ref' }),\n};\n"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"coreExtensionData.esm.js","sources":["../../src/wiring/coreExtensionData.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { JSX } from 'react';\nimport { IconElement } from '../icons/types';\nimport { RouteRef } from '../routing/RouteRef';\nimport { createExtensionDataRef } from './createExtensionDataRef';\n\n/** @public */\nexport const coreExtensionData = {\n title: createExtensionDataRef<string>().with({ id: 'core.title' }),\n /** An icon element for the extension. Should be exactly 24x24 pixels. */\n icon: createExtensionDataRef<IconElement>().with({ id: 'core.icon' }),\n reactElement: createExtensionDataRef<JSX.Element>().with({\n id: 'core.reactElement',\n }),\n routePath: createExtensionDataRef<string>().with({ id: 'core.routing.path' }),\n routeRef: createExtensionDataRef<RouteRef>().with({ id: 'core.routing.ref' }),\n};\n"],"names":[],"mappings":";;AAsBO,MAAM,iBAAA,GAAoB;AAAA,EAC/B,OAAO,sBAAA,EAA+B,CAAE,KAAK,EAAE,EAAA,EAAI,cAAc,CAAA;AAAA;AAAA,EAEjE,MAAM,sBAAA,EAAoC,CAAE,KAAK,EAAE,EAAA,EAAI,aAAa,CAAA;AAAA,EACpE,YAAA,EAAc,sBAAA,EAAoC,CAAE,IAAA,CAAK;AAAA,IACvD,EAAA,EAAI;AAAA,GACL,CAAA;AAAA,EACD,WAAW,sBAAA,EAA+B,CAAE,KAAK,EAAE,EAAA,EAAI,qBAAqB,CAAA;AAAA,EAC5E,UAAU,sBAAA,EAAiC,CAAE,KAAK,EAAE,EAAA,EAAI,oBAAoB;AAC9E;;;;"}
|
|
@@ -39,6 +39,8 @@ function createFrontendPlugin(options) {
|
|
|
39
39
|
return OpaqueFrontendPlugin.createInstance("v1", {
|
|
40
40
|
pluginId,
|
|
41
41
|
id: pluginId,
|
|
42
|
+
title: options.title,
|
|
43
|
+
icon: options.icon,
|
|
42
44
|
routes: options.routes ?? {},
|
|
43
45
|
externalRoutes: options.externalRoutes ?? {},
|
|
44
46
|
featureFlags: options.featureFlags ?? [],
|
|
@@ -63,8 +65,9 @@ function createFrontendPlugin(options) {
|
|
|
63
65
|
return `Plugin{id=${pluginId}}`;
|
|
64
66
|
},
|
|
65
67
|
withOverrides(overrides) {
|
|
68
|
+
const overrideExtensions = overrides.extensions ?? [];
|
|
66
69
|
const overriddenExtensionIds = new Set(
|
|
67
|
-
|
|
70
|
+
overrideExtensions.map(
|
|
68
71
|
(e) => resolveExtensionDefinition(e, { namespace: pluginId }).id
|
|
69
72
|
)
|
|
70
73
|
);
|
|
@@ -76,7 +79,9 @@ function createFrontendPlugin(options) {
|
|
|
76
79
|
return createFrontendPlugin({
|
|
77
80
|
...options,
|
|
78
81
|
pluginId,
|
|
79
|
-
|
|
82
|
+
title: overrides.title ?? options.title,
|
|
83
|
+
icon: overrides.icon ?? options.icon,
|
|
84
|
+
extensions: [...nonOverriddenExtensions, ...overrideExtensions],
|
|
80
85
|
info: {
|
|
81
86
|
...options.info,
|
|
82
87
|
...overrides.info
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createFrontendPlugin.esm.js","sources":["../../src/wiring/createFrontendPlugin.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n OpaqueExtensionDefinition,\n OpaqueFrontendPlugin,\n} from '@internal/frontend';\nimport {\n ExtensionDefinition,\n OverridableExtensionDefinition,\n} from './createExtension';\nimport {\n Extension,\n resolveExtensionDefinition,\n} from './resolveExtensionDefinition';\nimport { FeatureFlagConfig } from './types';\nimport { MakeSortedExtensionsMap } from './MakeSortedExtensionsMap';\nimport { JsonObject } from '@backstage/types';\nimport { RouteRef, SubRouteRef, ExternalRouteRef } from '../routing';\nimport { ID_PATTERN } from './constants';\n\n/**\n * Information about the plugin.\n *\n * @public\n * @remarks\n *\n * This interface is intended to be extended via [module\n * augmentation](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation)\n * in order to add fields that are specific to each project.\n *\n * For example, one might add a `slackChannel` field that is read from the\n * opaque manifest file.\n *\n * See the options for `createApp` for more information about how to\n * customize the parsing of manifest files.\n */\nexport interface FrontendPluginInfo {\n /**\n * The name of the package that implements the plugin.\n */\n packageName?: string;\n\n /**\n * The version of the plugin, typically the version of the package.json file.\n */\n version?: string;\n\n /**\n * As short description of the plugin, typically the description field in\n * package.json.\n */\n description?: string;\n\n /**\n * The owner entity references of the plugin.\n */\n ownerEntityRefs?: string[];\n\n /**\n * Links related to the plugin.\n */\n links?: Array<{ title: string; url: string }>;\n}\n\n/**\n * Options for providing information for a plugin.\n *\n * @public\n */\nexport type FrontendPluginInfoOptions = {\n /**\n * A loader function for the package.json file for the plugin.\n */\n packageJson?: () => Promise<{ name: string } & JsonObject>;\n /**\n * A loader function for an opaque manifest file for the plugin.\n */\n manifest?: () => Promise<JsonObject>;\n};\n\n/**\n * A variant of the {@link FrontendPlugin} interface that can also be used to install overrides for the plugin.\n *\n * @public\n */\nexport interface OverridableFrontendPlugin<\n TRoutes extends { [name in string]: RouteRef | SubRouteRef } = {\n [name in string]: RouteRef | SubRouteRef;\n },\n TExternalRoutes extends { [name in string]: ExternalRouteRef } = {\n [name in string]: ExternalRouteRef;\n },\n TExtensionMap extends { [id in string]: ExtensionDefinition } = {\n [id in string]: ExtensionDefinition;\n },\n> extends FrontendPlugin<TRoutes, TExternalRoutes> {\n getExtension<TId extends keyof TExtensionMap>(\n id: TId,\n ): OverridableExtensionDefinition<TExtensionMap[TId]['T']>;\n withOverrides(options: {\n extensions: Array<ExtensionDefinition>;\n\n /**\n * Overrides the original info loaders of the plugin one by one.\n */\n info?: FrontendPluginInfoOptions;\n }): OverridableFrontendPlugin<TRoutes, TExternalRoutes, TExtensionMap>;\n}\n\n/** @public */\nexport interface FrontendPlugin<\n TRoutes extends { [name in string]: RouteRef | SubRouteRef } = {\n [name in string]: RouteRef | SubRouteRef;\n },\n TExternalRoutes extends { [name in string]: ExternalRouteRef } = {\n [name in string]: ExternalRouteRef;\n },\n> {\n readonly $$type: '@backstage/FrontendPlugin';\n /**\n * The plugin ID.\n */\n readonly pluginId: string;\n /**\n * Deprecated alias for `pluginId`.\n *\n * @deprecated Use `pluginId` instead.\n */\n readonly id: string;\n readonly routes: TRoutes;\n readonly externalRoutes: TExternalRoutes;\n\n /**\n * Loads the plugin info.\n */\n info(): Promise<FrontendPluginInfo>;\n}\n\n/** @public */\nexport interface PluginOptions<\n TId extends string,\n TRoutes extends { [name in string]: RouteRef | SubRouteRef },\n TExternalRoutes extends { [name in string]: ExternalRouteRef },\n TExtensions extends readonly ExtensionDefinition[],\n> {\n pluginId: TId;\n routes?: TRoutes;\n externalRoutes?: TExternalRoutes;\n extensions?: TExtensions;\n featureFlags?: FeatureFlagConfig[];\n info?: FrontendPluginInfoOptions;\n}\n\n/**\n * Creates a new plugin that can be installed in a Backstage app.\n *\n * @remarks\n *\n * Every plugin is created with a unique ID and a set of extensions\n * that are installed as part of the plugin.\n *\n * For more information on how plugins work, see the\n * {@link https://backstage.io/docs/frontend-system/building-plugins/index | documentation for plugins}\n * in the frontend system documentation.\n *\n * @example\n *\n * ```tsx\n * import { createFrontendPlugin } from '@backstage/frontend-plugin-api';\n *\n * export const examplePlugin = createFrontendPlugin({\n * pluginId: 'example',\n * extensions: [\n * PageBlueprint.make({\n * path: '/example',\n * loader: () => import('./ExamplePage').then(m => <m.ExamplePage />),\n * }),\n * ],\n * });\n * ```\n *\n * @public\n */\nexport function createFrontendPlugin<\n TId extends string,\n TExtensions extends readonly ExtensionDefinition[],\n TRoutes extends { [name in string]: RouteRef | SubRouteRef } = {},\n TExternalRoutes extends { [name in string]: ExternalRouteRef } = {},\n>(\n options: PluginOptions<TId, TRoutes, TExternalRoutes, TExtensions>,\n): OverridableFrontendPlugin<\n TRoutes,\n TExternalRoutes,\n MakeSortedExtensionsMap<TExtensions[number], TId>\n> {\n const pluginId = options.pluginId;\n\n if (!ID_PATTERN.test(pluginId)) {\n // eslint-disable-next-line no-console\n console.warn(\n `WARNING: The pluginId '${pluginId}' will be invalid soon, please change it to match the pattern ${ID_PATTERN} (letters, digits, and dashes only, starting with a letter)`,\n );\n }\n\n const extensions = new Array<Extension<any>>();\n const extensionDefinitionsById = new Map<\n string,\n typeof OpaqueExtensionDefinition.TInternal\n >();\n\n for (const def of options.extensions ?? []) {\n const internal = OpaqueExtensionDefinition.toInternal(def);\n const ext = resolveExtensionDefinition(def, { namespace: pluginId });\n extensions.push(ext);\n extensionDefinitionsById.set(ext.id, {\n ...internal,\n namespace: pluginId,\n });\n }\n\n if (extensions.length !== extensionDefinitionsById.size) {\n const extensionIds = extensions.map(e => e.id);\n const duplicates = Array.from(\n new Set(\n extensionIds.filter((id, index) => extensionIds.indexOf(id) !== index),\n ),\n );\n // TODO(Rugvip): This could provide some more information about the kind + name of the extensions\n throw new Error(\n `Plugin '${pluginId}' provided duplicate extensions: ${duplicates.join(\n ', ',\n )}`,\n );\n }\n\n return OpaqueFrontendPlugin.createInstance('v1', {\n pluginId,\n id: pluginId,\n routes: options.routes ?? ({} as TRoutes),\n externalRoutes: options.externalRoutes ?? ({} as TExternalRoutes),\n featureFlags: options.featureFlags ?? [],\n extensions: extensions,\n infoOptions: options.info,\n\n // This method is overridden when the plugin instance is installed in an app\n async info() {\n throw new Error(\n `Attempted to load plugin info for plugin '${pluginId}', but the plugin instance is not installed in an app`,\n );\n },\n getExtension(id) {\n const ext = extensionDefinitionsById.get(id);\n if (!ext) {\n throw new Error(\n `Attempted to get non-existent extension '${id}' from plugin '${pluginId}'`,\n );\n }\n return ext;\n },\n toString() {\n return `Plugin{id=${pluginId}}`;\n },\n withOverrides(overrides) {\n const overriddenExtensionIds = new Set(\n overrides.extensions.map(\n e => resolveExtensionDefinition(e, { namespace: pluginId }).id,\n ),\n );\n const nonOverriddenExtensions = (options.extensions ?? []).filter(\n e =>\n !overriddenExtensionIds.has(\n resolveExtensionDefinition(e, { namespace: pluginId }).id,\n ),\n );\n return createFrontendPlugin({\n ...options,\n pluginId,\n extensions: [...nonOverriddenExtensions, ...overrides.extensions],\n info: {\n ...options.info,\n ...overrides.info,\n },\n });\n },\n });\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"createFrontendPlugin.esm.js","sources":["../../src/wiring/createFrontendPlugin.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n OpaqueExtensionDefinition,\n OpaqueFrontendPlugin,\n} from '@internal/frontend';\nimport {\n ExtensionDefinition,\n OverridableExtensionDefinition,\n} from './createExtension';\nimport {\n Extension,\n resolveExtensionDefinition,\n} from './resolveExtensionDefinition';\nimport { FeatureFlagConfig } from './types';\nimport { MakeSortedExtensionsMap } from './MakeSortedExtensionsMap';\nimport { JsonObject } from '@backstage/types';\nimport { IconElement } from '../icons/types';\nimport { RouteRef, SubRouteRef, ExternalRouteRef } from '../routing';\nimport { ID_PATTERN } from './constants';\n\n/**\n * Information about the plugin.\n *\n * @public\n * @remarks\n *\n * This interface is intended to be extended via [module\n * augmentation](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation)\n * in order to add fields that are specific to each project.\n *\n * For example, one might add a `slackChannel` field that is read from the\n * opaque manifest file.\n *\n * See the options for `createApp` for more information about how to\n * customize the parsing of manifest files.\n */\nexport interface FrontendPluginInfo {\n /**\n * The name of the package that implements the plugin.\n */\n packageName?: string;\n\n /**\n * The version of the plugin, typically the version of the package.json file.\n */\n version?: string;\n\n /**\n * As short description of the plugin, typically the description field in\n * package.json.\n */\n description?: string;\n\n /**\n * The owner entity references of the plugin.\n */\n ownerEntityRefs?: string[];\n\n /**\n * Links related to the plugin.\n */\n links?: Array<{ title: string; url: string }>;\n}\n\n/**\n * Options for providing information for a plugin.\n *\n * @public\n */\nexport type FrontendPluginInfoOptions = {\n /**\n * A loader function for the package.json file for the plugin.\n */\n packageJson?: () => Promise<{ name: string } & JsonObject>;\n /**\n * A loader function for an opaque manifest file for the plugin.\n */\n manifest?: () => Promise<JsonObject>;\n};\n\n/**\n * A variant of the {@link FrontendPlugin} interface that can also be used to install overrides for the plugin.\n *\n * @public\n */\nexport interface OverridableFrontendPlugin<\n TRoutes extends { [name in string]: RouteRef | SubRouteRef } = {\n [name in string]: RouteRef | SubRouteRef;\n },\n TExternalRoutes extends { [name in string]: ExternalRouteRef } = {\n [name in string]: ExternalRouteRef;\n },\n TExtensionMap extends { [id in string]: ExtensionDefinition } = {\n [id in string]: ExtensionDefinition;\n },\n> extends FrontendPlugin<TRoutes, TExternalRoutes> {\n getExtension<TId extends keyof TExtensionMap>(\n id: TId,\n ): OverridableExtensionDefinition<TExtensionMap[TId]['T']>;\n withOverrides(options: {\n extensions?: Array<ExtensionDefinition>;\n\n /**\n * Overrides the display title of the plugin.\n */\n title?: string;\n\n /**\n * Overrides the display icon of the plugin.\n */\n icon?: IconElement;\n\n /**\n * Overrides the original info loaders of the plugin one by one.\n */\n info?: FrontendPluginInfoOptions;\n }): OverridableFrontendPlugin<TRoutes, TExternalRoutes, TExtensionMap>;\n}\n\n/** @public */\nexport interface FrontendPlugin<\n TRoutes extends { [name in string]: RouteRef | SubRouteRef } = {\n [name in string]: RouteRef | SubRouteRef;\n },\n TExternalRoutes extends { [name in string]: ExternalRouteRef } = {\n [name in string]: ExternalRouteRef;\n },\n> {\n readonly $$type: '@backstage/FrontendPlugin';\n /**\n * The plugin ID.\n */\n readonly pluginId: string;\n /**\n * Deprecated alias for `pluginId`.\n *\n * @deprecated Use `pluginId` instead.\n */\n readonly id: string;\n /**\n * The display title of the plugin, used in page headers and navigation.\n * Falls back to the plugin ID if not provided.\n */\n readonly title?: string;\n /**\n * The display icon of the plugin, used in page headers and navigation.\n */\n readonly icon?: IconElement;\n readonly routes: TRoutes;\n readonly externalRoutes: TExternalRoutes;\n\n /**\n * Loads the plugin info.\n */\n info(): Promise<FrontendPluginInfo>;\n}\n\n/** @public */\nexport interface PluginOptions<\n TId extends string,\n TRoutes extends { [name in string]: RouteRef | SubRouteRef },\n TExternalRoutes extends { [name in string]: ExternalRouteRef },\n TExtensions extends readonly ExtensionDefinition[],\n> {\n pluginId: TId;\n /**\n * The display title of the plugin, used in page headers and navigation.\n * Falls back to the plugin ID if not provided.\n */\n title?: string;\n /**\n * The display icon of the plugin, used in page headers and navigation.\n */\n icon?: IconElement;\n routes?: TRoutes;\n externalRoutes?: TExternalRoutes;\n extensions?: TExtensions;\n featureFlags?: FeatureFlagConfig[];\n info?: FrontendPluginInfoOptions;\n}\n\n/**\n * Creates a new plugin that can be installed in a Backstage app.\n *\n * @remarks\n *\n * Every plugin is created with a unique ID and a set of extensions\n * that are installed as part of the plugin.\n *\n * For more information on how plugins work, see the\n * {@link https://backstage.io/docs/frontend-system/building-plugins/index | documentation for plugins}\n * in the frontend system documentation.\n *\n * @example\n *\n * ```tsx\n * import { createFrontendPlugin } from '@backstage/frontend-plugin-api';\n *\n * export const examplePlugin = createFrontendPlugin({\n * pluginId: 'example',\n * extensions: [\n * PageBlueprint.make({\n * path: '/example',\n * loader: () => import('./ExamplePage').then(m => <m.ExamplePage />),\n * }),\n * ],\n * });\n * ```\n *\n * @public\n */\nexport function createFrontendPlugin<\n TId extends string,\n TExtensions extends readonly ExtensionDefinition[],\n TRoutes extends { [name in string]: RouteRef | SubRouteRef } = {},\n TExternalRoutes extends { [name in string]: ExternalRouteRef } = {},\n>(\n options: PluginOptions<TId, TRoutes, TExternalRoutes, TExtensions>,\n): OverridableFrontendPlugin<\n TRoutes,\n TExternalRoutes,\n MakeSortedExtensionsMap<TExtensions[number], TId>\n> {\n const pluginId = options.pluginId;\n\n if (!ID_PATTERN.test(pluginId)) {\n // eslint-disable-next-line no-console\n console.warn(\n `WARNING: The pluginId '${pluginId}' will be invalid soon, please change it to match the pattern ${ID_PATTERN} (letters, digits, and dashes only, starting with a letter)`,\n );\n }\n\n const extensions = new Array<Extension<any>>();\n const extensionDefinitionsById = new Map<\n string,\n typeof OpaqueExtensionDefinition.TInternal\n >();\n\n for (const def of options.extensions ?? []) {\n const internal = OpaqueExtensionDefinition.toInternal(def);\n const ext = resolveExtensionDefinition(def, { namespace: pluginId });\n extensions.push(ext);\n extensionDefinitionsById.set(ext.id, {\n ...internal,\n namespace: pluginId,\n });\n }\n\n if (extensions.length !== extensionDefinitionsById.size) {\n const extensionIds = extensions.map(e => e.id);\n const duplicates = Array.from(\n new Set(\n extensionIds.filter((id, index) => extensionIds.indexOf(id) !== index),\n ),\n );\n // TODO(Rugvip): This could provide some more information about the kind + name of the extensions\n throw new Error(\n `Plugin '${pluginId}' provided duplicate extensions: ${duplicates.join(\n ', ',\n )}`,\n );\n }\n\n return OpaqueFrontendPlugin.createInstance('v1', {\n pluginId,\n id: pluginId,\n title: options.title,\n icon: options.icon,\n routes: options.routes ?? ({} as TRoutes),\n externalRoutes: options.externalRoutes ?? ({} as TExternalRoutes),\n featureFlags: options.featureFlags ?? [],\n extensions: extensions,\n infoOptions: options.info,\n\n // This method is overridden when the plugin instance is installed in an app\n async info() {\n throw new Error(\n `Attempted to load plugin info for plugin '${pluginId}', but the plugin instance is not installed in an app`,\n );\n },\n getExtension(id) {\n const ext = extensionDefinitionsById.get(id);\n if (!ext) {\n throw new Error(\n `Attempted to get non-existent extension '${id}' from plugin '${pluginId}'`,\n );\n }\n return ext;\n },\n toString() {\n return `Plugin{id=${pluginId}}`;\n },\n withOverrides(overrides) {\n const overrideExtensions = overrides.extensions ?? [];\n const overriddenExtensionIds = new Set(\n overrideExtensions.map(\n e => resolveExtensionDefinition(e, { namespace: pluginId }).id,\n ),\n );\n const nonOverriddenExtensions = (options.extensions ?? []).filter(\n e =>\n !overriddenExtensionIds.has(\n resolveExtensionDefinition(e, { namespace: pluginId }).id,\n ),\n );\n return createFrontendPlugin({\n ...options,\n pluginId,\n title: overrides.title ?? options.title,\n icon: overrides.icon ?? options.icon,\n extensions: [...nonOverriddenExtensions, ...overrideExtensions],\n info: {\n ...options.info,\n ...overrides.info,\n },\n });\n },\n });\n}\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/frontend-plugin-api",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.1",
|
|
4
4
|
"backstage": {
|
|
5
5
|
"role": "web-library"
|
|
6
6
|
},
|
|
@@ -52,18 +52,18 @@
|
|
|
52
52
|
"test": "backstage-cli package test"
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@backstage/errors": "1.2.7",
|
|
56
|
-
"@backstage/types": "1.2.2",
|
|
57
|
-
"@backstage/version-bridge": "1.0.12
|
|
55
|
+
"@backstage/errors": "^1.2.7",
|
|
56
|
+
"@backstage/types": "^1.2.2",
|
|
57
|
+
"@backstage/version-bridge": "^1.0.12",
|
|
58
58
|
"zod": "^3.25.76",
|
|
59
59
|
"zod-to-json-schema": "^3.25.1"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
|
-
"@backstage/cli": "0.35.4
|
|
63
|
-
"@backstage/config": "1.3.6",
|
|
64
|
-
"@backstage/frontend-app-api": "0.15.0
|
|
65
|
-
"@backstage/frontend-test-utils": "0.5.0
|
|
66
|
-
"@backstage/test-utils": "1.7.15
|
|
62
|
+
"@backstage/cli": "^0.35.4",
|
|
63
|
+
"@backstage/config": "^1.3.6",
|
|
64
|
+
"@backstage/frontend-app-api": "^0.15.0",
|
|
65
|
+
"@backstage/frontend-test-utils": "^0.5.0",
|
|
66
|
+
"@backstage/test-utils": "^1.7.15",
|
|
67
67
|
"@testing-library/jest-dom": "^6.0.0",
|
|
68
68
|
"@testing-library/react": "^16.0.0",
|
|
69
69
|
"@types/react": "^18.0.0",
|