@drax/crud-vue 0.4.0 → 0.5.2
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 +5 -4
- package/src/EntityCrud.ts +55 -41
- package/src/components/Crud.vue +10 -5
- package/src/components/CrudAutocomplete.vue +32 -14
- package/src/components/CrudDialog.vue +5 -3
- package/src/components/CrudExportList.vue +55 -0
- package/src/components/CrudForm.vue +17 -9
- package/src/components/CrudFormField.vue +11 -9
- package/src/components/CrudFormList.vue +6 -7
- package/src/components/CrudList.vue +66 -36
- package/src/components/CrudSearch.vue +3 -1
- package/src/components/buttons/CrudCreateButton.vue +25 -0
- package/src/components/buttons/CrudDeleteButton.vue +25 -0
- package/src/components/buttons/CrudExportButton.vue +48 -0
- package/src/components/buttons/CrudImportButton.vue +39 -0
- package/src/components/buttons/CrudUpdateButton.vue +25 -0
- package/src/composables/UseCrud.ts +68 -20
- package/src/index.ts +0 -2
- package/src/stores/UseCrudStore.ts +21 -2
- package/src/interfaces/IEntityCrud.ts +0 -33
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.5.2",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"main": "./src/index.ts",
|
|
9
9
|
"module": "./src/index.ts",
|
|
@@ -24,8 +24,9 @@
|
|
|
24
24
|
"format": "prettier --write src/"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@drax/common-front": "^0.
|
|
28
|
-
"@drax/
|
|
27
|
+
"@drax/common-front": "^0.5.1",
|
|
28
|
+
"@drax/crud-front": "^0.5.1",
|
|
29
|
+
"@drax/crud-share": "^0.5.2"
|
|
29
30
|
},
|
|
30
31
|
"peerDependencies": {
|
|
31
32
|
"pinia": "^2.2.2",
|
|
@@ -62,5 +63,5 @@
|
|
|
62
63
|
"vue-tsc": "^2.0.11",
|
|
63
64
|
"vuetify": "^3.7.1"
|
|
64
65
|
},
|
|
65
|
-
"gitHead": "
|
|
66
|
+
"gitHead": "6f854dbeb2af7bca32ed35bcec2f8e48790a73b9"
|
|
66
67
|
}
|
package/src/EntityCrud.ts
CHANGED
|
@@ -1,102 +1,98 @@
|
|
|
1
|
-
import type {IDraxCrud} from "@drax/common-share";
|
|
2
1
|
import type {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
ICrudRules,
|
|
8
|
-
ICrudField
|
|
9
|
-
} from "./interfaces/IEntityCrud";
|
|
2
|
+
IEntityCrud, IEntityCrudForm, IEntityCrudHeader, IEntityCrudRefs,
|
|
3
|
+
IEntityCrudRules, IEntityCrudField, IEntityCrudPermissions,
|
|
4
|
+
IDraxCrudProvider
|
|
5
|
+
} from "@drax/crud-share";
|
|
10
6
|
|
|
11
7
|
|
|
12
8
|
|
|
13
|
-
class EntityCrud{
|
|
9
|
+
class EntityCrud implements IEntityCrud{
|
|
14
10
|
|
|
15
11
|
name: string = ''
|
|
16
12
|
|
|
17
13
|
constructor() {
|
|
18
14
|
}
|
|
19
15
|
|
|
20
|
-
static get instance(){
|
|
16
|
+
static get instance():IEntityCrud{
|
|
21
17
|
throw new Error('EntityCrud instance not found')
|
|
22
18
|
}
|
|
23
19
|
|
|
24
20
|
|
|
25
|
-
get headers():
|
|
21
|
+
get headers():IEntityCrudHeader[]{
|
|
26
22
|
return [
|
|
27
23
|
{title: 'ID',key:'_id'},
|
|
28
24
|
]
|
|
29
25
|
}
|
|
30
26
|
|
|
31
|
-
get permissions():
|
|
27
|
+
get permissions(): IEntityCrudPermissions {
|
|
32
28
|
return {
|
|
33
29
|
manage: 'manage', view: 'view', create: 'create', update: 'update', delete: 'delete'
|
|
34
30
|
}
|
|
35
31
|
}
|
|
36
32
|
|
|
37
|
-
get provider():
|
|
33
|
+
get provider(): IDraxCrudProvider<any, any, any>{
|
|
38
34
|
throw new Error('provider not implemented')
|
|
39
35
|
}
|
|
40
36
|
|
|
41
|
-
get fields():
|
|
37
|
+
get fields():IEntityCrudField[]{
|
|
42
38
|
return [
|
|
43
39
|
{name: 'id', type: 'string', label: 'ID', default: '' },
|
|
44
40
|
]
|
|
45
41
|
}
|
|
46
42
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
})
|
|
60
|
-
}
|
|
61
|
-
return value
|
|
43
|
+
objectFields(field:IEntityCrudField){
|
|
44
|
+
let value:any = {}
|
|
45
|
+
if(field.objectFields){
|
|
46
|
+
field.objectFields.forEach(subField => {
|
|
47
|
+
if(subField.type === 'object'){
|
|
48
|
+
value[subField.name] = this.objectFields(subField)
|
|
49
|
+
}else{
|
|
50
|
+
value[subField.name] = subField.default
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
})
|
|
62
54
|
}
|
|
55
|
+
return value
|
|
56
|
+
}
|
|
63
57
|
|
|
64
|
-
|
|
58
|
+
get form():IEntityCrudForm{
|
|
65
59
|
|
|
60
|
+
const form = this.fields.reduce((acc, field) => {
|
|
66
61
|
let value = null
|
|
67
62
|
if(field.type === 'object'){
|
|
68
|
-
value = objectFields(field)
|
|
69
|
-
}
|
|
63
|
+
value = this.objectFields(field)
|
|
64
|
+
}else if(field.default != undefined){
|
|
70
65
|
value = field.default
|
|
71
66
|
}
|
|
72
67
|
|
|
73
68
|
return {...acc, [field.name]: value }
|
|
74
69
|
}, {})
|
|
75
70
|
|
|
76
|
-
console.log("Form: ", form)
|
|
71
|
+
//console.log("Form: ", form)
|
|
77
72
|
|
|
78
73
|
return form
|
|
79
74
|
|
|
80
75
|
}
|
|
81
76
|
|
|
82
|
-
get refs():{
|
|
77
|
+
get refs():IEntityCrudRefs{
|
|
83
78
|
return {}
|
|
84
79
|
}
|
|
85
80
|
|
|
86
|
-
getRef(ref: string):
|
|
81
|
+
getRef(ref: string):IEntityCrud{
|
|
87
82
|
if(!this.refs.hasOwnProperty(ref)) {
|
|
88
83
|
throw new Error("Ref not found: " + ref)
|
|
89
84
|
}
|
|
90
85
|
|
|
91
|
-
return this.refs[ref]
|
|
86
|
+
return this.refs[ref]
|
|
92
87
|
}
|
|
93
88
|
|
|
94
|
-
get rules():
|
|
89
|
+
get rules(): IEntityCrudRules{
|
|
95
90
|
return {}
|
|
96
91
|
}
|
|
97
92
|
|
|
98
|
-
|
|
99
|
-
|
|
93
|
+
getRule(field:string|undefined):Array<Function>|undefined {
|
|
94
|
+
console.log("Getting rule for field: ", field, this.rules)
|
|
95
|
+
return field && this.rules[field] && this.rules[field].length > 0 ? this.rules[field] : undefined
|
|
100
96
|
}
|
|
101
97
|
|
|
102
98
|
get isEditable(){
|
|
@@ -111,11 +107,29 @@ class EntityCrud{
|
|
|
111
107
|
return true
|
|
112
108
|
}
|
|
113
109
|
|
|
114
|
-
get
|
|
115
|
-
return
|
|
110
|
+
get isExportable(){
|
|
111
|
+
return true
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
get exportFormats(){
|
|
115
|
+
return ['CSV', 'JSON']
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
get exportHeaders(){
|
|
119
|
+
return ['_id']
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
get isImportable(){
|
|
123
|
+
return true
|
|
116
124
|
}
|
|
117
125
|
|
|
126
|
+
get importFormats(){
|
|
127
|
+
return ['CSV', 'JSON']
|
|
128
|
+
}
|
|
118
129
|
|
|
130
|
+
get dialogFullscreen(){
|
|
131
|
+
return false
|
|
132
|
+
}
|
|
119
133
|
|
|
120
134
|
|
|
121
135
|
}
|
package/src/components/Crud.vue
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import type
|
|
3
|
-
import
|
|
2
|
+
import {onBeforeMount, type PropType} from "vue";
|
|
3
|
+
import type {IEntityCrud} from "@drax/crud-share";
|
|
4
4
|
import CrudList from "./CrudList.vue";
|
|
5
5
|
import CrudForm from "./CrudForm.vue";
|
|
6
6
|
import CrudNotify from "./CrudNotify.vue";
|
|
@@ -8,14 +8,18 @@ import CrudDialog from "./CrudDialog.vue";
|
|
|
8
8
|
import {useCrud} from "../composables/UseCrud";
|
|
9
9
|
|
|
10
10
|
const {entity} = defineProps({
|
|
11
|
-
entity: {type: Object as PropType<
|
|
11
|
+
entity: {type: Object as PropType<IEntityCrud>, required: true},
|
|
12
12
|
})
|
|
13
13
|
|
|
14
14
|
const {
|
|
15
|
-
onCreate, onEdit, onDelete, onCancel, onSubmit,
|
|
16
|
-
operation, dialog, form,
|
|
15
|
+
onCreate, onEdit, onDelete, onCancel, onSubmit,resetCrudStore,
|
|
16
|
+
operation, dialog, form, notify, error, message, doExport
|
|
17
17
|
} = useCrud(entity);
|
|
18
18
|
|
|
19
|
+
onBeforeMount(() => {
|
|
20
|
+
resetCrudStore()
|
|
21
|
+
})
|
|
22
|
+
|
|
19
23
|
</script>
|
|
20
24
|
|
|
21
25
|
<template>
|
|
@@ -27,6 +31,7 @@ const {
|
|
|
27
31
|
@create="onCreate"
|
|
28
32
|
@edit="onEdit"
|
|
29
33
|
@delete="onDelete"
|
|
34
|
+
@export="doExport"
|
|
30
35
|
>
|
|
31
36
|
<template v-for="header in entity.headers" :key="header.key" v-slot:[`item.${header.key}`]="{item, value}">
|
|
32
37
|
<slot :name="`item.${header.key}`" v-bind="{item, value}">
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import {debounce} from "@drax/common-front"
|
|
3
|
-
import type
|
|
3
|
+
import { type PropType, type Ref} from "vue";
|
|
4
4
|
import {ref, onBeforeMount} from "vue";
|
|
5
|
-
import
|
|
6
|
-
import type {ICrudField} from "@/interfaces/IEntityCrud";
|
|
5
|
+
import type {IEntityCrud, IEntityCrudField} from "@drax/crud-share";
|
|
7
6
|
|
|
8
|
-
const valueModel = defineModel({type: [String, Array], required: false})
|
|
7
|
+
const valueModel = defineModel<string | string[]>({type: [String, Array], required: false})
|
|
9
8
|
|
|
10
9
|
const {entity, multiple} = defineProps({
|
|
11
|
-
entity: {type: Object as PropType<
|
|
12
|
-
field: {type: Object as PropType<
|
|
10
|
+
entity: {type: Object as PropType<IEntityCrud|undefined>, required: true},
|
|
11
|
+
field: {type: Object as PropType<IEntityCrudField>, required: true},
|
|
13
12
|
multiple: {type: Boolean, default: false},
|
|
14
13
|
chips: {type: Boolean, default: false},
|
|
15
14
|
closableChips: {type: Boolean, default: true},
|
|
@@ -17,10 +16,14 @@ const {entity, multiple} = defineProps({
|
|
|
17
16
|
label: {type: String},
|
|
18
17
|
itemValue: {type: [String], default: '_id'},
|
|
19
18
|
itemTitle: {type: [String], default: 'name'},
|
|
20
|
-
rules: {type: Array<
|
|
19
|
+
rules: {type: Array as PropType<any>, default: []},
|
|
21
20
|
errorMessages: {type: Array as PropType<string[]>, default: []},
|
|
22
21
|
})
|
|
23
22
|
|
|
23
|
+
if(!entity){
|
|
24
|
+
throw new Error('entity is required')
|
|
25
|
+
}
|
|
26
|
+
|
|
24
27
|
const loading: Ref<boolean> = ref(false)
|
|
25
28
|
const items: Ref<Array<any>> = ref([])
|
|
26
29
|
|
|
@@ -28,19 +31,33 @@ const debouncedSearch = debounce(search, 300)
|
|
|
28
31
|
|
|
29
32
|
onBeforeMount(async () => {
|
|
30
33
|
if(valueModel.value && valueModel.value.length > 0){
|
|
34
|
+
|
|
31
35
|
if(multiple && Array.isArray(valueModel.value) ){
|
|
32
36
|
items.value = valueModel.value
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
|
|
38
|
+
// valueModel.value = valueModel.value.map((item:any) => item._id)
|
|
39
|
+
await findByIds(valueModel.value)
|
|
40
|
+
}else if(!Array.isArray(valueModel.value)){
|
|
41
|
+
// items.value = [valueModel.value]
|
|
42
|
+
await findByIds([valueModel.value])
|
|
37
43
|
}
|
|
38
44
|
|
|
45
|
+
|
|
46
|
+
|
|
39
47
|
}
|
|
40
48
|
})
|
|
41
49
|
|
|
42
|
-
async function findByIds(ids: Array<string>) {
|
|
50
|
+
async function findByIds(ids: Array<string> = []) {
|
|
43
51
|
try{
|
|
52
|
+
if(!entity){
|
|
53
|
+
throw new Error('Entity is required')
|
|
54
|
+
}
|
|
55
|
+
if(!entity.provider){
|
|
56
|
+
throw new Error('Provider is not defined')
|
|
57
|
+
}
|
|
58
|
+
if (typeof entity.provider.findByIds !== 'function') {
|
|
59
|
+
throw new Error('Provider does not have a findByIds method');
|
|
60
|
+
}
|
|
44
61
|
loading.value = true
|
|
45
62
|
items.value = await entity.provider.findByIds(ids)
|
|
46
63
|
}catch (e){
|
|
@@ -51,11 +68,12 @@ async function findByIds(ids: Array<string>) {
|
|
|
51
68
|
}
|
|
52
69
|
|
|
53
70
|
|
|
54
|
-
|
|
55
|
-
|
|
56
71
|
async function search(value: any) {
|
|
57
72
|
try{
|
|
58
73
|
loading.value = true
|
|
74
|
+
if(!entity){
|
|
75
|
+
throw new Error('Entity is required')
|
|
76
|
+
}
|
|
59
77
|
if(!entity.provider.search){
|
|
60
78
|
throw new Error('Provider does not have a search method')
|
|
61
79
|
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type {TOperation} from "../interfaces/TOperation";
|
|
3
3
|
import type {PropType} from "vue";
|
|
4
|
-
import
|
|
4
|
+
import type {IEntityCrud} from "@drax/crud-share";
|
|
5
5
|
const dialog = defineModel({type: Boolean, default: false})
|
|
6
|
+
import {useI18n} from "vue-i18n";
|
|
7
|
+
const {t,te} = useI18n()
|
|
6
8
|
|
|
7
9
|
defineProps({
|
|
8
|
-
entity: {type: Object as PropType<
|
|
10
|
+
entity: {type: Object as PropType<IEntityCrud>, required: true},
|
|
9
11
|
operation: {type: String as PropType<TOperation>}
|
|
10
12
|
})
|
|
11
13
|
|
|
@@ -19,7 +21,7 @@ defineEmits(
|
|
|
19
21
|
<v-dialog v-model="dialog" :fullscreen="entity.dialogFullscreen">
|
|
20
22
|
<v-card>
|
|
21
23
|
<v-toolbar>
|
|
22
|
-
<v-toolbar-title>{{entity.name}} {{
|
|
24
|
+
<v-toolbar-title>{{entity.name}} {{te('action.'+operation) ? t('action.'+operation) : operation}}</v-toolbar-title>
|
|
23
25
|
<v-spacer></v-spacer>
|
|
24
26
|
<v-btn icon @click="dialog = false"><v-icon>mdi-close</v-icon></v-btn>
|
|
25
27
|
</v-toolbar>
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import {useCrud} from "../composables/UseCrud";
|
|
3
|
+
import type {PropType} from "vue";
|
|
4
|
+
import type {IEntityCrud} from "@drax/crud-share";
|
|
5
|
+
import {useI18n} from "vue-i18n";
|
|
6
|
+
const {t} = useI18n()
|
|
7
|
+
const {entity} = defineProps({
|
|
8
|
+
entity: {type: Object as PropType<IEntityCrud>, required: true},
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
const {
|
|
12
|
+
exportFiles, exportListVisible, exportLoading
|
|
13
|
+
} = useCrud(entity);
|
|
14
|
+
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<template>
|
|
18
|
+
<v-card
|
|
19
|
+
v-if="exportListVisible"
|
|
20
|
+
:loading="exportLoading"
|
|
21
|
+
class="ma-3" density="compact" variant="outlined" color="secondary"
|
|
22
|
+
>
|
|
23
|
+
<v-card-title>
|
|
24
|
+
{{ t('action.exports') }}
|
|
25
|
+
|
|
26
|
+
</v-card-title>
|
|
27
|
+
<v-card-text>
|
|
28
|
+
<v-table density="compact">
|
|
29
|
+
<thead>
|
|
30
|
+
<tr>
|
|
31
|
+
<th>Link</th><th>Rows</th><th>Time</th>
|
|
32
|
+
</tr>
|
|
33
|
+
</thead>
|
|
34
|
+
<tbody>
|
|
35
|
+
<tr v-for="exportFile in exportFiles">
|
|
36
|
+
<td><a :href="exportFile.url" target="_blank">{{ exportFile.url }}</a></td>
|
|
37
|
+
<td>{{ exportFile.rowCount }}</td>
|
|
38
|
+
<td>{{ exportFile.time }}</td>
|
|
39
|
+
</tr>
|
|
40
|
+
</tbody>
|
|
41
|
+
</v-table>
|
|
42
|
+
|
|
43
|
+
</v-card-text>
|
|
44
|
+
|
|
45
|
+
<v-card-actions>
|
|
46
|
+
<v-spacer></v-spacer>
|
|
47
|
+
<v-btn @click="exportFiles = []" :loading="exportLoading">{{ t('action.clear') }}</v-btn>
|
|
48
|
+
<v-btn @click="exportListVisible=false">{{ t('action.close') }}</v-btn>
|
|
49
|
+
</v-card-actions>
|
|
50
|
+
</v-card>
|
|
51
|
+
</template>
|
|
52
|
+
|
|
53
|
+
<style scoped>
|
|
54
|
+
|
|
55
|
+
</style>
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type {PropType} from "vue";
|
|
3
3
|
import {ref} from "vue";
|
|
4
|
-
import EntityCrud from "../EntityCrud";
|
|
5
4
|
import CrudFormField from "./CrudFormField.vue";
|
|
6
5
|
import type {TOperation} from "../interfaces/TOperation";
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
import type {IEntityCrud} from "@drax/crud-share";
|
|
7
|
+
import {useI18n} from "vue-i18n";
|
|
8
|
+
import {useCrudStore} from "../stores/UseCrudStore";
|
|
9
|
+
const {t,te} = useI18n()
|
|
10
|
+
const store = useCrudStore()
|
|
9
11
|
const valueModel = defineModel({type: [Object]})
|
|
10
12
|
|
|
11
13
|
|
|
12
14
|
const {entity} = defineProps({
|
|
13
|
-
entity: {type: Object as PropType<
|
|
15
|
+
entity: {type: Object as PropType<IEntityCrud>, required: true},
|
|
14
16
|
operation: {type: String as PropType<TOperation>, required: true},
|
|
15
17
|
readonly: {type: Boolean, default: false},
|
|
16
18
|
error: {type: String, required: false},
|
|
@@ -19,10 +21,13 @@ const {entity} = defineProps({
|
|
|
19
21
|
const valid = ref()
|
|
20
22
|
const formRef = ref()
|
|
21
23
|
|
|
22
|
-
function submit() {
|
|
23
|
-
|
|
24
|
+
async function submit() {
|
|
25
|
+
store.resetErrors()
|
|
26
|
+
await formRef.value.validate()
|
|
24
27
|
if(valid.value) {
|
|
25
28
|
emit('submit',valueModel.value)
|
|
29
|
+
}else{
|
|
30
|
+
console.log('Invalid form')
|
|
26
31
|
}
|
|
27
32
|
}
|
|
28
33
|
|
|
@@ -37,8 +42,11 @@ const emit = defineEmits(['submit', 'cancel'])
|
|
|
37
42
|
<template>
|
|
38
43
|
<v-form v-model="valid" ref="formRef" @submit.prevent >
|
|
39
44
|
<v-card flat>
|
|
45
|
+
|
|
46
|
+
<v-card-subtitle v-if="valueModel._id">ID: {{valueModel._id}}</v-card-subtitle>
|
|
47
|
+
|
|
40
48
|
<v-card-text v-if="error">
|
|
41
|
-
<v-alert color="error">{{
|
|
49
|
+
<v-alert color="error">{{ te(error) ? t(error) : error }}</v-alert>
|
|
42
50
|
</v-card-text>
|
|
43
51
|
<v-card-text>
|
|
44
52
|
<template v-for="field in entity.fields" :key="field.name">
|
|
@@ -52,9 +60,9 @@ const emit = defineEmits(['submit', 'cancel'])
|
|
|
52
60
|
|
|
53
61
|
<v-card-actions>
|
|
54
62
|
<v-spacer></v-spacer>
|
|
55
|
-
<v-btn variant="text" color="grey" @click="cancel">{{
|
|
63
|
+
<v-btn variant="text" color="grey" @click="cancel">{{ t('action.cancel') }}</v-btn>
|
|
56
64
|
<v-btn variant="flat" color="primary" @click="submit">
|
|
57
|
-
{{ operation ?
|
|
65
|
+
{{ operation ? t('action.' + operation) : t('action.sent') }}
|
|
58
66
|
</v-btn>
|
|
59
67
|
</v-card-actions>
|
|
60
68
|
</v-card>
|
|
@@ -1,26 +1,29 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import {computed} from "vue";
|
|
3
3
|
import type {PropType} from "vue";
|
|
4
|
-
import type {ICrudField} from "../interfaces/IEntityCrud";
|
|
5
4
|
import CrudFormList from "./CrudFormList.vue";
|
|
6
5
|
import CrudAutocomplete from "./CrudAutocomplete.vue";
|
|
7
|
-
import EntityCrud from "@/EntityCrud";
|
|
8
6
|
import {useI18n} from "vue-i18n";
|
|
9
7
|
import {useCrudStore} from "../stores/UseCrudStore";
|
|
10
8
|
import {VDateInput} from 'vuetify/labs/VDateInput'
|
|
9
|
+
import type {IEntityCrud, IEntityCrudField} from "@drax/crud-share";
|
|
11
10
|
const {t, te} = useI18n()
|
|
12
11
|
|
|
13
12
|
const store = useCrudStore()
|
|
14
13
|
|
|
15
|
-
const valueModel = defineModel({type: [String, Number, Boolean, Object, Array], default: false})
|
|
14
|
+
const valueModel = defineModel<any>({type: [String, Number, Boolean, Object, Array], default: false})
|
|
16
15
|
|
|
17
16
|
const {index, entity, field} = defineProps({
|
|
18
|
-
entity: {type: Object as PropType<
|
|
19
|
-
field: {type: Object as PropType<
|
|
17
|
+
entity: {type: Object as PropType<IEntityCrud>, required: true},
|
|
18
|
+
field: {type: Object as PropType<IEntityCrudField|undefined>, required: true},
|
|
20
19
|
readonly: {type: Boolean, default: false},
|
|
21
20
|
index: {type: Number, default: 0},
|
|
22
21
|
})
|
|
23
22
|
|
|
23
|
+
if(!field){
|
|
24
|
+
throw new Error("CrudFormField must be provided with a field object")
|
|
25
|
+
}
|
|
26
|
+
|
|
24
27
|
const name = computed(() => index > 0 ? `${field.name}_${index}` : field.name)
|
|
25
28
|
|
|
26
29
|
const label = computed(() => {
|
|
@@ -29,7 +32,7 @@ const label = computed(() => {
|
|
|
29
32
|
})
|
|
30
33
|
|
|
31
34
|
const rules = computed(() => {
|
|
32
|
-
return entity.
|
|
35
|
+
return entity.getRule(field.name) as any
|
|
33
36
|
})
|
|
34
37
|
|
|
35
38
|
const inputErrors = computed(() =>
|
|
@@ -41,7 +44,6 @@ const inputErrors = computed(() =>
|
|
|
41
44
|
<template>
|
|
42
45
|
|
|
43
46
|
<div v-if="field && field.type">
|
|
44
|
-
|
|
45
47
|
<v-text-field
|
|
46
48
|
v-if="field.type === 'string'"
|
|
47
49
|
type="text"
|
|
@@ -93,7 +95,7 @@ const inputErrors = computed(() =>
|
|
|
93
95
|
|
|
94
96
|
<crud-autocomplete
|
|
95
97
|
v-if="field.type === 'ref'"
|
|
96
|
-
:entity="entity.getRef(field.ref)
|
|
98
|
+
:entity="entity.getRef(field.ref)"
|
|
97
99
|
:field="field"
|
|
98
100
|
v-model="valueModel"
|
|
99
101
|
:label="label"
|
|
@@ -133,7 +135,7 @@ const inputErrors = computed(() =>
|
|
|
133
135
|
|
|
134
136
|
<crud-autocomplete
|
|
135
137
|
v-if="field.type === 'array.ref'"
|
|
136
|
-
:entity="entity.getRef(field.ref)
|
|
138
|
+
:entity="entity.getRef(field.ref)"
|
|
137
139
|
:field="field"
|
|
138
140
|
v-model="valueModel"
|
|
139
141
|
:multiple="true"
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type {PropType} from "vue";
|
|
3
|
-
import type {ICrudField} from "../interfaces/IEntityCrud";
|
|
4
3
|
import CrudFormField from "./CrudFormField.vue";
|
|
5
|
-
import
|
|
4
|
+
import type {IEntityCrud, IEntityCrudField} from "@drax/crud-share";
|
|
6
5
|
|
|
7
6
|
const valueModel = defineModel({type: Array, default: () => []});
|
|
8
7
|
|
|
9
8
|
const {field} = defineProps({
|
|
10
|
-
entity: {type: Object as PropType<
|
|
11
|
-
field: {type: Object as PropType<
|
|
9
|
+
entity: {type: Object as PropType<IEntityCrud>, required: true},
|
|
10
|
+
field: {type: Object as PropType<IEntityCrudField>, required: true},
|
|
12
11
|
readonly: {type: Boolean, default: false},
|
|
13
12
|
})
|
|
14
13
|
|
|
@@ -16,7 +15,7 @@ function newItem() {
|
|
|
16
15
|
return field.objectFields ? field.objectFields.reduce((acc, field) => ({...acc, [field.name]: field.default }), {}) : []
|
|
17
16
|
}
|
|
18
17
|
|
|
19
|
-
function getField(key: string):
|
|
18
|
+
function getField(key: string):IEntityCrudField|undefined {
|
|
20
19
|
return field.objectFields ? field.objectFields.find(field => field.name === key) : undefined;
|
|
21
20
|
}
|
|
22
21
|
|
|
@@ -43,12 +42,12 @@ function removeItem(index: number) {
|
|
|
43
42
|
<v-col cols="12" v-for="(item,index) in valueModel" :key="index" class="text-right">
|
|
44
43
|
<v-row dense align="center">
|
|
45
44
|
<v-col cols="11">
|
|
46
|
-
<template v-for="key in Object.keys(item)" :key="key">
|
|
45
|
+
<template v-for="key in Object.keys(item as Record<string, any>)" :key="key">
|
|
47
46
|
<crud-form-field
|
|
48
47
|
v-if="hasField(key)"
|
|
49
48
|
:entity="entity"
|
|
50
49
|
:field="getField(key)"
|
|
51
|
-
v-model="valueModel[index][key]"
|
|
50
|
+
v-model="(valueModel[index] as any)[key]"
|
|
52
51
|
:readonly="readonly"
|
|
53
52
|
:index="index"
|
|
54
53
|
/>
|
|
@@ -1,24 +1,37 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type {PropType} from 'vue'
|
|
3
3
|
import {useAuth} from '@drax/identity-vue'
|
|
4
|
-
import EntityCrud from "../EntityCrud";
|
|
5
4
|
import CrudSearch from "./CrudSearch.vue";
|
|
6
5
|
import {useCrud} from "../composables/UseCrud";
|
|
6
|
+
import CrudExportButton from "./buttons/CrudExportButton.vue";
|
|
7
|
+
import CrudImportButton from "./buttons/CrudImportButton.vue";
|
|
8
|
+
import CrudCreateButton from "./buttons/CrudCreateButton.vue";
|
|
9
|
+
import CrudUpdateButton from "./buttons/CrudUpdateButton.vue";
|
|
10
|
+
import CrudDeleteButton from "./buttons/CrudDeleteButton.vue";
|
|
11
|
+
import CrudExportList from "./CrudExportList.vue";
|
|
12
|
+
import type {IEntityCrud} from "@drax/crud-share";
|
|
7
13
|
import {useI18n} from "vue-i18n";
|
|
8
|
-
|
|
14
|
+
import type {IEntityCrudHeader} from "@drax/crud-share";
|
|
15
|
+
|
|
16
|
+
const {t,te} = useI18n()
|
|
9
17
|
const {hasPermission} = useAuth()
|
|
10
18
|
|
|
11
19
|
const {entity} = defineProps({
|
|
12
|
-
entity: {type: Object as PropType<
|
|
20
|
+
entity: {type: Object as PropType<IEntityCrud>, required: true},
|
|
13
21
|
})
|
|
14
22
|
|
|
15
|
-
const {
|
|
16
|
-
|
|
23
|
+
const {
|
|
24
|
+
loading, itemsPerPage, page, sortBy, search, totalItems, items,
|
|
25
|
+
loadItems
|
|
26
|
+
} = useCrud(entity)
|
|
17
27
|
|
|
18
|
-
const actions = [{title: t('action.actions'),key:'actions', sortable: false, align: '
|
|
19
|
-
const tHeaders = entity.headers.map(header => ({
|
|
28
|
+
const actions: IEntityCrudHeader[] = [{title: t('action.actions'), key: 'actions', sortable: false, align: 'end', minWidth: '140px'}]
|
|
29
|
+
const tHeaders: IEntityCrudHeader[] = entity.headers.map(header => ({
|
|
30
|
+
...header,
|
|
31
|
+
title: te(`${entity.name.toLowerCase()}.fields.${header.title}`) ? t(`${entity.name.toLowerCase()}.fields.${header.title}`) : header.title
|
|
32
|
+
}))
|
|
20
33
|
|
|
21
|
-
const headers = [...tHeaders, ...actions]
|
|
34
|
+
const headers: IEntityCrudHeader[] = [...tHeaders, ...actions]
|
|
22
35
|
|
|
23
36
|
|
|
24
37
|
defineExpose({
|
|
@@ -29,29 +42,46 @@ defineExpose({
|
|
|
29
42
|
|
|
30
43
|
<template>
|
|
31
44
|
<v-data-table-server
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
45
|
+
class="border"
|
|
46
|
+
v-if="hasPermission(entity.permissions.view)"
|
|
47
|
+
v-model:items-per-page="itemsPerPage"
|
|
48
|
+
:items-per-page-options="[5, 10, 20, 50]"
|
|
49
|
+
v-model:page="page"
|
|
50
|
+
v-model:sort-by="sortBy"
|
|
51
|
+
:headers="headers"
|
|
52
|
+
:items="items"
|
|
53
|
+
:items-length="totalItems"
|
|
54
|
+
:loading="loading"
|
|
55
|
+
:search="search"
|
|
56
|
+
:multi-sort="false"
|
|
57
|
+
item-value="name"
|
|
58
|
+
@update:options="loadItems"
|
|
46
59
|
>
|
|
47
60
|
<template v-slot:top>
|
|
48
|
-
<v-toolbar density="compact"
|
|
61
|
+
<v-toolbar density="compact">
|
|
49
62
|
<v-toolbar-title>{{ entity.name }}</v-toolbar-title>
|
|
50
63
|
<v-spacer></v-spacer>
|
|
51
|
-
|
|
52
|
-
|
|
64
|
+
|
|
65
|
+
<crud-import-button
|
|
66
|
+
:entity="entity"
|
|
67
|
+
@import="v => $emit('import', v)"
|
|
68
|
+
/>
|
|
69
|
+
|
|
70
|
+
<crud-export-button
|
|
71
|
+
:entity="entity"
|
|
72
|
+
@export="v => $emit('export',v)"
|
|
73
|
+
/>
|
|
74
|
+
|
|
75
|
+
<crud-create-button
|
|
76
|
+
v-if="entity.isCreatable"
|
|
77
|
+
:entity="entity"
|
|
78
|
+
@click="$emit('create')"
|
|
79
|
+
/>
|
|
80
|
+
|
|
53
81
|
</v-toolbar>
|
|
54
82
|
|
|
83
|
+
<crud-export-list :entity="entity"></crud-export-list>
|
|
84
|
+
|
|
55
85
|
<v-card>
|
|
56
86
|
<v-card-text>
|
|
57
87
|
<crud-search v-model="search"></crud-search>
|
|
@@ -62,21 +92,21 @@ defineExpose({
|
|
|
62
92
|
|
|
63
93
|
|
|
64
94
|
<template v-for="header in entity.headers" :key="header.key" v-slot:[`item.${header.key}`]="{item, value}">
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
95
|
+
<slot :name="`item.${header.key}`" v-bind="{item, value}">
|
|
96
|
+
{{ value }}
|
|
97
|
+
</slot>
|
|
68
98
|
</template>
|
|
69
99
|
|
|
70
100
|
|
|
71
101
|
<template v-slot:item.actions="{item}">
|
|
72
|
-
<
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
<
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
102
|
+
<crud-update-button
|
|
103
|
+
v-if="entity.isEditable && hasPermission(entity.permissions.update)"
|
|
104
|
+
@click="$emit('edit', item)"
|
|
105
|
+
/>
|
|
106
|
+
<crud-delete-button
|
|
107
|
+
v-if="entity.isDeletable && hasPermission(entity.permissions.delete)"
|
|
108
|
+
@click="$emit('delete', item)"
|
|
109
|
+
/>
|
|
80
110
|
</template>
|
|
81
111
|
|
|
82
112
|
</v-data-table-server>
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import {useI18n} from "vue-i18n";
|
|
3
|
+
const {t} = useI18n()
|
|
2
4
|
const model = defineModel<any>()
|
|
3
5
|
</script>
|
|
4
6
|
|
|
@@ -7,7 +9,7 @@ const model = defineModel<any>()
|
|
|
7
9
|
density="compact" class="mr-2"
|
|
8
10
|
variant="outlined"
|
|
9
11
|
append-inner-icon="mdi-magnify"
|
|
10
|
-
:label="
|
|
12
|
+
:label="t('action.search')"
|
|
11
13
|
single-line clearable @click:clear="() => model = ''"
|
|
12
14
|
/>
|
|
13
15
|
</template>
|
|
@@ -0,0 +1,25 @@
|
|
|
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-plus"
|
|
13
|
+
class="mr-1"
|
|
14
|
+
variant="text"
|
|
15
|
+
color="primary"
|
|
16
|
+
>
|
|
17
|
+
</v-btn>
|
|
18
|
+
</template>
|
|
19
|
+
{{ t('action.create')}}
|
|
20
|
+
</v-tooltip>
|
|
21
|
+
</template>
|
|
22
|
+
|
|
23
|
+
<style scoped>
|
|
24
|
+
|
|
25
|
+
</style>
|
|
@@ -0,0 +1,25 @@
|
|
|
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-delete"
|
|
13
|
+
class="mr-1"
|
|
14
|
+
variant="text"
|
|
15
|
+
color="red"
|
|
16
|
+
>
|
|
17
|
+
</v-btn>
|
|
18
|
+
</template>
|
|
19
|
+
{{ t('action.delete')}}
|
|
20
|
+
</v-tooltip>
|
|
21
|
+
</template>
|
|
22
|
+
|
|
23
|
+
<style scoped>
|
|
24
|
+
|
|
25
|
+
</style>
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type {PropType} from "vue";
|
|
3
|
+
import type {IEntityCrud} from "@drax/crud-share"
|
|
4
|
+
import {useCrud} from "../../composables/UseCrud";
|
|
5
|
+
import {useI18n} from "vue-i18n";
|
|
6
|
+
|
|
7
|
+
const {t} = useI18n()
|
|
8
|
+
|
|
9
|
+
const {entity} = defineProps({
|
|
10
|
+
entity: {type: Object as PropType<IEntityCrud>, required: true},
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
const {
|
|
14
|
+
exportLoading
|
|
15
|
+
} = useCrud(entity)
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<template>
|
|
19
|
+
<v-menu v-if="entity.isExportable">
|
|
20
|
+
<template v-slot:activator="{ props: mp }">
|
|
21
|
+
<v-tooltip location="top">
|
|
22
|
+
<template v-slot:activator="{ props: tp }">
|
|
23
|
+
<v-btn
|
|
24
|
+
v-bind="{...mp, ...tp}"
|
|
25
|
+
:disabled="exportLoading"
|
|
26
|
+
class="mr-1"
|
|
27
|
+
color="teal"
|
|
28
|
+
variant="text"
|
|
29
|
+
:loading="exportLoading"
|
|
30
|
+
icon="mdi-database-export-outline"
|
|
31
|
+
></v-btn>
|
|
32
|
+
</template>
|
|
33
|
+
{{ t('action.export')}}
|
|
34
|
+
</v-tooltip>
|
|
35
|
+
|
|
36
|
+
</template>
|
|
37
|
+
<v-list>
|
|
38
|
+
<v-list-item v-for="format in entity.exportFormats" @click="$emit('export', format)">
|
|
39
|
+
<v-list-item-title>{{format}}</v-list-item-title>
|
|
40
|
+
</v-list-item>
|
|
41
|
+
</v-list>
|
|
42
|
+
|
|
43
|
+
</v-menu>
|
|
44
|
+
</template>
|
|
45
|
+
|
|
46
|
+
<style scoped>
|
|
47
|
+
|
|
48
|
+
</style>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type {PropType} from "vue";
|
|
3
|
+
import type {IEntityCrud} from "@drax/crud-share"
|
|
4
|
+
import {useCrud} from "../../composables/UseCrud";
|
|
5
|
+
import {useI18n} from "vue-i18n";
|
|
6
|
+
|
|
7
|
+
const {t} = useI18n()
|
|
8
|
+
const {entity} = defineProps({
|
|
9
|
+
entity: {type: Object as PropType<IEntityCrud>, required: true},
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
const {
|
|
13
|
+
exportLoading
|
|
14
|
+
} = useCrud(entity)
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<template>
|
|
18
|
+
<div v-if="entity.isImportable">
|
|
19
|
+
<v-tooltip location="top">
|
|
20
|
+
<template v-slot:activator="{ props }">
|
|
21
|
+
<v-btn
|
|
22
|
+
v-bind="props"
|
|
23
|
+
:disabled="exportLoading"
|
|
24
|
+
class="mr-1"
|
|
25
|
+
color="purple"
|
|
26
|
+
variant="text"
|
|
27
|
+
:loading="exportLoading"
|
|
28
|
+
icon="mdi-database-import-outline"
|
|
29
|
+
></v-btn>
|
|
30
|
+
</template>
|
|
31
|
+
{{ t('action.import')}}
|
|
32
|
+
</v-tooltip>
|
|
33
|
+
|
|
34
|
+
</div>
|
|
35
|
+
</template>
|
|
36
|
+
|
|
37
|
+
<style scoped>
|
|
38
|
+
|
|
39
|
+
</style>
|
|
@@ -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-pencil"
|
|
12
|
+
class="mr-1"
|
|
13
|
+
variant="text"
|
|
14
|
+
color="primary"
|
|
15
|
+
slim
|
|
16
|
+
>
|
|
17
|
+
</v-btn>
|
|
18
|
+
</template>
|
|
19
|
+
{{ t('action.update')}}
|
|
20
|
+
</v-tooltip>
|
|
21
|
+
</template>
|
|
22
|
+
|
|
23
|
+
<style scoped>
|
|
24
|
+
|
|
25
|
+
</style>
|
|
@@ -1,14 +1,12 @@
|
|
|
1
|
-
import
|
|
2
|
-
import type {IDraxPaginateResult} from "@drax/common-share";
|
|
1
|
+
import type {IDraxPaginateResult, IEntityCrud} from "@drax/crud-share";
|
|
3
2
|
import {useCrudStore} from "../stores/UseCrudStore";
|
|
4
3
|
import {computed} from "vue";
|
|
5
|
-
import type {ICrudField} from "@/interfaces/IEntityCrud";
|
|
6
4
|
|
|
7
|
-
export function useCrud(entity:
|
|
5
|
+
export function useCrud(entity: IEntityCrud) {
|
|
8
6
|
|
|
9
7
|
const store = useCrudStore()
|
|
10
8
|
|
|
11
|
-
async function
|
|
9
|
+
async function doPaginate() {
|
|
12
10
|
store.setLoading(true)
|
|
13
11
|
try {
|
|
14
12
|
const r: IDraxPaginateResult<any> = await entity?.provider.paginate({
|
|
@@ -27,25 +25,68 @@ export function useCrud(entity: EntityCrud) {
|
|
|
27
25
|
}
|
|
28
26
|
}
|
|
29
27
|
|
|
30
|
-
function
|
|
28
|
+
async function doExport(format: 'JSON') {
|
|
29
|
+
store.setExportLoading(true)
|
|
30
|
+
store.setExportListVisible(true)
|
|
31
|
+
try {
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
.
|
|
34
|
-
|
|
35
|
-
item[field.name] = new Date(item[field.name])
|
|
36
|
-
}
|
|
37
|
-
})
|
|
33
|
+
if(!entity?.provider.export) {
|
|
34
|
+
throw new Error("provider.export not implemented")
|
|
35
|
+
}
|
|
38
36
|
|
|
39
|
-
|
|
37
|
+
const headers: string = entity.exportHeaders.join(',')
|
|
38
|
+
|
|
39
|
+
const r: any = await entity?.provider.export({
|
|
40
|
+
format: format,
|
|
41
|
+
headers: headers,
|
|
42
|
+
separator: ";",
|
|
43
|
+
orderBy: store.sortBy[0]?.key,
|
|
44
|
+
order: store.sortBy[0]?.order,
|
|
45
|
+
search: store.search
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
if(r && r.url) {
|
|
49
|
+
store.addExportFile(r)
|
|
50
|
+
store.showMessage("Export successful")
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return r
|
|
54
|
+
|
|
55
|
+
} catch (e) {
|
|
56
|
+
console.error("Error exporting csv", e)
|
|
57
|
+
} finally {
|
|
58
|
+
store.setExportLoading(false)
|
|
59
|
+
}
|
|
40
60
|
}
|
|
41
61
|
|
|
42
62
|
|
|
63
|
+
|
|
64
|
+
|
|
43
65
|
function onCreate() {
|
|
44
66
|
store.setOperation("create")
|
|
45
67
|
store.setForm(entity.form)
|
|
46
68
|
store.setDialog(true)
|
|
47
69
|
}
|
|
48
70
|
|
|
71
|
+
function cast(item: any){
|
|
72
|
+
entity.fields.filter(field => field.type === 'date')
|
|
73
|
+
.forEach(field => {
|
|
74
|
+
item[field.name] = new Date(item[field.name])
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
entity.fields.filter(field => field.type === 'ref')
|
|
78
|
+
.forEach(field => {
|
|
79
|
+
item[field.name] = item[field.name]._id
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
entity.fields.filter(field => field.type === 'array.ref')
|
|
83
|
+
.forEach(field => {
|
|
84
|
+
item[field.name] = item[field.name].map(((i:any) => i._id))
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
return item
|
|
88
|
+
}
|
|
89
|
+
|
|
49
90
|
function onEdit(item: object) {
|
|
50
91
|
store.setOperation("edit")
|
|
51
92
|
store.setForm(cast({...item}))
|
|
@@ -65,7 +106,6 @@ export function useCrud(entity: EntityCrud) {
|
|
|
65
106
|
}
|
|
66
107
|
|
|
67
108
|
function onSubmit(formData: any) {
|
|
68
|
-
console.log("formData", formData)
|
|
69
109
|
store.setInputErrors(null)
|
|
70
110
|
switch (store.operation) {
|
|
71
111
|
case "create":
|
|
@@ -83,7 +123,7 @@ export function useCrud(entity: EntityCrud) {
|
|
|
83
123
|
async function doCreate(formData: any) {
|
|
84
124
|
try {
|
|
85
125
|
await entity?.provider.create(formData)
|
|
86
|
-
await
|
|
126
|
+
await doPaginate()
|
|
87
127
|
store.setDialog(false)
|
|
88
128
|
store.showMessage("Entity created successfully!")
|
|
89
129
|
} catch (e: any) {
|
|
@@ -99,7 +139,7 @@ export function useCrud(entity: EntityCrud) {
|
|
|
99
139
|
async function doUpdate(formData: any) {
|
|
100
140
|
try {
|
|
101
141
|
await entity?.provider.update(formData._id, formData)
|
|
102
|
-
await
|
|
142
|
+
await doPaginate()
|
|
103
143
|
store.setDialog(false)
|
|
104
144
|
store.showMessage("Entity updated successfully!")
|
|
105
145
|
} catch (e: any) {
|
|
@@ -116,7 +156,7 @@ export function useCrud(entity: EntityCrud) {
|
|
|
116
156
|
async function doDelete(formData: any) {
|
|
117
157
|
try {
|
|
118
158
|
await entity?.provider.delete(formData._id)
|
|
119
|
-
await
|
|
159
|
+
await doPaginate()
|
|
120
160
|
store.setDialog(false)
|
|
121
161
|
store.showMessage("Entity deleted successfully!")
|
|
122
162
|
} catch (e: any) {
|
|
@@ -126,6 +166,10 @@ export function useCrud(entity: EntityCrud) {
|
|
|
126
166
|
|
|
127
167
|
}
|
|
128
168
|
|
|
169
|
+
function resetCrudStore(){
|
|
170
|
+
store.$reset()
|
|
171
|
+
}
|
|
172
|
+
|
|
129
173
|
const dialog = computed({get(){return store.dialog} , set(value){store.setDialog(value)}})
|
|
130
174
|
const operation = computed({get(){return store.operation} , set(value){store.setOperation(value)}})
|
|
131
175
|
const form = computed({get(){return store.form} , set(value){store.setForm(value)}})
|
|
@@ -140,11 +184,15 @@ export function useCrud(entity: EntityCrud) {
|
|
|
140
184
|
const search = computed({get(){return store.search} , set(value){store.setSearch(value)}})
|
|
141
185
|
const totalItems = computed({get(){return store.totalItems} , set(value){store.setTotalItems(value)}})
|
|
142
186
|
const items = computed({get(){return store.items} , set(value){store.setItems(value)}})
|
|
187
|
+
const exportFiles = computed({get(){return store.exportFiles} , set(value){store.setExportFiles(value)}})
|
|
188
|
+
const exportLoading = computed({get(){return store.exportLoading} , set(value){store.setExportLoading(value)}})
|
|
189
|
+
const exportListVisible = computed({get(){return store.exportListVisible} , set(value){store.setExportListVisible(value)}})
|
|
143
190
|
|
|
144
191
|
return {
|
|
145
|
-
loadItems, onCreate, onEdit, onDelete, onCancel, onSubmit,
|
|
146
|
-
operation, dialog, form, notify, error, message,
|
|
147
|
-
loading, itemsPerPage, page, sortBy, search, totalItems, items
|
|
192
|
+
loadItems: doPaginate, doExport, onCreate, onEdit, onDelete, onCancel, onSubmit,resetCrudStore,
|
|
193
|
+
operation, dialog, form, notify, error, message, formValid,
|
|
194
|
+
loading, itemsPerPage, page, sortBy, search, totalItems, items,
|
|
195
|
+
exportFiles,exportLoading,exportListVisible
|
|
148
196
|
}
|
|
149
197
|
|
|
150
198
|
}
|
package/src/index.ts
CHANGED
|
@@ -10,8 +10,6 @@ import {useCrudStore} from "./stores/UseCrudStore";
|
|
|
10
10
|
import {useCrud} from "./composables/UseCrud";
|
|
11
11
|
import {EntityCrud} from "./EntityCrud";
|
|
12
12
|
|
|
13
|
-
import type {IFields, ICrudForm, ICrudHeaders, ICrudPermissions, ICrudRules} from "./interfaces/IEntityCrud";
|
|
14
|
-
export type {IFields, ICrudForm, ICrudHeaders, ICrudPermissions, ICrudRules}
|
|
15
13
|
|
|
16
14
|
export {
|
|
17
15
|
Crud,
|
|
@@ -9,8 +9,8 @@ export const useCrudStore = defineStore('CrudStore', {
|
|
|
9
9
|
form: {} as any,
|
|
10
10
|
formValid: {} as any,
|
|
11
11
|
notify: false as boolean,
|
|
12
|
-
error: '' as string,
|
|
13
12
|
message: '' as string,
|
|
13
|
+
error: '' as string,
|
|
14
14
|
items: [] as any[],
|
|
15
15
|
totalItems: 0 as number,
|
|
16
16
|
itemsPerPage: 5 as number,
|
|
@@ -18,7 +18,10 @@ export const useCrudStore = defineStore('CrudStore', {
|
|
|
18
18
|
search: '' as string,
|
|
19
19
|
sortBy: [] as any[],
|
|
20
20
|
loading: false,
|
|
21
|
-
inputErrors: null
|
|
21
|
+
inputErrors: null,
|
|
22
|
+
exportLoading: false,
|
|
23
|
+
exportFiles: [] as string[],
|
|
24
|
+
exportListVisible: false,
|
|
22
25
|
}
|
|
23
26
|
),
|
|
24
27
|
getters:{
|
|
@@ -80,6 +83,22 @@ export const useCrudStore = defineStore('CrudStore', {
|
|
|
80
83
|
},
|
|
81
84
|
setInputErrors(inputErrors: any) {
|
|
82
85
|
this.inputErrors = inputErrors
|
|
86
|
+
},
|
|
87
|
+
resetErrors(){
|
|
88
|
+
this.inputErrors = null
|
|
89
|
+
this.error = ''
|
|
90
|
+
},
|
|
91
|
+
setExportFiles(exportFiles: string[]) {
|
|
92
|
+
this.exportFiles = exportFiles
|
|
93
|
+
},
|
|
94
|
+
addExportFile(exportFile: string) {
|
|
95
|
+
this.exportFiles.push(exportFile)
|
|
96
|
+
},
|
|
97
|
+
setExportLoading(exportLoading: boolean) {
|
|
98
|
+
this.exportLoading = exportLoading
|
|
99
|
+
},
|
|
100
|
+
setExportListVisible(exportListVisible: boolean) {
|
|
101
|
+
this.exportListVisible = exportListVisible
|
|
83
102
|
}
|
|
84
103
|
}
|
|
85
104
|
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
interface ICrudHeaders {
|
|
2
|
-
title: string
|
|
3
|
-
key: string
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
interface ICrudRules {
|
|
7
|
-
[key: string]: Array<Function>
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
interface ICrudField {
|
|
11
|
-
name: string
|
|
12
|
-
type: 'string' | 'number' | 'boolean' | 'date' | 'object' | 'ref' | 'array.string' | 'array.number' | 'array.object' | 'array.ref'
|
|
13
|
-
ref?: string
|
|
14
|
-
objectFields?: ICrudField[]
|
|
15
|
-
label: string,
|
|
16
|
-
default: any
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
interface ICrudForm {
|
|
20
|
-
[key: string]: string | number | boolean | Date | null
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
type IFields = ICrudField[]
|
|
24
|
-
|
|
25
|
-
interface ICrudPermissions {
|
|
26
|
-
manage: string
|
|
27
|
-
view: string
|
|
28
|
-
create: string
|
|
29
|
-
update: string
|
|
30
|
-
delete: string
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export type {ICrudHeaders, ICrudRules, ICrudField, IFields, ICrudForm, ICrudPermissions}
|