From 4818f2a82a6dd0c2422145be4bb93d6ab1c85ae6 Mon Sep 17 00:00:00 2001 From: lepdou Date: Mon, 1 Aug 2016 20:27:59 +0800 Subject: [PATCH] =?UTF-8?q?=E7=94=A8=E6=88=B7=E6=89=93=E7=82=B9&=20?= =?UTF-8?q?=E5=A4=9A=E5=A4=84=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ReleaseController.java | 9 -- .../AuthConfiguration.java | 2 +- .../WebContextConfiguration.java} | 25 +++- .../apollo/portal/constant/CatEventType.java | 2 + .../filters/RecordAccessUserFilter.java | 44 +++++++ .../src/main/resources/static/app.html | 47 +++++--- .../src/main/resources/static/cluster.html | 20 +++- .../src/main/resources/static/config.html | 50 ++++---- .../src/main/resources/static/namespace.html | 28 +++-- .../src/main/resources/static/scripts/app.js | 14 +-- .../scripts/controller/AppController.js | 4 +- .../scripts/controller/ClusterController.js | 1 + .../scripts/controller/IndexController.js | 50 ++++++-- .../scripts/controller/NamespaceController.js | 1 + .../config/ConfigBaseInfoController.js | 21 ++++ .../config/ConfigNamespaceController.js | 3 + .../main/resources/static/scripts/valdr.js | 108 ++++++++++++++++++ .../resources/static/styles/common-style.css | 51 ++++++--- .../static/vendor/valdr/valdr-message.min.js | 1 + .../static/vendor/valdr/valdr.min.js | 1 + 20 files changed, 369 insertions(+), 113 deletions(-) rename apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/{configutation => configuration}/AuthConfiguration.java (99%) rename apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/{configutation/ServletContextConfiguration.java => configuration/WebContextConfiguration.java} (54%) create mode 100644 apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/filters/RecordAccessUserFilter.java create mode 100644 apollo-portal/src/main/resources/static/scripts/valdr.js create mode 100755 apollo-portal/src/main/resources/static/vendor/valdr/valdr-message.min.js create mode 100755 apollo-portal/src/main/resources/static/vendor/valdr/valdr.min.js diff --git a/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/controller/ReleaseController.java b/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/controller/ReleaseController.java index 3311b4f35..fe0e302bf 100644 --- a/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/controller/ReleaseController.java +++ b/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/controller/ReleaseController.java @@ -55,15 +55,6 @@ public class ReleaseController { return BeanUtils.batchTransform(ReleaseDTO.class, releases); } - // TODO: 16/7/25 兼容老接口,下版本删除 - @RequestMapping("/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/releases") - public List findReleases(@PathVariable("appId") String appId, - @PathVariable("clusterName") String clusterName, - @PathVariable("namespaceName") String namespaceName, - Pageable page) { - List releases = releaseService.findAllReleases(appId, clusterName, namespaceName, page); - return BeanUtils.batchTransform(ReleaseDTO.class, releases); - } @RequestMapping("/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/releases/active") public List findActiveReleases(@PathVariable("appId") String appId, diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/configutation/AuthConfiguration.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/configuration/AuthConfiguration.java similarity index 99% rename from apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/configutation/AuthConfiguration.java rename to apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/configuration/AuthConfiguration.java index c7a7ef484..997456e60 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/configutation/AuthConfiguration.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/configuration/AuthConfiguration.java @@ -1,4 +1,4 @@ -package com.ctrip.framework.apollo.portal.configutation; +package com.ctrip.framework.apollo.portal.configuration; import com.ctrip.framework.apollo.portal.auth.ctrip.CtripLogoutHandler; import com.ctrip.framework.apollo.portal.auth.ctrip.CtripSsoHeartbeatHandler; diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/configutation/ServletContextConfiguration.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/configuration/WebContextConfiguration.java similarity index 54% rename from apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/configutation/ServletContextConfiguration.java rename to apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/configuration/WebContextConfiguration.java index 97878043d..3e75408e4 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/configutation/ServletContextConfiguration.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/configuration/WebContextConfiguration.java @@ -1,10 +1,13 @@ -package com.ctrip.framework.apollo.portal.configutation; +package com.ctrip.framework.apollo.portal.configuration; import com.google.common.base.Strings; +import com.ctrip.framework.apollo.portal.auth.UserInfoHolder; +import com.ctrip.framework.apollo.portal.filters.RecordAccessUserFilter; import com.ctrip.framework.apollo.portal.service.ServerConfigService; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.embedded.FilterRegistrationBean; import org.springframework.boot.context.embedded.ServletContextInitializer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -15,13 +18,15 @@ import javax.servlet.ServletException; @Configuration @Profile("ctrip") -public class ServletContextConfiguration { +public class WebContextConfiguration { @Autowired private ServerConfigService serverConfigService; + @Autowired + private UserInfoHolder userInfoHolder; @Bean - public ServletContextInitializer initializer() { + public ServletContextInitializer servletContextInitializer() { return new ServletContextInitializer() { @@ -31,13 +36,21 @@ public class ServletContextConfiguration { String loggingServerPort = serverConfigService.getValue("loggingServerPort"); String credisServiceUrl = serverConfigService.getValue("credisServiceUrl"); servletContext.setInitParameter("loggingServerIP", - Strings.isNullOrEmpty(loggingServerIP) ? "" : loggingServerIP); + Strings.isNullOrEmpty(loggingServerIP) ? "" : loggingServerIP); servletContext.setInitParameter("loggingServerPort", - Strings.isNullOrEmpty(loggingServerPort) ? "" : loggingServerPort); + Strings.isNullOrEmpty(loggingServerPort) ? "" : loggingServerPort); servletContext.setInitParameter("credisServiceUrl", - Strings.isNullOrEmpty(credisServiceUrl) ? "" : credisServiceUrl); + Strings.isNullOrEmpty(credisServiceUrl) ? "" : credisServiceUrl); } }; } + @Bean + public FilterRegistrationBean recordAccessUserFilter() { + FilterRegistrationBean filter = new FilterRegistrationBean(); + filter.setFilter(new RecordAccessUserFilter(userInfoHolder)); + filter.addUrlPatterns("/apps"); + return filter; + } + } diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/constant/CatEventType.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/constant/CatEventType.java index fd77f4e44..cd47e19d8 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/constant/CatEventType.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/constant/CatEventType.java @@ -18,4 +18,6 @@ public interface CatEventType { String API_RETRY = "API.Retry"; + String USER_ACCESS = "User.Access"; + } diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/filters/RecordAccessUserFilter.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/filters/RecordAccessUserFilter.java new file mode 100644 index 000000000..35f3ad77d --- /dev/null +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/filters/RecordAccessUserFilter.java @@ -0,0 +1,44 @@ +package com.ctrip.framework.apollo.portal.filters; + +import com.ctrip.framework.apollo.portal.auth.UserInfoHolder; +import com.ctrip.framework.apollo.portal.constant.CatEventType; +import com.dianping.cat.Cat; + +import java.io.IOException; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +public class RecordAccessUserFilter implements Filter { + + + private UserInfoHolder userInfoHolder; + + + public RecordAccessUserFilter(UserInfoHolder userInfoHolder) { + this.userInfoHolder = userInfoHolder; + } + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + + Cat.logEvent(CatEventType.USER_ACCESS, userInfoHolder.getUser().getUserId()); + + chain.doFilter(request, response); + } + + @Override + public void destroy() { + + } +} diff --git a/apollo-portal/src/main/resources/static/app.html b/apollo-portal/src/main/resources/static/app.html index 148233695..c97526b73 100644 --- a/apollo-portal/src/main/resources/static/app.html +++ b/apollo-portal/src/main/resources/static/app.html @@ -24,30 +24,43 @@
- -
+ +
- +
- +
-
- +
+
- (CMS上申请的App Id) + + (CMS上申请的App Id)
-
- +
+
- + (建议格式 xx-yy-zz 例:apollo-server)
- +
(负责人具有项目管理的最高权限,比如分配配置的修改权,发布权等) @@ -57,7 +70,9 @@
- +
@@ -83,6 +98,10 @@ + + + + @@ -92,5 +111,7 @@ + + diff --git a/apollo-portal/src/main/resources/static/cluster.html b/apollo-portal/src/main/resources/static/cluster.html index 6d00dff5f..72ec10ccf 100644 --- a/apollo-portal/src/main/resources/static/cluster.html +++ b/apollo-portal/src/main/resources/static/cluster.html @@ -33,7 +33,8 @@
-
+
-
+
- + (部署集群如:SHAJQ,SHAOY 或自定义集群如:SHAJQ-xx,SHAJQ-yy)
@@ -57,7 +58,8 @@
- + @@ -70,7 +72,9 @@
- +
@@ -100,6 +104,10 @@ + + + + @@ -109,5 +117,7 @@ + + diff --git a/apollo-portal/src/main/resources/static/config.html b/apollo-portal/src/main/resources/static/config.html index 2990f65b0..4e56dfaa4 100644 --- a/apollo-portal/src/main/resources/static/config.html +++ b/apollo-portal/src/main/resources/static/config.html @@ -32,7 +32,7 @@
- + @@ -122,7 +122,7 @@ -
AppId:
-
+
配置没有变化 @@ -214,15 +214,15 @@ -
- +
-
-
@@ -232,7 +232,7 @@
@@ -240,7 +240,7 @@ - + @@ -453,6 +442,10 @@ + + + + @@ -479,5 +472,6 @@ + diff --git a/apollo-portal/src/main/resources/static/namespace.html b/apollo-portal/src/main/resources/static/namespace.html index b3c30cff3..e12ad2766 100644 --- a/apollo-portal/src/main/resources/static/namespace.html +++ b/apollo-portal/src/main/resources/static/namespace.html @@ -40,10 +40,10 @@ - +
-
+
@@ -52,7 +52,7 @@ -
+
@@ -62,14 +62,14 @@ -
+
-
-
@@ -86,7 +86,7 @@ -
+
@@ -95,17 +95,17 @@
-
+
-
- +
+
-
+
@@ -114,7 +114,7 @@
- +
@@ -147,6 +147,9 @@ + + + @@ -160,6 +163,7 @@ + diff --git a/apollo-portal/src/main/resources/static/scripts/app.js b/apollo-portal/src/main/resources/static/scripts/app.js index cf30cfc7c..a1473f517 100644 --- a/apollo-portal/src/main/resources/static/scripts/app.js +++ b/apollo-portal/src/main/resources/static/scripts/app.js @@ -1,9 +1,9 @@ -/**service module 定义*/ -var appService = angular.module('app.service', ['ngResource']); - /**utils*/ var appUtil = angular.module('app.util', ['toastr']); +/**service module 定义*/ +var appService = angular.module('app.service', ['ngResource']); + /** directive */ var directive_module = angular.module('apollo.directive', ['app.service', 'app.util', 'toastr']); @@ -11,19 +11,19 @@ var directive_module = angular.module('apollo.directive', ['app.service', 'app.u // 首页 var index_module = angular.module('index', ['toastr', 'app.service', 'app.util', 'angular-loading-bar']); //项目主页 -var application_module = angular.module('application', ['app.service', 'apollo.directive', 'app.util', 'toastr', 'angular-loading-bar']); +var application_module = angular.module('application', ['app.service', 'apollo.directive', 'app.util', 'toastr', 'angular-loading-bar', 'valdr']); //创建项目页面 -var create_app_module = angular.module('create_app', ['apollo.directive', 'toastr', 'app.service', 'app.util', 'angular-loading-bar']); +var app_module = angular.module('create_app', ['apollo.directive', 'toastr', 'app.service', 'app.util', 'angular-loading-bar', 'valdr']); //配置同步页面 var sync_item_module = angular.module('sync_item', ['app.service', 'apollo.directive', 'app.util', 'toastr', 'angular-loading-bar']); //namespace -var namespace_module = angular.module('namespace', ['app.service', 'apollo.directive', 'app.util', 'toastr', 'angular-loading-bar']); +var namespace_module = angular.module('namespace', ['app.service', 'apollo.directive', 'app.util', 'toastr', 'angular-loading-bar', 'valdr']); //server config var server_config_module = angular.module('server_config', ['app.service', 'apollo.directive', 'app.util', 'toastr', 'angular-loading-bar']); //role var role_module = angular.module('role', ['app.service', 'apollo.directive', 'app.util', 'toastr', 'angular-loading-bar']); //cluster -var cluster_module = angular.module('cluster', ['app.service', 'apollo.directive', 'app.util', 'toastr', 'angular-loading-bar']); +var cluster_module = angular.module('cluster', ['app.service', 'apollo.directive', 'app.util', 'toastr', 'angular-loading-bar' , 'valdr']); //release history var release_history_module = angular.module('release_history', ['app.service', 'apollo.directive', 'app.util', 'toastr', 'angular-loading-bar']); diff --git a/apollo-portal/src/main/resources/static/scripts/controller/AppController.js b/apollo-portal/src/main/resources/static/scripts/controller/AppController.js index ed4a5f91f..69045d719 100644 --- a/apollo-portal/src/main/resources/static/scripts/controller/AppController.js +++ b/apollo-portal/src/main/resources/static/scripts/controller/AppController.js @@ -1,5 +1,5 @@ -create_app_module.controller('CreateAppController', ['$scope', '$window', 'toastr', 'AppService', 'UserService', 'AppUtil', 'OrganizationService', - function ($scope, $window, toastr, AppService, UserService, AppUtil, OrganizationService) { +app_module.controller('CreateAppController', ['$scope', '$window', 'toastr', 'AppService', 'UserService', 'AppUtil', 'OrganizationService', + function ($scope, $window, toastr, AppService, UserService, AppUtil, OrganizationService) { $scope.submitBtnDisabled = false; diff --git a/apollo-portal/src/main/resources/static/scripts/controller/ClusterController.js b/apollo-portal/src/main/resources/static/scripts/controller/ClusterController.js index 940da91bc..fa5bf63f4 100644 --- a/apollo-portal/src/main/resources/static/scripts/controller/ClusterController.js +++ b/apollo-portal/src/main/resources/static/scripts/controller/ClusterController.js @@ -33,6 +33,7 @@ cluster_module.controller('ClusterController', }; $scope.create = function () { + var noEnvChecked = true; $scope.envs.forEach(function (env) { if (env.checked) { diff --git a/apollo-portal/src/main/resources/static/scripts/controller/IndexController.js b/apollo-portal/src/main/resources/static/scripts/controller/IndexController.js index 4c3fc9869..d5e672c20 100644 --- a/apollo-portal/src/main/resources/static/scripts/controller/IndexController.js +++ b/apollo-portal/src/main/resources/static/scripts/controller/IndexController.js @@ -11,32 +11,60 @@ index_module.controller('IndexController', ['$scope', '$window', 'toastr', 'AppS toastr.error(AppUtil.errorMsg(result), "load env error"); }); - var apps = []; - + + $scope.switchEnv = function (env) { $scope.selectedEnv = env; loadApps(env); }; - + + var sourceApps = []; + function loadApps(env){ AppService.find_all_app(env).then(function (result) { - apps = result; - $scope.apps = apps; - $scope.appsCount = apps.length; + sourceApps = sortApps(result); + $scope.apps = sourceApps; + $scope.appsCount = sourceApps.length; $scope.selectedEnv = env; }, function (result) { - toastr.error(AppUtil.errorMsg(result), "load apps error"); - }); + toastr.error(AppUtil.errorMsg(result), "load apps error"); + }); + } + + var VISITED_APPS_STORAGE_KEY = "VisitedApps"; + //访问过的App放在列表最前面,方便用户选择 + function sortApps(sourceApps) { + var visitedApps = JSON.parse(localStorage.getItem(VISITED_APPS_STORAGE_KEY)); + if (!visitedApps){ + return; + } + var existedVisitedAppsMap = {}; + visitedApps.forEach(function (app) { + existedVisitedAppsMap[app] = true; + }); + + var sortedApps = []; + sourceApps.forEach(function (app) { + if (existedVisitedAppsMap[app.appId]){ + sortedApps.push(app); + } + }); + sourceApps.forEach(function (app) { + if (!existedVisitedAppsMap[app.appId]){ + sortedApps.push(app); + } + }); + return sortedApps; } - + $scope.search = function () { var key = $scope.searchKey.toLocaleLowerCase(); if (key == '') { - $scope.apps = apps; + $scope.apps = sourceApps; return; } var result = []; - apps.forEach(function (item) { + sourceApps.forEach(function (item) { if (item.appId.toLocaleLowerCase().indexOf(key) >= 0 || item.name.toLocaleLowerCase().indexOf(key) >= 0) { result.push(item); diff --git a/apollo-portal/src/main/resources/static/scripts/controller/NamespaceController.js b/apollo-portal/src/main/resources/static/scripts/controller/NamespaceController.js index 99f59328a..aadf32097 100644 --- a/apollo-portal/src/main/resources/static/scripts/controller/NamespaceController.js +++ b/apollo-portal/src/main/resources/static/scripts/controller/NamespaceController.js @@ -109,6 +109,7 @@ namespace_module.controller("LinkNamespaceController", toastr.error(AppUtil.errorMsg(result)); }); } else { + $scope.submitBtnDisabled = true; NamespaceService.createAppNamespace($scope.appId, $scope.appNamespace).then( function (result) { diff --git a/apollo-portal/src/main/resources/static/scripts/controller/config/ConfigBaseInfoController.js b/apollo-portal/src/main/resources/static/scripts/controller/config/ConfigBaseInfoController.js index 560331bdd..9c1333bf5 100644 --- a/apollo-portal/src/main/resources/static/scripts/controller/config/ConfigBaseInfoController.js +++ b/apollo-portal/src/main/resources/static/scripts/controller/config/ConfigBaseInfoController.js @@ -6,6 +6,27 @@ application_module.controller("ConfigBaseInfoController", var appId = AppUtil.parseParams($location.$$url).appid; + //save user recent visited apps + var VISITED_APPS_STORAGE_KEY = "VisitedApps"; + var visitedApps = JSON.parse(localStorage.getItem(VISITED_APPS_STORAGE_KEY)); + var hasSaved = false; + if (visitedApps){ + visitedApps.forEach(function (app) { + if (app == appId){ + hasSaved = true; + return; + } + }); + }else { + visitedApps = []; + } + if (!hasSaved){ + visitedApps.push(appId); + + localStorage.setItem(VISITED_APPS_STORAGE_KEY, + JSON.stringify(visitedApps)); + } + //load session storage to recovery scene var scene = JSON.parse(sessionStorage.getItem(appId)); diff --git a/apollo-portal/src/main/resources/static/scripts/controller/config/ConfigNamespaceController.js b/apollo-portal/src/main/resources/static/scripts/controller/config/ConfigNamespaceController.js index bb03f7bef..2b2282fb4 100644 --- a/apollo-portal/src/main/resources/static/scripts/controller/config/ConfigNamespaceController.js +++ b/apollo-portal/src/main/resources/static/scripts/controller/config/ConfigNamespaceController.js @@ -131,6 +131,7 @@ application_module.controller("ConfigNamespaceController", $scope.releaseComment = ''; function release() { + $scope.releaseBtnDisabled = true; ReleaseService.release($rootScope.pageContext.appId, $rootScope.pageContext.env, $rootScope.pageContext.clusterName, @@ -289,6 +290,7 @@ application_module.controller("ConfigNamespaceController", } selectedClusters.forEach(function (cluster) { if ($scope.tableViewOperType == TABLE_VIEW_OPER_TYPE.CREATE) { + //check key unique var hasRepeatKey = false; toOperationNamespace.items.forEach(function (item) { @@ -324,6 +326,7 @@ application_module.controller("ConfigNamespaceController", if (!$scope.item.comment) { $scope.item.comment = ""; } + ConfigService.update_item($rootScope.pageContext.appId, cluster.env, cluster.name, diff --git a/apollo-portal/src/main/resources/static/scripts/valdr.js b/apollo-portal/src/main/resources/static/scripts/valdr.js new file mode 100644 index 000000000..4b6dc519b --- /dev/null +++ b/apollo-portal/src/main/resources/static/scripts/valdr.js @@ -0,0 +1,108 @@ +app_module.config(function (valdrProvider) { + valdrProvider.addConstraints({ + 'App': { + 'appId': { + 'size': { + 'max': 32, + 'message': 'AppId长度不能多于32个字符' + }, + 'required': { + 'message': 'AppId不能为空' + } + }, + 'appName': { + 'size': { + 'max': 32, + 'message': '应用名称长度不能多于32个字符' + }, + 'required': { + 'message': '应用名称不能为空' + } + } + } + }) +}); + +cluster_module.config(function (valdrProvider) { + valdrProvider.addConstraints({ + 'Cluster': { + 'clusterName': { + 'size': { + 'max': 32, + 'message': '集群名称长度不能多于32个字符' + }, + 'required': { + 'message': '集群名称不能为空' + } + } + } + }) +}); + +namespace_module.config(function (valdrProvider) { + valdrProvider.addConstraints({ + 'AppNamespace': { + 'namespaceName': { + 'size': { + 'max': 32, + 'message': 'Namespace名称长度不能多于32个字符' + }, + 'required': { + 'message': 'Namespace名称不能为空' + } + }, + 'comment': { + 'size': { + 'max': 64, + 'message': '备注长度不能多于64个字符' + } + } + } + }) +}); + +application_module.config(function (valdrProvider) { + valdrProvider.addConstraints({ + 'Item': { + 'key': { + 'size': { + 'max': 128, + 'message': 'Key长度不能多于128个字符' + }, + 'required': { + 'message': 'Key不能为空' + } + }, + 'value': { + 'required': { + 'message': 'value不能为空' + } + }, + 'comment': { + 'size': { + 'max': 64, + 'message': '备注长度不能多于64个字符' + } + } + }, + 'Release': { + 'releaseName': { + 'size': { + 'max': 64, + 'message': 'Release Name长度不能多于64个字符' + }, + 'required': { + 'message': 'Release Name不能为空' + } + }, + 'comment': { + 'size': { + 'max': 64, + 'message': '备注长度不能多于64个字符' + } + } + } + }) +}); + + diff --git a/apollo-portal/src/main/resources/static/styles/common-style.css b/apollo-portal/src/main/resources/static/styles/common-style.css index ea801f683..63a52fb28 100644 --- a/apollo-portal/src/main/resources/static/styles/common-style.css +++ b/apollo-portal/src/main/resources/static/styles/common-style.css @@ -25,15 +25,15 @@ p, td, span { word-break: break-all; } -table{ +table { text-align: center; } -.no-radius{ +.no-radius { border-radius: 0px; } -.hide-border-top{ +.hide-border-top { border-top: 0px; } @@ -270,13 +270,12 @@ table th { background: #f1f2f7; } -.namespace-attribute-public{ +.namespace-attribute-public { background: #31708f; width: 40px; cursor: pointer; } - .second-panel-heading .nav-tabs { border-bottom: 0px; } @@ -400,60 +399,74 @@ table th { height: 5px; } -.release-history .media-body{ +.release-history .media-body { padding-left: 20px; } -.release-history .panel-body .load-more{ +.release-history .panel-body .load-more { margin-top: 20px; } -.release-history .media-body textarea{ +.release-history .media-body textarea { margin-top: 10px; } -.release-history .icon{ +.release-history .icon { font-size: 13px; } -.release-history .info{ +.release-history .info { font-size: 13px; margin-left: 5px; margin-top: 2px; } -.release-history .user .info{ +.release-history .user .info { font-size: 22px; } -.release-history .time{ +.release-history .time { padding-top: 8px; } -.release-history .comment{ +.release-history .comment { padding-top: 10px; } -.release-history .table{ +.release-history .table { margin-top: 15px; } -.release-history .badge-0{ +.release-history .badge-0 { background: #f0ad4e; } -.release-history .badge-1{ +.release-history .badge-1 { background: #c3c3c3; } -.release-history .badge-2{ +.release-history .badge-2 { background: #27AE60; } -.release-history .badge-3{ +.release-history .badge-3 { background: #3478a8; } -.release-history .label{ +.release-history .label { margin-right: 15px; } + +.valdr-message { + display: none; +} + +.valdr-message.ng-dirty.ng-invalid.ng-touched { + display: inline; + color: #a94442; +} + +.form-group .form-control.ng-invalid.ng-dirty.ng-touched { + border-color: #a94442; +} + diff --git a/apollo-portal/src/main/resources/static/vendor/valdr/valdr-message.min.js b/apollo-portal/src/main/resources/static/vendor/valdr/valdr-message.min.js new file mode 100755 index 000000000..2ff97d37f --- /dev/null +++ b/apollo-portal/src/main/resources/static/vendor/valdr/valdr-message.min.js @@ -0,0 +1 @@ +!function(a,b){"use strict";angular.module("valdr").provider("valdrMessage",function(){var a,b,c={},d="valdr/default-message.html",e='
{{ violation.message }}
',f='
';this.setTemplate=function(a){b=a},this.setTemplateUrl=function(b){a=b},this.addMessages=function(a){angular.extend(c,a)};var g=this.addMessages;this.getMessage=function(a,b,d){var e=a+"."+b+"."+d;return c[e]||c[d]||"["+d+"]"};var h=this.getMessage;this.$get=["$templateCache","$injector",function(c,i){function j(){try{return i.get("$translate")}catch(a){return void 0}}function k(){try{return i.get("valdrFieldNameKeyGenerator")}catch(a){return function(a){return a.type+"."+a.field}}}function l(){return angular.isDefined(b)?b:p?f:e}function m(){c.put(d,l()),a&&b&&c.put(a,b)}var n=!1,o=j(),p=angular.isDefined(o),q=k();return m(),{templateUrl:a||d,setTemplate:function(a){b=a,m()},translateAvailable:p,$translate:o,fieldNameKeyGenerator:q,addMessages:g,getMessage:h,angularMessagesEnabled:n}}]});var c=function(a){return["$compile",function(b){return{restrict:a,require:["?^valdrType","?^ngModel","?^valdrFormGroup"],link:function(a,c,d,e){var f=e[0],g=e[1],h=e[2],i=d.valdrNoValidate,j=d.valdrNoMessage,k=d.name;if(f&&h&&g&&!angular.isDefined(i)&&!angular.isDefined(j)){var l=angular.element('');b(l)(a),h.addMessageElement(g,l),a.$on("$destroy",function(){h.removeMessageElement(g)})}}}}]},d=c("E"),e=c("A"),f={getType:angular.noop};angular.module("valdr").directive("input",d).directive("select",d).directive("textarea",d).directive("enableValdrMessage",e).directive("valdrMessage",["$rootScope","$injector","valdrMessage","valdrUtil",function(a,b,c,d){return{replace:!0,restrict:"A",scope:{formFieldName:"@valdrMessage"},templateUrl:function(){return c.templateUrl},require:["^form","?^valdrType"],link:function(b,e,g,h){var i=h[0],j=h[1]||f,k=function(){c.translateAvailable&&angular.isArray(b.violations)&&angular.forEach(b.violations,function(a){c.$translate(c.fieldNameKeyGenerator(a)).then(function(b){a.fieldName=b})})},l=function(a){var d=j.getType(),e=b.formFieldName;return{type:d,field:e,validator:a,message:c.getMessage(d,e,a)}},m=function(){b.violations=[],angular.forEach(b.formField.valdrViolations,function(a){b.violations.push(a)}),c.angularMessagesEnabled&&angular.forEach(b.formField.$error,function(a,c){d.startsWith(c,"valdr")||b.violations.push(l(c))}),b.violation=b.violations[0],k()},n=function(){b.violations=void 0,b.violation=void 0},o=function(){return b.formField=i[b.formFieldName],b.formField?{valdr:b.formField.valdrViolations,error:b.formField.$error}:void 0};b.$watch(o,function(){b.formField&&b.formField.$invalid?m():n()},!0),a.$on("$translateChangeSuccess",function(){k()})}}}])}(window,document); \ No newline at end of file diff --git a/apollo-portal/src/main/resources/static/vendor/valdr/valdr.min.js b/apollo-portal/src/main/resources/static/vendor/valdr/valdr.min.js new file mode 100755 index 000000000..320731bd0 --- /dev/null +++ b/apollo-portal/src/main/resources/static/vendor/valdr/valdr.min.js @@ -0,0 +1 @@ +!function(a,b){"use strict";angular.module("valdr",["ng"]).constant("valdrEvents",{revalidate:"valdr-revalidate"}).value("valdrConfig",{addFormGroupClass:!0}).value("valdrClasses",{formGroup:"form-group",valid:"ng-valid",invalid:"ng-invalid",dirty:"ng-dirty",pristine:"ng-pristine",touched:"ng-touched",untouched:"ng-untouched",invalidDirtyTouchedGroup:"valdr-invalid-dirty-touched-group"}),angular.module("valdr").factory("valdrUtil",[function(){var a=function(a){return-1===a.lastIndexOf(".")?a:a.substring(a.lastIndexOf(".")+1,a.length)},b=/[A-Z]/g,c=function(a){return a.replace(b,function(a,b){return(b?"-":"")+a.toLowerCase()})},d=function(b){if(angular.isString(b)){var d=a(b);return d=c(d),"valdr-"+d}return b};return{validatorNameToToken:d,isNaN:function(a){return this.isNumber(a)&&a!==+a},isNumber:function(a){var b=typeof a;return"number"===b||a&&"object"===b&&"[object Number]"===Object.prototype.toString.call(a)||!1},has:function(a,b){return a?Object.prototype.hasOwnProperty.call(a,b):!1},notEmpty:function(a){return this.isNaN(a)?!1:angular.isDefined(a)&&""!==a&&null!==a},isEmpty:function(a){return this.isNaN(a)?!1:!this.notEmpty(a)},startsWith:function(a,b){return angular.isString(a)&&angular.isString(b)&&0===a.lastIndexOf(b,0)}}}]),angular.module("valdr").factory("valdrRequiredValidator",["valdrUtil",function(a){return{name:"required",validate:function(b){return a.notEmpty(b)}}}]),angular.module("valdr").factory("valdrMinValidator",["valdrUtil",function(a){return{name:"min",validate:function(b,c){var d=Number(c.value),e=Number(b);return a.isNaN(b)?!1:a.isEmpty(b)||e>=d}}}]),angular.module("valdr").factory("valdrMaxValidator",["valdrUtil",function(a){return{name:"max",validate:function(b,c){var d=Number(c.value),e=Number(b);return a.isNaN(b)?!1:a.isEmpty(b)||d>=e}}}]),angular.module("valdr").factory("valdrSizeValidator",function(){return{name:"size",validate:function(a,b){var c=b.min||0,d=b.max;return a=a||"",a.length>=c&&(void 0===d||a.length<=d)}}}),angular.module("valdr").factory("valdrEmailValidator",["valdrUtil",function(a){var b=/^[a-z0-9!#$%&'*+/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;return{name:"email",validate:function(c){return a.isEmpty(c)||b.test(c)}}}]),angular.module("valdr").factory("valdrUrlValidator",["valdrUtil",function(a){var b=/^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;return{name:"url",validate:function(c){return a.isEmpty(c)||b.test(c)}}}]),angular.module("valdr").factory("valdrDigitsValidator",["valdrUtil",function(a){var b=new RegExp("[^.\\d]","g"),c=function(a){return Number(a).toString().replace(b,"")},d=function(a,b){return a?a.length<=b:!0},e=function(a,b){var e,f,g=b.integer,h=b.fraction;return e=c(a),f=e.split("."),d(f[0],g)&&d(f[1],h)};return{name:"digits",validate:function(b,c){return a.isEmpty(b)?!0:a.isNaN(Number(b))?!1:e(b,c)}}}]),angular.module("valdr").factory("futureAndPastSharedValidator",["valdrUtil",function(a){var b=["D-M-YYYY","D.M.YYYY","D/M/YYYY","D. M. YYYY","YYYY.M.D"];return{validate:function(c,d){var e,f=moment();if(a.isEmpty(c))return!0;e=moment(c);for(var g=0;g=d:!1}}}]),angular.module("valdr").factory("valdrMaxLengthValidator",["valdrUtil",function(a){return{name:"maxLength",validate:function(b,c){var d=c.number;return a.isEmpty(b)?!0:"string"==typeof b?b.length<=d:!1}}}]),angular.module("valdr").factory("valdrHibernateEmailValidator",["valdrUtil",function(a){var b="[a-z0-9!#$%&'*+/=?^_`{|}~-]",c="^"+b+"+(\\."+b+"+)*$",d="^\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\]$",e=new RegExp("^"+b+"+(\\."+b+"+)*$","i"),f=new RegExp(c+"|"+d,"i");return{name:"hibernateEmail",validate:function(b){if(a.isEmpty(b))return!0;var c=b.split("@");return 2!==c.length?!1:e.test(c[0])?f.test(c[1]):!1}}}]),angular.module("valdr").provider("valdr",function(){var a,b,c={},d={},e={},f=["valdrRequiredValidator","valdrSizeValidator","valdrMinLengthValidator","valdrMaxLengthValidator","valdrMinValidator","valdrMaxValidator","valdrEmailValidator","valdrUrlValidator","valdrDigitsValidator","valdrFutureValidator","valdrPastValidator","valdrPatternValidator","valdrHibernateEmailValidator"],g=function(a){angular.extend(c,a)};this.addConstraints=g;var h=function(a){angular.isArray(a)?angular.forEach(a,function(a){delete c[a]}):angular.isString(a)&&delete c[a]};this.removeConstraints=h,this.setConstraintUrl=function(b){a=b},this.addValidator=function(a){f.push(a)},this.addConstraintAlias=function(a,b){angular.isArray(e[a])||(e[a]=[]),e[a].push(b)},this.$get=["$log","$injector","$rootScope","$http","valdrEvents","valdrUtil","valdrClasses",function(i,j,k,l,m,n,o){angular.forEach(f,function(a){var b=j.get(a);d[b.name]=b,angular.isArray(e[b.name])&&angular.forEach(e[b.name],function(a){d[a]=b})}),a&&(b=!0,l.get(a).then(function(a){b=!1,g(a.data),k.$broadcast(m.revalidate)})["finally"](function(){b=!1}));var p=function(a){return n.has(c,a)?c[a]:void(b||i.warn("No constraints for type '"+a+"' available."))};return{validate:function(a,b,c){var e={valid:!0},f=p(a);if(n.has(f,b)){var g=f[b],h=!0,j=[],k=[];return angular.forEach(g,function(f,g){var l=d[g];if(angular.isUndefined(l))return i.warn("No validator defined for '"+g+"'. Can not validate field '"+b+"'"),e;var m=l.validate(c,f),n={valid:m,value:c,field:b,type:a,validator:g};angular.extend(n,f),j.push(n),m||k.push(n),h=h&&m}),{valid:h,violations:0===k.length?void 0:k,validationResults:0===j.length?void 0:j}}return e},addConstraints:function(a){g(a),k.$broadcast(m.revalidate)},removeConstraints:function(a){h(a),k.$broadcast(m.revalidate)},getConstraints:function(){return c},setClasses:function(a){angular.extend(o,a),k.$broadcast(m.revalidate)}}}]});var c=["valdrClasses","valdrConfig",function(a,b){return{restrict:"EA",link:function(c,d){b.addFormGroupClass&&d.addClass(a.formGroup)},controller:["$scope","$element",function(b,c){var d=[],e={},f=function(){var a={invalidDirtyTouchedGroup:!1,valid:!0,itemStates:[]};return angular.forEach(d,function(b){b.$touched&&b.$dirty&&b.$invalid&&(a.invalidDirtyTouchedGroup=!0),b.$invalid&&(a.valid=!1);var c={name:b.$name,touched:b.$touched,dirty:b.$dirty,valid:b.$valid};a.itemStates.push(c)}),a},g=function(b){c.toggleClass(a.invalidDirtyTouchedGroup,b.invalidDirtyTouchedGroup),c.toggleClass(a.valid,b.valid),c.toggleClass(a.invalid,!b.valid),angular.forEach(b.itemStates,function(b){var c=e[b.name];c&&(c.toggleClass(a.valid,b.valid),c.toggleClass(a.invalid,!b.valid),c.toggleClass(a.dirty,b.dirty),c.toggleClass(a.pristine,!b.dirty),c.toggleClass(a.touched,b.touched),c.toggleClass(a.untouched,!b.touched))})};b.$watch(f,g,!0),this.addFormItem=function(a){d.push(a)},this.removeFormItem=function(a){var b=d.indexOf(a);b>=0&&d.splice(b,1)},this.addMessageElement=function(a,b){c.append(b),e[a.$name]=b},this.removeMessageElement=function(a){e[a.$name].remove()}}]}}];angular.module("valdr").directive("valdrFormGroup",c),angular.module("valdr").directive("valdrType",function(){return{priority:1,controller:["$attrs",function(a){this.getType=function(){return a.valdrType}}]}});var d={isEnabled:function(){return!0}},e={addFormItem:angular.noop,removeFormItem:angular.noop},f=function(a){return["valdrEvents","valdr","valdrUtil",function(b,c,f){return{restrict:a,require:["?^valdrType","?^ngModel","?^valdrFormGroup","?^valdrEnabled"],link:function(a,g,h,i){var j=i[0],k=i[1],l=i[2]||e,m=i[3]||d,n=h.valdrNoValidate,o=h.name;if(j&&k&&!angular.isDefined(n)){l.addFormItem(k),f.isEmpty(o)&&m.isEnabled()&&console.warn('Form element with ID "'+h.id+'" is not bound to a field name.');var p=function(a){if(m.isEnabled()){var b=["valdr"];angular.forEach(a.validationResults,function(a){var c=f.validatorNameToToken(a.validator);k.$setValidity(c,a.valid),b.push(c)}),k.$setValidity("valdr",a.valid),k.valdrViolations=a.violations,angular.forEach(k.$error,function(a,c){-1===b.indexOf(c)&&f.startsWith(c,"valdr")&&k.$setValidity(c,!0)})}else angular.forEach(k.$error,function(a,b){f.startsWith(b,"valdr")&&k.$setValidity(b,!0)}),k.valdrViolations=void 0},q=function(a){var b=c.validate(j.getType(),o,a);return p(b),m.isEnabled()?b.valid:!0};k.$validators.valdr=q,a.$on(b.revalidate,function(){q(k.$modelValue)}),a.$on("$destroy",function(){l.removeFormItem(k)})}}}}]},g=f("E"),h=f("A");angular.module("valdr").directive("input",g).directive("select",g).directive("textarea",g).directive("enableValdrValidation",h),angular.module("valdr").directive("valdrEnabled",["valdrEvents",function(a){return{controller:["$scope","$attrs",function(b,c){b.$watch(c.valdrEnabled,function(){b.$broadcast(a.revalidate)}),this.isEnabled=function(){var a=b.$eval(c.valdrEnabled);return void 0===a?!0:a}}]}}])}(window,document); \ No newline at end of file -- GitLab