diff --git a/packages/web/src/tabs/QueryTab.js b/packages/web/src/tabs/QueryTab.js
index 5cbc7f29..f5bcd52d 100644
--- a/packages/web/src/tabs/QueryTab.js
+++ b/packages/web/src/tabs/QueryTab.js
@@ -18,34 +18,27 @@ import SaveTabModal from '../modals/SaveTabModal';
import useModalState from '../modals/useModalState';
import sqlFormatter from 'sql-formatter';
import useEditorData from '../utility/useEditorData';
-import useSqlTemplate from '../utility/useSqlTemplate';
+import applySqlTemplate from '../utility/applySqlTemplate';
import LoadingInfo from '../widgets/LoadingInfo';
+import useExtensions from '../utility/useExtensions';
export default function QueryTab({ tabid, conid, database, initialArgs, tabVisible, toolbarPortalRef, ...other }) {
- const { sqlTemplate } = initialArgs || {};
const [sessionId, setSessionId] = React.useState(null);
const [executeNumber, setExecuteNumber] = React.useState(0);
const setOpenedTabs = useSetOpenedTabs();
const socket = useSocket();
const [busy, setBusy] = React.useState(false);
const saveFileModalState = useModalState();
- const { editorData, setEditorData, isLoading } = useEditorData(tabid);
+ const extensions = useExtensions();
+ const { editorData, setEditorData, isLoading } = useEditorData({
+ tabid,
+ loadFromArgs: initialArgs && initialArgs.sqlTemplate
+ ? () => applySqlTemplate(initialArgs.sqlTemplate, extensions, { conid, database, ...other })
+ : null,
+ });
- const [sqlFromTemplate, isLoadingTemplate] = useSqlTemplate(sqlTemplate, { conid, database, ...other });
const editorRef = React.useRef(null);
- React.useEffect(() => {
- if (sqlFromTemplate && sqlTemplate) {
- setEditorData(sqlFromTemplate);
- // editorRef.current.editor.setValue(sqlFromTemplate);
- // editorRef.current.editor.clearSelection();
- changeTab(tabid, setOpenedTabs, (tab) => ({
- ...tab,
- props: _.omit(tab.props, ['initialArgs']),
- }));
- }
- }, [sqlFromTemplate]);
-
const handleSessionDone = React.useCallback(() => {
setBusy(false);
}, []);
@@ -120,7 +113,7 @@ export default function QueryTab({ tabid, conid, database, initialArgs, tabVisib
editorRef.current.editor.clearSelection();
};
- if (isLoading || isLoadingTemplate)
+ if (isLoading)
return (
diff --git a/packages/web/src/utility/applySqlTemplate.js b/packages/web/src/utility/applySqlTemplate.js
new file mode 100644
index 00000000..bd0a59cb
--- /dev/null
+++ b/packages/web/src/utility/applySqlTemplate.js
@@ -0,0 +1,32 @@
+import { getDbCore, getConnectionInfo, getSqlObjectInfo } from '../utility/metadataLoaders';
+import sqlFormatter from 'sql-formatter';
+import { driverBase, findEngineDriver } from 'dbgate-tools';
+
+export default async function applySqlTemplate(sqlTemplate, extensions, props) {
+ if (sqlTemplate == 'CREATE TABLE') {
+ const tableInfo = await getDbCore(props, props.objectTypeField || 'tables');
+ const connection = await getConnectionInfo(props);
+ const driver = findEngineDriver(connection, extensions) || driverBase;
+ const dmp = driver.createDumper();
+ if (tableInfo) dmp.createTable(tableInfo);
+ return dmp.s;
+ }
+ if (sqlTemplate == 'CREATE OBJECT') {
+ const objectInfo = await getSqlObjectInfo(props);
+ if (objectInfo) {
+ if (objectInfo.requiresFormat && objectInfo.createSql) return sqlFormatter.format(objectInfo.createSql);
+ else return objectInfo.createSql;
+ }
+ }
+ if (sqlTemplate == 'EXECUTE PROCEDURE') {
+ const procedureInfo = await getSqlObjectInfo(props);
+ const connection = await getConnectionInfo(props);
+
+ const driver = findEngineDriver(connection, extensions) || driverBase;
+ const dmp = driver.createDumper();
+ if (procedureInfo) dmp.put('^execute %f', procedureInfo);
+ return dmp.s;
+ }
+
+ return null;
+}
diff --git a/packages/web/src/utility/useEditorData.js b/packages/web/src/utility/useEditorData.js
index 9b03e958..156c3058 100644
--- a/packages/web/src/utility/useEditorData.js
+++ b/packages/web/src/utility/useEditorData.js
@@ -1,29 +1,44 @@
import React from 'react';
import _ from 'lodash';
import localforage from 'localforage';
+import { changeTab } from './common';
+import { useSetOpenedTabs } from './globalState';
-export default function useEditorData(tabid, initialData = null) {
+export default function useEditorData({ tabid, loadFromArgs }) {
const localStorageKey = `tabdata_${tabid}`;
+ const setOpenedTabs = useSetOpenedTabs();
+ const changeCounterRef = React.useRef(0);
+ const savedCounterRef = React.useRef(0);
- const [value, setValue] = React.useState(initialData);
+ const [value, setValue] = React.useState(null);
const [isLoading, setIsLoading] = React.useState(true);
const valueRef = React.useRef(null);
const initialLoad = async () => {
- const initFallback = localStorage.getItem(localStorageKey);
- if (initFallback != null) {
- const init = JSON.parse(initFallback);
+ if (loadFromArgs) {
+ const init = await loadFromArgs();
+ changeTab(tabid, setOpenedTabs, (tab) => ({
+ ...tab,
+ props: _.omit(tab.props, ['initialArgs']),
+ }));
setValue(init);
valueRef.current = init;
- // move to local forage
- await localforage.setItem(localStorageKey, init);
- localStorage.removeItem(localStorageKey);
} else {
- const init = await localforage.getItem(localStorageKey);
- if (init) {
+ const initFallback = localStorage.getItem(localStorageKey);
+ if (initFallback != null) {
+ const init = JSON.parse(initFallback);
setValue(init);
valueRef.current = init;
+ // move to local forage
+ await localforage.setItem(localStorageKey, init);
+ localStorage.removeItem(localStorageKey);
+ } else {
+ const init = await localforage.getItem(localStorageKey);
+ if (init) {
+ setValue(init);
+ valueRef.current = init;
+ }
}
}
setIsLoading(false);
@@ -37,6 +52,7 @@ export default function useEditorData(tabid, initialData = null) {
if (valueRef.current == null) return;
try {
await localforage.setItem(localStorageKey, valueRef.current);
+ savedCounterRef.current = changeCounterRef.current;
} catch (err) {
console.error(err);
}
@@ -44,6 +60,7 @@ export default function useEditorData(tabid, initialData = null) {
const saveToStorageFallback = React.useCallback(() => {
if (valueRef.current == null) return;
+ if (savedCounterRef.current == changeCounterRef.current) return; // all saved
// on window unload must be synchronous actions, save to local storage instead
localStorage.setItem(localStorageKey, JSON.stringify(valueRef.current));
}, [localStorageKey, valueRef]);
@@ -53,6 +70,7 @@ export default function useEditorData(tabid, initialData = null) {
const handleChange = (newValue) => {
if (newValue != null) valueRef.current = newValue;
setValue(newValue);
+ changeCounterRef.current += 1;
saveToStorageDebounced();
};
diff --git a/packages/web/src/utility/useSqlTemplate.js b/packages/web/src/utility/useSqlTemplate.js
deleted file mode 100644
index bfc76940..00000000
--- a/packages/web/src/utility/useSqlTemplate.js
+++ /dev/null
@@ -1,48 +0,0 @@
-import React from 'react';
-
-import { getDbCore, getConnectionInfo, getSqlObjectInfo } from '../utility/metadataLoaders';
-import sqlFormatter from 'sql-formatter';
-import useExtensions from '../utility/useExtensions';
-import { driverBase, findEngineDriver } from 'dbgate-tools';
-
-export default function useSqlTemplate(sqlTemplate, props) {
- const [sql, setSql] = React.useState('');
- const extensions = useExtensions();
- const [isLoading, setIsLoading] = React.useState(!!sqlTemplate);
-
- async function loadTemplate() {
- if (sqlTemplate == 'CREATE TABLE') {
- const tableInfo = await getDbCore(props, props.objectTypeField || 'tables');
- const connection = await getConnectionInfo(props);
- const driver = findEngineDriver(connection, extensions) || driverBase;
- const dmp = driver.createDumper();
- if (tableInfo) dmp.createTable(tableInfo);
- setSql(dmp.s);
- }
- if (sqlTemplate == 'CREATE OBJECT') {
- const objectInfo = await getSqlObjectInfo(props);
- if (objectInfo) {
- if (objectInfo.requiresFormat && objectInfo.createSql) setSql(sqlFormatter.format(objectInfo.createSql));
- else setSql(objectInfo.createSql);
- }
- }
- if (sqlTemplate == 'EXECUTE PROCEDURE') {
- const procedureInfo = await getSqlObjectInfo(props);
- const connection = await getConnectionInfo(props);
-
- const driver = findEngineDriver(connection, extensions) || driverBase;
- const dmp = driver.createDumper();
- if (procedureInfo) dmp.put('^execute %f', procedureInfo);
- setSql(dmp.s);
- }
- setIsLoading(false);
- }
-
- React.useEffect(() => {
- if (sqlTemplate) {
- loadTemplate();
- }
- }, []);
-
- return [sql, isLoading];
-}