@quazardous/qdadm 1.19.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (291) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +111 -0
  3. package/package.json +101 -0
  4. package/src/assets/logo.svg +6 -0
  5. package/src/auth/SessionAuthAdapter.ts +459 -0
  6. package/src/auth/index.ts +15 -0
  7. package/src/chain/ActiveStack.ts +154 -0
  8. package/src/chain/StackHydrator.ts +292 -0
  9. package/src/chain/index.ts +25 -0
  10. package/src/chain/useActiveStack.ts +120 -0
  11. package/src/chain/useStackHydrator.ts +155 -0
  12. package/src/components/BoolCell.vue +34 -0
  13. package/src/components/InfoBanner.vue +73 -0
  14. package/src/components/QdadmRoot.vue +52 -0
  15. package/src/components/SeverityTag.vue +86 -0
  16. package/src/components/dialogs/BulkStatusDialog.vue +60 -0
  17. package/src/components/dialogs/MultiStepDialog.vue +331 -0
  18. package/src/components/dialogs/SimpleDialog.vue +122 -0
  19. package/src/components/dialogs/UnsavedChangesDialog.vue +80 -0
  20. package/src/components/display/BannerZone.vue +65 -0
  21. package/src/components/display/CardsGrid.vue +72 -0
  22. package/src/components/display/CopyableId.vue +84 -0
  23. package/src/components/display/EmptyState.vue +62 -0
  24. package/src/components/display/IntensityBar.vue +190 -0
  25. package/src/components/display/RichCardsGrid.vue +101 -0
  26. package/src/components/edit/FormActions.vue +78 -0
  27. package/src/components/edit/FormField.vue +82 -0
  28. package/src/components/edit/FormInput.vue +158 -0
  29. package/src/components/edit/FormPage.vue +260 -0
  30. package/src/components/edit/FormTab.vue +217 -0
  31. package/src/components/edit/FormTabs.vue +120 -0
  32. package/src/components/edit/LookupField.vue +406 -0
  33. package/src/components/edit/LookupPickerDialog.vue +230 -0
  34. package/src/components/editors/JsonEditorFoldable.vue +470 -0
  35. package/src/components/editors/JsonStructuredField.vue +264 -0
  36. package/src/components/editors/JsonViewer.vue +51 -0
  37. package/src/components/editors/KeyValueEditor.vue +314 -0
  38. package/src/components/editors/LanguageEditor.vue +259 -0
  39. package/src/components/editors/PermissionEditor.vue +558 -0
  40. package/src/components/editors/ScopeEditor.vue +372 -0
  41. package/src/components/editors/VanillaJsonEditor.vue +183 -0
  42. package/src/components/index.ts +83 -0
  43. package/src/components/item/FieldGroups.vue +392 -0
  44. package/src/components/layout/AppLayout.vue +1032 -0
  45. package/src/components/layout/BaseLayout.vue +190 -0
  46. package/src/components/layout/Breadcrumb.vue +55 -0
  47. package/src/components/layout/DashboardLayout.vue +104 -0
  48. package/src/components/layout/FormLayout.vue +256 -0
  49. package/src/components/layout/ListLayout.vue +278 -0
  50. package/src/components/layout/PageHeader.vue +156 -0
  51. package/src/components/layout/PageLayout.vue +126 -0
  52. package/src/components/layout/PageNav.vue +192 -0
  53. package/src/components/layout/SidebarBox.vue +87 -0
  54. package/src/components/layout/Zone.vue +182 -0
  55. package/src/components/layout/defaults/DefaultBreadcrumb.vue +149 -0
  56. package/src/components/layout/defaults/DefaultFooter.vue +89 -0
  57. package/src/components/layout/defaults/DefaultFormActions.vue +67 -0
  58. package/src/components/layout/defaults/DefaultHeader.vue +78 -0
  59. package/src/components/layout/defaults/DefaultMenu.vue +188 -0
  60. package/src/components/layout/defaults/DefaultPagination.vue +75 -0
  61. package/src/components/layout/defaults/DefaultTable.vue +137 -0
  62. package/src/components/layout/defaults/DefaultUserInfo.vue +111 -0
  63. package/src/components/layout/defaults/index.ts +16 -0
  64. package/src/components/lists/ActionButtons.vue +49 -0
  65. package/src/components/lists/ActionColumn.vue +40 -0
  66. package/src/components/lists/FilterBar.vue +54 -0
  67. package/src/components/lists/ListPage.vue +467 -0
  68. package/src/components/pages/LoginPage.vue +334 -0
  69. package/src/components/pages/NotFoundPage.vue +98 -0
  70. package/src/components/show/ShowDisplay.vue +343 -0
  71. package/src/components/show/ShowField.vue +67 -0
  72. package/src/components/show/ShowPage.vue +431 -0
  73. package/src/composables/index.ts +155 -0
  74. package/src/composables/useApp.ts +67 -0
  75. package/src/composables/useAuth.ts +98 -0
  76. package/src/composables/useBareForm.ts +319 -0
  77. package/src/composables/useBreadcrumb.ts +252 -0
  78. package/src/composables/useChildPage.ts +113 -0
  79. package/src/composables/useCurrentEntity.ts +60 -0
  80. package/src/composables/useDeferred.ts +94 -0
  81. package/src/composables/useDirtyState.ts +138 -0
  82. package/src/composables/useEntityItemFormPage.ts +942 -0
  83. package/src/composables/useEntityItemFormPage.types.ts +451 -0
  84. package/src/composables/useEntityItemPage.ts +438 -0
  85. package/src/composables/useEntityItemShowPage.ts +722 -0
  86. package/src/composables/useFieldManager.ts +692 -0
  87. package/src/composables/useForm.ts +544 -0
  88. package/src/composables/useGuardStore.ts +53 -0
  89. package/src/composables/useHooks.ts +56 -0
  90. package/src/composables/useInfoBanner.ts +217 -0
  91. package/src/composables/useJsonSyntax.ts +122 -0
  92. package/src/composables/useLayoutResolver.ts +329 -0
  93. package/src/composables/useListPage.ts +1535 -0
  94. package/src/composables/useListPage.types.ts +437 -0
  95. package/src/composables/useListPage.utils.ts +101 -0
  96. package/src/composables/useNavContext.ts +439 -0
  97. package/src/composables/useNavigation.ts +216 -0
  98. package/src/composables/useOptionsLookup.ts +323 -0
  99. package/src/composables/usePageTitle.ts +84 -0
  100. package/src/composables/useSSEBridge.ts +142 -0
  101. package/src/composables/useSemanticBreadcrumb.ts +222 -0
  102. package/src/composables/useSidebarState.ts +24 -0
  103. package/src/composables/useSignals.ts +52 -0
  104. package/src/composables/useUnsavedChangesGuard.ts +155 -0
  105. package/src/composables/useUserImpersonator.ts +317 -0
  106. package/src/composables/useZoneRegistry.ts +252 -0
  107. package/src/core/bundles.ts +558 -0
  108. package/src/core/decorator.ts +420 -0
  109. package/src/core/extension.ts +470 -0
  110. package/src/core/index.ts +59 -0
  111. package/src/deferred/DeferredRegistry.ts +353 -0
  112. package/src/deferred/index.ts +15 -0
  113. package/src/editors/index.ts +12 -0
  114. package/src/entity/EntityManager.cache.ts +530 -0
  115. package/src/entity/EntityManager.crud.ts +615 -0
  116. package/src/entity/EntityManager.interface.ts +78 -0
  117. package/src/entity/EntityManager.query.ts +221 -0
  118. package/src/entity/EntityManager.relations.ts +151 -0
  119. package/src/entity/EntityManager.ts +944 -0
  120. package/src/entity/EntityManager.types.ts +288 -0
  121. package/src/entity/auth/CompositeAuthAdapter.ts +194 -0
  122. package/src/entity/auth/EntityAuthAdapter.ts +119 -0
  123. package/src/entity/auth/PermissiveAdapter.ts +43 -0
  124. package/src/entity/auth/RoleHierarchy.ts +128 -0
  125. package/src/entity/auth/SecurityChecker.ts +202 -0
  126. package/src/entity/auth/factory.ts +203 -0
  127. package/src/entity/auth/index.ts +47 -0
  128. package/src/entity/factory.test.js +189 -0
  129. package/src/entity/factory.ts +146 -0
  130. package/src/entity/index.ts +49 -0
  131. package/src/entity/storage/ApiStorage.ts +228 -0
  132. package/src/entity/storage/IStorage.ts +100 -0
  133. package/src/entity/storage/LocalStorage.ts +200 -0
  134. package/src/entity/storage/MemoryStorage.ts +184 -0
  135. package/src/entity/storage/MockApiStorage.ts +318 -0
  136. package/src/entity/storage/SdkStorage.ts +377 -0
  137. package/src/entity/storage/factory.test.js +159 -0
  138. package/src/entity/storage/factory.ts +209 -0
  139. package/src/entity/storage/index.ts +75 -0
  140. package/src/gen/FieldMapper.ts +122 -0
  141. package/src/gen/StorageProfileFactory.ts +93 -0
  142. package/src/gen/connectors/BaseConnector.ts +150 -0
  143. package/src/gen/connectors/ManualConnector.test.js +499 -0
  144. package/src/gen/connectors/ManualConnector.ts +414 -0
  145. package/src/gen/connectors/OpenAPIConnector.test.js +836 -0
  146. package/src/gen/connectors/OpenAPIConnector.ts +693 -0
  147. package/src/gen/connectors/__fixtures__/sample-openapi.json +311 -0
  148. package/src/gen/connectors/index.ts +27 -0
  149. package/src/gen/createManagers.ts +245 -0
  150. package/src/gen/decorators.ts +134 -0
  151. package/src/gen/generateManagers.test.js +540 -0
  152. package/src/gen/generateManagers.ts +398 -0
  153. package/src/gen/index.ts +66 -0
  154. package/src/gen/schema.ts +248 -0
  155. package/src/gen/vite-plugin.ts +114 -0
  156. package/src/generated/managers/testManager.js +45 -0
  157. package/src/generated/managers/testManager.ts +46 -0
  158. package/src/hooks/HookRegistry.ts +16 -0
  159. package/src/hooks/index.ts +15 -0
  160. package/src/i18n/I18n.ts +344 -0
  161. package/src/i18n/IncrementalDomainProvider.ts +153 -0
  162. package/src/i18n/InlineTranslationProvider.ts +4 -0
  163. package/src/i18n/LazyTranslationProvider.ts +102 -0
  164. package/src/i18n/MessagesRegistry.ts +4 -0
  165. package/src/i18n/Resolver.ts +4 -0
  166. package/src/i18n/__tests__/I18n.test.ts +169 -0
  167. package/src/i18n/__tests__/IncrementalDomainProvider.test.ts +146 -0
  168. package/src/i18n/__tests__/LazyTranslationProvider.test.ts +100 -0
  169. package/src/i18n/__tests__/Resolver.test.ts +271 -0
  170. package/src/i18n/defaults/DefaultCoreProvider.ts +28 -0
  171. package/src/i18n/defaults/core.en.yml +55 -0
  172. package/src/i18n/defaults/core.fr.yml +55 -0
  173. package/src/i18n/index.ts +55 -0
  174. package/src/i18n/loaders/raw-modules.d.ts +15 -0
  175. package/src/i18n/loaders/yaml.ts +35 -0
  176. package/src/i18n/strategies.ts +4 -0
  177. package/src/i18n/types.ts +34 -0
  178. package/src/i18n/useI18n.ts +34 -0
  179. package/src/index.ts +453 -0
  180. package/src/kernel/EventRouter.ts +23 -0
  181. package/src/kernel/Kernel.api.ts +79 -0
  182. package/src/kernel/Kernel.auth.ts +120 -0
  183. package/src/kernel/Kernel.i18n.ts +29 -0
  184. package/src/kernel/Kernel.modules.ts +170 -0
  185. package/src/kernel/Kernel.registries.ts +237 -0
  186. package/src/kernel/Kernel.routing.ts +334 -0
  187. package/src/kernel/Kernel.ts +460 -0
  188. package/src/kernel/Kernel.types.ts +263 -0
  189. package/src/kernel/Kernel.vue.ts +304 -0
  190. package/src/kernel/KernelContext.entities.ts +80 -0
  191. package/src/kernel/KernelContext.events.ts +57 -0
  192. package/src/kernel/KernelContext.i18n.ts +37 -0
  193. package/src/kernel/KernelContext.permissions.ts +38 -0
  194. package/src/kernel/KernelContext.routing.ts +280 -0
  195. package/src/kernel/KernelContext.ts +252 -0
  196. package/src/kernel/KernelContext.types.ts +173 -0
  197. package/src/kernel/KernelContext.zones.ts +54 -0
  198. package/src/kernel/Module.ts +169 -0
  199. package/src/kernel/ModuleLoader.ts +645 -0
  200. package/src/kernel/SSEBridge.ts +11 -0
  201. package/src/kernel/SignalBus.ts +48 -0
  202. package/src/kernel/index.ts +56 -0
  203. package/src/module/index.ts +33 -0
  204. package/src/module/moduleRegistry.ts +492 -0
  205. package/src/modules/debug/AuthCollector.ts +501 -0
  206. package/src/modules/debug/Collector.ts +20 -0
  207. package/src/modules/debug/DebugBridge.ts +14 -0
  208. package/src/modules/debug/DebugModule.ts +220 -0
  209. package/src/modules/debug/EntitiesCollector.ts +839 -0
  210. package/src/modules/debug/ErrorCollector.ts +4 -0
  211. package/src/modules/debug/I18nCollector.ts +9 -0
  212. package/src/modules/debug/LocalStorageAdapter.ts +7 -0
  213. package/src/modules/debug/RouterCollector.ts +449 -0
  214. package/src/modules/debug/SignalCollector.ts +4 -0
  215. package/src/modules/debug/ToastCollector.ts +4 -0
  216. package/src/modules/debug/ZonesCollector.ts +447 -0
  217. package/src/modules/debug/components/DebugBar.vue +31 -0
  218. package/src/modules/debug/components/adminPanelsConfig.ts +42 -0
  219. package/src/modules/debug/components/index.ts +9 -0
  220. package/src/modules/debug/components/panels/AuthPanel.vue +267 -0
  221. package/src/modules/debug/components/panels/EntitiesPanel.vue +572 -0
  222. package/src/modules/debug/components/panels/I18nPanel.vue +738 -0
  223. package/src/modules/debug/components/panels/RouterPanel.vue +440 -0
  224. package/src/modules/debug/components/panels/ZonesPanel.vue +133 -0
  225. package/src/modules/debug/components/panels/index.ts +16 -0
  226. package/src/modules/debug/index.ts +58 -0
  227. package/src/modules/debug/styles.scss +2671 -0
  228. package/src/notifications/NotificationBadge.vue +35 -0
  229. package/src/notifications/NotificationListener.vue +71 -0
  230. package/src/notifications/NotificationModule.ts +76 -0
  231. package/src/notifications/NotificationPanel.vue +478 -0
  232. package/src/notifications/NotificationStore.ts +288 -0
  233. package/src/notifications/index.ts +42 -0
  234. package/src/notifications/styles.scss +32 -0
  235. package/src/orchestrator/Orchestrator.ts +427 -0
  236. package/src/orchestrator/index.ts +8 -0
  237. package/src/orchestrator/useOrchestrator.ts +80 -0
  238. package/src/plugin.ts +251 -0
  239. package/src/query/FilterQuery.ts +306 -0
  240. package/src/query/QueryExecutor.ts +341 -0
  241. package/src/query/index.ts +16 -0
  242. package/src/security/EntityRolesProvider.ts +385 -0
  243. package/src/security/PermissionMatcher.ts +152 -0
  244. package/src/security/PermissionRegistry.ts +273 -0
  245. package/src/security/PersistableRolesProvider.ts +584 -0
  246. package/src/security/RolesManager.ts +136 -0
  247. package/src/security/RolesProvider.ts +167 -0
  248. package/src/security/RolesProviderStorage.ts +211 -0
  249. package/src/security/SecurityModule.ts +94 -0
  250. package/src/security/StaticRolesProvider.ts +117 -0
  251. package/src/security/UsersManager.ts +163 -0
  252. package/src/security/index.ts +77 -0
  253. package/src/security/pages/RoleForm.vue +276 -0
  254. package/src/security/pages/RoleList.vue +123 -0
  255. package/src/styles/_alerts.scss +95 -0
  256. package/src/styles/_buttons.scss +391 -0
  257. package/src/styles/_cards.scss +241 -0
  258. package/src/styles/_code.scss +78 -0
  259. package/src/styles/_dialogs.scss +55 -0
  260. package/src/styles/_filter-bar.scss +70 -0
  261. package/src/styles/_forms.scss +434 -0
  262. package/src/styles/_helpers.scss +153 -0
  263. package/src/styles/_lists.scss +225 -0
  264. package/src/styles/_main.scss +356 -0
  265. package/src/styles/_markdown.scss +88 -0
  266. package/src/styles/_responsive.scss +255 -0
  267. package/src/styles/_show-pages.scss +186 -0
  268. package/src/styles/_sidebar.scss +380 -0
  269. package/src/styles/_states.scss +115 -0
  270. package/src/styles/_stats.scss +47 -0
  271. package/src/styles/_variables.scss +224 -0
  272. package/src/styles/index.scss +38 -0
  273. package/src/styles/theme/_components.scss +331 -0
  274. package/src/styles/theme/_index.scss +10 -0
  275. package/src/styles/theme/_tokens.scss +147 -0
  276. package/src/styles/theme/_utilities.scss +175 -0
  277. package/src/toast/ToastBridgeModule.ts +68 -0
  278. package/src/toast/ToastListener.vue +55 -0
  279. package/src/toast/index.ts +26 -0
  280. package/src/toast/useSignalToast.ts +154 -0
  281. package/src/types/index.ts +285 -0
  282. package/src/types/pluralize.d.ts +19 -0
  283. package/src/types/quarkernel.d.ts +50 -0
  284. package/src/utils/formatters.ts +174 -0
  285. package/src/utils/index.ts +35 -0
  286. package/src/utils/transformers.ts +131 -0
  287. package/src/vite/qdadmDebugPlugin.ts +401 -0
  288. package/src/vite-env.d.ts +50 -0
  289. package/src/zones/ZoneRegistry.ts +934 -0
  290. package/src/zones/index.ts +29 -0
  291. package/src/zones/zones.ts +191 -0
