@pagerduty/backstage-plugin 0.12.1-next.7 → 0.12.1-next.70
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/{index-814058ce.esm.js → index-aa780f0a.esm.js} +23 -5
- package/dist/esm/index-aa780f0a.esm.js.map +1 -0
- package/dist/esm/{index-76060cea.esm.js → index-bbb06199.esm.js} +2 -2
- package/dist/esm/{index-76060cea.esm.js.map → index-bbb06199.esm.js.map} +1 -1
- package/dist/esm/index-d604bce8.esm.js +195 -0
- package/dist/esm/index-d604bce8.esm.js.map +1 -0
- package/dist/index.d.ts +10 -4
- package/dist/index.esm.js +1 -1
- package/package.json +9 -3
- package/dist/esm/index-5125111c.esm.js +0 -166
- package/dist/esm/index-5125111c.esm.js.map +0 -1
- package/dist/esm/index-814058ce.esm.js.map +0 -1
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import React, { useState, useMemo } from 'react';
|
|
2
|
+
import { DialogTitle, DialogContent, DialogActions, Box, Tooltip, IconButton, Grid } from '@material-ui/core';
|
|
3
|
+
import { Page, Header, Content } from '@backstage/core-components';
|
|
4
|
+
import EditIcon from '@mui/icons-material/Edit';
|
|
5
|
+
import { useApi } from '@backstage/core-plugin-api';
|
|
6
|
+
import { p as pagerDutyApiRef } from './index-aa780f0a.esm.js';
|
|
7
|
+
import { QueryClient, QueryClientProvider, useQuery, useMutation } from '@tanstack/react-query';
|
|
8
|
+
import { useMaterialReactTable, MRT_EditActionButtons, MaterialReactTable } from 'material-react-table';
|
|
9
|
+
import { catalogApiRef } from '@backstage/plugin-catalog-react';
|
|
10
|
+
import '@backstage/errors';
|
|
11
|
+
import '@backstage/plugin-home-react';
|
|
12
|
+
import 'luxon';
|
|
13
|
+
import '@material-ui/icons/OpenInBrowser';
|
|
14
|
+
import '../assets/emptystate.svg';
|
|
15
|
+
import 'react-use/lib/useAsyncFn';
|
|
16
|
+
import '@material-ui/lab';
|
|
17
|
+
import '../assets/forbiddenstate.svg';
|
|
18
|
+
import '@material-ui/core/Avatar';
|
|
19
|
+
import '@material-ui/icons/Notifications';
|
|
20
|
+
import 'react-use/lib/useAsync';
|
|
21
|
+
import '@material-ui/icons/Link';
|
|
22
|
+
import '../assets/PD-Green.svg';
|
|
23
|
+
import '../assets/PD-White.svg';
|
|
24
|
+
import 'validate-color';
|
|
25
|
+
import '@material-ui/icons/Info';
|
|
26
|
+
import '@material-ui/icons/CheckCircle';
|
|
27
|
+
import '@material-ui/icons/RadioButtonUnchecked';
|
|
28
|
+
import '@material-ui/core/styles';
|
|
29
|
+
import 'react-use';
|
|
30
|
+
import '@material-ui/lab/Alert/Alert';
|
|
31
|
+
import '@backstage/catalog-model';
|
|
32
|
+
import '@material-ui/icons/AddAlert';
|
|
33
|
+
import '@material-ui/icons/ExpandMore';
|
|
34
|
+
|
|
35
|
+
const ServiceMappingComponent = () => {
|
|
36
|
+
const [catalogEntities, setCatalogEntities] = useState([]);
|
|
37
|
+
const pagerDutyApi = useApi(pagerDutyApiRef);
|
|
38
|
+
const catalogApi = useApi(catalogApiRef);
|
|
39
|
+
function useGetMappings() {
|
|
40
|
+
return useQuery({
|
|
41
|
+
queryKey: ["mappings"],
|
|
42
|
+
queryFn: async () => {
|
|
43
|
+
const { mappings: foundMappings } = await pagerDutyApi.getEntityMappings();
|
|
44
|
+
return foundMappings;
|
|
45
|
+
},
|
|
46
|
+
refetchOnWindowFocus: false
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
function useUpdateMapping() {
|
|
50
|
+
return useMutation({
|
|
51
|
+
mutationFn: async (mapping) => {
|
|
52
|
+
await pagerDutyApi.storeServiceMapping(
|
|
53
|
+
mapping.serviceId,
|
|
54
|
+
mapping.entityRef
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
// client side optimistic update
|
|
58
|
+
// onMutate: (newMappingInfo: PagerDutyEntityMapping) => {
|
|
59
|
+
// queryClient.setQueryData(["mappings"], (prevMappings: any) =>
|
|
60
|
+
// prevMappings?.map((prevMapping: PagerDutyEntityMapping) =>
|
|
61
|
+
// prevMapping.serviceId === newMappingInfo.serviceId
|
|
62
|
+
// ? newMappingInfo
|
|
63
|
+
// : prevMapping
|
|
64
|
+
// )
|
|
65
|
+
// );
|
|
66
|
+
// },
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
function fetchCatalogEntities() {
|
|
70
|
+
catalogApi.getEntities({
|
|
71
|
+
filter: { kind: "Component" }
|
|
72
|
+
}).then(({ items }) => {
|
|
73
|
+
const entities = [];
|
|
74
|
+
items.forEach((entity) => {
|
|
75
|
+
var _a, _b, _c, _d, _e, _f;
|
|
76
|
+
entities.push({
|
|
77
|
+
name: (_a = entity.metadata) == null ? void 0 : _a.name,
|
|
78
|
+
id: (_c = (_b = entity.metadata) == null ? void 0 : _b.uid) != null ? _c : "",
|
|
79
|
+
system: JSON.stringify((_d = entity.spec) == null ? void 0 : _d.system) || "",
|
|
80
|
+
owner: JSON.stringify((_e = entity.spec) == null ? void 0 : _e.owner) || "",
|
|
81
|
+
lifecycle: JSON.stringify((_f = entity.spec) == null ? void 0 : _f.lifecycle) || ""
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
setCatalogEntities(entities);
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
function getCatalogEntityOptions() {
|
|
88
|
+
if (catalogEntities.length === 0) {
|
|
89
|
+
fetchCatalogEntities();
|
|
90
|
+
}
|
|
91
|
+
const options = catalogEntities.map((entity) => ({
|
|
92
|
+
value: entity.id,
|
|
93
|
+
label: entity.name
|
|
94
|
+
}));
|
|
95
|
+
return options;
|
|
96
|
+
}
|
|
97
|
+
const DenseTable = () => {
|
|
98
|
+
const [validationErrors, setValidationErrors] = useState({});
|
|
99
|
+
const columns = useMemo(
|
|
100
|
+
() => [
|
|
101
|
+
{
|
|
102
|
+
accessorKey: "serviceId",
|
|
103
|
+
header: "Service ID",
|
|
104
|
+
visibleInShowHideMenu: false,
|
|
105
|
+
enableEditing: false
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
accessorKey: "serviceName",
|
|
109
|
+
header: "PagerDuty Service",
|
|
110
|
+
enableEditing: false
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
accessorKey: "team",
|
|
114
|
+
header: "Team",
|
|
115
|
+
enableEditing: false
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
accessorKey: "escalationPolicy",
|
|
119
|
+
header: "Escalation Policy",
|
|
120
|
+
enableEditing: false
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
accessorKey: "entityRef",
|
|
124
|
+
header: "Mapping",
|
|
125
|
+
editVariant: "select",
|
|
126
|
+
editSelectOptions: getCatalogEntityOptions(),
|
|
127
|
+
muiEditTextFieldProps: {
|
|
128
|
+
select: true,
|
|
129
|
+
error: !!(validationErrors == null ? void 0 : validationErrors.state),
|
|
130
|
+
helperText: validationErrors == null ? void 0 : validationErrors.state
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
accessorKey: "status",
|
|
135
|
+
header: "Status",
|
|
136
|
+
enableEditing: false
|
|
137
|
+
}
|
|
138
|
+
],
|
|
139
|
+
[validationErrors]
|
|
140
|
+
);
|
|
141
|
+
const {
|
|
142
|
+
data: fetchedMappings = [],
|
|
143
|
+
isError: isLoadingMappingsError,
|
|
144
|
+
isFetching: isFetchingMappings,
|
|
145
|
+
isLoading: isLoadingMappings
|
|
146
|
+
} = useGetMappings();
|
|
147
|
+
const { mutateAsync: updateUser, isPending: isUpdatingMapping } = useUpdateMapping();
|
|
148
|
+
const handleSaveUser = async ({ values, table }) => {
|
|
149
|
+
await updateUser(values);
|
|
150
|
+
table.setEditingRow(null);
|
|
151
|
+
};
|
|
152
|
+
const dataTable = useMaterialReactTable({
|
|
153
|
+
columns,
|
|
154
|
+
data: fetchedMappings,
|
|
155
|
+
editDisplayMode: "modal",
|
|
156
|
+
// default ('row', 'cell', 'table', and 'custom' are also available)
|
|
157
|
+
enableEditing: true,
|
|
158
|
+
positionActionsColumn: "last",
|
|
159
|
+
getRowId: (row) => row.serviceId,
|
|
160
|
+
muiToolbarAlertBannerProps: isLoadingMappingsError ? {
|
|
161
|
+
color: "error",
|
|
162
|
+
children: "Error loading data"
|
|
163
|
+
} : void 0,
|
|
164
|
+
muiTableContainerProps: {
|
|
165
|
+
sx: {
|
|
166
|
+
minHeight: "500px"
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
onEditingRowCancel: () => setValidationErrors({}),
|
|
170
|
+
onEditingRowSave: handleSaveUser,
|
|
171
|
+
// optionally customize modal content
|
|
172
|
+
renderEditRowDialogContent: ({ table, row, internalEditComponents }) => /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(DialogTitle, null, "Edit Mapping"), /* @__PURE__ */ React.createElement(DialogContent, null, internalEditComponents, " "), /* @__PURE__ */ React.createElement(DialogActions, null, /* @__PURE__ */ React.createElement(MRT_EditActionButtons, { variant: "text", table, row }))),
|
|
173
|
+
renderRowActions: ({ row, table }) => /* @__PURE__ */ React.createElement(Box, { sx: { display: "flex" } }, /* @__PURE__ */ React.createElement(Tooltip, { title: "Edit" }, /* @__PURE__ */ React.createElement(IconButton, { onClick: () => table.setEditingRow(row) }, /* @__PURE__ */ React.createElement(EditIcon, null)))),
|
|
174
|
+
state: {
|
|
175
|
+
isLoading: isLoadingMappings,
|
|
176
|
+
// || isLoadingEntities,
|
|
177
|
+
isSaving: isUpdatingMapping,
|
|
178
|
+
showAlertBanner: isLoadingMappingsError,
|
|
179
|
+
// || isLoadingEntitiesError,
|
|
180
|
+
showProgressBars: isFetchingMappings
|
|
181
|
+
// || isFetchingEntities,
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
return /* @__PURE__ */ React.createElement(MaterialReactTable, { table: dataTable });
|
|
185
|
+
};
|
|
186
|
+
const queryClient = new QueryClient();
|
|
187
|
+
return /* @__PURE__ */ React.createElement(QueryClientProvider, { client: queryClient }, /* @__PURE__ */ React.createElement(DenseTable, null));
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
const PagerDutyPage = () => {
|
|
191
|
+
return /* @__PURE__ */ React.createElement(Page, { themeId: "home" }, /* @__PURE__ */ React.createElement(Header, { title: "PagerDuty", subtitle: "Advanced configurations" }), /* @__PURE__ */ React.createElement(Content, null, /* @__PURE__ */ React.createElement(Grid, { container: true, spacing: 3, direction: "column" }, /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(ServiceMappingComponent, null)))));
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
export { PagerDutyPage };
|
|
195
|
+
//# sourceMappingURL=index-d604bce8.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-d604bce8.esm.js","sources":["../../src/components/PagerDutyPage/ServiceMappingComponent.tsx","../../src/components/PagerDutyPage/index.tsx"],"sourcesContent":["import React, { useMemo, useState } from \"react\";\nimport {\n Box,\n // Button,\n DialogActions,\n DialogContent,\n DialogTitle,\n // FormControl,\n IconButton,\n // MenuItem,\n // Select,\n Tooltip,\n // Typography,\n} from \"@material-ui/core\";\nimport EditIcon from \"@mui/icons-material/Edit\";\nimport { PagerDutyEntityMapping } from \"@pagerduty/backstage-plugin-common\";\nimport { useApi } from \"@backstage/core-plugin-api\";\nimport { pagerDutyApiRef } from \"../../api\";\nimport {\n QueryClient,\n QueryClientProvider,\n useMutation,\n useQuery,\n} from \"@tanstack/react-query\";\nimport {\n DropdownOption,\n MRT_ColumnDef,\n MRT_EditActionButtons,\n MRT_TableOptions,\n MaterialReactTable,\n useMaterialReactTable,\n} from \"material-react-table\";\nimport { catalogApiRef } from \"@backstage/plugin-catalog-react\";\n// import { catalogApiRef } from \"@backstage/plugin-catalog-react\";\n// import { Entity } from \"@backstage/catalog-model\";\n\ntype Service = {\n name: string; // \"Ads\"\n id: string; // \"QWe1j283n12j132\"\n system: string; // \"Production\"\n owner: string; // \"Mapped\"\n lifecycle: string; // \"Ads\"\n};\n\n// type TableItem = {\n// name: string | undefined;\n// team: string | undefined;\n// escalationPolicy: string | undefined;\n// mappingStatus: JSX.Element;\n// mapping: JSX.Element;\n// actions: JSX.Element;\n// };\n\n// type DenseTableProps = {\n// items: TableItem[];\n// };\n\n// function getColorFromStatus(status?: string) {\n// switch (status) {\n// case \"InSync\":\n// return \"green\";\n// case \"OutOfSync\":\n// return \"red\";\n// case \"NotMapped\":\n// return \"orange\";\n// default:\n// return \"gray\";\n// }\n// }\n\nexport const ServiceMappingComponent = () => {\n // const [catalogEntities, setCatalogEntities] = useState<Service[]>([]);\n // const [, setServiceMappings] = useState<PagerDutyEntityMapping[]>([]);\n // const [tableData, setTableData] = useState<TableItem[]>([]);\n // const [isLoading, setIsLoading] = useState(true);\n\n // const pagerDutyApi = useApi(pagerDutyApiRef);\n // const catalogApi = useApi(catalogApiRef);\n\n // useEffect(() => {\n // async function fetchEntities(): Promise<Service[]> {\n // const { items } = await catalogApi.getEntities({\n // filter: { kind: \"Component\" },\n // });\n\n // const backstageServices: Service[] = [];\n // items.forEach((entity: Entity) => {\n // backstageServices.push({\n // name: entity.metadata?.name,\n // id: entity.metadata?.uid ?? \"\",\n // system: JSON.stringify(entity.spec?.system) || \"\",\n // owner: JSON.stringify(entity.spec?.owner) || \"\",\n // lifecycle: JSON.stringify(entity.spec?.lifecycle) || \"\",\n // });\n // });\n\n // return backstageServices;\n // }\n\n // async function fetchServices(): Promise<PagerDutyEntityMapping[]> {\n // const { mappings: foundServices } = await pagerDutyApi.getEntityMappings();\n\n // return foundServices;\n // }\n\n // if (catalogEntities.length === 0) {\n // Promise.all([fetchEntities(), fetchServices()]).then(\n // ([entities, mappings]) => {\n // setCatalogEntities(entities);\n // setServiceMappings(mappings);\n\n // const data: TableItem[] = buildTableData(\n // entities,\n // mappings\n // );\n\n // setTableData(data);\n // setIsLoading(false);\n // }\n // );\n // }\n // }, [catalogApi, catalogEntities, pagerDutyApi]);\n\n // function buildTableData(\n // entities: Service[],\n // mappings: PagerDutyEntityMapping[]\n // ): TableItem[] {\n // const data: TableItem[] = mappings.map((service) => {\n // return {\n // name: service.serviceName,\n // team: service.team,\n // escalationPolicy: service.escalationPolicy,\n // // status of mapping\n // mappingStatus: (\n // <Typography\n // variant=\"body2\"\n // style={{\n // color: getColorFromStatus(service.status),\n // }}\n // >\n // {service.status}\n // </Typography>\n // ),\n // mapping: (\n // // dropdown menu with static options. If service.mapping is defined select that option\n // <FormControl variant=\"standard\">\n // <Select\n // displayEmpty\n // onChange={(selection) => {\n // handleMappingChange(service, selection);\n\n // }}\n // value={service.entityRef}\n // >\n // <MenuItem value=\"\">\n // <em>None</em>\n // </MenuItem>\n // {entities.map((backstageService) => {\n // return (\n // <MenuItem\n // key={backstageService.id}\n // value={backstageService.id}\n // >\n // {backstageService.name}\n // </MenuItem>\n // );\n // })}\n // </Select>\n // </FormControl>\n // ),\n // actions: (\n // <Button variant=\"contained\" color=\"primary\" href={service.serviceUrl}>\n // Open in PagerDuty\n // </Button>\n // ),\n // };\n // });\n\n // return data;\n // }\n\n // async function handleMappingChange(\n // service: PagerDutyEntityMapping,\n // event: ChangeEvent<{\n // name?: string | undefined;\n // value: unknown;\n // }>\n // ) {\n // // event.preventDefault();\n // const updatedData = [...tableData];\n\n // // find the service in updatedData\n // updatedData.findIndex((item) => item.name === service.serviceName);\n // // // updatedData[serviceIndex].mappingStatus = (\n // // // <Typography\n // // // variant=\"body2\"\n // // // style={{\n // // // color: getColorFromStatus(\"OutOfSync\"),\n // // // }}\n // // // >\n // // // \"OutOfSync\"\n // // // </Typography>\n // // // );\n\n // // // update the mapping status\n // // // service.status = \"OutOfSync\";\n\n // // // // update the mapping\n // // // service.entityRef = entityId;\n\n // // // store the mapping in the database\n // await pagerDutyApi.storeServiceMapping(\n // service.serviceId,\n // event.target.value as string\n // );\n // setTableData(updatedData);\n // }\n\n // const DenseTable = ({ items }: DenseTableProps) => {\n // // const [data, _] = useState<TableItem[]>(items);\n\n // // useEffect(() => {\n // // setData(items);\n // // }, [items]);\n\n // const columns: TableColumn[] = [\n // { title: \"PagerDuty Service\", field: \"name\" },\n // { title: \"Team\", field: \"team\" },\n // { title: \"Escalation Policy\", field: \"escalationPolicy\" },\n // { title: \"Mapping\", field: \"mapping\" },\n // { title: \"Status\", field: \"mappingStatus\" },\n // { title: \"Actions\", field: \"actions\" },\n // ];\n\n // return (\n // <Table\n // isLoading={isLoading}\n // title=\"PagerDuty Service Import\"\n // subtitle=\"Use this page to import services from PagerDuty and map them to existing Backstage services. Only 1:1 mapping is allowed.\"\n // options={{\n // search: true,\n // paging: true,\n // pageSize: 10,\n // pageSizeOptions: [10, 25, 50],\n // sorting: true,\n // emptyRowsWhenPaging: false,\n // showFirstLastPageButtons: true,\n // columnResizable: true,\n // columnsButton: true,\n // rowStyle: {\n // height: \"10px\",\n // },\n // padding: \"dense\",\n // }}\n // columns={columns}\n // data={items}\n // />\n // );\n // };\n\n // return <DenseTable items={tableData} />;\n\n const [catalogEntities, setCatalogEntities] = useState<Service[]>([]);\n\n const pagerDutyApi = useApi(pagerDutyApiRef);\n const catalogApi = useApi(catalogApiRef);\n\n // function useGetCatalogEntities() {\n // return useQuery<DropdownOption[]>({\n // queryKey: [\"catalogEntities\"],\n // queryFn: async () => {\n // // send api request here\n // const { items } = await catalogApi.getEntities({\n // filter: { kind: \"Component\" },\n // });\n\n // const entities: DropdownOption[] = [];\n // items.forEach((entity: Entity) => {\n // entities.push({\n // value: entity.metadata?.uid ?? \"\",\n // label: entity.metadata?.name,\n // });\n // });\n\n // return entities;\n // },\n // refetchOnWindowFocus: false,\n // });\n // }\n // const {\n // data: fetchedEntities = [],\n // isError: isLoadingEntitiesError,\n // isFetching: isFetchingEntities,\n // isLoading: isLoadingEntities,\n // } = useGetCatalogEntities();\n\n // READ hook (get mappings from api)\n function useGetMappings() {\n return useQuery<PagerDutyEntityMapping[]>({\n queryKey: [\"mappings\"],\n queryFn: async () => {\n // send api request here\n const { mappings: foundMappings } =\n await pagerDutyApi.getEntityMappings();\n\n return foundMappings;\n },\n refetchOnWindowFocus: false,\n });\n }\n\n // UPDATE hook (put mapping in api)\n function useUpdateMapping() {\n // const queryClient = useQueryClient();\n return useMutation({\n mutationFn: async (mapping: PagerDutyEntityMapping) => {\n await pagerDutyApi.storeServiceMapping(\n mapping.serviceId,\n mapping.entityRef\n );\n },\n // client side optimistic update\n // onMutate: (newMappingInfo: PagerDutyEntityMapping) => {\n // queryClient.setQueryData([\"mappings\"], (prevMappings: any) =>\n // prevMappings?.map((prevMapping: PagerDutyEntityMapping) =>\n // prevMapping.serviceId === newMappingInfo.serviceId\n // ? newMappingInfo\n // : prevMapping\n // )\n // );\n // },\n });\n }\n\n function fetchCatalogEntities() {\n catalogApi\n .getEntities({\n filter: { kind: \"Component\" },\n })\n .then(({ items }) => {\n const entities: Service[] = [];\n items.forEach((entity: any) => {\n entities.push({\n name: entity.metadata?.name,\n id: entity.metadata?.uid ?? \"\",\n system: JSON.stringify(entity.spec?.system) || \"\",\n owner: JSON.stringify(entity.spec?.owner) || \"\",\n lifecycle: JSON.stringify(entity.spec?.lifecycle) || \"\",\n });\n });\n setCatalogEntities(entities);\n });\n }\n\n function getCatalogEntityOptions() : DropdownOption[] {\n\n // fetch entities if not already fetched\n if (catalogEntities.length === 0) {\n fetchCatalogEntities();\n }\n \n const options : DropdownOption[] = catalogEntities.map((entity) => ({\n value: entity.id,\n label: entity.name,\n }));\n\n return options;\n }\n\n const DenseTable = () => {\n const [validationErrors, setValidationErrors] = useState<\n Record<string, string | undefined>\n >({});\n\n const columns = useMemo<MRT_ColumnDef<PagerDutyEntityMapping>[]>(\n () => [\n {\n accessorKey: \"serviceId\",\n header: \"Service ID\",\n visibleInShowHideMenu: false,\n enableEditing: false,\n },\n {\n accessorKey: \"serviceName\",\n header: \"PagerDuty Service\",\n enableEditing: false,\n },\n {\n accessorKey: \"team\",\n header: \"Team\",\n enableEditing: false,\n },\n {\n accessorKey: \"escalationPolicy\",\n header: \"Escalation Policy\",\n enableEditing: false,\n },\n {\n accessorKey: \"entityRef\",\n\n header: \"Mapping\",\n editVariant: \"select\",\n editSelectOptions: getCatalogEntityOptions(),\n muiEditTextFieldProps: {\n select: true,\n error: !!validationErrors?.state,\n helperText: validationErrors?.state,\n },\n },\n {\n accessorKey: \"status\",\n header: \"Status\",\n enableEditing: false,\n },\n ],\n [validationErrors]\n );\n\n // call READ hook\n const {\n data: fetchedMappings = [],\n isError: isLoadingMappingsError,\n isFetching: isFetchingMappings,\n isLoading: isLoadingMappings,\n } = useGetMappings();\n\n // call UPDATE hook\n const { mutateAsync: updateUser, isPending: isUpdatingMapping } =\n useUpdateMapping();\n\n // UPDATE action\n const handleSaveUser: MRT_TableOptions<PagerDutyEntityMapping>[\"onEditingRowSave\"] =\n async ({ values, table }) => {\n await updateUser(values);\n table.setEditingRow(null); // exit editing mode\n };\n\n const dataTable = useMaterialReactTable({\n columns,\n data: fetchedMappings,\n editDisplayMode: \"modal\", // default ('row', 'cell', 'table', and 'custom' are also available)\n enableEditing: true,\n positionActionsColumn: \"last\",\n getRowId: (row) => row.serviceId,\n muiToolbarAlertBannerProps: isLoadingMappingsError\n ? {\n color: \"error\",\n children: \"Error loading data\",\n }\n : undefined,\n muiTableContainerProps: {\n sx: {\n minHeight: \"500px\",\n },\n },\n onEditingRowCancel: () => setValidationErrors({}),\n onEditingRowSave: handleSaveUser,\n // optionally customize modal content\n renderEditRowDialogContent: ({ table, row, internalEditComponents }) => (\n <>\n <DialogTitle>Edit Mapping</DialogTitle>\n <DialogContent>\n {internalEditComponents}{\" \"}\n {/* or render custom edit components here */}\n </DialogContent>\n <DialogActions>\n <MRT_EditActionButtons variant=\"text\" table={table} row={row} />\n </DialogActions>\n </>\n ),\n renderRowActions: ({ row, table }) => (\n <Box sx={{ display: \"flex\" }}>\n <Tooltip title=\"Edit\">\n <IconButton onClick={() => table.setEditingRow(row)}>\n <EditIcon />\n </IconButton>\n </Tooltip>\n </Box>\n ),\n state: {\n isLoading: isLoadingMappings, // || isLoadingEntities,\n isSaving: isUpdatingMapping,\n showAlertBanner: isLoadingMappingsError, // || isLoadingEntitiesError,\n showProgressBars: isFetchingMappings, // || isFetchingEntities,\n },\n });\n\n // dataTable.setColumnVisibility({serviceId: false});\n\n return <MaterialReactTable table={dataTable} />;\n };\n\n const queryClient = new QueryClient();\n return (\n <QueryClientProvider client={queryClient}>\n <DenseTable />\n </QueryClientProvider>\n );\n};\n","import React from \"react\";\nimport { Grid } from \"@material-ui/core\";\nimport { Header, Page, Content } from \"@backstage/core-components\";\nimport { ServiceMappingComponent } from \"./ServiceMappingComponent\";\n\n/** @public */\nexport const PagerDutyPage = () => {\n return (\n <Page themeId=\"home\">\n <Header title=\"PagerDuty\" subtitle=\"Advanced configurations\" />\n <Content>\n {/* <Grid container spacing={3} direction=\"column\">\n <Grid item alignContent=\"flex-end\">\n <Button variant=\"contained\" color=\"primary\" onClick={() => {handleImport()}}>\n Import\n </Button>\n <Button variant=\"outlined\" color=\"primary\" onClick={() => {handleSave()}}>\n Save\n </Button>\n </Grid>\n </Grid> */}\n <Grid container spacing={3} direction=\"column\">\n <Grid item>\n <ServiceMappingComponent />\n </Grid>\n </Grid>\n </Content>\n </Page>\n );\n};\n"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import * as react from 'react';
|
|
|
5
5
|
import react__default, { ReactNode } from 'react';
|
|
6
6
|
import * as _backstage_core_plugin_api from '@backstage/core-plugin-api';
|
|
7
7
|
import { DiscoveryApi, FetchApi, ConfigApi } from '@backstage/core-plugin-api';
|
|
8
|
-
import {
|
|
8
|
+
import { PagerDutyEntityMappingResponse, PagerDutyServiceResponse, PagerDutyIncidentsResponse, PagerDutyChangeEventsResponse, PagerDutyServiceStandardsResponse, PagerDutyServiceMetricsResponse, PagerDutyUser } from '@pagerduty/backstage-plugin-common';
|
|
9
9
|
|
|
10
10
|
/** @public */
|
|
11
11
|
declare const isPluginApplicableToEntity$1: (entity: Entity) => boolean;
|
|
@@ -63,10 +63,15 @@ type PagerDutyTriggerAlarmRequest = {
|
|
|
63
63
|
/** @public */
|
|
64
64
|
interface PagerDutyApi {
|
|
65
65
|
/**
|
|
66
|
-
* Fetches all
|
|
66
|
+
* Fetches all entity mappings.
|
|
67
67
|
*
|
|
68
68
|
*/
|
|
69
|
-
|
|
69
|
+
getEntityMappings(): Promise<PagerDutyEntityMappingResponse>;
|
|
70
|
+
/**
|
|
71
|
+
* Stores the service mapping in the database.
|
|
72
|
+
*
|
|
73
|
+
*/
|
|
74
|
+
storeServiceMapping(serviceId: string, entityId: string): Promise<Response>;
|
|
70
75
|
/**
|
|
71
76
|
* Fetches the service for the provided pager duty Entity.
|
|
72
77
|
*
|
|
@@ -133,7 +138,8 @@ declare class PagerDutyClient implements PagerDutyApi {
|
|
|
133
138
|
static fromConfig(configApi: ConfigApi, dependencies: PagerDutyClientApiDependencies): PagerDutyClient;
|
|
134
139
|
constructor(config: PagerDutyClientApiConfig);
|
|
135
140
|
getServiceByPagerDutyEntity(pagerDutyEntity: PagerDutyEntity): Promise<PagerDutyServiceResponse>;
|
|
136
|
-
|
|
141
|
+
getEntityMappings(): Promise<PagerDutyEntityMappingResponse>;
|
|
142
|
+
storeServiceMapping(serviceId: string, backstageEntityId: string): Promise<Response>;
|
|
137
143
|
getServiceByEntity(entity: Entity): Promise<PagerDutyServiceResponse>;
|
|
138
144
|
getServiceById(serviceId: string): Promise<PagerDutyServiceResponse>;
|
|
139
145
|
getIncidentsByServiceId(serviceId: string): Promise<PagerDutyIncidentsResponse>;
|
package/dist/index.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { E as EntityPagerDutyCard, c as EntityPagerDutySmallCard, H as HomePagePagerDutyCard, f as PagerDutyCard, e as PagerDutyClient, b as PagerDutyPage, T as TriggerButton, U as UnauthorizedError, i as isPagerDutyAvailable, d as isPagerDutySmallCardAvailable, i as isPluginApplicableToEntity, p as pagerDutyApiRef, a as pagerDutyPlugin, a as plugin } from './esm/index-
|
|
1
|
+
export { E as EntityPagerDutyCard, c as EntityPagerDutySmallCard, H as HomePagePagerDutyCard, f as PagerDutyCard, e as PagerDutyClient, b as PagerDutyPage, T as TriggerButton, U as UnauthorizedError, i as isPagerDutyAvailable, d as isPagerDutySmallCardAvailable, i as isPluginApplicableToEntity, p as pagerDutyApiRef, a as pagerDutyPlugin, a as plugin } from './esm/index-aa780f0a.esm.js';
|
|
2
2
|
import '@backstage/core-plugin-api';
|
|
3
3
|
import '@backstage/errors';
|
|
4
4
|
import '@backstage/plugin-home-react';
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pagerduty/backstage-plugin",
|
|
3
3
|
"description": "A Backstage plugin that integrates towards PagerDuty",
|
|
4
|
-
"version": "0.12.1-next.
|
|
4
|
+
"version": "0.12.1-next.70",
|
|
5
5
|
"main": "dist/index.esm.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"license": "Apache-2.0",
|
|
@@ -41,16 +41,23 @@
|
|
|
41
41
|
"@backstage/plugin-catalog-react": "^1.9.1",
|
|
42
42
|
"@backstage/plugin-home-react": "^0.1.5",
|
|
43
43
|
"@backstage/theme": "^0.5.2",
|
|
44
|
+
"@emotion/react": "^11.11.4",
|
|
45
|
+
"@emotion/styled": "^11.11.5",
|
|
44
46
|
"@material-ui/core": "^4.12.2",
|
|
45
47
|
"@material-ui/icons": "^4.9.1",
|
|
46
48
|
"@material-ui/lab": "4.0.0-alpha.61",
|
|
49
|
+
"@mui/icons-material": "^5.15.19",
|
|
50
|
+
"@mui/material": "^5.15.19",
|
|
51
|
+
"@mui/x-date-pickers": "^7.6.1",
|
|
52
|
+
"@pagerduty/backstage-plugin-common": "^0.1.5-next.7",
|
|
53
|
+
"@tanstack/react-query": "^5.40.1",
|
|
47
54
|
"classnames": "^2.2.6",
|
|
48
55
|
"luxon": "^3.4.1",
|
|
56
|
+
"material-react-table": "^2.13.0",
|
|
49
57
|
"react-use": "^17.2.4",
|
|
50
58
|
"validate-color": "^2.2.4"
|
|
51
59
|
},
|
|
52
60
|
"peerDependencies": {
|
|
53
|
-
"@pagerduty/backstage-plugin-common": "^0.1.2",
|
|
54
61
|
"react": "^18.0.0 || ^20.0.0",
|
|
55
62
|
"react-dom": "^18.0.0 || ^20.0.0",
|
|
56
63
|
"react-router-dom": "^6.3.0"
|
|
@@ -62,7 +69,6 @@
|
|
|
62
69
|
"@backstage/test-utils": "^1.5.1",
|
|
63
70
|
"@commitlint/cli": "^17.7.1",
|
|
64
71
|
"@commitlint/config-conventional": "^17.7.0",
|
|
65
|
-
"@pagerduty/backstage-plugin-common": "^0.1.2",
|
|
66
72
|
"@testing-library/dom": "^8.0.0",
|
|
67
73
|
"@testing-library/jest-dom": "^5.10.1",
|
|
68
74
|
"@testing-library/react": "^12.1.3",
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { Typography, FormControl, InputLabel, Select, MenuItem, Button, Grid } from '@material-ui/core';
|
|
3
|
-
import { Table, Page, Header, Content } from '@backstage/core-components';
|
|
4
|
-
import { useApi } from '@backstage/core-plugin-api';
|
|
5
|
-
import { p as pagerDutyApiRef } from './index-814058ce.esm.js';
|
|
6
|
-
import { catalogApiRef } from '@backstage/plugin-catalog-react';
|
|
7
|
-
import { useAsync } from 'react-use';
|
|
8
|
-
import '@backstage/errors';
|
|
9
|
-
import '@backstage/plugin-home-react';
|
|
10
|
-
import 'luxon';
|
|
11
|
-
import '@material-ui/icons/OpenInBrowser';
|
|
12
|
-
import '../assets/emptystate.svg';
|
|
13
|
-
import 'react-use/lib/useAsyncFn';
|
|
14
|
-
import '@material-ui/lab';
|
|
15
|
-
import '../assets/forbiddenstate.svg';
|
|
16
|
-
import '@material-ui/core/Avatar';
|
|
17
|
-
import '@material-ui/icons/Notifications';
|
|
18
|
-
import 'react-use/lib/useAsync';
|
|
19
|
-
import '@material-ui/icons/Link';
|
|
20
|
-
import '../assets/PD-Green.svg';
|
|
21
|
-
import '../assets/PD-White.svg';
|
|
22
|
-
import 'validate-color';
|
|
23
|
-
import '@material-ui/icons/Info';
|
|
24
|
-
import '@material-ui/icons/CheckCircle';
|
|
25
|
-
import '@material-ui/icons/RadioButtonUnchecked';
|
|
26
|
-
import '@material-ui/core/styles';
|
|
27
|
-
import '@material-ui/lab/Alert/Alert';
|
|
28
|
-
import '@backstage/catalog-model';
|
|
29
|
-
import '@material-ui/icons/AddAlert';
|
|
30
|
-
import '@material-ui/icons/ExpandMore';
|
|
31
|
-
|
|
32
|
-
function getMappingStatus(serviceName) {
|
|
33
|
-
if (serviceName === "Ads") {
|
|
34
|
-
return "In Sync" /* InSync */;
|
|
35
|
-
}
|
|
36
|
-
return "Out Of Sync" /* OutOfSync */;
|
|
37
|
-
}
|
|
38
|
-
function getColorFromStatus(status) {
|
|
39
|
-
switch (status) {
|
|
40
|
-
case "In Sync" /* InSync */:
|
|
41
|
-
return "green";
|
|
42
|
-
case "Out Of Sync" /* OutOfSync */:
|
|
43
|
-
return "red";
|
|
44
|
-
default:
|
|
45
|
-
return "orange";
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
const DenseTable = ({ BackstageServices, PagerDutyServices }) => {
|
|
49
|
-
const columns = [
|
|
50
|
-
{ title: "PagerDuty Service", field: "name" },
|
|
51
|
-
{ title: "Team", field: "team" },
|
|
52
|
-
{ title: "Escalation Policy", field: "escalationPolicy" },
|
|
53
|
-
{ title: "Mapping", field: "mapping" },
|
|
54
|
-
{ title: "Status", field: "mappingStatus", width: "10%" },
|
|
55
|
-
{ title: "Actions", field: "actions" }
|
|
56
|
-
];
|
|
57
|
-
const data = PagerDutyServices.map((service) => {
|
|
58
|
-
var _a, _b;
|
|
59
|
-
const status = getMappingStatus(service.name);
|
|
60
|
-
return {
|
|
61
|
-
name: service.name,
|
|
62
|
-
team: (_b = (_a = service.teams) == null ? void 0 : _a.at(0)) == null ? void 0 : _b.summary,
|
|
63
|
-
escalationPolicy: service.escalation_policy.name,
|
|
64
|
-
mappingStatus: (
|
|
65
|
-
// status of mapping
|
|
66
|
-
/* @__PURE__ */ React.createElement(
|
|
67
|
-
Typography,
|
|
68
|
-
{
|
|
69
|
-
variant: "body2",
|
|
70
|
-
style: {
|
|
71
|
-
color: getColorFromStatus(status)
|
|
72
|
-
}
|
|
73
|
-
},
|
|
74
|
-
status
|
|
75
|
-
)
|
|
76
|
-
),
|
|
77
|
-
mapping: (
|
|
78
|
-
// dropdown menu with static options. If service.mapping is defined select that option
|
|
79
|
-
/* @__PURE__ */ React.createElement(FormControl, null, /* @__PURE__ */ React.createElement(InputLabel, { id: "demo-simple-select-helper-label" }, "Service"), /* @__PURE__ */ React.createElement(
|
|
80
|
-
Select,
|
|
81
|
-
{
|
|
82
|
-
labelId: "demo-simple-select-helper-label",
|
|
83
|
-
id: "demo-simple-select-helper"
|
|
84
|
-
},
|
|
85
|
-
/* @__PURE__ */ React.createElement(MenuItem, { value: "" }, /* @__PURE__ */ React.createElement("em", null, "None")),
|
|
86
|
-
BackstageServices.map((backstageService) => {
|
|
87
|
-
return /* @__PURE__ */ React.createElement(
|
|
88
|
-
MenuItem,
|
|
89
|
-
{
|
|
90
|
-
key: backstageService.name,
|
|
91
|
-
value: backstageService.name
|
|
92
|
-
},
|
|
93
|
-
backstageService.name
|
|
94
|
-
);
|
|
95
|
-
})
|
|
96
|
-
))
|
|
97
|
-
),
|
|
98
|
-
actions: /* @__PURE__ */ React.createElement(Button, { variant: "contained", color: "primary", href: service.html_url }, "Open in PagerDuty")
|
|
99
|
-
};
|
|
100
|
-
});
|
|
101
|
-
return /* @__PURE__ */ React.createElement(
|
|
102
|
-
Table,
|
|
103
|
-
{
|
|
104
|
-
title: "PagerDuty Service Import",
|
|
105
|
-
subtitle: "Use this page to import services from PagerDuty and map them to existing Backstage services ",
|
|
106
|
-
options: {
|
|
107
|
-
search: true,
|
|
108
|
-
paging: true,
|
|
109
|
-
pageSize: 10,
|
|
110
|
-
pageSizeOptions: [10, 25, 50],
|
|
111
|
-
sorting: true,
|
|
112
|
-
emptyRowsWhenPaging: false,
|
|
113
|
-
showFirstLastPageButtons: true,
|
|
114
|
-
columnResizable: true,
|
|
115
|
-
columnsButton: true,
|
|
116
|
-
rowStyle: {
|
|
117
|
-
height: "10px"
|
|
118
|
-
},
|
|
119
|
-
padding: "dense"
|
|
120
|
-
},
|
|
121
|
-
columns,
|
|
122
|
-
data
|
|
123
|
-
}
|
|
124
|
-
);
|
|
125
|
-
};
|
|
126
|
-
const ServiceMappingComponent = () => {
|
|
127
|
-
const backstageServices = [];
|
|
128
|
-
const pagerDutyApi = useApi(pagerDutyApiRef);
|
|
129
|
-
const catalogApi = useApi(catalogApiRef);
|
|
130
|
-
const {
|
|
131
|
-
value: pagerDutyServices,
|
|
132
|
-
loading,
|
|
133
|
-
error
|
|
134
|
-
} = useAsync(async () => {
|
|
135
|
-
catalogApi.getEntities(
|
|
136
|
-
{ filter: { kind: "Component" } }
|
|
137
|
-
).then(async (response) => {
|
|
138
|
-
response.items.forEach((entity) => {
|
|
139
|
-
var _a, _b, _c, _d, _e, _f;
|
|
140
|
-
backstageServices.push({
|
|
141
|
-
name: (_a = entity.metadata) == null ? void 0 : _a.name,
|
|
142
|
-
id: (_c = (_b = entity.metadata) == null ? void 0 : _b.uid) != null ? _c : "",
|
|
143
|
-
system: JSON.stringify((_d = entity.spec) == null ? void 0 : _d.system) || "",
|
|
144
|
-
owner: JSON.stringify((_e = entity.spec) == null ? void 0 : _e.owner) || "",
|
|
145
|
-
lifecycle: JSON.stringify((_f = entity.spec) == null ? void 0 : _f.lifecycle) || ""
|
|
146
|
-
});
|
|
147
|
-
});
|
|
148
|
-
const { services: foundServices } = await pagerDutyApi.getAllServices();
|
|
149
|
-
return foundServices;
|
|
150
|
-
});
|
|
151
|
-
}, []);
|
|
152
|
-
if (error) {
|
|
153
|
-
return /* @__PURE__ */ React.createElement("p", null, "Error: ", error.message);
|
|
154
|
-
}
|
|
155
|
-
if (loading) {
|
|
156
|
-
return /* @__PURE__ */ React.createElement("p", null, "Loading...");
|
|
157
|
-
}
|
|
158
|
-
return /* @__PURE__ */ React.createElement(DenseTable, { BackstageServices: backstageServices || [], PagerDutyServices: pagerDutyServices != null ? pagerDutyServices : [] });
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
const PagerDutyPage = () => {
|
|
162
|
-
return /* @__PURE__ */ React.createElement(Page, { themeId: "home" }, /* @__PURE__ */ React.createElement(Header, { title: "PagerDuty", subtitle: "Advanced configurations" }), /* @__PURE__ */ React.createElement(Content, null, /* @__PURE__ */ React.createElement(Grid, { container: true, spacing: 3, direction: "column" }, /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(ServiceMappingComponent, null)))));
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
export { PagerDutyPage };
|
|
166
|
-
//# sourceMappingURL=index-5125111c.esm.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-5125111c.esm.js","sources":["../../src/components/PagerDutyPage/ServiceMappingComponent.tsx","../../src/components/PagerDutyPage/index.tsx"],"sourcesContent":["import React from \"react\";\nimport {\n Table,\n TableColumn,\n} from \"@backstage/core-components\";\nimport { Button, FormControl, InputLabel, MenuItem, Select, Typography } from \"@material-ui/core\";\nimport { PagerDutyService } from \"@pagerduty/backstage-plugin-common\";\nimport { useApi } from \"@backstage/core-plugin-api\";\nimport { pagerDutyApiRef } from \"../../api\";\nimport { catalogApiRef } from \"@backstage/plugin-catalog-react\";\nimport { useAsync } from \"react-use\";\nimport { Entity } from \"@backstage/catalog-model\";\n\nenum MappingStatus { \n InSync = \"In Sync\", \n OutOfSync = \"Out Of Sync\", \n NotMapped = \"Not Mapped\"};\n\ntype Service = {\n name: string; // \"Ads\"\n id: string; // \"QWe1j283n12j132\"\n system: string; // \"Production\"\n owner: string; // \"Mapped\"\n lifecycle: string; // \"Ads\"\n};\n\n\ntype DenseTableProps = {\n BackstageServices: Service[];\n PagerDutyServices: PagerDutyService[];\n};\n\nfunction getMappingStatus(serviceName: string) : MappingStatus {\n \n if(serviceName === \"Ads\") {\n return MappingStatus.InSync;\n } \n \n return MappingStatus.OutOfSync;\n}\n\nfunction getColorFromStatus(status: MappingStatus) {\n switch (status) {\n case MappingStatus.InSync:\n return \"green\";\n case MappingStatus.OutOfSync:\n return \"red\";\n default:\n return \"orange\";\n }\n}\n\nexport const DenseTable = ({ BackstageServices, PagerDutyServices }: DenseTableProps) => {\n// const classes = useStyles();\n\n const columns: TableColumn[] = [\n { title: \"PagerDuty Service\", field: \"name\" },\n { title: \"Team\", field: \"team\" },\n { title: \"Escalation Policy\", field: \"escalationPolicy\" },\n { title: \"Mapping\", field: \"mapping\" },\n { title: \"Status\", field: \"mappingStatus\", width: \"10%\" },\n { title: \"Actions\", field: \"actions\" },\n ];\n\n const data = PagerDutyServices.map((service) => {\n\n const status = getMappingStatus(service.name);\n\n return {\n name: service.name,\n team: service.teams?.at(0)?.summary,\n escalationPolicy: service.escalation_policy.name,\n mappingStatus:\n ( // status of mapping\n <Typography\n variant=\"body2\"\n style={{\n color: getColorFromStatus(status),\n }}\n >\n {status}\n </Typography>\n ),\n mapping: (\n // dropdown menu with static options. If service.mapping is defined select that option\n <FormControl>\n <InputLabel id=\"demo-simple-select-helper-label\">Service</InputLabel>\n <Select\n labelId=\"demo-simple-select-helper-label\"\n id=\"demo-simple-select-helper\"\n // onChange={handleChange}\n >\n <MenuItem value=\"\">\n <em>None</em>\n </MenuItem>\n {BackstageServices.map((backstageService) => {\n return (\n <MenuItem\n key={backstageService.name}\n value={backstageService.name}\n >\n {backstageService.name}\n </MenuItem>\n );\n })}\n </Select>\n </FormControl>\n // <select title=\"Mapping\" value={service.mapping}>\n // <option aria-label=\"None\" value=\"\" />\n // <option value=\"Ads\">Ads</option>\n // <option value=\"Cache\">Cache</option>\n // <option value=\"Catalog\">Catalog</option>\n // <option value=\"Checkout\">Checkout</option>\n // </select>\n ),\n actions: (\n <Button variant=\"contained\" color=\"primary\" href={service.html_url}>\n Open in PagerDuty\n </Button>\n ),\n };\n });\n\n return (\n <Table\n title=\"PagerDuty Service Import\"\n subtitle=\"Use this page to import services from PagerDuty and map them to existing Backstage services \"\n options={{\n search: true,\n paging: true,\n pageSize: 10,\n pageSizeOptions: [10, 25, 50],\n sorting: true,\n emptyRowsWhenPaging: false,\n showFirstLastPageButtons: true,\n columnResizable: true,\n columnsButton: true,\n rowStyle: {\n height: \"10px\",\n },\n padding: \"dense\",\n }}\n columns={columns}\n data={data}\n />\n );\n};\n\nexport const ServiceMappingComponent = () => {\n const backstageServices: Service[] = [];\n // const [catalogEntities, setCatalogEntities] = useState<Entity[]>([]);\n const pagerDutyApi = useApi(pagerDutyApiRef);\n const catalogApi = useApi(catalogApiRef);\n\n // useEffect(() => {\n // async function fetchServices() {\n // const { services: foundServices } = await pagerDutyApi.getAllServices();\n\n // setPagerDutyServices(foundServices);\n // }\n\n // async function fetchEntities() { \n // const response : GetEntitiesResponse = await catalogApi.getEntities();\n\n // setCatalogEntities(response.items);\n // }\n\n // await fetchServices();\n // fetchEntities();\n // }, [catalogApi, pagerDutyApi]);\n\n const {\n value: pagerDutyServices,\n loading,\n error,\n } = useAsync(async () => {\n\n catalogApi.getEntities(\n { filter: { kind: \"Component\" } }\n ).then(async (response) => {\n // setCatalogEntities(response.items);\n \n\n response.items.forEach((entity : Entity) => {\n backstageServices.push({\n name: entity.metadata?.name,\n id: entity.metadata?.uid ?? \"\",\n system: JSON.stringify(entity.spec?.system) || \"\",\n owner: JSON.stringify(entity.spec?.owner) || \"\",\n lifecycle: JSON.stringify(entity.spec?.lifecycle) || \"\",\n });\n });\n\n const { services: foundServices } =\n await pagerDutyApi.getAllServices();\n \n return foundServices;\n });\n \n }, []);\n\n if (error) {\n return <p>Error: {error.message}</p>;\n }\n\n if(loading) {\n return <p>Loading...</p>;\n }\n\n return <DenseTable BackstageServices={backstageServices || []} PagerDutyServices={pagerDutyServices ?? []} />;\n};\n","import React from \"react\";\nimport { Grid } from \"@material-ui/core\";\nimport { Header, Page, Content } from \"@backstage/core-components\";\nimport { ServiceMappingComponent } from \"./ServiceMappingComponent\";\n\n/** @public */\nexport const PagerDutyPage = () => {\n // const [toggleImport, setToggleImport] = useState(false);\n // const [toggleSave, setToggleSave] = useState(false);\n\n // const handleImport = () => {\n // setToggleImport(!toggleImport);\n // };\n\n // const handleSave = () => {\n // setToggleSave(!toggleSave);\n // }\n\n return (\n <Page themeId=\"home\">\n <Header title=\"PagerDuty\" subtitle=\"Advanced configurations\" />\n <Content>\n {/* <Grid container spacing={3} direction=\"column\">\n <Grid item alignContent=\"flex-end\">\n <Button variant=\"contained\" color=\"primary\" onClick={() => {handleImport()}}>\n Import\n </Button>\n <Button variant=\"outlined\" color=\"primary\" onClick={() => {handleSave()}}>\n Save\n </Button>\n </Grid>\n </Grid> */}\n <Grid container spacing={3} direction=\"column\">\n <Grid item>\n <ServiceMappingComponent />\n </Grid>\n </Grid>\n </Content>\n </Page>\n );\n};\n"],"names":[],"mappings":"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"}
|