All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Fixes all 542 ESLint problems in the web package to achieve 0 errors and 0 warnings. Changes: - Fixed 144 issues: nullish coalescing, return types, unused variables - Fixed 118 issues: unnecessary conditions, type safety, template literals - Fixed 79 issues: non-null assertions, unsafe assignments, empty functions - Fixed 67 issues: explicit return types, promise handling, enum comparisons - Fixed 45 final warnings: missing return types, optional chains - Fixed 25 typecheck-related issues: async/await, type assertions, formatting - Fixed JSX.Element namespace errors across 90+ files All Quality Rails violations resolved. Lint and typecheck both pass with 0 problems. Files modified: 118 components, tests, hooks, and utilities Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
122 lines
3.9 KiB
TypeScript
122 lines
3.9 KiB
TypeScript
import type { KnowledgeEntryWithTags } from "@mosaic/shared";
|
|
import { EntryCard } from "./EntryCard";
|
|
import { BookOpen } from "lucide-react";
|
|
|
|
interface EntryListProps {
|
|
entries: KnowledgeEntryWithTags[];
|
|
isLoading: boolean;
|
|
currentPage: number;
|
|
totalPages: number;
|
|
onPageChange: (page: number) => void;
|
|
}
|
|
|
|
export function EntryList({
|
|
entries,
|
|
isLoading,
|
|
currentPage,
|
|
totalPages,
|
|
onPageChange,
|
|
}: EntryListProps): React.JSX.Element {
|
|
if (isLoading) {
|
|
return (
|
|
<div className="flex justify-center items-center p-12">
|
|
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div>
|
|
<span className="ml-3 text-gray-600">Loading entries...</span>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (entries.length === 0) {
|
|
return (
|
|
<div className="text-center p-12 bg-white rounded-lg shadow-sm border border-gray-200">
|
|
<BookOpen className="w-12 h-12 text-gray-400 mx-auto mb-3" />
|
|
<p className="text-lg text-gray-700 font-medium">No entries found</p>
|
|
<p className="text-sm text-gray-500 mt-2">
|
|
Try adjusting your filters or create a new entry
|
|
</p>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
{/* Entry cards */}
|
|
<div className="space-y-4">
|
|
{entries.map((entry) => (
|
|
<EntryCard key={entry.id} entry={entry} />
|
|
))}
|
|
</div>
|
|
|
|
{/* Pagination */}
|
|
{totalPages > 1 && (
|
|
<div className="flex items-center justify-center gap-2 pt-6">
|
|
<button
|
|
onClick={() => {
|
|
onPageChange(currentPage - 1);
|
|
}}
|
|
disabled={currentPage === 1}
|
|
className="px-4 py-2 border border-gray-300 rounded-lg text-sm font-medium text-gray-700 hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
|
>
|
|
Previous
|
|
</button>
|
|
|
|
<div className="flex items-center gap-1">
|
|
{Array.from({ length: totalPages }, (_, i) => i + 1).map((page) => {
|
|
// Show first, last, current, and pages around current
|
|
const shouldShow =
|
|
page === 1 || page === totalPages || Math.abs(page - currentPage) <= 1;
|
|
|
|
// Show ellipsis
|
|
const showEllipsisBefore = page === currentPage - 2 && currentPage > 3;
|
|
const showEllipsisAfter = page === currentPage + 2 && currentPage < totalPages - 2;
|
|
|
|
if (!shouldShow && !showEllipsisBefore && !showEllipsisAfter) {
|
|
return null;
|
|
}
|
|
|
|
if (showEllipsisBefore || showEllipsisAfter) {
|
|
return (
|
|
<span key={`ellipsis-${String(page)}`} className="px-2 text-gray-500">
|
|
...
|
|
</span>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<button
|
|
key={page}
|
|
onClick={() => {
|
|
onPageChange(page);
|
|
}}
|
|
className={`px-3 py-2 rounded-lg text-sm font-medium transition-colors ${
|
|
page === currentPage
|
|
? "bg-blue-600 text-white"
|
|
: "text-gray-700 hover:bg-gray-100"
|
|
}`}
|
|
>
|
|
{page}
|
|
</button>
|
|
);
|
|
})}
|
|
</div>
|
|
|
|
<button
|
|
onClick={() => {
|
|
onPageChange(currentPage + 1);
|
|
}}
|
|
disabled={currentPage === totalPages}
|
|
className="px-4 py-2 border border-gray-300 rounded-lg text-sm font-medium text-gray-700 hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
|
>
|
|
Next
|
|
</button>
|
|
</div>
|
|
)}
|
|
|
|
{/* Results info */}
|
|
<div className="text-center text-sm text-gray-500">
|
|
Page {currentPage} of {totalPages} ({entries.length} entries)
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|