mirror of
https://github.com/didi/KnowStreaming.git
synced 2025-12-24 11:52:08 +08:00
@@ -13,7 +13,7 @@
|
|||||||
## 环境依赖
|
## 环境依赖
|
||||||
|
|
||||||
- `Maven 3.5+`(后端打包依赖)
|
- `Maven 3.5+`(后端打包依赖)
|
||||||
- `node 10+`(前端打包依赖)
|
- `node v12+`(前端打包依赖)
|
||||||
- `Java 8+`(运行环境需要)
|
- `Java 8+`(运行环境需要)
|
||||||
- `MySQL 5.7`(数据存储)
|
- `MySQL 5.7`(数据存储)
|
||||||
|
|
||||||
|
|||||||
@@ -46,4 +46,15 @@ public class TopicCreationConstant {
|
|||||||
public static final String TOPIC_NAME_PREFIX_RU = "ru01_";
|
public static final String TOPIC_NAME_PREFIX_RU = "ru01_";
|
||||||
|
|
||||||
public static final Integer TOPIC_NAME_MAX_LENGTH = 255;
|
public static final Integer TOPIC_NAME_MAX_LENGTH = 255;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单次自动化审批, 默认允许的通过单子
|
||||||
|
*/
|
||||||
|
public static final Integer DEFAULT_MAX_PASSED_ORDER_NUM_PER_TASK = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单次自动化审批, 最多允许的通过单子
|
||||||
|
*/
|
||||||
|
public static final Integer MAX_PASSED_ORDER_NUM_PER_TASK = 200;
|
||||||
}
|
}
|
||||||
@@ -86,6 +86,8 @@ public enum ResultStatus {
|
|||||||
APP_ID_OR_PASSWORD_ILLEGAL(1000, "app or password illegal"),
|
APP_ID_OR_PASSWORD_ILLEGAL(1000, "app or password illegal"),
|
||||||
SYSTEM_CODE_ILLEGAL(1000, "system code illegal"),
|
SYSTEM_CODE_ILLEGAL(1000, "system code illegal"),
|
||||||
|
|
||||||
|
CLUSTER_TASK_HOST_LIST_ILLEGAL(1000, "主机列表错误,请检查主机列表"),
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.xiaojukeji.kafka.manager.common.entity.ao;
|
package com.xiaojukeji.kafka.manager.common.entity.ao;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -23,6 +24,8 @@ public class RdTopicBasic {
|
|||||||
|
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
|
private List<String> regionNameList;
|
||||||
|
|
||||||
public Long getClusterId() {
|
public Long getClusterId() {
|
||||||
return clusterId;
|
return clusterId;
|
||||||
}
|
}
|
||||||
@@ -87,6 +90,14 @@ public class RdTopicBasic {
|
|||||||
this.description = description;
|
this.description = description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<String> getRegionNameList() {
|
||||||
|
return regionNameList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRegionNameList(List<String> regionNameList) {
|
||||||
|
this.regionNameList = regionNameList;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "RdTopicBasic{" +
|
return "RdTopicBasic{" +
|
||||||
@@ -98,6 +109,7 @@ public class RdTopicBasic {
|
|||||||
", appName='" + appName + '\'' +
|
", appName='" + appName + '\'' +
|
||||||
", properties=" + properties +
|
", properties=" + properties +
|
||||||
", description='" + description + '\'' +
|
", description='" + description + '\'' +
|
||||||
|
", regionNameList='" + regionNameList + '\'' +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
package com.xiaojukeji.kafka.manager.common.entity.ao.config;
|
package com.xiaojukeji.kafka.manager.common.entity.ao.config;
|
||||||
|
|
||||||
|
import com.xiaojukeji.kafka.manager.common.constant.TopicCreationConstant;
|
||||||
|
import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -7,8 +10,27 @@ import java.util.List;
|
|||||||
* @date 20/7/24
|
* @date 20/7/24
|
||||||
*/
|
*/
|
||||||
public class CreateTopicConfig {
|
public class CreateTopicConfig {
|
||||||
|
/**
|
||||||
|
* 单次自动化审批, 允许的通过单子
|
||||||
|
*/
|
||||||
|
private Integer maxPassedOrderNumPerTask;
|
||||||
|
|
||||||
private List<CreateTopicElemConfig> configList;
|
private List<CreateTopicElemConfig> configList;
|
||||||
|
|
||||||
|
public Integer getMaxPassedOrderNumPerTask() {
|
||||||
|
if (ValidateUtils.isNull(maxPassedOrderNumPerTask)) {
|
||||||
|
return TopicCreationConstant.DEFAULT_MAX_PASSED_ORDER_NUM_PER_TASK;
|
||||||
|
}
|
||||||
|
if (maxPassedOrderNumPerTask > TopicCreationConstant.MAX_PASSED_ORDER_NUM_PER_TASK) {
|
||||||
|
return TopicCreationConstant.MAX_PASSED_ORDER_NUM_PER_TASK;
|
||||||
|
}
|
||||||
|
return maxPassedOrderNumPerTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxPassedOrderNumPerTask(Integer maxPassedOrderNumPerTask) {
|
||||||
|
this.maxPassedOrderNumPerTask = maxPassedOrderNumPerTask;
|
||||||
|
}
|
||||||
|
|
||||||
public List<CreateTopicElemConfig> getConfigList() {
|
public List<CreateTopicElemConfig> getConfigList() {
|
||||||
return configList;
|
return configList;
|
||||||
}
|
}
|
||||||
@@ -20,7 +42,8 @@ public class CreateTopicConfig {
|
|||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "CreateTopicConfig{" +
|
return "CreateTopicConfig{" +
|
||||||
"configList=" + configList +
|
"maxPassedOrderNumPerTask=" + maxPassedOrderNumPerTask +
|
||||||
|
", configList=" + configList +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
package com.xiaojukeji.kafka.manager.common.entity.ao.topic;
|
package com.xiaojukeji.kafka.manager.common.entity.ao.topic;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author arthur
|
* @author arthur
|
||||||
* @date 2018/09/03
|
* @date 2018/09/03
|
||||||
@@ -17,7 +19,7 @@ public class TopicBasicDTO {
|
|||||||
|
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
private String region;
|
private List<String> regionNameList;
|
||||||
|
|
||||||
private Integer score;
|
private Integer score;
|
||||||
|
|
||||||
@@ -83,12 +85,12 @@ public class TopicBasicDTO {
|
|||||||
this.description = description;
|
this.description = description;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getRegion() {
|
public List<String> getRegionNameList() {
|
||||||
return region;
|
return regionNameList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRegion(String region) {
|
public void setRegionNameList(List<String> regionNameList) {
|
||||||
this.region = region;
|
this.regionNameList = regionNameList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getScore() {
|
public Integer getScore() {
|
||||||
@@ -164,7 +166,7 @@ public class TopicBasicDTO {
|
|||||||
", principals='" + principals + '\'' +
|
", principals='" + principals + '\'' +
|
||||||
", topicName='" + topicName + '\'' +
|
", topicName='" + topicName + '\'' +
|
||||||
", description='" + description + '\'' +
|
", description='" + description + '\'' +
|
||||||
", region='" + region + '\'' +
|
", regionNameList='" + regionNameList + '\'' +
|
||||||
", score=" + score +
|
", score=" + score +
|
||||||
", topicCodeC='" + topicCodeC + '\'' +
|
", topicCodeC='" + topicCodeC + '\'' +
|
||||||
", partitionNum=" + partitionNum +
|
", partitionNum=" + partitionNum +
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ public class TopicOverview {
|
|||||||
|
|
||||||
private Object byteIn;
|
private Object byteIn;
|
||||||
|
|
||||||
|
private Object byteOut;
|
||||||
|
|
||||||
private Object produceRequest;
|
private Object produceRequest;
|
||||||
|
|
||||||
private String appName;
|
private String appName;
|
||||||
@@ -78,6 +80,14 @@ public class TopicOverview {
|
|||||||
this.byteIn = byteIn;
|
this.byteIn = byteIn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Object getByteOut() {
|
||||||
|
return byteOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setByteOut(Object byteOut) {
|
||||||
|
this.byteOut = byteOut;
|
||||||
|
}
|
||||||
|
|
||||||
public Object getProduceRequest() {
|
public Object getProduceRequest() {
|
||||||
return produceRequest;
|
return produceRequest;
|
||||||
}
|
}
|
||||||
@@ -135,6 +145,7 @@ public class TopicOverview {
|
|||||||
", partitionNum=" + partitionNum +
|
", partitionNum=" + partitionNum +
|
||||||
", retentionTime=" + retentionTime +
|
", retentionTime=" + retentionTime +
|
||||||
", byteIn=" + byteIn +
|
", byteIn=" + byteIn +
|
||||||
|
", byteOut=" + byteOut +
|
||||||
", produceRequest=" + produceRequest +
|
", produceRequest=" + produceRequest +
|
||||||
", appName='" + appName + '\'' +
|
", appName='" + appName + '\'' +
|
||||||
", appId='" + appId + '\'' +
|
", appId='" + appId + '\'' +
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.xiaojukeji.kafka.manager.common.entity.dto.rd;
|
package com.xiaojukeji.kafka.manager.common.entity.dto.rd;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
import com.xiaojukeji.kafka.manager.common.bizenum.ClusterModeEnum;
|
||||||
import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils;
|
import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils;
|
||||||
import io.swagger.annotations.ApiModel;
|
import io.swagger.annotations.ApiModel;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
@@ -108,10 +109,13 @@ public class LogicalClusterDTO {
|
|||||||
if (ValidateUtils.isNull(clusterId)
|
if (ValidateUtils.isNull(clusterId)
|
||||||
|| ValidateUtils.isNull(clusterId)
|
|| ValidateUtils.isNull(clusterId)
|
||||||
|| ValidateUtils.isEmptyList(regionIdList)
|
|| ValidateUtils.isEmptyList(regionIdList)
|
||||||
|| ValidateUtils.isNull(appId)
|
|
||||||
|| ValidateUtils.isNull(mode)) {
|
|| ValidateUtils.isNull(mode)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (!ClusterModeEnum.SHARED_MODE.getCode().equals(mode) && ValidateUtils.isNull(appId)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
appId = ValidateUtils.isNull(appId)? "": appId;
|
||||||
description = ValidateUtils.isNull(description)? "": description;
|
description = ValidateUtils.isNull(description)? "": description;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package com.xiaojukeji.kafka.manager.common.entity.metrics;
|
package com.xiaojukeji.kafka.manager.common.entity.metrics;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author zengqiao
|
* @author zengqiao
|
||||||
* @date 20/6/17
|
* @date 20/6/17
|
||||||
@@ -11,6 +13,8 @@ public class TopicMetrics extends BaseMetrics {
|
|||||||
|
|
||||||
private String topicName;
|
private String topicName;
|
||||||
|
|
||||||
|
private List<BrokerMetrics> brokerMetricsList;
|
||||||
|
|
||||||
public TopicMetrics(Long clusterId, String topicName) {
|
public TopicMetrics(Long clusterId, String topicName) {
|
||||||
super();
|
super();
|
||||||
this.clusterId = clusterId;
|
this.clusterId = clusterId;
|
||||||
@@ -24,6 +28,14 @@ public class TopicMetrics extends BaseMetrics {
|
|||||||
this.topicName = topicName;
|
this.topicName = topicName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TopicMetrics(String appId, Long clusterId, String topicName, List<BrokerMetrics> brokerMetricsList) {
|
||||||
|
super();
|
||||||
|
this.appId = appId;
|
||||||
|
this.clusterId = clusterId;
|
||||||
|
this.topicName = topicName;
|
||||||
|
this.brokerMetricsList = brokerMetricsList;
|
||||||
|
}
|
||||||
|
|
||||||
public String getAppId() {
|
public String getAppId() {
|
||||||
return appId;
|
return appId;
|
||||||
}
|
}
|
||||||
@@ -36,6 +48,14 @@ public class TopicMetrics extends BaseMetrics {
|
|||||||
return topicName;
|
return topicName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setBrokerMetricsList(List<BrokerMetrics> brokerMetricsList) {
|
||||||
|
this.brokerMetricsList = brokerMetricsList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<BrokerMetrics> getBrokerMetricsList() {
|
||||||
|
return brokerMetricsList;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "TopicMetrics{" +
|
return "TopicMetrics{" +
|
||||||
|
|||||||
@@ -28,6 +28,9 @@ public class TopicOverviewVO {
|
|||||||
@ApiModelProperty(value = "每秒流入流量(B)")
|
@ApiModelProperty(value = "每秒流入流量(B)")
|
||||||
private Object byteIn;
|
private Object byteIn;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "每秒流出流量(B)")
|
||||||
|
private Object byteOut;
|
||||||
|
|
||||||
@ApiModelProperty(value = "发送请求数(个/秒)")
|
@ApiModelProperty(value = "发送请求数(个/秒)")
|
||||||
private Object produceRequest;
|
private Object produceRequest;
|
||||||
|
|
||||||
@@ -94,6 +97,14 @@ public class TopicOverviewVO {
|
|||||||
this.byteIn = byteIn;
|
this.byteIn = byteIn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Object getByteOut() {
|
||||||
|
return byteOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setByteOut(Object byteOut) {
|
||||||
|
this.byteOut = byteOut;
|
||||||
|
}
|
||||||
|
|
||||||
public Object getProduceRequest() {
|
public Object getProduceRequest() {
|
||||||
return produceRequest;
|
return produceRequest;
|
||||||
}
|
}
|
||||||
@@ -151,6 +162,7 @@ public class TopicOverviewVO {
|
|||||||
", partitionNum=" + partitionNum +
|
", partitionNum=" + partitionNum +
|
||||||
", retentionTime=" + retentionTime +
|
", retentionTime=" + retentionTime +
|
||||||
", byteIn=" + byteIn +
|
", byteIn=" + byteIn +
|
||||||
|
", byteOut=" + byteOut +
|
||||||
", produceRequest=" + produceRequest +
|
", produceRequest=" + produceRequest +
|
||||||
", appName='" + appName + '\'' +
|
", appName='" + appName + '\'' +
|
||||||
", appId='" + appId + '\'' +
|
", appId='" + appId + '\'' +
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package com.xiaojukeji.kafka.manager.common.entity.vo.normal.topic;
|
|||||||
import io.swagger.annotations.ApiModel;
|
import io.swagger.annotations.ApiModel;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Topic的基本信息
|
* Topic的基本信息
|
||||||
* @author zengqiao
|
* @author zengqiao
|
||||||
@@ -49,6 +51,9 @@ public class TopicBasicVO {
|
|||||||
@ApiModelProperty(value = "集群地址")
|
@ApiModelProperty(value = "集群地址")
|
||||||
private String bootstrapServers;
|
private String bootstrapServers;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "所属region")
|
||||||
|
private List<String> regionNameList;
|
||||||
|
|
||||||
public Long getClusterId() {
|
public Long getClusterId() {
|
||||||
return clusterId;
|
return clusterId;
|
||||||
}
|
}
|
||||||
@@ -153,6 +158,14 @@ public class TopicBasicVO {
|
|||||||
this.score = score;
|
this.score = score;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<String> getRegionNameList() {
|
||||||
|
return regionNameList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRegionNameList(List<String> regionNameList) {
|
||||||
|
this.regionNameList = regionNameList;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "TopicBasicVO{" +
|
return "TopicBasicVO{" +
|
||||||
@@ -169,6 +182,7 @@ public class TopicBasicVO {
|
|||||||
", topicCodeC='" + topicCodeC + '\'' +
|
", topicCodeC='" + topicCodeC + '\'' +
|
||||||
", description='" + description + '\'' +
|
", description='" + description + '\'' +
|
||||||
", bootstrapServers='" + bootstrapServers + '\'' +
|
", bootstrapServers='" + bootstrapServers + '\'' +
|
||||||
|
", regionNameList=" + regionNameList +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package com.xiaojukeji.kafka.manager.common.entity.vo.normal.topic;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* author: mrazkonglingxu
|
||||||
|
* Date: 2020/12/7
|
||||||
|
* Time: 7:40 下午
|
||||||
|
*/
|
||||||
|
public class TopicBrokerRequestTimeVO {
|
||||||
|
|
||||||
|
private Long clusterId;
|
||||||
|
|
||||||
|
private Integer brokerId;
|
||||||
|
|
||||||
|
private TopicRequestTimeDetailVO brokerRequestTime;
|
||||||
|
|
||||||
|
public Long getClusterId() {
|
||||||
|
return clusterId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClusterId(Long clusterId) {
|
||||||
|
this.clusterId = clusterId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getBrokerId() {
|
||||||
|
return brokerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBrokerId(Integer brokerId) {
|
||||||
|
this.brokerId = brokerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TopicRequestTimeDetailVO getBrokerRequestTime() {
|
||||||
|
return brokerRequestTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBrokerRequestTime(TopicRequestTimeDetailVO brokerRequestTime) {
|
||||||
|
this.brokerRequestTime = brokerRequestTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,8 @@ package com.xiaojukeji.kafka.manager.common.entity.vo.normal.topic;
|
|||||||
import io.swagger.annotations.ApiModel;
|
import io.swagger.annotations.ApiModel;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author zengqiao
|
* @author zengqiao
|
||||||
* @date 20/4/8
|
* @date 20/4/8
|
||||||
@@ -33,6 +35,8 @@ public class TopicRequestTimeDetailVO {
|
|||||||
@ApiModelProperty(value = "totalTimeMs")
|
@ApiModelProperty(value = "totalTimeMs")
|
||||||
private Object totalTimeMs;
|
private Object totalTimeMs;
|
||||||
|
|
||||||
|
private List<TopicBrokerRequestTimeVO> brokerRequestTimeList;
|
||||||
|
|
||||||
public String getRequestTimeType() {
|
public String getRequestTimeType() {
|
||||||
return requestTimeType;
|
return requestTimeType;
|
||||||
}
|
}
|
||||||
@@ -97,6 +101,14 @@ public class TopicRequestTimeDetailVO {
|
|||||||
this.totalTimeMs = totalTimeMs;
|
this.totalTimeMs = totalTimeMs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<TopicBrokerRequestTimeVO> getBrokerRequestTimeList() {
|
||||||
|
return brokerRequestTimeList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBrokerRequestTimeList(List<TopicBrokerRequestTimeVO> brokerRequestTimeList) {
|
||||||
|
this.brokerRequestTimeList = brokerRequestTimeList;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "TopicRequestTimeDetailVO{" +
|
return "TopicRequestTimeDetailVO{" +
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.xiaojukeji.kafka.manager.common.entity.vo.rd;
|
|||||||
import io.swagger.annotations.ApiModel;
|
import io.swagger.annotations.ApiModel;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -35,6 +36,9 @@ public class RdTopicBasicVO {
|
|||||||
@ApiModelProperty(value = "备注")
|
@ApiModelProperty(value = "备注")
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "所属region")
|
||||||
|
private List<String> regionNameList;
|
||||||
|
|
||||||
public Long getClusterId() {
|
public Long getClusterId() {
|
||||||
return clusterId;
|
return clusterId;
|
||||||
}
|
}
|
||||||
@@ -99,6 +103,14 @@ public class RdTopicBasicVO {
|
|||||||
this.description = description;
|
this.description = description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<String> getRegionNameList() {
|
||||||
|
return regionNameList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRegionNameList(List<String> regionNameList) {
|
||||||
|
this.regionNameList = regionNameList;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "RdTopicBasicVO{" +
|
return "RdTopicBasicVO{" +
|
||||||
@@ -110,6 +122,7 @@ public class RdTopicBasicVO {
|
|||||||
", appName='" + appName + '\'' +
|
", appName='" + appName + '\'' +
|
||||||
", properties=" + properties +
|
", properties=" + properties +
|
||||||
", description='" + description + '\'' +
|
", description='" + description + '\'' +
|
||||||
|
", regionNameList='" + regionNameList + '\'' +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -64,7 +64,7 @@ public class JsonUtils {
|
|||||||
TopicConnectionDO connectionDO = new TopicConnectionDO();
|
TopicConnectionDO connectionDO = new TopicConnectionDO();
|
||||||
|
|
||||||
String[] appIdDetailArray = appIdDetail.toString().split("#");
|
String[] appIdDetailArray = appIdDetail.toString().split("#");
|
||||||
if (appIdDetailArray.length == 3) {
|
if (appIdDetailArray.length >= 3) {
|
||||||
connectionDO.setAppId(appIdDetailArray[0]);
|
connectionDO.setAppId(appIdDetailArray[0]);
|
||||||
connectionDO.setIp(appIdDetailArray[1]);
|
connectionDO.setIp(appIdDetailArray[1]);
|
||||||
connectionDO.setClientVersion(appIdDetailArray[2]);
|
connectionDO.setClientVersion(appIdDetailArray[2]);
|
||||||
|
|||||||
@@ -170,7 +170,10 @@ public class MbeanNameUtilV2 {
|
|||||||
new MbeanV2(
|
new MbeanV2(
|
||||||
"TopicCodeC",
|
"TopicCodeC",
|
||||||
JmxAttributeEnum.VALUE_ATTRIBUTE,
|
JmxAttributeEnum.VALUE_ATTRIBUTE,
|
||||||
"kafka.server:type=ReplicaManager,name=TopicCodeC"
|
Arrays.asList(
|
||||||
|
new AbstractMap.SimpleEntry<>(KafkaVersion.VERSION_0_10_3, "kafka.server:type=ReplicaManager,name=TopicCodeC"),
|
||||||
|
new AbstractMap.SimpleEntry<>(KafkaVersion.VERSION_MAX, "kafka.server:type=AppIdTopicMetrics,name=RecordCompression,appId=")
|
||||||
|
)
|
||||||
),
|
),
|
||||||
Arrays.asList(
|
Arrays.asList(
|
||||||
KafkaMetricsCollections.TOPIC_BASIC_PAGE_METRICS
|
KafkaMetricsCollections.TOPIC_BASIC_PAGE_METRICS
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ package com.xiaojukeji.kafka.manager.common.zookeeper;
|
|||||||
public class ZkPathUtil {
|
public class ZkPathUtil {
|
||||||
private static final String ZOOKEEPER_SEPARATOR = "/";
|
private static final String ZOOKEEPER_SEPARATOR = "/";
|
||||||
|
|
||||||
private static final String BROKER_ROOT_NODE = ZOOKEEPER_SEPARATOR + "brokers";
|
public static final String BROKER_ROOT_NODE = ZOOKEEPER_SEPARATOR + "brokers";
|
||||||
|
|
||||||
public static final String CONTROLLER_ROOT_NODE = ZOOKEEPER_SEPARATOR + "controller";
|
public static final String CONTROLLER_ROOT_NODE = ZOOKEEPER_SEPARATOR + "controller";
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,8 @@
|
|||||||
"mobx": "^5.9.4",
|
"mobx": "^5.9.4",
|
||||||
"mobx-react": "^5.4.3",
|
"mobx-react": "^5.4.3",
|
||||||
"moment": "^2.24.0",
|
"moment": "^2.24.0",
|
||||||
|
"monaco-editor": "^0.20.0",
|
||||||
|
"monaco-editor-webpack-plugin": "^1.9.0",
|
||||||
"optimize-css-assets-webpack-plugin": "^5.0.1",
|
"optimize-css-assets-webpack-plugin": "^5.0.1",
|
||||||
"react": "^16.8.4",
|
"react": "^16.8.4",
|
||||||
"react-hot-loader": "^4.8.4",
|
"react-hot-loader": "^4.8.4",
|
||||||
@@ -45,9 +47,13 @@
|
|||||||
"tslint": "^5.13.1",
|
"tslint": "^5.13.1",
|
||||||
"tslint-react": "^3.6.0",
|
"tslint-react": "^3.6.0",
|
||||||
"typescript": "^3.3.3333",
|
"typescript": "^3.3.3333",
|
||||||
|
"url-loader": "^4.1.1",
|
||||||
"webpack": "^4.29.6",
|
"webpack": "^4.29.6",
|
||||||
"webpack-cli": "^3.2.3",
|
"webpack-cli": "^3.2.3",
|
||||||
"webpack-dev-server": "^3.2.1",
|
"webpack-dev-server": "^3.2.1",
|
||||||
"xlsx": "^0.16.1"
|
"xlsx": "^0.16.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"format-to-json": "^1.0.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,9 +28,10 @@
|
|||||||
<goal>install-node-and-npm</goal>
|
<goal>install-node-and-npm</goal>
|
||||||
</goals>
|
</goals>
|
||||||
<configuration>
|
<configuration>
|
||||||
<nodeVersion>v8.12.0</nodeVersion>
|
<nodeVersion>v12.20.0</nodeVersion>
|
||||||
<npmVersion>6.4.1</npmVersion>
|
<npmVersion>6.14.8</npmVersion>
|
||||||
<nodeDownloadRoot>http://npm.taobao.org/mirrors/node/</nodeDownloadRoot>
|
<nodeDownloadRoot>http://npm.taobao.org/mirrors/node/</nodeDownloadRoot>
|
||||||
|
<npmDownloadRoot>https://registry.npm.taobao.org/npm/-/</npmDownloadRoot>
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
<execution>
|
<execution>
|
||||||
|
|||||||
@@ -48,6 +48,9 @@ import 'antd/es/notification/style';
|
|||||||
import Tooltip from 'antd/es/tooltip';
|
import Tooltip from 'antd/es/tooltip';
|
||||||
import 'antd/es/tooltip/style';
|
import 'antd/es/tooltip/style';
|
||||||
|
|
||||||
|
import Popover from 'antd/es/popover';
|
||||||
|
import 'antd/es/popover/style';
|
||||||
|
|
||||||
import Radio from 'antd/es/radio';
|
import Radio from 'antd/es/radio';
|
||||||
import 'antd/es/radio';
|
import 'antd/es/radio';
|
||||||
import { RadioChangeEvent } from 'antd/es/radio';
|
import { RadioChangeEvent } from 'antd/es/radio';
|
||||||
@@ -97,6 +100,9 @@ import 'antd/es/time-picker/style';
|
|||||||
import Badge from 'antd/es/badge';
|
import Badge from 'antd/es/badge';
|
||||||
import 'antd/es/badge/style';
|
import 'antd/es/badge/style';
|
||||||
|
|
||||||
|
import Progress from 'antd/es/progress';
|
||||||
|
import 'antd/es/progress/style';
|
||||||
|
|
||||||
import { RangePickerValue } from 'antd/es/date-picker/interface';
|
import { RangePickerValue } from 'antd/es/date-picker/interface';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
@@ -136,4 +142,5 @@ export {
|
|||||||
TimePicker,
|
TimePicker,
|
||||||
RangePickerValue,
|
RangePickerValue,
|
||||||
Badge,
|
Badge,
|
||||||
|
Popover
|
||||||
};
|
};
|
||||||
|
|||||||
68
kafka-manager-console/src/component/editor/editor.tsx
Normal file
68
kafka-manager-console/src/component/editor/editor.tsx
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
// import * as React from 'react';
|
||||||
|
// import CodeMirror from 'codemirror/lib/codemirror';
|
||||||
|
// import 'codemirror/lib/codemirror.css';
|
||||||
|
// import 'codemirror/mode/sql/sql';
|
||||||
|
// import 'codemirror/mode/javascript/javascript';
|
||||||
|
// import 'codemirror/addon/hint/show-hint.js';
|
||||||
|
// import 'codemirror/addon/hint/sql-hint.js';
|
||||||
|
// import 'codemirror/addon/hint/show-hint.css';
|
||||||
|
// import './index.less';
|
||||||
|
// import { indexStore } from 'store/my-index';
|
||||||
|
|
||||||
|
// interface IProps {
|
||||||
|
// value?: string;
|
||||||
|
// placeholder?: string;
|
||||||
|
// readOnly?: boolean;
|
||||||
|
// }
|
||||||
|
// export class CodeMirrorEditor extends React.Component<IProps> {
|
||||||
|
|
||||||
|
// public editor = null as any;
|
||||||
|
|
||||||
|
// public handleCodeFocus = () => {
|
||||||
|
// // tslint:disable-next-line:no-unused-expression
|
||||||
|
// this.editor && this.editor.focus();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public componentDidMount() {
|
||||||
|
// const { value, placeholder, readOnly } = this.props;
|
||||||
|
// const code = document.querySelector('.codemirror');
|
||||||
|
// code.innerHTML = '';
|
||||||
|
// const editor = CodeMirror(document.querySelector('.codemirror'), {
|
||||||
|
// mode: 'application/json',
|
||||||
|
// indentWithTabs: true,
|
||||||
|
// smartIndent: true,
|
||||||
|
// lineNumbers: true,
|
||||||
|
// matchBrackets: true,
|
||||||
|
// autoCloseBrackets: true,
|
||||||
|
// styleSelectedText: true,
|
||||||
|
// foldGutter: true,
|
||||||
|
// readOnly,
|
||||||
|
// extraKeys: readOnly ? {} : {
|
||||||
|
// 'Ctrl-Enter': 'autocomplete',
|
||||||
|
// 'Tab': (cm) => {
|
||||||
|
// const spaces = Array(cm.getOption('indentUnit') + 1).join(' ');
|
||||||
|
// cm.replaceSelection(spaces);
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// placeholder,
|
||||||
|
// });
|
||||||
|
// editor.setValue(value || '');
|
||||||
|
// indexStore.setCodeEditorValue(value || '');
|
||||||
|
// editor.on('changes', (a: any) => {
|
||||||
|
// const data = a.getValue();
|
||||||
|
// indexStore.setCodeEditorValue(data);
|
||||||
|
// });
|
||||||
|
// this.editor = editor;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public render() {
|
||||||
|
// return (
|
||||||
|
// <div
|
||||||
|
// className="editor-wrap"
|
||||||
|
// onClick={this.handleCodeFocus}
|
||||||
|
// >
|
||||||
|
// <div className="codemirror" />
|
||||||
|
// </div >
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
31
kafka-manager-console/src/component/editor/index.less
Normal file
31
kafka-manager-console/src/component/editor/index.less
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
.editor {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror-placeholder {
|
||||||
|
color:#999;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 14px;
|
||||||
|
font-family: -apple-system,BlinkMacSystemFont,Neue Haas Grotesk Text Pro,Arial Nova,Segoe UI,Helvetica Neue,\.PingFang SC,PingFang SC,Microsoft YaHei,Microsoft JhengHei,Source Han Sans SC,Noto Sans CJK SC,Source Han Sans CN,Noto Sans SC,Source Han Sans TC,Noto Sans CJK TC,Hiragino Sans GB,sans-serif;
|
||||||
|
}
|
||||||
|
.editor-wrap {
|
||||||
|
max-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror {
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.monacoEditor{
|
||||||
|
height: 150px;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid #cccccc;
|
||||||
|
border-radius: 4px;
|
||||||
|
.editor{
|
||||||
|
height: 100%;
|
||||||
|
position: absolute;
|
||||||
|
left: -14%;
|
||||||
|
width: 120%;
|
||||||
|
}
|
||||||
|
}
|
||||||
50
kafka-manager-console/src/component/editor/index.tsx
Normal file
50
kafka-manager-console/src/component/editor/index.tsx
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import * as monaco from 'monaco-editor';
|
||||||
|
|
||||||
|
import './index.less';
|
||||||
|
|
||||||
|
export interface IEditorProps {
|
||||||
|
style?: React.CSSProperties;
|
||||||
|
options: monaco.editor.IStandaloneEditorConstructionOptions;
|
||||||
|
uri?: monaco.Uri;
|
||||||
|
autoUnmount?: boolean;
|
||||||
|
customMount?: (editor: monaco.editor.IStandaloneCodeEditor, monaco: any) => any;
|
||||||
|
placeholder?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class EditorCom extends React.Component<IEditorProps> {
|
||||||
|
public ref: HTMLElement = null;
|
||||||
|
public editor: monaco.editor.IStandaloneCodeEditor;
|
||||||
|
public state = {
|
||||||
|
placeholder: this.props.placeholder ?? '',
|
||||||
|
};
|
||||||
|
|
||||||
|
public componentWillUnmount() {
|
||||||
|
if (this.props.autoUnmount === false) return;
|
||||||
|
const model = this.editor.getModel();
|
||||||
|
model.dispose();
|
||||||
|
this.editor.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public componentDidMount() {
|
||||||
|
const { customMount, options, uri } = this.props;
|
||||||
|
const { value, language } = options;
|
||||||
|
if (uri) {
|
||||||
|
options.model = monaco.editor.createModel(value, language, uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.editor = monaco.editor.create(this.ref,
|
||||||
|
options,
|
||||||
|
);
|
||||||
|
if (customMount) customMount(this.editor, monaco);
|
||||||
|
}
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
const { style } = this.props;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div style={style} className="editor" ref={(id) => { this.ref = id; }} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
77
kafka-manager-console/src/component/editor/monacoEditor.tsx
Normal file
77
kafka-manager-console/src/component/editor/monacoEditor.tsx
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import * as monaco from 'monaco-editor';
|
||||||
|
import format2json from 'format-to-json';
|
||||||
|
import { Input } from 'component/antd';
|
||||||
|
import './index.less';
|
||||||
|
|
||||||
|
export interface IEditorProps {
|
||||||
|
style?: React.CSSProperties;
|
||||||
|
options: monaco.editor.IStandaloneEditorConstructionOptions;
|
||||||
|
uri?: monaco.Uri;
|
||||||
|
autoUnmount?: boolean;
|
||||||
|
customMount?: (editor: monaco.editor.IStandaloneCodeEditor, monaco: any) => any;
|
||||||
|
placeholder?: string;
|
||||||
|
value: '';
|
||||||
|
onChange?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Monacoeditor extends React.Component<IEditorProps> {
|
||||||
|
public ref: HTMLElement = null;
|
||||||
|
public editor: monaco.editor.IStandaloneCodeEditor;
|
||||||
|
public state = {
|
||||||
|
placeholder: '',
|
||||||
|
};
|
||||||
|
// public arr = '{"clusterId":95,"startId":37397856,"step":100,"topicName":"kmo_topic_metrics_tempory_zq"}';
|
||||||
|
// public Ars(a: string) {
|
||||||
|
// const obj = JSON.parse(a);
|
||||||
|
// const newobj: any = {};
|
||||||
|
// for (const item in obj) {
|
||||||
|
// if (typeof obj[item] === 'object') {
|
||||||
|
// this.Ars(obj[item]);
|
||||||
|
// } else {
|
||||||
|
// newobj[item] = obj[item];
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return JSON.stringify(newobj);
|
||||||
|
// }
|
||||||
|
public async componentDidMount() {
|
||||||
|
const { value, onChange } = this.props;
|
||||||
|
const format: any = await format2json(value);
|
||||||
|
this.editor = monaco.editor.create(this.ref, {
|
||||||
|
value: format.result,
|
||||||
|
language: 'json',
|
||||||
|
lineNumbers: 'off',
|
||||||
|
scrollBeyondLastLine: false,
|
||||||
|
// selectOnLineNumbers: true,
|
||||||
|
// roundedSelection: false,
|
||||||
|
// readOnly: true,
|
||||||
|
minimap: {
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
// automaticLayout: true, // 自动布局
|
||||||
|
glyphMargin: true, // 字形边缘 {},[]
|
||||||
|
// useTabStops: false,
|
||||||
|
// formatOnPaste: true,
|
||||||
|
// mode: 'application/json',
|
||||||
|
// indentWithTabs: true,
|
||||||
|
// smartIndent: true,
|
||||||
|
// matchBrackets: 'always',
|
||||||
|
// autoCloseBrackets: true,
|
||||||
|
// styleSelectedText: true,
|
||||||
|
// foldGutter: true,
|
||||||
|
});
|
||||||
|
this.editor.onDidChangeModelContent((e) => {
|
||||||
|
const newValue = this.editor.getValue();
|
||||||
|
onChange(newValue);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public render() {
|
||||||
|
return (
|
||||||
|
<div className="monacoEditor ant-input" >
|
||||||
|
<Input style={{ display: 'none' }} {...this.props} />
|
||||||
|
<div className="editor" {...this.props} ref={(id) => { this.ref = id; }} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default Monacoeditor;
|
||||||
@@ -2,13 +2,13 @@ import * as React from 'react';
|
|||||||
import { Drawer, Modal, Button, message } from 'component/antd';
|
import { Drawer, Modal, Button, message } from 'component/antd';
|
||||||
import { XFormComponent } from 'component/x-form';
|
import { XFormComponent } from 'component/x-form';
|
||||||
import { IXFormWrapper } from 'types/base-type';
|
import { IXFormWrapper } from 'types/base-type';
|
||||||
|
import { wrapper } from 'store';
|
||||||
|
|
||||||
export class XFormWrapper extends React.Component<IXFormWrapper> {
|
export class XFormWrapper extends React.Component<IXFormWrapper> {
|
||||||
|
|
||||||
public state = {
|
public state = {
|
||||||
confirmLoading: false,
|
confirmLoading: false,
|
||||||
formMap: this.props.formMap || [] as any,
|
formMap: this.props.formMap || [] as any,
|
||||||
formData: this.props.formData || {},
|
formData: this.props.formData || {}
|
||||||
};
|
};
|
||||||
|
|
||||||
private $formRef: any;
|
private $formRef: any;
|
||||||
@@ -108,7 +108,7 @@ export class XFormWrapper extends React.Component<IXFormWrapper> {
|
|||||||
if (error) {
|
if (error) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { onSubmit, isWaitting } = this.props;
|
const { onSubmit, isWaitting, onSubmitFaild } = this.props;
|
||||||
|
|
||||||
if (typeof onSubmit === 'function') {
|
if (typeof onSubmit === 'function') {
|
||||||
if (isWaitting) {
|
if (isWaitting) {
|
||||||
@@ -116,12 +116,16 @@ export class XFormWrapper extends React.Component<IXFormWrapper> {
|
|||||||
confirmLoading: true,
|
confirmLoading: true,
|
||||||
});
|
});
|
||||||
onSubmit(result).then(() => {
|
onSubmit(result).then(() => {
|
||||||
this.setState({
|
|
||||||
confirmLoading: false,
|
|
||||||
});
|
|
||||||
message.success('操作成功');
|
message.success('操作成功');
|
||||||
this.resetForm();
|
this.resetForm();
|
||||||
this.closeModalWrapper();
|
this.closeModalWrapper();
|
||||||
|
}).catch((err: any) => {
|
||||||
|
const { formMap, formData } = wrapper.xFormWrapper;
|
||||||
|
onSubmitFaild(err, this.$formRef, formData, formMap);
|
||||||
|
}).finally(() => {
|
||||||
|
this.setState({
|
||||||
|
confirmLoading: false,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { Select, Input, InputNumber, Form, Switch, Checkbox, DatePicker, Radio, Upload, Button, Icon, Tooltip } from 'component/antd';
|
import { Select, Input, InputNumber, Form, Switch, Checkbox, DatePicker, Radio, Upload, Button, Icon, Tooltip } from 'component/antd';
|
||||||
|
import Monacoeditor from 'component/editor/monacoEditor';
|
||||||
import { searchProps } from 'constants/table';
|
import { searchProps } from 'constants/table';
|
||||||
import './index.less';
|
import './index.less';
|
||||||
|
|
||||||
@@ -19,6 +20,7 @@ export enum FormItemType {
|
|||||||
rangePicker = 'range_picker',
|
rangePicker = 'range_picker',
|
||||||
radioGroup = 'radio_group',
|
radioGroup = 'radio_group',
|
||||||
upload = 'upload',
|
upload = 'upload',
|
||||||
|
monacoEditor = 'monaco_editor',
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IFormItem {
|
export interface IFormItem {
|
||||||
@@ -105,13 +107,11 @@ class XForm extends React.Component<IXFormProps> {
|
|||||||
<Form layout={layout || 'horizontal'} onSubmit={() => ({})}>
|
<Form layout={layout || 'horizontal'} onSubmit={() => ({})}>
|
||||||
{formMap.map(formItem => {
|
{formMap.map(formItem => {
|
||||||
const { initialValue, valuePropName } = this.handleFormItem(formItem, formData);
|
const { initialValue, valuePropName } = this.handleFormItem(formItem, formData);
|
||||||
|
|
||||||
const getFieldValue = {
|
const getFieldValue = {
|
||||||
initialValue,
|
initialValue,
|
||||||
rules: formItem.rules || [{ required: false, message: '' }],
|
rules: formItem.rules || [{ required: false, message: '' }],
|
||||||
valuePropName,
|
valuePropName,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (formItem.type === FormItemType.upload) {
|
if (formItem.type === FormItemType.upload) {
|
||||||
Object.assign(getFieldValue, {
|
Object.assign(getFieldValue, {
|
||||||
getValueFromEvent: this.onUploadFileChange,
|
getValueFromEvent: this.onUploadFileChange,
|
||||||
@@ -137,7 +137,6 @@ class XForm extends React.Component<IXFormProps> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public renderFormItem(item: IFormItem) {
|
public renderFormItem(item: IFormItem) {
|
||||||
|
|
||||||
switch (item.type) {
|
switch (item.type) {
|
||||||
default:
|
default:
|
||||||
case FormItemType.input:
|
case FormItemType.input:
|
||||||
@@ -148,6 +147,9 @@ class XForm extends React.Component<IXFormProps> {
|
|||||||
return <InputNumber {...item.attrs} />;
|
return <InputNumber {...item.attrs} />;
|
||||||
case FormItemType.textArea:
|
case FormItemType.textArea:
|
||||||
return <TextArea rows={5} {...item.attrs} />;
|
return <TextArea rows={5} {...item.attrs} />;
|
||||||
|
case FormItemType.monacoEditor:
|
||||||
|
// tslint:disable-next-line: jsx-wrap-multiline
|
||||||
|
return <Monacoeditor {...item.attrs} />;
|
||||||
case FormItemType.select:
|
case FormItemType.select:
|
||||||
return (
|
return (
|
||||||
<Select
|
<Select
|
||||||
|
|||||||
@@ -66,7 +66,10 @@ export const timeMonthStr = 'YYYY/MM';
|
|||||||
|
|
||||||
// tslint:disable-next-line:max-line-length
|
// tslint:disable-next-line:max-line-length
|
||||||
|
|
||||||
export const indexUrl = 'https://github.com/didi/kafka-manager';
|
export const indexUrl ={
|
||||||
|
indexUrl:'https://github.com/didi/kafka-manager',
|
||||||
|
cagUrl:'https://github.com/didi/Logi-KafkaManager/blob/master/docs/user_guide/add_cluster/add_cluster.md', // 集群接入指南 Cluster access Guide
|
||||||
|
}
|
||||||
|
|
||||||
export const expandRemarks = `请填写不少于5字的申请原因!以便工作人员判断审核`;
|
export const expandRemarks = `请填写不少于5字的申请原因!以便工作人员判断审核`;
|
||||||
|
|
||||||
|
|||||||
@@ -169,6 +169,8 @@ export class ClusterBroker extends SearchAndFilterContainer {
|
|||||||
title="确定删除?"
|
title="确定删除?"
|
||||||
onConfirm={() => this.deteleTopic(record)}
|
onConfirm={() => this.deteleTopic(record)}
|
||||||
disabled={record.status === 0}
|
disabled={record.status === 0}
|
||||||
|
cancelText="取消"
|
||||||
|
okText="确认"
|
||||||
>
|
>
|
||||||
<a style={record.status === 0 ? { cursor: 'not-allowed', color: '#999' } : {}}>
|
<a style={record.status === 0 ? { cursor: 'not-allowed', color: '#999' } : {}}>
|
||||||
删除
|
删除
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ export class ClusterConsumer extends SearchAndFilterContainer {
|
|||||||
}) : [];
|
}) : [];
|
||||||
|
|
||||||
const consumptionColumns = [{
|
const consumptionColumns = [{
|
||||||
title: 'Topic名称',
|
title: '消费的Topic列表',
|
||||||
dataIndex: 'topicName',
|
dataIndex: 'topicName',
|
||||||
key: 'topicName',
|
key: 'topicName',
|
||||||
}];
|
}];
|
||||||
@@ -116,11 +116,13 @@ export class ClusterConsumer extends SearchAndFilterContainer {
|
|||||||
onCancel={() => this.handleDetailsCancel()}
|
onCancel={() => this.handleDetailsCancel()}
|
||||||
maskClosable={false}
|
maskClosable={false}
|
||||||
footer={null}
|
footer={null}
|
||||||
|
// centered={true}
|
||||||
>
|
>
|
||||||
<Table
|
<Table
|
||||||
columns={consumptionColumns}
|
columns={consumptionColumns}
|
||||||
dataSource={details}
|
dataSource={details}
|
||||||
pagination={pagination}
|
// 运维管控-消费组列表-详情
|
||||||
|
pagination={details.length < 10 ? false : pagination}
|
||||||
rowKey="key"
|
rowKey="key"
|
||||||
scroll={{ y: 260 }}
|
scroll={{ y: 260 }}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -46,12 +46,6 @@ export class ClusterController extends SearchAndFilterContainer {
|
|||||||
key: 'brokerId',
|
key: 'brokerId',
|
||||||
width: '30%',
|
width: '30%',
|
||||||
sorter: (a: IController, b: IController) => b.brokerId - a.brokerId,
|
sorter: (a: IController, b: IController) => b.brokerId - a.brokerId,
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'BrokerHost',
|
|
||||||
key: 'host',
|
|
||||||
dataIndex: 'host',
|
|
||||||
width: '30%',
|
|
||||||
render: (r: string, t: IController) => {
|
render: (r: string, t: IController) => {
|
||||||
return (
|
return (
|
||||||
<a href={`${this.urlPrefix}/admin/broker-detail?clusterId=${this.clusterId}&brokerId=${t.brokerId}`}>{r}
|
<a href={`${this.urlPrefix}/admin/broker-detail?clusterId=${this.clusterId}&brokerId=${t.brokerId}`}>{r}
|
||||||
@@ -59,6 +53,18 @@ export class ClusterController extends SearchAndFilterContainer {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: 'BrokerHost',
|
||||||
|
key: 'host',
|
||||||
|
dataIndex: 'host',
|
||||||
|
width: '30%',
|
||||||
|
// render: (r: string, t: IController) => {
|
||||||
|
// return (
|
||||||
|
// <a href={`${this.urlPrefix}/admin/broker-detail?clusterId=${this.clusterId}&brokerId=${t.brokerId}`}>{r}
|
||||||
|
// </a>
|
||||||
|
// );
|
||||||
|
// },
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: '变更时间',
|
title: '变更时间',
|
||||||
dataIndex: 'timestamp',
|
dataIndex: 'timestamp',
|
||||||
|
|||||||
@@ -32,10 +32,12 @@ export class ClusterOverview extends React.Component<IOverview> {
|
|||||||
const clusterContent = [{
|
const clusterContent = [{
|
||||||
value: content.clusterName,
|
value: content.clusterName,
|
||||||
label: '集群名称',
|
label: '集群名称',
|
||||||
}, {
|
},
|
||||||
value: clusterTypeMap[content.mode],
|
// {
|
||||||
label: '集群类型',
|
// value: clusterTypeMap[content.mode],
|
||||||
}, {
|
// label: '集群类型',
|
||||||
|
// },
|
||||||
|
{
|
||||||
value: gmtCreate,
|
value: gmtCreate,
|
||||||
label: '接入时间',
|
label: '接入时间',
|
||||||
}];
|
}];
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import * as React from 'react';
|
|||||||
import Url from 'lib/url-parser';
|
import Url from 'lib/url-parser';
|
||||||
import { region } from 'store';
|
import { region } from 'store';
|
||||||
import { admin } from 'store/admin';
|
import { admin } from 'store/admin';
|
||||||
|
import { topic } from 'store/topic';
|
||||||
import { Table, notification, Tooltip, Popconfirm } from 'antd';
|
import { Table, notification, Tooltip, Popconfirm } from 'antd';
|
||||||
import { pagination, cellStyle } from 'constants/table';
|
import { pagination, cellStyle } from 'constants/table';
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
@@ -15,6 +16,8 @@ import './index.less';
|
|||||||
|
|
||||||
import moment = require('moment');
|
import moment = require('moment');
|
||||||
import { ExpandPartitionFormWrapper } from 'container/modal/admin/expand-partition';
|
import { ExpandPartitionFormWrapper } from 'container/modal/admin/expand-partition';
|
||||||
|
import { ConfirmDetailTopicFormWrapper } from 'container/modal/admin/confirm-detail-topic';
|
||||||
|
|
||||||
import { showEditClusterTopic } from 'container/modal/admin';
|
import { showEditClusterTopic } from 'container/modal/admin';
|
||||||
import { timeFormat } from 'constants/strategy';
|
import { timeFormat } from 'constants/strategy';
|
||||||
|
|
||||||
@@ -26,6 +29,7 @@ export class ClusterTopic extends SearchAndFilterContainer {
|
|||||||
public state = {
|
public state = {
|
||||||
searchKey: '',
|
searchKey: '',
|
||||||
expandVisible: false,
|
expandVisible: false,
|
||||||
|
detailTopicVisible: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props: any) {
|
constructor(props: any) {
|
||||||
@@ -44,11 +48,44 @@ export class ClusterTopic extends SearchAndFilterContainer {
|
|||||||
this.setState({ expandVisible: val });
|
this.setState({ expandVisible: val });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 运维管控-集群列表-Topic列表修改删除业务逻辑-确认删除topic
|
||||||
|
public handleConfirmVisible(val: boolean) {
|
||||||
|
this.setState({ detailTopicVisible: val });
|
||||||
|
}
|
||||||
|
|
||||||
public expandPartition(item: IClusterTopics) {
|
public expandPartition(item: IClusterTopics) {
|
||||||
|
// getTopicBasicInfo
|
||||||
|
admin.getTopicsBasicInfo(item.clusterId, item.topicName).then(data => {
|
||||||
|
console.log(admin.topicsBasic);
|
||||||
|
console.log(admin.basicInfo);
|
||||||
this.clusterTopicsFrom = item;
|
this.clusterTopicsFrom = item;
|
||||||
this.setState({
|
this.setState({
|
||||||
expandVisible: true,
|
expandVisible: true,
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
// if (item.logicalClusterId) {
|
||||||
|
// topic.getTopicBasicInfo(item.logicalClusterId, item.topicName).then(data => {
|
||||||
|
// item.regionNameList = topic.baseInfo.regionNameList;
|
||||||
|
// this.clusterTopicsFrom = item;
|
||||||
|
// this.setState({
|
||||||
|
// expandVisible: true,
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
// } else {
|
||||||
|
// this.clusterTopicsFrom = item;
|
||||||
|
// this.setState({
|
||||||
|
// expandVisible: true,
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
// 运维管控-集群列表-Topic列表修改删除业务逻辑-确认删除topic
|
||||||
|
public confirmDetailTopic(item: IClusterTopics) {
|
||||||
|
this.clusterTopicsFrom = item;
|
||||||
|
// console.log(this.clusterTopicsFrom);
|
||||||
|
this.setState({
|
||||||
|
detailTopicVisible: true,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public deleteTopic(item: IClusterTopics) {
|
public deleteTopic(item: IClusterTopics) {
|
||||||
@@ -85,7 +122,7 @@ export class ClusterTopic extends SearchAndFilterContainer {
|
|||||||
title: 'Topic名称',
|
title: 'Topic名称',
|
||||||
dataIndex: 'topicName',
|
dataIndex: 'topicName',
|
||||||
key: 'topicName',
|
key: 'topicName',
|
||||||
width: '15%',
|
width: '120px',
|
||||||
sorter: (a: IClusterTopics, b: IClusterTopics) => a.topicName.charCodeAt(0) - b.topicName.charCodeAt(0),
|
sorter: (a: IClusterTopics, b: IClusterTopics) => a.topicName.charCodeAt(0) - b.topicName.charCodeAt(0),
|
||||||
render: (text: string, record: IClusterTopics) => {
|
render: (text: string, record: IClusterTopics) => {
|
||||||
return (
|
return (
|
||||||
@@ -99,11 +136,18 @@ export class ClusterTopic extends SearchAndFilterContainer {
|
|||||||
</Tooltip>);
|
</Tooltip>);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: '分区数',
|
||||||
|
dataIndex: 'partitionNum',
|
||||||
|
key: 'partitionNum',
|
||||||
|
width: '90px',
|
||||||
|
sorter: (a: IClusterTopics, b: IClusterTopics) => b.partitionNum - a.partitionNum,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: 'QPS',
|
title: 'QPS',
|
||||||
dataIndex: 'produceRequest',
|
dataIndex: 'produceRequest',
|
||||||
key: 'produceRequest',
|
key: 'produceRequest',
|
||||||
width: '10%',
|
// width: '10%',
|
||||||
sorter: (a: IClusterTopics, b: IClusterTopics) => b.produceRequest - a.produceRequest,
|
sorter: (a: IClusterTopics, b: IClusterTopics) => b.produceRequest - a.produceRequest,
|
||||||
render: (t: number) => t === null ? '' : t.toFixed(2),
|
render: (t: number) => t === null ? '' : t.toFixed(2),
|
||||||
},
|
},
|
||||||
@@ -111,15 +155,23 @@ export class ClusterTopic extends SearchAndFilterContainer {
|
|||||||
title: 'Bytes In(KB/s)',
|
title: 'Bytes In(KB/s)',
|
||||||
dataIndex: 'byteIn',
|
dataIndex: 'byteIn',
|
||||||
key: 'byteIn',
|
key: 'byteIn',
|
||||||
width: '15%',
|
// width: '15%',
|
||||||
sorter: (a: IClusterTopics, b: IClusterTopics) => b.byteIn - a.byteIn,
|
sorter: (a: IClusterTopics, b: IClusterTopics) => b.byteIn - a.byteIn,
|
||||||
render: (t: number) => t === null ? '' : (t / 1024).toFixed(2),
|
render: (t: number) => t === null ? '' : (t / 1024).toFixed(2),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: 'Bytes Out(KB/s)',
|
||||||
|
dataIndex: 'byteOut',
|
||||||
|
key: 'byteOut',
|
||||||
|
// width: '15%',
|
||||||
|
sorter: (a: IClusterTopics, b: IClusterTopics) => b.byteOut - a.byteOut,
|
||||||
|
render: (t: number) => t && t === null ? '' : (t / 1024).toFixed(2),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: '所属应用',
|
title: '所属应用',
|
||||||
dataIndex: 'appName',
|
dataIndex: 'appName',
|
||||||
key: 'appName',
|
key: 'appName',
|
||||||
width: '10%',
|
// width: '10%',
|
||||||
render: (val: string, record: IClusterTopics) => (
|
render: (val: string, record: IClusterTopics) => (
|
||||||
<Tooltip placement="bottomLeft" title={record.appId} >
|
<Tooltip placement="bottomLeft" title={record.appId} >
|
||||||
{val}
|
{val}
|
||||||
@@ -130,7 +182,7 @@ export class ClusterTopic extends SearchAndFilterContainer {
|
|||||||
title: '保存时间(h)',
|
title: '保存时间(h)',
|
||||||
dataIndex: 'retentionTime',
|
dataIndex: 'retentionTime',
|
||||||
key: 'retentionTime',
|
key: 'retentionTime',
|
||||||
width: '10%',
|
// width: '10%',
|
||||||
sorter: (a: IClusterTopics, b: IClusterTopics) => b.retentionTime - a.retentionTime,
|
sorter: (a: IClusterTopics, b: IClusterTopics) => b.retentionTime - a.retentionTime,
|
||||||
render: (time: any) => transMSecondToHour(time),
|
render: (time: any) => transMSecondToHour(time),
|
||||||
},
|
},
|
||||||
@@ -138,14 +190,15 @@ export class ClusterTopic extends SearchAndFilterContainer {
|
|||||||
title: '更新时间',
|
title: '更新时间',
|
||||||
dataIndex: 'updateTime',
|
dataIndex: 'updateTime',
|
||||||
key: 'updateTime',
|
key: 'updateTime',
|
||||||
|
sorter: (a: IClusterTopics, b: IClusterTopics) => b.updateTime - a.updateTime,
|
||||||
render: (t: number) => moment(t).format(timeFormat),
|
render: (t: number) => moment(t).format(timeFormat),
|
||||||
width: '10%',
|
// width: '10%',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Topic说明',
|
title: 'Topic说明',
|
||||||
dataIndex: 'description',
|
dataIndex: 'description',
|
||||||
key: 'description',
|
key: 'description',
|
||||||
width: '15%',
|
// width: '15%',
|
||||||
onCell: () => ({
|
onCell: () => ({
|
||||||
style: {
|
style: {
|
||||||
maxWidth: 180,
|
maxWidth: 180,
|
||||||
@@ -155,14 +208,19 @@ export class ClusterTopic extends SearchAndFilterContainer {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
width: '30%',
|
width: '120px',
|
||||||
render: (value: string, item: IClusterTopics) => (
|
render: (value: string, item: IClusterTopics) => (
|
||||||
<>
|
<>
|
||||||
<a onClick={() => this.getBaseInfo(item)} className="action-button">编辑</a>
|
<a onClick={() => this.getBaseInfo(item)} className="action-button">编辑</a>
|
||||||
<a onClick={() => this.expandPartition(item)} className="action-button">扩分区</a>
|
<a onClick={() => this.expandPartition(item)} className="action-button">扩分区</a>
|
||||||
|
{/* <a onClick={() => this.expandPartition(item)} className="action-button">删除</a> */}
|
||||||
<Popconfirm
|
<Popconfirm
|
||||||
title="确定删除?"
|
title="确定删除?"
|
||||||
onConfirm={() => this.deleteTopic(item)}
|
// 运维管控-集群列表-Topic列表修改删除业务逻辑
|
||||||
|
onConfirm={() => this.confirmDetailTopic(item)}
|
||||||
|
// onConfirm={() => this.deleteTopic(item)}
|
||||||
|
cancelText="取消"
|
||||||
|
okText="确认"
|
||||||
>
|
>
|
||||||
<a>删除</a>
|
<a>删除</a>
|
||||||
</Popconfirm>
|
</Popconfirm>
|
||||||
@@ -190,6 +248,24 @@ export class ClusterTopic extends SearchAndFilterContainer {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{this.renderExpandModal()}
|
{this.renderExpandModal()}
|
||||||
|
{this.renderConfirmDetailModal()}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// 运维管控-集群列表-Topic列表修改删除业务逻辑-确认删除topic
|
||||||
|
public renderConfirmDetailModal() {
|
||||||
|
let formData = {} as IClusterTopics;
|
||||||
|
formData = this.clusterTopicsFrom ? this.clusterTopicsFrom : formData;
|
||||||
|
// console.log(formData);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{this.state.detailTopicVisible && <ConfirmDetailTopicFormWrapper
|
||||||
|
deleteTopic={(val: IClusterTopics) => this.deleteTopic(val)}
|
||||||
|
handleVisible={(val: boolean) => this.handleConfirmVisible(val)}
|
||||||
|
visible={this.state.detailTopicVisible}
|
||||||
|
formData={formData}
|
||||||
|
clusterId={this.clusterId}
|
||||||
|
/>}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
import { Table, notification, Tooltip, Popconfirm } from 'component/antd';
|
import { Table, notification, Tooltip, Popconfirm, Modal, Button } from 'component/antd';
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
import { SearchAndFilterContainer } from 'container/search-filter';
|
import { SearchAndFilterContainer } from 'container/search-filter';
|
||||||
import { pagination, cellStyle } from 'constants/table';
|
import { pagination, cellStyle } from 'constants/table';
|
||||||
@@ -21,6 +21,8 @@ export class ExclusiveCluster extends SearchAndFilterContainer {
|
|||||||
public state = {
|
public state = {
|
||||||
searchKey: '',
|
searchKey: '',
|
||||||
filterStatus: false,
|
filterStatus: false,
|
||||||
|
deteleRegion: false,
|
||||||
|
logicalClusterName: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
private xFormModal: IXFormWrapper;
|
private xFormModal: IXFormWrapper;
|
||||||
@@ -143,6 +145,8 @@ export class ExclusiveCluster extends SearchAndFilterContainer {
|
|||||||
<Popconfirm
|
<Popconfirm
|
||||||
title="确定删除?"
|
title="确定删除?"
|
||||||
onConfirm={() => this.handleDeleteRegion(record)}
|
onConfirm={() => this.handleDeleteRegion(record)}
|
||||||
|
cancelText="取消"
|
||||||
|
okText="确认"
|
||||||
>
|
>
|
||||||
<a>删除</a>
|
<a>删除</a>
|
||||||
</Popconfirm>
|
</Popconfirm>
|
||||||
@@ -154,10 +158,31 @@ export class ExclusiveCluster extends SearchAndFilterContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public handleDeleteRegion = (record: IBrokersRegions) => {
|
public handleDeleteRegion = (record: IBrokersRegions) => {
|
||||||
|
const filterRegion = admin.logicalClusters.filter(item => item.regionIdList.includes(record.id));
|
||||||
|
|
||||||
|
if (!filterRegion) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (filterRegion && filterRegion.length < 1) {
|
||||||
deleteRegions(record.id).then(() => {
|
deleteRegions(record.id).then(() => {
|
||||||
notification.success({ message: '删除成功' });
|
notification.success({ message: '删除成功' });
|
||||||
admin.getBrokersRegions(this.clusterId);
|
admin.getBrokersRegions(this.clusterId);
|
||||||
});
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.setState({ deteleRegion: true, logicalClusterName: filterRegion[0].logicalClusterName });
|
||||||
|
// deleteRegions(record.id).then(() => {
|
||||||
|
// notification.success({ message: '删除成功' });
|
||||||
|
// admin.getBrokersRegions(this.clusterId);
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
|
||||||
|
public handleExpandOk = () => {
|
||||||
|
this.setState({ deteleRegion: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
public handleExpandCancel = () => {
|
||||||
|
this.setState({ deteleCluster: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
public addOrModifyRegion(record?: IBrokersRegions) {
|
public addOrModifyRegion(record?: IBrokersRegions) {
|
||||||
@@ -185,9 +210,9 @@ export class ExclusiveCluster extends SearchAndFilterContainer {
|
|||||||
key: 'brokerIdList',
|
key: 'brokerIdList',
|
||||||
label: 'Broker列表',
|
label: 'Broker列表',
|
||||||
defaultValue: record ? record.brokerIdList.join(',') : [],
|
defaultValue: record ? record.brokerIdList.join(',') : [],
|
||||||
rules: [{ required: true, message: '请输入BrokerIdList' }],
|
rules: [{ required: true, message: '请输入BrokerID,多个BrokerID用半角逗号分隔' }],
|
||||||
attrs: {
|
attrs: {
|
||||||
placeholder: '请输入BrokerIdList',
|
placeholder: '请输入BrokerID,多个BrokerID用半角逗号分隔',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -248,6 +273,7 @@ export class ExclusiveCluster extends SearchAndFilterContainer {
|
|||||||
|
|
||||||
public componentDidMount() {
|
public componentDidMount() {
|
||||||
admin.getBrokersRegions(this.clusterId);
|
admin.getBrokersRegions(this.clusterId);
|
||||||
|
admin.getLogicalClusters(this.clusterId);
|
||||||
admin.getBrokersMetadata(this.clusterId);
|
admin.getBrokersMetadata(this.clusterId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,9 +281,9 @@ export class ExclusiveCluster extends SearchAndFilterContainer {
|
|||||||
let data: T[] = origin;
|
let data: T[] = origin;
|
||||||
let { searchKey } = this.state;
|
let { searchKey } = this.state;
|
||||||
searchKey = (searchKey + '').trim().toLowerCase();
|
searchKey = (searchKey + '').trim().toLowerCase();
|
||||||
|
|
||||||
data = searchKey ? origin.filter((item: IBrokersRegions) =>
|
data = searchKey ? origin.filter((item: IBrokersRegions) =>
|
||||||
(item.name !== undefined && item.name !== null) && item.name.toLowerCase().includes(searchKey as string),
|
(item.name !== undefined && item.name !== null) && item.name.toLowerCase().includes(searchKey as string)
|
||||||
|
|| item.brokerIdList && item.brokerIdList.map(item => "" + item).join(',').includes(searchKey as string),
|
||||||
) : origin;
|
) : origin;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
@@ -272,6 +298,30 @@ export class ExclusiveCluster extends SearchAndFilterContainer {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// -删除RegionModal
|
||||||
|
public renderDeleteRegionModal() {
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
title="提示"
|
||||||
|
visible={this.state.deteleRegion}
|
||||||
|
// okText="确定"
|
||||||
|
// cancelText="取消"
|
||||||
|
maskClosable={false}
|
||||||
|
// onCancel={() => this.handleExpandCancel()}
|
||||||
|
closable={false}
|
||||||
|
// onOk={() => this.handleExpandOk()}
|
||||||
|
footer={<Button style={{ width: '80px' }} type="primary" onClick={() => this.handleExpandOk()}>确定</Button>}
|
||||||
|
// onCancel={() => this.handleExpandCancel()}
|
||||||
|
>
|
||||||
|
<div className="region-prompt">
|
||||||
|
<span>
|
||||||
|
由于该Region已被逻辑集群【 {this.state.logicalClusterName} 】使用
|
||||||
|
请先解除Region与逻辑集群的关系
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
return (
|
return (
|
||||||
@@ -282,7 +332,7 @@ export class ExclusiveCluster extends SearchAndFilterContainer {
|
|||||||
<i className="k-icon-xinjian didi-theme" />
|
<i className="k-icon-xinjian didi-theme" />
|
||||||
<span>新增Region</span>
|
<span>新增Region</span>
|
||||||
</li>
|
</li>
|
||||||
{this.renderSearch('', '请输入Region名称')}
|
{this.renderSearch('', '请输入Region名称/broker ID')}
|
||||||
</ul>
|
</ul>
|
||||||
{this.renderRegion()}
|
{this.renderRegion()}
|
||||||
</div >
|
</div >
|
||||||
|
|||||||
@@ -82,3 +82,16 @@
|
|||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.cluster-prompt{
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.cluster-explain{
|
||||||
|
color: #838383;
|
||||||
|
// transform: scale(0.95,0.95);
|
||||||
|
// text-align: center;
|
||||||
|
}
|
||||||
|
.region-prompt{
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
import { Table, notification, Popconfirm } from 'component/antd';
|
import { Table, notification, Popconfirm } from 'component/antd';
|
||||||
|
import { Modal } from 'antd';
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
import { SearchAndFilterContainer } from 'container/search-filter';
|
import { SearchAndFilterContainer } from 'container/search-filter';
|
||||||
import { pagination } from 'constants/table';
|
import { pagination } from 'constants/table';
|
||||||
@@ -21,6 +22,8 @@ export class LogicalCluster extends SearchAndFilterContainer {
|
|||||||
public state = {
|
public state = {
|
||||||
searchKey: '',
|
searchKey: '',
|
||||||
filterStatus: false,
|
filterStatus: false,
|
||||||
|
deteleCluster: false,
|
||||||
|
logicalClusterId: -1,
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props: any) {
|
constructor(props: any) {
|
||||||
@@ -37,9 +40,16 @@ export class LogicalCluster extends SearchAndFilterContainer {
|
|||||||
key: 'logicalClusterId',
|
key: 'logicalClusterId',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '逻辑集群名称',
|
title: '逻辑集群中文名称',
|
||||||
dataIndex: 'logicalClusterName',
|
dataIndex: 'logicalClusterName',
|
||||||
key: 'logicalClusterName',
|
key: 'logicalClusterName',
|
||||||
|
width: '150px'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '逻辑集群英文名称',
|
||||||
|
dataIndex: 'logicalClusterName',
|
||||||
|
key: 'logicalClusterName1',
|
||||||
|
width: '150px'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '应用ID',
|
title: '应用ID',
|
||||||
@@ -63,7 +73,7 @@ export class LogicalCluster extends SearchAndFilterContainer {
|
|||||||
key: 'mode',
|
key: 'mode',
|
||||||
render: (value: number) => {
|
render: (value: number) => {
|
||||||
let val = '';
|
let val = '';
|
||||||
cluster.clusterModes.forEach((ele: any) => {
|
cluster.clusterModes && cluster.clusterModes.forEach((ele: any) => {
|
||||||
if (value === ele.code) {
|
if (value === ele.code) {
|
||||||
val = ele.message;
|
val = ele.message;
|
||||||
}
|
}
|
||||||
@@ -84,16 +94,20 @@ export class LogicalCluster extends SearchAndFilterContainer {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
|
width: '120px',
|
||||||
render: (text: string, record: ILogicalCluster) => {
|
render: (text: string, record: ILogicalCluster) => {
|
||||||
return (
|
return (
|
||||||
<span className="table-operation">
|
<span className="table-operation">
|
||||||
<a onClick={() => this.editRegion(record)}>编辑</a>
|
<a onClick={() => this.editRegion(record)}>编辑</a>
|
||||||
<Popconfirm
|
<a onClick={() => this.handleDeleteRegion(record)}>删除</a>
|
||||||
|
{/* <Popconfirm
|
||||||
title="确定删除?"
|
title="确定删除?"
|
||||||
|
cancelText="取消"
|
||||||
|
okText="确认"
|
||||||
onConfirm={() => this.handleDeleteRegion(record)}
|
onConfirm={() => this.handleDeleteRegion(record)}
|
||||||
>
|
>
|
||||||
<a>删除</a>
|
<a>删除</a>
|
||||||
</Popconfirm>
|
</Popconfirm> */}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -102,9 +116,24 @@ export class LogicalCluster extends SearchAndFilterContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public handleDeleteRegion = (record: ILogicalCluster) => {
|
public handleDeleteRegion = (record: ILogicalCluster) => {
|
||||||
admin.deteleLogicalClusters(this.clusterId, record.logicalClusterId).then(() => {
|
this.setState({ deteleCluster: true, logicalClusterId: record.logicalClusterId });
|
||||||
|
// admin.deteleLogicalClusters(this.clusterId, record.logicalClusterId).then(() => {
|
||||||
|
// notification.success({ message: '删除成功' });
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
|
||||||
|
// -删除逻辑集群
|
||||||
|
|
||||||
|
public handleExpandOk = () => {
|
||||||
|
const { logicalClusterId } = this.state;
|
||||||
|
admin.deteleLogicalClusters(this.clusterId, logicalClusterId).then(() => {
|
||||||
notification.success({ message: '删除成功' });
|
notification.success({ message: '删除成功' });
|
||||||
});
|
});
|
||||||
|
this.setState({ deteleCluster: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
public handleExpandCancel = () => {
|
||||||
|
this.setState({ deteleCluster: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
public async editRegion(record: ILogicalCluster) {
|
public async editRegion(record: ILogicalCluster) {
|
||||||
@@ -131,7 +160,6 @@ export class LogicalCluster extends SearchAndFilterContainer {
|
|||||||
let data: T[] = origin;
|
let data: T[] = origin;
|
||||||
let { searchKey } = this.state;
|
let { searchKey } = this.state;
|
||||||
searchKey = (searchKey + '').trim().toLowerCase();
|
searchKey = (searchKey + '').trim().toLowerCase();
|
||||||
|
|
||||||
data = searchKey ? origin.filter((item: ILogicalCluster) =>
|
data = searchKey ? origin.filter((item: ILogicalCluster) =>
|
||||||
(item.logicalClusterName !== undefined && item.logicalClusterName !== null)
|
(item.logicalClusterName !== undefined && item.logicalClusterName !== null)
|
||||||
&& item.logicalClusterName.toLowerCase().includes(searchKey as string)
|
&& item.logicalClusterName.toLowerCase().includes(searchKey as string)
|
||||||
@@ -151,6 +179,32 @@ export class LogicalCluster extends SearchAndFilterContainer {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -删除逻辑集群
|
||||||
|
public renderDeleteCluster() {
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
title="提示"
|
||||||
|
visible={this.state.deteleCluster}
|
||||||
|
okText="确认删除"
|
||||||
|
cancelText="取消"
|
||||||
|
maskClosable={false}
|
||||||
|
onOk={() => this.handleExpandOk()}
|
||||||
|
onCancel={() => this.handleExpandCancel()}
|
||||||
|
>
|
||||||
|
<div className="cluster-prompt">
|
||||||
|
<span>
|
||||||
|
若逻辑集群上存在Topic,则删除逻辑集群后,用户将无法在Topic管理页查看到该Topic
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="cluster-explain">
|
||||||
|
<span>
|
||||||
|
说明:删除逻辑集群不会真实删除该逻辑集群上创建的topic
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
return (
|
return (
|
||||||
<div className="k-row">
|
<div className="k-row">
|
||||||
@@ -163,6 +217,7 @@ export class LogicalCluster extends SearchAndFilterContainer {
|
|||||||
{this.renderSearch('', '请输入逻辑集群名称或AppId')}
|
{this.renderSearch('', '请输入逻辑集群名称或AppId')}
|
||||||
</ul>
|
</ul>
|
||||||
{this.renderLogicalCluster()}
|
{this.renderLogicalCluster()}
|
||||||
|
{this.renderDeleteCluster()}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { Modal, Table, Button, notification, message, Tooltip, Icon, Popconfirm } from 'component/antd';
|
import { Modal, Table, Button, notification, message, Tooltip, Icon, Popconfirm, Alert } from 'component/antd';
|
||||||
import { wrapper } from 'store';
|
import { wrapper } from 'store';
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
import { IXFormWrapper, IMetaData, IRegister } from 'types/base-type';
|
import { IXFormWrapper, IMetaData, IRegister } from 'types/base-type';
|
||||||
@@ -9,6 +9,7 @@ import { SearchAndFilterContainer } from 'container/search-filter';
|
|||||||
import { cluster } from 'store/cluster';
|
import { cluster } from 'store/cluster';
|
||||||
import { customPagination } from 'constants/table';
|
import { customPagination } from 'constants/table';
|
||||||
import { urlPrefix } from 'constants/left-menu';
|
import { urlPrefix } from 'constants/left-menu';
|
||||||
|
import { indexUrl } from 'constants/strategy'
|
||||||
import { region } from 'store';
|
import { region } from 'store';
|
||||||
import './index.less';
|
import './index.less';
|
||||||
import { getAdminClusterColumns } from '../config';
|
import { getAdminClusterColumns } from '../config';
|
||||||
@@ -126,8 +127,13 @@ export class ClusterList extends SearchAndFilterContainer {
|
|||||||
message: '请输入安全协议',
|
message: '请输入安全协议',
|
||||||
}],
|
}],
|
||||||
attrs: {
|
attrs: {
|
||||||
placeholder: '请输入安全协议',
|
placeholder: `请输入安全协议,例如:
|
||||||
rows: 6,
|
{
|
||||||
|
"security.protocol": "SASL_PLAINTEXT",
|
||||||
|
"sasl.mechanism": "PLAIN",
|
||||||
|
"sasl.jaas.config": "org.apache.kafka.common.security.plain.PlainLoginModule required username=\"xxxxxx\" password=\"xxxxxx\";"
|
||||||
|
}`,
|
||||||
|
rows: 8,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -172,7 +178,7 @@ export class ClusterList extends SearchAndFilterContainer {
|
|||||||
<span className="offline_span">
|
<span className="offline_span">
|
||||||
删除集群
|
删除集群
|
||||||
<a>
|
<a>
|
||||||
<Tooltip placement="right" title={'当前集群存在逻辑集群,无法申请下线'} >
|
<Tooltip placement="right" title={'若当前集群存在逻辑集群,则无法删除'} >
|
||||||
<Icon type="question-circle" />
|
<Icon type="question-circle" />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</a>
|
</a>
|
||||||
@@ -185,7 +191,7 @@ export class ClusterList extends SearchAndFilterContainer {
|
|||||||
cancelText: '取消',
|
cancelText: '取消',
|
||||||
onOk() {
|
onOk() {
|
||||||
if (data.length) {
|
if (data.length) {
|
||||||
return message.warning('存在逻辑集群,无法申请下线!');
|
return message.warning('存在逻辑集群,无法删除!');
|
||||||
}
|
}
|
||||||
admin.deleteCluster(record.clusterId).then(data => {
|
admin.deleteCluster(record.clusterId).then(data => {
|
||||||
notification.success({ message: '删除成功' });
|
notification.success({ message: '删除成功' });
|
||||||
@@ -204,7 +210,7 @@ export class ClusterList extends SearchAndFilterContainer {
|
|||||||
};
|
};
|
||||||
const monitorColumns = [
|
const monitorColumns = [
|
||||||
{
|
{
|
||||||
title: '集群名称',
|
title: '逻辑集群列表',
|
||||||
dataIndex: 'name',
|
dataIndex: 'name',
|
||||||
key: 'name',
|
key: 'name',
|
||||||
onCell: () => ({
|
onCell: () => ({
|
||||||
@@ -231,6 +237,7 @@ export class ClusterList extends SearchAndFilterContainer {
|
|||||||
pagination={false}
|
pagination={false}
|
||||||
bordered={true}
|
bordered={true}
|
||||||
/>
|
/>
|
||||||
|
<Alert message="若当前集群存在逻辑集群,则无法删除" type="error" showIcon={true} />
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
@@ -261,6 +268,8 @@ export class ClusterList extends SearchAndFilterContainer {
|
|||||||
<Popconfirm
|
<Popconfirm
|
||||||
title={`确定${item.status === 1 ? '暂停' : '开始'}${item.clusterName}监控?`}
|
title={`确定${item.status === 1 ? '暂停' : '开始'}${item.clusterName}监控?`}
|
||||||
onConfirm={() => this.pauseMonitor(item)}
|
onConfirm={() => this.pauseMonitor(item)}
|
||||||
|
cancelText="取消"
|
||||||
|
okText="确认"
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
className="action-button"
|
className="action-button"
|
||||||
@@ -286,6 +295,7 @@ export class ClusterList extends SearchAndFilterContainer {
|
|||||||
<ul>
|
<ul>
|
||||||
{this.renderSearch('', '请输入集群名称')}
|
{this.renderSearch('', '请输入集群名称')}
|
||||||
<li className="right-btn-1">
|
<li className="right-btn-1">
|
||||||
|
<a style={{ display: 'inline-block', marginRight: '20px' }} href={indexUrl.cagUrl} target="_blank">集群接入指南</a>
|
||||||
<Button type="primary" onClick={this.createOrRegisterCluster.bind(this, null)}>接入集群</Button>
|
<Button type="primary" onClick={this.createOrRegisterCluster.bind(this, null)}>接入集群</Button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ export const getUserColumns = () => {
|
|||||||
<Popconfirm
|
<Popconfirm
|
||||||
title="确定删除?"
|
title="确定删除?"
|
||||||
onConfirm={() => users.deleteUser(record.username)}
|
onConfirm={() => users.deleteUser(record.username)}
|
||||||
|
cancelText="取消"
|
||||||
|
okText="确认"
|
||||||
>
|
>
|
||||||
<a>删除</a>
|
<a>删除</a>
|
||||||
</Popconfirm>
|
</Popconfirm>
|
||||||
@@ -54,7 +56,7 @@ export const getVersionColumns = () => {
|
|||||||
render: (text: string, record: IUploadFile) => {
|
render: (text: string, record: IUploadFile) => {
|
||||||
return (
|
return (
|
||||||
<Tooltip placement="topLeft" title={text} >
|
<Tooltip placement="topLeft" title={text} >
|
||||||
<a href={`${urlPrefix}/info?fileId=${record.id}`} target="_blank">{text}</a>
|
<a href={`${window.origin}/api/v1/rd/kafka-files/${record.id}/config-files?dataCenter=cn`} target="_blank">{text}</a>
|
||||||
</Tooltip>);
|
</Tooltip>);
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
@@ -109,6 +111,8 @@ export const getVersionColumns = () => {
|
|||||||
<Popconfirm
|
<Popconfirm
|
||||||
title="确定删除?"
|
title="确定删除?"
|
||||||
onConfirm={() => version.deleteFile(record.id)}
|
onConfirm={() => version.deleteFile(record.id)}
|
||||||
|
cancelText="取消"
|
||||||
|
okText="确认"
|
||||||
>
|
>
|
||||||
<a>删除</a>
|
<a>删除</a>
|
||||||
</Popconfirm>
|
</Popconfirm>
|
||||||
@@ -168,6 +172,8 @@ export const getConfigureColumns = () => {
|
|||||||
<Popconfirm
|
<Popconfirm
|
||||||
title="确定删除?"
|
title="确定删除?"
|
||||||
onConfirm={() => admin.deleteConfigure(record.configKey)}
|
onConfirm={() => admin.deleteConfigure(record.configKey)}
|
||||||
|
cancelText="取消"
|
||||||
|
okText="确认"
|
||||||
>
|
>
|
||||||
<a>删除</a>
|
<a>删除</a>
|
||||||
</Popconfirm>
|
</Popconfirm>
|
||||||
@@ -190,13 +196,13 @@ const renderClusterHref = (value: number | string, item: IMetaData, key: number
|
|||||||
export const getAdminClusterColumns = () => {
|
export const getAdminClusterColumns = () => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
title: '集群ID',
|
title: '物理集群ID',
|
||||||
dataIndex: 'clusterId',
|
dataIndex: 'clusterId',
|
||||||
key: 'clusterId',
|
key: 'clusterId',
|
||||||
sorter: (a: IMetaData, b: IMetaData) => b.clusterId - a.clusterId,
|
sorter: (a: IMetaData, b: IMetaData) => b.clusterId - a.clusterId,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '集群名称',
|
title: '物理集群名称',
|
||||||
dataIndex: 'clusterName',
|
dataIndex: 'clusterName',
|
||||||
key: 'clusterName',
|
key: 'clusterName',
|
||||||
sorter: (a: IMetaData, b: IMetaData) => a.clusterName.charCodeAt(0) - b.clusterName.charCodeAt(0),
|
sorter: (a: IMetaData, b: IMetaData) => a.clusterName.charCodeAt(0) - b.clusterName.charCodeAt(0),
|
||||||
|
|||||||
@@ -55,7 +55,9 @@ export class EassentialInfo extends React.Component<IEassProps> {
|
|||||||
<Descriptions.Item key={item.label || index} label={item.label}>{item.value}</Descriptions.Item>
|
<Descriptions.Item key={item.label || index} label={item.label}>{item.value}</Descriptions.Item>
|
||||||
))}
|
))}
|
||||||
<Descriptions.Item key="server" label="server配置名">
|
<Descriptions.Item key="server" label="server配置名">
|
||||||
<a href={`${urlPrefix}/info?fileId=${tasks.serverPropertiesFileId || ''}`} target="_blank">{tasks.serverPropertiesName}</a>
|
{/* /api/v1/rd/kafka-files/66/config-files?dataCenter=cn */}
|
||||||
|
|
||||||
|
<a href={`${window.origin}/api/v1/rd/kafka-files/${tasks.serverPropertiesFileId}/config-files?dataCenter=cn`} target="_blank">{tasks.serverPropertiesName}</a>
|
||||||
</Descriptions.Item>
|
</Descriptions.Item>
|
||||||
<Descriptions.Item key="server" label="server配置 MD5">{tasks.serverPropertiesMd5}</Descriptions.Item>
|
<Descriptions.Item key="server" label="server配置 MD5">{tasks.serverPropertiesMd5}</Descriptions.Item>
|
||||||
</Descriptions>
|
</Descriptions>
|
||||||
|
|||||||
@@ -82,6 +82,8 @@ export class OperationDetail extends React.Component {
|
|||||||
<Popconfirm
|
<Popconfirm
|
||||||
title={`确定${showContinue ? '开始' : '暂停'}?`}
|
title={`确定${showContinue ? '开始' : '暂停'}?`}
|
||||||
onConfirm={() => this.bindClick()}
|
onConfirm={() => this.bindClick()}
|
||||||
|
cancelText="取消"
|
||||||
|
okText="确认"
|
||||||
>
|
>
|
||||||
<a>{showContinue ? '开始' : '暂停'}</a>
|
<a>{showContinue ? '开始' : '暂停'}</a>
|
||||||
</Popconfirm>
|
</Popconfirm>
|
||||||
@@ -94,6 +96,8 @@ export class OperationDetail extends React.Component {
|
|||||||
<Popconfirm
|
<Popconfirm
|
||||||
title={`确定回滚?`}
|
title={`确定回滚?`}
|
||||||
onConfirm={() => this.callBackOrCancel('rollback')}
|
onConfirm={() => this.callBackOrCancel('rollback')}
|
||||||
|
cancelText="取消"
|
||||||
|
okText="确认"
|
||||||
>
|
>
|
||||||
<a>回滚</a>
|
<a>回滚</a>
|
||||||
</Popconfirm>
|
</Popconfirm>
|
||||||
@@ -106,6 +110,8 @@ export class OperationDetail extends React.Component {
|
|||||||
<Popconfirm
|
<Popconfirm
|
||||||
title={`确定回滚?`}
|
title={`确定回滚?`}
|
||||||
onConfirm={() => this.callBackOrCancel('cancel')}
|
onConfirm={() => this.callBackOrCancel('cancel')}
|
||||||
|
cancelText="取消"
|
||||||
|
okText="确认"
|
||||||
>
|
>
|
||||||
<a>取消</a>
|
<a>取消</a>
|
||||||
</Popconfirm>
|
</Popconfirm>
|
||||||
|
|||||||
@@ -87,6 +87,8 @@ export class TaskStatusDetails extends SearchAndFilterContainer {
|
|||||||
<Popconfirm
|
<Popconfirm
|
||||||
title={`确定忽略?`}
|
title={`确定忽略?`}
|
||||||
onConfirm={() => this.bindClick(record, 'ignore')}
|
onConfirm={() => this.bindClick(record, 'ignore')}
|
||||||
|
cancelText="取消"
|
||||||
|
okText="确认"
|
||||||
>
|
>
|
||||||
<a>忽略</a>
|
<a>忽略</a>
|
||||||
</Popconfirm>
|
</Popconfirm>
|
||||||
@@ -130,7 +132,7 @@ export class TaskStatusDetails extends SearchAndFilterContainer {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="config-info">
|
<div className="config-info">
|
||||||
{admin.clusterTaskLog}
|
{admin.clusterTaskLog ? admin.clusterTaskLog : '暂无数据'}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -78,10 +78,10 @@ export class ClusterTask extends SearchAndFilterContainer {
|
|||||||
cluster,
|
cluster,
|
||||||
{
|
{
|
||||||
title: '创建时间',
|
title: '创建时间',
|
||||||
dataIndex: 'gmtCreate',
|
dataIndex: 'createTime',
|
||||||
key: 'gmtCreate',
|
key: 'createTime',
|
||||||
width: '15%',
|
width: '15%',
|
||||||
sorter: (a: ITaskManage, b: ITaskManage) => b.gmtCreate - a.gmtCreate,
|
sorter: (a: ITaskManage, b: ITaskManage) => b.createTime - a.createTime,
|
||||||
render: (t: number) => moment(t).format(timeFormat),
|
render: (t: number) => moment(t).format(timeFormat),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ export const migrationTaskColumns = (migrationUrl: string) => {
|
|||||||
<Popconfirm
|
<Popconfirm
|
||||||
title="确定开始?"
|
title="确定开始?"
|
||||||
onConfirm={() => startMigrationTask(item, 'start')}
|
onConfirm={() => startMigrationTask(item, 'start')}
|
||||||
|
cancelText="取消"
|
||||||
|
okText="确认"
|
||||||
>
|
>
|
||||||
<a style={{ marginRight: 16 }}>开始</a>
|
<a style={{ marginRight: 16 }}>开始</a>
|
||||||
</Popconfirm>}
|
</Popconfirm>}
|
||||||
@@ -49,6 +51,8 @@ export const migrationTaskColumns = (migrationUrl: string) => {
|
|||||||
{item.status === 0 &&
|
{item.status === 0 &&
|
||||||
<Popconfirm
|
<Popconfirm
|
||||||
title="确定取消?"
|
title="确定取消?"
|
||||||
|
cancelText="取消"
|
||||||
|
okText="确认"
|
||||||
onConfirm={() => cancelMigrationTask(item, 'cancel')}
|
onConfirm={() => cancelMigrationTask(item, 'cancel')}
|
||||||
><a>取消</a>
|
><a>取消</a>
|
||||||
</Popconfirm>}
|
</Popconfirm>}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ export class MigrationDetail extends SearchAndFilterContainer {
|
|||||||
const detail = expert.tasksDetail;
|
const detail = expert.tasksDetail;
|
||||||
const gmtCreate = moment(detail.gmtCreate).format(timeFormat);
|
const gmtCreate = moment(detail.gmtCreate).format(timeFormat);
|
||||||
const startTime = moment(detail.beginTime).format(timeFormat);
|
const startTime = moment(detail.beginTime).format(timeFormat);
|
||||||
const endTime = moment(detail.endTime).format(timeFormat);
|
const endTime = detail.endTime == null ? '任务运行中' : moment(detail.endTime).format(timeFormat);
|
||||||
const options = [{
|
const options = [{
|
||||||
value: detail.taskName,
|
value: detail.taskName,
|
||||||
label: '任务名称',
|
label: '任务名称',
|
||||||
|
|||||||
@@ -76,6 +76,8 @@ export const getAlarmColumns = (urlPrefix: string) => {
|
|||||||
<Popconfirm
|
<Popconfirm
|
||||||
title="确定删除?"
|
title="确定删除?"
|
||||||
onConfirm={() => deteleMonitor(item)}
|
onConfirm={() => deteleMonitor(item)}
|
||||||
|
cancelText="取消"
|
||||||
|
okText="确认"
|
||||||
>
|
>
|
||||||
<a>删除</a>
|
<a>删除</a>
|
||||||
</Popconfirm>
|
</Popconfirm>
|
||||||
@@ -205,9 +207,9 @@ export const xActionFormMap = [{
|
|||||||
|
|
||||||
export const xTypeFormMap = [{
|
export const xTypeFormMap = [{
|
||||||
key: 'alarmName',
|
key: 'alarmName',
|
||||||
label: '告警规则',
|
label: '告警规则名称',
|
||||||
rules: [{ required: true, message: '请输入告警规则' }],
|
rules: [{ required: true, message: '请输入告警规则' }],
|
||||||
attrs: {placeholder: '请输入', disabled: isDetailPage},
|
attrs: { placeholder: '请输入告警规则名称', disabled: isDetailPage },
|
||||||
}, {
|
}, {
|
||||||
key: 'app',
|
key: 'app',
|
||||||
label: '所属应用',
|
label: '所属应用',
|
||||||
|
|||||||
@@ -260,7 +260,7 @@ export class DynamicSetFilter extends React.Component<IDynamicProps> {
|
|||||||
rules: [{ required: showMore, message: '请选择消费组' }],
|
rules: [{ required: showMore, message: '请选择消费组' }],
|
||||||
attrs: {
|
attrs: {
|
||||||
placeholder: '请选择消费组',
|
placeholder: '请选择消费组',
|
||||||
className: 'middle-size',
|
className: 'large-size',
|
||||||
disabled: this.isDetailPage,
|
disabled: this.isDetailPage,
|
||||||
onChange: (e: string) => this.handleSelectChange(e, 'consumerGroup'),
|
onChange: (e: string) => this.handleSelectChange(e, 'consumerGroup'),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -46,9 +46,12 @@
|
|||||||
|
|
||||||
&.type-form {
|
&.type-form {
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
|
.ant-form{
|
||||||
|
min-width: 755px;
|
||||||
|
}
|
||||||
.ant-form-item {
|
.ant-form-item {
|
||||||
width: 30%
|
width: 30%;
|
||||||
|
min-width: 360px;
|
||||||
}
|
}
|
||||||
.ant-form-item-label {
|
.ant-form-item-label {
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
@@ -161,7 +164,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.dynamic-set {
|
.dynamic-set {
|
||||||
padding: 15px 10px;
|
padding: 15px 0;
|
||||||
|
|
||||||
ul{
|
ul{
|
||||||
li{
|
li{
|
||||||
@@ -176,7 +179,7 @@
|
|||||||
|
|
||||||
.ant-form-item {
|
.ant-form-item {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin: 0px 5px 10px 5px;
|
margin: 0px 5px 10px 0;
|
||||||
|
|
||||||
.ant-select {
|
.ant-select {
|
||||||
width: 150px;
|
width: 150px;
|
||||||
|
|||||||
@@ -163,6 +163,8 @@ export class ShieldHistory extends React.Component {
|
|||||||
<Popconfirm
|
<Popconfirm
|
||||||
title="确定删除?"
|
title="确定删除?"
|
||||||
onConfirm={() => this.deleteSilences(record)}
|
onConfirm={() => this.deleteSilences(record)}
|
||||||
|
cancelText="取消"
|
||||||
|
okText="确认"
|
||||||
>
|
>
|
||||||
<a>删除</a>
|
<a>删除</a>
|
||||||
</Popconfirm>
|
</Popconfirm>
|
||||||
|
|||||||
@@ -29,11 +29,13 @@ export class AppSelect extends React.Component<IStaffSelectProps> {
|
|||||||
{d.name.length > 25 ? <Tooltip placement="bottomLeft" title={d.name}>{d.name}</Tooltip> : d.name}
|
{d.name.length > 25 ? <Tooltip placement="bottomLeft" title={d.name}>{d.name}</Tooltip> : d.name}
|
||||||
</Option>)}
|
</Option>)}
|
||||||
</Select>
|
</Select>
|
||||||
{
|
{/* {
|
||||||
selectData.length ? null : <i>
|
selectData.length ? null : */}
|
||||||
|
<i>
|
||||||
没有应用?
|
没有应用?
|
||||||
<a href={`${urlPrefix}/topic/app-list?${query}`}>立刻创建</a>
|
<a href={`${urlPrefix}/topic/app-list?${query}`}>立刻创建</a>
|
||||||
</i>}
|
</i>
|
||||||
|
{/* } */}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ export class AppDetail extends SearchAndFilterContainer {
|
|||||||
title: '申请时间',
|
title: '申请时间',
|
||||||
dataIndex: 'gmtCreate',
|
dataIndex: 'gmtCreate',
|
||||||
key: 'gmtCreate',
|
key: 'gmtCreate',
|
||||||
|
sorter: (a: any, b: any) => a.gmtCreate - b.gmtCreate,
|
||||||
render: (t: number) => moment(t).format(timeFormat),
|
render: (t: number) => moment(t).format(timeFormat),
|
||||||
},
|
},
|
||||||
statusColumn,
|
statusColumn,
|
||||||
|
|||||||
@@ -31,8 +31,13 @@ export class ClusterOverview extends React.Component<IOverview> {
|
|||||||
const content = this.props.basicInfo as IBasicInfo;
|
const content = this.props.basicInfo as IBasicInfo;
|
||||||
const clusterContent = [{
|
const clusterContent = [{
|
||||||
value: content.clusterName,
|
value: content.clusterName,
|
||||||
label: '集群名称',
|
label: '集群中文名称',
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
|
value: content.clusterName,
|
||||||
|
label: '集群英文名称',
|
||||||
|
},
|
||||||
|
{
|
||||||
value: clusterTypeMap[content.mode],
|
value: clusterTypeMap[content.mode],
|
||||||
label: '集群类型',
|
label: '集群类型',
|
||||||
}, {
|
}, {
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ export class ClusterTopic extends SearchAndFilterContainer {
|
|||||||
dataIndex: 'updateTime',
|
dataIndex: 'updateTime',
|
||||||
key: 'updateTime',
|
key: 'updateTime',
|
||||||
width: '20%',
|
width: '20%',
|
||||||
|
sorter: (a: IClusterTopics, b: IClusterTopics) => b.updateTime - a.updateTime,
|
||||||
render: (t: number) => moment(t).format(timeFormat),
|
render: (t: number) => moment(t).format(timeFormat),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -13,10 +13,35 @@ const { confirm } = Modal;
|
|||||||
export const getClusterColumns = (urlPrefix: string) => {
|
export const getClusterColumns = (urlPrefix: string) => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
title: '集群名称',
|
title: '逻辑集群ID',
|
||||||
|
dataIndex: 'clusterId',
|
||||||
|
key: 'clusterId',
|
||||||
|
width: '9%',
|
||||||
|
sorter: (a: IClusterData, b: IClusterData) => b.clusterId - a.clusterId,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '逻辑集群中文名称',
|
||||||
dataIndex: 'clusterName',
|
dataIndex: 'clusterName',
|
||||||
key: 'clusterName',
|
key: 'clusterName',
|
||||||
width: '15%',
|
width: '13%',
|
||||||
|
onCell: () => ({
|
||||||
|
style: {
|
||||||
|
maxWidth: 120,
|
||||||
|
...cellStyle,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
sorter: (a: IClusterData, b: IClusterData) => a.clusterName.charCodeAt(0) - b.clusterName.charCodeAt(0),
|
||||||
|
render: (text: string, record: IClusterData) => (
|
||||||
|
<Tooltip placement="bottomLeft" title={text} >
|
||||||
|
<a href={`${urlPrefix}/cluster/cluster-detail?clusterId=${record.clusterId}`}> {text} </a>
|
||||||
|
</Tooltip>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '逻辑集群英文名称',
|
||||||
|
dataIndex: 'clusterName',
|
||||||
|
key: 'clusterName',
|
||||||
|
width: '13%',
|
||||||
onCell: () => ({
|
onCell: () => ({
|
||||||
style: {
|
style: {
|
||||||
maxWidth: 120,
|
maxWidth: 120,
|
||||||
@@ -34,21 +59,21 @@ export const getClusterColumns = (urlPrefix: string) => {
|
|||||||
title: 'Topic数量',
|
title: 'Topic数量',
|
||||||
dataIndex: 'topicNum',
|
dataIndex: 'topicNum',
|
||||||
key: 'topicNum',
|
key: 'topicNum',
|
||||||
width: '10%',
|
width: '9%',
|
||||||
sorter: (a: IClusterData, b: IClusterData) => b.topicNum - a.topicNum,
|
sorter: (a: IClusterData, b: IClusterData) => b.topicNum - a.topicNum,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '集群类型',
|
title: '集群类型',
|
||||||
dataIndex: 'mode',
|
dataIndex: 'mode',
|
||||||
key: 'mode',
|
key: 'mode',
|
||||||
width: '10%',
|
width: '9%',
|
||||||
render: (text: number) => (clusterTypeMap[text] || ''),
|
render: (text: number) => (clusterTypeMap[text] || ''),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '集群版本',
|
title: '集群版本',
|
||||||
dataIndex: 'clusterVersion',
|
dataIndex: 'clusterVersion',
|
||||||
key: 'clusterVersion',
|
key: 'clusterVersion',
|
||||||
width: '25%',
|
width: '9%',
|
||||||
onCell: () => ({
|
onCell: () => ({
|
||||||
style: {
|
style: {
|
||||||
maxWidth: 200,
|
maxWidth: 200,
|
||||||
@@ -60,14 +85,14 @@ export const getClusterColumns = (urlPrefix: string) => {
|
|||||||
title: '接入时间',
|
title: '接入时间',
|
||||||
dataIndex: 'gmtCreate',
|
dataIndex: 'gmtCreate',
|
||||||
key: 'gmtCreate',
|
key: 'gmtCreate',
|
||||||
width: '15%',
|
width: '13%',
|
||||||
sorter: (a: IClusterData, b: IClusterData) => b.gmtCreate - a.gmtCreate,
|
sorter: (a: IClusterData, b: IClusterData) => b.gmtCreate - a.gmtCreate,
|
||||||
render: (t: number) => moment(t).format(timeFormat),
|
render: (t: number) => moment(t).format(timeFormat),
|
||||||
}, {
|
}, {
|
||||||
title: '修改时间',
|
title: '修改时间',
|
||||||
dataIndex: 'gmtModify',
|
dataIndex: 'gmtModify',
|
||||||
key: 'gmtModify',
|
key: 'gmtModify',
|
||||||
width: '15%',
|
width: '13%',
|
||||||
sorter: (a: IClusterData, b: IClusterData) => b.gmtModify - a.gmtModify,
|
sorter: (a: IClusterData, b: IClusterData) => b.gmtModify - a.gmtModify,
|
||||||
render: (t: number) => moment(t).format(timeFormat),
|
render: (t: number) => moment(t).format(timeFormat),
|
||||||
},
|
},
|
||||||
@@ -75,7 +100,7 @@ export const getClusterColumns = (urlPrefix: string) => {
|
|||||||
title: '操作',
|
title: '操作',
|
||||||
dataIndex: 'action',
|
dataIndex: 'action',
|
||||||
key: 'action',
|
key: 'action',
|
||||||
width: '10%',
|
width: '20%',
|
||||||
render: (val: string, record: IClusterData) => (
|
render: (val: string, record: IClusterData) => (
|
||||||
<>
|
<>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -113,8 +113,10 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
line-height: 32px;
|
line-height: 32px;
|
||||||
|
a {
|
||||||
|
display: inline-block;
|
||||||
padding: 0px 20px;
|
padding: 0px 20px;
|
||||||
|
}
|
||||||
&:hover {
|
&:hover {
|
||||||
background: rgba(236, 111, 38, 0.1);
|
background: rgba(236, 111, 38, 0.1);
|
||||||
}
|
}
|
||||||
@@ -160,3 +162,16 @@
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// .kafka-header-menu{
|
||||||
|
// .qqqq{
|
||||||
|
// position: relative;
|
||||||
|
// .popover {
|
||||||
|
// position: absolute;
|
||||||
|
// display: block;
|
||||||
|
// left: 0 !important;
|
||||||
|
// // left: 62% !important;
|
||||||
|
// // top: 68px !important;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import * as React from 'react';
|
|||||||
|
|
||||||
import './index.less';
|
import './index.less';
|
||||||
import { userLogOut } from 'lib/api';
|
import { userLogOut } from 'lib/api';
|
||||||
import { notification, Dropdown, Icon, Tooltip } from 'component/antd';
|
import { notification, Dropdown, Icon, Tooltip, Popover } from 'component/antd';
|
||||||
import { urlPrefix } from 'constants/left-menu';
|
import { urlPrefix } from 'constants/left-menu';
|
||||||
import { region, IRegionIdcs } from 'store/region';
|
import { region, IRegionIdcs } from 'store/region';
|
||||||
import logoUrl from '../../assets/image/kafka-logo.png';
|
import logoUrl from '../../assets/image/kafka-logo.png';
|
||||||
@@ -59,7 +59,11 @@ export const Header = observer((props: IHeader) => {
|
|||||||
notification.success({ message: '退出成功' });
|
notification.success({ message: '退出成功' });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
const content = (
|
||||||
|
<div style={{ height: '250px', padding: '5px' }} className="kafka-avatar-img">
|
||||||
|
<img style={{ width: '190px', height: '246px' }} src={weChat} alt="" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
const helpCenter = (
|
const helpCenter = (
|
||||||
<ul className="kafka-header-menu">
|
<ul className="kafka-header-menu">
|
||||||
<li>
|
<li>
|
||||||
@@ -70,25 +74,33 @@ export const Header = observer((props: IHeader) => {
|
|||||||
</a></li>
|
</a></li>
|
||||||
<li>
|
<li>
|
||||||
<a
|
<a
|
||||||
href="https://github.com/didi/kafka-manager"
|
href="https://github.com/didi/kafka-manager/blob/master/docs/user_guide/user_guide_cn.md"
|
||||||
|
target="_blank"
|
||||||
|
>使用手册
|
||||||
|
</a></li>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
href="https://github.com/didi/kafka-manager/blob/master/docs/install_guide/install_guide_cn.md"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>QuickStart
|
>QuickStart
|
||||||
</a></li>
|
</a></li>
|
||||||
<li>
|
<li>
|
||||||
<a
|
<a
|
||||||
href=""
|
href="https://github.com/didi/kafka-manager/blob/master/docs/user_guide/faq.md"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>常见问题
|
>常见问题
|
||||||
</a></li>
|
</a></li>
|
||||||
<li>
|
<li>
|
||||||
|
<Popover placement="left" content={content} trigger="hover">
|
||||||
<a
|
<a
|
||||||
// tslint:disable-next-line:max-line-length
|
// tslint:disable-next-line:max-line-length
|
||||||
href="https://github.com/didi/kafka-manager"
|
// href="https://github.com/didi/kafka-manager"
|
||||||
target="_blank"
|
href="javascript:void(0)"
|
||||||
|
onClick={() => { return false }}
|
||||||
|
// target="_blank"
|
||||||
>联系我们
|
>联系我们
|
||||||
</a></li>
|
</a>
|
||||||
<li style={{ height: '80px', padding: '5px' }} className="kafka-avatar-img">
|
</Popover>
|
||||||
<img style={{ width: '70px', height: '70px' }} src={weChat} alt="" />
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ export const showEditClusterTopic = (item: IClusterTopics) => {
|
|||||||
}],
|
}],
|
||||||
attrs: {
|
attrs: {
|
||||||
placeholder: '请输入应用ID',
|
placeholder: '请输入应用ID',
|
||||||
|
disabled: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -97,18 +98,13 @@ export const showEditClusterTopic = (item: IClusterTopics) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const showLogicalClusterOpModal = (clusterId: number, record?: ILogicalCluster) => {
|
export const showLogicalClusterOpModal = (clusterId: number, record?: ILogicalCluster) => {
|
||||||
let clusterModes = [] as IConfigInfo[];
|
let isShow = false;
|
||||||
clusterModes = cluster.clusterModes ? cluster.clusterModes : clusterModes;
|
if (record && record.mode != 0) {
|
||||||
const xFormModal = {
|
isShow = true;
|
||||||
formMap: [
|
}
|
||||||
{
|
const updateFormModal = (isShow: boolean) => {
|
||||||
key: 'logicalClusterName',
|
const formMap = wrapper.xFormWrapper.formMap;
|
||||||
label: '逻辑集群名称',
|
isShow ? formMap.splice(2, 0,
|
||||||
rules: [{ required: true, message: '请输入逻辑集群名称' }],
|
|
||||||
attrs: {
|
|
||||||
disabled: record ? true : false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: 'appId',
|
key: 'appId',
|
||||||
label: '所属应用',
|
label: '所属应用',
|
||||||
@@ -123,6 +119,41 @@ export const showLogicalClusterOpModal = (clusterId: number, record?: ILogicalCl
|
|||||||
attrs: {
|
attrs: {
|
||||||
placeholder: '请选择所属应用',
|
placeholder: '请选择所属应用',
|
||||||
},
|
},
|
||||||
|
}) : formMap.splice(2, 1);
|
||||||
|
const formData = wrapper.xFormWrapper.formData;
|
||||||
|
wrapper.ref && wrapper.ref.updateFormMap$(formMap, formData || {});
|
||||||
|
};
|
||||||
|
let clusterModes = [] as IConfigInfo[];
|
||||||
|
clusterModes = cluster.clusterModes ? cluster.clusterModes : clusterModes;
|
||||||
|
let xFormModal = {
|
||||||
|
formMap: [
|
||||||
|
{
|
||||||
|
key: 'logicalClusterName',
|
||||||
|
label: '逻辑集群中文名称',
|
||||||
|
// defaultValue:'',
|
||||||
|
rules: [{
|
||||||
|
required: true,
|
||||||
|
message: '请输入逻辑集群中文名称,支持中文、字母、数字、下划线(_)和短划线(-)组成,长度在3-128字符之间', // 不能以下划线(_)和短划线(-)开头和结尾
|
||||||
|
pattern: /^[a-zA-Z0-9_\-\u4e00-\u9fa5]{3,128}$/g, //(?!(_|\-))(?!.*?(_|\-)$)
|
||||||
|
}],
|
||||||
|
attrs: {
|
||||||
|
// disabled: record ? true : false,
|
||||||
|
placeholder:'请输入逻辑集群中文名称'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'logicalClusterName1',
|
||||||
|
label: '逻辑集群英文名称',
|
||||||
|
// defaultValue:'',
|
||||||
|
rules: [{
|
||||||
|
required: true,
|
||||||
|
message: '请输入逻辑集群英文名称,支持字母、数字、下划线(_)和短划线(-)组成,长度在3-128字符之间', //不能以下划线(_)和短划线(-)开头和结尾
|
||||||
|
pattern:/^[a-zA-Z0-9_\-]{3,128}$/g, //(?!(_|\-))(?!.*?(_|\-)$)
|
||||||
|
}],
|
||||||
|
attrs: {
|
||||||
|
disabled: record ? true : false,
|
||||||
|
placeholder:'请输入逻辑集群英文名称,创建后无法修改'
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'mode',
|
key: 'mode',
|
||||||
@@ -136,8 +167,32 @@ export const showLogicalClusterOpModal = (clusterId: number, record?: ILogicalCl
|
|||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
attrs: {
|
attrs: {
|
||||||
|
onChange(item: any) {
|
||||||
|
if (isShow && item == 0) {
|
||||||
|
updateFormModal(false);
|
||||||
|
isShow = false;
|
||||||
|
} else if (!isShow && (item == 1 || item == 2)) {
|
||||||
|
updateFormModal(true);
|
||||||
|
isShow = true;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// key: 'appId',
|
||||||
|
// label: '所属应用',
|
||||||
|
// rules: [{ required: true , message: '请选择所属应用' }],
|
||||||
|
// type: 'select',
|
||||||
|
// options: app.adminAppData.map(item => {
|
||||||
|
// return {
|
||||||
|
// label: item.name,
|
||||||
|
// value: item.appId,
|
||||||
|
// };
|
||||||
|
// }),
|
||||||
|
// attrs: {
|
||||||
|
// placeholder: '请选择所属应用',
|
||||||
|
// },
|
||||||
|
// },
|
||||||
{
|
{
|
||||||
key: 'regionIdList',
|
key: 'regionIdList',
|
||||||
label: 'RegionIdList',
|
label: 'RegionIdList',
|
||||||
@@ -149,10 +204,10 @@ export const showLogicalClusterOpModal = (clusterId: number, record?: ILogicalCl
|
|||||||
value: item.id,
|
value: item.id,
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
rules: [{ required: true, message: '请选择BrokerIdList' }],
|
rules: [{ required: true, message: '请选择RegionIdList' }],
|
||||||
attrs: {
|
attrs: {
|
||||||
mode: 'multiple',
|
mode: 'multiple',
|
||||||
placeholder: '请选择BrokerIdList',
|
placeholder: '请选择RegionIdList',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -169,7 +224,7 @@ export const showLogicalClusterOpModal = (clusterId: number, record?: ILogicalCl
|
|||||||
],
|
],
|
||||||
formData: record,
|
formData: record,
|
||||||
visible: true,
|
visible: true,
|
||||||
title: '新增逻辑集群',
|
title: record ? '编辑逻辑集群' : '新增逻辑集群',
|
||||||
onSubmit: (value: INewLogical) => {
|
onSubmit: (value: INewLogical) => {
|
||||||
const params = {
|
const params = {
|
||||||
appId: value.appId,
|
appId: value.appId,
|
||||||
@@ -178,6 +233,7 @@ export const showLogicalClusterOpModal = (clusterId: number, record?: ILogicalCl
|
|||||||
id: record ? record.logicalClusterId : '',
|
id: record ? record.logicalClusterId : '',
|
||||||
mode: value.mode,
|
mode: value.mode,
|
||||||
name: value.logicalClusterName,
|
name: value.logicalClusterName,
|
||||||
|
englishName:value.logicalClusterEName, // 存储逻辑集群英文名称
|
||||||
regionIdList: value.regionIdList,
|
regionIdList: value.regionIdList,
|
||||||
} as INewLogical;
|
} as INewLogical;
|
||||||
if (record) {
|
if (record) {
|
||||||
@@ -190,6 +246,7 @@ export const showLogicalClusterOpModal = (clusterId: number, record?: ILogicalCl
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
wrapper.open(xFormModal);
|
wrapper.open(xFormModal);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -216,9 +273,9 @@ export const showClusterRegionOpModal = (clusterId: number, content: IMetaData,
|
|||||||
key: 'brokerIdList',
|
key: 'brokerIdList',
|
||||||
label: 'Broker列表',
|
label: 'Broker列表',
|
||||||
defaultValue: record ? record.brokerIdList.join(',') : [] as any,
|
defaultValue: record ? record.brokerIdList.join(',') : [] as any,
|
||||||
rules: [{ required: true, message: '请输入BrokerIdList' }],
|
rules: [{ required: true, message: '请输入BrokerID,多个BrokerID用半角逗号分隔' }],
|
||||||
attrs: {
|
attrs: {
|
||||||
placeholder: '请输入BrokerIdList',
|
placeholder: '请输入BrokerID,多个BrokerID用半角逗号分隔',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,173 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { admin } from 'store/admin';
|
||||||
|
import { notification, Modal, Form, Input, Switch, Select, Tooltip, Radio } from 'antd';
|
||||||
|
import { IBrokersMetadata, IBrokersRegions, IExpand } from 'types/base-type';
|
||||||
|
import { searchProps } from 'constants/table';
|
||||||
|
import { expandPartition } from 'lib/api';
|
||||||
|
|
||||||
|
const layout = {
|
||||||
|
labelCol: { span: 6 },
|
||||||
|
wrapperCol: { span: 15 },
|
||||||
|
};
|
||||||
|
|
||||||
|
interface IXFormProps {
|
||||||
|
form: any;
|
||||||
|
formData?: any;
|
||||||
|
visible?: boolean;
|
||||||
|
handleVisible?: any;
|
||||||
|
clusterId?: number;
|
||||||
|
deleteTopic?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
class CustomForm extends React.Component<IXFormProps> {
|
||||||
|
// public state = {
|
||||||
|
// checked: false,
|
||||||
|
// };
|
||||||
|
|
||||||
|
// public onSwitchChange(checked: boolean) {
|
||||||
|
// this.setState({ checked });
|
||||||
|
// this.props.form.validateFields((err: any, values: any) => {
|
||||||
|
// checked ? values.brokerIdList = [] : values.regionId = '';
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
public handleExpandOk() {
|
||||||
|
this.props.form.validateFields((err: any, values: any) => {
|
||||||
|
const deleteData = this.props.formData;
|
||||||
|
if (!err) {
|
||||||
|
// console.log('values', values);
|
||||||
|
if (values.topicName !== this.props.formData.topicName) {
|
||||||
|
notification.error({ message: 'topic名称不正确,请重新输入' });
|
||||||
|
} else {
|
||||||
|
this.props.handleVisible(false);
|
||||||
|
// 调用删除接口
|
||||||
|
this.props.deleteTopic(deleteData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if (!err) {
|
||||||
|
// this.props.handleVisible(false);
|
||||||
|
// const params = {
|
||||||
|
// topicName: values.topicName,
|
||||||
|
// clusterId: this.props.clusterId,
|
||||||
|
// partitionNum: values.partitionNum,
|
||||||
|
// } as IExpand;
|
||||||
|
// if (values.brokerIdList) {
|
||||||
|
// params.brokerIdList = values.brokerIdList;
|
||||||
|
// } else {
|
||||||
|
// params.regionId = values.regionId;
|
||||||
|
// }
|
||||||
|
// const valueParams = [] as IExpand[];
|
||||||
|
// valueParams.push(params);
|
||||||
|
// expandPartition(valueParams).then(data => {
|
||||||
|
// notification.success({ message: '扩分成功' });
|
||||||
|
// this.props.form.resetFields();
|
||||||
|
// admin.getClusterTopics(this.props.clusterId);
|
||||||
|
// });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public handleExpandCancel() {
|
||||||
|
this.props.handleVisible(false);
|
||||||
|
this.props.form.resetFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
public componentDidMount() {
|
||||||
|
admin.getBrokersMetadata(this.props.clusterId);
|
||||||
|
admin.getBrokersRegions(this.props.clusterId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
// console.log('props', this.props);
|
||||||
|
const { formData = {} as any, visible } = this.props;
|
||||||
|
const { getFieldDecorator } = this.props.form;
|
||||||
|
let metadata = [] as IBrokersMetadata[];
|
||||||
|
metadata = admin.brokersMetadata ? admin.brokersMetadata : metadata;
|
||||||
|
let regions = [] as IBrokersRegions[];
|
||||||
|
regions = admin.brokersRegions ? admin.brokersRegions : regions;
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
title="提示"
|
||||||
|
visible={visible}
|
||||||
|
onOk={() => this.handleExpandOk()}
|
||||||
|
onCancel={() => this.handleExpandCancel()}
|
||||||
|
maskClosable={false}
|
||||||
|
okText="确认"
|
||||||
|
cancelText="取消"
|
||||||
|
>
|
||||||
|
<Form {...layout} name="basic" onSubmit={() => ({})} >
|
||||||
|
{/* <Form.Item label="Topic名称" >
|
||||||
|
{getFieldDecorator('topicName', {
|
||||||
|
initialValue: formData.topicName,
|
||||||
|
rules: [{ required: true, message: '请输入Topic名称' }],
|
||||||
|
})(<Input disabled={true} placeholder="请输入Topic名称" />)}
|
||||||
|
</Form.Item> */}
|
||||||
|
|
||||||
|
{/* 运维管控-topic信息-扩分区操作 */}
|
||||||
|
{/* <Form.Item label="所属region" >
|
||||||
|
{getFieldDecorator('topicName', {
|
||||||
|
initialValue: formData.topicName,
|
||||||
|
rules: [{ required: true, message: '请输入所属region' }],
|
||||||
|
})(<Input disabled={true} placeholder="请输入所属region" />)}
|
||||||
|
</Form.Item> */}
|
||||||
|
{/* 运维管控-topic信息-扩分区操作 */}
|
||||||
|
<div style={{ textAlign: 'center', padding: '10px 0', fontSize: '13px', fontWeight: 'bold', color: 'red' }}>
|
||||||
|
<span>由于删除Topic是高危操作,需再次输入Topic名称进行确认。</span>
|
||||||
|
</div>
|
||||||
|
<Form.Item label="Topic名称" >
|
||||||
|
{getFieldDecorator('topicName', {
|
||||||
|
rules: [{
|
||||||
|
required: true,
|
||||||
|
message: 'topic名称错误',
|
||||||
|
}],
|
||||||
|
})(<Input />)}
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
{/* <Form.Item label="brokerIdList" style={{ display: this.state.checked ? 'none' : '' }}>
|
||||||
|
{getFieldDecorator('brokerIdList', {
|
||||||
|
initialValue: formData.brokerIdList,
|
||||||
|
rules: [{ required: !this.state.checked, message: '请输入brokerIdList' }],
|
||||||
|
})(
|
||||||
|
<Select
|
||||||
|
mode="multiple"
|
||||||
|
{...searchProps}
|
||||||
|
>
|
||||||
|
{metadata.map((v, index) => (
|
||||||
|
<Select.Option
|
||||||
|
key={v.brokerId || v.key || index}
|
||||||
|
value={v.brokerId}
|
||||||
|
>
|
||||||
|
{v.host.length > 16 ?
|
||||||
|
<Tooltip placement="bottomLeft" title={v.host}> {v.host} </Tooltip>
|
||||||
|
: v.host}
|
||||||
|
</Select.Option>
|
||||||
|
))}
|
||||||
|
</Select>,
|
||||||
|
)}
|
||||||
|
|
||||||
|
</Form.Item>*/}
|
||||||
|
{/* <Form.Item label="regionId" style={{ display: this.state.checked ? '' : 'none' }} >
|
||||||
|
{getFieldDecorator('regionId', {
|
||||||
|
initialValue: formData.regionId,
|
||||||
|
rules: [{ required: this.state.checked, message: '请选择regionId' }],
|
||||||
|
})(
|
||||||
|
<Select {...searchProps}>
|
||||||
|
{regions.map((v, index) => (
|
||||||
|
<Select.Option
|
||||||
|
key={v.id || v.key || index}
|
||||||
|
value={v.id}
|
||||||
|
>
|
||||||
|
{v.name.length > 16 ?
|
||||||
|
<Tooltip placement="bottomLeft" title={v.name}> {v.name} </Tooltip>
|
||||||
|
: v.name}
|
||||||
|
</Select.Option>
|
||||||
|
))}
|
||||||
|
</Select>,
|
||||||
|
)}
|
||||||
|
</Form.Item> */}
|
||||||
|
</Form>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ConfirmDetailTopicFormWrapper = Form.create<IXFormProps>()(CustomForm);
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { admin } from 'store/admin';
|
import { admin } from 'store/admin';
|
||||||
import { notification, Modal, Form, Input, Switch, Select, Tooltip } from 'antd';
|
import { notification, Modal, Form, Input, Switch, Select, Tooltip, Radio } from 'antd';
|
||||||
import { IBrokersMetadata, IBrokersRegions, IExpand } from 'types/base-type';
|
import { IBrokersMetadata, IBrokersRegions, IExpand } from 'types/base-type';
|
||||||
import { searchProps } from 'constants/table';
|
import { searchProps } from 'constants/table';
|
||||||
import { expandPartition } from 'lib/api';
|
import { expandPartition } from 'lib/api';
|
||||||
@@ -89,14 +89,31 @@ class CustomForm extends React.Component<IXFormProps> {
|
|||||||
rules: [{ required: true, message: '请输入Topic名称' }],
|
rules: [{ required: true, message: '请输入Topic名称' }],
|
||||||
})(<Input disabled={true} placeholder="请输入Topic名称" />)}
|
})(<Input disabled={true} placeholder="请输入Topic名称" />)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
|
{/* 运维管控-topic信息-扩分区操作 */}
|
||||||
|
<Form.Item label="所属region" >
|
||||||
|
{getFieldDecorator('regionNameList', {
|
||||||
|
initialValue: admin.topicsBasic ? admin.topicsBasic.regionNameList : '',
|
||||||
|
rules: [{ required: true, message: '请输入所属region' }],
|
||||||
|
})(<Input disabled={true} />)}
|
||||||
|
</Form.Item>
|
||||||
|
{/* 运维管控-topic信息-扩分区操作 */}
|
||||||
|
|
||||||
<Form.Item label="分区数" >
|
<Form.Item label="分区数" >
|
||||||
{getFieldDecorator('partitionNum', {
|
{getFieldDecorator('partitionNum', {
|
||||||
rules: [{ required: true,
|
rules: [{
|
||||||
message: '请输入分区数' }],
|
required: true,
|
||||||
|
message: '请输入分区数',
|
||||||
|
}],
|
||||||
})(<Input placeholder="请输入分区数" />)}
|
})(<Input placeholder="请输入分区数" />)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={this.state.checked ? 'Region类型' : 'Borker类型'} >
|
<Form.Item label="类型">
|
||||||
<Switch onChange={(checked) => this.onSwitchChange(checked)} />
|
{/* <Form.Item label={this.state.checked ? 'Region类型' : 'Borker类型'} > */}
|
||||||
|
{/* <Switch onChange={(checked) => this.onSwitchChange(checked)} /> */}
|
||||||
|
<Radio.Group value={this.state.checked ? 'region' : 'broker'} onChange={(e) => { this.onSwitchChange(e.target.value === 'region' ? true : false); }}>
|
||||||
|
<Radio.Button value="region">Region类型</Radio.Button>
|
||||||
|
<Radio.Button value="broker">Borker类型</Radio.Button>
|
||||||
|
</Radio.Group>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="brokerIdList" style={{ display: this.state.checked ? 'none' : '' }}>
|
<Form.Item label="brokerIdList" style={{ display: this.state.checked ? 'none' : '' }}>
|
||||||
{getFieldDecorator('brokerIdList', {
|
{getFieldDecorator('brokerIdList', {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { Table, notification, Button, Modal, Input, Form, Select, message, Tooltip } from 'component/antd';
|
import { Table, notification, Button, Modal, Input, Form, Select, message, Tooltip, Icon, Spin } from 'component/antd';
|
||||||
import { IBrokersMetadata, IRebalance } from 'types/base-type';
|
import { IBrokersMetadata, IRebalance } from 'types/base-type';
|
||||||
import { admin } from 'store/admin';
|
import { admin } from 'store/admin';
|
||||||
import { implementRegions, rebalanceStatus } from 'lib/api';
|
import { implementRegions, rebalanceStatus } from 'lib/api';
|
||||||
@@ -27,6 +27,7 @@ class LeaderRebalanceModal extends React.Component<IXFormProps> {
|
|||||||
public state = {
|
public state = {
|
||||||
imVisible: false,
|
imVisible: false,
|
||||||
status: '',
|
status: '',
|
||||||
|
isExecutionBtn: false
|
||||||
};
|
};
|
||||||
|
|
||||||
public handleRebalanceCancel() {
|
public handleRebalanceCancel() {
|
||||||
@@ -48,6 +49,7 @@ class LeaderRebalanceModal extends React.Component<IXFormProps> {
|
|||||||
public handleSubmit = (e: any) => {
|
public handleSubmit = (e: any) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.props.form.validateFields((err: any, values: any) => {
|
this.props.form.validateFields((err: any, values: any) => {
|
||||||
|
values.brokerId && this.setState({ isExecutionBtn: true })
|
||||||
if (!err) {
|
if (!err) {
|
||||||
let params = {} as IRebalance;
|
let params = {} as IRebalance;
|
||||||
params = {
|
params = {
|
||||||
@@ -58,12 +60,19 @@ class LeaderRebalanceModal extends React.Component<IXFormProps> {
|
|||||||
topicName: '',
|
topicName: '',
|
||||||
};
|
};
|
||||||
implementRegions(params).then(data => {
|
implementRegions(params).then(data => {
|
||||||
message.success('获取成功');
|
// message.success('获取成功');
|
||||||
this.getStatus();
|
this.getStatus();
|
||||||
this.setState({
|
this.setState({
|
||||||
imVisible: true,
|
imVisible: true,
|
||||||
|
isExecutionBtn: false
|
||||||
});
|
});
|
||||||
|
}).catch((err) => {
|
||||||
|
message.error('获取失败')
|
||||||
|
this.setState({
|
||||||
|
imVisible: true,
|
||||||
|
isExecutionBtn: false
|
||||||
});
|
});
|
||||||
|
})
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -77,7 +86,7 @@ class LeaderRebalanceModal extends React.Component<IXFormProps> {
|
|||||||
|
|
||||||
public getStatus() {
|
public getStatus() {
|
||||||
rebalanceStatus(this.props.clusterId).then((data: any) => {
|
rebalanceStatus(this.props.clusterId).then((data: any) => {
|
||||||
message.success('状态更新成功');
|
// message.success('状态更新成功');
|
||||||
if (data.code === 30) { // code -1 未知 101 成功 30 运行中
|
if (data.code === 30) { // code -1 未知 101 成功 30 运行中
|
||||||
setTimeout(this.iTimer, 0);
|
setTimeout(this.iTimer, 0);
|
||||||
} else {
|
} else {
|
||||||
@@ -91,6 +100,8 @@ class LeaderRebalanceModal extends React.Component<IXFormProps> {
|
|||||||
public componentWillUnmount() {
|
public componentWillUnmount() {
|
||||||
clearInterval(this.timer);
|
clearInterval(this.timer);
|
||||||
}
|
}
|
||||||
|
// 执行加载图标
|
||||||
|
public antIcon = <Icon type="loading" style={{ fontSize: 12, color: '#cccccc' }} spin />
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
const { visible } = this.props;
|
const { visible } = this.props;
|
||||||
@@ -162,8 +173,9 @@ class LeaderRebalanceModal extends React.Component<IXFormProps> {
|
|||||||
htmlType="submit"
|
htmlType="submit"
|
||||||
type="primary"
|
type="primary"
|
||||||
className="implement-button"
|
className="implement-button"
|
||||||
|
disabled={this.state.isExecutionBtn}
|
||||||
>
|
>
|
||||||
执行
|
{this.state.isExecutionBtn ? (<span>执行中<Spin indicator={this.antIcon} size="small" /></span>) : '执行'}
|
||||||
</Button>,
|
</Button>,
|
||||||
)}
|
)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|||||||
@@ -287,6 +287,7 @@ export const addMigrationTask = () => {
|
|||||||
formData: {},
|
formData: {},
|
||||||
visible: true,
|
visible: true,
|
||||||
title: '新建集群任务',
|
title: '新建集群任务',
|
||||||
|
isWaitting: true,
|
||||||
onSubmit: (value: INewBulidEnums) => {
|
onSubmit: (value: INewBulidEnums) => {
|
||||||
value.kafkaPackageName = value.kafkafileNameMd5.split(',')[0];
|
value.kafkaPackageName = value.kafkafileNameMd5.split(',')[0];
|
||||||
value.kafkaPackageMd5 = value.kafkafileNameMd5.split(',')[1];
|
value.kafkaPackageMd5 = value.kafkafileNameMd5.split(',')[1];
|
||||||
@@ -294,10 +295,21 @@ export const addMigrationTask = () => {
|
|||||||
value.serverPropertiesMd5 = value.serverfileNameMd5.split(',')[1];
|
value.serverPropertiesMd5 = value.serverfileNameMd5.split(',')[1];
|
||||||
delete value.kafkafileNameMd5;
|
delete value.kafkafileNameMd5;
|
||||||
delete value.serverfileNameMd5;
|
delete value.serverfileNameMd5;
|
||||||
admin.addMigrationTask(value).then(data => {
|
return admin.addMigrationTask(value).then(data => {
|
||||||
notification.success({ message: '新建集群任务成功' });
|
notification.success({ message: '新建集群任务成功' });
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
onSubmitFaild: (err: any, ref: any, formData: any, formMap: any) => {
|
||||||
|
if (err.message === '主机列表错误,请检查主机列表') {
|
||||||
|
const hostList = ref.getFieldValue('hostList');
|
||||||
|
ref.setFields({
|
||||||
|
hostList: {
|
||||||
|
value: hostList,
|
||||||
|
errors: [new Error('主机列表错误,请检查主机列表')],
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
wrapper.open(xFormModal);
|
wrapper.open(xFormModal);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,12 +12,12 @@ const updateFormModal = (topicName?: string) => {
|
|||||||
const formMap = wrapper.xFormWrapper.formMap;
|
const formMap = wrapper.xFormWrapper.formMap;
|
||||||
const formData = wrapper.xFormWrapper.formData;
|
const formData = wrapper.xFormWrapper.formData;
|
||||||
if (topicName) {
|
if (topicName) {
|
||||||
formMap[5].options = expert.partitionIdMap[topicName]; // 3
|
formMap[2].options = expert.partitionIdMap[topicName]; // 3
|
||||||
formData.originalRetentionTime = transMSecondToHour(admin.topicsBasic.retentionTime);
|
formData.originalRetentionTime = transMSecondToHour(admin.topicsBasic.retentionTime);
|
||||||
} else {
|
} else {
|
||||||
formMap[1].options = expert.taskTopicMetadata;
|
formMap[1].options = expert.taskTopicMetadata;
|
||||||
formMap[3].options = admin.brokersMetadata; // 2
|
formMap[4].options = admin.brokersMetadata; // 2
|
||||||
formMap[4].options = admin.brokersRegions;
|
formMap[5].options = admin.brokersRegions;
|
||||||
}
|
}
|
||||||
// tslint:disable-next-line:no-unused-expression
|
// tslint:disable-next-line:no-unused-expression
|
||||||
wrapper.ref && wrapper.ref.updateFormMap$(formMap, wrapper.xFormWrapper.formData, !!topicName, ['partitionIdList']);
|
wrapper.ref && wrapper.ref.updateFormMap$(formMap, wrapper.xFormWrapper.formData, !!topicName, ['partitionIdList']);
|
||||||
@@ -25,11 +25,11 @@ const updateFormModal = (topicName?: string) => {
|
|||||||
|
|
||||||
const updateInputModal = (status?: string) => {
|
const updateInputModal = (status?: string) => {
|
||||||
const formMap = wrapper.xFormWrapper.formMap;
|
const formMap = wrapper.xFormWrapper.formMap;
|
||||||
formMap[3].invisible = status === 'region';
|
formMap[4].invisible = status === 'region';
|
||||||
formMap[4].invisible = status !== 'region';
|
formMap[5].invisible = status !== 'region';
|
||||||
|
|
||||||
formMap[3].rules = [{required: status !== 'region'}];
|
formMap[4].rules = [{required: status !== 'region'}];
|
||||||
formMap[4].rules = [{required: status === 'region'}];
|
formMap[5].rules = [{required: status === 'region'}];
|
||||||
// tslint:disable-next-line:no-unused-expression
|
// tslint:disable-next-line:no-unused-expression
|
||||||
wrapper.ref && wrapper.ref.updateFormMap$(formMap, wrapper.xFormWrapper.formData);
|
wrapper.ref && wrapper.ref.updateFormMap$(formMap, wrapper.xFormWrapper.formData);
|
||||||
};
|
};
|
||||||
@@ -81,6 +81,19 @@ export const createMigrationTasks = () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'partitionIdList',
|
||||||
|
label: '分区ID',
|
||||||
|
type: 'select',
|
||||||
|
defaultValue: [] as any,
|
||||||
|
rules: [{
|
||||||
|
required: false,
|
||||||
|
}],
|
||||||
|
attrs: {
|
||||||
|
mode: 'tags',
|
||||||
|
placeholder: '请选择PartitionIdList',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: 'species',
|
key: 'species',
|
||||||
label: '类型',
|
label: '类型',
|
||||||
@@ -110,10 +123,10 @@ export const createMigrationTasks = () => {
|
|||||||
defaultValue: [] as any,
|
defaultValue: [] as any,
|
||||||
invisible: false,
|
invisible: false,
|
||||||
options: admin.brokersMetadata,
|
options: admin.brokersMetadata,
|
||||||
rules: [{ required: true, message: '请选择Broker' }],
|
rules: [{ required: true, message: '请选择目标Broker,Broker数量需大于等于副本数量' }],
|
||||||
attrs: {
|
attrs: {
|
||||||
mode: 'multiple',
|
mode: 'multiple',
|
||||||
placeholder: '请选择Broker',
|
placeholder: '请选择目标Broker,Broker数量需大于等于副本数量',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -123,24 +136,12 @@ export const createMigrationTasks = () => {
|
|||||||
defaultValue: [] as any,
|
defaultValue: [] as any,
|
||||||
invisible: true,
|
invisible: true,
|
||||||
options: admin.brokersRegions,
|
options: admin.brokersRegions,
|
||||||
rules: [{ required: false, message: '请选择Region' }],
|
rules: [{ required: false, message: '请选择目标Region' }],
|
||||||
attrs: {
|
attrs: {
|
||||||
placeholder: '请选择Region',
|
placeholder: '请选择目标Region',
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'partitionIdList',
|
|
||||||
label: '分区ID',
|
|
||||||
type: 'select',
|
|
||||||
defaultValue: [] as any,
|
|
||||||
rules: [{
|
|
||||||
required: false,
|
|
||||||
}],
|
|
||||||
attrs: {
|
|
||||||
mode: 'tags',
|
|
||||||
placeholder: '请选择PartitionIdList',
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
key: 'beginTime',
|
key: 'beginTime',
|
||||||
label: '计划开始时间',
|
label: '计划开始时间',
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ export const showApplyModal = (record?: IUser) => {
|
|||||||
key: 'username',
|
key: 'username',
|
||||||
label: '用户名',
|
label: '用户名',
|
||||||
rules: [{ required: true, message: '请输入用户名' }],
|
rules: [{ required: true, message: '请输入用户名' }],
|
||||||
|
attrs: {
|
||||||
|
disabled: record ? true : false
|
||||||
|
}
|
||||||
}, {
|
}, {
|
||||||
key: 'role',
|
key: 'role',
|
||||||
label: '角色',
|
label: '角色',
|
||||||
|
|||||||
@@ -1,10 +1,15 @@
|
|||||||
|
import * as React from 'react';
|
||||||
import { notification } from 'component/antd';
|
import { notification } from 'component/antd';
|
||||||
import { IUploadFile, IConfigure } from 'types/base-type';
|
import { IUploadFile, IConfigure } from 'types/base-type';
|
||||||
import { version } from 'store/version';
|
import { version } from 'store/version';
|
||||||
import { admin } from 'store/admin';
|
import { admin } from 'store/admin';
|
||||||
import { wrapper } from 'store';
|
import { wrapper } from 'store';
|
||||||
import { computeChecksumMd5 } from 'lib/utils';
|
import { computeChecksumMd5 } from 'lib/utils';
|
||||||
|
import format2json from 'format-to-json';
|
||||||
|
|
||||||
|
interface ISearchAndFilterState {
|
||||||
|
[filter: string]: boolean | string | number | any[];
|
||||||
|
}
|
||||||
const handleSelectChange = (e: number) => {
|
const handleSelectChange = (e: number) => {
|
||||||
version.setAcceptFileType(e);
|
version.setAcceptFileType(e);
|
||||||
updateFormModal(e);
|
updateFormModal(e);
|
||||||
@@ -150,7 +155,11 @@ export const showModifyModal = (record: IUploadFile) => {
|
|||||||
wrapper.open(xFormModal);
|
wrapper.open(xFormModal);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const showConfigureModal = (record?: IConfigure) => {
|
export const showConfigureModal = async (record?: IConfigure) => {
|
||||||
|
if (record) {
|
||||||
|
const result:any = await format2json(record.configValue);
|
||||||
|
record.configValue = result.result;
|
||||||
|
}
|
||||||
const xFormModal = {
|
const xFormModal = {
|
||||||
formMap: [
|
formMap: [
|
||||||
{
|
{
|
||||||
@@ -163,8 +172,11 @@ export const showConfigureModal = (record?: IConfigure) => {
|
|||||||
}, {
|
}, {
|
||||||
key: 'configValue',
|
key: 'configValue',
|
||||||
label: '配置值',
|
label: '配置值',
|
||||||
type: 'text_area',
|
type: 'monaco_editor',
|
||||||
rules: [{ required: true, message: '请输入配置值' }],
|
rules: [{
|
||||||
|
required: true,
|
||||||
|
message: '请输入配置值',
|
||||||
|
}],
|
||||||
}, {
|
}, {
|
||||||
key: 'configDescription',
|
key: 'configDescription',
|
||||||
label: '备注',
|
label: '备注',
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ export const showEditModal = (record?: IAppItem, from?: string, isDisabled?: boo
|
|||||||
defaultValue: record && record.name || '',
|
defaultValue: record && record.name || '',
|
||||||
rules: [{
|
rules: [{
|
||||||
required: isDisabled ? false : true,
|
required: isDisabled ? false : true,
|
||||||
message: '请输入不得超过64个字符',
|
message: '应用名称只支持中文、字母、数字、下划线、短划线,长度限制在3-64字符',
|
||||||
pattern: /^.{1,64}$/,
|
pattern: /[\u4e00-\u9fa5_a-zA-Z0-9_-]{3,64}/,
|
||||||
}],
|
}],
|
||||||
attrs: { disabled: isDisabled },
|
attrs: { disabled: isDisabled },
|
||||||
}, {
|
}, {
|
||||||
@@ -85,7 +85,9 @@ export const showEditModal = (record?: IAppItem, from?: string, isDisabled?: boo
|
|||||||
],
|
],
|
||||||
formData: record,
|
formData: record,
|
||||||
visible: true,
|
visible: true,
|
||||||
title: `${isDisabled ? '详情' : record ? '编辑' : '应用申请'}`,
|
title: isDisabled ? '详情' : record ? '编辑' : <div><span>应用申请</span><a className='applicationDocument' href="###" target='_blank'>应用申请文档</a></div>,
|
||||||
|
// customRenderElement: isDisabled ? '' : record ? '' : <span className="tips">集群资源充足时,预计1分钟自动审批通过</span>,
|
||||||
|
isWaitting: true,
|
||||||
onSubmit: (value: IAppItem) => {
|
onSubmit: (value: IAppItem) => {
|
||||||
if (isDisabled) {
|
if (isDisabled) {
|
||||||
return;
|
return;
|
||||||
@@ -98,6 +100,17 @@ export const showEditModal = (record?: IAppItem, from?: string, isDisabled?: boo
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
onSubmitFaild: (err: any, ref: any, formData: any, formMap: any) => {
|
||||||
|
if (err.message == '资源已经存在') {
|
||||||
|
const topic = ref.getFieldValue('name');
|
||||||
|
ref.setFields({
|
||||||
|
name: {
|
||||||
|
value: topic,
|
||||||
|
errors: [new Error('该应用名称已存在')],
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
wrapper.open(xFormModal);
|
wrapper.open(xFormModal);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -116,11 +116,11 @@ export class CancelTopicPermission extends React.Component {
|
|||||||
type: 'check_box',
|
type: 'check_box',
|
||||||
defaultValue: accessStatus,
|
defaultValue: accessStatus,
|
||||||
options: [{
|
options: [{
|
||||||
label: '消费权限',
|
label: '取消消费权限',
|
||||||
value: '1',
|
value: '1',
|
||||||
disabled: send,
|
disabled: send,
|
||||||
}, {
|
}, {
|
||||||
label: '发送权限',
|
label: '取消发送权限',
|
||||||
value: '2',
|
value: '2',
|
||||||
disabled: consume,
|
disabled: consume,
|
||||||
}],
|
}],
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { Table, Modal, Tooltip, Icon, message, notification } from 'component/antd';
|
import { Table, Modal, Tooltip, Icon, message, notification, Alert } from 'component/antd';
|
||||||
import { getApplyOnlineColumns } from 'container/topic/config';
|
import { getApplyOnlineColumns } from 'container/topic/config';
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
import { modal } from 'store/modal';
|
import { modal } from 'store/modal';
|
||||||
@@ -59,7 +59,7 @@ export class ConnectTopicList extends React.Component {
|
|||||||
maskClosable={false}
|
maskClosable={false}
|
||||||
onCancel={this.handleCancel}
|
onCancel={this.handleCancel}
|
||||||
onOk={this.handleSubmit}
|
onOk={this.handleSubmit}
|
||||||
okText="下线"
|
okText="确认"
|
||||||
cancelText="取消"
|
cancelText="取消"
|
||||||
okButtonProps={{ disabled: topic.connectLoading || !!topic.connectionInfo.length }}
|
okButtonProps={{ disabled: topic.connectLoading || !!topic.connectionInfo.length }}
|
||||||
width={700}
|
width={700}
|
||||||
@@ -74,6 +74,7 @@ export class ConnectTopicList extends React.Component {
|
|||||||
pagination={false}
|
pagination={false}
|
||||||
bordered={true}
|
bordered={true}
|
||||||
/>
|
/>
|
||||||
|
<Alert message="如若有连接信息,则表示资源正处于使用中,禁止下线操作。如需下线,烦请关闭连接信息中的Kafka发送/消费客户端后再进行下线。" type="error" showIcon />
|
||||||
</Modal>
|
</Modal>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { Table, Modal, Tooltip, Icon, message, notification } from 'component/antd';
|
import { Table, Modal, Tooltip, Icon, message, notification, Alert } from 'component/antd';
|
||||||
import { app } from 'store/app';
|
import { app } from 'store/app';
|
||||||
import { getApplyOnlineColumns } from 'container/topic/config';
|
import { getApplyOnlineColumns } from 'container/topic/config';
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
@@ -55,7 +55,7 @@ export class ConnectAppList extends React.Component {
|
|||||||
maskClosable={false}
|
maskClosable={false}
|
||||||
onCancel={this.handleCancel}
|
onCancel={this.handleCancel}
|
||||||
onOk={this.handleSubmit}
|
onOk={this.handleSubmit}
|
||||||
okText="下线"
|
okText="确认"
|
||||||
cancelText="取消"
|
cancelText="取消"
|
||||||
okButtonProps={{ disabled: app.connectLoading || !!app.appsConnections.length }}
|
okButtonProps={{ disabled: app.connectLoading || !!app.appsConnections.length }}
|
||||||
width={700}
|
width={700}
|
||||||
@@ -70,6 +70,7 @@ export class ConnectAppList extends React.Component {
|
|||||||
pagination={false}
|
pagination={false}
|
||||||
bordered={true}
|
bordered={true}
|
||||||
/>
|
/>
|
||||||
|
<Alert message="如若有连接信息,则表示资源正处于使用中,禁止下线操作。如需下线,烦请关闭连接信息中的Kafka发送/消费客户端后再进行下线。" type="error" showIcon />
|
||||||
</Modal>
|
</Modal>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ export class OfflineClusterModal extends React.Component {
|
|||||||
maskClosable={false}
|
maskClosable={false}
|
||||||
onCancel={this.handleCancel}
|
onCancel={this.handleCancel}
|
||||||
onOk={this.handleSubmit}
|
onOk={this.handleSubmit}
|
||||||
okText="下线"
|
okText="确认"
|
||||||
cancelText="取消"
|
cancelText="取消"
|
||||||
okButtonProps={{ disabled: cluster.filterLoading || !!cluster.clusterMetaTopics.length }}
|
okButtonProps={{ disabled: cluster.filterLoading || !!cluster.clusterMetaTopics.length }}
|
||||||
width={700}
|
width={700}
|
||||||
|
|||||||
@@ -57,25 +57,26 @@ export const showApprovalModal = (info: IOrderInfo, status: number, from?: strin
|
|||||||
}],
|
}],
|
||||||
}, {
|
}, {
|
||||||
key: 'retentionTime',
|
key: 'retentionTime',
|
||||||
label: '保存时间',
|
label: '保存时间(/小时)',
|
||||||
defaultValue: '48',
|
defaultValue: '12',
|
||||||
type: 'select',
|
type: 'input_number',
|
||||||
options: [{
|
// options: [{
|
||||||
label: '12小时',
|
// label: '12小时',
|
||||||
value: '12',
|
// value: '12',
|
||||||
}, {
|
// }, {
|
||||||
label: '24小时',
|
// label: '24小时',
|
||||||
value: '24',
|
// value: '24',
|
||||||
}, {
|
// }, {
|
||||||
label: '48小时',
|
// label: '48小时',
|
||||||
value: '48',
|
// value: '48',
|
||||||
}, {
|
// }, {
|
||||||
label: '72小时',
|
// label: '72小时',
|
||||||
value: '72',
|
// value: '72',
|
||||||
}],
|
// }],
|
||||||
rules: [{
|
rules: [{
|
||||||
required: true,
|
required: true,
|
||||||
message: '请选择',
|
message: '请输入大于12小于999的整数',
|
||||||
|
pattern: /^([1-9]{1}[0-9]{2})$|^([2-9]{1}[0-9]{1})$|^(1[2-9]{1})$/,
|
||||||
}],
|
}],
|
||||||
}, {
|
}, {
|
||||||
key: 'species',
|
key: 'species',
|
||||||
@@ -242,11 +243,15 @@ export const showApprovalModal = (info: IOrderInfo, status: number, from?: strin
|
|||||||
if ((type === 2 || type === 12) && status === 1) { // 通过配额 12分区
|
if ((type === 2 || type === 12) && status === 1) { // 通过配额 12分区
|
||||||
xFormWrapper.formMap.splice(1, 0, ...quotaFormMap);
|
xFormWrapper.formMap.splice(1, 0, ...quotaFormMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
wrapper.open(xFormWrapper);
|
wrapper.open(xFormWrapper);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const renderOrderOpModal = (selectedRowKeys: IBaseOrder[], status: number) => {
|
export const renderOrderOpModal = (selectedRowKeys: IBaseOrder[], status: number, rowsCallBack?: any) => {
|
||||||
|
if (modal.actionAfterClose === 'close') {
|
||||||
|
// tslint:disable-next-line: no-unused-expression
|
||||||
|
rowsCallBack && rowsCallBack.onChange([], []);
|
||||||
|
order.setSelectedRows([]);
|
||||||
|
}
|
||||||
const orderIdList = selectedRowKeys.map((ele: IBaseOrder) => {
|
const orderIdList = selectedRowKeys.map((ele: IBaseOrder) => {
|
||||||
return ele.id;
|
return ele.id;
|
||||||
});
|
});
|
||||||
@@ -283,6 +288,7 @@ export const renderOrderOpModal = (selectedRowKeys: IBaseOrder[], status: number
|
|||||||
order.batchApprovalOrders(params).then(data => {
|
order.batchApprovalOrders(params).then(data => {
|
||||||
modal.setAction('close');
|
modal.setAction('close');
|
||||||
modal.showOrderOpResult();
|
modal.showOrderOpResult();
|
||||||
|
order.setSelectedRows();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -293,6 +299,7 @@ export const RenderOrderOpResult = () => {
|
|||||||
const handleOk = () => {
|
const handleOk = () => {
|
||||||
order.getApplyOrderList(0);
|
order.getApplyOrderList(0);
|
||||||
order.getApprovalList(0);
|
order.getApprovalList(0);
|
||||||
|
order.setSelectedRows();
|
||||||
modal.close();
|
modal.close();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ export class RenderOrderOpResult extends React.Component {
|
|||||||
maskClosable={false}
|
maskClosable={false}
|
||||||
onCancel={this.handleCancel}
|
onCancel={this.handleCancel}
|
||||||
onOk={this.handleSubmit}
|
onOk={this.handleSubmit}
|
||||||
okText="下线"
|
okText="确认"
|
||||||
cancelText="取消"
|
cancelText="取消"
|
||||||
okButtonProps={{ disabled: topic.connectLoading || !!topic.connectionInfo.length }}
|
okButtonProps={{ disabled: topic.connectLoading || !!topic.connectionInfo.length }}
|
||||||
width={700}
|
width={700}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export const applyTopic = () => {
|
|||||||
formMap: [
|
formMap: [
|
||||||
{
|
{
|
||||||
key: 'clusterId',
|
key: 'clusterId',
|
||||||
label: '所属集群:',
|
label: '所属逻辑集群:',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
options: cluster.clusterData,
|
options: cluster.clusterData,
|
||||||
rules: [{ required: true, message: '请选择' }],
|
rules: [{ required: true, message: '请选择' }],
|
||||||
@@ -36,8 +36,8 @@ export const applyTopic = () => {
|
|||||||
addonBefore: region.currentRegion === 'us' || region.currentRegion === 'ru' ? `${region.currentRegion}01_` : '',
|
addonBefore: region.currentRegion === 'us' || region.currentRegion === 'ru' ? `${region.currentRegion}01_` : '',
|
||||||
},
|
},
|
||||||
rules: [
|
rules: [
|
||||||
{ required: true },
|
|
||||||
{
|
{
|
||||||
|
required: true,
|
||||||
pattern: /^[-\w]{3,128}$/,
|
pattern: /^[-\w]{3,128}$/,
|
||||||
message: '只能包含字母、数字、下划线(_)和短划线(-),长度限制在3-128字符之间',
|
message: '只能包含字母、数字、下划线(_)和短划线(-),长度限制在3-128字符之间',
|
||||||
},
|
},
|
||||||
@@ -90,6 +90,8 @@ export const applyTopic = () => {
|
|||||||
visible: true,
|
visible: true,
|
||||||
title: '申请Topic',
|
title: '申请Topic',
|
||||||
okText: '确认',
|
okText: '确认',
|
||||||
|
// customRenderElement: <span className="tips">集群资源充足时,预计1分钟自动审批通过</span>,
|
||||||
|
isWaitting: true,
|
||||||
onSubmit: (value: any) => {
|
onSubmit: (value: any) => {
|
||||||
value.topicName = region.currentRegion === 'us' || region.currentRegion === 'ru' ?
|
value.topicName = region.currentRegion === 'us' || region.currentRegion === 'ru' ?
|
||||||
`${region.currentRegion}01_` + value.topicName : value.topicName;
|
`${region.currentRegion}01_` + value.topicName : value.topicName;
|
||||||
@@ -102,11 +104,21 @@ export const applyTopic = () => {
|
|||||||
description: value.description,
|
description: value.description,
|
||||||
extensions: JSON.stringify(params),
|
extensions: JSON.stringify(params),
|
||||||
};
|
};
|
||||||
topic.applyTopic(quotaParams).then(data => {
|
return topic.applyTopic(quotaParams).then(data => {
|
||||||
notification.success({ message: '申请Topic成功' });
|
|
||||||
window.location.href = `${urlPrefix}/user/order-detail/?orderId=${data.id}®ion=${region.currentRegion}`;
|
window.location.href = `${urlPrefix}/user/order-detail/?orderId=${data.id}®ion=${region.currentRegion}`;
|
||||||
});
|
})
|
||||||
},
|
},
|
||||||
|
onSubmitFaild: (err: any, ref: any, formData: any, formMap: any) => {
|
||||||
|
if (err.message === 'topic already existed') {
|
||||||
|
const topic = ref.getFieldValue('topicName');
|
||||||
|
ref.setFields({
|
||||||
|
topicName: {
|
||||||
|
value: topic,
|
||||||
|
errors: [new Error('该topic名称已存在')],
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
wrapper.open(xFormModal);
|
wrapper.open(xFormModal);
|
||||||
};
|
};
|
||||||
@@ -170,7 +182,7 @@ export const showApplyQuatoModal = (item: ITopic | IAppsIdInfo, record: IQuotaQu
|
|||||||
formMap: [
|
formMap: [
|
||||||
{
|
{
|
||||||
key: 'clusterName',
|
key: 'clusterName',
|
||||||
label: '集群名称',
|
label: '逻辑集群名称',
|
||||||
rules: [{ required: true, message: '' }],
|
rules: [{ required: true, message: '' }],
|
||||||
attrs: { disabled: true },
|
attrs: { disabled: true },
|
||||||
invisible: !item.hasOwnProperty('clusterName'),
|
invisible: !item.hasOwnProperty('clusterName'),
|
||||||
@@ -187,7 +199,7 @@ export const showApplyQuatoModal = (item: ITopic | IAppsIdInfo, record: IQuotaQu
|
|||||||
attrs: { disabled: true },
|
attrs: { disabled: true },
|
||||||
}, {
|
}, {
|
||||||
key: 'produceQuota',
|
key: 'produceQuota',
|
||||||
label: '发送数据速率',
|
label: '申请发送数据速率',
|
||||||
attrs: {
|
attrs: {
|
||||||
disabled: isProduce,
|
disabled: isProduce,
|
||||||
placeholder: '请输入',
|
placeholder: '请输入',
|
||||||
@@ -199,7 +211,7 @@ export const showApplyQuatoModal = (item: ITopic | IAppsIdInfo, record: IQuotaQu
|
|||||||
}],
|
}],
|
||||||
}, {
|
}, {
|
||||||
key: 'consumeQuota',
|
key: 'consumeQuota',
|
||||||
label: '消费数据速率',
|
label: '申请消费数据速率',
|
||||||
attrs: {
|
attrs: {
|
||||||
disabled: isConsume,
|
disabled: isConsume,
|
||||||
placeholder: '请输入',
|
placeholder: '请输入',
|
||||||
@@ -282,10 +294,10 @@ export const showTopicApplyQuatoModal = (item: ITopic) => {
|
|||||||
formMap: [
|
formMap: [
|
||||||
{
|
{
|
||||||
key: 'clusterName',
|
key: 'clusterName',
|
||||||
label: '集群名称',
|
label: '逻辑集群名称',
|
||||||
rules: [{ required: true, message: '' }],
|
rules: [{ required: true, message: '' }],
|
||||||
attrs: { disabled: true },
|
attrs: { disabled: true },
|
||||||
invisible: !item.hasOwnProperty('clusterName'),
|
// invisible: !item.hasOwnProperty('clusterName'),
|
||||||
}, {
|
}, {
|
||||||
key: 'topicName',
|
key: 'topicName',
|
||||||
label: 'Topic名称',
|
label: 'Topic名称',
|
||||||
@@ -318,7 +330,7 @@ export const showTopicApplyQuatoModal = (item: ITopic) => {
|
|||||||
},
|
},
|
||||||
}, { // 0 无权限 1可读 2可写 3 可读写 4可读写可管理
|
}, { // 0 无权限 1可读 2可写 3 可读写 4可读写可管理
|
||||||
key: 'produceQuota',
|
key: 'produceQuota',
|
||||||
label: '发送数据速率',
|
label: '申请发送数据速率',
|
||||||
attrs: {
|
attrs: {
|
||||||
disabled: false,
|
disabled: false,
|
||||||
placeholder: '请输入',
|
placeholder: '请输入',
|
||||||
@@ -330,7 +342,7 @@ export const showTopicApplyQuatoModal = (item: ITopic) => {
|
|||||||
}],
|
}],
|
||||||
}, {
|
}, {
|
||||||
key: 'consumeQuota',
|
key: 'consumeQuota',
|
||||||
label: '消费数据速率',
|
label: '申请消费数据速率',
|
||||||
attrs: {
|
attrs: {
|
||||||
disabled: false,
|
disabled: false,
|
||||||
placeholder: '请输入',
|
placeholder: '请输入',
|
||||||
@@ -704,14 +716,14 @@ export const applyExpandModal = (item: ITopic) => {
|
|||||||
rules: [{ required: true }],
|
rules: [{ required: true }],
|
||||||
}, {
|
}, {
|
||||||
key: 'needIncrPartitionNum',
|
key: 'needIncrPartitionNum',
|
||||||
label: '分区',
|
label: '申请增加分区数量',
|
||||||
type: 'input_number',
|
type: 'input_number',
|
||||||
rules: [{
|
rules: [{
|
||||||
required: true,
|
required: true,
|
||||||
message: '请输入0-100正整数',
|
message: '请输入0-1000正整数',
|
||||||
pattern: /^((?!0)\d{1,2}|100)$/,
|
pattern: /^((?!0)\d{1,3}|1000)$/,
|
||||||
}],
|
}],
|
||||||
attrs: { placeholder: '0-100正整数' },
|
attrs: { placeholder: '0-1000正整数' },
|
||||||
renderExtraElement: () => <div className="form-tip mr--10">分区标准为3MB/s一个,请按需申请</div>,
|
renderExtraElement: () => <div className="form-tip mr--10">分区标准为3MB/s一个,请按需申请</div>,
|
||||||
}, {
|
}, {
|
||||||
key: 'description',
|
key: 'description',
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ export class NetWorkFlow extends React.Component<any> {
|
|||||||
<div className="chart-box-0">
|
<div className="chart-box-0">
|
||||||
<div className="chart-title">
|
<div className="chart-title">
|
||||||
<span className="action-button">历史流量</span>
|
<span className="action-button">历史流量</span>
|
||||||
<a href={indexUrl} target="_blank">指标说明</a>
|
<a href={indexUrl.indexUrl} target="_blank">指标说明</a>
|
||||||
</div>
|
</div>
|
||||||
<Divider />
|
<Divider />
|
||||||
<ChartWithDatePicker
|
<ChartWithDatePicker
|
||||||
@@ -74,7 +74,7 @@ export const renderTrafficTable = (updateRealStatus: any, Element: React.Compone
|
|||||||
<div className="traffic-header">
|
<div className="traffic-header">
|
||||||
<span>
|
<span>
|
||||||
<span className="action-button">实时流量</span>
|
<span className="action-button">实时流量</span>
|
||||||
<a href={indexUrl} target="_blank">指标说明</a>
|
<a href={indexUrl.indexUrl} target="_blank">指标说明</a>
|
||||||
</span>
|
</span>
|
||||||
<span className="k-abs" onClick={updateRealStatus}>
|
<span className="k-abs" onClick={updateRealStatus}>
|
||||||
<i className="k-icon-shuaxin didi-theme mr-5" />
|
<i className="k-icon-shuaxin didi-theme mr-5" />
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ interface IFilterParams {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface ISearchAndFilterState {
|
interface ISearchAndFilterState {
|
||||||
[filter: string]: boolean | string | number;
|
[filter: string]: boolean | string | number | any[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SearchAndFilterContainer extends React.Component<any, ISearchAndFilterState> {
|
export class SearchAndFilterContainer extends React.Component<any, ISearchAndFilterState> {
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ export const applyQuotaQuery = (item: ITopic) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const applyTopicQuotaQuery = async (item: ITopic) => {
|
export const applyTopicQuotaQuery = async (item: ITopic) => {
|
||||||
|
console.log(item)
|
||||||
await app.getTopicAppQuota(item.clusterId, item.topicName);
|
await app.getTopicAppQuota(item.clusterId, item.topicName);
|
||||||
await showTopicApplyQuatoModal(item);
|
await showTopicApplyQuatoModal(item);
|
||||||
};
|
};
|
||||||
@@ -141,10 +142,8 @@ export const getAllTopicColumns = (urlPrefix: string) => {
|
|||||||
<Tooltip placement="bottomLeft" title={record.topicName} >
|
<Tooltip placement="bottomLeft" title={record.topicName} >
|
||||||
<a
|
<a
|
||||||
// tslint:disable-next-line:max-line-length
|
// tslint:disable-next-line:max-line-length
|
||||||
href={`${urlPrefix}/topic/topic-detail?clusterId=${record.clusterId}&topic=${record.topicName}®ion=${region.currentRegion}`}
|
href={`${urlPrefix}/topic/topic-detail?clusterId=${record.clusterId}&topic=${record.topicName}®ion=${region.currentRegion}&needAuth=${record.needAuth}&clusterName=${record.clusterName}`}
|
||||||
>
|
>{text}</a>
|
||||||
{text}
|
|
||||||
</a>
|
|
||||||
</Tooltip>);
|
</Tooltip>);
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Input } from 'component/antd';
|
import { Input } from 'component/antd';
|
||||||
import { region } from 'store';
|
import { region } from 'store';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
import { indexUrl } from 'constants/strategy';
|
||||||
|
|
||||||
interface IPeakFlowProps {
|
interface IPeakFlowProps {
|
||||||
value?: any;
|
value?: any;
|
||||||
@@ -23,7 +24,7 @@ export class PeakFlowInput extends React.Component<IPeakFlowProps> {
|
|||||||
预估费用:{region.currentRegion === 'cn' ? value * 40 : value * 45}元/月,
|
预估费用:{region.currentRegion === 'cn' ? value * 40 : value * 45}元/月,
|
||||||
<a
|
<a
|
||||||
// tslint:disable-next-line:max-line-length
|
// tslint:disable-next-line:max-line-length
|
||||||
href="https://github.com/didi/kafka-manager"
|
href={indexUrl.indexUrl}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>kafka计价方式
|
>kafka计价方式
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import 'styles/table-filter.less';
|
|||||||
@observer
|
@observer
|
||||||
export class AllTopic extends SearchAndFilterContainer {
|
export class AllTopic extends SearchAndFilterContainer {
|
||||||
public state = {
|
public state = {
|
||||||
searchKey: '',
|
searchKey: ''
|
||||||
};
|
};
|
||||||
|
|
||||||
public componentDidMount() {
|
public componentDidMount() {
|
||||||
|
|||||||
@@ -3,13 +3,16 @@ import './index.less';
|
|||||||
import Url from 'lib/url-parser';
|
import Url from 'lib/url-parser';
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
import { topic, IAppsIdInfo } from 'store/topic';
|
import { topic, IAppsIdInfo } from 'store/topic';
|
||||||
|
import { ITopic } from 'types/base-type';
|
||||||
import { Table, Tooltip } from 'component/antd';
|
import { Table, Tooltip } from 'component/antd';
|
||||||
import { SearchAndFilterContainer } from 'container/search-filter';
|
import { SearchAndFilterContainer } from 'container/search-filter';
|
||||||
import { IQuotaQuery } from 'types/base-type';
|
import { IQuotaQuery } from 'types/base-type';
|
||||||
import { showApplyQuatoModal } from 'container/modal';
|
import { showApplyQuatoModal } from 'container/modal';
|
||||||
import { pagination, cellStyle } from 'constants/table';
|
import { pagination, cellStyle } from 'constants/table';
|
||||||
import { transBToMB } from 'lib/utils';
|
import { transBToMB } from 'lib/utils';
|
||||||
|
import { topicStatusMap } from 'constants/status-map';
|
||||||
|
import { tableFilter } from 'lib/utils';
|
||||||
|
import { users } from 'store/users';
|
||||||
@observer
|
@observer
|
||||||
export class AppIdInformation extends SearchAndFilterContainer {
|
export class AppIdInformation extends SearchAndFilterContainer {
|
||||||
public clusterId: number;
|
public clusterId: number;
|
||||||
@@ -26,7 +29,20 @@ export class AppIdInformation extends SearchAndFilterContainer {
|
|||||||
this.topicName = url.search.topic;
|
this.topicName = url.search.topic;
|
||||||
}
|
}
|
||||||
|
|
||||||
public renderColumns = () => {
|
public renderColumns = (data: any) => {
|
||||||
|
const statusColumn = Object.assign({
|
||||||
|
title: '权限',
|
||||||
|
dataIndex: 'access',
|
||||||
|
key: 'access',
|
||||||
|
filters: tableFilter<ITopic>(data, 'access', topicStatusMap),
|
||||||
|
onFilter: (text: number, record: ITopic) => record.access === text,
|
||||||
|
render: (val: number) => (
|
||||||
|
<div className={val === 0 ? '' : 'success'}>
|
||||||
|
{topicStatusMap[val] || ''}
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
}, this.renderColumnsFilter('filterStatus')) as any;
|
||||||
|
|
||||||
return [{
|
return [{
|
||||||
title: '应用Id',
|
title: '应用Id',
|
||||||
key: 'appId',
|
key: 'appId',
|
||||||
@@ -53,7 +69,9 @@ export class AppIdInformation extends SearchAndFilterContainer {
|
|||||||
{text}
|
{text}
|
||||||
</Tooltip>);
|
</Tooltip>);
|
||||||
},
|
},
|
||||||
}, {
|
},
|
||||||
|
statusColumn,
|
||||||
|
{
|
||||||
title: '生产配额(MB/s)',
|
title: '生产配额(MB/s)',
|
||||||
key: 'produceQuota',
|
key: 'produceQuota',
|
||||||
dataIndex: 'produceQuota',
|
dataIndex: 'produceQuota',
|
||||||
@@ -77,8 +95,13 @@ export class AppIdInformation extends SearchAndFilterContainer {
|
|||||||
title: '操作',
|
title: '操作',
|
||||||
key: 'action',
|
key: 'action',
|
||||||
dataIndex: 'action',
|
dataIndex: 'action',
|
||||||
render: (val: string, item: IAppsIdInfo) =>
|
render: (val: string, item: IAppsIdInfo) => {
|
||||||
<a onClick={() => this.applyQuotaQuery(item)}>申请配额</a>,
|
const role = users.currentUser.role;
|
||||||
|
const showEditBtn = (role == 1 || role == 2) || (item && item.appPrincipals.includes(users.currentUser.username));
|
||||||
|
return (
|
||||||
|
showEditBtn ? <a onClick={() => this.applyQuotaQuery(item)}>申请配额</a> : '--'
|
||||||
|
)
|
||||||
|
}
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,7 +139,7 @@ export class AppIdInformation extends SearchAndFilterContainer {
|
|||||||
<div style={searchKey ? { minHeight: 700 } : null}>
|
<div style={searchKey ? { minHeight: 700 } : null}>
|
||||||
<Table
|
<Table
|
||||||
loading={topic.loading}
|
loading={topic.loading}
|
||||||
columns={this.renderColumns()}
|
columns={this.renderColumns(this.getData(topic.appsIdInfo))}
|
||||||
table-Layout="fixed"
|
table-Layout="fixed"
|
||||||
dataSource={this.getData(topic.appsIdInfo)}
|
dataSource={this.getData(topic.appsIdInfo)}
|
||||||
rowKey="key"
|
rowKey="key"
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import './index.less';
|
|||||||
import Url from 'lib/url-parser';
|
import Url from 'lib/url-parser';
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
import { topic, IRealConsumeDetail, ITopicBaseInfo, IRealTimeTraffic } from 'store/topic';
|
import { topic, IRealConsumeDetail, ITopicBaseInfo, IRealTimeTraffic } from 'store/topic';
|
||||||
import { Table, Tooltip, Icon, PageHeader, Descriptions, Spin } from 'component/antd';
|
import { Table, Tooltip, Icon, PageHeader, Descriptions, Spin, Switch } from 'component/antd';
|
||||||
import { ILabelValue } from 'types/base-type';
|
import { ILabelValue } from 'types/base-type';
|
||||||
import { copyString, transMSecondToHour } from 'lib/utils';
|
import { copyString, transMSecondToHour } from 'lib/utils';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
@@ -19,12 +19,14 @@ interface IInfoProps {
|
|||||||
export class BaseInformation extends React.Component<IInfoProps> {
|
export class BaseInformation extends React.Component<IInfoProps> {
|
||||||
public clusterId: number;
|
public clusterId: number;
|
||||||
public topicName: string;
|
public topicName: string;
|
||||||
|
public percentile: string;
|
||||||
|
|
||||||
constructor(props: any) {
|
constructor(props: any) {
|
||||||
super(props);
|
super(props);
|
||||||
const url = Url();
|
const url = Url();
|
||||||
this.clusterId = Number(url.search.clusterId);
|
this.clusterId = Number(url.search.clusterId);
|
||||||
this.topicName = url.search.topic;
|
this.topicName = url.search.topic;
|
||||||
|
this.percentile = "75thPercentile";
|
||||||
}
|
}
|
||||||
|
|
||||||
public updateRealStatus = () => {
|
public updateRealStatus = () => {
|
||||||
@@ -32,7 +34,11 @@ export class BaseInformation extends React.Component<IInfoProps> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public updateConsumeStatus = () => {
|
public updateConsumeStatus = () => {
|
||||||
topic.getRealConsume(this.clusterId, this.topicName);
|
topic.getRealConsume(this.clusterId, this.topicName, this.percentile);
|
||||||
|
}
|
||||||
|
public onSwitch = (val: boolean) => {
|
||||||
|
this.percentile = val ? '99thPercentile' : "75thPercentile"
|
||||||
|
topic.getRealConsume(this.clusterId, this.topicName, this.percentile);
|
||||||
}
|
}
|
||||||
|
|
||||||
public fillBaseInfo() {
|
public fillBaseInfo() {
|
||||||
@@ -63,8 +69,11 @@ export class BaseInformation extends React.Component<IInfoProps> {
|
|||||||
label: '压缩格式',
|
label: '压缩格式',
|
||||||
value: baseInfo.topicCodeC,
|
value: baseInfo.topicCodeC,
|
||||||
}, {
|
}, {
|
||||||
label: '集群ID',
|
label: '所属物理集群ID',
|
||||||
value: baseInfo.clusterId,
|
value: baseInfo.clusterId,
|
||||||
|
}, {
|
||||||
|
label: '所属region',
|
||||||
|
value: baseInfo.regionNameList && baseInfo.regionNameList.join(','),
|
||||||
}];
|
}];
|
||||||
const infoHide: ILabelValue[] = [{
|
const infoHide: ILabelValue[] = [{
|
||||||
label: 'Bootstrap Severs',
|
label: 'Bootstrap Severs',
|
||||||
@@ -195,7 +204,11 @@ export class BaseInformation extends React.Component<IInfoProps> {
|
|||||||
<div className="traffic-header">
|
<div className="traffic-header">
|
||||||
<span>
|
<span>
|
||||||
<span className="action-button">实时耗时</span>
|
<span className="action-button">实时耗时</span>
|
||||||
<a href={indexUrl} target="_blank">指标说明</a>
|
<a href={indexUrl.indexUrl} target="_blank">指标说明</a>
|
||||||
|
</span>
|
||||||
|
<span className="switch">
|
||||||
|
<span>默认展示75分位数据,点击开启99分位数据</span>
|
||||||
|
<Switch checkedChildren="开启" unCheckedChildren="关闭" onChange={this.onSwitch} />
|
||||||
</span>
|
</span>
|
||||||
<span className="k-abs" onClick={this.updateConsumeStatus}>
|
<span className="k-abs" onClick={this.updateConsumeStatus}>
|
||||||
<i className="k-icon-shuaxin didi-theme mr-5" />
|
<i className="k-icon-shuaxin didi-theme mr-5" />
|
||||||
@@ -217,7 +230,7 @@ export class BaseInformation extends React.Component<IInfoProps> {
|
|||||||
|
|
||||||
public componentDidMount() {
|
public componentDidMount() {
|
||||||
topic.getRealTimeTraffic(this.clusterId, this.topicName);
|
topic.getRealTimeTraffic(this.clusterId, this.topicName);
|
||||||
topic.getRealConsume(this.clusterId, this.topicName);
|
topic.getRealConsume(this.clusterId, this.topicName, this.percentile);
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
|
|||||||
@@ -69,9 +69,9 @@ export class NetWorkFlow extends React.Component<any> {
|
|||||||
>
|
>
|
||||||
{topic.appInfo.map((item: IAppsIdInfo) => (
|
{topic.appInfo.map((item: IAppsIdInfo) => (
|
||||||
<Select.Option key={item.appId} value={item.appId}>
|
<Select.Option key={item.appId} value={item.appId}>
|
||||||
{item.appName.length > 16 ?
|
{item.appName && item.appName.length > 16 ?
|
||||||
<Tooltip placement="bottomLeft" title={item.appName}> {item.appName} </Tooltip>
|
<Tooltip placement="bottomLeft" title={item.appName}> {item.appName} </Tooltip>
|
||||||
: item.appName}
|
: item.appName || ''}
|
||||||
</Select.Option>
|
</Select.Option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
|
|||||||
@@ -92,8 +92,8 @@ export class ConnectInformation extends SearchAndFilterContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public componentDidMount() {
|
public componentDidMount() {
|
||||||
const appId = this.props.baseInfo.appId;
|
// const appId = this.props.baseInfo.appId;
|
||||||
topic.getConnectionInfo(this.clusterId, this.topicName, appId);
|
topic.getConnectionInfo(this.clusterId, this.topicName, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
|
|||||||
@@ -215,3 +215,13 @@
|
|||||||
.is-show {
|
.is-show {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.switch {
|
||||||
|
position: absolute;
|
||||||
|
right: 70px;
|
||||||
|
span {
|
||||||
|
line-height: 20px !important;
|
||||||
|
font-size: 12px !important;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ import { PartitionInformation } from './partition-information';
|
|||||||
import { BrokersInformation } from './brokers-information';
|
import { BrokersInformation } from './brokers-information';
|
||||||
import { AppIdInformation } from './appid-information';
|
import { AppIdInformation } from './appid-information';
|
||||||
import { BillInformation } from './bill-information';
|
import { BillInformation } from './bill-information';
|
||||||
|
import { showAllPermissionModal } from 'container/modal';
|
||||||
import { IXFormWrapper, ITopic } from 'types/base-type';
|
import { IXFormWrapper, ITopic } from 'types/base-type';
|
||||||
import { getTopicCompile, getTopicSampling } from 'lib/api';
|
import { getTopicCompile, getTopicSampling } from 'lib/api';
|
||||||
import { copyString } from 'lib/utils';
|
import { copyString } from 'lib/utils';
|
||||||
@@ -22,17 +23,22 @@ import { users } from 'store/users';
|
|||||||
import { urlPrefix } from 'constants/left-menu';
|
import { urlPrefix } from 'constants/left-menu';
|
||||||
import { handlePageBack } from 'lib/utils';
|
import { handlePageBack } from 'lib/utils';
|
||||||
import Url from 'lib/url-parser';
|
import Url from 'lib/url-parser';
|
||||||
|
import router from 'routers/router';
|
||||||
const { TabPane } = Tabs;
|
const { TabPane } = Tabs;
|
||||||
|
import { app } from 'store/app';
|
||||||
|
|
||||||
interface IInfoData {
|
interface IInfoData {
|
||||||
value: string;
|
value: string;
|
||||||
|
history: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class TopicDetail extends React.Component {
|
export class TopicDetail extends React.Component<any> {
|
||||||
public clusterId: number;
|
public clusterId: number;
|
||||||
public topicName: string;
|
public topicName: string;
|
||||||
public isPhysicalTrue: string;
|
public isPhysicalTrue: string;
|
||||||
|
public needAuth: string;
|
||||||
|
public clusterName: string;
|
||||||
|
|
||||||
public state = {
|
public state = {
|
||||||
drawerVisible: false,
|
drawerVisible: false,
|
||||||
@@ -47,6 +53,8 @@ export class TopicDetail extends React.Component {
|
|||||||
super(props);
|
super(props);
|
||||||
const url = Url();
|
const url = Url();
|
||||||
this.clusterId = Number(url.search.clusterId);
|
this.clusterId = Number(url.search.clusterId);
|
||||||
|
this.needAuth = url.search.needAuth;
|
||||||
|
this.clusterName = url.search.clusterName;
|
||||||
this.topicName = url.search.topic;
|
this.topicName = url.search.topic;
|
||||||
const isPhysical = Url().search.hasOwnProperty('isPhysicalClusterId');
|
const isPhysical = Url().search.hasOwnProperty('isPhysicalClusterId');
|
||||||
this.isPhysicalTrue = isPhysical ? '&isPhysicalClusterId=true' : '';
|
this.isPhysicalTrue = isPhysical ? '&isPhysicalClusterId=true' : '';
|
||||||
@@ -110,11 +118,11 @@ export class TopicDetail extends React.Component {
|
|||||||
const formMap = [
|
const formMap = [
|
||||||
{
|
{
|
||||||
key: 'maxMsgNum',
|
key: 'maxMsgNum',
|
||||||
label: '最大采样数据条数',
|
label: '最大采样条数',
|
||||||
type: 'input_number',
|
type: 'input_number',
|
||||||
rules: [{
|
rules: [{
|
||||||
required: true,
|
required: true,
|
||||||
message: '请输入最大采样数据条数',
|
message: '请输入最大采样条数',
|
||||||
}],
|
}],
|
||||||
attrs: {
|
attrs: {
|
||||||
max: 100,
|
max: 100,
|
||||||
@@ -122,32 +130,32 @@ export class TopicDetail extends React.Component {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'timeout',
|
key: 'timeout',
|
||||||
label: '最大采样时间',
|
label: '采样超时时间(ms)',
|
||||||
type: 'input_number',
|
type: 'input_number',
|
||||||
rules: [{
|
rules: [{
|
||||||
required: true,
|
required: true,
|
||||||
message: '请输入最大采样时间',
|
message: '请输入采样超时时间(ms)',
|
||||||
}],
|
}],
|
||||||
attrs: {
|
attrs: {
|
||||||
max: 300000,
|
max: 500000,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'partitionId',
|
key: 'partitionId',
|
||||||
label: '分区号',
|
label: '采样分区号',
|
||||||
type: 'input_number',
|
type: 'input_number',
|
||||||
rules: [{
|
rules: [{
|
||||||
required: false,
|
required: false,
|
||||||
message: '请输入分区号',
|
message: '请输入采样分区号',
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'offset',
|
key: 'offset',
|
||||||
label: '偏移量',
|
label: '采样offset位置',
|
||||||
type: 'input_number',
|
type: 'input_number',
|
||||||
rules: [{
|
rules: [{
|
||||||
required: false,
|
required: false,
|
||||||
message: '请输入偏移量',
|
message: '请输入采样offset位置',
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -170,7 +178,7 @@ export class TopicDetail extends React.Component {
|
|||||||
] as IFormItem[];
|
] as IFormItem[];
|
||||||
const formData = {
|
const formData = {
|
||||||
maxMsgNum: 1,
|
maxMsgNum: 1,
|
||||||
timeout: 3000,
|
timeout: 5000,
|
||||||
};
|
};
|
||||||
const { infoVisible } = this.state;
|
const { infoVisible } = this.state;
|
||||||
return (
|
return (
|
||||||
@@ -312,11 +320,13 @@ export class TopicDetail extends React.Component {
|
|||||||
public render() {
|
public render() {
|
||||||
const role = users.currentUser.role;
|
const role = users.currentUser.role;
|
||||||
const baseInfo = topic.baseInfo as ITopicBaseInfo;
|
const baseInfo = topic.baseInfo as ITopicBaseInfo;
|
||||||
const showEditBtn = topic.topicBusiness && topic.topicBusiness.principals.includes(users.currentUser.username);
|
const showEditBtn = (role == 1 || role == 2) || (topic.topicBusiness && topic.topicBusiness.principals.includes(users.currentUser.username));
|
||||||
const topicRecord = {
|
const topicRecord = {
|
||||||
clusterId: this.clusterId,
|
clusterId: this.clusterId,
|
||||||
topicName: this.topicName,
|
topicName: this.topicName,
|
||||||
|
clusterName: this.clusterName
|
||||||
} as ITopic;
|
} as ITopic;
|
||||||
|
app.getAppList();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -329,10 +339,12 @@ export class TopicDetail extends React.Component {
|
|||||||
title={this.topicName || ''}
|
title={this.topicName || ''}
|
||||||
extra={
|
extra={
|
||||||
<>
|
<>
|
||||||
|
{this.needAuth == "true" && <Button key="0" type="primary" onClick={() => showAllPermissionModal(topicRecord)} >申请权限</Button>}
|
||||||
<Button key="1" type="primary" onClick={() => applyTopicQuotaQuery(topicRecord)} >申请配额</Button>
|
<Button key="1" type="primary" onClick={() => applyTopicQuotaQuery(topicRecord)} >申请配额</Button>
|
||||||
<Button key="2" type="primary" onClick={() => applyExpandModal(topicRecord)} >申请分区</Button>
|
<Button key="2" type="primary" onClick={() => applyExpandModal(topicRecord)} >申请分区</Button>
|
||||||
<Button key="3" type="primary" onClick={this.showDrawer.bind(this)} >采样</Button>
|
<Button key="3" type="primary" onClick={() => this.props.history.push(`/alarm/add`)} >新建告警规则</Button>
|
||||||
{showEditBtn && <Button key="4" onClick={() => this.compileDetails()} type="primary">编辑</Button>}
|
<Button key="4" type="primary" onClick={this.showDrawer.bind(this)} >采样</Button>
|
||||||
|
{showEditBtn && <Button key="5" onClick={() => this.compileDetails()} type="primary">编辑</Button>}
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ export class StatusChart extends React.Component {
|
|||||||
<div className="chart-box-0">
|
<div className="chart-box-0">
|
||||||
<div className="chart-title">
|
<div className="chart-title">
|
||||||
<span className="action-button">历史流量</span>
|
<span className="action-button">历史流量</span>
|
||||||
<a href={indexUrl} target="_blank">指标说明</a>
|
<a href={indexUrl.indexUrl} target="_blank">指标说明</a>
|
||||||
</div>
|
</div>
|
||||||
<Divider className="chart-divider" />
|
<Divider className="chart-divider" />
|
||||||
<NetWorkFlow
|
<NetWorkFlow
|
||||||
@@ -61,7 +61,7 @@ export class StatusChart extends React.Component {
|
|||||||
<div className="chart-box-0">
|
<div className="chart-box-0">
|
||||||
<div className="chart-title">
|
<div className="chart-title">
|
||||||
<span className="action-button">历史耗时信息</span>
|
<span className="action-button">历史耗时信息</span>
|
||||||
<a href={indexUrl} target="_blank">指标说明</a>
|
<a href={indexUrl.indexUrl} target="_blank">指标说明</a>
|
||||||
</div>
|
</div>
|
||||||
<Divider className="chart-divider" />
|
<Divider className="chart-divider" />
|
||||||
<NetWorkFlow
|
<NetWorkFlow
|
||||||
|
|||||||
@@ -2,12 +2,13 @@ import { observer } from 'mobx-react';
|
|||||||
import { order } from 'store/order';
|
import { order } from 'store/order';
|
||||||
import { OrderList } from './order-list';
|
import { OrderList } from './order-list';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { Table, Spin, Alert } from 'component/antd';
|
import { Table, Spin, Alert, Button } from 'component/antd';
|
||||||
import { modal } from 'store/modal';
|
import { modal } from 'store/modal';
|
||||||
import { pagination } from 'constants/table';
|
import { pagination } from 'constants/table';
|
||||||
import { renderOrderOpModal } from 'container/modal/order';
|
import { renderOrderOpModal } from 'container/modal/order';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import { IBaseOrder } from 'types/base-type';
|
import { IBaseOrder } from 'types/base-type';
|
||||||
|
// import { } from 'antd/es/radio';
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class MyApproval extends OrderList {
|
export class MyApproval extends OrderList {
|
||||||
@@ -15,29 +16,36 @@ export class MyApproval extends OrderList {
|
|||||||
public static defaultProps = {
|
public static defaultProps = {
|
||||||
type: 'approval',
|
type: 'approval',
|
||||||
};
|
};
|
||||||
|
|
||||||
public unpendinngRef: HTMLDivElement = null;
|
public unpendinngRef: HTMLDivElement = null;
|
||||||
|
|
||||||
public onSelectChange = {
|
public onSelectChange = {
|
||||||
onChange: (selectedRowKeys: string[], selectedRows: []) => {
|
onChange: (selectedRowKeys: string[], selectedRows: []) => {
|
||||||
const num = selectedRows.length;
|
const num = selectedRows.length;
|
||||||
ReactDOM.render(
|
order.setSelectedRows(selectedRows);
|
||||||
selectedRows.length ? (
|
// console.log(selectedRows);
|
||||||
<>
|
// ReactDOM.render(
|
||||||
<Alert
|
// selectedRows.length ? (
|
||||||
type="warning"
|
// <>
|
||||||
message={`已选择 ${num} 项 `}
|
// <Alert
|
||||||
showIcon={true}
|
// type="warning"
|
||||||
closable={false}
|
// message={`已选择 ${num} 项 `}
|
||||||
/>
|
// showIcon={true}
|
||||||
<span className="k-coll-btn" >
|
// closable={false}
|
||||||
<a className="btn-right" onClick={renderOrderOpModal.bind(this, selectedRows, 1)}>通过</a>
|
// />
|
||||||
<a onClick={renderOrderOpModal.bind(this, selectedRows, 2)}>驳回</a>
|
// <span className="k-coll-btn" >
|
||||||
</span>
|
// <a className="btn-right" onClick={renderOrderOpModal.bind(this, selectedRows, 1)}>通过</a>
|
||||||
</>) : null,
|
// <a onClick={renderOrderOpModal.bind(this, selectedRows, 2)}>驳回</a>
|
||||||
this.unpendinngRef,
|
// </span>
|
||||||
);
|
// </>
|
||||||
|
// ) : null,
|
||||||
|
// this.unpendinngRef,
|
||||||
|
// );
|
||||||
},
|
},
|
||||||
|
// getCheckboxProps: (record: any) => {
|
||||||
|
// return {
|
||||||
|
// disabled: record.type === 0 || record.type === 12 || record.type === 1,
|
||||||
|
// name: record.name,
|
||||||
|
// };
|
||||||
|
// },
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(defaultProps: any) {
|
constructor(defaultProps: any) {
|
||||||
@@ -50,13 +58,33 @@ export class MyApproval extends OrderList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public renderTableList(data: IBaseOrder[]) {
|
public renderTableList(data: IBaseOrder[]) {
|
||||||
const { currentTab } = this.state;
|
const { currentTab, selectedRows } = this.state;
|
||||||
if (modal.actionAfterClose === 'close') {
|
// if (modal.actionAfterClose === 'close') {
|
||||||
this.onSelectChange.onChange([], []);
|
// this.onSelectChange.onChange([], []);
|
||||||
}
|
// }
|
||||||
return (
|
return (
|
||||||
<Spin spinning={order.loading}>
|
<Spin spinning={order.loading}>
|
||||||
<div className="k-collect" ref={(id) => this.unpendinngRef = id} />
|
<div style={{ marginBottom: '0' }} className="k-collect" ref={(id) => this.unpendinngRef = id} />
|
||||||
|
{/* 我的审批 业务逻辑修改 问题:state无法定义 */}
|
||||||
|
<div style={{ paddingBottom: '10px' }}>
|
||||||
|
<Button
|
||||||
|
style={{ margin: '0 5px' }}
|
||||||
|
disabled={order.selectedRows.filter(item => item.type === 0 || item.type === 12).length > 0 || order.selectedRows.length < 1 ? true : false}
|
||||||
|
onClick={() => renderOrderOpModal(order.selectedRows, 1, this.onSelectChange)}
|
||||||
|
>
|
||||||
|
批量通过
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
disabled={order.selectedRows.length > 0 ? false : true}
|
||||||
|
onClick={() => renderOrderOpModal(order.selectedRows, 2, this.onSelectChange)}
|
||||||
|
>
|
||||||
|
批量驳回
|
||||||
|
</Button>
|
||||||
|
<span style={{ color: '#a1a0a0', fontSize: '10px', display: 'inline-block', margin: '0 10px' }}>
|
||||||
|
Topic申请、分区申请无法批量通过
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{/* 我的审批 业务逻辑修改 */}
|
||||||
<Table
|
<Table
|
||||||
rowKey="id"
|
rowKey="id"
|
||||||
columns={this.getColumns(data)}
|
columns={this.getColumns(data)}
|
||||||
|
|||||||
@@ -21,21 +21,20 @@ interface IProps {
|
|||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class OrderList extends SearchAndFilterContainer {
|
export class OrderList extends SearchAndFilterContainer {
|
||||||
|
|
||||||
public orderType: string;
|
public orderType: string;
|
||||||
|
public state: { [propname: string]: any } = {
|
||||||
public state = {
|
|
||||||
searchKey: '',
|
searchKey: '',
|
||||||
currentTab: '0',
|
currentTab: '0',
|
||||||
filterTypeVisible: false,
|
filterTypeVisible: false,
|
||||||
filterStatusVisible: false,
|
filterStatusVisible: false,
|
||||||
|
selectedRows: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
public currentItem = {} as IBaseOrder;
|
public currentItem = {} as IBaseOrder;
|
||||||
|
|
||||||
constructor(props: IProps) {
|
constructor(props: IProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.orderType = props.type;
|
this.orderType = props.type;
|
||||||
|
// this.state.b;
|
||||||
}
|
}
|
||||||
|
|
||||||
public cancelOrder(record: IBaseOrder) {
|
public cancelOrder(record: IBaseOrder) {
|
||||||
|
|||||||
@@ -94,8 +94,8 @@ export const getRealTimeTraffic = (clusterId: number, topicName: string) => {
|
|||||||
return fetch(`/normal/${clusterId}/topics/${topicName}/metrics`);
|
return fetch(`/normal/${clusterId}/topics/${topicName}/metrics`);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getRealConsume = (clusterId: number, topicName: string) => {
|
export const getRealConsume = (clusterId: number, topicName: string, percentile: string) => {
|
||||||
return fetch(`/normal/${clusterId}/topics/${topicName}/request-time`);
|
return fetch(`/normal/${clusterId}/topics/${topicName}/request-time?percentile=${percentile}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getConnectionInfo = (clusterId: number, topicName: string, appId?: string) => {
|
export const getConnectionInfo = (clusterId: number, topicName: string, appId?: string) => {
|
||||||
|
|||||||
@@ -76,7 +76,8 @@ export const getPieChartOption = (data: ILabelValue[], legend: string[]) => {
|
|||||||
},
|
},
|
||||||
emphasis: {
|
emphasis: {
|
||||||
label: {
|
label: {
|
||||||
show: true,
|
// show: true,
|
||||||
|
show: false,
|
||||||
fontSize: '16',
|
fontSize: '16',
|
||||||
fontWeight: 'bold',
|
fontWeight: 'bold',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import * as ReactDOM from 'react-dom';
|
|||||||
import { Provider } from 'mobx-react';
|
import { Provider } from 'mobx-react';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import Router from './router';
|
import Router from './router';
|
||||||
|
import 'styles/style.less';
|
||||||
|
|
||||||
const renderApp = () => {
|
const renderApp = () => {
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
|
|||||||
@@ -107,3 +107,10 @@ html, body, .router-nav {
|
|||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.applicationDocument {
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -597,7 +597,9 @@ class Admin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getTopicsBasicInfo(clusterId: number, topicName: string) {
|
public getTopicsBasicInfo(clusterId: number, topicName: string) {
|
||||||
return getTopicsBasicInfo(clusterId, topicName).then(this.setTopicsBasicInfo);
|
return getTopicsBasicInfo(clusterId, topicName).then(data => {
|
||||||
|
return this.setTopicsBasicInfo(data);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public getTasksKafkaFiles(clusterId?: any) {
|
public getTasksKafkaFiles(clusterId?: any) {
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ class Order {
|
|||||||
@observable
|
@observable
|
||||||
public loading: boolean = false;
|
public loading: boolean = false;
|
||||||
|
|
||||||
|
@observable
|
||||||
|
public selectedRows: any[] = [];
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
public orderList: IBaseOrder[] = [];
|
public orderList: IBaseOrder[] = [];
|
||||||
|
|
||||||
@@ -55,6 +58,15 @@ class Order {
|
|||||||
this.loading = value;
|
this.loading = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action.bound
|
||||||
|
public setSelectedRows(rows?: any[]) {
|
||||||
|
if (rows) {
|
||||||
|
this.selectedRows = rows;
|
||||||
|
} else {
|
||||||
|
this.selectedRows = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@action.bound
|
@action.bound
|
||||||
public setOrderList(data: IBaseOrder[]) {
|
public setOrderList(data: IBaseOrder[]) {
|
||||||
this.orderList = data;
|
this.orderList = data;
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ class RegionCenter {
|
|||||||
@observable
|
@observable
|
||||||
public regionIdcList: IRegionIdcs[] = [
|
public regionIdcList: IRegionIdcs[] = [
|
||||||
{ name: '国内', idc: 'cn' },
|
{ name: '国内', idc: 'cn' },
|
||||||
{ name: '美东', idc: 'us' },
|
// { name: '美东', idc: 'us' },
|
||||||
{ name: '俄罗斯', idc: 'ru' },
|
// { name: '俄罗斯', idc: 'ru' },
|
||||||
];
|
];
|
||||||
|
|
||||||
@action.bound
|
@action.bound
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ export interface ITopicBaseInfo {
|
|||||||
score: number;
|
score: number;
|
||||||
topicCodeC: string;
|
topicCodeC: string;
|
||||||
physicalClusterId: number;
|
physicalClusterId: number;
|
||||||
|
percentile: string;
|
||||||
|
regionNameList: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IRealTimeTraffic {
|
export interface IRealTimeTraffic {
|
||||||
@@ -488,9 +490,9 @@ class Topic {
|
|||||||
return getRealTimeTraffic(clusterId, topicName).then(this.setRealTimeTraffic);
|
return getRealTimeTraffic(clusterId, topicName).then(this.setRealTimeTraffic);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getRealConsume(clusterId: number, topicName: string) {
|
public getRealConsume(clusterId: number, topicName: string, percentile: string) {
|
||||||
this.setConsumeLoading(true);
|
this.setConsumeLoading(true);
|
||||||
return getRealConsume(clusterId, topicName).then(this.setRealConsume);
|
return getRealConsume(clusterId, topicName, percentile).then(this.setRealConsume);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getConnectionInfo(clusterId: number, topicName: string, appId?: string) {
|
public getConnectionInfo(clusterId: number, topicName: string, appId?: string) {
|
||||||
|
|||||||
@@ -44,11 +44,10 @@ export class Version {
|
|||||||
|
|
||||||
@action.bound
|
@action.bound
|
||||||
public setFileList(data: IUploadFile[]) {
|
public setFileList(data: IUploadFile[]) {
|
||||||
|
|
||||||
this.fileList = (data || []).map((item, index) => {
|
this.fileList = (data || []).map((item, index) => {
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
configType: this.acceptFileMap[item.fileType],
|
configType: this.acceptFileMap[item.fileType] || '',
|
||||||
key: index,
|
key: index,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ class Wrapper {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@action.bound
|
@action.bound
|
||||||
public setXFormWrapper(xFormWrapper: IXFormWrapper) {
|
public setXFormWrapper(xFormWrapper: IXFormWrapper) {
|
||||||
this.xFormWrapper = xFormWrapper;
|
this.xFormWrapper = xFormWrapper;
|
||||||
|
|||||||
15
kafka-manager-console/src/styles/style.less
Normal file
15
kafka-manager-console/src/styles/style.less
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
.ant-spin-blur .ant-table-content {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.ant-alert-error {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
.isSHowApp {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.isHideApp {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.tips {
|
||||||
|
margin-left: 48px;
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
.content-container {
|
.content-container {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
min-width: 760px;
|
||||||
.table-operation {
|
.table-operation {
|
||||||
a {
|
a {
|
||||||
color: @primary-color;
|
color: @primary-color;
|
||||||
|
|||||||
@@ -537,9 +537,10 @@ export interface IUtils {
|
|||||||
|
|
||||||
export interface IXFormWrapper {
|
export interface IXFormWrapper {
|
||||||
type?: string;
|
type?: string;
|
||||||
title: string;
|
title: string | JSX.Element;
|
||||||
onSubmit: (result: any) => any;
|
onSubmit: (result: any) => any;
|
||||||
onCancel?: () => any;
|
onCancel?: () => any;
|
||||||
|
onChange?: (result: any) => any;
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
onChangeVisible?: (visible: boolean) => any;
|
onChangeVisible?: (visible: boolean) => any;
|
||||||
formMap?: any[];
|
formMap?: any[];
|
||||||
@@ -552,6 +553,7 @@ export interface IXFormWrapper {
|
|||||||
noform?: boolean;
|
noform?: boolean;
|
||||||
nofooter?: boolean;
|
nofooter?: boolean;
|
||||||
isWaitting?: boolean;
|
isWaitting?: boolean;
|
||||||
|
onSubmitFaild?: (err: any, ref: any, formData: any, formMap: any) => any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IBaseOrder extends IBase {
|
export interface IBaseOrder extends IBase {
|
||||||
@@ -608,9 +610,11 @@ export interface IBasicInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IClusterTopics {
|
export interface IClusterTopics {
|
||||||
|
regionNameList: any;
|
||||||
appId: string;
|
appId: string;
|
||||||
appName: string;
|
appName: string;
|
||||||
byteIn: number;
|
byteIn: number;
|
||||||
|
byteOut: number;
|
||||||
clusterId: number;
|
clusterId: number;
|
||||||
description: string;
|
description: string;
|
||||||
partitionNum: number;
|
partitionNum: number;
|
||||||
@@ -916,6 +920,7 @@ export interface INewLogical {
|
|||||||
mode: number;
|
mode: number;
|
||||||
name: string;
|
name: string;
|
||||||
logicalClusterName?: string;
|
logicalClusterName?: string;
|
||||||
|
logicalClusterEName?: string;
|
||||||
regionIdList: number[];
|
regionIdList: number[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -935,6 +940,7 @@ export interface ITaskManage {
|
|||||||
clusterId: number;
|
clusterId: number;
|
||||||
clusterName: string;
|
clusterName: string;
|
||||||
gmtCreate: number;
|
gmtCreate: number;
|
||||||
|
createTime: number;
|
||||||
operator: string;
|
operator: string;
|
||||||
status: number;
|
status: number;
|
||||||
taskId: number;
|
taskId: number;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ const path = require('path')
|
|||||||
const isProd = process.env.NODE_ENV === 'production';
|
const isProd = process.env.NODE_ENV === 'production';
|
||||||
const outPath = path.resolve('../kafka-manager-web/src/main/resources/templates');
|
const outPath = path.resolve('../kafka-manager-web/src/main/resources/templates');
|
||||||
const filename = isProd ? '[name].[contenthash]' : '[name]';
|
const filename = isProd ? '[name].[contenthash]' : '[name]';
|
||||||
|
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
|
||||||
let publicPath = '/';
|
let publicPath = '/';
|
||||||
|
|
||||||
const plugins = [
|
const plugins = [
|
||||||
@@ -17,6 +17,7 @@ const plugins = [
|
|||||||
template: './src/routers/index.htm',
|
template: './src/routers/index.htm',
|
||||||
favicon: './src/assets/image/logo.ico'
|
favicon: './src/assets/image/logo.ico'
|
||||||
}),
|
}),
|
||||||
|
new MonacoWebpackPlugin()
|
||||||
];
|
];
|
||||||
|
|
||||||
if (isProd) {
|
if (isProd) {
|
||||||
@@ -85,7 +86,18 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
test: /\.(ttf)$/i,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: 'url-loader',
|
||||||
|
options: {
|
||||||
|
limit: 8192,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
optimization: {
|
optimization: {
|
||||||
@@ -118,7 +130,9 @@ module.exports = {
|
|||||||
historyApiFallback: true,
|
historyApiFallback: true,
|
||||||
proxy: {
|
proxy: {
|
||||||
'/api/v1/': {
|
'/api/v1/': {
|
||||||
target: 'http://127.0.0.1:8080',
|
// target: 'http://127.0.0.1:8080',
|
||||||
|
target: 'http://10.179.37.199:8008',
|
||||||
|
// target: 'http://99.11.45.164:8888',
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ public class LogicalClusterMetadataManager {
|
|||||||
|
|
||||||
Long logicalClusterId = logicalClusterIdMap.get(topicName);
|
Long logicalClusterId = logicalClusterIdMap.get(topicName);
|
||||||
if (ValidateUtils.isNull(logicalClusterId)) {
|
if (ValidateUtils.isNull(logicalClusterId)) {
|
||||||
|
LOGGER.debug("class=LogicalClusterMetadataManager||method=getTopicLogicalCluster||topicName={}||msg=logicalClusterId is null!",topicName);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return LOGICAL_CLUSTER_MAP.get(logicalClusterId);
|
return LOGICAL_CLUSTER_MAP.get(logicalClusterId);
|
||||||
@@ -107,6 +108,7 @@ public class LogicalClusterMetadataManager {
|
|||||||
|
|
||||||
public Long getPhysicalClusterId(Long logicalClusterId) {
|
public Long getPhysicalClusterId(Long logicalClusterId) {
|
||||||
if (ValidateUtils.isNull(logicalClusterId)) {
|
if (ValidateUtils.isNull(logicalClusterId)) {
|
||||||
|
LOGGER.debug("class=LogicalClusterMetadataManager||method=getPhysicalClusterId||msg=logicalClusterId is null!");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (!LOADED.get()) {
|
if (!LOADED.get()) {
|
||||||
@@ -114,6 +116,7 @@ public class LogicalClusterMetadataManager {
|
|||||||
}
|
}
|
||||||
LogicalClusterDO logicalClusterDO = LOGICAL_CLUSTER_MAP.get(logicalClusterId);
|
LogicalClusterDO logicalClusterDO = LOGICAL_CLUSTER_MAP.get(logicalClusterId);
|
||||||
if (ValidateUtils.isNull(logicalClusterDO)) {
|
if (ValidateUtils.isNull(logicalClusterDO)) {
|
||||||
|
LOGGER.debug("class=LogicalClusterMetadataManager||method=getPhysicalClusterId||logicalClusterId={}||msg=logicalClusterDO is null!",logicalClusterId);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return logicalClusterDO.getClusterId();
|
return logicalClusterDO.getClusterId();
|
||||||
@@ -124,6 +127,7 @@ public class LogicalClusterMetadataManager {
|
|||||||
return clusterId;
|
return clusterId;
|
||||||
}
|
}
|
||||||
if (ValidateUtils.isNull(clusterId)) {
|
if (ValidateUtils.isNull(clusterId)) {
|
||||||
|
LOGGER.warn("class=LogicalClusterMetadataManager||method=getPhysicalClusterId||isPhysicalClusterId={}||msg=clusterId is null!",isPhysicalClusterId);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (!LOADED.get()) {
|
if (!LOADED.get()) {
|
||||||
@@ -131,6 +135,7 @@ public class LogicalClusterMetadataManager {
|
|||||||
}
|
}
|
||||||
LogicalClusterDO logicalClusterDO = LOGICAL_CLUSTER_MAP.get(clusterId);
|
LogicalClusterDO logicalClusterDO = LOGICAL_CLUSTER_MAP.get(clusterId);
|
||||||
if (ValidateUtils.isNull(logicalClusterDO)) {
|
if (ValidateUtils.isNull(logicalClusterDO)) {
|
||||||
|
LOGGER.debug("class=LogicalClusterMetadataManager||method=getPhysicalClusterId||clusterId={}||msg=logicalClusterDO is null!",clusterId);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return logicalClusterDO.getClusterId();
|
return logicalClusterDO.getClusterId();
|
||||||
@@ -171,8 +176,7 @@ public class LogicalClusterMetadataManager {
|
|||||||
for (Long regionId: regionIdList) {
|
for (Long regionId: regionIdList) {
|
||||||
RegionDO regionDO = regionMap.get(regionId);
|
RegionDO regionDO = regionMap.get(regionId);
|
||||||
if (ValidateUtils.isNull(regionDO) || !logicalClusterDO.getClusterId().equals(regionDO.getClusterId())) {
|
if (ValidateUtils.isNull(regionDO) || !logicalClusterDO.getClusterId().equals(regionDO.getClusterId())) {
|
||||||
LOGGER.warn("flush logical cluster metadata failed, exist illegal region, logicalCluster:{} region:{}.",
|
LOGGER.warn("flush logical cluster metadata failed, exist illegal region, logicalCluster:{} region:{}.", logicalClusterDO, regionId);
|
||||||
logicalClusterDO, regionId);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
brokerIdSet.addAll(ListUtils.string2IntList(regionDO.getBrokerList()));
|
brokerIdSet.addAll(ListUtils.string2IntList(regionDO.getBrokerList()));
|
||||||
|
|||||||
@@ -86,19 +86,36 @@ public class PhysicalClusterMetadataManager {
|
|||||||
if (ZK_CONFIG_MAP.containsKey(clusterDO.getId())) {
|
if (ZK_CONFIG_MAP.containsKey(clusterDO.getId())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ZkConfigImpl zkConfig = new ZkConfigImpl(clusterDO.getZookeeper());
|
ZkConfigImpl zkConfig = new ZkConfigImpl(clusterDO.getZookeeper());
|
||||||
|
|
||||||
//增加Broker监控
|
// 初始化broker-map
|
||||||
BROKER_METADATA_MAP.put(clusterDO.getId(), new ConcurrentHashMap<>());
|
BROKER_METADATA_MAP.put(clusterDO.getId(), new ConcurrentHashMap<>());
|
||||||
JMX_CONNECTOR_MAP.put(clusterDO.getId(), new ConcurrentHashMap<>());
|
JMX_CONNECTOR_MAP.put(clusterDO.getId(), new ConcurrentHashMap<>());
|
||||||
KAFKA_VERSION_MAP.put(clusterDO.getId(), new ConcurrentHashMap<>());
|
KAFKA_VERSION_MAP.put(clusterDO.getId(), new ConcurrentHashMap<>());
|
||||||
|
|
||||||
|
// 初始化topic-map
|
||||||
|
TOPIC_METADATA_MAP.put(clusterDO.getId(), new ConcurrentHashMap<>());
|
||||||
|
TOPIC_RETENTION_TIME_MAP.put(clusterDO.getId(), new ConcurrentHashMap<>());
|
||||||
|
|
||||||
|
// 初始化cluster-map
|
||||||
|
CLUSTER_MAP.put(clusterDO.getId(), clusterDO);
|
||||||
|
|
||||||
|
if (!zkConfig.checkPathExists(ZkPathUtil.BROKER_ROOT_NODE)) {
|
||||||
|
LOGGER.info("ignore add cluster, zk path=/brokers not exist, clusterId:{}.", clusterDO.getId());
|
||||||
|
try {
|
||||||
|
zkConfig.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOGGER.warn("ignore add cluster, close zk connection failed, cluster:{}.", clusterDO, e);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//增加Broker监控
|
||||||
BrokerStateListener brokerListener = new BrokerStateListener(clusterDO.getId(), zkConfig, configUtils.getJmxMaxConn());
|
BrokerStateListener brokerListener = new BrokerStateListener(clusterDO.getId(), zkConfig, configUtils.getJmxMaxConn());
|
||||||
brokerListener.init();
|
brokerListener.init();
|
||||||
zkConfig.watchChildren(ZkPathUtil.BROKER_IDS_ROOT, brokerListener);
|
zkConfig.watchChildren(ZkPathUtil.BROKER_IDS_ROOT, brokerListener);
|
||||||
|
|
||||||
//增加Topic监控
|
//增加Topic监控
|
||||||
TOPIC_METADATA_MAP.put(clusterDO.getId(), new ConcurrentHashMap<>());
|
|
||||||
TopicStateListener topicListener = new TopicStateListener(clusterDO.getId(), zkConfig);
|
TopicStateListener topicListener = new TopicStateListener(clusterDO.getId(), zkConfig);
|
||||||
topicListener.init();
|
topicListener.init();
|
||||||
zkConfig.watchChildren(ZkPathUtil.BROKER_TOPICS_ROOT, topicListener);
|
zkConfig.watchChildren(ZkPathUtil.BROKER_TOPICS_ROOT, topicListener);
|
||||||
@@ -109,10 +126,6 @@ public class PhysicalClusterMetadataManager {
|
|||||||
controllerListener.init();
|
controllerListener.init();
|
||||||
zkConfig.watch(ZkPathUtil.CONTROLLER_ROOT_NODE, controllerListener);
|
zkConfig.watch(ZkPathUtil.CONTROLLER_ROOT_NODE, controllerListener);
|
||||||
|
|
||||||
//增加Config变更监控
|
|
||||||
TOPIC_RETENTION_TIME_MAP.put(clusterDO.getId(), new ConcurrentHashMap<>());
|
|
||||||
|
|
||||||
CLUSTER_MAP.put(clusterDO.getId(), clusterDO);
|
|
||||||
ZK_CONFIG_MAP.put(clusterDO.getId(), zkConfig);
|
ZK_CONFIG_MAP.put(clusterDO.getId(), zkConfig);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOGGER.error("add cluster failed, cluster:{}.", clusterDO, e);
|
LOGGER.error("add cluster failed, cluster:{}.", clusterDO, e);
|
||||||
@@ -444,8 +457,16 @@ public class PhysicalClusterMetadataManager {
|
|||||||
return kafkaVersion;
|
return kafkaVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getKafkaVersion(Long clusterId) {
|
public String getKafkaVersionFromCache(Long clusterId) {
|
||||||
return getKafkaVersion(clusterId, PhysicalClusterMetadataManager.getBrokerIdList(clusterId));
|
Set<String> kafkaVersionSet = new HashSet<>();
|
||||||
|
for (Integer brokerId: PhysicalClusterMetadataManager.getBrokerIdList(clusterId)) {
|
||||||
|
String kafkaVersion = this.getKafkaVersionFromCache(clusterId, brokerId);
|
||||||
|
if (ValidateUtils.isBlank(kafkaVersion)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
kafkaVersionSet.add(kafkaVersion);
|
||||||
|
}
|
||||||
|
return ListUtils.strList2String(new ArrayList<>(kafkaVersionSet));
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getKafkaVersion(Long clusterId, List<Integer> brokerIdList) {
|
public String getKafkaVersion(Long clusterId, List<Integer> brokerIdList) {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user