@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,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useStackHydrator - Access hydrated navigation stack
|
|
3
|
+
*
|
|
4
|
+
* Provides async-hydrated levels with entity data and labels.
|
|
5
|
+
* Each level has its own promise for fine-grained control.
|
|
6
|
+
*
|
|
7
|
+
* Listens to SignalBus events for reactivity:
|
|
8
|
+
* - stack:hydrated - when hydration completes (batched)
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* const hydrator = useStackHydrator()
|
|
12
|
+
*
|
|
13
|
+
* // Reactive usage (shows loading state, updates when ready)
|
|
14
|
+
* const parentLabel = computed(() =>
|
|
15
|
+
* hydrator.parent.value?.hydrated
|
|
16
|
+
* ? hydrator.parent.value.label
|
|
17
|
+
* : 'Loading...'
|
|
18
|
+
* )
|
|
19
|
+
*
|
|
20
|
+
* // Await specific level
|
|
21
|
+
* await hydrator.getParent()?.promise
|
|
22
|
+
*
|
|
23
|
+
* // Await all levels
|
|
24
|
+
* await Promise.all(hydrator.getLevels().map(l => l.promise))
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import { inject, ref, computed, onUnmounted, type Ref, type ComputedRef } from 'vue'
|
|
28
|
+
import type { SignalBus } from '../kernel/SignalBus'
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Hydrated level data
|
|
32
|
+
*/
|
|
33
|
+
export interface HydratedLevel {
|
|
34
|
+
entity: string
|
|
35
|
+
id: string | number
|
|
36
|
+
data: unknown | null
|
|
37
|
+
label: string | null
|
|
38
|
+
hydrated: boolean
|
|
39
|
+
promise: Promise<unknown>
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Stack hydrator interface (from StackHydrator class)
|
|
44
|
+
*/
|
|
45
|
+
interface StackHydratorClass {
|
|
46
|
+
getLevels: () => HydratedLevel[]
|
|
47
|
+
getLevel: (index: number) => HydratedLevel | null
|
|
48
|
+
getLevelByEntity: (entity: string) => HydratedLevel | null
|
|
49
|
+
getCurrent: () => HydratedLevel | null
|
|
50
|
+
getParent: () => HydratedLevel | null
|
|
51
|
+
setCurrentData: (data: unknown) => void
|
|
52
|
+
setEntityData: (entity: string, data: unknown) => void
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Return type for useStackHydrator
|
|
57
|
+
*/
|
|
58
|
+
export interface StackHydratorReturn {
|
|
59
|
+
// Computed refs (reactive)
|
|
60
|
+
levels: Ref<HydratedLevel[]>
|
|
61
|
+
current: ComputedRef<HydratedLevel | null>
|
|
62
|
+
parent: ComputedRef<HydratedLevel | null>
|
|
63
|
+
root: ComputedRef<HydratedLevel | null>
|
|
64
|
+
|
|
65
|
+
// Sync accessors (for immediate access + promise)
|
|
66
|
+
getLevel: (index: number) => HydratedLevel | null
|
|
67
|
+
getLevelByEntity: (entity: string) => HydratedLevel | null
|
|
68
|
+
getCurrent: () => HydratedLevel | null
|
|
69
|
+
getParent: () => HydratedLevel | null
|
|
70
|
+
getLevels: () => HydratedLevel[]
|
|
71
|
+
|
|
72
|
+
// Manual data setters (for pages that load their own data)
|
|
73
|
+
setCurrentData: (data: unknown) => void
|
|
74
|
+
setEntityData: (entity: string, data: unknown) => void
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function useStackHydrator(): StackHydratorReturn {
|
|
78
|
+
const hydrator = inject<StackHydratorClass | null>('qdadmStackHydrator', null)
|
|
79
|
+
const signalBus = inject<SignalBus | null>('qdadmSignals', null)
|
|
80
|
+
|
|
81
|
+
if (!hydrator) {
|
|
82
|
+
console.warn('[useStackHydrator] StackHydrator not provided')
|
|
83
|
+
return createEmptyHydrator()
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Reactive state - updated via SignalBus
|
|
87
|
+
const levels = ref<HydratedLevel[]>(hydrator.getLevels())
|
|
88
|
+
|
|
89
|
+
// Subscribe to hydration changes (batched signal)
|
|
90
|
+
// QuarKernel passes (event, ctx) where event.data contains the payload
|
|
91
|
+
let unsubscribe: (() => void) | null = null
|
|
92
|
+
if (signalBus) {
|
|
93
|
+
const handler = (event: unknown): void => {
|
|
94
|
+
const eventData = event as { data?: { levels?: HydratedLevel[] } }
|
|
95
|
+
const newLevels = eventData.data?.levels
|
|
96
|
+
if (newLevels) {
|
|
97
|
+
// Create new array reference to trigger reactivity
|
|
98
|
+
levels.value = [...newLevels]
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
unsubscribe = signalBus.on('stack:hydrated', handler)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Cleanup on unmount
|
|
105
|
+
onUnmounted(() => {
|
|
106
|
+
if (unsubscribe) {
|
|
107
|
+
unsubscribe()
|
|
108
|
+
}
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
// Computed accessors
|
|
112
|
+
const current = computed(() => levels.value.at(-1) ?? null)
|
|
113
|
+
const parent = computed(() => levels.value.at(-2) ?? null)
|
|
114
|
+
const root = computed(() => levels.value[0] ?? null)
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
// Computed refs (reactive)
|
|
118
|
+
levels,
|
|
119
|
+
current,
|
|
120
|
+
parent,
|
|
121
|
+
root,
|
|
122
|
+
|
|
123
|
+
// Sync accessors (for immediate access + promise)
|
|
124
|
+
getLevel: (i: number) => hydrator.getLevel(i),
|
|
125
|
+
getLevelByEntity: (e: string) => hydrator.getLevelByEntity(e),
|
|
126
|
+
getCurrent: () => hydrator.getCurrent(),
|
|
127
|
+
getParent: () => hydrator.getParent(),
|
|
128
|
+
getLevels: () => hydrator.getLevels(),
|
|
129
|
+
|
|
130
|
+
// Manual data setters (for pages that load their own data)
|
|
131
|
+
setCurrentData: (data: unknown) => hydrator.setCurrentData(data),
|
|
132
|
+
setEntityData: (entity: string, data: unknown) => hydrator.setEntityData(entity, data),
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Fallback when StackHydrator not available
|
|
138
|
+
*/
|
|
139
|
+
function createEmptyHydrator(): StackHydratorReturn {
|
|
140
|
+
return {
|
|
141
|
+
levels: ref<HydratedLevel[]>([]),
|
|
142
|
+
current: computed(() => null),
|
|
143
|
+
parent: computed(() => null),
|
|
144
|
+
root: computed(() => null),
|
|
145
|
+
getLevel: () => null,
|
|
146
|
+
getLevelByEntity: () => null,
|
|
147
|
+
getCurrent: () => null,
|
|
148
|
+
getParent: () => null,
|
|
149
|
+
getLevels: () => [],
|
|
150
|
+
setCurrentData: () => {},
|
|
151
|
+
setEntityData: () => {},
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export default useStackHydrator
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* BoolCell - Standardized boolean display for list columns
|
|
4
|
+
*
|
|
5
|
+
* Tristate display:
|
|
6
|
+
* - true / "true" / 1: green check
|
|
7
|
+
* - false / "false" / 0: red cross
|
|
8
|
+
* - null/undefined: empty
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* <Column field="read" header="Read">
|
|
12
|
+
* <template #body="{ data }">
|
|
13
|
+
* <BoolCell :value="data.read" />
|
|
14
|
+
* </template>
|
|
15
|
+
* </Column>
|
|
16
|
+
*/
|
|
17
|
+
import { computed } from 'vue'
|
|
18
|
+
|
|
19
|
+
interface Props {
|
|
20
|
+
value?: boolean | string | number | null
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
24
|
+
value: null
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
const isTrue = computed(() => props.value === true || props.value === 'true' || props.value === 1)
|
|
28
|
+
const isFalse = computed(() => props.value === false || props.value === 'false' || props.value === 0)
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<template>
|
|
32
|
+
<i v-if="isTrue" class="pi pi-check" style="color: var(--p-green-500)" />
|
|
33
|
+
<i v-else-if="isFalse" class="pi pi-times" style="color: var(--p-red-500)" />
|
|
34
|
+
</template>
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* InfoBanner - Consistent message banner component
|
|
4
|
+
*
|
|
5
|
+
* Wraps PrimeVue Message with standardized styling and icon support.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* // Simple usage
|
|
9
|
+
* <InfoBanner severity="warn">
|
|
10
|
+
* Settings will be lost on refresh.
|
|
11
|
+
* </InfoBanner>
|
|
12
|
+
*
|
|
13
|
+
* // With custom icon
|
|
14
|
+
* <InfoBanner severity="success" icon="pi-check-circle">
|
|
15
|
+
* Operation completed successfully.
|
|
16
|
+
* </InfoBanner>
|
|
17
|
+
*
|
|
18
|
+
* // Without icon
|
|
19
|
+
* <InfoBanner severity="info" :icon="false">
|
|
20
|
+
* Just some information.
|
|
21
|
+
* </InfoBanner>
|
|
22
|
+
*/
|
|
23
|
+
import Message from 'primevue/message'
|
|
24
|
+
import { computed } from 'vue'
|
|
25
|
+
|
|
26
|
+
type Severity = 'info' | 'success' | 'warn' | 'error' | 'secondary' | 'contrast'
|
|
27
|
+
|
|
28
|
+
interface Props {
|
|
29
|
+
/** Severity level: info, success, warn, error, secondary, contrast */
|
|
30
|
+
severity?: Severity
|
|
31
|
+
/** Custom icon class (e.g., 'pi-user'). Set to false to hide icon. */
|
|
32
|
+
icon?: string | boolean | null
|
|
33
|
+
/** Allow closing the banner (default: true) */
|
|
34
|
+
closable?: boolean
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
38
|
+
severity: 'info',
|
|
39
|
+
icon: null,
|
|
40
|
+
closable: true
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
// Default icons per severity
|
|
44
|
+
const defaultIcons: Record<Severity, string> = {
|
|
45
|
+
info: 'pi-info-circle',
|
|
46
|
+
success: 'pi-check-circle',
|
|
47
|
+
warn: 'pi-exclamation-triangle',
|
|
48
|
+
error: 'pi-times-circle',
|
|
49
|
+
secondary: 'pi-info-circle',
|
|
50
|
+
contrast: 'pi-info-circle'
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const iconClass = computed(() => {
|
|
54
|
+
if (props.icon === false) return null
|
|
55
|
+
if (props.icon && typeof props.icon === 'string') return `pi ${props.icon}`
|
|
56
|
+
return `pi ${defaultIcons[props.severity]}`
|
|
57
|
+
})
|
|
58
|
+
</script>
|
|
59
|
+
|
|
60
|
+
<template>
|
|
61
|
+
<Message
|
|
62
|
+
:severity="severity"
|
|
63
|
+
:closable="closable"
|
|
64
|
+
class="info-banner"
|
|
65
|
+
>
|
|
66
|
+
<div class="info-banner-content">
|
|
67
|
+
<i v-if="iconClass" :class="iconClass" class="info-banner-icon"></i>
|
|
68
|
+
<span class="info-banner-text">
|
|
69
|
+
<slot />
|
|
70
|
+
</span>
|
|
71
|
+
</div>
|
|
72
|
+
</Message>
|
|
73
|
+
</template>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* QdadmRoot — drop-in helper for hosts that own their own Vue app
|
|
4
|
+
* and want qdadm's DOM extras (Toast, ToastListener, DebugBar)
|
|
5
|
+
* rendered alongside.
|
|
6
|
+
*
|
|
7
|
+
* Equivalent to the wrapper Kernel produces internally when it owns
|
|
8
|
+
* `createApp`. When `Kernel({ existingApp })` is used, the host's
|
|
9
|
+
* App.vue should render `<QdadmRoot />` somewhere visible (typically
|
|
10
|
+
* at the end of the template) so toasts and the debug bar appear.
|
|
11
|
+
*
|
|
12
|
+
* The Toast / DebugBar children are conditional on what the Kernel
|
|
13
|
+
* was configured with (PrimeVue presence, debugBar option) — render
|
|
14
|
+
* is a no-op otherwise, so it's always safe to include.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { computed, inject, type Component } from 'vue'
|
|
18
|
+
import Toast from 'primevue/toast'
|
|
19
|
+
import ToastListener from '../toast/ToastListener.vue'
|
|
20
|
+
import { getQdadmDebugBarRef } from '../kernel/Kernel.vue'
|
|
21
|
+
|
|
22
|
+
const props = withDefaults(
|
|
23
|
+
defineProps<{
|
|
24
|
+
/**
|
|
25
|
+
* Render the qdadm debug bar inline. Default true preserves the
|
|
26
|
+
* legacy behaviour. Set false in hosts that already render their
|
|
27
|
+
* own (shared) `<DebugBar />` to avoid two bars on screen.
|
|
28
|
+
*/
|
|
29
|
+
debugBar?: boolean
|
|
30
|
+
}>(),
|
|
31
|
+
{ debugBar: true },
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
// Read the singleton-on-window debug bar ref. Using a getter (instead
|
|
35
|
+
// of importing the module-level const) makes this resilient to Vite
|
|
36
|
+
// HMR's module fragmentation in dev, where a top-level `const ref`
|
|
37
|
+
// can be torn into separate instances per importer.
|
|
38
|
+
const debugBarRef = getQdadmDebugBarRef()
|
|
39
|
+
const debugBarComp = computed<Component | null>(() =>
|
|
40
|
+
props.debugBar ? debugBarRef.value : null,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
// `qdadmHasPrimeVue` is provided by the Kernel during _installPlugins.
|
|
44
|
+
// True when PrimeVue is wired (so Toast / ToastListener are usable).
|
|
45
|
+
const hasToast = inject<boolean>('qdadmHasPrimeVue', false)
|
|
46
|
+
</script>
|
|
47
|
+
|
|
48
|
+
<template>
|
|
49
|
+
<Toast v-if="hasToast" />
|
|
50
|
+
<ToastListener v-if="hasToast" />
|
|
51
|
+
<component v-if="debugBarComp" :is="debugBarComp" />
|
|
52
|
+
</template>
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* SeverityTag - Auto-discovers severity from EntityManager
|
|
4
|
+
*
|
|
5
|
+
* Renders a PrimeVue Tag for simple severity strings, or a rich badge
|
|
6
|
+
* with icon (including animated spinners) when the severity map provides
|
|
7
|
+
* a descriptor with an `icon` field.
|
|
8
|
+
*
|
|
9
|
+
* Entity can be specified explicitly or auto-discovered from list context.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* // Explicit entity
|
|
13
|
+
* <SeverityTag entity="jobs" field="status" :value="job.status" />
|
|
14
|
+
*
|
|
15
|
+
* // Auto-discover from list context (inside ListPage)
|
|
16
|
+
* <SeverityTag field="status" :value="data.status" />
|
|
17
|
+
*
|
|
18
|
+
* // With custom label
|
|
19
|
+
* <SeverityTag entity="stories" field="status" :value="story.status" label="Published" />
|
|
20
|
+
*/
|
|
21
|
+
import { computed, inject } from 'vue'
|
|
22
|
+
import Tag from 'primevue/tag'
|
|
23
|
+
import type { Orchestrator } from '../orchestrator/Orchestrator'
|
|
24
|
+
import type { EntityManager } from '../entity/EntityManager'
|
|
25
|
+
|
|
26
|
+
interface Props {
|
|
27
|
+
/** Entity name (e.g., 'jobs', 'stories') - optional if inside ListPage context */
|
|
28
|
+
entity?: string | null
|
|
29
|
+
/** Field name for severity lookup (e.g., 'status') */
|
|
30
|
+
field: string
|
|
31
|
+
/** Field value */
|
|
32
|
+
value?: string | number | boolean | null
|
|
33
|
+
/** Optional custom label (defaults to value) */
|
|
34
|
+
label?: string | null
|
|
35
|
+
/** Default severity if no mapping found */
|
|
36
|
+
defaultSeverity?: string
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
40
|
+
entity: null,
|
|
41
|
+
value: null,
|
|
42
|
+
label: null,
|
|
43
|
+
defaultSeverity: 'secondary'
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
const orchestrator = inject<Orchestrator | null>('qdadmOrchestrator', null)
|
|
47
|
+
// Auto-discover entity from page context (provided by useListPage, useBareForm, etc.)
|
|
48
|
+
const mainEntity = inject<string | null>('mainEntity', null)
|
|
49
|
+
|
|
50
|
+
const resolvedEntity = computed(() => props.entity || mainEntity)
|
|
51
|
+
|
|
52
|
+
const manager = computed<EntityManager | null>(() => {
|
|
53
|
+
if (!resolvedEntity.value) return null
|
|
54
|
+
return orchestrator?.get(resolvedEntity.value) ?? null
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
const fieldValue = computed(() => {
|
|
58
|
+
if (props.value === null || props.value === undefined) return ''
|
|
59
|
+
return typeof props.value === 'boolean' ? String(props.value) : props.value
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
const descriptor = computed(() => {
|
|
63
|
+
if (!manager.value?.getSeverityDescriptor) {
|
|
64
|
+
return { severity: manager.value?.getSeverity?.(props.field, fieldValue.value as string | number, props.defaultSeverity) ?? props.defaultSeverity }
|
|
65
|
+
}
|
|
66
|
+
return manager.value.getSeverityDescriptor(props.field, fieldValue.value as string | number, props.defaultSeverity)
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
const severity = computed(() => descriptor.value.severity)
|
|
70
|
+
|
|
71
|
+
const displayLabel = computed(() => {
|
|
72
|
+
return props.label ?? descriptor.value.label ?? props.value
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
const hasIcon = computed(() => !!descriptor.value.icon)
|
|
76
|
+
</script>
|
|
77
|
+
|
|
78
|
+
<template>
|
|
79
|
+
<!-- Rich badge with icon -->
|
|
80
|
+
<span v-if="hasIcon" class="p-tag p-component" :class="`p-tag-${severity}`">
|
|
81
|
+
<i :class="descriptor.icon" />
|
|
82
|
+
<span class="p-tag-label">{{ displayLabel }}</span>
|
|
83
|
+
</span>
|
|
84
|
+
<!-- Simple PrimeVue Tag -->
|
|
85
|
+
<Tag v-else :value="displayLabel" :severity="severity" />
|
|
86
|
+
</template>
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import SimpleDialog from './SimpleDialog.vue'
|
|
3
|
+
import Select from 'primevue/select'
|
|
4
|
+
|
|
5
|
+
interface StatusOption {
|
|
6
|
+
label: string
|
|
7
|
+
value: string | number
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
visible?: boolean
|
|
12
|
+
title?: string
|
|
13
|
+
options: StatusOption[]
|
|
14
|
+
modelValue?: string | number
|
|
15
|
+
loading?: boolean
|
|
16
|
+
selectionCount?: number
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
withDefaults(defineProps<Props>(), {
|
|
20
|
+
visible: false,
|
|
21
|
+
title: 'Change Status',
|
|
22
|
+
loading: false,
|
|
23
|
+
selectionCount: 0
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
defineEmits<{
|
|
27
|
+
'update:visible': [value: boolean]
|
|
28
|
+
'update:modelValue': [value: string | number]
|
|
29
|
+
confirm: []
|
|
30
|
+
cancel: []
|
|
31
|
+
}>()
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<template>
|
|
35
|
+
<SimpleDialog
|
|
36
|
+
:visible="visible"
|
|
37
|
+
:title="title"
|
|
38
|
+
width="400px"
|
|
39
|
+
:loading="loading"
|
|
40
|
+
confirmLabel="Update"
|
|
41
|
+
confirmIcon="pi pi-check"
|
|
42
|
+
:confirmDisabled="!modelValue"
|
|
43
|
+
@update:visible="$emit('update:visible', $event)"
|
|
44
|
+
@confirm="$emit('confirm')"
|
|
45
|
+
@cancel="$emit('cancel')"
|
|
46
|
+
>
|
|
47
|
+
<p v-if="selectionCount > 0" class="mb-3">
|
|
48
|
+
Change status for {{ selectionCount }} selected item(s):
|
|
49
|
+
</p>
|
|
50
|
+
<Select
|
|
51
|
+
:modelValue="modelValue"
|
|
52
|
+
:options="options"
|
|
53
|
+
optionLabel="label"
|
|
54
|
+
optionValue="value"
|
|
55
|
+
placeholder="Select new status"
|
|
56
|
+
class="w-full"
|
|
57
|
+
@update:modelValue="$emit('update:modelValue', $event)"
|
|
58
|
+
/>
|
|
59
|
+
</SimpleDialog>
|
|
60
|
+
</template>
|