mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
fix: add warning on unsaved content changes
This commit is contained in:
1 parent
7fad595ef3
commit
26fbbf5062
3 files changed
+58
-3
No files matched your search
@@ -78,6 +78,7 @@ const TabSqlQuery = observer(() => {
|
||||
<MonacoEditor
|
||||
error={sqlEditorStore.activeTab.sqlQueryError}
|
||||
updateSqlSnippet={updateSqlSnippet}
|
||||
setUpdatingRequired={contentStore.setUpdatingRequired.bind(contentStore)}
|
||||
/>
|
||||
<div>
|
||||
<UtilityPanel updateSqlSnippet={updateSqlSnippet} />
|
||||
@@ -88,7 +89,7 @@ const TabSqlQuery = observer(() => {
|
||||
})
|
||||
export default TabSqlQuery
|
||||
|
||||
const MonacoEditor = ({ error, updateSqlSnippet }) => {
|
||||
const MonacoEditor = ({ error, updateSqlSnippet, setUpdatingRequired }) => {
|
||||
const sqlEditorStore = useSqlStore()
|
||||
const editorRef = useRef(null)
|
||||
const monacoRef = useRef(null)
|
||||
@@ -173,6 +174,10 @@ const MonacoEditor = ({ error, updateSqlSnippet }) => {
|
||||
// this is so any SQL run will be whatever is currently in monaco editor
|
||||
sqlEditorStore.activeTab.setQuery(value)
|
||||
|
||||
// inform the content store that the SQL has changed and needs to be persisted
|
||||
// this is so we can block the tab being closed if an update is required
|
||||
setUpdatingRequired?.()
|
||||
|
||||
// debounce changes
|
||||
debounceUpdateSqlSnippet(value)
|
||||
}
|
||||
|
||||
@@ -52,6 +52,37 @@ function MyApp({ Component, pageProps }: AppPropsWithLayout) {
|
||||
handleEmailVerificationError()
|
||||
}, [])
|
||||
|
||||
const getSavingState = () => rootStore.content.savingState
|
||||
|
||||
// prompt the user if they try and leave with unsaved content store changes
|
||||
useEffect(() => {
|
||||
const warningText = 'You have unsaved changes - are you sure you wish to leave this page?'
|
||||
|
||||
const handleWindowClose = (e: BeforeUnloadEvent) => {
|
||||
const savingState = getSavingState()
|
||||
|
||||
const unsavedChanges =
|
||||
savingState === 'UPDATING_REQUIRED' ||
|
||||
savingState === 'UPDATING' ||
|
||||
savingState === 'UPDATING_FAILED'
|
||||
|
||||
if (!unsavedChanges) {
|
||||
return
|
||||
}
|
||||
|
||||
e.preventDefault()
|
||||
|
||||
return (e.returnValue = warningText)
|
||||
}
|
||||
|
||||
window.addEventListener('beforeunload', handleWindowClose)
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('beforeunload', handleWindowClose)
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [])
|
||||
|
||||
const getLayout = Component.getLayout ?? ((page) => page)
|
||||
|
||||
return (
|
||||
|
||||
@@ -15,7 +15,13 @@ export interface IProjectContentStore {
|
||||
isLoading: boolean
|
||||
isInitialized: boolean
|
||||
isLoaded: boolean
|
||||
savingState: 'IDLE' | 'CREATING' | 'CREATING_FAILED' | 'UPDATING' | 'UPDATING_FAILED'
|
||||
savingState:
|
||||
| 'IDLE'
|
||||
| 'CREATING'
|
||||
| 'CREATING_FAILED'
|
||||
| 'UPDATING_REQUIRED'
|
||||
| 'UPDATING'
|
||||
| 'UPDATING_FAILED'
|
||||
error: any
|
||||
recentLogSqlSnippets: LogSqlSnippets.Content[]
|
||||
|
||||
@@ -81,6 +87,7 @@ export interface IProjectContentStore {
|
||||
|
||||
del(id: any): Promise<{ data: boolean; error: unknown }>
|
||||
delOptimistically(id: string): { data: boolean; error: null }
|
||||
setUpdatingRequired(): void
|
||||
}
|
||||
|
||||
export default class ProjectContentStore implements IProjectContentStore {
|
||||
@@ -102,7 +109,13 @@ export default class ProjectContentStore implements IProjectContentStore {
|
||||
recentLogSqlSnippets: LogSqlSnippets.Content[] = []
|
||||
|
||||
state = this.STATES.INITIAL
|
||||
savingState: 'IDLE' | 'CREATING' | 'CREATING_FAILED' | 'UPDATING' | 'UPDATING_FAILED'
|
||||
savingState:
|
||||
| 'IDLE'
|
||||
| 'CREATING'
|
||||
| 'CREATING_FAILED'
|
||||
| 'UPDATING_REQUIRED'
|
||||
| 'UPDATING'
|
||||
| 'UPDATING_FAILED'
|
||||
error = null
|
||||
|
||||
constructor(rootStore: IRootStore, options: { projectRef: string }) {
|
||||
@@ -354,6 +367,12 @@ export default class ProjectContentStore implements IProjectContentStore {
|
||||
return { data: true, error: null }
|
||||
}
|
||||
|
||||
setUpdatingRequired() {
|
||||
if (this.savingState === 'IDLE' || this.savingState === 'UPDATING_FAILED') {
|
||||
this.savingState = 'UPDATING_REQUIRED'
|
||||
}
|
||||
}
|
||||
|
||||
setProjectRef(ref?: string) {
|
||||
if (ref) {
|
||||
this.projectRef = ref
|
||||
|
||||
Reference in new issue
Block a user