diff --git a/src/components/BrowserRow/BrowserRow.react.js b/src/components/BrowserRow/BrowserRow.react.js
index c9993b7a0b..991af6ae22 100644
--- a/src/components/BrowserRow/BrowserRow.react.js
+++ b/src/components/BrowserRow/BrowserRow.react.js
@@ -92,7 +92,7 @@ export default class BrowserRow extends Component {
>
selectRow(obj.id, e.target.checked)}
onMouseDown={e => onMouseDownRowCheckBox(e.target.checked)}
/>
diff --git a/src/dashboard/Data/Browser/Browser.react.js b/src/dashboard/Data/Browser/Browser.react.js
index 1d5cd34da1..b60df5be4a 100644
--- a/src/dashboard/Data/Browser/Browser.react.js
+++ b/src/dashboard/Data/Browser/Browser.react.js
@@ -38,11 +38,86 @@ import subscribeTo from 'lib/subscribeTo';
import * as ColumnPreferences from 'lib/ColumnPreferences';
import * as ClassPreferences from 'lib/ClassPreferences';
import { Helmet } from 'react-helmet';
+import { useBeforeUnload } from 'react-router-dom';
import generatePath from 'lib/generatePath';
import { withRouter } from 'lib/withRouter';
import { get } from 'lib/AJAX';
import BrowserFooter from './BrowserFooter.react';
+const SELECTED_ROWS_MESSAGE =
+ 'There are selected rows. Are you sure you want to leave this page?';
+
+function SelectedRowsNavigationPrompt({ when }) {
+ const message = SELECTED_ROWS_MESSAGE;
+
+ React.useEffect(() => {
+ if (!when) {
+ return;
+ }
+
+ const handleBeforeUnload = event => {
+ event.preventDefault();
+ event.returnValue = message;
+ return message;
+ };
+
+ const handleLinkClick = event => {
+ if (event.defaultPrevented) {
+ return;
+ }
+ if (event.button !== 0) {
+ return;
+ }
+ if (event.metaKey || event.altKey || event.ctrlKey || event.shiftKey) {
+ return;
+ }
+ const anchor = event.target.closest('a[href]');
+ if (!anchor || anchor.target === '_blank') {
+ return;
+ }
+ const href = anchor.getAttribute('href');
+ if (!href || href === '#') {
+ return;
+ }
+ if (!window.confirm(message)) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ };
+
+ const handlePopState = () => {
+ if (!window.confirm(message)) {
+ window.history.go(1);
+ }
+ };
+
+ window.addEventListener('beforeunload', handleBeforeUnload);
+ document.addEventListener('click', handleLinkClick, true);
+ window.addEventListener('popstate', handlePopState);
+
+ return () => {
+ window.removeEventListener('beforeunload', handleBeforeUnload);
+ document.removeEventListener('click', handleLinkClick, true);
+ window.removeEventListener('popstate', handlePopState);
+ };
+ }, [when, message]);
+
+ useBeforeUnload(
+ React.useCallback(
+ event => {
+ if (when) {
+ event.preventDefault();
+ event.returnValue = message;
+ return message;
+ }
+ },
+ [when, message]
+ )
+ );
+
+ return null;
+}
+
// The initial and max amount of rows fetched by lazy loading
const BROWSER_LAST_LOCATION = 'brower_last_location';
@@ -879,6 +954,11 @@ class Browser extends DashboardView {
}
async refresh() {
+ if (Object.keys(this.state.selection).length > 0) {
+ if (!window.confirm(SELECTED_ROWS_MESSAGE)) {
+ return;
+ }
+ }
const relation = this.state.relation;
const prevFilters = this.state.filters || new List();
const initialState = {
@@ -2446,6 +2526,9 @@ class Browser extends DashboardView {
{pageTitle}
+ 0}
+ />
{browser}
{notification}
{extras}