qdadm 0.13.0

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.
Files changed (82) hide show
  1. package/CHANGELOG.md +270 -0
  2. package/LICENSE +21 -0
  3. package/README.md +166 -0
  4. package/package.json +48 -0
  5. package/src/assets/logo.svg +6 -0
  6. package/src/components/BoolCell.vue +28 -0
  7. package/src/components/dialogs/BulkStatusDialog.vue +43 -0
  8. package/src/components/dialogs/MultiStepDialog.vue +321 -0
  9. package/src/components/dialogs/SimpleDialog.vue +108 -0
  10. package/src/components/dialogs/UnsavedChangesDialog.vue +87 -0
  11. package/src/components/display/CardsGrid.vue +155 -0
  12. package/src/components/display/CopyableId.vue +92 -0
  13. package/src/components/display/EmptyState.vue +114 -0
  14. package/src/components/display/IntensityBar.vue +171 -0
  15. package/src/components/display/RichCardsGrid.vue +220 -0
  16. package/src/components/editors/JsonEditorFoldable.vue +467 -0
  17. package/src/components/editors/JsonStructuredField.vue +218 -0
  18. package/src/components/editors/JsonViewer.vue +91 -0
  19. package/src/components/editors/KeyValueEditor.vue +314 -0
  20. package/src/components/editors/LanguageEditor.vue +245 -0
  21. package/src/components/editors/ScopeEditor.vue +341 -0
  22. package/src/components/editors/VanillaJsonEditor.vue +185 -0
  23. package/src/components/forms/FormActions.vue +104 -0
  24. package/src/components/forms/FormField.vue +64 -0
  25. package/src/components/forms/FormTab.vue +217 -0
  26. package/src/components/forms/FormTabs.vue +108 -0
  27. package/src/components/index.js +44 -0
  28. package/src/components/layout/AppLayout.vue +430 -0
  29. package/src/components/layout/Breadcrumb.vue +106 -0
  30. package/src/components/layout/PageHeader.vue +75 -0
  31. package/src/components/layout/PageLayout.vue +93 -0
  32. package/src/components/lists/ActionButtons.vue +41 -0
  33. package/src/components/lists/ActionColumn.vue +37 -0
  34. package/src/components/lists/FilterBar.vue +53 -0
  35. package/src/components/lists/ListPage.vue +319 -0
  36. package/src/composables/index.js +19 -0
  37. package/src/composables/useApp.js +43 -0
  38. package/src/composables/useAuth.js +49 -0
  39. package/src/composables/useBareForm.js +143 -0
  40. package/src/composables/useBreadcrumb.js +221 -0
  41. package/src/composables/useDirtyState.js +103 -0
  42. package/src/composables/useEntityTitle.js +121 -0
  43. package/src/composables/useForm.js +254 -0
  44. package/src/composables/useGuardStore.js +37 -0
  45. package/src/composables/useJsonSyntax.js +101 -0
  46. package/src/composables/useListPageBuilder.js +1176 -0
  47. package/src/composables/useNavigation.js +89 -0
  48. package/src/composables/usePageBuilder.js +334 -0
  49. package/src/composables/useStatus.js +146 -0
  50. package/src/composables/useSubEditor.js +165 -0
  51. package/src/composables/useTabSync.js +110 -0
  52. package/src/composables/useUnsavedChangesGuard.js +122 -0
  53. package/src/entity/EntityManager.js +540 -0
  54. package/src/entity/index.js +11 -0
  55. package/src/entity/storage/ApiStorage.js +146 -0
  56. package/src/entity/storage/LocalStorage.js +220 -0
  57. package/src/entity/storage/MemoryStorage.js +201 -0
  58. package/src/entity/storage/index.js +10 -0
  59. package/src/index.js +29 -0
  60. package/src/kernel/Kernel.js +234 -0
  61. package/src/kernel/index.js +7 -0
  62. package/src/module/index.js +16 -0
  63. package/src/module/moduleRegistry.js +222 -0
  64. package/src/orchestrator/Orchestrator.js +141 -0
  65. package/src/orchestrator/index.js +8 -0
  66. package/src/orchestrator/useOrchestrator.js +61 -0
  67. package/src/plugin.js +142 -0
  68. package/src/styles/_alerts.css +48 -0
  69. package/src/styles/_code.css +33 -0
  70. package/src/styles/_dialogs.css +17 -0
  71. package/src/styles/_markdown.css +82 -0
  72. package/src/styles/_show-pages.css +84 -0
  73. package/src/styles/index.css +16 -0
  74. package/src/styles/main.css +845 -0
  75. package/src/styles/theme/components.css +286 -0
  76. package/src/styles/theme/index.css +10 -0
  77. package/src/styles/theme/tokens.css +125 -0
  78. package/src/styles/theme/utilities.css +172 -0
  79. package/src/utils/debugInjector.js +261 -0
  80. package/src/utils/formatters.js +165 -0
  81. package/src/utils/index.js +35 -0
  82. package/src/utils/transformers.js +105 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,270 @@
