Merge branch 'master' into feat/api-auth-client

This commit is contained in:
Patrik Oldsberg
2021-02-10 11:39:45 +01:00
committed by GitHub
449 changed files with 7356 additions and 2024 deletions
@@ -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 = {
entity: Entity;
/** @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 <RollbarProject entity={entity} />;
};
@@ -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<RollbarApi> = {
getAllProjects: () => Promise.resolve(projects),
};
const config: Partial<ConfigApi> = {
getString: () => 'foo',
getOptionalString: () => 'foo',
};
const renderWrapped = (children: React.ReactNode) =>
render(
wrapInTestApp(
<ApiProvider
apis={ApiRegistry.from([
[rollbarApiRef, rollbarApi],
[configApiRef, config],
[
catalogApiRef,
({
async getEntities() {
return { items: [] };
},
} as Partial<CatalogApi>) as CatalogApi,
],
])}
>
{children}
</ApiProvider>,
),
);
it('should render rollbar landing page', async () => {
const rendered = renderWrapped(<RollbarHome />);
expect(rendered.getByText(/Rollbar/)).toBeInTheDocument();
});
});
@@ -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 (
<Page themeId="tool">
<Header
title="Rollbar"
subtitle="Real-time error tracking & debugging tools for developers"
/>
<Content>
<RollbarProjectTable
entities={entities || []}
loading={loading}
error={error}
/>
</Content>
</Page>
);
};
@@ -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';
@@ -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<RollbarApi> = {
getTopActiveItems: () => Promise.resolve(items),
};
const config: Partial<ConfigApi> = {
getString: () => 'foo',
getOptionalString: () => 'foo',
};
const renderWrapped = (children: React.ReactNode) =>
render(
wrapInTestApp(
<ApiProvider
apis={ApiRegistry.from([
[rollbarApiRef, rollbarApi],
[configApiRef, config],
[
catalogApiRef,
({
async getEntityByName() {
return {
metadata: { name: 'foo' },
spec: { owner: 'bar', lifecycle: 'experimental' },
} as any;
},
} as Partial<CatalogApi>) as CatalogApi,
],
])}
>
{children}
</ApiProvider>,
),
);
it('should render rollbar project page', async () => {
const rendered = renderWrapped(<RollbarProjectPage />);
expect(rendered.getByText(/Rollbar/)).toBeInTheDocument();
});
});
@@ -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 (
<Page themeId="tool">
<Header title={entity?.metadata?.name} subtitle="Rollbar Project">
<HeaderLabel label="Owner" value={entity?.spec?.owner} />
<HeaderLabel label="Lifecycle" value={entity?.spec?.lifecycle} />
</Header>
<Content>
{entity ? <RollbarProject entity={entity} /> : 'Loading'}
</Content>
</Page>
);
};
@@ -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) => (
<Link
component={RouterLink}
to={generatePath(entityRouteRef.path, {
optionalNamespaceAndName: [
entity.metadata.namespace,
entity.metadata.name,
]
.filter(Boolean)
.join(':'),
kind: entity.kind,
})}
>
{entity.metadata.name}
</Link>
),
},
{
title: 'Description',
field: 'metadata.description',
},
];
type Props = {
entities: Entity[];
loading: boolean;
error?: any;
};
export const RollbarProjectTable = ({ entities, loading, error }: Props) => {
if (error) {
return (
<div>
<Alert severity="error">
Error encountered while fetching rollbar projects. {error.toString()}
</Alert>
</div>
);
}
return (
<Table
isLoading={loading}
columns={columns}
options={{
search: true,
paging: true,
pageSize: 10,
showEmptyDataSourceMessage: !loading,
}}
title="Projects"
data={entities}
/>
);
};
@@ -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[] = [
{
@@ -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,
+16 -9
View File
@@ -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 = {
entity: Entity;
/** @deprecated The entity is now grabbed from context instead */
entity?: Entity;
};
export const Router = ({ entity }: Props) =>
!isPluginApplicableToEntity(entity) ? (
<MissingAnnotationEmptyState annotation={ROLLBAR_ANNOTATION} />
) : (
export const Router = (_props: Props) => {
const { entity } = useEntity();
if (!isPluginApplicableToEntity(entity)) {
<MissingAnnotationEmptyState annotation={ROLLBAR_ANNOTATION} />;
}
return (
<Routes>
<Route
path={`/${catalogRouteRef.path}`}
path={`/${rootRouteRef.path}`}
element={<EntityPageRollbar entity={entity} />}
/>
</Routes>
);
};
@@ -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', () => {
+10 -4
View File
@@ -14,10 +14,16 @@
* 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 {
EntityRollbarContent,
rollbarPlugin as plugin,
rollbarPlugin,
} from './plugin';
+2 -2
View File
@@ -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();
});
});
+18 -8
View File
@@ -15,18 +15,22 @@
*/
import {
createPlugin,
createApiFactory,
createPlugin,
createRoutableExtension,
createRouteRef,
discoveryApiRef,
identityApiRef,
} 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({
@@ -36,8 +40,14 @@ export const plugin = createPlugin({
new RollbarClient({ discoveryApi, identityApi }),
}),
],
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,
}),
);
-36
View File
@@ -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',
});