Files
Sonia Aguilar d8d8ef1aff Alerting: Add Notification error feedback on contact points view (#56225)
* Alerting: Receivers integrations error feedback: WIP - Add notifications error at the top right on contact points view (#52390)

* Add interfaces for contact point errors

* [WIP] Create fake response for the new service to get contact point errors

* [WIP] Create action an reducer for the new service to get contact point errors

* Fetch fetchContactPointStates in Contact Points tab every 20s and when AM changes

* [WIP] Use store to get error count

* Show number of integrations errors at the contact points main view

* Add warning icon and refactor styles using getStyles

* Change lastNotify type to string instead of DateTime

* Use Stack component from experimental library when it is possible

* Alerting: Add receivers error feedback in contact point list (#52524)

* Refactor types for contact points state

* Add health column in ReceiversTable in case error state is available for this AM

* Create method for converting contact points state DTO to the FE type used in Redux store

* Update types

* Fix indexOf criteria getting integration type

* Change type name to integrationType name

* Change new components to be named functions to follow the FE style-guide

* Fix typos

Co-authored-by: Konrad Lalik <konrad.lalik@grafana.com>

* Decouple ReceiversTable from Redux state

* Create private useContactPointsState hook to simplify code in ReceiversTable component

* Add tests for getIntegrationType and refactor the method to validate the name

* Add tests for contactPointsStateDtoToModel method

* Remove unnecessary check

* Use Badge compoment for health status in contact point list

* Create new method parseIntegrationName to simplify getting types and index from integration name

Co-authored-by: Konrad Lalik <konrad.lalik@grafana.com>

* Alerting: Show integrations error feedback when expanding contact point in list (#52920)

* Use DynamicTable for rendering list of contact points and make them expandable if error status is available

* Render expanded content for contact points integrations

* Style and format last notify column

* Add send resolve column to the integration details

* Fix receiver id for DynamicTable row

* Update clock icon in integration state

* Fix tests

* Add PR review sugestions

* Alerting/integrations error feedback handle null dates in response 3 (#55659)

* Update fake response with lastNotify ISO8601 formatted, to be aligned with latest BE changes

* Update LastNotify in ReceiversTable component to handle null date

* Alerting/integrations error feedback handle 404 state not available (#55803)

* Create fetchContactPointsState using the future contact point url and handle 404 error

* Add contact points state tests

* Alerting/update receivers dto naming 2 (#56201)

* Update NotifierStatus naming and fix sendResolved not being updated in UI

* Return always empty ContactPointsState array when catching an error in the request response

* Fix test

* Show notification status only in notifications main view

* Calculate total error count from the final contactPointsState object, to avoid errors when duplicated entries are returned wronly in the response

* Add PR review suggestions

Co-authored-by: Konrad Lalik <konrad.lalik@grafana.com>
2022-10-06 15:23:38 +02:00

153 lines
5.7 KiB
TypeScript

import { ReceiversStateDTO } from 'app/types';
import { contactPointsStateDtoToModel, getIntegrationType, parseIntegrationName } from './grafana';
describe('parseIntegrationName method', () => {
it('should return the integration name and index string when it is a valid type name with [{number}] ', () => {
const { type, index } = parseIntegrationName('coolIntegration[1]');
expect(type).toBe('coolIntegration');
expect(index).toBe('[1]');
});
it('should return the integration name when it is a valid type name without [{number}] ', () => {
const { type, index } = parseIntegrationName('coolIntegration');
expect(type).toBe('coolIntegration');
expect(index).toBe(undefined);
});
it('should return name as it is and index as undefined when it is a invalid index format ', () => {
const { type, index } = parseIntegrationName('coolIntegration[345vadkfjgh');
expect(type).toBe('coolIntegration[345vadkfjgh');
expect(index).toBe(undefined);
});
});
describe('getIntegrationType method', () => {
it('should return the integration name when it is a valid type name with [{number}] ', () => {
const name = getIntegrationType('coolIntegration[1]');
expect(name).toBe('coolIntegration');
const name2 = getIntegrationType('coolIntegration[6767]');
expect(name2).toBe('coolIntegration');
});
it('should return the integration name when it is a valid type name without [{number}] ', () => {
const name = getIntegrationType('coolIntegration');
expect(name).toBe('coolIntegration');
});
it('should return name as it is when it is a invalid index format ', () => {
const name = getIntegrationType('coolIntegration[345vadkfjgh');
expect(name).toBe('coolIntegration[345vadkfjgh');
});
});
describe('contactPointsStateDtoToModel method', () => {
it('should return the expected object', () => {
const response = [
{
active: true,
integrations: [
{
lastNotifyAttemptError:
'establish connection to server: dial tcp: lookup smtp.example.org on 8.8.8.8:53: no such host',
lastNotifyAttempt: '2022-07-08 17:42:44.998893 +0000 UTC',
lastNotifyAttemptDuration: '117.2455ms',
name: 'email[0]',
},
{
lastNotifyAttemptError:
'establish connection to server: dial tcp: lookup smtp.example.org on 8.8.8.8:53: no such host',
lastNotifyAttempt: '2022-07-08 17:42:44.998893 +0000 UTC',
lastNotifyAttemptDuration: '117.2455ms',
name: 'email[1]',
},
{
lastNotifyAttempt: '2022-07-08 17:42:44.998893 +0000 UTC',
lastNotifyAttemptDuration: '117.2455ms',
name: 'email[2]',
},
{
lastNotifyAttemptError:
'establish connection to server: dial tcp: lookup smtp.example.org on 8.8.8.8:53: no such host',
lastNotifyAttempt: '2022-07-08 17:42:44.998893 +0000 UTC',
lastNotifyAttemptDuration: '117.2455ms',
name: 'webhook[0]',
},
],
name: 'contact point 1',
},
{
active: true,
integrations: [
{
lastNotifyAttempt: '2022-07-08 17:42:44.998893 +0000 UTC',
lastNotifyAttemptDuration: '117.2455ms',
name: 'email[0]',
},
],
name: 'contact point 2',
},
];
expect(contactPointsStateDtoToModel(response)).toStrictEqual({
errorCount: 3,
receivers: {
'contact point 1': {
active: true,
errorCount: 3,
notifiers: {
email: [
{
lastNotifyAttemptError:
'establish connection to server: dial tcp: lookup smtp.example.org on 8.8.8.8:53: no such host',
lastNotifyAttempt: '2022-07-08 17:42:44.998893 +0000 UTC',
lastNotifyAttemptDuration: '117.2455ms',
name: 'email[0]',
},
{
lastNotifyAttemptError:
'establish connection to server: dial tcp: lookup smtp.example.org on 8.8.8.8:53: no such host',
lastNotifyAttempt: '2022-07-08 17:42:44.998893 +0000 UTC',
lastNotifyAttemptDuration: '117.2455ms',
name: 'email[1]',
},
{
lastNotifyAttempt: '2022-07-08 17:42:44.998893 +0000 UTC',
lastNotifyAttemptDuration: '117.2455ms',
name: 'email[2]',
},
],
webhook: [
{
lastNotifyAttemptError:
'establish connection to server: dial tcp: lookup smtp.example.org on 8.8.8.8:53: no such host',
lastNotifyAttempt: '2022-07-08 17:42:44.998893 +0000 UTC',
lastNotifyAttemptDuration: '117.2455ms',
name: 'webhook[0]',
},
],
},
},
'contact point 2': {
active: true,
errorCount: 0,
notifiers: {
email: [
{
lastNotifyAttempt: '2022-07-08 17:42:44.998893 +0000 UTC',
lastNotifyAttemptDuration: '117.2455ms',
name: 'email[0]',
},
],
},
},
},
});
});
//this test will be updated depending on how BE response is implemented when there is no state available for this AM
it('should return the expected object if response is an empty array (no state available for this AM)', () => {
const response: ReceiversStateDTO[] = [];
expect(contactPointsStateDtoToModel(response)).toStrictEqual({
errorCount: 0,
receivers: {},
});
});
});