diff --git a/superset-frontend/src/dashboard/components/Dashboard.jsx b/superset-frontend/src/dashboard/components/Dashboard.jsx index 18c2450d0351..4da142874644 100644 --- a/superset-frontend/src/dashboard/components/Dashboard.jsx +++ b/superset-frontend/src/dashboard/components/Dashboard.jsx @@ -29,7 +29,11 @@ import { dashboardInfoPropShape, dashboardStatePropShape, } from '../util/propShapes'; -import { LOG_ACTIONS_MOUNT_DASHBOARD } from '../../logger/LogUtils'; +import { + LOG_ACTIONS_HIDE_BROWSER_TAB, + LOG_ACTIONS_MOUNT_DASHBOARD, + Logger, +} from '../../logger/LogUtils'; import OmniContainer from '../../components/OmniContainer'; import { areObjectsEqual } from '../../reduxUtils'; @@ -81,6 +85,8 @@ class Dashboard extends React.PureComponent { constructor(props) { super(props); this.appliedFilters = props.activeFilters || {}; + + this.onVisibilityChange = this.onVisibilityChange.bind(this); } componentDidMount() { @@ -90,6 +96,15 @@ class Dashboard extends React.PureComponent { eventData.target_id = directLinkComponentId; } this.props.actions.logEvent(LOG_ACTIONS_MOUNT_DASHBOARD, eventData); + + // Handle browser tab visibility change + if (document.visibilityState === 'hidden') { + this.visibilityEventData = { + start_offset: Logger.getTimestamp(), + ts: new Date().getTime(), + }; + } + window.addEventListener('visibilitychange', this.onVisibilityChange); } UNSAFE_componentWillReceiveProps(nextProps) { @@ -158,6 +173,27 @@ class Dashboard extends React.PureComponent { } } + componentWillUnmount() { + window.removeEventListener('visibilitychange', this.onVisibilityChange); + } + + onVisibilityChange() { + if (document.visibilityState === 'hidden') { + // from visible to hidden + this.visibilityEventData = { + start_offset: Logger.getTimestamp(), + ts: new Date().getTime(), + }; + } else if (document.visibilityState === 'visible') { + // from hidden to visible + const logStart = this.visibilityEventData.start_offset; + this.props.actions.logEvent(LOG_ACTIONS_HIDE_BROWSER_TAB, { + ...this.visibilityEventData, + duration: Logger.getTimestamp() - logStart, + }); + } + } + // return charts in array getAllCharts() { return Object.values(this.props.charts); diff --git a/superset-frontend/src/logger/LogUtils.js b/superset-frontend/src/logger/LogUtils.js index d5f6073082df..14299aa1b240 100644 --- a/superset-frontend/src/logger/LogUtils.js +++ b/superset-frontend/src/logger/LogUtils.js @@ -19,6 +19,7 @@ // Log event names ------------------------------------------------------------ export const LOG_ACTIONS_LOAD_CHART = 'load_chart'; export const LOG_ACTIONS_RENDER_CHART = 'render_chart'; +export const LOG_ACTIONS_HIDE_BROWSER_TAB = 'hide_browser_tab'; export const LOG_ACTIONS_MOUNT_DASHBOARD = 'mount_dashboard'; export const LOG_ACTIONS_MOUNT_EXPLORER = 'mount_explorer'; @@ -41,6 +42,7 @@ export const LOG_ACTIONS_OMNIBAR_TRIGGERED = 'omnibar_triggered'; export const LOG_EVENT_TYPE_TIMING = new Set([ LOG_ACTIONS_LOAD_CHART, LOG_ACTIONS_RENDER_CHART, + LOG_ACTIONS_HIDE_BROWSER_TAB, ]); export const LOG_EVENT_TYPE_USER = new Set([ LOG_ACTIONS_MOUNT_DASHBOARD,