Skip to content

Update to binary prefix file size, Add directory children count #152

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 27 additions & 4 deletions src/FssTreeItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { INotebookTracker } from '@jupyterlab/notebook';
import { fileIcon, folderIcon } from '@jupyterlab/ui-components';

import { FssTreeItemContext } from './FssTreeItemContext';
import { formatBytes } from './utils';
import { Logger } from './logger';

export class FssTreeItem {
Expand Down Expand Up @@ -159,17 +160,38 @@ export class FssTreeItem {
});
}

setMetadata(user_path: string, size: string) {
setMetadata(user_path: string, size: string, childrenCount?: number) {
this.logger.debug('Setting item metadata', {
path: user_path,
size
size,
childrenCount
});

this.root.dataset.fss = user_path;
this.root.dataset.fsize = size;

const sizeDisplay = `(${size.toLocaleString()})`;
this.sizeLbl.innerText = sizeDisplay;
if (childrenCount !== undefined) {
// For directories, show children count
const childrenDisplay = `(${childrenCount} item${childrenCount === 1 ? '' : 's'})`;
this.sizeLbl.innerText = childrenDisplay;
this.sizeLbl.style.display = 'block';
} else if (this.isDir) {
// For directories without known count, hide the size label
this.sizeLbl.style.display = 'none';
return;
} else {
// For files, show size
const sizeNumber = Number(size);
if (isNaN(sizeNumber)) {
this.logger.error('Invalid size', { size });
return;
}
const formattedSize = formatBytes(sizeNumber);
const formattedSizeString = formattedSize.toString();

const sizeDisplay = `(${formattedSizeString})`;
this.sizeLbl.innerText = sizeDisplay;
}
}

setText(value: string) {
Expand All @@ -191,6 +213,7 @@ export class FssTreeItem {
if (symbol === 'file') {
fileIcon.element({ container: this.dirSymbol });
this.isDir = false;
this.sizeLbl.style.display = 'block';
}
}

Expand Down
48 changes: 31 additions & 17 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -903,13 +903,21 @@ class FsspecWidget extends Widget {
// Update the TreeView in the UI
await this.updateFileBrowserView(nodeForPath);

// Update the children count for the expanded directory
if (nodeForPath.id.toString() in this.elementHeap) {
const uiElement = this.elementHeap[nodeForPath.id.toString()];
const actualChildrenCount = Object.keys(nodeForPath.children).length;
uiElement.setMetadata(
nodeForPath.path,
nodeForPath.metadata.size,
actualChildrenCount
);
uiElement.expandItem();

this.logger.debug('Auto-expanded directory node', {
path: source_path,
nodeId: nodeForPath.id
nodeId: nodeForPath.id,
childrenCount: actualChildrenCount
});
}
}
Expand Down Expand Up @@ -991,10 +999,28 @@ class FsspecWidget extends Widget {
true,
this.notebookTracker
);
item.setMetadata(
(pathInfo as any).path,
(pathInfo as any).metadata.size
);
const isDirectory =
Object.keys((pathInfo as any).children).length > 0 ||
('type' in (pathInfo as any).metadata &&
(pathInfo as any).metadata.type === 'directory');

if (isDirectory) {
// Since directroy children are lazy-loaded: set children count to undefined
// The count will be updated once the directory is expanded
item.setMetadata(
(pathInfo as any).path,
(pathInfo as any).metadata.size,
undefined
);
item.setType('dir');
} else {
item.setMetadata(
(pathInfo as any).path,
(pathInfo as any).metadata.size
);
item.setType('file');
}

item.setText(pathSegment);
item.treeItemClicked.connect(this.handleTreeItemClicked.bind(this));
item.getBytesRequested.connect(
Expand All @@ -1008,18 +1034,6 @@ class FsspecWidget extends Widget {
(pathInfo as any).id = item_id;
this.elementHeap[item_id.toString()] = item;

// Set the item type (file or directory)
const isDirectory =
Object.keys((pathInfo as any).children).length > 0 ||
('type' in (pathInfo as any).metadata &&
(pathInfo as any).metadata.type === 'directory');

if (isDirectory) {
item.setType('dir');
} else {
item.setType('file');
}

// Add children to build targets if needed
if (Object.keys((pathInfo as any).children).length > 0) {
buildTargets[(pathInfo as any).path] = [
Expand Down
28 changes: 28 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
export function formatBytes(n: number): string {
/**
* Examples:
* formatBytes(1) // '1 B'
* formatBytes(1234) // '1.21 kiB'
* formatBytes(12345678) // '11.77 MiB'
* formatBytes(1234567890) // '1.15 GiB'
* formatBytes(1234567890000) // '1.12 TiB'
* formatBytes(1234567890000000) // '1.10 PiB'
*
* For all values < 2^60, the output is always <= 10 characters.
* Note:Code adapted from dask.utils.format_bytes
*/
const units: [string, number][] = [
['Pi', Math.pow(2, 50)],
['Ti', Math.pow(2, 40)],
['Gi', Math.pow(2, 30)],
['Mi', Math.pow(2, 20)],
['ki', Math.pow(2, 10)]
];

for (const [prefix, k] of units) {
if (n >= k * 0.9) {
return `${(n / k).toFixed(2)} ${prefix}B`;
}
}
return `${n} B`;
}
Loading