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

[superset] branch master updated: feat(explore): collapse time section if no ts columns (#14493)

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 680c96e  feat(explore): collapse time section if no ts columns (#14493)
680c96e is described below

commit 680c96ec541b8db7316042c919d269aa979f6ac3
Author: Ville Brofeldt <33...@users.noreply.github.com>
AuthorDate: Fri May 7 11:55:54 2021 +0300

    feat(explore): collapse time section if no ts columns (#14493)
    
    * feat(explore): collapse time section if no ts columns
    
    * fix viz change bug
    
    * fix test
---
 .../cypress/integration/explore/control.test.ts    |   2 +-
 .../explore/components/ControlPanelsContainer.tsx  | 178 +++++++++++++++------
 2 files changed, 133 insertions(+), 47 deletions(-)

diff --git a/superset-frontend/cypress-base/cypress/integration/explore/control.test.ts b/superset-frontend/cypress-base/cypress/integration/explore/control.test.ts
index c65b5df..e6d8b56 100644
--- a/superset-frontend/cypress-base/cypress/integration/explore/control.test.ts
+++ b/superset-frontend/cypress-base/cypress/integration/explore/control.test.ts
@@ -111,7 +111,7 @@ describe('VizType control', () => {
     // should load mathjs for line chart
     cy.get('script[src*="mathjs"]').should('have.length', 1);
     cy.get('script').then(nodes => {
-      expect(nodes.length).to.eq(numScripts);
+      expect(nodes.length).to.greaterThan(numScripts);
     });
 
     cy.get('button[data-test="run-query-button"]').click();
diff --git a/superset-frontend/src/explore/components/ControlPanelsContainer.tsx b/superset-frontend/src/explore/components/ControlPanelsContainer.tsx
index 9181a56..a0d1f44 100644
--- a/superset-frontend/src/explore/components/ControlPanelsContainer.tsx
+++ b/superset-frontend/src/explore/components/ControlPanelsContainer.tsx
@@ -21,6 +21,7 @@ import React from 'react';
 import { bindActionCreators } from 'redux';
 import { connect } from 'react-redux';
 import {
+  ensureIsArray,
   t,
   styled,
   getChartControlPanelRegistry,
@@ -31,8 +32,10 @@ import {
   ControlPanelSectionConfig,
   ControlState,
   CustomControlItem,
+  DatasourceMeta,
   ExpandedControlItem,
   InfoTooltipWithTrigger,
+  sections,
 } from '@superset-ui/chart-controls';
 
 import Collapse from 'src/components/Collapse';
@@ -102,29 +105,129 @@ const ControlPanelsTabs = styled(Tabs)`
   }
 `;
 
-export class ControlPanelsContainer extends React.Component<ControlPanelsContainerProps> {
+type ControlPanelsContainerState = {
+  expandedQuerySections: string[];
+  expandedCustomizeSections: string[];
+  querySections: ControlPanelSectionConfig[];
+  customizeSections: ControlPanelSectionConfig[];
+};
+
+const isTimeSection = (section: ControlPanelSectionConfig): boolean =>
+  !!section.label &&
+  (sections.legacyRegularTime.label === section.label ||
+    sections.legacyTimeseriesTime.label === section.label);
+
+const hasTimeColumn = (datasource: DatasourceMeta): boolean =>
+  datasource?.columns?.some(c => c.is_dttm) ||
+  datasource.type === DatasourceType.Druid;
+
+const sectionsToExpand = (
+  sections: ControlPanelSectionConfig[],
+  datasource: DatasourceMeta,
+): string[] =>
+  // avoid expanding time section if datasource doesn't include time column
+  sections.reduce(
+    (acc, section) =>
+      section.expanded && (!isTimeSection(section) || hasTimeColumn(datasource))
+        ? [...acc, String(section.label)]
+        : acc,
+    [] as string[],
+  );
+
+function getState(
+  props: ControlPanelsContainerProps,
+): ControlPanelsContainerState {
+  const {
+    exploreState: { datasource },
+  } = props;
+
+  const querySections: ControlPanelSectionConfig[] = [];
+  const customizeSections: ControlPanelSectionConfig[] = [];
+
+  getSectionsToRender(props.form_data.viz_type, props.datasource_type).forEach(
+    section => {
+      // if at least one control in the section is not `renderTrigger`
+      // or asks to be displayed at the Data tab
+      if (
+        section.tabOverride === 'data' ||
+        section.controlSetRows.some(rows =>
+          rows.some(
+            control =>
+              control &&
+              typeof control === 'object' &&
+              'config' in control &&
+              control.config &&
+              (!control.config.renderTrigger ||
+                control.config.tabOverride === 'data'),
+          ),
+        )
+      ) {
+        querySections.push(section);
+      } else {
+        customizeSections.push(section);
+      }
+    },
+  );
+  const expandedQuerySections: string[] = sectionsToExpand(
+    querySections,
+    datasource,
+  );
+  const expandedCustomizeSections: string[] = sectionsToExpand(
+    customizeSections,
+    datasource,
+  );
+  return {
+    expandedQuerySections,
+    expandedCustomizeSections,
+    querySections,
+    customizeSections,
+  };
+}
+
+export class ControlPanelsContainer extends React.Component<
+  ControlPanelsContainerProps,
+  ControlPanelsContainerState
+> {
   // trigger updates to the component when async plugins load
   static contextType = PluginContext;
 
   constructor(props: ControlPanelsContainerProps) {
     super(props);
+    this.state = {
+      expandedQuerySections: [],
+      expandedCustomizeSections: [],
+      querySections: [],
+      customizeSections: [],
+    };
     this.renderControl = this.renderControl.bind(this);
     this.renderControlPanelSection = this.renderControlPanelSection.bind(this);
   }
 
-  sectionsToRender(): ExpandedControlPanelSectionConfig[] {
-    return getSectionsToRender(
-      this.props.form_data.viz_type,
-      this.props.datasource_type,
-    );
+  static getDerivedStateFromProps(
+    props: ControlPanelsContainerProps,
+    state: ControlPanelsContainerState,
+  ): ControlPanelsContainerState {
+    // only update the sections, not the expanded/collapsed state
+    const newState = getState(props);
+    return {
+      ...state,
+      customizeSections: newState.customizeSections,
+      querySections: newState.querySections,
+    };
   }
 
-  sectionsToExpand(sections: ControlPanelSectionConfig[]) {
-    return sections.reduce(
-      (acc, section) =>
-        section.expanded ? [...acc, String(section.label)] : acc,
-      [] as string[],
-    );
+  componentDidUpdate(prevProps: ControlPanelsContainerProps) {
+    if (
+      this.props.form_data.datasource !== prevProps.form_data.datasource ||
+      this.props.form_data.viz_type !== prevProps.form_data.viz_type
+    ) {
+      // eslint-disable-next-line react/no-did-update-set-state
+      this.setState(getState(this.props));
+    }
+  }
+
+  componentDidMount() {
+    this.setState(getState(this.props));
   }
 
   renderControl({ name, config }: CustomControlItem) {
@@ -260,36 +363,7 @@ export class ControlPanelsContainer extends React.Component<ControlPanelsContain
       return <Loading />;
     }
 
-    const querySectionsToRender: ExpandedControlPanelSectionConfig[] = [];
-    const displaySectionsToRender: ExpandedControlPanelSectionConfig[] = [];
-    this.sectionsToRender().forEach(section => {
-      // if at least one control in the section is not `renderTrigger`
-      // or asks to be displayed at the Data tab
-      if (
-        section.tabOverride === 'data' ||
-        section.controlSetRows.some(rows =>
-          rows.some(
-            control =>
-              control &&
-              typeof control === 'object' &&
-              'config' in control &&
-              control.config &&
-              (!control.config.renderTrigger ||
-                control.config.tabOverride === 'data'),
-          ),
-        )
-      ) {
-        querySectionsToRender.push(section);
-      } else {
-        displaySectionsToRender.push(section);
-      }
-    });
-
-    const showCustomizeTab = displaySectionsToRender.length > 0;
-    const expandedQuerySections = this.sectionsToExpand(querySectionsToRender);
-    const expandedCustomSections = this.sectionsToExpand(
-      displaySectionsToRender,
-    );
+    const showCustomizeTab = this.state.customizeSections.length > 0;
     return (
       <Styles>
         <ControlPanelsTabs
@@ -300,22 +374,34 @@ export class ControlPanelsContainer extends React.Component<ControlPanelsContain
           <Tabs.TabPane key="query" tab={t('Data')}>
             <Collapse
               bordered
-              defaultActiveKey={expandedQuerySections}
+              activeKey={this.state.expandedQuerySections}
               expandIconPosition="right"
+              onChange={selection => {
+                this.setState({
+                  expandedQuerySections: ensureIsArray(selection),
+                });
+              }}
               ghost
             >
-              {querySectionsToRender.map(this.renderControlPanelSection)}
+              {this.state.querySections.map(this.renderControlPanelSection)}
             </Collapse>
           </Tabs.TabPane>
           {showCustomizeTab && (
             <Tabs.TabPane key="display" tab={t('Customize')}>
               <Collapse
                 bordered
-                defaultActiveKey={expandedCustomSections}
+                activeKey={this.state.expandedCustomizeSections}
                 expandIconPosition="right"
+                onChange={selection => {
+                  this.setState({
+                    expandedCustomizeSections: ensureIsArray(selection),
+                  });
+                }}
                 ghost
               >
-                {displaySectionsToRender.map(this.renderControlPanelSection)}
+                {this.state.customizeSections.map(
+                  this.renderControlPanelSection,
+                )}
               </Collapse>
             </Tabs.TabPane>
           )}