Merge branch 'devel' into 4696-cb-4362-add-trim-to-all-inputs-in-forms-2

This commit is contained in:
sergeyteleshev
2025-08-21 15:26:18 +02:00
committed by GitHub
15 changed files with 77 additions and 30 deletions
@@ -146,9 +146,9 @@ export const Select: SelectType = observer(function Select({
function itemRender(item: (typeof items)[number]): React.ReactNode {
return (
<div className="select__item" title={item ? titleSelector?.(item) : undefined}>
<div className="select__item tw:truncate" title={item ? titleSelector?.(item) : undefined}>
{renderIcon(item)}
<span>{valueSelector(item)}</span>
{valueSelector(item)}
</div>
);
}
@@ -153,6 +153,7 @@ export const RenderField = observer<RenderFieldProps>(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<RenderFieldProps>(function RenderField({
items={property.validValues!}
keySelector={value => value}
valueSelector={value => value}
titleSelector={value => value}
defaultValue={defaultValue}
title={property.description}
disabled={disabled}
@@ -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);
}
}
@@ -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'>(this, {
mergedSchema: observable.ref,
@@ -29,7 +38,7 @@ export class SettingsProviderService {
createSettings<TSchema extends schema.ZodObject = schema.ZodObject>(schema: TSchema): SettingsProvider<TSchema> {
this.mergedSchema = this.mergedSchema.merge(schema);
const settings = new SettingsProvider(this.settingsResolverService, schema);
const settings = new SettingsProvider(this.resolver, schema);
return settings;
}
}
@@ -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<ISettingChangeData>;
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, 'layers' | 'sources' | 'update'>(this, {
makeObservable<this, 'layers' | 'sources' | 'update' | 'resolvers'>(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;
}
@@ -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();
}
}
@@ -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';
@@ -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),
],
@@ -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;
},
});
}
@@ -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;
@@ -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;
}
@@ -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;
@@ -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<SettingsGroupType, ISettingDescription<any>[]>;
treeFilter: ITreeFilter;
@@ -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<SettingsGroupType, ISettingDescription<any>[]>;
groupSelectExecutor: ISyncExecutor<string>;
groupsHidden?: boolean;
@@ -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() {
</ToolsAction>
</ToolsPanel>
</Group>
<Settings resolver={settingsResolverService} source={userSettingsService} accessor={clientScope} />
<Settings resolver={settingsProviderService.settingsResolver} source={userSettingsService} accessor={clientScope} />
</ColoredContainer>
</Form>
);