front page commit

This commit is contained in:
nkorange 2018-10-13 12:22:02 +08:00
commit 78277f9413
8 changed files with 509 additions and 223 deletions

View File

@ -0,0 +1,131 @@
import React from 'react';
import {Dialog, Form, Input, Switch, Select} from '@alifd/next';
import {I18N, DIALOG_FORM_LAYOUT} from './constant'
const FormItem = Form.Item;
const Option = Select.Option
/*****************************此行为标记行, 请勿删和修改此行, 文件和组件依赖请写在此行上面, 主体代码请写在此行下面的class中*****************************/
class EditClusterDialog extends React.Component {
constructor(props) {
super(props);
this.state = {
editCluster: {},
editClusterDialogVisible: false
}
this.show = this.show.bind(this)
}
show(editCluster) {
const {metadata = {}} = editCluster
editCluster.metadataText = Object.keys(metadata).map(k => `${k}=${metadata[k]}`).join(',')
this.setState({
editCluster,
editClusterDialogVisible: true
}, () => console.log(this.state.editCluster))
}
hide() {
this.setState({editClusterDialogVisible: false})
}
onConfirm() {
console.log('confirm', this.props, this.state)
}
onChangeCluster(changeVal) {
const {editCluster = {}} = this.state
this.setState({
editCluster: Object.assign({}, editCluster, changeVal)
})
}
render() {
const {editCluster = {}, editClusterDialogVisible} = this.state
const {
healthChecker = {},
useIPPort4Check,
defaultCheckPort = '80',
metadataText = ''
} = editCluster
const {type, path, headers} = healthChecker
const healthCheckerChange = changeVal => this.onChangeCluster({
healthChecker: Object.assign({}, healthChecker, changeVal)
})
return (
<Dialog
className="cluster-edit-dialog"
title={I18N.UPDATE_CLUSTER}
visible={editClusterDialogVisible}
onOk={() => this.onConfirm()}
onCancel={() => this.hide()}
onClose={() => this.hide()}
>
<Form {...DIALOG_FORM_LAYOUT}>
<FormItem label={`${I18N.CHECK_TYPE}:`}>
<Select
className="in-select"
defaultValue={type}
onChange={type => healthCheckerChange({type})}
>
<Option value="TCP">TCP</Option>
<Option value="HTTP">HTTP</Option>
</Select>
</FormItem>
<FormItem label={`${I18N.CHECK_PORT}:`}>
<Input className="in-text"
value={defaultCheckPort}
onChange={defaultCheckPort => this.onChangeCluster({defaultCheckPort})}
/>
</FormItem>
<FormItem label={`${I18N.USE_IP_PORT_CHECK}:`}>
<Switch
checked={useIPPort4Check}
onChange={useIPPort4Check => this.onChangeCluster({useIPPort4Check})}
/>
</FormItem>
{
type === 'HTTP'
? (<div>
<div className="next-row next-form-item next-left next-medium">
<div className="next-col next-col-fixed-12 next-form-item-label">
<label>{`${I18N.CHECK_PATH}:`}</label>
</div>
<div className="next-col next-col-12 next-form-item-control">
<Input
className="in-text"
value={path}
onChange={path => healthCheckerChange({path})}
/>
</div>
</div>
<div className="next-row next-form-item next-left next-medium">
<div className="next-col next-col-fixed-12 next-form-item-label">
<label>{`${I18N.CHECK_HEADERS}:`}</label>
</div>
<div className="next-col next-col-12 next-form-item-control">
<Input
className="in-text"
value={headers}
onChange={headers => healthCheckerChange({headers})}
/>
</div>
</div>
</div>)
: null
}
<FormItem label={`${I18N.METADATA}:`}>
<Input
className="in-text"
value={metadataText}
onChange={metadataText => this.onChangeCluster({metadataText})}
/>
</FormItem>
</Form>
</Dialog>
)
}
}
/*****************************此行为标记行, 请勿删和修改此行, 主体代码请写在此行上面的class中, 组件导出语句及其他信息请写在此行下面*****************************/
export default EditClusterDialog;

View File

