From d30aaf9e60ebaeb7c2656bf1bbf3cf1a3e3cdd2d Mon Sep 17 00:00:00 2001
From: Manuel <5673677+mtrezza@users.noreply.github.com>
Date: Thu, 10 Jul 2025 10:18:07 +0200
Subject: [PATCH 1/7] feat: warn when leaving page with selected rows
---
src/dashboard/Data/Browser/Browser.react.js | 22 +++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/src/dashboard/Data/Browser/Browser.react.js b/src/dashboard/Data/Browser/Browser.react.js
index 1d5cd34da1..849de3200a 100644
--- a/src/dashboard/Data/Browser/Browser.react.js
+++ b/src/dashboard/Data/Browser/Browser.react.js
@@ -38,11 +38,30 @@ import subscribeTo from 'lib/subscribeTo';
import * as ColumnPreferences from 'lib/ColumnPreferences';
import * as ClassPreferences from 'lib/ClassPreferences';
import { Helmet } from 'react-helmet';
+import { unstable_usePrompt as usePrompt, 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';
+function SelectedRowsNavigationPrompt({ when }) {
+ usePrompt({
+ when,
+ message: 'There are selected rows. Are you sure you want to leave this page?'
+ });
+ useBeforeUnload(
+ React.useCallback(
+ event => {
+ if (when) {
+ event.preventDefault();
+ }
+ },
+ [when]
+ )
+ );
+ return null;
+}
+
// The initial and max amount of rows fetched by lazy loading
const BROWSER_LAST_LOCATION = 'brower_last_location';
@@ -2446,6 +2465,9 @@ class Browser extends DashboardView {
{pageTitle}
+ 0}
+ />
{browser}
{notification}
{extras}
From 1388477aab28f9fff8d791b3790d4b20951401aa Mon Sep 17 00:00:00 2001
From: Manuel <5673677+mtrezza@users.noreply.github.com>
Date: Thu, 10 Jul 2025 10:34:54 +0200
Subject: [PATCH 2/7] fix: warn when leaving page with selections
---
src/dashboard/Data/Browser/Browser.react.js | 46 ++++++++++++++++++---
1 file changed, 41 insertions(+), 5 deletions(-)
diff --git a/src/dashboard/Data/Browser/Browser.react.js b/src/dashboard/Data/Browser/Browser.react.js
index 849de3200a..716f9bcbb4 100644
--- a/src/dashboard/Data/Browser/Browser.react.js
+++ b/src/dashboard/Data/Browser/Browser.react.js
@@ -38,17 +38,53 @@ import subscribeTo from 'lib/subscribeTo';
import * as ColumnPreferences from 'lib/ColumnPreferences';
import * as ClassPreferences from 'lib/ClassPreferences';
import { Helmet } from 'react-helmet';
-import { unstable_usePrompt as usePrompt, useBeforeUnload } from 'react-router-dom';
+import {
+ UNSAFE_NavigationContext,
+ 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';
+function useBlocker(blocker, when = true) {
+ const { navigator } = React.useContext(UNSAFE_NavigationContext);
+
+ React.useEffect(() => {
+ if (!when) {
+ return;
+ }
+
+ const unblock = navigator.block(tx => {
+ const autoUnblockingTx = {
+ ...tx,
+ retry() {
+ unblock();
+ tx.retry();
+ }
+ };
+ blocker(autoUnblockingTx);
+ });
+
+ return unblock;
+ }, [navigator, blocker, when]);
+}
+
+function usePrompt(message, when = true) {
+ const blocker = React.useCallback(
+ tx => {
+ if (window.confirm(message)) {
+ tx.retry();
+ }
+ },
+ [message]
+ );
+
+ useBlocker(blocker, when);
+}
+
function SelectedRowsNavigationPrompt({ when }) {
- usePrompt({
- when,
- message: 'There are selected rows. Are you sure you want to leave this page?'
- });
+ usePrompt('There are selected rows. Are you sure you want to leave this page?', when);
useBeforeUnload(
React.useCallback(
event => {
From 7170bff1a6c96d7dcebe3aea5b9e8fdd03cdbeeb Mon Sep 17 00:00:00 2001
From: Manuel <5673677+mtrezza@users.noreply.github.com>
Date: Thu, 10 Jul 2025 10:53:32 +0200
Subject: [PATCH 3/7] fix: warn when leaving page with selections
---
src/components/BrowserRow/BrowserRow.react.js | 2 +-
src/dashboard/Dashboard.js | 12 +++--
src/dashboard/Data/Browser/Browser.react.js | 47 +++++--------------
src/lib/history.js | 5 ++
4 files changed, 27 insertions(+), 39 deletions(-)
create mode 100644 src/lib/history.js
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/Dashboard.js b/src/dashboard/Dashboard.js
index 96be0559be..fe4a3c428c 100644
--- a/src/dashboard/Dashboard.js
+++ b/src/dashboard/Dashboard.js
@@ -48,7 +48,13 @@ import { AsyncStatus } from 'lib/Constants';
import baseStyles from 'stylesheets/base.scss';
import { get } from 'lib/AJAX';
import { setBasePath } from 'lib/AJAX';
-import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
+import {
+ unstable_HistoryRouter as HistoryRouter,
+ Routes,
+ Route,
+ Navigate,
+} from 'react-router-dom';
+import history from 'lib/history';
import { Helmet } from 'react-helmet';
import Playground from './Data/Playground/Playground.react';
import DashboardSettings from './Settings/DashboardSettings/DashboardSettings.react';
@@ -306,7 +312,7 @@ export default class Dashboard extends React.Component {
);
return (
-
+
Parse Dashboard
@@ -317,7 +323,7 @@ export default class Dashboard extends React.Component {
} />
} />
-
+
);
}
}
diff --git a/src/dashboard/Data/Browser/Browser.react.js b/src/dashboard/Data/Browser/Browser.react.js
index 716f9bcbb4..a02fd0cdce 100644
--- a/src/dashboard/Data/Browser/Browser.react.js
+++ b/src/dashboard/Data/Browser/Browser.react.js
@@ -38,58 +38,35 @@ import subscribeTo from 'lib/subscribeTo';
import * as ColumnPreferences from 'lib/ColumnPreferences';
import * as ClassPreferences from 'lib/ClassPreferences';
import { Helmet } from 'react-helmet';
-import {
- UNSAFE_NavigationContext,
- useBeforeUnload,
-} from 'react-router-dom';
+import { useBeforeUnload } from 'react-router-dom';
+import history from 'lib/history';
import generatePath from 'lib/generatePath';
import { withRouter } from 'lib/withRouter';
import { get } from 'lib/AJAX';
import BrowserFooter from './BrowserFooter.react';
-function useBlocker(blocker, when = true) {
- const { navigator } = React.useContext(UNSAFE_NavigationContext);
-
+function SelectedRowsNavigationPrompt({ when }) {
+ const message = 'There are selected rows. Are you sure you want to leave this page?';
React.useEffect(() => {
if (!when) {
- return;
+ return undefined;
}
-
- const unblock = navigator.block(tx => {
- const autoUnblockingTx = {
- ...tx,
- retry() {
- unblock();
- tx.retry();
- }
- };
- blocker(autoUnblockingTx);
- });
-
- return unblock;
- }, [navigator, blocker, when]);
-}
-
-function usePrompt(message, when = true) {
- const blocker = React.useCallback(
- tx => {
+ const unblock = history.block(tx => {
if (window.confirm(message)) {
+ unblock();
tx.retry();
}
- },
- [message]
- );
-
- useBlocker(blocker, when);
-}
+ });
+ return unblock;
+ }, [when]);
-function SelectedRowsNavigationPrompt({ when }) {
- usePrompt('There are selected rows. Are you sure you want to leave this page?', when);
useBeforeUnload(
React.useCallback(
event => {
if (when) {
event.preventDefault();
+ event.returnValue = message;
+ return message;
}
},
[when]
diff --git a/src/lib/history.js b/src/lib/history.js
new file mode 100644
index 0000000000..564e8ec761
--- /dev/null
+++ b/src/lib/history.js
@@ -0,0 +1,5 @@
+import { createBrowserHistory } from 'history';
+
+const history = createBrowserHistory();
+
+export default history;
From 78d82fcf30287c15f14275fce3f37497a4c9279d Mon Sep 17 00:00:00 2001
From: Manuel <5673677+mtrezza@users.noreply.github.com>
Date: Thu, 10 Jul 2025 11:05:56 +0200
Subject: [PATCH 4/7] feat: confirm navigation when rows selected
---
src/dashboard/Dashboard.js | 12 +++--------
src/dashboard/Data/Browser/Browser.react.js | 24 ++++++++++++---------
src/lib/history.js | 5 -----
3 files changed, 17 insertions(+), 24 deletions(-)
delete mode 100644 src/lib/history.js
diff --git a/src/dashboard/Dashboard.js b/src/dashboard/Dashboard.js
index fe4a3c428c..96be0559be 100644
--- a/src/dashboard/Dashboard.js
+++ b/src/dashboard/Dashboard.js
@@ -48,13 +48,7 @@ import { AsyncStatus } from 'lib/Constants';
import baseStyles from 'stylesheets/base.scss';
import { get } from 'lib/AJAX';
import { setBasePath } from 'lib/AJAX';
-import {
- unstable_HistoryRouter as HistoryRouter,
- Routes,
- Route,
- Navigate,
-} from 'react-router-dom';
-import history from 'lib/history';
+import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
import { Helmet } from 'react-helmet';
import Playground from './Data/Playground/Playground.react';
import DashboardSettings from './Settings/DashboardSettings/DashboardSettings.react';
@@ -312,7 +306,7 @@ export default class Dashboard extends React.Component {
);
return (
-
+
Parse Dashboard
@@ -323,7 +317,7 @@ export default class Dashboard extends React.Component {
} />
} />
-
+
);
}
}
diff --git a/src/dashboard/Data/Browser/Browser.react.js b/src/dashboard/Data/Browser/Browser.react.js
index a02fd0cdce..79d5c1094f 100644
--- a/src/dashboard/Data/Browser/Browser.react.js
+++ b/src/dashboard/Data/Browser/Browser.react.js
@@ -38,27 +38,31 @@ 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 history from 'lib/history';
+import { useBeforeUnload, useLocation, useNavigate } from 'react-router-dom';
import generatePath from 'lib/generatePath';
import { withRouter } from 'lib/withRouter';
import { get } from 'lib/AJAX';
import BrowserFooter from './BrowserFooter.react';
function SelectedRowsNavigationPrompt({ when }) {
+ const location = useLocation();
+ const navigate = useNavigate();
+ const previousLocation = React.useRef(location);
const message = 'There are selected rows. Are you sure you want to leave this page?';
+
React.useEffect(() => {
if (!when) {
- return undefined;
+ previousLocation.current = location;
+ return;
}
- const unblock = history.block(tx => {
- if (window.confirm(message)) {
- unblock();
- tx.retry();
+ if (location !== previousLocation.current) {
+ if (!window.confirm(message)) {
+ navigate(-1);
+ } else {
+ previousLocation.current = location;
}
- });
- return unblock;
- }, [when]);
+ }
+ }, [location, when, navigate]);
useBeforeUnload(
React.useCallback(
diff --git a/src/lib/history.js b/src/lib/history.js
deleted file mode 100644
index 564e8ec761..0000000000
--- a/src/lib/history.js
+++ /dev/null
@@ -1,5 +0,0 @@
-import { createBrowserHistory } from 'history';
-
-const history = createBrowserHistory();
-
-export default history;
From 982523c4f446b10ba7ea4f1853cd017281a05076 Mon Sep 17 00:00:00 2001
From: Manuel <5673677+mtrezza@users.noreply.github.com>
Date: Thu, 10 Jul 2025 11:19:37 +0200
Subject: [PATCH 5/7] fix: show confirmation when leaving with selected rows
---
src/dashboard/Data/Browser/Browser.react.js | 33 +++++++++++----------
1 file changed, 18 insertions(+), 15 deletions(-)
diff --git a/src/dashboard/Data/Browser/Browser.react.js b/src/dashboard/Data/Browser/Browser.react.js
index 79d5c1094f..2a66a589d4 100644
--- a/src/dashboard/Data/Browser/Browser.react.js
+++ b/src/dashboard/Data/Browser/Browser.react.js
@@ -38,32 +38,35 @@ import subscribeTo from 'lib/subscribeTo';
import * as ColumnPreferences from 'lib/ColumnPreferences';
import * as ClassPreferences from 'lib/ClassPreferences';
import { Helmet } from 'react-helmet';
-import { useBeforeUnload, useLocation, useNavigate } from 'react-router-dom';
+import {
+ useBeforeUnload,
+ UNSAFE_NavigationContext,
+} from 'react-router-dom';
import generatePath from 'lib/generatePath';
import { withRouter } from 'lib/withRouter';
import { get } from 'lib/AJAX';
import BrowserFooter from './BrowserFooter.react';
-function SelectedRowsNavigationPrompt({ when }) {
- const location = useLocation();
- const navigate = useNavigate();
- const previousLocation = React.useRef(location);
- const message = 'There are selected rows. Are you sure you want to leave this page?';
-
+function usePrompt(message, when) {
+ const { navigator } = React.useContext(UNSAFE_NavigationContext);
React.useEffect(() => {
if (!when) {
- previousLocation.current = location;
return;
}
- if (location !== previousLocation.current) {
- if (!window.confirm(message)) {
- navigate(-1);
- } else {
- previousLocation.current = location;
+ const unblock = navigator.block(tx => {
+ if (window.confirm(message)) {
+ unblock();
+ tx.retry();
}
- }
- }, [location, when, navigate]);
+ });
+ return unblock;
+ }, [navigator, message, when]);
+}
+function SelectedRowsNavigationPrompt({ when }) {
+ const message =
+ 'There are selected rows. Are you sure you want to leave this page?';
+ usePrompt(message, when);
useBeforeUnload(
React.useCallback(
event => {
From 6632f61c7bc9807328450617ed426a2ce99bb604 Mon Sep 17 00:00:00 2001
From: Manuel <5673677+mtrezza@users.noreply.github.com>
Date: Thu, 10 Jul 2025 11:25:41 +0200
Subject: [PATCH 6/7] fix: warn before leaving with selected rows
---
src/dashboard/Data/Browser/Browser.react.js | 72 +++++++++++++++------
1 file changed, 53 insertions(+), 19 deletions(-)
diff --git a/src/dashboard/Data/Browser/Browser.react.js b/src/dashboard/Data/Browser/Browser.react.js
index 2a66a589d4..32b4a90b1f 100644
--- a/src/dashboard/Data/Browser/Browser.react.js
+++ b/src/dashboard/Data/Browser/Browser.react.js
@@ -38,35 +38,68 @@ import subscribeTo from 'lib/subscribeTo';
import * as ColumnPreferences from 'lib/ColumnPreferences';
import * as ClassPreferences from 'lib/ClassPreferences';
import { Helmet } from 'react-helmet';
-import {
- useBeforeUnload,
- UNSAFE_NavigationContext,
-} from 'react-router-dom';
+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';
-function usePrompt(message, when) {
- const { navigator } = React.useContext(UNSAFE_NavigationContext);
+function SelectedRowsNavigationPrompt({ when }) {
+ const message =
+ 'There are selected rows. Are you sure you want to leave this page?';
+
React.useEffect(() => {
if (!when) {
return;
}
- const unblock = navigator.block(tx => {
- if (window.confirm(message)) {
- unblock();
- tx.retry();
+
+ const handleBeforeUnload = event => {
+ event.preventDefault();
+ event.returnValue = message;
+ return message;
+ };
+
+ const handleLinkClick = event => {
+ if (event.defaultPrevented) {
+ return;
}
- });
- return unblock;
- }, [navigator, message, when]);
-}
+ 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]);
-function SelectedRowsNavigationPrompt({ when }) {
- const message =
- 'There are selected rows. Are you sure you want to leave this page?';
- usePrompt(message, when);
useBeforeUnload(
React.useCallback(
event => {
@@ -76,9 +109,10 @@ function SelectedRowsNavigationPrompt({ when }) {
return message;
}
},
- [when]
+ [when, message]
)
);
+
return null;
}
From f74ba306b9fb9cc3005ee8e388be77fb5690f52e Mon Sep 17 00:00:00 2001
From: Manuel <5673677+mtrezza@users.noreply.github.com>
Date: Thu, 10 Jul 2025 11:31:05 +0200
Subject: [PATCH 7/7] feat: confirm refresh when rows selected
---
src/dashboard/Data/Browser/Browser.react.js | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/src/dashboard/Data/Browser/Browser.react.js b/src/dashboard/Data/Browser/Browser.react.js
index 32b4a90b1f..b60df5be4a 100644
--- a/src/dashboard/Data/Browser/Browser.react.js
+++ b/src/dashboard/Data/Browser/Browser.react.js
@@ -44,9 +44,11 @@ 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 =
- 'There are selected rows. Are you sure you want to leave this page?';
+ const message = SELECTED_ROWS_MESSAGE;
React.useEffect(() => {
if (!when) {
@@ -952,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 = {