[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:
### `npm start`
### `npm run start`
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.\
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`
Builds the app for production to the `build` folder.\

View File

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

View File

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

View File

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

View File

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

View File

@@ -16,16 +16,16 @@
*/
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 { ExclamationCircleOutlined, SyncOutlined } from '@ant-design/icons';
import { useLanguage } from '../i18n/LanguageContext';
import { remoteApi } from '../api/remoteApi/remoteApi'; // 确保这个路径正确
import {SyncOutlined} from '@ant-design/icons';
import {useLanguage} from '../i18n/LanguageContext';
import {remoteApi} from '../api/remoteApi/remoteApi'; // 确保这个路径正确
const { Text, Paragraph } = Typography;
const {Text, Paragraph} = Typography;
const MessageDetailViewDialog = ({ visible, onCancel, messageId, topic, onResendMessage }) => {
const { t } = useLanguage();
const MessageDetailViewDialog = ({visible, onCancel, messageId, topic, onResendMessage}) => {
const {t} = useLanguage();
const [loading, setLoading] = React.useState(true);
const [messageDetail, setMessageDetail] = 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}>
{error && (
<Paragraph type="danger" style={{ textAlign: 'center' }}>
<Paragraph type="danger" style={{textAlign: 'center'}}>
{error}
</Paragraph>
)}
{messageDetail ? ( // 确保 messageDetail 存在时才渲染内容
<>
{/* 消息信息部分 */}
<Descriptions title={<Text strong>{t.MESSAGE_INFO}</Text>} bordered column={2} size="small" style={{ marginBottom: 20 }}>
<Descriptions.Item label="Topic" span={2}><Text 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 title={<Text strong>{t.MESSAGE_INFO}</Text>} bordered column={2} size="small"
style={{marginBottom: 20}}>
<Descriptions.Item label="Topic" span={2}><Text
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="StoreTime">
{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")}
</Descriptions.Item>
<Descriptions.Item label="Queue ID">{messageDetail.messageView.queueId}</Descriptions.Item>
<Descriptions.Item label="Queue Offset">{messageDetail.messageView.queueOffset}</Descriptions.Item>
<Descriptions.Item label="StoreSize">{messageDetail.messageView.storeSize} bytes</Descriptions.Item>
<Descriptions.Item label="ReconsumeTimes">{messageDetail.messageView.reconsumeTimes}</Descriptions.Item>
<Descriptions.Item
label="Queue Offset">{messageDetail.messageView.queueOffset}</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="SysFlag">{messageDetail.messageView.sysFlag}</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>
{/* 消息属性部分 */}
{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]) => (
<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 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>
<Paragraph
copyable
@@ -146,9 +157,10 @@ const MessageDetailViewDialog = ({ visible, onCancel, messageId, topic, onResend
{messageDetail.messageTrackList && messageDetail.messageTrackList.length > 0 ? (
<>
<Text strong>{t.MESSAGE_TRACKING}</Text>
<div style={{ marginTop: 10 }}>
<div style={{marginTop: 10}}>
{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}>
{track.consumerGroup}
</Descriptions.Item>
@@ -165,10 +177,10 @@ const MessageDetailViewDialog = ({ visible, onCancel, messageId, topic, onResend
</Descriptions.Item>
<Descriptions.Item label={t.OPERATION}>
<Button
icon={<SyncOutlined />}
icon={<SyncOutlined/>}
onClick={() => onResendMessage(messageDetail.messageView, track.consumerGroup)}
size="small"
style={{ marginRight: 8 }}
style={{marginRight: 8}}
>
{t.RESEND_MESSAGE}
</Button>
@@ -181,7 +193,10 @@ const MessageDetailViewDialog = ({ visible, onCancel, messageId, topic, onResend
ellipsis={{
rows: 2, // 默认显示2行
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}
@@ -198,7 +213,8 @@ const MessageDetailViewDialog = ({ visible, onCancel, messageId, topic, onResend
</>
) : (
// 当 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>
</Modal>

View File

@@ -15,15 +15,15 @@
* limitations under the License.
*/
import React, { useEffect, useRef } from 'react';
import { Form, Input, Typography, Collapse, Table, Tag } from 'antd';
import React, {useEffect, useRef} from 'react';
import {Collapse, Form, Input, Table, Tag, Typography} from 'antd';
import moment from 'moment';
import { useLanguage } from '../i18n/LanguageContext';
import {useLanguage} from '../i18n/LanguageContext';
import Paragraph from "antd/es/skeleton/Paragraph";
import * as echarts from 'echarts'; // Import ECharts
const { Text } = Typography;
const { Panel } = Collapse;
const {Text} = Typography;
const {Panel} = Collapse;
// Constants for styling and formatting, derived from the example
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 TRANSACTION_CHECK_COST_TIME = 50; // transactionTraceNode do not have costTime, assume it cost 50ms
const MessageTraceDetailViewDialog = ({ ngDialogData }) => {
const { t } = useLanguage();
const MessageTraceDetailViewDialog = ({ngDialogData}) => {
const {t} = useLanguage();
const messageTraceGraphRef = useRef(null);
const producerNode = ngDialogData?.producerNode;
@@ -125,6 +125,7 @@ const MessageTraceDetailViewDialog = ({ ngDialogData }) => {
}
return `Cost Time: ${formatCostTimeStr(costTime)}<br/>`
}
function buildTimeStamp(timestamp) {
if (timestamp < 0) {
return 'N/A';
@@ -323,94 +324,181 @@ const MessageTraceDetailViewDialog = ({ ngDialogData }) => {
// ... (rest of your existing component code)
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.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' },
{
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.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 = [
{ 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.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' },
{
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.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 (
<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={{padding: '20px', backgroundColor: '#f0f2f5'}}>
<div style={{
marginBottom: '20px',
borderRadius: '8px',
overflow: 'hidden',
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.08)'
}}>
<Collapse defaultActiveKey={['messageTraceGraph']} expandIconPosition="right">
<Panel header={<Typography.Title level={3} style={{ margin: 0, color: '#333' }}>{t.MESSAGE_TRACE_GRAPH}</Typography.Title>} key="messageTraceGraph">
<div ref={messageTraceGraphRef} style={{ height: 500, width: '100%', backgroundColor: '#fff', padding: '10px' }}>
<Panel header={<Typography.Title level={3} style={{
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 */}
{(!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>
</Panel>
</Collapse>
</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">
<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 ? (
<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' }}>
<Typography.Title level={4} style={{ marginBottom: '20px' }}>
{t.SEND_MESSAGE_INFO} : ( {t.MESSAGE_ID} <Text strong copyable>{producerNode.msgId}</Text> )
<div style={{padding: '16px', backgroundColor: '#fff'}}>
<Typography.Title level={4} style={{marginBottom: '20px'}}>
{t.SEND_MESSAGE_INFO} : ( {t.MESSAGE_ID} <Text strong
copyable>{producerNode.msgId}</Text> )
</Typography.Title>
<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>}>
<Input value={producerNode.topic} readOnly />
<Input value={producerNode.topic} readOnly/>
</Form.Item>
<Form.Item label={<Text strong>{t.PRODUCER_GROUP}</Text>}>
<Input value={producerNode.groupName} readOnly />
<Input value={producerNode.groupName} readOnly/>
</Form.Item>
<Form.Item label={<Text strong>{t.MESSAGE_KEY}</Text>}>
<Input value={producerNode.keys} readOnly />
<Input value={producerNode.keys} readOnly/>
</Form.Item>
<Form.Item label={<Text strong>{t.TAG}</Text>}>
<Input value={producerNode.tags} readOnly />
<Input value={producerNode.tags} readOnly/>
</Form.Item>
<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 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 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 label={<Text strong>{t.MSG_TYPE}</Text>}>
<Input value={producerNode.traceNode.msgType} readOnly />
<Input value={producerNode.traceNode.msgType} readOnly/>
</Form.Item>
<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 label={<Text strong>{t.STORE_HOST}</Text>}>
<Input value={producerNode.traceNode.storeHost} readOnly />
<Input value={producerNode.traceNode.storeHost} readOnly/>
</Form.Item>
<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 label={<Text strong>{t.OFFSET_MSG_ID}</Text>}>
<Input value={producerNode.offSetMsgId} readOnly />
<Input value={producerNode.offSetMsgId} readOnly/>
</Form.Item>
</div>
</Form>
{producerNode.transactionNodeList && producerNode.transactionNodeList.length > 0 && (
<div style={{ marginTop: '30px' }}>
<Typography.Title level={4} style={{ marginBottom: '15px' }}>{t.CHECK_TRANSACTION_INFO}:</Typography.Title>
<div style={{marginTop: '30px'}}>
<Typography.Title level={4}
style={{marginBottom: '15px'}}>{t.CHECK_TRANSACTION_INFO}:</Typography.Title>
<Table
columns={transactionColumns}
dataSource={producerNode.transactionNodeList}
@@ -418,7 +506,7 @@ const MessageTraceDetailViewDialog = ({ ngDialogData }) => {
bordered
pagination={false}
size="middle"
scroll={{ x: 'max-content' }}
scroll={{x: 'max-content'}}
/>
</div>
)}
@@ -428,22 +516,31 @@ const MessageTraceDetailViewDialog = ({ ngDialogData }) => {
</Collapse>
</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">
<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 ? (
<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 => (
<Collapse
key={subscriptionNode.subscriptionGroup}
style={{ marginBottom: '10px', border: '1px solid #e0e0e0', borderRadius: '4px' }}
style={{marginBottom: '10px', border: '1px solid #e0e0e0', borderRadius: '4px'}}
defaultActiveKey={[subscriptionNode.subscriptionGroup]}
ghost
>
<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}
>
<Table
@@ -453,7 +550,7 @@ const MessageTraceDetailViewDialog = ({ ngDialogData }) => {
bordered
pagination={false}
size="middle"
scroll={{ x: 'max-content' }}
scroll={{x: 'max-content'}}
/>
</Panel>
</Collapse>

View File

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

View File

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

View File

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

View File

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

View File

@@ -15,13 +15,23 @@
* limitations under the License.
*/
import React, { useEffect, useState } from 'react';
import { Button, Descriptions, Form, Input, Select, Switch, message } from 'antd';
import { remoteApi } from '../../api/remoteApi/remoteApi'; // 确保路径正确
import React, {useEffect, useState} from 'react';
import {Button, Descriptions, Form, Input, message, Select, Switch} from 'antd';
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 [currentBrokerName, setCurrentBrokerName] = useState(brokerName);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -18,7 +18,7 @@
import {Button, Modal, Table} from "antd";
import React from "react";
const ResetOffsetResultDialog = ({ visible, onClose, result, t }) => {
const ResetOffsetResultDialog = ({visible, onClose, result, t}) => {
return (
<Modal
title="ResetResult"
@@ -31,12 +31,12 @@ const ResetOffsetResultDialog = ({ visible, onClose, result, t }) => {
]}
>
{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
dataSource={[{ groupName, status: groupData.status }]}
dataSource={[{groupName, status: groupData.status}]}
columns={[
{ title: 'GroupName', dataIndex: 'groupName', key: 'groupName' },
{ title: 'State', dataIndex: 'status', key: 'status' },
{title: 'GroupName', dataIndex: 'groupName', key: 'groupName'},
{title: 'State', dataIndex: 'status', key: 'status'},
]}
pagination={false}
rowKey="groupName"
@@ -47,8 +47,8 @@ const ResetOffsetResultDialog = ({ visible, onClose, result, t }) => {
<div>You Should Check It Yourself</div>
) : (
<Table
dataSource={groupData.rollbackStatsList.map((item, index) => ({ key: index, item }))}
columns={[{ dataIndex: 'item', key: 'item' }]}
dataSource={groupData.rollbackStatsList.map((item, index) => ({key: index, item}))}
columns={[{dataIndex: 'item', key: 'item'}]}
pagination={false}
rowKey="key"
size="small"

View File

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

View File

@@ -18,7 +18,7 @@
import {Button, Form, Modal, Table} from "antd";
import React from "react";
const SendResultDialog = ({ visible, onClose, result, t }) => {
const SendResultDialog = ({visible, onClose, result, t}) => {
return (
<Modal
title="SendResult"
@@ -43,11 +43,11 @@ const SendResultDialog = ({ visible, onClose, result, t }) => {
: []
}
columns={[
{ dataIndex: 'label', key: 'label' },
{dataIndex: 'label', key: 'label'},
{
dataIndex: '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}
@@ -61,5 +61,4 @@ const SendResultDialog = ({ visible, onClose, result, t }) => {
};
export default SendResultDialog;

View File

@@ -76,24 +76,24 @@ const SendTopicMessageDialog = ({
</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">
<Input disabled />
<Input disabled/>
</Form.Item>
<Form.Item label={t.TAG} name="tag">
<Input />
<Input/>
</Form.Item>
<Form.Item label={t.KEY} name="key">
<Input />
<Input/>
</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
style={{ maxHeight: '200px', minHeight: '200px', resize: 'none' }}
style={{maxHeight: '200px', minHeight: '200px', resize: 'none'}}
rows={8}
/>
</Form.Item>
<Form.Item label={t.ENABLE_MESSAGE_TRACE} name="traceEnabled" valuePropName="checked">
<Checkbox />
<Checkbox/>
</Form.Item>
</Form>
</Modal>

View File

@@ -15,10 +15,17 @@
* limitations under the License.
*/
import { Button, Form, message, Modal, Select } from "antd";
import React, { useEffect, useState } from "react";
import {Button, Form, message, Modal, Select} from "antd";
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 [selectedConsumerGroup, setSelectedConsumerGroup] = useState([]);
@@ -52,14 +59,14 @@ const SkipMessageAccumulateDialog = ({ visible, onClose, topic, allConsumerGroup
</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>
<Select
mode="multiple"
placeholder={t.SELECT_CONSUMER_GROUP}
value={selectedConsumerGroup}
onChange={setSelectedConsumerGroup}
options={allConsumerGroupList.map(group => ({ value: group, label: group }))}
options={allConsumerGroupList.map(group => ({value: group, label: group}))}
/>
</Form.Item>
</Form>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -19,7 +19,7 @@ import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import { App as AntdApp } from 'antd';
import {App as AntdApp} from 'antd';
import reportWebVitals from './reportWebVitals';
import {LanguageProvider} from "./i18n/LanguageContext";
import {Provider} from "react-redux";
@@ -27,17 +27,15 @@ import store from './store';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<LanguageProvider>
<React.StrictMode>
<AntdApp>
<Provider store={store}>
<App/>
<App/>
</Provider>
</AntdApp>
</React.StrictMode>
</LanguageProvider>
);
// 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 [showDeleteModal, setShowDeleteModal] = useState(false);
const [messageApi, msgContextHolder] = message.useMessage();
const [notificationApi,notificationContextHolder] = notification.useNotification();
const [notificationApi, notificationContextHolder] = notification.useNotification();
const [paginationConf, setPaginationConf] = useState({
current: 1,
@@ -63,9 +63,9 @@ const ConsumerGroupList = () => {
const response = await remoteApi.queryConsumerGroupList(false);
if (response.status === 0) {
setAllConsumerGroupList(response.data);
if(currentPage!=null){
if (currentPage != null) {
filterList(currentPage, response.data);
}else{
} else {
filterList(1, response.data);
}
} else {
@@ -380,7 +380,7 @@ const ConsumerGroupList = () => {
filterList(pagination.current, allConsumerGroupList);
};
const closeConfigModal = () =>{
const closeConfigModal = () => {
setShowConfig(false);
setIsAddConfig(false);
}

View File

@@ -16,17 +16,17 @@
*/
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";
const { Title } = Typography;
const {Title} = Typography;
const Login = () => {
const [form] = Form.useForm();
const [messageApi, msgContextHolder] = message.useMessage();
const onFinish = async (values) => {
const { username, password } = values;
const {username, password} = values;
remoteApi.login(username, password).then((res) => {
if (res.status === 0) {
messageApi.success('登录成功');

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -16,7 +16,8 @@
~ 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>
<groupId>org.apache</groupId>
@@ -432,7 +433,7 @@
</configuration>
<executions>
<execution>
<id>install node </id>
<id>install node</id>
<goals>
<goal>install-node-and-npm</goal>
</goals>
@@ -469,7 +470,7 @@
<configuration>
<target>
<copy todir="${project.build.directory}/classes/public">
<fileset dir="${project.basedir}/frontend-new/build" />
<fileset dir="${project.basedir}/frontend-new/build"/>
</copy>
</target>
</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
public PooledObject<MQAdminExt> makeObject() throws Exception {
DefaultPooledObject<MQAdminExt> pooledObject = new DefaultPooledObject<>(
mqAdminFactory.getInstance());
mqAdminFactory.getInstance());
return pooledObject;
}

View File

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

View File

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

View File

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

View File

@@ -54,7 +54,7 @@ public class ConsumerController {
@RequestMapping(value = "/group.refresh")
@ResponseBody
public Object refresh(String address,
String consumerGroup) {
String consumerGroup) {
return consumerService.refreshGroup(address, consumerGroup);
}
@@ -100,7 +100,7 @@ public class ConsumerController {
@ResponseBody
public Object consumerCreateOrUpdateRequest(@RequestBody ConsumerConfigInfo consumerConfigInfo) {
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);
}
@@ -127,7 +127,7 @@ public class ConsumerController {
@RequestMapping(value = "/consumerRunningInfo.query")
@ResponseBody
public Object getConsumerRunningInfo(@RequestParam String consumerGroup, @RequestParam String clientId,
@RequestParam boolean jstack) {
@RequestParam boolean jstack) {
return consumerService.getConsumerRunningInfo(consumerGroup, clientId, jstack);
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -59,7 +59,7 @@ public class TestController {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
ConsumeConcurrentlyContext context) {
ConsumeConcurrentlyContext context) {
logger.info("receiveMessage msgSize={}", msgs.size());
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
@@ -72,26 +72,25 @@ public class TestController {
new Thread(new Runnable() {
@Override public void run() {
@Override
public void run() {
int i = 0;
while (true) {
try {
Message msg = new Message(testTopic,
"TagA" + i,
"KEYS" + i,
("Hello RocketMQ " + i).getBytes()
"TagA" + i,
"KEYS" + i,
("Hello RocketMQ " + i).getBytes()
);
Thread.sleep(1000L);
SendResult sendResult = producer.send(msg);
logger.info("sendMessage={}", JsonUtil.obj2String(sendResult));
}
catch (Exception e) {
} catch (Exception e) {
e.printStackTrace();
try {
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)
@ResponseBody
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);
}
@@ -75,11 +75,11 @@ public class TopicController {
}
@RequestMapping(value = "/createOrUpdate.do", method = { RequestMethod.POST})
@RequestMapping(value = "/createOrUpdate.do", method = {RequestMethod.POST})
@ResponseBody
public Object topicCreateOrUpdateRequest(@RequestBody TopicConfigInfo topicCreateOrUpdateRequest) {
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));
topicService.createOrUpdate(topicCreateOrUpdateRequest);
return true;
@@ -100,14 +100,14 @@ public class TopicController {
@RequestMapping(value = "/examineTopicConfig.query")
@ResponseBody
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);
}
@RequestMapping(value = "/sendTopicMessage.do", method = {RequestMethod.POST})
@ResponseBody
public Object sendTopicMessage(
@RequestBody SendTopicMessageRequest sendTopicMessageRequest) throws RemotingException, MQClientException, InterruptedException {
@RequestBody SendTopicMessageRequest sendTopicMessageRequest) throws RemotingException, MQClientException, InterruptedException {
return topicService.sendTopicMessageRequest(sendTopicMessageRequest);
}

View File

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

View File

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

View File

@@ -15,6 +15,7 @@
* limitations under the License.
*/
package org.apache.rocketmq.dashboard.model.request;
import com.google.common.base.Objects;
import java.util.List;
@@ -24,7 +25,9 @@ public class TopicConfigInfo {
private List<String> clusterNameList;
private List<String> brokerNameList;
/** topicConfig */
/**
* topicConfig
*/
private String topicName;
private int writeQueueNums;
private int readQueueNums;
@@ -32,6 +35,7 @@ public class TopicConfigInfo {
private boolean order;
private String messageType;
public List<String> getClusterNameList() {
return clusterNameList;
}
@@ -40,8 +44,9 @@ public class TopicConfigInfo {
this.clusterNameList = clusterNameList;
}
/** topicConfig */
/**
* topicConfig
*/
public List<String> getBrokerNameList() {
@@ -102,8 +107,6 @@ public class TopicConfigInfo {
}
@Override
public boolean equals(Object o) {
if (this == o)
@@ -112,16 +115,16 @@ public class TopicConfigInfo {
return false;
TopicConfigInfo that = (TopicConfigInfo) o;
return writeQueueNums == that.writeQueueNums &&
readQueueNums == that.readQueueNums &&
perm == that.perm &&
order == that.order &&
Objects.equal(topicName, that.topicName) &&
Objects.equal(messageType, that.messageType);
readQueueNums == that.readQueueNums &&
perm == that.perm &&
order == that.order &&
Objects.equal(topicName, that.topicName) &&
Objects.equal(messageType, that.messageType);
}
@Override
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 {
@Resource
protected MQAdminExt mqAdminExt;
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();
if (CollectionUtils.isNotEmpty(clusterNameList)) {
try {
for (String clusterName : clusterNameList) {
finalBrokerNameList.addAll(clusterAddrTable.get(clusterName));
}
}
catch (Exception e) {
} catch (Exception e) {
Throwables.throwIfUnchecked(e);
throw new RuntimeException(e);
}

View File

@@ -39,5 +39,5 @@ public interface AclService {
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;
public interface ConsumerService {
List<GroupConsumeInfo> queryGroupList(boolean skipSysGroup,String address);
List<GroupConsumeInfo> queryGroupList(boolean skipSysGroup, String address);
GroupConsumeInfo queryGroup(String consumerGroup, String address);

View File

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

View File

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

View File

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

View File

@@ -24,5 +24,5 @@ public interface ProxyService {
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);
public MQAdminExtImpl() {}
public MQAdminExtImpl() {
}
@Override
public void updateBrokerConfig(String brokerAddr, Properties properties)
throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException,
UnsupportedEncodingException, InterruptedException, MQBrokerException, MQClientException {
throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException,
UnsupportedEncodingException, InterruptedException, MQBrokerException, MQClientException {
MQAdminInstance.threadLocalMQAdminExt().updateBrokerConfig(brokerAddr, properties);
}
@Override
public void createAndUpdateTopicConfig(String addr, TopicConfig config)
throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
MQAdminInstance.threadLocalMQAdminExt().createAndUpdateTopicConfig(addr, config);
}
@@ -118,7 +119,7 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override
public void createAndUpdateSubscriptionGroupConfig(String addr, SubscriptionGroupConfig config)
throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
MQAdminInstance.threadLocalMQAdminExt().createAndUpdateSubscriptionGroupConfig(addr, config);
}
@@ -134,8 +135,7 @@ public class MQAdminExtImpl implements MQAdminExt {
RemotingCommand response = null;
try {
response = remotingClient.invokeSync(addr, request, 8000);
}
catch (Exception err) {
} catch (Exception err) {
Throwables.throwIfUnchecked(err);
throw new RuntimeException(err);
}
@@ -178,7 +178,7 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override
public TopicStatsTable examineTopicStats(String topic)
throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
return MQAdminInstance.threadLocalMQAdminExt().examineTopicStats(topic);
}
@@ -191,14 +191,14 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override
public KVTable fetchBrokerRuntimeStats(String brokerAddr)
throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException,
InterruptedException, MQBrokerException {
throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException,
InterruptedException, MQBrokerException {
return MQAdminInstance.threadLocalMQAdminExt().fetchBrokerRuntimeStats(brokerAddr);
}
@Override
public ConsumeStats examineConsumeStats(String consumerGroup)
throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
return MQAdminInstance.threadLocalMQAdminExt().examineConsumeStats(consumerGroup);
}
@@ -209,7 +209,7 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override
public ConsumeStats examineConsumeStats(String consumerGroup, String topic)
throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
return MQAdminInstance.threadLocalMQAdminExt().examineConsumeStats(consumerGroup, topic);
}
@@ -220,27 +220,27 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override
public ClusterInfo examineBrokerClusterInfo()
throws InterruptedException, MQBrokerException, RemotingTimeoutException, RemotingSendRequestException,
RemotingConnectException {
throws InterruptedException, MQBrokerException, RemotingTimeoutException, RemotingSendRequestException,
RemotingConnectException {
return MQAdminInstance.threadLocalMQAdminExt().examineBrokerClusterInfo();
}
@Override
public TopicRouteData examineTopicRouteInfo(String topic)
throws RemotingException, MQClientException, InterruptedException {
throws RemotingException, MQClientException, InterruptedException {
return MQAdminInstance.threadLocalMQAdminExt().examineTopicRouteInfo(topic);
}
@Override
public ConsumerConnection examineConsumerConnectionInfo(String consumerGroup)
throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException,
InterruptedException, MQBrokerException, RemotingException, MQClientException {
throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException,
InterruptedException, MQBrokerException, RemotingException, MQClientException {
return MQAdminInstance.threadLocalMQAdminExt().examineConsumerConnectionInfo(consumerGroup);
}
@Override
public ProducerConnection examineProducerConnectionInfo(String producerGroup, String topic)
throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
return MQAdminInstance.threadLocalMQAdminExt().examineProducerConnectionInfo(producerGroup, topic);
}
@@ -251,14 +251,14 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override
public int wipeWritePermOfBroker(String namesrvAddr, String brokerName)
throws RemotingCommandException, RemotingConnectException, RemotingSendRequestException,
RemotingTimeoutException, InterruptedException, MQClientException {
throws RemotingCommandException, RemotingConnectException, RemotingSendRequestException,
RemotingTimeoutException, InterruptedException, MQClientException {
return MQAdminInstance.threadLocalMQAdminExt().wipeWritePermOfBroker(namesrvAddr, brokerName);
}
@Override
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);
}
@@ -269,62 +269,62 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override
public String getKVConfig(String namespace, String key)
throws RemotingException, MQClientException, InterruptedException {
throws RemotingException, MQClientException, InterruptedException {
return MQAdminInstance.threadLocalMQAdminExt().getKVConfig(namespace, key);
}
@Override
public KVTable getKVListByNamespace(String namespace)
throws RemotingException, MQClientException, InterruptedException {
throws RemotingException, MQClientException, InterruptedException {
return MQAdminInstance.threadLocalMQAdminExt().getKVListByNamespace(namespace);
}
@Override
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);
MQAdminInstance.threadLocalMQAdminExt().deleteTopicInBroker(addrs, topic);
}
@Override
public void deleteTopicInNameServer(Set<String> addrs, String topic)
throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
MQAdminInstance.threadLocalMQAdminExt().deleteTopicInNameServer(addrs, topic);
}
@Override
public void deleteSubscriptionGroup(String addr, String groupName)
throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
MQAdminInstance.threadLocalMQAdminExt().deleteSubscriptionGroup(addr, groupName);
}
@Override
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);
}
@Override
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);
}
@Override
public void deleteKvConfig(String namespace, String key)
throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
MQAdminInstance.threadLocalMQAdminExt().deleteKvConfig(namespace, key);
}
@Override
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);
}
@Override
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);
}
@@ -335,59 +335,59 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override
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);
}
@Override
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);
}
@Override
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);
}
@Override
public GroupList queryTopicConsumeByWho(String topic)
throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException,
InterruptedException, MQBrokerException, RemotingException, MQClientException {
throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException,
InterruptedException, MQBrokerException, RemotingException, MQClientException {
return MQAdminInstance.threadLocalMQAdminExt().queryTopicConsumeByWho(topic);
}
@Override
public boolean cleanExpiredConsumerQueue(String cluster)
throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQClientException,
InterruptedException {
throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQClientException,
InterruptedException {
return MQAdminInstance.threadLocalMQAdminExt().cleanExpiredConsumerQueue(cluster);
}
@Override
public boolean cleanExpiredConsumerQueueByAddr(String addr)
throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQClientException,
InterruptedException {
throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQClientException,
InterruptedException {
return MQAdminInstance.threadLocalMQAdminExt().cleanExpiredConsumerQueueByAddr(addr);
}
@Override
public ConsumerRunningInfo getConsumerRunningInfo(String consumerGroup, String clientId, boolean jstack)
throws RemotingException, MQClientException, InterruptedException {
throws RemotingException, MQClientException, InterruptedException {
return MQAdminInstance.threadLocalMQAdminExt().getConsumerRunningInfo(consumerGroup, clientId, jstack);
}
@Override
public List<MessageTrack> messageTrackDetail(MessageExt msg)
throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
return MQAdminInstance.threadLocalMQAdminExt().messageTrackDetail(msg);
}
@Override
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);
}
@@ -398,7 +398,7 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override
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);
}
@@ -424,7 +424,7 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override
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);
}
@@ -444,7 +444,7 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override
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);
}
@@ -454,7 +454,7 @@ public class MQAdminExtImpl implements MQAdminExt {
//https://github.com/apache/incubator-rocketmq/pull/69
@Override
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);
MQAdminImpl mqAdminImpl = MQAdminInstance.threadLocalMqClientInstance().getMQAdminImpl();
Set<String> clusterList = MQAdminInstance.threadLocalMQAdminExt().getTopicClusterList(topic);
@@ -478,7 +478,7 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override
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);
}
@@ -489,96 +489,99 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override
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);
}
@Override
public TopicList fetchTopicsByCLuster(
String clusterName) throws RemotingException, MQClientException, InterruptedException {
String clusterName) throws RemotingException, MQClientException, InterruptedException {
return MQAdminInstance.threadLocalMQAdminExt().fetchTopicsByCLuster(clusterName);
}
@Override
public boolean cleanUnusedTopic(
String cluster) throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQClientException, InterruptedException {
String cluster) throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQClientException, InterruptedException {
return MQAdminInstance.threadLocalMQAdminExt().cleanUnusedTopic(cluster);
}
@Override
public boolean cleanUnusedTopicByAddr(
String addr) throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQClientException, InterruptedException {
String addr) throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQClientException, InterruptedException {
return MQAdminInstance.threadLocalMQAdminExt().cleanUnusedTopicByAddr(addr);
}
@Override
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);
}
@Override
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);
}
@Override
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);
}
@Override
public Set<String> getTopicClusterList(
String topic) throws InterruptedException, MQBrokerException, MQClientException, RemotingException {
String topic) throws InterruptedException, MQBrokerException, MQClientException, RemotingException {
return MQAdminInstance.threadLocalMQAdminExt().getTopicClusterList(topic);
}
@Override
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);
}
@Override
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);
}
@Override
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);
}
@Override
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);
}
@Override
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);
}
// 4.0.0 added
@Override public void updateNameServerConfig(Properties properties,
List<String> list) throws InterruptedException, RemotingConnectException, UnsupportedEncodingException, RemotingSendRequestException, RemotingTimeoutException, MQClientException, MQBrokerException {
@Override
public void updateNameServerConfig(Properties properties,
List<String> list) throws InterruptedException, RemotingConnectException, UnsupportedEncodingException, RemotingSendRequestException, RemotingTimeoutException, MQClientException, MQBrokerException {
}
@Override public Map<String, Properties> getNameServerConfig(
List<String> list) throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException, MQClientException, UnsupportedEncodingException {
@Override
public Map<String, Properties> getNameServerConfig(
List<String> list) throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException, MQClientException, UnsupportedEncodingException {
return null;
}
@Override public QueryConsumeQueueResponseBody queryConsumeQueue(String brokerAddr, String topic,
int queueId, long index, int count,
String consumerGroup) throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException, MQClientException {
@Override
public QueryConsumeQueueResponseBody queryConsumeQueue(String brokerAddr, String topic,
int queueId, long index, int count,
String consumerGroup) throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException, MQClientException {
return null;
}
@@ -588,8 +591,9 @@ public class MQAdminExtImpl implements MQAdminExt {
}
@Override public boolean resumeCheckHalfMessage(String topic,
String msgId) throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
@Override
public boolean resumeCheckHalfMessage(String topic,
String msgId) throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
return false;
}
@@ -602,7 +606,7 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override
public void removeBrokerFromContainer(String brokerContainerAddr, String clusterName, String brokerName,
long brokerId) throws InterruptedException, MQBrokerException, RemotingTimeoutException,
long brokerId) throws InterruptedException, MQBrokerException, RemotingTimeoutException,
RemotingSendRequestException, RemotingConnectException {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'removeBrokerFromContainer'");
@@ -624,7 +628,7 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override
public ConsumeStats examineConsumeStats(String brokerAddr, String consumerGroup, String topicName,
long timeoutMillis) throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException,
long timeoutMillis) throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException,
RemotingConnectException, MQBrokerException {
// TODO Auto-generated method stub
return MQAdminInstance.threadLocalMQAdminExt().examineConsumeStats(brokerAddr, consumerGroup, topicName, timeoutMillis);
@@ -717,7 +721,7 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override
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
throw new UnsupportedOperationException("Unimplemented method 'getConsumerRunningInfo'");
}
@@ -731,7 +735,7 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override
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 {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'setMessageRequestMode'");
@@ -746,14 +750,14 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override
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
throw new UnsupportedOperationException("Unimplemented method 'resetOffsetByQueueId'");
}
@Override
public void createStaticTopic(String addr, String defaultTopic, TopicConfig topicConfig,
TopicQueueMappingDetail mappingDetail, boolean force)
TopicQueueMappingDetail mappingDetail, boolean force)
throws RemotingException, InterruptedException, MQBrokerException {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'createStaticTopic'");
@@ -761,7 +765,7 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override
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
throw new UnsupportedOperationException("Unimplemented method 'updateAndGetGroupReadForbidden'");
}
@@ -831,7 +835,7 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override
public void cleanControllerBrokerData(String controllerAddr, String clusterName, String brokerName,
String brokerAddr, boolean isCleanLivingBroker)
String brokerAddr, boolean isCleanLivingBroker)
throws RemotingException, InterruptedException, MQBrokerException {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'cleanControllerBrokerData'");

View File

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

View File

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

View File

@@ -34,6 +34,7 @@ public class DashboardServiceImpl implements DashboardService {
@Resource
private DashboardCollectService dashboardCollectService;
/**
* @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
*/
@Override

View File

@@ -60,7 +60,7 @@ public class DlqMessageServiceImpl implements DlqMessageService {
} catch (MQClientException e) {
// If the %DLQ%Group does not exist, the message returns null
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());
} else {
Throwables.throwIfUnchecked(e);
@@ -78,8 +78,8 @@ public class DlqMessageServiceImpl implements DlqMessageService {
List<DlqMessageResendResult> batchResendResults = new LinkedList<>();
for (DlqMessageRequest dlqMessage : dlqMessages) {
ConsumeMessageDirectlyResult result = messageService.consumeMessageDirectly(dlqMessage.getTopicName(),
dlqMessage.getMsgId(), dlqMessage.getConsumerGroup(),
dlqMessage.getClientId());
dlqMessage.getMsgId(), dlqMessage.getConsumerGroup(),
dlqMessage.getClientId());
DlqMessageResendResult resendResult = new DlqMessageResendResult(result, dlqMessage.getMsgId());
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.PullStatus;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.MixAll;
import org.apache.rocketmq.common.Pair;
import org.apache.rocketmq.common.message.MessageClientIDSetter;
import org.apache.rocketmq.common.message.MessageExt;
@@ -74,6 +73,9 @@ import java.util.stream.Collectors;
@Service
public class MessageServiceImpl implements MessageService {
@Resource
private AutoCloseConsumerWrapper autoCloseConsumerWrapper;
private Logger logger = LoggerFactory.getLogger(MessageServiceImpl.class);
private static final Cache<String, List<QueueOffsetInfo>> CACHE = CacheBuilder.newBuilder()
@@ -128,8 +130,8 @@ public class MessageServiceImpl implements MessageService {
if (isEnableAcl) {
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();
try {
String subExpression = "*";
@@ -262,8 +264,8 @@ public class MessageServiceImpl implements MessageService {
if (isEnableAcl) {
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;
List<QueueOffsetInfo> queueOffsetInfos = new ArrayList<>();
@@ -402,8 +404,8 @@ public class MessageServiceImpl implements MessageService {
if (isEnableAcl) {
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<>();
long offset = query.getPageNum() * query.getPageSize();
@@ -541,9 +543,9 @@ public class MessageServiceImpl implements MessageService {
}
}
public DefaultMQPullConsumer buildDefaultMQPullConsumer(RPCHook rpcHook, boolean useTLS) {
DefaultMQPullConsumer consumer = new DefaultMQPullConsumer(MixAll.TOOLS_CONSUMER_GROUP, rpcHook);
consumer.setUseTLS(useTLS);
return consumer;
}
// public DefaultMQPullConsumer buildDefaultMQPullConsumer(RPCHook rpcHook, boolean useTLS) {
// DefaultMQPullConsumer consumer = new DefaultMQPullConsumer(MixAll.TOOLS_CONSUMER_GROUP, rpcHook);
// consumer.setUseTLS(useTLS);
// return consumer;
// }
}

View File

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

View File

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

View File

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

View File

@@ -127,7 +127,7 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
try {
TopicConfigSerializeWrapper topicConfigSerializeWrapper = mqAdminExt.getAllTopicConfig(brokerAddr.getBrokerAddrs().get(0L), 10000L);
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())) {
continue;
}
@@ -149,7 +149,7 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
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();
topicType.setTopicName(topicName);

View File

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

View File

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

View File

@@ -37,8 +37,7 @@ public class GlobalExceptionHandler {
if (ex instanceof ServiceException) {
logger.error("Occur service exception: {}", ex.getMessage());
value = new JsonResult<Object>(((ServiceException) ex).getCode(), ex.getMessage());
}
else {
} else {
logger.error("op=global_exception_handler_print_error", ex);
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
public Object beforeBodyWrite(
Object obj, MethodParameter methodParameter, MediaType mediaType,
Class<? extends HttpMessageConverter<?>> converterType,
ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
Object obj, MethodParameter methodParameter, MediaType mediaType,
Class<? extends HttpMessageConverter<?>> converterType,
ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
Annotation originalControllerReturnValue = methodParameter.getMethodAnnotation(OriginalControllerReturnValue.class);
if (originalControllerReturnValue != null) {
return obj;
}
JsonResult value;
if (obj instanceof JsonResult) {
value = (JsonResult)obj;
}
else {
value = (JsonResult) obj;
} else {
value = new JsonResult(obj);
}
return value;

View File

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

View File

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

View File

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

View File

@@ -31,10 +31,10 @@ import java.util.List;
public class ExcelUtil {
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();
WriteFont writeFont = new WriteFont();
writeFont.setFontHeightInPoints((short)12);
writeFont.setFontHeightInPoints((short) 12);
writeFont.setFontName("Microsoft YaHei UI");
headWriteCellStyle.setWriteFont(writeFont);
headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
@@ -44,7 +44,7 @@ public class ExcelUtil {
contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
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 {

View File

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

View File

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

View File

@@ -17,34 +17,34 @@
-->
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<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>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder charset="UTF-8">
<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>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE" />
</root>
<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>
<charset class="java.nio.charset.Charset">UTF-8</charset>
</encoder>
</appender>
<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
# limitations under the License.
#
# 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)
# Define Admin
admin=admin,1
super=admin,1
# Define Users
user1=user1
user2=user2
user1=user
user2=user