adjust menu

This commit is contained in:
silenceqi 2021-02-04 23:04:57 +08:00
parent 853bc5cdde
commit 82a1c63233
40 changed files with 496 additions and 121 deletions

View File

@ -8,6 +8,7 @@ import (
"infini.sh/framework/core/ui"
"infini.sh/search-center/api/index_management"
"infini.sh/search-center/config"
"infini.sh/search-center/api/system"
)
func Init(cfg *config.AppConfig) {
@ -47,4 +48,13 @@ func Init(cfg *config.AppConfig) {
}
},
})
shdl := system.APIHandler{
Config: cfg,
}
ui.HandleUIMethod(api.POST, pathPrefix + "system/cluster", shdl.HandleCreateClusterAction)
ui.HandleUIMethod(api.PUT, pathPrefix + "system/cluster/:id", shdl.HandleUpdateClusterAction)
ui.HandleUIMethod(api.DELETE, pathPrefix + "system/cluster/:id", shdl.HandleDeleteClusterAction)
ui.HandleUIMethod(api.GET, pathPrefix + "system/cluster", shdl.HandleSearchClusterAction)
}

View File

@ -0,0 +1,134 @@
package system
import (
"fmt"
"infini.sh/framework/core/api"
httprouter "infini.sh/framework/core/api/router"
"infini.sh/framework/core/elastic"
"infini.sh/framework/core/util"
"infini.sh/search-center/config"
"infini.sh/search-center/model"
"infini.sh/framework/core/orm"
"net/http"
)
type APIHandler struct {
Config *config.AppConfig
api.Handler
}
func (h *APIHandler) HandleCreateClusterAction(w http.ResponseWriter, req *http.Request, ps httprouter.Params){
var conf = &model.ClusterConfig{}
resBody := map[string] interface{}{
"status": true,
}
err := h.DecodeJSON(req, conf)
if err != nil {
resBody["status"] = false
resBody["error"] = err
h.WriteJSON(w, resBody, http.StatusOK)
return
}
// TODO validate data format
esClient := elastic.GetClient(h.Config.Elasticsearch)
id := util.GetUUID()
ir, err := esClient.Index(orm.GetIndexName(model.ClusterConfig{}), "", id, conf)
if err != nil {
resBody["status"] = false
resBody["error"] = err
h.WriteJSON(w, resBody, http.StatusOK)
return
}
resBody["payload"] = ir
h.WriteJSON(w, resBody, http.StatusOK)
}
func (h *APIHandler) HandleUpdateClusterAction(w http.ResponseWriter, req *http.Request, ps httprouter.Params){
var conf = map[string]interface{}{}
resBody := map[string] interface{}{
"status": true,
}
err := h.DecodeJSON(req, conf)
if err != nil {
resBody["status"] = false
resBody["error"] = err
h.WriteJSON(w, resBody, http.StatusOK)
return
}
id := ps.ByName("id")
esClient := elastic.GetClient(h.Config.Elasticsearch)
indexName := orm.GetIndexName(model.ClusterConfig{})
originConf, err := esClient.Get(indexName, "", id)
if err != nil {
resBody["status"] = false
resBody["error"] = err
h.WriteJSON(w, resBody, http.StatusOK)
return
}
source := originConf.Source
for k, v := range conf {
if k == "id" {
continue
}
source[k] = v
}
ir, err := esClient.Index(indexName, "", id, source)
if err != nil {
resBody["status"] = false
resBody["error"] = err
h.WriteJSON(w, resBody, http.StatusOK)
return
}
resBody["payload"] = ir
h.WriteJSON(w, resBody, http.StatusOK)
}
func (h *APIHandler) HandleDeleteClusterAction(w http.ResponseWriter, req *http.Request, ps httprouter.Params){
resBody := map[string] interface{}{
"status": true,
}
id := ps.ByName("id")
esClient := elastic.GetClient(h.Config.Elasticsearch)
_, err := esClient.Delete(orm.GetIndexName(model.ClusterConfig{}), "", id)
if err != nil {
resBody["status"] = false
resBody["error"] = err
h.WriteJSON(w, resBody, http.StatusOK)
return
}
resBody["payload"] = true
h.WriteJSON(w, resBody, http.StatusOK)
}
func (h *APIHandler) HandleSearchClusterAction(w http.ResponseWriter, req *http.Request, ps httprouter.Params){
resBody := map[string] interface{}{
"status": true,
}
var (
name = h.GetParameterOrDefault(req, "name", "")
enable = h.GetParameterOrDefault(req, "enable", "")
queryDSL = `{"query":{"bool":{"must":[%s, %s]}}}`
)
if name != ""{
name = fmt.Sprintf(`{"match":{"name": "%s""}}`, name)
}
if enable != "" {
if enable != "true" {
enable = "false"
}
enable = fmt.Sprintf(`{"match":{"enable": "%s""}}`, enable)
}
queryDSL = fmt.Sprintf(queryDSL, name, enable)
esClient := elastic.GetClient(h.Config.Elasticsearch)
res, err := esClient.SearchWithRawQueryDSL(orm.GetIndexName(model.ClusterConfig{}), []byte(queryDSL))
if err != nil {
resBody["status"] = false
resBody["error"] = err
h.WriteJSON(w, resBody, http.StatusOK)
return
}
resBody["payload"] = res
h.WriteJSON(w, resBody, http.StatusOK)
}

