Skip to content

Commit

Permalink
release: 0.15.0 (#128)
Browse files Browse the repository at this point in the history
### Description

This release updates the `PagerDutyPage` component to add a new
configurations tab where users can configure how they want to sync
service dependencies between Backstage and PagerDuty.

<img width="811" alt="image"
src="https://github.com/user-attachments/assets/f8332378-2439-4b7d-b130-b73acccd666b">

**By default, service dependency syncing is disabled.** It's an opt-in
feature and admins need to be aware of what it does because you might
end up deleting existing service dependencies on Backstage or PagerDuty.

‼️ Important: Due to a Backstage design decision it is not possible to
fully overwrite the relations specified in each entity's configuration
file. For that reason the option to synchronise strictly from PagerDuty
side is not available.

On this release we also introduced a fix that was preventing users from
showing/hiding columns on the service to entity mapping table (#123).

## Acknowledgement

By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.

**Disclaimer:** We value your time and bandwidth. As such, any pull
requests created on non-triaged issues might not be successful.
  • Loading branch information
t1agob authored Jul 25, 2024
2 parents ada7bba + 5cdf6bc commit d284af6
Show file tree
Hide file tree
Showing 8 changed files with 301 additions and 28 deletions.
9 changes: 9 additions & 0 deletions dev/mockPagerDutyApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@ import { Entity } from '@backstage/catalog-model';
import { v4 as uuidv4 } from 'uuid';

export const mockPagerDutyApi: PagerDutyApi = {
async getSetting(id: string) {
return {
id: id,
value: 'backstage',
};
},
async storeSettings(settings) {
return new Response(JSON.stringify(settings));
},
async getEntityMappings() {
return {
mappings: [
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"@mui/icons-material": "^5.15.19",
"@mui/material": "^5.15.19",
"@mui/x-date-pickers": "^7.6.1",
"@pagerduty/backstage-plugin-common": "0.2.0",
"@pagerduty/backstage-plugin-common": "0.2.1",
"@tanstack/react-query": "^5.40.1",
"classnames": "^2.2.6",
"luxon": "^3.4.1",
Expand Down
80 changes: 79 additions & 1 deletion src/api/client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import { MockFetchApi } from '@backstage/test-utils';
import { DiscoveryApi } from '@backstage/core-plugin-api';
import { PagerDutyClient, UnauthorizedError } from './client';
import { PagerDutyService } from '@pagerduty/backstage-plugin-common';
import { PagerDutyService, PagerDutySetting } from '@pagerduty/backstage-plugin-common';
import { NotFoundError } from '@backstage/errors';
import { Entity } from '@backstage/catalog-model';

Expand Down Expand Up @@ -365,3 +365,81 @@ describe('PagerDutyClient', () => {
});
});
});

describe('getSetting', () => {
const settingId = 'settingId';
const setting: PagerDutySetting = {
id: settingId,
value: 'disabled',
};

beforeEach(() => {
mockFetch.mockResolvedValueOnce({
status: 200,
ok: true,
json: () => Promise.resolve(setting),
});
});

it('should fetch the setting by ID', async () => {
const result = await client.getSetting(settingId);

expect(result).toEqual(setting);
expect(mockFetch).toHaveBeenCalledWith(
'http://localhost:7007/pagerduty/settings/settingId',
requestHeaders,
);
});

describe('storeSettings', () => {
const settings: PagerDutySetting[] = [
{
id: 'setting1',
value: 'disabled',
},
{
id: 'setting2',
value: 'backstage',
},
];

beforeEach(() => {
mockFetch.mockReset();
});

it('should send a POST request to the correct URL with the settings', async () => {
const response = new Response(null, { status: 200 });
mockFetch.mockResolvedValueOnce(response);

const expectedUrl = 'http://localhost:7007/pagerduty/settings';
const expectedOptions = {
method: 'POST',
headers: {
'Content-Type': 'application/json; charset=UTF-8',
Accept: 'application/json, text/plain, */*',
},
body: JSON.stringify(settings),
};

await expect(client.storeSettings(settings)).resolves.toEqual(response);
expect(mockFetch).toHaveBeenCalledWith(expectedUrl, expectedOptions);
});

it('should throw an error if the request fails', async () => {
const errorResponse = {
status: 500,
ok: false,
json: () =>
Promise.resolve({
errors: ['Internal server error'],
}),
};
mockFetch.mockResolvedValueOnce(errorResponse);

await expect(client.storeSettings(settings)).rejects.toThrow(
'Request failed with 500, Internal server error',
);
});
});

});
30 changes: 29 additions & 1 deletion src/api/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ import { PagerDutyChangeEventsResponse,
PagerDutyIncidentsResponse,
PagerDutyServiceStandardsResponse,
PagerDutyServiceMetricsResponse,
PagerDutyEntityMappingsResponse
PagerDutyEntityMappingsResponse,
PagerDutySetting
} from '@pagerduty/backstage-plugin-common';
import { createApiRef, ConfigApi } from '@backstage/core-plugin-api';
import { NotFoundError } from '@backstage/errors';
Expand Down Expand Up @@ -106,6 +107,33 @@ export class PagerDutyClient implements PagerDutyApi {
return response;
}

async getSetting(id: string): Promise<PagerDutySetting> {
const url = `${await this.config.discoveryApi.getBaseUrl(
'pagerduty',
)}/settings/${id}`;

return await this.findByUrl<PagerDutySetting>(url);
}

async storeSettings(settings: PagerDutySetting[]): Promise<Response> {
const body = JSON.stringify(settings);

const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json; charset=UTF-8',
Accept: 'application/json, text/plain, */*',
},
body,
};

const url = `${await this.config.discoveryApi.getBaseUrl(
'pagerduty',
)}/settings`;

return this.request(url, options);
}

