fix: Badge count in folders editor (#38100)

This commit is contained in:
Kamil Gabryjelski
2026-02-19 18:45:04 +01:00
committed by GitHub
parent e12140beb6
commit 86c8fa5cd7
4 changed files with 95 additions and 3 deletions

View File

@@ -29,6 +29,9 @@ export const DEFAULT_METRICS_FOLDER_UUID =
export const DEFAULT_COLUMNS_FOLDER_UUID =
'83a7ae8f-2e8a-4f2b-a8cb-ebaebef95b9b';
// Number of default folders (Metrics, Columns)
export const DEFAULT_FOLDERS_COUNT = 2;
// Drag & drop constants
export const DRAG_INDENTATION_WIDTH = 64;
export const MAX_DEPTH = 3;

View File

@@ -28,8 +28,10 @@ import {
removeChildrenOf,
serializeForAPI,
getProjection,
countAllFolders,
} from './treeUtils';
import { FoldersEditorItemType } from '../types';
import { DatasourceFolder } from 'src/explore/components/DatasourcePanel/types';
const createMetricItem = (uuid: string, name: string): TreeItem => ({
uuid,
@@ -667,3 +669,60 @@ test('getProjection nests item under folder when dragging down with offset', ()
expect(projection!.depth).toBe(1);
expect(projection!.parentId).toBe('folder1');
});
test('countAllFolders returns 0 for empty array', () => {
expect(countAllFolders([])).toBe(0);
});
test('countAllFolders counts flat folders', () => {
const folders: DatasourceFolder[] = [
createFolderItem('f1', 'Metrics', [createMetricItem('m1', 'Metric 1')]),
createFolderItem('f2', 'Columns', [createColumnItem('c1', 'Column 1')]),
] as DatasourceFolder[];
expect(countAllFolders(folders)).toBe(2);
});
test('countAllFolders counts nested folders recursively', () => {
const folders: DatasourceFolder[] = [
createFolderItem('metrics', 'Metrics', [
createMetricItem('m1', 'Metric 1'),
]),
createFolderItem('columns', 'Columns', [
createColumnItem('c1', 'Column 1'),
]),
createFolderItem('custom', 'Custom Folder', [
createFolderItem('nested', 'Nested Folder', [
createMetricItem('m2', 'Metric 2'),
]),
]),
] as DatasourceFolder[];
expect(countAllFolders(folders)).toBe(4);
});
test('countAllFolders counts deeply nested folders', () => {
const folders: DatasourceFolder[] = [
createFolderItem('level0', 'Level 0', [
createFolderItem('level1', 'Level 1', [
createFolderItem('level2', 'Level 2', [
createMetricItem('m1', 'Metric 1'),
]),
]),
]),
] as DatasourceFolder[];
expect(countAllFolders(folders)).toBe(3);
});
test('countAllFolders ignores non-folder children', () => {
const folders: DatasourceFolder[] = [
createFolderItem('f1', 'Folder', [
createMetricItem('m1', 'Metric 1'),
createColumnItem('c1', 'Column 1'),
createMetricItem('m2', 'Metric 2'),
]),
] as DatasourceFolder[];
expect(countAllFolders(folders)).toBe(1);
});

View File

@@ -330,3 +330,22 @@ export function serializeForAPI(items: TreeItem[]): DatasourceFolder[] {
})
.filter((folder): folder is DatasourceFolder => folder !== null);
}
/**
* Recursively counts all folders in a DatasourceFolder array,
* including nested sub-folders within children.
*/
export function countAllFolders(folders: DatasourceFolder[]): number {
let count = 0;
for (const folder of folders) {
count += 1;
if (folder.children) {
for (const child of folder.children) {
if ('children' in child) {
count += countAllFolders([child as DatasourceFolder]);
}
}
}
}
return count;
}

View File

@@ -91,9 +91,11 @@ import { fetchSyncedColumns, updateColumns } from '../../utils';
import DatasetUsageTab from './components/DatasetUsageTab';
import {
DEFAULT_COLUMNS_FOLDER_UUID,
DEFAULT_FOLDERS_COUNT,
DEFAULT_METRICS_FOLDER_UUID,
} from '../../FoldersEditor/constants';
import { validateFolders } from '../../FoldersEditor/folderValidation';
import { countAllFolders } from '../../FoldersEditor/treeUtils';
import FoldersEditor from '../../FoldersEditor';
import { DatasourceFolder } from 'src/explore/components/DatasourcePanel/types';
@@ -266,6 +268,7 @@ interface DatasourceEditorState {
databaseColumns: Column[];
calculatedColumns: Column[];
folders: DatasourceFolder[];
folderCount: number;
metadataLoading: boolean;
activeTabKey: string;
datasourceType: string;
@@ -284,6 +287,7 @@ interface AbortControllers {
interface CollectionTabTitleProps {
title: string;
collection?: unknown[] | { length: number };
count?: number;
}
interface ColumnCollectionTableProps {
@@ -458,6 +462,7 @@ DATASOURCE_TYPES_ARR.forEach(o => {
function CollectionTabTitle({
title,
collection,
count,
}: CollectionTabTitleProps): JSX.Element {
return (
<div
@@ -465,7 +470,10 @@ function CollectionTabTitle({
data-test={`collection-tab-${title}`}
>
{title}{' '}
<StyledBadge count={collection ? collection.length : 0} showZero />
<StyledBadge
count={count ?? (collection ? collection.length : 0)}
showZero
/>
</div>
);
}
@@ -905,6 +913,8 @@ class DatasourceEditor extends PureComponent<
col => !!col.expression,
),
folders: props.datasource.folders || [],
folderCount:
countAllFolders(props.datasource.folders || []) + DEFAULT_FOLDERS_COUNT,
metadataLoading: false,
activeTabKey: TABS_KEYS.SOURCE,
datasourceType: props.datasource.sql
@@ -988,13 +998,14 @@ class DatasourceEditor extends PureComponent<
}
handleFoldersChange(folders: DatasourceFolder[]) {
const folderCount = countAllFolders(folders);
const userMadeFolders = folders.filter(
f =>
f.uuid !== DEFAULT_METRICS_FOLDER_UUID &&
f.uuid !== DEFAULT_COLUMNS_FOLDER_UUID &&
(f.children?.length ?? 0) > 0,
);
this.setState({ folders: userMadeFolders }, () => {
this.setState({ folders: userMadeFolders, folderCount }, () => {
this.onDatasourceChange({
...this.state.datasource,
folders: userMadeFolders,
@@ -2405,7 +2416,7 @@ class DatasourceEditor extends PureComponent<
key: TABS_KEYS.FOLDERS,
label: (
<CollectionTabTitle
collection={this.state.folders}
count={this.state.folderCount}
title={t('Folders')}
/>
),