You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@superset.apache.org by GitBox <gi...@apache.org> on 2019/11/13 18:13:28 UTC

[GitHub] [incubator-superset] graceguo-supercat opened a new pull request #8404: [WIP][dashboard scoped filter] part 1: scope selector modal

graceguo-supercat opened a new pull request #8404: [WIP][dashboard scoped filter] part 1: scope selector modal
URL: https://github.com/apache/incubator-superset/pull/8404
 
 
   ### CATEGORY
   
   - [ ] Bug Fix
   - [x] Enhancement (new features, refinement)
   - [ ] Refactor
   - [ ] Add tests
   - [ ] Build / Development Environment
   - [ ] Documentation
   
   ### SUMMARY
   This is part 1 for Dashboard Scoped Filter project. This PR is for a new UI module: **filter scope selector modal**. It covers the UI/UX that display/select scope (tabs and charts) for a filter field. Update dashboard redux state and persist filter scope settings to backend, will be covered in another PR.
   
   Superset dashboard stores layout data in a tree structure. This layout structure always contains a **root** component. A root component will have a grid component (for dashboard without tabs) or a root-level tabs components as its children. In the dashboard, every UI component (tabs, row, column, and chart, etc) is a **tree node**. For example:
   ![61979193-0da82280-afa8-11e9-9735-cd5c4435cc1e](https://user-images.githubusercontent.com/27990562/67975697-d6ae6200-fbd1-11e9-8931-4eac27c198d6.jpg)
   We can think A is root component, leaves(K,L, F, G, M, I, J) are chart components, and the rest can be container (like row, column or tabs) components.
   
   With the growing size of the dashboard, user may want to apply one dashboard filter to some of charts in dashboard, and one filter apply to another set of charts. A very common use case is user groups similar charts in different tabs, and make a filter only applicable for this group. Currently the way to set filter's scope is not very easy to use:
   <img width="1140" alt="Screen_Shot_2019-10-16_at_9_49_54_AM" src="https://user-images.githubusercontent.com/27990562/66944436-00785e00-f002-11e9-81c1-5b16aa6ba6ae.png">
   
   This PR introduced a new UI component: filter scope selector.
   
   - **left panel**: All filter_box in dashboard and their filter fields. There is also a toggle link to switch between single-edit mode or multi-edit mode.
   - **right panel**: show dashboard layout in the tree structure. But we hide row/column container, and group charts into its tab parent. If user have nested tabs containers, we will show all the nested tabs structure from chart to dashboard root component. We show a checkbox for each of chart and tab, user can click to select or deselect single or multiple charts. 
   
   When user clicks the `Save` button at the bottom of the modal, we will **aggregate** the checked chart ids **into _scope_ object** and update dashboard filters state. The algorithm for this aggregation will be covered in another PR. 
   
   #### Features:
   **1. single-edit mode, edit one filter field**
   ![TXAQC4vq8M](https://user-images.githubusercontent.com/27990562/66944581-4fbe8e80-f002-11e9-98ae-8e23cbbb6b6e.gif)
   
   **2. multi-edit mode, edit all selected filter fields:**
   ![NVVOnnHnLc](https://user-images.githubusercontent.com/27990562/66944819-c9567c80-f002-11e9-9ed7-c3980b922bed.gif)
   
   **3. Toggle any filter field in multi-edit mode**
   ![dY1ROPA9ck](https://user-images.githubusercontent.com/27990562/67745142-b2d7fa00-f9e0-11e9-9add-5cec7dc4fda7.gif)
   
   **4. search chart name and set scope**
   ![71qKzTDcmu](https://user-images.githubusercontent.com/27990562/66946004-e4c28700-f004-11e9-8ce3-6d80aadae7f3.gif)
   
   
   ### Implementation
   
   Filter scope selector has following UI components:
   - Container component: `src/dashboard/containers/FilterScope.jsx`
   - modal trigger: `src/dashboard/components/filterscope/FilterScopeModal.jsx`
   - core function UI component: `src/dashboard/components/filterscope/FilterScopeSelector.jsx`
   - checkbox tree component in left pane: `FilterFieldTree.jsx`
   recursive traversal renderer for each filter field tree node: `renderFilterFieldTreeNodes.jsx`
   simple UI component for filter filed item: `FilterFieldItem.jsx`
   
   - checkbox tree component in right pane:  `FilterScopeTree.jsx`
   recursive traversal renderer for each filter scope tree node: `renderFilterScopeTreeNodes.jsx`
   
   - util functions:
   
   `getFilterFieldNodesTree`: build filter field tree from dashboard filters redux state.
   `getFilterScopeNodesTree`: build filter scope tree from dashboard layout.
   
   #### Tree and tree nodes
   We used [a 3rd party component](https://github.com/jakezatecky/react-checkbox-tree) to render left panel filter field selector and right panel scope selector. It best matched our layout data structure, and offers very natural and convenient user experience like single selection, group selection, expand-on-click, etc. 
   
   According to [this API](https://github.com/jakezatecky/react-checkbox-tree#properties), a`CheckboxTree` component needs following props:
   ```
   // the original data to be rendered in `CheckboxTree`. The data should be in tree structure. Since js doesn't have build-in Tree data structure, we use array of node object.
   // for filter scope tree, it is full list of the dashboard layout (only have tabs and chart components), 
   // for filter fields tree, it is all dashboard filter box and its fields.
   nodes: PropTypes.arrayOf(filterScopeSelectorTreeNodePropShape).isRequired,
   
   // when user typed keywords in search box, right pane will only show matched charts and all their parent tabs. Only used by filter scope tree component.
   nodesFiltered: PropTypes.arrayOf(filterScopeSelectorTreeNodePropShape).isRequired,
   
   // An array of  node values. `CheckboxTree` component will show these node as checked.
   checked: PropTypes.arrayOf(
       PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
     ).isRequired, 
   
   // An array of node values. `CheckboxTree` component will show these node as expanded tree nodes. 
   expanded: PropTypes.arrayOf(
       PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
     ).isRequired
   ```
   
   For filter field tree, the tree node data is:
   ```
   {
     value: filter key.
     label: customized column label or column name for the chosen filter field.
     children: array of children node
   }
   ``` 
   For filter scope tree, the tree node data is:
   ```
   {
     value: chart id or tab component id
     label: chart name or tab title
     children: array of children node
   }
   ``` 
   
   #### Local state in the filter scope selector modal
   For each filter filed, we construct a unique filter key which is composed of filter_box's chart id and filter's column name: _`chartId_columnName`_
   
   `FilterScopeSelector` component uses following data to maintain the **current state in the modal:**
   
   - `showSelector`: as long as dashboard has one or more filter, we show filter scope selector UI. otherwise, show message says no filter in the dashboard.
   - `filterFieldNodes`: filter fields tree object.
   - `filterScopeMap`: a map for filter scope selections. in each entry, key is filter key, value is filter scope tree object for a filter field.
   - `checkedFilterFields`: array of all chosen filter key(s) in the left pane.
   
   Based on the chosen filter keys from left pane, we show the filter scope tree in the right pane, which memorize the expanded tabs and selected charts. If all charts under the tab are selected, tab will show **checked** state in its checkbox. If some of the charts under the tab are selected, tab will show **half checked** state. And if none of the charts are selected, tab will show a **empty** state for its checkbox.
   
   
   ### TEST PLAN
   Manual test.
   
   ### ADDITIONAL INFORMATION
   <!--- Check any relevant boxes with "x" -->
   <!--- HINT: Include "Fixes #nnn" if you are fixing an existing issue -->
   - [ ] Has associated issue:
   - [X] Changes UI
   - [ ] Requires DB Migration.
   - [ ] Confirm DB Migration upgrade and downgrade tested.
   - [ ] Introduces new feature or API
   - [ ] Removes existing feature or API
   
   ### REVIEWERS
   @etr2460 @williaster @mistercrunch @kenchendesign

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org