qdadm 0.13.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 (82) hide show
  1. package/CHANGELOG.md +270 -0
  2. package/LICENSE +21 -0
  3. package/README.md +166 -0
  4. package/package.json +48 -0
  5. package/src/assets/logo.svg +6 -0
  6. package/src/components/BoolCell.vue +28 -0
  7. package/src/components/dialogs/BulkStatusDialog.vue +43 -0
  8. package/src/components/dialogs/MultiStepDialog.vue +321 -0
  9. package/src/components/dialogs/SimpleDialog.vue +108 -0
  10. package/src/components/dialogs/UnsavedChangesDialog.vue +87 -0
  11. package/src/components/display/CardsGrid.vue +155 -0
  12. package/src/components/display/CopyableId.vue +92 -0
  13. package/src/components/display/EmptyState.vue +114 -0
  14. package/src/components/display/IntensityBar.vue +171 -0
  15. package/src/components/display/RichCardsGrid.vue +220 -0
  16. package/src/components/editors/JsonEditorFoldable.vue +467 -0
  17. package/src/components/editors/JsonStructuredField.vue +218 -0
  18. package/src/components/editors/JsonViewer.vue +91 -0
  19. package/src/components/editors/KeyValueEditor.vue +314 -0
  20. package/src/components/editors/LanguageEditor.vue +245 -0
  21. package/src/components/editors/ScopeEditor.vue +341 -0
  22. package/src/components/editors/VanillaJsonEditor.vue +185 -0
  23. package/src/components/forms/FormActions.vue +104 -0
  24. package/src/components/forms/FormField.vue +64 -0
  25. package/src/components/forms/FormTab.vue +217 -0
  26. package/src/components/forms/FormTabs.vue +108 -0
  27. package/src/components/index.js +44 -0
  28. package/src/components/layout/AppLayout.vue +430 -0
  29. package/src/components/layout/Breadcrumb.vue +106 -0
  30. package/src/components/layout/PageHeader.vue +75 -0
  31. package/src/components/layout/PageLayout.vue +93 -0
  32. package/src/components/lists/ActionButtons.vue +41 -0
  33. package/src/components/lists/ActionColumn.vue +37 -0
  34. package/src/components/lists/FilterBar.vue +53 -0
  35. package/src/components/lists/ListPage.vue +319 -0
  36. package/src/composables/index.js +19 -0
  37. package/src/composables/useApp.js +43 -0
  38. package/src/composables/useAuth.js +49 -0
  39. package/src/composables/useBareForm.js +143 -0
  40. package/src/composables/useBreadcrumb.js +221 -0
  41. package/src/composables/useDirtyState.js +103 -0
  42. package/src/composables/useEntityTitle.js +121 -0
  43. package/src/composables/useForm.js +254 -0
  44. package/src/composables/useGuardStore.js +37 -0
  45. package/src/composables/useJsonSyntax.js +101 -0
  46. package/src/composables/useListPageBuilder.js +1176 -0
  47. package/src/composables/useNavigation.js +89 -0
  48. package/src/composables/usePageBuilder.js +334 -0
  49. package/src/composables/useStatus.js +146 -0
  50. package/src/composables/useSubEditor.js +165 -0
  51. package/src/composables/useTabSync.js +110 -0
  52. package/src/composables/useUnsavedChangesGuard.js +122 -0
  53. package/src/entity/EntityManager.js +540 -0
  54. package/src/entity/index.js +11 -0
  55. package/src/entity/storage/ApiStorage.js +146 -0
  56. package/src/entity/storage/LocalStorage.js +220 -0
  57. package/src/entity/storage/MemoryStorage.js +201 -0
  58. package/src/entity/storage/index.js +10 -0
  59. package/src/index.js +29 -0
  60. package/src/kernel/Kernel.js +234 -0
  61. package/src/kernel/index.js +7 -0
  62. package/src/module/index.js +16 -0
  63. package/src/module/moduleRegistry.js +222 -0
  64. package/src/orchestrator/Orchestrator.js +141 -0
  65. package/src/orchestrator/index.js +8 -0
  66. package/src/orchestrator/useOrchestrator.js +61 -0
  67. package/src/plugin.js +142 -0
  68. package/src/styles/_alerts.css +48 -0
  69. package/src/styles/_code.css +33 -0
  70. package/src/styles/_dialogs.css +17 -0
  71. package/src/styles/_markdown.css +82 -0
  72. package/src/styles/_show-pages.css +84 -0
  73. package/src/styles/index.css +16 -0
  74. package/src/styles/main.css +845 -0
  75. package/src/styles/theme/components.css +286 -0
  76. package/src/styles/theme/index.css +10 -0
  77. package/src/styles/theme/tokens.css +125 -0
  78. package/src/styles/theme/utilities.css +172 -0
  79. package/src/utils/debugInjector.js +261 -0
  80. package/src/utils/formatters.js +165 -0
  81. package/src/utils/index.js +35 -0
  82. package/src/utils/transformers.js +105 -0
