From b8690455c4582fe80334631f9f511ecfcac7773a Mon Sep 17 00:00:00 2001 From: liugq Date: Wed, 27 Oct 2021 11:42:11 +0800 Subject: [PATCH] add new cluster overview and command manage --- api/index_management/common_command.go | 49 ++- api/init.go | 1 + config/generated.go | 8 +- web/config/router.config.js | 15 + .../kibana/console/components/Console.tsx | 1 + .../request_status_bar/request_status_bar.tsx | 10 +- web/src/pages/Cluster/NewOverview.js | 33 ++ .../pages/Cluster/components/cluster_card.js | 63 ++++ .../Cluster/components/cluster_card.scss | 124 +++++++ .../Cluster/components/cluster_detail.js | 32 ++ web/src/pages/Cluster/components/clusters.js | 73 ++++ .../pages/Cluster/components/clusters.scss | 72 ++++ .../pages/Cluster/components/detail/index.js | 1 + .../Cluster/components/detail/metrics.js | 8 + web/src/pages/Cluster/components/tag.js | 56 +++ web/src/pages/Cluster/components/tag.scss | 22 ++ web/src/pages/System/Command/Index.js | 331 ++++++++++++++++++ .../pages/System/Command/models/command.js | 54 +++ web/src/services/command.js | 24 ++ 19 files changed, 964 insertions(+), 13 deletions(-) create mode 100644 web/src/pages/Cluster/NewOverview.js create mode 100644 web/src/pages/Cluster/components/cluster_card.js create mode 100644 web/src/pages/Cluster/components/cluster_card.scss create mode 100644 web/src/pages/Cluster/components/cluster_detail.js create mode 100644 web/src/pages/Cluster/components/clusters.js create mode 100644 web/src/pages/Cluster/components/clusters.scss create mode 100644 web/src/pages/Cluster/components/detail/index.js create mode 100644 web/src/pages/Cluster/components/detail/metrics.js create mode 100644 web/src/pages/Cluster/components/tag.js create mode 100644 web/src/pages/Cluster/components/tag.scss create mode 100644 web/src/pages/System/Command/Index.js create mode 100644 web/src/pages/System/Command/models/command.js create mode 100644 web/src/services/command.js diff --git a/api/index_management/common_command.go b/api/index_management/common_command.go index b76bf5f9..aa008c6a 100644 --- a/api/index_management/common_command.go +++ b/api/index_management/common_command.go @@ -7,6 +7,8 @@ import ( "infini.sh/framework/core/orm" "infini.sh/framework/core/util" "net/http" + "strconv" + "strings" "time" ) @@ -52,20 +54,55 @@ func (h *APIHandler) HandleQueryCommonCommandAction(w http.ResponseWriter, req * resBody := map[string]interface{}{ } - //title := h.GetParameterOrDefault(req, "title", "") - //tag := h.GetParameterOrDefault(req, "search", "") + var ( + title = h.GetParameterOrDefault(req, "title", "") + queryDSL = `{"query":{"bool":{"filter":[%s]}}, "size": %d, "from": %d}` + strSize = h.GetParameterOrDefault(req, "size", "20") + strFrom = h.GetParameterOrDefault(req, "from", "0") + filterBuilder = &strings.Builder{} + ) + if title != ""{ + filterBuilder.WriteString(fmt.Sprintf(`{"prefix":{"title": "%s"}}`, title)) + } + size, _ := strconv.Atoi(strSize) + if size <= 0 { + size = 20 + } + from, _ := strconv.Atoi(strFrom) + if from < 0 { + from = 0 + } + queryDSL = fmt.Sprintf(queryDSL, filterBuilder.String(), size, from) esClient := elastic.GetClient(h.Config.Elasticsearch) - //queryDSL :=[]byte(fmt.Sprintf(`{"query":{"bool":{"must":{"match":{"title":"%s"}}}}}`, title)) - searchRes, err := esClient.SearchWithRawQueryDSL(orm.GetIndexName(elastic.CommonCommand{}),nil) + searchRes, err := esClient.SearchWithRawQueryDSL(orm.GetIndexName(elastic.CommonCommand{}), []byte(queryDSL)) if err != nil { resBody["error"] = err h.WriteJSON(w, resBody, http.StatusInternalServerError) return } - - h.WriteJSON(w, searchRes,http.StatusOK) } + +func (h *APIHandler) HandleDeleteCommonCommandAction(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { + resBody := map[string]interface{}{} + id := ps.ByName("cid") + esClient := elastic.GetClient(h.Config.Elasticsearch) + delRes, err := esClient.Delete(orm.GetIndexName(elastic.CommonCommand{}), "", id, "wait_for") + if err != nil { + resBody["error"] = err.Error() + if delRes!=nil{ + h.WriteJSON(w, resBody, delRes.StatusCode) + }else{ + h.WriteJSON(w, resBody, http.StatusInternalServerError) + } + return + } + + elastic.RemoveInstance(id) + resBody["_id"] = id + resBody["result"] = delRes.Result + h.WriteJSON(w, resBody, delRes.StatusCode) +} \ No newline at end of file diff --git a/api/init.go b/api/init.go index 1fb9c90e..7ad9bf25 100644 --- a/api/init.go +++ b/api/init.go @@ -44,6 +44,7 @@ func Init(cfg *config.AppConfig) { ui.HandleUIMethod(api.POST, path.Join(pathPrefix, "elasticsearch/command"), handler.HandleSaveCommonCommandAction) ui.HandleUIMethod(api.GET, path.Join(pathPrefix, "elasticsearch/command"), handler.HandleQueryCommonCommandAction) + ui.HandleUIMethod(api.DELETE, path.Join(pathPrefix, "elasticsearch/command/:cid"), handler.HandleDeleteCommonCommandAction) //new api ui.HandleUIMethod(api.GET, path.Join(pathPrefix, "alerting/overview"), alerting.GetAlertOverview) diff --git a/config/generated.go b/config/generated.go index 3b59192e..65c4273d 100644 --- a/config/generated.go +++ b/config/generated.go @@ -1,8 +1,8 @@ package config -const LastCommitLog = "b8fb6a3, Fri Oct 15 11:41:38 2021 +0800, liugq, console tab v0.1 " -const BuildDate = "2021-10-21 13:55:53" +const LastCommitLog = "N/A" +const BuildDate = "N/A" -const EOLDate = "2021-12-31 10:10:10" +const EOLDate = "N/A" -const Version = "1.0.0_SNAPSHOT" +const Version = "0.0.1-SNAPSHOT" diff --git a/web/config/router.config.js b/web/config/router.config.js index 1ced84e2..b33bbbb5 100644 --- a/web/config/router.config.js +++ b/web/config/router.config.js @@ -33,6 +33,15 @@ export default [ // { path: '/', redirect: '/' }, // ], // }, + { + path: '/cluster/overview_new', + name: 'overview', + component: './Cluster/NewOverview', + // hideInMenu: true, + routes:[ + { path: '/', redirect: '/' }, + ], + }, { path: '/cluster/overview', name: 'overview', @@ -471,6 +480,12 @@ export default [ component: './System/Cluster/Form', hideInMenu: true }, + { + path: '/system/command', + name: 'command', + component: './System/Command/Index', + hideInMenu: true + }, // { // path: '/system/settings', // name: 'settings', diff --git a/web/src/components/kibana/console/components/Console.tsx b/web/src/components/kibana/console/components/Console.tsx index ef08fb6e..89a314d1 100644 --- a/web/src/components/kibana/console/components/Console.tsx +++ b/web/src/components/kibana/console/components/Console.tsx @@ -99,6 +99,7 @@ const ConsoleWrapper = ({ { let content: React.ReactNode = null; const clusterContent = (
@@ -154,11 +155,11 @@ export const RequestStatusBar = ({
集群地址: - {selectedCluster.host} + {selectedCluster.host}
版本: - {selectedCluster.version} + {selectedCluster.version}
); const [headerInfoVisible, setHeaderInfoVisible] = React.useState(false) @@ -178,6 +179,7 @@ const [headerInfoVisible, setHeaderInfoVisible] = React.useState(false) <>
+ 响应状态:
+ 时延: {setHeaderInfoVisible(false)}} diff --git a/web/src/pages/Cluster/NewOverview.js b/web/src/pages/Cluster/NewOverview.js new file mode 100644 index 00000000..6c895ffd --- /dev/null +++ b/web/src/pages/Cluster/NewOverview.js @@ -0,0 +1,33 @@ +import * as React from 'react'; +import {Tabs} from 'antd'; +import Clusters from './components/clusters'; +const {TabPane} = Tabs; + + +const panes = [ + { title: 'Clusters', component: Clusters, key: 'clusters' }, + { title: 'Hosts', component: 'Content of Tab 2', key: 'hosts' }, + {title: 'Nodes', component: 'Content of Tab 3',key: 'nodes'}, + {title: 'Indices', component: 'Content of Tab 3',key: 'indices'}, +]; + +const NewOverview = ()=>{ + + return (
+
+ {}} + type="card" + tabBarGutter={10} + > + {panes.map(pane => ( + + {typeof pane.component == 'string'? pane.component: } + + ))} + +
+
); +} + +export default NewOverview; \ No newline at end of file diff --git a/web/src/pages/Cluster/components/cluster_card.js b/web/src/pages/Cluster/components/cluster_card.js new file mode 100644 index 00000000..c08b9520 --- /dev/null +++ b/web/src/pages/Cluster/components/cluster_card.js @@ -0,0 +1,63 @@ +import './cluster_card.scss'; + +const ClusterCard = ()=>{ + return ( +
+
+ Cluster A +
+
+
+ Availability History(Last 7 Days) +
+
+ 100.0% + 128 Nodes + 1280 Shards +
+
+ + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 100TB + Dev + 7.6.1 + 8 Nodes +
+
+
+ ) +} + +export default ClusterCard; \ No newline at end of file diff --git a/web/src/pages/Cluster/components/cluster_card.scss b/web/src/pages/Cluster/components/cluster_card.scss new file mode 100644 index 00000000..36fa4327 --- /dev/null +++ b/web/src/pages/Cluster/components/cluster_card.scss @@ -0,0 +1,124 @@ +.bg-green { + background-color: green; +} +.bg-yellow { + background-color: yellow; +} +.bg-red { + background-color: red; +} + .cluster-item { + border: 1px solid black; + width: 100%; + height: 130px; + margin-bottom: 15px; + display: flex; +} + .cluster-item .cluster-name { + width: 15%; + height: 100%; + background-color: #a9b108; + color: white; + display: inline-flex; + align-items: center; + justify-content: center; +} + .cluster-item .cluster-info { + /*background-color: lightblue;*/ + width: 40%; + height: 100%; + padding: 0 5px; +} + .cluster-item .cluster-info .info-top { + /*background-color: lightseagreen;*/ + margin: 5px 0 5px 5px; +} + .cluster-item .cluster-info .info-top .text { + height: 23px; + line-height: 23px; + font-weight: bold; + font-size: 12px; + padding-left: 5px +; +} + .cluster-item .cluster-info .info-middle { + width: 100%; + margin: 8px auto; + display: flex; + justify-content: space-between; + +} + .cluster-item .label { + text-align: center; + display: inline-block; + padding: 0 10px; + min-width: 60px; + height: 30px; + line-height: 30px; +} + .cluster-item .label.label-primary { + background-color: #1f63af; + color: white; +} + .cluster-item .cluster-info .info-bottom { + display: flex; + flex-wrap: wrap; + margin-top: 3px; +} + .cluster-item .cluster-info .info-bottom .status-block { + width: 18px; + height: 18px; + margin: 3px 5px; +} + .cluster-item .cluster-chart { + width: 45%; + height: 100%; + padding: 0 5px; +; +} + .cluster-item .cluster-chart .chart-top { + height: 90px; + width: 100%; + display: flex; + margin-top: 5px; + margin-bottom: 3px; +} + .cluster-item .cluster-chart .chart-top .pie-chart { + height: 90px; + width: 50%; + display: flex; + justify-content: space-between; + background-color: lightgray; +} + .cluster-item .cluster-chart .chart-top .pie-chart .item { + width: 50%; +} + .cluster-item .cluster-chart .chart-top .pie-chart .item.pie1{ + background-color: goldenrod; +} + .cluster-item .cluster-chart .chart-top .pie-chart .item.pie2{ + background-color: greenyellow; +} + .cluster-item .cluster-chart .chart-top .line-chart { + height: 90px; + width: 50%; + display: flex; + flex-direction: column; +} + .cluster-item .cluster-chart .chart-top .line-chart .item { + height: 45px; + width: 100%; +} + .cluster-item .cluster-chart .chart-top .line-chart .item.line1{ + background-color: #ff8080; +} + .cluster-item .cluster-chart .chart-top .line-chart .item.line2{ + background-color: lightseagreen; +} + .cluster-item .cluster-chart .chart-bottom { + height: 30px; + width: 100%; + display: flex; + /*background-color: lightgreen;*/ + justify-content: space-between; +} \ No newline at end of file diff --git a/web/src/pages/Cluster/components/cluster_detail.js b/web/src/pages/Cluster/components/cluster_detail.js new file mode 100644 index 00000000..64c85012 --- /dev/null +++ b/web/src/pages/Cluster/components/cluster_detail.js @@ -0,0 +1,32 @@ +import {Tabs} from 'antd'; +import {Metrics} from './detail'; + +const {TabPane} = Tabs; + +const panes = [ + { title: 'Metrics', component: Metrics, key: 'metrics' }, + { title: 'Infos', component: 'Content of Tab 2', key: 'infos' }, + {title: 'Activities', component: 'Content of Tab 3',key: 'activities'}, + {title: 'Console', component: 'Content of Tab 3',key: 'console'}, +]; + +const ClusterDetail = ()=>{ + return ( +
+ {}} + type="card" + tabBarGutter={10} + tabPosition="right" + > + {panes.map(pane => ( + + {typeof pane.component == 'string'? pane.component: } + + ))} + +
+ ); +} + +export default ClusterDetail; \ No newline at end of file diff --git a/web/src/pages/Cluster/components/clusters.js b/web/src/pages/Cluster/components/clusters.js new file mode 100644 index 00000000..037905d6 --- /dev/null +++ b/web/src/pages/Cluster/components/clusters.js @@ -0,0 +1,73 @@ +import { Input, Icon, List, Card,Button } from 'antd'; +import * as React from 'react'; +import './clusters.scss'; +import ClusterDetail from './cluster_detail'; +import {TagList} from './tag'; +import ClusterCard from './cluster_card'; + +const { Search } = Input; + +const Clusters = ()=>{ + const [collapse, setCollapse] = React.useState(false); + const toggleCollapse = ()=>{ + setCollapse(!collapse) + } + const clusterList = [1, 2, 3, 4, 5, 6, 7, 8]; + return ( +
+
+
+
+
+ console.log(value)} + /> +
+
+ +
+
+
+ +
+
+ { + console.log(page); + }, + showSizeChanger: true, + pageSizeOptions: ['5','10','20'], + showTotal: (total, range) => `${range[0]}-${range[1]} of ${total} items`, + pageSize: 5, + }} + dataSource={clusterList} + renderItem={(item)=>( + + {/* +

Card content

+
*/} + +
+ )} + /> +
+
+
+ + + +
+
+ +
+
+
+ ) +} + +export default Clusters; \ No newline at end of file diff --git a/web/src/pages/Cluster/components/clusters.scss b/web/src/pages/Cluster/components/clusters.scss new file mode 100644 index 00000000..189f2c27 --- /dev/null +++ b/web/src/pages/Cluster/components/clusters.scss @@ -0,0 +1,72 @@ +.overview { + padding: 15px; + .clusters{ + >.wrapper{ + display: flex; + .col{ + flex: 1 1 50%; + position: relative; + &.left{ + border-right: 1px solid rgb(232, 232, 232); + padding-right: 15px; + .card-cnt{ + margin-top: 10px; + .ant-list-item{ + border-bottom: none !important; + } + } + } + &.right{ + padding-left: 15px; + } + &.collapse{ + flex: 0 0 0px; + max-width: 0px; + min-width: 0px; + width: 0px; + height: 0px; + overflow: hidden; + padding-right: 0; + } + } + >.collapse{ + margin: auto; + .area{ + font-size: 12px; + display: inline-block; + color: #6c7f90; + z-index: 4; + left: -1px; + width: 22px; + cursor: pointer; + transition: color .3s; + background-color: #fff; + height: 66px; + box-sizing: border-box; + border-bottom-right-radius: 4px; + border-top-right-radius: 4px; + border: 1px solid #ececec; + border-left: none; + text-align: center; + position: relative; + .icon{ + position: absolute; + left: 3px; + top: 25px; + } + } + } + .search-line{ + display: flex; + align-items: center; + .search-box{ + flex: 1 1 auto; + max-width: 600px; + } + } + .tag-line{ + margin: 10px auto; + } + } + } +} \ No newline at end of file diff --git a/web/src/pages/Cluster/components/detail/index.js b/web/src/pages/Cluster/components/detail/index.js new file mode 100644 index 00000000..0a2ff2e0 --- /dev/null +++ b/web/src/pages/Cluster/components/detail/index.js @@ -0,0 +1 @@ +export * from './metrics'; \ No newline at end of file diff --git a/web/src/pages/Cluster/components/detail/metrics.js b/web/src/pages/Cluster/components/detail/metrics.js new file mode 100644 index 00000000..018146a0 --- /dev/null +++ b/web/src/pages/Cluster/components/detail/metrics.js @@ -0,0 +1,8 @@ + +export const Metrics = ()=>{ + return ( +
+ Metrics content +
+ ) +} \ No newline at end of file diff --git a/web/src/pages/Cluster/components/tag.js b/web/src/pages/Cluster/components/tag.js new file mode 100644 index 00000000..dfd41b41 --- /dev/null +++ b/web/src/pages/Cluster/components/tag.js @@ -0,0 +1,56 @@ + +import './tag.scss'; +import * as React from 'react'; + +export const Tag = (props={})=>{ + + const [checked, setChecked] = React.useState(props.checked) + const toggleChecked = ()=>{ + if(typeof props.onChange == 'function'){ + props.onChange({ + checked: !checked, + text: props.text, + }) + } + setChecked(!checked); + } + return ( +
+
+ {props.text} +
+
+ ) +} + +export const TagList = (props)=>{ + const [value, setValue] = React.useState(()=>{ + return (props.value||[]).filter(item=>item.checked == true) + }) + const onTagChange = (citem)=>{ + const newVal = [...value] + const idx = newVal.findIndex(item=>item.text == citem.text); + if(idx > -1) { + if(citem.checked == true){ + newVal[idx].checked = citem.checked; + }else{ + newVal.splice(idx,1) + } + }else{ + if(citem.checked == true){ + newVal.push(citem); + } + } + if(typeof props.onChange == 'function'){ + props.onChange(newVal); + } + setValue(newVal); + } + return ( +
+ {(props.value||[]).map((item)=>{ + return + })} +
+ ) +} \ No newline at end of file diff --git a/web/src/pages/Cluster/components/tag.scss b/web/src/pages/Cluster/components/tag.scss new file mode 100644 index 00000000..e82b8767 --- /dev/null +++ b/web/src/pages/Cluster/components/tag.scss @@ -0,0 +1,22 @@ +.tag-list{ + display: flex; + align-items: center; + .tag{ + margin-left: 10px; + display: inline-block; + border: 1px solid #e8e8e8; + cursor: pointer; + &.checked{ + background: #1890ff; + color: #fff; + } + >.wrapper{ + font-size: 12px; + line-height: 2em; + padding: 0 10px; + } + } + .tag:first-child{ + margin-left: 0px; + } +} diff --git a/web/src/pages/System/Command/Index.js b/web/src/pages/System/Command/Index.js new file mode 100644 index 00000000..2d3567b9 --- /dev/null +++ b/web/src/pages/System/Command/Index.js @@ -0,0 +1,331 @@ +import React, { PureComponent, Fragment } from 'react'; +import { connect } from 'dva'; +import {Link} from 'umi'; +import { + Row, + Col, + Card, + Form, + Input, + Button, + Modal, + message, + Divider, + Drawer, + Tabs, + Descriptions, + Menu, + Table, + Dropdown, + Icon, Popconfirm, + Switch, +} from 'antd'; +import Editor from '@monaco-editor/react'; + +import styles from '../../List/TableList.less'; +import {transformSettingsForApi} from '@/lib/elasticsearch/edit_settings'; +import PageHeaderWrapper from '@/components/PageHeaderWrapper'; + +const FormItem = Form.Item; +const { TextArea } = Input; +const {TabPane} = Tabs; + +class JSONWrapper extends PureComponent { + state ={ + height: 400, + } + componentDidMount(){ + + let getElementTop = (elem)=>{ +   var elemTop=elem.offsetTop; +   elem=elem.offsetParent; + +   while(elem!=null){ +     elemTop+=elem.offsetTop; +     elem=elem.offsetParent; +   } + +   return elemTop; + + } + // console.log(getElementTop(this.refs.jsonw)); + this.setState({height: window.innerHeight - getElementTop(this.refs.jsonw) -50}); + } + render(){ + return ( +
{console.log(document.getElementById('jsonw').offsetTop)}} style={{overflow:"scroll", height: this.state.height}}> {this.props.children}
+ ) + } +} +@Form.create() +class CreateForm extends React.Component { + okHandle = () => { + const {handleAdd, form} = this.props; + const me = this; + + form.validateFields((err, fieldsValue) => { + if (err) return; + fieldsValue['config'] = me.editor.getValue(); + handleAdd(fieldsValue); + form.resetFields(); + }); + }; + onEditorDidMount = (editor)=>{ + this.editor = editor; + } + + render() { + const {modalVisible, form, handleModalVisible} = this.props; + return ( + handleModalVisible()} + > + + {form.getFieldDecorator('index', { + rules: [{required: true, message: '请输入至少五个字符的名称!', min: 5}], + })()} + + +
+ +
+
+
+ ); + } +} + + +/* eslint react/no-multi-comp:0 */ +@connect(({ command }) => ({ + command +})) +@Form.create() +class Index extends PureComponent { + state = { + modalVisible: false, + updateModalVisible: false, + expandForm: false, + formValues: {}, + drawerVisible: false, + editingCommand:{}, + indexActiveKey: '1', + showSystemIndices: false, + }; + columns = [ + { + title: '名称', + dataIndex: 'title', + render: (text, record) => ( + { + this.setState({ + editingCommand: record, + drawerVisible: true, + }); + }}>{text} + ) + }, + { + title: '标签', + dataIndex: 'tag', + // render: (val)=>{ + // return val || 0; + // } + }, + { + title: '操作', + render: (text, record) => ( + + this.handleDeleteClick(record.id)}> + 删除 + + + ), + }, + ]; + + componentDidMount() { + this.fetchData() + } + + fetchData = (params={})=>{ + const { dispatch } = this.props; + dispatch({ + type: 'command/fetchCommandList', + payload: { + ...params + } + }); + } + + handleFormReset = () => { + const { form, dispatch } = this.props; + form.resetFields(); + this.setState({ + formValues: {}, + }); + }; + + handleDeleteClick = (id) => { + const { dispatch } = this.props; + dispatch({ + type: 'command/removeCommand', + payload: { + id: id, + } + }); + }; + + handleSearch = e => { + e.preventDefault(); + const { dispatch, form } = this.props; + + form.validateFields((err, fieldsValue) => { + if (err) return; + this.fetchData({ + title: fieldsValue.name, + from: 0, + size: 10, + }) + this.setState({ + searchKey: fieldsValue.name, + }); + }); + }; + + handleModalVisible = flag => { + this.setState({ + modalVisible: !!flag, + }); + }; + + handleIndexTabChanged = (activeKey, indexName) => { + } + handleEditorDidMount = (editorName, editor)=>{ + this[editorName] = editor; + } + + handleIndexSettingsSaveClick = (indexName)=>{ + } + buildRawCommonCommandRequest(cmd){ + const {requests} = cmd; + if(!requests){ + return ''; + } + const strReqs = requests.map((req)=>{ + const {method, path, body} = req; + return `${method} ${path}\n${body}`; + }) + return strReqs.join('\n'); + } + handleRereshClick=()=>{ + const {searchKey} = this.state; + this.fetchData({ + title: searchKey, + }) + } + + render() { + const {data, total} = this.props.command; + const { modalVisible, updateModalVisible, updateFormValues, drawerVisible, editingCommand } = this.state; + const parentMethods = { + handleAdd: this.handleAdd, + handleModalVisible: this.handleModalVisible, + }; + const updateMethods = { + handleUpdateModalVisible: this.handleUpdateModalVisible, + handleUpdate: this.handleUpdate, + }; + const {form: { getFieldDecorator }} = this.props; + + return ( + + +
+
+
+ + + + {getFieldDecorator('name')()} + + + + + + + + + + + + +
+
+ + + + + + { + this.setState({ + drawerVisible: false, + indexActiveKey: '1', + }); + }} + width={720} + > +
+ this.handleEditorDidMount('indexSettingsEditor', editor)} + /> +
+
+ + ); + } +} + +export default Index; diff --git a/web/src/pages/System/Command/models/command.js b/web/src/pages/System/Command/models/command.js new file mode 100644 index 00000000..0c37d4e9 --- /dev/null +++ b/web/src/pages/System/Command/models/command.js @@ -0,0 +1,54 @@ +import {searchCommand, deleteCommand} from "@/services/command"; +import {message} from "antd"; +import {formatESSearchResult} from '@/lib/elasticsearch/util'; + +export default { + namespace: 'command', + state: { + }, + effects:{ + *fetchCommandList({payload}, {call, put, select}){ + let res = yield call(searchCommand, payload); + if(res.error){ + message.error(res.error) + return false; + } + res = formatESSearchResult(res) + yield put({ + type: 'saveData', + payload: res + }) + }, + + *removeCommand({payload}, {call, put, select}) { + let res = yield call(deleteCommand, payload) + if(res.error){ + message.error(res.error) + return false; + } + let {data, total} = yield select(state => state.command); + data = data.filter((item)=>{ + return item.id !== payload.id; + }) + yield put({ + type: 'saveData', + payload: { + data, + total: { + ...total, + value: total.value - 1 + } + } + }) + return res; + }, + }, + reducers:{ + saveData(state, {payload}){ + return { + ...state, + ...payload, + } + } + } +} diff --git a/web/src/services/command.js b/web/src/services/command.js new file mode 100644 index 00000000..54420d2b --- /dev/null +++ b/web/src/services/command.js @@ -0,0 +1,24 @@ +import request from '@/utils/request'; +import {buildQueryArgs, pathPrefix} from './common'; + +export async function searchCommand(params) { + let url = `${pathPrefix}/elasticsearch/command`; + let args = buildQueryArgs({ + title: params.title, + from: params.from, + size: params.size, + }); + if(args.length > 0){ + url += args; + } + return request(url, { + method: 'GET' + }); +} + +export async function deleteCommand(params) { + const url = `${pathPrefix}/elasticsearch/command/${params.id}`; + return request(url, { + method: 'DELETE' + }); +} \ No newline at end of file