You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by el...@apache.org on 2021/07/28 23:30:08 UTC

[superset] branch selfSubscribeReports updated: feat: Create/onsave Email Report functionality for Dashboard and Chart (#15856)

This is an automated email from the ASF dual-hosted git repository.

elizabeth pushed a commit to branch selfSubscribeReports
in repository https://gitbox.apache.org/repos/asf/superset.git


The following commit(s) were added to refs/heads/selfSubscribeReports by this push:
     new a6687d3  feat: Create/onsave Email Report functionality for Dashboard and Chart (#15856)
a6687d3 is described below

commit a6687d3a1b0dc54d709fb5a0b64fdebfc0e35b18
Author: Lyndsi Kay Williams <55...@users.noreply.github.com>
AuthorDate: Wed Jul 28 18:28:45 2021 -0500

    feat: Create/onsave Email Report functionality for Dashboard and Chart (#15856)
    
    * style: Rough draft of email report modal (#15666)
    
    * clears errors when closing out of modal (#15623)
    
    * add test + fix types
    
    * fix lint errors
    
    * Building ReportModal component
    
    * Continued ReportModal creation
    
    * Visual details updated
    
    * CronError style
    
    * Very basic testing added
    
    Co-authored-by: AAfghahi <48...@users.noreply.github.com>
    
    * feat: toggle the ReportModal Icon based on user permissions (#15780)
    
    * style: Rough draft of email report modal (#15666)
    
    * clears errors when closing out of modal (#15623)
    
    * fix: avoid fetching favorite status for anonymous user (#15590)
    
    * avoid fetching favorite status for anonymous user
    
    * add test + fix types
    
    * fix lint errors
    
    * Building ReportModal component
    
    * Continued ReportModal creation
    
    * Visual details updated
    
    * CronError style
    
    * Very basic testing added
    
    Co-authored-by: AAfghahi <48...@users.noreply.github.com>
    Co-authored-by: aspedrosa <as...@ua.pt>
    
    * first draft
    
    * added testing props
    
    * cleaned up rebase
    
    * changed name and type
    
    Co-authored-by: Lyndsi Kay Williams <55...@users.noreply.github.com>
    Co-authored-by: aspedrosa <as...@ua.pt>
    
    * feat: Begin incorporation of email report modal to Charts (#15793)
    
    * Add email report modal to Charts
    
    * Fix px themes
    
    * feat: fetch UI specific reports  (#15785)
    
    * style: Rough draft of email report modal (#15666)
    
    * clears errors when closing out of modal (#15623)
    
    * fix: avoid fetching favorite status for anonymous user (#15590)
    
    * avoid fetching favorite status for anonymous user
    
    * add test + fix types
    
    * fix lint errors
    
    * Building ReportModal component
    
    * Continued ReportModal creation
    
    * Visual details updated
    
    * CronError style
    
    * Very basic testing added
    
    Co-authored-by: AAfghahi <48...@users.noreply.github.com>
    Co-authored-by: aspedrosa <as...@ua.pt>
    
    * first draft
    
    * created Api call
    
    * added click logic
    
    * made the fetch report into a action/reducer
    
    * abstracted report action
    
    * revision
    
    * added reportState to reducer
    
    * reports conditions
    
    * revisions
    
    * revisions
    
    Co-authored-by: Lyndsi Kay Williams <55...@users.noreply.github.com>
    Co-authored-by: aspedrosa <as...@ua.pt>
    
    * fix: Edit physical dataset from the Edit Dataset modal (#15770)
    
    * Remove unnecessary onChange
    
    * Remove confliciting onChange
    
    * Revert unnecessary change
    
    * Enhance and fix tests
    
    * feat: add show columns to Reports model (#15712)
    
    * added logic for creation_method
    
    * revisions
    
    * added index
    
    * Update superset/migrations/versions/3317e9248280_add_creation_method_to_reports_model.py
    
    * filters
    
    * search columns updated
    
    * fix: margin right on warning icon to 8px (#15715)
    
    * changed margin right on warning icon to 8px
    
    * fixed to grid units from pixels
    
    * feat: adding Progress Bar to Benchmark script (#15719)
    
    * rough draft of benchmark script
    
    * revisions
    
    * revisions
    
    * rough draft of benchmark script
    
    * revisions
    
    * Update requirements/development.in
    
    Co-authored-by: Beto Dealmeida <ro...@dealmeida.net>
    
    * Update superset/utils/mock_data.py
    
    Co-authored-by: Beto Dealmeida <ro...@dealmeida.net>
    
    * more revisions
    
    Co-authored-by: Beto Dealmeida <ro...@dealmeida.net>
    
    * fix: migration downgrade references wrong column (#15791)
    
    * fix(dashboard): Add resize handles to right and bottom of component (#15778)
    
    * fix(dashboard): Add resize handles to right and bottom of component
    
    * Fix test
    
    * chore: Add tags to the new viz gallery (#15734)
    
    * chore: add tags to gallery
    
    * fix UT
    
    * fix lint
    
    * redesign tags filter
    
    * chore: change to Highly-used and fix some css
    
    * fix UT
    
    Co-authored-by: stephenLYZ <75...@qq.com>
    
    * chore: bump 0.17.70 (#15795)
    
    * docs: Adding Sunbird to users list (#15794)
    
    * chore: Improves the Select component UI/UX - iteration 4 (#15480)
    
    * Add z-index only on maximize (#15800)
    
    * chore: remove `retry` dependency in favor of `backoff` (#15788)
    
    * chore: remove retry dep in favor of backoff
    
    * Fix lint
    
    * fix: create fk model in benchmark script (#15804)
    
    * style: Rough draft of email report modal (#15666)
    
    * clears errors when closing out of modal (#15623)
    
    * fix: avoid fetching favorite status for anonymous user (#15590)
    
    * avoid fetching favorite status for anonymous user
    
    * add test + fix types
    
    * fix lint errors
    
    * Building ReportModal component
    
    * Continued ReportModal creation
    
    * Visual details updated
    
    * CronError style
    
    * Very basic testing added
    
    Co-authored-by: AAfghahi <48...@users.noreply.github.com>
    Co-authored-by: aspedrosa <as...@ua.pt>
    
    * Working on onSave functionality
    
    * style: Rough draft of email report modal (#15666)
    
    * clears errors when closing out of modal (#15623)
    
    * add test + fix types
    
    * fix lint errors
    
    * Building ReportModal component
    
    * Continued ReportModal creation
    
    * Visual details updated
    
    * CronError style
    
    * Very basic testing added
    
    Co-authored-by: AAfghahi <48...@users.noreply.github.com>
    
    * feat: toggle the ReportModal Icon based on user permissions (#15780)
    
    * style: Rough draft of email report modal (#15666)
    
    * clears errors when closing out of modal (#15623)
    
    * fix: avoid fetching favorite status for anonymous user (#15590)
    
    * avoid fetching favorite status for anonymous user
    
    * add test + fix types
    
    * fix lint errors
    
    * Building ReportModal component
    
    * Continued ReportModal creation
    
    * Visual details updated
    
    * CronError style
    
    * Very basic testing added
    
    Co-authored-by: AAfghahi <48...@users.noreply.github.com>
    Co-authored-by: aspedrosa <as...@ua.pt>
    
    * first draft
    
    * added testing props
    
    * cleaned up rebase
    
    * changed name and type
    
    Co-authored-by: Lyndsi Kay Williams <55...@users.noreply.github.com>
    Co-authored-by: aspedrosa <as...@ua.pt>
    
    * feat: fetch UI specific reports  (#15785)
    
    * style: Rough draft of email report modal (#15666)
    
    * clears errors when closing out of modal (#15623)
    
    * fix: avoid fetching favorite status for anonymous user (#15590)
    
    * avoid fetching favorite status for anonymous user
    
    * add test + fix types
    
    * fix lint errors
    
    * Building ReportModal component
    
    * Continued ReportModal creation
    
    * Visual details updated
    
    * CronError style
    
    * Very basic testing added
    
    Co-authored-by: AAfghahi <48...@users.noreply.github.com>
    Co-authored-by: aspedrosa <as...@ua.pt>
    
    * first draft
    
    * created Api call
    
    * added click logic
    
    * made the fetch report into a action/reducer
    
    * abstracted report action
    
    * revision
    
    * added reportState to reducer
    
    * reports conditions
    
    * revisions
    
    * revisions
    
    Co-authored-by: Lyndsi Kay Williams <55...@users.noreply.github.com>
    Co-authored-by: aspedrosa <as...@ua.pt>
    
    * Dashboard onSave progress
    
    * More onSave/create progress
    
    * Dashboard POST working!
    
    * Dashboard POST relocated to redux
    
    * POST now also working in Charts
    
    * making linter happy
    
    * linter again
    
    Co-authored-by: AAfghahi <48...@users.noreply.github.com>
    Co-authored-by: aspedrosa <as...@ua.pt>
    Co-authored-by: Geido <60...@users.noreply.github.com>
    Co-authored-by: stellalc7 <st...@gmail.com>
    Co-authored-by: Beto Dealmeida <ro...@dealmeida.net>
    Co-authored-by: Kamil Gabryjelski <ka...@gmail.com>
    Co-authored-by: Yongjie Zhao <yo...@gmail.com>
    Co-authored-by: stephenLYZ <75...@qq.com>
    Co-authored-by: Kumar <ku...@gmail.com>
    Co-authored-by: Michael S. Molina <70...@users.noreply.github.com>
---
 .../src/components/ReportModal/index.tsx           | 168 ++++++++++++++-------
 .../src/components/ReportModal/styles.tsx          |  63 ++++++++
 .../src/dashboard/components/Header/index.jsx      |   1 +
 .../src/explore/components/ExploreChartHeader.jsx  |  15 ++
 .../src/reports/actions/reportState.js             |  16 ++
 .../src/reports/reducers/reportState.js            |  13 +-
 6 files changed, 224 insertions(+), 52 deletions(-)

diff --git a/superset-frontend/src/components/ReportModal/index.tsx b/superset-frontend/src/components/ReportModal/index.tsx
index 8fbc50f..9e81778 100644
--- a/superset-frontend/src/components/ReportModal/index.tsx
+++ b/superset-frontend/src/components/ReportModal/index.tsx
@@ -18,28 +18,39 @@
  */
 import React, {
   useState,
+  // useEffect,
   useCallback,
   useReducer,
   Reducer,
   FunctionComponent,
 } from 'react';
-import { styled, css, t } from '@superset-ui/core';
+import { t } from '@superset-ui/core';
+// import { useSingleViewResource } from 'src/views/CRUD/hooks';
+
+import { bindActionCreators } from 'redux';
+import { connect, useDispatch } from 'react-redux';
+import { addReport } from 'src/reports/actions/reportState';
 
 import LabeledErrorBoundInput from 'src/components/Form/LabeledErrorBoundInput';
 import Icons from 'src/components/Icons';
-import Modal from 'src/components/Modal';
+import withToasts from 'src/messageToasts/enhancers/withToasts';
 import { CronPicker, CronError } from 'src/components/CronPicker';
-
-interface ReportProps {
-  onHide: () => {};
-  show: boolean;
-  props: any;
-}
+import {
+  StyledModal,
+  StyledTopSection,
+  StyledBottomSection,
+  StyledIconWrapper,
+  StyledScheduleTitle,
+  StyledCronError,
+  noBottomMargin,
+  StyledFooterButton,
+} from './styles';
 
 interface ReportObject {
   active: boolean;
   crontab: string;
-  dashboard: number;
+  dashboard?: number;
+  chart?: number;
   description?: string;
   log_retention: number;
   name: string;
@@ -50,6 +61,22 @@ interface ReportObject {
   validator_config_json: {} | null;
   validator_type: string;
   working_timeout: number;
+  creation_method: string;
+}
+
+interface ReportProps {
+  addDangerToast: (msg: string) => void;
+  addSuccessToast: (msg: string) => void;
+  addReport: (report?: ReportObject) => {};
+  onHide: () => {};
+  onReportAdd: (report?: ReportObject) => {};
+  show: boolean;
+  userId: number;
+  userEmail: string;
+  dashboardId?: number;
+  chartId?: number;
+  creationMethod: string;
+  props: any;
 }
 
 enum ActionType {
@@ -94,47 +121,12 @@ const reportReducer = (
   }
 };
 
-const StyledModal = styled(Modal)`
-  .ant-modal-body {
-    padding: 0;
-  }
-`;
-
-const StyledTopSection = styled.div`
-  padding: ${({ theme }) => theme.gridUnit * 4}px;
-`;
-
-const StyledBottomSection = styled.div`
-  border-top: 1px solid ${({ theme }) => theme.colors.grayscale.light2};
-  padding: ${({ theme }) => theme.gridUnit * 4}px;
-`;
-
-const StyledIconWrapper = styled.span`
-  span {
-    margin-right: ${({ theme }) => theme.gridUnit * 2}px;
-    vertical-align: middle;
-  }
-  .text {
-    vertical-align: middle;
-  }
-`;
-
-const StyledScheduleTitle = styled.div`
-  margin-bottom: ${({ theme }) => theme.gridUnit * 7}px;
-`;
-
-const StyledCronError = styled.p`
-  color: ${({ theme }) => theme.colors.error.base};
-`;
-
-const noBottomMargin = css`
-  margin-bottom: 0;
-`;
-
 const ReportModal: FunctionComponent<ReportProps> = ({
-  show = false,
+  // addDangerToast,
+  onReportAdd,
   onHide,
-  props,
+  show = false,
+  ...props
 }) => {
   const [currentReport, setCurrentReport] = useReducer<
     Reducer<Partial<ReportObject> | null, ReportActionType>
@@ -143,6 +135,59 @@ const ReportModal: FunctionComponent<ReportProps> = ({
     setCurrentReport({ type, payload } as ReportActionType);
   }, []);
   const [error, setError] = useState<CronError>();
+  // ---------- comments on lines 21, 28, 125, 139-159 & 182 are being held for edit functionality
+  // const [hasConnectedReport, setHasConnectedReport] = useState<boolean>(false);
+  // const [isLoading, setLoading] = useState<boolean>(false);
+  const dispatch = useDispatch();
+
+  // Report fetch logic
+  // const {
+  //   state: { resource },
+  // } = useSingleViewResource<ReportObject>(
+  //   'report',
+  //   t('report'),
+  //   addDangerToast,
+  // );
+
+  // useEffect(() => {
+  //   if (resource?.dashboard) {
+  //     setHasConnectedReport(true);
+  //   }
+  // }, [resource?.dashboard]);
+
+  const onClose = () => {
+    // setLoading(false);
+    onHide();
+  };
+
+  const onSave = async () => {
+    // Create new Report
+    const newReportValues: Partial<ReportObject> = {
+      crontab: currentReport?.crontab,
+      dashboard: props.props.dashboardId,
+      chart: props.props.chartId,
+      description: currentReport?.description,
+      name: currentReport?.name || 'Weekly Report',
+      owners: [props.props.userId],
+      recipients: [
+        {
+          recipient_config_json: { target: props.props.userEmail },
+          type: 'Email',
+        },
+      ],
+      type: 'Report',
+      creation_method: props.props.creationMethod,
+    };
+
+    // setLoading(true);
+    await dispatch(addReport(newReportValues as ReportObject));
+
+    if (onReportAdd) {
+      onReportAdd();
+    }
+
+    onClose();
+  };
 
   const wrappedTitle = (
     <StyledIconWrapper>
@@ -151,8 +196,26 @@ const ReportModal: FunctionComponent<ReportProps> = ({
     </StyledIconWrapper>
   );
 
+  const renderModalFooter = (
+    <>
+      <StyledFooterButton key="back" onClick={onClose}>
+        Cancel
+      </StyledFooterButton>
+      <StyledFooterButton key="submit" buttonStyle="primary" onClick={onSave}>
+        Add
+      </StyledFooterButton>
+    </>
+  );
+
   return (
-    <StyledModal show={show} onHide={onHide} title={wrappedTitle}>
+    <StyledModal
+      show={show}
+      onHide={onClose}
+      title={wrappedTitle}
+      footer={renderModalFooter}
+      width="432"
+      centered
+    >
       <StyledTopSection>
         <LabeledErrorBoundInput
           id="name"
@@ -196,7 +259,7 @@ const ReportModal: FunctionComponent<ReportProps> = ({
 
       <StyledBottomSection>
         <StyledScheduleTitle>
-          <h1>Schedule</h1>
+          <h2>Schedule</h2>
           <p>Scheduled reports will be sent to your email as a PNG</p>
         </StyledScheduleTitle>
 
@@ -217,4 +280,7 @@ const ReportModal: FunctionComponent<ReportProps> = ({
   );
 };
 
-export default ReportModal;
+const mapDispatchToProps = (dispatch: any) =>
+  bindActionCreators({ addReport }, dispatch);
+
+export default connect(null, mapDispatchToProps)(withToasts(ReportModal));
diff --git a/superset-frontend/src/components/ReportModal/styles.tsx b/superset-frontend/src/components/ReportModal/styles.tsx
new file mode 100644
index 0000000..08fe73e
--- /dev/null
+++ b/superset-frontend/src/components/ReportModal/styles.tsx
@@ -0,0 +1,63 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { styled, css } from '@superset-ui/core';
+import Modal from 'src/components/Modal';
+import Button from 'src/components/Button';
+
+export const StyledModal = styled(Modal)`
+  .ant-modal-body {
+    padding: 0;
+  }
+`;
+
+export const StyledTopSection = styled.div`
+  padding: ${({ theme }) => theme.gridUnit * 4}px;
+`;
+
+export const StyledBottomSection = styled.div`
+  border-top: 1px solid ${({ theme }) => theme.colors.grayscale.light2};
+  padding: ${({ theme }) => theme.gridUnit * 4}px;
+`;
+
+export const StyledIconWrapper = styled.span`
+  span {
+    margin-right: ${({ theme }) => theme.gridUnit * 2}px;
+    vertical-align: middle;
+  }
+  .text {
+    vertical-align: middle;
+  }
+`;
+
+export const StyledScheduleTitle = styled.div`
+  margin-bottom: ${({ theme }) => theme.gridUnit * 7}px;
+`;
+
+export const StyledCronError = styled.p`
+  color: ${({ theme }) => theme.colors.error.base};
+`;
+
+export const noBottomMargin = css`
+  margin-bottom: 0;
+`;
+
+export const StyledFooterButton = styled(Button)`
+  width: ${({ theme }) => theme.gridUnit * 40}px;
+`;
diff --git a/superset-frontend/src/dashboard/components/Header/index.jsx b/superset-frontend/src/dashboard/components/Header/index.jsx
index 70ac4db..f2bc8d2 100644
--- a/superset-frontend/src/dashboard/components/Header/index.jsx
+++ b/superset-frontend/src/dashboard/components/Header/index.jsx
@@ -603,6 +603,7 @@ class Header extends React.PureComponent {
                 userId: user.userId,
                 userEmail: user.email,
                 dashboardId: dashboardInfo.id,
+                creationMethod: 'dashboards',
               }}
             />
           )}
diff --git a/superset-frontend/src/explore/components/ExploreChartHeader.jsx b/superset-frontend/src/explore/components/ExploreChartHeader.jsx
index e33f8e2..aeca9cd 100644
--- a/superset-frontend/src/explore/components/ExploreChartHeader.jsx
+++ b/superset-frontend/src/explore/components/ExploreChartHeader.jsx
@@ -280,10 +280,25 @@ export class ExploreChartHeader extends React.PureComponent {
             isRunning={chartStatus === 'loading'}
             status={CHART_STATUS_MAP[chartStatus]}
           />
+          <span
+            role="button"
+            title={t('Schedule email report')}
+            tabIndex={0}
+            className="action-button"
+            onClick={this.showReportModal}
+          >
+            <Icons.Calendar />
+          </span>
           {this.canAddReports() && this.renderReportModal()}
           <ReportModal
             show={this.state.showingReportModal}
             onHide={this.hideReportModal}
+            props={{
+              userId: this.props.userId,
+              userEmail: this.props.email,
+              chartId: this.props.chart.id,
+              creationMethod: 'charts',
+            }}
           />
           <ExploreActionButtons
             actions={{
diff --git a/superset-frontend/src/reports/actions/reportState.js b/superset-frontend/src/reports/actions/reportState.js
index 8bed099..f0c5b6a 100644
--- a/superset-frontend/src/reports/actions/reportState.js
+++ b/superset-frontend/src/reports/actions/reportState.js
@@ -70,6 +70,22 @@ export function fetchUISpecificReport(
   };
 }
 
+export const ADD_REPORT = 'ADD_REPORT';
+
+export const addReport = report => dispatch => {
+  SupersetClient.post({
+    endpoint: `/api/v1/report/`,
+    jsonPayload: report,
+  })
+    .then(() => {
+      dispatch({ type: ADD_REPORT, report });
+    })
+    .catch(() =>
+      dispatch(
+        addDangerToast(t('An error occurred while creating this report.')),
+      ),
+    );
+};
 export const EDIT_REPORT = 'EDIT_REPORT';
 
 export function reportEditor(report) {
diff --git a/superset-frontend/src/reports/reducers/reportState.js b/superset-frontend/src/reports/reducers/reportState.js
index 5946dbd..6493e0e 100644
--- a/superset-frontend/src/reports/reducers/reportState.js
+++ b/superset-frontend/src/reports/reducers/reportState.js
@@ -18,7 +18,12 @@
  */
 /* eslint-disable camelcase */
 import { alterInArr } from 'src/reduxUtils';
-import { SET_REPORT, EDIT_REPORT, TOGGLE_ACTIVE } from '../actions/reportState';
+import {
+  SET_REPORT,
+  ADD_REPORT,
+  EDIT_REPORT,
+  TOGGLE_ACTIVE,
+} from '../actions/reportState';
 
 export default function reportStateReducer(state = {}, action) {
   const actionHandlers = {
@@ -28,6 +33,12 @@ export default function reportStateReducer(state = {}, action) {
         report: action.report,
       };
     },
+    [ADD_REPORT]() {
+      return {
+        ...state,
+        report: action.report,
+      };
+    },
     [EDIT_REPORT]() {
       return {
         ...state,