WIP: create modal
This commit is contained in:
@@ -38,13 +38,14 @@ import { withPageErrorBoundary } from './withPageErrorBoundary';
|
|||||||
import { AlertmanagerGroup, Receiver, Route, ROUTES_META_SYMBOL } from '../../../plugins/datasource/alertmanager/types';
|
import { AlertmanagerGroup, Receiver, Route, ROUTES_META_SYMBOL } from '../../../plugins/datasource/alertmanager/types';
|
||||||
import { stringifyErrorLike } from './utils/misc';
|
import { stringifyErrorLike } from './utils/misc';
|
||||||
import {
|
import {
|
||||||
|
useCreateRoutingTree,
|
||||||
useDeleteRoutingTree,
|
useDeleteRoutingTree,
|
||||||
useListNotificationPolicyRoutes,
|
useListNotificationPolicyRoutes,
|
||||||
useRootRouteSearch,
|
useRootRouteSearch,
|
||||||
} from './components/notification-policies/useNotificationPolicyRoute';
|
} from './components/notification-policies/useNotificationPolicyRoute';
|
||||||
import { useURLSearchParams } from './hooks/useURLSearchParams';
|
import { useURLSearchParams } from './hooks/useURLSearchParams';
|
||||||
import { usePagination } from './hooks/usePagination';
|
import { usePagination } from './hooks/usePagination';
|
||||||
import { useDeleteRoutingTreeModal } from './components/notification-policies/components/Modals';
|
import { useCreateRoutingTreeModal, useDeleteRoutingTreeModal } from './components/notification-policies/components/Modals';
|
||||||
import { ALL_ROUTING_TREES, useExportRoutingTree } from './components/notification-policies/useExportRoutingTree';
|
import { ALL_ROUTING_TREES, useExportRoutingTree } from './components/notification-policies/useExportRoutingTree';
|
||||||
import { K8sAnnotations, ROOT_ROUTE_NAME } from './utils/k8s/constants';
|
import { K8sAnnotations, ROOT_ROUTE_NAME } from './utils/k8s/constants';
|
||||||
import ConditionalWrap from './components/ConditionalWrap';
|
import ConditionalWrap from './components/ConditionalWrap';
|
||||||
@@ -52,10 +53,11 @@ import { ProvisioningBadge } from './components/Provisioning';
|
|||||||
import { getAnnotation } from './utils/k8s/utils';
|
import { getAnnotation } from './utils/k8s/utils';
|
||||||
import { Spacer } from './components/Spacer';
|
import { Spacer } from './components/Spacer';
|
||||||
import MoreButton from './components/MoreButton';
|
import MoreButton from './components/MoreButton';
|
||||||
import { useContactPointsWithStatus } from './components/contact-points/useContactPoints';
|
import { useGrafanaContactPoints } from './components/contact-points/useContactPoints';
|
||||||
import { useAlertGroupsModal } from './components/notification-policies/Modals';
|
import { useAlertGroupsModal } from './components/notification-policies/Modals';
|
||||||
import { normalizeMatchers } from './utils/matchers';
|
import { normalizeMatchers } from './utils/matchers';
|
||||||
import { RoutingTreeFilter } from './components/notification-policies/components/RoutingTreeFilter';
|
import { RoutingTreeFilter } from './components/notification-policies/components/RoutingTreeFilter';
|
||||||
|
import {config} from '@grafana/runtime';
|
||||||
|
|
||||||
enum ActiveTab {
|
enum ActiveTab {
|
||||||
NotificationPolicies = 'notification_policies',
|
NotificationPolicies = 'notification_policies',
|
||||||
@@ -126,7 +128,9 @@ const NotificationPoliciesTabs = () => {
|
|||||||
const PolicyTreeTab = () => {
|
const PolicyTreeTab = () => {
|
||||||
const { isGrafanaAlertmanager } = useAlertmanager();
|
const { isGrafanaAlertmanager } = useAlertmanager();
|
||||||
|
|
||||||
if (!isGrafanaAlertmanager) {
|
const useMultiplePoliciesView = config.featureToggles.alertingMultiplePolicies;
|
||||||
|
|
||||||
|
if (!isGrafanaAlertmanager || !useMultiplePoliciesView) {
|
||||||
return <NotificationPoliciesTree />;
|
return <NotificationPoliciesTree />;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,7 +142,6 @@ const PolicyTreeTab = () => {
|
|||||||
const DEFAULT_PAGE_SIZE = 10;
|
const DEFAULT_PAGE_SIZE = 10;
|
||||||
|
|
||||||
const PolicyTreeTabContents = () => {
|
const PolicyTreeTabContents = () => {
|
||||||
const { selectedAlertmanager } = useAlertmanager();
|
|
||||||
const [queryParams] = useURLSearchParams();
|
const [queryParams] = useURLSearchParams();
|
||||||
|
|
||||||
const [[createPoliciesSupported, createPoliciesAllowed], [exportPoliciesSupported, exportPoliciesAllowed]] =
|
const [[createPoliciesSupported, createPoliciesAllowed], [exportPoliciesSupported, exportPoliciesAllowed]] =
|
||||||
@@ -151,18 +154,21 @@ const PolicyTreeTabContents = () => {
|
|||||||
currentData: allPolicies,
|
currentData: allPolicies,
|
||||||
isLoading,
|
isLoading,
|
||||||
error: fetchPoliciesError,
|
error: fetchPoliciesError,
|
||||||
} = useListNotificationPolicyRoutes({ alertmanager: selectedAlertmanager ?? '' });
|
} = useListNotificationPolicyRoutes();
|
||||||
|
|
||||||
const [ExportDrawer, showExportDrawer] = useExportRoutingTree();
|
const [ExportDrawer, showExportDrawer] = useExportRoutingTree();
|
||||||
|
|
||||||
|
const [createTrigger] = useCreateRoutingTree();
|
||||||
|
const [CreateModal, showCreateModal] = useCreateRoutingTreeModal(createTrigger.execute);
|
||||||
|
|
||||||
const search = queryParams.get('search');
|
const search = queryParams.get('search');
|
||||||
|
|
||||||
const [contactPointsSupported, canSeeContactPoints] = useAlertmanagerAbility(AlertmanagerAction.ViewContactPoint);
|
const [contactPointsSupported, canSeeContactPoints] = useAlertmanagerAbility(AlertmanagerAction.ViewContactPoint);
|
||||||
const shouldFetchContactPoints = contactPointsSupported && canSeeContactPoints;
|
const shouldFetchContactPoints = contactPointsSupported && canSeeContactPoints;
|
||||||
const { contactPoints: receivers } = useContactPointsWithStatus({
|
const { contactPoints: receivers } = useGrafanaContactPoints({
|
||||||
alertmanager: selectedAlertmanager ?? '',
|
|
||||||
fetchPolicies: false,
|
|
||||||
fetchStatuses: true,
|
|
||||||
skip: !shouldFetchContactPoints,
|
skip: !shouldFetchContactPoints,
|
||||||
|
fetchStatuses: false,
|
||||||
|
fetchPolicies: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
@@ -177,15 +183,15 @@ const PolicyTreeTabContents = () => {
|
|||||||
|
|
||||||
<Stack direction="row" gap={1}>
|
<Stack direction="row" gap={1}>
|
||||||
{createPoliciesSupported && (
|
{createPoliciesSupported && (
|
||||||
<LinkButton
|
<Button
|
||||||
icon="plus"
|
icon="plus"
|
||||||
aria-label={'add policy'}
|
aria-label={'add policy'}
|
||||||
variant="primary"
|
variant="primary"
|
||||||
href="/alerting/routes/new"
|
|
||||||
disabled={!createPoliciesAllowed}
|
disabled={!createPoliciesAllowed}
|
||||||
|
onClick={() => showCreateModal()}
|
||||||
>
|
>
|
||||||
Create policy
|
Create policy
|
||||||
</LinkButton>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{exportPoliciesSupported && (
|
{exportPoliciesSupported && (
|
||||||
<Button
|
<Button
|
||||||
@@ -210,6 +216,7 @@ const PolicyTreeTabContents = () => {
|
|||||||
receivers={receivers}
|
receivers={receivers}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{CreateModal}
|
||||||
{ExportDrawer}
|
{ExportDrawer}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
@@ -218,7 +225,7 @@ const PolicyTreeTabContents = () => {
|
|||||||
interface RoutingTreeListProps {
|
interface RoutingTreeListProps {
|
||||||
policies: Route[];
|
policies: Route[];
|
||||||
search?: string | null;
|
search?: string | null;
|
||||||
pageSize?: number;
|
pageSize: number;
|
||||||
receivers?: Receiver[];
|
receivers?: Receiver[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+27
-2
@@ -3,7 +3,7 @@ import { Controller, useForm } from 'react-hook-form';
|
|||||||
|
|
||||||
import { ContactPointSelector as GrafanaManagedContactPointSelector } from '@grafana/alerting/unstable';
|
import { ContactPointSelector as GrafanaManagedContactPointSelector } from '@grafana/alerting/unstable';
|
||||||
import { Trans, t } from '@grafana/i18n';
|
import { Trans, t } from '@grafana/i18n';
|
||||||
import { Collapse, Field, Link, MultiSelect, useStyles2 } from '@grafana/ui';
|
import { Collapse, Field, Input, Link, MultiSelect, useStyles2 } from '@grafana/ui';
|
||||||
import { ExternalAlertmanagerContactPointSelector } from 'app/features/alerting/unified/components/notification-policies/ContactPointSelector';
|
import { ExternalAlertmanagerContactPointSelector } from 'app/features/alerting/unified/components/notification-policies/ContactPointSelector';
|
||||||
import { handleContactPointSelect } from 'app/features/alerting/unified/components/notification-policies/utils';
|
import { handleContactPointSelect } from 'app/features/alerting/unified/components/notification-policies/utils';
|
||||||
import { RouteWithID } from 'app/plugins/datasource/alertmanager/types';
|
import { RouteWithID } from 'app/plugins/datasource/alertmanager/types';
|
||||||
@@ -30,9 +30,10 @@ export interface AmRootRouteFormProps {
|
|||||||
actionButtons: ReactNode;
|
actionButtons: ReactNode;
|
||||||
onSubmit: (route: Partial<FormAmRoute>) => void;
|
onSubmit: (route: Partial<FormAmRoute>) => void;
|
||||||
route: RouteWithID;
|
route: RouteWithID;
|
||||||
|
showNameField?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AmRootRouteForm = ({ actionButtons, alertManagerSourceName, onSubmit, route }: AmRootRouteFormProps) => {
|
export const AmRootRouteForm = ({ actionButtons, alertManagerSourceName, onSubmit, route, showNameField }: AmRootRouteFormProps) => {
|
||||||
const styles = useStyles2(getFormStyles);
|
const styles = useStyles2(getFormStyles);
|
||||||
const [isTimingOptionsExpanded, setIsTimingOptionsExpanded] = useState(false);
|
const [isTimingOptionsExpanded, setIsTimingOptionsExpanded] = useState(false);
|
||||||
const { isGrafanaAlertmanager } = useAlertmanager();
|
const { isGrafanaAlertmanager } = useAlertmanager();
|
||||||
@@ -55,6 +56,30 @@ export const AmRootRouteForm = ({ actionButtons, alertManagerSourceName, onSubmi
|
|||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
{showNameField && (<Field
|
||||||
|
required
|
||||||
|
label={t('alerting.am-root-route-form.name', 'Name')}
|
||||||
|
description={t(
|
||||||
|
'alerting.am-root-route-form.description-unique-route',
|
||||||
|
'A unique name for the routing tree'
|
||||||
|
)}
|
||||||
|
invalid={!!errors.name}
|
||||||
|
error={errors.name?.message}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
{...register('name', {
|
||||||
|
required: true,
|
||||||
|
validate: (value) => {
|
||||||
|
if (!value || value.trim().length === 0) {
|
||||||
|
return 'Name is required';
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
className={styles.input}
|
||||||
|
data-testid="routing-tree-name"
|
||||||
|
/>
|
||||||
|
</Field>)}
|
||||||
<Field
|
<Field
|
||||||
label={t('alerting.am-root-route-form.label-default-contact-point', 'Default contact point')}
|
label={t('alerting.am-root-route-form.label-default-contact-point', 'Default contact point')}
|
||||||
invalid={Boolean(errors.receiver) ? true : undefined}
|
invalid={Boolean(errors.receiver) ? true : undefined}
|
||||||
|
|||||||
@@ -298,10 +298,10 @@ const useAlertGroupsModal = (
|
|||||||
return [modalElement, handleShow, handleDismiss];
|
return [modalElement, handleShow, handleDismiss];
|
||||||
};
|
};
|
||||||
|
|
||||||
const UpdatingModal: FC<Pick<ModalProps, 'isOpen'>> = ({ isOpen }) => (
|
export const UpdatingModal: FC<Pick<ModalProps, 'isOpen' | 'onDismiss'>> = ({ isOpen, onDismiss = () => {}} ) => (
|
||||||
<Modal
|
<Modal
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
onDismiss={() => {}}
|
onDismiss={onDismiss}
|
||||||
closeOnBackdropClick={false}
|
closeOnBackdropClick={false}
|
||||||
closeOnEscape={false}
|
closeOnEscape={false}
|
||||||
ariaLabel={t('alerting.policies.update.updating', 'Updating...')}
|
ariaLabel={t('alerting.policies.update.updating', 'Updating...')}
|
||||||
|
|||||||
@@ -694,9 +694,9 @@ const AllMatchesIndicator: FC = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
type DefaultPolicyIndicatorProps = { route: RouteWithID };
|
type DefaultPolicyIndicatorProps = { route?: RouteWithID };
|
||||||
|
|
||||||
const DefaultPolicyIndicator: FC<DefaultPolicyIndicatorProps> = ({route}) => {
|
export const DefaultPolicyIndicator: FC<DefaultPolicyIndicatorProps> = ({route={}}) => {
|
||||||
const styles = useStyles2(getStyles);
|
const styles = useStyles2(getStyles);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
+97
-10
@@ -1,9 +1,16 @@
|
|||||||
import { useCallback, useMemo, useState } from 'react';
|
import { useCallback, useMemo, useState } from 'react';
|
||||||
|
|
||||||
import { Trans, t } from '@grafana/i18n';
|
import { Trans, t } from '@grafana/i18n';
|
||||||
import { Button, Modal, ModalProps } from '@grafana/ui';
|
import { Button, Modal, ModalProps, useStyles2 } from '@grafana/ui';
|
||||||
|
|
||||||
import { stringifyErrorLike } from '../../../utils/misc';
|
import { stringifyErrorLike } from '../../../utils/misc';
|
||||||
|
import { FormAmRoute } from '../../../types/amroutes';
|
||||||
|
import { AmRootRouteForm } from '../EditDefaultPolicyForm';
|
||||||
|
import { UpdatingModal } from '../Modals';
|
||||||
|
import { getFormStyles } from '../formStyles';
|
||||||
|
import { GRAFANA_RULES_SOURCE_NAME } from '../../../utils/datasource';
|
||||||
|
import { RouteWithID } from '../../../../../../plugins/datasource/alertmanager/types';
|
||||||
|
import { defaultGroupBy } from '../../../utils/amroutes';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This hook controls the delete modal for routing trees, showing loading and error states when appropriate
|
* This hook controls the delete modal for routing trees, showing loading and error states when appropriate
|
||||||
@@ -56,18 +63,12 @@ export const useDeleteRoutingTreeModal = (
|
|||||||
closeOnEscape={!isLoading}
|
closeOnEscape={!isLoading}
|
||||||
title={'Delete routing tree'}
|
title={'Delete routing tree'}
|
||||||
>
|
>
|
||||||
<p>
|
<p>Deleting this routing tree will permanently remove it.</p>
|
||||||
Deleting this routing tree will permanently remove it.
|
<p>Are you sure you want to delete this routing tree?</p>
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Are you sure you want to delete this routing tree?
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<Modal.ButtonRow>
|
<Modal.ButtonRow>
|
||||||
<Button type="button" variant="destructive" onClick={handleSubmit} disabled={isLoading}>
|
<Button type="button" variant="destructive" onClick={handleSubmit} disabled={isLoading}>
|
||||||
{isLoading
|
{isLoading ? 'Deleting...' : 'Yes, delete routing tree'}
|
||||||
? "Deleting..."
|
|
||||||
: "Yes, delete routing tree"}
|
|
||||||
</Button>
|
</Button>
|
||||||
<Button type="button" variant="secondary" onClick={handleDismiss} disabled={isLoading}>
|
<Button type="button" variant="secondary" onClick={handleDismiss} disabled={isLoading}>
|
||||||
<Trans i18nKey="alerting.common.cancel">Cancel</Trans>
|
<Trans i18nKey="alerting.common.cancel">Cancel</Trans>
|
||||||
@@ -80,6 +81,92 @@ export const useDeleteRoutingTreeModal = (
|
|||||||
return [modalElement, handleShow, handleDismiss] as const;
|
return [modalElement, handleShow, handleDismiss] as const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const emptyRouteWithID = {
|
||||||
|
id: '',
|
||||||
|
name: '',
|
||||||
|
group_by: defaultGroupBy,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This hook controls the create modal for routing trees, showing loading and error states when appropriate
|
||||||
|
*/
|
||||||
|
export const useCreateRoutingTreeModal = (handleCreate: (route: Partial<FormAmRoute>) => Promise<unknown>) => {
|
||||||
|
const styles = useStyles2(getFormStyles);
|
||||||
|
const [showModal, setShowModal] = useState(false);
|
||||||
|
const [route, setRoute] = useState<RouteWithID>(emptyRouteWithID);
|
||||||
|
const [error, setError] = useState<unknown | undefined>();
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
|
const handleDismiss = useCallback(() => {
|
||||||
|
if (isLoading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setShowModal(false);
|
||||||
|
setError(undefined);
|
||||||
|
setRoute(emptyRouteWithID);
|
||||||
|
}, [isLoading]);
|
||||||
|
|
||||||
|
const handleShow = useCallback(() => {
|
||||||
|
setShowModal(true);
|
||||||
|
setError(undefined);
|
||||||
|
setRoute(emptyRouteWithID);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleSubmit = useCallback(
|
||||||
|
(newRoute: Partial<FormAmRoute>) => {
|
||||||
|
if (newRoute) {
|
||||||
|
setIsLoading(true);
|
||||||
|
handleCreate(newRoute)
|
||||||
|
.then(() => setShowModal(false))
|
||||||
|
.catch(setError)
|
||||||
|
.finally(() => {
|
||||||
|
setIsLoading(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[handleCreate]
|
||||||
|
);
|
||||||
|
|
||||||
|
const modalElement = useMemo(() => {
|
||||||
|
if (error) {
|
||||||
|
return <ErrorModal isOpen={showModal} onDismiss={handleDismiss} error={error} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return <UpdatingModal isOpen={showModal} onDismiss={handleDismiss} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
isOpen={showModal}
|
||||||
|
onDismiss={handleDismiss}
|
||||||
|
closeOnBackdropClick={true}
|
||||||
|
closeOnEscape={true}
|
||||||
|
title={'Create routing tree'}
|
||||||
|
>
|
||||||
|
<AmRootRouteForm
|
||||||
|
route={route}
|
||||||
|
showNameField={true}
|
||||||
|
onSubmit={handleSubmit}
|
||||||
|
alertManagerSourceName={GRAFANA_RULES_SOURCE_NAME}
|
||||||
|
actionButtons={
|
||||||
|
<Modal.ButtonRow>
|
||||||
|
<Button type="button" variant="secondary" onClick={handleDismiss} fill="outline">
|
||||||
|
<Trans i18nKey="alerting.common.cancel">Cancel</Trans>
|
||||||
|
</Button>
|
||||||
|
<Button type="submit">
|
||||||
|
<Trans i18nKey="alerting.policies.save-policy">Add routing tree</Trans>
|
||||||
|
</Button>
|
||||||
|
</Modal.ButtonRow>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}, [route, error, handleSubmit, handleDismiss, isLoading, showModal, styles.input]);
|
||||||
|
|
||||||
|
return [modalElement, handleShow, handleDismiss] as const;
|
||||||
|
};
|
||||||
|
|
||||||
interface ErrorModalProps extends Pick<ModalProps, 'isOpen' | 'onDismiss'> {
|
interface ErrorModalProps extends Pick<ModalProps, 'isOpen' | 'onDismiss'> {
|
||||||
error: unknown;
|
error: unknown;
|
||||||
}
|
}
|
||||||
|
|||||||
+45
-4
@@ -35,6 +35,7 @@ import uFuzzy from '@leeoniya/ufuzzy';
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
useCreateNamespacedRoutingTreeMutation,
|
||||||
useDeleteNamespacedRoutingTreeMutation,
|
useDeleteNamespacedRoutingTreeMutation,
|
||||||
useListNamespacedRoutingTreeQuery,
|
useListNamespacedRoutingTreeQuery,
|
||||||
useReplaceNamespacedRoutingTreeMutation,
|
useReplaceNamespacedRoutingTreeMutation,
|
||||||
@@ -83,13 +84,11 @@ export const useNotificationPolicyRoute = (
|
|||||||
return k8sApiSupported ? k8sRouteQuery : amConfigQuery;
|
return k8sApiSupported ? k8sRouteQuery : amConfigQuery;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useListNotificationPolicyRoutes = ({ alertmanager }: BaseAlertmanagerArgs, { skip }: Skippable = {}) => {
|
export const useListNotificationPolicyRoutes = ({ skip }: Skippable = {}) => {
|
||||||
const k8sApiSupported = shouldUseK8sApi(alertmanager);
|
|
||||||
|
|
||||||
return useListNamespacedRoutingTreeQuery(
|
return useListNamespacedRoutingTreeQuery(
|
||||||
{ namespace: getAPINamespace() },
|
{ namespace: getAPINamespace() },
|
||||||
{
|
{
|
||||||
skip: skip || !k8sApiSupported,
|
skip: skip,
|
||||||
selectFromResult: (result) => {
|
selectFromResult: (result) => {
|
||||||
return {
|
return {
|
||||||
...result,
|
...result,
|
||||||
@@ -267,6 +266,48 @@ export function useDeleteRoutingTree() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useCreateRoutingTree() {
|
||||||
|
const [createNamespacedRoutingTree] = useCreateNamespacedRoutingTreeMutation();
|
||||||
|
|
||||||
|
return useAsync(async (partialFormRoute: Partial<FormAmRoute>) => {
|
||||||
|
const namespace = getAPINamespace();
|
||||||
|
|
||||||
|
const {
|
||||||
|
name,
|
||||||
|
overrideGrouping,
|
||||||
|
groupBy,
|
||||||
|
overrideTimings,
|
||||||
|
groupWaitValue,
|
||||||
|
groupIntervalValue,
|
||||||
|
repeatIntervalValue,
|
||||||
|
receiver,
|
||||||
|
} = partialFormRoute;
|
||||||
|
|
||||||
|
// This does not "inherit" from any existing route, as this is a new routing tree. If not set, it will use the system
|
||||||
|
// defaults. Currently supported by group_by, group_wait, group_interval, and repeat_interval
|
||||||
|
const USE_DEFAULTS = undefined;
|
||||||
|
|
||||||
|
const newRoute: Route = {
|
||||||
|
name: name,
|
||||||
|
group_by: overrideGrouping ? groupBy : USE_DEFAULTS,
|
||||||
|
group_wait: overrideTimings && groupWaitValue ? groupWaitValue : USE_DEFAULTS,
|
||||||
|
group_interval: overrideTimings && groupIntervalValue ? groupIntervalValue : USE_DEFAULTS,
|
||||||
|
repeat_interval: overrideTimings && repeatIntervalValue ? repeatIntervalValue : USE_DEFAULTS,
|
||||||
|
receiver: receiver,
|
||||||
|
};
|
||||||
|
|
||||||
|
// defaults(newRoute, TIMING_OPTIONS_DEFAULTS)
|
||||||
|
|
||||||
|
// Create the K8s route object
|
||||||
|
const routeObject = createKubernetesRoutingTreeSpec(newRoute);
|
||||||
|
|
||||||
|
return createNamespacedRoutingTree({
|
||||||
|
namespace,
|
||||||
|
comGithubGrafanaGrafanaPkgApisAlertingNotificationsV0Alpha1RoutingTree: cleanKubernetesRouteIDs(routeObject),
|
||||||
|
}).unwrap();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const fuzzyFinder = new uFuzzy({
|
const fuzzyFinder = new uFuzzy({
|
||||||
intraMode: 1,
|
intraMode: 1,
|
||||||
intraIns: 1,
|
intraIns: 1,
|
||||||
|
|||||||
Reference in New Issue
Block a user