/ src / renderer / components / common / ConfigJsonCard.vue
ConfigJsonCard.vue
 1  <script setup lang="ts">
 2  import { ref, computed, watch } from 'vue'
 3  
 4  defineOptions({
 5    inheritAttrs: false
 6  })
 7  
 8  const emit = defineEmits(['update:modelValue', 'onError', 'focus', 'blur'])
 9  
10  type JSONValue = string | number | boolean | null | JSONValue[] | { [key: string]: JSONValue }
11  
12  const props = defineProps({
13    modelValue: {
14      type: Object as () => {},
15      required: true
16    }
17  })
18  
19  const handleFocus = () => {
20    emit('focus')
21  }
22  
23  const handleBlur = () => {
24    emit('blur')
25  }
26  
27  const json2Str = (json: JSONValue | {}) => {
28    return JSON.stringify(json, null, 2)
29  }
30  
31  const { modelValue: jsonParams } = props
32  
33  const jsonString = ref(json2Str(jsonParams))
34  
35  const editableSamplingParams = computed({
36    get: () => jsonString.value,
37    set: (value) => {
38      console.log('JSON changed: ', value)
39      jsonString.value = value
40      try {
41        const parsed = JSON.parse(value)
42        emit('update:modelValue', parsed)
43        jsonError.value = null
44        emit('onError', null)
45      } catch (e: any) {
46        jsonError.value = e.message
47        emit('onError', e.message)
48      }
49    }
50  })
51  
52  const jsonError = ref<string | null>(null)
53  
54  watch(
55    () => jsonParams,
56    (newVal) => {
57      jsonString.value = json2Str(newVal)
58    },
59    { deep: true }
60  )
61  </script>
62  
63  <template>
64    <v-card variant="text">
65      <v-card-text>
66        <v-textarea
67          v-model="editableSamplingParams"
68          variant="solo"
69          outlined
70          auto-grow
71          v-bind="$attrs"
72          :error-messages="jsonError"
73          :hide-details="!Boolean(jsonError ?? '')"
74          @focus="handleFocus"
75          @blur="handleBlur"
76        ></v-textarea>
77      </v-card-text>
78    </v-card>
79  </template>