diff --git a/.gitignore b/.gitignore index 0f29597..870b4fb 100644 --- a/.gitignore +++ b/.gitignore @@ -108,6 +108,7 @@ dist dist-types dist-workspace assets +!src/assets # Gatsby files .cache/ diff --git a/src/api/client.ts b/src/api/client.ts index cd2f456..ac794e3 100644 --- a/src/api/client.ts +++ b/src/api/client.ts @@ -36,6 +36,9 @@ import { PagerDutyEntity } from '../types'; /** @public */ export class UnauthorizedError extends Error {} +/** @public */ +export class ForbiddenError extends Error { } + /** @public */ export const pagerDutyApiRef = createApiRef({ id: 'plugin.pagerduty.api', @@ -178,11 +181,15 @@ export class PagerDutyClient implements PagerDutyApi { ): Promise { const response = await this.config.fetchApi.fetch(url, options); if (response.status === 401) { - throw new UnauthorizedError(); + throw new UnauthorizedError("Unauthorized: You don't have access to this resource"); + } + + if (response.status === 403) { + throw new ForbiddenError("Forbidden: You are not allowed to perform this action"); } if (response.status === 404) { - throw new NotFoundError(); + throw new NotFoundError("Not Found: Resource not found"); } if (!response.ok) { diff --git a/src/assets/emptystate.svg b/src/assets/emptystate.svg index 8a04907..317868c 100644 --- a/src/assets/emptystate.svg +++ b/src/assets/emptystate.svg @@ -1 +1,6 @@ - + + + + + + diff --git a/src/assets/forbiddenstate.svg b/src/assets/forbiddenstate.svg new file mode 100644 index 0000000..f9ab332 --- /dev/null +++ b/src/assets/forbiddenstate.svg @@ -0,0 +1,25 @@ + + + +Created with Fabric.js 5.2.4 + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/components/ChangeEvents/ChangeEventForbiddenState.tsx b/src/components/ChangeEvents/ChangeEventForbiddenState.tsx new file mode 100644 index 0000000..3320d03 --- /dev/null +++ b/src/components/ChangeEvents/ChangeEventForbiddenState.tsx @@ -0,0 +1,37 @@ +/* + * Copyright 2020 The Backstage Authors + * + * 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-next-line @backstage/no-undeclared-imports +import React from 'react'; +import { Grid, Typography } from '@material-ui/core'; +import ForbiddenStateImage from '../../assets/forbiddenstate.svg'; + +export const ChangeEventForbiddenState = () => { + return ( + + + Feature not available with your account or token. + + + ForbiddenState + + + ); +}; diff --git a/src/components/ChangeEvents/ChangeEvents.test.tsx b/src/components/ChangeEvents/ChangeEvents.test.tsx index ca5bf08..d6e4858 100644 --- a/src/components/ChangeEvents/ChangeEvents.test.tsx +++ b/src/components/ChangeEvents/ChangeEvents.test.tsx @@ -44,6 +44,24 @@ describe('Incidents', () => { expect(getByText('No change events to display yet.')).toBeInTheDocument(); }); + it("Renders a forbidden state when change events is undefined", async () => { + mockPagerDutyApi.getChangeEventsByServiceId = jest + .fn() + .mockImplementationOnce(async () => {throw new Error("Forbidden: You allowed to perform this action");}); + + const { getByText, queryByTestId } = render( + wrapInTestApp( + + + + ) + ); + await waitFor(() => !queryByTestId("progress")); + expect( + getByText("Feature not available with your account or token.") + ).toBeInTheDocument(); + }); + it('Renders all change events', async () => { mockPagerDutyApi.getChangeEventsByServiceId = jest .fn() diff --git a/src/components/ChangeEvents/ChangeEvents.tsx b/src/components/ChangeEvents/ChangeEvents.tsx index f65ca8f..84d92f7 100644 --- a/src/components/ChangeEvents/ChangeEvents.tsx +++ b/src/components/ChangeEvents/ChangeEvents.tsx @@ -19,6 +19,7 @@ import React, { useEffect } from 'react'; import { List } from '@material-ui/core'; import { ChangeEventListItem } from './ChangeEventListItem'; import { ChangeEventEmptyState } from './ChangeEventEmptyState'; +import { ChangeEventForbiddenState } from './ChangeEventForbiddenState'; import useAsyncFn from 'react-use/lib/useAsyncFn'; import { pagerDutyApiRef } from '../../api'; import { useApi } from '@backstage/core-plugin-api'; @@ -45,6 +46,10 @@ export const ChangeEvents = ({ serviceId, refreshEvents }: Props) => { }, [refreshEvents, getChangeEvents]); if (error) { + if (error.message.includes('Forbidden')) { + return ; + } + return ( Error encountered while fetching information. {error.message}