Merge branch 'master' into bui-table
# Conflicts: # docs-ui/public/theme-backstage.css
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/backend-openapi-utils': patch
|
||||
---
|
||||
|
||||
Update `express-openapi-validator` to 5.5.8 to fix security vulnerability in transitive dependency `multer`
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/frontend-defaults': patch
|
||||
---
|
||||
|
||||
Deprecated `createPublicSignInApp`, which has been replaced by the new `appModulePublicSignIn` from `@backstage/plugin-app/alpha` instead.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/frontend-plugin-api': minor
|
||||
---
|
||||
|
||||
**BREAKING**: Remove deprecated `source` property from the `AppNodeSpec` type, use `AppNodeSpec.plugin` instead.
|
||||
@@ -0,0 +1,24 @@
|
||||
---
|
||||
'@backstage/frontend-plugin-api': patch
|
||||
'@backstage/frontend-app-api': patch
|
||||
---
|
||||
|
||||
Add support for a new `aliasFor` option for `createRouteRef`. This allows for the creation of a new route ref that acts as an alias for an existing route ref that is installed in the app. This is particularly useful when creating modules that override existing plugin pages, without referring to the existing plugin. For example:
|
||||
|
||||
```tsx
|
||||
export default createFrontendModule({
|
||||
pluginId: 'catalog',
|
||||
extensions: [
|
||||
PageBlueprint.make({
|
||||
params: {
|
||||
defaultPath: '/catalog',
|
||||
routeRef: createRouteRef({ aliasFor: 'catalog.catalogIndex' }),
|
||||
loader: () =>
|
||||
import('./CustomCatalogIndexPage').then(m => (
|
||||
<m.CustomCatalogIndexPage />
|
||||
)),
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/frontend-plugin-api': minor
|
||||
---
|
||||
|
||||
**BREAKING**: The `defaultPath` param of `PageBlueprint` has been renamed to `path`. This change does not affect the compatibility of extensions created with older versions of this blueprint.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-app': patch
|
||||
---
|
||||
|
||||
Default implementations of core components are now provided by this package.
|
||||
@@ -0,0 +1,15 @@
|
||||
---
|
||||
'@backstage/plugin-app': minor
|
||||
---
|
||||
|
||||
**BREAKING**: The `componentsApi` implementation has been removed from the plugin and replaced with the new `SwappableComponentsApi` instead.
|
||||
|
||||
If you were overriding the `componentsApi` implementation, you can now use the new `SwappableComponentsApi` instead.
|
||||
|
||||
```ts
|
||||
// old
|
||||
appPlugin.getExtension('api:app/components').override(...)
|
||||
|
||||
// new
|
||||
appPlugin.getExtension('api:app/swappable-components').override(...)
|
||||
```
|
||||
@@ -0,0 +1,96 @@
|
||||
---
|
||||
'@backstage/frontend-plugin-api': minor
|
||||
---
|
||||
|
||||
**BREAKING**: The component system has been overhauled to use `SwappableComponent` instead of `ComponentRef`. Several APIs have been removed and replaced:
|
||||
|
||||
- Removed: `createComponentRef`, `createComponentExtension`, `ComponentRef`, `ComponentsApi`, `componentsApiRef`, `useComponentRef`, `coreComponentRefs`
|
||||
- Added: `createSwappableComponent`, `SwappableComponentBlueprint`, `SwappableComponentRef`, `SwappableComponentsApi`, `swappableComponentsApiRef`
|
||||
|
||||
**BREAKING**: The default `componentRefs` and exported `Core*Props` have been removed and have replacement `SwappableComponents` and revised type names instead.
|
||||
|
||||
- The `errorBoundaryFallback` component and `CoreErrorBoundaryFallbackProps` type have been replaced with `ErrorDisplay` swappable component and `CoreErrorDisplayProps` respectively.
|
||||
- The `progress` component and `CoreProgressProps` type have been replaced with `Progress` swappable component and `ProgressProps` respectively.
|
||||
- The `notFoundErrorPage` component and `CoreNotFoundErrorPageProps` type have been replaced with `NotFoundErrorPage` swappable component and `NotFoundErrorPageProps` respectively.
|
||||
|
||||
**Migration for creating swappable components:**
|
||||
|
||||
```tsx
|
||||
// OLD: Using createComponentRef and createComponentExtension
|
||||
import {
|
||||
createComponentRef,
|
||||
createComponentExtension,
|
||||
} from '@backstage/frontend-plugin-api';
|
||||
|
||||
const myComponentRef = createComponentRef<{ title: string }>({
|
||||
id: 'my-plugin.my-component',
|
||||
});
|
||||
|
||||
const myComponentExtension = createComponentExtension({
|
||||
ref: myComponentRef,
|
||||
loader: {
|
||||
lazy: () => import('./MyComponent').then(m => m.MyComponent),
|
||||
},
|
||||
});
|
||||
|
||||
// NEW: Using createSwappableComponent and SwappableComponentBlueprint
|
||||
import {
|
||||
createSwappableComponent,
|
||||
SwappableComponentBlueprint,
|
||||
} from '@backstage/frontend-plugin-api';
|
||||
|
||||
const MySwappableComponent = createSwappableComponent({
|
||||
id: 'my-plugin.my-component',
|
||||
loader: () => import('./MyComponent').then(m => m.MyComponent),
|
||||
});
|
||||
|
||||
const myComponentExtension = SwappableComponentBlueprint.make({
|
||||
name: 'my-component',
|
||||
params: {
|
||||
component: MySwappableComponent,
|
||||
loader: () => import('./MyComponent').then(m => m.MyComponent),
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
**Migration for using components:**
|
||||
|
||||
```tsx
|
||||
// OLD: Using ComponentsApi and useComponentRef
|
||||
import {
|
||||
useComponentRef,
|
||||
componentsApiRef,
|
||||
useApi,
|
||||
coreComponentRefs,
|
||||
} from '@backstage/frontend-plugin-api';
|
||||
|
||||
const MyComponent = useComponentRef(myComponentRef);
|
||||
const ProgressComponent = useComponentRef(coreComponentRefs.progress);
|
||||
|
||||
|
||||
// NEW: Direct component usage
|
||||
import { Progress } from '@backstage/frontend-plugin-api';
|
||||
|
||||
// Use directly as React Component
|
||||
<Progress />
|
||||
<MySwappableComponent title="Hello World" />
|
||||
```
|
||||
|
||||
**Migration for core component references:**
|
||||
|
||||
```tsx
|
||||
// OLD: Core component refs
|
||||
import { coreComponentRefs } from '@backstage/frontend-plugin-api';
|
||||
|
||||
coreComponentRefs.progress
|
||||
coreComponentRefs.notFoundErrorPage
|
||||
coreComponentRefs.errorBoundaryFallback
|
||||
|
||||
// NEW: Direct swappable component imports
|
||||
import { Progress, NotFoundErrorPage, ErrorDisplay } from '@backstage/frontend-plugin-api';
|
||||
|
||||
// Use directly as React components
|
||||
<Progress />
|
||||
<NotFoundErrorPage />
|
||||
<ErrorDisplay plugin={plugin} error={error} resetError={resetError} />
|
||||
```
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/cli': minor
|
||||
---
|
||||
|
||||
Added plugin and module templates for the new frontend system. These templates are not included by default, but can be included by adding `@backstage/cli/templates/new-frontend-plugin` and `@backstage/cli/templates/new-frontend-plugin-module` as [custom templates](https://backstage.io/docs/tooling/cli/templates#installing-custom-templates).
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/create-app': patch
|
||||
---
|
||||
|
||||
Bumped create-app version.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/frontend-test-utils': patch
|
||||
---
|
||||
|
||||
Updated import of the `FrontendFeature` type.
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-unprocessed-entities': patch
|
||||
'@backstage/frontend-defaults': patch
|
||||
'@backstage/core-compat-api': patch
|
||||
'@backstage/plugin-app-visualizer': patch
|
||||
'@backstage/plugin-catalog-import': patch
|
||||
'@backstage/plugin-catalog-graph': patch
|
||||
'@backstage/plugin-notifications': patch
|
||||
'@backstage/plugin-user-settings': patch
|
||||
'@backstage/plugin-search-react': patch
|
||||
'@backstage/plugin-kubernetes': patch
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
'@backstage/plugin-api-docs': patch
|
||||
'@backstage/plugin-devtools': patch
|
||||
'@backstage/plugin-techdocs': patch
|
||||
'@backstage/plugin-catalog': patch
|
||||
'@backstage/plugin-search': patch
|
||||
'@backstage/plugin-home': patch
|
||||
---
|
||||
|
||||
Internal update to align with new blueprint parameter naming in the new frontend system.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend-module-gitlab': patch
|
||||
---
|
||||
|
||||
Show additional information about the cause in error messages from GitLab
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend': patch
|
||||
---
|
||||
|
||||
Attempt to circumvent event listener memory leak in compression middleware
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/frontend-plugin-api': minor
|
||||
---
|
||||
|
||||
**BREAKING**: Removed the deprecated `createFrontendPlugin` variant where the plugin ID is passed via an `id` option. To update existing code, switch to using the `pluginId` option instead.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/frontend-plugin-api': minor
|
||||
---
|
||||
|
||||
**BREAKING**: Removed the `routable` property from `ExtensionBoundary`. This property was never needed in practice and is instead inferred from whether or not the extension outputs a route reference. It can be safely removed.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/frontend-plugin-api': minor
|
||||
---
|
||||
|
||||
**BREAKING**: The `ResolveInputValueOverrides` type is no longer exported.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/frontend-plugin-api': minor
|
||||
---
|
||||
|
||||
**BREAKING**: Removed the ability to define a default extension `name` in blueprints. This option had no practical purpose as blueprints already use the `kind` to identity the source of the extension.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/frontend-app-api': minor
|
||||
---
|
||||
|
||||
Use an app plugin for built-in extension app node specs.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-app': patch
|
||||
---
|
||||
|
||||
Added a new module for implementing public sign-in apps, exported as `appModulePublicSignIn` via the `/alpha` sub-path export. This replaces the `createPublicSignInApp` export from `@backstage/frontend-defaults`, which is now deprecated.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/frontend-app-api': minor
|
||||
---
|
||||
|
||||
**BREAKING**: Removed the deprecated `FrontendFeature` type, import it from `@backstage/frontend-plugin-api` instead.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/frontend-defaults': minor
|
||||
---
|
||||
|
||||
**BREAKING**: Removed the deprecated `CreateAppFeatureLoader` and support for it in other APIs. Switch existing usage to use the newer `createFrontendFeatureLoader` from `@backstage/frontend-plugin-api` instead.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/frontend-plugin-api': minor
|
||||
---
|
||||
|
||||
**BREAKING**: The separate `RouteResolutionApiResolveOptions` type has been removed.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/core-compat-api': minor
|
||||
---
|
||||
|
||||
**BREAKING**: The `componentsApi` implementation has been removed from the plugin and replaced with the new `SwappableComponentsApi` instead. Which means that the `componentsApi` is not longer backwards compatible with legacy plugins.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend': minor
|
||||
---
|
||||
|
||||
Fixed fs:readdir action example
|
||||
@@ -0,0 +1,39 @@
|
||||
---
|
||||
'@backstage/frontend-plugin-api': minor
|
||||
---
|
||||
|
||||
**BREAKING**: In an attempt to align some of the API's around providing components to `Blueprints`, we've renamed the parameters for both the `RouterBlueprint` and `AppRootWrapperBlueprint` from `Component` to `component`.
|
||||
|
||||
```tsx
|
||||
// old
|
||||
RouterBlueprint.make({
|
||||
params: {
|
||||
Component: ({ children }) => <div>{children}</div>,
|
||||
},
|
||||
});
|
||||
|
||||
// new
|
||||
RouterBlueprint.make({
|
||||
params: {
|
||||
component: ({ children }) => <div>{children}</div>,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
```tsx
|
||||
// old
|
||||
AppRootWrapperBlueprint.make({
|
||||
params: {
|
||||
Component: ({ children }) => <div>{children}</div>,
|
||||
},
|
||||
});
|
||||
|
||||
// new
|
||||
AppRootWrapperBlueprint.make({
|
||||
params: {
|
||||
component: ({ children }) => <div>{children}</div>,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
As part of this change, the type for `component` has also changed from `ComponentType<PropsWithChildren<{}>>` to `(props: { children: ReactNode }) => JSX.Element | null` which is not breaking, just a little more reflective of the actual expected component.
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/frontend-test-utils': patch
|
||||
'@backstage/core-compat-api': patch
|
||||
'@backstage/plugin-app': patch
|
||||
---
|
||||
|
||||
Updated the usage of the `RouterBlueprint` and `AppRootWrapperBlueprint` to use the lowercase `component` parameter
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/ui': patch
|
||||
---
|
||||
|
||||
**Breaking change** Move breadcrumb to fit in the `HeaderPage` instead of the `Header` in Backstage UI.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-app': minor
|
||||
---
|
||||
|
||||
**BREAKING**: The `app-root-element` extension now only accepts `JSX.Element` in its `element` param, meaning overrides need to be updated.
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
'@backstage/frontend-plugin-api': minor
|
||||
---
|
||||
|
||||
**BREAKING**: The `AnyRoutes` and `AnyExternalRoutes` types have been removed and their usage has been inlined instead.
|
||||
|
||||
Existing usage can be replaced according to their previous definitions:
|
||||
|
||||
```ts
|
||||
type AnyRoutes = { [name in string]: RouteRef | SubRouteRef };
|
||||
type AnyExternalRoutes = { [name in string]: ExternalRouteRef };
|
||||
```
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-proxy-backend': patch
|
||||
---
|
||||
|
||||
correct rewrite rule to avoid extra subpath in proxy path
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/frontend-app-api': patch
|
||||
---
|
||||
|
||||
Renaming the `getNodesByRoutePath` parameter from `sourcePath` to `routePath`
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/core-compat-api': minor
|
||||
---
|
||||
|
||||
**BREAKING**: The `defaultPath` override of `convertLegacyPageExtension` has been renamed to `path`, in order to align with the same update that was made to the `PageBlueprint`.
|
||||
@@ -0,0 +1,18 @@
|
||||
---
|
||||
'@backstage/frontend-plugin-api': patch
|
||||
---
|
||||
|
||||
Plugins should now use the new `AnalyticsImplementationBlueprint` to define and provide concrete analytics implementations. For example:
|
||||
|
||||
```ts
|
||||
import { AnalyticsImplementationBlueprint } from '@backstage/frontend-plugin-api';
|
||||
|
||||
const AcmeAnalytics = AnalyticsImplementationBlueprint.make({
|
||||
name: 'acme-analytics',
|
||||
params: define =>
|
||||
define({
|
||||
deps: { config: configApiRef },
|
||||
factory: ({ config }) => AcmeAnalyticsImpl.fromConfig(config),
|
||||
}),
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-app': patch
|
||||
---
|
||||
|
||||
The default implementation of the Analytics API now collects and instantiates analytics implementations exposed via `AnalyticsImplementationBlueprint` extensions. If no such extensions are discovered, the API continues to do nothing with analytics events fired within Backstage. If multiple such extensions are discovered, every discovered implementation automatically receives analytics events.
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
**BREAKING**: The `ApiBlueprint` has been updated to use the new advanced type parameters through the new `defineParams` blueprint option. This is an immediate breaking change that requires all existing usages of `ApiBlueprint` to switch to the new callback format. Existing extensions created with the old format are still compatible with the latest version of the plugin API however, meaning that this does not break existing plugins.
|
||||
|
||||
To update existing usages of `ApiBlueprint`, you remove the outer level of the `params` object and replace `createApiFactory(...)` with `define => define(...)`.
|
||||
To update existing usages of `ApiBlueprint`, you remove the outer level of the `params` object and replace `createApiFactory(...)` with `defineParams => defineParams(...)`.
|
||||
|
||||
For example, the following old usage:
|
||||
|
||||
@@ -28,8 +28,8 @@ is migrated to the following:
|
||||
```ts
|
||||
ApiBlueprint.make({
|
||||
name: 'error',
|
||||
params: define =>
|
||||
define({
|
||||
params: defineParams =>
|
||||
defineParams({
|
||||
api: errorApiRef,
|
||||
deps: { alertApi: alertApiRef },
|
||||
factory: ({ alertApi }) => {
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/cli': minor
|
||||
---
|
||||
|
||||
**BREAKING**: Removed support for `.icon.svg` imports, which have been deprecated since the 1.19 release.
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-graph': patch
|
||||
'@backstage/plugin-api-docs': patch
|
||||
'@backstage/plugin-org': patch
|
||||
---
|
||||
|
||||
Updated README instructions for the new frontend system
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/frontend-plugin-api': patch
|
||||
---
|
||||
|
||||
Tweaked the return types from `createExtension` and `createExtensionBlueprint` to avoid the forwarding of `ConfigurableExtensionDataRef` into exported types.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder': minor
|
||||
---
|
||||
|
||||
Add resizable panels width for the editor and preview panels in the template editor and template form playground layouts. Users can now resize these panels by dragging the divider between the two areas.
|
||||
@@ -209,41 +209,74 @@
|
||||
"blue-apples-pump",
|
||||
"bright-elephants-sparkle",
|
||||
"calm-geese-serve",
|
||||
"chatty-coats-sin",
|
||||
"chatty-dodos-design",
|
||||
"chatty-schools-post",
|
||||
"clean-chairs-sit-2",
|
||||
"clean-chairs-sit",
|
||||
"clever-plants-warn",
|
||||
"cold-heads-arrive",
|
||||
"common-heads-build",
|
||||
"crazy-pants-exist",
|
||||
"create-app-1753196727",
|
||||
"create-app-1754401469",
|
||||
"cruel-bars-buy",
|
||||
"cruel-zoos-argue",
|
||||
"eleven-tigers-drop",
|
||||
"every-schools-find",
|
||||
"evil-forks-hang",
|
||||
"evil-phones-unite",
|
||||
"fancy-ducks-help",
|
||||
"fifty-ads-dance",
|
||||
"five-ducks-hide",
|
||||
"floppy-groups-hug",
|
||||
"four-spiders-jump",
|
||||
"free-months-share",
|
||||
"fruity-rockets-rhyme",
|
||||
"full-streets-take",
|
||||
"funny-brooms-trade",
|
||||
"funny-dancers-start",
|
||||
"fuzzy-ducks-speak",
|
||||
"great-snakes-dress",
|
||||
"green-lies-invite copy",
|
||||
"green-lies-invite",
|
||||
"honest-seas-repeat",
|
||||
"hot-clowns-behave",
|
||||
"huge-heads-occur",
|
||||
"huge-paws-design",
|
||||
"itchy-doodles-boil",
|
||||
"little-bugs-care",
|
||||
"long-grapes-glow",
|
||||
"lovely-fans-write",
|
||||
"major-comics-stay",
|
||||
"mighty-cycles-stay",
|
||||
"mira-looking-ostrich",
|
||||
"nej-inte-ostrich",
|
||||
"nice-actors-cheer",
|
||||
"nice-buttons-return",
|
||||
"nice-crabs-clean",
|
||||
"odd-beans-sell",
|
||||
"open-seas-ring",
|
||||
"orange-teams-smell",
|
||||
"polite-trains-notice",
|
||||
"quiet-parks-cheer",
|
||||
"rich-seals-itch",
|
||||
"ripe-comics-sip",
|
||||
"sad-cities-lay",
|
||||
"seven-crabs-stick",
|
||||
"sixty-clowns-float",
|
||||
"small-trams-do",
|
||||
"smart-planes-march",
|
||||
"spotty-clowns-lose",
|
||||
"spotty-icons-shake",
|
||||
"tender-crabs-stay",
|
||||
"thick-breads-add",
|
||||
"thirty-dingos-allow",
|
||||
"thirty-jobs-cut",
|
||||
"tired-lamps-start",
|
||||
"twenty-pumas-brush",
|
||||
"violet-weeks-trade",
|
||||
"whole-hands-cut",
|
||||
"wild-apes-care",
|
||||
"yellow-ducks-burn"
|
||||
]
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/ui': patch
|
||||
---
|
||||
|
||||
Remove stylesheet import from Select component.
|
||||
@@ -32,11 +32,11 @@ Usage of the above example looks as follows:
|
||||
|
||||
```ts
|
||||
const example = ExampleBlueprint.make({
|
||||
params: define => define({
|
||||
params: defineParams => defineParams({
|
||||
component: ...,
|
||||
fetcher: ...,
|
||||
}),
|
||||
});
|
||||
```
|
||||
|
||||
This `define => define(<params>)` is also known as the "callback syntax" and is required if a blueprint is created with the new `defineParams` option. The callback syntax can also optionally be used for other blueprints too, which means that it is not a breaking change to remove the `defineParams` option, as long as the external parameter types remain compatible.
|
||||
This `defineParams => defineParams(<params>)` is also known as the "callback syntax" and is required if a blueprint is created with the new `defineParams` option. The callback syntax can also optionally be used for other blueprints too, which means that it is not a breaking change to remove the `defineParams` option, as long as the external parameter types remain compatible.
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/core-components': patch
|
||||
---
|
||||
|
||||
Updated dependency `linkifyjs` to `4.3.2`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-auth-backend-module-okta-provider': patch
|
||||
---
|
||||
|
||||
Updated dependency `@davidzemon/passport-okta-oauth` to `^0.0.7`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/frontend-plugin-api': patch
|
||||
---
|
||||
|
||||
Updated the recommended naming of the blueprint param callback from `define` to `defineParams`, making the syntax `defineParams => defineParams(...)`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend-module-github': patch
|
||||
---
|
||||
|
||||
Fixed bug in the `customProperties` type which was preventing it being used to set a list of values against a key (e.g. for multi-select fields)
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-events-backend-module-kafka': patch
|
||||
---
|
||||
|
||||
Remove luxon dependency and minor internal improvements
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/frontend-plugin-api': patch
|
||||
---
|
||||
|
||||
Added added defaults for all type parameters of `ExtensionDataRef` and deprecated `AnyExtensionDataRef`, as it is now redundant.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/repo-tools': patch
|
||||
---
|
||||
|
||||
Removed build-in ignore of the `packages/canon` package for knip reports.
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/frontend-plugin-api': patch
|
||||
'@backstage/plugin-app': patch
|
||||
---
|
||||
|
||||
Adjusted the dialog API types to have more sensible defaults
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/ui': patch
|
||||
---
|
||||
|
||||
Add `startCollapsed` prop on the `SearchField` component in BUI.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-react': minor
|
||||
---
|
||||
|
||||
**BREAKING ALPHA**: The `defaultPath`, `defaultTitle`, and `defaultGroup` params of `PageBlueprint` has been renamed to `path`, `title`, and `group`. The `convertLegacyEntityContentExtension` utility has also received the same change. This change does not affect the compatibility of extensions created with older versions of this blueprint.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/frontend-plugin-api': minor
|
||||
---
|
||||
|
||||
**BREAKING**: The `element` param for `AppRootElementBlueprint` no longer accepts a component. If you are currently passing a component such as `element: () => <MyComponent />` or `element: MyComponent`, simply switch to `element: <MyComponent />`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-search-backend-module-catalog': patch
|
||||
---
|
||||
|
||||
Allow filter to be an array in config schema
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/frontend-defaults': patch
|
||||
'@backstage/frontend-app-api': patch
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Deprecated new frontend system config setting `app.experimental.packages` to just `app.packages`. The old config will continue working for the time being, but may be removed in a future release.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/frontend-app-api': patch
|
||||
---
|
||||
|
||||
Added a default implementation of the `SwappableComponentsApi` and removing the legacy `ComponentsApi` implementation
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/create-app': patch
|
||||
---
|
||||
|
||||
Updated the `app.packages` config setting now that it no longer is experimental
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/frontend-plugin-api': patch
|
||||
'@backstage/frontend-app-api': patch
|
||||
---
|
||||
|
||||
Improved runtime error message clarity when extension factories don't return an iterable object.
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/plugin-signals': patch
|
||||
'@backstage/plugin-home': patch
|
||||
---
|
||||
|
||||
**BREAKING ALPHA**: The `app-root-element` extension now only accepts `JSX.Element` in its `element` param, meaning overrides need to be updated.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend-module-github': patch
|
||||
---
|
||||
|
||||
Fix GitHub catalog entity provider branch matching on event processing.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/core-components': patch
|
||||
---
|
||||
|
||||
Added `FavoriteToggleProps`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/frontend-app-api': minor
|
||||
---
|
||||
|
||||
The `AppNodeSpec.plugin` property is now required.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
The Node.js transform in `@backstage/cli/config/nodeTransformHooks.mjs` now supports the built-in type stripping in Node.js, which is enabled by default from v22.18.0.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/frontend-app-api': patch
|
||||
---
|
||||
|
||||
Moved `createSpecializedApp` options to a new `CreateSpecializedAppOptions` type.
|
||||
@@ -0,0 +1,23 @@
|
||||
---
|
||||
'@backstage/frontend-defaults': minor
|
||||
'@backstage/frontend-app-api': minor
|
||||
---
|
||||
|
||||
**BREAKING**: Restructured some of option fields of `createApp` and `createSpecializedApp`.
|
||||
|
||||
- For `createApp`, all option fields _except_ `features` and `bindRoutes` have been moved into a new `advanced` object field.
|
||||
- For `createSpecializedApp`, all option fields _except_ `features`, `config`, and `bindRoutes` have been moved into a new `advanced` object field.
|
||||
|
||||
This helps highlight that some options are meant to rarely be needed or used, and simplifies the usage of those options that are almost always required.
|
||||
|
||||
As an example, if you used to supply a custom config loader, you would update your code as follows:
|
||||
|
||||
```diff
|
||||
createApp({
|
||||
features: [...],
|
||||
- configLoader: new MyCustomLoader(),
|
||||
+ advanced: {
|
||||
+ configLoader: new MyCustomLoader(),
|
||||
+ },
|
||||
})
|
||||
```
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/frontend-plugin-api': patch
|
||||
---
|
||||
|
||||
Added inline documentation for `createExtension`, `createExtensionBlueprint`, `createFrontendPlugin`, and `createFrontendModule`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/frontend-plugin-api': minor
|
||||
---
|
||||
|
||||
**BREAKING**: The `CommonAnalyticsContext` has been removed, and inlined into `AnalyticsContextValue` instead.
|
||||
@@ -28,7 +28,6 @@ yarn.lock @backstage/maintainers @backst
|
||||
/microsite/static @backstage/maintainers @backstage/documentation-maintainers
|
||||
/packages @backstage/framework-maintainers
|
||||
/packages/backend-openapi-utils @backstage/maintainers @backstage/reviewers @backstage/openapi-tooling-maintainers
|
||||
/packages/canon @backstage/design-system-maintainers
|
||||
/packages/catalog-client @backstage/catalog-maintainers
|
||||
/packages/catalog-model @backstage/catalog-maintainers
|
||||
/packages/cli @backstage/tooling-maintainers
|
||||
|
||||
@@ -30,11 +30,6 @@
|
||||
rangeStrategy: 'replace',
|
||||
matchSourceUrls: ['https://github.com/microsoft/rushstack{/,}**'],
|
||||
},
|
||||
{
|
||||
groupName: 'SVGR monorepo packages',
|
||||
rangeStrategy: 'replace',
|
||||
matchSourceUrls: ['https://github.com/gregberge/svgr{/,}**'],
|
||||
},
|
||||
{
|
||||
groupName: 'Module-federation monorepo packages',
|
||||
rangeStrategy: 'replace',
|
||||
|
||||
@@ -324,6 +324,8 @@ pagerduty
|
||||
pageview
|
||||
Pandey
|
||||
parallelization
|
||||
param
|
||||
params
|
||||
parseable
|
||||
Patrik
|
||||
pattison
|
||||
@@ -378,6 +380,7 @@ replicasets
|
||||
repo
|
||||
Repo
|
||||
repos
|
||||
requestors
|
||||
rerender
|
||||
rerenders
|
||||
resourcequotas
|
||||
@@ -385,6 +388,9 @@ retryable
|
||||
reusability
|
||||
Reusability
|
||||
roadmaps
|
||||
rollbar
|
||||
rollout
|
||||
rollouts
|
||||
Roboto
|
||||
rollbar
|
||||
Rollbar
|
||||
@@ -461,6 +467,7 @@ Superfences
|
||||
superset
|
||||
supertype
|
||||
SVGs
|
||||
swappable
|
||||
talkdesk
|
||||
Talkdesk
|
||||
Tanzu
|
||||
@@ -545,3 +552,4 @@ zod
|
||||
Zolotusky
|
||||
zoomable
|
||||
zsh
|
||||
resizable
|
||||
|
||||
@@ -74,7 +74,7 @@ jobs:
|
||||
|
||||
- name: Cache Comment
|
||||
if: ${{ steps.event.outputs.ACTION != 'closed' }}
|
||||
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
||||
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
|
||||
with:
|
||||
path: comment.md
|
||||
key: ${{ steps.hash.outputs.COMMENT_FILE_HASH }}
|
||||
|
||||
@@ -127,10 +127,6 @@ jobs:
|
||||
- name: build all packages
|
||||
run: yarn backstage-cli repo build --all
|
||||
|
||||
# For now canon has a custom build script and needs to be built separately
|
||||
- name: build canon
|
||||
run: yarn --cwd packages/canon build
|
||||
|
||||
# For now BUI has a custom build script and needs to be built separately
|
||||
- name: build BUI
|
||||
run: yarn --cwd packages/ui build
|
||||
|
||||
@@ -110,10 +110,6 @@ jobs:
|
||||
- name: build
|
||||
run: yarn backstage-cli repo build --all
|
||||
|
||||
# For now canon has a custom build script and needs to be built separately
|
||||
- name: build canon
|
||||
run: yarn --cwd packages/canon build
|
||||
|
||||
# For now BUI has a custom build script and needs to be built separately
|
||||
- name: build BUI
|
||||
run: yarn --cwd packages/ui build
|
||||
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
persist-credentials: false
|
||||
|
||||
- name: 'Run analysis'
|
||||
uses: ossf/scorecard-action@dc50aa9510b46c811795eb24b2f1ba02a914e534 # v2.3.3
|
||||
uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
@@ -67,6 +67,6 @@ jobs:
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: 'Upload to code-scanning'
|
||||
uses: github/codeql-action/upload-sarif@60168efe1c415ce0f5521ea06d5c2062adbeed1b # v3.28.17
|
||||
uses: github/codeql-action/upload-sarif@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
name: Sync Canon Docs
|
||||
name: Sync BUI Docs
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
- name: Configure Git
|
||||
run: |
|
||||
git config --global user.email noreply@backstage.io
|
||||
git config --global user.name 'Github Canon Docs workflow'
|
||||
git config --global user.name 'Github BUI Docs workflow'
|
||||
|
||||
- name: Install dependencies
|
||||
working-directory: docs-ui
|
||||
@@ -53,9 +53,9 @@ jobs:
|
||||
git rm -rf .
|
||||
cp -R ../docs-ui/dist/. .
|
||||
|
||||
- name: Commit to canon-storybook repo
|
||||
- name: Commit to bui-storybook repo
|
||||
working-directory: bui-external-docs
|
||||
run: |
|
||||
git add .
|
||||
git commit -am "Canon Docs build for backstage/backstage@${{ github.sha }}"
|
||||
git commit -am "BUI Docs build for backstage/backstage@${{ github.sha }}"
|
||||
git push
|
||||
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
cache-prefix: ${{ runner.os }}-v20.x
|
||||
|
||||
- name: Create Snyk report
|
||||
uses: snyk/actions/node@cdb760004ba9ea4d525f2e043745dfe85bb9077e # master
|
||||
uses: snyk/actions/node@77490d94e966421e076e95ad8fa87aa55e5ca409 # master
|
||||
continue-on-error: true # Snyk CLI exits with error when vulnerabilities are found
|
||||
with:
|
||||
args: >
|
||||
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- name: Monitor and Synchronize Snyk Policies
|
||||
uses: snyk/actions/node@cdb760004ba9ea4d525f2e043745dfe85bb9077e # master
|
||||
uses: snyk/actions/node@77490d94e966421e076e95ad8fa87aa55e5ca409 # master
|
||||
with:
|
||||
command: monitor
|
||||
args: >
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
# Above we run the `monitor` command, this runs the `test` command which is
|
||||
# the one that generates the SARIF report that we can upload to GitHub.
|
||||
- name: Create Snyk report
|
||||
uses: snyk/actions/node@cdb760004ba9ea4d525f2e043745dfe85bb9077e # master
|
||||
uses: snyk/actions/node@77490d94e966421e076e95ad8fa87aa55e5ca409 # master
|
||||
continue-on-error: true # To make sure that SARIF upload gets called
|
||||
with:
|
||||
args: >
|
||||
@@ -58,6 +58,6 @@ jobs:
|
||||
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
|
||||
NODE_OPTIONS: --max-old-space-size=7168
|
||||
- name: Upload Snyk report
|
||||
uses: github/codeql-action/upload-sarif@60168efe1c415ce0f5521ea06d5c2062adbeed1b # v3.28.17
|
||||
uses: github/codeql-action/upload-sarif@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
|
||||
with:
|
||||
sarif_file: snyk.sarif
|
||||
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@60168efe1c415ce0f5521ea06d5c2062adbeed1b # v3.28.17
|
||||
uses: github/codeql-action/init@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
@@ -66,7 +66,7 @@ jobs:
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@60168efe1c415ce0f5521ea06d5c2062adbeed1b # v3.28.17
|
||||
uses: github/codeql-action/autobuild@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
@@ -80,4 +80,4 @@ jobs:
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@60168efe1c415ce0f5521ea06d5c2062adbeed1b # v3.28.17
|
||||
uses: github/codeql-action/analyze@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
|
||||
|
||||
@@ -40,7 +40,7 @@ These labels indicate which part of Backstage an issue or pull request relates t
|
||||
- `area:auditor` - Auditor service and it's use in plugins.
|
||||
- `area:auth` - Authentication and 3rd party authorization.
|
||||
- `area:catalog` - The Catalog plugin and the Software Catalog model and integrations.
|
||||
- `area:design-system` - The Canon design system and library.
|
||||
- `area:design-system` - The Backstage UI design system and library.
|
||||
- `area:documentation` - Documentation for adopters, users, and developers.
|
||||
- `area:events` - The Events system and integrations for other plugins.
|
||||
- `area:framework` - The core Backstage framework.
|
||||
|
||||
+1
-2
@@ -1,8 +1,7 @@
|
||||
app:
|
||||
title: Backstage Example App
|
||||
baseUrl: http://localhost:3000
|
||||
experimental:
|
||||
packages: all # ✨
|
||||
packages: all # ✨
|
||||
|
||||
#datadogRum:
|
||||
# clientToken: '123456789'
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
"sync:css:watch": "node scripts/sync-css.js --watch"
|
||||
},
|
||||
"resolutions": {
|
||||
"@types/react": "19.1.8",
|
||||
"@types/react-dom": "19.1.6"
|
||||
"@types/react": "19.1.9",
|
||||
"@types/react-dom": "19.1.7"
|
||||
},
|
||||
"dependencies": {
|
||||
"@codemirror/lang-sass": "^6.0.2",
|
||||
@@ -31,16 +31,16 @@
|
||||
"next": "15.3.4",
|
||||
"next-mdx-remote-client": "^2.1.2",
|
||||
"prop-types": "^15.8.1",
|
||||
"react": "19.1.0",
|
||||
"react-dom": "19.1.0",
|
||||
"react": "19.1.1",
|
||||
"react-dom": "19.1.1",
|
||||
"shiki": "^1.26.1",
|
||||
"storybook": "^8.6.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/mdx": "^2.0.13",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "19.1.8",
|
||||
"@types/react-dom": "19.1.6",
|
||||
"@types/react": "19.1.9",
|
||||
"@types/react-dom": "19.1.7",
|
||||
"chokidar": "^3.6.0",
|
||||
"concurrently": "^8.2.2",
|
||||
"eslint": "^8",
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -65,6 +65,24 @@ export const propDefs: Record<string, PropDef> = {
|
||||
},
|
||||
},
|
||||
},
|
||||
breadcrumbs: {
|
||||
type: 'complex',
|
||||
complexType: {
|
||||
name: 'Breadcrumb[]',
|
||||
properties: {
|
||||
label: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'Display text for the breadcrumb',
|
||||
},
|
||||
href: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'URL for the breadcrumb link',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
...childrenPropDefs,
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
|
||||
@@ -18,24 +18,6 @@ export const propDefs: Record<string, PropDef> = {
|
||||
type: 'string',
|
||||
default: '/',
|
||||
},
|
||||
breadcrumbs: {
|
||||
type: 'complex',
|
||||
complexType: {
|
||||
name: 'Breadcrumb[]',
|
||||
properties: {
|
||||
label: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'Display text for the breadcrumb',
|
||||
},
|
||||
href: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'URL for the breadcrumb link',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
customActions: {
|
||||
type: 'enum',
|
||||
values: ['ReactNode'],
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
searchFieldDefaultSnippet,
|
||||
searchFieldSizesSnippet,
|
||||
searchFieldDescriptionSnippet,
|
||||
searchFieldCollapsibleSnippet,
|
||||
} from './search-field.props';
|
||||
import { PageTitle } from '@/components/PageTitle';
|
||||
import { Theming } from '@/components/Theming';
|
||||
@@ -59,6 +60,18 @@ Here's a simple SearchField with a description.
|
||||
code={searchFieldDescriptionSnippet}
|
||||
/>
|
||||
|
||||
### Collapsible
|
||||
|
||||
You can make the SearchField collapsible by setting the `startCollapsed` prop to `true`.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<SearchFieldSnippet story="StartCollapsed" />}
|
||||
code={searchFieldCollapsibleSnippet}
|
||||
/>
|
||||
|
||||
<Theming component="SearchField" />
|
||||
|
||||
<ChangelogComponent component="search-field" />
|
||||
|
||||
@@ -25,6 +25,10 @@ export const searchFieldPropDefs: Record<string, PropDef> = {
|
||||
type: 'string',
|
||||
required: true,
|
||||
},
|
||||
startCollapsed: {
|
||||
type: 'boolean',
|
||||
default: 'false',
|
||||
},
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
@@ -41,3 +45,5 @@ export const searchFieldSizesSnippet = `<Flex direction="row" gap="4">
|
||||
</Flex>`;
|
||||
|
||||
export const searchFieldDescriptionSnippet = `<SearchField label="Label" description="Description" placeholder="Enter a URL" />`;
|
||||
|
||||
export const searchFieldCollapsibleSnippet = `<SearchField startCollapsed />`;
|
||||
|
||||
+49
-49
@@ -1201,21 +1201,21 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/react-dom@npm:19.1.6":
|
||||
version: 19.1.6
|
||||
resolution: "@types/react-dom@npm:19.1.6"
|
||||
"@types/react-dom@npm:19.1.7":
|
||||
version: 19.1.7
|
||||
resolution: "@types/react-dom@npm:19.1.7"
|
||||
peerDependencies:
|
||||
"@types/react": ^19.0.0
|
||||
checksum: 10/b5b20b7f0797f34c5a11915b74dcf8b3b7a9da9fea90279975ce6f150ca5d31bb069dbb0838638a5e9e168098aa4bb4a6f61d078efa1bbb55d7f0bdfe47bb142
|
||||
checksum: 10/a99465e5a17d40725dedb3708357f8998c57caab768cee0992b4bb7822ce7ed2ec697a5f426cb98d3397b020756a6e4b0986dc5f6f4254e13b3536afb38538e6
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/react@npm:19.1.8":
|
||||
version: 19.1.8
|
||||
resolution: "@types/react@npm:19.1.8"
|
||||
"@types/react@npm:19.1.9":
|
||||
version: 19.1.9
|
||||
resolution: "@types/react@npm:19.1.9"
|
||||
dependencies:
|
||||
csstype: "npm:^3.0.2"
|
||||
checksum: 10/a3e6fe0f60f22828ef887f30993aa147b71532d7b1219dd00d246277eb7a9ca01ec533096237fa21ca1bccb3653373b4e8e59e5ae59f9c793058384bbc1f4d5c
|
||||
checksum: 10/b1032eae52e3b4f2a8b9ea6aac936385a78b7eff55cad4ff4f0d7e726c6ea87c1f287a1ba0e57a76a8e4456d3fb918b4f97a01e71686fdc11a65b26b8d296be4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -1369,9 +1369,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@uiw/codemirror-extensions-basic-setup@npm:4.23.13":
|
||||
version: 4.23.13
|
||||
resolution: "@uiw/codemirror-extensions-basic-setup@npm:4.23.13"
|
||||
"@uiw/codemirror-extensions-basic-setup@npm:4.24.2":
|
||||
version: 4.24.2
|
||||
resolution: "@uiw/codemirror-extensions-basic-setup@npm:4.24.2"
|
||||
dependencies:
|
||||
"@codemirror/autocomplete": "npm:^6.0.0"
|
||||
"@codemirror/commands": "npm:^6.0.0"
|
||||
@@ -1388,7 +1388,7 @@ __metadata:
|
||||
"@codemirror/search": ">=6.0.0"
|
||||
"@codemirror/state": ">=6.0.0"
|
||||
"@codemirror/view": ">=6.0.0"
|
||||
checksum: 10/35fd1894f9f7da8f94fa077a70821f92118597e2e2b12782b254b0844f06c1855508421c4cb47de7099a972ef706218c08203116aa93da4e8e1585c8d234015d
|
||||
checksum: 10/077f64b4bbb6178038d30a3cb2961c0ff89c0836b73210d0ac3fca828c3ba8fbce61e42635ec2e2997cdffff5472b75ad58541c4e62f98d52b83d475da0c56eb
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -1408,14 +1408,14 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"@uiw/react-codemirror@npm:^4.23.7":
|
||||
version: 4.23.13
|
||||
resolution: "@uiw/react-codemirror@npm:4.23.13"
|
||||
version: 4.24.2
|
||||
resolution: "@uiw/react-codemirror@npm:4.24.2"
|
||||
dependencies:
|
||||
"@babel/runtime": "npm:^7.18.6"
|
||||
"@codemirror/commands": "npm:^6.1.0"
|
||||
"@codemirror/state": "npm:^6.1.1"
|
||||
"@codemirror/theme-one-dark": "npm:^6.0.0"
|
||||
"@uiw/codemirror-extensions-basic-setup": "npm:4.23.13"
|
||||
"@uiw/codemirror-extensions-basic-setup": "npm:4.24.2"
|
||||
codemirror: "npm:^6.0.0"
|
||||
peerDependencies:
|
||||
"@babel/runtime": ">=7.11.0"
|
||||
@@ -1423,9 +1423,9 @@ __metadata:
|
||||
"@codemirror/theme-one-dark": ">=6.0.0"
|
||||
"@codemirror/view": ">=6.0.0"
|
||||
codemirror: ">=6.0.0"
|
||||
react: ">=16.8.0"
|
||||
react-dom: ">=16.8.0"
|
||||
checksum: 10/51777d7eb313be0716d3597f829e6ee9982ab2dc3e36dc5219f25cdf680b82a6c0a0951d9adaca85b9c829da92f7971aa6e65bdd50e7610972d89463fe2587a1
|
||||
react: ">=17.0.0"
|
||||
react-dom: ">=17.0.0"
|
||||
checksum: 10/f0816fcf40c451c8bc15319d62f5b8d62a04c12c2bc053569212b31edba7c7164e45fd161ebb683a03fd5a50697b91a6ac4cab2d2d1a45da5f2626d959c399a0
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -2315,8 +2315,8 @@ __metadata:
|
||||
"@storybook/react": "npm:^8.6.8"
|
||||
"@types/mdx": "npm:^2.0.13"
|
||||
"@types/node": "npm:^20"
|
||||
"@types/react": "npm:19.1.8"
|
||||
"@types/react-dom": "npm:19.1.6"
|
||||
"@types/react": "npm:19.1.9"
|
||||
"@types/react-dom": "npm:19.1.7"
|
||||
"@uiw/codemirror-themes": "npm:^4.23.7"
|
||||
"@uiw/react-codemirror": "npm:^4.23.7"
|
||||
chokidar: "npm:^3.6.0"
|
||||
@@ -2329,8 +2329,8 @@ __metadata:
|
||||
next: "npm:15.3.4"
|
||||
next-mdx-remote-client: "npm:^2.1.2"
|
||||
prop-types: "npm:^15.8.1"
|
||||
react: "npm:19.1.0"
|
||||
react-dom: "npm:19.1.0"
|
||||
react: "npm:19.1.1"
|
||||
react-dom: "npm:19.1.1"
|
||||
shiki: "npm:^1.26.1"
|
||||
storybook: "npm:^8.6.8"
|
||||
typescript: "npm:^5"
|
||||
@@ -3618,20 +3618,20 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"html-react-parser@npm:^5.2.5":
|
||||
version: 5.2.5
|
||||
resolution: "html-react-parser@npm:5.2.5"
|
||||
version: 5.2.6
|
||||
resolution: "html-react-parser@npm:5.2.6"
|
||||
dependencies:
|
||||
domhandler: "npm:5.0.3"
|
||||
html-dom-parser: "npm:5.1.1"
|
||||
react-property: "npm:2.0.2"
|
||||
style-to-js: "npm:1.1.16"
|
||||
style-to-js: "npm:1.1.17"
|
||||
peerDependencies:
|
||||
"@types/react": 0.14 || 15 || 16 || 17 || 18 || 19
|
||||
react: 0.14 || 15 || 16 || 17 || 18 || 19
|
||||
peerDependenciesMeta:
|
||||
"@types/react":
|
||||
optional: true
|
||||
checksum: 10/22852dc4826d3be9506e238e37a05c23b432675aac33f22bd5741caa195a32e99de99d2b99037fda532f198afbcdeacfc0b27627d6e529143a98c8f191e99c52
|
||||
checksum: 10/be2903fd932d44ff6cae66bd18b025d318879e16eb1e67c0ae6dc640e5c77509da41b61948c0d404a43b5362b57b7cfa3963df242b9773d4c7a16f410db7f2ac
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -5135,20 +5135,20 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"next-mdx-remote-client@npm:^2.1.2":
|
||||
version: 2.1.2
|
||||
resolution: "next-mdx-remote-client@npm:2.1.2"
|
||||
version: 2.1.3
|
||||
resolution: "next-mdx-remote-client@npm:2.1.3"
|
||||
dependencies:
|
||||
"@babel/code-frame": "npm:^7.27.1"
|
||||
"@mdx-js/mdx": "npm:^3.1.0"
|
||||
"@mdx-js/react": "npm:^3.1.0"
|
||||
remark-mdx-remove-esm: "npm:^1.1.0"
|
||||
remark-mdx-remove-esm: "npm:^1.2.0"
|
||||
serialize-error: "npm:^12.0.0"
|
||||
vfile: "npm:^6.0.3"
|
||||
vfile-matter: "npm:^5.0.1"
|
||||
peerDependencies:
|
||||
react: ^19.1.0
|
||||
react-dom: ^19.1.0
|
||||
checksum: 10/610e95bff6c1dcdb4d1fefc9333ac748f1899cbca1ea551e784cd1e8cfd077c14d6bb8ab27826886f354cc3b9cf700fe25810263f996c53f824a2cfdbc5a064f
|
||||
checksum: 10/3837c63edf7d707de2eea9b4c565eeb7e505a769e93c2673f746ec9993c644f7cd0aacb8bad911eff9ea63190f48c2c16ffe98d47c39591c5dac29c8bf9a9e0c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -5585,14 +5585,14 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-dom@npm:19.1.0":
|
||||
version: 19.1.0
|
||||
resolution: "react-dom@npm:19.1.0"
|
||||
"react-dom@npm:19.1.1":
|
||||
version: 19.1.1
|
||||
resolution: "react-dom@npm:19.1.1"
|
||||
dependencies:
|
||||
scheduler: "npm:^0.26.0"
|
||||
peerDependencies:
|
||||
react: ^19.1.0
|
||||
checksum: 10/c5b58605862c7b0bb044416b01c73647bb8e89717fb5d7a2c279b11815fb7b49b619fe685c404e59f55eb52c66831236cc565c25ee1c2d042739f4a2cc538aa2
|
||||
react: ^19.1.1
|
||||
checksum: 10/9005415d2175b1f1eb4a544ad04afb29691bb7b6dd43bbdaa09932146b310b73bd4552bc772ad78fa481f409eada1560cf887606c83c1a53a922c1e30f1b3a34
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -5610,10 +5610,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react@npm:19.1.0":
|
||||
version: 19.1.0
|
||||
resolution: "react@npm:19.1.0"
|
||||
checksum: 10/d0180689826fd9de87e839c365f6f361c561daea397d61d724687cae88f432a307d1c0f53a0ee95ddbe3352c10dac41d7ff1ad85530fb24951b27a39e5398db4
|
||||
"react@npm:19.1.1":
|
||||
version: 19.1.1
|
||||
resolution: "react@npm:19.1.1"
|
||||
checksum: 10/9801530fdc939e1a7a499422e930515b2400809cb39c2872984e99f832d233f61659a693871183dac3155c2f9b2c9dcf4440a56bd18983277ae92860e38c3a61
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -5754,7 +5754,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"remark-mdx-remove-esm@npm:^1.1.0":
|
||||
"remark-mdx-remove-esm@npm:^1.2.0":
|
||||
version: 1.2.0
|
||||
resolution: "remark-mdx-remove-esm@npm:1.2.0"
|
||||
dependencies:
|
||||
@@ -6480,21 +6480,21 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"style-to-js@npm:1.1.16, style-to-js@npm:^1.0.0":
|
||||
version: 1.1.16
|
||||
resolution: "style-to-js@npm:1.1.16"
|
||||
"style-to-js@npm:1.1.17, style-to-js@npm:^1.0.0":
|
||||
version: 1.1.17
|
||||
resolution: "style-to-js@npm:1.1.17"
|
||||
dependencies:
|
||||
style-to-object: "npm:1.0.8"
|
||||
checksum: 10/a876cc49a29ac90c7723b4d6f002ac6c1ac5ccc6b5bc963d9c607cfc74b15927b704c9324df6f824f576c65689fe4b4ff79caabcd44a13d8a02641f721f1b316
|
||||
style-to-object: "npm:1.0.9"
|
||||
checksum: 10/431f2fca8a55a61939a83ff0f58638e2996621ad93a97cf93f2be5115f411330d4e506ccf18621bd45607ec161546b763bb6961ad08238ad939b6261ff377230
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"style-to-object@npm:1.0.8":
|
||||
version: 1.0.8
|
||||
resolution: "style-to-object@npm:1.0.8"
|
||||
"style-to-object@npm:1.0.9":
|
||||
version: 1.0.9
|
||||
resolution: "style-to-object@npm:1.0.9"
|
||||
dependencies:
|
||||
inline-style-parser: "npm:0.2.4"
|
||||
checksum: 10/530b067325e3119bfaf75bdbe25cc86b02b559db00d881a74b98a2d5bb10ac953d1b455ed90c825963cf3b4bdaa1bda45f406d78d987391434b8d8ab3835df4e
|
||||
checksum: 10/fd0c131a83103fe4025afd8e0fd90c605054d485ad80f2ab402e7afa79f482f4b05fff40b6aa661cb1b835e5c56bb0644dc38cbf9b3d2982fc552435db3dae50
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
---
|
||||
id: adrs-adr015
|
||||
title: 'ADR015: Types and naming for element and component options'
|
||||
description: Architecture Decision Record (ADR) for the proper types and naming for element and component options
|
||||
---
|
||||
|
||||
## Context
|
||||
|
||||
Until now there hasn't been a clear standard for how to define options that are intended to provide JSX elements or components. This led to a mix of different patterns in public APIs, which this ADR aims to standardize.
|
||||
|
||||
## Decision
|
||||
|
||||
We will use one of the following option property names and types when defining options that are intended to provide JSX elements or components:
|
||||
|
||||
### Simple element
|
||||
|
||||
This option is used when a simple synchronous JSX element is provided. It must only be used in areas where lazy-loading is not needed.
|
||||
|
||||
```tsx
|
||||
{
|
||||
element: JSX.Element;
|
||||
}
|
||||
```
|
||||
|
||||
### Simple component
|
||||
|
||||
This option is used when a simple synchronous component is provided. It must only be used in areas where lazy-loading is not needed.
|
||||
|
||||
```tsx
|
||||
{
|
||||
component: (props: { ... }) => JSX.Element | null
|
||||
}
|
||||
```
|
||||
|
||||
### Async element loader
|
||||
|
||||
This option is used when a simple asynchronous JSX element is provided. It is the preferred option when only producing a single instance and there is no need to pass properties to the component. This format simplifies the creation of closures for passing additional properties in the loader implementation.
|
||||
|
||||
```tsx
|
||||
{
|
||||
loader: () => Promise<JSX.Element>;
|
||||
}
|
||||
```
|
||||
|
||||
### Async component loader
|
||||
|
||||
This option is used when a simple asynchronous component is provided. It is the preferred option when properties need to be passed to the component or multiple instance are needed, and lazy-loading is required.
|
||||
|
||||
```tsx
|
||||
{
|
||||
loader: () => Promise<(props: { ... }) => JSX.Element | null>
|
||||
}
|
||||
```
|
||||
|
||||
### Any component loader
|
||||
|
||||
This option is used in the same cases as the async component loader, but when the option of synchronous loading is also needed. The structure of always having the outer loader function, even in the synchronous case, makes it possible to determine the type of the loader at runtime.
|
||||
|
||||
```tsx
|
||||
{
|
||||
loader: (() => props => JSX.Element | null) | (() => Promise<props => JSX.Element | null>)
|
||||
}
|
||||
```
|
||||
|
||||
Note that when consuming this loader we'll need to unconditionally wrap it with `React.lazy`. This is because you can't delay the call to `React.lazy` until rendering, because you're not allowed to call it within a render function. This means that we can't first call the loader to check whether the returned value is a promise or not, and we must instead unconditionally wrap it with `React.lazy`. Therefore the implementation of accepting one of these loaders as an option needs to look something like this:
|
||||
|
||||
```tsx
|
||||
const LazyComponent = React.lazy(() =>
|
||||
Promise.resolve(options.loader()).then(loaded => ({ default: loaded })),
|
||||
);
|
||||
```
|
||||
|
||||
## Consequences
|
||||
|
||||
We will update all APIs for the new frontend system in the `@backstage/frontend-*` packages.
|
||||
|
||||
We will not update any of the existing APIs for the old frontend system in the `@backstage/core-*` packages.
|
||||
@@ -366,7 +366,7 @@ your first set of parameter fields would be shown. The same goes for the nested
|
||||
spec. Make sure to use the key `backstage:featureFlag` in your templates if
|
||||
you want to use this functionality.
|
||||
|
||||
Feature Flags cannot be used in `spec.steps[].if`(the conditional on whether to execute an step/action). But you can use feature flags to display parameters that allow for skipping steps.
|
||||
Feature Flags cannot be used in `spec.steps[].if`(the conditional on whether to execute a step/action). But you can use feature flags to display parameters that allow for skipping steps.
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
@@ -807,7 +807,7 @@ Have in mind that changes in this form will not be saved on the template and is
|
||||
|
||||
### Custom Field Explorer
|
||||
|
||||
The custom filed explorer allows you to select any custom field loaded on the backstage instance and test different values and configurations.
|
||||
The custom field explorer allows you to select any custom field loaded on the backstage instance and test different values and configurations.
|
||||
|
||||
## Presentation
|
||||
|
||||
|
||||
@@ -48,31 +48,28 @@ App feature discovery lets you automatically discover and install features provi
|
||||
|
||||
Because feature discovery needs to interact with the compilation process, it is only available when using the `@backstage/cli` to build your app. It is hooked into the WebPack compilation process by scanning your app package for compatible dependencies, which are then made part of the app compilation bundle.
|
||||
|
||||
Since the `@backstage/cli` is a more stable component than the new frontend system, feature discovery is currently marked as an experimental feature of the CLI and needs to be enabled manually. To enable it, add the following configuration to your `app-config.yaml`:
|
||||
To enable frontend feature discovery, add the following configuration to your `app-config.yaml`:
|
||||
|
||||
```yaml
|
||||
app:
|
||||
experimental:
|
||||
packages: all
|
||||
packages: all
|
||||
```
|
||||
|
||||
This will cause all dependencies in your app package to be installed automatically. If this is not desired, you can use include or exclude filters to narrow down the set of packages:
|
||||
|
||||
```yaml
|
||||
app:
|
||||
experimental:
|
||||
packages:
|
||||
# Only the following packages will be included
|
||||
include:
|
||||
- '@backstage/plugin-catalog'
|
||||
- '@backstage/plugin-scaffolder'
|
||||
packages:
|
||||
# Only the following packages will be included
|
||||
include:
|
||||
- '@backstage/plugin-catalog'
|
||||
- '@backstage/plugin-scaffolder'
|
||||
---
|
||||
app:
|
||||
experimental:
|
||||
packages:
|
||||
# All but the following package will be included
|
||||
exclude:
|
||||
- '@backstage/plugin-catalog'
|
||||
packages:
|
||||
# All but the following package will be included
|
||||
exclude:
|
||||
- '@backstage/plugin-catalog'
|
||||
```
|
||||
|
||||
Note that you do not need to manually exclude packages that you also import explicitly in code, since plugin instances are deduplicated by the app. You will never end up with duplicate plugin installations except if they are in fact two different plugin instances with different IDs.
|
||||
|
||||
@@ -21,7 +21,7 @@ Frontend plugin instances are created with the `createFrontendPlugin` function,
|
||||
// This creates a new extension, see "Extension Blueprints" documentation for more details
|
||||
const myPage = PageBlueprint.make({
|
||||
params: {
|
||||
defaultPath: '/my-page',
|
||||
path: '/my-page',
|
||||
loader: () => import('./MyPage').then(m => <m.MyPage />),
|
||||
},
|
||||
});
|
||||
@@ -107,7 +107,7 @@ export default plugin.withOverrides({
|
||||
// Override the catalog index page with a completely custom implementation
|
||||
PageBlueprint.make({
|
||||
params: {
|
||||
defaultPath: '/catalog',
|
||||
path: '/catalog',
|
||||
routeRef: plugin.routes.catalogIndex,
|
||||
loader: () => import('./CustomCatalogIndexPage').then(m => <m.Page />),
|
||||
},
|
||||
|
||||
@@ -18,7 +18,7 @@ The following is a simple example of how one might use the blueprint `make` meth
|
||||
```tsx
|
||||
const myPageExtension = PageBlueprint.make({
|
||||
params: {
|
||||
defaultPath: '/my-page',
|
||||
path: '/my-page',
|
||||
loader: () => import('./components/MyPage').then(m => <m.MyPage />),
|
||||
},
|
||||
});
|
||||
@@ -26,7 +26,7 @@ const myPageExtension = PageBlueprint.make({
|
||||
|
||||
The returned `myPageExtension` is an extension which is ready to be used in a plugin. It is the same type of object as is returned by the lower level `createExtension` function.
|
||||
|
||||
## Creating an extension from a blueprint with overrides
|
||||
### Creating an extension from a blueprint with overrides
|
||||
|
||||
Every extension blueprint also provides a `makeWithOverrides` method. It is useful in cases where you want to provide additional integration points for an extension created with a blueprint. You might for example want to define additional inputs or configuration schema, or use the existing configuration to dynamically compute the parameters passed to the blueprint.
|
||||
|
||||
@@ -34,22 +34,34 @@ The following is an example of how one might use the blueprint `makeWithOverride
|
||||
|
||||
```tsx
|
||||
const myPageExtension = PageBlueprint.makeWithOverrides({
|
||||
// This defines additional configuration options for the extension.
|
||||
config: {
|
||||
schema: {
|
||||
layout: z => z.enum(['grid', 'rows']).default('grid'),
|
||||
},
|
||||
},
|
||||
// The original blueprint factory is provided as the first argument
|
||||
factory(originalFactory, { config }) {
|
||||
// This defines additional inputs for the extension.
|
||||
inputs: {
|
||||
content: createExtensionInput([coreExtensionData.reactElement], {
|
||||
singleton: true,
|
||||
optional: true,
|
||||
}),
|
||||
},
|
||||
// The original blueprint factory is provided as the first argument.
|
||||
// By convention the name is `originalFactory`, but you can also pick a different name.
|
||||
factory(originalFactory, { config, inputs }) {
|
||||
// Call and forward the result from the original factory, providing
|
||||
// the blueprint parameters as the first argument.
|
||||
return originalFactory({
|
||||
defaultPath: '/my-page',
|
||||
path: '/my-page',
|
||||
loader: () =>
|
||||
import('./components/MyPage').then(m => (
|
||||
// We can now access values from the factory context when providing
|
||||
// the blueprint parameters, such as config values.
|
||||
<m.MyPage layout={config.layout} />
|
||||
// the blueprint parameters, such as config values and inputs.
|
||||
<m.MyPage
|
||||
layout={config.layout}
|
||||
content={inputs.content?.get(coreExtensionData.reactElement)}
|
||||
/>
|
||||
)),
|
||||
});
|
||||
},
|
||||
@@ -58,18 +70,18 @@ const myPageExtension = PageBlueprint.makeWithOverrides({
|
||||
|
||||
When using `makeWithOverrides`, we no longer pass the blueprint parameters directly. Instead, we provide a `factory` function that receives the original blueprint factory as the first argument, and the extension factory context as the second. We can then call the original blueprint factory with the blueprint parameters and forward the result as the return value of out factory. Notice that when passing the blueprint parameters using this pattern we have access to a lot more information than when using the `make` method, at the cost of being more complex.
|
||||
|
||||
Apart from the addition of the blueprint parameters of the first argument to the original factory function, the `makeWithOverrides` method works the same way as [extension overrides](./25-extension-overrides.md). All the same options and rules apply, including the ability to define additional inputs, override outputs, and so on. We therefore defer to the [extension overrides](./25-extension-overrides.md) documentation for more information on how to use the `makeWithOverrides` method.
|
||||
Apart from the addition of the blueprint parameters of the first argument to the original factory function, the `makeWithOverrides` method works the same way as [extension overrides](./25-extension-overrides.md). All the same options and rules apply, including the ability to define additional inputs, override outputs, and so on. For more details and examples on how this works, please refer to the [extension overrides](./25-extension-overrides.md) documentation. The patterns in that section also apply to the creation of extensions with the `makeWithOverrides` method.
|
||||
|
||||
### Creating an extension from a blueprint with advanced parameter types
|
||||
|
||||
Some blueprints may be defined with something known as "advanced parameter types". This is a feature that enables type inference and transform of the blueprint parameters, and the way that you pass the parameters look a little bit different. Rather than passing the parameters directly, they are instead passed as a callback function of the form `define => define(<params>)`.
|
||||
Some blueprints may be defined with something known as "advanced parameter types". This is a feature that enables type inference and transform of the blueprint parameters, and the way that you pass the parameters look a little bit different. Rather than passing the parameters directly, they are instead passed as a callback function of the form `defineParams => defineParams(<params>)`.
|
||||
|
||||
An example of a blueprint that uses advanced parameter types is the `ApiBlueprint` blueprint. Using it to create a simple implementation for the `AlertApi` might look like this:
|
||||
|
||||
```ts
|
||||
const alertApiBlueprint = ApiBlueprint.make({
|
||||
params: define =>
|
||||
define({
|
||||
params: defineParams =>
|
||||
defineParams({
|
||||
api: alertApiRef,
|
||||
deps: {},
|
||||
factory: () => new MyAlertApi(),
|
||||
@@ -82,8 +94,8 @@ This also works with `makeWithOverrides`, where the define callback is passed as
|
||||
```ts
|
||||
const alertApiBlueprint = ApiBlueprint.makeWithOverrides({
|
||||
factory(originalFactory, { config }) {
|
||||
return originalFactory(define =>
|
||||
define({
|
||||
return originalFactory(defineParams =>
|
||||
defineParams({
|
||||
api: alertApiRef,
|
||||
deps: {},
|
||||
factory: () => new MyAlertApi(config),
|
||||
@@ -101,7 +113,7 @@ The following is an example of how one might create a new extension blueprint:
|
||||
|
||||
```tsx
|
||||
export interface MyWidgetBlueprintParams {
|
||||
defaultTitle: string;
|
||||
title: string;
|
||||
element: JSX.Element;
|
||||
}
|
||||
|
||||
@@ -119,7 +131,7 @@ export const MyWidgetBlueprint = createExtensionBlueprint({
|
||||
// Note that while this is a valid pattern, you might often want to
|
||||
// return separate pieces of data instead, more on that below.
|
||||
coreExtensionData.reactElement(
|
||||
<MyWidgetContainer title={config.title ?? params.defaultTitle}>
|
||||
<MyWidgetContainer title={config.title ?? params.title}>
|
||||
{params.element}
|
||||
</MyWidgetContainer>,
|
||||
),
|
||||
@@ -175,7 +187,7 @@ To do that, we create a new extension data reference for our widget title. This
|
||||
|
||||
```tsx
|
||||
export interface MyWidgetBlueprintParams {
|
||||
defaultTitle: string;
|
||||
title: string;
|
||||
element: JSX.Element;
|
||||
}
|
||||
|
||||
@@ -194,7 +206,7 @@ export const MyWidgetBlueprint = createExtensionBlueprint({
|
||||
output: [widgetTitleRef, coreExtensionData.reactElement],
|
||||
factory(params: MyWidgetBlueprintParams, { config }) {
|
||||
return [
|
||||
widgetTitleRef(config.title ?? params.defaultTitle),
|
||||
widgetTitleRef(config.title ?? params.title),
|
||||
coreExtensionData.reactElement(params.element),
|
||||
];
|
||||
},
|
||||
|
||||
@@ -89,7 +89,7 @@ const exampleExtension = PageBlueprint.make({
|
||||
params: {
|
||||
loader: () =>
|
||||
import('./components/ExamplePage').then(m => <m.ExamplePage />),
|
||||
defaultPath: '/example',
|
||||
path: '/example',
|
||||
},
|
||||
});
|
||||
```
|
||||
@@ -318,7 +318,7 @@ import {
|
||||
|
||||
const customSearchPage = PageBlueprint.make({
|
||||
params: {
|
||||
defaultPath: '/search',
|
||||
path: '/search',
|
||||
loader: () =>
|
||||
import('./CustomSearchPage').then(m => <m.CustomSearchPage />),
|
||||
},
|
||||
|
||||
@@ -47,7 +47,7 @@ import { indexRouteRef } from './routes';
|
||||
|
||||
const catalogIndexPage = createPageExtension({
|
||||
// The `name` option is omitted because this is an index page
|
||||
defaultPath: '/entities',
|
||||
path: '/entities',
|
||||
// highlight-next-line
|
||||
routeRef: indexRouteRef,
|
||||
loader: () => import('./components').then(m => <m.IndexPage />),
|
||||
@@ -197,7 +197,7 @@ import {
|
||||
import { indexRouteRef, createComponentExternalRouteRef } from './routes';
|
||||
|
||||
const catalogIndexPage = createPageExtension({
|
||||
defaultPath: '/entities',
|
||||
path: '/entities',
|
||||
routeRef: indexRouteRef,
|
||||
loader: () => import('./components').then(m => <m.IndexPage />),
|
||||
});
|
||||
@@ -404,7 +404,7 @@ import {
|
||||
import { indexRouteRef, detailsSubRouteRef } from './routes';
|
||||
|
||||
const catalogIndexPage = createPageExtension({
|
||||
defaultPath: '/entities',
|
||||
path: '/entities',
|
||||
routeRef: indexRouteRef,
|
||||
loader: () => import('./components').then(m => <m.IndexPage />),
|
||||
});
|
||||
@@ -419,3 +419,42 @@ export default createFrontendPlugin({
|
||||
extensions: [catalogIndexPage],
|
||||
});
|
||||
```
|
||||
|
||||
## Route Aliases - Overriding Routed Extensions in Modules
|
||||
|
||||
It is possible to [override extensions of a plugin using a module](./25-extension-overrides.md#creating-a-frontend-module). In some cases the extension you're overriding may require a route reference. You could import import the plugin instance and access the it via the `routes` property, but this creates a direct dependency on the plugin and risks leading to package duplication issues that would also break the route reference.
|
||||
|
||||
Instead of accessing the route reference directly, you can create a new route reference that acts as an alias for the original one from the plugin. For example, you can override the catalog index page with a custom one like this:
|
||||
|
||||
```tsx
|
||||
const indexRouteRef = createRouteRef({ aliasFor: 'catalog.catalogIndex' });
|
||||
|
||||
export default createFrontendModule({
|
||||
pluginId: 'catalog',
|
||||
extensions: [
|
||||
PageBlueprint.make({
|
||||
params: {
|
||||
defaultPath: '/catalog',
|
||||
routeRef: indexRouteRef,
|
||||
loader: () =>
|
||||
import('./CustomCatalogIndexPage').then(m => (
|
||||
<m.CustomCatalogIndexPage />
|
||||
)),
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
Aliases are limited to the plugin that they are defined in. These aliases can also be imported and used as usual with for example `useRouteRef`, but they must always be registered in the app via an extension for this to work. For example, the following will not work:
|
||||
|
||||
```tsx
|
||||
function MyInvalidComponent() {
|
||||
// This is NOT valid
|
||||
const link = useRouteRef(
|
||||
createRouteRef({ aliasFor: 'catalog.catalogIndex' }),
|
||||
);
|
||||
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
@@ -42,7 +42,7 @@ The conversion functions such as `convertLegacyPageExtension` will attempt to in
|
||||
```ts
|
||||
const convertedIndexPage = convertLegacyPageExtension(TechDocsIndexPage, {
|
||||
name: 'index',
|
||||
defaultPath: '/docs',
|
||||
path: '/docs',
|
||||
});
|
||||
```
|
||||
|
||||
@@ -72,10 +72,10 @@ const convertedTechdocsPlugin = convertLegacyPlugin(techdocsPlugin, {
|
||||
extensions: [
|
||||
convertLegacyPageExtension(TechDocsIndexPage, {
|
||||
name: 'index',
|
||||
defaultPath: '/docs',
|
||||
path: '/docs',
|
||||
}),
|
||||
convertLegacyPageExtension(TechDocsReaderPage, {
|
||||
defaultPath: '/docs/:namespace/:kind/:name/*',
|
||||
path: '/docs/:namespace/:kind/:name/*',
|
||||
}),
|
||||
convertLegacyEntityContentExtension(EntityTechdocsContent),
|
||||
],
|
||||
|
||||
@@ -199,8 +199,8 @@ import { ApiBlueprint } from '@backstage/frontend-plugin-api';
|
||||
|
||||
const scmIntegrationsApi = ApiBlueprint.make({
|
||||
name: 'scm-integrations',
|
||||
params: define =>
|
||||
define({
|
||||
params: defineParams =>
|
||||
defineParams({
|
||||
api: scmIntegrationsApiRef,
|
||||
deps: { configApi: configApiRef },
|
||||
factory: ({ configApi }) => ScmIntegrationsApi.fromConfig(configApi),
|
||||
@@ -244,8 +244,7 @@ Plugins don't even have to be imported manually after installing their package i
|
||||
```yaml title="in app-config.yaml"
|
||||
app:
|
||||
# Enabling plugin and override features discovery
|
||||
experimental:
|
||||
packages: all # ✨
|
||||
packages: all # ✨
|
||||
```
|
||||
|
||||
### `featureFlags`
|
||||
|
||||
@@ -75,7 +75,7 @@ const examplePage = PageBlueprint.make({
|
||||
routeRef: rootRouteRef,
|
||||
|
||||
// This is the default path of this page, but integrators are free to override it
|
||||
defaultPath: '/example',
|
||||
path: '/example',
|
||||
|
||||
// Page extensions are always dynamically loaded using React.lazy().
|
||||
// All of the functionality of this page is implemented in the
|
||||
@@ -160,8 +160,8 @@ import { exampleApiRef, DefaultExampleApi } from './api';
|
||||
// highlight-add-start
|
||||
const exampleApi = ApiBlueprint.make({
|
||||
name: 'example',
|
||||
params: define =>
|
||||
define({
|
||||
params: defineParams =>
|
||||
defineParams({
|
||||
api: exampleApiRef,
|
||||
deps: {},
|
||||
factory: () => new DefaultExampleApi(),
|
||||
@@ -198,8 +198,8 @@ import { EntityContentBlueprint } from '@backstage/plugin-catalog-react/alpha';
|
||||
// route reference if you want to be able to generate a URL that links to the content.
|
||||
const exampleEntityContent = EntityContentBlueprint.make({
|
||||
params: {
|
||||
defaultPath: 'example',
|
||||
defaultTitle: 'Example',
|
||||
path: 'example',
|
||||
title: 'Example',
|
||||
loader: () =>
|
||||
import('./components/ExampleEntityContent').then(m => (
|
||||
<m.ExampleEntityContent />
|
||||
|
||||
@@ -17,10 +17,6 @@ These are the [extension blueprints](../architecture/23-extension-blueprints.md)
|
||||
|
||||
An API extension is used to add or override [Utility API factories](../utility-apis/01-index.md) in the app. They are commonly used by plugins for both internal and shared APIs. There are also many built-in Api extensions provided by the framework that you are able to override.
|
||||
|
||||
### Component - [Reference](../../reference/frontend-plugin-api.createcomponentextension.md)
|
||||
|
||||
Components extensions are used to override the component associated with a component reference throughout the app. This uses an extension creator function rather than a blueprint, but will likely be migrated to a blueprint in the future.
|
||||
|
||||
### NavItem - [Reference](../../reference/frontend-plugin-api.navitemblueprint.md)
|
||||
|
||||
Navigation item extensions are used to provide menu items that link to different parts of the app. By default nav items are attached to the app nav extension, which by default is rendered as the left sidebar in the app.
|
||||
@@ -33,6 +29,10 @@ Page extensions provide content for a particular route in the app. By default pa
|
||||
|
||||
Sign-in page extension have a single purpose - to implement a custom sign-in page. They are always attached to the app root extension and are rendered before the rest of the app until the user is signed in.
|
||||
|
||||
### SwappableComponent - [Reference](../../reference/frontend-plugin-api.swappablecomponentblueprint.md)
|
||||
|
||||
Swappable Components are extensions that are used to replace the implementations of components in the app and plugins.
|
||||
|
||||
### Theme - [Reference](../../reference/frontend-plugin-api.themeblueprint.md)
|
||||
|
||||
Theme extensions provide custom themes for the app. They are always attached to the app extension and you can have any number of themes extensions installed in an app at once, letting the user choose which theme to use.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user