mirror of
https://github.com/dbgate/dbgate
synced 2024-11-07 20:26:23 +00:00
use editor data
This commit is contained in:
parent
00d5b25baa
commit
f4fe5b9b53
@ -6,7 +6,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div bind:clientWidth bind:clientHeight class="ace-container">
|
<div bind:clientWidth bind:clientHeight class="ace-container">
|
||||||
<AceEditorCore {...$$props} width={clientWidth} height={clientHeight} />
|
<AceEditorCore {...$$props} width={clientWidth} height={clientHeight} on:input/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
@ -18,4 +18,4 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<AceEditor {mode} />
|
<AceEditor {mode} {...$$props} on:input />
|
||||||
|
148
packages/web/src/query/useEditorData.ts
Normal file
148
packages/web/src/query/useEditorData.ts
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
import _ from 'lodash';
|
||||||
|
import { writable, derived } from 'svelte/store';
|
||||||
|
import { onMount, onDestroy } from 'svelte';
|
||||||
|
import localforage from 'localforage';
|
||||||
|
import { changeTab } from '../utility/common';
|
||||||
|
|
||||||
|
function getParsedLocalStorage(key) {
|
||||||
|
const value = localStorage.getItem(key);
|
||||||
|
if (value != null) {
|
||||||
|
try {
|
||||||
|
const res = JSON.parse(value);
|
||||||
|
return res;
|
||||||
|
} catch (e) {
|
||||||
|
// console.log('FAILED LOAD FROM STORAGE', e);
|
||||||
|
// console.log('VALUE', value);
|
||||||
|
localStorage.removeItem(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function useEditorData({ tabid, reloadToken = 0, loadFromArgs = null }) {
|
||||||
|
const localStorageKey = `tabdata_editor_${tabid}`;
|
||||||
|
let changeCounter = 0;
|
||||||
|
let savedCounter = 0;
|
||||||
|
|
||||||
|
const editorState = writable({
|
||||||
|
errorMessage: null,
|
||||||
|
isLoading: true,
|
||||||
|
value: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
const editorValue = derived(editorState, $state => $state.value);
|
||||||
|
|
||||||
|
let initialData = null;
|
||||||
|
let value = null;
|
||||||
|
|
||||||
|
// const valueRef = React.useRef(null);
|
||||||
|
|
||||||
|
const initialLoad = async () => {
|
||||||
|
if (loadFromArgs) {
|
||||||
|
try {
|
||||||
|
const init = await loadFromArgs();
|
||||||
|
changeTab(tabid, tab => ({
|
||||||
|
...tab,
|
||||||
|
props: _.omit(tab.props, ['initialArgs']),
|
||||||
|
}));
|
||||||
|
editorState.update(x => ({
|
||||||
|
...x,
|
||||||
|
value: init,
|
||||||
|
}));
|
||||||
|
value = init;
|
||||||
|
initialData = init;
|
||||||
|
// mark as not saved
|
||||||
|
changeCounter += 1;
|
||||||
|
} catch (err) {
|
||||||
|
const message = (err && err.response && err.response.data && err.response.data.error) || 'Loading failed';
|
||||||
|
editorState.update(x => ({
|
||||||
|
...x,
|
||||||
|
errorMessage: message,
|
||||||
|
}));
|
||||||
|
console.error(err.response);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const initFallback = getParsedLocalStorage(localStorageKey);
|
||||||
|
if (initFallback != null) {
|
||||||
|
editorState.update(x => ({
|
||||||
|
...x,
|
||||||
|
value: initFallback,
|
||||||
|
}));
|
||||||
|
value = initFallback;
|
||||||
|
// move to local forage
|
||||||
|
await localforage.setItem(localStorageKey, initFallback);
|
||||||
|
localStorage.removeItem(localStorageKey);
|
||||||
|
initialData = initFallback;
|
||||||
|
} else {
|
||||||
|
const init = await localforage.getItem(localStorageKey);
|
||||||
|
if (init) {
|
||||||
|
editorState.update(x => ({
|
||||||
|
...x,
|
||||||
|
value: init,
|
||||||
|
}));
|
||||||
|
value = init;
|
||||||
|
initialData = init;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
editorState.update(x => ({
|
||||||
|
...x,
|
||||||
|
isLoading: false,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const saveToStorage = async () => {
|
||||||
|
if (value == null) return;
|
||||||
|
try {
|
||||||
|
await localforage.setItem(localStorageKey, value);
|
||||||
|
localStorage.removeItem(localStorageKey);
|
||||||
|
savedCounter = changeCounter;
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const saveToStorageSync = () => {
|
||||||
|
if (value == null) return;
|
||||||
|
if (savedCounter == changeCounter) return; // all saved
|
||||||
|
// on window unload must be synchronous actions, save to local storage instead
|
||||||
|
localStorage.setItem(localStorageKey, JSON.stringify(value));
|
||||||
|
};
|
||||||
|
|
||||||
|
const saveToStorageDebounced = _.debounce(saveToStorage, 5000);
|
||||||
|
|
||||||
|
const setEditorData = newValue => {
|
||||||
|
if (_.isFunction(newValue)) {
|
||||||
|
value = newValue(value);
|
||||||
|
} else {
|
||||||
|
if (newValue != null) value = newValue;
|
||||||
|
}
|
||||||
|
editorState.update(x => ({
|
||||||
|
...x,
|
||||||
|
value,
|
||||||
|
}));
|
||||||
|
|
||||||
|
changeCounter += 1;
|
||||||
|
saveToStorageDebounced();
|
||||||
|
};
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
window.addEventListener('beforeunload', saveToStorageSync);
|
||||||
|
initialLoad();
|
||||||
|
});
|
||||||
|
|
||||||
|
onDestroy(() => {
|
||||||
|
saveToStorage();
|
||||||
|
window.removeEventListener('beforeunload', saveToStorageSync);
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
editorState,
|
||||||
|
editorValue,
|
||||||
|
setEditorData,
|
||||||
|
initialData,
|
||||||
|
saveToStorage,
|
||||||
|
saveToStorageSync,
|
||||||
|
initialLoad,
|
||||||
|
};
|
||||||
|
}
|
@ -1,17 +1,33 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import VerticalSplitter from '../elements/VerticalSplitter.svelte';
|
import VerticalSplitter from '../elements/VerticalSplitter.svelte';
|
||||||
import SqlEditor from '../query/SqlEditor.svelte';
|
import SqlEditor from '../query/SqlEditor.svelte';
|
||||||
|
import useEditorData from '../query/useEditorData';
|
||||||
|
import { extensions } from '../stores';
|
||||||
|
import applySqlTemplate from '../utility/applySqlTemplate';
|
||||||
import { useConnectionInfo } from '../utility/metadataLoaders';
|
import { useConnectionInfo } from '../utility/metadataLoaders';
|
||||||
|
|
||||||
export let tabid;
|
export let tabid;
|
||||||
export let conid;
|
export let conid;
|
||||||
export let database;
|
export let database;
|
||||||
|
export let initialArgs;
|
||||||
|
|
||||||
$: connection = useConnectionInfo({ conid });
|
$: connection = useConnectionInfo({ conid });
|
||||||
|
|
||||||
|
const { editorState, setEditorData } = useEditorData({
|
||||||
|
tabid,
|
||||||
|
loadFromArgs:
|
||||||
|
initialArgs && initialArgs.sqlTemplate
|
||||||
|
? () => applySqlTemplate(initialArgs.sqlTemplate, $extensions, $$props)
|
||||||
|
: null,
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<VerticalSplitter>
|
<VerticalSplitter>
|
||||||
<svelte:fragment slot="1">
|
<svelte:fragment slot="1">
|
||||||
<SqlEditor engine={$connection && $connection.engine} />
|
<SqlEditor
|
||||||
|
engine={$connection && $connection.engine}
|
||||||
|
value={$editorState.value || ''}
|
||||||
|
on:input={e => setEditorData(e.detail)}
|
||||||
|
/>
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
</VerticalSplitter>
|
</VerticalSplitter>
|
||||||
|
32
packages/web/src/utility/applySqlTemplate.ts
Normal file
32
packages/web/src/utility/applySqlTemplate.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { getDbCore, getConnectionInfo, getSqlObjectInfo } from './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;
|
||||||
|
}
|
@ -1,9 +1,7 @@
|
|||||||
import { openedTabs } from '../stores';
|
import { openedTabs } from '../stores';
|
||||||
|
|
||||||
export class LoadingToken {
|
export class LoadingToken {
|
||||||
constructor() {
|
isCanceled = false;
|
||||||
this.isCanceled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
cancel() {
|
cancel() {
|
||||||
this.isCanceled = true;
|
this.isCanceled = true;
|
||||||
@ -14,8 +12,8 @@ export function sleep(milliseconds) {
|
|||||||
return new Promise(resolve => window.setTimeout(() => resolve(null), milliseconds));
|
return new Promise(resolve => window.setTimeout(() => resolve(null), milliseconds));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function changeTab(tabid, setOpenedTabs, changeFunc) {
|
export function changeTab(tabid, changeFunc) {
|
||||||
setOpenedTabs(files => files.map(tab => (tab.tabid == tabid ? changeFunc(tab) : tab)));
|
openedTabs.update(files => files.map(tab => (tab.tabid == tabid ? changeFunc(tab) : tab)));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setSelectedTabFunc(files, tabid) {
|
export function setSelectedTabFunc(files, tabid) {
|
@ -13,5 +13,7 @@
|
|||||||
"strictNullChecks": false,
|
"strictNullChecks": false,
|
||||||
"strict": false,
|
"strict": false,
|
||||||
"target": "es6",
|
"target": "es6",
|
||||||
|
// "allowJs": true,
|
||||||
|
// "checkJs": true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user