app menu definition in JSON

This commit is contained in:
Jan Prochazka 2022-02-12 07:40:58 +01:00
parent 19a43b6fbc
commit 0c951b4659
9 changed files with 266 additions and 107 deletions

View File

@ -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": {

View File

@ -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,

View File

@ -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' },
],
},
];

View File

@ -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"

View File

@ -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));

View File

@ -1,25 +1,18 @@
<script lang="ts">
import getElectron from '../utility/getElectron';
import { openWebLink } from '../utility/exportElectronFile';
export let href = undefined;
export let onClick = undefined;
const electron = getElectron();
</script>
{#if onClick}
<a on:click={onClick}>
<slot />
</a>
{:else if electron}
<a on:click={() => electron.shell.openExternal(href)}>
<slot />
</a>
{:else}
<a {href} target="_blank" rel="noopener noreferrer">
<slot />
</a>
{/if}
<a
on:click={() => {
if (onClick) onClick();
else openWebLink(href);
}}
>
<slot />
</a>
<style>
a {

View File

@ -136,7 +136,7 @@
}}
>
<a on:click={e => handleClick(e, item)} class:disabled={item.disabled}>
{item.text}
{item.text || item.label}
{#if item.keyText}
<span class="keyText">{item.keyText}</span>
{/if}

View File

@ -78,3 +78,13 @@ export async function saveFileToDisk(
window.open(`${resolveApi()}/uploads/get?file=${resp.fileName}`, '_blank');
}
}
export function openWebLink(href) {
const electron = getElectron();
if (electron) {
electron.send('open-link', href);
} else {
window.open(href, '_blank');
}
}

View File

@ -10,7 +10,7 @@
</script>
<div class="container">
<div class="icon"><FontIcon icon="img dbgate" /></div>
<div class="icon"><img src="logo192.png" width="20" height="20" /></div>
<div class="menu">File Edit Window</div>
<div class="title">{title}</div>
@ -41,6 +41,7 @@
.title {
flex-grow: 1;
text-align: center;
/* font-weight: bold; */
}
.icon {