@@ -2,7 +2,10 @@ import Button from "@mui/material/Button";
2
2
import IconButton from "@mui/material/IconButton" ;
3
3
import Tooltip from "@mui/material/Tooltip" ;
4
4
import CreateIcon from "@mui/icons-material/AddOutlined" ;
5
- import { Link as RouterLink } from "react-router-dom" ;
5
+ import {
6
+ Link as RouterLink ,
7
+ unstable_usePrompt as usePrompt ,
8
+ } from "react-router-dom" ;
6
9
import { type Interpolation , type Theme , useTheme } from "@emotion/react" ;
7
10
import { type FC , useCallback , useEffect , useRef , useState } from "react" ;
8
11
import AlertTitle from "@mui/material/AlertTitle" ;
@@ -65,8 +68,8 @@ export interface TemplateVersionEditorProps {
65
68
defaultFileTree : FileTree ;
66
69
buildLogs ?: ProvisionerJobLog [ ] ;
67
70
resources ?: WorkspaceResource [ ] ;
68
- isBuilding ? : boolean ;
69
- canPublish ? : boolean ;
71
+ isBuilding : boolean ;
72
+ canPublish : boolean ;
70
73
onPreview : ( files : FileTree ) => Promise < void > ;
71
74
onPublish : ( ) => void ;
72
75
onConfirmPublish : ( data : PublishVersionData ) => void ;
@@ -179,20 +182,7 @@ export const TemplateVersionEditor: FC<TemplateVersionEditorProps> = ({
179
182
}
180
183
} , [ buildLogs ] ) ;
181
184
182
- useEffect ( ( ) => {
183
- const onBeforeUnload = ( e : BeforeUnloadEvent ) => {
184
- if ( canPublish ) {
185
- e . preventDefault ( ) ;
186
- return "You have unpublished changes. Are you sure you want to leave?" ;
187
- }
188
- } ;
189
-
190
- window . addEventListener ( "beforeunload" , onBeforeUnload ) ;
191
-
192
- return ( ) => {
193
- window . removeEventListener ( "beforeunload" , onBeforeUnload ) ;
194
- } ;
195
- } , [ canPublish ] ) ;
185
+ useLeaveSiteWarning ( canPublish ) ;
196
186
197
187
const canBuild = ! isBuilding && dirty ;
198
188
@@ -666,6 +656,38 @@ export const TemplateVersionEditor: FC<TemplateVersionEditorProps> = ({
666
656
) ;
667
657
} ;
668
658
659
+ const useLeaveSiteWarning = ( enabled : boolean ) => {
660
+ const MESSAGE =
661
+ "You have unpublished changes. Are you sure you want to leave?" ;
662
+
663
+ // This works for regular browser actions like close tab and back button
664
+ useEffect ( ( ) => {
665
+ const onBeforeUnload = ( e : BeforeUnloadEvent ) => {
666
+ if ( enabled ) {
667
+ e . preventDefault ( ) ;
668
+ return MESSAGE ;
669
+ }
670
+ } ;
671
+
672
+ window . addEventListener ( "beforeunload" , onBeforeUnload ) ;
673
+
674
+ return ( ) => {
675
+ window . removeEventListener ( "beforeunload" , onBeforeUnload ) ;
676
+ } ;
677
+ } , [ enabled ] ) ;
678
+
679
+ // This is used for react router navigation that is not triggered by the
680
+ // browser
681
+ usePrompt ( {
682
+ message : MESSAGE ,
683
+ when : ( { nextLocation } ) => {
684
+ // We need to check the path because we change the URL when new template
685
+ // version is created during builds
686
+ return enabled && ! nextLocation . pathname . endsWith ( "/edit" ) ;
687
+ } ,
688
+ } ) ;
689
+ } ;
690
+
669
691
const styles = {
670
692
tab : ( theme ) => ( {
671
693
"&:not(:disabled)" : {
0 commit comments