mirror of
https://github.com/didi/KnowStreaming.git
synced 2025-12-24 11:52:08 +08:00
fix: 健康状态详情优化 & Connector 样式优化 & 无MM2任务指标兜底页
This commit is contained in:
@@ -36,7 +36,7 @@ export default (props: Props) => {
|
|||||||
const [disabled, setDisabled] = useState(true);
|
const [disabled, setDisabled] = useState(true);
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
Utils.request(api.getConnectors(clusterId))
|
Utils.request(api.getConnectClusters(clusterId))
|
||||||
.then((res: any[]) => {
|
.then((res: any[]) => {
|
||||||
res?.length && setDisabled(false);
|
res?.length && setDisabled(false);
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -94,28 +94,12 @@ const renderLine = (record: any, metricName: string) => {
|
|||||||
|
|
||||||
export const getConnectorsColumns = (arg?: any) => {
|
export const getConnectorsColumns = (arg?: any) => {
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
|
||||||
title: 'Connect集群',
|
|
||||||
dataIndex: 'connectClusterName',
|
|
||||||
key: 'connectClusterName',
|
|
||||||
width: 200,
|
|
||||||
fixed: 'left',
|
|
||||||
lineClampOne: true,
|
|
||||||
needTooltip: true,
|
|
||||||
// render: (t: string, r: any) => {
|
|
||||||
// return (
|
|
||||||
// <span>
|
|
||||||
// {t}
|
|
||||||
// {r?.status ? <Tag className="tag-success">Live</Tag> : <Tag className="tag-error">Down</Tag>}
|
|
||||||
// </span>
|
|
||||||
// );
|
|
||||||
// },
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: 'Connector Name',
|
title: 'Connector Name',
|
||||||
dataIndex: 'connectorName',
|
dataIndex: 'connectorName',
|
||||||
key: 'connectorName',
|
key: 'connectorName',
|
||||||
width: 160,
|
width: 160,
|
||||||
|
fixed: 'left',
|
||||||
lineClampOne: true,
|
lineClampOne: true,
|
||||||
render: (t: string, r: any) => {
|
render: (t: string, r: any) => {
|
||||||
return t ? (
|
return t ? (
|
||||||
@@ -135,6 +119,23 @@ export const getConnectorsColumns = (arg?: any) => {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: 'Connect集群',
|
||||||
|
dataIndex: 'connectClusterName',
|
||||||
|
key: 'connectClusterName',
|
||||||
|
width: 200,
|
||||||
|
lineClampOne: true,
|
||||||
|
needTooltip: true,
|
||||||
|
// render: (t: string, r: any) => {
|
||||||
|
// return (
|
||||||
|
// <span>
|
||||||
|
// {t}
|
||||||
|
// {r?.status ? <Tag className="tag-success">Live</Tag> : <Tag className="tag-error">Down</Tag>}
|
||||||
|
// </span>
|
||||||
|
// );
|
||||||
|
// },
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
title: 'State',
|
title: 'State',
|
||||||
dataIndex: 'state',
|
dataIndex: 'state',
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
import React, { useLayoutEffect, useState } from 'react';
|
||||||
|
import api from '@src/api';
|
||||||
|
import { Spin, Utils } from 'knowdesign';
|
||||||
|
import { useParams } from 'react-router-dom';
|
||||||
|
import NodataImg from '@src/assets/no-data.png';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
children: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NoConnector = () => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
height: 'calc(100vh - 118px)',
|
||||||
|
boxShadow: '0 2px 4px 0 rgba(0,0,0,0.01), 0 3px 6px 3px rgba(0,0,0,0.01), 0 2px 6px 0 rgba(0,0,0,0.03)',
|
||||||
|
borderRadius: 12,
|
||||||
|
background: '#fff',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img src={NodataImg} style={{ width: 100, height: 162 }} />
|
||||||
|
<span style={{ fontSize: 13, color: '#919AAC', paddingTop: 16 }}>暂无数据,请先创建 MM2 任务</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default (props: Props) => {
|
||||||
|
const { clusterId } = useParams<{
|
||||||
|
clusterId: string;
|
||||||
|
}>();
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [disabled, setDisabled] = useState(true);
|
||||||
|
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
Utils.request(api.getMirrorMakerMetadata(clusterId))
|
||||||
|
.then((res: any[]) => {
|
||||||
|
res?.length && setDisabled(false);
|
||||||
|
})
|
||||||
|
.finally(() => setLoading(false));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return disabled ? (
|
||||||
|
<Spin spinning={loading}>{loading ? <div style={{ height: 'calc(100vh - 118px)' }} /> : <NoConnector />}</Spin>
|
||||||
|
) : (
|
||||||
|
props.children
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { MetricType } from '@src/api';
|
||||||
|
import MirrorMakerCard from '@src/components/CardBar/MirrorMakerCard';
|
||||||
|
import DraggableCharts from '@src/components/DraggableCharts';
|
||||||
|
import DBreadcrumb from 'knowdesign/es/extend/d-breadcrumb';
|
||||||
|
import { AppContainer } from 'knowdesign';
|
||||||
|
import HasConnector from './HasConnector';
|
||||||
|
|
||||||
|
const MirrorMakerDashboard = (): JSX.Element => {
|
||||||
|
const [global] = AppContainer.useGlobalValue();
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="breadcrumb" style={{ marginBottom: '10px' }}>
|
||||||
|
<DBreadcrumb
|
||||||
|
breadcrumbs={[
|
||||||
|
{ label: '多集群管理', aHref: '/' },
|
||||||
|
{ label: global?.clusterInfo?.name, aHref: `/cluster/${global?.clusterInfo?.id}` },
|
||||||
|
{ label: 'Replication', aHref: `` },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<HasConnector>
|
||||||
|
<>
|
||||||
|
<MirrorMakerCard />
|
||||||
|
<DraggableCharts type={MetricType.MM2} />
|
||||||
|
</>
|
||||||
|
</HasConnector>
|
||||||
|
|
||||||
|
{/* <DraggableCharts type={MetricType.Broker} /> */}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MirrorMakerDashboard;
|
||||||
@@ -522,6 +522,7 @@ const ConnectorForm = (props: {
|
|||||||
const params = {
|
const params = {
|
||||||
...values,
|
...values,
|
||||||
id: initFieldsValue?.id,
|
id: initFieldsValue?.id,
|
||||||
|
jmxProperties: values.jmxProperties ? `{ "jmxProperties": "${values.jmxProperties}" }` : undefined,
|
||||||
};
|
};
|
||||||
Utils.put(api.batchConnectClusters, [params])
|
Utils.put(api.batchConnectClusters, [params])
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
@@ -542,7 +543,7 @@ const ConnectorForm = (props: {
|
|||||||
setSelectedTabKey(undefined);
|
setSelectedTabKey(undefined);
|
||||||
try {
|
try {
|
||||||
const jmxPortInfo = JSON.parse(initFieldsValue.jmxProperties) || {};
|
const jmxPortInfo = JSON.parse(initFieldsValue.jmxProperties) || {};
|
||||||
form.setFieldsValue({ ...initFieldsValue, jmxPort: jmxPortInfo.jmxPort });
|
form.setFieldsValue({ ...initFieldsValue, jmxProperties: jmxPortInfo.jmxProperties });
|
||||||
} catch {
|
} catch {
|
||||||
form.setFieldsValue({ ...initFieldsValue });
|
form.setFieldsValue({ ...initFieldsValue });
|
||||||
}
|
}
|
||||||
@@ -551,7 +552,7 @@ const ConnectorForm = (props: {
|
|||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
try {
|
try {
|
||||||
const jmxPortInfo = JSON.parse(initFieldsValue.jmxProperties) || {};
|
const jmxPortInfo = JSON.parse(initFieldsValue.jmxProperties) || {};
|
||||||
form.setFieldsValue({ ...initFieldsValue, jmxPort: jmxPortInfo.jmxPort });
|
form.setFieldsValue({ ...initFieldsValue, jmxProperties: jmxPortInfo.jmxProperties });
|
||||||
} catch {
|
} catch {
|
||||||
form.setFieldsValue({ ...initFieldsValue });
|
form.setFieldsValue({ ...initFieldsValue });
|
||||||
}
|
}
|
||||||
@@ -626,7 +627,7 @@ const ConnectorForm = (props: {
|
|||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item name="jmxPort" label="JMX Port" style={{ width: 202 }}>
|
<Form.Item name="jmxProperties" label="JMX Port" style={{ width: 202 }}>
|
||||||
<InputNumber min={0} max={99999} style={{ width: 202 }} />
|
<InputNumber min={0} max={99999} style={{ width: 202 }} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { message } from 'knowdesign';
|
||||||
|
import { HeartTwoTone } from '@ant-design/icons';
|
||||||
|
|
||||||
|
const AccessClusterConfig = () => {
|
||||||
|
const [count, setCount] = useState<number>(1);
|
||||||
|
|
||||||
|
const setErgeModal = () => {
|
||||||
|
if (count >= 50) {
|
||||||
|
message.success({
|
||||||
|
content: 'Erge',
|
||||||
|
icon: <HeartTwoTone />,
|
||||||
|
});
|
||||||
|
setCount(1);
|
||||||
|
} else {
|
||||||
|
setCount(count + 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return <div className="multi-cluster-erge" onClick={setErgeModal} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AccessClusterConfig;
|
||||||
@@ -6,6 +6,7 @@ import TourGuide, { MultiPageSteps } from '@src/components/TourGuide';
|
|||||||
import { healthSorceList, sliderValueMap, sortFieldList, sortTypes, statusFilters } from './config';
|
import { healthSorceList, sliderValueMap, sortFieldList, sortTypes, statusFilters } from './config';
|
||||||
import ClusterList from './List';
|
import ClusterList from './List';
|
||||||
import AccessClusters from './AccessCluster';
|
import AccessClusters from './AccessCluster';
|
||||||
|
import AccessCluster from './AccessClusterConfig';
|
||||||
import CustomCheckGroup from './CustomCheckGroup';
|
import CustomCheckGroup from './CustomCheckGroup';
|
||||||
import { ClustersPermissionMap } from '../CommonConfig';
|
import { ClustersPermissionMap } from '../CommonConfig';
|
||||||
import './index.less';
|
import './index.less';
|
||||||
@@ -359,6 +360,7 @@ const MultiClusterPage = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<AccessCluster />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="multi-cluster-page-dashboard">
|
<div className="multi-cluster-page-dashboard">
|
||||||
|
|||||||
@@ -343,6 +343,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.multi-cluster-erge {
|
||||||
|
position: absolute;
|
||||||
|
width: 15px;
|
||||||
|
height: 15px;
|
||||||
|
top: 100px;
|
||||||
|
left: 20px;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
&-dashboard {
|
&-dashboard {
|
||||||
& > .dcloud-spin-nested-loading > .dcloud-spin-container::after {
|
& > .dcloud-spin-nested-loading > .dcloud-spin-container::after {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ const CheckDetail = forwardRef((props: any, ref): JSX.Element => {
|
|||||||
const getHealthDetail = () => {
|
const getHealthDetail = () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
return Utils.request(API.getResourceListHealthDetail(+clusterId)).then((res: any) => {
|
return Utils.request(API.getResourceListHealthDetail(+clusterId)).then((res: any) => {
|
||||||
|
res.sort((a: any, b: any) => a.dimension - b.dimension);
|
||||||
setData(res);
|
setData(res);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -40,6 +40,10 @@ export const dimensionMap = {
|
|||||||
label: 'Connector',
|
label: 'Connector',
|
||||||
href: '/connect/connectors',
|
href: '/connect/connectors',
|
||||||
},
|
},
|
||||||
|
7: {
|
||||||
|
label: 'MirrorMaker',
|
||||||
|
href: '/replication',
|
||||||
|
},
|
||||||
} as any;
|
} as any;
|
||||||
|
|
||||||
const toLowerCase = (name = '') => {
|
const toLowerCase = (name = '') => {
|
||||||
@@ -95,6 +99,18 @@ const CONFIG_ITEM_DETAIL_DESC = {
|
|||||||
ConnectorUnassignedTaskCount: (valueGroup: any) => {
|
ConnectorUnassignedTaskCount: (valueGroup: any) => {
|
||||||
return `未被分配的任务数量 小于 ${valueGroup?.value}`;
|
return `未被分配的任务数量 小于 ${valueGroup?.value}`;
|
||||||
},
|
},
|
||||||
|
MirrorMakerFailedTaskCount: (valueGroup: any) => {
|
||||||
|
return `失败状态的任务数量 小于 ${valueGroup?.value}`;
|
||||||
|
},
|
||||||
|
MirrorMakerUnassignedTaskCount: (valueGroup: any) => {
|
||||||
|
return `未被分配的任务数量 小于 ${valueGroup?.value}`;
|
||||||
|
},
|
||||||
|
ReplicationLatencyMsMax: (valueGroup: any) => {
|
||||||
|
return `消息复制最大延迟时间 小于 ${valueGroup?.value}`;
|
||||||
|
},
|
||||||
|
'TotalRecord-errors': (valueGroup: any) => {
|
||||||
|
return `消息处理错误的次数 增量小于 ${valueGroup?.value}`;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getConfigItemDetailDesc = (item: keyof typeof CONFIG_ITEM_DETAIL_DESC, valueGroup: any) => {
|
export const getConfigItemDetailDesc = (item: keyof typeof CONFIG_ITEM_DETAIL_DESC, valueGroup: any) => {
|
||||||
@@ -409,6 +425,42 @@ export const getHealthySettingColumn = (form: any, data: any, clusterId: string)
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
case 'MirrorMakerFailedTaskCount': {
|
||||||
|
return (
|
||||||
|
<div className="table-form-item">
|
||||||
|
<span className="left-text">{'>'}</span>
|
||||||
|
{getFormItem({ configItem, attrs: { min: 0, max: 99998 } })}
|
||||||
|
<span className="right-text">则不通过</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case 'MirrorMakerUnassignedTaskCount': {
|
||||||
|
return (
|
||||||
|
<div className="table-form-item">
|
||||||
|
<span className="left-text">{'>'}</span>
|
||||||
|
{getFormItem({ configItem, attrs: { min: 0, max: 99998 } })}
|
||||||
|
<span className="right-text">则不通过</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case 'ReplicationLatencyMsMax': {
|
||||||
|
return (
|
||||||
|
<div className="table-form-item">
|
||||||
|
<span className="left-text">{'>'}</span>
|
||||||
|
{getFormItem({ configItem, attrs: { min: 0, max: 99998 } })}
|
||||||
|
<span className="right-text">则不通过</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case 'TotalRecord-errors': {
|
||||||
|
return (
|
||||||
|
<div className="table-form-item">
|
||||||
|
<span className="left-text">{'>'}</span>
|
||||||
|
{getFormItem({ configItem, attrs: { min: 0, max: 99998 } })}
|
||||||
|
<span className="right-text">则不通过</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user