chore: form tabs active change
This commit is contained in:
@@ -275,5 +275,6 @@ export default {
|
|||||||
'common.button.disable': 'Disable',
|
'common.button.disable': 'Disable',
|
||||||
'common.status.enabled': 'Enabled',
|
'common.status.enabled': 'Enabled',
|
||||||
'common.status.disabled': 'Disabled',
|
'common.status.disabled': 'Disabled',
|
||||||
'common.button.duplicate': 'Duplicate'
|
'common.button.duplicate': 'Duplicate',
|
||||||
|
'common.option.other': 'Other'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -275,7 +275,8 @@ export default {
|
|||||||
'common.button.disable': 'Disable',
|
'common.button.disable': 'Disable',
|
||||||
'common.status.enabled': 'Enabled',
|
'common.status.enabled': 'Enabled',
|
||||||
'common.status.disabled': 'Disabled',
|
'common.status.disabled': 'Disabled',
|
||||||
'common.button.duplicate': 'Duplicate'
|
'common.button.duplicate': 'Duplicate',
|
||||||
|
'common.option.other': 'Other'
|
||||||
};
|
};
|
||||||
|
|
||||||
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
||||||
@@ -315,5 +316,6 @@ export default {
|
|||||||
// 34. 'common.button.disable': 'Disable',
|
// 34. 'common.button.disable': 'Disable',
|
||||||
// 35. 'common.status.enabled': 'Enabled',
|
// 35. 'common.status.enabled': 'Enabled',
|
||||||
// 36. 'common.status.disabled': 'Disabled'
|
// 36. 'common.status.disabled': 'Disabled'
|
||||||
// 33. 'common.button.duplicate': 'Duplicate'
|
// 33. 'common.button.duplicate': 'Duplicate',
|
||||||
|
// 34. 'common.option.other': 'Other'
|
||||||
// ========== End of To-Do List ==========
|
// ========== End of To-Do List ==========
|
||||||
|
|||||||
@@ -274,7 +274,8 @@ export default {
|
|||||||
'common.button.disable': 'Disable',
|
'common.button.disable': 'Disable',
|
||||||
'common.status.enabled': 'Enabled',
|
'common.status.enabled': 'Enabled',
|
||||||
'common.status.disabled': 'Disabled',
|
'common.status.disabled': 'Disabled',
|
||||||
'common.button.duplicate': 'Duplicate'
|
'common.button.duplicate': 'Duplicate',
|
||||||
|
'common.option.other': 'Другое'
|
||||||
};
|
};
|
||||||
|
|
||||||
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
||||||
|
|||||||
@@ -267,5 +267,6 @@ export default {
|
|||||||
'common.button.disable': '禁用',
|
'common.button.disable': '禁用',
|
||||||
'common.status.enabled': '已启用',
|
'common.status.enabled': '已启用',
|
||||||
'common.status.disabled': '未启用',
|
'common.status.disabled': '未启用',
|
||||||
'common.button.duplicate': '复制'
|
'common.button.duplicate': '复制',
|
||||||
|
'common.option.other': '其它'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -33,9 +33,10 @@ const CollapsePanel: React.FC<{
|
|||||||
items: CollapseProps['items'];
|
items: CollapseProps['items'];
|
||||||
activeKey: string | string[];
|
activeKey: string | string[];
|
||||||
accordion?: boolean;
|
accordion?: boolean;
|
||||||
|
defaultActiveKey?: string | string[];
|
||||||
onChange?: (key: string | string[]) => void;
|
onChange?: (key: string | string[]) => void;
|
||||||
styles?: Record<string, React.CSSProperties>;
|
styles?: Record<string, React.CSSProperties>;
|
||||||
}> = ({ items, activeKey, accordion, onChange, styles }) => {
|
}> = ({ items, activeKey, accordion, defaultActiveKey, onChange, styles }) => {
|
||||||
return (
|
return (
|
||||||
<CollapseInner
|
<CollapseInner
|
||||||
expandIconPlacement="start"
|
expandIconPlacement="start"
|
||||||
@@ -43,6 +44,7 @@ const CollapsePanel: React.FC<{
|
|||||||
ghost
|
ghost
|
||||||
accordion={accordion}
|
accordion={accordion}
|
||||||
activeKey={activeKey}
|
activeKey={activeKey}
|
||||||
|
defaultActiveKey={defaultActiveKey}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
destroyOnHidden={false}
|
destroyOnHidden={false}
|
||||||
styles={{
|
styles={{
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
interface FinishFailedOptions {
|
||||||
|
requiredFields: {
|
||||||
|
[tab: string]: {
|
||||||
|
sort: number;
|
||||||
|
fields: string[];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
onTargetChange: (key: string) => void;
|
||||||
|
updateActiveKey: (key: string[]) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const useFinishFailed = (options: FinishFailedOptions) => {
|
||||||
|
const { requiredFields, onTargetChange, updateActiveKey } = options;
|
||||||
|
const handleOnFinishFailed = (errorInfo: any) => {
|
||||||
|
const { errorFields } = errorInfo;
|
||||||
|
|
||||||
|
console.log('Finish failed:', errorInfo);
|
||||||
|
|
||||||
|
if (errorFields && errorFields.length > 0) {
|
||||||
|
const collapseKeys: { sort: number; key: string }[] = [];
|
||||||
|
const names = errorFields.map((item: any) => item.name[0]);
|
||||||
|
Object.entries(requiredFields).forEach(([tab, { fields, sort }]) => {
|
||||||
|
const hasError = fields.some((field: string) => names.includes(field));
|
||||||
|
if (hasError) {
|
||||||
|
collapseKeys.push({ sort, key: tab });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (collapseKeys.length > 0) {
|
||||||
|
const keys = collapseKeys
|
||||||
|
.sort((a, b) => a.sort - b.sort)
|
||||||
|
.map((item) => item.key);
|
||||||
|
|
||||||
|
updateActiveKey(keys);
|
||||||
|
onTargetChange(collapseKeys[0].key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
handleOnFinishFailed
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useFinishFailed;
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
|
const useScrollActiveChange = (options: {
|
||||||
|
initalActiveKeys: string[];
|
||||||
|
initialCollapseKeys?: string[];
|
||||||
|
}) => {
|
||||||
|
const [activeKey, setActiveKey] = useState<string[]>(
|
||||||
|
options.initalActiveKeys
|
||||||
|
);
|
||||||
|
const [collapseKeys, setCollapseKeys] = useState<string[]>(
|
||||||
|
options.initialCollapseKeys || options.initalActiveKeys
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleActiveChange = (key: string[]) => {
|
||||||
|
setActiveKey(key);
|
||||||
|
setCollapseKeys(key);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOnCollapseChange = (keys: string | string[]) => {
|
||||||
|
const keysArray = Array.isArray(keys) ? keys : [keys];
|
||||||
|
setActiveKey(keysArray);
|
||||||
|
setCollapseKeys(keysArray);
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateActiveKey = (keys: string[]) => {
|
||||||
|
setActiveKey((prev: string[]) => [...new Set([...prev, ...keys])]);
|
||||||
|
setCollapseKeys((prev) => [...new Set([...prev, ...keys])]);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
activeKey,
|
||||||
|
collapseKeys,
|
||||||
|
handleActiveChange,
|
||||||
|
handleOnCollapseChange,
|
||||||
|
updateActiveKey
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useScrollActiveChange;
|
||||||
@@ -4,17 +4,13 @@ import { PageActionType } from '@/config/types';
|
|||||||
import CollapsePanel from '@/pages/_components/collapse-panel';
|
import CollapsePanel from '@/pages/_components/collapse-panel';
|
||||||
import { useWrapperContext } from '@/pages/_components/column-wrapper/use-wrapper-context';
|
import { useWrapperContext } from '@/pages/_components/column-wrapper/use-wrapper-context';
|
||||||
import ScrollSpyTabs from '@/pages/_components/scroll-spy-tabs';
|
import ScrollSpyTabs from '@/pages/_components/scroll-spy-tabs';
|
||||||
|
import useFinishFailed from '@/pages/_components/scroll-spy-tabs/use-finish-failed';
|
||||||
|
import useScrollActiveChange from '@/pages/_components/scroll-spy-tabs/use-scroll-active-change';
|
||||||
import { json2Yaml, yaml2Json } from '@/pages/backends/config';
|
import { json2Yaml, yaml2Json } from '@/pages/backends/config';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Form } from 'antd';
|
import { Form } from 'antd';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import {
|
import { forwardRef, useEffect, useImperativeHandle, useRef } from 'react';
|
||||||
forwardRef,
|
|
||||||
useEffect,
|
|
||||||
useImperativeHandle,
|
|
||||||
useRef,
|
|
||||||
useState
|
|
||||||
} from 'react';
|
|
||||||
import FormContext from '../config/form-context';
|
import FormContext from '../config/form-context';
|
||||||
import { FormData, MaasProviderItem as ListItem } from '../config/types';
|
import { FormData, MaasProviderItem as ListItem } from '../config/types';
|
||||||
import AdvanceConfig from './advance-config';
|
import AdvanceConfig from './advance-config';
|
||||||
@@ -31,18 +27,37 @@ interface ProviderFormProps {
|
|||||||
const TABKeysMap = {
|
const TABKeysMap = {
|
||||||
BASIC: 'basic',
|
BASIC: 'basic',
|
||||||
SUPPORTEDMODELS: 'supportedModels',
|
SUPPORTEDMODELS: 'supportedModels',
|
||||||
CUSTOMCONFIG: 'customConfig',
|
|
||||||
ADVANCED: 'advanced'
|
ADVANCED: 'advanced'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const requiredFields = {
|
||||||
|
[TABKeysMap.BASIC]: {
|
||||||
|
sort: 1,
|
||||||
|
fields: ['name', 'config.type', 'api_key']
|
||||||
|
},
|
||||||
|
[TABKeysMap.SUPPORTEDMODELS]: {
|
||||||
|
sort: 2,
|
||||||
|
fields: ['models']
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const ProviderForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
const ProviderForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
||||||
const { action, currentData, onFinish } = props;
|
const { action, currentData, onFinish } = props;
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const { getScrollElementScrollableHeight } = useWrapperContext();
|
const { getScrollElementScrollableHeight } = useWrapperContext();
|
||||||
const [activeKey, setActiveKey] = useState<string[]>([TABKeysMap.BASIC]);
|
|
||||||
const scrollTabsRef = useRef<any>(null);
|
const scrollTabsRef = useRef<any>(null);
|
||||||
const advanceRef = useRef<any>(null);
|
const advanceRef = useRef<any>(null);
|
||||||
|
const {
|
||||||
|
activeKey,
|
||||||
|
collapseKeys,
|
||||||
|
handleActiveChange,
|
||||||
|
handleOnCollapseChange,
|
||||||
|
updateActiveKey
|
||||||
|
} = useScrollActiveChange({
|
||||||
|
initalActiveKeys: [TABKeysMap.BASIC],
|
||||||
|
initialCollapseKeys: [TABKeysMap.SUPPORTEDMODELS]
|
||||||
|
});
|
||||||
|
|
||||||
const segmentOptions = [
|
const segmentOptions = [
|
||||||
{
|
{
|
||||||
@@ -96,13 +111,15 @@ const ProviderForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
|||||||
onFinish(data);
|
onFinish(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleActiveChange = (key: string[]) => {
|
const onTargetChange = (key: string) => {
|
||||||
setActiveKey(key);
|
scrollTabsRef.current?.handleTargetChange(key);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOnCollapseChange = (keys: string | string[]) => {
|
const { handleOnFinishFailed } = useFinishFailed({
|
||||||
setActiveKey(Array.isArray(keys) ? keys : [keys]);
|
requiredFields,
|
||||||
};
|
onTargetChange,
|
||||||
|
updateActiveKey
|
||||||
|
});
|
||||||
|
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
submit: () => {
|
submit: () => {
|
||||||
@@ -152,6 +169,7 @@ const ProviderForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
|||||||
<Form
|
<Form
|
||||||
form={form}
|
form={form}
|
||||||
onFinish={handleOnFinish}
|
onFinish={handleOnFinish}
|
||||||
|
onFinishFailed={handleOnFinishFailed}
|
||||||
initialValues={{
|
initialValues={{
|
||||||
proxy_enabled: false,
|
proxy_enabled: false,
|
||||||
proxy_url: '',
|
proxy_url: '',
|
||||||
@@ -160,7 +178,7 @@ const ProviderForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
|||||||
>
|
>
|
||||||
<Basic />
|
<Basic />
|
||||||
<CollapsePanel
|
<CollapsePanel
|
||||||
activeKey={activeKey}
|
activeKey={collapseKeys}
|
||||||
accordion={false}
|
accordion={false}
|
||||||
onChange={handleOnCollapseChange}
|
onChange={handleOnCollapseChange}
|
||||||
items={[
|
items={[
|
||||||
|
|||||||
@@ -38,13 +38,20 @@ const Basic = () => {
|
|||||||
})}
|
})}
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: false,
|
required: true,
|
||||||
message: getRuleMessage('select', 'models.form.categories')
|
message: getRuleMessage('select', 'models.form.categories')
|
||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<CategorySelect
|
<CategorySelect
|
||||||
options={[{ label: '', value: '' }, ...categoryOptions]}
|
required={true}
|
||||||
|
options={[
|
||||||
|
...categoryOptions,
|
||||||
|
{
|
||||||
|
label: intl.formatMessage({ id: 'common.option.other' }),
|
||||||
|
value: 'other'
|
||||||
|
}
|
||||||
|
]}
|
||||||
label={intl.formatMessage({ id: 'models.form.categories' })}
|
label={intl.formatMessage({ id: 'models.form.categories' })}
|
||||||
></CategorySelect>
|
></CategorySelect>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|||||||
@@ -4,17 +4,13 @@ import { PageActionType } from '@/config/types';
|
|||||||
import CollapsePanel from '@/pages/_components/collapse-panel';
|
import CollapsePanel from '@/pages/_components/collapse-panel';
|
||||||
import { useWrapperContext } from '@/pages/_components/column-wrapper/use-wrapper-context';
|
import { useWrapperContext } from '@/pages/_components/column-wrapper/use-wrapper-context';
|
||||||
import ScrollSpyTabs from '@/pages/_components/scroll-spy-tabs';
|
import ScrollSpyTabs from '@/pages/_components/scroll-spy-tabs';
|
||||||
|
import useFinishFailed from '@/pages/_components/scroll-spy-tabs/use-finish-failed';
|
||||||
|
import useScrollActiveChange from '@/pages/_components/scroll-spy-tabs/use-scroll-active-change';
|
||||||
import { modelCategoriesMap } from '@/pages/llmodels/config';
|
import { modelCategoriesMap } from '@/pages/llmodels/config';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Form } from 'antd';
|
import { Form } from 'antd';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import {
|
import { forwardRef, useEffect, useImperativeHandle, useRef } from 'react';
|
||||||
forwardRef,
|
|
||||||
useEffect,
|
|
||||||
useImperativeHandle,
|
|
||||||
useRef,
|
|
||||||
useState
|
|
||||||
} from 'react';
|
|
||||||
import FormContext from '../config/form-context';
|
import FormContext from '../config/form-context';
|
||||||
import { FormData, RouteItem as ListItem } from '../config/types';
|
import { FormData, RouteItem as ListItem } from '../config/types';
|
||||||
import useEditTargets from '../hooks/use-edit-targets';
|
import useEditTargets from '../hooks/use-edit-targets';
|
||||||
@@ -40,9 +36,18 @@ interface ProviderFormProps {
|
|||||||
|
|
||||||
const TABKeysMap = {
|
const TABKeysMap = {
|
||||||
BASIC: 'basic',
|
BASIC: 'basic',
|
||||||
METADATA: 'metadata',
|
TARGETS: 'targets'
|
||||||
TARGETS: 'targets',
|
};
|
||||||
ADVANCED: 'advanced'
|
|
||||||
|
const requiredFields = {
|
||||||
|
[TABKeysMap.BASIC]: {
|
||||||
|
sort: 1,
|
||||||
|
fields: ['name']
|
||||||
|
},
|
||||||
|
[TABKeysMap.TARGETS]: {
|
||||||
|
sort: 2,
|
||||||
|
fields: ['targets']
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const AccessForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
const AccessForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
||||||
@@ -50,11 +55,20 @@ const AccessForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
|||||||
const { action, realAction, currentData, open, onFinish, onFallbackChange } =
|
const { action, realAction, currentData, open, onFinish, onFallbackChange } =
|
||||||
props;
|
props;
|
||||||
const { getScrollElementScrollableHeight } = useWrapperContext();
|
const { getScrollElementScrollableHeight } = useWrapperContext();
|
||||||
const [activeKey, setActiveKey] = useState<string[]>([TABKeysMap.BASIC]);
|
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const scrollTabsRef = useRef<any>(null);
|
const scrollTabsRef = useRef<any>(null);
|
||||||
const targetsRef = useRef<any>(null);
|
const targetsRef = useRef<any>(null);
|
||||||
const { generateTargetData, fetchTargets } = useEditTargets();
|
const { generateTargetData, fetchTargets } = useEditTargets();
|
||||||
|
const {
|
||||||
|
activeKey,
|
||||||
|
collapseKeys,
|
||||||
|
handleActiveChange,
|
||||||
|
handleOnCollapseChange,
|
||||||
|
updateActiveKey
|
||||||
|
} = useScrollActiveChange({
|
||||||
|
initalActiveKeys: [TABKeysMap.BASIC],
|
||||||
|
initialCollapseKeys: [TABKeysMap.TARGETS]
|
||||||
|
});
|
||||||
|
|
||||||
const segmentOptions = [
|
const segmentOptions = [
|
||||||
{
|
{
|
||||||
@@ -71,10 +85,6 @@ const AccessForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
const handleActiveChange = (key: string[]) => {
|
|
||||||
setActiveKey(key);
|
|
||||||
};
|
|
||||||
|
|
||||||
const formatTargets = (values: FormData) => {
|
const formatTargets = (values: FormData) => {
|
||||||
let targetList = [...(values.targets || [])];
|
let targetList = [...(values.targets || [])];
|
||||||
let fallbackTarget = values.fallback_target;
|
let fallbackTarget = values.fallback_target;
|
||||||
@@ -125,10 +135,6 @@ const AccessForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
|||||||
onFinish(data);
|
onFinish(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOnCollapseChange = (keys: string | string[]) => {
|
|
||||||
setActiveKey(Array.isArray(keys) ? keys : [keys]);
|
|
||||||
};
|
|
||||||
|
|
||||||
// init form values
|
// init form values
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!open) {
|
if (!open) {
|
||||||
@@ -194,6 +200,16 @@ const AccessForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
|||||||
}
|
}
|
||||||
}, [action, currentData, form, open, realAction]);
|
}, [action, currentData, form, open, realAction]);
|
||||||
|
|
||||||
|
const onTargetChange = (key: string) => {
|
||||||
|
scrollTabsRef.current?.handleTargetChange(key);
|
||||||
|
};
|
||||||
|
|
||||||
|
const { handleOnFinishFailed } = useFinishFailed({
|
||||||
|
requiredFields,
|
||||||
|
onTargetChange,
|
||||||
|
updateActiveKey
|
||||||
|
});
|
||||||
|
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
submit: () => {
|
submit: () => {
|
||||||
form.submit();
|
form.submit();
|
||||||
@@ -222,6 +238,7 @@ const AccessForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
|||||||
<Form
|
<Form
|
||||||
form={form}
|
form={form}
|
||||||
onFinish={handleOnFinish}
|
onFinish={handleOnFinish}
|
||||||
|
onFinishFailed={handleOnFinishFailed}
|
||||||
initialValues={{
|
initialValues={{
|
||||||
categories: [modelCategoriesMap.llm],
|
categories: [modelCategoriesMap.llm],
|
||||||
meta: {}
|
meta: {}
|
||||||
@@ -229,7 +246,7 @@ const AccessForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
|||||||
>
|
>
|
||||||
<Basic />
|
<Basic />
|
||||||
<CollapsePanel
|
<CollapsePanel
|
||||||
activeKey={activeKey}
|
activeKey={collapseKeys}
|
||||||
accordion={false}
|
accordion={false}
|
||||||
onChange={handleOnCollapseChange}
|
onChange={handleOnCollapseChange}
|
||||||
items={[
|
items={[
|
||||||
|
|||||||
Reference in New Issue
Block a user