90 lines
2.7 KiB
Markdown
90 lines
2.7 KiB
Markdown
# Refresh Pools UX Improvement
|
|
|
|
## Issue
|
|
UI refresh update masih terlalu lama, sehingga user merasa command-nya gagal padahal sebenarnya tidak. User tidak mendapat feedback yang jelas bahwa proses sedang berjalan.
|
|
|
|
## Solution
|
|
Menambahkan loading state yang lebih jelas dan feedback visual yang lebih baik untuk memberikan indikasi bahwa proses refresh sedang berjalan.
|
|
|
|
## Changes Made
|
|
|
|
### 1. Added Loading State
|
|
**File**: `frontend/src/pages/Storage.tsx`
|
|
|
|
Menambahkan state untuk tracking manual refresh:
|
|
```typescript
|
|
const [isRefreshingPools, setIsRefreshingPools] = useState(false)
|
|
```
|
|
|
|
### 2. Improved Refresh Button
|
|
**File**: `frontend/src/pages/Storage.tsx` (line 446-465)
|
|
|
|
**Before:**
|
|
```typescript
|
|
<button
|
|
onClick={async () => {
|
|
await queryClient.invalidateQueries({ queryKey: ['storage', 'zfs', 'pools'] })
|
|
await queryClient.refetchQueries({ queryKey: ['storage', 'zfs', 'pools'] })
|
|
}}
|
|
disabled={poolsLoading}
|
|
...
|
|
>
|
|
```
|
|
|
|
**After:**
|
|
```typescript
|
|
<button
|
|
onClick={async () => {
|
|
setIsRefreshingPools(true)
|
|
try {
|
|
await queryClient.invalidateQueries({ queryKey: ['storage', 'zfs', 'pools'] })
|
|
await queryClient.refetchQueries({ queryKey: ['storage', 'zfs', 'pools'] })
|
|
// Small delay to show feedback
|
|
await new Promise(resolve => setTimeout(resolve, 300))
|
|
alert('Pools refreshed successfully!')
|
|
} catch (error) {
|
|
console.error('Failed to refresh pools:', error)
|
|
alert('Failed to refresh pools. Please try again.')
|
|
} finally {
|
|
setIsRefreshingPools(false)
|
|
}
|
|
}}
|
|
disabled={poolsLoading || isRefreshingPools}
|
|
className="... disabled:cursor-not-allowed"
|
|
...
|
|
>
|
|
<span className={`... ${(poolsLoading || isRefreshingPools) ? 'animate-spin' : ''}`}>
|
|
sync
|
|
</span>
|
|
{(poolsLoading || isRefreshingPools) ? 'Refreshing...' : 'Refresh Pools'}
|
|
</button>
|
|
```
|
|
|
|
## Improvements
|
|
|
|
### Visual Feedback
|
|
1. **Loading Spinner**: Icon `sync` berputar saat refresh
|
|
2. **Button Text**: Berubah menjadi "Refreshing..." saat loading
|
|
3. **Disabled State**: Button disabled dengan cursor `not-allowed` saat loading
|
|
4. **Success Alert**: Menampilkan alert setelah refresh selesai
|
|
5. **Error Handling**: Menampilkan alert jika refresh gagal
|
|
|
|
### User Experience
|
|
- User mendapat feedback visual yang jelas bahwa proses sedang berjalan
|
|
- User mendapat konfirmasi setelah refresh selesai
|
|
- User mendapat notifikasi jika terjadi error
|
|
- Button tidak bisa diklik berulang kali saat proses berjalan
|
|
|
|
## Testing
|
|
1. Klik "Refresh Pools"
|
|
2. Verify button menunjukkan loading state (spinner + "Refreshing...")
|
|
3. Verify button disabled saat loading
|
|
4. Verify success alert muncul setelah refresh selesai
|
|
5. Verify pools list ter-update
|
|
|
|
## Status
|
|
✅ **COMPLETED** - UX improvement untuk refresh pools button
|
|
|
|
## Date
|
|
2026-01-09
|