diff --git a/public/app/features/alerting/unified/MoreActionsRuleButtons.tsx b/public/app/features/alerting/unified/MoreActionsRuleButtons.tsx index e22af5ca6a4..ba1d61121ec 100644 --- a/public/app/features/alerting/unified/MoreActionsRuleButtons.tsx +++ b/public/app/features/alerting/unified/MoreActionsRuleButtons.tsx @@ -1,18 +1,20 @@ import React from 'react'; import { useLocation } from 'react-router-dom'; +import { useToggle } from 'react-use'; import { urlUtil } from '@grafana/data'; import { Button, Dropdown, Icon, LinkButton, Menu, MenuItem } from '@grafana/ui'; import { logInfo, LogMessages } from './Analytics'; +import { GrafanaRulesExporter } from './components/export/GrafanaRulesExporter'; import { useRulesAccess } from './utils/accessControlHooks'; -import { createUrl } from './utils/url'; interface Props {} export function MoreActionsRuleButtons({}: Props) { const { canCreateGrafanaRules, canCreateCloudRules, canReadProvisioning } = useRulesAccess(); const location = useLocation(); + const [showExportDrawer, toggleShowExportDrawer] = useToggle(false); const newMenu = ( {(canCreateGrafanaRules || canCreateCloudRules) && ( @@ -23,16 +25,7 @@ export function MoreActionsRuleButtons({}: Props) { label="New recording rule" /> )} - {canReadProvisioning && ( - - )} + {canReadProvisioning && } ); @@ -54,6 +47,7 @@ export function MoreActionsRuleButtons({}: Props) { + {showExportDrawer && } ); } diff --git a/public/app/features/alerting/unified/RuleList.test.tsx b/public/app/features/alerting/unified/RuleList.test.tsx index f371c453c89..54a5f82af68 100644 --- a/public/app/features/alerting/unified/RuleList.test.tsx +++ b/public/app/features/alerting/unified/RuleList.test.tsx @@ -117,7 +117,9 @@ const ui = { editCloudGroupIcon: byTestId('edit-group'), newRuleButton: byRole('link', { name: 'New alert rule' }), moreButton: byRole('button', { name: 'More' }), - exportButton: byRole('link', { name: /export/i }), + exportButton: byRole('menuitem', { + name: /export all grafana\-managed rules/i, + }), editGroupModal: { dialog: byRole('dialog'), namespaceInput: byRole('textbox', { name: /^Namespace/ }), diff --git a/public/app/features/alerting/unified/api/alertRuleApi.ts b/public/app/features/alerting/unified/api/alertRuleApi.ts index b3f0d7f6a25..d8b54019fe4 100644 --- a/public/app/features/alerting/unified/api/alertRuleApi.ts +++ b/public/app/features/alerting/unified/api/alertRuleApi.ts @@ -192,6 +192,13 @@ export const alertRuleApi = alertingApi.injectEndpoints({ responseType: 'text', }), }), + exportRules: build.query({ + query: ({ format }) => ({ + url: `/api/v1/provisioning/alert-rules/export`, + params: { format: format }, + responseType: 'text', + }), + }), exportReceiver: build.query({ query: ({ receiverName, decrypt, format }) => ({ url: `/api/v1/provisioning/contact-points/export/`, diff --git a/public/app/features/alerting/unified/components/export/GrafanaRulesExporter.tsx b/public/app/features/alerting/unified/components/export/GrafanaRulesExporter.tsx new file mode 100644 index 00000000000..ea8e8dbe000 --- /dev/null +++ b/public/app/features/alerting/unified/components/export/GrafanaRulesExporter.tsx @@ -0,0 +1,54 @@ +import React, { useState } from 'react'; + +import { LoadingPlaceholder } from '@grafana/ui'; + +import { alertRuleApi } from '../../api/alertRuleApi'; + +import { FileExportPreview } from './FileExportPreview'; +import { GrafanaExportDrawer } from './GrafanaExportDrawer'; +import { allGrafanaExportProviders, ExportFormats } from './providers'; + +interface GrafanaRulesExporterProps { + onClose: () => void; +} + +export function GrafanaRulesExporter({ onClose }: GrafanaRulesExporterProps) { + const [activeTab, setActiveTab] = useState('yaml'); + + return ( + + + + ); +} + +interface GrafanaRulesExportPreviewProps { + exportFormat: ExportFormats; + onClose: () => void; +} + +function GrafanaRulesExportPreview({ exportFormat, onClose }: GrafanaRulesExportPreviewProps) { + const { currentData: rulesDefinition = '', isFetching } = alertRuleApi.useExportRulesQuery({ + format: exportFormat, + }); + + const downloadFileName = `alert-rules-${new Date().getTime()}`; + + if (isFetching) { + return ; + } + + return ( + + ); +}