@ramathibodi/nuxt-commons 0.1.11 → 0.1.13
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/dist/module.json +1 -1
- package/dist/runtime/components/TabsGroup.vue +12 -8
- package/dist/runtime/components/form/Birthdate.vue +199 -0
- package/dist/runtime/components/form/CodeEditor.vue +3 -3
- package/dist/runtime/components/form/Dialog.vue +3 -2
- package/dist/runtime/components/form/Pad.vue +31 -9
- package/dist/runtime/components/form/Table.vue +4 -4
- package/dist/runtime/components/master/Combobox.vue +29 -25
- package/dist/runtime/components/master/RadioGroup.vue +40 -30
- package/dist/runtime/components/master/Select.vue +34 -23
- package/dist/runtime/components/model/Pad.vue +122 -0
- package/dist/runtime/components/model/Table.vue +126 -103
- package/dist/runtime/components/model/iterator.vue +312 -0
- package/dist/runtime/composables/graphql.mjs +1 -1
- package/dist/runtime/composables/graphqlModel.d.ts +5 -18
- package/dist/runtime/composables/graphqlModel.mjs +16 -86
- package/dist/runtime/composables/graphqlModelItem.d.ts +20 -0
- package/dist/runtime/composables/graphqlModelItem.mjs +103 -0
- package/dist/runtime/composables/graphqlModelOperation.d.ts +21 -0
- package/dist/runtime/composables/graphqlModelOperation.mjs +77 -0
- package/dist/runtime/composables/graphqlOperation.d.ts +2 -2
- package/dist/runtime/composables/graphqlOperation.mjs +9 -9
- package/dist/runtime/types/formDialog.d.ts +3 -3
- package/dist/runtime/types/graphqlOperation.d.ts +14 -14
- package/package.json +1 -1
- package/scripts/postInstall.cjs +38 -35
- package/templates/.codegen/codegen.ts +8 -8
- package/templates/.codegen/plugin-schema-object.js +103 -97
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import {computed, nextTick, ref, useAttrs, watch} from 'vue'
|
|
3
|
+
import {VDataIterator} from 'vuetify/components/VDataIterator'
|
|
4
|
+
import {omit} from 'lodash-es'
|
|
5
|
+
import type {GraphqlModelProps} from '../../composables/graphqlModel'
|
|
6
|
+
import {useGraphqlModel} from '../../composables/graphqlModel'
|
|
7
|
+
|
|
8
|
+
defineOptions({
|
|
9
|
+
inheritAttrs: false,
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
interface Props extends /* @vue-ignore */ InstanceType<typeof VDataIterator['$props']> {
|
|
13
|
+
title: string
|
|
14
|
+
noDataText?: string
|
|
15
|
+
dialogFullscreen?: boolean
|
|
16
|
+
initialData?: Record<string, any>
|
|
17
|
+
toolbarColor?: string
|
|
18
|
+
importable?: boolean
|
|
19
|
+
exportable?: boolean
|
|
20
|
+
cols?: string | number | boolean
|
|
21
|
+
xxl?: string | number | boolean
|
|
22
|
+
xl?: string | number | boolean
|
|
23
|
+
lg?: string | number | boolean
|
|
24
|
+
md?: string | number | boolean
|
|
25
|
+
sm?: string | number | boolean
|
|
26
|
+
itemsPerPage?: string | number
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const props = withDefaults(defineProps<Props & GraphqlModelProps>(), {
|
|
30
|
+
noDataText: 'ไม่พบข้อมูล',
|
|
31
|
+
dialogFullscreen: false,
|
|
32
|
+
toolbarColor: 'primary',
|
|
33
|
+
importable: false,
|
|
34
|
+
exportable: false,
|
|
35
|
+
modelKey: 'id',
|
|
36
|
+
modelBy: undefined,
|
|
37
|
+
fields: () => [],
|
|
38
|
+
cols: 12,
|
|
39
|
+
xxl: false,
|
|
40
|
+
xl: false,
|
|
41
|
+
lg: false,
|
|
42
|
+
md: 2,
|
|
43
|
+
sm: 6,
|
|
44
|
+
itemsPerPage: 12,
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
const attrs = useAttrs()
|
|
48
|
+
const plainAttrs = computed(() => {
|
|
49
|
+
const returnAttrs = omit(attrs, ['modelValue', 'onUpdate:modelValue'])
|
|
50
|
+
if (props.headers) returnAttrs['headers'] = props.headers
|
|
51
|
+
return returnAttrs
|
|
52
|
+
})
|
|
53
|
+
const currentItem = ref<Record<string, any> | undefined>(undefined)
|
|
54
|
+
const isDialogOpen = ref<boolean>(false)
|
|
55
|
+
|
|
56
|
+
const { items, itemsLength,
|
|
57
|
+
search, currentOptions,
|
|
58
|
+
canServerPageable, canServerSearch, canCreate, canUpdate, canDelete,
|
|
59
|
+
createItem, importItems, updateItem, deleteItem,
|
|
60
|
+
loadItems, reload,
|
|
61
|
+
isLoading } = useGraphqlModel(props)
|
|
62
|
+
|
|
63
|
+
function openDialog(item?: object) {
|
|
64
|
+
currentItem.value = item
|
|
65
|
+
nextTick(() => {
|
|
66
|
+
isDialogOpen.value = true
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const itemsPerPageInternal = ref<string | number>()
|
|
71
|
+
watch(() => props.itemsPerPage, (newValue) => {
|
|
72
|
+
if (newValue.toString().toLowerCase() == 'all') itemsPerPageInternal.value = '-1'
|
|
73
|
+
else if (newValue) itemsPerPageInternal.value = newValue
|
|
74
|
+
}, { immediate: true })
|
|
75
|
+
|
|
76
|
+
type SortItem = { key: string, order?: boolean | 'asc' | 'desc' }
|
|
77
|
+
const sortBy = ref<SortItem[]>()
|
|
78
|
+
|
|
79
|
+
const pageCount = computed(() => {
|
|
80
|
+
if (itemsPerPageInternal.value == 'All' || itemsPerPageInternal.value == '-1' || itemsPerPageInternal.value <= 0 || !itemsPerPageInternal.value) return 1
|
|
81
|
+
else return Math.ceil(itemsLength.value / Number(itemsPerPageInternal.value))
|
|
82
|
+
})
|
|
83
|
+
const currentPage = ref<number>(1)
|
|
84
|
+
|
|
85
|
+
watch([currentPage, itemsPerPageInternal, sortBy], () => {
|
|
86
|
+
if (canServerPageable.value) {
|
|
87
|
+
loadItems({
|
|
88
|
+
page: currentPage.value,
|
|
89
|
+
itemsPerPage: (itemsPerPageInternal.value == 'All' || itemsPerPageInternal.value <= 0) ? '-1' : itemsPerPageInternal.value,
|
|
90
|
+
sortBy: sortBy.value,
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
}, { immediate: true })
|
|
94
|
+
|
|
95
|
+
const operation = ref({ openDialog, createItem, importItems, updateItem, deleteItem, reload, canServerPageable, canServerSearch, canCreate, canUpdate, canDelete })
|
|
96
|
+
|
|
97
|
+
const computedInitialData = computed(() => {
|
|
98
|
+
return Object.assign({}, props.initialData, props.modelBy)
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
const computedSkeletonPerPage = computed(() => {
|
|
102
|
+
if (itemsPerPageInternal.value == 'All' || itemsPerPageInternal.value <= 0) return 1
|
|
103
|
+
else return Number(itemsPerPageInternal.value)
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
defineExpose({ reload })
|
|
107
|
+
</script>
|
|
108
|
+
|
|
109
|
+
<template>
|
|
110
|
+
<v-card>
|
|
111
|
+
<v-data-iterator
|
|
112
|
+
v-bind="plainAttrs"
|
|
113
|
+
v-model:items-per-page="itemsPerPageInternal"
|
|
114
|
+
v-model:sort-by="sortBy"
|
|
115
|
+
:items="items"
|
|
116
|
+
:item-value="modelKey"
|
|
117
|
+
:search="search"
|
|
118
|
+
:loading="isLoading"
|
|
119
|
+
>
|
|
120
|
+
<template #default="defaultProps">
|
|
121
|
+
<slot
|
|
122
|
+
v-bind="defaultProps"
|
|
123
|
+
:operation="operation"
|
|
124
|
+
>
|
|
125
|
+
<v-container fluid>
|
|
126
|
+
<v-row>
|
|
127
|
+
<v-col
|
|
128
|
+
v-for="(item, index) in defaultProps.items"
|
|
129
|
+
:key="index"
|
|
130
|
+
:cols="cols"
|
|
131
|
+
:sm="sm"
|
|
132
|
+
:md="md"
|
|
133
|
+
:lg="lg"
|
|
134
|
+
:xl="xl"
|
|
135
|
+
:xxl="xxl"
|
|
136
|
+
>
|
|
137
|
+
<slot
|
|
138
|
+
name="item"
|
|
139
|
+
:item="item"
|
|
140
|
+
:operation="operation"
|
|
141
|
+
/>
|
|
142
|
+
</v-col>
|
|
143
|
+
</v-row>
|
|
144
|
+
</v-container>
|
|
145
|
+
</slot>
|
|
146
|
+
</template>
|
|
147
|
+
<template #loader="loaderProps">
|
|
148
|
+
<slot
|
|
149
|
+
name="loader"
|
|
150
|
+
v-bind="loaderProps"
|
|
151
|
+
>
|
|
152
|
+
<v-container fluid>
|
|
153
|
+
<v-row>
|
|
154
|
+
<v-col
|
|
155
|
+
v-for="key in computedSkeletonPerPage"
|
|
156
|
+
:key="key"
|
|
157
|
+
:cols="cols"
|
|
158
|
+
:sm="sm"
|
|
159
|
+
:md="md"
|
|
160
|
+
:lg="lg"
|
|
161
|
+
:xl="xl"
|
|
162
|
+
:xxl="xxl"
|
|
163
|
+
>
|
|
164
|
+
<slot name="loaderItem">
|
|
165
|
+
<v-skeleton-loader
|
|
166
|
+
type="paragraph"
|
|
167
|
+
/>
|
|
168
|
+
</slot>
|
|
169
|
+
</v-col>
|
|
170
|
+
</v-row>
|
|
171
|
+
</v-container>
|
|
172
|
+
</slot>
|
|
173
|
+
</template>
|
|
174
|
+
<template #header="headerProps">
|
|
175
|
+
<slot
|
|
176
|
+
name="header"
|
|
177
|
+
v-bind="headerProps"
|
|
178
|
+
:items="items"
|
|
179
|
+
:search="search"
|
|
180
|
+
:operation="operation"
|
|
181
|
+
>
|
|
182
|
+
<VToolbar :color="toolbarColor">
|
|
183
|
+
<v-row
|
|
184
|
+
justify="end"
|
|
185
|
+
class="ma-1"
|
|
186
|
+
dense
|
|
187
|
+
no-gutters
|
|
188
|
+
align="center"
|
|
189
|
+
>
|
|
190
|
+
<v-col cols="7">
|
|
191
|
+
<VToolbarTitle class="pl-3">
|
|
192
|
+
<slot
|
|
193
|
+
name="title"
|
|
194
|
+
:reload="reload"
|
|
195
|
+
>
|
|
196
|
+
{{ title }}
|
|
197
|
+
<v-icon
|
|
198
|
+
size="small"
|
|
199
|
+
@click="reload"
|
|
200
|
+
>
|
|
201
|
+
mdi mdi-refresh
|
|
202
|
+
</v-icon>
|
|
203
|
+
</slot>
|
|
204
|
+
</VToolbarTitle>
|
|
205
|
+
</v-col>
|
|
206
|
+
<v-col cols="5">
|
|
207
|
+
<slot name="search">
|
|
208
|
+
<VTextField
|
|
209
|
+
v-model="search"
|
|
210
|
+
class="justify-end w-100"
|
|
211
|
+
density="compact"
|
|
212
|
+
hide-details
|
|
213
|
+
placeholder="ค้นหา"
|
|
214
|
+
clearable
|
|
215
|
+
variant="solo"
|
|
216
|
+
/>
|
|
217
|
+
</slot>
|
|
218
|
+
</v-col>
|
|
219
|
+
</v-row>
|
|
220
|
+
|
|
221
|
+
<VToolbarItems>
|
|
222
|
+
<slot name="toolbarItems" />
|
|
223
|
+
<ImportCSV
|
|
224
|
+
v-if="props.importable"
|
|
225
|
+
icon="mdi mdi-file-upload"
|
|
226
|
+
variant="flat"
|
|
227
|
+
@import="importItems"
|
|
228
|
+
/>
|
|
229
|
+
<ExportCSV
|
|
230
|
+
v-if="props.exportable && items.length"
|
|
231
|
+
icon="mdi mdi-file-download"
|
|
232
|
+
variant="flat"
|
|
233
|
+
:file-name="title"
|
|
234
|
+
:model-value="items"
|
|
235
|
+
/>
|
|
236
|
+
<VBtn
|
|
237
|
+
v-if="canCreate"
|
|
238
|
+
:color="toolbarColor"
|
|
239
|
+
prepend-icon="mdi mdi-plus"
|
|
240
|
+
variant="flat"
|
|
241
|
+
@click="openDialog()"
|
|
242
|
+
>
|
|
243
|
+
add
|
|
244
|
+
</VBtn>
|
|
245
|
+
</VToolbarItems>
|
|
246
|
+
</VToolbar>
|
|
247
|
+
</slot>
|
|
248
|
+
</template>
|
|
249
|
+
<template #footer="footerProps">
|
|
250
|
+
<v-container fluid>
|
|
251
|
+
<v-row
|
|
252
|
+
align-content="center"
|
|
253
|
+
justify="end"
|
|
254
|
+
dense
|
|
255
|
+
>
|
|
256
|
+
<v-spacer />
|
|
257
|
+
<v-select
|
|
258
|
+
v-model="itemsPerPageInternal"
|
|
259
|
+
density="compact"
|
|
260
|
+
variant="outlined"
|
|
261
|
+
:items="[6, 12, 18, 24, 30, { title: 'All', value: '-1' }]"
|
|
262
|
+
min-width="220"
|
|
263
|
+
max-width="220"
|
|
264
|
+
hide-details
|
|
265
|
+
>
|
|
266
|
+
<template #prepend>
|
|
267
|
+
Items per page:
|
|
268
|
+
</template>
|
|
269
|
+
</v-select>
|
|
270
|
+
<v-pagination
|
|
271
|
+
v-if="!canServerPageable"
|
|
272
|
+
v-model="currentPage"
|
|
273
|
+
density="compact"
|
|
274
|
+
:length="footerProps.pageCount"
|
|
275
|
+
total-visible="6"
|
|
276
|
+
show-first-last-page
|
|
277
|
+
@first="footerProps.setPage(1)"
|
|
278
|
+
@last="footerProps.setPage(footerProps.pageCount)"
|
|
279
|
+
@next="footerProps.nextPage"
|
|
280
|
+
@prev="footerProps.prevPage"
|
|
281
|
+
@update:model-value="footerProps.setPage"
|
|
282
|
+
/>
|
|
283
|
+
<v-pagination
|
|
284
|
+
v-else
|
|
285
|
+
v-model="currentPage"
|
|
286
|
+
density="compact"
|
|
287
|
+
:length="pageCount"
|
|
288
|
+
total-visible="6"
|
|
289
|
+
show-first-last-page
|
|
290
|
+
/>
|
|
291
|
+
</v-row>
|
|
292
|
+
</v-container>
|
|
293
|
+
</template>
|
|
294
|
+
</v-data-iterator>
|
|
295
|
+
<FormDialog
|
|
296
|
+
v-model="isDialogOpen"
|
|
297
|
+
:title="title"
|
|
298
|
+
:fullscreen="dialogFullscreen"
|
|
299
|
+
:initial-data="computedInitialData"
|
|
300
|
+
:form-data="currentItem"
|
|
301
|
+
@create="createItem"
|
|
302
|
+
@update="updateItem"
|
|
303
|
+
>
|
|
304
|
+
<template #default="slotData">
|
|
305
|
+
<slot
|
|
306
|
+
name="form"
|
|
307
|
+
v-bind="slotData"
|
|
308
|
+
/>
|
|
309
|
+
</template>
|
|
310
|
+
</FormDialog>
|
|
311
|
+
</v-card>
|
|
312
|
+
</template>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { mutation as gqlMutation, query as gqlQuery } from "gql-query-builder";
|
|
2
2
|
import { useQuery } from "@vue/apollo-composable";
|
|
3
3
|
import { classAttributes, isClassConstructor } from "../utils/object.mjs";
|
|
4
4
|
import { gql, useAsyncQuery, useMutation } from "#imports";
|
|
@@ -1,22 +1,10 @@
|
|
|
1
|
-
import type { FormDialogCallback } from
|
|
2
|
-
import type
|
|
1
|
+
import type { FormDialogCallback } from '../types/formDialog';
|
|
2
|
+
import { type GraphqlModelConfigProps } from './graphqlModelOperation';
|
|
3
3
|
export interface HeaderProps {
|
|
4
4
|
headers?: any[];
|
|
5
5
|
}
|
|
6
|
-
export
|
|
7
|
-
|
|
8
|
-
modelKey?: string;
|
|
9
|
-
modelBy?: object;
|
|
10
|
-
operationCreate?: graphqlOperationObject<any, any> | string;
|
|
11
|
-
operationUpdate?: graphqlOperationObject<any, any> | string;
|
|
12
|
-
operationDelete?: graphqlOperationObject<any, any> | string;
|
|
13
|
-
operationRead?: graphqlOperationObject<any, any> | string;
|
|
14
|
-
operationReadPageable?: graphqlOperationObject<any, any> | string;
|
|
15
|
-
operationSearch?: graphqlOperationObject<any, any> | string;
|
|
16
|
-
fields?: Array<string | object>;
|
|
17
|
-
}
|
|
18
|
-
type GraphqlModelPropsWithOptionalHeaders = GraphqlModelProps & Partial<HeaderProps>;
|
|
19
|
-
export declare function useGraphqlModel<T extends GraphqlModelPropsWithOptionalHeaders>(props: T): {
|
|
6
|
+
export type GraphqlModelProps = GraphqlModelConfigProps & Partial<HeaderProps>;
|
|
7
|
+
export declare function useGraphqlModel<T extends GraphqlModelProps>(props: T): {
|
|
20
8
|
items: import("vue").Ref<Record<string, any>[]>;
|
|
21
9
|
itemsLength: import("vue").Ref<number>;
|
|
22
10
|
search: import("vue").Ref<string | undefined>;
|
|
@@ -28,7 +16,7 @@ export declare function useGraphqlModel<T extends GraphqlModelPropsWithOptionalH
|
|
|
28
16
|
operationReadPageable: import("vue").ComputedRef<any>;
|
|
29
17
|
operationSearch: import("vue").ComputedRef<any>;
|
|
30
18
|
fields: import("vue").ComputedRef<any[]>;
|
|
31
|
-
canServerPageable: import("vue").ComputedRef<boolean
|
|
19
|
+
canServerPageable: import("vue").ComputedRef<boolean>;
|
|
32
20
|
canServerSearch: import("vue").ComputedRef<boolean>;
|
|
33
21
|
canCreate: import("vue").ComputedRef<boolean>;
|
|
34
22
|
canUpdate: import("vue").ComputedRef<boolean>;
|
|
@@ -41,4 +29,3 @@ export declare function useGraphqlModel<T extends GraphqlModelPropsWithOptionalH
|
|
|
41
29
|
reload: () => void;
|
|
42
30
|
isLoading: import("vue").Ref<boolean>;
|
|
43
31
|
};
|
|
44
|
-
export {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { computed, ref, watch } from "vue";
|
|
1
|
+
import { computed, onMounted, ref, watch } from "vue";
|
|
2
2
|
import { useAlert } from "./alert.mjs";
|
|
3
|
-
import { graphqlOperation } from "#imports";
|
|
4
3
|
import { buildRequiredInputFields } from "./graphqlOperation.mjs";
|
|
4
|
+
import { useGraphqlModelOperation } from "./graphqlModelOperation.mjs";
|
|
5
5
|
export function useGraphqlModel(props) {
|
|
6
6
|
const alert = useAlert();
|
|
7
7
|
const items = ref([]);
|
|
@@ -9,78 +9,7 @@ export function useGraphqlModel(props) {
|
|
|
9
9
|
const search = ref();
|
|
10
10
|
const currentOptions = ref();
|
|
11
11
|
const isLoading = ref(false);
|
|
12
|
-
|
|
13
|
-
return string?.charAt(0).toUpperCase() + string?.slice(1);
|
|
14
|
-
}
|
|
15
|
-
function lowercaseFirstLetter(string) {
|
|
16
|
-
return string?.charAt(0).toLowerCase() + string?.slice(1);
|
|
17
|
-
}
|
|
18
|
-
const operationCreate = computed(() => {
|
|
19
|
-
if (props.operationCreate) {
|
|
20
|
-
if (typeof props.operationCreate === "string") {
|
|
21
|
-
if (graphqlOperation[props.operationCreate])
|
|
22
|
-
return graphqlOperation[props.operationCreate];
|
|
23
|
-
} else {
|
|
24
|
-
return props.operationCreate;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
return graphqlOperation["create" + capitalizeFirstLetter(props.modelName)];
|
|
28
|
-
});
|
|
29
|
-
const operationUpdate = computed(() => {
|
|
30
|
-
if (props.operationUpdate) {
|
|
31
|
-
if (typeof props.operationUpdate === "string") {
|
|
32
|
-
if (graphqlOperation[props.operationUpdate])
|
|
33
|
-
return graphqlOperation[props.operationUpdate];
|
|
34
|
-
} else {
|
|
35
|
-
return props.operationUpdate;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
return graphqlOperation["update" + capitalizeFirstLetter(props.modelName)];
|
|
39
|
-
});
|
|
40
|
-
const operationDelete = computed(() => {
|
|
41
|
-
if (props.operationDelete) {
|
|
42
|
-
if (typeof props.operationDelete === "string") {
|
|
43
|
-
if (graphqlOperation[props.operationDelete])
|
|
44
|
-
return graphqlOperation[props.operationDelete];
|
|
45
|
-
} else {
|
|
46
|
-
return props.operationDelete;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
return graphqlOperation["delete" + capitalizeFirstLetter(props.modelName)];
|
|
50
|
-
});
|
|
51
|
-
const operationRead = computed(() => {
|
|
52
|
-
if (props.operationRead) {
|
|
53
|
-
if (typeof props.operationRead === "string") {
|
|
54
|
-
if (graphqlOperation[props.operationRead])
|
|
55
|
-
return graphqlOperation[props.operationRead];
|
|
56
|
-
} else {
|
|
57
|
-
return props.operationRead;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
return graphqlOperation[lowercaseFirstLetter(props.modelName)];
|
|
61
|
-
});
|
|
62
|
-
const operationReadPageable = computed(() => {
|
|
63
|
-
if (props.operationReadPageable) {
|
|
64
|
-
if (typeof props.operationReadPageable === "string") {
|
|
65
|
-
if (graphqlOperation[props.operationReadPageable])
|
|
66
|
-
return graphqlOperation[props.operationReadPageable];
|
|
67
|
-
} else {
|
|
68
|
-
return props.operationReadPageable;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
return graphqlOperation[lowercaseFirstLetter(props.modelName) + "Pageable"];
|
|
72
|
-
});
|
|
73
|
-
const operationSearch = computed(() => {
|
|
74
|
-
if (props.operationSearch) {
|
|
75
|
-
if (typeof props.operationSearch === "string") {
|
|
76
|
-
if (graphqlOperation[props.operationSearch])
|
|
77
|
-
return graphqlOperation[props.operationSearch];
|
|
78
|
-
} else {
|
|
79
|
-
return props.operationSearch;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
return graphqlOperation["search" + capitalizeFirstLetter(props.modelName)];
|
|
83
|
-
});
|
|
12
|
+
const { operationCreate, operationUpdate, operationDelete, operationRead, operationReadPageable, operationSearch } = useGraphqlModelOperation(props);
|
|
84
13
|
function keyToField(key) {
|
|
85
14
|
const parts = key.split(".");
|
|
86
15
|
if (parts.length > 1) {
|
|
@@ -102,8 +31,8 @@ export function useGraphqlModel(props) {
|
|
|
102
31
|
}
|
|
103
32
|
}
|
|
104
33
|
const fields = computed(() => {
|
|
105
|
-
|
|
106
|
-
|
|
34
|
+
const tmpFields = [];
|
|
35
|
+
const fieldsProps = props.fields || [];
|
|
107
36
|
let requiredInputFields = [];
|
|
108
37
|
if (props.headers && props.headers.length > 0) {
|
|
109
38
|
props.headers.forEach((header) => {
|
|
@@ -117,7 +46,7 @@ export function useGraphqlModel(props) {
|
|
|
117
46
|
return [.../* @__PURE__ */ new Set([...fieldsProps, ...tmpFields, ...requiredInputFields])];
|
|
118
47
|
});
|
|
119
48
|
const canServerPageable = computed(() => {
|
|
120
|
-
return !!operationReadPageable.value && (!search.value || search.value && canServerSearch.value);
|
|
49
|
+
return !!operationReadPageable.value && (!search.value || !!search.value && canServerSearch.value);
|
|
121
50
|
});
|
|
122
51
|
const canServerSearch = computed(() => {
|
|
123
52
|
return !!operationSearch.value;
|
|
@@ -150,9 +79,9 @@ export function useGraphqlModel(props) {
|
|
|
150
79
|
}
|
|
151
80
|
function importItems(importItems2, callback) {
|
|
152
81
|
isLoading.value = true;
|
|
153
|
-
|
|
82
|
+
const importPromise = [];
|
|
154
83
|
importItems2.forEach((item) => {
|
|
155
|
-
|
|
84
|
+
const eachPromise = createItem(item, void 0, true);
|
|
156
85
|
if (eachPromise)
|
|
157
86
|
importPromise.push(eachPromise);
|
|
158
87
|
});
|
|
@@ -169,7 +98,7 @@ export function useGraphqlModel(props) {
|
|
|
169
98
|
if (canServerPageable)
|
|
170
99
|
loadItems(currentOptions.value);
|
|
171
100
|
else {
|
|
172
|
-
|
|
101
|
+
const index = items.value.findIndex((item2) => item2[props.modelKey || "id"] === result[props.modelKey || "id"]);
|
|
173
102
|
if (index !== -1) {
|
|
174
103
|
items.value[index] = result;
|
|
175
104
|
}
|
|
@@ -196,7 +125,7 @@ export function useGraphqlModel(props) {
|
|
|
196
125
|
function loadItems(options) {
|
|
197
126
|
currentOptions.value = options;
|
|
198
127
|
if (canServerPageable) {
|
|
199
|
-
|
|
128
|
+
const pageableVariable = {
|
|
200
129
|
page: options.page,
|
|
201
130
|
perPage: options.itemsPerPage,
|
|
202
131
|
sortBy: options.sortBy
|
|
@@ -214,7 +143,8 @@ export function useGraphqlModel(props) {
|
|
|
214
143
|
}
|
|
215
144
|
function reload() {
|
|
216
145
|
if (canServerPageable.value) {
|
|
217
|
-
|
|
146
|
+
if (currentOptions.value)
|
|
147
|
+
loadItems(currentOptions.value);
|
|
218
148
|
} else {
|
|
219
149
|
isLoading.value = true;
|
|
220
150
|
operationRead.value?.call(fields.value, props.modelBy).then((result) => {
|
|
@@ -226,12 +156,12 @@ export function useGraphqlModel(props) {
|
|
|
226
156
|
});
|
|
227
157
|
}
|
|
228
158
|
}
|
|
229
|
-
watch(() => props.modelName, () => {
|
|
159
|
+
watch([() => props.modelName, () => props.modelBy, () => props.modelKey, canServerPageable], () => {
|
|
160
|
+
reload();
|
|
161
|
+
}, { deep: true });
|
|
162
|
+
onMounted(() => {
|
|
230
163
|
if (!canServerPageable.value)
|
|
231
164
|
reload();
|
|
232
|
-
}, { immediate: true });
|
|
233
|
-
watch(canServerPageable, () => {
|
|
234
|
-
reload();
|
|
235
165
|
});
|
|
236
166
|
return {
|
|
237
167
|
items,
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { FormDialogCallback } from '../types/formDialog';
|
|
2
|
+
import { type GraphqlModelConfigProps } from './graphqlModelOperation';
|
|
3
|
+
export type GraphqlModelItemProps = Omit<GraphqlModelConfigProps, 'operationSearch' | 'operationReadPageable'>;
|
|
4
|
+
export declare function useGraphqlModelItem<T extends GraphqlModelItemProps>(props: T): {
|
|
5
|
+
modelBy: import("vue").Ref<object | undefined>;
|
|
6
|
+
item: import("vue").Ref<Record<string, any> | undefined>;
|
|
7
|
+
operationCreate: import("vue").ComputedRef<any>;
|
|
8
|
+
operationUpdate: import("vue").ComputedRef<any>;
|
|
9
|
+
operationDelete: import("vue").ComputedRef<any>;
|
|
10
|
+
operationRead: import("vue").ComputedRef<any>;
|
|
11
|
+
fields: import("vue").ComputedRef<any[]>;
|
|
12
|
+
canCreate: import("vue").ComputedRef<boolean>;
|
|
13
|
+
canUpdate: import("vue").ComputedRef<boolean>;
|
|
14
|
+
canDelete: import("vue").ComputedRef<boolean>;
|
|
15
|
+
createItem: (createItem: Record<string, any>, callback?: FormDialogCallback) => any;
|
|
16
|
+
updateItem: (updateItem: Record<string, any>, callback?: FormDialogCallback) => any;
|
|
17
|
+
deleteItem: (item: Record<string, any>, callback?: FormDialogCallback) => any;
|
|
18
|
+
reload: () => void;
|
|
19
|
+
isLoading: import("vue").Ref<boolean>;
|
|
20
|
+
};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { computed, ref, watch } from "vue";
|
|
2
|
+
import { useAlert } from "./alert.mjs";
|
|
3
|
+
import { buildRequiredInputFields } from "./graphqlOperation.mjs";
|
|
4
|
+
import { useGraphqlModelOperation } from "./graphqlModelOperation.mjs";
|
|
5
|
+
export function useGraphqlModelItem(props) {
|
|
6
|
+
const alert = useAlert();
|
|
7
|
+
const modelBy = ref();
|
|
8
|
+
const item = ref();
|
|
9
|
+
const isLoading = ref(false);
|
|
10
|
+
const { operationCreate, operationUpdate, operationDelete, operationRead } = useGraphqlModelOperation(props);
|
|
11
|
+
const fields = computed(() => {
|
|
12
|
+
const fieldsProps = props.fields || [];
|
|
13
|
+
let requiredInputFields = [];
|
|
14
|
+
if (canUpdate.value) {
|
|
15
|
+
requiredInputFields = buildRequiredInputFields(operationUpdate.value?.variables);
|
|
16
|
+
}
|
|
17
|
+
return [.../* @__PURE__ */ new Set([...fieldsProps, ...requiredInputFields])];
|
|
18
|
+
});
|
|
19
|
+
const canCreate = computed(() => {
|
|
20
|
+
return !!operationCreate.value;
|
|
21
|
+
});
|
|
22
|
+
const canUpdate = computed(() => {
|
|
23
|
+
return !!operationUpdate.value;
|
|
24
|
+
});
|
|
25
|
+
const canDelete = computed(() => {
|
|
26
|
+
return !!operationDelete.value;
|
|
27
|
+
});
|
|
28
|
+
function createItem(createItem2, callback) {
|
|
29
|
+
isLoading.value = true;
|
|
30
|
+
return operationCreate.value?.call(fields.value, { input: createItem2 }).then((result) => {
|
|
31
|
+
item.value = result;
|
|
32
|
+
}).catch((error) => {
|
|
33
|
+
alert?.addAlert({ alertType: "error", message: error });
|
|
34
|
+
reload();
|
|
35
|
+
}).finally(() => {
|
|
36
|
+
isLoading.value = false;
|
|
37
|
+
if (callback)
|
|
38
|
+
callback.done();
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
function updateItem(updateItem2, callback) {
|
|
42
|
+
isLoading.value = true;
|
|
43
|
+
return operationUpdate.value?.call(fields.value, { input: updateItem2 }).then((result) => {
|
|
44
|
+
item.value = result;
|
|
45
|
+
}).catch((error) => {
|
|
46
|
+
alert?.addAlert({ alertType: "error", message: error });
|
|
47
|
+
reload();
|
|
48
|
+
}).finally(() => {
|
|
49
|
+
isLoading.value = false;
|
|
50
|
+
if (callback)
|
|
51
|
+
callback.done();
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
function deleteItem(item2, callback) {
|
|
55
|
+
isLoading.value = true;
|
|
56
|
+
return operationDelete.value?.call(fields.value, { input: item2 }).catch((error) => {
|
|
57
|
+
alert?.addAlert({ alertType: "error", message: error });
|
|
58
|
+
}).finally(() => {
|
|
59
|
+
isLoading.value = false;
|
|
60
|
+
reload();
|
|
61
|
+
if (callback)
|
|
62
|
+
callback.done();
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
function reload() {
|
|
66
|
+
isLoading.value = true;
|
|
67
|
+
item.value = void 0;
|
|
68
|
+
operationRead.value?.call(fields.value, computedModelBy.value).then((result) => {
|
|
69
|
+
if (Array.isArray(result)) {
|
|
70
|
+
alert?.addAlert({ alertType: "error", message: "Return result is not single item" });
|
|
71
|
+
} else {
|
|
72
|
+
item.value = result;
|
|
73
|
+
}
|
|
74
|
+
}).catch((error) => {
|
|
75
|
+
alert?.addAlert({ alertType: "error", message: error });
|
|
76
|
+
}).finally(() => {
|
|
77
|
+
isLoading.value = false;
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
const computedModelBy = computed(() => {
|
|
81
|
+
return Object.assign({}, props.modelBy, modelBy.value);
|
|
82
|
+
});
|
|
83
|
+
watch([() => props.modelName, () => props.modelKey, computedModelBy], () => {
|
|
84
|
+
reload();
|
|
85
|
+
}, { immediate: true, deep: true });
|
|
86
|
+
return {
|
|
87
|
+
modelBy,
|
|
88
|
+
item,
|
|
89
|
+
operationCreate,
|
|
90
|
+
operationUpdate,
|
|
91
|
+
operationDelete,
|
|
92
|
+
operationRead,
|
|
93
|
+
fields,
|
|
94
|
+
canCreate,
|
|
95
|
+
canUpdate,
|
|
96
|
+
canDelete,
|
|
97
|
+
createItem,
|
|
98
|
+
updateItem,
|
|
99
|
+
deleteItem,
|
|
100
|
+
reload,
|
|
101
|
+
isLoading
|
|
102
|
+
};
|
|
103
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { graphqlOperationObject } from '../types/graphqlOperation';
|
|
2
|
+
export interface GraphqlModelConfigProps {
|
|
3
|
+
modelName: string;
|
|
4
|
+
modelKey?: string;
|
|
5
|
+
modelBy?: object;
|
|
6
|
+
operationCreate?: graphqlOperationObject<any, any> | string;
|
|
7
|
+
operationUpdate?: graphqlOperationObject<any, any> | string;
|
|
8
|
+
operationDelete?: graphqlOperationObject<any, any> | string;
|
|
9
|
+
operationRead?: graphqlOperationObject<any, any> | string;
|
|
10
|
+
operationReadPageable?: graphqlOperationObject<any, any> | string;
|
|
11
|
+
operationSearch?: graphqlOperationObject<any, any> | string;
|
|
12
|
+
fields?: Array<string | object>;
|
|
13
|
+
}
|
|
14
|
+
export declare function useGraphqlModelOperation<T extends GraphqlModelConfigProps>(props: T): {
|
|
15
|
+
operationCreate: import("vue").ComputedRef<any>;
|
|
16
|
+
operationUpdate: import("vue").ComputedRef<any>;
|
|
17
|
+
operationDelete: import("vue").ComputedRef<any>;
|
|
18
|
+
operationRead: import("vue").ComputedRef<any>;
|
|
19
|
+
operationReadPageable: import("vue").ComputedRef<any>;
|
|
20
|
+
operationSearch: import("vue").ComputedRef<any>;
|
|
21
|
+
};
|