mirror of
https://github.com/grafana/grafana.git
synced 2025-09-20 19:52:52 +08:00

* 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>
153 lines
5.7 KiB
TypeScript
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: {},
|
|
});
|
|
});
|
|
});
|