diff --git a/packages/web/src/commands/CommandListener.svelte b/packages/web/src/commands/CommandListener.svelte
index 8b75bec91..527fde9d0 100644
--- a/packages/web/src/commands/CommandListener.svelte
+++ b/packages/web/src/commands/CommandListener.svelte
@@ -31,6 +31,7 @@
if (command) {
e.preventDefault();
+ e.stopPropagation();
command.onClick();
}
}
diff --git a/packages/web/src/modals/SaveFileModal.svelte b/packages/web/src/modals/SaveFileModal.svelte
new file mode 100644
index 000000000..064235e71
--- /dev/null
+++ b/packages/web/src/modals/SaveFileModal.svelte
@@ -0,0 +1,81 @@
+
+
+
+
+ Save file
+
+
+
+ {#if electron}
+ {
+ const file = electron.remote.dialog.showSaveDialogSync(electron.remote.getCurrentWindow(), {
+ filters: [
+ { name: `${fileExtension.toUpperCase()} files`, extensions: [fileExtension] },
+ { name: `All files`, extensions: ['*'] },
+ ],
+ defaultPath: filePath || `${name}.${fileExtension}`,
+ properties: ['showOverwriteConfirmation'],
+ });
+ if (file) {
+ handleSaveToDisk(file);
+ }
+ }}
+ />
+ {/if}
+
+
+
diff --git a/packages/web/src/tabs/QueryTab.svelte b/packages/web/src/tabs/QueryTab.svelte
index 7930771d8..df6daa04e 100644
--- a/packages/web/src/tabs/QueryTab.svelte
+++ b/packages/web/src/tabs/QueryTab.svelte
@@ -46,6 +46,14 @@
enabledStore: derived(currentQuery, query => query != null),
onClick: () => get(currentQuery).formatCode(),
});
+ registerSaveCommands({
+ idPrefix: 'query',
+ category: 'Query',
+ editorStore: currentQuery,
+ folder: 'sql',
+ format: 'text',
+ fileExtension: 'sql',
+ });
diff --git a/packages/web/src/utility/saveTabFile.ts b/packages/web/src/utility/saveTabFile.ts
new file mode 100644
index 000000000..204e600e2
--- /dev/null
+++ b/packages/web/src/utility/saveTabFile.ts
@@ -0,0 +1,75 @@
+import { derived, get } from 'svelte/store';
+import { showModal } from '../modals/modalTools';
+import { openedTabs } from '../stores';
+import axiosInstance from '../utility/axiosInstance';
+import { changeTab } from './common';
+import SaveFileModal from '../modals/SaveFileModal.svelte';
+import registerCommand from '../commands/registerCommand';
+
+export function saveTabEnabledStore(editorStore) {
+ return derived(editorStore, editor => editor != null);
+}
+
+export default function saveTabFile(editorStore, saveAs, folder, format, fileExtension) {
+ const editor: any = get(editorStore);
+ const tabs = get(openedTabs);
+ const tabid = editor.getTabId();
+ const data = editor.getData();
+ const { savedFile, savedFilePath } = tabs.find(x => x.tabid == tabid).props || {};
+
+ const handleSave = async () => {
+ if (savedFile) {
+ await axiosInstance.post('files/save', { folder, file: savedFile, data, format });
+ }
+ if (savedFilePath) {
+ await axiosInstance.post('files/save-as', { filePath: savedFilePath, data, format });
+ }
+ };
+
+ const onSave = (title, newProps) => {
+ changeTab(tabid, tab => ({
+ ...tab,
+ title,
+ props: {
+ ...tab.props,
+ savedFormat: format,
+ ...newProps,
+ },
+ }));
+ };
+
+ if ((savedFile || savedFilePath) && !saveAs) {
+ handleSave();
+ } else {
+ showModal(SaveFileModal, {
+ data,
+ folder,
+ format,
+ fileExtension,
+ name: savedFile || 'newFile',
+ filePath: savedFilePath,
+ onSave,
+ });
+ }
+}
+
+export function registerSaveCommands({ idPrefix, category, editorStore, folder, format, fileExtension }) {
+ registerCommand({
+ id: idPrefix + '.save',
+ category,
+ name: 'Save',
+ keyText: 'Ctrl+S',
+ icon: 'icon save',
+ toolbar: true,
+ enabledStore: saveTabEnabledStore(editorStore),
+ onClick: () => saveTabFile(editorStore, false, folder, format, fileExtension),
+ });
+ registerCommand({
+ id: idPrefix + '.saveAs',
+ category,
+ name: 'Save As',
+ keyText: 'Ctrl+Shift+S',
+ enabledStore: saveTabEnabledStore(editorStore),
+ onClick: () => saveTabFile(editorStore, true, folder, format, fileExtension),
+ });
+}