@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,427 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Orchestrator - Manager of EntityManagers
|
|
3
|
+
*
|
|
4
|
+
* Central registry that creates and distributes EntityManagers.
|
|
5
|
+
* Uses a factory function provided by the consuming application.
|
|
6
|
+
* Entity configs can be declared by modules via registry.addEntity().
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* ```js
|
|
10
|
+
* // Dashboard provides a factory that receives (name, config)
|
|
11
|
+
* const entityFactory = (entityName, entityConfig) => {
|
|
12
|
+
* // entityConfig comes from registry.addEntity() or is undefined
|
|
13
|
+
* if (entityConfig instanceof EntityManager) {
|
|
14
|
+
* return entityConfig // Module provided a custom manager
|
|
15
|
+
* }
|
|
16
|
+
* return new EntityManager({
|
|
17
|
+
* name: entityName,
|
|
18
|
+
* storage: new ApiStorage({
|
|
19
|
+
* endpoint: entityConfig?.endpoint || `/${entityName}`,
|
|
20
|
+
* client
|
|
21
|
+
* })
|
|
22
|
+
* })
|
|
23
|
+
* }
|
|
24
|
+
*
|
|
25
|
+
* const orchestrator = new Orchestrator({ entityFactory })
|
|
26
|
+
*
|
|
27
|
+
* // Get managers (created lazily)
|
|
28
|
+
* const usersManager = orchestrator.get('users')
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
import { getEntityConfig } from '../module/moduleRegistry'
|
|
32
|
+
import type { EntityManager, EntityManagerOptions } from '../entity/EntityManager'
|
|
33
|
+
import type { EntityRecord } from '../types'
|
|
34
|
+
import type { SignalBus } from '../kernel/SignalBus'
|
|
35
|
+
import type { HookRegistry } from '../hooks/HookRegistry'
|
|
36
|
+
import type { EntityAuthAdapter } from '../entity/auth/EntityAuthAdapter'
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* DeferredRegistry interface (minimal for Orchestrator needs)
|
|
40
|
+
*/
|
|
41
|
+
export interface DeferredRegistry {
|
|
42
|
+
has(key: string): boolean
|
|
43
|
+
await(key: string): Promise<unknown>
|
|
44
|
+
queue<T>(key: string, fn: () => Promise<T>): Promise<T>
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Entity factory function type
|
|
49
|
+
*/
|
|
50
|
+
export type EntityFactory = (
|
|
51
|
+
entityName: string,
|
|
52
|
+
entityConfig: EntityManagerOptions | EntityManager | undefined
|
|
53
|
+
) => EntityManager | null
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Toast options
|
|
57
|
+
*/
|
|
58
|
+
export interface ToastOptions {
|
|
59
|
+
life?: number
|
|
60
|
+
emitter?: string
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Toast config for default life durations
|
|
65
|
+
*/
|
|
66
|
+
export interface ToastConfig {
|
|
67
|
+
success?: number
|
|
68
|
+
error?: number
|
|
69
|
+
warn?: number
|
|
70
|
+
info?: number
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Toast helper interface
|
|
75
|
+
*/
|
|
76
|
+
export interface ToastHelper {
|
|
77
|
+
success(summary: string, detail?: string, options?: string | ToastOptions): void
|
|
78
|
+
error(summary: string, detail?: string, options?: string | ToastOptions): void
|
|
79
|
+
warn(summary: string, detail?: string, options?: string | ToastOptions): void
|
|
80
|
+
info(summary: string, detail?: string, options?: string | ToastOptions): void
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Orchestrator constructor options
|
|
85
|
+
*/
|
|
86
|
+
export interface OrchestratorOptions {
|
|
87
|
+
entityFactory?: EntityFactory | null
|
|
88
|
+
managers?: Record<string, EntityManager>
|
|
89
|
+
signals?: SignalBus | null
|
|
90
|
+
hooks?: HookRegistry | null
|
|
91
|
+
deferred?: DeferredRegistry | null
|
|
92
|
+
entityAuthAdapter?: EntityAuthAdapter | null
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export class Orchestrator {
|
|
96
|
+
private _entityFactory: EntityFactory | null
|
|
97
|
+
private _managers: Map<string, EntityManager>
|
|
98
|
+
private _signals: SignalBus | null
|
|
99
|
+
private _hooks: HookRegistry | null
|
|
100
|
+
private _deferred: DeferredRegistry | null
|
|
101
|
+
private _entityAuthAdapter: EntityAuthAdapter | null
|
|
102
|
+
private _toastConfig: ToastConfig = {}
|
|
103
|
+
private _toastHelper: ToastHelper | null = null
|
|
104
|
+
|
|
105
|
+
// Kernel options (set by Kernel after construction, avoids circular reference)
|
|
106
|
+
kernelOptions?: {
|
|
107
|
+
defaultEntityCacheTtlMs?: number
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
constructor(options: OrchestratorOptions = {}) {
|
|
111
|
+
const {
|
|
112
|
+
entityFactory = null,
|
|
113
|
+
// Optional: pre-registered managers (for special cases)
|
|
114
|
+
managers = {},
|
|
115
|
+
// SignalBus instance for event-driven communication
|
|
116
|
+
signals = null,
|
|
117
|
+
// HookRegistry instance for lifecycle hooks
|
|
118
|
+
hooks = null,
|
|
119
|
+
// DeferredRegistry instance for async warmup
|
|
120
|
+
deferred = null,
|
|
121
|
+
// Optional: AuthAdapter for entity permission checks (scope/silo)
|
|
122
|
+
entityAuthAdapter = null,
|
|
123
|
+
} = options
|
|
124
|
+
|
|
125
|
+
this._entityFactory = entityFactory
|
|
126
|
+
this._managers = new Map()
|
|
127
|
+
this._signals = signals
|
|
128
|
+
this._hooks = hooks
|
|
129
|
+
this._deferred = deferred
|
|
130
|
+
this._entityAuthAdapter = entityAuthAdapter
|
|
131
|
+
|
|
132
|
+
// Register pre-provided managers
|
|
133
|
+
for (const [name, manager] of Object.entries(managers)) {
|
|
134
|
+
this.register(name, manager)
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Set the SignalBus instance
|
|
140
|
+
*/
|
|
141
|
+
setSignals(signals: SignalBus): void {
|
|
142
|
+
this._signals = signals
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Get the SignalBus instance
|
|
147
|
+
*/
|
|
148
|
+
get signals(): SignalBus | null {
|
|
149
|
+
return this._signals
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Set toast configuration (life defaults per severity)
|
|
154
|
+
*/
|
|
155
|
+
setToastConfig(config: ToastConfig): void {
|
|
156
|
+
this._toastConfig = { ...this._toastConfig, ...config }
|
|
157
|
+
this._toastHelper = null // Reset helper to pick up new config
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Toast helper - wraps signal-based toasts
|
|
162
|
+
*
|
|
163
|
+
* Usage:
|
|
164
|
+
* orchestrator.toast.success('Saved', 'Item saved successfully')
|
|
165
|
+
* orchestrator.toast.error('Error', 'Failed to save', 'MyComponent')
|
|
166
|
+
* orchestrator.toast.warn('Warning', 'Check your input', { life: 10000, emitter: 'Custom' })
|
|
167
|
+
*
|
|
168
|
+
* Third param can be:
|
|
169
|
+
* - string: treated as emitter
|
|
170
|
+
* - object: { life, emitter }
|
|
171
|
+
*/
|
|
172
|
+
get toast(): ToastHelper {
|
|
173
|
+
if (!this._toastHelper) {
|
|
174
|
+
// Default life values per severity (can be overridden via setToastConfig)
|
|
175
|
+
const defaults: Required<ToastConfig> = {
|
|
176
|
+
success: 3000,
|
|
177
|
+
error: 5000,
|
|
178
|
+
warn: 5000,
|
|
179
|
+
info: 3000,
|
|
180
|
+
...this._toastConfig,
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const emit = (
|
|
184
|
+
severity: keyof ToastConfig,
|
|
185
|
+
summary: string,
|
|
186
|
+
detail?: string,
|
|
187
|
+
options?: string | ToastOptions
|
|
188
|
+
): void => {
|
|
189
|
+
if (this._signals) {
|
|
190
|
+
// Options can be string (emitter) or object { life, emitter }
|
|
191
|
+
const opts: ToastOptions =
|
|
192
|
+
typeof options === 'string' ? { emitter: options } : options || {}
|
|
193
|
+
this._signals.emit(`toast:${severity}`, {
|
|
194
|
+
summary,
|
|
195
|
+
detail,
|
|
196
|
+
life: opts.life ?? defaults[severity],
|
|
197
|
+
emitter: opts.emitter,
|
|
198
|
+
})
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
this._toastHelper = {
|
|
203
|
+
success: (summary, detail, options) => emit('success', summary, detail, options),
|
|
204
|
+
error: (summary, detail, options) => emit('error', summary, detail, options),
|
|
205
|
+
warn: (summary, detail, options) => emit('warn', summary, detail, options),
|
|
206
|
+
info: (summary, detail, options) => emit('info', summary, detail, options),
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return this._toastHelper
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Set the entity AuthAdapter for permission checks
|
|
214
|
+
* This adapter will be injected into all newly registered managers
|
|
215
|
+
* (unless they already have their own adapter)
|
|
216
|
+
*/
|
|
217
|
+
setEntityAuthAdapter(adapter: EntityAuthAdapter): void {
|
|
218
|
+
this._entityAuthAdapter = adapter
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Get the entity AuthAdapter
|
|
223
|
+
*/
|
|
224
|
+
get entityAuthAdapter(): EntityAuthAdapter | null {
|
|
225
|
+
return this._entityAuthAdapter
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Set the HookRegistry instance
|
|
230
|
+
*/
|
|
231
|
+
setHooks(hooks: HookRegistry): void {
|
|
232
|
+
this._hooks = hooks
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Get the HookRegistry instance
|
|
237
|
+
*/
|
|
238
|
+
get hooks(): HookRegistry | null {
|
|
239
|
+
return this._hooks
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Set the DeferredRegistry instance
|
|
244
|
+
*/
|
|
245
|
+
setDeferred(deferred: DeferredRegistry): void {
|
|
246
|
+
this._deferred = deferred
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Get the DeferredRegistry instance
|
|
251
|
+
*/
|
|
252
|
+
get deferred(): DeferredRegistry | null {
|
|
253
|
+
return this._deferred
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Set the entity factory
|
|
258
|
+
*/
|
|
259
|
+
setFactory(factory: EntityFactory): void {
|
|
260
|
+
this._entityFactory = factory
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Register an EntityManager manually
|
|
265
|
+
* Use this for special managers that don't follow the factory pattern
|
|
266
|
+
*/
|
|
267
|
+
register(name: string, manager: EntityManager): void {
|
|
268
|
+
this._managers.set(name, manager)
|
|
269
|
+
// Pass signals reference to manager for event emission
|
|
270
|
+
if (this._signals && manager.setSignals) {
|
|
271
|
+
manager.setSignals(this._signals)
|
|
272
|
+
}
|
|
273
|
+
// Pass hooks reference to manager for lifecycle hooks
|
|
274
|
+
if (this._hooks && manager.setHooks) {
|
|
275
|
+
manager.setHooks(this._hooks)
|
|
276
|
+
}
|
|
277
|
+
// Inject entityAuthAdapter if provided and manager doesn't have one
|
|
278
|
+
// Manager's own adapter takes precedence (allows per-entity customization)
|
|
279
|
+
const managerWithAuth = manager as EntityManager & { _authAdapter?: unknown }
|
|
280
|
+
if (this._entityAuthAdapter && !managerWithAuth._authAdapter) {
|
|
281
|
+
manager.authAdapter = this._entityAuthAdapter
|
|
282
|
+
}
|
|
283
|
+
if (manager.onRegister) {
|
|
284
|
+
manager.onRegister(this)
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Check if a manager exists (registered or can be created via factory)
|
|
290
|
+
*/
|
|
291
|
+
has(name: string): boolean {
|
|
292
|
+
return this._managers.has(name) || !!this._entityFactory
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Check if a manager is actually registered (not just creatable)
|
|
297
|
+
* Use this to check if ctx.entity() was called for this entity
|
|
298
|
+
*/
|
|
299
|
+
isRegistered(name: string): boolean {
|
|
300
|
+
return this._managers.has(name)
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Get an EntityManager by name
|
|
305
|
+
* Creates it via factory if not already registered
|
|
306
|
+
*/
|
|
307
|
+
get<T extends EntityRecord = EntityRecord>(name: string): EntityManager<T> | undefined {
|
|
308
|
+
// Return existing manager
|
|
309
|
+
if (this._managers.has(name)) {
|
|
310
|
+
return this._managers.get(name) as unknown as EntityManager<T>
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Get entity config from module registry (if declared)
|
|
314
|
+
const entityConfig = getEntityConfig(name) as
|
|
315
|
+
| EntityManagerOptions
|
|
316
|
+
| EntityManager
|
|
317
|
+
| undefined
|
|
318
|
+
|
|
319
|
+
// If config is already an EntityManager, use it directly
|
|
320
|
+
if (entityConfig && typeof (entityConfig as EntityManager).get === 'function') {
|
|
321
|
+
this.register(name, entityConfig as EntityManager)
|
|
322
|
+
return entityConfig as unknown as EntityManager<T>
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Create via factory
|
|
326
|
+
if (this._entityFactory) {
|
|
327
|
+
const manager = this._entityFactory(name, entityConfig)
|
|
328
|
+
if (manager) {
|
|
329
|
+
this.register(name, manager)
|
|
330
|
+
return manager as unknown as EntityManager<T>
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Build helpful error message
|
|
335
|
+
const registered = this.getRegisteredNames()
|
|
336
|
+
const hint =
|
|
337
|
+
registered.length > 0
|
|
338
|
+
? `\nRegistered entities: ${registered.join(', ')}\n`
|
|
339
|
+
: '\nNo entities registered yet.\n'
|
|
340
|
+
|
|
341
|
+
const suggestion = `
|
|
342
|
+
Possible causes:
|
|
343
|
+
1. Entity "${name}" not declared in any module (ctx.entity('${name}', {...}))
|
|
344
|
+
2. Module not loaded (check moduleDefs in config/modules.js)
|
|
345
|
+
3. Typo in entity name
|
|
346
|
+
|
|
347
|
+
Example fix in your module:
|
|
348
|
+
ctx.entity('${name}', {
|
|
349
|
+
name: '${name}',
|
|
350
|
+
labelField: 'name',
|
|
351
|
+
fields: { ... },
|
|
352
|
+
storage: yourStorage
|
|
353
|
+
})`
|
|
354
|
+
|
|
355
|
+
throw new Error(`[Orchestrator] No manager for entity "${name}"${hint}${suggestion}`)
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Get all registered manager names
|
|
360
|
+
*/
|
|
361
|
+
getRegisteredNames(): string[] {
|
|
362
|
+
return Array.from(this._managers.keys())
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Fire warmup for all managers (fire-and-forget)
|
|
367
|
+
*
|
|
368
|
+
* Triggers cache preloading for all managers with warmupEnabled.
|
|
369
|
+
* Each manager registers its warmup in the DeferredRegistry, allowing
|
|
370
|
+
* pages to await specific entities before rendering.
|
|
371
|
+
*
|
|
372
|
+
* IMPORTANT: This is fire-and-forget by design. Don't await this method.
|
|
373
|
+
* Components await what they need via DeferredRegistry:
|
|
374
|
+
* `await deferred.await('entity:books:cache')`
|
|
375
|
+
*
|
|
376
|
+
* @returns For debugging/logging only
|
|
377
|
+
*
|
|
378
|
+
* @example
|
|
379
|
+
* ```js
|
|
380
|
+
* // At boot (fire-and-forget)
|
|
381
|
+
* orchestrator.fireWarmups()
|
|
382
|
+
*
|
|
383
|
+
* // In component - await specific entity cache
|
|
384
|
+
* await deferred.await('entity:books:cache')
|
|
385
|
+
* const { items } = await booksManager.list() // Uses local cache
|
|
386
|
+
* ```
|
|
387
|
+
*/
|
|
388
|
+
fireWarmups(): Map<string, boolean | Error | null> {
|
|
389
|
+
const results = new Map<string, boolean | Error | null>()
|
|
390
|
+
|
|
391
|
+
for (const [name, manager] of this._managers) {
|
|
392
|
+
if (manager.warmup && manager.warmupEnabled) {
|
|
393
|
+
// Fire each warmup - they register themselves in DeferredRegistry
|
|
394
|
+
manager
|
|
395
|
+
.warmup()
|
|
396
|
+
.then((result) => {
|
|
397
|
+
results.set(name, result)
|
|
398
|
+
})
|
|
399
|
+
.catch((error: Error) => {
|
|
400
|
+
console.warn(`[Orchestrator] Warmup failed for ${name}:`, error.message)
|
|
401
|
+
results.set(name, error)
|
|
402
|
+
})
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
return results
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Dispose all managers
|
|
411
|
+
*/
|
|
412
|
+
dispose(): void {
|
|
413
|
+
for (const [, manager] of this._managers) {
|
|
414
|
+
if (manager.onDispose) {
|
|
415
|
+
manager.onDispose()
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
this._managers.clear()
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Factory function to create an Orchestrator
|
|
424
|
+
*/
|
|
425
|
+
export function createOrchestrator(options?: OrchestratorOptions): Orchestrator {
|
|
426
|
+
return new Orchestrator(options)
|
|
427
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Orchestrator Module
|
|
3
|
+
*
|
|
4
|
+
* Manager of EntityManagers - central registry for entity access.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export { Orchestrator, createOrchestrator, type OrchestratorOptions } from './Orchestrator'
|
|
8
|
+
export { useOrchestrator, useEntity, type UseOrchestratorReturn } from './useOrchestrator'
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useOrchestrator - Composable to access the Orchestrator
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* ```ts
|
|
6
|
+
* const { orchestrator, getManager } = useOrchestrator()
|
|
7
|
+
*
|
|
8
|
+
* // Get a specific manager
|
|
9
|
+
* const usersManager = getManager('users')
|
|
10
|
+
*
|
|
11
|
+
* // Use it
|
|
12
|
+
* const { items } = await usersManager.list({ page: 1 })
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
import { inject } from 'vue'
|
|
16
|
+
import type { Orchestrator } from './Orchestrator'
|
|
17
|
+
import type { EntityManager } from '../entity/EntityManager'
|
|
18
|
+
import type { EntityRecord } from '../types'
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Return type for useOrchestrator
|
|
22
|
+
*/
|
|
23
|
+
export interface UseOrchestratorReturn {
|
|
24
|
+
orchestrator: Orchestrator
|
|
25
|
+
getManager: <T extends EntityRecord = EntityRecord>(name: string) => EntityManager<T>
|
|
26
|
+
hasManager: (name: string) => boolean
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function useOrchestrator(): UseOrchestratorReturn {
|
|
30
|
+
const injectedOrchestrator = inject<Orchestrator | undefined>('qdadmOrchestrator')
|
|
31
|
+
|
|
32
|
+
if (!injectedOrchestrator) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
'[qdadm] Orchestrator not provided.\n' +
|
|
35
|
+
'Possible causes:\n' +
|
|
36
|
+
'1. Kernel not initialized - ensure createKernel().createApp() is called before mounting\n' +
|
|
37
|
+
'2. Component used outside of qdadm app context\n' +
|
|
38
|
+
'3. Missing entityFactory in Kernel options'
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Capture after null check for closure
|
|
43
|
+
const orchestrator = injectedOrchestrator
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Get an EntityManager by name
|
|
47
|
+
* @param name - Entity name
|
|
48
|
+
*/
|
|
49
|
+
function getManager<T extends EntityRecord = EntityRecord>(name: string): EntityManager<T> {
|
|
50
|
+
return orchestrator.get(name) as EntityManager<T>
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Check if a manager exists
|
|
55
|
+
* @param name - Entity name
|
|
56
|
+
*/
|
|
57
|
+
function hasManager(name: string): boolean {
|
|
58
|
+
return orchestrator.has(name)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
orchestrator,
|
|
63
|
+
getManager,
|
|
64
|
+
hasManager
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* useEntity - Shorthand composable to get a specific EntityManager
|
|
70
|
+
*
|
|
71
|
+
* Usage:
|
|
72
|
+
* ```ts
|
|
73
|
+
* const users = useEntity('users')
|
|
74
|
+
* const { items } = await users.list()
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export function useEntity<T extends EntityRecord = EntityRecord>(name: string): EntityManager<T> {
|
|
78
|
+
const { getManager } = useOrchestrator()
|
|
79
|
+
return getManager<T>(name)
|
|
80
|
+
}
|