[ISSUE #330] Format code and update the doc (#334)

This commit is contained in:
Crazylychee
2025-07-05 20:50:36 +08:00
committed by GitHub
parent 706082c62f
commit ff73529a75
85 changed files with 1012 additions and 906 deletions

View File

@@ -6,19 +6,14 @@ This project was bootstrapped with [Create React App](https://github.com/faceboo
In the project directory, you can run: In the project directory, you can run:
### `npm start` ### `npm run start`
Runs the app in the development mode.\ Runs the app in the development mode.\
Open [http://localhost:3000](http://localhost:3000) to view it in your browser. Open [http://localhost:3003](http://localhost:3000) to view it in your browser.
The page will reload when you make changes.\ The page will reload when you make changes.\
You may also see any lint errors in the console. You may also see any lint errors in the console.
### `npm test`
Launches the test runner in the interactive watch mode.\
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
### `npm run build` ### `npm run build`
Builds the app for production to the `build` folder.\ Builds the app for production to the `build` folder.\

View File

@@ -18,13 +18,13 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8"/>
<link rel="shortcut icon" href="./favicon.ico" type="image/x-icon" /> <link rel="shortcut icon" href="./favicon.ico" type="image/x-icon"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta name="description" content="" /> <meta name="description" content=""/>
<meta name="keywords" content="" /> <meta name="keywords" content=""/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<title>RocketMQ Dashboard</title> <title>RocketMQ Dashboard</title>
</head> </head>
<body> <body>
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>

View File

@@ -17,19 +17,19 @@
import React from 'react'; import React from 'react';
import AppRouter from './router'; // 你 router/index.jsx 导出的组件 import AppRouter from './router'; // 你 router/index.jsx 导出的组件
import { ToastContainer } from 'react-toastify'; import {ToastContainer} from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css'; import 'react-toastify/dist/ReactToastify.css';
import {ConfigProvider} from "antd"; import {ConfigProvider} from "antd";
import {useTheme} from "./store/context/ThemeContext"; import {useTheme} from "./store/context/ThemeContext";
function App() { function App() {
const {currentTheme} = useTheme(); const {currentTheme} = useTheme();
return ( return (
<> <>
<ConfigProvider theme={currentTheme}> <ConfigProvider theme={currentTheme}>
<ToastContainer /> <ToastContainer/>
<AppRouter /> <AppRouter/>
</ConfigProvider> </ConfigProvider>
</> </>
); );

View File

@@ -15,11 +15,11 @@
* limitations under the License. * limitations under the License.
*/ */
import { render, screen } from '@testing-library/react'; import {render, screen} from '@testing-library/react';
import App from './App'; import App from './App';
test('renders learn react link', () => { test('renders learn react link', () => {
render(<App />); render(<App/>);
const linkElement = screen.getByText(/learn react/i); const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument(); expect(linkElement).toBeInTheDocument();
}); });

View File

@@ -16,20 +16,20 @@
*/ */
import React from 'react'; import React from 'react';
import { Form, Input, Typography, Modal } from 'antd'; import {Form, Input, Typography} from 'antd';
import moment from 'moment'; import moment from 'moment';
import { useLanguage } from '../i18n/LanguageContext'; // 根据实际路径调整 import {useLanguage} from '../i18n/LanguageContext'; // 根据实际路径调整
const { Text } = Typography; const {Text} = Typography;
const DlqMessageDetailViewDialog = ({ ngDialogData }) => { const DlqMessageDetailViewDialog = ({ngDialogData}) => {
const { t } = useLanguage(); const {t} = useLanguage();
const messageView = ngDialogData?.messageView || {}; const messageView = ngDialogData?.messageView || {};
return ( return (
<div style={{ padding: '20px' }}> <div style={{padding: '20px'}}>
<Form layout="horizontal" labelCol={{ span: 4 }} wrapperCol={{ span: 20 }}> <Form layout="horizontal" labelCol={{span: 4}} wrapperCol={{span: 20}}>
<Form.Item label="Message ID:"> <Form.Item label="Message ID:">
<Text strong>{messageView.msgId}</Text> <Text strong>{messageView.msgId}</Text>
</Form.Item> </Form.Item>
@@ -39,7 +39,7 @@ const DlqMessageDetailViewDialog = ({ ngDialogData }) => {
<Form.Item label="Properties:"> <Form.Item label="Properties:">
<Input.TextArea <Input.TextArea
value={typeof messageView.properties === 'object' ? JSON.stringify(messageView.properties, null, 2) : messageView.properties} value={typeof messageView.properties === 'object' ? JSON.stringify(messageView.properties, null, 2) : messageView.properties}
style={{ minHeight: 100, resize: 'none' }} style={{minHeight: 100, resize: 'none'}}
readOnly readOnly
/> />
</Form.Item> </Form.Item>
@@ -61,7 +61,7 @@ const DlqMessageDetailViewDialog = ({ ngDialogData }) => {
<Form.Item label="Message body:"> <Form.Item label="Message body:">
<Input.TextArea <Input.TextArea
value={messageView.messageBody} value={messageView.messageBody}
style={{ minHeight: 100, resize: 'none' }} style={{minHeight: 100, resize: 'none'}}
readOnly readOnly
/> />
</Form.Item> </Form.Item>

View File

@@ -16,16 +16,16 @@
*/ */
import React from 'react'; import React from 'react';
import { Modal, Button, Typography, Descriptions, Tag, Spin, notification } from 'antd'; import {Button, Descriptions, Modal, notification, Spin, Tag, Typography} from 'antd';
import moment from 'moment'; import moment from 'moment';
import { ExclamationCircleOutlined, SyncOutlined } from '@ant-design/icons'; import {SyncOutlined} from '@ant-design/icons';
import { useLanguage } from '../i18n/LanguageContext'; import {useLanguage} from '../i18n/LanguageContext';
import { remoteApi } from '../api/remoteApi/remoteApi'; // 确保这个路径正确 import {remoteApi} from '../api/remoteApi/remoteApi'; // 确保这个路径正确
const { Text, Paragraph } = Typography; const {Text, Paragraph} = Typography;
const MessageDetailViewDialog = ({ visible, onCancel, messageId, topic, onResendMessage }) => { const MessageDetailViewDialog = ({visible, onCancel, messageId, topic, onResendMessage}) => {
const { t } = useLanguage(); const {t} = useLanguage();
const [loading, setLoading] = React.useState(true); const [loading, setLoading] = React.useState(true);
const [messageDetail, setMessageDetail] = React.useState(null); const [messageDetail, setMessageDetail] = React.useState(null);
const [error, setError] = React.useState(null); const [error, setError] = React.useState(null);
@@ -89,17 +89,21 @@ const MessageDetailViewDialog = ({ visible, onCancel, messageId, topic, onResend
> >
<Spin spinning={loading} tip={t.LOADING}> <Spin spinning={loading} tip={t.LOADING}>
{error && ( {error && (
<Paragraph type="danger" style={{ textAlign: 'center' }}> <Paragraph type="danger" style={{textAlign: 'center'}}>
{error} {error}
</Paragraph> </Paragraph>
)} )}
{messageDetail ? ( // 确保 messageDetail 存在时才渲染内容 {messageDetail ? ( // 确保 messageDetail 存在时才渲染内容
<> <>
{/* 消息信息部分 */} {/* 消息信息部分 */}
<Descriptions title={<Text strong>{t.MESSAGE_INFO}</Text>} bordered column={2} size="small" style={{ marginBottom: 20 }}> <Descriptions title={<Text strong>{t.MESSAGE_INFO}</Text>} bordered column={2} size="small"
<Descriptions.Item label="Topic" span={2}><Text copyable>{messageDetail.messageView.topic}</Text></Descriptions.Item> style={{marginBottom: 20}}>
<Descriptions.Item label="Message ID" span={2}><Text copyable>{messageDetail.messageView.msgId}</Text></Descriptions.Item> <Descriptions.Item label="Topic" span={2}><Text
<Descriptions.Item label="StoreHost">{messageDetail.messageView.storeHost}</Descriptions.Item> copyable>{messageDetail.messageView.topic}</Text></Descriptions.Item>
<Descriptions.Item label="Message ID" span={2}><Text
copyable>{messageDetail.messageView.msgId}</Text></Descriptions.Item>
<Descriptions.Item
label="StoreHost">{messageDetail.messageView.storeHost}</Descriptions.Item>
<Descriptions.Item label="BornHost">{messageDetail.messageView.bornHost}</Descriptions.Item> <Descriptions.Item label="BornHost">{messageDetail.messageView.bornHost}</Descriptions.Item>
<Descriptions.Item label="StoreTime"> <Descriptions.Item label="StoreTime">
{moment(messageDetail.messageView.storeTimestamp).format("YYYY-MM-DD HH:mm:ss")} {moment(messageDetail.messageView.storeTimestamp).format("YYYY-MM-DD HH:mm:ss")}
@@ -108,26 +112,33 @@ const MessageDetailViewDialog = ({ visible, onCancel, messageId, topic, onResend
{moment(messageDetail.messageView.bornTimestamp).format("YYYY-MM-DD HH:mm:ss")} {moment(messageDetail.messageView.bornTimestamp).format("YYYY-MM-DD HH:mm:ss")}
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label="Queue ID">{messageDetail.messageView.queueId}</Descriptions.Item> <Descriptions.Item label="Queue ID">{messageDetail.messageView.queueId}</Descriptions.Item>
<Descriptions.Item label="Queue Offset">{messageDetail.messageView.queueOffset}</Descriptions.Item> <Descriptions.Item
<Descriptions.Item label="StoreSize">{messageDetail.messageView.storeSize} bytes</Descriptions.Item> label="Queue Offset">{messageDetail.messageView.queueOffset}</Descriptions.Item>
<Descriptions.Item label="ReconsumeTimes">{messageDetail.messageView.reconsumeTimes}</Descriptions.Item> <Descriptions.Item
label="StoreSize">{messageDetail.messageView.storeSize} bytes</Descriptions.Item>
<Descriptions.Item
label="ReconsumeTimes">{messageDetail.messageView.reconsumeTimes}</Descriptions.Item>
<Descriptions.Item label="BodyCRC">{messageDetail.messageView.bodyCRC}</Descriptions.Item> <Descriptions.Item label="BodyCRC">{messageDetail.messageView.bodyCRC}</Descriptions.Item>
<Descriptions.Item label="SysFlag">{messageDetail.messageView.sysFlag}</Descriptions.Item> <Descriptions.Item label="SysFlag">{messageDetail.messageView.sysFlag}</Descriptions.Item>
<Descriptions.Item label="Flag">{messageDetail.messageView.flag}</Descriptions.Item> <Descriptions.Item label="Flag">{messageDetail.messageView.flag}</Descriptions.Item>
<Descriptions.Item label="PreparedTransactionOffset">{messageDetail.messageView.preparedTransactionOffset}</Descriptions.Item> <Descriptions.Item
label="PreparedTransactionOffset">{messageDetail.messageView.preparedTransactionOffset}</Descriptions.Item>
</Descriptions> </Descriptions>
{/* 消息属性部分 */} {/* 消息属性部分 */}
{Object.keys(messageDetail.messageView.properties).length > 0 && ( {Object.keys(messageDetail.messageView.properties).length > 0 && (
<Descriptions title={<Text strong>{t.MESSAGE_PROPERTIES}</Text>} bordered column={1} size="small" style={{ marginBottom: 20 }}> <Descriptions title={<Text strong>{t.MESSAGE_PROPERTIES}</Text>} bordered column={1}
size="small" style={{marginBottom: 20}}>
{Object.entries(messageDetail.messageView.properties).map(([key, value]) => ( {Object.entries(messageDetail.messageView.properties).map(([key, value]) => (
<Descriptions.Item label={key} key={key}><Text copyable>{value}</Text></Descriptions.Item> <Descriptions.Item label={key} key={key}><Text
copyable>{value}</Text></Descriptions.Item>
))} ))}
</Descriptions> </Descriptions>
)} )}
{/* 消息体部分 */} {/* 消息体部分 */}
<Descriptions title={<Text strong>{t.MESSAGE_BODY}</Text>} bordered column={1} size="small" style={{ marginBottom: 20 }}> <Descriptions title={<Text strong>{t.MESSAGE_BODY}</Text>} bordered column={1} size="small"
style={{marginBottom: 20}}>
<Descriptions.Item> <Descriptions.Item>
<Paragraph <Paragraph
copyable copyable
@@ -146,9 +157,10 @@ const MessageDetailViewDialog = ({ visible, onCancel, messageId, topic, onResend
{messageDetail.messageTrackList && messageDetail.messageTrackList.length > 0 ? ( {messageDetail.messageTrackList && messageDetail.messageTrackList.length > 0 ? (
<> <>
<Text strong>{t.MESSAGE_TRACKING}</Text> <Text strong>{t.MESSAGE_TRACKING}</Text>
<div style={{ marginTop: 10 }}> <div style={{marginTop: 10}}>
{messageDetail.messageTrackList.map((track, index) => ( {messageDetail.messageTrackList.map((track, index) => (
<Descriptions bordered column={1} size="small" key={index} style={{ marginBottom: 15 }}> <Descriptions bordered column={1} size="small" key={index}
style={{marginBottom: 15}}>
<Descriptions.Item label={t.CONSUMER_GROUP}> <Descriptions.Item label={t.CONSUMER_GROUP}>
{track.consumerGroup} {track.consumerGroup}
</Descriptions.Item> </Descriptions.Item>
@@ -165,10 +177,10 @@ const MessageDetailViewDialog = ({ visible, onCancel, messageId, topic, onResend
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label={t.OPERATION}> <Descriptions.Item label={t.OPERATION}>
<Button <Button
icon={<SyncOutlined />} icon={<SyncOutlined/>}
onClick={() => onResendMessage(messageDetail.messageView, track.consumerGroup)} onClick={() => onResendMessage(messageDetail.messageView, track.consumerGroup)}
size="small" size="small"
style={{ marginRight: 8 }} style={{marginRight: 8}}
> >
{t.RESEND_MESSAGE} {t.RESEND_MESSAGE}
</Button> </Button>
@@ -181,7 +193,10 @@ const MessageDetailViewDialog = ({ visible, onCancel, messageId, topic, onResend
ellipsis={{ ellipsis={{
rows: 2, // 默认显示2行 rows: 2, // 默认显示2行
expandable: true, expandable: true,
symbol: <Text style={{ color: '#1890ff', cursor: 'pointer' }}>{t.READ_MORE}</Text>, // 蓝色展开文本 symbol: <Text style={{
color: '#1890ff',
cursor: 'pointer'
}}>{t.READ_MORE}</Text>, // 蓝色展开文本
}} }}
> >
{track.exceptionDesc} {track.exceptionDesc}
@@ -198,7 +213,8 @@ const MessageDetailViewDialog = ({ visible, onCancel, messageId, topic, onResend
</> </>
) : ( ) : (
// 当 messageDetail 为 null 时,可以显示一个占位符或者不显示内容 // 当 messageDetail 为 null 时,可以显示一个占位符或者不显示内容
!loading && !error && <Paragraph style={{ textAlign: 'center' }}>{t.NO_MESSAGE_DETAIL_AVAILABLE}</Paragraph> !loading && !error &&
<Paragraph style={{textAlign: 'center'}}>{t.NO_MESSAGE_DETAIL_AVAILABLE}</Paragraph>
)} )}
</Spin> </Spin>
</Modal> </Modal>

View File

@@ -15,15 +15,15 @@
* limitations under the License. * limitations under the License.
*/ */
import React, { useEffect, useRef } from 'react'; import React, {useEffect, useRef} from 'react';
import { Form, Input, Typography, Collapse, Table, Tag } from 'antd'; import {Collapse, Form, Input, Table, Tag, Typography} from 'antd';
import moment from 'moment'; import moment from 'moment';
import { useLanguage } from '../i18n/LanguageContext'; import {useLanguage} from '../i18n/LanguageContext';
import Paragraph from "antd/es/skeleton/Paragraph"; import Paragraph from "antd/es/skeleton/Paragraph";
import * as echarts from 'echarts'; // Import ECharts import * as echarts from 'echarts'; // Import ECharts
const { Text } = Typography; const {Text} = Typography;
const { Panel } = Collapse; const {Panel} = Collapse;
// Constants for styling and formatting, derived from the example // Constants for styling and formatting, derived from the example
const SUCCESS_COLOR = '#75d874'; const SUCCESS_COLOR = '#75d874';
@@ -36,8 +36,8 @@ const TIME_FORMAT_PATTERN = "YYYY-MM-DD HH:mm:ss.SSS";
const DEFAULT_DISPLAY_DURATION = 10 * 1000; const DEFAULT_DISPLAY_DURATION = 10 * 1000;
const TRANSACTION_CHECK_COST_TIME = 50; // transactionTraceNode do not have costTime, assume it cost 50ms const TRANSACTION_CHECK_COST_TIME = 50; // transactionTraceNode do not have costTime, assume it cost 50ms
const MessageTraceDetailViewDialog = ({ ngDialogData }) => { const MessageTraceDetailViewDialog = ({ngDialogData}) => {
const { t } = useLanguage(); const {t} = useLanguage();
const messageTraceGraphRef = useRef(null); const messageTraceGraphRef = useRef(null);
const producerNode = ngDialogData?.producerNode; const producerNode = ngDialogData?.producerNode;
@@ -125,6 +125,7 @@ const MessageTraceDetailViewDialog = ({ ngDialogData }) => {
} }
return `Cost Time: ${formatCostTimeStr(costTime)}<br/>` return `Cost Time: ${formatCostTimeStr(costTime)}<br/>`
} }
function buildTimeStamp(timestamp) { function buildTimeStamp(timestamp) {
if (timestamp < 0) { if (timestamp < 0) {
return 'N/A'; return 'N/A';
@@ -323,94 +324,181 @@ const MessageTraceDetailViewDialog = ({ ngDialogData }) => {
// ... (rest of your existing component code) // ... (rest of your existing component code)
const transactionColumns = [ const transactionColumns = [
{ title: t.TIMESTAMP, dataIndex: 'beginTimestamp', key: 'beginTimestamp', align: 'center', render: (text) => moment(text).format('YYYY-MM-DD HH:mm:ss.SSS') }, {
{ title: t.TRANSACTION_STATE, dataIndex: 'transactionState', key: 'transactionState', align: 'center', render: (text) => <Tag color={text === 'COMMIT_MESSAGE' ? 'green' : (text === 'ROLLBACK_MESSAGE' ? 'red' : 'default')}>{text}</Tag> }, title: t.TIMESTAMP,
{ title: t.FROM_TRANSACTION_CHECK, dataIndex: 'fromTransactionCheck', key: 'fromTransactionCheck', align: 'center', render: (text) => (text ? <Tag color="blue">{t.YES}</Tag> : <Tag color="purple">{t.NO}</Tag>) }, dataIndex: 'beginTimestamp',
{ title: t.CLIENT_HOST, dataIndex: 'clientHost', key: 'clientHost', align: 'center' }, key: 'beginTimestamp',
{ title: t.STORE_HOST, dataIndex: 'storeHost', key: 'storeHost', align: 'center' }, align: 'center',
render: (text) => moment(text).format('YYYY-MM-DD HH:mm:ss.SSS')
},
{
title: t.TRANSACTION_STATE,
dataIndex: 'transactionState',
key: 'transactionState',
align: 'center',
render: (text) => <Tag
color={text === 'COMMIT_MESSAGE' ? 'green' : (text === 'ROLLBACK_MESSAGE' ? 'red' : 'default')}>{text}</Tag>
},
{
title: t.FROM_TRANSACTION_CHECK,
dataIndex: 'fromTransactionCheck',
key: 'fromTransactionCheck',
align: 'center',
render: (text) => (text ? <Tag color="blue">{t.YES}</Tag> : <Tag color="purple">{t.NO}</Tag>)
},
{title: t.CLIENT_HOST, dataIndex: 'clientHost', key: 'clientHost', align: 'center'},
{title: t.STORE_HOST, dataIndex: 'storeHost', key: 'storeHost', align: 'center'},
]; ];
const consumeColumns = [ const consumeColumns = [
{ title: t.BEGIN_TIMESTAMP, dataIndex: 'beginTimestamp', key: 'beginTimestamp', align: 'center', render: (text) => text < 0 ? 'N/A' : moment(text).format('YYYY-MM-DD HH:mm:ss.SSS') }, {
{ title: t.END_TIMESTAMP, dataIndex: 'endTimestamp', key: 'endTimestamp', align: 'center', render: (text) => text < 0 ? 'N/A' : moment(text).format('YYYY-MM-DD HH:mm:ss.SSS') }, title: t.BEGIN_TIMESTAMP,
{ title: t.COST_TIME, dataIndex: 'costTime', key: 'costTime', align: 'center', render: (text) => text < 0 ? 'N/A' : `${text === 0 ? '<1' : text}ms` }, dataIndex: 'beginTimestamp',
{ title: t.STATUS, dataIndex: 'status', key: 'status', align: 'center', render: (text) => <Tag color={text === 'SUCCESS' ? 'green' : (text === 'FAILED' ? 'red' : 'default')}>{text}</Tag> }, key: 'beginTimestamp',
{ title: t.RETRY_TIMES, dataIndex: 'retryTimes', key: 'retryTimes', align: 'center', render: (text) => text < 0 ? 'N/A' : text }, align: 'center',
{ title: t.CLIENT_HOST, dataIndex: 'clientHost', key: 'clientHost', align: 'center' }, render: (text) => text < 0 ? 'N/A' : moment(text).format('YYYY-MM-DD HH:mm:ss.SSS')
{ title: t.STORE_HOST, dataIndex: 'storeHost', key: 'storeHost', align: 'center' }, },
{
title: t.END_TIMESTAMP,
dataIndex: 'endTimestamp',
key: 'endTimestamp',
align: 'center',
render: (text) => text < 0 ? 'N/A' : moment(text).format('YYYY-MM-DD HH:mm:ss.SSS')
},
{
title: t.COST_TIME,
dataIndex: 'costTime',
key: 'costTime',
align: 'center',
render: (text) => text < 0 ? 'N/A' : `${text === 0 ? '<1' : text}ms`
},
{
title: t.STATUS,
dataIndex: 'status',
key: 'status',
align: 'center',
render: (text) => <Tag
color={text === 'SUCCESS' ? 'green' : (text === 'FAILED' ? 'red' : 'default')}>{text}</Tag>
},
{
title: t.RETRY_TIMES,
dataIndex: 'retryTimes',
key: 'retryTimes',
align: 'center',
render: (text) => text < 0 ? 'N/A' : text
},
{title: t.CLIENT_HOST, dataIndex: 'clientHost', key: 'clientHost', align: 'center'},
{title: t.STORE_HOST, dataIndex: 'storeHost', key: 'storeHost', align: 'center'},
]; ];
return ( return (
<div style={{ padding: '20px', backgroundColor: '#f0f2f5' }}> <div style={{padding: '20px', backgroundColor: '#f0f2f5'}}>
<div style={{ marginBottom: '20px', borderRadius: '8px', overflow: 'hidden', boxShadow: '0 4px 12px rgba(0, 0, 0, 0.08)' }}> <div style={{
marginBottom: '20px',
borderRadius: '8px',
overflow: 'hidden',
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.08)'
}}>
<Collapse defaultActiveKey={['messageTraceGraph']} expandIconPosition="right"> <Collapse defaultActiveKey={['messageTraceGraph']} expandIconPosition="right">
<Panel header={<Typography.Title level={3} style={{ margin: 0, color: '#333' }}>{t.MESSAGE_TRACE_GRAPH}</Typography.Title>} key="messageTraceGraph"> <Panel header={<Typography.Title level={3} style={{
<div ref={messageTraceGraphRef} style={{ height: 500, width: '100%', backgroundColor: '#fff', padding: '10px' }}> margin: 0,
color: '#333'
}}>{t.MESSAGE_TRACE_GRAPH}</Typography.Title>} key="messageTraceGraph">
<div ref={messageTraceGraphRef}
style={{height: 500, width: '100%', backgroundColor: '#fff', padding: '10px'}}>
{/* ECharts message trace graph will be rendered here */} {/* ECharts message trace graph will be rendered here */}
{(!producerNode && subscriptionNodeList.length === 0) && ( {(!producerNode && subscriptionNodeList.length === 0) && (
<Text type="secondary" style={{ display: 'block', textAlign: 'center', marginTop: '150px' }}>{t.TRACE_GRAPH_PLACEHOLDER}</Text> <Text type="secondary" style={{
display: 'block',
textAlign: 'center',
marginTop: '150px'
}}>{t.TRACE_GRAPH_PLACEHOLDER}</Text>
)} )}
</div> </div>
</Panel> </Panel>
</Collapse> </Collapse>
</div> </div>
<div style={{ marginBottom: '20px', borderRadius: '8px', overflow: 'hidden', boxShadow: '0 4px 12px rgba(0, 0, 0, 0.08)' }}> <div style={{
marginBottom: '20px',
borderRadius: '8px',
overflow: 'hidden',
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.08)'
}}>
<Collapse defaultActiveKey={['sendMessageTrace']} expandIconPosition="right"> <Collapse defaultActiveKey={['sendMessageTrace']} expandIconPosition="right">
<Panel header={<Typography.Title level={3} style={{ margin: 0, color: '#333' }}>{t.SEND_MESSAGE_TRACE}</Typography.Title>} key="sendMessageTrace"> <Panel header={<Typography.Title level={3} style={{
margin: 0,
color: '#333'
}}>{t.SEND_MESSAGE_TRACE}</Typography.Title>} key="sendMessageTrace">
{!producerNode ? ( {!producerNode ? (
<Paragraph style={{ padding: '16px', textAlign: 'center', color: '#666' }}>{t.NO_PRODUCER_TRACE_DATA}</Paragraph> <Paragraph style={{
padding: '16px',
textAlign: 'center',
color: '#666'
}}>{t.NO_PRODUCER_TRACE_DATA}</Paragraph>
) : ( ) : (
<div style={{ padding: '16px', backgroundColor: '#fff' }}> <div style={{padding: '16px', backgroundColor: '#fff'}}>
<Typography.Title level={4} style={{ marginBottom: '20px' }}> <Typography.Title level={4} style={{marginBottom: '20px'}}>
{t.SEND_MESSAGE_INFO} : ( {t.MESSAGE_ID} <Text strong copyable>{producerNode.msgId}</Text> ) {t.SEND_MESSAGE_INFO} : ( {t.MESSAGE_ID} <Text strong
copyable>{producerNode.msgId}</Text> )
</Typography.Title> </Typography.Title>
<Form layout="vertical" colon={false}> <Form layout="vertical" colon={false}>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))', gap: '16px' }}> <div style={{
display: 'grid',
gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))',
gap: '16px'
}}>
<Form.Item label={<Text strong>{t.TOPIC}</Text>}> <Form.Item label={<Text strong>{t.TOPIC}</Text>}>
<Input value={producerNode.topic} readOnly /> <Input value={producerNode.topic} readOnly/>
</Form.Item> </Form.Item>
<Form.Item label={<Text strong>{t.PRODUCER_GROUP}</Text>}> <Form.Item label={<Text strong>{t.PRODUCER_GROUP}</Text>}>
<Input value={producerNode.groupName} readOnly /> <Input value={producerNode.groupName} readOnly/>
</Form.Item> </Form.Item>
<Form.Item label={<Text strong>{t.MESSAGE_KEY}</Text>}> <Form.Item label={<Text strong>{t.MESSAGE_KEY}</Text>}>
<Input value={producerNode.keys} readOnly /> <Input value={producerNode.keys} readOnly/>
</Form.Item> </Form.Item>
<Form.Item label={<Text strong>{t.TAG}</Text>}> <Form.Item label={<Text strong>{t.TAG}</Text>}>
<Input value={producerNode.tags} readOnly /> <Input value={producerNode.tags} readOnly/>
</Form.Item> </Form.Item>
<Form.Item label={<Text strong>{t.BEGIN_TIMESTAMP}</Text>}> <Form.Item label={<Text strong>{t.BEGIN_TIMESTAMP}</Text>}>
<Input value={moment(producerNode.traceNode.beginTimestamp).format('YYYY-MM-DD HH:mm:ss.SSS')} readOnly /> <Input
value={moment(producerNode.traceNode.beginTimestamp).format('YYYY-MM-DD HH:mm:ss.SSS')}
readOnly/>
</Form.Item> </Form.Item>
<Form.Item label={<Text strong>{t.END_TIMESTAMP}</Text>}> <Form.Item label={<Text strong>{t.END_TIMESTAMP}</Text>}>
<Input value={moment(producerNode.traceNode.endTimestamp).format('YYYY-MM-DD HH:mm:ss.SSS')} readOnly /> <Input
value={moment(producerNode.traceNode.endTimestamp).format('YYYY-MM-DD HH:mm:ss.SSS')}
readOnly/>
</Form.Item> </Form.Item>
<Form.Item label={<Text strong>{t.COST_TIME}</Text>}> <Form.Item label={<Text strong>{t.COST_TIME}</Text>}>
<Input value={`${producerNode.traceNode.costTime === 0 ? '<1' : producerNode.traceNode.costTime}ms`} readOnly /> <Input
value={`${producerNode.traceNode.costTime === 0 ? '<1' : producerNode.traceNode.costTime}ms`}
readOnly/>
</Form.Item> </Form.Item>
<Form.Item label={<Text strong>{t.MSG_TYPE}</Text>}> <Form.Item label={<Text strong>{t.MSG_TYPE}</Text>}>
<Input value={producerNode.traceNode.msgType} readOnly /> <Input value={producerNode.traceNode.msgType} readOnly/>
</Form.Item> </Form.Item>
<Form.Item label={<Text strong>{t.CLIENT_HOST}</Text>}> <Form.Item label={<Text strong>{t.CLIENT_HOST}</Text>}>
<Input value={producerNode.traceNode.clientHost} readOnly /> <Input value={producerNode.traceNode.clientHost} readOnly/>
</Form.Item> </Form.Item>
<Form.Item label={<Text strong>{t.STORE_HOST}</Text>}> <Form.Item label={<Text strong>{t.STORE_HOST}</Text>}>
<Input value={producerNode.traceNode.storeHost} readOnly /> <Input value={producerNode.traceNode.storeHost} readOnly/>
</Form.Item> </Form.Item>
<Form.Item label={<Text strong>{t.RETRY_TIMES}</Text>}> <Form.Item label={<Text strong>{t.RETRY_TIMES}</Text>}>
<Input value={producerNode.traceNode.retryTimes} readOnly /> <Input value={producerNode.traceNode.retryTimes} readOnly/>
</Form.Item> </Form.Item>
<Form.Item label={<Text strong>{t.OFFSET_MSG_ID}</Text>}> <Form.Item label={<Text strong>{t.OFFSET_MSG_ID}</Text>}>
<Input value={producerNode.offSetMsgId} readOnly /> <Input value={producerNode.offSetMsgId} readOnly/>
</Form.Item> </Form.Item>
</div> </div>
</Form> </Form>
{producerNode.transactionNodeList && producerNode.transactionNodeList.length > 0 && ( {producerNode.transactionNodeList && producerNode.transactionNodeList.length > 0 && (
<div style={{ marginTop: '30px' }}> <div style={{marginTop: '30px'}}>
<Typography.Title level={4} style={{ marginBottom: '15px' }}>{t.CHECK_TRANSACTION_INFO}:</Typography.Title> <Typography.Title level={4}
style={{marginBottom: '15px'}}>{t.CHECK_TRANSACTION_INFO}:</Typography.Title>
<Table <Table
columns={transactionColumns} columns={transactionColumns}
dataSource={producerNode.transactionNodeList} dataSource={producerNode.transactionNodeList}
@@ -418,7 +506,7 @@ const MessageTraceDetailViewDialog = ({ ngDialogData }) => {
bordered bordered
pagination={false} pagination={false}
size="middle" size="middle"
scroll={{ x: 'max-content' }} scroll={{x: 'max-content'}}
/> />
</div> </div>
)} )}
@@ -428,22 +516,31 @@ const MessageTraceDetailViewDialog = ({ ngDialogData }) => {
</Collapse> </Collapse>
</div> </div>
<div style={{ borderRadius: '8px', overflow: 'hidden', boxShadow: '0 4px 12px rgba(0, 0, 0, 0.08)' }}> <div style={{borderRadius: '8px', overflow: 'hidden', boxShadow: '0 4px 12px rgba(0, 0, 0, 0.08)'}}>
<Collapse defaultActiveKey={['consumeMessageTrace']} expandIconPosition="right"> <Collapse defaultActiveKey={['consumeMessageTrace']} expandIconPosition="right">
<Panel header={<Typography.Title level={3} style={{ margin: 0, color: '#333' }}>{t.CONSUME_MESSAGE_TRACE}</Typography.Title>} key="consumeMessageTrace"> <Panel header={<Typography.Title level={3} style={{
margin: 0,
color: '#333'
}}>{t.CONSUME_MESSAGE_TRACE}</Typography.Title>} key="consumeMessageTrace">
{subscriptionNodeList.length === 0 ? ( {subscriptionNodeList.length === 0 ? (
<Paragraph style={{ padding: '16px', textAlign: 'center', color: '#666' }}>{t.NO_CONSUMER_TRACE_DATA}</Paragraph> <Paragraph style={{
padding: '16px',
textAlign: 'center',
color: '#666'
}}>{t.NO_CONSUMER_TRACE_DATA}</Paragraph>
) : ( ) : (
<div style={{ padding: '16px', backgroundColor: '#fff' }}> <div style={{padding: '16px', backgroundColor: '#fff'}}>
{subscriptionNodeList.map(subscriptionNode => ( {subscriptionNodeList.map(subscriptionNode => (
<Collapse <Collapse
key={subscriptionNode.subscriptionGroup} key={subscriptionNode.subscriptionGroup}
style={{ marginBottom: '10px', border: '1px solid #e0e0e0', borderRadius: '4px' }} style={{marginBottom: '10px', border: '1px solid #e0e0e0', borderRadius: '4px'}}
defaultActiveKey={[subscriptionNode.subscriptionGroup]} defaultActiveKey={[subscriptionNode.subscriptionGroup]}
ghost ghost
> >
<Panel <Panel
header={<Typography.Title level={4} style={{ margin: 0 }}>{t.SUBSCRIPTION_GROUP}: <Text strong>{subscriptionNode.subscriptionGroup}</Text></Typography.Title>} header={<Typography.Title level={4}
style={{margin: 0}}>{t.SUBSCRIPTION_GROUP}: <Text
strong>{subscriptionNode.subscriptionGroup}</Text></Typography.Title>}
key={subscriptionNode.subscriptionGroup} key={subscriptionNode.subscriptionGroup}
> >
<Table <Table
@@ -453,7 +550,7 @@ const MessageTraceDetailViewDialog = ({ ngDialogData }) => {
bordered bordered
pagination={false} pagination={false}
size="middle" size="middle"
scroll={{ x: 'max-content' }} scroll={{x: 'max-content'}}
/> />
</Panel> </Panel>
</Collapse> </Collapse>

View File

@@ -16,29 +16,29 @@
*/ */
import React, {useEffect, useState} from 'react'; import React, {useEffect, useState} from 'react';
import { Layout, Menu, Dropdown, Button, Drawer, Grid, Space } from 'antd'; import {Button, Drawer, Dropdown, Grid, Layout, Menu, Space} from 'antd';
import {GlobalOutlined, DownOutlined, UserOutlined, MenuOutlined, BgColorsOutlined} from '@ant-design/icons'; import {BgColorsOutlined, DownOutlined, GlobalOutlined, MenuOutlined, UserOutlined} from '@ant-design/icons';
import { useLocation, useNavigate } from 'react-router-dom'; import {useLocation, useNavigate} from 'react-router-dom';
import { useLanguage } from '../i18n/LanguageContext'; import {useLanguage} from '../i18n/LanguageContext';
import {useTheme} from "../store/context/ThemeContext"; import {useTheme} from "../store/context/ThemeContext";
import {remoteApi} from "../api/remoteApi/remoteApi"; import {remoteApi} from "../api/remoteApi/remoteApi";
const { Header } = Layout; const {Header} = Layout;
const { useBreakpoint } = Grid; // Used to determine screen breakpoints const {useBreakpoint} = Grid; // Used to determine screen breakpoints
const Navbar = ({ rmqVersion = true, showAcl = true}) => { const Navbar = ({rmqVersion = true, showAcl = true}) => {
const location = useLocation(); const location = useLocation();
const navigate = useNavigate(); const navigate = useNavigate();
const { lang, setLang, t } = useLanguage(); const {lang, setLang, t} = useLanguage();
const screens = useBreakpoint(); // Get current screen size breakpoints const screens = useBreakpoint(); // Get current screen size breakpoints
const { currentThemeName, setCurrentThemeName } = useTheme(); const {currentThemeName, setCurrentThemeName} = useTheme();
const [userName, setUserName] = useState(null); const [userName, setUserName] = useState(null);
const [drawerVisible, setDrawerVisible] = useState(false); // Controls drawer visibility const [drawerVisible, setDrawerVisible] = useState(false); // Controls drawer visibility
// Get selected menu item key based on current route path // Get selected menu item key based on current route path
const getPath = () => location.pathname.replace('/', ''); const getPath = () => location.pathname.replace('/', '');
const handleMenuClick = ({ key }) => { const handleMenuClick = ({key}) => {
navigate(`/${key}`); navigate(`/${key}`);
setDrawerVisible(false); // Close drawer after clicking a menu item setDrawerVisible(false); // Close drawer after clicking a menu item
}; };
@@ -63,13 +63,13 @@ const Navbar = ({ rmqVersion = true, showAcl = true}) => {
const storedUsername = window.localStorage.getItem("username"); const storedUsername = window.localStorage.getItem("username");
if (storedUsername) { if (storedUsername) {
setUserName(storedUsername); setUserName(storedUsername);
}else { } else {
setUserName(null); setUserName(null);
} }
}, []); }, []);
const langMenu = ( const langMenu = (
<Menu onClick={({ key }) => setLang(key)}> <Menu onClick={({key}) => setLang(key)}>
<Menu.Item key="en">{t.ENGLISH}</Menu.Item> <Menu.Item key="en">{t.ENGLISH}</Menu.Item>
<Menu.Item key="zh">{t.CHINESE}</Menu.Item> <Menu.Item key="zh">{t.CHINESE}</Menu.Item>
</Menu> </Menu>
@@ -82,7 +82,7 @@ const Navbar = ({ rmqVersion = true, showAcl = true}) => {
); );
const themeMenu = ( const themeMenu = (
<Menu onClick={({ key }) => setCurrentThemeName(key)}> <Menu onClick={({key}) => setCurrentThemeName(key)}>
<Menu.Item key="default">{t.BLUE} ({t.DEFAULT})</Menu.Item> <Menu.Item key="default">{t.BLUE} ({t.DEFAULT})</Menu.Item>
<Menu.Item key="pink">{t.PINK}</Menu.Item> <Menu.Item key="pink">{t.PINK}</Menu.Item>
<Menu.Item key="green">{t.GREEN}</Menu.Item> <Menu.Item key="green">{t.GREEN}</Menu.Item>
@@ -92,17 +92,17 @@ const Navbar = ({ rmqVersion = true, showAcl = true}) => {
// Menu item configuration // Menu item configuration
const menuItems = [ const menuItems = [
{ key: 'ops', label: t.OPS }, {key: 'ops', label: t.OPS},
...(rmqVersion ? [{ key: 'proxy', label: t.PROXY }] : []), ...(rmqVersion ? [{key: 'proxy', label: t.PROXY}] : []),
{ key: '', label: t.DASHBOARD }, // Dashboard corresponds to root path {key: '', label: t.DASHBOARD}, // Dashboard corresponds to root path
{ key: 'cluster', label: t.CLUSTER }, {key: 'cluster', label: t.CLUSTER},
{ key: 'topic', label: t.TOPIC }, {key: 'topic', label: t.TOPIC},
{ key: 'consumer', label: t.CONSUMER }, {key: 'consumer', label: t.CONSUMER},
{ key: 'producer', label: t.PRODUCER }, {key: 'producer', label: t.PRODUCER},
{ key: 'message', label: t.MESSAGE }, {key: 'message', label: t.MESSAGE},
{ key: 'dlqMessage', label: t.DLQ_MESSAGE }, {key: 'dlqMessage', label: t.DLQ_MESSAGE},
{ key: 'messageTrace', label: t.MESSAGETRACE }, {key: 'messageTrace', label: t.MESSAGETRACE},
...(showAcl ? [{ key: 'acl', label: t.WHITE_LIST }] : []), ...(showAcl ? [{key: 'acl', label: t.ACL_MANAGEMENT}] : []),
]; ];
// Determine if it's a small screen (e.g., less than md) // Determine if it's a small screen (e.g., less than md)
@@ -120,7 +120,7 @@ const Navbar = ({ rmqVersion = true, showAcl = true}) => {
padding: isExtraSmallScreen ? '0 16px' : '0 24px', // Smaller padding on extra small screens padding: isExtraSmallScreen ? '0 16px' : '0 24px', // Smaller padding on extra small screens
}} }}
> >
<div className="navbar-left" style={{ display: 'flex', alignItems: 'center' }}> <div className="navbar-left" style={{display: 'flex', alignItems: 'center'}}>
<div <div
style={{ style={{
fontWeight: 'bold', fontWeight: 'bold',
@@ -141,33 +141,33 @@ const Navbar = ({ rmqVersion = true, showAcl = true}) => {
mode="horizontal" mode="horizontal"
items={menuItems} items={menuItems}
theme="dark" // Use dark theme to match Header background theme="dark" // Use dark theme to match Header background
style={{ flex: 1, minWidth: 0 }} // Allow menu items to adapt width style={{flex: 1, minWidth: 0}} // Allow menu items to adapt width
/> />
)} )}
</div> </div>
<Space size={isExtraSmallScreen ? 8 : 16} > {/* Adjust spacing for buttons */} <Space size={isExtraSmallScreen ? 8 : 16}> {/* Adjust spacing for buttons */}
{/* Theme switch button */} {/* Theme switch button */}
<Dropdown overlay={themeMenu}> <Dropdown overlay={themeMenu}>
<Button icon={<BgColorsOutlined />} size="small"> <Button icon={<BgColorsOutlined/>} size="small">
{!isExtraSmallScreen && `${t.TOPIC}: ${currentThemeName}`} {!isExtraSmallScreen && `${t.TOPIC}: ${currentThemeName}`}
<DownOutlined /> <DownOutlined/>
</Button> </Button>
</Dropdown> </Dropdown>
<Dropdown overlay={langMenu}> <Dropdown overlay={langMenu}>
<Button icon={<GlobalOutlined />} size="small"> <Button icon={<GlobalOutlined/>} size="small">
{!isExtraSmallScreen && t.CHANGE_LANG} {/* Hide text on extra small screens */} {!isExtraSmallScreen && t.CHANGE_LANG} {/* Hide text on extra small screens */}
<DownOutlined /> <DownOutlined/>
</Button> </Button>
</Dropdown> </Dropdown>
{userName && ( {userName && (
<Dropdown overlay={userMenu}> <Dropdown overlay={userMenu}>
{/* 使用一个可点击的元素作为 Dropdown 的唯一子元素 */} {/* 使用一个可点击的元素作为 Dropdown 的唯一子元素 */}
<a onClick={e => e.preventDefault()} style={{ display: 'flex', alignItems: 'center' }}> <a onClick={e => e.preventDefault()} style={{display: 'flex', alignItems: 'center'}}>
<UserOutlined style={{ marginRight: 8 }} /> {/* 添加一些间距 */} <UserOutlined style={{marginRight: 8}}/> {/* 添加一些间距 */}
{userName} {userName}
<DownOutlined style={{ marginLeft: 8 }} /> <DownOutlined style={{marginLeft: 8}}/>
</a> </a>
</Dropdown> </Dropdown>
)} )}
@@ -175,9 +175,9 @@ const Navbar = ({ rmqVersion = true, showAcl = true}) => {
{isSmallScreen && ( // Display hamburger icon on small screens {isSmallScreen && ( // Display hamburger icon on small screens
<Button <Button
type="primary" type="primary"
icon={<MenuOutlined />} icon={<MenuOutlined/>}
onClick={() => setDrawerVisible(true)} onClick={() => setDrawerVisible(true)}
style={{ marginLeft: isExtraSmallScreen ? 8 : 16 }} // Adjust margin for hamburger icon style={{marginLeft: isExtraSmallScreen ? 8 : 16}} // Adjust margin for hamburger icon
/> />
)} )}
</Space> </Space>
@@ -192,7 +192,7 @@ const Navbar = ({ rmqVersion = true, showAcl = true}) => {
open={drawerVisible} open={drawerVisible}
// If you want the Drawer's background to match the Menu's background color, you can set bodyStyle like this // If you want the Drawer's background to match the Menu's background color, you can set bodyStyle like this
// or set components.Drawer.colorBgElevated in theme.js, etc. // or set components.Drawer.colorBgElevated in theme.js, etc.
bodyStyle={{ padding: 0, backgroundColor: '#1c324a' }} // Set Drawer body background to dark bodyStyle={{padding: 0, backgroundColor: '#1c324a'}} // Set Drawer body background to dark
width={200} // Set drawer width width={200} // Set drawer width
> >
<Menu <Menu
@@ -201,7 +201,7 @@ const Navbar = ({ rmqVersion = true, showAcl = true}) => {
mode="inline" // Use vertical menu in drawer mode="inline" // Use vertical menu in drawer
items={menuItems} items={menuItems}
theme="dark" theme="dark"
style={{ height: '100%', borderRight: 0 }} // Ensure menu fills the drawer style={{height: '100%', borderRight: 0}} // Ensure menu fills the drawer
/> />
</Drawer> </Drawer>
</Header> </Header>

View File

@@ -15,23 +15,23 @@
* limitations under the License. * limitations under the License.
*/ */
import { Input, Select, Tag, Space } from 'antd'; import {Input, Select, Space, Tag} from 'antd';
import { PlusOutlined } from '@ant-design/icons'; import {PlusOutlined} from '@ant-design/icons';
import React, { useState } from 'react'; import React, {useState} from 'react';
const { Option } = Select; const {Option} = Select;
// 资源类型枚举 // 资源类型枚举
const resourceTypes = [ const resourceTypes = [
{ value: 0, label: 'Unknown', prefix: 'UNKNOWN' }, {value: 0, label: 'Unknown', prefix: 'UNKNOWN'},
{ value: 1, label: 'Any', prefix: 'ANY' }, {value: 1, label: 'Any', prefix: 'ANY'},
{ value: 2, label: 'Cluster', prefix: 'CLUSTER' }, {value: 2, label: 'Cluster', prefix: 'CLUSTER'},
{ value: 3, label: 'Namespace', prefix: 'NAMESPACE' }, {value: 3, label: 'Namespace', prefix: 'NAMESPACE'},
{ value: 4, label: 'Topic', prefix: 'TOPIC' }, {value: 4, label: 'Topic', prefix: 'TOPIC'},
{ value: 5, label: 'Group', prefix: 'GROUP' }, {value: 5, label: 'Group', prefix: 'GROUP'},
]; ];
const ResourceInput = ({ value = [], onChange }) => { const ResourceInput = ({value = [], onChange}) => {
// 确保 value 始终是数组 // 确保 value 始终是数组
const safeValue = Array.isArray(value) ? value : []; const safeValue = Array.isArray(value) ? value : [];
@@ -96,7 +96,7 @@ const ResourceInput = ({ value = [], onChange }) => {
<Space> <Space>
<Select <Select
value={selectedType} value={selectedType}
style={{ width: 120 }} style={{width: 120}}
onChange={handleTypeChange} onChange={handleTypeChange}
> >
{resourceTypes.map(type => ( {resourceTypes.map(type => (
@@ -107,7 +107,7 @@ const ResourceInput = ({ value = [], onChange }) => {
</Select> </Select>
<Input <Input
ref={inputRef} ref={inputRef}
style={{ width: 180 }} style={{width: 180}}
value={resourceName} value={resourceName}
onChange={handleNameChange} onChange={handleNameChange}
onPressEnter={handleAddResource} onPressEnter={handleAddResource}
@@ -116,8 +116,8 @@ const ResourceInput = ({ value = [], onChange }) => {
/> />
</Space> </Space>
) : ( ) : (
<Tag onClick={showInput} style={{ background: '#fff', borderStyle: 'dashed' }}> <Tag onClick={showInput} style={{background: '#fff', borderStyle: 'dashed'}}>
<PlusOutlined /> 添加资源 <PlusOutlined/> 添加资源
</Tag> </Tag>
)} )}
</Space> </Space>

View File

@@ -15,27 +15,27 @@
* limitations under the License. * limitations under the License.
*/ */
import { Input, Select } from 'antd'; import {Input, Select} from 'antd';
import React, { useState, useEffect } from 'react'; import React, {useEffect, useState} from 'react';
const { Option } = Select; const {Option} = Select;
// Subject 类型枚举 // Subject 类型枚举
const subjectTypes = [ const subjectTypes = [
{ value: 'User', label: 'User' }, {value: 'User', label: 'User'},
]; ];
const SubjectInput = ({ value, onChange, disabled }) => { const SubjectInput = ({value, onChange, disabled}) => {
// 解析传入的 value将其拆分为 type 和 name // 解析传入的 value将其拆分为 type 和 name
const parseValue = (val) => { const parseValue = (val) => {
if (!val || typeof val !== 'string') { if (!val || typeof val !== 'string') {
return { type: subjectTypes[0].value, name: '' }; // 默认值 return {type: subjectTypes[0].value, name: ''}; // 默认值
} }
const parts = val.split(':'); const parts = val.split(':');
if (parts.length === 2 && subjectTypes.some(t => t.value === parts[0])) { if (parts.length === 2 && subjectTypes.some(t => t.value === parts[0])) {
return { type: parts[0], name: parts[1] }; return {type: parts[0], name: parts[1]};
} }
return { type: subjectTypes[0].value, name: val }; // 如果格式不匹配,将整个值作为 name类型设为默认 return {type: subjectTypes[0].value, name: val}; // 如果格式不匹配,将整个值作为 name类型设为默认
}; };
const [currentType, setCurrentType] = useState(() => parseValue(value).type); const [currentType, setCurrentType] = useState(() => parseValue(value).type);
@@ -76,7 +76,7 @@ const SubjectInput = ({ value, onChange, disabled }) => {
return ( return (
<Input.Group compact> <Input.Group compact>
<Select <Select
style={{ width: '30%' }} style={{width: '30%'}}
value={currentType} value={currentType}
onChange={onTypeChange} onChange={onTypeChange}
disabled={disabled} disabled={disabled}
@@ -88,7 +88,7 @@ const SubjectInput = ({ value, onChange, disabled }) => {
))} ))}
</Select> </Select>
<Input <Input
style={{ width: '70%' }} style={{width: '70%'}}
value={currentName} value={currentName}
onChange={onNameChange} onChange={onNameChange}
placeholder="请输入名称 (例如: yourUsername)" placeholder="请输入名称 (例如: yourUsername)"

View File

@@ -15,13 +15,13 @@
* limitations under the License. * limitations under the License.
*/ */
import React, { useState, useEffect } from 'react'; import React, {useEffect, useState} from 'react';
import { Modal, Table, Spin } from 'antd'; import {Modal, Spin, Table} from 'antd';
import { remoteApi } from '../../api/remoteApi/remoteApi'; import {remoteApi} from '../../api/remoteApi/remoteApi';
import { useLanguage } from '../../i18n/LanguageContext'; import {useLanguage} from '../../i18n/LanguageContext';
const ClientInfoModal = ({ visible, group, address, onCancel }) => { const ClientInfoModal = ({visible, group, address, onCancel}) => {
const { t } = useLanguage(); const {t} = useLanguage();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [connectionData, setConnectionData] = useState(null); const [connectionData, setConnectionData] = useState(null);
const [subscriptionData, setSubscriptionData] = useState(null); const [subscriptionData, setSubscriptionData] = useState(null);
@@ -46,15 +46,15 @@ const ClientInfoModal = ({ visible, group, address, onCancel }) => {
}, [visible, group, address]); }, [visible, group, address]);
const connectionColumns = [ const connectionColumns = [
{ title: 'ClientId', dataIndex: 'clientId' }, {title: 'ClientId', dataIndex: 'clientId'},
{ title: 'ClientAddr', dataIndex: 'clientAddr' }, {title: 'ClientAddr', dataIndex: 'clientAddr'},
{ title: 'Language', dataIndex: 'language' }, {title: 'Language', dataIndex: 'language'},
{ title: 'Version', dataIndex: 'versionDesc' }, {title: 'Version', dataIndex: 'versionDesc'},
]; ];
const subscriptionColumns = [ const subscriptionColumns = [
{ title: 'Topic', dataIndex: 'topic' }, {title: 'Topic', dataIndex: 'topic'},
{ title: 'SubExpression', dataIndex: 'subString' }, {title: 'SubExpression', dataIndex: 'subString'},
]; ];
return ( return (
@@ -88,7 +88,7 @@ const ClientInfoModal = ({ visible, group, address, onCancel }) => {
rowKey="topic" rowKey="topic"
pagination={false} pagination={false}
locale={{ locale={{
emptyText: loading ? <Spin size="small" /> : t.NO_DATA emptyText: loading ? <Spin size="small"/> : t.NO_DATA
}} }}
/> />
<p>ConsumeType: {connectionData.consumeType}</p> <p>ConsumeType: {connectionData.consumeType}</p>

View File

@@ -15,13 +15,23 @@
* limitations under the License. * limitations under the License.
*/ */
import React, { useEffect, useState } from 'react'; import React, {useEffect, useState} from 'react';
import { Button, Descriptions, Form, Input, Select, Switch, message } from 'antd'; import {Button, Descriptions, Form, Input, message, Select, Switch} from 'antd';
import { remoteApi } from '../../api/remoteApi/remoteApi'; // 确保路径正确 import {remoteApi} from '../../api/remoteApi/remoteApi'; // 确保路径正确
const { Option } = Select; const {Option} = Select;
const ConsumerConfigItem = ({ initialConfig, isAddConfig, group, brokerName, allBrokerList, allClusterNames,onCancel, onSuccess, t }) => { const ConsumerConfigItem = ({
initialConfig,
isAddConfig,
group,
brokerName,
allBrokerList,
allClusterNames,
onCancel,
onSuccess,
t
}) => {
const [form] = Form.useForm(); const [form] = Form.useForm();
const [currentBrokerName, setCurrentBrokerName] = useState(brokerName); const [currentBrokerName, setCurrentBrokerName] = useState(brokerName);

View File

@@ -34,7 +34,7 @@ const ConsumerConfigModal = ({visible, isAddConfig, group, onCancel, setIsAddCon
setLoading(true); setLoading(true);
try { try {
// Fetch cluster list for broker names and cluster names // Fetch cluster list for broker names and cluster names
if(isAddConfig) { if (isAddConfig) {
const clusterResponse = await remoteApi.getClusterList(); const clusterResponse = await remoteApi.getClusterList();
if (clusterResponse.status === 0 && clusterResponse.data) { if (clusterResponse.status === 0 && clusterResponse.data) {
const clusterInfo = clusterResponse.data.clusterInfo; const clusterInfo = clusterResponse.data.clusterInfo;

View File

@@ -15,13 +15,13 @@
* limitations under the License. * limitations under the License.
*/ */
import React, { useState, useEffect } from 'react'; import React, {useEffect, useState} from 'react';
import { Modal, Table, Spin } from 'antd'; import {Modal, Spin, Table} from 'antd';
import { remoteApi } from '../../api/remoteApi/remoteApi'; import {remoteApi} from '../../api/remoteApi/remoteApi';
import { useLanguage } from '../../i18n/LanguageContext'; import {useLanguage} from '../../i18n/LanguageContext';
const ConsumerDetailModal = ({ visible, group, address, onCancel }) => { const ConsumerDetailModal = ({visible, group, address, onCancel}) => {
const { t } = useLanguage(); const {t} = useLanguage();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [details, setDetails] = useState([]); const [details, setDetails] = useState([]);
@@ -44,12 +44,12 @@ const ConsumerDetailModal = ({ visible, group, address, onCancel }) => {
}, [visible, group, address]); }, [visible, group, address]);
const queueColumns = [ const queueColumns = [
{ title: 'Broker', dataIndex: 'brokerName' }, {title: 'Broker', dataIndex: 'brokerName'},
{ title: 'Queue', dataIndex: 'queueId' }, {title: 'Queue', dataIndex: 'queueId'},
{ title: 'BrokerOffset', dataIndex: 'brokerOffset' }, {title: 'BrokerOffset', dataIndex: 'brokerOffset'},
{ title: 'ConsumerOffset', dataIndex: 'consumerOffset' }, {title: 'ConsumerOffset', dataIndex: 'consumerOffset'},
{ title: 'DiffTotal', dataIndex: 'diffTotal' }, {title: 'DiffTotal', dataIndex: 'diffTotal'},
{ title: 'LastTimestamp', dataIndex: 'lastTimestamp' }, {title: 'LastTimestamp', dataIndex: 'lastTimestamp'},
]; ];
return ( return (

View File

@@ -15,13 +15,13 @@
* limitations under the License. * limitations under the License.
*/ */
import React, { useState, useEffect } from 'react'; import React, {useEffect, useState} from 'react';
import { Modal, Spin, Checkbox, Button, notification } from 'antd'; import {Button, Checkbox, Modal, notification, Spin} from 'antd';
import { remoteApi } from '../../api/remoteApi/remoteApi'; import {remoteApi} from '../../api/remoteApi/remoteApi';
import { useLanguage } from '../../i18n/LanguageContext'; import {useLanguage} from '../../i18n/LanguageContext';
const DeleteConsumerModal = ({ visible, group, onCancel, onSuccess }) => { const DeleteConsumerModal = ({visible, group, onCancel, onSuccess}) => {
const { t } = useLanguage(); const {t} = useLanguage();
const [brokerList, setBrokerList] = useState([]); const [brokerList, setBrokerList] = useState([]);
const [selectedBrokers, setSelectedBrokers] = useState([]); const [selectedBrokers, setSelectedBrokers] = useState([]);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@@ -48,7 +48,7 @@ const DeleteConsumerModal = ({ visible, group, onCancel, onSuccess }) => {
// 处理删除提交 // 处理删除提交
const handleDelete = async () => { const handleDelete = async () => {
if (selectedBrokers.length === 0) { if (selectedBrokers.length === 0) {
notification.warning({ message: t.PLEASE_SELECT_BROKER }); notification.warning({message: t.PLEASE_SELECT_BROKER});
return; return;
} }
@@ -60,7 +60,7 @@ const DeleteConsumerModal = ({ visible, group, onCancel, onSuccess }) => {
); );
if (response.status === 0) { if (response.status === 0) {
notification.success({ message: t.DELETE_SUCCESS }); notification.success({message: t.DELETE_SUCCESS});
onSuccess(); onSuccess();
onCancel(); onCancel();
} }
@@ -90,9 +90,9 @@ const DeleteConsumerModal = ({ visible, group, onCancel, onSuccess }) => {
]} ]}
> >
<Spin spinning={loading}> <Spin spinning={loading}>
<div style={{ marginBottom: 16 }}>{t.SELECT_DELETE_BROKERS}:</div> <div style={{marginBottom: 16}}>{t.SELECT_DELETE_BROKERS}:</div>
<Checkbox.Group <Checkbox.Group
style={{ width: '100%' }} style={{width: '100%'}}
value={selectedBrokers} value={selectedBrokers}
onChange={values => setSelectedBrokers(values)} onChange={values => setSelectedBrokers(values)}
> >

View File

@@ -15,10 +15,10 @@
* limitations under the License. * limitations under the License.
*/ */
import { Button, DatePicker, Form, Modal, Select } from "antd"; import {Button, DatePicker, Form, Modal, Select} from "antd";
import React, { useEffect, useState } from "react"; import React, {useEffect, useState} from "react";
const ConsumerResetOffsetDialog = ({ visible, onClose, topic, allConsumerGroupList, handleResetOffset, t }) => { const ConsumerResetOffsetDialog = ({visible, onClose, topic, allConsumerGroupList, handleResetOffset, t}) => {
const [form] = Form.useForm(); const [form] = Form.useForm();
const [selectedConsumerGroup, setSelectedConsumerGroup] = useState([]); const [selectedConsumerGroup, setSelectedConsumerGroup] = useState([]);
const [selectedTime, setSelectedTime] = useState(null); const [selectedTime, setSelectedTime] = useState(null);
@@ -49,14 +49,14 @@ const ConsumerResetOffsetDialog = ({ visible, onClose, topic, allConsumerGroupLi
</Button>, </Button>,
]} ]}
> >
<Form form={form} layout="horizontal" labelCol={{ span: 6 }} wrapperCol={{ span: 18 }}> <Form form={form} layout="horizontal" labelCol={{span: 6}} wrapperCol={{span: 18}}>
<Form.Item label={t.SUBSCRIPTION_GROUP} required> <Form.Item label={t.SUBSCRIPTION_GROUP} required>
<Select <Select
mode="multiple" mode="multiple"
placeholder={t.SELECT_CONSUMER_GROUP} placeholder={t.SELECT_CONSUMER_GROUP}
value={selectedConsumerGroup} value={selectedConsumerGroup}
onChange={setSelectedConsumerGroup} onChange={setSelectedConsumerGroup}
options={allConsumerGroupList.map(group => ({ value: group, label: group }))} options={allConsumerGroupList.map(group => ({value: group, label: group}))}
/> />
</Form.Item> </Form.Item>
<Form.Item label={t.TIME} required> <Form.Item label={t.TIME} required>
@@ -65,7 +65,7 @@ const ConsumerResetOffsetDialog = ({ visible, onClose, topic, allConsumerGroupLi
format="YYYY-MM-DD HH:mm:ss" format="YYYY-MM-DD HH:mm:ss"
value={selectedTime} value={selectedTime}
onChange={setSelectedTime} onChange={setSelectedTime}
style={{ width: '100%' }} style={{width: '100%'}}
/> />
</Form.Item> </Form.Item>
</Form> </Form>

View File

@@ -19,13 +19,13 @@ import moment from "moment/moment";
import {Button, Modal, Table} from "antd"; import {Button, Modal, Table} from "antd";
import React from "react"; import React from "react";
const ConsumerViewDialog = ({ visible, onClose, topic, consumerData, consumerGroupCount, t }) => { const ConsumerViewDialog = ({visible, onClose, topic, consumerData, consumerGroupCount, t}) => {
const columns = [ const columns = [
{ title: t.BROKER, dataIndex: 'brokerName', key: 'brokerName', align: 'center' }, {title: t.BROKER, dataIndex: 'brokerName', key: 'brokerName', align: 'center'},
{ title: t.QUEUE, dataIndex: 'queueId', key: 'queueId', align: 'center' }, {title: t.QUEUE, dataIndex: 'queueId', key: 'queueId', align: 'center'},
{ title: t.CONSUMER_CLIENT, dataIndex: 'clientInfo', key: 'clientInfo', align: 'center' }, {title: t.CONSUMER_CLIENT, dataIndex: 'clientInfo', key: 'clientInfo', align: 'center'},
{ title: t.BROKER_OFFSET, dataIndex: 'brokerOffset', key: 'brokerOffset', align: 'center' }, {title: t.BROKER_OFFSET, dataIndex: 'brokerOffset', key: 'brokerOffset', align: 'center'},
{ title: t.CONSUMER_OFFSET, dataIndex: 'consumerOffset', key: 'consumerOffset', align: 'center' }, {title: t.CONSUMER_OFFSET, dataIndex: 'consumerOffset', key: 'consumerOffset', align: 'center'},
{ {
title: t.DIFF_TOTAL, title: t.DIFF_TOTAL,
dataIndex: 'diffTotal', dataIndex: 'diffTotal',
@@ -58,15 +58,19 @@ const ConsumerViewDialog = ({ visible, onClose, topic, consumerData, consumerGro
<div>{t.NO_DATA} {t.SUBSCRIPTION_GROUP}</div> <div>{t.NO_DATA} {t.SUBSCRIPTION_GROUP}</div>
) : ( ) : (
consumerData && Object.entries(consumerData).map(([consumerGroup, consumeDetail]) => ( consumerData && Object.entries(consumerData).map(([consumerGroup, consumeDetail]) => (
<div key={consumerGroup} style={{ marginBottom: '24px' }}> <div key={consumerGroup} style={{marginBottom: '24px'}}>
<Table <Table
bordered bordered
pagination={false} pagination={false}
showHeader={false} showHeader={false}
dataSource={[{ consumerGroup, diffTotal: consumeDetail.diffTotal, lastTimestamp: consumeDetail.lastTimestamp }]} dataSource={[{
consumerGroup,
diffTotal: consumeDetail.diffTotal,
lastTimestamp: consumeDetail.lastTimestamp
}]}
columns={[ columns={[
{ title: t.SUBSCRIPTION_GROUP, dataIndex: 'consumerGroup', key: 'consumerGroup' }, {title: t.SUBSCRIPTION_GROUP, dataIndex: 'consumerGroup', key: 'consumerGroup'},
{ title: t.DELAY, dataIndex: 'diffTotal', key: 'diffTotal' }, {title: t.DELAY, dataIndex: 'diffTotal', key: 'diffTotal'},
{ {
title: t.LAST_CONSUME_TIME, title: t.LAST_CONSUME_TIME,
dataIndex: 'lastTimestamp', dataIndex: 'lastTimestamp',
@@ -76,7 +80,7 @@ const ConsumerViewDialog = ({ visible, onClose, topic, consumerData, consumerGro
]} ]}
rowKey="consumerGroup" rowKey="consumerGroup"
size="small" size="small"
style={{ marginBottom: '12px' }} style={{marginBottom: '12px'}}
/> />
<Table <Table
bordered bordered

View File

@@ -18,7 +18,7 @@
import {Button, Modal, Table} from "antd"; import {Button, Modal, Table} from "antd";
import React from "react"; import React from "react";
const ResetOffsetResultDialog = ({ visible, onClose, result, t }) => { const ResetOffsetResultDialog = ({visible, onClose, result, t}) => {
return ( return (
<Modal <Modal
title="ResetResult" title="ResetResult"
@@ -31,12 +31,12 @@ const ResetOffsetResultDialog = ({ visible, onClose, result, t }) => {
]} ]}
> >
{result && Object.entries(result).map(([groupName, groupData]) => ( {result && Object.entries(result).map(([groupName, groupData]) => (
<div key={groupName} style={{ marginBottom: '16px', border: '1px solid #f0f0f0', padding: '10px' }}> <div key={groupName} style={{marginBottom: '16px', border: '1px solid #f0f0f0', padding: '10px'}}>
<Table <Table
dataSource={[{ groupName, status: groupData.status }]} dataSource={[{groupName, status: groupData.status}]}
columns={[ columns={[
{ title: 'GroupName', dataIndex: 'groupName', key: 'groupName' }, {title: 'GroupName', dataIndex: 'groupName', key: 'groupName'},
{ title: 'State', dataIndex: 'status', key: 'status' }, {title: 'State', dataIndex: 'status', key: 'status'},
]} ]}
pagination={false} pagination={false}
rowKey="groupName" rowKey="groupName"
@@ -47,8 +47,8 @@ const ResetOffsetResultDialog = ({ visible, onClose, result, t }) => {
<div>You Should Check It Yourself</div> <div>You Should Check It Yourself</div>
) : ( ) : (
<Table <Table
dataSource={groupData.rollbackStatsList.map((item, index) => ({ key: index, item }))} dataSource={groupData.rollbackStatsList.map((item, index) => ({key: index, item}))}
columns={[{ dataIndex: 'item', key: 'item' }]} columns={[{dataIndex: 'item', key: 'item'}]}
pagination={false} pagination={false}
rowKey="key" rowKey="key"
size="small" size="small"

View File

@@ -15,10 +15,10 @@
* limitations under the License. * limitations under the License.
*/ */
import { Button, Modal, Table } from "antd"; import {Button, Modal, Table} from "antd";
import React from "react"; import React from "react";
const RouterViewDialog = ({ visible, onClose, topic, routeData, t }) => { const RouterViewDialog = ({visible, onClose, topic, routeData, t}) => {
const brokerColumns = [ const brokerColumns = [
{ {
title: 'Broker', title: 'Broker',
@@ -30,10 +30,14 @@ const RouterViewDialog = ({ visible, onClose, topic, routeData, t }) => {
key: 'brokerAddrs', key: 'brokerAddrs',
render: (_, record) => ( render: (_, record) => (
<Table <Table
dataSource={Object.entries(record.brokerAddrs || []).map(([key, value]) => ({ key, idx: key, address: value }))} dataSource={Object.entries(record.brokerAddrs || []).map(([key, value]) => ({
key,
idx: key,
address: value
}))}
columns={[ columns={[
{ title: 'Index', dataIndex: 'idx', key: 'idx' }, {title: 'Index', dataIndex: 'idx', key: 'idx'},
{ title: 'Address', dataIndex: 'address', key: 'address' }, {title: 'Address', dataIndex: 'address', key: 'address'},
]} ]}
pagination={false} pagination={false}
bordered bordered
@@ -82,7 +86,7 @@ const RouterViewDialog = ({ visible, onClose, topic, routeData, t }) => {
<div> <div>
<h3>Broker Datas:</h3> <h3>Broker Datas:</h3>
{routeData?.brokerDatas?.map((item, index) => ( {routeData?.brokerDatas?.map((item, index) => (
<div key={index} style={{ marginBottom: '15px', border: '1px solid #d9d9d9', padding: '10px' }}> <div key={index} style={{marginBottom: '15px', border: '1px solid #d9d9d9', padding: '10px'}}>
<Table <Table
dataSource={[item]} dataSource={[item]}
columns={brokerColumns} columns={brokerColumns}
@@ -93,7 +97,7 @@ const RouterViewDialog = ({ visible, onClose, topic, routeData, t }) => {
</div> </div>
))} ))}
</div> </div>
<div style={{ marginTop: '20px' }}> <div style={{marginTop: '20px'}}>
<h3>{t.QUEUE_DATAS}:</h3> <h3>{t.QUEUE_DATAS}:</h3>
<Table <Table
dataSource={routeData?.queueDatas || []} dataSource={routeData?.queueDatas || []}

View File

@@ -18,7 +18,7 @@
import {Button, Form, Modal, Table} from "antd"; import {Button, Form, Modal, Table} from "antd";
import React from "react"; import React from "react";
const SendResultDialog = ({ visible, onClose, result, t }) => { const SendResultDialog = ({visible, onClose, result, t}) => {
return ( return (
<Modal <Modal
title="SendResult" title="SendResult"
@@ -43,11 +43,11 @@ const SendResultDialog = ({ visible, onClose, result, t }) => {
: [] : []
} }
columns={[ columns={[
{ dataIndex: 'label', key: 'label' }, {dataIndex: 'label', key: 'label'},
{ {
dataIndex: 'value', dataIndex: 'value',
key: 'value', key: 'value',
render: (text) => <pre style={{ whiteSpace: 'pre-wrap', margin: 0 }}>{text}</pre>, render: (text) => <pre style={{whiteSpace: 'pre-wrap', margin: 0}}>{text}</pre>,
}, },
]} ]}
pagination={false} pagination={false}
@@ -61,5 +61,4 @@ const SendResultDialog = ({ visible, onClose, result, t }) => {
}; };
export default SendResultDialog; export default SendResultDialog;

View File

@@ -76,24 +76,24 @@ const SendTopicMessageDialog = ({
</Button>, </Button>,
]} ]}
> >
<Form form={form} layout="horizontal" labelCol={{ span: 6 }} wrapperCol={{ span: 18 }}> <Form form={form} layout="horizontal" labelCol={{span: 6}} wrapperCol={{span: 18}}>
<Form.Item label={t.TOPIC} name="topic"> <Form.Item label={t.TOPIC} name="topic">
<Input disabled /> <Input disabled/>
</Form.Item> </Form.Item>
<Form.Item label={t.TAG} name="tag"> <Form.Item label={t.TAG} name="tag">
<Input /> <Input/>
</Form.Item> </Form.Item>
<Form.Item label={t.KEY} name="key"> <Form.Item label={t.KEY} name="key">
<Input /> <Input/>
</Form.Item> </Form.Item>
<Form.Item label={t.MESSAGE_BODY} name="messageBody" rules={[{ required: true, message: t.REQUIRED }]}> <Form.Item label={t.MESSAGE_BODY} name="messageBody" rules={[{required: true, message: t.REQUIRED}]}>
<Input.TextArea <Input.TextArea
style={{ maxHeight: '200px', minHeight: '200px', resize: 'none' }} style={{maxHeight: '200px', minHeight: '200px', resize: 'none'}}
rows={8} rows={8}
/> />
</Form.Item> </Form.Item>
<Form.Item label={t.ENABLE_MESSAGE_TRACE} name="traceEnabled" valuePropName="checked"> <Form.Item label={t.ENABLE_MESSAGE_TRACE} name="traceEnabled" valuePropName="checked">
<Checkbox /> <Checkbox/>
</Form.Item> </Form.Item>
</Form> </Form>
</Modal> </Modal>

View File

@@ -15,10 +15,17 @@
* limitations under the License. * limitations under the License.
*/ */
import { Button, Form, message, Modal, Select } from "antd"; import {Button, Form, message, Modal, Select} from "antd";
import React, { useEffect, useState } from "react"; import React, {useEffect, useState} from "react";
const SkipMessageAccumulateDialog = ({ visible, onClose, topic, allConsumerGroupList, handleSkipMessageAccumulate, t }) => { const SkipMessageAccumulateDialog = ({
visible,
onClose,
topic,
allConsumerGroupList,
handleSkipMessageAccumulate,
t
}) => {
const [form] = Form.useForm(); const [form] = Form.useForm();
const [selectedConsumerGroup, setSelectedConsumerGroup] = useState([]); const [selectedConsumerGroup, setSelectedConsumerGroup] = useState([]);
@@ -52,14 +59,14 @@ const SkipMessageAccumulateDialog = ({ visible, onClose, topic, allConsumerGroup
</Button>, </Button>,
]} ]}
> >
<Form form={form} layout="horizontal" labelCol={{ span: 6 }} wrapperCol={{ span: 18 }}> <Form form={form} layout="horizontal" labelCol={{span: 6}} wrapperCol={{span: 18}}>
<Form.Item label={t.SUBSCRIPTION_GROUP} required> <Form.Item label={t.SUBSCRIPTION_GROUP} required>
<Select <Select
mode="multiple" mode="multiple"
placeholder={t.SELECT_CONSUMER_GROUP} placeholder={t.SELECT_CONSUMER_GROUP}
value={selectedConsumerGroup} value={selectedConsumerGroup}
onChange={setSelectedConsumerGroup} onChange={setSelectedConsumerGroup}
options={allConsumerGroupList.map(group => ({ value: group, label: group }))} options={allConsumerGroupList.map(group => ({value: group, label: group}))}
/> />
</Form.Item> </Form.Item>
</Form> </Form>

View File

@@ -19,11 +19,11 @@ import moment from "moment/moment";
import {Button, Modal, Table} from "antd"; import {Button, Modal, Table} from "antd";
import React from "react"; import React from "react";
const StatsViewDialog = ({ visible, onClose, topic, statsData, t }) => { const StatsViewDialog = ({visible, onClose, topic, statsData, t}) => {
const columns = [ const columns = [
{ title: t.QUEUE, dataIndex: 'queue', key: 'queue', align: 'center' }, {title: t.QUEUE, dataIndex: 'queue', key: 'queue', align: 'center'},
{ title: t.MIN_OFFSET, dataIndex: 'minOffset', key: 'minOffset', align: 'center' }, {title: t.MIN_OFFSET, dataIndex: 'minOffset', key: 'minOffset', align: 'center'},
{ title: t.MAX_OFFSET, dataIndex: 'maxOffset', key: 'maxOffset', align: 'center' }, {title: t.MAX_OFFSET, dataIndex: 'maxOffset', key: 'maxOffset', align: 'center'},
{ {
title: t.LAST_UPDATE_TIME_STAMP, title: t.LAST_UPDATE_TIME_STAMP,
dataIndex: 'lastUpdateTimestamp', dataIndex: 'lastUpdateTimestamp',

View File

@@ -16,7 +16,7 @@
*/ */
// TopicModifyDialog.js // TopicModifyDialog.js
import { Button, Modal } from "antd"; import {Button, Modal} from "antd";
import React from "react"; import React from "react";
import TopicSingleModifyForm from './TopicSingleModifyForm'; import TopicSingleModifyForm from './TopicSingleModifyForm';
@@ -43,7 +43,7 @@ const TopicModifyDialog = ({
{t.CLOSE} {t.CLOSE}
</Button>, </Button>,
]} ]}
Style={{ maxHeight: '70vh', overflowY: 'auto' }} Style={{maxHeight: '70vh', overflowY: 'auto'}}
> >
{initialData.map((data, index) => ( {initialData.map((data, index) => (
<TopicSingleModifyForm <TopicSingleModifyForm

View File

@@ -16,8 +16,8 @@
*/ */
// TopicSingleModifyForm.js // TopicSingleModifyForm.js
import React, { useEffect } from "react"; import React, {useEffect} from "react";
import {Button, Form, Input, Select, Divider, Row, Col} from "antd"; import {Button, Col, Divider, Form, Input, Row, Select} from "antd";
const TopicSingleModifyForm = ({ const TopicSingleModifyForm = ({
initialData, initialData,
@@ -42,9 +42,9 @@ const TopicSingleModifyForm = ({
const handleFormSubmit = () => { const handleFormSubmit = () => {
form.validateFields() form.validateFields()
.then(values => { .then(values => {
const updatedValues = { ...values }; const updatedValues = {...values};
// 提交时,如果 clusterNameList 或 brokerNameList 为空,则填充所有可用的名称 // 提交时,如果 clusterNameList 或 brokerNameList 为空,则填充所有可用的名称
if(!bIsUpdate){ if (!bIsUpdate) {
if (!updatedValues.clusterNameList || updatedValues.clusterNameList.length === 0) { if (!updatedValues.clusterNameList || updatedValues.clusterNameList.length === 0) {
updatedValues.clusterNameList = allClusterNameList; updatedValues.clusterNameList = allClusterNameList;
} }
@@ -60,84 +60,85 @@ const TopicSingleModifyForm = ({
}; };
const messageTypeOptions = [ const messageTypeOptions = [
{ value: 'TRANSACTION', label: 'TRANSACTION' }, {value: 'TRANSACTION', label: 'TRANSACTION'},
{ value: 'FIFO', label: 'FIFO' }, {value: 'FIFO', label: 'FIFO'},
{ value: 'DELAY', label: 'DELAY' }, {value: 'DELAY', label: 'DELAY'},
{ value: 'NORMAL', label: 'NORMAL' }, {value: 'NORMAL', label: 'NORMAL'},
]; ];
return ( return (
<div style={{ paddingBottom: 24 }}> <div style={{paddingBottom: 24}}>
{bIsUpdate && <Divider orientation="left">{`${t.TOPIC_CONFIG} - ${initialData.brokerNameList ? initialData.brokerNameList.join(', ') : t.UNKNOWN_BROKER}`}</Divider>} {bIsUpdate && <Divider
<Row justify="center"> {/* 使用 Row 居中内容 */} orientation="left">{`${t.TOPIC_CONFIG} - ${initialData.brokerNameList ? initialData.brokerNameList.join(', ') : t.UNKNOWN_BROKER}`}</Divider>}
<Col span={16}> {/* 表单内容占据 12 栅格宽度,并自动居中 */} <Row justify="center"> {/* 使用 Row 居中内容 */}
<Form <Col span={16}> {/* 表单内容占据 12 栅格宽度,并自动居中 */}
form={form} <Form
layout="horizontal" form={form}
labelCol={{ span: 8 }} layout="horizontal"
wrapperCol={{ span: 16 }} labelCol={{span: 8}}
wrapperCol={{span: 16}}
>
<Form.Item label={t.CLUSTER_NAME} name="clusterNameList">
<Select
mode="multiple"
disabled={bIsUpdate}
placeholder={t.SELECT_CLUSTER_NAME}
options={allClusterNameList.map(name => ({value: name, label: name}))}
/>
</Form.Item>
<Form.Item label="BROKER_NAME" name="brokerNameList">
<Select
mode="multiple"
disabled={bIsUpdate}
placeholder={t.SELECT_BROKER_NAME}
options={allBrokerNameList.map(name => ({value: name, label: name}))}
/>
</Form.Item>
<Form.Item
label={t.TOPIC_NAME}
name="topicName"
rules={[{required: true, message: `${t.TOPIC_NAME}${t.CANNOT_BE_EMPTY}`}]}
> >
<Form.Item label={t.CLUSTER_NAME} name="clusterNameList"> <Input disabled={bIsUpdate}/>
<Select </Form.Item>
mode="multiple" <Form.Item label={t.MESSAGE_TYPE} name="messageType">
disabled={bIsUpdate} <Select
placeholder={t.SELECT_CLUSTER_NAME} disabled={bIsUpdate}
options={allClusterNameList.map(name => ({ value: name, label: name }))} options={messageTypeOptions}
/> />
</Form.Item>
<Form.Item
label={t.WRITE_QUEUE_NUMS}
name="writeQueueNums"
rules={[{required: true, message: `${t.WRITE_QUEUE_NUMS}${t.CANNOT_BE_EMPTY}`}]}
>
<Input disabled={!writeOperationEnabled}/>
</Form.Item>
<Form.Item
label={t.READ_QUEUE_NUMS}
name="readQueueNums"
rules={[{required: true, message: `${t.READ_QUEUE_NUMS}${t.CANNOT_BE_EMPTY}`}]}
>
<Input disabled={!writeOperationEnabled}/>
</Form.Item>
<Form.Item
label={t.PERM}
name="perm"
rules={[{required: true, message: `${t.PERM}${t.CANNOT_BE_EMPTY}`}]}
>
<Input disabled={!writeOperationEnabled}/>
</Form.Item>
{!initialData.sysFlag && writeOperationEnabled && (
<Form.Item wrapperCol={{offset: 8, span: 16}}>
<Button type="primary" onClick={handleFormSubmit}>
{t.COMMIT}
</Button>
</Form.Item> </Form.Item>
<Form.Item label="BROKER_NAME" name="brokerNameList"> )}
<Select </Form>
mode="multiple" </Col>
disabled={bIsUpdate} </Row>
placeholder={t.SELECT_BROKER_NAME} </div>
options={allBrokerNameList.map(name => ({ value: name, label: name }))}
/>
</Form.Item>
<Form.Item
label={t.TOPIC_NAME}
name="topicName"
rules={[{ required: true, message: `${t.TOPIC_NAME}${t.CANNOT_BE_EMPTY}` }]}
>
<Input disabled={bIsUpdate} />
</Form.Item>
<Form.Item label={t.MESSAGE_TYPE} name="messageType">
<Select
disabled={bIsUpdate}
options={messageTypeOptions}
/>
</Form.Item>
<Form.Item
label={t.WRITE_QUEUE_NUMS}
name="writeQueueNums"
rules={[{ required: true, message: `${t.WRITE_QUEUE_NUMS}${t.CANNOT_BE_EMPTY}` }]}
>
<Input disabled={!writeOperationEnabled} />
</Form.Item>
<Form.Item
label={t.READ_QUEUE_NUMS}
name="readQueueNums"
rules={[{ required: true, message: `${t.READ_QUEUE_NUMS}${t.CANNOT_BE_EMPTY}` }]}
>
<Input disabled={!writeOperationEnabled} />
</Form.Item>
<Form.Item
label={t.PERM}
name="perm"
rules={[{ required: true, message: `${t.PERM}${t.CANNOT_BE_EMPTY}` }]}
>
<Input disabled={!writeOperationEnabled} />
</Form.Item>
{!initialData.sysFlag && writeOperationEnabled && (
<Form.Item wrapperCol={{ offset: 8, span: 16 }}>
<Button type="primary" onClick={handleFormSubmit}>
{t.COMMIT}
</Button>
</Form.Item>
)}
</Form>
</Col>
</Row>
</div>
); );
}; };

View File

@@ -15,20 +15,21 @@
* limitations under the License. * limitations under the License.
*/ */
import React, { createContext, useState, useContext } from 'react'; import React, {createContext, useContext, useState} from 'react';
import { translations } from '../i18n'; import {translations} from '../i18n';
const LanguageContext = createContext({ const LanguageContext = createContext({
lang: 'en', lang: 'en',
setLang: () => {}, setLang: () => {
},
t: translations['en'], // 当前语言的文本资源 t: translations['en'], // 当前语言的文本资源
}); });
export const LanguageProvider = ({ children }) => { export const LanguageProvider = ({children}) => {
const [lang, setLang] = useState('en'); const [lang, setLang] = useState('en');
const t = translations[lang] || translations['en']; const t = translations[lang] || translations['en'];
return ( return (
<LanguageContext.Provider value={{ lang, setLang, t }}> <LanguageContext.Provider value={{lang, setLang, t}}>
{children} {children}
</LanguageContext.Provider> </LanguageContext.Provider>
); );

View File

@@ -47,10 +47,10 @@ export const translations = {
"FETCH_TOPIC_FAILED": "获取主题列表失败", "FETCH_TOPIC_FAILED": "获取主题列表失败",
"CONFIRM_DELETE": "确认删除", "CONFIRM_DELETE": "确认删除",
"CANCEL": "取消", "CANCEL": "取消",
"SELECT_DELETE_BROKERS":"请选择在哪个Broker删除消费者组", "SELECT_DELETE_BROKERS": "请选择在哪个Broker删除消费者组",
"DELETE_CONSUMER_GROUP":"删除消费者组", "DELETE_CONSUMER_GROUP": "删除消费者组",
"ENGLISH": "英文", "ENGLISH": "英文",
"ADD_CONSUMER":"添加消费者", "ADD_CONSUMER": "添加消费者",
"CHINESE": "简体中文", "CHINESE": "简体中文",
"CANNOT_BE_EMPTY": "不能为空", "CANNOT_BE_EMPTY": "不能为空",
"TITLE": "RocketMQ仪表板", "TITLE": "RocketMQ仪表板",
@@ -70,16 +70,16 @@ export const translations = {
"CLUSTER_DETAIL": "集群详情", "CLUSTER_DETAIL": "集群详情",
"COMMIT": "提交", "COMMIT": "提交",
"TOPIC": "主题", "TOPIC": "主题",
"SUBSCRIPTION_GROUP":"订阅组", "SUBSCRIPTION_GROUP": "订阅组",
"PRODUCER_GROUP":"生产组", "PRODUCER_GROUP": "生产组",
"CONSUMER":"消费者", "CONSUMER": "消费者",
"PRODUCER":"生产者", "PRODUCER": "生产者",
"MESSAGE":"消息", "MESSAGE": "消息",
"MESSAGE_DETAIL":"消息详情", "MESSAGE_DETAIL": "消息详情",
"RESEND_MESSAGE":"重新发送", "RESEND_MESSAGE": "重新发送",
"VIEW_EXCEPTION":"查看异常", "VIEW_EXCEPTION": "查看异常",
"DLQ_MESSAGE":"死信消息", "DLQ_MESSAGE": "死信消息",
"MESSAGETRACE":"消息轨迹", "MESSAGETRACE": "消息轨迹",
"OPERATION": "操作", "OPERATION": "操作",
"ADD": "新增", "ADD": "新增",
"UPDATE": "更新", "UPDATE": "更新",
@@ -89,7 +89,7 @@ export const translations = {
"CONFIG": "配置", "CONFIG": "配置",
"SEND_MSG": "发送消息", "SEND_MSG": "发送消息",
"RESET_CUS_OFFSET": "重置消费位点", "RESET_CUS_OFFSET": "重置消费位点",
"SKIP_MESSAGE_ACCUMULATE":"跳过堆积", "SKIP_MESSAGE_ACCUMULATE": "跳过堆积",
"DELETE": "删除", "DELETE": "删除",
"CHANGE_LANG": "更换语言", "CHANGE_LANG": "更换语言",
"CHANGE_VERSION": "更换版本", "CHANGE_VERSION": "更换版本",
@@ -100,73 +100,72 @@ export const translations = {
"TRANSACTION": "事务", "TRANSACTION": "事务",
"UNSPECIFIED": "未指定", "UNSPECIFIED": "未指定",
"DLQ": "死信", "DLQ": "死信",
"QUANTITY":"数量", "QUANTITY": "数量",
"TYPE":"类型", "TYPE": "类型",
"MODE":"模式", "MODE": "模式",
"DELAY":"延迟", "DELAY": "延迟",
"DASHBOARD":"驾驶舱", "DASHBOARD": "驾驶舱",
"CONSUME_DETAIL":"消费详情", "CONSUME_DETAIL": "消费详情",
"CLIENT":"终端", "CLIENT": "终端",
"LAST_CONSUME_TIME":"最后消费时间", "LAST_CONSUME_TIME": "最后消费时间",
"TIME":"时间点", "TIME": "时间点",
"RESET":"重置", "RESET": "重置",
"DATE":"日期", "DATE": "日期",
"NO_DATA":"暂无数据", "NO_DATA": "暂无数据",
"SEARCH":"搜索", "SEARCH": "搜索",
"BEGIN":"开始", "BEGIN": "开始",
"END":"结束", "END": "结束",
"TOPIC_CHANGE":"修改主题", "TOPIC_CHANGE": "修改主题",
"SEND":"发送", "SEND": "发送",
"SUBSCRIPTION_CHANGE":"修改订阅", "SUBSCRIPTION_CHANGE": "修改订阅",
"QUEUE":"队列", "QUEUE": "队列",
"MIN_OFFSET":"最小位点", "MIN_OFFSET": "最小位点",
"MAX_OFFSET":"最大位点", "MAX_OFFSET": "最大位点",
"LAST_UPDATE_TIME_STAMP":"上次更新时间", "LAST_UPDATE_TIME_STAMP": "上次更新时间",
"QUEUE_DATAS":"队列信息", "QUEUE_DATAS": "队列信息",
"READ_QUEUE_NUMS":"读队列数量", "READ_QUEUE_NUMS": "读队列数量",
"WRITE_QUEUE_NUMS":"写队列数量", "WRITE_QUEUE_NUMS": "写队列数量",
"PERM":"perm", "PERM": "perm",
"TAG":"标签", "TAG": "标签",
"KEY":"值", "KEY": "值",
"MESSAGE_BODY":"消息主体", "MESSAGE_BODY": "消息主体",
"TOPIC_NAME":"主题名", "TOPIC_NAME": "主题名",
"ORDER":"顺序", "ORDER": "顺序",
"CONSUMER_CLIENT":"消费者终端", "CONSUMER_CLIENT": "消费者终端",
"BROKER_OFFSET":"代理者位点", "BROKER_OFFSET": "代理者位点",
"CONSUMER_OFFSET":"消费者位点", "CONSUMER_OFFSET": "消费者位点",
"DIFF_TOTAL":"差值", "DIFF_TOTAL": "差值",
"LAST_TIME_STAMP":"上次时间", "LAST_TIME_STAMP": "上次时间",
"RESET_OFFSET":"重置位点", "RESET_OFFSET": "重置位点",
"CLUSTER_NAME":"集群名", "CLUSTER_NAME": "集群名",
"OPS":"运维", "OPS": "运维",
"PROXY":"代理", "PROXY": "代理",
"AUTO_REFRESH":"自动刷新", "AUTO_REFRESH": "自动刷新",
"REFRESH":"刷新", "REFRESH": "刷新",
"LOGOUT":"退出", "LOGOUT": "退出",
"LOGIN":"登录", "LOGIN": "登录",
"USER_NAME":"用户名", "USER_NAME": "用户名",
"PASSWORD":"密码", "PASSWORD": "密码",
"SYSTEM":"系统", "SYSTEM": "系统",
"WELCOME":"您好欢迎使用RocketMQ仪表盘", "WELCOME": "您好欢迎使用RocketMQ仪表盘",
"ENABLE_MESSAGE_TRACE":"开启消息轨迹", "ENABLE_MESSAGE_TRACE": "开启消息轨迹",
"MESSAGE_TRACE_DETAIL":"消息轨迹详情", "MESSAGE_TRACE_DETAIL": "消息轨迹详情",
"TRACE_TOPIC":"消息轨迹主题", "TRACE_TOPIC": "消息轨迹主题",
"SELECT_TRACE_TOPIC":"选择消息轨迹主题", "SELECT_TRACE_TOPIC": "选择消息轨迹主题",
"EXPORT": "导出", "EXPORT": "导出",
"NO_MATCH_RESULT": "没有查到符合条件的结果", "NO_MATCH_RESULT": "没有查到符合条件的结果",
"BATCH_RESEND": "批量重发", "BATCH_RESEND": "批量重发",
"BATCH_EXPORT": "批量导出", "BATCH_EXPORT": "批量导出",
"WHITE_LIST":"白名单", "ACCOUNT_INFO": "账户信息",
"ACCOUNT_INFO":"账户信息", "IS_ADMIN": "是否管理员",
"IS_ADMIN":"是否管理员", "DEFAULT_TOPIC_PERM": "topic默认权限",
"DEFAULT_TOPIC_PERM":"topic默认权限", "DEFAULT_GROUP_PERM": "消费组默认权限",
"DEFAULT_GROUP_PERM":"消费组默认权限", "TOPIC_PERM": "topic权限",
"TOPIC_PERM":"topic权限", "GROUP_PERM": "消费组权限",
"GROUP_PERM":"消费组权限", "SYNCHRONIZE": "同步",
"SYNCHRONIZE":"同步", "SHOW": "显示",
"SHOW":"显示", "HIDE": "隐藏",
"HIDE":"隐藏", "MESSAGE_TYPE": "消息类型",
"MESSAGE_TYPE":"消息类型",
"MESSAGE_TYPE_UNSPECIFIED": "未指定,为普通消息", "MESSAGE_TYPE_UNSPECIFIED": "未指定,为普通消息",
"MESSAGE_TYPE_NORMAL": "普通消息", "MESSAGE_TYPE_NORMAL": "普通消息",
"MESSAGE_TYPE_FIFO": "顺序消息", "MESSAGE_TYPE_FIFO": "顺序消息",
@@ -294,7 +293,7 @@ export const translations = {
"SELECT_TOPIC_PLACEHOLDER": "Please select topic", "SELECT_TOPIC_PLACEHOLDER": "Please select topic",
"MESSAGE_ID_TOPIC_HINT": "Message ID Topic", "MESSAGE_ID_TOPIC_HINT": "Message ID Topic",
"TOPIC_ADD": "Add Topic", "TOPIC_ADD": "Add Topic",
"SKIP_MESSAGE_ACCUMULATE":"Skip Message Accumulate", "SKIP_MESSAGE_ACCUMULATE": "Skip Message Accumulate",
"OPERATION_FAILED": "Operation Failed", "OPERATION_FAILED": "Operation Failed",
"FORM_VALIDATION_FAILED": "Form Validation Failed", "FORM_VALIDATION_FAILED": "Form Validation Failed",
"ADD_CONSUMER": "Add Consumer", "ADD_CONSUMER": "Add Consumer",
@@ -325,7 +324,7 @@ export const translations = {
"ADDRESS": "Address", "ADDRESS": "Address",
"VERSION": "Version", "VERSION": "Version",
"PRO_MSG_TPS": "Produce Message TPS", "PRO_MSG_TPS": "Produce Message TPS",
"CUS_MSG_TPS": "Consume Message TPS", "CUS_MSG_TPS": "Consumer Message TPS",
"YESTERDAY_PRO_COUNT": "Yesterday Produce Count", "YESTERDAY_PRO_COUNT": "Yesterday Produce Count",
"YESTERDAY_CUS_COUNT": "Yesterday Consume Count", "YESTERDAY_CUS_COUNT": "Yesterday Consume Count",
"TODAY_PRO_COUNT": "Today Produce Count", "TODAY_PRO_COUNT": "Today Produce Count",
@@ -335,16 +334,16 @@ export const translations = {
"CLUSTER": "Cluster", "CLUSTER": "Cluster",
"CLUSTER_DETAIL": "Cluster Detail", "CLUSTER_DETAIL": "Cluster Detail",
"TOPIC": "Topic", "TOPIC": "Topic",
"SUBSCRIPTION_GROUP":"SubscriptionGroup", "SUBSCRIPTION_GROUP": "SubscriptionGroup",
"PRODUCER_GROUP":"ProducerGroup", "PRODUCER_GROUP": "ProducerGroup",
"CONSUMER":"Consumer", "CONSUMER": "Consumer",
"PRODUCER":"Producer", "PRODUCER": "Producer",
"MESSAGE":"Message", "MESSAGE": "Message",
"MESSAGE_DETAIL":"Message Detail", "MESSAGE_DETAIL": "Message Detail",
"RESEND_MESSAGE":"Resend Message", "RESEND_MESSAGE": "Resend Message",
"VIEW_EXCEPTION":"View Exception", "VIEW_EXCEPTION": "View Exception",
"MESSAGETRACE":"MessageTrace", "MESSAGETRACE": "MessageTrace",
"DLQ_MESSAGE":"DLQMessage", "DLQ_MESSAGE": "DLQMessage",
"COMMIT": "Commit", "COMMIT": "Commit",
"OPERATION": "Operation", "OPERATION": "Operation",
"ADD": "Add", "ADD": "Add",
@@ -365,73 +364,72 @@ export const translations = {
"TRANSACTION": "TRANSACTION", "TRANSACTION": "TRANSACTION",
"UNSPECIFIED": "UNSPECIFIED", "UNSPECIFIED": "UNSPECIFIED",
"DLQ": "DLQ", "DLQ": "DLQ",
"QUANTITY":"Quantity", "QUANTITY": "Quantity",
"TYPE":"Type", "TYPE": "Type",
"MODE":"Mode", "MODE": "Mode",
"DELAY":"Delay", "DELAY": "Delay",
"DASHBOARD":"Dashboard", "DASHBOARD": "Dashboard",
"CONSUME_DETAIL":"CONSUME DETAIL", "CONSUME_DETAIL": "CONSUME DETAIL",
"CLIENT":"CLIENT", "CLIENT": "CLIENT",
"LAST_CONSUME_TIME":"LastConsumeTime", "LAST_CONSUME_TIME": "LastConsumeTime",
"TIME":"Time", "TIME": "Time",
"RESET":"RESET", "RESET": "RESET",
"DATE":"Date", "DATE": "Date",
"NO_DATA":"NO DATA", "NO_DATA": "NO DATA",
"SEARCH":"Search", "SEARCH": "Search",
"BEGIN":"Begin", "BEGIN": "Begin",
"END":"End", "END": "End",
"TOPIC_CHANGE":"Topic Change", "TOPIC_CHANGE": "Topic Change",
"SEND":"Send", "SEND": "Send",
"SUBSCRIPTION_CHANGE":"Subscription Change", "SUBSCRIPTION_CHANGE": "Subscription Change",
"QUEUE":"Queue", "QUEUE": "Queue",
"MIN_OFFSET":"minOffset", "MIN_OFFSET": "minOffset",
"MAX_OFFSET":"maxOffset", "MAX_OFFSET": "maxOffset",
"LAST_UPDATE_TIME_STAMP":"lastUpdateTimeStamp", "LAST_UPDATE_TIME_STAMP": "lastUpdateTimeStamp",
"QUEUE_DATAS":"queueDatas", "QUEUE_DATAS": "queueDatas",
"READ_QUEUE_NUMS":"readQueueNums", "READ_QUEUE_NUMS": "readQueueNums",
"WRITE_QUEUE_NUMS":"writeQueueNums", "WRITE_QUEUE_NUMS": "writeQueueNums",
"PERM":"perm", "PERM": "perm",
"TAG":"Tag", "TAG": "Tag",
"KEY":"Key", "KEY": "Key",
"MESSAGE_BODY":"Message Body", "MESSAGE_BODY": "Message Body",
"TOPIC_NAME":"topicName", "TOPIC_NAME": "topicName",
"ORDER":"order", "ORDER": "order",
"CONSUMER_CLIENT":"consumerClient", "CONSUMER_CLIENT": "consumerClient",
"BROKER_OFFSET":"brokerOffset", "BROKER_OFFSET": "brokerOffset",
"CONSUMER_OFFSET":"consumerOffset", "CONSUMER_OFFSET": "consumerOffset",
"DIFF_TOTAL":"diffTotal", "DIFF_TOTAL": "diffTotal",
"LAST_TIME_STAMP":"lastTimeStamp", "LAST_TIME_STAMP": "lastTimeStamp",
"RESET_OFFSET":"resetOffset", "RESET_OFFSET": "resetOffset",
"CLUSTER_NAME":"clusterName", "CLUSTER_NAME": "clusterName",
"OPS":"OPS", "OPS": "OPS",
"PROXY":"Proxy", "PROXY": "Proxy",
"AUTO_REFRESH":"AUTO_REFRESH", "AUTO_REFRESH": "AUTO_REFRESH",
"REFRESH":"REFRESH", "REFRESH": "REFRESH",
"LOGOUT":"Logout", "LOGOUT": "Logout",
"LOGIN":"Login", "LOGIN": "Login",
"USER_NAME":"Username", "USER_NAME": "Username",
"PASSWORD":"Password", "PASSWORD": "Password",
"SYSTEM":"SYSTEM", "SYSTEM": "SYSTEM",
"WELCOME":"Hi, welcome using RocketMQ Dashboard", "WELCOME": "Hi, welcome using RocketMQ Dashboard",
"ENABLE_MESSAGE_TRACE":"Enable Message Trace", "ENABLE_MESSAGE_TRACE": "Enable Message Trace",
"MESSAGE_TRACE_DETAIL":"Message Trace Detail", "MESSAGE_TRACE_DETAIL": "Message Trace Detail",
"TRACE_TOPIC":"TraceTopic", "TRACE_TOPIC": "TraceTopic",
"SELECT_TRACE_TOPIC":"selectTraceTopic", "SELECT_TRACE_TOPIC": "selectTraceTopic",
"EXPORT": "export", "EXPORT": "export",
"NO_MATCH_RESULT": "no match result", "NO_MATCH_RESULT": "no match result",
"BATCH_RESEND": "batchReSend", "BATCH_RESEND": "batchReSend",
"BATCH_EXPORT": "batchExport", "BATCH_EXPORT": "batchExport",
"WHITE_LIST":"White List", "ACCOUNT_INFO": "Account Info",
"ACCOUNT_INFO":"Account Info", "IS_ADMIN": "Is Admin",
"IS_ADMIN":"Is Admin", "DEFAULT_TOPIC_PERM": "Default Topic Permission",
"DEFAULT_TOPIC_PERM":"Default Topic Permission", "DEFAULT_GROUP_PERM": "Default Group Permission",
"DEFAULT_GROUP_PERM":"Default Group Permission", "TOPIC_PERM": "Topic Permission",
"TOPIC_PERM":"Topic Permission", "GROUP_PERM": "Group Permission",
"GROUP_PERM":"Group Permission", "SYNCHRONIZE": "Synchronize Data",
"SYNCHRONIZE":"Synchronize Data", "SHOW": "Show",
"SHOW":"Show", "HIDE": "Hide",
"HIDE":"Hide", "MESSAGE_TYPE": "messageType",
"MESSAGE_TYPE":"messageType",
"MESSAGE_TYPE_UNSPECIFIED": "UNSPECIFIED, is NORMAL", "MESSAGE_TYPE_UNSPECIFIED": "UNSPECIFIED, is NORMAL",
"MESSAGE_TYPE_NORMAL": "NORMAL", "MESSAGE_TYPE_NORMAL": "NORMAL",
"MESSAGE_TYPE_FIFO": "FIFO", "MESSAGE_TYPE_FIFO": "FIFO",

View File

@@ -16,15 +16,15 @@
*/ */
body { body {
margin: 0; margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif; sans-serif;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
code { code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace; monospace;
} }

View File

@@ -19,7 +19,7 @@ import React from 'react';
import ReactDOM from 'react-dom/client'; import ReactDOM from 'react-dom/client';
import './index.css'; import './index.css';
import App from './App'; import App from './App';
import { App as AntdApp } from 'antd'; import {App as AntdApp} from 'antd';
import reportWebVitals from './reportWebVitals'; import reportWebVitals from './reportWebVitals';
import {LanguageProvider} from "./i18n/LanguageContext"; import {LanguageProvider} from "./i18n/LanguageContext";
import {Provider} from "react-redux"; import {Provider} from "react-redux";
@@ -27,17 +27,15 @@ import store from './store';
const root = ReactDOM.createRoot(document.getElementById('root')); const root = ReactDOM.createRoot(document.getElementById('root'));
root.render( root.render(
<LanguageProvider> <LanguageProvider>
<React.StrictMode> <React.StrictMode>
<AntdApp> <AntdApp>
<Provider store={store}> <Provider store={store}>
<App/> <App/>
</Provider> </Provider>
</AntdApp> </AntdApp>
</React.StrictMode> </React.StrictMode>
</LanguageProvider> </LanguageProvider>
); );
// If you want to start measuring performance in your app, pass a function // If you want to start measuring performance in your app, pass a function

View File

@@ -44,7 +44,7 @@ const ConsumerGroupList = () => {
const [isAddConfig, setIsAddConfig] = useState(false); const [isAddConfig, setIsAddConfig] = useState(false);
const [showDeleteModal, setShowDeleteModal] = useState(false); const [showDeleteModal, setShowDeleteModal] = useState(false);
const [messageApi, msgContextHolder] = message.useMessage(); const [messageApi, msgContextHolder] = message.useMessage();
const [notificationApi,notificationContextHolder] = notification.useNotification(); const [notificationApi, notificationContextHolder] = notification.useNotification();
const [paginationConf, setPaginationConf] = useState({ const [paginationConf, setPaginationConf] = useState({
current: 1, current: 1,
@@ -63,9 +63,9 @@ const ConsumerGroupList = () => {
const response = await remoteApi.queryConsumerGroupList(false); const response = await remoteApi.queryConsumerGroupList(false);
if (response.status === 0) { if (response.status === 0) {
setAllConsumerGroupList(response.data); setAllConsumerGroupList(response.data);
if(currentPage!=null){ if (currentPage != null) {
filterList(currentPage, response.data); filterList(currentPage, response.data);
}else{ } else {
filterList(1, response.data); filterList(1, response.data);
} }
} else { } else {
@@ -380,7 +380,7 @@ const ConsumerGroupList = () => {
filterList(pagination.current, allConsumerGroupList); filterList(pagination.current, allConsumerGroupList);
}; };
const closeConfigModal = () =>{ const closeConfigModal = () => {
setShowConfig(false); setShowConfig(false);
setIsAddConfig(false); setIsAddConfig(false);
} }

View File

@@ -16,17 +16,17 @@
*/ */
import React from 'react'; import React from 'react';
import { Form, Input, Button, message, Typography } from 'antd'; import {Button, Form, Input, message, Typography} from 'antd';
import {remoteApi} from "../../api/remoteApi/remoteApi"; import {remoteApi} from "../../api/remoteApi/remoteApi";
const { Title } = Typography; const {Title} = Typography;
const Login = () => { const Login = () => {
const [form] = Form.useForm(); const [form] = Form.useForm();
const [messageApi, msgContextHolder] = message.useMessage(); const [messageApi, msgContextHolder] = message.useMessage();
const onFinish = async (values) => { const onFinish = async (values) => {
const { username, password } = values; const {username, password} = values;
remoteApi.login(username, password).then((res) => { remoteApi.login(username, password).then((res) => {
if (res.status === 0) { if (res.status === 0) {
messageApi.success('登录成功'); messageApi.success('登录成功');

View File

@@ -15,12 +15,12 @@
* limitations under the License. * limitations under the License.
*/ */
import React, { useState, useEffect } from 'react'; import React, {useEffect, useState} from 'react';
import { Select, Button, Switch, Input, Typography, Space, message } from 'antd'; import {Button, Input, message, Select, Space, Switch, Typography} from 'antd';
import {remoteApi} from '../../api/remoteApi/remoteApi'; import {remoteApi} from '../../api/remoteApi/remoteApi';
const { Title } = Typography; const {Title} = Typography;
const { Option } = Select; const {Option} = Select;
const Ops = () => { const Ops = () => {
const [namesrvAddrList, setNamesrvAddrList] = useState([]); const [namesrvAddrList, setNamesrvAddrList] = useState([]);

View File

@@ -15,16 +15,16 @@
* limitations under the License. * limitations under the License.
*/ */
import React, { useState, useEffect } from 'react'; import React, {useEffect, useState} from 'react';
import { Modal, Button, Select, Input, Card, Row, Col, notification, Spin } from 'antd'; import {Button, Card, Col, Input, Modal, notification, Row, Select, Spin} from 'antd';
import { useLanguage } from '../../i18n/LanguageContext'; import {useLanguage} from '../../i18n/LanguageContext';
import { remoteApi } from "../../api/remoteApi/remoteApi"; import {remoteApi} from "../../api/remoteApi/remoteApi";
const { Option } = Select; const {Option} = Select;
const ProxyManager = () => { const ProxyManager = () => {
const { t } = useLanguage(); const {t} = useLanguage();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [proxyAddrList, setProxyAddrList] = useState([]); const [proxyAddrList, setProxyAddrList] = useState([]);
@@ -47,7 +47,7 @@ const ProxyManager = () => {
remoteApi.queryProxyHomePage((resp) => { remoteApi.queryProxyHomePage((resp) => {
setLoading(false); setLoading(false);
if (resp.status === 0) { if (resp.status === 0) {
const { proxyAddrList, currentProxyAddr } = resp.data; const {proxyAddrList, currentProxyAddr} = resp.data;
setProxyAddrList(proxyAddrList || []); setProxyAddrList(proxyAddrList || []);
setSelectedProxy(currentProxyAddr || (proxyAddrList && proxyAddrList.length > 0 ? proxyAddrList[0] : '')); setSelectedProxy(currentProxyAddr || (proxyAddrList && proxyAddrList.length > 0 ? proxyAddrList[0] : ''));
@@ -58,7 +58,7 @@ const ProxyManager = () => {
} }
} else { } else {
notificationApi.error({ message: resp.errMsg || t.FETCH_PROXY_LIST_FAILED, duration: 2 }); notificationApi.error({message: resp.errMsg || t.FETCH_PROXY_LIST_FAILED, duration: 2});
} }
}); });
}, [t]); }, [t]);
@@ -71,7 +71,10 @@ const ProxyManager = () => {
const handleAddProxyAddr = () => { const handleAddProxyAddr = () => {
if (!newProxyAddr.trim()) { if (!newProxyAddr.trim()) {
notificationApi.warning({ message: t.INPUT_PROXY_ADDR_REQUIRED || "Please input a new proxy address.", duration: 2 }); notificationApi.warning({
message: t.INPUT_PROXY_ADDR_REQUIRED || "Please input a new proxy address.",
duration: 2
});
return; return;
} }
setLoading(true); setLoading(true);
@@ -82,28 +85,28 @@ const ProxyManager = () => {
setProxyAddrList(prevList => [...prevList, newProxyAddr.trim()]); setProxyAddrList(prevList => [...prevList, newProxyAddr.trim()]);
} }
setNewProxyAddr(''); setNewProxyAddr('');
notificationApi.info({ message: t.SUCCESS || "SUCCESS", duration: 2 }); notificationApi.info({message: t.SUCCESS || "SUCCESS", duration: 2});
} else { } else {
notificationApi.error({ message: resp.errMsg || t.ADD_PROXY_FAILED, duration: 2 }); notificationApi.error({message: resp.errMsg || t.ADD_PROXY_FAILED, duration: 2});
} }
}); });
}; };
return ( return (
<Spin spinning={loading} tip={t.LOADING}> <Spin spinning={loading} tip={t.LOADING}>
<div className="container-fluid" style={{ padding: '24px' }} id="deployHistoryList"> <div className="container-fluid" style={{padding: '24px'}} id="deployHistoryList">
<Card <Card
title={ title={
<div style={{ fontSize: '20px', fontWeight: 'bold' }}> <div style={{fontSize: '20px', fontWeight: 'bold'}}>
ProxyServerAddressList ProxyServerAddressList
</div> </div>
} }
bordered={false} bordered={false}
> >
<Row gutter={[16, 16]} align="middle"> <Row gutter={[16, 16]} align="middle">
<Col flex="auto" style={{ minWidth: 300, maxWidth: 500 }}> <Col flex="auto" style={{minWidth: 300, maxWidth: 500}}>
<Select <Select
style={{ width: '100%' }} style={{width: '100%'}}
value={selectedProxy} value={selectedProxy}
onChange={handleSelectChange} onChange={handleSelectChange}
placeholder={t.SELECT} placeholder={t.SELECT}
@@ -122,14 +125,14 @@ const ProxyManager = () => {
</Row> </Row>
{writeOperationEnabled && ( {writeOperationEnabled && (
<Row gutter={[16, 16]} align="middle" style={{ marginTop: 16 }}> <Row gutter={[16, 16]} align="middle" style={{marginTop: 16}}>
<Col> <Col>
<label htmlFor="newProxyAddrInput">ProxyAddr:</label> <label htmlFor="newProxyAddrInput">ProxyAddr:</label>
</Col> </Col>
<Col> <Col>
<Input <Input
id="newProxyAddrInput" id="newProxyAddrInput"
style={{ width: 300 }} style={{width: 300}}
value={newProxyAddr} value={newProxyAddr}
onChange={(e) => setNewProxyAddr(e.target.value)} onChange={(e) => setNewProxyAddr(e.target.value)}
placeholder={t.INPUT_PROXY_ADDR} placeholder={t.INPUT_PROXY_ADDR}
@@ -149,25 +152,26 @@ const ProxyManager = () => {
onCancel={() => setShowModal(false)} onCancel={() => setShowModal(false)}
title={`${t.PROXY_CONFIG} [${selectedProxy}]`} title={`${t.PROXY_CONFIG} [${selectedProxy}]`}
footer={ footer={
<div style={{ textAlign: 'center' }}> <div style={{textAlign: 'center'}}>
<Button onClick={() => setShowModal(false)}>{t.CLOSE}</Button> <Button onClick={() => setShowModal(false)}>{t.CLOSE}</Button>
</div> </div>
} }
width={800} width={800}
bodyStyle={{ maxHeight: '60vh', overflowY: 'auto' }} bodyStyle={{maxHeight: '60vh', overflowY: 'auto'}}
> >
<table className="table table-bordered" style={{ width: '100%' }}> <table className="table table-bordered" style={{width: '100%'}}>
<tbody> <tbody>
{Object.entries(allProxyConfig).length > 0 ? ( {Object.entries(allProxyConfig).length > 0 ? (
Object.entries(allProxyConfig).map(([key, value]) => ( Object.entries(allProxyConfig).map(([key, value]) => (
<tr key={key}> <tr key={key}>
<td style={{ fontWeight: 500, width: '30%' }}>{key}</td> <td style={{fontWeight: 500, width: '30%'}}>{key}</td>
<td>{value}</td> <td>{value}</td>
</tr> </tr>
)) ))
) : ( ) : (
<tr> <tr>
<td colSpan="2" style={{ textAlign: 'center' }}>{t.NO_CONFIG_DATA || "No configuration data available."}</td> <td colSpan="2"
style={{textAlign: 'center'}}>{t.NO_CONFIG_DATA || "No configuration data available."}</td>
</tr> </tr>
)} )}
</tbody> </tbody>

View File

@@ -173,7 +173,6 @@ const DeployHistoryList = () => {
}; };
const filterList = (currentPage) => { const filterList = (currentPage) => {
const lowExceptStr = filterStr.toLowerCase(); const lowExceptStr = filterStr.toLowerCase();
const canShowList = allTopicList.filter((topic, index) => { const canShowList = allTopicList.filter((topic, index) => {
@@ -223,7 +222,7 @@ const DeployHistoryList = () => {
try { try {
if (isUpdate) { if (isUpdate) {
// topic 已经是字符串 // topic 已经是字符串
const configResult = await remoteApi.getTopicConfig(topic); const configResult = await remoteApi.getTopicConfig(topic);
if (configResult.status === 0) { if (configResult.status === 0) {
const dataToSet = Array.isArray(configResult.data) ? configResult.data : [configResult.data]; const dataToSet = Array.isArray(configResult.data) ? configResult.data : [configResult.data];
@@ -257,7 +256,7 @@ const DeployHistoryList = () => {
return; return;
} }
if(!isUpdate){ if (!isUpdate) {
const clusterResult = await remoteApi.getClusterList(); const clusterResult = await remoteApi.getClusterList();
if (clusterResult.status === 0) { if (clusterResult.status === 0) {
setAllClusterNameList(Object.keys(clusterResult.data.clusterInfo.clusterAddrTable)); setAllClusterNameList(Object.keys(clusterResult.data.clusterInfo.clusterAddrTable));
@@ -276,7 +275,7 @@ const DeployHistoryList = () => {
if (result.status === 0) { if (result.status === 0) {
messageApi.success(t.TOPIC_OPERATION_SUCCESS); messageApi.success(t.TOPIC_OPERATION_SUCCESS);
closeAddUpdateDialog(); closeAddUpdateDialog();
if(!isUpdateMode) { if (!isUpdateMode) {
await getTopicList() await getTopicList()
} }
} else { } else {

View File

@@ -16,15 +16,15 @@
*/ */
const reportWebVitals = onPerfEntry => { const reportWebVitals = onPerfEntry => {
if (onPerfEntry && onPerfEntry instanceof Function) { if (onPerfEntry && onPerfEntry instanceof Function) {
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { import('web-vitals').then(({getCLS, getFID, getFCP, getLCP, getTTFB}) => {
getCLS(onPerfEntry); getCLS(onPerfEntry);
getFID(onPerfEntry); getFID(onPerfEntry);
getFCP(onPerfEntry); getFCP(onPerfEntry);
getLCP(onPerfEntry); getLCP(onPerfEntry);
getTTFB(onPerfEntry); getTTFB(onPerfEntry);
}); });
} }
}; };
export default reportWebVitals; export default reportWebVitals;

View File

@@ -64,7 +64,7 @@ const AppRouter = () => {
useEffect(() => { useEffect(() => {
remoteApi.setRedirectHandler(() => { remoteApi.setRedirectHandler(() => {
navigate('/login', { replace: true }); navigate('/login', {replace: true});
}); });
}, [navigate]); }, [navigate]);

View File

@@ -14,10 +14,10 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { useEffect } from 'react'; import {useEffect} from 'react';
import { useSelector, useDispatch } from 'react-redux'; import {useDispatch, useSelector} from 'react-redux';
import { themes, defaultTheme } from '../../assets/styles/theme'; import {defaultTheme, themes} from '../../assets/styles/theme';
import { setTheme } from '../actions/themeActions'; import {setTheme} from '../actions/themeActions';
export const useTheme = () => { export const useTheme = () => {
// 从 Redux store 中取出 currentThemeName // 从 Redux store 中取出 currentThemeName

View File

@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { createStore,combineReducers } from 'redux'; import {combineReducers, createStore} from 'redux';
import themeReducer from './reducers/themeReducer'; import themeReducer from './reducers/themeReducer';
// 组合所有的 reducers // 组合所有的 reducers

View File

@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { SET_THEME } from '../actions/themeActions'; import {SET_THEME} from '../actions/themeActions';
const getInitialTheme = () => { const getInitialTheme = () => {
return localStorage.getItem('appTheme') || 'default'; return localStorage.getItem('appTheme') || 'default';

View File

@@ -16,7 +16,8 @@
~ limitations under the License. ~ limitations under the License.
--> -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <parent>
<groupId>org.apache</groupId> <groupId>org.apache</groupId>
@@ -432,7 +433,7 @@
</configuration> </configuration>
<executions> <executions>
<execution> <execution>
<id>install node </id> <id>install node</id>
<goals> <goals>
<goal>install-node-and-npm</goal> <goal>install-node-and-npm</goal>
</goals> </goals>
@@ -469,7 +470,7 @@
<configuration> <configuration>
<target> <target>
<copy todir="${project.build.directory}/classes/public"> <copy todir="${project.build.directory}/classes/public">
<fileset dir="${project.basedir}/frontend-new/build" /> <fileset dir="${project.basedir}/frontend-new/build"/>
</copy> </copy>
</target> </target>
</configuration> </configuration>

View File

@@ -1,25 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.dashboard.admin;
import org.apache.rocketmq.tools.admin.MQAdminExt;
@FunctionalInterface
public interface MQAdminExtCallback<T> {
T doInMQAdminExt(MQAdminExt mqAdminExt) throws Exception;
}

View File

@@ -32,7 +32,7 @@ public class MQAdminPooledObjectFactory implements PooledObjectFactory<MQAdminEx
@Override @Override
public PooledObject<MQAdminExt> makeObject() throws Exception { public PooledObject<MQAdminExt> makeObject() throws Exception {
DefaultPooledObject<MQAdminExt> pooledObject = new DefaultPooledObject<>( DefaultPooledObject<MQAdminExt> pooledObject = new DefaultPooledObject<>(
mqAdminFactory.getInstance()); mqAdminFactory.getInstance());
return pooledObject; return pooledObject;
} }

View File

@@ -40,8 +40,8 @@ public class MqAdminExtObjectPool {
MQAdminFactory mqAdminFactory = new MQAdminFactory(rmqConfigure); MQAdminFactory mqAdminFactory = new MQAdminFactory(rmqConfigure);
mqAdminPooledObjectFactory.setMqAdminFactory(mqAdminFactory); mqAdminPooledObjectFactory.setMqAdminFactory(mqAdminFactory);
GenericObjectPool<MQAdminExt> genericObjectPool = new GenericObjectPool<MQAdminExt>( GenericObjectPool<MQAdminExt> genericObjectPool = new GenericObjectPool<MQAdminExt>(
mqAdminPooledObjectFactory, mqAdminPooledObjectFactory,
genericObjectPoolConfig); genericObjectPoolConfig);
return genericObjectPool; return genericObjectPool;
} }
} }

View File

@@ -41,20 +41,20 @@ public class CollectExecutorConfig {
@Bean(name = "collectExecutor") @Bean(name = "collectExecutor")
public ExecutorService collectExecutor(CollectExecutorConfig collectExecutorConfig) { public ExecutorService collectExecutor(CollectExecutorConfig collectExecutorConfig) {
ExecutorService collectExecutor = new ThreadPoolExecutor( ExecutorService collectExecutor = new ThreadPoolExecutor(
collectExecutorConfig.getCoreSize(), collectExecutorConfig.getCoreSize(),
collectExecutorConfig.getMaxSize(), collectExecutorConfig.getMaxSize(),
collectExecutorConfig.getKeepAliveTime(), collectExecutorConfig.getKeepAliveTime(),
TimeUnit.MILLISECONDS, TimeUnit.MILLISECONDS,
new LinkedBlockingDeque<>(collectExecutorConfig.getQueueSize()), new LinkedBlockingDeque<>(collectExecutorConfig.getQueueSize()),
new ThreadFactory() { new ThreadFactory() {
private final AtomicLong threadIndex = new AtomicLong(0); private final AtomicLong threadIndex = new AtomicLong(0);
@Override @Override
public Thread newThread(Runnable r) { public Thread newThread(Runnable r) {
return new Thread(r, "collectTopicThread_" + this.threadIndex.incrementAndGet()); return new Thread(r, "collectTopicThread_" + this.threadIndex.incrementAndGet());
} }
}, },
new ThreadPoolExecutor.DiscardOldestPolicy() new ThreadPoolExecutor.DiscardOldestPolicy()
); );
return collectExecutor; return collectExecutor;
} }

View File

@@ -91,6 +91,10 @@ public class RMQConfigure {
@Getter @Getter
private Integer clientCallbackExecutorThreads = 4; private Integer clientCallbackExecutorThreads = 4;
@Setter
@Getter
private String authMode = "file";
public void setProxyAddrs(List<String> proxyAddrs) { public void setProxyAddrs(List<String> proxyAddrs) {
this.proxyAddrs = proxyAddrs; this.proxyAddrs = proxyAddrs;
if (CollectionUtils.isNotEmpty(proxyAddrs)) { if (CollectionUtils.isNotEmpty(proxyAddrs)) {
@@ -112,10 +116,12 @@ public class RMQConfigure {
logger.info("setNameSrvAddrByProperty nameSrvAddr={}", namesrvAddr); logger.info("setNameSrvAddrByProperty nameSrvAddr={}", namesrvAddr);
} }
} }
public boolean isACLEnabled() { public boolean isACLEnabled() {
return !(StringUtils.isAnyBlank(this.accessKey, this.secretKey) || return !(StringUtils.isAnyBlank(this.accessKey, this.secretKey) ||
StringUtils.isAnyEmpty(this.accessKey, this.secretKey)); StringUtils.isAnyEmpty(this.accessKey, this.secretKey));
} }
public String getRocketMqDashboardDataPath() { public String getRocketMqDashboardDataPath() {
return dataPath; return dataPath;
} }

View File

@@ -54,7 +54,7 @@ public class ConsumerController {
@RequestMapping(value = "/group.refresh") @RequestMapping(value = "/group.refresh")
@ResponseBody @ResponseBody
public Object refresh(String address, public Object refresh(String address,
String consumerGroup) { String consumerGroup) {
return consumerService.refreshGroup(address, consumerGroup); return consumerService.refreshGroup(address, consumerGroup);
} }
@@ -100,7 +100,7 @@ public class ConsumerController {
@ResponseBody @ResponseBody
public Object consumerCreateOrUpdateRequest(@RequestBody ConsumerConfigInfo consumerConfigInfo) { public Object consumerCreateOrUpdateRequest(@RequestBody ConsumerConfigInfo consumerConfigInfo) {
Preconditions.checkArgument(CollectionUtils.isNotEmpty(consumerConfigInfo.getBrokerNameList()) || CollectionUtils.isNotEmpty(consumerConfigInfo.getClusterNameList()), Preconditions.checkArgument(CollectionUtils.isNotEmpty(consumerConfigInfo.getBrokerNameList()) || CollectionUtils.isNotEmpty(consumerConfigInfo.getClusterNameList()),
"clusterName or brokerName can not be all blank"); "clusterName or brokerName can not be all blank");
return consumerService.createAndUpdateSubscriptionGroupConfig(consumerConfigInfo); return consumerService.createAndUpdateSubscriptionGroupConfig(consumerConfigInfo);
} }
@@ -127,7 +127,7 @@ public class ConsumerController {
@RequestMapping(value = "/consumerRunningInfo.query") @RequestMapping(value = "/consumerRunningInfo.query")
@ResponseBody @ResponseBody
public Object getConsumerRunningInfo(@RequestParam String consumerGroup, @RequestParam String clientId, public Object getConsumerRunningInfo(@RequestParam String consumerGroup, @RequestParam String clientId,
@RequestParam boolean jstack) { @RequestParam boolean jstack) {
return consumerService.getConsumerRunningInfo(consumerGroup, clientId, jstack); return consumerService.getConsumerRunningInfo(consumerGroup, clientId, jstack);
} }
} }

View File

@@ -47,7 +47,7 @@ public class DashboardController {
if (Strings.isNullOrEmpty(topicName)) { if (Strings.isNullOrEmpty(topicName)) {
return dashboardService.queryTopicData(date); return dashboardService.queryTopicData(date);
} }
return dashboardService.queryTopicData(date,topicName); return dashboardService.queryTopicData(date, topicName);
} }
@RequestMapping(value = "/topicCurrent.query", method = RequestMethod.GET) @RequestMapping(value = "/topicCurrent.query", method = RequestMethod.GET)

View File

@@ -64,7 +64,7 @@ public class MessageTraceController {
@RequestMapping(value = "/viewMessageTraceGraph.query", method = RequestMethod.GET) @RequestMapping(value = "/viewMessageTraceGraph.query", method = RequestMethod.GET)
@ResponseBody @ResponseBody
public MessageTraceGraph viewMessageTraceGraph(@RequestParam String msgId, public MessageTraceGraph viewMessageTraceGraph(@RequestParam String msgId,
@RequestParam(required = false) String traceTopic) { @RequestParam(required = false) String traceTopic) {
return messageTraceService.queryMessageTraceGraph(msgId, traceTopic); return messageTraceService.queryMessageTraceGraph(msgId, traceTopic);
} }
} }

View File

@@ -40,7 +40,7 @@ public class MonitorController {
@RequestMapping(value = "/createOrUpdateConsumerMonitor.do", method = {RequestMethod.POST}) @RequestMapping(value = "/createOrUpdateConsumerMonitor.do", method = {RequestMethod.POST})
@ResponseBody @ResponseBody
public Object createOrUpdateConsumerMonitor(@RequestParam String consumeGroupName, @RequestParam int minCount, public Object createOrUpdateConsumerMonitor(@RequestParam String consumeGroupName, @RequestParam int minCount,
@RequestParam int maxDiffTotal) { @RequestParam int maxDiffTotal) {
return monitorService.createOrUpdateConsumerMonitor(consumeGroupName, new ConsumerMonitorConfig(minCount, maxDiffTotal)); return monitorService.createOrUpdateConsumerMonitor(consumeGroupName, new ConsumerMonitorConfig(minCount, maxDiffTotal));
} }

View File

@@ -52,7 +52,7 @@ public class OpsController {
@ResponseBody @ResponseBody
public Object addNameSvrAddr(@RequestParam String newNamesrvAddr) { public Object addNameSvrAddr(@RequestParam String newNamesrvAddr) {
Preconditions.checkArgument(StringUtils.isNotEmpty(newNamesrvAddr), Preconditions.checkArgument(StringUtils.isNotEmpty(newNamesrvAddr),
"namesrvAddr can not be blank"); "namesrvAddr can not be blank");
opsService.addNameSvrAddr(newNamesrvAddr); opsService.addNameSvrAddr(newNamesrvAddr);
return true; return true;
} }

View File

@@ -31,6 +31,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
public class ProxyController { public class ProxyController {
@Resource @Resource
private ProxyService proxyService; private ProxyService proxyService;
@RequestMapping(value = "/homePage.query", method = RequestMethod.GET) @RequestMapping(value = "/homePage.query", method = RequestMethod.GET)
@ResponseBody @ResponseBody
public Object homePage() { public Object homePage() {

View File

@@ -59,7 +59,7 @@ public class TestController {
@Override @Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
ConsumeConcurrentlyContext context) { ConsumeConcurrentlyContext context) {
logger.info("receiveMessage msgSize={}", msgs.size()); logger.info("receiveMessage msgSize={}", msgs.size());
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
} }
@@ -72,26 +72,25 @@ public class TestController {
new Thread(new Runnable() { new Thread(new Runnable() {
@Override public void run() { @Override
public void run() {
int i = 0; int i = 0;
while (true) { while (true) {
try { try {
Message msg = new Message(testTopic, Message msg = new Message(testTopic,
"TagA" + i, "TagA" + i,
"KEYS" + i, "KEYS" + i,
("Hello RocketMQ " + i).getBytes() ("Hello RocketMQ " + i).getBytes()
); );
Thread.sleep(1000L); Thread.sleep(1000L);
SendResult sendResult = producer.send(msg); SendResult sendResult = producer.send(msg);
logger.info("sendMessage={}", JsonUtil.obj2String(sendResult)); logger.info("sendMessage={}", JsonUtil.obj2String(sendResult));
} } catch (Exception e) {
catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
try { try {
Thread.sleep(1000); Thread.sleep(1000);
} } catch (Exception ignore) {
catch (Exception ignore) {
} }
} }
} }

View File

@@ -51,7 +51,7 @@ public class TopicController {
@RequestMapping(value = "/list.query", method = RequestMethod.GET) @RequestMapping(value = "/list.query", method = RequestMethod.GET)
@ResponseBody @ResponseBody
public Object list(@RequestParam(value = "skipSysProcess", required = false) boolean skipSysProcess, public Object list(@RequestParam(value = "skipSysProcess", required = false) boolean skipSysProcess,
@RequestParam(value = "skipRetryAndDlq", required = false) boolean skipRetryAndDlq) { @RequestParam(value = "skipRetryAndDlq", required = false) boolean skipRetryAndDlq) {
return topicService.fetchAllTopicList(skipSysProcess, skipRetryAndDlq); return topicService.fetchAllTopicList(skipSysProcess, skipRetryAndDlq);
} }
@@ -75,11 +75,11 @@ public class TopicController {
} }
@RequestMapping(value = "/createOrUpdate.do", method = { RequestMethod.POST}) @RequestMapping(value = "/createOrUpdate.do", method = {RequestMethod.POST})
@ResponseBody @ResponseBody
public Object topicCreateOrUpdateRequest(@RequestBody TopicConfigInfo topicCreateOrUpdateRequest) { public Object topicCreateOrUpdateRequest(@RequestBody TopicConfigInfo topicCreateOrUpdateRequest) {
Preconditions.checkArgument(CollectionUtils.isNotEmpty(topicCreateOrUpdateRequest.getBrokerNameList()) || CollectionUtils.isNotEmpty(topicCreateOrUpdateRequest.getClusterNameList()), Preconditions.checkArgument(CollectionUtils.isNotEmpty(topicCreateOrUpdateRequest.getBrokerNameList()) || CollectionUtils.isNotEmpty(topicCreateOrUpdateRequest.getClusterNameList()),
"clusterName or brokerName can not be all blank"); "clusterName or brokerName can not be all blank");
logger.info("op=look topicCreateOrUpdateRequest={}", JsonUtil.obj2String(topicCreateOrUpdateRequest)); logger.info("op=look topicCreateOrUpdateRequest={}", JsonUtil.obj2String(topicCreateOrUpdateRequest));
topicService.createOrUpdate(topicCreateOrUpdateRequest); topicService.createOrUpdate(topicCreateOrUpdateRequest);
return true; return true;
@@ -100,14 +100,14 @@ public class TopicController {
@RequestMapping(value = "/examineTopicConfig.query") @RequestMapping(value = "/examineTopicConfig.query")
@ResponseBody @ResponseBody
public Object examineTopicConfig(@RequestParam String topic, public Object examineTopicConfig(@RequestParam String topic,
@RequestParam(required = false) String brokerName) throws RemotingException, MQClientException, InterruptedException { @RequestParam(required = false) String brokerName) throws RemotingException, MQClientException, InterruptedException {
return topicService.examineTopicConfig(topic); return topicService.examineTopicConfig(topic);
} }
@RequestMapping(value = "/sendTopicMessage.do", method = {RequestMethod.POST}) @RequestMapping(value = "/sendTopicMessage.do", method = {RequestMethod.POST})
@ResponseBody @ResponseBody
public Object sendTopicMessage( public Object sendTopicMessage(
@RequestBody SendTopicMessageRequest sendTopicMessageRequest) throws RemotingException, MQClientException, InterruptedException { @RequestBody SendTopicMessageRequest sendTopicMessageRequest) throws RemotingException, MQClientException, InterruptedException {
return topicService.sendTopicMessageRequest(sendTopicMessageRequest); return topicService.sendTopicMessageRequest(sendTopicMessageRequest);
} }

View File

@@ -29,7 +29,6 @@ import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
@WebFilter(urlPatterns = "/*", filterName = "httpBasicAuthorizedFilter") @WebFilter(urlPatterns = "/*", filterName = "httpBasicAuthorizedFilter")
public class HttpBasicAuthorizedFilter implements Filter { public class HttpBasicAuthorizedFilter implements Filter {

View File

@@ -25,7 +25,9 @@ import java.util.Map;
public class MessageView { public class MessageView {
/** from MessageExt **/ /**
* from MessageExt
**/
private int queueId; private int queueId;
private int storeSize; private int storeSize;
private long queueOffset; private long queueOffset;
@@ -41,13 +43,17 @@ public class MessageView {
private long preparedTransactionOffset; private long preparedTransactionOffset;
/**from MessageExt**/ /**from MessageExt**/
/** from Message **/ /**
* from Message
**/
private String topic; private String topic;
private int flag; private int flag;
private Map<String, String> properties; private Map<String, String> properties;
private String messageBody; // body private String messageBody; // body
/** from Message **/ /**
* from Message
**/
public static MessageView fromMessageExt(MessageExt messageExt) { public static MessageView fromMessageExt(MessageExt messageExt) {
MessageView messageView = new MessageView(); MessageView messageView = new MessageView();

View File

@@ -15,6 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
package org.apache.rocketmq.dashboard.model.request; package org.apache.rocketmq.dashboard.model.request;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import java.util.List; import java.util.List;
@@ -24,7 +25,9 @@ public class TopicConfigInfo {
private List<String> clusterNameList; private List<String> clusterNameList;
private List<String> brokerNameList; private List<String> brokerNameList;
/** topicConfig */ /**
* topicConfig
*/
private String topicName; private String topicName;
private int writeQueueNums; private int writeQueueNums;
private int readQueueNums; private int readQueueNums;
@@ -32,6 +35,7 @@ public class TopicConfigInfo {
private boolean order; private boolean order;
private String messageType; private String messageType;
public List<String> getClusterNameList() { public List<String> getClusterNameList() {
return clusterNameList; return clusterNameList;
} }
@@ -40,8 +44,9 @@ public class TopicConfigInfo {
this.clusterNameList = clusterNameList; this.clusterNameList = clusterNameList;
} }
/** topicConfig */ /**
* topicConfig
*/
public List<String> getBrokerNameList() { public List<String> getBrokerNameList() {
@@ -102,8 +107,6 @@ public class TopicConfigInfo {
} }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) if (this == o)
@@ -112,16 +115,16 @@ public class TopicConfigInfo {
return false; return false;
TopicConfigInfo that = (TopicConfigInfo) o; TopicConfigInfo that = (TopicConfigInfo) o;
return writeQueueNums == that.writeQueueNums && return writeQueueNums == that.writeQueueNums &&
readQueueNums == that.readQueueNums && readQueueNums == that.readQueueNums &&
perm == that.perm && perm == that.perm &&
order == that.order && order == that.order &&
Objects.equal(topicName, that.topicName) && Objects.equal(topicName, that.topicName) &&
Objects.equal(messageType, that.messageType); Objects.equal(messageType, that.messageType);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hashCode(topicName, writeQueueNums, readQueueNums, perm, order,messageType); return Objects.hashCode(topicName, writeQueueNums, readQueueNums, perm, order, messageType);
} }
} }

View File

@@ -29,16 +29,16 @@ import java.util.Set;
public abstract class AbstractCommonService { public abstract class AbstractCommonService {
@Resource @Resource
protected MQAdminExt mqAdminExt; protected MQAdminExt mqAdminExt;
protected final Set<String> changeToBrokerNameSet(Map<String, Set<String>> clusterAddrTable, protected final Set<String> changeToBrokerNameSet(Map<String, Set<String>> clusterAddrTable,
List<String> clusterNameList, List<String> brokerNameList) { List<String> clusterNameList, List<String> brokerNameList) {
Set<String> finalBrokerNameList = Sets.newHashSet(); Set<String> finalBrokerNameList = Sets.newHashSet();
if (CollectionUtils.isNotEmpty(clusterNameList)) { if (CollectionUtils.isNotEmpty(clusterNameList)) {
try { try {
for (String clusterName : clusterNameList) { for (String clusterName : clusterNameList) {
finalBrokerNameList.addAll(clusterAddrTable.get(clusterName)); finalBrokerNameList.addAll(clusterAddrTable.get(clusterName));
} }
} } catch (Exception e) {
catch (Exception e) {
Throwables.throwIfUnchecked(e); Throwables.throwIfUnchecked(e);
throw new RuntimeException(e); throw new RuntimeException(e);
} }

View File

@@ -39,5 +39,5 @@ public interface AclService {
void deleteAcl(String brokerAddress, String subject, String resource); void deleteAcl(String brokerAddress, String subject, String resource);
void updateAcl(PolicyRequest policyRequest); void updateAcl(PolicyRequest policyRequest);
} }

View File

@@ -31,7 +31,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
public interface ConsumerService { public interface ConsumerService {
List<GroupConsumeInfo> queryGroupList(boolean skipSysGroup,String address); List<GroupConsumeInfo> queryGroupList(boolean skipSysGroup, String address);
GroupConsumeInfo queryGroup(String consumerGroup, String address); GroupConsumeInfo queryGroup(String consumerGroup, String address);

View File

@@ -32,7 +32,7 @@ public interface DashboardService {
Map<String, List<String>> queryTopicData(String date); Map<String, List<String>> queryTopicData(String date);
/** /**
* @param date format yyyy-MM-dd * @param date format yyyy-MM-dd
* @param topicName * @param topicName
*/ */
List<String> queryTopicData(String date, String topicName); List<String> queryTopicData(String date, String topicName);

View File

@@ -39,21 +39,18 @@ public interface MessageService {
/** /**
* @param topic * @param topic
* @param begin * @param begin
* @param end * @param end org.apache.rocketmq.tools.command.message.PrintMessageSubCommand
* org.apache.rocketmq.tools.command.message.PrintMessageSubCommand
*/ */
List<MessageView> queryMessageByTopic(final String topic, final long begin, List<MessageView> queryMessageByTopic(final String topic, final long begin,
final long end); final long end);
List<MessageTrack> messageTrackDetail(MessageExt msg); List<MessageTrack> messageTrackDetail(MessageExt msg);
ConsumeMessageDirectlyResult consumeMessageDirectly(String topic, String msgId, String consumerGroup, ConsumeMessageDirectlyResult consumeMessageDirectly(String topic, String msgId, String consumerGroup,
String clientId); String clientId);
MessagePage queryMessageByPage(MessageQuery query); MessagePage queryMessageByPage(MessageQuery query);
} }

View File

@@ -27,7 +27,7 @@ public interface OpsService {
String getNameSvrList(); String getNameSvrList();
Map<CheckerType,Object> rocketMqStatusCheck(); Map<CheckerType, Object> rocketMqStatusCheck();
boolean updateIsVIPChannel(String useVIPChannel); boolean updateIsVIPChannel(String useVIPChannel);

View File

@@ -24,5 +24,5 @@ public interface ProxyService {
void updateProxyAddrList(String proxyAddr); void updateProxyAddrList(String proxyAddr);
Map<String, Object> getProxyHomePage(); Map<String, Object> getProxyHomePage();
} }

View File

@@ -94,19 +94,20 @@ public class MQAdminExtImpl implements MQAdminExt {
private Logger logger = LoggerFactory.getLogger(MQAdminExtImpl.class); private Logger logger = LoggerFactory.getLogger(MQAdminExtImpl.class);
public MQAdminExtImpl() {} public MQAdminExtImpl() {
}
@Override @Override
public void updateBrokerConfig(String brokerAddr, Properties properties) public void updateBrokerConfig(String brokerAddr, Properties properties)
throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException,
UnsupportedEncodingException, InterruptedException, MQBrokerException, MQClientException { UnsupportedEncodingException, InterruptedException, MQBrokerException, MQClientException {
MQAdminInstance.threadLocalMQAdminExt().updateBrokerConfig(brokerAddr, properties); MQAdminInstance.threadLocalMQAdminExt().updateBrokerConfig(brokerAddr, properties);
} }
@Override @Override
public void createAndUpdateTopicConfig(String addr, TopicConfig config) public void createAndUpdateTopicConfig(String addr, TopicConfig config)
throws RemotingException, MQBrokerException, InterruptedException, MQClientException { throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
MQAdminInstance.threadLocalMQAdminExt().createAndUpdateTopicConfig(addr, config); MQAdminInstance.threadLocalMQAdminExt().createAndUpdateTopicConfig(addr, config);
} }
@@ -118,7 +119,7 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override @Override
public void createAndUpdateSubscriptionGroupConfig(String addr, SubscriptionGroupConfig config) public void createAndUpdateSubscriptionGroupConfig(String addr, SubscriptionGroupConfig config)
throws RemotingException, MQBrokerException, InterruptedException, MQClientException { throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
MQAdminInstance.threadLocalMQAdminExt().createAndUpdateSubscriptionGroupConfig(addr, config); MQAdminInstance.threadLocalMQAdminExt().createAndUpdateSubscriptionGroupConfig(addr, config);
} }
@@ -134,8 +135,7 @@ public class MQAdminExtImpl implements MQAdminExt {
RemotingCommand response = null; RemotingCommand response = null;
try { try {
response = remotingClient.invokeSync(addr, request, 8000); response = remotingClient.invokeSync(addr, request, 8000);
} } catch (Exception err) {
catch (Exception err) {
Throwables.throwIfUnchecked(err); Throwables.throwIfUnchecked(err);
throw new RuntimeException(err); throw new RuntimeException(err);
} }
@@ -178,7 +178,7 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override @Override
public TopicStatsTable examineTopicStats(String topic) public TopicStatsTable examineTopicStats(String topic)
throws RemotingException, MQClientException, InterruptedException, MQBrokerException { throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
return MQAdminInstance.threadLocalMQAdminExt().examineTopicStats(topic); return MQAdminInstance.threadLocalMQAdminExt().examineTopicStats(topic);
} }
@@ -191,14 +191,14 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override @Override
public KVTable fetchBrokerRuntimeStats(String brokerAddr) public KVTable fetchBrokerRuntimeStats(String brokerAddr)
throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException,
InterruptedException, MQBrokerException { InterruptedException, MQBrokerException {
return MQAdminInstance.threadLocalMQAdminExt().fetchBrokerRuntimeStats(brokerAddr); return MQAdminInstance.threadLocalMQAdminExt().fetchBrokerRuntimeStats(brokerAddr);
} }
@Override @Override
public ConsumeStats examineConsumeStats(String consumerGroup) public ConsumeStats examineConsumeStats(String consumerGroup)
throws RemotingException, MQClientException, InterruptedException, MQBrokerException { throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
return MQAdminInstance.threadLocalMQAdminExt().examineConsumeStats(consumerGroup); return MQAdminInstance.threadLocalMQAdminExt().examineConsumeStats(consumerGroup);
} }
@@ -209,7 +209,7 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override @Override
public ConsumeStats examineConsumeStats(String consumerGroup, String topic) public ConsumeStats examineConsumeStats(String consumerGroup, String topic)
throws RemotingException, MQClientException, InterruptedException, MQBrokerException { throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
return MQAdminInstance.threadLocalMQAdminExt().examineConsumeStats(consumerGroup, topic); return MQAdminInstance.threadLocalMQAdminExt().examineConsumeStats(consumerGroup, topic);
} }
@@ -220,27 +220,27 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override @Override
public ClusterInfo examineBrokerClusterInfo() public ClusterInfo examineBrokerClusterInfo()
throws InterruptedException, MQBrokerException, RemotingTimeoutException, RemotingSendRequestException, throws InterruptedException, MQBrokerException, RemotingTimeoutException, RemotingSendRequestException,
RemotingConnectException { RemotingConnectException {
return MQAdminInstance.threadLocalMQAdminExt().examineBrokerClusterInfo(); return MQAdminInstance.threadLocalMQAdminExt().examineBrokerClusterInfo();
} }
@Override @Override
public TopicRouteData examineTopicRouteInfo(String topic) public TopicRouteData examineTopicRouteInfo(String topic)
throws RemotingException, MQClientException, InterruptedException { throws RemotingException, MQClientException, InterruptedException {
return MQAdminInstance.threadLocalMQAdminExt().examineTopicRouteInfo(topic); return MQAdminInstance.threadLocalMQAdminExt().examineTopicRouteInfo(topic);
} }
@Override @Override
public ConsumerConnection examineConsumerConnectionInfo(String consumerGroup) public ConsumerConnection examineConsumerConnectionInfo(String consumerGroup)
throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException,
InterruptedException, MQBrokerException, RemotingException, MQClientException { InterruptedException, MQBrokerException, RemotingException, MQClientException {
return MQAdminInstance.threadLocalMQAdminExt().examineConsumerConnectionInfo(consumerGroup); return MQAdminInstance.threadLocalMQAdminExt().examineConsumerConnectionInfo(consumerGroup);
} }
@Override @Override
public ProducerConnection examineProducerConnectionInfo(String producerGroup, String topic) public ProducerConnection examineProducerConnectionInfo(String producerGroup, String topic)
throws RemotingException, MQClientException, InterruptedException, MQBrokerException { throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
return MQAdminInstance.threadLocalMQAdminExt().examineProducerConnectionInfo(producerGroup, topic); return MQAdminInstance.threadLocalMQAdminExt().examineProducerConnectionInfo(producerGroup, topic);
} }
@@ -251,14 +251,14 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override @Override
public int wipeWritePermOfBroker(String namesrvAddr, String brokerName) public int wipeWritePermOfBroker(String namesrvAddr, String brokerName)
throws RemotingCommandException, RemotingConnectException, RemotingSendRequestException, throws RemotingCommandException, RemotingConnectException, RemotingSendRequestException,
RemotingTimeoutException, InterruptedException, MQClientException { RemotingTimeoutException, InterruptedException, MQClientException {
return MQAdminInstance.threadLocalMQAdminExt().wipeWritePermOfBroker(namesrvAddr, brokerName); return MQAdminInstance.threadLocalMQAdminExt().wipeWritePermOfBroker(namesrvAddr, brokerName);
} }
@Override @Override
public int addWritePermOfBroker(String namesrvAddr, public int addWritePermOfBroker(String namesrvAddr,
String brokerName) throws RemotingCommandException, RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, InterruptedException, MQClientException { String brokerName) throws RemotingCommandException, RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, InterruptedException, MQClientException {
return MQAdminInstance.threadLocalMQAdminExt().addWritePermOfBroker(namesrvAddr, brokerName); return MQAdminInstance.threadLocalMQAdminExt().addWritePermOfBroker(namesrvAddr, brokerName);
} }
@@ -269,62 +269,62 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override @Override
public String getKVConfig(String namespace, String key) public String getKVConfig(String namespace, String key)
throws RemotingException, MQClientException, InterruptedException { throws RemotingException, MQClientException, InterruptedException {
return MQAdminInstance.threadLocalMQAdminExt().getKVConfig(namespace, key); return MQAdminInstance.threadLocalMQAdminExt().getKVConfig(namespace, key);
} }
@Override @Override
public KVTable getKVListByNamespace(String namespace) public KVTable getKVListByNamespace(String namespace)
throws RemotingException, MQClientException, InterruptedException { throws RemotingException, MQClientException, InterruptedException {
return MQAdminInstance.threadLocalMQAdminExt().getKVListByNamespace(namespace); return MQAdminInstance.threadLocalMQAdminExt().getKVListByNamespace(namespace);
} }
@Override @Override
public void deleteTopicInBroker(Set<String> addrs, String topic) public void deleteTopicInBroker(Set<String> addrs, String topic)
throws RemotingException, MQBrokerException, InterruptedException, MQClientException { throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
logger.info("addrs={} topic={}", JsonUtil.obj2String(addrs), topic); logger.info("addrs={} topic={}", JsonUtil.obj2String(addrs), topic);
MQAdminInstance.threadLocalMQAdminExt().deleteTopicInBroker(addrs, topic); MQAdminInstance.threadLocalMQAdminExt().deleteTopicInBroker(addrs, topic);
} }
@Override @Override
public void deleteTopicInNameServer(Set<String> addrs, String topic) public void deleteTopicInNameServer(Set<String> addrs, String topic)
throws RemotingException, MQBrokerException, InterruptedException, MQClientException { throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
MQAdminInstance.threadLocalMQAdminExt().deleteTopicInNameServer(addrs, topic); MQAdminInstance.threadLocalMQAdminExt().deleteTopicInNameServer(addrs, topic);
} }
@Override @Override
public void deleteSubscriptionGroup(String addr, String groupName) public void deleteSubscriptionGroup(String addr, String groupName)
throws RemotingException, MQBrokerException, InterruptedException, MQClientException { throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
MQAdminInstance.threadLocalMQAdminExt().deleteSubscriptionGroup(addr, groupName); MQAdminInstance.threadLocalMQAdminExt().deleteSubscriptionGroup(addr, groupName);
} }
@Override @Override
public void deleteSubscriptionGroup(String addr, String groupName, boolean removeOffset) public void deleteSubscriptionGroup(String addr, String groupName, boolean removeOffset)
throws RemotingException, MQBrokerException, InterruptedException, MQClientException { throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
MQAdminInstance.threadLocalMQAdminExt().deleteSubscriptionGroup(addr, groupName, removeOffset); MQAdminInstance.threadLocalMQAdminExt().deleteSubscriptionGroup(addr, groupName, removeOffset);
} }
@Override @Override
public void createAndUpdateKvConfig(String namespace, String key, String value) public void createAndUpdateKvConfig(String namespace, String key, String value)
throws RemotingException, MQBrokerException, InterruptedException, MQClientException { throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
MQAdminInstance.threadLocalMQAdminExt().createAndUpdateKvConfig(namespace, key, value); MQAdminInstance.threadLocalMQAdminExt().createAndUpdateKvConfig(namespace, key, value);
} }
@Override @Override
public void deleteKvConfig(String namespace, String key) public void deleteKvConfig(String namespace, String key)
throws RemotingException, MQBrokerException, InterruptedException, MQClientException { throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
MQAdminInstance.threadLocalMQAdminExt().deleteKvConfig(namespace, key); MQAdminInstance.threadLocalMQAdminExt().deleteKvConfig(namespace, key);
} }
@Override @Override
public List<RollbackStats> resetOffsetByTimestampOld(String consumerGroup, String topic, long timestamp, public List<RollbackStats> resetOffsetByTimestampOld(String consumerGroup, String topic, long timestamp,
boolean force) throws RemotingException, MQBrokerException, InterruptedException, MQClientException { boolean force) throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
return MQAdminInstance.threadLocalMQAdminExt().resetOffsetByTimestampOld(consumerGroup, topic, timestamp, force); return MQAdminInstance.threadLocalMQAdminExt().resetOffsetByTimestampOld(consumerGroup, topic, timestamp, force);
} }
@Override @Override
public Map<MessageQueue, Long> resetOffsetByTimestamp(String topic, String group, long timestamp, public Map<MessageQueue, Long> resetOffsetByTimestamp(String topic, String group, long timestamp,
boolean isForce) throws RemotingException, MQBrokerException, InterruptedException, MQClientException { boolean isForce) throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
return MQAdminInstance.threadLocalMQAdminExt().resetOffsetByTimestamp(topic, group, timestamp, isForce); return MQAdminInstance.threadLocalMQAdminExt().resetOffsetByTimestamp(topic, group, timestamp, isForce);
} }
@@ -335,59 +335,59 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override @Override
public void resetOffsetNew(String consumerGroup, String topic, long timestamp) public void resetOffsetNew(String consumerGroup, String topic, long timestamp)
throws RemotingException, MQBrokerException, InterruptedException, MQClientException { throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
MQAdminInstance.threadLocalMQAdminExt().resetOffsetNew(consumerGroup, topic, timestamp); MQAdminInstance.threadLocalMQAdminExt().resetOffsetNew(consumerGroup, topic, timestamp);
} }
@Override @Override
public Map<String, Map<MessageQueue, Long>> getConsumeStatus(String topic, String group, public Map<String, Map<MessageQueue, Long>> getConsumeStatus(String topic, String group,
String clientAddr) throws RemotingException, MQBrokerException, InterruptedException, MQClientException { String clientAddr) throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
return MQAdminInstance.threadLocalMQAdminExt().getConsumeStatus(topic, group, clientAddr); return MQAdminInstance.threadLocalMQAdminExt().getConsumeStatus(topic, group, clientAddr);
} }
@Override @Override
public void createOrUpdateOrderConf(String key, String value, boolean isCluster) public void createOrUpdateOrderConf(String key, String value, boolean isCluster)
throws RemotingException, MQBrokerException, InterruptedException, MQClientException { throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
MQAdminInstance.threadLocalMQAdminExt().createOrUpdateOrderConf(key, value, isCluster); MQAdminInstance.threadLocalMQAdminExt().createOrUpdateOrderConf(key, value, isCluster);
} }
@Override @Override
public GroupList queryTopicConsumeByWho(String topic) public GroupList queryTopicConsumeByWho(String topic)
throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException,
InterruptedException, MQBrokerException, RemotingException, MQClientException { InterruptedException, MQBrokerException, RemotingException, MQClientException {
return MQAdminInstance.threadLocalMQAdminExt().queryTopicConsumeByWho(topic); return MQAdminInstance.threadLocalMQAdminExt().queryTopicConsumeByWho(topic);
} }
@Override @Override
public boolean cleanExpiredConsumerQueue(String cluster) public boolean cleanExpiredConsumerQueue(String cluster)
throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQClientException, throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQClientException,
InterruptedException { InterruptedException {
return MQAdminInstance.threadLocalMQAdminExt().cleanExpiredConsumerQueue(cluster); return MQAdminInstance.threadLocalMQAdminExt().cleanExpiredConsumerQueue(cluster);
} }
@Override @Override
public boolean cleanExpiredConsumerQueueByAddr(String addr) public boolean cleanExpiredConsumerQueueByAddr(String addr)
throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQClientException, throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQClientException,
InterruptedException { InterruptedException {
return MQAdminInstance.threadLocalMQAdminExt().cleanExpiredConsumerQueueByAddr(addr); return MQAdminInstance.threadLocalMQAdminExt().cleanExpiredConsumerQueueByAddr(addr);
} }
@Override @Override
public ConsumerRunningInfo getConsumerRunningInfo(String consumerGroup, String clientId, boolean jstack) public ConsumerRunningInfo getConsumerRunningInfo(String consumerGroup, String clientId, boolean jstack)
throws RemotingException, MQClientException, InterruptedException { throws RemotingException, MQClientException, InterruptedException {
return MQAdminInstance.threadLocalMQAdminExt().getConsumerRunningInfo(consumerGroup, clientId, jstack); return MQAdminInstance.threadLocalMQAdminExt().getConsumerRunningInfo(consumerGroup, clientId, jstack);
} }
@Override @Override
public List<MessageTrack> messageTrackDetail(MessageExt msg) public List<MessageTrack> messageTrackDetail(MessageExt msg)
throws RemotingException, MQClientException, InterruptedException, MQBrokerException { throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
return MQAdminInstance.threadLocalMQAdminExt().messageTrackDetail(msg); return MQAdminInstance.threadLocalMQAdminExt().messageTrackDetail(msg);
} }
@Override @Override
public void cloneGroupOffset(String srcGroup, String destGroup, String topic, boolean isOffline) public void cloneGroupOffset(String srcGroup, String destGroup, String topic, boolean isOffline)
throws RemotingException, MQClientException, InterruptedException, MQBrokerException { throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
MQAdminInstance.threadLocalMQAdminExt().cloneGroupOffset(srcGroup, destGroup, topic, isOffline); MQAdminInstance.threadLocalMQAdminExt().cloneGroupOffset(srcGroup, destGroup, topic, isOffline);
} }
@@ -398,7 +398,7 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override @Override
public void createTopic(String key, String newTopic, int queueNum, int topicSysFlag, Map<String, String> attributes) public void createTopic(String key, String newTopic, int queueNum, int topicSysFlag, Map<String, String> attributes)
throws MQClientException { throws MQClientException {
MQAdminInstance.threadLocalMQAdminExt().createTopic(key, newTopic, queueNum, topicSysFlag, attributes); MQAdminInstance.threadLocalMQAdminExt().createTopic(key, newTopic, queueNum, topicSysFlag, attributes);
} }
@@ -424,7 +424,7 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override @Override
public QueryResult queryMessage(String topic, String key, int maxNum, long begin, long end) public QueryResult queryMessage(String topic, String key, int maxNum, long begin, long end)
throws MQClientException, InterruptedException { throws MQClientException, InterruptedException {
return MQAdminInstance.threadLocalMQAdminExt().queryMessage(topic, key, maxNum, begin, end); return MQAdminInstance.threadLocalMQAdminExt().queryMessage(topic, key, maxNum, begin, end);
} }
@@ -444,7 +444,7 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override @Override
public List<QueueTimeSpan> queryConsumeTimeSpan(String topic, public List<QueueTimeSpan> queryConsumeTimeSpan(String topic,
String group) throws InterruptedException, MQBrokerException, RemotingException, MQClientException { String group) throws InterruptedException, MQBrokerException, RemotingException, MQClientException {
return MQAdminInstance.threadLocalMQAdminExt().queryConsumeTimeSpan(topic, group); return MQAdminInstance.threadLocalMQAdminExt().queryConsumeTimeSpan(topic, group);
} }
@@ -454,7 +454,7 @@ public class MQAdminExtImpl implements MQAdminExt {
//https://github.com/apache/incubator-rocketmq/pull/69 //https://github.com/apache/incubator-rocketmq/pull/69
@Override @Override
public MessageExt viewMessage(String topic, public MessageExt viewMessage(String topic,
String msgId) throws RemotingException, MQBrokerException, InterruptedException, MQClientException { String msgId) throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
logger.info("MessageClientIDSetter.getNearlyTimeFromID(msgId)={} msgId={}", MessageClientIDSetter.getNearlyTimeFromID(msgId), msgId); logger.info("MessageClientIDSetter.getNearlyTimeFromID(msgId)={} msgId={}", MessageClientIDSetter.getNearlyTimeFromID(msgId), msgId);
MQAdminImpl mqAdminImpl = MQAdminInstance.threadLocalMqClientInstance().getMQAdminImpl(); MQAdminImpl mqAdminImpl = MQAdminInstance.threadLocalMqClientInstance().getMQAdminImpl();
Set<String> clusterList = MQAdminInstance.threadLocalMQAdminExt().getTopicClusterList(topic); Set<String> clusterList = MQAdminInstance.threadLocalMQAdminExt().getTopicClusterList(topic);
@@ -478,7 +478,7 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override @Override
public ConsumeMessageDirectlyResult consumeMessageDirectly(String consumerGroup, String clientId, String topic, public ConsumeMessageDirectlyResult consumeMessageDirectly(String consumerGroup, String clientId, String topic,
String msgId) throws RemotingException, MQClientException, InterruptedException, MQBrokerException { String msgId) throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
return MQAdminInstance.threadLocalMQAdminExt().consumeMessageDirectly(consumerGroup, clientId, topic, msgId); return MQAdminInstance.threadLocalMQAdminExt().consumeMessageDirectly(consumerGroup, clientId, topic, msgId);
} }
@@ -489,96 +489,99 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override @Override
public Properties getBrokerConfig( public Properties getBrokerConfig(
String brokerAddr) throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, UnsupportedEncodingException, InterruptedException, MQBrokerException { String brokerAddr) throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, UnsupportedEncodingException, InterruptedException, MQBrokerException {
return MQAdminInstance.threadLocalMQAdminExt().getBrokerConfig(brokerAddr); return MQAdminInstance.threadLocalMQAdminExt().getBrokerConfig(brokerAddr);
} }
@Override @Override
public TopicList fetchTopicsByCLuster( public TopicList fetchTopicsByCLuster(
String clusterName) throws RemotingException, MQClientException, InterruptedException { String clusterName) throws RemotingException, MQClientException, InterruptedException {
return MQAdminInstance.threadLocalMQAdminExt().fetchTopicsByCLuster(clusterName); return MQAdminInstance.threadLocalMQAdminExt().fetchTopicsByCLuster(clusterName);
} }
@Override @Override
public boolean cleanUnusedTopic( public boolean cleanUnusedTopic(
String cluster) throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQClientException, InterruptedException { String cluster) throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQClientException, InterruptedException {
return MQAdminInstance.threadLocalMQAdminExt().cleanUnusedTopic(cluster); return MQAdminInstance.threadLocalMQAdminExt().cleanUnusedTopic(cluster);
} }
@Override @Override
public boolean cleanUnusedTopicByAddr( public boolean cleanUnusedTopicByAddr(
String addr) throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQClientException, InterruptedException { String addr) throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQClientException, InterruptedException {
return MQAdminInstance.threadLocalMQAdminExt().cleanUnusedTopicByAddr(addr); return MQAdminInstance.threadLocalMQAdminExt().cleanUnusedTopicByAddr(addr);
} }
@Override @Override
public BrokerStatsData viewBrokerStatsData(String brokerAddr, String statsName, public BrokerStatsData viewBrokerStatsData(String brokerAddr, String statsName,
String statsKey) throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQClientException, InterruptedException { String statsKey) throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQClientException, InterruptedException {
return MQAdminInstance.threadLocalMQAdminExt().viewBrokerStatsData(brokerAddr, statsName, statsKey); return MQAdminInstance.threadLocalMQAdminExt().viewBrokerStatsData(brokerAddr, statsName, statsKey);
} }
@Override @Override
public Set<String> getClusterList( public Set<String> getClusterList(
String topic) throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQClientException, InterruptedException { String topic) throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQClientException, InterruptedException {
return MQAdminInstance.threadLocalMQAdminExt().getClusterList(topic); return MQAdminInstance.threadLocalMQAdminExt().getClusterList(topic);
} }
@Override @Override
public ConsumeStatsList fetchConsumeStatsInBroker(String brokerAddr, boolean isOrder, public ConsumeStatsList fetchConsumeStatsInBroker(String brokerAddr, boolean isOrder,
long timeoutMillis) throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQClientException, InterruptedException { long timeoutMillis) throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQClientException, InterruptedException {
return MQAdminInstance.threadLocalMQAdminExt().fetchConsumeStatsInBroker(brokerAddr, isOrder, timeoutMillis); return MQAdminInstance.threadLocalMQAdminExt().fetchConsumeStatsInBroker(brokerAddr, isOrder, timeoutMillis);
} }
@Override @Override
public Set<String> getTopicClusterList( public Set<String> getTopicClusterList(
String topic) throws InterruptedException, MQBrokerException, MQClientException, RemotingException { String topic) throws InterruptedException, MQBrokerException, MQClientException, RemotingException {
return MQAdminInstance.threadLocalMQAdminExt().getTopicClusterList(topic); return MQAdminInstance.threadLocalMQAdminExt().getTopicClusterList(topic);
} }
@Override @Override
public SubscriptionGroupWrapper getAllSubscriptionGroup(String brokerAddr, public SubscriptionGroupWrapper getAllSubscriptionGroup(String brokerAddr,
long timeoutMillis) throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException, MQBrokerException { long timeoutMillis) throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException, MQBrokerException {
return MQAdminInstance.threadLocalMQAdminExt().getAllSubscriptionGroup(brokerAddr, timeoutMillis); return MQAdminInstance.threadLocalMQAdminExt().getAllSubscriptionGroup(brokerAddr, timeoutMillis);
} }
@Override @Override
public SubscriptionGroupWrapper getUserSubscriptionGroup(String brokerAddr, public SubscriptionGroupWrapper getUserSubscriptionGroup(String brokerAddr,
long timeoutMillis) throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException, MQBrokerException { long timeoutMillis) throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException, MQBrokerException {
return MQAdminInstance.threadLocalMQAdminExt().getUserSubscriptionGroup(brokerAddr, timeoutMillis); return MQAdminInstance.threadLocalMQAdminExt().getUserSubscriptionGroup(brokerAddr, timeoutMillis);
} }
@Override @Override
public TopicConfigSerializeWrapper getAllTopicConfig(String brokerAddr, public TopicConfigSerializeWrapper getAllTopicConfig(String brokerAddr,
long timeoutMillis) throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException, MQBrokerException { long timeoutMillis) throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException, MQBrokerException {
return MQAdminInstance.threadLocalMQAdminExt().getAllTopicConfig(brokerAddr, timeoutMillis); return MQAdminInstance.threadLocalMQAdminExt().getAllTopicConfig(brokerAddr, timeoutMillis);
} }
@Override @Override
public TopicConfigSerializeWrapper getUserTopicConfig(String brokerAddr, boolean specialTopic, public TopicConfigSerializeWrapper getUserTopicConfig(String brokerAddr, boolean specialTopic,
long timeoutMillis) throws InterruptedException, RemotingException, MQBrokerException, MQClientException { long timeoutMillis) throws InterruptedException, RemotingException, MQBrokerException, MQClientException {
return MQAdminInstance.threadLocalMQAdminExt().getUserTopicConfig(brokerAddr, specialTopic, timeoutMillis); return MQAdminInstance.threadLocalMQAdminExt().getUserTopicConfig(brokerAddr, specialTopic, timeoutMillis);
} }
@Override @Override
public void updateConsumeOffset(String brokerAddr, String consumeGroup, MessageQueue mq, public void updateConsumeOffset(String brokerAddr, String consumeGroup, MessageQueue mq,
long offset) throws RemotingException, InterruptedException, MQBrokerException { long offset) throws RemotingException, InterruptedException, MQBrokerException {
MQAdminInstance.threadLocalMQAdminExt().updateConsumeOffset(brokerAddr, consumeGroup, mq, offset); MQAdminInstance.threadLocalMQAdminExt().updateConsumeOffset(brokerAddr, consumeGroup, mq, offset);
} }
// 4.0.0 added // 4.0.0 added
@Override public void updateNameServerConfig(Properties properties, @Override
List<String> list) throws InterruptedException, RemotingConnectException, UnsupportedEncodingException, RemotingSendRequestException, RemotingTimeoutException, MQClientException, MQBrokerException { public void updateNameServerConfig(Properties properties,
List<String> list) throws InterruptedException, RemotingConnectException, UnsupportedEncodingException, RemotingSendRequestException, RemotingTimeoutException, MQClientException, MQBrokerException {
} }
@Override public Map<String, Properties> getNameServerConfig( @Override
List<String> list) throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException, MQClientException, UnsupportedEncodingException { public Map<String, Properties> getNameServerConfig(
List<String> list) throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException, MQClientException, UnsupportedEncodingException {
return null; return null;
} }
@Override public QueryConsumeQueueResponseBody queryConsumeQueue(String brokerAddr, String topic, @Override
int queueId, long index, int count, public QueryConsumeQueueResponseBody queryConsumeQueue(String brokerAddr, String topic,
String consumerGroup) throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException, MQClientException { int queueId, long index, int count,
String consumerGroup) throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException, MQClientException {
return null; return null;
} }
@@ -588,8 +591,9 @@ public class MQAdminExtImpl implements MQAdminExt {
} }
@Override public boolean resumeCheckHalfMessage(String topic, @Override
String msgId) throws RemotingException, MQClientException, InterruptedException, MQBrokerException { public boolean resumeCheckHalfMessage(String topic,
String msgId) throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
return false; return false;
} }
@@ -602,7 +606,7 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override @Override
public void removeBrokerFromContainer(String brokerContainerAddr, String clusterName, String brokerName, public void removeBrokerFromContainer(String brokerContainerAddr, String clusterName, String brokerName,
long brokerId) throws InterruptedException, MQBrokerException, RemotingTimeoutException, long brokerId) throws InterruptedException, MQBrokerException, RemotingTimeoutException,
RemotingSendRequestException, RemotingConnectException { RemotingSendRequestException, RemotingConnectException {
// TODO Auto-generated method stub // TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'removeBrokerFromContainer'"); throw new UnsupportedOperationException("Unimplemented method 'removeBrokerFromContainer'");
@@ -624,7 +628,7 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override @Override
public ConsumeStats examineConsumeStats(String brokerAddr, String consumerGroup, String topicName, public ConsumeStats examineConsumeStats(String brokerAddr, String consumerGroup, String topicName,
long timeoutMillis) throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, long timeoutMillis) throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException,
RemotingConnectException, MQBrokerException { RemotingConnectException, MQBrokerException {
// TODO Auto-generated method stub // TODO Auto-generated method stub
return MQAdminInstance.threadLocalMQAdminExt().examineConsumeStats(brokerAddr, consumerGroup, topicName, timeoutMillis); return MQAdminInstance.threadLocalMQAdminExt().examineConsumeStats(brokerAddr, consumerGroup, topicName, timeoutMillis);
@@ -717,7 +721,7 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override @Override
public ConsumerRunningInfo getConsumerRunningInfo(String consumerGroup, String clientId, boolean jstack, public ConsumerRunningInfo getConsumerRunningInfo(String consumerGroup, String clientId, boolean jstack,
boolean metrics) throws RemotingException, MQClientException, InterruptedException { boolean metrics) throws RemotingException, MQClientException, InterruptedException {
// TODO Auto-generated method stub // TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'getConsumerRunningInfo'"); throw new UnsupportedOperationException("Unimplemented method 'getConsumerRunningInfo'");
} }
@@ -731,7 +735,7 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override @Override
public void setMessageRequestMode(String brokerAddr, String topic, String consumerGroup, MessageRequestMode mode, public void setMessageRequestMode(String brokerAddr, String topic, String consumerGroup, MessageRequestMode mode,
int popWorkGroupSize, long timeoutMillis) throws InterruptedException, RemotingTimeoutException, int popWorkGroupSize, long timeoutMillis) throws InterruptedException, RemotingTimeoutException,
RemotingSendRequestException, RemotingConnectException, MQClientException { RemotingSendRequestException, RemotingConnectException, MQClientException {
// TODO Auto-generated method stub // TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'setMessageRequestMode'"); throw new UnsupportedOperationException("Unimplemented method 'setMessageRequestMode'");
@@ -746,14 +750,14 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override @Override
public void resetOffsetByQueueId(String brokerAddr, String consumerGroup, String topicName, int queueId, public void resetOffsetByQueueId(String brokerAddr, String consumerGroup, String topicName, int queueId,
long resetOffset) throws RemotingException, InterruptedException, MQBrokerException { long resetOffset) throws RemotingException, InterruptedException, MQBrokerException {
// TODO Auto-generated method stub // TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'resetOffsetByQueueId'"); throw new UnsupportedOperationException("Unimplemented method 'resetOffsetByQueueId'");
} }
@Override @Override
public void createStaticTopic(String addr, String defaultTopic, TopicConfig topicConfig, public void createStaticTopic(String addr, String defaultTopic, TopicConfig topicConfig,
TopicQueueMappingDetail mappingDetail, boolean force) TopicQueueMappingDetail mappingDetail, boolean force)
throws RemotingException, InterruptedException, MQBrokerException { throws RemotingException, InterruptedException, MQBrokerException {
// TODO Auto-generated method stub // TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'createStaticTopic'"); throw new UnsupportedOperationException("Unimplemented method 'createStaticTopic'");
@@ -761,7 +765,7 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override @Override
public GroupForbidden updateAndGetGroupReadForbidden(String brokerAddr, String groupName, String topicName, public GroupForbidden updateAndGetGroupReadForbidden(String brokerAddr, String groupName, String topicName,
Boolean readable) throws RemotingException, InterruptedException, MQBrokerException { Boolean readable) throws RemotingException, InterruptedException, MQBrokerException {
// TODO Auto-generated method stub // TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'updateAndGetGroupReadForbidden'"); throw new UnsupportedOperationException("Unimplemented method 'updateAndGetGroupReadForbidden'");
} }
@@ -831,7 +835,7 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override @Override
public void cleanControllerBrokerData(String controllerAddr, String clusterName, String brokerName, public void cleanControllerBrokerData(String controllerAddr, String clusterName, String brokerName,
String brokerAddr, boolean isCleanLivingBroker) String brokerAddr, boolean isCleanLivingBroker)
throws RemotingException, InterruptedException, MQBrokerException { throws RemotingException, InterruptedException, MQBrokerException {
// TODO Auto-generated method stub // TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'cleanControllerBrokerData'"); throw new UnsupportedOperationException("Unimplemented method 'cleanControllerBrokerData'");

View File

@@ -212,7 +212,6 @@ public class ConsumerServiceImpl extends AbstractCommonService implements Consum
} else { } else {
consumeInfo.setSubGroupType(subscriptionGroupTable.get(consumerGroup).isConsumeMessageOrderly() ? "FIFO" : "NORMAL"); consumeInfo.setSubGroupType(subscriptionGroupTable.get(consumerGroup).isConsumeMessageOrderly() ? "FIFO" : "NORMAL");
} }
consumeInfo.setGroup(consumerGroup);
consumeInfo.setUpdateTime(new Date()); consumeInfo.setUpdateTime(new Date());
groupConsumeInfoList.add(consumeInfo); groupConsumeInfoList.add(consumeInfo);
} catch (Exception e) { } catch (Exception e) {
@@ -270,6 +269,7 @@ public class ConsumerServiceImpl extends AbstractCommonService implements Consum
logger.warn("examineConsumeStats or examineConsumerConnectionInfo exception, " logger.warn("examineConsumeStats or examineConsumerConnectionInfo exception, "
+ consumerGroup, e); + consumerGroup, e);
} }
groupConsumeInfo.setGroup(consumerGroup);
return groupConsumeInfo; return groupConsumeInfo;
} }

View File

@@ -51,51 +51,52 @@ public class DashboardCollectServiceImpl implements DashboardCollectService {
private final static Logger log = LoggerFactory.getLogger(DashboardCollectServiceImpl.class); private final static Logger log = LoggerFactory.getLogger(DashboardCollectServiceImpl.class);
private LoadingCache<String, List<String>> brokerMap = CacheBuilder.newBuilder() private LoadingCache<String, List<String>> brokerMap = CacheBuilder.newBuilder()
.maximumSize(1000) .maximumSize(1000)
.concurrencyLevel(10) .concurrencyLevel(10)
.recordStats() .recordStats()
.ticker(Ticker.systemTicker()) .ticker(Ticker.systemTicker())
.removalListener(new RemovalListener<Object, Object>() { .removalListener(new RemovalListener<Object, Object>() {
@Override
public void onRemoval(RemovalNotification<Object, Object> notification) {
log.debug(notification.getKey() + " was removed, cause is " + notification.getCause());
}
})
.build(
new CacheLoader<String, List<String>>() {
@Override @Override
public List<String> load(String key) { public void onRemoval(RemovalNotification<Object, Object> notification) {
List<String> list = Lists.newArrayList(); log.debug(notification.getKey() + " was removed, cause is " + notification.getCause());
return list;
} }
} })
); .build(
new CacheLoader<String, List<String>>() {
@Override
public List<String> load(String key) {
List<String> list = Lists.newArrayList();
return list;
}
}
);
private LoadingCache<String, List<String>> topicMap = CacheBuilder.newBuilder() private LoadingCache<String, List<String>> topicMap = CacheBuilder.newBuilder()
.maximumSize(1000) .maximumSize(1000)
.concurrencyLevel(10) .concurrencyLevel(10)
.recordStats() .recordStats()
.ticker(Ticker.systemTicker()) .ticker(Ticker.systemTicker())
.removalListener(new RemovalListener<Object, Object>() { .removalListener(new RemovalListener<Object, Object>() {
@Override
public void onRemoval(RemovalNotification<Object, Object> notification) {
log.debug(notification.getKey() + " was removed, cause is " + notification.getCause());
}
})
.build(
new CacheLoader<String, List<String>>() {
@Override @Override
public List<String> load(String key) { public void onRemoval(RemovalNotification<Object, Object> notification) {
List<String> list = Lists.newArrayList(); log.debug(notification.getKey() + " was removed, cause is " + notification.getCause());
return list;
} }
} })
); .build(
new CacheLoader<String, List<String>>() {
@Override
public List<String> load(String key) {
List<String> list = Lists.newArrayList();
return list;
}
}
);
@Override @Override
public LoadingCache<String, List<String>> getBrokerMap() { public LoadingCache<String, List<String>> getBrokerMap() {
return brokerMap; return brokerMap;
} }
@Override @Override
public LoadingCache<String, List<String>> getTopicMap() { public LoadingCache<String, List<String>> getTopicMap() {
return topicMap; return topicMap;
@@ -106,8 +107,7 @@ public class DashboardCollectServiceImpl implements DashboardCollectService {
List<String> strings; List<String> strings;
try { try {
strings = Files.readLines(file, Charsets.UTF_8); strings = Files.readLines(file, Charsets.UTF_8);
} } catch (IOException e) {
catch (IOException e) {
Throwables.throwIfUnchecked(e); Throwables.throwIfUnchecked(e);
throw new RuntimeException(e); throw new RuntimeException(e);
} }

View File

@@ -34,6 +34,7 @@ public class DashboardServiceImpl implements DashboardService {
@Resource @Resource
private DashboardCollectService dashboardCollectService; private DashboardCollectService dashboardCollectService;
/** /**
* @param date format yyyy-MM-dd * @param date format yyyy-MM-dd
*/ */
@@ -48,7 +49,7 @@ public class DashboardServiceImpl implements DashboardService {
} }
/** /**
* @param date format yyyy-MM-dd * @param date format yyyy-MM-dd
* @param topicName * @param topicName
*/ */
@Override @Override

View File

@@ -60,7 +60,7 @@ public class DlqMessageServiceImpl implements DlqMessageService {
} catch (MQClientException e) { } catch (MQClientException e) {
// If the %DLQ%Group does not exist, the message returns null // If the %DLQ%Group does not exist, the message returns null
if (topic.startsWith(MixAll.DLQ_GROUP_TOPIC_PREFIX) if (topic.startsWith(MixAll.DLQ_GROUP_TOPIC_PREFIX)
&& e.getResponseCode() == ResponseCode.TOPIC_NOT_EXIST) { && e.getResponseCode() == ResponseCode.TOPIC_NOT_EXIST) {
return new MessagePage(new PageImpl<>(messageViews, page, 0), query.getTaskId()); return new MessagePage(new PageImpl<>(messageViews, page, 0), query.getTaskId());
} else { } else {
Throwables.throwIfUnchecked(e); Throwables.throwIfUnchecked(e);
@@ -78,8 +78,8 @@ public class DlqMessageServiceImpl implements DlqMessageService {
List<DlqMessageResendResult> batchResendResults = new LinkedList<>(); List<DlqMessageResendResult> batchResendResults = new LinkedList<>();
for (DlqMessageRequest dlqMessage : dlqMessages) { for (DlqMessageRequest dlqMessage : dlqMessages) {
ConsumeMessageDirectlyResult result = messageService.consumeMessageDirectly(dlqMessage.getTopicName(), ConsumeMessageDirectlyResult result = messageService.consumeMessageDirectly(dlqMessage.getTopicName(),
dlqMessage.getMsgId(), dlqMessage.getConsumerGroup(), dlqMessage.getMsgId(), dlqMessage.getConsumerGroup(),
dlqMessage.getClientId()); dlqMessage.getClientId());
DlqMessageResendResult resendResult = new DlqMessageResendResult(result, dlqMessage.getMsgId()); DlqMessageResendResult resendResult = new DlqMessageResendResult(result, dlqMessage.getMsgId());
batchResendResults.add(resendResult); batchResendResults.add(resendResult);
} }

View File

@@ -33,7 +33,6 @@ import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer;
import org.apache.rocketmq.client.consumer.PullResult; import org.apache.rocketmq.client.consumer.PullResult;
import org.apache.rocketmq.client.consumer.PullStatus; import org.apache.rocketmq.client.consumer.PullStatus;
import org.apache.rocketmq.client.exception.MQClientException; import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.MixAll;
import org.apache.rocketmq.common.Pair; import org.apache.rocketmq.common.Pair;
import org.apache.rocketmq.common.message.MessageClientIDSetter; import org.apache.rocketmq.common.message.MessageClientIDSetter;
import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.message.MessageExt;
@@ -74,6 +73,9 @@ import java.util.stream.Collectors;
@Service @Service
public class MessageServiceImpl implements MessageService { public class MessageServiceImpl implements MessageService {
@Resource
private AutoCloseConsumerWrapper autoCloseConsumerWrapper;
private Logger logger = LoggerFactory.getLogger(MessageServiceImpl.class); private Logger logger = LoggerFactory.getLogger(MessageServiceImpl.class);
private static final Cache<String, List<QueueOffsetInfo>> CACHE = CacheBuilder.newBuilder() private static final Cache<String, List<QueueOffsetInfo>> CACHE = CacheBuilder.newBuilder()
@@ -128,8 +130,8 @@ public class MessageServiceImpl implements MessageService {
if (isEnableAcl) { if (isEnableAcl) {
rpcHook = new AclClientRPCHook(new SessionCredentials(configure.getAccessKey(), configure.getSecretKey())); rpcHook = new AclClientRPCHook(new SessionCredentials(configure.getAccessKey(), configure.getSecretKey()));
} }
AutoCloseConsumerWrapper consumerWrapper = new AutoCloseConsumerWrapper();
DefaultMQPullConsumer consumer = consumerWrapper.getConsumer(rpcHook, configure.isUseTLS()); DefaultMQPullConsumer consumer = autoCloseConsumerWrapper.getConsumer(rpcHook, configure.isUseTLS());
List<MessageView> messageViewList = Lists.newArrayList(); List<MessageView> messageViewList = Lists.newArrayList();
try { try {
String subExpression = "*"; String subExpression = "*";
@@ -262,8 +264,8 @@ public class MessageServiceImpl implements MessageService {
if (isEnableAcl) { if (isEnableAcl) {
rpcHook = new AclClientRPCHook(new SessionCredentials(configure.getAccessKey(), configure.getSecretKey())); rpcHook = new AclClientRPCHook(new SessionCredentials(configure.getAccessKey(), configure.getSecretKey()));
} }
AutoCloseConsumerWrapper consumerWrapper = new AutoCloseConsumerWrapper();
DefaultMQPullConsumer consumer = consumerWrapper.getConsumer(rpcHook, configure.isUseTLS()); DefaultMQPullConsumer consumer = autoCloseConsumerWrapper.getConsumer(rpcHook, configure.isUseTLS());
long total = 0; long total = 0;
List<QueueOffsetInfo> queueOffsetInfos = new ArrayList<>(); List<QueueOffsetInfo> queueOffsetInfos = new ArrayList<>();
@@ -402,8 +404,8 @@ public class MessageServiceImpl implements MessageService {
if (isEnableAcl) { if (isEnableAcl) {
rpcHook = new AclClientRPCHook(new SessionCredentials(configure.getAccessKey(), configure.getSecretKey())); rpcHook = new AclClientRPCHook(new SessionCredentials(configure.getAccessKey(), configure.getSecretKey()));
} }
AutoCloseConsumerWrapper consumerWrapper = new AutoCloseConsumerWrapper();
DefaultMQPullConsumer consumer = consumerWrapper.getConsumer(rpcHook, configure.isUseTLS()); DefaultMQPullConsumer consumer = autoCloseConsumerWrapper.getConsumer(rpcHook, configure.isUseTLS());
List<MessageView> messageViews = new ArrayList<>(); List<MessageView> messageViews = new ArrayList<>();
long offset = query.getPageNum() * query.getPageSize(); long offset = query.getPageNum() * query.getPageSize();
@@ -541,9 +543,9 @@ public class MessageServiceImpl implements MessageService {
} }
} }
public DefaultMQPullConsumer buildDefaultMQPullConsumer(RPCHook rpcHook, boolean useTLS) { // public DefaultMQPullConsumer buildDefaultMQPullConsumer(RPCHook rpcHook, boolean useTLS) {
DefaultMQPullConsumer consumer = new DefaultMQPullConsumer(MixAll.TOOLS_CONSUMER_GROUP, rpcHook); // DefaultMQPullConsumer consumer = new DefaultMQPullConsumer(MixAll.TOOLS_CONSUMER_GROUP, rpcHook);
consumer.setUseTLS(useTLS); // consumer.setUseTLS(useTLS);
return consumer; // return consumer;
} // }
} }

View File

@@ -133,21 +133,21 @@ public class MessageTraceServiceImpl implements MessageTraceService {
} }
private List<SubscriptionNode> buildSubscriptionNodeList( private List<SubscriptionNode> buildSubscriptionNodeList(
Map<String, Pair<MessageTraceView, MessageTraceView>> requestIdTracePairMap) { Map<String, Pair<MessageTraceView, MessageTraceView>> requestIdTracePairMap) {
Map<String, List<TraceNode>> subscriptionTraceNodeMap = Maps.newHashMap(); Map<String, List<TraceNode>> subscriptionTraceNodeMap = Maps.newHashMap();
for (Pair<MessageTraceView, MessageTraceView> traceNodePair : requestIdTracePairMap.values()) { for (Pair<MessageTraceView, MessageTraceView> traceNodePair : requestIdTracePairMap.values()) {
List<TraceNode> traceNodeList = subscriptionTraceNodeMap List<TraceNode> traceNodeList = subscriptionTraceNodeMap
.computeIfAbsent(buildGroupName(traceNodePair), (o) -> Lists.newArrayList()); .computeIfAbsent(buildGroupName(traceNodePair), (o) -> Lists.newArrayList());
traceNodeList.add(buildConsumeMessageTraceNode(traceNodePair)); traceNodeList.add(buildConsumeMessageTraceNode(traceNodePair));
} }
return subscriptionTraceNodeMap.entrySet().stream() return subscriptionTraceNodeMap.entrySet().stream()
.map((Function<Map.Entry<String, List<TraceNode>>, SubscriptionNode>) subscriptionEntry -> { .map((Function<Map.Entry<String, List<TraceNode>>, SubscriptionNode>) subscriptionEntry -> {
List<TraceNode> traceNodeList = subscriptionEntry.getValue(); List<TraceNode> traceNodeList = subscriptionEntry.getValue();
SubscriptionNode subscriptionNode = new SubscriptionNode(); SubscriptionNode subscriptionNode = new SubscriptionNode();
subscriptionNode.setSubscriptionGroup(subscriptionEntry.getKey()); subscriptionNode.setSubscriptionGroup(subscriptionEntry.getKey());
subscriptionNode.setConsumeNodeList(sortTraceNodeListByBeginTimestamp(traceNodeList)); subscriptionNode.setConsumeNodeList(sortTraceNodeListByBeginTimestamp(traceNodeList));
return subscriptionNode; return subscriptionNode;
}).collect(Collectors.toList()); }).collect(Collectors.toList());
} }
private <E> E getTraceValue(Pair<MessageTraceView, MessageTraceView> traceNodePair, Function<MessageTraceView, E> function) { private <E> E getTraceValue(Pair<MessageTraceView, MessageTraceView> traceNodePair, Function<MessageTraceView, E> function) {
@@ -206,7 +206,7 @@ public class MessageTraceServiceImpl implements MessageTraceService {
private void putIntoMessageTraceViewGroupMap(MessageTraceView messageTraceView, private void putIntoMessageTraceViewGroupMap(MessageTraceView messageTraceView,
Map<String, Pair<MessageTraceView, MessageTraceView>> messageTraceViewGroupMap) { Map<String, Pair<MessageTraceView, MessageTraceView>> messageTraceViewGroupMap) {
Pair<MessageTraceView, MessageTraceView> messageTracePair = messageTraceViewGroupMap Pair<MessageTraceView, MessageTraceView> messageTracePair = messageTraceViewGroupMap
.computeIfAbsent(messageTraceView.getRequestId(), (o) -> new Pair<>(null, null)); .computeIfAbsent(messageTraceView.getRequestId(), (o) -> new Pair<>(null, null));
switch (TraceType.valueOf(messageTraceView.getTraceType())) { switch (TraceType.valueOf(messageTraceView.getTraceType())) {
case SubBefore: case SubBefore:
messageTracePair.setObject1(messageTraceView); messageTracePair.setObject1(messageTraceView);

View File

@@ -81,8 +81,7 @@ public class MonitorServiceImpl implements MonitorService {
private void writeDataJsonToFile(String path, String dataStr) { private void writeDataJsonToFile(String path, String dataStr) {
try { try {
MixAll.string2File(dataStr, path); MixAll.string2File(dataStr, path);
} } catch (Exception e) {
catch (Exception e) {
Throwables.throwIfUnchecked(e); Throwables.throwIfUnchecked(e);
throw new RuntimeException(e); throw new RuntimeException(e);
} }

View File

@@ -33,8 +33,7 @@ public class ProducerServiceImpl implements ProducerService {
public ProducerConnection getProducerConnection(String producerGroup, String topic) { public ProducerConnection getProducerConnection(String producerGroup, String topic) {
try { try {
return mqAdminExt.examineProducerConnectionInfo(producerGroup, topic); return mqAdminExt.examineProducerConnectionInfo(producerGroup, topic);
} } catch (Exception e) {
catch (Exception e) {
Throwables.throwIfUnchecked(e); Throwables.throwIfUnchecked(e);
throw new RuntimeException(e); throw new RuntimeException(e);
} }

View File

@@ -127,7 +127,7 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
try { try {
TopicConfigSerializeWrapper topicConfigSerializeWrapper = mqAdminExt.getAllTopicConfig(brokerAddr.getBrokerAddrs().get(0L), 10000L); TopicConfigSerializeWrapper topicConfigSerializeWrapper = mqAdminExt.getAllTopicConfig(brokerAddr.getBrokerAddrs().get(0L), 10000L);
for (TopicConfig topicConfig : topicConfigSerializeWrapper.getTopicConfigTable().values()) { for (TopicConfig topicConfig : topicConfigSerializeWrapper.getTopicConfigTable().values()) {
TopicTypeMeta topicType = classifyTopicType(topicConfig.getTopicName(), topicConfigSerializeWrapper.getTopicConfigTable().get(topicConfig.getTopicName()).getAttributes(),sysTopics.getTopicList()); TopicTypeMeta topicType = classifyTopicType(topicConfig.getTopicName(), topicConfigSerializeWrapper.getTopicConfigTable().get(topicConfig.getTopicName()).getAttributes(), sysTopics.getTopicList());
if (names.contains(topicType.getTopicName())) { if (names.contains(topicType.getTopicName())) {
continue; continue;
} }
@@ -149,7 +149,7 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
return new TopicTypeList(names, messageTypes); return new TopicTypeList(names, messageTypes);
} }
private TopicTypeMeta classifyTopicType(String topicName, Map<String,String> attributes, Set<String> sysTopics) { private TopicTypeMeta classifyTopicType(String topicName, Map<String, String> attributes, Set<String> sysTopics) {
TopicTypeMeta topicType = new TopicTypeMeta(); TopicTypeMeta topicType = new TopicTypeMeta();
topicType.setTopicName(topicName); topicType.setTopicName(topicName);

View File

@@ -17,29 +17,26 @@
package org.apache.rocketmq.dashboard.service.impl; package org.apache.rocketmq.dashboard.service.impl;
import jakarta.annotation.Resource;
import org.apache.rocketmq.auth.authentication.enums.UserType; import org.apache.rocketmq.auth.authentication.enums.UserType;
import org.apache.rocketmq.dashboard.admin.UserMQAdminPoolManager; import org.apache.rocketmq.dashboard.admin.UserMQAdminPoolManager;
import org.apache.rocketmq.dashboard.config.RMQConfigure;
import org.apache.rocketmq.dashboard.model.User; import org.apache.rocketmq.dashboard.model.User;
import org.apache.rocketmq.dashboard.service.UserService; import org.apache.rocketmq.dashboard.service.UserService;
import org.apache.rocketmq.dashboard.service.provider.UserInfoProvider; import org.apache.rocketmq.dashboard.service.strategy.UserContext;
import org.apache.rocketmq.remoting.protocol.body.UserInfo; import org.apache.rocketmq.remoting.protocol.body.UserInfo;
import org.apache.rocketmq.tools.admin.MQAdminExt; import org.apache.rocketmq.tools.admin.MQAdminExt;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service @Service
public class UserServiceImpl implements UserService { public class UserServiceImpl implements UserService {
private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class); private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
@Resource
private RMQConfigure configure;
@Autowired @Autowired
private UserInfoProvider userInfoProvider; private UserContext userContext;
@Autowired @Autowired
private UserMQAdminPoolManager userMQAdminPoolManager; private UserMQAdminPoolManager userMQAdminPoolManager;
@@ -47,7 +44,7 @@ public class UserServiceImpl implements UserService {
@Override @Override
public User queryByName(String name) { public User queryByName(String name) {
UserInfo userInfo = userInfoProvider.getUserInfoByUsername(name); UserInfo userInfo = userContext.queryByUsername(name);
if (userInfo == null) { if (userInfo == null) {
return null; return null;
} }

View File

@@ -23,6 +23,7 @@ import org.apache.rocketmq.common.MixAll;
import org.apache.rocketmq.remoting.RPCHook; import org.apache.rocketmq.remoting.RPCHook;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.time.Duration; import java.time.Duration;
import java.time.Instant; import java.time.Instant;
@@ -32,9 +33,10 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
@Component
public class AutoCloseConsumerWrapper { public class AutoCloseConsumerWrapper {
private final Logger logger = LoggerFactory.getLogger(GlobalRestfulResponseBodyAdvice.class); private final Logger logger = LoggerFactory.getLogger(AutoCloseConsumerWrapper.class);
private static final AtomicReference<DefaultMQPullConsumer> CONSUMER_REF = new AtomicReference<>(); private static final AtomicReference<DefaultMQPullConsumer> CONSUMER_REF = new AtomicReference<>();
private final AtomicBoolean isTaskScheduled = new AtomicBoolean(false); private final AtomicBoolean isTaskScheduled = new AtomicBoolean(false);
@@ -77,7 +79,10 @@ public class AutoCloseConsumerWrapper {
protected DefaultMQPullConsumer createNewConsumer(RPCHook rpcHook, Boolean useTLS) { protected DefaultMQPullConsumer createNewConsumer(RPCHook rpcHook, Boolean useTLS) {
return new DefaultMQPullConsumer(MixAll.TOOLS_CONSUMER_GROUP, rpcHook) { return new DefaultMQPullConsumer(MixAll.TOOLS_CONSUMER_GROUP, rpcHook) {
{ setUseTLS(useTLS); } }; {
setUseTLS(useTLS);
}
};
} }
private void startIdleCheckTask() { private void startIdleCheckTask() {

View File

@@ -37,8 +37,7 @@ public class GlobalExceptionHandler {
if (ex instanceof ServiceException) { if (ex instanceof ServiceException) {
logger.error("Occur service exception: {}", ex.getMessage()); logger.error("Occur service exception: {}", ex.getMessage());
value = new JsonResult<Object>(((ServiceException) ex).getCode(), ex.getMessage()); value = new JsonResult<Object>(((ServiceException) ex).getCode(), ex.getMessage());
} } else {
else {
logger.error("op=global_exception_handler_print_error", ex); logger.error("op=global_exception_handler_print_error", ex);
value = new JsonResult<Object>(-1, ex.getMessage() == null ? ex.toString() : ex.getMessage()); value = new JsonResult<Object>(-1, ex.getMessage() == null ? ex.toString() : ex.getMessage());
} }

View File

@@ -37,18 +37,17 @@ public class GlobalRestfulResponseBodyAdvice implements ResponseBodyAdvice<Objec
@Override @Override
public Object beforeBodyWrite( public Object beforeBodyWrite(
Object obj, MethodParameter methodParameter, MediaType mediaType, Object obj, MethodParameter methodParameter, MediaType mediaType,
Class<? extends HttpMessageConverter<?>> converterType, Class<? extends HttpMessageConverter<?>> converterType,
ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) { ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
Annotation originalControllerReturnValue = methodParameter.getMethodAnnotation(OriginalControllerReturnValue.class); Annotation originalControllerReturnValue = methodParameter.getMethodAnnotation(OriginalControllerReturnValue.class);
if (originalControllerReturnValue != null) { if (originalControllerReturnValue != null) {
return obj; return obj;
} }
JsonResult value; JsonResult value;
if (obj instanceof JsonResult) { if (obj instanceof JsonResult) {
value = (JsonResult)obj; value = (JsonResult) obj;
} } else {
else {
value = new JsonResult(obj); value = new JsonResult(obj);
} }
return value; return value;

View File

@@ -44,7 +44,7 @@ public class CollectTaskRunnble implements Runnable {
private DashboardCollectService dashboardCollectService; private DashboardCollectService dashboardCollectService;
public CollectTaskRunnble(String topic, MQAdminExt mqAdminExt, public CollectTaskRunnble(String topic, MQAdminExt mqAdminExt,
DashboardCollectService dashboardCollectService) { DashboardCollectService dashboardCollectService) {
this.topic = topic; this.topic = topic;
this.mqAdminExt = mqAdminExt; this.mqAdminExt = mqAdminExt;
this.dashboardCollectService = dashboardCollectService; this.dashboardCollectService = dashboardCollectService;

View File

@@ -80,15 +80,14 @@ public class DashboardCollectTask {
this.addSystemTopic(); this.addSystemTopic();
for (String topic : topicSet) { for (String topic : topicSet) {
if (topic.startsWith(MixAll.RETRY_GROUP_TOPIC_PREFIX) if (topic.startsWith(MixAll.RETRY_GROUP_TOPIC_PREFIX)
|| topic.startsWith(MixAll.DLQ_GROUP_TOPIC_PREFIX) || topic.startsWith(MixAll.DLQ_GROUP_TOPIC_PREFIX)
|| TopicValidator.isSystemTopic(topic)) { || TopicValidator.isSystemTopic(topic)) {
continue; continue;
} }
CollectTaskRunnble collectTask = new CollectTaskRunnble(topic, mqAdminExt, dashboardCollectService); CollectTaskRunnble collectTask = new CollectTaskRunnble(topic, mqAdminExt, dashboardCollectService);
collectExecutor.submit(collectTask); collectExecutor.submit(collectTask);
} }
} } catch (Exception err) {
catch (Exception err) {
Throwables.throwIfUnchecked(err); Throwables.throwIfUnchecked(err);
throw new RuntimeException(err); throw new RuntimeException(err);
} }
@@ -100,7 +99,6 @@ public class DashboardCollectTask {
} }
@Scheduled(cron = "0 0/1 * * * ?") @Scheduled(cron = "0 0/1 * * * ?")
public void collectBroker() { public void collectBroker() {
if (!rmqConfigure.isEnableDashBoardCollect()) { if (!rmqConfigure.isEnableDashBoardCollect()) {
@@ -139,8 +137,7 @@ public class DashboardCollectTask {
dashboardCollectService.getBrokerMap().put(entry.getValue(), list); dashboardCollectService.getBrokerMap().put(entry.getValue(), list);
} }
log.debug("Broker Collected Data in memory = {}" + JsonUtil.obj2String(dashboardCollectService.getBrokerMap().asMap())); log.debug("Broker Collected Data in memory = {}" + JsonUtil.obj2String(dashboardCollectService.getBrokerMap().asMap()));
} } catch (Exception e) {
catch (Exception e) {
Throwables.throwIfUnchecked(e); Throwables.throwIfUnchecked(e);
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@@ -152,12 +149,10 @@ public class DashboardCollectTask {
} }
try { try {
return mqAdminExt.fetchBrokerRuntimeStats(brokerAddr); return mqAdminExt.fetchBrokerRuntimeStats(brokerAddr);
} } catch (Exception e) {
catch (Exception e) {
try { try {
Thread.sleep(1000); Thread.sleep(1000);
} } catch (InterruptedException e1) {
catch (InterruptedException e1) {
Throwables.throwIfUnchecked(e1); Throwables.throwIfUnchecked(e1);
throw new RuntimeException(e1); throw new RuntimeException(e1);
} }
@@ -189,16 +184,14 @@ public class DashboardCollectTask {
Map<String, List<String>> topicFileMap; Map<String, List<String>> topicFileMap;
if (brokerFile.exists()) { if (brokerFile.exists()) {
brokerFileMap = dashboardCollectService.jsonDataFile2map(brokerFile); brokerFileMap = dashboardCollectService.jsonDataFile2map(brokerFile);
} } else {
else {
brokerFileMap = Maps.newHashMap(); brokerFileMap = Maps.newHashMap();
Files.createParentDirs(brokerFile); Files.createParentDirs(brokerFile);
} }
if (topicFile.exists()) { if (topicFile.exists()) {
topicFileMap = dashboardCollectService.jsonDataFile2map(topicFile); topicFileMap = dashboardCollectService.jsonDataFile2map(topicFile);
} } else {
else {
topicFileMap = Maps.newHashMap(); topicFileMap = Maps.newHashMap();
Files.createParentDirs(topicFile); Files.createParentDirs(topicFile);
} }
@@ -211,21 +204,19 @@ public class DashboardCollectTask {
log.debug("Broker Collected Data in memory = {}" + JsonUtil.obj2String(dashboardCollectService.getBrokerMap().asMap())); log.debug("Broker Collected Data in memory = {}" + JsonUtil.obj2String(dashboardCollectService.getBrokerMap().asMap()));
log.debug("Topic Collected Data in memory = {}" + JsonUtil.obj2String(dashboardCollectService.getTopicMap().asMap())); log.debug("Topic Collected Data in memory = {}" + JsonUtil.obj2String(dashboardCollectService.getTopicMap().asMap()));
} } catch (IOException e) {
catch (IOException e) {
Throwables.throwIfUnchecked(e); Throwables.throwIfUnchecked(e);
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
private void writeFile(LoadingCache<String, List<String>> map, Map<String, List<String>> fileMap, private void writeFile(LoadingCache<String, List<String>> map, Map<String, List<String>> fileMap,
File file) throws IOException { File file) throws IOException {
Map<String, List<String>> newMap = map.asMap(); Map<String, List<String>> newMap = map.asMap();
Map<String, List<String>> resultMap = Maps.newHashMap(); Map<String, List<String>> resultMap = Maps.newHashMap();
if (fileMap.size() == 0) { if (fileMap.size() == 0) {
resultMap = newMap; resultMap = newMap;
} } else {
else {
for (Map.Entry<String, List<String>> entry : fileMap.entrySet()) { for (Map.Entry<String, List<String>> entry : fileMap.entrySet()) {
List<String> oldList = entry.getValue(); List<String> oldList = entry.getValue();
List<String> newList = newMap.get(entry.getKey()); List<String> newList = newMap.get(entry.getKey());

View File

@@ -38,7 +38,7 @@ public class MonitorTask {
@Resource @Resource
private ConsumerService consumerService; private ConsumerService consumerService;
// @Scheduled(cron = "* * * * * ?") // @Scheduled(cron = "* * * * * ?")
public void scanProblemConsumeGroup() { public void scanProblemConsumeGroup() {
for (Map.Entry<String, ConsumerMonitorConfig> configEntry : monitorService.queryConsumerMonitorConfig().entrySet()) { for (Map.Entry<String, ConsumerMonitorConfig> configEntry : monitorService.queryConsumerMonitorConfig().entrySet()) {
GroupConsumeInfo consumeInfo = consumerService.queryGroup(configEntry.getKey(), null); GroupConsumeInfo consumeInfo = consumerService.queryGroup(configEntry.getKey(), null);

View File

@@ -31,10 +31,10 @@ import java.util.List;
public class ExcelUtil { public class ExcelUtil {
public static void writeExcel(HttpServletResponse response, List<? extends Object> data, String fileName, public static void writeExcel(HttpServletResponse response, List<? extends Object> data, String fileName,
String sheetName, Class clazz) throws Exception { String sheetName, Class clazz) throws Exception {
WriteCellStyle headWriteCellStyle = new WriteCellStyle(); WriteCellStyle headWriteCellStyle = new WriteCellStyle();
WriteFont writeFont = new WriteFont(); WriteFont writeFont = new WriteFont();
writeFont.setFontHeightInPoints((short)12); writeFont.setFontHeightInPoints((short) 12);
writeFont.setFontName("Microsoft YaHei UI"); writeFont.setFontName("Microsoft YaHei UI");
headWriteCellStyle.setWriteFont(writeFont); headWriteCellStyle.setWriteFont(writeFont);
headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER); headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
@@ -44,7 +44,7 @@ public class ExcelUtil {
contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER); contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle); HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
EasyExcel.write(getOutputStream(fileName, response), clazz) EasyExcel.write(getOutputStream(fileName, response), clazz)
.excelType(ExcelTypeEnum.XLSX).sheet(sheetName).registerWriteHandler(horizontalCellStyleStrategy).doWrite(data); .excelType(ExcelTypeEnum.XLSX).sheet(sheetName).registerWriteHandler(horizontalCellStyleStrategy).doWrite(data);
} }
private static OutputStream getOutputStream(String fileName, HttpServletResponse response) throws Exception { private static OutputStream getOutputStream(String fileName, HttpServletResponse response) throws Exception {

View File

@@ -55,8 +55,7 @@ public class JsonUtil {
public static void writeValue(Writer writer, Object obj) { public static void writeValue(Writer writer, Object obj) {
try { try {
objectMapper.writeValue(writer, obj); objectMapper.writeValue(writer, obj);
} } catch (IOException e) {
catch (IOException e) {
Throwables.propagateIfPossible(e); Throwables.propagateIfPossible(e);
} }
} }
@@ -67,9 +66,8 @@ public class JsonUtil {
} }
try { try {
return src instanceof String ? (String)src : objectMapper.writeValueAsString(src); return src instanceof String ? (String) src : objectMapper.writeValueAsString(src);
} } catch (Exception e) {
catch (Exception e) {
logger.error("Parse Object to String error src=" + src, e); logger.error("Parse Object to String error src=" + src, e);
return null; return null;
} }
@@ -81,9 +79,8 @@ public class JsonUtil {
} }
try { try {
return src instanceof byte[] ? (byte[])src : objectMapper.writeValueAsBytes(src); return src instanceof byte[] ? (byte[]) src : objectMapper.writeValueAsBytes(src);
} } catch (Exception e) {
catch (Exception e) {
logger.error("Parse Object to byte[] error", e); logger.error("Parse Object to byte[] error", e);
return null; return null;
} }
@@ -95,9 +92,8 @@ public class JsonUtil {
} }
str = escapesSpecialChar(str); str = escapesSpecialChar(str);
try { try {
return clazz.equals(String.class) ? (T)str : objectMapper.readValue(str, clazz); return clazz.equals(String.class) ? (T) str : objectMapper.readValue(str, clazz);
} } catch (Exception e) {
catch (Exception e) {
logger.error("Parse String to Object error\nString: {}\nClass<T>: {}\nError: {}", str, clazz.getName(), e); logger.error("Parse String to Object error\nString: {}\nClass<T>: {}\nError: {}", str, clazz.getName(), e);
return null; return null;
} }
@@ -108,9 +104,8 @@ public class JsonUtil {
return null; return null;
} }
try { try {
return clazz.equals(byte[].class) ? (T)bytes : objectMapper.readValue(bytes, clazz); return clazz.equals(byte[].class) ? (T) bytes : objectMapper.readValue(bytes, clazz);
} } catch (Exception e) {
catch (Exception e) {
logger.error("Parse byte[] to Object error\nbyte[]: {}\nClass<T>: {}\nError: {}", bytes, clazz.getName(), e); logger.error("Parse byte[] to Object error\nbyte[]: {}\nClass<T>: {}\nError: {}", bytes, clazz.getName(), e);
return null; return null;
} }
@@ -122,11 +117,10 @@ public class JsonUtil {
} }
str = escapesSpecialChar(str); str = escapesSpecialChar(str);
try { try {
return (T)(typeReference.getType().equals(String.class) ? str : objectMapper.readValue(str, typeReference)); return (T) (typeReference.getType().equals(String.class) ? str : objectMapper.readValue(str, typeReference));
} } catch (Exception e) {
catch (Exception e) {
logger.error("Parse String to Object error\nString: {}\nTypeReference<T>: {}\nError: {}", str, logger.error("Parse String to Object error\nString: {}\nTypeReference<T>: {}\nError: {}", str,
typeReference.getType(), e); typeReference.getType(), e);
return null; return null;
} }
} }
@@ -136,12 +130,11 @@ public class JsonUtil {
return null; return null;
} }
try { try {
return (T)(typeReference.getType().equals(byte[].class) ? bytes : objectMapper.readValue(bytes, return (T) (typeReference.getType().equals(byte[].class) ? bytes : objectMapper.readValue(bytes,
typeReference)); typeReference));
} } catch (Exception e) {
catch (Exception e) {
logger.error("Parse byte[] to Object error\nbyte[]: {}\nTypeReference<T>: {}\nError: {}", bytes, logger.error("Parse byte[] to Object error\nbyte[]: {}\nTypeReference<T>: {}\nError: {}", bytes,
typeReference.getType(), e); typeReference.getType(), e);
return null; return null;
} }
} }

View File

@@ -107,7 +107,7 @@ public class WebUtil {
HttpSession session = request.getSession(false); HttpSession session = request.getSession(false);
if (session != null) { if (session != null) {
return session.getAttribute(key); return session.getAttribute(key);
} }
return null; return null;

View File

@@ -17,34 +17,34 @@
--> -->
<configuration> <configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder charset="UTF-8"> <encoder charset="UTF-8">
<pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] %p %t - %m%n</pattern>
</encoder>
</appender>
<appender name="FILE"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${user.home}/logs/dashboardlogs/rocketmq-dashboard.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${user.home}/logs/dashboardlogs/rocketmq-dashboard-%d{yyyy-MM-dd}.%i.log
</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>104857600</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<MaxHistory>10</MaxHistory>
</rollingPolicy>
<encoder>
<pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] %p %t - %m%n</pattern> <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] %p %t - %m%n</pattern>
<charset class="java.nio.charset.Charset">UTF-8</charset> </encoder>
</encoder> </appender>
</appender>
<root level="INFO"> <appender name="FILE"
<appender-ref ref="STDOUT" /> class="ch.qos.logback.core.rolling.RollingFileAppender">
<appender-ref ref="FILE" /> <file>${user.home}/logs/dashboardlogs/rocketmq-dashboard.log</file>
</root> <append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${user.home}/logs/dashboardlogs/rocketmq-dashboard-%d{yyyy-MM-dd}.%i.log
</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>104857600</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<MaxHistory>10</MaxHistory>
</rollingPolicy>
<encoder>
<pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] %p %t - %m%n</pattern>
<charset class="java.nio.charset.Charset">UTF-8</charset>
</encoder>
</appender>
</configuration> <root level="INFO">
<appender-ref ref="STDOUT"/>
<appender-ref ref="FILE"/>
</root>
</configuration>

View File

@@ -14,13 +14,10 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# #
# This file supports hot change, any change will be auto-reloaded without Dashboard restarting. # This file supports hot change, any change will be auto-reloaded without Dashboard restarting.
# Format: a user per line, username=password[,N] #N is optional, 0 (Normal User); 1 (Admin) # Format: a user per line, username=password[,N] #N is optional, 0 (Normal User); 1 (Admin)
# Define Admin # Define Admin
admin=admin,1 super=admin,1
# Define Users # Define Users
user1=user1 user1=user
user2=user2 user2=user