@drax/crud-vue 2.8.0 → 3.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/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "
|
|
6
|
+
"version": "3.0.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": "^
|
|
28
|
-
"@drax/crud-front": "^
|
|
29
|
-
"@drax/crud-share": "^
|
|
30
|
-
"@drax/media-vue": "^
|
|
27
|
+
"@drax/common-front": "^3.0.0",
|
|
28
|
+
"@drax/crud-front": "^3.0.0",
|
|
29
|
+
"@drax/crud-share": "^3.0.0",
|
|
30
|
+
"@drax/media-vue": "^3.0.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": "63ae718b24ea25ae80b1a9a5dfb84a3abbb95199"
|
|
54
54
|
}
|
|
@@ -7,8 +7,9 @@ import {useAuth} from "@drax/identity-vue";
|
|
|
7
7
|
import {useFilterIcon} from "../composables/UseFilterIcon";
|
|
8
8
|
import {useCrudStore} from "../stores/UseCrudStore";
|
|
9
9
|
import {useEntityStore} from "../stores/UseEntityStore";
|
|
10
|
+
import {useDynamicFilters} from "../composables/UseDynamicFilters";
|
|
10
11
|
|
|
11
|
-
const {t
|
|
12
|
+
const {t} = useI18n()
|
|
12
13
|
const valueModel = defineModel({type: [Object]})
|
|
13
14
|
const {hasPermission} = useAuth()
|
|
14
15
|
const {filterIcon} = useFilterIcon()
|
|
@@ -28,12 +29,26 @@ const aFields = computed(() => {
|
|
|
28
29
|
.filter((field: IEntityCrudFilter) => !field.permission || hasPermission(field.permission))
|
|
29
30
|
})
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
|
|
33
|
+
const filtersRef = computed({
|
|
34
|
+
get: () => store.dynamicFilters,
|
|
35
|
+
set: v => store.dynamicFilters = v
|
|
35
36
|
})
|
|
36
37
|
|
|
38
|
+
const {
|
|
39
|
+
dynamicFilter,
|
|
40
|
+
selectableFields,
|
|
41
|
+
getOperations,
|
|
42
|
+
isValueRequired,
|
|
43
|
+
onUpdateField,
|
|
44
|
+
addFilter,
|
|
45
|
+
removeFilter
|
|
46
|
+
} = useDynamicFilters(
|
|
47
|
+
computed(() => entity.name),
|
|
48
|
+
computed(() => storeEntity?.fields || []),
|
|
49
|
+
filtersRef
|
|
50
|
+
)
|
|
51
|
+
|
|
37
52
|
function filter() {
|
|
38
53
|
emit('applyFilter')
|
|
39
54
|
}
|
|
@@ -50,83 +65,32 @@ function onUpdateValue() {
|
|
|
50
65
|
}
|
|
51
66
|
}
|
|
52
67
|
|
|
53
|
-
|
|
54
|
-
return
|
|
55
|
-
return te(entity.name.toLowerCase() + ".field." + field.name) ? t(entity.name.toLowerCase() + ".field." + field.name) : field.label
|
|
56
|
-
}
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
const selectableFields = computed(() => {
|
|
60
|
-
return storeEntity ? storeEntity.fields
|
|
61
|
-
.filter((f: any) => !['fullFile', 'object', 'array.object'].includes(f.type))
|
|
62
|
-
.map((f: any) => ({title: fieldI18n.value(f), value: f.name})) : []
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
function normalizeFieldType(type: string) :string{
|
|
66
|
-
if (type === 'array.ref') return 'ref';
|
|
67
|
-
if (type === 'array.string') return 'string';
|
|
68
|
-
if (type === 'longString') return 'string';
|
|
69
|
-
if (type === 'array.number') return 'number';
|
|
70
|
-
if (type === 'array.enum') return 'enum';
|
|
71
|
-
return type;
|
|
68
|
+
function numericIndex(index: string | number) {
|
|
69
|
+
return typeof index === 'number' ? index : Number(index)
|
|
72
70
|
}
|
|
73
71
|
|
|
74
|
-
function
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
dynamicFilter.value(index).value = null
|
|
78
|
-
|
|
79
|
-
if (!field) return
|
|
80
|
-
|
|
81
|
-
if(field.ref){
|
|
82
|
-
dynamicFilter.value(index).ref = field.ref
|
|
83
|
-
}
|
|
84
|
-
if(field.refDisplay){
|
|
85
|
-
dynamicFilter.value(index).refDisplay = field.refDisplay
|
|
86
|
-
}
|
|
87
|
-
if(field.enum){
|
|
88
|
-
dynamicFilter.value(index).enum = field.enum
|
|
89
|
-
}
|
|
90
|
-
if(field.type){
|
|
91
|
-
dynamicFilter.value(index).type = normalizeFieldType(field.type)
|
|
72
|
+
function getDynamicFilter(index: string | number) {
|
|
73
|
+
return dynamicFilter.value(numericIndex(index))
|
|
74
|
+
}
|
|
92
75
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
76
|
+
function updateDynamicField(index: string | number, resetOperator = false) {
|
|
77
|
+
onUpdateField(numericIndex(index), resetOperator)
|
|
78
|
+
}
|
|
96
79
|
|
|
97
|
-
|
|
80
|
+
function getDynamicOperations(index: string | number) {
|
|
81
|
+
return getOperations.value(numericIndex(index))
|
|
98
82
|
}
|
|
99
83
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
{title: t('operation.notEquals'), value: 'ne'},
|
|
103
|
-
{title: t('operation.contains'), value: 'like'},
|
|
104
|
-
{title: t('operation.greaterThan'), value: 'gt'},
|
|
105
|
-
{title: t('operation.lessThan'), value: 'lt'},
|
|
106
|
-
{title: t('operation.greaterThanOrEqual'), value: 'gte'},
|
|
107
|
-
{title: t('operation.lessThanOrEqual'), value: 'lte'},
|
|
108
|
-
// {title: t('operation.in'), value: 'in'},
|
|
109
|
-
// {title: t('operation.notIn'), value: 'nin'},
|
|
110
|
-
]
|
|
111
|
-
|
|
112
|
-
function removeFilter(index: string | number){
|
|
113
|
-
store.removeDynamicFilter(index)
|
|
84
|
+
function dynamicValueRequired(index: string | number) {
|
|
85
|
+
return isValueRequired.value(numericIndex(index))
|
|
114
86
|
}
|
|
115
87
|
|
|
116
|
-
function
|
|
117
|
-
|
|
118
|
-
default: undefined,
|
|
119
|
-
label: "",
|
|
120
|
-
name: '',
|
|
121
|
-
operator: 'eq',
|
|
122
|
-
type: 'string',
|
|
123
|
-
permission: '',
|
|
124
|
-
value: ''
|
|
125
|
-
}
|
|
126
|
-
store.addDynamicFilter(filter)
|
|
88
|
+
function deleteFilter(index: string | number) {
|
|
89
|
+
removeFilter(numericIndex(index))
|
|
127
90
|
}
|
|
128
91
|
|
|
129
92
|
|
|
93
|
+
|
|
130
94
|
const emit = defineEmits(['applyFilter', 'clearFilter'])
|
|
131
95
|
|
|
132
96
|
</script>
|
|
@@ -141,29 +105,31 @@ const emit = defineEmits(['applyFilter', 'clearFilter'])
|
|
|
141
105
|
<v-col cols="12" sm="4">
|
|
142
106
|
<v-select
|
|
143
107
|
:items="selectableFields"
|
|
144
|
-
v-model="
|
|
108
|
+
v-model="getDynamicFilter(index)!.name"
|
|
145
109
|
:label="t('crud.field')"
|
|
146
110
|
density="compact"
|
|
147
111
|
variant="outlined"
|
|
148
112
|
hide-details
|
|
149
|
-
@update:modelValue="(
|
|
113
|
+
@update:modelValue="(_v:string) => updateDynamicField(index, true)"
|
|
150
114
|
/>
|
|
151
115
|
</v-col>
|
|
152
116
|
<v-col cols="12" sm="3">
|
|
153
117
|
<v-select
|
|
154
|
-
:items="
|
|
155
|
-
v-model="
|
|
118
|
+
:items="getDynamicOperations(index)"
|
|
119
|
+
v-model="getDynamicFilter(index)!.operator"
|
|
156
120
|
:label="t('crud.operator')"
|
|
157
121
|
density="compact"
|
|
158
122
|
variant="outlined"
|
|
159
123
|
hide-details
|
|
124
|
+
@update:modelValue="(_v:string) => updateDynamicField(index)"
|
|
160
125
|
/>
|
|
161
126
|
</v-col>
|
|
162
127
|
<v-col cols="10" sm="4">
|
|
163
128
|
<crud-form-field
|
|
129
|
+
v-if="dynamicValueRequired(index)"
|
|
164
130
|
:field="filter"
|
|
165
131
|
:entity="entity"
|
|
166
|
-
v-model="
|
|
132
|
+
v-model="getDynamicFilter(index)!.value"
|
|
167
133
|
:clearable="true"
|
|
168
134
|
density="compact"
|
|
169
135
|
variant="outlined"
|
|
@@ -173,7 +139,7 @@ const emit = defineEmits(['applyFilter', 'clearFilter'])
|
|
|
173
139
|
/>
|
|
174
140
|
</v-col>
|
|
175
141
|
<v-col cols="2" sm="1">
|
|
176
|
-
<v-btn @click="
|
|
142
|
+
<v-btn @click="deleteFilter(index)"
|
|
177
143
|
icon="mdi-delete"
|
|
178
144
|
class="mr-1"
|
|
179
145
|
variant="text"
|
|
@@ -9,9 +9,14 @@ import {useI18n} from "vue-i18n";
|
|
|
9
9
|
import {useCrudStore} from "../stores/UseCrudStore";
|
|
10
10
|
import {VDateInput} from 'vuetify/labs/VDateInput'
|
|
11
11
|
import type {IEntityCrud, IEntityCrudField, IEntityCrudFilter} from "@drax/crud-share";
|
|
12
|
-
import {MediaField, MediaFullField} from "@drax/media-vue";
|
|
13
12
|
import {useAuth} from "@drax/identity-vue";
|
|
14
13
|
|
|
14
|
+
//TODO: Ver si esto no puede traer problemas...
|
|
15
|
+
import MediaField from "@drax/media-vue/src/components/MediaField.vue";
|
|
16
|
+
import MediaFullField from "@drax/media-vue/src/components/MediaFullField.vue";
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
15
20
|
const {t, te} = useI18n()
|
|
16
21
|
|
|
17
22
|
const {hasPermission} = useAuth()
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import {computed} from "vue"
|
|
2
|
+
import type {Ref} from "vue"
|
|
3
|
+
import {useI18n} from "vue-i18n"
|
|
4
|
+
import type {
|
|
5
|
+
IEntityCrudFilter,
|
|
6
|
+
IEntityCrudFieldTypes
|
|
7
|
+
} from "@drax/crud-share"
|
|
8
|
+
|
|
9
|
+
export function useDynamicFilters(
|
|
10
|
+
entityName: Ref<string | undefined>,
|
|
11
|
+
entityFields: Ref<any[]>,
|
|
12
|
+
filters: Ref<IEntityCrudFilter[]>
|
|
13
|
+
) {
|
|
14
|
+
|
|
15
|
+
const {t, te} = useI18n()
|
|
16
|
+
|
|
17
|
+
const dynamicFilter = computed(() => {
|
|
18
|
+
return (index: number) => filters.value[index]
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
const fieldI18n = computed(() => {
|
|
22
|
+
return (field: any) => {
|
|
23
|
+
const key = entityName.value?.toLowerCase() + ".field." + field.name
|
|
24
|
+
return te(key) ? t(key) : field.label
|
|
25
|
+
}
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
const selectableFields = computed(() => {
|
|
29
|
+
return entityFields.value
|
|
30
|
+
?.filter((f: any) => !['fullFile', 'object', 'array.object'].includes(f.type))
|
|
31
|
+
.map((f: any) => ({
|
|
32
|
+
title: fieldI18n.value(f),
|
|
33
|
+
value: f.name
|
|
34
|
+
})) || []
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
function normalizeFieldType(type: string): IEntityCrudFieldTypes {
|
|
38
|
+
if (type === 'array.ref') return 'ref'
|
|
39
|
+
if (type === 'array.string') return 'string'
|
|
40
|
+
if (type === 'longString') return 'string'
|
|
41
|
+
if (type === 'array.number') return 'number'
|
|
42
|
+
if (type === 'array.enum') return 'enum'
|
|
43
|
+
return type as IEntityCrudFieldTypes
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function onUpdateField(index: number, resetOperator = false) {
|
|
47
|
+
|
|
48
|
+
const filter = filters.value[index]
|
|
49
|
+
if (!filter) return
|
|
50
|
+
|
|
51
|
+
if(resetOperator){
|
|
52
|
+
filter.operator = 'eq'
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
let filterName = filter.name
|
|
56
|
+
|
|
57
|
+
const field = entityFields.value?.find((e: any) => e.name === filterName)
|
|
58
|
+
|
|
59
|
+
filter.value = null
|
|
60
|
+
if (!field) return
|
|
61
|
+
|
|
62
|
+
if (field.ref) filter.ref = field.ref
|
|
63
|
+
if (field.refDisplay) filter.refDisplay = field.refDisplay
|
|
64
|
+
if (field.enum) filter.enum = field.enum
|
|
65
|
+
|
|
66
|
+
if (field.type) {
|
|
67
|
+
|
|
68
|
+
filter.type = normalizeFieldType(field.type)
|
|
69
|
+
|
|
70
|
+
//aplico default false si type es boolean
|
|
71
|
+
if (field.type === "boolean") {
|
|
72
|
+
filter.value = false
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
//Convierto a multiple si operadores son in o nin
|
|
78
|
+
if (filter.operator && ['in','nin'].includes(filter.operator)) {
|
|
79
|
+
|
|
80
|
+
if (['ref', 'array.ref'].includes(field.type)) {
|
|
81
|
+
filter.type = 'array.ref'
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (['string', 'longString', 'array.string'].includes(field.type)) {
|
|
85
|
+
filter.type = 'array.string'
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (['enum', 'array.enum'].includes(field.type)) {
|
|
89
|
+
filter.type = 'array.enum'
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function addFilter() {
|
|
96
|
+
const filter: IEntityCrudFilter = {
|
|
97
|
+
default: undefined,
|
|
98
|
+
label: "",
|
|
99
|
+
name: "",
|
|
100
|
+
operator: "eq",
|
|
101
|
+
type: "string",
|
|
102
|
+
permission: "",
|
|
103
|
+
value: ""
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
filters.value.push(filter)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function removeFilter(index: number) {
|
|
110
|
+
filters.value.splice(index, 1)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const operations = [
|
|
114
|
+
{title: t('operation.equals'), value: 'eq'},
|
|
115
|
+
{title: t('operation.contains'), value: 'like'},
|
|
116
|
+
{title: t('operation.empty'), value: 'empty'},
|
|
117
|
+
{title: t('operation.notEquals'), value: 'ne'},
|
|
118
|
+
{title: t('operation.greaterThan'), value: 'gt'},
|
|
119
|
+
{title: t('operation.lessThan'), value: 'lt'},
|
|
120
|
+
{title: t('operation.greaterThanOrEqual'), value: 'gte'},
|
|
121
|
+
{title: t('operation.lessThanOrEqual'), value: 'lte'},
|
|
122
|
+
{title: t('operation.in'), value: 'in'},
|
|
123
|
+
{title: t('operation.notIn'), value: 'nin'},
|
|
124
|
+
]
|
|
125
|
+
|
|
126
|
+
const getOperations = computed(() => {
|
|
127
|
+
return (index: number) => {
|
|
128
|
+
|
|
129
|
+
const filter = filters.value[index]
|
|
130
|
+
if (!filter || !filter.type) return []
|
|
131
|
+
|
|
132
|
+
return operations.filter(op => {
|
|
133
|
+
if (['ref','array.ref'].includes(filter.type) && ['gt', 'gte', 'lt', 'lte', 'like'].includes(op.value)) {
|
|
134
|
+
return false
|
|
135
|
+
}
|
|
136
|
+
return true
|
|
137
|
+
})
|
|
138
|
+
}
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
const isValueRequired = computed(() => {
|
|
142
|
+
return (index: number) => {
|
|
143
|
+
const filter = filters.value[index]
|
|
144
|
+
if (!filter || !filter.operator){
|
|
145
|
+
return false
|
|
146
|
+
}
|
|
147
|
+
if (['empty'].includes(filter.operator)) {
|
|
148
|
+
return false
|
|
149
|
+
}
|
|
150
|
+
return true
|
|
151
|
+
}
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
dynamicFilter,
|
|
157
|
+
selectableFields,
|
|
158
|
+
fieldI18n,
|
|
159
|
+
operations,
|
|
160
|
+
getOperations,
|
|
161
|
+
isValueRequired,
|
|
162
|
+
addFilter,
|
|
163
|
+
removeFilter,
|
|
164
|
+
onUpdateField,
|
|
165
|
+
normalizeFieldType
|
|
166
|
+
}
|
|
167
|
+
}
|