@@ -0,0 +1,217 @@
1
+ <script setup>
2
+ /**
3
+ * FormTab - Normalized tab header component
4
+ *
5
+ * Provides consistent tab headers with optional icon, count badge, and visibility control.
6
+ *
7
+ * Props:
8
+ * - value: Tab identifier (required)
9
+ * - label: Display text (required)
10
+ * - icon: PrimeIcon class (e.g., 'pi-cog')
11
+ * - count: Number to display as badge
12
+ * - badge: Custom badge text/value
13
+ * - badgeSeverity: Badge color ('secondary', 'info', 'success', 'warn', 'danger')
14
+ * - visible: Show/hide tab (default: true)
15
+ * - disabled: Disable tab interaction
16
+ *
17
+ * Usage:
18
+ * <FormTab value="general" label="General" icon="pi-cog" />
19
+ * <FormTab value="items" label="Items" :count="5" />
20
+ * <FormTab value="errors" label="Errors" :count="errors.length" badge-severity="danger" />
21
+ * <FormTab value="advanced" label="Advanced" :visible="isEdit" />
22
+ */
23
+
24
+ import Tab from 'primevue/tab'
25
+ import Tag from 'primevue/tag'
26
+
27
+ const props = defineProps({
28
+ /**
29
+ * Tab identifier (used for v-model matching)
30
+ */
31
+ value: {
32
+ type: String,
33
+ required: true
34
+ },
35
+
36
+ /**
37
+ * Display label
38
+ */
39
+ label: {
40
+ type: String,
41
+ required: true
42
+ },
43
+
44
+ /**
45
+ * PrimeIcon class (without 'pi' prefix or with full class)
46
+ * Examples: 'pi-cog', 'cog', 'pi pi-cog'
47
+ */
48
+ icon: {
49
+ type: String,
50
+ default: null
51
+ },
52
+
53
+ /**
54
+ * Count to display as badge (shows only if > 0)
55
+ */
56
+ count: {
57
+ type: Number,
58
+ default: null
59
+ },
60
+
61
+ /**
62
+ * Custom badge text (alternative to count)
63
+ */
64
+ badge: {
65
+ type: [String, Number],
66
+ default: null
67
+ },
68
+
69
+ /**
70
+ * Badge severity/color
71
+ */
72
+ badgeSeverity: {
73
+ type: String,
74
+ default: 'secondary',
75
+ validator: (v) => ['secondary', 'info', 'success', 'warn', 'danger', 'contrast'].includes(v)
76
+ },
77
+
78
+ /**
79
+ * Show/hide the tab
80
+ */
81
+ visible: {
82
+ type: Boolean,
83
+ default: true
84
+ },
85
+
86
+ /**
87
+ * Disable tab interaction
88
+ */
89
+ disabled: {
90
+ type: Boolean,
91
+ default: false
92
+ }
93
+ })
94
+
95
+ /**
96
+ * Normalize icon class
97
+ */
98
+ function getIconClass() {
99
+ if (!props.icon) return null
100
+ // Already has 'pi' prefix
101
+ if (props.icon.startsWith('pi')) {
102
+ return props.icon.includes(' ') ? props.icon : `pi ${props.icon}`
103
+ }
104
+ // Just icon name
105
+ return `pi pi-${props.icon}`
106
+ }
107
+
108
+ /**
109
+ * Get count value to display
110
+ */
111
+ function getCountValue() {
112
+ if (props.count !== null && props.count > 0) return props.count
113
+ return null
114
+ }
115
+
116
+ /**
117
+ * Get badge value to display (separate from count)
118
+ */
119
+ function getBadgeValue() {
120
+ if (props.badge !== null) return props.badge
121
+ // If no badge but count provided, show count as badge (legacy behavior)
122
+ if (props.count !== null && props.count > 0 && props.badge === null) return props.count
123
+ return null
124
+ }
125
+
126
+ /**
127
+ * Check if we should show count and badge separately
128
+ */
129
+ function showBothCountAndBadge() {
130
+ return props.count !== null && props.count > 0 && props.badge !== null
131
+ }
132
+ </script>
133
+
134
+ <template>
135
+ <Tab
136
+ v-if="visible"
137
+ :value="value"
138
+ :disabled="disabled"
139
+ >
140
+ <i v-if="icon" :class="getIconClass()" class="tab-icon" ></i>
141
+ <span class="tab-label">{{ label }}</span>
142
+ <!-- When both count and badge are provided, show count first then badge indicator -->
143
+ <template v-if="showBothCountAndBadge()">
144
+ <Tag
145
+ :value="String(getCountValue())"
146
+ severity="secondary"
147
+ class="tab-badge"
148
+ />
149
+ <span class="tab-alert-dot" :class="`alert-${badgeSeverity}`"></span>
150
+ </template>
151
+ <!-- Otherwise show single badge (legacy behavior) -->
152
+ <Tag
153
+ v-else-if="getBadgeValue() !== null"
154
+ :value="String(getBadgeValue())"
155
+ :severity="badgeSeverity"
156
+ class="tab-badge"
157
+ />
158
+ </Tab>
159
+ </template>
160
+
161
+ <style scoped>
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>
@@ -0,0 +1,108 @@
1
+ <script setup>
2
+ /**
3
+ * FormTabs - Normalized tab container for forms
4
+ *
5
+ * Provides consistent styling and behavior for form tabs.
6
+ * Works with FormTab component for individual tabs.
7
+ *
8
+ * Usage:
9
+ * <FormTabs v-model="activeTab" @update:modelValue="onTabChange">
10
+ * <template #tabs>
11
+ * <FormTab value="general" label="General" icon="pi-cog" />
12
+ * <FormTab value="items" label="Items" icon="pi-list" :count="items.length" />
13
+ * <FormTab value="advanced" label="Advanced" :visible="isEdit" />
14
+ * </template>
15
+ * <template #panels>
16
+ * <TabPanel value="general">...</TabPanel>
17
+ * <TabPanel value="items">...</TabPanel>
18
+ * <TabPanel value="advanced">...</TabPanel>
19
+ * </template>
20
+ * </FormTabs>
21
+ */
22
+
23
+ import Tabs from 'primevue/tabs'
24
+ import TabList from 'primevue/tablist'
25
+ import TabPanels from 'primevue/tabpanels'
26
+
27
+ defineProps({
28
+ /**
29
+ * Active tab value (v-model)
30
+ */
31
+ modelValue: {
32
+ type: String,
33
+ required: true
34
+ }
35
+ })
36
+
37
+ const emit = defineEmits(['update:modelValue'])
38
+
39
+ function onTabChange(value) {
40
+ emit('update:modelValue', value)
41
+ }
42
+ </script>
43
+
44
+ <template>
45
+ <div class="form-tabs">
46
+ <Tabs :value="modelValue" @update:value="onTabChange">
47
+ <TabList class="form-tabs__list">
48
+ <slot name="tabs" ></slot>
49
+ </TabList>
50
+ <TabPanels class="form-tabs__panels">
51
+ <slot name="panels" ></slot>
52
+ </TabPanels>
53
+ </Tabs>
54
+ </div>
55
+ </template>
56
+
57
+ <style scoped>
58
+ .form-tabs {
59
+ margin-top: 1rem;
60
+ }
61
+
62
+ .form-tabs :deep(.form-tabs__list) {
63
+ border-bottom: 1px solid var(--p-surface-200);
64
+ gap: 0;
65
+ }
66
+
67
+ .form-tabs :deep(.form-tabs__panels) {
68
+ padding: 1.5rem 0;
69
+ }
70
+
71
+ /* Tab styling */
72
+ .form-tabs :deep(.p-tab) {
73
+ padding: 0.75rem 1.25rem;
74
+ border-radius: 0;
75
+ border-bottom: 2px solid transparent;
76
+ margin-bottom: -1px;
77
+ transition: all 0.2s ease;
78
+ }
79
+
80
+ .form-tabs :deep(.p-tab:hover) {
81
+ background: var(--p-surface-50);
82
+ }
83
+
84
+ .form-tabs :deep(.p-tab[data-p-active="true"]) {
85
+ border-bottom-color: var(--p-primary-500);
86
+ color: var(--p-primary-500);
87
+ }
88
+
89
+ /* Tab icon alignment */
90
+ .form-tabs :deep(.p-tab .pi) {
91
+ margin-right: 0.5rem;
92
+ }
93
+
94
+ /* Tab badge/count styling */
95
+ .form-tabs :deep(.tab-badge) {
96
+ margin-left: 0.5rem;
97
+ font-size: 0.7rem;
98
+ padding: 0.15rem 0.4rem;
99
+ min-width: 1.25rem;
100
+ text-align: center;
101
+ }
102
+
103
+ /* Disabled tab */
104
+ .form-tabs :deep(.p-tab[data-p-disabled="true"]) {
105
+ opacity: 0.5;
106
+ cursor: not-allowed;
107
+ }
108
+ </style>
@@ -0,0 +1,44 @@
1
+ /**
2
+ * qdadm - Components exports
3
+ */
4
+
5
+ // Layout
6
+ export { default as AppLayout } from './layout/AppLayout.vue'
7
+ export { default as PageLayout } from './layout/PageLayout.vue'
8
+ export { default as PageHeader } from './layout/PageHeader.vue'
9
+ export { default as Breadcrumb } from './layout/Breadcrumb.vue'
10
+
11
+ // Forms
12
+ export { default as FormField } from './forms/FormField.vue'
13
+ export { default as FormActions } from './forms/FormActions.vue'
14
+ export { default as FormTabs } from './forms/FormTabs.vue'
15
+ export { default as FormTab } from './forms/FormTab.vue'
16
+
17
+ // Lists
18
+ export { default as ListPage } from './lists/ListPage.vue'
19
+ export { default as ActionButtons } from './lists/ActionButtons.vue'
20
+ export { default as ActionColumn } from './lists/ActionColumn.vue'
21
+ export { default as FilterBar } from './lists/FilterBar.vue'
22
+
23
+ // Editors
24
+ export { default as KeyValueEditor } from './editors/KeyValueEditor.vue'
25
+ export { default as LanguageEditor } from './editors/LanguageEditor.vue'
26
+ export { default as ScopeEditor } from './editors/ScopeEditor.vue'
27
+ export { default as VanillaJsonEditor } from './editors/VanillaJsonEditor.vue'
28
+ export { default as JsonEditorFoldable } from './editors/JsonEditorFoldable.vue'
29
+ export { default as JsonStructuredField } from './editors/JsonStructuredField.vue'
30
+ export { default as JsonViewer } from './editors/JsonViewer.vue'
31
+
32
+ // Dialogs
33
+ export { default as SimpleDialog } from './dialogs/SimpleDialog.vue'
34
+ export { default as MultiStepDialog } from './dialogs/MultiStepDialog.vue'
35
+ export { default as BulkStatusDialog } from './dialogs/BulkStatusDialog.vue'
36
+ export { default as UnsavedChangesDialog } from './dialogs/UnsavedChangesDialog.vue'
37
+
38
+ // Display
39
+ export { default as CardsGrid } from './display/CardsGrid.vue'
40
+ export { default as RichCardsGrid } from './display/RichCardsGrid.vue'
41
+ export { default as CopyableId } from './display/CopyableId.vue'
42
+ export { default as EmptyState } from './display/EmptyState.vue'
43
+ export { default as IntensityBar } from './display/IntensityBar.vue'
44
+ export { default as BoolCell } from './BoolCell.vue'