Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions apps/application/flow/step_node/form_node/impl/base_form_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,22 @@
from application.flow.i_step_node import NodeResult
from application.flow.step_node.form_node.i_form_node import IFormNode

multi_select_list = [
'MultiSelect',
'MultiRow'
]


def get_default_option(option_list, _type, value_field):
try:
if option_list is not None and isinstance(option_list, list) and len(option_list) > 0:
default_value_list = [o.get(value_field) for o in option_list if o.get('default')]
if len(default_value_list) == 0:
return [option_list[0].get(
value_field)] if _type == 'MultiSelect' else option_list[0].get(
value_field)] if multi_select_list.__contains__(_type) else option_list[0].get(
value_field)
else:
if _type == 'MultiSelect':
if multi_select_list.__contains__(_type):
return default_value_list
else:
return default_value_list[0]
Expand Down Expand Up @@ -84,7 +89,7 @@ def reset_field(self, field):
if tooltip is not None:
_value.get('attrs')['tooltip'] = generate_prompt(self.workflow_manage, tooltip)

if ['SingleSelect', 'MultiSelect', 'RadioCard', 'RadioRow'].__contains__(field.get('input_type')):
if ['SingleSelect', 'MultiSelect', 'RadioCard', 'RadioRow', 'MultiRow'].__contains__(field.get('input_type')):
if field.get('assignment_method') == 'ref_variables':
option_list = self.workflow_manage.get_reference_field(field.get('option_list')[0],
field.get('option_list')[1:])
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are no significant irregularities or potential issues in this code. However, there are a few minor optimizations that can be made:

  1. Replace list.__contains__ with in operator in both if statements to improve readability.

  2. Move the declaration of multi_select_list outside the functions and define it at class level, where applicable, especially if used frequently across multiple methods. This will make the function more concise and reusable.

  3. Consider using a set instead of list for multi_select_list since sets offer O(1) average time complexity for membership checks.

Here's an example of how you could refactor these changes:

# Define multi-select options as a set for faster membership-checking
multi_select_set = {'.MultiSelect', 'MultiRow'}

def get_default_option(option_list, _type, value_field):
    # ... rest of the code remains similar ...

def reset_field(self, field):
    # ... rest of the code remains similar ...

These small improvements enhance readability and maintainability while keeping the logic essentially unchanged.