View File

@ -71,6 +71,7 @@ func main() {
}, func() {
orm.RegisterSchemaWithIndexName(model.Dict{}, "infini-dict")
orm.RegisterSchemaWithIndexName(model.Reindex{}, "infini-reindex")
orm.RegisterSchemaWithIndexName(model.Reindex{}, "infini-cluster")
})
}

11
model/cluster_config.go Normal file
View File

@ -0,0 +1,11 @@
package model
type ClusterConfig struct {
ID string `json:"id" elastic_meta:"_id"`
Name string `json:"name" elastic_mapping:"name:{type:text}"`
Endpoint string `json:"endpoint" elastic_mapping:"name:{type:text}"`
User string `json:"user" elastic_mapping:"name:{type:keyword}"`
Password string `json:"password"elastic_mapping:"name:{type:keyword}" `
Description string `json:"desc" elastic_mapping:"name:{type:text}"`
Enable bool `json:"enable" elastic_mapping:"name:{type:boolean}"`
}

View File

@ -1,11 +1,11 @@
elasticsearch:
- name: default
enabled: true
endpoint: http://localhost:9200
endpoint: http://localhost:8001
index_prefix:
basic_auth:
username: elastic
password: ZBdkVQUUdF1Sir4X4BGB
password: liugq123
web:
enabled: true

View File

