diff --git a/web/src/assets/elasticsearch.svg b/web/src/assets/elasticsearch.svg
new file mode 100644
index 00000000..b95507cd
--- /dev/null
+++ b/web/src/assets/elasticsearch.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/web/src/components/GlobalHeader/DropdownSelect.js b/web/src/components/GlobalHeader/DropdownSelect.js
index 7c98db2b..e27e904f 100644
--- a/web/src/components/GlobalHeader/DropdownSelect.js
+++ b/web/src/components/GlobalHeader/DropdownSelect.js
@@ -7,11 +7,16 @@ import {DropdownItem} from './DropdownItem';
import {HealthStatusCircle} from '@/components/infini/health_status_circle'
class DropdownSelect extends React.Component{
- state={
- value: this.props.defaultValue,
- loading: false,
- hasMore: true,
- overlayVisible: false,
+ 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)=>{
@@ -28,47 +33,35 @@ class DropdownSelect extends React.Component{
}
componentDidMount(){
- let me = this;
- this.fetchData().then((data)=>{
- let hasMore = true;
- if(data.length < this.props.size){
- hasMore = false;
- }
- me.setState({
- hasMore
- })
- })
- }
- fetchData = (name)=>{
- let me = this;
- const {fetchData, size} = this.props;
- let data = this.props.data || [];
- return fetchData(name || '', size);
}
- handleInfiniteOnLoad = (name) => {
- let { data } = this.props;
+ handleInfiniteOnLoad = (current) => {
+ let {size } = this.props;
+ let targetLength = current * size;
+ let {hasMore, dataSource} = this.state;
+ if(dataSource.length < targetLength){
+ targetLength = dataSource.length;
+ hasMore = false
+ }
+ const newData = this.state.dataSource.slice(0, targetLength);
+
this.setState({
- loading: true,
+ data: newData,
+ hasMore: hasMore,
})
- this.fetchData(name).then((newdata)=>{
- let newState = {
- loading: false,
- };
- if(newdata.length < this.props.size){
- //message.info("no more data");
- newState.hasMore = false;
- }
- this.setState(newState);
- });
}
handleInputChange = (e) =>{
const name = e.target.value;
+ const newData = this.props.data.filter(item=>{
+ return item.name.includes(name);
+ });
this.setState({
displayValue: name,
+ dataSource: newData,
+ data: newData,
+ hasMore: newData.length > this.props.size,
})
- this.handleInfiniteOnLoad(name);
}
@@ -79,7 +72,7 @@ class DropdownSelect extends React.Component{
let displayVaue = value[labelField];
const menu = (
-
+
- {(!this.props.data || !this.props.data.length)&&
匹配不到集群(匹配规则为前缀匹配)
}
- {(this.props.data || []).map((item)=>{
+ {(!this.state.data || !this.state.data.length)&&
匹配不到集群(匹配规则为前缀匹配)
}
+ {(this.state.data || []).map((item)=>{
// return
//
-
+
+
+
+
+
+
+
+
+
+
+
+ {lastDatum?.request.header}
+
+
+
+
+ {lastDatum?.response.header}
+
+
+
+
+
{selectedCluster.version}
);
-const [headerInfoVisible, setHeaderInfoVisible] = React.useState(false)
if (requestInProgress) {
content = (
@@ -140,12 +139,6 @@ const [headerInfoVisible, setHeaderInfoVisible] = React.useState(false)
-
- {/* */}
-
>
);
@@ -154,32 +147,7 @@ const [headerInfoVisible, setHeaderInfoVisible] = React.useState(false)
return (
{left?
{clusterContent}
:
- [
{content}
,
-
{setHeaderInfoVisible(false)}}
- >
-
-
-
-
- {requestResult?.requestHeader}
-
-
-
-
-
-
- {requestResult?.responseHeader}
-
-
-
- ]
+ [
{content}
,]
}
diff --git a/web/src/pages/DevTool/Console.tsx b/web/src/pages/DevTool/Console.tsx
index 777c8f21..823573b4 100644
--- a/web/src/pages/DevTool/Console.tsx
+++ b/web/src/pages/DevTool/Console.tsx
@@ -1,7 +1,8 @@
import Console from '../../components/kibana/console/components/Console';
import {connect} from 'dva';
-import {Button, Icon, Menu, Dropdown, Tabs} from 'antd';
-// import Tabs from '@/components/infini/tabs';
+import {Button, Icon, Menu, Dropdown, } from 'antd';
+import Tabs from '@/components/infini/tabs';
+import {DraggableTabs} from '@/components/infini/tabs/DraggableTabs';
import {useState, useReducer, useCallback, useEffect, useMemo, useRef, useLayoutEffect} from 'react';
import {useLocalStorage} from '@/lib/hooks/storage';
import {setClusterID} from '../../components/kibana/console/modules/mappings/mappings';
@@ -9,6 +10,7 @@ import {TabTitle} from './console_tab_title';
import '@/assets/utility.scss';
import { Resizable } from "re-resizable";
import {ResizeBar} from '@/components/infini/resize_bar';
+import NewTabMenu from './NewTabMenu';
const { TabPane } = Tabs;
@@ -94,6 +96,11 @@ const consoleTabReducer = (state: any, action: any) => {
panes,
});
break;
+ case 'saveOrder':
+ newState = ({
+ ...state,
+ order: action.payload.order,
+ });
default:
}
// setLocalState(newState);
@@ -123,8 +130,8 @@ export const ConsoleUI = ({selectedCluster,
return cm;
}
(clusterList || []).map((cluster: any)=>{
- cluster.status = clusterStatus[cluster.id].health?.status;
- if(!clusterStatus[cluster.id].available){
+ cluster.status = clusterStatus[cluster.id]?.health?.status;
+ if(!clusterStatus[cluster.id]?.available){
cluster.status = 'unavailable';
}
cm[cluster.id] = cluster;
@@ -184,7 +191,7 @@ export const ConsoleUI = ({selectedCluster,
};
const newTabClick = useCallback((param: any)=>{
- const cluster = clusterList.find(item=>item.id == param.key);
+ const cluster = clusterList.find(item=>item.id == param.id);
if(!cluster){
console.log('cluster not found')
return;
@@ -198,11 +205,16 @@ export const ConsoleUI = ({selectedCluster,
},[clusterList])
const menu = (
-
+ //
+
);
const rootRef = useRef(null);
@@ -220,26 +232,35 @@ export const ConsoleUI = ({selectedCluster,
setIsFullscreen(!isFullscreen)
}
- const tabBarExtra =(
+ const tabBarExtra ={
+ left:
+ {minimize? :null}
+
,
+ right:(
-
-
-
{isFullscreen?
:
-
- );
+ ),
+ append:(
+
+
+
+
+
+
+
+ )
+};
setClusterID(tabState.activeKey?.split(':')[0]);
const panes = tabState.panes.filter((pane: any)=>{
@@ -268,6 +289,14 @@ export const ConsoleUI = ({selectedCluster,
const enableWindowScroll = ()=>{
document.body.style.overflow = '';
}
+ const onTabNodeMoved=(newOrder:string[])=>{
+ dispatch({
+ type:'saveOrder',
+ payload: {
+ order: newOrder,
+ }
+ })
+ }
return (
@@ -275,7 +304,7 @@ export const ConsoleUI = ({selectedCluster,
defaultSize={{
height: editorHeight||'50vh'
}}
- minHeight={200}
+ minHeight={70}
maxHeight="100vh"
handleComponent={{ top:
}}
onResize={onResize}
@@ -294,13 +323,15 @@ export const ConsoleUI = ({selectedCluster,
onMouseOut={enableWindowScroll}
id="console"
ref={rootRef} >
-
{panes.map(pane => (
{saveTitle(pane.key, title)}}/>} key={pane.key} closable={pane.closable}>
@@ -308,7 +339,7 @@ export const ConsoleUI = ({selectedCluster,
{/* {pane.content} */}
))}
-
+
);
diff --git a/web/src/pages/DevTool/NewTabMenu.jsx b/web/src/pages/DevTool/NewTabMenu.jsx
new file mode 100644
index 00000000..43511351
--- /dev/null
+++ b/web/src/pages/DevTool/NewTabMenu.jsx
@@ -0,0 +1,100 @@
+import { Button, Dropdown, List, Spin, message, Icon, Input } from 'antd';
+import * as React from 'react';
+import InfiniteScroll from 'react-infinite-scroller';
+import styles from '@/components/GlobalHeader/DropdownSelect.less';
+import _ from "lodash";
+import {DropdownItem} from '@/components/GlobalHeader/DropdownItem';
+import {HealthStatusCircle} from '@/components/infini/health_status_circle'
+
+class NewTabMenu extends React.Component{
+ handleItemClick = (item)=>{
+ const onItemClick = this.props.onItemClick;
+ if(onItemClick && typeof onItemClick == 'function'){
+ onItemClick(item)
+ }
+ }
+ constructor(props){
+ super(props);
+ this.state={
+ loading: false,
+ hasMore: (props.data || []).length > props.size,
+ data: (props.data || []).slice(0, props.size || 10),
+ initialLoad: true,
+ dataSource: [...props.data],
+ dataSourceKey: 1,
+ }
+ }
+
+ componentDidMount(){
+ }
+ handleInfiniteOnLoad = (current) => {
+ let {size } = this.props;
+ let targetLength = current * size;
+ let {hasMore, dataSource} = this.state;
+ if(dataSource.length < targetLength){
+ targetLength = dataSource.length;
+ hasMore = false
+ }
+ const newData = this.state.dataSource.slice(0, targetLength);
+
+ this.setState({
+ data: newData,
+ hasMore: hasMore,
+ })
+
+ }
+
+ handleInputChange = (e) =>{
+ const name = e.target.value;
+ const newData = this.props.data.filter(item=>{
+ return item.name.includes(name);
+ });
+ this.setState({
+ displayValue: name,
+ dataSource: newData,
+ data: newData,
+ hasMore: newData.length > this.props.size,
+ })
+
+ }
+
+
+ render(){
+ const {clusterStatus} = this.props;
+ return (