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

diegopucci pushed a commit to branch geido/feat/progressive-dashboard-header
in repository https://gitbox.apache.org/repos/asf/superset.git

commit 3bdacded281f8869029df3a946a652092c2e4082
Author: Diego Pucci <[email protected]>
AuthorDate: Tue Oct 15 18:02:19 2024 +0300

    chore(Dashboard): Unblock header actions while loading
---
 .../src/components/FaveStar/index.tsx              | 12 ++++++----
 .../Header/HeaderActionsDropdown/index.jsx         | 26 ++++++++++++++--------
 .../src/dashboard/components/Header/index.jsx      | 17 +++++++-------
 .../dashboard/components/PublishedStatus/index.jsx |  4 ++++
 .../dashboard/components/RefreshIntervalModal.tsx  | 25 +++++++++++++--------
 5 files changed, 54 insertions(+), 30 deletions(-)

diff --git a/superset-frontend/src/components/FaveStar/index.tsx 
b/superset-frontend/src/components/FaveStar/index.tsx
index fa7963480c..44f5a91cdd 100644
--- a/superset-frontend/src/components/FaveStar/index.tsx
+++ b/superset-frontend/src/components/FaveStar/index.tsx
@@ -24,7 +24,7 @@ import { Tooltip } from 'src/components/Tooltip';
 import Icons from 'src/components/Icons';
 
 export interface FaveStarProps {
-  itemId: number;
+  itemId?: number;
   isStarred?: boolean;
   showTooltip?: boolean;
   saveFaveStar(id: number, isStarred: boolean): any;
@@ -47,13 +47,17 @@ const FaveStar = ({
   fetchFaveStar,
 }: FaveStarProps) => {
   useEffect(() => {
-    fetchFaveStar?.(itemId);
+    if (itemId) {
+      fetchFaveStar?.(itemId);
+    }
   }, [fetchFaveStar, itemId]);
 
   const onClick = useCallback(
     (e: MouseEvent) => {
-      e.preventDefault();
-      saveFaveStar(itemId, !!isStarred);
+      if (itemId) {
+        e.preventDefault();
+        saveFaveStar(itemId, !!isStarred);
+      }
     },
     [isStarred, itemId, saveFaveStar],
   );
diff --git 
a/superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx
 
b/superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx
index 50cdb67813..fe9b727336 100644
--- 
a/superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx
+++ 
b/superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx
@@ -40,7 +40,7 @@ import { MenuKeys } from 'src/dashboard/types';
 const propTypes = {
   addSuccessToast: PropTypes.func.isRequired,
   addDangerToast: PropTypes.func.isRequired,
-  dashboardInfo: PropTypes.object.isRequired,
+  dashboardInfo: PropTypes.object,
   dashboardId: PropTypes.number,
   dashboardTitle: PropTypes.string,
   dataMask: PropTypes.object.isRequired,
@@ -196,7 +196,7 @@ export class HeaderActionsDropdown extends PureComponent {
     });
 
     const refreshIntervalOptions =
-      dashboardInfo.common?.conf?.DASHBOARD_AUTO_REFRESH_INTERVALS;
+      dashboardInfo?.common?.conf?.DASHBOARD_AUTO_REFRESH_INTERVALS;
 
     const dashboardComponentId = [...(directPathToChild || [])].pop();
 
@@ -216,6 +216,7 @@ export class HeaderActionsDropdown extends PureComponent {
           <Menu.Item
             key={MenuKeys.ToggleFullscreen}
             onClick={this.handleMenuClick}
+            disabled={isLoading}
           >
             {getUrlParam(URL_PARAMS.standalone)
               ? t('Exit fullscreen')
@@ -226,23 +227,25 @@ export class HeaderActionsDropdown extends PureComponent {
           <Menu.Item
             key={MenuKeys.EditProperties}
             onClick={this.handleMenuClick}
+            disabled={isLoading}
           >
             {t('Edit properties')}
           </Menu.Item>
         )}
         {editMode && (
-          <Menu.Item key={MenuKeys.EditCss}>
+          <Menu.Item key={MenuKeys.EditCss} disabled={isLoading}>
             <CssEditor
               triggerNode={<span>{t('Edit CSS')}</span>}
               initialCss={this.state.css}
               onChange={this.changeCss}
               addDangerToast={addDangerToast}
+              disabled={isLoading}
             />
           </Menu.Item>
         )}
         <Menu.Divider />
         {userCanSave && (
-          <Menu.Item key={MenuKeys.SaveModal}>
+          <Menu.Item key={MenuKeys.SaveModal} disabled={isLoading}>
             <SaveModal
               addSuccessToast={this.props.addSuccessToast}
               addDangerToast={this.props.addDangerToast}
@@ -303,6 +306,7 @@ export class HeaderActionsDropdown extends PureComponent {
           <Menu.Item
             key={MenuKeys.ManageEmbedded}
             onClick={this.handleMenuClick}
+            disabled={isLoading}
           >
             {t('Embed dashboard')}
           </Menu.Item>
@@ -311,9 +315,12 @@ export class HeaderActionsDropdown extends PureComponent {
         {!editMode ? (
           this.state.showReportSubMenu ? (
             <>
-              <Menu.SubMenu title={t('Manage email report')}>
+              <Menu.SubMenu
+                title={t('Manage email report')}
+                disabled={isLoading}
+              >
                 <HeaderReportDropdown
-                  dashboardId={dashboardInfo.id}
+                  dashboardId={dashboardInfo?.id}
                   setShowReportSubMenu={this.setShowReportSubMenu}
                   showReportSubMenu={this.state.showReportSubMenu}
                   setIsDropdownVisible={setIsDropdownVisible}
@@ -326,17 +333,18 @@ export class HeaderActionsDropdown extends PureComponent {
           ) : (
             <Menu>
               <HeaderReportDropdown
-                dashboardId={dashboardInfo.id}
+                dashboardId={dashboardInfo?.id}
                 setShowReportSubMenu={this.setShowReportSubMenu}
                 setIsDropdownVisible={setIsDropdownVisible}
                 isDropdownVisible={isDropdownVisible}
                 useTextMenu
+                disabled={isLoading}
               />
             </Menu>
           )
         ) : null}
         {editMode && !isEmpty(dashboardInfo?.metadata?.filter_scopes) && (
-          <Menu.Item key={MenuKeys.SetFilterMapping}>
+          <Menu.Item key={MenuKeys.SetFilterMapping} disabled={isLoading}>
             <FilterScopeModal
               className="m-r-5"
               triggerNode={t('Set filter mapping')}
@@ -344,7 +352,7 @@ export class HeaderActionsDropdown extends PureComponent {
           </Menu.Item>
         )}
 
-        <Menu.Item key={MenuKeys.AutorefreshModal}>
+        <Menu.Item key={MenuKeys.AutorefreshModal} disabled={isLoading}>
           <RefreshIntervalModal
             addSuccessToast={this.props.addSuccessToast}
             refreshFrequency={refreshFrequency}
diff --git a/superset-frontend/src/dashboard/components/Header/index.jsx 
b/superset-frontend/src/dashboard/components/Header/index.jsx
index 9feb086bfc..e6b3b32b29 100644
--- a/superset-frontend/src/dashboard/components/Header/index.jsx
+++ b/superset-frontend/src/dashboard/components/Header/index.jsx
@@ -446,7 +446,8 @@ class Header extends PureComponent {
       },
       {
         type: MetadataType.Owner,
-        createdBy: getOwnerName(dashboardInfo?.created_by) || t('Not 
available'),
+        createdBy:
+          getOwnerName(dashboardInfo?.created_by) || t('Not available'),
         owners:
           dashboardInfo?.owners.length > 0
             ? dashboardInfo?.owners.map(getOwnerName)
@@ -458,6 +459,9 @@ class Header extends PureComponent {
 
   render() {
     const {
+      dashboardInfo,
+      dashboardTitle,
+      chartsLoading,
       layout,
       expandedSlices,
       customCss,
@@ -477,16 +481,12 @@ class Header extends PureComponent {
       isPublished,
       user,
       hasUnsavedChanges,
-      chartsLoading,
       refreshFrequency,
       shouldPersistRefreshFrequency,
       setRefreshFrequency,
       lastModifiedTime,
       logEvent,
     } = this.props;
-    const dashboardInfo = null;
-    const dashboardTitle = null;
-
     const userCanEdit =
       dashboardInfo?.dash_edit_perm && !dashboardInfo?.is_managed_externally;
     const userCanShare = dashboardInfo?.dash_share_perm;
@@ -544,7 +544,7 @@ class Header extends PureComponent {
             fetchFaveStar: this.props.fetchFaveStar,
             saveFaveStar: this.props.saveFaveStar,
             isStarred: this.props.isStarred,
-            showTooltip: true,
+            showTooltip: !!dashboardInfo?.id,
           }}
           titlePanelAdditionalItems={[
             !editMode && (
@@ -555,13 +555,14 @@ class Header extends PureComponent {
                 canEdit={userCanEdit}
                 canSave={userCanSaveAs}
                 visible={!editMode}
+                loading={!dashboardInfo?.id}
               />
             ),
             !editMode && (
               <MetadataBar
                 items={this.getMetadataItems()}
                 tooltipPlacement="bottom"
-                loading={!dashboardInfo}
+                loading={!dashboardInfo?.id}
               />
             ),
           ]}
@@ -701,7 +702,7 @@ class Header extends PureComponent {
               userCanShare={userCanShare}
               userCanSave={userCanSaveAs}
               userCanCurate={userCanCurate}
-              isLoading={chartsLoading}
+              isLoading={chartsLoading || !dashboardInfo?.id}
               showPropertiesModal={this.showPropertiesModal}
               manageEmbedded={this.showEmbedModal}
               refreshLimit={refreshLimit}
diff --git 
a/superset-frontend/src/dashboard/components/PublishedStatus/index.jsx 
b/superset-frontend/src/dashboard/components/PublishedStatus/index.jsx
index c966542146..abc9671fbc 100644
--- a/superset-frontend/src/dashboard/components/PublishedStatus/index.jsx
+++ b/superset-frontend/src/dashboard/components/PublishedStatus/index.jsx
@@ -28,6 +28,7 @@ const propTypes = {
   savePublished: PropTypes.func.isRequired,
   canEdit: PropTypes.bool,
   canSave: PropTypes.bool,
+  loading: PropTypes.bool,
 };
 
 const draftButtonTooltip = t(
@@ -54,6 +55,9 @@ export default class PublishedStatus extends Component {
   }
 
   render() {
+    if (this.props.loading) {
+      return <Label>{t('...')}</Label>;
+    }
     // Show everybody the draft badge
     if (!this.props.isPublished) {
       // if they can edit the dash, make the badge a button
diff --git 
a/superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx 
b/superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx
index 89f34bc33d..b1fcee9c54 100644
--- a/superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx
+++ b/superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx
@@ -50,16 +50,16 @@ const InnerStyledDiv = styled.div`
 type RefreshIntervalModalProps = {
   addSuccessToast: (msg: string) => void;
   triggerNode: JSX.Element;
-  refreshFrequency: number;
+  refreshFrequency?: number;
   onChange: (refreshLimit: number, editMode: boolean) => void;
   editMode: boolean;
   refreshLimit?: number;
   refreshWarning: string | null;
-  refreshIntervalOptions: [number, string][];
+  refreshIntervalOptions?: [number, string][];
 };
 
 type RefreshIntervalModalState = {
-  refreshFrequency: number;
+  refreshFrequency?: number;
   custom_hour: number;
   custom_min: number;
   custom_sec: number;
@@ -93,9 +93,11 @@ class RefreshIntervalModal extends PureComponent<
   }
 
   onSave() {
-    this.props.onChange(this.state.refreshFrequency, this.props.editMode);
-    this.modalRef?.current?.close();
-    this.props.addSuccessToast(t('Refresh interval saved'));
+    if (this.state.refreshFrequency !== undefined) {
+      this.props.onChange(this.state.refreshFrequency, this.props.editMode);
+      this.modalRef?.current?.close();
+      this.props.addSuccessToast(t('Refresh interval saved'));
+    }
   }
 
   onCancel() {
@@ -108,7 +110,7 @@ class RefreshIntervalModal extends PureComponent<
   handleFrequencyChange(value: number) {
     const { refreshIntervalOptions } = this.props;
     this.setState({
-      refreshFrequency: value || refreshIntervalOptions[0][0],
+      refreshFrequency: value || refreshIntervalOptions?.[0]?.[0],
     });
 
     this.setState({
@@ -135,7 +137,7 @@ class RefreshIntervalModal extends PureComponent<
 
     refresh_options.push({ value: -1, label: t('Custom interval') });
     refresh_options.push(
-      ...refreshIntervalOptions.map(option => ({
+      ...refreshIntervalOptions?.map(option => ({
         value: option[0],
         label: t(option[1]),
       })),
@@ -221,7 +223,11 @@ class RefreshIntervalModal extends PureComponent<
               </FormLabel>
               <Select
                 ariaLabel={t('Refresh interval')}
-                options={this.createIntervalOptions(refreshIntervalOptions)}
+                options={
+                  refreshIntervalOptions
+                    ? this.createIntervalOptions(refreshIntervalOptions)
+                    : []
+                }
                 value={refreshFrequency}
                 onChange={this.handleFrequencyChange}
                 sortComparator={propertyComparator('value')}
@@ -307,6 +313,7 @@ class RefreshIntervalModal extends PureComponent<
             <Button
               buttonStyle="primary"
               buttonSize="small"
+              disabled={!refreshIntervalOptions}
               onClick={() =>
                 this.refresh_custom_val(
                   custom_block,

Reply via email to