From bc6f0f70cb66e85faa58e5a1b474b3ce8f1c8d04 Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Thu, 16 May 2024 13:21:40 -0700 Subject: [PATCH] Support replacing route on redirect (#3072) * Support replacing route on redirect Support next/router `.replace` interface to change page without creating a history entry. * test_event: include test cases for new "replace" kwarg --- reflex/.templates/web/utils/state.js | 9 +++++-- reflex/event.py | 13 ++++++++-- tests/test_event.py | 39 +++++++++++++++++++++------- 3 files changed, 47 insertions(+), 14 deletions(-) diff --git a/reflex/.templates/web/utils/state.js b/reflex/.templates/web/utils/state.js index 5bc6b8b8b07..8386261e95a 100644 --- a/reflex/.templates/web/utils/state.js +++ b/reflex/.templates/web/utils/state.js @@ -126,8 +126,13 @@ export const applyDelta = (state, delta) => { export const applyEvent = async (event, socket) => { // Handle special events if (event.name == "_redirect") { - if (event.payload.external) window.open(event.payload.path, "_blank"); - else Router.push(event.payload.path); + if (event.payload.external) { + window.open(event.payload.path, "_blank"); + } else if (event.payload.replace) { + Router.replace(event.payload.path); + } else { + Router.push(event.payload.path); + } return false; } diff --git a/reflex/event.py b/reflex/event.py index 3f1487c1997..96a59fdc105 100644 --- a/reflex/event.py +++ b/reflex/event.py @@ -467,18 +467,27 @@ def fn(): ) -def redirect(path: str | Var[str], external: Optional[bool] = False) -> EventSpec: +def redirect( + path: str | Var[str], + external: Optional[bool] = False, + replace: Optional[bool] = False, +) -> EventSpec: """Redirect to a new path. Args: path: The path to redirect to. external: Whether to open in new tab or not. + replace: If True, the current page will not create a new history entry. Returns: An event to redirect to the path. """ return server_side( - "_redirect", get_fn_signature(redirect), path=path, external=external + "_redirect", + get_fn_signature(redirect), + path=path, + external=external, + replace=replace, ) diff --git a/tests/test_event.py b/tests/test_event.py index 88526315761..284542a4347 100644 --- a/tests/test_event.py +++ b/tests/test_event.py @@ -158,12 +158,29 @@ def test_fn_with_args(_, arg1, arg2): @pytest.mark.parametrize( "input,output", [ - (("/path", None), 'Event("_redirect", {path:`/path`,external:false})'), - (("/path", True), 'Event("_redirect", {path:`/path`,external:true})'), - (("/path", False), 'Event("_redirect", {path:`/path`,external:false})'), ( - (Var.create_safe("path"), None), - 'Event("_redirect", {path:path,external:false})', + ("/path", None, None), + 'Event("_redirect", {path:`/path`,external:false,replace:false})', + ), + ( + ("/path", True, None), + 'Event("_redirect", {path:`/path`,external:true,replace:false})', + ), + ( + ("/path", False, None), + 'Event("_redirect", {path:`/path`,external:false,replace:false})', + ), + ( + (Var.create_safe("path"), None, None), + 'Event("_redirect", {path:path,external:false,replace:false})', + ), + ( + ("/path", None, True), + 'Event("_redirect", {path:`/path`,external:false,replace:true})', + ), + ( + ("/path", True, True), + 'Event("_redirect", {path:`/path`,external:true,replace:true})', ), ], ) @@ -174,11 +191,13 @@ def test_event_redirect(input, output): input: The input for running the test. output: The expected output to validate the test. """ - path, external = input - if external is None: - spec = event.redirect(path) - else: - spec = event.redirect(path, external=external) + path, external, replace = input + kwargs = {} + if external is not None: + kwargs["external"] = external + if replace is not None: + kwargs["replace"] = replace + spec = event.redirect(path, **kwargs) assert isinstance(spec, EventSpec) assert spec.handler.fn.__qualname__ == "_redirect"