fix: error after changed table mode in overview (#30)

Co-authored-by: yaojiping <yaojiping@infini.ltd>
This commit is contained in:
yaojp123 2024-12-14 10:52:21 +08:00 committed by GitHub
parent cfdc1870a9
commit a08e33a570
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 662 additions and 725 deletions

View File

@ -301,6 +301,7 @@ export default forwardRef((props: IProps, ref: any) => {
setSelectedItem(item); setSelectedItem(item);
drawRef.current?.open(); drawRef.current?.open();
}} }}
parentLoading={loading}
/> />
)} )}
</div> </div>

View File

@ -1,303 +1,233 @@
import React, { useState, useEffect, useMemo } from "react"; import React, { useState, useEffect, useMemo } from "react";
import { Table, Tooltip, Progress } from "antd"; import { Table, Tooltip, Progress } from "antd";
import { formatter } from "@/utils/format"; import { formatter } from "@/utils/format";
import { formatUtcTimeToLocal } from "@/utils/utils";
import { formatMessage } from "umi/locale"; import { formatMessage } from "umi/locale";
import { SearchEngineIcon } from "@/lib/search_engines"; import { SearchEngineIcon } from "@/lib/search_engines";
import { HealthStatusView } from "@/components/infini/health_status_view"; import { HealthStatusView } from "@/components/infini/health_status_view";
import { StatusBlockGroup } from "@/components/infini/status_block"; import { StatusBlockGroup } from "@/components/infini/status_block";
import { Providers, ProviderIcon } from "@/lib/providers"; import { Providers, ProviderIcon } from "@/lib/providers";
import request from "@/utils/request"; import CommonTable from "../../components/CommonTable";
import styles from "./index.less"
export default (props) => { export default (props) => {
const {
dataSource,
total,
from,
pageSize,
loading,
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;
const metadata = item._source || {};
const info = id && infos[id] ? infos[id] : {};
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;
const jvm_mem_total_in_bytes = summary?.jvm?.heap_max_in_bytes || 0;
const jvm_mem_used_in_bytes = summary?.jvm?.heap_used_in_bytes || 0;
const disk_percent =
fs_total_in_bytes > 0
? Math.round((fs_used_in_bytes / fs_total_in_bytes) * 100)
: 0;
const jvm_mem_percent =
jvm_mem_total_in_bytes > 0
? Math.round((jvm_mem_used_in_bytes / jvm_mem_total_in_bytes) * 100)
: 0;
const metrics_status = metrics?.status || {};
return {
id,
metadata,
summary,
metrics_status,
fs_total_in_bytes,
fs_available_in_bytes,
fs_used_in_bytes,
jvm_mem_total_in_bytes,
jvm_mem_used_in_bytes,
disk_percent,
jvm_mem_percent,
};
});
return [tableData];
}, [JSON.stringify(dataSource), JSON.stringify(infos)]);
const [columns] = useMemo(() => {
let columns = [
{
title: "Name",
dataIndex: "name",
render: (text, record) => {
return (
<Tooltip
placement="topLeft"
title={
<span>
Host: {record.metadata?.host}
<br />
Provider:{" "}
{formatMessage({
id: `cluster.providers.${record.metadata?.location
?.provider ?? Providers.OnPremises}`,
})}
<br />
Region: {record.metadata?.location?.region ?? ""}
<br />
Version: {record.metadata?.version ?? ""}
<br />
Tags:{" "}
{record.metadata?.tags ? record.metadata.tags.toString() : ""}
</span>
}
>
<div style={{ display: "flex", alignContent: "center", gap: 5 }}>
<SearchEngineIcon
distribution={record.metadata?.distribution}
width="20px"
height="20px"
/>
<span>{record.metadata?.name}</span>
</div>
</Tooltip>
);
},
},
{
title: "Version",
dataIndex: "version",
render: (text, record) => {
return record.metadata?.version ?? "";
},
},
{
title: "Health",
dataIndex: "health_status",
render: (text, record) => {
return (
<Tooltip
title={
<span
style={{
display: "flex",
flexDirection: "column",
gap: 5,
padding: 5,
}}
>
<StatusBlockGroup data={record.metrics_status?.data} />
<span>
{record.metrics_status?.metric?.label +
"(" +
(record.metrics_status?.data?.length || 14) +
" " +
record.metrics_status?.metric?.units +
")"}
</span>
</span>
}
>
<div>
<HealthStatusView
status={record.metadata?.labels?.health_status}
/>
</div>
</Tooltip>
);
},
},
{
title: "Nodes",
dataIndex: "nodes",
render: (text, record) => {
return record.summary?.number_of_nodes || 0;
},
},
{
title: "Indices",
dataIndex: "Indices",
render: (text, record) => {
return record.summary?.number_of_indices || 0;
},
},
{
title: "Shards",
dataIndex: "Shards",
render: (text, record) => {
return record.summary?.number_of_shards || 0;
},
},
{
title: "Docs",
dataIndex: "Docs",
render: (text, record) => {
return (
<Tooltip
title={`Docs:${formatter.number(
record.summary?.number_of_documents
)}`}
>
{formatter.numberToHuman(record.summary?.number_of_documents)}
</Tooltip>
);
},
},
{
title: "Disk Usage",
dataIndex: "DiskUsage",
render: (text, record) => {
return (
<Tooltip
title={
<span>
Total:{formatter.bytes(record.fs_total_in_bytes)}
<br />
Used:{formatter.bytes(record.fs_used_in_bytes)}
<br />
Free:{formatter.bytes(record.fs_available_in_bytes)}
</span>
}
>
<Progress
strokeLinecap="square"
strokeColor="#558EF0"
strokeWidth={12}
percent={record.disk_percent}
format={(percent) => `${percent}%`}
/>
</Tooltip>
);
},
},
{
title: "JVM Heap",
dataIndex: "JVMHeap",
render: (text, record) => {
return (
<Tooltip
title={
<span>
Total:{formatter.bytes(record.jvm_mem_total_in_bytes)}
<br />
Used:{formatter.bytes(record.jvm_mem_used_in_bytes)}
<br />
Free:
{formatter.bytes(
record.jvm_mem_total_in_bytes - record.jvm_mem_used_in_bytes
)}
</span>
}
>
<Progress
strokeLinecap="square"
strokeColor="#00BFB3"
strokeWidth={12}
percent={record.jvm_mem_percent}
format={(percent) => `${percent}%`}
/>
</Tooltip>
);
},
},
];
return [columns];
}, []);
return ( return (
<div className="table-wrap"> <CommonTable
<Table {...props}
size={"small"} columns={[
loading={loading} {
columns={columns} title: "Name",
dataSource={tableData} dataIndex: "name",
rowKey={"id"} render: (text, record) => {
pagination={{ return (
size: "small", <Tooltip
total, placement="topLeft"
pageSize, title={
onChange: onPageChange, <span>
showSizeChanger: true, Host: {record.metadata?.host}
onShowSizeChange: (_, size) => { <br />
onPageSizeChange(size); Provider:{" "}
{formatMessage({
id: `cluster.providers.${record.metadata?.location
?.provider ?? Providers.OnPremises}`,
})}
<br />
Region: {record.metadata?.location?.region ?? ""}
<br />
Version: {record.metadata?.version ?? ""}
<br />
Tags:{" "}
{record.metadata?.tags ? record.metadata.tags.toString() : ""}
</span>
}
>
<div style={{ display: "flex", alignContent: "center", gap: 5 }}>
<SearchEngineIcon
distribution={record.metadata?.distribution}
width="20px"
height="20px"
/>
<span>{record.metadata?.name}</span>
</div>
</Tooltip>
);
}, },
showTotal: (total, range) => },
`${range[0]}-${range[1]} of ${total} items`, {
}} title: "Version",
onRow={(record, i) => { dataIndex: "version",
render: (text, record) => {
return record.metadata?.version ?? "";
},
},
{
title: "Health",
dataIndex: "health_status",
render: (text, record) => {
return (
<Tooltip
title={
<span
style={{
display: "flex",
flexDirection: "column",
gap: 5,
padding: 5,
}}
>
<StatusBlockGroup data={record.metrics_status?.data} />
<span>
{record.metrics_status?.metric?.label +
"(" +
(record.metrics_status?.data?.length || 14) +
" " +
record.metrics_status?.metric?.units +
")"}
</span>
</span>
}
>
<div>
<HealthStatusView
status={record.metadata?.labels?.health_status}
/>
</div>
</Tooltip>
);
},
},
{
title: "Nodes",
dataIndex: "nodes",
render: (text, record) => {
return record.summary?.number_of_nodes || 0;
},
},
{
title: "Indices",
dataIndex: "Indices",
render: (text, record) => {
return record.summary?.number_of_indices || 0;
},
},
{
title: "Shards",
dataIndex: "Shards",
render: (text, record) => {
return record.summary?.number_of_shards || 0;
},
},
{
title: "Docs",
dataIndex: "Docs",
render: (text, record) => {
return (
<Tooltip
title={`Docs:${formatter.number(
record.summary?.number_of_documents
)}`}
>
{formatter.numberToHuman(record.summary?.number_of_documents)}
</Tooltip>
);
},
},
{
title: "Disk Usage",
dataIndex: "DiskUsage",
render: (text, record) => {
return (
<Tooltip
title={
<span>
Total:{formatter.bytes(record.fs_total_in_bytes)}
<br />
Used:{formatter.bytes(record.fs_used_in_bytes)}
<br />
Free:{formatter.bytes(record.fs_available_in_bytes)}
</span>
}
>
<Progress
strokeLinecap="square"
strokeColor="#558EF0"
strokeWidth={12}
percent={record.disk_percent}
format={(percent) => `${percent}%`}
/>
</Tooltip>
);
},
},
{
title: "JVM Heap",
dataIndex: "JVMHeap",
render: (text, record) => {
return (
<Tooltip
title={
<span>
Total:{formatter.bytes(record.jvm_mem_total_in_bytes)}
<br />
Used:{formatter.bytes(record.jvm_mem_used_in_bytes)}
<br />
Free:
{formatter.bytes(
record.jvm_mem_total_in_bytes - record.jvm_mem_used_in_bytes
)}
</span>
}
>
<Progress
strokeLinecap="square"
strokeColor="#00BFB3"
strokeWidth={12}
percent={record.jvm_mem_percent}
format={(percent) => `${percent}%`}
/>
</Tooltip>
);
},
},
]}
formatData={(dataSource, infos) => {
const newData = dataSource?.map((item) => {
const id = item?._id;
const metadata = item._source || {};
const info = id && infos[id] ? infos[id] : {};
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;
const jvm_mem_total_in_bytes = summary?.jvm?.heap_max_in_bytes || 0;
const jvm_mem_used_in_bytes = summary?.jvm?.heap_used_in_bytes || 0;
const disk_percent =
fs_total_in_bytes > 0
? Math.round((fs_used_in_bytes / fs_total_in_bytes) * 100)
: 0;
const jvm_mem_percent =
jvm_mem_total_in_bytes > 0
? Math.round((jvm_mem_used_in_bytes / jvm_mem_total_in_bytes) * 100)
: 0;
const metrics_status = metrics?.status || {};
return { return {
onClick: (event) => { id,
onRowClick(dataSource[i]); metadata,
}, summary,
metrics_status,
fs_total_in_bytes,
fs_available_in_bytes,
fs_used_in_bytes,
jvm_mem_total_in_bytes,
jvm_mem_used_in_bytes,
disk_percent,
jvm_mem_percent,
}; };
}} });
rowClassName={() => styles.rowPointer} return newData
/> }}
</div> />
); );
}; };

