Merge branch 'master' into newbackenddocs2

Signed-off-by: Alex Crome <afscrome@users.noreply.github.com>
This commit is contained in:
Alex Crome
2023-12-06 09:00:34 +00:00
committed by GitHub
1456 changed files with 43229 additions and 13566 deletions
+6
View File
@@ -236,6 +236,12 @@ export default async function createPlugin(
// an entity you will need to replace this step as well.
//
// You might also replace it if you for example want to filter out certain groups.
//
// Note that `getDefaultOwnershipEntityRefs` only includes groups to which the
// user has a direct MEMBER_OF relationship. It's perfectly fine to include
// groups that the user is transitively part of in the claims array, but the
// catalog doesn't currently provide a direct way of accessing this list of
// groups.
const ownershipRefs = getDefaultOwnershipEntityRefs(entity);
// The last step is to issue the token, where we might provide more options in the future.
@@ -25,8 +25,8 @@ import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node'
import { MyCustomProcessor } from './MyCustomProcessor';
export const catalogModuleExampleCustomProcessor = createBackendModule({
moduleId: 'exampleCustomProcessor',
pluginId: 'catalog',
moduleId: 'example-custom-processor',
register(env) {
env.registerInit({
deps: {
@@ -10,18 +10,20 @@ description: Naming patterns in the backend system
These are the naming patterns to adhere to within the backend system. They help us keep exports consistent across packages and make it easier to understand the usage and intent of exports.
As a rule, all names should be camel case, with the exceptions of plugin and module IDs, which should be kebab case.
### Plugins
| Description | Pattern | Examples |
| ----------- | ------------ | ----------------------------------- |
| export | `<id>Plugin` | `catalogPlugin`, `scaffolderPlugin` |
| ID | `'<id>'` | `'catalog'`, `'scaffolder'` |
| Description | Pattern | Examples |
| ----------- | ----------------- | ------------------------------------- |
| export | `<camelId>Plugin` | `catalogPlugin`, `userSettingsPlugin` |
| ID | `'<kebab-id>'` | `'catalog'`, `'user-settings'` |
Example:
```ts
export const catalogPlugin = createBackendPlugin({
pluginId: 'catalog',
export const userSettingsPlugin = createBackendPlugin({
pluginId: 'user-settings',
...
})
```
@@ -31,14 +33,14 @@ export const catalogPlugin = createBackendPlugin({
| Description | Pattern | Examples |
| ----------- | ---------------------------- | ----------------------------------- |
| export | `<pluginId>Module<ModuleId>` | `catalogModuleGithubEntityProvider` |
| ID | `'<moduleId>'` | `'githubEntityProvider'` |
| ID | `'<module-id>'` | `'github-entity-provider'` |
Example:
```ts
export const catalogModuleGithubEntityProvider = createBackendModule({
pluginId: 'catalog',
moduleId: 'githubEntityProvider',
moduleId: 'github-entity-provider',
...
})
```
@@ -547,7 +547,7 @@ import { microsoftGraphOrgEntityProviderTransformExtensionPoint } from '@backsta
backend.add(
createBackendModule({
pluginId: 'catalog',
moduleId: 'microsoftGraphTransformers',
moduleId: 'microsoft-graph-extensions',
register(env) {
env.registerInit({
deps: {
@@ -580,21 +580,21 @@ depends on the appropriate extension point and interacts with it.
```ts title="packages/backend/src/index.ts"
/* highlight-add-start */
import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node';
import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha';
import { createBackendModule } from '@backstage/backend-plugin-api';
/* highlight-add-end */
/* highlight-add-start */
const catalogModuleCustomExtensions = createBackendModule({
pluginId: 'catalog', // name of the plugin that the module is targeting
moduleId: 'customExtensions',
moduleId: 'custom-extensions',
register(env) {
env.registerInit({
deps: {
catalog: catalogProcessingExtensionPoint,
// ... and other dependencies as needed
},
init({ catalog /* ..., other dependencies */ }) {
async init({ catalog /* ..., other dependencies */ }) {
// Here you have the opportunity to interact with the extension
// point before the plugin itself gets instantiated
catalog.addEntityProvider(new MyEntityProvider()); // just an example
@@ -649,21 +649,21 @@ depends on the appropriate extension point and interacts with it.
```ts title="packages/backend/src/index.ts"
/* highlight-add-start */
import { eventsExtensionPoint } from '@backstage/plugin-events-node';
import { eventsExtensionPoint } from '@backstage/plugin-events-node/alpha';
import { createBackendModule } from '@backstage/backend-plugin-api';
/* highlight-add-end */
/* highlight-add-start */
const eventsModuleCustomExtensions = createBackendModule({
pluginId: 'events', // name of the plugin that the module is targeting
moduleId: 'customExtensions',
moduleId: 'custom-extensions',
register(env) {
env.registerInit({
deps: {
events: eventsExtensionPoint,
// ... and other dependencies as needed
},
init({ events /* ..., other dependencies */ }) {
async init({ events /* ..., other dependencies */ }) {
// Here you have the opportunity to interact with the extension
// point before the plugin itself gets instantiated
events.addSubscribers(new MySubscriber()); // just an example
@@ -714,21 +714,21 @@ depends on the appropriate extension point and interacts with it.
```ts title="packages/backend/src/index.ts"
/* highlight-add-start */
import { scaffolderActionsExtensionPoint } from '@backstage/plugin-scaffolder-node';
import { scaffolderActionsExtensionPoint } from '@backstage/plugin-scaffolder-node/alpha';
import { createBackendModule } from '@backstage/backend-plugin-api';
/* highlight-add-end */
/* highlight-add-start */
const scaffolderModuleCustomExtensions = createBackendModule({
pluginId: 'scaffolder', // name of the plugin that the module is targeting
moduleId: 'customExtensions',
moduleId: 'custom-extensions',
register(env) {
env.registerInit({
deps: {
scaffolder: scaffolderActionsExtensionPoint,
// ... and other dependencies as needed
},
init({ scaffolder /* ..., other dependencies */ }) {
async init({ scaffolder /* ..., other dependencies */ }) {
// Here you have the opportunity to interact with the extension
// point before the plugin itself gets instantiated
scaffolder.addActions(new MyAction()); // just an example
@@ -104,8 +104,8 @@ import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node'
import { MyCustomProcessor } from './MyCustomProcessor';
export const catalogModuleExampleCustomProcessor = createBackendModule({
moduleId: 'exampleCustomProcessor',
pluginId: 'catalog',
moduleId: 'example-custom-processor',
register(env) {
env.registerInit({
deps: {
@@ -73,30 +73,99 @@ export const kubernetesPlugin = createBackendPlugin({
});
```
Done! Users of this plugin are now able to import the `kubernetesPlugin` and register it in their backend using
Lastly, make sure you re-export the plugin instance as the default export of your package in `src/index.ts`:
```ts
export { kubernetesPlugin as default } from './plugin.ts';
```
Done! Users of this plugin are now able to import your plugin package and register it in their backend using
```ts
// packages/backend/src/index.ts
import { kubernetesPlugin } from '@backstage/plugin-kubernetes-backend';
backend.add(kubernetesPlugin);
backend.add(import('@backstage/plugin-kubernetes-backend'));
```
There's one thing missing that those sharp eyed readers might have noticed: the `clusterSupplier` option is missing from the original plugin. Let's add it and discuss the alternatives.
One alternative is to pass the `ClusterSupplier` in as options to the plugin, which is quick and easy but not very flexible, and also hard to evolve without introducing breaking changes as it changes the public API for the plugin. Having complex types passed in directly to the plugin also clutters the backend setup code and makes it harder to read.
Options are primarily used for simple configuration values that are not complex types. In this case we want to allow users to register their own `ClusterSupplier` implementations to the plugin. This is where the new backend system's [extension points](../architecture/05-extension-points.md) come in handy, but let's look at doing this with options first.
One alternative is to make it possible to build the cluster supplier using static configuration. It could for example be that there is a selection of built-in implementations to choose from, or that the logic for how the `ClusterSupplier` is supposed to function is all determined by configuration, or a combination of the two. Using static configuration for customization is always the preferred option whenever it's possible. In this case, we could for example imagine that we would be able to configure our cluster supplier like this:
```ts
/* omitted imports but they remain the same as above */
export interface KubernetesOptions {
clusterSupplier?: KubernetesClustersSupplier;
}
const kubernetesPlugin = createBackendPlugin((options: KubernetesOptions) => ({
const kubernetesPlugin = createBackendPlugin({
pluginId: 'kubernetes',
register(env) {
env.registerInit({
deps: {
/* omitted dependencies but they remain the same as above */
},
async init({ config, logger, catalogApi, discovery, http }) {
// Note that in a real implementation this would be done by the `KubernetesBuilder` instead,
// but here we've extracted it into a separate call to highlight the example.
const configuredClusterSupplier = readClusterSupplierFromConfig(config);
const { router } = await KubernetesBuilder.createBuilder({
config,
logger,
catalogApi,
discovery,
})
.setClusterSupplier(configuredClusterSupplier)
.build();
http.use(router);
},
});
},
});
```
There are however many types of customizations that are not possible to do with static configuration. In this case we want integrators to be able to create arbitrary implementations of the `ClusterSupplier` interface, which in the end requires an implementation through code. This is where the new backend system's [extension points](../architecture/05-extension-points.md) come in handy.
The new [extension points](../architecture/05-extension-points.md) API allows [modules](../architecture/06-modules.md) to add functionality into the backend plugin itself, in this case an additional `ClusterSupplier`. Let's look at how we could add support for installing custom suppliers using an extension point. This will allow integrators to build their own internal module with a custom `ClusterSupplier` implementation.
First we'll go ahead and create a `@backstage/plugin-kubernetes-node` package where we can define our extension point. A separate package is used to avoid direct dependencies on the plugin package itself. With the new package created, we define the extension point like this:
```ts
import { createExtensionPoint } from '@backstage/backend-plugin-api';
export interface KubernetesClusterSupplierExtensionPoint {
setClusterSupplier(supplier: KubernetesClustersSupplier): void;
}
/**
* An extension point that allows other plugins to set the cluster supplier.
*/
export const kubernetesClustersSupplierExtensionPoint =
createExtensionPoint<KubernetesClusterSupplierExtensionPoint>({
id: 'kubernetes.cluster-supplier',
});
```
For more information on how to design extension points, see the [extension points](../architecture/05-extension-points.md#extension-point-design) documentation.
Next we'll need to add support for this extension point to the Kubernetes backend plugin itself:
```ts
/* omitted other imports but they remain the same as above */
import { kubernetesClustersSupplierExtensionPoint } from '@backstage/plugin-kubernetes-node';
export const kubernetesPlugin = createBackendPlugin({
pluginId: 'kubernetes',
register(env) {
let clusterSupplier: KubernetesClustersSupplier | undefined = undefined;
// We register the extension point with the backend, which allows modules to
// register their own ClusterSupplier.
env.registerExtensionPoint(kubernetesClustersSupplierExtensionPoint, {
setClusterSupplier(supplier) {
if (clusterSupplier) {
throw new Error('ClusterSupplier may only be set once');
}
clusterSupplier = supplier;
},
});
env.registerInit({
deps: {
/* omitted dependencies but they remain the same as above */
@@ -108,103 +177,7 @@ const kubernetesPlugin = createBackendPlugin((options: KubernetesOptions) => ({
catalogApi,
discovery,
})
.setClusterSupplier(options.clusterSupplier)
.build();
http.use(router);
},
});
},
}));
```
The above would allow users to specify their own `ClusterSupplier` implementation to the plugin like this:
```ts
backend.add(
kubernetesPlugin({ clusterSupplier: new MyCustomClusterSupplier() }),
);
```
Just to echo what was said above, this is not a very flexible solution and will for example be problematic to keep backwards compatible if we start evolving the options to for example accept multiple suppliers or tweak the `ClusterSupplier` interface.
The new [extension points](../architecture/05-extension-points.md) API allows [modules](../architecture/06-modules.md) to add functionality into the backend plugin itself, in this case an additional `ClusterSupplier`.
The kubernetes backend plugin only supports one `ClusterSupplier` at this time but let's look at how we could add support for multiple suppliers using extension points. This allows users to install several modules that add their own `ClusterSupplier` implementations to the plugin like this:
```ts
backend.add(kubernetesPlugin());
backend.add(kubernetesGoogleContainerEngineClusterSupplier());
backend.add(kubernetesElasticContainerEngine());
```
Now let's look at how to implement this with extension points. First we need to define the extension point itself. As the extension point will be used by other modules, it's common practice to export these from a shared package so that they can be imported by other modules and plugins.
We'll go ahead and create a `@backstage/plugin-kubernetes-node` package for this and from there we'll export the extension point.
```ts
import { createExtensionPoint } from '@backstage/backend-plugin-api';
export interface KubernetesClusterSupplierExtensionPoint {
addClusterSupplier(supplier: KubernetesClustersSupplier): void;
}
/**
* An extension point that allows other plugins to add cluster suppliers.
* @public
*/
export const kubernetesClustersSupplierExtensionPoint =
createExtensionPoint<KubernetesClusterSupplierExtensionPoint>({
id: 'kubernetes.cluster-supplier',
});
```
Now we can use this extension point in the kubernetes backend plugin to register the extension point for modules to use.
```ts
import { kubernetesClustersSupplierExtensionPoint, KubernetesClusterSupplierExtensionPoint } from '@backstage/plugin-kubernetes-node';
// Our internal implementation of the extension point, should not be exported.
class ClusterSupplier implements KubernetesClusterSupplierExtensionPoint {
private clusterSuppliers: KubernetesClustersSupplier | undefined;
// This method is private and only used internally to retrieve the registered supplier.
getClusterSupplier() {
return this.clusterSuppliers;
}
addClusterSupplier(supplier: KubernetesClustersSupplier) {
// We can remove this check once the plugin support multiple suppliers.
if(this.clusterSuppliers) {
throw new Error('Multiple Kubernetes cluster suppliers is not supported at this time');
}
this.clusterSuppliers = supplier;
}
}
export const kubernetesPlugin = createBackendPlugin({
pluginId: 'kubernetes',
register(env) {
const extensionPoint = new ClusterSupplier();
// We register the extension point with the backend, which allows modules to
// register their own ClusterSupplier.
env.registerExtensionPoint(
kubernetesClustersSupplierExtensionPoint,
extensionPoint,
);
env.registerInit({
deps: {
... omitted ...
},
async init({ config, logger, catalogApi, discovery, http }) {
const { router } = await KubernetesBuilder.createBuilder({
config,
logger,
catalogApi,
discovery,
})
// We pass in the registered supplier from the extension point.
.setClusterSupplier(extensionPoint.getClusterSupplier())
.setClusterSupplier(clusterSupplier)
.build();
http.use(router);
},
@@ -213,24 +186,33 @@ export const kubernetesPlugin = createBackendPlugin({
});
```
And that's it! Modules can now be built that add clusters into to the kubernetes backend plugin, here's an example of a module that adds a `GoogleContainerEngineSupplier` to the kubernetes backend.
And that's it! Modules can now be built that add clusters into to the kubernetes backend plugin, here's an example of a module that adds a `GoogleContainerEngineSupplier` to the kubernetes backend:
```ts
import { kubernetesClustersSupplierExtensionPoint } from '@backstage/plugin-kubernetes-node';
export const kubernetesGoogleContainerEngineClusterSupplier =
createBackendModule({
pluginId: 'kubernetes',
moduleId: 'gke.supplier',
register(env) {
env.registerInit({
deps: {
supplier: kubernetesClustersSupplierExtensionPoint,
},
async init({ supplier }) {
supplier.addClusterSupplier(new GoogleContainerEngineSupplier());
},
});
},
});
// This is a custom implementation of the ClusterSupplier interface.
import { GoogleContainerEngineSupplier } from './GoogleContainerEngineSupplier';
export default createBackendModule({
pluginId: 'kubernetes',
moduleId: 'gke-supplier',
register(env) {
env.registerInit({
deps: {
supplier: kubernetesClustersSupplierExtensionPoint,
},
async init({ supplier }) {
supplier.setClusterSupplier(new GoogleContainerEngineSupplier());
},
});
},
});
```
The above module can then be installed by the integrator alongside the kubernetes backend plugin:
```ts
backend.add(import('@backstage/plugin-kubernetes-backend'));
backend.add(import('@internal/gke-cluster-supplier'));
```
+2 -2
View File
@@ -31,8 +31,8 @@ with a `Bearer` token, which should then be the Backstage token returned by the
These are the endpoints that deal with reading of entities directly. What it
exposes are final entities - i.e. the output of all processing and the stitching
process, not the raw originally ingested entity data. See [The Life of an
Entity](life-of-an-entity.md) for more details about this process and
process, not the raw originally ingested entity data. See
[The Life of an Entity](./life-of-an-entity.md) for more details about this process and
distinction.
### `GET /entities`
@@ -114,6 +114,6 @@ configured differently should be running on `/catalog-import`.
For information about writing your own templates, you can check out the docs
[here](./writing-templates.md)
If you are looking for a method to discover templates without the need for manual ingestion, there are several options available. One approach is to utilize Discovery providers, such as [GitHub Discovery](https://backstage.io/docs/integrations/github/discover).
If you are looking for a method to discover templates without the need for manual ingestion, there are several options available. One approach is to utilize Discovery providers, such as [GitHub Discovery](https://backstage.io/docs/integrations/github/discovery).
Alternatively, you can choose to set up an external integration. This involves connecting your system to external sources or platforms that may host templates relevant to your needs, as mentioned in [External Integration](https://backstage.io/docs/features/software-catalog/external-integrations/).
+4
View File
@@ -91,6 +91,9 @@ Options:
--docker-option <DOCKER_OPTION...> Extra options to pass to the docker run command, e.g. "--add-host=internal.host:192.168.11.12"
(can be added multiple times).
--no-docker Do not use Docker, use MkDocs executable in current user environment.
--mkdocs-parameter-clean Pass "--clean" parameter to mkdocs server running in containerized environment.
--mkdocs-parameter-dirtyreload Pass "--dirtyreload" parameter to mkdocs server running in containerized environment.
--mkdocs-parameter-strict Pass "--strict" parameter to mkdocs server running in containerized environment.
--mkdocs-port <PORT> Port for MkDocs server to use (default: "8000")
--preview-app-bundle-path <PATH_TO_BUNDLE> Preview documentation using a web app other than the included one.
--preview-app-port <PORT> Port where the preview will be served.
@@ -147,6 +150,7 @@ Options:
Defaults to false, which means that the techdocs-core plugin is always added to the mkdocs file.
--legacyCopyReadmeMdToIndexMd Attempt to ensure an index.md exists falling back to using <docs-dir>/README.md or README.md
in case a default <docs-dir>/index.md is not provided. (default: false)
--runAsDefaultUser Bypass setting the container user as the same user and group id as host for Linux and MacOS (default: false)
-v --verbose Enable verbose output. (default: false)
-h, --help display help for command
```
+12
View File
@@ -504,6 +504,18 @@ folder (/docs) or replace the content in this file.
Done! You now have support for TechDocs in your own software template!
### Prevent download of Google fonts
If your Backstage instance does not have internet access, the generation will fail. TechDocs tries to download the Roboto font from Google. You can disable it by adding the following lines to mkdocs.yaml:
```yaml
theme:
name: material
font: false
```
> Note: The addition `name: material` is necessary. Otherwise it will not work
## How to enable iframes in TechDocs
TechDocs uses the [DOMPurify](https://github.com/cure53/DOMPurify) library to
+4
View File
@@ -484,3 +484,7 @@ You can see more ways to use this in the [Storybook Sidebar examples](https://ba
In addition to a custom theme, a custom logo, you can also customize the
homepage of your app. Read the full guide on the [next page](homepage.md).
## Migrating to Material UI v5
We now support Material UI v5 in Backstage. Check out our [migration guide](../tutorials/migrate-to-mui5.md) to get started.
+5
View File
@@ -290,6 +290,11 @@ otherwise something went terribly wrong.
## Create a new component using a software template
> Note: if you're running Backstage with Node 20 or later, you'll need to pass the flag `--no-node-snapshot` to Node in order to
> use the templates feature.
> One way to do this is to specify the `NODE_OPTIONS` environment variable before starting Backstage:
> `export NODE_OPTIONS=--no-node-snapshot`
- Go to `create` and choose to create a website with the `Example Node.js Template`
- Type in a name, let's use `tutorial` and click `Next Step`
@@ -15,7 +15,7 @@ The following steps assume that you have
to it.
We are using the
[CircleCI](https://github.com/backstage/backstage/blob/master/plugins/circleci/README.md)
[CircleCI](https://github.com/CircleCI-Public/backstage-plugin/tree/main/plugins/circleci)
plugin in this example, which is designed to show CI/CD pipeline information attached
to an entity in the software catalog.
@@ -23,7 +23,7 @@ to an entity in the software catalog.
```bash
# From your Backstage root directory
yarn add --cwd packages/app @backstage/plugin-circleci
yarn add --cwd packages/app @circleci/backstage-plugin
```
Note the plugin is added to the `app` package, rather than the root
@@ -38,7 +38,7 @@ to an entity in the software catalog.
import {
EntityCircleCIContent,
isCircleCIAvailable,
} from '@backstage/plugin-circleci';
} from '@circleci/backstage-plugin';
/* highlight-add-end */
const cicdContent = (
+15 -11
View File
@@ -295,7 +295,8 @@ Webpack configuration itself varies very little between the frontend development
and production bundling, so we'll dive more into the configuration in the
production section below. The main differences are that `process.env.NODE_ENV`
is set to `'development'`, minification is disabled, cheap source maps are used,
and [React Hot Loader](https://github.com/gaearon/react-hot-loader) is enabled.
and [React Refresh](https://github.com/pmmmwh/react-refresh-webpack-plugin#readme)
is enabled.
If you prefer to run type checking and linting as part of the Webpack process,
you can enable usage of the
@@ -589,22 +590,25 @@ For your productivity working with unit tests it's quite essential to have your
A complete launch configuration for VS Code debugging may look like this:
```json
```jsonc
{
"type": "node",
"name": "vscode-jest-tests",
"name": "vscode-jest-tests.v2",
"request": "launch",
"args": [
"repo",
"test",
"--runInBand",
"--watchAll=false",
"--testNamePattern",
"${jest.testNamePattern}",
"--runTestsByPath",
"${jest.testFile}"
],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"disableOptimisticBPs": true,
"program": "${workspaceFolder}/node_modules/.bin/jest",
"cwd": "${workspaceFolder}",
"args": [
"--config",
"node_modules/@backstage/cli/config/jest.js",
"--runInBand",
"--watchAll=false"
]
"program": "${workspaceFolder}/node_modules/.bin/backstage-cli"
}
```
+24
View File
@@ -47,3 +47,27 @@ The resulting log should now have more information available for debugging:
[1] 2023-04-12T00:51:44.118Z search info Collating documents for tools succeeded type=plugin documentType=tools
[1] 2023-04-12T00:51:44.119Z backstage debug task: search_index_tools will next occur around 2023-04-11T21:01:44.118-04:00 type=taskManager task=search_index_tools
```
## Debugger
### VSCode
In your `launch.json`, add a new entry with the following,
```jsonc
{
"name": "Start Backend",
"type": "node",
"request": "launch",
"args": [
"package",
"start"
],
"cwd": "${workspaceFolder}/packages/backend",
"program": "${workspaceFolder}/node_modules/.bin/backstage-cli",
"skipFiles": [
"<node_internals>/**"
],
"console": "integratedTerminal"
},
```
+25
View File
@@ -0,0 +1,25 @@
## How to generate a client with `repo-tools schema openapi generate-client`?
### Prerequisites
1. Add your plugin ID as the last `servers` item, like this,
```yaml
servers:
# first value, used for OpenAPI router validation.
- url: /
# final value, pluginId.
- url: catalog
```
2. Find or create a new plugin to house your new generated client. Currently, we do not support generating an entirely new plugin and instead just generate client files.
### Generating your client
1. Run `yarn backstage-repo-tools schema openapi generate-client --input-spec <file> --output-directory <directory>`. This will create a new folder in `<directory>/src/generated` to house the generated content.
2. You should use the generated files as follows,
- `apis/DefaultApi.client.ts` - this is the client that you should use. It has types for all of the various operations on your API.
- `models/*` - These are the types generated from your OpenAPI file, ideally you should not need to use these directly and can instead use the inferred types from `apis/DefaultApi.client.ts`.
- everything else is directory specific and shouldn't be touched.
+12 -1
View File
@@ -21,7 +21,18 @@ description: A brief description of the plugin. # Max 170 characters
documentation: # A link to your documentation E.g. Your github README
iconUrl: # Used as the src attribute for your logo.
# You can provide an external url or add your logo under static/img and provide a path
# relative to static/ e.g. img/my-logo.png
# relative to static/ e.g. /img/my-logo.png
npmPackageName: # Your npm package name E.g. '@backstage/plugin-<etc>' quotes are required
addedDate: # The date plugin added to directory E.g. '2022-10-01' quotes are required
```
## Submission Tips
Here are a few tips to help speed up the review process when you submit your plugin:
- For any icon that you use make sure you have the proper rights to use it.
- Make sure that your package had been published on the NPM registry and that it's public.
- Make sure your package on NPM has a link back to your code repo, this helps provide confidence that it's the right package.
- Where possible, please use an [NPM scope](https://docs.npmjs.com/about-scopes) that matches either your Organization name or user name, this provides trust in the plugin
- If your plugin has both a frontend and backend link the documentation to the frontend package but make sure it mentioned needing to install the backend package.
- Where possible include a screenshot of the features in you plugin documentation, it really does help when deciding to use a plugin.
+11 -6
View File
@@ -10,7 +10,7 @@ The Backstage core function provides internationalization for plugins
## For a plugin developer
When you are creating your plugin, you have the possibility to use `createTranslationRef` to define all messages for your plugin. For example
When you are creating your plugin, you have the possibility to use `createTranslationRef` to define all messages for your plugin. For example:
```ts
import { createTranslationRef } from '@backstage/core-plugin-api/alpha';
@@ -19,8 +19,13 @@ import { createTranslationRef } from '@backstage/core-plugin-api/alpha';
export const myPluginTranslationRef = createTranslationRef({
id: 'plugin.my-plugin',
messages: {
index_page_title: 'All your components',
create_component_button_label: 'Create new component',
indexPage: {
title: 'All your components',
createButtonTitle: 'Create new component',
},
entityPage: {
notFound: 'Entity not found',
},
},
});
```
@@ -33,9 +38,9 @@ import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
const { t } = useTranslationRef(myPluginTranslationRef);
return (
<PageHeader title={t('index_page_title')}>
<PageHeader title={t('indexPage.title')}>
<Button onClick={handleCreateComponent}>
{t('create_component_button_label')}
{t('indexPage.createButtonTitle')}
</Button>
</PageHeader>
);
@@ -53,7 +58,7 @@ In an app you can both override the default messages, as well as register transl
+ createTranslationMessages({
+ ref: myPluginTranslationRef,
+ messages: {
+ create_component_button_label: 'Create new entity',
+ 'indexPage.createButtonTitle': 'Create new entity',
+ },
+ }),
+ createTranslationResource({
+1 -1
View File
@@ -147,8 +147,8 @@ import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node'
import { MyCustomProcessor } from './processor';
export const exampleCustomProcessorCatalogModule = createBackendModule({
moduleId: 'exampleCustomProcessor',
pluginId: 'catalog',
moduleId: 'example-custom-processor',
register(env) {
env.registerInit({
deps: {
File diff suppressed because it is too large Load Diff
+140
View File
@@ -0,0 +1,140 @@
# Release v1.21.0-next.1
## @backstage/core-compat-api@0.0.1-next.0
### Patch Changes
- c219b168aa: Made package public so it can be published
## @backstage/create-app@0.5.8-next.1
### Patch Changes
- Bumped create-app version.
## @backstage/plugin-api-docs@0.10.2-next.1
### Patch Changes
- Updated dependencies
- @backstage/plugin-catalog@1.16.0-next.1
## @backstage/plugin-bazaar@0.2.20-next.1
### Patch Changes
- Updated dependencies
- @backstage/plugin-catalog@1.16.0-next.1
## @backstage/plugin-catalog@1.16.0-next.1
### Patch Changes
- Updated dependencies
- @backstage/core-compat-api@0.0.1-next.0
## @backstage/plugin-catalog-import@0.10.4-next.1
### Patch Changes
- Updated dependencies
- @backstage/core-compat-api@0.0.1-next.0
## @backstage/plugin-graphiql@0.3.1-next.1
### Patch Changes
- Updated dependencies
- @backstage/core-compat-api@0.0.1-next.0
## @backstage/plugin-search@1.4.4-next.1
### Patch Changes
- Updated dependencies
- @backstage/core-compat-api@0.0.1-next.0
## @backstage/plugin-tech-radar@0.6.11-next.1
### Patch Changes
- Updated dependencies
- @backstage/core-compat-api@0.0.1-next.0
## @backstage/plugin-techdocs@1.9.2-next.1
### Patch Changes
- Updated dependencies
- @backstage/core-compat-api@0.0.1-next.0
## @backstage/plugin-techdocs-addons-test-utils@1.0.25-next.1
### Patch Changes
- Updated dependencies
- @backstage/plugin-catalog@1.16.0-next.1
- @backstage/plugin-techdocs@1.9.2-next.1
## @backstage/plugin-user-settings@0.7.14-next.1
### Patch Changes
- Updated dependencies
- @backstage/core-compat-api@0.0.1-next.0
## example-app@0.2.90-next.1
### Patch Changes
- Updated dependencies
- @backstage/plugin-catalog@1.16.0-next.1
- @backstage/plugin-catalog-import@0.10.4-next.1
- @backstage/plugin-graphiql@0.3.1-next.1
- @backstage/plugin-search@1.4.4-next.1
- @backstage/plugin-tech-radar@0.6.11-next.1
- @backstage/plugin-techdocs@1.9.2-next.1
- @backstage/plugin-user-settings@0.7.14-next.1
- @backstage/plugin-api-docs@0.10.2-next.1
- @backstage/plugin-catalog-graph@0.3.2-next.0
- @backstage/plugin-explore@0.4.14-next.0
- @backstage/plugin-org@0.6.18-next.0
- @backstage/plugin-scaffolder@1.16.2-next.0
- @backstage/plugin-scaffolder-react@1.6.2-next.0
- @backstage/plugin-techdocs-module-addons-contrib@1.1.3-next.0
## example-app-next@0.0.4-next.1
### Patch Changes
- Updated dependencies
- @backstage/core-compat-api@0.0.1-next.0
- @backstage/plugin-catalog@1.16.0-next.1
- @backstage/plugin-catalog-import@0.10.4-next.1
- @backstage/plugin-graphiql@0.3.1-next.1
- @backstage/plugin-search@1.4.4-next.1
- @backstage/plugin-tech-radar@0.6.11-next.1
- @backstage/plugin-techdocs@1.9.2-next.1
- @backstage/plugin-user-settings@0.7.14-next.1
- @backstage/plugin-api-docs@0.10.2-next.1
- @backstage/plugin-catalog-graph@0.3.2-next.0
- @backstage/plugin-explore@0.4.14-next.0
- @backstage/plugin-org@0.6.18-next.0
- @backstage/plugin-scaffolder@1.16.2-next.0
- @backstage/plugin-scaffolder-react@1.6.2-next.0
- @backstage/plugin-techdocs-module-addons-contrib@1.1.3-next.0
## e2e-test@0.2.10-next.1
### Patch Changes
- Updated dependencies
- @backstage/create-app@0.5.8-next.1
## techdocs-cli-embedded-app@0.2.89-next.1
### Patch Changes
- Updated dependencies
- @backstage/plugin-catalog@1.16.0-next.1
- @backstage/plugin-techdocs@1.9.2-next.1
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+65
View File
@@ -0,0 +1,65 @@
---
id: migrate-to-mui5
title: Migrating from Material UI v4 to v5
description: Additional resources for the Material UI v5 migration guide specifically for Backstage
---
Backstage supports developing new plugins or components using Material UI v5. At the same time, large parts of the application as well as existing plugins will still be using Material UI v4. To support Material UI v4 and v5 at the same time, we have introduced a new concept called the `UnifiedTheme`. The goal of the `UnifiedTheme` is to allow gradual migration by running both versions in parallel, applying theme options similarly & supporting potential future versions of Material UI.
By default, the `UnifiedThemeProvider` is already used. If you add a custom theme in your `createApp` function, you would need to replace the Material UI `ThemeProvider` with the `UnifiedThemeProvider`:
```diff ts
+ import import {
+ UnifiedThemeProvider,
+ themes as builtinThemes,
+ } from '@backstage/theme';
const app = createApp({
// ...
themes: [
{
// ...
provider: ({ children }) => (
- <ThemeProvider theme={lightTheme}>.
- <CssBaseline>{children}</CssBaseline>.
- </ThemeProvider
+ <UnifiedThemeProvider theme={builtinThemes.light} children={children} />
),
}
]
});
```
Before making specific changes to your Backstage instance, it might be helpful to take a look at the [Migration Guide provided by Material UI](https://mui.com/material-ui/migration/migration-v4/) first. It breaks down the differences between v4 and v5, and will make it easier to understand the impact on your Backstage instance & plugins.
It is worth noting that we are still using `@mui/styles` & `jss`. You may stumble upon documentation for migrating to `emotion` when using `makeStyles` or `withStyles`. It is not necessary to switch to `emotion`.
Important to keep in mind is that Material UI v5 is meant to be used with React Version 17 or higher. This means if you intend to use the Material UI v5 components in your plugins, you have to enforce React Version to be at least 17 for these plugins:
```json
...
"peerDependencies": {
"react": "^17.0.0 || ^18.0.0",
"react-dom": "^17.0.0 || ^18.0.0",
"react-router-dom": "6.0.0-beta.0 || ^6.3.0"
},
...
```
To comply with Material UI recommendations, we are enforcing a new linting rule that favors standard imports over named imports and also restricts 3rd-level imports as they are considered private ([Guide: Minimizing Bundle Size](https://mui.com/material-ui/guides/minimizing-bundle-size)).
There are `core-components` as well as components exported from Backstage `*-react` plugins written in Material UI v4, which expect Material UI components as props. In these cases you will still be forced to use Material UI v4.
For current known issues with the Material UI v5 migration, follow our [Milestone on GitHub](https://github.com/backstage/backstage/milestone/40). Please open a new issue if you run into different problems.
### Plugins
To migrate your plugin to Material UI v5, you can build on the resources available.
1. Manually fix the imports from named to default imports to match the new [linting rules for minimizing bundle size](https://mui.com/material-ui/guides/minimizing-bundle-size).
2. Run the migration `codemod` for the path of the specific plugin: `npx @mui/codemod v5.0.0/preset-safe plugins/<path>`.
3. Take a look at possible `TODO:` items the `codemod` could not fix.
4. Remove types & methods from `@backstage/theme` which are marked as `@deprecated`.
5. Ensure you are using `"react": "^17.0.0"` (or newer) as a peer dependency
You can follow the [migration of the GraphiQL plugin](https://github.com/backstage/backstage/pull/17696) as an example of a plugin migration.