@quazardous/qdadm 1.22.0 → 2.0.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.
- package/README.md +1 -1
- package/package.json +1 -1
- package/src/components/index.ts +0 -3
- package/src/components/layout/AppLayout.vue +2 -2
- package/src/components/layout/BaseLayout.vue +1 -1
- package/src/components/layout/PageHeader.vue +1 -1
- package/src/components/show/ShowDisplay.vue +6 -10
- package/src/composables/index.ts +0 -7
- package/src/composables/useListPage.ts +3 -8
- package/src/composables/useNavContext.ts +1 -1
- package/src/composables/usePageTitle.ts +2 -2
- package/src/entity/EntityManager.crud.ts +6 -1
- package/src/entity/storage/ApiStorage.ts +0 -5
- package/src/entity/storage/LocalStorage.ts +0 -5
- package/src/entity/storage/MemoryStorage.ts +0 -5
- package/src/entity/storage/MockApiStorage.ts +0 -5
- package/src/entity/storage/SdkStorage.ts +0 -5
- package/src/generated/managers/testManager.ts +46 -0
- package/src/index.ts +0 -7
- package/src/utils/formatters.ts +38 -7
- package/src/utils/index.ts +1 -0
- package/src/components/edit/FormTab.vue +0 -217
- package/src/components/edit/FormTabs.vue +0 -120
- package/src/components/lists/ActionColumn.vue +0 -40
- package/src/composables/useCurrentEntity.ts +0 -60
- package/src/composables/useForm.ts +0 -544
|
@@ -1,217 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
/**
|
|
3
|
-
* FormTab - Normalized tab header component
|
|
4
|
-
*
|
|
5
|
-
* @deprecated Use FieldGroups with layout="tabs" instead. FieldGroups now supports
|
|
6
|
-
* icon, badge, count, visible, and disabled options on groups.
|
|
7
|
-
*
|
|
8
|
-
* ```ts
|
|
9
|
-
* // Before (deprecated)
|
|
10
|
-
* <FormTab value="general" label="General" icon="pi-cog" :count="5" />
|
|
11
|
-
*
|
|
12
|
-
* // After (recommended)
|
|
13
|
-
* form.group('general', ['field1'], { label: 'General', icon: 'cog', count: 5 })
|
|
14
|
-
* ```
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import { type PropType } from 'vue'
|
|
18
|
-
import Tab from 'primevue/tab'
|
|
19
|
-
import Tag from 'primevue/tag'
|
|
20
|
-
|
|
21
|
-
type BadgeSeverity = 'secondary' | 'info' | 'success' | 'warn' | 'danger' | 'contrast'
|
|
22
|
-
|
|
23
|
-
const props = defineProps({
|
|
24
|
-
/**
|
|
25
|
-
* Tab identifier (used for v-model matching)
|
|
26
|
-
*/
|
|
27
|
-
value: {
|
|
28
|
-
type: String,
|
|
29
|
-
required: true
|
|
30
|
-
},
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Display label
|
|
34
|
-
*/
|
|
35
|
-
label: {
|
|
36
|
-
type: String,
|
|
37
|
-
required: true
|
|
38
|
-
},
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* PrimeIcon class (without 'pi' prefix or with full class)
|
|
42
|
-
* Examples: 'pi-cog', 'cog', 'pi pi-cog'
|
|
43
|
-
*/
|
|
44
|
-
icon: {
|
|
45
|
-
type: String as () => string | null,
|
|
46
|
-
default: null
|
|
47
|
-
},
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Count to display as badge (shows only if > 0)
|
|
51
|
-
*/
|
|
52
|
-
count: {
|
|
53
|
-
type: Number as () => number | null,
|
|
54
|
-
default: null
|
|
55
|
-
},
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Custom badge text (alternative to count)
|
|
59
|
-
*/
|
|
60
|
-
badge: {
|
|
61
|
-
type: [String, Number] as unknown as PropType<string | number | null>,
|
|
62
|
-
default: null
|
|
63
|
-
},
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Badge severity/color
|
|
67
|
-
*/
|
|
68
|
-
badgeSeverity: {
|
|
69
|
-
type: String as () => BadgeSeverity,
|
|
70
|
-
default: 'secondary',
|
|
71
|
-
validator: (v: string) => ['secondary', 'info', 'success', 'warn', 'danger', 'contrast'].includes(v)
|
|
72
|
-
},
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Show/hide the tab
|
|
76
|
-
*/
|
|
77
|
-
visible: {
|
|
78
|
-
type: Boolean,
|
|
79
|
-
default: true
|
|
80
|
-
},
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Disable tab interaction
|
|
84
|
-
*/
|
|
85
|
-
disabled: {
|
|
86
|
-
type: Boolean,
|
|
87
|
-
default: false
|
|
88
|
-
}
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Normalize icon class
|
|
93
|
-
*/
|
|
94
|
-
function getIconClass(): string | null {
|
|
95
|
-
if (!props.icon) return null
|
|
96
|
-
// Already has 'pi' prefix
|
|
97
|
-
if (props.icon.startsWith('pi')) {
|
|
98
|
-
return props.icon.includes(' ') ? props.icon : `pi ${props.icon}`
|
|
99
|
-
}
|
|
100
|
-
// Just icon name
|
|
101
|
-
return `pi pi-${props.icon}`
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Get count value to display
|
|
106
|
-
*/
|
|
107
|
-
function getCountValue(): number | null {
|
|
108
|
-
if (props.count !== null && props.count > 0) return props.count
|
|
109
|
-
return null
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Get badge value to display (separate from count)
|
|
114
|
-
*/
|
|
115
|
-
function getBadgeValue(): string | number | null {
|
|
116
|
-
if (props.badge !== null) return props.badge
|
|
117
|
-
// If no badge but count provided, show count as badge (legacy behavior)
|
|
118
|
-
if (props.count !== null && props.count > 0 && props.badge === null) return props.count
|
|
119
|
-
return null
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Check if we should show count and badge separately
|
|
124
|
-
*/
|
|
125
|
-
function showBothCountAndBadge(): boolean {
|
|
126
|
-
return props.count !== null && props.count > 0 && props.badge !== null
|
|
127
|
-
}
|
|
128
|
-
</script>
|
|
129
|
-
|
|
130
|
-
<template>
|
|
131
|
-
<Tab
|
|
132
|
-
v-if="visible"
|
|
133
|
-
:value="value"
|
|
134
|
-
:disabled="disabled"
|
|
135
|
-
>
|
|
136
|
-
<i v-if="icon" :class="getIconClass()" class="tab-icon" ></i>
|
|
137
|
-
<span class="tab-label">{{ label }}</span>
|
|
138
|
-
<!-- When both count and badge are provided, show count first then badge indicator -->
|
|
139
|
-
<template v-if="showBothCountAndBadge()">
|
|
140
|
-
<Tag
|
|
141
|
-
:value="String(getCountValue())"
|
|
142
|
-
severity="secondary"
|
|
143
|
-
class="tab-badge"
|
|
144
|
-
/>
|
|
145
|
-
<span class="tab-alert-dot" :class="`alert-${badgeSeverity}`"></span>
|
|
146
|
-
</template>
|
|
147
|
-
<!-- Otherwise show single badge (legacy behavior) -->
|
|
148
|
-
<Tag
|
|
149
|
-
v-else-if="getBadgeValue() !== null"
|
|
150
|
-
:value="String(getBadgeValue())"
|
|
151
|
-
:severity="badgeSeverity"
|
|
152
|
-
class="tab-badge"
|
|
153
|
-
/>
|
|
154
|
-
</Tab>
|
|
155
|
-
</template>
|
|
156
|
-
|
|
157
|
-
<style scoped>
|
|
158
|
-
/*
|
|
159
|
-
* Only keep styles here that REQUIRE scoping (:deep, dynamic binding, component-specific overrides).
|
|
160
|
-
* Generic/reusable styles belong in src/styles/ partials (see _forms.scss, _cards.scss, etc.).
|
|
161
|
-
*/
|
|
162
|
-
.tab-icon {
|
|
163
|
-
margin-right: 0.5rem;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
.tab-label {
|
|
167
|
-
/* Ensure consistent text rendering */
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
.tab-badge {
|
|
171
|
-
margin-left: 0.5rem;
|
|
172
|
-
font-size: 0.7rem;
|
|
173
|
-
padding: 0.15rem 0.4rem;
|
|
174
|
-
min-width: 1.25rem;
|
|
175
|
-
text-align: center;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
.tab-alert-dot {
|
|
179
|
-
display: inline-block;
|
|
180
|
-
width: 8px !important;
|
|
181
|
-
height: 8px !important;
|
|
182
|
-
min-width: 8px;
|
|
183
|
-
max-width: 8px;
|
|
184
|
-
border-radius: 50%;
|
|
185
|
-
margin-left: 0.35rem;
|
|
186
|
-
animation: pulse 1.5s infinite;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
.alert-warn {
|
|
190
|
-
background-color: var(--p-orange-500);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
.alert-danger {
|
|
194
|
-
background-color: var(--p-red-500);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
.alert-info {
|
|
198
|
-
background-color: var(--p-blue-500);
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
.alert-success {
|
|
202
|
-
background-color: var(--p-green-500);
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
.alert-secondary {
|
|
206
|
-
background-color: var(--p-gray-500);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
.alert-contrast {
|
|
210
|
-
background-color: var(--p-primary-500);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
@keyframes pulse {
|
|
214
|
-
0%, 100% { opacity: 1; }
|
|
215
|
-
50% { opacity: 0.5; }
|
|
216
|
-
}
|
|
217
|
-
</style>
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
/**
|
|
3
|
-
* FormTabs - Normalized tab container for forms
|
|
4
|
-
*
|
|
5
|
-
* @deprecated Use FieldGroups with layout="tabs" instead. FieldGroups now supports
|
|
6
|
-
* icon, badge, count, visible, and disabled options on groups.
|
|
7
|
-
*
|
|
8
|
-
* ```vue
|
|
9
|
-
* <!-- Before (deprecated) -->
|
|
10
|
-
* <FormTabs v-model="activeTab">
|
|
11
|
-
* <template #tabs>
|
|
12
|
-
* <FormTab value="general" label="General" icon="pi-cog" />
|
|
13
|
-
* </template>
|
|
14
|
-
* <template #panels>
|
|
15
|
-
* <TabPanel value="general">...</TabPanel>
|
|
16
|
-
* </template>
|
|
17
|
-
* </FormTabs>
|
|
18
|
-
*
|
|
19
|
-
* <!-- After (recommended) -->
|
|
20
|
-
* form.group('general', ['field1', 'field2'], { label: 'General', icon: 'cog' })
|
|
21
|
-
* <FieldGroups :groups="form.groups.value" layout="tabs">
|
|
22
|
-
* <template #field="{ field }">
|
|
23
|
-
* <FormField :field="field" />
|
|
24
|
-
* </template>
|
|
25
|
-
* </FieldGroups>
|
|
26
|
-
* ```
|
|
27
|
-
*/
|
|
28
|
-
|
|
29
|
-
import Tabs from 'primevue/tabs'
|
|
30
|
-
import TabList from 'primevue/tablist'
|
|
31
|
-
import TabPanels from 'primevue/tabpanels'
|
|
32
|
-
|
|
33
|
-
defineProps({
|
|
34
|
-
/**
|
|
35
|
-
* Active tab value (v-model)
|
|
36
|
-
*/
|
|
37
|
-
modelValue: {
|
|
38
|
-
type: String,
|
|
39
|
-
required: true
|
|
40
|
-
}
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
const emit = defineEmits<{
|
|
44
|
-
'update:modelValue': [value: string]
|
|
45
|
-
}>()
|
|
46
|
-
|
|
47
|
-
function onTabChange(value: string | number): void {
|
|
48
|
-
emit('update:modelValue', String(value))
|
|
49
|
-
}
|
|
50
|
-
</script>
|
|
51
|
-
|
|
52
|
-
<template>
|
|
53
|
-
<div class="form-tabs">
|
|
54
|
-
<Tabs :value="modelValue" @update:value="onTabChange">
|
|
55
|
-
<TabList class="form-tabs__list">
|
|
56
|
-
<slot name="tabs" ></slot>
|
|
57
|
-
</TabList>
|
|
58
|
-
<TabPanels class="form-tabs__panels">
|
|
59
|
-
<slot name="panels" ></slot>
|
|
60
|
-
</TabPanels>
|
|
61
|
-
</Tabs>
|
|
62
|
-
</div>
|
|
63
|
-
</template>
|
|
64
|
-
|
|
65
|
-
<style scoped>
|
|
66
|
-
/*
|
|
67
|
-
* Only keep styles here that REQUIRE scoping (:deep, dynamic binding, component-specific overrides).
|
|
68
|
-
* Generic/reusable styles belong in src/styles/ partials (see _forms.scss, _cards.scss, etc.).
|
|
69
|
-
*/
|
|
70
|
-
.form-tabs {
|
|
71
|
-
margin-top: 1rem;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
.form-tabs :deep(.form-tabs__list) {
|
|
75
|
-
border-bottom: 1px solid var(--p-surface-200);
|
|
76
|
-
gap: 0;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
.form-tabs :deep(.form-tabs__panels) {
|
|
80
|
-
padding: 1.5rem 0;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/* Tab styling */
|
|
84
|
-
.form-tabs :deep(.p-tab) {
|
|
85
|
-
padding: 0.75rem 1.25rem;
|
|
86
|
-
border-radius: 0;
|
|
87
|
-
border-bottom: 2px solid transparent;
|
|
88
|
-
margin-bottom: -1px;
|
|
89
|
-
transition: all 0.2s ease;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
.form-tabs :deep(.p-tab:hover) {
|
|
93
|
-
background: var(--p-surface-50);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
.form-tabs :deep(.p-tab[data-p-active="true"]) {
|
|
97
|
-
border-bottom-color: var(--p-primary-500);
|
|
98
|
-
color: var(--p-primary-500);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/* Tab icon alignment */
|
|
102
|
-
.form-tabs :deep(.p-tab .pi) {
|
|
103
|
-
margin-right: 0.5rem;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/* Tab badge/count styling */
|
|
107
|
-
.form-tabs :deep(.tab-badge) {
|
|
108
|
-
margin-left: 0.5rem;
|
|
109
|
-
font-size: 0.7rem;
|
|
110
|
-
padding: 0.15rem 0.4rem;
|
|
111
|
-
min-width: 1.25rem;
|
|
112
|
-
text-align: center;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/* Disabled tab */
|
|
116
|
-
.form-tabs :deep(.p-tab[data-p-disabled="true"]) {
|
|
117
|
-
opacity: 0.5;
|
|
118
|
-
cursor: not-allowed;
|
|
119
|
-
}
|
|
120
|
-
</style>
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
/**
|
|
3
|
-
* ActionColumn - Reusable table action buttons (edit, delete)
|
|
4
|
-
*
|
|
5
|
-
* Slots:
|
|
6
|
-
* - default: Extra actions (after edit/delete)
|
|
7
|
-
*
|
|
8
|
-
* Emits:
|
|
9
|
-
* - edit: When edit button is clicked
|
|
10
|
-
* - delete: When delete button is clicked
|
|
11
|
-
*/
|
|
12
|
-
import Button from 'primevue/button'
|
|
13
|
-
|
|
14
|
-
defineEmits<{
|
|
15
|
-
edit: []
|
|
16
|
-
delete: []
|
|
17
|
-
}>()
|
|
18
|
-
</script>
|
|
19
|
-
|
|
20
|
-
<template>
|
|
21
|
-
<div class="table-actions">
|
|
22
|
-
<Button
|
|
23
|
-
icon="pi pi-pencil"
|
|
24
|
-
severity="secondary"
|
|
25
|
-
text
|
|
26
|
-
rounded
|
|
27
|
-
@click="$emit('edit')"
|
|
28
|
-
v-tooltip.top="'Edit'"
|
|
29
|
-
/>
|
|
30
|
-
<Button
|
|
31
|
-
icon="pi pi-trash"
|
|
32
|
-
severity="danger"
|
|
33
|
-
text
|
|
34
|
-
rounded
|
|
35
|
-
@click="$emit('delete')"
|
|
36
|
-
v-tooltip.top="'Delete'"
|
|
37
|
-
/>
|
|
38
|
-
<slot ></slot>
|
|
39
|
-
</div>
|
|
40
|
-
</template>
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @deprecated Use useStackHydrator() instead
|
|
3
|
-
*
|
|
4
|
-
* Legacy composable for setting breadcrumb entity data.
|
|
5
|
-
* This has been replaced by the activeStack + stackHydrator system.
|
|
6
|
-
*
|
|
7
|
-
* Migration:
|
|
8
|
-
* ```ts
|
|
9
|
-
* // Before (deprecated)
|
|
10
|
-
* const { setBreadcrumbEntity } = useCurrentEntity()
|
|
11
|
-
* setBreadcrumbEntity(data)
|
|
12
|
-
*
|
|
13
|
-
* // After
|
|
14
|
-
* const hydrator = useStackHydrator()
|
|
15
|
-
* hydrator.setCurrentData(data)
|
|
16
|
-
* ```
|
|
17
|
-
*/
|
|
18
|
-
import { useStackHydrator } from '../chain/useStackHydrator'
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Return type for useCurrentEntity
|
|
22
|
-
*/
|
|
23
|
-
export interface UseCurrentEntityReturn {
|
|
24
|
-
/** @deprecated Use hydrator.setCurrentData() instead */
|
|
25
|
-
setBreadcrumbEntity: (data: unknown, level?: number) => void
|
|
26
|
-
/** @deprecated Use hydrator.setCurrentData() instead */
|
|
27
|
-
setCurrentEntity: (data: unknown) => void
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* @deprecated Use useStackHydrator() instead
|
|
32
|
-
*/
|
|
33
|
-
export function useCurrentEntity(): UseCurrentEntityReturn {
|
|
34
|
-
console.warn(
|
|
35
|
-
'[qdadm] useCurrentEntity is deprecated. Use useStackHydrator() instead.'
|
|
36
|
-
)
|
|
37
|
-
|
|
38
|
-
const hydrator = useStackHydrator()
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* @deprecated Use hydrator.setCurrentData() instead
|
|
42
|
-
*/
|
|
43
|
-
function setBreadcrumbEntity(data: unknown, level = 1): void {
|
|
44
|
-
if (level === 1) {
|
|
45
|
-
hydrator.setCurrentData(data)
|
|
46
|
-
} else {
|
|
47
|
-
// For parent levels, use setEntityData with entity name
|
|
48
|
-
// But we don't have entity name here - just set current
|
|
49
|
-
hydrator.setCurrentData(data)
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// Backwards compat alias
|
|
54
|
-
const setCurrentEntity = (data: unknown): void => setBreadcrumbEntity(data, 1)
|
|
55
|
-
|
|
56
|
-
return {
|
|
57
|
-
setBreadcrumbEntity,
|
|
58
|
-
setCurrentEntity,
|
|
59
|
-
}
|
|
60
|
-
}
|