View File

@ -1,208 +1,167 @@
import React, { useState, useEffect, useMemo } from "react"; import React, { useState, useEffect, useMemo } from "react";
import { Table, Tooltip, Progress, Icon } from "antd"; import { Tooltip, Progress, Icon } from "antd";
import { formatter } from "@/utils/format"; import { formatter } from "@/utils/format";
import { formatUtcTimeToLocal } from "@/utils/utils"; import { formatUtcTimeToLocal } from "@/utils/utils";
import { formatMessage } from "umi/locale"; import { formatMessage } from "umi/locale";
import { SearchEngineIcon } from "@/lib/search_engines";
import { HealthStatusView } from "@/components/infini/health_status_view"; import { HealthStatusView } from "@/components/infini/health_status_view";
import { StatusBlockGroup } from "@/components/infini/status_block"; import { StatusBlockGroup } from "@/components/infini/status_block";
import CommonTable from "../../components/CommonTable";
export default (props) => { export default (props) => {
const {
infos,
dataSource,
total,
from,
pageSize,
loading,
onPageChange,
onPageSizeChange,
onRowClick,
} = props;
const [tableData] = useMemo(() => {
let tableData = dataSource?.map((item) => {
const id = item?._source?.metadata?.index_id;
const metadata = item?._source?.metadata || {};
const info = id && infos[id] ? infos[id] : {};
const summary = info.summary || {};
const metrics = info.metrics || {};
const timestamp = item?._source?.timestamp
? formatUtcTimeToLocal(item?._source?.timestamp)
: "N/A";
const metrics_status = metrics?.status || {};
return {
id,
metadata,
summary,
metrics_status,
timestamp,
};
});
return [tableData];
}, [JSON.stringify(dataSource), JSON.stringify(infos)]);
const [columns] = useMemo(() => {
let columns = [
{
title: "Name",
dataIndex: "name",
render: (text, record) => {
return (
<Tooltip
placement="topLeft"
title={
<span>
Cluster: {record.metadata?.cluster_name}
<br />
Aliases: {record.metadata?.aliases?.join(",")}
<br />
Timestamp: {record.timestamp}
</span>
}
>
<div style={{ display: "flex", alignContent: "center", gap: 5 }}>
<span>
<Icon type="table" />
</span>
<span>{record.metadata?.index_name}</span>
</div>
</Tooltip>
);
},
},
{
title: "Health",
dataIndex: "health_status",
render: (text, record) => {
return (
<Tooltip
title={
<span
style={{
display: "flex",
flexDirection: "column",
gap: 5,
padding: 5,
}}
>
<StatusBlockGroup data={record.metrics_status?.data} />
<span>
{record.metrics_status?.metric?.label +
"(" +
(record.metrics_status?.data?.length || 14) +
" " +
record.metrics_status?.metric?.units +
")"}
</span>
</span>
}
>
<div>
<HealthStatusView
status={record.metadata?.labels?.health_status}
/>
</div>
</Tooltip>
);
},
},
{
title: "Status",
dataIndex: "index_status",
render: (text, record) => {
return record.metadata?.labels?.state ?? "N/A";
},
},
{
title: "Store Size",
dataIndex: "store_size",
render: (text, record) => {
return record.summary?.index_info?.store_size?.toUpperCase() || "N/A";
},
},
{
title: "Shards",
dataIndex: "Shards",
render: (text, record) => {
return (
<Tooltip
title={
<span>
Unassigned Shards:
{record.summary?.unassigned_shards || 0}
<br />
Shards:
{record.summary?.index_info?.shards || 0}
<br />
Replicas:
{record.summary?.index_info?.replicas || 0}
</span>
}
>
{record.summary?.unassigned_shards || 0} /{" "}
{record.summary?.index_info?.shards ||
0 + (record.summary?.index_info?.replicas || 0)}
</Tooltip>
);
},
},
{
title: "Docs",
dataIndex: "Docs",
render: (text, record) => {
return (
<Tooltip
title={
<span>
Deleted:
{formatter.number(record.summary?.docs?.deleted || 0)}
<br />
Total:
{formatter.number(record.summary?.docs?.count || 0)}
</span>
}
>
{formatter.numberToHuman(record.summary?.docs?.deleted)} /{" "}
{formatter.numberToHuman(record.summary?.docs?.count)}
</Tooltip>
);
},
},
];
return [columns];
}, []);
return ( return (
<div className="table-wrap"> <CommonTable
<Table {...props}
size={"small"} columns={[
loading={loading} {
columns={columns} title: "Name",
dataSource={tableData} dataIndex: "name",
rowKey={"id"} render: (text, record) => {
pagination={{ return (
size: "small", <Tooltip
total, placement="topLeft"
pageSize, title={
onChange: onPageChange, <span>
showSizeChanger: true, Cluster: {record.metadata?.cluster_name}
onShowSizeChange: (_, size) => { <br />
onPageSizeChange(size); Aliases: {record.metadata?.aliases?.join(",")}
<br />
Timestamp: {record.timestamp}
</span>
}
>
<div style={{ display: "flex", alignContent: "center", gap: 5 }}>
<span>
<Icon type="table" />
</span>
<span>{record.metadata?.index_name}</span>
</div>
</Tooltip>
);
}, },
showTotal: (total, range) => },
`${range[0]}-${range[1]} of ${total} items`, {
}} title: "Health",
onRow={(record, i) => { dataIndex: "health_status",
render: (text, record) => {
return (
<Tooltip
title={
<span
style={{
display: "flex",
flexDirection: "column",
gap: 5,
padding: 5,
}}
>
<StatusBlockGroup data={record.metrics_status?.data} />
<span>
{record.metrics_status?.metric?.label +
"(" +
(record.metrics_status?.data?.length || 14) +
" " +
record.metrics_status?.metric?.units +
")"}
</span>
</span>
}
>
<div>
<HealthStatusView
status={record.metadata?.labels?.health_status}
/>
</div>
</Tooltip>
);
},
},
{
title: "Status",
dataIndex: "index_status",
render: (text, record) => {
return record.metadata?.labels?.state ?? "N/A";
},
},
{
title: "Store Size",
dataIndex: "store_size",
render: (text, record) => {
return record.summary?.index_info?.store_size?.toUpperCase() || "N/A";
},
},
{
title: "Shards",
dataIndex: "Shards",
render: (text, record) => {
return (
<Tooltip
title={
<span>
Unassigned Shards:
{record.summary?.unassigned_shards || 0}
<br />
Shards:
{record.summary?.index_info?.shards || 0}
<br />
Replicas:
{record.summary?.index_info?.replicas || 0}
</span>
}
>
{record.summary?.unassigned_shards || 0} /{" "}
{record.summary?.index_info?.shards ||
0 + (record.summary?.index_info?.replicas || 0)}
</Tooltip>
);
},
},
{
title: "Docs",
dataIndex: "Docs",
render: (text, record) => {
return (
<Tooltip
title={
<span>
Deleted:
{formatter.number(record.summary?.docs?.deleted || 0)}
<br />
Total:
{formatter.number(record.summary?.docs?.count || 0)}
</span>
}
>
{formatter.numberToHuman(record.summary?.docs?.deleted)} /{" "}
{formatter.numberToHuman(record.summary?.docs?.count)}
</Tooltip>
);
},
},
]}
formatData={(dataSource, infos) => {
const newData = dataSource?.map((item) => {
const id = item?._source?.metadata?.index_id;
const metadata = item?._source?.metadata || {};
const info = id && infos[id] ? infos[id] : {};
const summary = info.summary || {};
const metrics = info.metrics || {};
const timestamp = item?._source?.timestamp
? formatUtcTimeToLocal(item?._source?.timestamp)
: "N/A";
const metrics_status = metrics?.status || {};
return { return {
onClick: (event) => { id,
onRowClick(dataSource[i]); metadata,
}, summary,
metrics_status,
timestamp,
}; };
}} });
/> return newData
</div> }}
/>
); );
}; };