@ -0,0 +1,85 @@
import React from 'react';
import {Dialog, Form, Input, Switch} from '@alifd/next';
import {I18N, DIALOG_FORM_LAYOUT} from './constant'
const FormItem = Form.Item;
/*****************************此行为标记行, 请勿删和修改此行, 文件和组件依赖请写在此行上面, 主体代码请写在此行下面的class中*****************************/
class EditInstanceDialog extends React.Component {
constructor(props) {
super(props);
this.state = {
editInstance: {},
editInstanceDialogVisible: false
}
this.show = this.show.bind(this)
}
show(editInstance) {
const {metadata = {}} = editInstance
if (!Object.keys(metadata).length) {
editInstance.metadataText = Object.keys(metadata).map(k => `${k}=${metadata[k]}`).join(',')
}
this.setState({editInstance, editInstanceDialogVisible: true})
}
hide() {
this.setState({editInstanceDialogVisible: false})
}
onConfirm() {
console.log('confirm', this.props, this.state)
}
onChangeCluster(changeVal) {
const {editInstance = {}} = this.state
this.setState({
editInstance: Object.assign({}, editInstance, changeVal)
})
}
render() {
const {editInstanceDialogVisible, editInstance} = this.state
return (
<Dialog
className="instance-edit-dialog"
title={I18N.UPDATE_INSTANCE}
visible={editInstanceDialogVisible}
onOk={() => this.onConfirm()}
onCancel={() => this.hide()}
onClose={() => this.hide()}
>
<Form {...DIALOG_FORM_LAYOUT}>
<FormItem label="IP:">
<p>{editInstance.ip}</p>
</FormItem>
<FormItem label={`${I18N.PORT}:`}>
<p>{editInstance.port}</p>
</FormItem>
<FormItem label={`${I18N.WEIGHT}:`}>
<Input
className="in-text"
value={editInstance.weight}
onChange={weight => this.onChangeCluster({weight})}
/>
</FormItem>
<FormItem label={`${I18N.WHETHER_ONLINE}:`}>
<Switch
checked={editInstance.enabled}
onChange={enabled => this.onChangeCluster({enabled})}/>
</FormItem>
<FormItem label={`${I18N.METADATA}:`}>
<Input
className="in-text"
value={editInstance.metadataText}
onChange={metadataText => this.onChangeCluster({metadataText})}
/>
</FormItem>
</Form>
</Dialog>
)
}
}
/*****************************此行为标记行, 请勿删和修改此行, 主体代码请写在此行上面的class中, 组件导出语句及其他信息请写在此行下面*****************************/
export default EditInstanceDialog;

View File

@ -0,0 +1,97 @@
import React from 'react';
import {Dialog, Form, Input, Select} from '@alifd/next';
import {I18N, DIALOG_FORM_LAYOUT} from './constant'
const FormItem = Form.Item;
const Option = Select.Option
/*****************************此行为标记行, 请勿删和修改此行, 文件和组件依赖请写在此行上面, 主体代码请写在此行下面的class中*****************************/
class EditServiceDialog extends React.Component {
constructor(props) {
super(props);
this.state = {
editService: {},
editServiceDialogVisible: false
}
this.show = this.show.bind(this)
}
show(editService) {
const {metadata = {}} = editService
if (Object.keys(metadata).length) {
editService.metadataText = Object.keys(metadata).map(k => `${k}=${metadata[k]}`).join(',')
}
this.setState({editService, editServiceDialogVisible: true})
}
hide() {
this.setState({editServiceDialogVisible: false})
}
onConfirm() {
const editService = Object.assign({}, this.state)
console.log('confirm', editService)
this.hide()
}
onChangeCluster(changeVal) {
const {editService = {}} = this.state
this.setState({
editService: Object.assign({}, editService, changeVal)
})
}
render() {
const {editService, editServiceDialogVisible} = this.state
const {
name,
protectThreshold,
healthCheckMode,
metadataText
} = editService
return (
<Dialog
className="service-detail-edit-dialog"
title={I18N.UPDATE_SERVICE}
visible={editServiceDialogVisible}
onOk={() => this.onConfirm()}
onCancel={() => this.hide()}
onClose={() => this.hide()}
>
<Form {...DIALOG_FORM_LAYOUT}>
<FormItem label={`${I18N.SERVICE_NAME}:`}>
<p>{name}</p>
</FormItem>
<FormItem label={`${I18N.PROTECT_THRESHOLD}:`}>
<Input
className="in-text"
value={protectThreshold}
onChange={protectThreshold => this.onChangeCluster({protectThreshold})}
/>
</FormItem>
<FormItem label={`${I18N.HEALTH_CHECK_PATTERN}:`}>
<Select
className="in-select"
defaultValue={healthCheckMode}
onChange={healthCheckMode => this.onChangeCluster({healthCheckMode})}
>
<Option value="server">{I18N.HEALTH_CHECK_PATTERN_SERVICE}</Option>
<Option value="client">{I18N.HEALTH_CHECK_PATTERN_CLIENT}</Option>
<Option value="forbidden">{I18N.HEALTH_CHECK_PATTERN_FORBIDDEN}</Option>
</Select>
</FormItem>
<FormItem label={`${I18N.METADATA}:`}>
<Input
className="in-text"
value={metadataText}
onChange={metadataText => this.onChangeCluster({metadataText})}
/>
</FormItem>
</Form>
</Dialog>
)
}
}
/*****************************此行为标记行, 请勿删和修改此行, 主体代码请写在此行上面的class中, 组件导出语句及其他信息请写在此行下面*****************************/
export default EditServiceDialog;

