SYNC: settings storage changed

This commit is contained in:
Jan Prochazka
2025-12-03 11:09:09 +01:00
committed by Diflow
parent 0218bb4990
commit 6112d9b1b0
7 changed files with 185 additions and 173 deletions

View File

@@ -289,16 +289,11 @@ module.exports = {
const res = await lock.acquire('settings', async () => { const res = await lock.acquire('settings', async () => {
const currentValue = await this.loadSettings(); const currentValue = await this.loadSettings();
try { try {
let updated = currentValue; let updated = {
...currentValue,
...values,
};
if (process.env.STORAGE_DATABASE) { if (process.env.STORAGE_DATABASE) {
updated = {
...currentValue,
..._.mapValues(values, v => {
if (v === true) return 'true';
if (v === false) return 'false';
return v;
}),
};
await storage.writeConfig({ await storage.writeConfig({
group: 'settings', group: 'settings',
config: updated, config: updated,

View File

@@ -360,6 +360,12 @@ module.exports = {
"columnName": "value", "columnName": "value",
"dataType": "varchar(1000)", "dataType": "varchar(1000)",
"notNull": false "notNull": false
},
{
"pureName": "config",
"columnName": "valueType",
"dataType": "varchar(50)",
"notNull": false
} }
], ],
"foreignKeys": [], "foreignKeys": [],

View File

@@ -40,8 +40,6 @@ import { getSettings } from '../utility/metadataLoaders';
import { isMac, switchCurrentDatabase } from '../utility/common'; import { isMac, switchCurrentDatabase } from '../utility/common';
import { doLogout } from '../clientAuth'; import { doLogout } from '../clientAuth';
import { disconnectServerConnection } from '../appobj/ConnectionAppObject.svelte'; import { disconnectServerConnection } from '../appobj/ConnectionAppObject.svelte';
import UploadErrorModal from '../modals/UploadErrorModal.svelte';
import ErrorMessageModal from '../modals/ErrorMessageModal.svelte';
import NewCollectionModal from '../modals/NewCollectionModal.svelte'; import NewCollectionModal from '../modals/NewCollectionModal.svelte';
import ConfirmModal from '../modals/ConfirmModal.svelte'; import ConfirmModal from '../modals/ConfirmModal.svelte';
import localforage from 'localforage'; import localforage from 'localforage';
@@ -73,7 +71,8 @@ registerCommand({
category: __t('command.theme', { defaultMessage: 'Theme' }), category: __t('command.theme', { defaultMessage: 'Theme' }),
name: __t('command.theme.change', { defaultMessage: 'Change' }), name: __t('command.theme.change', { defaultMessage: 'Change' }),
toolbarName: __t('command.theme.changeToolbar', { defaultMessage: 'Change theme' }), toolbarName: __t('command.theme.changeToolbar', { defaultMessage: 'Change theme' }),
onClick: () => openNewTab({ onClick: () =>
openNewTab({
title: 'Settings', title: 'Settings',
icon: 'icon settings', icon: 'icon settings',
tabComponent: 'SettingsTab', tabComponent: 'SettingsTab',
@@ -1230,8 +1229,7 @@ registerCommand({
}, },
}); });
if ( hasPermission('application-log')) if (hasPermission('application-log')) {
{
registerCommand({ registerCommand({
id: 'app.showLogs', id: 'app.showLogs',
category: __t('command.application', { defaultMessage: 'Application' }), category: __t('command.application', { defaultMessage: 'Application' }),
@@ -1246,8 +1244,7 @@ if ( hasPermission('application-log'))
}); });
} }
if (hasPermission('widgets/plugins')) if (hasPermission('widgets/plugins')) {
{
registerCommand({ registerCommand({
id: 'app.managePlugins', id: 'app.managePlugins',
category: __t('command.application', { defaultMessage: 'Application' }), category: __t('command.application', { defaultMessage: 'Application' }),

View File

@@ -1,81 +1,64 @@
<script lang="ts"> <script lang="ts">
import CheckboxField from "../forms/CheckboxField.svelte"; import CheckboxField from '../forms/CheckboxField.svelte';
import FormCheckboxField from "../forms/FormCheckboxField.svelte"; import FormCheckboxField from '../forms/FormCheckboxField.svelte';
import FormFieldTemplateLarge from "../forms/FormFieldTemplateLarge.svelte"; import FormFieldTemplateLarge from '../forms/FormFieldTemplateLarge.svelte';
import FormSelectField from "../forms/FormSelectField.svelte"; import FormSelectField from '../forms/FormSelectField.svelte';
import FormTextField from "../forms/FormTextField.svelte"; import FormTextField from '../forms/FormTextField.svelte';
import FormValues from "../forms/FormValues.svelte"; import FormValues from '../forms/FormValues.svelte';
import { lockedDatabaseMode } from "../stores"; import { lockedDatabaseMode } from '../stores';
import { _t } from "../translations"; import { _t } from '../translations';
</script> </script>
<div class="wrapper"> <div class="wrapper">
<FormValues let:values> <FormValues let:values>
<div class="heading">{_t('settings.connection', { defaultMessage: 'Connection' })}</div> <div class="heading">{_t('settings.connection', { defaultMessage: 'Connection' })}</div>
<FormFieldTemplateLarge
label={_t('settings.connection.showOnlyTabsFromSelectedDatabase', {
defaultMessage: 'Show only tabs from selected database',
})}
type="checkbox"
labelProps={{
onClick: () => {
$lockedDatabaseMode = !$lockedDatabaseMode;
},
}}
>
<CheckboxField checked={$lockedDatabaseMode} on:change={e => ($lockedDatabaseMode = e.target.checked)} data-testid="ConnectionSettings_lockedDatabaseMode"/>
</FormFieldTemplateLarge>
<FormCheckboxField <FormCheckboxField
name="connection.autoRefresh" name="connection.autoRefresh"
label={_t('settings.connection.autoRefresh', { label={_t('settings.connection.autoRefresh', {
defaultMessage: 'Automatic refresh of database model on background', defaultMessage: 'Automatic refresh of database model on background',
})} })}
defaultValue={false} defaultValue={false}
/> />
<FormTextField <FormTextField
name="connection.autoRefreshInterval" name="connection.autoRefreshInterval"
label={_t('settings.connection.autoRefreshInterval', { label={_t('settings.connection.autoRefreshInterval', {
defaultMessage: 'Interval between automatic DB structure reloads in seconds', defaultMessage: 'Interval between automatic DB structure reloads in seconds',
})} })}
defaultValue="30" defaultValue="30"
disabled={values['connection.autoRefresh'] === false} disabled={values['connection.autoRefresh'] === false}
/> />
<FormSelectField <FormSelectField
label={_t('settings.connection.sshBindHost', { defaultMessage: 'Local host address for SSH connections' })} label={_t('settings.connection.sshBindHost', { defaultMessage: 'Local host address for SSH connections' })}
name="connection.sshBindHost" name="connection.sshBindHost"
isNative isNative
defaultValue="127.0.0.1" defaultValue="127.0.0.1"
options={[ options={[
{ value: '127.0.0.1', label: '127.0.0.1 (IPv4)' }, { value: '127.0.0.1', label: '127.0.0.1 (IPv4)' },
{ value: '::1', label: '::1 (IPv6)' }, { value: '::1', label: '::1 (IPv6)' },
{ value: 'localhost', label: 'localhost (domain name)' }, { value: 'localhost', label: 'localhost (domain name)' },
]} ]}
/> />
<div class="heading">{_t('settings.session', { defaultMessage: 'Query sessions' })}</div> <div class="heading">{_t('settings.session', { defaultMessage: 'Query sessions' })}</div>
<FormCheckboxField <FormCheckboxField
name="session.autoClose" name="session.autoClose"
label={_t('settings.session.autoClose', { label={_t('settings.session.autoClose', {
defaultMessage: 'Automatic close query sessions after period without any activity', defaultMessage: 'Automatic close query sessions after period without any activity',
})} })}
defaultValue={true} defaultValue={true}
/> />
<FormTextField <FormTextField
name="session.autoCloseTimeout" name="session.autoCloseTimeout"
label={_t('settings.session.autoCloseTimeout', { label={_t('settings.session.autoCloseTimeout', {
defaultMessage: 'Interval, after which query session without activity is closed (in minutes)', defaultMessage: 'Interval, after which query session without activity is closed (in minutes)',
})} })}
defaultValue="15" defaultValue="15"
disabled={values['session.autoClose'] === false} disabled={values['session.autoClose'] === false}
/> />
</FormValues> </FormValues>
</div> </div>
<style> <style>
.heading { .heading {
font-size: 20px; font-size: 20px;
@@ -84,12 +67,11 @@
margin-top: var(--dim-large-form-margin); margin-top: var(--dim-large-form-margin);
} }
.wrapper :global(input){ .wrapper :global(input) {
max-width: 400px; max-width: 400px;
} }
.wrapper :global(select){ .wrapper :global(select) {
max-width: 400px; max-width: 400px;
} }
</style>
</style>

View File

@@ -10,6 +10,9 @@
import { isMac } from '../utility/common'; import { isMac } from '../utility/common';
import getElectron from '../utility/getElectron'; import getElectron from '../utility/getElectron';
import ConfirmModal from '../modals/ConfirmModal.svelte'; import ConfirmModal from '../modals/ConfirmModal.svelte';
import hasPermission from '../utility/hasPermission';
import CheckboxField from '../forms/CheckboxField.svelte';
import { lockedDatabaseMode } from '../stores';
const electron = getElectron(); const electron = getElectron();
let restartWarning = false; let restartWarning = false;
@@ -78,6 +81,24 @@
/> />
{/if} {/if}
<FormFieldTemplateLarge
label={_t('settings.connection.showOnlyTabsFromSelectedDatabase', {
defaultMessage: 'Show only tabs from selected database',
})}
type="checkbox"
labelProps={{
onClick: () => {
$lockedDatabaseMode = !$lockedDatabaseMode;
},
}}
>
<CheckboxField
checked={$lockedDatabaseMode}
on:change={e => ($lockedDatabaseMode = e.target['checked'])}
data-testid="ConnectionSettings_lockedDatabaseMode"
/>
</FormFieldTemplateLarge>
<div class="heading">{_t('settings.appearance', { defaultMessage: 'Appearance' })}</div> <div class="heading">{_t('settings.appearance', { defaultMessage: 'Appearance' })}</div>
{#if electron} {#if electron}
@@ -106,6 +127,7 @@
defaultMessage: 'Show server name alongside database name in title of the tab group', defaultMessage: 'Show server name alongside database name in title of the tab group',
})} })}
defaultValue={false} defaultValue={false}
disabled={!hasPermission('settings/change')}
/> />
</div> </div>

View File

@@ -29,6 +29,13 @@ export function getStringSettingsValue(name, defaultValue) {
return res; return res;
} }
export function getObjectSettingsValue(name, defaultValue) {
const settings = getCurrentSettings();
const res = settings[name];
if (res == null) return defaultValue;
return res;
}
export function getConnectionClickActionSetting(): 'connect' | 'openDetails' | 'none' { export function getConnectionClickActionSetting(): 'connect' | 'openDetails' | 'none' {
return getStringSettingsValue('defaultAction.connectionClick', 'connect'); return getStringSettingsValue('defaultAction.connectionClick', 'connect');
} }

View File

@@ -3,111 +3,114 @@
</script> </script>
<script lang="ts"> <script lang="ts">
import SettingsMenuControl from "../elements/SettingsMenuControl.svelte"; import SettingsMenuControl from '../elements/SettingsMenuControl.svelte';
import GeneralSettings from "../settings/GeneralSettings.svelte"; import GeneralSettings from '../settings/GeneralSettings.svelte';
import SettingsFormProvider from "../forms/SettingsFormProvider.svelte"; import SettingsFormProvider from '../forms/SettingsFormProvider.svelte';
import ConnectionSettings from "../settings/ConnectionSettings.svelte"; import ConnectionSettings from '../settings/ConnectionSettings.svelte';
import ThemeSettings from "../settings/ThemeSettings.svelte"; import ThemeSettings from '../settings/ThemeSettings.svelte';
import DefaultActionsSettings from "../settings/DefaultActionsSettings.svelte"; import DefaultActionsSettings from '../settings/DefaultActionsSettings.svelte';
import BehaviourSettings from "../settings/BehaviourSettings.svelte"; import BehaviourSettings from '../settings/BehaviourSettings.svelte';
import ExternalToolsSettings from "../settings/ExternalToolsSettings.svelte"; import ExternalToolsSettings from '../settings/ExternalToolsSettings.svelte';
import LicenseSettings from "../settings/LicenseSettings.svelte"; import LicenseSettings from '../settings/LicenseSettings.svelte';
import { isProApp } from "../utility/proTools"; import { isProApp } from '../utility/proTools';
import { _t } from "../translations"; import { _t } from '../translations';
import CommandListTab from "./CommandListTab.svelte"; import CommandListTab from './CommandListTab.svelte';
import DataGridSettings from "../settings/DataGridSettings.svelte"; import DataGridSettings from '../settings/DataGridSettings.svelte';
import SQLEditorSettings from "../settings/SQLEditorSettings.svelte"; import SQLEditorSettings from '../settings/SQLEditorSettings.svelte';
import AiSettingsTab from "../settings/AiSettingsTab.svelte"; import AiSettingsTab from '../settings/AiSettingsTab.svelte';
import hasPermission from '../utility/hasPermission';
export let selectedItem = 'general'; export let selectedItem = 'general';
const menuItems = [ const menuItems = [
{ {
label: _t('settings.general', { defaultMessage: 'General' }), label: _t('settings.general', { defaultMessage: 'General' }),
identifier: 'general', identifier: 'general',
component: GeneralSettings, component: GeneralSettings,
props: {}, props: {},
testid: 'settings-general', testid: 'settings-general',
}, },
{ hasPermission('settings/change') && {
label: _t('settings.connection', { defaultMessage: 'Connection' }), label: _t('settings.connection', { defaultMessage: 'Connection' }),
identifier: 'connection', identifier: 'connection',
component: ConnectionSettings, component: ConnectionSettings,
props: {}, props: {},
testid: 'settings-connection', testid: 'settings-connection',
}, },
{ hasPermission('settings/change') && {
label: _t('settings.dataGrid.title', { defaultMessage: 'Data grid' }), label: _t('settings.dataGrid.title', { defaultMessage: 'Data grid' }),
identifier: 'data-grid', identifier: 'data-grid',
component: DataGridSettings, component: DataGridSettings,
props: {}, props: {},
testid: 'settings-data-grid', testid: 'settings-data-grid',
}, },
{ hasPermission('settings/change') && {
label: _t('settings.sqlEditor.title', { defaultMessage: 'SQL Editor' }), label: _t('settings.sqlEditor.title', { defaultMessage: 'SQL Editor' }),
identifier: 'sql-editor', identifier: 'sql-editor',
component: SQLEditorSettings, component: SQLEditorSettings,
props: {}, props: {},
testid: 'settings-sql-editor', testid: 'settings-sql-editor',
}, },
{ {
label: _t('settings.theme', { defaultMessage: 'Themes' }), label: _t('settings.theme', { defaultMessage: 'Themes' }),
identifier: 'theme', identifier: 'theme',
component: ThemeSettings, component: ThemeSettings,
props: {}, props: {},
testid: 'settings-themes', testid: 'settings-themes',
}, },
{ hasPermission('settings/change') && {
label: _t('settings.defaultActions', { defaultMessage: 'Default Actions' }), label: _t('settings.defaultActions', { defaultMessage: 'Default Actions' }),
identifier: 'default-actions', identifier: 'default-actions',
component: DefaultActionsSettings, component: DefaultActionsSettings,
props: {}, props: {},
testid: 'settings-default-actions', testid: 'settings-default-actions',
}, },
{ hasPermission('settings/change') && {
label: _t('settings.behaviour', { defaultMessage: 'Behaviour' }), label: _t('settings.behaviour', { defaultMessage: 'Behaviour' }),
identifier: 'behaviour', identifier: 'behaviour',
component: BehaviourSettings, component: BehaviourSettings,
props: {}, props: {},
testid: 'settings-behaviour', testid: 'settings-behaviour',
}, },
{ hasPermission('settings/change') && {
label: _t('settings.externalTools', { defaultMessage: 'External Tools' }), label: _t('settings.externalTools', { defaultMessage: 'External Tools' }),
identifier: 'external-tools', identifier: 'external-tools',
component: ExternalToolsSettings, component: ExternalToolsSettings,
props: {}, props: {},
testid: 'settings-external-tools', testid: 'settings-external-tools',
}, },
{ hasPermission('settings/change') && {
label: _t('command.settings.shortcuts', { defaultMessage: 'Keyboard shortcuts' }), label: _t('command.settings.shortcuts', { defaultMessage: 'Keyboard shortcuts' }),
identifier: 'shortcuts', identifier: 'shortcuts',
component: CommandListTab, component: CommandListTab,
props: {}, props: {},
testid: 'settings-shortcuts', testid: 'settings-shortcuts',
}, },
isProApp() && { hasPermission('settings/change') &&
label: _t('settings.license', { defaultMessage: 'License' }), isProApp() && {
identifier: 'license', label: _t('settings.license', { defaultMessage: 'License' }),
component: LicenseSettings, identifier: 'license',
props: {}, component: LicenseSettings,
testid: 'settings-license', props: {},
}, testid: 'settings-license',
isProApp() && { },
label: _t('settings.AI', { defaultMessage: 'AI'}), hasPermission('settings/change') &&
identifier: 'ai', isProApp() && {
component: AiSettingsTab, label: _t('settings.AI', { defaultMessage: 'AI' }),
props: {}, identifier: 'ai',
testid: 'settings-ai', component: AiSettingsTab,
}, props: {},
]; testid: 'settings-ai',
},
];
</script> </script>
<SettingsFormProvider> <SettingsFormProvider>
<SettingsMenuControl <SettingsMenuControl
items={menuItems} items={menuItems}
bind:value={selectedItem} bind:value={selectedItem}
flex1={true} flex1={true}
flexColContainer={true} flexColContainer={true}
scrollableContentContainer={true} scrollableContentContainer={true}
/> />
</SettingsFormProvider> </SettingsFormProvider>