fix: add warning on unsaved content changes

This commit is contained in:
Alaister Young committed 2022-09-22 16:48:24 +10:00
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)
}
+31
View File
@@ -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 (
+21 -2
View File
@@ -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