fix cn
All checks were successful
Build and Deploy Log Center / build-and-deploy (push) Successful in 1m20s

This commit is contained in:
zyc 2026-02-12 10:53:03 +08:00
parent 61cbcfc4c4
commit 7ee724f8ac
6 changed files with 168 additions and 102 deletions

View File

@ -16,7 +16,7 @@ function App() {
<div className="logo-icon"> <div className="logo-icon">
<Shield size={16} /> <Shield size={16} />
</div> </div>
Log Center
</div> </div>
<nav> <nav>
<ul className="nav-menu"> <ul className="nav-menu">
@ -27,7 +27,7 @@ function App() {
end end
> >
<LayoutDashboard size={16} /> <LayoutDashboard size={16} />
Dashboard
</NavLink> </NavLink>
</li> </li>
<li className="nav-item"> <li className="nav-item">
@ -36,7 +36,7 @@ function App() {
className={({ isActive }) => `nav-link ${isActive ? 'active' : ''}`} className={({ isActive }) => `nav-link ${isActive ? 'active' : ''}`}
> >
<Bug size={16} /> <Bug size={16} />
Bug List
</NavLink> </NavLink>
</li> </li>
<li className="nav-item"> <li className="nav-item">
@ -45,7 +45,7 @@ function App() {
className={({ isActive }) => `nav-link ${isActive ? 'active' : ''}`} className={({ isActive }) => `nav-link ${isActive ? 'active' : ''}`}
> >
<Wrench size={16} /> <Wrench size={16} />
Repair Reports
</NavLink> </NavLink>
</li> </li>
</ul> </ul>

View File

@ -3,6 +3,18 @@ import { useParams, Link, useLocation } from 'react-router-dom';
import { ArrowLeft, Play, Loader2, FileCode, GitCommit } from 'lucide-react'; import { ArrowLeft, Play, Loader2, FileCode, GitCommit } from 'lucide-react';
import { getBugDetail, triggerRepair, type ErrorLog } from '../api'; import { getBugDetail, triggerRepair, type ErrorLog } from '../api';
const STATUS_LABELS: Record<string, string> = {
NEW: '新发现',
VERIFYING: '验证中',
CANNOT_REPRODUCE: '无法复现',
PENDING_FIX: '待修复',
FIXING: '修复中',
FIXED: '已修复',
VERIFIED: '已验证',
DEPLOYED: '已部署',
FIX_FAILED: '修复失败',
};
export default function BugDetail() { export default function BugDetail() {
const { id } = useParams<{ id: string }>(); const { id } = useParams<{ id: string }>();
const location = useLocation(); const location = useLocation();
@ -35,10 +47,10 @@ export default function BugDetail() {
try { try {
await triggerRepair(bug.id); await triggerRepair(bug.id);
setBug({ ...bug, status: 'PENDING_FIX' }); setBug({ ...bug, status: 'PENDING_FIX' });
setRepairMessage('Repair triggered successfully'); setRepairMessage('已成功触发修复');
} catch (error) { } catch (error) {
console.error('Failed to trigger repair:', error); console.error('Failed to trigger repair:', error);
setRepairMessage('Failed to trigger repair'); setRepairMessage('触发修复失败');
} finally { } finally {
setRepairing(false); setRepairing(false);
} }
@ -53,7 +65,7 @@ export default function BugDetail() {
} }
if (!bug) { if (!bug) {
return <div className="loading">Bug not found</div>; return <div className="loading"></div>;
} }
const canTriggerRepair = ['NEW', 'FIX_FAILED'].includes(bug.status); const canTriggerRepair = ['NEW', 'FIX_FAILED'].includes(bug.status);
@ -62,7 +74,7 @@ export default function BugDetail() {
<div> <div>
<Link to={`/bugs${backSearch ? `?${backSearch}` : ''}`} className="back-link"> <Link to={`/bugs${backSearch ? `?${backSearch}` : ''}`} className="back-link">
<ArrowLeft size={14} /> <ArrowLeft size={14} />
Back to Bug List
</Link> </Link>
<div className="detail-card"> <div className="detail-card">
@ -72,25 +84,27 @@ export default function BugDetail() {
{bug.error_type}: {bug.error_message} {bug.error_type}: {bug.error_message}
</h2> </h2>
<div className="detail-meta"> <div className="detail-meta">
<span>Project: {bug.project_id}</span> <span>{bug.project_id}</span>
<span>Env: {bug.environment}</span> <span>{bug.environment}</span>
<span>Level: {bug.level}</span> <span>{bug.level}</span>
</div> </div>
</div> </div>
<span className={`status-badge status-${bug.status}`}>{bug.status}</span> <span className={`status-badge status-${bug.status}`}>
{STATUS_LABELS[bug.status] || bug.status}
</span>
</div> </div>
<div className="detail-section"> <div className="detail-section">
<div className="detail-section-title">Location</div> <div className="detail-section-title"></div>
<div className="detail-section-value"> <div className="detail-section-value">
<FileCode size={14} style={{ display: 'inline', verticalAlign: 'middle', marginRight: '6px' }} /> <FileCode size={14} style={{ display: 'inline', verticalAlign: 'middle', marginRight: '6px' }} />
{bug.file_path} : Line {bug.line_number} {bug.file_path} : {bug.line_number}
</div> </div>
</div> </div>
{bug.commit_hash && ( {bug.commit_hash && (
<div className="detail-section"> <div className="detail-section">
<div className="detail-section-title">Git Info</div> <div className="detail-section-title">Git </div>
<div className="detail-section-value"> <div className="detail-section-value">
<GitCommit size={14} style={{ display: 'inline', verticalAlign: 'middle', marginRight: '6px' }} /> <GitCommit size={14} style={{ display: 'inline', verticalAlign: 'middle', marginRight: '6px' }} />
{bug.commit_hash} {bug.commit_hash}
@ -100,7 +114,7 @@ export default function BugDetail() {
)} )}
<div className="detail-section"> <div className="detail-section">
<div className="detail-section-title">Stack Trace</div> <div className="detail-section-title"></div>
<pre className="code-block error"> <pre className="code-block error">
{typeof bug.stack_trace === 'string' {typeof bug.stack_trace === 'string'
? bug.stack_trace ? bug.stack_trace
@ -110,7 +124,7 @@ export default function BugDetail() {
{bug.context && Object.keys(bug.context).length > 0 && ( {bug.context && Object.keys(bug.context).length > 0 && (
<div className="detail-section"> <div className="detail-section">
<div className="detail-section-title">Context</div> <div className="detail-section-title"></div>
<pre className="code-block accent"> <pre className="code-block accent">
{JSON.stringify(bug.context, null, 2)} {JSON.stringify(bug.context, null, 2)}
</pre> </pre>
@ -128,42 +142,42 @@ export default function BugDetail() {
) : ( ) : (
<Play size={14} /> <Play size={14} />
)} )}
{repairing ? 'Triggering...' : 'Trigger Repair'} {repairing ? '触发中...' : '触发修复'}
</button> </button>
{repairMessage && ( {repairMessage && (
<span style={{ <span style={{
fontSize: '13px', fontSize: '13px',
color: repairMessage.includes('success') ? 'var(--success)' : 'var(--error)' color: repairMessage.includes('成功') ? 'var(--success)' : 'var(--error)'
}}> }}>
{repairMessage} {repairMessage}
</span> </span>
)} )}
{!canTriggerRepair && !repairing && ( {!canTriggerRepair && !repairing && (
<span style={{ fontSize: '13px', color: 'var(--text-tertiary)' }}> <span style={{ fontSize: '13px', color: 'var(--text-tertiary)' }}>
Only NEW or FIX_FAILED bugs can be triggered "新发现""修复失败"
</span> </span>
)} )}
</div> </div>
</div> </div>
<div className="detail-card"> <div className="detail-card">
<div className="detail-section-title" style={{ marginBottom: '12px' }}>Metadata</div> <div className="detail-section-title" style={{ marginBottom: '12px' }}></div>
<table className="meta-table"> <table className="meta-table">
<tbody> <tbody>
<tr> <tr>
<td className="meta-label">Bug ID</td> <td className="meta-label"></td>
<td>{bug.id}</td> <td>{bug.id}</td>
</tr> </tr>
<tr> <tr>
<td className="meta-label">Fingerprint</td> <td className="meta-label"></td>
<td className="cell-mono">{bug.fingerprint}</td> <td className="cell-mono">{bug.fingerprint}</td>
</tr> </tr>
<tr> <tr>
<td className="meta-label">Retry Count</td> <td className="meta-label"></td>
<td>{bug.retry_count}</td> <td>{bug.retry_count}</td>
</tr> </tr>
<tr> <tr>
<td className="meta-label">Reported At</td> <td className="meta-label"></td>
<td>{new Date(bug.timestamp).toLocaleString()}</td> <td>{new Date(bug.timestamp).toLocaleString()}</td>
</tr> </tr>
</tbody> </tbody>

View File

@ -7,6 +7,18 @@ const STATUSES = [
'FIXING', 'FIXED', 'VERIFIED', 'DEPLOYED', 'FIX_FAILED' 'FIXING', 'FIXED', 'VERIFIED', 'DEPLOYED', 'FIX_FAILED'
]; ];
const STATUS_LABELS: Record<string, string> = {
NEW: '新发现',
VERIFYING: '验证中',
CANNOT_REPRODUCE: '无法复现',
PENDING_FIX: '待修复',
FIXING: '修复中',
FIXED: '已修复',
VERIFIED: '已验证',
DEPLOYED: '已部署',
FIX_FAILED: '修复失败',
};
export default function BugList() { export default function BugList() {
const [searchParams, setSearchParams] = useSearchParams(); const [searchParams, setSearchParams] = useSearchParams();
@ -71,8 +83,8 @@ export default function BugList() {
return ( return (
<div> <div>
<div className="page-header"> <div className="page-header">
<h1 className="page-title">Bug List</h1> <h1 className="page-title"></h1>
<p className="page-subtitle">All reported errors and their current status</p> <p className="page-subtitle"></p>
</div> </div>
<div className="project-tabs"> <div className="project-tabs">
@ -80,7 +92,7 @@ export default function BugList() {
className={`project-tab ${currentProject === '' ? 'active' : ''}`} className={`project-tab ${currentProject === '' ? 'active' : ''}`}
onClick={() => updateParams({ project: '' })} onClick={() => updateParams({ project: '' })}
> >
All Projects
</button> </button>
{projects.map(p => ( {projects.map(p => (
<button <button
@ -98,7 +110,7 @@ export default function BugList() {
className={`status-tab ${currentStatus === '' ? 'active' : ''}`} className={`status-tab ${currentStatus === '' ? 'active' : ''}`}
onClick={() => updateParams({ status: '' })} onClick={() => updateParams({ status: '' })}
> >
All Status
</button> </button>
{STATUSES.map(s => ( {STATUSES.map(s => (
<button <button
@ -106,7 +118,7 @@ export default function BugList() {
className={`status-tab ${currentStatus === s ? 'active' : ''} status-color-${s}`} className={`status-tab ${currentStatus === s ? 'active' : ''} status-color-${s}`}
onClick={() => updateParams({ status: s })} onClick={() => updateParams({ status: s })}
> >
{s.replace('_', ' ')} {STATUS_LABELS[s] || s}
</button> </button>
))} ))}
</div> </div>
@ -118,21 +130,21 @@ export default function BugList() {
</div> </div>
) : bugs.length === 0 ? ( ) : bugs.length === 0 ? (
<div className="empty-state"> <div className="empty-state">
No bugs found
{currentProject && <span> in <strong>{currentProject}</strong></span>} {currentProject && <span><strong>{currentProject}</strong></span>}
{currentStatus && <span> with status <strong>{currentStatus}</strong></span>} {currentStatus && <span><strong>{STATUS_LABELS[currentStatus] || currentStatus}</strong></span>}
</div> </div>
) : ( ) : (
<> <>
<table> <table>
<thead> <thead>
<tr> <tr>
<th>ID</th> <th></th>
<th>Project</th> <th></th>
<th>Error Type</th> <th></th>
<th>File</th> <th></th>
<th>Status</th> <th></th>
<th>Time</th> <th></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -160,7 +172,7 @@ export default function BugList() {
</td> </td>
<td> <td>
<span className={`status-badge status-${bug.status}`}> <span className={`status-badge status-${bug.status}`}>
{bug.status} {STATUS_LABELS[bug.status] || bug.status}
</span> </span>
</td> </td>
<td className="cell-secondary"> <td className="cell-secondary">
@ -177,16 +189,16 @@ export default function BugList() {
onClick={() => updateParams({ page: String(Math.max(1, currentPage - 1)) })} onClick={() => updateParams({ page: String(Math.max(1, currentPage - 1)) })}
disabled={currentPage === 1} disabled={currentPage === 1}
> >
Previous
</button> </button>
<span className="pagination-info"> <span className="pagination-info">
Page {currentPage} of {totalPages} {currentPage} {totalPages}
</span> </span>
<button <button
onClick={() => updateParams({ page: String(Math.min(totalPages, currentPage + 1)) })} onClick={() => updateParams({ page: String(Math.min(totalPages, currentPage + 1)) })}
disabled={currentPage === totalPages} disabled={currentPage === totalPages}
> >
Next
</button> </button>
</div> </div>
)} )}

View File

@ -2,6 +2,18 @@ import { useState, useEffect } from 'react';
import { Bug, CalendarPlus, TrendingUp, AlertTriangle } from 'lucide-react'; import { Bug, CalendarPlus, TrendingUp, AlertTriangle } from 'lucide-react';
import { getStats, type DashboardStats } from '../api'; import { getStats, type DashboardStats } from '../api';
const STATUS_LABELS: Record<string, string> = {
NEW: '新发现',
VERIFYING: '验证中',
CANNOT_REPRODUCE: '无法复现',
PENDING_FIX: '待修复',
FIXING: '修复中',
FIXED: '已修复',
VERIFIED: '已验证',
DEPLOYED: '已部署',
FIX_FAILED: '修复失败',
};
export default function Dashboard() { export default function Dashboard() {
const [stats, setStats] = useState<DashboardStats | null>(null); const [stats, setStats] = useState<DashboardStats | null>(null);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
@ -29,14 +41,14 @@ export default function Dashboard() {
} }
if (!stats) { if (!stats) {
return <div className="loading">Failed to load statistics</div>; return <div className="loading"></div>;
} }
return ( return (
<div> <div>
<div className="page-header"> <div className="page-header">
<h1 className="page-title">Dashboard</h1> <h1 className="page-title"></h1>
<p className="page-subtitle">Overview of your error tracking system</p> <p className="page-subtitle"></p>
</div> </div>
<div className="stats-grid"> <div className="stats-grid">
@ -44,28 +56,28 @@ export default function Dashboard() {
<div className="stat-icon accent"> <div className="stat-icon accent">
<Bug size={18} /> <Bug size={18} />
</div> </div>
<div className="stat-label">Total Bugs</div> <div className="stat-label"></div>
<div className="stat-value accent">{stats.total_bugs}</div> <div className="stat-value accent">{stats.total_bugs}</div>
</div> </div>
<div className="stat-card"> <div className="stat-card">
<div className="stat-icon warning"> <div className="stat-icon warning">
<CalendarPlus size={18} /> <CalendarPlus size={18} />
</div> </div>
<div className="stat-label">Today's New</div> <div className="stat-label"></div>
<div className="stat-value warning">{stats.today_bugs}</div> <div className="stat-value warning">{stats.today_bugs}</div>
</div> </div>
<div className="stat-card"> <div className="stat-card">
<div className="stat-icon success"> <div className="stat-icon success">
<TrendingUp size={18} /> <TrendingUp size={18} />
</div> </div>
<div className="stat-label">Fix Rate</div> <div className="stat-label"></div>
<div className="stat-value success">{stats.fix_rate}%</div> <div className="stat-value success">{stats.fix_rate}%</div>
</div> </div>
<div className="stat-card"> <div className="stat-card">
<div className="stat-icon error"> <div className="stat-icon error">
<AlertTriangle size={18} /> <AlertTriangle size={18} />
</div> </div>
<div className="stat-label">Pending Fix</div> <div className="stat-label"></div>
<div className="stat-value error"> <div className="stat-value error">
{(stats.status_distribution['NEW'] || 0) + {(stats.status_distribution['NEW'] || 0) +
(stats.status_distribution['PENDING_FIX'] || 0)} (stats.status_distribution['PENDING_FIX'] || 0)}
@ -75,20 +87,22 @@ export default function Dashboard() {
<div className="table-container"> <div className="table-container">
<div className="table-header"> <div className="table-header">
<h3 className="table-title">Status Distribution</h3> <h3 className="table-title"></h3>
</div> </div>
<table> <table>
<thead> <thead>
<tr> <tr>
<th>Status</th> <th></th>
<th>Count</th> <th></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{Object.entries(stats.status_distribution).map(([status, count]) => ( {Object.entries(stats.status_distribution).map(([status, count]) => (
<tr key={status}> <tr key={status}>
<td> <td>
<span className={`status-badge status-${status}`}>{status}</span> <span className={`status-badge status-${status}`}>
{STATUS_LABELS[status] || status}
</span>
</td> </td>
<td>{count}</td> <td>{count}</td>
</tr> </tr>

View File

@ -3,6 +3,18 @@ import { useParams, Link } from 'react-router-dom';
import { ArrowLeft, Bot, FileCode, FlaskConical } from 'lucide-react'; import { ArrowLeft, Bot, FileCode, FlaskConical } from 'lucide-react';
import { getRepairReportDetail, type RepairReport } from '../api'; import { getRepairReportDetail, type RepairReport } from '../api';
const STATUS_LABELS: Record<string, string> = {
NEW: '新发现',
VERIFYING: '验证中',
CANNOT_REPRODUCE: '无法复现',
PENDING_FIX: '待修复',
FIXING: '修复中',
FIXED: '已修复',
VERIFIED: '已验证',
DEPLOYED: '已部署',
FIX_FAILED: '修复失败',
};
export default function RepairDetail() { export default function RepairDetail() {
const { id } = useParams<{ id: string }>(); const { id } = useParams<{ id: string }>();
const [report, setReport] = useState<RepairReport | null>(null); const [report, setReport] = useState<RepairReport | null>(null);
@ -33,57 +45,59 @@ export default function RepairDetail() {
} }
if (!report) { if (!report) {
return <div className="loading">Report not found</div>; return <div className="loading"></div>;
} }
return ( return (
<div> <div>
<Link to="/repairs" className="back-link"> <Link to="/repairs" className="back-link">
<ArrowLeft size={14} /> <ArrowLeft size={14} />
Back to Repair Reports
</Link> </Link>
<div style={{ marginBottom: '20px' }}> <div style={{ marginBottom: '20px' }}>
<div className="title-row"> <div className="title-row">
<h1 className="page-title">Repair Report #{report.id}</h1> <h1 className="page-title"> #{report.id}</h1>
<span className={`status-badge status-${report.status}`}>{report.status}</span> <span className={`status-badge status-${report.status}`}>
</div> {STATUS_LABELS[report.status] || report.status}
</div>
<div className="card">
<h2>Basic Info</h2>
<div className="info-row">
<span>Project</span>
<strong>{report.project_id}</strong>
</div>
<div className="info-row">
<span>Bug ID</span>
<Link to={`/bugs/${report.error_log_id}`}>#{report.error_log_id}</Link>
</div>
<div className="info-row">
<span>Created At</span>
<span>{new Date(report.created_at).toLocaleString()}</span>
</div>
<div className="info-row">
<span>Test Result</span>
<span className={report.test_passed ? 'test-pass' : 'test-fail'}>
{report.test_passed ? 'PASS' : 'FAIL'}
</span> </span>
</div> </div>
</div> </div>
<div className="card"> <div className="card">
<h2><Bot size={16} /> AI Analysis</h2> <h2></h2>
<div className="info-row">
<span></span>
<strong>{report.project_id}</strong>
</div>
<div className="info-row">
<span></span>
<Link to={`/bugs/${report.error_log_id}`}>#{report.error_log_id}</Link>
</div>
<div className="info-row">
<span></span>
<span>{new Date(report.created_at).toLocaleString()}</span>
</div>
<div className="info-row">
<span></span>
<span className={report.test_passed ? 'test-pass' : 'test-fail'}>
{report.test_passed ? '通过' : '失败'}
</span>
</div>
</div>
<div className="card">
<h2><Bot size={16} /> AI </h2>
<pre className="code-block neutral">{report.ai_analysis}</pre> <pre className="code-block neutral">{report.ai_analysis}</pre>
</div> </div>
<div className="card"> <div className="card">
<h2><FileCode size={16} /> Code Changes</h2> <h2><FileCode size={16} /> </h2>
<pre className="code-block neutral">{report.code_diff || 'No changes recorded'}</pre> <pre className="code-block neutral">{report.code_diff || '无变更记录'}</pre>
</div> </div>
<div className="card"> <div className="card">
<h2><FlaskConical size={16} /> Test Output</h2> <h2><FlaskConical size={16} /> </h2>
<pre className="code-block neutral">{report.test_output}</pre> <pre className="code-block neutral">{report.test_output}</pre>
</div> </div>
</div> </div>

View File

@ -2,6 +2,18 @@ import { useState, useEffect } from 'react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { getRepairReports, type RepairReport, getProjects } from '../api'; import { getRepairReports, type RepairReport, getProjects } from '../api';
const STATUS_LABELS: Record<string, string> = {
NEW: '新发现',
VERIFYING: '验证中',
CANNOT_REPRODUCE: '无法复现',
PENDING_FIX: '待修复',
FIXING: '修复中',
FIXED: '已修复',
VERIFIED: '已验证',
DEPLOYED: '已部署',
FIX_FAILED: '修复失败',
};
export default function RepairList() { export default function RepairList() {
const [reports, setReports] = useState<RepairReport[]>([]); const [reports, setReports] = useState<RepairReport[]>([]);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
@ -52,8 +64,8 @@ export default function RepairList() {
<div className="page-header"> <div className="page-header">
<div className="title-row"> <div className="title-row">
<div> <div>
<h1 className="page-title">Repair Reports</h1> <h1 className="page-title"></h1>
<p className="page-subtitle">AI-powered bug repair attempts and their results</p> <p className="page-subtitle">AI </p>
</div> </div>
<div className="filters"> <div className="filters">
<select <select
@ -61,7 +73,7 @@ export default function RepairList() {
value={filters.project_id} value={filters.project_id}
onChange={(e) => handleFilterChange('project_id', e.target.value)} onChange={(e) => handleFilterChange('project_id', e.target.value)}
> >
<option value="">All Projects</option> <option value=""></option>
{projects.map((p) => ( {projects.map((p) => (
<option key={p} value={p}>{p}</option> <option key={p} value={p}>{p}</option>
))} ))}
@ -76,19 +88,19 @@ export default function RepairList() {
<div className="spinner"></div> <div className="spinner"></div>
</div> </div>
) : reports.length === 0 ? ( ) : reports.length === 0 ? (
<div className="empty-state">No reports found</div> <div className="empty-state"></div>
) : ( ) : (
<table> <table>
<thead> <thead>
<tr> <tr>
<th>ID</th> <th></th>
<th>Project</th> <th></th>
<th>Bug ID</th> <th></th>
<th>Modified Files</th> <th></th>
<th>Test Result</th> <th></th>
<th>Status</th> <th></th>
<th>Date</th> <th></th>
<th>Actions</th> <th></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -101,15 +113,15 @@ export default function RepairList() {
#{report.error_log_id} #{report.error_log_id}
</Link> </Link>
</td> </td>
<td>{report.modified_files.length} files</td> <td>{report.modified_files.length} </td>
<td> <td>
<span className={report.test_passed ? 'test-pass' : 'test-fail'}> <span className={report.test_passed ? 'test-pass' : 'test-fail'}>
{report.test_passed ? 'PASS' : 'FAIL'} {report.test_passed ? '通过' : '失败'}
</span> </span>
</td> </td>
<td> <td>
<span className={`status-badge status-${report.status}`}> <span className={`status-badge status-${report.status}`}>
{report.status} {STATUS_LABELS[report.status] || report.status}
</span> </span>
</td> </td>
<td className="cell-secondary"> <td className="cell-secondary">
@ -117,7 +129,7 @@ export default function RepairList() {
</td> </td>
<td> <td>
<Link to={`/repairs/${report.id}`} className="btn-link"> <Link to={`/repairs/${report.id}`} className="btn-link">
View
</Link> </Link>
</td> </td>
</tr> </tr>
@ -133,16 +145,16 @@ export default function RepairList() {
disabled={filters.page === 1} disabled={filters.page === 1}
onClick={() => setFilters((prev) => ({ ...prev, page: prev.page - 1 }))} onClick={() => setFilters((prev) => ({ ...prev, page: prev.page - 1 }))}
> >
Previous
</button> </button>
<span className="pagination-info"> <span className="pagination-info">
Page {filters.page} of {totalPages} {filters.page} {totalPages}
</span> </span>
<button <button
disabled={filters.page === totalPages} disabled={filters.page === totalPages}
onClick={() => setFilters((prev) => ({ ...prev, page: prev.page + 1 }))} onClick={() => setFilters((prev) => ({ ...prev, page: prev.page + 1 }))}
> >
Next
</button> </button>
</div> </div>
)} )}