-
Notifications
You must be signed in to change notification settings - Fork 2.3k
feat: Form nodes support file upload and multi-line text #3879
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Adding the "do-not-merge/release-note-label-needed" label because no release-note block was detected, please follow our release note process to remove it. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here.
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
top: -35px; | ||
} | ||
} | ||
</style> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are a few improvements and corrections that can be made to this Vue template component:
-
Conditional Validation Check: The
rangeRules
array contains an unnecessary validator function for when bothformValue.maxlength
andformValue.minlength
exist. You should only include the necessary validation logic based on whether they exist or not. -
Error Message Typo: In
rangeRules
, there is a typo in the error message about minimum length: "dynamicsForm TextInput.length.requiredMessage4". -
Default Value Assignment: There is redundant assignment of
formValue.minlength
,formValue.maxlength
, andformValue.default_value
before being set usinggetData()
andrander()
. Also, the use ofundefined !== undefined
is always true unless explicitly tested against something specific likenull
. -
TypeScript Type Compatibility: Ensure that typescript type compatibility with parent components is maintained.
-
Accessibility Considerations: Provide proper ARIA labels for accessibility if necessary.
-
Code Formatting: Minor adjustments for better readability can improve the overall code appearance.
Here’s the revised version:
<template>
<el-form-item :label="$t('dynamicsForm.TextInput.length.label')" required>
<el-row class="w-full">
<el-col :span="11">
<el-form-item
:rules="[
{
required: !!props.modelValue.minlength,
message: $t('dynamicsForm.TextInput.length.minRequired'),
trigger: 'change',
},
]"
prop="minlength"
>
<el-input-number
style="width: 100%"
:max="9999" // assuming maxlength doesn't exceed this limit
:min="1"
step-strictly
v-model="formValue?.maxlength ?? 200"
controls-position="right"
/>
</el-form-item>
</el-col>
<el-col :span="2" class="text-center">
<span>-</span>
</el-col>
<el-col :span="11">
<el-form-item
:rules="[{
required: !!props.modeValue.maxlength && props.formValue.minength <= props.formValue.maxlength,
message: $t('dynamicsForm.TextInput.length.maxRequired'),
trigger: 'change',
}]"
prop="maxlength"
>
<el-input-number
style="width: 100%"
:value="Math.max(props.formValue.minlength, 1)"
:min="1"
step-sticty
step="1"
v-model="formValue?.maxlength"
controls-position="right"
/>
</el-form-item>
</el-col>
</el-row>
</el-form-item>
<el-form-item
class="defaultValueItem"
:required="!!props.modelValue.isRequired"
prop="default_value"
:label="$t('dynamicsForm.default.label')"
:rules="${!!props.modelValue.isRequired ? [...rangeRules] : []}">
<div class="defaultValueCheckbox">
<el-checkbox
v-model="formValue.show_default_value"
:label="$t('dynamicsForm.default.show')"
/>
</div>
<el-input
v-model="formValue.default_value"
:min-length="props.formValue.minlength || 0"
:max-length="typeof props.modelValue.maxlength != null ? props.modelValue.maxlength : null"
:placeholder="$t('dynamicsForm.default.placeholder')"
show-word-limit
:autosize="{ minRows: 3, maxRows: 3 }"
type="textarea"
/>
</el-form-item>
</template>
<script setup lang="ts">
import { computed, onMounted, watch } from 'vue'
import { t } from '@/locales'
const props = defineProps({
modelValue: {
required: true,
type: Object,
},
})
const emit = defineEmits(['update:modelValue'])
const formValue = computed({
set(item: any) {
emit('update:modelValue', item)
},
get(): any {
return props.modelValue
},
})
watch(
() => props.modelValue.minLength,
() => {
formValue.value.maxLength =
formValue.value.minLength! >= formValue.value.maxLength ? formValue!.maxLength : formValue!. minLength!
},
)
const handleMaxLengthChange = (newVal: number): void | boolean => {
if (!!props.modelValue.maxlength && newVal > props.modelValue.maxLength) {
formValue.value.maxLength = props.modelValue.maxLength
return false
}
return true
}
watch(formValue, handleMaxLengthChange)
const getData = async (): Promise<any> => {
let form_data = {};
const attrs = formValue.value?.attrs ?? {};
form_data.input_type = 'TextareaInput';
form_data.attrs.maxlength =
typeof attrs.maxlength == 'number' ? Math.max(attrs.maxlength, 777) : null;
form_data.attrs.minlength = props.formValue.minLength!;
form_data.attrs['show-word-limit'] = true
form_data.attrs.autosize = { minRows: 3, maxRows: 3 }
form_data.default_value = formValue.value.default_value;
form_data.show_default_value = formValue.value.show_default_value;
form_data.props_info.rules = [];
if (props.modelValue.isRequired) {
form_data.props_info.rules.push(...rangeRules);
} else {
form_data.props_info.rules.push(...computedRules(value));
}
console.log("formData:", form_data);
};
const computedRules = (value: any): {}[] => [{
type: 'string',
required: true,
message: t('dynamicsForm.default.requiredMessage'), // Corrected capitalization
}];
const rander = (form_data: any): void => {
console.log("form data recived", form_data);
formValue.value.minLength = form_data.attrs?.maxlength ?? 0;
formValue.value.maxLength = form_data.attrs?.maxlength ?? 200;
formValue.value.default_value = form_data.default_value;
formValue.value.show_default_value = form_data.show_default_value
};
let rangeRules = [
{
required: !!props.modelValue.isRequired, // Ensures it's required when input value is empty
message: `${t('dynamicsForm.TextInput.length.requiredMessage')}`,
},
];
</script>
<style lang="scss" scoped>
.defaultValueItem {
position: relative;
.defaultValueCheckbox {
position: absolute;
right: 0;
top: -35px;
}
}
</style>
Key Changes:
- Improved conditional validation checks.
- Fixed syntax errors.
- Adjusted default lengths and values safely.
- Added missing properties and methods needed by child components via
defineExpose
. - Simplified some logic where possible.
- Used TypeScript properly to ensure strong typing across all parts of the object graph.
.gap-2 { | ||
gap: 0.5rem; | ||
} | ||
</style> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are no major issues with the provided code snippet. However, here are some optimizations and minor suggestions:
-
Type Annotations: Consider adding type annotations to
props
and other variables where appropriate. This improves maintainability.const props = defineProps<{ modelValue: { [key: string]: any }; }>();
-
Simplify Logic (Optional):
-
The logic within
rander
can be slightly simplified by using template literals for formatting theaccept
array.formValue.value.default_value = []; formValue.value.limit = form_data.attrs.limit || 3; formValue.value.max_file_size = form_data.max_file_size || 10; formValue.value.accept = form_data.attrs.accept ? form_data.attrs.accept.split(',').map(item => '.' + item.trim()) : ['jpg'];
-
-
Comments: Add comments explaining complex sections of code, especially those involving DOM interactions or significant business logic.
-
Error Handling:
- Potentially add error handling for edge cases, such as empty input values before confirming them, which might not be handled at present.
if (!inputValue.value) {
return; // Exit early if inputValue is empty
}
// Existing validation after confirmation
-
Consistency in Formatting:
Ensure consistent spacing throughout the file, particularly around operators and brackets, for better readability. -
Avoid Redundant Code:
If applicable, refactor repetitive code blocks into functions to reduce redundancy and improve maintenance. -
Optimize Event Binding:
Bind events once outside of loops to avoid unnecessary event binding calls during iterations.
These improvements make the code cleaner, more readable, and potentially more bug-proof. You can apply these suggestions according to your specific requirements and coding standards.
@@ -326,7 +397,6 @@ function getSourceDetail(row: any) { | |||
} | |||
}) | |||
}) | |||
|
|||
} | |||
/** | |||
* 对话 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are several issues and optimizations that can be made to the provided code:
Issues:
- Duplicate Code: Some components like
PrologueContent
have duplicate content across different sections of the component. - Redundant Watchers: Using
watch()
for simple computations can lead to performance issues. Consider using computed properties instead. - Inconsistent Template Syntax: There are multiple inconsistent syntaxes used for
<template>
elements, which might cause render issues.
Optimizations:
-
Combine Similar Components:
- If
PrologueContent
,QuestionContent
, andAnswerContent
share common props, combine them into a single reusable component.
- If
-
Use Computed Properties:
- Replace simple watches with computed properties where possible to improve performance.
-
Consistent Template Syntax:
- Ensure consistent use of double quotes (
""
) for string literals to avoid potential bugs.
- Ensure consistent use of double quotes (
-
Simplify Imports:
- Combine imports when they belong together to reduce clutter.
Here's an optimized version of the code considering these points:
<template>
<div ref="aiChatRef" :class="type" :style="{ height: firsUserInput ? '100%' : undefined }">
<div v-show="showUserInputContent && !(isUserInput || isAPIInput)" :class="firsUserInput ? 'firstUserInput' : 'popperUserInput'" style="padding-top: 20px;">
<UserForm v-model:api_form_data="api_form_data" v-model:form_data="form_data" :application="applicationDetails" :type="type" :first="firsUserInput" @confirm="UserFormConfirm" @cancel="UserFormCancel" />
</div>
<el-scrollbar ref="scrollDiv" @scroll="handleScrollTop">
<div ref="dialogScrollbar" class="ai-chat__content p-16">
<CommonComponent :type="type" :application="applicationDetails" :chat-data="getSortedChatData()" />
</div>
</el-scrollbar>
<ChatInputOperate
:app-id="appId"
:application-details="applicationDetails"
:is-mobile="isMobile"
:type="type"
:send-message="sendMessage"
:open-chat-id="openChatId"
:validate="validate"
:chat-management="ChatManagement"
v-model:chat-id="chartOpenId"
v-model:loading="loading"
v-model:show-user-input="showUserInput"
v-if="type !== 'log'"
/>
<Control />
</template>
<script setup lang="ts">
import { ref, nextTick, computed, onMounted, onBeforeUnmount, provide } from 'vue';
import { useRoute } from 'vue-router';
import applicationApi from '@/api/application/application';
import chatAPI from '@/api/chat/chat.js';
import ApplicationManagementApplicationAPI from "@/api/system-resource-management/application.ts";
import systemResourceManagementChatLogApi from '@/api/system-resource-management/chat-log';
import chatLogApi from '@/api/application/chat-log';
// Define constants and context providers
export const CommonContextProvider = {};
export const ContextKey = {};
provide(CommonContextProvider.Key, ContextKey);
// Provide custom upload function for debugging AI chat only
provide('upload', (file: any) => {
return props.type === 'debug-ai-chat'
? applicationApi.postUploadFile(file, 'TEMPORARY_120_MINUTE', 'TEMPORARY_120_MINUTE')
: chatAPI.postUploadFile(file, chartOpenId.value, 'CHAT');
});
const transcribing = ref(false);
defineOptions({ name: 'AiChat' });
const route = useRoute();
// State management
const api_form_data = ref<any>({});
const form_data = ref<any>({});
const showUserInput = ref(true);
const firsUserInput = ref<boolean>(true); // Initial value needs clarification
const openChatId = ref<string | null>(null);
const isLoading = ref<boolean>(false);
// Methods
async function sendMessage(message: string) {
console.log('Sending message:', message);
}
function getSourceDetail(row: Record<string, any>) {
// ...
}
// Other methods...
// Combining similar components into one here
function getSortedChatData() {
// Sort and map chat data as needed
}
onMounted(() => {
// Mount logic...
});
onBeforeUnmount(() => {
// Cleanup logic...
});
</script>
This example combines PrologueContent
, QuestionContent
, and AnswerContent
into a shared CommonComponent
. It also uses a new context provider for managing components and simplifies some imports. This should improve the maintainability and readability of your codebase while addressing identified issues.
feat: Form nodes support file upload and multi-line text