kafka-manager 2.0

This commit is contained in:
zengqiao
2020-09-28 15:46:34 +08:00
parent 28d985aaf1
commit c6e4b60424
1253 changed files with 82183 additions and 37179 deletions

View File

@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=2">
<title>KafkaManager</title>
<link rel="stylesheet" href="//at.alicdn.com/t/font_1251424_q66z80q0hio.css" />
</head>
<body>
<div id="root"></div>
<div id="modal"></div>
<script type="text/javascript" charSet="utf-8" async="" src="//shares-static.xiaojukeji.com/static/ep_survey_img/track.js"></script>
</body>
</html>

View File

@@ -0,0 +1,15 @@
import * as ReactDOM from 'react-dom';
import { Provider } from 'mobx-react';
import * as React from 'react';
import Router from './router';
const renderApp = () => {
ReactDOM.render(
<Provider>
<Router />
</Provider>,
document.getElementById('root'),
);
};
renderApp();

View File

@@ -0,0 +1,72 @@
import * as React from 'react';
import CommonRoutePage from './common';
import urlParser from 'lib/url-parser';
import urlQuery from 'store/url-query';
import { AppDetail } from 'container/app';
import { AdminAppList, ClusterList, ClusterDetail, BrokerDetail, UserManagement, VersionManagement, OperationManagement, OperationDetail, BillManagement, ConfigureManagement, IndividualBill, MigrationDetail, BillDetail } from 'container/admin';
import { PlatformManagement } from 'container/admin/platform-management';
export default class Home extends React.Component<any> {
private pageRoute = [{
path: '/admin',
exact: true,
component: ClusterList,
}, {
path: '/admin/cluster-detail',
exact: true,
component: ClusterDetail,
}, {
path: '/admin/broker-detail',
exact: true,
component: BrokerDetail,
}, {
path: '/admin/operation',
exact: true,
component: OperationManagement,
}, {
path: '/admin/operation-detail',
exact: true,
component: OperationDetail,
}, {
path: '/admin/bill',
exact: true,
component: BillManagement,
}, {
path: '/admin/bill-individual',
exact: true,
component: IndividualBill,
}, {
path: '/admin/bill-detail',
exact: true,
component: BillDetail,
}, {
path: '/admin/app',
exact: true,
component: PlatformManagement,
}, {
path: '/admin/app-detail',
exact: true,
component: AppDetail,
}, {
path: '/admin/migration-detail',
exact: true,
component: MigrationDetail,
}];
constructor(props: any) {
super(props);
const search = urlParser().search;
urlQuery.clusterId = Number(search.clusterId);
urlQuery.brokerId = Number(search.brokerId);
urlQuery.group = search.group;
urlQuery.location = search.location;
urlQuery.topicName = search.topic;
}
public render() {
return (
<CommonRoutePage pageRoute={this.pageRoute} mode="admin" active="admin"/>
);
}
}

View File

@@ -0,0 +1,39 @@
import * as React from 'react';
import CommonRoutePage from './common';
import { AlarmList, AddAlarm } from 'container/alarm';
import { AlarmDetail } from 'container/alarm/alarm-detail';
import { HistoryDetail } from 'container/alarm/alarm-detail/history-detail';
export default class Alarm extends React.Component {
public pageRoute = [{
path: '/alarm',
exact: true,
component: AlarmList,
}, {
path: '/alarm/detail',
exact: true,
component: AddAlarm,
}, {
path: '/alarm/add',
exact: true,
component: AddAlarm,
}, {
path: '/alarm/modify',
exact: true,
component: AddAlarm,
}, {
path: '/alarm/alarm-detail',
exact: true,
component: AlarmDetail,
}, {
path: '/alarm/history-detail',
exact: true,
component: HistoryDetail,
}];
public render() {
return (
<CommonRoutePage pageRoute={this.pageRoute} mode="alarm" active="alarm"/>
);
}
}

View File

@@ -0,0 +1,23 @@
import * as React from 'react';
import { MyCluster, ClusterDetail } from 'container/cluster';
import CommonRoutePage from './common';
export default class Cluster extends React.Component<any> {
public pageRoute = [{
path: '/cluster',
exact: true,
component: MyCluster,
}, {
path: '/cluster/cluster-detail',
exact: true,
component: ClusterDetail,
}];
public render() {
return (
<CommonRoutePage pageRoute={this.pageRoute} mode="cluster" active="cluster"/>
);
}
}

View File

