@quazardous/qdadm 1.19.3

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 (291) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +111 -0
  3. package/package.json +101 -0
  4. package/src/assets/logo.svg +6 -0
  5. package/src/auth/SessionAuthAdapter.ts +459 -0
  6. package/src/auth/index.ts +15 -0
  7. package/src/chain/ActiveStack.ts +154 -0
  8. package/src/chain/StackHydrator.ts +292 -0
  9. package/src/chain/index.ts +25 -0
  10. package/src/chain/useActiveStack.ts +120 -0
  11. package/src/chain/useStackHydrator.ts +155 -0
  12. package/src/components/BoolCell.vue +34 -0
  13. package/src/components/InfoBanner.vue +73 -0
  14. package/src/components/QdadmRoot.vue +52 -0
  15. package/src/components/SeverityTag.vue +86 -0
  16. package/src/components/dialogs/BulkStatusDialog.vue +60 -0
  17. package/src/components/dialogs/MultiStepDialog.vue +331 -0
  18. package/src/components/dialogs/SimpleDialog.vue +122 -0
  19. package/src/components/dialogs/UnsavedChangesDialog.vue +80 -0
  20. package/src/components/display/BannerZone.vue +65 -0
  21. package/src/components/display/CardsGrid.vue +72 -0
  22. package/src/components/display/CopyableId.vue +84 -0
  23. package/src/components/display/EmptyState.vue +62 -0
  24. package/src/components/display/IntensityBar.vue +190 -0
  25. package/src/components/display/RichCardsGrid.vue +101 -0
  26. package/src/components/edit/FormActions.vue +78 -0
  27. package/src/components/edit/FormField.vue +82 -0
  28. package/src/components/edit/FormInput.vue +158 -0
  29. package/src/components/edit/FormPage.vue +260 -0
  30. package/src/components/edit/FormTab.vue +217 -0
  31. package/src/components/edit/FormTabs.vue +120 -0
  32. package/src/components/edit/LookupField.vue +406 -0
  33. package/src/components/edit/LookupPickerDialog.vue +230 -0
  34. package/src/components/editors/JsonEditorFoldable.vue +470 -0
  35. package/src/components/editors/JsonStructuredField.vue +264 -0
  36. package/src/components/editors/JsonViewer.vue +51 -0
  37. package/src/components/editors/KeyValueEditor.vue +314 -0
  38. package/src/components/editors/LanguageEditor.vue +259 -0
  39. package/src/components/editors/PermissionEditor.vue +558 -0
  40. package/src/components/editors/ScopeEditor.vue +372 -0
  41. package/src/components/editors/VanillaJsonEditor.vue +183 -0
  42. package/src/components/index.ts +83 -0
  43. package/src/components/item/FieldGroups.vue +392 -0
  44. package/src/components/layout/AppLayout.vue +1032 -0
  45. package/src/components/layout/BaseLayout.vue +190 -0
  46. package/src/components/layout/Breadcrumb.vue +55 -0
  47. package/src/components/layout/DashboardLayout.vue +104 -0
  48. package/src/components/layout/FormLayout.vue +256 -0
  49. package/src/components/layout/ListLayout.vue +278 -0
  50. package/src/components/layout/PageHeader.vue +156 -0
  51. package/src/components/layout/PageLayout.vue +126 -0
  52. package/src/components/layout/PageNav.vue +192 -0
  53. package/src/components/layout/SidebarBox.vue +87 -0
  54. package/src/components/layout/Zone.vue +182 -0
  55. package/src/components/layout/defaults/DefaultBreadcrumb.vue +149 -0
  56. package/src/components/layout/defaults/DefaultFooter.vue +89 -0
  57. package/src/components/layout/defaults/DefaultFormActions.vue +67 -0
  58. package/src/components/layout/defaults/DefaultHeader.vue +78 -0
  59. package/src/components/layout/defaults/DefaultMenu.vue +188 -0
  60. package/src/components/layout/defaults/DefaultPagination.vue +75 -0
  61. package/src/components/layout/defaults/DefaultTable.vue +137 -0
  62. package/src/components/layout/defaults/DefaultUserInfo.vue +111 -0
  63. package/src/components/layout/defaults/index.ts +16 -0
  64. package/src/components/lists/ActionButtons.vue +49 -0
  65. package/src/components/lists/ActionColumn.vue +40 -0
  66. package/src/components/lists/FilterBar.vue +54 -0
  67. package/src/components/lists/ListPage.vue +467 -0
  68. package/src/components/pages/LoginPage.vue +334 -0
  69. package/src/components/pages/NotFoundPage.vue +98 -0
  70. package/src/components/show/ShowDisplay.vue +343 -0
  71. package/src/components/show/ShowField.vue +67 -0
  72. package/src/components/show/ShowPage.vue +431 -0
  73. package/src/composables/index.ts +155 -0
  74. package/src/composables/useApp.ts +67 -0
  75. package/src/composables/useAuth.ts +98 -0
  76. package/src/composables/useBareForm.ts +319 -0
  77. package/src/composables/useBreadcrumb.ts +252 -0
  78. package/src/composables/useChildPage.ts +113 -0
  79. package/src/composables/useCurrentEntity.ts +60 -0
  80. package/src/composables/useDeferred.ts +94 -0
  81. package/src/composables/useDirtyState.ts +138 -0
  82. package/src/composables/useEntityItemFormPage.ts +942 -0
  83. package/src/composables/useEntityItemFormPage.types.ts +451 -0
  84. package/src/composables/useEntityItemPage.ts +438 -0
  85. package/src/composables/useEntityItemShowPage.ts +722 -0
  86. package/src/composables/useFieldManager.ts +692 -0
  87. package/src/composables/useForm.ts +544 -0
  88. package/src/composables/useGuardStore.ts +53 -0
  89. package/src/composables/useHooks.ts +56 -0
  90. package/src/composables/useInfoBanner.ts +217 -0
  91. package/src/composables/useJsonSyntax.ts +122 -0
  92. package/src/composables/useLayoutResolver.ts +329 -0
  93. package/src/composables/useListPage.ts +1535 -0
  94. package/src/composables/useListPage.types.ts +437 -0
  95. package/src/composables/useListPage.utils.ts +101 -0
  96. package/src/composables/useNavContext.ts +439 -0
  97. package/src/composables/useNavigation.ts +216 -0
  98. package/src/composables/useOptionsLookup.ts +323 -0
  99. package/src/composables/usePageTitle.ts +84 -0
  100. package/src/composables/useSSEBridge.ts +142 -0
  101. package/src/composables/useSemanticBreadcrumb.ts +222 -0
  102. package/src/composables/useSidebarState.ts +24 -0
  103. package/src/composables/useSignals.ts +52 -0
  104. package/src/composables/useUnsavedChangesGuard.ts +155 -0
  105. package/src/composables/useUserImpersonator.ts +317 -0
  106. package/src/composables/useZoneRegistry.ts +252 -0
  107. package/src/core/bundles.ts +558 -0
  108. package/src/core/decorator.ts +420 -0
  109. package/src/core/extension.ts +470 -0
  110. package/src/core/index.ts +59 -0
  111. package/src/deferred/DeferredRegistry.ts +353 -0
  112. package/src/deferred/index.ts +15 -0
  113. package/src/editors/index.ts +12 -0
  114. package/src/entity/EntityManager.cache.ts +530 -0
  115. package/src/entity/EntityManager.crud.ts +615 -0
  116. package/src/entity/EntityManager.interface.ts +78 -0
  117. package/src/entity/EntityManager.query.ts +221 -0
  118. package/src/entity/EntityManager.relations.ts +151 -0
  119. package/src/entity/EntityManager.ts +944 -0
  120. package/src/entity/EntityManager.types.ts +288 -0
  121. package/src/entity/auth/CompositeAuthAdapter.ts +194 -0
  122. package/src/entity/auth/EntityAuthAdapter.ts +119 -0
  123. package/src/entity/auth/PermissiveAdapter.ts +43 -0
  124. package/src/entity/auth/RoleHierarchy.ts +128 -0
  125. package/src/entity/auth/SecurityChecker.ts +202 -0
  126. package/src/entity/auth/factory.ts +203 -0
  127. package/src/entity/auth/index.ts +47 -0
  128. package/src/entity/factory.test.js +189 -0
  129. package/src/entity/factory.ts +146 -0
  130. package/src/entity/index.ts +49 -0
  131. package/src/entity/storage/ApiStorage.ts +228 -0
  132. package/src/entity/storage/IStorage.ts +100 -0
  133. package/src/entity/storage/LocalStorage.ts +200 -0
  134. package/src/entity/storage/MemoryStorage.ts +184 -0
  135. package/src/entity/storage/MockApiStorage.ts +318 -0
  136. package/src/entity/storage/SdkStorage.ts +377 -0
  137. package/src/entity/storage/factory.test.js +159 -0
  138. package/src/entity/storage/factory.ts +209 -0
  139. package/src/entity/storage/index.ts +75 -0
  140. package/src/gen/FieldMapper.ts +122 -0
  141. package/src/gen/StorageProfileFactory.ts +93 -0
  142. package/src/gen/connectors/BaseConnector.ts +150 -0
  143. package/src/gen/connectors/ManualConnector.test.js +499 -0
  144. package/src/gen/connectors/ManualConnector.ts +414 -0
  145. package/src/gen/connectors/OpenAPIConnector.test.js +836 -0
  146. package/src/gen/connectors/OpenAPIConnector.ts +693 -0
  147. package/src/gen/connectors/__fixtures__/sample-openapi.json +311 -0
  148. package/src/gen/connectors/index.ts +27 -0
  149. package/src/gen/createManagers.ts +245 -0
  150. package/src/gen/decorators.ts +134 -0
  151. package/src/gen/generateManagers.test.js +540 -0
  152. package/src/gen/generateManagers.ts +398 -0
  153. package/src/gen/index.ts +66 -0
  154. package/src/gen/schema.ts +248 -0
  155. package/src/gen/vite-plugin.ts +114 -0
  156. package/src/generated/managers/testManager.js +45 -0
  157. package/src/generated/managers/testManager.ts +46 -0
  158. package/src/hooks/HookRegistry.ts +16 -0
  159. package/src/hooks/index.ts +15 -0
  160. package/src/i18n/I18n.ts +344 -0
  161. package/src/i18n/IncrementalDomainProvider.ts +153 -0
  162. package/src/i18n/InlineTranslationProvider.ts +4 -0
  163. package/src/i18n/LazyTranslationProvider.ts +102 -0
  164. package/src/i18n/MessagesRegistry.ts +4 -0
  165. package/src/i18n/Resolver.ts +4 -0
  166. package/src/i18n/__tests__/I18n.test.ts +169 -0
  167. package/src/i18n/__tests__/IncrementalDomainProvider.test.ts +146 -0
  168. package/src/i18n/__tests__/LazyTranslationProvider.test.ts +100 -0
  169. package/src/i18n/__tests__/Resolver.test.ts +271 -0
  170. package/src/i18n/defaults/DefaultCoreProvider.ts +28 -0
  171. package/src/i18n/defaults/core.en.yml +55 -0
  172. package/src/i18n/defaults/core.fr.yml +55 -0
  173. package/src/i18n/index.ts +55 -0
  174. package/src/i18n/loaders/raw-modules.d.ts +15 -0
  175. package/src/i18n/loaders/yaml.ts +35 -0
  176. package/src/i18n/strategies.ts +4 -0
  177. package/src/i18n/types.ts +34 -0
  178. package/src/i18n/useI18n.ts +34 -0
  179. package/src/index.ts +453 -0
  180. package/src/kernel/EventRouter.ts +23 -0
  181. package/src/kernel/Kernel.api.ts +79 -0
  182. package/src/kernel/Kernel.auth.ts +120 -0
  183. package/src/kernel/Kernel.i18n.ts +29 -0
  184. package/src/kernel/Kernel.modules.ts +170 -0
  185. package/src/kernel/Kernel.registries.ts +237 -0
  186. package/src/kernel/Kernel.routing.ts +334 -0
  187. package/src/kernel/Kernel.ts +460 -0
  188. package/src/kernel/Kernel.types.ts +263 -0
  189. package/src/kernel/Kernel.vue.ts +304 -0
  190. package/src/kernel/KernelContext.entities.ts +80 -0
  191. package/src/kernel/KernelContext.events.ts +57 -0
  192. package/src/kernel/KernelContext.i18n.ts +37 -0
  193. package/src/kernel/KernelContext.permissions.ts +38 -0
  194. package/src/kernel/KernelContext.routing.ts +280 -0
  195. package/src/kernel/KernelContext.ts +252 -0
  196. package/src/kernel/KernelContext.types.ts +173 -0
  197. package/src/kernel/KernelContext.zones.ts +54 -0
  198. package/src/kernel/Module.ts +169 -0
  199. package/src/kernel/ModuleLoader.ts +645 -0
  200. package/src/kernel/SSEBridge.ts +11 -0
  201. package/src/kernel/SignalBus.ts +48 -0
  202. package/src/kernel/index.ts +56 -0
  203. package/src/module/index.ts +33 -0
  204. package/src/module/moduleRegistry.ts +492 -0
  205. package/src/modules/debug/AuthCollector.ts +501 -0
  206. package/src/modules/debug/Collector.ts +20 -0
  207. package/src/modules/debug/DebugBridge.ts +14 -0
  208. package/src/modules/debug/DebugModule.ts +220 -0
  209. package/src/modules/debug/EntitiesCollector.ts +839 -0
  210. package/src/modules/debug/ErrorCollector.ts +4 -0
  211. package/src/modules/debug/I18nCollector.ts +9 -0
  212. package/src/modules/debug/LocalStorageAdapter.ts +7 -0
  213. package/src/modules/debug/RouterCollector.ts +449 -0
  214. package/src/modules/debug/SignalCollector.ts +4 -0
  215. package/src/modules/debug/ToastCollector.ts +4 -0
  216. package/src/modules/debug/ZonesCollector.ts +447 -0
  217. package/src/modules/debug/components/DebugBar.vue +31 -0
  218. package/src/modules/debug/components/adminPanelsConfig.ts +42 -0
  219. package/src/modules/debug/components/index.ts +9 -0
  220. package/src/modules/debug/components/panels/AuthPanel.vue +267 -0
  221. package/src/modules/debug/components/panels/EntitiesPanel.vue +572 -0
  222. package/src/modules/debug/components/panels/I18nPanel.vue +738 -0
  223. package/src/modules/debug/components/panels/RouterPanel.vue +440 -0
  224. package/src/modules/debug/components/panels/ZonesPanel.vue +133 -0
  225. package/src/modules/debug/components/panels/index.ts +16 -0
  226. package/src/modules/debug/index.ts +58 -0
  227. package/src/modules/debug/styles.scss +2671 -0
  228. package/src/notifications/NotificationBadge.vue +35 -0
  229. package/src/notifications/NotificationListener.vue +71 -0
  230. package/src/notifications/NotificationModule.ts +76 -0
  231. package/src/notifications/NotificationPanel.vue +478 -0
  232. package/src/notifications/NotificationStore.ts +288 -0
  233. package/src/notifications/index.ts +42 -0
  234. package/src/notifications/styles.scss +32 -0
  235. package/src/orchestrator/Orchestrator.ts +427 -0
  236. package/src/orchestrator/index.ts +8 -0
  237. package/src/orchestrator/useOrchestrator.ts +80 -0
  238. package/src/plugin.ts +251 -0
  239. package/src/query/FilterQuery.ts +306 -0
  240. package/src/query/QueryExecutor.ts +341 -0
  241. package/src/query/index.ts +16 -0
  242. package/src/security/EntityRolesProvider.ts +385 -0
  243. package/src/security/PermissionMatcher.ts +152 -0
  244. package/src/security/PermissionRegistry.ts +273 -0
  245. package/src/security/PersistableRolesProvider.ts +584 -0
  246. package/src/security/RolesManager.ts +136 -0
  247. package/src/security/RolesProvider.ts +167 -0
  248. package/src/security/RolesProviderStorage.ts +211 -0
  249. package/src/security/SecurityModule.ts +94 -0
  250. package/src/security/StaticRolesProvider.ts +117 -0
  251. package/src/security/UsersManager.ts +163 -0
  252. package/src/security/index.ts +77 -0
  253. package/src/security/pages/RoleForm.vue +276 -0
  254. package/src/security/pages/RoleList.vue +123 -0
  255. package/src/styles/_alerts.scss +95 -0
  256. package/src/styles/_buttons.scss +391 -0
  257. package/src/styles/_cards.scss +241 -0
  258. package/src/styles/_code.scss +78 -0
  259. package/src/styles/_dialogs.scss +55 -0
  260. package/src/styles/_filter-bar.scss +70 -0
  261. package/src/styles/_forms.scss +434 -0
  262. package/src/styles/_helpers.scss +153 -0
  263. package/src/styles/_lists.scss +225 -0
  264. package/src/styles/_main.scss +356 -0
  265. package/src/styles/_markdown.scss +88 -0
  266. package/src/styles/_responsive.scss +255 -0
  267. package/src/styles/_show-pages.scss +186 -0
  268. package/src/styles/_sidebar.scss +380 -0
  269. package/src/styles/_states.scss +115 -0
  270. package/src/styles/_stats.scss +47 -0
  271. package/src/styles/_variables.scss +224 -0
  272. package/src/styles/index.scss +38 -0
  273. package/src/styles/theme/_components.scss +331 -0
  274. package/src/styles/theme/_index.scss +10 -0
  275. package/src/styles/theme/_tokens.scss +147 -0
  276. package/src/styles/theme/_utilities.scss +175 -0
  277. package/src/toast/ToastBridgeModule.ts +68 -0
  278. package/src/toast/ToastListener.vue +55 -0
  279. package/src/toast/index.ts +26 -0
  280. package/src/toast/useSignalToast.ts +154 -0
  281. package/src/types/index.ts +285 -0
  282. package/src/types/pluralize.d.ts +19 -0
  283. package/src/types/quarkernel.d.ts +50 -0
  284. package/src/utils/formatters.ts +174 -0
  285. package/src/utils/index.ts +35 -0
  286. package/src/utils/transformers.ts +131 -0
  287. package/src/vite/qdadmDebugPlugin.ts +401 -0
  288. package/src/vite-env.d.ts +50 -0
  289. package/src/zones/ZoneRegistry.ts +934 -0
  290. package/src/zones/index.ts +29 -0
  291. package/src/zones/zones.ts +191 -0
