Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed
- Upgraded `brace-expansion` to `^1.1.17`/`^2.1.3`/`^5.0.8`. [#1527](https://github.com/sourcebot-dev/sourcebot/pull/1527)
- The browse file-tree panel now shows a clear "This repository is empty." (root) or "This directory is empty." (sub-path) message when the folder contents are empty, and a dedicated "Repository not found." message for 404s, instead of the generic "Error loading tree preview" or a blank scroll area. [#1530](https://github.com/sourcebot-dev/sourcebot/pull/1530)

## [5.1.5] - 2026-07-31

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { describe, expect, test, vi } from 'vitest';
import { render, screen } from '@testing-library/react';
import { SidebarProvider } from '@/components/ui/sidebar';

// Stub the file-tree item component so the test only exercises the
// empty-state branch. The real component pulls in `usePathname` and
// a router context that's heavy to mock for an empty-state assertion.
vi.mock('@/app/(app)/browse/components/fileTreeItemComponent', () => ({
FileTreeItemComponent: () => <li data-testid="file-tree-item" />,
}));

vi.mock('next/navigation', () => ({
usePathname: () => '/browse/github.com/foo/bar@main/-/tree/src',
}));

vi.mock('@/hooks/use-mobile', () => ({
useIsMobile: () => false,
}));

const { PureTreePreviewPanel } = await import('./pureTreePreviewPanel');

const wrap = (ui: React.ReactNode) => (
<SidebarProvider defaultOpen={true}>
<ul>{ui}</ul>
</SidebarProvider>
);

describe('PureTreePreviewPanel empty state (issue #1530)', () => {
test('renders the "This directory is empty" message when the items array is empty', () => {
// The empty-state message is rendered inside the same
// ScrollArea as the items, so a real "directory" sub-path
// (path != '') still shows the path header above the panel
// and the "This directory is empty." copy below. The
// PureTree component doesn't know about the path; the caller
// decides whether to render the full panel (path != '') or
// the full-panel "This repository is empty" copy (path == '').
render(wrap(<PureTreePreviewPanel items={[]} />));
expect(screen.getByText('This directory is empty.')).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,28 @@ export const PureTreePreviewPanel = ({ items }: PureTreePreviewPanelProps) => {
className="flex flex-col p-0.5"
ref={scrollAreaRef}
>
{items.map((item) => (
<FileTreeItemComponent
key={item.path}
node={item}
isActive={false}
depth={0}
isCollapseChevronVisible={false}
parentRef={scrollAreaRef}
href={getBrowsePath({
repoName,
revisionName,
path: item.path,
pathType: item.type === 'tree' ? 'tree' : 'blob',
})}
/>
))}
{items.length === 0 ? (
<div className="p-4 text-sm text-muted-foreground">
This directory is empty.
</div>
Comment thread
cursor[bot] marked this conversation as resolved.
) : (
items.map((item) => (
<FileTreeItemComponent
key={item.path}
node={item}
isActive={false}
depth={0}
isCollapseChevronVisible={false}
parentRef={scrollAreaRef}
href={getBrowsePath({
repoName,
revisionName,
path: item.path,
pathType: item.type === 'tree' ? 'tree' : 'blob',
})}
/>
))
)}
</ScrollArea>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ export const TreePreviewPanel = async ({ path, repoName, revisionName }: TreePre
const repoInfoResponse = await getRepoInfoByName(repoName);

if (isServiceError(repoInfoResponse)) {
// A 404 means the user hit a typo in a repo name (or a config
// that's no longer indexed). A different status code is an
// actual system error. Showing the same generic message for
// both confuses users — the typo case looks like a sync
// problem. See issue #1530.
if (repoInfoResponse.errorCode === 'NOT_FOUND') {
return <div>Repository not found.</div>;
}
return <div>Error loading tree preview</div>
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,22 @@ export const TreePreviewPanelClient = ({ path, repoName, revisionName, repo }: T
return <div>Error loading tree preview</div>
}

// Distinguish "the repository has no files" from "this sub-directory
// has no files" at the root path. The latter is handled inside
// `PureTreePreviewPanel` with a "This directory is empty." copy;
// the former is a stronger message and avoids rendering a path
// header for a non-existent root. See issue #1530.
if (folderContentsResponse.length === 0 && path === '') {
return (
<div className="flex flex-col w-full min-h-full items-center justify-center gap-2 p-6 text-muted-foreground">
<p className="text-sm font-medium">This repository is empty.</p>
<p className="text-xs">
Once a commit lands on the default branch, its files will appear here.
</p>
</div>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Root empty state ignores active revision

Medium Severity

The new root empty-state UI runs whenever folderContentsResponse is [] and path === '', but the fetch uses the browse URL’s revisionName (or HEAD). An empty tree at that ref still shows “This repository is empty.” and copy about the default branch, even when the repo has files on other refs or the user is viewing a non-default revision.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 43f2949. Configure here.

);
}

return (
<>
<div className="flex flex-row py-1 px-2 items-center justify-between">
Expand Down