@@ -0,0 +1,57 @@
import * as React from 'react';
import './index.less';
import 'styles/header-search.less';
import { Header } from 'container/header';
import { LeftMenu } from 'container/left-menu';
import AllWrapperInOne from 'container/wrapper';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import { IPageRouteItem } from 'types/base-type';
import { region } from 'store/region';
import { observer } from 'mobx-react';
import { users } from 'store/users';
import { FullScreen } from 'container/full-screen';
import Url from 'lib/url-parser';
import AllCustomModalInOne from 'container/wrapper/custom-modal';
interface ICommonRoute {
pageRoute: IPageRouteItem[];
mode?: 'admin' | 'user' | 'topic' | 'cluster' | 'expert' | 'alarm';
active: string;
}
@observer
export default class CommonRoutePage extends React.Component<ICommonRoute> {
constructor(props: ICommonRoute) {
super(props);
const url = Url();
const index = region.regionIdcList.findIndex(item => item.idc === url.search.region);
if (index > -1) {
region.setRegion(region.regionIdcList[index]);
}
}
public componentDidMount() {
region.getRegionIdcs();
users.getAccount();
}
public render() {
const { pageRoute, mode, active } = this.props;
return (
<>
<Header active={active} />
<div className="core-container">
<LeftMenu mode={mode} />
<div className="content-container">
{pageRoute.map((item: IPageRouteItem, key: number) =>
<Route key={key} path={item.path} exact={item.exact} component={item.component} />)}
</div>
</div>
<AllWrapperInOne />
<AllCustomModalInOne />
<FullScreen />
</>
);
}
}

View File

@@ -0,0 +1,22 @@
import * as React from 'react';
import { ForbiddenPage } from 'container/error';
import { IPageRouteItem } from 'types/base-type';
import { Route } from 'react-router-dom';
export default class ErrorPage extends React.Component<any> {
public pageRoute = [{
path: '/error',
exact: true,
component: ForbiddenPage,
}];
public render() {
return (
<>
{this.pageRoute.map((item: IPageRouteItem, key: number) =>
<Route key={key} path={item.path} exact={item.exact} component={item.component} />)}
</>
);
}
}

View File

@@ -0,0 +1,39 @@
import * as React from 'react';
import { HotSpotTopic, PartitionTopic, GovernanceTopic, Diagnosis } from 'container/expert';
import { MigrationDetail } from 'container/admin';
import CommonRoutePage from './common';
export default class Expert extends React.Component<any> {
public pageRoute = [{
path: '/expert',
exact: true,
component: HotSpotTopic,
}, {
path: '/expert/topic-partition',
exact: true,
component: PartitionTopic,
}, {
path: '/expert/topic-governance',
exact: true,
component: GovernanceTopic,
}, {
path: '/expert/diagnosis',
exact: true,
component: Diagnosis,
}, {
path: '/expert/hotspot-detail',
exact: true,
component: MigrationDetail,
}];
constructor(props: any) {
super(props);
}
public render() {
return (
<CommonRoutePage pageRoute={this.pageRoute} mode="expert" active="expert" />
);
}
}

View File

@@ -0,0 +1,109 @@
* {
padding: 0;
margin: 0;
-webkit-font-smoothing: antialiased;
}
.hide {
display: none;
}
li {
list-style-type: none;
}
html, body, .router-nav {
width: 100%;
height: 100%;
font-family: PingFangSC-Regular;
}
[class*=k-icon-] {
font-family: kafka-manager;
font-style: normal;
font-weight: 400;
text-transform: none;
line-height: 1;
vertical-align: baseline;
display: inline-block;
-webkit-font-smoothing: antialiased;
font-variant: normal normal;
}
#root {
width: 100%;
position: fixed;
top: 0;
bottom: 0;
font-size: 14px;
}
.core-container {
display: flex;
flex-flow: row nowrap;
bottom: 0;
top: 65px;
position: absolute;
width: 100%;
}
.didi-theme {
color: @primary-color;
}
.ant-table-thead > tr > th, .ant-table-tbody > tr > td {
padding: 13px;
}
.ant-table-tbody > tr > td {
background: #fff;
}
.ant-select-dropdown-menu-item-active,
.ant-select-dropdown-menu-item:hover {
background: #f3f3f3;
}
.content-container {
flex: 1;
padding: 24px;
background: rgba(243, 244, 245, 1);
overflow: auto;
}
.ant-form-item {
margin-bottom: 16px;
}
.mb-24 {
margin-bottom: 24px;
}
.ant-table-thead > tr > th .ant-table-filter-icon {
right: initial;
}
.success {
color: #2fc25b;
}
.fail {
color: #f5222d;
}
.mr-5 {
margin-right: 5px;
}
.ml-10 {
margin-left: 10px;
}
.config-info{
white-space: pre-line;
height: 100%;
overflow-y: scroll;
padding: 10px;
}

