From df7e2b6a8e5ce01cbc79d832e86fc4b8511f4385 Mon Sep 17 00:00:00 2001 From: Lily Kuang Date: Thu, 15 Apr 2021 14:07:49 -0700 Subject: [PATCH] feat(alert/report): chart as csv format attachment for email and slack (#13828) * add ui for setting report format * refactor default notification format * init csv data alert report * add report format to report_schedule model * add ALERTS_ATTACH_REPORTS feature flag * fix lint * update check image tag * fix migrations Co-authored-by: samtfm --- .../src/views/CRUD/alert/AlertReportModal.tsx | 211 +++-------- .../alert/components/NotificationMethod.tsx | 168 +++++++++ .../src/views/CRUD/alert/types.ts | 1 + ...3_add_report_format_to_report_schedule_.py | 44 +++ superset/models/reports.py | 7 +- superset/reports/api.py | 4 +- superset/reports/commands/exceptions.py | 8 + superset/reports/commands/execute.py | 56 ++- superset/reports/notifications/base.py | 3 +- superset/reports/notifications/email.py | 15 +- superset/reports/notifications/slack.py | 14 +- superset/reports/schemas.py | 9 + superset/utils/csv.py | 21 +- tests/reports/commands_tests.py | 352 ++++++++++++++---- tests/reports/utils.py | 3 + 15 files changed, 670 insertions(+), 246 deletions(-) create mode 100644 superset-frontend/src/views/CRUD/alert/components/NotificationMethod.tsx create mode 100644 superset/migrations/versions/19e978e1b9c3_add_report_format_to_report_schedule_.py diff --git a/superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx b/superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx index ea9422cfa..6f4d57f52 100644 --- a/superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx +++ b/superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx @@ -26,10 +26,13 @@ import Modal from 'src/common/components/Modal'; import { Switch } from 'src/common/components/Switch'; import { Radio } from 'src/common/components/Radio'; import { AsyncSelect, NativeGraySelect as Select } from 'src/components/Select'; +import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags'; import withToasts from 'src/messageToasts/enhancers/withToasts'; import Owner from 'src/types/Owner'; import TextAreaControl from 'src/explore/components/controls/TextAreaControl'; import { AlertReportCronScheduler } from './components/AlertReportCronScheduler'; +import { NotificationMethod } from './components/NotificationMethod'; + import { AlertObject, ChartObject, @@ -58,7 +61,7 @@ interface AlertReportModalProps { } const NOTIFICATION_METHODS: NotificationMethod[] = ['Email', 'Slack']; - +const DEFAULT_NOTIFICATION_FORMAT = 'PNG'; const CONDITIONS = [ { label: t('< (Smaller than)'), @@ -326,33 +329,6 @@ const StyledNotificationAddButton = styled.div` } `; -const StyledNotificationMethod = styled.div` - margin-bottom: 10px; - - .input-container { - textarea { - height: auto; - } - } - - .inline-container { - margin-bottom: 10px; - - .input-container { - margin-left: 10px; - } - - > div { - margin: 0; - } - - .delete-button { - margin-left: 10px; - padding-top: 3px; - } - } -`; - type NotificationAddStatus = 'active' | 'disabled' | 'hidden'; interface NotificationMethodAddProps { @@ -392,116 +368,6 @@ type NotificationSetting = { options: NotificationMethod[]; }; -interface NotificationMethodProps { - setting?: NotificationSetting | null; - index: number; - onUpdate?: (index: number, updatedSetting: NotificationSetting) => void; - onRemove?: (index: number) => void; -} - -const NotificationMethod: FunctionComponent = ({ - setting = null, - index, - onUpdate, - onRemove, -}) => { - const { method, recipients, options } = setting || {}; - const [recipientValue, setRecipientValue] = useState( - recipients || '', - ); - - if (!setting) { - return null; - } - - const onMethodChange = (method: NotificationMethod) => { - // Since we're swapping the method, reset the recipients - setRecipientValue(''); - if (onUpdate) { - const updatedSetting = { - ...setting, - method, - recipients: '', - }; - - onUpdate(index, updatedSetting); - } - }; - - const onRecipientsChange = ( - event: React.ChangeEvent, - ) => { - const { target } = event; - - setRecipientValue(target.value); - - if (onUpdate) { - const updatedSetting = { - ...setting, - recipients: target.value, - }; - - onUpdate(index, updatedSetting); - } - }; - - // Set recipients - if (!!recipients && recipientValue !== recipients) { - setRecipientValue(recipients); - } - - const methodOptions = (options || []).map((method: NotificationMethod) => ( - - {t(method)} - - )); - - return ( - -
- -
- -
-
- {method !== undefined && !!onRemove ? ( - onRemove(index)} - > - - - ) : null} -
- {method !== undefined ? ( - -
{t(method)}
-
-