From fa47090faa9bcbd268a4b92b55057afe2182aabb Mon Sep 17 00:00:00 2001 From: Julian Rojas Valvo Date: Tue, 11 Jul 2023 11:45:34 -0400 Subject: [PATCH 1/6] feat: Added button to execute all query cells in a datadoc after the current cell --- querybook/server/datasources/datadoc.py | 3 +- querybook/server/tasks/run_datadoc.py | 3 +- .../DataDocQueryCell/DataDocQueryCell.tsx | 2 + .../QueryCellRunAllFromCellButton.tsx | 89 +++++++++++++++++++ .../QueryComposer/QueryComposer.tsx | 2 + .../QueryRunButton/QueryRunButton.tsx | 14 +++ querybook/webapp/const/analytics.ts | 1 + querybook/webapp/resource/dataDoc.ts | 7 +- querybook/webapp/ui/Icon/LucideIcons.ts | 2 + 9 files changed, 120 insertions(+), 3 deletions(-) create mode 100644 querybook/webapp/components/QueryCellRunAllFromCellButton/QueryCellRunAllFromCellButton.tsx diff --git a/querybook/server/datasources/datadoc.py b/querybook/server/datasources/datadoc.py index 618829437..99bedb31b 100644 --- a/querybook/server/datasources/datadoc.py +++ b/querybook/server/datasources/datadoc.py @@ -380,7 +380,7 @@ def run_data_doc(id): @register("/datadoc//run/", methods=["POST"]) -def adhoc_run_data_doc(id, send_notification=False): +def adhoc_run_data_doc(id, start_index=0, send_notification=False): assert_can_write(id) verify_data_doc_permission(id) @@ -403,6 +403,7 @@ def adhoc_run_data_doc(id, send_notification=False): args=[], kwargs={ "doc_id": id, + "start_index": start_index, "user_id": current_user.id, "execution_type": QueryExecutionType.ADHOC.value, "notifications": notifications, diff --git a/querybook/server/tasks/run_datadoc.py b/querybook/server/tasks/run_datadoc.py index 0f109759a..682027d3a 100644 --- a/querybook/server/tasks/run_datadoc.py +++ b/querybook/server/tasks/run_datadoc.py @@ -39,6 +39,7 @@ def run_datadoc(self, *args, **kwargs): def run_datadoc_with_config( self, doc_id, + start_index=0, notifications=[], user_id=None, execution_type=QueryExecutionType.SCHEDULED.value, @@ -56,7 +57,7 @@ def run_datadoc_with_config( return runner_id = user_id if user_id is not None else data_doc.owner_uid - query_cells = data_doc.get_query_cells() + query_cells = (data_doc.get_query_cells())[start_index:] # Create db entry record only for scheduled run if execution_type == QueryExecutionType.SCHEDULED.value: diff --git a/querybook/webapp/components/DataDocQueryCell/DataDocQueryCell.tsx b/querybook/webapp/components/DataDocQueryCell/DataDocQueryCell.tsx index fc62358c6..ed5ef9b45 100644 --- a/querybook/webapp/components/DataDocQueryCell/DataDocQueryCell.tsx +++ b/querybook/webapp/components/DataDocQueryCell/DataDocQueryCell.tsx @@ -708,6 +708,8 @@ class DataDocQueryCellComponent extends React.PureComponent { ? this.handleMetaRowLimitChange : null } + docId={this.props.docId} + index={this.props.queryIndexInDoc} /> {this.getAdditionalDropDownButtonDOM()} diff --git a/querybook/webapp/components/QueryCellRunAllFromCellButton/QueryCellRunAllFromCellButton.tsx b/querybook/webapp/components/QueryCellRunAllFromCellButton/QueryCellRunAllFromCellButton.tsx new file mode 100644 index 000000000..72ae5ec49 --- /dev/null +++ b/querybook/webapp/components/QueryCellRunAllFromCellButton/QueryCellRunAllFromCellButton.tsx @@ -0,0 +1,89 @@ +import React, { useCallback, useMemo, useRef } from 'react'; +import toast from 'react-hot-toast'; + +import { ComponentType, ElementType } from 'const/analytics'; +import { useQueryCells } from 'hooks/dataDoc/useQueryCells'; +import { useMakeSelector } from 'hooks/redux/useMakeSelector'; +import { trackClick } from 'lib/analytics'; +import { sendConfirm } from 'lib/querybookUI'; +import { makeLatestQueryExecutionsSelector } from 'redux/queryExecutions/selector'; +import { DataDocResource } from 'resource/dataDoc'; + +import { AsyncButton } from '../../ui/AsyncButton/AsyncButton'; +import { Icon } from '../../ui/Icon/Icon'; +import { DataDocRunAllButtonConfirm } from '../DataDocRightSidebar/DataDocRunAllButtonConfirm'; + +interface IProps { + docId: number; + enabled: boolean; + index: number; +} + +export const QueryCellRunAllFromCellButton: React.FunctionComponent = ({ + docId, + enabled, + index, +}) => { + let queryCells = useQueryCells(docId); + const queryTitle = queryCells[index].meta.title; + const title = + queryTitle == null || queryTitle === '' + ? 'Query #' + (index + 1).toString() + : queryTitle; + queryCells = queryCells.slice(index); + + const latestQueryExecutions = useMakeSelector( + makeLatestQueryExecutionsSelector, + queryCells.map((c) => c.id) ?? [] + ); + const hasQueryRunning = useMemo( + () => latestQueryExecutions.some((q) => q.status < 3), + [latestQueryExecutions] + ); + const notification = useRef(true); + + const onRunAll = useCallback(() => { + sendConfirm({ + header: 'Run Cells From ' + title, + message: ( + { + notification.current = value; + }} + hasQueryRunning={hasQueryRunning} + queryCells={queryCells} + /> + ), + onConfirm: () => { + trackClick({ + component: ComponentType.DATADOC_PAGE, + element: ElementType.RUN_ALL_FROM_CELL_BUTTON, + }); + toast.promise( + DataDocResource.run(docId, notification.current, index), + { + loading: null, + success: 'DataDoc execution started!', + error: 'Failed to start the execution', + } + ); + }, + confirmText: 'Run', + }); + return null; + }, [docId, hasQueryRunning, notification, queryCells]); + + return ( + enabled && ( + } + aria-label={'Run All Cells From Here'} + data-balloon-pos={'up'} + color={'accent'} + onClick={onRunAll} + style={{ width: '60px' }} + /> + ) + ); +}; diff --git a/querybook/webapp/components/QueryComposer/QueryComposer.tsx b/querybook/webapp/components/QueryComposer/QueryComposer.tsx index 10b43e9f6..7a191915c 100644 --- a/querybook/webapp/components/QueryComposer/QueryComposer.tsx +++ b/querybook/webapp/components/QueryComposer/QueryComposer.tsx @@ -637,6 +637,8 @@ const QueryComposer: React.FC = () => { runButtonTooltipPos={'down'} rowLimit={rowLimit} onRowLimitChange={setRowLimit} + docId={null} + index={null} /> ); diff --git a/querybook/webapp/components/QueryRunButton/QueryRunButton.tsx b/querybook/webapp/components/QueryRunButton/QueryRunButton.tsx index 116ddae21..5c2e1f15e 100644 --- a/querybook/webapp/components/QueryRunButton/QueryRunButton.tsx +++ b/querybook/webapp/components/QueryRunButton/QueryRunButton.tsx @@ -24,6 +24,8 @@ import { SearchBar } from 'ui/SearchBar/SearchBar'; import { StatusIcon } from 'ui/StatusIcon/StatusIcon'; import { Tag } from 'ui/Tag/Tag'; +import { QueryCellRunAllFromCellButton } from '../QueryCellRunAllFromCellButton/QueryCellRunAllFromCellButton'; + import './QueryRunButton.scss'; const EXECUTE_QUERY_SHORTCUT = getShortcutSymbols( @@ -38,6 +40,9 @@ interface IQueryRunButtonProps extends IQueryEngineSelectorProps { rowLimit?: number; onRunClick: () => any; onRowLimitChange?: (rowLimit: number) => void; + + docId: number; + index: number; } export interface IQueryRunButtonHandles { @@ -60,6 +65,8 @@ export const QueryRunButton = React.forwardRef< onEngineIdSelect, rowLimit, onRowLimitChange, + docId, + index, }, ref ) => { @@ -115,6 +122,13 @@ export const QueryRunButton = React.forwardRef< /> {rowLimitDOM} {runButtonDOM} + {docId != null && ( + + )} ); } diff --git a/querybook/webapp/const/analytics.ts b/querybook/webapp/const/analytics.ts index 0a4cae7bf..61f9d13e3 100644 --- a/querybook/webapp/const/analytics.ts +++ b/querybook/webapp/const/analytics.ts @@ -84,6 +84,7 @@ export enum ElementType { TEMPLATE_CONFIG_BUTTON = 'TEMPLATE_CONFIG_BUTTON', RENDER_QUERY_BUTTON = 'RENDER_QUERY_BUTTON', CREATE_DATADOC_BUTTON = 'CREATE_DATADOC_BUTTON', + RUN_ALL_FROM_CELL_BUTTON = 'RUN_ALL_FROM_CELL_BUTTON', // Table detail view OVERVIEW_TABLE_TAB = 'OVERVIEW_TABLE_TAB', diff --git a/querybook/webapp/resource/dataDoc.ts b/querybook/webapp/resource/dataDoc.ts index f6b2cc038..6cbd71003 100644 --- a/querybook/webapp/resource/dataDoc.ts +++ b/querybook/webapp/resource/dataDoc.ts @@ -101,8 +101,13 @@ export const DataDocResource = { }>(`/favorite_data_doc/${docId}/`), unfavorite: (docId: number) => ds.delete(`/favorite_data_doc/${docId}/`), - run: (docId: number, sendNotification: boolean = false) => + run: ( + docId: number, + sendNotification: boolean = false, + start_index: number = 0 + ) => ds.save(`/datadoc/${docId}/run/`, { + start_index, send_notification: sendNotification, }), diff --git a/querybook/webapp/ui/Icon/LucideIcons.ts b/querybook/webapp/ui/Icon/LucideIcons.ts index 7d53f820e..8df91f88b 100644 --- a/querybook/webapp/ui/Icon/LucideIcons.ts +++ b/querybook/webapp/ui/Icon/LucideIcons.ts @@ -47,6 +47,7 @@ import { ExternalLink, Eye, EyeOff, + FastForward, File, FileOutput, FileText, @@ -161,6 +162,7 @@ const AllLucideIcons = { EyeOff, Expand, ExternalLink, + FastForward, File, FileOutput, FileText, From 0925d12fc4e27af06b8a86bc3efea5053308a446 Mon Sep 17 00:00:00 2001 From: jvalvo Date: Wed, 16 Aug 2023 14:01:17 -0700 Subject: [PATCH 2/6] feat: added new button under dropdown --- .../components/DataDocQueryCell/DataDocQueryCell.tsx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/querybook/webapp/components/DataDocQueryCell/DataDocQueryCell.tsx b/querybook/webapp/components/DataDocQueryCell/DataDocQueryCell.tsx index ed5ef9b45..73ff448c0 100644 --- a/querybook/webapp/components/DataDocQueryCell/DataDocQueryCell.tsx +++ b/querybook/webapp/components/DataDocQueryCell/DataDocQueryCell.tsx @@ -545,6 +545,14 @@ class DataDocQueryCellComponent extends React.PureComponent { tooltipPos: 'left', }); + additionalButtons.push({ + name: 'Run From Current Cell', + onClick: null, + icon: 'FastForward', + tooltip: 'Run all cells in the current datadoc after this cell', + tooltipPos: 'left', + }); + additionalButtons.push({ name: queryCollapsed ? 'Show Query' : 'Hide Query', onClick: this.toggleQueryCollapsing.bind(this, !queryCollapsed), From 0ca12528c322bec0429d1c3402fc897aec3eda9b Mon Sep 17 00:00:00 2001 From: jvalvo Date: Thu, 24 Aug 2023 16:55:46 -0700 Subject: [PATCH 3/6] feat: moved run from any cell functionality to drop down menu --- .../components/DataDocCell/DataDocCell.tsx | 69 +++++++++++++- .../DataDocQueryCell/DataDocQueryCell.tsx | 3 +- .../QueryCellRunAllFromCellButton.tsx | 89 ------------------- .../QueryRunButton/QueryRunButton.tsx | 9 -- 4 files changed, 70 insertions(+), 100 deletions(-) delete mode 100644 querybook/webapp/components/QueryCellRunAllFromCellButton/QueryCellRunAllFromCellButton.tsx diff --git a/querybook/webapp/components/DataDocCell/DataDocCell.tsx b/querybook/webapp/components/DataDocCell/DataDocCell.tsx index 9cc8d93aa..8ecf4d59d 100644 --- a/querybook/webapp/components/DataDocCell/DataDocCell.tsx +++ b/querybook/webapp/components/DataDocCell/DataDocCell.tsx @@ -1,5 +1,11 @@ import clsx from 'clsx'; -import React, { useCallback, useContext, useEffect, useMemo } from 'react'; +import React, { + useCallback, + useContext, + useEffect, + useMemo, + useRef, +} from 'react'; import { useSelector } from 'react-redux'; import { DataDocCellControl } from 'components/DataDoc/DataDocCellControl'; @@ -22,6 +28,12 @@ import { getShareUrl } from 'lib/data-doc/data-doc-utils'; import * as dataDocActions from 'redux/dataDoc/action'; import * as dataDocSelectors from 'redux/dataDoc/selector'; import { IStoreState } from 'redux/store/types'; +import { useQueryCells } from '../../hooks/dataDoc/useQueryCells'; +import { makeLatestQueryExecutionsSelector } from '../../redux/queryExecutions/selector'; +import { sendConfirm } from '../../lib/querybookUI'; +import { DataDocRunAllButtonConfirm } from '../DataDocRightSidebar/DataDocRunAllButtonConfirm'; +import toast from 'react-hot-toast'; +import { DataDocResource } from '../../resource/dataDoc'; import './DataDocCell.scss'; @@ -80,6 +92,60 @@ export const DataDocCell: React.FunctionComponent = fullScreenCellIndex, } = useContext(DataDocContext); + let queryCells = useQueryCells(docId); + const queryTitle = queryCells[index].meta.title; + const title = + queryTitle == null || queryTitle === '' + ? 'Query #' + (index + 1).toString() + : queryTitle; + queryCells = queryCells.slice(index); + + const latestQueryExecutions = useMakeSelector( + makeLatestQueryExecutionsSelector, + queryCells.map((c) => c.id) ?? [] + ); + const hasQueryRunning = useMemo( + () => latestQueryExecutions.some((q) => q.status < 3), + [latestQueryExecutions] + ); + const notification = useRef(true); + + const onRunAll = useCallback(() => { + sendConfirm({ + header: 'Run Cells From ' + title, + message: ( + { + notification.current = value; + }} + hasQueryRunning={hasQueryRunning} + queryCells={queryCells} + /> + ), + onConfirm: () => { + trackClick({ + component: ComponentType.DATADOC_PAGE, + element: ElementType.RUN_ALL_FROM_CELL_BUTTON, + }); + toast.promise( + DataDocResource.run( + docId, + notification.current, + index + ), + { + loading: null, + success: 'DataDoc execution started!', + error: 'Failed to start the execution', + } + ); + }, + confirmText: 'Run', + }); + return null; + }, [docId, hasQueryRunning, notification, queryCells]); + const cellIdtoUid = useMakeSelector( dataDocSelectors.makeDataDocCursorByCellIdSelector, docId @@ -186,6 +252,7 @@ export const DataDocCell: React.FunctionComponent = templatedVariables, isFullScreen, toggleFullScreen, + onRunAll, }; cellDOM = ; } else if (cell.cell_type === 'chart') { diff --git a/querybook/webapp/components/DataDocQueryCell/DataDocQueryCell.tsx b/querybook/webapp/components/DataDocQueryCell/DataDocQueryCell.tsx index 73ff448c0..eb90a71d0 100644 --- a/querybook/webapp/components/DataDocQueryCell/DataDocQueryCell.tsx +++ b/querybook/webapp/components/DataDocQueryCell/DataDocQueryCell.tsx @@ -93,6 +93,7 @@ interface IOwnProps { onUpKeyPressed?: () => any; onDownKeyPressed?: () => any; toggleFullScreen: () => any; + onRunAll: () => any; } type IProps = IOwnProps & StateProps & DispatchProps; @@ -547,7 +548,7 @@ class DataDocQueryCellComponent extends React.PureComponent { additionalButtons.push({ name: 'Run From Current Cell', - onClick: null, + onClick: this.props.onRunAll, icon: 'FastForward', tooltip: 'Run all cells in the current datadoc after this cell', tooltipPos: 'left', diff --git a/querybook/webapp/components/QueryCellRunAllFromCellButton/QueryCellRunAllFromCellButton.tsx b/querybook/webapp/components/QueryCellRunAllFromCellButton/QueryCellRunAllFromCellButton.tsx deleted file mode 100644 index 72ae5ec49..000000000 --- a/querybook/webapp/components/QueryCellRunAllFromCellButton/QueryCellRunAllFromCellButton.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import React, { useCallback, useMemo, useRef } from 'react'; -import toast from 'react-hot-toast'; - -import { ComponentType, ElementType } from 'const/analytics'; -import { useQueryCells } from 'hooks/dataDoc/useQueryCells'; -import { useMakeSelector } from 'hooks/redux/useMakeSelector'; -import { trackClick } from 'lib/analytics'; -import { sendConfirm } from 'lib/querybookUI'; -import { makeLatestQueryExecutionsSelector } from 'redux/queryExecutions/selector'; -import { DataDocResource } from 'resource/dataDoc'; - -import { AsyncButton } from '../../ui/AsyncButton/AsyncButton'; -import { Icon } from '../../ui/Icon/Icon'; -import { DataDocRunAllButtonConfirm } from '../DataDocRightSidebar/DataDocRunAllButtonConfirm'; - -interface IProps { - docId: number; - enabled: boolean; - index: number; -} - -export const QueryCellRunAllFromCellButton: React.FunctionComponent = ({ - docId, - enabled, - index, -}) => { - let queryCells = useQueryCells(docId); - const queryTitle = queryCells[index].meta.title; - const title = - queryTitle == null || queryTitle === '' - ? 'Query #' + (index + 1).toString() - : queryTitle; - queryCells = queryCells.slice(index); - - const latestQueryExecutions = useMakeSelector( - makeLatestQueryExecutionsSelector, - queryCells.map((c) => c.id) ?? [] - ); - const hasQueryRunning = useMemo( - () => latestQueryExecutions.some((q) => q.status < 3), - [latestQueryExecutions] - ); - const notification = useRef(true); - - const onRunAll = useCallback(() => { - sendConfirm({ - header: 'Run Cells From ' + title, - message: ( - { - notification.current = value; - }} - hasQueryRunning={hasQueryRunning} - queryCells={queryCells} - /> - ), - onConfirm: () => { - trackClick({ - component: ComponentType.DATADOC_PAGE, - element: ElementType.RUN_ALL_FROM_CELL_BUTTON, - }); - toast.promise( - DataDocResource.run(docId, notification.current, index), - { - loading: null, - success: 'DataDoc execution started!', - error: 'Failed to start the execution', - } - ); - }, - confirmText: 'Run', - }); - return null; - }, [docId, hasQueryRunning, notification, queryCells]); - - return ( - enabled && ( - } - aria-label={'Run All Cells From Here'} - data-balloon-pos={'up'} - color={'accent'} - onClick={onRunAll} - style={{ width: '60px' }} - /> - ) - ); -}; diff --git a/querybook/webapp/components/QueryRunButton/QueryRunButton.tsx b/querybook/webapp/components/QueryRunButton/QueryRunButton.tsx index 5c2e1f15e..144611785 100644 --- a/querybook/webapp/components/QueryRunButton/QueryRunButton.tsx +++ b/querybook/webapp/components/QueryRunButton/QueryRunButton.tsx @@ -24,8 +24,6 @@ import { SearchBar } from 'ui/SearchBar/SearchBar'; import { StatusIcon } from 'ui/StatusIcon/StatusIcon'; import { Tag } from 'ui/Tag/Tag'; -import { QueryCellRunAllFromCellButton } from '../QueryCellRunAllFromCellButton/QueryCellRunAllFromCellButton'; - import './QueryRunButton.scss'; const EXECUTE_QUERY_SHORTCUT = getShortcutSymbols( @@ -122,13 +120,6 @@ export const QueryRunButton = React.forwardRef< /> {rowLimitDOM} {runButtonDOM} - {docId != null && ( - - )} ); } From c17ba0a7221b2989074b9566eb848e57eb2fcf40 Mon Sep 17 00:00:00 2001 From: jvalvo Date: Fri, 25 Aug 2023 11:23:25 -0700 Subject: [PATCH 4/6] feat: resolving comments --- .../components/DataDocCell/DataDocCell.tsx | 104 +++++++++--------- .../DataDocQueryCell/DataDocQueryCell.tsx | 9 +- .../QueryRunButton/QueryRunButton.tsx | 5 - querybook/webapp/resource/dataDoc.ts | 4 +- 4 files changed, 56 insertions(+), 66 deletions(-) diff --git a/querybook/webapp/components/DataDocCell/DataDocCell.tsx b/querybook/webapp/components/DataDocCell/DataDocCell.tsx index 8ecf4d59d..4f487f6b0 100644 --- a/querybook/webapp/components/DataDocCell/DataDocCell.tsx +++ b/querybook/webapp/components/DataDocCell/DataDocCell.tsx @@ -34,6 +34,7 @@ import { sendConfirm } from '../../lib/querybookUI'; import { DataDocRunAllButtonConfirm } from '../DataDocRightSidebar/DataDocRunAllButtonConfirm'; import toast from 'react-hot-toast'; import { DataDocResource } from '../../resource/dataDoc'; +import { QueryExecutionStatus } from '../../const/queryExecution'; import './DataDocCell.scss'; @@ -61,6 +62,53 @@ function getEstimatedCellHeight(cell: IDataCell) { return 80; } +function useRunAll(docId, index) { + let queryCells = useQueryCells(docId); + queryCells = queryCells.slice(index); + + const latestQueryExecutions = useMakeSelector( + makeLatestQueryExecutionsSelector, + queryCells.map((c) => c.id) ?? [] + ); + const hasQueryRunning = useMemo( + () => latestQueryExecutions.some((q) => QueryExecutionStatus.DONE), + [latestQueryExecutions] + ); + const notification = useRef(true); + + const onRunAll = useCallback(() => { + sendConfirm({ + header: 'Run all cells below', + message: ( + { + notification.current = value; + }} + hasQueryRunning={hasQueryRunning} + queryCells={queryCells} + /> + ), + onConfirm: () => { + trackClick({ + component: ComponentType.DATADOC_PAGE, + element: ElementType.RUN_ALL_FROM_CELL_BUTTON, + }); + toast.promise( + DataDocResource.run(docId, notification.current, index), + { + loading: null, + success: 'DataDoc execution started!', + error: 'Failed to start the execution', + } + ); + }, + confirmText: 'Run', + }); + return null; + }, [docId, hasQueryRunning, notification, queryCells]); +} + // renders cell export const DataDocCell: React.FunctionComponent = React.memo( @@ -92,60 +140,6 @@ export const DataDocCell: React.FunctionComponent = fullScreenCellIndex, } = useContext(DataDocContext); - let queryCells = useQueryCells(docId); - const queryTitle = queryCells[index].meta.title; - const title = - queryTitle == null || queryTitle === '' - ? 'Query #' + (index + 1).toString() - : queryTitle; - queryCells = queryCells.slice(index); - - const latestQueryExecutions = useMakeSelector( - makeLatestQueryExecutionsSelector, - queryCells.map((c) => c.id) ?? [] - ); - const hasQueryRunning = useMemo( - () => latestQueryExecutions.some((q) => q.status < 3), - [latestQueryExecutions] - ); - const notification = useRef(true); - - const onRunAll = useCallback(() => { - sendConfirm({ - header: 'Run Cells From ' + title, - message: ( - { - notification.current = value; - }} - hasQueryRunning={hasQueryRunning} - queryCells={queryCells} - /> - ), - onConfirm: () => { - trackClick({ - component: ComponentType.DATADOC_PAGE, - element: ElementType.RUN_ALL_FROM_CELL_BUTTON, - }); - toast.promise( - DataDocResource.run( - docId, - notification.current, - index - ), - { - loading: null, - success: 'DataDoc execution started!', - error: 'Failed to start the execution', - } - ); - }, - confirmText: 'Run', - }); - return null; - }, [docId, hasQueryRunning, notification, queryCells]); - const cellIdtoUid = useMakeSelector( dataDocSelectors.makeDataDocCursorByCellIdSelector, docId @@ -252,7 +246,7 @@ export const DataDocCell: React.FunctionComponent = templatedVariables, isFullScreen, toggleFullScreen, - onRunAll, + useRunAll, }; cellDOM = ; } else if (cell.cell_type === 'chart') { diff --git a/querybook/webapp/components/DataDocQueryCell/DataDocQueryCell.tsx b/querybook/webapp/components/DataDocQueryCell/DataDocQueryCell.tsx index eb90a71d0..57ff20cef 100644 --- a/querybook/webapp/components/DataDocQueryCell/DataDocQueryCell.tsx +++ b/querybook/webapp/components/DataDocQueryCell/DataDocQueryCell.tsx @@ -93,7 +93,7 @@ interface IOwnProps { onUpKeyPressed?: () => any; onDownKeyPressed?: () => any; toggleFullScreen: () => any; - onRunAll: () => any; + useRunAll: (docId: number, index: number) => any; } type IProps = IOwnProps & StateProps & DispatchProps; @@ -548,7 +548,10 @@ class DataDocQueryCellComponent extends React.PureComponent { additionalButtons.push({ name: 'Run From Current Cell', - onClick: this.props.onRunAll, + onClick: this.props.useRunAll( + this.props.docId, + this.props.queryIndexInDoc + ), icon: 'FastForward', tooltip: 'Run all cells in the current datadoc after this cell', tooltipPos: 'left', @@ -717,8 +720,6 @@ class DataDocQueryCellComponent extends React.PureComponent { ? this.handleMetaRowLimitChange : null } - docId={this.props.docId} - index={this.props.queryIndexInDoc} /> {this.getAdditionalDropDownButtonDOM()} diff --git a/querybook/webapp/components/QueryRunButton/QueryRunButton.tsx b/querybook/webapp/components/QueryRunButton/QueryRunButton.tsx index 144611785..116ddae21 100644 --- a/querybook/webapp/components/QueryRunButton/QueryRunButton.tsx +++ b/querybook/webapp/components/QueryRunButton/QueryRunButton.tsx @@ -38,9 +38,6 @@ interface IQueryRunButtonProps extends IQueryEngineSelectorProps { rowLimit?: number; onRunClick: () => any; onRowLimitChange?: (rowLimit: number) => void; - - docId: number; - index: number; } export interface IQueryRunButtonHandles { @@ -63,8 +60,6 @@ export const QueryRunButton = React.forwardRef< onEngineIdSelect, rowLimit, onRowLimitChange, - docId, - index, }, ref ) => { diff --git a/querybook/webapp/resource/dataDoc.ts b/querybook/webapp/resource/dataDoc.ts index 6cbd71003..3d1973be6 100644 --- a/querybook/webapp/resource/dataDoc.ts +++ b/querybook/webapp/resource/dataDoc.ts @@ -104,10 +104,10 @@ export const DataDocResource = { run: ( docId: number, sendNotification: boolean = false, - start_index: number = 0 + startIndex: number = 0 ) => ds.save(`/datadoc/${docId}/run/`, { - start_index, + startIndex, send_notification: sendNotification, }), From 0aa13466ce0b528f1b2510b903d565cac531e106 Mon Sep 17 00:00:00 2001 From: jvalvo Date: Tue, 12 Sep 2023 11:12:49 -0700 Subject: [PATCH 5/6] feat: consolidated runall code into one react hook, use from run all and from all from here buttons --- .../components/DataDocCell/DataDocCell.tsx | 71 +++---------------- .../DataDocQueryCell/DataDocQueryCell.tsx | 12 ++-- .../DataDocRunAllButton.tsx | 54 +------------- .../DataDocRunAllButtonConfirm.tsx | 27 +++++-- .../hooks/dataDoc/useRunAllFromIndex.tsx | 47 ++++++++++++ querybook/webapp/resource/dataDoc.ts | 2 +- 6 files changed, 88 insertions(+), 125 deletions(-) create mode 100644 querybook/webapp/hooks/dataDoc/useRunAllFromIndex.tsx diff --git a/querybook/webapp/components/DataDocCell/DataDocCell.tsx b/querybook/webapp/components/DataDocCell/DataDocCell.tsx index 4f487f6b0..c04297b81 100644 --- a/querybook/webapp/components/DataDocCell/DataDocCell.tsx +++ b/querybook/webapp/components/DataDocCell/DataDocCell.tsx @@ -1,11 +1,5 @@ import clsx from 'clsx'; -import React, { - useCallback, - useContext, - useEffect, - useMemo, - useRef, -} from 'react'; +import React, { useCallback, useContext, useEffect, useMemo } from 'react'; import { useSelector } from 'react-redux'; import { DataDocCellControl } from 'components/DataDoc/DataDocCellControl'; @@ -28,15 +22,9 @@ import { getShareUrl } from 'lib/data-doc/data-doc-utils'; import * as dataDocActions from 'redux/dataDoc/action'; import * as dataDocSelectors from 'redux/dataDoc/selector'; import { IStoreState } from 'redux/store/types'; -import { useQueryCells } from '../../hooks/dataDoc/useQueryCells'; -import { makeLatestQueryExecutionsSelector } from '../../redux/queryExecutions/selector'; -import { sendConfirm } from '../../lib/querybookUI'; -import { DataDocRunAllButtonConfirm } from '../DataDocRightSidebar/DataDocRunAllButtonConfirm'; -import toast from 'react-hot-toast'; -import { DataDocResource } from '../../resource/dataDoc'; -import { QueryExecutionStatus } from '../../const/queryExecution'; import './DataDocCell.scss'; +import { useRunAllFromIndex } from 'hooks/dataDoc/useRunAllFromIndex'; interface IDataDocCellProps { docId: number; @@ -62,53 +50,6 @@ function getEstimatedCellHeight(cell: IDataCell) { return 80; } -function useRunAll(docId, index) { - let queryCells = useQueryCells(docId); - queryCells = queryCells.slice(index); - - const latestQueryExecutions = useMakeSelector( - makeLatestQueryExecutionsSelector, - queryCells.map((c) => c.id) ?? [] - ); - const hasQueryRunning = useMemo( - () => latestQueryExecutions.some((q) => QueryExecutionStatus.DONE), - [latestQueryExecutions] - ); - const notification = useRef(true); - - const onRunAll = useCallback(() => { - sendConfirm({ - header: 'Run all cells below', - message: ( - { - notification.current = value; - }} - hasQueryRunning={hasQueryRunning} - queryCells={queryCells} - /> - ), - onConfirm: () => { - trackClick({ - component: ComponentType.DATADOC_PAGE, - element: ElementType.RUN_ALL_FROM_CELL_BUTTON, - }); - toast.promise( - DataDocResource.run(docId, notification.current, index), - { - loading: null, - success: 'DataDoc execution started!', - error: 'Failed to start the execution', - } - ); - }, - confirmText: 'Run', - }); - return null; - }, [docId, hasQueryRunning, notification, queryCells]); -} - // renders cell export const DataDocCell: React.FunctionComponent = React.memo( @@ -140,6 +81,12 @@ export const DataDocCell: React.FunctionComponent = fullScreenCellIndex, } = useContext(DataDocContext); + const onRunAllFromIndex = useRunAllFromIndex( + docId, + queryIndexInDoc + ); + console.log(onRunAllFromIndex); + const cellIdtoUid = useMakeSelector( dataDocSelectors.makeDataDocCursorByCellIdSelector, docId @@ -246,7 +193,7 @@ export const DataDocCell: React.FunctionComponent = templatedVariables, isFullScreen, toggleFullScreen, - useRunAll, + onRunAllFromIndex, }; cellDOM = ; } else if (cell.cell_type === 'chart') { diff --git a/querybook/webapp/components/DataDocQueryCell/DataDocQueryCell.tsx b/querybook/webapp/components/DataDocQueryCell/DataDocQueryCell.tsx index 57ff20cef..268549cb8 100644 --- a/querybook/webapp/components/DataDocQueryCell/DataDocQueryCell.tsx +++ b/querybook/webapp/components/DataDocQueryCell/DataDocQueryCell.tsx @@ -93,7 +93,7 @@ interface IOwnProps { onUpKeyPressed?: () => any; onDownKeyPressed?: () => any; toggleFullScreen: () => any; - useRunAll: (docId: number, index: number) => any; + onRunAllFromIndex: () => any; } type IProps = IOwnProps & StateProps & DispatchProps; @@ -548,12 +548,12 @@ class DataDocQueryCellComponent extends React.PureComponent { additionalButtons.push({ name: 'Run From Current Cell', - onClick: this.props.useRunAll( - this.props.docId, - this.props.queryIndexInDoc - ), + onClick: () => { + this.props.onRunAllFromIndex(); + }, icon: 'FastForward', - tooltip: 'Run all cells in the current datadoc after this cell', + tooltip: + 'Run all cells in the current datadoc starting from this cell', tooltipPos: 'left', }); diff --git a/querybook/webapp/components/DataDocRightSidebar/DataDocRunAllButton.tsx b/querybook/webapp/components/DataDocRightSidebar/DataDocRunAllButton.tsx index 330ed3c0e..bbc1db205 100644 --- a/querybook/webapp/components/DataDocRightSidebar/DataDocRunAllButton.tsx +++ b/querybook/webapp/components/DataDocRightSidebar/DataDocRunAllButton.tsx @@ -1,16 +1,8 @@ -import React, { useCallback, useMemo, useRef } from 'react'; -import toast from 'react-hot-toast'; +import React from 'react'; -import { ComponentType, ElementType } from 'const/analytics'; -import { useQueryCells } from 'hooks/dataDoc/useQueryCells'; -import { useMakeSelector } from 'hooks/redux/useMakeSelector'; -import { trackClick } from 'lib/analytics'; -import { sendConfirm } from 'lib/querybookUI'; -import { makeLatestQueryExecutionsSelector } from 'redux/queryExecutions/selector'; -import { DataDocResource } from 'resource/dataDoc'; import { IconButton } from 'ui/Button/IconButton'; -import { DataDocRunAllButtonConfirm } from './DataDocRunAllButtonConfirm'; +import { useRunAllFromIndex } from '../../hooks/dataDoc/useRunAllFromIndex'; interface IProps { docId: number; @@ -19,47 +11,7 @@ interface IProps { export const DataDocRunAllButton: React.FunctionComponent = ({ docId, }) => { - const queryCells = useQueryCells(docId); - const latestQueryExecutions = useMakeSelector( - makeLatestQueryExecutionsSelector, - queryCells.map((c) => c.id) ?? [] - ); - const hasQueryRunning = useMemo( - () => latestQueryExecutions.some((q) => q.status < 3), - [latestQueryExecutions] - ); - const notification = useRef(true); - - const onRunAll = useCallback(() => { - sendConfirm({ - header: 'Run All Cells', - message: ( - { - notification.current = value; - }} - hasQueryRunning={hasQueryRunning} - queryCells={queryCells} - /> - ), - onConfirm: () => { - trackClick({ - component: ComponentType.DATADOC_PAGE, - element: ElementType.RUN_ALL_CELLS_BUTTON, - }); - toast.promise( - DataDocResource.run(docId, notification.current), - { - loading: null, - success: 'DataDoc execution started!', - error: 'Failed to start the execution', - } - ); - }, - confirmText: 'Run', - }); - }, [docId, hasQueryRunning, notification, queryCells]); + const onRunAll = useRunAllFromIndex(docId, null); return ( void; - hasQueryRunning: boolean; - queryCells: ReturnType; + docId: number; + index?: number; } export const DataDocRunAllButtonConfirm: React.FunctionComponent = ({ defaultNotification, onNotificationChange, - hasQueryRunning, - queryCells, + docId, + index, }) => { const [notification, setNotification] = useState(defaultNotification); @@ -27,6 +30,20 @@ export const DataDocRunAllButtonConfirm: React.FunctionComponent = ({ [onNotificationChange, setNotification] ); + let queryCells = useQueryCells(docId); + if (index !== undefined) { + queryCells = queryCells.slice(index); + } + + const latestQueryExecutions = useMakeSelector( + makeLatestQueryExecutionsSelector, + queryCells.map((c) => c.id) ?? [] + ); + const hasQueryRunning = useMemo( + () => latestQueryExecutions.some((q) => QueryExecutionStatus.DONE), + [latestQueryExecutions] + ); + return (
{hasQueryRunning && ( diff --git a/querybook/webapp/hooks/dataDoc/useRunAllFromIndex.tsx b/querybook/webapp/hooks/dataDoc/useRunAllFromIndex.tsx new file mode 100644 index 000000000..2b75df82b --- /dev/null +++ b/querybook/webapp/hooks/dataDoc/useRunAllFromIndex.tsx @@ -0,0 +1,47 @@ +import React, { useCallback, useRef } from 'react'; +import { sendConfirm } from '../../lib/querybookUI'; +import { DataDocRunAllButtonConfirm } from '../../components/DataDocRightSidebar/DataDocRunAllButtonConfirm'; +import { trackClick } from '../../lib/analytics'; +import { ComponentType, ElementType } from '../../const/analytics'; +import toast from 'react-hot-toast'; +import { DataDocResource } from '../../resource/dataDoc'; + +export function useRunAllFromIndex(docId: number, index?: number) { + const header = + index === undefined ? 'Run All Cells' : 'Run all cells below'; + + const notification = useRef(true); + + const onRunAll = useCallback(() => { + sendConfirm({ + header, + message: ( + { + notification.current = value; + }} + docId={docId} + index={index} + /> + ), + onConfirm: () => { + trackClick({ + component: ComponentType.DATADOC_PAGE, + element: ElementType.RUN_ALL_FROM_CELL_BUTTON, + }); + toast.promise( + DataDocResource.run(docId, notification.current, index), + { + loading: null, + success: 'DataDoc execution started!', + error: 'Failed to start the execution', + } + ); + }, + confirmText: 'Run', + }); + return null; + }, [docId, notification]); + return onRunAll; +} diff --git a/querybook/webapp/resource/dataDoc.ts b/querybook/webapp/resource/dataDoc.ts index 3d1973be6..deddebb65 100644 --- a/querybook/webapp/resource/dataDoc.ts +++ b/querybook/webapp/resource/dataDoc.ts @@ -107,7 +107,7 @@ export const DataDocResource = { startIndex: number = 0 ) => ds.save(`/datadoc/${docId}/run/`, { - startIndex, + start_index: startIndex, send_notification: sendNotification, }), From eea9a630acf77e81b7a2b9849ca084af9ff5db2b Mon Sep 17 00:00:00 2001 From: jvalvo Date: Tue, 12 Sep 2023 11:24:26 -0700 Subject: [PATCH 6/6] feat: removed unused variables --- .../webapp/components/DataDocQueryCell/DataDocQueryCell.tsx | 1 - querybook/webapp/components/QueryComposer/QueryComposer.tsx | 2 -- 2 files changed, 3 deletions(-) diff --git a/querybook/webapp/components/DataDocQueryCell/DataDocQueryCell.tsx b/querybook/webapp/components/DataDocQueryCell/DataDocQueryCell.tsx index 268549cb8..26b78816e 100644 --- a/querybook/webapp/components/DataDocQueryCell/DataDocQueryCell.tsx +++ b/querybook/webapp/components/DataDocQueryCell/DataDocQueryCell.tsx @@ -674,7 +674,6 @@ class DataDocQueryCellComponent extends React.PureComponent { public renderCellHeaderDOM() { const { - docId, cellId, queryEngines, queryEngineById, diff --git a/querybook/webapp/components/QueryComposer/QueryComposer.tsx b/querybook/webapp/components/QueryComposer/QueryComposer.tsx index 7a191915c..10b43e9f6 100644 --- a/querybook/webapp/components/QueryComposer/QueryComposer.tsx +++ b/querybook/webapp/components/QueryComposer/QueryComposer.tsx @@ -637,8 +637,6 @@ const QueryComposer: React.FC = () => { runButtonTooltipPos={'down'} rowLimit={rowLimit} onRowLimitChange={setRowLimit} - docId={null} - index={null} />
);