@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.
- package/LICENSE +21 -0
- package/README.md +111 -0
- package/package.json +101 -0
- package/src/assets/logo.svg +6 -0
- package/src/auth/SessionAuthAdapter.ts +459 -0
- package/src/auth/index.ts +15 -0
- package/src/chain/ActiveStack.ts +154 -0
- package/src/chain/StackHydrator.ts +292 -0
- package/src/chain/index.ts +25 -0
- package/src/chain/useActiveStack.ts +120 -0
- package/src/chain/useStackHydrator.ts +155 -0
- package/src/components/BoolCell.vue +34 -0
- package/src/components/InfoBanner.vue +73 -0
- package/src/components/QdadmRoot.vue +52 -0
- package/src/components/SeverityTag.vue +86 -0
- package/src/components/dialogs/BulkStatusDialog.vue +60 -0
- package/src/components/dialogs/MultiStepDialog.vue +331 -0
- package/src/components/dialogs/SimpleDialog.vue +122 -0
- package/src/components/dialogs/UnsavedChangesDialog.vue +80 -0
- package/src/components/display/BannerZone.vue +65 -0
- package/src/components/display/CardsGrid.vue +72 -0
- package/src/components/display/CopyableId.vue +84 -0
- package/src/components/display/EmptyState.vue +62 -0
- package/src/components/display/IntensityBar.vue +190 -0
- package/src/components/display/RichCardsGrid.vue +101 -0
- package/src/components/edit/FormActions.vue +78 -0
- package/src/components/edit/FormField.vue +82 -0
- package/src/components/edit/FormInput.vue +158 -0
- package/src/components/edit/FormPage.vue +260 -0
- package/src/components/edit/FormTab.vue +217 -0
- package/src/components/edit/FormTabs.vue +120 -0
- package/src/components/edit/LookupField.vue +406 -0
- package/src/components/edit/LookupPickerDialog.vue +230 -0
- package/src/components/editors/JsonEditorFoldable.vue +470 -0
- package/src/components/editors/JsonStructuredField.vue +264 -0
- package/src/components/editors/JsonViewer.vue +51 -0
- package/src/components/editors/KeyValueEditor.vue +314 -0
- package/src/components/editors/LanguageEditor.vue +259 -0
- package/src/components/editors/PermissionEditor.vue +558 -0
- package/src/components/editors/ScopeEditor.vue +372 -0
- package/src/components/editors/VanillaJsonEditor.vue +183 -0
- package/src/components/index.ts +83 -0
- package/src/components/item/FieldGroups.vue +392 -0
- package/src/components/layout/AppLayout.vue +1032 -0
- package/src/components/layout/BaseLayout.vue +190 -0
- package/src/components/layout/Breadcrumb.vue +55 -0
- package/src/components/layout/DashboardLayout.vue +104 -0
- package/src/components/layout/FormLayout.vue +256 -0
- package/src/components/layout/ListLayout.vue +278 -0
- package/src/components/layout/PageHeader.vue +156 -0
- package/src/components/layout/PageLayout.vue +126 -0
- package/src/components/layout/PageNav.vue +192 -0
- package/src/components/layout/SidebarBox.vue +87 -0
- package/src/components/layout/Zone.vue +182 -0
- package/src/components/layout/defaults/DefaultBreadcrumb.vue +149 -0
- package/src/components/layout/defaults/DefaultFooter.vue +89 -0
- package/src/components/layout/defaults/DefaultFormActions.vue +67 -0
- package/src/components/layout/defaults/DefaultHeader.vue +78 -0
- package/src/components/layout/defaults/DefaultMenu.vue +188 -0
- package/src/components/layout/defaults/DefaultPagination.vue +75 -0
- package/src/components/layout/defaults/DefaultTable.vue +137 -0
- package/src/components/layout/defaults/DefaultUserInfo.vue +111 -0
- package/src/components/layout/defaults/index.ts +16 -0
- package/src/components/lists/ActionButtons.vue +49 -0
- package/src/components/lists/ActionColumn.vue +40 -0
- package/src/components/lists/FilterBar.vue +54 -0
- package/src/components/lists/ListPage.vue +467 -0
- package/src/components/pages/LoginPage.vue +334 -0
- package/src/components/pages/NotFoundPage.vue +98 -0
- package/src/components/show/ShowDisplay.vue +343 -0
- package/src/components/show/ShowField.vue +67 -0
- package/src/components/show/ShowPage.vue +431 -0
- package/src/composables/index.ts +155 -0
- package/src/composables/useApp.ts +67 -0
- package/src/composables/useAuth.ts +98 -0
- package/src/composables/useBareForm.ts +319 -0
- package/src/composables/useBreadcrumb.ts +252 -0
- package/src/composables/useChildPage.ts +113 -0
- package/src/composables/useCurrentEntity.ts +60 -0
- package/src/composables/useDeferred.ts +94 -0
- package/src/composables/useDirtyState.ts +138 -0
- package/src/composables/useEntityItemFormPage.ts +942 -0
- package/src/composables/useEntityItemFormPage.types.ts +451 -0
- package/src/composables/useEntityItemPage.ts +438 -0
- package/src/composables/useEntityItemShowPage.ts +722 -0
- package/src/composables/useFieldManager.ts +692 -0
- package/src/composables/useForm.ts +544 -0
- package/src/composables/useGuardStore.ts +53 -0
- package/src/composables/useHooks.ts +56 -0
- package/src/composables/useInfoBanner.ts +217 -0
- package/src/composables/useJsonSyntax.ts +122 -0
- package/src/composables/useLayoutResolver.ts +329 -0
- package/src/composables/useListPage.ts +1535 -0
- package/src/composables/useListPage.types.ts +437 -0
- package/src/composables/useListPage.utils.ts +101 -0
- package/src/composables/useNavContext.ts +439 -0
- package/src/composables/useNavigation.ts +216 -0
- package/src/composables/useOptionsLookup.ts +323 -0
- package/src/composables/usePageTitle.ts +84 -0
- package/src/composables/useSSEBridge.ts +142 -0
- package/src/composables/useSemanticBreadcrumb.ts +222 -0
- package/src/composables/useSidebarState.ts +24 -0
- package/src/composables/useSignals.ts +52 -0
- package/src/composables/useUnsavedChangesGuard.ts +155 -0
- package/src/composables/useUserImpersonator.ts +317 -0
- package/src/composables/useZoneRegistry.ts +252 -0
- package/src/core/bundles.ts +558 -0
- package/src/core/decorator.ts +420 -0
- package/src/core/extension.ts +470 -0
- package/src/core/index.ts +59 -0
- package/src/deferred/DeferredRegistry.ts +353 -0
- package/src/deferred/index.ts +15 -0
- package/src/editors/index.ts +12 -0
- package/src/entity/EntityManager.cache.ts +530 -0
- package/src/entity/EntityManager.crud.ts +615 -0
- package/src/entity/EntityManager.interface.ts +78 -0
- package/src/entity/EntityManager.query.ts +221 -0
- package/src/entity/EntityManager.relations.ts +151 -0
- package/src/entity/EntityManager.ts +944 -0
- package/src/entity/EntityManager.types.ts +288 -0
- package/src/entity/auth/CompositeAuthAdapter.ts +194 -0
- package/src/entity/auth/EntityAuthAdapter.ts +119 -0
- package/src/entity/auth/PermissiveAdapter.ts +43 -0
- package/src/entity/auth/RoleHierarchy.ts +128 -0
- package/src/entity/auth/SecurityChecker.ts +202 -0
- package/src/entity/auth/factory.ts +203 -0
- package/src/entity/auth/index.ts +47 -0
- package/src/entity/factory.test.js +189 -0
- package/src/entity/factory.ts +146 -0
- package/src/entity/index.ts +49 -0
- package/src/entity/storage/ApiStorage.ts +228 -0
- package/src/entity/storage/IStorage.ts +100 -0
- package/src/entity/storage/LocalStorage.ts +200 -0
- package/src/entity/storage/MemoryStorage.ts +184 -0
- package/src/entity/storage/MockApiStorage.ts +318 -0
- package/src/entity/storage/SdkStorage.ts +377 -0
- package/src/entity/storage/factory.test.js +159 -0
- package/src/entity/storage/factory.ts +209 -0
- package/src/entity/storage/index.ts +75 -0
- package/src/gen/FieldMapper.ts +122 -0
- package/src/gen/StorageProfileFactory.ts +93 -0
- package/src/gen/connectors/BaseConnector.ts +150 -0
- package/src/gen/connectors/ManualConnector.test.js +499 -0
- package/src/gen/connectors/ManualConnector.ts +414 -0
- package/src/gen/connectors/OpenAPIConnector.test.js +836 -0
- package/src/gen/connectors/OpenAPIConnector.ts +693 -0
- package/src/gen/connectors/__fixtures__/sample-openapi.json +311 -0
- package/src/gen/connectors/index.ts +27 -0
- package/src/gen/createManagers.ts +245 -0
- package/src/gen/decorators.ts +134 -0
- package/src/gen/generateManagers.test.js +540 -0
- package/src/gen/generateManagers.ts +398 -0
- package/src/gen/index.ts +66 -0
- package/src/gen/schema.ts +248 -0
- package/src/gen/vite-plugin.ts +114 -0
- package/src/generated/managers/testManager.js +45 -0
- package/src/generated/managers/testManager.ts +46 -0
- package/src/hooks/HookRegistry.ts +16 -0
- package/src/hooks/index.ts +15 -0
- package/src/i18n/I18n.ts +344 -0
- package/src/i18n/IncrementalDomainProvider.ts +153 -0
- package/src/i18n/InlineTranslationProvider.ts +4 -0
- package/src/i18n/LazyTranslationProvider.ts +102 -0
- package/src/i18n/MessagesRegistry.ts +4 -0
- package/src/i18n/Resolver.ts +4 -0
- package/src/i18n/__tests__/I18n.test.ts +169 -0
- package/src/i18n/__tests__/IncrementalDomainProvider.test.ts +146 -0
- package/src/i18n/__tests__/LazyTranslationProvider.test.ts +100 -0
- package/src/i18n/__tests__/Resolver.test.ts +271 -0
- package/src/i18n/defaults/DefaultCoreProvider.ts +28 -0
- package/src/i18n/defaults/core.en.yml +55 -0
- package/src/i18n/defaults/core.fr.yml +55 -0
- package/src/i18n/index.ts +55 -0
- package/src/i18n/loaders/raw-modules.d.ts +15 -0
- package/src/i18n/loaders/yaml.ts +35 -0
- package/src/i18n/strategies.ts +4 -0
- package/src/i18n/types.ts +34 -0
- package/src/i18n/useI18n.ts +34 -0
- package/src/index.ts +453 -0
- package/src/kernel/EventRouter.ts +23 -0
- package/src/kernel/Kernel.api.ts +79 -0
- package/src/kernel/Kernel.auth.ts +120 -0
- package/src/kernel/Kernel.i18n.ts +29 -0
- package/src/kernel/Kernel.modules.ts +170 -0
- package/src/kernel/Kernel.registries.ts +237 -0
- package/src/kernel/Kernel.routing.ts +334 -0
- package/src/kernel/Kernel.ts +460 -0
- package/src/kernel/Kernel.types.ts +263 -0
- package/src/kernel/Kernel.vue.ts +304 -0
- package/src/kernel/KernelContext.entities.ts +80 -0
- package/src/kernel/KernelContext.events.ts +57 -0
- package/src/kernel/KernelContext.i18n.ts +37 -0
- package/src/kernel/KernelContext.permissions.ts +38 -0
- package/src/kernel/KernelContext.routing.ts +280 -0
- package/src/kernel/KernelContext.ts +252 -0
- package/src/kernel/KernelContext.types.ts +173 -0
- package/src/kernel/KernelContext.zones.ts +54 -0
- package/src/kernel/Module.ts +169 -0
- package/src/kernel/ModuleLoader.ts +645 -0
- package/src/kernel/SSEBridge.ts +11 -0
- package/src/kernel/SignalBus.ts +48 -0
- package/src/kernel/index.ts +56 -0
- package/src/module/index.ts +33 -0
- package/src/module/moduleRegistry.ts +492 -0
- package/src/modules/debug/AuthCollector.ts +501 -0
- package/src/modules/debug/Collector.ts +20 -0
- package/src/modules/debug/DebugBridge.ts +14 -0
- package/src/modules/debug/DebugModule.ts +220 -0
- package/src/modules/debug/EntitiesCollector.ts +839 -0
- package/src/modules/debug/ErrorCollector.ts +4 -0
- package/src/modules/debug/I18nCollector.ts +9 -0
- package/src/modules/debug/LocalStorageAdapter.ts +7 -0
- package/src/modules/debug/RouterCollector.ts +449 -0
- package/src/modules/debug/SignalCollector.ts +4 -0
- package/src/modules/debug/ToastCollector.ts +4 -0
- package/src/modules/debug/ZonesCollector.ts +447 -0
- package/src/modules/debug/components/DebugBar.vue +31 -0
- package/src/modules/debug/components/adminPanelsConfig.ts +42 -0
- package/src/modules/debug/components/index.ts +9 -0
- package/src/modules/debug/components/panels/AuthPanel.vue +267 -0
- package/src/modules/debug/components/panels/EntitiesPanel.vue +572 -0
- package/src/modules/debug/components/panels/I18nPanel.vue +738 -0
- package/src/modules/debug/components/panels/RouterPanel.vue +440 -0
- package/src/modules/debug/components/panels/ZonesPanel.vue +133 -0
- package/src/modules/debug/components/panels/index.ts +16 -0
- package/src/modules/debug/index.ts +58 -0
- package/src/modules/debug/styles.scss +2671 -0
- package/src/notifications/NotificationBadge.vue +35 -0
- package/src/notifications/NotificationListener.vue +71 -0
- package/src/notifications/NotificationModule.ts +76 -0
- package/src/notifications/NotificationPanel.vue +478 -0
- package/src/notifications/NotificationStore.ts +288 -0
- package/src/notifications/index.ts +42 -0
- package/src/notifications/styles.scss +32 -0
- package/src/orchestrator/Orchestrator.ts +427 -0
- package/src/orchestrator/index.ts +8 -0
- package/src/orchestrator/useOrchestrator.ts +80 -0
- package/src/plugin.ts +251 -0
- package/src/query/FilterQuery.ts +306 -0
- package/src/query/QueryExecutor.ts +341 -0
- package/src/query/index.ts +16 -0
- package/src/security/EntityRolesProvider.ts +385 -0
- package/src/security/PermissionMatcher.ts +152 -0
- package/src/security/PermissionRegistry.ts +273 -0
- package/src/security/PersistableRolesProvider.ts +584 -0
- package/src/security/RolesManager.ts +136 -0
- package/src/security/RolesProvider.ts +167 -0
- package/src/security/RolesProviderStorage.ts +211 -0
- package/src/security/SecurityModule.ts +94 -0
- package/src/security/StaticRolesProvider.ts +117 -0
- package/src/security/UsersManager.ts +163 -0
- package/src/security/index.ts +77 -0
- package/src/security/pages/RoleForm.vue +276 -0
- package/src/security/pages/RoleList.vue +123 -0
- package/src/styles/_alerts.scss +95 -0
- package/src/styles/_buttons.scss +391 -0
- package/src/styles/_cards.scss +241 -0
- package/src/styles/_code.scss +78 -0
- package/src/styles/_dialogs.scss +55 -0
- package/src/styles/_filter-bar.scss +70 -0
- package/src/styles/_forms.scss +434 -0
- package/src/styles/_helpers.scss +153 -0
- package/src/styles/_lists.scss +225 -0
- package/src/styles/_main.scss +356 -0
- package/src/styles/_markdown.scss +88 -0
- package/src/styles/_responsive.scss +255 -0
- package/src/styles/_show-pages.scss +186 -0
- package/src/styles/_sidebar.scss +380 -0
- package/src/styles/_states.scss +115 -0
- package/src/styles/_stats.scss +47 -0
- package/src/styles/_variables.scss +224 -0
- package/src/styles/index.scss +38 -0
- package/src/styles/theme/_components.scss +331 -0
- package/src/styles/theme/_index.scss +10 -0
- package/src/styles/theme/_tokens.scss +147 -0
- package/src/styles/theme/_utilities.scss +175 -0
- package/src/toast/ToastBridgeModule.ts +68 -0
- package/src/toast/ToastListener.vue +55 -0
- package/src/toast/index.ts +26 -0
- package/src/toast/useSignalToast.ts +154 -0
- package/src/types/index.ts +285 -0
- package/src/types/pluralize.d.ts +19 -0
- package/src/types/quarkernel.d.ts +50 -0
- package/src/utils/formatters.ts +174 -0
- package/src/utils/index.ts +35 -0
- package/src/utils/transformers.ts +131 -0
- package/src/vite/qdadmDebugPlugin.ts +401 -0
- package/src/vite-env.d.ts +50 -0
- package/src/zones/ZoneRegistry.ts +934 -0
- package/src/zones/index.ts +29 -0
- package/src/zones/zones.ts +191 -0
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* extendModule - Module extension helper for qdadm
|
|
3
|
+
*
|
|
4
|
+
* Provides a clean API for one module to extend another module's
|
|
5
|
+
* configuration and behavior through the hook system.
|
|
6
|
+
*
|
|
7
|
+
* Extension types:
|
|
8
|
+
* - columns: adds columns via `{target}:list:alter` hook
|
|
9
|
+
* - fields: adds fields via `{target}:form:alter` hook
|
|
10
|
+
* - filters: adds filters via `{target}:filter:alter` hook
|
|
11
|
+
* - blocks: injects blocks via zone registry
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* // Simple config object approach
|
|
15
|
+
* const cleanup = extendModule('books', {
|
|
16
|
+
* columns: [
|
|
17
|
+
* { field: 'rating', header: 'Rating', width: 100 }
|
|
18
|
+
* ],
|
|
19
|
+
* fields: [
|
|
20
|
+
* { name: 'rating', type: 'number', label: 'Rating' }
|
|
21
|
+
* ],
|
|
22
|
+
* blocks: {
|
|
23
|
+
* 'books:detail:sidebar': [
|
|
24
|
+
* { component: RatingWidget, weight: 20 }
|
|
25
|
+
* ]
|
|
26
|
+
* }
|
|
27
|
+
* }, { hooks, zones })
|
|
28
|
+
*
|
|
29
|
+
* // Later: cleanup() // Removes all registered extensions
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* // Fluent API approach
|
|
33
|
+
* const cleanup = extendModule('books')
|
|
34
|
+
* .addColumn({ field: 'rating', header: 'Rating' })
|
|
35
|
+
* .addField({ name: 'rating', type: 'number' })
|
|
36
|
+
* .addBlock('books:detail:sidebar', { component: RatingWidget })
|
|
37
|
+
* .register({ hooks, zones })
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
import type { Component } from 'vue'
|
|
41
|
+
import type { HookRegistry } from '../hooks/HookRegistry'
|
|
42
|
+
import type { ZoneRegistry } from '../zones/ZoneRegistry'
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Default priority for extension hooks
|
|
46
|
+
*/
|
|
47
|
+
const DEFAULT_PRIORITY = 50
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Column configuration
|
|
51
|
+
*/
|
|
52
|
+
export interface ExtensionColumn {
|
|
53
|
+
field: string
|
|
54
|
+
header?: string
|
|
55
|
+
width?: number
|
|
56
|
+
body?: (data: unknown) => unknown
|
|
57
|
+
[key: string]: unknown
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Field configuration
|
|
62
|
+
*/
|
|
63
|
+
export interface ExtensionField {
|
|
64
|
+
name: string
|
|
65
|
+
type?: string
|
|
66
|
+
label?: string
|
|
67
|
+
[key: string]: unknown
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Filter configuration
|
|
72
|
+
*/
|
|
73
|
+
export interface ExtensionFilter {
|
|
74
|
+
name: string
|
|
75
|
+
type?: string
|
|
76
|
+
label?: string
|
|
77
|
+
[key: string]: unknown
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Block configuration
|
|
82
|
+
*/
|
|
83
|
+
export interface ExtensionBlock {
|
|
84
|
+
component: Component
|
|
85
|
+
weight?: number
|
|
86
|
+
props?: Record<string, unknown>
|
|
87
|
+
id?: string
|
|
88
|
+
[key: string]: unknown
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Extensions config object
|
|
93
|
+
*/
|
|
94
|
+
export interface ExtensionsConfig {
|
|
95
|
+
columns?: ExtensionColumn[]
|
|
96
|
+
fields?: ExtensionField[]
|
|
97
|
+
filters?: ExtensionFilter[]
|
|
98
|
+
blocks?: Record<string, ExtensionBlock[]>
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Registration context
|
|
103
|
+
*/
|
|
104
|
+
export interface ExtensionContext {
|
|
105
|
+
hooks: HookRegistry
|
|
106
|
+
zones?: ZoneRegistry
|
|
107
|
+
priority?: number
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Collected extensions config for serialization
|
|
112
|
+
*/
|
|
113
|
+
export interface CollectedExtensions {
|
|
114
|
+
target: string
|
|
115
|
+
columns?: ExtensionColumn[]
|
|
116
|
+
fields?: ExtensionField[]
|
|
117
|
+
filters?: ExtensionFilter[]
|
|
118
|
+
blocks?: Record<string, ExtensionBlock[]>
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Block ID reference for cleanup
|
|
123
|
+
*/
|
|
124
|
+
interface BlockIdRef {
|
|
125
|
+
zoneName: string
|
|
126
|
+
id: string
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Extension builder for fluent API
|
|
131
|
+
*/
|
|
132
|
+
export class ExtensionBuilder {
|
|
133
|
+
private _target: string
|
|
134
|
+
private _columns: ExtensionColumn[]
|
|
135
|
+
private _fields: ExtensionField[]
|
|
136
|
+
private _filters: ExtensionFilter[]
|
|
137
|
+
private _blocks: Map<string, ExtensionBlock[]>
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* @param target - Target module name to extend
|
|
141
|
+
*/
|
|
142
|
+
constructor(target: string) {
|
|
143
|
+
if (!target || typeof target !== 'string') {
|
|
144
|
+
throw new Error('[extendModule] Target module name must be a non-empty string')
|
|
145
|
+
}
|
|
146
|
+
this._target = target
|
|
147
|
+
this._columns = []
|
|
148
|
+
this._fields = []
|
|
149
|
+
this._filters = []
|
|
150
|
+
this._blocks = new Map()
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Add a column to the target module's list view
|
|
155
|
+
*
|
|
156
|
+
* @param column - Column configuration
|
|
157
|
+
* @returns This instance for chaining
|
|
158
|
+
*/
|
|
159
|
+
addColumn(column: ExtensionColumn): this {
|
|
160
|
+
if (!column || !column.field) {
|
|
161
|
+
throw new Error('[extendModule] Column must have a field property')
|
|
162
|
+
}
|
|
163
|
+
this._columns.push(column)
|
|
164
|
+
return this
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Add multiple columns to the target module's list view
|
|
169
|
+
*
|
|
170
|
+
* @param columns - Array of column configurations
|
|
171
|
+
* @returns This instance for chaining
|
|
172
|
+
*/
|
|
173
|
+
addColumns(columns: ExtensionColumn[]): this {
|
|
174
|
+
if (!Array.isArray(columns)) {
|
|
175
|
+
throw new Error('[extendModule] addColumns expects an array')
|
|
176
|
+
}
|
|
177
|
+
for (const column of columns) {
|
|
178
|
+
this.addColumn(column)
|
|
179
|
+
}
|
|
180
|
+
return this
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Add a field to the target module's form view
|
|
185
|
+
*
|
|
186
|
+
* @param field - Field configuration
|
|
187
|
+
* @returns This instance for chaining
|
|
188
|
+
*/
|
|
189
|
+
addField(field: ExtensionField): this {
|
|
190
|
+
if (!field || !field.name) {
|
|
191
|
+
throw new Error('[extendModule] Field must have a name property')
|
|
192
|
+
}
|
|
193
|
+
this._fields.push(field)
|
|
194
|
+
return this
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Add multiple fields to the target module's form view
|
|
199
|
+
*
|
|
200
|
+
* @param fields - Array of field configurations
|
|
201
|
+
* @returns This instance for chaining
|
|
202
|
+
*/
|
|
203
|
+
addFields(fields: ExtensionField[]): this {
|
|
204
|
+
if (!Array.isArray(fields)) {
|
|
205
|
+
throw new Error('[extendModule] addFields expects an array')
|
|
206
|
+
}
|
|
207
|
+
for (const field of fields) {
|
|
208
|
+
this.addField(field)
|
|
209
|
+
}
|
|
210
|
+
return this
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Add a filter to the target module's filter bar
|
|
215
|
+
*
|
|
216
|
+
* @param filter - Filter configuration
|
|
217
|
+
* @returns This instance for chaining
|
|
218
|
+
*/
|
|
219
|
+
addFilter(filter: ExtensionFilter): this {
|
|
220
|
+
if (!filter || !filter.name) {
|
|
221
|
+
throw new Error('[extendModule] Filter must have a name property')
|
|
222
|
+
}
|
|
223
|
+
this._filters.push(filter)
|
|
224
|
+
return this
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Add multiple filters to the target module's filter bar
|
|
229
|
+
*
|
|
230
|
+
* @param filters - Array of filter configurations
|
|
231
|
+
* @returns This instance for chaining
|
|
232
|
+
*/
|
|
233
|
+
addFilters(filters: ExtensionFilter[]): this {
|
|
234
|
+
if (!Array.isArray(filters)) {
|
|
235
|
+
throw new Error('[extendModule] addFilters expects an array')
|
|
236
|
+
}
|
|
237
|
+
for (const filter of filters) {
|
|
238
|
+
this.addFilter(filter)
|
|
239
|
+
}
|
|
240
|
+
return this
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Add a block to a zone in the target module
|
|
245
|
+
*
|
|
246
|
+
* @param zoneName - Zone name (e.g., 'books:detail:sidebar')
|
|
247
|
+
* @param block - Block configuration
|
|
248
|
+
* @returns This instance for chaining
|
|
249
|
+
*/
|
|
250
|
+
addBlock(zoneName: string, block: ExtensionBlock): this {
|
|
251
|
+
if (!zoneName || typeof zoneName !== 'string') {
|
|
252
|
+
throw new Error('[extendModule] Zone name must be a non-empty string')
|
|
253
|
+
}
|
|
254
|
+
if (!block || !block.component) {
|
|
255
|
+
throw new Error('[extendModule] Block must have a component property')
|
|
256
|
+
}
|
|
257
|
+
if (!this._blocks.has(zoneName)) {
|
|
258
|
+
this._blocks.set(zoneName, [])
|
|
259
|
+
}
|
|
260
|
+
this._blocks.get(zoneName)!.push(block)
|
|
261
|
+
return this
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Add multiple blocks to a zone
|
|
266
|
+
*
|
|
267
|
+
* @param zoneName - Zone name
|
|
268
|
+
* @param blocks - Array of block configurations
|
|
269
|
+
* @returns This instance for chaining
|
|
270
|
+
*/
|
|
271
|
+
addBlocks(zoneName: string, blocks: ExtensionBlock[]): this {
|
|
272
|
+
if (!Array.isArray(blocks)) {
|
|
273
|
+
throw new Error('[extendModule] addBlocks expects an array')
|
|
274
|
+
}
|
|
275
|
+
for (const block of blocks) {
|
|
276
|
+
this.addBlock(zoneName, block)
|
|
277
|
+
}
|
|
278
|
+
return this
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Register all extensions with the kernel
|
|
283
|
+
*
|
|
284
|
+
* @param context - Registration context
|
|
285
|
+
* @returns Cleanup function to remove all extensions
|
|
286
|
+
*/
|
|
287
|
+
register(context: ExtensionContext): () => void {
|
|
288
|
+
if (!context || !context.hooks) {
|
|
289
|
+
throw new Error('[extendModule] register() requires { hooks } context')
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const { hooks, zones, priority = DEFAULT_PRIORITY } = context
|
|
293
|
+
const cleanupFns: Array<() => void> = []
|
|
294
|
+
|
|
295
|
+
// Register column alter hook
|
|
296
|
+
if (this._columns.length > 0) {
|
|
297
|
+
const hookName = `${this._target}:list:alter`
|
|
298
|
+
const columns = [...this._columns]
|
|
299
|
+
const unbind = hooks.register(
|
|
300
|
+
hookName,
|
|
301
|
+
(config) => {
|
|
302
|
+
const cfg = config as { columns?: ExtensionColumn[] }
|
|
303
|
+
if (!cfg.columns) {
|
|
304
|
+
cfg.columns = []
|
|
305
|
+
}
|
|
306
|
+
cfg.columns.push(...columns)
|
|
307
|
+
return config
|
|
308
|
+
},
|
|
309
|
+
{ priority }
|
|
310
|
+
)
|
|
311
|
+
cleanupFns.push(unbind)
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Register field alter hook
|
|
315
|
+
if (this._fields.length > 0) {
|
|
316
|
+
const hookName = `${this._target}:form:alter`
|
|
317
|
+
const fields = [...this._fields]
|
|
318
|
+
const unbind = hooks.register(
|
|
319
|
+
hookName,
|
|
320
|
+
(config) => {
|
|
321
|
+
const cfg = config as { fields?: ExtensionField[] }
|
|
322
|
+
if (!cfg.fields) {
|
|
323
|
+
cfg.fields = []
|
|
324
|
+
}
|
|
325
|
+
cfg.fields.push(...fields)
|
|
326
|
+
return config
|
|
327
|
+
},
|
|
328
|
+
{ priority }
|
|
329
|
+
)
|
|
330
|
+
cleanupFns.push(unbind)
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Register filter alter hook
|
|
334
|
+
if (this._filters.length > 0) {
|
|
335
|
+
const hookName = `${this._target}:filter:alter`
|
|
336
|
+
const filters = [...this._filters]
|
|
337
|
+
const unbind = hooks.register(
|
|
338
|
+
hookName,
|
|
339
|
+
(config) => {
|
|
340
|
+
const cfg = config as { filters?: ExtensionFilter[] }
|
|
341
|
+
if (!cfg.filters) {
|
|
342
|
+
cfg.filters = []
|
|
343
|
+
}
|
|
344
|
+
cfg.filters.push(...filters)
|
|
345
|
+
return config
|
|
346
|
+
},
|
|
347
|
+
{ priority }
|
|
348
|
+
)
|
|
349
|
+
cleanupFns.push(unbind)
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// Register zone blocks
|
|
353
|
+
if (this._blocks.size > 0) {
|
|
354
|
+
if (!zones) {
|
|
355
|
+
throw new Error('[extendModule] register() requires { zones } context when blocks are defined')
|
|
356
|
+
}
|
|
357
|
+
for (const [zoneName, blocks] of this._blocks) {
|
|
358
|
+
for (const block of blocks) {
|
|
359
|
+
zones.registerBlock(zoneName, block)
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
// Zone blocks cleanup: store zone/id pairs for removal
|
|
363
|
+
const blockIds: BlockIdRef[] = []
|
|
364
|
+
for (const [zoneName, blocks] of this._blocks) {
|
|
365
|
+
for (const block of blocks) {
|
|
366
|
+
if (block.id) {
|
|
367
|
+
blockIds.push({ zoneName, id: block.id })
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
if (blockIds.length > 0) {
|
|
372
|
+
cleanupFns.push(() => {
|
|
373
|
+
for (const { zoneName, id } of blockIds) {
|
|
374
|
+
zones.removeBlock(zoneName, id)
|
|
375
|
+
}
|
|
376
|
+
})
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// Return cleanup function
|
|
381
|
+
return () => {
|
|
382
|
+
for (const cleanup of cleanupFns) {
|
|
383
|
+
cleanup()
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Get collected extensions as a config object
|
|
390
|
+
*
|
|
391
|
+
* Useful for debugging or serialization.
|
|
392
|
+
*
|
|
393
|
+
* @returns Extensions config
|
|
394
|
+
*/
|
|
395
|
+
toConfig(): CollectedExtensions {
|
|
396
|
+
const config: CollectedExtensions = {
|
|
397
|
+
target: this._target,
|
|
398
|
+
}
|
|
399
|
+
if (this._columns.length > 0) {
|
|
400
|
+
config.columns = [...this._columns]
|
|
401
|
+
}
|
|
402
|
+
if (this._fields.length > 0) {
|
|
403
|
+
config.fields = [...this._fields]
|
|
404
|
+
}
|
|
405
|
+
if (this._filters.length > 0) {
|
|
406
|
+
config.filters = [...this._filters]
|
|
407
|
+
}
|
|
408
|
+
if (this._blocks.size > 0) {
|
|
409
|
+
config.blocks = {}
|
|
410
|
+
for (const [zoneName, blocks] of this._blocks) {
|
|
411
|
+
config.blocks[zoneName] = [...blocks]
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
return config
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Create an extension for a target module
|
|
420
|
+
*
|
|
421
|
+
* Can be used in two ways:
|
|
422
|
+
* 1. Fluent API: extendModule('target').addColumn(...).register({ hooks })
|
|
423
|
+
* 2. Config object: extendModule('target', { columns: [...] }, { hooks })
|
|
424
|
+
*
|
|
425
|
+
* @param target - Target module name to extend
|
|
426
|
+
* @param extensions - Optional extensions config object
|
|
427
|
+
* @param context - Registration context (required if extensions provided)
|
|
428
|
+
* @returns Builder for fluent API, or cleanup function if extensions provided
|
|
429
|
+
*/
|
|
430
|
+
export function extendModule(target: string): ExtensionBuilder
|
|
431
|
+
export function extendModule(
|
|
432
|
+
target: string,
|
|
433
|
+
extensions: ExtensionsConfig,
|
|
434
|
+
context: ExtensionContext
|
|
435
|
+
): () => void
|
|
436
|
+
export function extendModule(
|
|
437
|
+
target: string,
|
|
438
|
+
extensions?: ExtensionsConfig,
|
|
439
|
+
context?: ExtensionContext
|
|
440
|
+
): ExtensionBuilder | (() => void) {
|
|
441
|
+
const builder = new ExtensionBuilder(target)
|
|
442
|
+
|
|
443
|
+
// If no extensions provided, return builder for fluent API
|
|
444
|
+
if (!extensions) {
|
|
445
|
+
return builder
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// Config object approach: apply extensions and register immediately
|
|
449
|
+
if (extensions.columns) {
|
|
450
|
+
builder.addColumns(extensions.columns)
|
|
451
|
+
}
|
|
452
|
+
if (extensions.fields) {
|
|
453
|
+
builder.addFields(extensions.fields)
|
|
454
|
+
}
|
|
455
|
+
if (extensions.filters) {
|
|
456
|
+
builder.addFilters(extensions.filters)
|
|
457
|
+
}
|
|
458
|
+
if (extensions.blocks) {
|
|
459
|
+
for (const [zoneName, blocks] of Object.entries(extensions.blocks)) {
|
|
460
|
+
builder.addBlocks(zoneName, blocks)
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// Context required for config object approach
|
|
465
|
+
if (!context) {
|
|
466
|
+
throw new Error('[extendModule] Context { hooks } is required when extensions are provided')
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
return builder.register(context)
|
|
470
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core Module
|
|
3
|
+
*
|
|
4
|
+
* Extension and helper utilities for qdadm modules.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export {
|
|
8
|
+
extendModule,
|
|
9
|
+
ExtensionBuilder,
|
|
10
|
+
type ExtensionColumn,
|
|
11
|
+
type ExtensionField,
|
|
12
|
+
type ExtensionFilter,
|
|
13
|
+
type ExtensionBlock,
|
|
14
|
+
type ExtensionsConfig,
|
|
15
|
+
type ExtensionContext,
|
|
16
|
+
type CollectedExtensions,
|
|
17
|
+
} from './extension'
|
|
18
|
+
|
|
19
|
+
export {
|
|
20
|
+
createDecoratedManager,
|
|
21
|
+
withValidation,
|
|
22
|
+
withAuditLog as withAuditLogDecorator,
|
|
23
|
+
withSoftDelete as withSoftDeleteDecorator,
|
|
24
|
+
withTimestamps as withTimestampsDecorator,
|
|
25
|
+
type DecoratorEntityManager,
|
|
26
|
+
type ManagerDecorator,
|
|
27
|
+
type AuditLogDetails,
|
|
28
|
+
type AuditLogger,
|
|
29
|
+
type AuditLogDecoratorOptions,
|
|
30
|
+
type SoftDeleteDecoratorOptions,
|
|
31
|
+
type TimestampDecoratorOptions,
|
|
32
|
+
type ValidationContext,
|
|
33
|
+
type ValidationErrors,
|
|
34
|
+
type ValidatorFn,
|
|
35
|
+
type ValidationError,
|
|
36
|
+
type ValidationDecoratorOptions,
|
|
37
|
+
} from './decorator'
|
|
38
|
+
|
|
39
|
+
export {
|
|
40
|
+
createHookBundle,
|
|
41
|
+
applyBundle,
|
|
42
|
+
applyBundles,
|
|
43
|
+
withSoftDelete,
|
|
44
|
+
withTimestamps,
|
|
45
|
+
withVersioning,
|
|
46
|
+
withAuditLog,
|
|
47
|
+
type BundleRegisterFn,
|
|
48
|
+
type BundleContext,
|
|
49
|
+
type BundleSetupFn,
|
|
50
|
+
type Bundle,
|
|
51
|
+
type BundleFactory,
|
|
52
|
+
type ApplyBundleContext,
|
|
53
|
+
type SoftDeleteOptions,
|
|
54
|
+
type TimestampOptions,
|
|
55
|
+
type VersioningOptions,
|
|
56
|
+
type VersionConflictError,
|
|
57
|
+
type AuditLogOptions,
|
|
58
|
+
type AuditLogEntry,
|
|
59
|
+
} from './bundles'
|