fix: enable folder navigation in workspace file browser
FilesTab in WorkspaceDetailPage was returning early for directories with no action, making folders unclickable. Changes: - use-workspace-files.ts: add currentPath state and navigateTo() function; refresh() now passes currentPath to listWorkspaceFiles API - WorkspaceDetailPage.tsx FilesTab: handleSelect now calls navigateTo() for directories; added navigateUp() button using '..' when not at root - Clear selected file/editor state when changing directories Quality gates: tsc --noEmit pass, npm run build pass, 82/82 tests pass
This commit is contained in:
@@ -11,11 +11,13 @@ import {
|
||||
export interface UseWorkspaceFilesResult {
|
||||
entries: FileEntry[];
|
||||
content: string | null;
|
||||
currentPath: string;
|
||||
loading: boolean;
|
||||
error: string | null;
|
||||
refresh: () => Promise<void>;
|
||||
loadFile: (path: string) => Promise<void>;
|
||||
saveFile: (path: string, content: string, message?: string) => Promise<void>;
|
||||
navigateTo: (path: string) => void;
|
||||
}
|
||||
|
||||
export function useWorkspaceFiles(
|
||||
@@ -23,6 +25,7 @@ export function useWorkspaceFiles(
|
||||
): UseWorkspaceFilesResult {
|
||||
const [entries, setEntries] = useState<FileEntry[]>([]);
|
||||
const [content, setContent] = useState<string | null>(null);
|
||||
const [currentPath, setCurrentPath] = useState("");
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
@@ -30,14 +33,19 @@ export function useWorkspaceFiles(
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
const data = await listWorkspaceFiles(workspaceId);
|
||||
const data = await listWorkspaceFiles(workspaceId, currentPath);
|
||||
setEntries(data);
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : "Failed to load files");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [workspaceId]);
|
||||
}, [workspaceId, currentPath]);
|
||||
|
||||
const navigateTo = useCallback((path: string) => {
|
||||
setCurrentPath(path);
|
||||
setContent(null);
|
||||
}, []);
|
||||
|
||||
const loadFile = useCallback(
|
||||
async (path: string) => {
|
||||
@@ -64,5 +72,5 @@ export function useWorkspaceFiles(
|
||||
refresh();
|
||||
}, [refresh]);
|
||||
|
||||
return { entries, content, loading, error, refresh, loadFile, saveFile };
|
||||
return { entries, content, currentPath, loading, error, refresh, loadFile, saveFile, navigateTo };
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ function MobileTabBar({
|
||||
/* ─── Files Tab ─── */
|
||||
|
||||
function FilesTab({ workspaceId }: { workspaceId: string }) {
|
||||
const { entries, content, loadFile, saveFile, loading, error } =
|
||||
const { entries, content, currentPath, loadFile, saveFile, loading, error, navigateTo } =
|
||||
useWorkspaceFiles(workspaceId);
|
||||
const { status, commit, push, pull, fetch } = useWorkspaceGit(workspaceId);
|
||||
const [selectedPath, setSelectedPath] = useState<string | null>(null);
|
||||
@@ -159,13 +159,28 @@ function FilesTab({ workspaceId }: { workspaceId: string }) {
|
||||
const [commitMessage, setCommitMessage] = useState("");
|
||||
|
||||
const handleSelect = (entry: FileEntry) => {
|
||||
if (entry.type === "directory") return;
|
||||
if (entry.type === "directory") {
|
||||
setSelectedPath(null);
|
||||
setIsEditing(false);
|
||||
setEditContent(null);
|
||||
navigateTo(entry.path);
|
||||
return;
|
||||
}
|
||||
setSelectedPath(entry.path);
|
||||
setIsEditing(false);
|
||||
setEditContent(null);
|
||||
loadFile(entry.path);
|
||||
};
|
||||
|
||||
const navigateUp = () => {
|
||||
if (!currentPath) return;
|
||||
const parentPath = currentPath.split("/").slice(0, -1).join("/");
|
||||
navigateTo(parentPath);
|
||||
setSelectedPath(null);
|
||||
setIsEditing(false);
|
||||
setEditContent(null);
|
||||
};
|
||||
|
||||
const handleEdit = () => {
|
||||
if (content !== null) {
|
||||
setEditContent(content);
|
||||
@@ -224,6 +239,15 @@ function FilesTab({ workspaceId }: { workspaceId: string }) {
|
||||
)}
|
||||
<div className="files-split">
|
||||
<div className="file-tree">
|
||||
{currentPath && (
|
||||
<button
|
||||
className="tree-entry tree-up"
|
||||
onClick={navigateUp}
|
||||
type="button"
|
||||
>
|
||||
<Icon name="folder" size="sm" /> ..
|
||||
</button>
|
||||
)}
|
||||
{loading && <p className="muted">Loading...</p>}
|
||||
{error && <p className="error-text">{error}</p>}
|
||||
{entries.map((entry) => (
|
||||
|
||||
Reference in New Issue
Block a user