View File

@ -0,0 +1,116 @@
import React from 'react';
import {Button, Pagination, Table} from '@alifd/next';
import {I18N} from './constant'
import EditInstanceDialog from "./EditInstanceDialog";
/*****************************此行为标记行, 请勿删和修改此行, 文件和组件依赖请写在此行上面, 主体代码请写在此行下面的class中*****************************/
class InstanceTable extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
instance: {count: 0, list: []},
pageNum: 1,
pageSize: 10
}
}
componentDidMount() {
this.getInstanceList()
}
getInstanceList() {
const {clusterName, serviceName} = this.props
if (!clusterName) return
const {pageSize, pageNum} = this.state
window.request({
url: '/nacos/v1/ns/catalog/instanceList',
data: {
serviceName,
clusterName,
pgSize: pageSize,
startPg: pageNum
},
beforeSend: () => this.setState({loading: true}),
success: instance => this.setState({instance}),
complete: () => this.setState({loading: false})
})
}
openInstanceDialog(instance) {
this.refs.editInstanceDialog.show(instance)
}
switchState(index, record) {
const {instance} = this.state
const {ip, port, weight, enabled} = record
const {clusterName, serviceName} = this.props
const newVal = Object.assign({}, instance)
newVal.list[index]['enabled'] = !enabled
window.request({
method: 'POST',
url: '/nacos/v1/ns/instance/update',
data: {serviceName, clusterName, ip, port, weight, enable: !enabled},
dataType: 'text',
beforeSend: () => this.setState({loading: true}),
success: () => this.setState({instance: newVal}),
complete: () => this.setState({loading: false})
})
}
onChangePage(pageNum) {
this.setState({pageNum}, () => this.getInstanceList())
}
render() {
const {instance, pageSize, loading} = this.state
return instance.count ? (
<div>
<Table dataSource={instance.list} loading={loading}>
<Table.Column title="IP" dataIndex="ip"/>
<Table.Column title={I18N.PORT} dataIndex="port"/>
<Table.Column title={I18N.WEIGHT} dataIndex="weight"/>
<Table.Column title={I18N.HEALTHY} dataIndex="healthy" cell={val => `${val}`}/>
<Table.Column
title={I18N.METADATA}
dataIndex="metadata"
cell={metadata => Object.keys(metadata).map(k => `${k}=${metadata[k]}`).join(',')}
/>
<Table.Column
title={I18N.OPERATION}
width={150}
cell={(value, index, record) => (
<div>
<Button
type="normal"
className="edit-btn"
onClick={() => this.openInstanceDialog(record)}
>{I18N.EDITOR}</Button>
<Button
type={record.enabled ? 'normal' : 'secondary'}
onClick={() => this.switchState(index, record)}
>{I18N[record.enabled ? 'OFFLINE' : 'ONLINE']}</Button>
</div>
)}/>
</Table>
{
instance.count > pageSize
? (
<Pagination
className="pagination"
total={instance.count}
pageSize={pageSize}
onChange={currentPage => this.onChangePage(currentPage)}
/>
)
: null
}
<EditInstanceDialog ref="editInstanceDialog"/>
</div>
) : null
}
}
/*****************************此行为标记行, 请勿删和修改此行, 主体代码请写在此行上面的class中, 组件导出语句及其他信息请写在此行下面*****************************/
export default InstanceTable;

