diff --git a/superset-frontend/src/SqlLab/App.jsx b/superset-frontend/src/SqlLab/App.jsx index 812202eec20f8..623f59ec7c758 100644 --- a/superset-frontend/src/SqlLab/App.jsx +++ b/superset-frontend/src/SqlLab/App.jsx @@ -30,6 +30,7 @@ import { FeatureFlag, } from 'src/featureFlags'; import setupExtensions from 'src/setup/setupExtensions'; +import logger from 'src/middleware/loggerMiddleware'; import getInitialState from './reducers/getInitialState'; import rootReducer from './reducers/index'; import { initEnhancer } from '../reduxUtils'; @@ -116,7 +117,7 @@ const store = createStore( rootReducer, initialState, compose( - applyMiddleware(thunkMiddleware), + applyMiddleware(thunkMiddleware, logger), initEnhancer( !isFeatureEnabled(FeatureFlag.SQLLAB_BACKEND_PERSISTENCE), sqlLabPersistStateConfig, diff --git a/superset-frontend/src/SqlLab/components/App/App.test.jsx b/superset-frontend/src/SqlLab/components/App/App.test.jsx index 0629de27d5d6c..c06262915637a 100644 --- a/superset-frontend/src/SqlLab/components/App/App.test.jsx +++ b/superset-frontend/src/SqlLab/components/App/App.test.jsx @@ -19,21 +19,29 @@ import React from 'react'; import configureStore from 'redux-mock-store'; import thunk from 'redux-thunk'; - -import { shallow } from 'enzyme'; +import { render } from 'spec/helpers/testing-library'; import App from 'src/SqlLab/components/App'; -import TabbedSqlEditors from 'src/SqlLab/components/TabbedSqlEditors'; import sqlLabReducer from 'src/SqlLab/reducers/index'; +import { LOCALSTORAGE_MAX_USAGE_KB } from 'src/SqlLab/constants'; +import { LOG_EVENT } from 'src/logger/actions'; + +jest.mock('src/SqlLab/components/TabbedSqlEditors', () => () => ( +
+)); +jest.mock('src/SqlLab/components/QueryAutoRefresh', () => () => ( +
+)); describe('SqlLab App', () => { const middlewares = [thunk]; const mockStore = configureStore(middlewares); const store = mockStore(sqlLabReducer(undefined, {}), {}); - let wrapper; - beforeEach(() => { - wrapper = shallow().dive(); + jest.useFakeTimers(); + }); + afterEach(() => { + jest.useRealTimers(); }); it('is valid', () => { @@ -41,8 +49,31 @@ describe('SqlLab App', () => { }); it('should render', () => { - const inner = wrapper.dive(); - expect(inner.find('.SqlLab')).toHaveLength(1); - expect(inner.find(TabbedSqlEditors)).toHaveLength(1); + const { getByTestId } = render(, { useRedux: true, store }); + expect(getByTestId('SqlLabApp')).toBeInTheDocument(); + expect(getByTestId('mock-tabbed-sql-editors')).toBeInTheDocument(); + }); + + it('logs current usage warning', async () => { + const localStorageUsageInKilobytes = LOCALSTORAGE_MAX_USAGE_KB + 10; + const storeExceedLocalStorage = mockStore( + sqlLabReducer( + { + localStorageUsageInKilobytes, + }, + {}, + ), + ); + + const { rerender } = render(, { + useRedux: true, + store: storeExceedLocalStorage, + }); + rerender(); + expect(storeExceedLocalStorage.getActions()).toContainEqual( + expect.objectContaining({ + type: LOG_EVENT, + }), + ); }); }); diff --git a/superset-frontend/src/SqlLab/components/App/index.jsx b/superset-frontend/src/SqlLab/components/App/index.jsx index 3aae12bfb33ca..3e9c4310cb505 100644 --- a/superset-frontend/src/SqlLab/components/App/index.jsx +++ b/superset-frontend/src/SqlLab/components/App/index.jsx @@ -29,6 +29,8 @@ import { LOCALSTORAGE_WARNING_MESSAGE_THROTTLE_MS, } from 'src/SqlLab/constants'; import * as Actions from 'src/SqlLab/actions/sqlLab'; +import { logEvent } from 'src/logger/actions'; +import { LOG_ACTIONS_SQLLAB_WARN_LOCAL_STORAGE_USAGE } from 'src/logger/LogUtils'; import TabbedSqlEditors from '../TabbedSqlEditors'; import QueryAutoRefresh from '../QueryAutoRefresh'; @@ -62,6 +64,7 @@ class App extends React.PureComponent { ) { this.showLocalStorageUsageWarning( this.props.localStorageUsageInKilobytes, + this.props.queries?.lenghth || 0, ); } } @@ -77,7 +80,7 @@ class App extends React.PureComponent { this.setState({ hash: window.location.hash }); } - showLocalStorageUsageWarning(currentUsage) { + showLocalStorageUsageWarning(currentUsage, queryCount) { this.props.actions.addDangerToast( t( "SQL Lab uses your browser's local storage to store queries and results." + @@ -91,6 +94,14 @@ class App extends React.PureComponent { }, ), ); + const eventData = { + current_usage: currentUsage, + query_count: queryCount, + }; + this.props.actions.logEvent( + LOG_ACTIONS_SQLLAB_WARN_LOCAL_STORAGE_USAGE, + eventData, + ); } render() { @@ -99,7 +110,7 @@ class App extends React.PureComponent { return window.location.replace('/superset/sqllab/history/'); } return ( -
+
next => action => { return next(action); } - const { dashboardInfo, explore, impressionId, dashboardLayout } = + const { dashboardInfo, explore, impressionId, dashboardLayout, sqlLab } = store.getState(); let logMetadata = { impression_id: impressionId, @@ -90,6 +90,16 @@ const loggerMiddleware = store => next => action => { source_id: explore.slice ? explore.slice.slice_id : 0, ...logMetadata, }; + } else if (sqlLab) { + const editor = sqlLab.queryEditors.find( + ({ id }) => id === sqlLab.tabHistory.slice(-1)[0], + ); + logMetadata = { + source: 'sqlLab', + source_id: editor?.id, + db_id: editor?.dbId, + schema: editor?.schema, + }; } const { eventName } = action.payload;