@axis-backstage/plugin-statuspage 0.2.1 → 0.3.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @axis-backstage/plugin-statuspage
2
2
 
3
+ ## 0.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 32683b9: StatuspageEntityCard was route mounted incorrectly, which broke the component in certain cases.
8
+
3
9
  ## 0.2.1
4
10
 
5
11
  ### Patch Changes
package/README.md CHANGED
@@ -6,11 +6,11 @@ Welcome to the Statuspage.io plugin!
6
6
 
7
7
  The **Statuspage** plugin allows you to embedd https://statuspage.io components, component groups and dashboards in Backstage.
8
8
 
9
- There is a React-card, `<StatuspageEntityComponent />`, that is suitable for the Entity component/service overview page:
9
+ There is a React-card, `<StatuspageEntityCard />`, that is suitable for the Entity component/service overview page:
10
10
 
11
11
  ![entity-card](https://github.com/AxisCommunications/backstage-plugins/blob/main/plugins/statuspage/media/entity-card.png)
12
12
 
13
- And also one card, `<StatuspageComponent instance="myinstance"/>`, for easy integration of a complete Statuspage. This component is _not_ dependent
13
+ And also one card, `<StatuspagePage name="myinstance"/>`, for easy integration of a complete Statuspage. This component is _not_ dependent
14
14
  on the `useEntity()`-hook, making it easy to integrate on the Home-page (or some other portal).
15
15
 
16
16
  ![full-status](https://github.com/AxisCommunications/backstage-plugins/blob/main/plugins/statuspage/media/full-status.png)
@@ -50,7 +50,7 @@ const defaultEntityPage = (
50
50
  <EntitySwitch>
51
51
  <EntitySwitch.Case if={isStatuspageAvailable}>
52
52
  <Grid item xs={12}>
53
- <StatuspageEntityComponent />
53
+ <StatuspageEntityCard />
54
54
  </Grid>
55
55
  </EntitySwitch.Case>
56
56
  </EntitySwitch>
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  /// <reference types="react" />
2
2
  import * as React from 'react';
3
+ import React__default from 'react';
3
4
  import * as _backstage_core_plugin_api from '@backstage/core-plugin-api';
4
5
  import { Entity } from '@backstage/catalog-model';
5
6
 
@@ -32,11 +33,13 @@ declare const statuspagePlugin: _backstage_core_plugin_api.BackstagePlugin<{
32
33
  * @public
33
34
  */
34
35
  declare const StatuspagePage: ({ name }: StatuspageProps) => React.JSX.Element;
36
+
35
37
  /**
36
- * Routable extension for StatuspageComponent.
38
+ * Statuspage card intended for the EntityPage. Allows embedding of specific
39
+ * statuspage components and component groups.
37
40
  *
38
41
  * @public
39
42
  */
40
- declare const StatuspageEntityCard: () => React.JSX.Element;
43
+ declare const StatuspageEntityCard: () => React__default.JSX.Element;
41
44
 
42
45
  export { StatuspageEntityCard, StatuspagePage, StatuspageProps, isStatuspageAvailable, statuspagePlugin };
package/dist/index.esm.js CHANGED
@@ -1,4 +1,304 @@
1
- export { b as StatuspageEntityCard, S as StatuspagePage, i as isStatuspageAvailable, a as statuspagePlugin } from './esm/index-f9afba17.esm.js';
2
- import '@backstage/core-plugin-api';
3
- import '@axis-backstage/plugin-statuspage-common';
1
+ import { createRouteRef, createApiRef, createPlugin, createApiFactory, discoveryApiRef, fetchApiRef, createRoutableExtension, useApi } from '@backstage/core-plugin-api';
2
+ import { STATUSPAGE_ANNOTATION } from '@axis-backstage/plugin-statuspage-common';
3
+ import React from 'react';
4
+ import { Progress, ResponseErrorPanel, InfoCard, Table } from '@backstage/core-components';
5
+ import OpenInNewIcon from '@mui/icons-material/OpenInNew';
6
+ import { useEntity } from '@backstage/plugin-catalog-react';
7
+ import Chip from '@mui/material/Chip';
8
+ import Stack from '@mui/material/Stack';
9
+ import Accordion from '@mui/material/Accordion';
10
+ import AccordionDetails from '@mui/material/AccordionDetails';
11
+ import AccordionSummary from '@mui/material/AccordionSummary';
12
+ import Typography from '@mui/material/Typography';
13
+ import { styled } from '@mui/material/styles';
14
+ import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
15
+ import Grid from '@mui/material/Unstable_Grid2';
16
+ import IconButton from '@mui/material/IconButton';
17
+ import useAsync from 'react-use/lib/useAsync';
18
+
19
+ const rootRouteRef = createRouteRef({
20
+ id: "statuspage"
21
+ });
22
+
23
+ const statuspageApiRef = createApiRef({
24
+ id: "plugin.statuspage"
25
+ });
26
+
27
+ var __defProp = Object.defineProperty;
28
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
29
+ var __publicField = (obj, key, value) => {
30
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
31
+ return value;
32
+ };
33
+ class StatuspageClient {
34
+ constructor(options) {
35
+ __publicField(this, "discoveryApi");
36
+ __publicField(this, "fetchApi");
37
+ this.discoveryApi = options.discoveryApi;
38
+ this.fetchApi = options.fetchApi;
39
+ }
40
+ async getLink(name) {
41
+ const baseUrl = await this.discoveryApi.getBaseUrl("statuspage");
42
+ const response = await this.fetchApi.fetch(
43
+ `${baseUrl}/fetch-link/${encodeURIComponent(name)}`,
44
+ {
45
+ method: "GET",
46
+ headers: {
47
+ "Content-Type": "application/json"
48
+ }
49
+ }
50
+ );
51
+ if (response.ok) {
52
+ const data = await response.json();
53
+ return data;
54
+ }
55
+ throw new Error(
56
+ `Failed to get statuspage link for ${name} with status code ${response.status}`
57
+ );
58
+ }
59
+ async getComponents(name) {
60
+ const baseUrl = await this.discoveryApi.getBaseUrl("statuspage");
61
+ const data = await this.fetchApi.fetch(
62
+ `${baseUrl}/fetch-components/${encodeURIComponent(name)}`,
63
+ {
64
+ method: "GET",
65
+ headers: {
66
+ "Content-Type": "application/json"
67
+ }
68
+ }
69
+ );
70
+ if (data.ok)
71
+ return data.json();
72
+ throw new Error(`Failed to get statuspage components for ${name}`);
73
+ }
74
+ async getComponentGroups(name) {
75
+ const baseUrl = await this.discoveryApi.getBaseUrl("statuspage");
76
+ const data = await this.fetchApi.fetch(
77
+ `${baseUrl}/fetch-component-groups/${encodeURIComponent(name)}`,
78
+ {
79
+ method: "GET",
80
+ headers: {
81
+ "Content-Type": "application/json"
82
+ }
83
+ }
84
+ );
85
+ if (data.ok)
86
+ return data.json();
87
+ throw new Error(`Failed to get statuspage component groups for ${name}`);
88
+ }
89
+ }
90
+
91
+ const isStatuspageAvailable = (entity) => {
92
+ var _a;
93
+ return Boolean((_a = entity.metadata.annotations) == null ? void 0 : _a[STATUSPAGE_ANNOTATION]);
94
+ };
95
+ const statuspagePlugin = createPlugin({
96
+ id: "statuspage",
97
+ apis: [
98
+ createApiFactory({
99
+ api: statuspageApiRef,
100
+ deps: {
101
+ discoveryApi: discoveryApiRef,
102
+ fetchApi: fetchApiRef
103
+ },
104
+ factory: ({ discoveryApi, fetchApi }) => new StatuspageClient({ discoveryApi, fetchApi })
105
+ })
106
+ ],
107
+ routes: {
108
+ root: rootRouteRef
109
+ }
110
+ });
111
+ const StatuspagePage = statuspagePlugin.provide(
112
+ createRoutableExtension({
113
+ name: "StatuspagePage",
114
+ component: () => Promise.resolve().then(function () { return StatuspageComponent$1; }).then(
115
+ (m) => m.StatuspageComponent
116
+ ),
117
+ mountPoint: rootRouteRef
118
+ })
119
+ );
120
+
121
+ const ComponentGroupStatusChips = ({
122
+ components
123
+ }) => /* @__PURE__ */ React.createElement(React.Fragment, null, components.some((component) => component.status !== "operational") ? components.filter((component) => component.status !== "operational").map((component) => /* @__PURE__ */ React.createElement(Grid, { key: component.id }, /* @__PURE__ */ React.createElement(StatusChip, { status: component.status }))) : /* @__PURE__ */ React.createElement(Grid, null, /* @__PURE__ */ React.createElement(StatusChip, { status: "operational" })));
124
+
125
+ const DenseAccordion = styled(Accordion)({
126
+ margin: "2px",
127
+ borderRadius: "2px"
128
+ });
129
+ const ComponentGroupCard = ({
130
+ components,
131
+ componentGroup,
132
+ expanded = false
133
+ }) => {
134
+ return /* @__PURE__ */ React.createElement(DenseAccordion, { key: componentGroup.id, defaultExpanded: expanded }, /* @__PURE__ */ React.createElement(
135
+ AccordionSummary,
136
+ {
137
+ style: { padding: "0 10px !important", display: "flex !important" },
138
+ expandIcon: /* @__PURE__ */ React.createElement(ExpandMoreIcon, null)
139
+ },
140
+ /* @__PURE__ */ React.createElement(Typography, null, componentGroup.name),
141
+ /* @__PURE__ */ React.createElement(ComponentGroupStatusChips, { components })
142
+ ), /* @__PURE__ */ React.createElement(AccordionDetails, null, /* @__PURE__ */ React.createElement(ComponentsTable, { components })));
143
+ };
144
+
145
+ const ComponentGroupsList = ({
146
+ components,
147
+ componentGroups,
148
+ expanded
149
+ }) => {
150
+ return /* @__PURE__ */ React.createElement(Stack, { paddingTop: "10px" }, componentGroups.map((componentGroup) => /* @__PURE__ */ React.createElement(
151
+ ComponentGroupCard,
152
+ {
153
+ key: componentGroup.id,
154
+ componentGroup,
155
+ components: components.filter((c) => c.group_id === componentGroup.id),
156
+ expanded
157
+ }
158
+ )));
159
+ };
160
+
161
+ const useComponents = (name) => {
162
+ const statuspageApi = useApi(statuspageApiRef);
163
+ return useAsync(async () => {
164
+ const components = await statuspageApi.getComponents(name);
165
+ const componentGroups = await statuspageApi.getComponentGroups(name);
166
+ const { url } = await statuspageApi.getLink(name);
167
+ return {
168
+ components,
169
+ componentGroups,
170
+ url
171
+ };
172
+ }, [name]);
173
+ };
174
+
175
+ const statusColorMap = {
176
+ under_maintenance: "info",
177
+ operational: "success",
178
+ degraded_performance: "warning",
179
+ partial_outage: "warning",
180
+ major_outage: "error"
181
+ };
182
+ const StatuspageComponent = ({ name }) => {
183
+ const { loading, error, value } = useComponents(name);
184
+ if (loading) {
185
+ return /* @__PURE__ */ React.createElement(Progress, null);
186
+ }
187
+ if (error) {
188
+ return /* @__PURE__ */ React.createElement(ResponseErrorPanel, { error });
189
+ }
190
+ const linkAction = (value == null ? void 0 : value.url) && /* @__PURE__ */ React.createElement(
191
+ IconButton,
192
+ {
193
+ "aria-label": "Go to our statuspage",
194
+ role: "button",
195
+ title: "Go to statuspage(.io)",
196
+ href: value == null ? void 0 : value.url,
197
+ target: "_blank"
198
+ },
199
+ /* @__PURE__ */ React.createElement(OpenInNewIcon, null)
200
+ );
201
+ return /* @__PURE__ */ React.createElement(InfoCard, { title: "Status of our services", action: linkAction }, /* @__PURE__ */ React.createElement(
202
+ ComponentGroupsList,
203
+ {
204
+ components: (value == null ? void 0 : value.components) || [],
205
+ componentGroups: (value == null ? void 0 : value.componentGroups) || []
206
+ }
207
+ ));
208
+ };
209
+
210
+ var StatuspageComponent$1 = /*#__PURE__*/Object.freeze({
211
+ __proto__: null,
212
+ statusColorMap: statusColorMap,
213
+ StatuspageComponent: StatuspageComponent
214
+ });
215
+
216
+ const formatStatusString = (status) => status.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
217
+ const StatusChip = ({ status }) => /* @__PURE__ */ React.createElement(
218
+ Chip,
219
+ {
220
+ sx: { margin: "0 8px" },
221
+ size: "small",
222
+ label: formatStatusString(status),
223
+ color: statusColorMap[status] || "default"
224
+ }
225
+ );
226
+
227
+ const ComponentsTable = ({ components }) => {
228
+ const columns = [
229
+ { title: "System", field: "name", id: "id" },
230
+ {
231
+ title: "Status",
232
+ field: "status",
233
+ render: (rowData) => /* @__PURE__ */ React.createElement(StatusChip, { status: rowData.status }),
234
+ align: "right"
235
+ }
236
+ ];
237
+ return /* @__PURE__ */ React.createElement(
238
+ Table,
239
+ {
240
+ options: {
241
+ search: false,
242
+ paging: false,
243
+ header: false,
244
+ padding: "dense",
245
+ toolbar: false
246
+ },
247
+ columns,
248
+ data: components.map(({ name, status, id }) => ({ name, status, id }))
249
+ }
250
+ );
251
+ };
252
+
253
+ const StatuspageEntityCard = () => {
254
+ var _a, _b;
255
+ const { entity } = useEntity();
256
+ const [name, wantedComponentsStr] = (_b = (_a = entity.metadata.annotations) == null ? void 0 : _a[STATUSPAGE_ANNOTATION]) == null ? void 0 : _b.split(":");
257
+ const wantedComponents = wantedComponentsStr == null ? void 0 : wantedComponentsStr.split(",").map((it) => it.trim());
258
+ const { loading, error, value } = useComponents(name);
259
+ if (loading) {
260
+ return /* @__PURE__ */ React.createElement(Progress, null);
261
+ }
262
+ if (error) {
263
+ return /* @__PURE__ */ React.createElement(ResponseErrorPanel, { error });
264
+ }
265
+ if (loading) {
266
+ return /* @__PURE__ */ React.createElement(Progress, null);
267
+ }
268
+ if (error) {
269
+ return /* @__PURE__ */ React.createElement(ResponseErrorPanel, { error });
270
+ }
271
+ const linkAction = (value == null ? void 0 : value.url) && /* @__PURE__ */ React.createElement(
272
+ IconButton,
273
+ {
274
+ "aria-label": "Go to our statuspage",
275
+ role: "button",
276
+ title: "Go to statuspage(.io)",
277
+ href: value == null ? void 0 : value.url,
278
+ target: "_blank"
279
+ },
280
+ /* @__PURE__ */ React.createElement(OpenInNewIcon, null)
281
+ );
282
+ const fullStatuspage = !wantedComponents;
283
+ const filteredComponents = (value == null ? void 0 : value.components.filter(
284
+ (c) => !fullStatuspage && !c.group && wantedComponents.includes(c.id)
285
+ )) || [];
286
+ const filteredComponentGroups = (value == null ? void 0 : value.componentGroups.filter(
287
+ (c) => fullStatuspage || wantedComponents.includes(c.id)
288
+ )) || [];
289
+ const noComponents = (!filteredComponents || filteredComponentGroups.length === 0) && filteredComponents && filteredComponents.length === 0;
290
+ if (noComponents) {
291
+ return /* @__PURE__ */ React.createElement(InfoCard, { title: "Service Status", action: linkAction }, /* @__PURE__ */ React.createElement(Typography, { variant: "body2", color: "#FF5555" }, "The specified statuspage.io components could not be found. Check your annotation."));
292
+ }
293
+ return /* @__PURE__ */ React.createElement(InfoCard, { title: "Service Status", action: linkAction }, filteredComponents && filteredComponents.length > 0 && /* @__PURE__ */ React.createElement(ComponentsTable, { components: filteredComponents }), filteredComponentGroups && filteredComponentGroups.length > 0 && /* @__PURE__ */ React.createElement(
294
+ ComponentGroupsList,
295
+ {
296
+ components: (value == null ? void 0 : value.components) || [],
297
+ componentGroups: filteredComponentGroups,
298
+ expanded: !fullStatuspage
299
+ }
300
+ ));
301
+ };
302
+
303
+ export { StatuspageEntityCard, StatuspagePage, isStatuspageAvailable, statuspagePlugin };
4
304
  //# sourceMappingURL=index.esm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
1
+ {"version":3,"file":"index.esm.js","sources":["../src/routes.ts","../src/api/StatuspageApi.ts","../src/api/StatuspageClient.ts","../src/plugin.ts","../src/components/ComponentGroupStatusChips.tsx","../src/components/ComponentGroupCard.tsx","../src/components/ComponentGroupsList.tsx","../src/hooks/useComponents.ts","../src/components/StatuspageComponent.tsx","../src/components/StatusChip.tsx","../src/components/ComponentsTable.tsx","../src/components/StatuspageEntityCard.tsx"],"sourcesContent":["import { createRouteRef } from '@backstage/core-plugin-api';\n\nexport const rootRouteRef = createRouteRef({\n id: 'statuspage',\n});\n","import { createApiRef } from '@backstage/core-plugin-api';\n\nimport type {\n Component,\n ComponentGroup,\n} from '@axis-backstage/plugin-statuspage-common';\n\nexport type StatuspageApi = {\n getComponents(name: string): Promise<Component[]>;\n getComponentGroups(name: string): Promise<ComponentGroup[]>;\n getLink(name: string): Promise<{ url: string }>;\n};\n\nexport const statuspageApiRef = createApiRef<StatuspageApi>({\n id: 'plugin.statuspage',\n});\n","import { DiscoveryApi, FetchApi } from '@backstage/core-plugin-api';\nimport { StatuspageApi } from './StatuspageApi';\nimport {\n Component,\n ComponentGroup,\n} from '@axis-backstage/plugin-statuspage-common';\n\nexport class StatuspageClient implements StatuspageApi {\n private readonly discoveryApi: DiscoveryApi;\n private readonly fetchApi: FetchApi;\n\n constructor(options: { discoveryApi: DiscoveryApi; fetchApi: FetchApi }) {\n this.discoveryApi = options.discoveryApi;\n this.fetchApi = options.fetchApi;\n }\n\n async getLink(name: string): Promise<{ url: string }> {\n const baseUrl = await this.discoveryApi.getBaseUrl('statuspage');\n const response = await this.fetchApi.fetch(\n `${baseUrl}/fetch-link/${encodeURIComponent(name)}`,\n {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n },\n },\n );\n if (response.ok) {\n const data = await response.json();\n return data;\n }\n throw new Error(\n `Failed to get statuspage link for ${name} with status code ${response.status}`,\n );\n }\n\n async getComponents(name: string): Promise<Component[]> {\n const baseUrl = await this.discoveryApi.getBaseUrl('statuspage');\n const data = await this.fetchApi.fetch(\n `${baseUrl}/fetch-components/${encodeURIComponent(name)}`,\n {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n },\n },\n );\n\n if (data.ok) return data.json();\n throw new Error(`Failed to get statuspage components for ${name}`);\n }\n\n async getComponentGroups(name: string): Promise<ComponentGroup[]> {\n const baseUrl = await this.discoveryApi.getBaseUrl('statuspage');\n const data = await this.fetchApi.fetch(\n `${baseUrl}/fetch-component-groups/${encodeURIComponent(name)}`,\n {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n },\n },\n );\n\n if (data.ok) return data.json();\n throw new Error(`Failed to get statuspage component groups for ${name}`);\n }\n}\n","import {\n createApiFactory,\n createPlugin,\n createRoutableExtension,\n discoveryApiRef,\n fetchApiRef,\n} from '@backstage/core-plugin-api';\n\nimport { STATUSPAGE_ANNOTATION } from '@axis-backstage/plugin-statuspage-common';\nimport { Entity } from '@backstage/catalog-model';\n\nimport { rootRouteRef } from './routes';\nimport { statuspageApiRef } from './api/StatuspageApi';\nimport { StatuspageClient } from './api/StatuspageClient';\n\n/**\n * Checks availability of a statuspage component\n *\n * @public\n */\nexport const isStatuspageAvailable = (entity: Entity) =>\n Boolean(entity.metadata.annotations?.[STATUSPAGE_ANNOTATION]);\n\n/**\n * Create the plugin.\n *\n * @public\n */\nexport const statuspagePlugin = createPlugin({\n id: 'statuspage',\n apis: [\n createApiFactory({\n api: statuspageApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n fetchApi: fetchApiRef,\n },\n factory: ({ discoveryApi, fetchApi }) =>\n new StatuspageClient({ discoveryApi, fetchApi }),\n }),\n ],\n routes: {\n root: rootRouteRef,\n },\n});\n\n/**\n * Routable extension for StatuspageComponent.\n *\n * @public\n */\nexport const StatuspagePage = statuspagePlugin.provide(\n createRoutableExtension({\n name: 'StatuspagePage',\n component: () =>\n import('./components/StatuspageComponent').then(\n m => m.StatuspageComponent,\n ),\n mountPoint: rootRouteRef,\n }),\n);\n","import React from 'react';\nimport Grid from '@mui/material/Unstable_Grid2';\nimport { StatusChip } from './StatusChip';\nimport { ComponentsTableProps } from './ComponentsTable';\n\nexport const ComponentGroupStatusChips = ({\n components,\n}: ComponentsTableProps) => (\n <>\n {components.some(component => component.status !== 'operational') ? (\n components\n .filter(component => component.status !== 'operational')\n .map(component => (\n <Grid key={component.id}>\n <StatusChip status={component.status} />\n </Grid>\n ))\n ) : (\n <Grid>\n <StatusChip status=\"operational\" />\n </Grid>\n )}\n </>\n);\n","import React from 'react';\nimport Accordion from '@mui/material/Accordion';\nimport AccordionDetails from '@mui/material/AccordionDetails';\nimport AccordionSummary from '@mui/material/AccordionSummary';\nimport Typography from '@mui/material/Typography';\nimport { styled } from '@mui/material/styles';\nimport ExpandMoreIcon from '@mui/icons-material/ExpandMore';\nimport { ComponentsTable } from './ComponentsTable';\nimport { ComponentGroupStatusChips } from './ComponentGroupStatusChips';\nimport type {\n Component,\n ComponentGroup,\n} from '@axis-backstage/plugin-statuspage-common';\n\nexport type ComponentGroupProps = {\n components: Component[];\n componentGroup: ComponentGroup;\n expanded?: boolean;\n};\n\nconst DenseAccordion = styled(Accordion)({\n margin: '2px',\n borderRadius: '2px',\n});\n\nexport const ComponentGroupCard = ({\n components,\n componentGroup,\n expanded = false,\n}: ComponentGroupProps) => {\n return (\n <DenseAccordion key={componentGroup.id} defaultExpanded={expanded}>\n <AccordionSummary\n style={{ padding: '0 10px !important', display: 'flex !important' }}\n expandIcon={<ExpandMoreIcon />}\n >\n <Typography>{componentGroup.name}</Typography>\n <ComponentGroupStatusChips components={components} />\n </AccordionSummary>\n <AccordionDetails>\n <ComponentsTable components={components} />\n </AccordionDetails>\n </DenseAccordion>\n );\n};\n","import React from 'react';\nimport Stack from '@mui/material/Stack';\nimport { ComponentGroupCard } from './ComponentGroupCard';\nimport type {\n Component,\n ComponentGroup,\n} from '@axis-backstage/plugin-statuspage-common';\n\nexport type ComponentGroupListProps = {\n components: Component[];\n componentGroups: ComponentGroup[];\n expanded?: boolean;\n};\n\nexport const ComponentGroupsList = ({\n components,\n componentGroups,\n expanded,\n}: ComponentGroupListProps) => {\n return (\n <Stack paddingTop=\"10px\">\n {componentGroups.map(componentGroup => (\n <ComponentGroupCard\n key={componentGroup.id}\n componentGroup={componentGroup}\n components={components.filter(c => c.group_id === componentGroup.id)}\n expanded={expanded}\n />\n ))}\n </Stack>\n );\n};\n","import { useApi } from '@backstage/core-plugin-api';\nimport { statuspageApiRef } from '../api/StatuspageApi';\nimport useAsync from 'react-use/lib/useAsync';\nimport {\n Component,\n ComponentGroup,\n} from '@axis-backstage/plugin-statuspage-common';\n\nexport const useComponents = (name: string) => {\n const statuspageApi = useApi(statuspageApiRef);\n\n return useAsync(async (): Promise<{\n components: Component[];\n componentGroups: ComponentGroup[];\n url?: string;\n }> => {\n const components = await statuspageApi.getComponents(name);\n const componentGroups = await statuspageApi.getComponentGroups(name);\n const { url } = await statuspageApi.getLink(name);\n return {\n components,\n componentGroups,\n url,\n };\n }, [name]);\n};\n","import React from 'react';\nimport {\n InfoCard,\n Progress,\n ResponseErrorPanel,\n} from '@backstage/core-components';\nimport type { ComponentStatus } from '@axis-backstage/plugin-statuspage-common';\nimport { ComponentGroupsList } from './ComponentGroupsList';\nimport IconButton from '@mui/material/IconButton';\nimport OpenInNewIcon from '@mui/icons-material/OpenInNew';\nimport { useComponents } from '../hooks/useComponents';\n\n/**\n * StatuspageComponent props.\n *\n * @public\n */\nexport type StatuspageProps = {\n name: string;\n};\n\n/**\n * Maps statuspage component statuses to MUI colors.\n *\n * @public\n */\nexport const statusColorMap: { [key in ComponentStatus]: string } = {\n under_maintenance: 'info',\n operational: 'success',\n degraded_performance: 'warning',\n partial_outage: 'warning',\n major_outage: 'error',\n};\n\n/**\n * Visualizes a full statuspage.\n *\n * @param name - instance name from app config.\n * @public\n */\nexport const StatuspageComponent = ({ name }: StatuspageProps) => {\n const { loading, error, value } = useComponents(name);\n\n if (loading) {\n return <Progress />;\n }\n if (error) {\n return <ResponseErrorPanel error={error} />;\n }\n\n const linkAction = value?.url && (\n <IconButton\n aria-label=\"Go to our statuspage\"\n role=\"button\"\n title=\"Go to statuspage(.io)\"\n href={value?.url}\n target=\"_blank\"\n >\n <OpenInNewIcon />\n </IconButton>\n );\n\n return (\n <InfoCard title=\"Status of our services\" action={linkAction}>\n <ComponentGroupsList\n components={value?.components || []}\n componentGroups={value?.componentGroups || []}\n />\n </InfoCard>\n );\n};\n","import React from 'react';\nimport type { ComponentStatus } from '@axis-backstage/plugin-statuspage-common';\nimport Chip from '@mui/material/Chip';\nimport { statusColorMap } from './StatuspageComponent';\n\ntype StatusChipProps = {\n status: ComponentStatus;\n};\n\nconst formatStatusString = (status: string): string =>\n status\n .split('_')\n .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join(' ');\n\nexport const StatusChip = ({ status }: StatusChipProps) => (\n <Chip\n sx={{ margin: '0 8px' }}\n size=\"small\"\n label={formatStatusString(status)}\n color={statusColorMap[status] || ('default' as any)}\n />\n);\n","import React from 'react';\nimport { Table, TableColumn } from '@backstage/core-components';\nimport type { Component } from '@axis-backstage/plugin-statuspage-common';\nimport { StatusChip } from './StatusChip';\n\nexport type ComponentsTableProps = {\n components: Component[];\n};\n\nexport const ComponentsTable = ({ components }: ComponentsTableProps) => {\n // Columns definition\n const columns: TableColumn[] = [\n { title: 'System', field: 'name', id: 'id' },\n {\n title: 'Status',\n field: 'status',\n render: (rowData: any) => <StatusChip status={rowData.status} />,\n align: 'right',\n },\n ];\n\n return (\n <Table\n options={{\n search: false,\n paging: false,\n header: false,\n padding: 'dense',\n toolbar: false,\n }}\n columns={columns}\n data={components.map(({ name, status, id }) => ({ name, status, id }))}\n />\n );\n};\n","import React from 'react';\nimport {\n InfoCard,\n Progress,\n ResponseErrorPanel,\n} from '@backstage/core-components';\nimport OpenInNewIcon from '@mui/icons-material/OpenInNew';\nimport { useEntity } from '@backstage/plugin-catalog-react';\nimport { ComponentsTable } from './ComponentsTable';\nimport { ComponentGroupsList } from './ComponentGroupsList';\nimport IconButton from '@mui/material/IconButton';\nimport Typography from '@mui/material/Typography';\nimport { STATUSPAGE_ANNOTATION } from '@axis-backstage/plugin-statuspage-common';\nimport { useComponents } from '../hooks/useComponents';\n\n/**\n * Statuspage card intended for the EntityPage. Allows embedding of specific\n * statuspage components and component groups.\n *\n * @public\n */\nexport const StatuspageEntityCard = () => {\n const { entity } = useEntity();\n const [name, wantedComponentsStr] =\n entity.metadata.annotations?.[STATUSPAGE_ANNOTATION]?.split(':')!;\n const wantedComponents = wantedComponentsStr?.split(',').map(it => it.trim());\n\n const { loading, error, value } = useComponents(name);\n\n if (loading) {\n return <Progress />;\n }\n if (error) {\n return <ResponseErrorPanel error={error} />;\n }\n\n if (loading) {\n return <Progress />;\n }\n if (error) {\n return <ResponseErrorPanel error={error} />;\n }\n\n const linkAction = value?.url && (\n <IconButton\n aria-label=\"Go to our statuspage\"\n role=\"button\"\n title=\"Go to statuspage(.io)\"\n href={value?.url}\n target=\"_blank\"\n >\n <OpenInNewIcon />\n </IconButton>\n );\n\n const fullStatuspage = !wantedComponents;\n const filteredComponents =\n value?.components.filter(\n c => !fullStatuspage && !c.group && wantedComponents.includes(c.id),\n ) || [];\n const filteredComponentGroups =\n value?.componentGroups.filter(\n c => fullStatuspage || wantedComponents.includes(c.id),\n ) || [];\n const noComponents =\n (!filteredComponents || filteredComponentGroups.length === 0) &&\n filteredComponents &&\n filteredComponents.length === 0;\n\n if (noComponents) {\n return (\n <InfoCard title=\"Service Status\" action={linkAction}>\n <Typography variant=\"body2\" color=\"#FF5555\">\n The specified statuspage.io components could not be found. Check your\n annotation.\n </Typography>\n </InfoCard>\n );\n }\n return (\n <InfoCard title=\"Service Status\" action={linkAction}>\n {filteredComponents && filteredComponents.length > 0 && (\n <ComponentsTable components={filteredComponents} />\n )}\n {filteredComponentGroups && filteredComponentGroups.length > 0 && (\n <ComponentGroupsList\n components={value?.components || []}\n componentGroups={filteredComponentGroups}\n expanded={!fullStatuspage}\n />\n )}\n </InfoCard>\n );\n};\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axis-backstage/plugin-statuspage",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "main": "dist/index.esm.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "license": "Apache-2.0",
@@ -1,151 +0,0 @@
1
- import React from 'react';
2
- import { Table, Progress, ResponseErrorPanel, InfoCard } from '@backstage/core-components';
3
- import Stack from '@mui/material/Stack';
4
- import Accordion from '@mui/material/Accordion';
5
- import AccordionDetails from '@mui/material/AccordionDetails';
6
- import AccordionSummary from '@mui/material/AccordionSummary';
7
- import Typography from '@mui/material/Typography';
8
- import { styled } from '@mui/material/styles';
9
- import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
10
- import Chip from '@mui/material/Chip';
11
- import IconButton from '@mui/material/IconButton';
12
- import OpenInNewIcon from '@mui/icons-material/OpenInNew';
13
- import { useApi } from '@backstage/core-plugin-api';
14
- import { s as statuspageApiRef } from './index-f9afba17.esm.js';
15
- import useAsync from 'react-use/lib/useAsync';
16
- import Grid from '@mui/material/Unstable_Grid2';
17
-
18
- const formatStatusString = (status) => status.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
19
- const StatusChip = ({ status }) => /* @__PURE__ */ React.createElement(
20
- Chip,
21
- {
22
- sx: { margin: "0 8px" },
23
- size: "small",
24
- label: formatStatusString(status),
25
- color: statusColorMap[status] || "default"
26
- }
27
- );
28
-
29
- const ComponentsTable = ({ components }) => {
30
- const columns = [
31
- { title: "System", field: "name", id: "id" },
32
- {
33
- title: "Status",
34
- field: "status",
35
- render: (rowData) => /* @__PURE__ */ React.createElement(StatusChip, { status: rowData.status }),
36
- align: "right"
37
- }
38
- ];
39
- return /* @__PURE__ */ React.createElement(
40
- Table,
41
- {
42
- options: {
43
- search: false,
44
- paging: false,
45
- header: false,
46
- padding: "dense",
47
- toolbar: false
48
- },
49
- columns,
50
- data: components.map(({ name, status, id }) => ({ name, status, id }))
51
- }
52
- );
53
- };
54
-
55
- const ComponentGroupStatusChips = ({
56
- components
57
- }) => /* @__PURE__ */ React.createElement(React.Fragment, null, components.some((component) => component.status !== "operational") ? components.filter((component) => component.status !== "operational").map((component) => /* @__PURE__ */ React.createElement(Grid, { key: component.id }, /* @__PURE__ */ React.createElement(StatusChip, { status: component.status }))) : /* @__PURE__ */ React.createElement(Grid, null, /* @__PURE__ */ React.createElement(StatusChip, { status: "operational" })));
58
-
59
- const DenseAccordion = styled(Accordion)({
60
- margin: "2px",
61
- borderRadius: "2px"
62
- });
63
- const ComponentGroupCard = ({
64
- components,
65
- componentGroup,
66
- expanded = false
67
- }) => {
68
- return /* @__PURE__ */ React.createElement(DenseAccordion, { key: componentGroup.id, defaultExpanded: expanded }, /* @__PURE__ */ React.createElement(
69
- AccordionSummary,
70
- {
71
- style: { padding: "0 10px !important", display: "flex !important" },
72
- expandIcon: /* @__PURE__ */ React.createElement(ExpandMoreIcon, null)
73
- },
74
- /* @__PURE__ */ React.createElement(Typography, null, componentGroup.name),
75
- /* @__PURE__ */ React.createElement(ComponentGroupStatusChips, { components })
76
- ), /* @__PURE__ */ React.createElement(AccordionDetails, null, /* @__PURE__ */ React.createElement(ComponentsTable, { components })));
77
- };
78
-
79
- const ComponentGroupsList = ({
80
- components,
81
- componentGroups,
82
- expanded
83
- }) => {
84
- return /* @__PURE__ */ React.createElement(Stack, { paddingTop: "10px" }, componentGroups.map((componentGroup) => /* @__PURE__ */ React.createElement(
85
- ComponentGroupCard,
86
- {
87
- key: componentGroup.id,
88
- componentGroup,
89
- components: components.filter((c) => c.group_id === componentGroup.id),
90
- expanded
91
- }
92
- )));
93
- };
94
-
95
- const useComponents = (name) => {
96
- const statuspageApi = useApi(statuspageApiRef);
97
- return useAsync(async () => {
98
- const components = await statuspageApi.getComponents(name);
99
- const componentGroups = await statuspageApi.getComponentGroups(name);
100
- const { url } = await statuspageApi.getLink(name);
101
- return {
102
- components,
103
- componentGroups,
104
- url
105
- };
106
- }, [name]);
107
- };
108
-
109
- const statusColorMap = {
110
- under_maintenance: "info",
111
- operational: "success",
112
- degraded_performance: "warning",
113
- partial_outage: "warning",
114
- major_outage: "error"
115
- };
116
- const StatuspageComponent = ({ name }) => {
117
- const { loading, error, value } = useComponents(name);
118
- if (loading) {
119
- return /* @__PURE__ */ React.createElement(Progress, null);
120
- }
121
- if (error) {
122
- return /* @__PURE__ */ React.createElement(ResponseErrorPanel, { error });
123
- }
124
- const linkAction = (value == null ? void 0 : value.url) && /* @__PURE__ */ React.createElement(
125
- IconButton,
126
- {
127
- "aria-label": "Go to our statuspage",
128
- role: "button",
129
- title: "Go to statuspage(.io)",
130
- href: value == null ? void 0 : value.url,
131
- target: "_blank"
132
- },
133
- /* @__PURE__ */ React.createElement(OpenInNewIcon, null)
134
- );
135
- return /* @__PURE__ */ React.createElement(InfoCard, { title: "Status of our services", action: linkAction }, /* @__PURE__ */ React.createElement(
136
- ComponentGroupsList,
137
- {
138
- components: (value == null ? void 0 : value.components) || [],
139
- componentGroups: (value == null ? void 0 : value.componentGroups) || []
140
- }
141
- ));
142
- };
143
-
144
- var StatuspageComponent$1 = /*#__PURE__*/Object.freeze({
145
- __proto__: null,
146
- statusColorMap: statusColorMap,
147
- StatuspageComponent: StatuspageComponent
148
- });
149
-
150
- export { ComponentsTable as C, StatuspageComponent$1 as S, ComponentGroupsList as a, useComponents as u };
151
- //# sourceMappingURL=StatuspageComponent-b7a15df1.esm.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"StatuspageComponent-b7a15df1.esm.js","sources":["../../src/components/StatusChip.tsx","../../src/components/ComponentsTable.tsx","../../src/components/ComponentGroupStatusChips.tsx","../../src/components/ComponentGroupCard.tsx","../../src/components/ComponentGroupsList.tsx","../../src/hooks/useComponents.ts","../../src/components/StatuspageComponent.tsx"],"sourcesContent":["import React from 'react';\nimport type { ComponentStatus } from '@axis-backstage/plugin-statuspage-common';\nimport Chip from '@mui/material/Chip';\nimport { statusColorMap } from './StatuspageComponent';\n\ntype StatusChipProps = {\n status: ComponentStatus;\n};\n\nconst formatStatusString = (status: string): string =>\n status\n .split('_')\n .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join(' ');\n\nexport const StatusChip = ({ status }: StatusChipProps) => (\n <Chip\n sx={{ margin: '0 8px' }}\n size=\"small\"\n label={formatStatusString(status)}\n color={statusColorMap[status] || ('default' as any)}\n />\n);\n","import React from 'react';\nimport { Table, TableColumn } from '@backstage/core-components';\nimport type { Component } from '@axis-backstage/plugin-statuspage-common';\nimport { StatusChip } from './StatusChip';\n\nexport type ComponentsTableProps = {\n components: Component[];\n};\n\nexport const ComponentsTable = ({ components }: ComponentsTableProps) => {\n // Columns definition\n const columns: TableColumn[] = [\n { title: 'System', field: 'name', id: 'id' },\n {\n title: 'Status',\n field: 'status',\n render: (rowData: any) => <StatusChip status={rowData.status} />,\n align: 'right',\n },\n ];\n\n return (\n <Table\n options={{\n search: false,\n paging: false,\n header: false,\n padding: 'dense',\n toolbar: false,\n }}\n columns={columns}\n data={components.map(({ name, status, id }) => ({ name, status, id }))}\n />\n );\n};\n","import React from 'react';\nimport Grid from '@mui/material/Unstable_Grid2';\nimport { StatusChip } from './StatusChip';\nimport { ComponentsTableProps } from './ComponentsTable';\n\nexport const ComponentGroupStatusChips = ({\n components,\n}: ComponentsTableProps) => (\n <>\n {components.some(component => component.status !== 'operational') ? (\n components\n .filter(component => component.status !== 'operational')\n .map(component => (\n <Grid key={component.id}>\n <StatusChip status={component.status} />\n </Grid>\n ))\n ) : (\n <Grid>\n <StatusChip status=\"operational\" />\n </Grid>\n )}\n </>\n);\n","import React from 'react';\nimport Accordion from '@mui/material/Accordion';\nimport AccordionDetails from '@mui/material/AccordionDetails';\nimport AccordionSummary from '@mui/material/AccordionSummary';\nimport Typography from '@mui/material/Typography';\nimport { styled } from '@mui/material/styles';\nimport ExpandMoreIcon from '@mui/icons-material/ExpandMore';\nimport { ComponentsTable } from './ComponentsTable';\nimport { ComponentGroupStatusChips } from './ComponentGroupStatusChips';\nimport type {\n Component,\n ComponentGroup,\n} from '@axis-backstage/plugin-statuspage-common';\n\nexport type ComponentGroupProps = {\n components: Component[];\n componentGroup: ComponentGroup;\n expanded?: boolean;\n};\n\nconst DenseAccordion = styled(Accordion)({\n margin: '2px',\n borderRadius: '2px',\n});\n\nexport const ComponentGroupCard = ({\n components,\n componentGroup,\n expanded = false,\n}: ComponentGroupProps) => {\n return (\n <DenseAccordion key={componentGroup.id} defaultExpanded={expanded}>\n <AccordionSummary\n style={{ padding: '0 10px !important', display: 'flex !important' }}\n expandIcon={<ExpandMoreIcon />}\n >\n <Typography>{componentGroup.name}</Typography>\n <ComponentGroupStatusChips components={components} />\n </AccordionSummary>\n <AccordionDetails>\n <ComponentsTable components={components} />\n </AccordionDetails>\n </DenseAccordion>\n );\n};\n","import React from 'react';\nimport Stack from '@mui/material/Stack';\nimport { ComponentGroupCard } from './ComponentGroupCard';\nimport type {\n Component,\n ComponentGroup,\n} from '@axis-backstage/plugin-statuspage-common';\n\nexport type ComponentGroupListProps = {\n components: Component[];\n componentGroups: ComponentGroup[];\n expanded?: boolean;\n};\n\nexport const ComponentGroupsList = ({\n components,\n componentGroups,\n expanded,\n}: ComponentGroupListProps) => {\n return (\n <Stack paddingTop=\"10px\">\n {componentGroups.map(componentGroup => (\n <ComponentGroupCard\n key={componentGroup.id}\n componentGroup={componentGroup}\n components={components.filter(c => c.group_id === componentGroup.id)}\n expanded={expanded}\n />\n ))}\n </Stack>\n );\n};\n","import { useApi } from '@backstage/core-plugin-api';\nimport { statuspageApiRef } from '../api/StatuspageApi';\nimport useAsync from 'react-use/lib/useAsync';\nimport {\n Component,\n ComponentGroup,\n} from '@axis-backstage/plugin-statuspage-common';\n\nexport const useComponents = (name: string) => {\n const statuspageApi = useApi(statuspageApiRef);\n\n return useAsync(async (): Promise<{\n components: Component[];\n componentGroups: ComponentGroup[];\n url?: string;\n }> => {\n const components = await statuspageApi.getComponents(name);\n const componentGroups = await statuspageApi.getComponentGroups(name);\n const { url } = await statuspageApi.getLink(name);\n return {\n components,\n componentGroups,\n url,\n };\n }, [name]);\n};\n","import React from 'react';\nimport {\n InfoCard,\n Progress,\n ResponseErrorPanel,\n} from '@backstage/core-components';\nimport type { ComponentStatus } from '@axis-backstage/plugin-statuspage-common';\nimport { ComponentGroupsList } from './ComponentGroupsList';\nimport IconButton from '@mui/material/IconButton';\nimport OpenInNewIcon from '@mui/icons-material/OpenInNew';\nimport { useComponents } from '../hooks/useComponents';\n\n/**\n * StatuspageComponent props.\n *\n * @public\n */\nexport type StatuspageProps = {\n name: string;\n};\n\n/**\n * Maps statuspage component statuses to MUI colors.\n *\n * @public\n */\nexport const statusColorMap: { [key in ComponentStatus]: string } = {\n under_maintenance: 'info',\n operational: 'success',\n degraded_performance: 'warning',\n partial_outage: 'warning',\n major_outage: 'error',\n};\n\n/**\n * Visualizes a full statuspage.\n *\n * @param name - instance name from app config.\n * @public\n */\nexport const StatuspageComponent = ({ name }: StatuspageProps) => {\n const { loading, error, value } = useComponents(name);\n\n if (loading) {\n return <Progress />;\n }\n if (error) {\n return <ResponseErrorPanel error={error} />;\n }\n\n const linkAction = value?.url && (\n <IconButton\n aria-label=\"Go to our statuspage\"\n role=\"button\"\n title=\"Go to statuspage(.io)\"\n href={value?.url}\n target=\"_blank\"\n >\n <OpenInNewIcon />\n </IconButton>\n );\n\n return (\n <InfoCard title=\"Status of our services\" action={linkAction}>\n <ComponentGroupsList\n components={value?.components || []}\n componentGroups={value?.componentGroups || []}\n />\n </InfoCard>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -1,72 +0,0 @@
1
- import React from 'react';
2
- import { Progress, ResponseErrorPanel, InfoCard } from '@backstage/core-components';
3
- import OpenInNewIcon from '@mui/icons-material/OpenInNew';
4
- import { useEntity } from '@backstage/plugin-catalog-react';
5
- import { u as useComponents, C as ComponentsTable, a as ComponentGroupsList } from './StatuspageComponent-b7a15df1.esm.js';
6
- import IconButton from '@mui/material/IconButton';
7
- import Typography from '@mui/material/Typography';
8
- import { STATUSPAGE_ANNOTATION } from '@axis-backstage/plugin-statuspage-common';
9
- import '@mui/material/Stack';
10
- import '@mui/material/Accordion';
11
- import '@mui/material/AccordionDetails';
12
- import '@mui/material/AccordionSummary';
13
- import '@mui/material/styles';
14
- import '@mui/icons-material/ExpandMore';
15
- import '@mui/material/Chip';
16
- import '@backstage/core-plugin-api';
17
- import './index-f9afba17.esm.js';
18
- import 'react-use/lib/useAsync';
19
- import '@mui/material/Unstable_Grid2';
20
-
21
- const StatuspageEntityComponent = () => {
22
- var _a, _b;
23
- const { entity } = useEntity();
24
- const [name, wantedComponentsStr] = (_b = (_a = entity.metadata.annotations) == null ? void 0 : _a[STATUSPAGE_ANNOTATION]) == null ? void 0 : _b.split(":");
25
- const wantedComponents = wantedComponentsStr == null ? void 0 : wantedComponentsStr.split(",").map((it) => it.trim());
26
- const { loading, error, value } = useComponents(name);
27
- if (loading) {
28
- return /* @__PURE__ */ React.createElement(Progress, null);
29
- }
30
- if (error) {
31
- return /* @__PURE__ */ React.createElement(ResponseErrorPanel, { error });
32
- }
33
- if (loading) {
34
- return /* @__PURE__ */ React.createElement(Progress, null);
35
- }
36
- if (error) {
37
- return /* @__PURE__ */ React.createElement(ResponseErrorPanel, { error });
38
- }
39
- const linkAction = (value == null ? void 0 : value.url) && /* @__PURE__ */ React.createElement(
40
- IconButton,
41
- {
42
- "aria-label": "Go to our statuspage",
43
- role: "button",
44
- title: "Go to statuspage(.io)",
45
- href: value == null ? void 0 : value.url,
46
- target: "_blank"
47
- },
48
- /* @__PURE__ */ React.createElement(OpenInNewIcon, null)
49
- );
50
- const fullStatuspage = !wantedComponents;
51
- const filteredComponents = (value == null ? void 0 : value.components.filter(
52
- (c) => !fullStatuspage && !c.group && wantedComponents.includes(c.id)
53
- )) || [];
54
- const filteredComponentGroups = (value == null ? void 0 : value.componentGroups.filter(
55
- (c) => fullStatuspage || wantedComponents.includes(c.id)
56
- )) || [];
57
- const noComponents = (!filteredComponents || filteredComponentGroups.length === 0) && filteredComponents && filteredComponents.length === 0;
58
- if (noComponents) {
59
- return /* @__PURE__ */ React.createElement(InfoCard, { title: "Service Status", action: linkAction }, /* @__PURE__ */ React.createElement(Typography, { variant: "body2", color: "#FF5555" }, "The specified statuspage.io components could not be found. Check your annotation."));
60
- }
61
- return /* @__PURE__ */ React.createElement(InfoCard, { title: "Service Status", action: linkAction }, filteredComponents && filteredComponents.length > 0 && /* @__PURE__ */ React.createElement(ComponentsTable, { components: filteredComponents }), filteredComponentGroups && filteredComponentGroups.length > 0 && /* @__PURE__ */ React.createElement(
62
- ComponentGroupsList,
63
- {
64
- components: (value == null ? void 0 : value.components) || [],
65
- componentGroups: filteredComponentGroups,
66
- expanded: !fullStatuspage
67
- }
68
- ));
69
- };
70
-
71
- export { StatuspageEntityComponent };
72
- //# sourceMappingURL=StatuspageEntityComponent-9fe1f0c9.esm.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"StatuspageEntityComponent-9fe1f0c9.esm.js","sources":["../../src/components/StatuspageEntityComponent.tsx"],"sourcesContent":["import React from 'react';\nimport {\n InfoCard,\n Progress,\n ResponseErrorPanel,\n} from '@backstage/core-components';\nimport OpenInNewIcon from '@mui/icons-material/OpenInNew';\nimport { useEntity } from '@backstage/plugin-catalog-react';\nimport { ComponentsTable } from './ComponentsTable';\nimport { ComponentGroupsList } from './ComponentGroupsList';\nimport IconButton from '@mui/material/IconButton';\nimport Typography from '@mui/material/Typography';\nimport { STATUSPAGE_ANNOTATION } from '@axis-backstage/plugin-statuspage-common';\nimport { useComponents } from '../hooks/useComponents';\n\n/**\n * Statuspage card intended for the EntityPage. Allows embedding of specific\n * statuspage components and component groups.\n *\n * @public\n */\nexport const StatuspageEntityComponent = () => {\n const { entity } = useEntity();\n const [name, wantedComponentsStr] =\n entity.metadata.annotations?.[STATUSPAGE_ANNOTATION]?.split(':')!;\n const wantedComponents = wantedComponentsStr?.split(',').map(it => it.trim());\n\n const { loading, error, value } = useComponents(name);\n\n if (loading) {\n return <Progress />;\n }\n if (error) {\n return <ResponseErrorPanel error={error} />;\n }\n\n if (loading) {\n return <Progress />;\n }\n if (error) {\n return <ResponseErrorPanel error={error} />;\n }\n\n const linkAction = value?.url && (\n <IconButton\n aria-label=\"Go to our statuspage\"\n role=\"button\"\n title=\"Go to statuspage(.io)\"\n href={value?.url}\n target=\"_blank\"\n >\n <OpenInNewIcon />\n </IconButton>\n );\n\n const fullStatuspage = !wantedComponents;\n const filteredComponents =\n value?.components.filter(\n c => !fullStatuspage && !c.group && wantedComponents.includes(c.id),\n ) || [];\n const filteredComponentGroups =\n value?.componentGroups.filter(\n c => fullStatuspage || wantedComponents.includes(c.id),\n ) || [];\n const noComponents =\n (!filteredComponents || filteredComponentGroups.length === 0) &&\n filteredComponents &&\n filteredComponents.length === 0;\n\n if (noComponents) {\n return (\n <InfoCard title=\"Service Status\" action={linkAction}>\n <Typography variant=\"body2\" color=\"#FF5555\">\n The specified statuspage.io components could not be found. Check your\n annotation.\n </Typography>\n </InfoCard>\n );\n }\n return (\n <InfoCard title=\"Service Status\" action={linkAction}>\n {filteredComponents && filteredComponents.length > 0 && (\n <ComponentsTable components={filteredComponents} />\n )}\n {filteredComponentGroups && filteredComponentGroups.length > 0 && (\n <ComponentGroupsList\n components={value?.components || []}\n componentGroups={filteredComponentGroups}\n expanded={!fullStatuspage}\n />\n )}\n </InfoCard>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -1,116 +0,0 @@
1
- import { createRouteRef, createApiRef, createPlugin, createApiFactory, discoveryApiRef, fetchApiRef, createRoutableExtension } from '@backstage/core-plugin-api';
2
- import { STATUSPAGE_ANNOTATION } from '@axis-backstage/plugin-statuspage-common';
3
-
4
- const rootRouteRef = createRouteRef({
5
- id: "statuspage"
6
- });
7
-
8
- const statuspageApiRef = createApiRef({
9
- id: "plugin.statuspage"
10
- });
11
-
12
- var __defProp = Object.defineProperty;
13
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
14
- var __publicField = (obj, key, value) => {
15
- __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
16
- return value;
17
- };
18
- class StatuspageClient {
19
- constructor(options) {
20
- __publicField(this, "discoveryApi");
21
- __publicField(this, "fetchApi");
22
- this.discoveryApi = options.discoveryApi;
23
- this.fetchApi = options.fetchApi;
24
- }
25
- async getLink(name) {
26
- const baseUrl = await this.discoveryApi.getBaseUrl("statuspage");
27
- const response = await this.fetchApi.fetch(
28
- `${baseUrl}/fetch-link/${encodeURIComponent(name)}`,
29
- {
30
- method: "GET",
31
- headers: {
32
- "Content-Type": "application/json"
33
- }
34
- }
35
- );
36
- if (response.ok) {
37
- const data = await response.json();
38
- return data;
39
- }
40
- throw new Error(
41
- `Failed to get statuspage link for ${name} with status code ${response.status}`
42
- );
43
- }
44
- async getComponents(name) {
45
- const baseUrl = await this.discoveryApi.getBaseUrl("statuspage");
46
- const data = await this.fetchApi.fetch(
47
- `${baseUrl}/fetch-components/${encodeURIComponent(name)}`,
48
- {
49
- method: "GET",
50
- headers: {
51
- "Content-Type": "application/json"
52
- }
53
- }
54
- );
55
- if (data.ok)
56
- return data.json();
57
- throw new Error(`Failed to get statuspage components for ${name}`);
58
- }
59
- async getComponentGroups(name) {
60
- const baseUrl = await this.discoveryApi.getBaseUrl("statuspage");
61
- const data = await this.fetchApi.fetch(
62
- `${baseUrl}/fetch-component-groups/${encodeURIComponent(name)}`,
63
- {
64
- method: "GET",
65
- headers: {
66
- "Content-Type": "application/json"
67
- }
68
- }
69
- );
70
- if (data.ok)
71
- return data.json();
72
- throw new Error(`Failed to get statuspage component groups for ${name}`);
73
- }
74
- }
75
-
76
- const isStatuspageAvailable = (entity) => {
77
- var _a;
78
- return Boolean((_a = entity.metadata.annotations) == null ? void 0 : _a[STATUSPAGE_ANNOTATION]);
79
- };
80
- const statuspagePlugin = createPlugin({
81
- id: "statuspage",
82
- apis: [
83
- createApiFactory({
84
- api: statuspageApiRef,
85
- deps: {
86
- discoveryApi: discoveryApiRef,
87
- fetchApi: fetchApiRef
88
- },
89
- factory: ({ discoveryApi, fetchApi }) => new StatuspageClient({ discoveryApi, fetchApi })
90
- })
91
- ],
92
- routes: {
93
- root: rootRouteRef
94
- }
95
- });
96
- const StatuspagePage = statuspagePlugin.provide(
97
- createRoutableExtension({
98
- name: "StatuspagePage",
99
- component: () => import('./StatuspageComponent-b7a15df1.esm.js').then(function (n) { return n.S; }).then(
100
- (m) => m.StatuspageComponent
101
- ),
102
- mountPoint: rootRouteRef
103
- })
104
- );
105
- const StatuspageEntityCard = statuspagePlugin.provide(
106
- createRoutableExtension({
107
- name: "StatuspageEntityCard",
108
- component: () => import('./StatuspageEntityComponent-9fe1f0c9.esm.js').then(
109
- (m) => m.StatuspageEntityComponent
110
- ),
111
- mountPoint: rootRouteRef
112
- })
113
- );
114
-
115
- export { StatuspagePage as S, statuspagePlugin as a, StatuspageEntityCard as b, isStatuspageAvailable as i, statuspageApiRef as s };
116
- //# sourceMappingURL=index-f9afba17.esm.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index-f9afba17.esm.js","sources":["../../src/routes.ts","../../src/api/StatuspageApi.ts","../../src/api/StatuspageClient.ts","../../src/plugin.ts"],"sourcesContent":["import { createRouteRef } from '@backstage/core-plugin-api';\n\nexport const rootRouteRef = createRouteRef({\n id: 'statuspage',\n});\n","import { createApiRef } from '@backstage/core-plugin-api';\n\nimport type {\n Component,\n ComponentGroup,\n} from '@axis-backstage/plugin-statuspage-common';\n\nexport type StatuspageApi = {\n getComponents(name: string): Promise<Component[]>;\n getComponentGroups(name: string): Promise<ComponentGroup[]>;\n getLink(name: string): Promise<{ url: string }>;\n};\n\nexport const statuspageApiRef = createApiRef<StatuspageApi>({\n id: 'plugin.statuspage',\n});\n","import { DiscoveryApi, FetchApi } from '@backstage/core-plugin-api';\nimport { StatuspageApi } from './StatuspageApi';\nimport {\n Component,\n ComponentGroup,\n} from '@axis-backstage/plugin-statuspage-common';\n\nexport class StatuspageClient implements StatuspageApi {\n private readonly discoveryApi: DiscoveryApi;\n private readonly fetchApi: FetchApi;\n\n constructor(options: { discoveryApi: DiscoveryApi; fetchApi: FetchApi }) {\n this.discoveryApi = options.discoveryApi;\n this.fetchApi = options.fetchApi;\n }\n\n async getLink(name: string): Promise<{ url: string }> {\n const baseUrl = await this.discoveryApi.getBaseUrl('statuspage');\n const response = await this.fetchApi.fetch(\n `${baseUrl}/fetch-link/${encodeURIComponent(name)}`,\n {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n },\n },\n );\n if (response.ok) {\n const data = await response.json();\n return data;\n }\n throw new Error(\n `Failed to get statuspage link for ${name} with status code ${response.status}`,\n );\n }\n\n async getComponents(name: string): Promise<Component[]> {\n const baseUrl = await this.discoveryApi.getBaseUrl('statuspage');\n const data = await this.fetchApi.fetch(\n `${baseUrl}/fetch-components/${encodeURIComponent(name)}`,\n {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n },\n },\n );\n\n if (data.ok) return data.json();\n throw new Error(`Failed to get statuspage components for ${name}`);\n }\n\n async getComponentGroups(name: string): Promise<ComponentGroup[]> {\n const baseUrl = await this.discoveryApi.getBaseUrl('statuspage');\n const data = await this.fetchApi.fetch(\n `${baseUrl}/fetch-component-groups/${encodeURIComponent(name)}`,\n {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n },\n },\n );\n\n if (data.ok) return data.json();\n throw new Error(`Failed to get statuspage component groups for ${name}`);\n }\n}\n","import {\n createApiFactory,\n createPlugin,\n createRoutableExtension,\n discoveryApiRef,\n fetchApiRef,\n} from '@backstage/core-plugin-api';\n\nimport { STATUSPAGE_ANNOTATION } from '@axis-backstage/plugin-statuspage-common';\nimport { Entity } from '@backstage/catalog-model';\n\nimport { rootRouteRef } from './routes';\nimport { statuspageApiRef } from './api/StatuspageApi';\nimport { StatuspageClient } from './api/StatuspageClient';\n\n/**\n * Checks availability of a statuspage component\n *\n * @public\n */\nexport const isStatuspageAvailable = (entity: Entity) =>\n Boolean(entity.metadata.annotations?.[STATUSPAGE_ANNOTATION]);\n\n/**\n * Create the plugin.\n *\n * @public\n */\nexport const statuspagePlugin = createPlugin({\n id: 'statuspage',\n apis: [\n createApiFactory({\n api: statuspageApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n fetchApi: fetchApiRef,\n },\n factory: ({ discoveryApi, fetchApi }) =>\n new StatuspageClient({ discoveryApi, fetchApi }),\n }),\n ],\n routes: {\n root: rootRouteRef,\n },\n});\n\n/**\n * Routable extension for StatuspageComponent.\n *\n * @public\n */\nexport const StatuspagePage = statuspagePlugin.provide(\n createRoutableExtension({\n name: 'StatuspagePage',\n component: () =>\n import('./components/StatuspageComponent').then(\n m => m.StatuspageComponent,\n ),\n mountPoint: rootRouteRef,\n }),\n);\n\n/**\n * Routable extension for StatuspageComponent.\n *\n * @public\n */\nexport const StatuspageEntityCard = statuspagePlugin.provide(\n createRoutableExtension({\n name: 'StatuspageEntityCard',\n component: () =>\n import('./components/StatuspageEntityComponent').then(\n m => m.StatuspageEntityComponent,\n ),\n mountPoint: rootRouteRef,\n }),\n);\n"],"names":[],"mappings":"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"}