Merge branch 'master' into add-topics-to-notification-settings

Signed-off-by: billyatroadie <bstalnaker@roadie.com>
This commit is contained in:
billyatroadie
2025-04-09 08:14:34 -04:00
committed by GitHub
1705 changed files with 37649 additions and 29031 deletions
+7
View File
@@ -0,0 +1,7 @@
---
'@backstage/plugin-devtools': patch
'@backstage/plugin-catalog': patch
'@backstage/plugin-search': patch
---
Updated `README.md` to use `yarn start` instead of `yarn dev`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend': patch
---
Fix for duplicate results in `queryEntities` when providing an `orderField` parameter
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-node': patch
---
Use a different ID for the deprecated alpha version of the catalog service, as it has a different type definition and cannot be used interchangeably with the non-alpha version.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/cli': patch
---
Avoid trailing `/*` when automatically adding imports for package with multiple entry points.
+16
View File
@@ -0,0 +1,16 @@
---
'@backstage/create-app': patch
---
Updated the root `package.json` in the template to use the new `backstage-cli repo start` command.
The `yarn dev` command is now redundant and has been removed from the template. We recommend existing projects to add these or similar scripts to help redirect users:
```json
{
"scripts": {
"dev": "echo \"Use 'yarn start' instead\"",
"start-backend": "echo \"Use 'yarn start backend' instead\""
}
}
```
+7
View File
@@ -0,0 +1,7 @@
---
'@backstage/cli': minor
---
Removes default React imports from template files, aligning with the requirements for the upcoming React 19 migration. Introduces a new ESLint rule to disallow `import React from 'react'` and `import * as React from 'react'`.
<https://legacy.reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html>
+51
View File
@@ -0,0 +1,51 @@
---
'@backstage/plugin-api-docs-module-protoc-gen-doc': patch
'@backstage/plugin-techdocs-module-addons-contrib': patch
'@backstage/plugin-catalog-unprocessed-entities': patch
'@backstage/plugin-techdocs-addons-test-utils': patch
'@backstage/frontend-plugin-api': patch
'@backstage/frontend-test-utils': patch
'@backstage/frontend-defaults': patch
'@backstage/integration-react': patch
'@backstage/plugin-kubernetes-cluster': patch
'@backstage/frontend-app-api': patch
'@backstage/core-compat-api': patch
'@backstage/core-components': patch
'@backstage/core-plugin-api': patch
'@backstage/plugin-kubernetes-react': patch
'@backstage/plugin-permission-react': patch
'@backstage/plugin-scaffolder-react': patch
'@backstage/plugin-app-visualizer': patch
'@backstage/plugin-catalog-import': patch
'@backstage/plugin-techdocs-react': patch
'@backstage/app-defaults': patch
'@backstage/core-app-api': patch
'@backstage/plugin-catalog-graph': patch
'@backstage/plugin-catalog-react': patch
'@backstage/plugin-config-schema': patch
'@backstage/plugin-notifications': patch
'@backstage/plugin-user-settings': patch
'@backstage/plugin-search-react': patch
'@backstage/create-app': patch
'@backstage/test-utils': patch
'@backstage/dev-utils': patch
'@backstage/plugin-auth-react': patch
'@backstage/plugin-home-react': patch
'@backstage/plugin-kubernetes': patch
'@backstage/plugin-scaffolder': patch
'@backstage/plugin-org-react': patch
'@backstage/plugin-api-docs': patch
'@backstage/plugin-devtools': patch
'@backstage/plugin-techdocs': patch
'@backstage/plugin-catalog': patch
'@backstage/canon': patch
'@backstage/theme': patch
'@backstage/plugin-search': patch
'@backstage/plugin-home': patch
'@backstage/plugin-app': patch
'@backstage/plugin-org': patch
---
Removes instances of default React imports, a necessary update for the upcoming React 19 migration.
<https://legacy.reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html>
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder': patch
---
Tweaked template editor tooltip to mention HTTPS requirement.
+11
View File
@@ -0,0 +1,11 @@
---
'@backstage/plugin-catalog-react': minor
'@backstage/plugin-catalog': minor
---
**BREAKING ALPHA**: `CatalogFilterBlueprint`, used in the new frontend system, is now exported under plugin-catalog-react instead of plugin-catalog.
```diff
+ import { CatalogFilterBlueprint } from '@backstage/plugin-catalog-react/alpha';
- import { CatalogFilterBlueprint } from '@backstage/plugin-catalog/alpha';
```
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/canon': patch
---
Improved Container styles, changing our max-width to 120rem and improving padding on smaller screens.
+23
View File
@@ -201,6 +201,7 @@
"changesets": [
"chatty-days-wonder",
"chilly-sheep-scream",
"chubby-tables-tie",
"clear-pigs-share",
"clever-tomatoes-jump",
"common-parrots-wink",
@@ -216,38 +217,60 @@
"every-ties-wink",
"famous-dragons-bake",
"famous-eggs-dance",
"famous-tips-raise",
"few-humans-listen",
"fluffy-dancers-sneeze",
"four-drinks-begin",
"friendly-donuts-pump-cli",
"friendly-donuts-pump",
"funny-clouds-send",
"funny-hotels-cut",
"funny-lizards-clean",
"giant-donkeys-punch",
"happy-spoons-sing",
"honest-ties-worry",
"huge-toys-beam",
"itchy-times-behave",
"large-kings-protect",
"lemon-shoes-enter",
"light-cameras-fold",
"long-hornets-share",
"metal-animals-notice",
"moody-eagles-smile",
"nine-falcons-repeat",
"odd-bobcats-hang",
"orange-queens-grin",
"proud-dots-fry",
"quick-carrots-open",
"rare-colts-drum",
"rich-ends-throw",
"rotten-bobcats-notice",
"rotten-windows-fly",
"sad-pots-try",
"serious-guests-tan",
"shiny-bears-know",
"silent-snails-lie",
"silver-rocks-invite",
"slimy-houses-chew",
"spotty-towns-show",
"stale-chairs-look",
"stale-tables-stick",
"strange-planes-kneel",
"sweet-maps-invent",
"swift-boats-add",
"tame-sloths-brake",
"tame-worms-do",
"tangy-dryers-lick",
"ten-dodos-lead",
"tender-gifts-fall",
"thin-snails-judge",
"tiny-swans-warn",
"twelve-hornets-smell",
"twenty-forks-cheat",
"twenty-walls-join",
"unlucky-carrots-shave",
"wet-penguins-beg",
"whole-papers-retire",
"wide-planets-camp",
"witty-planets-sing"
]
+37
View File
@@ -0,0 +1,37 @@
---
'@backstage/plugin-catalog-react': minor
'@backstage/plugin-catalog': minor
---
Adds `EntityContextMenuItemBlueprint` to enable extending the entity page's context menu with user defined items.
For example:
```ts
import { EntityContextMenuItemBlueprint } from '@backstage/plugin-catalog-react/alpha';
const myCustomHref = EntityContextMenuItemBlueprint.make({
name: 'test-href',
params: {
icon: <span>Example Icon</span>,
useProps: () => ({
title: 'Example Href',
href: '/example-path',
disabled: false,
component: 'a',
}),
},
});
const myCustomOnClick = EntityContextMenuItemBlueprint.make({
name: 'test-click',
params: {
icon: <span>Test Icon</span>,
useProps: () => ({
title: 'Example onClick',
onClick: () => window.alert('Hello world!'),
disabled: false,
}),
},
});
```
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/canon': patch
---
Move styles to the root of the TextField component.
+8
View File
@@ -0,0 +1,8 @@
---
'@backstage/cli': patch
---
Update the `to do` plugin template to stop using the deprecated catalog alpha service reference.
If you start seeing the `should create TODO item with catalog information` test failing, you have two options to fix this:
Update the test to mock the legacy alpha catalog service, or migrate the `TODO` plugin backend to use the new catalog service reference.
We recommend the second option, see [this](https://github.com/backstage/backstage/pull/29450/files/267115d0436009443ca68ac84e7dcc646c9c938d#diff-47e01aeb12dd55fab9e697f810be21a8d08d39c37df1b078f6d0894f9bad5a1b) pull request for an example of how to do the migration.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-defaults': patch
---
Adds `backend.auditor.severityLogLevelMappings` to map severity levels to log levels.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/canon': minor
---
Updated TextField and Select component to work with React Hook Form.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder-backend-module-github': patch
---
Add support to github:repo:create to allow branch updates
+26
View File
@@ -0,0 +1,26 @@
---
'@backstage/plugin-scaffolder': minor
---
**BREAKING ALPHA**: Extract out schema rendering components into their own Component. This means that the translation keys have changed for `actionsPage.content.tableCell.*`. They have moved to their own root key `renderSchema.*` instead.
```diff
...
- tableCell: {
- name: 'Name',
- title: 'Title',
- description: 'Description',
- type: 'Type',
- },
- noRowsDescription: 'No schema defined',
...
+ renderSchema: {
+ tableCell: {
+ name: 'Name',
+ title: 'Title',
+ description: 'Description',
+ type: 'Type',
+ },
+ undefined: 'No schema defined',
+ },
```
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-techdocs-node': patch
---
Update Azure file retrieval logic from storing file in buffer array to piping to res for better memory efficiency.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/cli': patch
---
make certificate strings optional for Dev environments
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/canon': patch
---
We added a render prop to the Link component to make sure it can work with React Router.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/canon': minor
---
Add new Select component for Canon
+30
View File
@@ -0,0 +1,30 @@
---
'@backstage/cli': patch
---
Added a new `repo start` command to replace the existing pattern of using `yarn dev` scripts. The `repo start` command runs the app and/or backend package in the repo by default, but will also fall back to running other individual frontend or backend packages or even plugin dev entry points if the can be uniquely selected.
The goal of this change is to reduce the number of different necessary scripts and align on `yarn start` being the only command needed for local development, similar to how `repo test` handles testing in the repo. It also opens up for more powerful options, like the `--plugin <pluginId>` flag that runs the dev entry point of the selected plugin.
The new script is installed as follows, replacing the existing `yarn start` script:
```json
{
"scripts": {
"start": "backstage-cli repo start"
}
}
```
In order to help users migrate in existing projects, it is recommended to add the following scripts to the root `package.json`:
```json
{
"scripts": {
"dev": "echo \"Use 'yarn start' instead\"",
"start-backend": "echo \"Use 'yarn start backend' instead\""
}
}
```
For more information, run `yarn start --help` once the new command is installed.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/canon': minor
---
**BREAKING**: Added a new TextField component to replace the Field and Input component. After feedback, it became clear that we needed to build a more opinionated version to avoid any problem in the future.
+12
View File
@@ -20,6 +20,7 @@ module.exports = {
root: true,
plugins: ['@spotify', 'notice', 'react', 'testing-library'],
rules: {
'react/react-in-jsx-scope': 'off',
'notice/notice': [
'error',
{
@@ -47,6 +48,17 @@ module.exports = {
selector:
"CallExpression[arguments.length=0] > MemberExpression[property.name='toUpperCase']",
},
{
message: "React default imports are deprecated. Follow the x migration guide for details.",
selector:
"ImportDeclaration[source.value='react'][specifiers.0.type='ImportDefaultSpecifier']",
},
{
message:
"React default imports are deprecated. Follow the x migration guide for details. If you need a global type that collides with a React named export (such as `MouseEvent`), try using `globalThis.MouseHandler`.",
selector:
"ImportDeclaration[source.value='react'] :matches(ImportDefaultSpecifier, ImportNamespaceSpecifier)",
},
],
'testing-library/await-async-queries': 'error',
'testing-library/await-async-utils': 'error',
+1 -1
View File
@@ -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@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11
uses: github/codeql-action/upload-sarif@45775bd8235c68ba998cffa5171334d58593da47 # v3.28.15
with:
sarif_file: results.sarif
+1 -1
View File
@@ -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@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11
uses: github/codeql-action/upload-sarif@45775bd8235c68ba998cffa5171334d58593da47 # v3.28.15
with:
sarif_file: snyk.sarif
+3 -3
View File
@@ -55,7 +55,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11
uses: github/codeql-action/init@45775bd8235c68ba998cffa5171334d58593da47 # v3.28.15
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@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11
uses: github/codeql-action/autobuild@45775bd8235c68ba998cffa5171334d58593da47 # v3.28.15
# ️ 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@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11
uses: github/codeql-action/analyze@45775bd8235c68ba998cffa5171334d58593da47 # v3.28.15
+1 -1
View File
@@ -54,7 +54,7 @@ jobs:
- run: yarn --cwd packages/canon build-storybook
- uses: chromaui/action@c93e0bc3a63aa176e14a75b61a31847cbfdd341c # v11
- uses: chromaui/action@649b4fd73c3f7cd7a65bd0b9f131349335ec661b # v11
with:
token: ${{ secrets.GITHUB_TOKEN }}
# projectToken intentionally shared to allow collaborators to run Chromatic on forks
File diff suppressed because one or more lines are too long
-875
View File
File diff suppressed because one or more lines are too long
+935
View File
File diff suppressed because one or more lines are too long
+3 -5
View File
@@ -1,3 +1,5 @@
compressionLevel: mixed
enableGlobalCache: true
httpTimeout: 300000
@@ -6,8 +8,4 @@ nodeLinker: node-modules
npmRegistryServer: 'https://registry.npmjs.org/'
plugins:
- path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs
spec: '@yarnpkg/plugin-workspace-tools'
yarnPath: .yarn/releases/yarn-3.8.1.cjs
yarnPath: .yarn/releases/yarn-4.8.1.cjs
+1 -1
View File
@@ -68,7 +68,7 @@ yarn tsc # does a first run of type generation and checks
Open a terminal window and start the web app by using the following command from the project root. Make sure you have run the above mentioned commands first.
```bash
yarn dev
yarn start
```
This is going to start two things, the frontend (:3000) and the backend (:7007).
+1 -1
View File
@@ -18,7 +18,7 @@
"@uiw/codemirror-themes": "^4.23.7",
"@uiw/react-codemirror": "^4.23.7",
"motion": "^12.4.1",
"next": "14.2.25",
"next": "14.2.26",
"react": "^18.0.2",
"react-dom": "^18.0.2",
"react-frame-component": "^5.2.7",
@@ -1,99 +0,0 @@
import { PropsTable } from '@/components/PropsTable';
import { Snippet } from '@/components/Snippet';
import { Tabs } from '@/components/Tabs';
import { CodeBlock } from '@/components/CodeBlock';
import { FieldSnippet } from '@/snippets/stories-snippets';
import { BaseUI } from '@/components/HeadlessBanners/BaseUI';
import {
fieldRootPropDefs,
fieldLabelPropDefs,
fieldDescriptionPropDefs,
fieldErrorPropDefs,
} from './props';
# Field
A wrapper around `Input` or `Select` component to add label, description and error messages..
<Snippet
align="center"
py={4}
preview={<FieldSnippet story="Default" />}
code={`<Field />`}
/>
<Tabs.Root>
<Tabs.List>
<Tabs.Tab>Usage</Tabs.Tab>
<Tabs.Tab>Theming</Tabs.Tab>
</Tabs.List>
<Tabs.Panel>
<CodeBlock
code={`import { Field } from '@backstage/canon';
<Field.Root>
<Field.Label>Name</Field.Label>
<Input placeholder="Enter your name" />
<Field.Description>Visible on your profile</Field.Description>
<Field.Error />
</Field.Root>`}
/>
</Tabs.Panel>
<Tabs.Panel>
We recommend starting with our [global tokens](/theme/theming) to customize the library and align it with
your brand. For additional flexibility, you can use the provided class names for each element listed below.
<CodeBlock
code={`<Field.Root className='canon-FieldRoot'>
<Field.Label className='canon-FieldLabel' />
<Field.Description className='canon-FieldDescription' />
<Field.Error className='canon-FieldError' />
</Field.Root>`}
/>
</Tabs.Panel>
</Tabs.Root>
## API reference
<BaseUI href="https://base-ui.com/react/components/field" />
### Field.Root
Groups all parts of the field. Renders a `<div>` element.
<PropsTable data={fieldRootPropDefs} />
### Field.Label
An accessible label that is automatically associated with the field control. Renders a `<label>` element.
<PropsTable data={fieldLabelPropDefs} />
### Field.Description
A paragraph with additional information about the field. Renders a `<p>` element.
<PropsTable data={fieldDescriptionPropDefs} />
### Field.Error
An error message displayed if the field control fails validation. Renders a `<div>` element.
<PropsTable data={fieldErrorPropDefs} />
## Examples
### With Label and Description
Here's a simple input with a label and description.
<Snippet
align="center"
py={4}
open
preview={<FieldSnippet story="WithLabelAndDescription" />}
code={`<Field>
<Field.Label>Name</Field.Label>
<Field.Description>Visible on your profile</Field.Description>
<Input placeholder="Enter your name" />
</Field>`}
/>
@@ -1,69 +0,0 @@
import { classNamePropDefs, stylePropDefs } from '../../../../utils/propDefs';
import type { PropDef } from '../../../../utils/propDefs';
export const fieldRootPropDefs: Record<string, PropDef> = {
name: {
type: 'string',
responsive: false,
},
disabled: {
type: 'boolean',
responsive: false,
},
invalid: {
type: 'boolean',
responsive: false,
},
validate: {
type: 'enum',
values: ['(value) => string | string[] | null | Promise'],
responsive: false,
},
validationMode: {
type: 'enum',
values: ['onBlur', 'onChange'],
responsive: false,
},
validationDebounceTime: {
type: 'number',
responsive: false,
},
...classNamePropDefs,
...stylePropDefs,
};
export const fieldLabelPropDefs: Record<string, PropDef> = {
...classNamePropDefs,
...stylePropDefs,
};
export const fieldDescriptionPropDefs: Record<string, PropDef> = {
...classNamePropDefs,
...stylePropDefs,
};
export const fieldErrorPropDefs: Record<string, PropDef> = {
match: {
type: 'enum',
values: [
'badInput',
'customError',
'patternMismatch',
'rangeOverflow',
'rangeUnderflow',
'stepMismatch',
'tooLong',
'tooShort',
'typeMismatch',
'valid',
'valueMissing',
],
responsive: false,
},
forceShow: {
type: 'boolean',
responsive: false,
},
...classNamePropDefs,
...stylePropDefs,
};
@@ -0,0 +1,128 @@
import { PropsTable } from '@/components/PropsTable';
import { Snippet } from '@/components/Snippet';
import { Tabs } from '@/components/Tabs';
import { CodeBlock } from '@/components/CodeBlock';
import { SelectSnippet } from '@/snippets/stories-snippets';
import { selectPropDefs } from './props';
# Select
A common form component for choosing a predefined value in a dropdown menu.
<Snippet
align="center"
py={4}
preview={<SelectSnippet story="Preview" />}
code={`<Select name="font" label="Font Family" options={[
{ value: 'sans', label: 'Sans-serif' },
{ value: 'serif', label: 'Serif' },
{ value: 'mono', label: 'Monospace' },
{ value: 'cursive', label: 'Cursive' },
]} />
`}
/>
<Tabs.Root>
<Tabs.List>
<Tabs.Tab>Usage</Tabs.Tab>
<Tabs.Tab>Theming</Tabs.Tab>
</Tabs.List>
<Tabs.Panel>
<CodeBlock
code={`import { Select } from '@backstage/canon';
<Select
name="font"
options={[
{ value: 'sans', label: 'Sans-serif' },
{ value: 'serif', label: 'Serif' },
{ value: 'mono', label: 'Monospace' },
{ value: 'cursive', label: 'Cursive' },
]}
/>
`}
/>
</Tabs.Panel>
<Tabs.Panel>
We recommend starting with our [global tokens](/theme/theming) to customize the library and align it with
your brand. For additional flexibility, you can use the provided class names for each element listed below.
<CodeBlock
code={`<Select className="canon-SelectFieldRoot" />`}
/>
</Tabs.Panel>
</Tabs.Root>
## API reference
<PropsTable data={selectPropDefs} />
## Examples
### With Label and description
Select component with label and description.
<Snippet
align="center"
py={4}
open
preview={<SelectSnippet story="WithDescription" />}
code={`<Select
name="font"
label="Font Family"
description="Choose a font family for your document"
options={[ ... ]}
/>`}
/>
### Sizes
Here's a view when the selects have different sizes.
<Snippet
align="center"
py={4}
open
preview={<SelectSnippet story="Sizes" />}
code={`<Flex>
<Select
size="small"
label="Font family"
options={[ ... ]}
/>
<Select
size="medium"
label="Font family"
options={[ ... ]}
/>
</Flex>`}
/>
### Disabled
Here's a view when the select is disabled.
<Snippet
align="center"
py={4}
open
preview={<SelectSnippet story="Disabled" />}
code={`<Select
disabled
label="Font family"
options={[ ... ]}
/>`}
/>
### Responsive
Here's a view when the select is responsive.
<CodeBlock
code={`<Select
size={{ initial: 'small', lg: 'medium' }}
label="Font family"
options={[ ... ]}
/>`}
/>
@@ -0,0 +1,54 @@
import { classNamePropDefs, stylePropDefs } from '../../../../utils/propDefs';
import type { PropDef } from '../../../../utils/propDefs';
export const selectPropDefs: Record<string, PropDef> = {
label: {
type: 'string',
default: 'Select an option',
responsive: false,
},
description: {
type: 'string',
responsive: false,
},
name: {
type: 'string',
responsive: false,
required: true,
},
options: {
type: 'enum',
values: ['Array<{ value: string, label: string }>'],
required: true,
},
value: {
type: 'string',
responsive: false,
},
defaultValue: {
type: 'string',
responsive: false,
},
placeholder: {
type: 'string',
responsive: false,
},
size: {
type: 'enum',
values: ['small', 'medium'],
default: 'medium',
responsive: true,
},
onValueChange: {
type: 'enum',
values: ['(value: string) => void'],
responsive: false,
},
onOpenChange: {
type: 'enum',
values: ['(open: boolean) => void'],
responsive: false,
},
...classNamePropDefs,
...stylePropDefs,
};
@@ -2,19 +2,19 @@ import { PropsTable } from '@/components/PropsTable';
import { Snippet } from '@/components/Snippet';
import { Tabs } from '@/components/Tabs';
import { CodeBlock } from '@/components/CodeBlock';
import { InputSnippet } from '@/snippets/stories-snippets';
import { TextFieldSnippet } from '@/snippets/stories-snippets';
import { BaseUI } from '@/components/HeadlessBanners/BaseUI';
import { inputPropDefs } from './props';
# Input
# TextField
A input component tfor your forms.
A text field component for your forms.
<Snippet
align="center"
py={4}
preview={<InputSnippet story="Primary" />}
code={`<Input label="Name" placeholder="Enter your name" />`}
preview={<TextFieldSnippet story="WithLabel" />}
code={`<TextField label="Label" placeholder="Enter a URL" />`}
/>
<Tabs.Root>
@@ -24,9 +24,9 @@ A input component tfor your forms.
</Tabs.List>
<Tabs.Panel>
<CodeBlock
code={`import { Input } from '@backstage/canon';
code={`import { TextField } from '@backstage/canon';
<Input />
<TextField />
`}
/>
</Tabs.Panel>
@@ -34,30 +34,40 @@ A input component tfor your forms.
We recommend starting with our [global tokens](/theme/theming) to customize the library and align it with
your brand. For additional flexibility, you can use the provided class names for each element listed below.
<CodeBlock
code={`<Input className="canon-Input" />`}
code={`<TextField className="canon-TextField" />`}
/>
</Tabs.Panel>
</Tabs.Root>
## API reference
<BaseUI href="https://base-ui.com/react/components/input" />
<PropsTable data={inputPropDefs} />
## Examples
### Sizes
Here's a simple input with a label and description.
We support two different sizes: `small`, `medium`.
<Snippet
align="center"
py={4}
open
preview={<InputSnippet story="Sizes" />}
code={`<Grid>
<Input size="sm" placeholder="Small" />
<Input size="md" placeholder="Medium" />
</Grid>`}
preview={<TextFieldSnippet story="Sizes" />}
code={`<Flex direction="row" gap="4">
<TextField size="small" placeholder="Small" />
<TextField size="medium" placeholder="Medium" />
</Flex>`}
/>
### With description
Here's a simple TextField with a description.
<Snippet
align="center"
py={4}
open
preview={<TextFieldSnippet story="WithDescription" />}
code={`<TextField label="Label" description="Description" placeholder="Enter a URL" />`}
/>
@@ -4,10 +4,20 @@ import type { PropDef } from '../../../../utils/propDefs';
export const inputPropDefs: Record<string, PropDef> = {
size: {
type: 'enum',
values: ['sm', 'md'],
default: 'md',
values: ['small', 'medium'],
default: 'medium',
responsive: false,
},
label: {
type: 'string',
},
description: {
type: 'string',
},
name: {
type: 'string',
required: true,
},
...classNamePropDefs,
...stylePropDefs,
};
@@ -0,0 +1,31 @@
# Releases
## Version 0.2.0
### Main updates
- New `Tooltip` component ([#29241](https://github.com/backstage/backstage/pull/29241))
- New `Menu` component. ([#29151](https://github.com/backstage/backstage/pull/29151))
- New `IconButton` component. ([#29239](https://github.com/backstage/backstage/pull/29239))
- New `ScrollArea` component. ([#29240](https://github.com/backstage/backstage/pull/29240))
- Improve `Button` & `Checkbox` styles. ([#29127](https://github.com/backstage/backstage/pull/29127)) ([#28789](https://github.com/backstage/backstage/pull/28789))
- Improve `Text` styles. ([#29200](https://github.com/backstage/backstage/pull/29200))
- Renamed `CanonProvider` to `IconProvider`. ([#29002](https://github.com/backstage/backstage/pull/29002))
- Added about 40+ new icons. ([#29264](https://github.com/backstage/backstage/pull/29264))
- Simplified styling into a unique styles.css file ([#29199](https://github.com/backstage/backstage/pull/29199))
- Added Canon styles to Backstage ([#29137](https://github.com/backstage/backstage/pull/29137))
- Update global CSS tokens ([#28804](https://github.com/backstage/backstage/pull/28804))
- Merge Stack + Inline into Flex ([#28634](https://github.com/backstage/backstage/pull/28634))
### Notable fixes:
- Improve `Button` types. ([#29205](https://github.com/backstage/backstage/pull/29205))
- Move font weight and family back to each components ([#28972](https://github.com/backstage/backstage/pull/28972))
- Fix custom values in spacing props ([#28770](https://github.com/backstage/backstage/pull/28770))
- Multiple updates on the Canon Docs site ([#28760](https://github.com/backstage/backstage/pull/28760)) ([#28591](https://github.com/backstage/backstage/pull/28591))
## Version 0.1.0
We're excited to share the initial release of Canon 💚 In this first alpha version, you'll find the foundation of our design system:
a set of versatile layout components and a handful of essential atomic elements to help you get started. While Canon is still in its
early stages, it's ready for exploration and we'd love for you to give it a try and share your feedback.
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import styles from './styles.module.css';
export const Banner = ({
+2 -2
View File
@@ -14,14 +14,14 @@
* limitations under the License.
*/
import React from 'react';
import { ReactNode } from 'react';
import styles from './styles.module.css';
export const Chip = ({
children,
head = false,
}: {
children: React.ReactNode;
children: ReactNode;
head?: boolean;
}) => {
return (
@@ -14,14 +14,14 @@
* limitations under the License.
*/
import React from 'react';
import { ReactNode, CSSProperties } from 'react';
export const Columns = ({
children,
style,
}: {
children: React.ReactNode;
style?: React.CSSProperties;
children: ReactNode;
style?: CSSProperties;
}) => {
return (
<div className="columns" style={style}>
@@ -1,4 +1,3 @@
import React from 'react';
import { BoxSvg } from './svgs/box';
import { FlexSvg } from './svgs/flex';
import { GridSvg } from './svgs/grid';
@@ -13,8 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
export const BoxSvg = () => {
return (
<svg
@@ -13,8 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
export const ContainerSvg = () => {
return (
<svg
@@ -13,8 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
export const FlexSvg = () => {
return (
<svg
@@ -13,8 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
export const GridSvg = () => {
return (
<svg
@@ -13,8 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
export const InlineSvg = () => {
return (
<svg
@@ -25,8 +25,8 @@ export const PropsTable = <T extends Record<string, PropData>>({
<Table.Header>
<Table.HeaderRow>
<Table.HeaderCell style={{ width: '16%' }}>Prop</Table.HeaderCell>
<Table.HeaderCell style={{ width: '56%' }}>Type</Table.HeaderCell>
<Table.HeaderCell style={{ width: '14%' }}>Default</Table.HeaderCell>
<Table.HeaderCell style={{ width: '50%' }}>Type</Table.HeaderCell>
<Table.HeaderCell style={{ width: '20%' }}>Default</Table.HeaderCell>
<Table.HeaderCell style={{ width: '14%' }}>
Responsive
</Table.HeaderCell>
@@ -45,7 +45,7 @@ export const PropsTable = <T extends Record<string, PropData>>({
<Table.Cell style={{ width: '16%' }}>
<Chip head>{n}</Chip>
</Table.Cell>
<Table.Cell style={{ width: '56%' }}>
<Table.Cell style={{ width: '50%' }}>
<div
style={{ display: 'flex', flexWrap: 'wrap', gap: '0.375rem' }}
>
@@ -61,7 +61,7 @@ export const PropsTable = <T extends Record<string, PropData>>({
)}
</div>
</Table.Cell>
<Table.Cell style={{ width: '14%' }}>
<Table.Cell style={{ width: '20%' }}>
<Chip>{data[n].default ? data[n].default : '-'}</Chip>
</Table.Cell>
<Table.Cell style={{ width: '14%' }}>
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import { RoadmapItem } from './list';
export const Roadmap = ({ list }: { list: RoadmapItem[] }) => {
+10 -10
View File
@@ -1,7 +1,7 @@
import React from 'react';
import { CSSProperties, ReactNode } from 'react';
import styles from './styles.module.css';
export const Root = ({ children }: { children: React.ReactNode }) => {
export const Root = ({ children }: { children: ReactNode }) => {
return (
<div className={styles.wrapper}>
<table className={styles.table}>{children}</table>
@@ -9,15 +9,15 @@ export const Root = ({ children }: { children: React.ReactNode }) => {
);
};
export const Header = ({ children }: { children: React.ReactNode }) => {
export const Header = ({ children }: { children: ReactNode }) => {
return <thead>{children}</thead>;
};
export const Body = ({ children }: { children: React.ReactNode }) => {
export const Body = ({ children }: { children: ReactNode }) => {
return <tbody>{children}</tbody>;
};
export const HeaderRow = ({ children }: { children: React.ReactNode }) => {
export const HeaderRow = ({ children }: { children: ReactNode }) => {
return <tr>{children}</tr>;
};
@@ -25,8 +25,8 @@ export const HeaderCell = ({
children,
style,
}: {
children: React.ReactNode;
style?: React.CSSProperties;
children: ReactNode;
style?: CSSProperties;
}) => {
return (
<th
@@ -38,7 +38,7 @@ export const HeaderCell = ({
);
};
export const Row = ({ children }: { children: React.ReactNode }) => {
export const Row = ({ children }: { children: ReactNode }) => {
return <tr className={styles.tableRow}>{children}</tr>;
};
@@ -46,8 +46,8 @@ export const Cell = ({
children,
style,
}: {
children: React.ReactNode;
style?: React.CSSProperties;
children: ReactNode;
style?: CSSProperties;
}) => {
return (
<td className={styles.tableCell} style={style}>
+2
View File
@@ -3,6 +3,7 @@
--panel: #fff;
--primary: #000;
--secondary: #757575;
--link: #4f5ce0;
--font-regular: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
'Helvetica Neue', Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
'Segoe UI Symbol', 'Noto Color Emoji';
@@ -18,6 +19,7 @@
--panel: #222222;
--primary: #fff;
--secondary: #9e9e9e;
--link: #4856e8;
--border: rgba(255, 255, 255, 0.1);
}
+17 -2
View File
@@ -27,6 +27,21 @@
color: var(--secondary);
}
.p:first-of-type {
margin-bottom: 2rem;
.ul {
margin: 0;
padding-left: 2rem;
}
.li {
color: var(--secondary);
margin-bottom: 0.5rem;
}
.a {
color: var(--link);
text-decoration: none;
}
.a:hover {
text-decoration: underline;
}
+7 -4
View File
@@ -1,4 +1,4 @@
import React, { ReactNode } from 'react';
import { isValidElement, ReactNode } from 'react';
import type { MDXComponents } from 'mdx/types';
import Image, { ImageProps } from 'next/image';
import { CodeBlock } from '@/components/CodeBlock';
@@ -17,15 +17,18 @@ export function useMDXComponents(components: MDXComponents): MDXComponents {
),
p: ({ children }) => <p className={styles.p}>{children as ReactNode}</p>,
a: ({ children, href }) => (
<a href={href} style={{ color: 'var(--primary)' }}>
<a href={href} className={styles.a}>
{children as ReactNode}
</a>
),
ul: ({ children }) => (
<ul className={styles.ul}>{children as ReactNode}</ul>
),
li: ({ children }) => (
<li style={{ marginBottom: '0.5rem' }}>{children as ReactNode}</li>
<li className={styles.li}>{children as ReactNode}</li>
),
pre: ({ children }) => {
const codeContent = React.isValidElement(children)
const codeContent = isValidElement(children)
? (children.props as { children: string }).children
: '';
+16 -16
View File
@@ -5,14 +5,14 @@ import * as BoxStories from '../../../packages/canon/src/components/Box/Box.stor
import * as ButtonStories from '../../../packages/canon/src/components/Button/Button.stories';
import * as CheckboxStories from '../../../packages/canon/src/components/Checkbox/Checkbox.stories';
import * as ContainerStories from '../../../packages/canon/src/components/Container/Container.stories';
import * as FieldStories from '../../../packages/canon/src/components/Field/Field.stories';
import * as GridStories from '../../../packages/canon/src/components/Grid/Grid.stories';
import * as HeadingStories from '../../../packages/canon/src/components/Heading/Heading.stories';
import * as IconButtonStories from '../../../packages/canon/src/components/IconButton/IconButton.stories';
import * as IconStories from '../../../packages/canon/src/components/Icon/Icon.stories';
import * as InputStories from '../../../packages/canon/src/components/Input/Input.stories';
import * as TextFieldStories from '../../../packages/canon/src/components/TextField/TextField.stories';
import * as TextStories from '../../../packages/canon/src/components/Text/Text.stories';
import * as FlexStories from '../../../packages/canon/src/components/Flex/Flex.stories';
import * as SelectStories from '../../../packages/canon/src/components/Select/Select.stories';
export const BoxSnippet = ({ story }: { story: keyof typeof BoxStories }) => {
const stories = composeStories(BoxStories);
@@ -61,12 +61,12 @@ export const FlexSnippet = ({ story }: { story: keyof typeof FlexStories }) => {
return StoryComponent ? <StoryComponent /> : null;
};
export const FieldSnippet = ({
export const TextFieldSnippet = ({
story,
}: {
story: keyof typeof FieldStories;
story: keyof typeof TextFieldStories;
}) => {
const stories = composeStories(FieldStories);
const stories = composeStories(TextFieldStories);
const StoryComponent = stories[story as keyof typeof stories];
return StoryComponent ? <StoryComponent /> : null;
@@ -108,20 +108,20 @@ export const IconSnippet = ({ story }: { story: keyof typeof IconStories }) => {
return StoryComponent ? <StoryComponent /> : null;
};
export const InputSnippet = ({
story,
}: {
story: keyof typeof InputStories;
}) => {
const stories = composeStories(InputStories);
const StoryComponent = stories[story as keyof typeof stories];
return StoryComponent ? <StoryComponent /> : null;
};
export const TextSnippet = ({ story }: { story: keyof typeof TextStories }) => {
const stories = composeStories(TextStories);
const StoryComponent = stories[story as keyof typeof stories];
return StoryComponent ? <StoryComponent /> : null;
};
export const SelectSnippet = ({
story,
}: {
story: keyof typeof SelectStories;
}) => {
const stories = composeStories(SelectStories);
const StoryComponent = stories[story as keyof typeof stories];
return StoryComponent ? <StoryComponent /> : null;
};
+11 -7
View File
@@ -13,6 +13,10 @@ export const overview: Page[] = [
title: 'About',
slug: 'about',
},
{
title: 'Releases',
slug: 'releases',
},
];
export const theme: Page[] = [
@@ -72,11 +76,6 @@ export const components: Page[] = [
slug: 'checkbox',
status: 'alpha',
},
{
title: 'Field',
slug: 'field',
status: 'alpha',
},
{
title: 'Heading',
slug: 'heading',
@@ -93,8 +92,8 @@ export const components: Page[] = [
status: 'alpha',
},
{
title: 'Input',
slug: 'input',
title: 'Select',
slug: 'select',
status: 'alpha',
},
{
@@ -107,6 +106,11 @@ export const components: Page[] = [
slug: 'text',
status: 'alpha',
},
{
title: 'TextField',
slug: 'text-field',
status: 'alpha',
},
];
export type ScreenSize = {
+1 -1
View File
@@ -1,4 +1,4 @@
import React, {
import {
createContext,
useContext,
ReactNode,
+1800 -1800
View File
File diff suppressed because it is too large Load Diff
+8 -8
View File
@@ -192,11 +192,11 @@ check: check-code check-docs check-type-dependencies check-styles
# run development instance
# BUG: the frontend seems to run on "$(backend_port)" (7007 default).
# The documentation states "This is going to start two things,
# The documentation states "This is going to start two things,
# the frontend (:3000) and the backend (:7007)."
# However, the frontend seems to end up running on 7007.
.PHONY: dev
dev: build
start: build
@docker run --rm -it \
--name $(docker_name_timestamp_prefix)-$@ \
-p $(frontend_port):$(frontend_host_port) \
@@ -206,12 +206,12 @@ dev: build
-w /app \
--entrypoint "" \
$(docker_tag) \
yarn dev
yarn start
# convenience: dev alias
.PHONY: start
start: dev
# convenience: start alias
.PHONY: dev
dev: start
# convenience: dev alias
# convenience: start alias
.PHONY: run
run: dev
run: start
@@ -55,15 +55,15 @@ When using ALB authentication Backstage will only be loaded once the user has su
- add the following definition just before the app is created (`const app = createApp`):
```ts
import React from 'react';
import { useState, useEffect } from 'react';
import { UserIdentity } from '@backstage/core-components';
import { SignInPageProps } from '@backstage/core-app-api';
import { useApi, configApiRef } from '@backstage/core-plugin-api';
const SampleSignInComponent: any = (props: SignInPageProps) => {
const [error, setError] = React.useState<string | undefined>();
const [error, setError] = useState<string | undefined>();
const config = useApi(configApiRef);
React.useEffect(() => {
useEffect(() => {
const shouldAuth = !!config.getOptionalConfig('auth.providers.awsalb');
if (shouldAuth) {
fetch(`${window.location.origin}/api/auth/awsalb/refresh`)
@@ -3,7 +3,6 @@
ExampleComponent.tsx reference
```tsx
import React from 'react';
import { Typography, Grid } from '@material-ui/core';
import { identityApiRef, useApi } from '@backstage/core-plugin-api';
import {
@@ -3,7 +3,6 @@
ExampleFetchComponent.tsx reference
```tsx
import React from 'react';
import useAsync from 'react-use/lib/useAsync';
import Alert from '@material-ui/lab/Alert';
import { githubAuthApiRef, useApi } from '@backstage/core-plugin-api';
@@ -1,7 +1,6 @@
ConfluenceResultListItem.tsx reference
```tsx
import React from 'react';
import { Link } from '@backstage/core-components';
import { IndexableDocument } from '@backstage/plugin-search-common';
import {
-1
View File
@@ -37,7 +37,6 @@ components. For example, the
[`ErrorApi`](../reference/core-plugin-api.errorapi.md) can be accessed like this:
```tsx
import React from 'react';
import { useApi, errorApiRef } from '@backstage/core-plugin-api';
export const MyComponent = () => {
@@ -151,3 +151,41 @@ To clarify how to utilize the Auditor feature effectively, we recommend explorin
- It illustrates how to detail various `eventId` values and their corresponding `meta` fields (e.g., `queryType`, `actionType`) for different plugin operations.
These examples provide both a code-level demonstration and a documentation guideline for effectively utilizing the `AuditorService` to manage audit events within your Backstage plugins.
## Severity Log Level Mappings
The Auditor Service provides a way for plugins to log significant events, categorized by their severity. The `severityLogLevelMappings` configuration option enables you to customize how these severity levels are mapped to actual log levels within your Backstage backend, giving you precise control over the verbosity of your audit logs.
### Configuration
The `severityLogLevelMappings` are configured under the `backend.auditor` section of your `app-config.yaml` file. This structure allows you to specify the log level for each severity level supported by the Auditor Service. You can override individual severity levels without changing the entire mapping.
Example configuration:
```yaml
backend:
auditor:
severityLogLevelMappings:
low: debug
medium: info
high: warn
critical: error
```
### Severity Levels and Default Mappings
The Auditor Service supports the following severity levels:
- `low`: Represents low-importance events, typically informational or debug-level.
- `medium`: Represents events of moderate importance, requiring some attention.
- `high`: Represents high-importance events, potentially indicating a problem or security issue.
- `critical`: Represents critical events, requiring immediate attention.
By default, these severity levels are mapped to the following log levels:
- `low`: `debug`
- `medium`: `info`
- `high`: `info`
- `critical`: `info`
As a result, medium, high, and critical events are logged as info-level events by default, while low-level events are treated as debug.
-1
View File
@@ -24,7 +24,6 @@ Create a new `packages/app/src/components/search/SearchPage.tsx` file in your
Backstage app with the following contents:
```tsx
import React from 'react';
import { Content, Header, Page } from '@backstage/core-components';
import { Grid, List, Card, CardContent } from '@material-ui/core';
import {
-4
View File
@@ -242,8 +242,6 @@ which renderers to use. Note that the order of the renderers matters! The first
Here is an example of customizing your `SearchPage`:
```tsx title="packages/app/src/components/searchPage.tsx"
import React from 'react';
import { Grid, Paper } from '@material-ui/core';
import BuildIcon from '@material-ui/icons/Build';
@@ -325,8 +323,6 @@ export const Root = ({ children }: PropsWithChildren<{}>) => {
Assuming you have completely customized your SearchModal, here's an example that renders results with extensions:
```tsx title="packages/app/src/components/searchModal.tsx"
import React from 'react';
import { DialogContent, DialogTitle, Paper } from '@material-ui/core';
import BuildIcon from '@material-ui/icons/Build';
@@ -442,7 +442,6 @@ import {
EntityTypePicker,
UserListPicker,
} from '@backstage/plugin-catalog-react';
import React from 'react';
export const CustomCatalogPage = () => {
const orgName =
@@ -29,7 +29,6 @@ As an example, we will create a component that validates whether a string is in
```tsx
//packages/app/src/scaffolder/ValidateKebabCase/ValidateKebabCaseExtension.tsx
import React from 'react';
import { FieldExtensionComponentProps } from '@backstage/plugin-scaffolder-react';
import type { FieldValidation } from '@rjsf/utils';
import FormControl from '@material-ui/core/FormControl';
@@ -18,8 +18,7 @@ This is the same [field](https://rjsf-team.github.io/react-jsonschema-form/docs/
The [createScaffolderLayout](https://backstage.io/docs/reference/plugin-scaffolder-react.createscaffolderlayout) function is used to mark a component as a custom step layout:
```ts
import React from 'react';
```tsx
import { scaffolderPlugin } from '@backstage/plugin-scaffolder';
import {
createScaffolderLayout,
+1 -2
View File
@@ -181,8 +181,7 @@ provided by the Addon framework.
```tsx
// plugins/your-plugin/src/addons/MakeAllImagesCatGifs.tsx
import React, { useEffect } from 'react';
import { useEffect } from 'react';
import { useShadowRootElements } from '@backstage/plugin-techdocs-react';
// This is a normal react component; in order to make it an Addon, you would
+5 -4
View File
@@ -135,6 +135,7 @@ You can easily customize the TechDocs home page using TechDocs panel layout
Modify your `App.tsx` as follows:
```tsx
import { Fragment, PropsWithChildren } from 'react';
import { TechDocsCustomHome } from '@backstage/plugin-techdocs';
//...
@@ -175,7 +176,7 @@ const techDocsTabsConfig = [
filterPredicate: filterEntity,
panelType: 'TechDocsIndexPage',
title: 'All',
panelProps: { PageWrapper: React.Fragment, CustomHeader: React.Fragment, options: options },
panelProps: { PageWrapper: Fragment, CustomHeader: Fragment, options: options },
},
],
},
@@ -184,7 +185,7 @@ const docsFilter = {
kind: ['Location', 'Resource', 'Component'],
'metadata.annotations.featured-docs': CATALOG_FILTER_EXISTS,
}
const customPageWrapper = ({ children }: React.PropsWithChildren<{}>) =>
const customPageWrapper = ({ children }: PropsWithChildren<{}>) =>
(<PageWithHeader title="Docs" themeId="documentation">{children}</PageWithHeader>)
const AppRoutes = () => {
<FlatRoutes>
@@ -212,7 +213,7 @@ maintain such a component in a new directory at
For example, you can define the following Custom home page component:
```tsx
import React from 'react';
import { ReactNode } from 'react';
import { Content } from '@backstage/core-components';
import {
@@ -232,7 +233,7 @@ import { EntityListDocsGrid } from '@backstage/plugin-techdocs';
export type CustomTechDocsHomeProps = {
groups?: Array<{
title: React.ReactNode;
title: ReactNode;
filterPredicate: ((entity: Entity) => boolean) | string;
}>;
};
@@ -40,7 +40,6 @@ Route refs do not have any behavior themselves. They are an opaque value that re
The code snippet in the previous section does not indicate which plugin the route belongs to. To do so, you have to use it in the creation of any kind of routable extension, such as a page extension:
```tsx title="plugins/catalog/src/plugin.tsx"
import React from 'react';
import {
createFrontendPlugin,
createPageExtension,
@@ -91,7 +90,6 @@ Route references can be used to link to page in the same plugin, or to pages in
Suppose we are creating a plugin that renders a Catalog index page with a link to a "Foo" component details page. Here is the code for the index page:
```tsx title="plugins/catalog/src/components/IndexPage.tsx"
import React from 'react';
import { useRouteRef } from '@backstage/frontend-plugin-api';
import { detailsRouteRef } from '../routes';
@@ -125,7 +123,6 @@ We use the `useRouteRef` hook to create a link generator function that returns t
Let's see how the details page can get the parameters from the URL:
```tsx title="plugins/catalog/src/components/DetailsPage.tsx"
import React from 'react';
import { useRouteRefParams } from '@backstage/frontend-plugin-api';
import { detailsRouteRef } from '../routes';
@@ -169,7 +166,6 @@ export const createComponentExternalRouteRef = createExternalRouteRef();
External routes are also used in a similar way as regular routes:
```tsx title="plugins/catalog/src/components/IndexPage.tsx"
import React from 'react';
import { useRouteRef } from '@backstage/frontend-plugin-api';
import { createComponentExternalRouteRef } from '../routes';
@@ -194,7 +190,6 @@ Given the above binding, using `useRouteRef(createComponentExternalRouteRef)` wi
Now the only thing left is to provide the page and external route via a plugin:
```tsx title="plugins/catalog/src/plugin.tsx"
import React from 'react';
import {
createFrontendPlugin,
createPageExtension,
@@ -333,7 +328,6 @@ export const detailsSubRouteRef = createSubRouteRef({
Using subroutes in a page extension is as simple as this:
```tsx title="plugins/catalog/src/components/IndexPage.tsx"
import React from 'react';
import { Routes, Route, useLocation } from 'react-router-dom';
import { useRouteRef } from '@backstage/frontend-plugin-api';
import { indexRouteRef, detailsSubRouteRef } from '../routes';
@@ -381,7 +375,6 @@ export const IndexPage = () => {
This is how you can get the parameters of a sub route URL:
```tsx title="plugins/catalog/src/components/DetailsPage.tsx"
import React from 'react';
import { useParams } from 'react-router-dom';
export const DetailsPage = () => {
@@ -405,7 +398,6 @@ export const DetailsPage = () => {
Finally, see how a plugin can provide subroutes:
```tsx title="plugins/catalog/src/plugin.tsx"
import React from 'react';
import {
createFrontendPlugin,
createPageExtension,
@@ -1,9 +1,9 @@
---
id: migrations
title: Frontend System Migrations
sidebar_label: Migrations
title: Frontend System Changelog
sidebar_label: Changelog
# prettier-ignore
description: Migration documentation for different versions of the frontend system core APIs.
description: Changelog documentation for different versions of the frontend system core APIs.
---
> **NOTE: The new frontend system is in alpha and is only supported by a small number of plugins.**
@@ -86,7 +86,6 @@ There is one more detail that we need to deal with before moving on. The `app.cr
```tsx title="in packages/app/src/index.tsx"
import '@backstage/cli/asset-types';
import React from 'react';
import ReactDOM from 'react-dom/client';
// highlight-remove-next-line
import App from './App';
@@ -25,7 +25,6 @@ A component can be used for more than one extension, and it should be tested ind
Use the `renderInTestApp` helper to render a given component inside a Backstage test app:
```tsx
import React from 'react';
import { screen } from '@testing-library/react';
import { renderInTestApp } from '@backstage/frontend-test-utils';
import { EntityDetails } from './plugin';
@@ -44,7 +43,6 @@ describe('Entity details component', () => {
To mock [Utility APIs](../architecture/33-utility-apis.md) that are used by your component you can use the `TestApiProvider` to override individual API implementations. In the snippet below, we wrap the component within a `TestApiProvider` in order to mock the catalog client API:
```tsx
import React from 'react';
import { screen } from '@testing-library/react';
import {
renderInTestApp,
@@ -10,7 +10,7 @@ description: Extension blueprints provided by the frontend system and core featu
This section covers many of the [extension blueprints](../architecture/23-extension-blueprints.md) available at your disposal when building Backstage frontend plugins.
## Built-in extension blueprints
## Extension blueprints in `@backstage/frontend-plugin-api`
These are the [extension blueprints](../architecture/23-extension-blueprints.md) provided by the Backstage frontend framework itself.
@@ -46,18 +46,26 @@ Icon bundle extensions provide the ability to replace or provide new icons to th
Translation extension provide custom translation messages for the app. They can be used both to override the default english messages to custom ones, as well as provide translations for additional languages.
## Core feature extension blueprints
## Extension blueprints in `@backstage/plugin-catalog-react/alpha`
These are the [extension blueprints](../architecture/23-extension-blueprints.md) provided by the Backstage core feature plugins.
These are the [extension blueprints](../architecture/23-extension-blueprints.md) provided by the Catalog plugin.
### EntityCard - [Reference](https://github.com/backstage/backstage/blob/master/plugins/catalog-react/report-alpha.api.md)
### EntityCard - [Example](https://github.com/backstage/backstage/blob/75e79518eafc6e6eb55585f166667418419662de/plugins/org/src/alpha.tsx#L27-L36)
Creates entity cards to be displayed on the entity pages of the catalog plugin. Exported as `EntityCardBlueprint`.
### EntityContent - [Reference](https://github.com/backstage/backstage/blob/master/plugins/catalog-react/report-alpha.api.md)
Avoid using `convertLegacyEntityCardExtension` from `@backstage/core-compat-api` to convert legacy entity card extensions to the new system. Instead, use the `EntityCardBlueprint` directly. The legacy converter is only intended to help adapt 3rd party plugins that you don't control, and doesn't produce as good results as using the blueprint directly.
### EntityContent - [Example](https://github.com/backstage/backstage/blob/cd71065a02bed740011daee96a865108a785dff6/plugins/kubernetes/src/alpha/entityContents.tsx#L22-L34)
Creates entity content to be displayed on the entity pages of the catalog plugin. Exported as `EntityContentBlueprint`.
### SearchResultListItem - [Reference](https://github.com/backstage/backstage/blob/master/plugins/search-react/report-alpha.api.md)
Avoid using `convertLegacyEntityContentExtension` from `@backstage/core-compat-api` to convert legacy entity content extensions to the new system. Instead, use the `EntityContentBlueprint` directly. The legacy converter is only intended to help adapt 3rd party plugins that you don't control, and doesn't produce as good results as using the blueprint directly.
## Extension blueprints in `@backstage/plugin-search-react/alpha`
These are the [extension blueprints](../architecture/23-extension-blueprints.md) provided by the Search plugin.
### SearchResultListItem - [Example](https://github.com/backstage/backstage/blob/8cb9a85596a5417a004811ffa429527b17ce9b72/plugins/catalog/src/alpha/searchResultItems.tsx#L19-L27)
Creates search result list items for different types of search results, to be displayed in search result lists. Exported as `SearchResultListItemBlueprint`.
@@ -12,6 +12,12 @@ The main concept is that routes, components, apis are now extensions. You can us
## Migrating the plugin
:::note Note
Unless you are migrating a plugin that is only used within your own project, we recommend all plugins to keep support for the old system intact. The code added in these examples should be added to a new `src/alpha.tsx` entry point of your plugin.
:::
In the legacy frontend system a plugin was defined in its own `plugin.ts` file as following:
```ts title="my-plugin/src/plugin.ts"
@@ -19,7 +25,7 @@ In the legacy frontend system a plugin was defined in its own `plugin.ts` file a
export const myPlugin = createPlugin({
id: 'my-plugin',
apis: [],
apis: [ ... ],
routes: {
...
},
@@ -29,17 +35,17 @@ In the legacy frontend system a plugin was defined in its own `plugin.ts` file a
});
```
In order to migrate the actual definition of the plugin you need to recreate the plugin using the new `createFrontendPlugin` utility exported by `@backstage/frontend-plugin-api`.
The new `createFrontendPlugin` function doesn't accept apis anymore as apis are now extensions.
In order to migrate the actual definition of the plugin you need to recreate the plugin using the new `createFrontendPlugin` utility exported by `@backstage/frontend-plugin-api`. The new `createFrontendPlugin` function doesn't accept apis anymore as apis are now extensions.
```ts title="my-plugin/src/alpha.ts"
```ts title="my-plugin/src/alpha.tsx"
import { createFrontendPlugin } from '@backstage/frontend-plugin-api';
import { convertLegacyRouteRefs } from '@backstage/core-compat-api';
export default createFrontendPlugin({
id: 'my-plugin',
// bind all the extensions to the plugin
/* highlight-next-line */
extensions: [],
extensions: [/* APIs will go here, but don't worry about those yet */],
// convert old route refs to the new system
/* highlight-next-line */
routes: convertLegacyRouteRefs({
@@ -52,20 +58,20 @@ The new `createFrontendPlugin` function doesn't accept apis anymore as apis are
});
```
The code above binds all the extensions to the plugin. _Important_: Make sure to export the plugin as default export of your package as a separate entrypoint, preferably `/alpha`, as suggested by the code snippet above. Make sure `src/alpha.ts` is exported in your `package.json`:
The code above binds all the extensions to the plugin. _Important_: Make sure to export the plugin as default export of your package as a separate entrypoint, preferably `/alpha`, as suggested by the code snippet above. Make sure `src/alpha.tsx` is exported in your `package.json`:
```ts title="my-plugin/package.json"
"exports": {
".": "./src/index.ts",
/* highlight-add-next-line */
"./alpha": "./src/alpha.ts",
"./alpha": "./src/alpha.tsx",
"./package.json": "./package.json"
},
"typesVersions": {
"*": {
/* highlight-add-start */
"alpha": [
"src/alpha.ts"
"src/alpha.tsx"
],
/* highlight-add-end */
"package.json": [
@@ -79,6 +85,8 @@ The code above binds all the extensions to the plugin. _Important_: Make sure to
Pages that were previously created using the `createRoutableExtension` extension function can be migrated to the new Frontend System using the `PageBlueprint` [extension blueprint](../architecture/23-extension-blueprints.md), exported by `@backstage/frontend-plugin-api`.
In the new system plugins provide more information than they used to. For example, the plugin is now responsible for providing the path for the page, rather than it being part of the app code.
For example, given the following page:
```ts
@@ -91,7 +99,13 @@ export const FooPage = fooPlugin.provide(
);
```
it can be migrated as the following:
and the following instruction in the plugin README:
```tsx
<Route path="/foo" element={<FooPage />} />
```
it can be migrated as the following, keeping in mind that you may need to switch from `.ts` to `.tsx`:
```tsx
import { PageBlueprint } from '@backstage/frontend-plugin-api';
@@ -102,15 +116,16 @@ import {
const fooPage = PageBlueprint.make({
params: {
// This is the path that was previously defined in the app code.
// It's labelled as the default one because it can be changed via configuration.
defaultPath: '/foo',
// you can reuse the existing routeRef
// by wrapping into the convertLegacyRouteRef.
// You can reuse the existing routeRef by wrapping it with convertLegacyRouteRef.
routeRef: convertLegacyRouteRef(rootRouteRef),
// these inputs usually match the props required by the component.
loader: ({ inputs }) =>
loader: () =>
import('./components/').then(m =>
// The compatWrapper utility allows you to use the existing
// legacy frontend utilities used internally by the components.
// The compatWrapper utility allows you to keep using @backstage/core-plugin-api in the
// implementation of the component and switch to @backstage/frontend-plugin-api later.
compatWrapper(<m.FooPage />),
),
},
@@ -119,7 +134,7 @@ const fooPage = PageBlueprint.make({
Then add the `fooPage` extension to the plugin:
```ts title="my-plugin/src/alpha.ts"
```ts title="my-plugin/src/alpha.tsx"
import { createFrontendPlugin } from '@backstage/frontend-plugin-api';
export default createFrontendPlugin({
@@ -210,7 +225,7 @@ const exampleWorkApi = ApiBlueprint.make({
Finally, let's add the `exampleWorkApi` extension to the plugin:
```ts title="my-plugin/src/alpha.ts"
```ts title="my-plugin/src/alpha.tsx"
import { createFrontendPlugin } from '@backstage/frontend-plugin-api';
export default createFrontendPlugin({
-2
View File
@@ -416,8 +416,6 @@ In your front-end application, locate the `src` folder. We suggest creating the
```tsx title="customIcons.tsx"
import { SvgIcon, SvgIconProps } from '@material-ui/core';
import React from 'react';
export const ExampleIcon = (props: SvgIconProps) => (
<SvgIcon {...props} viewBox="0 0 24 24">
<path
+1 -1
View File
@@ -111,7 +111,7 @@ If you opt for the second option of replacing the entire string, take care to no
[Start the Backstage app](../index.md#2-run-the-backstage-app):
```shell
yarn dev
yarn start
```
After the Backstage frontend launches, you should notice that nothing has changed. This is a good sign. If everything is setup correctly above, this means that the data is flowing from the demo data files directly into your database!
-3
View File
@@ -37,8 +37,6 @@ yarn --cwd packages/app add @backstage/plugin-home
Inside your `packages/app` directory, create a new file where our new homepage component is going to live. Create `packages/app/src/components/home/HomePage.tsx` with the following initial code
```tsx
import React from 'react';
export const HomePage = () => (
/* We will shortly compose a pretty homepage here. */
<h1>Welcome to Backstage!</h1>
@@ -156,7 +154,6 @@ contribute, check the
> [Contributing documentation](https://github.com/backstage/backstage/blob/master/plugins/home/README.md#contributing)
```tsx
import React from 'react';
import Grid from '@material-ui/core/Grid';
import { HomePageCompanyLogo } from '@backstage/plugin-home';
+2 -2
View File
@@ -116,11 +116,11 @@ If this fails on the `yarn install` step, it's likely that you will need to inst
## 2. Run the Backstage app
Your Backstage app is fully installed and ready to be run! Now that the installation is complete, you can go to the application directory and start the app using the `yarn dev` command. The `yarn dev` command will run both the frontend and backend as separate processes (named `[0]` and `[1]`) in the same window.
Your Backstage app is fully installed and ready to be run! Now that the installation is complete, you can go to the application directory and start the app using the `yarn start` command. The `yarn start` command will run both the frontend and backend as separate processes (named `[0]` and `[1]`) in the same window.
```bash
cd my-backstage-app # your app name
yarn dev
yarn start
```
![Screenshot of the command output, with the message web pack compiled successfully](../assets/getting-started/startup.png)
+1 -1
View File
@@ -16,7 +16,7 @@ You should have already [have a standalone app](./index.md) and completed the Gi
## 1. Login to Backstage
Run your Backstage app with `yarn dev`. Navigate to `http://localhost:3000`.
Run your Backstage app with `yarn start`. Navigate to `http://localhost:3000`.
If you're not already logged in, you should see a login screen like this,
+1 -1
View File
@@ -187,7 +187,7 @@ To install custom rules in a plugin, we need to use the [`PermissionsRegistrySer
backend.add(import('./extensions/catalogPermissionRules'));
```
5. Now when you run you Backstage instance - `yarn dev` - the rule will be added to the catalog plugin.
5. Now when you run you Backstage instance - `yarn start` - the rule will be added to the catalog plugin.
The updated policy will allow catalog entity resource permissions if any of the following are true:
+2 -2
View File
@@ -103,10 +103,10 @@ Now lets test end to end that the permissions framework is setup and configured
enabled: true
```
2. Now run `yarn dev`, Backstage should load up in your browser
2. Now run `yarn start`, Backstage should load up in your browser
3. You should see that you have entities in your Catalog, pretty simple
4. Let's change this line in our Test Permission Policy `return { result: AuthorizeResult.ALLOW };` to be `return { result: AuthorizeResult.DENY };`
5. Run `yarn dev` once again, Backstage should load up in your browser
5. Run `yarn start` once again, Backstage should load up in your browser
6. This time you should not see any entities in your Catalog, if you do then something went wrong along the way and you'll need to review the steps above
7. Revert the change we made in step 4 so that the line looks like this: `return { result: AuthorizeResult.ALLOW };`
+1 -1
View File
@@ -25,7 +25,7 @@ And then select `frontend-plugin`.
This will create a new Backstage Plugin based on the ID that was provided. It
will be built and added to the Backstage App automatically.
> If the Backstage App is already running (with `yarn start` or `yarn dev`) you
> If the Backstage App is already running (with `yarn start`) you
> should be able to see the default page for your new plugin directly by
> navigating to `http://localhost:3000/my-plugin`.
@@ -245,7 +245,7 @@ You can also check out the documentation on [how to test Backstage plugin module
#### 9. Running the collator locally
Run `yarn dev` in the root folder of your Backstage project and look for logs like these:
Run `yarn start` in the root folder of your Backstage project and look for logs like these:
```sh
[backend]: YYYY-MM-DDTHH:MM:SS.000Z search info Task worker starting: search_index_faq_snippets, {"version":2,"cadence":"PT10M","initialDelayDuration":"PT3S","timeoutAfterDuration":"PT15M"} task=search_index_faq_snippets
File diff suppressed because it is too large Load Diff
+33 -6
View File
@@ -48,12 +48,14 @@ help [command] display help for command
The `repo` command category, `yarn backstage-cli repo --help`:
```text
build [options] Build packages in the project, excluding bundled app and backend packages.
lint [options] Lint all packages in the project
clean Delete cache and output directories
list-deprecations [options] List deprecations
test [options] Run tests, forwarding args to Jest, defaulting to watch mode
help [command] display help for command
start [options] [packageName...] Starts packages in the repo for local development
build [options] Build packages in the project, excluding bundled app and backend packages.
test [options] Run tests, forwarding args to Jest, defaulting to watch mode
lint [options] Lint all packages in the project
fix [options] Automatically fix packages in the project
clean Delete cache and output directories
list-deprecations [options] List deprecations
help [command] display help for command
```
The `migrate` command category, `yarn backstage-cli migrate --help`:
@@ -67,6 +69,31 @@ react-router-deps Migrates the react-router dependencies for all packages to
help [command] display help for command
```
## repo start
Start a set of packages in the project for local development. If no explicit packages are listed via arguments or options, packages will instead be selected based on their [package role](./02-build-system.md#package-roles). If a single set of frontend and/or backend packages are found, they will be started. If there are multiple matches the directories 'packages/app' and 'packages/backend' will be preferred. If no matches are found the command will fall back to expecting a single plugin frontend and/or backend package to start instead.
Any `--config` options in the `start` script in `package.json` of the selected packages will be picked up and used, unless a `--config` option is provided to this command, in which case it will be used instead.
Any `--require` option in the `start` script in `package.json` of the selected backend package will be picked up and used.
```text
Usage: backstage-cli repo start [options] [packageNameOrPath...]
Starts packages in the repo for local development
Arguments:
packageNameOrPath Run the specified packages instead of the defaults.
Options:
--plugin <pluginId> Start the dev entry-point for any matching plugin package in the repo (default: [])
--config <path> Config files to load instead of app-config.yaml (default: [])
--inspect [host] Enable debugger in Node.js environments. Applies to backend package only
--inspect-brk [host] Enable debugger in Node.js environments, breaking before code starts. Applies to backend package only
--require <path...> Add a --require argument to the node process. Applies to backend package only
--link <path> Link an external workspace for module resolution
```
## repo build
Builds all packages in the project, excluding bundled packages by default, i.e. ones
+1 -1
View File
@@ -19,7 +19,7 @@ Changing the level can be done by setting the `LOG_LEVEL` environment variable.
For example, to turn on debug logs when running the app locally, you can run:
```shell
LOG_LEVEL=debug yarn dev
LOG_LEVEL=debug yarn start
```
The resulting log should now have more information available for debugging:
+1 -1
View File
@@ -60,6 +60,6 @@ See more command options in the AutoCannon documentation.
Profiling the frontend can be done by using the `React DevTools` extension for Chrome or Firefox.
The extension is available for download from the Chrome Web Store or the Firefox Add-ons website.
To start profiling, start the application with `yarn dev` and open inspector in the browser. In the
To start profiling, start the application with `yarn start` and open inspector in the browser. In the
`Profiler` tab (far to the right), click the `Start profiling` button to start recording. After
you have recorded some data by navigating through the page, click the `Stop profiling` button to stop the recording.
-1
View File
@@ -32,7 +32,6 @@ With that, Backstage's cli and backend will detect public entry point and serve
2. This file is the public entry point for your application, and it should only contain what unauthenticated users should see:
```tsx title="in packages/app/src/index-public-experimental.tsx"
import React from 'react';
import ReactDOM from 'react-dom/client';
import { createApp } from '@backstage/app-defaults';
import { AppRouter } from '@backstage/core-app-api';
-1
View File
@@ -134,7 +134,6 @@ changes, let's start by wiping this component clean.
1. Replace everything in the file with the following:
```tsx
import React from 'react';
import useAsync from 'react-use/lib/useAsync';
import Alert from '@material-ui/lab/Alert';
import { Table, TableColumn, Progress } from '@backstage/core-components';
-1
View File
@@ -50,7 +50,6 @@ To switch a project to React 18, there are generally three changes that need to
```tsx title="packages/app/src/index.tsx"
import '@backstage/cli/asset-types';
import React from 'react';
// highlight-remove-next-line
import ReactDOM from 'react-dom';
// highlight-add-next-line
+1 -1
View File
@@ -62,7 +62,7 @@ For local development, you can add the required flag in your `packages/backend/p
...
```
You can now start your Backstage instance as usual, using `yarn dev`.
You can now start your Backstage instance as usual, using `yarn start`.
## Production Setup
+1 -1
View File
@@ -52,7 +52,7 @@ module.exports = {
outputPath: './.lighthouseci/reports',
preset: 'desktop',
},
startServerCommand: 'yarn start:lighthouse',
startServerCommand: 'yarn start',
startServerReadyPattern: 'webpack compiled successfully',
startServerReadyTimeout: 600000,
numberOfRuns: 1,
@@ -45,7 +45,7 @@ The only thing you need to do is to start the app:
```bash
cd my-app
yarn dev
yarn start
```
And you are good to go! 👍

Some files were not shown because too many files have changed in this diff Show More