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

graceguo pushed a commit to branch gg-Test-Scoped-Filters
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git

commit 79e0986ec415eb088e144768ee2440ecb636c35f
Author: Grace <[email protected]>
AuthorDate: Mon Oct 21 17:48:36 2019 -0700

    convert ids to scope object
---
 .../util/getFilterScopeFromNodesTree_spec.js       | 216 +++++++++++++++++++++
 .../dashboard/util/getFilterScopeFromNodesTree.js  | 132 +++++++++++++
 2 files changed, 348 insertions(+)

diff --git 
a/superset/assets/spec/javascripts/dashboard/util/getFilterScopeFromNodesTree_spec.js
 
b/superset/assets/spec/javascripts/dashboard/util/getFilterScopeFromNodesTree_spec.js
new file mode 100644
index 0000000..067e193
--- /dev/null
+++ 
b/superset/assets/spec/javascripts/dashboard/util/getFilterScopeFromNodesTree_spec.js
@@ -0,0 +1,216 @@
+/**
+ * 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 getFilterScopeFromNodesTree from 
'../../../../src/dashboard/util/getFilterScopeFromNodesTree';
+
+describe('getFilterScopeFromNodesTree', () => {
+  it('should return empty scope', () => {
+    const nodes = [];
+    expect(
+      getFilterScopeFromNodesTree({
+        filterKey: '107_region',
+        nodes,
+        checkedChartIds: [],
+      }),
+    ).toEqual({});
+  });
+
+  it('should return scope for simple grid', () => {
+    const nodes = [
+      {
+        label: 'All dashboard',
+        type: 'ROOT',
+        value: 'ROOT_ID',
+        children: [
+          {
+            value: 104,
+            label: 'Life Expectancy VS Rural %',
+            type: 'CHART',
+          },
+          { value: 105, label: 'Rural Breakdown', type: 'CHART' },
+          {
+            value: 106,
+            label: "World's Pop Growth",
+            type: 'CHART',
+          },
+          {
+            label: 'Time Filter',
+            showCheckbox: false,
+            type: 'CHART',
+            value: 108,
+          },
+        ],
+      },
+    ];
+    const checkedChartIds = [104, 106];
+    expect(
+      getFilterScopeFromNodesTree({
+        filterKey: '108___time_range',
+        nodes,
+        checkedChartIds,
+      }),
+    ).toEqual({
+      scope: ['ROOT_ID'],
+      immune: [105],
+    });
+  });
+
+  describe('should return scope for tabbed dashboard', () => {
+    const nodes = [
+      {
+        label: 'All dashboard',
+        type: 'ROOT',
+        value: 'ROOT_ID',
+        children: [
+          {
+            label: 'Tab 1',
+            type: 'TAB',
+            value: 'TAB-Rb5aaqKWgG',
+            children: [
+              {
+                label: 'Geo Filters',
+                showCheckbox: false,
+                type: 'CHART',
+                value: 107,
+              },
+              {
+                label: "World's Pop Growth",
+                showCheckbox: true,
+                type: 'CHART',
+                value: 106,
+              },
+            ],
+          },
+          {
+            label: 'Tab 2',
+            type: 'TAB',
+            value: 'TAB-w5Fp904Rs',
+            children: [
+              {
+                label: 'Time Filter',
+                showCheckbox: true,
+                type: 'CHART',
+                value: 108,
+              },
+              {
+                label: 'Life Expectancy VS Rural %',
+                showCheckbox: true,
+                type: 'CHART',
+                value: 104,
+              },
+              {
+                label: 'Row Tab 1',
+                type: 'TAB',
+                value: 'TAB-E4mJaZ-uQM',
+                children: [
+                  {
+                    value: 105,
+                    label: 'Rural Breakdown',
+                    type: 'CHART',
+                    showCheckbox: true,
+                  },
+                  {
+                    value: 103,
+                    label: '% Rural',
+                    type: 'CHART',
+                    showCheckbox: true,
+                  },
+                ],
+              },
+              {
+                value: 'TAB-rLYu-Cryu',
+                label: 'New Tab',
+                type: 'TAB',
+                children: [
+                  {
+                    value: 102,
+                    label: 'Most Populated Countries',
+                    type: 'CHART',
+                    showCheckbox: true,
+                  },
+                  {
+                    value: 101,
+                    label: "World's Population",
+                    type: 'CHART',
+                    showCheckbox: true,
+                  },
+                ],
+              },
+            ],
+          },
+        ],
+      },
+    ];
+
+    it('root level tab scope', () => {
+      const checkedChartIds = [106];
+      expect(
+        getFilterScopeFromNodesTree({
+          filterKey: '107_region',
+          nodes,
+          checkedChartIds,
+        }),
+      ).toEqual({
+        scope: ['TAB-Rb5aaqKWgG'],
+        immune: [],
+      });
+    });
+
+    it('global scope', () => {
+      const checkedChartIds = [106, 104, 101, 102, 103, 105];
+      expect(
+        getFilterScopeFromNodesTree({
+          filterKey: '107_country_name',
+          nodes,
+          checkedChartIds,
+        }),
+      ).toEqual({
+        scope: ['ROOT_ID'],
+        immune: [108],
+      });
+    });
+
+    it('row level tab scope', () => {
+      const checkedChartIds = [103, 105];
+      expect(
+        getFilterScopeFromNodesTree({
+          filterKey: '108___time_range',
+          nodes,
+          checkedChartIds,
+        }),
+      ).toEqual({
+        scope: ['TAB-E4mJaZ-uQM'],
+        immune: [],
+      });
+    });
+
+    it('mixed row level and root level scope', () => {
+      const checkedChartIds = [103, 105, 106];
+      expect(
+        getFilterScopeFromNodesTree({
+          filterKey: '107_region',
+          nodes,
+          checkedChartIds,
+        }),
+      ).toEqual({
+        scope: ['TAB-Rb5aaqKWgG', 'TAB-E4mJaZ-uQM'],
+        immune: [],
+      });
+    });
+  });
+});
diff --git a/superset/assets/src/dashboard/util/getFilterScopeFromNodesTree.js 
b/superset/assets/src/dashboard/util/getFilterScopeFromNodesTree.js
new file mode 100644
index 0000000..9ec328b
--- /dev/null
+++ b/superset/assets/src/dashboard/util/getFilterScopeFromNodesTree.js
@@ -0,0 +1,132 @@
+/**
+ * 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 { isEmpty } from 'lodash';
+import { CHART_TYPE, TAB_TYPE } from './componentTypes';
+import { getChartIdAndColumnFromFilterKey } from './getDashboardFilterKey';
+
+function getTabChildrenScope({
+  tabScopes,
+  parentNodeValue,
+  forceAggregate = false,
+}) {
+  // if all sub-tabs are in scope, or forceAggregate =  true
+  // aggregate scope to parentNodeValue
+  if (
+    forceAggregate ||
+    Object.entries(tabScopes).every(
+      ([key, { scope }]) => scope.length && key === scope[0],
+    )
+  ) {
+    return {
+      scope: [parentNodeValue],
+      immune: [].concat(
+        ...Object.values(tabScopes).map(({ immune }) => immune),
+      ),
+    };
+  }
+
+  const componentsInScope = Object.values(tabScopes).filter(
+    ({ scope }) => scope && scope.length,
+  );
+  const scopeValue = [].concat(...componentsInScope.map(({ scope }) => scope));
+  const immuneValue = [].concat(
+    ...componentsInScope.map(({ immune }) => immune),
+  );
+
+  return {
+    scope: scopeValue,
+    immune: immuneValue,
+  };
+}
+
+function traverse({ currentNode = {}, filterId, checkedChartIds = [] }) {
+  if (!currentNode) {
+    return {};
+  }
+
+  const { value: currentValue, children } = currentNode;
+  const chartChildren = children.filter(({ type }) => type === CHART_TYPE);
+  const tabChildren = children.filter(({ type }) => type === TAB_TYPE);
+
+  const chartsImmune = chartChildren
+    .filter(
+      ({ value }) => filterId !== value && !checkedChartIds.includes(value),
+    )
+    .map(({ value }) => value);
+  const tabScopes = tabChildren.reduce((map, child) => {
+    const { value: tabValue } = child;
+    return {
+      ...map,
+      [tabValue]: traverse({
+        currentNode: child,
+        filterId,
+        checkedChartIds,
+      }),
+    };
+  }, {});
+
+  // if any chart type child is in scope,
+  // no matter has tab children or not, current node should be scope
+  if (
+    !isEmpty(chartChildren) &&
+    chartChildren.some(({ value }) => checkedChartIds.includes(value))
+  ) {
+    if (isEmpty(tabChildren)) {
+      return { scope: [currentValue], immune: chartsImmune };
+    }
+
+    const { scope, immune } = getTabChildrenScope({
+      tabScopes,
+      parentNodeValue: currentValue,
+      forceAggregate: true,
+    });
+    return {
+      scope,
+      immune: chartsImmune.concat(immune),
+    };
+  }
+
+  // has tab children but only some sub-tab in scope
+  if (!isEmpty(tabChildren)) {
+    return getTabChildrenScope({ tabScopes, parentNodeValue: currentValue });
+  }
+
+  // no tab children and no chart children in scope
+  return {
+    scope: [],
+    immune: chartsImmune,
+  };
+}
+
+export default function getFilterScopeFromNodesTree({
+  filterKey,
+  nodes = [],
+  checkedChartIds = [],
+}) {
+  const { chartId } = getChartIdAndColumnFromFilterKey(filterKey);
+  if (nodes.length) {
+    return traverse({
+      currentNode: nodes[0],
+      filterId: chartId,
+      checkedChartIds,
+    });
+  }
+
+  return {};
+}

Reply via email to