Merge pull request #1436 from loadchange/feat/1.1.0

Feat component subscribers
This commit is contained in:
Fury Zhu 2019-06-27 18:46:18 +08:00 committed by GitHub
commit 75b52924ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 365 additions and 51 deletions

View File

@ -20,3 +20,6 @@ export const LANGUAGE_SWITCH = 'LANGUAGE_SWITCH';
export const REDUX_DEVTOOLS = '__REDUX_DEVTOOLS_EXTENSION__';
export const GET_STATE = 'GET_STATE';
export const GET_SUBSCRIBERS = 'GET_SUBSCRIBERS';
export const REMOVE_SUBSCRIBERS = 'REMOVE_SUBSCRIBERS';

View File

@ -41,6 +41,7 @@ import ListeningToQuery from './pages/ConfigurationManagement/ListeningToQuery';
import ConfigurationManagement from './pages/ConfigurationManagement/ConfigurationManagement';
import ServiceList from './pages/ServiceManagement/ServiceList';
import ServiceDetail from './pages/ServiceManagement/ServiceDetail';
import SubscriberList from './pages/ServiceManagement/SubscriberList';
import ClusterNodeList from './pages/ClusterManagement/ClusterNodeList';
import reducers from './reducers';
@ -82,6 +83,7 @@ const MENU = [
{ path: '/configurationManagement', component: ConfigurationManagement },
{ path: '/serviceManagement', component: ServiceList },
{ path: '/serviceDetail', component: ServiceDetail },
{ path: '/subscriberList', component: SubscriberList },
{ path: '/clusterManagement', component: ClusterNodeList },
];

View File

