From eabc59fcb7f2d720a71329712eb970b7f661137e Mon Sep 17 00:00:00 2001 From: justinpark Date: Mon, 3 Jun 2024 16:42:33 -0700 Subject: [PATCH 1/3] chore(sqllab): Add logging for actions --- .../src/SqlLab/components/ResultSet/index.tsx | 20 ++++++- .../components/RunQueryActionButton/index.tsx | 16 +++++- .../src/SqlLab/components/SaveQuery/index.tsx | 14 ++++- .../components/ShareSqlLabQuery/index.tsx | 7 ++- .../src/SqlLab/components/SqlEditor/index.tsx | 42 ++++++++++++-- superset-frontend/src/logger/LogUtils.ts | 14 +++++ .../src/logger/useLogAction.test.ts | 55 +++++++++++++++++++ superset-frontend/src/logger/useLogAction.ts | 40 ++++++++++++++ 8 files changed, 194 insertions(+), 14 deletions(-) create mode 100644 superset-frontend/src/logger/useLogAction.test.ts create mode 100644 superset-frontend/src/logger/useLogAction.ts diff --git a/superset-frontend/src/SqlLab/components/ResultSet/index.tsx b/superset-frontend/src/SqlLab/components/ResultSet/index.tsx index a6bbb84bac942..b42852bf32147 100644 --- a/superset-frontend/src/SqlLab/components/ResultSet/index.tsx +++ b/superset-frontend/src/SqlLab/components/ResultSet/index.tsx @@ -63,12 +63,17 @@ import { reRunQuery, } from 'src/SqlLab/actions/sqlLab'; import { URL_PARAMS } from 'src/constants'; +import useLogAction from 'src/logger/useLogAction'; +import { + LOG_ACTIONS_SQLLAB_COPY_RESULT_TO_CLIPBOARD, + LOG_ACTIONS_SQLLAB_CREATE_CHART, + LOG_ACTIONS_SQLLAB_DOWNLOAD_CSV, +} from 'src/logger/LogUtils'; import Icons from 'src/components/Icons'; import ExploreCtasResultsButton from '../ExploreCtasResultsButton'; import ExploreResultsButton from '../ExploreResultsButton'; import HighlightedSql from '../HighlightedSql'; import QueryStateLabel from '../QueryStateLabel'; - enum LimitingFactor { Query = 'QUERY', QueryAndDropdown = 'QUERY_AND_DROPDOWN', @@ -163,6 +168,7 @@ const ResultSet = ({ 'dbId', 'tab', 'sql', + 'sqlEditorId', 'templateParams', 'schema', 'rows', @@ -193,6 +199,7 @@ const ResultSet = ({ const history = useHistory(); const dispatch = useDispatch(); + const logAction = useLogAction({ queryId, sqlEditorId: query.sqlEditorId }); const reRunQueryIfSessionTimeoutErrorOnMount = useCallback(() => { if ( @@ -250,7 +257,7 @@ const ResultSet = ({ const { results } = query; const openInNewWindow = clickEvent.metaKey; - + logAction(LOG_ACTIONS_SQLLAB_CREATE_CHART, {}); if (results?.query_id) { const key = await postFormData(results.query_id, 'query', { ...EXPLORE_CHART_DEFAULT, @@ -313,7 +320,11 @@ const ResultSet = ({ /> )} {csv && ( - )} @@ -327,6 +338,9 @@ const ResultSet = ({ } hideTooltip + onCopyEnd={() => + logAction(LOG_ACTIONS_SQLLAB_COPY_RESULT_TO_CLIPBOARD, {}) + } /> {search && ( diff --git a/superset-frontend/src/SqlLab/components/RunQueryActionButton/index.tsx b/superset-frontend/src/SqlLab/components/RunQueryActionButton/index.tsx index 30f8121132162..4965b17e35faf 100644 --- a/superset-frontend/src/SqlLab/components/RunQueryActionButton/index.tsx +++ b/superset-frontend/src/SqlLab/components/RunQueryActionButton/index.tsx @@ -25,6 +25,11 @@ import { DropdownButton } from 'src/components/DropdownButton'; import { detectOS } from 'src/utils/common'; import { QueryButtonProps } from 'src/SqlLab/types'; import useQueryEditor from 'src/SqlLab/hooks/useQueryEditor'; +import { + LOG_ACTIONS_SQLLAB_RUN_QUERY, + LOG_ACTIONS_SQLLAB_STOP_QUERY, +} from 'src/logger/LogUtils'; +import useLogAction from 'src/logger/useLogAction'; export interface RunQueryActionButtonProps { queryEditorId: string; @@ -89,6 +94,7 @@ const RunQueryActionButton = ({ stopQuery, }: RunQueryActionButtonProps) => { const theme = useTheme(); + const logAction = useLogAction({ queryEditorId }); const userOS = detectOS(); const { selectedText, sql } = useQueryEditor(queryEditorId, [ @@ -120,9 +126,13 @@ const RunQueryActionButton = ({ - onClick(shouldShowStopBtn, allowAsync, runQuery, stopQuery) - } + onClick={() => { + const eventName = shouldShowStopBtn + ? LOG_ACTIONS_SQLLAB_STOP_QUERY + : LOG_ACTIONS_SQLLAB_RUN_QUERY; + logAction(eventName, { shortcut: false }); + onClick(shouldShowStopBtn, allowAsync, runQuery, stopQuery); + }} disabled={isDisabled} tooltip={ (!isDisabled && diff --git a/superset-frontend/src/SqlLab/components/SaveQuery/index.tsx b/superset-frontend/src/SqlLab/components/SaveQuery/index.tsx index 2cb50b0c066cb..1462cd2a9a0c8 100644 --- a/superset-frontend/src/SqlLab/components/SaveQuery/index.tsx +++ b/superset-frontend/src/SqlLab/components/SaveQuery/index.tsx @@ -33,6 +33,11 @@ import { import { getDatasourceAsSaveableDataset } from 'src/utils/datasourceUtils'; import useQueryEditor from 'src/SqlLab/hooks/useQueryEditor'; import { QueryEditor } from 'src/SqlLab/types'; +import useLogAction from 'src/logger/useLogAction'; +import { + LOG_ACTIONS_SQLLAB_CREATE_CHART, + LOG_ACTIONS_SQLLAB_SAVE_QUERY, +} from 'src/logger/LogUtils'; interface SaveQueryProps { queryEditorId: string; @@ -91,6 +96,7 @@ const SaveQuery = ({ }), [queryEditor, columns], ); + const logAction = useLogAction({ queryEditorId }); const defaultLabel = query.name || query.description || t('Undefined'); const [description, setDescription] = useState( query.description || '', @@ -105,7 +111,12 @@ const SaveQuery = ({ const overlayMenu = ( - setShowSaveDatasetModal(true)}> + { + logAction(LOG_ACTIONS_SQLLAB_CREATE_CHART, {}); + setShowSaveDatasetModal(true); + }} + > {t('Save dataset')} @@ -129,6 +140,7 @@ const SaveQuery = ({ const close = () => setShowSave(false); const onSaveWrapper = () => { + logAction(LOG_ACTIONS_SQLLAB_SAVE_QUERY, {}); onSave(queryPayload(), query.id); close(); }; diff --git a/superset-frontend/src/SqlLab/components/ShareSqlLabQuery/index.tsx b/superset-frontend/src/SqlLab/components/ShareSqlLabQuery/index.tsx index 9309ce7c05934..b5dea4c750894 100644 --- a/superset-frontend/src/SqlLab/components/ShareSqlLabQuery/index.tsx +++ b/superset-frontend/src/SqlLab/components/ShareSqlLabQuery/index.tsx @@ -31,6 +31,8 @@ import withToasts from 'src/components/MessageToasts/withToasts'; import CopyToClipboard from 'src/components/CopyToClipboard'; import { storeQuery } from 'src/utils/common'; import useQueryEditor from 'src/SqlLab/hooks/useQueryEditor'; +import { LOG_ACTIONS_SQLLAB_COPY_LINK } from 'src/logger/LogUtils'; +import useLogAction from 'src/logger/useLogAction'; interface ShareSqlLabQueryProps { queryEditorId: string; @@ -52,7 +54,7 @@ const ShareSqlLabQuery = ({ addDangerToast, }: ShareSqlLabQueryProps) => { const theme = useTheme(); - + const logAction = useLogAction({ queryEditorId }); const { dbId, name, schema, autorun, sql, remoteId, templateParams } = useQueryEditor(queryEditorId, [ 'dbId', @@ -92,6 +94,9 @@ const ShareSqlLabQuery = ({ } }; const getCopyUrl = (callback: Function) => { + logAction(LOG_ACTIONS_SQLLAB_COPY_LINK, { + shortcut: false, + }); if (isFeatureEnabled(FeatureFlag.ShareQueriesViaKvStore)) { return getCopyUrlForKvStore(callback); } diff --git a/superset-frontend/src/SqlLab/components/SqlEditor/index.tsx b/superset-frontend/src/SqlLab/components/SqlEditor/index.tsx index 0c69e20fc6d98..7b7191d99513f 100644 --- a/superset-frontend/src/SqlLab/components/SqlEditor/index.tsx +++ b/superset-frontend/src/SqlLab/components/SqlEditor/index.tsx @@ -98,6 +98,15 @@ import { } from 'src/utils/localStorageHelpers'; import { EmptyStateBig } from 'src/components/EmptyState'; import getBootstrapData from 'src/utils/getBootstrapData'; +import useLogAction from 'src/logger/useLogAction'; +import { + LOG_ACTIONS_SQLLAB_CREATE_TABLE_AS, + LOG_ACTIONS_SQLLAB_CREATE_VIEW_AS, + LOG_ACTIONS_SQLLAB_ESTIMATE_QUERY_COST, + LOG_ACTIONS_SQLLAB_FORMAT_SQL, + LOG_ACTIONS_SQLLAB_RUN_QUERY, + LOG_ACTIONS_SQLLAB_STOP_QUERY, +} from 'src/logger/LogUtils'; import TemplateParamsEditor from '../TemplateParamsEditor'; import SouthPane from '../SouthPane'; import SaveQuery, { QueryPayload } from '../SaveQuery'; @@ -271,6 +280,7 @@ const SqlEditor: React.FC = ({ }; }, shallowEqual); + const logAction = useLogAction({ queryEditorId: queryEditor.id }); const isActive = currentQueryEditorId === queryEditor.id; const [height, setHeight] = useState(0); const [autorun, setAutorun] = useState(queryEditor.autorun); @@ -317,9 +327,15 @@ const SqlEditor: React.FC = ({ [ctas, database, defaultQueryLimit, dispatch, queryEditor], ); - const formatCurrentQuery = useCallback(() => { - dispatch(formatQuery(queryEditor)); - }, [dispatch, queryEditor]); + const formatCurrentQuery = useCallback( + (useShortcut?: boolean) => { + logAction(LOG_ACTIONS_SQLLAB_FORMAT_SQL, { + shortcut: Boolean(useShortcut), + }); + dispatch(formatQuery(queryEditor)); + }, + [dispatch, queryEditor, logAction], + ); const stopQuery = useCallback(() => { if (latestQuery && ['running', 'pending'].indexOf(latestQuery.state) >= 0) { @@ -358,6 +374,7 @@ const SqlEditor: React.FC = ({ descr: KEY_MAP[KeyboardShortcut.CtrlR], func: () => { if (queryEditor.sql.trim() !== '') { + logAction(LOG_ACTIONS_SQLLAB_RUN_QUERY, { shortcut: true }); startQuery(); } }, @@ -368,6 +385,7 @@ const SqlEditor: React.FC = ({ descr: KEY_MAP[KeyboardShortcut.CtrlEnter], func: () => { if (queryEditor.sql.trim() !== '') { + logAction(LOG_ACTIONS_SQLLAB_RUN_QUERY, { shortcut: true }); startQuery(); } }, @@ -398,14 +416,17 @@ const SqlEditor: React.FC = ({ key: KeyboardShortcut.CtrlE, descr: KEY_MAP[KeyboardShortcut.CtrlE], }), - func: stopQuery, + func: () => { + logAction(LOG_ACTIONS_SQLLAB_STOP_QUERY, { shortcut: true }); + stopQuery(); + }, }, { name: 'formatQuery', key: KeyboardShortcut.CtrlShiftF, descr: KEY_MAP[KeyboardShortcut.CtrlShiftF], func: () => { - formatCurrentQuery(); + formatCurrentQuery(true); }, }, ]; @@ -600,6 +621,7 @@ const SqlEditor: React.FC = ({ }); const getQueryCostEstimate = () => { + logAction(LOG_ACTIONS_SQLLAB_ESTIMATE_QUERY_COST, { shortcut: false }); if (database) { dispatch(estimateQueryCost(queryEditor)); } @@ -666,7 +688,9 @@ const SqlEditor: React.FC = ({ /> )} - {t('Format SQL')} + formatCurrentQuery()}> + {t('Format SQL')} + {!isEmpty(scheduledQueriesConf) && ( = ({ {allowCTAS && ( { + logAction(LOG_ACTIONS_SQLLAB_CREATE_TABLE_AS, { + shortcut: false, + }); setShowCreateAsModal(true); setCreateAs(CtasEnum.Table); }} @@ -715,6 +742,9 @@ const SqlEditor: React.FC = ({ {allowCVAS && ( { + logAction(LOG_ACTIONS_SQLLAB_CREATE_VIEW_AS, { + shortcut: false, + }); setShowCreateAsModal(true); setCreateAs(CtasEnum.View); }} diff --git a/superset-frontend/src/logger/LogUtils.ts b/superset-frontend/src/logger/LogUtils.ts index 2020cb67c0a92..6163452481d77 100644 --- a/superset-frontend/src/logger/LogUtils.ts +++ b/superset-frontend/src/logger/LogUtils.ts @@ -70,6 +70,20 @@ export const LOG_ACTIONS_DRILL_BY_BREADCRUMB_CLICKED = 'drill_by_breadcrumb_clicked'; export const LOG_ACTIONS_SQLLAB_MONITOR_LOCAL_STORAGE_USAGE = 'sqllab_monitor_local_storage_usage'; +export const LOG_ACTIONS_SQLLAB_CREATE_TABLE_AS = 'sqllab_create_table_as'; +export const LOG_ACTIONS_SQLLAB_CREATE_VIEW_AS = 'sqllab_create_view_as'; +export const LOG_ACTIONS_SQLLAB_RUN_QUERY = 'sqllab_run_query'; +export const LOG_ACTIONS_SQLLAB_STOP_QUERY = 'sqllab_stop_query'; +export const LOG_ACTIONS_SQLLAB_ESTIMATE_QUERY_COST = + 'sqllab_estimate_query_cost'; +export const LOG_ACTIONS_SQLLAB_SAVE_QUERY = 'sqllab_save_query'; +export const LOG_ACTIONS_SQLLAB_SAVE_DATASET = 'sqllab_save_dataset'; +export const LOG_ACTIONS_SQLLAB_COPY_LINK = 'sqllab_copy_link'; +export const LOG_ACTIONS_SQLLAB_FORMAT_SQL = 'sqllab_format_sql'; +export const LOG_ACTIONS_SQLLAB_DOWNLOAD_CSV = 'sqllab_download_csv'; +export const LOG_ACTIONS_SQLLAB_COPY_RESULT_TO_CLIPBOARD = + 'sqllab_copy_result_to_clipboard'; +export const LOG_ACTIONS_SQLLAB_CREATE_CHART = 'sqllab_create_chart'; // Log event types -------------------------------------------------------------- export const LOG_EVENT_TYPE_TIMING = new Set([ diff --git a/superset-frontend/src/logger/useLogAction.test.ts b/superset-frontend/src/logger/useLogAction.test.ts new file mode 100644 index 0000000000000..bf314ff0ee9e7 --- /dev/null +++ b/superset-frontend/src/logger/useLogAction.test.ts @@ -0,0 +1,55 @@ +/** + * 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 configureStore from 'redux-mock-store'; +import thunk from 'redux-thunk'; +import { renderHook } from '@testing-library/react-hooks'; +import { createWrapper } from 'spec/helpers/testing-library'; +import useLogAction from './useLogAction'; +import { LOG_ACTIONS_SQLLAB_COPY_LINK } from './LogUtils'; +import { LOG_EVENT } from './actions'; + +const middlewares = [thunk]; +const mockStore = configureStore(middlewares); + +test('dispatches logEvent action with static EventData', () => { + const staticEventData = { staticEventKey: 'value1' }; + const store = mockStore(); + const { result } = renderHook(() => useLogAction(staticEventData), { + wrapper: createWrapper({ + useRedux: true, + store, + }), + }); + result.current(LOG_ACTIONS_SQLLAB_COPY_LINK, { count: 1 }); + store.getActions(); + expect(store.getActions()).toEqual([ + { + type: LOG_EVENT, + payload: { + eventName: LOG_ACTIONS_SQLLAB_COPY_LINK, + eventData: { + payload: { + ...staticEventData, + count: 1, + }, + }, + }, + }, + ]); +}); diff --git a/superset-frontend/src/logger/useLogAction.ts b/superset-frontend/src/logger/useLogAction.ts new file mode 100644 index 0000000000000..3f8cdcc50fccb --- /dev/null +++ b/superset-frontend/src/logger/useLogAction.ts @@ -0,0 +1,40 @@ +/** + * 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 { useCallback } from 'react'; +import { useDispatch } from 'react-redux'; +import { logEvent } from 'src/logger/actions'; + +export default function useLogAction(staticEventData: Record) { + const dispatch = useDispatch(); + const logAction = useCallback( + (type, payload) => + dispatch( + logEvent(type, { + payload: { + ...staticEventData, + ...payload, + }, + }), + ), + [staticEventData, dispatch], + ); + + return logAction; +} From d14e908448000b52de23255f2eb7f4d91d56578c Mon Sep 17 00:00:00 2001 From: justinpark Date: Mon, 3 Jun 2024 17:08:38 -0700 Subject: [PATCH 2/3] lint fix and stop query --- .../src/SqlLab/components/ResultSet/index.tsx | 1 + .../components/RunQueryActionButton/index.tsx | 16 +++++++++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/superset-frontend/src/SqlLab/components/ResultSet/index.tsx b/superset-frontend/src/SqlLab/components/ResultSet/index.tsx index b42852bf32147..5a6b0a8a39641 100644 --- a/superset-frontend/src/SqlLab/components/ResultSet/index.tsx +++ b/superset-frontend/src/SqlLab/components/ResultSet/index.tsx @@ -74,6 +74,7 @@ import ExploreCtasResultsButton from '../ExploreCtasResultsButton'; import ExploreResultsButton from '../ExploreResultsButton'; import HighlightedSql from '../HighlightedSql'; import QueryStateLabel from '../QueryStateLabel'; + enum LimitingFactor { Query = 'QUERY', QueryAndDropdown = 'QUERY_AND_DROPDOWN', diff --git a/superset-frontend/src/SqlLab/components/RunQueryActionButton/index.tsx b/superset-frontend/src/SqlLab/components/RunQueryActionButton/index.tsx index 4965b17e35faf..0d1740cbac634 100644 --- a/superset-frontend/src/SqlLab/components/RunQueryActionButton/index.tsx +++ b/superset-frontend/src/SqlLab/components/RunQueryActionButton/index.tsx @@ -62,7 +62,13 @@ const onClick = ( allowAsync: boolean, runQuery: (c?: boolean) => void = () => undefined, stopQuery = () => {}, + logAction: (name: string, payload: Record) => void, ): void => { + const eventName = shouldShowStopButton + ? LOG_ACTIONS_SQLLAB_STOP_QUERY + : LOG_ACTIONS_SQLLAB_RUN_QUERY; + + logAction(eventName, { shortcut: false }); if (shouldShowStopButton) return stopQuery(); if (allowAsync) { return runQuery(true); @@ -126,13 +132,9 @@ const RunQueryActionButton = ({ { - const eventName = shouldShowStopBtn - ? LOG_ACTIONS_SQLLAB_STOP_QUERY - : LOG_ACTIONS_SQLLAB_RUN_QUERY; - logAction(eventName, { shortcut: false }); - onClick(shouldShowStopBtn, allowAsync, runQuery, stopQuery); - }} + onClick={() => + onClick(shouldShowStopBtn, allowAsync, runQuery, stopQuery, logAction) + } disabled={isDisabled} tooltip={ (!isDisabled && From fb1774aea91b063739eae016b34d605cecd76556 Mon Sep 17 00:00:00 2001 From: justinpark Date: Wed, 12 Jun 2024 16:12:19 -0700 Subject: [PATCH 3/3] log loading tabs --- .../src/SqlLab/components/SqlEditor/index.tsx | 10 ++++++++++ .../src/SqlLab/components/TabbedSqlEditors/index.tsx | 12 +++++++++++- superset-frontend/src/logger/LogUtils.ts | 2 ++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/superset-frontend/src/SqlLab/components/SqlEditor/index.tsx b/superset-frontend/src/SqlLab/components/SqlEditor/index.tsx index 7b7191d99513f..e3a118c48ac31 100644 --- a/superset-frontend/src/SqlLab/components/SqlEditor/index.tsx +++ b/superset-frontend/src/SqlLab/components/SqlEditor/index.tsx @@ -104,8 +104,10 @@ import { LOG_ACTIONS_SQLLAB_CREATE_VIEW_AS, LOG_ACTIONS_SQLLAB_ESTIMATE_QUERY_COST, LOG_ACTIONS_SQLLAB_FORMAT_SQL, + LOG_ACTIONS_SQLLAB_LOAD_TAB_STATE, LOG_ACTIONS_SQLLAB_RUN_QUERY, LOG_ACTIONS_SQLLAB_STOP_QUERY, + Logger, } from 'src/logger/LogUtils'; import TemplateParamsEditor from '../TemplateParamsEditor'; import SouthPane from '../SouthPane'; @@ -402,6 +404,7 @@ const SqlEditor: React.FC = ({ descr: KEY_MAP[KeyboardShortcut.CtrlT], }), func: () => { + Logger.markTimeOrigin(); dispatch(addNewQueryEditor()); }, }, @@ -524,6 +527,13 @@ const SqlEditor: React.FC = ({ !queryEditor.loaded; const loadQueryEditor = useEffectEvent(() => { + const duration = Logger.getTimestamp(); + logAction(LOG_ACTIONS_SQLLAB_LOAD_TAB_STATE, { + duration, + queryEditorId: queryEditor.id, + inLocalStorage: Boolean(queryEditor.inLocalStorage), + hasLoaded: !shouldLoadQueryEditor, + }); if (shouldLoadQueryEditor) { dispatch(switchQueryEditor(queryEditor, displayLimit)); } diff --git a/superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.tsx b/superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.tsx index 7b4db1cbe844c..e8b01e44d3504 100644 --- a/superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.tsx +++ b/superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.tsx @@ -23,6 +23,7 @@ import { connect } from 'react-redux'; import URI from 'urijs'; import type { QueryEditor, SqlLabRootState } from 'src/SqlLab/types'; import { FeatureFlag, styled, t, isFeatureEnabled } from '@superset-ui/core'; +import { Logger } from 'src/logger/LogUtils'; import { Tooltip } from 'src/components/Tooltip'; import { detectOS } from 'src/utils/common'; import * as Actions from 'src/SqlLab/actions/sqlLab'; @@ -222,6 +223,7 @@ class TabbedSqlEditors extends React.PureComponent { } } if (action === 'add') { + Logger.markTimeOrigin(); this.newQueryEditor(); } } @@ -230,6 +232,14 @@ class TabbedSqlEditors extends React.PureComponent { this.props.actions.removeQueryEditor(qe); } + onTabClicked = () => { + Logger.markTimeOrigin(); + const noQueryEditors = this.props.queryEditors?.length === 0; + if (noQueryEditors) { + this.newQueryEditor(); + } + }; + render() { const noQueryEditors = this.props.queryEditors?.length === 0; const editors = this.props.queryEditors?.map(qe => ( @@ -290,7 +300,7 @@ class TabbedSqlEditors extends React.PureComponent { onChange={this.handleSelect} fullWidth={false} hideAdd={this.props.offline} - onTabClick={() => noQueryEditors && this.newQueryEditor()} + onTabClick={this.onTabClicked} onEdit={this.handleEdit} type={noQueryEditors ? 'card' : 'editable-card'} addIcon={ diff --git a/superset-frontend/src/logger/LogUtils.ts b/superset-frontend/src/logger/LogUtils.ts index 6163452481d77..913a3d5af7bb7 100644 --- a/superset-frontend/src/logger/LogUtils.ts +++ b/superset-frontend/src/logger/LogUtils.ts @@ -84,6 +84,7 @@ export const LOG_ACTIONS_SQLLAB_DOWNLOAD_CSV = 'sqllab_download_csv'; export const LOG_ACTIONS_SQLLAB_COPY_RESULT_TO_CLIPBOARD = 'sqllab_copy_result_to_clipboard'; export const LOG_ACTIONS_SQLLAB_CREATE_CHART = 'sqllab_create_chart'; +export const LOG_ACTIONS_SQLLAB_LOAD_TAB_STATE = 'sqllab_load_tab_state'; // Log event types -------------------------------------------------------------- export const LOG_EVENT_TYPE_TIMING = new Set([ @@ -91,6 +92,7 @@ export const LOG_EVENT_TYPE_TIMING = new Set([ LOG_ACTIONS_RENDER_CHART, LOG_ACTIONS_HIDE_BROWSER_TAB, LOG_ACTIONS_SQLLAB_FETCH_FAILED_QUERY, + LOG_ACTIONS_SQLLAB_LOAD_TAB_STATE, ]); export const LOG_EVENT_TYPE_USER = new Set([ LOG_ACTIONS_MOUNT_DASHBOARD,