diff --git a/.changeset/angry-phones-wash.md b/.changeset/angry-phones-wash.md
new file mode 100644
index 0000000000..ac59a924a2
--- /dev/null
+++ b/.changeset/angry-phones-wash.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-devtools': patch
+---
+
+Allow specifying custom title for `DevToolsLayout`
diff --git a/.changeset/cli-always-yarn-pack-freal.md b/.changeset/cli-always-yarn-pack-freal.md
new file mode 100644
index 0000000000..b58ffea857
--- /dev/null
+++ b/.changeset/cli-always-yarn-pack-freal.md
@@ -0,0 +1,5 @@
+---
+'@backstage/cli': patch
+---
+
+Fixed the `--alwaysYarnPack` flag on the`backstage-cli build-workspace` command.
diff --git a/.changeset/cyan-shirts-deny.md b/.changeset/cyan-shirts-deny.md
new file mode 100644
index 0000000000..d6d3a2a2ba
--- /dev/null
+++ b/.changeset/cyan-shirts-deny.md
@@ -0,0 +1,10 @@
+---
+'@backstage/plugin-catalog-unprocessed-entities': patch
+---
+
+The Catalog Unprocessed Entities plugin can now be integrated as a tab within the DevTools plugin
+
+- Added an export for `UnprocessedEntitiesContent`
+- Updated the `README` with images of the features
+- Adjusted the styles to fill in the available space
+- Set the table page size to 20 as 40 was causing errors in the browser console
diff --git a/.changeset/dirty-wasps-draw.md b/.changeset/dirty-wasps-draw.md
new file mode 100644
index 0000000000..5686191cab
--- /dev/null
+++ b/.changeset/dirty-wasps-draw.md
@@ -0,0 +1,5 @@
+---
+'@backstage/errors': patch
+---
+
+Set `this.name` in all error classes that extend `CustomErrorBase` class to their actual name
diff --git a/.changeset/dull-onions-remember.md b/.changeset/dull-onions-remember.md
new file mode 100644
index 0000000000..f309bf5c4c
--- /dev/null
+++ b/.changeset/dull-onions-remember.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-stackstorm': patch
+---
+
+Add props to StackstormHome for Header Customization
diff --git a/.changeset/green-otters-wait.md b/.changeset/green-otters-wait.md
new file mode 100644
index 0000000000..02bc30f6aa
--- /dev/null
+++ b/.changeset/green-otters-wait.md
@@ -0,0 +1,7 @@
+---
+'@backstage/plugin-catalog-unprocessed-entities': patch
+---
+
+Export some types and API items. This allows people to call the API from different places with the ApiRef, as well
+as completely customize the client if required. Check the [README.md](https://github.com/backstage/backstage/blob/master/plugins/catalog-unprocessed-entities/README.md) to
+note what needs to be added in order to use the new `catalogUnprocessedEntitiesApiRef` exported function.
diff --git a/.changeset/lazy-frogs-destroy.md b/.changeset/lazy-frogs-destroy.md
new file mode 100644
index 0000000000..eb2b320e0a
--- /dev/null
+++ b/.changeset/lazy-frogs-destroy.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-devtools': patch
+---
+
+Updated the `README` with instructions on how to integrate the Catalog Unprocessed Entities plugin as a tab within DevTools
diff --git a/.changeset/many-ants-poke.md b/.changeset/many-ants-poke.md
new file mode 100644
index 0000000000..e6d94fdee5
--- /dev/null
+++ b/.changeset/many-ants-poke.md
@@ -0,0 +1,5 @@
+---
+'@backstage/backend-common': patch
+---
+
+use `Readable.from` to explicitly convert the `buffer` from `node-fetch` to a `Readable` stream
diff --git a/.changeset/mighty-shoes-refuse.md b/.changeset/mighty-shoes-refuse.md
new file mode 100644
index 0000000000..ec17e5e357
--- /dev/null
+++ b/.changeset/mighty-shoes-refuse.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-dynatrace': patch
+---
+
+updated the link that the "View Entity in Dynatrace" redirects the user to.
diff --git a/.changeset/old-rules-give.md b/.changeset/old-rules-give.md
new file mode 100644
index 0000000000..e28e2778ed
--- /dev/null
+++ b/.changeset/old-rules-give.md
@@ -0,0 +1,6 @@
+---
+'@backstage/plugin-catalog-backend-module-unprocessed': patch
+'@backstage/plugin-catalog-unprocessed-entities': patch
+---
+
+Fix and improve documentation for the unprocessed entities modules.
diff --git a/.changeset/popular-kangaroos-accept.md b/.changeset/popular-kangaroos-accept.md
new file mode 100644
index 0000000000..c297b3220f
--- /dev/null
+++ b/.changeset/popular-kangaroos-accept.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-home': patch
+---
+
+fix: update plugin home dependency for `@rjsf/material-ui` to `@rjsf/material-ui-v5`
diff --git a/.changeset/purple-starfishes-design.md b/.changeset/purple-starfishes-design.md
new file mode 100644
index 0000000000..d10602ee3d
--- /dev/null
+++ b/.changeset/purple-starfishes-design.md
@@ -0,0 +1,8 @@
+---
+'@backstage/plugin-catalog-backend-module-github': patch
+'@backstage/core-components': patch
+'@backstage/plugin-playlist': patch
+'@backstage/plugin-nomad': patch
+---
+
+Break some internal circular import chains
diff --git a/.changeset/short-rabbits-roll.md b/.changeset/short-rabbits-roll.md
new file mode 100644
index 0000000000..4ed0768485
--- /dev/null
+++ b/.changeset/short-rabbits-roll.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-entity-feedback-backend': patch
+---
+
+Added support for the new backend system
diff --git a/.changeset/sour-humans-begin.md b/.changeset/sour-humans-begin.md
new file mode 100644
index 0000000000..1f090f1c89
--- /dev/null
+++ b/.changeset/sour-humans-begin.md
@@ -0,0 +1,6 @@
+---
+'@backstage/plugin-catalog-backend': minor
+'@backstage/plugin-catalog-node': minor
+---
+
+Support placeholder resolvers in the CatalogPlugin, also moves `PlaceholderResolver` and related types from `@backstage/plugin-catalog-backend` to `@backstage/plugin-catalog-node`.
diff --git a/.changeset/tough-flowers-suffer.md b/.changeset/tough-flowers-suffer.md
new file mode 100644
index 0000000000..784d331107
--- /dev/null
+++ b/.changeset/tough-flowers-suffer.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-kubernetes-backend': patch
+---
+
+Update readme with a valid link to k8s documentation
diff --git a/.changeset/twenty-seas-float.md b/.changeset/twenty-seas-float.md
new file mode 100644
index 0000000000..3ee79ba4e5
--- /dev/null
+++ b/.changeset/twenty-seas-float.md
@@ -0,0 +1,5 @@
+---
+'@backstage/core-components': patch
+---
+
+Fix keyboard navigation & focus highlight on Select component.
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 33097b505a..82a9eb499d 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -39,6 +39,9 @@ yarn.lock @backstage/maintainers @back
/plugins/code-coverage-backend @backstage/maintainers @alde @nissayeva
/plugins/cost-insights @backstage/maintainers @backstage/silver-lining
/plugins/cost-insights-* @backstage/maintainers @backstage/silver-lining
+/plugins/devtools @backstage/maintainers @awanlin
+/plugins/devtools-backend @backstage/maintainers @awanlin
+/plugins/devtools-common @backstage/maintainers @awanlin
/plugins/entity-feedback @backstage/maintainers @kuangp
/plugins/entity-feedback-* @backstage/maintainers @kuangp
/plugins/events-backend @backstage/maintainers @pjungermann
@@ -64,6 +67,9 @@ yarn.lock @backstage/maintainers @back
/plugins/kafka-backend @backstage/maintainers @nirga @andrewthauer
/plugins/kubernetes @backstage/maintainers @backstage/kubernetes-maintainers
/plugins/kubernetes-* @backstage/maintainers @backstage/kubernetes-maintainers
+/plugins/linguist @backstage/maintainers @awanlin
+/plugins/linguist-backend @backstage/maintainers @awanlin
+/plugins/linguist-common @backstage/maintainers @awanlin
/plugins/microsoft-calendar @backstage/maintainers @abhay-soni-developer @NishkarshRaj
/plugins/newrelic-dashboard @backstage/maintainers @mufaddal7
/plugins/permission-* @backstage/permission-maintainers
diff --git a/cypress/yarn.lock b/cypress/yarn.lock
index 36dd0b056d..290f441c4c 100644
--- a/cypress/yarn.lock
+++ b/cypress/yarn.lock
@@ -1230,13 +1230,13 @@ __metadata:
linkType: hard
"semver@npm:^7.3.2":
- version: 7.3.7
- resolution: "semver@npm:7.3.7"
+ version: 7.5.3
+ resolution: "semver@npm:7.5.3"
dependencies:
lru-cache: ^6.0.0
bin:
semver: bin/semver.js
- checksum: 2fa3e877568cd6ce769c75c211beaed1f9fce80b28338cadd9d0b6c40f2e2862bafd62c19a6cff42f3d54292b7c623277bcab8816a2b5521cf15210d43e75232
+ checksum: 9d58db16525e9f749ad0a696a1f27deabaa51f66e91d2fa2b0db3de3e9644e8677de3b7d7a03f4c15bc81521e0c3916d7369e0572dbde250d9bedf5194e2a8a7
languageName: node
linkType: hard
diff --git a/docs/features/software-catalog/descriptor-format.md b/docs/features/software-catalog/descriptor-format.md
index 1c9825d5ca..0be2bf0292 100644
--- a/docs/features/software-catalog/descriptor-format.md
+++ b/docs/features/software-catalog/descriptor-format.md
@@ -351,7 +351,7 @@ component, like `java` or `go`.
This field is optional, and currently has no special semantics.
-Each tag must be sequences of `[a-z0-9]` separated by `-`, at most 63 characters
+Each tag must be sequences of `[a-z0-9:+#]` separated by `-`, at most 63 characters
in total.
### `links` [optional]
diff --git a/docs/features/software-templates/writing-custom-actions.md b/docs/features/software-templates/writing-custom-actions.md
index f04940a418..c2f14d0ca0 100644
--- a/docs/features/software-templates/writing-custom-actions.md
+++ b/docs/features/software-templates/writing-custom-actions.md
@@ -4,8 +4,8 @@ title: Writing Custom Actions
description: How to write your own actions
---
-If you're wanting to extend the functionality of the Scaffolder, you can do so
-by writing custom actions which can be used along side our
+If you want to extend the functionality of the Scaffolder, you can do so
+by writing custom actions which can be used alongside our
[built-in actions](./builtin-actions.md).
> Note: When adding custom actions, the actions array will **replace the
@@ -65,7 +65,7 @@ The `createTemplateAction` takes an object which specifies the following:
- `schema.input` - A `zod` or JSON schema object for input values to your function
- `schema.output` - A `zod` or JSON schema object for values which are output from the
function using `ctx.output`
-- `handler` - the actual code which is run part of the action, with a context
+- `handler` - the actual code which is run as part of the action, with a context
You can also choose to define your custom action using JSON schema instead of `zod`:
diff --git a/docs/getting-started/homepage.md b/docs/getting-started/homepage.md
index 9c6f6380a1..04dfb13d6a 100644
--- a/docs/getting-started/homepage.md
+++ b/docs/getting-started/homepage.md
@@ -40,7 +40,7 @@ Inside your `packages/app` directory, create a new file where our new homepage c
```tsx
import React from 'react';
-export const homePage = (
+export const HomePage = () => (
/* We will shortly compose a pretty homepage here. */
Welcome to Backstage!
);
diff --git a/docs/getting-started/index.md b/docs/getting-started/index.md
index 820f5ef394..773b5bd5a2 100644
--- a/docs/getting-started/index.md
+++ b/docs/getting-started/index.md
@@ -53,6 +53,8 @@ create a subdirectory inside your current working directory.
npx @backstage/create-app@latest
```
+> Note: If this fails on the `yarn install` step, it's likely that you will need to install some additional dependencies which are used to configure `isolated-vm`. You can find out more in their [requirements section](https://github.com/laverdet/isolated-vm#requirements), and then run `yarn install` manually again after you've completed those steps.
+
The wizard will ask you for the name of the app, which will also be the name of the directory

diff --git a/docs/integrations/azure/org.md b/docs/integrations/azure/org.md
index f855b29bb9..8b7bd3c5b8 100644
--- a/docs/integrations/azure/org.md
+++ b/docs/integrations/azure/org.md
@@ -37,7 +37,7 @@ catalog:
```
Finally, register the plugin in `catalog.ts`.
-For large organizations, this plugin can take a long time, so be careful setting low frequency / timeouts.
+For large organizations, this plugin can take a long time, so be careful setting low frequency / timeouts and importing a large amount of users / groups for the first try.
```ts title="packages/backend/src/plugins/catalog.ts"
/* highlight-add-next-line */
@@ -106,7 +106,7 @@ To grant the managed identity the same permissions as mentioned in _App Registra
## Filtering imported Users and Groups
By default, the plugin will import all users and groups from your directory.
-This can be customized through [filters](https://learn.microsoft.com/en-us/graph/filter-query-parameter) and [search](https://learn.microsoft.com/en-us/graph/search-query-parameter) queries.
+This can be customized through [filters](https://learn.microsoft.com/en-us/graph/filter-query-parameter) and [search](https://learn.microsoft.com/en-us/graph/search-query-parameter) queries. Keep in mind that if you omit filters and search queries for the user or group properties, the plugin will automatically import all available users or groups.
### Groups
diff --git a/microsite/data/plugins/devtools.yaml b/microsite/data/plugins/devtools.yaml
new file mode 100644
index 0000000000..b531195c04
--- /dev/null
+++ b/microsite/data/plugins/devtools.yaml
@@ -0,0 +1,10 @@
+---
+title: 'DevTools'
+author: Keyloop
+authorUrl: https://keyloop.com/
+category: Tools
+description: Tools for helping with the Ops side of running a Backstage instance
+documentation: https://github.com/backstage/backstage/blob/master/plugins/devtools/README.md
+iconUrl: /img/devtools.svg
+npmPackageName: '@backstage/plugin-devtools'
+addedDate: '2023-06-17'
diff --git a/microsite/data/plugins/linguist.yaml b/microsite/data/plugins/linguist.yaml
new file mode 100644
index 0000000000..d76936391c
--- /dev/null
+++ b/microsite/data/plugins/linguist.yaml
@@ -0,0 +1,10 @@
+---
+title: 'Linguist'
+author: Keyloop
+authorUrl: https://keyloop.com/
+category: Metadata
+description: View the programming language break down for your entities within the Software Catalog
+documentation: https://github.com/backstage/backstage/blob/master/plugins/linguist/README.md
+iconUrl: /img/linguist.svg
+npmPackageName: '@backstage/plugin-linguist'
+addedDate: '2023-06-17'
diff --git a/microsite/data/plugins/search-backend-module-azure-devops-wiki b/microsite/data/plugins/search-backend-module-azure-devops-wiki.yaml
similarity index 98%
rename from microsite/data/plugins/search-backend-module-azure-devops-wiki
rename to microsite/data/plugins/search-backend-module-azure-devops-wiki.yaml
index 0f421abfa8..02d4131cce 100644
--- a/microsite/data/plugins/search-backend-module-azure-devops-wiki
+++ b/microsite/data/plugins/search-backend-module-azure-devops-wiki.yaml
@@ -3,7 +3,7 @@ title: Azure DevOps Wiki Search
author: Drew Hill
authorUrl: https://github.com/arhill05
category: Search
-description: Index wiki articles from an Azure DevOps wiki into Backstage to allow you to search them with the Backstage Search feature.
+description: Index wiki articles from an Azure DevOps wiki into Backstage to allow you to search them with the Backstage Search feature.
documentation: https://github.com/arhill05/backstage-plugin-search-backend-module-azure-devops-wiki#readme
iconUrl: img/ado-wiki-search-icon.png
npmPackageName: '@mdude2314/backstage-plugin-search-backend-module-azure-devops-wiki'
diff --git a/microsite/docusaurus.config.js b/microsite/docusaurus.config.js
index a13168472d..e78626e37c 100644
--- a/microsite/docusaurus.config.js
+++ b/microsite/docusaurus.config.js
@@ -127,6 +127,10 @@ module.exports = {
from: '/docs/features/techdocs/techdocs-overview',
to: '/docs/features/techdocs/',
},
+ {
+ from: '/docs/features/kubernetes/overview',
+ to: '/docs/features/kubernetes/',
+ },
{
from: '/docs/features/search/search-overview',
to: '/docs/features/search/',
diff --git a/microsite/static/img/devtools.svg b/microsite/static/img/devtools.svg
new file mode 100644
index 0000000000..6bd5dc17c5
--- /dev/null
+++ b/microsite/static/img/devtools.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/microsite/static/img/linguist.svg b/microsite/static/img/linguist.svg
new file mode 100644
index 0000000000..3cddc1affc
--- /dev/null
+++ b/microsite/static/img/linguist.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/microsite/yarn.lock b/microsite/yarn.lock
index 3c19a6e05c..269f752352 100644
--- a/microsite/yarn.lock
+++ b/microsite/yarn.lock
@@ -2604,90 +2604,90 @@ __metadata:
languageName: node
linkType: hard
-"@swc/core-darwin-arm64@npm:1.3.62":
- version: 1.3.62
- resolution: "@swc/core-darwin-arm64@npm:1.3.62"
+"@swc/core-darwin-arm64@npm:1.3.66":
+ version: 1.3.66
+ resolution: "@swc/core-darwin-arm64@npm:1.3.66"
conditions: os=darwin & cpu=arm64
languageName: node
linkType: hard
-"@swc/core-darwin-x64@npm:1.3.62":
- version: 1.3.62
- resolution: "@swc/core-darwin-x64@npm:1.3.62"
+"@swc/core-darwin-x64@npm:1.3.66":
+ version: 1.3.66
+ resolution: "@swc/core-darwin-x64@npm:1.3.66"
conditions: os=darwin & cpu=x64
languageName: node
linkType: hard
-"@swc/core-linux-arm-gnueabihf@npm:1.3.62":
- version: 1.3.62
- resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.62"
+"@swc/core-linux-arm-gnueabihf@npm:1.3.66":
+ version: 1.3.66
+ resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.66"
conditions: os=linux & cpu=arm
languageName: node
linkType: hard
-"@swc/core-linux-arm64-gnu@npm:1.3.62":
- version: 1.3.62
- resolution: "@swc/core-linux-arm64-gnu@npm:1.3.62"
+"@swc/core-linux-arm64-gnu@npm:1.3.66":
+ version: 1.3.66
+ resolution: "@swc/core-linux-arm64-gnu@npm:1.3.66"
conditions: os=linux & cpu=arm64 & libc=glibc
languageName: node
linkType: hard
-"@swc/core-linux-arm64-musl@npm:1.3.62":
- version: 1.3.62
- resolution: "@swc/core-linux-arm64-musl@npm:1.3.62"
+"@swc/core-linux-arm64-musl@npm:1.3.66":
+ version: 1.3.66
+ resolution: "@swc/core-linux-arm64-musl@npm:1.3.66"
conditions: os=linux & cpu=arm64 & libc=musl
languageName: node
linkType: hard
-"@swc/core-linux-x64-gnu@npm:1.3.62":
- version: 1.3.62
- resolution: "@swc/core-linux-x64-gnu@npm:1.3.62"
+"@swc/core-linux-x64-gnu@npm:1.3.66":
+ version: 1.3.66
+ resolution: "@swc/core-linux-x64-gnu@npm:1.3.66"
conditions: os=linux & cpu=x64 & libc=glibc
languageName: node
linkType: hard
-"@swc/core-linux-x64-musl@npm:1.3.62":
- version: 1.3.62
- resolution: "@swc/core-linux-x64-musl@npm:1.3.62"
+"@swc/core-linux-x64-musl@npm:1.3.66":
+ version: 1.3.66
+ resolution: "@swc/core-linux-x64-musl@npm:1.3.66"
conditions: os=linux & cpu=x64 & libc=musl
languageName: node
linkType: hard
-"@swc/core-win32-arm64-msvc@npm:1.3.62":
- version: 1.3.62
- resolution: "@swc/core-win32-arm64-msvc@npm:1.3.62"
+"@swc/core-win32-arm64-msvc@npm:1.3.66":
+ version: 1.3.66
+ resolution: "@swc/core-win32-arm64-msvc@npm:1.3.66"
conditions: os=win32 & cpu=arm64
languageName: node
linkType: hard
-"@swc/core-win32-ia32-msvc@npm:1.3.62":
- version: 1.3.62
- resolution: "@swc/core-win32-ia32-msvc@npm:1.3.62"
+"@swc/core-win32-ia32-msvc@npm:1.3.66":
+ version: 1.3.66
+ resolution: "@swc/core-win32-ia32-msvc@npm:1.3.66"
conditions: os=win32 & cpu=ia32
languageName: node
linkType: hard
-"@swc/core-win32-x64-msvc@npm:1.3.62":
- version: 1.3.62
- resolution: "@swc/core-win32-x64-msvc@npm:1.3.62"
+"@swc/core-win32-x64-msvc@npm:1.3.66":
+ version: 1.3.66
+ resolution: "@swc/core-win32-x64-msvc@npm:1.3.66"
conditions: os=win32 & cpu=x64
languageName: node
linkType: hard
"@swc/core@npm:^1.3.46":
- version: 1.3.62
- resolution: "@swc/core@npm:1.3.62"
+ version: 1.3.66
+ resolution: "@swc/core@npm:1.3.66"
dependencies:
- "@swc/core-darwin-arm64": 1.3.62
- "@swc/core-darwin-x64": 1.3.62
- "@swc/core-linux-arm-gnueabihf": 1.3.62
- "@swc/core-linux-arm64-gnu": 1.3.62
- "@swc/core-linux-arm64-musl": 1.3.62
- "@swc/core-linux-x64-gnu": 1.3.62
- "@swc/core-linux-x64-musl": 1.3.62
- "@swc/core-win32-arm64-msvc": 1.3.62
- "@swc/core-win32-ia32-msvc": 1.3.62
- "@swc/core-win32-x64-msvc": 1.3.62
+ "@swc/core-darwin-arm64": 1.3.66
+ "@swc/core-darwin-x64": 1.3.66
+ "@swc/core-linux-arm-gnueabihf": 1.3.66
+ "@swc/core-linux-arm64-gnu": 1.3.66
+ "@swc/core-linux-arm64-musl": 1.3.66
+ "@swc/core-linux-x64-gnu": 1.3.66
+ "@swc/core-linux-x64-musl": 1.3.66
+ "@swc/core-win32-arm64-msvc": 1.3.66
+ "@swc/core-win32-ia32-msvc": 1.3.66
+ "@swc/core-win32-x64-msvc": 1.3.66
peerDependencies:
"@swc/helpers": ^0.5.0
dependenciesMeta:
@@ -2714,7 +2714,7 @@ __metadata:
peerDependenciesMeta:
"@swc/helpers":
optional: true
- checksum: a7a0d9ffdb8a2b0050e0ff89fdb86fe189d9bcb7f91cb6847f1bfe3e2b520a87ea2e83692dfd80b6d541fb5addb2194769484516b8ca6d3c62ad80f1c79a9368
+ checksum: e6029c648ba47c522bed51a9f2fee606f82de1f9233e2e89197e43b0a4867054174ca05e825e688cdc4de332221c0da2e12ba7ba875549e8b5432aa70fe19263
languageName: node
linkType: hard
diff --git a/packages/app/src/components/devtools/CustomDevToolsPage.tsx b/packages/app/src/components/devtools/CustomDevToolsPage.tsx
index dfe70426aa..788b555c6d 100644
--- a/packages/app/src/components/devtools/CustomDevToolsPage.tsx
+++ b/packages/app/src/components/devtools/CustomDevToolsPage.tsx
@@ -21,6 +21,7 @@ import {
} from '@backstage/plugin-devtools';
import { DevToolsLayout } from '@backstage/plugin-devtools';
import React from 'react';
+import { UnprocessedEntitiesContent } from '@backstage/plugin-catalog-unprocessed-entities';
const DevToolsPage = () => {
return (
@@ -37,6 +38,12 @@ const DevToolsPage = () => {
>
+
+
+
);
};
diff --git a/packages/backend-common/src/reading/AzureUrlReader.ts b/packages/backend-common/src/reading/AzureUrlReader.ts
index 26fe3f4a12..94abf3a178 100644
--- a/packages/backend-common/src/reading/AzureUrlReader.ts
+++ b/packages/backend-common/src/reading/AzureUrlReader.ts
@@ -158,7 +158,7 @@ export class AzureUrlReader implements UrlReader {
}
return await this.deps.treeResponseFactory.fromZipArchive({
- stream: archiveAzureResponse.body as unknown as Readable,
+ stream: Readable.from(archiveAzureResponse.body),
etag: commitSha,
filter,
subpath,
diff --git a/packages/backend-common/src/reading/BitbucketCloudUrlReader.ts b/packages/backend-common/src/reading/BitbucketCloudUrlReader.ts
index 1522b7678d..93587cd6ae 100644
--- a/packages/backend-common/src/reading/BitbucketCloudUrlReader.ts
+++ b/packages/backend-common/src/reading/BitbucketCloudUrlReader.ts
@@ -160,7 +160,7 @@ export class BitbucketCloudUrlReader implements UrlReader {
}
return await this.deps.treeResponseFactory.fromTarArchive({
- stream: archiveResponse.body as unknown as Readable,
+ stream: Readable.from(archiveResponse.body),
subpath: filepath,
etag: lastCommitShortHash,
filter: options?.filter,
diff --git a/packages/backend-common/src/reading/BitbucketServerUrlReader.ts b/packages/backend-common/src/reading/BitbucketServerUrlReader.ts
index 2b6b5a1f8f..8e2f1708c4 100644
--- a/packages/backend-common/src/reading/BitbucketServerUrlReader.ts
+++ b/packages/backend-common/src/reading/BitbucketServerUrlReader.ts
@@ -151,7 +151,7 @@ export class BitbucketServerUrlReader implements UrlReader {
}
return await this.deps.treeResponseFactory.fromTarArchive({
- stream: archiveResponse.body as unknown as Readable,
+ stream: Readable.from(archiveResponse.body),
subpath: filepath,
etag: lastCommitShortHash,
filter: options?.filter,
diff --git a/packages/backend-common/src/reading/BitbucketUrlReader.ts b/packages/backend-common/src/reading/BitbucketUrlReader.ts
index 3a34c725c6..090fe9098d 100644
--- a/packages/backend-common/src/reading/BitbucketUrlReader.ts
+++ b/packages/backend-common/src/reading/BitbucketUrlReader.ts
@@ -171,7 +171,7 @@ export class BitbucketUrlReader implements UrlReader {
}
return await this.deps.treeResponseFactory.fromTarArchive({
- stream: archiveBitbucketResponse.body as unknown as Readable,
+ stream: Readable.from(archiveBitbucketResponse.body),
subpath: filepath,
etag: lastCommitShortHash,
filter: options?.filter,
diff --git a/packages/backend-common/src/reading/GerritUrlReader.ts b/packages/backend-common/src/reading/GerritUrlReader.ts
index 5d86e5d9ac..8ac5452a4c 100644
--- a/packages/backend-common/src/reading/GerritUrlReader.ts
+++ b/packages/backend-common/src/reading/GerritUrlReader.ts
@@ -204,7 +204,7 @@ export class GerritUrlReader implements UrlReader {
});
const tarArchive = Readable.from(data);
return await this.deps.treeResponseFactory.fromTarArchive({
- stream: tarArchive as unknown as Readable,
+ stream: tarArchive,
subpath: filePath === '/' ? undefined : filePath,
etag: branchInfo.revision,
filter: options?.filter,
diff --git a/packages/backend-common/src/reading/GithubUrlReader.ts b/packages/backend-common/src/reading/GithubUrlReader.ts
index 8300127c5b..764431386d 100644
--- a/packages/backend-common/src/reading/GithubUrlReader.ts
+++ b/packages/backend-common/src/reading/GithubUrlReader.ts
@@ -238,7 +238,7 @@ export class GithubUrlReader implements UrlReader {
return await this.deps.treeResponseFactory.fromTarArchive({
// TODO(Rugvip): Underlying implementation of fetch will be node-fetch, we probably want
// to stick to using that in exclusively backend code.
- stream: archive.body as unknown as Readable,
+ stream: Readable.from(archive.body),
subpath,
etag: sha,
filter: options?.filter,
@@ -347,7 +347,6 @@ export class GithubUrlReader implements UrlReader {
init: RequestInit,
): Promise {
const urlAsString = url.toString();
-
const response = await fetch(urlAsString, init);
if (!response.ok) {
diff --git a/packages/backend-common/src/reading/GitlabUrlReader.ts b/packages/backend-common/src/reading/GitlabUrlReader.ts
index ab59c19b16..178e65b40a 100644
--- a/packages/backend-common/src/reading/GitlabUrlReader.ts
+++ b/packages/backend-common/src/reading/GitlabUrlReader.ts
@@ -229,7 +229,7 @@ export class GitlabUrlReader implements UrlReader {
}
return await this.deps.treeResponseFactory.fromTarArchive({
- stream: archiveGitLabResponse.body as unknown as Readable,
+ stream: Readable.from(archiveGitLabResponse.body),
subpath: filepath,
etag: commitSha,
filter: options?.filter,
diff --git a/packages/backend-common/src/reading/tree/TarArchiveResponse.ts b/packages/backend-common/src/reading/tree/TarArchiveResponse.ts
index 493e283c5f..e1529c196a 100644
--- a/packages/backend-common/src/reading/tree/TarArchiveResponse.ts
+++ b/packages/backend-common/src/reading/tree/TarArchiveResponse.ts
@@ -151,7 +151,6 @@ export class TarArchiveResponse implements ReadTreeResponse {
const strip = this.subPath ? this.subPath.split('/').length : 1;
let filterError: Error | undefined = undefined;
-
await pipeline(
this.stream,
tar.extract({
diff --git a/packages/backend-next/package.json b/packages/backend-next/package.json
index e13078890a..bc7d5e666f 100644
--- a/packages/backend-next/package.json
+++ b/packages/backend-next/package.json
@@ -30,6 +30,7 @@
"@backstage/plugin-auth-node": "workspace:^",
"@backstage/plugin-catalog-backend": "workspace:^",
"@backstage/plugin-catalog-backend-module-unprocessed": "workspace:^",
+ "@backstage/plugin-entity-feedback-backend": "workspace:^",
"@backstage/plugin-kubernetes-backend": "workspace:^",
"@backstage/plugin-permission-backend": "workspace:^",
"@backstage/plugin-permission-common": "workspace:^",
diff --git a/packages/backend-next/src/index.ts b/packages/backend-next/src/index.ts
index cdba12e0e3..900062d61b 100644
--- a/packages/backend-next/src/index.ts
+++ b/packages/backend-next/src/index.ts
@@ -30,12 +30,16 @@ import { searchModuleTechDocsCollator } from '@backstage/plugin-search-backend-m
import { searchPlugin } from '@backstage/plugin-search-backend/alpha';
import { techdocsPlugin } from '@backstage/plugin-techdocs-backend/alpha';
import { todoPlugin } from '@backstage/plugin-todo-backend';
+import { entityFeedbackPlugin } from '@backstage/plugin-entity-feedback-backend';
import { catalogModuleUnprocessedEntities } from '@backstage/plugin-catalog-backend-module-unprocessed';
const backend = createBackend();
backend.add(appPlugin({ appPackageName: 'example-app' }));
+// Entity Feedback
+backend.add(entityFeedbackPlugin());
+
// Todo
backend.add(todoPlugin());
diff --git a/packages/cli/src/commands/buildWorkspace.ts b/packages/cli/src/commands/buildWorkspace.ts
index 97bf2f1239..685e4b1cb0 100644
--- a/packages/cli/src/commands/buildWorkspace.ts
+++ b/packages/cli/src/commands/buildWorkspace.ts
@@ -17,12 +17,17 @@
import fs from 'fs-extra';
import { createDistWorkspace } from '../lib/packager';
-export default async (dir: string, packages: string[]) => {
+type Options = {
+ alwaysYarnPack?: boolean;
+};
+
+export default async (dir: string, packages: string[], options: Options) => {
if (!(await fs.pathExists(dir))) {
throw new Error(`Target workspace directory doesn't exist, '${dir}'`);
}
await createDistWorkspace(packages, {
targetDir: dir,
+ alwaysYarnPack: options.alwaysYarnPack,
});
};
diff --git a/packages/core-components/src/components/Select/Select.tsx b/packages/core-components/src/components/Select/Select.tsx
index dbf5601112..918ce301fb 100644
--- a/packages/core-components/src/components/Select/Select.tsx
+++ b/packages/core-components/src/components/Select/Select.tsx
@@ -43,6 +43,9 @@ const BootstrapInput = withStyles(
'label + &': {
marginTop: theme.spacing(3),
},
+ '&.Mui-focused > div[role=button]': {
+ borderColor: theme.palette.primary.main,
+ },
},
input: {
borderRadius: theme.shape.borderRadius,
@@ -75,7 +78,7 @@ const useStyles = makeStyles(
(theme: Theme) =>
createStyles({
formControl: {
- margin: `${theme.spacing(1)} 0px`,
+ margin: theme.spacing(1, 0),
maxWidth: 300,
},
label: {
@@ -212,7 +215,6 @@ export function SelectComponent(props: SelectProps) {
onClose={handleClose}
input={}
label={label}
- tabIndex={0}
renderValue={s =>
multiple && (value as any[]).length !== 0 ? (
diff --git a/packages/core-components/src/layout/ItemCard/ItemCard.stories.tsx b/packages/core-components/src/layout/ItemCard/ItemCard.stories.tsx
index 1ba3dec3fd..a03ad9be41 100644
--- a/packages/core-components/src/layout/ItemCard/ItemCard.stories.tsx
+++ b/packages/core-components/src/layout/ItemCard/ItemCard.stories.tsx
@@ -22,7 +22,7 @@ import CardMedia from '@material-ui/core/CardMedia';
import Typography from '@material-ui/core/Typography';
import React from 'react';
import { MemoryRouter } from 'react-router-dom';
-import { LinkButton } from '../../components';
+import { LinkButton } from '../../components/LinkButton/LinkButton';
import { ItemCardGrid } from './ItemCardGrid';
import { ItemCardHeader } from './ItemCardHeader';
diff --git a/packages/core-components/src/layout/ItemCard/ItemCard.tsx b/packages/core-components/src/layout/ItemCard/ItemCard.tsx
index 0b1ee34c0c..3d9963760b 100644
--- a/packages/core-components/src/layout/ItemCard/ItemCard.tsx
+++ b/packages/core-components/src/layout/ItemCard/ItemCard.tsx
@@ -21,7 +21,7 @@ import CardContent from '@material-ui/core/CardContent';
import CardMedia from '@material-ui/core/CardMedia';
import Chip from '@material-ui/core/Chip';
import React, { ReactNode } from 'react';
-import { LinkButton } from '../../components';
+import { LinkButton } from '../../components/LinkButton/LinkButton';
import { ItemCardHeader } from './ItemCardHeader';
type ItemCardProps = {
diff --git a/packages/core-components/src/layout/Sidebar/SidebarGroup.tsx b/packages/core-components/src/layout/Sidebar/SidebarGroup.tsx
index 1eb1423c61..1dd61d3170 100644
--- a/packages/core-components/src/layout/Sidebar/SidebarGroup.tsx
+++ b/packages/core-components/src/layout/Sidebar/SidebarGroup.tsx
@@ -22,7 +22,7 @@ import BottomNavigationAction, {
import { makeStyles } from '@material-ui/core/styles';
import React, { useContext } from 'react';
import { useLocation } from 'react-router-dom';
-import { Link } from '../../components';
+import { Link } from '../../components/Link/Link';
import { SidebarConfig, SidebarConfigContext } from './config';
import { MobileSidebarContext } from './MobileSidebar';
import { useSidebarPinState } from './SidebarPinStateContext';
diff --git a/packages/errors/api-report.md b/packages/errors/api-report.md
index 0d405d8ba6..3ece63035b 100644
--- a/packages/errors/api-report.md
+++ b/packages/errors/api-report.md
@@ -9,10 +9,16 @@ import { JsonObject } from '@backstage/types';
export function assertError(value: unknown): asserts value is ErrorLike;
// @public
-export class AuthenticationError extends CustomErrorBase {}
+export class AuthenticationError extends CustomErrorBase {
+ // (undocumented)
+ name: 'AuthenticationError';
+}
// @public
-export class ConflictError extends CustomErrorBase {}
+export class ConflictError extends CustomErrorBase {
+ // (undocumented)
+ name: 'ConflictError';
+}
// @public
export type ConsumedResponse = {
@@ -73,22 +79,37 @@ export class ForwardedError extends CustomErrorBase {
}
// @public
-export class InputError extends CustomErrorBase {}
+export class InputError extends CustomErrorBase {
+ // (undocumented)
+ name: 'InputError';
+}
// @public
export function isError(value: unknown): value is ErrorLike;
// @public
-export class NotAllowedError extends CustomErrorBase {}
+export class NotAllowedError extends CustomErrorBase {
+ // (undocumented)
+ name: 'NotAllowedError';
+}
// @public
-export class NotFoundError extends CustomErrorBase {}
+export class NotFoundError extends CustomErrorBase {
+ // (undocumented)
+ name: 'NotFoundError';
+}
// @public
-export class NotImplementedError extends CustomErrorBase {}
+export class NotImplementedError extends CustomErrorBase {
+ // (undocumented)
+ name: 'NotImplementedError';
+}
// @public
-export class NotModifiedError extends CustomErrorBase {}
+export class NotModifiedError extends CustomErrorBase {
+ // (undocumented)
+ name: 'NotModifiedError';
+}
// @public
export function parseErrorResponseBody(
diff --git a/packages/errors/src/errors/CustomErrorBase.ts b/packages/errors/src/errors/CustomErrorBase.ts
index b831d4eea3..ea9c91f173 100644
--- a/packages/errors/src/errors/CustomErrorBase.ts
+++ b/packages/errors/src/errors/CustomErrorBase.ts
@@ -22,8 +22,11 @@ import { isError } from './assertion';
*
* @public
* @example
- *```ts
- * class MyCustomError extends CustomErrorBase {}
+ *
+ * ```ts
+ * class MyCustomError extends CustomErrorBase {
+ * name = 'MyCustomError' as const;
+ * }
*
* const e = new MyCustomError('Some message', cause);
* // e.name === 'MyCustomError'
@@ -53,7 +56,13 @@ export class CustomErrorBase extends Error {
Error.captureStackTrace?.(this, this.constructor);
- this.name = this.constructor.name;
+ if (!this.name || this.name === 'Error') {
+ const baseName = this.constructor.name;
+ if (baseName !== 'Error') {
+ this.name = this.constructor.name;
+ }
+ }
+
this.cause = isError(cause) ? cause : undefined;
}
}
diff --git a/packages/errors/src/errors/common.ts b/packages/errors/src/errors/common.ts
index a2ea20e99f..861c3a7c3a 100644
--- a/packages/errors/src/errors/common.ts
+++ b/packages/errors/src/errors/common.ts
@@ -33,21 +33,27 @@ import { CustomErrorBase } from './CustomErrorBase';
*
* @public
*/
-export class InputError extends CustomErrorBase {}
+export class InputError extends CustomErrorBase {
+ name = 'InputError' as const;
+}
/**
* The request requires authentication, which was not properly supplied.
*
* @public
*/
-export class AuthenticationError extends CustomErrorBase {}
+export class AuthenticationError extends CustomErrorBase {
+ name = 'AuthenticationError' as const;
+}
/**
* The authenticated caller is not allowed to perform this request.
*
* @public
*/
-export class NotAllowedError extends CustomErrorBase {}
+export class NotAllowedError extends CustomErrorBase {
+ name = 'NotAllowedError' as const;
+}
/**
* The requested resource could not be found.
@@ -57,7 +63,9 @@ export class NotAllowedError extends CustomErrorBase {}
*
* @public
*/
-export class NotFoundError extends CustomErrorBase {}
+export class NotFoundError extends CustomErrorBase {
+ name = 'NotFoundError' as const;
+}
/**
* The request could not complete due to a conflict in the current state of the
@@ -65,21 +73,27 @@ export class NotFoundError extends CustomErrorBase {}
*
* @public
*/
-export class ConflictError extends CustomErrorBase {}
+export class ConflictError extends CustomErrorBase {
+ name = 'ConflictError' as const;
+}
/**
* The requested resource has not changed since last request.
*
* @public
*/
-export class NotModifiedError extends CustomErrorBase {}
+export class NotModifiedError extends CustomErrorBase {
+ name = 'NotModifiedError' as const;
+}
/**
* The server does not support the functionality required to fulfill the request.
*
* @public
*/
-export class NotImplementedError extends CustomErrorBase {}
+export class NotImplementedError extends CustomErrorBase {
+ name = 'NotImplementedError' as const;
+}
/**
* The server is not ready to handle the request.
diff --git a/plugins/catalog-backend-module-github/src/providers/GithubOrgEntityProvider.ts b/plugins/catalog-backend-module-github/src/providers/GithubOrgEntityProvider.ts
index c181510a67..bf82607c6b 100644
--- a/plugins/catalog-backend-module-github/src/providers/GithubOrgEntityProvider.ts
+++ b/plugins/catalog-backend-module-github/src/providers/GithubOrgEntityProvider.ts
@@ -28,48 +28,46 @@ import {
ScmIntegrations,
SingleInstanceGithubCredentialsProvider,
} from '@backstage/integration';
-import { EventParams } from '@backstage/plugin-events-node';
-import { EventSubscriber } from '@backstage/plugin-events-node';
import {
EntityProvider,
EntityProviderConnection,
} from '@backstage/plugin-catalog-node';
+import { EventParams, EventSubscriber } from '@backstage/plugin-events-node';
import { graphql } from '@octokit/graphql';
import {
+ MembershipEvent,
OrganizationEvent,
OrganizationMemberAddedEvent,
OrganizationMemberRemovedEvent,
- TeamEvent,
TeamEditedEvent,
- MembershipEvent,
+ TeamEvent,
} from '@octokit/webhooks-types';
import { merge } from 'lodash';
import * as uuid from 'uuid';
import { Logger } from 'winston';
-import {
- assignGroupsToUsers,
- buildOrgHierarchy,
- defaultOrganizationTeamTransformer,
- defaultUserTransformer,
- getOrganizationTeams,
- getOrganizationUsers,
- GithubTeam,
- parseGithubOrgUrl,
-} from '../lib';
-import { TeamTransformer, UserTransformer } from '../lib';
-import {
- createAddEntitiesOperation,
- createRemoveEntitiesOperation,
- createReplaceEntitiesOperation,
- DeferredEntitiesBuilder,
- getOrganizationTeam,
- getOrganizationTeamsFromUsers,
-} from '../lib/github';
import {
ANNOTATION_GITHUB_TEAM_SLUG,
ANNOTATION_GITHUB_USER_LOGIN,
} from '../lib/annotation';
-import { splitTeamSlug } from '../lib/util';
+import {
+ TeamTransformer,
+ UserTransformer,
+ defaultOrganizationTeamTransformer,
+ defaultUserTransformer,
+} from '../lib/defaultTransformers';
+import {
+ DeferredEntitiesBuilder,
+ GithubTeam,
+ createAddEntitiesOperation,
+ createRemoveEntitiesOperation,
+ createReplaceEntitiesOperation,
+ getOrganizationTeam,
+ getOrganizationTeams,
+ getOrganizationTeamsFromUsers,
+ getOrganizationUsers,
+} from '../lib/github';
+import { assignGroupsToUsers, buildOrgHierarchy } from '../lib/org';
+import { parseGithubOrgUrl, splitTeamSlug } from '../lib/util';
/**
* Options for {@link GithubOrgEntityProvider}.
diff --git a/plugins/catalog-backend-module-unprocessed/README.md b/plugins/catalog-backend-module-unprocessed/README.md
index dc5e830fa4..92d9e59445 100644
--- a/plugins/catalog-backend-module-unprocessed/README.md
+++ b/plugins/catalog-backend-module-unprocessed/README.md
@@ -1,4 +1,4 @@
-# @backstage/plugin-catalog-backend-module-unprocessed-node
+# @backstage/plugin-catalog-backend-module-unprocessed
This catalog-backend module adds support for viewing unprocessed entities. An unprocessed entity is one that doesn't show up in the catalog.
@@ -10,11 +10,15 @@ A `pending` entity has not been processed yet.
## Installation
+```shell
+yarn add --cwd packages/backend @backstage/plugin-catalog-backend-module-unprocessed
+```
+
### backend
In `packages/backend/src/plugins/catalog.ts` import the module and initialize it after invoking `CatalogBuilder.build()`:
-```ts
+```ts title="packages/backend/src/plugins/catalog.ts"
import { UnprocessedEntitesModule } from '@backstage/plugin-catalog-backend-module-unprocessed';
//...
@@ -22,7 +26,6 @@ import { UnprocessedEntitesModule } from '@backstage/plugin-catalog-backend-modu
const unprocessed = new UnprocessedEntitesModule(
await env.database.getClient(),
router,
- env.logger,
);
unprocessed.registerRoutes();
```
@@ -31,7 +34,7 @@ unprocessed.registerRoutes();
In `packages/backend-next/src/index.ts` add the module:
-```ts
+```ts title="packages/backend-next/src/index.ts"
backend.add(catalogModuleUnprocessedEntities());
```
diff --git a/plugins/catalog-backend/api-report.md b/plugins/catalog-backend/api-report.md
index 3e97442dd4..84d8de4753 100644
--- a/plugins/catalog-backend/api-report.md
+++ b/plugins/catalog-backend/api-report.md
@@ -410,12 +410,12 @@ export type PlaceholderProcessorOptions = {
integrations: ScmIntegrationRegistry;
};
-// @public (undocumented)
+// @public @deprecated (undocumented)
export type PlaceholderResolver = (
params: PlaceholderResolverParams,
) => Promise;
-// @public (undocumented)
+// @public @deprecated (undocumented)
export type PlaceholderResolverParams = {
key: string;
value: JsonValue;
@@ -425,10 +425,10 @@ export type PlaceholderResolverParams = {
emit: CatalogProcessorEmit_2;
};
-// @public (undocumented)
+// @public @deprecated (undocumented)
export type PlaceholderResolverRead = (url: string) => Promise;
-// @public (undocumented)
+// @public @deprecated (undocumented)
export type PlaceholderResolverResolveUrl = (
url: string,
base: string,
diff --git a/plugins/catalog-backend/src/modules/core/PlaceholderProcessor.ts b/plugins/catalog-backend/src/modules/core/PlaceholderProcessor.ts
index 79fcee960c..ee61e931e3 100644
--- a/plugins/catalog-backend/src/modules/core/PlaceholderProcessor.ts
+++ b/plugins/catalog-backend/src/modules/core/PlaceholderProcessor.ts
@@ -26,16 +26,25 @@ import {
processingResult,
} from '@backstage/plugin-catalog-node';
-/** @public */
+/**
+ * @public
+ * @deprecated Use the exported value from `@backstage/plugin-catalog-node` instead.
+ */
export type PlaceholderResolverRead = (url: string) => Promise;
-/** @public */
+/**
+ * @public
+ * @deprecated Use the exported value from `@backstage/plugin-catalog-node` instead.
+ */
export type PlaceholderResolverResolveUrl = (
url: string,
base: string,
) => string;
-/** @public */
+/**
+ * @public
+ * @deprecated Use the exported value from `@backstage/plugin-catalog-node` instead.
+ */
export type PlaceholderResolverParams = {
key: string;
value: JsonValue;
@@ -45,7 +54,10 @@ export type PlaceholderResolverParams = {
emit: CatalogProcessorEmit;
};
-/** @public */
+/**
+ * @public
+ * @deprecated Use the exported value from `@backstage/plugin-catalog-node` instead.
+ */
export type PlaceholderResolver = (
params: PlaceholderResolverParams,
) => Promise;
diff --git a/plugins/catalog-backend/src/service/CatalogPlugin.ts b/plugins/catalog-backend/src/service/CatalogPlugin.ts
index e0399c1683..d77b034517 100644
--- a/plugins/catalog-backend/src/service/CatalogPlugin.ts
+++ b/plugins/catalog-backend/src/service/CatalogPlugin.ts
@@ -27,10 +27,12 @@ import {
EntityProvider,
} from '@backstage/plugin-catalog-node';
import { loggerToWinstonLogger } from '@backstage/backend-common';
+import { PlaceholderResolver } from '../modules';
class CatalogExtensionPointImpl implements CatalogProcessingExtensionPoint {
#processors = new Array();
#entityProviders = new Array();
+ #placeholderResolvers: Record = {};
addProcessor(
...processors: Array>
@@ -44,6 +46,14 @@ class CatalogExtensionPointImpl implements CatalogProcessingExtensionPoint {
this.#entityProviders.push(...providers.flat());
}
+ addPlaceholderResolver(key: string, resolver: PlaceholderResolver) {
+ if (key in this.#placeholderResolvers)
+ throw new Error(
+ `A placeholder resolver for '${key}' has already been set up, please check your config.`,
+ );
+ this.#placeholderResolvers[key] = resolver;
+ }
+
get processors() {
return this.#processors;
}
@@ -51,6 +61,10 @@ class CatalogExtensionPointImpl implements CatalogProcessingExtensionPoint {
get entityProviders() {
return this.#entityProviders;
}
+
+ get placeholderResolvers() {
+ return this.#placeholderResolvers;
+ }
}
/**
@@ -99,6 +113,10 @@ export const catalogPlugin = createBackendPlugin({
});
builder.addProcessor(...processingExtensions.processors);
builder.addEntityProvider(...processingExtensions.entityProviders);
+ Object.entries(processingExtensions.placeholderResolvers).forEach(
+ ([key, resolver]) => builder.setPlaceholderResolver(key, resolver),
+ );
+
const { processingEngine, router } = await builder.build();
await processingEngine.start();
diff --git a/plugins/catalog-node/alpha-api-report.md b/plugins/catalog-node/alpha-api-report.md
index ba1bcd47b2..082228a58e 100644
--- a/plugins/catalog-node/alpha-api-report.md
+++ b/plugins/catalog-node/alpha-api-report.md
@@ -7,6 +7,7 @@ import { CatalogApi } from '@backstage/catalog-client';
import { CatalogProcessor } from '@backstage/plugin-catalog-node';
import { EntityProvider } from '@backstage/plugin-catalog-node';
import { ExtensionPoint } from '@backstage/backend-plugin-api';
+import { PlaceholderResolver } from '@backstage/plugin-catalog-node';
import { ServiceRef } from '@backstage/backend-plugin-api';
// @alpha (undocumented)
@@ -16,6 +17,8 @@ export interface CatalogProcessingExtensionPoint {
...providers: Array>
): void;
// (undocumented)
+ addPlaceholderResolver(key: string, resolver: PlaceholderResolver): void;
+ // (undocumented)
addProcessor(
...processors: Array>
): void;
diff --git a/plugins/catalog-node/api-report.md b/plugins/catalog-node/api-report.md
index 47a8e66ca9..34d7a4bc9b 100644
--- a/plugins/catalog-node/api-report.md
+++ b/plugins/catalog-node/api-report.md
@@ -152,6 +152,30 @@ export function locationSpecToLocationEntity(opts: {
// @public
export function locationSpecToMetadataName(location: LocationSpec_2): string;
+// @public (undocumented)
+export type PlaceholderResolver = (
+ params: PlaceholderResolverParams,
+) => Promise;
+
+// @public (undocumented)
+export type PlaceholderResolverParams = {
+ key: string;
+ value: JsonValue;
+ baseUrl: string;
+ read: PlaceholderResolverRead;
+ resolveUrl: PlaceholderResolverResolveUrl;
+ emit: CatalogProcessorEmit;
+};
+
+// @public (undocumented)
+export type PlaceholderResolverRead = (url: string) => Promise;
+
+// @public (undocumented)
+export type PlaceholderResolverResolveUrl = (
+ url: string,
+ base: string,
+) => string;
+
// @public
export const processingResult: Readonly<{
readonly notFoundError: (
diff --git a/plugins/catalog-node/src/extensions.ts b/plugins/catalog-node/src/extensions.ts
index 0466af36b0..5225ad7545 100644
--- a/plugins/catalog-node/src/extensions.ts
+++ b/plugins/catalog-node/src/extensions.ts
@@ -17,6 +17,7 @@ import { createExtensionPoint } from '@backstage/backend-plugin-api';
import {
EntityProvider,
CatalogProcessor,
+ PlaceholderResolver,
} from '@backstage/plugin-catalog-node';
/**
@@ -29,6 +30,7 @@ export interface CatalogProcessingExtensionPoint {
addEntityProvider(
...providers: Array>
): void;
+ addPlaceholderResolver(key: string, resolver: PlaceholderResolver): void;
}
/**
diff --git a/plugins/catalog-node/src/processing/index.ts b/plugins/catalog-node/src/processing/index.ts
index 90b87aa850..40cee63e25 100644
--- a/plugins/catalog-node/src/processing/index.ts
+++ b/plugins/catalog-node/src/processing/index.ts
@@ -14,4 +14,10 @@
* limitations under the License.
*/
-export type { DeferredEntity } from './types';
+export type {
+ DeferredEntity,
+ PlaceholderResolver,
+ PlaceholderResolverParams,
+ PlaceholderResolverRead,
+ PlaceholderResolverResolveUrl,
+} from './types';
diff --git a/plugins/catalog-node/src/processing/types.ts b/plugins/catalog-node/src/processing/types.ts
index 25e76faea3..b98e2da1b7 100644
--- a/plugins/catalog-node/src/processing/types.ts
+++ b/plugins/catalog-node/src/processing/types.ts
@@ -15,6 +15,8 @@
*/
import { Entity } from '@backstage/catalog-model';
+import { JsonValue } from '@backstage/types';
+import { CatalogProcessorEmit } from '../api';
/**
* Entities that are not yet processed.
@@ -24,3 +26,27 @@ export type DeferredEntity = {
entity: Entity;
locationKey?: string;
};
+
+/** @public */
+export type PlaceholderResolverRead = (url: string) => Promise;
+
+/** @public */
+export type PlaceholderResolverResolveUrl = (
+ url: string,
+ base: string,
+) => string;
+
+/** @public */
+export type PlaceholderResolverParams = {
+ key: string;
+ value: JsonValue;
+ baseUrl: string;
+ read: PlaceholderResolverRead;
+ resolveUrl: PlaceholderResolverResolveUrl;
+ emit: CatalogProcessorEmit;
+};
+
+/** @public */
+export type PlaceholderResolver = (
+ params: PlaceholderResolverParams,
+) => Promise;
diff --git a/plugins/catalog-unprocessed-entities/README.md b/plugins/catalog-unprocessed-entities/README.md
index fd824bec94..699629e0b2 100644
--- a/plugins/catalog-unprocessed-entities/README.md
+++ b/plugins/catalog-unprocessed-entities/README.md
@@ -1,16 +1,40 @@
-# catalog-unprocessed-entities
+# Catalog Unprocessed Entities
+
+## Features
Frontend plugin to view unprocessed entities.
+### Failed Entities
+
+You can see entities that are in a failed state:
+
+
+
+### Pending Entities
+
+You can see entities that are in a pending state:
+
+
+
+### Raw View
+
+In either of the failed or pending tabs you have the option to see the raw entity as JSON:
+
+
+
## Requirements
Requires the `@backstage/plugin-catalog-backend-module-unprocessed` module to be installed.
## Installation
-Import into your App.tsx and include into the `` component:
+```shell
+yarn add --cwd packages/backend @backstage/plugin-catalog-backend-module-unprocessed
+```
-```tsx
+Import into your `App.tsx` and include into the `` component:
+
+```tsx title="packages/app/src/App.tsx"
import { CatalogUnprocessedEntitiesPage } from '@backstage/plugin-catalog-unprocessed-entities';
//...
@@ -20,9 +44,44 @@ import { CatalogUnprocessedEntitiesPage } from '@backstage/plugin-catalog-unproc
/>;
```
+## Customization
+
+If you want to use the provided endpoints in a different way, you can use the ApiRef doing the following:
+
+```typescript
+import { catalogUnprocessedEntitiesApiRef } from '@backstage/plugin-catalog-unprocessed-entities';
+import { useApi } from '@backstage/core-plugin-api';
+
+const catalogUnprocessedEntitiesApi = useApi(catalogUnprocessedEntitiesApiRef);
+```
+
+Note that if you are not rendering the `CatalogUnprocessedEntitiesPage` in the `App.tsx` tree, you will need to export the `catalogUnproccessedEntitiesPlugin` from your `plugins.ts` file to setup the plugin otherwise you will receive an error like `No implementation available for apiRef{plugin.catalog-unprocessed-entities.service}`
+
+```typescript
+// In packages/app/src/plugins.ts
+...
+export { catalogUnprocessedEntitiesPlugin } from '@backstage/plugin-catalog-unprocessed-entities';
+```
+
+If you don't have a `plugins.ts` file, you can create it with the path `packages/app/src/plugins.ts` and then import it into your `App.tsx`:
+
+```diff
++ import * as plugins from './plugins';
+
+const app = createApp({
+ apis,
++ plugins: Object.values(plugins),
+ bindRoutes({ bind }) {
+ /* ... */
+ },
+});
+```
+
## Getting started
-Your plugin has been added to the example app in this repository, meaning you'll be able to access it by running `yarn start` in the root directory, and then navigating to [/catalog-unprocessed-entities](http://localhost:3000/catalog-unprocessed-entities).
+Your plugin has been added to the example app in this repository,
+meaning you'll be able to access it by running `yarn start` in the root directory,
+and then navigating to [/catalog-unprocessed-entities](http://localhost:3000/catalog-unprocessed-entities).
You can also serve the plugin in isolation by running `yarn start` in the plugin directory.
This method of serving the plugin provides quicker iteration speed and a faster startup and hot reloads.
diff --git a/plugins/catalog-unprocessed-entities/api-report.md b/plugins/catalog-unprocessed-entities/api-report.md
index b1e0d6f53d..0ccf9716f2 100644
--- a/plugins/catalog-unprocessed-entities/api-report.md
+++ b/plugins/catalog-unprocessed-entities/api-report.md
@@ -5,9 +5,25 @@
```ts
///
+import { ApiRef } from '@backstage/core-plugin-api';
import { BackstagePlugin } from '@backstage/core-plugin-api';
+import { Entity } from '@backstage/catalog-model';
import { RouteRef } from '@backstage/core-plugin-api';
+// @public
+export interface CatalogUnprocessedEntitiesApi {
+ failed(): Promise;
+ pending(): Promise;
+}
+
+// @public
+export const catalogUnprocessedEntitiesApiRef: ApiRef;
+
+// @public
+export type CatalogUnprocessedEntitiesApiResponse = {
+ entities: UnprocessedEntity[];
+};
+
// @public
export const CatalogUnprocessedEntitiesPage: () => JSX.Element;
@@ -20,5 +36,40 @@ export const catalogUnprocessedEntitiesPlugin: BackstagePlugin<
{}
>;
+// @public (undocumented)
+export const UnprocessedEntitiesContent: () => JSX.Element;
+
+// @public
+export type UnprocessedEntity = {
+ entity_id: string;
+ entity_ref: string;
+ unprocessed_entity: Entity;
+ unprocessed_hash?: string;
+ processed_entity?: Entity;
+ result_hash?: string;
+ cache?: UnprocessedEntityCache;
+ next_update_at: string | Date;
+ last_discovery_at: string | Date;
+ errors?: UnprocessedEntityError[];
+ location_key?: string;
+};
+
+// @public
+export type UnprocessedEntityCache = {
+ ttl: number;
+ cache: object;
+};
+
+// @public
+export type UnprocessedEntityError = {
+ name: string;
+ message: string;
+ cause: {
+ name: string;
+ message: string;
+ stack: string;
+ };
+};
+
// (No @packageDocumentation comment for this package)
```
diff --git a/plugins/catalog-unprocessed-entities/docs/catalog-unprocessed-entities-failed.png b/plugins/catalog-unprocessed-entities/docs/catalog-unprocessed-entities-failed.png
new file mode 100644
index 0000000000..9a65654630
Binary files /dev/null and b/plugins/catalog-unprocessed-entities/docs/catalog-unprocessed-entities-failed.png differ
diff --git a/plugins/catalog-unprocessed-entities/docs/catalog-unprocessed-entities-pending.png b/plugins/catalog-unprocessed-entities/docs/catalog-unprocessed-entities-pending.png
new file mode 100644
index 0000000000..d2924b0d7e
Binary files /dev/null and b/plugins/catalog-unprocessed-entities/docs/catalog-unprocessed-entities-pending.png differ
diff --git a/plugins/catalog-unprocessed-entities/docs/catalog-unprocessed-entities-raw.png b/plugins/catalog-unprocessed-entities/docs/catalog-unprocessed-entities-raw.png
new file mode 100644
index 0000000000..3b63b00cda
Binary files /dev/null and b/plugins/catalog-unprocessed-entities/docs/catalog-unprocessed-entities-raw.png differ
diff --git a/plugins/catalog-unprocessed-entities/package.json b/plugins/catalog-unprocessed-entities/package.json
index 2058da0d6c..0297220148 100644
--- a/plugins/catalog-unprocessed-entities/package.json
+++ b/plugins/catalog-unprocessed-entities/package.json
@@ -12,6 +12,12 @@
"backstage": {
"role": "frontend-plugin"
},
+ "homepage": "https://backstage.io",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/backstage/backstage",
+ "directory": "plugins/catalog-unprocessed-entities"
+ },
"scripts": {
"start": "backstage-cli package start",
"build": "backstage-cli package build",
diff --git a/plugins/catalog-unprocessed-entities/src/api/index.ts b/plugins/catalog-unprocessed-entities/src/api/index.ts
index 5be81c8331..92dde93a93 100644
--- a/plugins/catalog-unprocessed-entities/src/api/index.ts
+++ b/plugins/catalog-unprocessed-entities/src/api/index.ts
@@ -32,20 +32,43 @@ export const catalogUnprocessedEntitiesApiRef =
});
/**
- * API client for the Catalog Unprocessed Entities plugin
+ * Response expected by the {@link CatalogUnprocessedEntitiesApi}
*
* @public
*/
-export class CatalogUnprocessedEntitiesApi {
- url: string = '';
+export type CatalogUnprocessedEntitiesApiResponse = {
+ entities: UnprocessedEntity[];
+};
+/**
+ * Interface for the CatalogUnprocessedEntitiesApi.
+ *
+ * @public
+ */
+export interface CatalogUnprocessedEntitiesApi {
+ /**
+ * Returns a list of entities with state 'pending'
+ */
+ pending(): Promise;
+ /**
+ * Returns a list of entities with state 'failed'
+ */
+ failed(): Promise;
+}
+
+/**
+ * Default API implementation for the Catalog Unprocessed Entities plugin
+ *
+ * @public
+ */
+export class CatalogUnprocessedEntitiesClient
+ implements CatalogUnprocessedEntitiesApi
+{
constructor(public discovery: DiscoveryApi, public fetchApi: FetchApi) {}
private async fetch(path: string, init?: RequestInit): Promise {
- if (!this.url) {
- this.url = await this.discovery.getBaseUrl('catalog');
- }
- const resp = await this.fetchApi.fetch(`${this.url}/${path}`, init);
+ const url = await this.discovery.getBaseUrl('catalog');
+ const resp = await this.fetchApi.fetch(`${url}/${path}`, init);
if (!resp.ok) {
throw await ResponseError.fromResponse(resp);
}
@@ -53,11 +76,11 @@ export class CatalogUnprocessedEntitiesApi {
return await resp.json();
}
- async pending(): Promise<{ entities: UnprocessedEntity[] }> {
+ async pending(): Promise {
return await this.fetch('entities/unprocessed/pending');
}
- async failed(): Promise<{ entities: UnprocessedEntity[] }> {
+ async failed(): Promise {
return await this.fetch('entities/unprocessed/failed');
}
}
diff --git a/plugins/catalog-unprocessed-entities/src/components/FailedEntities.tsx b/plugins/catalog-unprocessed-entities/src/components/FailedEntities.tsx
index 44a146f027..662c5c9db6 100644
--- a/plugins/catalog-unprocessed-entities/src/components/FailedEntities.tsx
+++ b/plugins/catalog-unprocessed-entities/src/components/FailedEntities.tsx
@@ -126,7 +126,7 @@ export const FailedEntities = () => {
return (
<>