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
|
// Section for local-db actions
|
||||||
|
|
||||||
func (app *App) getModificationHistoryHandler(c *gin.Context) {
|
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 {
|
if err != nil {
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to retrieve modification history"})
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to retrieve modification history"})
|
||||||
log.Errorf("Failed to retrieve modification history: %v", err)
|
log.Errorf("Failed to retrieve modification history: %v", err)
|
||||||
return
|
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) {
|
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
|
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) {
|
func GetAllModifications(db *gorm.DB) ([]ModificationHistory, error) {
|
||||||
var records []ModificationHistory
|
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
|
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
|
// UndoModification marks a modification record as undone and sets the undo date
|
||||||
func SetModificationUndone(db *gorm.DB, record *ModificationHistory) error {
|
func SetModificationUndone(db *gorm.DB, record *ModificationHistory) error {
|
||||||
record.Undone = true
|
record.Undone = true
|
||||||
|
|
|
@ -12,11 +12,23 @@ interface ModificationHistory {
|
||||||
UndoneDate: string | null;
|
UndoneDate: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface PaginatedResponse {
|
||||||
|
items: ModificationHistory[];
|
||||||
|
totalItems: number;
|
||||||
|
totalPages: number;
|
||||||
|
currentPage: number;
|
||||||
|
pageSize: number;
|
||||||
|
}
|
||||||
|
|
||||||
const History: React.FC = () => {
|
const History: React.FC = () => {
|
||||||
const [modifications, setModifications] = useState<ModificationHistory[]>([]);
|
const [modifications, setModifications] = useState<ModificationHistory[]>([]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [paperlessUrl, setPaperlessUrl] = useState<string>('');
|
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
|
// Get Paperless URL
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -36,19 +48,22 @@ const History: React.FC = () => {
|
||||||
fetchUrl();
|
fetchUrl();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// Get all modifications
|
// Get modifications with pagination
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchModifications();
|
fetchModifications(currentPage);
|
||||||
}, []);
|
}, [currentPage]);
|
||||||
|
|
||||||
const fetchModifications = async () => {
|
const fetchModifications = async (page: number) => {
|
||||||
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
const response = await fetch('/api/modifications');
|
const response = await fetch(`/api/modifications?page=${page}&pageSize=${pageSize}`);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error('Failed to fetch modifications');
|
throw new Error('Failed to fetch modifications');
|
||||||
}
|
}
|
||||||
const data = await response.json();
|
const data: PaginatedResponse = await response.json();
|
||||||
setModifications(data);
|
setModifications(data.items);
|
||||||
|
setTotalPages(data.totalPages);
|
||||||
|
setTotalItems(data.totalItems);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setError(err instanceof Error ? err.message : 'Unknown error occurred');
|
setError(err instanceof Error ? err.message : 'Unknown error occurred');
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -108,19 +123,55 @@ const History: React.FC = () => {
|
||||||
No modifications found
|
No modifications found
|
||||||
</p>
|
</p>
|
||||||
) : (
|
) : (
|
||||||
<div className="grid gap-4 md:grid-cols-1 lg:grid-cols-1">
|
<>
|
||||||
{modifications.map((modification) => (
|
<div className="grid gap-4 md:grid-cols-1 lg:grid-cols-1 mb-6">
|
||||||
<UndoCard
|
{modifications.map((modification) => (
|
||||||
key={modification.ID}
|
<UndoCard
|
||||||
{...modification}
|
key={modification.ID}
|
||||||
onUndo={handleUndo}
|
{...modification}
|
||||||
paperlessUrl={paperlessUrl}
|
onUndo={handleUndo}
|
||||||
/>
|
paperlessUrl={paperlessUrl}
|
||||||
))}
|
/>
|
||||||
</div>
|
))}
|
||||||
|
</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>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default History;
|
export default History;
|
||||||
|
|
Loading…
Reference in a new issue