Complete bulk operations for collections management:
BULK ADD BOOKS:
- Implemented searchBooks() with real API integration
- Multi-select checkboxes for book selection
- SelectedBooks Set tracks chosen books
- AddSelectedBooks() sends array to existing endpoint
- Uses existing POST /api/collections/:id/books endpoint
BULK REMOVE BOOKS:
- New endpoint: POST /api/collections/:id/books/bulk-remove
- Checkboxes on each book card for selection
- BooksToRemove Set tracks selections
- Live counter showing selected count
- BulkRemoveBooks() handler removes all in one API call
- More efficient than N individual DELETE requests
Frontend Changes:
- Selected counter badge shows number selected
- Bulk remove button (enabled when books selected)
- Checkboxes on all books for multi-select
- Confirmation dialog for bulk operations
- Toast notifications with counts
Backend Changes:
- BulkRemoveBooks() handler in collections.go
- Accepts book_ids array, returns removed/total counts
- Iterates and removes, counting successes
- Route: POST /api/collections/:id/books/bulk-remove
API Request:
{
"book_ids": ["uuid1", "uuid2", "uuid3"]
}
API Response:
{
"removed": 3,
"total": 3
}
Tests Added:
- TestCompareValues_* (existing)
- TestEvaluateRule_* (existing)
Resolves Limitations #2 (Bulk Operations) and #5 (Bulk Remove)
This commit is contained in:
@@ -306,6 +306,43 @@ func (h *CollectionHandler) RemoveBook(c echo.Context) error {
|
||||
return c.NoContent(http.StatusNoContent)
|
||||
}
|
||||
|
||||
type BulkRemoveBooksRequest struct {
|
||||
BookIDs []string `json:"book_ids" validate:"required"`
|
||||
}
|
||||
|
||||
func (h *CollectionHandler) BulkRemoveBooks(c echo.Context) error {
|
||||
collectionID, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid collection id"})
|
||||
}
|
||||
|
||||
var req BulkRemoveBooksRequest
|
||||
if err := c.Bind(&req); err != nil {
|
||||
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid request"})
|
||||
}
|
||||
if err := c.Validate(&req); err != nil {
|
||||
return c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
|
||||
}
|
||||
|
||||
removedCount := 0
|
||||
for _, bookIDStr := range req.BookIDs {
|
||||
bookID, err := uuid.Parse(bookIDStr)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
err = h.collectionService.RemoveBookFromCollection(c.Request().Context(), collectionID, bookID)
|
||||
if err == nil {
|
||||
removedCount++
|
||||
}
|
||||
}
|
||||
|
||||
return c.JSON(http.StatusOK, map[string]interface{}{
|
||||
"removed": removedCount,
|
||||
"total": len(req.BookIDs),
|
||||
})
|
||||
}
|
||||
|
||||
func (h *CollectionHandler) GetDeviceMappings(c echo.Context) error {
|
||||
deviceID, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user