fix: cluster value setting, volumes setting

This commit is contained in:
jialin
2025-09-19 20:00:25 +08:00
parent b640963f65
commit f542ebecb4
27 changed files with 677 additions and 109 deletions
+1 -2
View File
@@ -172,9 +172,8 @@ export default function CollapsibleContainer({
<div
ref={contentRef}
style={{
maxHeight: height,
height: height,
overflow: 'hidden'
// transition: collapsible ? 'max-height 0.2s ease' : 'none'
}}
>
<div style={{ paddingTop: 8 }}>{children}</div>
@@ -4,6 +4,7 @@ import { FormWidgetProps } from '../config/types';
const FormWidget: React.FC<
FormWidgetProps & {
onChange?: (data: any) => void;
disabled?: boolean;
}
> = ({
widget,
@@ -17,8 +18,10 @@ const FormWidget: React.FC<
value,
min,
max,
status,
checked,
readOnly: disabled,
isInFormItems,
disabled,
onChange
}) => {
const Component = ComponentsMap[widget];
@@ -38,6 +41,8 @@ const FormWidget: React.FC<
min,
max
}}
status={status}
isInFormItems={isInFormItems}
disabled={disabled}
options={options || optionList}
value={value}
@@ -3,6 +3,7 @@ import { MinusOutlined } from '@ant-design/icons';
import { Button } from 'antd';
import React, { useEffect, useMemo } from 'react';
import styled from 'styled-components';
import { statusType } from '../config/types';
import FormWidget from './form-widget';
const RowWrapper = styled.div`
@@ -23,8 +24,12 @@ interface ListMapProps {
dataList: any[];
label?: React.ReactNode;
btnText?: string;
requiredFields?: string[];
validateStatusList?: Record<string, statusType>[];
properties: Record<string, any>;
disabled?: boolean;
onAdd?: (data: any[]) => void;
onDelete?: (deletedItem: any, data: any[]) => void;
onChange?: (data: any) => void;
}
@@ -32,6 +37,7 @@ interface ListItemProps {
schemaList: any[];
data: Record<string, any>;
disabled?: boolean;
validateStatus?: Record<string, statusType>;
onChange?: (data: any) => void;
}
@@ -39,6 +45,7 @@ const ListItem: React.FC<ListItemProps> = ({
schemaList,
data,
onChange,
validateStatus,
disabled
}) => {
const handleValueChange = (name: string, target: any) => {
@@ -50,17 +57,18 @@ const ListItem: React.FC<ListItemProps> = ({
onChange?.({ [name]: value });
}
};
return (
<>
{schemaList.map((schema: any) => (
<FormWidget
status={validateStatus?.[schema.name]}
widget={schema.type}
{...schema}
disabled={disabled}
disabled={disabled || schema.readOnly}
key={schema.name}
value={data?.[schema.name]}
checked={data?.[schema.name]}
isInFormItems={false}
onChange={(target) => handleValueChange(schema.name, target)}
/>
))}
@@ -73,8 +81,12 @@ const ListMap: React.FC<ListMapProps> = ({
label,
btnText,
properties = {},
requiredFields = [],
minItems = 0,
validateStatusList = [],
disabled,
onAdd,
onDelete,
onChange
}) => {
const [items, setItems] = React.useState(dataList || []);
@@ -82,23 +94,27 @@ const ListMap: React.FC<ListMapProps> = ({
const schemaList = useMemo(() => {
const list = Object.entries(properties).map(([key, value]) => ({
...value,
required: requiredFields.includes(key),
name: key
}));
return list;
}, [properties]);
}, [properties, requiredFields]);
const handleOnAdd = () => {
const keys = Object.keys(properties);
setItems([
const newItems = [
...items,
{ ...keys.reduce((acc, key) => ({ ...acc, [key]: '' }), {}) }
]);
];
setItems(newItems);
onAdd?.(newItems);
};
const handleDelete = (index: number) => {
const deleteItem = items[index];
const newItems = items.filter((_, i) => i !== index);
setItems(newItems);
onChange?.(newItems);
onDelete?.(deleteItem, newItems);
};
const handleItemChange = (index: number, data: { [key: string]: any }) => {
@@ -131,6 +147,7 @@ const ListMap: React.FC<ListMapProps> = ({
<ListItem
schemaList={schemaList}
data={item}
validateStatus={validateStatusList?.[index]}
disabled={disabled}
onChange={(value) => handleItemChange(index, value)}
/>
@@ -15,9 +15,13 @@ export interface FieldSchema {
widget?: string;
min?: number;
style?: React.CSSProperties;
required?: string[];
}
export type statusType = 'error' | 'warning' | '' | undefined;
export interface FormWidgetProps {
status?: statusType;
isInFormItems?: boolean;
widget: 'Input' | 'Select' | 'Checkbox' | 'InputNumber';
name: string;
title?: string;
@@ -0,0 +1,61 @@
import { useRef } from 'react';
import { statusType } from '../config/types';
export default function useValidateFields(params: {
requiredFields?: string[];
setValidateStatusList: (statusList: { [key: string]: statusType }[]) => void;
}) {
const { requiredFields, setValidateStatusList } = params;
const validationEnabled = useRef(false);
const isEmptyValue = (value: any, key: string) => {
return !value;
};
const validateRule = (value: any, key: string) => {
return true;
};
const listMapValidator = async (_: any, valueList: any) => {
if (!validationEnabled.current) {
return Promise.resolve();
}
const fields = new Set<string>();
const statusList: { [key: string]: statusType }[] = [];
(valueList || []).forEach((item: any, index: number) => {
const status: { [key: string]: statusType } = {};
Object.entries(item || {}).forEach(([key, value]) => {
if (isEmptyValue(value, key)) {
fields.add(key);
if (requiredFields?.includes(key)) {
status[key] = 'error';
} else {
status[key] = '';
}
} else if (validateRule(value, key)) {
status[key] = '';
}
});
statusList.push(status);
});
setValidateStatusList(statusList);
if (fields.size > 0) {
return Promise.reject(`${Array.from(fields).join(', ')} is required`);
}
return Promise.resolve();
};
const toggleValidation = (enabled: boolean) => {
validationEnabled.current = enabled;
};
return {
listMapValidator,
toggleValidation
};
}
+35 -33
View File
@@ -3,41 +3,43 @@ import type { SelectProps } from 'antd';
import { Select } from 'antd';
import React, { forwardRef, useImperativeHandle } from 'react';
const BaseSelect: React.FC<SelectProps> = forwardRef((props, ref) => {
const [isFocus, setIsFocus] = React.useState(false);
const inputRef = React.useRef<any>(null);
const BaseSelect: React.FC<SelectProps & { ref?: any }> = forwardRef(
(props, ref) => {
const [isFocus, setIsFocus] = React.useState(false);
const inputRef = React.useRef<any>(null);
useImperativeHandle(ref, () => ({
...(inputRef.current || ({} as any))
}));
useImperativeHandle(ref, () => ({
...(inputRef.current || ({} as any))
}));
const handleFocus = (e: React.FocusEvent<HTMLDivElement>) => {
setIsFocus(true);
props.onFocus?.(e);
};
const handleBlur = (e: React.FocusEvent<HTMLDivElement>) => {
setIsFocus(false);
props.onBlur?.(e);
};
const renderSuffixIcon = () => {
if (props.suffixIcon) {
return props.suffixIcon;
}
if (!props.showSearch) {
return <IconFont type="icon-down"></IconFont>;
}
return !isFocus ? <IconFont type="icon-down"></IconFont> : undefined;
};
const handleFocus = (e: React.FocusEvent<HTMLDivElement>) => {
setIsFocus(true);
props.onFocus?.(e);
};
const handleBlur = (e: React.FocusEvent<HTMLDivElement>) => {
setIsFocus(false);
props.onBlur?.(e);
};
const renderSuffixIcon = () => {
if (props.suffixIcon) {
return props.suffixIcon;
}
if (!props.showSearch) {
return <IconFont type="icon-down"></IconFont>;
}
return !isFocus ? <IconFont type="icon-down"></IconFont> : undefined;
};
return (
<Select
{...props}
ref={inputRef}
onFocus={handleFocus}
onBlur={handleBlur}
suffixIcon={renderSuffixIcon()}
/>
);
});
return (
<Select
{...props}
ref={inputRef}
onFocus={handleFocus}
onBlur={handleBlur}
suffixIcon={renderSuffixIcon()}
/>
);
}
);
export default BaseSelect;
@@ -23,6 +23,8 @@ const SealInputNumber: React.FC<InputNumberProps & SealFormItemProps> = (
if (isInFormItems) {
const statusData = Form?.Item?.useStatus?.();
status = statusData?.status || '';
} else {
status = props.status || '';
}
useEffect(() => {
+2
View File
@@ -31,6 +31,8 @@ const SealInput: React.FC<InputProps & SealFormItemProps> = (props) => {
if (isInFormItems) {
const statusData = Form?.Item?.useStatus?.();
status = statusData?.status || '';
} else {
status = props.status || '';
}
useEffect(() => {
+3
View File
@@ -25,12 +25,15 @@ const SealSelect: React.FC<SelectProps & SealFormItemProps> = (props) => {
const intl = useIntl();
const [isFocus, setIsFocus] = useState(false);
const inputRef = useRef<any>(null);
let status = '';
// the status can be controlled by Form.Item
if (isInFormItems) {
const statusData = Form?.Item?.useStatus?.();
status = statusData?.status || '';
} else {
status = props.status || '';
}
const _options = useMemo(() => {