View File

@ -1,47 +1,50 @@
import React from 'react';
import {Button, Card, Dialog, Table, Form, Pagination, Loading, Input, Switch, Select} from '@alifd/next';
import {Button, Card, Form, Loading} from '@alifd/next';
import EditServiceDialog from './EditServiceDialog'
import EditClusterDialog from './EditClusterDialog'
import InstanceTable from './InstanceTable'
import queryString from 'query-string'
import {I18N} from './constant'
import './ServiceDetail.less'
const FormItem = Form.Item;
const Option = Select.Option
const dataSource = () => {
const result = [];
for (let i = 0; i < 8; i++) {
result.push({ip: '1.1.1.1', port: '80', weight: '50', healthy: 'true', metadata: 'k1=v1', online: true});
}
return result;
const pageFormLayout = {
labelCol: {fixedSpan: 10},
wrapperCol: {span: 14}
};
const dialogFormLayout = {
labelCol: {fixedSpan: 12},
wrapperCol: {span: 12}
}
/*****************************此行为标记行, 请勿删和修改此行, 文件和组件依赖请写在此行上面, 主体代码请写在此行下面的class中*****************************/
class ServiceDetail extends React.Component {
constructor(props) {
super(props);
this.state = {
serviceName: queryString.parse(props.location.search).name,
loading: false,
tableLoading: false,
currentPage: 1,
instanceList: [],
editServiceDialogVisible: false,
editClusterDialogVisible: false,
editInstanceDialogVisible: false,
checkType: 'tcp'
clusters: [],
instances: {},
service: {},
pageSize: 10,
pageNum: {}
}
}
componentDidMount() {
setTimeout(() => this.setState({loading: true}, () => {
this.setState({
instanceList: dataSource(),
loading: false
})
}), 300)
if (!this.state.serviceName) {
this.props.history.goBack()
return
}
this.getServiceDetail()
}
getServiceDetail() {
const {serviceName} = this.state
window.request({
url: `/nacos/v1/ns/catalog/serviceDetail?serviceName=${serviceName}`,
beforeSend: () => this.openLoading(),
success: ({clusters = [], service = {}}) => this.setState({service, clusters}),
complete: () => this.closeLoading()
})
}
openLoading() {
@ -52,162 +55,26 @@ class ServiceDetail extends React.Component {
this.setState({loading: false})
}
editServiceDialog() {
const hideDialog = () => this.setState({editServiceDialogVisible: false})
const {editServiceDialogVisible} = this.state
return (
<Dialog
className="service-detail-edit-dialog"
title={I18N.UPDATE_SERVICE}
visible={editServiceDialogVisible}
onOk={hideDialog}
onCancel={hideDialog}
onClose={hideDialog}
>
<Form {...dialogFormLayout}>
<FormItem label={`${I18N.SERVICE_NAME}:`}>
<p>test.com</p>
</FormItem>
<FormItem label={`${I18N.PROTECT_THRESHOLD}:`}>
<Input className="in-text" value="0.5"/>
</FormItem>
<FormItem label={`${I18N.HEALTH_CHECK_PATTERN}:`}>
<Select defaultValue="service" className="in-select">
<Option value="service">{I18N.HEALTH_CHECK_PATTERN_SERVICE}</Option>
<Option value="client">{I18N.HEALTH_CHECK_PATTERN_CLIENT}</Option>
<Option value="forbidden">{I18N.HEALTH_CHECK_PATTERN_FORBIDDEN}</Option>
</Select>
</FormItem>
<FormItem label={`${I18N.METADATA}:`}>
<Input className="in-text" value="k1=v1,k2=v2"/>
</FormItem>
</Form>
</Dialog>
)
openEditServiceDialog() {
this.refs.editServiceDialog.show(this.state.service)
}
editClusterDialog() {
const hideDialog = () => this.setState({editClusterDialogVisible: false})
const {editClusterDialogVisible} = this.state
return (
<Dialog
className="cluster-edit-dialog"
title={I18N.UPDATE_CLUSTER}
visible={editClusterDialogVisible}
onOk={hideDialog}
onCancel={hideDialog}
onClose={hideDialog}
>
<Form {...dialogFormLayout}>
<FormItem label={`${I18N.CHECK_TYPE}:`}>
<Select
className="in-select"
defaultValue={this.state.checkType}
onChange={checkType => this.setState({checkType})}
>
<Select.Option value="tcp">TCP</Select.Option>
<Select.Option value="http">HTTP</Select.Option>
</Select>
</FormItem>
<FormItem label={`${I18N.CHECK_PORT}:`}>
<Input className="in-text" value="80"/>
</FormItem>
<FormItem label={`${I18N.USE_IP_PORT_CHECK}:`}>
<Switch onChange={f => f}/>
</FormItem>
{
this.state.checkType === 'http'
? (
<Form {...dialogFormLayout}>
<FormItem label={`${I18N.CHECK_PATH}:`}>
<Input className="in-text"/>
</FormItem>
<FormItem label={`${I18N.CHECK_HEADERS}:`}>
<Input className="in-text"/>
</FormItem>
</Form>
)
: null
}
<FormItem label={`${I18N.METADATA}:`}>
<Input className="in-text" value="k1=v1,k2=v2"/>
</FormItem>
</Form>
</Dialog>
)
openClusterDialog(cluster) {
this.refs.editClusterDialog.show(cluster)
}
editInstanceDialog() {
const hideDialog = () => this.setState({editInstanceDialogVisible: false})
const {editInstanceDialogVisible} = this.state
return (
<Dialog
className="instance-edit-dialog"
title={I18N.UPDATE_INSTANCE}
visible={editInstanceDialogVisible}
onOk={hideDialog}
onCancel={hideDialog}
onClose={hideDialog}
>
<Form {...dialogFormLayout}>
<FormItem label="IP:">
<p>1.1.1.1</p>
</FormItem>
<FormItem label={`${I18N.PORT}:`}>
<p>8080</p>
</FormItem>
<FormItem label={`${I18N.WEIGHT}:`}>
<Input className="in-text" value="0.5"/>
</FormItem>
<FormItem label={`${I18N.WHETHER_ONLINE}:`}>
<Switch onChange={f => f}/>
</FormItem>
<FormItem label={`${I18N.METADATA}:`}>
<Input className="in-text" value="k1=v1,k2=v2"/>
</FormItem>
</Form>
</Dialog>
)
}
switchState(index, record) {
const {instanceList} = this.state
this.setState({tableLoading: true}, () => {
setTimeout(() => {
instanceList[index].online = !record.online
this.setState({
instanceList,
tableLoading: false
})
}, 300)
})
}
onChange(currentPage) {
this.setState({tableLoading: true})
setTimeout(() => {
this.setState({tableLoading: false, currentPage})
}, 200)
}
openEditServiceDialog = () => this.setState({editServiceDialogVisible: true})
openClusterDialog = () => this.setState({editClusterDialogVisible: true})
openInstanceDialog = () => this.setState({editInstanceDialogVisible: true})
render() {
const {loading, tableLoading, instanceList} = this.state
const formItemLayout = {
labelCol: {fixedSpan: 10},
wrapperCol: {span: 14}
};
const {serviceName, loading, service = {}, clusters} = this.state
const {metadata = {}} = service
const metadataText = Object.keys(metadata).map(key => `${key}=${metadata[key]}`).join(',')
return (
<div className="main-container service-detail">
<Loading
shape={"flower"}
tip={"Loading..."}
className="loading"
visible={loading} color={"#333"}
visible={loading}
color={"#333"}
>
<h1 style={{
position: 'relative',
@ -217,67 +84,49 @@ class ServiceDetail extends React.Component {
<Button
type="normal"
className="edit-service-btn"
onClick={this.openEditServiceDialog}
onClick={() => this.openEditServiceDialog()}
>{I18N.EDIT_SERVICE}</Button>
</h1>
<Form style={{width: '60%'}} {...formItemLayout}>
<Form style={{width: '60%'}} {...pageFormLayout}>
<FormItem label={`${I18N.SERVICE_NAME}:`}>
<p>test.com</p>
<p>{service.name}</p>
</FormItem>
<FormItem label={`${I18N.PROTECT_THRESHOLD}:`}>
<p>0.5</p>
<p>{service.protectThreshold}</p>
</FormItem>
<FormItem label={`${I18N.HEALTH_CHECK_PATTERN}:`}>
<p>true</p>
<p>{service.healthCheckMode}</p>
</FormItem>
<FormItem label={`${I18N.METADATA}:`}>
<p>k1=v1,k2=v2</p>
<p>{metadataText}</p>
</FormItem>
</Form>
<Card
title={`${I18N.CLUSTER}:`}
subTitle="DEFAULT"
contentHeight="auto"
extra={<Button type="normal" onClick={this.openClusterDialog}>{I18N.EDIT_CLUSTER}</Button>}
>
<Loading
shape={"flower"}
tip={"Loading..."}
className="loading"
visible={tableLoading} color={"#333"}
>
<Table dataSource={instanceList}>
<Table.Column title="IP" dataIndex="ip"/>
<Table.Column title={I18N.PORT} dataIndex="port"/>
<Table.Column title={I18N.WEIGHT} dataIndex="weight"/>
<Table.Column title={I18N.HEALTHY} dataIndex="healthy"/>
<Table.Column title={I18N.METADATA} dataIndex="metadata"/>
<Table.Column title={I18N.OPERATION} width={150} cell={(value, index, record) => (
<div>
<Button
type="normal"
className="edit-btn"
onClick={this.openInstanceDialog}
>{I18N.EDITOR}</Button>
<Button
type={record.online ? 'normal' : 'secondary'}
onClick={() => this.switchState(index, record)}
>{I18N[record.online ? 'OFFLINE' : 'ONLINE']}</Button>
</div>
)}/>
</Table>
</Loading>
<Pagination
className="pagination"
onChange={currentPage => this.onChange(currentPage)}
/>
</Card>
{this.editServiceDialog()}
{this.editInstanceDialog()}
{this.editClusterDialog()}
{
clusters.map(cluster => (
<Card
key={cluster.name}
className="cluster-card"
title={`${I18N.CLUSTER}:`}
subTitle={cluster.name}
contentHeight="auto"
extra={(
<Button
type="normal"
onClick={() => this.openClusterDialog(cluster)}
>{I18N.EDIT_CLUSTER}</Button>
)}
>
<InstanceTable
clusterName={cluster.name}
serviceName={serviceName}
/>
</Card>
))
}
</Loading>
<EditServiceDialog ref="editServiceDialog"/>
<EditClusterDialog ref="editClusterDialog"/>
</div>
);
}

View File

@ -17,6 +17,9 @@
float: right;
margin-top: 15px;
}
.cluster-card {
margin-bottom: 30px;
}
}
.service-detail-edit-dialog, .instance-edit-dialog, .cluster-edit-dialog {

View File

@ -108,3 +108,8 @@ I18N.UPDATE_INSTANCE = getI18N('update_instance')
* 是否上线
*/
I18N.WHETHER_ONLINE = getI18N('whether_online')
export const DIALOG_FORM_LAYOUT = {
labelCol: {fixedSpan: 12},
wrapperCol: {span: 12}
}

View File

@ -23,9 +23,6 @@ class ServiceManagement extends React.Component {
this.field = new Field(this);
}
componentDidMount() {
}
openLoading() {
this.setState({loading: true})
}
@ -116,7 +113,10 @@ class ServiceManagement extends React.Component {
<Column title={I18N.COLUMN_IP_COUNT} dataIndex="ipCount"/>
<Column title={I18N.COLUMN_HEALTH_STATUS} dataIndex="status"/>
<Column title={I18N.COLUMN_OPERATION} align="center" cell={(value, index, record) => (
<Button type="normal" disabled>详情</Button>
<Button
type="normal"
onClick={() => this.props.history.push(`/serviceDetail?name=${record.name}`)}
>详情</Button>
)}/>
</Table>
</Col>