[Init] Initial commit - NetMesh terminal manager
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
This commit is contained in:
120
components/sftp/useSftpPaneTreeRows.tsx
Normal file
120
components/sftp/useSftpPaneTreeRows.tsx
Normal file
@@ -0,0 +1,120 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { AlertCircle, Loader2 } from 'lucide-react';
|
||||
import { TreeNode, TREE_ROW_HEIGHT } from './SftpPaneTreeNode';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
type SftpPaneTreeRowsProps = Record<string, any>;
|
||||
|
||||
export function useSftpPaneTreeRows(props: SftpPaneTreeRowsProps) {
|
||||
const {
|
||||
nodeDescriptors, scrollTop, viewportHeight, tRef, columnTemplate, visibleColumns, selectedPaths, dragOverNodePath,
|
||||
toggleExpand, handleNodeClick, stableOnOpenEntry, stableOnDragStart, stableOnDragEnd,
|
||||
handleNodeDragOver, handleNodeDrop, handleNodeDragLeave, handleNodeContextMenu,
|
||||
} = props;
|
||||
|
||||
const { totalHeight, visibleRange } = useMemo(() => {
|
||||
const totalCount = nodeDescriptors.length;
|
||||
const total = totalCount * TREE_ROW_HEIGHT;
|
||||
const shouldVirtualize = viewportHeight > 0 && totalCount > 50;
|
||||
|
||||
if (!shouldVirtualize) {
|
||||
return { totalHeight: 0, visibleRange: { start: 0, end: totalCount - 1, virtualized: false } };
|
||||
}
|
||||
|
||||
const overscan = 6;
|
||||
const start = Math.max(0, Math.floor(scrollTop / TREE_ROW_HEIGHT) - overscan);
|
||||
const end = Math.min(totalCount - 1, Math.ceil((scrollTop + viewportHeight) / TREE_ROW_HEIGHT) + overscan);
|
||||
return { totalHeight: total, visibleRange: { start, end, virtualized: true } };
|
||||
}, [nodeDescriptors.length, scrollTop, viewportHeight]);
|
||||
|
||||
// ── Render visible rows ──────────────────────────────────────────
|
||||
const treeRows = useMemo(() => {
|
||||
const { start, end, virtualized } = visibleRange;
|
||||
const rows: React.ReactNode[] = [];
|
||||
|
||||
for (let i = start; i <= end; i++) {
|
||||
const descriptor = nodeDescriptors[i];
|
||||
if (!descriptor) continue;
|
||||
|
||||
let content: React.ReactNode;
|
||||
if (descriptor.type === 'loading') {
|
||||
content = (
|
||||
<div
|
||||
style={{ paddingLeft: (descriptor.depth + 1) * 16 + 8, height: TREE_ROW_HEIGHT }}
|
||||
className="text-xs text-muted-foreground flex items-center gap-1"
|
||||
>
|
||||
<Loader2 size={12} className="animate-spin" /> {tRef.current('sftp.tree.loading')}
|
||||
</div>
|
||||
);
|
||||
} else if (descriptor.type === 'error') {
|
||||
content = (
|
||||
<div
|
||||
style={{ paddingLeft: (descriptor.depth + 1) * 16 + 8, height: TREE_ROW_HEIGHT }}
|
||||
className="text-xs text-destructive flex items-center gap-1"
|
||||
>
|
||||
<AlertCircle size={12} /> {tRef.current('sftp.tree.loadError')}
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
content = (
|
||||
<TreeNode
|
||||
entry={descriptor.entry}
|
||||
entryPath={descriptor.entryPath}
|
||||
depth={descriptor.depth}
|
||||
columnTemplate={columnTemplate}
|
||||
visibleColumns={visibleColumns}
|
||||
isSelected={selectedPaths.has(descriptor.entryPath)}
|
||||
isExpanded={descriptor.isExpanded}
|
||||
isLoading={descriptor.isLoading}
|
||||
isDragOver={dragOverNodePath === descriptor.entryPath}
|
||||
onToggleExpand={toggleExpand}
|
||||
onNodeClick={handleNodeClick}
|
||||
onOpenEntry={stableOnOpenEntry}
|
||||
onDragStart={stableOnDragStart}
|
||||
onDragEnd={stableOnDragEnd}
|
||||
onDragOverEntry={handleNodeDragOver}
|
||||
onDropEntry={handleNodeDrop}
|
||||
onDragLeaveEntry={handleNodeDragLeave}
|
||||
onContextMenu={handleNodeContextMenu}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const key = descriptor.type === 'node' ? descriptor.entryPath : descriptor.key;
|
||||
if (virtualized) {
|
||||
rows.push(
|
||||
<div
|
||||
key={key}
|
||||
className="absolute left-0 right-0"
|
||||
style={{ top: i * TREE_ROW_HEIGHT, height: TREE_ROW_HEIGHT }}
|
||||
>
|
||||
{content}
|
||||
</div>,
|
||||
);
|
||||
} else {
|
||||
rows.push(<React.Fragment key={key}>{content}</React.Fragment>);
|
||||
}
|
||||
}
|
||||
|
||||
return rows;
|
||||
}, [
|
||||
visibleRange,
|
||||
nodeDescriptors,
|
||||
columnTemplate,
|
||||
visibleColumns,
|
||||
selectedPaths,
|
||||
dragOverNodePath,
|
||||
toggleExpand,
|
||||
handleNodeClick,
|
||||
stableOnOpenEntry,
|
||||
stableOnDragStart,
|
||||
stableOnDragEnd,
|
||||
handleNodeDragOver,
|
||||
handleNodeDrop,
|
||||
handleNodeDragLeave,
|
||||
handleNodeContextMenu,
|
||||
tRef,
|
||||
]);
|
||||
|
||||
return { totalHeight, treeRows, visibleRange };
|
||||
}
|
||||
Reference in New Issue
Block a user