From 8bb3de3037f9b78e54285a3db7d190d4c22a84b0 Mon Sep 17 00:00:00 2001
From: Dominik Prokop <dominik.prokop@grafana.com>
Date: Wed, 16 Feb 2022 05:16:25 -0800
Subject: [PATCH] Analytics: Collect information about queries reordering
 (#45392)

---
 .../QueryOperationRow/QueryOperationRow.tsx   | 23 +++++++++++++-
 .../query/components/QueryEditorRows.tsx      | 31 ++++++++++++++++---
 2 files changed, 49 insertions(+), 5 deletions(-)

diff --git a/public/app/core/components/QueryOperationRow/QueryOperationRow.tsx b/public/app/core/components/QueryOperationRow/QueryOperationRow.tsx
index 146b21f9e68..4004424e07f 100644
--- a/public/app/core/components/QueryOperationRow/QueryOperationRow.tsx
+++ b/public/app/core/components/QueryOperationRow/QueryOperationRow.tsx
@@ -4,6 +4,7 @@ import { GrafanaTheme } from '@grafana/data';
 import { css, cx } from '@emotion/css';
 import { useUpdateEffect } from 'react-use';
 import { Draggable } from 'react-beautiful-dnd';
+import { reportInteraction } from '@grafana/runtime';
 
 interface QueryOperationRowProps {
   index: number;
@@ -47,6 +48,24 @@ export const QueryOperationRow: React.FC<QueryOperationRowProps> = ({
     setIsContentVisible(!isContentVisible);
   }, [isContentVisible, setIsContentVisible]);
 
+  const reportDragMousePosition = useCallback((e) => {
+    // When drag detected react-beautiful-dnd will preventDefault the event
+    // Ref: https://github.com/atlassian/react-beautiful-dnd/blob/master/docs/guides/how-we-use-dom-events.md#a-mouse-drag-has-started-and-the-user-is-now-dragging
+    if (e.defaultPrevented) {
+      const rect = e.currentTarget.getBoundingClientRect();
+      var x = e.clientX - rect.left;
+      var y = e.clientY - rect.top;
+
+      // report relative mouse position within the header element
+      reportInteraction('query_row_reorder_drag_position', {
+        x: x / rect.width,
+        y: y / rect.height,
+        width: rect.width,
+        height: rect.height,
+      });
+    }
+  }, []);
+
   useUpdateEffect(() => {
     if (isContentVisible) {
       if (onOpen) {
@@ -106,7 +125,9 @@ export const QueryOperationRow: React.FC<QueryOperationRowProps> = ({
           return (
             <>
               <div ref={provided.innerRef} className={styles.wrapper} {...provided.draggableProps}>
-                <div {...dragHandleProps}>{rowHeader}</div>
+                <div {...dragHandleProps} onMouseMove={reportDragMousePosition}>
+                  {rowHeader}
+                </div>
                 {isContentVisible && <div className={styles.content}>{children}</div>}
               </div>
             </>
diff --git a/public/app/features/query/components/QueryEditorRows.tsx b/public/app/features/query/components/QueryEditorRows.tsx
index 5786b0149e5..575569fc59c 100644
--- a/public/app/features/query/components/QueryEditorRows.tsx
+++ b/public/app/features/query/components/QueryEditorRows.tsx
@@ -11,8 +11,8 @@ import {
   PanelData,
 } from '@grafana/data';
 import { QueryEditorRow } from './QueryEditorRow';
-import { DragDropContext, Droppable, DropResult } from 'react-beautiful-dnd';
-import { getDataSourceSrv } from '@grafana/runtime';
+import { DragDropContext, DragStart, Droppable, DropResult } from 'react-beautiful-dnd';
+import { getDataSourceSrv, reportInteraction } from '@grafana/runtime';
 
 interface Props {
   // The query configuration
@@ -81,8 +81,18 @@ export class QueryEditorRows extends PureComponent<Props> {
     );
   }
 
+  onDragStart = (result: DragStart) => {
+    const { queries, dsSettings } = this.props;
+
+    reportInteraction('query_row_reorder_started', {
+      startIndex: result.source.index,
+      numberOfQueries: queries.length,
+      datasourceType: dsSettings.type,
+    });
+  };
+
   onDragEnd = (result: DropResult) => {
-    const { queries, onQueriesChange } = this.props;
+    const { queries, onQueriesChange, dsSettings } = this.props;
 
     if (!result || !result.destination) {
       return;
@@ -91,6 +101,12 @@ export class QueryEditorRows extends PureComponent<Props> {
     const startIndex = result.source.index;
     const endIndex = result.destination.index;
     if (startIndex === endIndex) {
+      reportInteraction('query_row_reorder_canceled', {
+        startIndex,
+        endIndex,
+        numberOfQueries: queries.length,
+        datasourceType: dsSettings.type,
+      });
       return;
     }
 
@@ -98,13 +114,20 @@ export class QueryEditorRows extends PureComponent<Props> {
     const [removed] = update.splice(startIndex, 1);
     update.splice(endIndex, 0, removed);
     onQueriesChange(update);
+
+    reportInteraction('query_row_reorder_ended', {
+      startIndex,
+      endIndex,
+      numberOfQueries: queries.length,
+      datasourceType: dsSettings.type,
+    });
   };
 
   render() {
     const { dsSettings, data, queries, app, history, eventBus } = this.props;
 
     return (
-      <DragDropContext onDragEnd={this.onDragEnd}>
+      <DragDropContext onDragStart={this.onDragStart} onDragEnd={this.onDragEnd}>
         <Droppable droppableId="transformations-list" direction="vertical">
           {(provided) => {
             return (