View File

@@ -0,0 +1,22 @@
import * as React from 'react';
import { ConfigureInfoPage } from 'container/configure-info';
import { IPageRouteItem } from 'types/base-type';
import { Route } from 'react-router-dom';
export default class InfoPage extends React.Component<any> {
public pageRoute = [{
path: '/info',
exact: true,
component: ConfigureInfoPage,
}];
public render() {
return (
<>
{this.pageRoute.map((item: IPageRouteItem, key: number) =>
<Route key={key} path={item.path} exact={item.exact} component={item.component} />)}
</>
);
}
}

View File

@@ -0,0 +1,89 @@
.l-container {
width: 100%;
height: 100%;
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background-size: 100% 100%;
top: -20px;
.top-title {
width: 320px;
height: 57px;
margin-bottom: 24px;
}
.f-container {
padding: 20px 30px;
background-color: #fff;
box-shadow: 0px 0px 6px 2px #999;
overflow: hidden;
transition: all 500ms ease-in-out;
width:540px;
height:320px;
background:rgba(255,255,255,1);
box-shadow:0px 2px 16px 0px rgba(0,0,0,0.1);
border-radius:8px;
position: relative;
.item-style {
width:400px;
margin-bottom: 20px;
}
.btn-style {
width:400px;
height:56px;
background:rgba(255,129,0,1);
border-radius:4px;
text-align: center;
}
.ant-input-affix-wrapper {
font-size: 14px;
}
.ant-input-suffix {
top: 40%;
color: rgba(0, 0, 0, 0.25);
}
.title {
font-size: 20px;
line-height: 35px;
margin-bottom: 26px;
transition: all 500ms ease-in-out;
text-align: center;
}
.ant-form {
position: absolute;
box-sizing: border-box;
top: 17%;
left: 13%;
}
.ant-input {
height:56px;
background:rgba(0,0,0,0.02);
font-size: 18px;
border-radius:4px;
font-family:PingFangSC-Regular,PingFang SC;
font-weight:400;
color:rgba(153,153,153,1);
line-height:25px;
border: none;
}
.b-item {
button {
background-color: transparent;
border-style: none;
height: 56px;
font-weight: 400;
color: rgba(255,255,255,1);
line-height: 25px;
font-size: 18px;
width: 100%;
}
}
&.show {
.b-item {
left: 219px;
}
}
}
}

View File

@@ -0,0 +1,73 @@
import * as React from 'react';
import { Form, Row, Input, Button, notification, Icon } from 'component/antd';
import { userLogin } from 'lib/api';
import { setCookie } from 'lib/utils';
import './index.less';
import bgImgUrl from '../../../assets/image/login-bg.png';
import kafkaImgUrl from '../../../assets/image/kafka-manager.png';
class Login extends React.Component<any> {
public state = {
show: '',
};
public handleSubmit = (e: React.MouseEvent<any, MouseEvent>) => {
e.preventDefault();
this.props.form.validateFields((err: Error, values: any) => {
if (err) return;
userLogin(values).then((data: any) => {
setCookie([{ key: 'username', value: data.username, time: 1 }, { key: 'role', value: data.role, time: 1 }]);
notification.success({ message: '登录成功' });
this.props.history.push('/');
});
});
}
public handleReset = () => {
this.props.form.resetFields();
}
public handleKeyPress = (e: any) => {
if (e.nativeEvent.keyCode === 13) {
this.handleSubmit(e);
}
}
public inputOnBlur = () => {
this.setState({ show: 'show' });
}
public render() {
const { getFieldDecorator } = this.props.form;
return (
<div className="l-container" style={{ background: `url(${bgImgUrl})`, backgroundSize: '100% 100%'}}>
<img className="top-title" src={kafkaImgUrl} />
<div className="f-container">
<Form onSubmit={this.handleSubmit} labelAlign="left" >
<Form.Item className="item-style">
{getFieldDecorator('username')(
<Input
placeholder="请输入用户名"
onChange={this.inputOnBlur}
/>,
)}
</Form.Item>
<Form.Item className="item-style">
{getFieldDecorator('password')(
<Input.Password
placeholder="请输入密码"
/>,
)}
</Form.Item>
<Form.Item className="b-item btn-style">
<Button htmlType="submit" onKeyPress={this.handleKeyPress}></Button>
</Form.Item>
</Form>
</div>
</div>
);
}
}
export default Form.create({ name: 'login' })(Login);

View File

