mirror of
https://github.com/icereed/paperless-gpt.git
synced 2025-03-12 21:08:00 -05:00
Implement pagination for modification history retrieval and update frontend to support paginated data
This commit is contained in:
parent
32cc3d2794
commit
969bacc137
3 changed files with 116 additions and 22 deletions
|
@ -248,13 +248,34 @@ func (app *App) getDocumentHandler() gin.HandlerFunc {
|
|||
// Section for local-db actions
|
||||
|
||||
func (app *App) getModificationHistoryHandler(c *gin.Context) {
|
||||
modifications, err := GetAllModifications(app.Database)
|
||||
// Parse pagination parameters
|
||||
page := 1
|
||||
pageSize := 20
|
||||
|
||||
if p, err := strconv.Atoi(c.DefaultQuery("page", "1")); err == nil && p > 0 {
|
||||
page = p
|
||||
}
|
||||
if ps, err := strconv.Atoi(c.DefaultQuery("pageSize", "20")); err == nil && ps > 0 && ps <= 100 {
|
||||
pageSize = ps
|
||||
}
|
||||
|
||||
// Get paginated modifications and total count
|
||||
modifications, total, err := GetPaginatedModifications(app.Database, page, pageSize)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to retrieve modification history"})
|
||||
log.Errorf("Failed to retrieve modification history: %v", err)
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, modifications)
|
||||
|
||||
totalPages := (int(total) + pageSize - 1) / pageSize
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"items": modifications,
|
||||
"totalItems": total,
|
||||
"totalPages": totalPages,
|
||||
"currentPage": page,
|
||||
"pageSize": pageSize,
|
||||
})
|
||||
}
|
||||
|
||||
func (app *App) undoModificationHandler(c *gin.Context) {
|
||||
|
|
26
local_db.go
26
local_db.go
|
@ -63,13 +63,35 @@ func GetModification(db *gorm.DB, id uint) (*ModificationHistory, error) {
|
|||
return &record, result.Error
|
||||
}
|
||||
|
||||
// GetAllModifications retrieves all modification records from the database
|
||||
// GetAllModifications retrieves all modification records from the database (deprecated - use GetPaginatedModifications instead)
|
||||
func GetAllModifications(db *gorm.DB) ([]ModificationHistory, error) {
|
||||
var records []ModificationHistory
|
||||
result := db.Order("date_changed DESC").Find(&records) // GORM's Find method retrieves all records
|
||||
result := db.Order("date_changed DESC").Find(&records)
|
||||
return records, result.Error
|
||||
}
|
||||
|
||||
// GetPaginatedModifications retrieves a page of modification records with total count
|
||||
func GetPaginatedModifications(db *gorm.DB, page int, pageSize int) ([]ModificationHistory, int64, error) {
|
||||
var records []ModificationHistory
|
||||
var total int64
|
||||
|
||||
// Get total count
|
||||
if err := db.Model(&ModificationHistory{}).Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// Calculate offset
|
||||
offset := (page - 1) * pageSize
|
||||
|
||||
// Get paginated records
|
||||
result := db.Order("date_changed DESC").
|
||||
Offset(offset).
|
||||
Limit(pageSize).
|
||||
Find(&records)
|
||||
|
||||
return records, total, result.Error
|
||||
}
|
||||
|
||||
// UndoModification marks a modification record as undone and sets the undo date
|
||||
func SetModificationUndone(db *gorm.DB, record *ModificationHistory) error {
|
||||
record.Undone = true
|
||||
|
|
|
@ -12,11 +12,23 @@ interface ModificationHistory {
|
|||
UndoneDate: string | null;
|
||||
}
|
||||
|
||||
interface PaginatedResponse {
|
||||
items: ModificationHistory[];
|
||||
totalItems: number;
|
||||
totalPages: number;
|
||||
currentPage: number;
|
||||
pageSize: number;
|
||||
}
|
||||
|
||||
const History: React.FC = () => {
|
||||
const [modifications, setModifications] = useState<ModificationHistory[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [paperlessUrl, setPaperlessUrl] = useState<string>('');
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [totalPages, setTotalPages] = useState(1);
|
||||
const [totalItems, setTotalItems] = useState(0);
|
||||
const pageSize = 20;
|
||||
|
||||
// Get Paperless URL
|
||||
useEffect(() => {
|
||||
|
@ -36,19 +48,22 @@ const History: React.FC = () => {
|
|||
fetchUrl();
|
||||
}, []);
|
||||
|
||||
// Get all modifications
|
||||
// Get modifications with pagination
|
||||
useEffect(() => {
|
||||
fetchModifications();
|
||||
}, []);
|
||||
fetchModifications(currentPage);
|
||||
}, [currentPage]);
|
||||
|
||||
const fetchModifications = async () => {
|
||||
const fetchModifications = async (page: number) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const response = await fetch('/api/modifications');
|
||||
const response = await fetch(`/api/modifications?page=${page}&pageSize=${pageSize}`);
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch modifications');
|
||||
}
|
||||
const data = await response.json();
|
||||
setModifications(data);
|
||||
const data: PaginatedResponse = await response.json();
|
||||
setModifications(data.items);
|
||||
setTotalPages(data.totalPages);
|
||||
setTotalItems(data.totalItems);
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Unknown error occurred');
|
||||
} finally {
|
||||
|
@ -108,7 +123,8 @@ const History: React.FC = () => {
|
|||
No modifications found
|
||||
</p>
|
||||
) : (
|
||||
<div className="grid gap-4 md:grid-cols-1 lg:grid-cols-1">
|
||||
<>
|
||||
<div className="grid gap-4 md:grid-cols-1 lg:grid-cols-1 mb-6">
|
||||
{modifications.map((modification) => (
|
||||
<UndoCard
|
||||
key={modification.ID}
|
||||
|
@ -118,6 +134,41 @@ const History: React.FC = () => {
|
|||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className="flex items-center justify-between border-t border-gray-200 dark:border-gray-700 pt-4">
|
||||
<div className="flex items-center text-sm text-gray-500 dark:text-gray-400">
|
||||
<span>
|
||||
Showing {((currentPage - 1) * pageSize) + 1} to {Math.min(currentPage * pageSize, totalItems)} of {totalItems} results
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<button
|
||||
onClick={() => setCurrentPage(page => Math.max(1, page - 1))}
|
||||
disabled={currentPage === 1}
|
||||
className={`px-3 py-1 rounded-md ${
|
||||
currentPage === 1
|
||||
? 'bg-gray-100 text-gray-400 cursor-not-allowed dark:bg-gray-800'
|
||||
: 'bg-blue-500 text-white hover:bg-blue-600 dark:bg-blue-600 dark:hover:bg-blue-700'
|
||||
}`}
|
||||
>
|
||||
Previous
|
||||
</button>
|
||||
<span className="text-sm text-gray-600 dark:text-gray-300">
|
||||
Page {currentPage} of {totalPages}
|
||||
</span>
|
||||
<button
|
||||
onClick={() => setCurrentPage(page => Math.min(totalPages, page + 1))}
|
||||
disabled={currentPage === totalPages}
|
||||
className={`px-3 py-1 rounded-md ${
|
||||
currentPage === totalPages
|
||||
? 'bg-gray-100 text-gray-400 cursor-not-allowed dark:bg-gray-800'
|
||||
: 'bg-blue-500 text-white hover:bg-blue-600 dark:bg-blue-600 dark:hover:bg-blue-700'
|
||||
}`}
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
|
Loading…
Reference in a new issue