@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,304 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createApp,
|
|
3
|
+
h,
|
|
4
|
+
defineComponent,
|
|
5
|
+
ref,
|
|
6
|
+
type App,
|
|
7
|
+
type Component,
|
|
8
|
+
type Ref,
|
|
9
|
+
} from 'vue'
|
|
10
|
+
import { createPinia } from 'pinia'
|
|
11
|
+
import ToastService from 'primevue/toastservice'
|
|
12
|
+
import ConfirmationService from 'primevue/confirmationservice'
|
|
13
|
+
import Tooltip from 'primevue/tooltip'
|
|
14
|
+
import Toast from 'primevue/toast'
|
|
15
|
+
import ToastListener from '../toast/ToastListener.vue'
|
|
16
|
+
import { createQdadm } from '../plugin.js'
|
|
17
|
+
import { createNotificationStore, NOTIFICATION_KEY } from '../notifications/NotificationStore'
|
|
18
|
+
import { I18N_INJECTION_KEY } from '../i18n/useI18n'
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
20
|
+
type Self = any
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Reactive reference to the debug bar component, set by the Kernel
|
|
24
|
+
* constructor when `debugBar.component` is provided.
|
|
25
|
+
*
|
|
26
|
+
* Why a window-stashed ref instead of a plain module-level export:
|
|
27
|
+
* Vite's HMR can fragment a single source module into multiple live
|
|
28
|
+
* instances (each importer getting a different `?t=…` version after
|
|
29
|
+
* HMR), so a module-level `const ref` is NOT shared across
|
|
30
|
+
* importers. Stashing the ref on `window.__qdadmDebugBarRef` (and
|
|
31
|
+
* lazy-initialising) is the only way to guarantee a single instance
|
|
32
|
+
* across all callers in dev. The Kernel writes via
|
|
33
|
+
* `setQdadmDebugBar()`; `<QdadmRoot />` reads via the same getter.
|
|
34
|
+
*/
|
|
35
|
+
const QDADM_DEBUG_BAR_GLOBAL_KEY = '__qdadmDebugBarRef'
|
|
36
|
+
|
|
37
|
+
export function getQdadmDebugBarRef(): Ref<Component | null> {
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
39
|
+
const w = typeof window !== 'undefined' ? (window as any) : null
|
|
40
|
+
if (w && w[QDADM_DEBUG_BAR_GLOBAL_KEY]) return w[QDADM_DEBUG_BAR_GLOBAL_KEY]
|
|
41
|
+
const r = ref<Component | null>(null)
|
|
42
|
+
if (w) w[QDADM_DEBUG_BAR_GLOBAL_KEY] = r
|
|
43
|
+
return r
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Back-compat alias — same instance as `getQdadmDebugBarRef()`. */
|
|
47
|
+
export const qdadmDebugBarRef: Ref<Component | null> = getQdadmDebugBarRef()
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Set the debug bar component reference (called from Kernel
|
|
51
|
+
* constructor). Equivalent to `getQdadmDebugBarRef().value = component`.
|
|
52
|
+
*/
|
|
53
|
+
export function setQdadmDebugBar(component: Component | null): void {
|
|
54
|
+
getQdadmDebugBarRef().value = component
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Patch Kernel prototype with Vue app creation methods.
|
|
59
|
+
*/
|
|
60
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
61
|
+
export function applyVueMethods(KernelClass: { prototype: any }): void {
|
|
62
|
+
const proto = KernelClass.prototype as Self
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Create layout components map for useLayoutResolver
|
|
66
|
+
*/
|
|
67
|
+
proto._createLayoutComponents = function (this: Self): void {
|
|
68
|
+
const layouts = this.options.layouts || {}
|
|
69
|
+
this.layoutComponents = {
|
|
70
|
+
list: layouts.list || layouts.ListLayout || null,
|
|
71
|
+
form: layouts.form || layouts.FormLayout || null,
|
|
72
|
+
dashboard: layouts.dashboard || layouts.DashboardLayout || null,
|
|
73
|
+
base: layouts.base || layouts.BaseLayout || null,
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Create Vue app instance.
|
|
79
|
+
*
|
|
80
|
+
* When `options.existingApp` is provided, the Kernel reuses the
|
|
81
|
+
* host's app and skips its own `createApp(WrappedRoot)`. The host
|
|
82
|
+
* is then responsible for rendering qdadm's DOM extras (Toast,
|
|
83
|
+
* ToastListener, DebugBar) — see `<QdadmRoot />` for a drop-in
|
|
84
|
+
* helper that does it.
|
|
85
|
+
*
|
|
86
|
+
* `options.root` is ignored in this mode (the host already mounted
|
|
87
|
+
* its own root).
|
|
88
|
+
*/
|
|
89
|
+
proto._createVueApp = function (this: Self): void {
|
|
90
|
+
if (this.options.existingApp) {
|
|
91
|
+
this.vueApp = this.options.existingApp
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (!this.options.root) {
|
|
96
|
+
throw new Error('[Kernel] root component is required (or pass options.existingApp)')
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const OriginalRoot = this.options.root
|
|
100
|
+
const debugBarRef = getQdadmDebugBarRef()
|
|
101
|
+
const DebugBarComponent =
|
|
102
|
+
this.options.debugBar?.component && debugBarRef.value
|
|
103
|
+
? debugBarRef.value
|
|
104
|
+
: null
|
|
105
|
+
const hasPrimeVue = !!this.options.primevue?.plugin
|
|
106
|
+
const appKey = this._appKey
|
|
107
|
+
|
|
108
|
+
const WrappedRoot = defineComponent({
|
|
109
|
+
name: 'QdadmRootWrapper',
|
|
110
|
+
setup() {
|
|
111
|
+
return () => {
|
|
112
|
+
const children = [h(OriginalRoot, { key: appKey.value })]
|
|
113
|
+
|
|
114
|
+
if (hasPrimeVue) {
|
|
115
|
+
children.push(h(Toast))
|
|
116
|
+
children.push(h(ToastListener))
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (DebugBarComponent) {
|
|
120
|
+
children.push(h(DebugBarComponent))
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return h(
|
|
124
|
+
'div',
|
|
125
|
+
{ id: 'qdadm-root', style: 'display: contents' },
|
|
126
|
+
children
|
|
127
|
+
)
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
this.vueApp = createApp(WrappedRoot)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Install all plugins on Vue app.
|
|
137
|
+
*
|
|
138
|
+
* When a host shell uses `existingApp`, it may have already
|
|
139
|
+
* installed Pinia / PrimeVue / vue-router. Calling `app.use(plugin)`
|
|
140
|
+
* twice is harmless for stateless plugins (vue-router, Pinia
|
|
141
|
+
* recognise the duplicate and no-op), but PrimeVue does not — guard
|
|
142
|
+
* with `_qdadmPluginsInstalled` markers on globalProperties so the
|
|
143
|
+
* Kernel never double-installs PrimeVue, ToastService, or
|
|
144
|
+
* ConfirmationService.
|
|
145
|
+
*/
|
|
146
|
+
proto._installPlugins = function (this: Self): void {
|
|
147
|
+
const app = this.vueApp!
|
|
148
|
+
const { authAdapter, features, primevue, existingApp } = this.options
|
|
149
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
150
|
+
const marks = (app.config.globalProperties as any).__qdadmInstalled ??= {
|
|
151
|
+
pinia: false,
|
|
152
|
+
primevue: false,
|
|
153
|
+
router: false,
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (!marks.pinia) {
|
|
157
|
+
app.use(createPinia())
|
|
158
|
+
marks.pinia = true
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (primevue?.plugin && !marks.primevue) {
|
|
162
|
+
const pvConfig = {
|
|
163
|
+
theme: {
|
|
164
|
+
preset: primevue.theme,
|
|
165
|
+
options: {
|
|
166
|
+
darkModeSelector: '.dark-mode',
|
|
167
|
+
...primevue.options,
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
}
|
|
171
|
+
app.use(primevue.plugin as { install: (app: App, options: unknown) => void }, pvConfig)
|
|
172
|
+
app.use(ToastService)
|
|
173
|
+
app.use(ConfirmationService)
|
|
174
|
+
app.directive('tooltip', Tooltip)
|
|
175
|
+
marks.primevue = true
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Skip vue-router install when the host owned the router from the
|
|
179
|
+
// start — they already called `app.use(router)`. Calling it again
|
|
180
|
+
// emits Vue's "Plugin has already been applied" warning. When
|
|
181
|
+
// Kernel created the router itself, install is required.
|
|
182
|
+
if (!marks.router && !this.options.existingRouter) {
|
|
183
|
+
app.use(this.router!)
|
|
184
|
+
marks.router = true
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Avoid eslint unused-var warning when host owns the app
|
|
188
|
+
void existingApp
|
|
189
|
+
|
|
190
|
+
for (const [key, value] of this._pendingProvides) {
|
|
191
|
+
app.provide(key, value)
|
|
192
|
+
}
|
|
193
|
+
this._pendingProvides.clear()
|
|
194
|
+
|
|
195
|
+
for (const [name, component] of this._pendingComponents) {
|
|
196
|
+
app.component(name, component)
|
|
197
|
+
}
|
|
198
|
+
this._pendingComponents.clear()
|
|
199
|
+
|
|
200
|
+
const { homeRoute } = this.options
|
|
201
|
+
const homeRouteName =
|
|
202
|
+
typeof homeRoute === 'object' ? homeRoute?.name : homeRoute
|
|
203
|
+
|
|
204
|
+
app.provide('qdadmZoneRegistry', this.zoneRegistry)
|
|
205
|
+
app.provide('qdadmActiveStack', this.activeStack)
|
|
206
|
+
app.provide('qdadmStackHydrator', this.stackHydrator)
|
|
207
|
+
|
|
208
|
+
if (this.options.debug && typeof window !== 'undefined') {
|
|
209
|
+
const self = this
|
|
210
|
+
// Single namespaced surface for browser-console & agent introspection.
|
|
211
|
+
// The `debug` sub-object proxies to whatever DebugBridge the DebugModule
|
|
212
|
+
// installed (resolved lazily so we don't depend on module load order).
|
|
213
|
+
const debugProxy = {
|
|
214
|
+
get bridge() {
|
|
215
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
216
|
+
const debugMod = (self as any).moduleLoader?.getModules?.()?.get?.('debug')
|
|
217
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
218
|
+
return debugMod?.getBridge?.() ?? (debugMod as any)?._bridge ?? null
|
|
219
|
+
},
|
|
220
|
+
describe(): unknown {
|
|
221
|
+
const b = this.bridge
|
|
222
|
+
return b ? b.describe() : null
|
|
223
|
+
},
|
|
224
|
+
dump(): unknown {
|
|
225
|
+
const b = this.bridge
|
|
226
|
+
return b ? b.dump() : null
|
|
227
|
+
},
|
|
228
|
+
call(name: string, action: string, args: Record<string, unknown> = {}): Promise<unknown> {
|
|
229
|
+
const b = this.bridge
|
|
230
|
+
if (!b) return Promise.reject(new Error('[qdadm] DebugBridge unavailable'))
|
|
231
|
+
return b.call(name, action, args)
|
|
232
|
+
},
|
|
233
|
+
}
|
|
234
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
235
|
+
;(window as any).__qdadm = {
|
|
236
|
+
kernel: this,
|
|
237
|
+
orchestrator: this.orchestrator,
|
|
238
|
+
signals: this.signals,
|
|
239
|
+
hooks: this.hookRegistry,
|
|
240
|
+
zones: this.zoneRegistry,
|
|
241
|
+
activeStack: this.activeStack,
|
|
242
|
+
stackHydrator: this.stackHydrator,
|
|
243
|
+
deferred: this.deferred,
|
|
244
|
+
router: this.router,
|
|
245
|
+
i18n: this.i18nInstance,
|
|
246
|
+
get: (name: string) => this.orchestrator!.get(name),
|
|
247
|
+
managers: () => this.orchestrator!.getRegisteredNames(),
|
|
248
|
+
debug: debugProxy,
|
|
249
|
+
}
|
|
250
|
+
console.debug(
|
|
251
|
+
'[qdadm] Debug mode: window.__qdadm.{kernel,orchestrator,signals,hooks,zones,router,i18n,debug.{describe,dump,call}}'
|
|
252
|
+
)
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
app.provide('qdadmSignals', this.signals)
|
|
256
|
+
|
|
257
|
+
if (this.i18nInstance) {
|
|
258
|
+
app.provide(I18N_INJECTION_KEY, this.i18nInstance)
|
|
259
|
+
app.provide('qdadmI18n', this.i18nInstance)
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (this.sseBridge) {
|
|
263
|
+
app.provide('qdadmSSEBridge', this.sseBridge)
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
app.provide('qdadmHooks', this.hookRegistry)
|
|
267
|
+
app.provide('qdadmDeferred', this.deferred)
|
|
268
|
+
app.provide('qdadmLayoutComponents', this.layoutComponents)
|
|
269
|
+
// Surface PrimeVue presence so host-rendered <QdadmRoot /> can
|
|
270
|
+
// decide whether to mount Toast / ToastListener.
|
|
271
|
+
app.provide('qdadmHasPrimeVue', !!primevue?.plugin)
|
|
272
|
+
|
|
273
|
+
if (this.securityChecker) {
|
|
274
|
+
app.provide('qdadmSecurityChecker', this.securityChecker)
|
|
275
|
+
}
|
|
276
|
+
if (this.permissionRegistry) {
|
|
277
|
+
app.provide('qdadmPermissionRegistry', this.permissionRegistry)
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Create and provide notification store if notifications are enabled
|
|
281
|
+
if (this.options.notifications?.enabled) {
|
|
282
|
+
this.notificationStore = createNotificationStore({
|
|
283
|
+
maxNotifications: this.options.notifications.maxNotifications,
|
|
284
|
+
})
|
|
285
|
+
app.provide(NOTIFICATION_KEY, this.notificationStore)
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
289
|
+
const qdadmOptions: any = {
|
|
290
|
+
orchestrator: this.orchestrator,
|
|
291
|
+
authAdapter,
|
|
292
|
+
router: this.router,
|
|
293
|
+
toast: app.config.globalProperties.$toast,
|
|
294
|
+
app: this.options.app,
|
|
295
|
+
homeRoute: homeRouteName,
|
|
296
|
+
features: {
|
|
297
|
+
auth: !!authAdapter,
|
|
298
|
+
poweredBy: true,
|
|
299
|
+
...features,
|
|
300
|
+
},
|
|
301
|
+
}
|
|
302
|
+
app.use(createQdadm(qdadmOptions) as unknown as { install: (app: App) => void })
|
|
303
|
+
}
|
|
304
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Patch KernelContext prototype with entity registration methods:
|
|
3
|
+
* - entity(name, config) — generic EntityManager registration
|
|
4
|
+
* - userEntity(options) — UsersManager registration with conventions
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { managerFactory, type ManagerFactoryContext } from '../entity/factory.js'
|
|
8
|
+
import type { EntityManager } from '../entity/EntityManager'
|
|
9
|
+
import { UsersManager } from '../security/UsersManager'
|
|
10
|
+
import type { UserEntityOptions } from './KernelContext.types'
|
|
11
|
+
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
13
|
+
type Self = any
|
|
14
|
+
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
16
|
+
export function applyEntityMethods(KernelContextClass: { prototype: any }): void {
|
|
17
|
+
const proto = KernelContextClass.prototype as Self
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Register an entity manager.
|
|
21
|
+
*
|
|
22
|
+
* Uses managerFactory to resolve config into a manager instance.
|
|
23
|
+
* Registers with Orchestrator for CRUD operations.
|
|
24
|
+
*/
|
|
25
|
+
proto.entity = function (
|
|
26
|
+
this: Self,
|
|
27
|
+
name: string,
|
|
28
|
+
config: string | Record<string, unknown> | EntityManager
|
|
29
|
+
): Self {
|
|
30
|
+
const factoryContext = {
|
|
31
|
+
storageResolver: this._kernel.options.storageResolver,
|
|
32
|
+
managerResolver: this._kernel.options.managerResolver,
|
|
33
|
+
managerRegistry: this._kernel.options.managerRegistry || {},
|
|
34
|
+
} as ManagerFactoryContext
|
|
35
|
+
|
|
36
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
37
|
+
const manager = managerFactory(config as any, name, factoryContext)
|
|
38
|
+
|
|
39
|
+
if (this._kernel.orchestrator) {
|
|
40
|
+
this._kernel.orchestrator.register(name, manager)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (this._kernel.permissionRegistry) {
|
|
44
|
+
this._kernel.permissionRegistry.registerEntity(name, {
|
|
45
|
+
module: (this._module?.constructor as { name?: string })?.name || 'unknown',
|
|
46
|
+
// Register entity-own:* permissions if manager has isOwn configured
|
|
47
|
+
hasOwnership: !!(manager as unknown as { _isOwn?: unknown })._isOwn,
|
|
48
|
+
})
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Track entity → module for the 'module' i18n key strategy
|
|
52
|
+
if (this._kernel.i18nInstance) {
|
|
53
|
+
const moduleName = (this._module?.constructor as { name?: string })?.name
|
|
54
|
+
if (moduleName) {
|
|
55
|
+
this._kernel.i18nInstance.registerEntityModule(name, moduleName)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return this
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Register a users entity with standard fields and role linking.
|
|
64
|
+
*/
|
|
65
|
+
proto.userEntity = function (this: Self, options: UserEntityOptions): Self {
|
|
66
|
+
const manager = new UsersManager(options)
|
|
67
|
+
|
|
68
|
+
if (this._kernel.orchestrator) {
|
|
69
|
+
this._kernel.orchestrator.register('users', manager)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (this._kernel.permissionRegistry) {
|
|
73
|
+
this._kernel.permissionRegistry.registerEntity('users', {
|
|
74
|
+
module: (this._module?.constructor as { name?: string })?.name || 'unknown',
|
|
75
|
+
})
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return this
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Patch KernelContext prototype with event-bus / hook / deferred methods:
|
|
3
|
+
* - on(signal, handler, options) — signal subscription, auto-cleaned on
|
|
4
|
+
* module disconnect
|
|
5
|
+
* - hook(hookName, handler, options) — hook registration
|
|
6
|
+
* - defer(name, factory) — queue a deferred task
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { ListenerOptions } from '@quazardous/quarkernel'
|
|
10
|
+
import type {
|
|
11
|
+
DeferredFactory,
|
|
12
|
+
HookHandler,
|
|
13
|
+
SignalHandler,
|
|
14
|
+
} from './KernelContext.types'
|
|
15
|
+
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17
|
+
type Self = any
|
|
18
|
+
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
20
|
+
export function applyEventMethods(KernelContextClass: { prototype: any }): void {
|
|
21
|
+
const proto = KernelContextClass.prototype as Self
|
|
22
|
+
|
|
23
|
+
proto.on = function (
|
|
24
|
+
this: Self,
|
|
25
|
+
signal: string,
|
|
26
|
+
handler: SignalHandler,
|
|
27
|
+
options: ListenerOptions = {}
|
|
28
|
+
): Self {
|
|
29
|
+
if (this._kernel.signals) {
|
|
30
|
+
const cleanup = this._kernel.signals.on(signal, handler, options)
|
|
31
|
+
// Register cleanup with module for automatic unsubscribe on disconnect
|
|
32
|
+
if (this._module && typeof this._module._addSignalCleanup === 'function') {
|
|
33
|
+
this._module._addSignalCleanup(cleanup)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return this
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
proto.hook = function (
|
|
40
|
+
this: Self,
|
|
41
|
+
hookName: string,
|
|
42
|
+
handler: HookHandler,
|
|
43
|
+
options: Record<string, unknown> = {}
|
|
44
|
+
): Self {
|
|
45
|
+
if (this._kernel.hookRegistry) {
|
|
46
|
+
this._kernel.hookRegistry.register(hookName, handler, options)
|
|
47
|
+
}
|
|
48
|
+
return this
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
proto.defer = function (this: Self, name: string, factory: DeferredFactory): Self {
|
|
52
|
+
if (this._kernel.deferred) {
|
|
53
|
+
this._kernel.deferred.queue(name, factory)
|
|
54
|
+
}
|
|
55
|
+
return this
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Patch KernelContext prototype with i18n declarative methods:
|
|
3
|
+
* - messages(locale, bundle) — declare translations
|
|
4
|
+
* - aliases(patterns) — declare pattern aliases
|
|
5
|
+
* - messagesProvider(provider) — register a TranslationProvider
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { AliasPattern, MessagesBundle, TranslationProvider } from '../i18n/types'
|
|
9
|
+
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
11
|
+
type Self = any
|
|
12
|
+
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
14
|
+
export function applyI18nMethods(KernelContextClass: { prototype: any }): void {
|
|
15
|
+
const proto = KernelContextClass.prototype as Self
|
|
16
|
+
|
|
17
|
+
proto.messages = function (this: Self, locale: string, bundle: MessagesBundle): Self {
|
|
18
|
+
if (this._kernel.i18nInstance) {
|
|
19
|
+
this._kernel.i18nInstance.addMessages(locale, bundle)
|
|
20
|
+
}
|
|
21
|
+
return this
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
proto.aliases = function (this: Self, patterns: AliasPattern[]): Self {
|
|
25
|
+
if (this._kernel.i18nInstance) {
|
|
26
|
+
this._kernel.i18nInstance.addAliases(patterns)
|
|
27
|
+
}
|
|
28
|
+
return this
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
proto.messagesProvider = function (this: Self, provider: TranslationProvider): Self {
|
|
32
|
+
if (this._kernel.i18nInstance) {
|
|
33
|
+
this._kernel.i18nInstance.addProvider(provider)
|
|
34
|
+
}
|
|
35
|
+
return this
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Patch KernelContext prototype with permission registration methods:
|
|
3
|
+
* - permissions(namespace, perms, options) — generic registration
|
|
4
|
+
* - entityPermissions(entity, perms) — shorthand for entity-scoped
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { PermissionMeta, PermissionOptions } from './KernelContext.types'
|
|
8
|
+
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
10
|
+
type Self = any
|
|
11
|
+
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
13
|
+
export function applyPermissionMethods(KernelContextClass: { prototype: any }): void {
|
|
14
|
+
const proto = KernelContextClass.prototype as Self
|
|
15
|
+
|
|
16
|
+
proto.permissions = function (
|
|
17
|
+
this: Self,
|
|
18
|
+
namespace: string,
|
|
19
|
+
permissions: Record<string, string | PermissionMeta>,
|
|
20
|
+
options: PermissionOptions = {}
|
|
21
|
+
): Self {
|
|
22
|
+
if (this._kernel.permissionRegistry) {
|
|
23
|
+
this._kernel.permissionRegistry.register(namespace, permissions, {
|
|
24
|
+
...options,
|
|
25
|
+
module: (this._module?.constructor as { name?: string })?.name || 'unknown',
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
return this
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
proto.entityPermissions = function (
|
|
32
|
+
this: Self,
|
|
33
|
+
entity: string,
|
|
34
|
+
permissions: Record<string, string | PermissionMeta>
|
|
35
|
+
): Self {
|
|
36
|
+
return this.permissions(entity, permissions, { isEntity: true })
|
|
37
|
+
}
|
|
38
|
+
}
|