diff --git a/package.json b/package.json index 0860c8a6ff..a43466e219 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "@ant-design/icons": "^4.0.0", "@ant-design/pro-layout": "^6.0.0", "@ant-design/pro-table": "2.6.3", - "@api7-dashboard/plugin": "^1.0.4", + "@api7-dashboard/plugin": "^1.0.5", "@api7-dashboard/pluginchart": "^1.0.11", "@api7-dashboard/ui": "^1.0.3", "@rjsf/antd": "2.2.0", diff --git a/src/pages/Route/Create.tsx b/src/pages/Route/Create.tsx index 40c63653be..759d775d54 100644 --- a/src/pages/Route/Create.tsx +++ b/src/pages/Route/Create.tsx @@ -22,15 +22,7 @@ import { transformer as chartTransformer } from '@api7-dashboard/pluginchart'; import ActionBar from '@/components/ActionBar'; -import { - create, - fetchItem, - fetchUpstreamItem, - fetchRouteGroupItem, - update, - checkUniqueName, - checkHostWithSSL -} from './service'; +import { create, fetchItem, update, checkUniqueName, checkHostWithSSL } from './service'; import Step1 from './components/Step1'; import Step2 from './components/Step2'; import Step3 from './components/Step3'; @@ -68,10 +60,11 @@ const Page: React.FC = (props) => { formatMessage({ id: 'route.constants.preview' }), ]; - const [step1Data, setStep1Data] = useState(DEFAULT_STEP_1_DATA); - const [step2Data, setStep2Data] = useState(DEFAULT_STEP_2_DATA); + const [advancedMatchingRules, setAdvancedMatchingRules] = useState( + [], + ); + const [upstreamHeaderList, setUpstreamHeaderList] = useState([]); const [step3Data, setStep3Data] = useState(DEFAULT_STEP_3_DATA); - const [redirect, setRedirect] = useState(false); const [form1] = Form.useForm(); @@ -79,69 +72,51 @@ const Page: React.FC = (props) => { const [step, setStep] = useState(1); const [stepHeader, setStepHeader] = useState(STEP_HEADER_4); - const [chart, setChart] = useState(INIT_CHART); - const routeData = { - step1Data, - step2Data, - step3Data, - }; const setupRoute = (rid: number) => fetchItem(rid).then((data) => { - form1.setFieldsValue(data.step1Data); - setStep1Data(data.step1Data as RouteModule.Step1Data); - - form2.setFieldsValue(data.step2Data); - setStep2Data(data.step2Data); - + form1.setFieldsValue(data.form1Data); + setAdvancedMatchingRules(data.advancedMatchingRules); + form2.setFieldsValue(data.form2Data); + setUpstreamHeaderList(data.upstreamHeaderList); setStep3Data(data.step3Data); }); - useEffect(() => { - if (props.route.path.indexOf('edit') !== -1) { - setupRoute(props.match.params.rid); - } - }, []); - - useEffect(() => { - const { redirectOption } = step1Data; - - if (redirectOption === 'customRedirect') { - setRedirect(true); - setStepHeader(STEP_HEADER_2); - return; - } - setRedirect(false); - setStepHeader(STEP_HEADER_4); - }, [step1Data]); - const onReset = () => { - setStep1Data(DEFAULT_STEP_1_DATA); - setStep2Data(DEFAULT_STEP_2_DATA); + setAdvancedMatchingRules([]); + setUpstreamHeaderList([]); setStep3Data(DEFAULT_STEP_3_DATA); - form1.setFieldsValue(DEFAULT_STEP_1_DATA); form2.setFieldsValue(DEFAULT_STEP_2_DATA); setStep(1); }; + useEffect(() => { + if (props.route.path.indexOf('edit') !== -1) { + setupRoute(props.match.params.rid); + } else { + onReset(); + } + }, []); + const renderStep = () => { if (step === 1) { return ( { - if (params.route_group_id) { - fetchRouteGroupItem(params.route_group_id).then((data) => { - form1.setFieldsValue({ - ...form1.getFieldsValue(), - ...data, - }); - }); + advancedMatchingRules={advancedMatchingRules} + onChange={({ action, data }) => { + if (action === 'redirectOptionChange' && data === 'customRedirect') { + setStepHeader(STEP_HEADER_2); + setRedirect(true); + } else { + setStepHeader(STEP_HEADER_4); + setRedirect(false); + } + if (action === 'advancedMatchingRulesChange') { + setAdvancedMatchingRules(data); } - setStep1Data({ ...form1.getFieldsValue(), ...step1Data, ...params }); }} isEdit={props.route.path.indexOf('edit') > 0} /> @@ -151,34 +126,25 @@ const Page: React.FC = (props) => { if (step === 2) { if (redirect) { return ( - {}} redirect /> + ); } return ( { - if (params.upstream_id) { - fetchUpstreamItem(params.upstream_id).then((data) => { - form2.setFieldsValue({ - ...form2.getFieldsValue(), - ...data, - }); - setStep2Data({ - ...step2Data, - ...form2.getFieldsValue(), - ...params, - } as RouteModule.Step2Data); - }); - return; + onChange={({ action, data }) => { + if (action === 'upstreamHeaderListChange') { + setUpstreamHeaderList(data); } - setStep2Data({ - ...step2Data, - ...form2.getFieldsValue(), - ...params, - } as RouteModule.Step2Data); }} /> ); @@ -197,7 +163,15 @@ const Page: React.FC = (props) => { } if (step === 4) { - return {}} />; + return ( + + ); } if (step === 5) { @@ -216,13 +190,20 @@ const Page: React.FC = (props) => { }; const onStepChange = (nextStep: number) => { + const routeData = { + form1Data: form1.getFieldsValue(), + form2Data: form2.getFieldsValue(), + step3Data, + upstreamHeaderList, + advancedMatchingRules, + } as RouteModule.RequestData; const onUpdateOrCreate = () => { if (props.route.path.indexOf('edit') !== -1) { - update((props as any).match.params.rid, { data: routeData }).then(() => { + update((props as any).match.params.rid, routeData).then(() => { setStep(5); }); } else { - create({ data: routeData }).then(() => { + create(routeData).then(() => { setStep(5); }); } @@ -249,7 +230,6 @@ const Page: React.FC = (props) => { redirectOption === 'forceHttps' ? checkHostWithSSL(hosts) : Promise.resolve(), checkUniqueName(value.name, (props as any).match.params.rid || ''), ]).then(() => { - setStep1Data({ ...step1Data, ...value }); setStep(nextStep); }); }); @@ -265,8 +245,7 @@ const Page: React.FC = (props) => { onUpdateOrCreate(); return; } - form2.validateFields().then((value) => { - setStep2Data({ ...step2Data, ...value }); + form2.validateFields().then(() => { setStep(nextStep); }); return; diff --git a/src/pages/Route/components/CreateStep4/CreateStep4.tsx b/src/pages/Route/components/CreateStep4/CreateStep4.tsx index 1d6928a901..6b28150cc1 100644 --- a/src/pages/Route/components/CreateStep4/CreateStep4.tsx +++ b/src/pages/Route/components/CreateStep4/CreateStep4.tsx @@ -23,11 +23,14 @@ import PluginOrchestration from '@api7-dashboard/pluginchart'; import Step1 from '../Step1'; import Step2 from '../Step2'; -interface Props extends RouteModule.Data { +type Props = { form1: FormInstance; form2: FormInstance; redirect?: boolean; -} + step3Data: RouteModule.Step3Data; + advancedMatchingRules: RouteModule.MatchingRule[]; + upstreamHeaderList: RouteModule.UpstreamHeader[]; +}; const style = { marginTop: '40px', @@ -35,7 +38,7 @@ const style = { const CreateStep4: React.FC = ({ form1, form2, redirect, ...rest }) => { const { formatMessage } = useIntl(); - const { plugins = {}, script = {} } = rest.data.step3Data; + const { plugins = {}, script = {} } = rest.step3Data; return ( <> @@ -44,17 +47,18 @@ const CreateStep4: React.FC = ({ form1, form2, redirect, ...rest }) => { {!redirect && ( <>

{formatMessage({ id: 'route.create.define.api.backend.server' })}

- + {}} + />

{formatMessage({ id: 'route.create.plugin.configuration' })}

{Boolean(Object.keys(plugins).length !== 0) && ( - + )} {Boolean(Object.keys(script).length !== 0) && ( - {}} - /> + {}} /> )} )} diff --git a/src/pages/Route/components/Step1/MatchingRulesView.tsx b/src/pages/Route/components/Step1/MatchingRulesView.tsx index ed42f4526c..5d571c6338 100644 --- a/src/pages/Route/components/Step1/MatchingRulesView.tsx +++ b/src/pages/Route/components/Step1/MatchingRulesView.tsx @@ -19,11 +19,11 @@ import { Button, Table, Modal, Form, Select, Input, Space } from 'antd'; import { useIntl } from 'umi'; import { PanelSection } from '@api7-dashboard/ui'; -interface Props extends RouteModule.Data {} - -const MatchingRulesView: React.FC = ({ data, disabled, onChange }) => { - const { advancedMatchingRules } = data.step1Data; - +const MatchingRulesView: React.FC = ({ + advancedMatchingRules, + disabled, + onChange = () => {}, +}) => { const [visible, setVisible] = useState(false); const [mode, setMode] = useState('CREATE'); const [namePlaceholder, setNamePlaceholder] = useState(''); @@ -38,8 +38,8 @@ const MatchingRulesView: React.FC = ({ data, disabled, onChange }) => { if (mode === 'EDIT') { const key = modalForm.getFieldValue('key'); onChange({ - ...data.step1Data, - advancedMatchingRules: advancedMatchingRules.map((rule) => { + action: 'advancedMatchingRulesChange', + data: advancedMatchingRules.map((rule) => { if (rule.key === key) { return { ...(value as RouteModule.MatchingRule), key }; } @@ -51,7 +51,10 @@ const MatchingRulesView: React.FC = ({ data, disabled, onChange }) => { ...(value as RouteModule.MatchingRule), key: Math.random().toString(36).slice(2), }; - onChange({ ...data.step1Data, advancedMatchingRules: advancedMatchingRules.concat(rule) }); + onChange({ + action: 'advancedMatchingRulesChange', + data: advancedMatchingRules.concat(rule), + }); } modalForm.resetFields(); setVisible(false); @@ -66,8 +69,8 @@ const MatchingRulesView: React.FC = ({ data, disabled, onChange }) => { const handleRemove = (key: string) => { onChange({ - ...data.step1Data, - advancedMatchingRules: advancedMatchingRules.filter((item) => item.key !== key), + action: 'advancedMatchingRulesChange', + data: advancedMatchingRules.filter((item) => item.key !== key), }); }; @@ -164,7 +167,7 @@ const MatchingRulesView: React.FC = ({ data, disabled, onChange }) => { cancelText={formatMessage({ id: 'route.match.cancel' })} destroyOnClose > -
+ = ({ data, disabled, onChange, isEdit }) => { - const { step1Data } = data; +const MetaView: React.FC = ({ form, disabled, isEdit }) => { const { formatMessage } = useIntl(); - const routeGroupDisabled = disabled || !!step1Data.route_group_id; + const [routeGroups, setRouteGroups] = useState<{ id: string; name: string }[]>(); + let routeGroupDisabled = disabled || Boolean(form.getFieldValue('route_group_id')); + useEffect(() => { // eslint-disable-next-line no-shadow fetchRouteGroupList().then(({ data }) => { @@ -36,11 +35,9 @@ const MetaView: React.FC = ({ data, disabled, onChange, isEdit }) => { { name: formatMessage({ id: 'route.meta.api.create.group.name' }), id: null }, ...data, ]); - if (step1Data.route_group_id) { - onChange({ route_group_id: step1Data.route_group_id }); - } }); }, []); + return ( = ({ data, disabled, onChange, isEdit }) => { + - {step1Data.redirectOption === 'customRedirect' && ( - - - - - - - - - - + { + onChange({ action: 'redirectOptionChange', data: next.redirectOption }); + return prev.redirectOption !== next.redirectOption; + }} + > + {() => { + if (form.getFieldValue('redirectOption') === 'customRedirect') { + return ( + + + + + + + + + + + + + - - - - )} + ); + } + return null; + }} + ); }; diff --git a/src/pages/Route/components/Step1/index.tsx b/src/pages/Route/components/Step1/index.tsx index e73b98ec57..9f8c07f96b 100644 --- a/src/pages/Route/components/Step1/index.tsx +++ b/src/pages/Route/components/Step1/index.tsx @@ -16,7 +16,6 @@ */ import React from 'react'; import { Form } from 'antd'; -import { FormInstance } from 'antd/lib/form'; import { FORM_ITEM_LAYOUT } from '@/pages/Route/constants'; import styles from '../../Create.less'; @@ -24,28 +23,10 @@ import MetaView from './MetaView'; import RequestConfigView from './RequestConfigView'; import MatchingRulesView from './MatchingRulesView'; -interface Props extends RouteModule.Data { - form: FormInstance; - isEdit?: boolean; -} - -const Step1: React.FC = (props) => { - const { data, form, onChange } = props; +const Step1: React.FC = (props) => { return ( <> - { - if (field.redirectOption === 'forceHttps' || field.redirectOption === 'disabled') { - form.setFieldsValue({ redirectURI: '' }); - } - onChange({ ...data.step1Data, ...field }); - }} - initialValues={data.step1Data} - > + diff --git a/src/pages/Route/components/Step2/HttpHeaderRewriteView.tsx b/src/pages/Route/components/Step2/HttpHeaderRewriteView.tsx index 543db05714..bfc4901cd9 100644 --- a/src/pages/Route/components/Step2/HttpHeaderRewriteView.tsx +++ b/src/pages/Route/components/Step2/HttpHeaderRewriteView.tsx @@ -20,10 +20,11 @@ import { Button, Table, Space, Modal, Input, Select } from 'antd'; import { useIntl } from 'umi'; import { PanelSection } from '@api7-dashboard/ui'; -interface Props extends RouteModule.Data {} - -const HttpHeaderRewriteView: React.FC = ({ data, disabled, onChange }) => { - const { upstreamHeaderList = [] } = data.step2Data; +const HttpHeaderRewriteView: React.FC = ({ + upstreamHeaderList = [], + disabled, + onChange, +}) => { const [visible, setVisible] = useState(false); const [modalForm] = Form.useForm(); const [mode, setMode] = useState('CREATE'); @@ -36,7 +37,10 @@ const HttpHeaderRewriteView: React.FC = ({ data, disabled, onChange }) => modalForm.setFieldsValue(record); }; const handleRemove = (key: string) => { - onChange({ upstreamHeaderList: upstreamHeaderList.filter((item) => item.key !== key) }); + onChange({ + action: 'upstreamHeaderListChange', + data: upstreamHeaderList.filter((item) => item.key !== key), + }); }; const columns = [ @@ -92,17 +96,18 @@ const HttpHeaderRewriteView: React.FC = ({ data, disabled, onChange }) => if (mode === 'EDIT') { const key = modalForm.getFieldValue('key'); onChange({ - upstreamHeaderList: upstreamHeaderList.map((item) => { + action: 'upstreamHeaderListChange', + data: upstreamHeaderList.map((item) => { if (item.key === key) { return { ...(value as RouteModule.UpstreamHeader), key }; } return item; }), - key, }); } else { onChange({ - upstreamHeaderList: upstreamHeaderList.concat({ + action: 'upstreamHeaderListChange', + data: upstreamHeaderList.concat({ ...(value as RouteModule.UpstreamHeader), key: Math.random().toString(36).slice(2), }), diff --git a/src/pages/Route/components/Step2/RequestRewriteView.tsx b/src/pages/Route/components/Step2/RequestRewriteView.tsx index 12ad7af813..7294b0cef5 100644 --- a/src/pages/Route/components/Step2/RequestRewriteView.tsx +++ b/src/pages/Route/components/Step2/RequestRewriteView.tsx @@ -15,7 +15,7 @@ * limitations under the License. */ import React, { useEffect, useState } from 'react'; -import Form, { FormInstance } from 'antd/es/form'; +import Form from 'antd/es/form'; import Radio from 'antd/lib/radio'; import { Input, Row, Col, InputNumber, Button, Select } from 'antd'; import { PlusOutlined, MinusCircleOutlined } from '@ant-design/icons'; @@ -29,15 +29,23 @@ import { HASH_ON_LIST, } from '@/pages/Route/constants'; import styles from '../../Create.less'; -import { fetchUpstreamList } from '../../service'; +import { fetchUpstreamList, fetchUpstreamItem } from '../../service'; -interface Props extends RouteModule.Data { - form: FormInstance; -} -const RequestRewriteView: React.FC = ({ data, form, disabled, onChange }) => { - const { step2Data } = data; +const RequestRewriteView: React.FC = ({ form, disabled }) => { const [upstearms, setUpstreams] = useState<{ id: string; name: string }[]>(); - const upstreamDisabled = disabled || !!step2Data.upstream_id; + const [upstreamId, setUpstreamId] = useState(form.getFieldValue('upstream_id')); + // TODO: need to check + let upstreamDisabled = disabled || Boolean(form.getFieldValue('upstream_id')); + + if (upstreamId) { + fetchUpstreamItem(upstreamId).then((data) => { + form.setFieldsValue({ + ...form.getFieldsValue(), + ...data, + }); + upstreamDisabled = true; + }); + } const { formatMessage } = useIntl(); useEffect(() => { @@ -47,41 +55,45 @@ const RequestRewriteView: React.FC = ({ data, form, disabled, onChange }) { name: formatMessage({ id: 'route.request.override.input' }), id: null }, ...data, ]); - if (step2Data.upstream_id) { - onChange({ upstream_id: step2Data.upstream_id }); - } }); }, []); const renderUpstreamMeta = () => ( <> - roundrobin chash - {step2Data.type === 'chash' && ( - <> - - - - - - - - )} + prev.type !== next.type}> + {() => { + if (form.getFieldValue('type') === 'chash') { + return ( + <> + + + + + + + + ); + } + return null; + }} + {(fields, { add, remove }) => ( <> @@ -209,13 +221,7 @@ const RequestRewriteView: React.FC = ({ data, form, disabled, onChange }) const renderTimeUnit = () => ms; return ( -
+ = ({ data, form, disabled, onChange }) }, ]} > - { - onChange({ upstream_protocol: e.target.value }); - }} - name="upstream_protocol" - disabled={disabled} - > + {formatMessage({ id: 'route.request.override.stay.same' })} HTTP HTTPS - { - onChange({ rewriteType: e.target.value }); - }} - disabled={disabled} - > + {formatMessage({ id: 'route.request.override.stay.same' })} {formatMessage({ id: 'page.route.radio.static' })} {formatMessage({ id: 'page.route.radio.regx' })} - {step2Data.rewriteType === 'regx' && ( - - - - )} - {(step2Data.rewriteType === 'static' || step2Data.rewriteType === 'regx') && ( - - - - )} + prev.rewriteType !== next.rewriteType}> + {() => { + if (form.getFieldValue('rewriteType') === 'regx') { + return ( + + + + ); + } + return null; + }} + + prev.rewriteType !== next.rewriteType}> + {() => { + if ( + form.getFieldValue('rewriteType') === 'static' || + form.getFieldValue('rewriteType') === 'regx' + ) { + return ( + + + + ); + } + return null; + }} + +