@drax/crud-vue 3.25.1 → 3.29.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
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "3.
|
|
6
|
+
"version": "3.29.0",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"main": "./src/index.ts",
|
|
9
9
|
"module": "./src/index.ts",
|
|
@@ -24,10 +24,10 @@
|
|
|
24
24
|
"format": "prettier --write src/"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@drax/common-front": "^3.
|
|
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.29.0",
|
|
30
|
+
"@drax/media-vue": "^3.29.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": "4f97968e53b812a348aec9f09e59bff69e71ca9e"
|
|
54
54
|
}
|
|
@@ -10,7 +10,7 @@ import {useDisplay} from "vuetify"
|
|
|
10
10
|
const {t, te} = useI18n()
|
|
11
11
|
const valueModel = defineModel({type: Array, default: () => []});
|
|
12
12
|
|
|
13
|
-
const {field, entity} = defineProps({
|
|
13
|
+
const {field, entity, readonly} = defineProps({
|
|
14
14
|
entity: {type: Object as PropType<IEntityCrud>, required: true},
|
|
15
15
|
field: {type: Object as PropType<IEntityCrudField>, required: true},
|
|
16
16
|
readonly: {type: Boolean, default: false},
|
|
@@ -45,15 +45,22 @@ function addItem() {
|
|
|
45
45
|
const item = newItem()
|
|
46
46
|
valueModel.value.push(item);
|
|
47
47
|
menuSelect(item, valueModel.value.length - 1)
|
|
48
|
+
emit('updateValue')
|
|
48
49
|
}
|
|
49
50
|
|
|
50
51
|
function removeItem(index: number) {
|
|
52
|
+
const removedItem = valueModel.value[index]
|
|
53
|
+
|
|
51
54
|
if (indexSelected.value === index) {
|
|
52
|
-
|
|
53
|
-
|
|
55
|
+
valueModel.value.splice(index, 1);
|
|
56
|
+
syncSelectedItem(undefined)
|
|
57
|
+
emit('updateValue')
|
|
58
|
+
return
|
|
54
59
|
}
|
|
55
|
-
valueModel.value.splice(index, 1);
|
|
56
60
|
|
|
61
|
+
valueModel.value.splice(index, 1);
|
|
62
|
+
syncSelectedItem(itemSelected.value === removedItem ? undefined : itemSelected.value)
|
|
63
|
+
emit('updateValue')
|
|
57
64
|
}
|
|
58
65
|
|
|
59
66
|
const label = computed(() => {
|
|
@@ -81,10 +88,87 @@ const menuMaxHeight = computed(() => {
|
|
|
81
88
|
return field.menuMaxHeight || '300px'
|
|
82
89
|
})
|
|
83
90
|
|
|
84
|
-
defineEmits(['updateValue'])
|
|
91
|
+
const emit = defineEmits(['updateValue'])
|
|
85
92
|
|
|
86
93
|
const {xs} = useDisplay()
|
|
87
94
|
|
|
95
|
+
const dragIndex = ref<number | null>(null)
|
|
96
|
+
const dragOverIndex = ref<number | null>(null)
|
|
97
|
+
|
|
98
|
+
const isSortable = computed(() => {
|
|
99
|
+
return !readonly
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
function getItemTitle(index: number) {
|
|
103
|
+
//@ts-ignore
|
|
104
|
+
return valueModel.value[index]?.[field?.arrayObjectShowField ?? Object.keys(valueModel.value[index] as any)[0]]
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function syncSelectedItem(item?: any) {
|
|
108
|
+
if (!item) {
|
|
109
|
+
itemSelected.value = undefined
|
|
110
|
+
indexSelected.value = undefined
|
|
111
|
+
return
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const nextIndex = valueModel.value.findIndex(currentItem => currentItem === item)
|
|
115
|
+
|
|
116
|
+
if (nextIndex === -1) {
|
|
117
|
+
itemSelected.value = undefined
|
|
118
|
+
indexSelected.value = undefined
|
|
119
|
+
return
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
itemSelected.value = item
|
|
123
|
+
indexSelected.value = nextIndex
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function reorderItems(fromIndex: number, toIndex: number) {
|
|
127
|
+
if (fromIndex === toIndex) {
|
|
128
|
+
return
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const movedItem = valueModel.value[fromIndex]
|
|
132
|
+
const selectedItem = itemSelected.value
|
|
133
|
+
|
|
134
|
+
valueModel.value.splice(fromIndex, 1)
|
|
135
|
+
valueModel.value.splice(toIndex, 0, movedItem)
|
|
136
|
+
|
|
137
|
+
syncSelectedItem(selectedItem ?? movedItem)
|
|
138
|
+
emit('updateValue')
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function onDragStart(index: number) {
|
|
142
|
+
if (!isSortable.value) {
|
|
143
|
+
return
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
dragIndex.value = index
|
|
147
|
+
dragOverIndex.value = index
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function onDragEnter(index: number) {
|
|
151
|
+
if (!isSortable.value || dragIndex.value === null) {
|
|
152
|
+
return
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
dragOverIndex.value = index
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function onDrop(index: number) {
|
|
159
|
+
if (!isSortable.value || dragIndex.value === null) {
|
|
160
|
+
return
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
reorderItems(dragIndex.value, index)
|
|
164
|
+
clearDragState()
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function clearDragState() {
|
|
168
|
+
dragIndex.value = null
|
|
169
|
+
dragOverIndex.value = null
|
|
170
|
+
}
|
|
171
|
+
|
|
88
172
|
</script>
|
|
89
173
|
|
|
90
174
|
<template>
|
|
@@ -95,14 +179,19 @@ const {xs} = useDisplay()
|
|
|
95
179
|
<!--ACCORDION-->
|
|
96
180
|
<v-card-text v-if="field.arrayObjectUI === 'accordion' || xs">
|
|
97
181
|
<v-expansion-panels>
|
|
98
|
-
<v-expansion-panel v-for="(item,index) in valueModel" :key="index"
|
|
182
|
+
<v-expansion-panel v-for="(item,index) in valueModel" :key="index"
|
|
183
|
+
:class="{'crud-form-list--drag-over': dragOverIndex === index}"
|
|
184
|
+
:draggable="isSortable"
|
|
185
|
+
@dragstart="onDragStart(index)"
|
|
186
|
+
@dragenter.prevent="onDragEnter(index)"
|
|
187
|
+
@dragover.prevent
|
|
188
|
+
@drop.prevent="onDrop(index)"
|
|
189
|
+
@dragend="clearDragState">
|
|
99
190
|
|
|
100
191
|
<v-expansion-panel-title>
|
|
192
|
+
<v-icon v-if="isSortable" class="mr-2" size="small">mdi-drag</v-icon>
|
|
101
193
|
<v-chip class="mr-2" :color="hasError(index) ? 'red':'teal'">{{ index }}</v-chip>
|
|
102
|
-
{{
|
|
103
|
-
//@ts-ignore
|
|
104
|
-
valueModel[index][field?.arrayObjectShowField ?? Object.keys(valueModel[index] as any)[0]]
|
|
105
|
-
}}
|
|
194
|
+
{{ getItemTitle(index) }}
|
|
106
195
|
|
|
107
196
|
<template v-slot:actions="{expanded}">
|
|
108
197
|
<v-icon>{{ expanded ? "mdi-menu-down" : "mdi-menu-up" }}</v-icon>
|
|
@@ -169,12 +258,16 @@ const {xs} = useDisplay()
|
|
|
169
258
|
|
|
170
259
|
<v-chip v-for="(item,index) in valueModel" :key="index"
|
|
171
260
|
:value="index" @click="menuSelect(item, index)"
|
|
261
|
+
:draggable="isSortable"
|
|
262
|
+
:class="{'crud-form-list--drag-over': dragOverIndex === index}"
|
|
263
|
+
@dragstart="onDragStart(index)"
|
|
264
|
+
@dragenter.prevent="onDragEnter(index)"
|
|
265
|
+
@dragover.prevent
|
|
266
|
+
@drop.prevent="onDrop(index)"
|
|
267
|
+
@dragend="clearDragState"
|
|
172
268
|
label class="pr-0" :color="indexSelected === index ? 'primary' : ''"
|
|
173
269
|
>
|
|
174
|
-
{{
|
|
175
|
-
//@ts-ignore
|
|
176
|
-
valueModel[index][field?.arrayObjectShowField ?? Object.keys(valueModel[index] as any)[0]] || (index)
|
|
177
|
-
}}
|
|
270
|
+
{{ getItemTitle(index) || (index) }}
|
|
178
271
|
|
|
179
272
|
<template v-slot:append>
|
|
180
273
|
<v-btn variant="text" class="ml-2" density="compact"
|
|
@@ -227,9 +320,17 @@ const {xs} = useDisplay()
|
|
|
227
320
|
<v-card-text>
|
|
228
321
|
<v-list v-model="itemSelected" :style="{ maxHeight: menuMaxHeight, overflowY: 'auto' }">
|
|
229
322
|
<v-list-item v-for="(item,index) in valueModel" :key="index" rounded="shaped"
|
|
323
|
+
:class="{'crud-form-list--drag-over': dragOverIndex === index}"
|
|
230
324
|
:value="item" @click="menuSelect(item, index)"
|
|
325
|
+
:draggable="isSortable"
|
|
326
|
+
@dragstart="onDragStart(index)"
|
|
327
|
+
@dragenter.prevent="onDragEnter(index)"
|
|
328
|
+
@dragover.prevent
|
|
329
|
+
@drop.prevent="onDrop(index)"
|
|
330
|
+
@dragend="clearDragState"
|
|
231
331
|
>
|
|
232
332
|
<template v-slot:append>
|
|
333
|
+
<v-icon v-if="isSortable" size="small" class="mr-2">mdi-drag</v-icon>
|
|
233
334
|
<v-btn size="x-small" variant="text" color="red" icon="mdi-delete"
|
|
234
335
|
@click="removeItem(index)"
|
|
235
336
|
|
|
@@ -237,10 +338,7 @@ const {xs} = useDisplay()
|
|
|
237
338
|
</template>
|
|
238
339
|
<v-list-item-title>
|
|
239
340
|
<v-chip class="mr-2" :color="hasError(index) ? 'red':'teal'">{{ index }}</v-chip>
|
|
240
|
-
{{
|
|
241
|
-
//@ts-ignore
|
|
242
|
-
valueModel[index][field?.arrayObjectShowField ?? Object.keys(valueModel[index] as any)[0]]
|
|
243
|
-
}}
|
|
341
|
+
{{ getItemTitle(index) }}
|
|
244
342
|
</v-list-item-title>
|
|
245
343
|
</v-list-item>
|
|
246
344
|
|
|
@@ -287,5 +385,8 @@ const {xs} = useDisplay()
|
|
|
287
385
|
</template>
|
|
288
386
|
|
|
289
387
|
<style scoped>
|
|
290
|
-
|
|
388
|
+
.crud-form-list--drag-over {
|
|
389
|
+
outline: 2px dashed rgb(var(--v-theme-primary));
|
|
390
|
+
outline-offset: 2px;
|
|
391
|
+
}
|
|
291
392
|
</style>
|
|
@@ -22,6 +22,7 @@ import CrudFiltersDynamic from "./CrudFiltersDynamic.vue";
|
|
|
22
22
|
import CrudFiltersAction from "./CrudFiltersAction.vue";
|
|
23
23
|
import CrudFilterButton from "./buttons/CrudFilterButton.vue";
|
|
24
24
|
import CrudSavedQueriesButton from "./buttons/CrudSavedQueriesButton.vue";
|
|
25
|
+
import CrudRefreshButton from "./buttons/CrudRefreshButton.vue";
|
|
25
26
|
|
|
26
27
|
const {t, te} = useI18n()
|
|
27
28
|
const {hasPermission} = useAuth()
|
|
@@ -98,6 +99,11 @@ onMounted(() => {
|
|
|
98
99
|
<slot name="toolbar">
|
|
99
100
|
</slot>
|
|
100
101
|
|
|
102
|
+
<crud-refresh-button
|
|
103
|
+
v-if="entity.isRefreshable !== false"
|
|
104
|
+
@click="doPaginate"
|
|
105
|
+
/>
|
|
106
|
+
|
|
101
107
|
<crud-create-button
|
|
102
108
|
v-if="entity.isCreatable"
|
|
103
109
|
:entity="entity"
|
|
@@ -22,6 +22,7 @@ import CrudFiltersAction from "./CrudFiltersAction.vue";
|
|
|
22
22
|
import CrudFilterButton from "./buttons/CrudFilterButton.vue";
|
|
23
23
|
import CrudSavedQueriesButton from "./buttons/CrudSavedQueriesButton.vue";
|
|
24
24
|
import CrudRowValue from "./CrudRowValue.vue";
|
|
25
|
+
import CrudRefreshButton from "./buttons/CrudRefreshButton.vue";
|
|
25
26
|
|
|
26
27
|
const {t, te} = useI18n()
|
|
27
28
|
const {hasPermission} = useAuth()
|
|
@@ -131,6 +132,11 @@ defineEmits(['import', 'export', 'create', 'update', 'delete', 'view', 'edit'])
|
|
|
131
132
|
|
|
132
133
|
</slot>
|
|
133
134
|
|
|
135
|
+
<crud-refresh-button
|
|
136
|
+
v-if="entity.isRefreshable !== false"
|
|
137
|
+
@click="doPaginate"
|
|
138
|
+
/>
|
|
139
|
+
|
|
134
140
|
<crud-create-button
|
|
135
141
|
v-if="entity.isCreatable"
|
|
136
142
|
:entity="entity"
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import {useI18n} from "vue-i18n";
|
|
3
|
+
|
|
4
|
+
const {t} = useI18n()
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<template>
|
|
8
|
+
<v-tooltip location="top">
|
|
9
|
+
<template v-slot:activator="{ props }">
|
|
10
|
+
<v-btn
|
|
11
|
+
v-bind="{ ...$attrs, ...props }"
|
|
12
|
+
icon="mdi-refresh"
|
|
13
|
+
class="mr-1"
|
|
14
|
+
variant="text"
|
|
15
|
+
>
|
|
16
|
+
</v-btn>
|
|
17
|
+
</template>
|
|
18
|
+
{{ t('action.refresh')}}
|
|
19
|
+
</v-tooltip>
|
|
20
|
+
</template>
|
|
21
|
+
|
|
22
|
+
<style scoped>
|
|
23
|
+
|
|
24
|
+
</style>
|
package/src/cruds/EntityCrud.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -14,6 +14,7 @@ import CrudNotify from "./components/CrudNotify.vue";
|
|
|
14
14
|
import CrudSearch from "./components/CrudSearch.vue";
|
|
15
15
|
import CrudAutocomplete from "./components/CrudAutocomplete.vue";
|
|
16
16
|
import CrudSavedQueriesButton from "./components/buttons/CrudSavedQueriesButton.vue";
|
|
17
|
+
import CrudRefreshButton from "./components/buttons/CrudRefreshButton.vue";
|
|
17
18
|
import EntityCombobox from "./components/combobox/EntityCombobox.vue";
|
|
18
19
|
import {useCrudStore} from "./stores/UseCrudStore";
|
|
19
20
|
import {useEntityStore} from "./stores/UseEntityStore";
|
|
@@ -39,6 +40,7 @@ export {
|
|
|
39
40
|
CrudSearch,
|
|
40
41
|
CrudAutocomplete,
|
|
41
42
|
CrudSavedQueriesButton,
|
|
43
|
+
CrudRefreshButton,
|
|
42
44
|
CrudFilters,
|
|
43
45
|
CrudFiltersAction,
|
|
44
46
|
useCrud,
|