@ramathibodi/nuxt-commons 0.1.50 → 0.1.51

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 CHANGED
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": "^3.0.0"
6
6
  },
7
- "version": "0.1.50",
7
+ "version": "0.1.51",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "0.8.4",
10
10
  "unbuild": "2.0.0"
@@ -6,23 +6,23 @@ import type {FormDialogCallback} from '../../types/formDialog'
6
6
  interface Props {
7
7
  title?: string
8
8
  initialData?: object
9
- createCaption?: string
10
- updateCaption?: string
9
+ saveCaption?: string
11
10
  cancelCaption?: string
11
+ readonly?: boolean
12
12
  showTitle?: boolean
13
13
  }
14
14
 
15
15
  const props = withDefaults(defineProps<Props>(), {
16
- createCaption: 'Add',
17
- updateCaption: 'Save',
18
- cancelCaption: 'Cancel',
16
+ saveCaption: 'บันทึก',
17
+ cancelCaption: 'ยกเลิก',
18
+ readonly: false,
19
19
  showTitle: false,
20
20
  })
21
21
 
22
22
  const isSaving = ref<boolean>(false)
23
23
  const formPadRef = ref()
24
- const formOriginalData = ref<object>()
25
24
  const formData = ref<object>({})
25
+ const formDataOriginalValue = ref<object>()
26
26
 
27
27
  const emit = defineEmits(['create', 'update'])
28
28
 
@@ -38,7 +38,8 @@ function cancel() {
38
38
  }
39
39
 
40
40
  function reset() {
41
- formOriginalData.value = undefined
41
+ formDataOriginalValue.value = undefined
42
+ formPadRef.value.reset()
42
43
  loadFormData()
43
44
  }
44
45
 
@@ -53,11 +54,11 @@ const callback: FormDialogCallback = {
53
54
  }
54
55
 
55
56
  const isDataChange = computed(() => {
56
- return !((isCreating.value) ? isEqual(formData.value, createOriginalValue.value) : isEqual(formData.value, formOriginalData.value))
57
+ return !((isCreating.value) ? isEqual(formData.value, createOriginalValue.value) : isEqual(formData.value, formDataOriginalValue.value))
57
58
  })
58
59
 
59
60
  const isCreating = computed(() => {
60
- return !formOriginalData.value
61
+ return !formDataOriginalValue.value
61
62
  })
62
63
 
