Alerting: Fix loading states (#100641)

This commit is contained in:
Gilles De Mey 2025-02-14 11:38:38 +01:00 committed by GitHub
parent 9d68c4f665
commit ba3a90d8fd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 59 additions and 31 deletions

View File

@ -36,7 +36,7 @@ const RuleViewer = (): JSX.Element => {
}, [id]);
// we then fetch the rule from the correct API endpoint(s)
const { loading, error, result: rule } = useCombinedRule({ ruleIdentifier: identifier, limitAlerts });
const { loading, error, result: rule, uninitialized } = useCombinedRule({ ruleIdentifier: identifier, limitAlerts });
if (error) {
return (
@ -46,7 +46,7 @@ const RuleViewer = (): JSX.Element => {
);
}
if (loading) {
if (loading || uninitialized) {
return (
<AlertingPageWrapper pageNav={defaultPageNav} navId="alert-list" isLoading={true}>
<></>

View File

@ -80,6 +80,7 @@ interface RequestState<T> {
result?: T;
loading: boolean;
error?: unknown;
uninitialized: boolean;
}
interface Props {
@ -99,6 +100,7 @@ export function useCombinedRule({ ruleIdentifier, limitAlerts }: Props): Request
loading: isLoadingRuleLocation,
error: ruleLocationError,
result: ruleLocation,
uninitialized,
} = useRuleLocation(ruleIdentifier);
const {
@ -125,7 +127,12 @@ export function useCombinedRule({ ruleIdentifier, limitAlerts }: Props): Request
const [
fetchRulerRuleGroup,
{ currentData: rulerRuleGroup, isLoading: isLoadingRulerGroup, error: rulerRuleGroupError },
{
currentData: rulerRuleGroup,
isLoading: isLoadingRulerGroup,
error: rulerRuleGroupError,
isUninitialized: ruleGroupUninitialized,
},
] = alertRuleApi.endpoints.getRuleGroupForNamespace.useLazyQuery();
useEffect(() => {
@ -158,9 +165,10 @@ export function useCombinedRule({ ruleIdentifier, limitAlerts }: Props): Request
}, [ruleIdentifier, ruleSourceName, promRuleNs, rulerRuleGroup, ruleSource, ruleLocation, namespaceName]);
return {
loading: isLoadingDsFeatures || isLoadingPromRules || isLoadingRulerGroup,
loading: isLoadingDsFeatures || isLoadingPromRules || isLoadingRulerGroup || ruleGroupUninitialized,
error: ruleLocationError ?? promRuleNsError ?? rulerRuleGroupError,
result: rule,
uninitialized,
};
}
@ -187,17 +195,19 @@ export function useRuleLocation(ruleIdentifier: RuleIdentifier): RequestState<Ru
ruleName: ruleIdentifier.ruleName,
},
loading: false,
uninitialized: isUninitialized,
};
}
if (isGrafanaRuleIdentifier(ruleIdentifier)) {
if (isLoading || isUninitialized) {
return { loading: true };
if (isLoading) {
return { loading: isLoading, uninitialized: isUninitialized };
}
if (error) {
return { loading: false, error };
return { loading: false, error, uninitialized: isUninitialized };
}
if (currentData) {
return {
result: {
@ -207,6 +217,7 @@ export function useRuleLocation(ruleIdentifier: RuleIdentifier): RequestState<Ru
ruleName: currentData.grafana_alert.title,
},
loading: false,
uninitialized: isUninitialized,
};
}
@ -214,14 +225,16 @@ export function useRuleLocation(ruleIdentifier: RuleIdentifier): RequestState<Ru
return {
loading: false,
error: new Error(`Unable to obtain rule location for rule ${ruleIdentifier.uid}`),
uninitialized: isUninitialized,
};
}
return {
loading: false,
uninitialized: isUninitialized,
error: new Error('Unsupported rule identifier'),
};
}, [ruleIdentifier, isLoading, isUninitialized, error, currentData]);
}, [ruleIdentifier, isUninitialized, isLoading, error, currentData]);
}
function getRulesSourceFromIdentifier(ruleIdentifier: RuleIdentifier): RulesSource | undefined {
@ -249,16 +262,12 @@ export function useRuleWithLocation({
loading: isLoadingRuleLocation,
error: ruleLocationError,
result: ruleLocation,
uninitialized,
} = useRuleLocation(ruleIdentifier);
const [
fetchRulerRuleGroup,
{
currentData: rulerRuleGroup,
isLoading: isLoadingRulerGroup,
isUninitialized: isUninitializedRulerGroup,
error: rulerRuleGroupError,
},
{ currentData: rulerRuleGroup, isLoading: isLoadingRulerGroup, error: rulerRuleGroupError },
] = alertRuleApi.endpoints.getRuleGroupForNamespace.useLazyQuery();
useEffect(() => {
@ -297,9 +306,10 @@ export function useRuleWithLocation({
}, [ruleIdentifier, rulerRuleGroup, ruleSource, ruleLocation]);
return {
loading: isLoadingRuleLocation || isLoadingDsFeatures || isLoadingRulerGroup || isUninitializedRulerGroup,
loading: isLoadingRuleLocation || isLoadingDsFeatures || isLoadingRulerGroup,
error: ruleLocationError ?? rulerRuleGroupError,
result: ruleWithLocation,
uninitialized,
};
}

View File

@ -16,19 +16,22 @@ interface ResultBag {
}
export function useIsRuleEditable(rulesSourceName: string, rule?: RulerRuleDTO): ResultBag {
const { currentData: dsFeatures, isLoading } = featureDiscoveryApi.endpoints.discoverDsFeatures.useQuery({
uid: getDatasourceAPIUid(rulesSourceName),
});
const { currentData: dsFeatures, isLoading: loadingDataSourceFeatures } =
featureDiscoveryApi.endpoints.discoverDsFeatures.useQuery({
uid: getDatasourceAPIUid(rulesSourceName),
});
const folderUID = rule && isGrafanaRulerRule(rule) ? rule.grafana_alert.namespace_uid : undefined;
const rulePermission = getRulesPermissions(rulesSourceName);
const { folder, loading } = useFolder(folderUID);
const { folder, loading: loadingFolder } = useFolder(folderUID);
if (!rule) {
return { isEditable: false, isRemovable: false, loading: false };
}
const loading = loadingFolder || loadingDataSourceFeatures;
// Grafana rules can be edited if user can edit the folder they're in
// When RBAC is disabled access to a folder is the only requirement for managing rules
// When RBAC is enabled the appropriate alerting permissions need to be met
@ -39,13 +42,23 @@ export function useIsRuleEditable(rulesSourceName: string, rule?: RulerRuleDTO):
);
}
if (!folder) {
// Loading or invalid folder UID
// loading folder information
if (loadingFolder) {
return {
isRulerAvailable: true,
isEditable: false,
isRemovable: false,
loading,
loading: true,
};
}
// invalid folder UID
if (!folder) {
return {
isRulerAvailable: true,
isEditable: false,
isRemovable: false,
loading: false,
};
}
@ -56,7 +69,7 @@ export function useIsRuleEditable(rulesSourceName: string, rule?: RulerRuleDTO):
isRulerAvailable: true,
isEditable: canEditGrafanaRules,
isRemovable: canRemoveGrafanaRules,
loading: loading || isLoading,
loading: loading,
};
}
@ -69,6 +82,6 @@ export function useIsRuleEditable(rulesSourceName: string, rule?: RulerRuleDTO):
isRulerAvailable,
isEditable: canEditCloudRules && isRulerAvailable,
isRemovable: canRemoveCloudRules && isRulerAvailable,
loading: isLoading,
loading: loading,
};
}

