@ramathibodi/nuxt-commons 0.1.37 → 0.1.39

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.37",
7
+ "version": "0.1.39",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "0.8.3",
10
10
  "unbuild": "2.0.0"
@@ -1,43 +1,76 @@
1
1
  <script lang="ts" setup>
2
- import {ref} from 'vue'
2
+ import { ref } from 'vue'
3
3
  import * as XLSX from 'xlsx'
4
- import {VBtn} from 'vuetify/components/VBtn'
5
- import {useAlert} from '../composables/alert'
4
+ import { VBtn } from 'vuetify/components/VBtn'
5
+ import { useAlert } from '../composables/alert'
6
6
 
7
7
  interface ExportButtonProps extends /* @vue-ignore */ InstanceType<typeof VBtn['$props']> {
8
8
  fileName?: string
9
+ sheetName?: string
9
10
  modelValue?: object[]
10
11
  }
11
12
 
12
13
  const props = withDefaults(defineProps<ExportButtonProps>(), {
13
14
  fileName: 'download',
15
+ sheetName: 'Sheet1',
14
16
  })
15
17
 
16
18
  const alert = useAlert()
17
19
  const loading = ref(false)
18
20
 
21
+ /**
22
+ * Triggers file export
23
+ */
19
24
  function exportFile() {
20
- if (props.modelValue && Array.isArray(props.modelValue)) {
25
+ if (props.modelValue && Array.isArray(props.modelValue) && props.modelValue.length > 0) {
21
26
  loading.value = true
22
- const workbook = XLSX.utils.book_new()
23
- const worksheet = XLSX.utils.json_to_sheet(serializeRoleField(props.modelValue))
24
- const fileName = `${props.fileName}.xlsx`
25
- XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1')
26
- XLSX.writeFile(workbook, fileName)
27
- loading.value = false
28
- }
29
- else {
27
+
28
+ try {
29
+ const workbook = XLSX.utils.book_new()
30
+ const worksheet = XLSX.utils.json_to_sheet(flattenNestedFields(props.modelValue))
31
+ const fileName = `${props.fileName}.xlsx`
32
+
33
+ XLSX.utils.book_append_sheet(workbook, worksheet, props.sheetName)
34
+ XLSX.writeFile(workbook, fileName)
35
+ } catch (error: any) {
36
+ alert?.addAlert({ message: `Export failed: ${error.message}`, alertType: 'error' })
37
+ } finally {
38
+ loading.value = false
39
+ }
40
+ } else {
30
41
  alert?.addAlert({ message: 'Invalid or no data to export', alertType: 'error' })
31
42
  }
32
43
  }
33
44
 
34
- const serializeRoleField = (items: any) => {
35
- return items.map((item:any) => {
36
- if (item.properties && typeof item.properties === 'object') {
37
- item.properties = JSON.stringify(item.properties);
45
+ /**
46
+ * Recursively flattens nested fields for export
47
+ * @param items - Array of objects to flatten
48
+ */
49
+ function flattenNestedFields(items: any[]) {
50
+ return items.map((item: any) => {
51
+ return flattenObject(item)
52
+ })
53
+ }
54
+
55
+ /**
56
+ * Recursively flattens an object, converting nested keys into dot-separated keys
57
+ * @param obj - Object to flatten
58
+ * @param parentKey - Parent key (for recursion)
59
+ * @param separator - Separator for nested keys
60
+ */
61
+ function flattenObject(obj: any, parentKey = '', separator = '.') {
62
+ return Object.keys(obj).reduce((acc: any, key: string) => {
63
+ const newKey = parentKey ? `${parentKey}${separator}${key}` : key
64
+ const value = obj[key]
65
+
66
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
67
+ Object.assign(acc, flattenObject(value, newKey, separator))
68
+ } else {
69
+ acc[newKey] = typeof value === 'object' ? JSON.stringify(value) : value
38
70
  }
39
- return item;
40
- });
71
+
72
+ return acc
73
+ }, {})
41
74
  }
42
75
  </script>
43
76
 
@@ -1,7 +1,7 @@
1
1
  <script lang="ts" setup>
2
2
  import * as XLSX from 'xlsx'
3
- import {ref} from 'vue'
4
- import {useAlert} from '../composables/alert'
3
+ import { ref } from 'vue'
4
+ import { useAlert } from '../composables/alert'
5
5
 
6
6
  const alert = useAlert()
7
7
  const emit = defineEmits<{
@@ -23,15 +23,17 @@ function uploadedFile(files: File[] | File | undefined) {
23
23
 
24
24
  const fileExtension = files.name.slice(files.name.lastIndexOf('.')).toLowerCase()
25
25
  if (!['.xlsx', '.csv'].includes(fileExtension)) {
26
- alert?.addAlert({ message: 'Please upload a file with .csv or .xlsx extension only (' + files.name + ')', alertType: 'error' })
26
+ alert?.addAlert({ message: `Please upload a file with .csv or .xlsx extension only (${files.name})`, alertType: 'error' })
27
27
  return
28
28
  }
29
29
 
30
30
  const reader = new FileReader()
31
31
  reader.onload = (e: ProgressEvent<FileReader>) => {
32
32
  const workbook = XLSX.read(e.target?.result)
33
- const parseData = parsePropertiesField(XLSX.utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]]))
34
- emit('import', parseData)
33
+ const parsedData = parseAndAggregateColumns(
34
+ XLSX.utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]])
35
+ )
36
+ emit('import', parsedData)
35
37
  loading.value = false
