@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": "2.8.0",
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": "^2.8.0",
28
- "@drax/crud-front": "^2.0.0",
29
- "@drax/crud-share": "^2.8.0",
30
- "@drax/media-vue": "^2.2.1"
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": "3adeb31ee60eb83c92137dc28162f9226cab06c1"
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, te} = useI18n()
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
- const dynamicFilter = computed(() => {
32
- return (index: string | number) => {
33
- return store.dynamicFilters[index]
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
- const fieldI18n = computed(() => {
54
- return (field: IEntityCrudFilter) => {
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 onUpdateField(index: string | number, val: string){
75
-
76
- const field = storeEntity.fields.find((e: any) => e.name === val)
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
- if(field.type === 'boolean'){
94
- dynamicFilter.value(index).value = false
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
- const operations = [
101
- {title: t('operation.equals'), value: 'eq'},
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 addFilter() {
117
- const filter: IEntityCrudFilter = {
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="dynamicFilter(index).name"
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="(v:string) => onUpdateField(index, v)"
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="operations"
155
- v-model="dynamicFilter(index).operator"
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="dynamicFilter(index).value"
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="removeFilter(index)"
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
+ }