@ramathibodi/nuxt-commons 0.1.50 → 0.1.52

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.52",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "0.8.4",
10
10
  "unbuild": "2.0.0"
@@ -2,32 +2,35 @@
2
2
  import {computed, defineExpose, ref, watchEffect} from 'vue'
3
3
  import {cloneDeep, isEqual} from 'lodash-es'
4
4
  import type {FormDialogCallback} from '../../types/formDialog'
5
+ import FormPadComponent from './Pad.vue'
5
6
 
6
- interface Props {
7
+ interface Props extends /* @vue-ignore */ InstanceType<typeof FormPadComponent['$props']> {
7
8
  title?: string
8
9
  initialData?: object
9
- createCaption?: string
10
- updateCaption?: string
10
+ saveCaption?: string
11
11
  cancelCaption?: string
12
+ readonly?: boolean
12
13
  showTitle?: boolean
14
+ skipValidation?:boolean
13
15
  }
14
16
 
15
17
  const props = withDefaults(defineProps<Props>(), {
16
- createCaption: 'Add',
17
- updateCaption: 'Save',
18
- cancelCaption: 'Cancel',
18
+ saveCaption: 'บันทึก',
19
+ cancelCaption: 'ยกเลิก',
20
+ readonly: false,
19
21
  showTitle: false,
22
+ skipValidation:false
20
23
  })
21
24
 
22
25
  const isSaving = ref<boolean>(false)
23
26
  const formPadRef = ref()
24
- const formOriginalData = ref<object>()
25
27
  const formData = ref<object>({})
28
+ const formDataOriginalValue = ref<object>()
26
29
 
27
30
  const emit = defineEmits(['create', 'update'])
28
31
 
29
32
  function save() {
30
- if (formPadRef.value.isValid) {
33
+ if (props.skipValidation || formPadRef.value?.isValid) {
31
34
  isSaving.value = true
32
35
  emit((isCreating.value) ? 'create' : 'update', cloneDeep(formData.value), callback)
33
36
  }
@@ -38,7 +41,8 @@ function cancel() {
38
41
  }
39
42
 
40
43
  function reset() {
41
- formOriginalData.value = undefined
44
+ formDataOriginalValue.value = undefined
45
+ formPadRef.value?.reset()
42
46
  loadFormData()
43
47
  }
44
48
 
@@ -53,11 +57,11 @@ const callback: FormDialogCallback = {
53
57
  }
54
58
 
55
59
  const isDataChange = computed(() => {
56
- return !((isCreating.value) ? isEqual(formData.value, createOriginalValue.value) : isEqual(formData.value, formOriginalData.value))
60
+ return !((isCreating.value) ? isEqual(formData.value, createOriginalValue.value) : isEqual(formData.value, formDataOriginalValue.value))
57
61
  })
58
62
 
59
63
  const isCreating = computed(() => {
60
- return !formOriginalData.value
64
+ return !formDataOriginalValue.value
61
65
  })
62
66
 
63
67
  const createOriginalValue = computed(() => {
@@ -65,69 +69,75 @@ const createOriginalValue = computed(() => {
65
69
  })
66
70
 
67
71
  const loadFormData = () => {
68
- if (formOriginalData.value) {
69
- formData.value = cloneDeep(formOriginalData.value)
72
+ if (formDataOriginalValue.value) {
73
+ formData.value = cloneDeep(formDataOriginalValue.value)
70
74
  }
71
75
  else {
72
76
  formData.value = Object.assign({}, props.initialData)
73
77
  }
74
78
  }
75
79
 
80
+ const operation = ref({ isDataChange, isCreating, isSaving, save, cancel })
81
+
76
82
  watchEffect(loadFormData)
77
83
 
78
84
  function setOriginalData(originalData?: object) {
79
- formOriginalData.value = originalData
85
+ formDataOriginalValue.value = originalData
80
86
  }
81
87
 
82
- defineExpose({setOriginalData,reset})
88
+ defineExpose({setOriginalData,operation,formPad: formPadRef})
83
89
  </script>
84
90
 
85
91
  <template>
86
- <VCard flat>
87
- <VToolbar v-if="showTitle">
88
- <VToolbarTitle>
89
- <slot name="title">
90
- {{ (isCreating) ? "New" : "Edit" }} {{ title }}
92
+ <VCard flat>
93
+ <VToolbar v-if="showTitle">
94
+ <slot name="titleToolbar" :operation="operation">
95
+ <VToolbarTitle>
96
+ <slot name="title" :operation="operation">
97
+ {{ (isCreating) ? "New" : "Edit" }} {{ title }}
98
+ </slot>
99
+ </VToolbarTitle>
91
100
  </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"
101
+ </VToolbar>
102
+ <VCardText>
103
+ <form-pad
104
+ ref="formPadRef"
105
+ v-model="formData"
106
+ :readonly="readonly"
107
+ isolated
108
+ v-bind="$attrs"
127
109
  >
128
- {{ cancelCaption }}
129
- </VBtn>
130
- </slot>
131
- </VCardActions>
132
- </VCard>
110
+ <template #default="slotData">
111
+ <slot
112
+ v-bind="slotData"
113
+ :is-creating="isCreating"
114
+ :is-data-change="isDataChange"
115
+ />
116
+ </template>
117
+ </form-pad>
118
+ </VCardText>
119
+ <VCardActions>
120
+ <slot name="action" :operation="operation">
121
+ <VSpacer />
122
+ <VBtn
123
+ color="primary"
124
+ variant="flat"
125
+ :loading="isSaving"
126
+ :disabled="!isDataChange"
127
+ @click="save"
128
+ v-if="!readonly"
129
+ >
130
+ {{ saveCaption }}
131
+ </VBtn>
132
+ <VBtn
133
+ color="error"
134
+ variant="flat"
135
+ :disabled="isSaving"
136
+ @click="cancel"
137
+ >
138
+ {{ cancelCaption }}
139
+ </VBtn>
140
+ </slot>
141
+ </VCardActions>
142
+ </VCard>
133
143
  </template>
@@ -0,0 +1,144 @@
1
+ <script lang="ts" setup>
2
+ import {computed, defineExpose, ref, watchEffect} from 'vue'
3
+ import {cloneDeep, isEqual} from 'lodash-es'
4
+ import type {FormDialogCallback} from '../../types/formDialog'
5
+ import FormPadComponent from './Pad.vue'
6
+
7
+ interface Props extends /* @vue-ignore */ InstanceType<typeof FormPadComponent['$props']> {
8
+ title?: string
9
+ initialData?: object
10
+ formData?: object
11
+ saveCaption?: string
12
+ cancelCaption?: string
13
+ readonly?: boolean
14
+ showTitle?: boolean
15
+ skipValidation?:boolean
16
+ }
17
+
18
+ const props = withDefaults(defineProps<Props>(), {
19
+ saveCaption: 'บันทึก',
20
+ cancelCaption: 'ยกเลิก',
21
+ readonly: false,
22
+ showTitle: false,
23
+ skipValidation:false
24
+ })
25
+
26
+ const isSaving = ref<boolean>(false)
27
+ const formPadRef = ref()
28
+ const formData = ref<object>({})
29
+ const formDataOriginalValue = ref<object>()
30
+
31
+ const emit = defineEmits(['create', 'update'])
32
+
33
+ function save() {
34
+ if (props.skipValidation || formPadRef.value?.isValid) {
35
+ isSaving.value = true
36
+ emit((isCreating.value) ? 'create' : 'update', cloneDeep(formData.value), callback)
37
+ }
38
+ }
39
+
40
+ function cancel() {
41
+ reset()
42
+ }
43
+
44
+ function reset() {
45
+ formDataOriginalValue.value = undefined
46
+ formPadRef.value?.reset()
47
+ loadFormData()
48
+ }
49
+
50
+ const callback: FormDialogCallback = {
51
+ done: function () {
52
+ isSaving.value = false
53
+ },
54
+ error: function () {
55
+ isSaving.value = false
56
+ },
57
+ setData: function (item: object) {
58
+ formData.value = cloneDeep(item)
59
+ formDataOriginalValue.value = cloneDeep(item)
60
+ }
61
+ }
62
+
63
+ const isDataChange = computed(() => {
64
+ return !((isCreating.value) ? isEqual(formData.value, createOriginalValue.value) : isEqual(formData.value, formDataOriginalValue.value))
65
+ })
66
+
67
+ const isCreating = computed(() => {
68
+ return !props.formData
69
+ })
70
+
71
+ const createOriginalValue = computed(() => {
72
+ return Object.assign({}, props.initialData)
73
+ })
74
+
75
+ const loadFormData = () => {
76
+ if (props.formData) {
77
+ formData.value = cloneDeep(props.formData)
78
+ formDataOriginalValue.value = cloneDeep(props.formData)
79
+ }
80
+ else {
81
+ formData.value = Object.assign({}, props.initialData)
82
+ }
83
+ }
84
+
85
+ const operation = ref({ isDataChange, isCreating, isSaving, save, cancel })
86
+
87
+ watchEffect(loadFormData)
88
+
89
+ defineExpose({operation,formPad:formPadRef})
90
+ </script>
91
+
92
+ <template>
93
+ <VCard flat>
94
+ <VToolbar v-if="showTitle">
95
+ <slot name="titleToolbar" :operation="operation">
96
+ <VToolbarTitle>
97
+ <slot name="title" :operation="operation">
98
+ {{ (isCreating) ? "New" : "Edit" }} {{ title }}
99
+ </slot>
100
+ </VToolbarTitle>
101
+ </slot>
102
+ </VToolbar>
103
+ <VCardText>
104
+ <form-pad
105
+ ref="formPadRef"
106
+ v-model="formData"
107
+ :readonly="readonly"
108
+ isolated
109
+ v-bind="$attrs"
110
+ >
111
+ <template #default="slotData">
112
+ <slot
113
+ v-bind="slotData"
114
+ :is-creating="isCreating"
115
+ :is-data-change="isDataChange"
116
+ />
117
+ </template>
118
+ </form-pad>
119
+ </VCardText>
120
+ <VCardActions>
121
+ <slot name="action" :operation="operation">
122
+ <VSpacer />
123
+ <VBtn
124
+ color="primary"
125
+ variant="flat"
126
+ :loading="isSaving"
127
+ :disabled="!isDataChange"
128
+ @click="save"
129
+ v-if="!readonly"
130
+ >
131
+ {{ saveCaption }}
132
+ </VBtn>
133
+ <VBtn
134
+ color="error"
135
+ variant="flat"
136
+ :disabled="isSaving"
137
+ @click="cancel"
138
+ >
139
+ {{ cancelCaption }}
140
+ </VBtn>
141
+ </slot>
142
+ </VCardActions>
143
+ </VCard>
144
+ </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,22 +1,16 @@
1
1
  <script lang="ts" setup>
2
- import { computed, ref, watchEffect } from 'vue'
3
- import { cloneDeep, isEqual } from 'lodash-es'
2
+ import { computed, useTemplateRef, defineExpose } 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>(), {
18
- saveCaption: 'บันทึก',
19
- cancelCaption: 'ยกเลิก',
20
14
  fields: () => ['*'],
21
15
  })
22
16
 
@@ -25,92 +19,43 @@ const { item,
25
19
  createItem, updateItem,
26
20
  reload, isLoading } = useGraphqlModelItem(props)
27
21
 
28
- const formPadRef = ref()
29
- const formData = ref<object>({})
22
+ const editPad = useTemplateRef<typeof EditPad>("editPadRef")
30
23
 
31
- const canSave = computed(() => { return (canCreate.value && isCreating.value) || canUpdate.value })
24
+ const canSave = computed<boolean>(() => { return ((canCreate.value && editPad.value?.operation?.isCreating?.value) || canUpdate.value) as boolean})
32
25
 
33
- const isDataChange = computed(() => {
34
- return !((isCreating.value) ? isEqual(formData.value, createOriginalValue.value) : isEqual(formData.value, item.value))
26
+ const operation : any = computed(()=>{
27
+ return Object.assign({},editPad.value?.operation,{canSave,reload,item})
35
28
  })
36
29
 
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 })
30
+ defineExpose({ operation, formPad: editPad.value?.formPad })
71
31
  </script>
72
32
 
73
33
  <template>
74
- <VCard>
75
- <VToolbar>
34
+ <FormEditPad v-bind="$attrs" :form-data="item" ref="editPadRef" @create="createItem" @update="updateItem">
35
+ <template #titleToolbar>
76
36
  <slot name="titleToolbar" :operation="operation">
77
37
  <VToolbarTitle>
78
38
  <slot name="title" :operation="operation">
79
39
  {{ title }}
80
40
  <v-icon
81
- size="small"
82
- @click="reload"
41
+ size="small"
42
+ @click="reload"
83
43
  >
84
44
  mdi mdi-refresh
85
45
  </v-icon>
86
46
  </slot>
87
47
  </VToolbarTitle>
88
48
  </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>
49
+ </template>
50
+ <template #action="slotData">
106
51
  <slot name="action" :operation="operation">
107
52
  <VSpacer />
108
53
  <VBtn
109
54
  color="primary"
110
55
  variant="flat"
111
56
  :loading="isLoading"
112
- :disabled="!isDataChange || !canSave"
113
- @click="save"
57
+ :disabled="!slotData.operation?.isDataChange || !canSave"
58
+ @click="slotData.operation?.save"
114
59
  >
115
60
  {{ saveCaption }}
116
61
  </VBtn>
@@ -118,11 +63,18 @@ defineExpose({ save, cancel, reload, item, isLoading })
118
63
  color="error"
119
64
  variant="flat"
120
65
  :disabled="isLoading"
121
- @click="cancel"
66
+ @click="slotData.operation?.cancel"
122
67
  >
123
68
  {{ cancelCaption }}
124
69
  </VBtn>
125
70
  </slot>
126
- </VCardActions>
127
- </VCard>
71
+ </template>
72
+ <template #default="slotData">
73
+ <slot
74
+ v-bind="slotData"
75
+ :is-creating="isCreating"
76
+ :is-data-change="isDataChange"
77
+ />
78
+ </template>
79
+ </FormEditPad>
128
80
  </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)}'
@@ -1 +1 @@
1
- export declare const useUserPermission: () => unknown;
1
+ export declare const useUserPermission: () => import("../types/permission").PermissionPlugin;
@@ -11,18 +11,18 @@ export default defineNuxtPlugin((nuxtApp) => {
11
11
  const arr = normalize(input);
12
12
  return arr.length === 0 || arr.every((v) => v.trim() === "");
13
13
  }
14
- function check(permissionIds) {
14
+ const check = (permissionIds) => {
15
15
  if (isBlank(permissionIds)) return true;
16
16
  const auth = useAuthentication();
17
17
  const perms = normalize(permissionIds);
18
18
  return perms.some((id) => auth?.hasPermission(id));
19
- }
20
- function checkAll(permissionIds) {
19
+ };
20
+ const checkAll = (permissionIds) => {
21
21
  if (isBlank(permissionIds)) return true;
22
22
  const auth = useAuthentication();
23
23
  const perms = normalize(permissionIds);
24
24
  return perms.every((id) => auth?.hasPermission(id));
25
- }
25
+ };
26
26
  nuxtApp.vueApp.directive("permission", (el, binding, vnode) => {
27
27
  if (!check(binding.value)) {
28
28
  vnode?.um?.forEach?.((um) => um());
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.52",
4
4
  "description": "Ramathibodi Nuxt modules for common components",
5
5
  "repository": {
6
6
  "type": "git",