From 0c951b46593b1a3deac30e2b95c2218bb5307698 Mon Sep 17 00:00:00 2001 From: Jan Prochazka Date: Sat, 12 Feb 2022 07:40:58 +0100 Subject: [PATCH] app menu definition in JSON --- app/package.json | 1 + app/src/electron.js | 202 ++++++++++-------- app/src/mainMenuDefinition.js | 64 ++++++ app/yarn.lock | 5 + packages/web/src/commands/stdCommands.ts | 61 ++++++ packages/web/src/elements/Link.svelte | 25 +-- packages/web/src/modals/DropDownMenu.svelte | 2 +- .../web/src/utility/exportElectronFile.ts | 10 + packages/web/src/widgets/TitleBar.svelte | 3 +- 9 files changed, 266 insertions(+), 107 deletions(-) create mode 100644 app/src/mainMenuDefinition.js diff --git a/app/package.json b/app/package.json index af5a3edc..77566f39 100644 --- a/app/package.json +++ b/app/package.json @@ -7,6 +7,7 @@ "dependencies": { "electron-log": "^4.4.1", "electron-updater": "^4.6.1", + "lodash.clonedeepwith": "^4.5.0", "patch-package": "^6.4.7" }, "repository": { diff --git a/app/src/electron.js b/app/src/electron.js index 553f4bc4..8ab81405 100644 --- a/app/src/electron.js +++ b/app/src/electron.js @@ -4,6 +4,7 @@ const fs = require('fs'); const { Menu, ipcMain } = require('electron'); const { autoUpdater } = require('electron-updater'); const log = require('electron-log'); +const _cloneDeepWith = require('lodash.clonedeepwith'); // Module to control application life. const app = electron.app; @@ -12,6 +13,7 @@ const BrowserWindow = electron.BrowserWindow; const path = require('path'); const url = require('url'); +const mainMenuDefinition = require('./mainMenuDefinition'); let isNativeMenu = true; @@ -53,96 +55,105 @@ function commandItem(id) { } function buildMenu() { - const template = [ - { - label: 'File', - submenu: [ - commandItem('new.connection'), - commandItem('new.sqliteDatabase'), - commandItem('new.modelCompare'), - commandItem('new.freetable'), - { type: 'separator' }, - commandItem('file.open'), - commandItem('file.openArchive'), - { type: 'separator' }, - commandItem('group.save'), - commandItem('group.saveAs'), - commandItem('database.search'), - { type: 'separator' }, - commandItem('tabs.closeTab'), - commandItem('file.exit'), - ], - }, - { - label: 'Window', - submenu: [commandItem('new.query'), { type: 'separator' }, commandItem('tabs.closeAll'), { role: 'minimize' }], - }, + const template = _cloneDeepWith(mainMenuDefinition, item => { + if (item.divider) { + return { type: 'separator' }; + } - // { - // label: 'Edit', - // submenu: [ - // { role: 'undo' }, - // { role: 'redo' }, - // { type: 'separator' }, - // { role: 'cut' }, - // { role: 'copy' }, - // { role: 'paste' }, - // ], - // }, - { - label: 'View', - submenu: [ - { role: 'reload' }, - { role: 'forcereload' }, - { role: 'toggledevtools' }, - { type: 'separator' }, - { role: 'resetzoom' }, - { role: 'zoomin' }, - { role: 'zoomout' }, - { type: 'separator' }, - { role: 'togglefullscreen' }, - commandItem('theme.changeTheme'), - ], - }, - { - role: 'help', - submenu: [ - { - label: 'Documentation', - click() { - electron.shell.openExternal('https://github.com/dbgate/dbgate/wiki'); - }, - }, - { - label: 'DbGate web', - click() { - electron.shell.openExternal('https://dbgate.org'); - }, - }, - { - label: 'Report problem or feature request', - click() { - electron.shell.openExternal('https://github.com/dbgate/dbgate/issues/new'); - }, - }, - { - label: 'Become sponsor', - click() { - electron.shell.openExternal('https://opencollective.com/dbgate'); - }, - }, - // { - // label: 'Discussions', - // click() { - // electron.shell.openExternal('https://github.com/dbgate/dbgate/discussions'); - // }, - // }, - { type: 'separator' }, - commandItem('tabs.changelog'), - commandItem('about.show'), - ], - }, - ]; + if (item.command) { + return commandItem(item.command); + } + }); + // const template = [ + // { + // label: 'File', + // submenu: [ + // commandItem('new.connection'), + // commandItem('new.sqliteDatabase'), + // commandItem('new.modelCompare'), + // commandItem('new.freetable'), + // { type: 'separator' }, + // commandItem('file.open'), + // commandItem('file.openArchive'), + // { type: 'separator' }, + // commandItem('group.save'), + // commandItem('group.saveAs'), + // commandItem('database.search'), + // { type: 'separator' }, + // commandItem('tabs.closeTab'), + // commandItem('file.exit'), + // ], + // }, + // { + // label: 'Window', + // submenu: [commandItem('new.query'), { type: 'separator' }, commandItem('tabs.closeAll'), { role: 'minimize' }], + // }, + + // // { + // // label: 'Edit', + // // submenu: [ + // // { role: 'undo' }, + // // { role: 'redo' }, + // // { type: 'separator' }, + // // { role: 'cut' }, + // // { role: 'copy' }, + // // { role: 'paste' }, + // // ], + // // }, + // { + // label: 'View', + // submenu: [ + // { role: 'reload' }, + // { role: 'forcereload' }, + // { role: 'toggledevtools' }, + // { type: 'separator' }, + // { role: 'resetzoom' }, + // { role: 'zoomin' }, + // { role: 'zoomout' }, + // { type: 'separator' }, + // { role: 'togglefullscreen' }, + // commandItem('theme.changeTheme'), + // ], + // }, + // { + // role: 'help', + // submenu: [ + // { + // label: 'Documentation', + // click() { + // electron.shell.openExternal('https://github.com/dbgate/dbgate/wiki'); + // }, + // }, + // { + // label: 'DbGate web', + // click() { + // electron.shell.openExternal('https://dbgate.org'); + // }, + // }, + // { + // label: 'Report problem or feature request', + // click() { + // electron.shell.openExternal('https://github.com/dbgate/dbgate/issues/new'); + // }, + // }, + // { + // label: 'Become sponsor', + // click() { + // electron.shell.openExternal('https://opencollective.com/dbgate'); + // }, + // }, + // // { + // // label: 'Discussions', + // // click() { + // // electron.shell.openExternal('https://github.com/dbgate/dbgate/discussions'); + // // }, + // // }, + // { type: 'separator' }, + // commandItem('tabs.changelog'), + // commandItem('about.show'), + // ], + // }, + // ]; return Menu.buildFromTemplate(template); } @@ -170,6 +181,9 @@ ipcMain.on('close-window', async (event, arg) => { ipcMain.on('set-title', async (event, arg) => { mainWindow.setTitle(arg); }); +ipcMain.on('open-link', async (event, arg) => { + electron.shell.openExternal(arg); +}); ipcMain.on('window-action', async (event, arg) => { switch (arg) { case 'minimize': @@ -185,6 +199,15 @@ ipcMain.on('window-action', async (event, arg) => { case 'close': mainWindow.close(); break; + case 'fullscreen': + mainWindow.setFullScreen(!mainWindow.isFullScreen()); + break; + case 'devtools': + mainWindow.webContents.toggleDevTools(); + break; + case 'reload': + mainWindow.webContents.reloadIgnoringCache(); + break; } mainWindow.setTitle(arg); }); @@ -212,6 +235,7 @@ function createWindow() { isNativeMenu = os.platform() == 'darwin' ? true : false; if (initialConfig['menuStyle'] == 'native') isNativeMenu = true; if (initialConfig['menuStyle'] == 'client') isNativeMenu = false; + isNativeMenu = true; mainWindow = new BrowserWindow({ width: 1200, diff --git a/app/src/mainMenuDefinition.js b/app/src/mainMenuDefinition.js new file mode 100644 index 00000000..702bd008 --- /dev/null +++ b/app/src/mainMenuDefinition.js @@ -0,0 +1,64 @@ +module.exports = [ + { + label: 'File', + submenu: [ + { command: 'new.connection' }, + { command: 'new.sqliteDatabase' }, + { divider: true }, + { command: 'file.open' }, + { command: 'file.openArchive' }, + { divider: true }, + { command: 'group.save' }, + { command: 'group.saveAs' }, + { command: 'database.search' }, + { divider: true }, + + { command: 'file.exit' }, + ], + }, + { + label: 'Window', + submenu: [ + { command: 'new.query' }, + { command: 'new.modelCompare' }, + { command: 'new.freetable' }, + { divider: true }, + { command: 'tabs.closeTab' }, + { command: 'tabs.closeAll' }, + ], + }, + + // { + // label: 'Edit', + // submenu: [ + // { role: 'undo' }, + // { role: 'redo' }, + // { type: 'separator' }, + // { role: 'cut' }, + // { role: 'copy' }, + // { role: 'paste' }, + // ], + // }, + { + label: 'View', + submenu: [ + { command: 'app.reload' }, + { command: 'app.toggleDevTools' }, + { command: 'app.toggleFullScreen' }, + { command: 'app.minimize' }, + { command: 'theme.changeTheme' }, + ], + }, + { + label: 'help', + submenu: [ + { command: 'app.openDocs' }, + { command: 'app.openWeb' }, + { command: 'app.openIssue' }, + { command: 'app.openSponsoring' }, + { divider: true }, + { command: 'tabs.changelog' }, + { command: 'about.show' }, + ], + }, +]; diff --git a/app/yarn.lock b/app/yarn.lock index c7ca69a6..70eeb989 100644 --- a/app/yarn.lock +++ b/app/yarn.lock @@ -1455,6 +1455,11 @@ lazy-val@^1.0.4, lazy-val@^1.0.5: resolved "https://registry.yarnpkg.com/lazy-val/-/lazy-val-1.0.5.tgz#6cf3b9f5bc31cee7ee3e369c0832b7583dcd923d" integrity sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q== +lodash.clonedeepwith@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clonedeepwith/-/lodash.clonedeepwith-4.5.0.tgz#6ee30573a03a1a60d670a62ef33c10cf1afdbdd4" + integrity sha1-buMFc6A6GmDWcKYu8zwQzxr9vdQ= + lodash.escaperegexp@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz#64762c48618082518ac3df4ccf5d5886dae20347" diff --git a/packages/web/src/commands/stdCommands.ts b/packages/web/src/commands/stdCommands.ts index e855e3b4..fdfb2c34 100644 --- a/packages/web/src/commands/stdCommands.ts +++ b/packages/web/src/commands/stdCommands.ts @@ -26,6 +26,7 @@ import { removeLocalStorage } from '../utility/storageCache'; import { showSnackbarSuccess } from '../utility/snackbar'; import { apiCall } from '../utility/api'; import runCommand from './runCommand'; +import { openWebLink } from '../utility/exportElectronFile'; function themeCommand(theme: ThemeDefinition) { return { @@ -552,6 +553,66 @@ export function registerFileCommands({ } } +registerCommand({ + id: 'app.minimize', + category: 'Application', + name: 'Minimize', + testEnabled: () => getElectron() != null, + onClick: () => getElectron().send('window-action', 'minimize'), +}); + +registerCommand({ + id: 'app.toggleFullScreen', + category: 'Application', + name: 'Toggle full screen', + testEnabled: () => getElectron() != null, + onClick: () => getElectron().send('window-action', 'fullscreen'), +}); + +registerCommand({ + id: 'app.toggleDevTools', + category: 'Application', + name: 'Toggle Dev Tools', + testEnabled: () => getElectron() != null, + onClick: () => getElectron().send('window-action', 'devtools'), +}); + +registerCommand({ + id: 'app.reload', + category: 'Application', + name: 'Reload', + testEnabled: () => getElectron() != null, + onClick: () => getElectron().send('window-action', 'reload'), +}); + +registerCommand({ + id: 'app.openDocs', + category: 'Application', + name: 'Documentation', + onClick: () => openWebLink('https://github.com/dbgate/dbgate/wiki'), +}); + +registerCommand({ + id: 'app.openWeb', + category: 'Application', + name: 'DbGate web', + onClick: () => openWebLink('https://dbgate.org'), +}); + +registerCommand({ + id: 'app.openIssue', + category: 'Application', + name: 'Report problem or feature request', + onClick: () => openWebLink('https://github.com/dbgate/dbgate/issues/new'), +}); + +registerCommand({ + id: 'app.openSponsoring', + category: 'Application', + name: 'Become sponsor', + onClick: () => openWebLink('https://opencollective.com/dbgate'), +}); + const electron = getElectron(); if (electron) { electron.addEventListener('run-command', (e, commandId) => runCommand(commandId)); diff --git a/packages/web/src/elements/Link.svelte b/packages/web/src/elements/Link.svelte index a1792029..b3ce281c 100644 --- a/packages/web/src/elements/Link.svelte +++ b/packages/web/src/elements/Link.svelte @@ -1,25 +1,18 @@ -{#if onClick} - - - -{:else if electron} - electron.shell.openExternal(href)}> - - -{:else} - - - -{/if} + { + if (onClick) onClick(); + else openWebLink(href); + }} +> + +