mirror of
https://github.com/Noooste/garage-ui.git
synced 2026-08-19 17:26:17 +00:00
5d33382e30
* feat(backend,frontend): recursive delete of key prefixes in bulk actions
Bulk object selection previously only supported deleting individually
listed object keys — folders ("prefixes") could not be selected or
deleted, leaving no way to remove a directory and all of its contents.
Backend:
- Add S3Service.DeleteObjectsByPrefix, which recursively lists every
object under a prefix and batch-deletes them, returning the count.
- Extend the delete-multiple endpoint to accept a "prefixes" array
alongside "keys"; keys are batch-deleted and each prefix is deleted
recursively. Response now reports the total objects removed.
Frontend:
- Enable folder checkboxes and add a per-folder "Delete folder" action.
- Select-all now covers both files and folders.
- Route all bulk/folder deletes through a confirmation dialog that
spells out the file/folder counts and warns that folders are removed
recursively (previously bulk delete fired with no confirmation).
- api/hook send "prefixes"; optimistic update drops objects under any
deleted prefix.
* fix(backend): validate delete prefixes and count actual removals
Addresses maintainer review on the recursive prefix-delete endpoint:
- Reject blank/whitespace-only prefixes with a 400 instead of a 500, and
normalize each prefix to have a trailing "/" so "photos/2024" can no
longer also delete siblings like "photos/2024-old/..." on this
irreversible public endpoint.
- DeleteMultipleObjects now returns the number of objects actually
removed (requested keys minus failures) rather than assuming every
requested key was deleted; the handler sums real counts across the
keys and prefix paths. Draining the full RemoveObjects error channel
also fixes a potential sender-goroutine leak on early return.
- Add tests: blank-prefix -> 400, prefix trailing-slash normalization,
and S3Service.DeleteObjectsByPrefix (list-then-delete, empty prefix,
no-match, and list-error propagation).
* fix(frontend): align select-all with the active search filter
The header "select all" checkbox derived its checked state from the
filtered (searched) rows, but handleSelectAll operated on the full,
unfiltered object list — so with a search active it selected hidden
items and the checkbox state disagreed with the selection.
ObjectsTable now passes the keys of the currently visible (filtered)
rows to onSelectAll, and its checked state reflects whether every
visible row is selected. handleSelectAll toggles only those visible
rows, leaving any off-screen selection intact.
* fix(frontend): scope select-all to the visible page
After merging upstream's client-side deep-search pagination, the rendered
rows are pageObjects (one page slice) while select-all still operated on
filteredObjects (every match across hidden pages). Scope the header
checkbox's state and its select-all action to pageObjects so one click
never selects off-screen rows for a destructive bulk delete. In
normal/prefix browsing pageObjects === filteredObjects, so behavior there
is unchanged.
---------
Authored-by: Camilo Hollanda <775409+prem-prakash@users.noreply.github.com>
Garage UI - Frontend
Modern React frontend for Garage S3-compatible object storage management.
Features
- Dashboard - Overview of storage metrics and recent activity
- Bucket Management - Create, view, and manage S3 buckets
- Object Browser - Navigate folders, upload/download files with drag-and-drop
- Access Control - Manage API keys and permissions
- Dark/Light Mode - System-aware theme with manual toggle
- Data-Dense UI - Optimized for power users with comprehensive tables
Tech Stack
- Framework: React 19 + TypeScript
- Build Tool: Vite 7
- Routing: React Router v6
- State Management: Zustand
- UI Components: shadcn/ui (built on Radix UI primitives)
- Styling: Tailwind CSS v4
- Forms: React Hook Form + Zod
- Tables: TanStack Table
- File Upload: React Dropzone
- Icons: Lucide React
Getting Started
Prerequisites
- Node.js 18+ and npm
Installation
- Install dependencies:
npm install
- Create environment file:
cp .env.example .env
- Update
.envwith your backend API URL:
VITE_API_URL=http://localhost:8080/api
Development
Start the development server:
npm run dev
The app will be available at http://localhost:3000
Building for Production
Build the application:
npm run build
Preview the production build:
npm run preview
Project Structure
src/
├── components/
│ ├── ui/ # shadcn/ui base components
│ ├── layout/ # Layout components (Sidebar, Header)
│ ├── buckets/ # Bucket-specific components
│ ├── objects/ # Object browser components
│ └── access/ # Access control components
├── pages/ # Page components
│ ├── Dashboard.tsx
│ ├── Buckets.tsx
│ ├── Objects.tsx
│ └── AccessControl.tsx
├── lib/
│ ├── api.ts # API client with mock data
│ └── utils.ts # Utility functions
├── hooks/ # Custom React hooks
├── types/ # TypeScript type definitions
└── stores/ # Zustand stores
API Integration
The app is currently using mock data. To connect to your Go backend:
- Ensure your backend is running on
http://localhost:8080 - In
src/lib/api.ts, uncomment the real API calls - Comment out or remove the mock data returns
Example:
// Before (mock data)
list: async (): Promise<Bucket[]> => {
return mockBuckets;
},
// After (real API)
list: async (): Promise<Bucket[]> => {
const response = await api.get('/buckets');
return response.data;
},
Features by Page
Dashboard
- Storage metrics overview
- Bucket count and object statistics
- Storage distribution visualization
- Recent buckets list
Buckets
- List all buckets with search
- Create new buckets
- View bucket details
- Delete buckets
- Region information
Objects
- Browse objects and folders
- Breadcrumb navigation
- Drag-and-drop file upload
- Multiple file selection
- Download objects
- Delete objects
- Object metadata
Access Control
- API key management
- Create keys with permissions
- Activate/deactivate keys
- Copy access key IDs
- Permission configuration
Theme Customization
The app uses CSS variables for theming. Customize colors in src/index.css:
:root {
--primary: 240 5.9% 10%;
--secondary: 240 4.8% 95.9%;
/* ... more variables */
}
Contributing
This is a custom frontend for Garage storage. Feel free to extend with additional features:
- Analytics dashboards
- Versioning management
- Lifecycle policies UI
- Replication configuration
- Metrics visualization
License
MIT