From 942c4779b913111b80fecd645287f0280e604eec Mon Sep 17 00:00:00 2001 From: Sonia Aguilar <33540275+soniaAguilarPeiron@users.noreply.github.com> Date: Mon, 18 Sep 2023 10:31:19 +0200 Subject: [PATCH] Alerting: Add export drawer when exporting all Grafana managed alerts (#74846) * Add export formats drawer when exporting contact points * Add 'export by format' drawer in policies (root policy) * Add test for showing export policies button * Add tests for Policy.tsx * Add tests for export functionality in receivers * Add exporter drawer for receivers * Fix prettier warnings * Allow HCL only for alert rules exports * Add tests for Policies * Fix tests * Refactor: Update ExportProviders types for limiting the avaliable export formats when using GrafanaExportDrawer * Delete unused shouldShowExportOption method and tests * Add exporter drawer when clicking export all Grafana managed alerts * Fix test * fix prettier * lint --------- Co-authored-by: Gilles De Mey --- .../unified/MoreActionsRuleButtons.tsx | 16 ++---- .../alerting/unified/RuleList.test.tsx | 4 +- .../alerting/unified/api/alertRuleApi.ts | 7 +++ .../export/GrafanaRulesExporter.tsx | 54 +++++++++++++++++++ 4 files changed, 69 insertions(+), 12 deletions(-) create mode 100644 public/app/features/alerting/unified/components/export/GrafanaRulesExporter.tsx 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 ( + + ); +}