diff --git a/plugins/splunk-on-call/src/components/EntitySplunkOnCallCard.test.tsx b/plugins/splunk-on-call/src/components/EntitySplunkOnCallCard.test.tsx index a83db136e4..6944dee4c9 100644 --- a/plugins/splunk-on-call/src/components/EntitySplunkOnCallCard.test.tsx +++ b/plugins/splunk-on-call/src/components/EntitySplunkOnCallCard.test.tsx @@ -53,6 +53,14 @@ const mockSplunkOnCallApi: Partial = { const configApi: ConfigApi = new ConfigReader({ splunkOnCall: { eventsRestEndpoint: 'EXAMPLE_REST_ENDPOINT', + readOnly: false, + }, +}); + +const readOnlyConfigApi: ConfigApi = new ConfigReader({ + splunkOnCall: { + eventsRestEndpoint: 'EXAMPLE_REST_ENDPOINT', + readOnly: true, }, }); @@ -62,6 +70,12 @@ const apis = TestApiRegistry.from( [alertApiRef, {}], ); +const readOnlyApis = TestApiRegistry.from( + [splunkOnCallApiRef, mockSplunkOnCallApi], + [configApiRef, readOnlyConfigApi], + [alertApiRef, {}], +); + const mockEntity = { apiVersion: 'backstage.io/v1alpha1', kind: 'Component', @@ -131,6 +145,32 @@ describe('SplunkOnCallCard', () => { expect(getByText('Empty escalation policy')).toBeInTheDocument(); }); + it('does not render a "Create incident" link in read only mode', async () => { + mockSplunkOnCallApi.getUsers = jest + .fn() + .mockImplementationOnce(async () => [MOCKED_USER]); + mockSplunkOnCallApi.getTeams = jest + .fn() + .mockImplementation(async () => [MOCK_TEAM_NO_INCIDENTS]); + + const { getByText, queryByTestId } = render( + wrapInTestApp( + + + + + , + ), + ); + await waitFor(() => !queryByTestId('progress')); + expect(() => getByText('Create Incident')).toThrow(); + await waitFor( + () => expect(getByText('Nice! No incidents found!')).toBeInTheDocument(), + { timeout: 2000 }, + ); + expect(getByText('Empty escalation policy')).toBeInTheDocument(); + }); + it('handles a "splunk.com/on-call-routing-key" annotation', async () => { mockSplunkOnCallApi.getUsers = jest .fn() diff --git a/plugins/splunk-on-call/src/components/EntitySplunkOnCallCard.tsx b/plugins/splunk-on-call/src/components/EntitySplunkOnCallCard.tsx index 4a6f983636..1727e462c1 100644 --- a/plugins/splunk-on-call/src/components/EntitySplunkOnCallCard.tsx +++ b/plugins/splunk-on-call/src/components/EntitySplunkOnCallCard.tsx @@ -124,7 +124,9 @@ export const EntitySplunkOnCallCard = () => { : undefined; const eventsRestEndpoint = - config.getOptionalString('splunkOnCall.eventsRestEndpoint') || null; + config.getOptionalString('splunkOnCall.eventsRestEndpoint') || true; + + const readOnly = config.getOptionalBoolean('splunkOnCall.readOnly') || false; const handleRefresh = useCallback(() => { setRefreshIncidents(x => !x); @@ -218,7 +220,11 @@ export const EntitySplunkOnCallCard = () => { return ( <> - + {usersHashMap && team && ( )} @@ -259,7 +265,7 @@ export const EntitySplunkOnCallCard = () => { , , ]} /> diff --git a/plugins/splunk-on-call/src/components/Incident/IncidentListItem.tsx b/plugins/splunk-on-call/src/components/Incident/IncidentListItem.tsx index 4c9975bd06..8078f07fc7 100644 --- a/plugins/splunk-on-call/src/components/Incident/IncidentListItem.tsx +++ b/plugins/splunk-on-call/src/components/Incident/IncidentListItem.tsx @@ -64,6 +64,7 @@ type Props = { team: string; incident: Incident; onIncidentAction: () => void; + readOnly: boolean; }; const IncidentPhaseStatus = ({ @@ -135,6 +136,7 @@ const IncidentAction = ({ export const IncidentListItem = ({ incident, + readOnly, onIncidentAction, team, }: Props) => { @@ -241,12 +243,16 @@ export const IncidentListItem = ({ {incident.incidentLink && incident.incidentNumber && ( - + {!readOnly ? ( + + ) : ( + '' + )} { expect(getAllByTitle('View in Splunk On-Call').length).toEqual(1); }); + it('does not render incident action buttons in read only mode', async () => { + mockSplunkOnCallApi.getIncidents.mockResolvedValue([MOCK_INCIDENT]); + mockSplunkOnCallApi.getTeams.mockResolvedValue([MOCK_TEAM]); + + const { + getByText, + getByTitle, + getAllByTitle, + getByLabelText, + queryByTestId, + } = render( + wrapInTestApp( + + + , + ), + ); + await waitFor(() => !queryByTestId('progress')); + await waitFor( + () => + expect( + getByText('user', { + exact: false, + }), + ).toBeInTheDocument(), + { timeout: 2000 }, + ); + expect(getByText('test-incident')).toBeInTheDocument(); + expect(getByLabelText('Status warning')).toBeInTheDocument(); + expect(() => getAllByTitle('Acknowledge')).toThrow( + 'Unable to find an element with the title: Acknowledge.', + ); + expect(() => getAllByTitle('Resolve')).toThrow( + 'Unable to find an element with the title: Resolve.', + ); + + // assert links, mailto and hrefs, date calculation + expect(getAllByTitle('View in Splunk On-Call').length).toEqual(1); + }); + it('Handle errors', async () => { mockSplunkOnCallApi.getIncidents.mockRejectedValueOnce( new Error('Error occurred'), diff --git a/plugins/splunk-on-call/src/components/Incident/Incidents.tsx b/plugins/splunk-on-call/src/components/Incident/Incidents.tsx index 3c557773fd..e2ec9609bd 100644 --- a/plugins/splunk-on-call/src/components/Incident/Incidents.tsx +++ b/plugins/splunk-on-call/src/components/Incident/Incidents.tsx @@ -49,9 +49,10 @@ const useStyles = makeStyles((theme: Theme) => type Props = { refreshIncidents: boolean; team: string; + readOnly: boolean; }; -export const Incidents = ({ refreshIncidents, team }: Props) => { +export const Incidents = ({ readOnly, refreshIncidents, team }: Props) => { const classes = useStyles(); const api = useApi(splunkOnCallApiRef); @@ -108,6 +109,7 @@ export const Incidents = ({ refreshIncidents, team }: Props) => { key={index} team={team} incident={incident} + readOnly={readOnly} /> )) )}