@ -83,7 +83,7 @@ class Header extends React.Component {
rel="noopener noreferrer"
>
<img
src="img/TB118jPv_mWBKNjSZFBXXXxUFXa-2000-390.svg"
src="img/logo-2000-390.svg"
className="logo"
alt={siteConfig.name}
title={siteConfig.name}

View File

@ -44,6 +44,7 @@ const I18N_CONF = {
listeningToQuery: 'Listening Query',
serviceManagementVirtual: 'ServiceManagement',
serviceManagement: 'Service List',
subscriberList: 'Subscribers',
serviceDetail: 'Service Details',
namespace: 'Namespace',
clusterManagementVirtual: 'ClusterManagement',
@ -92,6 +93,19 @@ const I18N_CONF = {
promptDelete: 'Do you want to delete the service?',
create: 'Create Service',
},
SubscriberList: {
subscriberList: 'Subscriber List',
serviceName: 'Service Name',
serviceNamePlaceholder: 'Enter Service Name',
groupName: 'Group Name',
groupNamePlaceholder: 'Enter Group Name',
query: 'Search',
pubNoData: 'No results found.',
address: 'Address',
clientVersion: 'Client Version',
appName: 'Application Name',
searchServiceNamePrompt: 'Service name required!',
},
ClusterNodeList: {
clusterNodeList: 'Node List',
nodeIp: 'NodeIp',

View File

@ -44,6 +44,7 @@ const I18N_CONF = {
listeningToQuery: '监听查询',
serviceManagementVirtual: '服务管理',
serviceManagement: '服务列表',
subscriberList: '订阅者列表',
serviceDetail: '服务详情',
namespace: '命名空间',
clusterManagementVirtual: '集群管理',
@ -92,6 +93,19 @@ const I18N_CONF = {
promptDelete: '确定要删除当前服务吗',
create: '创建服务',
},
SubscriberList: {
subscriberList: '订阅者列表',
serviceName: '服务名称',
serviceNamePlaceholder: '请输入服务名称',
groupName: '分组名称',
groupNamePlaceholder: '请输入分组名称',
query: '查询',
pubNoData: '没有数据',
address: '地址',
clientVersion: '客户端版本',
appName: '应用名',
searchServiceNamePrompt: '请输入服务名称',
},
ClusterNodeList: {
clusterNodeList: '节点列表',
nodeIp: '节点Ip',

View File

@ -209,6 +209,21 @@ module.exports = {
},
],
},
{
isExtend: false,
name: '订阅者列表',
title: '订阅者列表',
isVirtual: false,
projectName: 'nacos',
serviceName: 'subscriberList',
link: 'subscriberList',
hasFusion: true,
template: '',
registerName: 'com.alibaba.nacos.page.subscriberList',
useRouter: false,
id: 'subscriberList',
children: [],
},
],
},
{

View File

@ -0,0 +1,217 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
* Licensed 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.
*/
import React from 'react';
import PropTypes from 'prop-types';
import {
Button,
Field,
Form,
Grid,
Input,
Loading,
Pagination,
Table,
Dialog,
Message,
ConfigProvider,
} from '@alifd/next';
import { connect } from 'react-redux';
import { getSubscribers, removeSubscribers } from '../../../reducers/subscribers';
import { request } from '../../../globalLib';
import RegionGroup from '../../../components/RegionGroup';
import './SubscriberList.scss';
const FormItem = Form.Item;
const { Row, Col } = Grid;
const { Column } = Table;
@connect(
state => ({ subscriberData: state.subscribers }),
{ getSubscribers, removeSubscribers }
)
@ConfigProvider.config
class SubscriberList extends React.Component {
static displayName = 'SubscriberList';
static propTypes = {
locale: PropTypes.object,
getSubscribers: PropTypes.func,
removeSubscribers: PropTypes.func,
subscriberData: PropTypes.object,
};
constructor(props) {
super(props);
this.state = {
loading: false,
total: 0,
pageSize: 10,
pageNo: 1,
search: {
serviceName: '',
groupName: '',
},
};
this.field = new Field(this);
}
openLoading() {
this.setState({ loading: true });
}
closeLoading() {
this.setState({ loading: false });
}
querySubscriberList() {
const { searchServiceNamePrompt } = this.props.locale;
const { search, pageSize, pageNo, nowNamespaceId = '' } = this.state;
if (!search.serviceName) {
Message.error(searchServiceNamePrompt);
return;
}
this.props.getSubscribers({
...search,
pageSize,
pageNo,
namespaceId: nowNamespaceId,
});
}
switchNamespace = () => {
this.setState({ search: { serviceName: '', groupName: '' } });
this.props.removeSubscribers();
};
setNowNameSpace = (nowNamespaceName, nowNamespaceId) =>
this.setState({
nowNamespaceName,
nowNamespaceId,
});
render() {
const { locale = {}, subscriberData = {} } = this.props;
const { count = 0, subscribers = [] } = subscriberData;
const {
pubNoData,
subscriberList,
serviceName,
serviceNamePlaceholder,
groupName,
groupNamePlaceholder,
query,
} = locale;
const { search, nowNamespaceName, nowNamespaceId } = this.state;
const { init, getValue } = this.field;
this.init = init;
this.getValue = getValue;
return (
<div className="main-container subscriber-list">
<Loading
shape="flower"
style={{
position: 'relative',
width: '100%',
}}
visible={this.state.loading}
tip="Loading..."
color="#333"
>
<div style={{ marginTop: -15 }}>
<RegionGroup
setNowNameSpace={this.setNowNameSpace}
namespaceCallBack={this.switchNamespace}
/>
</div>
<h3 className="page-title">
<span className="title-item">{subscriberList}</span>
<span className="title-item">|</span>
<span className="title-item">{nowNamespaceName}</span>
<span className="title-item">{nowNamespaceId}</span>
</h3>
<Row
className="demo-row"
style={{
marginBottom: 10,
padding: 0,
}}
>
<Col span="24">
<Form inline field={this.field}>
<FormItem label={serviceName}>
<Input
placeholder={serviceNamePlaceholder}
style={{ width: 200 }}
value={search.serviceName}
onChange={serviceName => this.setState({ search: { ...search, serviceName } })}
onPressEnter={() =>
this.setState({ pageNo: 1 }, () => this.querySubscriberList())
}
/>
</FormItem>
<FormItem label={groupName}>
<Input
placeholder={groupNamePlaceholder}
style={{ width: 200 }}
value={search.groupName}
onChange={groupName => this.setState({ search: { ...search, groupName } })}
onPressEnter={() =>
this.setState({ pageNo: 1 }, () => this.querySubscriberList())
}
/>
</FormItem>
<FormItem label="">
<Button
type="primary"
onClick={() => this.setState({ pageNo: 1 }, () => this.querySubscriberList())}
style={{ marginRight: 10 }}
>
{query}
</Button>
</FormItem>
</Form>
</Col>
</Row>
<Row style={{ padding: 0 }}>
<Col span="24" style={{ padding: 0 }}>
<Table dataSource={subscribers} locale={{ empty: pubNoData }}>
<Column title={locale.address} dataIndex="addrStr" />
<Column title={locale.clientVersion} dataIndex="agent" />
<Column title={locale.appName} dataIndex="app" />
</Table>
</Col>
</Row>
{count > this.state.pageSize && (
<div
style={{
marginTop: 10,
textAlign: 'right',
}}
>
<Pagination
current={this.state.pageNo}
total={count}
pageSize={this.state.pageSize}
onChange={pageNo => this.setState({ pageNo }, () => this.querySubscriberList())}
/>
</div>
)}
</Loading>
</div>
);
}
}
export default SubscriberList;

View File

@ -0,0 +1,30 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
* Licensed 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.
*/
.subscriber-list {
.page-title {
height: 30px;
width: 100%;
line-height: 30px;
margin: 0 0 20px;
padding: 0 0 0 10px;
border-left: 3px solid #09c;
color: #ccc;
}
.title-item {
font-size: 14px;
color: #000;
margin-right: 8px;
}
}

View File

@ -0,0 +1,16 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
* Licensed 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.
*/
import SubscriberList from './SubscriberList';
export default SubscriberList;

View File

@ -13,5 +13,6 @@
import locale from './locale';
import base from './base';
import subscribers from './subscribers';
export default { locale, base };
export default { locale, base, subscribers };

View File

@ -0,0 +1,41 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
* Licensed 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.
*/
import request from '../utils/request';
import { GET_SUBSCRIBERS, REMOVE_SUBSCRIBERS } from '../constants';
const initialState = {
subscribers: {},
};
const getSubscribers = params => dispatch =>
request.get('v1/ns/service/subscribers', { params }).then(data => {
dispatch({
type: GET_SUBSCRIBERS,
data,
});
});
const removeSubscribers = () => dispatch => dispatch({ type: REMOVE_SUBSCRIBERS });
export default (state = initialState, action) => {
switch (action.type) {
case GET_SUBSCRIBERS:
return { ...state, ...action.data };
case REMOVE_SUBSCRIBERS:
return { ...state, subscribers: {} };
default:
return state;
}
};
export { getSubscribers, removeSubscribers };

View File

@ -46,42 +46,3 @@ export const getParameter = (search, name) => {
const [, value = ''] = hit.split('=');
return value;
};
export const encodeKV = (text, separator) =>
text
.split('\r\n')
.filter(row => row.trim() && row.split('=').filter(kv => kv.trim()).length === 2)
.map(row =>
row
.split('=')
.map(kv => encodeURIComponent(kv.trim()))
.join('=')
)
.join(separator);
/**
* 将回车符和空格替换
* @param {*} separator 替换符
*/
export const replaceEnter = (separator = ',') => text => {
if (typeof text !== 'string') {
return text;
}
return encodeKV(text, separator)
.replace(/[\r\n]/g, separator)
.replace(/[\t\s]/g, '');
};
/**
* 处理metaData对象生成可显示对象
*/
export const processMetaData = (separator = ',') => (metadata = {}) => {
if (Object.prototype.toString.call(metadata) !== '[object Object]') {
return '';
}
return Object.keys(metadata)
.map(key => `${key}=${metadata[key]}`)
.join(separator);
};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long