blob: 77f509af36ddf2183d8f5f3895ffc863f1b37eab [file] [log] [blame]
// 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>
<div>
<a-card
class="ant-form-text"
v-if="description && description.length > 0"
v-html="$t(description)">
</a-card>
<a-form
v-ctrl-enter="handleSubmit"
class="form-content"
:ref="formRef"
:model="form"
:rules="rules"
@finish="handleSubmit"
>
<div v-for="(field, index) in fields" :key="index">
<a-form-item
:name="field.key"
:ref="field.key"
:label="$t(field.title)"
v-if="isDisplayInput(field)"
v-bind="formItemLayout"
:has-feedback="field.switch ? false : true">
<a-select
v-if="field.select"
v-model:value="form[field.key]"
:allowClear="true"
v-focus="index === 0"
showSearch
optionFilterProp="label"
:filterOption="(input, option) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
}" >
<a-select-option
v-for="option in field.options"
:key="option.id"
:value="option.id"
:label="option.name || option.description"
>
{{ option.name || option.description }}
</a-select-option>
</a-select>
<a-switch
v-else-if="field.switch"
v-model:checked="form[field.key]"
v-focus="index === 0"
/>
<a-checkbox
v-else-if="field.checkbox"
v-model:checked="form[field.key]"
v-focus="index === 0">
</a-checkbox>
<a-input
v-else-if="field.password"
type="password"
v-model:value="form[field.key]"
v-focus="index === 0"
/>
<a-radio-group
v-else-if="field.radioGroup"
v-model:value="form[field.key]"
buttonStyle="solid">
<span
style="margin-right: 5px;"
v-for="(radioItem, idx) in field.radioOption"
:key="idx">
<a-radio-button
:value="radioItem.value"
v-if="isDisplayItem(radioItem.condition)">
{{ $t(radioItem.label) }}
</a-radio-button>
</span>
<a-alert style="margin-top: 5px" type="warning" v-if="field.alert && isDisplayItem(field.alert.display)">
<template #message>
<span v-html="$t(field.alert.message)" />
</template>
</a-alert>
</a-radio-group>
<a-input
v-else
v-model:value="form[field.key]"
v-focus="index === 0"
/>
</a-form-item>
</div>
</a-form>
<div class="form-action">
<a-button
v-if="!isFixError"
class="button-prev"
@click="handleBack">
{{ $t('label.previous') }}
</a-button>
<a-button class="button-next" ref="submit" type="primary" @click="handleSubmit">
{{ $t('label.next') }}
</a-button>
</div>
</div>
</template>
<script>
import { ref, reactive, toRaw } from 'vue'
export default {
props: {
prefillContent: {
type: Object,
default: function () {
return {}
}
},
fields: {
type: Array,
default: function () {
return []
}
},
description: {
type: String,
default: 'label.creating.iprange'
},
isFixError: {
type: Boolean,
default: false
}
},
created () {
this.initForm()
},
computed: {
hypervisor () {
return this.prefillContent?.hypervisor || null
}
},
mounted () {
this.fillValue()
},
data: () => ({
formItemLayout: {
labelCol: { span: 8 },
wrapperCol: { span: 12 }
},
ipV4Regex: /^(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)$/i,
ipV6Regex: /^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$/i,
formModel: {}
}),
watch: {
formModel: {
deep: true,
handler (changedFields) {
const fieldsChanged = toRaw(changedFields)
this.$emit('fieldsChanged', fieldsChanged)
}
},
'prefillContent.provider' (val) {
if (['SolidFire', 'PowerFlex'].includes(val)) {
this.form.primaryStorageProtocol = 'custom'
}
}
},
methods: {
initForm () {
this.formRef = ref()
this.form = reactive({})
this.rules = reactive({})
},
fillValue () {
this.fields.forEach(field => {
this.setRules(field)
const fieldExists = this.isDisplayInput(field)
if (!fieldExists) {
return
}
if (field.key === 'agentUserName' && !this.getPrefilled(field)) {
this.form[field.key] = 'Oracle'
} else {
if (field.switch || field.checkbox) {
this.form[field.key] = this.isChecked(field)
} else {
this.form[field.key] = this.getPrefilled(field)
}
}
})
this.formModel = toRaw(this.form)
},
setRules (field) {
this.rules[field.key] = []
if (field.required) {
this.rules[field.key].push({ required: field.required, message: this.$t(field.placeHolder) })
}
if (field.ipV4 || field.ipV6) {
this.rules[field.key].push({
ipV4: field.ipV4,
ipV6: field.ipV6,
validator: this.checkIpFormat,
message: this.$t(field.message)
})
}
},
getPrefilled (field) {
if (field.key === 'authmethod' && this.hypervisor !== 'KVM') {
return field.value || field.defaultValue || 'password'
}
return this.prefillContent?.[field.key] || field.value || field.defaultValue || null
},
handleSubmit () {
this.formRef.value.validate().then(() => {
if (this.isFixError) {
this.$emit('submitLaunchZone')
return
}
this.$emit('nextPressed')
}).catch(error => {
this.formRef.value.scrollToField(error.errorFields[0].name)
})
},
handleBack () {
this.$emit('backPressed')
},
async checkIpFormat (rule, value) {
if (!value || value === '') {
return Promise.resolve()
} else if (rule.ipV4 && !this.ipV4Regex.test(value)) {
return Promise.reject(rule.message)
} else if (rule.ipV6 && !this.ipV6Regex.test(value)) {
return Promise.reject(rule.message)
} else {
return Promise.resolve()
}
},
isDisplayInput (field) {
if (!field.display && !field.hidden) {
return true
}
const conditions = field.display || field.hidden
if (!conditions || Object.keys(conditions).length === 0) {
return true
}
let isShow = true
Object.keys(conditions).forEach(key => {
if (isShow) {
const condition = conditions[key]
const fieldVal = this.form[key]
? this.form[key]
: (this.prefillContent?.[key] || null)
if (field.hidden) {
if (Array.isArray(condition) && condition.includes(fieldVal)) {
isShow = false
} else if (!Array.isArray(condition) && fieldVal === condition) {
isShow = false
}
} else if (field.display) {
if (Array.isArray(condition) && !condition.includes(fieldVal)) {
isShow = false
} else if (!Array.isArray(condition) && fieldVal !== condition) {
isShow = false
}
}
}
})
return isShow
},
isChecked (field) {
if (this.prefillContent[field.key]) {
return this.prefillContent[field.key]
}
if (!field.checked) {
return false
}
return true
},
isDisplayItem (conditions) {
if (!conditions || Object.keys(conditions).length === 0) {
return true
}
let isShow = true
Object.keys(conditions).forEach(key => {
if (!isShow) return false
const condition = conditions[key]
const fieldVal = this.form[key]
? this.form[key]
: (this.prefillContent?.[key] || null)
if (Array.isArray(condition) && !condition.includes(fieldVal)) {
isShow = false
} else if (!Array.isArray(condition) && fieldVal !== condition) {
isShow = false
}
})
return isShow
}
}
}
</script>
<style scoped lang="less">
.form-content {
border: 1px dashed #e9e9e9;
border-radius: 6px;
background-color: #fafafa;
min-height: 200px;
text-align: center;
vertical-align: center;
margin-top: 8px;
max-height: 300px;
overflow-y: auto;
padding: 16px 20px 0;
:deep(.has-error) {
.ant-form-explain {
text-align: left;
}
}
:deep(.ant-form-item-control) {
text-align: left;
}
}
.ant-form-text {
text-align: justify;
margin: 10px 0;
padding: 24px;
width: 100%;
}
.form-action {
margin-top: 16px;
}
</style>