diff --git a/app/src/mainMenuDefinition.js b/app/src/mainMenuDefinition.js index 71d236e72..bb3696c94 100644 --- a/app/src/mainMenuDefinition.js +++ b/app/src/mainMenuDefinition.js @@ -76,6 +76,8 @@ module.exports = ({ editMenu, isMac }, currentTranslations = null) => [ { command: 'app.zoomIn', hideDisabled: true }, { command: 'app.zoomOut', hideDisabled: true }, { command: 'app.zoomReset', hideDisabled: true }, + { divider: true }, + { command: 'app.showLogs', hideDisabled: true }, ], }, { @@ -95,6 +97,8 @@ module.exports = ({ editMenu, isMac }, currentTranslations = null) => [ { divider: true }, { command: 'app.exportConnections', hideDisabled: true }, { command: 'app.importConnections', hideDisabled: true }, + { divider: true }, + { command: 'app.managePlugins', hideDisabled: true }, ], }, ...(isMac diff --git a/packages/web/src/commands/stdCommands.ts b/packages/web/src/commands/stdCommands.ts index 44582a2d2..4e69d4fbe 100644 --- a/packages/web/src/commands/stdCommands.ts +++ b/packages/web/src/commands/stdCommands.ts @@ -11,6 +11,7 @@ import { promoWidgetPreview, visibleToolbar, visibleWidgetSideBar, + selectedWidget, } from '../stores'; import registerCommand from './registerCommand'; import { get } from 'svelte/store'; @@ -767,6 +768,19 @@ if (isProApp()) { } if (hasPermission('settings/change')) { + registerCommand({ + id: 'settings.settingsTab', + category: __t('command.settings', { defaultMessage: 'Settings' }), + name: __t('command.settings.settingsTab', { defaultMessage: 'Settings tab' }), + onClick: () => { + openNewTab({ + title: _t('command.settings.settingsTab', { defaultMessage: 'Settings tab' }), + icon: 'icon settings', + tabComponent: 'SettingsTab', + props: {}, + }); + }, + }); registerCommand({ id: 'settings.commands', category: __t('command.settings', { defaultMessage: 'Settings' }), @@ -782,14 +796,14 @@ if (hasPermission('settings/change')) { testEnabled: () => hasPermission('settings/change'), }); - registerCommand({ - id: 'settings.show', - category: __t('command.settings', { defaultMessage: 'Settings' }), - name: __t('command.settings.change', { defaultMessage: 'Change' }), - toolbarName: __t('command.settings', { defaultMessage: 'Settings' }), - onClick: () => showModal(SettingsModal), - testEnabled: () => hasPermission('settings/change'), - }); + // registerCommand({ + // id: 'settings.show', + // category: __t('command.settings', { defaultMessage: 'Settings' }), + // name: __t('command.settings.change', { defaultMessage: 'Change' }), + // toolbarName: __t('command.settings', { defaultMessage: 'Settings' }), + // onClick: () => showModal(SettingsModal), + // testEnabled: () => hasPermission('settings/change'), + // }); } registerCommand({ @@ -1210,6 +1224,35 @@ registerCommand({ }, }); +if ( hasPermission('application-log')) +{ + registerCommand({ + id: 'app.showLogs', + category: __t('command.application', { defaultMessage: 'Application' }), + name: __t('command.application.showLogs', { defaultMessage: 'View application logs' }), + onClick: () => { + openNewTab({ + title: 'Application log', + icon: 'img applog', + tabComponent: 'AppLogTab', + }); + }, + }); +} + +if (hasPermission('widgets/plugins')) +{ + registerCommand({ + id: 'app.managePlugins', + category: __t('command.application', { defaultMessage: 'Application' }), + name: __t('command.application.managePlugins', { defaultMessage: 'Manage plugins' }), + onClick: () => { + selectedWidget.set('plugins'); + visibleWidgetSideBar.set(true); + }, + }); +} + const electron = getElectron(); if (electron) { electron.addEventListener('run-command', (e, commandId) => runCommand(commandId)); diff --git a/packages/web/src/elements/SettingsMenuControl.svelte b/packages/web/src/elements/SettingsMenuControl.svelte new file mode 100644 index 000000000..7669682be --- /dev/null +++ b/packages/web/src/elements/SettingsMenuControl.svelte @@ -0,0 +1,165 @@ + + +
+ + + + + + +
+ {#each _.compact(items) as item, index} +
+ +
+ {/each} +
+
+
+
+ + diff --git a/packages/web/src/settings/BehaviourSettings.svelte b/packages/web/src/settings/BehaviourSettings.svelte new file mode 100644 index 000000000..c4cb45704 --- /dev/null +++ b/packages/web/src/settings/BehaviourSettings.svelte @@ -0,0 +1,70 @@ + + +
+ +
{_t('settings.behaviour', { defaultMessage: 'Behaviour' })}
+ + + + + +
+ + {_t('settings.behaviour.singleClickPreview', { + defaultMessage: + 'When you single-click or select a file in the "Tables, Views, Functions" view, it is shown in a preview mode and reuses an existing tab (preview tab). This is useful if you are quickly browsing tables and don\'t want every visited table to have its own tab. When you start editing the table or use double-click to open the table from the "Tables" view, a new tab is dedicated to that table.', + })} +
+ + + +
{_t('settings.confirmations', { defaultMessage: 'Confirmations' })}
+ + + +
+
+ + \ No newline at end of file diff --git a/packages/web/src/settings/ConnectionSettings.svelte b/packages/web/src/settings/ConnectionSettings.svelte new file mode 100644 index 000000000..7e26bdb0c --- /dev/null +++ b/packages/web/src/settings/ConnectionSettings.svelte @@ -0,0 +1,87 @@ + + +
+ +
{_t('settings.connection', { defaultMessage: 'Connection' })}
+ + { + $lockedDatabaseMode = !$lockedDatabaseMode; + }, + }} + > + ($lockedDatabaseMode = e.target.checked)} /> + + + + + + +
{_t('settings.session', { defaultMessage: 'Query sessions' })}
+ + +
+
+ + + \ No newline at end of file diff --git a/packages/web/src/settings/DataGridSettings.svelte b/packages/web/src/settings/DataGridSettings.svelte new file mode 100644 index 000000000..6fbdf7ed6 --- /dev/null +++ b/packages/web/src/settings/DataGridSettings.svelte @@ -0,0 +1,100 @@ + + +
+
{_t('settings.dataGrid.title', { defaultMessage: 'Data grid' })}
+ +{#if isProApp()} + +{/if} + + + + + + + + + + + + + +
+ + \ No newline at end of file diff --git a/packages/web/src/settings/DefaultActionsSettings.svelte b/packages/web/src/settings/DefaultActionsSettings.svelte new file mode 100644 index 000000000..c0c293780 --- /dev/null +++ b/packages/web/src/settings/DefaultActionsSettings.svelte @@ -0,0 +1,103 @@ + + +
+ +
{_t('settings.defaultActions', { defaultMessage: 'Default actions' })}
+ + + + + + + + + + + + + +
+
+ + + \ No newline at end of file diff --git a/packages/web/src/settings/ExternalToolsSettings.svelte b/packages/web/src/settings/ExternalToolsSettings.svelte new file mode 100644 index 000000000..56bbfbfb3 --- /dev/null +++ b/packages/web/src/settings/ExternalToolsSettings.svelte @@ -0,0 +1,50 @@ + + +
+
{_t('settings.externalTools', { defaultMessage: 'External tools' })}
+ + + + + +
+ + \ No newline at end of file diff --git a/packages/web/src/settings/GeneralSettings.svelte b/packages/web/src/settings/GeneralSettings.svelte new file mode 100644 index 000000000..acff0fedb --- /dev/null +++ b/packages/web/src/settings/GeneralSettings.svelte @@ -0,0 +1,100 @@ + +
+
{_t('settings.general', { defaultMessage: 'General' })}
+{#if electron} +
{_t('settings.appearance', { defaultMessage: 'Appearance' })}
+ { + restartWarning = true; + }} + /> + {#if restartWarning} +
+ + {_t('settings.nativeMenuRestartWarning', { + defaultMessage: 'Native menu settings will be applied after app restart', + })} +
+ {/if} +{/if} + + +
{_t('settings.localization', { defaultMessage: 'Localization' })}
+ + + { + setSelectedLanguage(e.detail); + showModal(ConfirmModal, { + message: _t('settings.localization.reloadWarning', { + defaultMessage: 'Application will be reloaded to apply new language settings', + }), + onConfirm: () => { + setTimeout(() => { + internalRedirectTo(electron ? '/index.html' : '/'); + }, 100); + }, + }); + }} +/> + +
+ + \ No newline at end of file diff --git a/packages/web/src/settings/LicenseSettings.svelte b/packages/web/src/settings/LicenseSettings.svelte new file mode 100644 index 000000000..f9261d8b1 --- /dev/null +++ b/packages/web/src/settings/LicenseSettings.svelte @@ -0,0 +1,91 @@ + + +
{_t('settings.other.license', { defaultMessage: 'License' })}
+ { + licenseKeyCheckResult = await apiCall('config/check-license', { licenseKey: value }); +}} +/> +{#if licenseKeyCheckResult} +
+ {#if licenseKeyCheckResult.status == 'ok'} +
+ + {_t('settings.other.licenseKey.valid', { defaultMessage: 'License key is valid' })} +
+ {#if licenseKeyCheckResult.validTo} +
+ {_t('settings.other.licenseKey.validTo', { defaultMessage: 'License valid to:' })} + {licenseKeyCheckResult.validTo} +
+ {/if} + {#if licenseKeyCheckResult.expiration} +
+ {_t('settings.other.licenseKey.expiration', { defaultMessage: 'License key expiration:' })} + {safeFormatDate(licenseKeyCheckResult.expiration)} +
+ {/if} + {:else if licenseKeyCheckResult.status == 'error'} +
+ + {licenseKeyCheckResult.errorMessage ?? + _t('settings.other.licenseKey.invalid', { defaultMessage: 'License key is invalid' })} + {#if licenseKeyCheckResult.expiration} +
+ {_t('settings.other.licenseKey.expiration', { defaultMessage: 'License key expiration:' })} + {safeFormatDate(licenseKeyCheckResult.expiration)} +
+ {/if} +
+ {#if licenseKeyCheckResult.isExpired} +
+ { + licenseKeyCheckResult = await apiCall('config/get-new-license', { oldLicenseKey: licenseKey }); + if (licenseKeyCheckResult.licenseKey) { + apiCall('config/update-settings', { 'other.licenseKey': licenseKeyCheckResult.licenseKey }); + } + }} + /> +
+ {/if} + {/if} +
+{/if} + + \ No newline at end of file diff --git a/packages/web/src/settings/OtherSettings.svelte b/packages/web/src/settings/OtherSettings.svelte new file mode 100644 index 000000000..7ab2f36bb --- /dev/null +++ b/packages/web/src/settings/OtherSettings.svelte @@ -0,0 +1,64 @@ + + +
+
{_t('settings.other', { defaultMessage: 'Other' })}
+ + + + + +{#if isProApp()} + +{/if} +
+ + + \ No newline at end of file diff --git a/packages/web/src/settings/SQLEditorSettings.svelte b/packages/web/src/settings/SQLEditorSettings.svelte new file mode 100644 index 000000000..5829986e4 --- /dev/null +++ b/packages/web/src/settings/SQLEditorSettings.svelte @@ -0,0 +1,100 @@ + + +
+
{_t('settings.sqlEditor', { defaultMessage: 'SQL editor' })}
+ +
+
+ +
+
+ + ({ label: mode.label, value: mode.value }))} + value={$currentEditorKeybindigMode} + on:change={e => ($currentEditorKeybindigMode = e.detail)} + /> + +
+
+ + ($currentEditorWrapEnabled = e.target.checked)} + /> + +
+
+ + + + + + + + + + +
+ + \ No newline at end of file diff --git a/packages/web/src/settings/ThemeSettings.svelte b/packages/web/src/settings/ThemeSettings.svelte new file mode 100644 index 000000000..7d13e17d0 --- /dev/null +++ b/packages/web/src/settings/ThemeSettings.svelte @@ -0,0 +1,164 @@ + + +
+
{_t('settings.appearance', { defaultMessage: 'Application theme' })}
+ + { + if ($currentTheme) { + $currentTheme = null; + } else { + $currentTheme = getSystemTheme(); + } + }, + }} + > + { + if (e.target['checked']) { + $currentTheme = null; + } else { + $currentTheme = getSystemTheme(); + } + }} + /> + + +
+ {#each $extensions.themes as theme} + + {/each} +
+ +
+ {_t('settings.appearance.moreThemes', { defaultMessage: 'More themes are available as' })} + plugins +
+ {_t('settings.appearance.afterInstalling', { + defaultMessage: + 'After installing theme plugin (try search "theme" in available extensions) new themes will be available here.', + })} +
+ +
{_t('settings.appearance.editorTheme', { defaultMessage: 'Editor theme' })}
+ +
+
+ + ({ label: theme, value: theme }))} + value={$currentEditorTheme} + on:change={e => ($currentEditorTheme = e.detail)} + /> + +
+ +
+ + x.value == $currentEditorFontSize) ? $currentEditorFontSize : 'custom'} + on:change={e => ($currentEditorFontSize = e.detail)} + /> + +
+ +
+ + ($currentEditorFontSize = e.target['value'])} + disabled={!!FONT_SIZES.find(x => x.value == $currentEditorFontSize) && + $currentEditorFontSize != 'custom'} + /> + +
+ +
+ +
+
+ +
+ +
+
+ + \ No newline at end of file diff --git a/packages/web/src/tabs/SettingsTab.svelte b/packages/web/src/tabs/SettingsTab.svelte new file mode 100644 index 000000000..e4e89c8f9 --- /dev/null +++ b/packages/web/src/tabs/SettingsTab.svelte @@ -0,0 +1,121 @@ + + + + + + + \ No newline at end of file diff --git a/packages/web/src/tabs/index.js b/packages/web/src/tabs/index.js index f8c0cdd8b..1e34e5102 100644 --- a/packages/web/src/tabs/index.js +++ b/packages/web/src/tabs/index.js @@ -25,6 +25,7 @@ import * as ServerSummaryTab from './ServerSummaryTab.svelte'; import * as ImportExportTab from './ImportExportTab.svelte'; import * as SqlObjectTab from './SqlObjectTab.svelte'; import * as AppLogTab from './AppLogTab.svelte'; +import * as SettingsTab from './SettingsTab.svelte'; import protabs from './index-pro'; @@ -56,5 +57,6 @@ export default { ImportExportTab, SqlObjectTab, AppLogTab, + SettingsTab, ...protabs, }; diff --git a/packages/web/src/widgets/WidgetIconPanel.svelte b/packages/web/src/widgets/WidgetIconPanel.svelte index fa812c188..505f04946 100644 --- a/packages/web/src/widgets/WidgetIconPanel.svelte +++ b/packages/web/src/widgets/WidgetIconPanel.svelte @@ -113,32 +113,12 @@ //const handleChangeWidget= e => (selectedWidget.set(item.name)) function handleSettingsMenu() { - const rect = domSettings.getBoundingClientRect(); - const left = rect.right; - const top = rect.bottom; - const items = [ - hasPermission('settings/change') && { command: 'settings.show' }, - { command: 'theme.changeTheme' }, - hasPermission('settings/change') && { command: 'settings.commands' }, - hasPermission('widgets/plugins') && { - text: _t('widgets.managePlugins', { defaultMessage: 'Manage plugins' }), - onClick: () => { - $selectedWidget = 'plugins'; - $visibleWidgetSideBar = true; - }, - }, - hasPermission('application-log') && { - text: _t('widgets.viewApplicationLogs', { defaultMessage: 'View application logs' }), - onClick: () => { - openNewTab({ - title: 'Application log', - icon: 'img applog', - tabComponent: 'AppLogTab', - }); - }, - }, - ]; - currentDropDownMenu.set({ left, top, items }); + openNewTab({ + title: 'Settings', + icon: 'icon settings', + tabComponent: 'SettingsTab', + props: {}, + }); } function handleCloudAccountMenu() {