63
64
  const createOriginalValue = computed(() => {
@@ -65,69 +66,74 @@ const createOriginalValue = computed(() => {
65
66
  })
66
67
 
67
68
  const loadFormData = () => {
68
- if (formOriginalData.value) {
69
- formData.value = cloneDeep(formOriginalData.value)
69
+ if (formDataOriginalValue.value) {
70
+ formData.value = cloneDeep(formDataOriginalValue.value)
70
71
  }
71
72
  else {
72
73
  formData.value = Object.assign({}, props.initialData)
73
74
  }
74
75
  }
75
76
 
77
+ const operation = ref({ isDataChange, isCreating, isSaving, save, cancel })
78
+
76
79
  watchEffect(loadFormData)
77
80
 
78
81
  function setOriginalData(originalData?: object) {
79
- formOriginalData.value = originalData
82
+ formDataOriginalValue.value = originalData
80
83
  }
81
84
 
82
- defineExpose({setOriginalData,reset})
85
+ defineExpose({setOriginalData,operation})
83
86
  </script>
84
87
 
85
88
  <template>
86
- <VCard flat>
87
- <VToolbar v-if="showTitle">
88
- <VToolbarTitle>
89
- <slot name="title">
90
- {{ (isCreating) ? "New" : "Edit" }} {{ title }}
89
+ <VCard flat>
90
+ <VToolbar v-if="showTitle">
91
+ <slot name="titleToolbar" :operation="operation">
92
+ <VToolbarTitle>
93
+ <slot name="title" :operation="operation">
94
+ {{ (isCreating) ? "New" : "Edit" }} {{ title }}
95
+ </slot>
96
+ </VToolbarTitle>
91
97
  </slot>
92
- </VToolbarTitle>
93
- <VSpacer />
94
- </VToolbar>
95
- <VCardText>
96
- <form-pad
97
- ref="formPadRef"
98
- v-model="formData"
99
- isolated
100
- >
101
- <template #default="slotData">
102
- <slot
103
- v-bind="slotData"
104
- :is-creating="isCreating"
105
- :is-data-change="isDataChange"
106
- />
107
- </template>
108
- </form-pad>
109
- </VCardText>
110
- <VCardActions>
111
- <slot name="action" :save="save" :cancel="cancel">
112
- <VSpacer />
113
- <VBtn
114
- color="primary"
115
- variant="flat"
116
- :loading="isSaving"
117
- :disabled="!isDataChange"
118
- @click="save"
119
- >
120
- {{ (isCreating) ? createCaption : updateCaption }}
121
- </VBtn>
122
- <VBtn
123
- color="error"
124
- variant="flat"
125
- :disabled="isSaving"
126
- @click="cancel"
98
+ </VToolbar>
99
+ <VCardText>
100
+ <form-pad
101
+ ref="formPadRef"
102
+ v-model="formData"
103
+ :readonly="readonly"
104
+ isolated
127
105
  >
128
- {{ cancelCaption }}
129
- </VBtn>
130
- </slot>
131
- </VCardActions>
132
- </VCard>
106
+ <template #default="slotData">
107
+ <slot
108
+ v-bind="slotData"
109
+ :is-creating="isCreating"
110
+ :is-data-change="isDataChange"
111
+ />
112
+ </template>
113
+ </form-pad>
114
+ </VCardText>
115
+ <VCardActions>
116
+ <slot name="action" :operation="operation">
117
+ <VSpacer />
118
+ <VBtn
119
+ color="primary"
120
+ variant="flat"
121
+ :loading="isSaving"
122
+ :disabled="!isDataChange"
123
+ @click="save"
124
+ v-if="!readonly"
125
+ >
126
+ {{ saveCaption }}
127
+ </VBtn>
128
+ <VBtn
129
+ color="error"
130
+ variant="flat"
131
+ :disabled="isSaving"
132
+ @click="cancel"
133
+ >
134
+ {{ cancelCaption }}
135
+ </VBtn>
136
+ </slot>
137
+ </VCardActions>
138
+ </VCard>
133
139
  </template>
@@ -0,0 +1,140 @@
1
+ <script lang="ts" setup>
2
+ import {computed, ref, watchEffect} from 'vue'
3
+ import {cloneDeep, isEqual} from 'lodash-es'
4
+ import type {FormDialogCallback} from '../../types/formDialog'
5
+
6
+ interface Props {
7
+ title?: string
8
+ initialData?: object
9
+ formData?: object
10
+ saveCaption?: string
11
+ cancelCaption?: string
12
+ readonly?: boolean
13
+ showTitle?: boolean
14
+ }
15
+
16
+ const props = withDefaults(defineProps<Props>(), {
17
+ saveCaption: 'บันทึก',
18
+ cancelCaption: 'ยกเลิก',
19
+ readonly: false,
20
+ showTitle: false,
21
+ })
22
+
23
+ const isSaving = ref<boolean>(false)
24
+ const formPadRef = ref()
25
+ const formData = ref<object>({})
26
+ const formDataOriginalValue = ref<object>()
27
+
28
+ const emit = defineEmits(['create', 'update'])
29
+
30
+ function save() {
31
+ if (formPadRef.value.isValid) {
32
+ isSaving.value = true
33
+ emit((isCreating.value) ? 'create' : 'update', cloneDeep(formData.value), callback)
34
+ }
35
+ }
36
+
37
+ function cancel() {
38
+ reset()
39
+ }
40
+
41
+ function reset() {
42
+ formDataOriginalValue.value = undefined
43
+ formPadRef.value.reset()
44
+ loadFormData()
45
+ }
46
+
47
+ const callback: FormDialogCallback = {
48
+ done: function () {
49
+ isSaving.value = false
50
+ },
51
+ error: function () {
52
+ isSaving.value = false
53
+ },
54
+ setData: function (item: object) {
55
+ formData.value = cloneDeep(item)
56
+ formDataOriginalValue.value = cloneDeep(item)
57
+ }
58
+ }
59
+
60
+ const isDataChange = computed(() => {
61
+ return !((isCreating.value) ? isEqual(formData.value, createOriginalValue.value) : isEqual(formData.value, formDataOriginalValue.value))
62
+ })
63
+
64
+ const isCreating = computed(() => {
65
+ return !props.formData
66
+ })
67
+
68
+ const createOriginalValue = computed(() => {
69
+ return Object.assign({}, props.initialData)
70
+ })
71
+
72
+ const loadFormData = () => {
73
+ if (props.formData) {
74
+ formData.value = cloneDeep(props.formData)
75
+ formDataOriginalValue.value = cloneDeep(props.formData)
76
+ }
77
+ else {
78
+ formData.value = Object.assign({}, props.initialData)
79
+ }
80
+ }
81
+
82
+ const operation = ref({ isDataChange, isCreating, isSaving, save, cancel })
83
+
84
+ watchEffect(loadFormData)
85
+
86
+ defineExpose({operation})
87
+ </script>
88
+
89
+ <template>
90
+ <VCard flat>
91
+ <VToolbar v-if="showTitle">
92
+ <slot name="titleToolbar" :operation="operation">
93
+ <VToolbarTitle>
94
+ <slot name="title" :operation="operation">
95
+ {{ (isCreating) ? "New" : "Edit" }} {{ title }}
96
+ </slot>
97
+ </VToolbarTitle>
98
+ </slot>
99
+ </VToolbar>
100
+ <VCardText>
101
+ <form-pad
102
+ ref="formPadRef"
103
+ v-model="formData"
104
+ :readonly="readonly"
105
+ isolated
106
+ >
107
+ <template #default="slotData">
108
+ <slot
109
+ v-bind="slotData"
110
+ :is-creating="isCreating"
111
+ :is-data-change="isDataChange"
112
+ />
113
+ </template>
114
+ </form-pad>
115
+ </VCardText>
116
+ <VCardActions>
117
+ <slot name="action" :operation="operation">
118
+ <VSpacer />
119
+ <VBtn
120
+ color="primary"
121
+ variant="flat"
122
+ :loading="isSaving"
123
+ :disabled="!isDataChange"
124
+ @click="save"
125
+ v-if="!readonly"
126
+ >
127
+ {{ saveCaption }}
128
+ </VBtn>
129
+ <VBtn
130
+ color="error"
131
+ variant="flat"
132
+ :disabled="isSaving"
133
+ @click="cancel"
134
+ >
135
+ {{ cancelCaption }}
136
+ </VBtn>
137
+ </slot>
138
+ </VCardActions>
139
+ </VCard>
140
+ </template>
@@ -26,7 +26,6 @@ interface Props extends /* @vue-ignore */ InstanceType<typeof VDataTable['$props
26
26
  inputPadOnly?: boolean
27
27
  saveAndStay?: boolean
28
28
  stringFields?: Array<string>
29
- items?: Record<string, any>[]
30
29
  }
31
30
 
32
31
  const props = withDefaults(defineProps<Props>(), {
@@ -85,11 +84,6 @@ watch(items, (newValue) => {
85
84
  emit('update:modelValue', newValue)
86
85
  }, { deep: true })
87
86
 
88
- onMounted(()=>{
89
- if (props.items){
90
- items.value = props.items
91
- }
92
- })
93
87
 
94
88
  function createItem(item: Record<string, any>, callback?: FormDialogCallback) {
95
89
  if (items.value.length > 0) item[props.modelKey] = Math.max(...items.value.map(i => i[props.modelKey] || 0)) + 1
@@ -0,0 +1,82 @@
1
+ <script setup lang="ts">
2
+ import {VDataTable} from 'vuetify/components/VDataTable'
3
+ import {computed, onMounted, ref, useAttrs, watch} from 'vue'
4
+ import {omit} from "lodash-es";
5
+ interface Props extends /* @vue-ignore */ InstanceType<typeof VDataTable['$props']> {
6
+ title: string
7
+ modelValue?: Record<string, any>[]
8
+ modelKey?: string
9
+ toolbarColor?: string
10
+ items : Record<string, any>
11
+ }
12
+ const props = withDefaults(defineProps<Props>(), {
13
+ modelKey: 'id',
14
+ })
15
+
16
+ const emit = defineEmits(['update:modelValue'])
17
+ const attrs = useAttrs()
18
+ const plainAttrs = computed(() => {
19
+ return omit(attrs, ['modelValue', 'onUpdate:modelValue'])
20
+ })
21
+ const modelValue = ref()
22
+ const setDataItems = ()=>{
23
+ modelValue.value = props.items
24
+ }
25
+ watch(() => props.modelValue, (newValue) => {
26
+ if (!Array.isArray(newValue) || !newValue.every(item => typeof item === 'object')) {
27
+ modelValue.value = []
28
+ }
29
+ else {
30
+ let maxKey = 0
31
+
32
+ newValue.forEach((item) => {
33
+ if (!item.hasOwnProperty(props.modelKey)) {
34
+ maxKey = Math.max(maxKey, ...newValue.map(i => i[props.modelKey] || 0))
35
+ item[props.modelKey] = maxKey + 1
36
+ }
37
+ })
38
+
39
+ modelValue.value = newValue
40
+ }
41
+ }, { immediate: true })
42
+
43
+ watch(modelValue, (newValue) => {
44
+ emit('update:modelValue', newValue)
45
+ }, { deep: true })
46
+
47
+ onMounted(()=>{
48
+ setDataItems()
49
+ })
50
+
51
+ </script>
52
+
53
+
54
+ <template>
55
+ <form-table
56
+ v-bind="plainAttrs"
57
+ v-model="modelValue"
58
+ :title="props.title"
59
+ :toolbarColor="props.toolbarColor"
60
+ :model-key="props.modelKey"
61
+ :insertable="false"
62
+ :importable="false"
63
+ :exportable="false"
64
+ :searchable="false"
65
+ hide-default-footer>
66
+ <!-- @ts-ignore -->
67
+ <template
68
+ v-for="(_, name, index) in ($slots as {})"
69
+ :key="index"
70
+ #[name]="slotData"
71
+ >
72
+ <slot
73
+ :name="name"
74
+ v-bind="((slotData || {}) as object)"
75
+ />
76
+ </template>
77
+ </form-table>
78
+ </template>
79
+
80
+ <style scoped>
81
+
82
+ </style>
@@ -1,17 +1,13 @@
1
1
  <script lang="ts" setup>
2
- import { computed, ref, watchEffect } from 'vue'
3
- import { cloneDeep, isEqual } from 'lodash-es'
2
+ import { computed, useTemplateRef } from 'vue'
4
3
  import { type GraphqlModelItemProps, useGraphqlModelItem } from '../../composables/graphqlModelItem'
4
+ import EditPad from '../form/EditPad.vue'
5
5
 
6
6
  defineOptions({
7
7
  inheritAttrs: false,
8
8
  })
9
9
 
10
- interface Props {
11
- title?: string
12
- initialData?: object
13
- saveCaption?: string
14
- cancelCaption?: string
10
+ interface Props extends /* @vue-ignore */ InstanceType<typeof EditPad['$props']> {
15
11
  }
16
12
 
17
13
  const props = withDefaults(defineProps<Props & GraphqlModelItemProps>(), {
@@ -25,92 +21,43 @@ const { item,
25
21
  createItem, updateItem,
26
22
  reload, isLoading } = useGraphqlModelItem(props)
27
23
 
28
- const formPadRef = ref()
29
- const formData = ref<object>({})
24
+ const editPad = useTemplateRef<typeof EditPad>("editPadRef")
30
25
 
31
- const canSave = computed(() => { return (canCreate.value && isCreating.value) || canUpdate.value })
26
+ const canSave = computed<boolean>(() => { return ((canCreate.value && editPad.value?.operation?.isCreating?.value) || canUpdate.value) as boolean})
32
27
 
33
- const isDataChange = computed(() => {
34
- return !((isCreating.value) ? isEqual(formData.value, createOriginalValue.value) : isEqual(formData.value, item.value))
28
+ const operation : any = computed(()=>{
29
+ return Object.assign({},editPad.value?.operation,{canSave,reload,item})
35
30
  })
36
31
 
37
- const isCreating = computed(() => {
38
- return !item.value
39
- })
40
-
41
- const createOriginalValue = computed(() => {
42
- return Object.assign({}, props.initialData)
43
- })
44
-
45
- const loadFormData = () => {
46
- if (item.value) {
47
- formData.value = cloneDeep(item.value)
48
- }
49
- else {
50
- formData.value = Object.assign({}, props.initialData)
51
- }
52
- }
53
-
54
- watchEffect(loadFormData)
55
-
56
- function save() {
57
- if (formPadRef.value.isValid) {
58
- if (isCreating.value) createItem(formData.value)
59
- else updateItem(formData.value)
60
- }
61
- }
62
-
63
- function cancel() {
64
- formPadRef.value.reset()
65
- loadFormData()
66
- }
67
-
68
- const operation = ref({save, cancel, reload, item, canSave, isLoading,isDataChange,isCreating})
69
-
70
- defineExpose({ save, cancel, reload, item, isLoading })
32
+ defineExpose({ operation })
71
33
  </script>
72
34
 
73
35
  <template>
74
- <VCard>
75
- <VToolbar>
36
+ <FormEditPad :form-data="item" ref="editPadRef" @create="createItem" @update="updateItem">
37
+ <template #titleToolbar="slotData">
76
38
  <slot name="titleToolbar" :operation="operation">
77
39
  <VToolbarTitle>
78
40
  <slot name="title" :operation="operation">
79
41
  {{ title }}
80
42
  <v-icon
81
- size="small"
82
- @click="reload"
43
+ size="small"
44
+ @click="reload"
83
45
  >
84
46
  mdi mdi-refresh
85
47
  </v-icon>
86
48
  </slot>
87
49
  </VToolbarTitle>
88
50
  </slot>
89
- </VToolbar>
90
- <VCardText>
91
- <form-pad
92
- ref="formPadRef"
93
- v-model="formData"
94
- isolated
95
- >
96
- <template #default="slotData">
97
- <slot
98
- v-bind="slotData"
99
- :is-creating="isCreating"
100
- :is-data-change="isDataChange"
101
- />
102
- </template>
103
- </form-pad>
104
- </VCardText>
105
- <VCardActions>
51
+ </template>
52
+ <template #action="slotData">
106
53
  <slot name="action" :operation="operation">
107
54
  <VSpacer />
108
55
  <VBtn
109
56
  color="primary"
110
57
  variant="flat"
111
58
  :loading="isLoading"
112
- :disabled="!isDataChange || !canSave"
113
- @click="save"
59
+ :disabled="!slotData.operation?.isDataChange || !canSave"
60
+ @click="slotData.operation?.save"
114
61
  >
115
62
  {{ saveCaption }}
116
63
  </VBtn>
@@ -118,11 +65,18 @@ defineExpose({ save, cancel, reload, item, isLoading })
118
65
  color="error"
119
66
  variant="flat"
120
67
  :disabled="isLoading"
121
- @click="cancel"
68
+ @click="slotData.operation?.cancel"
122
69
  >
123
70
  {{ cancelCaption }}
124
71
  </VBtn>
125
72
  </slot>
126
- </VCardActions>
127
- </VCard>
73
+ </template>
74
+ <template #default="slotData">
75
+ <slot
76
+ v-bind="slotData"
77
+ :is-creating="isCreating"
78
+ :is-data-change="isDataChange"
79
+ />
80
+ </template>
81
+ </FormEditPad>
128
82
  </template>
@@ -37,7 +37,7 @@ export function processTemplateFormTableData(item, parentTemplates) {
37
37
  </template>`;
38
38
  }
39
39
  }
40
- item.inputType = "FormTable";
40
+ item.inputType = "FormTableData";
41
41
  return processDefaultTemplate(item, tableTemplate, `title="${tableOptions.title}"
42
42
  :headers='${escapeObjectForInlineBinding(tableHeader)}'
43
43
  :items='${escapeObjectForInlineBinding(tableItems)}'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ramathibodi/nuxt-commons",
3
- "version": "0.1.50",
3
+ "version": "0.1.51",
4
4
  "description": "Ramathibodi Nuxt modules for common components",
5
5
  "repository": {
6
6
  "type": "git",