From c6b5ee164b94368f9b9706b9b754c1269291bbeb Mon Sep 17 00:00:00 2001 From: Stela Augustinova Date: Wed, 26 Nov 2025 16:21:07 +0100 Subject: [PATCH 1/7] Added settings tab and settings components --- packages/web/src/commands/stdCommands.ts | 13 + .../src/elements/SettingsMenuControl.svelte | 166 +++++++++++ .../web/src/settings/BehaviourSettings.svelte | 68 +++++ .../src/settings/ConnectionSettings.svelte | 89 ++++++ .../settings/DefaultActionsSettings.svelte | 105 +++++++ .../src/settings/ExternalToolsSettings.svelte | 52 ++++ .../web/src/settings/GeneralSettings.svelte | 259 ++++++++++++++++++ .../web/src/settings/LicenseSettings.svelte | 96 +++++++ .../web/src/settings/OtherSettings.svelte | 66 +++++ .../web/src/settings/ThemeSettings.svelte | 169 ++++++++++++ packages/web/src/tabs/SettingsTab.svelte | 85 ++++++ packages/web/src/tabs/index.js | 2 + .../web/src/widgets/WidgetIconPanel.svelte | 1 + 13 files changed, 1171 insertions(+) create mode 100644 packages/web/src/elements/SettingsMenuControl.svelte create mode 100644 packages/web/src/settings/BehaviourSettings.svelte create mode 100644 packages/web/src/settings/ConnectionSettings.svelte create mode 100644 packages/web/src/settings/DefaultActionsSettings.svelte create mode 100644 packages/web/src/settings/ExternalToolsSettings.svelte create mode 100644 packages/web/src/settings/GeneralSettings.svelte create mode 100644 packages/web/src/settings/LicenseSettings.svelte create mode 100644 packages/web/src/settings/OtherSettings.svelte create mode 100644 packages/web/src/settings/ThemeSettings.svelte create mode 100644 packages/web/src/tabs/SettingsTab.svelte diff --git a/packages/web/src/commands/stdCommands.ts b/packages/web/src/commands/stdCommands.ts index 1b6db8bdc..100bb6332 100644 --- a/packages/web/src/commands/stdCommands.ts +++ b/packages/web/src/commands/stdCommands.ts @@ -767,6 +767,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' }), diff --git a/packages/web/src/elements/SettingsMenuControl.svelte b/packages/web/src/elements/SettingsMenuControl.svelte new file mode 100644 index 000000000..8fc1bd875 --- /dev/null +++ b/packages/web/src/elements/SettingsMenuControl.svelte @@ -0,0 +1,166 @@ + + +
+ + + + + + +
+ {#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..95d32d5f0 --- /dev/null +++ b/packages/web/src/settings/BehaviourSettings.svelte @@ -0,0 +1,68 @@ + + + +
{_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..b57df5786 --- /dev/null +++ b/packages/web/src/settings/ConnectionSettings.svelte @@ -0,0 +1,89 @@ + + + +
{_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/DefaultActionsSettings.svelte b/packages/web/src/settings/DefaultActionsSettings.svelte new file mode 100644 index 000000000..ab360f830 --- /dev/null +++ b/packages/web/src/settings/DefaultActionsSettings.svelte @@ -0,0 +1,105 @@ + + + +
{_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..0547094ac --- /dev/null +++ b/packages/web/src/settings/ExternalToolsSettings.svelte @@ -0,0 +1,52 @@ + + +
{_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..d8375fd5c --- /dev/null +++ b/packages/web/src/settings/GeneralSettings.svelte @@ -0,0 +1,259 @@ + + +{#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); + }, + }); + }} +/> + + +
{_t('settings.dataGrid.title', { defaultMessage: 'Data grid' })}
+ +{#if isProApp()} + +{/if} + + + + + + + + + + + + + + +
{_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/LicenseSettings.svelte b/packages/web/src/settings/LicenseSettings.svelte new file mode 100644 index 000000000..d25f6c51c --- /dev/null +++ b/packages/web/src/settings/LicenseSettings.svelte @@ -0,0 +1,96 @@ + + +
{_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..80d94d067 --- /dev/null +++ b/packages/web/src/settings/OtherSettings.svelte @@ -0,0 +1,66 @@ + + +
{_t('settings.other', { defaultMessage: 'Other' })}
+ + + + + +{#if isProApp()} + +{/if} + + \ 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..80590f25d --- /dev/null +++ b/packages/web/src/settings/ThemeSettings.svelte @@ -0,0 +1,169 @@ + + +
{_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..4598926c7 --- /dev/null +++ b/packages/web/src/tabs/SettingsTab.svelte @@ -0,0 +1,85 @@ + + + + + \ 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 4dfef5ab5..9d9a4360f 100644 --- a/packages/web/src/widgets/WidgetIconPanel.svelte +++ b/packages/web/src/widgets/WidgetIconPanel.svelte @@ -118,6 +118,7 @@ const top = rect.bottom; const items = [ hasPermission('settings/change') && { command: 'settings.show' }, + hasPermission('settings/change') && { command: 'settings.settingsTab' }, { command: 'theme.changeTheme' }, hasPermission('settings/change') && { command: 'settings.commands' }, hasPermission('widgets/plugins') && { From 06a9a93d1c90eb29fd9bd59d0812e1ea39dfdfa7 Mon Sep 17 00:00:00 2001 From: Stela Augustinova Date: Thu, 27 Nov 2025 09:11:33 +0100 Subject: [PATCH 2/7] Added translation tag for settings --- .../web/src/settings/GeneralSettings.svelte | 2 +- packages/web/src/tabs/SettingsTab.svelte | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/packages/web/src/settings/GeneralSettings.svelte b/packages/web/src/settings/GeneralSettings.svelte index d8375fd5c..6ece49d79 100644 --- a/packages/web/src/settings/GeneralSettings.svelte +++ b/packages/web/src/settings/GeneralSettings.svelte @@ -19,7 +19,7 @@ const electron = getElectron(); let restartWarning = false; - +
{_t('settings.general', { defaultMessage: 'General' })}
{#if electron}
{_t('settings.appearance', { defaultMessage: 'Appearance' })}
Date: Thu, 27 Nov 2025 09:23:36 +0100 Subject: [PATCH 3/7] Added keyboard shortcuts to settings tab --- packages/web/src/tabs/SettingsTab.svelte | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/web/src/tabs/SettingsTab.svelte b/packages/web/src/tabs/SettingsTab.svelte index ecc4e6b9b..f86f73be2 100644 --- a/packages/web/src/tabs/SettingsTab.svelte +++ b/packages/web/src/tabs/SettingsTab.svelte @@ -12,6 +12,7 @@ import LicenseSettings from "../settings/LicenseSettings.svelte"; import { isProApp } from "../utility/proTools"; import { _t } from "../translations"; + import CommandListTab from "./CommandListTab.svelte"; const menuItems = [ { @@ -56,6 +57,13 @@ props: {}, testid: 'settings-external-tools', }, + { + label: _t('command.settings.shortcuts', { defaultMessage: 'Keyboard shortcuts' }), + identifier: 'shortcuts', + component: CommandListTab, + props: {}, + testid: 'settings-shortcuts', + }, isProApp() && { label: _t('settings.license', { defaultMessage: 'License' }), identifier: 'license', From 21eb27f6e383368716abc058054d24899c44a1b2 Mon Sep 17 00:00:00 2001 From: Stela Augustinova Date: Thu, 27 Nov 2025 14:42:24 +0100 Subject: [PATCH 4/7] Added new settings components, added wrapper to all setting components --- .../src/elements/SettingsMenuControl.svelte | 3 +- .../web/src/settings/BehaviourSettings.svelte | 2 + .../src/settings/ConnectionSettings.svelte | 3 + .../web/src/settings/DataGridSettings.svelte | 100 +++++++++ .../settings/DefaultActionsSettings.svelte | 3 + .../src/settings/ExternalToolsSettings.svelte | 2 + .../web/src/settings/GeneralSettings.svelte | 158 +------------- .../web/src/settings/OtherSettings.svelte | 3 + .../web/src/settings/SQLEditorSettings.svelte | 100 +++++++++ .../web/src/settings/ThemeSettings.svelte | 202 +++++++++--------- packages/web/src/tabs/SettingsTab.svelte | 16 ++ 11 files changed, 333 insertions(+), 259 deletions(-) create mode 100644 packages/web/src/settings/DataGridSettings.svelte create mode 100644 packages/web/src/settings/SQLEditorSettings.svelte diff --git a/packages/web/src/elements/SettingsMenuControl.svelte b/packages/web/src/elements/SettingsMenuControl.svelte index 8fc1bd875..7669682be 100644 --- a/packages/web/src/elements/SettingsMenuControl.svelte +++ b/packages/web/src/elements/SettingsMenuControl.svelte @@ -101,7 +101,7 @@ height: 100%; width: 100%; background-color: var(--theme-bg-2); - overflow-y: auto; + overflow-x: auto; } .menu::-webkit-scrollbar { @@ -111,7 +111,6 @@ .menu-item { white-space: nowrap; padding: 12px 20px; - width: 100%; display: flex; align-items: center; cursor: pointer; diff --git a/packages/web/src/settings/BehaviourSettings.svelte b/packages/web/src/settings/BehaviourSettings.svelte index 95d32d5f0..c4cb45704 100644 --- a/packages/web/src/settings/BehaviourSettings.svelte +++ b/packages/web/src/settings/BehaviourSettings.svelte @@ -5,6 +5,7 @@ import FormValues from "../forms/FormValues.svelte"; +
{_t('settings.behaviour', { defaultMessage: 'Behaviour' })}
@@ -52,6 +53,7 @@ })} />
+
\ No newline at end of file diff --git a/packages/web/src/settings/DefaultActionsSettings.svelte b/packages/web/src/settings/DefaultActionsSettings.svelte index ab360f830..a19d00ec0 100644 --- a/packages/web/src/settings/DefaultActionsSettings.svelte +++ b/packages/web/src/settings/DefaultActionsSettings.svelte @@ -8,6 +8,7 @@ +
{_t('settings.defaultActions', { defaultMessage: 'Default actions' })}
@@ -88,6 +89,8 @@ disabled={values['defaultAction.useLastUsedAction'] !== false} />
+
+ \ No newline at end of file diff --git a/packages/web/src/settings/ThemeSettings.svelte b/packages/web/src/settings/ThemeSettings.svelte index 80590f25d..4af6ad926 100644 --- a/packages/web/src/settings/ThemeSettings.svelte +++ b/packages/web/src/settings/ThemeSettings.svelte @@ -35,109 +35,110 @@ ORDER BY `; -
{_t('settings.appearance', { defaultMessage: 'Application theme' })}
+
+
{_t('settings.appearance', { defaultMessage: 'Application theme' })}
- { - if ($currentTheme) { - $currentTheme = null; - } else { - $currentTheme = getSystemTheme(); - } - }, -}} -> - { - if (e.target['checked']) { - $currentTheme = null; - } else { - $currentTheme = getSystemTheme(); - } - }} -/> - + { + if ($currentTheme) { + $currentTheme = null; + } else { + $currentTheme = getSystemTheme(); + } + }, + }} + > + { + if (e.target['checked']) { + $currentTheme = null; + } else { + $currentTheme = getSystemTheme(); + } + }} + /> + -
-{#each $extensions.themes as theme} - -{/each} +
+ {#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'} + /> + +
+ +
+ +
+
+ +
+ +
-
-{_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/settings/DefaultActionsSettings.svelte b/packages/web/src/settings/DefaultActionsSettings.svelte index a19d00ec0..c0c293780 100644 --- a/packages/web/src/settings/DefaultActionsSettings.svelte +++ b/packages/web/src/settings/DefaultActionsSettings.svelte @@ -100,9 +100,4 @@ margin-top: var(--dim-large-form-margin); } - .tip { - margin-left: var(--dim-large-form-margin); - margin-top: var(--dim-large-form-margin); - } - \ No newline at end of file diff --git a/packages/web/src/settings/ExternalToolsSettings.svelte b/packages/web/src/settings/ExternalToolsSettings.svelte index a5958e4f6..56bbfbfb3 100644 --- a/packages/web/src/settings/ExternalToolsSettings.svelte +++ b/packages/web/src/settings/ExternalToolsSettings.svelte @@ -47,8 +47,4 @@ margin-top: var(--dim-large-form-margin); } - .tip { - margin-left: var(--dim-large-form-margin); - margin-top: var(--dim-large-form-margin); - } \ No newline at end of file diff --git a/packages/web/src/settings/GeneralSettings.svelte b/packages/web/src/settings/GeneralSettings.svelte index 459480980..acff0fedb 100644 --- a/packages/web/src/settings/GeneralSettings.svelte +++ b/packages/web/src/settings/GeneralSettings.svelte @@ -97,9 +97,4 @@ type="combo" margin-top: var(--dim-large-form-margin); } - .tip { - margin-left: var(--dim-large-form-margin); - margin-top: var(--dim-large-form-margin); - } - \ No newline at end of file diff --git a/packages/web/src/settings/LicenseSettings.svelte b/packages/web/src/settings/LicenseSettings.svelte index d25f6c51c..f9261d8b1 100644 --- a/packages/web/src/settings/LicenseSettings.svelte +++ b/packages/web/src/settings/LicenseSettings.svelte @@ -88,9 +88,4 @@ onChange={async value => { margin-left: var(--dim-large-form-margin); margin-top: var(--dim-large-form-margin); } - - .tip { - margin-left: var(--dim-large-form-margin); - margin-top: var(--dim-large-form-margin); - } \ No newline at end of file diff --git a/packages/web/src/settings/OtherSettings.svelte b/packages/web/src/settings/OtherSettings.svelte index 6ad9709b4..7ab2f36bb 100644 --- a/packages/web/src/settings/OtherSettings.svelte +++ b/packages/web/src/settings/OtherSettings.svelte @@ -61,9 +61,4 @@ options={[ margin-left: var(--dim-large-form-margin); margin-top: var(--dim-large-form-margin); } - - .tip { - margin-left: var(--dim-large-form-margin); - margin-top: var(--dim-large-form-margin); - } \ No newline at end of file diff --git a/packages/web/src/settings/ThemeSettings.svelte b/packages/web/src/settings/ThemeSettings.svelte index 4af6ad926..7d13e17d0 100644 --- a/packages/web/src/settings/ThemeSettings.svelte +++ b/packages/web/src/settings/ThemeSettings.svelte @@ -147,11 +147,6 @@ ORDER BY margin-top: var(--dim-large-form-margin); } - .tip { - margin-left: var(--dim-large-form-margin); - margin-top: var(--dim-large-form-margin); - } - .themes { display: flex; flex-wrap: wrap;