mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-09-24 16:04:36 +08:00
dbeaver/pro#7566 feat: add settings functionality to the new tree (#4184)
* dbeaver/pro#7566 feat: add settings functionality to the new tree Implemented settings as a part of Toolbar. The key reason was that the TreeToolbar sets different contexts for all other actions related to tree and easily extendible as a menu service. It might limit in some weird cases, but for now it looks like a valid decision Settings are made as unknown intentionally to be polymorphic. We could use Record<string, unknown> instead, but I don't see it really improving anything. * dbeaver/pro#7566 refactor: introduce ITreeSettings interface add filter with settings connection via useTreeFilterState hook * dbeaver/pro#7566 refactor: remove redundant hooks, update ITreeSettings * dbeaver/pro#7566 refactor: move actions to cloudbeaver part * dbeaver/pro#7566 feat: add universal hook that persists any tree settings via UserDataService as a flat key-value record * dbeaver/pro#7566 refactor: remove unused childrenTransformers and stateTransformers from ITreeFilterState * dbeaver/pro#7566 feat: enhance tree settings functionality with replace method and user data synchronization * dbeaver/pro#7566 refactor: remove toolbarFilter from ITreeFilterState interface * dbeaver/pro#7566 refactor: simplify useUserTreeSettings * dbeaver/pro#7566 fix: lint rule and defaults inconsistency * dbeaver/pro#7566 fix: defaults * dbeaver/pro#7566 fix: update Russian translations for navigation tree settings --------- Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com> Co-authored-by: sergeyteleshev <iamsergeyteleshev@gmail.com>
This commit is contained in:
co-authored by
Evgenia
sergeyteleshev
parent
051695451b
commit
2abdbce8ff
+5
-2
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2025 DBeaver Corp and others
|
||||
* Copyright (C) 2020-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -10,17 +10,19 @@ import { Bootstrap, injectable } from '@cloudbeaver/core-di';
|
||||
import { LeftBarPanelService } from '@cloudbeaver/core-ui';
|
||||
|
||||
import { NavigationTreeSettingsService } from '../NavigationTreeSettingsService.js';
|
||||
import { TreeSettingsMenuService } from '../TreeNew/TreeSettingsMenuService.js';
|
||||
import { TreeToolbarMenuService } from '../TreeNew/TreeToolbarMenuService.js';
|
||||
import { ElementsTreeToolsMenuService } from './ElementsTree/ElementsTreeTools/ElementsTreeToolsMenuService.js';
|
||||
|
||||
const NavigationTreePanel = importLazyComponent(() => import('./NavigationTreePanel.js').then(m => m.NavigationTreePanel));
|
||||
|
||||
@injectable(() => [NavigationTreeSettingsService, ElementsTreeToolsMenuService, TreeToolbarMenuService, LeftBarPanelService])
|
||||
@injectable(() => [NavigationTreeSettingsService, ElementsTreeToolsMenuService, TreeToolbarMenuService, TreeSettingsMenuService, LeftBarPanelService])
|
||||
export class NavigationTreeBootstrap extends Bootstrap {
|
||||
constructor(
|
||||
private readonly navigationTreeSettingsService: NavigationTreeSettingsService,
|
||||
private readonly elementsTreeToolsMenuService: ElementsTreeToolsMenuService,
|
||||
private readonly treeToolbarMenuService: TreeToolbarMenuService,
|
||||
private readonly treeSettingsMenuService: TreeSettingsMenuService,
|
||||
private readonly leftBarPanelService: LeftBarPanelService,
|
||||
) {
|
||||
super();
|
||||
@@ -29,6 +31,7 @@ export class NavigationTreeBootstrap extends Bootstrap {
|
||||
override register(): void {
|
||||
this.elementsTreeToolsMenuService.register();
|
||||
this.treeToolbarMenuService.register();
|
||||
this.treeSettingsMenuService.register();
|
||||
this.leftBarPanelService.tabsContainer.add({
|
||||
key: 'navigation-tree-tab',
|
||||
order: 0,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2025 DBeaver Corp and others
|
||||
* Copyright (C) 2020-2026 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,11 +8,13 @@
|
||||
import { createDataContext } from '@cloudbeaver/core-data-context';
|
||||
|
||||
import type { ITreeData } from './ITreeData.js';
|
||||
import type { ITreeFilter } from './useTreeFilter.js';
|
||||
import type { ITreeFilter, ITreeFilterState } from './useTreeFilter.js';
|
||||
import type { ITreeSettings } from './useTreeSettings.js';
|
||||
|
||||
export type ITreeToolbarFilter = ITreeFilter & { filterPlaceholder?: string };
|
||||
export type ITreeToolbarFilter = ITreeFilter & ITreeFilterState & { filterPlaceholder?: string };
|
||||
export type TreeRefreshHandler = () => Promise<void>;
|
||||
|
||||
export const DATA_CONTEXT_TREE_DATA = createDataContext<ITreeData>('tree-new-data');
|
||||
export const DATA_CONTEXT_TREE_FILTER = createDataContext<ITreeToolbarFilter>('tree-new-filter');
|
||||
export const DATA_CONTEXT_TREE_REFRESH = createDataContext<TreeRefreshHandler>('tree-new-refresh');
|
||||
export const DATA_CONTEXT_TREE_SETTINGS = createDataContext<ITreeSettings>('tree-new-settings');
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2026 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 { createMenu } from '@cloudbeaver/core-view';
|
||||
|
||||
export const MENU_TREE_SETTINGS = createMenu('tree-settings', {
|
||||
label: 'plugin_navigation_tree_settings_menu_title',
|
||||
icon: '/icons/settings_cog_sm.svg',
|
||||
});
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2026 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 { IDataContextProvider } from '@cloudbeaver/core-data-context';
|
||||
import { injectable } from '@cloudbeaver/core-di';
|
||||
import { ActionService, type IAction, MenuService } from '@cloudbeaver/core-view';
|
||||
|
||||
import { DATA_CONTEXT_TREE_SETTINGS } from './DATA_CONTEXT_TREE.js';
|
||||
import { MENU_TREE_SETTINGS } from './MENU_TREE_SETTINGS.js';
|
||||
import { ACTION_TREE_SAVE_STATE } from './actions/ACTION_TREE_SAVE_STATE.js';
|
||||
import { ACTION_TREE_SHOW_DESCRIPTIONS } from './actions/ACTION_TREE_SHOW_DESCRIPTIONS.js';
|
||||
import { ACTION_TREE_SHOW_FILTER } from './actions/ACTION_TREE_SHOW_FILTER.js';
|
||||
import { TREE_SETTINGS_FILTER_ENABLED } from './useTreeFilter.js';
|
||||
|
||||
export const TREE_SETTINGS_SHOW_DESCRIPTIONS = 'tree.showDescriptions';
|
||||
export const TREE_SETTINGS_SAVE_STATE = 'tree.saveState';
|
||||
|
||||
@injectable(() => [ActionService, MenuService])
|
||||
export class TreeSettingsMenuService {
|
||||
constructor(
|
||||
private readonly actionService: ActionService,
|
||||
private readonly menuService: MenuService,
|
||||
) { }
|
||||
|
||||
register(): void {
|
||||
this.actionService.addHandler({
|
||||
id: 'tree-settings-handler',
|
||||
menus: [MENU_TREE_SETTINGS],
|
||||
actions: [ACTION_TREE_SHOW_FILTER, ACTION_TREE_SHOW_DESCRIPTIONS, ACTION_TREE_SAVE_STATE],
|
||||
contexts: [DATA_CONTEXT_TREE_SETTINGS],
|
||||
isActionApplicable(context: IDataContextProvider): boolean {
|
||||
const settings = context.get(DATA_CONTEXT_TREE_SETTINGS);
|
||||
return settings !== undefined;
|
||||
},
|
||||
isChecked(context: IDataContextProvider, action: IAction): boolean {
|
||||
const settings = context.get(DATA_CONTEXT_TREE_SETTINGS);
|
||||
|
||||
if (!settings) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (action === ACTION_TREE_SHOW_FILTER) {
|
||||
return settings.get<boolean>(TREE_SETTINGS_FILTER_ENABLED) ?? false;
|
||||
}
|
||||
|
||||
if (action === ACTION_TREE_SHOW_DESCRIPTIONS) {
|
||||
return settings.get<boolean>(TREE_SETTINGS_SHOW_DESCRIPTIONS) ?? false;
|
||||
}
|
||||
|
||||
if (action === ACTION_TREE_SAVE_STATE) {
|
||||
return settings.get<boolean>(TREE_SETTINGS_SAVE_STATE) ?? false;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
handler(context: IDataContextProvider, action: IAction): void {
|
||||
const settings = context.get(DATA_CONTEXT_TREE_SETTINGS);
|
||||
|
||||
if (!settings) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (action === ACTION_TREE_SHOW_FILTER) {
|
||||
settings.set(TREE_SETTINGS_FILTER_ENABLED, !(settings.get<boolean>(TREE_SETTINGS_FILTER_ENABLED) ?? false));
|
||||
} else if (action === ACTION_TREE_SHOW_DESCRIPTIONS) {
|
||||
settings.set(TREE_SETTINGS_SHOW_DESCRIPTIONS, !(settings.get<boolean>(TREE_SETTINGS_SHOW_DESCRIPTIONS) ?? false));
|
||||
} else if (action === ACTION_TREE_SAVE_STATE) {
|
||||
settings.set(TREE_SETTINGS_SAVE_STATE, !(settings.get<boolean>(TREE_SETTINGS_SAVE_STATE) ?? false));
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
this.menuService.addCreator({
|
||||
menus: [MENU_TREE_SETTINGS],
|
||||
getItems: (context, items) => [...items, ACTION_TREE_SHOW_FILTER, ACTION_TREE_SHOW_DESCRIPTIONS, ACTION_TREE_SAVE_STATE],
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2025 DBeaver Corp and others
|
||||
* Copyright (C) 2020-2026 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,22 +8,37 @@
|
||||
|
||||
import React, { use } from 'react';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { DATA_CONTEXT_TREE_DATA, DATA_CONTEXT_TREE_FILTER, DATA_CONTEXT_TREE_REFRESH, type ITreeToolbarFilter } from './DATA_CONTEXT_TREE.js';
|
||||
import {
|
||||
DATA_CONTEXT_TREE_DATA,
|
||||
DATA_CONTEXT_TREE_FILTER,
|
||||
DATA_CONTEXT_TREE_REFRESH,
|
||||
DATA_CONTEXT_TREE_SETTINGS,
|
||||
type ITreeToolbarFilter,
|
||||
} from './DATA_CONTEXT_TREE.js';
|
||||
import type { ITreeSettings } from './useTreeSettings.js';
|
||||
|
||||
import { clsx } from '@dbeaver/ui-kit';
|
||||
import { useCaptureViewContext } from '@cloudbeaver/core-view';
|
||||
import { TreeDataContext } from './contexts/TreeDataContext.js';
|
||||
|
||||
export interface TreeToolbarProps {
|
||||
settings?: ITreeSettings;
|
||||
filter?: ITreeToolbarFilter;
|
||||
onRefresh?: () => Promise<void> | void;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const TreeToolbar = observer<React.PropsWithChildren<TreeToolbarProps>>(function TreeToolbar({ className, children, filter, onRefresh }) {
|
||||
export const TreeToolbar = observer<React.PropsWithChildren<TreeToolbarProps>>(function TreeToolbar({
|
||||
className,
|
||||
children,
|
||||
settings,
|
||||
filter,
|
||||
onRefresh,
|
||||
}) {
|
||||
const data = use(TreeDataContext);
|
||||
useCaptureViewContext((context, id) => {
|
||||
context.set(DATA_CONTEXT_TREE_DATA, data, id);
|
||||
context.set(DATA_CONTEXT_TREE_SETTINGS, settings, id);
|
||||
context.set(DATA_CONTEXT_TREE_FILTER, filter, id);
|
||||
context.set(DATA_CONTEXT_TREE_REFRESH, onRefresh, id);
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2025 DBeaver Corp and others
|
||||
* Copyright (C) 2020-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,7 +20,7 @@ export const TreeToolbarFilter = observer(function TreeToolbarFilter() {
|
||||
const context = useDataContext(viewContext);
|
||||
const filter = context.get(DATA_CONTEXT_TREE_FILTER);
|
||||
|
||||
if (!filter) {
|
||||
if (!filter?.enabled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2025 DBeaver Corp and others
|
||||
* Copyright (C) 2020-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -10,6 +10,7 @@ import { injectable } from '@cloudbeaver/core-di';
|
||||
import { ACTION_COLLAPSE_ALL, ActionService, type IAction, MenuService } from '@cloudbeaver/core-view';
|
||||
|
||||
import { DATA_CONTEXT_TREE_DATA, DATA_CONTEXT_TREE_REFRESH } from './DATA_CONTEXT_TREE.js';
|
||||
import { MENU_TREE_SETTINGS } from './MENU_TREE_SETTINGS.js';
|
||||
import { MENU_TREE_TOOLBAR } from './MENU_TREE_TOOLBAR.js';
|
||||
import { ACTION_TREE_REFRESH } from './actions/ACTION_TREE_REFRESH.js';
|
||||
|
||||
@@ -51,7 +52,7 @@ export class TreeToolbarMenuService {
|
||||
|
||||
this.menuService.addCreator({
|
||||
menus: [MENU_TREE_TOOLBAR],
|
||||
getItems: (_, items) => [...items, ACTION_TREE_REFRESH, ACTION_COLLAPSE_ALL],
|
||||
getItems: (_, items) => [...items, MENU_TREE_SETTINGS, ACTION_TREE_REFRESH, ACTION_COLLAPSE_ALL],
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2026 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 { createAction } from '@cloudbeaver/core-view';
|
||||
|
||||
export const ACTION_TREE_SAVE_STATE = createAction('tree-save-state', {
|
||||
label: 'plugin_navigation_tree_settings_save_state',
|
||||
type: 'checkbox',
|
||||
});
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2026 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 { createAction } from '@cloudbeaver/core-view';
|
||||
|
||||
export const ACTION_TREE_SHOW_DESCRIPTIONS = createAction('tree-show-descriptions', {
|
||||
label: 'plugin_navigation_tree_settings_show_descriptions',
|
||||
type: 'checkbox',
|
||||
});
|
||||
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2026 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 { createAction } from '@cloudbeaver/core-view';
|
||||
|
||||
export const ACTION_TREE_SHOW_FILTER = createAction('tree-show-filter', {
|
||||
label: 'plugin_navigation_tree_settings_show_filter',
|
||||
type: 'checkbox',
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2025 DBeaver Corp and others
|
||||
* Copyright (C) 2020-2026 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,6 +12,7 @@ import { useObjectRef, useObservableRef } from '@cloudbeaver/core-blocks';
|
||||
import type { TreeDataTransformer } from './DataTransformers/TreeDataTransformer.js';
|
||||
import type { ITreeData } from './ITreeData.js';
|
||||
import type { INodeState } from './INodeState.js';
|
||||
import type { ITreeSettings } from './useTreeSettings.js';
|
||||
|
||||
export interface ITreeFilterOptions {
|
||||
isNodeMatched?: (nodeId: string, filter: string, isMatched: boolean) => boolean;
|
||||
@@ -25,7 +26,22 @@ export interface ITreeFilter {
|
||||
setFilter(filter: string): void;
|
||||
}
|
||||
|
||||
export function useTreeFilter(options: ITreeFilterOptions = {}): Readonly<ITreeFilter> {
|
||||
export interface ITreeFilterState {
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
export type ITreeFilterWithState = Readonly<ITreeFilter & ITreeFilterState>;
|
||||
|
||||
export const TREE_SETTINGS_FILTER_ENABLED = 'tree.filter.enabled';
|
||||
|
||||
interface ITreeFilterStateObject extends ITreeFilter, ITreeFilterState {
|
||||
settings?: ITreeSettings;
|
||||
}
|
||||
|
||||
export function useTreeFilter(
|
||||
options: ITreeFilterOptions = {},
|
||||
settings?: ITreeSettings,
|
||||
): ITreeFilterWithState {
|
||||
options = useObjectRef(options);
|
||||
const matchCache = new Map<string, boolean>();
|
||||
|
||||
@@ -57,9 +73,13 @@ export function useTreeFilter(options: ITreeFilterOptions = {}): Readonly<ITreeF
|
||||
return false;
|
||||
}
|
||||
|
||||
return useObservableRef<ITreeFilter>(
|
||||
return useObservableRef<ITreeFilterStateObject>(
|
||||
() => ({
|
||||
settings,
|
||||
filter: '',
|
||||
get enabled() {
|
||||
return this.settings?.get<boolean>(TREE_SETTINGS_FILTER_ENABLED) ?? false;
|
||||
},
|
||||
isNodeMatched(treeData: ITreeData, nodeId: string): boolean {
|
||||
const filter = this.filter.trim();
|
||||
if (!filter) {
|
||||
@@ -75,6 +95,10 @@ export function useTreeFilter(options: ITreeFilterOptions = {}): Readonly<ITreeF
|
||||
return isNodeMatched || treeData.getChildren(nodeId).length > 0;
|
||||
},
|
||||
transformer(treeData: ITreeData, nodeId: string, children: string[]): string[] {
|
||||
if (!this.enabled) {
|
||||
return children;
|
||||
}
|
||||
|
||||
const filter = this.filter.trim();
|
||||
if (!filter) {
|
||||
return children;
|
||||
@@ -93,6 +117,10 @@ export function useTreeFilter(options: ITreeFilterOptions = {}): Readonly<ITreeF
|
||||
return children.filter(child => this.isNodeMatched(treeData, child));
|
||||
},
|
||||
stateTransformer(treeData: ITreeData, nodeId: string, state: INodeState): INodeState {
|
||||
if (!this.enabled) {
|
||||
return state;
|
||||
}
|
||||
|
||||
const filter = this.filter.trim();
|
||||
if (!filter) {
|
||||
return state;
|
||||
@@ -110,9 +138,10 @@ export function useTreeFilter(options: ITreeFilterOptions = {}): Readonly<ITreeF
|
||||
},
|
||||
}),
|
||||
{
|
||||
settings: observable.ref,
|
||||
filter: observable.ref,
|
||||
},
|
||||
false,
|
||||
{ settings },
|
||||
['setFilter', 'isNodeMatched', 'transformer', 'stateTransformer'],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2026 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 { action, observable } from 'mobx';
|
||||
|
||||
import { useObservableRef } from '@cloudbeaver/core-blocks';
|
||||
|
||||
export interface ITreeSettings {
|
||||
get<T>(key: string): T | undefined;
|
||||
set<T>(key: string, value: T): void;
|
||||
delete(key: string): void;
|
||||
clear(): void;
|
||||
replace(entries: Record<string, unknown>): void;
|
||||
}
|
||||
|
||||
export interface ITreeSettingsOptions {
|
||||
initialSettings?: Record<string, unknown>;
|
||||
onChange?(entities: ReadonlyMap<string, unknown>): void;
|
||||
}
|
||||
|
||||
export function useTreeSettings(options: ITreeSettingsOptions = {}): ITreeSettings {
|
||||
const { initialSettings = {}, onChange } = options;
|
||||
|
||||
return useObservableRef(
|
||||
() => ({
|
||||
settings: observable.map<string, unknown>(initialSettings),
|
||||
get<T>(key: string): T | undefined {
|
||||
return this.settings.get(key) as T | undefined;
|
||||
},
|
||||
set<T>(key: string, value: T): void {
|
||||
this.settings.set(key, value);
|
||||
onChange?.(this.settings);
|
||||
},
|
||||
delete(key: string): void {
|
||||
this.settings.delete(key);
|
||||
onChange?.(this.settings);
|
||||
},
|
||||
clear(): void {
|
||||
this.settings.clear();
|
||||
onChange?.(this.settings);
|
||||
},
|
||||
replace(entries: Record<string, unknown>): void {
|
||||
this.settings.replace(entries);
|
||||
},
|
||||
}),
|
||||
{
|
||||
settings: observable.ref,
|
||||
set: action.bound,
|
||||
delete: action.bound,
|
||||
clear: action.bound,
|
||||
replace: action.bound,
|
||||
},
|
||||
false,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2026 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 { useEffect, useRef } from 'react';
|
||||
|
||||
import { useUserData } from '@cloudbeaver/core-blocks';
|
||||
|
||||
import { type ITreeSettings, useTreeSettings } from './useTreeSettings.js';
|
||||
|
||||
function validateRecord(data: unknown): boolean {
|
||||
return typeof data === 'object' && data !== null && !Array.isArray(data);
|
||||
}
|
||||
|
||||
export function useUserTreeSettings(settingsId: string): ITreeSettings {
|
||||
const persistedSettingsRef = useRef<Record<string, unknown> | null>(null);
|
||||
const treeSettingsRef = useRef<ITreeSettings | null>(null);
|
||||
|
||||
const persistedSettings = useUserData<Record<string, unknown>>(
|
||||
settingsId,
|
||||
() => ({}),
|
||||
data => {
|
||||
treeSettingsRef.current?.replace(data);
|
||||
},
|
||||
validateRecord,
|
||||
);
|
||||
|
||||
const treeSettings = useTreeSettings({
|
||||
initialSettings: persistedSettings,
|
||||
onChange(newSettings) {
|
||||
const current = persistedSettingsRef.current;
|
||||
|
||||
if (!current) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const key of Object.keys(current)) {
|
||||
if (!newSettings.has(key)) {
|
||||
delete current[key];
|
||||
}
|
||||
}
|
||||
|
||||
for (const [key, value] of newSettings) {
|
||||
current[key] = value;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
persistedSettingsRef.current = persistedSettings;
|
||||
treeSettingsRef.current = treeSettings;
|
||||
});
|
||||
|
||||
return treeSettings;
|
||||
}
|
||||
@@ -54,6 +54,8 @@ export * from './TreeNew/NodeControlLazy.js';
|
||||
export * from './TreeNew/useTreeData.js';
|
||||
export * from './TreeNew/ITreeData.js';
|
||||
export * from './TreeNew/useTreeFilter.js';
|
||||
export * from './TreeNew/useTreeSettings.js';
|
||||
export * from './TreeNew/useUserTreeSettings.js';
|
||||
export * from './TreeNew/useTreeSelection.js';
|
||||
export * from './TreeNew/useTreeClickSelection.js';
|
||||
export * from './TreeNew/ITreeSelection.js';
|
||||
@@ -65,7 +67,12 @@ export * from './TreeNew/TreeToolbarMenuLazy.js';
|
||||
export * from './TreeNew/TreeToolbarMenuService.js';
|
||||
export * from './TreeNew/DATA_CONTEXT_TREE.js';
|
||||
export * from './TreeNew/MENU_TREE_TOOLBAR.js';
|
||||
export * from './TreeNew/MENU_TREE_SETTINGS.js';
|
||||
export * from './TreeNew/actions/ACTION_TREE_REFRESH.js';
|
||||
export * from './TreeNew/actions/ACTION_TREE_SHOW_FILTER.js';
|
||||
export * from './TreeNew/actions/ACTION_TREE_SHOW_DESCRIPTIONS.js';
|
||||
export * from './TreeNew/actions/ACTION_TREE_SAVE_STATE.js';
|
||||
export * from './TreeNew/TreeSettingsMenuService.js';
|
||||
|
||||
export * from './NavigationTree/getNavigationTreeUserSettingsId.js';
|
||||
export * from './NodesManager/NavNodeView/IFolderTransform.js';
|
||||
|
||||
@@ -35,4 +35,8 @@ export default [
|
||||
['plugin_navigation_tree_settings_disable', 'Disable'],
|
||||
['plugin_navigation_tree_settings_disable_description', 'Disable navigation tree for all users'],
|
||||
['plugin_navigation_tree_toolbar_menu_title', 'Tree Toolbar'],
|
||||
['plugin_navigation_tree_settings_menu_title', 'Tree settings'],
|
||||
['plugin_navigation_tree_settings_show_filter', 'Show filter'],
|
||||
['plugin_navigation_tree_settings_show_descriptions', 'Show descriptions'],
|
||||
['plugin_navigation_tree_settings_save_state', 'Save tree state'],
|
||||
];
|
||||
|
||||
@@ -36,4 +36,5 @@ export default [
|
||||
['plugin_navigation_tree_settings_disable', 'Désactiver'],
|
||||
['plugin_navigation_tree_settings_disable_description', 'Désactiver l’arborescence de navigation pour tous les utilisateurs'],
|
||||
['plugin_navigation_tree_toolbar_menu_title', "Barre d'outils de l'arborescence"],
|
||||
['plugin_navigation_tree_settings_menu_title', "Paramètres de l'arborescence"],
|
||||
];
|
||||
|
||||
@@ -32,4 +32,5 @@ export default [
|
||||
['plugin_navigation_tree_settings_disable', 'Disabilita'],
|
||||
['plugin_navigation_tree_settings_disable_description', "Disabilita l'albero di navigazione per tutti gli utenti"],
|
||||
['plugin_navigation_tree_toolbar_menu_title', "Barra degli strumenti dell'albero"],
|
||||
['plugin_navigation_tree_settings_menu_title', "Impostazioni dell'albero"],
|
||||
];
|
||||
|
||||
@@ -38,4 +38,8 @@ export default [
|
||||
['plugin_navigation_tree_settings_disable', 'Отключить'],
|
||||
['plugin_navigation_tree_settings_disable_description', 'Отключить дерево навигации для всех пользователей'],
|
||||
['plugin_navigation_tree_toolbar_menu_title', 'Панель инструментов дерева'],
|
||||
['plugin_navigation_tree_settings_menu_title', 'Настройки дерева'],
|
||||
['plugin_navigation_tree_settings_show_filter', 'Показывать фильтр'],
|
||||
['plugin_navigation_tree_settings_show_descriptions', 'Показывать описания'],
|
||||
['plugin_navigation_tree_settings_save_state', 'Сохранять состояние дерева'],
|
||||
];
|
||||
|
||||
@@ -35,4 +35,5 @@ export default [
|
||||
['plugin_navigation_tree_settings_disable', 'Tắt'],
|
||||
['plugin_navigation_tree_settings_disable_description', 'Tắt cây điều hướng cho tất cả người dùng'],
|
||||
['plugin_navigation_tree_toolbar_menu_title', 'Menu Thanh công cụ Cây'],
|
||||
['plugin_navigation_tree_settings_menu_title', 'Cài đặt Cây'],
|
||||
];
|
||||
|
||||
@@ -34,4 +34,5 @@ export default [
|
||||
['plugin_navigation_tree_settings_disable', 'Disable'],
|
||||
['plugin_navigation_tree_settings_disable_description', 'Disable navigation tree for all users'],
|
||||
['plugin_navigation_tree_toolbar_menu_title', '树工具栏菜单'],
|
||||
['plugin_navigation_tree_settings_menu_title', '树设置'],
|
||||
];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2025 DBeaver Corp and others
|
||||
* Copyright (C) 2020-2026 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,6 +17,7 @@ import { ElementsTreeSettingsService } from './NavigationTree/ElementsTree/Eleme
|
||||
import { ElementsTreeToolsMenuService } from './NavigationTree/ElementsTree/ElementsTreeTools/ElementsTreeToolsMenuService.js';
|
||||
import { ElementsTreeService } from './NavigationTree/ElementsTree/ElementsTreeService.js';
|
||||
import { TreeToolbarMenuService } from './TreeNew/TreeToolbarMenuService.js';
|
||||
import { TreeSettingsMenuService } from './TreeNew/TreeSettingsMenuService.js';
|
||||
import { LocaleService } from './LocaleService.js';
|
||||
|
||||
export default ModuleRegistry.add({
|
||||
@@ -37,6 +38,7 @@ export default ModuleRegistry.add({
|
||||
.addSingleton(ElementsTreeSettingsService)
|
||||
.addSingleton(ElementsTreeToolsMenuService)
|
||||
.addSingleton(TreeToolbarMenuService)
|
||||
.addSingleton(TreeSettingsMenuService)
|
||||
.addSingleton(ElementsTreeService);
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user