提交 e2276f2d 编写于 作者: L lepdou

发布时可以查看变更集 & 自定义集群选择标签可以设置默认选择 & 获取adminservice地址增加重试和缓存机制

上级 fc38ec96
...@@ -25,6 +25,6 @@ public class API { ...@@ -25,6 +25,6 @@ public class API {
} }
public String getAdminServiceHost(Env env) { public String getAdminServiceHost(Env env) {
return serviceLocator.getAdminService(env).getHomepageUrl(); return serviceLocator.getServiceAddress(env).getHomepageUrl();
} }
} }
...@@ -30,7 +30,7 @@ public class PortalConfigController { ...@@ -30,7 +30,7 @@ public class PortalConfigController {
@Autowired @Autowired
private PortalConfigService configService; private PortalConfigService configService;
@RequestMapping(value = "/apps/{appId}/env/{env}/clusters/{clusterName}/namespaces/{namespaceName}/items", method = RequestMethod.PUT, consumes = { @RequestMapping(value = "/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/items", method = RequestMethod.PUT, consumes = {
"application/json"}) "application/json"})
public void modifyItems(@PathVariable String appId, @PathVariable String env, public void modifyItems(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName, @PathVariable String namespaceName, @PathVariable String clusterName, @PathVariable String namespaceName,
...@@ -51,7 +51,7 @@ public class PortalConfigController { ...@@ -51,7 +51,7 @@ public class PortalConfigController {
configService.updateConfigItemByText(model); configService.updateConfigItemByText(model);
} }
@RequestMapping(value = "/apps/{appId}/env/{env}/clusters/{clusterName}/namespaces/{namespaceName}/item", method = RequestMethod.POST) @RequestMapping(value = "/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/item", method = RequestMethod.POST)
public ItemDTO createItem(@PathVariable String appId, @PathVariable String env, public ItemDTO createItem(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName, @PathVariable String namespaceName, @PathVariable String clusterName, @PathVariable String namespaceName,
@RequestBody ItemDTO item){ @RequestBody ItemDTO item){
...@@ -64,7 +64,7 @@ public class PortalConfigController { ...@@ -64,7 +64,7 @@ public class PortalConfigController {
return configService.createOrUpdateItem(appId, Env.valueOf(env), clusterName, namespaceName, item); return configService.createOrUpdateItem(appId, Env.valueOf(env), clusterName, namespaceName, item);
} }
@RequestMapping(value = "/apps/{appId}/env/{env}/clusters/{clusterName}/namespaces/{namespaceName}/item", method = RequestMethod.PUT) @RequestMapping(value = "/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/item", method = RequestMethod.PUT)
public ItemDTO updateItem(@PathVariable String appId, @PathVariable String env, public ItemDTO updateItem(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName, @PathVariable String namespaceName, @PathVariable String clusterName, @PathVariable String namespaceName,
@RequestBody ItemDTO item){ @RequestBody ItemDTO item){
...@@ -85,7 +85,7 @@ public class PortalConfigController { ...@@ -85,7 +85,7 @@ public class PortalConfigController {
configService.deleteItem(Env.valueOf(env), itemId); configService.deleteItem(Env.valueOf(env), itemId);
} }
@RequestMapping(value = "/apps/{appId}/env/{env}/clusters/{clusterName}/namespaces/{namespaceName}/release", method = RequestMethod.POST, consumes = { @RequestMapping(value = "/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/release", method = RequestMethod.POST, consumes = {
"application/json"}) "application/json"})
public ReleaseDTO createRelease(@PathVariable String appId, public ReleaseDTO createRelease(@PathVariable String appId,
@PathVariable String env, @PathVariable String clusterName, @PathVariable String env, @PathVariable String clusterName,
...@@ -106,7 +106,7 @@ public class PortalConfigController { ...@@ -106,7 +106,7 @@ public class PortalConfigController {
} }
@RequestMapping(value = "/apps/{appId}/env/{env}/clusters/{clusterName}/namespaces/{namespaceName}/items") @RequestMapping(value = "/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/items")
public List<ItemDTO> findItems(@PathVariable String appId, @PathVariable String env, public List<ItemDTO> findItems(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName, @PathVariable String namespaceName){ @PathVariable String clusterName, @PathVariable String namespaceName){
......
...@@ -45,7 +45,7 @@ public class PortalNamespaceController { ...@@ -45,7 +45,7 @@ public class PortalNamespaceController {
namespaceService.createAppNamespace(appNamespace); namespaceService.createAppNamespace(appNamespace);
} }
@RequestMapping("/apps/{appId}/env/{env}/clusters/{clusterName}/namespaces") @RequestMapping("/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces")
public List<NamespaceVO> findNamespaces(@PathVariable String appId, @PathVariable String env, public List<NamespaceVO> findNamespaces(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName) { @PathVariable String clusterName) {
if (StringUtils.isContainEmpty(appId, env, clusterName)) { if (StringUtils.isContainEmpty(appId, env, clusterName)) {
......
...@@ -16,7 +16,7 @@ public class NamespaceTextModel implements Verifiable { ...@@ -16,7 +16,7 @@ public class NamespaceTextModel implements Verifiable {
@Override @Override
public boolean isInvalid(){ public boolean isInvalid(){
return StringUtils.isContainEmpty(appId, env, clusterName, namespaceName, configText) || namespaceId <= 0; return StringUtils.isContainEmpty(appId, env, clusterName, namespaceName) || namespaceId <= 0;
} }
public String getAppId() { public String getAppId() {
return appId; return appId;
......
...@@ -8,6 +8,7 @@ import com.ctrip.framework.apollo.core.dto.ItemDTO; ...@@ -8,6 +8,7 @@ import com.ctrip.framework.apollo.core.dto.ItemDTO;
import com.ctrip.framework.apollo.core.dto.NamespaceDTO; import com.ctrip.framework.apollo.core.dto.NamespaceDTO;
import com.ctrip.framework.apollo.core.dto.ReleaseDTO; import com.ctrip.framework.apollo.core.dto.ReleaseDTO;
import com.ctrip.framework.apollo.core.enums.Env; import com.ctrip.framework.apollo.core.enums.Env;
import com.ctrip.framework.apollo.core.exception.NotFoundException;
import com.ctrip.framework.apollo.core.utils.StringUtils; import com.ctrip.framework.apollo.core.utils.StringUtils;
import com.ctrip.framework.apollo.portal.PortalSettings; import com.ctrip.framework.apollo.portal.PortalSettings;
import com.ctrip.framework.apollo.portal.api.AdminServiceAPI; import com.ctrip.framework.apollo.portal.api.AdminServiceAPI;
...@@ -47,11 +48,11 @@ public class PortalNamespaceService { ...@@ -47,11 +48,11 @@ public class PortalNamespaceService {
private Gson gson = new Gson(); private Gson gson = new Gson();
public List<AppNamespaceDTO> findPublicAppNamespaces(){ public List<AppNamespaceDTO> findPublicAppNamespaces() {
return namespaceAPI.findPublicAppNamespaces(portalSettings.getFirstAliveEnv()); return namespaceAPI.findPublicAppNamespaces(portalSettings.getFirstAliveEnv());
} }
public NamespaceDTO createNamespace(Env env, NamespaceDTO namespace){ public NamespaceDTO createNamespace(Env env, NamespaceDTO namespace) {
return namespaceAPI.createNamespace(env, namespace); return namespaceAPI.createNamespace(env, namespace);
} }
......
package com.ctrip.framework.apollo.portal.service; package com.ctrip.framework.apollo.portal.service;
import java.net.URI; import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
...@@ -33,57 +31,21 @@ public class ServiceLocator { ...@@ -33,57 +31,21 @@ public class ServiceLocator {
private static final int DEFAULT_TIMEOUT_MS = 1000; private static final int DEFAULT_TIMEOUT_MS = 1000;
private static final int RETRY_TIMES = 3;
private static final int CALL_META_SERVER_THRESHOLD = 10;
private static final String ADMIN_SERVICE_URL_PATH = "/services/admin";
private RestTemplate restTemplate; private RestTemplate restTemplate;
@Autowired @Autowired
private HttpMessageConverters httpMessageConverters; private HttpMessageConverters httpMessageConverters;
private Map<Env, List<ServiceDTO>> serviceCaches = new ConcurrentHashMap<Env, List<ServiceDTO>>(); private Map<Env, ServiceDTO[]> serviceAddressCache = new ConcurrentHashMap<>();
private final AtomicInteger adminCallCounts = new AtomicInteger(0); private final AtomicInteger adminCallCounts = new AtomicInteger(0);
private final AtomicInteger configCallCounts = new AtomicInteger(0);
public ServiceDTO getAdminService(Env env) throws ServiceException {
List<ServiceDTO> services = getServices(env, "admin");
if (services == null || services.size() == 0) {
throw new ServiceException("No available admin service");
}
return services.get(Math.abs(adminCallCounts.getAndIncrement()) % services.size());
}
public ServiceDTO getConfigService(Env env) throws ServiceException {
List<ServiceDTO> services = getServices(env, "config");
if (services == null || services.size() == 0) {
throw new ServiceException("No available config service");
}
return services.get(Math.abs(configCallCounts.getAndIncrement()) % services.size());
}
private List<ServiceDTO> getServices(Env env, String serviceUrl) {
String domainName = MetaDomainConsts.getDomain(env);
String url = domainName + "/services/" + serviceUrl;
List<ServiceDTO> serviceDtos = null;
try {
ServiceDTO[] services = restTemplate.getForObject(new URI(url), ServiceDTO[].class);
if (services != null && services.length > 0) {
if (!serviceCaches.containsKey(env)) {
serviceDtos = new ArrayList<ServiceDTO>();
serviceCaches.put(env, serviceDtos);
} else {
serviceDtos = serviceCaches.get(env);
serviceDtos.clear();
}
for (ServiceDTO service : services) {
serviceDtos.add(service);
}
}
} catch (Exception ex) {
logger.warn(ex.getMessage());
}
return serviceDtos;
}
@PostConstruct @PostConstruct
private void postConstruct() { private void postConstruct() {
restTemplate = new RestTemplate(httpMessageConverters.getConverters()); restTemplate = new RestTemplate(httpMessageConverters.getConverters());
...@@ -99,4 +61,55 @@ public class ServiceLocator { ...@@ -99,4 +61,55 @@ public class ServiceLocator {
rf.setConnectTimeout(DEFAULT_TIMEOUT_MS); rf.setConnectTimeout(DEFAULT_TIMEOUT_MS);
} }
} }
public ServiceDTO getServiceAddress(Env env) throws ServiceException {
if (adminCallCounts.get() % CALL_META_SERVER_THRESHOLD == 0) {
return getServiceAddressFromMetaServer(env);
} else {
//if cached then return from cache
ServiceDTO[] serviceDTOs = serviceAddressCache.get(env);
if (serviceDTOs != null && serviceDTOs.length > 0){
return randomServiceAddress(serviceDTOs);
}else {//return from meta server
return getServiceAddressFromMetaServer(env);
}
}
}
public ServiceDTO getServiceAddressFromMetaServer(Env env) {
//retry
for (int i = 0; i < RETRY_TIMES; i++) {
ServiceDTO[] services = getServices(env);
if (services != null && services.length > 0) {
serviceAddressCache.put(env, services);
return randomServiceAddress(services);
} else {
logger.warn(String.format("can not get %s admin service address at %d time", env, i));
}
}
logger.error(String.format("can not get %s admin service address", env));
throw new ServiceException("No available admin service");
}
private ServiceDTO[] getServices(Env env) {
String domainName = MetaDomainConsts.getDomain(env);
String url = domainName + ADMIN_SERVICE_URL_PATH;
try {
return restTemplate.getForObject(new URI(url), ServiceDTO[].class);
} catch (Exception ex) {
logger.warn(ex.getMessage());
return null;
}
}
private ServiceDTO randomServiceAddress(ServiceDTO[] services){
return services[Math.abs(adminCallCounts.getAndIncrement()) % services.length];
}
} }
...@@ -3,7 +3,6 @@ package com.ctrip.framework.apollo.portal.service.txtresolver; ...@@ -3,7 +3,6 @@ package com.ctrip.framework.apollo.portal.service.txtresolver;
import com.ctrip.framework.apollo.core.dto.ItemChangeSets; import com.ctrip.framework.apollo.core.dto.ItemChangeSets;
import com.ctrip.framework.apollo.core.dto.ItemDTO; import com.ctrip.framework.apollo.core.dto.ItemDTO;
import com.ctrip.framework.apollo.core.exception.BadRequestException; import com.ctrip.framework.apollo.core.exception.BadRequestException;
import com.ctrip.framework.apollo.core.utils.StringUtils;
import com.ctrip.framework.apollo.common.utils.BeanUtils; import com.ctrip.framework.apollo.common.utils.BeanUtils;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
......
...@@ -222,7 +222,8 @@ ...@@ -222,7 +222,8 @@
<!--table view--> <!--table view-->
<div class="namespace-view-table"> <div class="namespace-view-table">
<table class="table table-bordered table-striped text-center table-hover" <table class="table table-bordered table-striped text-center table-hover"
ng-show="namespace.viewType == 'table' && namespace.items.length > 0"> ng-show="namespace.viewType == 'table' && namespace.items.length > 0
&& !(namespace.items.length == 1 && !namespace.items[0].key)">
<thead> <thead>
<tr> <tr>
<th> <th>
...@@ -283,7 +284,7 @@ ...@@ -283,7 +284,7 @@
<span class="glyphicon glyphicon-remove" aria-hidden="true" <span class="glyphicon glyphicon-remove" aria-hidden="true"
data-toggle="modal" data-target="#deleteModal" data-toggle="modal" data-target="#deleteModal"
data-tooltip="tooltip" data-placement="bottom" title="删除" data-tooltip="tooltip" data-placement="bottom" title="删除"
ng-click="preDeleteItem(config.item.id)"> ng-click="preDeleteItem(config.item.id)">
</span> </span>
</td> </td>
...@@ -390,7 +391,7 @@ ...@@ -390,7 +391,7 @@
<!--create release modal--> <!--create release modal-->
<form class="modal fade form-horizontal" id="releaseModal" tabindex="-1" role="dialog" <form class="modal fade form-horizontal" id="releaseModal" tabindex="-1" role="dialog"
ng-submit="release()"> ng-submit="release()">
<div class="modal-dialog" role="document"> <div class="modal-dialog" role="document" style="width: 960px">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header panel-primary"> <div class="modal-header panel-primary">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
...@@ -399,17 +400,71 @@ ...@@ -399,17 +400,71 @@
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div class="form-group"> <div class="form-group">
<label class="col-sm-3 control-label"> <label class="col-sm-2 control-label">
Changes:</label>
<div class="col-sm-10">
<table class="table table-bordered table-striped text-center table-hover"
ng-show="toReleaseNamespace.itemModifiedCnt">
<thead>
<tr>
<th>
Key
</th>
<th>
Old Value
</th>
<th>
New Value
</th>
<th>
最后修改人
</th>
<th>
最后修改时间
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="config in toReleaseNamespace.items"
ng-if="config.item.key && config.isModified">
<td width="20%" title="{{config.item.key}}">
<span ng-bind="config.item.key | limitTo: 250"></span>
<span ng-bind="config.item.key.length > 250 ? '...' :''"></span>
</td>
<td width="25%" title="{{config.oldValue}}">
<span ng-bind="config.oldValue | limitTo: 250"></span>
<span ng-bind="config.oldValue.length > 250 ? '...': ''"></span>
</td>
<td width="25%" title="{{config.item.value}}">
<span ng-bind="config.item.value | limitTo: 250"></span>
<span ng-bind="config.item.value.length > 250 ? '...': ''"></span>
</td>
<td width="15%" ng-bind="config.item.lastModifiedBy">
</td>
<td width="15%"
ng-bind="config.item.lastModifiedTime | date: 'yyyy-MM-dd HH:mm:ss'">
</td>
</tr>
</tbody>
</table>
<span ng-show="!toReleaseNamespace.itemModifiedCnt">
配置没有变化
</span>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">
<apollorequiredfiled></apollorequiredfiled> <apollorequiredfiled></apollorequiredfiled>
Release Name:</label> Release Name:</label>
<div class="col-sm-9"> <div class="col-sm-5">
<input type="text" class="form-control" placeholder="input release title" <input type="text" class="form-control" placeholder="input release title"
ng-model="releaseTitle" ng-required="true"> ng-model="releaseTitle" ng-required="true">
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="col-sm-3 control-label">Comment:</label> <label class="col-sm-2 control-label">Comment:</label>
<div class="col-sm-9"> <div class="col-sm-10">
<textarea rows="4" class="form-control" style="margin-top: 15px;" <textarea rows="4" class="form-control" style="margin-top: 15px;"
ng-model="releaseComment" ng-model="releaseComment"
placeholder="Add an optional extended description..."></textarea> placeholder="Add an optional extended description..."></textarea>
...@@ -420,7 +475,7 @@ ...@@ -420,7 +475,7 @@
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button> <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
<button type="submit" class="btn btn-primary">提交 <button type="submit" class="btn btn-primary">发布
</button> </button>
</div> </div>
</div> </div>
...@@ -442,14 +497,22 @@ ...@@ -442,14 +497,22 @@
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div class="form-group"> <div class="form-group">
<label class="col-sm-2 control-label"><apollorequiredfiled></apollorequiredfiled>Key</label> <label class="col-sm-2 control-label">
<apollorequiredfiled
ng-show="tableViewOperType != 'retrieve'"></apollorequiredfiled>
Key
</label>
<div class="col-sm-10"> <div class="col-sm-10">
<input type="text" class="form-control" ng-model="item.key" <input type="text" class="form-control" ng-model="item.key"
ng-required="true" ng-disabled="tableViewOperType != 'create'"> ng-required="true" ng-disabled="tableViewOperType != 'create'">
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="col-sm-2 control-label"><apollorequiredfiled></apollorequiredfiled>Value</label> <label class="col-sm-2 control-label">
<apollorequiredfiled
ng-show="tableViewOperType != 'retrieve'"></apollorequiredfiled>
Value
</label>
<div class="col-sm-10"> <div class="col-sm-10">
<textarea type="text" class="form-control" rows="6" ng-model="item.value" <textarea type="text" class="form-control" rows="6" ng-model="item.value"
ng-required="true" ng-show="tableViewOperType != 'retrieve'"> ng-required="true" ng-show="tableViewOperType != 'retrieve'">
...@@ -460,7 +523,8 @@ ...@@ -460,7 +523,8 @@
<div class="form-group" ng-show="tableViewOperType == 'retrieve'"> <div class="form-group" ng-show="tableViewOperType == 'retrieve'">
<label class="col-sm-2 control-label">Released Value</label> <label class="col-sm-2 control-label">Released Value</label>
<div class="col-sm-10"> <div class="col-sm-10">
<span ng-show="!item.oldVale">这是新增的配置</span> <p ng-show="!item.oldValue">这是新增的配置</p>
<p ng-show="item.oldValue" ng-bind="item.oldValue"></p>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
...@@ -473,18 +537,28 @@ ...@@ -473,18 +537,28 @@
</div> </div>
</div> </div>
<div class="form-group" ng-show="tableViewOperType != 'retrieve'"> <div class="form-group" ng-show="tableViewOperType != 'retrieve'">
<label class="col-sm-2 control-label"><apollorequiredfiled></apollorequiredfiled>选择集群</label> <label class="col-sm-2 control-label">
<apollorequiredfiled></apollorequiredfiled>
选择集群</label>
<div class="col-sm-10"> <div class="col-sm-10">
<apolloclusterselector apollo-app-id="pageContext.appId" apollo-default-checked="false" <apolloclusterselector apollo-app-id="pageContext.appId"
apollo-select="collectSelectedClusters"></apolloclusterselector> apollo-default-all-checked="false"
apollo-default-checked-env="pageContext.env"
apollo-default-checked-cluster="pageContext.clusterName"
apollo-select="collectSelectedClusters">
</apolloclusterselector>
</div> </div>
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-default" ng-click="switchToEdit()" ng-show="tableViewOperType == 'retrieve'">修改</button> <button type="button" class="btn btn-default" ng-click="switchToEdit()"
ng-show="tableViewOperType == 'retrieve'">修改
</button>
<button type="button" class="btn btn-default" data-dismiss="modal">关闭 <button type="button" class="btn btn-default" data-dismiss="modal">关闭
</button> </button>
<button type="submit" class="btn btn-primary" ng-show="tableViewOperType != 'retrieve'">提交 <button type="submit" class="btn btn-primary"
ng-show="tableViewOperType != 'retrieve'">提交
</button> </button>
</div> </div>
</div> </div>
......
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
<div class="form-group"> <div class="form-group">
<label class="col-sm-2 control-label">同步到那个集群</label> <label class="col-sm-2 control-label">同步到那个集群</label>
<div class="col-sm-6"> <div class="col-sm-6">
<apolloclusterselector apollo-app-id="pageContext.appId" apollo-default-checked="true" <apolloclusterselector apollo-app-id="pageContext.appId" apollo-default-all-checked="true"
apollo-select="collectSelectedClusters"></apolloclusterselector> apollo-select="collectSelectedClusters"></apolloclusterselector>
</div> </div>
</div> </div>
......
...@@ -41,7 +41,7 @@ ...@@ -41,7 +41,7 @@
<div class="form-group"> <div class="form-group">
<label class="col-sm-3 control-label"><font style="color: red">*</font>选择集群</label> <label class="col-sm-3 control-label"><font style="color: red">*</font>选择集群</label>
<div class="col-sm-6"> <div class="col-sm-6">
<apolloclusterselector apollo-app-id="appId" apollo-default-checked="true" <apolloclusterselector apollo-app-id="appId" apollo-default-all-checked="true"
apollo-select="collectSelectedClusters"></apolloclusterselector> apollo-select="collectSelectedClusters"></apolloclusterselector>
</div> </div>
</div> </div>
......
...@@ -26,12 +26,12 @@ appUtil.service('AppUtil', ['toastr', function (toastr) { ...@@ -26,12 +26,12 @@ appUtil.service('AppUtil', ['toastr', function (toastr) {
collectData: function (response) { collectData: function (response) {
var data = []; var data = [];
response.entities.forEach(function (entity) { response.entities.forEach(function (entity) {
if (entity.code == 200){ if (entity.code == 200) {
data.push(entity.body); data.push(entity.body);
}else { } else {
toastr.warning(entity.message); toastr.warning(entity.message);
} }
}); });
return data; return data;
} }
} }
......
...@@ -14,3 +14,28 @@ $(document).ready(function () { ...@@ -14,3 +14,28 @@ $(document).ready(function () {
$(function () { $(function () {
$('[data-toggle="tooltip"]').tooltip() $('[data-toggle="tooltip"]').tooltip()
}); });
// (new Date()).Format("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423
// (new Date()).Format("yyyy-M-d h:m:s.S") ==> 2006-7-2 8:9:4.18
Date.prototype.Format = function (fmt) {
var o = {
"M+": this.getMonth() + 1, //月份
"d+": this.getDate(), //日
"h+": this.getHours(), //小时
"m+": this.getMinutes(), //分
"s+": this.getSeconds(), //秒
"q+": Math.floor((this.getMonth() + 3) / 3), //季度
"S": this.getMilliseconds() //毫秒
};
if (/(y+)/.test(fmt)) {
fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
}
for (var k in o) {
if (new RegExp("(" + k + ")").test(fmt)) {
fmt =
fmt.replace(RegExp.$1,
(RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
}
}
return fmt;
};
...@@ -2,8 +2,6 @@ application_module.controller("ConfigNamespaceController", ...@@ -2,8 +2,6 @@ application_module.controller("ConfigNamespaceController",
['$rootScope', '$scope', '$location', 'toastr', 'AppUtil', 'ConfigService', ['$rootScope', '$scope', '$location', 'toastr', 'AppUtil', 'ConfigService',
function ($rootScope, $scope, $location, toastr, AppUtil, ConfigService) { function ($rootScope, $scope, $location, toastr, AppUtil, ConfigService) {
////// namespace //////
var namespace_view_type = { var namespace_view_type = {
TEXT: 'text', TEXT: 'text',
TABLE: 'table', TABLE: 'table',
...@@ -53,8 +51,6 @@ application_module.controller("ConfigNamespaceController", ...@@ -53,8 +51,6 @@ application_module.controller("ConfigNamespaceController",
}); });
}; };
////// global view oper //////
$scope.switchView = function (namespace, viewType) { $scope.switchView = function (namespace, viewType) {
if (namespace_view_type.TEXT == viewType) { if (namespace_view_type.TEXT == viewType) {
namespace.text = parseModel2Text(namespace); namespace.text = parseModel2Text(namespace);
...@@ -89,8 +85,6 @@ application_module.controller("ConfigNamespaceController", ...@@ -89,8 +85,6 @@ application_module.controller("ConfigNamespaceController",
return result; return result;
} }
////// text view oper //////
$scope.toCommitNamespace = {}; $scope.toCommitNamespace = {};
$scope.setCommitNamespace = function (namespace) { $scope.setCommitNamespace = function (namespace) {
...@@ -133,19 +127,20 @@ application_module.controller("ConfigNamespaceController", ...@@ -133,19 +127,20 @@ application_module.controller("ConfigNamespaceController",
} }
}; };
/////// release ///////
var releaseModal = $('#releaseModal'); var releaseModal = $('#releaseModal');
var releaseNamespace = {}; $scope.toReleaseNamespace = {};
$scope.prepareReleaseNamespace = function (namespace) { $scope.prepareReleaseNamespace = function (namespace) {
releaseNamespace = namespace; $scope.releaseTitle = new Date().Format("yyyy-MM-dd hh:mm:ss");
$scope.toReleaseNamespace = namespace;
}; };
$scope.releaseComment = ''; $scope.releaseComment = '';
$scope.releaseTitle = '';
$scope.release = function () { $scope.release = function () {
ConfigService.release($rootScope.pageContext.appId, $rootScope.pageContext.env, ConfigService.release($rootScope.pageContext.appId, $rootScope.pageContext.env,
$rootScope.pageContext.clusterName, $rootScope.pageContext.clusterName,
releaseNamespace.namespace.namespaceName, $scope.toReleaseNamespace.namespace.namespaceName,
$scope.releaseTitle, $scope.releaseTitle,
$scope.releaseComment).then( $scope.releaseComment).then(
function (result) { function (result) {
...@@ -182,12 +177,13 @@ application_module.controller("ConfigNamespaceController", ...@@ -182,12 +177,13 @@ application_module.controller("ConfigNamespaceController",
}; };
$scope.deleteItem = function () { $scope.deleteItem = function () {
ConfigService.delete_item($rootScope.pageContext.env, toDeleteItemId).then(function (result) { ConfigService.delete_item($rootScope.pageContext.env, toDeleteItemId).then(
toastr.success("删除成功!"); function (result) {
$rootScope.refreshNamespaces(); toastr.success("删除成功!");
}, function (result) { $rootScope.refreshNamespaces();
toastr.error(AppUtil.errorMsg(result), "删除失败"); }, function (result) {
}); toastr.error(AppUtil.errorMsg(result), "删除失败");
});
}; };
var toOperationNamespaceName = ''; var toOperationNamespaceName = '';
......
...@@ -116,7 +116,6 @@ directive_module.directive('apollonav', function ($compile, $window, toastr, App ...@@ -116,7 +116,6 @@ directive_module.directive('apollonav', function ($compile, $window, toastr, App
}); });
/** env cluster selector*/ /** env cluster selector*/
directive_module.directive('apolloclusterselector', function ($compile, $window, AppService, AppUtil, toastr) { directive_module.directive('apolloclusterselector', function ($compile, $window, AppService, AppUtil, toastr) {
return { return {
restrict: 'E', restrict: 'E',
...@@ -125,28 +124,42 @@ directive_module.directive('apolloclusterselector', function ($compile, $window, ...@@ -125,28 +124,42 @@ directive_module.directive('apolloclusterselector', function ($compile, $window,
replace: true, replace: true,
scope: { scope: {
appId: '=apolloAppId', appId: '=apolloAppId',
defaultChecked: '=apolloDefaultChecked', defaultAllChecked: '=apolloDefaultAllChecked',
select: '=apolloSelect' select: '=apolloSelect',
defaultCheckedEnv: '=apolloDefaultCheckedEnv',
defaultCheckedCluster: '=apolloDefaultCheckedCluster'
}, },
link: function (scope, element, attrs) { link: function (scope, element, attrs) {
////// load env ////// ////// load env //////
AppService.load_nav_tree(scope.appId).then(function (result) {
scope.clusters = []; scope.$watch("defaultCheckedEnv", function (newValue, oldValue) {
var envClusterInfo = AppUtil.collectData(result); refreshClusterList();
envClusterInfo.forEach(function (node) {
var env = node.env;
node.clusters.forEach(function (cluster) {
cluster.env = env;
cluster.checked = scope.defaultChecked;
scope.clusters.push(cluster);
})
});
scope.select(collectSelectedClusters());
}, function (result) {
toastr.error(AppUtil.errorMsg(result), "加载环境信息出错");
}); });
scope.envAllSelected = scope.defaultChecked; refreshClusterList();
function refreshClusterList() {
AppService.load_nav_tree(scope.appId).then(function (result) {
scope.clusters = [];
var envClusterInfo = AppUtil.collectData(result);
envClusterInfo.forEach(function (node) {
var env = node.env;
node.clusters.forEach(function (cluster) {
cluster.env = env;
cluster.checked = scope.defaultAllChecked ||
(cluster.env == scope.defaultCheckedEnv && cluster.name
== scope.defaultCheckedCluster);
scope.clusters.push(cluster);
})
});
scope.select(collectSelectedClusters());
}, function (result) {
toastr.error(AppUtil.errorMsg(result), "加载环境信息出错");
});
}
scope.envAllSelected = scope.defaultAllChecked;
scope.toggleEnvsCheckedStatus = function () { scope.toggleEnvsCheckedStatus = function () {
scope.envAllSelected = !scope.envAllSelected; scope.envAllSelected = !scope.envAllSelected;
......
...@@ -3,20 +3,20 @@ appService.service("ConfigService", ['$resource', '$q', function ($resource, $q) ...@@ -3,20 +3,20 @@ appService.service("ConfigService", ['$resource', '$q', function ($resource, $q)
load_all_namespaces: { load_all_namespaces: {
method: 'GET', method: 'GET',
isArray: true, isArray: true,
url: '/apps/:appId/env/:env/clusters/:clusterName/namespaces' url: '/apps/:appId/envs/:env/clusters/:clusterName/namespaces'
}, },
find_items: { find_items: {
method: 'GET', method: 'GET',
isArray: true, isArray: true,
url: '/apps/:appId/env/:env/clusters/:clusterName/namespaces/:namespaceName/items' url: '/apps/:appId/envs/:env/clusters/:clusterName/namespaces/:namespaceName/items'
}, },
modify_items: { modify_items: {
method: 'PUT', method: 'PUT',
url: '/apps/:appId/env/:env/clusters/:clusterName/namespaces/:namespaceName/items' url: '/apps/:appId/envs/:env/clusters/:clusterName/namespaces/:namespaceName/items'
}, },
release: { release: {
method: 'POST', method: 'POST',
url: '/apps/:appId/env/:env/clusters/:clusterName/namespaces/:namespaceName/release' url: '/apps/:appId/envs/:env/clusters/:clusterName/namespaces/:namespaceName/release'
}, },
diff: { diff: {
method: 'POST', method: 'POST',
...@@ -30,11 +30,11 @@ appService.service("ConfigService", ['$resource', '$q', function ($resource, $q) ...@@ -30,11 +30,11 @@ appService.service("ConfigService", ['$resource', '$q', function ($resource, $q)
}, },
create_item: { create_item: {
method: 'POST', method: 'POST',
url: '/apps/:appId/env/:env/clusters/:clusterName/namespaces/:namespaceName/item' url: '/apps/:appId/envs/:env/clusters/:clusterName/namespaces/:namespaceName/item'
}, },
update_item: { update_item: {
method: 'PUT', method: 'PUT',
url: '/apps/:appId/env/:env/clusters/:clusterName/namespaces/:namespaceName/item' url: '/apps/:appId/envs/:env/clusters/:clusterName/namespaces/:namespaceName/item'
}, },
delete_item: { delete_item: {
method: 'DELETE', method: 'DELETE',
...@@ -56,6 +56,7 @@ appService.service("ConfigService", ['$resource', '$q', function ($resource, $q) ...@@ -56,6 +56,7 @@ appService.service("ConfigService", ['$resource', '$q', function ($resource, $q)
}); });
return d.promise; return d.promise;
}, },
find_items: function (appId, env, clusterName, namespaceName) { find_items: function (appId, env, clusterName, namespaceName) {
var d = $q.defer(); var d = $q.defer();
config_source.find_items({ config_source.find_items({
......
...@@ -1691,7 +1691,7 @@ ...@@ -1691,7 +1691,7 @@
for (r in i.events)x.removeEvent(t, r, i.handle); for (r in i.events)x.removeEvent(t, r, i.handle);
t.removeAttribute(x.expando) t.removeAttribute(x.expando)
} }
"script" === n && t.text !== e.text ? (Ht(t).text = e.text, qt(t)) : "object" === n ? (t.parentNode && (t.outerHTML = e.outerHTML), x.support.html5Clone && e.innerHTML && !x.trim(t.innerHTML) && (t.innerHTML = e.innerHTML)) : "input" === n && Ct.test(e.type) ? (t.defaultChecked = t.checked = e.checked, t.value !== e.value && (t.value = e.value)) : "option" === n ? t.defaultSelected = t.selected = e.defaultSelected : ("input" === n || "textarea" === n) && (t.defaultValue = e.defaultValue) "script" === n && t.text !== e.text ? (Ht(t).text = e.text, qt(t)) : "object" === n ? (t.parentNode && (t.outerHTML = e.outerHTML), x.support.html5Clone && e.innerHTML && !x.trim(t.innerHTML) && (t.innerHTML = e.innerHTML)) : "input" === n && Ct.test(e.type) ? (t.defaultAllChecked = t.checked = e.checked, t.value !== e.value && (t.value = e.value)) : "option" === n ? t.defaultSelected = t.selected = e.defaultSelected : ("input" === n || "textarea" === n) && (t.defaultValue = e.defaultValue)
} }
} }
...@@ -1715,7 +1715,7 @@ ...@@ -1715,7 +1715,7 @@
} }
function Bt(e) { function Bt(e) {
Ct.test(e.type) && (e.defaultChecked = e.checked) Ct.test(e.type) && (e.defaultAllChecked = e.checked)
} }
x.extend({ x.extend({
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册