diff --git a/webapp/packages/core-blocks/src/FormControls/Select.tsx b/webapp/packages/core-blocks/src/FormControls/Select.tsx
index 673210f6fd..2d5b281282 100644
--- a/webapp/packages/core-blocks/src/FormControls/Select.tsx
+++ b/webapp/packages/core-blocks/src/FormControls/Select.tsx
@@ -146,9 +146,9 @@ export const Select: SelectType = observer(function Select({
function itemRender(item: (typeof items)[number]): React.ReactNode {
return (
-
+
{renderIcon(item)}
- {valueSelector(item)}
+ {valueSelector(item)}
);
}
diff --git a/webapp/packages/core-blocks/src/ObjectPropertyInfo/ObjectPropertyInfoForm/RenderField.tsx b/webapp/packages/core-blocks/src/ObjectPropertyInfo/ObjectPropertyInfoForm/RenderField.tsx
index d22f87eb80..41d95737d4 100644
--- a/webapp/packages/core-blocks/src/ObjectPropertyInfo/ObjectPropertyInfoForm/RenderField.tsx
+++ b/webapp/packages/core-blocks/src/ObjectPropertyInfo/ObjectPropertyInfoForm/RenderField.tsx
@@ -153,6 +153,7 @@ export const RenderField = observer
(function RenderField({
items={property.validValues!}
keySelector={value => value}
valueSelector={value => value}
+ titleSelector={value => value}
defaultValue={defaultValue}
title={property.description}
disabled={disabled}
@@ -172,6 +173,7 @@ export const RenderField = observer(function RenderField({
items={property.validValues!}
keySelector={value => value}
valueSelector={value => value}
+ titleSelector={value => value}
defaultValue={defaultValue}
title={property.description}
disabled={disabled}
diff --git a/webapp/packages/core-settings-user/src/SettingsUserBootstrap.ts b/webapp/packages/core-settings-user/src/SettingsUserBootstrap.ts
index cdd1b51608..6a636ef7ab 100644
--- a/webapp/packages/core-settings-user/src/SettingsUserBootstrap.ts
+++ b/webapp/packages/core-settings-user/src/SettingsUserBootstrap.ts
@@ -1,26 +1,26 @@
/*
* CloudBeaver - Cloud Database Manager
- * Copyright (C) 2020-2024 DBeaver Corp and others
+ * Copyright (C) 2020-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { Bootstrap, injectable } from '@cloudbeaver/core-di';
import { SESSION_SETTINGS_LAYER } from '@cloudbeaver/core-root';
-import { SettingsResolverService } from '@cloudbeaver/core-settings';
+import { UserSettingsResolverService } from '@cloudbeaver/core-settings';
import { UserSettingsService } from './UserSettingsService.js';
@injectable()
export class SettingsUserBootstrap extends Bootstrap {
constructor(
- private readonly settingsResolverService: SettingsResolverService,
+ private readonly userSettingsResolverService: UserSettingsResolverService,
private readonly userSettingsService: UserSettingsService,
) {
super();
}
override register(): void {
- this.settingsResolverService.addResolver(SESSION_SETTINGS_LAYER, this.userSettingsService);
+ this.userSettingsResolverService.addResolver(SESSION_SETTINGS_LAYER, this.userSettingsService);
}
}
diff --git a/webapp/packages/core-settings/src/SettingsProviderService.ts b/webapp/packages/core-settings/src/SettingsProviderService.ts
index 29fd427da1..74b70d991f 100644
--- a/webapp/packages/core-settings/src/SettingsProviderService.ts
+++ b/webapp/packages/core-settings/src/SettingsProviderService.ts
@@ -12,15 +12,24 @@ import { schema } from '@cloudbeaver/core-utils';
import { SettingsProvider } from './SettingsProvider.js';
import { SettingsResolverService } from './SettingsResolverService.js';
+import { UserSettingsResolverService } from './UserSettingsResolverService.js';
+import { SettingsResolverSource } from './SettingsResolverSource.js';
@injectable()
export class SettingsProviderService {
get schema(): schema.ZodObject {
return this.mergedSchema;
}
+ get settingsResolver(): SettingsResolverSource {
+ return this.resolver;
+ }
private mergedSchema: schema.ZodObject;
- constructor(private readonly settingsResolverService: SettingsResolverService) {
+ private resolver: SettingsResolverSource;
+ constructor(settingsResolverService: SettingsResolverService, userSettingsResolverService: UserSettingsResolverService) {
this.mergedSchema = schema.object({});
+ this.resolver = new SettingsResolverSource();
+
+ this.resolver.add(settingsResolverService, userSettingsResolverService);
makeObservable(this, {
mergedSchema: observable.ref,
@@ -29,7 +38,7 @@ export class SettingsProviderService {
createSettings(schema: TSchema): SettingsProvider {
this.mergedSchema = this.mergedSchema.merge(schema);
- const settings = new SettingsProvider(this.settingsResolverService, schema);
+ const settings = new SettingsProvider(this.resolver, schema);
return settings;
}
}
diff --git a/webapp/packages/core-settings/src/SettingsResolverSource.ts b/webapp/packages/core-settings/src/SettingsResolverSource.ts
index 9dc01b7064..0ae3749e23 100644
--- a/webapp/packages/core-settings/src/SettingsResolverSource.ts
+++ b/webapp/packages/core-settings/src/SettingsResolverSource.ts
@@ -15,41 +15,49 @@ import type { ISettingChangeData, ISettingsSource } from './ISettingsSource.js';
import type { ISettingsLayer } from './SettingsLayer.js';
import { isEditableSettingsSource, type IEditableSettingsSource } from './IEditableSettingsSource.js';
-type SettingsSource = ISettingsSource | IEditableSettingsSource;
+type SettingsSourceUnion = ISettingsSource | IEditableSettingsSource;
interface ISettingsSourcesLayer {
layer: ISettingsLayer;
- sources: SettingsSource[];
+ sources: SettingsSourceUnion[];
}
export class SettingsResolverSource implements ISettingsResolverSource {
readonly onChange: ISyncExecutor;
- protected get sources(): SettingsSource[] {
- return this.layers
+ protected get sources(): SettingsSourceUnion[] {
+ return [...this.layers, ...this.resolvers.map(r => r.layers).flat()]
.slice()
.sort((a, b) => a.layer.level - b.layer.level)
.flatMap(layer => layer.sources)
.reverse();
}
protected layers: ISettingsSourcesLayer[];
+ protected resolvers: SettingsResolverSource[];
private updating: boolean;
constructor() {
this.onChange = new SyncExecutor();
this.layers = [];
+ this.resolvers = [];
this.updating = false;
- makeObservable(this, {
+ makeObservable(this, {
layers: observable.shallow,
sources: computed,
update: action,
+ resolvers: observable.shallow,
});
}
- hasResolver(layer: ISettingsLayer, resolver: SettingsSource): boolean {
+ add(...resolvers: SettingsResolverSource[]): this {
+ this.resolvers.push(...resolvers);
+ return this;
+ }
+
+ hasResolver(layer: ISettingsLayer, resolver: SettingsSourceUnion): boolean {
return this.tryGetLayerSources(layer)?.sources.includes(resolver) || false;
}
- removeResolver(layer: ISettingsLayer, resolver: SettingsSource): void {
+ removeResolver(layer: ISettingsLayer, resolver: SettingsSourceUnion): void {
const layerSources = this.getLayerSources(layer);
const index = layerSources.sources.indexOf(resolver);
@@ -60,7 +68,7 @@ export class SettingsResolverSource implements ISettingsResolverSource {
}
}
- addResolver(layer: ISettingsLayer, ...resolvers: SettingsSource[]): void {
+ addResolver(layer: ISettingsLayer, ...resolvers: SettingsSourceUnion[]): void {
if (resolvers.some(this.hasResolver.bind(this, layer))) {
return;
}
diff --git a/webapp/packages/core-settings/src/UserSettingsResolverService.ts b/webapp/packages/core-settings/src/UserSettingsResolverService.ts
new file mode 100644
index 0000000000..f5790b10e5
--- /dev/null
+++ b/webapp/packages/core-settings/src/UserSettingsResolverService.ts
@@ -0,0 +1,17 @@
+/*
+ * CloudBeaver - Cloud Database Manager
+ * Copyright (C) 2020-2025 DBeaver Corp and others
+ *
+ * Licensed under the Apache License, Version 2.0.
+ * you may not use this file except in compliance with the License.
+ */
+import { injectable } from '@cloudbeaver/core-di';
+
+import { SettingsResolverSource } from './SettingsResolverSource.js';
+
+@injectable()
+export class UserSettingsResolverService extends SettingsResolverSource {
+ constructor() {
+ super();
+ }
+}
diff --git a/webapp/packages/core-settings/src/index.ts b/webapp/packages/core-settings/src/index.ts
index b4ea35f491..ae7caf63a7 100644
--- a/webapp/packages/core-settings/src/index.ts
+++ b/webapp/packages/core-settings/src/index.ts
@@ -14,6 +14,7 @@ export * from './ISettingsResolverSource.js';
export * from './IEditableSettingsSource.js';
export * from './ISettingsSource.js';
export * from './SettingsLayer.js';
+export * from './UserSettingsResolverService.js';
export * from './SettingsResolverService.js';
export * from './SettingsProvider.js';
export * from './SettingsProviderService.js';
diff --git a/webapp/packages/core-settings/src/manifest.ts b/webapp/packages/core-settings/src/manifest.ts
index c99ec45428..355f1d8231 100644
--- a/webapp/packages/core-settings/src/manifest.ts
+++ b/webapp/packages/core-settings/src/manifest.ts
@@ -1,6 +1,6 @@
/*
* CloudBeaver - Cloud Database Manager
- * Copyright (C) 2020-2024 DBeaver Corp and others
+ * Copyright (C) 2020-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
@@ -15,6 +15,7 @@ export const coreSettingsManifest: PluginManifest = {
providers: [
() => import('./SettingsManager/SettingsManagerService.js').then(m => m.SettingsManagerService),
() => import('./SettingsResolverService.js').then(m => m.SettingsResolverService),
+ () => import('./UserSettingsResolverService.js').then(m => m.UserSettingsResolverService),
() => import('./LocaleService.js').then(m => m.LocaleService),
() => import('./SettingsProviderService.js').then(m => m.SettingsProviderService),
],
diff --git a/webapp/packages/core-theming/src/SystemThemeService.ts b/webapp/packages/core-theming/src/SystemThemeService.ts
index 2cafef2fff..5f5bafae91 100644
--- a/webapp/packages/core-theming/src/SystemThemeService.ts
+++ b/webapp/packages/core-theming/src/SystemThemeService.ts
@@ -61,6 +61,15 @@ export class SystemThemeService extends Bootstrap {
}
return undefined;
},
+ getEditedValue(key) {
+ if (key === 'core.theming.theme') {
+ return 'system';
+ }
+ return undefined;
+ },
+ isEdited(key) {
+ return false;
+ },
});
}
diff --git a/webapp/packages/plugin-settings-panel/src/SettingsPanel/Setting.tsx b/webapp/packages/plugin-settings-panel/src/SettingsPanel/Setting.tsx
index f6083f2e55..0844a7251c 100644
--- a/webapp/packages/plugin-settings-panel/src/SettingsPanel/Setting.tsx
+++ b/webapp/packages/plugin-settings-panel/src/SettingsPanel/Setting.tsx
@@ -9,11 +9,11 @@ import { observer } from 'mobx-react-lite';
import { Link, useTranslate } from '@cloudbeaver/core-blocks';
import { clsx } from '@dbeaver/ui-kit';
-import { SettingsResolverSource, type ISettingDescription, type IEditableSettingsSource } from '@cloudbeaver/core-settings';
+import { type ISettingDescription, type IEditableSettingsSource, type ISettingsResolverSource } from '@cloudbeaver/core-settings';
import { SettingField } from './SettingField.js';
interface Props {
- resolver: SettingsResolverSource;
+ resolver: ISettingsResolverSource;
source: IEditableSettingsSource;
setting: ISettingDescription;
displayRestore?: boolean;
diff --git a/webapp/packages/plugin-settings-panel/src/SettingsPanel/SettingField.tsx b/webapp/packages/plugin-settings-panel/src/SettingsPanel/SettingField.tsx
index 927f81708e..c21a8a0901 100644
--- a/webapp/packages/plugin-settings-panel/src/SettingsPanel/SettingField.tsx
+++ b/webapp/packages/plugin-settings-panel/src/SettingsPanel/SettingField.tsx
@@ -11,16 +11,16 @@ import { useService } from '@cloudbeaver/core-di';
import {
ESettingsValueType,
SettingsProviderService,
- SettingsResolverSource,
type ISettingDescription,
type IEditableSettingsSource,
+ type ISettingsResolverSource,
} from '@cloudbeaver/core-settings';
import { schemaValidationError } from '@cloudbeaver/core-utils';
import { isNotNullDefined } from '@dbeaver/js-helpers';
import { observer } from 'mobx-react-lite';
interface Props {
- resolver: SettingsResolverSource;
+ resolver: ISettingsResolverSource;
source: IEditableSettingsSource;
setting: ISettingDescription;
}
diff --git a/webapp/packages/plugin-settings-panel/src/SettingsPanel/Settings.tsx b/webapp/packages/plugin-settings-panel/src/SettingsPanel/Settings.tsx
index 1bba7e5416..a45d217100 100644
--- a/webapp/packages/plugin-settings-panel/src/SettingsPanel/Settings.tsx
+++ b/webapp/packages/plugin-settings-panel/src/SettingsPanel/Settings.tsx
@@ -9,7 +9,7 @@ import { useId, useState } from 'react';
import { observer } from 'mobx-react-lite';
import { Container, Filter, getComputed, Group, s, TextPlaceholder, useTranslate } from '@cloudbeaver/core-blocks';
-import { type IEditableSettingsSource, ROOT_SETTINGS_GROUP, SettingsGroup, SettingsResolverSource } from '@cloudbeaver/core-settings';
+import { type IEditableSettingsSource, type ISettingsResolverSource, ROOT_SETTINGS_GROUP, SettingsGroup } from '@cloudbeaver/core-settings';
import { useTreeData, useTreeFilter } from '@cloudbeaver/plugin-navigation-tree';
import { SyncExecutor } from '@cloudbeaver/core-executor';
@@ -20,7 +20,7 @@ import { SettingsList } from './SettingsList.js';
import { useSettings } from './useSettings.js';
export interface ISettingsProps {
- resolver: SettingsResolverSource;
+ resolver: ISettingsResolverSource;
source: IEditableSettingsSource;
accessor?: string[];
hideGroupsSettingsLimit?: number;
diff --git a/webapp/packages/plugin-settings-panel/src/SettingsPanel/SettingsGroup.tsx b/webapp/packages/plugin-settings-panel/src/SettingsPanel/SettingsGroup.tsx
index d545784ba8..828d71696b 100644
--- a/webapp/packages/plugin-settings-panel/src/SettingsPanel/SettingsGroup.tsx
+++ b/webapp/packages/plugin-settings-panel/src/SettingsPanel/SettingsGroup.tsx
@@ -11,8 +11,8 @@ import { getComputed, Group, GroupTitle, useExecutor, useTranslate } from '@clou
import type {
IEditableSettingsSource,
ISettingDescription,
+ ISettingsResolverSource,
SettingsGroup as SettingsGroupType,
- SettingsResolverSource,
} from '@cloudbeaver/core-settings';
import { isArraysEqual } from '@cloudbeaver/core-utils';
import type { ITreeFilter } from '@cloudbeaver/plugin-navigation-tree';
@@ -27,7 +27,7 @@ import { getSettingGroupId } from './getSettingGroupId.js';
interface Props {
settingsId: string;
group: SettingsGroupType;
- resolver: SettingsResolverSource;
+ resolver: ISettingsResolverSource;
source: IEditableSettingsSource;
settings: Map[]>;
treeFilter: ITreeFilter;
diff --git a/webapp/packages/plugin-settings-panel/src/SettingsPanel/SettingsList.tsx b/webapp/packages/plugin-settings-panel/src/SettingsPanel/SettingsList.tsx
index d2f0fcb154..c1ea691f21 100644
--- a/webapp/packages/plugin-settings-panel/src/SettingsPanel/SettingsList.tsx
+++ b/webapp/packages/plugin-settings-panel/src/SettingsPanel/SettingsList.tsx
@@ -9,9 +9,9 @@ import { observer } from 'mobx-react-lite';
import { Group, s, TextPlaceholder, useTranslate } from '@cloudbeaver/core-blocks';
import {
- SettingsResolverSource,
type IEditableSettingsSource,
type ISettingDescription,
+ type ISettingsResolverSource,
type SettingsGroup as SettingsGroupType,
} from '@cloudbeaver/core-settings';
import type { ITreeData, ITreeFilter } from '@cloudbeaver/plugin-navigation-tree';
@@ -27,7 +27,7 @@ interface Props {
treeData: ITreeData;
treeFilter: ITreeFilter;
source: IEditableSettingsSource;
- resolver: SettingsResolverSource;
+ resolver: ISettingsResolverSource;
settings: Map[]>;
groupSelectExecutor: ISyncExecutor;
groupsHidden?: boolean;
diff --git a/webapp/packages/plugin-user-profile-settings/src/UserProfileSettings.tsx b/webapp/packages/plugin-user-profile-settings/src/UserProfileSettings.tsx
index fd00872335..5374080fac 100644
--- a/webapp/packages/plugin-user-profile-settings/src/UserProfileSettings.tsx
+++ b/webapp/packages/plugin-user-profile-settings/src/UserProfileSettings.tsx
@@ -12,13 +12,13 @@ import { useService } from '@cloudbeaver/core-di';
import { NotificationService } from '@cloudbeaver/core-events';
import { UserSettingsService } from '@cloudbeaver/core-settings-user';
import { Settings } from '@cloudbeaver/plugin-settings-panel';
-import { SettingsResolverService } from '@cloudbeaver/core-settings';
+import { SettingsProviderService } from '@cloudbeaver/core-settings';
const clientScope = ['client'];
export const UserProfileSettings = observer(function UserProfileSettings() {
const translate = useTranslate();
- const settingsResolverService = useService(SettingsResolverService);
+ const settingsProviderService = useService(SettingsProviderService);
const userSettingsService = useService(UserSettingsService);
const notificationService = useService(NotificationService);
@@ -72,7 +72,7 @@ export const UserProfileSettings = observer(function UserProfileSettings() {
-
+
);