@@ -0,0 +1,33 @@
import * as React from 'react';
import Url from 'lib/url-parser';
import { getTicketBycode } from 'lib/api';
import { IUser } from 'types/base-type';
import { urlPrefix } from 'constants/left-menu';
export class SSOCallBack extends React.Component<any> {
constructor(public code: string, public jumpto: string) {
super({});
const url = Url();
this.jumpto = url.search.jumpto;
this.code = url.search.code;
}
public componentDidMount() {
getTicketBycode(this.code).then((data: IUser) => {
const userData = data || {} as IUser;
(window as any).taotieCommandQueue = (window as any).taotieCommandQueue || [];
(window as any).taotieCommandQueue.push({command: 'setCookieUserNameForTaotie', parameter: userData.username});
if (this.jumpto) {
window.location.href = decodeURIComponent(this.jumpto);
} else {
window.location.href = `${urlPrefix}`;
}
});
}
public render() {
return (
<div>...</div>
);
}
}

View File

@@ -0,0 +1,49 @@
import * as React from 'react';
import { TopicAppList, AllTopic, MineTopic, TopicDetail } from 'container/topic';
import { AppDetail } from 'container/app';
import CommonRoutePage from './common';
import urlParser from 'lib/url-parser';
import urlQuery from 'store/url-query';
export default class Home extends React.Component<any> {
public pageRoute = [{
path: '/',
exact: true,
component: MineTopic,
}, {
path: '/topic',
exact: true,
component: MineTopic,
}, {
path: '/topic/topic-all',
exact: true,
component: AllTopic,
}, {
path: '/topic/topic-detail',
exact: true,
component: TopicDetail,
}, {
path: '/topic/app-list',
exact: true,
component: TopicAppList,
}, {
path: '/topic/app-detail',
exact: true,
component: AppDetail,
}];
constructor(props: any) {
super(props);
const search = urlParser().search;
urlQuery.clusterId = Number(search.clusterId);
urlQuery.brokerId = Number(search.brokerId);
urlQuery.appId = search.appId;
}
public render() {
return (
<CommonRoutePage pageRoute={this.pageRoute} active="topic"/>
);
}
}

View File

@@ -0,0 +1,38 @@
import * as React from 'react';
import CommonRoutePage from './common';
import { MyApproval, MyBill, MyOrder, BillDetail } from 'container/user-center';
import { OrderDetail } from 'container/user-center/order-detail';
export default class User extends React.Component {
public pageRoute = [{
path: '/user',
exact: true,
component: MyOrder,
}, {
path: '/user/my-order',
exact: true,
component: MyOrder,
}, {
path: '/user/my-approval',
exact: true,
component: MyApproval,
}, {
path: '/user/order-detail',
exact: true,
component: OrderDetail,
}, {
path: '/user/bill',
exact: true,
component: MyBill,
}, {
path: '/user/bill-detail',
exact: true,
component: BillDetail,
}];
public render() {
return (
<CommonRoutePage pageRoute={this.pageRoute} mode="user" active="user"/>
);
}
}

View File

@@ -0,0 +1,71 @@
import { BrowserRouter as Router, Route } from 'react-router-dom';
import { hot } from 'react-hot-loader/root';
import * as React from 'react';
import Home from './page/topic';
import Admin from './page/admin';
import Alarm from './page/alarm';
import Cluster from './page/cluster';
import Expert from './page/expert';
import User from './page/user';
import { urlPrefix } from 'constants/left-menu';
import ErrorPage from './page/error';
import Login from './page/login';
import InfoPage from './page/info';
class RouterDom extends React.Component {
public render() {
return (
<Router basename={urlPrefix}>
<Route path="/" exact={true} component={Home} />
<Route path={`/topic`} exact={true} component={Home} />
<Route
path={`/topic/:page`}
exact={true}
component={Home}
/>
<Route path={`/admin`} exact={true} component={Admin} />
<Route
path={`/admin/:page`}
exact={true}
component={Admin}
/>
<Route path={`/user`} exact={true} component={User} />
<Route path={`/user/:page`} exact={true} component={User} />
<Route path={`/cluster`} exact={true} component={Cluster} />
<Route
path={`/cluster/:page`}
exact={true}
component={Cluster}
/>
<Route path={`/expert`} exact={true} component={Expert} />
<Route
path={`/expert/:page`}
exact={true}
component={Expert}
/>
<Route path={`/alarm`} exact={true} component={Alarm} />
<Route
path={`/alarm/:page`}
exact={true}
component={Alarm}
/>
<Route
path={`/login`}
exact={true}
component={Login}
/>
<Route path={`/error`} exact={true} component={ErrorPage} />
<Route path={`/info`} exact={true} component={InfoPage} />
</Router>
);
}
}
export default hot(RouterDom);