async getEntityMappings(): Promise<PagerDutyEntityMappingsResponse> {
const url = `${await this.config.discoveryApi.getBaseUrl(
'pagerduty',
Expand Down
13 changes: 12 additions & 1 deletion src/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import { PagerDutyChangeEventsResponse,
PagerDutyServiceMetricsResponse,
PagerDutyServiceStandards,
PagerDutyServiceMetrics,
PagerDutyEntityMappingsResponse
PagerDutyEntityMappingsResponse,
PagerDutySetting
} from '@pagerduty/backstage-plugin-common';
import { DiscoveryApi, FetchApi } from '@backstage/core-plugin-api';
import { Entity } from '@backstage/catalog-model';
Expand Down Expand Up @@ -52,6 +53,16 @@ export type PagerDutyCardServiceResponse = {

/** @public */
export interface PagerDutyApi {
/**
* Fetches PagerDuty setting from store.
*
*/
getSetting(id: string): Promise<PagerDutySetting>;
/**
* Stores PagerDuty setting in the database.
*
*/
storeSettings(settings: PagerDutySetting[]): Promise<Response>;
/**
* Fetches all entity mappings.
*
Expand Down
16 changes: 14 additions & 2 deletions src/components/PagerDutyPage/MappingTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ export const MappingTable = ({
const columns = useMemo<MRT_ColumnDef<PagerDutyEntityMapping>[]>(
() => [
{
id: "serviceId",
accessorKey: "serviceId",
header: "Service ID",
visibleInShowHideMenu: false,
Expand All @@ -109,34 +110,40 @@ export const MappingTable = ({
),
},
{
id: "integrationKey",
accessorKey: "integrationKey",
header: "Integration Key",
visibleInShowHideMenu: false,
enableEditing: false,
Edit: () => null,
},
{
id: "serviceName",
accessorKey: "serviceName",
header: "PagerDuty Service",
enableEditing: false,
},
{
id: "account",
accessorKey: "account",
header: "Account",
enableEditing: false,
Edit: () => null,
},
{
id: "team",
accessorKey: "team",
header: "Team",
enableEditing: false,
},
{
id: "escalationPolicy",
accessorKey: "escalationPolicy",
header: "Escalation Policy",
enableEditing: false,
},
{
id: "entityRef",
accessorKey: "entityRef",
header: "Mapping",
visibleInShowHideMenu: false,
Expand All @@ -151,12 +158,14 @@ export const MappingTable = ({
},
},
{
id: "entityName",
accessorKey: "entityName",
header: "Mapped Entity Name",
enableEditing: false,
Edit: () => null,
},
{
id: "status",
accessorKey: "status",
header: "Status",
enableEditing: false,
Expand All @@ -174,6 +183,7 @@ export const MappingTable = ({
),
},
{
id: "serviceUrl",
accessorKey: "serviceUrl",
header: "Service URL",
visibleInShowHideMenu: false,
Expand All @@ -190,9 +200,9 @@ export const MappingTable = ({
mutationFn: async (mapping: PagerDutyEntityMapping) => {
return await pagerDutyApi.storeServiceMapping(
mapping.serviceId,
mapping.integrationKey || "",
mapping.integrationKey ?? "",
mapping.entityRef,
mapping.account || ""
mapping.account ?? ""
);
},
});
Expand Down Expand Up @@ -297,6 +307,8 @@ export const MappingTable = ({
showAlertBanner:
mappings === undefined || catalogEntities === undefined,
showProgressBars: mappings.length === 0 || catalogEntities.length === 0,
},
initialState: {
columnVisibility: {
serviceId: false,
entityRef: false,
Expand Down
Loading

0 comments on commit d284af6

Please sign in to comment.