@drax/crud-vue 3.46.0 → 3.48.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 (44) hide show
  1. package/package.json +4 -4
  2. package/src/components/Crud.vue +27 -12
  3. package/src/components/CrudActiveFilters.vue +11 -9
  4. package/src/components/CrudAi.vue +38 -25
  5. package/src/components/CrudAutocomplete.vue +14 -2
  6. package/src/components/CrudDialog.vue +6 -6
  7. package/src/components/CrudExportList.vue +13 -12
  8. package/src/components/CrudFieldRange.vue +8 -4
  9. package/src/components/CrudFilters.vue +8 -2
  10. package/src/components/CrudFiltersAction.vue +3 -3
  11. package/src/components/CrudFiltersDynamic.vue +18 -10
  12. package/src/components/CrudForm.vue +44 -31
  13. package/src/components/CrudFormField.vue +48 -8
  14. package/src/components/CrudFormList.vue +44 -32
  15. package/src/components/CrudFormRecord.vue +19 -11
  16. package/src/components/CrudImportList.vue +17 -16
  17. package/src/components/CrudList.vue +41 -12
  18. package/src/components/CrudListGallery.vue +65 -27
  19. package/src/components/CrudListTable.vue +49 -10
  20. package/src/components/CrudNotify.vue +3 -1
  21. package/src/components/CrudRefDisplay.vue +2 -2
  22. package/src/components/CrudRouteForm.vue +8 -4
  23. package/src/components/CrudRowValue.vue +9 -8
  24. package/src/components/CrudSearch.vue +2 -1
  25. package/src/components/buttons/CrudAiButton.vue +9 -4
  26. package/src/components/buttons/CrudColumnsButton.vue +22 -8
  27. package/src/components/buttons/CrudCreateButton.vue +9 -4
  28. package/src/components/buttons/CrudCreateOnTheFlyButton.vue +13 -4
  29. package/src/components/buttons/CrudDeleteButton.vue +9 -5
  30. package/src/components/buttons/CrudDialogNextButton.vue +19 -0
  31. package/src/components/buttons/CrudDialogPrevButton.vue +19 -0
  32. package/src/components/buttons/CrudExportButton.vue +13 -8
  33. package/src/components/buttons/CrudFilterButton.vue +10 -5
  34. package/src/components/buttons/CrudGroupByButton.vue +33 -16
  35. package/src/components/buttons/CrudImportButton.vue +16 -10
  36. package/src/components/buttons/CrudOpenRouteFormButton.vue +19 -0
  37. package/src/components/buttons/CrudRefreshButton.vue +9 -4
  38. package/src/components/buttons/CrudSavedQueriesButton.vue +42 -20
  39. package/src/components/buttons/CrudUpdateButton.vue +9 -5
  40. package/src/components/buttons/CrudViewButton.vue +9 -5
  41. package/src/components/combobox/EntityCombobox.vue +4 -0
  42. package/src/config/CrudButtonConfig.ts +104 -0
  43. package/src/cruds/EntityCrud.ts +7 -7
  44. package/src/index.ts +33 -1
@@ -6,8 +6,10 @@ import { useDateFormat } from "@drax/common-vue"
6
6
  import { useI18n } from "vue-i18n"
7
7
  import { useCrudGroupBy } from '../../composables/UseCrudGroupBy'
8
8
  import CrudActiveFilters from "../CrudActiveFilters.vue";
9
+ import { useCrudButtonConfig } from "../../config/CrudButtonConfig";
9
10
 
10
11
  const { t, te } = useI18n()
12
+ const buttonConfig = useCrudButtonConfig("groupBy")
11
13
 
12
14
  const {formatDateByUnit} = useDateFormat()
13
15
 
