Files
Sonia Aguilar 64ee42d01e Alerting: Add limits and move state and label matching filters to the BE (#66267)
* WIP

* Add instance totals to combined rule. Use totals to display instances stats in the UI

* WIP

* add global summaries, fix TS errors

* fix useCombined test

* fix test

* use activeAt from rule when available

* Fix NaN in global stats

* Add no data total to global summary

* Add totals recalculation for filtered rules

* Fix instances totals, remove instances filtering from alert list view

* Update tests

* Fetch alerts considering filtering label matchers

* WIP - Fetch alerts appending state filter to endpoint

* Fix multiple values for state in request being applyied

* fix test

* Calculate hidden by for grafana managed alerts

* Use INSTANCES_DISPLAY_LIMIT constant for limiting alert instances instead of 1

* Rename matchers parameter according to API changes

* Fix calculating total number of grafana instances

* Rename matcher prop after previous change

* Display button to remove max instances limit

* Change matcher query param to be an array of strings

* Add test for paramsWithMatcherAndState method

* Refactor matcher to be an string array to be consistent with state

* Use matcher query string as matcher object type (encoded JSON)

* Avoind encoding matcher parameters twice

* fix tests

* Enable toggle for the limit/show all button and restore limit and filters when we come back from custom view

* Move getMatcherListFromString method to utils/alertmanager.ts

* Fix limit toggle button being shown when it's not necessary

* Use filteredTotals from be response to calculate hidden by count

* Fix variables not being replaced correctly

* Fix total shown to be all the instances filtered without limits

* Adress some PR review comments

* Move paramsWithMatcherAndState inside prometheusUrlBuilder method

---------

Co-authored-by: Gilles De Mey <gilles.de.mey@gmail.com>
Co-authored-by: Konrad Lalik <konrad.lalik@grafana.com>
Co-authored-by: Virginia Cepeda <virginia.cepeda@grafana.com>
2023-04-25 11:19:20 +02:00

90 lines
2.3 KiB
TypeScript

import { css } from '@emotion/css';
import React, { useMemo } from 'react';
import { GrafanaTheme2, intervalToAbbreviatedDurationString } from '@grafana/data';
import { Stack } from '@grafana/experimental';
import { Spinner, useStyles2 } from '@grafana/ui';
import { CombinedRule } from 'app/types/unified-alerting';
import { PromAlertingRuleState } from 'app/types/unified-alerting-dto';
import { isAlertingRule, isRecordingRule, getFirstActiveAt } from '../../utils/rules';
import { AlertStateTag } from './AlertStateTag';
interface Props {
rule: CombinedRule;
isDeleting: boolean;
isCreating: boolean;
isPaused?: boolean;
}
export const RuleState = ({ rule, isDeleting, isCreating, isPaused }: Props) => {
const style = useStyles2(getStyle);
const { promRule } = rule;
// return how long the rule has been in its firing state, if any
const forTime = useMemo(() => {
if (
promRule &&
isAlertingRule(promRule) &&
promRule.alerts?.length &&
promRule.state !== PromAlertingRuleState.Inactive
) {
// find earliest alert
const firstActiveAt = promRule.activeAt ? new Date(promRule.activeAt) : getFirstActiveAt(promRule);
// calculate time elapsed from earliest alert
if (firstActiveAt) {
return (
<span title={String(firstActiveAt)} className={style.for}>
for{' '}
{intervalToAbbreviatedDurationString(
{
start: firstActiveAt,
end: new Date(),
},
false
)}
</span>
);
}
}
return null;
}, [promRule, style]);
if (isDeleting) {
return (
<Stack gap={1}>
<Spinner />
Deleting
</Stack>
);
} else if (isCreating) {
return (
<Stack gap={1}>
<Spinner />
Creating
</Stack>
);
} else if (promRule && isAlertingRule(promRule)) {
return (
<Stack gap={1}>
<AlertStateTag state={promRule.state} isPaused={isPaused} />
{forTime}
</Stack>
);
} else if (promRule && isRecordingRule(promRule)) {
return <>Recording rule</>;
}
return <>n/a</>;
};
const getStyle = (theme: GrafanaTheme2) => ({
for: css`
font-size: ${theme.typography.bodySmall.fontSize};
color: ${theme.colors.text.secondary};
white-space: nowrap;
padding-top: 2px;
`,
});