diff --git a/.changeset/late-crews-train.md b/.changeset/late-crews-train.md new file mode 100644 index 0000000000..00f8f8b6ee --- /dev/null +++ b/.changeset/late-crews-train.md @@ -0,0 +1,6 @@ +--- +'example-app': patch +'@backstage/plugin-rollbar': patch +--- + +Migrated to new composability API, exporting the plugin instance as `rollbarPlugin`, the entity page content as `EntityRollbarContent`, and entity conditional as `isRollbarAvailable`. Updated the `EntityPage` for the `example-app` to include a composite `ErrorsSwitcher` component that works with both `Sentry` & `Rollbar`. Also removed the unused and undocumented `RollbarHome` related components. diff --git a/packages/app/src/components/catalog/EntityPage.tsx b/packages/app/src/components/catalog/EntityPage.tsx index 0372c8759c..5474afa72c 100644 --- a/packages/app/src/components/catalog/EntityPage.tsx +++ b/packages/app/src/components/catalog/EntityPage.tsx @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { ApiEntity, Entity, @@ -64,6 +65,10 @@ import { isPluginApplicableToEntity as isPagerDutyAvailable, PagerDutyCard, } from '@backstage/plugin-pagerduty'; +import { + isRollbarAvailable, + Router as RollbarRouter, +} from '@backstage/plugin-rollbar'; import { Router as SentryRouter } from '@backstage/plugin-sentry'; import { EmbeddedDocsRouter as DocsRouter } from '@backstage/plugin-techdocs'; import { Button, Grid } from '@material-ui/core'; @@ -153,6 +158,15 @@ const RecentCICDRunsSwitcher = ({ entity }: { entity: Entity }) => { ); }; +export const ErrorsSwitcher = ({ entity }: { entity: Entity }) => { + switch (true) { + case isRollbarAvailable(entity): + return ; + default: + return ; + } +}; + const ComponentOverviewContent = ({ entity }: { entity: Entity }) => ( @@ -212,9 +226,9 @@ const ServiceEntityPage = ({ entity }: { entity: Entity }) => ( element={} /> } + path="/errors/*" + title="Errors" + element={} /> ( element={} /> } + path="/errors/*" + title="Errors" + element={} /> ( ); ``` -6. Setup the `app.config.yaml` and account token environment variable +5. Setup the `app.config.yaml` and account token environment variable ```yaml # app.config.yaml @@ -59,7 +49,7 @@ rollbar: $env: ROLLBAR_ACCOUNT_TOKEN ``` -7. Annotate entities with the rollbar project slug +6. Annotate entities with the rollbar project slug ```yaml # pump-station-catalog-component.yaml @@ -71,7 +61,7 @@ metadata: rollbar.com/project-slug: project-name ``` -8. Run app with `yarn start` and navigate to `/rollbar` or a catalog entity +7. Run app with `yarn start` and navigate to `/rollbar` or a catalog entity ## Features diff --git a/plugins/rollbar/dev/index.tsx b/plugins/rollbar/dev/index.tsx index 812a5585d4..6cac0d9a0c 100644 --- a/plugins/rollbar/dev/index.tsx +++ b/plugins/rollbar/dev/index.tsx @@ -15,6 +15,6 @@ */ import { createDevApp } from '@backstage/dev-utils'; -import { plugin } from '../src/plugin'; +import { rollbarPlugin } from '../src/plugin'; -createDevApp().registerPlugin(plugin).render(); +createDevApp().registerPlugin(rollbarPlugin).render(); diff --git a/plugins/rollbar/src/components/EntityPageRollbar/EntityPageRollbar.tsx b/plugins/rollbar/src/components/EntityPageRollbar/EntityPageRollbar.tsx index 888b9aabe0..b30874865f 100644 --- a/plugins/rollbar/src/components/EntityPageRollbar/EntityPageRollbar.tsx +++ b/plugins/rollbar/src/components/EntityPageRollbar/EntityPageRollbar.tsx @@ -14,14 +14,18 @@ * limitations under the License. */ -import React from 'react'; import { Entity } from '@backstage/catalog-model'; +import { useEntity } from '@backstage/plugin-catalog-react'; +import React from 'react'; import { RollbarProject } from '../RollbarProject/RollbarProject'; type Props = { + /** @deprecated The entity is now grabbed from context instead */ entity: Entity; }; -export const EntityPageRollbar = ({ entity }: Props) => { +export const EntityPageRollbar = (_props: Props) => { + const { entity } = useEntity(); + return ; }; diff --git a/plugins/rollbar/src/components/RollbarHome/RollbarHome.test.tsx b/plugins/rollbar/src/components/RollbarHome/RollbarHome.test.tsx deleted file mode 100644 index 5bd885c488..0000000000 --- a/plugins/rollbar/src/components/RollbarHome/RollbarHome.test.tsx +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import * as React from 'react'; -import { - ApiProvider, - ApiRegistry, - ConfigApi, - configApiRef, -} from '@backstage/core'; -import { catalogApiRef, CatalogApi } from '@backstage/plugin-catalog-react'; -import { wrapInTestApp } from '@backstage/test-utils'; -import { render } from '@testing-library/react'; -import { RollbarApi, rollbarApiRef } from '../../api/RollbarApi'; -import { RollbarProject } from '../../api/types'; -import { RollbarHome } from './RollbarHome'; - -describe('RollbarHome component', () => { - const projects: RollbarProject[] = [ - { id: 123, name: 'abc', accountId: 1, status: 'enabled' }, - { id: 456, name: 'xyz', accountId: 1, status: 'enabled' }, - ]; - const rollbarApi: Partial = { - getAllProjects: () => Promise.resolve(projects), - }; - const config: Partial = { - getString: () => 'foo', - getOptionalString: () => 'foo', - }; - - const renderWrapped = (children: React.ReactNode) => - render( - wrapInTestApp( - ) as CatalogApi, - ], - ])} - > - {children} - , - ), - ); - - it('should render rollbar landing page', async () => { - const rendered = renderWrapped(); - expect(rendered.getByText(/Rollbar/)).toBeInTheDocument(); - }); -}); diff --git a/plugins/rollbar/src/components/RollbarHome/RollbarHome.tsx b/plugins/rollbar/src/components/RollbarHome/RollbarHome.tsx deleted file mode 100644 index fe99e70575..0000000000 --- a/plugins/rollbar/src/components/RollbarHome/RollbarHome.tsx +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import React from 'react'; -import { Content, Header, Page } from '@backstage/core'; -import { RollbarProjectTable } from '../RollbarProjectTable/RollbarProjectTable'; -import { useRollbarEntities } from '../../hooks/useRollbarEntities'; - -export const RollbarHome = () => { - const { entities, loading, error } = useRollbarEntities(); - - return ( - -
- - - - - ); -}; diff --git a/plugins/rollbar/src/components/RollbarProject/RollbarProject.tsx b/plugins/rollbar/src/components/RollbarProject/RollbarProject.tsx index 34881ba560..b69c69a56b 100644 --- a/plugins/rollbar/src/components/RollbarProject/RollbarProject.tsx +++ b/plugins/rollbar/src/components/RollbarProject/RollbarProject.tsx @@ -14,8 +14,8 @@ * limitations under the License. */ -import React from 'react'; import { Entity } from '@backstage/catalog-model'; +import React from 'react'; import { useTopActiveItems } from '../../hooks/useTopActiveItems'; import { RollbarTopItemsTable } from '../RollbarTopItemsTable/RollbarTopItemsTable'; diff --git a/plugins/rollbar/src/components/RollbarProjectPage/RollbarProjectPage.test.tsx b/plugins/rollbar/src/components/RollbarProjectPage/RollbarProjectPage.test.tsx deleted file mode 100644 index 6aeee782c4..0000000000 --- a/plugins/rollbar/src/components/RollbarProjectPage/RollbarProjectPage.test.tsx +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { - ApiProvider, - ApiRegistry, - ConfigApi, - configApiRef, -} from '@backstage/core'; -import { CatalogApi, catalogApiRef } from '@backstage/plugin-catalog-react'; -import { wrapInTestApp } from '@backstage/test-utils'; -import { render } from '@testing-library/react'; -import * as React from 'react'; -import { RollbarApi, rollbarApiRef } from '../../api/RollbarApi'; -import { RollbarTopActiveItem } from '../../api/types'; -import { RollbarProjectPage } from './RollbarProjectPage'; - -describe('RollbarProjectPage component', () => { - const items: RollbarTopActiveItem[] = [ - { - item: { - id: 9898989, - counter: 1234, - environment: 'production', - framework: 2, - lastOccurrenceTimestamp: new Date().getTime() / 1000, - level: 50, - occurrences: 100, - projectId: 12345, - title: 'error occurred', - uniqueOccurrences: 10, - }, - counts: [10, 10, 10, 10, 10, 50], - }, - ]; - const rollbarApi: Partial = { - getTopActiveItems: () => Promise.resolve(items), - }; - const config: Partial = { - getString: () => 'foo', - getOptionalString: () => 'foo', - }; - - const renderWrapped = (children: React.ReactNode) => - render( - wrapInTestApp( - ) as CatalogApi, - ], - ])} - > - {children} - , - ), - ); - - it('should render rollbar project page', async () => { - const rendered = renderWrapped(); - expect(rendered.getByText(/Rollbar/)).toBeInTheDocument(); - }); -}); diff --git a/plugins/rollbar/src/components/RollbarProjectPage/RollbarProjectPage.tsx b/plugins/rollbar/src/components/RollbarProjectPage/RollbarProjectPage.tsx deleted file mode 100644 index 5563a6d7a0..0000000000 --- a/plugins/rollbar/src/components/RollbarProjectPage/RollbarProjectPage.tsx +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import React from 'react'; -import { Content, Header, HeaderLabel, Page } from '@backstage/core'; -import { useCatalogEntity } from '../../hooks/useCatalogEntity'; -import { RollbarProject } from '../RollbarProject/RollbarProject'; - -export const RollbarProjectPage = () => { - const { entity } = useCatalogEntity(); - - return ( - -
- - -
- - {entity ? : 'Loading'} - -
- ); -}; diff --git a/plugins/rollbar/src/components/RollbarProjectTable/RollbarProjectTable.tsx b/plugins/rollbar/src/components/RollbarProjectTable/RollbarProjectTable.tsx deleted file mode 100644 index 5b3631ade9..0000000000 --- a/plugins/rollbar/src/components/RollbarProjectTable/RollbarProjectTable.tsx +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import React from 'react'; -import { Link as RouterLink, generatePath } from 'react-router-dom'; -import { Table, TableColumn } from '@backstage/core'; -import { Entity } from '@backstage/catalog-model'; -import { Link } from '@material-ui/core'; -import { Alert } from '@material-ui/lab'; -import { entityRouteRef } from '../../routes'; - -const columns: TableColumn[] = [ - { - title: 'Name', - field: 'metadata.name', - type: 'string', - highlight: true, - render: (entity: any) => ( - - {entity.metadata.name} - - ), - }, - { - title: 'Description', - field: 'metadata.description', - }, -]; - -type Props = { - entities: Entity[]; - loading: boolean; - error?: any; -}; - -export const RollbarProjectTable = ({ entities, loading, error }: Props) => { - if (error) { - return ( -
- - Error encountered while fetching rollbar projects. {error.toString()} - -
- ); - } - - return ( - - ); -}; diff --git a/plugins/rollbar/src/components/RollbarTopItemsTable/RollbarTopItemsTable.test.tsx b/plugins/rollbar/src/components/RollbarTopItemsTable/RollbarTopItemsTable.test.tsx index dc177265cd..2916fefbcf 100644 --- a/plugins/rollbar/src/components/RollbarTopItemsTable/RollbarTopItemsTable.test.tsx +++ b/plugins/rollbar/src/components/RollbarTopItemsTable/RollbarTopItemsTable.test.tsx @@ -17,8 +17,8 @@ import { wrapInTestApp } from '@backstage/test-utils'; import { render } from '@testing-library/react'; import * as React from 'react'; -import { RollbarTopItemsTable } from './RollbarTopItemsTable'; import { RollbarTopActiveItem } from '../../api/types'; +import { RollbarTopItemsTable } from './RollbarTopItemsTable'; const items: RollbarTopActiveItem[] = [ { diff --git a/plugins/rollbar/src/components/RollbarTopItemsTable/RollbarTopItemsTable.tsx b/plugins/rollbar/src/components/RollbarTopItemsTable/RollbarTopItemsTable.tsx index a04155a0c3..c22f813dd9 100644 --- a/plugins/rollbar/src/components/RollbarTopItemsTable/RollbarTopItemsTable.tsx +++ b/plugins/rollbar/src/components/RollbarTopItemsTable/RollbarTopItemsTable.tsx @@ -14,10 +14,10 @@ * limitations under the License. */ -import React from 'react'; import { Table, TableColumn } from '@backstage/core'; import { Box, Link, Typography } from '@material-ui/core'; import { Alert } from '@material-ui/lab'; +import React from 'react'; import { RollbarFrameworkId, RollbarLevel, diff --git a/plugins/rollbar/src/components/Router.tsx b/plugins/rollbar/src/components/Router.tsx index f0756cb02a..6d793d7426 100644 --- a/plugins/rollbar/src/components/Router.tsx +++ b/plugins/rollbar/src/components/Router.tsx @@ -14,29 +14,36 @@ * limitations under the License. */ -import React from 'react'; -import { Routes, Route } from 'react-router'; import { Entity } from '@backstage/catalog-model'; import { MissingAnnotationEmptyState } from '@backstage/core'; -import { catalogRouteRef } from '../routes'; +import { useEntity } from '@backstage/plugin-catalog-react'; +import React from 'react'; +import { Route, Routes } from 'react-router'; import { ROLLBAR_ANNOTATION } from '../constants'; +import { rootRouteRef } from '../plugin'; import { EntityPageRollbar } from './EntityPageRollbar/EntityPageRollbar'; export const isPluginApplicableToEntity = (entity: Entity) => Boolean(entity.metadata.annotations?.[ROLLBAR_ANNOTATION]); type Props = { + /** @deprecated The entity is now grabbed from context instead */ entity: Entity; }; -export const Router = ({ entity }: Props) => - !isPluginApplicableToEntity(entity) ? ( - - ) : ( +export const Router = (_props: Props) => { + const { entity } = useEntity(); + + if (!isPluginApplicableToEntity(entity)) { + ; + } + + return ( } /> ); +}; diff --git a/plugins/rollbar/src/components/TrendGraph/TrendGraph.test.tsx b/plugins/rollbar/src/components/TrendGraph/TrendGraph.test.tsx index ac1a328521..e944a53551 100644 --- a/plugins/rollbar/src/components/TrendGraph/TrendGraph.test.tsx +++ b/plugins/rollbar/src/components/TrendGraph/TrendGraph.test.tsx @@ -14,9 +14,9 @@ * limitations under the License. */ -import React from 'react'; -import { render } from '@testing-library/react'; import { wrapInTestApp } from '@backstage/test-utils'; +import { render } from '@testing-library/react'; +import React from 'react'; import { TrendGraph } from './TrendGraph'; describe('TrendGraph component', () => { diff --git a/plugins/rollbar/src/index.ts b/plugins/rollbar/src/index.ts index 2a31c91a13..52c0c35fd7 100644 --- a/plugins/rollbar/src/index.ts +++ b/plugins/rollbar/src/index.ts @@ -14,10 +14,12 @@ * limitations under the License. */ -export { plugin } from './plugin'; export * from './api'; -export * from './routes'; -export { Router } from './components/Router'; -export { RollbarProjectPage } from './components/RollbarProjectPage/RollbarProjectPage'; export { EntityPageRollbar } from './components/EntityPageRollbar/EntityPageRollbar'; +export { + isPluginApplicableToEntity, + isPluginApplicableToEntity as isRollbarAvailable, + Router, +} from './components/Router'; export { ROLLBAR_ANNOTATION } from './constants'; +export { rollbarPlugin as plugin, rollbarPlugin } from './plugin'; diff --git a/plugins/rollbar/src/plugin.test.ts b/plugins/rollbar/src/plugin.test.ts index 44c2168c78..7ef23b019a 100644 --- a/plugins/rollbar/src/plugin.test.ts +++ b/plugins/rollbar/src/plugin.test.ts @@ -14,10 +14,10 @@ * limitations under the License. */ -import { plugin } from './plugin'; +import { rollbarPlugin } from './plugin'; describe('rollbar', () => { it('should export plugin', () => { - expect(plugin).toBeDefined(); + expect(rollbarPlugin).toBeDefined(); }); }); diff --git a/plugins/rollbar/src/plugin.ts b/plugins/rollbar/src/plugin.ts index c3ca6173ff..216713b3fc 100644 --- a/plugins/rollbar/src/plugin.ts +++ b/plugins/rollbar/src/plugin.ts @@ -15,17 +15,21 @@ */ import { - createPlugin, createApiFactory, + createPlugin, + createRoutableExtension, + createRouteRef, discoveryApiRef, } from '@backstage/core'; -import { rootRouteRef, entityRouteRef } from './routes'; -import { RollbarHome } from './components/RollbarHome/RollbarHome'; -import { RollbarProjectPage } from './components/RollbarProjectPage/RollbarProjectPage'; import { rollbarApiRef } from './api/RollbarApi'; import { RollbarClient } from './api/RollbarClient'; -export const plugin = createPlugin({ +export const rootRouteRef = createRouteRef({ + path: '', + title: 'Rollbar', +}); + +export const rollbarPlugin = createPlugin({ id: 'rollbar', apis: [ createApiFactory({ @@ -34,8 +38,14 @@ export const plugin = createPlugin({ factory: ({ discoveryApi }) => new RollbarClient({ discoveryApi }), }), ], - register({ router }) { - router.addRoute(rootRouteRef, RollbarHome); - router.addRoute(entityRouteRef, RollbarProjectPage); + routes: { + entityContent: rootRouteRef, }, }); + +export const EntityRollbarContent = rollbarPlugin.provide( + createRoutableExtension({ + component: () => import('./components/Router').then(m => m.Router), + mountPoint: rootRouteRef, + }), +); diff --git a/plugins/rollbar/src/routes.ts b/plugins/rollbar/src/routes.ts deleted file mode 100644 index b514dff3c8..0000000000 --- a/plugins/rollbar/src/routes.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { createRouteRef } from '@backstage/core'; - -const NoIcon = () => null; - -export const rootRouteRef = createRouteRef({ - icon: NoIcon, - path: '/rollbar', - title: 'Rollbar Home', -}); - -export const entityRouteRef = createRouteRef({ - path: '/rollbar/:optionalNamespaceAndName', - title: 'Rollbar', -}); - -export const catalogRouteRef = createRouteRef({ - icon: NoIcon, - path: '', - title: 'Rollbar', -});