@drax/crud-vue 0.5.3 → 0.5.4
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/EntityCrud.ts +12 -0
- package/src/components/Crud.vue +2 -1
- package/src/components/CrudAutocomplete.vue +43 -38
- package/src/components/CrudDialog.vue +2 -3
- package/src/components/CrudFilters.vue +1 -0
- package/src/components/CrudForm.vue +40 -13
- package/src/components/CrudFormField.vue +47 -10
- package/src/components/CrudFormList.vue +0 -1
- package/src/components/CrudList.vue +10 -2
- package/src/components/buttons/CrudViewButton.vue +25 -0
- package/src/composables/UseCrud.ts +33 -16
- package/src/composables/UseFormUtils.ts +42 -0
- package/src/index.ts +2 -0
- package/src/stores/UseCrudStore.ts +3 -3
- package/src/interfaces/TOperation.ts +0 -6
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.5.
|
|
6
|
+
"version": "0.5.4",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"main": "./src/index.ts",
|
|
9
9
|
"module": "./src/index.ts",
|
|
@@ -24,9 +24,9 @@
|
|
|
24
24
|
"format": "prettier --write src/"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@drax/common-front": "^0.5.
|
|
27
|
+
"@drax/common-front": "^0.5.4",
|
|
28
28
|
"@drax/crud-front": "^0.5.3",
|
|
29
|
-
"@drax/crud-share": "^0.5.
|
|
29
|
+
"@drax/crud-share": "^0.5.4"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
32
|
"pinia": "^2.2.2",
|
|
@@ -63,5 +63,5 @@
|
|
|
63
63
|
"vue-tsc": "^2.0.11",
|
|
64
64
|
"vuetify": "^3.7.1"
|
|
65
65
|
},
|
|
66
|
-
"gitHead": "
|
|
66
|
+
"gitHead": "6db0bebb2df9edecd2c3caa7288fb5c7001c4243"
|
|
67
67
|
}
|
package/src/EntityCrud.ts
CHANGED
|
@@ -40,6 +40,14 @@ class EntityCrud implements IEntityCrud{
|
|
|
40
40
|
]
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
get createFields(){
|
|
44
|
+
return this.fields
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
get updateFields(){
|
|
48
|
+
return this.fields
|
|
49
|
+
}
|
|
50
|
+
|
|
43
51
|
get filters():IEntityCrudFilter[]{
|
|
44
52
|
return [
|
|
45
53
|
{name: '_id', type: 'string', label: 'ID', default: '', operator: 'eq' },
|
|
@@ -104,6 +112,10 @@ class EntityCrud implements IEntityCrud{
|
|
|
104
112
|
return field && this.rules[field] && this.rules[field].length > 0 ? this.rules[field] : undefined
|
|
105
113
|
}
|
|
106
114
|
|
|
115
|
+
get isViewable(){
|
|
116
|
+
return true
|
|
117
|
+
}
|
|
118
|
+
|
|
107
119
|
get isEditable(){
|
|
108
120
|
return true
|
|
109
121
|
}
|
package/src/components/Crud.vue
CHANGED
|
@@ -12,7 +12,7 @@ const {entity} = defineProps({
|
|
|
12
12
|
})
|
|
13
13
|
|
|
14
14
|
const {
|
|
15
|
-
onCreate, onEdit, onDelete, onCancel, onSubmit,resetCrudStore,
|
|
15
|
+
onView, onCreate, onEdit, onDelete, onCancel, onSubmit,resetCrudStore,
|
|
16
16
|
operation, dialog, form, notify, error, message, doExport,
|
|
17
17
|
prepareFilters
|
|
18
18
|
} = useCrud(entity);
|
|
@@ -34,6 +34,7 @@ onBeforeMount(() => {
|
|
|
34
34
|
@edit="onEdit"
|
|
35
35
|
@delete="onDelete"
|
|
36
36
|
@export="doExport"
|
|
37
|
+
@view="onView"
|
|
37
38
|
>
|
|
38
39
|
<template v-for="header in entity.headers" :key="header.key" v-slot:[`item.${header.key}`]="{item, value}">
|
|
39
40
|
<slot :name="`item.${header.key}`" v-bind="{item, value}">
|
|
@@ -3,16 +3,20 @@ import {debounce} from "@drax/common-front"
|
|
|
3
3
|
import { type PropType, type Ref} from "vue";
|
|
4
4
|
import {ref, onBeforeMount} from "vue";
|
|
5
5
|
import type {IEntityCrud, IEntityCrudField} from "@drax/crud-share";
|
|
6
|
-
import {VDateInput} from "vuetify/lib/labs/VDateInput";
|
|
7
6
|
|
|
8
7
|
const valueModel = defineModel<string | string[]>({type: [String, Array], required: false})
|
|
9
8
|
|
|
10
9
|
const {entity, multiple} = defineProps({
|
|
11
10
|
entity: {type: Object as PropType<IEntityCrud|undefined>, required: true},
|
|
12
11
|
field: {type: Object as PropType<IEntityCrudField>, required: true},
|
|
12
|
+
prependIcon: {type: String},
|
|
13
|
+
prependInnerIcon: {type: String},
|
|
14
|
+
appendIcon: {type: String},
|
|
15
|
+
appendInnerIcon: {type: String},
|
|
13
16
|
multiple: {type: Boolean, default: false},
|
|
14
17
|
chips: {type: Boolean, default: false},
|
|
15
18
|
closableChips: {type: Boolean, default: true},
|
|
19
|
+
readonly: {type: Boolean, default: false},
|
|
16
20
|
clearable: {type: Boolean, default: true},
|
|
17
21
|
label: {type: String},
|
|
18
22
|
itemValue: {type: [String], default: '_id'},
|
|
@@ -34,63 +38,59 @@ const items: Ref<Array<any>> = ref([])
|
|
|
34
38
|
|
|
35
39
|
const debouncedSearch = debounce(search, 300)
|
|
36
40
|
|
|
37
|
-
|
|
38
|
-
if(valueModel.value && valueModel.value.length > 0){
|
|
39
|
-
|
|
40
|
-
if(multiple && Array.isArray(valueModel.value) ){
|
|
41
|
-
items.value = valueModel.value
|
|
42
|
-
|
|
43
|
-
// valueModel.value = valueModel.value.map((item:any) => item._id)
|
|
44
|
-
await findByIds(valueModel.value)
|
|
45
|
-
}else if(!Array.isArray(valueModel.value)){
|
|
46
|
-
// items.value = [valueModel.value]
|
|
47
|
-
await findByIds([valueModel.value])
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
async function findByIds(ids: Array<string> = []) {
|
|
41
|
+
async function search(value: any) {
|
|
56
42
|
try{
|
|
43
|
+
loading.value = true
|
|
57
44
|
if(!entity){
|
|
58
45
|
throw new Error('Entity is required')
|
|
59
46
|
}
|
|
60
|
-
if(!entity.provider){
|
|
61
|
-
throw new Error('Provider
|
|
62
|
-
}
|
|
63
|
-
if (typeof entity.provider.findByIds !== 'function') {
|
|
64
|
-
throw new Error('Provider does not have a findByIds method');
|
|
47
|
+
if(!entity.provider.search){
|
|
48
|
+
throw new Error('Provider does not have a search method')
|
|
65
49
|
}
|
|
66
|
-
|
|
67
|
-
items.value = await entity.provider.findByIds(ids)
|
|
50
|
+
items.value = await entity.provider.search(value)
|
|
68
51
|
}catch (e){
|
|
69
52
|
console.error(e)
|
|
70
53
|
}finally{
|
|
71
54
|
loading.value = false
|
|
72
55
|
}
|
|
56
|
+
|
|
73
57
|
}
|
|
74
58
|
|
|
59
|
+
onBeforeMount(async () => {
|
|
75
60
|
|
|
76
|
-
|
|
61
|
+
await search('')
|
|
62
|
+
await checkIds()
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
async function checkIds(ids: Array<string> = []) {
|
|
77
66
|
try{
|
|
78
|
-
|
|
79
|
-
if(
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
67
|
+
|
|
68
|
+
if(valueModel.value) {
|
|
69
|
+
let ids = Array.isArray(valueModel.value) ? valueModel.value : [valueModel.value]
|
|
70
|
+
for (let id of ids) {
|
|
71
|
+
if (!items.value.some((item: any) => item._id === id)) {
|
|
72
|
+
if (!entity) {
|
|
73
|
+
throw new Error('CrudAutocomplete Entity is required')
|
|
74
|
+
}
|
|
75
|
+
if (!entity.provider) {
|
|
76
|
+
throw new Error('CrudAutocomplete Provider is not defined')
|
|
77
|
+
}
|
|
78
|
+
if (typeof entity.provider.findById !== 'function') {
|
|
79
|
+
throw new Error('CrudAutocomplete Provider does not have a findById method');
|
|
80
|
+
}
|
|
81
|
+
let item = await entity.provider.findById(id)
|
|
82
|
+
items.value.push(item)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
84
85
|
}
|
|
85
|
-
items.value = await entity.provider.search(value)
|
|
86
86
|
}catch (e){
|
|
87
87
|
console.error(e)
|
|
88
|
-
}finally{
|
|
89
|
-
loading.value = false
|
|
90
88
|
}
|
|
91
|
-
|
|
92
89
|
}
|
|
93
90
|
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
|
|
94
94
|
defineEmits(['updateValue'])
|
|
95
95
|
|
|
96
96
|
</script>
|
|
@@ -108,6 +108,7 @@ defineEmits(['updateValue'])
|
|
|
108
108
|
:item-title="itemTitle"
|
|
109
109
|
:loading="loading"
|
|
110
110
|
:rules="rules"
|
|
111
|
+
:readonly="readonly"
|
|
111
112
|
:density="density"
|
|
112
113
|
:variant="variant"
|
|
113
114
|
:hide-details="hideDetails"
|
|
@@ -116,6 +117,10 @@ defineEmits(['updateValue'])
|
|
|
116
117
|
:error-messages="errorMessages"
|
|
117
118
|
@update:search="debouncedSearch"
|
|
118
119
|
@update:modelValue="$emit('updateValue')"
|
|
120
|
+
:prepend-icon="prependIcon"
|
|
121
|
+
:append-icon="appendIcon"
|
|
122
|
+
:prepend-inner-icon="prependInnerIcon"
|
|
123
|
+
:append-inner-icon="appendInnerIcon"
|
|
119
124
|
></v-autocomplete>
|
|
120
125
|
</template>
|
|
121
126
|
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import type {TOperation} from "../interfaces/TOperation";
|
|
3
2
|
import type {PropType} from "vue";
|
|
4
|
-
import type {IEntityCrud} from "@drax/crud-share";
|
|
3
|
+
import type {IEntityCrud, IEntityCrudOperation} from "@drax/crud-share";
|
|
5
4
|
const dialog = defineModel({type: Boolean, default: false})
|
|
6
5
|
import {useI18n} from "vue-i18n";
|
|
7
6
|
const {t,te} = useI18n()
|
|
8
7
|
|
|
9
8
|
defineProps({
|
|
10
9
|
entity: {type: Object as PropType<IEntityCrud>, required: true},
|
|
11
|
-
operation: {type: String as PropType<
|
|
10
|
+
operation: {type: String as PropType<IEntityCrudOperation>}
|
|
12
11
|
})
|
|
13
12
|
|
|
14
13
|
defineEmits(
|
|
@@ -1,26 +1,43 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import type {PropType} from "vue";
|
|
3
|
-
import {ref} from "vue";
|
|
4
|
-
import CrudFormField from "./CrudFormField.vue";
|
|
5
|
-
import type {TOperation} from "../interfaces/TOperation";
|
|
6
|
-
import type {IEntityCrud} from "@drax/crud-share";
|
|
7
2
|
import {useI18n} from "vue-i18n";
|
|
3
|
+
import type {IEntityCrud, IEntityCrudOperation} from "@drax/crud-share";
|
|
4
|
+
import {useFormUtils} from "../composables/UseFormUtils";
|
|
5
|
+
import CrudFormField from "./CrudFormField.vue";
|
|
6
|
+
import {computed, defineEmits, defineModel, defineProps, ref} from "vue";
|
|
7
|
+
import type { PropType} from "vue";
|
|
8
8
|
import {useCrudStore} from "../stores/UseCrudStore";
|
|
9
|
-
const {t,te} = useI18n()
|
|
10
|
-
const store = useCrudStore()
|
|
11
|
-
const valueModel = defineModel({type: [Object]})
|
|
12
9
|
|
|
13
10
|
|
|
14
|
-
const {
|
|
11
|
+
const {t, te} = useI18n()
|
|
12
|
+
|
|
13
|
+
const valueModel = defineModel({type: [Object]})
|
|
14
|
+
|
|
15
|
+
const {entity, operation} = defineProps({
|
|
15
16
|
entity: {type: Object as PropType<IEntityCrud>, required: true},
|
|
16
|
-
operation: {type: String as PropType<
|
|
17
|
+
operation: {type: String as PropType<IEntityCrudOperation>, required: true},
|
|
17
18
|
readonly: {type: Boolean, default: false},
|
|
18
19
|
error: {type: String, required: false},
|
|
19
20
|
})
|
|
20
21
|
|
|
22
|
+
const emit = defineEmits(['submit', 'cancel'])
|
|
23
|
+
|
|
24
|
+
const store = useCrudStore()
|
|
25
|
+
|
|
21
26
|
const valid = ref()
|
|
22
27
|
const formRef = ref()
|
|
23
28
|
|
|
29
|
+
const fields = computed(() => {
|
|
30
|
+
if(operation === 'create') {
|
|
31
|
+
return entity.createFields
|
|
32
|
+
}else if(operation === 'edit') {
|
|
33
|
+
return entity.updateFields
|
|
34
|
+
}else if(operation === 'delete') {
|
|
35
|
+
return entity.updateFields
|
|
36
|
+
}else if(operation === 'view') {
|
|
37
|
+
return entity.updateFields
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
|
|
24
41
|
async function submit() {
|
|
25
42
|
store.resetErrors()
|
|
26
43
|
await formRef.value.validate()
|
|
@@ -35,7 +52,10 @@ function cancel() {
|
|
|
35
52
|
emit('cancel')
|
|
36
53
|
}
|
|
37
54
|
|
|
38
|
-
const
|
|
55
|
+
const {
|
|
56
|
+
variant, submitColor, readonly
|
|
57
|
+
} = useFormUtils(operation)
|
|
58
|
+
|
|
39
59
|
|
|
40
60
|
</script>
|
|
41
61
|
|
|
@@ -49,11 +69,18 @@ const emit = defineEmits(['submit', 'cancel'])
|
|
|
49
69
|
<v-alert color="error">{{ te(error) ? t(error) : error }}</v-alert>
|
|
50
70
|
</v-card-text>
|
|
51
71
|
<v-card-text>
|
|
52
|
-
<template v-for="field in
|
|
72
|
+
<template v-for="field in fields" :key="field.name">
|
|
53
73
|
<crud-form-field
|
|
54
74
|
:field="field"
|
|
55
75
|
:entity="entity"
|
|
56
76
|
v-model="valueModel[field.name]"
|
|
77
|
+
:clearable="false"
|
|
78
|
+
:readonly="readonly"
|
|
79
|
+
:variant="variant"
|
|
80
|
+
:prepend-inner-icon="field?.prependInnerIcon"
|
|
81
|
+
:prepend-icon="field?.prependIcon"
|
|
82
|
+
:append-icon="field?.appendIcon"
|
|
83
|
+
:append-inner-icon="field?.appendInnerIcon"
|
|
57
84
|
/>
|
|
58
85
|
</template>
|
|
59
86
|
</v-card-text>
|
|
@@ -61,7 +88,7 @@ const emit = defineEmits(['submit', 'cancel'])
|
|
|
61
88
|
<v-card-actions>
|
|
62
89
|
<v-spacer></v-spacer>
|
|
63
90
|
<v-btn variant="text" color="grey" @click="cancel">{{ t('action.cancel') }}</v-btn>
|
|
64
|
-
<v-btn variant="flat" color="
|
|
91
|
+
<v-btn variant="flat" v-if="operation != 'view'" :color="submitColor" @click="submit">
|
|
65
92
|
{{ operation ? t('action.' + operation) : t('action.sent') }}
|
|
66
93
|
</v-btn>
|
|
67
94
|
</v-card-actions>
|
|
@@ -16,10 +16,14 @@ const valueModel = defineModel<any>({type: [String, Number, Boolean, Object, Arr
|
|
|
16
16
|
const {index, entity, field, disableRules} = defineProps({
|
|
17
17
|
entity: {type: Object as PropType<IEntityCrud>, required: true},
|
|
18
18
|
field: {type: Object as PropType<IEntityCrudField|IEntityCrudFilter|undefined>, required: true},
|
|
19
|
+
prependIcon: {type: String, default: ''},
|
|
20
|
+
prependInnerIcon: {type: String, default: ''},
|
|
21
|
+
appendIcon: {type: String, default: ''},
|
|
22
|
+
appendInnerIcon: {type: String, default: ''},
|
|
19
23
|
readonly: {type: Boolean, default: false},
|
|
20
24
|
hideDetails: {type: Boolean, default: false},
|
|
21
25
|
singleLine: {type: Boolean, default: false},
|
|
22
|
-
clearable: {type: Boolean, default:
|
|
26
|
+
clearable: {type: Boolean, default: false},
|
|
23
27
|
disableRules: {type: Boolean, default: false},
|
|
24
28
|
index: {type: Number, default: 0},
|
|
25
29
|
density: {type: String as PropType<'comfortable' | 'compact' | 'default'>, default: 'default'},
|
|
@@ -69,9 +73,12 @@ defineEmits(['updateValue'])
|
|
|
69
73
|
:clearable="clearable"
|
|
70
74
|
:hide-details="hideDetails"
|
|
71
75
|
:single-line="singleLine"
|
|
76
|
+
:prepend-icon="prependIcon"
|
|
77
|
+
:append-icon="appendIcon"
|
|
78
|
+
:prepend-inner-icon="prependInnerIcon"
|
|
79
|
+
:append-inner-icon="appendInnerIcon"
|
|
72
80
|
@update:modelValue="$emit('updateValue')"
|
|
73
|
-
|
|
74
|
-
</v-text-field>
|
|
81
|
+
/>
|
|
75
82
|
|
|
76
83
|
<v-text-field
|
|
77
84
|
v-if="field.type === 'number'"
|
|
@@ -88,10 +95,13 @@ defineEmits(['updateValue'])
|
|
|
88
95
|
:hide-details="hideDetails"
|
|
89
96
|
:single-line="singleLine"
|
|
90
97
|
@update:modelValue="$emit('updateValue')"
|
|
91
|
-
|
|
92
|
-
|
|
98
|
+
:prepend-icon="prependIcon"
|
|
99
|
+
:append-icon="appendIcon"
|
|
100
|
+
:prepend-inner-icon="prependInnerIcon"
|
|
101
|
+
:append-inner-icon="appendInnerIcon"
|
|
102
|
+
/>
|
|
93
103
|
|
|
94
|
-
<v-
|
|
104
|
+
<v-switch
|
|
95
105
|
v-if="field.type === 'boolean'"
|
|
96
106
|
:name="name"
|
|
97
107
|
:label="label"
|
|
@@ -105,8 +115,12 @@ defineEmits(['updateValue'])
|
|
|
105
115
|
:hide-details="hideDetails"
|
|
106
116
|
:single-line="singleLine"
|
|
107
117
|
@update:modelValue="$emit('updateValue')"
|
|
108
|
-
|
|
109
|
-
|
|
118
|
+
:prepend-icon="prependIcon"
|
|
119
|
+
:append-icon="appendIcon"
|
|
120
|
+
:prepend-inner-icon="prependInnerIcon"
|
|
121
|
+
:append-inner-icon="appendInnerIcon"
|
|
122
|
+
color="primary"
|
|
123
|
+
/>
|
|
110
124
|
|
|
111
125
|
|
|
112
126
|
<v-date-input
|
|
@@ -117,8 +131,6 @@ defineEmits(['updateValue'])
|
|
|
117
131
|
v-model="valueModel"
|
|
118
132
|
:readonly="readonly"
|
|
119
133
|
:error-messages="inputErrors"
|
|
120
|
-
prepend-inner-icon="mdi-calendar"
|
|
121
|
-
prepend-icon=""
|
|
122
134
|
:rules="rules"
|
|
123
135
|
:density="density"
|
|
124
136
|
:variant="variant"
|
|
@@ -126,6 +138,10 @@ defineEmits(['updateValue'])
|
|
|
126
138
|
:hide-details="hideDetails"
|
|
127
139
|
:single-line="singleLine"
|
|
128
140
|
@update:modelValue="$emit('updateValue')"
|
|
141
|
+
:prepend-icon="prependIcon"
|
|
142
|
+
:append-icon="appendIcon"
|
|
143
|
+
:prepend-inner-icon="prependInnerIcon"
|
|
144
|
+
:append-inner-icon="appendInnerIcon"
|
|
129
145
|
/>
|
|
130
146
|
|
|
131
147
|
<crud-autocomplete
|
|
@@ -138,10 +154,15 @@ defineEmits(['updateValue'])
|
|
|
138
154
|
:rules="rules"
|
|
139
155
|
:density="density"
|
|
140
156
|
:variant="variant"
|
|
157
|
+
:readonly="readonly"
|
|
141
158
|
:clearable="clearable"
|
|
142
159
|
:hide-details="hideDetails"
|
|
143
160
|
:single-line="singleLine"
|
|
144
161
|
@updateValue="$emit('updateValue')"
|
|
162
|
+
:prepend-icon="prependIcon"
|
|
163
|
+
:append-icon="appendIcon"
|
|
164
|
+
:prepend-inner-icon="prependInnerIcon"
|
|
165
|
+
:append-inner-icon="appendInnerIcon"
|
|
145
166
|
/>
|
|
146
167
|
|
|
147
168
|
<v-card v-if="field.type === 'object'" class="mt-3" variant="flat" border>
|
|
@@ -159,6 +180,10 @@ defineEmits(['updateValue'])
|
|
|
159
180
|
:hide-details="hideDetails"
|
|
160
181
|
:single-line="singleLine"
|
|
161
182
|
@updateValue="$emit('updateValue')"
|
|
183
|
+
:prepend-icon="prependIcon"
|
|
184
|
+
:append-icon="appendIcon"
|
|
185
|
+
:prepend-inner-icon="prependInnerIcon"
|
|
186
|
+
:append-inner-icon="appendInnerIcon"
|
|
162
187
|
></crud-form-field>
|
|
163
188
|
</v-card-text>
|
|
164
189
|
|
|
@@ -182,6 +207,10 @@ defineEmits(['updateValue'])
|
|
|
182
207
|
:single-line="singleLine"
|
|
183
208
|
:rules="rules"
|
|
184
209
|
@update:modelValue="$emit('updateValue')"
|
|
210
|
+
:prepend-icon="prependIcon"
|
|
211
|
+
:append-icon="appendIcon"
|
|
212
|
+
:prepend-inner-icon="prependInnerIcon"
|
|
213
|
+
:append-inner-icon="appendInnerIcon"
|
|
185
214
|
>
|
|
186
215
|
</v-combobox>
|
|
187
216
|
|
|
@@ -202,6 +231,10 @@ defineEmits(['updateValue'])
|
|
|
202
231
|
:hide-details="hideDetails"
|
|
203
232
|
:single-line="singleLine"
|
|
204
233
|
@updateValue="$emit('updateValue')"
|
|
234
|
+
:prepend-icon="prependIcon"
|
|
235
|
+
:append-icon="appendIcon"
|
|
236
|
+
:prepend-inner-icon="prependInnerIcon"
|
|
237
|
+
:append-inner-icon="appendInnerIcon"
|
|
205
238
|
/>
|
|
206
239
|
|
|
207
240
|
|
|
@@ -222,6 +255,10 @@ defineEmits(['updateValue'])
|
|
|
222
255
|
:single-line="singleLine"
|
|
223
256
|
:rules="rules"
|
|
224
257
|
@update:modelValue="$emit('updateValue')"
|
|
258
|
+
:prepend-icon="prependIcon"
|
|
259
|
+
:append-icon="appendIcon"
|
|
260
|
+
:prepend-inner-icon="prependInnerIcon"
|
|
261
|
+
:append-inner-icon="appendInnerIcon"
|
|
225
262
|
>
|
|
226
263
|
</v-combobox>
|
|
227
264
|
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
import type {PropType} from "vue";
|
|
3
3
|
import CrudFormField from "./CrudFormField.vue";
|
|
4
4
|
import type {IEntityCrud, IEntityCrudField} from "@drax/crud-share";
|
|
5
|
-
import {VDateInput} from "vuetify/lib/labs/VDateInput";
|
|
6
5
|
|
|
7
6
|
const valueModel = defineModel({type: Array, default: () => []});
|
|
8
7
|
|
|
@@ -8,6 +8,7 @@ import CrudImportButton from "./buttons/CrudImportButton.vue";
|
|
|
8
8
|
import CrudCreateButton from "./buttons/CrudCreateButton.vue";
|
|
9
9
|
import CrudUpdateButton from "./buttons/CrudUpdateButton.vue";
|
|
10
10
|
import CrudDeleteButton from "./buttons/CrudDeleteButton.vue";
|
|
11
|
+
import CrudViewButton from "./buttons/CrudViewButton.vue";
|
|
11
12
|
import CrudExportList from "./CrudExportList.vue";
|
|
12
13
|
import type {IEntityCrud} from "@drax/crud-share";
|
|
13
14
|
import {useI18n} from "vue-i18n";
|
|
@@ -31,8 +32,8 @@ const actions: IEntityCrudHeader[] = [{
|
|
|
31
32
|
title: t('action.actions'),
|
|
32
33
|
key: 'actions',
|
|
33
34
|
sortable: false,
|
|
34
|
-
align: '
|
|
35
|
-
minWidth: '
|
|
35
|
+
align: 'center',
|
|
36
|
+
minWidth: '190px'
|
|
36
37
|
}]
|
|
37
38
|
const tHeaders: IEntityCrudHeader[] = entity.headers.map(header => ({
|
|
38
39
|
...header,
|
|
@@ -46,6 +47,8 @@ defineExpose({
|
|
|
46
47
|
doPaginate
|
|
47
48
|
});
|
|
48
49
|
|
|
50
|
+
defineEmits(['import', 'export', 'create', 'update', 'delete', 'view'])
|
|
51
|
+
|
|
49
52
|
</script>
|
|
50
53
|
|
|
51
54
|
<template>
|
|
@@ -120,6 +123,11 @@ defineExpose({
|
|
|
120
123
|
|
|
121
124
|
|
|
122
125
|
<template v-slot:item.actions="{item}">
|
|
126
|
+
<crud-view-button
|
|
127
|
+
v-if="entity.isViewable && hasPermission(entity.permissions.view)"
|
|
128
|
+
@click="$emit('view', item)"
|
|
129
|
+
/>
|
|
130
|
+
|
|
123
131
|
<crud-update-button
|
|
124
132
|
v-if="entity.isEditable && hasPermission(entity.permissions.update)"
|
|
125
133
|
@click="$emit('edit', item)"
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import {useI18n} from "vue-i18n";
|
|
3
|
+
const {t} = useI18n()
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<template>
|
|
7
|
+
<v-tooltip location="top">
|
|
8
|
+
<template v-slot:activator="{ props}">
|
|
9
|
+
<v-btn
|
|
10
|
+
v-bind="{ ...$attrs, ...props }"
|
|
11
|
+
icon="mdi-magnify"
|
|
12
|
+
class="mr-1"
|
|
13
|
+
variant="text"
|
|
14
|
+
color="secondary"
|
|
15
|
+
slim
|
|
16
|
+
>
|
|
17
|
+
</v-btn>
|
|
18
|
+
</template>
|
|
19
|
+
{{ t('action.view')}}
|
|
20
|
+
</v-tooltip>
|
|
21
|
+
</template>
|
|
22
|
+
|
|
23
|
+
<style scoped>
|
|
24
|
+
|
|
25
|
+
</style>
|
|
@@ -83,13 +83,6 @@ export function useCrud(entity: IEntityCrud) {
|
|
|
83
83
|
|
|
84
84
|
|
|
85
85
|
|
|
86
|
-
|
|
87
|
-
function onCreate() {
|
|
88
|
-
store.setOperation("create")
|
|
89
|
-
store.setForm(entity.form)
|
|
90
|
-
store.setDialog(true)
|
|
91
|
-
}
|
|
92
|
-
|
|
93
86
|
function cast(item: any){
|
|
94
87
|
entity.fields.filter(field => field.type === 'date')
|
|
95
88
|
.forEach(field => {
|
|
@@ -98,31 +91,44 @@ export function useCrud(entity: IEntityCrud) {
|
|
|
98
91
|
|
|
99
92
|
entity.fields.filter(field => field.type === 'ref')
|
|
100
93
|
.forEach(field => {
|
|
101
|
-
item[field.name] = item[field.name]._id
|
|
94
|
+
item[field.name] = item[field.name]?._id ? item[field.name]._id : item[field.name]
|
|
102
95
|
})
|
|
103
96
|
|
|
104
97
|
entity.fields.filter(field => field.type === 'array.ref')
|
|
105
98
|
.forEach(field => {
|
|
106
|
-
item[field.name] = item[field.name].map(((i:any) => i._id))
|
|
99
|
+
item[field.name] = item[field.name].map(((i:any) => i?._id ? i._id : i))
|
|
107
100
|
})
|
|
108
101
|
|
|
109
102
|
return item
|
|
110
103
|
}
|
|
111
104
|
|
|
105
|
+
function onView(item: object) {
|
|
106
|
+
store.setOperation("view")
|
|
107
|
+
store.setForm(cast({...item}))
|
|
108
|
+
openDialog()
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
function onCreate() {
|
|
113
|
+
store.setOperation("create")
|
|
114
|
+
store.setForm(entity.form)
|
|
115
|
+
openDialog()
|
|
116
|
+
}
|
|
117
|
+
|
|
112
118
|
function onEdit(item: object) {
|
|
113
119
|
store.setOperation("edit")
|
|
114
120
|
store.setForm(cast({...item}))
|
|
115
|
-
|
|
121
|
+
openDialog()
|
|
116
122
|
}
|
|
117
123
|
|
|
118
124
|
function onDelete(item: object) {
|
|
119
125
|
store.setOperation("delete")
|
|
120
126
|
store.setForm(cast({...item}))
|
|
121
|
-
|
|
127
|
+
openDialog()
|
|
122
128
|
}
|
|
123
129
|
|
|
124
130
|
function onCancel() {
|
|
125
|
-
|
|
131
|
+
closeDialog()
|
|
126
132
|
store.setError("")
|
|
127
133
|
store.setInputErrors(null)
|
|
128
134
|
}
|
|
@@ -130,6 +136,9 @@ export function useCrud(entity: IEntityCrud) {
|
|
|
130
136
|
function onSubmit(formData: any) {
|
|
131
137
|
store.setInputErrors(null)
|
|
132
138
|
switch (store.operation) {
|
|
139
|
+
case "view":
|
|
140
|
+
closeDialog()
|
|
141
|
+
break
|
|
133
142
|
case "create":
|
|
134
143
|
doCreate(formData)
|
|
135
144
|
break
|
|
@@ -142,11 +151,19 @@ export function useCrud(entity: IEntityCrud) {
|
|
|
142
151
|
}
|
|
143
152
|
}
|
|
144
153
|
|
|
154
|
+
function openDialog() {
|
|
155
|
+
store.setDialog(true)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function closeDialog() {
|
|
159
|
+
store.setDialog(false)
|
|
160
|
+
}
|
|
161
|
+
|
|
145
162
|
async function doCreate(formData: any) {
|
|
146
163
|
try {
|
|
147
164
|
await entity?.provider.create(formData)
|
|
148
165
|
await doPaginate()
|
|
149
|
-
|
|
166
|
+
closeDialog()
|
|
150
167
|
store.showMessage("Entity created successfully!")
|
|
151
168
|
} catch (e: any) {
|
|
152
169
|
if(e.inputErrors){
|
|
@@ -162,7 +179,7 @@ export function useCrud(entity: IEntityCrud) {
|
|
|
162
179
|
try {
|
|
163
180
|
await entity?.provider.update(formData._id, formData)
|
|
164
181
|
await doPaginate()
|
|
165
|
-
|
|
182
|
+
closeDialog()
|
|
166
183
|
store.showMessage("Entity updated successfully!")
|
|
167
184
|
} catch (e: any) {
|
|
168
185
|
console.log("inputErrors", e.inputErrors)
|
|
@@ -179,7 +196,7 @@ export function useCrud(entity: IEntityCrud) {
|
|
|
179
196
|
try {
|
|
180
197
|
await entity?.provider.delete(formData._id)
|
|
181
198
|
await doPaginate()
|
|
182
|
-
|
|
199
|
+
closeDialog()
|
|
183
200
|
store.showMessage("Entity deleted successfully!")
|
|
184
201
|
} catch (e: any) {
|
|
185
202
|
store.setError(e.message || "An error occurred while deleting the entity")
|
|
@@ -198,7 +215,7 @@ export function useCrud(entity: IEntityCrud) {
|
|
|
198
215
|
|
|
199
216
|
|
|
200
217
|
return {
|
|
201
|
-
doPaginate, doExport, onCreate, onEdit, onDelete, onCancel, onSubmit,resetCrudStore,
|
|
218
|
+
doPaginate, doExport, onView, onCreate, onEdit, onDelete, onCancel, onSubmit,resetCrudStore,
|
|
202
219
|
operation, dialog, form, notify, error, message, formValid,
|
|
203
220
|
loading, itemsPerPage, page, sortBy, search, totalItems, items,
|
|
204
221
|
prepareFilters,filters,
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type {IEntityCrudOperation} from "@drax/crud-share";
|
|
2
|
+
import {computed} from "vue";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export function useFormUtils(operation:IEntityCrudOperation) {
|
|
6
|
+
|
|
7
|
+
const readonly = computed(() => {
|
|
8
|
+
return operation === 'delete' || operation === 'view';
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
const submitColor = computed(() => {
|
|
12
|
+
if(operation === 'create') {
|
|
13
|
+
return 'primary'
|
|
14
|
+
}else if(operation === 'edit') {
|
|
15
|
+
return 'primary'
|
|
16
|
+
}else if(operation === 'delete') {
|
|
17
|
+
return 'red'
|
|
18
|
+
}else if(operation === 'view') {
|
|
19
|
+
return 'secondary'
|
|
20
|
+
}
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
const variant = computed(() => {
|
|
24
|
+
if(operation === 'create') {
|
|
25
|
+
return 'filled'
|
|
26
|
+
}else if(operation === 'edit') {
|
|
27
|
+
return 'filled'
|
|
28
|
+
}else if(operation === 'delete') {
|
|
29
|
+
return 'underlined'
|
|
30
|
+
}else if(operation === 'view') {
|
|
31
|
+
return 'underlined'
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
readonly,
|
|
39
|
+
variant,
|
|
40
|
+
submitColor,
|
|
41
|
+
}
|
|
42
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -8,6 +8,7 @@ import CrudNotify from "./components/CrudNotify.vue";
|
|
|
8
8
|
import CrudSearch from "./components/CrudSearch.vue";
|
|
9
9
|
import {useCrudStore} from "./stores/UseCrudStore";
|
|
10
10
|
import {useCrud} from "./composables/UseCrud";
|
|
11
|
+
import {useFormUtils} from "./composables/UseFormUtils";
|
|
11
12
|
import {EntityCrud} from "./EntityCrud";
|
|
12
13
|
|
|
13
14
|
|
|
@@ -21,6 +22,7 @@ export {
|
|
|
21
22
|
CrudNotify,
|
|
22
23
|
CrudSearch,
|
|
23
24
|
useCrud,
|
|
25
|
+
useFormUtils,
|
|
24
26
|
useCrudStore,
|
|
25
27
|
EntityCrud
|
|
26
28
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {defineStore} from "pinia";
|
|
2
|
-
import type {
|
|
2
|
+
import type {IEntityCrudOperation} from "@drax/crud-share";
|
|
3
3
|
|
|
4
4
|
export const useCrudStore = defineStore('CrudStore', {
|
|
5
5
|
state: () => (
|
|
6
6
|
{
|
|
7
|
-
operation: null as
|
|
7
|
+
operation: null as IEntityCrudOperation,
|
|
8
8
|
dialog: false as boolean,
|
|
9
9
|
form: {} as any,
|
|
10
10
|
formValid: {} as any,
|
|
@@ -36,7 +36,7 @@ export const useCrudStore = defineStore('CrudStore', {
|
|
|
36
36
|
}
|
|
37
37
|
},
|
|
38
38
|
actions: {
|
|
39
|
-
setOperation(operation:
|
|
39
|
+
setOperation(operation: IEntityCrudOperation) {
|
|
40
40
|
this.operation = operation
|
|
41
41
|
},
|
|
42
42
|
setDialog(dialog: boolean) {
|