From 8c767e9fae46f2d2bbacc98a9d8f9af568de5518 Mon Sep 17 00:00:00 2001
From: Tom Robinson <tlrobinson@gmail.com>
Date: Mon, 16 Apr 2018 23:52:36 -0700
Subject: [PATCH] Fix table header drill, and flow types

---
 frontend/interfaces/underscore.js             |  4 ++
 .../components/TableInteractive.css           |  2 +-
 .../components/TableInteractive.jsx           | 65 ++++++++++++++-----
 3 files changed, 52 insertions(+), 19 deletions(-)

diff --git a/frontend/interfaces/underscore.js b/frontend/interfaces/underscore.js
index b66b10caa1e..f62b3031196 100644
--- a/frontend/interfaces/underscore.js
+++ b/frontend/interfaces/underscore.js
@@ -10,6 +10,10 @@ declare module "underscore" {
     list: ?(T[]),
     predicate: (val: T) => boolean,
   ): number;
+  declare function findLastIndex<T>(
+    list: ?(T[]),
+    predicate: (val: T) => boolean,
+  ): number;
 
   declare function clone<T>(obj: T): T;
 
diff --git a/frontend/src/metabase/visualizations/components/TableInteractive.css b/frontend/src/metabase/visualizations/components/TableInteractive.css
index 79d44f33d60..07511fb6817 100644
--- a/frontend/src/metabase/visualizations/components/TableInteractive.css
+++ b/frontend/src/metabase/visualizations/components/TableInteractive.css
@@ -92,5 +92,5 @@
 
 .TableInteractive .TableInteractive-cellWrapper.tether-enabled {
   background-color: var(--brand-color);
-  color: white;
+  color: white !important;
 }
diff --git a/frontend/src/metabase/visualizations/components/TableInteractive.jsx b/frontend/src/metabase/visualizations/components/TableInteractive.jsx
index 7a8e6fbfa58..5930688ebec 100644
--- a/frontend/src/metabase/visualizations/components/TableInteractive.jsx
+++ b/frontend/src/metabase/visualizations/components/TableInteractive.jsx
@@ -59,6 +59,17 @@ type Props = VisualizationProps & {
 type State = {
   columnWidths: number[],
   contentWidths: ?(number[]),
+
+  dragColIndex?: ?number,
+  dragColStyle?: ?{ [key: string]: any },
+  dragColNewLefts?: ?(number[]),
+  dragColNewIndex?: ?number,
+  columnPositions?: ?({
+    left: number,
+    right: number,
+    center: number,
+    width: number,
+  }[]),
 };
 
 type CellRendererProps = {
@@ -83,6 +94,7 @@ export default class TableInteractive extends Component {
 
   header: GridComponent;
   grid: GridComponent;
+  headerRefs: HTMLElement[];
 
   constructor(props: Props) {
     super(props);
@@ -92,6 +104,7 @@ export default class TableInteractive extends Component {
       contentWidths: null,
     };
     this.columnHasResized = {};
+    this.headerRefs = [];
   }
 
   static propTypes = {
@@ -315,19 +328,21 @@ export default class TableInteractive extends Component {
     );
   };
 
-  getDragColNewIndex(data) {
+  getDragColNewIndex(data: { x: number }) {
     const { columnPositions, dragColNewIndex, dragColStyle } = this.state;
-    if (data.x < 0) {
-      const left = dragColStyle.left + data.x;
-      const index = _.findIndex(columnPositions, p => left < p.center);
-      if (index >= 0) {
-        return index;
-      }
-    } else if (data.x > 0) {
-      const right = dragColStyle.left + dragColStyle.width + data.x;
-      const index = _.findLastIndex(columnPositions, p => right > p.center);
-      if (index >= 0) {
-        return index;
+    if (dragColStyle) {
+      if (data.x < 0) {
+        const left = dragColStyle.left + data.x;
+        const index = _.findIndex(columnPositions, p => left < p.center);
+        if (index >= 0) {
+          return index;
+        }
+      } else if (data.x > 0) {
+        const right = dragColStyle.left + dragColStyle.width + data.x;
+        const index = _.findLastIndex(columnPositions, p => right > p.center);
+        if (index >= 0) {
+          return index;
+        }
       }
     }
     return dragColNewIndex;
@@ -348,14 +363,16 @@ export default class TableInteractive extends Component {
     });
   }
 
-  getNewColumnLefts(dragColNewIndex) {
+  getNewColumnLefts(dragColNewIndex: number) {
     const { dragColIndex, columnPositions } = this.state;
     const { cols } = this.props.data;
     const indexes = cols.map((col, index) => index);
+    // $FlowFixMe: inner indexes.splice should always return an index
     indexes.splice(dragColNewIndex, 0, indexes.splice(dragColIndex, 1)[0]);
     let left = 0;
     const lefts = indexes.map(index => {
       const thisLeft = left;
+      // $FlowFixMe: we know columnPositions[index] isn't null because onDrag is called after onStart
       left += columnPositions[index].width;
       return { index, left: thisLeft };
     });
@@ -363,7 +380,7 @@ export default class TableInteractive extends Component {
     return lefts.map(p => p.left);
   }
 
-  getColumnLeft(style, index) {
+  getColumnLeft(style: any, index: number) {
     const { dragColNewIndex, dragColNewLefts } = this.state;
     if (dragColNewIndex != null && dragColNewLefts) {
       return dragColNewLefts[index];
@@ -423,7 +440,7 @@ export default class TableInteractive extends Component {
         }}
         onDrag={(e, data) => {
           const newIndex = this.getDragColNewIndex(data);
-          if (newIndex !== this.state.dragColNewIndex) {
+          if (newIndex != null && newIndex !== this.state.dragColNewIndex) {
             this.setState({
               dragColNewIndex: newIndex,
               dragColNewLefts: this.getNewColumnLefts(newIndex),
@@ -431,10 +448,22 @@ export default class TableInteractive extends Component {
           }
         }}
         onStop={(e, d) => {
-          DRAG_COUNTER++;
           const { dragColIndex, dragColNewIndex } = this.state;
-          if (dragColIndex !== dragColNewIndex) {
+          DRAG_COUNTER++;
+          if (
+            dragColIndex != null &&
+            dragColNewIndex != null &&
+            dragColIndex !== dragColNewIndex
+          ) {
             this.onColumnReorder(dragColIndex, dragColNewIndex);
+          } else if (Math.abs(d.x) + Math.abs(d.y) < 5) {
+            // in setTimeout since headers will be rerendered due to DRAG_COUNTER changing
+            setTimeout(() => {
+              onVisualizationClick({
+                ...clicked,
+                element: this.headerRefs[columnIndex],
+              });
+            });
           }
           this.setState({
             columnPositions: null,
@@ -446,7 +475,7 @@ export default class TableInteractive extends Component {
         }}
       >
         <div
-          key={key}
+          ref={e => (this.headerRefs[columnIndex] = e)}
           style={{
             ...style,
             overflow: "visible" /* ensure resize handle is visible */,
-- 
GitLab