From 408c2feb50a29e606cff5e745d20b994518e6977 Mon Sep 17 00:00:00 2001 From: liugq Date: Thu, 18 Nov 2021 16:26:43 +0800 Subject: [PATCH] monitor of node level and index level, common command manage --- api/index_management/common_command.go | 71 +- api/init.go | 3 +- main.go | 1 + web/config/router.config.js | 406 +++--- .../components/GlobalHeader/DropdownSelect.js | 249 ++-- .../components/GlobalHeader/RightContent.js | 129 +- .../console/components/CommonCommandModal.tsx | 81 +- .../console/components/ConsoleInput.tsx | 242 ++-- .../index_patterns/index_patterns.ts | 2 +- .../components/doc_viewer/doc_viewer.scss | 6 +- .../application/components/table/table.tsx | 38 +- web/src/lib/hooks/use_async.js | 23 + web/src/lib/hooks/use_fetch.js | 21 + web/src/pages/Cluster/Metrics.js | 1146 +++++++++-------- web/src/pages/Cluster/Metrics.less | 10 +- .../pages/Cluster/components/index_metric.jsx | 225 ++++ .../pages/Cluster/components/node_metric.jsx | 223 ++++ .../pages/Cluster/components/node_metric.scss | 13 + web/src/pages/Cluster/format.js | 46 + web/src/pages/Cluster/models/cluster.js | 94 +- web/src/pages/DataManagement/Discover.jsx | 5 +- web/src/pages/DevTool/Console.tsx | 9 +- web/src/pages/DevTool/NewTabMenu.jsx | 221 ++-- .../pages/System/Cluster/models/cluster.js | 173 +-- web/src/pages/System/Command/Index.js | 381 +++--- .../pages/System/Command/models/command.js | 111 +- web/src/services/command.js | 46 +- 27 files changed, 2458 insertions(+), 1517 deletions(-) create mode 100644 web/src/lib/hooks/use_async.js create mode 100644 web/src/lib/hooks/use_fetch.js create mode 100644 web/src/pages/Cluster/components/index_metric.jsx create mode 100644 web/src/pages/Cluster/components/node_metric.jsx create mode 100644 web/src/pages/Cluster/components/node_metric.scss create mode 100644 web/src/pages/Cluster/format.js diff --git a/api/index_management/common_command.go b/api/index_management/common_command.go index aa008c6a..ea101d65 100644 --- a/api/index_management/common_command.go +++ b/api/index_management/common_command.go @@ -12,15 +12,15 @@ import ( "time" ) -func (h *APIHandler) HandleSaveCommonCommandAction(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { +func (h *APIHandler) HandleAddCommonCommandAction(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { resBody := map[string]interface{}{ } reqParams := elastic.CommonCommand{} err := h.DecodeJSON(req, &reqParams) if err != nil { - resBody["error"] = err - h.WriteJSON(w, resBody, http.StatusInternalServerError) + resBody["error"] = err.Error() + h.WriteJSON(w, resBody, http.StatusOK) return } @@ -28,20 +28,25 @@ func (h *APIHandler) HandleSaveCommonCommandAction(w http.ResponseWriter, req *h reqParams.ID = util.GetUUID() esClient := elastic.GetClient(h.Config.Elasticsearch) - queryDSL :=[]byte(fmt.Sprintf(`{"size":1, "query":{"bool":{"must":{"match":{"title":"%s"}}}}}`, reqParams.Title)) + queryDSL :=[]byte(fmt.Sprintf(`{"size":1, "query":{"bool":{"must":{"match":{"title.keyword":"%s"}}}}}`, reqParams.Title)) var indexName = orm.GetIndexName(reqParams) searchRes, err := esClient.SearchWithRawQueryDSL(indexName, queryDSL) if err != nil { - resBody["error"] = err - h.WriteJSON(w, resBody, http.StatusInternalServerError) + resBody["error"] = err.Error() + h.WriteJSON(w, resBody, http.StatusOK) return } if len(searchRes.Hits.Hits) > 0 { resBody["error"] = "title already exists" - h.WriteJSON(w, resBody, http.StatusInternalServerError) + h.WriteJSON(w, resBody, http.StatusOK) return } _, err = esClient.Index(indexName,"", reqParams.ID, reqParams) + if err != nil { + resBody["error"] = err.Error() + h.WriteJSON(w, resBody, http.StatusOK) + return + } resBody["_id"] = reqParams.ID resBody["result"] = "created" @@ -49,20 +54,64 @@ func (h *APIHandler) HandleSaveCommonCommandAction(w http.ResponseWriter, req *h h.WriteJSON(w, resBody,http.StatusOK) } +func (h *APIHandler) HandleSaveCommonCommandAction(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { + resBody := map[string]interface{}{ + } + + reqParams := elastic.CommonCommand{} + err := h.DecodeJSON(req, &reqParams) + if err != nil { + resBody["error"] = err.Error() + h.WriteJSON(w, resBody, http.StatusOK) + return + } + reqParams.ID = ps.ByName("cid") + esClient := elastic.GetClient(h.Config.Elasticsearch) + + queryDSL :=[]byte(fmt.Sprintf(`{"size":1, "query":{"bool":{"must":{"match":{"title.keyword":"%s"}}}}}`, reqParams.Title)) + var indexName = orm.GetIndexName(reqParams) + searchRes, err := esClient.SearchWithRawQueryDSL(indexName, queryDSL) + if err != nil { + resBody["error"] = err.Error() + h.WriteJSON(w, resBody, http.StatusOK) + return + } + if len(searchRes.Hits.Hits) > 0 && searchRes.Hits.Hits[0].ID.(string) != reqParams.ID { + resBody["error"] = "title already exists" + h.WriteJSON(w, resBody, http.StatusOK) + return + } + _, err = esClient.Index(indexName,"", reqParams.ID, reqParams) + if err != nil { + resBody["error"] = err.Error() + h.WriteJSON(w, resBody, http.StatusOK) + return + } + + resBody["_id"] = reqParams.ID + resBody["result"] = "updated" + resBody["_source"] = reqParams + + h.WriteJSON(w, resBody,http.StatusOK) +} func (h *APIHandler) HandleQueryCommonCommandAction(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { resBody := map[string]interface{}{ } var ( - title = h.GetParameterOrDefault(req, "title", "") - queryDSL = `{"query":{"bool":{"filter":[%s]}}, "size": %d, "from": %d}` + keyword = h.GetParameterOrDefault(req, "keyword", "") + queryDSL = `{"query":{"bool":{"must":[%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)) + if keyword != ""{ + filterBuilder.WriteString(fmt.Sprintf(`{"query_string": { + "default_field": "*", + "query": "%s" + } + }`, keyword)) } size, _ := strconv.Atoi(strSize) if size <= 0 { diff --git a/api/init.go b/api/init.go index b86b1ddb..b13468ae 100644 --- a/api/init.go +++ b/api/init.go @@ -41,7 +41,8 @@ func Init(cfg *config.AppConfig) { api.HandleAPIMethod(api.DELETE, path.Join(esPrefix, "index/:index"), handler.HandleDeleteIndexAction) api.HandleAPIMethod(api.POST, path.Join(esPrefix, "index/:index"), handler.HandleCreateIndexAction) - api.HandleAPIMethod(api.POST, path.Join(pathPrefix, "elasticsearch/command"), handler.HandleSaveCommonCommandAction) + api.HandleAPIMethod(api.POST, path.Join(pathPrefix, "elasticsearch/command"), handler.HandleAddCommonCommandAction) + api.HandleAPIMethod(api.PUT, path.Join(pathPrefix, "elasticsearch/command/:cid"), handler.HandleSaveCommonCommandAction) api.HandleAPIMethod(api.GET, path.Join(pathPrefix, "elasticsearch/command"), handler.HandleQueryCommonCommandAction) api.HandleAPIMethod(api.DELETE, path.Join(pathPrefix, "elasticsearch/command/:cid"), handler.HandleDeleteCommonCommandAction) diff --git a/main.go b/main.go index 9f119a32..4a965f88 100644 --- a/main.go +++ b/main.go @@ -91,6 +91,7 @@ func main() { orm.RegisterSchemaWithIndexName(alerting.Config{}, "alerting-config") orm.RegisterSchemaWithIndexName(alerting.Alert{}, "alerting-alerts") orm.RegisterSchemaWithIndexName(alerting.AlertingHistory{}, "alerting-alert-history") + orm.RegisterSchema(elastic.CommonCommand{}) alertSrv.GetScheduler().Start() },nil){ app.Run() diff --git a/web/config/router.config.js b/web/config/router.config.js index 0ade204b..d94334b3 100644 --- a/web/config/router.config.js +++ b/web/config/router.config.js @@ -1,97 +1,93 @@ export default [ // user { - path: '/user', - component: '../layouts/UserLayout', + path: "/user", + component: "../layouts/UserLayout", routes: [ - { path: '/user', redirect: '/user/login' }, - { path: '/user/login', component: './User/Login' }, - { path: '/user/register', component: './User/Register' }, - { path: '/user/register-result', component: './User/RegisterResult' }, + { path: "/user", redirect: "/user/login" }, + { path: "/user/login", component: "./User/Login" }, + { path: "/user/register", component: "./User/Register" }, + { path: "/user/register-result", component: "./User/RegisterResult" }, ], }, // app { - path: '/', - component: '../layouts/BasicLayout', - Routes: ['src/pages/Authorized'], - authority: ['admin', 'user'], + path: "/", + component: "../layouts/BasicLayout", + Routes: ["src/pages/Authorized"], + authority: ["admin", "user"], routes: [ // cluster - { path: '/', redirect: '/cluster/overview' }, + { path: "/", redirect: "/cluster/overview" }, { - path: '/cluster', - name: 'cluster', - icon: 'cluster', + path: "/cluster", + name: "cluster", + icon: "cluster", routes: [ - // { path: '/', redirect: '/platform/gateway' }, - // { - // path: '/cluster/overview/', - // name: 'overview', - // component: './Cluster/Overview', - // routes:[ - // { path: '/', redirect: '/' }, - // ], - // }, + // { path: '/', redirect: '/platform/gateway' }, + // { + // path: '/cluster/overview/', + // name: 'overview', + // component: './Cluster/Overview', + // routes:[ + // { path: '/', redirect: '/' }, + // ], + // }, { - path: '/cluster/overview', - name: 'overview', - component: './Cluster/NewOverview', - // hideInMenu: true, - routes:[ - { path: '/', redirect: '/' }, - ], - }, - { - path: '/cluster/monitoring/:cluster_id', - name: 'cluster', - component: './Cluster/ClusterMonitor', - hideInMenu: true, - routes:[ - { path: '/', redirect: '/' }, - ], - }, { - path: '/cluster/metrics/', - name: 'monitoring', - component: './Cluster/Metrics', - routes:[ - { path: '/', redirect: '/' }, - ], - }, { - path: '/cluster/metrics/:cluster_id', - name: 'monitoring', - component: './Cluster/Metrics', - hideInMenu: true, - }, - // { - // path: '/cluster/logs/', - // name: 'logging', - // component: './Cluster/SearchMonitor', - // routes:[ - // { path: '/', redirect: '/' }, - // ], - // },{ - // path: '/cluster/settings/', - // name: 'settings', - // component: './Cluster/Settings/Base', - // routes: [ - // { - // path: '/cluster/settings', - // redirect: '/cluster/settings/repository', - // routes:[ - // { path: '/', redirect: '/' }, - // ], - // }, - // { - // path: '/cluster/settings/repository', - // component: './Cluster/Settings/Repository', - // routes:[ - // { path: '/', redirect: '/' }, - // ], - // } - // ] - // }, - ] + path: "/cluster/overview", + name: "overview", + component: "./Cluster/NewOverview", + // hideInMenu: true, + routes: [{ path: "/", redirect: "/" }], + }, + { + path: "/cluster/monitoring/:cluster_id", + name: "cluster", + component: "./Cluster/ClusterMonitor", + hideInMenu: true, + routes: [{ path: "/", redirect: "/" }], + }, + { + path: "/cluster/metrics/", + name: "monitoring", + component: "./Cluster/Metrics", + routes: [{ path: "/", redirect: "/" }], + }, + { + path: "/cluster/metrics/:cluster_id", + name: "monitoring", + component: "./Cluster/Metrics", + hideInMenu: true, + }, + // { + // path: '/cluster/logs/', + // name: 'logging', + // component: './Cluster/SearchMonitor', + // routes:[ + // { path: '/', redirect: '/' }, + // ], + // },{ + // path: '/cluster/settings/', + // name: 'settings', + // component: './Cluster/Settings/Base', + // routes: [ + // { + // path: '/cluster/settings', + // redirect: '/cluster/settings/repository', + // routes:[ + // { path: '/', redirect: '/' }, + // ], + // }, + // { + // path: '/cluster/settings/repository', + // component: './Cluster/Settings/Repository', + // routes:[ + // { path: '/', redirect: '/' }, + // ], + // } + // ] + // }, + ], }, //devtools // { @@ -104,40 +100,38 @@ export default [ // component: './DevTool/Console', // }, - //alerting - { - path: '/alerting', - name: 'alerting', - icon: 'alert', - routes: [{ - routes:[ - { path: '/', redirect: '/' }, - ], - path: '/alerting/overview', - component: './Alerting/pages/Overview/Overview', - name: 'overview' - },{ - routes:[ - { path: '/', redirect: '/' }, - ], - path: '/alerting/monitor', - component: './Alerting/index', - name: 'monitor' - },{ - routes:[ - { path: '/', redirect: '/' }, - ], - path: '/alerting/destination', - component: './Alerting/destination', - name: 'destination' - }] + //alerting + { + path: "/alerting", + name: "alerting", + icon: "alert", + routes: [ + { + routes: [{ path: "/", redirect: "/" }], + path: "/alerting/overview", + component: "./Alerting/pages/Overview/Overview", + name: "overview", + }, + { + routes: [{ path: "/", redirect: "/" }], + path: "/alerting/monitor", + component: "./Alerting/index", + name: "monitor", + }, + { + routes: [{ path: "/", redirect: "/" }], + path: "/alerting/destination", + component: "./Alerting/destination", + name: "destination", + }, + ], }, //data { - path: '/data', - name: 'data', - icon: 'database', + path: "/data", + name: "data", + icon: "database", routes: [ // { // path: '/data/overview', @@ -146,14 +140,12 @@ export default [ // routes:[ // { path: '/', redirect: '/' }, // ], - // }, + // }, { - path: '/data/index', - name: 'index', - component: './DataManagement/Index', - routes:[ - { path: '/', redirect: '/' }, - ], + path: "/data/index", + name: "index", + component: "./DataManagement/Index", + routes: [{ path: "/", redirect: "/" }], }, // { // path: '/data/document', @@ -162,7 +154,7 @@ export default [ // routes:[ // { path: '/', redirect: '/' }, // ], - // }, + // }, // { // path: '/data/template', // name: 'template', @@ -180,31 +172,25 @@ export default [ // ], // }, { - routes:[ - { path: '/', redirect: '/' }, - ], - path: '/data/discover', - name: 'discover', - component: './DataManagement/Discover', + routes: [{ path: "/", redirect: "/" }], + path: "/data/discover", + name: "discover", + component: "./DataManagement/Discover", }, { - routes:[ - { path: '/', redirect: '/' }, - ], - path: '/data/views/', - name: 'indexPatterns', - component: './DataManagement/IndexPatterns', - + routes: [{ path: "/", redirect: "/" }], + path: "/data/views/", + name: "indexPatterns", + component: "./DataManagement/IndexPatterns", }, - ] + ], }, - - + //search { - path: '/search', - name: 'search', - icon: 'search', + path: "/search", + name: "search", + icon: "search", routes: [ // { // path: '/search/overview', @@ -245,34 +231,30 @@ export default [ // ], // }, // ] - // }, + // }, { - path: '/search/alias', - name: 'alias', - component: './SearchManage/alias/Alias', - routes: [ - { - path: '/search/alias', - redirect: '/search/alias/index', - // routes:[ - // { path: '/', redirect: '/' }, - // ], - }, - { - path: '/search/alias/index', - component: './SearchManage/alias/AliasManage', - routes:[ - { path: '/', redirect: '/' }, - ], - }, - { - path: '/search/alias/rule', - component: './SearchManage/alias/Rule', - routes:[ - { path: '/', redirect: '/' }, - ], - } - ] + path: "/search/alias", + name: "alias", + component: "./SearchManage/alias/Alias", + routes: [ + { + path: "/search/alias", + redirect: "/search/alias/index", + // routes:[ + // { path: '/', redirect: '/' }, + // ], + }, + { + path: "/search/alias/index", + component: "./SearchManage/alias/AliasManage", + routes: [{ path: "/", redirect: "/" }], + }, + { + path: "/search/alias/rule", + component: "./SearchManage/alias/Rule", + routes: [{ path: "/", redirect: "/" }], + }, + ], }, // { // path: '/search/dict', @@ -328,33 +310,33 @@ export default [ // ] // } //, { - // path: '/search/nlp', - // name: 'nlp', - // component: './SearchManage/nlp/NLP', - // routes: [ - // { - // path: '/search/nlp', - // redirect: '/search/nlp/query', - // }, - // { - // path: '/search/nlp/query', - // component: './SearchManage/nlp/Query', - // }, - // { - // path: '/search/nlp/intention', - // component: './SearchManage/nlp/Intention', - // }, - // { - // path: '/search/nlp/knowledge', - // component: './SearchManage/nlp/Knowledge', - // }, - // { - // path: '/search/nlp/text', - // component: './SearchManage/nlp/Text', - // } - //] - //}, - ] + // path: '/search/nlp', + // name: 'nlp', + // component: './SearchManage/nlp/NLP', + // routes: [ + // { + // path: '/search/nlp', + // redirect: '/search/nlp/query', + // }, + // { + // path: '/search/nlp/query', + // component: './SearchManage/nlp/Query', + // }, + // { + // path: '/search/nlp/intention', + // component: './SearchManage/nlp/Intention', + // }, + // { + // path: '/search/nlp/knowledge', + // component: './SearchManage/nlp/Knowledge', + // }, + // { + // path: '/search/nlp/text', + // component: './SearchManage/nlp/Text', + // } + //] + //}, + ], }, // // //sync @@ -450,32 +432,32 @@ export default [ //settings { - path: '/system', - name: 'system', - icon: 'setting', + path: "/system", + name: "system", + icon: "setting", routes: [ { - path: '/system/cluster', - name: 'cluster', - component: './System/Cluster/Index', + path: "/system/cluster", + name: "cluster", + component: "./System/Cluster/Index", }, { - path: '/system/cluster/regist', - name: 'registCluster', - component: './System/Cluster/Step', - hideInMenu: true + path: "/system/cluster/regist", + name: "registCluster", + component: "./System/Cluster/Step", + hideInMenu: true, }, { - path: '/system/cluster/edit', - name: 'editCluster', - component: './System/Cluster/Form', - hideInMenu: true + path: "/system/cluster/edit", + name: "editCluster", + component: "./System/Cluster/Form", + hideInMenu: true, }, { - path: '/system/command', - name: 'commonCommand', - component: './System/Command/Index', - hideInMenu: true + path: "/system/command", + name: "commonCommand", + component: "./System/Command/Index", + // hideInMenu: true }, // { // path: '/system/settings', @@ -549,7 +531,7 @@ export default [ // }, // ] // }, - ] + ], }, // // forms @@ -768,7 +750,7 @@ export default [ // ], // }, { - component: '404', + component: "404", }, ], }, diff --git a/web/src/components/GlobalHeader/DropdownSelect.js b/web/src/components/GlobalHeader/DropdownSelect.js index e27e904f..26a2fd4c 100644 --- a/web/src/components/GlobalHeader/DropdownSelect.js +++ b/web/src/components/GlobalHeader/DropdownSelect.js @@ -1,59 +1,71 @@ -import { Button, Dropdown, List, Spin, message, Icon, Input } from 'antd'; -import React from 'react'; -import InfiniteScroll from 'react-infinite-scroller'; -import styles from './DropdownSelect.less'; +import { Button, Dropdown, List, Spin, message, Icon, Input } from "antd"; +import React from "react"; +import InfiniteScroll from "react-infinite-scroller"; +import styles from "./DropdownSelect.less"; import _ from "lodash"; -import {DropdownItem} from './DropdownItem'; -import {HealthStatusCircle} from '@/components/infini/health_status_circle' +import { DropdownItem } from "./DropdownItem"; +import { HealthStatusCircle } from "@/components/infini/health_status_circle"; -class DropdownSelect extends React.Component{ - constructor(props){ - super(props) - this.state={ +class DropdownSelect extends React.Component { + constructor(props) { + super(props); + this.state = { value: props.defaultValue, loading: false, hasMore: props.data.length > props.size, overlayVisible: false, data: (props.data || []).slice(0, props.size), dataSource: [...props.data], + }; + } + + handleItemClick = (item) => { + let preValue = this.props.value || this.state.value; + this.setState( + { + value: item, + overlayVisible: false, + }, + () => { + let onChange = this.props.onChange; + if (preValue != item && onChange && typeof onChange == "function") { + onChange(item); + } + } + ); + }; + + componentDidMount() {} + componentDidUpdate(preProps, preState) { + if (preProps.data.length != preState.dataSource.length) { + const newData = [...preProps.data]; + this.setState({ + dataSource: newData, + data: newData, + hasMore: newData.length > this.props.size, + selectedIndex: -1, + }); } } - - handleItemClick = (item)=>{ - let preValue = this.props.value || this.state.value; - this.setState({ - value: item, - overlayVisible: false, - },()=>{ - let onChange = this.props.onChange; - if(preValue != item && onChange && typeof onChange == 'function'){ - onChange(item) - } - }) - } - - componentDidMount(){ - } - handleInfiniteOnLoad = (current) => { - let {size } = this.props; + let { size } = this.props; let targetLength = current * size; - let {hasMore, dataSource} = this.state; - if(dataSource.length < targetLength){ + let { hasMore, dataSource } = this.state; + if (dataSource.length < targetLength) { targetLength = dataSource.length; - hasMore = false + hasMore = false; } const newData = this.state.dataSource.slice(0, targetLength); this.setState({ data: newData, hasMore: hasMore, - }) - } + }); + }; - handleInputChange = (e) =>{ + handleInputChange = (e) => { const name = e.target.value; - const newData = this.props.data.filter(item=>{ + const newData = this.props.data.filter((item) => { return item.name.includes(name); }); this.setState({ @@ -61,76 +73,127 @@ class DropdownSelect extends React.Component{ dataSource: newData, data: newData, hasMore: newData.length > this.props.size, - }) - } + }); + }; - - render(){ + render() { let me = this; - const {labelField, clusterStatus} = this.props; + const { labelField, clusterStatus } = this.props; let value = this.props.value || this.state.value; let displayVaue = value[labelField]; - const menu = (
-
-
- -
- +
+
+ +
+ -
- {(!this.state.data || !this.state.data.length)&&
匹配不到集群(匹配规则为前缀匹配)
} - {(this.state.data || []).map((item)=>{ - // return
- // - //
- const cstatus = clusterStatus ? clusterStatus[item.id] : null; - return { - this.handleItemClick(item) - }} - /> - })} + > +
+ {(!this.state.data || !this.state.data.length) && ( +
+ 匹配不到集群(匹配规则为前缀匹配) +
+ )} + {(this.state.data || []).map((item) => { + // return
+ // + //
+ const cstatus = clusterStatus ? clusterStatus[item.id] : null; + return ( + { + this.handleItemClick(item); + }} + /> + ); + })} +
+
-
+ {!this.state.loading && this.state.hasMore && ( +
+ pull load more +
+ )}
- {!this.state.loading && this.state.hasMore && ( -
- pull load more -
- )} -
); + ); const cstatus = clusterStatus ? clusterStatus[value?.id] : null; - return( - this.props.visible ? - ({ - this.setState({ overlayVisible: flag }); - }}> - {/* */} - - - {cstatus?.available ? : } - - - - - - ) : "" - ) + + + {cstatus?.available ? ( + + ) : ( + + )} + + + + + + ) : ( + "" + ); } - } -export default DropdownSelect; \ No newline at end of file +export default DropdownSelect; diff --git a/web/src/components/GlobalHeader/RightContent.js b/web/src/components/GlobalHeader/RightContent.js index b80d1c35..82ac01d8 100644 --- a/web/src/components/GlobalHeader/RightContent.js +++ b/web/src/components/GlobalHeader/RightContent.js @@ -1,24 +1,24 @@ -import React, { PureComponent } from 'react'; -import { FormattedMessage, formatMessage } from 'umi/locale'; -import { Spin, Tag, Menu, Icon, Dropdown, Avatar, Tooltip } from 'antd'; -import moment from 'moment'; -import groupBy from 'lodash/groupBy'; -import NoticeIcon from '../NoticeIcon'; -import HeaderSearch from '../HeaderSearch'; -import SelectLang from '../SelectLang'; -import styles from './index.less'; -import {ConsoleUI} from '@/pages/DevTool/Console'; +import React, { PureComponent } from "react"; +import { FormattedMessage, formatMessage } from "umi/locale"; +import { Spin, Tag, Menu, Icon, Dropdown, Avatar, Tooltip } from "antd"; +import moment from "moment"; +import groupBy from "lodash/groupBy"; +import NoticeIcon from "../NoticeIcon"; +import HeaderSearch from "../HeaderSearch"; +import SelectLang from "../SelectLang"; +import styles from "./index.less"; +import { ConsoleUI } from "@/pages/DevTool/Console"; import { Resizable } from "re-resizable"; -import {ResizeBar} from '@/components/infini/resize_bar'; +import { ResizeBar } from "@/components/infini/resize_bar"; export default class GlobalHeaderRight extends PureComponent { - state={consoleVisible: false} + state = { consoleVisible: false }; getNoticeData() { const { notices = [] } = this.props; if (notices.length === 0) { return {}; } - const newNotices = notices.map(notice => { + const newNotices = notices.map((notice) => { const newNotice = { ...notice }; if (newNotice.datetime) { newNotice.datetime = moment(notice.datetime).fromNow(); @@ -28,10 +28,10 @@ export default class GlobalHeaderRight extends PureComponent { } if (newNotice.extra && newNotice.status) { const color = { - todo: '', - processing: 'blue', - urgent: 'red', - doing: 'gold', + todo: "", + processing: "blue", + urgent: "red", + doing: "gold", }[newNotice.status]; newNotice.extra = ( @@ -41,7 +41,7 @@ export default class GlobalHeaderRight extends PureComponent { } return newNotice; }); - return groupBy(newNotices, 'type'); + return groupBy(newNotices, "type"); } render() { @@ -57,15 +57,24 @@ export default class GlobalHeaderRight extends PureComponent { - + - + - + @@ -76,7 +85,7 @@ export default class GlobalHeaderRight extends PureComponent { ); const noticeData = this.getNoticeData(); let className = styles.right; - if (theme === 'dark') { + if (theme === "dark") { className = `${styles.right} ${styles.dark}`; } return ( @@ -97,13 +106,19 @@ export default class GlobalHeaderRight extends PureComponent { }} /> */} - { - const {history, selectedCluster} = this.props; - // history.push(`/dev_tool`); - this.setState({ - consoleVisible: !this.state.consoleVisible - }) - }}> + { + const { history, selectedCluster } = this.props; + // history.push(`/dev_tool`); + this.setState({ + consoleVisible: !this.state.consoleVisible, + }); + }} + > + {" "} + + {/* )} */} -
- {/* + {/* */} - {this.props.clusterList.length > 0 && { - this.setState({ - consoleVisible: false, - }) - }} - clusterStatus={this.props.clusterStatus} - resizeable={true} - />} -
+ {this.props.clusterList.length > 0 && + this.props.selectedCluster.id != "" && ( + { + this.setState({ + consoleVisible: false, + }); + }} + clusterStatus={this.props.clusterStatus} + resizeable={true} + /> + )} +
); } @@ -205,4 +226,4 @@ export default class GlobalHeaderRight extends PureComponent { const TopHandle = () => { return
hello world
; -}; \ No newline at end of file +}; diff --git a/web/src/components/kibana/console/components/CommonCommandModal.tsx b/web/src/components/kibana/console/components/CommonCommandModal.tsx index 0b3b54fe..f74ad35b 100644 --- a/web/src/components/kibana/console/components/CommonCommandModal.tsx +++ b/web/src/components/kibana/console/components/CommonCommandModal.tsx @@ -1,16 +1,16 @@ // @ts-ignore -import React, { useState, useCallback } from 'react'; -import { Modal, Form, Input, Tag } from 'antd'; -import { PlusOutlined } from '@ant-design/icons'; +import React, { useState, useCallback } from "react"; +import { Modal, Form, Input, Tag } from "antd"; +import { PlusOutlined } from "@ant-design/icons"; interface ITagGeneratorProps { - value?: Array, + value?: Array; onChange?: (val: Array) => void; } -const TagGenerator = ({ value = [], onChange }: ITagGeneratorProps) => { +export const TagGenerator = ({ value = [], onChange }: ITagGeneratorProps) => { const [inputVisible, setInputVisible] = useState(false); - const [inputValue, setInputValue] = useState(''); + const [inputValue, setInputValue] = useState(""); const handleInputChange = (e) => { setInputValue(e.target.value); @@ -20,31 +20,52 @@ const TagGenerator = ({ value = [], onChange }: ITagGeneratorProps) => { setInputVisible(true); }; - const handleInputConfirm = useCallback((e) => { - onChange([...(value || []), e.target.value]); - setInputVisible(false); - setInputValue(''); - }, [value]); + const handleInputConfirm = useCallback( + (e) => { + onChange([...(value || []), e.target.value]); + setInputVisible(false); + setInputValue(""); + }, + [value] + ); - const handleRemove = useCallback((index) => { - const newValue = [...value]; - newValue.splice(index, 1); - onChange(newValue); - }, [value]); + const handleRemove = useCallback( + (index) => { + const newValue = [...value]; + newValue.splice(index, 1); + onChange(newValue); + }, + [value] + ); return (
{value.map((tag, index) => ( - handleRemove(index)}>{tag} + handleRemove(index)} + > + {tag} + ))} - {inputVisible && } + {inputVisible && ( + + )} {!inputVisible && ( - + 新建标签 )}
- ) + ); }; interface ICommonCommandModalProps { @@ -60,21 +81,27 @@ const CommonCommandModal = Form.create()((props: ICommonCommandModalProps) => { try { const values = await form.validateFields(); props.onConfirm(values); - } catch (e) { - - } + } catch (e) {} }; return ( - +
- {form.getFieldDecorator('title', { - rules: [{ required: true, message: '请输入标题' }] + {form.getFieldDecorator("title", { + rules: [{ required: true, message: "请输入标题" }], })()} - {form.getFieldDecorator('tag')( )} + {form.getFieldDecorator("tag")()}
diff --git a/web/src/components/kibana/console/components/ConsoleInput.tsx b/web/src/components/kibana/console/components/ConsoleInput.tsx index 3e0837b4..0a472edb 100644 --- a/web/src/components/kibana/console/components/ConsoleInput.tsx +++ b/web/src/components/kibana/console/components/ConsoleInput.tsx @@ -1,32 +1,38 @@ // @ts-ignore -import React, { useRef, useEffect, CSSProperties, useMemo } from 'react'; -import ace from 'brace'; -import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiToolTip, PropertySortType } from '@elastic/eui'; -import { SenseEditor } from '../entities/sense_editor'; -import { LegacyCoreEditor } from '../modules/legacy_core_editor/legacy_core_editor'; -import ConsoleMenu from './ConsoleMenu'; +import React, { useRef, useEffect, CSSProperties, useMemo } from "react"; +import ace from "brace"; +import { + EuiFlexGroup, + EuiFlexItem, + EuiIcon, + EuiToolTip, + PropertySortType, +} from "@elastic/eui"; +import { SenseEditor } from "../entities/sense_editor"; +import { LegacyCoreEditor } from "../modules/legacy_core_editor/legacy_core_editor"; +import ConsoleMenu from "./ConsoleMenu"; // import { RequestContextProvider } from '../contexts/request_context'; -import { getDocumentation, autoIndent } from '../entities/console_menu_actions'; -import './ConsoleInput.scss'; -import { useSendCurrentRequestToES } from '../hooks/use_send_current_request_to_es'; -import { useSetInputEditor } from '../hooks/use_set_input_editor'; -import '@elastic/eui/dist/eui_theme_light.css'; -import { instance as registry } from '../contexts/editor_context/editor_registry'; -import 'antd/dist/antd.css'; -import {retrieveAutoCompleteInfo} from '../modules/mappings/mappings'; -import {useSaveCurrentTextObject} from '../hooks/use_save_current_text_object'; -import {useEditorReadContext} from '../contexts/editor_context/editor_context'; -import {useDataInit} from '../hooks/use_data_init'; -import { useServicesContext } from '../contexts'; -import {applyCurrentSettings} from './apply_editor_settings'; -import { subscribeResizeChecker } from './subscribe_console_resize_checker'; +import { getDocumentation, autoIndent } from "../entities/console_menu_actions"; +import "./ConsoleInput.scss"; +import { useSendCurrentRequestToES } from "../hooks/use_send_current_request_to_es"; +import { useSetInputEditor } from "../hooks/use_set_input_editor"; +import "@elastic/eui/dist/eui_theme_light.css"; +import { instance as registry } from "../contexts/editor_context/editor_registry"; +import "antd/dist/antd.css"; +import { retrieveAutoCompleteInfo } from "../modules/mappings/mappings"; +import { useSaveCurrentTextObject } from "../hooks/use_save_current_text_object"; +import { useEditorReadContext } from "../contexts/editor_context/editor_context"; +import { useDataInit } from "../hooks/use_data_init"; +import { useServicesContext } from "../contexts"; +import { applyCurrentSettings } from "./apply_editor_settings"; +import { subscribeResizeChecker } from "./subscribe_console_resize_checker"; const abs: CSSProperties = { - position: 'absolute', - top: '0', - left: '0', - bottom: '0', - right: '0', + position: "absolute", + top: "0", + left: "0", + bottom: "0", + right: "0", }; // interface IConsoleInputProps { @@ -41,19 +47,16 @@ const SendRequestButton = (props: any) => { const sendCurrentRequestToES = useSendCurrentRequestToES(); const saveCurrentTextObject = useSaveCurrentTextObject(); - const {saveCurrentTextObjectRef} = props; - useEffect(()=>{ - saveCurrentTextObjectRef.current = saveCurrentTextObject - }, [saveCurrentTextObjectRef]) - + const { saveCurrentTextObjectRef } = props; + useEffect(() => { + saveCurrentTextObjectRef.current = saveCurrentTextObject; + }, [saveCurrentTextObjectRef]); return ( - + - - - - + {/* + + */} - - - - { + onClose={() => { this.setState({ drawerVisible: false, - indexActiveKey: '1', + indexActiveKey: "1", }); }} width={720} > -
- this.handleEditorDidMount('indexSettingsEditor', editor)} - /> +
+
标题:
+
+ +
+
+
+
标签:
+
+ + {/* */} +
+
+
内容:
+
+ + {this.buildRawCommonCommandRequest(editingCommand)} + + {/* + this.handleEditorDidMount("commandEditor", editor) + } + /> */} +
+
+
diff --git a/web/src/pages/System/Command/models/command.js b/web/src/pages/System/Command/models/command.js index 0c37d4e9..594a3222 100644 --- a/web/src/pages/System/Command/models/command.js +++ b/web/src/pages/System/Command/models/command.js @@ -1,54 +1,63 @@ -import {searchCommand, deleteCommand} from "@/services/command"; -import {message} from "antd"; -import {formatESSearchResult} from '@/lib/elasticsearch/util'; +import { searchCommand, deleteCommand, saveCommand } 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 - }) - }, + 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, - } - } - } -} + *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; + }, + + *updateCommand({ payload }, { call, put, select }) { + let res = yield call(saveCommand, payload); + if (res.error) { + message.error(res.error); + return false; + } + // let {data, total} = yield select(state => state.command); + return res; + }, + }, + reducers: { + saveData(state, { payload }) { + return { + ...state, + ...payload, + }; + }, + }, +}; diff --git a/web/src/services/command.js b/web/src/services/command.js index 54420d2b..5d3f16a5 100644 --- a/web/src/services/command.js +++ b/web/src/services/command.js @@ -1,24 +1,32 @@ -import request from '@/utils/request'; -import {buildQueryArgs, pathPrefix} from './common'; +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' - }); + let url = `${pathPrefix}/elasticsearch/command`; + let args = buildQueryArgs({ + keyword: params.keyword, + 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 + const url = `${pathPrefix}/elasticsearch/command/${params.id}`; + return request(url, { + method: "DELETE", + }); +} + +export async function saveCommand(params) { + const url = `${pathPrefix}/elasticsearch/command/${params.id}`; + return request(url, { + method: "PUT", + body: params, + }); +}