You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shenyu.apache.org by fe...@apache.org on 2021/07/08 13:17:49 UTC
[incubator-shenyu-dashboard] branch master updated: Support
response plugin (#131) (#132)
This is an automated email from the ASF dual-hosted git repository.
fengzhenbing pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-shenyu-dashboard.git
The following commit(s) were added to refs/heads/master by this push:
new 45b1c73 Support response plugin (#131) (#132)
45b1c73 is described below
commit 45b1c73f9499cacb6afca49af84b1c9ceaafdfb1
Author: dayu <we...@qq.com>
AuthorDate: Thu Jul 8 21:17:43 2021 +0800
Support response plugin (#131) (#132)
Co-authored-by: wenyu.dai <“wenyu.dai@qq.com”>
---
.../Plugin/PluginRuleHandle/ResponseRuleHandle.js | 415 +++++++++++++++++++++
src/routes/Plugin/PluginRuleHandle/index.js | 14 +-
2 files changed, 423 insertions(+), 6 deletions(-)
diff --git a/src/routes/Plugin/PluginRuleHandle/ResponseRuleHandle.js b/src/routes/Plugin/PluginRuleHandle/ResponseRuleHandle.js
new file mode 100644
index 0000000..39849c2
--- /dev/null
+++ b/src/routes/Plugin/PluginRuleHandle/ResponseRuleHandle.js
@@ -0,0 +1,415 @@
+/* eslint-disable react/no-access-state-in-setstate */
+import React, { Component } from "react";
+import {
+ Tabs,
+ Form,
+ Select,
+ Row,
+ Col,
+ Input,
+ Button,
+ Table,
+ InputNumber
+} from "antd";
+import { getIntlContent } from "../../../utils/IntlUtils";
+
+const { Option } = Select;
+const { TabPane } = Tabs;
+
+const TypeKey = {
+ statusCode: ["statusCode"],
+ headers: [
+ "addHeaders",
+ "setHeaders",
+ "replaceHeaderKeys",
+ "removeHeaderKeys"
+ ],
+ body: ["addBodyKeys", "replaceBodyKeys", "removeBodyKeys"]
+};
+
+function ConfigInput(cfProps) {
+ const { code, data, onChange } = cfProps;
+ return (
+ <Input
+ value={data[code]}
+ placeholder={`please enter ${code}`}
+ addonBefore={code}
+ onChange={e => {
+ onChange({ [code]: e.target.value }, data.id);
+ }}
+ />
+ );
+}
+
+class ResponseConfig extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ activeKey: "statusCode",
+ headers: [{ id: (+new Date() + 1).toString() }],
+ body: [{ id: (+new Date() + 1).toString() }],
+ statusCode: [{ id: (+new Date() + 1).toString(), type: "statusCode" }]
+ };
+ }
+
+ componentDidMount() {
+ const { value } = this.props;
+ const { headers, body } = this.state;
+ if (value) {
+ const data = {};
+ try {
+ Object.assign(data, JSON.parse(value));
+ } catch (e) {
+ console.log(e);
+ }
+ const headerData = [];
+ const bodyData = [];
+ const statusCodeData = [
+ { id: (+new Date() + 1).toString(), type: "statusCode" }
+ ];
+ const draftData = [];
+
+ Object.keys(data).forEach(type => {
+ if (Array.isArray(data[type])) {
+ data[type].forEach(item => {
+ if (typeof item === "string") {
+ draftData.push({ type, key: item });
+ } else {
+ draftData.push({ type, ...item });
+ }
+ });
+ }
+ if (Object.prototype.toString.call(data[type]) === "[object Object]") {
+ Object.keys(data[type]).forEach(key => {
+ draftData.push({ type, key, value: data[type][key] });
+ });
+ }
+ if (typeof data[type] === "number") {
+ statusCodeData[0].code = data[type];
+ }
+ });
+ draftData.forEach((item, i) => {
+ if (TypeKey.headers.includes(item.type)) {
+ headerData.push({
+ ...item,
+ id: i.toString()
+ });
+ }
+ if (TypeKey.body.includes(item.type)) {
+ bodyData.push({ ...item, id: i.toString() });
+ }
+ });
+ this.setState({
+ headers: headerData.concat(headers),
+ body: bodyData.concat(body),
+ statusCode: statusCodeData
+ });
+ }
+ }
+
+ componentDidUpdate() {
+ const { onChange, value } = this.props;
+ const data = {};
+ const currentData = this.getCurrentData();
+ const valueStr = JSON.stringify(currentData);
+ // console.log(currentData);
+ if (value !== undefined) {
+ try {
+ Object.assign(data, JSON.parse(value));
+ } catch (e) {
+ console.log(e);
+ }
+ }
+
+ if (valueStr !== value && onChange) {
+ onChange(valueStr);
+ }
+ }
+
+ getCurrentData = () => {
+ const { headers, body, statusCode } = this.state;
+ const currentData = {};
+ const hanleKeyValue = item => {
+ if (currentData[item.type] === undefined) {
+ currentData[item.type] = {};
+ }
+ currentData[item.type][item.key] = item.value;
+ };
+ const hanlePathKeyValue = item => {
+ if (currentData[item.type] === undefined) {
+ currentData[item.type] = [];
+ }
+ currentData[item.type].push({
+ path: item.path,
+ key: item.key,
+ value: item.value
+ });
+ };
+ const hanleKeys = item => {
+ if (currentData[item.type] === undefined) {
+ currentData[item.type] = [];
+ }
+ currentData[item.type].push(item.key);
+ };
+ const hanleStatusCode = item => {
+ if (currentData[item.type] === undefined) {
+ currentData[item.type] = [];
+ }
+ currentData.statusCode = item.code;
+ };
+ const handleForEach = item => {
+ if (
+ ["addHeaders", "setHeaders", "replaceHeaderKeys"].includes(item.type)
+ ) {
+ hanleKeyValue(item);
+ }
+ if (["addBodyKeys", "replaceBodyKeys"].includes(item.type)) {
+ hanlePathKeyValue(item);
+ }
+ if (["removeHeaderKeys", "removeBodyKeys"].includes(item.type)) {
+ hanleKeys(item);
+ }
+ if (["statusCode"].includes(item.type)) {
+ hanleStatusCode(item);
+ }
+ };
+ headers.forEach(handleForEach);
+ body.forEach(handleForEach);
+ statusCode.forEach(handleForEach);
+ return currentData;
+ };
+
+ onChangeConfig = (value, id) => {
+ const state = this.state;
+ const { activeKey } = state;
+ const index = state[activeKey].findIndex(v => v.id === id);
+ const newData = state[activeKey].map(v => {
+ if (v.id === id) {
+ return value.type
+ ? { id: v.id, ...value }
+ : {
+ ...v,
+ ...value
+ };
+ }
+ return v;
+ });
+ this.setState({
+ [activeKey]:
+ value.type &&
+ state[activeKey][index].type === undefined &&
+ activeKey !== "statusCode"
+ ? newData.concat([{ id: (+new Date()).toString() }])
+ : newData
+ });
+ };
+
+ renderConfig = data => {
+ let Comp = null;
+ if (!data.type) {
+ return Comp;
+ }
+
+ switch (data.type) {
+ case "addHeaders":
+ case "setHeaders":
+ case "replaceHeaderKeys":
+ Comp = (
+ <Row gutter={8}>
+ <Col span={12}>
+ <ConfigInput
+ code="key"
+ data={data}
+ onChange={this.onChangeConfig}
+ />
+ </Col>
+ <Col span={12}>
+ <ConfigInput
+ code="value"
+ data={data}
+ onChange={this.onChangeConfig}
+ />
+ </Col>
+ </Row>
+ );
+ break;
+ case "addBodyKeys":
+ case "replaceBodyKeys":
+ Comp = (
+ <Row gutter={8}>
+ <Col span={8}>
+ <ConfigInput
+ code="path"
+ data={data}
+ onChange={this.onChangeConfig}
+ />
+ </Col>
+ <Col span={8}>
+ <ConfigInput
+ code="key"
+ data={data}
+ onChange={this.onChangeConfig}
+ />
+ </Col>
+ <Col span={8}>
+ <ConfigInput
+ code="value"
+ data={data}
+ onChange={this.onChangeConfig}
+ />
+ </Col>
+ </Row>
+ );
+ break;
+ case "removeHeaderKeys":
+ case "removeBodyKeys":
+ default:
+ Comp = (
+ <Row gutter={8}>
+ <Col span={24}>
+ <ConfigInput
+ code="key"
+ data={data}
+ onChange={this.onChangeConfig}
+ />
+ </Col>
+ </Row>
+ );
+ break;
+ }
+
+ return Comp;
+ };
+
+ render() {
+ const { activeKey } = this.state;
+
+ const columns = [
+ {
+ title: "Type",
+ dataIndex: "type",
+ width: 180,
+ render: (value, row) => {
+ return (
+ <Select
+ value={row.type}
+ onChange={type => this.onChangeConfig({ type }, row.id)}
+ >
+ {TypeKey[activeKey].map(v => (
+ <Option key={v} value={v}>
+ {v}
+ </Option>
+ ))}
+ </Select>
+ );
+ }
+ },
+ {
+ title: "Config",
+ dataIndex: "config",
+ align: "center",
+ render: (value, row) => this.renderConfig(row)
+ },
+ {
+ title: "Operater",
+ dataIndex: "id",
+ with: 80,
+ fixed: "right",
+ render: (value, row, index) => {
+ return (
+ this.state[activeKey].length - 1 !== index && (
+ <Button
+ type="danger"
+ onClick={() => {
+ this.setState({
+ [activeKey]: this.state[activeKey].filter(
+ v => v.id !== row.id
+ )
+ });
+ }}
+ >
+ {getIntlContent("SHENYU.COMMON.DELETE.NAME")}
+ </Button>
+ )
+ );
+ }
+ }
+ ];
+
+ const statusCodeColums = [
+ {
+ title: "Code",
+ dataIndex: "code",
+ render: (value, row) => (
+ <InputNumber
+ style={{ width: 100 }}
+ precision={0}
+ min={200}
+ max={599}
+ placeholder="200~599"
+ value={value}
+ onChange={v => this.onChangeConfig({ code: v }, row.id)}
+ />
+ )
+ }
+ ];
+
+ return (
+ <>
+ <Tabs
+ activeKey={activeKey}
+ onChange={key =>
+ this.setState({
+ activeKey: key
+ })
+ }
+ >
+ <TabPane tab="StatusCode" key="statusCode" />
+ <TabPane tab="Headers" key="headers" />
+ <TabPane tab="Body" key="body" />
+ </Tabs>
+ <Table
+ rowKey="id"
+ size="small"
+ columns={activeKey === "statusCode" ? statusCodeColums : columns}
+ dataSource={this.state[activeKey]}
+ pagination={false}
+ />
+ </>
+ );
+ }
+}
+
+export default class ResponseRuleHandle extends Component {
+ constructor(props) {
+ super(props);
+ props.onRef(this);
+ }
+
+ getData = () => {
+ const {
+ form: { getFieldValue }
+ } = this.props;
+ const value = getFieldValue("handle");
+ return value;
+ };
+
+ render() {
+ const {
+ handle,
+ form: { getFieldDecorator }
+ } = this.props;
+
+ return (
+ <Form.Item
+ label={getIntlContent("SHENYU.COMMON.DEAL")}
+ labelCol={{ span: 3 }}
+ wrapperCol={{ span: 21 }}
+ >
+ {getFieldDecorator("handle", {
+ initialValue: handle
+ })(<ResponseConfig />)}
+ </Form.Item>
+ );
+ }
+}
diff --git a/src/routes/Plugin/PluginRuleHandle/index.js b/src/routes/Plugin/PluginRuleHandle/index.js
index b880994..5019490 100644
--- a/src/routes/Plugin/PluginRuleHandle/index.js
+++ b/src/routes/Plugin/PluginRuleHandle/index.js
@@ -1,9 +1,11 @@
-import RequestRuleHandle from './RequestRuleHandle';
-import HystrixRuleHandle from './HystrixRuleHandle';
+import RequestRuleHandle from "./RequestRuleHandle";
+import HystrixRuleHandle from "./HystrixRuleHandle";
import ParamPluginRuleHandle from "./ParamPluginRuleHandle";
+import ResponseRuleHandle from "./ResponseRuleHandle";
export default {
- request:RequestRuleHandle,
- hystrix:HystrixRuleHandle,
- param_mapping: ParamPluginRuleHandle
-}
+ request: RequestRuleHandle,
+ modifyResponse: ResponseRuleHandle,
+ hystrix: HystrixRuleHandle,
+ param_mapping: ParamPluginRuleHandle
+};