View File

@ -1,257 +1,213 @@
import React, { useState, useEffect, useMemo } from "react"; import React, { useState, useEffect, useMemo } from "react";
import { Table, Tooltip, Progress, Icon } from "antd"; import { Tooltip, Progress, Icon } from "antd";
import { formatter } from "@/utils/format"; import { formatter } from "@/utils/format";
import { formatUtcTimeToLocal } from "@/utils/utils";
import { formatMessage } from "umi/locale";
import { SearchEngineIcon } from "@/lib/search_engines";
import { HealthStatusView } from "@/components/infini/health_status_view"; import { HealthStatusView } from "@/components/infini/health_status_view";
import { StatusBlockGroup } from "@/components/infini/status_block"; import { StatusBlockGroup } from "@/components/infini/status_block";
import CommonTable from "../../components/CommonTable";
export default (props) => { export default (props) => {
const {
infos,
dataSource,
total,
from,
pageSize,
loading,
onPageChange,
onPageSizeChange,
onRowClick,
} = props;
const [tableData] = useMemo(() => {
let tableData = dataSource?.map((item) => {
const id = item?._source?.metadata?.node_id;
const metadata = item._source?.metadata || {};
const info = id && infos[id] ? infos[id] : {};
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;
const jvm_mem_total_in_bytes = summary?.jvm?.mem?.heap_max_in_bytes || 0;
const jvm_mem_used_in_bytes = summary?.jvm?.mem?.heap_used_in_bytes || 0;
const disk_percent =
fs_total_in_bytes > 0
? Math.round((fs_used_in_bytes / fs_total_in_bytes) * 100)
: 0;
const jvm_mem_percent =
jvm_mem_total_in_bytes > 0
? Math.round((jvm_mem_used_in_bytes / jvm_mem_total_in_bytes) * 100)
: 0;
const metrics_status = metrics?.status || {};
return {
id,
metadata,
summary,
metrics_status,
fs_total_in_bytes,
fs_available_in_bytes,
fs_used_in_bytes,
jvm_mem_total_in_bytes,
jvm_mem_used_in_bytes,
disk_percent,
jvm_mem_percent,
};
});
return [tableData];
}, [JSON.stringify(dataSource), JSON.stringify(infos)]);
const [columns] = useMemo(() => {
let columns = [
{
title: "Name",
dataIndex: "name",
render: (text, record) => {
return (
<Tooltip
placement="topLeft"
title={
<span>
Transport Address:{" "}
{record.metadata?.labels?.transport_address}
<br />
Cluster: {record.metadata?.cluster_name ?? ""}
<br />
Version: {record.metadata?.labels?.version ?? ""}
<br />
Roles:{" "}
{record.metadata?.labels?.roles
? record.metadata?.labels?.roles?.toString()
: ""}
</span>
}
>
<div style={{ display: "flex", alignContent: "center", gap: 5 }}>
<span>
{record.summary?.is_master_node ? (
<Icon type="star" theme="filled" />
) : (
<Icon type="database" />
)}
</span>
<span>{record.metadata?.node_name}</span>
</div>
</Tooltip>
);
},
},
{
title: "Status",
dataIndex: "status",
render: (text, record) => {
return (
<Tooltip
title={
<span
style={{
display: "flex",
flexDirection: "column",
gap: 5,
padding: 5,
}}
>
<StatusBlockGroup data={record.metrics_status?.data} />
<span>
{record.metrics_status?.metric?.label +
"(" +
(record.metrics_status?.data?.length || 14) +
" " +
record.metrics_status?.metric?.units +
")"}
</span>
</span>
}
>
<div>
<HealthStatusView status={record.metadata?.labels?.status} />
</div>
</Tooltip>
);
},
},
{
title: "Indices",
dataIndex: "Indices",
render: (text, record) => {
return record.summary?.shard_info?.indices_count || 0;
},
},
{
title: "Shards",
dataIndex: "Shards",
render: (text, record) => {
return record.summary?.shard_info?.shard_count || 0;
},
},
{
title: "Docs",
dataIndex: "Docs",
render: (text, record) => {
return (
<Tooltip
title={`Docs:${formatter.number(
record.summary?.indices?.docs?.count
)}`}
>
{formatter.numberToHuman(record.summary?.indices?.docs?.count)}
</Tooltip>
);
},
},
{
title: "Disk Usage",
dataIndex: "DiskUsage",
render: (text, record) => {
return (
<Tooltip
title={
<span>
Total:{formatter.bytes(record.fs_total_in_bytes)}
<br />
Used:{formatter.bytes(record.fs_used_in_bytes)}
<br />
Free:{formatter.bytes(record.fs_available_in_bytes)}
</span>
}
>
<Progress
strokeLinecap="square"
strokeColor="#558EF0"
strokeWidth={12}
percent={record.disk_percent}
format={(percent) => `${percent}%`}
/>
</Tooltip>
);
},
},
{
title: "JVM Heap",
dataIndex: "JVMHeap",
render: (text, record) => {
return (
<Tooltip
title={
<span>
Total:{formatter.bytes(record.jvm_mem_total_in_bytes)}
<br />
Used:{formatter.bytes(record.jvm_mem_used_in_bytes)}
<br />
Free:
{formatter.bytes(
record.jvm_mem_total_in_bytes - record.jvm_mem_used_in_bytes
)}
</span>
}
>
<Progress
strokeLinecap="square"
strokeColor="#00BFB3"
strokeWidth={12}
percent={record.jvm_mem_percent}
format={(percent) => `${percent}%`}
/>
</Tooltip>
);
},
},
];
return [columns];
}, []);
return ( return (
<div className="table-wrap"> <CommonTable
<Table {...props}
size={"small"} columns={[
loading={loading} {
columns={columns} title: "Name",
dataSource={tableData} dataIndex: "name",
rowKey={"id"} render: (text, record) => {
pagination={{ return (
size: "small", <Tooltip
total, placement="topLeft"
pageSize, title={
onChange: onPageChange, <span>
showSizeChanger: true, Transport Address:{" "}
onShowSizeChange: (_, size) => { {record.metadata?.labels?.transport_address}
onPageSizeChange(size); <br />
Cluster: {record.metadata?.cluster_name ?? ""}
<br />
Version: {record.metadata?.labels?.version ?? ""}
<br />
Roles:{" "}
{record.metadata?.labels?.roles
? record.metadata?.labels?.roles?.toString()
: ""}
</span>
}
>
<div style={{ display: "flex", alignContent: "center", gap: 5 }}>
<span>
{record.summary?.is_master_node ? (
<Icon type="star" theme="filled" />
) : (
<Icon type="database" />
)}
</span>
<span>{record.metadata?.node_name}</span>
</div>
</Tooltip>
);
}, },
showTotal: (total, range) => },
`${range[0]}-${range[1]} of ${total} items`, {
}} title: "Status",
onRow={(record, i) => { dataIndex: "status",
render: (text, record) => {
return (
<Tooltip
title={
<span
style={{
display: "flex",
flexDirection: "column",
gap: 5,
padding: 5,
}}
>
<StatusBlockGroup data={record.metrics_status?.data} />
<span>
{record.metrics_status?.metric?.label +
"(" +
(record.metrics_status?.data?.length || 14) +
" " +
record.metrics_status?.metric?.units +
")"}
</span>
</span>
}
>
<div>
<HealthStatusView status={record.metadata?.labels?.status} />
</div>
</Tooltip>
);
},
},
{
title: "Indices",
dataIndex: "Indices",
render: (text, record) => {
return record.summary?.shard_info?.indices_count || 0;
},
},
{
title: "Shards",
dataIndex: "Shards",
render: (text, record) => {
return record.summary?.shard_info?.shard_count || 0;
},
},
{
title: "Docs",
dataIndex: "Docs",
render: (text, record) => {
return (
<Tooltip
title={`Docs:${formatter.number(
record.summary?.indices?.docs?.count
)}`}
>
{formatter.numberToHuman(record.summary?.indices?.docs?.count)}
</Tooltip>
);
},
},
{
title: "Disk Usage",
dataIndex: "DiskUsage",
render: (text, record) => {
return (
<Tooltip
title={
<span>
Total:{formatter.bytes(record.fs_total_in_bytes)}
<br />
Used:{formatter.bytes(record.fs_used_in_bytes)}
<br />
Free:{formatter.bytes(record.fs_available_in_bytes)}
</span>
}
>
<Progress
strokeLinecap="square"
strokeColor="#558EF0"
strokeWidth={12}
percent={record.disk_percent}
format={(percent) => `${percent}%`}
/>
</Tooltip>
);
},
},
{
title: "JVM Heap",
dataIndex: "JVMHeap",
render: (text, record) => {
return (
<Tooltip
title={
<span>
Total:{formatter.bytes(record.jvm_mem_total_in_bytes)}
<br />
Used:{formatter.bytes(record.jvm_mem_used_in_bytes)}
<br />
Free:
{formatter.bytes(
record.jvm_mem_total_in_bytes - record.jvm_mem_used_in_bytes
)}
</span>
}
>
<Progress
strokeLinecap="square"
strokeColor="#00BFB3"
strokeWidth={12}
percent={record.jvm_mem_percent}
format={(percent) => `${percent}%`}
/>
</Tooltip>
);
},
},
]}
formatData={(dataSource, infos) => {
const newData = dataSource?.map((item) => {
const id = item?._source?.metadata?.node_id;
const metadata = item._source?.metadata || {};
const info = id && infos[id] ? infos[id] : {};
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;
const jvm_mem_total_in_bytes = summary?.jvm?.mem?.heap_max_in_bytes || 0;
const jvm_mem_used_in_bytes = summary?.jvm?.mem?.heap_used_in_bytes || 0;
const disk_percent =
fs_total_in_bytes > 0
? Math.round((fs_used_in_bytes / fs_total_in_bytes) * 100)
: 0;
const jvm_mem_percent =
jvm_mem_total_in_bytes > 0
? Math.round((jvm_mem_used_in_bytes / jvm_mem_total_in_bytes) * 100)
: 0;
const metrics_status = metrics?.status || {};
return { return {
onClick: (event) => { id,
onRowClick(dataSource[i]); metadata,
}, summary,
metrics_status,
fs_total_in_bytes,
fs_available_in_bytes,
fs_used_in_bytes,
jvm_mem_total_in_bytes,
jvm_mem_used_in_bytes,
disk_percent,
jvm_mem_percent,
}; };
}} });
/> return newData
</div> }}
/>
); );
}; };