View File

@ -1,4 +1,5 @@
import { Alert, LoadingPlaceholder } from '@grafana/ui';
import { EntityNotFound } from 'app/core/components/PageNotFound/EntityNotFound';
import { RuleIdentifier } from 'app/types/unified-alerting';
import { AlertWarning } from '../AlertWarning';
@ -13,17 +14,21 @@ interface ExistingRuleEditorProps {
}
export function ExistingRuleEditor({ identifier }: ExistingRuleEditorProps) {
const ruleSourceName = ruleId.ruleIdentifierToRuleSourceName(identifier);
const {
loading: loadingAlertRule,
result: ruleWithLocation,
error,
uninitialized,
} = useRuleWithLocation({ ruleIdentifier: identifier });
const ruleSourceName = ruleId.ruleIdentifierToRuleSourceName(identifier);
const { isEditable, loading: loadingEditable } = useIsRuleEditable(ruleSourceName, ruleWithLocation?.rule);
const loading = loadingAlertRule || loadingEditable;
// the loading of the editable state only happens once we've got a rule with location loaded, so we set it to true by default here
const loadingEditableState = Boolean(ruleWithLocation) ? loadingEditable : true;
const loading = loadingAlertRule || loadingEditableState || uninitialized;
const ruleNotFound = !Boolean(ruleWithLocation);
if (loading) {
return <LoadingPlaceholder text="Loading rule..." />;
@ -37,11 +42,11 @@ export function ExistingRuleEditor({ identifier }: ExistingRuleEditorProps) {
);
}
if (!ruleWithLocation) {
return <AlertWarning title="Rule not found">Sorry! This rule does not exist.</AlertWarning>;
if (ruleNotFound) {
return <EntityNotFound entity="Rule" />;
}
if (isEditable === false) {
if (isEditable === false && !loadingEditable) {
return <AlertWarning title="Cannot edit rule">Sorry! You do not have permission to edit this rule.</AlertWarning>;
}