-
-
Notifications
You must be signed in to change notification settings - Fork 83
fix: show empty state when filters match zero repositories #201
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -54,7 +54,7 @@ export default function RepositoriesPage() { | |
| const { sorted, sortConfig, onSort } = useSortedData(filtered, 'healthScore', 'desc') | ||
| const visible = sorted.slice(0, shown) | ||
|
|
||
| if(loading) return <RepositorySkeleton /> | ||
| if (loading) return <RepositorySkeleton /> | ||
| if (!model) return null | ||
|
|
||
| const TABLE_COLS = [ | ||
|
|
@@ -66,6 +66,8 @@ export default function RepositoriesPage() { | |
| ['pushed_at', 'Repository Activity'], | ||
| ] | ||
|
|
||
| const showNoSearchResults = search.trim() && filtered.length === 0 | ||
|
|
||
| return ( | ||
| <div style={{ padding: '32px 24px', maxWidth: 1100, margin: '0 auto' }} className="fade-up"> | ||
| <AnalysisBanner | ||
|
|
@@ -189,70 +191,77 @@ export default function RepositoriesPage() { | |
| ))} | ||
| </div> | ||
| </div> | ||
| {allRepos?.length ? ( | ||
| <> | ||
| {/* Table view */} | ||
| <div style={{ ...C.card, padding: 0, overflowX: 'auto' }}> | ||
| <table style={{ width: '100%', borderCollapse: 'collapse' }}> | ||
| <thead> | ||
| <tr> | ||
| {TABLE_COLS.map(([k, l]) => ( | ||
| <SortTh key={k} label={l} sortKey={k} sortConfig={sortConfig} onSort={onSort} /> | ||
| ))} | ||
| </tr> | ||
| </thead> | ||
| <tbody> | ||
| {visible.map((r, i) => ( | ||
| <tr key={r.id} style={{ borderBottom: '1px solid var(--border)', background: i % 2 ? 'var(--surface2)' : 'transparent' }}> | ||
| <td style={{ padding: '10px 14px' }}> | ||
| <a | ||
| href={`${r.html_url}`} | ||
| target="_blank" | ||
| rel="noopener noreferrer" | ||
| style={{ | ||
| textDecoration: 'none', | ||
| color: 'inherit', | ||
| }} | ||
| > | ||
| <div style={{ fontWeight: 500, fontSize: 13 }}>{r.name}</div> | ||
| {r.orgLogin && <div style={{ fontSize: 11, color: 'var(--text2)' }}>{r.orgLogin}</div>} | ||
| </a> | ||
| </td> | ||
| <td style={{ padding: '10px 14px', fontSize: 13, color: 'var(--text2)' }}>{r.stargazers_count.toLocaleString()}</td> | ||
| <td style={{ padding: '10px 14px', fontSize: 13, color: 'var(--text2)' }}>{r.forks_count.toLocaleString()}</td> | ||
| <td style={{ padding: '10px 14px', fontSize: 13, color: r.open_issues_count > 30 ? 'var(--red)' : 'var(--text2)' }}>{r.open_issues_count}</td> | ||
| <td style={{ padding: '10px 14px', minWidth: 130 }}><HealthBar score={r.healthScore} /></td> | ||
| <td style={{ padding: '10px 14px' }}> | ||
| <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}><Badge text={r.activityClassification} /> | ||
| <span style={{ fontSize: 11, color: 'var(--text2)' }}> | ||
| Last push: {r.pushed_at?.slice(0, 10)} | ||
| </span> | ||
| </div> | ||
| </td> | ||
| </tr> | ||
|
|
||
| {!allRepos?.length && ( | ||
| <div style={{ padding: '32px 24px', maxWidth: 900, margin: '0 auto' }}> | ||
| <EmptyStateCard | ||
| SvgIcon={<FiDatabase size={36} color="var(--accent)" />} | ||
| title="No repositories available" | ||
| description="We couldn't find any repositories for this organization yet." | ||
| buttonText="Go to Home" | ||
| onButtonClick={() => navigate('/')} | ||
|
Comment on lines
+199
to
+202
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift Externalize the new empty-state strings. Move these titles, descriptions, and button labels to the i18n resource files. The new direct literals prevent localization of the added states. As per path instructions, “User-visible strings should be externalized to resource files (i18n).” Also applies to: 211-214 🤖 Prompt for AI AgentsSource: Path instructions |
||
| /> | ||
| </div> | ||
| )} | ||
|
|
||
| {allRepos?.length > 0 && showNoSearchResults && ( | ||
| <div style={{ padding: '32px 24px', maxWidth: 900, margin: '0 auto' }}> | ||
| <EmptyStateCard | ||
| SvgIcon={<FiDatabase size={36} color="var(--accent)" />} | ||
| title="No matching repositories" | ||
| description="No repositories match your search. Try a different search term." | ||
| buttonText="Clear Search" | ||
| onButtonClick={() => setSearch('')} | ||
| /> | ||
| </div> | ||
| )} | ||
|
|
||
| {allRepos?.length > 0 && !showNoSearchResults && ( | ||
| <div style={{ ...C.card, padding: 0, overflowX: 'auto' }}> | ||
| <table style={{ width: '100%', borderCollapse: 'collapse' }}> | ||
| <thead> | ||
| <tr> | ||
| {TABLE_COLS.map(([k, l]) => ( | ||
| <SortTh key={k} label={l} sortKey={k} sortConfig={sortConfig} onSort={onSort} /> | ||
| ))} | ||
| </tbody> | ||
| </table> | ||
| <LoadMore shown={shown} total={sorted.length} onLoad={() => setShown(s => s + 20)} /> | ||
| </div> | ||
| </>) | ||
| : ( | ||
| <div | ||
| style={{ | ||
| padding: '32px 24px', | ||
| maxWidth: 900, | ||
| margin: '0 auto', | ||
| }} | ||
| > | ||
| <EmptyStateCard | ||
| SvgIcon={<FiDatabase size={36} color="var(--accent)" />} | ||
| title="No repositories available" | ||
| description="We couldn't find any repositories for this organization yet." | ||
| buttonText="Go to Home" | ||
| onButtonClick={() => navigate('/')} | ||
| /> | ||
| </div> | ||
| )} | ||
| </div> | ||
| </tr> | ||
| </thead> | ||
| <tbody> | ||
| {visible.map((r, i) => ( | ||
| <tr key={r.id} style={{ borderBottom: '1px solid var(--border)', background: i % 2 ? 'var(--surface2)' : 'transparent' }}> | ||
| <td style={{ padding: '10px 14px' }}> | ||
| <a | ||
| href={`${r.html_url}`} | ||
| target="_blank" | ||
| rel="noopener noreferrer" | ||
| style={{ | ||
| textDecoration: 'none', | ||
| color: 'inherit', | ||
| }} | ||
| > | ||
| <div style={{ fontWeight: 500, fontSize: 13 }}>{r.name}</div> | ||
| {r.orgLogin && <div style={{ fontSize: 11, color: 'var(--text2)' }}>{r.orgLogin}</div>} | ||
| </a> | ||
| </td> | ||
| <td style={{ padding: '10px 14px', fontSize: 13, color: 'var(--text2)' }}>{r.stargazers_count.toLocaleString()}</td> | ||
| <td style={{ padding: '10px 14px', fontSize: 13, color: 'var(--text2)' }}>{r.forks_count.toLocaleString()}</td> | ||
| <td style={{ padding: '10px 14px', fontSize: 13, color: r.open_issues_count > 30 ? 'var(--red)' : 'var(--text2)' }}>{r.open_issues_count}</td> | ||
| <td style={{ padding: '10px 14px', minWidth: 130 }}><HealthBar score={r.healthScore} /></td> | ||
| <td style={{ padding: '10px 14px' }}> | ||
| <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}><Badge text={r.activityClassification} /> | ||
| <span style={{ fontSize: 11, color: 'var(--text2)' }}> | ||
| Last push: {r.pushed_at?.slice(0, 10)} | ||
| </span> | ||
| </div> | ||
| </td> | ||
| </tr> | ||
| ))} | ||
| </tbody> | ||
| </table> | ||
| <LoadMore shown={shown} total={sorted.length} onLoad={() => setShown(s => s + 20)} /> | ||
| </div> | ||
| ) | ||
| } | ||
| </div > | ||
| ) | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Normalize the query before filtering.
When
searchcontains only whitespace, the filter uses the untrimmed value but Line 69 treats it as empty. If no repository contains that whitespace sequence, the table renders with zero rows and no empty state. Use the same trimmed query in both expressions.🤖 Prompt for AI Agents