Expand Down
4 changes: 4 additions & 0 deletions ui/src/components/dynamics-form/constructor/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ const input_type_list = [
label: t('dynamicsForm.input_type_list.RadioRow'),
value: 'RadioRow',
},
{
label: t('dynamicsForm.input_type_list.MultiRow'),
value: 'MultiRow',
},
{
label: t('dynamicsForm.input_type_list.Slider'),
value: 'Slider',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
<template>
<el-form-item v-if="getModel">
<template #label>
<div class="flex-between">
{{ $t('dynamicsForm.AssignmentMethod.label', '赋值方式') }}
</div>
</template>

<el-row style="width: 100%" :gutter="10">
<el-radio-group @change="formValue.option_list = []" v-model="formValue.assignment_method">
<el-radio :value="item.value" size="large" v-for="item in assignment_method_option_list"
>{{ item.label }}
<el-popover
width="300px"
v-if="item.value == 'ref_variables'"
class="box-item"
placement="top-start"
>
{{ $t('dynamicsForm.AssignmentMethod.ref_variables.popover') }}:<br />
[<br />
{<br />
"label": "xx",<br />
"value": "xx",<br />
"default": false<br />
}<br />
]<br />
label: {{ $t('dynamicsForm.AssignmentMethod.ref_variables.popover_label') }}
{{ $t('common.required') }}<br />
value: {{ $t('dynamicsForm.AssignmentMethod.ref_variables.popover_value') }}
{{ $t('common.required') }}<br />
default:{{ $t('dynamicsForm.AssignmentMethod.ref_variables.popover_default') }}
<template #reference>
<el-icon><InfoFilled /></el-icon>
</template>
</el-popover>
</el-radio>
</el-radio-group>
</el-row>
</el-form-item>
<el-form-item
v-if="formValue.assignment_method == 'ref_variables'"
:required="true"
prop="option_list"
:rules="[default_ref_variables_value_rule]"
>
<NodeCascader
ref="nodeCascaderRef"
:nodeModel="model"
class="w-full"
:placeholder="$t('views.applicationWorkflow.variable.placeholder')"
v-model="formValue.option_list"
/>
</el-form-item>
<el-form-item v-if="formValue.assignment_method == 'custom'">
<template #label>
<div class="flex-between">
{{ $t('dynamicsForm.Select.label') }}
<el-button link type="primary" @click.stop="addOption()">
<AppIcon iconName="app-add-outlined" class="mr-4"></AppIcon>
{{ $t('common.add') }}
</el-button>
</div>
</template>

<el-row style="width: 100%" :gutter="10">
<el-col :span="10">
<div class="grid-content ep-bg-purple" />
{{ $t('dynamicsForm.tag.label') }}
</el-col>
<el-col :span="12">
<div class="grid-content ep-bg-purple" />
{{ $t('dynamicsForm.Select.label') }}
</el-col>
</el-row>
<el-row
style="width: 100%"
v-for="(option, $index) in formValue.option_list"
:key="$index"
:gutter="10"
class="mb-8"
>
<el-col :span="10">
<div class="grid-content ep-bg-purple" />
<el-input
v-model="formValue.option_list[$index].label"
:placeholder="$t('dynamicsForm.tag.placeholder')"
/>
</el-col>
<el-col :span="12">
<div class="grid-content ep-bg-purple" />
<el-input
v-model="formValue.option_list[$index].value"
:placeholder="$t('dynamicsForm.Select.label')"
/>
</el-col>
<el-col :span="1">
<div class="grid-content ep-bg-purple" />
<el-button link class="ml-8" @click.stop="delOption($index)">
<AppIcon iconName="app-delete"></AppIcon>
</el-button>
</el-col>
</el-row>
</el-form-item>
<el-form-item
v-if="formValue.assignment_method == 'custom'"
class="defaultValueItem"
:label="$t('dynamicsForm.default.label')"
:required="formValue.required"
prop="default_value"
:rules="
formValue.required
? [
{
required: true,
message: `${$t('dynamicsForm.default.label')}${$t('dynamicsForm.default.requiredMessage')}`,
},
]
: []
"
>
<div class="defaultValueCheckbox">
<el-checkbox
v-model="formValue.show_default_value"
:label="$t('dynamicsForm.default.show')"
/>
</div>
<MultiRow
:form-field="formField"
v-model="formValue.default_value"
:other-params="{}"
field="default_value"
>
</MultiRow>
</el-form-item>
</template>
<script setup lang="ts">
import { computed, onMounted, inject } from 'vue'
import MultiRow from '@/components/dynamics-form/items/MultiRow.vue'
import NodeCascader from '@/workflow/common/NodeCascader.vue'
import type { FormField } from '@/components/dynamics-form/type'
import { t } from '@/locales'
const getModel = inject('getModel') as any

const assignment_method_option_list = computed(() => {
const option_list = [
{
label: t('dynamicsForm.AssignmentMethod.custom.label', '自定义'),
value: 'custom',
},
]
if (getModel) {
option_list.push({
label: t('dynamicsForm.AssignmentMethod.ref_variables.label', '引用变量'),
value: 'ref_variables',
})
}
return option_list
})

const model = computed(() => {
if (getModel) {
return getModel()
} else {
return null
}
})
const props = defineProps<{
modelValue: any
}>()
const emit = defineEmits(['update:modelValue'])
const formValue = computed({
set: (item) => {
emit('update:modelValue', item)
},
get: () => {
return props.modelValue
},
})

const default_ref_variables_value_rule = {
required: true,
validator: (rule: any, value: any, callback: any) => {
console.log(value.length)
if (!(Array.isArray(value) && value.length > 1)) {
callback(
t('dynamicsForm.AssignmentMethod.ref_variables.label', '引用变量') + t('common.required'),
)
}

return true
},
trigger: 'blur',
}
const addOption = () => {
formValue.value.option_list.push({ value: '', label: '' })
}

const delOption = (index: number) => {
const option = formValue.value.option_list[index]
if (option.value && formValue.value.default_value == option.value) {
formValue.value.default_value = ''
}
formValue.value.option_list.splice(index, 1)
}
const formField = computed<FormField>(() => {
return { field: '', ...getData() }
})
const getData = () => {
return {
input_type: 'MultiRow',
attrs: {},
default_value: formValue.value.default_value,
text_field: 'label',
value_field: 'value',
option_list: formValue.value.option_list,
assignment_method: formValue.value.assignment_method || 'custom',
}
}
const rander = (form_data: any) => {
formValue.value.option_list = form_data.option_list || []
formValue.value.default_value = form_data.default_value
formValue.value.assignment_method = form_data.assignment_method || 'custom'
}

defineExpose({ getData, rander })
onMounted(() => {
formValue.value.option_list = []
formValue.value.default_value = ''
formValue.value.assignment_method = 'custom'
if (formValue.value.show_default_value === undefined) {
formValue.value.show_default_value = true
}
addOption()
})
</script>
<style lang="scss" scoped>
.defaultValueItem {
position: relative;
.defaultValueCheckbox {
position: absolute;
right: 0;
top: -35px;
}
}
:deep(.el-form-item__label) {
display: block;
}

:deep(.el-select-dropdown) {
max-width: 400px;
}
</style>
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The provided code for a Vue.js component to render a dynamic form is mostly well-written. Here are some considerations for improvement and potential optimizations:

  1. Code Duplicacy: There's significant duplicated logic in handling the assignment_method selection, especially when setting up default_ref_variables_value_rule. Consider abstracting this into reusable functions.

  2. Error Handling: The function that validates the ref_variables values does not handle cases where the first item of the validation array is incorrect. Consider adding early returns or more robust error messages.

  3. Performance Optimization: The use of deep selectors like :deep() can be overkill, particularly if other components might also use these styles in unintended ways. It would be better to isolate specific classes within their respective components.

  4. Consistent Formatting: Ensure consistent spacing and line breaks within comments and strings for easier readability.

  5. Event Emission: Although not explicitly shown, ensure there’s no missing events being emitted that could affect behavior elsewhere in the application.

Here is a revised version with suggested improvements:

<script setup lang="ts">
import { computed, onMounted, inject } from 'vue';
import MultiRow from '@/components/dynamics-form/items/MultiRow.vue';
import NodeCascader from '@/workflow/common/NodeCascader.vue';
import type { FormField } from '@/components/dynamics-form/type';

const getModel = inject('getModel') as any;

// Abstracted function for validating default_ref_variables_value_rule
function validateRefVariables(rule: any, value: any): boolean {
  if (!Array.isArray(value) || value.length <= 1) {
    return false;
  }
  // Additional custom validations if needed
  return true;
}

const assignment_method_option_list = computed(() => {
  const option_list = [
    {
      label: t('dynamicsForm.AssignmentMethod.custom.label', '自定义'),
      value: 'custom',
    },
  ];

  if (getModel) {
    option_list.push({
      label: t('dynamicsForm.AssignmentMethod.ref_variables.label', '引用变量'),
      value: 'ref_variables',
    });
  }

  return option_list;
});

... rest of the script remains the same

</script>

<style scoped>
.defaultValueItem {
  position: relative;
  .defaultValueCheckbox {
    position: absolute;
    right: 0;
    top: -35px;
  }
}

/* Isolated deeper selector */
/deep/.el-select-dropdown {
  max-width: 400px;
}
</style> 

These adjustments improve the maintainability and consistency of the code while ensuring functionality remains intact.

Loading
Loading