Alerting: Show disabled provisioned evaluation group (#69932)

This commit is contained in:
Gilles De Mey 2023-06-13 11:26:01 +02:00 committed by GitHub
parent fa70fba0e3
commit a00d7770bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 40 additions and 17 deletions

View File

@ -13,5 +13,6 @@ export interface SelectableValue<T = any> {
title?: string;
// Optional component that will be shown together with other options. Does not get past any props.
component?: React.ComponentType<any>;
isDisabled?: boolean;
[key: string]: any;
}

View File

@ -357,7 +357,7 @@ export function SelectBase<T>({
return <DropdownIndicator isOpen={props.selectProps.menuIsOpen} />;
},
SingleValue(props: any) {
return <SingleValue {...props} disabled={disabled} />;
return <SingleValue {...props} isDisabled={disabled} />;
},
SelectContainer,
MultiValueContainer: MultiValueContainer,

View File

@ -90,7 +90,7 @@ export interface SelectCommonProps<T> {
virtualized?: boolean;
/** Sets the width to a multiple of 8px. Should only be used with inline forms. Setting width of the container is preferred in other cases.*/
width?: number | 'auto';
isOptionDisabled?: () => boolean;
isOptionDisabled?: (option: SelectableValue<T>) => boolean;
/** allowCustomValue must be enabled. Determines whether the "create new" option should be displayed based on the current input value, select value and options array. */
isValidNewOption?: (
inputValue: string,

View File

@ -5,9 +5,10 @@ import { useFormContext } from 'react-hook-form';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import { Stack } from '@grafana/experimental';
import { AsyncSelect, Field, InputControl, Label, LoadingPlaceholder, useStyles2 } from '@grafana/ui';
import { AsyncSelect, Badge, Field, InputControl, Label, LoadingPlaceholder, useStyles2 } from '@grafana/ui';
import { contextSrv } from 'app/core/core';
import { AccessControlAction, useDispatch } from 'app/types';
import { CombinedRuleGroup } from 'app/types/unified-alerting';
import { useCombinedRuleNamespaces } from '../../hooks/useCombinedRuleNamespaces';
import { useUnifiedAlertingSelector } from '../../hooks/useUnifiedAlertingSelector';
@ -34,21 +35,29 @@ export const useGetGroupOptionsFromFolder = (folderTitle: string) => {
const grafanaFolders = useCombinedRuleNamespaces(GRAFANA_RULES_SOURCE_NAME);
const folderGroups = grafanaFolders.find((f) => f.name === folderTitle)?.groups ?? [];
const nonProvisionedGroups = folderGroups.filter((g) => {
return g.rules.every(
(r) => isGrafanaRulerRule(r.rulerRule) && Boolean(r.rulerRule.grafana_alert.provenance) === false
);
});
const groupOptions = nonProvisionedGroups.map<SelectableValue<string>>((group) => ({
label: group.name,
value: group.name,
description: group.interval ?? MINUTE,
}));
const groupOptions = folderGroups
.map<SelectableValue<string>>((group) => ({
label: group.name,
value: group.name,
description: group.interval ?? MINUTE,
// we include provisioned folders, but disable the option to select them
isDisabled: isProvisionedGroup(group),
}))
.sort(sortByLabel);
return { groupOptions, loading: groupfoldersForGrafana?.loading };
};
const isProvisionedGroup = (group: CombinedRuleGroup) => {
return group.rules.some(
(rule) => isGrafanaRulerRule(rule.rulerRule) && Boolean(rule.rulerRule.grafana_alert.provenance) === true
);
};
const sortByLabel = (a: SelectableValue<string>, b: SelectableValue<string>) => {
return a.label?.localeCompare(b.label ?? '') || 0;
};
export function FolderAndGroup({ initialFolder }: FolderAndGroupProps) {
const {
formState: { errors },
@ -97,6 +106,7 @@ export function FolderAndGroup({ initialFolder }: FolderAndGroupProps) {
})
)
: sliceResults(groupOptions);
return results;
},
[groupOptions]
@ -160,7 +170,7 @@ export function FolderAndGroup({ initialFolder }: FolderAndGroupProps) {
invalid={!!errors.group?.message}
>
<InputControl
render={({ field: { ref, ...field } }) =>
render={({ field: { ref, ...field }, fieldState }) =>
loading ? (
<LoadingPlaceholder text="Loading..." />
) : (
@ -169,12 +179,23 @@ export function FolderAndGroup({ initialFolder }: FolderAndGroupProps) {
inputId="group"
key={`my_unique_select_key__${selectedGroup?.title ?? ''}`}
{...field}
invalid={Boolean(folder) && !selectedGroup.title}
invalid={Boolean(folder) && !selectedGroup.title && Boolean(fieldState.error)}
loadOptions={debouncedSearch}
loadingMessage={'Loading groups...'}
defaultOptions={groupOptions}
defaultValue={selectedGroup}
getOptionLabel={(option: SelectableValue<string>) => `${option.label}`}
getOptionLabel={(option: SelectableValue<string>) => (
<div>
<span>{option.label}</span>
{/* making the assumption here that it's provisioned when it's disabled, should probably change this */}
{option.isDisabled && (
<>
{' '}
<Badge color="purple" text="Provisioned" />
</>
)}
</div>
)}
placeholder={'Evaluation group name'}
onChange={(value) => {
field.onChange(value.label ?? '');
@ -209,6 +230,7 @@ const getStyles = (theme: GrafanaTheme2) => ({
`,
formInput: css`
width: 275px;
& + & {
margin-left: ${theme.spacing(3)};
}