@@ -0,0 +1,334 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * LoginPage - Generic login page component
4
+ *
5
+ * Uses authAdapter from qdadm context for authentication.
6
+ * Customizable via props and slots for app branding.
7
+ *
8
+ * Usage:
9
+ * <LoginPage />
10
+ * <LoginPage title="My App" icon="pi pi-lock" />
11
+ * <LoginPage :logo="LogoComponent" />
12
+ *
13
+ * With slot:
14
+ * <LoginPage>
15
+ * <template #footer>
16
+ * <p>Demo accounts: admin, user</p>
17
+ * </template>
18
+ * </LoginPage>
19
+ */
20
+ import { ref, inject, computed, type PropType, type Component } from 'vue'
21
+ import { useRouter } from 'vue-router'
22
+ import Card from 'primevue/card'
23
+ import InputText from 'primevue/inputtext'
24
+ import Password from 'primevue/password'
25
+ import Button from 'primevue/button'
26
+
27
+ /**
28
+ * Auth adapter interface
29
+ */
30
+ interface AuthAdapter {
31
+ login: (credentials: { username: string; password: string }) => Promise<LoginResult>
32
+ }
33
+
34
+ /**
35
+ * Login result from auth adapter
36
+ */
37
+ interface LoginResult {
38
+ user?: {
39
+ username?: string
40
+ email?: string
41
+ [key: string]: unknown
42
+ }
43
+ [key: string]: unknown
44
+ }
45
+
46
+ /**
47
+ * Orchestrator interface
48
+ */
49
+ interface Orchestrator {
50
+ toast: {
51
+ success: (summary: string, detail?: string, emitter?: string) => void
52
+ error: (summary: string, detail?: string, emitter?: string) => void
53
+ }
54
+ signals: {
55
+ emit: (signal: string, payload: unknown) => void
56
+ }
57
+ }
58
+
59
+ /**
60
+ * App config interface
61
+ */
62
+ interface AppConfig {
63
+ name?: string
64
+ [key: string]: unknown
65
+ }
66
+
67
+ /**
68
+ * Axios-like error interface
69
+ */
70
+ interface AxiosError {
71
+ response?: {
72
+ data?: {
73
+ error?: {
74
+ message?: string
75
+ }
76
+ message?: string
77
+ }
78
+ status?: number
79
+ }
80
+ message?: string
81
+ }
82
+
83
+ const props = defineProps({
84
+ /**
85
+ * Override app title (defaults to qdadm app.name config)
86
+ */
87
+ title: {
88
+ type: String as PropType<string | null>,
89
+ default: null
90
+ },
91
+ /**
92
+ * PrimeIcons icon class (e.g., 'pi pi-lock')
93
+ */
94
+ icon: {
95
+ type: String,
96
+ default: 'pi pi-shield'
97
+ },
98
+ /**
99
+ * Custom logo component (replaces icon)
100
+ */
101
+ logo: {
102
+ type: Object as PropType<Component | null>,
103
+ default: null
104
+ },
105
+ /**
106
+ * Username field label
107
+ */
108
+ usernameLabel: {
109
+ type: String,
110
+ default: 'Username'
111
+ },
112
+ /**
113
+ * Password field label
114
+ */
115
+ passwordLabel: {
116
+ type: String,
117
+ default: 'Password'
118
+ },
119
+ /**
120
+ * Submit button label
121
+ */
122
+ submitLabel: {
123
+ type: String,
124
+ default: 'Sign In'
125
+ },
126
+ /**
127
+ * Route to redirect after successful login
128
+ */
129
+ redirectTo: {
130
+ type: String,
131
+ default: '/'
132
+ },
133
+ /**
134
+ * Default username value
135
+ */
136
+ defaultUsername: {
137
+ type: String,
138
+ default: ''
139
+ },
140
+ /**
141
+ * Default password value
142
+ */
143
+ defaultPassword: {
144
+ type: String,
145
+ default: ''
146
+ },
147
+ /**
148
+ * Emit auth:login signal on successful login
149
+ * Required for debug bar auth tracking and other signal listeners
150
+ */
151
+ emitSignal: {
152
+ type: Boolean,
153
+ default: true
154
+ }
155
+ })
156
+
157
+ const emit = defineEmits<{
158
+ (e: 'login', result: LoginResult): void
159
+ (e: 'error', error: unknown): void
160
+ }>()
161
+
162
+ const router = useRouter()
163
+ const authAdapter = inject<AuthAdapter | null>('authAdapter', null)
164
+ const orchestrator = inject<Orchestrator | null>('qdadmOrchestrator', null)
165
+ const appConfig = inject<AppConfig>('qdadmApp', {})
166
+
167
+ const username = ref<string>(props.defaultUsername)
168
+ const password = ref<string>(props.defaultPassword)
169
+ const loading = ref<boolean>(false)
170
+
171
+ const displayTitle = computed<string>(() => props.title || appConfig.name || 'Admin')
172
+
173
+ async function handleLogin(): Promise<void> {
174
+ if (!authAdapter?.login) {
175
+ orchestrator?.toast.error('Configuration Error', 'No auth adapter configured', 'LoginPage')
176
+ return
177
+ }
178
+
179
+ loading.value = true
180
+ try {
181
+ const result = await authAdapter.login({
182
+ username: username.value,
183
+ password: password.value
184
+ })
185
+
186
+ // Emit auth:login signal for debug bar and other listeners
187
+ orchestrator?.signals.emit('auth:login', { user: result.user })
188
+ orchestrator?.toast.success(
189
+ 'Welcome',
190
+ `Logged in as ${result.user?.username || result.user?.email || username.value}`,
191
+ 'LoginPage'
192
+ )
193
+
194
+ emit('login', result)
195
+ router.push(props.redirectTo)
196
+ } catch (error) {
197
+ password.value = ''
198
+
199
+ const axiosError = error as AxiosError
200
+ const message = axiosError.response?.data?.error?.message
201
+ || axiosError.response?.data?.message
202
+ || axiosError.message
203
+ || 'Invalid credentials'
204
+
205
+ orchestrator?.signals.emit('auth:login:error', {
206
+ username: username.value,
207
+ error: message,
208
+ status: axiosError.response?.status
209
+ })
210
+ orchestrator?.toast.error('Login Failed', message, 'LoginPage')
211
+
212
+ emit('error', error)
213
+ } finally {
214
+ loading.value = false
215
+ }
216
+ }
217
+ </script>
218
+
219
+ <template>
220
+ <div class="qdadm-login-page">
221
+ <Card class="qdadm-login-card">
222
+ <template #title>
223
+ <div class="qdadm-login-header">
224
+ <slot name="logo">
225
+ <component v-if="logo" :is="logo" class="qdadm-login-logo" />
226
+ <i v-else :class="icon" class="qdadm-login-icon"></i>
227
+ </slot>
228
+ <h1>{{ displayTitle }}</h1>
229
+ </div>
230
+ </template>
231
+ <template #content>
232
+ <form @submit.prevent="handleLogin" class="qdadm-login-form" autocomplete="off">
233
+ <div class="qdadm-login-field">
234
+ <label for="qdadm-username">{{ usernameLabel }}</label>
235
+ <InputText
236
+ v-model="username"
237
+ id="qdadm-username"
238
+ class="w-full"
239
+ autocomplete="username"
240
+ :disabled="loading"
241
+ />
242
+ </div>
243
+ <div class="qdadm-login-field">
244
+ <label for="qdadm-password">{{ passwordLabel }}</label>
245
+ <Password
246
+ v-model="password"
247
+ inputId="qdadm-password"
248
+ class="w-full"
249
+ :feedback="false"
250
+ toggleMask
251
+ :disabled="loading"
252
+ />
253
+ </div>
254
+ <Button
255
+ type="submit"
256
+ :label="submitLabel"
257
+ icon="pi pi-sign-in"
258
+ class="w-full"
259
+ :loading="loading"
260
+ />
261
+ <slot name="footer"></slot>
262
+ </form>
263
+ </template>
264
+ </Card>
265
+ </div>
266
+ </template>
267
+
268
+ <style scoped>
269
+ /*
270
+ * Only keep styles here that REQUIRE scoping (:deep, dynamic binding, component-specific overrides).
271
+ * Generic/reusable styles belong in src/styles/ partials (see _forms.scss, _cards.scss, etc.).
272
+ */
273
+ .qdadm-login-page {
274
+ min-height: 100vh;
275
+ display: flex;
276
+ align-items: center;
277
+ justify-content: center;
278
+ background: var(--p-surface-100);
279
+ }
280
+
281
+ .qdadm-login-card {
282
+ width: 100%;
283
+ max-width: 400px;
284
+ margin: 1rem;
285
+ }
286
+
287
+ .qdadm-login-header {
288
+ display: flex;
289
+ align-items: center;
290
+ gap: 0.75rem;
291
+ justify-content: center;
292
+ }
293
+
294
+ .qdadm-login-header h1 {
295
+ margin: 0;
296
+ font-size: 1.5rem;
297
+ color: var(--p-text-color);
298
+ }
299
+
300
+ .qdadm-login-icon {
301
+ font-size: 2rem;
302
+ color: var(--p-primary-500);
303
+ }
304
+
305
+ .qdadm-login-logo {
306
+ height: 2rem;
307
+ width: auto;
308
+ }
309
+
310
+ .qdadm-login-form {
311
+ display: flex;
312
+ flex-direction: column;
313
+ gap: 1rem;
314
+ }
315
+
316
+ .qdadm-login-field {
317
+ display: flex;
318
+ flex-direction: column;
319
+ gap: 0.5rem;
320
+ }
321
+
322
+ .qdadm-login-field label {
323
+ font-weight: 500;
324
+ color: var(--p-text-color);
325
+ }
326
+
327
+ /* Responsive */
328
+ @media (max-width: 480px) {
329
+ .qdadm-login-card {
330
+ max-width: 100%;
331
+ margin: 0.5rem;
332
+ }
333
+ }
334
+ </style>
@@ -0,0 +1,98 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * NotFoundPage - Default 404 page
4
+ *
5
+ * Simple page with link to home. Can be replaced via pages.notFound option.
6
+ */
7
+ import { computed, type ComputedRef } from 'vue'
8
+ import { useRouter, type RouteRecordName } from 'vue-router'
9
+
10
+ const router = useRouter()
11
+
12
+ const homeRoute: ComputedRef<RouteRecordName | string> = computed(() => {
13
+ // Find home route (first route or named 'home'/'dashboard')
14
+ const routes = router.getRoutes()
15
+ const home = routes.find(r => r.name === 'home' || r.name === 'dashboard')
16
+ return home?.name || '/'
17
+ })
18
+
19
+ function goHome(): void {
20
+ if (typeof homeRoute.value === 'string' && homeRoute.value.startsWith('/')) {
21
+ router.push(homeRoute.value)
22
+ } else {
23
+ router.push({ name: homeRoute.value })
24
+ }
25
+ }
26
+ </script>
27
+
28
+ <template>
29
+ <div class="not-found-page">
30
+ <div class="not-found-content">
31
+ <div class="not-found-code">404</div>
32
+ <h1>Page not found</h1>
33
+ <p>The page you're looking for doesn't exist or has been moved.</p>
34
+ <button class="home-link" @click="goHome">
35
+ <i class="pi pi-home"></i>
36
+ Back to Home
37
+ </button>
38
+ </div>
39
+ </div>
40
+ </template>
41
+
42
+ <style scoped>
43
+ /*
44
+ * Only keep styles here that REQUIRE scoping (:deep, dynamic binding, component-specific overrides).
45
+ * Generic/reusable styles belong in src/styles/ partials (see _forms.scss, _cards.scss, etc.).
46
+ */
47
+ .not-found-page {
48
+ display: flex;
49
+ align-items: center;
50
+ justify-content: center;
51
+ min-height: 100vh;
52
+ background: var(--p-surface-ground, #f8fafc);
53
+ }
54
+
55
+ .not-found-content {
56
+ text-align: center;
57
+ padding: 2rem;
58
+ }
59
+
60
+ .not-found-code {
61
+ font-size: 8rem;
62
+ font-weight: 700;
63
+ color: var(--p-primary-color, #3b82f6);
64
+ line-height: 1;
65
+ margin-bottom: 1rem;
66
+ opacity: 0.8;
67
+ }
68
+
69
+ h1 {
70
+ font-size: 1.5rem;
71
+ font-weight: 600;
72
+ color: var(--p-text-color, #1e293b);
73
+ margin: 0 0 0.5rem 0;
74
+ }
75
+
76
+ p {
77
+ color: var(--p-text-muted-color, #64748b);
78
+ margin: 0 0 2rem 0;
79
+ }
80
+
81
+ .home-link {
82
+ display: inline-flex;
83
+ align-items: center;
84
+ gap: 0.5rem;
85
+ padding: 0.75rem 1.5rem;
86
+ background: var(--p-primary-color, #3b82f6);
87
+ color: white;
88
+ border: none;
89
+ border-radius: 0.5rem;
90
+ font-size: 1rem;
91
+ cursor: pointer;
92
+ transition: background 0.2s;
93
+ }
94
+
95
+ .home-link:hover {
96
+ background: var(--p-primary-600, #2563eb);
97
+ }
98
+ </style>