Commit 92a8a0fd by Yiming Liu

Merge pull request #107 from lepdou/portal

portal service unit test & remove js dependency
parents 6a7477c2 ed5e5321
......@@ -28,9 +28,11 @@ public class ItemDTO{
}
public ItemDTO(String key, String value) {
public ItemDTO(String key, String value, String comment, int lineNum) {
this.key = key;
this.value = value;
this.comment = comment;
this.lineNum = lineNum;
}
public String getComment() {
......
......@@ -49,15 +49,21 @@ public class AdminServiceAPI {
@Service
public static class NamespaceAPI extends API {
public List<NamespaceDTO> findGroupsByAppAndCluster(String appId, Env env,
public List<NamespaceDTO> findNamespaceByCluster(String appId, Env env,
String clusterName) {
if (StringUtils.isContainEmpty(appId, clusterName)) {
return null;
}
return Arrays.asList(restTemplate.getForObject(
NamespaceDTO[] namespaceDTOs = restTemplate.getForObject(
getAdminServiceHost(env) + String.format("apps/%s/clusters/%s/namespaces", appId, clusterName),
NamespaceDTO[].class));
NamespaceDTO[].class);
if (namespaceDTOs == null){
return Collections.emptyList();
}else {
return Arrays.asList(namespaceDTOs);
}
}
public NamespaceDTO loadNamespace(String appId, Env env,
......@@ -79,10 +85,16 @@ public class AdminServiceAPI {
return Collections.emptyList();
}
return Arrays.asList(restTemplate.getForObject(getAdminServiceHost(env) + String
ItemDTO[] itemDTOs = restTemplate.getForObject(getAdminServiceHost(env) + String
.format("apps/%s/clusters/%s/namespaces/%s/items", appId,
clusterName, namespace),
ItemDTO[].class));
ItemDTO[].class);
if (itemDTOs == null) {
return Collections.emptyList();
} else {
return Arrays.asList(itemDTOs);
}
}
public void updateItems(String appId, Env env, String clusterName, String namespace,
......@@ -106,9 +118,14 @@ public class AdminServiceAPI {
return null;
}
return Arrays
.asList(restTemplate.getForObject(getAdminServiceHost(env) + String.format("apps/%s/clusters", appId),
ClusterDTO[].class));
ClusterDTO[] clusterDTOs = restTemplate.getForObject(getAdminServiceHost(env) + String.format("apps/%s/clusters", appId),
ClusterDTO[].class);
if (clusterDTOs == null){
return Collections.emptyList();
}else {
return Arrays.asList(clusterDTOs);
}
}
}
......
......@@ -33,7 +33,7 @@ public class ConfigService {
private Logger logger = LoggerFactory.getLogger(ConfigService.class);
@Autowired
private AdminServiceAPI.NamespaceAPI groupAPI;
private AdminServiceAPI.NamespaceAPI namespaceAPI;
@Autowired
private AdminServiceAPI.ItemAPI itemAPI;
@Autowired
......@@ -54,7 +54,7 @@ public class ConfigService {
*/
public List<NamespaceVO> findNampspaces(String appId, Env env, String clusterName) {
List<NamespaceDTO> namespaces = groupAPI.findGroupsByAppAndCluster(appId, env, clusterName);
List<NamespaceDTO> namespaces = namespaceAPI.findNamespaceByCluster(appId, env, clusterName);
if (namespaces == null || namespaces.size() == 0) {
return Collections.emptyList();
}
......@@ -99,7 +99,7 @@ public class ConfigService {
}
}
//not createRelease config items
//not Release config items
List<ItemDTO> items = itemAPI.findItems(appId, env, clusterName, namespaceName);
int modifiedItemCnt = 0;
for (ItemDTO itemDTO : items) {
......
......@@ -147,11 +147,12 @@ public class PropertyResolver implements ConfigTextResolver {
}
private boolean isCommentItem(ItemDTO item) {
return item != null && "".equals(item.getKey()) && item.getComment().startsWith("#");
return item != null && "".equals(item.getKey())
&& (item.getComment().startsWith("#") || item.getComment().startsWith("!"));
}
private boolean isCommentItem(String line) {
return line != null && line.startsWith("#");
return line != null && (line.startsWith("#") || line.startsWith("!"));
}
private boolean isBlankItem(ItemDTO item) {
......@@ -196,13 +197,9 @@ public class PropertyResolver implements ConfigTextResolver {
}
private ItemDTO buildNormalItem(Long id, Long namespaceId, String key, String value, String comment, int lineNum) {
ItemDTO item = new ItemDTO();
ItemDTO item = new ItemDTO(key, value, comment, lineNum);
item.setId(id);
item.setNamespaceId(namespaceId);
item.setKey(key);
item.setValue(value);
item.setComment(comment);
item.setLineNum(lineNum);
return item;
}
}
ddd
<!doctype html>
<html ng-app="create_app">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<!-- styles -->
<link rel="stylesheet" type="text/css" href="vendor/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="vendor/angular/angular-toastr-1.4.1.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">
<title>apollo</title>
</head>
<body>
<div ng-include="'views/common/nav.html'"></div>
<div class="container-fluid apollo-container">
<div class="row">
<div class="col-lg-12 text-center">
<h1>welcome to apollo!~~</h1>
<img src="img/dolphin.jpg" style="width: 100px; height: 130px;"/>
<a class="btn btn-primary btn-lg" href="views/create-app.html" role="button">create app</a>
</div>
</div>
</div>
<div ng-include="'views/common/footer.html'"></div>
<!--angular-->
<script src="vendor/angular/angular.min.js"></script>
<script src="vendor/angular/angular-route.min.js"></script>
<script src="vendor/angular/angular-resource.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>
<!-- jquery.js -->
<script src="vendor/jquery.js" type="text/javascript"></script>
<!-- bootstrap.js -->
<script src="vendor/bootstrap/js/bootstrap.min.js" type="text/javascript"></script>
<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/controller/CreateAppController.js"></script>
</body>
</html>
......@@ -11,6 +11,11 @@ a{
cursor: pointer;
}
.apollo-container{
min-height: 550px;
}
.footer {
height: 100px;
width: 100%;
......@@ -72,6 +77,13 @@ table th {
height: 500px;
overflow: scroll;
}
#editor {
position: relative;
width: 500px;
height: 400px;
}
.namespace-view-table{
max-height: 700px;
overflow: scroll;
......
This source diff could not be displayed because it is too large. You can view the blob instead.
/**
* angular-strap
* @version v2.2.2 - 2015-05-15
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes <olivier@mg-crea.com> (https://github.com/mgcrea)
* @license MIT License, http://www.opensource.org/licenses/MIT
*/
!function (t, e, n) {
'use strict';
angular.module('mgcrea.ngStrap.alert').run(['$templateCache', function (t) {
t.put('alert/alert.tpl.html', '<div class="alert" ng-class="[type ? \'alert-\' + type : null]"><button type="button" class="close" ng-if="dismissable" ng-click="$hide()">&times;</button> <strong ng-bind="title"></strong>&nbsp;<span ng-bind-html="content"></span></div>')
}]), angular.module('mgcrea.ngStrap.aside').run(['$templateCache', function (t) {
t.put('aside/aside.tpl.html', '<div class="aside" tabindex="-1" role="dialog"><div class="aside-dialog"><div class="aside-content"><div class="aside-header" ng-show="title"><button type="button" class="close" ng-click="$hide()">&times;</button><h4 class="aside-title" ng-bind="title"></h4></div><div class="aside-body" ng-bind="content"></div><div class="aside-footer"><button type="button" class="btn btn-default" ng-click="$hide()">Close</button></div></div></div></div>')
}]), angular.module('mgcrea.ngStrap.datepicker').run(['$templateCache', function (t) {
t.put('datepicker/datepicker.tpl.html', '<div class="dropdown-menu datepicker" ng-class="\'datepicker-mode-\' + $mode" style="max-width: 320px"><table style="table-layout: fixed; height: 100%; width: 100%"><thead><tr class="text-center"><th><button tabindex="-1" type="button" class="btn btn-default pull-left" ng-click="$selectPane(-1)"><i class="{{$iconLeft}}"></i></button></th><th colspan="{{ rows[0].length - 2 }}"><button tabindex="-1" type="button" class="btn btn-default btn-block text-strong" ng-click="$toggleMode()"><strong style="text-transform: capitalize" ng-bind="title"></strong></button></th><th><button tabindex="-1" type="button" class="btn btn-default pull-right" ng-click="$selectPane(+1)"><i class="{{$iconRight}}"></i></button></th></tr><tr ng-show="showLabels" ng-bind-html="labels"></tr></thead><tbody><tr ng-repeat="(i, row) in rows" height="{{ 100 / rows.length }}%"><td class="text-center" ng-repeat="(j, el) in row"><button tabindex="-1" type="button" class="btn btn-default" style="width: 100%" ng-class="{\'btn-primary\': el.selected, \'btn-info btn-today\': el.isToday && !el.selected}" ng-click="$select(el.date)" ng-disabled="el.disabled"><span ng-class="{\'text-muted\': el.muted}" ng-bind="el.label"></span></button></td></tr></tbody></table></div>')
}]), angular.module('mgcrea.ngStrap.dropdown').run(['$templateCache', function (t) {
t.put('dropdown/dropdown.tpl.html', '<ul tabindex="-1" class="dropdown-menu" role="menu"><li role="presentation" ng-class="{divider: item.divider}" ng-repeat="item in content"><a role="menuitem" tabindex="-1" ng-href="{{item.href}}" ng-if="!item.divider && item.href" target="{{item.target || \'\'}}" ng-bind="item.text"></a> <a role="menuitem" tabindex="-1" href="javascript:void(0)" ng-if="!item.divider && item.click" ng-click="$eval(item.click);$hide()" ng-bind="item.text"></a></li></ul>')
}]), angular.module('mgcrea.ngStrap.modal').run(['$templateCache', function (t) {
t.put('modal/modal.tpl.html', '<div class="modal" tabindex="-1" role="dialog" aria-hidden="true"><div class="modal-dialog"><div class="modal-content"><div class="modal-header" ng-show="title"><button type="button" class="close" aria-label="Close" ng-click="$hide()"><span aria-hidden="true">&times;</span></button><h4 class="modal-title" ng-bind="title"></h4></div><div class="modal-body" ng-bind="content"></div><div class="modal-footer"><button type="button" class="btn btn-default" ng-click="$hide()">Close</button></div></div></div></div>')
}]), angular.module('mgcrea.ngStrap.popover').run(['$templateCache', function (t) {
t.put('popover/popover.tpl.html', '<div class="popover"><div class="arrow"></div><h3 class="popover-title" ng-bind="title" ng-show="title"></h3><div class="popover-content" ng-bind="content"></div></div>')
}]), angular.module('mgcrea.ngStrap.select').run(['$templateCache', function (t) {
t.put('select/select.tpl.html', '<ul tabindex="-1" class="select dropdown-menu" ng-show="$isVisible()" role="select"><li ng-if="$showAllNoneButtons"><div class="btn-group" style="margin-bottom: 5px; margin-left: 5px"><button type="button" class="btn btn-default btn-xs" ng-click="$selectAll()">{{$allText}}</button> <button type="button" class="btn btn-default btn-xs" ng-click="$selectNone()">{{$noneText}}</button></div></li><li role="presentation" ng-repeat="match in $matches" ng-class="{active: $isActive($index)}"><a style="cursor: default" role="menuitem" tabindex="-1" ng-click="$select($index, $event)"><i class="{{$iconCheckmark}} pull-right" ng-if="$isMultiple && $isActive($index)"></i> <span ng-bind="match.label"></span></a></li></ul>')
}]), angular.module('mgcrea.ngStrap.timepicker').run(['$templateCache', function (t) {
t.put('timepicker/timepicker.tpl.html', '<div class="dropdown-menu timepicker" style="min-width: 0px;width: auto"><table height="100%"><thead><tr class="text-center"><th><button tabindex="-1" type="button" class="btn btn-default pull-left" ng-click="$arrowAction(-1, 0)"><i class="{{ $iconUp }}"></i></button></th><th>&nbsp;</th><th><button tabindex="-1" type="button" class="btn btn-default pull-left" ng-click="$arrowAction(-1, 1)"><i class="{{ $iconUp }}"></i></button></th><th>&nbsp;</th><th><button ng-if="showSeconds" tabindex="-1" type="button" class="btn btn-default pull-left" ng-click="$arrowAction(-1, 2)"><i class="{{ $iconUp }}"></i></button></th></tr></thead><tbody><tr ng-repeat="(i, row) in rows"><td class="text-center"><button tabindex="-1" style="width: 100%" type="button" class="btn btn-default" ng-class="{\'btn-primary\': row[0].selected}" ng-click="$select(row[0].date, 0)" ng-disabled="row[0].disabled"><span ng-class="{\'text-muted\': row[0].muted}" ng-bind="row[0].label"></span></button></td><td><span ng-bind="i == midIndex ? timeSeparator : \' \'"></span></td><td class="text-center"><button tabindex="-1" ng-if="row[1].date" style="width: 100%" type="button" class="btn btn-default" ng-class="{\'btn-primary\': row[1].selected}" ng-click="$select(row[1].date, 1)" ng-disabled="row[1].disabled"><span ng-class="{\'text-muted\': row[1].muted}" ng-bind="row[1].label"></span></button></td><td><span ng-bind="i == midIndex ? timeSeparator : \' \'"></span></td><td class="text-center"><button tabindex="-1" ng-if="showSeconds && row[2].date" style="width: 100%" type="button" class="btn btn-default" ng-class="{\'btn-primary\': row[2].selected}" ng-click="$select(row[2].date, 2)" ng-disabled="row[2].disabled"><span ng-class="{\'text-muted\': row[2].muted}" ng-bind="row[2].label"></span></button></td><td ng-if="showAM">&nbsp;</td><td ng-if="showAM"><button tabindex="-1" ng-show="i == midIndex - !isAM * 1" style="width: 100%" type="button" ng-class="{\'btn-primary\': !!isAM}" class="btn btn-default" ng-click="$switchMeridian()" ng-disabled="el.disabled">AM</button> <button tabindex="-1" ng-show="i == midIndex + 1 - !isAM * 1" style="width: 100%" type="button" ng-class="{\'btn-primary\': !isAM}" class="btn btn-default" ng-click="$switchMeridian()" ng-disabled="el.disabled">PM</button></td></tr></tbody><tfoot><tr class="text-center"><th><button tabindex="-1" type="button" class="btn btn-default pull-left" ng-click="$arrowAction(1, 0)"><i class="{{ $iconDown }}"></i></button></th><th>&nbsp;</th><th><button tabindex="-1" type="button" class="btn btn-default pull-left" ng-click="$arrowAction(1, 1)"><i class="{{ $iconDown }}"></i></button></th><th>&nbsp;</th><th><button ng-if="showSeconds" tabindex="-1" type="button" class="btn btn-default pull-left" ng-click="$arrowAction(1, 2)"><i class="{{ $iconDown }}"></i></button></th></tr></tfoot></table></div>')
}]), angular.module('mgcrea.ngStrap.tab').run(['$templateCache', function (t) {
t.put('tab/tab.tpl.html', '<ul class="nav" ng-class="$navClass" role="tablist"><li role="presentation" ng-repeat="$pane in $panes track by $index" ng-class="[ $index == $panes.$active ? $activeClass : \'\', $pane.disabled ? \'disabled\' : \'\' ]"><a role="tab" data-toggle="tab" ng-click="!$pane.disabled && $setActive($index)" data-index="{{ $index }}" ng-bind-html="$pane.title" aria-controls="$pane.title"></a></li></ul><div ng-transclude class="tab-content"></div>')
}]), angular.module('mgcrea.ngStrap.tooltip').run(['$templateCache', function (t) {
t.put('tooltip/tooltip.tpl.html', '<div class="tooltip in" ng-show="title"><div class="tooltip-arrow"></div><div class="tooltip-inner" ng-bind="title"></div></div>')
}]), angular.module('mgcrea.ngStrap.typeahead').run(['$templateCache', function (t) {
t.put('typeahead/typeahead.tpl.html', '<ul tabindex="-1" class="typeahead dropdown-menu" ng-show="$isVisible()" role="select"><li role="presentation" ng-repeat="match in $matches" ng-class="{active: $index == $activeIndex}"><a role="menuitem" tabindex="-1" ng-click="$select($index, $event)" ng-bind="match.label"></a></li></ul>')
}])
}(window, document);
"use strict";
angular.module("lr.upload", ["lr.upload.formdata", "lr.upload.iframe", "lr.upload.directives"]), angular.module("lr.upload.directives", []), angular.module("lr.upload.directives").directive("uploadButton", ["upload", function (a) {
return {
restrict: "EA",
scope: {
data: "=?data",
url: "@",
id: "@",
param: "@",
method: "@",
onUpload: "&",
onSuccess: "&",
onError: "&",
onComplete: "&"
},
link: function (b, c, d) {
var e = angular.element(c), f = angular.element('<input id="' + b.id + '" type="file" />');
if (e.append(f), f.on("change", function () {
var c = angular.element(this);
if (!c[0].files || 0 !== c[0].files.length) {
var e = {
url: b.url,
method: b.method || "POST",
forceIFrameUpload: b.$eval(d.forceIframeUpload) || !1,
data: b.data || {}
};
e.data[b.param || "file"] = c, b.$apply(function () {
b.onUpload({files: c[0].files})
}), a(e).then(function (a) {
b.onSuccess({response: a}), b.onComplete({response: a})
}, function (a) {
b.onError({response: a}), b.onComplete({response: a})
})
}
}), "required" in d && d.$observe("required", function (a) {
var d = "" === a ? !0 : b.$eval(a);
f.attr("required", d), c.toggleClass("ng-valid", !d), c.toggleClass("ng-invalid ng-invalid-required", d)
}), "accept" in d && d.$observe("accept", function (a) {
f.attr("accept", a)
}), a.support.formData) {
var g = function () {
f.attr("multiple", !(!b.$eval(d.multiple) || b.$eval(d.forceIframeUpload)))
};
d.$observe("multiple", g), d.$observe("forceIframeUpload", g)
}
}
}
}]), angular.module("lr.upload.formdata", []).factory("formDataTransform", function () {
return function (a) {
var b = new FormData;
return angular.forEach(a, function (a, c) {
if (angular.isElement(a)) {
var d = [];
angular.forEach(a, function (a) {
angular.forEach(a.files, function (a) {
d.push(a)
}), a.value = ""
}), 0 !== d.length && (d.length > 1 ? angular.forEach(d, function (a, d) {
b.append(c + "[" + d + "]", a)
}) : b.append(c, d[0]))
} else b.append(c, a)
}), b
}
}).factory("formDataUpload", ["$http", "formDataTransform", function (a, b) {
return function (c) {
return c.transformRequest = b, c.method = c.method || "POST", c.headers = angular.extend(c.headers || {}, {"Content-Type": void 0}), a(c)
}
}]), angular.module("lr.upload.iframe", []).factory("iFrameUpload", ["$q", "$http", "$document", "$rootScope", function (a, b, c, d) {
function e(a, b) {
if (a.indexOf)return a.indexOf(b);
for (var c = 0; c < a.length; c++)if (b === a[c])return c;
return -1
}
function f(f) {
var g = [], h = a.defer(), i = h.promise;
angular.forEach(f.data || {}, function (a, b) {
angular.isElement(a) && (delete f.data[b], a.attr("name", b), g.push(a))
});
var j = /\?/.test(f.url) ? "&" : "?";
"DELETE" === f.method ? (f.url = f.url + j + "_method=DELETE", f.method = "POST") : "PUT" === f.method ? (f.url = f.url + j + "_method=PUT", f.method = "POST") : "PATCH" === f.method && (f.url = f.url + j + "_method=PATCH", f.method = "POST");
var k = angular.element(c[0].body), l = d.$new(), m = "iframe-transport-" + l.$id;
l.$destroy();
var n = angular.element("<form></form>");
n.attr("target", m), n.attr("action", f.url), n.attr("method", f.method || "POST"), n.css("display", "none"), g.length && (n.attr("enctype", "multipart/form-data"), n.attr("encoding", "multipart/form-data"));
var o = angular.element('<iframe name="' + m + '" src="javascript:false;"></iframe>');
return o.on("load", function () {
function a(a, b) {
var c = [];
return angular.isFunction(b) ? b(a, c) : (angular.forEach(b, function (b) {
a = b(a, c)
}), a)
}
function c() {
var a = e(b.pendingRequests, f);
-1 !== a && (b.pendingRequests.splice(a, 1), f.$iframeTransportForm.remove(), delete f.$iframeTransportForm)
}
o.off("load").on("load", function () {
var c;
try {
var d = this.contentWindow ? this.contentWindow.document : this.contentDocument;
if (c = angular.element(d.body).text(), !c.length)throw new Error
} catch (e) {
}
n.append(angular.element('<iframe src="javascript:false;"></iframe>'));
try {
c = a(c, b.defaults.transformResponse)
} catch (e) {
}
h.resolve({data: c, status: 200, headers: [], config: f})
}), angular.forEach(f.data, function (a, b) {
var c = angular.element('<input type="hidden" />');
c.attr("name", b), c.val(a), n.append(c)
}), angular.forEach(g, function (a) {
var b = a.clone(!0);
a.after(b), n.append(a)
}), f.$iframeTransportForm = n, b.pendingRequests.push(f), n[0].submit(), i.then(c, c)
}), n.append(o), k.append(n), i
}
return f
}]), angular.module("lr.upload").factory("upload", ["$window", "formDataUpload", "iFrameUpload", function (a, b, c) {
function d(a) {
return e.formData && !a.forceIFrameUpload ? b(a) : c(a)
}
var e = {
fileInput: !(new RegExp("(Android (1\\.[0156]|2\\.[01]))|(Windows Phone (OS 7|8\\.0))|(XBLWP)|(ZuneWP)|(WPDesktop)|(w(eb)?OSBrowser)|(webOS)|(Kindle/(1\\.0|2\\.[05]|3\\.0))").test(a.navigator.userAgent) || angular.element('<input type="file">').prop("disabled")),
fileUpload: !(!a.XMLHttpRequestUpload || !a.FileReader),
formData: !!a.FormData
};
return d.support = e, d
}]);
/**
* @version 2.0.2
* @license MIT
*/
!function (t, e) {
"use strict";
t.module("smart-table", []).run(["$templateCache", function (t) {
t.put("template/smart-table/pagination.html", '<nav ng-if="pages.length >= 2"><ul class="pagination"><li ng-repeat="page in pages" ng-class="{active: page==currentPage}"><a ng-click="selectPage(page)">{{page}}</a></li></ul></nav>')
}]), t.module("smart-table").constant("stConfig", {
pagination: {
template: "template/smart-table/pagination.html",
itemsByPage: 10,
displayedPages: 5
},
search: {delay: 400},
select: {mode: "single", selectedClass: "st-selected"},
sort: {ascentClass: "st-sort-ascent", descentClass: "st-sort-descent"},
pipe: {delay: 100}
}), t.module("smart-table").controller("stTableController", ["$scope", "$parse", "$filter", "$attrs", function (a, s, n, r) {
function i(t) {
return t ? [].concat(t) : []
}
function c() {
h = i(l(a)), P === !0 && S.pipe()
}
var l, o, u, p = r.stTable, g = s(p), f = g.assign, d = n("orderBy"), m = n("filter"), h = i(g(a)), b = {
sort: {},
search: {},
pagination: {start: 0}
}, P = !0, S = this;
r.stSafeSrc && (l = s(r.stSafeSrc), a.$watch(function () {
var t = l(a);
return t ? t.length : 0
}, function (t) {
t !== h.length && c()
}), a.$watch(function () {
return l(a)
}, function (t, e) {
t !== e && c()
})), this.sortBy = function (e, a) {
return b.sort.predicate = e, b.sort.reverse = a === !0, t.isFunction(e) ? b.sort.functionName = e.name : delete b.sort.functionName, b.pagination.start = 0, this.pipe()
}, this.search = function (e, a) {
var s = b.search.predicateObject || {}, n = a ? a : "$";
return e = t.isString(e) ? e.trim() : e, s[n] = e, e || delete s[n], b.search.predicateObject = s, b.pagination.start = 0, this.pipe()
}, this.pipe = function () {
var t, s = b.pagination;
o = b.search.predicateObject ? m(h, b.search.predicateObject) : h, b.sort.predicate && (o = d(o, b.sort.predicate, b.sort.reverse)), s.number !== e && (s.numberOfPages = o.length > 0 ? Math.ceil(o.length / s.number) : 1, s.start = s.start >= o.length ? (s.numberOfPages - 1) * s.number : s.start, t = o.slice(s.start, s.start + parseInt(s.number))), f(a, t || o)
}, this.select = function (t, a) {
var s = h, n = s.indexOf(t);
-1 !== n && ("single" === a ? (t.isSelected = t.isSelected !== !0, u && (u.isSelected = !1), u = t.isSelected === !0 ? t : e) : s[n].isSelected = !s[n].isSelected)
}, this.slice = function (t, e) {
return b.pagination.start = t, b.pagination.number = e, this.pipe()
}, this.tableState = function () {
return b
}, this.getFilteredCollection = function () {
return o || h
}, this.setFilterFunction = function (t) {
m = n(t)
}, this.setSortFunction = function (t) {
d = n(t)
}, this.preventPipeOnWatch = function () {
P = !1
}
}]).directive("stTable", function () {
return {
restrict: "A", controller: "stTableController", link: function (t, e, a, s) {
a.stSetFilter && s.setFilterFunction(a.stSetFilter), a.stSetSort && s.setSortFunction(a.stSetSort)
}
}
}), t.module("smart-table").directive("stSearch", ["stConfig", "$timeout", function (t, e) {
return {
require: "^stTable", link: function (a, s, n, r) {
var i = r, c = null, l = n.stDelay || t.search.delay;
n.$observe("stSearch", function (t, e) {
var a = s[0].value;
t !== e && a && (r.tableState().search = {}, i.search(a, t))
}), a.$watch(function () {
return r.tableState().search
}, function (t) {
var e = n.stSearch || "$";
t.predicateObject && t.predicateObject[e] !== s[0].value && (s[0].value = t.predicateObject[e] || "")
}, !0), s.bind("input", function (t) {
t = t.originalEvent || t, null !== c && e.cancel(c), c = e(function () {
i.search(t.target.value, n.stSearch || ""), c = null
}, l)
})
}
}
}]), t.module("smart-table").directive("stSelectRow", ["stConfig", function (t) {
return {
restrict: "A", require: "^stTable", scope: {row: "=stSelectRow"}, link: function (e, a, s, n) {
var r = s.stSelectMode || t.select.mode;
a.bind("click", function () {
e.$apply(function () {
n.select(e.row, r)
})
}), e.$watch("row.isSelected", function (e) {
e === !0 ? a.addClass(t.select.selectedClass) : a.removeClass(t.select.selectedClass)
})
}
}
}]), t.module("smart-table").directive("stSort", ["stConfig", "$parse", function (a, s) {
return {
restrict: "A", require: "^stTable", link: function (n, r, i, c) {
function l() {
g++, u = t.isFunction(p(n)) ? p(n) : i.stSort, g % 3 === 0 && i.stSkipNatural === e ? (g = 0, c.tableState().sort = {}, c.tableState().pagination.start = 0, c.pipe()) : c.sortBy(u, g % 2 === 0)
}
var o, u = i.stSort, p = s(u), g = 0, f = i.stClassAscent || a.sort.ascentClass, d = i.stClassDescent || a.sort.descentClass, m = [f, d];
i.stSortDefault && (o = n.$eval(i.stSortDefault) !== e ? n.$eval(i.stSortDefault) : i.stSortDefault), r.bind("click", function () {
u && n.$apply(l)
}), o && (g = "reverse" === o ? 1 : 0, l()), n.$watch(function () {
return c.tableState().sort
}, function (t) {
t.predicate !== u ? (g = 0, r.removeClass(f).removeClass(d)) : (g = t.reverse === !0 ? 2 : 1, r.removeClass(m[g % 2]).addClass(m[g - 1]))
}, !0)
}
}
}]), t.module("smart-table").directive("stPagination", ["stConfig", function (t) {
return {
restrict: "EA",
require: "^stTable",
scope: {stItemsByPage: "=?", stDisplayedPages: "=?", stPageChange: "&"},
templateUrl: function (e, a) {
return a.stTemplate ? a.stTemplate : t.pagination.template
},
link: function (e, a, s, n) {
function r() {
var t, a, s = n.tableState().pagination, r = 1, i = e.currentPage;
for (e.currentPage = Math.floor(s.start / s.number) + 1, r = Math.max(r, e.currentPage - Math.abs(Math.floor(e.stDisplayedPages / 2))), t = r + e.stDisplayedPages, t > s.numberOfPages && (t = s.numberOfPages + 1, r = Math.max(1, t - e.stDisplayedPages)), e.pages = [], e.numPages = s.numberOfPages, a = r; t > a; a++)e.pages.push(a);
i !== e.currentPage && e.stPageChange({newPage: e.currentPage})
}
e.stItemsByPage = e.stItemsByPage ? +e.stItemsByPage : t.pagination.itemsByPage, e.stDisplayedPages = e.stDisplayedPages ? +e.stDisplayedPages : t.pagination.displayedPages, e.currentPage = 1, e.pages = [], e.$watch(function () {
return n.tableState().pagination
}, r, !0), e.$watch("stItemsByPage", function (t, a) {
t !== a && e.selectPage(1)
}), e.$watch("stDisplayedPages", r), e.selectPage = function (t) {
t > 0 && t <= e.numPages && n.slice((t - 1) * e.stItemsByPage, e.stItemsByPage)
}, n.tableState().pagination.number || n.slice(0, e.stItemsByPage)
}
}
}]), t.module("smart-table").directive("stPipe", ["stConfig", "$timeout", function (e, a) {
return {
require: "stTable", scope: {stPipe: "="}, link: {
pre: function (s, n, r, i) {
var c = null;
t.isFunction(s.stPipe) && (i.preventPipeOnWatch(), i.pipe = function () {
return null !== c && a.cancel(c), c = a(function () {
s.stPipe(i.tableState(), i)
}, e.pipe.delay)
})
}, post: function (t, e, a, s) {
s.pipe()
}
}
}
}])
}(angular);
......@@ -14,7 +14,7 @@
<div ng-include="'common/nav.html'"></div>
<div class="container-fluid">
<div class="container-fluid apollo-container">
<div class="app" ng-controller="AppConfigController as appConfig">
<!--配置信息-->
......@@ -100,8 +100,8 @@
</div>
</div>
</header>
<div ng-show="namespace.viewType == 'text'">
<textarea class="form-control" rows="30" ng-model="namespace.text"
ng-disabled="!namespace.isTextEditing">
{{namespace.text}}
......@@ -305,11 +305,10 @@
<!--controller-->
<script type="application/javascript" src="../scripts/controller/app/AppConfigController.js"></script>
<script type="application/javascript">
$(function () {
$('[data-toggle="tooltip"]').tooltip()
})
});
</script>
</body>
</html>
......@@ -14,8 +14,7 @@
<div ng-include="'common/nav.html'"></div>
<div class="container">
<div class="container-fluid">
<div class="container-fluid apollo-container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
......@@ -64,7 +63,6 @@
</div>
</div>
</div>
</div>
</div>
<div ng-include="'common/footer.html'"></div>
......
package com.ctrip.apollo.portal;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
@SuiteClasses({
ConfigServiceTest.class, PropertyResolverTest.class,
AppServiceTest.class
})
public class AllTests {
......
package com.ctrip.apollo.portal;
import com.ctrip.apollo.core.dto.AppDTO;
import com.ctrip.apollo.core.dto.ClusterDTO;
import com.ctrip.apollo.core.enums.Env;
import com.ctrip.apollo.portal.api.AdminServiceAPI;
import com.ctrip.apollo.portal.entity.ClusterNavTree;
import com.ctrip.apollo.portal.service.AppService;
import com.ctrip.apollo.portal.service.ClusterService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class AppServiceTest extends AbstractPortalTest{
@Mock
private PortalSettings settings;
@Mock
private ClusterService clusterService;
@Mock
private AdminServiceAPI.AppAPI appAPI;
@InjectMocks
private AppService appService;
@Test
public void testBuildNavTree(){
String appId = "6666";
ClusterDTO c1 = new ClusterDTO();
c1.setAppId(appId);
c1.setName("default");
c1.setId(1);
ClusterDTO c2 = new ClusterDTO();
c2.setAppId(appId);
c2.setName("oy");
c2.setId(2);
List<ClusterDTO> clusterDTOs = Arrays.asList(c1, c2);
when(settings.getEnvs()).thenReturn(Arrays.asList(Env.DEV, Env.FAT));
when(clusterService.findClusters(Env.DEV, appId)).thenReturn(clusterDTOs);
when(clusterService.findClusters(Env.FAT, appId)).thenReturn(Arrays.asList(c1));
ClusterNavTree tree = appService.buildClusterNavTree(appId);
assertEquals(2, tree.getNodes().size());
ClusterNavTree.Node node1 = tree.getNodes().get(0);
assertEquals(Env.DEV, node1.getEnv());
assertEquals(2, node1.getClusters().size());
assertEquals("default", node1.getClusters().get(0).getName());
}
@Test
public void testSaveApp(){
String appId = "6666";
String appName = "hermas";
AppDTO appDTO = new AppDTO();
appDTO.setAppId(appId);
appDTO.setName(appName);
appDTO.setDataChangeLastModifiedBy("ll");
appDTO.setDataChangeCreatedTime(new Date());
appDTO.setOwnerEmail("qq@qq.com");
appDTO.setOwnerName("zz");
when(appService.save(appDTO)).thenReturn(appDTO);
AppDTO createApp = appService.save(appDTO);
assertEquals(appId, createApp.getAppId());
assertEquals(appName, createApp.getName());
}
}
package com.ctrip.apollo.portal;
import com.ctrip.apollo.core.dto.ItemChangeSets;
import com.ctrip.apollo.core.dto.ItemDTO;
import com.ctrip.apollo.core.dto.NamespaceDTO;
import com.ctrip.apollo.core.dto.ReleaseDTO;
import com.ctrip.apollo.core.enums.Env;
import com.ctrip.apollo.core.exception.ServiceException;
import com.ctrip.apollo.portal.api.AdminServiceAPI;
import com.ctrip.apollo.portal.entity.NamespaceVO;
import com.ctrip.apollo.portal.entity.form.NamespaceTextModel;
import com.ctrip.apollo.portal.service.ConfigService;
import com.ctrip.apollo.portal.service.txtresolver.PropertyResolver;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import java.util.Arrays;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class ConfigServiceTest extends AbstractPortalTest{
@Mock
private AdminServiceAPI.NamespaceAPI namespaceAPI;
@Mock
private AdminServiceAPI.ReleaseAPI releaseAPI;
@Mock
private AdminServiceAPI.ItemAPI itemAPI;
@Mock
private PropertyResolver resolver;
@InjectMocks
private ConfigService configService;
@Before
public void setup() {
}
@Test
public void testFindNamespace() {
String appId = "6666";
String clusterName = "default";
String namespaceName = "application";
NamespaceDTO application = new NamespaceDTO();
application.setId(1);
application.setClusterName(clusterName);
application.setAppId(appId);
application.setNamespaceName(namespaceName);
NamespaceDTO hermas = new NamespaceDTO();
hermas.setId(2);
hermas.setClusterName("default");
hermas.setAppId(appId);
hermas.setNamespaceName("hermas");
List<NamespaceDTO> namespaces = Arrays.asList(application, hermas);
ReleaseDTO someRelease = new ReleaseDTO();
someRelease.setConfigurations("{\"a\":\"123\",\"b\":\"123\"}");
ItemDTO i1 = new ItemDTO("a", "123", "", 1);
ItemDTO i2 = new ItemDTO("b", "1", "", 2);
ItemDTO i3 = new ItemDTO("", "", "#dddd", 3);
ItemDTO i4 = new ItemDTO("c", "1", "", 4);
List<ItemDTO> someItems = Arrays.asList(i1, i2, i3, i4);
when(namespaceAPI.findNamespaceByCluster(appId, Env.DEV, clusterName)).thenReturn(namespaces);
when(releaseAPI.loadLatestRelease(appId, Env.DEV, clusterName, namespaceName)).thenReturn(someRelease);
when(itemAPI.findItems(appId, Env.DEV, clusterName, namespaceName)).thenReturn(someItems);
List<NamespaceVO> namespaceVOs = configService.findNampspaces(appId, Env.DEV, clusterName);
assertEquals(2, namespaceVOs.size());
NamespaceVO namespaceVO = namespaceVOs.get(0);
assertEquals(4, namespaceVO.getItems().size());
assertEquals("a", namespaceVO.getItems().get(0).getItem().getKey());
assertEquals(2, namespaceVO.getItemModifiedCnt());
assertEquals(appId, namespaceVO.getNamespace().getAppId());
assertEquals(clusterName, namespaceVO.getNamespace().getClusterName());
assertEquals(namespaceName, namespaceVO.getNamespace().getNamespaceName());
}
@Test
public void testUpdateConfigByText() {
String appId = "6666";
String clusterName = "default";
String namespaceName = "application";
NamespaceTextModel model = new NamespaceTextModel();
model.setEnv("DEV");
model.setModifyBy("ll");
model.setNamespaceName(namespaceName);
model.setClusterName(clusterName);
model.setAppId(appId);
model.setConfigText("a=b\nb=c\nc=d");
List<ItemDTO> itemDTOs = mockBaseItemHas3Key();
ItemChangeSets changeSets = new ItemChangeSets();
changeSets.setModifyBy("ll");
changeSets.addCreateItem(new ItemDTO("d", "c", "", 4));
when(itemAPI.findItems(appId, Env.DEV, clusterName, namespaceName)).thenReturn(itemDTOs);
try {
// 调用itemAPI.updateConfig 会抛出ServiceException.
// itemAPI.updateConfig ut 放在admin service.
// 所以只要在调用itemAPI.updateConfig前全部通过,此ut应该通过.
configService.updateConfigItemByText(model);
}catch (Exception e){
Assert.assertTrue(e instanceof ServiceException);
}
}
/**
* a=b b=c c=d
*/
private List<ItemDTO> mockBaseItemHas3Key() {
ItemDTO item1 = new ItemDTO("a", "b", "", 1);
ItemDTO item2 = new ItemDTO("b", "c", "", 2);
ItemDTO item3 = new ItemDTO("c", "d", "", 3);
return Arrays.asList(item1, item2, item3);
}
}
package com.ctrip.apollo.portal;
import com.ctrip.apollo.core.dto.ItemChangeSets;
import com.ctrip.apollo.core.dto.ItemDTO;
import com.ctrip.apollo.core.exception.BadRequestException;
import com.ctrip.apollo.portal.service.txtresolver.ConfigTextResolver;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class PropertyResolverTest extends AbstractPortalTest {
@Autowired
private ConfigTextResolver resolver;
@Test
public void testEmptyText() {
try {
resolver.resolve(0, "", null);
} catch (Exception e) {
Assert.assertTrue(e instanceof BadRequestException);
}
}
@Test
public void testAddItemBeforeNoItem() {
ItemChangeSets changeSets = resolver.resolve(1, "a=b\nb=c", Collections.emptyList());
Assert.assertEquals(2, changeSets.getCreateItems().size());
}
@Test
public void testAddItemBeforeHasItem() {
ItemChangeSets changeSets = resolver.resolve(1, "x=y\na=b\nb=c\nc=d", mockBaseItemHas3Key());
Assert.assertEquals("x", changeSets.getCreateItems().get(0).getKey());
Assert.assertEquals(1, changeSets.getCreateItems().size());
Assert.assertEquals(3, changeSets.getUpdateItems().size());
}
@Test
public void testAddCommentAndBlankItem() {
ItemChangeSets changeSets = resolver.resolve(1, "#ddd\na=b\n\nb=c\nc=d", mockBaseItemHas3Key());
Assert.assertEquals(2, changeSets.getCreateItems().size());
Assert.assertEquals(3, changeSets.getUpdateItems().size());
}
@Test
public void testChangeItemNumLine() {
ItemChangeSets changeSets = resolver.resolve(1, "b=c\nc=d\na=b", mockBaseItemHas3Key());
Assert.assertEquals(3, changeSets.getUpdateItems().size());
}
@Test
public void testDeleteItem() {
ItemChangeSets changeSets = resolver.resolve(1, "a=b", mockBaseItemHas3Key());
Assert.assertEquals(2, changeSets.getDeleteItems().size());
}
@Test
public void testDeleteCommentItem() {
ItemChangeSets changeSets = resolver.resolve(1, "a=b\n\nb=c", mockBaseItemWith2Key1Comment1Blank());
Assert.assertEquals(2, changeSets.getDeleteItems().size());
Assert.assertEquals(2, changeSets.getUpdateItems().size());
Assert.assertEquals(1, changeSets.getCreateItems().size());
}
@Test
public void testDeleteBlankItem(){
ItemChangeSets changeSets = resolver.resolve(1, "#qqqq\na=b\nb=c", mockBaseItemWith2Key1Comment1Blank());
Assert.assertEquals(1, changeSets.getDeleteItems().size());
Assert.assertEquals(1, changeSets.getUpdateItems().size());
Assert.assertEquals(0, changeSets.getCreateItems().size());
}
@Test
public void testUpdateItem() {
ItemChangeSets changeSets = resolver.resolve(1, "a=d", mockBaseItemHas3Key());
List<ItemDTO> updateItems = changeSets.getUpdateItems();
Assert.assertEquals(1, updateItems.size());
Assert.assertEquals("d", updateItems.get(0).getValue());
}
@Test
public void testUpdateCommentItem() {
ItemChangeSets changeSets = resolver.resolve(1, "#ww\n"
+ "a=b\n"
+"\n"
+ "b=c", mockBaseItemWith2Key1Comment1Blank());
Assert.assertEquals(1, changeSets.getDeleteItems().size());
Assert.assertEquals(0, changeSets.getUpdateItems().size());
Assert.assertEquals(1, changeSets.getCreateItems().size());
}
@Test
public void testAllSituation(){
ItemChangeSets changeSets = resolver.resolve(1, "#ww\nd=e\nb=c\na=b\n\nq=w\n#eee", mockBaseItemWith2Key1Comment1Blank());
Assert.assertEquals(2, changeSets.getDeleteItems().size());
Assert.assertEquals(2, changeSets.getUpdateItems().size());
Assert.assertEquals(5, changeSets.getCreateItems().size());
}
/**
* a=b b=c c=d
*/
private List<ItemDTO> mockBaseItemHas3Key() {
ItemDTO item1 = new ItemDTO("a", "b", "", 1);
ItemDTO item2 = new ItemDTO("b", "c", "", 2);
ItemDTO item3 = new ItemDTO("c", "d", "", 3);
return Arrays.asList(item1, item2, item3);
}
/**
* #qqqq
* a=b
*
* b=c
*/
private List<ItemDTO> mockBaseItemWith2Key1Comment1Blank() {
ItemDTO i1 = new ItemDTO("", "", "#qqqq", 1);
ItemDTO i2 = new ItemDTO("a", "b", "", 2);
ItemDTO i3 = new ItemDTO("", "", "", 3);
ItemDTO i4 = new ItemDTO("b", "c", "", 4);
i4.setLineNum(4);
return Arrays.asList(i1, i2, i3, i4);
}
}
......@@ -17,3 +17,7 @@ logging:
ctrip:
appid: 100003173
apollo:
portal:
env: dev
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