Alerting: Fix action buttons flickering in the old list view (#108321)

* fix action buttons flickering in the old list view

* prettier

* address review coments

* remove duplication

* add canCreateGrafanaRules check for ai button
This commit is contained in:
Sonia Aguilar
2025-07-24 13:05:56 +00:00
committed by GitHub
parent 1e8b065a0a
commit b129b28d7e
2 changed files with 79 additions and 61 deletions
@@ -1,16 +1,13 @@
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useLocation } from 'react-router-dom-v5-compat';
import { useAsyncFn, useInterval } from 'react-use';
import { urlUtil } from '@grafana/data';
import { Trans, t } from '@grafana/i18n';
import { logInfo } from '@grafana/runtime';
import { Button, LinkButton, Stack } from '@grafana/ui';
import { t } from '@grafana/i18n';
import { Button, Stack } from '@grafana/ui';
import { useQueryParams } from 'app/core/hooks/useQueryParams';
import { useDispatch } from 'app/types/store';
import { CombinedRuleNamespace } from 'app/types/unified-alerting';
import { LogMessages, trackRuleListNavigation } from '../Analytics';
import { trackRuleListNavigation } from '../Analytics';
import { AlertingPageWrapper } from '../components/AlertingPageWrapper';
import RulesFilter from '../components/rules/Filter/RulesFilter.v1';
import { NoRulesSplash } from '../components/rules/NoRulesCTA';
@@ -19,18 +16,16 @@ import { RuleListErrors } from '../components/rules/RuleListErrors';
import { RuleListGroupView } from '../components/rules/RuleListGroupView';
import { RuleListStateView } from '../components/rules/RuleListStateView';
import { RuleStats } from '../components/rules/RuleStats';
import { AIAlertRuleButtonComponent } from '../enterprise-components/AI/AIGenAlertRuleButton/addAIAlertRuleButton';
import { shouldUsePrometheusRulesPrimary } from '../featureToggles';
import { AlertingAction, useAlertingAbility } from '../hooks/useAbilities';
import { useCombinedRuleNamespaces } from '../hooks/useCombinedRuleNamespaces';
import { useFilteredRules, useRulesFilter } from '../hooks/useFilteredRules';
import { useUnifiedAlertingSelector } from '../hooks/useUnifiedAlertingSelector';
import { fetchAllPromAndRulerRulesAction, fetchAllPromRulesAction, fetchRulerRulesAction } from '../state/actions';
import { RULE_LIST_POLL_INTERVAL_MS } from '../utils/constants';
import { GRAFANA_RULES_SOURCE_NAME, getAllRulesSourceNames } from '../utils/datasource';
import { createRelativeUrl } from '../utils/url';
import { RuleListPageTitle } from './RuleListPageTitle';
import { RuleListActionButtons } from './components/RuleListActionButtons';
const VIEWS = {
groups: RuleListGroupView,
@@ -127,13 +122,7 @@ const RuleListV1 = () => {
navId="alert-list"
isLoading={false}
renderTitle={(title) => <RuleListPageTitle title={title} />}
actions={
hasAlertRulesCreated && (
<Stack gap={1}>
<CreateAlertButton /> <ExportNewRuleButton />
</Stack>
)
}
actions={<RuleListActionButtons hasAlertRulesCreated={hasAlertRulesCreated} />}
>
<Stack direction="column">
<RuleListErrors />
@@ -162,48 +151,3 @@ const RuleListV1 = () => {
};
export default RuleListV1;
export function CreateAlertButton() {
const [createRuleSupported, createRuleAllowed] = useAlertingAbility(AlertingAction.CreateAlertRule);
const [createCloudRuleSupported, createCloudRuleAllowed] = useAlertingAbility(AlertingAction.CreateExternalAlertRule);
const location = useLocation();
const canCreateCloudRules = createCloudRuleSupported && createCloudRuleAllowed;
const canCreateGrafanaRules = createRuleSupported && createRuleAllowed;
if (canCreateGrafanaRules || canCreateCloudRules) {
return (
<Stack direction="row" gap={1}>
<LinkButton
href={urlUtil.renderUrl('alerting/new/alerting', { returnTo: location.pathname + location.search })}
icon="plus"
onClick={() => logInfo(LogMessages.alertRuleFromScratch)}
>
<Trans i18nKey="alerting.rule-list.new-alert-rule">New alert rule</Trans>
</LinkButton>
{canCreateGrafanaRules && AIAlertRuleButtonComponent && <AIAlertRuleButtonComponent />}
</Stack>
);
}
return null;
}
function ExportNewRuleButton() {
const returnTo = window.location.pathname + window.location.search;
const url = createRelativeUrl(`/alerting/export-new-rule`, {
returnTo,
});
return (
<LinkButton
href={url}
icon="download-alt"
variant="secondary"
tooltip={t('alerting.export-new-rule-button.tooltip-export-new-grafana-rule', 'Export new grafana rule')}
onClick={() => logInfo(LogMessages.exportNewGrafanaRule)}
>
<Trans i18nKey="alerting.list-view.section.grafanaManaged.export-new-rule">Export rule definition</Trans>
</LinkButton>
);
}
@@ -0,0 +1,74 @@
import { memo } from 'react';
import { Trans, t } from '@grafana/i18n';
import { logInfo } from '@grafana/runtime';
import { LinkButton, Stack } from '@grafana/ui';
import { LogMessages } from '../../Analytics';
import { AIAlertRuleButtonComponent } from '../../enterprise-components/AI/AIGenAlertRuleButton/addAIAlertRuleButton';
import { AlertingAction, useAlertingAbility } from '../../hooks/useAbilities';
import { createReturnTo } from '../../hooks/useReturnTo';
import { createRelativeUrl } from '../../utils/url';
interface RuleListActionButtonsProps {
hasAlertRulesCreated: boolean;
}
export const RuleListActionButtons = memo<RuleListActionButtonsProps>(({ hasAlertRulesCreated }) => {
if (!hasAlertRulesCreated) {
return null;
}
return (
<Stack gap={1}>
<CreateAlertButtons />
<ExportNewRuleButton />
</Stack>
);
});
RuleListActionButtons.displayName = 'RuleListActionButtons';
function CreateAlertButtons() {
const [createRuleSupported, createRuleAllowed] = useAlertingAbility(AlertingAction.CreateAlertRule);
const [createCloudRuleSupported, createCloudRuleAllowed] = useAlertingAbility(AlertingAction.CreateExternalAlertRule);
const returnTo = createReturnTo();
const canCreateCloudRules = createCloudRuleSupported && createCloudRuleAllowed;
const canCreateGrafanaRules = createRuleSupported && createRuleAllowed;
if (canCreateGrafanaRules || canCreateCloudRules) {
return (
<Stack direction="row" gap={1}>
{canCreateGrafanaRules && <AIAlertRuleButtonComponent />}
<LinkButton
href={createRelativeUrl('/alerting/new/alerting', { returnTo })}
icon="plus"
onClick={() => logInfo(LogMessages.alertRuleFromScratch)}
>
<Trans i18nKey="alerting.rule-list.new-alert-rule">New alert rule</Trans>
</LinkButton>
</Stack>
);
}
return null;
}
function ExportNewRuleButton() {
const returnTo = createReturnTo();
const url = createRelativeUrl(`/alerting/export-new-rule`, {
returnTo,
});
return (
<LinkButton
href={url}
icon="download-alt"
variant="secondary"
tooltip={t('alerting.export-new-rule-button.tooltip-export-new-grafana-rule', 'Export new grafana rule')}
onClick={() => logInfo(LogMessages.exportNewGrafanaRule)}
>
<Trans i18nKey="alerting.list-view.section.grafanaManaged.export-new-rule">Export rule definition</Trans>
</LinkButton>
);
}