Composability updates for Splunk On-Call plugin

Signed-off-by: Tim Hansen <timbonicus@gmail.com>
This commit is contained in:
Tim Hansen
2021-05-17 11:22:42 -06:00
parent 99dddfb610
commit 8aa0b60257
7 changed files with 97 additions and 57 deletions
+23
View File
@@ -0,0 +1,23 @@
---
'@backstage/plugin-splunk-on-call': minor
---
Updates the Splunk On-Call plugin for the [composability system
migration](https://backstage.io/docs/plugins/composability#porting-existing-plugins).
To upgrade, modify your `EntityPage` to use the updated export names. The
`EntitySplunkOnCallCard` should be wrapped in an `<EntitySwitch>` condition as
shown in the plugin README, which you may already have in place.
```diff
import {
- isPluginApplicableToEntity as isSplunkOnCallAvailable,
+ isSplunkOnCallAvailable,
- SplunkOnCallCard
+ EntitySplunkOnCallCard,
} from '@backstage/plugin-splunk-on-call';
...
- <SplunkOnCallCard entity={entity}>
+ <EntitySplunkOnCallCard />
```
+13 -16
View File
@@ -25,27 +25,24 @@ cd packages/app
yarn add @backstage/plugin-splunk-on-call
```
Add it to the app in `plugins.ts`:
```ts
export { plugin as SplunkOnCall } from '@backstage/plugin-splunk-on-call';
```
Add it to the `EntityPage.tsx`:
Add it to your `EntityPage`:
```ts
// packages/app/src/components/catalog/EntityPage.tsx
import {
isPluginApplicableToEntity as isSplunkOnCallAvailable,
SplunkOnCallCard,
isSplunkOnCallAvailable,
EntitySplunkOnCallCard,
} from '@backstage/plugin-splunk-on-call';
// ...
{
isSplunkOnCallAvailable(entity) && (
<Grid item md={6}>
<SplunkOnCallCard entity={entity} />
</Grid>
);
}
const overviewContent = (
<Grid container spacing={3} alignItems="stretch">
<EntitySwitch>
<EntitySwitch.Case if={isSplunkOnCallAvailable}>
<Grid item md={6}>
<EntitySplunkOnCallCard />
</Grid>
</EntitySwitch.Case>
</EntitySwitch>
```
## Client configuration
@@ -14,10 +14,8 @@
* limitations under the License.
*/
import React from 'react';
import { render, waitFor, fireEvent, act } from '@testing-library/react';
import { SplunkOnCallCard } from './SplunkOnCallCard';
import { act, fireEvent, render, waitFor } from '@testing-library/react';
import { Entity } from '@backstage/catalog-model';
import { wrapInTestApp } from '@backstage/test-utils';
import {
alertApiRef,
ApiProvider,
@@ -27,10 +25,12 @@ import {
ConfigReader,
createApiRef,
} from '@backstage/core';
import { EntityContext } from '@backstage/plugin-catalog-react';
import { wrapInTestApp } from '@backstage/test-utils';
import {
splunkOnCallApiRef,
UnauthorizedError,
SplunkOnCallClient,
UnauthorizedError,
} from '../api';
import {
ESCALATION_POLICIES,
@@ -39,6 +39,7 @@ import {
MOCK_INCIDENT,
MOCK_TEAM,
} from '../api/mocks';
import { EntitySplunkOnCallCard } from './EntitySplunkOnCallCard';
const mockSplunkOnCallApi: Partial<SplunkOnCallClient> = {
getUsers: async () => [],
@@ -65,15 +66,20 @@ const apis = ApiRegistry.from([
}),
],
]);
const entity: Entity = {
apiVersion: 'backstage.io/v1alpha1',
kind: 'Component',
metadata: {
name: 'splunkoncall-test',
annotations: {
'splunk.com/on-call-team': 'Example',
const mockEntityData = {
loading: false,
error: undefined,
entity: {
apiVersion: 'backstage.io/v1alpha1',
kind: 'Component',
metadata: {
name: 'splunkoncall-test',
annotations: {
'splunk.com/on-call-team': 'Example',
},
},
},
} as Entity,
};
describe('SplunkOnCallCard', () => {
@@ -85,7 +91,9 @@ describe('SplunkOnCallCard', () => {
const { getByText, queryByTestId } = render(
wrapInTestApp(
<ApiProvider apis={apis}>
<SplunkOnCallCard entity={entity} />
<EntityContext.Provider value={mockEntityData}>
<EntitySplunkOnCallCard />
</EntityContext.Provider>
</ApiProvider>,
),
);
@@ -106,7 +114,9 @@ describe('SplunkOnCallCard', () => {
const { getByText, queryByTestId } = render(
wrapInTestApp(
<ApiProvider apis={apis}>
<SplunkOnCallCard entity={entity} />
<EntityContext.Provider value={mockEntityData}>
<EntitySplunkOnCallCard />
</EntityContext.Provider>
</ApiProvider>,
),
);
@@ -123,7 +133,9 @@ describe('SplunkOnCallCard', () => {
const { getByText, queryByTestId } = render(
wrapInTestApp(
<ApiProvider apis={apis}>
<SplunkOnCallCard entity={entity} />
<EntityContext.Provider value={mockEntityData}>
<EntitySplunkOnCallCard />
</EntityContext.Provider>
</ApiProvider>,
),
);
@@ -144,7 +156,9 @@ describe('SplunkOnCallCard', () => {
const { getByText, queryByTestId, getByRole } = render(
wrapInTestApp(
<ApiProvider apis={apis}>
<SplunkOnCallCard entity={entity} />
<EntityContext.Provider value={mockEntityData}>
<EntitySplunkOnCallCard />
</EntityContext.Provider>
</ApiProvider>,
),
);
@@ -13,33 +13,34 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React, { useState, useCallback } from 'react';
import React, { useCallback, useState } from 'react';
import { useAsync } from 'react-use';
import {
useApi,
Progress,
HeaderIconLinkRow,
MissingAnnotationEmptyState,
configApiRef,
EmptyState,
HeaderIconLinkRow,
IconLinkVerticalProps,
MissingAnnotationEmptyState,
Progress,
useApi,
} from '@backstage/core';
import { Entity } from '@backstage/catalog-model';
import { useEntity } from '@backstage/plugin-catalog-react';
import {
Card,
CardContent,
CardHeader,
Divider,
CardContent,
Typography,
} from '@material-ui/core';
import { Incidents } from './Incident';
import { EscalationPolicy } from './Escalation';
import AlarmAddIcon from '@material-ui/icons/AlarmAdd';
import WebIcon from '@material-ui/icons/Web';
import { useAsync } from 'react-use';
import { Alert } from '@material-ui/lab';
import { splunkOnCallApiRef, UnauthorizedError } from '../api';
import AlarmAddIcon from '@material-ui/icons/AlarmAdd';
import { TriggerDialog } from './TriggerDialog';
import { MissingApiKeyOrApiIdError } from './Errors/MissingApiKeyOrApiIdError';
import { EscalationPolicy } from './Escalation';
import { Incidents } from './Incident';
import { TriggerDialog } from './TriggerDialog';
import { User } from './types';
export const SPLUNK_ON_CALL_TEAM = 'splunk.com/on-call-team';
@@ -58,16 +59,13 @@ export const MissingEventsRestEndpoint = () => (
</CardContent>
);
export const isPluginApplicableToEntity = (entity: Entity) =>
export const isSplunkOnCallAvailable = (entity: Entity) =>
Boolean(entity.metadata.annotations?.[SPLUNK_ON_CALL_TEAM]);
type Props = {
entity: Entity;
};
export const SplunkOnCallCard = ({ entity }: Props) => {
export const EntitySplunkOnCallCard = () => {
const config = useApi(configApiRef);
const api = useApi(splunkOnCallApiRef);
const { entity } = useEntity();
const [showDialog, setShowDialog] = useState<boolean>(false);
const [refreshIncidents, setRefreshIncidents] = useState<boolean>(false);
const team = entity.metadata.annotations![SPLUNK_ON_CALL_TEAM];
@@ -23,8 +23,7 @@ import {
Header,
SupportButton,
} from '@backstage/core';
import { SplunkOnCallCard } from './SplunkOnCallCard';
import { useEntity } from '@backstage/plugin-catalog-react';
import { EntitySplunkOnCallCard } from './EntitySplunkOnCallCard';
const useStyles = makeStyles(() => ({
overflowXScroll: {
@@ -44,7 +43,6 @@ export const SplunkOnCallPage = ({
pageTitle,
}: SplunkOnCallPageProps): JSX.Element => {
const classes = useStyles();
const { entity } = useEntity();
return (
<Page themeId="tool">
@@ -57,7 +55,7 @@ export const SplunkOnCallPage = ({
</ContentHeader>
<Grid container spacing={3} direction="row">
<Grid item xs={12} sm={6} md={4}>
<SplunkOnCallCard entity={entity} />
<EntitySplunkOnCallCard />
</Grid>
</Grid>
</Content>
+2 -4
View File
@@ -14,14 +14,12 @@
* limitations under the License.
*/
export {
SplunkOnCallCard,
splunkOnCallPlugin,
splunkOnCallPlugin as plugin,
SplunkOnCallPage,
} from './plugin';
export {
isPluginApplicableToEntity,
SplunkOnCallCard,
} from './components/SplunkOnCallCard';
export { isSplunkOnCallAvailable } from './components/EntitySplunkOnCallCard';
export {
SplunkOnCallClient,
splunkOnCallApiRef,
+12
View File
@@ -20,6 +20,7 @@ import {
discoveryApiRef,
configApiRef,
createRoutableExtension,
createComponentExtension,
} from '@backstage/core';
import { splunkOnCallApiRef, SplunkOnCallClient } from './api';
@@ -49,3 +50,14 @@ export const SplunkOnCallPage = splunkOnCallPlugin.provide(
mountPoint: rootRouteRef,
}),
);
export const SplunkOnCallCard = splunkOnCallPlugin.provide(
createComponentExtension({
component: {
lazy: () =>
import('./components/EntitySplunkOnCallCard').then(
m => m.EntitySplunkOnCallCard,
),
},
}),
);