@quazardous/qdadm 2.13.0 → 2.15.0

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 (50) hide show
  1. package/README.md +1 -0
  2. package/package.json +6 -4
  3. package/src/chain/index.ts +5 -0
  4. package/src/components/InfoBanner.vue +3 -3
  5. package/src/components/base/QdButton.vue +20 -0
  6. package/src/components/base/QdMessage.vue +17 -0
  7. package/src/components/dialogs/MultiStepDialog.vue +5 -5
  8. package/src/components/dialogs/SimpleDialog.vue +4 -4
  9. package/src/components/dialogs/UnsavedChangesDialog.vue +2 -2
  10. package/src/components/display/CopyableId.vue +2 -2
  11. package/src/components/edit/FormActions.vue +4 -4
  12. package/src/components/edit/FormPage.vue +7 -7
  13. package/src/components/edit/LookupPickerDialog.vue +3 -3
  14. package/src/components/editors/JsonEditorFoldable.vue +8 -8
  15. package/src/components/editors/JsonStructuredField.vue +3 -3
  16. package/src/components/editors/KeyValueEditor.vue +3 -3
  17. package/src/components/editors/LanguageEditor.vue +5 -5
  18. package/src/components/editors/ScopeEditor.vue +3 -3
  19. package/src/components/index.ts +4 -0
  20. package/src/components/layout/AppLayout.vue +2 -2
  21. package/src/components/layout/PageLayout.vue +2 -2
  22. package/src/components/layout/defaults/DefaultUserInfo.vue +2 -2
  23. package/src/components/lists/ActionButtons.vue +2 -2
  24. package/src/components/lists/ListPage.vue +4 -4
  25. package/src/components/pages/LoginPage.vue +2 -2
  26. package/src/components/show/ShowPage.vue +6 -6
  27. package/src/composables/useEntityItemShowPage.ts +8 -0
  28. package/src/composables/useListPage.ts +23 -0
  29. package/src/composables/useListPage.types.ts +3 -0
  30. package/src/composables/useLiveEntity.ts +115 -0
  31. package/src/deferred/index.ts +5 -0
  32. package/src/entity/EntityManager.cache.ts +20 -0
  33. package/src/entity/EntityManager.interface.ts +3 -0
  34. package/src/entity/EntityManager.ts +29 -1
  35. package/src/entity/EntityManager.types.ts +32 -0
  36. package/src/gen/vite-plugin.ts +4 -0
  37. package/src/index.ts +10 -0
  38. package/src/kernel/Kernel.registries.ts +31 -5
  39. package/src/kernel/Kernel.ts +3 -0
  40. package/src/kernel/Kernel.types.ts +31 -0
  41. package/src/kernel/LiveEntityRouter.ts +189 -0
  42. package/src/kernel/SSEBridge.ts +3 -0
  43. package/src/query/index.ts +7 -0
  44. package/src/security/pages/RoleList.vue +3 -3
  45. package/src/types/index.ts +2 -0
  46. package/src/utils/pluralize.ts +472 -0
  47. package/src/vite/qdadmDebugPlugin.ts +178 -2
  48. package/src/vite/qdadmPlugin.ts +5 -19
  49. package/src/vite-env.d.ts +0 -16
  50. package/src/types/pluralize.d.ts +0 -19
package/README.md CHANGED
@@ -6,6 +6,7 @@
6
6
 
7
7
  ```bash
8
8
  npm install @quazardous/qdadm primevue @primeuix/themes primeicons vue-router pinia
9
+ npm install -D sass-embedded # compiles qdadm's shipped .scss styles (or `sass`)
9
10
  ```
10
11
 