View File

@ -0,0 +1,91 @@
import React, { useState, useEffect, useMemo } from "react";
import { Table, Tooltip, Progress } from "antd";
import { formatter } from "@/utils/format";
import { formatUtcTimeToLocal } from "@/utils/utils";
import { formatMessage } from "umi/locale";
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 {
dataSource,
total,
from,
pageSize,
loading,
onPageChange,
onPageSizeChange,
onRowClick,
infoAction,
formatData,
columns = [],
parentLoading
} = 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(() => {
if (!parentLoading) {
fetchListInfo(dataSource);
}
}, [JSON.stringify(dataSource), parentLoading])
const tableData = useMemo(() => {
return formatData(dataSource, infos);
}, [JSON.stringify(dataSource), JSON.stringify(infos)]);
return (
<div className="table-wrap">
<Table
size={"small"}
loading={loading}
columns={columns}
dataSource={tableData}
rowKey={"id"}
pagination={{
size: "small",
total,
pageSize,
onChange: onPageChange,
showSizeChanger: true,
onShowSizeChange: (_, size) => {
onPageSizeChange(size);
},
showTotal: (total, range) =>
`${range[0]}-${range[1]} of ${total} items`,
}}
onRow={(record, i) => {
return {
onClick: (event) => {
onRowClick(dataSource[i]);
},
};
}}
rowClassName={() => styles.rowPointer}
/>
</div>
);
};