optimize node top metric and change cluster config editing logic

This commit is contained in:
liugq 2021-12-10 12:23:08 +08:00
parent 740cda1ff7
commit 475dd606e8
15 changed files with 166 additions and 39 deletions

View File

@ -448,7 +448,7 @@ export default [
hideInMenu: true,
},
{
path: "/system/cluster/edit",
path: "/system/cluster/:id/edit",
name: "editCluster",
component: "./System/Cluster/Form",
hideInMenu: true,

View File

@ -16,6 +16,7 @@ class DropdownSelect extends React.Component {
overlayVisible: false,
data: (props.data || []).slice(0, props.size),
dataSource: [...props.data],
selectedIndex: -1,
};
}
@ -75,9 +76,38 @@ class DropdownSelect extends React.Component {
hasMore: newData.length > this.props.size,
});
};
selectOffset = (offset) => {
let { selectedIndex, data } = this.state;
const len = data.length;
selectedIndex = (selectedIndex + offset + len) % len;
this.setState({
selectedIndex,
});
};
onKeyDown = (e) => {
const { which } = e;
switch (which) {
case 38:
this.selectOffset(-1);
e.preventDefault();
e.stopPropagation();
break;
case 40:
this.selectOffset(1);
e.stopPropagation();
break;
case 13:
const { data, selectedIndex } = this.state;
if (selectedIndex > -1) {
this.handleItemClick(data[selectedIndex]);
this.setState({ overlayVisible: false });
}
break;
}
};
render() {
let me = this;
const { labelField, clusterStatus } = this.props;
let value = this.props.value || this.state.value;
let displayVaue = value[labelField];
@ -86,6 +116,10 @@ class DropdownSelect extends React.Component {
<div
className={styles.infiniteContainer}
style={{ height: this.props.height }}
onMouseEnter={() => {
this.searchInputRef.focus();
}}
onKeyDown={this.onKeyDown}
>
<div
className={styles.filter}
@ -97,6 +131,9 @@ class DropdownSelect extends React.Component {
onChange={this.handleInputChange}
placeholder="输入集群名称查找"
value={this.state.displayValue || ""}
ref={(ref) => {
this.searchInputRef = ref;
}}
/>
</div>
<InfiniteScroll
@ -118,7 +155,7 @@ class DropdownSelect extends React.Component {
匹配不到集群(匹配规则为前缀匹配)
</div>
)}
{(this.state.data || []).map((item) => {
{(this.state.data || []).map((item, idx) => {
// return <div className={styles.item}>
// <Button key={item[labelField]}
// onClick={() => {
@ -132,6 +169,7 @@ class DropdownSelect extends React.Component {
key={item.id}
isSelected={item.id === value.id}
clusterItem={item}
isSelected={this.state.selectedIndex == idx}
clusterStatus={cstatus}
onClick={() => {
this.handleItemClick(item);

View File

@ -37,6 +37,7 @@ interface props {
initialText: string;
paneKey: string;
height: number;
isActive: boolean;
}
const INITIAL_PANEL_WIDTH = 50;
@ -47,6 +48,7 @@ const ConsoleWrapper = ({
saveEditorContent,
initialText,
paneKey,
isActive,
height,
}: props) => {
const {
@ -84,6 +86,7 @@ const ConsoleWrapper = ({
saveEditorContent={saveEditorContent}
initialText={initialText}
paneKey={paneKey}
isActive={isActive}
/>
<div
style={{

View File

@ -71,6 +71,7 @@ interface ConsoleInputProps {
initialText: string | undefined;
saveEditorContent: (content: string) => void;
paneKey: string;
isActive: boolean;
height?: string;
}
@ -87,6 +88,7 @@ const ConsoleInputUI = ({
saveEditorContent,
paneKey,
height = "100%",
isActive,
}: ConsoleInputProps) => {
const editorRef = useRef<HTMLDivElement | null>(null);
const editorActionsRef = useRef<HTMLDivElement | null>(null);
@ -103,6 +105,11 @@ const ConsoleInputUI = ({
const {
services: { settings },
} = useServicesContext();
// if (isActive) {
// if (aceEditorRef.current) {
// aceEditorRef.current.focus();
// }
// }
useEffect(() => {
const aceEditor = ace.edit(editorRef.current!);

View File

@ -90,7 +90,7 @@ export default {
"form.button.pre": "上一步",
"form.button.goback": "返回",
"form.button.reset": "重置",
"form.label.search-keyword": "观检测",
"form.label.search-keyword": "关键词",
"component.globalHeader.search": "站内搜索",
"component.globalHeader.search.example1": "搜索提示一",

View File

@ -246,6 +246,7 @@ export default {
updateCluster(state, { payload }) {
let idx = state.clusterList.findIndex((item) => item.id === payload.id);
idx > -1 && (state.clusterList[idx].name = payload.name);
state.clusterStatus[payload.id].config.monitored = payload.monitored;
return state;
},
changeClusterById(state, { payload }) {

View File

@ -16,6 +16,7 @@ import {
} from "antd";
import moment from "moment";
import router from "umi/router";
import Link from "umi/link";
import "@elastic/charts/dist/theme_only_light.css";
import {
@ -38,6 +39,7 @@ import NodeMetric from "./components/node_metric";
import IndexMetric from "./components/index_metric";
import ClusterMetric from "./components/cluster_metric";
import QueueMetric from "./components/queue_metric";
// import StorageMetric from "./components/storage_metric";
import { formatter, getFormatter, getNumFormatter } from "./format";
const { RangePicker } = DatePicker;
@ -452,8 +454,10 @@ class ClusterMonitor extends PureComponent {
});
let clusterAvailable = true;
const { clusterStatus: cstatus, selectedCluster } = this.props;
let clusterMonitored = true;
if (cstatus && selectedCluster && cstatus[selectedCluster.id]) {
clusterAvailable = cstatus[selectedCluster.id].available;
clusterMonitored = cstatus[selectedCluster.id].config.monitored;
}
return (
@ -476,10 +480,26 @@ class ClusterMonitor extends PureComponent {
Last data collection time: {clusterStats?.timestamp}
</div>
</div>
) : !clusterMonitored ? (
<div className={styles.mask}>
<div>
Cluster is not monitored.{" "}
<Button type="primary">
<Link to={`/system/cluster/${selectedCluster.id}/edit`}>
Go to open
</Link>
</Button>
</div>
<div className={styles.time}>
Last data collection time: {clusterStats?.timestamp}
</div>
</div>
) : null}
<Row
gutter={[16, { xs: 8, sm: 16, md: 24, lg: 32 }]}
className={!clusterAvailable ? styles.metricMask : ""}
className={
!clusterAvailable || !clusterMonitored ? styles.metricMask : ""
}
>
<Col md={2} xs={4}>
<Statistic
@ -510,7 +530,11 @@ class ClusterMonitor extends PureComponent {
</Col>
<Col md={2} xs={4}>
<Statistic
valueStyle={vstyle}
valueStyle={{
...vstyle,
display: "flex",
alignItems: "center",
}}
title={formatMessage({
id: "cluster.monitor.summary.health",
})}
@ -649,6 +673,18 @@ class ClusterMonitor extends PureComponent {
handleTimeChange={this.handleTimeChange}
/>
</Tabs.TabPane>
{/* <Tabs.TabPane
key="storage"
tab={formatMessage({
id: "cluster.monitor.queue.storage",
})}
>
<StorageMetric
clusterID={this.props.selectedCluster.id}
timezone={timezone}
timeRange={this.state.timeRange}
/>
</Tabs.TabPane> */}
</Tabs>
</div>
</div>

View File

@ -23,10 +23,10 @@ import MetricContainer from "./metric_container";
import _ from "lodash";
const gorupOrder = [
"storage",
"document",
"operations",
"latency",
"storage",
"document",
"memory",
"cache",
];

View File

@ -23,10 +23,10 @@ import MetricContainer from "./metric_container";
import _ from "lodash";
const gorupOrder = [
"system",
"transport",
"operations",
"latency",
"system",
"transport",
"storage",
"document",
"http",

View File

@ -23,8 +23,8 @@ import MetricContainer from "./metric_container";
import _ from "lodash";
const gorupOrder = [
"thread_pool_search",
"thread_pool_write",
"thread_pool_search",
"thread_pool_index",
"thread_pool_bulk",
"thread_pool_get",

View File

@ -436,6 +436,7 @@ export const ConsoleUI = ({
paneKey={pane.key}
saveEditorContent={saveEditorContent}
initialText={pane.content}
isActive={pane.key == tabState.activeKey}
/>
{/* {pane.content} */}
</TabPane>

View File

@ -25,23 +25,36 @@ import { formatMessage } from "umi/locale";
class ClusterForm extends React.Component {
constructor(props) {
super(props);
let editValue = this.props.clusterConfig.editValue;
let needAuth = false;
if (
editValue.basic_auth &&
typeof editValue.basic_auth.username !== "undefined" &&
editValue.basic_auth.username !== ""
) {
needAuth = true;
}
this.state = {
confirmDirty: false,
needAuth: needAuth,
isLoading: false,
};
}
componentDidMount() {
//console.log(this.props.clusterConfig.editMode)
const { match, dispatch, clusterConfig } = this.props;
dispatch({
type: "clusterConfig/fetchCluster",
payload: {
id: match.params.id,
},
}).then((res) => {
if (res && res.found) {
let editValue = res._source;
let needAuth = false;
if (
editValue.basic_auth &&
typeof editValue.basic_auth.username !== "undefined"
) {
needAuth = true;
}
this.setState({
needAuth: needAuth,
});
}
});
}
compareToFirstPassword = (rule, value, callback) => {
@ -62,7 +75,7 @@ class ClusterForm extends React.Component {
};
handleSubmit = () => {
const { form, dispatch, clusterConfig } = this.props;
const { form, dispatch, clusterConfig, history } = this.props;
form.validateFields((errors, values) => {
if (errors) {
return;
@ -100,7 +113,8 @@ class ClusterForm extends React.Component {
}).then(function(rel) {
if (rel) {
message.success("修改成功");
router.push("/system/cluster");
// router.push("/system/cluster");
history.go(-1);
}
});
}
@ -256,7 +270,7 @@ class ClusterForm extends React.Component {
})}
>
<Switch
defaultChecked={this.state.needAuth}
checked={this.state.needAuth}
onChange={this.handleAuthChange}
checkedChildren={<Icon type="check" />}
unCheckedChildren={<Icon type="close" />}

View File

@ -178,7 +178,7 @@ class Index extends React.Component {
render: (text, record) => (
<div>
<Link
to="/system/cluster/edit"
to={`/system/cluster/${record.id}/edit`}
onClick={() => {
this.handleEditClick(record);
}}

View File

@ -4,6 +4,7 @@ import {
updateClusterConfig,
deleteClusterConfig,
tryConnect,
getClusterConfig,
} from "@/services/cluster";
import { message } from "antd";
import { formatESSearchResult } from "@/lib/elasticsearch/util";
@ -36,6 +37,23 @@ export default {
},
});
},
*fetchCluster({ payload }, { call, put, select }) {
let res = yield call(getClusterConfig, payload);
if (res.error) {
message.error(res.error);
return false;
}
yield put({
type: "saveData",
payload: {
editValue: {
...res._source,
id: res._id,
},
},
});
return res;
},
*addCluster({ payload }, { call, put, select }) {
let res = yield call(createClusterConfig, payload);
if (res.error) {
@ -76,20 +94,22 @@ export default {
return false;
}
let { data } = yield select((state) => state.clusterConfig);
let idx = data.findIndex((item) => {
return item.id === res._id;
});
if (data) {
let idx = data.findIndex((item) => {
return item.id === res._id;
});
data[idx] = {
...data[idx],
...res._source,
};
yield put({
type: "saveData",
payload: {
data,
},
});
}
data[idx] = {
...data[idx],
...res._source,
};
yield put({
type: "saveData",
payload: {
data,
},
});
//handle global cluster logic
yield put({
@ -97,9 +117,9 @@ export default {
payload: {
id: res._id,
name: res._source.name,
monitored: res._source.monitored,
},
});
return res;
},
*deleteCluster({ payload }, { call, put, select }) {

View File

@ -72,3 +72,10 @@ export async function tryConnect(params) {
body: params,
});
}
export async function getClusterConfig(params) {
let url = `${ESPrefix}/${params.id}`;
return request(url, {
method: "GET",
});
}