Commit 6698804e by lepdou

add miss envs

parent 536eb044
......@@ -27,5 +27,4 @@ public class API {
public String getAdminServiceHost(Env env) {
return serviceLocator.getAdminService(env).getHomepageUrl();
}
}
......@@ -12,6 +12,7 @@ import com.ctrip.apollo.core.dto.AppDTO;
import com.ctrip.apollo.core.enums.Env;
import com.ctrip.apollo.core.exception.BadRequestException;
import com.ctrip.apollo.core.utils.StringUtils;
import com.ctrip.apollo.portal.entity.AppInfoVO;
import com.ctrip.apollo.portal.entity.ClusterNavTree;
import com.ctrip.apollo.portal.service.AppService;
......@@ -25,7 +26,7 @@ public class AppController {
private AppService appService;
@RequestMapping("/env/{env}")
@RequestMapping("/envs/{env}")
public List<AppDTO> findAllApp(@PathVariable String env){
if (StringUtils.isEmpty(env)){
throw new BadRequestException("env can not be empty");
......@@ -42,17 +43,21 @@ public class AppController {
return appService.buildClusterNavTree(appId);
}
@RequestMapping(value = "", method = RequestMethod.POST, consumes = {"application/json"})
public ResponseEntity<Void> create(@RequestBody AppDTO app) {
@RequestMapping(value = "/envs/{env}", method = RequestMethod.POST, consumes = {"application/json"})
public ResponseEntity<Void> create(@PathVariable String env, @RequestBody AppDTO app) {
if (isInvalidApp(app)){
throw new BadRequestException("request payload contains empty");
}
appService.save(app);
if ("ALL".equals(env)){
appService.save(app);
} else {
appService.save(Env.valueOf(env), app);
}
return ResponseEntity.ok().build();
}
@RequestMapping(value = "/{appId}", method = RequestMethod.GET)
public AppDTO load(@PathVariable String appId){
public AppInfoVO load(@PathVariable String appId){
if (StringUtils.isEmpty(appId)){
throw new BadRequestException("app id can not be empty.");
}
......
package com.ctrip.apollo.portal.entity;
import com.ctrip.apollo.core.dto.AppDTO;
import com.ctrip.apollo.core.enums.Env;
import java.util.List;
public class AppInfoVO {
private AppDTO app;
/**
* 在创建app的时候可能在某些环境下创建失败
*/
private List<Env> missEnvs;
public AppDTO getApp() {
return app;
}
public void setApp(AppDTO app) {
this.app = app;
}
public List<Env> getMissEnvs() {
return missEnvs;
}
public void setMissEnvs(List<Env> missEnvs) {
this.missEnvs = missEnvs;
}
}
package com.ctrip.apollo.portal.service;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import org.slf4j.Logger;
......@@ -17,6 +19,7 @@ import com.ctrip.apollo.core.exception.BadRequestException;
import com.ctrip.apollo.core.exception.ServiceException;
import com.ctrip.apollo.portal.PortalSettings;
import com.ctrip.apollo.portal.api.AdminServiceAPI;
import com.ctrip.apollo.portal.entity.AppInfoVO;
import com.ctrip.apollo.portal.entity.ClusterNavTree;
@Service
......@@ -37,16 +40,19 @@ public class AppService {
return appAPI.findApps(env);
}
public AppDTO load(String appId) {
public AppInfoVO load(String appId) {
//轮询环境直到能找到此app的信息
AppDTO app = null;
List<Env> missEnvs = new LinkedList<>();
for (Env env : portalSettings.getEnvs()) {
try {
app = appAPI.loadApp(env, appId);
break;
} catch (HttpClientErrorException e) {
//not exist maybe because create app fail.
if (e.getStatusCode() == HttpStatus.NOT_FOUND) {
missEnvs.add(env);
logger.warn("app:{} in {} not exist", appId, env);
} else {
logger.error("load app info({}) from env:{} error.", appId, env);
......@@ -54,11 +60,15 @@ public class AppService {
}
}
}
if (app == null){
if (app == null) {
throw new BadRequestException(String.format("invalid app id %s", appId));
}
return app;
AppInfoVO appInfo = new AppInfoVO();
appInfo.setApp(app);
appInfo.setMissEnvs(missEnvs);
return appInfo;
}
......@@ -86,4 +96,13 @@ public class AppService {
}
}
public void save(Env env, AppDTO app) {
try {
appAPI.save(env, app);
} catch (HttpStatusCodeException e) {
logger.error(ExceptionUtils.toString(e));
throw e;
}
}
}
......@@ -79,6 +79,7 @@
<script type="application/javascript" src="scripts/app.js"></script>
<script type="application/javascript" src="scripts/services/AppService.js"></script>
<script type="application/javascript" src="scripts/services/EnvService.js"></script>
<script type="application/javascript" src="scripts/AppUtils.js"></script>
<script type="application/javascript" src="scripts/controller/IndexController.js"></script>
</body>
</html>
appUtil.service('AppUtil', [function () {
return {
errorMsg: function (response) {
var msg = "Code:" + response.status;
if (response.data.message != null){
msg += " Msg:" + response.data.message;
}
return msg;
}
}
}]);
/**service module 定义*/
var appService = angular.module('app.service', ['ngResource']);
/**utils*/
var appUtil = angular.module('app.util', []);
/** page module 定义*/
// 首页
var index_module = angular.module('index', ['toastr', 'app.service', 'angular-loading-bar']);
var index_module = angular.module('index', ['toastr', 'app.service', 'app.util', 'angular-loading-bar']);
//项目主页
var application_module = angular.module('application', ['app.service', 'toastr', 'angular-loading-bar']);
var application_module = angular.module('application', ['app.service', 'app.util', 'toastr', 'angular-loading-bar']);
//创建项目页面
var create_app_module = angular.module('create_app', ['ngResource', 'toastr', 'app.service', 'angular-loading-bar']);
var create_app_module = angular.module('create_app', ['ngResource', 'toastr', 'app.service', 'app.util', 'angular-loading-bar']);
......
create_app_module.controller('CreateAppController', ['$scope', '$window', 'toastr', 'AppService',
function ($scope, $window, toastr, AppService) {
create_app_module.controller('CreateAppController', ['$scope', '$window', 'toastr', 'AppService', 'AppUtil',
function ($scope, $window, toastr, AppService, AppUtil) {
$scope.save = function () {
AppService.add($scope.app).then(function (result) {
$scope.create = function () {
AppService.create('ALL', $scope.app).then(function (result) {
toastr.success('添加成功!');
setInterval(function () {
$window.location.href = '/views/app.html?#appid=' + result.appId;
}, 1000);
}, function (result) {
toastr.error(result.status + result.data.message, '添加失败!');
toastr.error(AppUtil.errorMsg(result), '添加失败!');
});
};
......
index_module.controller('IndexController', ['$scope', '$window', 'toastr', 'AppService', 'EnvService',
function ($scope, $window, toastr, AppService, EnvService) {
index_module.controller('IndexController', ['$scope', '$window', 'toastr', 'AppService', 'AppUtil', 'EnvService',
function ($scope, $window, toastr, AppService, AppUtil, EnvService) {
$scope.envs = [];
$scope.selectedEnv = '';
......@@ -8,7 +8,7 @@ index_module.controller('IndexController', ['$scope', '$window', 'toastr', 'AppS
//default select first env
$scope.switchEnv($scope.envs[0]);
}, function (result) {
toastr.error(result.status + result.data.message, "load env error");
toastr.error(AppUtil.errorMsg(result), "load env error");
});
var apps = [];
......@@ -25,7 +25,7 @@ index_module.controller('IndexController', ['$scope', '$window', 'toastr', 'AppS
$scope.appsCount = apps.length;
$scope.selectedEnv = env;
}, function (result) {
toastr.error(result.status + result.data.message, "load apps error");
toastr.error(AppUtil.errorMsg(result), "load apps error");
});
};
......
application_module.controller("AppConfigController",
['$scope', '$location', 'toastr', 'AppService', 'ConfigService',
function ($scope, $location, toastr, AppService, ConfigService) {
['$scope', '$location', 'toastr', 'AppService', 'AppUtil', 'ConfigService',
function ($scope, $location, toastr, AppService, AppUtil, ConfigService) {
var appId = $location.$$url.split("=")[1];
var currentUser = 'test_user';
......@@ -12,7 +12,7 @@ application_module.controller("AppConfigController",
$scope.pageContext = pageContext;
///////////// load cluster nav tree /////////
////// load cluster nav tree //////
AppService.load_nav_tree($scope.pageContext.appId).then(function (result) {
var navTree = [];
......@@ -58,18 +58,20 @@ application_module.controller("AppConfigController",
}
});
}, function (result) {
toastr.error(result.status + result.data.message, "加载导航出错");
toastr.error(AppUtil.errorMsg(result), "加载导航出错");
});
/////////// app info ////////////
////// app info //////
AppService.load($scope.pageContext.appId).then(function (result) {
$scope.appInfo = result;
$scope.appBaseInfo = result.app;
$scope.missEnvs = result.missEnvs;
$scope.selectedEnvs = angular.copy($scope.missEnvs);
},function (result) {
toastr.error(result.status + result.data.message, "加载App信息出错");
toastr.error(AppUtil.errorMsg(result), "加载App信息出错");
});
/////////// namespace ////////////
////// namespace //////
var namespace_view_type = {
TEXT:'text',
......@@ -103,11 +105,11 @@ application_module.controller("AppConfigController",
}
}, function (result) {
toastr.error(result.status + result.data.message, "加载配置信息出错");
toastr.error(AppUtil.errorMsg(result), "加载配置信息出错");
});
}
////////////global view oper /////////////
////// global view oper //////
$scope.switchView = function (namespace, viewType) {
......@@ -138,7 +140,7 @@ application_module.controller("AppConfigController",
return result;
}
////////// text view oper /////////
////// text view oper //////
$scope.draft = {};
//保存草稿
......@@ -161,7 +163,7 @@ application_module.controller("AppConfigController",
$scope.toggleTextEditStatus($scope.draft);
}, function (result) {
toastr.error(result.status + result.data.message, "更新失败");
toastr.error(AppUtil.errorMsg(result), "更新失败");
}
);
......@@ -169,6 +171,7 @@ application_module.controller("AppConfigController",
$scope.isItemsViewOpened = true;
$scope.toggleItemView = function (isOpened) {
$scope.isItemsViewOpened = isOpened;
};
......@@ -185,7 +188,7 @@ application_module.controller("AppConfigController",
}
};
////////// table view oper /////////
////// table view oper //////
//查看旧值
$scope.queryOldValue = function (key, oldValue) {
......@@ -215,11 +218,47 @@ application_module.controller("AppConfigController",
refreshNamespaces();
}, function (result) {
toastr.error(result.status + result.data.message, "发布失败");
toastr.error(AppUtil.errorMsg(result), "发布失败");
}
);
}
////// create env //////
$scope.toggleSelection = function toggleSelection(env) {
var idx = $scope.selectedEnvs.indexOf(env);
// is currently selected
if (idx > -1) {
$scope.selectedEnvs.splice(idx, 1);
}
// is newly selected
else {
$scope.selectedEnvs.push(env);
}
};
$scope.createEnvs = function () {
var count = 0;
$scope.selectedEnvs.forEach(function (env) {
AppService.create(env, $scope.appBaseInfo).then(function (result) {
toastr.success(env, '创建成功');
count ++;
if (count == $scope.selectedEnvs){
$route.reload();
}
}, function (result) {
toastr.error(AppUtil.errorMsg(result), '创建失败:' + env);
count ++;
if (count == $scope.selectedEnvs){
$route.reload();
}
});
});
};
}]);
......@@ -3,7 +3,7 @@ appService.service('AppService', ['$resource', '$q', function ($resource, $q) {
find_all_app:{
method: 'GET',
isArray: true,
url:'/apps/env/:env'
url:'/apps/envs/:env'
},
load_navtree:{
methode: 'GET',
......@@ -14,9 +14,9 @@ appService.service('AppService', ['$resource', '$q', function ($resource, $q) {
method: 'GET',
isArray: false
},
add_app: {
create_app: {
method: 'POST',
url: '/apps'
url: '/apps/envs/:env'
}
});
return {
......@@ -42,9 +42,9 @@ appService.service('AppService', ['$resource', '$q', function ($resource, $q) {
});
return d.promise;
},
add: function (app) {
create: function (env, app) {
var d = $q.defer();
app_resource.add_app({}, app, function (result) {
app_resource.create_app({env:env}, app, function (result) {
d.resolve(result);
}, function (result) {
d.reject(result);
......
......@@ -16,6 +16,21 @@ a {
cursor: pointer;
}
.i-20{
height: 20px;
width: 20px;
}
.i-25-20{
height: 20px;
width: 25px;
}
.i-15{
height: 15px;
width: 15px;
}
.apollo-container {
min-height: 90%;
}
......@@ -122,6 +137,12 @@ table th {
font-weight: 300;
}
.project-info th {
text-align: right;
padding: 4px 6px;
white-space: nowrap;
}
.project-info td {
word-wrap: break-word;
word-break: break-all;
......
......@@ -28,35 +28,71 @@
<!--app info-->
<section class="panel">
<header class="panel-heading">
应用信息
<span class="tools pull-right">
<a href="javascript:;" class="icon-chevron-down"></a>
</span>
<img src="../img/info.png" class="i-25-20"/> 应用信息
<span class="tools pull-right">
<a href="javascript:;" class="icon-chevron-down"></a>
</span>
</header>
<div class="panel-body">
<table class="project-info">
<tbody>
<tr>
<th>应用ID:</th>
<td>{{appInfo.appId}}</td>
<td>{{appBaseInfo.appId}}</td>
</tr>
<tr>
<th>应用名:</th>
<td>{{appInfo.name}}</td>
<td>{{appBaseInfo.name}}</td>
</tr>
<tr>
<th>Owner:</th>
<td>{{appInfo.ownerName}}</td>
<td>{{appBaseInfo.ownerName}}</td>
</tr>
<tr>
<th>Owner Email:</th>
<td>{{appInfo.ownerEmail}}</td>
<td>{{appBaseInfo.ownerEmail}}</td>
</tr>
<tr ng-show="missEnvs.length > 0">
<th>缺失的环境:</th>
<td>
<font ng-repeat="env in missEnvs">
{{env}}
</font>
</td>
</tr>
</tbody>
</table>
</div>
</section>
<a class="list-group-item" data-toggle="modal" data-target="#createEnvModal" ng-show="missEnvs.length > 0">
<div class="row">
<div class="col-md-2"><img src="../img/plus.png" class="i-20"></div>
<div class="col-md-7 hidden-xs">
<p class="apps-description">添加环境</p>
</div>
</div>
</a>
<a class="list-group-item" target="_blank" href="/views/app.html?#/appid={{app.appId}}">
<div class="row">
<div class="col-md-2"><img src="../img/plus.png" class="i-20"></div>
<div class="col-md-7 hidden-xs">
<p class="apps-description">添加集群</p>
</div>
</div>
</a>
<a class="list-group-item" target="_blank" href="/views/app.html?#/appid={{app.appId}}">
<div class="row">
<div class="col-md-2"><img src="../img/plus.png" class="i-20"></div>
<div class="col-md-7 hidden-xs">
<p class="apps-description">添加Namespace</p>
</div>
</div>
</a>
</section>
</div>
<div class="col-md-9 config-item-container">
......@@ -65,12 +101,14 @@
<div class="panel">
<header class="panel-heading">
<div class="row">
<div class="col-md-4">
<div class="col-md-3">
<img src="../img/close.png" class="i-15" ng-show="!isItemsViewOpened"/>
<img src="../img/open.png" class="i-15" ng-show="isItemsViewOpened"/>
<b>{{namespace.namespace.namespaceName}}</b>
<span class="label label-info" ng-show="namespace.itemModifiedCnt > 0">有修改,可发布
<span class="badge">{{namespace.itemModifiedCnt}}</span></span>
</div>
<div class="col-md-7">
<div class="col-md-8">
<div class="btn-toolbar" role="toolbar" aria-label="...">
<div class="btn-group" role="group" aria-label="...">
<button type="button" data-toggle="modal" data-target="#releaseModal"
......@@ -120,7 +158,7 @@
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
</a>
<a data-toggle="tooltip" data-placement="top" title="修改配置"
ng-show="!namespace.isTextEditing && namespace.viewType == 'text'"
ng-show="!namespace.isTextEditing && namespace.viewType == 'text' && isItemsViewOpened"
ng-click="toggleTextEditStatus(namespace)">
<span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
</a>
......@@ -134,7 +172,8 @@
</header>
<!--text view-->
<textarea class="form-control" rows="30" ng-show="isItemsViewOpened && namespace.viewType == 'text'"
<textarea class="form-control" rows="30"
ng-show="isItemsViewOpened && namespace.viewType == 'text'"
ng-disabled="!namespace.isTextEditing" ng-model="namespace.text">
{{namespace.text}}
</textarea>
......@@ -145,7 +184,7 @@
ng-show="isItemsViewOpened && namespace.viewType == 'table'">
<thead>
<tr>
<th >
<th>
Key
</th>
<th>
......@@ -164,7 +203,8 @@
</thead>
<tbody>
<tr ng-repeat="config in namespace.items" ng-class="{warning:config.modified}" ng-if="config.item.key">
<tr ng-repeat="config in namespace.items" ng-class="{warning:config.modified}"
ng-if="config.item.key">
<td width="25%">
{{config.item.key}}
</td>
......@@ -175,7 +215,7 @@
ng-show="config.modified"
ng-click="queryOldValue(config.item.key, config.oldValue)"></button>
{{config.item.value}}
</td >
</td>
<td width="20%">
{{config.item.comment}}
</td>
......@@ -192,7 +232,8 @@
</div>
<!--历史修改视图-->
<div class="J_historyview history-view" ng-show="isItemsViewOpened && namespace.viewType == 'history'">
<div class="J_historyview history-view"
ng-show="isItemsViewOpened && namespace.viewType == 'history'">
<div class="row">
<div class="col-md-11 col-md-offset-1 list" style="">
<div class="media">
......@@ -244,39 +285,40 @@
</div>
<!-- view old value Modal -->
<div class="modal fade " id="oldValueModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal fade " id="oldValueModal" tabindex="-1" role="dialog">
<div class="modal-dialog modal-sm" role="document">
<div class="modal-content">
<div class="modal-header panel-primary">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="myModalLabel">旧值</h4>
<h4 class="modal-title">旧值</h4>
</div>
<div class="modal-body">
{{OldValue}}
</div>
<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">Close</button>
</div>
</div>
</div>
</div>
<!-- commit modify config modal-->
<div class="modal fade" id="commitModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel2">
<div class="modal fade" id="commitModal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header panel-primary">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="myModalLabel2">Commit changes</h4>
<h4 class="modal-title">Commit changes</h4>
</div>
<div class="modal-body">
<textarea rows="4" class="form-control" style="width:570px;" placeholder="input change log...."
ng-model="commitComment"></textarea>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary" data-dismiss="modal" ng-click="commitChange()">
提交
</button>
......@@ -285,26 +327,57 @@
</div>
</div>
<!--createRelease modal-->
<div class="modal fade" id="releaseModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel3">
<!--create release modal-->
<div class="modal fade" id="releaseModal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header panel-primary">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="myModalLabel3">发布</h4>
<h4 class="modal-title">发布</h4>
</div>
<div class="modal-body">
<textarea rows="4" class="form-control" style="width:570px;" ng-model="releaseComment"
placeholder="input release log...."></textarea>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary" data-dismiss="modal" ng-click="release()">提交
</button>
</div>
</div>
</div>
</div>
<!--create env modal-->
<div class="modal fade" id="createEnvModal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header panel-primary">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
aria-hidden="true">&times;</span></button>
<h4 class="modal-title">添加环境</h4>
</div>
<div class="modal-body">
<div class="form-group">
<label>请选择环境:</label>
<div class="checkbox" ng-repeat="env in missEnvs">
<label>
<input type="checkbox" name="selectedEnvs[]" value="{{env}}"
ng-checked="selectedEnvs.indexOf(env) > -1" ng-click="toggleSelection(env)">{{env}}
</label>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary" data-dismiss="modal" ng-click="createEnvs()">添加
</button>
</div>
</div>
</div>
</div>
</div>
</div>
......@@ -339,6 +412,7 @@
<!--service-->
<script type="application/javascript" src="../scripts/services/AppService.js"></script>
<script type="application/javascript" src="../scripts/services/ConfigService.js"></script>
<script type="application/javascript" src="../scripts/AppUtils.js"></script>
<!--controller-->
<script type="application/javascript" src="../scripts/controller/app/AppConfigController.js"></script>
......
......@@ -24,7 +24,7 @@
</header>
<div class="panel-body">
<form class="form-horizontal" ng-controller="CreateAppController" ng-submit="save()">
<form class="form-horizontal" ng-controller="CreateAppController" ng-submit="create()">
<div class="form-group">
<label class="col-sm-2 control-label"><font style="color: red">*</font> 应用ID</label>
<div class="col-sm-3">
......@@ -81,6 +81,8 @@
<script type="application/javascript" src="../scripts/app.js"></script>
<script type="application/javascript" src="../scripts/services/AppService.js"></script>
<script type="application/javascript" src="../scripts/AppUtils.js"></script>
<script type="application/javascript" src="../scripts/controller/CreateAppController.js"></script>
</body>
</html>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment