mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-08-22 00:42:47 +08:00
✨ feat(sidebar): 支持自定义对象分类显示
新增侧栏对象分类开关与仅显示表快捷设置 配置持久化并即时应用到所有连接 补充筛选、持久化与国际化回归测试
This commit is contained in:
@@ -15,7 +15,7 @@ const aiSettingsModalSource = readFileSync(
|
||||
describe('settings center layout', () => {
|
||||
it('uses the same split navigation shell as the tool center', () => {
|
||||
expect(appSource).toContain("type SettingsCenterGroupKey = 'preferences' | 'services' | 'about';");
|
||||
expect(appSource).toContain("type SettingsCenterPaneKey = 'language' | 'theme' | 'sidebar-metadata' | 'proxy' | 'web-auth' | 'ai' | 'about-go-navi';");
|
||||
expect(appSource).toContain("type SettingsCenterPaneKey = 'language' | 'theme' | 'sidebar-metadata' | 'sidebar-objects' | 'proxy' | 'web-auth' | 'ai' | 'about-go-navi';");
|
||||
expect(appSource).toContain("const [activeSettingsCenterGroupKey, setActiveSettingsCenterGroupKey] = useState<SettingsCenterGroupKey>('preferences');");
|
||||
expect(appSource).toContain("const [activeSettingsCenterPane, setActiveSettingsCenterPane] = useState<SettingsCenterPaneState | null>(null);");
|
||||
expect(appSource).toContain('style={toolCenterModalWorkspaceStyle}');
|
||||
@@ -47,6 +47,17 @@ describe('settings center layout', () => {
|
||||
expect(appSource).not.toContain("setIsLanguageModalOpen(true)");
|
||||
});
|
||||
|
||||
it('adds persistent sidebar object visibility controls to preferences', () => {
|
||||
expect(appSource).toContain("key: 'sidebar-objects'");
|
||||
expect(appSource).toContain("title: t('app.settings.sidebar_objects.title')");
|
||||
expect(appSource).toContain("description: t('app.settings.sidebar_objects.description')");
|
||||
expect(appSource).toContain("handleOpenSettingsCenterPane('preferences', 'sidebar-objects')");
|
||||
expect(appSource).toContain("if (activeSettingsCenterPane.key === 'sidebar-objects')");
|
||||
expect(appSource).toContain('renderSidebarObjectVisibilitySettingsPane();');
|
||||
expect(appSource).toContain('sidebarHiddenObjectGroups');
|
||||
expect(appSource).toContain('SIDEBAR_OBJECT_GROUP_KEYS.filter((key) => key !== \'tables\')');
|
||||
});
|
||||
|
||||
it('adds browser auth management into the services settings group', () => {
|
||||
expect(appSource).toContain("key: 'web-auth' as const");
|
||||
expect(appSource).toContain("title: t('app.settings.entry.web_auth.title')");
|
||||
|
||||
@@ -105,6 +105,10 @@ import {
|
||||
setSidebarTableMetadataFieldSelected,
|
||||
type SidebarTableMetadataField,
|
||||
} from './utils/sidebarTableMetadata';
|
||||
import {
|
||||
SIDEBAR_OBJECT_GROUP_KEYS,
|
||||
type SidebarObjectGroupKey,
|
||||
} from './utils/sidebarObjectVisibility';
|
||||
import {
|
||||
getSecurityUpdateStatusMeta,
|
||||
resolveSecurityUpdateEntryVisibility,
|
||||
@@ -465,7 +469,7 @@ type ToolCenterPaneState = {
|
||||
};
|
||||
|
||||
type SettingsCenterGroupKey = 'preferences' | 'services' | 'about';
|
||||
type SettingsCenterPaneKey = 'language' | 'theme' | 'sidebar-metadata' | 'proxy' | 'web-auth' | 'ai' | 'about-go-navi';
|
||||
type SettingsCenterPaneKey = 'language' | 'theme' | 'sidebar-metadata' | 'sidebar-objects' | 'proxy' | 'web-auth' | 'ai' | 'about-go-navi';
|
||||
type SettingsCenterPaneState = {
|
||||
key: SettingsCenterPaneKey;
|
||||
group: SettingsCenterGroupKey;
|
||||
@@ -4415,6 +4419,81 @@ function App() {
|
||||
utilityMutedTextStyle,
|
||||
utilityPanelStyle,
|
||||
]);
|
||||
const renderSidebarObjectVisibilitySettingsPane = useCallback(() => {
|
||||
const hiddenObjectGroups = new Set(appearance.sidebarHiddenObjectGroups);
|
||||
const objectGroupItems: Array<{ key: SidebarObjectGroupKey; label: string }> = [
|
||||
{ key: 'savedQueries', label: t('sidebar.tree.saved_queries') },
|
||||
{ key: 'tables', label: t('sidebar.object_group.tables') },
|
||||
{ key: 'views', label: t('sidebar.object_group.views') },
|
||||
{ key: 'materializedViews', label: t('sidebar.object_group.materialized_views') },
|
||||
{ key: 'routines', label: t('sidebar.object_group.routines') },
|
||||
{ key: 'triggers', label: t('sidebar.object_group.triggers') },
|
||||
{ key: 'events', label: t('sidebar.object_group.events') },
|
||||
{ key: 'sequences', label: t('sidebar.object_group.sequences') },
|
||||
{ key: 'packages', label: t('sidebar.object_group.packages') },
|
||||
];
|
||||
const setObjectGroupVisible = (key: SidebarObjectGroupKey, visible: boolean) => {
|
||||
const nextHiddenObjectGroups = visible
|
||||
? appearance.sidebarHiddenObjectGroups.filter((item) => item !== key)
|
||||
: Array.from(new Set([...appearance.sidebarHiddenObjectGroups, key]));
|
||||
setAppearance({ sidebarHiddenObjectGroups: nextHiddenObjectGroups });
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 16, padding: '12px 0' }}>
|
||||
<div style={utilityPanelStyle}>
|
||||
<div style={{ marginBottom: 8, fontWeight: 600 }}>{t('app.settings.sidebar_objects.title')}</div>
|
||||
<div style={{ ...utilityMutedTextStyle, marginBottom: 14 }}>
|
||||
{t('app.settings.sidebar_objects.description')}
|
||||
</div>
|
||||
<div style={{ display: 'grid', gap: 8 }}>
|
||||
{objectGroupItems.map((item) => (
|
||||
<div
|
||||
key={item.key}
|
||||
data-sidebar-object-group-setting={item.key}
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
gap: 12,
|
||||
minHeight: 36,
|
||||
padding: '0 2px',
|
||||
borderBottom: `1px solid ${overlayTheme.divider}`,
|
||||
}}
|
||||
>
|
||||
<span>{item.label}</span>
|
||||
<Switch
|
||||
checked={!hiddenObjectGroups.has(item.key)}
|
||||
aria-label={item.label}
|
||||
onChange={(visible) => setObjectGroupVisible(item.key, visible)}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div style={{ display: 'flex', justifyContent: 'flex-end', gap: 8, flexWrap: 'wrap', marginTop: 14 }}>
|
||||
<Button onClick={() => setAppearance({ sidebarHiddenObjectGroups: [] })}>
|
||||
{t('app.settings.sidebar_objects.action.show_all')}
|
||||
</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => setAppearance({
|
||||
sidebarHiddenObjectGroups: SIDEBAR_OBJECT_GROUP_KEYS.filter((key) => key !== 'tables'),
|
||||
})}
|
||||
>
|
||||
{t('app.settings.sidebar_objects.action.tables_only')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}, [
|
||||
appearance.sidebarHiddenObjectGroups,
|
||||
overlayTheme.divider,
|
||||
setAppearance,
|
||||
t,
|
||||
utilityMutedTextStyle,
|
||||
utilityPanelStyle,
|
||||
]);
|
||||
const updateInstallActionLabel = updateInstallAction === 'install-and-restart'
|
||||
? t('app.about.action.install_and_restart')
|
||||
: (updateInstallAction === 'launch-installer'
|
||||
@@ -6431,6 +6510,13 @@ function App() {
|
||||
description: t('app.settings.sidebar_metadata.description'),
|
||||
onClick: () => handleOpenSettingsCenterPane('preferences', 'sidebar-metadata'),
|
||||
},
|
||||
{
|
||||
key: 'sidebar-objects',
|
||||
icon: <FolderOpenOutlined />,
|
||||
title: t('app.settings.sidebar_objects.title'),
|
||||
description: t('app.settings.sidebar_objects.description'),
|
||||
onClick: () => handleOpenSettingsCenterPane('preferences', 'sidebar-objects'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -6524,6 +6610,9 @@ function App() {
|
||||
if (activeSettingsCenterPane.key === 'sidebar-metadata') {
|
||||
return renderSidebarMetadataSettingsPane();
|
||||
}
|
||||
if (activeSettingsCenterPane.key === 'sidebar-objects') {
|
||||
return renderSidebarObjectVisibilitySettingsPane();
|
||||
}
|
||||
if (activeSettingsCenterPane.key === 'proxy') {
|
||||
return renderProxySettingsContent();
|
||||
}
|
||||
|
||||
@@ -160,6 +160,7 @@ import { useExportProgressDialog } from './ExportProgressModal';
|
||||
import { getShortcutPlatform, resolveShortcutDisplay } from '../utils/shortcuts';
|
||||
import { buildExternalSQLRootNode, type ExternalSQLTreeNode } from '../utils/externalSqlTree';
|
||||
import { resolveSidebarTableMetadataFields } from '../utils/sidebarTableMetadata';
|
||||
import { filterSidebarTreeByHiddenObjectGroups } from '../utils/sidebarObjectVisibility';
|
||||
import { t } from '../i18n';
|
||||
import MessagePublishModal from './MessagePublishModal';
|
||||
import {
|
||||
@@ -687,6 +688,12 @@ const Sidebar: React.FC<{
|
||||
const allSavedQueriesNode = useMemo<TreeNode | null>(() => {
|
||||
return buildAllSavedQueriesTreeNode(savedQueries, connections, savedQueryGroups);
|
||||
}, [connections, savedQueries, savedQueryGroups]);
|
||||
const sidebarHiddenObjectGroups = appearance.sidebarHiddenObjectGroups;
|
||||
const visibleSidebarTreeData = useMemo(
|
||||
() => filterSidebarTreeByHiddenObjectGroups(treeData, sidebarHiddenObjectGroups),
|
||||
[sidebarHiddenObjectGroups, treeData],
|
||||
);
|
||||
const sidebarObjectVisibilitySignature = sidebarHiddenObjectGroups.join('|') || 'all';
|
||||
const snapshotTreeSelectionBeforeDrag = useCallback(() => {
|
||||
treeDragSelectionSnapshotRef.current = {
|
||||
selectedKeys: [...selectedKeys],
|
||||
@@ -2484,7 +2491,7 @@ const Sidebar: React.FC<{
|
||||
setV2CommandActiveIndex,
|
||||
v2ExplorerFilter,
|
||||
sidebarTableMetadataFields,
|
||||
treeData,
|
||||
treeData: visibleSidebarTreeData,
|
||||
treeViewportWidth,
|
||||
treeHeight,
|
||||
isV2Ui,
|
||||
@@ -3267,7 +3274,7 @@ const Sidebar: React.FC<{
|
||||
>
|
||||
<div className="sidebar-tree-scroll-content">
|
||||
<Tree
|
||||
key={isV2Ui ? `v2-tree-${v2ExplorerFilter}` : 'legacy-tree'}
|
||||
key={`${isV2Ui ? `v2-tree-${v2ExplorerFilter}` : 'legacy-tree'}-${sidebarObjectVisibilitySignature}`}
|
||||
ref={treeRef}
|
||||
showIcon
|
||||
draggable={{
|
||||
|
||||
@@ -6,6 +6,8 @@ const source = [
|
||||
readFileSync(new URL('./sidebar/useSidebarTreeLoaders.tsx', import.meta.url), 'utf8'),
|
||||
].join('\n');
|
||||
|
||||
const appSource = readFileSync(new URL('../App.tsx', import.meta.url), 'utf8');
|
||||
|
||||
const locales = ['zh-CN', 'zh-TW', 'en-US', 'ja-JP', 'de-DE', 'ru-RU'] as const;
|
||||
const requiredKeys = [
|
||||
'sidebar.tree.default_schema',
|
||||
@@ -19,6 +21,13 @@ const requiredKeys = [
|
||||
'sidebar.object_group.events',
|
||||
];
|
||||
|
||||
const visibilityKeys = [
|
||||
'app.settings.sidebar_objects.title',
|
||||
'app.settings.sidebar_objects.description',
|
||||
'app.settings.sidebar_objects.action.show_all',
|
||||
'app.settings.sidebar_objects.action.tables_only',
|
||||
];
|
||||
|
||||
describe('Sidebar object group i18n', () => {
|
||||
it('localizes database object group titles and default schema fallback', () => {
|
||||
[
|
||||
@@ -56,4 +65,16 @@ describe('Sidebar object group i18n', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('localizes the persistent object visibility settings', () => {
|
||||
visibilityKeys.forEach((key) => {
|
||||
expect(appSource).toContain(`t('${key}'`);
|
||||
});
|
||||
locales.forEach((locale) => {
|
||||
const catalog = JSON.parse(readFileSync(new URL(`../../../shared/i18n/${locale}.json`, import.meta.url), 'utf8')) as Record<string, string>;
|
||||
visibilityKeys.forEach((key) => {
|
||||
expect(catalog[key], `${locale}:${key}`).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -75,6 +75,7 @@ describe('store appearance persistence', () => {
|
||||
expect(appearance.v2CommandSearchPersistentFilterEnabled).toBe(false);
|
||||
expect(appearance.v2SidebarPersistedFilter).toBe('');
|
||||
expect(appearance.v2SidebarRailScale).toBe(1);
|
||||
expect(appearance.sidebarHiddenObjectGroups).toEqual([]);
|
||||
expect(appearance.showDataTableVerticalBorders).toBe(false);
|
||||
expect(appearance.showDataTableRowNumber).toBe(true);
|
||||
expect(appearance.dataTableDensity).toBe('comfortable');
|
||||
@@ -153,6 +154,33 @@ describe('store appearance persistence', () => {
|
||||
expect(appearance.v2SidebarRailScale).toBe(1.55);
|
||||
});
|
||||
|
||||
it('persists and sanitizes hidden sidebar object groups', async () => {
|
||||
const { useStore } = await importStore();
|
||||
|
||||
useStore.getState().setAppearance({
|
||||
sidebarHiddenObjectGroups: ['views', 'routines', 'views'],
|
||||
});
|
||||
|
||||
const persisted = JSON.parse(storage.getItem('lite-db-storage') || '{}');
|
||||
expect(persisted.state.appearance.sidebarHiddenObjectGroups).toEqual(['views', 'routines']);
|
||||
|
||||
vi.resetModules();
|
||||
const reloaded = await importStore();
|
||||
expect(reloaded.useStore.getState().appearance.sidebarHiddenObjectGroups).toEqual(['views', 'routines']);
|
||||
|
||||
storage.setItem('lite-db-storage', JSON.stringify({
|
||||
state: {
|
||||
appearance: {
|
||||
sidebarHiddenObjectGroups: ['tables', 'unknown', 'tables', 1],
|
||||
},
|
||||
},
|
||||
version: 16,
|
||||
}));
|
||||
vi.resetModules();
|
||||
const sanitized = await importStore();
|
||||
expect(sanitized.useStore.getState().appearance.sidebarHiddenObjectGroups).toEqual(['tables']);
|
||||
});
|
||||
|
||||
it('migrates legacy sidebar table comment settings into metadata fields and persists explicit selections', async () => {
|
||||
storage.setItem('lite-db-storage', JSON.stringify({
|
||||
state: {
|
||||
|
||||
@@ -115,6 +115,10 @@ import {
|
||||
sanitizeSidebarTableMetadataFields,
|
||||
type SidebarTableMetadataField,
|
||||
} from "./utils/sidebarTableMetadata";
|
||||
import {
|
||||
sanitizeSidebarHiddenObjectGroups,
|
||||
type SidebarObjectGroupKey,
|
||||
} from "./utils/sidebarObjectVisibility";
|
||||
|
||||
export type TableDoubleClickAction = "open-data" | "open-design";
|
||||
export type ThemeMode = "light" | "dark";
|
||||
@@ -133,6 +137,7 @@ export interface AppearanceSettings extends DataGridDisplaySettings {
|
||||
v2CommandSearchPersistentFilterEnabled: boolean;
|
||||
v2SidebarPersistedFilter: string;
|
||||
v2SidebarRailScale: number;
|
||||
sidebarHiddenObjectGroups: SidebarObjectGroupKey[];
|
||||
customUIFontFamily: string | null;
|
||||
customMonoFontFamily: string | null;
|
||||
newQuerySqlTemplate: string | null;
|
||||
@@ -155,6 +160,7 @@ export const DEFAULT_APPEARANCE: AppearanceSettings = {
|
||||
v2CommandSearchPersistentFilterEnabled: false,
|
||||
v2SidebarPersistedFilter: "",
|
||||
v2SidebarRailScale: DEFAULT_V2_SIDEBAR_RAIL_SCALE,
|
||||
sidebarHiddenObjectGroups: [],
|
||||
customUIFontFamily: null,
|
||||
customMonoFontFamily: null,
|
||||
newQuerySqlTemplate: null,
|
||||
@@ -3070,6 +3076,9 @@ const sanitizeAppearance = (
|
||||
v2SidebarRailScale: sanitizeV2SidebarRailScale(
|
||||
appearance.v2SidebarRailScale,
|
||||
),
|
||||
sidebarHiddenObjectGroups: sanitizeSidebarHiddenObjectGroups(
|
||||
appearance.sidebarHiddenObjectGroups,
|
||||
),
|
||||
customUIFontFamily: sanitizeFontFamilyInput(appearance.customUIFontFamily),
|
||||
customMonoFontFamily: sanitizeFontFamilyInput(appearance.customMonoFontFamily),
|
||||
newQuerySqlTemplate: sanitizeNewQuerySqlTemplate(appearance.newQuerySqlTemplate),
|
||||
|
||||
54
frontend/src/utils/sidebarObjectVisibility.test.ts
Normal file
54
frontend/src/utils/sidebarObjectVisibility.test.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import {
|
||||
filterSidebarTreeByHiddenObjectGroups,
|
||||
sanitizeSidebarHiddenObjectGroups,
|
||||
} from './sidebarObjectVisibility';
|
||||
|
||||
describe('sidebar object visibility', () => {
|
||||
it('keeps only enabled object categories while preserving the source tree', () => {
|
||||
const tree = [{
|
||||
key: 'db',
|
||||
type: 'database',
|
||||
children: [
|
||||
{ key: 'db-queries', type: 'queries-folder', children: [{ key: 'query-1', type: 'saved-query' }] },
|
||||
{ key: 'db-tables', type: 'object-group', dataRef: { groupKey: 'tables' }, children: [{ key: 'orders', type: 'table' }] },
|
||||
{ key: 'db-views', type: 'object-group', dataRef: { groupKey: 'views' } },
|
||||
{
|
||||
key: 'db-schema-dbo',
|
||||
type: 'object-group',
|
||||
dataRef: { groupKey: 'schema' },
|
||||
children: [
|
||||
{ key: 'dbo-tables', type: 'object-group', dataRef: { groupKey: 'tables' }, children: [{ key: 'customers', type: 'table' }] },
|
||||
{ key: 'dbo-events', type: 'object-group', dataRef: { groupKey: 'events' } },
|
||||
],
|
||||
},
|
||||
],
|
||||
}];
|
||||
|
||||
const filtered = filterSidebarTreeByHiddenObjectGroups(tree, [
|
||||
'savedQueries',
|
||||
'views',
|
||||
'events',
|
||||
]);
|
||||
|
||||
expect(filtered[0].children?.map((node) => node.key)).toEqual(['db-tables', 'db-schema-dbo']);
|
||||
expect(filtered[0].children?.[1].children?.map((node) => node.key)).toEqual(['dbo-tables']);
|
||||
expect(tree[0].children?.map((node) => node.key)).toEqual([
|
||||
'db-queries',
|
||||
'db-tables',
|
||||
'db-views',
|
||||
'db-schema-dbo',
|
||||
]);
|
||||
});
|
||||
|
||||
it('drops invalid and duplicate persisted object group keys', () => {
|
||||
expect(sanitizeSidebarHiddenObjectGroups([
|
||||
'views',
|
||||
'views',
|
||||
'unknown',
|
||||
3,
|
||||
' tables ',
|
||||
])).toEqual(['views', 'tables']);
|
||||
});
|
||||
});
|
||||
76
frontend/src/utils/sidebarObjectVisibility.ts
Normal file
76
frontend/src/utils/sidebarObjectVisibility.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
export const SIDEBAR_OBJECT_GROUP_KEYS = [
|
||||
'savedQueries',
|
||||
'tables',
|
||||
'views',
|
||||
'materializedViews',
|
||||
'sequences',
|
||||
'routines',
|
||||
'packages',
|
||||
'triggers',
|
||||
'events',
|
||||
] as const;
|
||||
|
||||
export type SidebarObjectGroupKey = (typeof SIDEBAR_OBJECT_GROUP_KEYS)[number];
|
||||
|
||||
type SidebarObjectVisibilityTreeNode = {
|
||||
type?: string;
|
||||
dataRef?: { groupKey?: unknown };
|
||||
children?: SidebarObjectVisibilityTreeNode[];
|
||||
isLeaf?: boolean;
|
||||
};
|
||||
|
||||
const SIDEBAR_OBJECT_GROUP_KEY_SET = new Set<string>(SIDEBAR_OBJECT_GROUP_KEYS);
|
||||
|
||||
export const sanitizeSidebarHiddenObjectGroups = (value: unknown): SidebarObjectGroupKey[] => {
|
||||
if (!Array.isArray(value)) return [];
|
||||
const seen = new Set<SidebarObjectGroupKey>();
|
||||
value.forEach((item) => {
|
||||
if (typeof item !== 'string') return;
|
||||
const key = item.trim();
|
||||
if (SIDEBAR_OBJECT_GROUP_KEY_SET.has(key)) {
|
||||
seen.add(key as SidebarObjectGroupKey);
|
||||
}
|
||||
});
|
||||
return Array.from(seen);
|
||||
};
|
||||
|
||||
const resolveObjectGroupKey = (
|
||||
node: SidebarObjectVisibilityTreeNode,
|
||||
): SidebarObjectGroupKey | null => {
|
||||
if (node.type === 'queries-folder' || node.type === 'all-saved-queries') {
|
||||
return 'savedQueries';
|
||||
}
|
||||
if (node.type !== 'object-group') return null;
|
||||
const groupKey = String(node.dataRef?.groupKey || '').trim();
|
||||
return SIDEBAR_OBJECT_GROUP_KEY_SET.has(groupKey)
|
||||
? groupKey as SidebarObjectGroupKey
|
||||
: null;
|
||||
};
|
||||
|
||||
const isSchemaGroupNode = (node: SidebarObjectVisibilityTreeNode): boolean => (
|
||||
node.type === 'object-group' && node.dataRef?.groupKey === 'schema'
|
||||
);
|
||||
|
||||
export const filterSidebarTreeByHiddenObjectGroups = <T extends SidebarObjectVisibilityTreeNode>(
|
||||
nodes: T[],
|
||||
hiddenObjectGroups: readonly SidebarObjectGroupKey[],
|
||||
): T[] => {
|
||||
if (hiddenObjectGroups.length === 0) return nodes;
|
||||
const hidden = new Set(hiddenObjectGroups);
|
||||
|
||||
return nodes.flatMap((node): T[] => {
|
||||
const objectGroupKey = resolveObjectGroupKey(node);
|
||||
if (objectGroupKey && hidden.has(objectGroupKey)) return [];
|
||||
|
||||
if (!node.children || node.children.length === 0) return [node];
|
||||
const children = filterSidebarTreeByHiddenObjectGroups(node.children as T[], hiddenObjectGroups);
|
||||
if (isSchemaGroupNode(node) && children.length === 0) return [];
|
||||
if (children.length === node.children.length) return [node];
|
||||
|
||||
return [{
|
||||
...node,
|
||||
children,
|
||||
...(children.length === 0 ? { isLeaf: true } : {}),
|
||||
}];
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user