Merge branch 'backstage:master' into topic/update-backend-tasks-readme
This commit is contained in:
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-rollbar-backend': patch
|
||||
---
|
||||
|
||||
Moved `@backstage/test-utils` to `devDependencies`.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/backend-test-utils': patch
|
||||
---
|
||||
|
||||
Lazy-load `testcontainers` module in order to avoid side-effects.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-auth-backend': patch
|
||||
---
|
||||
|
||||
Replaces the usage of `got` with `node-fetch` in the `getUserPhoto` method of the Microsoft provider
|
||||
@@ -1,24 +0,0 @@
|
||||
---
|
||||
'@backstage/create-app': patch
|
||||
---
|
||||
|
||||
removed inline and internal CSS from index.html
|
||||
|
||||
To make this change to an existing app, apply the following changes to the `packages/app/public/index.html` file:
|
||||
|
||||
Remove internal style
|
||||
|
||||
```diff
|
||||
- <style>
|
||||
- #root {
|
||||
- min-height: 100%;
|
||||
- }
|
||||
- </style>
|
||||
```
|
||||
|
||||
Remove inline style from the body tag
|
||||
|
||||
```diff
|
||||
- <body style="margin: 0">
|
||||
+ <body>
|
||||
```
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-cost-insights': patch
|
||||
---
|
||||
|
||||
Fixed an accidental re-export of `@backstage/test-utils` that broke this plugin in the most recent release.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/test-utils': patch
|
||||
---
|
||||
|
||||
JSON serialize and freeze values stored by the `MockStorageApi`.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/techdocs-common': patch
|
||||
---
|
||||
|
||||
Bump `@azure/identity` from `^1.5.0` to `^2.0.1`.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/backend-common': patch
|
||||
---
|
||||
|
||||
In-memory cache clients instantiated from the same cache manager now share the same memory space.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/backend-common': patch
|
||||
---
|
||||
|
||||
Use the default CSP policy provided by `helmet` directly rather than a copy.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-auth-backend': patch
|
||||
---
|
||||
|
||||
Update `auth0` and `onelogin` providers to allow for `authHandler` and `signIn.resolver` configuration.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-auth-backend': patch
|
||||
---
|
||||
|
||||
Fixed bug on refresh token on Okta provider, now it gets the refresh token and it sends it into providerInfo
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-tech-insights': minor
|
||||
---
|
||||
|
||||
fixes api auth in tech-insights plugin
|
||||
@@ -1,29 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-auth-backend': minor
|
||||
---
|
||||
|
||||
Avoid ever returning OAuth refresh tokens back to the client, and always exchange refresh tokens for a new one when available for all providers.
|
||||
|
||||
This comes with a breaking change to the TypeScript API for custom auth providers. The `refresh` method of `OAuthHandlers` implementation must now return a `{ response, refreshToken }` object rather than a direct response. Existing `refresh` implementations are typically migrated by changing an existing return expression that looks like this:
|
||||
|
||||
```ts
|
||||
return await this.handleResult({
|
||||
fullProfile,
|
||||
params,
|
||||
accessToken,
|
||||
refreshToken,
|
||||
});
|
||||
```
|
||||
|
||||
Into the following:
|
||||
|
||||
```ts
|
||||
return {
|
||||
response: await this.handleResult({
|
||||
fullProfile,
|
||||
params,
|
||||
accessToken,
|
||||
}),
|
||||
refreshToken,
|
||||
};
|
||||
```
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-search': patch
|
||||
---
|
||||
|
||||
Internal cleanup of the exports structure
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/create-app': patch
|
||||
---
|
||||
|
||||
Removed unused templating asset.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-app-backend': patch
|
||||
---
|
||||
|
||||
Set `X-Frame-Options: deny` rather than the default `sameorigin` for all content served by the `app-backend`.`
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Fix issue with plugin:serve for Plugins not using Lerna monorepo.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
remove inline CSS from serve_index.html
|
||||
@@ -1,9 +0,0 @@
|
||||
---
|
||||
'@backstage/backend-common': patch
|
||||
'@backstage/plugin-catalog': patch
|
||||
'@backstage/plugin-catalog-backend': patch
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
'@backstage/plugin-scaffolder-backend': patch
|
||||
---
|
||||
|
||||
Uptake changes to the GitHub Credentials Provider interface.
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-react': patch
|
||||
---
|
||||
|
||||
When a user has zero owned entities when viewing an entity kind in the catalog
|
||||
page, it will be automatically redirected to see all the entities. Furthermore,
|
||||
for the kind User and Group there are no longer the owned selector.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/create-app': patch
|
||||
---
|
||||
|
||||
Add a comment to the default backend about the fallback 404 handler.
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-techdocs': patch
|
||||
---
|
||||
|
||||
Add the techdocs.sanitizer.allowedIframeHosts config.
|
||||
This config allows all iframes which have the host of the attribute src in the 'allowedIframehosts' list to be displayed in the documentation.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@techdocs/cli': patch
|
||||
---
|
||||
|
||||
remove internal and inline CSS from index.html
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-rollbar-backend': patch
|
||||
---
|
||||
|
||||
Replace the usage of `axios` with `node-fetch` in the Rollbar API
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
'@backstage/plugin-scaffolder-backend': patch
|
||||
'@backstage/plugin-scaffolder-common': patch
|
||||
---
|
||||
|
||||
Support navigating back to pre-filled templates to update inputs of scaffolder tasks for resubmission
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-react': patch
|
||||
---
|
||||
|
||||
Add Override Components for Components in @backstage/plugin-catalog-react
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-search': patch
|
||||
---
|
||||
|
||||
Introduces a `<SearchType.Accordion />` variant, which operates on the same part of a search query as the existing `<SearchType />`, but in a more opinionated way (as a single-select control surface suitable for faceted search UIs).
|
||||
|
||||
Check the [search plugin storybook](https://backstage.io/storybook/?path=/story/plugins-search-searchtype--accordion) to see how it can be used.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-search': patch
|
||||
---
|
||||
|
||||
Captures the search term entered in the SearchBarBase as a `search` event.
|
||||
@@ -1,58 +0,0 @@
|
||||
---
|
||||
'@backstage/create-app': patch
|
||||
---
|
||||
|
||||
The `<SearchType />` filter in the composed `SearchPage.tsx` was replaced with the `<SearchType.Accordion />` variant.
|
||||
|
||||
This is an entirely optional change; if you wish to display a control surface for search `types` as a single-select accordion (as opposed to the current multi-select of checkboxes), you can make the following (or similar) changes to your search page layout:
|
||||
|
||||
```diff
|
||||
--- a/packages/app/src/components/search/SearchPage.tsx
|
||||
+++ b/packages/app/src/components/search/SearchPage.tsx
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
SearchType,
|
||||
DefaultResultListItem,
|
||||
} from '@backstage/plugin-search';
|
||||
-import { Content, Header, Page } from '@backstage/core-components';
|
||||
+import { CatalogIcon, Content, DocsIcon, Header, Page } from '@backstage/core-components';
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) => ({
|
||||
bar: {
|
||||
@@ -19,6 +19,7 @@ const useStyles = makeStyles((theme: Theme) => ({
|
||||
},
|
||||
filters: {
|
||||
padding: theme.spacing(2),
|
||||
+ marginTop: theme.spacing(2),
|
||||
},
|
||||
filter: {
|
||||
'& + &': {
|
||||
@@ -41,12 +42,23 @@ const SearchPage = () => {
|
||||
</Paper>
|
||||
</Grid>
|
||||
<Grid item xs={3}>
|
||||
+ <SearchType.Accordion
|
||||
+ name="Result Type"
|
||||
+ defaultValue="software-catalog"
|
||||
+ types={[
|
||||
+ {
|
||||
+ value: 'software-catalog',
|
||||
+ name: 'Software Catalog',
|
||||
+ icon: <CatalogIcon />,
|
||||
+ },
|
||||
+ {
|
||||
+ value: 'techdocs',
|
||||
+ name: 'Documentation',
|
||||
+ icon: <DocsIcon />,
|
||||
+ },
|
||||
+ ]}
|
||||
+ />
|
||||
<Paper className={classes.filters}>
|
||||
- <SearchType
|
||||
- values={['techdocs', 'software-catalog']}
|
||||
- name="type"
|
||||
- defaultValue="software-catalog"
|
||||
- />
|
||||
<SearchFilter.Select
|
||||
className={classes.filter}
|
||||
name="kind"
|
||||
```
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-techdocs-backend': patch
|
||||
---
|
||||
|
||||
Add support for API auth in DefaultTechDocsCollator
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend': patch
|
||||
---
|
||||
|
||||
Support custom file name for `catalog:write` action
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/plugin-kubernetes': patch
|
||||
'@backstage/plugin-kubernetes-backend': patch
|
||||
'@backstage/plugin-kubernetes-common': patch
|
||||
---
|
||||
|
||||
implement dashboard link formatter for GKE
|
||||
@@ -1,13 +0,0 @@
|
||||
---
|
||||
'@backstage/integration': minor
|
||||
---
|
||||
|
||||
Create an interface for the GitHub credentials provider in order to support providing implementations.
|
||||
|
||||
We have changed the name of the `GithubCredentialsProvider` to `SingleInstanceGithubCredentialsProvider`.
|
||||
|
||||
`GithubCredentialsProvider` is now an interface that maybe implemented to provide a custom mechanism to retrieve GitHub credentials.
|
||||
|
||||
In a later release we will support configuring URL readers, scaffolder tasks, and processors with customer GitHub credentials providers.
|
||||
|
||||
If you want to uptake this release, you will need to replace all references to `GithubCredentialsProvider.create` with `SingleInstanceGithubCredentialsProvider.create`.
|
||||
@@ -1,41 +0,0 @@
|
||||
---
|
||||
'@backstage/create-app': patch
|
||||
---
|
||||
|
||||
Add a `scheduler` to the plugin environment, which can schedule collaborative tasks across backends. To apply the same change in your backend, follow the steps below.
|
||||
|
||||
First install the package:
|
||||
|
||||
```shell
|
||||
# From the Backstage repository root
|
||||
cd packages/backend
|
||||
yarn add @backstage/backend-tasks
|
||||
```
|
||||
|
||||
Add the scheduler to your plugin environment type:
|
||||
|
||||
```diff
|
||||
// In packages/backend/src/types.ts
|
||||
+import { PluginTaskScheduler } from '@backstage/backend-tasks';
|
||||
|
||||
export type PluginEnvironment = {
|
||||
+ scheduler: PluginTaskScheduler;
|
||||
```
|
||||
|
||||
And finally make sure to add such an instance to each plugin's environment:
|
||||
|
||||
```diff
|
||||
// In packages/backend/src/index.ts
|
||||
+import { TaskScheduler } from '@backstage/backend-tasks';
|
||||
|
||||
function makeCreateEnv(config: Config) {
|
||||
// ...
|
||||
+ const taskScheduler = TaskScheduler.fromConfig(config);
|
||||
|
||||
return (plugin: string): PluginEnvironment => {
|
||||
// ...
|
||||
+ const scheduler = taskScheduler.forPlugin(plugin);
|
||||
return {
|
||||
+ scheduler,
|
||||
// ...
|
||||
```
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-tech-insights': patch
|
||||
---
|
||||
|
||||
Export `techInsightsApiRef` and associated types.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-tech-insights': patch
|
||||
---
|
||||
|
||||
remove unnecessary http request when running all checks
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/config-loader': patch
|
||||
---
|
||||
|
||||
Bump `typescript-json-schema` from `^0.51.0` to `^0.52.0`.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-tech-insights-backend-module-jsonfc': patch
|
||||
---
|
||||
|
||||
ability to add custom operators
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Add option to build command for minifying the generated code
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/plugin-api-docs': patch
|
||||
'@backstage/plugin-catalog': patch
|
||||
---
|
||||
|
||||
Support customizing index page layouts via outlets
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-auth-backend': patch
|
||||
---
|
||||
|
||||
Enforce cookie SSL protection when in production for auth-backend sessions
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-api-docs': patch
|
||||
---
|
||||
|
||||
Display entity title on `ApiDefinitionCard` if defined
|
||||
@@ -124,6 +124,9 @@ jobs:
|
||||
- name: check api reports and generate API reference
|
||||
run: yarn build:api-reports:only --ci --docs
|
||||
|
||||
- name: verify changesets
|
||||
run: node scripts/verify-changesets.js
|
||||
|
||||
- name: verify doc links
|
||||
run: node scripts/verify-links.js
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ kubernetes:
|
||||
region: 'europe-west1'
|
||||
skipTLSVerify: true
|
||||
skipMetricsLookup: true
|
||||
exposeDashboard: true
|
||||
```
|
||||
|
||||
### `serviceLocatorMethod`
|
||||
@@ -113,9 +114,13 @@ kubectl -n <NAMESPACE> get secret $(kubectl -n <NAMESPACE> get sa <SERVICE_ACCOU
|
||||
Specifies the link to the Kubernetes dashboard managing this cluster.
|
||||
|
||||
Note that you should specify the app used for the dashboard using the
|
||||
**dashboardApp property**, in order to properly format links to kubernetes
|
||||
`dashboardApp` property, in order to properly format links to kubernetes
|
||||
resources, otherwise it will assume that you're running the standard one.
|
||||
|
||||
Note also that this attribute is optional for some kinds of dashboards, such as
|
||||
GKE, which requires additional parameters specified in the `dashboardParameters`
|
||||
option.
|
||||
|
||||
##### `clusters.\*.dashboardApp` (optional)
|
||||
|
||||
Specifies the app that provides the Kubernetes dashboard.
|
||||
@@ -124,11 +129,14 @@ This will be used for formatting links to kubernetes objects inside the
|
||||
dashboard.
|
||||
|
||||
The supported dashboards are: `standard`, `rancher`, `openshift`, `gke`, `aks`,
|
||||
`eks` However, not all of them are implemented yet, so please contribute!
|
||||
`eks`. However, not all of them are implemented yet, so please contribute!
|
||||
|
||||
Note that it will default to the regular dashboard provided by the Kubernetes
|
||||
project (`standard`), that can run in any Kubernetes cluster.
|
||||
|
||||
Note that for the `gke` app, you must provide additional information in the
|
||||
`dashboardParameters` option.
|
||||
|
||||
Note that you can add your own formatter by registering it to the
|
||||
`clusterLinksFormatters` dictionary, in the app project.
|
||||
|
||||
@@ -143,6 +151,43 @@ See also
|
||||
https://github.com/backstage/backstage/tree/master/plugins/kubernetes/src/utils/clusterLinks/formatters
|
||||
for real examples.
|
||||
|
||||
##### `clusters.\*.dashboardParameters` (optional)
|
||||
|
||||
Specifies additional information for the selected `dashboardApp` formatter.
|
||||
|
||||
Note that, even though `dashboardParameters` is optional, it might be mandatory
|
||||
for some dashboards, such as GKE.
|
||||
|
||||
###### required parameters for GKE
|
||||
|
||||
| Name | Description |
|
||||
| ----------- | ------------------------------------------------------------------------ |
|
||||
| projectId | the ID of the GCP project containing your Kubernetes clusters |
|
||||
| region | the region of GCP containing your Kubernetes clusters |
|
||||
| clusterName | the name of your kubernetes cluster, within your `projectId` GCP project |
|
||||
|
||||
Note that the GKE cluster locator can automatically provide the values for the
|
||||
`dashboardApp` and `dashboardParameters` options if you set the
|
||||
`exposeDashboard` property to `true`.
|
||||
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
kubernetes:
|
||||
serviceLocatorMethod:
|
||||
type: 'multiTenant'
|
||||
clusterLocatorMethods:
|
||||
- type: 'config'
|
||||
clusters:
|
||||
- url: http://127.0.0.1:9999
|
||||
name: my-cluster
|
||||
dashboardApp: gke
|
||||
dashboardParameters:
|
||||
projectId: my-project
|
||||
region: us-east1
|
||||
clusterName: my-cluster
|
||||
```
|
||||
|
||||
##### `clusters.\*.caData` (optional)
|
||||
|
||||
PEM-encoded certificate authority certificates.
|
||||
@@ -184,6 +229,10 @@ For example:
|
||||
Will configure the Kubernetes plugin to connect to all GKE clusters in the
|
||||
project `gke-clusters` in the region `europe-west1`.
|
||||
|
||||
Note that the GKE cluster locator can automatically provide the values for the
|
||||
`dashboardApp` and `dashboardParameters` options if you enable the
|
||||
`exposeDashboard` option.
|
||||
|
||||
##### `projectId`
|
||||
|
||||
The Google Cloud project to look for Kubernetes clusters in.
|
||||
@@ -203,6 +252,14 @@ presented by the API server. Defaults to `false`.
|
||||
This determines whether the Kubernetes client looks up resource metrics
|
||||
CPU/Memory for pods returned by the API server. Defaults to `false`.
|
||||
|
||||
##### `exposeDashboard`
|
||||
|
||||
This determines wether the `dashboardApp` and `dashboardParameters` should be
|
||||
automatically configured in order to expose the GKE dashboard from the
|
||||
Kubernetes plugin.
|
||||
|
||||
Defaults to `false`.
|
||||
|
||||
### `customResources` (optional)
|
||||
|
||||
Configures which [custom resources][3] to look for when returning an entity's
|
||||
|
||||
@@ -10,8 +10,7 @@ and find catalog entities. This is already set up by default by
|
||||
`@backstage/create-app`.
|
||||
|
||||
If you want to change the default index page - such as to add a custom filter to
|
||||
the catalog - you can replace the routing in `App.tsx` to point to your own
|
||||
`CatalogIndexPage`.
|
||||
the catalog - you can create your own `CatalogIndexPage`.
|
||||
|
||||
> Note: The catalog index page is designed to have a minimal code footprint to
|
||||
> support easy customization, but creating a copy does introduce a possibility
|
||||
@@ -21,12 +20,11 @@ the catalog - you can replace the routing in `App.tsx` to point to your own
|
||||
|
||||
For example, suppose that I want to allow filtering by a custom annotation added
|
||||
to entities, `company.com/security-tier`. To start, I'll copy the code for the
|
||||
default catalog page and create a component in a
|
||||
[new plugin](../../plugins/create-a-plugin.md):
|
||||
default catalog page and create a component.
|
||||
|
||||
```tsx
|
||||
// imports, etc omitted for brevity. for full source see:
|
||||
// https://github.com/backstage/backstage/blob/master/plugins/catalog/src/components/CatalogPage/CatalogPage.tsx
|
||||
// https://github.com/backstage/backstage/blob/master/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx
|
||||
export const CustomCatalogPage = ({
|
||||
columns,
|
||||
actions,
|
||||
@@ -167,21 +165,7 @@ export const CustomCatalogPage = ({
|
||||
};
|
||||
```
|
||||
|
||||
This page itself can be exported as a routable extension in the plugin:
|
||||
|
||||
```ts
|
||||
export const CustomCatalogIndexPage = myPlugin.provide(
|
||||
createRoutableExtension({
|
||||
name: 'CustomCatalogIndexPage',
|
||||
component: () =>
|
||||
import('./components/CustomCatalogPage').then(m => m.CustomCatalogPage),
|
||||
mountPoint: catalogRouteRef,
|
||||
}),
|
||||
);
|
||||
```
|
||||
|
||||
Finally, we can replace the catalog route in the Backstage application with our
|
||||
new `CustomCatalogIndexPage`.
|
||||
Finally, we can apply our new `CustomCatalogPage`.
|
||||
|
||||
```diff
|
||||
# packages/app/src/App.tsx
|
||||
@@ -189,7 +173,9 @@ const routes = (
|
||||
<FlatRoutes>
|
||||
<Navigate key="/" to="catalog" />
|
||||
- <Route path="/catalog" element={<CatalogIndexPage />} />
|
||||
+ <Route path="/catalog" element={<CustomCatalogIndexPage />} />
|
||||
+ <Route path="/catalog" element={<CatalogIndexPage />}>
|
||||
+ <CustomCatalogPage />
|
||||
+ </Route>
|
||||
```
|
||||
|
||||
The same method can be used to customize the _default_ filters with a different
|
||||
|
||||
@@ -53,8 +53,10 @@ To add a custom theme to your Backstage app, you pass it as configuration to
|
||||
For example, adding the theme that we created in the previous section can be
|
||||
done like this:
|
||||
|
||||
```ts
|
||||
```tsx
|
||||
import { createApp } from '@backstage/app-defaults';
|
||||
import { ThemeProvider } from '@material-ui/core/styles';
|
||||
import CssBaseline from '@material-ui/core/CssBaseline';
|
||||
|
||||
const app = createApp({
|
||||
apis: ...,
|
||||
@@ -63,7 +65,11 @@ const app = createApp({
|
||||
id: 'my-theme',
|
||||
title: 'My Custom Theme',
|
||||
variant: 'light',
|
||||
theme: myTheme,
|
||||
Provider: ({ children }) => (
|
||||
<ThemeProvider theme={myTheme}>
|
||||
<CssBaseline>{children}</CssBaseline>
|
||||
</ThemeProvider>
|
||||
),
|
||||
}]
|
||||
})
|
||||
```
|
||||
@@ -76,60 +82,67 @@ want to use the default themes, they are exported as `lightTheme` and
|
||||
## Example of a custom theme
|
||||
|
||||
```ts
|
||||
const themeOptions = createThemeOptions({
|
||||
import {
|
||||
createTheme,
|
||||
genPageTheme,
|
||||
lightTheme,
|
||||
shapes,
|
||||
} from '@backstage/theme';
|
||||
|
||||
const myTheme = createTheme({
|
||||
palette: {
|
||||
...lightTheme.palette,
|
||||
primary: {
|
||||
main: '#123456',
|
||||
main: '#343b58',
|
||||
},
|
||||
secondary: {
|
||||
main: '#123456',
|
||||
main: '#565a6e',
|
||||
},
|
||||
error: {
|
||||
main: '#123456',
|
||||
main: '#8c4351',
|
||||
},
|
||||
warning: {
|
||||
main: '#123456',
|
||||
main: '#8f5e15',
|
||||
},
|
||||
info: {
|
||||
main: '#123456',
|
||||
main: '#34548a',
|
||||
},
|
||||
success: {
|
||||
main: '#123456',
|
||||
main: '#485e30',
|
||||
},
|
||||
background: {
|
||||
default: '#123456',
|
||||
paper: '#123456',
|
||||
default: '#d5d6db',
|
||||
paper: '#d5d6db',
|
||||
},
|
||||
banner: {
|
||||
info: '#123456',
|
||||
error: '#123456',
|
||||
text: '#123456',
|
||||
link: '#123456',
|
||||
info: '#34548a',
|
||||
error: '#8c4351',
|
||||
text: '#343b58',
|
||||
link: '#565a6e',
|
||||
},
|
||||
errorBackground: '#123456',
|
||||
warningBackground: '#123456',
|
||||
infoBackground: '#123456',
|
||||
errorBackground: '#8c4351',
|
||||
warningBackground: '#8f5e15',
|
||||
infoBackground: '#343b58',
|
||||
navigation: {
|
||||
background: '#123456',
|
||||
indicator: '#123456',
|
||||
color: '#123456',
|
||||
selectedColor: '#123456',
|
||||
background: '#343b58',
|
||||
indicator: '#8f5e15',
|
||||
color: '#d5d6db',
|
||||
selectedColor: '#ffffff',
|
||||
},
|
||||
},
|
||||
defaultPageTheme: 'home',
|
||||
fontFamily: 'Comic Sans',
|
||||
fontFamily: 'Comic Sans MS',
|
||||
/* below drives the header colors */
|
||||
pageTheme: {
|
||||
home: genPageTheme(['#123456', '#123456'], shapes.wave),
|
||||
documentation: genPageTheme(['#123456', '#123456'], shapes.wave2),
|
||||
tool: genPageTheme(['#123456', '#123456'], shapes.round),
|
||||
service: genPageTheme(['#123456', '#123456'], shapes.wave),
|
||||
website: genPageTheme(['#123456', '#123456'], shapes.wave),
|
||||
library: genPageTheme(['#123456', '#123456'], shapes.wave),
|
||||
other: genPageTheme(['#123456', '#123456'], shapes.wave),
|
||||
app: genPageTheme(['#123456', '#123456'], shapes.wave),
|
||||
apis: genPageTheme(['#123456', '#123456'], shapes.wave),
|
||||
home: genPageTheme(['#8c4351', '#343b58'], shapes.wave),
|
||||
documentation: genPageTheme(['#8c4351', '#343b58'], shapes.wave2),
|
||||
tool: genPageTheme(['#8c4351', '#343b58'], shapes.round),
|
||||
service: genPageTheme(['#8c4351', '#343b58'], shapes.wave),
|
||||
website: genPageTheme(['#8c4351', '#343b58'], shapes.wave),
|
||||
library: genPageTheme(['#8c4351', '#343b58'], shapes.wave),
|
||||
other: genPageTheme(['#8c4351', '#343b58'], shapes.wave),
|
||||
app: genPageTheme(['#8c4351', '#343b58'], shapes.wave),
|
||||
apis: genPageTheme(['#8c4351', '#343b58'], shapes.wave),
|
||||
},
|
||||
});
|
||||
```
|
||||
@@ -162,7 +175,7 @@ wouldn't be enough to alter the `box-shadow` property or to add css rules that
|
||||
aren't already defined like a margin. For these cases you should also create an
|
||||
override.
|
||||
|
||||
```ts
|
||||
```tsx
|
||||
import { createApp } from '@backstage/core-app-api';
|
||||
import { BackstageTheme, lightTheme } from '@backstage/theme';
|
||||
/**
|
||||
@@ -187,6 +200,16 @@ export const createCustomThemeOverrides = (
|
||||
};
|
||||
};
|
||||
|
||||
const customTheme: BackstageTheme = {
|
||||
...lightTheme,
|
||||
overrides: {
|
||||
// These are the overrides that Backstage applies to `material-ui` components
|
||||
...lightTheme.overrides,
|
||||
// These are your custom overrides, either to `material-ui` or Backstage components.
|
||||
...createCustomThemeOverrides(lightTheme),
|
||||
},
|
||||
};
|
||||
|
||||
const app = createApp({
|
||||
apis: ...,
|
||||
plugins: ...,
|
||||
@@ -194,15 +217,11 @@ const app = createApp({
|
||||
id: 'my-theme',
|
||||
title: 'My Custom Theme',
|
||||
variant: 'light',
|
||||
theme: {
|
||||
...lightTheme,
|
||||
overrides: {
|
||||
// These are the overrides that Backstage applies to `material-ui` components
|
||||
...lightTheme.overrides,
|
||||
// These are your custom overrides, either to `material-ui` or Backstage components.
|
||||
...createCustomThemeOverrides(lightTheme),
|
||||
},
|
||||
},
|
||||
Provider: ({ children }) => (
|
||||
<ThemeProvider theme={customTheme}>
|
||||
<CssBaseline>{children}</CssBaseline>
|
||||
</ThemeProvider>
|
||||
),
|
||||
}]
|
||||
});
|
||||
```
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# @backstage/backend-common
|
||||
|
||||
## 0.10.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 94cdf5d1bd: In-memory cache clients instantiated from the same cache manager now share the same memory space.
|
||||
- 916b2f1f3e: Use the default CSP policy provided by `helmet` directly rather than a copy.
|
||||
- 7d4b4e937c: Uptake changes to the GitHub Credentials Provider interface.
|
||||
- 995e4c7d9d: Added support for non-"amazonaws.com" hosts (for example when testing with LocalStack) in AwsS3UrlReader.
|
||||
- Updated dependencies
|
||||
- @backstage/integration@0.7.0
|
||||
- @backstage/config-loader@0.9.1
|
||||
|
||||
## 0.10.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-common",
|
||||
"description": "Common functionality library for Backstage backends",
|
||||
"version": "0.10.0",
|
||||
"version": "0.10.1",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"private": false,
|
||||
@@ -31,9 +31,9 @@
|
||||
"dependencies": {
|
||||
"@backstage/cli-common": "^0.1.6",
|
||||
"@backstage/config": "^0.1.11",
|
||||
"@backstage/config-loader": "^0.9.0",
|
||||
"@backstage/config-loader": "^0.9.1",
|
||||
"@backstage/errors": "^0.1.5",
|
||||
"@backstage/integration": "^0.6.10",
|
||||
"@backstage/integration": "^0.7.0",
|
||||
"@backstage/types": "^0.1.1",
|
||||
"@google-cloud/storage": "^5.8.0",
|
||||
"@lerna/project": "^4.0.0",
|
||||
@@ -81,8 +81,8 @@
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.10.3",
|
||||
"@backstage/test-utils": "^0.2.0",
|
||||
"@backstage/cli": "^0.10.4",
|
||||
"@backstage/test-utils": "^0.2.1",
|
||||
"@types/archiver": "^5.1.0",
|
||||
"@types/compression": "^1.7.0",
|
||||
"@types/concat-stream": "^1.6.0",
|
||||
|
||||
@@ -178,7 +178,7 @@ describe('AwsS3UrlReader', () => {
|
||||
),
|
||||
).rejects.toThrow(
|
||||
Error(
|
||||
`Could not retrieve file from S3; caused by Error: not a valid AWS S3 URL: https://test-bucket.s3.us-east-2.NOTamazonaws.com/file.yaml`,
|
||||
`Could not retrieve file from S3; caused by Error: invalid AWS S3 URL, cannot parse region from host in https://test-bucket.s3.us-east-2.NOTamazonaws.com/file.yaml`,
|
||||
),
|
||||
);
|
||||
});
|
||||
@@ -234,7 +234,7 @@ describe('AwsS3UrlReader', () => {
|
||||
),
|
||||
).rejects.toThrow(
|
||||
Error(
|
||||
`Could not retrieve file from S3; caused by Error: not a valid AWS S3 URL: https://test-bucket.s3.us-east-2.NOTamazonaws.com/file.yaml`,
|
||||
`Could not retrieve file from S3; caused by Error: invalid AWS S3 URL, cannot parse region from host in https://test-bucket.s3.us-east-2.NOTamazonaws.com/file.yaml`,
|
||||
),
|
||||
);
|
||||
});
|
||||
@@ -332,4 +332,47 @@ describe('AwsS3UrlReader', () => {
|
||||
expect(body.toString().trim()).toBe('site_name: Test');
|
||||
});
|
||||
});
|
||||
|
||||
describe('readNonAwsHost', () => {
|
||||
let awsS3UrlReader: AwsS3UrlReader;
|
||||
|
||||
beforeAll(() => {
|
||||
AWSMock.setSDKInstance(aws);
|
||||
AWSMock.mock(
|
||||
'S3',
|
||||
'getObject',
|
||||
Buffer.from(
|
||||
require('fs').readFileSync(
|
||||
path.resolve(
|
||||
__dirname,
|
||||
'__fixtures__/awsS3/awsS3-mock-object.yaml',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
const s3 = new aws.S3();
|
||||
awsS3UrlReader = new AwsS3UrlReader(
|
||||
new AwsS3Integration(
|
||||
readAwsS3IntegrationConfig(
|
||||
new ConfigReader({
|
||||
host: 'localhost:4566',
|
||||
accessKeyId: 'fake-access-key',
|
||||
secretAccessKey: 'fake-secret-key',
|
||||
endpoint: 'http://localhost:4566',
|
||||
s3ForcePathStyle: true,
|
||||
}),
|
||||
),
|
||||
),
|
||||
{ s3, treeResponseFactory },
|
||||
);
|
||||
});
|
||||
|
||||
it('returns contents of an object in a bucket', async () => {
|
||||
const response = await awsS3UrlReader.read(
|
||||
'http://localhost:4566/test-bucket/awsS3-mock-object.yaml',
|
||||
);
|
||||
expect(response.toString().trim()).toBe('site_name: Test');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -27,12 +27,17 @@ import {
|
||||
UrlReader,
|
||||
} from './types';
|
||||
import getRawBody from 'raw-body';
|
||||
import { AwsS3Integration, ScmIntegrations } from '@backstage/integration';
|
||||
import {
|
||||
AwsS3Integration,
|
||||
ScmIntegrations,
|
||||
AwsS3IntegrationConfig,
|
||||
} from '@backstage/integration';
|
||||
import { ForwardedError, NotModifiedError } from '@backstage/errors';
|
||||
import { ListObjectsV2Output, ObjectList } from 'aws-sdk/clients/s3';
|
||||
|
||||
const parseURL = (
|
||||
url: string,
|
||||
config: AwsS3IntegrationConfig,
|
||||
): { path: string; bucket: string; region: string } => {
|
||||
let { host, pathname } = new URL(url);
|
||||
|
||||
@@ -42,20 +47,45 @@ const parseURL = (
|
||||
*/
|
||||
pathname = pathname.substr(1);
|
||||
|
||||
let bucket;
|
||||
let region;
|
||||
|
||||
/**
|
||||
* Checks that the given URL is a valid S3 object url.
|
||||
* Format of a Valid S3 URL: https://bucket-name.s3.Region.amazonaws.com/keyname
|
||||
* Path style URLs: https://s3.Region.amazonaws.com/bucket-name/key-name
|
||||
* Virtual hosted style URLs: https://bucket-name.s3.Region.amazonaws.com/key-name
|
||||
* See https://docs.aws.amazon.com/AmazonS3/latest/userguide/VirtualHosting.html#path-style-access
|
||||
*/
|
||||
const validHost = new RegExp(
|
||||
/^[a-z\d][a-z\d\.-]{1,61}[a-z\d]\.s3\.[a-z\d-]+\.amazonaws.com$/,
|
||||
);
|
||||
if (!validHost.test(host)) {
|
||||
throw new Error(`not a valid AWS S3 URL: ${url}`);
|
||||
if (config.s3ForcePathStyle) {
|
||||
if (pathname.indexOf('/') < 0) {
|
||||
throw new Error(
|
||||
`invalid path-style AWS S3 URL, ${url} does not contain bucket in the path`,
|
||||
);
|
||||
}
|
||||
[bucket] = pathname.split('/');
|
||||
pathname = pathname.substr(bucket.length + 1);
|
||||
} else {
|
||||
if (host.indexOf('.') < 0) {
|
||||
throw new Error(
|
||||
`invalid virtual hosted-style AWS S3 URL, ${url} does not contain bucket prefix in the host`,
|
||||
);
|
||||
}
|
||||
[bucket] = host.split('.');
|
||||
host = host.substr(bucket.length + 1);
|
||||
}
|
||||
|
||||
const [bucket] = host.split(/\.s3\.[a-z\d-]+\.amazonaws.com/);
|
||||
host = host.substring(bucket.length);
|
||||
const [, , region, ,] = host.split('.');
|
||||
// Only extract region from *.amazonaws.com hosts
|
||||
if (config.host === 'amazonaws.com') {
|
||||
// At this point bucket prefix is removed from host for virtual hosted URLs
|
||||
const match = host.match(/^s3\.([a-z\d-]+)\.amazonaws\.com$/);
|
||||
if (!match) {
|
||||
throw new Error(
|
||||
`invalid AWS S3 URL, cannot parse region from host in ${url}`,
|
||||
);
|
||||
}
|
||||
region = match[1];
|
||||
} else {
|
||||
region = '';
|
||||
}
|
||||
|
||||
return {
|
||||
path: pathname,
|
||||
@@ -70,9 +100,12 @@ export class AwsS3UrlReader implements UrlReader {
|
||||
|
||||
return integrations.awsS3.list().map(integration => {
|
||||
const creds = AwsS3UrlReader.buildCredentials(integration);
|
||||
|
||||
const s3 = new S3({
|
||||
apiVersion: '2006-03-01',
|
||||
credentials: creds,
|
||||
endpoint: integration.config.endpoint,
|
||||
s3ForcePathStyle: integration.config.s3ForcePathStyle,
|
||||
});
|
||||
const reader = new AwsS3UrlReader(integration, {
|
||||
s3,
|
||||
@@ -138,7 +171,7 @@ export class AwsS3UrlReader implements UrlReader {
|
||||
options?: ReadUrlOptions,
|
||||
): Promise<ReadUrlResponse> {
|
||||
try {
|
||||
const { path, bucket, region } = parseURL(url);
|
||||
const { path, bucket, region } = parseURL(url, this.integration.config);
|
||||
aws.config.update({ region: region });
|
||||
|
||||
let params;
|
||||
@@ -178,7 +211,7 @@ export class AwsS3UrlReader implements UrlReader {
|
||||
options?: ReadTreeOptions,
|
||||
): Promise<ReadTreeResponse> {
|
||||
try {
|
||||
const { path, bucket, region } = parseURL(url);
|
||||
const { path, bucket, region } = parseURL(url, this.integration.config);
|
||||
const allObjects: ObjectList = [];
|
||||
const responses = [];
|
||||
let continuationToken: string | undefined;
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
# @backstage/backend-test-utils
|
||||
|
||||
## 0.1.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 130b7aadf2: Lazy-load `testcontainers` module in order to avoid side-effects.
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.10.1
|
||||
- @backstage/cli@0.10.4
|
||||
|
||||
## 0.1.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-test-utils",
|
||||
"description": "Test helpers library for Backstage backends",
|
||||
"version": "0.1.11",
|
||||
"version": "0.1.12",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"private": false,
|
||||
@@ -30,8 +30,8 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/backend-common": "^0.10.0",
|
||||
"@backstage/cli": "^0.10.3",
|
||||
"@backstage/backend-common": "^0.10.1",
|
||||
"@backstage/cli": "^0.10.4",
|
||||
"@backstage/config": "^0.1.9",
|
||||
"knex": "^0.95.1",
|
||||
"mysql2": "^2.2.5",
|
||||
@@ -41,7 +41,7 @@
|
||||
"uuid": "^8.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.10.3",
|
||||
"@backstage/cli": "^0.10.4",
|
||||
"jest": "^26.0.1"
|
||||
},
|
||||
"files": [
|
||||
|
||||
@@ -1,5 +1,25 @@
|
||||
# example-backend
|
||||
|
||||
## 0.2.59
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-rollbar-backend@0.1.18
|
||||
- @backstage/plugin-auth-backend@0.6.0
|
||||
- @backstage/backend-common@0.10.1
|
||||
- @backstage/plugin-app-backend@0.3.21
|
||||
- @backstage/plugin-catalog-backend@0.19.4
|
||||
- @backstage/plugin-scaffolder-backend@0.15.19
|
||||
- @backstage/integration@0.7.0
|
||||
- @backstage/plugin-techdocs-backend@0.12.2
|
||||
- @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.4
|
||||
- @backstage/plugin-permission-backend@0.2.3
|
||||
- @backstage/plugin-permission-node@0.2.3
|
||||
- @backstage/plugin-code-coverage-backend@0.1.18
|
||||
- @backstage/plugin-scaffolder-backend-module-rails@0.2.2
|
||||
- @backstage/plugin-todo-backend@0.1.17
|
||||
|
||||
## 0.2.58
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "example-backend",
|
||||
"version": "0.2.58",
|
||||
"version": "0.2.59",
|
||||
"main": "dist/index.cjs.js",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -24,38 +24,38 @@
|
||||
"migrate:create": "knex migrate:make -x ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/backend-common": "^0.10.0",
|
||||
"@backstage/backend-common": "^0.10.1",
|
||||
"@backstage/backend-tasks": "^0.1.0",
|
||||
"@backstage/catalog-client": "^0.5.3",
|
||||
"@backstage/catalog-model": "^0.9.8",
|
||||
"@backstage/config": "^0.1.10",
|
||||
"@backstage/integration": "^0.6.10",
|
||||
"@backstage/plugin-app-backend": "^0.3.20",
|
||||
"@backstage/plugin-auth-backend": "^0.5.2",
|
||||
"@backstage/integration": "^0.7.0",
|
||||
"@backstage/plugin-app-backend": "^0.3.21",
|
||||
"@backstage/plugin-auth-backend": "^0.6.0",
|
||||
"@backstage/plugin-azure-devops-backend": "^0.2.6",
|
||||
"@backstage/plugin-badges-backend": "^0.1.14",
|
||||
"@backstage/plugin-catalog-backend": "^0.19.3",
|
||||
"@backstage/plugin-code-coverage-backend": "^0.1.17",
|
||||
"@backstage/plugin-catalog-backend": "^0.19.4",
|
||||
"@backstage/plugin-code-coverage-backend": "^0.1.18",
|
||||
"@backstage/plugin-graphql-backend": "^0.1.10",
|
||||
"@backstage/plugin-jenkins-backend": "^0.1.10",
|
||||
"@backstage/plugin-kubernetes-backend": "^0.4.1",
|
||||
"@backstage/plugin-kafka-backend": "^0.2.13",
|
||||
"@backstage/plugin-permission-backend": "^0.2.2",
|
||||
"@backstage/plugin-permission-backend": "^0.2.3",
|
||||
"@backstage/plugin-permission-common": "^0.3.0",
|
||||
"@backstage/plugin-permission-node": "^0.2.2",
|
||||
"@backstage/plugin-permission-node": "^0.2.3",
|
||||
"@backstage/plugin-proxy-backend": "^0.2.15",
|
||||
"@backstage/plugin-rollbar-backend": "^0.1.17",
|
||||
"@backstage/plugin-scaffolder-backend": "^0.15.18",
|
||||
"@backstage/plugin-scaffolder-backend-module-rails": "^0.2.1",
|
||||
"@backstage/plugin-rollbar-backend": "^0.1.18",
|
||||
"@backstage/plugin-scaffolder-backend": "^0.15.19",
|
||||
"@backstage/plugin-scaffolder-backend-module-rails": "^0.2.2",
|
||||
"@backstage/plugin-search-backend": "^0.3.0",
|
||||
"@backstage/plugin-search-backend-node": "^0.4.2",
|
||||
"@backstage/plugin-search-backend-module-elasticsearch": "^0.0.7",
|
||||
"@backstage/plugin-search-backend-module-pg": "^0.2.3",
|
||||
"@backstage/plugin-techdocs-backend": "^0.12.1",
|
||||
"@backstage/plugin-techdocs-backend": "^0.12.2",
|
||||
"@backstage/plugin-tech-insights-backend": "^0.1.4",
|
||||
"@backstage/plugin-tech-insights-node": "^0.1.2",
|
||||
"@backstage/plugin-tech-insights-backend-module-jsonfc": "^0.1.3",
|
||||
"@backstage/plugin-todo-backend": "^0.1.16",
|
||||
"@backstage/plugin-tech-insights-backend-module-jsonfc": "^0.1.4",
|
||||
"@backstage/plugin-todo-backend": "^0.1.17",
|
||||
"@gitbeaker/node": "^34.6.0",
|
||||
"@octokit/rest": "^18.5.3",
|
||||
"azure-devops-node-api": "^11.0.1",
|
||||
@@ -72,7 +72,7 @@
|
||||
"winston": "^3.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.10.3",
|
||||
"@backstage/cli": "^0.10.4",
|
||||
"@types/dockerode": "^3.3.0",
|
||||
"@types/express": "^4.17.6",
|
||||
"@types/express-serve-static-core": "^4.17.5"
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
# @backstage/cli
|
||||
|
||||
## 0.10.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 1d26017090: Fix issue with plugin:serve for Plugins not using Lerna monorepo.
|
||||
- 9c3aaf3512: Bump `@typescript-eslint/eslint-plugin` to `4.33.0`
|
||||
- 808828e4fa: remove inline CSS from serve_index.html
|
||||
- 6e4080d31b: Add option to build command for minifying the generated code
|
||||
- Updated dependencies
|
||||
- @backstage/config-loader@0.9.1
|
||||
|
||||
## 0.10.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/cli",
|
||||
"description": "CLI for developing Backstage plugins and apps",
|
||||
"version": "0.10.3",
|
||||
"version": "0.10.4",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
@@ -30,7 +30,7 @@
|
||||
"dependencies": {
|
||||
"@backstage/cli-common": "^0.1.6",
|
||||
"@backstage/config": "^0.1.11",
|
||||
"@backstage/config-loader": "^0.9.0",
|
||||
"@backstage/config-loader": "^0.9.1",
|
||||
"@backstage/errors": "^0.1.5",
|
||||
"@backstage/types": "^0.1.1",
|
||||
"@hot-loader/react-dom": "^16.13.0",
|
||||
@@ -51,7 +51,7 @@
|
||||
"@svgr/rollup": "5.5.x",
|
||||
"@svgr/webpack": "5.5.x",
|
||||
"@types/webpack-env": "^1.15.2",
|
||||
"@typescript-eslint/eslint-plugin": "^v4.30.0",
|
||||
"@typescript-eslint/eslint-plugin": "^v4.33.0",
|
||||
"@typescript-eslint/parser": "^v4.28.3",
|
||||
"@yarnpkg/lockfile": "^1.1.0",
|
||||
"bfj": "^7.0.2",
|
||||
@@ -114,13 +114,13 @@
|
||||
"yn": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/backend-common": "^0.10.0",
|
||||
"@backstage/backend-common": "^0.10.1",
|
||||
"@backstage/config": "^0.1.11",
|
||||
"@backstage/core-components": "^0.8.2",
|
||||
"@backstage/core-plugin-api": "^0.4.0",
|
||||
"@backstage/core-app-api": "^0.3.0",
|
||||
"@backstage/dev-utils": "^0.2.15",
|
||||
"@backstage/test-utils": "^0.2.0",
|
||||
"@backstage/test-utils": "^0.2.1",
|
||||
"@backstage/theme": "^0.2.14",
|
||||
"@types/diff": "^5.0.0",
|
||||
"@types/express": "^4.17.6",
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @backstage/config-loader
|
||||
|
||||
## 0.9.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 84663d59a3: Bump `typescript-json-schema` from `^0.51.0` to `^0.52.0`.
|
||||
|
||||
## 0.9.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/config-loader",
|
||||
"description": "Config loading functionality used by Backstage backend, and CLI",
|
||||
"version": "0.9.0",
|
||||
"version": "0.9.1",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
|
||||
@@ -1,5 +1,125 @@
|
||||
# @backstage/create-app
|
||||
|
||||
## 0.4.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 79b342bd36: removed inline and internal CSS from index.html
|
||||
|
||||
To make this change to an existing app, apply the following changes to the `packages/app/public/index.html` file:
|
||||
|
||||
Remove internal style
|
||||
|
||||
```diff
|
||||
- <style>
|
||||
- #root {
|
||||
- min-height: 100%;
|
||||
- }
|
||||
- </style>
|
||||
```
|
||||
|
||||
Remove inline style from the body tag
|
||||
|
||||
```diff
|
||||
- <body style="margin: 0">
|
||||
+ <body>
|
||||
```
|
||||
|
||||
- d33b65dc52: Removed unused templating asset.
|
||||
- 613ad12960: Add a comment to the default backend about the fallback 404 handler.
|
||||
- 20af5a701f: The `<SearchType />` filter in the composed `SearchPage.tsx` was replaced with the `<SearchType.Accordion />` variant.
|
||||
|
||||
This is an entirely optional change; if you wish to display a control surface for search `types` as a single-select accordion (as opposed to the current multi-select of checkboxes), you can make the following (or similar) changes to your search page layout:
|
||||
|
||||
```diff
|
||||
--- a/packages/app/src/components/search/SearchPage.tsx
|
||||
+++ b/packages/app/src/components/search/SearchPage.tsx
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
SearchType,
|
||||
DefaultResultListItem,
|
||||
} from '@backstage/plugin-search';
|
||||
-import { Content, Header, Page } from '@backstage/core-components';
|
||||
+import { CatalogIcon, Content, DocsIcon, Header, Page } from '@backstage/core-components';
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) => ({
|
||||
bar: {
|
||||
@@ -19,6 +19,7 @@ const useStyles = makeStyles((theme: Theme) => ({
|
||||
},
|
||||
filters: {
|
||||
padding: theme.spacing(2),
|
||||
+ marginTop: theme.spacing(2),
|
||||
},
|
||||
filter: {
|
||||
'& + &': {
|
||||
@@ -41,12 +42,23 @@ const SearchPage = () => {
|
||||
</Paper>
|
||||
</Grid>
|
||||
<Grid item xs={3}>
|
||||
+ <SearchType.Accordion
|
||||
+ name="Result Type"
|
||||
+ defaultValue="software-catalog"
|
||||
+ types={[
|
||||
+ {
|
||||
+ value: 'software-catalog',
|
||||
+ name: 'Software Catalog',
|
||||
+ icon: <CatalogIcon />,
|
||||
+ },
|
||||
+ {
|
||||
+ value: 'techdocs',
|
||||
+ name: 'Documentation',
|
||||
+ icon: <DocsIcon />,
|
||||
+ },
|
||||
+ ]}
|
||||
+ />
|
||||
<Paper className={classes.filters}>
|
||||
- <SearchType
|
||||
- values={['techdocs', 'software-catalog']}
|
||||
- name="type"
|
||||
- defaultValue="software-catalog"
|
||||
- />
|
||||
<SearchFilter.Select
|
||||
className={classes.filter}
|
||||
name="kind"
|
||||
```
|
||||
|
||||
- 0dcd1dd64f: Add a `scheduler` to the plugin environment, which can schedule collaborative tasks across backends. To apply the same change in your backend, follow the steps below.
|
||||
|
||||
First install the package:
|
||||
|
||||
```shell
|
||||
# From the Backstage repository root
|
||||
cd packages/backend
|
||||
yarn add @backstage/backend-tasks
|
||||
```
|
||||
|
||||
Add the scheduler to your plugin environment type:
|
||||
|
||||
```diff
|
||||
// In packages/backend/src/types.ts
|
||||
+import { PluginTaskScheduler } from '@backstage/backend-tasks';
|
||||
|
||||
export type PluginEnvironment = {
|
||||
+ scheduler: PluginTaskScheduler;
|
||||
```
|
||||
|
||||
And finally make sure to add such an instance to each plugin's environment:
|
||||
|
||||
```diff
|
||||
// In packages/backend/src/index.ts
|
||||
+import { TaskScheduler } from '@backstage/backend-tasks';
|
||||
|
||||
function makeCreateEnv(config: Config) {
|
||||
// ...
|
||||
+ const taskScheduler = TaskScheduler.fromConfig(config);
|
||||
|
||||
return (plugin: string): PluginEnvironment => {
|
||||
// ...
|
||||
+ const scheduler = taskScheduler.forPlugin(plugin);
|
||||
return {
|
||||
+ scheduler,
|
||||
// ...
|
||||
```
|
||||
|
||||
## 0.4.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/create-app",
|
||||
"description": "A CLI that helps you create your own Backstage app",
|
||||
"version": "0.4.9",
|
||||
"version": "0.4.10",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @backstage/integration-react
|
||||
|
||||
## 0.1.17
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/integration@0.7.0
|
||||
|
||||
## 0.1.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/integration-react",
|
||||
"description": "Frontend package for managing integrations towards external systems",
|
||||
"version": "0.1.16",
|
||||
"version": "0.1.17",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -24,7 +24,7 @@
|
||||
"@backstage/config": "^0.1.11",
|
||||
"@backstage/core-components": "^0.8.2",
|
||||
"@backstage/core-plugin-api": "^0.4.0",
|
||||
"@backstage/integration": "^0.6.10",
|
||||
"@backstage/integration": "^0.7.0",
|
||||
"@backstage/theme": "^0.2.14",
|
||||
"@material-ui/core": "^4.12.2",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
@@ -35,9 +35,9 @@
|
||||
"react": "^16.13.1 || ^17.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.10.3",
|
||||
"@backstage/cli": "^0.10.4",
|
||||
"@backstage/dev-utils": "^0.2.15",
|
||||
"@backstage/test-utils": "^0.2.0",
|
||||
"@backstage/test-utils": "^0.2.1",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^11.2.5",
|
||||
"@testing-library/user-event": "^13.1.8",
|
||||
|
||||
@@ -1,5 +1,23 @@
|
||||
# @backstage/integration
|
||||
|
||||
## 0.7.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 7d4b4e937c: Create an interface for the GitHub credentials provider in order to support providing implementations.
|
||||
|
||||
We have changed the name of the `GithubCredentialsProvider` to `SingleInstanceGithubCredentialsProvider`.
|
||||
|
||||
`GithubCredentialsProvider` is now an interface that maybe implemented to provide a custom mechanism to retrieve GitHub credentials.
|
||||
|
||||
In a later release we will support configuring URL readers, scaffolder tasks, and processors with customer GitHub credentials providers.
|
||||
|
||||
If you want to uptake this release, you will need to replace all references to `GithubCredentialsProvider.create` with `SingleInstanceGithubCredentialsProvider.create`.
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- cf2e20a792: Added `endpoint` and `s3ForcePathStyle` as optional configuration for AWS S3 integrations.
|
||||
|
||||
## 0.6.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -30,6 +30,8 @@ export class AwsS3Integration implements ScmIntegration {
|
||||
// @public
|
||||
export type AwsS3IntegrationConfig = {
|
||||
host: string;
|
||||
endpoint?: string;
|
||||
s3ForcePathStyle?: boolean;
|
||||
accessKeyId?: string;
|
||||
secretAccessKey?: string;
|
||||
roleArn?: string;
|
||||
|
||||
Vendored
+15
-2
@@ -167,10 +167,23 @@ export interface Config {
|
||||
/** Integration configuration for AWS S3 Service */
|
||||
awsS3?: Array<{
|
||||
/**
|
||||
* The host of the target that this matches on, e.g. "amazonaws.com".
|
||||
* AWS Endpoint.
|
||||
* The endpoint URI to send requests to. The default endpoint is built from the configured region.
|
||||
* @see https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#constructor-property
|
||||
*
|
||||
* Supports non-AWS providers, e.g. for LocalStack, endpoint may look like http://localhost:4566
|
||||
* @visibility frontend
|
||||
*/
|
||||
host: string;
|
||||
endpoint?: string;
|
||||
|
||||
/**
|
||||
* Whether to use path style URLs when communicating with S3.
|
||||
* Defaults to false.
|
||||
* This allows providers like LocalStack, Minio and Wasabi (and possibly others) to be used.
|
||||
* @visibility frontend
|
||||
*/
|
||||
s3ForcePathStyle?: boolean;
|
||||
|
||||
/**
|
||||
* Account access key used to authenticate requests.
|
||||
* @visibility backend
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/integration",
|
||||
"description": "Helpers for managing integrations towards external systems",
|
||||
"version": "0.6.10",
|
||||
"version": "0.7.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -39,9 +39,9 @@
|
||||
"lodash": "^4.17.21"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.10.3",
|
||||
"@backstage/config-loader": "^0.9.0",
|
||||
"@backstage/test-utils": "^0.2.0",
|
||||
"@backstage/cli": "^0.10.4",
|
||||
"@backstage/config-loader": "^0.9.1",
|
||||
"@backstage/test-utils": "^0.2.1",
|
||||
"@types/jest": "^26.0.7",
|
||||
"@types/luxon": "^2.0.4",
|
||||
"msw": "^0.35.0"
|
||||
|
||||
@@ -24,7 +24,7 @@ describe('AwsS3Integration', () => {
|
||||
integrations: {
|
||||
awsS3: [
|
||||
{
|
||||
host: 'a.com',
|
||||
endpoint: 'https://a.com',
|
||||
accessKeyId: 'access key',
|
||||
secretAccessKey: 'secret key',
|
||||
},
|
||||
|
||||
@@ -26,16 +26,33 @@ describe('readAwsS3IntegrationConfig', () => {
|
||||
return new ConfigReader(data);
|
||||
}
|
||||
|
||||
it('reads all values', () => {
|
||||
it('reads all values (default)', () => {
|
||||
const output = readAwsS3IntegrationConfig(
|
||||
buildConfig({
|
||||
host: 'amazonaws.com',
|
||||
accessKeyId: 'fake-key',
|
||||
secretAccessKey: 'fake-secret-key',
|
||||
}),
|
||||
);
|
||||
expect(output).toEqual({
|
||||
host: 'amazonaws.com',
|
||||
s3ForcePathStyle: false,
|
||||
accessKeyId: 'fake-key',
|
||||
secretAccessKey: 'fake-secret-key',
|
||||
});
|
||||
});
|
||||
it('reads all values (endpoint)', () => {
|
||||
const output = readAwsS3IntegrationConfig(
|
||||
buildConfig({
|
||||
endpoint: 'http://localhost:4566',
|
||||
s3ForcePathStyle: true,
|
||||
accessKeyId: 'fake-key',
|
||||
secretAccessKey: 'fake-secret-key',
|
||||
}),
|
||||
);
|
||||
expect(output).toEqual({
|
||||
host: 'localhost:4566',
|
||||
endpoint: 'http://localhost:4566',
|
||||
s3ForcePathStyle: true,
|
||||
accessKeyId: 'fake-key',
|
||||
secretAccessKey: 'fake-secret-key',
|
||||
});
|
||||
@@ -59,6 +76,7 @@ describe('readAwsS3IntegrationConfigs', () => {
|
||||
);
|
||||
expect(output).toContainEqual({
|
||||
host: 'amazonaws.com',
|
||||
s3ForcePathStyle: false,
|
||||
accessKeyId: 'key',
|
||||
secretAccessKey: 'secret',
|
||||
});
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
|
||||
import { Config } from '@backstage/config';
|
||||
import { isValidHost } from '../helpers';
|
||||
|
||||
const AMAZON_AWS_HOST = 'amazonaws.com';
|
||||
|
||||
@@ -26,24 +25,38 @@ const AMAZON_AWS_HOST = 'amazonaws.com';
|
||||
*/
|
||||
export type AwsS3IntegrationConfig = {
|
||||
/**
|
||||
* The host of the target that this matches on, e.g. "amazonaws.com"
|
||||
*
|
||||
* Currently only "amazonaws.com" is supported.
|
||||
* Host, derived from endpoint, and defaults to amazonaws.com
|
||||
*/
|
||||
host: string;
|
||||
|
||||
/**
|
||||
* accessKeyId
|
||||
* (Optional) AWS Endpoint.
|
||||
* The endpoint URI to send requests to. The default endpoint is built from the configured region.
|
||||
* @see https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#constructor-property
|
||||
*
|
||||
* Supports non-AWS providers, e.g. for LocalStack, endpoint may look like http://localhost:4566
|
||||
*/
|
||||
endpoint?: string;
|
||||
|
||||
/**
|
||||
* (Optional) Whether to use path style URLs when communicating with S3.
|
||||
* Defaults to false.
|
||||
* This allows providers like LocalStack, Minio and Wasabi (and possibly others) to be used.
|
||||
*/
|
||||
s3ForcePathStyle?: boolean;
|
||||
|
||||
/**
|
||||
* (Optional) User access key id
|
||||
*/
|
||||
accessKeyId?: string;
|
||||
|
||||
/**
|
||||
* secretAccessKey
|
||||
* (Optional) User secret access key
|
||||
*/
|
||||
secretAccessKey?: string;
|
||||
|
||||
/**
|
||||
* roleArn
|
||||
* (Optional) ARN of role to be assumed
|
||||
*/
|
||||
roleArn?: string;
|
||||
};
|
||||
@@ -58,18 +71,42 @@ export type AwsS3IntegrationConfig = {
|
||||
export function readAwsS3IntegrationConfig(
|
||||
config: Config,
|
||||
): AwsS3IntegrationConfig {
|
||||
const host = config.getOptionalString('host') ?? AMAZON_AWS_HOST;
|
||||
const endpoint = config.getOptionalString('endpoint');
|
||||
const s3ForcePathStyle =
|
||||
config.getOptionalBoolean('s3ForcePathStyle') ?? false;
|
||||
let host;
|
||||
let pathname;
|
||||
if (endpoint) {
|
||||
try {
|
||||
const url = new URL(endpoint);
|
||||
host = url.host;
|
||||
pathname = url.pathname;
|
||||
} catch {
|
||||
throw new Error(
|
||||
`invalid awsS3 integration config, endpoint '${endpoint}' is not a valid URL`,
|
||||
);
|
||||
}
|
||||
if (pathname !== '/') {
|
||||
throw new Error(
|
||||
`invalid awsS3 integration config, endpoints cannot contain path, got '${endpoint}'`,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
host = AMAZON_AWS_HOST;
|
||||
}
|
||||
|
||||
const accessKeyId = config.getOptionalString('accessKeyId');
|
||||
const secretAccessKey = config.getOptionalString('secretAccessKey');
|
||||
const roleArn = config.getOptionalString('roleArn');
|
||||
|
||||
if (!isValidHost(host)) {
|
||||
throw new Error(
|
||||
`Invalid awsS3 integration config, '${host}' is not a valid host`,
|
||||
);
|
||||
}
|
||||
|
||||
return { host, accessKeyId, secretAccessKey, roleArn };
|
||||
return {
|
||||
host,
|
||||
endpoint,
|
||||
s3ForcePathStyle,
|
||||
accessKeyId,
|
||||
secretAccessKey,
|
||||
roleArn,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
# @techdocs/cli
|
||||
|
||||
## 0.8.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 8fbc988bfc: remove internal and inline CSS from index.html
|
||||
- Updated dependencies
|
||||
- @backstage/techdocs-common@0.11.2
|
||||
- @backstage/backend-common@0.10.1
|
||||
|
||||
## 0.8.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@techdocs/cli",
|
||||
"description": "Utility CLI for managing TechDocs sites in Backstage.",
|
||||
"version": "0.8.9",
|
||||
"version": "0.8.10",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
@@ -32,7 +32,7 @@
|
||||
"techdocs-cli": "bin/techdocs-cli"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.10.3",
|
||||
"@backstage/cli": "^0.10.4",
|
||||
"@types/commander": "^2.12.2",
|
||||
"@types/fs-extra": "^9.0.6",
|
||||
"@types/http-proxy": "^1.17.4",
|
||||
@@ -56,10 +56,10 @@
|
||||
"ext": "ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/backend-common": "^0.10.0",
|
||||
"@backstage/backend-common": "^0.10.1",
|
||||
"@backstage/catalog-model": "^0.9.7",
|
||||
"@backstage/config": "^0.1.10",
|
||||
"@backstage/techdocs-common": "^0.11.1",
|
||||
"@backstage/techdocs-common": "^0.11.2",
|
||||
"@types/dockerode": "^3.3.0",
|
||||
"commander": "^6.1.0",
|
||||
"dockerode": "^3.3.1",
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
# @backstage/techdocs-common
|
||||
|
||||
## 0.11.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- c2c8768771: Bump `@azure/identity` from `^1.5.0` to `^2.0.1`.
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.10.1
|
||||
- @backstage/integration@0.7.0
|
||||
|
||||
## 0.11.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/techdocs-common",
|
||||
"description": "Common functionalities for TechDocs, to be shared between techdocs-backend plugin and techdocs-cli",
|
||||
"version": "0.11.1",
|
||||
"version": "0.11.2",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"private": false,
|
||||
@@ -38,12 +38,12 @@
|
||||
"dependencies": {
|
||||
"@azure/identity": "^2.0.1",
|
||||
"@azure/storage-blob": "^12.5.0",
|
||||
"@backstage/backend-common": "^0.10.0",
|
||||
"@backstage/backend-common": "^0.10.1",
|
||||
"@backstage/catalog-model": "^0.9.7",
|
||||
"@backstage/config": "^0.1.11",
|
||||
"@backstage/errors": "^0.1.5",
|
||||
"@backstage/search-common": "^0.2.1",
|
||||
"@backstage/integration": "^0.6.10",
|
||||
"@backstage/integration": "^0.7.0",
|
||||
"@google-cloud/storage": "^5.6.0",
|
||||
"@trendyol-js/openstack-swift-sdk": "^0.0.5",
|
||||
"@types/express": "^4.17.6",
|
||||
@@ -60,7 +60,7 @@
|
||||
"winston": "^3.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.10.3",
|
||||
"@backstage/cli": "^0.10.4",
|
||||
"@types/fs-extra": "^9.0.5",
|
||||
"@types/js-yaml": "^4.0.0",
|
||||
"@types/mime-types": "^2.1.0",
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @backstage/test-utils
|
||||
|
||||
## 0.2.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- c36b7794f7: JSON serialize and freeze values stored by the `MockStorageApi`.
|
||||
|
||||
## 0.2.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/test-utils",
|
||||
"description": "Utilities to test Backstage plugins and apps.",
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.1",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
@@ -47,7 +47,7 @@
|
||||
"react": "^16.13.1 || ^17.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.10.3",
|
||||
"@backstage/cli": "^0.10.4",
|
||||
"@types/jest": "^26.0.7",
|
||||
"@types/node": "^14.14.32"
|
||||
},
|
||||
|
||||
@@ -37,10 +37,10 @@
|
||||
"react": "^16.13.1 || ^17.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.10.3",
|
||||
"@backstage/cli": "^0.10.4",
|
||||
"@backstage/core-app-api": "^0.3.0",
|
||||
"@backstage/dev-utils": "^0.2.15",
|
||||
"@backstage/test-utils": "^0.2.0",
|
||||
"@backstage/test-utils": "^0.2.1",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^11.2.5",
|
||||
"@testing-library/user-event": "^13.1.8",
|
||||
|
||||
@@ -35,10 +35,10 @@
|
||||
"react": "^16.13.1 || ^17.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.10.3",
|
||||
"@backstage/cli": "^0.10.4",
|
||||
"@backstage/core-app-api": "^0.3.0",
|
||||
"@backstage/dev-utils": "^0.2.15",
|
||||
"@backstage/test-utils": "^0.2.0",
|
||||
"@backstage/test-utils": "^0.2.1",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^11.2.5",
|
||||
"@testing-library/user-event": "^13.1.8",
|
||||
|
||||
@@ -33,10 +33,10 @@
|
||||
"react": "^16.13.1 || ^17.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.10.3",
|
||||
"@backstage/cli": "^0.10.4",
|
||||
"@backstage/core-app-api": "^0.3.0",
|
||||
"@backstage/dev-utils": "^0.2.15",
|
||||
"@backstage/test-utils": "^0.2.0",
|
||||
"@backstage/test-utils": "^0.2.1",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^11.2.5",
|
||||
"@testing-library/user-event": "^13.1.8",
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
# @backstage/plugin-api-docs
|
||||
|
||||
## 0.6.20
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- de81b7455e: Display entity title on `ApiDefinitionCard` if defined
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-catalog@0.7.6
|
||||
- @backstage/plugin-catalog-react@0.6.9
|
||||
|
||||
## 0.6.19
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
```ts
|
||||
/// <reference types="react" />
|
||||
|
||||
import { Action } from '@material-table/core';
|
||||
import { ApiEntity } from '@backstage/catalog-model';
|
||||
import { ApiRef } from '@backstage/core-plugin-api';
|
||||
import { BackstagePlugin } from '@backstage/core-plugin-api';
|
||||
@@ -15,6 +14,7 @@ import { ExternalRouteRef } from '@backstage/core-plugin-api';
|
||||
import { default as React_2 } from 'react';
|
||||
import { RouteRef } from '@backstage/core-plugin-api';
|
||||
import { TableColumn } from '@backstage/core-components';
|
||||
import { TableProps } from '@backstage/core-components';
|
||||
import { UserListFilterKind } from '@backstage/plugin-catalog-react';
|
||||
|
||||
// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts
|
||||
@@ -53,27 +53,17 @@ const apiDocsPlugin: BackstagePlugin<
|
||||
export { apiDocsPlugin };
|
||||
export { apiDocsPlugin as plugin };
|
||||
|
||||
// @public
|
||||
export const ApiExplorerIndexPage: (
|
||||
props: DefaultApiExplorerPageProps,
|
||||
) => JSX.Element;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "ApiExplorerPage" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export const ApiExplorerPage: ({
|
||||
initiallySelectedFilter,
|
||||
columns,
|
||||
actions,
|
||||
}: {
|
||||
initiallySelectedFilter?: UserListFilterKind | undefined;
|
||||
columns?: TableColumn<CatalogTableRow>[] | undefined;
|
||||
actions?:
|
||||
| (
|
||||
| Action<CatalogTableRow>
|
||||
| {
|
||||
action: (rowData: CatalogTableRow) => Action<CatalogTableRow>;
|
||||
position: string;
|
||||
}
|
||||
| ((rowData: CatalogTableRow) => Action<CatalogTableRow>)
|
||||
)[]
|
||||
| undefined;
|
||||
}) => JSX.Element;
|
||||
export const ApiExplorerPage: (
|
||||
props: DefaultApiExplorerPageProps,
|
||||
) => JSX.Element;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "ApiTypeTitle" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
@@ -110,6 +100,20 @@ export const ConsumedApisCard: ({ variant }: Props_2) => JSX.Element;
|
||||
// @public (undocumented)
|
||||
export const ConsumingComponentsCard: ({ variant }: Props_5) => JSX.Element;
|
||||
|
||||
// @public
|
||||
export const DefaultApiExplorerPage: ({
|
||||
initiallySelectedFilter,
|
||||
columns,
|
||||
actions,
|
||||
}: DefaultApiExplorerPageProps) => JSX.Element;
|
||||
|
||||
// @public
|
||||
export type DefaultApiExplorerPageProps = {
|
||||
initiallySelectedFilter?: UserListFilterKind;
|
||||
columns?: TableColumn<CatalogTableRow>[];
|
||||
actions?: TableProps<CatalogTableRow>['actions'];
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "defaultDefinitionWidgets" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/plugin-api-docs",
|
||||
"description": "A Backstage plugin that helps represent API entities in the frontend",
|
||||
"version": "0.6.19",
|
||||
"version": "0.6.20",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -34,8 +34,8 @@
|
||||
"@backstage/catalog-model": "^0.9.7",
|
||||
"@backstage/core-components": "^0.8.2",
|
||||
"@backstage/core-plugin-api": "^0.4.0",
|
||||
"@backstage/plugin-catalog": "^0.7.5",
|
||||
"@backstage/plugin-catalog-react": "^0.6.8",
|
||||
"@backstage/plugin-catalog": "^0.7.6",
|
||||
"@backstage/plugin-catalog-react": "^0.6.9",
|
||||
"@backstage/theme": "^0.2.14",
|
||||
"@material-ui/core": "^4.12.2",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
@@ -54,10 +54,10 @@
|
||||
"react": "^16.13.1 || ^17.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.10.3",
|
||||
"@backstage/cli": "^0.10.4",
|
||||
"@backstage/core-app-api": "^0.3.0",
|
||||
"@backstage/dev-utils": "^0.2.15",
|
||||
"@backstage/test-utils": "^0.2.0",
|
||||
"@backstage/test-utils": "^0.2.1",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^11.2.5",
|
||||
"@testing-library/user-event": "^13.1.8",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020 The Backstage Authors
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,185 +14,31 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Entity, RELATION_MEMBER_OF } from '@backstage/catalog-model';
|
||||
import { ConfigReader } from '@backstage/core-app-api';
|
||||
import { TableColumn, TableProps } from '@backstage/core-components';
|
||||
import {
|
||||
ConfigApi,
|
||||
configApiRef,
|
||||
storageApiRef,
|
||||
} from '@backstage/core-plugin-api';
|
||||
import { CatalogTableRow } from '@backstage/plugin-catalog';
|
||||
import {
|
||||
CatalogApi,
|
||||
catalogApiRef,
|
||||
DefaultStarredEntitiesApi,
|
||||
entityRouteRef,
|
||||
starredEntitiesApiRef,
|
||||
} from '@backstage/plugin-catalog-react';
|
||||
import {
|
||||
MockStorageApi,
|
||||
TestApiProvider,
|
||||
wrapInTestApp,
|
||||
} from '@backstage/test-utils';
|
||||
import DashboardIcon from '@material-ui/icons/Dashboard';
|
||||
import { render } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { apiDocsConfigRef } from '../../config';
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
import { useOutlet } from 'react-router';
|
||||
import { ApiExplorerPage } from './ApiExplorerPage';
|
||||
|
||||
describe('ApiCatalogPage', () => {
|
||||
const catalogApi: Partial<CatalogApi> = {
|
||||
getEntities: () =>
|
||||
Promise.resolve({
|
||||
items: [
|
||||
{
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'API',
|
||||
metadata: {
|
||||
name: 'Entity1',
|
||||
},
|
||||
spec: { type: 'openapi' },
|
||||
},
|
||||
] as Entity[],
|
||||
}),
|
||||
getLocationByEntity: () =>
|
||||
Promise.resolve({ id: 'id', type: 'github', target: 'url' }),
|
||||
getEntityByName: async entityName => {
|
||||
return {
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'User',
|
||||
metadata: { name: entityName.name },
|
||||
relations: [
|
||||
{
|
||||
type: RELATION_MEMBER_OF,
|
||||
target: { namespace: 'default', kind: 'Group', name: 'tools' },
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
};
|
||||
jest.mock('react-router', () => ({
|
||||
...jest.requireActual('react-router'),
|
||||
useOutlet: jest.fn().mockReturnValue('Route Children'),
|
||||
}));
|
||||
|
||||
const configApi: ConfigApi = new ConfigReader({
|
||||
organization: {
|
||||
name: 'My Company',
|
||||
},
|
||||
jest.mock('./DefaultApiExplorerPage', () => ({
|
||||
DefaultApiExplorerPage: jest.fn().mockReturnValue('DefaultApiExplorerPage'),
|
||||
}));
|
||||
|
||||
describe('ApiExplorerPage', () => {
|
||||
it('renders provided router element', async () => {
|
||||
const { getByText } = await renderInTestApp(<ApiExplorerPage />);
|
||||
|
||||
expect(getByText('Route Children')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
const apiDocsConfig = {
|
||||
getApiDefinitionWidget: () => undefined,
|
||||
};
|
||||
it('renders DefaultApiExplorerPage home when no router children are provided', async () => {
|
||||
(useOutlet as jest.Mock).mockReturnValueOnce(null);
|
||||
const { getByText } = await renderInTestApp(<ApiExplorerPage />);
|
||||
|
||||
const storageApi = MockStorageApi.create();
|
||||
|
||||
const renderWrapped = (children: React.ReactNode) =>
|
||||
render(
|
||||
wrapInTestApp(
|
||||
<TestApiProvider
|
||||
apis={[
|
||||
[catalogApiRef, catalogApi],
|
||||
[configApiRef, configApi],
|
||||
[storageApiRef, storageApi],
|
||||
[
|
||||
starredEntitiesApiRef,
|
||||
new DefaultStarredEntitiesApi({ storageApi }),
|
||||
],
|
||||
[apiDocsConfigRef, apiDocsConfig],
|
||||
]}
|
||||
>
|
||||
{children}
|
||||
</TestApiProvider>,
|
||||
{
|
||||
mountedRoutes: {
|
||||
'/catalog/:namespace/:kind/:name': entityRouteRef,
|
||||
},
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
// this test right now causes some red lines in the log output when running tests
|
||||
// related to some theme issues in mui-table
|
||||
// https://github.com/mbrn/material-table/issues/1293
|
||||
it('should render', async () => {
|
||||
const { findByText } = renderWrapped(<ApiExplorerPage />);
|
||||
expect(await findByText(/My Company API Explorer/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render the default column of the grid', async () => {
|
||||
const { getAllByRole } = renderWrapped(<ApiExplorerPage />);
|
||||
|
||||
const columnHeader = getAllByRole('button').filter(
|
||||
c => c.tagName === 'SPAN',
|
||||
);
|
||||
const columnHeaderLabels = columnHeader.map(c => c.textContent);
|
||||
|
||||
expect(columnHeaderLabels).toEqual([
|
||||
'Name',
|
||||
'System',
|
||||
'Owner',
|
||||
'Type',
|
||||
'Lifecycle',
|
||||
'Description',
|
||||
'Tags',
|
||||
'Actions',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should render the custom column passed as prop', async () => {
|
||||
const columns: TableColumn<CatalogTableRow>[] = [
|
||||
{ title: 'Foo', field: 'entity.foo' },
|
||||
{ title: 'Bar', field: 'entity.bar' },
|
||||
{ title: 'Baz', field: 'entity.spec.lifecycle' },
|
||||
];
|
||||
const { getAllByRole } = renderWrapped(
|
||||
<ApiExplorerPage columns={columns} />,
|
||||
);
|
||||
|
||||
const columnHeader = getAllByRole('button').filter(
|
||||
c => c.tagName === 'SPAN',
|
||||
);
|
||||
const columnHeaderLabels = columnHeader.map(c => c.textContent);
|
||||
|
||||
expect(columnHeaderLabels).toEqual(['Foo', 'Bar', 'Baz', 'Actions']);
|
||||
});
|
||||
|
||||
it('should render the default actions of an item in the grid', async () => {
|
||||
const { findByTitle, findByText } = await renderWrapped(
|
||||
<ApiExplorerPage />,
|
||||
);
|
||||
expect(await findByText(/All \(1\)/)).toBeInTheDocument();
|
||||
expect(await findByTitle(/View/)).toBeInTheDocument();
|
||||
expect(await findByTitle(/View/)).toBeInTheDocument();
|
||||
expect(await findByTitle(/Edit/)).toBeInTheDocument();
|
||||
expect(await findByTitle(/Add to favorites/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render the custom actions of an item passed as prop', async () => {
|
||||
const actions: TableProps<CatalogTableRow>['actions'] = [
|
||||
() => {
|
||||
return {
|
||||
icon: () => <DashboardIcon fontSize="small" />,
|
||||
tooltip: 'Foo Action',
|
||||
disabled: false,
|
||||
onClick: () => jest.fn(),
|
||||
};
|
||||
},
|
||||
() => {
|
||||
return {
|
||||
icon: () => <DashboardIcon fontSize="small" />,
|
||||
tooltip: 'Bar Action',
|
||||
disabled: true,
|
||||
onClick: () => jest.fn(),
|
||||
};
|
||||
},
|
||||
];
|
||||
|
||||
const { findByTitle, findByText } = await renderWrapped(
|
||||
<ApiExplorerPage actions={actions} />,
|
||||
);
|
||||
expect(await findByText(/All \(1\)/)).toBeInTheDocument();
|
||||
expect(await findByTitle(/Foo Action/)).toBeInTheDocument();
|
||||
expect(await findByTitle(/Bar Action/)).toBeInTheDocument();
|
||||
expect((await findByTitle(/Bar Action/)).firstChild).toBeDisabled();
|
||||
expect(getByText('DefaultApiExplorerPage')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020 The Backstage Authors
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,97 +14,19 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
Content,
|
||||
ContentHeader,
|
||||
CreateButton,
|
||||
PageWithHeader,
|
||||
SupportButton,
|
||||
TableColumn,
|
||||
TableProps,
|
||||
} from '@backstage/core-components';
|
||||
import { configApiRef, useApi, useRouteRef } from '@backstage/core-plugin-api';
|
||||
import {
|
||||
CatalogTable,
|
||||
CatalogTableRow,
|
||||
FilteredEntityLayout,
|
||||
EntityListContainer,
|
||||
FilterContainer,
|
||||
} from '@backstage/plugin-catalog';
|
||||
import {
|
||||
EntityKindPicker,
|
||||
EntityLifecyclePicker,
|
||||
EntityListProvider,
|
||||
EntityOwnerPicker,
|
||||
EntityTagPicker,
|
||||
EntityTypePicker,
|
||||
UserListFilterKind,
|
||||
UserListPicker,
|
||||
} from '@backstage/plugin-catalog-react';
|
||||
import React from 'react';
|
||||
import { createComponentRouteRef } from '../../routes';
|
||||
import { useOutlet } from 'react-router';
|
||||
import {
|
||||
DefaultApiExplorerPage,
|
||||
DefaultApiExplorerPageProps,
|
||||
} from './DefaultApiExplorerPage';
|
||||
|
||||
const defaultColumns: TableColumn<CatalogTableRow>[] = [
|
||||
CatalogTable.columns.createNameColumn({ defaultKind: 'API' }),
|
||||
CatalogTable.columns.createSystemColumn(),
|
||||
CatalogTable.columns.createOwnerColumn(),
|
||||
CatalogTable.columns.createSpecTypeColumn(),
|
||||
CatalogTable.columns.createSpecLifecycleColumn(),
|
||||
CatalogTable.columns.createMetadataDescriptionColumn(),
|
||||
CatalogTable.columns.createTagsColumn(),
|
||||
];
|
||||
/**
|
||||
* ApiExplorerPage
|
||||
* @public
|
||||
*/
|
||||
export const ApiExplorerPage = (props: DefaultApiExplorerPageProps) => {
|
||||
const outlet = useOutlet();
|
||||
|
||||
type ApiExplorerPageProps = {
|
||||
initiallySelectedFilter?: UserListFilterKind;
|
||||
columns?: TableColumn<CatalogTableRow>[];
|
||||
actions?: TableProps<CatalogTableRow>['actions'];
|
||||
};
|
||||
|
||||
export const ApiExplorerPage = ({
|
||||
initiallySelectedFilter = 'all',
|
||||
columns,
|
||||
actions,
|
||||
}: ApiExplorerPageProps) => {
|
||||
const configApi = useApi(configApiRef);
|
||||
const generatedSubtitle = `${
|
||||
configApi.getOptionalString('organization.name') ?? 'Backstage'
|
||||
} API Explorer`;
|
||||
const createComponentLink = useRouteRef(createComponentRouteRef);
|
||||
|
||||
return (
|
||||
<PageWithHeader
|
||||
themeId="apis"
|
||||
title="APIs"
|
||||
subtitle={generatedSubtitle}
|
||||
pageTitleOverride="APIs"
|
||||
>
|
||||
<Content>
|
||||
<ContentHeader title="">
|
||||
<CreateButton
|
||||
title="Register Existing API"
|
||||
to={createComponentLink?.()}
|
||||
/>
|
||||
<SupportButton>All your APIs</SupportButton>
|
||||
</ContentHeader>
|
||||
<EntityListProvider>
|
||||
<FilteredEntityLayout>
|
||||
<FilterContainer>
|
||||
<EntityKindPicker initialFilter="api" hidden />
|
||||
<EntityTypePicker />
|
||||
<UserListPicker initialFilter={initiallySelectedFilter} />
|
||||
<EntityOwnerPicker />
|
||||
<EntityLifecyclePicker />
|
||||
<EntityTagPicker />
|
||||
</FilterContainer>
|
||||
<EntityListContainer>
|
||||
<CatalogTable
|
||||
columns={columns || defaultColumns}
|
||||
actions={actions}
|
||||
/>
|
||||
</EntityListContainer>
|
||||
</FilteredEntityLayout>
|
||||
</EntityListProvider>
|
||||
</Content>
|
||||
</PageWithHeader>
|
||||
);
|
||||
return outlet || <DefaultApiExplorerPage {...props} />;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Entity, RELATION_MEMBER_OF } from '@backstage/catalog-model';
|
||||
import { ConfigReader } from '@backstage/core-app-api';
|
||||
import { TableColumn, TableProps } from '@backstage/core-components';
|
||||
import {
|
||||
ConfigApi,
|
||||
configApiRef,
|
||||
storageApiRef,
|
||||
} from '@backstage/core-plugin-api';
|
||||
import { CatalogTableRow } from '@backstage/plugin-catalog';
|
||||
import {
|
||||
CatalogApi,
|
||||
catalogApiRef,
|
||||
DefaultStarredEntitiesApi,
|
||||
entityRouteRef,
|
||||
starredEntitiesApiRef,
|
||||
} from '@backstage/plugin-catalog-react';
|
||||
import {
|
||||
MockStorageApi,
|
||||
TestApiProvider,
|
||||
wrapInTestApp,
|
||||
} from '@backstage/test-utils';
|
||||
import DashboardIcon from '@material-ui/icons/Dashboard';
|
||||
import { render } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { apiDocsConfigRef } from '../../config';
|
||||
import { DefaultApiExplorerPage } from './DefaultApiExplorerPage';
|
||||
|
||||
describe('DefaultApiExplorerPage', () => {
|
||||
const catalogApi: Partial<CatalogApi> = {
|
||||
getEntities: () =>
|
||||
Promise.resolve({
|
||||
items: [
|
||||
{
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'API',
|
||||
metadata: {
|
||||
name: 'Entity1',
|
||||
},
|
||||
spec: { type: 'openapi' },
|
||||
},
|
||||
] as Entity[],
|
||||
}),
|
||||
getLocationByEntity: () =>
|
||||
Promise.resolve({ id: 'id', type: 'github', target: 'url' }),
|
||||
getEntityByName: async entityName => {
|
||||
return {
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'User',
|
||||
metadata: { name: entityName.name },
|
||||
relations: [
|
||||
{
|
||||
type: RELATION_MEMBER_OF,
|
||||
target: { namespace: 'default', kind: 'Group', name: 'tools' },
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
const configApi: ConfigApi = new ConfigReader({
|
||||
organization: {
|
||||
name: 'My Company',
|
||||
},
|
||||
});
|
||||
|
||||
const apiDocsConfig = {
|
||||
getApiDefinitionWidget: () => undefined,
|
||||
};
|
||||
|
||||
const storageApi = MockStorageApi.create();
|
||||
|
||||
const renderWrapped = (children: React.ReactNode) =>
|
||||
render(
|
||||
wrapInTestApp(
|
||||
<TestApiProvider
|
||||
apis={[
|
||||
[catalogApiRef, catalogApi],
|
||||
[configApiRef, configApi],
|
||||
[storageApiRef, storageApi],
|
||||
[
|
||||
starredEntitiesApiRef,
|
||||
new DefaultStarredEntitiesApi({ storageApi }),
|
||||
],
|
||||
[apiDocsConfigRef, apiDocsConfig],
|
||||
]}
|
||||
>
|
||||
{children}
|
||||
</TestApiProvider>,
|
||||
{
|
||||
mountedRoutes: {
|
||||
'/catalog/:namespace/:kind/:name': entityRouteRef,
|
||||
},
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
// this test right now causes some red lines in the log output when running tests
|
||||
// related to some theme issues in mui-table
|
||||
// https://github.com/mbrn/material-table/issues/1293
|
||||
it('should render', async () => {
|
||||
const { findByText } = renderWrapped(<DefaultApiExplorerPage />);
|
||||
expect(await findByText(/My Company API Explorer/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render the default column of the grid', async () => {
|
||||
const { getAllByRole } = renderWrapped(<DefaultApiExplorerPage />);
|
||||
|
||||
const columnHeader = getAllByRole('button').filter(
|
||||
c => c.tagName === 'SPAN',
|
||||
);
|
||||
const columnHeaderLabels = columnHeader.map(c => c.textContent);
|
||||
|
||||
expect(columnHeaderLabels).toEqual([
|
||||
'Name',
|
||||
'System',
|
||||
'Owner',
|
||||
'Type',
|
||||
'Lifecycle',
|
||||
'Description',
|
||||
'Tags',
|
||||
'Actions',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should render the custom column passed as prop', async () => {
|
||||
const columns: TableColumn<CatalogTableRow>[] = [
|
||||
{ title: 'Foo', field: 'entity.foo' },
|
||||
{ title: 'Bar', field: 'entity.bar' },
|
||||
{ title: 'Baz', field: 'entity.spec.lifecycle' },
|
||||
];
|
||||
const { getAllByRole } = renderWrapped(
|
||||
<DefaultApiExplorerPage columns={columns} />,
|
||||
);
|
||||
|
||||
const columnHeader = getAllByRole('button').filter(
|
||||
c => c.tagName === 'SPAN',
|
||||
);
|
||||
const columnHeaderLabels = columnHeader.map(c => c.textContent);
|
||||
|
||||
expect(columnHeaderLabels).toEqual(['Foo', 'Bar', 'Baz', 'Actions']);
|
||||
});
|
||||
|
||||
it('should render the default actions of an item in the grid', async () => {
|
||||
const { findByTitle, findByText } = await renderWrapped(
|
||||
<DefaultApiExplorerPage />,
|
||||
);
|
||||
expect(await findByText(/All \(1\)/)).toBeInTheDocument();
|
||||
expect(await findByTitle(/View/)).toBeInTheDocument();
|
||||
expect(await findByTitle(/View/)).toBeInTheDocument();
|
||||
expect(await findByTitle(/Edit/)).toBeInTheDocument();
|
||||
expect(await findByTitle(/Add to favorites/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render the custom actions of an item passed as prop', async () => {
|
||||
const actions: TableProps<CatalogTableRow>['actions'] = [
|
||||
() => {
|
||||
return {
|
||||
icon: () => <DashboardIcon fontSize="small" />,
|
||||
tooltip: 'Foo Action',
|
||||
disabled: false,
|
||||
onClick: () => jest.fn(),
|
||||
};
|
||||
},
|
||||
() => {
|
||||
return {
|
||||
icon: () => <DashboardIcon fontSize="small" />,
|
||||
tooltip: 'Bar Action',
|
||||
disabled: true,
|
||||
onClick: () => jest.fn(),
|
||||
};
|
||||
},
|
||||
];
|
||||
|
||||
const { findByTitle, findByText } = await renderWrapped(
|
||||
<DefaultApiExplorerPage actions={actions} />,
|
||||
);
|
||||
expect(await findByText(/All \(1\)/)).toBeInTheDocument();
|
||||
expect(await findByTitle(/Foo Action/)).toBeInTheDocument();
|
||||
expect(await findByTitle(/Bar Action/)).toBeInTheDocument();
|
||||
expect((await findByTitle(/Bar Action/)).firstChild).toBeDisabled();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
Content,
|
||||
ContentHeader,
|
||||
CreateButton,
|
||||
PageWithHeader,
|
||||
SupportButton,
|
||||
TableColumn,
|
||||
TableProps,
|
||||
} from '@backstage/core-components';
|
||||
import { configApiRef, useApi, useRouteRef } from '@backstage/core-plugin-api';
|
||||
import {
|
||||
CatalogTable,
|
||||
CatalogTableRow,
|
||||
FilteredEntityLayout,
|
||||
EntityListContainer,
|
||||
FilterContainer,
|
||||
} from '@backstage/plugin-catalog';
|
||||
import {
|
||||
EntityKindPicker,
|
||||
EntityLifecyclePicker,
|
||||
EntityListProvider,
|
||||
EntityOwnerPicker,
|
||||
EntityTagPicker,
|
||||
EntityTypePicker,
|
||||
UserListFilterKind,
|
||||
UserListPicker,
|
||||
} from '@backstage/plugin-catalog-react';
|
||||
import React from 'react';
|
||||
import { createComponentRouteRef } from '../../routes';
|
||||
|
||||
const defaultColumns: TableColumn<CatalogTableRow>[] = [
|
||||
CatalogTable.columns.createNameColumn({ defaultKind: 'API' }),
|
||||
CatalogTable.columns.createSystemColumn(),
|
||||
CatalogTable.columns.createOwnerColumn(),
|
||||
CatalogTable.columns.createSpecTypeColumn(),
|
||||
CatalogTable.columns.createSpecLifecycleColumn(),
|
||||
CatalogTable.columns.createMetadataDescriptionColumn(),
|
||||
CatalogTable.columns.createTagsColumn(),
|
||||
];
|
||||
|
||||
/**
|
||||
* DefaultApiExplorerPageProps
|
||||
* @public
|
||||
*/
|
||||
export type DefaultApiExplorerPageProps = {
|
||||
initiallySelectedFilter?: UserListFilterKind;
|
||||
columns?: TableColumn<CatalogTableRow>[];
|
||||
actions?: TableProps<CatalogTableRow>['actions'];
|
||||
};
|
||||
|
||||
/**
|
||||
* DefaultApiExplorerPage
|
||||
* @public
|
||||
*/
|
||||
export const DefaultApiExplorerPage = ({
|
||||
initiallySelectedFilter = 'all',
|
||||
columns,
|
||||
actions,
|
||||
}: DefaultApiExplorerPageProps) => {
|
||||
const configApi = useApi(configApiRef);
|
||||
const generatedSubtitle = `${
|
||||
configApi.getOptionalString('organization.name') ?? 'Backstage'
|
||||
} API Explorer`;
|
||||
const createComponentLink = useRouteRef(createComponentRouteRef);
|
||||
|
||||
return (
|
||||
<PageWithHeader
|
||||
themeId="apis"
|
||||
title="APIs"
|
||||
subtitle={generatedSubtitle}
|
||||
pageTitleOverride="APIs"
|
||||
>
|
||||
<Content>
|
||||
<ContentHeader title="">
|
||||
<CreateButton
|
||||
title="Register Existing API"
|
||||
to={createComponentLink?.()}
|
||||
/>
|
||||
<SupportButton>All your APIs</SupportButton>
|
||||
</ContentHeader>
|
||||
<EntityListProvider>
|
||||
<FilteredEntityLayout>
|
||||
<FilterContainer>
|
||||
<EntityKindPicker initialFilter="api" hidden />
|
||||
<EntityTypePicker />
|
||||
<UserListPicker initialFilter={initiallySelectedFilter} />
|
||||
<EntityOwnerPicker />
|
||||
<EntityLifecyclePicker />
|
||||
<EntityTagPicker />
|
||||
</FilterContainer>
|
||||
<EntityListContainer>
|
||||
<CatalogTable
|
||||
columns={columns || defaultColumns}
|
||||
actions={actions}
|
||||
/>
|
||||
</EntityListContainer>
|
||||
</FilteredEntityLayout>
|
||||
</EntityListProvider>
|
||||
</Content>
|
||||
</PageWithHeader>
|
||||
);
|
||||
};
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020 The Backstage Authors
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,4 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { ApiExplorerPage } from './ApiExplorerPage';
|
||||
export { ApiExplorerPage as ApiExplorerIndexPage } from './ApiExplorerPage';
|
||||
export { DefaultApiExplorerPage } from './DefaultApiExplorerPage';
|
||||
export type { DefaultApiExplorerPageProps } from './DefaultApiExplorerPage';
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export * from './ApiExplorerPage';
|
||||
export * from './ApiDefinitionCard';
|
||||
export * from './ApisCards';
|
||||
export * from './AsyncApiDefinitionWidget';
|
||||
|
||||
@@ -53,7 +53,7 @@ export const ApiExplorerPage = apiDocsPlugin.provide(
|
||||
createRoutableExtension({
|
||||
name: 'ApiExplorerPage',
|
||||
component: () =>
|
||||
import('./components/ApiExplorerPage').then(m => m.ApiExplorerPage),
|
||||
import('./components/ApiExplorerPage').then(m => m.ApiExplorerIndexPage),
|
||||
mountPoint: rootRoute,
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
# @backstage/plugin-app-backend
|
||||
|
||||
## 0.3.21
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 9d9cfc1b8a: Set `X-Frame-Options: deny` rather than the default `sameorigin` for all content served by the `app-backend`.`
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.10.1
|
||||
- @backstage/config-loader@0.9.1
|
||||
|
||||
## 0.3.20
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/plugin-app-backend",
|
||||
"description": "A Backstage backend plugin that serves the Backstage frontend app",
|
||||
"version": "0.3.20",
|
||||
"version": "0.3.21",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -30,8 +30,8 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/backend-common": "^0.10.0",
|
||||
"@backstage/config-loader": "^0.9.0",
|
||||
"@backstage/backend-common": "^0.10.1",
|
||||
"@backstage/config-loader": "^0.9.1",
|
||||
"@backstage/config": "^0.1.11",
|
||||
"@backstage/types": "^0.1.1",
|
||||
"@types/express": "^4.17.6",
|
||||
@@ -43,7 +43,7 @@
|
||||
"yn": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.10.3",
|
||||
"@backstage/cli": "^0.10.4",
|
||||
"@backstage/types": "^0.1.1",
|
||||
"@types/supertest": "^2.0.8",
|
||||
"msw": "^0.35.0",
|
||||
|
||||
@@ -1,5 +1,45 @@
|
||||
# @backstage/plugin-auth-backend
|
||||
|
||||
## 0.6.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- c88cdacc1a: Avoid ever returning OAuth refresh tokens back to the client, and always exchange refresh tokens for a new one when available for all providers.
|
||||
|
||||
This comes with a breaking change to the TypeScript API for custom auth providers. The `refresh` method of `OAuthHandlers` implementation must now return a `{ response, refreshToken }` object rather than a direct response. Existing `refresh` implementations are typically migrated by changing an existing return expression that looks like this:
|
||||
|
||||
```ts
|
||||
return await this.handleResult({
|
||||
fullProfile,
|
||||
params,
|
||||
accessToken,
|
||||
refreshToken,
|
||||
});
|
||||
```
|
||||
|
||||
Into the following:
|
||||
|
||||
```ts
|
||||
return {
|
||||
response: await this.handleResult({
|
||||
fullProfile,
|
||||
params,
|
||||
accessToken,
|
||||
}),
|
||||
refreshToken,
|
||||
};
|
||||
```
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- f0f81f6cc7: Replaces the usage of `got` with `node-fetch` in the `getUserPhoto` method of the Microsoft provider
|
||||
- 2f26120a36: Update `auth0` and `onelogin` providers to allow for `authHandler` and `signIn.resolver` configuration.
|
||||
- a9abafa9df: Fixed bug on refresh token on Okta provider, now it gets the refresh token and it sends it into providerInfo
|
||||
- eb48e78886: Enforce cookie SSL protection when in production for auth-backend sessions
|
||||
- Updated dependencies
|
||||
- @backstage/test-utils@0.2.1
|
||||
- @backstage/backend-common@0.10.1
|
||||
|
||||
## 0.5.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/plugin-auth-backend",
|
||||
"description": "A Backstage backend plugin that handles authentication",
|
||||
"version": "0.5.2",
|
||||
"version": "0.6.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -30,12 +30,12 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/backend-common": "^0.10.0",
|
||||
"@backstage/backend-common": "^0.10.1",
|
||||
"@backstage/catalog-client": "^0.5.3",
|
||||
"@backstage/catalog-model": "^0.9.8",
|
||||
"@backstage/config": "^0.1.11",
|
||||
"@backstage/errors": "^0.1.5",
|
||||
"@backstage/test-utils": "^0.2.0",
|
||||
"@backstage/test-utils": "^0.2.1",
|
||||
"@google-cloud/firestore": "^4.15.1",
|
||||
"@types/express": "^4.17.6",
|
||||
"@types/passport": "^1.0.3",
|
||||
@@ -72,7 +72,7 @@
|
||||
"yn": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.10.3",
|
||||
"@backstage/cli": "^0.10.4",
|
||||
"@types/body-parser": "^1.19.0",
|
||||
"@types/cookie-parser": "^1.4.2",
|
||||
"@types/express-session": "^1.17.2",
|
||||
|
||||
@@ -46,10 +46,10 @@
|
||||
"react": "^16.13.1 || ^17.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.10.3",
|
||||
"@backstage/cli": "^0.10.4",
|
||||
"@backstage/core-app-api": "^0.3.0",
|
||||
"@backstage/dev-utils": "^0.2.15",
|
||||
"@backstage/test-utils": "^0.2.0",
|
||||
"@backstage/test-utils": "^0.2.1",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^11.2.5",
|
||||
"@testing-library/user-event": "^13.1.8",
|
||||
|
||||
@@ -43,10 +43,10 @@
|
||||
"react": "^16.13.1 || ^17.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.10.3",
|
||||
"@backstage/cli": "^0.10.4",
|
||||
"@backstage/core-app-api": "^0.3.0",
|
||||
"@backstage/dev-utils": "^0.2.15",
|
||||
"@backstage/test-utils": "^0.2.0",
|
||||
"@backstage/test-utils": "^0.2.1",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^11.2.5",
|
||||
"@testing-library/user-event": "^13.1.8",
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
"react": "^16.13.1 || ^17.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.10.3",
|
||||
"@backstage/cli": "^0.10.4",
|
||||
"@backstage/dev-utils": "^0.2.15",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"cross-fetch": "^3.0.6"
|
||||
|
||||
@@ -40,10 +40,10 @@
|
||||
"react": "^16.13.1 || ^17.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.10.3",
|
||||
"@backstage/cli": "^0.10.4",
|
||||
"@backstage/core-app-api": "^0.3.0",
|
||||
"@backstage/dev-utils": "^0.2.15",
|
||||
"@backstage/test-utils": "^0.2.0",
|
||||
"@backstage/test-utils": "^0.2.1",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^11.2.5",
|
||||
"@testing-library/user-event": "^13.1.8",
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# @backstage/plugin-catalog-backend
|
||||
|
||||
## 0.19.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 7d4b4e937c: Uptake changes to the GitHub Credentials Provider interface.
|
||||
- 3a63491c5f: Filter out projects with missing `default_branch` from GitLab Discovery.
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.10.1
|
||||
- @backstage/integration@0.7.0
|
||||
|
||||
## 0.19.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/plugin-catalog-backend",
|
||||
"description": "The Backstage backend plugin that provides the Backstage catalog",
|
||||
"version": "0.19.3",
|
||||
"version": "0.19.4",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -30,12 +30,12 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/backend-common": "^0.10.0",
|
||||
"@backstage/backend-common": "^0.10.1",
|
||||
"@backstage/catalog-client": "^0.5.3",
|
||||
"@backstage/catalog-model": "^0.9.8",
|
||||
"@backstage/config": "^0.1.11",
|
||||
"@backstage/errors": "^0.1.5",
|
||||
"@backstage/integration": "^0.6.10",
|
||||
"@backstage/integration": "^0.7.0",
|
||||
"@backstage/search-common": "^0.2.1",
|
||||
"@backstage/types": "^0.1.1",
|
||||
"@octokit/graphql": "^4.5.8",
|
||||
@@ -62,9 +62,9 @@
|
||||
"yup": "^0.32.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/backend-test-utils": "^0.1.11",
|
||||
"@backstage/cli": "^0.10.3",
|
||||
"@backstage/test-utils": "^0.2.0",
|
||||
"@backstage/backend-test-utils": "^0.1.12",
|
||||
"@backstage/cli": "^0.10.4",
|
||||
"@backstage/test-utils": "^0.2.1",
|
||||
"@types/core-js": "^2.5.4",
|
||||
"@types/git-url-parse": "^9.0.0",
|
||||
"@types/lodash": "^4.14.151",
|
||||
|
||||
@@ -184,6 +184,13 @@ describe('GitlabDiscoveryProcessor', () => {
|
||||
last_activity_at: '2021-08-05T11:03:05.774Z',
|
||||
web_url: 'https://gitlab.fake/3',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
archived: false,
|
||||
default_branch: undefined, // MISSING DEFAULT BRANCH
|
||||
last_activity_at: '2021-08-05T11:03:05.774Z',
|
||||
web_url: 'https://gitlab.fake/4',
|
||||
},
|
||||
],
|
||||
};
|
||||
default:
|
||||
|
||||
@@ -94,9 +94,16 @@ export class GitLabDiscoveryProcessor implements CatalogProcessor {
|
||||
};
|
||||
for await (const project of projects) {
|
||||
result.scanned++;
|
||||
if (!project.archived) {
|
||||
result.matches.push(project);
|
||||
|
||||
if (project.archived) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (branch === '*' && project.default_branch === undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
result.matches.push(project);
|
||||
}
|
||||
|
||||
for (const project of result.matches) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user