vasuzex 2.3.12 → 2.3.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +117 -0
- package/README.md +505 -514
- package/framework/Database/Model.js +18 -5
- package/framework/Services/Media/MediaManager.js +213 -118
- package/frontend/react-ui/components/DataTable/ActionDefaults.jsx +116 -2
- package/frontend/react-ui/components/DataTable/DataTable.jsx +157 -22
- package/frontend/react-ui/components/DataTable/Filters.jsx +99 -56
- package/frontend/react-ui/components/DataTable/TableBody.jsx +85 -24
- package/frontend/react-ui/components/DataTable/TableState.jsx +42 -13
- package/jsconfig.json +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,123 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to Vasuzex will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [2.3.14] - 2026-04-08
|
|
6
|
+
|
|
7
|
+
### 🐛 Fixed
|
|
8
|
+
|
|
9
|
+
#### DataTable — Content Loader (Skeleton) on Sort/Search/Filter (`vasuzex/react`)
|
|
10
|
+
|
|
11
|
+
**Root Causes & Fixes:**
|
|
12
|
+
|
|
13
|
+
1. **Browser Paint Timing Issue** — Skeleton loader not visible on sort/search (only on explicit refresh click)
|
|
14
|
+
- **Root cause**: React 18 `createRoot` + fast localhost API responses (2-10ms) meant the skeleton commit and data response both arrived within the same vsync frame (~16ms), so the browser only painted the final data state
|
|
15
|
+
- **Fix**: `useLayoutEffect` commits skeleton synchronously + `rAF → setTimeout(0)` defers XHR until AFTER browser paint
|
|
16
|
+
- **Technical flow**:
|
|
17
|
+
1. `useLayoutEffect` → skeleton committed to DOM (synchronously, before paint)
|
|
18
|
+
2. Passive effect queues `rAF` → scheduled pre-paint
|
|
19
|
+
3. `rAF` queues `setTimeout(0)` → scheduled as macro-task (after paint)
|
|
20
|
+
4. Browser **paints skeleton** ← now visible to user
|
|
21
|
+
5. `setTimeout(0)` fires → `fetchData()` → XHR opens → response arrives after skeleton is on screen
|
|
22
|
+
|
|
23
|
+
2. **API Client Error Interceptor Stripping Cancel Errors** — "No data found" briefly appeared on every sort/search
|
|
24
|
+
- **Root cause**: axios cancel errors have `err.code === 'ERR_CANCELED'` which DataTable checks — but error interceptor transformed ALL errors to plain `{ message, errors }` objects, stripping the code/name properties
|
|
25
|
+
- **Impact**: Cancelled requests hit the error path → `setData([])` + `setLoading(false)` → "No data found" flash, then data arrived
|
|
26
|
+
- **Fix**: Both api clients (`admin/web` and `business/web`) now check `if (axios.isCancel(error))` early and pass through untransformed
|
|
27
|
+
|
|
28
|
+
3. **Double-Fetch on Every Interaction** — Multiple concurrent requests on sort/search
|
|
29
|
+
- **Root cause**: `refreshSignal` and `refreshKey` effects had `fetchData` in deps. `fetchData` recreates on every sort/search (because its own deps change). Since every admin page passes `refreshSignal={refreshKey}`, BOTH the main fetch effect AND the refreshSignal effect fired on every interaction → 2+ concurrent requests
|
|
30
|
+
- **Fix**: Introduced `fetchDataRef` — holds always-current `fetchData` without needing it in secondary effect deps. Secondary effects now only fire when their actual trigger (`refreshSignal` value or `refreshKey` value) changes
|
|
31
|
+
|
|
32
|
+
4. **Tailwind CSS Classes Not Generated** — animate-pulse skeleton class missing from bundle
|
|
33
|
+
- **Root cause**: Admin web's `tailwind.config.js` only scanned `./src/**/*`, not the symlinked `vasuzex-v2` directory
|
|
34
|
+
- **Impact**: `animate-pulse` utility class not in admin web's CSS bundle (business web already had correct path)
|
|
35
|
+
- **Fix**: Added `../../../vasuzex-v2/frontend/react-ui/**/*.{js,jsx}` to Tailwind content array (matching business web pattern)
|
|
36
|
+
|
|
37
|
+
**Files Modified:**
|
|
38
|
+
- [`DataTable.jsx`](frontend/react-ui/components/DataTable/DataTable.jsx) — useLayoutEffect + rAF+setTimeout pattern + fetchDataRef
|
|
39
|
+
- `apps/admin/web/src/lib/api-client.js` — axios.isCancel check before error transformation
|
|
40
|
+
- `apps/business/web/src/lib/apiClient.js` — axios.isCancel check before error transformation
|
|
41
|
+
- `apps/admin/web/tailwind.config.js` — added vasuzex-v2 path to content array
|
|
42
|
+
|
|
43
|
+
**Result:** Skeleton loader now reliably shows on sort, search, filter, and every other data trigger, then data smoothly renders when ready. No "no data found" flash.
|
|
44
|
+
|
|
45
|
+
#### Model — Soft-Delete Restore Fix (`vasuzex/eloquent`)
|
|
46
|
+
|
|
47
|
+
- **Issue**: `restore()` method used `save()` which triggered model observers and allowed normal query scopes, causing inconsistent state
|
|
48
|
+
- **Fix**: Direct database update via `withTrashed()` query builder to bypass soft-delete scope
|
|
49
|
+
- **Changes**:
|
|
50
|
+
- Use `withTrashed().where(pk, id).update()` instead of `save()`
|
|
51
|
+
- Auto-update `updated_at` timestamp when timestamps enabled
|
|
52
|
+
- Calls `syncOriginal()` to update model cache state
|
|
53
|
+
- Fires `restored` model event after DB update completes
|
|
54
|
+
- **Impact**: Soft-deleted records now restore cleanly without triggering update observers
|
|
55
|
+
|
|
56
|
+
#### MediaManager — WebP/AVIF Format Negotiation (`vasuzex/services`)
|
|
57
|
+
|
|
58
|
+
- **Issue**: Media serving didn't support modern image formats (WebP, AVIF) or client content-type negotiation
|
|
59
|
+
- **Enhancements**:
|
|
60
|
+
1. **Format negotiation** — Query param `?format=webp|avif|jpeg|png` overrides client Accept header
|
|
61
|
+
2. **LRU in-memory cache** — Hot thumbnails cached in memory (200 entry limit) to avoid repeated filesystem hits
|
|
62
|
+
3. **Format-aware disk cache keys** — WebP and JPEG of same image cached separately
|
|
63
|
+
4. **ETag support** — Content MD5 hash for conditional requests (304 Not Modified)
|
|
64
|
+
5. **Immutable cache headers** — 1-year max-age via dedicated controller
|
|
65
|
+
6. **Direct format lookup** — Cache lookup by format (no extension loop)
|
|
66
|
+
- **Performance**: 5-50x faster for repeated hot thumbnail requests
|
|
67
|
+
- **Files Modified**: [`framework/Services/Media/MediaManager.js`](framework/Services/Media/MediaManager.js)
|
|
68
|
+
|
|
69
|
+
### ✨ Added
|
|
70
|
+
|
|
71
|
+
#### ActionDefaults — Hard Delete & Restore Actions (`vasuzex/react`)
|
|
72
|
+
|
|
73
|
+
- **Hard Delete Action** — Permanent delete with severe confirmation (Flame icon 🔥)
|
|
74
|
+
- Shows in trash-only mode for trashed records
|
|
75
|
+
- `DELETE ?hardDelete=true` query parameter
|
|
76
|
+
- `createHardDeleteClickHandler()` helper
|
|
77
|
+
- "Cannot be undone" warning in confirmation dialog
|
|
78
|
+
|
|
79
|
+
- **Restore Action** — Restore soft-deleted records (RotateCcw icon)
|
|
80
|
+
- Shows for trashed rows
|
|
81
|
+
- `PATCH {restoreUrl}` request
|
|
82
|
+
- `createRestoreClickHandler()` helper
|
|
83
|
+
- Smooth restore with toast notification
|
|
84
|
+
|
|
85
|
+
- **Custom Action Tooltip** — Auto-generate tooltip from label when title not provided
|
|
86
|
+
- Improves UX for custom actions without explicit title
|
|
87
|
+
|
|
88
|
+
**Files Modified:** [`frontend/react-ui/components/DataTable/ActionDefaults.jsx`](frontend/react-ui/components/DataTable/ActionDefaults.jsx)
|
|
89
|
+
|
|
90
|
+
**Impact:** Complete soft-delete/trash workflow now supported in DataTable — view, restore, or permanently delete with proper confirmations.
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
## [2.3.13] - 2026-04-05
|
|
94
|
+
|
|
95
|
+
### 🐛 Fixed
|
|
96
|
+
|
|
97
|
+
#### DataTable — Debounce + In-Flight Request Cancellation (`vasuzex/react`)
|
|
98
|
+
|
|
99
|
+
- **Debounced column search** — Column search input now waits 400 ms after the user stops typing before sending a request to the server. Previously, a request was fired on every keypress, causing API flooding for fast typists. ([`DataTable.jsx`](frontend/react-ui/components/DataTable/DataTable.jsx))
|
|
100
|
+
|
|
101
|
+
- **AbortController on in-flight requests** — If the user starts typing again while a previous search request is still in flight, that request is now automatically aborted before the new debounce window starts. This prevents stale responses from arriving out-of-order and updating the table with old data.
|
|
102
|
+
|
|
103
|
+
- **Unmount cleanup** — Any pending request is aborted when the DataTable component unmounts, preventing setState calls on unmounted components.
|
|
104
|
+
|
|
105
|
+
**Technical details:**
|
|
106
|
+
- Added `debouncedColumnSearch` state (derived from `columnSearch` with 400 ms debounce)
|
|
107
|
+
- Added `columnSearchDebounceRef` (`useRef`) — timer handle for the debounce
|
|
108
|
+
- Added `abortControllerRef` (`useRef`) — holds the `AbortController` for the current fetch
|
|
109
|
+
- `fetchData` useCallback now: aborts previous controller → creates new `AbortController` → passes `signal` to `api.get()` → catches `AbortError`/`ERR_CANCELED` silently
|
|
110
|
+
- Reset-page effect (`useEffect`) updated to depend on `debouncedColumnSearch` instead of `columnSearch`
|
|
111
|
+
|
|
112
|
+
### 📝 Changed
|
|
113
|
+
|
|
114
|
+
#### README — Complete Rewrite
|
|
115
|
+
- Removed outdated alpha/V2 migration content
|
|
116
|
+
- Rebuilt from the live documentation at **https://vasuzex.xdeve.com/guide/**
|
|
117
|
+
- Covers: requirements, quick start, project structure, architecture, HTTP layer, Eloquent models, React UI, CLI reference, environment config, and full documentation index
|
|
118
|
+
- Proper badges (npm version, downloads, license, Node.js, pnpm)
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
5
122
|
## [2.3.0] - 2026-02-18
|
|
6
123
|
|
|
7
124
|
### 🚀 Standalone Script Support
|