mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-09-19 10:56:04 +08:00
dbeaver/pro#5087 feat: gql api (#3400)
* dbeaver/pro#5087 Add role settings * dbeaver/pro#5087 feat: gql api * dbeaver/pro#5087 feat: gql api * dbeaver/pro#5087 Add role settings * feat: user role settings * chore: add tailwind intellisense * chore: remove mock data * dbeaver/pro#5087 Add role settings * dbeaver/pro#5087 Add role settings * dbeaver/pro#5087 Add role settings * fix: update roles enum * feat: settings restore and set status * dbeaver/pro#5087 fix roles * chore: hide single settings tab, allow reset for settings that doesn't support full reset * chore: remove `isSet` method from settings API * refactor: extract repeatable logic * chore: add server setting * chore: better settings grouping * dbeaver/pro#5087 fixes * fix: review * chore: remove roles related code * chore: hide spreadsheet hiding setting * dbeaver/pro#5087 Removed everything related with authRole * chore: hide some settings from UI * chore: hide per-setting reset * fix: selecting empty settings groups --------- Co-authored-by: Ruslan <pupkinvasya7000@gmail.com> Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
This commit is contained in:
+1
-1
@@ -19,8 +19,8 @@ package io.cloudbeaver.model.config;
|
||||
import com.google.gson.annotations.Expose;
|
||||
import io.cloudbeaver.auth.provider.local.LocalAuthProviderConstants;
|
||||
import io.cloudbeaver.model.app.BaseWebAppConfiguration;
|
||||
import io.cloudbeaver.model.app.WebAppConfiguration;
|
||||
import io.cloudbeaver.model.app.ServletAuthConfiguration;
|
||||
import io.cloudbeaver.model.app.WebAppConfiguration;
|
||||
import io.cloudbeaver.registry.WebAuthProviderDescriptor;
|
||||
import io.cloudbeaver.registry.WebAuthProviderRegistry;
|
||||
import org.jkiss.code.NotNull;
|
||||
|
||||
+7
-1
@@ -37,7 +37,13 @@ public class WebSessionPreferenceStore extends AbstractUserPreferenceStore {
|
||||
|
||||
// to avoid redundant sm api call
|
||||
public void updatePreferenceValues(@NotNull Map<String, Object> newValues) {
|
||||
userPreferences.putAll(newValues);
|
||||
for (Map.Entry<String, Object> entry : newValues.entrySet()) {
|
||||
if (entry.getValue() == null) {
|
||||
userPreferences.remove(entry.getKey());
|
||||
} else {
|
||||
userPreferences.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -89,13 +89,13 @@ public class ServletAppUtils {
|
||||
var additionalValue = additional.get(rootKey);
|
||||
|
||||
if (originValue == null || additionalValue == null) {
|
||||
Object resultValue = null;
|
||||
if (additional.containsKey(rootKey)) {
|
||||
resultValue = additionalValue;
|
||||
if (additionalValue != null) {
|
||||
resultConfig.put(rootKey, additionalValue);
|
||||
}
|
||||
} else if (originValue != null) {
|
||||
resultValue = originValue;
|
||||
resultConfig.put(rootKey, originValue);
|
||||
}
|
||||
resultConfig.put(rootKey, resultValue);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
"@cloudbeaver/core-root": "workspace:*",
|
||||
"@cloudbeaver/core-routing": "workspace:*",
|
||||
"@cloudbeaver/core-sdk": "workspace:*",
|
||||
"@cloudbeaver/core-settings": "workspace:*",
|
||||
"@cloudbeaver/core-storage": "workspace:*",
|
||||
"@cloudbeaver/core-utils": "workspace:*",
|
||||
"@dbeaver/js-helpers": "workspace:^",
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* 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 { ROOT_SETTINGS_GROUP } from '@cloudbeaver/core-settings';
|
||||
|
||||
export const ADMINISTRATION_SETTINGS_GROUP = ROOT_SETTINGS_GROUP.createSubGroup('core_administration_settings_group');
|
||||
@@ -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.
|
||||
@@ -17,3 +17,4 @@ export * from './AdministrationScreen/ConfigurationWizard/ConfigurationWizardSer
|
||||
export * from './DataContext/DATA_CONTEXT_ADMINISTRATION_ITEM_ROUTE.js';
|
||||
export * from './AdministrationLocaleService.js';
|
||||
export * from './PermissionsResource.js';
|
||||
export * from './ADMINISTRATION_SETTINGS_GROUP.js';
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
export default [
|
||||
['administration_menu_enter', 'Administration'],
|
||||
['core_administration_settings_group', 'Administration'],
|
||||
['administration_menu_back', 'Back to app'],
|
||||
['administration_configuration_wizard_title', 'Initial Server Configuration'],
|
||||
['administration_configuration_wizard_finish_success_title', 'Server configured'],
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
export default [
|
||||
['administration_menu_enter', 'Administration'],
|
||||
['core_administration_settings_group', 'Administration'],
|
||||
['administration_menu_back', "Retour à l'application"],
|
||||
['administration_configuration_wizard_title', 'Configuration initiale du serveur'],
|
||||
['administration_configuration_wizard_finish_success_title', 'Serveur configuré'],
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
export default [
|
||||
['administration_menu_enter', 'Amministrazione'],
|
||||
['core_administration_settings_group', 'Administration'],
|
||||
['administration_menu_back', 'Torna indietro'],
|
||||
['administration_configuration_wizard_title', 'Configurazione Iniziale del Server'],
|
||||
['administration_configuration_wizard_finish_success_title', 'Server configured'],
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
export default [
|
||||
['administration_menu_enter', 'Администрирование'],
|
||||
['core_administration_settings_group', 'Администрирование'],
|
||||
['administration_menu_back', 'Вернуться в приложение'],
|
||||
['administration_configuration_wizard_title', 'Начальная настройка сервера'],
|
||||
['administration_configuration_wizard_finish_success_title', 'Сервер настроен'],
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
export default [
|
||||
['administration_menu_enter', '管理'],
|
||||
['core_administration_settings_group', 'Administration'],
|
||||
['administration_menu_back', '返回应用'],
|
||||
['administration_configuration_wizard_title', '初始化服务器配置'],
|
||||
['administration_configuration_wizard_finish_success_title', '服务器已完成配置'],
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -43,6 +43,9 @@
|
||||
{
|
||||
"path": "../core-sdk"
|
||||
},
|
||||
{
|
||||
"path": "../core-settings"
|
||||
},
|
||||
{
|
||||
"path": "../core-storage"
|
||||
},
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
@@ -9,7 +9,7 @@
|
||||
export enum ELMRole {
|
||||
ADMINISTRATOR = 'ADMINISTRATOR',
|
||||
DEVELOPER = 'DEVELOPER',
|
||||
DATA_MANAGER = 'DATA_MANAGER',
|
||||
MANAGER = 'MANAGER',
|
||||
EDITOR = 'EDITOR',
|
||||
VIEWER = 'VIEWER',
|
||||
}
|
||||
|
||||
@@ -11,23 +11,13 @@ import { injectable } from '@cloudbeaver/core-di';
|
||||
import { AutoRunningTask, type ISyncExecutor, type ITask, SyncExecutor, whileTask } from '@cloudbeaver/core-executor';
|
||||
import { CachedDataResource, type ResourceKeySimple, ResourceKeyUtils } from '@cloudbeaver/core-resource';
|
||||
import { SessionResource } from '@cloudbeaver/core-root';
|
||||
import {
|
||||
type FederatedAuthInfo,
|
||||
type AuthInfo,
|
||||
type AuthLogoutQuery,
|
||||
AuthStatus,
|
||||
type GetActiveUserQueryVariables,
|
||||
GraphQLService,
|
||||
type UserInfo,
|
||||
} from '@cloudbeaver/core-sdk';
|
||||
import { type FederatedAuthInfo, type AuthInfo, type AuthLogoutQuery, AuthStatus, GraphQLService, type UserInfo } from '@cloudbeaver/core-sdk';
|
||||
|
||||
import { AUTH_PROVIDER_LOCAL_ID } from './AUTH_PROVIDER_LOCAL_ID.js';
|
||||
import { AuthProviderService } from './AuthProviderService.js';
|
||||
import type { ELMRole } from './ELMRole.js';
|
||||
import type { IAuthCredentials } from './IAuthCredentials.js';
|
||||
|
||||
export type UserInfoIncludes = GetActiveUserQueryVariables;
|
||||
|
||||
export type UserLogoutInfo = AuthLogoutQuery['result'];
|
||||
|
||||
export interface ILoginOptions {
|
||||
@@ -42,7 +32,7 @@ export type IFederatedLoginOptions = Omit<ILoginOptions, 'credentials'>;
|
||||
export const ANONYMOUS_USER_ID = 'anonymous';
|
||||
|
||||
@injectable()
|
||||
export class UserInfoResource extends CachedDataResource<UserInfo | null, void, UserInfoIncludes> {
|
||||
export class UserInfoResource extends CachedDataResource<UserInfo | null, void> {
|
||||
readonly onUserChange: ISyncExecutor<string>;
|
||||
readonly onException: ISyncExecutor<Error>;
|
||||
|
||||
@@ -63,7 +53,7 @@ export class UserInfoResource extends CachedDataResource<UserInfo | null, void,
|
||||
private readonly authProviderService: AuthProviderService,
|
||||
private readonly sessionResource: SessionResource,
|
||||
) {
|
||||
super(() => null, undefined, ['includeConfigurationParameters']);
|
||||
super(() => null);
|
||||
|
||||
this.onUserChange = new SyncExecutor();
|
||||
this.onException = new SyncExecutor();
|
||||
@@ -210,8 +200,6 @@ export class UserInfoResource extends CachedDataResource<UserInfo | null, void,
|
||||
await this.performUpdate(undefined, [], async () => {
|
||||
const { user } = await this.graphQLService.sdk.updateUserPreferences({
|
||||
preferences,
|
||||
...this.getDefaultIncludes(),
|
||||
...this.getIncludesMap(),
|
||||
});
|
||||
|
||||
this.setData(user as UserInfo | null);
|
||||
@@ -291,12 +279,9 @@ export class UserInfoResource extends CachedDataResource<UserInfo | null, void,
|
||||
this.sessionResource.markOutdated();
|
||||
}
|
||||
|
||||
protected async loader(key: void, includes?: ReadonlyArray<string>): Promise<UserInfo | null> {
|
||||
protected async loader(key: void): Promise<UserInfo | null> {
|
||||
try {
|
||||
const { user } = await this.graphQLService.sdk.getActiveUser({
|
||||
...this.getDefaultIncludes(),
|
||||
...this.getIncludesMap(key, includes),
|
||||
});
|
||||
const { user } = await this.graphQLService.sdk.getActiveUser({});
|
||||
|
||||
return (user as UserInfo | null) || null;
|
||||
} catch (exception: any) {
|
||||
@@ -317,10 +302,4 @@ export class UserInfoResource extends CachedDataResource<UserInfo | null, void,
|
||||
this.onUserChange.execute(currentUserId);
|
||||
}
|
||||
}
|
||||
|
||||
private getDefaultIncludes(): UserInfoIncludes {
|
||||
return {
|
||||
includeConfigurationParameters: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,4 +7,10 @@ export default [
|
||||
['core_authentication_password_policy_upper_lower_case', 'Password must contain both upper and lower case letters'],
|
||||
['core_authentication_password_policy_min_digits', 'Password must contain at least {arg:min} digits'],
|
||||
['core_authentication_password_policy_min_special_characters', 'Password must contain at least {arg:min} special characters'],
|
||||
|
||||
['core_authentication_role_administrator', 'Administrator'],
|
||||
['core_authentication_role_manager', 'Manager'],
|
||||
['core_authentication_role_editor', 'Editor'],
|
||||
['core_authentication_role_viewer', 'Viewer'],
|
||||
['core_authentication_role_developer', 'Developer'],
|
||||
];
|
||||
|
||||
@@ -7,4 +7,10 @@ export default [
|
||||
['core_authentication_password_policy_upper_lower_case', 'Le mot de passe doit contenir des lettres majuscules et minuscules'],
|
||||
['core_authentication_password_policy_min_digits', 'Le mot de passe doit contenir au moins {arg:min} chiffres'],
|
||||
['core_authentication_password_policy_min_special_characters', 'Le mot de passe doit contenir au moins {arg:min} caractères spéciaux'],
|
||||
|
||||
['core_authentication_role_administrator', 'Administrator'],
|
||||
['core_authentication_role_manager', 'Manager'],
|
||||
['core_authentication_role_editor', 'Editor'],
|
||||
['core_authentication_role_viewer', 'Viewer'],
|
||||
['core_authentication_role_developer', 'Developer'],
|
||||
];
|
||||
|
||||
@@ -7,4 +7,10 @@ export default [
|
||||
['core_authentication_password_policy_upper_lower_case', 'Password must contain both upper and lower case letters'],
|
||||
['core_authentication_password_policy_min_digits', 'Password must contain at least {arg:min} digits'],
|
||||
['core_authentication_password_policy_min_special_characters', 'Password must contain at least {arg:min} special characters'],
|
||||
|
||||
['core_authentication_role_administrator', 'Administrator'],
|
||||
['core_authentication_role_manager', 'Manager'],
|
||||
['core_authentication_role_editor', 'Editor'],
|
||||
['core_authentication_role_viewer', 'Viewer'],
|
||||
['core_authentication_role_developer', 'Developer'],
|
||||
];
|
||||
|
||||
@@ -7,4 +7,10 @@ export default [
|
||||
['core_authentication_password_policy_upper_lower_case', 'Пароль должен содержать как заглавные, так и строчные буквы'],
|
||||
['core_authentication_password_policy_min_digits', 'Пароль должен содержать не менее {arg:min} цифр'],
|
||||
['core_authentication_password_policy_min_special_characters', 'Пароль должен содержать не менее {arg:min} специальных символов'],
|
||||
|
||||
['core_authentication_role_administrator', 'Администратор'],
|
||||
['core_authentication_role_manager', 'Менеджер'],
|
||||
['core_authentication_role_editor', 'Редактор'],
|
||||
['core_authentication_role_viewer', 'Зритель'],
|
||||
['core_authentication_role_developer', 'Разработчик'],
|
||||
];
|
||||
|
||||
@@ -7,4 +7,10 @@ export default [
|
||||
['core_authentication_password_policy_upper_lower_case', '密码必须包含大写和小写字母'],
|
||||
['core_authentication_password_policy_min_digits', '密码至少需要包含 {arg:min} 个数字'],
|
||||
['core_authentication_password_policy_min_special_characters', '密码至少需要包含 {arg:min} 个特殊字符'],
|
||||
|
||||
['core_authentication_role_administrator', 'Administrator'],
|
||||
['core_authentication_role_manager', 'Manager'],
|
||||
['core_authentication_role_editor', 'Editor'],
|
||||
['core_authentication_role_viewer', 'Viewer'],
|
||||
['core_authentication_role_developer', 'Developer'],
|
||||
];
|
||||
|
||||
@@ -41,6 +41,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
&.compact {
|
||||
&.gap > .groupTitle {
|
||||
padding: 16px 0;
|
||||
margin: -16px 0;
|
||||
|
||||
& > .groupClose {
|
||||
right: 0px;
|
||||
top: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.form > * {
|
||||
margin-right: 25%;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* 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 { observer } from 'mobx-react-lite';
|
||||
import React, { forwardRef, useContext } from 'react';
|
||||
import React, { forwardRef, useContext, useLayoutEffect, useRef } from 'react';
|
||||
|
||||
import { EventContext, EventStopPropagationFlag } from '@cloudbeaver/core-events';
|
||||
|
||||
@@ -18,6 +18,7 @@ import { EventTreeNodeSelectFlag } from './EventTreeNodeSelectFlag.js';
|
||||
import type { ITreeNodeState } from './ITreeNodeState.js';
|
||||
import { TreeNodeContext } from './TreeNodeContext.js';
|
||||
import style from './TreeNodeControl.module.css';
|
||||
import { useMergeRefs } from '../../useMergeRefs.js';
|
||||
|
||||
const KEY = {
|
||||
ENTER: 'Enter',
|
||||
@@ -38,6 +39,8 @@ export const TreeNodeControl = observer<Props & React.HTMLAttributes<HTMLDivElem
|
||||
) {
|
||||
const styles = useS(style);
|
||||
const context = useContext(TreeNodeContext);
|
||||
const innerRef = useRef<HTMLDivElement>(null);
|
||||
const mergedRef = useMergeRefs(innerRef, ref);
|
||||
|
||||
if (!context) {
|
||||
throw new Error('Context not provided');
|
||||
@@ -109,9 +112,15 @@ export const TreeNodeControl = observer<Props & React.HTMLAttributes<HTMLDivElem
|
||||
}
|
||||
}
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (context.selected) {
|
||||
innerRef.current?.focus();
|
||||
}
|
||||
}, [context.selected]);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
ref={mergedRef}
|
||||
tabIndex={context.selected ? 0 : -1}
|
||||
title={title}
|
||||
aria-selected={context.selected}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
/*
|
||||
* 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 { Dependency, injectable } from '@cloudbeaver/core-di';
|
||||
import { SettingsProvider, SettingsProviderService } from '@cloudbeaver/core-settings';
|
||||
import { ESettingsValueType, SettingsManagerService, SettingsProvider, SettingsProviderService } from '@cloudbeaver/core-settings';
|
||||
import { schema, schemaExtra } from '@cloudbeaver/core-utils';
|
||||
import { CONNECTIONS_SETTINGS_GROUP } from './CONNECTIONS_SETTINGS_GROUP.js';
|
||||
|
||||
const settingsSchema = schema.object({
|
||||
'core.connections.disabled': schemaExtra.stringedBoolean().default(false),
|
||||
@@ -22,24 +23,27 @@ export class ConnectionsSettingsService extends Dependency {
|
||||
}
|
||||
readonly settings: SettingsProvider<typeof settingsSchema>;
|
||||
|
||||
constructor(private readonly settingsProviderService: SettingsProviderService) {
|
||||
constructor(
|
||||
private readonly settingsProviderService: SettingsProviderService,
|
||||
private readonly settingsManagerService: SettingsManagerService,
|
||||
) {
|
||||
super();
|
||||
this.settings = this.settingsProviderService.createSettings(settingsSchema);
|
||||
this.registerSettings();
|
||||
}
|
||||
|
||||
private registerSettings() {
|
||||
// this.settingsManagerService.registerSettings(this.settings, () => [
|
||||
// {
|
||||
// group: CONNECTIONS_SETTINGS_GROUP,
|
||||
// key: 'core.connections.disabled',
|
||||
// access: {
|
||||
// scope: ['server'],
|
||||
// },
|
||||
// name: 'core_connections_settings_disable',
|
||||
// description: 'core_connections_settings_disable_description',
|
||||
// type: ESettingsValueType.Checkbox,
|
||||
// },
|
||||
// ]);
|
||||
this.settingsManagerService.registerSettings(this.settings, () => [
|
||||
{
|
||||
group: CONNECTIONS_SETTINGS_GROUP,
|
||||
key: 'core.connections.disabled',
|
||||
access: {
|
||||
scope: ['role'],
|
||||
},
|
||||
name: 'core_connections_settings_disable',
|
||||
description: 'core_connections_settings_disable_description',
|
||||
type: ESettingsValueType.Checkbox,
|
||||
},
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -8,12 +8,15 @@
|
||||
import { Dependency, injectable } from '@cloudbeaver/core-di';
|
||||
import {
|
||||
createSettingsAliasResolver,
|
||||
ESettingsValueType,
|
||||
ROOT_SETTINGS_LAYER,
|
||||
SettingsManagerService,
|
||||
SettingsProvider,
|
||||
SettingsProviderService,
|
||||
SettingsResolverService,
|
||||
} from '@cloudbeaver/core-settings';
|
||||
import { schema, schemaExtra } from '@cloudbeaver/core-utils';
|
||||
import { NAVIGATION_TREE_SETTINGS_GROUP } from './NAVIGATION_TREE_SETTINGS_GROUP.js';
|
||||
|
||||
const settingsSchema = schema.object({
|
||||
'core.navigation-tree.childrenLimit': schema.coerce.number().min(10).max(1000).default(100),
|
||||
@@ -39,6 +42,7 @@ export class NavTreeSettingsService extends Dependency {
|
||||
constructor(
|
||||
private readonly settingsProviderService: SettingsProviderService,
|
||||
private readonly settingsResolverService: SettingsResolverService,
|
||||
private readonly settingsManagerService: SettingsManagerService,
|
||||
) {
|
||||
super();
|
||||
this.settings = this.settingsProviderService.createSettings(settingsSchema);
|
||||
@@ -58,37 +62,37 @@ export class NavTreeSettingsService extends Dependency {
|
||||
}
|
||||
|
||||
private registerSettings() {
|
||||
// this.settingsManagerService.registerSettings(this.settings, () => [
|
||||
// {
|
||||
// key: 'core.navigation-tree.childrenLimit',
|
||||
// access: {
|
||||
// scope: ['server'],
|
||||
// },
|
||||
// group: NAVIGATION_TREE_SETTINGS_GROUP,
|
||||
// name: 'core_navigation_tree_settings_children_limit',
|
||||
// description: 'core_navigation_tree_settings_children_limit_description',
|
||||
// type: ESettingsValueType.Input,
|
||||
// },
|
||||
// {
|
||||
// group: NAVIGATION_TREE_SETTINGS_GROUP,
|
||||
// key: 'core.navigation-tree.editing',
|
||||
// access: {
|
||||
// scope: ['server'],
|
||||
// },
|
||||
// name: 'core_navigation_tree_settings_editing',
|
||||
// description: 'core_navigation_tree_settings_editing_description',
|
||||
// type: ESettingsValueType.Checkbox,
|
||||
// },
|
||||
// {
|
||||
// group: NAVIGATION_TREE_SETTINGS_GROUP,
|
||||
// key: 'core.navigation-tree.deleting',
|
||||
// access: {
|
||||
// scope: ['server'],
|
||||
// },
|
||||
// name: 'core_navigation_tree_settings_deleting',
|
||||
// description: 'core_navigation_tree_settings_deleting_description',
|
||||
// type: ESettingsValueType.Checkbox,
|
||||
// },
|
||||
// ]);
|
||||
this.settingsManagerService.registerSettings(this.settings, () => [
|
||||
{
|
||||
key: 'core.navigation-tree.childrenLimit',
|
||||
access: {
|
||||
scope: ['client', 'server'],
|
||||
},
|
||||
group: NAVIGATION_TREE_SETTINGS_GROUP,
|
||||
name: 'core_navigation_tree_settings_children_limit',
|
||||
description: 'core_navigation_tree_settings_children_limit_description',
|
||||
type: ESettingsValueType.Input,
|
||||
},
|
||||
{
|
||||
group: NAVIGATION_TREE_SETTINGS_GROUP,
|
||||
key: 'core.navigation-tree.editing',
|
||||
access: {
|
||||
scope: ['role'],
|
||||
},
|
||||
name: 'core_navigation_tree_settings_editing',
|
||||
description: 'core_navigation_tree_settings_editing_description',
|
||||
type: ESettingsValueType.Checkbox,
|
||||
},
|
||||
{
|
||||
group: NAVIGATION_TREE_SETTINGS_GROUP,
|
||||
key: 'core.navigation-tree.deleting',
|
||||
access: {
|
||||
scope: ['role'],
|
||||
},
|
||||
name: 'core_navigation_tree_settings_deleting',
|
||||
description: 'core_navigation_tree_settings_deleting_description',
|
||||
type: ESettingsValueType.Checkbox,
|
||||
},
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* 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 { createSettingsLayer } from '@cloudbeaver/core-settings';
|
||||
import { ROLE_SETTINGS_LAYER } from './ROLE_SETTINGS_LAYER.js';
|
||||
|
||||
export const HIGHEST_SETTINGS_LAYER = createSettingsLayer(ROLE_SETTINGS_LAYER, 'highest');
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* 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 { createSettingsLayer } from '@cloudbeaver/core-settings';
|
||||
import { TEAM_SETTINGS_LAYER } from './TEAM_SETTINGS_LAYER.js';
|
||||
|
||||
export const ROLE_SETTINGS_LAYER = createSettingsLayer(TEAM_SETTINGS_LAYER, 'role');
|
||||
@@ -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.
|
||||
@@ -42,6 +42,10 @@ export class ServerSettingsService extends SettingsSource {
|
||||
return this.settings.has(key) || super.has(key);
|
||||
}
|
||||
|
||||
isOverrideDefaults(): boolean {
|
||||
return this.settings.size > 0;
|
||||
}
|
||||
|
||||
isReadOnly(key: any): boolean {
|
||||
return !this.sessionPermissionsResource.has(EAdminPermission.admin);
|
||||
}
|
||||
@@ -50,17 +54,6 @@ export class ServerSettingsService extends SettingsSource {
|
||||
return this.settings.get(key);
|
||||
}
|
||||
|
||||
override clear(): void {
|
||||
this.update(() => {
|
||||
super.clear();
|
||||
this.settings.clear();
|
||||
});
|
||||
}
|
||||
|
||||
resetChanges() {
|
||||
super.clear();
|
||||
}
|
||||
|
||||
async save() {
|
||||
await this.serverConfigResource.updateProductConfiguration(Object.fromEntries(this.changes));
|
||||
}
|
||||
@@ -69,9 +62,19 @@ export class ServerSettingsService extends SettingsSource {
|
||||
return Object.fromEntries(this.settings);
|
||||
}
|
||||
|
||||
restoreDefaults() {
|
||||
this.update(() => {
|
||||
this.clear();
|
||||
for (const key of this.settings.keys()) {
|
||||
this.setValue(key, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private refreshConfig() {
|
||||
this.update(() => {
|
||||
this.clear();
|
||||
this.settings.clear();
|
||||
|
||||
if (!this.serverConfigResource.data) {
|
||||
this.lastConfig = null;
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* 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 { createSettingsLayer } from '@cloudbeaver/core-settings';
|
||||
import { USER_SETTINGS_LAYER } from './USER_SETTINGS_LAYER.js';
|
||||
|
||||
export const TEAM_SETTINGS_LAYER = createSettingsLayer(USER_SETTINGS_LAYER, 'team');
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* 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 { createSettingsLayer } from '@cloudbeaver/core-settings';
|
||||
|
||||
import { SESSION_SETTINGS_LAYER } from './SESSION_SETTINGS_LAYER.js';
|
||||
|
||||
export const USER_SETTINGS_LAYER = createSettingsLayer(SESSION_SETTINGS_LAYER, 'user');
|
||||
@@ -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.
|
||||
@@ -27,6 +27,10 @@ export * from './SessionResource.js';
|
||||
export * from './Settings/ServerSettingsManagerService.js';
|
||||
export * from './Settings/ServerSettingsService.js';
|
||||
export * from './Settings/SESSION_SETTINGS_LAYER.js';
|
||||
export * from './Settings/ROLE_SETTINGS_LAYER.js';
|
||||
export * from './Settings/TEAM_SETTINGS_LAYER.js';
|
||||
export * from './Settings/USER_SETTINGS_LAYER.js';
|
||||
export * from './Settings/HIGHEST_SETTINGS_LAYER.js';
|
||||
export * from './SessionActionService.js';
|
||||
export * from './EAdminPermission.js';
|
||||
export * from './SessionDataResource.js';
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
query getActiveUser($includeConfigurationParameters: Boolean!) {
|
||||
query getActiveUser {
|
||||
user: activeUser {
|
||||
userId
|
||||
isAnonymous
|
||||
displayName
|
||||
authRole
|
||||
linkedAuthProviders
|
||||
configurationParameters @include(if: $includeConfigurationParameters)
|
||||
configurationParameters
|
||||
teams {
|
||||
teamId
|
||||
teamName
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
query getAuthRoles {
|
||||
roles: listAuthRoles
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
mutation updateUserPreferences($preferences: Object!, $includeConfigurationParameters: Boolean!) {
|
||||
mutation updateUserPreferences($preferences: Object!) {
|
||||
user: setUserPreferences(preferences: $preferences) {
|
||||
userId
|
||||
displayName
|
||||
authRole
|
||||
linkedAuthProviders
|
||||
configurationParameters @include(if: $includeConfigurationParameters)
|
||||
configurationParameters
|
||||
teams {
|
||||
teamId
|
||||
teamName
|
||||
|
||||
@@ -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.
|
||||
@@ -49,6 +49,10 @@ export class UserSettingsService extends SettingsSource {
|
||||
return this.getSource().has(key) || super.has(key);
|
||||
}
|
||||
|
||||
isOverrideDefaults(): boolean {
|
||||
return this.getSource().size > 0;
|
||||
}
|
||||
|
||||
isReadOnly(key: any): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -22,4 +22,6 @@ export interface ISettingsSource {
|
||||
setValue: (key: any, value: any) => void;
|
||||
save: () => Promise<void>;
|
||||
clear: () => void;
|
||||
isOverrideDefaults?: () => boolean;
|
||||
restoreDefaults?: () => void;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
import { computed, makeObservable, observable } from 'mobx';
|
||||
import { action, computed, makeObservable, observable } from 'mobx';
|
||||
|
||||
import { type ISyncExecutor, SyncExecutor } from '@cloudbeaver/core-executor';
|
||||
import { isNotNullDefined } from '@dbeaver/js-helpers';
|
||||
@@ -29,13 +29,16 @@ export class SettingsResolverSource implements ISettingsResolverSource {
|
||||
.reverse();
|
||||
}
|
||||
protected layers: ISettingsSourcesLayer[];
|
||||
private updating: boolean;
|
||||
|
||||
constructor() {
|
||||
this.onChange = new SyncExecutor();
|
||||
this.layers = [];
|
||||
makeObservable<this, 'layers' | 'sources'>(this, {
|
||||
this.updating = false;
|
||||
makeObservable<this, 'layers' | 'sources' | 'update'>(this, {
|
||||
layers: observable.shallow,
|
||||
sources: computed,
|
||||
update: action,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -81,21 +84,29 @@ export class SettingsResolverSource implements ISettingsResolverSource {
|
||||
this.layers = [];
|
||||
}
|
||||
|
||||
isOverrideDefaults(): boolean {
|
||||
return this.sources.some(r => r.isOverrideDefaults?.());
|
||||
}
|
||||
|
||||
isEdited(key?: any): boolean {
|
||||
return this.sources.find(r => r.has(key))?.isEdited(key) || false;
|
||||
}
|
||||
|
||||
isReadOnly(key: any): boolean {
|
||||
isReadOnly(key: any, stopAt?: ISettingsSource): boolean {
|
||||
for (const source of this.sources) {
|
||||
if (!source.isReadOnly(key)) {
|
||||
return false;
|
||||
if (!source.has(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (source.has(key)) {
|
||||
if (source === stopAt) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (source.isReadOnly(key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
has(key: any): boolean {
|
||||
@@ -162,4 +173,36 @@ export class SettingsResolverSource implements ISettingsResolverSource {
|
||||
|
||||
return layerSources;
|
||||
}
|
||||
|
||||
protected getSnapshot(): Record<string, any> {
|
||||
return {};
|
||||
}
|
||||
|
||||
protected update(action: () => void) {
|
||||
if (this.updating) {
|
||||
action();
|
||||
return;
|
||||
}
|
||||
|
||||
this.updating = true;
|
||||
try {
|
||||
const snapshot = this.getSnapshot();
|
||||
action();
|
||||
const newSnapshot = this.getSnapshot();
|
||||
|
||||
for (const [key, value] of Object.entries(newSnapshot)) {
|
||||
if (snapshot[key] !== value) {
|
||||
this.onChange.execute({ key, value });
|
||||
}
|
||||
}
|
||||
|
||||
for (const key of Object.keys(snapshot)) {
|
||||
if (!(key in newSnapshot)) {
|
||||
this.onChange.execute({ key, value: undefined });
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
this.updating = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -76,6 +76,7 @@ export function createSettingsAliasResolver<TTarget extends schema.SomeZodObject
|
||||
|
||||
return has;
|
||||
},
|
||||
isOverrideDefaults: source.isOverrideDefaults?.bind(source.isOverrideDefaults),
|
||||
isEdited(key) {
|
||||
if (!(key in mappings)) {
|
||||
return false;
|
||||
|
||||
@@ -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.
|
||||
@@ -17,7 +17,7 @@ import { TabActions } from './TabActions.js';
|
||||
import type { TabProps } from './TabProps.js';
|
||||
import { useTab } from './useTab.js';
|
||||
|
||||
export const Tab = observer<TabProps>(function Tab(props) {
|
||||
export const Tab = observer<TabProps>(function Tab({ after, ...props }) {
|
||||
const translate = useTranslate();
|
||||
const { tabId, title, disabled, className, children, onOpen, onClose, onClick } = props;
|
||||
const ref = useRef<HTMLButtonElement>(null);
|
||||
@@ -57,6 +57,7 @@ export const Tab = observer<TabProps>(function Tab(props) {
|
||||
>
|
||||
<div className={s(styles, { tabContainer: true })}>{children}</div>
|
||||
</BaseTab>
|
||||
{after}
|
||||
</div>
|
||||
</div>
|
||||
</TabContext.Provider>
|
||||
|
||||
@@ -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.
|
||||
@@ -18,6 +18,7 @@ export type TabProps = PropsWithChildren<{
|
||||
selected?: boolean;
|
||||
disabled?: boolean;
|
||||
className?: string;
|
||||
after?: React.ReactElement;
|
||||
onOpen?: (tab: ITabData<any>) => void;
|
||||
onClose?: (tab: ITabData<any>) => void;
|
||||
onClick?: (tabId: string) => void;
|
||||
|
||||
@@ -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,8 +15,8 @@ export interface ITabData<T = void> {
|
||||
props: T;
|
||||
}
|
||||
|
||||
export type TabContainerTabComponent<TProps = void> = React.FC<TabProps & TProps>;
|
||||
export type TabContainerPanelComponent<TProps = void> = React.FC<{ tabId: string; className?: string } & TProps>;
|
||||
export type TabContainerTabComponent<TProps = {}> = React.FC<TabProps & TProps>;
|
||||
export type TabContainerPanelComponent<TProps = {}> = React.FC<{ tabId: string; className?: string } & TProps>;
|
||||
|
||||
export interface ITabInfoOptions<TProps = void, TOptions extends Record<string, any> | unknown = unknown> {
|
||||
key: string;
|
||||
@@ -59,6 +59,7 @@ export interface ITabsContainer<TProps = void, TOptions extends Record<string, a
|
||||
valueGetter?: MetadataValueGetter<string, T>,
|
||||
schema?: schema.AnyZodObject,
|
||||
) => T;
|
||||
setTabState: <T>(state: MetadataMap<string, any>, tabId: string, value: T) => T;
|
||||
getDisplayed: (props?: TProps) => Array<ITabInfo<TProps, TOptions>>;
|
||||
getIdList: (props?: TProps) => string[];
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -76,6 +76,10 @@ export class TabsContainer<TProps = void, TOptions extends Record<string, any> |
|
||||
return state.get(tabId, valueGetter || tabInfo?.stateGetter?.(props), schema);
|
||||
}
|
||||
|
||||
setTabState<T>(state: MetadataMap<string, any>, tabId: string, value: T): T {
|
||||
return state.set(tabId, value).get(tabId);
|
||||
}
|
||||
|
||||
getDisplayed(props?: TProps): Array<ITabInfo<TProps, TOptions>> {
|
||||
return this.tabInfoList.filter(tabInfo => !tabInfo.isHidden?.(tabInfo.key, props));
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -31,6 +31,7 @@ export interface ITabsContext<T = Record<string, any>> {
|
||||
canClose: (tabId: string) => boolean;
|
||||
getTabInfo: (tabId: string) => ITabInfo<T> | undefined;
|
||||
getTabState: <T>(tabId: string, valueGetter?: MetadataValueGetter<string, T>, schema?: schema.AnyZodObject) => T;
|
||||
setTabState: <T>(tabId: string, value: T) => T;
|
||||
getLocalState: <T>(tabId: string, valueGetter?: MetadataValueGetter<string, T>, schema?: schema.AnyZodObject) => T;
|
||||
open: (tabId: string) => Promise<void>;
|
||||
close: (tabId: string) => Promise<void>;
|
||||
|
||||
@@ -24,8 +24,10 @@ type ExtractContainerProps<T> = T extends void ? Record<string, any> : T;
|
||||
|
||||
export type TabsStateProps<T = Record<string, any>> = ExtractContainerProps<T> &
|
||||
React.PropsWithChildren<{
|
||||
/** Default selected tab id */
|
||||
selectedId?: string;
|
||||
orientation?: 'horizontal' | 'vertical';
|
||||
/** Provide a tab Id to control tabs state */
|
||||
currentTabId?: string | null;
|
||||
container?: ITabsContainer<T, any>;
|
||||
localState?: MetadataMap<string, any>;
|
||||
@@ -168,6 +170,9 @@ export const TabsState = observer(function TabsState<T = Record<string, any>>({
|
||||
getTabState(tabId: string, valueGetter?: MetadataValueGetter<string, any>, schema?: schema.AnyZodObject) {
|
||||
return dynamic.container?.getTabState(dynamic.tabsState, tabId, dynamic.props, valueGetter, schema);
|
||||
},
|
||||
setTabState(tabId: string, value: any) {
|
||||
return dynamic.container?.setTabState(dynamic.tabsState, tabId, value);
|
||||
},
|
||||
getLocalState(tabId: string, valueGetter?: MetadataValueGetter<string, any>, schema?: schema.AnyZodObject) {
|
||||
return dynamic.tabsState.get(tabId, valueGetter, schema);
|
||||
},
|
||||
|
||||
+1
-1
@@ -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.
|
||||
|
||||
+1
-1
@@ -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.
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
/*
|
||||
* 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 { CONNECTIONS_SETTINGS_GROUP } from '@cloudbeaver/core-connections';
|
||||
import { Dependency, injectable } from '@cloudbeaver/core-di';
|
||||
import { SettingsManagerService, SettingsProvider, SettingsProviderService } from '@cloudbeaver/core-settings';
|
||||
import { ESettingsValueType, SettingsManagerService, SettingsProvider, SettingsProviderService } from '@cloudbeaver/core-settings';
|
||||
import { schema, schemaExtra } from '@cloudbeaver/core-utils';
|
||||
|
||||
const settings = schema.object({
|
||||
@@ -32,12 +33,15 @@ export class CustomConnectionSettingsService extends Dependency {
|
||||
|
||||
private registerSettings() {
|
||||
this.settingsManagerService.registerSettings(this.settings, () => [
|
||||
// {
|
||||
// group: CONNECTIONS_SETTINGS_GROUP,
|
||||
// key: 'disabled',
|
||||
// type: ESettingsValueType.Checkbox,
|
||||
// name: 'Disable custom connections',
|
||||
// },
|
||||
{
|
||||
key: 'plugin.connection-custom.disabled',
|
||||
access: {
|
||||
scope: ['role'],
|
||||
},
|
||||
group: CONNECTIONS_SETTINGS_GROUP,
|
||||
name: 'plugin_connection_custom_settings_disabled_name',
|
||||
type: ESettingsValueType.Checkbox,
|
||||
},
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1,4 @@
|
||||
export default [['plugin_connection_custom_action_custom_label', 'New Connection']];
|
||||
export default [
|
||||
['plugin_connection_custom_action_custom_label', 'New Connection'],
|
||||
['plugin_connection_custom_settings_disabled_name', 'Disable custom connections'],
|
||||
];
|
||||
|
||||
@@ -1 +1,4 @@
|
||||
export default [['plugin_connection_custom_action_custom_label', 'Nouvelle connexion']];
|
||||
export default [
|
||||
['plugin_connection_custom_action_custom_label', 'Nouvelle connexion'],
|
||||
['plugin_connection_custom_settings_disabled_name', 'Disable custom connections'],
|
||||
];
|
||||
|
||||
@@ -1 +1,4 @@
|
||||
export default [['plugin_connection_custom_action_custom_label', 'New Connection']];
|
||||
export default [
|
||||
['plugin_connection_custom_action_custom_label', 'New Connection'],
|
||||
['plugin_connection_custom_settings_disabled_name', 'Disable custom connections'],
|
||||
];
|
||||
|
||||
@@ -1 +1,4 @@
|
||||
export default [['plugin_connection_custom_action_custom_label', 'Новое подключение']];
|
||||
export default [
|
||||
['plugin_connection_custom_action_custom_label', 'Новое подключение'],
|
||||
['plugin_connection_custom_settings_disabled_name', 'Отключить пользовательские подключения'],
|
||||
];
|
||||
|
||||
@@ -1 +1,4 @@
|
||||
export default [['plugin_connection_custom_action_custom_label', '新建连接']];
|
||||
export default [
|
||||
['plugin_connection_custom_action_custom_label', '新建连接'],
|
||||
['plugin_connection_custom_settings_disabled_name', 'Disable custom connections'],
|
||||
];
|
||||
|
||||
@@ -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.
|
||||
@@ -37,7 +37,7 @@ export class ConnectionSearchSettingsService extends Dependency {
|
||||
group: CONNECTIONS_SETTINGS_GROUP,
|
||||
key: 'plugin.connection-search.disabled',
|
||||
access: {
|
||||
scope: ['server'],
|
||||
scope: ['server', 'role'],
|
||||
},
|
||||
type: ESettingsValueType.Checkbox,
|
||||
name: 'plugin_connection_search_settings_disable',
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
/*
|
||||
* 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 { CONNECTIONS_SETTINGS_GROUP } from '@cloudbeaver/core-connections';
|
||||
import { Dependency, injectable } from '@cloudbeaver/core-di';
|
||||
import { SettingsProvider, SettingsProviderService } from '@cloudbeaver/core-settings';
|
||||
import { ESettingsValueType, SettingsManagerService, SettingsProvider, SettingsProviderService } from '@cloudbeaver/core-settings';
|
||||
import { schema, schemaExtra } from '@cloudbeaver/core-utils';
|
||||
|
||||
const defaultSettings = schema.object({
|
||||
@@ -22,7 +23,10 @@ export class PluginConnectionsSettingsService extends Dependency {
|
||||
}
|
||||
readonly settings: SettingsProvider<typeof defaultSettings>;
|
||||
|
||||
constructor(private readonly settingsProviderService: SettingsProviderService) {
|
||||
constructor(
|
||||
private readonly settingsProviderService: SettingsProviderService,
|
||||
private readonly settingsManagerService: SettingsManagerService,
|
||||
) {
|
||||
super();
|
||||
this.settings = this.settingsProviderService.createSettings(defaultSettings);
|
||||
|
||||
@@ -31,17 +35,17 @@ export class PluginConnectionsSettingsService extends Dependency {
|
||||
|
||||
private registerSettings() {
|
||||
// todo: probably not working as a separate setting
|
||||
// this.settingsManagerService.registerSettings(this.settings, () => [
|
||||
// {
|
||||
// key: 'plugin.connections.hideConnectionViewForUsers',
|
||||
// type: ESettingsValueType.Checkbox,
|
||||
// access: {
|
||||
// scope: ['server'],
|
||||
// },
|
||||
// name: 'plugin_connections_settings_hide_connections_view_name',
|
||||
// description: 'plugin_connections_settings_hide_connections_view_description',
|
||||
// group: CONNECTIONS_SETTINGS_GROUP,
|
||||
// },
|
||||
// ]);
|
||||
this.settingsManagerService.registerSettings(this.settings, () => [
|
||||
{
|
||||
key: 'plugin.connections.hideConnectionViewForUsers',
|
||||
type: ESettingsValueType.Checkbox,
|
||||
access: {
|
||||
scope: ['role'],
|
||||
},
|
||||
name: 'plugin_connections_settings_hide_connections_view_name',
|
||||
description: 'plugin_connections_settings_hide_connections_view_description',
|
||||
group: CONNECTIONS_SETTINGS_GROUP,
|
||||
},
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,8 +26,8 @@ export default [
|
||||
['plugin_connections_menu_connections_label', 'Connection'],
|
||||
['plugin_connections_action_disconnect_all_label', 'Disconnect All'],
|
||||
['plugin_connections_settings', 'Connections'],
|
||||
['plugin_connections_settings_hide_connections_view_name', 'Hide connections'],
|
||||
['plugin_connections_settings_hide_connections_view_description', 'Connections will be hidden for all users except administrators'],
|
||||
['plugin_connections_settings_hide_connections_view_name', 'Hide connection view management'],
|
||||
['plugin_connections_settings_hide_connections_view_description', 'Connections view submenu will be hidden for all users except administrators'],
|
||||
|
||||
['plugin_connections_connection_ssl_enable', 'Enable SSL'],
|
||||
|
||||
|
||||
@@ -38,8 +38,8 @@ export default [
|
||||
['plugin_connections_menu_connections_label', 'Connexion'],
|
||||
['plugin_connections_action_disconnect_all_label', 'Déconnecter tout'],
|
||||
['plugin_connections_settings', 'Connexions'],
|
||||
['plugin_connections_settings_hide_connections_view_name', 'Hide connections'],
|
||||
['plugin_connections_settings_hide_connections_view_description', 'Connections will be hidden for all users except administrators'],
|
||||
['plugin_connections_settings_hide_connections_view_name', 'Hide connection view management'],
|
||||
['plugin_connections_settings_hide_connections_view_description', 'Connections view submenu will be hidden for all users except administrators'],
|
||||
|
||||
['plugin_connections_connection_ssl_enable', 'Activer SSL'],
|
||||
|
||||
|
||||
@@ -28,8 +28,8 @@ export default [
|
||||
['plugin_connections_menu_connections_label', 'Connessione'],
|
||||
['plugin_connections_action_disconnect_all_label', 'Scollegati da tutto'],
|
||||
['plugin_connections_settings', 'Connections'],
|
||||
['plugin_connections_settings_hide_connections_view_name', 'Hide connections'],
|
||||
['plugin_connections_settings_hide_connections_view_description', 'Connections will be hidden for all users except administrators'],
|
||||
['plugin_connections_settings_hide_connections_view_name', 'Hide connection view management'],
|
||||
['plugin_connections_settings_hide_connections_view_description', 'Connections view submenu will be hidden for all users except administrators'],
|
||||
|
||||
['plugin_connections_connection_ssl_enable', 'Enable SSL'],
|
||||
|
||||
|
||||
@@ -26,8 +26,8 @@ export default [
|
||||
['plugin_connections_menu_connections_label', 'Подключение'],
|
||||
['plugin_connections_action_disconnect_all_label', 'Отключить все'],
|
||||
['plugin_connections_settings', 'Подключения'],
|
||||
['plugin_connections_settings_hide_connections_view_name', 'Скрыть подключения'],
|
||||
['plugin_connections_settings_hide_connections_view_description', 'Подключения будут скрыты для всех пользователей, кроме администраторов'],
|
||||
['plugin_connections_settings_hide_connections_view_name', 'Скрыть управление отображением подключений'],
|
||||
['plugin_connections_settings_hide_connections_view_description', 'Подменю выбора отображения подключения будет скрыто для всех пользователей, кроме администраторов'],
|
||||
|
||||
['plugin_connections_connection_ssl_enable', 'Включить SSL'],
|
||||
|
||||
|
||||
@@ -25,8 +25,8 @@ export default [
|
||||
['plugin_connections_menu_connections_label', '连接'],
|
||||
['plugin_connections_action_disconnect_all_label', '断开所有连接'],
|
||||
['plugin_connections_settings', '连接'],
|
||||
['plugin_connections_settings_hide_connections_view_name', 'Hide connections'],
|
||||
['plugin_connections_settings_hide_connections_view_description', 'Connections will be hidden for all users except administrators'],
|
||||
['plugin_connections_settings_hide_connections_view_name', 'Hide connection view management'],
|
||||
['plugin_connections_settings_hide_connections_view_description', 'Connections view submenu will be hidden for all users except administrators'],
|
||||
|
||||
['plugin_connections_connection_ssl_enable', '启用 SSL'],
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -37,7 +37,7 @@ export class DataImportSettingsService {
|
||||
name: 'plugin_data_import_disable_data_import_name',
|
||||
description: 'plugin_data_import_disable_data_import_description',
|
||||
access: {
|
||||
scope: ['server'],
|
||||
scope: ['server', 'role'],
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -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.
|
||||
@@ -55,7 +55,7 @@ export class DataGridSettingsService extends Dependency {
|
||||
group: DATA_EDITOR_SETTINGS_GROUP,
|
||||
key: 'plugin.data-spreadsheet.hidden',
|
||||
access: {
|
||||
scope: ['server'],
|
||||
scope: ['role'],
|
||||
},
|
||||
type: ESettingsValueType.Checkbox,
|
||||
name: 'plugin_data_spreadsheet_new_settings_disable',
|
||||
|
||||
@@ -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.
|
||||
@@ -118,7 +118,7 @@ export class DataViewerSettingsService extends Dependency {
|
||||
{
|
||||
key: 'plugin.data-viewer.disableEdit',
|
||||
access: {
|
||||
scope: ['server'],
|
||||
scope: ['server', 'role'],
|
||||
},
|
||||
type: ESettingsValueType.Checkbox,
|
||||
name: 'settings_data_editor_disable_edit_name',
|
||||
@@ -128,7 +128,7 @@ export class DataViewerSettingsService extends Dependency {
|
||||
{
|
||||
key: 'plugin.data-viewer.disableCopyData',
|
||||
access: {
|
||||
scope: ['server'],
|
||||
scope: ['server', 'role'],
|
||||
},
|
||||
type: ESettingsValueType.Checkbox,
|
||||
name: 'settings_data_editor_disable_data_copy_name',
|
||||
@@ -138,7 +138,7 @@ export class DataViewerSettingsService extends Dependency {
|
||||
{
|
||||
key: 'plugin.data-viewer.fetchMax',
|
||||
access: {
|
||||
scope: ['server'],
|
||||
scope: ['server', 'role'],
|
||||
},
|
||||
type: ESettingsValueType.Input,
|
||||
name: 'settings_data_editor_fetch_max_name',
|
||||
@@ -152,7 +152,7 @@ export class DataViewerSettingsService extends Dependency {
|
||||
name: 'settings_data_editor_disable_data_export_name',
|
||||
description: 'settings_data_editor_disable_data_export_description',
|
||||
access: {
|
||||
scope: ['server'],
|
||||
scope: ['server', 'role'],
|
||||
},
|
||||
},
|
||||
];
|
||||
@@ -161,7 +161,7 @@ export class DataViewerSettingsService extends Dependency {
|
||||
settings.push({
|
||||
key: 'resultset.maxrows',
|
||||
access: {
|
||||
scope: ['server'],
|
||||
scope: ['server', 'client'],
|
||||
},
|
||||
type: ESettingsValueType.Input,
|
||||
name: 'settings_data_editor_fetch_default_name',
|
||||
|
||||
@@ -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.
|
||||
@@ -87,7 +87,7 @@ export class LogViewerSettingsService extends Dependency {
|
||||
{
|
||||
key: 'plugin.log-viewer.disabled',
|
||||
access: {
|
||||
scope: ['server'],
|
||||
scope: ['server', 'role'],
|
||||
},
|
||||
group: TOOLS_PANEL_SETTINGS_GROUP,
|
||||
type: ESettingsValueType.Checkbox,
|
||||
|
||||
@@ -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.
|
||||
@@ -8,8 +8,9 @@
|
||||
import { computed, makeObservable } from 'mobx';
|
||||
|
||||
import { Dependency, injectable } from '@cloudbeaver/core-di';
|
||||
import { SettingsManagerService, SettingsProvider, SettingsProviderService } from '@cloudbeaver/core-settings';
|
||||
import { ESettingsValueType, SettingsManagerService, SettingsProvider, SettingsProviderService } from '@cloudbeaver/core-settings';
|
||||
import { schema, schemaExtra } from '@cloudbeaver/core-utils';
|
||||
import { NAVIGATION_TREE_SETTINGS_GROUP } from '@cloudbeaver/core-navigation-tree';
|
||||
|
||||
const defaultSettings = schema.object({
|
||||
'plugin.navigation-tree.disabled': schemaExtra.stringedBoolean().default(false),
|
||||
@@ -41,16 +42,16 @@ export class NavigationTreeSettingsService extends Dependency {
|
||||
|
||||
private registerSettings() {
|
||||
this.settingsManagerService.registerSettings(this.settings, () => [
|
||||
// {
|
||||
// group: NAVIGATION_TREE_SETTINGS_GROUP,
|
||||
// key: 'plugin.navigation-tree.disabled',
|
||||
// access: {
|
||||
// scope: ['server'],
|
||||
// },
|
||||
// type: ESettingsValueType.Checkbox,
|
||||
// name: 'plugin_navigation_tree_settings_disable',
|
||||
// description: 'plugin_navigation_tree_settings_disable_description',
|
||||
// },
|
||||
{
|
||||
group: NAVIGATION_TREE_SETTINGS_GROUP,
|
||||
key: 'plugin.navigation-tree.disabled',
|
||||
access: {
|
||||
scope: ['role'],
|
||||
},
|
||||
type: ESettingsValueType.Checkbox,
|
||||
name: 'plugin_navigation_tree_settings_disable',
|
||||
description: 'plugin_navigation_tree_settings_disable_description',
|
||||
},
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
+13
-12
@@ -1,12 +1,13 @@
|
||||
/*
|
||||
* 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 { Dependency, injectable } from '@cloudbeaver/core-di';
|
||||
import { SettingsManagerService, SettingsProvider, SettingsProviderService } from '@cloudbeaver/core-settings';
|
||||
import { RESOURCE_MANAGER_SETTINGS_GROUP } from '@cloudbeaver/core-resource-manager';
|
||||
import { ESettingsValueType, SettingsManagerService, SettingsProvider, SettingsProviderService } from '@cloudbeaver/core-settings';
|
||||
import { schema, schemaExtra } from '@cloudbeaver/core-utils';
|
||||
|
||||
const settingsSchema = schema.object({
|
||||
@@ -35,16 +36,16 @@ export class ResourceManagerScriptsSettingsService extends Dependency {
|
||||
|
||||
private registerSettings() {
|
||||
this.settingsManagerService.registerSettings(this.settings, () => [
|
||||
// {
|
||||
// group: RESOURCE_MANAGER_SETTINGS_GROUP,
|
||||
// key: 'plugin.resource-manager-scripts.disabled',
|
||||
// access: {
|
||||
// scope: ['server'],
|
||||
// },
|
||||
// type: ESettingsValueType.Checkbox,
|
||||
// name: 'plugin_resource_manager_scripts_disable',
|
||||
// description: 'plugin_resource_manager_scripts_disable_description',
|
||||
// },
|
||||
{
|
||||
group: RESOURCE_MANAGER_SETTINGS_GROUP,
|
||||
key: 'plugin.resource-manager-scripts.disabled',
|
||||
access: {
|
||||
scope: ['role'],
|
||||
},
|
||||
type: ESettingsValueType.Checkbox,
|
||||
name: 'plugin_resource_manager_scripts_disable',
|
||||
description: 'plugin_resource_manager_scripts_disable_description',
|
||||
},
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
"@cloudbeaver/core-events": "workspace:*",
|
||||
"@cloudbeaver/core-localization": "workspace:*",
|
||||
"@cloudbeaver/core-root": "workspace:*",
|
||||
"@cloudbeaver/core-settings": "workspace:*",
|
||||
"@cloudbeaver/core-ui": "workspace:*",
|
||||
"@cloudbeaver/plugin-settings-panel": "workspace:*",
|
||||
"mobx": "^6",
|
||||
|
||||
@@ -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.
|
||||
@@ -8,26 +8,30 @@
|
||||
import { observer } from 'mobx-react-lite';
|
||||
|
||||
import type { AdministrationItemContentProps } from '@cloudbeaver/core-administration';
|
||||
import { ColoredContainer, Form, Group, ToolsAction, ToolsPanel, useForm, useTranslate } from '@cloudbeaver/core-blocks';
|
||||
import { ColoredContainer, Form, Group, ToolsAction, ToolsPanel, useForm, useTranslate, getComputed, TextPlaceholder } from '@cloudbeaver/core-blocks';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import { NotificationService } from '@cloudbeaver/core-events';
|
||||
import { ServerSettingsService } from '@cloudbeaver/core-root';
|
||||
import { Settings } from '@cloudbeaver/plugin-settings-panel';
|
||||
|
||||
const clientScope = ['server'];
|
||||
import { TabList, TabsState, type ITabData } from '@cloudbeaver/core-ui';
|
||||
import { SettingsAdministrationService } from './SettingsAdministrationService.js';
|
||||
import { useState } from 'react';
|
||||
|
||||
export const SettingsAdministration = observer<AdministrationItemContentProps>(function SettingsAdministration() {
|
||||
const translate = useTranslate();
|
||||
const serverSettingsService = useService(ServerSettingsService);
|
||||
const settingsAdministrationService = useService(SettingsAdministrationService);
|
||||
const notificationService = useService(NotificationService);
|
||||
const changed = serverSettingsService.isEdited();
|
||||
const [tabId, setTabId] = useState<string | null>(null);
|
||||
const translate = useTranslate();
|
||||
const tabInfo = getComputed(() => (tabId ? settingsAdministrationService.tabsContainer.getTabInfo(tabId) : null));
|
||||
const settingsSource = tabInfo?.options?.source;
|
||||
const accessor = tabInfo?.options?.accessor;
|
||||
const changed = settingsSource?.isEdited() || false;
|
||||
|
||||
async function handleSave() {
|
||||
if (!changed) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await serverSettingsService.save();
|
||||
await settingsSource?.save();
|
||||
notificationService.logSuccess({ title: translate('plugin_settings_administration_settings_save_success') });
|
||||
} catch (error: any) {
|
||||
notificationService.logException(error, 'plugin_settings_administration_settings_save_fail');
|
||||
@@ -41,24 +45,50 @@ export const SettingsAdministration = observer<AdministrationItemContentProps>(f
|
||||
});
|
||||
|
||||
function handleReset() {
|
||||
serverSettingsService.resetChanges();
|
||||
settingsSource?.clear();
|
||||
}
|
||||
|
||||
function handleRestoreDefaults() {
|
||||
settingsSource?.restoreDefaults?.();
|
||||
}
|
||||
|
||||
function handleTabChange(tab: ITabData<void>) {
|
||||
setTabId(tab.tabId);
|
||||
}
|
||||
|
||||
const hideSingleTab = settingsAdministrationService.tabsContainer.getDisplayed().length === 1;
|
||||
|
||||
return (
|
||||
<Form context={form} contents>
|
||||
<ColoredContainer overflow parent vertical noWrap gap>
|
||||
<Group box keepSize>
|
||||
<ToolsPanel rounded>
|
||||
<ToolsAction icon="admin-save" viewBox="0 0 24 24" disabled={!changed} onClick={() => form.submit()}>
|
||||
{translate('ui_processing_save')}
|
||||
</ToolsAction>
|
||||
<ToolsAction icon="admin-cancel" viewBox="0 0 24 24" disabled={!changed} onClick={handleReset}>
|
||||
{translate('ui_processing_cancel')}
|
||||
</ToolsAction>
|
||||
</ToolsPanel>
|
||||
</Group>
|
||||
<Settings source={serverSettingsService} accessor={clientScope} />
|
||||
</ColoredContainer>
|
||||
</Form>
|
||||
<TabsState container={settingsAdministrationService.tabsContainer} currentTabId={tabId} onChange={handleTabChange}>
|
||||
<Form context={form} contents>
|
||||
<ColoredContainer overflow parent vertical noWrap gap>
|
||||
<Group box keepSize>
|
||||
<ToolsPanel rounded>
|
||||
<ToolsAction icon="admin-save" viewBox="0 0 24 24" disabled={!changed} onClick={() => form.submit()}>
|
||||
{translate('ui_processing_save')}
|
||||
</ToolsAction>
|
||||
<ToolsAction icon="admin-cancel" viewBox="0 0 24 24" disabled={!changed} onClick={handleReset}>
|
||||
{translate('ui_processing_cancel')}
|
||||
</ToolsAction>
|
||||
{settingsSource?.restoreDefaults && (
|
||||
<ToolsAction
|
||||
icon="/icons/settings_restore_defaults2_m.svg#root"
|
||||
viewBox="0 0 24 24"
|
||||
disabled={settingsSource.isOverrideDefaults?.() === false}
|
||||
svg
|
||||
onClick={handleRestoreDefaults}
|
||||
>
|
||||
{translate('plugin_user_profile_settings_restore_defaults')}
|
||||
</ToolsAction>
|
||||
)}
|
||||
</ToolsPanel>
|
||||
</Group>
|
||||
<Group hidden={hideSingleTab} box keepSize hideOverflow>
|
||||
<TabList underline />
|
||||
</Group>
|
||||
{settingsSource ? <Settings source={settingsSource} accessor={accessor} /> : <TextPlaceholder>{translate('plugin_settings_administration_no_settings')}</TextPlaceholder>}
|
||||
</ColoredContainer>
|
||||
</Form>
|
||||
</TabsState>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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 type { ISettingsSource } from '@cloudbeaver/core-settings';
|
||||
import { TabsContainer } from '@cloudbeaver/core-ui';
|
||||
|
||||
export interface IAdministrationSettingsOptions {
|
||||
source: ISettingsSource;
|
||||
accessor: string[];
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export class SettingsAdministrationService {
|
||||
readonly tabsContainer: TabsContainer<void, IAdministrationSettingsOptions>;
|
||||
constructor() {
|
||||
this.tabsContainer = new TabsContainer('layer');
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
/*
|
||||
* 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 { settingsAdministrationPlugin } from './manifest.js';
|
||||
export { SettingsAdministrationService } from './SettingsAdministrationService.js';
|
||||
|
||||
export { settingsAdministrationPlugin };
|
||||
export default settingsAdministrationPlugin;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
export default [
|
||||
['plugin_settings_administration_settings_save_success', 'Preferences saved successfully'],
|
||||
['plugin_settings_administration_settings_save_fail', 'Preferences save failed'],
|
||||
['plugin_settings_administration_drawer_item_title', 'Global Preferences'],
|
||||
['plugin_settings_administration_settings_save_success', 'Settings saved successfully'],
|
||||
['plugin_settings_administration_settings_save_fail', 'Settings save failed'],
|
||||
['plugin_settings_administration_drawer_item_title', 'Settings'],
|
||||
['plugin_settings_administration_no_settings', 'Settings not available'],
|
||||
];
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
export default [
|
||||
['plugin_settings_administration_settings_save_success', 'Préférences enregistrées avec succès'],
|
||||
['plugin_settings_administration_settings_save_fail', "Échec de l'enregistrement des préférences"],
|
||||
['plugin_settings_administration_drawer_item_title', 'Global Preferences'],
|
||||
['plugin_settings_administration_drawer_item_title', 'Settings'],
|
||||
['plugin_settings_administration_no_settings', 'Settings not available'],
|
||||
];
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
export default [
|
||||
['plugin_settings_administration_settings_save_success', 'Preferences saved successfully'],
|
||||
['plugin_settings_administration_settings_save_fail', 'Preferences save failed'],
|
||||
['plugin_settings_administration_drawer_item_title', 'Global Preferences'],
|
||||
['plugin_settings_administration_drawer_item_title', 'Settings'],
|
||||
['plugin_settings_administration_no_settings', 'Settings not available'],
|
||||
];
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
export default [
|
||||
['plugin_settings_administration_settings_save_success', 'Настройки сохранены успешно'],
|
||||
['plugin_settings_administration_settings_save_fail', 'Ошибка сохранения настроек'],
|
||||
['plugin_settings_administration_drawer_item_title', ' Глобальные настройки'],
|
||||
['plugin_settings_administration_drawer_item_title', 'Настройки'],
|
||||
['plugin_settings_administration_no_settings', 'Настройки недоступны'],
|
||||
];
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
export default [
|
||||
['plugin_settings_administration_settings_save_success', '偏好设置保存成功'],
|
||||
['plugin_settings_administration_settings_save_fail', '偏好设置保存失败'],
|
||||
['plugin_settings_administration_drawer_item_title', '全局偏好设置'],
|
||||
['plugin_settings_administration_drawer_item_title', 'Settings'],
|
||||
['plugin_settings_administration_no_settings', 'Settings not available'],
|
||||
];
|
||||
|
||||
@@ -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.
|
||||
@@ -12,5 +12,6 @@ export const settingsAdministrationPlugin: PluginManifest = {
|
||||
providers: [
|
||||
() => import('./SettingsAdministrationPluginBootstrap.js').then(m => m.SettingsAdministrationPluginBootstrap),
|
||||
() => import('./LocaleService.js').then(m => m.LocaleService),
|
||||
() => import('./SettingsAdministrationService.js').then(m => m.SettingsAdministrationService),
|
||||
],
|
||||
};
|
||||
|
||||
@@ -31,6 +31,9 @@
|
||||
{
|
||||
"path": "../core-root"
|
||||
},
|
||||
{
|
||||
"path": "../core-settings"
|
||||
},
|
||||
{
|
||||
"path": "../core-ui"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/lib
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env*
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"name": "@cloudbeaver/plugin-settings-default-administration",
|
||||
"type": "module",
|
||||
"sideEffects": [
|
||||
"src/**/*.css",
|
||||
"src/**/*.scss",
|
||||
"public/**/*"
|
||||
],
|
||||
"version": "0.1.0",
|
||||
"description": "",
|
||||
"license": "Apache-2.0",
|
||||
"exports": {
|
||||
".": "./lib/index.js"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc -b",
|
||||
"clean": "rimraf --glob lib",
|
||||
"lint": "eslint ./src/ --ext .ts,.tsx",
|
||||
"validate-dependencies": "core-cli-validate-dependencies"
|
||||
},
|
||||
"dependencies": {
|
||||
"@cloudbeaver/core-authentication": "workspace:*",
|
||||
"@cloudbeaver/core-di": "workspace:*",
|
||||
"@cloudbeaver/core-localization": "workspace:*",
|
||||
"@cloudbeaver/core-root": "workspace:*",
|
||||
"@cloudbeaver/core-settings": "workspace:*",
|
||||
"@cloudbeaver/core-utils": "workspace:*",
|
||||
"@cloudbeaver/plugin-settings-administration": "workspace:*",
|
||||
"mobx": "^6",
|
||||
"tslib": "^2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cloudbeaver/core-cli": "workspace:*",
|
||||
"@cloudbeaver/tsconfig": "workspace:*",
|
||||
"typescript": "^5"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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 { Bootstrap, injectable } from '@cloudbeaver/core-di';
|
||||
import { LocalizationService } from '@cloudbeaver/core-localization';
|
||||
|
||||
@injectable()
|
||||
export class LocaleService extends Bootstrap {
|
||||
constructor(private readonly localizationService: LocalizationService) {
|
||||
super();
|
||||
}
|
||||
|
||||
override register(): void {
|
||||
this.localizationService.addProvider(this.provider.bind(this));
|
||||
}
|
||||
|
||||
private async provider(locale: string) {
|
||||
switch (locale) {
|
||||
case 'ru':
|
||||
return (await import('./locales/ru.js')).default;
|
||||
case 'it':
|
||||
return (await import('./locales/it.js')).default;
|
||||
case 'zh':
|
||||
return (await import('./locales/zh.js')).default;
|
||||
case 'fr':
|
||||
return (await import('./locales/fr.js')).default;
|
||||
default:
|
||||
return (await import('./locales/en.js')).default;
|
||||
}
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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 { Bootstrap, injectable } from '@cloudbeaver/core-di';
|
||||
import { SettingsAdministrationService } from '@cloudbeaver/plugin-settings-administration';
|
||||
import { ServerSettingsService } from '@cloudbeaver/core-root';
|
||||
|
||||
@injectable()
|
||||
export class SettingsDefaultAdministrationBootstrap extends Bootstrap {
|
||||
constructor(
|
||||
private readonly settingsAdministrationService: SettingsAdministrationService,
|
||||
private readonly serverSettingsService: ServerSettingsService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
override register(): void {
|
||||
this.settingsAdministrationService.tabsContainer.add({
|
||||
key: 'default',
|
||||
name: 'plugin_settings_default_administration_settings_tab_name',
|
||||
order: 0,
|
||||
options: {
|
||||
source: this.serverSettingsService,
|
||||
accessor: ['server'],
|
||||
},
|
||||
panel: () => () => null,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export * from './manifest.js';
|
||||
@@ -0,0 +1,3 @@
|
||||
export default [
|
||||
['plugin_settings_default_administration_settings_tab_name', 'Default'],
|
||||
];
|
||||
@@ -0,0 +1,3 @@
|
||||
export default [
|
||||
['plugin_settings_default_administration_settings_tab_name', 'Default'],
|
||||
];
|
||||
@@ -0,0 +1,3 @@
|
||||
export default [
|
||||
['plugin_settings_default_administration_settings_tab_name', 'Default'],
|
||||
];
|
||||
@@ -0,0 +1,3 @@
|
||||
export default [
|
||||
['plugin_settings_default_administration_settings_tab_name', 'По умолчанию'],
|
||||
];
|
||||
@@ -0,0 +1,3 @@
|
||||
export default [
|
||||
['plugin_settings_default_administration_settings_tab_name', 'Default'],
|
||||
];
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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 type { PluginManifest } from '@cloudbeaver/core-di';
|
||||
|
||||
export const pluginSettingsDefaultAdministrationManifest: PluginManifest = {
|
||||
info: {
|
||||
name: 'Plugin Default Settings Administration',
|
||||
},
|
||||
|
||||
providers: [
|
||||
() => import('./SettingsDefaultBootstrap.js').then(m => m.SettingsDefaultAdministrationBootstrap),
|
||||
() => import('./LocaleService.js').then(m => m.LocaleService),
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"extends": "@cloudbeaver/tsconfig/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "src",
|
||||
"outDir": "lib",
|
||||
"tsBuildInfoFile": "lib/tsconfig.tsbuildinfo",
|
||||
"composite": true
|
||||
},
|
||||
"exclude": [
|
||||
"**/node_modules",
|
||||
"lib/**/*"
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "../core-authentication"
|
||||
},
|
||||
{
|
||||
"path": "../core-cli"
|
||||
},
|
||||
{
|
||||
"path": "../core-di"
|
||||
},
|
||||
{
|
||||
"path": "../core-localization"
|
||||
},
|
||||
{
|
||||
"path": "../core-root"
|
||||
},
|
||||
{
|
||||
"path": "../core-settings"
|
||||
},
|
||||
{
|
||||
"path": "../core-utils"
|
||||
},
|
||||
{
|
||||
"path": "../plugin-settings-administration"
|
||||
}
|
||||
],
|
||||
"include": [
|
||||
"__custom_mocks__/**/*",
|
||||
"src/**/*",
|
||||
"src/**/*.json",
|
||||
"src/**/*.css",
|
||||
"src/**/*.scss"
|
||||
]
|
||||
}
|
||||
@@ -22,11 +22,13 @@
|
||||
"dependencies": {
|
||||
"@cloudbeaver/core-blocks": "workspace:*",
|
||||
"@cloudbeaver/core-di": "workspace:*",
|
||||
"@cloudbeaver/core-executor": "workspace:*",
|
||||
"@cloudbeaver/core-localization": "workspace:*",
|
||||
"@cloudbeaver/core-settings": "workspace:*",
|
||||
"@cloudbeaver/core-utils": "workspace:*",
|
||||
"@cloudbeaver/plugin-navigation-tree": "workspace:*",
|
||||
"@dbeaver/js-helpers": "workspace:^",
|
||||
"@dbeaver/ui-kit": "workspace:^",
|
||||
"mobx": "^6",
|
||||
"mobx-react-lite": "^4",
|
||||
"react": "^19",
|
||||
|
||||
@@ -7,17 +7,10 @@
|
||||
*/
|
||||
import { observer } from 'mobx-react-lite';
|
||||
|
||||
import { Combobox, FieldCheckbox, InputField, Textarea, useCustomInputValidation, useTranslate } from '@cloudbeaver/core-blocks';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import {
|
||||
ESettingsValueType,
|
||||
type ISettingDescription,
|
||||
type ISettingsSource,
|
||||
SettingsProviderService,
|
||||
SettingsResolverService,
|
||||
} from '@cloudbeaver/core-settings';
|
||||
import { schemaValidationError } from '@cloudbeaver/core-utils';
|
||||
import { isNotNullDefined } from '@dbeaver/js-helpers';
|
||||
import { Link, useTranslate } from '@cloudbeaver/core-blocks';
|
||||
import { clsx } from '@dbeaver/ui-kit';
|
||||
import { type ISettingDescription, type ISettingsSource } from '@cloudbeaver/core-settings';
|
||||
import { SettingField } from './SettingField.js';
|
||||
|
||||
interface Props {
|
||||
source: ISettingsSource;
|
||||
@@ -25,117 +18,29 @@ interface Props {
|
||||
}
|
||||
|
||||
export const Setting = observer<Props>(function Setting({ source, setting }) {
|
||||
const settingsResolverService = useService(SettingsResolverService);
|
||||
const settingsProviderService = useService(SettingsProviderService);
|
||||
const translate = useTranslate();
|
||||
// DODO: hide this logic until we have more than one scope
|
||||
const isOverride = source.has(setting.key) && source.getEditedValue(setting.key) !== null && false;
|
||||
|
||||
const name = translate(setting.name);
|
||||
const description = translate(setting.description);
|
||||
const disabled = false;
|
||||
const readOnly = settingsResolverService.isReadOnly(setting.key) ?? false;
|
||||
|
||||
let value = source.getEditedValue(setting.key);
|
||||
if (readOnly || !isNotNullDefined(value)) {
|
||||
value = settingsResolverService.getEditedValue(setting.key);
|
||||
}
|
||||
|
||||
if (setting.key in settingsProviderService.schema.shape) {
|
||||
const schema = settingsProviderService.schema.shape[setting.key];
|
||||
if (!isNotNullDefined(value)) {
|
||||
const result = schema.safeParse(undefined);
|
||||
value = result.success ? result.data : '';
|
||||
}
|
||||
|
||||
const result = schema.safeParse(value);
|
||||
value = result.success ? result.data : value;
|
||||
}
|
||||
|
||||
value = value ?? '';
|
||||
|
||||
const customValidation = useCustomInputValidation(value => {
|
||||
if (!(setting.key in settingsProviderService.schema.shape)) {
|
||||
return null;
|
||||
}
|
||||
const result = settingsProviderService.schema.shape[setting.key].safeParse(value);
|
||||
|
||||
if (result.success) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return schemaValidationError(result.error, { prefix: null }).toString();
|
||||
});
|
||||
|
||||
function handleChange(value: any) {
|
||||
source.setValue(setting.key, value);
|
||||
}
|
||||
|
||||
if (setting.type === ESettingsValueType.Checkbox) {
|
||||
return (
|
||||
<FieldCheckbox
|
||||
id={String(setting.key)}
|
||||
checked={value}
|
||||
label={name}
|
||||
title={name}
|
||||
caption={description}
|
||||
disabled={disabled}
|
||||
readOnly={readOnly}
|
||||
groupGap
|
||||
onChange={handleChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (setting.type === ESettingsValueType.Select) {
|
||||
const options = setting.options?.map(option => ({ ...option, name: translate(option.name) })) || [];
|
||||
return (
|
||||
<Combobox
|
||||
id={String(setting.key)}
|
||||
items={options}
|
||||
keySelector={value => value.value}
|
||||
valueSelector={value => value.name}
|
||||
value={value}
|
||||
title={name}
|
||||
disabled={disabled}
|
||||
readOnly={readOnly}
|
||||
description={description}
|
||||
small
|
||||
onSelect={handleChange}
|
||||
>
|
||||
{name}
|
||||
</Combobox>
|
||||
);
|
||||
}
|
||||
|
||||
if (setting.type === ESettingsValueType.Textarea) {
|
||||
return (
|
||||
<Textarea
|
||||
id={String(setting.key)}
|
||||
title={value}
|
||||
labelTooltip={description}
|
||||
value={value}
|
||||
disabled={disabled}
|
||||
readOnly={readOnly}
|
||||
onChange={handleChange}
|
||||
>
|
||||
{name}
|
||||
</Textarea>
|
||||
);
|
||||
function handleRestore() {
|
||||
source.setValue(setting.key, null);
|
||||
}
|
||||
|
||||
return (
|
||||
<InputField
|
||||
ref={customValidation}
|
||||
id={String(setting.key)}
|
||||
type="text"
|
||||
title={value}
|
||||
labelTooltip={description}
|
||||
value={value}
|
||||
description={description}
|
||||
readOnly={readOnly || disabled}
|
||||
small
|
||||
onChange={handleChange}
|
||||
>
|
||||
{name}
|
||||
</InputField>
|
||||
<div className='tw:flex tw:relative tw:gap-2'>
|
||||
<div className="tw:w-1 tw:h-full" hidden>
|
||||
{isOverride && (
|
||||
<div className={clsx('tw:h-full tw:w-full tw:bg-zinc-100 tw:dark:bg-zinc-700')} title={translate('plugin_settings_panel_setting_set_in_scope')} />
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<SettingField setting={setting} source={source} />
|
||||
{isOverride && (
|
||||
<Link className="theme-typography--caption" title={translate('plugin_settings_panel_setting_reset_tooltip')} onClick={handleRestore}>
|
||||
{translate('plugin_settings_panel_setting_reset')}
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* 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 { Combobox, FieldCheckbox, InputField, Textarea, useCustomInputValidation, useTranslate } from '@cloudbeaver/core-blocks';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import {
|
||||
ESettingsValueType,
|
||||
SettingsProviderService,
|
||||
SettingsResolverService,
|
||||
type ISettingDescription,
|
||||
type ISettingsSource,
|
||||
} from '@cloudbeaver/core-settings';
|
||||
import { schemaValidationError } from '@cloudbeaver/core-utils';
|
||||
import { isNotNullDefined } from '@dbeaver/js-helpers';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
|
||||
interface Props {
|
||||
source: ISettingsSource;
|
||||
setting: ISettingDescription;
|
||||
}
|
||||
|
||||
export const SettingField = observer<Props>(function SettingField({ setting, source }) {
|
||||
const settingsResolverService = useService(SettingsResolverService);
|
||||
const settingsProviderService = useService(SettingsProviderService);
|
||||
const translate = useTranslate();
|
||||
|
||||
const name = translate(setting.name);
|
||||
const description = translate(setting.description);
|
||||
const disabled = false;
|
||||
// TODO: need to figure out how to ignore user scope settings during configuring admin settings
|
||||
// probably we can use layers to skip some layers when checking settings
|
||||
// const readOnly = settingsResolverService.isReadOnly(setting.key, source) ?? false;
|
||||
const readOnly = false;
|
||||
|
||||
let value = source.getEditedValue(setting.key);
|
||||
if (readOnly || !isNotNullDefined(value)) {
|
||||
value = settingsResolverService.getEditedValue(setting.key);
|
||||
}
|
||||
|
||||
if (setting.key in settingsProviderService.schema.shape) {
|
||||
const schema = settingsProviderService.schema.shape[setting.key];
|
||||
if (!isNotNullDefined(value)) {
|
||||
const result = schema.safeParse(undefined);
|
||||
value = result.success ? result.data : '';
|
||||
}
|
||||
|
||||
const result = schema.safeParse(value);
|
||||
value = result.success ? result.data : value;
|
||||
}
|
||||
|
||||
value = value ?? '';
|
||||
|
||||
const customValidation = useCustomInputValidation(value => {
|
||||
if (!(setting.key in settingsProviderService.schema.shape)) {
|
||||
return null;
|
||||
}
|
||||
const result = settingsProviderService.schema.shape[setting.key].safeParse(value);
|
||||
|
||||
if (result.success) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return schemaValidationError(result.error, { prefix: null }).toString();
|
||||
});
|
||||
|
||||
function handleChange(value: any) {
|
||||
source.setValue(setting.key, value);
|
||||
}
|
||||
|
||||
if (setting.type === ESettingsValueType.Checkbox) {
|
||||
return (
|
||||
<FieldCheckbox
|
||||
id={String(setting.key)}
|
||||
checked={value}
|
||||
label={name}
|
||||
title={name}
|
||||
caption={description}
|
||||
disabled={disabled}
|
||||
readOnly={readOnly}
|
||||
groupGap
|
||||
onChange={handleChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (setting.type === ESettingsValueType.Select) {
|
||||
const options = setting.options?.map(option => ({ ...option, name: translate(option.name) })) || [];
|
||||
return (
|
||||
<Combobox
|
||||
id={String(setting.key)}
|
||||
items={options}
|
||||
keySelector={value => value.value}
|
||||
valueSelector={value => value.name}
|
||||
value={value}
|
||||
title={name}
|
||||
disabled={disabled}
|
||||
readOnly={readOnly}
|
||||
description={description}
|
||||
small
|
||||
onSelect={handleChange}
|
||||
>
|
||||
{name}
|
||||
</Combobox>
|
||||
);
|
||||
}
|
||||
|
||||
if (setting.type === ESettingsValueType.Textarea) {
|
||||
return (
|
||||
<Textarea
|
||||
id={String(setting.key)}
|
||||
title={value}
|
||||
labelTooltip={description}
|
||||
value={value}
|
||||
disabled={disabled}
|
||||
readOnly={readOnly}
|
||||
onChange={handleChange}
|
||||
>
|
||||
{name}
|
||||
</Textarea>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<InputField
|
||||
ref={customValidation}
|
||||
id={String(setting.key)}
|
||||
type="text"
|
||||
title={value}
|
||||
labelTooltip={description}
|
||||
value={value}
|
||||
description={description}
|
||||
readOnly={readOnly || disabled}
|
||||
small
|
||||
onChange={handleChange}
|
||||
>
|
||||
{name}
|
||||
</InputField>
|
||||
);
|
||||
});
|
||||
@@ -5,13 +5,14 @@
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
import { useId, useState } from 'react';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
|
||||
import { Container, Filter, Group, s, TextPlaceholder, useTranslate } from '@cloudbeaver/core-blocks';
|
||||
import { type ISettingsSource, ROOT_SETTINGS_GROUP, SettingsGroup } from '@cloudbeaver/core-settings';
|
||||
import { useTreeData, useTreeFilter } from '@cloudbeaver/plugin-navigation-tree';
|
||||
import { SyncExecutor } from '@cloudbeaver/core-executor';
|
||||
|
||||
import { getSettingGroupId } from './getSettingGroupId.js';
|
||||
import classes from './Settings.module.css';
|
||||
import { settingsFilter } from './settingsFilter.js';
|
||||
import { SettingsGroups } from './SettingsGroups/SettingsGroups.js';
|
||||
@@ -25,7 +26,9 @@ export interface ISettingsProps {
|
||||
|
||||
export const Settings = observer<ISettingsProps>(function Settings({ source, accessor }) {
|
||||
const translate = useTranslate();
|
||||
const settingsId = useId();
|
||||
const settings = useSettings(accessor);
|
||||
const [groupSelectExecutor] = useState(() => new SyncExecutor<string>());
|
||||
|
||||
function filterExistsGroups(group: SettingsGroup) {
|
||||
return settings.groups.has(group);
|
||||
@@ -71,12 +74,12 @@ export const Settings = observer<ISettingsProps>(function Settings({ source, acc
|
||||
}
|
||||
|
||||
function handleClick(id: string) {
|
||||
document.querySelector('#' + getSettingGroupId(id))?.scrollIntoView();
|
||||
groupSelectExecutor.execute(id);
|
||||
}
|
||||
|
||||
return (
|
||||
<Container gap overflow noWrap>
|
||||
<Group className={s(classes, { settingsGroups: true })} vertical box keepSize overflow hidden>
|
||||
<Group className={s(classes, { settingsGroups: true })} vertical box keepSize overflow>
|
||||
<SettingsGroups treeData={treeData} onClick={handleClick} />
|
||||
</Group>
|
||||
<Container className={s(classes, { settingsContainer: true })} overflow vertical gap noWrap>
|
||||
@@ -89,7 +92,14 @@ export const Settings = observer<ISettingsProps>(function Settings({ source, acc
|
||||
/>
|
||||
</Container>
|
||||
<Container overflow vertical>
|
||||
<SettingsList treeData={treeData} treeFilter={treeFilter} source={source} settings={settings.settings} />
|
||||
<SettingsList
|
||||
settingsId={settingsId}
|
||||
treeData={treeData}
|
||||
treeFilter={treeFilter}
|
||||
source={source}
|
||||
settings={settings.settings}
|
||||
groupSelectExecutor={groupSelectExecutor}
|
||||
/>
|
||||
</Container>
|
||||
</Container>
|
||||
</Container>
|
||||
|
||||
@@ -1,35 +1,59 @@
|
||||
/*
|
||||
* 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 { observer } from 'mobx-react-lite';
|
||||
|
||||
import { getComputed, Group, GroupTitle, useTranslate } from '@cloudbeaver/core-blocks';
|
||||
import { getComputed, Group, GroupTitle, useExecutor, useTranslate } from '@cloudbeaver/core-blocks';
|
||||
import type { ISettingDescription, ISettingsSource, SettingsGroup as SettingsGroupType } from '@cloudbeaver/core-settings';
|
||||
import { isArraysEqual } from '@cloudbeaver/core-utils';
|
||||
import type { ITreeFilter } from '@cloudbeaver/plugin-navigation-tree';
|
||||
|
||||
import { getSettingGroupId } from './getSettingGroupId.js';
|
||||
import { Setting } from './Setting.js';
|
||||
import { settingsFilter } from './settingsFilter.js';
|
||||
import { SettingsGroupTitle } from './SettingsGroupTitle.js';
|
||||
import type { ISyncExecutor } from '@cloudbeaver/core-executor';
|
||||
import { useRef } from 'react';
|
||||
import { getSettingGroupId } from './getSettingGroupId.js';
|
||||
|
||||
interface Props {
|
||||
settingsId: string;
|
||||
group: SettingsGroupType;
|
||||
source: ISettingsSource;
|
||||
settings: Map<SettingsGroupType, ISettingDescription<any>[]>;
|
||||
treeFilter: ITreeFilter;
|
||||
groupSelectExecutor: ISyncExecutor<string>;
|
||||
}
|
||||
|
||||
export const SettingsGroup = observer<Props>(function SettingsGroup({ group, source, settings, treeFilter }) {
|
||||
export const SettingsGroup = observer<Props>(function SettingsGroup({ settingsId, group, source, settings, treeFilter, groupSelectExecutor }) {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const translate = useTranslate();
|
||||
const groupSettings = getComputed(() => settings.get(group)?.filter(settingsFilter(translate, treeFilter.filter)) || [], isArraysEqual);
|
||||
const hidden = groupSettings.length === 0;
|
||||
|
||||
useExecutor({
|
||||
executor: groupSelectExecutor,
|
||||
handlers: [
|
||||
id => {
|
||||
if (id === group.id) {
|
||||
if (hidden) {
|
||||
const next = ref.current?.nextSibling;
|
||||
if (next instanceof HTMLElement) {
|
||||
next?.scrollIntoView();
|
||||
}
|
||||
} else {
|
||||
ref.current?.scrollIntoView();
|
||||
}
|
||||
}
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
return (
|
||||
<Group id={getSettingGroupId(group.id)} hidden={groupSettings.length === 0} vertical gap>
|
||||
<Group ref={ref} id={getSettingGroupId(settingsId, group.id)} hidden={hidden} vertical gap compact>
|
||||
<GroupTitle sticky>
|
||||
<SettingsGroupTitle group={group} />
|
||||
</GroupTitle>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/*
|
||||
* 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 { observer } from 'mobx-react-lite';
|
||||
|
||||
import { Container, s, TextPlaceholder, useTranslate } from '@cloudbeaver/core-blocks';
|
||||
import { Group, s, TextPlaceholder, useTranslate } from '@cloudbeaver/core-blocks';
|
||||
import { type ISettingDescription, type ISettingsSource, type SettingsGroup as SettingsGroupType } from '@cloudbeaver/core-settings';
|
||||
import type { ITreeData, ITreeFilter } from '@cloudbeaver/plugin-navigation-tree';
|
||||
|
||||
@@ -15,27 +15,46 @@ import { getGroupsFromTree } from './getGroupsFromTree.js';
|
||||
import { SettingsGroup } from './SettingsGroup.js';
|
||||
import classes from './SettingsList.module.css';
|
||||
import { useTreeScrollSync } from './useTreeScrollSync.js';
|
||||
import type { ISyncExecutor } from '@cloudbeaver/core-executor';
|
||||
|
||||
interface Props {
|
||||
settingsId: string;
|
||||
treeData: ITreeData;
|
||||
treeFilter: ITreeFilter;
|
||||
source: ISettingsSource;
|
||||
settings: Map<SettingsGroupType, ISettingDescription<any>[]>;
|
||||
groupSelectExecutor: ISyncExecutor<string>;
|
||||
onSettingsOpen?: (groupId: string) => void;
|
||||
}
|
||||
|
||||
export const SettingsList = observer<Props>(function SettingsList({ treeData, treeFilter, source, settings, onSettingsOpen }) {
|
||||
export const SettingsList = observer<Props>(function SettingsList({
|
||||
settingsId,
|
||||
treeData,
|
||||
treeFilter,
|
||||
source,
|
||||
settings,
|
||||
groupSelectExecutor,
|
||||
onSettingsOpen,
|
||||
}) {
|
||||
const translate = useTranslate();
|
||||
const ref = useTreeScrollSync(treeData, onSettingsOpen);
|
||||
const ref = useTreeScrollSync(settingsId, treeData, onSettingsOpen);
|
||||
const groups = Array.from(getGroupsFromTree(treeData, treeData.getChildren(treeData.rootId)));
|
||||
|
||||
return (
|
||||
<Container ref={ref} gap overflow>
|
||||
<Group ref={ref} parent box overflow>
|
||||
{groups.map(group => (
|
||||
<SettingsGroup key={group.id} group={group} source={source} settings={settings} treeFilter={treeFilter} />
|
||||
<SettingsGroup
|
||||
key={group.id}
|
||||
settingsId={settingsId}
|
||||
group={group}
|
||||
source={source}
|
||||
settings={settings}
|
||||
treeFilter={treeFilter}
|
||||
groupSelectExecutor={groupSelectExecutor}
|
||||
/>
|
||||
))}
|
||||
{groups.length === 0 && <TextPlaceholder>{translate('plugin_settings_panel_no_settings')}</TextPlaceholder>}
|
||||
<div className={s(classes, { spaceFill: true })} />
|
||||
</Container>
|
||||
</Group>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* 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 { SETTINGS_GROUP_ID_PREFIX } from './SETTINGS_GROUP_ID_PREFIX.js';
|
||||
|
||||
export function getSettingGroupId(id: string): string {
|
||||
return `${SETTINGS_GROUP_ID_PREFIX}${id}`;
|
||||
export function getSettingGroupId(settingsId: string, id: string): string {
|
||||
return `${SETTINGS_GROUP_ID_PREFIX}${settingsId}-${id}`;
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* 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 { SETTINGS_GROUP_ID_PREFIX } from './SETTINGS_GROUP_ID_PREFIX.js';
|
||||
|
||||
export function getSettingGroupIdFromElementId(id: string): string {
|
||||
return id.replace(SETTINGS_GROUP_ID_PREFIX, '');
|
||||
export function getSettingGroupIdFromElementId(settingsId: string, id: string): string {
|
||||
return id.replace(SETTINGS_GROUP_ID_PREFIX + `${settingsId}-`, '');
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -26,7 +26,7 @@ export function useSettings(accessor?: string[]): ISettings {
|
||||
get settings() {
|
||||
const map = new Map();
|
||||
const settings = this.settingsManagerService.activeSettings
|
||||
.filter(setting => accessor?.some(value => setting.access.scope.includes(value)))
|
||||
.filter(setting => this.accessor?.some(value => setting.access.scope.includes(value)))
|
||||
.sort((a, b) => a.name.localeCompare(b.name));
|
||||
|
||||
for (const setting of settings) {
|
||||
@@ -54,6 +54,7 @@ export function useSettings(accessor?: string[]): ISettings {
|
||||
settings: computed,
|
||||
groups: computed,
|
||||
settingsManagerService: observable.ref,
|
||||
accessor: observable.ref,
|
||||
},
|
||||
{ settingsManagerService, accessor },
|
||||
);
|
||||
|
||||
@@ -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.
|
||||
@@ -14,7 +14,11 @@ import type { ITreeData } from '@cloudbeaver/plugin-navigation-tree';
|
||||
import { getSettingGroupIdFromElementId } from './getSettingGroupIdFromElementId.js';
|
||||
import { querySettingsGroups } from './querySettingsGroups.js';
|
||||
|
||||
export function useTreeScrollSync(treeData: ITreeData, onSettingsOpen?: (groupId: string) => void): React.RefObject<HTMLDivElement | null> {
|
||||
export function useTreeScrollSync(
|
||||
settingsId: string,
|
||||
treeData: ITreeData,
|
||||
onSettingsOpen?: (groupId: string) => void,
|
||||
): React.RefObject<HTMLDivElement | null> {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -38,7 +42,7 @@ export function useTreeScrollSync(treeData: ITreeData, onSettingsOpen?: (groupId
|
||||
}
|
||||
|
||||
if (firstVisibleElement) {
|
||||
const groupId = getSettingGroupIdFromElementId(firstVisibleElement.id);
|
||||
const groupId = getSettingGroupIdFromElementId(settingsId, firstVisibleElement.id);
|
||||
let group = ROOT_SETTINGS_GROUP.get(groupId)!;
|
||||
|
||||
treeData.updateAllState({ selected: false, expanded: false });
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user