11
12
  ```ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quazardous/qdadm",
3
- "version": "2.13.0",
3
+ "version": "2.15.0",
4
4
  "description": "Vue 3 framework for admin dashboards with PrimeVue",
5
5
  "author": "quazardous",
6
6
  "license": "MIT",
@@ -51,16 +51,15 @@
51
51
  "LICENSE"
52
52
  ],
53
53
  "dependencies": {
54
- "@quazardous/qdcore": "^1.0.0",
55
- "@types/pluralize": "^0.0.33",
54
+ "@quazardous/qdcore": "^1.1.0",
56
55
  "@quazardous/qddebug": "^1.0.0",
57
56
  "@quazardous/quarkernel": "^2.1.0",
58
- "pluralize": "^8.0.0",
59
57
  "yaml": "^2.8.4"
60
58
  },
61
59
  "peerDependencies": {
62
60
  "pinia": "^2.0.0 || ^3.0.0 || ^4.0.0",
63
61
  "primevue": "^4.0.0",
62
+ "sass-embedded": "^1.0.0",
64
63
  "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0",
65
64
  "vue": "^3.3.0",
66
65
  "vue-router": "^4.0.0 || ^5.0.0"
@@ -74,6 +73,9 @@
74
73
  },
75
74
  "primevue": {
76
75
  "optional": true
76
+ },
77
+ "sass-embedded": {
78
+ "optional": "true"
77
79
  }
78
80
  },
79
81
  "optionalDependencies": {
@@ -7,6 +7,11 @@
7
7
  * - useActiveStack: Composable to build and access the sync stack
8
8
  * - useStackHydrator: Composable to access hydrated data
9
9
  *
10
+ * @experimental Navigation-stack plumbing that happens to be exported: the
11
+ * level shape and the hydration payloads may change in a minor release. The
12
+ * parent/child routing built on top of it is stable — see
13
+ * docs/API_STABILITY.md.
14
+ *
10
15
  * @module chain
11
16
  */
12
17
 
@@ -20,7 +20,7 @@
20
20
  * Just some information.
21
21
  * </InfoBanner>
22
22
  */
23
- import Message from 'primevue/message'
23
+ import QdMessage from './base/QdMessage.vue'
24
24
  import { computed } from 'vue'
25
25
 
26
26
  type Severity = 'info' | 'success' | 'warn' | 'error' | 'secondary' | 'contrast'
@@ -58,7 +58,7 @@ const iconClass = computed(() => {
58
58
  </script>
59
59
 
60
60
  <template>
61
- <Message
61
+ <QdMessage
62
62
  :severity="severity"
63
63
  :closable="closable"
64
64
  class="info-banner"
@@ -69,5 +69,5 @@ const iconClass = computed(() => {
69
69
  <slot />
70
70
  </span>
71
71
  </div>
72
- </Message>
72
+ </QdMessage>
73
73
  </template>
@@ -0,0 +1,20 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * QdButton — the single indirection point over the widget library's Button
4
+ * (#1391 exit-readiness). Generic pass-through: every attr/prop/listener and
5
+ * every slot is forwarded verbatim, so swapping or shimming the underlying
6
+ * widget is a one-file change. Imports `primevue/button`, which the
7
+ * qdadmVitePlugin flavor alias (#1393) traverses.
8
+ */
9
+ import Button from 'primevue/button'
10
+
11
+ defineOptions({ inheritAttrs: false })
12
+ </script>
13
+
14
+ <template>
15
+ <Button v-bind="$attrs">
16
+ <template v-for="(_, name) in $slots" #[name]="slotProps">
17
+ <slot :name="name" v-bind="slotProps ?? {}" />
18
+ </template>
19
+ </Button>
20
+ </template>
@@ -0,0 +1,17 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * QdMessage — the single indirection point over the widget library's Message
4
+ * (#1391 exit-readiness). Generic pass-through, same contract as QdButton.
5
+ */
6
+ import Message from 'primevue/message'
7
+
8
+ defineOptions({ inheritAttrs: false })
9
+ </script>
10
+
11
+ <template>
12
+ <Message v-bind="$attrs">
13
+ <template v-for="(_, name) in $slots" #[name]="slotProps">
14
+ <slot :name="name" v-bind="slotProps ?? {}" />
15
+ </template>
16
+ </Message>
17
+ </template>
@@ -58,7 +58,7 @@
58
58
  */
59
59
  import { computed, watch, type PropType } from 'vue'
60
60
  import Dialog from 'primevue/dialog'
61
- import Button from 'primevue/button'
61
+ import QdButton from '../base/QdButton.vue'
62
62
  import Stepper from 'primevue/stepper'
63
63
  import StepList from 'primevue/steplist'
64
64
  import Step from 'primevue/step'
@@ -284,7 +284,7 @@ const slotActions = computed<SlotActions>(() => ({
284
284
  <div class="step-actions">
285
285
  <slot name="actions" v-bind="slotActions">
286
286
  <!-- Back button -->
287
- <Button
287
+ <QdButton
288
288
  v-if="!isFirstStep || showBackOnFirst"
289
289
  :label="backLabel"
290
290
  icon="pi pi-arrow-left"
@@ -294,7 +294,7 @@ const slotActions = computed<SlotActions>(() => ({
294
294
  />
295
295
 
296
296
  <!-- Cancel button -->
297
- <Button
297
+ <QdButton
298
298
  :label="cancelLabel"
299
299
  severity="secondary"
300
300
  @click="cancel"
@@ -302,7 +302,7 @@ const slotActions = computed<SlotActions>(() => ({
302
302
  />
303
303
 
304
304
  <!-- Next button (not on last step) -->
305
- <Button
305
+ <QdButton
306
306
  v-if="!isLastStep"
307
307
  :label="nextLabel"
308
308
  icon="pi pi-arrow-right"
@@ -312,7 +312,7 @@ const slotActions = computed<SlotActions>(() => ({
312
312
  />
313
313
 
314
314
  <!-- Submit button (only on last step) -->
315
- <Button
315
+ <QdButton
316
316
  v-if="isLastStep"
317
317
  :label="submitLabel"
318
318
  icon="pi pi-check"
@@ -26,13 +26,13 @@
26
26
  * <SimpleDialog v-model:visible="showDialog" title="View Key" :showConfirm="false">
27
27
  * <p>{{ key }}</p>
28
28
  * <template #actions>
29
- * <Button label="Copy" icon="pi pi-copy" @click="copyKey" />
29
+ * <QdButton label="Copy" icon="pi pi-copy" @click="copyKey" />
30
30
  * </template>
31
31
  * </SimpleDialog>
32
32
  */
33
33
  import { computed } from 'vue'
34
34
  import Dialog from 'primevue/dialog'
35
- import Button from 'primevue/button'
35
+ import QdButton from '../base/QdButton.vue'
36
36
 
37
37
  interface Props {
38
38
  visible?: boolean
@@ -101,14 +101,14 @@ const canClose = computed((): boolean => props.closable && !props.loading)
101
101
 
102
102
  <template #footer v-if="showCancel || showConfirm || $slots.actions">
103
103
  <slot name="actions" />
104
- <Button
104
+ <QdButton
105
105
  v-if="showCancel"
106
106
  :label="cancelLabel"
107
107
  severity="secondary"
108
108
  @click="onCancel"
109
109
  :disabled="loading"
110
110
  />
111
- <Button
111
+ <QdButton
112
112
  v-if="showConfirm"
113
113
  :label="confirmLabel"
114
114
  :icon="confirmIcon"
@@ -8,7 +8,7 @@
8
8
  * - Stay: cancels navigation
9
9
  */
10
10
  import SimpleDialog from './SimpleDialog.vue'
11
- import Button from 'primevue/button'
11
+ import QdButton from '../base/QdButton.vue'
12
12
 
13
13
  interface Props {
14
14
  visible?: boolean
@@ -67,7 +67,7 @@ function onSaveAndLeave(): void {
67
67
  </div>
68
68
 
69
69
  <template #actions>
70
- <Button
70
+ <QdButton
71
71
  v-if="hasOnSave"
72
72
  label="Save & Leave"
73
73
  icon="pi pi-save"
@@ -7,7 +7,7 @@
7
7
  * <CopyableId :value="apiKey" label="API Key" />
8
8
  */
9
9
  import { ref, inject } from 'vue'
10
- import Button from 'primevue/button'
10
+ import QdButton from '../base/QdButton.vue'
11
11
  import type { Orchestrator } from '../../orchestrator/Orchestrator'
12
12
 
13
13
  interface Props {
@@ -40,7 +40,7 @@ async function copyToClipboard(): Promise<void> {
40
40
  <div class="form-field">
41
41
  <label class="form-field-label">{{ label }}</label>
42
42
  <div class="copyable-id">
43
- <Button
43
+ <QdButton
44
44
  type="button"
45
45
  :icon="copied ? 'pi pi-check' : 'pi pi-copy'"
46
46
  :severity="copied ? 'success' : 'secondary'"
@@ -13,7 +13,7 @@
13
13
  * - cancel: Cancel/close without saving
14
14
  */
15
15
 
16
- import Button from 'primevue/button'
16
+ import QdButton from '../base/QdButton.vue'
17
17
  import { useI18n } from '../../i18n/useI18n'
18
18
 
19
19
  const { t } = useI18n()
@@ -42,7 +42,7 @@ const emit = defineEmits<{
42
42
  <template>
43
43
  <div class="form-actions">
44
44
  <div class="form-actions-left">
45
- <Button
45
+ <QdButton
46
46
  type="button"
47
47
  :label="isEdit ? t('core.actions.update') : t('core.actions.create')"
48
48
  :loading="saving"
@@ -51,7 +51,7 @@ const emit = defineEmits<{
51
51
  @click="emit('save')"
52
52
  v-tooltip.top="t('core.tooltips.saveAndContinue')"
53
53
  />
54
- <Button
54
+ <QdButton
55
55
  v-if="showSaveAndClose"
56
56
  type="button"
57
57
  :label="isEdit ? t('core.actions.updateAndClose') : t('core.actions.createAndClose')"
@@ -66,7 +66,7 @@ const emit = defineEmits<{
66
66
  <i class="pi pi-circle-fill"></i>
67
67
  </span>
68
68
  </div>
69
- <Button
69
+ <QdButton
70
70
  type="button"
71
71
  :label="t('core.actions.cancel')"
72
72
  severity="secondary"
@@ -38,8 +38,8 @@ import FormActions from './FormActions.vue'
38
38
  import UnsavedChangesDialog from '../dialogs/UnsavedChangesDialog.vue'
39
39
  import CardShell from '../layout/CardShell.vue'
40
40
  import { formatFetchError } from '../../utils/errors'
41
- import Button from 'primevue/button'
42
- import Message from 'primevue/message'
41
+ import QdButton from '../base/QdButton.vue'
42
+ import QdMessage from '../base/QdMessage.vue'
43
43
  import type { ResolvedAction, ResolvedFieldConfig } from '../../composables/useEntityItemFormPage'
44
44
  import type { GuardDialogState } from '../../composables/useUnsavedChangesGuard'
45
45
 
@@ -151,7 +151,7 @@ function onGuardStay(): void {
151
151
  <template #actions>
152
152
  <slot name="header-actions" />
153
153
  <!-- Header actions from builder (excludes save/delete/cancel) -->
154
- <Button
154
+ <QdButton
155
155
  v-for="action in headerActions"
156
156
  :key="action.name"
157
157
  :label="action.label"
@@ -180,16 +180,16 @@ function onGuardStay(): void {
180
180
  <!-- Error State (fetch error) -->
181
181
  <template v-else-if="fetchError">
182
182
  <slot name="error" :error="fetchError">
183
- <Message severity="error" :closable="false" class="form-error-message">
183
+ <QdMessage severity="error" :closable="false" class="form-error-message">
184
184
  {{ fetchErrorMessage }}
185
- </Message>
185
+ </QdMessage>
186
186
  </slot>
187
187
  </template>
188
188
 
189
189
  <!-- Form Content -->
190
190
  <template v-else>
191
191
  <!-- Validation Error Summary -->
192
- <Message
192
+ <QdMessage
193
193
  v-if="errorSummary && errorSummary.length > 0"
194
194
  severity="warn"
195
195
  :closable="false"
@@ -200,7 +200,7 @@ function onGuardStay(): void {
200
200
  <strong>{{ error.label }}:</strong> {{ error.message }}
201
201
  </li>
202
202
  </ul>
203
- </Message>
203
+ </QdMessage>
204
204
 
205
205
  <!-- Single content body; Card wrapper is conditional (#1193) -->
206
206
  <CardShell :card="cardWrapper">
@@ -12,7 +12,7 @@ import Dialog from 'primevue/dialog'
12
12
  import DataTable from 'primevue/datatable'
13
13
  import Column from 'primevue/column'
14
14
  import InputText from 'primevue/inputtext'
15
- import Button from 'primevue/button'
15
+ import QdButton from '../base/QdButton.vue'
16
16
  import { useI18n } from '../../i18n/useI18n'
17
17
 
18
18
  const { t } = useI18n()
@@ -208,12 +208,12 @@ const confirmLabel = computed(() => {
208
208
  </DataTable>
209
209
 
210
210
  <template #footer>
211
- <Button
211
+ <QdButton
212
212
  :label="t('core.actions.cancel')"
213
213
  severity="secondary"
214
214
  @click="onCancel"
215
215
  />
216
- <Button
216
+ <QdButton
217
217
  :label="confirmLabel"
218
218
  icon="pi pi-check"
219
219
  :disabled="confirmDisabled"
@@ -10,10 +10,10 @@
10
10
  */
11
11
 
12
12
  import { ref, computed, watch } from 'vue'
13
- import Button from 'primevue/button'
13
+ import QdButton from '../base/QdButton.vue'
14
14
  import Textarea from 'primevue/textarea'
15
15
  import InputText from 'primevue/inputtext'
16
- import Message from 'primevue/message'
16
+ import QdMessage from '../base/QdMessage.vue'
17
17
  import { getJsonValueType, getJsonPreview } from '../../composables/useJsonSyntax'
18
18
 
19
19
  interface Props {
@@ -165,7 +165,7 @@ function isMultiline(value: unknown): boolean {
165
165
  <!-- Toolbar -->
166
166
  <div class="editor-toolbar">
167
167
  <div class="toolbar-left">
168
- <Button
168
+ <QdButton
169
169
  :icon="rawJsonMode ? 'pi pi-list' : 'pi pi-code'"
170
170
  :label="rawJsonMode ? 'Structured' : 'Raw JSON'"
171
171
  size="small"
@@ -175,7 +175,7 @@ function isMultiline(value: unknown): boolean {
175
175
  />
176
176
  </div>
177
177
  <div class="toolbar-right" v-if="!rawJsonMode">
178
- <Button
178
+ <QdButton
179
179
  icon="pi pi-plus"
180
180
  label="Expand All"
181
181
  size="small"
@@ -183,7 +183,7 @@ function isMultiline(value: unknown): boolean {
183
183
  text
184
184
  @click="expandAll"
185
185
  />
186
- <Button
186
+ <QdButton
187
187
  icon="pi pi-minus"
188
188
  label="Collapse All"
189
189
  size="small"
@@ -282,12 +282,12 @@ function isMultiline(value: unknown): boolean {
282
282
  spellcheck="false"
283
283
  ></textarea>
284
284
  <div v-if="parseError" class="raw-json-actions">
285
- <Message severity="error" :closable="false" class="parse-error">
285
+ <QdMessage severity="error" :closable="false" class="parse-error">
286
286
  {{ parseError }}
287
- </Message>
287
+ </QdMessage>
288
288
  </div>
289
289
  <div v-else class="raw-json-actions">
290
- <Button
290
+ <QdButton
291
291
  label="Apply Changes"
292
292
  icon="pi pi-check"
293
293
  size="small"
@@ -42,7 +42,7 @@
42
42
 
43
43
  import { ref, computed, watch } from 'vue'
44
44
  import SelectButton from 'primevue/selectbutton'
45
- import Message from 'primevue/message'
45
+ import QdMessage from '../base/QdMessage.vue'
46
46
  import VanillaJsonEditor from './VanillaJsonEditor.vue'
47
47
  import type { Mode } from 'vanilla-jsoneditor'
48
48
 
@@ -179,14 +179,14 @@ watch(() => props.mode, (newMode: ViewMode | null | undefined) => {
179
179
 
180
180
  <!-- JSON View -->
181
181
  <div v-if="viewMode === 'json'" class="json-view">
182
- <Message
182
+ <QdMessage
183
183
  v-if="guardInvalidJson && hasJsonError"
184
184
  severity="error"
185
185
  :closable="false"
186
186
  class="json-error"
187
187
  >
188
188
  {{ invalidJsonMessage }}
189
- </Message>
189
+ </QdMessage>
190
190
  <VanillaJsonEditor
191
191
  :modelValue="effectiveJsonValue"
192
192
  :mode="jsonMode"
@@ -18,7 +18,7 @@
18
18
  */
19
19
 
20
20
  import { ref, computed } from 'vue'
21
- import Button from 'primevue/button'
21
+ import QdButton from '../base/QdButton.vue'
22
22
  import InputText from 'primevue/inputtext'
23
23
  import AutoComplete from 'primevue/autocomplete'
24
24
  import Slider from 'primevue/slider'
@@ -161,7 +161,7 @@ function updateItemValue(index: number, value: string | number): void {
161
161
  />
162
162
  </template>
163
163
  </div>
164
- <Button
164
+ <QdButton
165
165
  icon="pi pi-times"
166
166
  severity="danger"
167
167
  text
@@ -172,7 +172,7 @@ function updateItemValue(index: number, value: string | number): void {
172
172
  </div>
173
173
  </div>
174
174
  <div class="kv-add">
175
- <Button
175
+ <QdButton
176
176
  icon="pi pi-plus"
177
177
  @click="addItem"
178
178
  :disabled="!newItem.key || (isTextMode && !newItem.value)"
@@ -9,7 +9,7 @@
9
9
  */
10
10
 
11
11
  import { ref, computed } from 'vue'
12
- import Button from 'primevue/button'
12
+ import QdButton from '../base/QdButton.vue'
13
13
  import InputText from 'primevue/inputtext'
14
14
  import Slider from 'primevue/slider'
15
15
  import Checkbox from 'primevue/checkbox'
@@ -113,7 +113,7 @@ function updateFluency(index: number, fluency: number | number[]): void {
113
113
  style="width: 100px"
114
114
  />
115
115
  </div>
116
- <Button
116
+ <QdButton
117
117
  v-if="lang.primary"
118
118
  icon="pi pi-star-fill"
119
119
  severity="warning"
@@ -122,7 +122,7 @@ function updateFluency(index: number, fluency: number | number[]): void {
122
122
  size="small"
123
123
  v-tooltip.top="'Primary language'"
124
124
  />
125
- <Button
125
+ <QdButton
126
126
  v-else
127
127
  icon="pi pi-star"
128
128
  severity="secondary"
@@ -132,7 +132,7 @@ function updateFluency(index: number, fluency: number | number[]): void {
132
132
  @click="setPrimaryLanguage(index)"
133
133
  v-tooltip.top="'Set as primary'"
134
134
  />
135
- <Button
135
+ <QdButton
136
136
  icon="pi pi-times"
137
137
  severity="danger"
138
138
  text
@@ -143,7 +143,7 @@ function updateFluency(index: number, fluency: number | number[]): void {
143
143
  </div>
144
144
  </div>
145
145
  <div class="lang-add">
146
- <Button
146
+ <QdButton
147
147
  icon="pi pi-plus"
148
148
  @click="addLanguage"
149
149
  :disabled="!newLanguage.code"
@@ -3,7 +3,7 @@ import { ref, computed, onMounted, watch, inject } from 'vue'
3
3
  import type { HttpClient } from '../../entity/storage/ApiStorage'
4
4
  import AutoComplete from 'primevue/autocomplete'
5
5
  import Select from 'primevue/select'
6
- import Button from 'primevue/button'
6
+ import QdButton from '../base/QdButton.vue'
7
7
 
8
8
  interface ScopeRow {
9
9
  resource: string
@@ -266,7 +266,7 @@ onMounted(async () => {
266
266
  />
267
267
  <span v-if="isRowComplete(row)" class="scope-valid">✓</span>
268
268
  <span v-else class="scope-incomplete">...</span>
269
- <Button
269
+ <QdButton
270
270
  icon="pi pi-trash"
271
271
  severity="danger"
272
272
  text
@@ -279,7 +279,7 @@ onMounted(async () => {
279
279
  </div>
280
280
 
281
281
  <div class="scope-add">
282
- <Button
282
+ <QdButton
283
283
  label="Add Scope"
284
284
  icon="pi pi-plus"
285
285
  severity="secondary"
@@ -3,6 +3,10 @@
3
3
  */
4
4
 
5
5
  // Layout
6
+ // Base widget wrappers — the single indirection points over the widget
7
+ // library (#1391 exit-readiness)
8
+ export { default as QdButton } from './base/QdButton.vue'
9
+ export { default as QdMessage } from './base/QdMessage.vue'
6
10
  export { default as AppLayout } from './layout/AppLayout.vue'
7
11
  export { default as BaseLayout } from './layout/BaseLayout.vue'
8
12
  export { default as PageLayout } from './layout/PageLayout.vue'
@@ -21,7 +21,7 @@ import { useApp } from '../../composables/useApp'
21
21
  import { useAuth } from '../../composables/useAuth'
22
22
  import { useGuardDialog } from '../../composables/useGuardStore'
23
23
  import { useNavContext, type BreadcrumbItem, type NavLinkItem } from '../../composables/useNavContext'
24
- import Button from 'primevue/button'
24
+ import QdButton from '../base/QdButton.vue'
25
25
  import Breadcrumb from 'primevue/breadcrumb'
26
26
  import UnsavedChangesDialog from '../dialogs/UnsavedChangesDialog.vue'
27
27
  import SidebarBox from './SidebarBox.vue'
@@ -366,7 +366,7 @@ const showBreadcrumb = computed<boolean>(() => {
366
366
  <main class="main-content" :class="{ 'main-content--sidebar-collapsed': sidebarCollapsed }">
367
367
  <!-- Mobile header bar -->
368
368
  <div class="mobile-header">
369
- <Button
369
+ <QdButton
370
370
  icon="pi pi-bars"
371
371
  severity="secondary"
372
372
  text
@@ -17,7 +17,7 @@
17
17
  */
18
18
  import PageHeader from './PageHeader.vue'
19
19
  import CardsGrid from '../display/CardsGrid.vue'
20
- import Button from 'primevue/button'
20
+ import QdButton from '../base/QdButton.vue'
21
21
 
22
22
  interface TitleParts {
23
23
  action?: string
@@ -89,7 +89,7 @@ function resolveLabel(label: string | (() => string)): string {
89
89
  </template>
90
90
  <template #actions>
91
91
  <slot name="header-actions" ></slot>
92
- <Button
92
+ <QdButton
93
93
  v-for="action in headerActions"
94
94
  :key="action.name"
95
95
  :label="resolveLabel(action.label)"
@@ -11,7 +11,7 @@ import { computed, type ComputedRef } from 'vue'
11
11
  import { useRouter } from 'vue-router'
12
12
  import { prettifyRole } from '../../../utils/formatters'
13
13
  import { useAuth } from '../../../composables/useAuth'
14
- import Button from 'primevue/button'
14
+ import QdButton from '../../base/QdButton.vue'
15
15
 
16
16
  interface UserData {
17
17
  username?: string
@@ -56,7 +56,7 @@ function handleLogout(): void {
56
56
  <div class="user-name">{{ userDisplayName }}</div>
57
57
  <div class="user-role">{{ userSubtitle }}</div>
58
58
  </div>
59
- <Button
59
+ <QdButton
60
60
  icon="pi pi-sign-out"
61
61
  severity="secondary"
62
62
  text
@@ -12,7 +12,7 @@
12
12
  * - handler: Click handler function
13
13
  * - isDisabled: Boolean disabled state
14
14
  */
15
- import Button from 'primevue/button'
15
+ import QdButton from '../base/QdButton.vue'
16
16
 
17
17
  interface Action {
18
18
  name: string
@@ -32,7 +32,7 @@ defineProps<Props>()
32
32
 
33
33
  <template>
34
34
  <div class="table-actions">
35
- <Button
35
+ <QdButton
36
36
  v-for="action in actions"
37
37
  :key="action.name"
38
38
  :icon="action.icon"
@@ -21,7 +21,7 @@ import FilterBar from './FilterBar.vue'
21
21
  import ActionButtons from './ActionButtons.vue'
22
22
  import DataTable from 'primevue/datatable'
23
23
  import Column from 'primevue/column'
24
- import Button from 'primevue/button'
24
+ import QdButton from '../base/QdButton.vue'
25
25
  import Select from 'primevue/select'
26
26
  import AutoComplete from 'primevue/autocomplete'
27
27
  import SplitButton from 'primevue/splitbutton'
@@ -333,7 +333,7 @@ function getFilterClass(filter: FilterConfig): Record<string, boolean> {
333
333
  <!-- Mobile: split button (primary action + dropdown) -->
334
334
  <template v-if="isMobile && headerActions.length > 0 && primaryHeaderAction">
335
335
  <!-- Single action: just a button -->
336
- <Button
336
+ <QdButton
337
337
  v-if="headerActions.length === 1"
338
338
  :label="resolveLabel(primaryHeaderAction.label)"
339
339
  :icon="primaryHeaderAction.icon"
@@ -355,7 +355,7 @@ function getFilterClass(filter: FilterConfig): Record<string, boolean> {
355
355
  </template>
356
356
  <!-- Desktop: individual buttons -->
357
357
  <template v-else>
358
- <Button
358
+ <QdButton
359
359
  v-for="action in headerActions"
360
360
  :key="action.name"
361
361
  :label="resolveLabel(action.label)"
@@ -417,7 +417,7 @@ function getFilterClass(filter: FilterConfig): Record<string, boolean> {
417
417
  />
418
418
  </template>
419
419
  <slot name="filters" ></slot>
420
- <Button
420
+ <QdButton
421
421
  v-if="hasActiveFilters"
422
422
  icon="pi pi-filter-slash"
423
423
  severity="secondary"