提交 8a39ccea 编写于 作者: L lepdou

admin can modify app information

上级 f5373b19
...@@ -20,6 +20,7 @@ import org.springframework.web.bind.annotation.RequestParam; ...@@ -20,6 +20,7 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.util.List; import java.util.List;
import java.util.Objects;
@RestController @RestController
public class AppController { public class AppController {
...@@ -47,7 +48,7 @@ public class AppController { ...@@ -47,7 +48,7 @@ public class AppController {
return dto; return dto;
} }
@RequestMapping(path = "/apps/{appId}", method = RequestMethod.DELETE) @RequestMapping(value = "/apps/{appId}", method = RequestMethod.DELETE)
public void delete(@PathVariable("appId") String appId, @RequestParam String operator) { public void delete(@PathVariable("appId") String appId, @RequestParam String operator) {
App entity = appService.findOne(appId); App entity = appService.findOne(appId);
if (entity == null) { if (entity == null) {
...@@ -56,6 +57,15 @@ public class AppController { ...@@ -56,6 +57,15 @@ public class AppController {
appService.delete(entity.getId(), operator); appService.delete(entity.getId(), operator);
} }
@RequestMapping(value = "/apps/{appId}", method = RequestMethod.PUT)
public void update(@PathVariable String appId, @RequestBody App app) {
if (!Objects.equals(appId, app.getAppId())) {
throw new BadRequestException("The App Id of path variable and request body is different");
}
appService.update(app);
}
@RequestMapping(value = "/apps", method = RequestMethod.GET) @RequestMapping(value = "/apps", method = RequestMethod.GET)
public List<AppDTO> find(@RequestParam(value = "name", required = false) String name, public List<AppDTO> find(@RequestParam(value = "name", required = false) String name,
Pageable pageable) { Pageable pageable) {
......
...@@ -3,6 +3,7 @@ package com.ctrip.framework.apollo.biz.service; ...@@ -3,6 +3,7 @@ package com.ctrip.framework.apollo.biz.service;
import com.ctrip.framework.apollo.biz.entity.Audit; import com.ctrip.framework.apollo.biz.entity.Audit;
import com.ctrip.framework.apollo.biz.repository.AppRepository; import com.ctrip.framework.apollo.biz.repository.AppRepository;
import com.ctrip.framework.apollo.common.entity.App; import com.ctrip.framework.apollo.common.entity.App;
import com.ctrip.framework.apollo.common.exception.BadRequestException;
import com.ctrip.framework.apollo.common.exception.ServiceException; import com.ctrip.framework.apollo.common.exception.ServiceException;
import com.ctrip.framework.apollo.common.utils.BeanUtils; import com.ctrip.framework.apollo.common.utils.BeanUtils;
...@@ -71,14 +72,25 @@ public class AppService { ...@@ -71,14 +72,25 @@ public class AppService {
} }
@Transactional @Transactional
public App update(App app) { public void update(App app) {
App managedApp = appRepository.findByAppId(app.getAppId()); String appId = app.getAppId();
BeanUtils.copyEntityProperties(app, managedApp);
App managedApp = appRepository.findByAppId(appId);
if (managedApp == null) {
throw new BadRequestException(String.format("App not exists. AppId = %s", appId));
}
managedApp.setName(app.getName());
managedApp.setOrgId(app.getOrgId());
managedApp.setOrgName(app.getOrgName());
managedApp.setOwnerName(app.getOwnerName());
managedApp.setOwnerEmail(app.getOwnerEmail());
managedApp.setDataChangeLastModifiedBy(app.getDataChangeLastModifiedBy());
managedApp = appRepository.save(managedApp); managedApp = appRepository.save(managedApp);
auditService.audit(App.class.getSimpleName(), managedApp.getId(), Audit.OP.UPDATE, auditService.audit(App.class.getSimpleName(), managedApp.getId(), Audit.OP.UPDATE,
managedApp.getDataChangeLastModifiedBy()); managedApp.getDataChangeLastModifiedBy());
return managedApp;
} }
} }
...@@ -58,6 +58,10 @@ public class AdminServiceAPI { ...@@ -58,6 +58,10 @@ public class AdminServiceAPI {
public AppDTO createApp(Env env, AppDTO app) { public AppDTO createApp(Env env, AppDTO app) {
return restTemplate.post(env, "apps", app, AppDTO.class); return restTemplate.post(env, "apps", app, AppDTO.class);
} }
public void updateApp(Env env, AppDTO app) {
restTemplate.put(env, "apps/{appId}", app, app.getAppId());
}
} }
......
...@@ -65,6 +65,10 @@ public class PermissionValidator { ...@@ -65,6 +65,10 @@ public class PermissionValidator {
} }
} }
public boolean isAppAdmin(String appId) {
return isSuperAdmin() || hasAssignRolePermission(appId);
}
public boolean isSuperAdmin() { public boolean isSuperAdmin() {
return rolePermissionService.isSuperAdmin(userInfoHolder.getUser().getUserId()); return rolePermissionService.isSuperAdmin(userInfoHolder.getUser().getUserId());
} }
......
...@@ -14,6 +14,7 @@ import com.ctrip.framework.apollo.portal.component.PortalSettings; ...@@ -14,6 +14,7 @@ import com.ctrip.framework.apollo.portal.component.PortalSettings;
import com.ctrip.framework.apollo.portal.entity.model.AppModel; import com.ctrip.framework.apollo.portal.entity.model.AppModel;
import com.ctrip.framework.apollo.portal.entity.vo.EnvClusterInfo; import com.ctrip.framework.apollo.portal.entity.vo.EnvClusterInfo;
import com.ctrip.framework.apollo.portal.listener.AppCreationEvent; import com.ctrip.framework.apollo.portal.listener.AppCreationEvent;
import com.ctrip.framework.apollo.portal.listener.AppInfoChangedEvent;
import com.ctrip.framework.apollo.portal.service.AppService; import com.ctrip.framework.apollo.portal.service.AppService;
import com.ctrip.framework.apollo.portal.service.RolePermissionService; import com.ctrip.framework.apollo.portal.service.RolePermissionService;
import com.ctrip.framework.apollo.portal.spi.UserInfoHolder; import com.ctrip.framework.apollo.portal.spi.UserInfoHolder;
...@@ -24,6 +25,7 @@ import org.springframework.context.ApplicationEventPublisher; ...@@ -24,6 +25,7 @@ import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
...@@ -35,6 +37,7 @@ import org.springframework.web.bind.annotation.RestController; ...@@ -35,6 +37,7 @@ import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.HttpClientErrorException;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.Set; import java.util.Set;
...@@ -69,6 +72,38 @@ public class AppController { ...@@ -69,6 +72,38 @@ public class AppController {
return appService.findByOwnerName(owner, page); return appService.findByOwnerName(owner, page);
} }
@RequestMapping(value = "", method = RequestMethod.POST)
public App create(@RequestBody AppModel appModel) {
App app = transformToApp(appModel);
App createdApp = appService.createAppInLocal(app);
publisher.publishEvent(new AppCreationEvent(createdApp));
Set<String> admins = appModel.getAdmins();
if (!CollectionUtils.isEmpty(admins)) {
rolePermissionService.assignRoleToUsers(RoleUtils.buildAppMasterRoleName(createdApp.getAppId()),
admins, userInfoHolder.getUser().getUserId());
}
return createdApp;
}
@PreAuthorize(value = "@permissionValidator.isAppAdmin(#appId)")
@RequestMapping(value = "/{appId}", method = RequestMethod.PUT)
public void update(@PathVariable String appId, @RequestBody AppModel appModel) {
if (!Objects.equals(appId, appModel.getAppId())) {
throw new BadRequestException("The App Id of path variable and request body is different");
}
App app = transformToApp(appModel);
App updatedApp = appService.updateAppInLocal(app);
publisher.publishEvent(new AppInfoChangedEvent(updatedApp));
}
@RequestMapping(value = "/{appId}/navtree", method = RequestMethod.GET) @RequestMapping(value = "/{appId}/navtree", method = RequestMethod.GET)
public MultiResponseEntity<EnvClusterInfo> nav(@PathVariable String appId) { public MultiResponseEntity<EnvClusterInfo> nav(@PathVariable String appId) {
...@@ -86,41 +121,6 @@ public class AppController { ...@@ -86,41 +121,6 @@ public class AppController {
return response; return response;
} }
@RequestMapping(value = "", method = RequestMethod.POST)
public App create(@RequestBody AppModel appModel) {
String appId = appModel.getAppId();
String appName = appModel.getName();
String ownerName = appModel.getOwnerName();
String orgId = appModel.getOrgId();
String orgName = appModel.getOrgName();
RequestPrecondition.checkArgumentsNotEmpty(appId, appName, ownerName, orgId, orgName);
if (!InputValidator.isValidClusterNamespace(appModel.getAppId())) {
throw new BadRequestException(String.format("AppId格式错误: %s", InputValidator.INVALID_CLUSTER_NAMESPACE_MESSAGE));
}
App app = new App();
app.setAppId(appId);
app.setName(appName);
app.setOwnerName(ownerName);
app.setOrgId(orgId);
app.setOrgName(orgName);
App createdApp = appService.create(app);
publisher.publishEvent(new AppCreationEvent(createdApp));
Set<String> admins = appModel.getAdmins();
if (!CollectionUtils.isEmpty(admins)) {
rolePermissionService
.assignRoleToUsers(RoleUtils.buildAppMasterRoleName(appId), admins, userInfoHolder.getUser().getUserId());
}
return createdApp;
}
@RequestMapping(value = "/envs/{env}", method = RequestMethod.POST, consumes = { @RequestMapping(value = "/envs/{env}", method = RequestMethod.POST, consumes = {
"application/json"}) "application/json"})
public ResponseEntity<Void> create(@PathVariable String env, @RequestBody App app) { public ResponseEntity<Void> create(@PathVariable String env, @RequestBody App app) {
...@@ -131,7 +131,7 @@ public class AppController { ...@@ -131,7 +131,7 @@ public class AppController {
throw new BadRequestException(InputValidator.INVALID_CLUSTER_NAMESPACE_MESSAGE); throw new BadRequestException(InputValidator.INVALID_CLUSTER_NAMESPACE_MESSAGE);
} }
appService.createApp(Env.valueOf(env), app); appService.createAppInRemote(Env.valueOf(env), app);
return ResponseEntity.ok().build(); return ResponseEntity.ok().build();
} }
...@@ -155,7 +155,8 @@ public class AppController { ...@@ -155,7 +155,8 @@ public class AppController {
response.addResponseEntity(RichResponseEntity.ok(env)); response.addResponseEntity(RichResponseEntity.ok(env));
} else { } else {
response.addResponseEntity(RichResponseEntity.error(HttpStatus.INTERNAL_SERVER_ERROR, response.addResponseEntity(RichResponseEntity.error(HttpStatus.INTERNAL_SERVER_ERROR,
String.format("load appId:%s from env %s error.", appId,env) String.format("load appId:%s from env %s error.", appId,
env)
+ e.getMessage())); + e.getMessage()));
} }
} }
...@@ -164,4 +165,27 @@ public class AppController { ...@@ -164,4 +165,27 @@ public class AppController {
return response; return response;
} }
private App transformToApp(AppModel appModel) {
String appId = appModel.getAppId();
String appName = appModel.getName();
String ownerName = appModel.getOwnerName();
String orgId = appModel.getOrgId();
String orgName = appModel.getOrgName();
RequestPrecondition.checkArgumentsNotEmpty(appId, appName, ownerName, orgId, orgName);
if (!InputValidator.isValidClusterNamespace(appModel.getAppId())) {
throw new BadRequestException(String.format("AppId格式错误: %s", InputValidator.INVALID_CLUSTER_NAMESPACE_MESSAGE));
}
App app = new App();
app.setAppId(appId);
app.setName(appName);
app.setOwnerName(ownerName);
app.setOrgId(orgId);
app.setOrgName(orgName);
return app;
}
} }
package com.ctrip.framework.apollo.portal.listener;
import com.google.common.base.Preconditions;
import com.ctrip.framework.apollo.common.entity.App;
import org.springframework.context.ApplicationEvent;
public class AppInfoChangedEvent extends ApplicationEvent{
public AppInfoChangedEvent(Object source) {
super(source);
}
public App getApp() {
Preconditions.checkState(source != null);
return (App) this.source;
}
}
package com.ctrip.framework.apollo.portal.listener;
import com.ctrip.framework.apollo.common.dto.AppDTO;
import com.ctrip.framework.apollo.common.utils.BeanUtils;
import com.ctrip.framework.apollo.core.enums.Env;
import com.ctrip.framework.apollo.portal.api.AdminServiceAPI;
import com.ctrip.framework.apollo.portal.component.PortalSettings;
import com.ctrip.framework.apollo.tracer.Tracer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class AppInfoChangedListener {
private static final Logger logger = LoggerFactory.getLogger(AppInfoChangedListener.class);
@Autowired
private AdminServiceAPI.AppAPI appAPI;
@Autowired
private PortalSettings portalSettings;
@EventListener
public void onAppInfoChange(AppInfoChangedEvent event) {
AppDTO appDTO = BeanUtils.transfrom(AppDTO.class, event.getApp());
String appId = appDTO.getAppId();
List<Env> envs = portalSettings.getActiveEnvs();
for (Env env : envs) {
try {
appAPI.updateApp(env, appDTO);
} catch (Throwable e) {
logger.error("Update app's info failed. Env = {}, AppId = {}", env, appId, e);
Tracer.logError(String.format("Update app's info failed. Env = {}, AppId = {}", env, appId), e);
}
}
}
}
...@@ -36,8 +36,8 @@ public class CreationListener { ...@@ -36,8 +36,8 @@ public class CreationListener {
try { try {
appAPI.createApp(env, appDTO); appAPI.createApp(env, appDTO);
} catch (Throwable e) { } catch (Throwable e) {
logger.error("call appAPI.createApp error.(appId={appId}, env={env})", appDTO.getAppId(), env, e); logger.error("Create app failed. appId = {}, env = {})", appDTO.getAppId(), env, e);
Tracer.logError(String.format("call appAPI.createApp error. (appId=%s, env=%s)", appDTO.getAppId(), env), e); Tracer.logError(String.format("Create app failed. appId = %s, env = %s", appDTO.getAppId(), env), e);
} }
} }
} }
...@@ -50,8 +50,8 @@ public class CreationListener { ...@@ -50,8 +50,8 @@ public class CreationListener {
try { try {
namespaceAPI.createAppNamespace(env, appNamespace); namespaceAPI.createAppNamespace(env, appNamespace);
} catch (Throwable e) { } catch (Throwable e) {
logger.error("call appAPI.createApp error.(appId={appId}, env={env})", appNamespace.getAppId(), env, e); logger.error("Create appNamespace failed. appId = {}, env = {}", appNamespace.getAppId(), env, e);
Tracer.logError(String.format("call appAPI.createApp error. (appId=%s, env=%s)", appNamespace.getAppId(), env), e); Tracer.logError(String.format("Create appNamespace failed. appId = %s, env = %s", appNamespace.getAppId(), env), e);
} }
} }
} }
......
...@@ -6,7 +6,6 @@ import com.ctrip.framework.apollo.common.dto.AppDTO; ...@@ -6,7 +6,6 @@ import com.ctrip.framework.apollo.common.dto.AppDTO;
import com.ctrip.framework.apollo.common.entity.App; import com.ctrip.framework.apollo.common.entity.App;
import com.ctrip.framework.apollo.common.exception.BadRequestException; import com.ctrip.framework.apollo.common.exception.BadRequestException;
import com.ctrip.framework.apollo.common.utils.BeanUtils; import com.ctrip.framework.apollo.common.utils.BeanUtils;
import com.ctrip.framework.apollo.common.utils.ExceptionUtils;
import com.ctrip.framework.apollo.core.enums.Env; import com.ctrip.framework.apollo.core.enums.Env;
import com.ctrip.framework.apollo.portal.api.AdminServiceAPI; import com.ctrip.framework.apollo.portal.api.AdminServiceAPI;
import com.ctrip.framework.apollo.portal.constant.CatEventType; import com.ctrip.framework.apollo.portal.constant.CatEventType;
...@@ -17,13 +16,10 @@ import com.ctrip.framework.apollo.portal.spi.UserInfoHolder; ...@@ -17,13 +16,10 @@ import com.ctrip.framework.apollo.portal.spi.UserInfoHolder;
import com.ctrip.framework.apollo.portal.spi.UserService; import com.ctrip.framework.apollo.portal.spi.UserService;
import com.ctrip.framework.apollo.tracer.Tracer; import com.ctrip.framework.apollo.tracer.Tracer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.HttpStatusCodeException;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
...@@ -32,8 +28,6 @@ import java.util.Set; ...@@ -32,8 +28,6 @@ import java.util.Set;
@Service @Service
public class AppService { public class AppService {
private Logger logger = LoggerFactory.getLogger(AppService.class);
@Autowired @Autowired
private UserInfoHolder userInfoHolder; private UserInfoHolder userInfoHolder;
@Autowired @Autowired
...@@ -78,26 +72,17 @@ public class AppService { ...@@ -78,26 +72,17 @@ public class AppService {
return appAPI.loadApp(env, appId); return appAPI.loadApp(env, appId);
} }
public void createApp(Env env, App app) { public void createAppInRemote(Env env, App app) {
enrichUserInfo(app);
try {
AppDTO appDTO = BeanUtils.transfrom(AppDTO.class, app);
appAPI.createApp(env, appDTO);
} catch (HttpStatusCodeException e) {
logger.error(ExceptionUtils.toString(e));
throw e;
}
}
public void enrichUserInfo(App app) {
String username = userInfoHolder.getUser().getUserId(); String username = userInfoHolder.getUser().getUserId();
app.setDataChangeCreatedBy(username); app.setDataChangeCreatedBy(username);
app.setDataChangeLastModifiedBy(username); app.setDataChangeLastModifiedBy(username);
}
AppDTO appDTO = BeanUtils.transfrom(AppDTO.class, app);
appAPI.createApp(env, appDTO);
}
@Transactional @Transactional
public App create(App app) { public App createAppInLocal(App app) {
String appId = app.getAppId(); String appId = app.getAppId();
App managedApp = appRepository.findByAppId(appId); App managedApp = appRepository.findByAppId(appId);
...@@ -125,6 +110,33 @@ public class AppService { ...@@ -125,6 +110,33 @@ public class AppService {
return createdApp; return createdApp;
} }
@Transactional
public App updateAppInLocal(App app) {
String appId = app.getAppId();
App managedApp = appRepository.findByAppId(appId);
if (managedApp == null) {
throw new BadRequestException(String.format("App not exists. AppId = %s", appId));
}
managedApp.setName(app.getName());
managedApp.setOrgId(app.getOrgId());
managedApp.setOrgName(app.getOrgName());
String ownerName = app.getOwnerName();
UserInfo owner = userService.findByUserId(ownerName);
if (owner == null) {
throw new BadRequestException(String.format("App's owner not exists. owner = %s", ownerName));
}
managedApp.setOwnerName(owner.getUserId());
managedApp.setOwnerEmail(owner.getEmail());
String operator = userInfoHolder.getUser().getUserId();
managedApp.setDataChangeLastModifiedBy(operator);
return appRepository.save(managedApp);
}
public EnvClusterInfo createEnvNavNode(Env env, String appId) { public EnvClusterInfo createEnvNavNode(Env env, String appId) {
EnvClusterInfo node = new EnvClusterInfo(env); EnvClusterInfo node = new EnvClusterInfo(env);
node.setClusters(clusterService.findClusters(env, appId)); node.setClusters(clusterService.findClusters(env, appId));
......
...@@ -25,71 +25,71 @@ ...@@ -25,71 +25,71 @@
创建项目 创建项目
</header> </header>
<div class="panel-body"> <form class="form-horizontal panel-body" name="appForm" ng-controller="CreateAppController"
<form class="form-horizontal" name="appForm" ng-controller="CreateAppController" valdr-type="App" valdr-type="App"
ng-submit="create()"> ng-submit="create()">
<div class="form-group"> <div class="form-group">
<label class="col-sm-3 control-label"> <label class="col-sm-3 control-label">
<apollorequiredfield></apollorequiredfield> <apollorequiredfield></apollorequiredfield>
部门</label> 部门</label>
<div class="col-sm-3"> <div class="col-sm-3">
<select id="organization"> <select id="organization">
<option></option> <option></option>
</select> </select>
</div>
</div> </div>
<div class="form-group" valdr-form-group> </div>
<label class="col-sm-3 control-label"> <div class="form-group" valdr-form-group>
<apollorequiredfield></apollorequiredfield> <label class="col-sm-3 control-label">
应用Id</label> <apollorequiredfield></apollorequiredfield>
<div class="col-sm-3"> 应用Id</label>
<input type="text" class="form-control" name="appId" ng-model="app.appId"> <div class="col-sm-3">
<small>(CMS上申请的App Id)</small> <input type="text" class="form-control" name="appId" ng-model="app.appId">
</div> <small>(CMS上申请的App Id)</small>
</div> </div>
<div class="form-group" valdr-form-group> </div>
<label class="col-sm-3 control-label"> <div class="form-group" valdr-form-group>
<apollorequiredfield></apollorequiredfield> <label class="col-sm-3 control-label">
应用名称</label> <apollorequiredfield></apollorequiredfield>
<div class="col-sm-5"> 应用名称</label>
<input type="text" class="form-control" name="appName" ng-model="app.name"> <div class="col-sm-5">
<small>(建议格式 xx-yy-zz 例:apollo-server)</small> <input type="text" class="form-control" name="appName" ng-model="app.name">
</div> <small>(建议格式 xx-yy-zz 例:apollo-server)</small>
</div> </div>
<div class="form-group"> </div>
<label class="col-sm-3 control-label"> <div class="form-group">
<apollorequiredfield></apollorequiredfield> <label class="col-sm-3 control-label">
应用负责人</label> <apollorequiredfield></apollorequiredfield>
<div class="col-sm-6 J_ownerSelectorPanel"> 应用负责人</label>
<apollouserselector apollo-id="'ownerSelector'"></apollouserselector> <div class="col-sm-6 J_ownerSelectorPanel">
</div> <apollouserselector apollo-id="'ownerSelector'"></apollouserselector>
</div> </div>
</div>
<div class="form-group"> <div class="form-group">
<label class="col-sm-3 control-label">项目管理员<br> <label class="col-sm-3 control-label">项目管理员<br>
</label> </label>
<div class="col-sm-9 J_adminSelectorPanel"> <div class="col-sm-9 J_adminSelectorPanel">
<apollomultipleuserselector apollo-id="'adminSelector'"></apollomultipleuserselector> <apollomultipleuserselector apollo-id="'adminSelector'"></apollomultipleuserselector>
<br> <br>
<small>(应用负责人默认具有项目管理员权限,</small> <small>(应用负责人默认具有项目管理员权限,</small>
<br> <br>
<small>项目管理员可以创建Namespace和集群、分配用户权限)</small> <small>项目管理员可以创建Namespace和集群、分配用户权限)</small>
</div>
</div> </div>
</div>
<div class="form-group"> <div class="form-group">
<div class="col-sm-offset-3 col-sm-9"> <div class="col-sm-offset-3 col-sm-9">
<button type="submit" class="btn btn-primary" <button type="submit" class="btn btn-primary"
ng-disabled="appForm.$invalid || submitBtnDisabled">提交 ng-disabled="appForm.$invalid || submitBtnDisabled">提交
</button> </button>
</div>
</div> </div>
</form> </div>
</div> </form>
</div> </div>
</div> </div>
</div> </div>
......
<!doctype html> <!doctype html>
<html ng-app="role"> <html ng-app="setting">
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="icon" href="../img/config.png"> <link rel="icon" href="../img/config.png">
...@@ -9,19 +9,19 @@ ...@@ -9,19 +9,19 @@
<link rel="stylesheet" type="text/css" media='all' href="../vendor/angular/loading-bar.min.css"> <link rel="stylesheet" type="text/css" media='all' href="../vendor/angular/loading-bar.min.css">
<link rel="stylesheet" type="text/css" href="../styles/common-style.css"> <link rel="stylesheet" type="text/css" href="../styles/common-style.css">
<link rel="stylesheet" type="text/css" href="../vendor/select2/select2.min.css"> <link rel="stylesheet" type="text/css" href="../vendor/select2/select2.min.css">
<title>权限管理</title> <title>项目管理</title>
</head> </head>
<body> <body>
<apollonav></apollonav> <apollonav></apollonav>
<div class="container-fluid apollo-container"> <div class="container-fluid apollo-container project-setting" ng-controller="SettingController">
<section class="panel col-md-offset-1 col-md-10" ng-controller="AppRoleController"> <section class="col-md-10 col-md-offset-1 panel hidden">
<header class="panel-heading"> <header class="panel-heading">
<div class="row"> <div class="row">
<div class="col-md-7"> <div class="col-md-7">
<h4 class="modal-title">权限管理<small>(AppId:<label ng-bind="pageContext.appId"></label> )</small> <h4 class="modal-title">项目管理 ( AppId:<label ng-bind="pageContext.appId"></label> )
</h4> </h4>
</div> </div>
<div class="col-md-5 text-right"> <div class="col-md-5 text-right">
...@@ -31,42 +31,127 @@ ...@@ -31,42 +31,127 @@
</div> </div>
</div> </div>
</header> </header>
<div class="panel-body" ng-show="hasAssignUserPermission">
<div class="row">
<div class="form-horizontal">
<div class="form-group">
<label class="col-sm-2 control-label">管理员<br><small>(可以创建Namespace<br>可以创建集群<br>可以分配用户权限)</small></label>
<div class="col-sm-8">
<form class="form-inline" ng-submit="assignMasterRoleToUser()">
<div class="form-group">
<apollouserselector apollo-id="userSelectWidgetId"></apollouserselector>
</div>
<button type="submit" class="btn btn-default" style="margin-left: 20px;" ng-disabled="submitBtnDisabled">添加</button>
</form>
<!-- Split button -->
<div class="item-container">
<div class="btn-group item-info" ng-repeat="user in appRoleUsers.masterUsers">
<button type="button" class="btn btn-default" ng-bind="user.userId"></button>
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false" ng-click="removeMasterRoleFromUser(user.userId)">
<span class="glyphicon glyphicon-remove"></span>
</button>
</div>
</div>
<div class="panel-body row">
<section class="context" ng-show="hasAssignUserPermission">
<!--project admin-->
<section class="form-horizontal">
<h5>管理员
<small>
(项目管理员具有以下权限: 1. 创建Namespace 2. 创建集群 3. 管理项目、Namespace权限)
</small>
</h5>
<hr>
<div class="col-md-offset-1">
<form class="form-inline" ng-submit="assignMasterRoleToUser()">
<div class="form-group" style="padding-left: 15px">
<apollouserselector apollo-id="userSelectWidgetId"></apollouserselector>
</div>
<button type="submit" class="btn btn-default" style="margin-left: 20px;"
ng-disabled="submitBtnDisabled">添加
</button>
</form>
<!-- Split button -->
<div class="item-container">
<div class="btn-group item-info" ng-repeat="user in appRoleUsers.masterUsers">
<button type="button" class="btn btn-default" ng-bind="user.userId"></button>
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false"
ng-click="removeMasterRoleFromUser(user.userId)">
<span class="glyphicon glyphicon-remove"></span>
</button>
</div>
</div> </div>
</div> </div>
</div>
</div>
</section>
<!--application info-->
<section>
<h5>基本信息</h5>
<hr>
<form class="form-horizontal" name="appForm" valdr-type="App"
ng-submit="updateAppInfo()">
<div class="form-group" valdr-form-group>
<label class="col-sm-2 control-label">
<apollorequiredfield></apollorequiredfield>
AppId</label>
<div class="col-sm-3">
<label class="form-control-static" ng-bind="pageContext.appId">
</label>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">
<apollorequiredfield></apollorequiredfield>
部门</label>
<div class="col-sm-3">
<select id="organization" ng-disabled="!display.app.edit">
<option></option>
</select>
</div>
</div>
<div class="form-group" valdr-form-group>
<label class="col-sm-2 control-label">
<apollorequiredfield></apollorequiredfield>
项目名称</label>
<div class="col-sm-4">
<input type="text" class="form-control" name="appName" ng-model="viewApp.name"
ng-disabled="!display.app.edit">
<small>(建议格式 xx-yy-zz 例:apollo-server)</small>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">
<apollorequiredfield></apollorequiredfield>
项目负责人</label>
<div class="col-sm-6 J_ownerSelectorPanel">
<apollouserselector apollo-id="'ownerSelector'"
disabled="!display.app.edit"></apollouserselector>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-9">
<button type="button" class="btn btn-primary"
ng-show="!display.app.edit"
ng-click="toggleEditStatus()">
修改项目信息
</button>
<button type="button" class="btn btn-warning"
ng-show="display.app.edit"
ng-click="toggleEditStatus()">
取消修改
</button>
<button type="submit" class="btn btn-primary"
ng-show="display.app.edit"
ng-disabled="appForm.$invalid || submitBtnDisabled">
提交
</button>
</div>
</div>
</form>
</section>
</section>
<section class="context" ng-show="!hasAssignUserPermission">
<div class="panel-body text-center">
<h4>您没有权限操作,请找 [{{admins.join(',')}}] 开通权限</h4>
</div>
</section>
</div> </div>
<div class="panel-body text-center" ng-show="!hasAssignUserPermission">
<h2>您没有权限哟!</h2>
</div>
<apolloconfirmdialog apollo-dialog-id="'warning'" apollo-title="'删除管理员'" <apolloconfirmdialog apollo-dialog-id="'warning'" apollo-title="'删除管理员'"
apollo-detail="'不能删除所有的管理员'" apollo-confirm="" apollo-detail="'不能删除所有的管理员'"
apollo-show-cancel-btn="false"></apolloconfirmdialog> apollo-show-cancel-btn="false"></apolloconfirmdialog>
</section> </section>
</div> </div>
...@@ -83,12 +168,16 @@ ...@@ -83,12 +168,16 @@
<script src="../vendor/angular/angular-toastr-1.4.1.tpls.min.js"></script> <script src="../vendor/angular/angular-toastr-1.4.1.tpls.min.js"></script>
<script src="../vendor/angular/loading-bar.min.js"></script> <script src="../vendor/angular/loading-bar.min.js"></script>
<!--valdr-->
<script src="../vendor/valdr/valdr.min.js" type="text/javascript"></script>
<script src="../vendor/valdr/valdr-message.min.js" type="text/javascript"></script>
<!-- bootstrap.js --> <!-- bootstrap.js -->
<script src="../vendor/bootstrap/js/bootstrap.min.js" type="text/javascript"></script> <script src="../vendor/bootstrap/js/bootstrap.min.js" type="text/javascript"></script>
<!--nicescroll--> <!--nicescroll-->
<script src="../vendor/jquery.nicescroll.min.js"></script> <script src="../vendor/jquery.nicescroll.min.js"></script>
<script src="../vendor/lodash.min.js"></script>
<script src="../vendor/select2/select2.min.js" type="text/javascript"></script> <script src="../vendor/select2/select2.min.js" type="text/javascript"></script>
<!--biz--> <!--biz-->
...@@ -98,12 +187,14 @@ ...@@ -98,12 +187,14 @@
<script type="application/javascript" src="../scripts/services/EnvService.js"></script> <script type="application/javascript" src="../scripts/services/EnvService.js"></script>
<script type="application/javascript" src="../scripts/services/UserService.js"></script> <script type="application/javascript" src="../scripts/services/UserService.js"></script>
<script type="application/javascript" src="../scripts/services/PermissionService.js"></script> <script type="application/javascript" src="../scripts/services/PermissionService.js"></script>
<script type="application/javascript" src="../scripts/services/OrganizationService.js"></script>
<script type="application/javascript" src="../scripts/AppUtils.js"></script> <script type="application/javascript" src="../scripts/AppUtils.js"></script>
<script type="application/javascript" src="../scripts/PageCommon.js"></script> <script type="application/javascript" src="../scripts/PageCommon.js"></script>
<script type="application/javascript" src="../scripts/directive/directive.js"></script> <script type="application/javascript" src="../scripts/directive/directive.js"></script>
<script type="application/javascript" src="../scripts/valdr.js"></script>
<script type="application/javascript" src="../scripts/controller/role/AppRoleController.js"></script> <script type="application/javascript" src="../scripts/controller/SettingController.js"></script>
</body> </body>
</html> </html>
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
<!--env list--> <!--env list-->
<section class="panel"> <section class="panel">
<header class="panel-heading"> <header class="panel-heading">
<img src="img/env.png" class="i-20">&nbsp;环境列表 环境列表
<span class="pull-right" <span class="pull-right"
data-tooltip="tooltip" data-placement="bottom" title="通过切换环境、集群来管理不同环境、集群的配置"> data-tooltip="tooltip" data-placement="bottom" title="通过切换环境、集群来管理不同环境、集群的配置">
<img src="img/question.png" class="i-20"/> <img src="img/question.png" class="i-20"/>
...@@ -47,16 +47,22 @@ ...@@ -47,16 +47,22 @@
<!--app info--> <!--app info-->
<section class="panel"> <section class="panel">
<header class="panel-heading"> <header class="panel-heading">
<img src="img/info.png" class="i-25-20"/> 项目信息 项目信息
<span class="pull-right cursor-pointer"> <span class="pull-right">
<a ng-if="!favoriteId" ng-click="addFavorite()"
data-tooltip="tooltip" data-placement="bottom" title="收藏"> <a href="/app/setting.html?#/appid={{pageContext.appId}}"
<img src="img/unlike.png" class="i-20"/> style="margin-right: 5px;text-decoration:none;">
</a> <img src="img/edit.png" class="i-20 cursor-pointer"
<a ng-if="favoriteId" ng-click="deleteFavorite()" data-tooltip="tooltip" data-placement="bottom" title="修改项目基本信息"/>
data-tooltip="tooltip" data-placement="bottom" title="取消收藏">
<img src="img/like.png" class="i-20"/>
</a> </a>
<img src="img/unlike.png" class="i-20 cursor-pointer"
ng-if="!favoriteId" ng-click="addFavorite()"
data-tooltip="tooltip" data-placement="bottom" title="收藏"/>
<img src="img/like.png" class="i-20 cursor-pointer"
ng-if="favoriteId" ng-click="deleteFavorite()"
data-tooltip="tooltip" data-placement="bottom" title="取消收藏"/>
</span> </span>
</header> </header>
<div class="panel-body"> <div class="panel-body">
...@@ -101,6 +107,9 @@ ...@@ -101,6 +107,9 @@
<!--operation entrance--> <!--operation entrance-->
<section> <section>
<apolloentrance apollo-title="'管理项目'" apollo-img-src="'project-manage'"
apollo-href="'/app/setting.html?#/appid=' + pageContext.appId"></apolloentrance>
<a class="list-group-item" ng-show="missEnvs.length > 0" ng-click="createAppInMissEnv()"> <a class="list-group-item" ng-show="missEnvs.length > 0" ng-click="createAppInMissEnv()">
<div class="row icon-text icon-plus-orange"> <div class="row icon-text icon-plus-orange">
<p class="btn-title ng-binding">补缺环境</p> <p class="btn-title ng-binding">补缺环境</p>
...@@ -129,9 +138,7 @@ ...@@ -129,9 +138,7 @@
</div> </div>
</div> </div>
<apolloentrance apollo-title="'项目权限'" apollo-img-src="'user-manage'"
apollo-href="'/app/role.html?#/appid=' + pageContext.appId"
ng-show="hasAssignUserPermission"></apolloentrance>
</section> </section>
</div> </div>
...@@ -169,14 +176,14 @@ ...@@ -169,14 +176,14 @@
<span ng-bind="pageContext.clusterName"></span> <span ng-bind="pageContext.clusterName"></span>
集群的实例只会使用 集群的实例只会使用
<span ng-bind="pageContext.clusterName"></span> <span ng-bind="pageContext.clusterName"></span>
集群(当前页面)的配置,只有当对应namespace在当前集群没有发布过配置时,才会使用default集群的配置 集群(当前页面)的配置,只有当对应namespace在当前集群没有发布过配置时,才会使用default集群的配置
</div> </div>
</div> </div>
<div class="alert alert-info" <div class="alert alert-info"
ng-if="hasNotPublishNamespace"> ng-if="hasNotPublishNamespace">
<p><b>注意:</b>以下环境/集群有未发布的配置,客户端获取不到未发布的配置,请及时发布。</p> <p><b>注意:</b> 以下环境/集群有未发布的配置,客户端获取不到未发布的配置,请及时发布。</p>
<p> <p>
<mark ng-bind="namespacePublishInfo.join(',')"></mark> <mark ng-bind="namespacePublishInfo.join(',')"></mark>
</p> </p>
......
<svg height="1024" width="896" xmlns="http://www.w3.org/2000/svg">
<path d="M128 768h256v64H128v-64z m320-384H128v64h320v-64z m128 192V448L384 640l192 192V704h320V576H576z m-288-64H128v64h160v-64zM128 704h160v-64H128v64z m576 64h64v128c-1 18-7 33-19 45s-27 18-45 19H64c-35 0-64-29-64-64V192c0-35 29-64 64-64h192C256 57 313 0 384 0s128 57 128 128h192c35 0 64 29 64 64v320h-64V320H64v576h640V768zM128 256h512c0-35-29-64-64-64h-64c-35 0-64-29-64-64s-29-64-64-64-64 29-64 64-29 64-64 64h-64c-35 0-64 29-64 64z" />
</svg>
...@@ -28,6 +28,12 @@ appUtil.service('AppUtil', ['toastr', '$window', function (toastr, $window) { ...@@ -28,6 +28,12 @@ appUtil.service('AppUtil', ['toastr', '$window', function (toastr, $window) {
if (query.indexOf('/') == 0) { if (query.indexOf('/') == 0) {
query = query.substring(1, query.length); query = query.substring(1, query.length);
} }
var anchorIndex = query.indexOf('#');
if (anchorIndex >= 0) {
query = query.substring(0, anchorIndex);
}
var params = query.split("&"); var params = query.split("&");
var result = {}; var result = {};
params.forEach(function (param) { params.forEach(function (param) {
......
...@@ -20,6 +20,8 @@ var sync_item_module = angular.module('sync_item', ['app.service', 'apollo.direc ...@@ -20,6 +20,8 @@ var sync_item_module = angular.module('sync_item', ['app.service', 'apollo.direc
var namespace_module = angular.module('namespace', ['app.service', 'apollo.directive', 'app.util', 'toastr', 'angular-loading-bar', 'valdr']); var namespace_module = angular.module('namespace', ['app.service', 'apollo.directive', 'app.util', 'toastr', 'angular-loading-bar', 'valdr']);
//server config //server config
var server_config_module = angular.module('server_config', ['app.service', 'apollo.directive', 'app.util', 'toastr', 'angular-loading-bar']); var server_config_module = angular.module('server_config', ['app.service', 'apollo.directive', 'app.util', 'toastr', 'angular-loading-bar']);
//setting
var setting_module = angular.module('setting', ['app.service', 'apollo.directive', 'app.util', 'toastr', 'angular-loading-bar', 'valdr']);
//role //role
var role_module = angular.module('role', ['app.service', 'apollo.directive', 'app.util', 'toastr', 'angular-loading-bar']); var role_module = angular.module('role', ['app.service', 'apollo.directive', 'app.util', 'toastr', 'angular-loading-bar']);
//cluster //cluster
......
...@@ -51,7 +51,7 @@ function createAppController($scope, $window, toastr, AppService, AppUtil, Organ ...@@ -51,7 +51,7 @@ function createAppController($scope, $window, toastr, AppService, AppUtil, Organ
// owner // owner
var owner = $('.ownerSelector').select2('data')[0]; var owner = $('.ownerSelector').select2('data')[0];
if (!owner) { if (!owner) {
toastr.warning("输入应用负责人"); toastr.warning("选择应用负责人");
return; return;
} }
$scope.app.ownerName = owner.id; $scope.app.ownerName = owner.id;
......
setting_module.controller('SettingController',
['$scope', '$location', 'toastr',
'AppService', 'AppUtil', 'PermissionService',
'OrganizationService',
SettingController]);
function SettingController($scope, $location, toastr,
AppService, AppUtil, PermissionService,
OrganizationService) {
var params = AppUtil.parseParams($location.$$url);
var $orgWidget = $('#organization');
$scope.pageContext = {
appId: params.appid
};
$scope.display = {
app: {
edit: false
}
};
$scope.submitBtnDisabled = false;
$scope.userSelectWidgetId = 'toAssignMasterRoleUser';
$scope.assignMasterRoleToUser = assignMasterRoleToUser;
$scope.removeMasterRoleFromUser = removeMasterRoleFromUser;
$scope.toggleEditStatus = toggleEditStatus;
$scope.updateAppInfo = updateAppInfo;
init();
function init() {
initOrganization();
initPermission();
initAdmins();
initApplication();
}
function initOrganization() {
OrganizationService.find_organizations().then(function (result) {
var organizations = [];
result.forEach(function (item) {
var org = {};
org.id = item.orgId;
org.text = item.orgName + '(' + item.orgId + ')';
org.name = item.orgName;
organizations.push(org);
});
$orgWidget.select2({
placeholder: '请选择部门',
width: '100%',
data: organizations
});
}, function (result) {
toastr.error(AppUtil.errorMsg(result), "load organizations error");
});
}
function initPermission() {
PermissionService.has_assign_user_permission($scope.pageContext.appId)
.then(function (result) {
$scope.hasAssignUserPermission = result.hasPermission;
});
}
function initAdmins() {
PermissionService.get_app_role_users($scope.pageContext.appId)
.then(function (result) {
$scope.appRoleUsers = result;
$scope.admins = [];
$scope.appRoleUsers.masterUsers.forEach(function (user) {
$scope.admins.push(user.userId);
});
});
}
function initApplication() {
AppService.load($scope.pageContext.appId).then(function (app) {
$scope.app = app;
$scope.viewApp = _.clone(app);
initAppForm(app);
$('.project-setting .panel').removeClass('hidden');
})
}
function initAppForm(app) {
$orgWidget.val(app.orgId).trigger("change");
var $ownerSelector = $('.ownerSelector');
var defaultSelectedDOM = '<option value="' + app.ownerName + '" selected="selected">' + app.ownerName
+ '</option>';
$ownerSelector.append(defaultSelectedDOM);
$ownerSelector.trigger('change');
}
function assignMasterRoleToUser() {
var user = $('.' + $scope.userSelectWidgetId).select2('data')[0];
if (!user) {
toastr.warning("请选择用户");
return;
}
var toAssignMasterRoleUser = user.id;
$scope.submitBtnDisabled = true;
PermissionService.assign_master_role($scope.pageContext.appId,
toAssignMasterRoleUser)
.then(function (result) {
$scope.submitBtnDisabled = false;
toastr.success("添加成功");
$scope.appRoleUsers.masterUsers.push({userId: toAssignMasterRoleUser});
$('.' + $scope.userSelectWidgetId).select2("val", "");
}, function (result) {
$scope.submitBtnDisabled = false;
toastr.error(AppUtil.errorMsg(result), "添加失败");
});
}
function removeMasterRoleFromUser(user) {
if ($scope.appRoleUsers.masterUsers.length <= 1) {
$('#warning').modal('show');
return;
}
PermissionService.remove_master_role($scope.pageContext.appId, user)
.then(function (result) {
toastr.success("删除成功");
removeUserFromList($scope.appRoleUsers.masterUsers, user);
}, function (result) {
toastr.error(AppUtil.errorMsg(result), "删除失败");
});
}
function removeUserFromList(list, user) {
var index = 0;
for (var i = 0; i < list.length; i++) {
if (list[i].userId == user) {
index = i;
break;
}
}
list.splice(index, 1);
}
function toggleEditStatus() {
if ($scope.display.app.edit) {//cancel edit
$scope.viewApp = _.clone($scope.app);
initAppForm($scope.viewApp);
} else {//edit
}
$scope.display.app.edit = !$scope.display.app.edit;
}
function updateAppInfo() {
$scope.submitBtnDisabled = true;
var app = $scope.viewApp;
var selectedOrg = $orgWidget.select2('data')[0];
if (!selectedOrg.id) {
toastr.warning("请选择部门");
return;
}
app.orgId = selectedOrg.id;
app.orgName = selectedOrg.name;
// owner
var owner = $('.ownerSelector').select2('data')[0];
if (!owner) {
toastr.warning("请选择应用负责人");
return;
}
app.ownerName = owner.id;
AppService.update(app).then(function (app) {
toastr.success("修改成功");
initApplication();
$scope.display.app.edit = false;
$scope.submitBtnDisabled = false;
}, function (result) {
AppUtil.showErrorMsg(result);
$scope.submitBtnDisabled = false;
})
}
}
role_module.controller('AppRoleController',
['$scope', '$location', '$window', 'toastr', 'AppService', 'AppUtil', 'PermissionService',
function ($scope, $location, $window, toastr, AppService, AppUtil, PermissionService) {
var params = AppUtil.parseParams($location.$$url);
$scope.pageContext = {
appId: params.appid
};
$scope.submitBtnDisabled = false;
$scope.userSelectWidgetId = 'toAssignMasterRoleUser';
PermissionService.has_assign_user_permission($scope.pageContext.appId)
.then(function (result) {
$scope.hasAssignUserPermission = result.hasPermission;
}, function (reslt) {
});
PermissionService.get_app_role_users($scope.pageContext.appId)
.then(function (result) {
$scope.appRoleUsers = result;
}, function (result) {
});
$scope.assignMasterRoleToUser = function () {
var user = $('.' + $scope.userSelectWidgetId).select2('data')[0];
if (!user){
toastr.warning("请选择用户");
return;
}
var toAssignMasterRoleUser = user.id;
$scope.submitBtnDisabled = true;
PermissionService.assign_master_role($scope.pageContext.appId,
toAssignMasterRoleUser)
.then(function (result) {
$scope.submitBtnDisabled = false;
toastr.success("添加成功");
$scope.appRoleUsers.masterUsers.push({userId: toAssignMasterRoleUser});
$('.' + $scope.userSelectWidgetId).select2("val", "");
}, function (result) {
$scope.submitBtnDisabled = false;
toastr.error(AppUtil.errorMsg(result), "添加失败");
});
};
$scope.removeMasterRoleFromUser = function (user) {
if ($scope.appRoleUsers.masterUsers.length <= 1) {
$('#warning').modal('show');
return;
}
PermissionService.remove_master_role($scope.pageContext.appId, user)
.then(function (result) {
toastr.success("删除成功");
removeUserFromList($scope.appRoleUsers.masterUsers, user);
}, function (result) {
toastr.error(AppUtil.errorMsg(result), "删除失败");
});
};
function removeUserFromList(list, user) {
var index = 0;
for (var i = 0; i < list.length; i++) {
if (list[i].userId == user) {
index = i;
break;
}
}
list.splice(index, 1);
}
}]);
...@@ -275,13 +275,14 @@ directive_module.directive('apollouserselector', function ($compile, $window) { ...@@ -275,13 +275,14 @@ directive_module.directive('apollouserselector', function ($compile, $window) {
transclude: true, transclude: true,
replace: true, replace: true,
scope: { scope: {
id: '=apolloId' id: '=apolloId',
disabled: '='
}, },
link: function (scope, element, attrs) { link: function (scope, element, attrs) {
scope.$watch("id", initSelect2); scope.$watch("id", initSelect2);
var searchUsersAjax = { var select2Options = {
ajax: { ajax: {
url: '/users', url: '/users',
dataType: 'json', dataType: 'json',
...@@ -311,8 +312,9 @@ directive_module.directive('apollouserselector', function ($compile, $window) { ...@@ -311,8 +312,9 @@ directive_module.directive('apollouserselector', function ($compile, $window) {
}; };
function initSelect2() { function initSelect2() {
$('.' + scope.id).select2(searchUsersAjax); $('.' + scope.id).select2(select2Options);
} }
} }
} }
......
...@@ -11,7 +11,7 @@ appService.service('AppService', ['$resource', '$q', function ($resource, $q) { ...@@ -11,7 +11,7 @@ appService.service('AppService', ['$resource', '$q', function ($resource, $q) {
url: '/apps/by-owner' url: '/apps/by-owner'
}, },
load_navtree: { load_navtree: {
methode: 'GET', method: 'GET',
isArray: false, isArray: false,
url: '/apps/:appId/navtree' url: '/apps/:appId/navtree'
}, },
...@@ -23,6 +23,10 @@ appService.service('AppService', ['$resource', '$q', function ($resource, $q) { ...@@ -23,6 +23,10 @@ appService.service('AppService', ['$resource', '$q', function ($resource, $q) {
method: 'POST', method: 'POST',
url: '/apps' url: '/apps'
}, },
update_app: {
method: 'PUT',
url: '/apps/:appId'
},
create_app_remote: { create_app_remote: {
method: 'POST', method: 'POST',
url: '/apps/envs/:env' url: '/apps/envs/:env'
...@@ -78,6 +82,17 @@ appService.service('AppService', ['$resource', '$q', function ($resource, $q) { ...@@ -78,6 +82,17 @@ appService.service('AppService', ['$resource', '$q', function ($resource, $q) {
}); });
return d.promise; return d.promise;
}, },
update: function (app) {
var d = $q.defer();
app_resource.update_app({
appId: app.appId
}, app, function (result) {
d.resolve(result);
}, function (result) {
d.reject(result);
});
return d.promise;
},
create_remote: function (env, app) { create_remote: function (env, app) {
var d = $q.defer(); var d = $q.defer();
app_resource.create_app_remote({env: env}, app, function (result) { app_resource.create_app_remote({env: env}, app, function (result) {
......
app_module.config(function (valdrProvider) { app_module.config(appValdr);
setting_module.config(appValdr);
function appValdr(valdrProvider) {
valdrProvider.addConstraints({ valdrProvider.addConstraints({
'App': { 'App': {
'appId': { 'appId': {
...@@ -21,7 +24,7 @@ app_module.config(function (valdrProvider) { ...@@ -21,7 +24,7 @@ app_module.config(function (valdrProvider) {
} }
} }
}) })
}); }
cluster_module.config(function (valdrProvider) { cluster_module.config(function (valdrProvider) {
valdrProvider.addConstraints({ valdrProvider.addConstraints({
......
...@@ -144,6 +144,7 @@ pre { ...@@ -144,6 +144,7 @@ pre {
.footer { .footer {
width: 100%; width: 100%;
height: 75px; height: 75px;
margin-top: 50px;
padding-top: 25px; padding-top: 25px;
} }
...@@ -494,14 +495,15 @@ table th { ...@@ -494,14 +495,15 @@ table th {
margin: 0; margin: 0;
} }
.list-group-item .icon-plus-orange { .list-group-item .icon-project-manage {
background: url(../img/plus-orange.png) no-repeat; background: url(../img/manage.png) no-repeat;
} }
.list-group-item .icon-user-manage { .list-group-item .icon-plus-orange {
background: url(../img/user_manage.png) no-repeat; background: url(../img/add.png) no-repeat;
} }
.list-group-item .icon-text { .list-group-item .icon-text {
background-size: 20px; background-size: 20px;
background-position: 5% 50%; background-position: 5% 50%;
...@@ -790,3 +792,11 @@ table th { ...@@ -790,3 +792,11 @@ table th {
background: #fff; background: #fff;
} }
.project-setting .panel-body {
padding-top: 35px
}
.project-setting .panel-body .context {
padding-left: 30px;
}
...@@ -22,14 +22,14 @@ ...@@ -22,14 +22,14 @@
<ul class="nav navbar-nav navbar-right"> <ul class="nav navbar-nav navbar-right">
<li> <li>
<a href="http://conf.ctripcorp.com/display/FRAM/Apollo" target="_blank"> <a href="http://conf.ctripcorp.com/display/FRAM/Apollo" target="_blank">
<span class="glyphicon glyphicon-question-sign"></span>帮助 <span class="glyphicon glyphicon-question-sign"></span> 帮助
</a> </a>
</li> </li>
<li class="dropdown"> <li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" <a class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false"><span class="glyphicon glyphicon-user"></span>{{userName}} <span aria-expanded="false"><span class="glyphicon glyphicon-user"></span> {{userName}} <span
class="caret"></span></a> class="caret"></span></a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><a href="/user/logout">退出</a></li> <li><a href="/user/logout">退出</a></li>
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
<div class="navbar-form navbar-right form-inline" role="search"> <div class="navbar-form navbar-right form-inline" role="search">
<div class="form-group"> <div class="form-group">
<input type="text" class="form-control search-input" placeholder="搜索项目(项目ID、项目名)" <input type="text" class="form-control search-input" placeholder="搜索项目(AppId、项目名)"
style="width: 350px" style="width: 350px"
ng-model="searchKey" ng-change="changeSearchKey()" ng-focus="changeSearchKey()"> ng-model="searchKey" ng-change="changeSearchKey()" ng-focus="changeSearchKey()">
......
<select class="{{id}}" style="width: 450px;"> <select class="{{id}}" style="width: 450px;" ng-disabled="disabled">
</select> </select>
...@@ -51,7 +51,7 @@ public class ServiceExceptionTest extends AbstractUnitTest { ...@@ -51,7 +51,7 @@ public class ServiceExceptionTest extends AbstractUnitTest {
new HttpServerErrorException(HttpStatus.INTERNAL_SERVER_ERROR, "admin server error", new HttpServerErrorException(HttpStatus.INTERNAL_SERVER_ERROR, "admin server error",
new Gson().toJson(errorAttributes).getBytes(), Charset.defaultCharset()); new Gson().toJson(errorAttributes).getBytes(), Charset.defaultCharset());
when(appService.create(any())).thenThrow(adminException); when(appService.createAppInLocal(any())).thenThrow(adminException);
AppModel app = generateSampleApp(); AppModel app = generateSampleApp();
try { try {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册