1
+ # Changelog
2
+
3
+ All notable changes to qdadm will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/).
7
+
8
+ ## [0.13.0] - 2025-12-21
9
+
10
+ ### Added
11
+ - `EntityManager.getMany(ids)`: Batch fetch multiple entities by IDs
12
+ - Delegates to `storage.getMany(ids)` if available
13
+ - Falls back to parallel `get()` calls
14
+ - `EntityManager.canCreate()`: Permission check for creating entities
15
+ - `EntityManager.canUpdate(entity?)`: Permission check for updating entities
16
+ - `EntityManager.children`: Config for parent-child entity relationships
17
+ - `BoolCell` component: Standardized tristate boolean display
18
+ - `true` → green check (`--p-green-500`)
19
+ - `false` → red cross (`--p-red-500`)
20
+ - `null/undefined` → empty
21
+ - `LocalStorage.getMany(ids)`: Optimized batch fetch for localStorage adapter
22
+
23
+ ### Changed
24
+ - **BREAKING**: Removed `canWrite()` - use `canCreate()` / `canUpdate()` instead
25
+ - `addCreateAction()`: Uses `manager.canCreate()` for visibility
26
+ - `addEditAction()`: Uses `manager.canUpdate(row)` for visibility
27
+
28
+ ### Demo
29
+ - `read` field moved from `books` to `loans` entity
30
+ - `BookForm`: Tabs in edit mode showing child entities (Loans)
31
+ - `LoanList`: Bulk actions "Mark Read" / "Mark Unread"
32
+ - `LoanForm`: Toggle for `read` field
33
+ - Permission examples updated to use `canCreate()` / `canUpdate()`
34
+
35
+ ## [0.12.0] - 2025-12-21
36
+
37
+ ### Added
38
+ - `useListPageBuilder.addFilter({ local_filter })`: Custom filter callback for local mode
39
+ - Specifies HOW to filter when in local mode (items < threshold)
40
+ - Example: `local_filter: (item, value) => value === 'active' ? !item.returned_at : true`
41
+ - Filters with `local_filter` are **not sent to manager** (virtual fields)
42
+ - `local_filter: false` = manager only, skip in local mode
43
+ - `useListPageBuilder.setSearch({ local_search })`: Custom search callback for local mode
44
+ - Specifies HOW to search when in local mode
45
+ - Example: `local_search: (item, query) => booksMap[item.book_id]?.title.includes(query)`
46
+ - `local_search: false` = manager only, skip in local mode
47
+ - `EntityManager.localFilterThreshold`: Per-entity threshold for auto local filtering
48
+ - Priority: config `autoFilterThreshold` > `manager.localFilterThreshold` > default (100)
49
+
50
+ ### Changed
51
+ - **BREAKING**: Renamed `filterMode: 'api'` → `filterMode: 'manager'` (clearer intent)
52
+ - **Demo**: `LoanList` uses `local_filter` for virtual `status` filter
53
+ - **Demo**: `LoanList` uses `local_search` for book title lookup
54
+
55
+ ### Documentation
56
+ - **The threshold decides everything**:
57
+ - `items >= threshold` → **manager mode**: delegate ALL filtering to EntityManager
58
+ - `items < threshold` → **local mode**: filter client-side
59
+ - **Modes**:
60
+ - `filterMode: 'manager'`: Always delegate to EntityManager
61
+ - `filterMode: 'local'`: Always filter client-side
62
+ - `filterMode: 'auto'` (default): Switch based on threshold
63
+ - **Behavior Matrix**:
64
+ | Type | Mode `manager` | Mode `local` |
65
+ |-----------------------------|-----------------|-----------------------------|
66
+ | Filter standard | Manager handles | `item[field] === value` |
67
+ | Filter + `local_filter` | Manager handles | `local_filter(item, value)` |
68
+ | Filter + `local_filter:false` | Manager handles | (skipped) |
69
+ | Search standard | Manager handles | `field.includes(query)` |
70
+ | Search + `local_search` | Manager handles | `local_search(item, query)` |
71
+ | Search + `local_search:false` | Manager handles | (skipped) |
72
+ - **Threshold Priority**: config > `manager.localFilterThreshold` > 100
73
+
74
+ ## [0.11.0] - 2025-12-20
75
+
76
+ ### Added
77
+ - **Demo**: Permission-aware form fields pattern
78
+ - `LoanForm`: Non-admin users get `user_id` auto-set and field locked
79
+ - `LoansManager.create()`: Enforces `user_id` server-side for non-admin
80
+ - **Demo**: Detailed comments on `useForm` return values (`loading`, `saving`, `dirty`, `isEdit`)
81
+
82
+ ### Changed
83
+ - **Demo**: Simplified `onMounted` pattern replaces `watch` for form field initialization
84
+
85
+ ## [0.10.0] - 2025-12-20
86
+
87
+ ### Added
88
+ - **Demo**: Complete permission patterns with documented examples
89
+ - `UsersManager`: Admin-only access (canRead/canWrite)
90
+ - `BooksManager`: Everyone edits, admin-only delete (canDelete)
91
+ - `LoansManager`: Ownership-based filtering (list override + row-level permissions)
92
+ - **Demo**: Detailed JSDoc comments explaining all qdadm patterns
93
+ - **Demo**: Fixture seeding system with JSON files
94
+
95
+ ### Changed
96
+ - **Demo**: Login page shows all available demo accounts with role explanations
97
+
98
+ ## [0.9.0] - 2025-12-20
99
+
100
+ ### Added
101
+ - `useListPageBuilder.props`: Computed object with all ListPage props - use with `v-bind="list.props.value"`
102
+ - `useListPageBuilder.events`: Event handlers object - use with `v-on="list.events"`
103
+ - `useListPageBuilder.hasBulkActions`: Auto-detects if bulk actions are available
104
+ - Auto-selectable: Checkboxes shown only when bulk actions exist (no manual `selectable` prop needed)
105
+
106
+ ### Changed
107
+ - ListPage template simplified from ~20 props/events to just `v-bind` + `v-on`
108
+
109
+ ## [0.8.0] - 2025-12-20
110
+
111
+ ### Added
112
+ - `EntityManager.canDelete(entity?)`: Fine-grained delete permission check
113
+ - `useListPageBuilder`: Standard actions now respect permissions:
114
+ - `addCreateAction()`: Hidden if `manager.canCreate()` returns false
115
+ - `addEditAction()`: Hidden per row if `manager.canUpdate(row)` returns false
116
+ - `addDeleteAction()`: Hidden per row if `manager.canDelete(row)` returns false
117
+ - `addBulkDeleteAction()`: Hidden if `manager.canDelete()` returns false
118
+
119
+ ## [0.7.0] - 2025-12-20
120
+
121
+ ### Added
122
+ - `Kernel`: All-in-one bootstrap class - handles Vue app, Pinia, PrimeVue, router, auth guard, and qdadm
123
+ - Constructor is declarative (stores config only)
124
+ - `createApp()` does all initialization, returns Vue app for mount
125
+ - Allows tweaking `kernel.options` before `createApp()`, or adding plugins/directives before `mount()`
126
+ ```js
127
+ const kernel = new Kernel({
128
+ root: App,
129
+ modules: import.meta.glob('./modules/*/init.js', { eager: true }),
130
+ managers, authAdapter,
131
+ pages: { login, layout },
132
+ homeRoute: 'book',
133
+ app: { name: 'My App' },
134
+ primevue: { plugin: PrimeVue, theme: Aura }
135
+ })
136
+ kernel.createApp().mount('#app')
137
+ ```
138
+ - `kernel.getRouter()`, `kernel.getApp()`, `kernel.getOrchestrator()` - access internals
139
+
140
+ ## [0.6.0] - 2025-12-20
141
+
142
+ ### Added
143
+ - `registry.addRoutes(prefix, routes, { entity })`: Route-level entity binding for permission checks
144
+ - `registry.addNavItem({ entity })`: Nav item entity binding for permission checks
145
+ - **Auto Route Guard**: Plugin adds `beforeEach` guard that redirects to `/` if `manager.canRead()` returns false
146
+ - **Auto Nav Filtering**: `useNavigation` filters items and hides empty sections based on `manager.canRead()`
147
+
148
+ ## [0.5.0] - 2025-12-20
149
+
150
+ ### Added
151
+ - `useGuardStore`: Shared reactive store for automatic UnsavedChangesDialog rendering
152
+ - `AppLayout`: Automatically renders UnsavedChangesDialog when a form is active (no code needed in forms)
153
+ - `EntityManager.canRead(entity?)`: Permission check for reading (general or specific entity)
154
+ - `EntityManager.canWrite(entity?)`: Permission check for writing (general or specific entity)
155
+
156
+ ### Changed
157
+ - `useBareForm`: Uses `registerGuardDialog`/`unregisterGuardDialog` from store instead of provide/inject
158
+ - `UnsavedChangesDialog`: Refactored to use `SimpleDialog` internally
159
+ - `PageLayout`: Removed `guardDialog` prop (dialog is now automatic via AppLayout)
160
+
161
+ ### Removed
162
+ - `features.scopes`: Removed from plugin config - permission logic belongs in EntityManager
163
+ - `useAuth.hasScope()`: Replaced by `EntityManager.canRead()`/`canWrite()` pattern
164
+
165
+ ### Fixed
166
+ - `useDirtyState`: Fixed timing issue where `takeSnapshot()` used `nextTick()` causing navigation to be blocked after save
167
+
168
+ ## [0.4.0] - 2025-12-20
169
+
170
+ ### Added
171
+ - `EntityManager.getEntityLabel(entity)`: Method to get display label, handles both string field and callback
172
+ - `EntityManager.labelField`: Can now be a string (field name) or callback function `(entity) => string`
173
+ - `PageLayout`: `manager` prop - derives labelField automatically from EntityManager
174
+
175
+ ### Changed
176
+ - `PageLayout`: Uses `manager.getEntityLabel()` instead of manual field access
177
+ - `useBreadcrumb`: Shows entity label in breadcrumb (replaces ID segment), keeps action labels (Edit/Create/View)
178
+
179
+ ## [0.3.1] - 2025-12-20
180
+
181
+ ### Added
182
+ - `AppLayout`: "powered by qdadm" footer with version display
183
+ - `assets/logo.svg`: Hexagon logo with "QD" in two-tone blue
184
+ - `features.poweredBy`: Option to hide "powered by" footer (default: true)
185
+
186
+ ### Fixed
187
+ - `AppLayout`: Vue Flow and full-height components now render correctly (flex layout)
188
+ - `AppLayout`: Use `<RouterView />` fallback when no slot content provided
189
+
190
+ ### Changed
191
+ - `AppLayout`: Sidebar width uses CSS variable `var(--fad-sidebar-width, 15rem)` instead of hardcoded `250px`
192
+ - `tokens.css`: Layout tokens now use `rem` units (`--fad-sidebar-width`, `--fad-header-height`, `--fad-content-max-width`)
193
+ - `main.css`: Removed ~130 lines of duplicated styles (sidebar, nav, login, user-info) - now only in AppLayout scoped CSS
194
+
195
+ ## [0.3.0] - 2025-12-20
196
+
197
+ ### Added
198
+ - `AppLayout` component with auto-nav from module registry
199
+ - `useNavigation` composable for navigation state management
200
+ - `useStatus` composable for generic status/option loading
201
+ - `setSectionOrder()` to configure navigation section order
202
+ - `initModules()` accepts external module imports and core nav items
203
+
204
+ ### Changed
205
+ - Module registry is now fully configurable (no hardcoded imports)
206
+ - Navigation auto-builds from module declarations (registry.addNavItem)
207
+ - Branding comes from bootstrap config (createQdadm app option)
208
+ - Dashboard now uses qdadm AppLayout instead of local implementation
209
+
210
+ ### Removed
211
+ - Hardcoded import.meta.glob in moduleRegistry
212
+ - Hardcoded sectionOrder in moduleRegistry
213
+
214
+ ## [0.2.0] - 2025-12-20
215
+
216
+ ### Added
217
+ - README.md with quick start guide
218
+ - TODO.md for planned features
219
+ - docs/FRAMEWORK.md moved from dashboard
220
+
221
+ ### Changed
222
+ - Successfully integrated with Faketual dashboard
223
+ - All 60+ dashboard modules migrated to use qdadm imports
224
+ - Validated build and runtime functionality
225
+
226
+ ### Fixed
227
+ - Component import paths (PageHeader, CardsGrid, ListPage)
228
+ - useJsonSyntax import paths in editor components
229
+ - Theme CSS import path in styles/index.css
230
+
231
+ ## [0.1.0] - 2025-12-20
232
+
233
+ ### Added
234
+ - Initial extraction from Faketual dashboard
235
+ - `createQdadm` plugin for Vue 3 bootstrap
236
+ - **Adapters**:
237
+ - `ApiAdapter` interface for CRUD operations
238
+ - `AuthAdapter` interface for authentication (optional)
239
+ - **Composables**:
240
+ - `useForm` - Form state management with validation
241
+ - `useListPageBuilder` - Paginated list with filters and actions
242
+ - `useBareForm` - Minimal form without routing
243
+ - `useBreadcrumb` - Breadcrumb builder
244
+ - `useDirtyState` - Track unsaved changes
245
+ - `useEntityTitle` - Dynamic page titles
246
+ - `useJsonSyntax` - JSON validation helpers
247
+ - `usePageBuilder` - Generic page builder
248
+ - `useSubEditor` - Sub-component for complex forms
249
+ - `useTabSync` - Sync tabs with URL
250
+ - `useUnsavedChangesGuard` - Block navigation if dirty
251
+ - `useAuth` - Authentication access
252
+ - `useApp` - App branding access
253
+ - **Components**:
254
+ - Layout: `PageLayout`, `PageHeader`, `Breadcrumb`
255
+ - Forms: `FormField`, `FormActions`, `FormTabs`, `FormTab`
256
+ - Lists: `ListPage`, `ActionButtons`, `ActionColumn`, `FilterBar`
257
+ - Editors: `KeyValueEditor`, `LanguageEditor`, `ScopeEditor`, `VanillaJsonEditor`, `JsonEditorFoldable`, `JsonStructuredField`, `JsonViewer`
258
+ - Dialogs: `SimpleDialog`, `MultiStepDialog`, `BulkStatusDialog`, `UnsavedChangesDialog`
259
+ - Display: `CardsGrid`, `RichCardsGrid`, `CopyableId`, `EmptyState`, `IntensityBar`
260
+ - Auth: `LoginPage`, `AuthGuard`, `ScopeGuard`
261
+ - **Module System**:
262
+ - `moduleRegistry` for auto-discovery of modules
263
+ - Route registration with path prefix
264
+ - Navigation item registration
265
+ - Route family for active state detection
266
+ - **Configuration**:
267
+ - `app` config for branding (name, logo, version, theme)
268
+ - `features` toggles (auth, scopes)
269
+ - `builtinModules` for users/roles
270
+ - `endpoints` configuration
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 quazardous
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,166 @@
1
+ # qdadm
2
+
3
+ Vue 3 framework for building admin dashboards with PrimeVue.
4
+
5
+ ## Features
6
+
7
+ - **Kernel**: All-in-one bootstrap (Vue app, router, Pinia, PrimeVue, auth guard)
8
+ - **EntityManager**: CRUD operations with permission control (`canRead`/`canCreate`/`canUpdate`/`canDelete`)
9
+ - **Module System**: Auto-discovery of modules with routes and navigation
10
+ - **Components**: Forms, lists, dialogs, editors ready to use
11
+ - **Composables**: `useForm`, `useListPageBuilder`, `useBareForm`, etc.
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ npm install qdadm
17
+ ```
18
+
19
+ ## Quick Start with Kernel
20
+
21
+ ```js
22
+ import { Kernel, EntityManager, LocalStorage } from 'qdadm'
23
+ import PrimeVue from 'primevue/config'
24
+ import Aura from '@primeuix/themes/aura'
25
+ import 'qdadm/styles'
26
+
27
+ import App from './App.vue'
28
+ import { authAdapter } from './adapters/authAdapter'
29
+
30
+ const managers = {
31
+ books: new EntityManager({
32
+ name: 'books',
33
+ storage: new LocalStorage({ key: 'my_books' }),
34
+ fields: {
35
+ title: { type: 'text', label: 'Title', required: true },
36
+ author: { type: 'text', label: 'Author' }
37
+ }
38
+ })
39
+ }
40
+
41
+ const kernel = new Kernel({
42
+ root: App,
43
+ modules: import.meta.glob('./modules/*/init.js', { eager: true }),
44
+ sectionOrder: ['Library'],
45
+ managers,
46
+ authAdapter,
47
+ pages: {
48
+ login: () => import('./pages/LoginPage.vue'),
49
+ layout: () => import('./pages/MainLayout.vue')
50
+ },
51
+ homeRoute: 'book',
52
+ app: { name: 'My App', version: '1.0.0' },
53
+ primevue: { plugin: PrimeVue, theme: Aura }
54
+ })
55
+
56
+ kernel.createApp().mount('#app')
57
+ ```
58
+
59
+ ## Manual Bootstrap (without Kernel)
60
+
61
+ ```js
62
+ import { createQdadm, initModules, getRoutes } from 'qdadm'
63
+
64
+ // Init modules
65
+ initModules(import.meta.glob('./modules/*/init.js', { eager: true }))
66
+
67
+ // Create router with getRoutes()
68
+ const router = createRouter({
69
+ history: createWebHistory(),
70
+ routes: [
71
+ { path: '/login', component: LoginPage },
72
+ { path: '/', component: Layout, children: getRoutes() }
73
+ ]
74
+ })
75
+
76
+ // Install plugin
77
+ app.use(createQdadm({ managers, authAdapter, router, toast }))
78
+ ```
79
+
80
+ ## Module Structure
81
+
82
+ ```
83
+ modules/
84
+ └── books/
85
+ ├── init.js # Route & nav registration
86
+ └── pages/
87
+ ├── BookList.vue
88
+ └── BookForm.vue
89
+ ```
90
+
91
+ **init.js:**
92
+ ```js
93
+ export function init(registry) {
94
+ registry.addRoutes('books', [
95
+ { path: '', name: 'book', component: () => import('./pages/BookList.vue') },
96
+ { path: 'create', name: 'book-create', component: () => import('./pages/BookForm.vue') },
97
+ { path: ':id/edit', name: 'book-edit', component: () => import('./pages/BookForm.vue') }
98
+ ], { entity: 'books' })
99
+
100
+ registry.addNavItem({
101
+ section: 'Library',
102
+ route: 'book',
103
+ icon: 'pi pi-book',
104
+ label: 'Books',
105
+ entity: 'books'
106
+ })
107
+
108
+ registry.addRouteFamily('book', ['book-'])
109
+ }
110
+ ```
111
+
112
+ ## EntityManager Permissions
113
+
114
+ ```js
115
+ class UsersManager extends EntityManager {
116
+ canRead() {
117
+ return authAdapter.getUser()?.role === 'admin'
118
+ }
119
+ canCreate() {
120
+ return authAdapter.getUser()?.role === 'admin'
121
+ }
122
+ canUpdate(entity) {
123
+ return authAdapter.getUser()?.role === 'admin'
124
+ }
125
+ canDelete(entity) {
126
+ return authAdapter.getUser()?.role === 'admin'
127
+ }
128
+ }
129
+ ```
130
+
131
+ When `canRead()` returns false:
132
+ - Navigation items are hidden
133
+ - Routes redirect to `/`
134
+
135
+ ## Components
136
+
137
+ | Category | Components |
138
+ |----------|------------|
139
+ | Layout | `AppLayout`, `PageLayout`, `PageHeader`, `Breadcrumb` |
140
+ | Forms | `FormField`, `FormActions`, `FormTabs`, `FormTab` |
141
+ | Lists | `ListPage`, `ActionButtons`, `FilterBar` |
142
+ | Editors | `JsonViewer`, `KeyValueEditor`, `VanillaJsonEditor` |
143
+ | Dialogs | `SimpleDialog`, `MultiStepDialog`, `UnsavedChangesDialog` |
144
+ | Display | `CardsGrid`, `CopyableId`, `EmptyState` |
145
+
146
+ ## Composables
147
+
148
+ | Composable | Description |
149
+ |------------|-------------|
150
+ | `useForm` | Form with validation, dirty state, navigation guard |
151
+ | `useBareForm` | Lightweight form without routing |
152
+ | `useListPageBuilder` | Paginated list with filters and actions |
153
+ | `useTabSync` | Sync tabs with URL query params |
154
+ | `useBreadcrumb` | Dynamic breadcrumb from route |
155
+
156
+ ## Peer Dependencies
157
+
158
+ - vue ^3.3.0
159
+ - vue-router ^4.0.0
160
+ - primevue ^4.0.0
161
+ - pinia ^2.0.0
162
+ - vanilla-jsoneditor ^0.23.0
163
+
164
+ ## License
165
+
166
+ MIT
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "qdadm",
3
+ "version": "0.13.0",
4
+ "description": "Vue 3 framework for admin dashboards with PrimeVue",
5
+ "author": "quazardous",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/quazardous/qdadm.git"
10
+ },
11
+ "homepage": "https://github.com/quazardous/qdadm#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/quazardous/qdadm/issues"
14
+ },
15
+ "type": "module",
16
+ "main": "src/index.js",
17
+ "exports": {
18
+ ".": "./src/index.js",
19
+ "./composables": "./src/composables/index.js",
20
+ "./components": "./src/components/index.js",
21
+ "./module": "./src/module/index.js",
22
+ "./utils": "./src/utils/index.js",
23
+ "./styles": "./src/styles/index.css"
24
+ },
25
+ "files": [
26
+ "src",
27
+ "README.md",
28
+ "CHANGELOG.md",
29
+ "LICENSE"
30
+ ],
31
+ "peerDependencies": {
32
+ "vue": "^3.3.0",
33
+ "vue-router": "^4.0.0",
34
+ "primevue": "^4.0.0",
35
+ "pinia": "^2.0.0",
36
+ "vanilla-jsoneditor": "^0.23.0"
37
+ },
38
+ "keywords": [
39
+ "vue",
40
+ "vue3",
41
+ "admin",
42
+ "dashboard",
43
+ "framework",
44
+ "primevue",
45
+ "crud",
46
+ "entity-manager"
47
+ ]
48
+ }
@@ -0,0 +1,6 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
2
+ <polygon points="50,5 93,27.5 93,72.5 50,95 7,72.5 7,27.5" fill="#1E3A8A"/>
3
+ <text x="48" y="50" text-anchor="middle" dominant-baseline="central" font-family="system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif" font-size="58" font-weight="800" letter-spacing="-4">
4
+ <tspan fill="#60A5FA">Q</tspan><tspan fill="#93C5FD">D</tspan>
5
+ </text>
6
+ </svg>
@@ -0,0 +1,28 @@
1
+ <script setup>
2
+ /**
3
+ * BoolCell - Standardized boolean display for list columns
4
+ *
5
+ * Tristate display:
6
+ * - true: green check
7
+ * - false: red cross
8
+ * - null/undefined: empty
9
+ *
10
+ * Usage:
11
+ * <Column field="read" header="Read">
12
+ * <template #body="{ data }">
13
+ * <BoolCell :value="data.read" />
14
+ * </template>
15
+ * </Column>
16
+ */
17
+ defineProps({
18
+ value: {
19
+ type: Boolean,
20
+ default: null
21
+ }
22
+ })
23
+ </script>
24
+
25
+ <template>
26
+ <i v-if="value === true" class="pi pi-check" style="color: var(--p-green-500)" />
27
+ <i v-else-if="value === false" class="pi pi-times" style="color: var(--p-red-500)" />
28
+ </template>
@@ -0,0 +1,43 @@
1
+ <script setup>
2
+ import SimpleDialog from './SimpleDialog.vue'
3
+ import Select from 'primevue/select'
4
+
5
+ defineProps({
6
+ visible: Boolean,
7
+ title: { type: String, default: 'Change Status' },
8
+ options: { type: Array, required: true },
9
+ modelValue: [String, Number],
10
+ loading: Boolean,
11
+ selectionCount: { type: Number, default: 0 }
12
+ })
13
+
14
+ defineEmits(['update:visible', 'update:modelValue', 'confirm', 'cancel'])
15
+ </script>
16
+
17
+ <template>
18
+ <SimpleDialog
19
+ :visible="visible"
20
+ :title="title"
21
+ width="400px"
22
+ :loading="loading"
23
+ confirmLabel="Update"
24
+ confirmIcon="pi pi-check"
25
+ :confirmDisabled="!modelValue"
26
+ @update:visible="$emit('update:visible', $event)"
27
+ @confirm="$emit('confirm')"
28
+ @cancel="$emit('cancel')"
29
+ >
30
+ <p v-if="selectionCount > 0" class="mb-3">
31
+ Change status for {{ selectionCount }} selected item(s):
32
+ </p>
33
+ <Select
34
+ :modelValue="modelValue"
35
+ :options="options"
36
+ optionLabel="label"
37
+ optionValue="value"
38
+ placeholder="Select new status"
39
+ class="w-full"
40
+ @update:modelValue="$emit('update:modelValue', $event)"
41
+ />
42
+ </SimpleDialog>
43
+ </template>