diff --git a/superset-frontend/src/dashboard/components/Dashboard.jsx b/superset-frontend/src/dashboard/components/Dashboard.jsx
index e168b394a5bc8..8a5e037983665 100644
--- a/superset-frontend/src/dashboard/components/Dashboard.jsx
+++ b/superset-frontend/src/dashboard/components/Dashboard.jsx
@@ -101,6 +101,7 @@ class Dashboard extends React.PureComponent {
const bootstrapData = appContainer?.getAttribute('data-bootstrap') || '';
const { dashboardState, layout } = this.props;
const eventData = {
+ is_soft_navigation: Logger.timeOriginOffset > 0,
is_edit_mode: dashboardState.editMode,
mount_duration: Logger.getTimestamp(),
is_empty: isDashboardEmpty(layout),
diff --git a/superset-frontend/src/logger/LogUtils.ts b/superset-frontend/src/logger/LogUtils.ts
index bfb7a7f112b41..9cdb5e4634bd5 100644
--- a/superset-frontend/src/logger/LogUtils.ts
+++ b/superset-frontend/src/logger/LogUtils.ts
@@ -59,8 +59,14 @@ export const LOG_EVENT_TYPE_USER = new Set([
]);
export const Logger = {
- // note that this returns ms since page load, NOT ms since epoch
+ timeOriginOffset: 0,
+
+ markTimeOrigin() {
+ this.timeOriginOffset = window.performance.now();
+ },
+
+ // note that this returns ms since last navigation, NOT ms since epoch
getTimestamp() {
- return Math.round(window.performance.now());
+ return Math.round(window.performance.now() - this.timeOriginOffset);
},
};
diff --git a/superset-frontend/src/views/App.tsx b/superset-frontend/src/views/App.tsx
index 445a87527f8c7..d04b08d93f147 100644
--- a/superset-frontend/src/views/App.tsx
+++ b/superset-frontend/src/views/App.tsx
@@ -16,10 +16,15 @@
* specific language governing permissions and limitations
* under the License.
*/
-import React, { Suspense } from 'react';
+import React, { Suspense, useEffect } from 'react';
import { hot } from 'react-hot-loader/root';
import { Provider as ReduxProvider } from 'react-redux';
-import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
+import {
+ BrowserRouter as Router,
+ Switch,
+ Route,
+ useLocation,
+} from 'react-router-dom';
import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import { QueryParamProvider } from 'use-query-params';
@@ -34,6 +39,7 @@ import { theme } from 'src/preamble';
import ToastPresenter from 'src/messageToasts/containers/ToastPresenter';
import setupApp from 'src/setup/setupApp';
import { routes, isFrontendRoute } from 'src/views/routes';
+import { Logger } from 'src/logger/LogUtils';
import { store } from './store';
setupApp();
@@ -43,26 +49,39 @@ const bootstrap = JSON.parse(container?.getAttribute('data-bootstrap') ?? '{}');
const user = { ...bootstrap.user };
const menu = { ...bootstrap.common.menu_data };
const common = { ...bootstrap.common };
+let lastLocationPathname: string;
initFeatureFlags(bootstrap.common.feature_flags);
-const RootContextProviders: React.FC = ({ children }) => (
-
-
-
-
-
-
- {children}
-
-
-
-
-
-
-);
+const RootContextProviders: React.FC = ({ children }) => {
+ const location = useLocation();
+ useEffect(() => {
+ // reset performance logger timer start point to avoid soft navigation
+ // cause dashboard perf measurement problem
+ if (lastLocationPathname && lastLocationPathname !== location.pathname) {
+ Logger.markTimeOrigin();
+ }
+ lastLocationPathname = location.pathname;
+ }, [location.pathname]);
+
+ return (
+
+
+
+
+
+
+ {children}
+
+
+
+
+
+
+ );
+};
const App = () => (