From 6b8bf8161ea2796c44f69c2a000d558ccc52e101 Mon Sep 17 00:00:00 2001 From: Jan Prochazka Date: Thu, 3 Jun 2021 20:58:38 +0200 Subject: [PATCH 01/12] quick export WIP --- packages/types/extensions.d.ts | 7 + .../src/appobj/DatabaseObjectAppObject.svelte | 203 ++++++++++-------- .../web/src/plugins/PluginsProvider.svelte | 10 +- .../web/src/utility/exportElectronFile.ts | 29 +++ .../dbgate-plugin-csv/src/frontend/index.js | 25 +++ .../dbgate-plugin-excel/src/frontend/index.js | 13 ++ 6 files changed, 197 insertions(+), 90 deletions(-) create mode 100644 packages/web/src/utility/exportElectronFile.ts diff --git a/packages/types/extensions.d.ts b/packages/types/extensions.d.ts index 142b6658a..fca442fe9 100644 --- a/packages/types/extensions.d.ts +++ b/packages/types/extensions.d.ts @@ -33,9 +33,16 @@ export interface PluginDefinition { content: any; } +export interface QuickExportDefinition { + label: string; + createWriter: (fileName: string) => { functionName: string; props: any }; + extension: string; +} + export interface ExtensionsDirectory { plugins: PluginDefinition[]; fileFormats: FileFormatDefinition[]; + quickExports: QuickExportDefinition[]; drivers: EngineDriver[]; themes: ThemeDefinition[]; } diff --git a/packages/web/src/appobj/DatabaseObjectAppObject.svelte b/packages/web/src/appobj/DatabaseObjectAppObject.svelte index f125e77cc..edfc2de46 100644 --- a/packages/web/src/appobj/DatabaseObjectAppObject.svelte +++ b/packages/web/src/appobj/DatabaseObjectAppObject.svelte @@ -1,6 +1,7 @@ ({ name: x.label, extensions: [x.extension] })); +} + +export async function exportElectronFile() { + const electron = getElectron(); + const ext = get(extensions); + const filters = getFileFormatFilters(ext); + console.log('FLT', filters); + electron.remote.dialog + .showSaveDialog(electron.remote.getCurrentWindow(), { + filters, + }) + .then(filePaths => { + console.log('filePaths ASYNC2', filePaths); + const filePath = filePaths && filePaths[0]; + console.log('filePath', filePath); + }); +} diff --git a/plugins/dbgate-plugin-csv/src/frontend/index.js b/plugins/dbgate-plugin-csv/src/frontend/index.js index 33b0f6a17..94a199e3d 100644 --- a/plugins/dbgate-plugin-csv/src/frontend/index.js +++ b/plugins/dbgate-plugin-csv/src/frontend/index.js @@ -43,4 +43,29 @@ const fileFormat = { export default { fileFormats: [fileFormat], + + quickExports: [ + { + label: 'CSV file', + extension: 'csv', + createWriter: (fileName) => ({ + functionName: 'writer', + props: { + fileName, + delimiter: ',', + }, + }), + }, + { + label: 'CSV file (semicolor separated)', + extension: 'csv', + createWriter: (fileName) => ({ + functionName: 'writer', + props: { + fileName, + delimiter: ';', + }, + }), + }, + ], }; diff --git a/plugins/dbgate-plugin-excel/src/frontend/index.js b/plugins/dbgate-plugin-excel/src/frontend/index.js index 94d515376..f79e18307 100644 --- a/plugins/dbgate-plugin-excel/src/frontend/index.js +++ b/plugins/dbgate-plugin-excel/src/frontend/index.js @@ -64,5 +64,18 @@ const fileFormat = { export default { fileFormats: [fileFormat], + quickExports: [ + { + label: 'MS Excel', + extension: 'xlsx', + createWriter: (fileName) => ({ + functionName: 'writer', + props: { + fileName, + sheetName: 'data', + }, + }), + }, + ], initialize, }; From 50b90e181aafda90666c69e9b48fb66f68ab22dc Mon Sep 17 00:00:00 2001 From: Jan Prochazka Date: Sat, 5 Jun 2021 08:14:03 +0200 Subject: [PATCH 02/12] context menu submenu support --- .../src/appobj/DatabaseObjectAppObject.svelte | 20 ++++++- packages/web/src/icons/FontIcon.svelte | 1 + packages/web/src/modals/DropDownMenu.svelte | 54 +++++++++++++++++-- 3 files changed, 69 insertions(+), 6 deletions(-) diff --git a/packages/web/src/appobj/DatabaseObjectAppObject.svelte b/packages/web/src/appobj/DatabaseObjectAppObject.svelte index edfc2de46..ac0196715 100644 --- a/packages/web/src/appobj/DatabaseObjectAppObject.svelte +++ b/packages/web/src/appobj/DatabaseObjectAppObject.svelte @@ -51,7 +51,8 @@ label: 'Export', isExport: true, }, - electron && { + // electron && + { label: 'Quick export', isQuickExport: true, }, @@ -394,6 +395,23 @@ .filter(x => x) .map(menu => { if (menu.divider) return menu; + + if (menu.isQuickExport) { + return { + text: menu.label, + submenu: [ + { + text: 'CSV file', + isQuickExport: true, + }, + { + text: 'Excel', + isQuickExport: true, + }, + ], + }; + } + return { text: menu.label, onClick: async () => { diff --git a/packages/web/src/icons/FontIcon.svelte b/packages/web/src/icons/FontIcon.svelte index c6a989fd1..ee027ea43 100644 --- a/packages/web/src/icons/FontIcon.svelte +++ b/packages/web/src/icons/FontIcon.svelte @@ -67,6 +67,7 @@ 'icon chevron-left': 'mdi mdi-chevron-left', 'icon chevron-right': 'mdi mdi-chevron-right', 'icon chevron-up': 'mdi mdi-chevron-up', + 'icon menu-right': 'mdi mdi-menu-right', 'icon plugin': 'mdi mdi-toy-brick', 'icon menu': 'mdi mdi-menu', diff --git a/packages/web/src/modals/DropDownMenu.svelte b/packages/web/src/modals/DropDownMenu.svelte index efce406ae..043b57ec5 100644 --- a/packages/web/src/modals/DropDownMenu.svelte +++ b/packages/web/src/modals/DropDownMenu.svelte @@ -1,9 +1,10 @@ +{#if submenuItem?.submenu} + +{/if} From 27311afb3150b424d112b6a5d6647291ce6c200b Mon Sep 17 00:00:00 2001 From: Jan Prochazka Date: Sun, 6 Jun 2021 10:25:52 +0200 Subject: [PATCH 03/12] quick exports - basic skeleton working --- .../src/appobj/DatabaseObjectAppObject.svelte | 65 +++++++++++-------- packages/web/src/modals/DropDownMenu.svelte | 32 +++++++-- .../web/src/utility/exportElectronFile.ts | 53 ++++++++------- .../dbgate-plugin-csv/src/frontend/index.js | 4 +- .../dbgate-plugin-excel/src/frontend/index.js | 6 +- 5 files changed, 96 insertions(+), 64 deletions(-) diff --git a/packages/web/src/appobj/DatabaseObjectAppObject.svelte b/packages/web/src/appobj/DatabaseObjectAppObject.svelte index ac0196715..9578e9db2 100644 --- a/packages/web/src/appobj/DatabaseObjectAppObject.svelte +++ b/packages/web/src/appobj/DatabaseObjectAppObject.svelte @@ -47,15 +47,15 @@ { divider: true, }, + electron && { + label: 'Quick export', + isQuickExport: true, + functionName: 'tableReader', + }, { label: 'Export', isExport: true, }, - // electron && - { - label: 'Quick export', - isQuickExport: true, - }, { label: 'Open in free table editor', isOpenFreeTable: true, @@ -114,14 +114,14 @@ { divider: true, }, - { - label: 'Export', - isExport: true, - }, electron && { label: 'Quick export', isQuickExport: true, }, + { + label: 'Export', + isExport: true, + }, { label: 'Open in free table editor', isOpenFreeTable: true, @@ -175,14 +175,14 @@ { divider: true, }, - { - label: 'Export', - isExport: true, - }, electron && { label: 'Quick export', isQuickExport: true, }, + { + label: 'Export', + isExport: true, + }, { label: 'Open in free table editor', isOpenFreeTable: true, @@ -275,14 +275,14 @@ }, }, }, - { - label: 'Export', - isExport: true, - }, electron && { label: 'Quick export', isQuickExport: true, }, + { + label: 'Export', + isExport: true, + }, { divider: true, }, @@ -399,16 +399,26 @@ if (menu.isQuickExport) { return { text: menu.label, - submenu: [ - { - text: 'CSV file', - isQuickExport: true, + submenu: $extensions.quickExports.map(fmt => ({ + text: fmt.label, + onClick: async () => { + const coninfo = await getConnectionInfo(data); + exportElectronFile( + data.pureName, + { + functionName: menu.functionName, + props: { + connection: { + ..._.omit(coninfo, ['_id', 'displayName']), + ..._.pick(data, ['database']), + }, + ..._.pick(data, ['pureName', 'schemaName']), + }, + }, + fmt + ); }, - { - text: 'Excel', - isQuickExport: true, - }, - ], + })), }; } @@ -425,8 +435,6 @@ sourceList: [data.pureName], }, }); - } else if (menu.isQuickExport) { - exportElectronFile(data); } else if (menu.isOpenFreeTable) { const coninfo = await getConnectionInfo(data); openNewTab({ @@ -511,6 +519,7 @@ mapItem(x, $commandsCustomized))); $: filtered = compacted.filter(x => !x.disabled || !x.hideDisabled); + const handleClickOutside = event => { + // if (element && !element.contains(event.target) && !event.defaultPrevented) { + if (event.target.closest('ul.dropDownMenuMarker')) return; + + dispatch('close'); + }; + + onMount(() => { + document.addEventListener('mousedown', handleClickOutside, true); + return () => { + document.removeEventListener('mousedown', handleClickOutside, true); + }; + }); + -
    dispatch('close')} - bind:this={element} -> + {#if submenuItem?.submenu} - + { + if (onCloseParent) onCloseParent(); + dispatch('close'); + }} + /> {/if} diff --git a/packages/web/src/datagrid/SqlDataGridCore.svelte b/packages/web/src/datagrid/SqlDataGridCore.svelte index f1c8ae84f..d25829c43 100644 --- a/packages/web/src/datagrid/SqlDataGridCore.svelte +++ b/packages/web/src/datagrid/SqlDataGridCore.svelte @@ -71,11 +71,7 @@ + import { openedSnackbars } from '../stores'; + + export interface SnackbarButton { + label: string; + onClick: Function; + } + + export interface SnackbarInfo { + message: string; + icon?: string; + autoClose?: boolean; + allowClose?: boolean; + buttons?: SnackbarButton[]; + } + + let lastSnackbarId = 0; + + export function showSnackbar(snackbar: SnackbarInfo) { + lastSnackbarId += 1; + openedSnackbars.update(x => [ + ...x, + { + ...snackbar, + id: lastSnackbarId, + }, + ]); + } + + export function showSnackbarSuccess(message: string) { + showSnackbar({ + message, + icon: 'img ok', + allowClose: true, + autoClose: true, + }); + } + +// showSnackbar({ +// icon: 'img ok', +// message: 'Test snackbar', +// allowClose: true, +// }); +// showSnackbar({ +// icon: 'img ok', +// message: 'Auto close', +// autoClose: true, +// }); +// showSnackbar({ +// icon: 'img warn', +// message: 'Buttons', +// buttons: [{ label: 'OK', onClick: () => console.log('OK') }], +// }); + + + + + +
    +
    + + {message} +
    + + {#if allowClose} +
    + +
    + {/if} + + {#if buttons?.length > 0} +
    + {#each buttons as button} +
    + +
    + {/each} +
    + {/if} +
    + + From 26ff3f45f85ff40d4dffb41cc8b957f05595ddb2 Mon Sep 17 00:00:00 2001 From: Jan Prochazka Date: Sun, 6 Jun 2021 13:13:38 +0200 Subject: [PATCH 05/12] quick export with snackbar info, allows canceling process --- packages/web/src/Screen.svelte | 4 +- packages/web/src/icons/FontIcon.svelte | 1 + packages/web/src/tabs/TableDataTab.svelte | 2 +- .../web/src/utility/exportElectronFile.ts | 30 +++++++- packages/web/src/utility/snackbar.ts | 75 +++++++++++++++++++ packages/web/src/widgets/Snackbar.svelte | 57 +------------- 6 files changed, 107 insertions(+), 62 deletions(-) create mode 100644 packages/web/src/utility/snackbar.ts diff --git a/packages/web/src/Screen.svelte b/packages/web/src/Screen.svelte index 5d87f3308..3dd219694 100644 --- a/packages/web/src/Screen.svelte +++ b/packages/web/src/Screen.svelte @@ -69,7 +69,9 @@ {/if}
    {#each $openedSnackbars as snackbar} - + {#key snackbar.id} + + {/key} {/each}
    diff --git a/packages/web/src/icons/FontIcon.svelte b/packages/web/src/icons/FontIcon.svelte index ee027ea43..8d06dfdcf 100644 --- a/packages/web/src/icons/FontIcon.svelte +++ b/packages/web/src/icons/FontIcon.svelte @@ -77,6 +77,7 @@ 'img error': 'mdi mdi-close-circle color-icon-red', 'img error-inv': 'mdi mdi-close-circle color-icon-inv-red', 'img warn': 'mdi mdi-alert color-icon-gold', + 'img info': 'mdi mdi-information color-icon-blue', // 'img statusbar-ok': 'mdi mdi-check-circle color-on-statusbar-green', 'img archive': 'mdi mdi-table color-icon-gold', diff --git a/packages/web/src/tabs/TableDataTab.svelte b/packages/web/src/tabs/TableDataTab.svelte index 305bfe217..ebff70b99 100644 --- a/packages/web/src/tabs/TableDataTab.svelte +++ b/packages/web/src/tabs/TableDataTab.svelte @@ -47,7 +47,7 @@ import createActivator, { getActiveComponent } from '../utility/createActivator'; import registerCommand from '../commands/registerCommand'; import { registerMenu } from '../utility/contextMenu'; - import { showSnackbarSuccess } from '../widgets/Snackbar.svelte'; + import { showSnackbarSuccess } from '../utility/snackbar'; export let tabid; export let conid; diff --git a/packages/web/src/utility/exportElectronFile.ts b/packages/web/src/utility/exportElectronFile.ts index 86aaea777..2bf4caefa 100644 --- a/packages/web/src/utility/exportElectronFile.ts +++ b/packages/web/src/utility/exportElectronFile.ts @@ -1,6 +1,8 @@ import ScriptWriter from '../impexp/ScriptWriter'; import getElectron from './getElectron'; import axiosInstance from '../utility/axiosInstance'; +import socket from '../utility/socket'; +import { showSnackbar, showSnackbarInfo, showSnackbarError, closeSnackbar } from '../utility/snackbar'; export async function exportElectronFile(dataName, reader, format) { const electron = getElectron(); @@ -18,8 +20,6 @@ export async function exportElectronFile(dataName, reader, format) { const sourceVar = script.allocVariable(); script.assign(sourceVar, reader.functionName, reader.props); - console.log('format.createWriter(filePath, dataName)', format.createWriter(filePath, dataName)); - const targetVar = script.allocVariable(); const writer = format.createWriter(filePath, dataName); script.assign(targetVar, writer.functionName, writer.props); @@ -27,8 +27,30 @@ export async function exportElectronFile(dataName, reader, format) { script.copyStream(sourceVar, targetVar); script.put(); - console.log('script.getScript()', script.getScript()); - const resp = await axiosInstance.post('runners/start', { script: script.getScript() }); const runid = resp.data.runid; + let isCanceled = false; + + const snackId = showSnackbar({ + message: `Exporting ${dataName}`, + icon: 'icon loading', + buttons: [ + { + label: 'Cancel', + onClick: () => { + isCanceled = true; + axiosInstance.post('runners/cancel', { runid }); + }, + }, + ], + }); + + function handleRunnerDone() { + closeSnackbar(snackId); + socket.off(`runner-done-${runid}`, handleRunnerDone); + if (isCanceled) showSnackbarError(`Export ${dataName} canceled`); + else showSnackbarInfo(`Export ${dataName} finished`); + } + + socket.on(`runner-done-${runid}`, handleRunnerDone); } diff --git a/packages/web/src/utility/snackbar.ts b/packages/web/src/utility/snackbar.ts new file mode 100644 index 000000000..95513c6cc --- /dev/null +++ b/packages/web/src/utility/snackbar.ts @@ -0,0 +1,75 @@ +import { openedSnackbars } from '../stores'; + +export interface SnackbarButton { + label: string; + onClick: Function; +} + +export interface SnackbarInfo { + message: string; + icon?: string; + autoClose?: boolean; + allowClose?: boolean; + buttons?: SnackbarButton[]; +} + +let lastSnackbarId = 0; + +export function showSnackbar(snackbar: SnackbarInfo): string { + lastSnackbarId += 1; + const id = lastSnackbarId.toString(); + openedSnackbars.update(x => [ + ...x, + { + ...snackbar, + id, + }, + ]); + return id; +} + +export function showSnackbarSuccess(message: string) { + showSnackbar({ + message, + icon: 'img ok', + allowClose: true, + autoClose: true, + }); +} + +export function showSnackbarInfo(message: string) { + showSnackbar({ + message, + icon: 'img info', + allowClose: true, + autoClose: true, + }); +} + +export function showSnackbarError(message: string) { + showSnackbar({ + message, + icon: 'img error', + allowClose: true, + autoClose: true, + }); +} + +export function closeSnackbar(snackId: string) { + openedSnackbars.update(x => x.filter(x => x.id != snackId)); +} +// showSnackbar({ +// icon: 'img ok', +// message: 'Test snackbar', +// allowClose: true, +// }); +showSnackbar({ + icon: 'img ok', + message: 'Auto close', + autoClose: true, +}); +// showSnackbar({ +// icon: 'img warn', +// message: 'Buttons', +// buttons: [{ label: 'OK', onClick: () => console.log('OK') }], +// }); diff --git a/packages/web/src/widgets/Snackbar.svelte b/packages/web/src/widgets/Snackbar.svelte index 0cbff48b2..0315b7393 100644 --- a/packages/web/src/widgets/Snackbar.svelte +++ b/packages/web/src/widgets/Snackbar.svelte @@ -1,63 +1,8 @@ - - Function +) { + return { + text: 'Quick export', + submenu: extensions.quickExports.map(fmt => ({ + text: fmt.label, + onClick: handler(fmt), + })), + }; +} From 8f19ce2607fc4a11d2d7b5b58c135185457cfd52 Mon Sep 17 00:00:00 2001 From: Jan Prochazka Date: Sun, 6 Jun 2021 17:59:03 +0200 Subject: [PATCH 09/12] quick export - added to grids --- .../src/appobj/DatabaseObjectAppObject.svelte | 14 +++---- .../datagrid/CollectionDataGridCore.svelte | 27 +++++++++++++ .../web/src/datagrid/JslDataGridCore.svelte | 39 ++++++++++++++++++- packages/web/src/utility/contextMenu.ts | 2 +- .../web/src/utility/createQuickExportMenu.ts | 5 +++ 5 files changed, 78 insertions(+), 9 deletions(-) diff --git a/packages/web/src/appobj/DatabaseObjectAppObject.svelte b/packages/web/src/appobj/DatabaseObjectAppObject.svelte index beaac4fc7..8acb72ccb 100644 --- a/packages/web/src/appobj/DatabaseObjectAppObject.svelte +++ b/packages/web/src/appobj/DatabaseObjectAppObject.svelte @@ -47,7 +47,7 @@ { divider: true, }, - electron && { + { isQuickExport: true, functionName: 'tableReader', }, @@ -113,8 +113,8 @@ { divider: true, }, - electron && { - label: 'Quick export', + { + isQuickExport: true, functionName: 'tableReader', }, { @@ -174,8 +174,8 @@ { divider: true, }, - electron && { - label: 'Quick export', + { + isQuickExport: true, functionName: 'tableReader', }, { @@ -274,8 +274,8 @@ }, }, }, - electron && { - label: 'Quick export', + { + isQuickExport: true, functionName: 'tableReader', }, { diff --git a/packages/web/src/datagrid/CollectionDataGridCore.svelte b/packages/web/src/datagrid/CollectionDataGridCore.svelte index 6690d58c7..eae2313f8 100644 --- a/packages/web/src/datagrid/CollectionDataGridCore.svelte +++ b/packages/web/src/datagrid/CollectionDataGridCore.svelte @@ -112,6 +112,7 @@ return response.data.count; } + Function ) { + const electron = getElectron(); + if (!electron) { + return { _skip: true }; + } return { text: 'Quick export', submenu: extensions.quickExports.map(fmt => ({ From d10dc960c5c08047ed339ed37a679b8c4ef979f7 Mon Sep 17 00:00:00 2001 From: Jan Prochazka Date: Sun, 6 Jun 2021 18:02:04 +0200 Subject: [PATCH 10/12] fix --- packages/web/src/Screen.svelte | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/web/src/Screen.svelte b/packages/web/src/Screen.svelte index 3dd219694..0b15333ab 100644 --- a/packages/web/src/Screen.svelte +++ b/packages/web/src/Screen.svelte @@ -68,10 +68,8 @@ {/if}
    - {#each $openedSnackbars as snackbar} - {#key snackbar.id} - - {/key} + {#each $openedSnackbars as snackbar(snackbar.id)} + {/each}
    From 1e59407954a8467a73977458ea956687e7c7381e Mon Sep 17 00:00:00 2001 From: Jan Prochazka Date: Sun, 6 Jun 2021 18:23:14 +0200 Subject: [PATCH 11/12] archive - export menu --- .../src/appobj/ArchiveFileAppObject.svelte | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/packages/web/src/appobj/ArchiveFileAppObject.svelte b/packages/web/src/appobj/ArchiveFileAppObject.svelte index c1da6219c..35cd5f07b 100644 --- a/packages/web/src/appobj/ArchiveFileAppObject.svelte +++ b/packages/web/src/appobj/ArchiveFileAppObject.svelte @@ -14,14 +14,19 @@ export const extractKey = data => data.fileName; export const createMatcher = ({ fileName }) => filter => filterName(filter, fileName); + Date: Sun, 6 Jun 2021 18:40:05 +0200 Subject: [PATCH 12/12] open wizard from shell - not working yet --- packages/web/src/tabs/ShellTab.svelte | 34 ++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/packages/web/src/tabs/ShellTab.svelte b/packages/web/src/tabs/ShellTab.svelte index 42ffb46bc..0e18e0bef 100644 --- a/packages/web/src/tabs/ShellTab.svelte +++ b/packages/web/src/tabs/ShellTab.svelte @@ -14,24 +14,37 @@ findReplace: true, }); + // registerCommand({ + // id: 'shell.openWizard', + // category: 'Shell', + // name: 'Open wizard', + // // testEnabled: () => getCurrentEditor()?.openWizardEnabled(), + // onClick: () => getCurrentEditor().openWizard(), + // }); + const configRegex = /\s*\/\/\s*@ImportExportConfigurator\s*\n\s*\/\/\s*(\{[^\n]+\})\n/; const requireRegex = /\s*(\/\/\s*@require\s+[^\n]+)\n/g; const initRegex = /([^\n]+\/\/\s*@init)/g; +