diff --git a/public/app/features/alerting/unified/RuleEditorCloudRules.test.tsx b/public/app/features/alerting/unified/RuleEditorCloudRules.test.tsx
index b1429b3a32d..0ed3e4bf9bc 100644
--- a/public/app/features/alerting/unified/RuleEditorCloudRules.test.tsx
+++ b/public/app/features/alerting/unified/RuleEditorCloudRules.test.tsx
@@ -36,6 +36,10 @@ jest.mock('app/features/query/components/QueryEditorRow', () => ({
QueryEditorRow: () =>
hi
,
}));
+jest.mock('app/core/components/AppChrome/AppChromeUpdate', () => ({
+ AppChromeUpdate: ({ actions }: { actions: React.ReactNode }) => {actions}
,
+}));
+
jest.spyOn(config, 'getAllDataSources');
// these tests are rather slow because we have to wait for various API calls and mocks to be called
diff --git a/public/app/features/alerting/unified/RuleEditorExisting.test.tsx b/public/app/features/alerting/unified/RuleEditorExisting.test.tsx
index e2e98488f1f..97975680a55 100644
--- a/public/app/features/alerting/unified/RuleEditorExisting.test.tsx
+++ b/public/app/features/alerting/unified/RuleEditorExisting.test.tsx
@@ -32,6 +32,10 @@ jest.mock('./components/rule-editor/ExpressionEditor', () => ({
),
}));
+jest.mock('app/core/components/AppChrome/AppChromeUpdate', () => ({
+ AppChromeUpdate: ({ actions }: { actions: React.ReactNode }) => {actions}
,
+}));
+
jest.mock('./api/buildInfo');
jest.mock('./api/ruler');
jest.mock('../../../../app/features/manage-dashboards/state/actions');
diff --git a/public/app/features/alerting/unified/RuleEditorGrafanaRules.test.tsx b/public/app/features/alerting/unified/RuleEditorGrafanaRules.test.tsx
index 8954ded9477..3d07778998d 100644
--- a/public/app/features/alerting/unified/RuleEditorGrafanaRules.test.tsx
+++ b/public/app/features/alerting/unified/RuleEditorGrafanaRules.test.tsx
@@ -32,6 +32,10 @@ jest.mock('./api/buildInfo');
jest.mock('./api/ruler');
jest.mock('../../../../app/features/manage-dashboards/state/actions');
+jest.mock('app/core/components/AppChrome/AppChromeUpdate', () => ({
+ AppChromeUpdate: ({ actions }: { actions: React.ReactNode }) => {actions}
,
+}));
+
// there's no angular scope in test and things go terribly wrong when trying to render the query editor row.
// lets just skip it
jest.mock('app/features/query/components/QueryEditorRow', () => ({
diff --git a/public/app/features/alerting/unified/RuleEditorRecordingRule.test.tsx b/public/app/features/alerting/unified/RuleEditorRecordingRule.test.tsx
index 39f92cb129d..07be64d8515 100644
--- a/public/app/features/alerting/unified/RuleEditorRecordingRule.test.tsx
+++ b/public/app/features/alerting/unified/RuleEditorRecordingRule.test.tsx
@@ -39,6 +39,10 @@ jest.mock('./components/rule-editor/RecordingRuleEditor', () => ({
},
}));
+jest.mock('app/core/components/AppChrome/AppChromeUpdate', () => ({
+ AppChromeUpdate: ({ actions }: { actions: React.ReactNode }) => {actions}
,
+}));
+
jest.mock('./api/buildInfo');
jest.mock('./api/ruler');
jest.mock('../../../../app/features/manage-dashboards/state/actions');
diff --git a/public/app/features/alerting/unified/components/rule-editor/AlertRuleForm.tsx b/public/app/features/alerting/unified/components/rule-editor/AlertRuleForm.tsx
index 95c7537b1cf..17ee45d7b1c 100644
--- a/public/app/features/alerting/unified/components/rule-editor/AlertRuleForm.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/AlertRuleForm.tsx
@@ -7,6 +7,7 @@ import { Link, useParams } from 'react-router-dom';
import { GrafanaTheme2 } from '@grafana/data';
import { config, logInfo } from '@grafana/runtime';
import { Button, ConfirmModal, CustomScrollbar, Field, HorizontalGroup, Input, Spinner, useStyles2 } from '@grafana/ui';
+import { AppChromeUpdate } from 'app/core/components/AppChrome/AppChromeUpdate';
import { useAppNotification } from 'app/core/copy/appNotification';
import { contextSrv } from 'app/core/core';
import { useCleanup } from 'app/core/hooks/useCleanup';
@@ -192,49 +193,56 @@ export const AlertRuleForm = ({ existing, prefill }: Props) => {
const evaluateEveryInForm = watch('evaluateEvery');
useEffect(() => setEvaluateEvery(evaluateEveryInForm), [evaluateEveryInForm]);
+ const actionButtons = (
+
+ submit(values, false), onInvalid)}
+ disabled={submitState.loading}
+ >
+ {submitState.loading && }
+ Save rule
+
+ submit(values, true), onInvalid)}
+ disabled={submitState.loading}
+ >
+ {submitState.loading && }
+ Save rule and exit
+
+
+
+ Cancel
+
+
+ {existing ? (
+ setShowDeleteModal(true)} size="sm">
+ Delete
+
+ ) : null}
+ {isCortexLokiOrRecordingRule(watch) && (
+ setShowEditYaml(true)}
+ disabled={submitState.loading}
+ size="sm"
+ >
+ Edit YAML
+
+ )}
+
+ );
+
return (
+