@@ -0,0 +1,4 @@
1
+ /**
2
+ * ErrorCollector — qdadm re-export from @quazardous/qddebug.
3
+ */
4
+ export { ErrorCollector, type ErrorEntry } from '@quazardous/qddebug'
@@ -0,0 +1,9 @@
1
+ /**
2
+ * I18nCollector — qdadm re-export from @quazardous/qddebug.
3
+ */
4
+ export {
5
+ I18nCollector,
6
+ type MissingKeyEntry,
7
+ type LocaleChange,
8
+ type I18nCollectorOptions,
9
+ } from '@quazardous/qddebug'
@@ -0,0 +1,7 @@
1
+ /**
2
+ * LocalStorageAdapter — qdadm re-export.
3
+ *
4
+ * The actual implementation now lives in `@quazardous/qddebug`.
5
+ */
6
+
7
+ export { LocalStorageAdapter, createLocalStorageAdapter } from '@quazardous/qddebug'
@@ -0,0 +1,449 @@
1
+ /**
2
+ * RouterCollector - Debug collector for Vue Router state
3
+ *
4
+ * Displays current routing information:
5
+ * - Current route (name, path, params, query, meta)
6
+ * - Navigation history (recent route changes)
7
+ * - All registered routes
8
+ *
9
+ * @example
10
+ * const collector = new RouterCollector()
11
+ * collector.install(ctx)
12
+ */
13
+
14
+ import {
15
+ Collector,
16
+ type CollectorContext,
17
+ type CollectorEntry,
18
+ type CollectorManifest,
19
+ type CollectorOptions,
20
+ type CollectorSnapshot,
21
+ } from './Collector'
22
+ import { computeSemanticBreadcrumb } from '../../composables/useSemanticBreadcrumb'
23
+ import type { Router, RouteLocationNormalized, RouteRecordNormalized } from 'vue-router'
24
+ import type { ActiveStack, StackLevel } from '../../chain/ActiveStack'
25
+ import type { StackHydrator, HydratedLevel } from '../../chain/StackHydrator'
26
+
27
+ /**
28
+ * Serialized route info
29
+ */
30
+ export interface SerializedRoute {
31
+ name: string
32
+ path: string
33
+ fullPath: string
34
+ params: Record<string, string | string[]>
35
+ query: Record<string, string | string[] | null>
36
+ hash: string
37
+ meta: Record<string, unknown>
38
+ matched: Array<{
39
+ name: string | null
40
+ path: string
41
+ meta: Record<string, unknown>
42
+ }>
43
+ }
44
+
45
+ /**
46
+ * Navigation history entry
47
+ */
48
+ export interface NavigationEntry extends CollectorEntry {
49
+ id: number
50
+ to: SerializedRoute
51
+ from: SerializedRoute | null
52
+ seen: boolean
53
+ }
54
+
55
+ /**
56
+ * Route list entry
57
+ */
58
+ export interface RouteListEntry {
59
+ name: string
60
+ path: string
61
+ meta: Record<string, unknown>
62
+ hasComponent: boolean
63
+ children: number
64
+ }
65
+
66
+ /**
67
+ * Active stack debug info
68
+ */
69
+ export interface ActiveStackInfo {
70
+ levels: Array<{
71
+ entity: string
72
+ param: string
73
+ foreignKey: string | null
74
+ id: string | null
75
+ hydrated: boolean
76
+ loading: boolean
77
+ label: string | null
78
+ hasData: boolean
79
+ }>
80
+ depth: number
81
+ current: StackLevel | null
82
+ parent: StackLevel | null
83
+ }
84
+
85
+ /**
86
+ * RouterCollector options
87
+ */
88
+ export interface RouterCollectorOptions extends CollectorOptions {
89
+ maxHistory?: number
90
+ }
91
+
92
+ /**
93
+ * Extended context for router collector
94
+ */
95
+ interface RouterCollectorContext extends CollectorContext {
96
+ router?: Router
97
+ activeStack?: ActiveStack
98
+ stackHydrator?: StackHydrator
99
+ }
100
+
101
+ /**
102
+ * Collector for Vue Router state visualization
103
+ */
104
+ export class RouterCollector extends Collector<NavigationEntry> {
105
+ /**
106
+ * Collector name identifier
107
+ */
108
+ static override collectorName = 'router'
109
+
110
+ /**
111
+ * This collector records navigation events
112
+ */
113
+ static override records = true
114
+
115
+ private _history: NavigationEntry[] = []
116
+ private _maxHistory: number
117
+ private _removeGuard: (() => void) | null = null
118
+ private _guardInstalled: boolean = false
119
+ private _activeStack: ActiveStack | null = null
120
+ private _stackHydrator: StackHydrator | null = null
121
+ private _removeHydratedListener: (() => void) | null = null
122
+ private _removeStackChangeListener: (() => void) | null = null
123
+
124
+ constructor(options: RouterCollectorOptions = {}) {
125
+ super(options)
126
+ this._maxHistory = options.maxHistory ?? 20
127
+ }
128
+
129
+ /**
130
+ * Get router lazily (router might not exist at install time)
131
+ * @private
132
+ */
133
+ private get _router(): Router | undefined {
134
+ return (this._ctx as RouterCollectorContext)?.router
135
+ }
136
+
137
+ /**
138
+ * Internal install - store context (router is accessed lazily)
139
+ * @protected
140
+ */
141
+ protected override _doInstall(ctx: CollectorContext): void {
142
+ this._ctx = ctx
143
+ const routerCtx = ctx as RouterCollectorContext
144
+ this._activeStack = routerCtx.activeStack ?? null
145
+ this._stackHydrator = routerCtx.stackHydrator ?? null
146
+ // Router guard will be installed lazily when router becomes available
147
+
148
+ // Re-render the panel when the active stack changes or finishes hydrating —
149
+ // otherwise level.label stays on its loading placeholder until the next
150
+ // navigation triggers reactivity. afterEach (the navigation guard) only
151
+ // fires when the route changes, not when the async hydrator resolves.
152
+ const signals = ctx.signals
153
+ if (signals) {
154
+ this._removeStackChangeListener = signals.on('stack:change', () => {
155
+ this.notifyChange()
156
+ })
157
+ this._removeHydratedListener = signals.on('stack:hydrated', () => {
158
+ this.notifyChange()
159
+ })
160
+ }
161
+ }
162
+
163
+ /**
164
+ * Ensure router guard is installed (called lazily)
165
+ * @private
166
+ */
167
+ private _ensureGuard(): void {
168
+ if (this._guardInstalled || !this._router) return
169
+
170
+ // Track navigation with afterEach
171
+ this._removeGuard = this._router.afterEach((to, from) => {
172
+ this._addNavigation(to, from)
173
+ })
174
+ this._guardInstalled = true
175
+
176
+ // Add initial route if not on home
177
+ const current = this._router.currentRoute?.value
178
+ if (current && current.path !== '/') {
179
+ this._history.unshift({
180
+ timestamp: Date.now(),
181
+ id: Date.now(),
182
+ to: this._serializeRoute(current),
183
+ from: null,
184
+ seen: false
185
+ })
186
+ }
187
+ }
188
+
189
+ /**
190
+ * Add navigation event to history
191
+ * @private
192
+ */
193
+ private _addNavigation(to: RouteLocationNormalized, from: RouteLocationNormalized): void {
194
+ const entry: NavigationEntry = {
195
+ timestamp: Date.now(),
196
+ id: Date.now(),
197
+ to: this._serializeRoute(to),
198
+ from: from?.name ? this._serializeRoute(from) : null,
199
+ seen: false
200
+ }
201
+
202
+ // Create new array reference for Vue reactivity
203
+ this._history = [entry, ...this._history.slice(0, this._maxHistory - 1)]
204
+
205
+ this.notifyChange()
206
+ }
207
+
208
+ /**
209
+ * Serialize route to plain object
210
+ * @private
211
+ */
212
+ private _serializeRoute(route: RouteLocationNormalized): SerializedRoute {
213
+ return {
214
+ name: (route.name as string) || '(unnamed)',
215
+ path: route.path,
216
+ fullPath: route.fullPath,
217
+ params: { ...route.params } as Record<string, string | string[]>,
218
+ query: { ...route.query } as Record<string, string | string[] | null>,
219
+ hash: route.hash,
220
+ meta: { ...route.meta },
221
+ // Matched routes with their individual metas
222
+ matched: route.matched?.map(m => ({
223
+ name: (m.name as string) || null,
224
+ path: m.path,
225
+ meta: { ...m.meta }
226
+ })) ?? []
227
+ }
228
+ }
229
+
230
+ /**
231
+ * Internal uninstall - cleanup
232
+ * @protected
233
+ */
234
+ protected override _doUninstall(): void {
235
+ if (this._removeGuard) {
236
+ this._removeGuard()
237
+ this._removeGuard = null
238
+ }
239
+ if (this._removeStackChangeListener) {
240
+ this._removeStackChangeListener()
241
+ this._removeStackChangeListener = null
242
+ }
243
+ if (this._removeHydratedListener) {
244
+ this._removeHydratedListener()
245
+ this._removeHydratedListener = null
246
+ }
247
+ this._guardInstalled = false
248
+ this._ctx = null
249
+ this._history = []
250
+ }
251
+
252
+ /**
253
+ * Get badge - count of unseen navigations
254
+ */
255
+ override getBadge(): number {
256
+ return this._history.filter(h => !h.seen).length
257
+ }
258
+
259
+ /**
260
+ * Mark all history as seen
261
+ */
262
+ markSeen(): void {
263
+ for (const item of this._history) {
264
+ item.seen = true
265
+ }
266
+ }
267
+
268
+ /**
269
+ * Get current route info
270
+ */
271
+ getCurrentRoute(): SerializedRoute | null {
272
+ this._ensureGuard()
273
+ const router = this._router
274
+ if (!router) return null
275
+ const current = router.currentRoute?.value
276
+ if (!current) return null
277
+ return this._serializeRoute(current)
278
+ }
279
+
280
+ /**
281
+ * Get navigation history
282
+ */
283
+ getHistory(): NavigationEntry[] {
284
+ return this._history
285
+ }
286
+
287
+ /**
288
+ * Get all registered routes
289
+ */
290
+ getRoutes(): RouteListEntry[] {
291
+ this._ensureGuard()
292
+ if (!this._router) return []
293
+
294
+ const routes = this._router.getRoutes()
295
+ return routes.map((route: RouteRecordNormalized) => ({
296
+ name: (route.name as string) || '(unnamed)',
297
+ path: route.path,
298
+ meta: { ...route.meta },
299
+ hasComponent: !!route.components?.default,
300
+ children: route.children?.length || 0
301
+ })).sort((a, b) => a.path.localeCompare(b.path))
302
+ }
303
+
304
+ /**
305
+ * Get computed breadcrumb for current route
306
+ * Returns semantic objects per level - adapters resolve labels/paths
307
+ *
308
+ * Uses shared computeSemanticBreadcrumb function from composables.
309
+ *
310
+ * Kinds:
311
+ * - route: Generic route (e.g., home)
312
+ * - entity-list: Entity collection (e.g., /books)
313
+ * - entity-show: Entity instance view
314
+ * - entity-edit: Entity instance edit
315
+ * - entity-create: Entity creation
316
+ */
317
+ getBreadcrumb(): unknown[] {
318
+ this._ensureGuard()
319
+ const current = this._router?.currentRoute?.value
320
+ if (!current) return []
321
+
322
+ return computeSemanticBreadcrumb(current.path, this._router!.getRoutes(), current)
323
+ }
324
+
325
+ /**
326
+ * Get entries for display (implements Collector interface)
327
+ */
328
+ override getEntries(): NavigationEntry[] {
329
+ return this._history
330
+ }
331
+
332
+ /**
333
+ * Clear navigation history
334
+ */
335
+ override clear(): void {
336
+ this._history = []
337
+ this.notifyChange()
338
+ }
339
+
340
+ /**
341
+ * Get activeStack state for debugging
342
+ * Combines sync stack (config) with hydrator (async data)
343
+ */
344
+ getActiveStack(): ActiveStackInfo | null {
345
+ if (!this._activeStack) return null
346
+
347
+ const syncLevels = this._activeStack.getLevels()
348
+ const hydratorLevels = this._stackHydrator?.getLevels() ?? []
349
+
350
+ return {
351
+ levels: syncLevels.map((level, idx) => {
352
+ const hydrated = hydratorLevels[idx] as HydratedLevel | undefined
353
+ return {
354
+ // Sync (from ActiveStack)
355
+ entity: level.entity,
356
+ param: level.param,
357
+ foreignKey: level.foreignKey,
358
+ id: level.id,
359
+ // Async (from StackHydrator)
360
+ hydrated: hydrated?.hydrated ?? false,
361
+ loading: hydrated?.loading ?? false,
362
+ label: hydrated?.label ?? null,
363
+ hasData: !!hydrated?.data,
364
+ }
365
+ }),
366
+ depth: syncLevels.length,
367
+ current: this._activeStack.getCurrent(),
368
+ parent: this._activeStack.getParent(),
369
+ }
370
+ }
371
+
372
+ /**
373
+ * Navigate to a path
374
+ * @param path - Path to navigate to
375
+ */
376
+ async navigate(path: string): Promise<void> {
377
+ if (!this._router) return
378
+ await this._router.push(path)
379
+ }
380
+
381
+ override describe(): CollectorManifest {
382
+ return {
383
+ name: this.name,
384
+ records: true,
385
+ summary:
386
+ 'Captures navigations (afterEach) and exposes the current route, registered routes and the live ActiveStack.',
387
+ entryShape: {
388
+ id: 'number',
389
+ to: 'SerializedRoute',
390
+ from: 'SerializedRoute?',
391
+ seen: 'boolean',
392
+ timestamp: 'number',
393
+ },
394
+ stateShape: {
395
+ currentRoute: 'SerializedRoute?',
396
+ routes: 'RouteListEntry[]',
397
+ breadcrumb: 'unknown[]',
398
+ activeStack: 'ActiveStackInfo?',
399
+ },
400
+ actions: [
401
+ ...this._builtinActionManifests(),
402
+ {
403
+ name: 'navigate',
404
+ summary: 'Push a path onto the router (router.push).',
405
+ args: { path: 'string' },
406
+ mutates: true,
407
+ },
408
+ {
409
+ name: 'getCurrentRoute',
410
+ summary: 'Return the serialized current route.',
411
+ },
412
+ {
413
+ name: 'getRoutes',
414
+ summary: 'List every registered route.',
415
+ },
416
+ {
417
+ name: 'getBreadcrumb',
418
+ summary: 'Return the semantic breadcrumb for the current route.',
419
+ },
420
+ ],
421
+ }
422
+ }
423
+
424
+ override snapshot(): CollectorSnapshot {
425
+ return {
426
+ name: this.name,
427
+ entries: this._history.map((e) => ({ ...e })),
428
+ count: this._history.length,
429
+ unseen: this.getBadge(),
430
+ state: {
431
+ currentRoute: this.getCurrentRoute(),
432
+ routes: this.getRoutes(),
433
+ breadcrumb: this.getBreadcrumb(),
434
+ activeStack: this.getActiveStack(),
435
+ },
436
+ }
437
+ }
438
+
439
+ override async call(actionName: string, args: Record<string, unknown> = {}): Promise<unknown> {
440
+ if (actionName === 'navigate') {
441
+ await this.navigate(String(args.path ?? ''))
442
+ return { ok: true }
443
+ }
444
+ if (actionName === 'getCurrentRoute') return this.getCurrentRoute()
445
+ if (actionName === 'getRoutes') return this.getRoutes()
446
+ if (actionName === 'getBreadcrumb') return this.getBreadcrumb()
447
+ return super.call(actionName, args)
448
+ }
449
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * SignalCollector — qdadm re-export from @quazardous/qddebug.
3
+ */
4
+ export { SignalCollector, type SignalEntry } from '@quazardous/qddebug'
@@ -0,0 +1,4 @@
1
+ /**
2
+ * ToastCollector — qdadm re-export from @quazardous/qddebug.
3
+ */
4
+ export { ToastCollector, type ToastEntry } from '@quazardous/qddebug'