From 040b54f7e58f4d9dce4ea55fce461c7ff5b6c7d5 Mon Sep 17 00:00:00 2001 From: Paul Schultz Date: Wed, 8 Mar 2023 10:13:38 -0600 Subject: [PATCH] clean up formatting Signed-off-by: Paul Schultz --- docs/auth/cloudflare/access.md | 2 +- docs/auth/google/gcp-iap-auth.md | 4 +- docs/auth/index.md | 17 +- docs/auth/microsoft/azure-easyauth.md | 6 +- docs/auth/oauth2-proxy/provider.md | 6 +- docs/auth/oidc.md | 33 ++-- .../building-backends/08-migrating.md | 33 ++-- docs/features/kubernetes/installation.md | 2 +- docs/features/search/how-to-guides.md | 86 ++++----- .../software-catalog/external-integrations.md | 4 +- .../testing-scaffolder-alpha.md | 61 +++---- docs/getting-started/app-custom-theme.md | 150 +++++++-------- .../configure-app-with-plugins.md | 36 ++-- docs/getting-started/homepage.md | 6 +- docs/integrations/azure/discovery.md | 6 +- docs/integrations/azure/org.md | 4 +- docs/integrations/bitbucketCloud/discovery.md | 4 +- docs/integrations/github/discovery.md | 20 +- docs/integrations/github/org.md | 2 +- docs/integrations/gitlab/discovery.md | 2 +- docs/permissions/getting-started.md | 172 +++++++++--------- docs/permissions/plugin-authors/01-setup.md | 152 ++++++++-------- .../03-adding-a-resource-permission-check.md | 10 +- ...04-authorizing-access-to-paginated-data.md | 18 +- .../05-frontend-authorization.md | 18 +- .../react-router-stable-migration.md | 12 +- 26 files changed, 449 insertions(+), 417 deletions(-) diff --git a/docs/auth/cloudflare/access.md b/docs/auth/cloudflare/access.md index 05663aca30..51567e9a0f 100644 --- a/docs/auth/cloudflare/access.md +++ b/docs/auth/cloudflare/access.md @@ -100,7 +100,7 @@ const app = createApp({ }, /* highlight-add-end */ // .. -}) +}); ``` See [Sign-In with Proxy Providers](../index.md#sign-in-with-proxy-providers) for pointers on how to set up the sign-in page to also work smoothly for local development. diff --git a/docs/auth/google/gcp-iap-auth.md b/docs/auth/google/gcp-iap-auth.md index 138d795f0f..410008b22e 100644 --- a/docs/auth/google/gcp-iap-auth.md +++ b/docs/auth/google/gcp-iap-auth.md @@ -104,13 +104,13 @@ installed in `packages/app/src/App.tsx` like this: import { ProxiedSignInPage } from '@backstage/core-components'; const app = createApp({ - /* highlight-add-start */ + /* highlight-add-start */ components: { SignInPage: props => , }, /* highlight-add-end */ // .. -}) +}); ``` See the [Sign-In with Proxy Providers](../index.md#sign-in-with-proxy-providers) section for more information. diff --git a/docs/auth/index.md b/docs/auth/index.md index 7f4511af24..abe7fb8db6 100644 --- a/docs/auth/index.md +++ b/docs/auth/index.md @@ -121,12 +121,15 @@ const app = createApp({ SignInPage: props => ( ), }, @@ -314,7 +317,7 @@ import { export const apis: AnyApiFactory[] = [ /* highlight-add-next-line */ ScmAuth.createDefaultApiFactory(), - // ... + // ... ]; ``` diff --git a/docs/auth/microsoft/azure-easyauth.md b/docs/auth/microsoft/azure-easyauth.md index fb0b897760..4daf0851f0 100644 --- a/docs/auth/microsoft/azure-easyauth.md +++ b/docs/auth/microsoft/azure-easyauth.md @@ -67,11 +67,13 @@ import { ProxiedSignInPage } from '@backstage/core-components'; const app = createApp({ /* highlight-add-start */ components: { - SignInPage: props => , + SignInPage: props => ( + + ), }, /* highlight-add-end */ // .. -}) +}); ``` See the [Sign-In with Proxy Providers](../index.md#sign-in-with-proxy-providers) section for more information. diff --git a/docs/auth/oauth2-proxy/provider.md b/docs/auth/oauth2-proxy/provider.md index e3b5e89633..9c8f681138 100644 --- a/docs/auth/oauth2-proxy/provider.md +++ b/docs/auth/oauth2-proxy/provider.md @@ -70,11 +70,13 @@ import { ProxiedSignInPage } from '@backstage/core-components'; const app = createApp({ /* highlight-add-start */ components: { - SignInPage: props => , + SignInPage: props => ( + + ), }, /* highlight-add-end */ // .. -}) +}); ``` See [Sign-In with Proxy Providers](../index.md#sign-in-with-proxy-providers) for pointers on how to set up the sign-in page to also work smoothly for local development. diff --git a/docs/auth/oidc.md b/docs/auth/oidc.md index 0a9e4417ed..9c681b7360 100644 --- a/docs/auth/oidc.md +++ b/docs/auth/oidc.md @@ -89,28 +89,23 @@ export const apis: AnyApiFactory[] = [ discoveryApi: discoveryApiRef, oauthRequestApi: oauthRequestApiRef, configApi: configApiRef, - }, - factory: ({ discoveryApi, oauthRequestApi, configApi }) => - OAuth2.create({ - discoveryApi, - oauthRequestApi, - provider: { - id: 'my-auth-provider', - title: 'My custom auth provider', - icon: () => null, - }, - environment: configApi.getOptionalString('auth.environment'), - defaultScopes: [ - 'openid', - 'profile', - 'email', - ], - }), + }, + factory: ({ discoveryApi, oauthRequestApi, configApi }) => + OAuth2.create({ + discoveryApi, + oauthRequestApi, + provider: { + id: 'my-auth-provider', + title: 'My custom auth provider', + icon: () => null, + }, + environment: configApi.getOptionalString('auth.environment'), + defaultScopes: ['openid', 'profile', 'email'], + }), }), /* highlight-add-end */ // .. -] - +]; ``` Please note we're importing the `OAuth2` class from `@backstage/core-app-api` effectively diff --git a/docs/backend-system/building-backends/08-migrating.md b/docs/backend-system/building-backends/08-migrating.md index 358b6ae764..b4005b41b4 100644 --- a/docs/backend-system/building-backends/08-migrating.md +++ b/docs/backend-system/building-backends/08-migrating.md @@ -134,7 +134,10 @@ import { createBackend } from '@backstage/backend-defaults'; /* highlight-remove-next-line */ import { legacyPlugin } from '@backstage/backend-common'; /* highlight-add-start */ -import { makeLegacyPlugin, loggerToWinstonLogger } from '@backstage/backend-common'; +import { + makeLegacyPlugin, + loggerToWinstonLogger, +} from '@backstage/backend-common'; import { coreServices } from '@backstage/backend-plugin-api'; /* highlight-add-end */ @@ -187,16 +190,16 @@ In this example, we'll assume that your added environment field is named /* highlight-add-next-line */ import { exampleServiceRef } from ''; // if the definition is elsewhere - const legacyPlugin = makeLegacyPlugin( - { - // ... the above core services still go here - /* highlight-add-next-line */ - example: exampleServiceRef - }, - { - logger: log => loggerToWinstonLogger(log), - }, - ); +const legacyPlugin = makeLegacyPlugin( + { + // ... the above core services still go here + /* highlight-add-next-line */ + example: exampleServiceRef, + }, + { + logger: log => loggerToWinstonLogger(log), + }, +); ``` After this, your backend will know how to instantiate your thing on demand and @@ -282,7 +285,7 @@ import { createBackendModule } from '@backstage/backend-plugin-api'; /* highlight-add-start */ const catalogModuleCustomExtensions = createBackendModule({ - pluginId: 'catalog', // name of the plugin that the module is targeting + pluginId: 'catalog', // name of the plugin that the module is targeting moduleId: 'customExtensions', register(env) { env.registerInit({ @@ -294,7 +297,7 @@ const catalogModuleCustomExtensions = createBackendModule({ // Here you have the opportunity to interact with the extension // point before the plugin itself gets instantiated catalog.addEntityProvider(new MyEntityProvider()); // just an example - catalog.addProcessor(new MyProcessor()); // just an example + catalog.addProcessor(new MyProcessor()); // just an example }, }); }, @@ -352,7 +355,7 @@ import { createBackendModule } from '@backstage/backend-plugin-api'; /* highlight-add-start */ const eventsModuleCustomExtensions = createBackendModule({ - pluginId: 'events', // name of the plugin that the module is targeting + pluginId: 'events', // name of the plugin that the module is targeting moduleId: 'customExtensions', register(env) { env.registerInit({ @@ -420,7 +423,7 @@ import { createBackendModule } from '@backstage/backend-plugin-api'; /* highlight-add-start */ const scaffolderModuleCustomExtensions = createBackendModule({ - pluginId: 'scaffolder', // name of the plugin that the module is targeting + pluginId: 'scaffolder', // name of the plugin that the module is targeting moduleId: 'customExtensions', register(env) { env.registerInit({ diff --git a/docs/features/kubernetes/installation.md b/docs/features/kubernetes/installation.md index abc42ddbe0..ae7826a804 100644 --- a/docs/features/kubernetes/installation.md +++ b/docs/features/kubernetes/installation.md @@ -38,7 +38,7 @@ const serviceEntityPage = ( {/* highlight-add-end */} -) +); ``` **Notes:** diff --git a/docs/features/search/how-to-guides.md b/docs/features/search/how-to-guides.md index 7a00d10ede..5b28e259b5 100644 --- a/docs/features/search/how-to-guides.md +++ b/docs/features/search/how-to-guides.md @@ -20,30 +20,30 @@ to do that in two steps. [interface](https://github.com/backstage/backstage/blob/db2666b980853c281b8fe77905d7639c5d255f13/plugins/search/src/apis.ts#L31) according to your needs. - ```typescript - export class SearchClient implements SearchApi { - // your implementation - } - ``` + ```typescript + export class SearchClient implements SearchApi { + // your implementation + } + ``` 2. Override the API ref `searchApiRef` with your new implemented API in the `App.tsx` using `ApiFactories`. [Read more about App APIs](https://backstage.io/docs/api/utility-apis#app-apis). - ```typescript - const app = createApp({ - apis: [ - // SearchApi - createApiFactory({ - api: searchApiRef, - deps: { discovery: discoveryApiRef }, - factory({ discovery }) { - return new SearchClient({ discoveryApi: discovery }); - }, - }), - ], - }); - ``` + ```typescript + const app = createApp({ + apis: [ + // SearchApi + createApiFactory({ + api: searchApiRef, + deps: { discovery: discoveryApiRef }, + factory({ discovery }) { + return new SearchClient({ discoveryApi: discovery }); + }, + }), + ], + }); + ``` ## How to index TechDocs documents @@ -63,35 +63,35 @@ getting started guide. 1. Import the `DefaultTechDocsCollatorFactory` from `@backstage/plugin-techdocs-backend`. - ```typescript - import { DefaultTechDocsCollatorFactory } from '@backstage/plugin-techdocs-backend'; - ``` + ```typescript + import { DefaultTechDocsCollatorFactory } from '@backstage/plugin-techdocs-backend'; + ``` 2. If there isn't an existing schedule you'd like to run the collator on, be sure to create it first. Something like... - ```typescript - import { Duration } from 'luxon'; + ```typescript + import { Duration } from 'luxon'; - const every10MinutesSchedule = env.scheduler.createScheduledTaskRunner({ - frequency: Duration.fromObject({ seconds: 600 }), - timeout: Duration.fromObject({ seconds: 900 }), - initialDelay: Duration.fromObject({ seconds: 3 }), - }); - ``` + const every10MinutesSchedule = env.scheduler.createScheduledTaskRunner({ + frequency: Duration.fromObject({ seconds: 600 }), + timeout: Duration.fromObject({ seconds: 900 }), + initialDelay: Duration.fromObject({ seconds: 3 }), + }); + ``` 3. Register the `DefaultTechDocsCollatorFactory` with the IndexBuilder. - ```typescript - indexBuilder.addCollator({ - schedule: every10MinutesSchedule, - factory: DefaultTechDocsCollatorFactory.fromConfig(env.config, { - discovery: env.discovery, - logger: env.logger, - tokenManager: env.tokenManager, - }), - }); - ``` + ```typescript + indexBuilder.addCollator({ + schedule: every10MinutesSchedule, + factory: DefaultTechDocsCollatorFactory.fromConfig(env.config, { + discovery: env.discovery, + logger: env.logger, + tokenManager: env.tokenManager, + }), + }); + ``` You should now have your TechDocs documents indexed to your search engine of choice! @@ -125,7 +125,9 @@ You can either just simply amend default behaviour, or even to write completely > `authorization` and `location` cannot be modified via a `entityTransformer`, `location` can be modified only through `locationTemplate`. ```ts title="packages/backend/src/plugins/search.ts" -const entityTransformer: CatalogCollatorEntityTransformer = (entity: Entity) => { +const entityTransformer: CatalogCollatorEntityTransformer = ( + entity: Entity, +) => { if (entity.kind === 'SomeKind') { return { // customize here output for 'SomeKind' kind @@ -173,7 +175,7 @@ indexBuilder.addCollator({ tokenManager: env.tokenManager, /* highlight-add-start */ filter: { - kind: ['API', 'Component', 'Domain', 'Group', 'System', 'User'], + kind: ['API', 'Component', 'Domain', 'Group', 'System', 'User'], }, /* highlight-add-end */ }), diff --git a/docs/features/software-catalog/external-integrations.md b/docs/features/software-catalog/external-integrations.md index d8e4c2099a..6f957625bd 100644 --- a/docs/features/software-catalog/external-integrations.md +++ b/docs/features/software-catalog/external-integrations.md @@ -254,7 +254,9 @@ export default async function createPlugin( /* highlight-add-start */ await env.scheduler.scheduleTask({ id: 'run_frobs_refresh', - fn: async () => { await frobs.run(); }, + fn: async () => { + await frobs.run(); + }, frequency: { minutes: 30 }, timeout: { minutes: 10 }, }); diff --git a/docs/features/software-templates/testing-scaffolder-alpha.md b/docs/features/software-templates/testing-scaffolder-alpha.md index 1791ab0822..c0b97e897c 100644 --- a/docs/features/software-templates/testing-scaffolder-alpha.md +++ b/docs/features/software-templates/testing-scaffolder-alpha.md @@ -46,7 +46,6 @@ The `ScaffolderPage` router has a completely different export for the `scaffolde import { ScaffolderPage } from '@backstage/plugin-scaffolder'; /* highlight-add-next-line */ import { NextScaffolderPage } from '@backstage/plugin-scaffolder/alpha'; - ``` And this API should be the exact same as the previous Router, so you should be able to make a change like the following further down in this file: @@ -136,7 +135,7 @@ export const EntityNamePicker = ( placeholder, } = props; // .. -} +}; ``` There's another `/alpha` export that you need to replace `FieldExtensionComponentProps` with which is the `NextFieldExtensionComponentProps`. @@ -167,7 +166,7 @@ export const EntityNamePicker = ( placeholder, } = props; // .. -} +}; ``` You'll notice that there's an additional change here, which is that we're now defaulting the `uiSchema` to an empty object. This is because the `uiSchema` is now optional, and if you don't provide it, it will be `undefined` instead of an empty object. There's more around this in the [breaking changes](#breaking-changes) section. @@ -218,20 +217,20 @@ Once we fully release the code that is in the `/alpha` exports right now onto th Later releases of `react-jsonschema-form` have made the `uiSchema` optional, and if you don't provide it, it will be `undefined` instead of an empty object. This means that you will need to make sure that you're defaulting the `uiSchema` to an empty object if you're using it in your code. ```tsx - const { - onChange, - required, - schema: { title = 'Name', description = 'Unique name of the component' }, - rawErrors, - formData, - /* highlight-remove-next-line */ - uiSchema: { 'ui:autofocus': autoFocus }, - /* highlight-add-next-line */ - uiSchema: { 'ui:autofocus': autoFocus } = {}, - idSchema, - placeholder, - } = props; - // .. +const { + onChange, + required, + schema: { title = 'Name', description = 'Unique name of the component' }, + rawErrors, + formData, + /* highlight-remove-next-line */ + uiSchema: { 'ui:autofocus': autoFocus }, + /* highlight-add-next-line */ + uiSchema: { 'ui:autofocus': autoFocus } = {}, + idSchema, + placeholder, +} = props; +// .. ``` ### `formData` can also be `undefined` @@ -239,18 +238,18 @@ Later releases of `react-jsonschema-form` have made the `uiSchema` optional, and If you were using the `formData` and assuming that it was set to an empty object when building `Field Extensions` that return objects, then this will be `undefined` now due to a change in the `react-jsonschema-form` library. ```tsx - const { - onChange, - required, - schema: { title = 'Name', description = 'Unique name of the component' }, - rawErrors, - /* highlight-remove-next-line */ - formData, - /* highlight-add-next-line */ - formData = {}, // or maybe some other default value that you would prefer - uiSchema: { 'ui:autofocus': autoFocus } = {}, - idSchema, - placeholder, - } = props; - // .. +const { + onChange, + required, + schema: { title = 'Name', description = 'Unique name of the component' }, + rawErrors, + /* highlight-remove-next-line */ + formData, + /* highlight-add-next-line */ + formData = {}, // or maybe some other default value that you would prefer + uiSchema: { 'ui:autofocus': autoFocus } = {}, + idSchema, + placeholder, +} = props; +// .. ``` diff --git a/docs/getting-started/app-custom-theme.md b/docs/getting-started/app-custom-theme.md index fcb27c220d..697c58ac8f 100644 --- a/docs/getting-started/app-custom-theme.md +++ b/docs/getting-started/app-custom-theme.md @@ -346,19 +346,19 @@ You can add more icons, if the [default icons](https://github.com/backstage/back 2. Then you want to import your icon, add this to the rest of your imports: `import AlarmIcon from '@material-ui/icons/Alarm';` 3. Next you want to add the icon like this to your `createApp`: - ```tsx title="packages/app/src/App.tsx" - const app = createApp({ - apis: ..., - plugins: ..., - /* highlight-add-start */ - icons: { - alert: AlarmIcon, - }, - /* highlight-add-end */ - themes: ..., - components: ..., - }); - ``` + ```tsx title="packages/app/src/App.tsx" + const app = createApp({ + apis: ..., + plugins: ..., + /* highlight-add-start */ + icons: { + alert: AlarmIcon, + }, + /* highlight-add-end */ + themes: ..., + components: ..., + }); + ``` 4. Now we can reference `alert` for our icon in our entity links like this: @@ -413,71 +413,71 @@ For this example we'll show you how you can expand the sidebar with a sub-menu: 3. Then update the `@backstage/core-components` import like this: - ```tsx - import { - Sidebar, - sidebarConfig, - SidebarDivider, - SidebarGroup, - SidebarItem, - SidebarPage, - SidebarScrollWrapper, - SidebarSpace, - useSidebarOpenState, - Link, - /* highlight-add-start */ - GroupIcon, - SidebarSubmenu, - SidebarSubmenuItem, - /* highlight-add-end */ - } from '@backstage/core-components'; - ``` + ```tsx + import { + Sidebar, + sidebarConfig, + SidebarDivider, + SidebarGroup, + SidebarItem, + SidebarPage, + SidebarScrollWrapper, + SidebarSpace, + useSidebarOpenState, + Link, + /* highlight-add-start */ + GroupIcon, + SidebarSubmenu, + SidebarSubmenuItem, + /* highlight-add-end */ + } from '@backstage/core-components'; + ``` 4. Finally replace `` with this: - ```tsx - - - - - - - - - - - - - - ``` + ```tsx + + + + + + + + + + + + + + ``` When you startup your Backstage app and hover over the Home option on the sidebar you'll now see a nice sub-menu appear with links to the various Kinds in your Catalog. It would look like this: diff --git a/docs/getting-started/configure-app-with-plugins.md b/docs/getting-started/configure-app-with-plugins.md index 54654366d8..e0c698d3a1 100644 --- a/docs/getting-started/configure-app-with-plugins.md +++ b/docs/getting-started/configure-app-with-plugins.md @@ -33,25 +33,25 @@ to an entity in the software catalog. 2. Add the `EntityCircleCIContent` extension to the entity pages in the app: - ```tsx title="packages/app/src/components/catalog/EntityPage.tsx" - /* highlight-add-start */ - import { - EntityCircleCIContent, - isCircleCIAvailable, - } from '@backstage/plugin-circleci'; - /* highlight-add-end */ + ```tsx title="packages/app/src/components/catalog/EntityPage.tsx" + /* highlight-add-start */ + import { + EntityCircleCIContent, + isCircleCIAvailable, + } from '@backstage/plugin-circleci'; + /* highlight-add-end */ - const cicdContent = ( - - {/* ... */} - {/* highlight-add-next-line */} - - - ; - {/* highlight-add-end */} - - ); - ``` + const cicdContent = ( + + {/* ... */} + {/* highlight-add-next-line */} + + + + ;{/* highlight-add-end */} + + ); + ``` This is just one example, but each Backstage instance may integrate content or cards to suit their needs on different pages, tabs, etc. In addition, while some diff --git a/docs/getting-started/homepage.md b/docs/getting-started/homepage.md index 29b427bad8..63a97ec54f 100644 --- a/docs/getting-started/homepage.md +++ b/docs/getting-started/homepage.md @@ -58,7 +58,7 @@ const routes = ( {/* ... */} -) +); ``` Let's replace the `` line and use the new component we created in the previous step as the new homepage. @@ -80,7 +80,7 @@ const routes = ( {/* highlight-add-end */} {/* ... */} -) +); ``` #### 4. Update sidebar items @@ -122,7 +122,7 @@ export const Root = ({ children }: PropsWithChildren<{}>) => ( -) +); ``` That's it! You should now have _(although slightly boring)_ a homepage! diff --git a/docs/integrations/azure/discovery.md b/docs/integrations/azure/discovery.md index d4ded290c3..d1309a80eb 100644 --- a/docs/integrations/azure/discovery.md +++ b/docs/integrations/azure/discovery.md @@ -128,7 +128,11 @@ export default async function createPlugin( ): Promise { const builder = await CatalogBuilder.create(env); /* highlight-add-next-line */ - builder.addProcessor(AzureDevOpsDiscoveryProcessor.fromConfig(env.config, { logger: env.logger })); + builder.addProcessor( + AzureDevOpsDiscoveryProcessor.fromConfig(env.config, { + logger: env.logger, + }), + ); // .. } diff --git a/docs/integrations/azure/org.md b/docs/integrations/azure/org.md index 403f0042a9..f855b29bb9 100644 --- a/docs/integrations/azure/org.md +++ b/docs/integrations/azure/org.md @@ -44,7 +44,7 @@ For large organizations, this plugin can take a long time, so be careful setting import { MicrosoftGraphOrgEntityProvider } from '@backstage/plugin-catalog-backend-module-msgraph'; export default async function createPlugin( - env: PluginEnvironment, + env: PluginEnvironment, ): Promise { const builder = await CatalogBuilder.create(env); @@ -55,7 +55,7 @@ export default async function createPlugin( schedule: env.scheduler.createScheduledTaskRunner({ frequency: { hours: 1 }, timeout: { minutes: 50 }, - initialDelay: { seconds: 15} + initialDelay: { seconds: 15 }, }), }), ); diff --git a/docs/integrations/bitbucketCloud/discovery.md b/docs/integrations/bitbucketCloud/discovery.md index 7074fcac1b..c5a7eee4a0 100644 --- a/docs/integrations/bitbucketCloud/discovery.md +++ b/docs/integrations/bitbucketCloud/discovery.md @@ -105,8 +105,8 @@ export default async function createCatalogEventBasedProviders( }), ); /* highlight-add-end */ - return providers.flat(); - } + return providers.flat(); +} ``` **Attention:** diff --git a/docs/integrations/github/discovery.md b/docs/integrations/github/discovery.md index 499cb32812..fb65173b28 100644 --- a/docs/integrations/github/discovery.md +++ b/docs/integrations/github/discovery.md @@ -44,7 +44,7 @@ export default async function createPlugin( schedule: env.scheduler.createScheduledTaskRunner({ frequency: { minutes: 30 }, timeout: { minutes: 3 }, - }), + }), // optional: alternatively, use schedule scheduler: env.scheduler, }), @@ -88,14 +88,14 @@ export default async function createCatalogEventBasedProviders( /* highlight-add-start */ providers.push( GithubEntityProvider.fromConfig(env.config, { - logger: env.logger, - // optional: alternatively, use scheduler with schedule defined in app-config.yaml - schedule: env.scheduler.createScheduledTaskRunner({ - frequency: { minutes: 30 }, - timeout: { minutes: 3 }, - }), - // optional: alternatively, use schedule - scheduler: env.scheduler, + logger: env.logger, + // optional: alternatively, use scheduler with schedule defined in app-config.yaml + schedule: env.scheduler.createScheduledTaskRunner({ + frequency: { minutes: 30 }, + timeout: { minutes: 3 }, + }), + // optional: alternatively, use schedule + scheduler: env.scheduler, }), ); /* highlight-add-end */ @@ -269,7 +269,7 @@ import { } from '@backstage/plugin-catalog-backend-module-github'; import { ScmIntegrations, - DefaultGithubCredentialsProvider + DefaultGithubCredentialsProvider, } from '@backstage/integration'; /* highlight-add-end */ diff --git a/docs/integrations/github/org.md b/docs/integrations/github/org.md index 4600d65466..8f67e2a43f 100644 --- a/docs/integrations/github/org.md +++ b/docs/integrations/github/org.md @@ -88,7 +88,7 @@ import { PluginEnvironment } from '../types'; export default async function createCatalogEventBasedProviders( /* highlight-remove-next-line */ _: PluginEnvironment, - /* highlight-add-next-line */ + /* highlight-add-next-line */ env: PluginEnvironment, ): Promise> { const providers: Array< diff --git a/docs/integrations/gitlab/discovery.md b/docs/integrations/gitlab/discovery.md index 8c95243b04..6d0bb7e2e2 100644 --- a/docs/integrations/gitlab/discovery.md +++ b/docs/integrations/gitlab/discovery.md @@ -99,7 +99,7 @@ export default async function createPlugin( const builder = await CatalogBuilder.create(env); /* highlight-add-start */ builder.addProcessor( - GitLabDiscoveryProcessor.fromConfig(env.config, { logger: env.logger }) + GitLabDiscoveryProcessor.fromConfig(env.config, { logger: env.logger }), ); /* highlight-add-end */ diff --git a/docs/permissions/getting-started.md b/docs/permissions/getting-started.md index bb6c9a558e..8cb6dd953e 100644 --- a/docs/permissions/getting-started.md +++ b/docs/permissions/getting-started.md @@ -46,67 +46,67 @@ The permissions framework uses a new `permission-backend` plugin to accept autho 1. Add `@backstage/plugin-permission-backend` as a dependency of your Backstage backend: - ```bash - # From your Backstage root directory - $ yarn add --cwd packages/backend @backstage/plugin-permission-backend - ``` + ```bash + # From your Backstage root directory + $ yarn add --cwd packages/backend @backstage/plugin-permission-backend + ``` 2. Add the following to a new file, `packages/backend/src/plugins/permission.ts`. This adds the permission-backend router, and configures it with a policy which allows everything. - ```typescript title="packages/backend/src/plugins/permission.ts" - import { createRouter } from '@backstage/plugin-permission-backend'; - import { - AuthorizeResult, - PolicyDecision, - } from '@backstage/plugin-permission-common'; - import { PermissionPolicy } from '@backstage/plugin-permission-node'; - import { Router } from 'express'; - import { PluginEnvironment } from '../types'; + ```typescript title="packages/backend/src/plugins/permission.ts" + import { createRouter } from '@backstage/plugin-permission-backend'; + import { + AuthorizeResult, + PolicyDecision, + } from '@backstage/plugin-permission-common'; + import { PermissionPolicy } from '@backstage/plugin-permission-node'; + import { Router } from 'express'; + import { PluginEnvironment } from '../types'; - class TestPermissionPolicy implements PermissionPolicy { - async handle(): Promise { - return { result: AuthorizeResult.ALLOW }; - } - } + class TestPermissionPolicy implements PermissionPolicy { + async handle(): Promise { + return { result: AuthorizeResult.ALLOW }; + } + } - export default async function createPlugin( - env: PluginEnvironment, - ): Promise { - return await createRouter({ - config: env.config, - logger: env.logger, - discovery: env.discovery, - policy: new TestPermissionPolicy(), - identity: env.identity, - }); - } - ``` + export default async function createPlugin( + env: PluginEnvironment, + ): Promise { + return await createRouter({ + config: env.config, + logger: env.logger, + discovery: env.discovery, + policy: new TestPermissionPolicy(), + identity: env.identity, + }); + } + ``` 3. Wire up the permission policy in `packages/backend/src/index.ts`. [The index in the example backend](https://github.com/backstage/backstage/blob/master/packages/backend/src/index.ts) shows how to do this. You’ll need to import the module from the previous step, create a plugin environment, and add the router to the express app: - ```ts title="packages/backend/src/index.ts" - import proxy from './plugins/proxy'; - import techdocs from './plugins/techdocs'; - import search from './plugins/search'; - /* highlight-add-next-line */ - import permission from './plugins/permission'; + ```ts title="packages/backend/src/index.ts" + import proxy from './plugins/proxy'; + import techdocs from './plugins/techdocs'; + import search from './plugins/search'; + /* highlight-add-next-line */ + import permission from './plugins/permission'; - async function main() { - const techdocsEnv = useHotMemoize(module, () => createEnv('techdocs')); - const searchEnv = useHotMemoize(module, () => createEnv('search')); - const appEnv = useHotMemoize(module, () => createEnv('app')); - /* highlight-add-next-line */ - const permissionEnv = useHotMemoize(module, () => createEnv('permission')); - // .. + async function main() { + const techdocsEnv = useHotMemoize(module, () => createEnv('techdocs')); + const searchEnv = useHotMemoize(module, () => createEnv('search')); + const appEnv = useHotMemoize(module, () => createEnv('app')); + /* highlight-add-next-line */ + const permissionEnv = useHotMemoize(module, () => createEnv('permission')); + // .. - apiRouter.use('/techdocs', await techdocs(techdocsEnv)); - apiRouter.use('/proxy', await proxy(proxyEnv)); - apiRouter.use('/search', await search(searchEnv)); - /* highlight-add-next-line */ - apiRouter.use('/permission', await permission(permissionEnv)); - // .. - } - ``` + apiRouter.use('/techdocs', await techdocs(techdocsEnv)); + apiRouter.use('/proxy', await proxy(proxyEnv)); + apiRouter.use('/search', await search(searchEnv)); + /* highlight-add-next-line */ + apiRouter.use('/permission', await permission(permissionEnv)); + // .. + } + ``` ### 2. Enable and test the permissions system @@ -114,46 +114,46 @@ Now that the permission backend is running, it’s time to enable the permission 1. Set the property `permission.enabled` to `true` in `app-config.yaml`. - ```yaml title="app-config.yaml" - permission: - enabled: true - ``` + ```yaml title="app-config.yaml" + permission: + enabled: true + ``` 2. Update the PermissionPolicy in `packages/backend/src/plugins/permission.ts` to disable a permission that’s easy for us to test. This policy rejects any attempt to delete a catalog entity: - ```ts title="packages/backend/src/plugins/permission.ts" - import { createRouter } from '@backstage/plugin-permission-backend'; - import { - AuthorizeResult, - PolicyDecision, - } from '@backstage/plugin-permission-common'; - /* highlight-remove-next-line */ - import { PermissionPolicy } from '@backstage/plugin-permission-node'; - /* highlight-add-start */ - import { - PermissionPolicy, - PolicyQuery, - } from '@backstage/plugin-permission-node'; - /* highlight-add-end */ - import { Router } from 'express'; - import { PluginEnvironment } from '../types'; + ```ts title="packages/backend/src/plugins/permission.ts" + import { createRouter } from '@backstage/plugin-permission-backend'; + import { + AuthorizeResult, + PolicyDecision, + } from '@backstage/plugin-permission-common'; + /* highlight-remove-next-line */ + import { PermissionPolicy } from '@backstage/plugin-permission-node'; + /* highlight-add-start */ + import { + PermissionPolicy, + PolicyQuery, + } from '@backstage/plugin-permission-node'; + /* highlight-add-end */ + import { Router } from 'express'; + import { PluginEnvironment } from '../types'; - class TestPermissionPolicy implements PermissionPolicy { - /* highlight-remove-next-line */ - async handle(): Promise { - /* highlight-add-start */ - async handle(request: PolicyQuery): Promise { - if (request.permission.name === 'catalog.entity.delete') { - return { - result: AuthorizeResult.DENY, - }; - } - /* highlight-add-end */ + class TestPermissionPolicy implements PermissionPolicy { + /* highlight-remove-next-line */ + async handle(): Promise { + /* highlight-add-start */ + async handle(request: PolicyQuery): Promise { + if (request.permission.name === 'catalog.entity.delete') { + return { + result: AuthorizeResult.DENY, + }; + } + /* highlight-add-end */ - return { result: AuthorizeResult.ALLOW }; - } - } - ``` + return { result: AuthorizeResult.ALLOW }; + } + } + ``` 3. Now that you’ve made this change, you should find that the unregister entity menu option on the catalog entity page is disabled. diff --git a/docs/permissions/plugin-authors/01-setup.md b/docs/permissions/plugin-authors/01-setup.md index 46673ed307..6827096900 100644 --- a/docs/permissions/plugin-authors/01-setup.md +++ b/docs/permissions/plugin-authors/01-setup.md @@ -20,99 +20,99 @@ The source code is available here: 1. Copy-paste the three folders into the plugins folder of your backstage application repository (removing the `example-` prefix from each folder) or run the following script from the root of your backstage application: - ```bash - $ cd $(mktemp -d) - git clone --depth 1 --quiet --no-checkout --filter=blob:none https://github.com/backstage/backstage.git . - git checkout master -- plugins/example-todo-list/ - git checkout master -- plugins/example-todo-list-backend/ - git checkout master -- plugins/example-todo-list-common/ - sed -i '' 's/workspace:\^/\*/g' plugins/example-todo-list/package.json - sed -i '' 's/workspace:\^/\*/g' plugins/example-todo-list-backend/package.json - sed -i '' 's/workspace:\^/\*/g' plugins/example-todo-list-common/package.json - for file in plugins/*; do mv "$file" "$OLDPWD/${file/example-todo/todo}"; done - cd - - ``` + ```bash + $ cd $(mktemp -d) + git clone --depth 1 --quiet --no-checkout --filter=blob:none https://github.com/backstage/backstage.git . + git checkout master -- plugins/example-todo-list/ + git checkout master -- plugins/example-todo-list-backend/ + git checkout master -- plugins/example-todo-list-common/ + sed -i '' 's/workspace:\^/\*/g' plugins/example-todo-list/package.json + sed -i '' 's/workspace:\^/\*/g' plugins/example-todo-list-backend/package.json + sed -i '' 's/workspace:\^/\*/g' plugins/example-todo-list-common/package.json + for file in plugins/*; do mv "$file" "$OLDPWD/${file/example-todo/todo}"; done + cd - + ``` - The `plugins` directory of your project should now include `todo-list`, `todo-list-backend`, and `todo-list-common`. + The `plugins` directory of your project should now include `todo-list`, `todo-list-backend`, and `todo-list-common`. - **Important**: if you are on **Windows**, make sure you have WSL and git installed on your machine before executing the script above. + **Important**: if you are on **Windows**, make sure you have WSL and git installed on your machine before executing the script above. 2. Add these packages as dependencies for your Backstage app: - ```sh - # From your Backstage root directory - $ yarn add --cwd packages/backend @internal/plugin-todo-list-backend @internal/plugin-todo-list-common - $ yarn add --cwd packages/app @internal/plugin-todo-list - ``` + ```sh + # From your Backstage root directory + $ yarn add --cwd packages/backend @internal/plugin-todo-list-backend @internal/plugin-todo-list-common + $ yarn add --cwd packages/app @internal/plugin-todo-list + ``` 3. Include the backend and frontend plugin in your application: - Create a new `packages/backend/src/plugins/todolist.ts` with the following content: + Create a new `packages/backend/src/plugins/todolist.ts` with the following content: - ```typescript title="packages/backend/src/plugins/todolist.ts" - import { DefaultIdentityClient } from '@backstage/plugin-auth-node'; - import { createRouter } from '@internal/plugin-todo-list-backend'; - import { Router } from 'express'; - import { PluginEnvironment } from '../types'; + ```typescript title="packages/backend/src/plugins/todolist.ts" + import { DefaultIdentityClient } from '@backstage/plugin-auth-node'; + import { createRouter } from '@internal/plugin-todo-list-backend'; + import { Router } from 'express'; + import { PluginEnvironment } from '../types'; - export default async function createPlugin({ - logger, - discovery, - }: PluginEnvironment): Promise { - return await createRouter({ - logger, - identity: DefaultIdentityClient.create({ - discovery, - issuer: await discovery.getExternalBaseUrl('auth'), - }), - }); - } - ``` + export default async function createPlugin({ + logger, + discovery, + }: PluginEnvironment): Promise { + return await createRouter({ + logger, + identity: DefaultIdentityClient.create({ + discovery, + issuer: await discovery.getExternalBaseUrl('auth'), + }), + }); + } + ``` - Apply the following changes to `packages/backend/src/index.ts`: + Apply the following changes to `packages/backend/src/index.ts`: - ```ts title="packages/backend/src/index.ts" - import techdocs from './plugins/techdocs'; - /* highlight-add-next-line */ - import todoList from './plugins/todolist'; - import search from './plugins/search'; + ```ts title="packages/backend/src/index.ts" + import techdocs from './plugins/techdocs'; + /* highlight-add-next-line */ + import todoList from './plugins/todolist'; + import search from './plugins/search'; - async function main() { - const searchEnv = useHotMemoize(module, () => createEnv('search')); - const appEnv = useHotMemoize(module, () => createEnv('app')); - /* highlight-add-next-line */ - const todoListEnv = useHotMemoize(module, () => createEnv('todolist')); - // .. + async function main() { + const searchEnv = useHotMemoize(module, () => createEnv('search')); + const appEnv = useHotMemoize(module, () => createEnv('app')); + /* highlight-add-next-line */ + const todoListEnv = useHotMemoize(module, () => createEnv('todolist')); + // .. - apiRouter.use('/proxy', await proxy(proxyEnv)); - apiRouter.use('/search', await search(searchEnv)); - apiRouter.use('/permission', await permission(permissionEnv)); - /* highlight-add-next-line */ - apiRouter.use('/todolist', await todoList(todoListEnv)); - // Add backends ABOVE this line; this 404 handler is the catch-all fallback - apiRouter.use(notFoundHandler()); - // .. - } - ``` + apiRouter.use('/proxy', await proxy(proxyEnv)); + apiRouter.use('/search', await search(searchEnv)); + apiRouter.use('/permission', await permission(permissionEnv)); + /* highlight-add-next-line */ + apiRouter.use('/todolist', await todoList(todoListEnv)); + // Add backends ABOVE this line; this 404 handler is the catch-all fallback + apiRouter.use(notFoundHandler()); + // .. + } + ``` - Apply the following changes to `packages/app/src/App.tsx`: + Apply the following changes to `packages/app/src/App.tsx`: - ```tsx title="packages/app/src/App.tsx" - /* highlight-add-next-line */ - import { TodoListPage } from '@internal/plugin-todo-list'; + ```tsx title="packages/app/src/App.tsx" + /* highlight-add-next-line */ + import { TodoListPage } from '@internal/plugin-todo-list'; - const routes = ( - - }> - {searchPage} - - } /> - {/* highlight-add-next-line */} - } /> - {/* ... */} - - ); - ``` + const routes = ( + + }> + {searchPage} + + } /> + {/* highlight-add-next-line */} + } /> + {/* ... */} + + ); + ``` Now if you start your application you should be able to reach the `/todo-list` page: diff --git a/docs/permissions/plugin-authors/03-adding-a-resource-permission-check.md b/docs/permissions/plugin-authors/03-adding-a-resource-permission-check.md index ed4fb74573..e714301ded 100644 --- a/docs/permissions/plugin-authors/03-adding-a-resource-permission-check.md +++ b/docs/permissions/plugin-authors/03-adding-a-resource-permission-check.md @@ -32,7 +32,10 @@ export const todoListUpdatePermission = createPermission({ /* highlight-remove-next-line */ export const todoListPermissions = [todoListCreatePermission]; /* highlight-add-next-line */ -export const todoListPermissions = [todoListCreatePermission, todoListUpdatePermission]; +export const todoListPermissions = [ + todoListCreatePermission, + todoListUpdatePermission, +]; ``` Notice that unlike `todoListCreatePermission`, the `todoListUpdatePermission` permission contains a `resourceType` field. This field indicates to the permission framework that this permission is intended to be authorized in the context of a resource with type `'todo-item'`. You can use whatever string you like as the resource type, as long as you use the same value consistently for each type of resource. @@ -45,7 +48,10 @@ To start, let's edit `plugins/todo-list-backend/src/service/router.ts` in the sa /* highlight-remove-next-line */ import { todoListCreatePermission } from '@internal/plugin-todo-list-common'; /* highlight-add-next-line */ -import { todoListCreatePermission, todoListUpdatePermission } from '@internal/plugin-todo-list-common'; +import { + todoListCreatePermission, + todoListUpdatePermission, +} from '@internal/plugin-todo-list-common'; router.put('/todos', async (req, res) => { /* highlight-add-start */ diff --git a/docs/permissions/plugin-authors/04-authorizing-access-to-paginated-data.md b/docs/permissions/plugin-authors/04-authorizing-access-to-paginated-data.md index 4b12e9e407..bd56afc971 100644 --- a/docs/permissions/plugin-authors/04-authorizing-access-to-paginated-data.md +++ b/docs/permissions/plugin-authors/04-authorizing-access-to-paginated-data.md @@ -14,11 +14,14 @@ router.get('/todos', async (req, res) => { const token = IdentityClient.getBearerToken(req.header('authorization')); /* highlight-remove-next-line */ - res.json(getAll()) + res.json(getAll()); /* highlight-add-start */ const items = getAll(); const decisions = await permissions.authorize( - items.map(({ id }) => ({ permission: todoListReadPermission, resourceRef: id })), + items.map(({ id }) => ({ + permission: todoListReadPermission, + resourceRef: id, + })), ); const filteredItems = decisions.filter( @@ -64,9 +67,16 @@ export const todoListReadPermission = createPermission({ /* highlight-add-end */ /* highlight-add-next-line */ -export const todoListPermissions = [todoListCreatePermission, todoListUpdatePermission]; +export const todoListPermissions = [ + todoListCreatePermission, + todoListUpdatePermission, +]; /* highlight-add-next-line */ -export const todoListPermissions = [todoListCreatePermission, todoListUpdatePermission, todoListReadPermission]; +export const todoListPermissions = [ + todoListCreatePermission, + todoListUpdatePermission, + todoListReadPermission, +]; ``` ## Using conditional policy decisions diff --git a/docs/permissions/plugin-authors/05-frontend-authorization.md b/docs/permissions/plugin-authors/05-frontend-authorization.md index 235495e13f..92d855698f 100644 --- a/docs/permissions/plugin-authors/05-frontend-authorization.md +++ b/docs/permissions/plugin-authors/05-frontend-authorization.md @@ -36,7 +36,9 @@ import { todoListCreatePermission } from '@internal/plugin-todo-list-common'; function AddTodo({ onAdd }: { onAdd: (title: string) => any }) { const title = useRef(''); /* highlight-add-next-line */ - const { loading: loadingPermission, allowed: canAddTodo } = usePermission({ permission: todoListCreatePermission }); + const { loading: loadingPermission, allowed: canAddTodo } = usePermission({ + permission: todoListCreatePermission, + }); return ( <> @@ -78,7 +80,6 @@ Here we are using the [`usePermission` hook](https://backstage.io/docs/reference It's really that simple! Let's change our policy to test the disabled button: ```ts title="packages/backend/src/plugins/permission.ts" - if (isPermission(request.permission, todoListCreatePermission)) { return { /* highlight-remove-next-line */ @@ -117,10 +118,7 @@ export const TodoListPage = () => { {/* highlight-remove-end */} {/* highlight-add-start */} - } - > + }> @@ -129,13 +127,15 @@ export const TodoListPage = () => { - -} + ; +}; function AddTodo({ onAdd }: { onAdd: (title: string) => any }) { const title = useRef(''); /* highlight-remove-next-line */ - const { loading: loadingPermission, allowed: canAddTodo } = usePermission({ permission: todoListCreatePermission }); + const { loading: loadingPermission, allowed: canAddTodo } = usePermission({ + permission: todoListCreatePermission, + }); return ( <> diff --git a/docs/tutorials/react-router-stable-migration.md b/docs/tutorials/react-router-stable-migration.md index 24dba3c244..017f69ba4f 100644 --- a/docs/tutorials/react-router-stable-migration.md +++ b/docs/tutorials/react-router-stable-migration.md @@ -181,10 +181,14 @@ It's crucial that you update to `RequirePermission` at the same time as you upda When migrating over to React Router v6 stable, you might also see browser console warnings for the `Navigate` component. This will need to be wrapped up in a `Route` component with the `Navigate` component in the `element` prop. ```tsx -{/* highlight-remove-next-line */} - -{/* highlight-add-next-line */} -} /> +{ + /* highlight-remove-next-line */ +} +; +{ + /* highlight-add-next-line */ +} +} />; ``` ### `NavLink`