| // Licensed to the Apache Software Foundation (ASF) under one | |
| // or more contributor license agreements. See the NOTICE file | |
| // distributed with this work for additional information | |
| // regarding copyright ownership. The ASF licenses this file | |
| // to you under the Apache License, Version 2.0 (the | |
| // "License"); you may not use this file except in compliance | |
| // with the License. You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, | |
| // software distributed under the License is distributed on an | |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
| // KIND, either express or implied. See the License for the | |
| // specific language governing permissions and limitations | |
| // under the License. | |
| <template> | |
| <a-card> | |
| <a-row :gutter="[16, 8]"> | |
| <a-col :span="18"> | |
| <a-row :gutter="[16, 8]"> | |
| <a-col :span="18"> | |
| <a-form-item no-style> | |
| <tooltip-label :title="$t('label.name')" /> | |
| <a-input | |
| v-model:value="newParam.name" | |
| :placeholder="$t('label.name')" | |
| class="input-field" | |
| /> | |
| </a-form-item> | |
| </a-col> | |
| <a-col :span="6" style="display: flex; align-items: flex-end;"> | |
| <a-form-item no-style> | |
| <a-checkbox | |
| v-model:checked="newParam.required" | |
| class="required-checkbox" | |
| > | |
| Required | |
| </a-checkbox> | |
| </a-form-item> | |
| </a-col> | |
| <a-col :span="12"> | |
| <a-form-item no-style> | |
| <tooltip-label :title="$t('label.type')" /> | |
| <a-select | |
| v-model:value="newParam.type" | |
| :placeholder="$t('label.type')" | |
| class="input-field" | |
| @change="onNewParamTypeChange" | |
| > | |
| <a-select-option | |
| v-for="t in types" | |
| :key="t" | |
| :value="t" | |
| > | |
| {{ t }} | |
| </a-select-option> | |
| </a-select> | |
| </a-form-item> | |
| </a-col> | |
| <a-col :span="12"> | |
| <a-form-item no-style> | |
| <tooltip-label :title="$t('label.validationformat')" :tooltip="$t('message.desc.validationformat')" /> | |
| <a-select | |
| :disabled="!['NUMBER', 'STRING'].includes(newParam.type)" | |
| v-model:value="newParam.validationformat" | |
| :placeholder="$t('message.desc.validationformat')" | |
| class="input-field" | |
| > | |
| <a-select-option | |
| v-for="t in newParamFormats" | |
| :key="t" | |
| :value="t" | |
| > | |
| {{ t }} | |
| </a-select-option> | |
| </a-select> | |
| </a-form-item> | |
| </a-col> | |
| <a-col :span="24"> | |
| <a-form-item no-style> | |
| <tooltip-label :title="$t('label.valueoptions')" :tooltip="$t('message.desc.valueoptions')" /> | |
| <a-input | |
| :disabled="!['NUMBER', 'STRING'].includes(newParam.type)" | |
| v-model:value="newParam.valueoptions" | |
| :placeholder="$t('message.desc.valueoptions')" | |
| class="input-field" | |
| /> | |
| </a-form-item> | |
| </a-col> | |
| </a-row> | |
| </a-col> | |
| <a-col :span="6" style="display: flex; align-items: flex-end; justify-content: center;"> | |
| <a-button | |
| type="primary" | |
| class="add-button" | |
| @click="addEntry" | |
| :disabled="!newParam.name || !newParam.type" | |
| > | |
| Add | |
| </a-button> | |
| </a-col> | |
| </a-row> | |
| <a-table | |
| :columns="columns" | |
| :dataSource="tableData" | |
| rowKey="name" | |
| size="small" | |
| :pagination="false" | |
| :showHeader="showTableHeaders" | |
| class="table" | |
| > | |
| <template #bodyCell="{ column, record }"> | |
| <template v-if="column.key === 'actions'"> | |
| <template v-if="record.editing"> | |
| <div class="flex-gap"> | |
| <tooltip-button :tooltip="$t('label.ok')" icon="check-outlined" @onClick="saveEdit(record)" /> | |
| <tooltip-button :tooltip="$t('label.cancel')" icon="close-outlined" @onClick="cancelEdit(record)" /> | |
| </div> | |
| </template> | |
| <template v-else> | |
| <div class="flex-gap"> | |
| <tooltip-button :tooltip="$t('label.edit')" icon="edit-outlined" @onClick="editRow(record)" /> | |
| <tooltip-button type="danger" :tooltip="$t('label.remove')" icon="delete-outlined" @onClick="removeEntry(record.name)" /> | |
| </div> | |
| </template> | |
| </template> | |
| <template v-else-if="record.editing"> | |
| <a-form-item no-style> | |
| <a-input v-if="column.key === 'name'" v-model:value="editBuffer.name" /> | |
| </a-form-item> | |
| <a-form-item no-style> | |
| <a-select v-if="column.key === 'type'" v-model:value="editBuffer.type" @change="onEditBufferTypeChange"> | |
| <a-select-option v-for="t in types" :key="t" :value="t">{{ t }}</a-select-option> | |
| </a-select> | |
| </a-form-item> | |
| <a-form-item no-style> | |
| <a-select v-if="column.key === 'validationformat'" :disabled="!['NUMBER', 'STRING'].includes(editBuffer.type)" v-model:value="editBuffer.validationformat"> | |
| <a-select-option v-for="t in editBufferFormats" :key="t" :value="t">{{ t }}</a-select-option> | |
| </a-select> | |
| </a-form-item> | |
| <a-form-item no-style> | |
| <a-input v-if="column.key === 'valueoptions'" :disabled="!['NUMBER', 'STRING'].includes(editBuffer.type)" v-model:value="editBuffer.valueoptions" /> | |
| </a-form-item> | |
| <a-form-item no-style> | |
| <a-checkbox v-if="column.key === 'required'" v-model:checked="editBuffer.required" /> | |
| </a-form-item> | |
| </template> | |
| <template v-else> | |
| <template v-if="column.key === 'required'">{{ record.required ? 'Yes' : 'No' }}</template> | |
| <template v-else-if="column.key === 'valueoptions'"> | |
| {{ Array.isArray(record.valueoptions) ? record.valueoptions.join(',') : record.valueoptions }} | |
| </template> | |
| <template v-else>{{ record[column.key] }}</template> | |
| </template> | |
| </template> | |
| </a-table> | |
| </a-card> | |
| </template> | |
| <script> | |
| import TooltipButton from '@/components/widgets/TooltipButton' | |
| import TooltipLabel from '@/components/widgets/TooltipLabel' | |
| export default { | |
| name: 'ParametersInput', | |
| components: { | |
| TooltipButton, | |
| TooltipLabel | |
| }, | |
| props: { | |
| value: { | |
| type: Array, | |
| default: () => [] | |
| }, | |
| showTableHeaders: { | |
| type: Boolean, | |
| default: true | |
| } | |
| }, | |
| data () { | |
| return { | |
| newParam: {}, | |
| columns: [ | |
| { title: this.$t('label.name'), dataIndex: 'name', key: 'name', width: '20%' }, | |
| { title: this.$t('label.type'), dataIndex: 'type', key: 'type', width: '15%' }, | |
| { title: this.$t('label.validationformat'), dataIndex: 'validationformat', key: 'validationformat', width: '15%' }, | |
| { title: this.$t('label.valueoptions'), dataIndex: 'valueoptions', key: 'valueoptions', width: '25%' }, | |
| { title: this.$t('label.required'), dataIndex: 'required', key: 'required', width: '10%' }, | |
| { title: this.$t('label.actions'), key: 'actions', width: '15%' } | |
| ], | |
| tableData: [], | |
| editBuffer: null | |
| } | |
| }, | |
| watch: { | |
| value: { | |
| immediate: true, | |
| handler (newVal) { | |
| this.tableData = (newVal || []).map(p => ({ | |
| ...p, | |
| editing: false | |
| })) | |
| } | |
| } | |
| }, | |
| emits: ['update:value'], | |
| computed: { | |
| types () { | |
| return [ | |
| 'BOOLEAN', | |
| 'DATE', | |
| 'NUMBER', | |
| 'STRING' | |
| ] | |
| }, | |
| newParamFormats () { | |
| return this.getFormatOptions(this.newParam?.type) | |
| }, | |
| editBufferFormats () { | |
| return this.getFormatOptions(this.editBuffer?.type) | |
| } | |
| }, | |
| methods: { | |
| getFormatOptions (type) { | |
| const formats = ['NONE'] | |
| if (type === 'STRING') { | |
| formats.push('EMAIL', 'PASSWORD', 'URL', 'UUID') | |
| } else if (type === 'NUMBER') { | |
| formats.push('DECIMAL') | |
| } | |
| return formats | |
| }, | |
| resetFormatAndOptions (obj) { | |
| delete obj.validationformat | |
| delete obj.valueoptions | |
| }, | |
| onNewParamTypeChange () { | |
| this.resetFormatAndOptions(this.newParam) | |
| }, | |
| onEditBufferTypeChange () { | |
| this.resetFormatAndOptions(this.editBuffer) | |
| }, | |
| addEntry () { | |
| const existingIndex = this.tableData.findIndex(row => row.name === this.newParam.name) | |
| if (existingIndex !== -1) { | |
| this.tableData[existingIndex] = { ...this.newParam } | |
| } else { | |
| this.tableData.push({ ...this.newParam, editing: false }) | |
| } | |
| this.updateData() | |
| this.newParam = {} | |
| }, | |
| removeEntry (name) { | |
| this.tableData = this.tableData.filter(item => item.name !== name) | |
| this.updateData() | |
| }, | |
| editRow (record) { | |
| this.editBuffer = { ...record } | |
| if (Array.isArray(this.editBuffer.valueoptions)) { | |
| this.editBuffer.valueoptions = this.editBuffer.valueoptions.join(',') | |
| } | |
| record.editing = true | |
| }, | |
| cancelEdit (record) { | |
| record.editing = false | |
| this.editBuffer = {} | |
| }, | |
| saveEdit (record) { | |
| if (!this.editBuffer) return | |
| Object.assign(record, this.editBuffer) | |
| if (!this.editBuffer.validationformat) { | |
| delete record.validationformat | |
| } | |
| if (!this.editBuffer.valueoptions) { | |
| delete record.valueoptions | |
| } | |
| record.editing = false | |
| this.updateData() | |
| this.editBuffer = {} | |
| }, | |
| updateData () { | |
| const data = this.tableData.map(({ name, type, validationformat, valueoptions, required }) => ({ | |
| name, | |
| type, | |
| validationformat, | |
| valueoptions: Array.isArray(valueoptions) ? valueoptions.join(',') : valueoptions, | |
| required | |
| })) | |
| this.$emit('update:value', data) | |
| } | |
| } | |
| } | |
| </script> | |
| <style scoped> | |
| .input-row { | |
| display: grid; | |
| grid-template-columns: 1fr auto; /* First column flexible, second column auto-sized */ | |
| grid-template-rows: auto auto auto; | |
| gap: 8px 16px; /* row-gap and column-gap */ | |
| align-items: center; | |
| } | |
| .grid-cell { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 4px; | |
| } | |
| .input-field { | |
| width: 100%; | |
| } | |
| .add-button { | |
| white-space: nowrap; | |
| } | |
| .table { | |
| margin-top: 10px; | |
| width: 100%; | |
| } | |
| .flex-gap { | |
| display: flex; | |
| gap: 8px; | |
| } | |
| </style> |