fix: optimize metrics fetching in overview (#24)
Co-authored-by: yaojiping <yaojiping@infini.ltd>
This commit is contained in:
parent
217008fd2f
commit
84577784a2
|
@ -1,7 +1,7 @@
|
|||
import { HealthStatusCircle } from "@/components/infini/health_status_circle";
|
||||
import request from "@/utils/request";
|
||||
import { AutoComplete, Input, Select, Button, Radio, Icon } from "antd";
|
||||
import { Fragment, useState } from "react";
|
||||
import { Fragment, useEffect, useMemo, useRef, useState } from "react";
|
||||
import Filters from "./Filters";
|
||||
import styles from "./index.scss";
|
||||
import CardViewSvg from "@/components/Icons/CardView";
|
||||
|
@ -53,8 +53,10 @@ export default (props: IProps) => {
|
|||
showStatus = false,
|
||||
showTags = false,
|
||||
getOptionMeta,
|
||||
getSearch
|
||||
},
|
||||
getExtra,
|
||||
defaultSearchValue,
|
||||
} = props;
|
||||
|
||||
const [searchValue, setSearchValue] = useState("");
|
||||
|
@ -63,10 +65,18 @@ export default (props: IProps) => {
|
|||
|
||||
const [searchOpen, setSearchOpen] = useState(false);
|
||||
|
||||
const firstInitRef = useRef(true)
|
||||
|
||||
useEffect(() => {
|
||||
if (defaultSearchValue) {
|
||||
setSearchValue(defaultSearchValue)
|
||||
}
|
||||
}, [defaultSearchValue])
|
||||
|
||||
function renderOption(item) {
|
||||
const { title, desc, right, tags, status } = getOptionMeta(item);
|
||||
const { title, desc, right, tags, status, text } = getOptionMeta(item);
|
||||
return (
|
||||
<Select.Option key={item._id} text={item._source?.name}>
|
||||
<Select.Option key={item._id} text={text} item={item}>
|
||||
<div className="suggest-item">
|
||||
<div className="suggest-line">
|
||||
<div>
|
||||
|
@ -132,6 +142,14 @@ export default (props: IProps) => {
|
|||
|
||||
const activeColor = "#1890ff";
|
||||
|
||||
const autoCompleteProps = useMemo(() => {
|
||||
if (defaultSearchValue && firstInitRef.current) {
|
||||
firstInitRef.current = false
|
||||
return { value: defaultSearchValue }
|
||||
}
|
||||
return {}
|
||||
}, [defaultSearchValue, searchValue])
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={styles.searchLine}>
|
||||
|
@ -180,12 +198,24 @@ export default (props: IProps) => {
|
|||
<AutoComplete
|
||||
style={{ width: `calc(100% - ${filterWidth}px)` }}
|
||||
dataSource={dataSource.map(renderOption)}
|
||||
onSelect={(value, option) => onSearchChange(option.props.text)}
|
||||
onSelect={(value, option) => {
|
||||
if (getSearch) {
|
||||
const search = getSearch(option.props.item)
|
||||
if (search) {
|
||||
setSearchValue(search.keyword)
|
||||
onSearchChange(search.keyword)
|
||||
if (search.filter) {
|
||||
onFacetChange(search.filter)
|
||||
}
|
||||
}
|
||||
}
|
||||
}}
|
||||
onSearch={handleSearch}
|
||||
optionLabelProp="text"
|
||||
getPopupContainer={(trigger) => trigger.parentElement}
|
||||
open={searchOpen}
|
||||
onDropdownVisibleChange={setSearchOpen}
|
||||
{...autoCompleteProps}
|
||||
>
|
||||
<Input.Search
|
||||
placeholder="Type keyword to search"
|
||||
|
|
|
@ -150,7 +150,11 @@ export default forwardRef((props: IProps, ref: any) => {
|
|||
throw new Error();
|
||||
}
|
||||
}
|
||||
const [queryParams, dispatch] = useReducer(reducer, initialQueryParams);
|
||||
const [queryParams, dispatch] = useReducer(reducer, {
|
||||
from: param?.from || initialQueryParams.from,
|
||||
size: param?.size || initialQueryParams.size ,
|
||||
keyword: param?.keyword || initialQueryParams.keyword
|
||||
});
|
||||
|
||||
const { run, loading, value } = useFetch(
|
||||
searchAction,
|
||||
|
@ -166,10 +170,10 @@ export default forwardRef((props: IProps, ref: any) => {
|
|||
},
|
||||
filter: param?.filters || {},
|
||||
sort: param?.sort || [],
|
||||
search_field: searchField,
|
||||
search_field: searchField || searchAutoCompleteConfig?.defaultSearchField,
|
||||
},
|
||||
},
|
||||
[queryParams, param?.filters, param?.sort]
|
||||
[queryParams, param?.filters, param?.sort, aggsParams, searchHighlightFields, searchField, searchAutoCompleteConfig?.defaultSearchField]
|
||||
);
|
||||
|
||||
const result = (value as any)?.hits || {};
|
||||
|
@ -220,7 +224,7 @@ export default forwardRef((props: IProps, ref: any) => {
|
|||
return;
|
||||
}
|
||||
|
||||
fetchListInfo();
|
||||
// fetchListInfo();
|
||||
}, [value]);
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -248,7 +252,10 @@ export default forwardRef((props: IProps, ref: any) => {
|
|||
setSearchField(value);
|
||||
setParam({ ...param, search_field: value });
|
||||
}}
|
||||
onSearchChange={(value) => dispatch({ type: "search", value })}
|
||||
defaultSearchValue={queryParams?.keyword}
|
||||
onSearchChange={(value) => {
|
||||
dispatch({ type: "search", value })
|
||||
}}
|
||||
onFacetChange={onFacetChange}
|
||||
dispalyType={dispalyTypeObj[currentTab]}
|
||||
onDisplayTypeChange={onDisplayTypeChange}
|
||||
|
@ -278,6 +285,7 @@ export default forwardRef((props: IProps, ref: any) => {
|
|||
return (
|
||||
<listItemConfig.component
|
||||
data={item}
|
||||
id={infoField}
|
||||
info={
|
||||
infoField && infos[infoField] ? infos[infoField] : {}
|
||||
}
|
||||
|
@ -287,6 +295,8 @@ export default forwardRef((props: IProps, ref: any) => {
|
|||
drawRef.current?.open();
|
||||
}}
|
||||
onChangeFacet={onFacetChange}
|
||||
infoAction={infoAction}
|
||||
parentLoading={loading}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import { Icon, Tooltip } from "antd";
|
||||
import { Icon, Spin, Tooltip } from "antd";
|
||||
import TinyArea from "@/components/infini/TinyArea";
|
||||
import { Pie } from "@/components/Charts";
|
||||
import { formatter } from "@/utils/format";
|
||||
|
@ -10,12 +10,39 @@ import "./index.scss";
|
|||
import { Providers, ProviderIcon } from "@/lib/providers";
|
||||
import { formatMessage } from "umi/locale";
|
||||
import { SearchEngineIcon } from "@/lib/search_engines";
|
||||
import request from "@/utils/request";
|
||||
|
||||
export default (props) => {
|
||||
const { infoAction, id, parentLoading } = props;
|
||||
const clusterID = props.data?._id;
|
||||
const metadata = props.data._source || {};
|
||||
const summary = props.info.summary || {};
|
||||
const metrics = props.info.metrics || {};
|
||||
|
||||
const [info, setInfo] = useState({});
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
const fetchListInfo = async (id) => {
|
||||
if (!id) return
|
||||
setLoading(true)
|
||||
const res = await request(infoAction, {
|
||||
method: "POST",
|
||||
body: [id],
|
||||
ignoreTimeout: true
|
||||
}, false, false);
|
||||
if (res) {
|
||||
setInfo(res[id] || {});
|
||||
}
|
||||
setLoading(false)
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!parentLoading) {
|
||||
fetchListInfo(id)
|
||||
}
|
||||
}, [id, parentLoading])
|
||||
|
||||
const summary = info?.summary || {};
|
||||
const metrics = info?.metrics || {};
|
||||
|
||||
const fs_total_in_bytes = summary?.fs?.total_in_bytes || 0;
|
||||
const fs_available_in_bytes = summary?.fs?.available_in_bytes || 0;
|
||||
const fs_used_in_bytes = fs_total_in_bytes - fs_available_in_bytes;
|
||||
|
@ -84,7 +111,9 @@ export default (props) => {
|
|||
const healthStatus = metadata.labels?.health_status;
|
||||
|
||||
return (
|
||||
<div className="card-wrap">
|
||||
<Spin spinning={!parentLoading && loading}>
|
||||
|
||||
<div className="card-wrap">
|
||||
<div
|
||||
className={`card-item ${props.isActive ? "active" : ""}`}
|
||||
onClick={() => props.onSelect()}
|
||||
|
@ -243,5 +272,6 @@ export default (props) => {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Spin>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -41,15 +41,20 @@ export default () => {
|
|||
searchAutoCompleteConfig={{
|
||||
showStatus: true,
|
||||
showTags: true,
|
||||
defaultSearchField: 'name',
|
||||
getSearch: (item) => ({
|
||||
keyword: item?._source?.name,
|
||||
}),
|
||||
getOptionMeta: (item) => ({
|
||||
title: item.highlight?.name || item._source?.name,
|
||||
desc: item.highlight?.version || item._source?.version,
|
||||
right: item.highlight?.host || item._source?.host,
|
||||
tags: item._source?.tags,
|
||||
status: item._source.labels?.health_status,
|
||||
text: item?._source?.name
|
||||
}),
|
||||
}}
|
||||
infoAction={`${ESPrefix}/cluster/info`}
|
||||
infoAction={`${ESPrefix}/cluster/info?timeout=120s`}
|
||||
facetLabels={facetLabels}
|
||||
aggsParams={aggsParams}
|
||||
sideSorterOptions={sideSorterOptions}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import { Icon, Tooltip } from "antd";
|
||||
import { Icon, Spin, Tooltip } from "antd";
|
||||
import TinyArea from "@/components/infini/TinyArea";
|
||||
import { Pie } from "@/components/Charts";
|
||||
import { formatter } from "@/utils/format";
|
||||
|
@ -9,11 +9,11 @@ import moment from "moment";
|
|||
import { formatUtcTimeToLocal } from "@/utils/utils";
|
||||
import { FieldFilterFacet } from "@/components/Overview/List/FieldFilterFacet";
|
||||
import "./index.scss";
|
||||
import request from "@/utils/request";
|
||||
|
||||
export default (props) => {
|
||||
const { infoAction, id, parentLoading } = props;
|
||||
const metadata = props.data._source?.metadata || {};
|
||||
const summary = props.info?.summary || {};
|
||||
const metrics = props.info?.metrics || {};
|
||||
const timestamp = props.data._source?.timestamp
|
||||
? formatUtcTimeToLocal(props.data._source?.timestamp)
|
||||
: "N/A";
|
||||
|
@ -27,6 +27,32 @@ export default (props) => {
|
|||
return items;
|
||||
};
|
||||
|
||||
const [info, setInfo] = useState({});
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
const fetchListInfo = async (id) => {
|
||||
if (!id) return
|
||||
setLoading(true)
|
||||
const res = await request(infoAction, {
|
||||
method: "POST",
|
||||
body: [id],
|
||||
ignoreTimeout: true
|
||||
}, false, false);
|
||||
if (res) {
|
||||
setInfo(res[id] || {});
|
||||
}
|
||||
setLoading(false)
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!parentLoading) {
|
||||
fetchListInfo(id)
|
||||
}
|
||||
}, [id, parentLoading])
|
||||
|
||||
const summary = info?.summary || {};
|
||||
const metrics = info?.metrics || {};
|
||||
|
||||
let metricsSearch = metrics?.search || {};
|
||||
let metricsSearchData = metricsSearch?.data || defaultEmptyMetricsData();
|
||||
let searchLineMaxValue = metricsSearchData?.[0]?.[1] || 0;
|
||||
|
@ -81,6 +107,7 @@ export default (props) => {
|
|||
const unassignedShards = (numReplicas+1)*numShards-summary?.shards - summary?.replicas || 0
|
||||
|
||||
return (
|
||||
<Spin spinning={!parentLoading && loading}>
|
||||
<div className="card-wrap card-index">
|
||||
<div
|
||||
className={`card-item ${props.isActive ? "active" : ""}`}
|
||||
|
@ -201,5 +228,6 @@ export default (props) => {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Spin>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -6,13 +6,13 @@ import Table from "./Table";
|
|||
import Overview from "@/components/Overview";
|
||||
|
||||
const facetLabels = {
|
||||
"metadata.index_name": "index",
|
||||
"metadata.cluster_name": "cluster",
|
||||
"metadata.labels.health_status": "health",
|
||||
"metadata.labels.state": "state",
|
||||
};
|
||||
|
||||
const aggsParams = [
|
||||
{ field: "metadata.index_name", params: { size: 500 } },
|
||||
{ field: "metadata.cluster_name", params: { size: 150 } },
|
||||
{ field: "metadata.labels.state", params: { size: 100 } },
|
||||
{ field: "metadata.labels.health_status", params: { size: 150 } },
|
||||
];
|
||||
|
@ -39,6 +39,11 @@ export default () => {
|
|||
]}
|
||||
searchAutoCompleteConfig={{
|
||||
showStatus: true,
|
||||
defaultSearchField: 'metadata.index_name',
|
||||
getSearch: (item) => ({
|
||||
keyword: item?._source?.metadata?.index_name,
|
||||
filter: { value: [item?._source?.metadata?.cluster_name], field: 'metadata.cluster_name' }
|
||||
}),
|
||||
getOptionMeta: (item) => ({
|
||||
title:
|
||||
item?.highlight?.index_name || item?._source?.metadata?.index_name,
|
||||
|
@ -46,9 +51,10 @@ export default () => {
|
|||
item?.highlight?.cluster_name ||
|
||||
item?._source?.metadata?.cluster_name,
|
||||
status: item?._source?.metadata?.labels?.health_status,
|
||||
text: item?._source?.metadata?.index_name
|
||||
}),
|
||||
}}
|
||||
infoAction={`${ESPrefix}/index/info`}
|
||||
infoAction={`${ESPrefix}/index/info?timeout=120s`}
|
||||
facetLabels={facetLabels}
|
||||
aggsParams={aggsParams}
|
||||
sideSorterOptions={sideSorterOptions}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import { Icon, Tooltip } from "antd";
|
||||
import { Icon, Spin, Tooltip } from "antd";
|
||||
import TinyArea from "@/components/infini/TinyArea";
|
||||
import { Pie } from "@/components/Charts";
|
||||
import { formatter } from "@/utils/format";
|
||||
|
@ -8,11 +8,36 @@ import { HealthStatusView } from "@/components/infini/health_status_view";
|
|||
import { formatUtcTimeToLocal } from "@/utils/utils";
|
||||
import { FieldFilterFacet } from "@/components/Overview/List/FieldFilterFacet";
|
||||
import "./index.scss";
|
||||
import request from "@/utils/request";
|
||||
|
||||
export default (props) => {
|
||||
const { infoAction, id, parentLoading } = props;
|
||||
const metadata = props.data._source?.metadata || {};
|
||||
const summary = props.info?.summary || {};
|
||||
const metrics = props.info?.metrics || {};
|
||||
const [info, setInfo] = useState({});
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
const fetchListInfo = async (id) => {
|
||||
if (!id) return
|
||||
setLoading(true)
|
||||
const res = await request(infoAction, {
|
||||
method: "POST",
|
||||
body: [id],
|
||||
ignoreTimeout: true
|
||||
}, false, false);
|
||||
if (res) {
|
||||
setInfo(res[id] || {});
|
||||
}
|
||||
setLoading(false)
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!parentLoading) {
|
||||
fetchListInfo(id)
|
||||
}
|
||||
}, [id, parentLoading])
|
||||
|
||||
const summary = info?.summary || {};
|
||||
const metrics = info?.metrics || {};
|
||||
const fs_total_in_bytes = summary?.fs?.total?.total_in_bytes || 0;
|
||||
const fs_available_in_bytes = summary?.fs?.total?.available_in_bytes || 0;
|
||||
const fs_used_in_bytes = fs_total_in_bytes - fs_available_in_bytes;
|
||||
|
@ -81,6 +106,8 @@ export default (props) => {
|
|||
const healthStatus = metadata?.labels?.status;
|
||||
|
||||
return (
|
||||
<Spin spinning={!parentLoading && loading}>
|
||||
|
||||
<div className="card-wrap">
|
||||
<div
|
||||
className={`card-item ${props.isActive ? "active" : ""}`}
|
||||
|
@ -238,5 +265,6 @@ export default (props) => {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Spin>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -48,6 +48,11 @@ export default () => {
|
|||
"metadata.cluster_name",
|
||||
]}
|
||||
searchAutoCompleteConfig={{
|
||||
defaultSearchField: 'metadata.node_name',
|
||||
getSearch: (item) => ({
|
||||
keyword: item?._source?.metadata?.node_name,
|
||||
filter: { value: [item?._source?.metadata?.cluster_name], field: 'metadata.cluster_name' }
|
||||
}),
|
||||
getOptionMeta: (item) => ({
|
||||
title:
|
||||
item?.highlight?.node_name || item?._source?.metadata?.node_name,
|
||||
|
@ -55,9 +60,10 @@ export default () => {
|
|||
item?.highlight?.cluster_name ||
|
||||
item?._source?.metadata?.cluster_name,
|
||||
right: item?.highlight?.host || item?._source?.metadata?.host,
|
||||
text: item?._source?.metadata?.node_name
|
||||
}),
|
||||
}}
|
||||
infoAction={`${ESPrefix}/node/info`}
|
||||
infoAction={`${ESPrefix}/node/info?timeout=120s`}
|
||||
facetLabels={facetLabels}
|
||||
selectFilterLabels={selectFilterLabels}
|
||||
aggsParams={aggsParams}
|
||||
|
|
Loading…
Reference in New Issue