Fix: some issue (#29)
* chore: change loading ui of DropdownList * fix: remove index health in shard monitor overview * chore: add error handling to monitor chart * fix: lose table data in Overview * chore: optimize ui of collect status * fix: remove team in audit --------- Co-authored-by: yaojiping <yaojiping@infini.ltd>
This commit is contained in:
parent
9cb54a3381
commit
cfdc1870a9
|
@ -1,13 +1,12 @@
|
|||
import Loading from "./loading.svg";
|
||||
import styles from "./Loading.less";
|
||||
import { Spin } from "antd";
|
||||
|
||||
export default (props) => {
|
||||
const { loading = true, currentLocales } = props;
|
||||
if (!loading) return null;
|
||||
return (
|
||||
<div className={styles.loading}>
|
||||
<img src={Loading}/>
|
||||
<div className={styles.tips}>{currentLocales["dropdownlist.loading"]}</div>
|
||||
<Spin tip={currentLocales["dropdownlist.loading"]}/>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -1,9 +1,8 @@
|
|||
import request from "@/utils/request"
|
||||
import { firstUpperCase, formatToUniversalTime } from "@/utils/utils";
|
||||
import { Descriptions, Icon, Tooltip } from "antd";
|
||||
import { Descriptions, Icon, Spin, Tooltip } from "antd";
|
||||
import moment from "moment";
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import styles from "./index.less";
|
||||
import { formatMessage } from "umi/locale";
|
||||
|
||||
const STATUS_ICONS = {
|
||||
|
@ -48,14 +47,18 @@ export default (props) => {
|
|||
const [data, setData] = useState();
|
||||
const intervalRef = useRef()
|
||||
|
||||
const fetchData = async (fetchUrl) => {
|
||||
const fetchData = async (fetchUrl, showLoading = true) => {
|
||||
if (!fetchUrl) return
|
||||
setLoading(true)
|
||||
if (showLoading) {
|
||||
setLoading(true)
|
||||
}
|
||||
const res = await request(fetchUrl)
|
||||
if (res && !res?.error) {
|
||||
setData(res)
|
||||
}
|
||||
setLoading(false)
|
||||
if (showLoading) {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -64,7 +67,7 @@ export default (props) => {
|
|||
clearInterval(intervalRef.current)
|
||||
}
|
||||
intervalRef.current = setInterval(() => {
|
||||
fetchData(fetchUrl)
|
||||
fetchData(fetchUrl, false)
|
||||
}, 300000)
|
||||
return () => {
|
||||
if (intervalRef.current) {
|
||||
|
@ -91,24 +94,35 @@ export default (props) => {
|
|||
<Tooltip
|
||||
placement="bottomRight"
|
||||
title={(
|
||||
<Descriptions className={styles.content} title={formatMessage({ id: 'cluster.collect.last_active_at'})} column={1}>
|
||||
{
|
||||
stats.map((key) => (
|
||||
<Descriptions.Item key={key} label={formatMessage({ id: `cluster.manage.monitor_configs.${key}`})}>
|
||||
<div style={{ display: 'flex', gap: 6, alignItems: 'center' }}>
|
||||
{STATUS_ICONS[data?.[key]?.status || 'unknown']}{formatToUniversalTime(data?.[key]?.last_active_at)}
|
||||
<Spin spinning={loading}>
|
||||
<div>
|
||||
<div style={{ marginBottom: 12 }} >
|
||||
<span style={{ fontWeight: 'bold' }}>
|
||||
{formatMessage({ id: 'cluster.collect.last_active_at'})}
|
||||
</span>
|
||||
<a style={{ marginLeft: 8 }} onClick={() => !loading && fetchData(fetchUrl)} ><Icon type="reload"/></a>
|
||||
</div>
|
||||
{
|
||||
stats.map((key, i) => (
|
||||
<div key={key} style={{ display: 'flex', gap: 6, alignItems: 'center', marginBottom: i === stats.length - 1 ? 0 : 12 }}>
|
||||
<div style={{ width: 130 }}>{formatMessage({ id: `cluster.manage.monitor_configs.${key}`})}</div>
|
||||
<div style={{ display: 'flex', gap: 6, alignItems: 'center' }}>
|
||||
{STATUS_ICONS[data?.[key]?.status || 'unknown']}{data?.[key]?.last_active_at ? moment.duration(data?.[key]?.last_active_at - new Date().valueOf()).humanize(true) : '-'}
|
||||
</div>
|
||||
</div>
|
||||
</Descriptions.Item>
|
||||
))
|
||||
}
|
||||
</Descriptions>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</Spin>
|
||||
)}
|
||||
overlayStyle={{ maxWidth: 360 }}
|
||||
overlayStyle={{ maxWidth: 'none', width: 'auto' }}
|
||||
>
|
||||
<div style={{ display: "flex", alignItems: "center", gap: 6 }}>
|
||||
{renderIcon()}
|
||||
{firstUpperCase(data?.metric_collection_mode) || "Unknown"}
|
||||
</div>
|
||||
<Spin spinning={loading}>
|
||||
<div style={{ display: "flex", alignItems: "center", gap: 6, cursor: 'pointer' }}>
|
||||
{renderIcon()}
|
||||
{firstUpperCase(data?.metric_collection_mode) || "Unknown"}
|
||||
</div>
|
||||
</Spin>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
.content {
|
||||
:global {
|
||||
.ant-descriptions-item-label {
|
||||
width: 110px;
|
||||
}
|
||||
.ant-descriptions-title, .ant-descriptions-item-label, .ant-descriptions-item-content {
|
||||
color: #fff;
|
||||
}
|
||||
.ant-descriptions-title {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.ant-descriptions-item {
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
.ant-descriptions-row:last-child {
|
||||
.ant-descriptions-item {
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -475,7 +475,6 @@ const Index = forwardRef((props, ref) => {
|
|||
timeRange={queryParams?.timeRange || {}}
|
||||
onTimeRangeChange={onTimeRangeChange}
|
||||
isRefreshPaused={isRefreshPaused}
|
||||
onRefresh={onRefresh}
|
||||
recentlyUsedRangesKey={collectionName}
|
||||
/>
|
||||
) : null}
|
||||
|
|
|
@ -121,7 +121,7 @@ const Monitor = (props) => {
|
|||
|
||||
<Card bodyStyle={{ padding: 15 }}>
|
||||
{
|
||||
selectedCluster ? (
|
||||
selectedCluster?.id ? (
|
||||
<>
|
||||
<div style={{ marginBottom: 5 }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||
|
|
|
@ -103,7 +103,6 @@ export default forwardRef((props: IProps, ref: any) => {
|
|||
const drawRef = useRef<IDrawerRef>(null);
|
||||
|
||||
const [searchField, setSearchField] = useState<string>();
|
||||
const [infos, setInfos] = useState({});
|
||||
const [selectedItem, setSelectedItem] = useState<IRecord>({});
|
||||
|
||||
const [dispalyTypeObj, setDispalyTypeObj] = useLocalStorage(
|
||||
|
@ -187,20 +186,6 @@ export default forwardRef((props: IProps, ref: any) => {
|
|||
});
|
||||
};
|
||||
|
||||
const fetchListInfo = async () => {
|
||||
const ids = hits?.map((hit: { _id: string }) => listItemConfig.getId(hit));
|
||||
if (!ids || ids.length == 0) {
|
||||
return;
|
||||
}
|
||||
const res = await request(infoAction, {
|
||||
method: "POST",
|
||||
body: ids,
|
||||
});
|
||||
if (res) {
|
||||
setInfos(res);
|
||||
}
|
||||
};
|
||||
|
||||
const onFacetChange = (v: { value: string[]; field: string }) => {
|
||||
const { filters = {}, ...restParams } = param;
|
||||
if (!v.value || v.value.length === 0) {
|
||||
|
@ -286,9 +271,6 @@ export default forwardRef((props: IProps, ref: any) => {
|
|||
<listItemConfig.component
|
||||
data={item}
|
||||
id={infoField}
|
||||
info={
|
||||
infoField && infos[infoField] ? infos[infoField] : {}
|
||||
}
|
||||
isActive={selectedItem?._id == item?._id}
|
||||
onSelect={() => {
|
||||
setSelectedItem(item);
|
||||
|
@ -303,8 +285,8 @@ export default forwardRef((props: IProps, ref: any) => {
|
|||
/>
|
||||
) : (
|
||||
<tableConfig.component
|
||||
infos={infos}
|
||||
dataSource={hits}
|
||||
infoAction={infoAction}
|
||||
dataSource={hits.map((item) => ({...item, id: listItemConfig.getId(item)}))}
|
||||
total={result?.total?.value || 0}
|
||||
from={queryParams.from}
|
||||
pageSize={queryParams.size}
|
||||
|
|
|
@ -16,6 +16,7 @@ import host from "./en-US/host";
|
|||
import settings from "./en-US/settings";
|
||||
import listview from "./en-US/listview";
|
||||
import audit from "./en-US/audit";
|
||||
import error from "./en-US/error";
|
||||
|
||||
export default {
|
||||
"navBar.lang": "Languages",
|
||||
|
@ -622,5 +623,6 @@ export default {
|
|||
...host,
|
||||
...settings,
|
||||
...listview,
|
||||
...audit
|
||||
...audit,
|
||||
...error
|
||||
};
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
export default {
|
||||
"error.split": ", ",
|
||||
"error.unknown": "unknown error, please try again later or contact the support team!",
|
||||
"error.request_timeout_error": "request timeout, please try again later or contact the support team!",
|
||||
};
|
|
@ -16,6 +16,7 @@ import host from "./zh-CN/host";
|
|||
import settings from "./zh-CN/settings";
|
||||
import listview from "./zh-CN/listview";
|
||||
import audit from "./zh-CN/audit";
|
||||
import error from "./zh-CN/error";
|
||||
|
||||
export default {
|
||||
"navBar.lang": "语言",
|
||||
|
@ -613,5 +614,6 @@ export default {
|
|||
...host,
|
||||
...settings,
|
||||
...listview,
|
||||
...audit
|
||||
...audit,
|
||||
...error
|
||||
};
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
export default {
|
||||
"error.split": ",",
|
||||
"error.unknown": "未知错误,请稍后重试或者联系支持团队!",
|
||||
"error.request_timeout_error": "请求超时,请稍后重试或者联系支持团队!",
|
||||
}
|
|
@ -7,10 +7,11 @@ import { SearchEngineIcon } from "@/lib/search_engines";
|
|||
import { HealthStatusView } from "@/components/infini/health_status_view";
|
||||
import { StatusBlockGroup } from "@/components/infini/status_block";
|
||||
import { Providers, ProviderIcon } from "@/lib/providers";
|
||||
import request from "@/utils/request";
|
||||
import styles from "./index.less"
|
||||
|
||||
export default (props) => {
|
||||
const {
|
||||
infos,
|
||||
dataSource,
|
||||
total,
|
||||
from,
|
||||
|
@ -19,8 +20,34 @@ export default (props) => {
|
|||
onPageChange,
|
||||
onPageSizeChange,
|
||||
onRowClick,
|
||||
infoAction
|
||||
} = props;
|
||||
|
||||
const [infos, setInfos] = useState({});
|
||||
|
||||
const fetchListInfo = async (data) => {
|
||||
const res = await Promise.all(data?.map((item) => request(infoAction, {
|
||||
method: "POST",
|
||||
body: [item.id],
|
||||
}, false, false)));
|
||||
if (res) {
|
||||
let newInfos = {}
|
||||
res.forEach((item) => {
|
||||
if (item && !item.error) {
|
||||
newInfos = {
|
||||
...newInfos,
|
||||
...item
|
||||
}
|
||||
}
|
||||
})
|
||||
setInfos(newInfos);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchListInfo(dataSource);
|
||||
}, [JSON.stringify(dataSource)])
|
||||
|
||||
const [tableData] = useMemo(() => {
|
||||
let tableData = dataSource?.map((item) => {
|
||||
const id = item?._id;
|
||||
|
@ -269,6 +296,7 @@ export default (props) => {
|
|||
},
|
||||
};
|
||||
}}
|
||||
rowClassName={() => styles.rowPointer}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
.rowPointer {
|
||||
cursor: pointer;
|
||||
}
|
|
@ -29,12 +29,12 @@ export default ({
|
|||
timeout={timeout}
|
||||
refresh={refresh}
|
||||
metrics={[
|
||||
"index_health",
|
||||
isAgent && shardID ? 'shard_state' : "index_health",
|
||||
"index_throughput",
|
||||
"search_throughput",
|
||||
"index_latency",
|
||||
"search_latency",
|
||||
isAgent ? "shard_state" : undefined,
|
||||
isAgent && !shardID ? "shard_state" : undefined,
|
||||
].filter((item) => !!item)}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import request from "@/utils/request";
|
||||
import request, { formatResponse } from "@/utils/request";
|
||||
import { cloneDeep } from "lodash";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { formatMessage } from "umi/locale";
|
||||
|
@ -71,8 +71,9 @@ export default (props) => {
|
|||
},
|
||||
ignoreTimeout: true
|
||||
}, false, false)
|
||||
if (res?.error?.reason) {
|
||||
setError(res.error.reason)
|
||||
if (res?.error) {
|
||||
const error = formatResponse(res.error);
|
||||
setError(error?.errorObject?.key ? formatMessage({ id: `${error?.errorObject?.key}` }) : res?.error?.reason)
|
||||
} else if (res && !res.error) {
|
||||
const { metrics = {} } = res || {};
|
||||
const metric = metrics[metricKey]
|
||||
|
|
|
@ -56,13 +56,6 @@ export default (props) => {
|
|||
searchable: true,
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
title: "TEAM",
|
||||
key: "metadata.labels.team",
|
||||
aggregable: true,
|
||||
searchable: true,
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
title: "OPERATION",
|
||||
key: "metadata.labels.operation",
|
||||
|
@ -206,10 +199,6 @@ export default (props) => {
|
|||
<div className={styles.label}>操作者</div>
|
||||
<div className={styles.value}>{selectedItem.metadata.operator || '-'}</div>
|
||||
</div>
|
||||
<div className={styles.item}>
|
||||
<div className={styles.label}>团队</div>
|
||||
<div className={styles.value}>{selectedItem.metadata.labels.team || '-'}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.drawerMsg}>
|
||||
|
|
|
@ -5,6 +5,31 @@ import hash from "hash.js";
|
|||
import { isAntdPro } from "./utils";
|
||||
import { formatMessage } from "umi/locale";
|
||||
import { getAuthorizationHeader } from "./authority";
|
||||
import * as uuid from 'uuid';
|
||||
|
||||
export const formatResponse = (response) => {
|
||||
if (!response || !response.error) return response;
|
||||
let key;
|
||||
let msg;
|
||||
if (response.error.reason === 'context deadline exceeded') {
|
||||
key = 'error.timeout'
|
||||
} else {
|
||||
const errors = response.error.reason?.split(':');
|
||||
const errorKey = errors[0]?.endsWith('_error') ? errors[0] : 'unknown';
|
||||
const field = errors[1]
|
||||
key = errorKey !== 'unknown' && errors[1] ? `error.${errorKey}.${errors[1]}` : `error.${errorKey}`;
|
||||
msg = errors.slice(2).join(':')
|
||||
}
|
||||
|
||||
return {
|
||||
...response,
|
||||
errorObject: {
|
||||
id: uuid.v4(),
|
||||
key,
|
||||
msg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const checkStatus = async (response, noticeable, option={}) => {
|
||||
const codeMessage = {
|
||||
|
|
Loading…
Reference in New Issue