mirror of
https://github.com/grafana/grafana.git
synced 2025-12-20 19:44:55 +08:00
Compare commits
1 Commits
zoltan/pos
...
alerting/l
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a6a8f661d |
@@ -1,5 +1,5 @@
|
||||
import { css } from '@emotion/css';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { FormProvider, SubmitErrorHandler, UseFormWatch, useForm } from 'react-hook-form';
|
||||
import { useParams } from 'react-router-dom-v5-compat';
|
||||
|
||||
@@ -92,11 +92,12 @@ export const AlertRuleForm = ({ existing, prefill, isManualRestore }: Props) =>
|
||||
|
||||
const ruleType = translateRouteParamToRuleType(routeParams.type);
|
||||
|
||||
const defaultValues: RuleFormValues = useMemo(() => {
|
||||
const defaultValues = useCallback(async () => {
|
||||
// If we have an existing AND a prefill, then we're coming from the restore dialog
|
||||
// and we want to merge the two
|
||||
if (existing && prefill) {
|
||||
return { ...formValuesFromExistingRule(existing), ...formValuesFromPrefill(prefill) };
|
||||
const prefillValues = await formValuesFromPrefill(prefill);
|
||||
return { ...formValuesFromExistingRule(existing), ...prefillValues };
|
||||
}
|
||||
if (existing) {
|
||||
return formValuesFromExistingRule(existing);
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import { clamp } from 'lodash';
|
||||
import z from 'zod';
|
||||
|
||||
import { config, getDataSourceSrv } from '@grafana/runtime';
|
||||
import { alertingAlertRuleFormSchema } from 'app/features/plugins/components/restrictedGrafanaApis/alerting/alertRuleFormSchema';
|
||||
import { RuleWithLocation } from 'app/types/unified-alerting';
|
||||
import { GrafanaAlertStateDecision, RulerRuleDTO } from 'app/types/unified-alerting-dto';
|
||||
|
||||
@@ -157,90 +155,15 @@ export function formValuesFromQueryParams(ruleDefinition: string, type: RuleForm
|
||||
)
|
||||
);
|
||||
}
|
||||
// schema for cloud rule form values. This is necessary because the cloud rule form values are not the same as the grafana rule form values.
|
||||
// schema for grafana rule values is navigateToAlertFormSchema , shared in the restrictedGrafanaApis.
|
||||
// TODO: add this to the DMA new plugin.
|
||||
// ⚠️ Lazy-loaded function to avoid bundling zod in the main bundle
|
||||
// This function is async to allow dynamic imports of the zod schemas
|
||||
export async function formValuesFromPrefill(rule: Partial<RuleFormValues>): Promise<RuleFormValues> {
|
||||
const [{ cloudRuleFormValuesSchema }, { alertingAlertRuleFormSchema }] = await Promise.all([
|
||||
import('./formDefaultsSchemas'),
|
||||
import('app/features/plugins/components/restrictedGrafanaApis/alerting/alertRuleFormSchema'),
|
||||
]);
|
||||
|
||||
const cloudRuleFormValuesSchema = z.looseObject({
|
||||
name: z.string().optional(),
|
||||
type: z.enum(RuleFormType).catch(RuleFormType.grafana),
|
||||
dataSourceName: z.string().optional().default(''),
|
||||
group: z.string().optional(),
|
||||
labels: z
|
||||
.array(
|
||||
z.object({
|
||||
key: z.string(),
|
||||
value: z.string(),
|
||||
})
|
||||
)
|
||||
.optional()
|
||||
.default([]),
|
||||
annotations: z
|
||||
.array(
|
||||
z.object({
|
||||
key: z.string(),
|
||||
value: z.string(),
|
||||
})
|
||||
)
|
||||
.optional()
|
||||
.default([]),
|
||||
queries: z.array(z.any()).optional(),
|
||||
condition: z.string().optional(),
|
||||
noDataState: z
|
||||
.enum(GrafanaAlertStateDecision)
|
||||
.optional()
|
||||
.default(GrafanaAlertStateDecision.NoData)
|
||||
.catch(GrafanaAlertStateDecision.NoData),
|
||||
execErrState: z
|
||||
.enum(GrafanaAlertStateDecision)
|
||||
.optional()
|
||||
.default(GrafanaAlertStateDecision.Error)
|
||||
.catch(GrafanaAlertStateDecision.Error),
|
||||
folder: z
|
||||
.union([
|
||||
z.object({
|
||||
title: z.string(),
|
||||
uid: z.string(),
|
||||
}),
|
||||
z.undefined(),
|
||||
])
|
||||
.optional(),
|
||||
evaluateEvery: z.string().optional(),
|
||||
evaluateFor: z.string().optional().default('0s'),
|
||||
keepFiringFor: z.string().optional(),
|
||||
isPaused: z.boolean().optional().default(false),
|
||||
manualRouting: z.boolean().optional(),
|
||||
contactPoints: z
|
||||
.record(
|
||||
z.string(),
|
||||
z.object({
|
||||
selectedContactPoint: z.string(),
|
||||
overrideGrouping: z.boolean(),
|
||||
groupBy: z.array(z.string()),
|
||||
overrideTimings: z.boolean(),
|
||||
groupWaitValue: z.string(),
|
||||
groupIntervalValue: z.string(),
|
||||
repeatIntervalValue: z.string(),
|
||||
muteTimeIntervals: z.array(z.string()),
|
||||
activeTimeIntervals: z.array(z.string()),
|
||||
})
|
||||
)
|
||||
.optional(),
|
||||
editorSettings: z
|
||||
.object({
|
||||
simplifiedQueryEditor: z.boolean(),
|
||||
simplifiedNotificationEditor: z.boolean(),
|
||||
})
|
||||
.optional(),
|
||||
metric: z.string().optional(),
|
||||
targetDatasourceUid: z.string().optional(),
|
||||
namespace: z.string().optional(),
|
||||
expression: z.string().optional(),
|
||||
missingSeriesEvalsToResolve: z.number().optional(),
|
||||
});
|
||||
|
||||
export function formValuesFromPrefill(rule: Partial<RuleFormValues>): RuleFormValues {
|
||||
let parsedRule: z.infer<typeof alertingAlertRuleFormSchema> | z.infer<typeof cloudRuleFormValuesSchema>;
|
||||
let parsedRule: Partial<RuleFormValues>;
|
||||
// differencitate between cloud and grafana prefill
|
||||
if (rule.type === RuleFormType.cloudAlerting) {
|
||||
// we use this schema to coerce prefilled query params into a valid "FormValues" interface
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
import z from 'zod';
|
||||
|
||||
import { GrafanaAlertStateDecision } from 'app/types/unified-alerting-dto';
|
||||
|
||||
import { RuleFormType } from '../types/rule-form';
|
||||
|
||||
// Schema for cloud rule form values. This is necessary because the cloud rule form values are not the same as the grafana rule form values.
|
||||
// schema for grafana rule values is navigateToAlertFormSchema , shared in the restrictedGrafanaApis.
|
||||
// TODO: add this to the DMA new plugin.
|
||||
|
||||
export const cloudRuleFormValuesSchema = z.looseObject({
|
||||
name: z.string().optional(),
|
||||
type: z.enum(RuleFormType).catch(RuleFormType.grafana),
|
||||
dataSourceName: z.string().optional().default(''),
|
||||
group: z.string().optional(),
|
||||
labels: z
|
||||
.array(
|
||||
z.object({
|
||||
key: z.string(),
|
||||
value: z.string(),
|
||||
})
|
||||
)
|
||||
.optional()
|
||||
.default([]),
|
||||
annotations: z
|
||||
.array(
|
||||
z.object({
|
||||
key: z.string(),
|
||||
value: z.string(),
|
||||
})
|
||||
)
|
||||
.optional()
|
||||
.default([]),
|
||||
queries: z.array(z.any()).optional(),
|
||||
condition: z.string().optional(),
|
||||
noDataState: z
|
||||
.enum(GrafanaAlertStateDecision)
|
||||
.optional()
|
||||
.default(GrafanaAlertStateDecision.NoData)
|
||||
.catch(GrafanaAlertStateDecision.NoData),
|
||||
execErrState: z
|
||||
.enum(GrafanaAlertStateDecision)
|
||||
.optional()
|
||||
.default(GrafanaAlertStateDecision.Error)
|
||||
.catch(GrafanaAlertStateDecision.Error),
|
||||
folder: z
|
||||
.union([
|
||||
z.object({
|
||||
title: z.string(),
|
||||
uid: z.string(),
|
||||
}),
|
||||
z.undefined(),
|
||||
])
|
||||
.optional(),
|
||||
evaluateEvery: z.string().optional(),
|
||||
evaluateFor: z.string().optional().default('0s'),
|
||||
keepFiringFor: z.string().optional(),
|
||||
isPaused: z.boolean().optional().default(false),
|
||||
manualRouting: z.boolean().optional(),
|
||||
contactPoints: z
|
||||
.record(
|
||||
z.string(),
|
||||
z.object({
|
||||
selectedContactPoint: z.string(),
|
||||
overrideGrouping: z.boolean(),
|
||||
groupBy: z.array(z.string()),
|
||||
overrideTimings: z.boolean(),
|
||||
groupWaitValue: z.string(),
|
||||
groupIntervalValue: z.string(),
|
||||
repeatIntervalValue: z.string(),
|
||||
muteTimeIntervals: z.array(z.string()),
|
||||
activeTimeIntervals: z.array(z.string()),
|
||||
})
|
||||
)
|
||||
.optional(),
|
||||
editorSettings: z
|
||||
.object({
|
||||
simplifiedQueryEditor: z.boolean(),
|
||||
simplifiedNotificationEditor: z.boolean(),
|
||||
})
|
||||
.optional(),
|
||||
metric: z.string().optional(),
|
||||
targetDatasourceUid: z.string().optional(),
|
||||
namespace: z.string().optional(),
|
||||
expression: z.string().optional(),
|
||||
missingSeriesEvalsToResolve: z.number().optional(),
|
||||
});
|
||||
@@ -21,7 +21,6 @@ import { notifyApp } from 'app/core/reducers/appNotification';
|
||||
import { contextSrv } from 'app/core/services/context_srv';
|
||||
import { getMessageFromError } from 'app/core/utils/errors';
|
||||
import { getCreateAlertInMenuAvailability } from 'app/features/alerting/unified/utils/access-control';
|
||||
import { scenesPanelToRuleFormValues } from 'app/features/alerting/unified/utils/rule-form';
|
||||
import { getTrackingSource, shareDashboardType } from 'app/features/dashboard/components/ShareModal/utils';
|
||||
import { InspectTab } from 'app/features/inspector/types';
|
||||
import { getScenePanelLinksSupplier } from 'app/features/panel/panellinks/linkSuppliers';
|
||||
@@ -527,6 +526,8 @@ export function onRemovePanel(dashboard: DashboardScene, panel: VizPanel) {
|
||||
|
||||
const onCreateAlert = async (panel: VizPanel) => {
|
||||
try {
|
||||
// ⚠️ Dynamically importing this to prevent Zod from being bundled into the dashboard bundle
|
||||
const { scenesPanelToRuleFormValues } = await import('app/features/alerting/unified/utils/rule-form');
|
||||
const formValues = await scenesPanelToRuleFormValues(panel);
|
||||
const ruleFormUrl = urlUtil.renderUrl('/alerting/new', {
|
||||
defaults: JSON.stringify(formValues),
|
||||
|
||||
@@ -7,7 +7,6 @@ import { contextSrv } from 'app/core/services/context_srv';
|
||||
import { getMessageFromError } from 'app/core/utils/errors';
|
||||
import { getExploreUrl } from 'app/core/utils/explore';
|
||||
import { RuleFormValues } from 'app/features/alerting/unified/types/rule-form';
|
||||
import { panelToRuleFormValues } from 'app/features/alerting/unified/utils/rule-form';
|
||||
import { DashboardModel } from 'app/features/dashboard/state/DashboardModel';
|
||||
import { PanelModel } from 'app/features/dashboard/state/PanelModel';
|
||||
import {
|
||||
@@ -175,6 +174,8 @@ export function getPanelMenu(
|
||||
const createAlert = async () => {
|
||||
let formValues: Partial<RuleFormValues> | undefined;
|
||||
try {
|
||||
// ⚠️ Dynamically importing this to prevent Zod from being bundled into the dashboard bundle
|
||||
const { panelToRuleFormValues } = await import('app/features/alerting/unified/utils/rule-form');
|
||||
formValues = await panelToRuleFormValues(panel, dashboard);
|
||||
} catch (err) {
|
||||
const message = `Error getting rule values from the panel: ${getMessageFromError(err)}`;
|
||||
|
||||
@@ -1,16 +1,7 @@
|
||||
import { PropsWithChildren, ReactElement } from 'react';
|
||||
import { PropsWithChildren, ReactElement, useEffect, useState } from 'react';
|
||||
|
||||
import { RestrictedGrafanaApisContextProvider, RestrictedGrafanaApisContextType } from '@grafana/data';
|
||||
import { config } from '@grafana/runtime';
|
||||
import { alertingAlertRuleFormSchemaApi } from 'app/features/plugins/components/restrictedGrafanaApis/alerting/alertRuleFormSchema';
|
||||
|
||||
const restrictedGrafanaApis: RestrictedGrafanaApisContextType = config.featureToggles.restrictedPluginApis
|
||||
? {
|
||||
// Add your restricted APIs here
|
||||
// (APIs that should be availble to ALL plugins should be shared via our packages, e.g. @grafana/data.)
|
||||
alertingAlertRuleFormSchema: alertingAlertRuleFormSchemaApi.alertingAlertRuleFormSchema,
|
||||
}
|
||||
: {};
|
||||
|
||||
// This Provider is a wrapper around `RestrictedGrafanaApisContextProvider` from `@grafana/data`.
|
||||
// The reason for this is that like this we only need to define the configuration once (here) and can use it in multiple places (app root page, extensions).
|
||||
@@ -18,6 +9,23 @@ export function RestrictedGrafanaApisProvider({
|
||||
children,
|
||||
pluginId,
|
||||
}: PropsWithChildren<{ pluginId: string }>): ReactElement {
|
||||
const [restrictedGrafanaApis, setRestrictedGrafanaApis] = useState<RestrictedGrafanaApisContextType>({});
|
||||
|
||||
// Add your restricted APIs here
|
||||
// (APIs that should be availble to ALL plugins should be shared via our packages, e.g. @grafana/data.)
|
||||
useEffect(() => {
|
||||
if (!config.featureToggles.restrictedPluginApis) {
|
||||
return;
|
||||
}
|
||||
|
||||
// ⚠️ Lazy-load the alerting schema to avoid bundling zod in the main app bundle
|
||||
import('app/features/plugins/components/restrictedGrafanaApis/alerting/alertRuleFormSchema').then((module) => {
|
||||
setRestrictedGrafanaApis({
|
||||
alertingAlertRuleFormSchema: module.alertingAlertRuleFormSchemaApi.alertingAlertRuleFormSchema,
|
||||
});
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<RestrictedGrafanaApisContextProvider
|
||||
pluginId={pluginId}
|
||||
|
||||
Reference in New Issue
Block a user