This is an automated email from the ASF dual-hosted git repository.

kgabryje pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git


The following commit(s) were added to refs/heads/master by this push:
     new 86c8fa5cd7b fix: Badge count in folders editor (#38100)
86c8fa5cd7b is described below

commit 86c8fa5cd7b6946400d5ea7efc18fe3f0d52f064
Author: Kamil Gabryjelski <[email protected]>
AuthorDate: Thu Feb 19 18:45:04 2026 +0100

    fix: Badge count in folders editor (#38100)
---
 .../Datasource/FoldersEditor/constants.ts          |  3 ++
 .../Datasource/FoldersEditor/treeUtils.test.ts     | 59 ++++++++++++++++++++++
 .../Datasource/FoldersEditor/treeUtils.ts          | 19 +++++++
 .../DatasourceEditor/DatasourceEditor.tsx          | 17 +++++--
 4 files changed, 95 insertions(+), 3 deletions(-)

diff --git 
a/superset-frontend/src/components/Datasource/FoldersEditor/constants.ts 
b/superset-frontend/src/components/Datasource/FoldersEditor/constants.ts
index fc9f4d189f8..913ee905fb6 100644
--- a/superset-frontend/src/components/Datasource/FoldersEditor/constants.ts
+++ b/superset-frontend/src/components/Datasource/FoldersEditor/constants.ts
@@ -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;
diff --git 
a/superset-frontend/src/components/Datasource/FoldersEditor/treeUtils.test.ts 
b/superset-frontend/src/components/Datasource/FoldersEditor/treeUtils.test.ts
index c6fdfa444b7..b17b7b727fe 100644
--- 
a/superset-frontend/src/components/Datasource/FoldersEditor/treeUtils.test.ts
+++ 
b/superset-frontend/src/components/Datasource/FoldersEditor/treeUtils.test.ts
@@ -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);
+});
diff --git 
a/superset-frontend/src/components/Datasource/FoldersEditor/treeUtils.ts 
b/superset-frontend/src/components/Datasource/FoldersEditor/treeUtils.ts
index 10dec0d28ab..c35817606d9 100644
--- a/superset-frontend/src/components/Datasource/FoldersEditor/treeUtils.ts
+++ b/superset-frontend/src/components/Datasource/FoldersEditor/treeUtils.ts
@@ -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;
+}
diff --git 
a/superset-frontend/src/components/Datasource/components/DatasourceEditor/DatasourceEditor.tsx
 
b/superset-frontend/src/components/Datasource/components/DatasourceEditor/DatasourceEditor.tsx
index c7819929074..fae377266a6 100644
--- 
a/superset-frontend/src/components/Datasource/components/DatasourceEditor/DatasourceEditor.tsx
+++ 
b/superset-frontend/src/components/Datasource/components/DatasourceEditor/DatasourceEditor.tsx
@@ -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')}
                       />
                     ),

Reply via email to