Merge branch 'backstage:master' into milliehartnt123-create-ui-doc

This commit is contained in:
milliehartnt123
2025-11-12 08:39:47 -05:00
committed by GitHub
764 changed files with 28261 additions and 5855 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/ui': patch
---
Fix broken external links in Backstage UI Header component.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-org': patch
---
Improved responsiveness of GroupProfileCard component
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/repo-tools': patch
---
Updated knip-reports to detect dependencies in dev/alpha pattern
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend': minor
---
Enable YAML merge keys in yamlPlaceholderResolver
+10
View File
@@ -0,0 +1,10 @@
---
'@backstage/plugin-search-backend-module-elasticsearch': patch
'@backstage/plugin-kubernetes-backend': patch
'@backstage/plugin-techdocs-backend': patch
'@backstage/plugin-signals-backend': patch
'@backstage/plugin-techdocs': patch
'@backstage/plugin-signals': patch
---
Removed/moved unused dependencies
+8
View File
@@ -0,0 +1,8 @@
---
'@backstage/plugin-search-react': minor
'@backstage/plugin-techdocs': minor
'@backstage/plugin-catalog': minor
'@backstage/plugin-search': minor
---
Add support for customizable icons in `SearchResultListItemBlueprint` and related components
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/create-app': patch
---
Bumped create-app version.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/create-app': patch
---
Bumped create-app version.
+27
View File
@@ -0,0 +1,27 @@
---
'@backstage/ui': minor
---
**BREAKING**: Migrated Avatar component from Base UI to custom implementation with size changes:
- Base UI-specific props are no longer supported
- Size values have been updated:
- New `x-small` size added (1.25rem / 20px)
- `small` size unchanged (1.5rem / 24px)
- `medium` size unchanged (2rem / 32px, default)
- `large` size **changed from 3rem to 2.5rem** (40px)
- New `x-large` size added (3rem / 48px)
Migration:
```diff
# Remove Base UI-specific props
- <Avatar src="..." name="..." render={...} />
+ <Avatar src="..." name="..." />
# Update large size usage to x-large for same visual size
- <Avatar src="..." name="..." size="large" />
+ <Avatar src="..." name="..." size="x-large" />
```
Added `purpose` prop for accessibility control (`'informative'` or `'decoration'`).
+58
View File
@@ -0,0 +1,58 @@
---
'@backstage/ui': minor
---
**BREAKING**: Migrated Checkbox component from Base UI to React Aria Components.
API changes required:
- `checked``isSelected`
- `defaultChecked``defaultSelected`
- `disabled``isDisabled`
- `required``isRequired`
- `label` prop removed - use `children` instead
- CSS: `bui-CheckboxLabel` class removed
- Data attribute: `data-checked``data-selected`
- Use without label is no longer supported
Migration examples:
Before:
```tsx
<Checkbox label="Accept terms" checked={agreed} onChange={setAgreed} />
```
After:
```tsx
<Checkbox isSelected={agreed} onChange={setAgreed}>
Accept terms
</Checkbox>
```
Before:
```tsx
<Checkbox label="Option" disabled />
```
After:
```tsx
<Checkbox isDisabled>Option</Checkbox>
```
Before:
```tsx
<Checkbox />
```
After:
```tsx
<Checkbox>
<VisuallyHidden>Accessible label</VisuallyHidden>
</Checkbox>
```
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/ui': patch
---
Fixed CSS issues in Select component including popover width constraints, focus outline behavior, and overflow handling.
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/plugin-catalog-backend': minor
'@backstage/plugin-catalog-node': minor
---
Make YAML merge (<<:) support configurable in the Backstage Catalog instead of always being enabled
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-home': patch
---
Allow customization of VisitList by adding optional enrichVisit, transformPathname, canSave functions to VisitsStorageApi, along with VisitDisplayProvider for colors, labels
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-app-visualizer': patch
---
Improve tree visualizer to use a horizontal layout and fill the content space.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-defaults': patch
---
Fix a bug in the Gitlab URL reader where `search` did not handle multiple globs
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-react': patch
---
Added missing i18n
+9
View File
@@ -0,0 +1,9 @@
---
'@backstage/plugin-notifications-backend': minor
'@backstage/plugin-notifications-common': minor
---
Adds support for default configuration for an entire notification channel.
This setting will also be inherited down to origins and topics while still respecting the users individual choices.
This will be handy if you want to use a "opt-in" strategy.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/ui': patch
---
Improved visual consistency of PasswordField, SearchField, and MenuAutocomplete components.
+10
View File
@@ -0,0 +1,10 @@
---
'@backstage/plugin-notifications-backend': patch
---
Show default settings for notifications even before receiving first notification.
Previously, it was not possible for the users to see or modify their notification settings until they had received at
least one notification from specific origin or topic.
This update ensures that default settings are displayed from the outset,
allowing users to customize their preferences immediately.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/ui': patch
---
Fixed Text component to prevent `truncate` prop from being spread to the underlying DOM element.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend-module-openapi': patch
---
fix wrong dereferencing for AsyncApi 3 documents
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder-backend-module-gitlab': minor
---
fix scaffolder action createDeployToken to allow usage of oauth tokens
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/cli': patch
---
Fix inconsistent behavior in the `new` command for the `@internal` scope: it now consistently defaults to the `backstage-plugin-` infix whether the `--scope` option is not set or it's set to `internal`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-techdocs-module-addons-contrib': patch
---
ExpandableCollapse Techdocs Addon was breaking native sidebar collapse on Firefox
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/ui': patch
---
Improved the Link component structure in Backstage UI.
+70
View File
@@ -0,0 +1,70 @@
---
'@backstage/plugin-catalog-backend-module-ldap': minor
---
Moved from `ldapjs` dependency to `ldapts`
### Breaking Changes
**Type Migration**
Custom transformers must now accept `Entry` from ldapts instead of `SearchEntry`
from ldapjs The Entry type provides direct property access without need for
`.object()` or `.raw()` methods.
If you have custom user or group transformers, update the signature from:
```typescript
(vendor: LdapVendor, config: UserConfig, entry: SearchEntry) =>
Promise<UserEntity | undefined>;
```
to
```typescript
(vendor: LdapVendor, config: UserConfig, entry: Entry) =>
Promise<UserEntity | undefined>;
```
**Search Options**
Updated LDAP search configuration `typesOnly: false``attributeValues: true`
This inverts the boolean logic: ldapjs used negative form while ldapts uses
positive form. Both achieve the same result: retrieving attribute values rather
than just attribute names.
Update LDAP search options in configuration from
```yaml
options:
typesOnly: false
```
to
```yaml
options:
attributeValues: true
```
**API Changes** Removed `LdapClient.searchStreaming()` method. Users should
migrate to `LdapClient.search()` instead
If you're using `searchStreaming` directly:
```typescript
// Before
await client.searchStreaming(dn, options, async entry => {
// process each entry
});
// After
const entries = await client.search(dn, options);
for (const entry of entries) {
// process each entry
}
```
> **_NOTE:_**: Both methods have always loaded all entries into memory. The
> searchStreaming method was only needed internally to handle ldapjs's
> event-based API.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/ui': patch
---
Fixed dialog backdrop appearance in dark mode.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-plugin-api': minor
---
Promote `instanceMetadata` service to main entrypoint.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/ui': patch
---
Migrated CellProfile component from Base UI Avatar to Backstage UI Avatar component.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/ui': minor
---
Fixing styles on SearchField in Backstage UI after migration to CSS modules. `SearchField` has now its own set of class names. We previously used class names from `TextField` but this approach was creating some confusion so going forward in your theme you'll be able to theme `TextField` and `SearchField` separately.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/create-app': patch
---
Added `@backstage/plugin-app-visualizer` to the app in the `--next` template.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-react': patch
---
Apply default ordering of templates
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/ui': patch
---
Avatar components in x-small and small sizes now display only one initial instead of two, improving readability at smaller dimensions.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/repo-tools': minor
---
The `package-docs` command will now automatically use a `typedoc.json` file if one exists at the root of your project.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-gateway-backend': minor
---
Update usage of the `instanceMetadata` service.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-plugin-api': minor
---
Explicitly mark `coreServices.rootInstanceMetadata` as a root service.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-test-utils': patch
---
Tweak some of the mock services to have more precise types
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-app-api': minor
---
Updates API for `instanceMetadata` service to return a list of plugins not features.
+17
View File
@@ -0,0 +1,17 @@
---
'@backstage/frontend-plugin-api': patch
---
Added support for plugin-relative `attachTo` declarations for extension definitions. This allows for the creation of extension and extension blueprints that attach to other extensions of a particular `kind` in the same plugin, rather than needing to provide the exact extension ID. This is particularly useful when wanting to provide extension blueprints with a built-in hierarchy where the extensions created from one blueprint attach to extensions created from the other blueprint, for example:
```ts
// kind: 'tabbed-page'
const parentPage = TabbedPageBlueprint.make({
params: {....}
})
// attachTo: { kind: 'tabbed-page', input: 'tabs' }
const child1 = TabContentBlueprint.make({
name: 'tab1',
params: {....}
})
```
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/ui': patch
---
Removed `@base-ui-components/react` dependency as all components now use React Aria Components.
+63 -1
View File
@@ -207,25 +207,87 @@
"@backstage/plugin-user-settings-common": "0.0.1"
},
"changesets": [
"all-camels-agree",
"all-parrots-change",
"better-hats-cross",
"better-steaks-act",
"breezy-times-ring",
"bright-ears-send",
"busy-goats-create",
"clever-boats-clap",
"create-app-1761312116",
"create-app-1762897504",
"cruel-items-dig",
"cruel-plums-talk",
"deep-gifts-slide",
"easy-hands-grow",
"eighty-mails-leave",
"eighty-results-prove",
"eleven-carpets-win",
"eleven-lights-taste",
"every-ants-count",
"every-clocks-arrive",
"fancy-years-camp",
"fast-tables-sink",
"fast-tools-mate",
"fine-hands-return",
"five-seas-jam",
"fix-text-truncate-prop",
"flat-paws-do",
"fruity-snails-laugh",
"funny-stars-open",
"gentle-bikes-relax",
"giant-lamps-happen",
"grumpy-planes-bet",
"heavy-cars-wash",
"honest-lamps-occur",
"honest-pandas-win",
"huge-taxis-grab",
"itchy-bars-smell",
"legal-weeks-walk",
"lemon-spies-sleep",
"long-humans-sink",
"long-impalas-burn",
"loud-carpets-throw",
"moody-plums-add",
"ninety-cobras-feel",
"odd-states-melt",
"open-cloths-listen",
"open-items-open",
"plugin-relative-extensions",
"polite-eggs-dance",
"polite-seas-divide",
"pretty-kids-allow",
"purple-deer-bet",
"quiet-singers-pick",
"renovate-cd75086",
"rich-streets-rule",
"ripe-crabs-care",
"seven-cycles-pick",
"sharp-dragons-relate",
"short-sides-feel",
"silver-garlics-thank",
"sixty-clowns-run",
"smart-donuts-teach",
"solid-bees-agree",
"solid-dancers-march",
"stupid-doodles-love",
"ten-houses-attack",
"tender-regions-know",
"thirty-hoops-own",
"tough-sloths-spend",
"true-taxes-cover",
"twelve-spoons-feel",
"typescript-constructor-refactor",
"upset-teeth-add",
"warm-carrots-lead",
"warm-ducks-notice",
"warm-moments-repeat",
"wild-owls-divide"
"warm-shrimps-clap",
"wicked-cycles-enter",
"wide-papers-run",
"wild-donkeys-sneeze",
"wild-owls-divide",
"yummy-socks-brake"
]
}
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend-module-github': patch
---
Added configurable `pageSizes` for GitHub GraphQL API queries to prevent `RESOURCE_LIMITS_EXCEEDED` errors with organizations with large number of repositories. Please see the [GitHub Discovery documentation](https://backstage.io/docs/integrations/github/discovery#configuration) for new configuration options.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-graph': patch
---
Ensure the catalog graph entity card respects the height prop so the visualization scales down properly on wide screens.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-signals': patch
---
Fixes a bug where the `SignalClient` would try to subscribe to the same channel twice after an error, instead of just once.
+8
View File
@@ -0,0 +1,8 @@
---
'@backstage/plugin-kubernetes-backend': patch
'@backstage/plugin-kubernetes-common': patch
'@backstage/plugin-kubernetes-node': patch
'@backstage/plugin-kubernetes-react': patch
---
Updated dependency `@kubernetes/client-node` to `1.4.0`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/ui': patch
---
Fixed RadioGroup radio button ellipse distortion by preventing flex shrink and grow.
+17
View File
@@ -0,0 +1,17 @@
---
'@backstage/ui': minor
---
**BREAKING**: Changed className prop behavior to augment default styles instead of being ignored or overriding them.
Affected components:
- Menu, MenuListBox, MenuAutocomplete, MenuAutocompleteListbox, MenuItem, MenuListBoxItem, MenuSection, MenuSeparator
- Switch
- Skeleton
- FieldLabel
- Header, HeaderToolbar
- HeaderPage
- Tabs, TabList, Tab, TabPanel
If you were passing custom className values to any of these components that relied on the previous behavior, you may need to adjust your styles to account for the default classes now being applied alongside your custom classes.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-app-visualizer': patch
---
Migrated to use `@backstage/ui`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/core-components': patch
---
Line numbers in LogViewer will not be selectable in UI anymore
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/ui': patch
---
Enable tree-shaking of imports other than `*.css`.
+15
View File
@@ -0,0 +1,15 @@
---
'@backstage/plugin-scaffolder-backend-module-gitlab': patch
'@backstage/plugin-scaffolder-backend-module-rails': patch
'@backstage/plugin-permission-backend': patch
'@backstage/plugin-permission-common': patch
'@backstage/core-components': patch
'@backstage/core-plugin-api': patch
'@backstage/plugin-devtools-common': patch
'@backstage/plugin-search-backend': patch
'@backstage/core-app-api': patch
'@backstage/plugin-catalog-graph': patch
'@backstage/cli': patch
---
Convert all enums to erasable-syntax compliant patterns
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/frontend-plugin-api': patch
---
Updated to `ExtensionInput` to make all type parameters optional.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend-module-github-org': patch
---
Added configurable `pageSizes` for GitHub GraphQL API queries to prevent `RESOURCE_LIMITS_EXCEEDED` errors with organizations with large number of teams and members. Please see the [GitHub Org Data documentation](https://backstage.io/docs/integrations/github/org#configuration-details) for new configuration options.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/ui': patch
---
Added `loading` prop to Button and ButtonIcon components for displaying spinner during async operations.
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/plugin-catalog-backend': minor
'@backstage/plugin-catalog-node': minor
---
Enable YAML merge keys in yamlPlaceholderResolver
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-mui-to-bui': patch
---
Updated BUI checkbox preview example to align with new component API.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/ui': patch
---
Fixed Table Row component to properly support opening links in new tabs via right-click or Cmd+Click when using the href prop.
+39
View File
@@ -0,0 +1,39 @@
---
'@backstage/ui': minor
---
**BREAKING**: Removed `Collapsible` component. Migrate to `Accordion` or use React Aria `Disclosure`.
## Migration Path 1: Accordion (Opinionated Styled Component)
Accordion provides preset styling with a similar component structure.
```diff
- import { Collapsible } from '@backstage/ui';
+ import { Accordion, AccordionTrigger, AccordionPanel } from '@backstage/ui';
- <Collapsible.Root>
- <Collapsible.Trigger render={(props) => <Button {...props}>Toggle</Button>} />
- <Collapsible.Panel>Content</Collapsible.Panel>
- </Collapsible.Root>
+ <Accordion>
+ <AccordionTrigger title="Toggle" />
+ <AccordionPanel>Content</AccordionPanel>
+ </Accordion>
```
CSS classes: `.bui-CollapsibleRoot``.bui-Accordion`, `.bui-CollapsibleTrigger``.bui-AccordionTrigger` (now on heading element), `.bui-CollapsiblePanel``.bui-AccordionPanel`
## Migration Path 2: React Aria Disclosure (Full Customization)
For custom styling without preset styles:
```tsx
import { Disclosure, Button, DisclosurePanel } from 'react-aria-components';
<Disclosure>
<Button slot="trigger">Toggle</Button>
<DisclosurePanel>Content</DisclosurePanel>
</Disclosure>;
```
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend-module-incremental-ingestion': patch
---
Correctly handle entity removal computation when DB count query returns string
+9
View File
@@ -0,0 +1,9 @@
---
'@backstage/ui': minor
---
**BREAKING**: The `SelectProps` interface now accepts a generic type parameter for selection mode.
Added searchable and multiple selection support to Select component. The component now accepts `searchable`, `selectionMode`, and `searchPlaceholder` props to enable filtering and multi-selection modes.
Migration: If you're using `SelectProps` type directly, update from `SelectProps` to `SelectProps<'single' | 'multiple'>`. Component usage remains backward compatible.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/ui': patch
---
Set the color-scheme property depending on theme
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/ui': patch
---
Added new VisuallyHidden component for hiding content visually while keeping it accessible to screen readers.
+7
View File
@@ -0,0 +1,7 @@
---
'@backstage/plugin-auth-backend': patch
---
Allow configuring dynamic client registration token expiration with config `auth.experimentalDynamicClientRegistration.tokenExpiration`.
Maximum expiration for the DCR token is 24 hours. Default expiration is 1 hour.
@@ -110,6 +110,7 @@ dependabot
deps
dequeue
dequeueing
dereferencing
deserialization
destructured
destructuring
@@ -179,6 +180,7 @@ graphql
GraphQL
graphviz
Hackathons
hackathon
haproxy
hardcoded
hardcoding
@@ -228,6 +230,7 @@ JWTs
Kaewkasi
Kaswell
keepalive
Keycloak
Keyv
Knex
knip
@@ -568,3 +571,4 @@ Zolotusky
zoomable
zsh
resizable
enums
@@ -99,11 +99,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4
- name: Fetch cached Manifests File
id: cache
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: comment.md
key: ${{ needs.setup.outputs.comment-cache-key }}
+1 -1
View File
@@ -24,7 +24,7 @@ jobs:
name: Verify ${{ matrix.node-version }}
steps:
# - name: Harden Runner
# uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1
# uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.5.1
# with:
# egress-policy: audit
+2 -2
View File
@@ -236,7 +236,7 @@ jobs:
# Use the lower-level cache actions for the success cache, so that we can store the cache even on failed builds
- name: restore backstage-cli cache
uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 # v4
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .cache/backstage-cli
key: ${{ runner.os }}-v${{ matrix.node-version }}-backstage-cli-${{ github.run_id }}
@@ -260,7 +260,7 @@ jobs:
# Always save success cache even if there were failures, that way it can be used in re-triggered builds
- name: save backstage-cli cache
uses: actions/cache/save@0400d5f644dc74513175e3cd8d07132dd4860809 # v4
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
if: always()
with:
path: .cache/backstage-cli
+6 -6
View File
@@ -28,7 +28,7 @@ jobs:
egress-policy: audit
- name: find latest release
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
id: find-release
with:
script: |
@@ -82,7 +82,7 @@ jobs:
# Use the lower-level cache actions for the success cache, so that we can store the cache even on failed builds
- name: restore package-docs cache
uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 # v4
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .cache/package-docs
key: ${{ runner.os }}-v${{ matrix.node-version }}-package-docs-stable-${{ github.run_id }}
@@ -102,7 +102,7 @@ jobs:
# Always save success cache even if there were failures, that way it can be used in re-triggered builds
- name: save package-docs cache
uses: actions/cache/save@0400d5f644dc74513175e3cd8d07132dd4860809 # v4
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
if: always()
with:
path: .cache/package-docs
@@ -166,7 +166,7 @@ jobs:
# Use the lower-level cache actions for the success cache, so that we can store the cache even on failed builds
- name: restore package-docs cache
uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 # v4
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .cache/package-docs
key: ${{ runner.os }}-v${{ matrix.node-version }}-package-docs-${{ github.run_id }}
@@ -186,7 +186,7 @@ jobs:
# Always save success cache even if there were failures, that way it can be used in re-triggered builds
- name: save package-docs cache
uses: actions/cache/save@0400d5f644dc74513175e3cd8d07132dd4860809 # v4
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
if: always()
with:
path: .cache/package-docs
@@ -329,7 +329,7 @@ jobs:
run: ls microsite/build && ls microsite/build/storybook && ls microsite/build/api/stable && ls microsite/build/api/next
- name: Deploy both microsite and storybook to gh-pages
uses: JamesIves/github-pages-deploy-action@6c2d9db40f9296374acc17b90404b6e8864128c8 # v4.7.3
uses: JamesIves/github-pages-deploy-action@4a3abc783e1a24aeb44c16e869ad83caf6b4cc23 # v4.7.4
with:
branch: gh-pages
folder: microsite/build
+1 -1
View File
@@ -94,7 +94,7 @@ jobs:
run: yarn backstage-cli config:check --lax
- name: backstage-cli cache
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .cache/backstage-cli
key: ${{ runner.os }}-v${{ matrix.node-version }}-backstage-cli-${{ github.run_id }}
+1 -1
View File
@@ -22,7 +22,7 @@ jobs:
# We need to checkout the `.github/ISSUE_TEMPLATE` for the advanced labeler action to be able to read the templates
# While at it we might as well checkout all of `.github` so that the labeling actions don't need to fetch their configs
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4
with:
sparse-checkout: .github
@@ -0,0 +1,70 @@
name: MUI to BUI Migration Tracker
on:
schedule:
# Run daily at midnight UTC
- cron: '0 0 * * *'
workflow_dispatch:
# Allow manual triggering
permissions:
issues: write
contents: read
jobs:
update-migration-progress:
runs-on: ubuntu-latest
name: Update Migration Progress Issue
steps:
- name: Harden Runner
uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0
with:
egress-policy: audit
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: 20.x
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
uses: backstage/actions/yarn-install@b3c1841fd69e1658ac631afafd0fb140a2309024 # v0.6.17
with:
cache-prefix: ${{ runner.os }}-v20.x
- name: Run migration analysis
id: analysis
run: |
# Run the migration script and save markdown output
yarn mui-to-bui --markdown > migration-report.md
# Read the report into an environment variable (escape for GitHub Actions)
echo "REPORT<<EOF" >> $GITHUB_ENV
cat migration-report.md >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
- name: Update GitHub Issue
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const issueNumber = 31467;
const reportBody = process.env.REPORT;
try {
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
body: reportBody
});
console.log(`✅ Successfully updated issue #${issueNumber}`);
} catch (error) {
console.error(`❌ Error updating issue: ${error.message}`);
throw error;
}
+1 -1
View File
@@ -39,7 +39,7 @@ jobs:
persist-credentials: false
- name: 'Run analysis'
uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2
uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
with:
results_file: results.sarif
results_format: sarif
@@ -29,7 +29,7 @@ jobs:
cache-prefix: ${{ runner.os }}-v20.x
- name: Create Snyk report
uses: snyk/actions/node@77490d94e966421e076e95ad8fa87aa55e5ca409 # master
uses: snyk/actions/node@9adf32b1121593767fc3c057af55b55db032dc04 # master
continue-on-error: true # Snyk CLI exits with error when vulnerabilities are found
with:
args: >
+2 -2
View File
@@ -31,7 +31,7 @@ jobs:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Monitor and Synchronize Snyk Policies
uses: snyk/actions/node@77490d94e966421e076e95ad8fa87aa55e5ca409 # master
uses: snyk/actions/node@9adf32b1121593767fc3c057af55b55db032dc04 # master
with:
command: monitor
args: >
@@ -46,7 +46,7 @@ jobs:
# Above we run the `monitor` command, this runs the `test` command which is
# the one that generates the SARIF report that we can upload to GitHub.
- name: Create Snyk report
uses: snyk/actions/node@77490d94e966421e076e95ad8fa87aa55e5ca409 # master
uses: snyk/actions/node@9adf32b1121593767fc3c057af55b55db032dc04 # master
continue-on-error: true # To make sure that SARIF upload gets called
with:
args: >
+13 -5
View File
@@ -64,21 +64,29 @@ jobs:
- name: Prepare Chromatic Message
if: github.event_name == 'pull_request' && steps.chromatic.outputs.url
id: prepare-message
id: prepareMessage
run: |
if [ "${{ steps.chromatic.outputs.changeCount }}" = "0" ] || [ -z "${{ steps.chromatic.outputs.changeCount }}" ]; then
echo "changes-text=No visual changes detected - [**View build in Chromatic**](${{ steps.chromatic.outputs.buildUrl }})" >> $GITHUB_OUTPUT
echo "changesText=No visual changes detected - [**View build in Chromatic**](${{ steps.chromatic.outputs.buildUrl }})" >> $GITHUB_OUTPUT
else
echo "changes-text=**${{ steps.chromatic.outputs.changeCount }}** visual changes are waiting for review - [**Review changes in Chromatic**](${{ steps.chromatic.outputs.buildUrl }})" >> $GITHUB_OUTPUT
echo "changesText=**${{ steps.chromatic.outputs.changeCount }}** visual changes are waiting for review - [**Review changes in Chromatic**](${{ steps.chromatic.outputs.buildUrl }})" >> $GITHUB_OUTPUT
fi
- name: Post Chromatic Link in PR Comment
- name: Post Chromatic Results to Job Summary
if: github.event_name == 'pull_request' && steps.chromatic.outputs.url
run: |
echo "## 🎨 Visual Testing with Chromatic" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- ${{ steps.prepareMessage.outputs.changesText }}" >> $GITHUB_STEP_SUMMARY
echo "- **${{ steps.chromatic.outputs.specCount}}** stories for **${{ steps.chromatic.outputs.componentCount}}** Components - [**Preview changes in Storybook**](${{ steps.chromatic.outputs.storybookUrl }})" >> $GITHUB_STEP_SUMMARY
- name: Post Chromatic Link in PR Comment
if: github.event_name == 'pull_request' && steps.chromatic.outputs.url && github.event.pull_request.head.repo.full_name == github.repository
uses: mshick/add-pr-comment@v2
with:
message: |
## 🎨 Visual Testing with Chromatic
- ${{ steps.prepare-message.outputs.changes-text }}
- ${{ steps.prepareMessage.outputs.changesText }}
- **${{ steps.chromatic.outputs.specCount}}** stories for **${{ steps.chromatic.outputs.componentCount}}** Components - [**Preview changes in Storybook**](${{ steps.chromatic.outputs.storybookUrl }})
repo-token: ${{ secrets.GITHUB_TOKEN }}
+5 -5
View File
@@ -33,7 +33,7 @@ jobs:
egress-policy: audit
- name: find latest release
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
id: find-release
with:
script: |
@@ -87,7 +87,7 @@ jobs:
# Use the lower-level cache actions for the success cache, so that we can store the cache even on failed builds
- name: restore package-docs cache
uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 # v4
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .cache/package-docs
key: ${{ runner.os }}-v${{ matrix.node-version }}-package-docs-stable-${{ github.run_id }}
@@ -105,7 +105,7 @@ jobs:
# Always save success cache even if there were failures, that way it can be used in re-triggered builds
- name: save package-docs cache
uses: actions/cache/save@0400d5f644dc74513175e3cd8d07132dd4860809 # v4
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
if: always()
with:
path: .cache/package-docs
@@ -168,7 +168,7 @@ jobs:
# Use the lower-level cache actions for the success cache, so that we can store the cache even on failed builds
- name: restore package-docs cache
uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 # v4
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .cache/package-docs
key: ${{ runner.os }}-v${{ matrix.node-version }}-package-docs-next-${{ github.run_id }}
@@ -186,7 +186,7 @@ jobs:
# Always save success cache even if there were failures, that way it can be used in re-triggered builds
- name: save package-docs cache
uses: actions/cache/save@0400d5f644dc74513175e3cd8d07132dd4860809 # v4
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
if: always()
with:
path: .cache/package-docs
+42
View File
@@ -0,0 +1,42 @@
name: Add a welcome comment
on:
pull_request_target:
types: [opened]
permissions:
issues: write
pull-requests: write
contents: read
jobs:
welcome:
runs-on: ubuntu-latest
if: github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR'
steps:
- name: Add a welcome comment
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const pr = context.payload.pull_request
const login = pr.user.login
const message = `
Hi @${login}, thanks for opening your first pull request in Backstage! 👋
A couple of useful links to help you get started:
* [Contributing Guide](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md)
* [DCO Sign-off Instructions](https://github.com/backstage/backstage/blob/master/DCO)
* [Style Guide](https://github.com/backstage/backstage/blob/master/STYLE.md)
We really appreciate your contribution and look forward to reviewing your work. Welcome aboard!
`
await github.rest.issues.createComment({
issue_number: pr.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: message
})
+1 -1
View File
@@ -1,5 +1,5 @@
> [!NOTE]
> 🏖 From Monday October 27th through November 3rd, maintainers and Spotify employees will be on vacation due to Wellness Week. Expect the project to move a little slower than normal, and support to be limited. Normal service will resume after that! 🏝
> ✈️ From Monday November 10th through November 14rd, several maintainers and Spotify employees will be at KubeCon / BackstageCon! Expect the project to move a little slower than normal, and support to be limited. Normal service will resume after that! And do come visit our booth if you are there. ✈️
[![headline](docs/assets/headline.png)](https://backstage.io/)
@@ -6,7 +6,7 @@
# This dockerfile also performs the build first inside docker. This may come
# with a build time impact, but is sometimes desirable. If you want to run the
# build on the host instead, use the file simply named Dockerfile in this folder
# build on the host instead, use the file simply named Dockerfile.hostbuild in this folder
# instead.
# USAGE:
+1 -1
View File
@@ -24,7 +24,7 @@ services:
timeout: 3s
retries: 5
opensearch:
image: opensearchproject/opensearch:2.19.3
image: opensearchproject/opensearch:2.19.4
environment:
plugins.security.disabled: true
discovery.type: single-node
+6
View File
@@ -1,4 +1,6 @@
import createMDX from '@next/mdx';
import path from 'path';
import { fileURLToPath } from 'url';
const nextConfig = {
pageExtensions: ['js', 'jsx', 'md', 'mdx', 'ts', 'tsx'],
@@ -13,6 +15,10 @@ const nextConfig = {
// These are type-level conflicts that don't affect runtime behavior
ignoreBuildErrors: true,
},
outputFileTracingRoot: path.join(
path.dirname(fileURLToPath(import.meta.url)),
'..',
),
};
const withMDX = createMDX({});
+3 -2
View File
@@ -7,7 +7,7 @@
"build": "next build",
"lint": "next lint",
"prestart": "yarn sync:css",
"start": "concurrently \"yarn sync:css:watch\" \"next dev\"",
"start": "next dev",
"sync:css": "node scripts/sync-css.js",
"sync:css:watch": "node scripts/sync-css.js --watch"
},
@@ -16,6 +16,7 @@
"@types/react-dom": "19.1.7"
},
"dependencies": {
"@base-ui-components/react": "^1.0.0-beta.4",
"@codemirror/lang-sass": "^6.0.2",
"@codemirror/view": "^6.34.4",
"@lezer/highlight": "^1.2.1",
@@ -26,6 +27,7 @@
"@storybook/react": "^8.6.12",
"@uiw/codemirror-themes": "^4.23.7",
"@uiw/react-codemirror": "^4.23.7",
"clsx": "^2.1.1",
"html-react-parser": "^5.2.5",
"motion": "^12.4.1",
"next": "15.4.7",
@@ -43,7 +45,6 @@
"@types/react": "19.1.9",
"@types/react-dom": "19.1.7",
"chokidar": "^3.6.0",
"concurrently": "^8.2.2",
"eslint": "^8",
"eslint-config-next": "15.3.4",
"lightningcss": "^1.28.2",
-32
View File
@@ -1,32 +0,0 @@
# About Backstage UI
Backstage UI is a design system created specifically for Backstage, built with React, TypeScript, and vanilla CSS.
This open-source library is hosted in the Backstage monorepo. While it can be used in other projects, Backstage UI
is designed to deliver a consistent, accessible, and extensible experience tailored to Backstage users.
## Philosophy
Backstage empowers product teams to build software faster and with greater quality. Its extensibility,
however, required us to rethink how to deliver a consistent and accessible user experience. Our goal is
to enable plugin creators to design plugins that seamlessly integrate with Backstage&apos;s look and feel while
still allowing customization to match individual brands.
Instead of reinventing the wheel, we chose to focus on layout and styling while leveraging existing headless
component libraries for functionality. This approach allows us to dedicate our efforts to creating a cohesive
and flexible theming system.
## Team
Backstage UI is designed and maintained primarily by Spotify&apos;s Backstage team, leveraging Spotify&apos;s expertise in
crafting high-quality design and technology. Drawing from our experience in building reliable and intuitive
user experiences for the music industry, we&apos;ve created a design system that looks great and works seamlessly.
## Community
Backstage UI is an open-source project and we welcome contributions from the community. If you are interested in
contributing to Backstage UI, please read our [contributing guide](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md)
and our [code of conduct](https://github.com/backstage/backstage/blob/master/CODE_OF_CONDUCT.md).
## License
Backstage UI is licensed under the Apache 2.0 license. See the [LICENSE](https://github.com/backstage/backstage/blob/master/LICENSE) file for more details.
+1 -3
View File
@@ -7,9 +7,7 @@ export default async function Page({
}) {
const { slug } = await params;
const { default: Component } = await import(
`@/content/components/${slug}.mdx`
);
const { default: Component } = await import(`@/content/${slug}.mdx`);
return <Component />;
}
+173
View File
@@ -0,0 +1,173 @@
import { ComponentCards, ComponentCard } from '@/components/ComponentCards';
import { LayoutComponents } from '@/components/LayoutComponents';
import { CodeBlock } from '@/components/CodeBlock';
# Components
## Layout Components
We built a couple of layout components to help you build responsive elements
that will be consistent with the rest of your Backstage instance. These
components are opinionated and use TypeScript to ensure that the props you
provide are the ones coming from the theme.
<CodeBlock
title="Layout components"
code={`<Flex direction="column" gap="4">
<Box>Hello World</Box>
<Inline gap="sm">
<Box>Project 1</Box>
<Box>Project 2</Box>
</Inline>
</Flex>
`}
/>
<LayoutComponents />
## Components
### Actions
<ComponentCards>
<ComponentCard
title="Button"
description="A button component to help you trigger actions."
href="/components/button"
/>
<ComponentCard
title="ButtonLink"
description="A button component to help you trigger actions."
href="/components/button-link"
/>
<ComponentCard
title="ButtonIcon"
description="A button for actions with an icon."
href="/components/button-icon"
/>
<ComponentCard
title="Link"
description="A link component to help you navigate to other pages."
href="/components/link"
/>
</ComponentCards>
### Content display
<ComponentCards>
<ComponentCard
title="Card"
description="A component to separate your content on the page."
href="/components/card"
/>
<ComponentCard
title="Collapsible"
description="A collapsible component for expandable content."
href="/components/collapsible"
/>
</ComponentCards>
### Selection and inputs
<ComponentCards>
<ComponentCard
title="Checkbox"
description="A checkbox component to help you select items."
href="/components/checkbox"
/>
<ComponentCard
title="TextField"
description="A text field component to help you input text."
href="/components/text-field"
/>
<ComponentCard
title="SearchField"
description="A search field component to help you search for items."
href="/components/search-field"
/>
<ComponentCard
title="PasswordField"
description="A password field component to help you input passwords."
href="/components/password-field"
/>
<ComponentCard
title="Select"
description="A select component to help you select items."
href="/components/select"
/>
<ComponentCard
title="Switch"
description="A switch component to help you toggle items."
href="/components/switch"
/>
<ComponentCard
title="RadioGroup"
description="A radio group component to help you select items."
href="/components/radio-group"
/>
</ComponentCards>
### Navigation
<ComponentCards>
<ComponentCard
title="Header"
description="A header component to help you display a header."
href="/components/header"
/>
<ComponentCard
title="HeaderPage"
description="A header to complement the Header component."
href="/components/header-page"
/>
<ComponentCard
title="Menu"
description="A menu component to help you display a menu."
href="/components/menu"
/>
<ComponentCard
title="Tabs"
description="A tabs component to help you display a tabs."
href="/components/tabs"
/>
</ComponentCards>
### Images and icons
<ComponentCards>
<ComponentCard
title="Avatar"
description="A avatar component to help you display user avatars."
href="/components/avatar"
/>
<ComponentCard
title="Icon"
description="A icon component to help you display icons."
href="/components/icon"
/>
</ComponentCards>
### Feedback indicators
<ComponentCards>
<ComponentCard
title="Skeleton"
description="A skeleton component to help you display loading states."
href="/components/skeleton"
/>
<ComponentCard
title="Tooltip"
description="A tooltip component to help you display a tooltip."
href="/components/tooltip"
/>
</ComponentCards>
### Typography
<ComponentCards>
<ComponentCard
title="Text"
description="A text component to help you style your text."
href="/components/text"
/>
</ComponentCards>
-52
View File
@@ -1,52 +0,0 @@
import { CodeBlock } from '@/components/CodeBlock';
import { Banner } from '@/components/Banner';
import { snippet } from './snippets';
# How to install Backstage UI
## How to import BUI's global styles
Backstage UI works by importing a global CSS file at the root of your application. This file includes all the default styles for the components.
First, you'll need to install the package using a package manager. For example, if you're using Yarn:
<CodeBlock
lang="shell"
title="Run this command in your `packages/app` directory"
code={`yarn add @backstage/ui`}
/>
<CodeBlock
lang="tsx"
title="Add this line to `packages/app/src/index.tsx`"
code={`import '@backstage/cli/asset-types';
import ReactDOM from 'react-dom/client';
import App from './App';
import '@backstage/ui/css/styles.css'; // [!code ++]
ReactDOM.createRoot(document.getElementById('root')!).render(<App />);`}
/>
<Banner
text="Import these styles only once at your application root. Plugin developers should skip this step to avoid conflicts."
variant="warning"
/>
## How to use BUI components
As a plugin maintainer, you can use BUI components in your plugin. As mentioned above, you should not import the styles
again in your plugin as this will be handled at the root of your application. To get started, just add the library to
your plugin and import the components you need.
<CodeBlock
lang="shell"
title="Run this command in your `packages/[your-plugin]` directory"
code={`yarn add @backstage/ui`}
/>
<CodeBlock lang="tsx" title="Let's get started 🚀" code={snippet} />
## Next steps
Now that you have the basics down, you can start building your plugin using the new design system.
Please familiarise yourself first with our theming principles. This will help you understand the core concepts of the design system.
If you have any questions, please reach out to us on [Discord](https://discord.gg/MUpMjP2).
+32 -14
View File
@@ -1,28 +1,46 @@
.container {
position: relative;
z-index: 20;
width: calc(100% - 64px);
margin-inline: 0 16px;
margin-left: 32px;
margin-right: 32px;
margin-top: 112px;
margin-bottom: 48px;
padding-inline: 40px;
padding-block: 48px;
background-color: var(--panel);
border-radius: 0.5rem;
padding-inline: 24px;
}
.contentWrapper {
display: flex;
width: 100%;
max-width: 1200px;
margin: 0 auto;
justify-content: center;
flex-direction: column;
}
.content {
width: 100%;
max-width: 960px;
margin: 0 auto;
display: flex;
gap: 40px;
}
.contentInner {
flex: 1;
min-width: 0;
overflow-x: hidden;
}
.toc {
display: none;
}
@media (min-width: 768px) {
.container {
width: calc(100% - 332px - 40px);
margin-left: 332px;
width: calc(100% - 260px);
margin-left: 260px;
margin-right: 40px;
}
}
@media (min-width: 1280px) {
.toc {
display: block;
width: 240px;
flex-shrink: 0;
}
}
+13 -5
View File
@@ -1,9 +1,10 @@
import type { Metadata } from 'next';
import { Sidebar } from '../components/Sidebar';
import { Sidebar } from '@/components/Sidebar/Sidebar';
import { Toolbar } from '@/components/Toolbar';
import { StickyHeader } from '../components/StickyHeader/StickyHeader';
import { Providers } from './providers';
import { CustomTheme } from '@/components/CustomTheme';
import { TableOfContents } from '@/components/TableOfContents';
import { MobileBottomNav } from '@/components/MobileBottomNav';
import styles from './layout.module.css';
import '../css/globals.css';
@@ -51,11 +52,18 @@ export default async function RootLayout({
<body>
<Providers>
<Sidebar />
<Toolbar version={packageVersion} />
<StickyHeader />
<div className={styles.container}>
<div className={styles.content}>{children}</div>
<div className={styles.contentWrapper}>
<Toolbar version={packageVersion} />
<div className={styles.content}>
<div className={styles.contentInner}>{children}</div>
<aside className={styles.toc}>
<TableOfContents />
</aside>
</div>
</div>
</div>
<MobileBottomNav />
<CustomTheme />
</Providers>
</body>
-42
View File
@@ -1,42 +0,0 @@
import { LayoutComponents } from '@/components/LayoutComponents';
import { CodeBlock } from '@/components/CodeBlock';
# Layout
Backstage UI is made for extensibility. We built this library to make it easy for any
Backstage plugin creator to be able to build their ideas at speed ensuring
consistency across the rest of your ecosystem. Each component is designed to
be editable to match your need but sometimes you want to have more control
over the layout of your page. To help you with that, we created a set of
layout components that you can use to build your own layouts. All of these
components are built to extend on our theming system, making it easy for you
to build your own layouts. Sometimes these components are not enough so we
created a set of helpers to be used with any CSS-in-JS library.
## Layout Components
We built a couple of layout components to help you build responsive elements
that will be consistent with the rest of your Backstage instance. These
components are opinionated and use TypeScript to ensure that the props you
provide are the ones coming from the theme.
<CodeBlock
title="Layout components"
code={`<Flex direction="column" gap="4">
<Box>Hello World</Box>
<Inline gap="sm">
<Box>Project 1</Box>
<Box>Project 2</Box>
</Inline>
</Flex>
`}
/>
<LayoutComponents />
## Layout Helpers
Sometimes you want to use global tokens dynamically outside of React
components. To help you with that we would like to provide a set of helpers
that you can use in your code. These helpers are not available just yet but we
are working on it.
+65 -161
View File
@@ -1,179 +1,83 @@
import { ComponentCards, ComponentCard } from '@/components/ComponentCards';
import { CodeBlock } from '@/components/CodeBlock';
import { Banner } from '@/components/Banner';
import { snippet } from './snippets';
## Welcome to Backstage UI, the new design library for Backstage plugins.
# Welcome to Backstage UI
This project is still under active development but we will make sure to document
the API as we go. We are aiming to improve the general UI of Backstage and
plugins across Backstage. This new library will take time to build but we are
building it incrementally with not conflict with the existing theming system.
Backstage UI is a design system created specifically for Backstage, built with React, TypeScript, and vanilla CSS.
This open-source library is hosted in the Backstage monorepo. While it can be used in other projects, Backstage UI
is designed to deliver a consistent, accessible, and extensible experience tailored to Backstage users.
### Actions
## Import BUI's global styles
<ComponentCards>
<ComponentCard
title="Button"
description="A button component to help you trigger actions."
href="/components/button"
/>
<ComponentCard
title="ButtonLink"
description="A button component to help you trigger actions."
href="/components/button-link"
/>
<ComponentCard
title="ButtonIcon"
description="A button for actions with an icon."
href="/components/button-icon"
/>
<ComponentCard
title="Link"
description="A link component to help you navigate to other pages."
href="/components/link"
/>
</ComponentCards>
Backstage UI works by importing a global CSS file at the root of your application. This file includes all the default styles for the components.
First, you'll need to install the package using a package manager. For example, if you're using Yarn:
### Layout
<CodeBlock
lang="shell"
title="Run this command in your `packages/app` directory"
code={`yarn add @backstage/ui`}
/>
<ComponentCards>
<ComponentCard
title="Box"
description="The simplest component to help you style your content."
href="/components/box"
/>
<ComponentCard
title="Flex"
description="A flex container for your layout."
href="/components/flex"
/>
<ComponentCard
title="Grid"
description="A grid container for your layout."
href="/components/grid"
/>
<ComponentCard
title="Container"
description="Helps you center your content."
href="/components/container"
/>
<ComponentCard
title="Card"
description="A component to separate your content on the page."
href="/components/card"
/>
<ComponentCard
title="Collapsible"
description="A collapsible component for expandable content."
href="/components/collapsible"
/>
</ComponentCards>
<CodeBlock
lang="tsx"
title="Add this line to `packages/app/src/index.tsx`"
code={`import '@backstage/cli/asset-types';
import ReactDOM from 'react-dom/client';
import App from './App';
import '@backstage/ui/css/styles.css'; // [!code ++]
### Selection and inputs
ReactDOM.createRoot(document.getElementById('root')!).render(<App />);`}
/>
<ComponentCards>
<ComponentCard
title="Checkbox"
description="A checkbox component to help you select items."
href="/components/checkbox"
/>
<ComponentCard
title="TextField"
description="A text field component to help you input text."
href="/components/text-field"
/>
<ComponentCard
title="SearchField"
description="A search field component to help you search for items."
href="/components/search-field"
/>
<ComponentCard
title="PasswordField"
description="A password field component to help you input passwords."
href="/components/password-field"
/>
<ComponentCard
title="Select"
description="A select component to help you select items."
href="/components/select"
/>
<ComponentCard
title="Switch"
description="A switch component to help you toggle items."
href="/components/switch"
/>
<ComponentCard
title="RadioGroup"
description="A radio group component to help you select items."
href="/components/radio-group"
/>
</ComponentCards>
<Banner
text="Import these styles only once at your application root. Plugin developers should skip this step to avoid conflicts."
variant="warning"
/>
### Navigation
## Use BUI components
<ComponentCards>
<ComponentCard
title="Header"
description="A header component to help you display a header."
href="/components/header"
/>
<ComponentCard
title="HeaderPage"
description="A header to complement the Header component."
href="/components/header-page"
/>
<ComponentCard
title="Menu"
description="A menu component to help you display a menu."
href="/components/menu"
/>
<ComponentCard
title="Tabs"
description="A tabs component to help you display a tabs."
href="/components/tabs"
/>
</ComponentCards>
As a plugin maintainer, you can use BUI components in your plugin. As mentioned above, you should not import the styles
again in your plugin as this will be handled at the root of your application. To get started, just add the library to
your plugin and import the components you need.
### Images and icons
<CodeBlock
lang="shell"
title="Run this command in your `packages/[your-plugin]` directory"
code={`yarn add @backstage/ui`}
/>
<ComponentCards>
<ComponentCard
title="Avatar"
description="A avatar component to help you display user avatars."
href="/components/avatar"
/>
<ComponentCard
title="Icon"
description="A icon component to help you display icons."
href="/components/icon"
/>
</ComponentCards>
### Feedback indicators
<ComponentCards>
<ComponentCard
title="Skeleton"
description="A skeleton component to help you display loading states."
href="/components/skeleton"
/>
<ComponentCard
title="Tooltip"
description="A tooltip component to help you display a tooltip."
href="/components/tooltip"
/>
</ComponentCards>
### Typography
<ComponentCards>
<ComponentCard
title="Text"
description="A text component to help you style your text."
href="/components/text"
/>
</ComponentCards>
<CodeBlock lang="tsx" title="Let's get started 🚀" code={snippet} />
## Support
Now that you have the basics down, you can start building your plugin using the new design system.
Please familiarise yourself first with our theming principles. This will help you understand the core concepts of the design system.
If you have any questions, please reach out to us on [Discord](https://discord.gg/MUpMjP2).
## Philosophy
Backstage empowers product teams to build software faster and with greater quality. Its extensibility,
however, required us to rethink how to deliver a consistent and accessible user experience. Our goal is
to enable plugin creators to design plugins that seamlessly integrate with Backstage&apos;s look and feel while
still allowing customization to match individual brands.
Instead of reinventing the wheel, we chose to focus on layout and styling while leveraging existing headless
component libraries for functionality. This approach allows us to dedicate our efforts to creating a cohesive
and flexible theming system.
## Team
Backstage UI is designed and maintained primarily by Spotify&apos;s Backstage team, leveraging Spotify&apos;s expertise in
crafting high-quality design and technology. Drawing from our experience in building reliable and intuitive
user experiences for the music industry, we&apos;ve created a design system that looks great and works seamlessly.
## Community
Backstage UI is an open-source project and we welcome contributions from the community. If you are interested in
contributing to Backstage UI, please read our [contributing guide](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md)
and our [code of conduct](https://github.com/backstage/backstage/blob/master/CODE_OF_CONDUCT.md).
## License
Backstage UI is licensed under the Apache 2.0 license. See the [LICENSE](https://github.com/backstage/backstage/blob/master/LICENSE) file for more details.
-107
View File
@@ -1,107 +0,0 @@
import * as Table from '@/components/Table';
import { Chip } from '@/components/Chip';
import { CodeBlock } from '@/components/CodeBlock';
# Responsive
Backstage UI is built on a responsive design system, meaning that the components are
designed to adapt to different screen sizes. By default we offer a set of
breakpoints that you can use to create responsive components.
## Breakpoints
<Table.Root>
<Table.Header>
<Table.HeaderRow>
<Table.HeaderCell>Breakpoint prefix</Table.HeaderCell>
<Table.HeaderCell>Minimum width</Table.HeaderCell>
<Table.HeaderCell>CSS</Table.HeaderCell>
</Table.HeaderRow>
</Table.Header>
<Table.Body>
<Table.Row>
<Table.Cell>
<Chip head>xs</Chip>
</Table.Cell>
<Table.Cell>
<Chip>0px</Chip>
</Table.Cell>
<Table.Cell>
<Chip>{`{ ... }`}</Chip>
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
<Chip head>sm</Chip>
</Table.Cell>
<Table.Cell>
<Chip>640px</Chip>
</Table.Cell>
<Table.Cell>
<Chip>{`@media (min-width: 640px) { ... }`}</Chip>
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
<Chip head>md</Chip>
</Table.Cell>
<Table.Cell>
<Chip>768px</Chip>
</Table.Cell>
<Table.Cell>
<Chip>{`@media (min-width: 768px) { ... }`}</Chip>
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
<Chip head>lg</Chip>
</Table.Cell>
<Table.Cell>
<Chip>1024px</Chip>
</Table.Cell>
<Table.Cell>
<Chip>{`@media (min-width: 1024px) { ... }`}</Chip>
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
<Chip head>xl</Chip>
</Table.Cell>
<Table.Cell>
<Chip>1280px</Chip>
</Table.Cell>
<Table.Cell>
<Chip>{`@media (min-width: 1280px) { ... }`}</Chip>
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
<Chip head>2xl</Chip>
</Table.Cell>
<Table.Cell>
<Chip>1536px</Chip>
</Table.Cell>
<Table.Cell>
<Chip>{`@media (min-width: 1536px) { ... }`}</Chip>
</Table.Cell>
</Table.Row>
</Table.Body>
</Table.Root>
## Responsive components
Backstage UI components are designed to be responsive, meaning that they will adapt
to different screen sizes. Not every component is responsive, but the ones
that are will have a prop to control the responsive behavior.
The behaviour is the same for each component. For each prop, instead of adding
the value, you add an object with the value and the breakpoint prefix.
<CodeBlock
code={`// Fixed value
<Button size="small">Button</Button>
// Responsive value
<Button size={{ xs: 'small', md: 'medium' }}>Button</Button>`} />
@@ -3,48 +3,109 @@ import * as Table from '@/components/Table';
import { Chip } from '@/components/Chip';
import { customTheme } from '@/snippets/code-snippets';
# Theming
# Tokens
Backstage UI theming is built entirely on CSS, without relying on any CSS-in-JS libraries.
At its core, it provides a solid default theme that is easily customizable using a
comprehensive set of CSS variables. Additionally, it enables anyone to adapt the design
to their specific needs. Each component comes with fixed class names, making customization
even more straightforward.
## Responsive breakpoints
## Light & Dark modes
Backstage UI is built on a responsive design system, meaning that the components are
designed to adapt to different screen sizes. By default we offer a set of
breakpoints that you can use to create responsive components.
By default, Backstage UI supports both light and dark modes using the `data-theme-mode` attribute.
The light theme is applied by default if no `data-theme-mode` attribute is specified. To create
a custom theme, you'll need to define both light and dark modes as outlined below. If
only one mode is defined, the other will fall back to the default theme.
<Table.Root>
<Table.Header>
<Table.HeaderRow>
<Table.HeaderCell>Breakpoint prefix</Table.HeaderCell>
<Table.HeaderCell>Minimum width</Table.HeaderCell>
<Table.HeaderCell>CSS</Table.HeaderCell>
</Table.HeaderRow>
</Table.Header>
<Table.Body>
<Table.Row>
<Table.Cell>
<Chip head>xs</Chip>
</Table.Cell>
<Table.Cell>
<Chip>0px</Chip>
</Table.Cell>
<Table.Cell>
<Chip>{`{ ... }`}</Chip>
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
<Chip head>sm</Chip>
</Table.Cell>
<Table.Cell>
<Chip>640px</Chip>
</Table.Cell>
<Table.Cell>
<Chip>{`@media (min-width: 640px) { ... }`}</Chip>
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
<Chip head>md</Chip>
</Table.Cell>
<Table.Cell>
<Chip>768px</Chip>
</Table.Cell>
<Table.Cell>
<Chip>{`@media (min-width: 768px) { ... }`}</Chip>
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
<Chip head>lg</Chip>
</Table.Cell>
<Table.Cell>
<Chip>1024px</Chip>
</Table.Cell>
<Table.Cell>
<Chip>{`@media (min-width: 1024px) { ... }`}</Chip>
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
<Chip head>xl</Chip>
</Table.Cell>
<Table.Cell>
<Chip>1280px</Chip>
</Table.Cell>
<Table.Cell>
<Chip>{`@media (min-width: 1280px) { ... }`}</Chip>
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
<Chip head>2xl</Chip>
</Table.Cell>
<Table.Cell>
<Chip>1536px</Chip>
</Table.Cell>
<Table.Cell>
<Chip>{`@media (min-width: 1536px) { ... }`}</Chip>
</Table.Cell>
</Table.Row>
</Table.Body>
</Table.Root>
## How to create your own theme
Backstage UI components are designed to be responsive, meaning that they will adapt
to different screen sizes. Not every component is responsive, but the ones
that are will have a prop to control the responsive behavior.
In our [started guide](/), we ask you to import two css files. The `core.css` file includes
the default set of variables. We recommend to keep this file in place and add your own theme
on top of it. `core.css` also include an opinionated reset. If you decided to remove `core.css`
you will have to provide your own reset css.
The behaviour is the same for each component. For each prop, instead of adding
the value, you add an object with the value and the breakpoint prefix.
Here's an example of how your theme.css file should look like:
<CodeBlock
code={`// Fixed value
<CodeBlock lang="css" code={customTheme} />
<Button size="small">Button</Button>
## CSS class name structure
// Responsive value
All Backstage UI components come with a set of CSS classes that you can use to style them. To make it
easier to identify the class name you can use, we use a specific structure for the class names.
<Button size={{ xs: 'small', md: 'medium' }}>Button</Button>`} />
<img
src="/css-classname-structure.png"
style={{ width: '100%', marginBottom: '32px', marginTop: '16px' }}
/>
Every component has a unique prefix `.bui-` followed by the component name. Component props
are represented using the `data-` attribute. That way, class names are easily identifiable.
## Available CSS variables
### Base colors
## Base colors
These colors are used for special purposes like ring, scrollbar, ...
@@ -123,7 +184,7 @@ These colors are used for special purposes like ring, scrollbar, ...
</Table.Body>
</Table.Root>
### Core background colors
## Core background colors
These colors are used for the background of your application. We are mostly using for now a
single elevated background for panels. `--bui-bg` should mostly use as the main background
@@ -224,7 +285,7 @@ color of your app.
</Table.Body>
</Table.Root>
### Foreground colors
## Foreground colors
Foreground colours are meant to work in pair with a background colours. Typically this would work
for icons, texts, shapes, ... Use a matching name to know what foreground color to use. These colors
@@ -329,7 +390,7 @@ are prefixed with `fg` to make it easier to identify.
</Table.Body>
</Table.Root>
### Border colors
## Border colors
These border colors are mostly meant to be used as borders on top of any components with
low contrast to help as a separator with the different background colors.
@@ -391,7 +452,7 @@ low contrast to help as a separator with the different background colors.
</Table.Body>
</Table.Root>
### Special colors
## Special colors
These colors are used for special purposes like ring, scrollbar, ...
@@ -424,7 +485,7 @@ These colors are used for special purposes like ring, scrollbar, ...
</Table.Body>
</Table.Root>
### Font families
## Font families
We have two fonts that we use across Backstage UI. The first one is the sans-serif
font that we use for the body of the application. The second one is the
@@ -453,7 +514,7 @@ monospace font that we use for code blocks and tables.
</Table.Body>
</Table.Root>
### Font weights
## Font weights
We have two font weights that we use across Backstage UI. Regular or Bold.
@@ -480,7 +541,7 @@ We have two font weights that we use across Backstage UI. Regular or Bold.
</Table.Body>
</Table.Root>
### Spacing
## Spacing
We built a spacing system based on a single value `--bui-space`. This value is
used to calculate the spacing for all the components. By default if you would like to
@@ -619,7 +680,7 @@ tokens for pretty much each spacing properties like padding, margin, gaps, ...
</Table.Body>
</Table.Root>
### Radius
## Radius
We use a radius system to make sure that the components have a consistent look and feel.
+14 -5
View File
@@ -9,15 +9,24 @@ export interface CodeBlockProps {
code?: string;
}
export async function CodeBlock({ lang = 'tsx', title, code }: CodeBlockProps) {
const out = await codeToHtml(code || '', {
lang: lang,
export async function CodeBlock(props: CodeBlockProps) {
const { lang = 'tsx', title, code } = props;
let out = await codeToHtml(code || '', {
lang,
transformers: [transformerNotationDiff({ matchAlgorithm: 'v3' })],
themes: {
light: 'min-light',
light: 'github-dark',
dark: 'min-dark',
},
transformers: [transformerNotationDiff({ matchAlgorithm: 'v3' })],
});
// Remove background-color from the pre tag to use our theme colors
out = out.replace(
/style="([^"]*?)background-color:[^;]+;?([^"]*?)"/g,
'style="$1$2"',
);
// Clean up empty style attributes
out = out.replace(/style=""\s?/g, '');
return <CodeBlockClient out={out} title={title} />;
}
@@ -1,33 +1,29 @@
.codeBlock {
border-radius: 4px;
border: 1px solid var(--border);
border-radius: 8px;
position: relative;
background: transparent;
overflow-x: auto;
font-family: var(--font-mono);
background-color: #fff;
background-color: var(--code-bg);
margin-bottom: 1rem;
}
[data-theme-mode='dark'] .codeBlock {
background-color: #121212;
}
.title {
border-bottom: 1px solid var(--border);
padding: 12px 20px;
font-size: 0.8125rem;
color: var(--primary);
color: #fff;
font-family: var(--font-regular);
font-weight: var(--font-weight-bold);
background-color: var(--code-title);
}
.title code {
background-color: var(--surface-1);
background-color: rgba(255, 255, 255, 0.1);
padding: 0.2rem 0.375rem;
border-radius: 0.25rem;
color: var(--secondary);
font-size: 0.8125rem;
color: #fff;
font-size: 0.75rem;
font-weight: var(--font-weight-bold);
}
.code {
@@ -28,7 +28,7 @@
display: flex;
flex-direction: column;
justify-content: flex-end;
background-color: var(--panel);
background-color: var(--bg);
border-radius: 8px;
border: 1px solid var(--border);
padding: 16px;
@@ -36,7 +36,7 @@
min-height: 120px;
&:hover {
background-color: var(--panel-hover);
background-color: var(--bg-hover);
}
}
@@ -5,7 +5,7 @@
right: 16px;
width: 240px;
height: 47px;
background-color: var(--panel);
background-color: var(--bg);
border-radius: 0.375rem;
border: 1px solid var(--border);
display: flex;
@@ -33,7 +33,7 @@
height: 46px;
flex-shrink: 0;
border-bottom: 1px solid var(--border);
background-color: var(--panel);
background-color: var(--bg);
display: flex;
justify-content: space-between;
align-items: center;
@@ -1,6 +1,6 @@
.container {
display: flex;
background-color: var(--panel);
background-color: var(--bg);
padding: 1.5rem;
border-radius: 0.25rem;
border: 1px solid var(--border);
@@ -19,7 +19,7 @@
& .content {
flex: none;
background-color: var(--panel);
background-color: var(--bg);
border: 1px solid var(--border);
border-radius: 4px;
width: 100%;
@@ -0,0 +1,40 @@
.icon {
display: block;
}
.topLine,
.middleLine,
.bottomLine {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
/* Menu state (default) */
.topLine {
transform-origin: 10px 5px;
transform: rotate(0deg);
}
.middleLine {
opacity: 1;
transform-origin: 10px 10px;
}
.bottomLine {
transform-origin: 10px 15px;
transform: rotate(0deg);
}
/* Close state (when open) */
.icon[data-open='true'] .topLine {
transform-origin: 10px 5px;
transform: translateY(5px) rotate(45deg);
}
.icon[data-open='true'] .middleLine {
opacity: 0;
}
.icon[data-open='true'] .bottomLine {
transform-origin: 10px 15px;
transform: translateY(-5px) rotate(-45deg);
}

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