@ -17,35 +17,45 @@ export default [
Routes: ['src/pages/Authorized'],
authority: ['admin', 'user'],
routes: [
// dashboard
{ path: '/', redirect: '/platform/clusterlist' },
// cluster
{ path: '/', redirect: '/cluster/overview' },
{
path: '/platform',
name: 'platform',
icon: 'dashboard',
path: '/cluster',
name: 'cluster',
icon: 'cluster',
routes: [
// { path: '/', redirect: '/platform/gateway' },
{
path: '/platform/gateway',
name: 'gateway',
component: './Dashboard/GatewayMonitor',
path: '/cluster/overview',
name: 'overview',
component: './Cluster/ClusterList',
}, {
path: '/platform/cluster/:name',
path: '/cluster/monitoring/:name',
name: 'cluster',
component: './Dashboard/ClusterMonitor',
component: './Cluster/ClusterMonitor',
hideInMenu: true,
}, {
path: '/platform/clusterlist',
name: 'cluster',
component: './Dashboard/ClusterList',
path: '/cluster/monitoring',
name: 'monitoring',
component: './Cluster/ClusterList',
}, {
path: '/platform/tasks',
name: 'tasks',
component: './Dashboard/TaskMonitor',
path: '/cluster/settings',
name: 'settings',
component: './Cluster/Settings/Base',
routes: [
{
path: '/cluster/settings',
redirect: '/cluster/settings/repository',
},
{
path: '/cluster/settings/repository',
component: './Cluster/Settings/Repository',
}
]
}, {
path: '/platform/search',
name: 'search',
component: './Dashboard/SearchMonitor',
path: '/cluster/logging',
name: 'logging',
component: './Cluster/SearchMonitor',
},
]
@ -57,84 +67,52 @@ export default [
name: 'data',
icon: 'database',
routes: [
// {
// path: '/data/pipes',
// name: 'pipes',
// component: './DataManagement/Pipes',
// routes: [
// {
// path: '/data/pipes',
// redirect: '/data/pipes/logstash',
// },
// {
// path: '/data/pipes/logstash',
// component: './DataManagement/LogstashConfig',
// },
// {
// path: '/data/pipes/ingestpipeline',
// component: './DataManagement/IngestPipeline',
// },
// ]
// },
{
path: '/data/pipes',
name: 'pipes',
component: './DataManagement/Pipes',
routes: [
{
path: '/data/pipes',
redirect: '/data/pipes/logstash',
},
{
path: '/data/pipes/logstash',
component: './DataManagement/LogstashConfig',
},
{
path: '/data/pipes/ingestpipeline',
component: './DataManagement/IngestPipeline',
},
]
},{
path: '/data/indices',
path: '/data/overview',
name: 'overview',
component: './DataManagement/Indices',
}, {
path: '/data/index',
name: 'index',
component: './DataManagement/Indices',
routes: [
{
path: '/data/indices',
redirect: '/data/indices/summary',
},
{
path: '/data/indices/summary',
component: './DataManagement/IndexSummary',
},
{
path: '/data/indices/doc',
component: './DataManagement/Index',
},
{
path: '/data/indices/template',
component: './DataManagement/IndexTemplate',
},
{
path: '/data/indices/ilm',
component: './DataManagement/IndexLifeCycle',
},
]
}, {
path: '/data/backup',
name: 'snapshot',
component: './DataManagement/Backup',
routes: [
{
path: '/data/backup',
redirect: '/data/backup/bakandrestore',
},
{
path: '/data/backup/bakandrestore',
component: './DataManagement/backup/BakAndRestore',
},{
path: '/data/backup/bakcycle',
component: './DataManagement/backup/BakCycle',
}
]
}, {
path: '/data/rebuild',
name: 'rebuildlist',
component: './DataManagement/RebuildList',
},{
path: '/data/rebuild/new',
name: 'rebuild',
component: './DataManagement/Rebuild',
hideInMenu: true,
}, {
path: '/data/import',
name: 'export',
component: './DataManagement/Import',
},{
path: '/data/doc',
name: 'query',
path: '/data/document',
name: 'document',
component: './DataManagement/Document',
}, {
path: '/data/template',
name: 'template',
component: './DataManagement/Indices',
},
// {
// path: '/data/rebuild/new',
// name: 'rebuild',
// component: './DataManagement/Rebuild',
// hideInMenu: true,
// },
{
path: '/data/lifecycle',
name: 'lifecycle',
component: './DataManagement/Indices',
},
]
},
@ -146,6 +124,11 @@ export default [
name: 'search',
icon: 'search',
routes: [
{
path: '/search/overview',
name: 'overview',
component: './SearchManage/template/Template',
},
{
path: '/search/template',
name: 'template',
@ -248,12 +231,79 @@ export default [
]
},
//sync
{
path: '/sync',
name: 'synchronize',
icon: 'sync',
routes: [
{
path: '/sync/overview',
name: 'overview',
component: './Synchronize/Pipes',
},
{
path: '/sync/pipeline',
name: 'pipeline',
component: './Synchronize/Pipes',
routes: [
{
path: '/sync/pipeline',
redirect: '/sync/pipeline',
},
{
path: '/sync/pipeline/ingestpipeline',
component: './Synchronize/IngestPipeline',
}, {
path: '/sync/pipeline/logstash',
component: './Synchronize/LogstashConfig',
}]
},{
path: '/sync/rebuild',
name: 'rebuild',
component: './Synchronize/RebuildList',
},{
path: '/sync/inout',
name: 'inout',
component: './Synchronize/Import',
}
]
},
//backup
{
path: '/backup',
name: 'backup',
icon: 'cloud',
routes: [
{
path: '/backup/overview',
name: 'overview',
component: './SearchManage/template/Template',
},
{
path: '/backup/index',
name: 'index',
component: './SearchManage/template/Template',
},{
path: '/backup/lifecycle',
name: 'lifecycle',
component: './SearchManage/template/Template',
}
]
},
//settings
{
path: '/system',
name: 'system',
icon: 'setting',
routes: [
{
path: '/system/cluster',
name: 'cluster',
component: './System/Settings/Base',
},
{
path: '/system/settings',
name: 'settings',

View File

@ -85,30 +85,41 @@ export default {
'component.noticeIcon.empty': 'No notifications',
'menu.home': 'Home',
'menu.platform': 'DASHBOARD',
'menu.platform.gateway': 'GATEWAY',
'menu.platform.cluster': 'CLUSTER',
'menu.platform.tasks': 'TASKS',
'menu.platform.search': 'SEARCH',
'menu.cluster': 'CLUSTER',
'menu.cluster.overview': 'OVERVIEW',
'menu.cluster.monitoring': 'MONITORING',
'menu.cluster.settings': 'SETTINGS',
'menu.cluster.logging': 'LOGGING',
'menu.data': 'DATA MANAGEMENT',
'menu.data.pipes': 'PIPELINE',
'menu.data.overview': 'OVERVIEW',
'menu.data.index': 'INDEX',
'menu.data.snapshot': 'SNAPSHOT',
'menu.data.rebuildlist': 'REBUILD',
'menu.data.rebuild': 'NEW REBUILD',
'menu.data.export': 'IMPORT&EXPORT',
'menu.data.query': 'DOCUMENT',
'menu.data.document': 'DOCUMENT',
'menu.data.template': 'TEMPLATE',
'menu.data.lifecycle': 'LIFECYCLE',
'menu.search': 'SEARCH',
'menu.search.overview': 'OVERVIEW',
'menu.search.template': 'TEMPLATE',
'menu.search.alias': 'ALIAS',
'menu.search.dict': 'DICTIONARY',
'menu.search.analyzer': 'ANALYZER',
'menu.search.nlp': 'NLP',
'menu.synchronize': 'SYNCHRONIZE',
'menu.synchronize.overview': 'OVERVIEW',
'menu.synchronize.pipeline': 'PIPELINE',
'menu.synchronize.rebuild': 'REBUILD',
'menu.synchronize.inout': 'INOUT',
'menu.backup': 'BACKUP',
'menu.backup.overview': 'OVERVIEW',
'menu.backup.index': 'BACKUP AND RESTORE',
'menu.backup.lifecycle': 'BACKUP LIFECYCLE',
'menu.system': 'SYSTEM',
'menu.system.cluster': 'CLUSTER',
'menu.system.settings': 'SETTINGS',
'menu.system.settings.global': 'GLOBAL',
'menu.system.settings.gateway': 'GATEWAY',

View File

@ -92,31 +92,41 @@ export default {
'menu.home': '首页',
'menu.platform': '平台概览',
'menu.platform.gateway': '网关监控',
'menu.platform.cluster': '集群监控',
'menu.platform.tasks': '任务监控',
'menu.platform.search': '搜索监控',
'menu.platform.clusterlist': '集群列表',
'menu.cluster': '集群管理',
'menu.cluster.overview': '集群概览',
'menu.cluster.monitoring': '集群监控',
'menu.cluster.settings': '集群设置',
'menu.cluster.logging': '集群日志',
'menu.data': '数据管理',
'menu.data.pipes': '数据加工',
'menu.data.overview': '概览',
'menu.data.index': '索引管理',
'menu.data.snapshot': '快照管理',
'menu.data.rebuildlist': '重建管理',
'menu.data.rebuild': '新建重建',
'menu.data.export': '导入导出',
'menu.data.query': '文档管理',
'menu.data.document': '文档管理',
'menu.data.template': '索引模版管理',
'menu.data.lifecycle': '索引生命周期管理',
'menu.search': '搜索管理',
'menu.search.overview': '概览',
'menu.search.template': '搜索模板',
'menu.search.alias': '别名管理',
'menu.search.dict': '词库管理',
'menu.search.analyzer': '分词管理',
'menu.search.nlp': '自然语言处理',
'menu.synchronize': '同步管理',
'menu.synchronize.overview': '概览',
'menu.synchronize.pipeline': '数据加工',
'menu.synchronize.rebuild': '数据重建',
'menu.synchronize.inout': '导入导出',
'menu.backup': '备份管理',
'menu.backup.overview': '概览',
'menu.backup.index': '索引备份与还原',
'menu.backup.lifecycle': '备份周期管理',
'menu.system': '系统管理',
'menu.system.cluster': '集群管理',
'menu.system.settings': '系统设置',
'menu.system.settings.global': '全局设置',
'menu.system.settings.gateway': '网关设置',

View File

@ -33,7 +33,7 @@ class ClusterList extends React.Component{
renderItem={item => (
<List.Item key={item.name}>
<Card title={item.name + ": "+ item.nodes.length}
extra={<Link to={"/platform/cluster/" + item.name}>查看更多</Link>}
extra={<Link to={"/cluster/monitoring/" + item.name}>查看更多</Link>}
>
<div>
{/* {item.nodes.map(node => {

View File

@ -481,7 +481,7 @@ class ClusterMonitor extends PureComponent {
}
fetchData = () => {
fetchDataCount++;
console.log(fetchDataCount, moment().diff(startTime)/1000);
//console.log(fetchDataCount, moment().diff(startTime)/1000);
const { dispatch } = this.props;
let {timeRange, lastSeconds } = this.state;
if(lastSeconds && lastSeconds > 0){

View File

@ -0,0 +1,40 @@
import React, { Component } from 'react';
import router from 'umi/router';
import { connect } from 'dva';
import PageHeaderWrapper from '@/components/PageHeaderWrapper';
@connect()
class Base extends Component {
handleTabChange = key => {
const { match } = this.props;
switch (key) {
case 'repository':
router.push(`${match.url}/repository`);
break;
default:
break;
}
}
render() {
const tabList = [
{
key: 'repository',
tab: 'repository',
}
];
const { match, children, location } = this.props;
return (
<PageHeaderWrapper
tabList={tabList}
tabActiveKey={location.pathname.replace(`${match.path}/`, '')}
onTabChange={this.handleTabChange}
>
{children}
</PageHeaderWrapper>
);
}
}
export default Base;

View File

@ -0,0 +1,109 @@
import React, { Component,Fragment } from 'react';
import { connect } from 'dva';
import { Card,Form,Input, Select,Button,message,Divider,Drawer,Table } from 'antd';
const { Option } = Select;
import { formatMessage, FormattedMessage } from 'umi/locale';
@connect(({logstash,loading }) => ({
}))
@Form.create()
class Repository extends Component {
state = {
drawerVisible: false,
};
componentDidMount() {
}
handleRepoClick = ()=>{
this.setState({
drawerVisible: true,
});
}
repoColumns = [
{
title: '仓库名',
dataIndex: 'id',
render: (text, record) => (<Fragment>
<a onClick={() => this.handleRepoClick(record)}>{record.id}</a>
</Fragment>
)
},
{
title: '创建时间',
dataIndex: 'dateCreated'
},
{
title: '操作',
render: (text, record) => (
<Fragment>
{/* <a onClick={() => this.handleDownload(record)}></a>
<Divider type="vertical" /> */}
<a onClick={() => {
this.state.selectedRows.push(record);
this.handleDeleteClick();
}}>删除</a>
</Fragment>
),
},
];
repoData = [{
id: "my_local_repo",
dateCreated: "2020-10-09 20:30:23",
}];
repoTable = () =>{
return (
<div>
<div style={{marginBottom: 10}}>
<Button icon="plus" type="primary" onClick={() => {}}>
新建
</Button>
</div>
<Table
bordered
dataSource={this.repoData}
columns={this.repoColumns}
rowKey="id"
/>
</div>
);
}
onCloseRep = () => {
this.setState({
drawerVisible: false,
});
};
render() {
return (
<Fragment>
<Card
bordered={false}
onTabChange={this.onOperationTabChange}
>
<div>
{this.repoTable()}
<Drawer
title="仓库"
placement="right"
width={720}
visible={this.state.drawerVisible}
onClose={this.onCloseRep}
>
<p>Some contents...</p>
<p>Some contents...</p>
<p>Some contents...</p>
</Drawer>
</div>
</Card>
</Fragment>
);
}
}
export default Repository;

View File

@ -507,7 +507,7 @@ class EditableCell extends React.Component {
dataIndex: key,
ellipsis: true,
sorter: sortObj[key],
render: (text)=>(<Tooltip placement="top" title={text}>{text}</Tooltip>),
//render: (text)=>(<Tooltip placement="top" title={text}>{text}</Tooltip>),
onCell: record => ({
record,
dataIndex: key,
@ -867,7 +867,6 @@ class Doucment extends React.Component {
height="200px"
language="json"
theme="light"
// value={`{"match":{"name": "cincky"}}`}
options={{
minimap: {
enabled: false,