@@ -66,25 +68,31 @@ const totalCount = computed(() => {
66
68
  </script>
67
69
 
68
70
  <template>
69
- <div>
71
+ <div id="crud-group-by-wrapper" class="crud-group-by-wrapper">
70
72
  <v-btn
73
+ id="crud-group-by-button"
74
+ class="crud-group-by-button mr-1"
71
75
  icon
72
- variant="text"
76
+ :variant="buttonConfig.variant"
77
+ :rounded="buttonConfig.rounded"
78
+ :color="buttonConfig.color"
73
79
  @click="openDialog"
74
80
  >
75
- <v-icon>mdi-chart-bar</v-icon>
81
+ <v-icon id="crud-group-by-button-icon" class="crud-group-by-button__icon">{{ buttonConfig.icon }}</v-icon>
76
82
  <v-tooltip activator="parent" location="bottom">
77
83
  {{ t('crud.groupBy.button') }}
78
84
  </v-tooltip>
79
85
  </v-btn>
80
86
 
81
- <v-dialog v-model="dialog" max-width="800" >
82
- <v-card>
83
- <v-card-title class="d-flex align-center">
84
- <v-icon class="mr-2">mdi-chart-bar</v-icon>
87
+ <v-dialog id="crud-group-by-dialog" class="crud-group-by-dialog" v-model="dialog" max-width="800" >
88
+ <v-card id="crud-group-by-card" class="crud-group-by-dialog__card">
89
+ <v-card-title id="crud-group-by-title" class="crud-group-by-dialog__title d-flex align-center">
90
+ <v-icon id="crud-group-by-title-icon" class="crud-group-by-dialog__title-icon mr-2">mdi-chart-bar</v-icon>
85
91
  {{ t('crud.groupBy.title') }}
86
92
  <v-spacer></v-spacer>
87
93
  <v-btn
94
+ id="crud-group-by-close-button"
95
+ class="crud-group-by-dialog__close-button"
88
96
  icon
89
97
  variant="text"
90
98
  @click="resetAndClose"
@@ -96,11 +104,13 @@ const totalCount = computed(() => {
96
104
 
97
105
  <v-divider></v-divider>
98
106
 
99
- <v-card-text>
100
- <crud-active-filters :entity="entity"></crud-active-filters>
107
+ <v-card-text id="crud-group-by-config" class="crud-group-by-dialog__config">
108
+ <crud-active-filters id="crud-group-by-active-filters" class="crud-group-by-dialog__active-filters" :entity="entity"></crud-active-filters>
101
109
  <v-divider></v-divider>
102
110
 
103
111
  <v-select
112
+ id="crud-group-by-fields-select"
113
+ class="crud-group-by-dialog__fields-select"
104
114
  v-model="selectedFields"
105
115
  :items="availableFields"
106
116
  item-title="label"
@@ -116,12 +126,13 @@ const totalCount = computed(() => {
116
126
  <!-- Selector de formato de fecha -->
117
127
  <v-select
118
128
  v-if="hasDateFields"
129
+ id="crud-group-by-date-format-select"
119
130
  v-model="dateFormat"
120
131
  :items="dateFormatOptions"
121
132
  :label="t('crud.groupBy.dateFormatLabel')"
122
133
  density="compact"
123
134
  variant="outlined"
124
- class="mt-4"
135
+ class="crud-group-by-dialog__date-format-select mt-4"
125
136
  :menu-props="{ zIndex: 3000 }"
126
137
  >
127
138
  <template v-slot:prepend-inner>
@@ -134,9 +145,11 @@ const totalCount = computed(() => {
134
145
 
135
146
  <v-divider></v-divider>
136
147
 
137
- <v-card-actions>
148
+ <v-card-actions id="crud-group-by-actions" class="crud-group-by-dialog__actions">
138
149
  <v-spacer></v-spacer>
139
150
  <v-btn
151
+ id="crud-group-by-apply-button"
152
+ class="crud-group-by-dialog__apply-button"
140
153
  color="primary"
141
154
  variant="flat"
142
155
  @click="handleGroupBy"
@@ -148,20 +161,22 @@ const totalCount = computed(() => {
148
161
  </v-card-actions>
149
162
  <v-divider class="mb-4"></v-divider>
150
163
  <!-- Tabla de resultados -->
151
- <v-card-text v-if="groupByData.length > 0">
164
+ <v-card-text v-if="groupByData.length > 0" id="crud-group-by-results" class="crud-group-by-dialog__results">
152
165
 
153
166
 
154
- <div class="d-flex align-center mb-3">
155
- <v-icon class="mr-2">mdi-table</v-icon>
156
- <span class="text-h6">{{ t('crud.groupBy.results') }}</span>
167
+ <div id="crud-group-by-results-header" class="crud-group-by-dialog__results-header d-flex align-center mb-3">
168
+ <v-icon id="crud-group-by-results-icon" class="crud-group-by-dialog__results-icon mr-2">mdi-table</v-icon>
169
+ <span id="crud-group-by-results-title" class="crud-group-by-dialog__results-title text-h6">{{ t('crud.groupBy.results') }}</span>
157
170
  <v-spacer></v-spacer>
158
- <v-chip color="primary" variant="flat" size="small">
171
+ <v-chip id="crud-group-by-total-chip" class="crud-group-by-dialog__total-chip" color="primary" variant="flat" size="small">
159
172
  {{ t('crud.groupBy.total') }}: {{ totalCount }}
160
173
  </v-chip>
161
174
  </div>
162
175
 
163
176
 
164
177
  <v-data-table
178
+ id="crud-group-by-results-table"
179
+ class="crud-group-by-dialog__results-table"
165
180
  :headers="headers"
166
181
  :items="groupByData"
167
182
  density="compact"
@@ -191,7 +206,9 @@ const totalCount = computed(() => {
191
206
  <!-- Formato especial para el count -->
192
207
  <template v-slot:item.count="{ value }">
193
208
  <v-chip color="primary" size="small" variant="flat">
209
+ <span class="crud-group-by-dialog__count-value">
194
210
  {{ value }}
211
+ </span>
195
212
  </v-chip>
196
213
  </template>
197
214
  </v-data-table>
@@ -4,8 +4,10 @@ import type {PropType} from "vue";
4
4
  import type {IEntityCrud} from "@drax/crud-share"
5
5
  import {useCrud} from "../../composables/UseCrud";
6
6
  import {useI18n} from "vue-i18n";
7
+ import {useCrudButtonConfig} from "../../config/CrudButtonConfig";
7
8
 
8
9
  const {t} = useI18n()
10
+ const buttonConfig = useCrudButtonConfig("import")
9
11
  const {entity} = defineProps({
10
12
  entity: {type: Object as PropType<IEntityCrud>, required: true},
11
13
  })
@@ -37,33 +39,37 @@ function onFileChange(event: Event) {
37
39
  </script>
38
40
 
39
41
  <template>
40
- <div v-if="entity.isImportable">
42
+ <div v-if="entity.isImportable" id="crud-import-button-wrapper" class="crud-import-button-wrapper">
41
43
  <input
42
44
  ref="fileInput"
43
- class="d-none"
45
+ id="crud-import-file-input"
46
+ class="crud-import-button__file-input d-none"
44
47
  type="file"
45
48
  :accept="entity.importFormats.includes('CSV') && entity.importFormats.includes('JSON') ? '.csv,.json,application/json,text/csv' : entity.importFormats.includes('CSV') ? '.csv,text/csv' : '.json,application/json'"
46
49
  @change="onFileChange"
47
50
  />
48
- <v-menu>
51
+ <v-menu id="crud-import-menu" class="crud-import-menu">
49
52
  <template v-slot:activator="{ props: mp }">
50
- <v-tooltip location="top">
53
+ <v-tooltip id="crud-import-button-tooltip" class="crud-import-button__tooltip" location="top">
51
54
  <template v-slot:activator="{ props }">
52
55
  <v-btn
53
56
  v-bind="{...mp, ...props}"
54
57
  :disabled="importLoading"
55
- class="mr-1"
56
- variant="text"
58
+ id="crud-import-button"
59
+ class="crud-import-button mr-1"
60
+ :variant="buttonConfig.variant"
61
+ :rounded="buttonConfig.rounded"
62
+ :color="buttonConfig.color"
57
63
  :loading="importLoading"
58
- icon="mdi-database-import-outline"
64
+ :icon="buttonConfig.icon"
59
65
  ></v-btn>
60
66
  </template>
61
67
  {{ t('action.import')}}
62
68
  </v-tooltip>
63
69
  </template>
64
- <v-list>
65
- <v-list-item v-for="format in entity.importFormats" @click="selectFormat(format)">
66
- <v-list-item-title>{{ format }}</v-list-item-title>
70
+ <v-list id="crud-import-format-list" class="crud-import-menu__list">
71
+ <v-list-item v-for="format in entity.importFormats" :id="`crud-import-format-${format}`" class="crud-import-menu__item" @click="selectFormat(format)">
72
+ <v-list-item-title class="crud-import-menu__item-title">{{ format }}</v-list-item-title>
67
73
  </v-list-item>
68
74
  </v-list>
69
75
  </v-menu>
@@ -0,0 +1,19 @@
1
+ <script setup lang="ts">
2
+ import {useCrudButtonConfig} from "../../config/CrudButtonConfig";
3
+
4
+ defineOptions({inheritAttrs: false})
5
+
6
+ const buttonConfig = useCrudButtonConfig("openRouteForm")
7
+ </script>
8
+
9
+ <template>
10
+ <v-btn
11
+ v-bind="$attrs"
12
+ :id="$attrs.id || 'crud-open-route-form-button'"
13
+ class="crud-open-route-form-button"
14
+ :icon="buttonConfig.icon"
15
+ :variant="buttonConfig.variant"
16
+ :rounded="buttonConfig.rounded"
17
+ :color="buttonConfig.color"
18
+ />
19
+ </template>
@@ -1,17 +1,22 @@
1
1
  <script setup lang="ts">
2
2
  import {useI18n} from "vue-i18n";
3
+ import {useCrudButtonConfig} from "../../config/CrudButtonConfig";
3
4
 
4
5
  const {t} = useI18n()
6
+ const buttonConfig = useCrudButtonConfig("refresh")
5
7
  </script>
6
8
 
7
9
  <template>
8
- <v-tooltip location="top">
10
+ <v-tooltip :id="`${$attrs.id || 'crud-refresh-button'}-tooltip`" class="crud-refresh-button__tooltip" location="top">
9
11
  <template v-slot:activator="{ props }">
10
12
  <v-btn
11
13
  v-bind="{ ...$attrs, ...props }"
12
- icon="mdi-refresh"
13
- class="mr-1"
14
- variant="text"
14
+ :icon="buttonConfig.icon"
15
+ :id="$attrs.id || 'crud-refresh-button'"
16
+ class="crud-refresh-button mr-1"
17
+ :variant="buttonConfig.variant"
18
+ :rounded="buttonConfig.rounded"
19
+ :color="buttonConfig.color"
15
20
  >
16
21
  </v-btn>
17
22
  </template>
@@ -8,10 +8,12 @@ import {useCrudColumns} from "../../composables/UseCrudColumns";
8
8
  import {CrudSavedQueryProvider} from "@drax/crud-front";
9
9
  import {useAuth, useAuthStore} from "@drax/identity-vue";
10
10
  import {createCrudFilterValue} from "../../helpers/CrudRangeFilters";
11
+ import {useCrudButtonConfig} from "../../config/CrudButtonConfig";
11
12
 
12
13
  const {t, te} = useI18n();
13
14
  const {hasPermission} = useAuth();
14
15
  const authStore = useAuthStore();
16
+ const buttonConfig = useCrudButtonConfig("savedQueries");
15
17
 
16
18
  const props = defineProps({
17
19
  entity: {type: Object as PropType<IEntityCrud>, required: true},
@@ -216,6 +218,8 @@ function onMenuUpdate(value: boolean) {
216
218
  <template>
217
219
  <v-menu
218
220
  v-if="canViewSavedQueries"
221
+ id="crud-saved-queries-menu"
222
+ class="crud-saved-queries-menu"
219
223
  :model-value="menu"
220
224
  offset-y
221
225
  :close-on-content-click="false"
@@ -224,21 +228,27 @@ function onMenuUpdate(value: boolean) {
224
228
  <template #activator="{ props: activatorProps }">
225
229
  <v-btn
226
230
  v-bind="activatorProps"
231
+ id="crud-saved-queries-button"
232
+ class="crud-saved-queries-button mr-1"
227
233
  icon
228
- variant="text"
234
+ :variant="buttonConfig.variant"
235
+ :rounded="buttonConfig.rounded"
236
+ :color="buttonConfig.color"
229
237
  >
230
- <v-icon>mdi-content-save-cog</v-icon>
238
+ <v-icon id="crud-saved-queries-button-icon" class="crud-saved-queries-button__icon">{{ buttonConfig.icon }}</v-icon>
231
239
  <v-tooltip activator="parent" location="bottom">
232
240
  {{ title }}
233
241
  </v-tooltip>
234
242
  </v-btn>
235
243
  </template>
236
244
 
237
- <v-list min-width="280">
238
- <v-list-subheader>{{ title }}</v-list-subheader>
245
+ <v-list id="crud-saved-queries-list" class="crud-saved-queries-menu__list" min-width="280">
246
+ <v-list-subheader id="crud-saved-queries-title" class="crud-saved-queries-menu__title">{{ title }}</v-list-subheader>
239
247
 
240
248
  <v-list-item
241
249
  v-if="canCreateSavedQueries"
250
+ id="crud-saved-queries-save-item"
251
+ class="crud-saved-queries-menu__save-item"
242
252
  @click="openSaveDialog"
243
253
  >
244
254
  <template #prepend>
@@ -249,17 +259,19 @@ function onMenuUpdate(value: boolean) {
249
259
 
250
260
  <v-divider />
251
261
 
252
- <v-list-item v-if="loading">
253
- <v-progress-linear indeterminate />
262
+ <v-list-item v-if="loading" id="crud-saved-queries-loading-item" class="crud-saved-queries-menu__loading-item">
263
+ <v-progress-linear id="crud-saved-queries-loading" class="crud-saved-queries-menu__loading" indeterminate />
254
264
  </v-list-item>
255
265
 
256
- <v-list-item v-else-if="savedQueries.length === 0">
257
- <v-list-item-title class="text-medium-emphasis">{{ noQueriesText }}</v-list-item-title>
266
+ <v-list-item v-else-if="savedQueries.length === 0" id="crud-saved-queries-empty-item" class="crud-saved-queries-menu__empty-item">
267
+ <v-list-item-title class="crud-saved-queries-menu__empty-title text-medium-emphasis">{{ noQueriesText }}</v-list-item-title>
258
268
  </v-list-item>
259
269
 
260
270
  <v-list-item
261
271
  v-for="query in savedQueries"
262
272
  :key="query._id"
273
+ :id="`crud-saved-query-${query._id}`"
274
+ class="crud-saved-queries-menu__query-item"
263
275
  @click="applyQuery(query)"
264
276
  >
265
277
  <template #prepend>
@@ -269,6 +281,8 @@ function onMenuUpdate(value: boolean) {
269
281
  <template #append>
270
282
  <v-btn
271
283
  v-if="canDeleteQuery(query)"
284
+ :id="`crud-saved-query-delete-${query._id}`"
285
+ class="crud-saved-queries-menu__delete-button"
272
286
  icon
273
287
  variant="text"
274
288
  color="red"
@@ -285,11 +299,13 @@ function onMenuUpdate(value: boolean) {
285
299
  </v-list>
286
300
  </v-menu>
287
301
 
288
- <v-dialog v-model="saveDialog" max-width="460">
289
- <v-card>
290
- <v-card-title>{{ saveTitle }}</v-card-title>
291
- <v-card-text>
302
+ <v-dialog id="crud-saved-query-save-dialog" class="crud-saved-query-save-dialog" v-model="saveDialog" max-width="460">
303
+ <v-card id="crud-saved-query-save-card" class="crud-saved-query-save-dialog__card">
304
+ <v-card-title id="crud-saved-query-save-title" class="crud-saved-query-save-dialog__title">{{ saveTitle }}</v-card-title>
305
+ <v-card-text id="crud-saved-query-save-content" class="crud-saved-query-save-dialog__content">
292
306
  <v-text-field
307
+ id="crud-saved-query-name-field"
308
+ class="crud-saved-query-save-dialog__name-field"
293
309
  v-model="form.name"
294
310
  :label="te('crud.savedQueries.name') ? t('crud.savedQueries.name') : 'Name'"
295
311
  density="compact"
@@ -297,18 +313,22 @@ function onMenuUpdate(value: boolean) {
297
313
  autofocus
298
314
  />
299
315
  <v-switch
316
+ id="crud-saved-query-shared-switch"
317
+ class="crud-saved-query-save-dialog__shared-switch"
300
318
  v-model="form.shared"
301
319
  :label="te('crud.savedQueries.shared') ? t('crud.savedQueries.shared') : 'Shared'"
302
320
  color="primary"
303
321
  hide-details
304
322
  />
305
323
  </v-card-text>
306
- <v-card-actions>
324
+ <v-card-actions id="crud-saved-query-save-actions" class="crud-saved-query-save-dialog__actions">
307
325
  <v-spacer />
308
- <v-btn variant="text" @click="saveDialog = false">
326
+ <v-btn id="crud-saved-query-save-cancel-button" class="crud-saved-query-save-dialog__cancel-button" variant="text" @click="saveDialog = false">
309
327
  {{ te('action.cancel') ? t('action.cancel') : 'Cancel' }}
310
328
  </v-btn>
311
329
  <v-btn
330
+ id="crud-saved-query-save-submit-button"
331
+ class="crud-saved-query-save-dialog__submit-button"
312
332
  color="primary"
313
333
  variant="flat"
314
334
  :loading="saving"
@@ -321,18 +341,20 @@ function onMenuUpdate(value: boolean) {
321
341
  </v-card>
322
342
  </v-dialog>
323
343
 
324
- <v-dialog v-model="deleteDialog" max-width="460">
325
- <v-card>
326
- <v-card-title>{{ deleteTitle }}</v-card-title>
327
- <v-card-text>
344
+ <v-dialog id="crud-saved-query-delete-dialog" class="crud-saved-query-delete-dialog" v-model="deleteDialog" max-width="460">
345
+ <v-card id="crud-saved-query-delete-card" class="crud-saved-query-delete-dialog__card">
346
+ <v-card-title id="crud-saved-query-delete-title" class="crud-saved-query-delete-dialog__title">{{ deleteTitle }}</v-card-title>
347
+ <v-card-text id="crud-saved-query-delete-content" class="crud-saved-query-delete-dialog__content">
328
348
  {{ deleteConfirmText }}
329
349
  </v-card-text>
330
- <v-card-actions>
350
+ <v-card-actions id="crud-saved-query-delete-actions" class="crud-saved-query-delete-dialog__actions">
331
351
  <v-spacer />
332
- <v-btn variant="text" @click="deleteDialog = false">
352
+ <v-btn id="crud-saved-query-delete-cancel-button" class="crud-saved-query-delete-dialog__cancel-button" variant="text" @click="deleteDialog = false">
333
353
  {{ te('action.cancel') ? t('action.cancel') : 'Cancel' }}
334
354
  </v-btn>
335
355
  <v-btn
356
+ id="crud-saved-query-delete-confirm-button"
357
+ class="crud-saved-query-delete-dialog__confirm-button"
336
358
  color="red"
337
359
  variant="flat"
338
360
  :loading="deleting"
@@ -1,17 +1,21 @@
1
1
  <script setup lang="ts">
2
2
  import {useI18n} from "vue-i18n";
3
+ import {useCrudButtonConfig} from "../../config/CrudButtonConfig";
3
4
  const {t} = useI18n()
5
+ const buttonConfig = useCrudButtonConfig("update")
4
6
  </script>
5
7
 
6
8
  <template>
7
- <v-tooltip location="top">
9
+ <v-tooltip :id="`${$attrs.id || 'crud-update-button'}-tooltip`" class="crud-update-button__tooltip" location="top">
8
10
  <template v-slot:activator="{ props}">
9
11
  <v-btn
10
12
  v-bind="{ ...$attrs, ...props }"
11
- icon="mdi-pencil"
12
- class="mr-1"
13
- variant="text"
14
- color="blue"
13
+ :icon="buttonConfig.icon"
14
+ :id="$attrs.id || 'crud-update-button'"
15
+ class="crud-update-button mr-1"
16
+ :variant="buttonConfig.variant"
17
+ :rounded="buttonConfig.rounded"
18
+ :color="buttonConfig.color"
15
19
  slim
16
20
  >
17
21
  </v-btn>
@@ -1,17 +1,21 @@
1
1
  <script setup lang="ts">
2
2
  import {useI18n} from "vue-i18n";
3
+ import {useCrudButtonConfig} from "../../config/CrudButtonConfig";
3
4
  const {t} = useI18n()
5
+ const buttonConfig = useCrudButtonConfig("view")
4
6
  </script>
5
7
 
6
8
  <template>
7
- <v-tooltip location="top">
9
+ <v-tooltip :id="`${$attrs.id || 'crud-view-button'}-tooltip`" class="crud-view-button__tooltip" location="top">
8
10
  <template v-slot:activator="{ props}">
9
11
  <v-btn
10
12
  v-bind="{ ...$attrs, ...props }"
11
- icon="mdi-magnify"
12
- class="mr-1"
13
- variant="text"
14
- color="teal"
13
+ :icon="buttonConfig.icon"
14
+ :id="$attrs.id || 'crud-view-button'"
15
+ class="crud-view-button mr-1"
16
+ :variant="buttonConfig.variant"
17
+ :rounded="buttonConfig.rounded"
18
+ :color="buttonConfig.color"
15
19
  slim
16
20
  >
17
21
  </v-btn>
@@ -17,6 +17,8 @@ const getEntityLabel = (entity: IEntityCrud) => {
17
17
  <template>
18
18
 
19
19
  <v-select
20
+ id="entity-combobox"
21
+ class="entity-combobox"
20
22
  :items="entityStore.entities"
21
23
  item-value="name"
22
24
  v-model="valueModel"
@@ -28,6 +30,8 @@ const getEntityLabel = (entity: IEntityCrud) => {
28
30
  <template v-slot:item="{ props: itemProps, item }">
29
31
  <v-list-item
30
32
  v-bind="itemProps"
33
+ :id="`entity-combobox-item-${(item.raw as IEntityCrud).name}`"
34
+ class="entity-combobox__item"
31
35
  density="compact"
32
36
  :title="getEntityLabel(item.raw as IEntityCrud)"
33
37
 
@@ -0,0 +1,104 @@
1
+ import {computed, reactive} from "vue";
2
+
3
+ export type CrudButtonName =
4
+ "ai"
5
+ | "columns"
6
+ | "create"
7
+ | "createOnTheFly"
8
+ | "delete"
9
+ | "dialogNext"
10
+ | "dialogPrev"
11
+ | "export"
12
+ | "filter"
13
+ | "groupBy"
14
+ | "import"
15
+ | "openRouteForm"
16
+ | "refresh"
17
+ | "savedQueries"
18
+ | "update"
19
+ | "view";
20
+
21
+ export type CrudButtonRounded = boolean | string | number;
22
+ export type CrudButtonVariant = "flat" | "text" | "elevated" | "outlined" | "plain" | "tonal";
23
+
24
+ export interface CrudButtonStyle {
25
+ icon?: string;
26
+ activeIcon?: string;
27
+ variant?: CrudButtonVariant;
28
+ rounded?: CrudButtonRounded;
29
+ color?: string;
30
+ }
31
+
32
+ export type CrudButtonGlobalStyle = Pick<CrudButtonStyle, "variant" | "rounded" | "color">;
33
+
34
+ export type CrudButtonsConfig = {
35
+ defaults?: CrudButtonGlobalStyle;
36
+ buttons?: Partial<Record<CrudButtonName, CrudButtonStyle>>;
37
+ };
38
+
39
+ const crudButtonDefaultStyles: Record<CrudButtonName, CrudButtonStyle> = {
40
+ ai: {icon: "mdi-robot-outline", variant: "text"},
41
+ columns: {icon: "mdi-view-column", variant: "text"},
42
+ create: {icon: "mdi-plus", variant: "text"},
43
+ createOnTheFly: {icon: "mdi-plus", variant: "text"},
44
+ delete: {icon: "mdi-delete", variant: "text", color: "red"},
45
+ dialogNext: {icon: "mdi-chevron-right", variant: "text"},
46
+ dialogPrev: {icon: "mdi-chevron-left", variant: "text"},
47
+ export: {icon: "mdi-database-export-outline", variant: "text"},
48
+ filter: {icon: "mdi-filter", activeIcon: "mdi-filter-off", variant: "text"},
49
+ groupBy: {icon: "mdi-chart-bar", variant: "text"},
50
+ import: {icon: "mdi-database-import-outline", variant: "text"},
51
+ openRouteForm: {icon: "mdi-open-in-new", variant: "text"},
52
+ refresh: {icon: "mdi-refresh", variant: "text"},
53
+ savedQueries: {icon: "mdi-content-save-cog", variant: "text"},
54
+ update: {icon: "mdi-pencil", variant: "text", color: "blue"},
55
+ view: {icon: "mdi-magnify", variant: "text", color: "teal"},
56
+ };
57
+
58
+ const crudButtonsConfig = reactive<Required<CrudButtonsConfig>>({
59
+ defaults: {},
60
+ buttons: {},
61
+ });
62
+
63
+ export function configureCrudButtons(config: CrudButtonsConfig) {
64
+ if (config.defaults) {
65
+ Object.assign(crudButtonsConfig.defaults, config.defaults);
66
+ }
67
+
68
+ if (config.buttons) {
69
+ Object.entries(config.buttons).forEach(([buttonName, buttonConfig]) => {
70
+ if (!buttonConfig) {
71
+ return;
72
+ }
73
+
74
+ const key = buttonName as CrudButtonName;
75
+ crudButtonsConfig.buttons[key] = {
76
+ ...(crudButtonsConfig.buttons[key] || {}),
77
+ ...buttonConfig,
78
+ };
79
+ });
80
+ }
81
+ }
82
+
83
+ export function resetCrudButtonsConfig() {
84
+ Object.keys(crudButtonsConfig.defaults).forEach((key) => {
85
+ delete crudButtonsConfig.defaults[key as keyof CrudButtonGlobalStyle];
86
+ });
87
+ Object.keys(crudButtonsConfig.buttons).forEach((key) => {
88
+ delete crudButtonsConfig.buttons[key as CrudButtonName];
89
+ });
90
+ }
91
+
92
+ export function getCrudButtonConfig(buttonName: CrudButtonName): CrudButtonStyle {
93
+ return {
94
+ ...crudButtonDefaultStyles[buttonName],
95
+ ...crudButtonsConfig.defaults,
96
+ ...(crudButtonsConfig.buttons[buttonName] || {}),
97
+ };
98
+ }
99
+
100
+ export function useCrudButtonConfig(buttonName: CrudButtonName) {
101
+ return computed(() => getCrudButtonConfig(buttonName));
102
+ }
103
+
104
+ export {crudButtonDefaultStyles, crudButtonsConfig};
@@ -287,24 +287,24 @@ class EntityCrud implements IEntityCrud {
287
287
  return false
288
288
  }
289
289
 
290
- get cardDensity(): 'default' | 'comfortable' | 'compact' {
291
- return 'default'
290
+ get cardDensity(): 'default' | 'comfortable' | 'compact' | undefined {
291
+ return undefined
292
292
  }
293
293
 
294
294
  get cardClass(): string {
295
- return 'rounded-xl'
295
+ return ''
296
296
  }
297
297
 
298
- get toolbarDensity(): 'default' | 'comfortable' | 'compact' {
299
- return 'default'
298
+ get toolbarDensity(): 'default' | 'comfortable' | 'compact' | undefined {
299
+ return undefined
300
300
  }
301
301
 
302
302
  get toolbarClass(): string {
303
303
  return 'bg-primary'
304
304
  }
305
305
 
306
- get tableDensity(): 'default' | 'comfortable' | 'compact' {
307
- return 'default'
306
+ get tableDensity(): 'default' | 'comfortable' | 'compact' | undefined {
307
+ return undefined
308
308
  }
309
309
 
310
310
  get headerProps() {