adding rollbar plugin & backend

This is the first commit of the rollbar plugin. It is fully functional
but will require some additional features to make it more usable and
feature complete. It currently includes a backend wraps the rollbar REST
API and provides data for the frontend plugin.
This commit is contained in:
Andrew Thauer
2020-07-08 21:43:53 -04:00
parent 9047c7caf4
commit 8885ebee89
44 changed files with 1975 additions and 0 deletions
+37
View File
@@ -0,0 +1,37 @@
/*
* 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 { createApiRef } from '@backstage/core';
import {
RollbarItemsResponse,
RollbarProject,
RollbarTopActiveItem,
} from './types';
export const rollbarApiRef = createApiRef<RollbarApi>({
id: 'plugin.rollbar.service',
description:
'Used by the Rollbar plugin to make requests to accompanying backend',
});
export interface RollbarApi {
getAllProjects(): Promise<RollbarProject[]>;
getTopActiveItems(
project: string,
hours?: number,
): Promise<RollbarTopActiveItem[]>;
getProjectItems(project: string): Promise<RollbarItemsResponse>;
}
+73
View File
@@ -0,0 +1,73 @@
/*
* 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 { RollbarApi } from './RollbarApi';
import {
RollbarItemsResponse,
RollbarProject,
RollbarTopActiveItem,
} from './types';
export class RollbarClient implements RollbarApi {
private apiOrigin: string;
private basePath: string;
constructor({
apiOrigin,
basePath,
}: {
apiOrigin: string;
basePath: string;
}) {
this.apiOrigin = apiOrigin;
this.basePath = basePath;
}
async getAllProjects(): Promise<RollbarProject[]> {
const path = `/projects`;
return await this.get(path);
}
async getTopActiveItems(
project: string,
hours = 24,
environment = 'production',
): Promise<RollbarTopActiveItem[]> {
const path = `/projects/${project}/top_active_items?environment=${environment}&hours=${hours}`;
return await this.get(path);
}
async getProjectItems(project: string): Promise<RollbarItemsResponse> {
const path = `/projects/${project}/items`;
return await this.get(path);
}
private async get(path: string): Promise<any> {
const url = `${this.apiOrigin}${this.basePath}${path}`;
const response = await fetch(url);
if (!response.ok) {
const payload = await response.text();
const message = `Request failed with ${response.status} ${response.statusText}, ${payload}`;
throw new Error(message);
}
return await response.json();
}
}
@@ -0,0 +1,70 @@
/*
* 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.
*/
/* eslint-disable @typescript-eslint/no-unused-vars */
import { RollbarApi } from './RollbarApi';
import {
RollbarItemsResponse,
RollbarProject,
RollbarTopActiveItem,
} from './types';
export class RollbarMockClient implements RollbarApi {
async getAllProjects(): Promise<RollbarProject[]> {
return Promise.resolve([
{ id: 123, name: 'project-a', accountId: 1, status: 'enabled' },
{ id: 356, name: 'project-b', accountId: 1, status: 'enabled' },
{ id: 789, name: 'project-c', accountId: 1, status: 'enabled' },
]);
}
async getTopActiveItems(
_project: string,
_hours = 24,
_environment = 'production',
): Promise<RollbarTopActiveItem[]> {
const createItem = (id: number): RollbarTopActiveItem => ({
item: {
id,
counter: id,
environment: 'production',
framework: 2,
lastOccurrenceTimestamp: new Date().getTime() / 1000,
level: 50,
occurrences: 100,
projectId: 12345,
title: `Some error occurred in service - ${id}`,
uniqueOccurrences: 10,
},
counts: Array.from({ length: 168 }, () =>
Math.floor(Math.random() * 100),
),
});
const items = Array.from({ length: 10 }, (_, i) => createItem(i));
return Promise.resolve(items);
}
async getProjectItems(_project: string): Promise<RollbarItemsResponse> {
return Promise.resolve({
items: [],
page: 0,
totalCount: 0,
});
}
}
+135
View File
@@ -0,0 +1,135 @@
/*
* 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.
*/
// TODO: Make this shared/dry with backend
export type RollbarProjectAccessTokenScope = 'read' | 'write';
export type RollbarEnvironment = 'production' | string;
export enum RollbarLevel {
debug = 10,
info = 20,
warning = 30,
error = 40,
critical = 50,
}
export enum RollbarFrameworkId {
'unknown' = 0,
'rails' = 1,
'django' = 2,
'pyramid' = 3,
'node-js' = 4,
'pylons' = 5,
'php' = 6,
'browser-js' = 7,
'rollbar-system' = 8,
'android' = 9,
'ios' = 10,
'mailgun' = 11,
'logentries' = 12,
'python' = 13,
'ruby' = 14,
'sidekiq' = 15,
'flask' = 16,
'celery' = 17,
'rq' = 18,
}
export enum RollbarPlatformId {
'unknown' = 0,
'browser' = 1,
'flash' = 2,
'android' = 3,
'ios' = 4,
'heroku' = 5,
'google-app-engine' = 6,
'client' = 7,
}
export type RollbarProject = {
id: number;
name: string;
accountId: number;
status: 'enabled' | string;
};
export type RollbarProjectAccessToken = {
projectId: number;
name: string;
scopes: RollbarProjectAccessTokenScope[];
accessToken: string;
status: 'enabled' | string;
};
export type RollbarItem = {
publicItemId: number;
integrationsData: null;
levelLock: number;
controllingId: number;
lastActivatedTimestamp: number;
assignedUserId: number;
groupStatus: number;
hash: string;
id: number;
environment: RollbarEnvironment;
titleLock: number;
title: string;
lastOccurrenceId: number;
lastOccurrenceTimestamp: number;
platform: RollbarPlatformId;
firstOccurrenceTimestamp: number;
project_id: number;
resolvedInVersion: string;
status: 'enabled' | string;
uniqueOccurrences: number;
groupItemId: number;
framework: RollbarFrameworkId;
totalOccurrences: number;
level: RollbarLevel;
counter: number;
lastModifiedBy: number;
firstOccurrenceId: number;
activatingOccurrenceId: number;
lastResolvedTimestamp: number;
};
export type RollbarItemsResponse = {
items: RollbarItem[];
page: number;
totalCount: number;
};
export type RollbarItemCount = {
timestamp: number;
count: number;
};
export type RollbarTopActiveItem = {
item: {
id: number;
counter: number;
environment: RollbarEnvironment;
framework: RollbarFrameworkId;
lastOccurrenceTimestamp: number;
level: number;
occurrences: number;
projectId: number;
title: string;
uniqueOccurrences: number;
};
counts: number[];
};
@@ -0,0 +1,52 @@
/*
* 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, { ReactNode } from 'react';
import {
Header,
Page,
pageTheme,
Content,
ContentHeader,
SupportButton,
} from '@backstage/core';
import { Grid } from '@material-ui/core';
type Props = {
title?: string;
children: ReactNode;
};
export const RollbarLayout = ({ title = 'Dashboard', children }: Props) => {
return (
<Page theme={pageTheme.tool}>
<Header
title="Rollbar"
subtitle="Real-time error tracking & debugging tools for developers"
/>
<Content>
<ContentHeader title={title}>
<SupportButton>
Rollbar plugin allows you to preview issues and navigate to rollbar.
</SupportButton>
</ContentHeader>
<Grid container spacing={3} direction="column">
{children}
</Grid>
</Content>
</Page>
);
};
@@ -0,0 +1,47 @@
/*
* 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 } from '@backstage/core';
import { wrapInTestApp } from '@backstage/test-utils';
import { render } from '@testing-library/react';
import { RollbarApi, rollbarApiRef } from '../../api/RollbarApi';
import { RollbarProject } from '../../api/types';
import { RollbarPage } from './RollbarPage';
describe('RollbarPage 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 renderWrapped = (children: React.ReactNode) =>
render(
wrapInTestApp(
<ApiProvider apis={ApiRegistry.from([[rollbarApiRef, rollbarApi]])}>
{children}
</ApiProvider>,
),
);
it('should render rollbar landing page', async () => {
const rendered = renderWrapped(<RollbarPage />);
expect(rendered.getByText(/Rollbar/)).toBeInTheDocument();
});
});
@@ -0,0 +1,33 @@
/*
* 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 { useAsync } from 'react-use';
import { useApi } from '@backstage/core';
import { rollbarApiRef } from '../../api/RollbarApi';
import { RollbarLayout } from '../RollbarLayout/RollbarLayout';
import { RollbarProjectTable } from './RollbarProjectTable';
export const RollbarPage = () => {
const rollbarApi = useApi(rollbarApiRef);
const { value, loading } = useAsync(() => rollbarApi.getAllProjects());
return (
<RollbarLayout>
<RollbarProjectTable loading={loading} projects={value || []} />
</RollbarLayout>
);
};
@@ -0,0 +1,72 @@
/*
* 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 } from 'react-router-dom';
import { Link } from '@material-ui/core';
import { Table, TableColumn } from '@backstage/core';
import { RollbarProject } from '../../api/types';
const columns: TableColumn[] = [
{
title: 'ID',
field: 'id',
type: 'numeric',
align: 'left',
width: '100px',
},
{
title: 'Name',
field: 'name',
type: 'string',
align: 'left',
highlight: true,
render: (row: Partial<RollbarProject>) => (
<Link component={RouterLink} to={`/rollbar/${row.name}`}>
{row.name}
</Link>
),
},
{
title: 'Status',
field: 'status',
type: 'string',
align: 'left',
},
];
type Props = {
projects: RollbarProject[];
loading: boolean;
};
export const RollbarProjectTable = ({ projects, loading }: Props) => {
return (
<Table
isLoading={loading}
columns={columns}
options={{
padding: 'dense',
paging: true,
search: true,
pageSize: 10,
showEmptyDataSourceMessage: !loading,
}}
title="Projects"
data={projects}
/>
);
};
@@ -0,0 +1,60 @@
/*
* 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 } from '@backstage/core';
import { wrapInTestApp } from '@backstage/test-utils';
import { render } from '@testing-library/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 occured',
uniqueOccurrences: 10,
},
counts: [10, 10, 10, 10, 10, 50],
},
];
const rollbarApi: Partial<RollbarApi> = {
getTopActiveItems: () => Promise.resolve(items),
};
const renderWrapped = (children: React.ReactNode) =>
render(
wrapInTestApp(
<ApiProvider apis={ApiRegistry.from([[rollbarApiRef, rollbarApi]])}>
{children}
</ApiProvider>,
),
);
it('should render rollbar project page', async () => {
const rendered = renderWrapped(<RollbarProjectPage />);
expect(rendered.getByText(/Top Active Items/)).toBeInTheDocument();
});
});
@@ -0,0 +1,43 @@
/*
* 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 { useParams } from 'react-router-dom';
import { useAsync } from 'react-use';
import { useApi } from '@backstage/core';
import { rollbarApiRef } from '../../api/RollbarApi';
import { RollbarLayout } from '../RollbarLayout/RollbarLayout';
import { RollbarTopItemsTable } from '../RollbarTopItemsTable/RollbarTopItemsTable';
export const RollbarProjectPage = () => {
const rollbarApi = useApi(rollbarApiRef);
const { componentId } = useParams() as {
componentId: string;
};
const { value, loading } = useAsync(() =>
rollbarApi
.getTopActiveItems(componentId, 168)
.then(data =>
data.sort((a, b) => b.item.occurrences - a.item.occurrences),
),
);
return (
<RollbarLayout>
<RollbarTopItemsTable loading={loading} items={value || []} />
</RollbarLayout>
);
};
@@ -0,0 +1,57 @@
/*
* 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 { 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';
const items: RollbarTopActiveItem[] = [
{
item: {
id: 89898989,
counter: 1234,
environment: 'production',
framework: 0,
lastOccurrenceTimestamp: new Date().getTime() / 1000,
level: 50,
occurrences: 150,
title: 'Error in foo',
uniqueOccurrences: 40,
projectId: 12345,
},
counts: [10, 20, 30, 40, 50],
},
];
describe('RollbarTopItemsTable component', () => {
it('should render empty data message when loaded and no data', async () => {
const rendered = render(
wrapInTestApp(<RollbarTopItemsTable items={[]} loading={false} />),
);
expect(rendered.getByText(/No records to display/)).toBeInTheDocument();
});
it('should display item attributes when loading has finished', async () => {
const rendered = render(
wrapInTestApp(<RollbarTopItemsTable items={items} loading={false} />),
);
expect(rendered.getByText(/1234/)).toBeInTheDocument();
expect(rendered.getByText(/Error in foo/)).toBeInTheDocument();
expect(rendered.getByText(/critical/)).toBeInTheDocument();
});
});
@@ -0,0 +1,102 @@
/*
* 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 { Table, TableColumn } from '@backstage/core';
import {
RollbarFrameworkId,
RollbarLevel,
RollbarTopActiveItem,
} from '../../api/types';
import { RollbarTrendGraph } from '../RollbarTrendGraph/RollbarTrendGraph';
const columns: TableColumn[] = [
{
title: 'ID',
field: 'item.counter',
type: 'string',
align: 'left',
width: '70px',
},
{
title: 'Title',
field: 'item.title',
type: 'string',
align: 'left',
},
{
title: 'Trend',
sorting: false,
render: data => (
<RollbarTrendGraph counts={(data as RollbarTopActiveItem).counts} />
),
},
{
title: 'Occurrences',
field: 'item.occurrences',
type: 'numeric',
align: 'right',
},
{
title: 'Environment',
field: 'item.environment',
type: 'string',
},
{
title: 'Level',
field: 'item.level',
type: 'string',
render: data => RollbarLevel[(data as RollbarTopActiveItem).item.level],
},
{
title: 'Framework',
field: 'item.framework',
type: 'string',
render: data =>
RollbarFrameworkId[(data as RollbarTopActiveItem).item.framework],
},
{
title: 'Last Occurrence',
field: 'item.lastOccurrenceTimestamp',
type: 'datetime',
render: data =>
new Date(
(data as RollbarTopActiveItem).item.lastOccurrenceTimestamp * 1000,
).toLocaleDateString(),
},
];
type Props = {
items: RollbarTopActiveItem[];
loading: boolean;
};
export const RollbarTopItemsTable = ({ items, loading }: Props) => {
return (
<Table
isLoading={loading}
columns={columns}
options={{
padding: 'dense',
paging: false,
search: true,
showEmptyDataSourceMessage: !loading,
}}
title="Top Active Items"
data={items}
/>
);
};
@@ -0,0 +1,32 @@
/*
* 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 { render } from '@testing-library/react';
import { wrapInTestApp } from '@backstage/test-utils';
import { RollbarTrendGraph } from './RollbarTrendGraph';
describe('RollbarTrendGraph component', () => {
it('should render a trend graph sparkline', async () => {
const mockCounts = [1, 2, 3, 4];
const rendered = render(
wrapInTestApp(
<RollbarTrendGraph counts={mockCounts} data-testid="graph" />,
),
);
expect(rendered).toBeTruthy();
});
});
@@ -0,0 +1,30 @@
/*
* 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 { Sparklines, SparklinesBars } from 'react-sparklines';
type Props = {
counts: number[];
};
export const RollbarTrendGraph = ({ counts }: Props) => {
return (
<Sparklines data={counts} svgHeight={48} min={0} margin={4}>
<SparklinesBars barWidth={2} />
</Sparklines>
);
};
+20
View File
@@ -0,0 +1,20 @@
/*
* 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.
*/
export { plugin } from './plugin';
export * from './api/RollbarApi';
export { RollbarClient } from './api/RollbarClient';
export { RollbarMockClient } from './api/RollbarMockClient';
+23
View File
@@ -0,0 +1,23 @@
/*
* 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 { plugin } from './plugin';
describe('rollbar', () => {
it('should export plugin', () => {
expect(plugin).toBeDefined();
});
});
+28
View File
@@ -0,0 +1,28 @@
/*
* 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 { createPlugin } from '@backstage/core';
import { RollbarPage } from './components/RollbarPage/RollbarPage';
import { RollbarProjectPage } from './components/RollbarProjectPage/RollbarProjectPage';
import { rootRoute, rootProjectRoute } from './routes';
export const plugin = createPlugin({
id: 'rollbar',
register({ router }) {
router.addRoute(rootRoute, RollbarPage);
router.addRoute(rootProjectRoute, RollbarProjectPage);
},
});
+27
View File
@@ -0,0 +1,27 @@
/*
* 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';
export const rootRoute = createRouteRef({
path: '/rollbar',
title: 'Rollbar Home',
});
export const rootProjectRoute = createRouteRef({
path: '/rollbar/:componentId/*',
title: 'Rollbar',
});
+19
View File
@@ -0,0 +1,19 @@
/*
* 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 '@testing-library/jest-dom';
require('jest-fetch-mock').enableMocks();