@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.
- package/package.json +4 -4
- package/src/components/Crud.vue +27 -12
- package/src/components/CrudActiveFilters.vue +11 -9
- package/src/components/CrudAi.vue +38 -25
- package/src/components/CrudAutocomplete.vue +14 -2
- package/src/components/CrudDialog.vue +6 -6
- package/src/components/CrudExportList.vue +13 -12
- package/src/components/CrudFieldRange.vue +8 -4
- package/src/components/CrudFilters.vue +8 -2
- package/src/components/CrudFiltersAction.vue +3 -3
- package/src/components/CrudFiltersDynamic.vue +18 -10
- package/src/components/CrudForm.vue +44 -31
- package/src/components/CrudFormField.vue +48 -8
- package/src/components/CrudFormList.vue +44 -32
- package/src/components/CrudFormRecord.vue +19 -11
- package/src/components/CrudImportList.vue +17 -16
- package/src/components/CrudList.vue +41 -12
- package/src/components/CrudListGallery.vue +65 -27
- package/src/components/CrudListTable.vue +49 -10
- package/src/components/CrudNotify.vue +3 -1
- package/src/components/CrudRefDisplay.vue +2 -2
- package/src/components/CrudRouteForm.vue +8 -4
- package/src/components/CrudRowValue.vue +9 -8
- package/src/components/CrudSearch.vue +2 -1
- package/src/components/buttons/CrudAiButton.vue +9 -4
- package/src/components/buttons/CrudColumnsButton.vue +22 -8
- package/src/components/buttons/CrudCreateButton.vue +9 -4
- package/src/components/buttons/CrudCreateOnTheFlyButton.vue +13 -4
- package/src/components/buttons/CrudDeleteButton.vue +9 -5
- package/src/components/buttons/CrudDialogNextButton.vue +19 -0
- package/src/components/buttons/CrudDialogPrevButton.vue +19 -0
- package/src/components/buttons/CrudExportButton.vue +13 -8
- package/src/components/buttons/CrudFilterButton.vue +10 -5
- package/src/components/buttons/CrudGroupByButton.vue +33 -16
- package/src/components/buttons/CrudImportButton.vue +16 -10
- package/src/components/buttons/CrudOpenRouteFormButton.vue +19 -0
- package/src/components/buttons/CrudRefreshButton.vue +9 -4
- package/src/components/buttons/CrudSavedQueriesButton.vue +42 -20
- package/src/components/buttons/CrudUpdateButton.vue +9 -5
- package/src/components/buttons/CrudViewButton.vue +9 -5
- package/src/components/combobox/EntityCombobox.vue +4 -0
- package/src/config/CrudButtonConfig.ts +104 -0
- package/src/cruds/EntityCrud.ts +7 -7
- package/src/index.ts +33 -1
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "3.
|
|
6
|
+
"version": "3.48.0",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"main": "./src/index.ts",
|
|
9
9
|
"module": "./src/index.ts",
|
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@drax/common-front": "^3.29.0",
|
|
28
28
|
"@drax/crud-front": "^3.21.0",
|
|
29
|
-
"@drax/crud-share": "^3.
|
|
30
|
-
"@drax/media-vue": "^3.
|
|
29
|
+
"@drax/crud-share": "^3.48.0",
|
|
30
|
+
"@drax/media-vue": "^3.48.0"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
33
|
"pinia": "^3.0.4",
|
|
@@ -50,5 +50,5 @@
|
|
|
50
50
|
"vue-tsc": "^3.2.4",
|
|
51
51
|
"vuetify": "^3.11.8"
|
|
52
52
|
},
|
|
53
|
-
"gitHead": "
|
|
53
|
+
"gitHead": "455427fd48fc742af2e301ab85af2d48e5b2da16"
|
|
54
54
|
}
|
package/src/components/Crud.vue
CHANGED
|
@@ -9,6 +9,9 @@ import CrudRouteForm from "./CrudRouteForm.vue";
|
|
|
9
9
|
import CrudNotify from "./CrudNotify.vue";
|
|
10
10
|
import CrudDialog from "./CrudDialog.vue";
|
|
11
11
|
import CrudAiButton from "./buttons/CrudAiButton.vue";
|
|
12
|
+
import CrudDialogNextButton from "./buttons/CrudDialogNextButton.vue";
|
|
13
|
+
import CrudDialogPrevButton from "./buttons/CrudDialogPrevButton.vue";
|
|
14
|
+
import CrudOpenRouteFormButton from "./buttons/CrudOpenRouteFormButton.vue";
|
|
12
15
|
import CrudAi from "./CrudAi.vue";
|
|
13
16
|
import {useCrud} from "../composables/UseCrud";
|
|
14
17
|
import {useDisplay} from 'vuetify'
|
|
@@ -137,6 +140,8 @@ watch(dialog, (value) => {
|
|
|
137
140
|
<template>
|
|
138
141
|
<crud-route-form
|
|
139
142
|
v-if="isRouteCrudForm"
|
|
143
|
+
:id="`crud-route-form-${entity.name}`"
|
|
144
|
+
class="crud__route-form"
|
|
140
145
|
:entity="entity"
|
|
141
146
|
@created="item => emit('created', item)"
|
|
142
147
|
@updated="item => emit('updated', item)"
|
|
@@ -150,11 +155,13 @@ watch(dialog, (value) => {
|
|
|
150
155
|
</template>
|
|
151
156
|
</crud-route-form>
|
|
152
157
|
|
|
153
|
-
<v-container v-else :fluid="entity.containerFluid" class="mt-5">
|
|
154
|
-
<v-card :class="entity.cardClass" :density="entity.cardDensity">
|
|
158
|
+
<v-container v-else :id="`crud-container-${entity.name}`" :fluid="entity.containerFluid" class="crud mt-5">
|
|
159
|
+
<v-card :id="`crud-card-${entity.name}`" :class="['crud__card', entity.cardClass]" :density="entity.cardDensity">
|
|
155
160
|
|
|
156
161
|
<component
|
|
157
162
|
:is="listComponent"
|
|
163
|
+
:id="`crud-list-component-${entity.name}`"
|
|
164
|
+
class="crud__list"
|
|
158
165
|
:entity="entity"
|
|
159
166
|
@create="onCreate"
|
|
160
167
|
@edit="onEditAt"
|
|
@@ -229,36 +236,40 @@ watch(dialog, (value) => {
|
|
|
229
236
|
</v-card>
|
|
230
237
|
|
|
231
238
|
<crud-dialog
|
|
239
|
+
:id="`crud-dialog-${entity.name}`"
|
|
240
|
+
class="crud__dialog"
|
|
232
241
|
v-model="dialog"
|
|
233
242
|
:entity="entity"
|
|
234
243
|
:operation="operation"
|
|
235
244
|
>
|
|
236
245
|
<template #toolbar-actions>
|
|
237
|
-
<
|
|
246
|
+
<crud-open-route-form-button
|
|
238
247
|
v-if="canOpenRouteCrudForm"
|
|
239
|
-
|
|
240
|
-
|
|
248
|
+
id="crud-open-route-form-button"
|
|
249
|
+
class="crud__open-route-form-button"
|
|
241
250
|
@click="openRouteCrudForm"
|
|
242
251
|
/>
|
|
243
252
|
|
|
244
|
-
<
|
|
253
|
+
<crud-dialog-prev-button
|
|
245
254
|
v-if="canNavigateItems"
|
|
246
|
-
|
|
247
|
-
|
|
255
|
+
id="crud-dialog-prev-button"
|
|
256
|
+
class="crud__dialog-prev-button"
|
|
248
257
|
:disabled="!canNavigatePrev"
|
|
249
258
|
@click="navigateView(-1)"
|
|
250
259
|
/>
|
|
251
260
|
|
|
252
|
-
<
|
|
261
|
+
<crud-dialog-next-button
|
|
253
262
|
v-if="canNavigateItems"
|
|
254
|
-
|
|
255
|
-
|
|
263
|
+
id="crud-dialog-next-button"
|
|
264
|
+
class="crud__dialog-next-button"
|
|
256
265
|
:disabled="!canNavigateNext"
|
|
257
266
|
@click="navigateView(1)"
|
|
258
267
|
/>
|
|
259
268
|
|
|
260
269
|
<crud-ai-button
|
|
261
270
|
v-if="entity.isAiAssistable && ['create', 'edit'].includes(operation) && hasPermission('ai:promptCrud')"
|
|
271
|
+
id="crud-ai-toggle-button"
|
|
272
|
+
class="crud__ai-toggle-button"
|
|
262
273
|
:entity="entity"
|
|
263
274
|
v-model="aiExpanded"
|
|
264
275
|
/>
|
|
@@ -267,6 +278,8 @@ watch(dialog, (value) => {
|
|
|
267
278
|
<slot name="tools">
|
|
268
279
|
<crud-ai
|
|
269
280
|
v-if="entity.isAiAssistable && ['create', 'edit'].includes(operation) && hasPermission('ai:promptCrud')"
|
|
281
|
+
id="crud-ai"
|
|
282
|
+
class="crud__ai"
|
|
270
283
|
:entity="entity"
|
|
271
284
|
v-model="aiExpanded"
|
|
272
285
|
@apply="applyAiSuggestions"
|
|
@@ -277,6 +290,8 @@ watch(dialog, (value) => {
|
|
|
277
290
|
<slot name="form" v-bind="{form, operation}">
|
|
278
291
|
|
|
279
292
|
<crud-form
|
|
293
|
+
id="crud-form-dialog"
|
|
294
|
+
class="crud__form"
|
|
280
295
|
:entity="entity"
|
|
281
296
|
@created="item => emit('created', item)"
|
|
282
297
|
@updated="item => emit('updated', item)"
|
|
@@ -295,7 +310,7 @@ watch(dialog, (value) => {
|
|
|
295
310
|
|
|
296
311
|
</crud-dialog>
|
|
297
312
|
|
|
298
|
-
<crud-notify v-model="notify" :message="message"></crud-notify>
|
|
313
|
+
<crud-notify id="crud-notify" class="crud__notify" v-model="notify" :message="message"></crud-notify>
|
|
299
314
|
</v-container>
|
|
300
315
|
</template>
|
|
301
316
|
|
|
@@ -122,16 +122,18 @@ const emit = defineEmits(['filterRemoved', 'filtersCleared'])
|
|
|
122
122
|
</script>
|
|
123
123
|
|
|
124
124
|
<template>
|
|
125
|
-
<v-card v-if="activeFilters.length > 0" flat class="mb-2">
|
|
126
|
-
<v-card-text class="py-2">
|
|
127
|
-
<div class="d-flex align-center flex-wrap ga-2">
|
|
128
|
-
<span class="text-caption text-medium-emphasis">
|
|
129
|
-
<v-icon size="x-small">mdi-filter</v-icon> {{ t('crud.activeFilters') }}:
|
|
125
|
+
<v-card v-if="activeFilters.length > 0" id="crud-active-filters" flat class="crud-active-filters mb-2">
|
|
126
|
+
<v-card-text id="crud-active-filters-content" class="crud-active-filters__content py-2">
|
|
127
|
+
<div id="crud-active-filters-list" class="crud-active-filters__list d-flex align-center flex-wrap ga-2">
|
|
128
|
+
<span id="crud-active-filters-label" class="crud-active-filters__label text-caption text-medium-emphasis">
|
|
129
|
+
<v-icon id="crud-active-filters-icon" class="crud-active-filters__icon" size="x-small">mdi-filter</v-icon> {{ t('crud.activeFilters') }}:
|
|
130
130
|
</span>
|
|
131
131
|
|
|
132
132
|
<v-chip
|
|
133
133
|
v-for="filter in activeFilters"
|
|
134
134
|
:key="filter.index"
|
|
135
|
+
:id="`crud-active-filter-${filter.index}`"
|
|
136
|
+
class="crud-active-filters__chip"
|
|
135
137
|
closable
|
|
136
138
|
size="small"
|
|
137
139
|
color="primary"
|
|
@@ -139,15 +141,15 @@ const emit = defineEmits(['filterRemoved', 'filtersCleared'])
|
|
|
139
141
|
@click:close="removeFilter(filter.index)"
|
|
140
142
|
>
|
|
141
143
|
|
|
142
|
-
<span class="font-weight-medium">{{ getFilterLabel(filter) }}</span>
|
|
143
|
-
<v-icon :icon="filterIcon(filter)" size="x-small" class="mx-1" />
|
|
144
|
-
<span v-if="['ref','array.ref'].includes(filter.type)">
|
|
144
|
+
<span class="crud-active-filters__chip-label font-weight-medium">{{ getFilterLabel(filter) }}</span>
|
|
145
|
+
<v-icon :icon="filterIcon(filter)" size="x-small" class="crud-active-filters__chip-icon mx-1" />
|
|
146
|
+
<span v-if="['ref','array.ref'].includes(filter.type)" class="crud-active-filters__chip-ref-value">
|
|
145
147
|
<crud-ref-display
|
|
146
148
|
:ref-display="filter.refDisplay"
|
|
147
149
|
:value="filter.value"
|
|
148
150
|
:entity="entity.getRef(filter.ref)" />
|
|
149
151
|
</span>
|
|
150
|
-
<span v-else>{{ getFilterValue(filter) }}</span>
|
|
152
|
+
<span v-else class="crud-active-filters__chip-value">{{ getFilterValue(filter) }}</span>
|
|
151
153
|
|
|
152
154
|
<v-tooltip
|
|
153
155
|
v-if="filter.endOfDay"
|
|
@@ -300,32 +300,36 @@ watch(prompt, () => {
|
|
|
300
300
|
|
|
301
301
|
<template>
|
|
302
302
|
<v-expand-transition>
|
|
303
|
-
<div v-if="expanded" class="mb-4">
|
|
304
|
-
<v-card variant="tonal" class="crud-ai-panel">
|
|
305
|
-
<v-card-text>
|
|
306
|
-
<div class="d-flex align-center mb-4">
|
|
307
|
-
<div class="text-subtitle-1">{{ subtitle }}</div>
|
|
303
|
+
<div v-if="expanded" id="crud-ai-panel-wrapper" class="crud-ai-panel-wrapper mb-4">
|
|
304
|
+
<v-card id="crud-ai-panel" variant="tonal" class="crud-ai-panel">
|
|
305
|
+
<v-card-text id="crud-ai-content" class="crud-ai-panel__content">
|
|
306
|
+
<div id="crud-ai-header" class="crud-ai-panel__header d-flex align-center mb-4">
|
|
307
|
+
<div id="crud-ai-subtitle" class="crud-ai-panel__subtitle text-subtitle-1">{{ subtitle }}</div>
|
|
308
308
|
<v-spacer />
|
|
309
|
-
<v-btn icon="mdi-close" variant="text" @click="expanded = false" />
|
|
309
|
+
<v-btn id="crud-ai-close-button" class="crud-ai-panel__close-button" icon="mdi-close" variant="text" @click="expanded = false" />
|
|
310
310
|
</div>
|
|
311
311
|
|
|
312
312
|
<v-alert
|
|
313
313
|
v-if="error"
|
|
314
|
+
id="crud-ai-error"
|
|
314
315
|
type="error"
|
|
315
316
|
variant="tonal"
|
|
316
|
-
class="mb-4"
|
|
317
|
+
class="crud-ai-panel__error mb-4"
|
|
317
318
|
:text="error"
|
|
318
319
|
/>
|
|
319
320
|
|
|
320
321
|
<v-alert
|
|
321
322
|
v-if="editableFields.length === 0"
|
|
323
|
+
id="crud-ai-empty-fields-warning"
|
|
322
324
|
type="warning"
|
|
323
325
|
variant="tonal"
|
|
324
|
-
class="mb-4"
|
|
326
|
+
class="crud-ai-panel__empty-fields-warning mb-4"
|
|
325
327
|
:text="te('ai.noEditableFields') ? t('ai.noEditableFields') : 'No hay campos editables disponibles para asistir con IA.'"
|
|
326
328
|
/>
|
|
327
329
|
|
|
328
330
|
<v-textarea
|
|
331
|
+
id="crud-ai-prompt"
|
|
332
|
+
class="crud-ai-panel__prompt"
|
|
329
333
|
v-model="prompt"
|
|
330
334
|
rows="3"
|
|
331
335
|
auto-grow
|
|
@@ -334,8 +338,10 @@ watch(prompt, () => {
|
|
|
334
338
|
:placeholder="te('ai.promptPlaceholder') ? t('ai.promptPlaceholder') : 'Ejemplo: completá este formulario para un producto premium orientado a pequeñas empresas.'"
|
|
335
339
|
/>
|
|
336
340
|
|
|
337
|
-
<div class="d-flex justify-end mt-2">
|
|
341
|
+
<div id="crud-ai-prompt-actions" class="crud-ai-panel__prompt-actions d-flex justify-end mt-2">
|
|
338
342
|
<v-btn
|
|
343
|
+
id="crud-ai-generate-button"
|
|
344
|
+
class="crud-ai-panel__generate-button"
|
|
339
345
|
color="primary"
|
|
340
346
|
variant="flat"
|
|
341
347
|
:loading="loading"
|
|
@@ -346,54 +352,59 @@ watch(prompt, () => {
|
|
|
346
352
|
</v-btn>
|
|
347
353
|
</div>
|
|
348
354
|
|
|
349
|
-
<v-card v-if="response" variant="outlined" class="mt-6">
|
|
350
|
-
<v-card-title>
|
|
355
|
+
<v-card v-if="response" id="crud-ai-preview" variant="outlined" class="crud-ai-panel__preview mt-6">
|
|
356
|
+
<v-card-title id="crud-ai-preview-title" class="crud-ai-panel__preview-title">
|
|
351
357
|
{{ te('ai.preview') ? t('ai.preview') : 'Vista previa' }}
|
|
352
358
|
</v-card-title>
|
|
353
359
|
|
|
354
|
-
<v-card-text>
|
|
360
|
+
<v-card-text id="crud-ai-preview-content" class="crud-ai-panel__preview-content">
|
|
355
361
|
<v-alert
|
|
356
362
|
v-if="response.message"
|
|
363
|
+
id="crud-ai-response-message"
|
|
357
364
|
variant="tonal"
|
|
358
365
|
type="info"
|
|
359
|
-
class="mb-4"
|
|
366
|
+
class="crud-ai-panel__response-message mb-4"
|
|
360
367
|
:text="response.message"
|
|
361
368
|
/>
|
|
362
369
|
|
|
363
370
|
<v-alert
|
|
364
371
|
v-if="changedEntries.length === 0"
|
|
372
|
+
id="crud-ai-no-changes"
|
|
365
373
|
variant="tonal"
|
|
366
374
|
type="info"
|
|
375
|
+
class="crud-ai-panel__no-changes"
|
|
367
376
|
:text="te('ai.noChanges') ? t('ai.noChanges') : 'La IA no propuso cambios aplicables para este formulario.'"
|
|
368
377
|
/>
|
|
369
378
|
|
|
370
|
-
<v-list v-else lines="three">
|
|
379
|
+
<v-list v-else id="crud-ai-changes-list" class="crud-ai-panel__changes-list" lines="three">
|
|
371
380
|
<v-list-item
|
|
372
381
|
v-for="entry in changedEntries"
|
|
373
382
|
:key="entry.field.name"
|
|
374
|
-
|
|
383
|
+
:id="`crud-ai-change-${entry.field.name}`"
|
|
384
|
+
class="crud-ai-panel__change px-0"
|
|
375
385
|
>
|
|
376
|
-
<v-list-item-title>
|
|
386
|
+
<v-list-item-title class="crud-ai-panel__change-title">
|
|
377
387
|
{{ entry.field.label || entry.field.name }}
|
|
378
388
|
</v-list-item-title>
|
|
379
|
-
<div class="mt-1 preview-block">
|
|
389
|
+
<div class="crud-ai-panel__change-preview mt-1 preview-block">
|
|
380
390
|
<template v-if="showCurrentValues">
|
|
381
|
-
<div class="text-caption text-medium-emphasis">Actual</div>
|
|
382
|
-
<pre class="value-preview">{{ formatValue(entry.currentValue) }}</pre>
|
|
391
|
+
<div class="crud-ai-panel__current-label text-caption text-medium-emphasis">Actual</div>
|
|
392
|
+
<pre class="crud-ai-panel__current-value value-preview">{{ formatValue(entry.currentValue) }}</pre>
|
|
383
393
|
</template>
|
|
384
|
-
<div class="text-caption text-medium-emphasis mt-2">Sugerido</div>
|
|
385
|
-
<pre class="value-preview">{{ formatValue(entry.suggestedValue) }}</pre>
|
|
394
|
+
<div class="crud-ai-panel__suggested-label text-caption text-medium-emphasis mt-2">Sugerido</div>
|
|
395
|
+
<pre class="crud-ai-panel__suggested-value value-preview">{{ formatValue(entry.suggestedValue) }}</pre>
|
|
386
396
|
</div>
|
|
387
397
|
</v-list-item>
|
|
388
398
|
</v-list>
|
|
389
399
|
|
|
390
|
-
<div v-if="(response.warnings || []).length > 0" class="mt-4">
|
|
400
|
+
<div v-if="(response.warnings || []).length > 0" id="crud-ai-warnings" class="crud-ai-panel__warnings mt-4">
|
|
391
401
|
<v-alert
|
|
392
402
|
v-for="warning in response.warnings || []"
|
|
393
403
|
:key="warning"
|
|
404
|
+
:id="`crud-ai-warning-${warning.replace(/[^a-zA-Z0-9_-]/g, '-')}`"
|
|
394
405
|
variant="tonal"
|
|
395
406
|
type="warning"
|
|
396
|
-
class="mb-3"
|
|
407
|
+
class="crud-ai-panel__warning mb-3"
|
|
397
408
|
:text="warning"
|
|
398
409
|
/>
|
|
399
410
|
</div>
|
|
@@ -401,12 +412,14 @@ watch(prompt, () => {
|
|
|
401
412
|
</v-card>
|
|
402
413
|
</v-card-text>
|
|
403
414
|
|
|
404
|
-
<v-card-actions v-if="response">
|
|
415
|
+
<v-card-actions v-if="response" id="crud-ai-actions" class="crud-ai-panel__actions">
|
|
405
416
|
<v-spacer />
|
|
406
|
-
<v-btn variant="text" @click="expanded = false">
|
|
417
|
+
<v-btn id="crud-ai-cancel-button" class="crud-ai-panel__cancel-button" variant="text" @click="expanded = false">
|
|
407
418
|
{{ t('action.cancel') }}
|
|
408
419
|
</v-btn>
|
|
409
420
|
<v-btn
|
|
421
|
+
id="crud-ai-apply-button"
|
|
422
|
+
class="crud-ai-panel__apply-button"
|
|
410
423
|
color="primary"
|
|
411
424
|
variant="flat"
|
|
412
425
|
:disabled="changedEntries.length === 0"
|
|
@@ -109,6 +109,8 @@ defineEmits(['updateValue'])
|
|
|
109
109
|
|
|
110
110
|
<v-select
|
|
111
111
|
v-if="noFilter"
|
|
112
|
+
:id="`crud-autocomplete-select-${field.name}`"
|
|
113
|
+
class="crud-autocomplete crud-autocomplete--select"
|
|
112
114
|
v-model="valueModel"
|
|
113
115
|
:label="label ? label : field.label"
|
|
114
116
|
:placeholder="label ? label : field.label"
|
|
@@ -143,12 +145,14 @@ defineEmits(['updateValue'])
|
|
|
143
145
|
>
|
|
144
146
|
|
|
145
147
|
<template v-if="addOnTheFly" v-slot:append>
|
|
146
|
-
<crud-create-on-the-fly-button :entity="entity" @created="onCreated"></crud-create-on-the-fly-button>
|
|
148
|
+
<crud-create-on-the-fly-button :id="`crud-autocomplete-create-${field.name}`" class="crud-autocomplete__create-button" :entity="entity" @created="onCreated"></crud-create-on-the-fly-button>
|
|
147
149
|
</template>
|
|
148
150
|
|
|
149
151
|
<template v-slot:item="{ props: itemProps, item }">
|
|
150
152
|
<v-list-item
|
|
151
153
|
v-bind="itemProps"
|
|
154
|
+
:id="`crud-autocomplete-select-item-${field.name}-${item.raw[itemValue]}`"
|
|
155
|
+
class="crud-autocomplete__item"
|
|
152
156
|
density="compact"
|
|
153
157
|
:title="item.raw[itemTitle]"
|
|
154
158
|
:color="item.raw?.color"
|
|
@@ -159,6 +163,8 @@ defineEmits(['updateValue'])
|
|
|
159
163
|
|
|
160
164
|
<template v-slot:selection="{item}">
|
|
161
165
|
<v-chip tile density="compact"
|
|
166
|
+
:id="`crud-autocomplete-select-selection-${field.name}-${item.raw[itemValue]}`"
|
|
167
|
+
class="crud-autocomplete__selection-chip"
|
|
162
168
|
:color="item.raw?.color"
|
|
163
169
|
:prepend-icon="typeof item.raw?.icon=== 'string' ? item.raw?.icon : null"
|
|
164
170
|
>
|
|
@@ -171,6 +177,8 @@ defineEmits(['updateValue'])
|
|
|
171
177
|
|
|
172
178
|
<v-autocomplete
|
|
173
179
|
v-else
|
|
180
|
+
:id="`crud-autocomplete-input-${field.name}`"
|
|
181
|
+
class="crud-autocomplete crud-autocomplete--filterable"
|
|
174
182
|
v-model="valueModel"
|
|
175
183
|
:label="label ? label : field.label"
|
|
176
184
|
:placeholder="label ? label : field.label"
|
|
@@ -206,12 +214,14 @@ defineEmits(['updateValue'])
|
|
|
206
214
|
>
|
|
207
215
|
|
|
208
216
|
<template v-if="addOnTheFly" v-slot:append>
|
|
209
|
-
<crud-create-on-the-fly-button :entity="entity" @created="onCreated"></crud-create-on-the-fly-button>
|
|
217
|
+
<crud-create-on-the-fly-button :id="`crud-autocomplete-create-${field.name}`" class="crud-autocomplete__create-button" :entity="entity" @created="onCreated"></crud-create-on-the-fly-button>
|
|
210
218
|
</template>
|
|
211
219
|
|
|
212
220
|
<template v-slot:item="{ props: itemProps, item }">
|
|
213
221
|
<v-list-item
|
|
214
222
|
v-bind="itemProps"
|
|
223
|
+
:id="`crud-autocomplete-item-${field.name}-${item.raw[itemValue]}`"
|
|
224
|
+
class="crud-autocomplete__item"
|
|
215
225
|
density="compact"
|
|
216
226
|
:title="item.raw[itemTitle]"
|
|
217
227
|
:color="item.raw?.color"
|
|
@@ -222,6 +232,8 @@ defineEmits(['updateValue'])
|
|
|
222
232
|
|
|
223
233
|
<template v-slot:selection="{item}">
|
|
224
234
|
<v-chip tile density="compact"
|
|
235
|
+
:id="`crud-autocomplete-selection-${field.name}-${item.raw[itemValue]}`"
|
|
236
|
+
class="crud-autocomplete__selection-chip"
|
|
225
237
|
:color="item.raw?.color"
|
|
226
238
|
:prepend-icon="typeof item.raw?.icon=== 'string' ? item.raw?.icon : null"
|
|
227
239
|
>
|
|
@@ -32,19 +32,19 @@ const title = computed(() => {
|
|
|
32
32
|
</script>
|
|
33
33
|
|
|
34
34
|
<template>
|
|
35
|
-
<v-dialog v-model="dialog"
|
|
35
|
+
<v-dialog id="crud-dialog" class="crud-dialog" v-model="dialog"
|
|
36
36
|
:z-index="entity.dialogZindex"
|
|
37
37
|
:fullscreen="fullscreen === undefined ? entity.dialogFullscreen : fullscreen"
|
|
38
38
|
:max-width="maxWidth === undefined ? entity.dialogMaxWidth : maxWidth"
|
|
39
39
|
>
|
|
40
|
-
<v-card>
|
|
41
|
-
<v-toolbar>
|
|
42
|
-
<v-toolbar-title>{{title}}</v-toolbar-title>
|
|
40
|
+
<v-card id="crud-dialog-card" class="crud-dialog__card">
|
|
41
|
+
<v-toolbar id="crud-dialog-toolbar" class="crud-dialog__toolbar">
|
|
42
|
+
<v-toolbar-title id="crud-dialog-title" class="crud-dialog__title">{{title}}</v-toolbar-title>
|
|
43
43
|
<v-spacer></v-spacer>
|
|
44
44
|
<slot name="toolbar-actions"></slot>
|
|
45
|
-
<v-btn icon @click="dialog = false"><v-icon>mdi-close</v-icon></v-btn>
|
|
45
|
+
<v-btn id="crud-dialog-close-button" class="crud-dialog__close-button" icon @click="dialog = false"><v-icon>mdi-close</v-icon></v-btn>
|
|
46
46
|
</v-toolbar>
|
|
47
|
-
<v-card-text>
|
|
47
|
+
<v-card-text id="crud-dialog-content" class="crud-dialog__content">
|
|
48
48
|
<slot></slot>
|
|
49
49
|
</v-card-text>
|
|
50
50
|
</v-card>
|
|
@@ -17,20 +17,21 @@ const {
|
|
|
17
17
|
<template>
|
|
18
18
|
<v-card
|
|
19
19
|
v-if="exportListVisible"
|
|
20
|
+
id="crud-export-list"
|
|
20
21
|
:loading="exportLoading"
|
|
21
|
-
class="ma-3" density="compact" variant="outlined" color="secondary"
|
|
22
|
+
class="crud-export-list ma-3" density="compact" variant="outlined" color="secondary"
|
|
22
23
|
>
|
|
23
|
-
<v-card-title>
|
|
24
|
+
<v-card-title id="crud-export-list-title" class="crud-export-list__title">
|
|
24
25
|
{{ t('action.exports') }}
|
|
25
26
|
|
|
26
27
|
</v-card-title>
|
|
27
|
-
<v-card-text>
|
|
28
|
-
<v-alert v-if="exportError" type="error">
|
|
28
|
+
<v-card-text id="crud-export-list-content" class="crud-export-list__content">
|
|
29
|
+
<v-alert v-if="exportError" id="crud-export-list-error" class="crud-export-list__error" type="error">
|
|
29
30
|
{{ t('error.crud.export') }}
|
|
30
31
|
</v-alert>
|
|
31
32
|
<template v-else>
|
|
32
33
|
<slot name="export-table" :exportFiles="exportFiles">
|
|
33
|
-
<v-table density="compact">
|
|
34
|
+
<v-table id="crud-export-list-table" class="crud-export-list__table" density="compact">
|
|
34
35
|
<thead>
|
|
35
36
|
<tr>
|
|
36
37
|
<th>Link</th>
|
|
@@ -39,10 +40,10 @@ const {
|
|
|
39
40
|
</tr>
|
|
40
41
|
</thead>
|
|
41
42
|
<tbody>
|
|
42
|
-
<tr v-for="exportFile in exportFiles">
|
|
43
|
-
<td><a :href="exportFile.url" target="_blank">{{ exportFile.url }}</a></td>
|
|
44
|
-
<td>{{ exportFile.rowCount }}</td>
|
|
45
|
-
<td>{{ exportFile.time }}</td>
|
|
43
|
+
<tr v-for="(exportFile, index) in exportFiles" :id="`crud-export-list-row-${index}`" class="crud-export-list__row">
|
|
44
|
+
<td class="crud-export-list__url-cell"><a :id="`crud-export-list-link-${index}`" class="crud-export-list__link" :href="exportFile.url" target="_blank">{{ exportFile.url }}</a></td>
|
|
45
|
+
<td class="crud-export-list__row-count-cell">{{ exportFile.rowCount }}</td>
|
|
46
|
+
<td class="crud-export-list__time-cell">{{ exportFile.time }}</td>
|
|
46
47
|
</tr>
|
|
47
48
|
</tbody>
|
|
48
49
|
</v-table>
|
|
@@ -50,10 +51,10 @@ const {
|
|
|
50
51
|
</template>
|
|
51
52
|
</v-card-text>
|
|
52
53
|
|
|
53
|
-
<v-card-actions>
|
|
54
|
+
<v-card-actions id="crud-export-list-actions" class="crud-export-list__actions">
|
|
54
55
|
<v-spacer></v-spacer>
|
|
55
|
-
<v-btn @click="exportFiles = []" :loading="exportLoading">{{ t('action.clear') }}</v-btn>
|
|
56
|
-
<v-btn @click="exportListVisible=false">{{ t('action.close') }}</v-btn>
|
|
56
|
+
<v-btn id="crud-export-list-clear-button" class="crud-export-list__clear-button" @click="exportFiles = []" :loading="exportLoading">{{ t('action.clear') }}</v-btn>
|
|
57
|
+
<v-btn id="crud-export-list-close-button" class="crud-export-list__close-button" @click="exportListVisible=false">{{ t('action.close') }}</v-btn>
|
|
57
58
|
</v-card-actions>
|
|
58
59
|
</v-card>
|
|
59
60
|
</template>
|
|
@@ -149,9 +149,11 @@ const toInnerIcon = computed(() => {
|
|
|
149
149
|
</script>
|
|
150
150
|
|
|
151
151
|
<template>
|
|
152
|
-
<v-row dense>
|
|
153
|
-
<v-col cols="12" sm="6">
|
|
152
|
+
<v-row :id="`crud-field-range-${name}`" class="crud-field-range" dense>
|
|
153
|
+
<v-col :id="`crud-field-range-from-column-${name}`" class="crud-field-range__from-column" cols="12" sm="6">
|
|
154
154
|
<v-date-input
|
|
155
|
+
:id="`crud-field-range-from-${name}`"
|
|
156
|
+
class="crud-field-range__from-input"
|
|
155
157
|
:name="`${name}_from`"
|
|
156
158
|
:label="`${label} ${t('crud.from')}`"
|
|
157
159
|
:hint="hint ?? field.hint"
|
|
@@ -177,8 +179,10 @@ const toInnerIcon = computed(() => {
|
|
|
177
179
|
/>
|
|
178
180
|
</v-col>
|
|
179
181
|
|
|
180
|
-
<v-col cols="12" sm="6">
|
|
182
|
+
<v-col :id="`crud-field-range-to-column-${name}`" class="crud-field-range__to-column" cols="12" sm="6">
|
|
181
183
|
<v-date-input
|
|
184
|
+
:id="`crud-field-range-to-${name}`"
|
|
185
|
+
class="crud-field-range__to-input"
|
|
182
186
|
:name="`${name}_to`"
|
|
183
187
|
:label="`${label} ${t('crud.to')}`"
|
|
184
188
|
:hint="hint ?? field.hint"
|
|
@@ -204,7 +208,7 @@ const toInnerIcon = computed(() => {
|
|
|
204
208
|
@input="onInput"
|
|
205
209
|
>
|
|
206
210
|
<template v-if="field.endOfDay && field.showEndOfDayChip !== false" v-slot:append-inner>
|
|
207
|
-
<v-chip size="small">23:59</v-chip>
|
|
211
|
+
<v-chip :id="`crud-field-range-end-of-day-${name}`" class="crud-field-range__end-of-day-chip" size="small">23:59</v-chip>
|
|
208
212
|
</template>
|
|
209
213
|
</v-date-input>
|
|
210
214
|
</v-col>
|
|
@@ -44,10 +44,12 @@ const emit = defineEmits(['applyFilter', 'clearFilter'])
|
|
|
44
44
|
</script>
|
|
45
45
|
|
|
46
46
|
<template>
|
|
47
|
-
<v-card flat >
|
|
48
|
-
<v-row
|
|
47
|
+
<v-card id="crud-filters" class="crud-filters" flat >
|
|
48
|
+
<v-row id="crud-filters-row" class="crud-filters__row mt-1" dense>
|
|
49
49
|
<v-col v-for="(filter,index) in aFields"
|
|
50
50
|
:key="filter.name"
|
|
51
|
+
:id="`crud-filter-column-${filter.name}`"
|
|
52
|
+
class="crud-filters__column"
|
|
51
53
|
:cols="filter.cols ? filter.cols : 12"
|
|
52
54
|
:sm="filter.sm ? filter.sm : 6"
|
|
53
55
|
:md="filter.md ? filter.md : 6"
|
|
@@ -58,6 +60,8 @@ const emit = defineEmits(['applyFilter', 'clearFilter'])
|
|
|
58
60
|
<slot :name="`filter.${filter.name}`" v-bind="{filter, filterIndex: index}">
|
|
59
61
|
<crud-field-range
|
|
60
62
|
v-if="filter && valueModel[index] !== undefined && isRangeFilter(filter)"
|
|
63
|
+
:id="`crud-filter-range-${filter.name}`"
|
|
64
|
+
class="crud-filters__range-field"
|
|
61
65
|
:name="filter.name"
|
|
62
66
|
:label="filter.label"
|
|
63
67
|
:entity="entity"
|
|
@@ -71,6 +75,8 @@ const emit = defineEmits(['applyFilter', 'clearFilter'])
|
|
|
71
75
|
/>
|
|
72
76
|
<crud-form-field
|
|
73
77
|
v-else-if="filter && valueModel[index] !== undefined"
|
|
78
|
+
:id="`crud-filter-field-${filter.name}`"
|
|
79
|
+
class="crud-filters__field"
|
|
74
80
|
:field="filter"
|
|
75
81
|
:entity="entity"
|
|
76
82
|
v-model="valueModel[index].value"
|
|
@@ -22,10 +22,10 @@ const emit = defineEmits(['applyFilter', 'clearFilter'])
|
|
|
22
22
|
|
|
23
23
|
<template>
|
|
24
24
|
|
|
25
|
-
<v-card-actions
|
|
25
|
+
<v-card-actions id="crud-filters-actions" class="crud-filters-actions pb-0">
|
|
26
26
|
<v-spacer />
|
|
27
|
-
<v-btn
|
|
28
|
-
<v-btn variant="flat" density="compact" :class="entity.applyFilterClass" @click="filter">
|
|
27
|
+
<v-btn id="crud-filters-clear-button" variant="text" density="compact" :class="['crud-filters-actions__clear-button', entity.cleanFilterClass]" @click="clear">{{ t('action.clear') }}</v-btn>
|
|
28
|
+
<v-btn id="crud-filters-apply-button" variant="flat" density="compact" :class="['crud-filters-actions__apply-button', entity.applyFilterClass]" @click="filter">
|
|
29
29
|
{{ t('action.filter') }}
|
|
30
30
|
</v-btn>
|
|
31
31
|
</v-card-actions>
|
|
@@ -96,14 +96,17 @@ const emit = defineEmits(['applyFilter', 'clearFilter'])
|
|
|
96
96
|
</script>
|
|
97
97
|
|
|
98
98
|
<template>
|
|
99
|
-
<v-row
|
|
99
|
+
<v-row id="crud-dynamic-filters" class="crud-dynamic-filters mt-4" dense>
|
|
100
100
|
<v-col v-for="(filter,index) in aFields"
|
|
101
101
|
:key="filter.name"
|
|
102
|
-
|
|
102
|
+
:id="`crud-dynamic-filter-${index}`"
|
|
103
|
+
cols="12" class="crud-dynamic-filters__item tdash"
|
|
103
104
|
>
|
|
104
|
-
<v-row >
|
|
105
|
-
<v-col cols="12" sm="4">
|
|
105
|
+
<v-row :id="`crud-dynamic-filter-row-${index}`" class="crud-dynamic-filters__item-row">
|
|
106
|
+
<v-col :id="`crud-dynamic-filter-field-column-${index}`" class="crud-dynamic-filters__field-column" cols="12" sm="4">
|
|
106
107
|
<v-select
|
|
108
|
+
:id="`crud-dynamic-filter-field-select-${index}`"
|
|
109
|
+
class="crud-dynamic-filters__field-select"
|
|
107
110
|
:items="selectableFields"
|
|
108
111
|
v-model="getDynamicFilter(index)!.name"
|
|
109
112
|
:label="t('crud.field')"
|
|
@@ -113,8 +116,10 @@ const emit = defineEmits(['applyFilter', 'clearFilter'])
|
|
|
113
116
|
@update:modelValue="(_v:string) => updateDynamicField(index, true)"
|
|
114
117
|
/>
|
|
115
118
|
</v-col>
|
|
116
|
-
<v-col cols="12" sm="3">
|
|
119
|
+
<v-col :id="`crud-dynamic-filter-operator-column-${index}`" class="crud-dynamic-filters__operator-column" cols="12" sm="3">
|
|
117
120
|
<v-select
|
|
121
|
+
:id="`crud-dynamic-filter-operator-select-${index}`"
|
|
122
|
+
class="crud-dynamic-filters__operator-select"
|
|
118
123
|
:items="getDynamicOperations(index)"
|
|
119
124
|
v-model="getDynamicFilter(index)!.operator"
|
|
120
125
|
:label="t('crud.operator')"
|
|
@@ -124,9 +129,11 @@ const emit = defineEmits(['applyFilter', 'clearFilter'])
|
|
|
124
129
|
@update:modelValue="(_v:string) => updateDynamicField(index)"
|
|
125
130
|
/>
|
|
126
131
|
</v-col>
|
|
127
|
-
<v-col cols="10" sm="4">
|
|
132
|
+
<v-col :id="`crud-dynamic-filter-value-column-${index}`" class="crud-dynamic-filters__value-column" cols="10" sm="4">
|
|
128
133
|
<crud-form-field
|
|
129
134
|
v-if="dynamicValueRequired(index)"
|
|
135
|
+
:id="`crud-dynamic-filter-value-field-${index}`"
|
|
136
|
+
class="crud-dynamic-filters__value-field"
|
|
130
137
|
:field="filter"
|
|
131
138
|
:entity="entity"
|
|
132
139
|
v-model="getDynamicFilter(index)!.value"
|
|
@@ -138,10 +145,11 @@ const emit = defineEmits(['applyFilter', 'clearFilter'])
|
|
|
138
145
|
@updateValue="onUpdateValue"
|
|
139
146
|
/>
|
|
140
147
|
</v-col>
|
|
141
|
-
<v-col cols="2" sm="1">
|
|
148
|
+
<v-col :id="`crud-dynamic-filter-delete-column-${index}`" class="crud-dynamic-filters__delete-column" cols="2" sm="1">
|
|
142
149
|
<v-btn @click="deleteFilter(index)"
|
|
150
|
+
:id="`crud-dynamic-filter-delete-button-${index}`"
|
|
143
151
|
icon="mdi-delete"
|
|
144
|
-
class="mr-1"
|
|
152
|
+
class="crud-dynamic-filters__delete-button mr-1"
|
|
145
153
|
variant="text"
|
|
146
154
|
color="red"
|
|
147
155
|
>
|
|
@@ -152,8 +160,8 @@ const emit = defineEmits(['applyFilter', 'clearFilter'])
|
|
|
152
160
|
|
|
153
161
|
</v-col>
|
|
154
162
|
|
|
155
|
-
<v-col cols="12">
|
|
156
|
-
<v-btn size="small" variant="outlined" color="primary" @click="addFilter">+ {{ t('action.addFilter') }}</v-btn>
|
|
163
|
+
<v-col id="crud-dynamic-filters-add-column" class="crud-dynamic-filters__add-column" cols="12">
|
|
164
|
+
<v-btn id="crud-dynamic-filters-add-button" class="crud-dynamic-filters__add-button" size="small" variant="outlined" color="primary" @click="addFilter">+ {{ t('action.addFilter') }}</v-btn>
|
|
157
165
|
</v-col>
|
|
158
166
|
|
|
159
167
|
</v-row>
|