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

79 lines
2.8 KiB
TypeScript

import { lastValueFrom } from 'rxjs';
import { getBackendSrv } from '@grafana/runtime';
import { ContactPointsState, NotifierDTO, ReceiversStateDTO, ReceiverState } from 'app/types';
import { getDatasourceAPIUid } from '../utils/datasource';
export function fetchNotifiers(): Promise<NotifierDTO[]> {
return getBackendSrv().get(`/api/alert-notifiers`);
}
interface IntegrationNameObject {
type: string;
index?: string;
}
export const parseIntegrationName = (integrationName: string): IntegrationNameObject => {
const matches = integrationName.match(/^(\w+)(\[\d+\])?$/);
if (!matches) {
return { type: integrationName, index: undefined };
}
return {
type: matches[1],
index: matches[2],
};
};
export const contactPointsStateDtoToModel = (receiversStateDto: ReceiversStateDTO[]): ContactPointsState => {
// init object to return
const contactPointsState: ContactPointsState = { receivers: {}, errorCount: 0 };
// for each receiver from response
receiversStateDto.forEach((cpState) => {
//init receiver state
contactPointsState.receivers[cpState.name] = { active: cpState.active, notifiers: {}, errorCount: 0 };
const receiverState = contactPointsState.receivers[cpState.name];
//update integrations in response
cpState.integrations.forEach((integrationStatusDTO) => {
//update errorcount
const hasError = Boolean(integrationStatusDTO?.lastNotifyAttemptError);
if (hasError) {
receiverState.errorCount += 1;
}
//add integration for this type
const integrationType = getIntegrationType(integrationStatusDTO.name);
if (integrationType) {
//if type still does not exist in IntegrationsTypeState we initialize it with an empty array
if (!receiverState.notifiers[integrationType]) {
receiverState.notifiers[integrationType] = [];
}
// add error status for this type
receiverState.notifiers[integrationType].push(integrationStatusDTO);
}
});
});
const errorsCount = Object.values(contactPointsState.receivers).reduce(
(prevCount: number, receiverState: ReceiverState) => prevCount + receiverState.errorCount,
0
);
return { ...contactPointsState, errorCount: errorsCount };
};
export const getIntegrationType = (integrationName: string): string | undefined =>
parseIntegrationName(integrationName)?.type;
export async function fetchContactPointsState(alertManagerSourceName: string): Promise<ContactPointsState> {
try {
const response = await lastValueFrom(
getBackendSrv().fetch<ReceiversStateDTO[]>({
url: `/api/alertmanager/${getDatasourceAPIUid(alertManagerSourceName)}/config/api/v1/receivers`,
showErrorAlert: false,
showSuccessAlert: false,
})
);
return contactPointsStateDtoToModel(response.data);
} catch (error) {
return contactPointsStateDtoToModel([]);
}
}