From d4ac812e828ec08d30b91a8cd694553524959699 Mon Sep 17 00:00:00 2001 From: litesun <7sunmiao@gmail.com> Date: Thu, 17 Sep 2020 18:01:44 +0800 Subject: [PATCH 1/8] feat: improve step1 --- .../components/Step1/MatchingRulesView.tsx | 25 ++--- src/pages/Route/components/Step1/MetaView.tsx | 31 +++--- .../components/Step1/RequestConfigView.tsx | 99 ++++++++++--------- src/pages/Route/components/Step1/index.tsx | 23 +---- src/pages/Route/typing.d.ts | 37 +++++++ 5 files changed, 127 insertions(+), 88 deletions(-) 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 }[]>(); + const [routeGroupId, setRouteGroupId] = useState(form.getFieldValue('route_group_id')); + let routeGroupDisabled = disabled || Boolean(form.getFieldValue('route_group_id')); + + // TODO: EVENT LOOP + if (routeGroupId) { + fetchRouteGroupItem(routeGroupId).then((data) => { + form.setFieldsValue({ + ...form.getFieldsValue(), + ...data, + }); + routeGroupDisabled = true; + }); + } + useEffect(() => { // eslint-disable-next-line no-shadow fetchRouteGroupList().then(({ data }) => { @@ -36,11 +47,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/typing.d.ts b/src/pages/Route/typing.d.ts index ed4e3c4461..81b8bfbabc 100644 --- a/src/pages/Route/typing.d.ts +++ b/src/pages/Route/typing.d.ts @@ -158,4 +158,41 @@ declare namespace RouteModule { }; script: Record; }; + // step1 + interface MatchingRule { + position: VarPosition; + name: string; + operator: Operator; + value: string; + key: string; + } + + type Step1PassProps = { + form: FormInstance; + advancedMatchingRules: MatchingRule[]; + disabled?: boolean; + isEdit?: boolean; + onChange?(data: { + action: 'redirectOptionChange' | 'advancedMatchingRulesChange'; + data: T; + }): void; + }; + + type Form1Data = { + name: string; + desc: string; + priority: number; + protocols: RequestProtocol[]; + websocket: boolean; + hosts: string[]; + paths: string[]; + methods: HttpMethod[]; + redirectOption: 'forceHttps' | 'customRedirect' | 'disabled'; + redirectURI?: string; + redirectCode?: number; + }; + + type AvancedMatchingRules = { + advancedMatchingRules: MatchingRule[]; + }; } From 430cb2fd59239953c0faaf7494e3a75462de83ee Mon Sep 17 00:00:00 2001 From: litesun <7sunmiao@gmail.com> Date: Thu, 17 Sep 2020 21:41:39 +0800 Subject: [PATCH 2/8] feat: improve step2 --- .../Step2/HttpHeaderRewriteView.tsx | 21 +- .../components/Step2/RequestRewriteView.tsx | 193 ++++++++++-------- src/pages/Route/components/Step2/index.tsx | 7 +- src/pages/Route/typing.d.ts | 15 ++ 4 files changed, 133 insertions(+), 103 deletions(-) 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..b9e53b76d3 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; + }} + + { - setRouteGroupId(value); + if (!value) { + form.setFieldsValue({ + ...form.getFieldsValue(), + route_group_name: '', + }); + return; + } + fetchRouteGroupItem(value.toString()).then((data) => { + console.log('data: ', data); + form.setFieldsValue({ + ...form.getFieldsValue(), + ...data, + }); + routeGroupDisabled = true; + }); }} disabled={disabled} > diff --git a/src/pages/Route/constants.ts b/src/pages/Route/constants.ts index bf23e596d0..d421b57637 100644 --- a/src/pages/Route/constants.ts +++ b/src/pages/Route/constants.ts @@ -40,8 +40,8 @@ export const FORM_ITEM_WITHOUT_LABEL = { }, }; -export const DEFAULT_STEP_1_DATA: RouteModule.Step1Data = { - route_group_id: '', +export const DEFAULT_STEP_1_DATA: RouteModule.Form1Data = { + route_group_id: null, route_group_name: '', name: '', desc: '', @@ -55,13 +55,13 @@ export const DEFAULT_STEP_1_DATA: RouteModule.Step1Data = { redirectURI: '', redirectCode: 302, methods: HTTP_METHOD_OPTION_LIST, - advancedMatchingRules: [], }; -export const DEFAULT_STEP_2_DATA: RouteModule.Step2Data = { +export const DEFAULT_STEP_2_DATA: RouteModule.Form2Data = { upstream_protocol: 'keep', upstreamHostList: [{} as RouteModule.UpstreamHost], - upstreamHeaderList: [], + upstream_id: null, + pass_host: 'pass', upstreamPath: undefined, type: 'roundrobin', mappingStrategy: undefined, diff --git a/src/pages/Route/typing.d.ts b/src/pages/Route/typing.d.ts index 66a139d5b3..867377c60e 100644 --- a/src/pages/Route/typing.d.ts +++ b/src/pages/Route/typing.d.ts @@ -45,17 +45,6 @@ declare namespace RouteModule { script: any; }; - interface Data { - disabled?: boolean; - data: { - step1Data: Step1Data; - step2Data: Step2Data; - step3Data: Step3Data; - }; - onChange(data: T): void; - isEdit?: boolean; - } - type UpstreamHost = { host: string; port: number; @@ -71,24 +60,6 @@ declare namespace RouteModule { key: string; } - type Step2Data = { - upstream_protocol: 'http' | 'https' | 'keep'; - type: 'roundrobin' | 'chash'; - hash_on?: string; - key?: string; - upstreamHostList: UpstreamHost[]; - mappingStrategy: string | undefined; - rewriteType: string | undefined; - upstreamPath: string | undefined; - upstreamHeaderList: UpstreamHeader[]; - upstream_id?: string; - timeout: { - connect: number; - send: number; - read: number; - }; - }; - type ModalType = 'CREATE' | 'EDIT'; type Redirect = { @@ -100,7 +71,7 @@ declare namespace RouteModule { // Request Body or Response Data for API type Body = { id?: number; - route_group_id?: string; + route_group_id: string; route_group_name: string; status: boolean; name: string; @@ -164,7 +135,7 @@ declare namespace RouteModule { type Form1Data = { name: string; desc: string; - route_group_id?: string; + route_group_id: string | null; route_group_name: string; priority: number; protocols: RequestProtocol[]; @@ -210,7 +181,6 @@ declare namespace RouteModule { send: number; read: number; }; - upstream_id: string | undefined; pass_host: 'pass' | 'node' | 'rewrite'; upstream_host?: string; upstreamHostList: UpstreamHost[]; diff --git a/yarn.lock b/yarn.lock index 978e8cac85..ed1658cf51 100644 --- a/yarn.lock +++ b/yarn.lock @@ -187,14 +187,15 @@ lodash "^4.17.15" resize-observer-polyfill "^1.5.0" -"@api7-dashboard/plugin@^1.0.4": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@api7-dashboard/plugin/-/plugin-1.0.4.tgz#aaf945136398e61ef154b7cdd15319956854285b" - integrity sha512-hjwwhQCOWLR9ybIYeItSnTStU4A9ZcZMHsfrwXdLaWLGMVLLFhhopoBBtRUIszm5NHN1fCYNsLjGv4bNnCI/Qg== +"@api7-dashboard/plugin@^1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@api7-dashboard/plugin/-/plugin-1.0.5.tgz#75ae3348984f7619f7cfb87e49e17d6de6619909" + integrity sha512-FVAtsT1CJGmKN+jSsF8rOljNXj7VfMPOzf/BfaKuz7nhYrPUVTmIxAJ3BjS4eucNop5eo3FBFb0ohNAJU+qp4g== dependencies: "@rjsf/antd" "^2.3.0" "@rjsf/core" "^2.3.0" "@uiw/react-codemirror" "^3.0.1" + ajv "^6.12.5" json-schema "^0.2.5" set-value "^3.0.2" @@ -3780,6 +3781,16 @@ ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.2, ajv@^6.12.3, ajv@^6.7.0, ajv@ json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@^6.12.5: + version "6.12.5" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.5.tgz#19b0e8bae8f476e5ba666300387775fb1a00a4da" + integrity sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + alphanum-sort@^1.0.0: version "1.0.2" resolved "https://registry.npm.taobao.org/alphanum-sort/download/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" From b071b2e1e4c672c3fd5dbd1c9ca6cd0bc8c8241b Mon Sep 17 00:00:00 2001 From: litesun <7sunmiao@gmail.com> Date: Sun, 20 Sep 2020 23:09:26 +0800 Subject: [PATCH 6/8] feat: clean code --- src/pages/Route/components/Step1/MetaView.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/Route/components/Step1/MetaView.tsx b/src/pages/Route/components/Step1/MetaView.tsx index b564a1d5c2..4c87fc4f4f 100644 --- a/src/pages/Route/components/Step1/MetaView.tsx +++ b/src/pages/Route/components/Step1/MetaView.tsx @@ -68,7 +68,6 @@ const MetaView: React.FC = ({ form, disabled, isEdit return; } fetchRouteGroupItem(value.toString()).then((data) => { - console.log('data: ', data); form.setFieldsValue({ ...form.getFieldsValue(), ...data, From 9888730b0c0c61f558dec56962450848cd9c7c7b Mon Sep 17 00:00:00 2001 From: litesun <7sunmiao@gmail.com> Date: Sun, 20 Sep 2020 23:34:24 +0800 Subject: [PATCH 7/8] fix: lost route_group info when enable redirect --- src/pages/Route/transform.ts | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/pages/Route/transform.ts b/src/pages/Route/transform.ts index 39e1793e42..9603d4ebdc 100644 --- a/src/pages/Route/transform.ts +++ b/src/pages/Route/transform.ts @@ -25,7 +25,7 @@ export const transformStepData = ({ step3Data, }: RouteModule.RequestData) => { const nodes = {}; - form2Data.upstreamHostList.forEach((node) => { + (form2Data.upstreamHostList || []).forEach((node) => { nodes[`${node.host}:${node.port}`] = node.weight; }); @@ -101,13 +101,12 @@ export const transformStepData = ({ } } - if (step3Data.plugins.prometheus) { - // eslint-disable-next-line no-param-reassign - step3Data.plugins.prometheus = {}; - } - // 未启用 redirect if (!redirect.uri) { + if (step3Data.plugins.prometheus) { + // eslint-disable-next-line no-param-reassign + step3Data.plugins.prometheus = {}; + } // 移除前端部分自定义变量 return omit(data, [ 'advancedMatchingRules', @@ -127,7 +126,18 @@ export const transformStepData = ({ ]); } - return pick(data, ['name', 'desc', 'protocols', 'hosts', 'uris', 'methods', 'redirect', 'vars']); + return pick(data, [ + 'name', + 'desc', + 'protocols', + 'hosts', + 'uris', + 'methods', + 'redirect', + 'vars', + 'route_group_id', + 'route_group_name', + ]); }; const transformVarsToRules = ( @@ -242,9 +252,10 @@ export const transformRouteData = (data: RouteModule.Body) => { const { plugins, script } = data; - if (plugins.prometheus) { + if (plugins && plugins.prometheus) { plugins.prometheus = { enabled: true }; } + const step3Data: RouteModule.Step3Data = { plugins, script, From b27a98c517ce59fea4346836d278377e16d00547 Mon Sep 17 00:00:00 2001 From: litesun <7sunmiao@gmail.com> Date: Mon, 21 Sep 2020 16:47:25 +0800 Subject: [PATCH 8/8] feat: UI improve --- .../Route/components/Step1/RequestConfigView.tsx | 2 +- .../Route/components/Step2/RequestRewriteView.tsx | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/pages/Route/components/Step1/RequestConfigView.tsx b/src/pages/Route/components/Step1/RequestConfigView.tsx index 853b58c67d..236e4e6ff8 100644 --- a/src/pages/Route/components/Step1/RequestConfigView.tsx +++ b/src/pages/Route/components/Step1/RequestConfigView.tsx @@ -226,6 +226,7 @@ const RequestConfigView: React.FC = ({ { onChange({ action: 'redirectOptionChange', data: next.redirectOption }); return prev.redirectOption !== next.redirectOption; @@ -235,7 +236,6 @@ const RequestConfigView: React.FC = ({ if (form.getFieldValue('redirectOption') === 'customRedirect') { return ( diff --git a/src/pages/Route/components/Step2/RequestRewriteView.tsx b/src/pages/Route/components/Step2/RequestRewriteView.tsx index b9e53b76d3..7294b0cef5 100644 --- a/src/pages/Route/components/Step2/RequestRewriteView.tsx +++ b/src/pages/Route/components/Step2/RequestRewriteView.tsx @@ -65,12 +65,12 @@ const RequestRewriteView: React.FC = ({ form, disabl chash - prev.type !== next.type}> + prev.type !== next.type}> {() => { if (form.getFieldValue('type') === 'chash') { return ( <> - + - +