36
38
  fileBtnRef.value.reset()
37
39
  }
@@ -39,14 +41,63 @@ function uploadedFile(files: File[] | File | undefined) {
39
41
  reader.readAsArrayBuffer(files)
40
42
  }
41
43
 
42
- const parsePropertiesField = (items:any) => {
43
- return items.map((item : any) => {
44
- if (item.properties && typeof item.properties === 'string') {
45
- item.properties = JSON.parse(item.properties);
44
+ /**
45
+ * Recursively aggregates nested columns and properties.
46
+ * @param items - Array of data from the Excel sheet
47
+ */
48
+ const parseAndAggregateColumns = (items: any[]) => {
49
+ return items.map((item: any) => {
50
+ const aggregatedItem: any = {}
51
+
52
+ for (const key in item) {
53
+ if (key.includes('.')) {
54
+ // Extract root key and subKey
55
+ const [rootKey, ...subKeys] = key.split('.')
56
+
57
+ // Recursively aggregate subKeys
58
+ aggregatedItem[rootKey] = aggregatedItem[rootKey] || {}
59
+ assignNestedValue(aggregatedItem[rootKey], subKeys, parseIfJson(item[key]))
60
+ } else {
61
+ // Directly assign root-level properties
62
+ aggregatedItem[key] = parseIfJson(item[key])
63
+ }
46
64
  }
47
- return item;
48
- });
49
- };
65
+
66
+ return aggregatedItem
67
+ })
68
+ }
69
+
70
+ /**
71
+ * Recursively assigns a value to a nested key structure.
72
+ * @param obj - The object to assign to
73
+ * @param keys - Array of keys leading to the final property
74
+ * @param value - The value to assign
75
+ */
76
+ const assignNestedValue = (obj: any, keys: string[], value: any) => {
77
+ const [currentKey, ...remainingKeys] = keys
78
+ if (remainingKeys.length === 0) {
79
+ obj[currentKey] = value
80
+ } else {
81
+ obj[currentKey] = obj[currentKey] || {}
82
+ assignNestedValue(obj[currentKey], remainingKeys, value)
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Attempt to parse a value as JSON or array.
88
+ * @param value - The value to parse
89
+ */
90
+ const parseIfJson = (value: any) => {
91
+ if (typeof value === 'string') {
92
+ try {
93
+ return JSON.parse(value)
94
+ } catch {
95
+ // If parsing fails, return the original value
96
+ return value
97
+ }
98
+ }
99
+ return value
100
+ }
50
101
  </script>
51
102
 
52
103
  <template>
@@ -0,0 +1,43 @@
1
+ <script lang="ts" setup>
2
+ import {ref, withDefaults,watch,computed} from 'vue'
3
+ import {graphqlOperation} from '#imports'
4
+
5
+ interface Props {
6
+ templateCode: string
7
+ parentTemplates?: string|string[]
8
+ }
9
+
10
+ const props = withDefaults(defineProps<Props>(), {
11
+ parentTemplates: (): string[] => [],
12
+ })
13
+
14
+ const template = ref<any>()
15
+ const templateScript = ref<string>()
16
+
17
+ const parentTemplates = computed(()=>{
18
+ if (typeof props.parentTemplates === 'string') {
19
+ if (props.parentTemplates && props.parentTemplates!="") return props.parentTemplates.split("|")
20
+ else return []
21
+ } else {
22
+ return props.parentTemplates
23
+ }
24
+ })
25
+
26
+ const parentTemplatesNext = computed(()=>{
27
+ return [...parentTemplates.value,props.templateCode]
28
+ })
29
+
30
+ watch(()=>props.templateCode,()=>{
31
+ if (!parentTemplates.value.includes(props.templateCode) && props.templateCode) {
32
+ if (graphqlOperation["documentTemplateByTemplateCode"]) {
33
+ graphqlOperation["documentTemplateByTemplateCode"].call(["*"],{templateCode: props.templateCode}).then((result: any)=>{
34
+ template.value = result.editTemplate
35
+ templateScript.value = result.templateScript
36
+ })
37
+ }
38
+ }
39
+ },{immediate: true})
40
+ </script>
41
+ <template>
42
+ <form-pad :template="template" :template-script="templateScript" :parent-templates="parentTemplatesNext"></form-pad>
43
+ </template>
@@ -2,7 +2,15 @@
2
2
  import {computed, ref, watch} from 'vue'
3
3
  import * as prettier from 'prettier'
4
4
  import prettierPluginHtml from 'prettier/plugins/html'
5
- import {useDocumentTemplate, validationRulesRegex} from '../../composables/document/template'
5
+ import {useDocumentTemplate, validationRulesRegex,optionStringToChoiceObject} from '../../composables/document/template'
6
+
7
+ interface Props {
8
+ title?: string
9
+ }
10
+
11
+ const props = withDefaults(defineProps<Props>(), {
12
+ title: "Document Template"
13
+ })
6
14
 
7
15
  const emit = defineEmits(['update:modelValue'])
8
16
  const modelValue = defineModel<string>()
@@ -49,6 +57,33 @@ const headers = ref([
49
57
  },
50
58
  ])
51
59
 
60
+ const formTableHeaders = ref([
61
+ {
62
+ title: 'Title',
63
+ key: 'title',
64
+ },
65
+ {
66
+ title: 'Key',
67
+ key: 'key',
68
+ },
69
+ {
70
+ title: 'Width',
71
+ key: 'width',
72
+ },
73
+ ])
74
+
75
+ const choiceHeaders = ref([
76
+ {
77
+ title: 'Label',
78
+ key: 'label',
79
+ },
80
+ {
81
+ title: 'Value',
82
+ key: 'value',
83
+ },
84
+ ])
85
+
86
+
52
87
  function isValidJsonArrayOfObjects(str: string | undefined) {
53
88
  try {
54
89
  const parsed = JSON.parse(str as string)
@@ -72,17 +107,48 @@ async function convertToAdvanceMode() {
72
107
  modelValue.value = await prettier.format(useDocumentTemplate(templateItems.value).replaceAll('>', '>\n'), { parser: 'html', plugins: [prettierPluginHtml] })
73
108
  }
74
109
  }
110
+ const inputTypeChoice = ref([
111
+ { label: 'Text Field', value: 'VTextField' },
112
+ { label: 'Text Area', value: 'VTextarea' },
113
+ { label: 'Text Date Picker', value: 'FormDate' },
114
+ { label: 'Text Time Picker', value: 'FormTime' },
115
+ { label: 'Text Date & Time Picker', value: 'FormDateTime' },
116
+ { label: 'Select Dropdown', value: 'VSelect' },
117
+ { label: 'Select Combobox', value: 'VCombobox' },
118
+ { label: 'Autocomplete', value: 'VAutocomplete' },
119
+ { label: 'Autocomplete from Master', value: 'MasterAutocomplete' },
120
+ { label: 'Radio Buttons', value: 'VRadio' },
121
+ { label: 'Radio Buttons Inline', value: 'VRadioInline' },
122
+ { label: 'Checkbox', value: 'VCheckbox' },
123
+ { label: 'Switch', value: 'VSwitch' },
124
+ { label: 'File Upload', value: 'FormFile' },
125
+ { label: 'Signature Pad', value: 'FormSignPad' },
126
+ { label: 'Table', value: 'FormTable' },
127
+ { label: '[Decoration] Header', value: 'Header' },
128
+ { label: '[Decoration] Separator', value: 'Separator' },
129
+ { label: '[Advanced] Hidden Field', value: 'FormHidden' },
130
+ { label: '[Advanced] Inherit Form', value: 'DocumentForm' },
131
+ { label: '[Advanced] Custom Code', value: 'CustomCode' },
132
+ ]);
133
+
134
+ const requireOption = ref(['VSelect', 'VAutocomplete', 'VCombobox', 'VRadio', 'VRadioInline', 'MasterAutocomplete','FormTable','DocumentForm'])
135
+ const notRequireVariable = ref(['Header', 'Separator', 'CustomCode','DocumentForm'])
136
+ const notRequireLabel = ref(['Separator', 'CustomCode', 'FormFile', 'FormHidden','DocumentForm'])
137
+ const notRequireWidth = ref(['Separator', 'FormHidden','DocumentForm'])
138
+ const notRequireOptions = ref(['Separator','CustomCode', 'FormFile'])
139
+ const notRequireRules = ref(['Separator','Header','CustomCode','FormHidden','DocumentForm'])
140
+ const notRequireInputAttributes = ref(['CustomCode','Header', 'FormHidden','DocumentForm'])
141
+ const notRequireColumnAttributes = ref(['Separator', 'FormHidden','DocumentForm'])
142
+ const notRequireAdvancedSetting = ref(['Separator','CustomCode', 'FormHidden'])
75
143
 
76
- const inputTypeChoice = ref(['VTextField', 'VTextarea', 'VSelect', 'VAutocomplete', 'FormDate', 'FormTime', 'FormDateTime', 'VCombobox', 'VRadio', 'VRadioInline', 'VCheckbox', 'VSwitch', 'MasterAutocomplete', 'Header', 'Separator', 'CustomCode', 'FormTable', 'FormHidden', 'FormFile', 'FormSignPad'])
77
- const requireOption = ref(['VSelect', 'VAutocomplete', 'VCombobox', 'VRadio', 'VRadioInline', 'MasterAutocomplete'])
78
- const notRequireVariable = ref(['Header', 'Separator', 'CustomCode'])
79
- const notRequireLabel = ref(['Separator', 'CustomCode', 'FormFile', 'FormSignPad', 'FormTable', 'FormHidden'])
80
- const notRequireOptions = ref(['CustomCode', 'FormSignPad', 'FormFile', 'FormTable'])
81
- const notRequireRules = ref(['CustomCode', 'FormSignPad', 'FormFile', 'FormTable' ,'FormHidden'])
82
- const notRequireInputAttributes = ref(['CustomCode', 'FormHidden'])
83
- const notRequireColumnAttributes = ref(['Separator', 'FormHidden'])
144
+ const hasSpecificOption = ref(['FormHidden','FormTable'])
84
145
 
85
- const choiceOption = ref(['VSelect', 'VRadio', 'VRadioInline'])
146
+ const choiceOption = ref(['VRadio', 'VRadioInline','VSelect', 'VAutocomplete', 'VCombobox'])
147
+ const inputOptionsLabel = ref<Record<string,string>>({
148
+ 'MasterAutocomplete' : "Group Key",
149
+ 'Header' : "Class",
150
+ 'DocumentForm': "Template Code",
151
+ })
86
152
 
87
153
  const ruleOptions = (inputType: string) => (value: any) => {
88
154
  if (choiceOption.value.includes(inputType) && !(/^[^'",]+(,[^'",]+)*$/.test(value))) return 'Invalid options format'
@@ -96,7 +162,7 @@ const ruleOptions = (inputType: string) => (value: any) => {
96
162
  v-if="!isAdvanceMode"
97
163
  v-model="templateItems"
98
164
  :headers="headers"
99
- title="Document Template"
165
+ :title="props.title"
100
166
  >
101
167
  <template #toolbarItems>
102
168
  <VBtn
@@ -118,19 +184,20 @@ const ruleOptions = (inputType: string) => (value: any) => {
118
184
  v-model="data.inputType"
119
185
  label="Input Type"
120
186
  :items="inputTypeChoice"
187
+ item-title="label"
188
+ item-value="value"
189
+ :return-object="false"
121
190
  :rules="[rules.require()]"
122
191
  />
123
192
  </v-col>
124
- <v-col
125
- v-if="data.inputType!='Separator'"
126
- cols="1"
127
- >
193
+ <v-col cols="1" v-if="!notRequireWidth.includes(data.inputType)">
128
194
  <v-text-field
129
195
  v-model="data.width"
130
196
  label="Width"
131
197
  :rules="[rules.require()]"
132
198
  type="number"
133
199
  />
200
+ <form-hidden v-model="data.inputOptions" :item-value="data.inputType" :hook="()=>undefined"></form-hidden>
134
201
  </v-col>
135
202
  <v-col cols="4" v-if="!notRequireLabel.includes(data.inputType)">
136
203
  <v-text-field
@@ -150,32 +217,67 @@ const ruleOptions = (inputType: string) => (value: any) => {
150
217
  v-if="!notRequireOptions.includes(data.inputType)"
151
218
  cols="12"
152
219
  >
220
+ <form-pad v-model="data.inputOptions" v-if="data.inputType=='FormTable'">
221
+ <template #default="{data: optionData}">
222
+ <v-row dense>
223
+ <v-col cols="12">
224
+ <form-table v-model="optionData.headers" :headers="formTableHeaders" title="Headers">
225
+ <template #form="{data: headerData,rules}">
226
+ <v-container fluid>
227
+ <v-row dense>
228
+ <v-col cols="6"><v-text-field v-model="headerData.title" label="Title"></v-text-field></v-col>
229
+ <v-col cols="3"><v-text-field v-model="headerData.key" label="Key" :rules="[rules.require()]"></v-text-field></v-col>
230
+ <v-col cols="3"><v-text-field v-model="headerData.width" label="Width"></v-text-field></v-col>
231
+ </v-row>
232
+ </v-container>
233
+ </template>
234
+ </form-table>
235
+ </v-col>
236
+ <v-col cols="12">
237
+ <document-template-builder v-model="optionData.formTemplate" title="Form Template"></document-template-builder>
238
+ </v-col>
239
+ </v-row>
240
+ </template>
241
+ </form-pad>
242
+ <form-pad v-model="data.inputOptions" v-if="data.inputType=='FormHidden'">
243
+ <template #default="{data: optionData}">
244
+ <v-row dense>
245
+ <v-col cols="12">
246
+ <v-text-field
247
+ v-model="optionData.hook"
248
+ label="Hook"
249
+ :rules="[rules.require()]"
250
+ />
251
+ </v-col>
252
+ <v-col cols="12">
253
+ <v-text-field
254
+ v-model="optionData.itemValue"
255
+ label="Item Value"
256
+ />
257
+ </v-col>
258
+ </v-row>
259
+ </template>
260
+ </form-pad>
261
+ <form-table v-model="data.inputOptions" :headers="choiceHeaders" title="Choices" v-if="choiceOption.includes(data.inputType) && (!data.inputOptions || typeof data.inputOptions === 'object')">
262
+ <template #form="{data: optionData,rules}">
263
+ <v-container fluid>
264
+ <v-row dense>
265
+ <v-col cols="6"><v-text-field v-model="optionData.label" label="Label"></v-text-field></v-col>
266
+ <v-col cols="6"><v-text-field v-model="optionData.value" label="Value" :rules="[rules.require()]"></v-text-field></v-col>
267
+ </v-row>
268
+ </v-container>
269
+ </template>
270
+ </form-table>
271
+ <form-hidden v-model="data.inputOptions" :itemValue="data.inputOptions" :hook="(option: any)=>optionStringToChoiceObject(option)" v-if="choiceOption.includes(data.inputType) && data.inputOptions && typeof data.inputOptions === 'string'"></form-hidden>
153
272
  <v-textarea
154
273
  v-model="data.inputOptions"
155
- label="Input Options"
274
+ :label="inputOptionsLabel[data.inputType] || 'Input Options'"
156
275
  auto-grow
157
276
  :rules="[rules.requireIf(requireOption.includes(data.inputType)), ruleOptions(data.inputType)]"
277
+ v-if="!hasSpecificOption.includes(data.inputType) && !choiceOption.includes(data.inputType)"
158
278
  />
159
279
  </v-col>
160
- <v-col v-if="data.inputType!='CustomCode'">
161
- <v-text-field
162
- v-model="data.validationRules"
163
- label="Validation Rules"
164
- :rules="[rules.regex(validationRulesRegex)]"
165
- />
166
- </v-col>
167
- <v-col v-if="data.inputType!='CustomCode'">
168
- <v-text-field
169
- v-model="data.inputAttributes"
170
- label="Input Attributes"
171
- />
172
- </v-col>
173
- <v-col v-if="data.inputType!='Separator'">
174
- <v-text-field
175
- v-model="data.columnAttributes"
176
- label="Column Attributes"
177
- />
178
- </v-col>
280
+
179
281
  <v-col
180
282
  v-if="data.inputType=='CustomCode'"
181
283
  cols="12"
@@ -186,25 +288,67 @@ const ruleOptions = (inputType: string) => (value: any) => {
186
288
  :rules="[rules.require()]"
187
289
  />
188
290
  </v-col>
189
- <v-col
190
- v-if="data.inputType=='FormTable'"
191
- cols="12"
192
- >
193
- <FormCodeEditor
194
- v-model="data.inputFormTable"
195
- label="Form Table"
196
- :rules="[rules.require()]"
197
- />
198
- </v-col>
199
- <v-col
200
- v-if="data.inputType=='FormHidden'"
201
- cols="12"
202
- >
203
- <FormCodeEditor
204
- v-model="data.inputFormHidden"
205
- label="Form Table"
206
- :rules="[rules.require()]"
207
- />
291
+ </v-row>
292
+ <v-row dense>
293
+ <v-col>
294
+ <v-expansion-panels>
295
+ <v-expansion-panel v-if="!notRequireRules.includes(data.inputType)">
296
+ <v-expansion-panel-title collapse-icon="mdi mdi-minus" expand-icon="mdi mdi-plus" class="font-weight-bold">Validations</v-expansion-panel-title>
297
+ <v-expansion-panel-text>
298
+ <v-container fluid>
299
+ <v-row dense>
300
+ <v-col cols="12">
301
+ <v-text-field
302
+ v-model="data.validationRules"
303
+ label="Validation Rules"
304
+ :rules="[rules.regex(validationRulesRegex)]"
305
+ />
306
+ <b>Available rules :</b> require, requireIf(condition), requireTrue, requireTrueIf(condition), numeric, range(min,max), integer, unique, length(length), lengthGreater(length), lengthLess(length), telephone, email, regex(regex), idcard, DateFuture, DatetimeFuture, DateHappen, DatetimeHappen, DateAfter(date), DateBefore(Date), DateEqual(date)
307
+ </v-col>
308
+ </v-row>
309
+ </v-container>
310
+ </v-expansion-panel-text>
311
+ </v-expansion-panel>
312
+ <v-expansion-panel v-if="!notRequireAdvancedSetting.includes(data.inputType)">
313
+ <v-expansion-panel-title collapse-icon="mdi mdi-minus" expand-icon="mdi mdi-plus" class="font-weight-bold">Advanced settings</v-expansion-panel-title>
314
+ <v-expansion-panel-text>
315
+ <v-container fluid>
316
+ <v-row dense>
317
+ <v-col cols="12" md="6" v-if="!notRequireInputAttributes.includes(data.inputType)">
318
+ <v-text-field
319
+ v-model="data.inputAttributes"
320
+ label="Input Attributes"
321
+ />
322
+ </v-col>
323
+ <v-col cols="12" md="6" v-if="!notRequireColumnAttributes.includes(data.inputType)">
324
+ <v-text-field
325
+ v-model="data.columnAttributes"
326
+ label="Column Attributes"
327
+ />
328
+ </v-col>
329
+ <v-col cols="12" md="6">
330
+ <v-text-field
331
+ v-model="data.conditionalDisplay"
332
+ label="Conditional Display"
333
+ />
334
+ </v-col>
335
+ <v-col cols="12" md="6">
336
+ <v-text-field
337
+ v-model="data.computedValue"
338
+ label="Computed Value"
339
+ />
340
+ </v-col>
341
+ <v-col cols="12" md="6">
342
+ <v-text-field
343
+ v-model="data.retrievedValue"
344
+ label="Retrieved Value"
345
+ />
346
+ </v-col>
347
+ </v-row>
348
+ </v-container>
349
+ </v-expansion-panel-text>
350
+ </v-expansion-panel>
351
+ </v-expansion-panels>
208
352
  </v-col>
209
353
  </v-row>
210
354
  </v-container>
@@ -223,14 +367,6 @@ const ruleOptions = (inputType: string) => (value: any) => {
223
367
  <template v-if="props.item.inputAttributes">
224
368
  <b>Input Attributes :</b> {{ props.item.inputAttributes }}<br>
225
369
  </template>
226
- <template v-if="props.item.inputType=='FormTable'">
227
- <b>Form Table :</b><br>
228
- <span style="white-space: pre-line">{{ props.item.inputFormTable }}</span>
229
- </template>
230
- <template v-if="props.item.inputType=='FormHidden'">
231
- <b>Form Hidden :</b><br>
232
- <span style="white-space: pre-line">{{ props.item.inputFormHidden }}</span>
233
- </template>
234
370
  </template>
235
371
  </FormTable>
236
372
  <FormCodeEditor