Commit 437026f3 authored by Jason Song's avatar Jason Song Committed by Jared Tan

add i18n support and English translations (#2641)

* init i18n support

* polish translations and fix some bugs introduced
parent f050e44d
...@@ -45,6 +45,7 @@ public class WebMvcConfig implements WebMvcConfigurer, WebServerFactoryCustomize ...@@ -45,6 +45,7 @@ public class WebMvcConfig implements WebMvcConfigurer, WebServerFactoryCustomize
addCacheControl(registry, "scripts", 86400); addCacheControl(registry, "scripts", 86400);
addCacheControl(registry, "styles", 86400); addCacheControl(registry, "styles", 86400);
addCacheControl(registry, "views", 86400); addCacheControl(registry, "views", 86400);
addCacheControl(registry, "i18n", 86400);
} }
private void addCacheControl(ResourceHandlerRegistry registry, String folder, int cachePeriod) { private void addCacheControl(ResourceHandlerRegistry registry, String folder, int cachePeriod) {
......
...@@ -11,7 +11,7 @@ public class AppDTO extends BaseDTO{ ...@@ -11,7 +11,7 @@ public class AppDTO extends BaseDTO{
@Pattern( @Pattern(
regexp = InputValidator.CLUSTER_NAMESPACE_VALIDATOR, regexp = InputValidator.CLUSTER_NAMESPACE_VALIDATOR,
message = "AppId格式错误: " + InputValidator.INVALID_CLUSTER_NAMESPACE_MESSAGE message = "Invalid AppId format: " + InputValidator.INVALID_CLUSTER_NAMESPACE_MESSAGE
) )
private String appId; private String appId;
......
...@@ -11,7 +11,7 @@ public class ClusterDTO extends BaseDTO{ ...@@ -11,7 +11,7 @@ public class ClusterDTO extends BaseDTO{
@NotBlank(message = "cluster name cannot be blank") @NotBlank(message = "cluster name cannot be blank")
@Pattern( @Pattern(
regexp = InputValidator.CLUSTER_NAMESPACE_VALIDATOR, regexp = InputValidator.CLUSTER_NAMESPACE_VALIDATOR,
message = "Cluster格式错误: " + InputValidator.INVALID_CLUSTER_NAMESPACE_MESSAGE message = "Invalid Cluster format: " + InputValidator.INVALID_CLUSTER_NAMESPACE_MESSAGE
) )
private String name; private String name;
......
...@@ -12,7 +12,7 @@ public class NamespaceDTO extends BaseDTO{ ...@@ -12,7 +12,7 @@ public class NamespaceDTO extends BaseDTO{
@Pattern( @Pattern(
regexp = InputValidator.CLUSTER_NAMESPACE_VALIDATOR, regexp = InputValidator.CLUSTER_NAMESPACE_VALIDATOR,
message = "Namespace格式错误: " + InputValidator.INVALID_CLUSTER_NAMESPACE_MESSAGE message = "Invalid Namespace format: " + InputValidator.INVALID_CLUSTER_NAMESPACE_MESSAGE
) )
private String namespaceName; private String namespaceName;
......
...@@ -22,7 +22,7 @@ public class AppNamespace extends BaseEntity { ...@@ -22,7 +22,7 @@ public class AppNamespace extends BaseEntity {
@NotBlank(message = "AppNamespace Name cannot be blank") @NotBlank(message = "AppNamespace Name cannot be blank")
@Pattern( @Pattern(
regexp = InputValidator.CLUSTER_NAMESPACE_VALIDATOR, regexp = InputValidator.CLUSTER_NAMESPACE_VALIDATOR,
message = "Namespace格式错误: " + InputValidator.INVALID_CLUSTER_NAMESPACE_MESSAGE + " & " + InputValidator.INVALID_NAMESPACE_NAMESPACE_MESSAGE message = "Invalid Namespace format: " + InputValidator.INVALID_CLUSTER_NAMESPACE_MESSAGE + " & " + InputValidator.INVALID_NAMESPACE_NAMESPACE_MESSAGE
) )
@Column(name = "Name", nullable = false) @Column(name = "Name", nullable = false)
private String name; private String name;
......
...@@ -8,8 +8,8 @@ import java.util.regex.Pattern; ...@@ -8,8 +8,8 @@ import java.util.regex.Pattern;
* @author Jason Song(song_s@ctrip.com) * @author Jason Song(song_s@ctrip.com)
*/ */
public class InputValidator { public class InputValidator {
public static final String INVALID_CLUSTER_NAMESPACE_MESSAGE = "只允许输入数字,字母和符号 - _ ."; public static final String INVALID_CLUSTER_NAMESPACE_MESSAGE = "Only digits, alphabets and symbol - _ . are allowed";
public static final String INVALID_NAMESPACE_NAMESPACE_MESSAGE = "不允许以.json, .yml, .yaml, .xml, .properties结尾"; public static final String INVALID_NAMESPACE_NAMESPACE_MESSAGE = "not allowed to end with .json, .yml, .yaml, .xml, .properties";
public static final String CLUSTER_NAMESPACE_VALIDATOR = "[0-9a-zA-Z_.-]+"; public static final String CLUSTER_NAMESPACE_VALIDATOR = "[0-9a-zA-Z_.-]+";
private static final String APP_NAMESPACE_VALIDATOR = "[a-zA-Z0-9._-]+(?<!\\.(json|yml|yaml|xml|properties))$"; private static final String APP_NAMESPACE_VALIDATOR = "[a-zA-Z0-9._-]+(?<!\\.(json|yml|yaml|xml|properties))$";
private static final Pattern CLUSTER_NAMESPACE_PATTERN = Pattern.compile(CLUSTER_NAMESPACE_VALIDATOR); private static final Pattern CLUSTER_NAMESPACE_PATTERN = Pattern.compile(CLUSTER_NAMESPACE_VALIDATOR);
......
...@@ -59,7 +59,7 @@ public class ClusterController { ...@@ -59,7 +59,7 @@ public class ClusterController {
if (!InputValidator.isValidClusterNamespace(clusterName)) { if (!InputValidator.isValidClusterNamespace(clusterName)) {
throw new BadRequestException( throw new BadRequestException(
String.format("Cluster Name 格式错误: %s", InputValidator.INVALID_CLUSTER_NAMESPACE_MESSAGE)); String.format("Invalid ClusterName format: %s", InputValidator.INVALID_CLUSTER_NAMESPACE_MESSAGE));
} }
if (userService.findByUserId(operator) == null) { if (userService.findByUserId(operator) == null) {
......
...@@ -68,7 +68,7 @@ public class NamespaceController { ...@@ -68,7 +68,7 @@ public class NamespaceController {
appNamespaceDTO.getFormat(), appNamespaceDTO.getDataChangeCreatedBy()); appNamespaceDTO.getFormat(), appNamespaceDTO.getDataChangeCreatedBy());
if (!InputValidator.isValidAppNamespace(appNamespaceDTO.getName())) { if (!InputValidator.isValidAppNamespace(appNamespaceDTO.getName())) {
throw new BadRequestException(String.format("Namespace格式错误: %s", throw new BadRequestException(String.format("Invalid Namespace format: %s",
InputValidator.INVALID_CLUSTER_NAMESPACE_MESSAGE + " & " InputValidator.INVALID_CLUSTER_NAMESPACE_MESSAGE + " & "
+ InputValidator.INVALID_NAMESPACE_NAMESPACE_MESSAGE)); + InputValidator.INVALID_NAMESPACE_NAMESPACE_MESSAGE));
} }
......
...@@ -193,7 +193,7 @@ public class NamespaceController { ...@@ -193,7 +193,7 @@ public class NamespaceController {
@RequestParam(defaultValue = "true") boolean appendNamespacePrefix, @RequestParam(defaultValue = "true") boolean appendNamespacePrefix,
@Valid @RequestBody AppNamespace appNamespace) { @Valid @RequestBody AppNamespace appNamespace) {
if (!InputValidator.isValidAppNamespace(appNamespace.getName())) { if (!InputValidator.isValidAppNamespace(appNamespace.getName())) {
throw new BadRequestException(String.format("Namespace格式错误: %s", throw new BadRequestException(String.format("Invalid Namespace format: %s",
InputValidator.INVALID_CLUSTER_NAMESPACE_MESSAGE + " & " + InputValidator.INVALID_NAMESPACE_NAMESPACE_MESSAGE)); InputValidator.INVALID_CLUSTER_NAMESPACE_MESSAGE + " & " + InputValidator.INVALID_NAMESPACE_NAMESPACE_MESSAGE));
} }
......
...@@ -154,7 +154,7 @@ public class PermissionController { ...@@ -154,7 +154,7 @@ public class PermissionController {
Set<String> assignedUser = rolePermissionService.assignRoleToUsers(RoleUtils.buildNamespaceRoleName(appId, namespaceName, roleType, env), Set<String> assignedUser = rolePermissionService.assignRoleToUsers(RoleUtils.buildNamespaceRoleName(appId, namespaceName, roleType, env),
Sets.newHashSet(user), userInfoHolder.getUser().getUserId()); Sets.newHashSet(user), userInfoHolder.getUser().getUserId());
if (CollectionUtils.isEmpty(assignedUser)) { if (CollectionUtils.isEmpty(assignedUser)) {
throw new BadRequestException(user + "已授权"); throw new BadRequestException(user + " already authorized");
} }
return ResponseEntity.ok().build(); return ResponseEntity.ok().build();
...@@ -209,7 +209,7 @@ public class PermissionController { ...@@ -209,7 +209,7 @@ public class PermissionController {
Set<String> assignedUser = rolePermissionService.assignRoleToUsers(RoleUtils.buildNamespaceRoleName(appId, namespaceName, roleType), Set<String> assignedUser = rolePermissionService.assignRoleToUsers(RoleUtils.buildNamespaceRoleName(appId, namespaceName, roleType),
Sets.newHashSet(user), userInfoHolder.getUser().getUserId()); Sets.newHashSet(user), userInfoHolder.getUser().getUserId());
if (CollectionUtils.isEmpty(assignedUser)) { if (CollectionUtils.isEmpty(assignedUser)) {
throw new BadRequestException(user + "已授权"); throw new BadRequestException(user + " already authorized");
} }
return ResponseEntity.ok().build(); return ResponseEntity.ok().build();
...@@ -253,7 +253,7 @@ public class PermissionController { ...@@ -253,7 +253,7 @@ public class PermissionController {
Set<String> assignedUsers = rolePermissionService.assignRoleToUsers(RoleUtils.buildAppRoleName(appId, roleType), Set<String> assignedUsers = rolePermissionService.assignRoleToUsers(RoleUtils.buildAppRoleName(appId, roleType),
Sets.newHashSet(user), userInfoHolder.getUser().getUserId()); Sets.newHashSet(user), userInfoHolder.getUser().getUserId());
if (CollectionUtils.isEmpty(assignedUsers)) { if (CollectionUtils.isEmpty(assignedUsers)) {
throw new BadRequestException(user + "已授权"); throw new BadRequestException(user + " already authorized");
} }
return ResponseEntity.ok().build(); return ResponseEntity.ok().build();
......
...@@ -14,7 +14,7 @@ public class AppModel { ...@@ -14,7 +14,7 @@ public class AppModel {
@NotBlank(message = "appId cannot be blank") @NotBlank(message = "appId cannot be blank")
@Pattern( @Pattern(
regexp = InputValidator.CLUSTER_NAMESPACE_VALIDATOR, regexp = InputValidator.CLUSTER_NAMESPACE_VALIDATOR,
message = "AppId格式错误: " + InputValidator.INVALID_CLUSTER_NAMESPACE_MESSAGE message = "Invalid AppId format: " + InputValidator.INVALID_CLUSTER_NAMESPACE_MESSAGE
) )
private String appId; private String appId;
......
...@@ -271,7 +271,7 @@ public class AuthConfiguration { ...@@ -271,7 +271,7 @@ public class AuthConfiguration {
http.csrf().disable(); http.csrf().disable();
http.headers().frameOptions().sameOrigin(); http.headers().frameOptions().sameOrigin();
http.authorizeRequests() http.authorizeRequests()
.antMatchers("/prometheus/**","/metrics/**","/openapi/**", "/vendor/**", "/styles/**", "/scripts/**", "/views/**", "/img/**").permitAll() .antMatchers("/prometheus/**","/metrics/**","/openapi/**", "/vendor/**", "/styles/**", "/scripts/**", "/views/**", "/img/**", "/i18n/**").permitAll()
.antMatchers("/**").hasAnyRole(USER_ROLE); .antMatchers("/**").hasAnyRole(USER_ROLE);
http.formLogin().loginPage("/signin").defaultSuccessUrl("/", true).permitAll().failureUrl("/signin?#/error").and() http.formLogin().loginPage("/signin").defaultSuccessUrl("/", true).permitAll().failureUrl("/signin?#/error").and()
.httpBasic(); .httpBasic();
...@@ -403,7 +403,7 @@ public class AuthConfiguration { ...@@ -403,7 +403,7 @@ public class AuthConfiguration {
http.csrf().disable(); http.csrf().disable();
http.headers().frameOptions().sameOrigin(); http.headers().frameOptions().sameOrigin();
http.authorizeRequests() http.authorizeRequests()
.antMatchers("/prometheus/**","/metrics/**","/openapi/**", "/vendor/**", "/styles/**", "/scripts/**", "/views/**", "/img/**").permitAll() .antMatchers("/prometheus/**","/metrics/**","/openapi/**", "/vendor/**", "/styles/**", "/scripts/**", "/views/**", "/img/**", "/i18n/**").permitAll()
.antMatchers("/**").authenticated(); .antMatchers("/**").authenticated();
http.formLogin().loginPage("/signin").defaultSuccessUrl("/", true).permitAll().failureUrl("/signin?#/error").and() http.formLogin().loginPage("/signin").defaultSuccessUrl("/", true).permitAll().failureUrl("/signin?#/error").and()
.httpBasic(); .httpBasic();
......
...@@ -12,11 +12,11 @@ public class RelativeDateFormat { ...@@ -12,11 +12,11 @@ public class RelativeDateFormat {
private static final long ONE_HOUR = 3600000L; private static final long ONE_HOUR = 3600000L;
private static final long ONE_DAY = 86400000L; private static final long ONE_DAY = 86400000L;
private static final String ONE_SECOND_AGO = "秒前"; private static final String ONE_SECOND_AGO = " seconds ago";
private static final String ONE_MINUTE_AGO = "分钟前"; private static final String ONE_MINUTE_AGO = " minutes ago";
private static final String ONE_HOUR_AGO = "小时前"; private static final String ONE_HOUR_AGO = " hours ago";
private static final String ONE_DAY_AGO = "天前"; private static final String ONE_DAY_AGO = " days ago";
private static final String ONE_MONTH_AGO = "月前"; private static final String ONE_MONTH_AGO = " months ago";
public static String format(Date date) { public static String format(Date date) {
if (date.after(new Date())) { if (date.after(new Date())) {
...@@ -39,11 +39,11 @@ public class RelativeDateFormat { ...@@ -39,11 +39,11 @@ public class RelativeDateFormat {
Date lastDayBeginTime = getDateOffset(-1); Date lastDayBeginTime = getDateOffset(-1);
if (date.after(lastDayBeginTime)) { if (date.after(lastDayBeginTime)) {
return "昨天"; return "yesterday";
} }
Date lastTwoDaysBeginTime = getDateOffset(-2); Date lastTwoDaysBeginTime = getDateOffset(-2);
if (date.after(lastTwoDaysBeginTime)) { if (date.after(lastTwoDaysBeginTime)) {
return "前天"; return "the day before yesterday";
} }
if (delta < 30L * ONE_DAY) { if (delta < 30L * ONE_DAY) {
long days = toDays(delta); long days = toDays(delta);
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<link rel="stylesheet" type="text/css" media='all' href="vendor/angular/loading-bar.min.css"> <link rel="stylesheet" type="text/css" media='all' href="vendor/angular/loading-bar.min.css">
<link rel="stylesheet" type="text/css" href="styles/common-style.css"> <link rel="stylesheet" type="text/css" href="styles/common-style.css">
<title>新建项目</title> <title>{{'App.CreateProject' | translate }}</title>
</head> </head>
<body> <body>
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
<div class="col-md-8 col-md-offset-2"> <div class="col-md-8 col-md-offset-2">
<div class="panel"> <div class="panel">
<header class="panel-heading"> <header class="panel-heading">
创建项目 {{'App.CreateProject' | translate }}
</header> </header>
<form class="form-horizontal panel-body" name="appForm" ng-controller="CreateAppController" <form class="form-horizontal panel-body" name="appForm" ng-controller="CreateAppController"
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
<div class="form-group"> <div class="form-group">
<label class="col-sm-3 control-label"> <label class="col-sm-3 control-label">
<apollorequiredfield></apollorequiredfield> <apollorequiredfield></apollorequiredfield>
部门</label> {{'Common.Department' | translate }}</label>
<div class="col-sm-3"> <div class="col-sm-3">
<select id="organization"> <select id="organization">
<option></option> <option></option>
...@@ -41,43 +41,44 @@ ...@@ -41,43 +41,44 @@
<div class="form-group" valdr-form-group> <div class="form-group" valdr-form-group>
<label class="col-sm-3 control-label"> <label class="col-sm-3 control-label">
<apollorequiredfield></apollorequiredfield> <apollorequiredfield></apollorequiredfield>
应用Id</label> {{'Common.AppId' | translate }}</label>
<div class="col-sm-3"> <div class="col-sm-3">
<input type="text" class="form-control" name="appId" ng-model="app.appId"> <input type="text" class="form-control" name="appId" ng-model="app.appId">
<small>(应用唯一标识)</small> <small>{{'App.AppIdTips' | translate }}
</small>
</div> </div>
</div> </div>
<div class="form-group" valdr-form-group> <div class="form-group" valdr-form-group>
<label class="col-sm-3 control-label"> <label class="col-sm-3 control-label">
<apollorequiredfield></apollorequiredfield> <apollorequiredfield></apollorequiredfield>
应用名称</label> {{'Common.AppName' | translate }}</label>
<div class="col-sm-5"> <div class="col-sm-5">
<input type="text" class="form-control" name="appName" ng-model="app.name"> <input type="text" class="form-control" name="appName" ng-model="app.name">
<small>(建议格式 xx-yy-zz 例:apollo-server)</small> <small>{{'App.AppNameTips' | translate }}</small>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="col-sm-3 control-label"> <label class="col-sm-3 control-label">
<apollorequiredfield></apollorequiredfield> <apollorequiredfield></apollorequiredfield>
应用负责人</label> {{'Common.AppOwnerLong' | translate }}</label>
<div class="col-sm-6 J_ownerSelectorPanel"> <div class="col-sm-6 J_ownerSelectorPanel">
<apollouserselector apollo-id="'ownerSelector'" disabled="isOpenManageAppMasterRoleLimit"></apollouserselector> <apollouserselector apollo-id="'ownerSelector'" disabled="isOpenManageAppMasterRoleLimit"></apollouserselector>
<small style="color: maroon" ng-if="isOpenManageAppMasterRoleLimit">(开启项目管理员分配权限控制后,应用负责人和项目管理员默认为本账号,不可选择)</small> <small style="color: maroon" ng-if="isOpenManageAppMasterRoleLimit">{{'App.AppOwnerTips' | translate }}</small>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="col-sm-3 control-label">项目管理员<br> <label class="col-sm-3 control-label">{{'Common.AppAdmin' | translate }}<br>
</label> </label>
<div class="col-sm-9 J_adminSelectorPanel"> <div class="col-sm-9 J_adminSelectorPanel">
<apollomultipleuserselector apollo-id="'adminSelector'" ng-disabled="isOpenManageAppMasterRoleLimit"></apollomultipleuserselector> <apollomultipleuserselector apollo-id="'adminSelector'" ng-disabled="isOpenManageAppMasterRoleLimit"></apollomultipleuserselector>
<br> <br>
<small>(应用负责人默认具有项目管理员权限,</small> <small>{{'App.AppAdminTips1' | translate }}</small>
<br> <br>
<small>项目管理员可以创建Namespace和集群、分配用户权限)</small> <small>{{'App.AppAdminTips2' | translate }}</small>
</div> </div>
</div> </div>
...@@ -86,7 +87,7 @@ ...@@ -86,7 +87,7 @@
<div class="col-sm-offset-3 col-sm-9"> <div class="col-sm-offset-3 col-sm-9">
<button type="submit" class="btn btn-primary" <button type="submit" class="btn btn-primary"
ng-disabled="appForm.$invalid || submitBtnDisabled">提交 ng-disabled="appForm.$invalid || submitBtnDisabled">{{'Common.Submit' | translate }}
</button> </button>
</div> </div>
</div> </div>
...@@ -104,6 +105,11 @@ ...@@ -104,6 +105,11 @@
<script src="vendor/angular/angular-resource.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/angular-toastr-1.4.1.tpls.min.js"></script>
<script src="vendor/angular/loading-bar.min.js"></script> <script src="vendor/angular/loading-bar.min.js"></script>
<script src="vendor/angular/angular-cookies.min.js"></script>
<script src="vendor/angular/angular-translate.2.18.1/angular-translate.min.js"></script>
<script src="vendor/angular/angular-translate.2.18.1/angular-translate-loader-static-files.min.js"></script>
<script src="vendor/angular/angular-translate.2.18.1/angular-translate-storage-cookie.min.js"></script>
<!-- jquery.js --> <!-- jquery.js -->
<script src="vendor/jquery.min.js" type="text/javascript"></script> <script src="vendor/jquery.min.js" type="text/javascript"></script>
......
<!doctype html> <!doctype html>
<html ng-app="setting"> <html ng-app="setting">
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="icon" href="../img/config.png"> <link rel="icon" href="../img/config.png">
...@@ -9,192 +10,198 @@ ...@@ -9,192 +10,198 @@
<link rel="stylesheet" type="text/css" media='all' href="../vendor/angular/loading-bar.min.css"> <link rel="stylesheet" type="text/css" media='all' href="../vendor/angular/loading-bar.min.css">
<link rel="stylesheet" type="text/css" href="../styles/common-style.css"> <link rel="stylesheet" type="text/css" href="../styles/common-style.css">
<link rel="stylesheet" type="text/css" href="../vendor/select2/select2.min.css"> <link rel="stylesheet" type="text/css" href="../vendor/select2/select2.min.css">
<title>项目管理</title> <title>{{'App.Setting.Title' | translate }}</title>
</head> </head>
<body> <body>
<apollonav></apollonav> <apollonav></apollonav>
<div class="container-fluid apollo-container project-setting" ng-controller="SettingController"> <div class="container-fluid apollo-container project-setting" ng-controller="SettingController">
<section class="col-md-10 col-md-offset-1 panel hidden"> <section class="col-md-10 col-md-offset-1 panel hidden">
<header class="panel-heading"> <header class="panel-heading">
<div class="row"> <div class="row">
<div class="col-md-7"> <div class="col-md-7">
<h4 class="modal-title">项目管理 ( AppId:<label ng-bind="pageContext.appId"></label> ) <h4 class="modal-title">{{'App.Setting.Title' | translate }} (
</h4> {{'Common.AppId' | translate }}:<label ng-bind="pageContext.appId"></label> )
</div> </h4>
<div class="col-md-5 text-right"> </div>
<a type="button" class="btn btn-info" data-dismiss="modal" <div class="col-md-5 text-right">
href="/config.html?#appid={{pageContext.appId}}">返回到项目首页 <a type="button" class="btn btn-info" data-dismiss="modal"
</a> href="/config.html?#appid={{pageContext.appId}}">{{'Common.ReturnToIndex' | translate }}
</a>
</div>
</div> </div>
</div> </header>
</header>
<div class="panel-body row">
<div class="panel-body row">
<section class="context" ng-show="hasAssignUserPermission">
<section class="context" ng-show="hasAssignUserPermission"> <!--project admin-->
<!--project admin--> <section class="form-horizontal" ng-show="hasManageAppMasterPermission">
<section class="form-horizontal" ng-show="hasManageAppMasterPermission"> <h5>{{'App.Setting.Admin' | translate }}
<h5>管理员 <small>
<small> {{'App.Setting.AdminTips' | translate }}
(项目管理员具有以下权限: 1. 创建Namespace 2. 创建集群 3. 管理项目、Namespace权限) </small>
</small> </h5>
</h5> <hr>
<hr>
<div class="col-md-offset-1">
<div class="col-md-offset-1"> <form class="form-inline" ng-submit="assignMasterRoleToUser()">
<form class="form-inline" ng-submit="assignMasterRoleToUser()"> <div class="form-group" style="padding-left: 15px">
<div class="form-group" style="padding-left: 15px"> <apollouserselector apollo-id="userSelectWidgetId"></apollouserselector>
<apollouserselector apollo-id="userSelectWidgetId"></apollouserselector> </div>
</div> <button type="submit" class="btn btn-default" style="margin-left: 20px;"
<button type="submit" class="btn btn-default" style="margin-left: 20px;" ng-disabled="submitBtnDisabled">{{'App.Setting.Add' | translate }}
ng-disabled="submitBtnDisabled">添加 </button>
</button> </form>
</form> <!-- Split button -->
<!-- Split button --> <div class="item-container">
<div class="item-container">
<div class="btn-group item-info" ng-repeat="user in appRoleUsers.masterUsers"> <div class="btn-group item-info" ng-repeat="user in appRoleUsers.masterUsers">
<button type="button" class="btn btn-default" ng-bind="user.userId"></button> <button type="button" class="btn btn-default" ng-bind="user.userId"></button>
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false" aria-haspopup="true" aria-expanded="false"
ng-click="removeMasterRoleFromUser(user.userId)"> ng-click="removeMasterRoleFromUser(user.userId)">
<span class="glyphicon glyphicon-remove"></span> <span class="glyphicon glyphicon-remove"></span>
</button> </button>
</div>
</div> </div>
</div> </div>
</div>
</section>
</section> <!--application info-->
<section>
<h5>{{'App.Setting.BasicInfo' | translate }}</h5>
<hr>
<form class="form-horizontal" name="appForm" valdr-type="App" ng-submit="updateAppInfo()">
<!--application info--> <div class="form-group" valdr-form-group>
<section> <label class="col-sm-2 control-label">
<h5>基本信息</h5> <apollorequiredfield></apollorequiredfield>
<hr> {{'Common.AppId' | translate }}
<form class="form-horizontal" name="appForm" valdr-type="App"
ng-submit="updateAppInfo()">
<div class="form-group" valdr-form-group>
<label class="col-sm-2 control-label">
<apollorequiredfield></apollorequiredfield>
AppId</label>
<div class="col-sm-3">
<label class="form-control-static" ng-bind="pageContext.appId">
</label> </label>
<div class="col-sm-3">
<label class="form-control-static" ng-bind="pageContext.appId">
</label>
</div>
</div> </div>
</div> <div class="form-group">
<div class="form-group"> <label class="col-sm-2 control-label">
<label class="col-sm-2 control-label"> <apollorequiredfield></apollorequiredfield>
<apollorequiredfield></apollorequiredfield> {{'Common.Department' | translate }}
部门</label> </label>
<div class="col-sm-3"> <div class="col-sm-3">
<select id="organization" ng-disabled="!display.app.edit"> <select id="organization" ng-disabled="!display.app.edit">
<option></option> <option></option>
</select> </select>
</div>
</div> </div>
</div>
<div class="form-group" valdr-form-group> <div class="form-group" valdr-form-group>
<label class="col-sm-2 control-label"> <label class="col-sm-2 control-label">
<apollorequiredfield></apollorequiredfield> <apollorequiredfield></apollorequiredfield>
项目名称</label> {{'App.Setting.ProjectName' | translate }}
<div class="col-sm-4"> </label>
<input type="text" class="form-control" name="appName" ng-model="viewApp.name" <div class="col-sm-4">
ng-disabled="!display.app.edit"> <input type="text" class="form-control" name="appName" ng-model="viewApp.name"
<small>(建议格式 xx-yy-zz 例:apollo-server)</small> ng-disabled="!display.app.edit">
<small>{{'App.Setting.ProjectNameTips' | translate }}</small>
</div>
</div> </div>
</div> <div class="form-group">
<div class="form-group"> <label class="col-sm-2 control-label">
<label class="col-sm-2 control-label"> <apollorequiredfield></apollorequiredfield>
<apollorequiredfield></apollorequiredfield> {{'App.Setting.ProjectOwner' | translate }}
项目负责人</label> </label>
<div class="col-sm-6 J_ownerSelectorPanel"> <div class="col-sm-6 J_ownerSelectorPanel">
<apollouserselector apollo-id="'ownerSelector'" <apollouserselector apollo-id="'ownerSelector'" disabled="!display.app.edit">
disabled="!display.app.edit"></apollouserselector> </apollouserselector>
</div>
</div> </div>
</div>
<div class="form-group"> <div class="form-group">
<div class="col-sm-offset-2 col-sm-9"> <div class="col-sm-offset-2 col-sm-9">
<button type="button" class="btn btn-primary" <button type="button" class="btn btn-primary" ng-show="!display.app.edit"
ng-show="!display.app.edit"
ng-click="toggleEditStatus()"> ng-click="toggleEditStatus()">
修改项目信息 {{'App.Setting.Modify' | translate }}
</button> </button>
<button type="button" class="btn btn-warning" <button type="button" class="btn btn-warning" ng-show="display.app.edit"
ng-show="display.app.edit"
ng-click="toggleEditStatus()"> ng-click="toggleEditStatus()">
取消修改 {{'App.Setting.Cancel' | translate }}
</button> </button>
<button type="submit" class="btn btn-primary" <button type="submit" class="btn btn-primary" ng-show="display.app.edit"
ng-show="display.app.edit"
ng-disabled="appForm.$invalid || submitBtnDisabled"> ng-disabled="appForm.$invalid || submitBtnDisabled">
提交 {{'Common.Submit' | translate }}
</button> </button>
</div>
</div> </div>
</div> </form>
</form> </section>
</section>
</section> </section>
<section class="context" ng-show="!hasAssignUserPermission"> <section class="context" ng-show="!hasAssignUserPermission">
<div class="panel-body text-center"> <div class="panel-body text-center">
<h4>您没有权限操作,请找 [{{admins.join(',')}}] 开通权限</h4> <h4 translate="App.Setting.NoPermissionTips" translate-value-users="{{admins.join(',')}}"></h4>
</div> </div>
</section> </section>
</div> </div>
<apolloconfirmdialog apollo-dialog-id="'warning'" apollo-title="'删除管理员'" <apolloconfirmdialog apollo-dialog-id="'warning'" apollo-title="'App.Setting.DeleteAdmin' | translate"
apollo-detail="'不能删除所有的管理员'" apollo-detail="'App.Setting.CanNotDeleteAllAdmin' | translate" apollo-show-cancel-btn="false">
apollo-show-cancel-btn="false"></apolloconfirmdialog> </apolloconfirmdialog>
</section> </section>
</div> </div>
<div ng-include="'../views/common/footer.html'"></div> <div ng-include="'../views/common/footer.html'"></div>
<!-- jquery.js --> <!-- jquery.js -->
<script src="../vendor/jquery.min.js" type="text/javascript"></script> <script src="../vendor/jquery.min.js" type="text/javascript"></script>
<!--angular--> <!--angular-->
<script src="../vendor/angular/angular.min.js"></script> <script src="../vendor/angular/angular.min.js"></script>
<script src="../vendor/angular/angular-route.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-resource.min.js"></script>
<script src="../vendor/angular/angular-toastr-1.4.1.tpls.min.js"></script> <script src="../vendor/angular/angular-toastr-1.4.1.tpls.min.js"></script>
<script src="../vendor/angular/loading-bar.min.js"></script> <script src="../vendor/angular/loading-bar.min.js"></script>
<script src="../vendor/angular/angular-cookies.min.js"></script>
<!--valdr-->
<script src="../vendor/valdr/valdr.min.js" type="text/javascript"></script> <script src="../vendor/angular/angular-translate.2.18.1/angular-translate.min.js"></script>
<script src="../vendor/valdr/valdr-message.min.js" type="text/javascript"></script> <script src="../vendor/angular/angular-translate.2.18.1/angular-translate-loader-static-files.min.js"></script>
<script src="../vendor/angular/angular-translate.2.18.1/angular-translate-storage-cookie.min.js"></script>
<!-- bootstrap.js --> <!--valdr-->
<script src="../vendor/bootstrap/js/bootstrap.min.js" type="text/javascript"></script> <script src="../vendor/valdr/valdr.min.js" type="text/javascript"></script>
<script src="../vendor/valdr/valdr-message.min.js" type="text/javascript"></script>
<script src="../vendor/lodash.min.js"></script>
<!-- bootstrap.js -->
<script src="../vendor/select2/select2.min.js" type="text/javascript"></script> <script src="../vendor/bootstrap/js/bootstrap.min.js" type="text/javascript"></script>
<!--biz-->
<!--must import--> <script src="../vendor/lodash.min.js"></script>
<script type="application/javascript" src="../scripts/app.js"></script>
<script type="application/javascript" src="../scripts/services/AppService.js"></script> <script src="../vendor/select2/select2.min.js" type="text/javascript"></script>
<script type="application/javascript" src="../scripts/services/EnvService.js"></script> <!--biz-->
<script type="application/javascript" src="../scripts/services/UserService.js"></script> <!--must import-->
<script type="application/javascript" src="../scripts/services/CommonService.js"></script> <script type="application/javascript" src="../scripts/app.js"></script>
<script type="application/javascript" src="../scripts/services/PermissionService.js"></script> <script type="application/javascript" src="../scripts/services/AppService.js"></script>
<script type="application/javascript" src="../scripts/services/OrganizationService.js"></script> <script type="application/javascript" src="../scripts/services/EnvService.js"></script>
<script type="application/javascript" src="../scripts/services/PermissionService.js"></script> <script type="application/javascript" src="../scripts/services/UserService.js"></script>
<script type="application/javascript" src="../scripts/services/CommonService.js"></script>
<script type="application/javascript" src="../scripts/AppUtils.js"></script> <script type="application/javascript" src="../scripts/services/PermissionService.js"></script>
<script type="application/javascript" src="../scripts/services/OrganizationService.js"></script>
<script type="application/javascript" src="../scripts/PageCommon.js"></script> <script type="application/javascript" src="../scripts/services/PermissionService.js"></script>
<script type="application/javascript" src="../scripts/directive/directive.js"></script>
<script type="application/javascript" src="../scripts/valdr.js"></script> <script type="application/javascript" src="../scripts/AppUtils.js"></script>
<script type="application/javascript" src="../scripts/controller/SettingController.js"></script> <script type="application/javascript" src="../scripts/PageCommon.js"></script>
<script type="application/javascript" src="../scripts/directive/directive.js"></script>
<script type="application/javascript" src="../scripts/valdr.js"></script>
<script type="application/javascript" src="../scripts/controller/SettingController.js"></script>
</body> </body>
</html>
</html>
\ No newline at end of file
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
<link rel="stylesheet" type="text/css" href="vendor/select2/select2.min.css"> <link rel="stylesheet" type="text/css" href="vendor/select2/select2.min.css">
<link rel="stylesheet" type="text/css" media='all' href="vendor/angular/loading-bar.min.css"> <link rel="stylesheet" type="text/css" media='all' href="vendor/angular/loading-bar.min.css">
<link rel="stylesheet" type="text/css" href="styles/common-style.css"> <link rel="stylesheet" type="text/css" href="styles/common-style.css">
<title>新建集群</title> <title>{{'Cluster.CreateCluster' | translate }}</title>
</head> </head>
<body> <body>
...@@ -23,10 +23,10 @@ ...@@ -23,10 +23,10 @@
<header class="panel-heading"> <header class="panel-heading">
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
<h4>创建集群</h4> <h4>{{'Cluster.CreateCluster' | translate }}</h4>
</div> </div>
<div class="col-md-6 text-right"> <div class="col-md-6 text-right">
<a type="button" class="btn btn-info" href="/config.html?#/appid={{appId}}">返回到项目首页 <a type="button" class="btn btn-info" href="/config.html?#/appid={{appId}}">{{'Common.ReturnToIndex' | translate }}
</a> </a>
</div> </div>
</div> </div>
...@@ -39,13 +39,10 @@ ...@@ -39,13 +39,10 @@
<div class="alert alert-info no-radius" role="alert"> <div class="alert alert-info no-radius" role="alert">
<strong>Tips:</strong> <strong>Tips:</strong>
<ul> <ul>
<li>通过添加集群,可以使同一份程序在不同的集群(如不同的数据中心)使用不同的配置</li> <li>{{'Cluster.Tips.1' | translate }}</li>
<li>如果不同集群使用一样的配置,则没有必要创建集群</li> <li>{{'Cluster.Tips.2' | translate }}</li>
<li> <li>{{'Cluster.Tips.3' | translate }}</li>
Apollo默认会读取机器上/opt/settings/server.properties(linux)或C:\opt\settings\server.properties(windows)文件中的idc属性作为集群名字, <li>{{'Cluster.Tips.4' | translate }}</li>
如SHAJQ(金桥数据中心)、SHAOY(欧阳数据中心)
</li>
<li>在这里创建的集群名字需要和机器上server.properties中的idc属性一致</li>
</ul> </ul>
</div> </div>
<form class="form-horizontal" name="clusterForm" valdr-type="Cluster" ng-show="step == 1" <form class="form-horizontal" name="clusterForm" valdr-type="Cluster" ng-show="step == 1"
...@@ -53,7 +50,7 @@ ...@@ -53,7 +50,7 @@
<div class="form-group"> <div class="form-group">
<label class="col-sm-2 control-label"> <label class="col-sm-2 control-label">
<apollorequiredfield></apollorequiredfield> <apollorequiredfield></apollorequiredfield>
应用AppId</label> {{'Common.AppId' | translate }}</label>
<div class="col-sm-6"> <div class="col-sm-6">
<label class="form-control-static" ng-bind="appId"></label> <label class="form-control-static" ng-bind="appId"></label>
</div> </div>
...@@ -61,16 +58,16 @@ ...@@ -61,16 +58,16 @@
<div class="form-group" valdr-form-group> <div class="form-group" valdr-form-group>
<label class="col-sm-2 control-label"> <label class="col-sm-2 control-label">
<apollorequiredfield></apollorequiredfield> <apollorequiredfield></apollorequiredfield>
集群名称</label> {{'Common.ClusterName' | translate }}</label>
<div class="col-sm-6"> <div class="col-sm-6">
<input type="text" class="form-control" name="clusterName" ng-model="clusterName"> <input type="text" class="form-control" name="clusterName" ng-model="clusterName">
<small>(部署集群如:SHAJQ,SHAOY 或自定义集群如:SHAJQ-xx,SHAJQ-yy)</small> <small>{{'Cluster.CreateNameTips' | translate }}</small>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="col-sm-2 control-label"> <label class="col-sm-2 control-label">
<apollorequiredfield></apollorequiredfield> <apollorequiredfield></apollorequiredfield>
选择环境</label> {{'Cluster.ChooseEnvironment' | translate }}</label>
<div class="col-sm-5"> <div class="col-sm-5">
<table class="table table-hover" style="width: 100px"> <table class="table table-hover" style="width: 100px">
<tbody> <tbody>
...@@ -89,14 +86,14 @@ ...@@ -89,14 +86,14 @@
<div class="col-sm-offset-2 col-sm-10"> <div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-primary" <button type="submit" class="btn btn-primary"
ng-disabled="clusterForm.$invalid || submitBtnDisabled">提交 ng-disabled="clusterForm.$invalid || submitBtnDisabled">{{'Common.Submit' | translate }}
</button> </button>
</div> </div>
</div> </div>
</form> </form>
<div class="row text-center" ng-show="step == 2"> <div class="row text-center" ng-show="step == 2">
<img src="img/sync-succ.png" style="height: 100px; width: 100px"> <img src="img/sync-succ.png" style="height: 100px; width: 100px">
<h3>创建成功!</h3> <h3>{{'Common.Created' | translate }}!</h3>
</div> </div>
</div> </div>
</div> </div>
...@@ -111,6 +108,11 @@ ...@@ -111,6 +108,11 @@
<script src="vendor/angular/angular-resource.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/angular-toastr-1.4.1.tpls.min.js"></script>
<script src="vendor/angular/loading-bar.min.js"></script> <script src="vendor/angular/loading-bar.min.js"></script>
<script src="vendor/angular/angular-cookies.min.js"></script>
<script src="vendor/angular/angular-translate.2.18.1/angular-translate.min.js"></script>
<script src="vendor/angular/angular-translate.2.18.1/angular-translate-loader-static-files.min.js"></script>
<script src="vendor/angular/angular-translate.2.18.1/angular-translate-storage-cookie.min.js"></script>
<!-- jquery.js --> <!-- jquery.js -->
<script src="vendor/jquery.min.js" type="text/javascript"></script> <script src="vendor/jquery.min.js" type="text/javascript"></script>
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Apollo配置中心</title> <title>{{'Config.Title' | translate }}</title>
<link rel="icon" href="./img/config.png"> <link rel="icon" href="./img/config.png">
<link rel="stylesheet" type="text/css" href="vendor/bootstrap/css/bootstrap.min.css"> <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" href="vendor/angular/angular-toastr-1.4.1.min.css">
...@@ -15,437 +15,417 @@ ...@@ -15,437 +15,417 @@
<body> <body>
<apollonav></apollonav> <apollonav></apollonav>
<div id="config-info" class="apollo-container app"> <div id="config-info" class="apollo-container app">
<div ng-controller="ConfigBaseInfoController"> <div ng-controller="ConfigBaseInfoController">
<div class="J_appNotFound hidden row text-center app-not-found" ng-show="notFoundApp"> <div class="J_appNotFound hidden row text-center app-not-found" ng-show="notFoundApp">
<img src="img/404.png"> <img src="img/404.png">
<br> <br>
<p> <p>
<span ng-bind="pageContext.appId"></span> 不存在,<a href="/app.html">点击创建</a> <span ng-bind="pageContext.appId"></span> {{'Config.AppIdNotFound' | translate }}<a
</p> href="/app.html">{{'Config.ClickByCreate' | translate }}</a>
</div> </p>
</div>
<div class="side-bar" <div class="side-bar" ng-class="{'position-absolute': viewMode == 1, 'position-fixed': viewMode == 2}">
ng-class="{'position-absolute': viewMode == 1, 'position-fixed': viewMode == 2}"> <div class="J_appFound hidden"
<div class="J_appFound hidden" ng-show="!notFoundApp && (viewMode == 1 || (viewMode == 2 && showSideBar))">
ng-show="!notFoundApp && (viewMode == 1 || (viewMode == 2 && showSideBar))">
<!--env list-->
<!--env list--> <section class="panel">
<section class="panel"> <header class="panel-heading">
<header class="panel-heading"> {{'Config.EnvList' | translate }}
环境列表 <span class="pull-right" data-tooltip="tooltip" data-placement="bottom"
<span class="pull-right" title="{{'Config.EnvListTips' | translate }}">
data-tooltip="tooltip" data-placement="bottom" title="通过切换环境、集群来管理不同环境、集群的配置"> <img src="img/question.png" class="i-20" />
<img src="img/question.png" class="i-20"/>
</span> </span>
</header> </header>
<div id="treeview" class="no-radius"></div> <div id="treeview" class="no-radius"></div>
</section> </section>
<!--app info--> <!--app info-->
<section class="panel"> <section class="panel">
<header class="panel-heading"> <header class="panel-heading">
项目信息 {{'Config.ProjectInfo' | translate }}
<span class="pull-right"> <span class="pull-right">
<a href="/app/setting.html?#/appid={{pageContext.appId}}" <a href="/app/setting.html?#/appid={{pageContext.appId}}"
style="margin-right: 5px;text-decoration:none;"> style="margin-right: 5px;text-decoration:none;">
<img src="img/edit.png" class="i-20 cursor-pointer" <img src="img/edit.png" class="i-20 cursor-pointer" data-tooltip="tooltip"
data-tooltip="tooltip" data-placement="bottom" title="修改项目基本信息"/> data-placement="bottom"
title="{{'Config.ModifyBasicProjectInfo' | translate }}" />
</a> </a>
<img src="img/unlike.png" class="i-20 cursor-pointer" <img src="img/unlike.png" class="i-20 cursor-pointer" ng-if="!favoriteId"
ng-if="!favoriteId" ng-click="addFavorite()" ng-click="addFavorite()" data-tooltip="tooltip" data-placement="bottom"
data-tooltip="tooltip" data-placement="bottom" title="收藏"/> title="{{'Config.Favorite' | translate }}" />
<img src="img/like.png" class="i-20 cursor-pointer" <img src="img/like.png" class="i-20 cursor-pointer" ng-if="favoriteId"
ng-if="favoriteId" ng-click="deleteFavorite()" ng-click="deleteFavorite()" data-tooltip="tooltip" data-placement="bottom"
data-tooltip="tooltip" data-placement="bottom" title="取消收藏"/> title="{{'Config.CancelFavorite' | translate }}" />
</span> </span>
</header> </header>
<div class="panel-body"> <div class="panel-body">
<table class="project-info"> <table class="project-info">
<tbody class="text-left"> <tbody class="text-left">
<tr> <tr>
<th>AppId:</th> <th>{{'Common.Department' | translate }}:</th>
<td ng-bind="appBaseInfo.appId"></td> <td ng-bind="appBaseInfo.appId"></td>
</tr> </tr>
<tr> <tr>
<th>应用名:</th> <th>{{'Common.AppName' | translate }}:</th>
<td> <td>
<small ng-bind="appBaseInfo.name"></small> <small ng-bind="appBaseInfo.name"></small>
</td> </td>
</tr> </tr>
<tr> <tr>
<th>部门:</th> <th>{{'Common.Department' | translate }}:</th>
<td ng-bind="appBaseInfo.orgInfo"></td> <td ng-bind="appBaseInfo.orgInfo"></td>
</tr> </tr>
<tr> <tr>
<th>负责人:</th> <th>{{'Common.AppOwner' | translate }}:</th>
<td ng-bind="appBaseInfo.ownerName"></td> <td ng-bind="appBaseInfo.ownerName"></td>
</tr> </tr>
<tr> <tr>
<th>邮箱:</th> <th>{{'Common.Email' | translate }}:</th>
<td> <td>
<small ng-bind="appBaseInfo.ownerEmail"></small> <small ng-bind="appBaseInfo.ownerEmail"></small>
</td> </td>
</tr> </tr>
<tr ng-show="missEnvs.length > 0"> <tr ng-show="missEnvs.length > 0">
<th>缺失的环境:</th> <th>{{'Config.MissEnv' | translate }}:</th>
<td> <td>
<span ng-repeat="env in missEnvs" ng-bind="env"> <span ng-repeat="env in missEnvs" ng-bind="env">
</span> </span>
</td> </td>
</tr> </tr>
<tr ng-show="missingNamespaces.length > 0"> <tr ng-show="missingNamespaces.length > 0">
<th>缺失的Namespace:</th> <th>{{'Config.MissNamespace' | translate }}:</th>
<td> <td>
<span ng-repeat="namespace in missingNamespaces" ng-bind="namespace"> <span ng-repeat="namespace in missingNamespaces" ng-bind="namespace">
</span> </span>
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div>
</section>
<!--operation entrance-->
<section>
<apolloentrance apollo-title="'管理项目'" apollo-img-src="'project-manage'"
apollo-href="'/app/setting.html?#/appid=' + pageContext.appId"></apolloentrance>
<a class="list-group-item" ng-show="missEnvs.length > 0" ng-click="createAppInMissEnv()">
<div class="row icon-text icon-plus-orange">
<p class="btn-title ng-binding">补缺环境</p>
</div>
</a>
<a class="list-group-item" ng-show="missingNamespaces.length > 0" ng-click="createMissingNamespaces()">
<div class="row icon-text icon-plus-orange">
<p class="btn-title ng-binding">补缺Namespace</p>
</div> </div>
</a> </section>
<apolloentrance apollo-title="'添加集群'" apollo-img-src="'plus-orange'" <!--operation entrance-->
apollo-href="'cluster.html?#/appid=' + pageContext.appId" <section>
ng-show="hasCreateClusterPermission"></apolloentrance> <apolloentrance apollo-title="'Config.ProjectManage' | translate"
apollo-img-src="'project-manage'"
<div class="list-group-item cursor-pointer hover" ng-click="showMasterPermissionTips()" apollo-href="'/app/setting.html?#/appid=' + pageContext.appId"></apolloentrance>
ng-show="!hasCreateClusterPermission">
<div class="row icon-text icon-plus-orange"> <a class="list-group-item" ng-show="missEnvs.length > 0" ng-click="createAppInMissEnv()">
<p class="btn-title">添加集群</p> <div class="row icon-text icon-plus-orange">
<p class="btn-title ng-binding">{{'Config.CreateAppMissEnv' | translate }}</p>
</div>
</a>
<a class="list-group-item" ng-show="missingNamespaces.length > 0"
ng-click="createMissingNamespaces()">
<div class="row icon-text icon-plus-orange">
<p class="btn-title ng-binding">{{'Config.CreateAppMissNamespace' | translate }}</p>
</div>
</a>
<apolloentrance apollo-title="'Config.AddCluster' | translate" apollo-img-src="'plus-orange'"
apollo-href="'cluster.html?#/appid=' + pageContext.appId"
ng-show="hasCreateClusterPermission"></apolloentrance>
<div class="list-group-item cursor-pointer hover" ng-click="showMasterPermissionTips()"
ng-show="!hasCreateClusterPermission">
<div class="row icon-text icon-plus-orange">
<p class="btn-title">{{'Config.AddCluster' | translate }}</p>
</div>
</div> </div>
</div>
<apolloentrance apollo-title="'添加Namespace'" apollo-img-src="'plus-orange'" <apolloentrance apollo-title="'Config.AddNamespace' | translate" apollo-img-src="'plus-orange'"
apollo-href="'namespace.html?#/appid=' + pageContext.appId" apollo-href="'namespace.html?#/appid=' + pageContext.appId"
ng-show="hasCreateNamespacePermission"></apolloentrance> ng-show="hasCreateNamespacePermission"></apolloentrance>
<div class="list-group-item cursor-pointer hover" ng-click="showMasterPermissionTips()" <div class="list-group-item cursor-pointer hover" ng-click="showMasterPermissionTips()"
ng-show="!hasCreateNamespacePermission"> ng-show="!hasCreateNamespacePermission">
<div class="row icon-text icon-plus-orange"> <div class="row icon-text icon-plus-orange">
<p class="btn-title">添加Namespace</p> <p class="btn-title">{{'Config.AddNamespace' | translate }}</p>
</div>
</div> </div>
</div>
</section> </section>
</div>
</div> </div>
</div> </div>
</div>
<!--具体配置信息--> <!--具体配置信息-->
<!--namespaces--> <!--namespaces-->
<div class="config-item-container hide" <div class="config-item-container hide" ng-class="{'view-mode-1': viewMode == 1, 'view-mode-2': viewMode == 2}"
ng-class="{'view-mode-1': viewMode == 1, 'view-mode-2': viewMode == 2}" ng-controller="ConfigNamespaceController">
ng-controller="ConfigNamespaceController">
<h4 class="text-center" ng-show="viewMode == 2">
<h4 class="text-center" ng-show="viewMode == 2"> {{'Config.CurrentlyOperatorEnv' | translate }}:{{pageContext.env}},
当前操作环境:{{pageContext.env}}, 集群:{{pageContext.clusterName}} {{'Common.Cluster' | translate }}:{{pageContext.clusterName}}
</h4> </h4>
<div class="alert alert-info alert-dismissible" role="alert" <div class="alert alert-info alert-dismissible" role="alert"
ng-show="(!hideTip || !hideTip[pageContext.appId][pageContext.clusterName]) && envMapClusters[pageContext.env]"> ng-show="(!hideTip || !hideTip[pageContext.appId][pageContext.clusterName]) && envMapClusters[pageContext.env]">
<button class="btn btn-sm btn-default pull-right" style="margin-top: -7px;margin-right:-15px;" <button class="btn btn-sm btn-default pull-right" style="margin-top: -7px;margin-right:-15px;"
ng-click="closeTip(pageContext.clusterName)">不再提示 ng-click="closeTip(pageContext.clusterName)">{{'Config.DoNotRemindAgain' | translate }}
</button> </button>
<!--default cluster tip --> <!--default cluster tip -->
<div ng-show="pageContext.clusterName == 'default'"> <div ng-show="pageContext.clusterName == 'default'">
<strong>注意: </strong>所有不属于 <strong>{{'Config.Note' | translate }}:</strong>
<span ng-bind="envMapClusters[pageContext.env]"></span> <span translate="Config.ClusterIsDefaultTipContent"
集群的实例会使用default集群(当前页面)的配置,属于 translate-value-name="{{envMapClusters[pageContext.env]}}"></span>
<span ng-bind="envMapClusters[pageContext.env]"></span> </div>
的实例会使用对应集群的配置!
</div>
<!--custom cluster tip--> <!--custom cluster tip-->
<div ng-show="pageContext.clusterName != 'default'"> <div ng-show="pageContext.clusterName != 'default'">
<strong>注意:</strong>属于 <strong>{{'Config.Note' | translate }}:</strong>
<span ng-bind="pageContext.clusterName"></span> <span translate="Config.ClusterIsCustomTipContent"
集群的实例只会使用 translate-value-name="{{pageContext.clusterName}}"></span>
<span ng-bind="pageContext.clusterName"></span> </div>
集群(当前页面)的配置,只有当对应namespace在当前集群没有发布过配置时,才会使用default集群的配置。
</div>
</div> </div>
<div class="alert alert-info" <div class="alert alert-info" ng-if="hasNotPublishNamespace">
ng-if="hasNotPublishNamespace"> <p><b>{{'Config.Note' | translate }}:</b> {{'Config.HasNotPublishNamespace' | translate }}</p>
<p><b>注意:</b> 以下环境/集群有未发布的配置,客户端获取不到未发布的配置,请及时发布。</p> <p>
<p> <mark ng-bind="namespacePublishInfo.join(',')"></mark>
<mark ng-bind="namespacePublishInfo.join(',')"></mark> </p>
</p> </div>
</div>
<apollonspanel ng-repeat="namespace in namespaces" <apollonspanel ng-repeat="namespace in namespaces" namespace="namespace" app-id="pageContext.appId"
namespace="namespace" env="pageContext.env" lock-check="lockCheck" cluster="pageContext.clusterName" user="currentUser"
app-id="pageContext.appId" pre-release-ns="prepareReleaseNamespace" create-item="createItem" edit-item="editItem"
env="pageContext.env" pre-delete-item="preDeleteItem" show-text="showText"
lock-check="lockCheck" show-no-modify-permission-dialog="showNoModifyPermissionDialog" show-body="namespaces.length < 3"
cluster="pageContext.clusterName" lazy-load="namespaces.length > 10" pre-create-branch="preCreateBranch"
user="currentUser" pre-delete-branch="preDeleteBranch">
pre-release-ns="prepareReleaseNamespace" </apollonspanel>
create-item="createItem" edit-item="editItem"
pre-delete-item="preDeleteItem" <releasemodal app-id="pageContext.appId" env="pageContext.env" cluster="pageContext.clusterName">
show-text="showText" </releasemodal>
show-no-modify-permission-dialog="showNoModifyPermissionDialog"
show-body="namespaces.length < 3" <itemmodal to-operation-namespace="toOperationNamespace" app-id="pageContext.appId" env="pageContext.env"
lazy-load="namespaces.length > 10" cluster="pageContext.clusterName" item="item">
pre-create-branch="preCreateBranch" </itemmodal>
pre-delete-branch="preDeleteBranch">
</apollonspanel> <showtextmodal text="text"></showtextmodal>
<releasemodal app-id="pageContext.appId" <rollbackmodal app-id="pageContext.appId" env="pageContext.env" cluster="pageContext.clusterName">
env="pageContext.env" </rollbackmodal>
cluster="pageContext.clusterName">
</releasemodal> <rulesmodal app-id="pageContext.appId" env="pageContext.env" cluster="pageContext.clusterName">
<itemmodal to-operation-namespace="toOperationNamespace" </rulesmodal>
app-id="pageContext.appId"
env="pageContext.env"
cluster="pageContext.clusterName" <mergeandpublishmodal app-id="pageContext.appId" env="pageContext.env" cluster="pageContext.clusterName">
item="item"> </mergeandpublishmodal>
</itemmodal>
<publishdenymodal env="pageContext.env"></publishdenymodal>
<showtextmodal text="text"></showtextmodal>
<deletenamespacemodal env="pageContext.env"></deletenamespacemodal>
<rollbackmodal app-id="pageContext.appId"
env="pageContext.env" <apolloconfirmdialog apollo-dialog-id="'deleteConfirmDialog'"
cluster="pageContext.clusterName"> apollo-title="'Config.DeleteItem.DialogTitle' | translate"
</rollbackmodal> apollo-detail="'Config.DeleteItem.DialogContent' | translate:this" apollo-show-cancel-btn="true"
apollo-confirm="deleteItem"></apolloconfirmdialog>
<rulesmodal app-id="pageContext.appId"
env="pageContext.env" <apolloconfirmdialog apollo-dialog-id="'releaseNoPermissionDialog'"
cluster="pageContext.clusterName"> apollo-title="'Config.PublishNoPermission.DialogTitle' | translate"
apollo-detail="'Config.PublishNoPermission.DialogContent' | translate:this"
</rulesmodal> apollo-show-cancel-btn="false">
</apolloconfirmdialog>
<mergeandpublishmodal app-id="pageContext.appId" <apolloconfirmdialog apollo-dialog-id="'modifyNoPermissionDialog'"
env="pageContext.env" apollo-title="'Config.ModifyNoPermission.DialogTitle' | translate"
cluster="pageContext.clusterName"> apollo-detail="'Config.ModifyNoPermission.DialogContent' | translate:this"
</mergeandpublishmodal> apollo-show-cancel-btn="false">
</apolloconfirmdialog>
<publishdenymodal env="pageContext.env"></publishdenymodal>
<apolloconfirmdialog apollo-dialog-id="'masterNoPermissionDialog'"
<deletenamespacemodal env="pageContext.env"></deletenamespacemodal> apollo-title="'Config.MasterNoPermission.DialogTitle' | translate"
apollo-detail="'Config.MasterNoPermission.DialogContent' | translate:this"
<apolloconfirmdialog apollo-dialog-id="'deleteConfirmDialog'" apollo-title="'删除配置'" apollo-show-cancel-btn="false">
apollo-detail="'您正在删除 Key 为 <b>' + config.key + '</b> Value 为 <b>' + config.value + '</b> 的配置.<br>确定要删除配置吗?'" </apolloconfirmdialog>
apollo-show-cancel-btn="true" apollo-confirm="deleteItem"></apolloconfirmdialog>
<apolloconfirmdialog apollo-dialog-id="'namespaceLockedDialog'"
<apolloconfirmdialog apollo-dialog-id="'releaseNoPermissionDialog'" apollo-title="'发布'" apollo-title="'Config.NamespaceLocked.DialogTitle' | translate"
apollo-detail="'您没有发布权限哦~ 请找项目管理员 ' + masterUsers + ' 分配发布权限'" apollo-detail="'Config.NamespaceLocked.DialogContent' | translate:this" apollo-show-cancel-btn="false">
apollo-show-cancel-btn="false"></apolloconfirmdialog> </apolloconfirmdialog>
<apolloconfirmdialog apollo-dialog-id="'modifyNoPermissionDialog'" apollo-title="'申请配置权限'" <apolloconfirmdialog apollo-dialog-id="'rollbackAlertDialog'"
apollo-detail="'请找项目管理员 ' + masterUsers + ' 分配编辑或发布权限'" apollo-title="'Config.RollbackAlert.DialogTitle' | translate"
apollo-show-cancel-btn="false"></apolloconfirmdialog> apollo-detail="'Config.RollbackAlert.DialogContent' | translate" apollo-show-cancel-btn="true"
apollo-confirm="rollback"></apolloconfirmdialog>
<apolloconfirmdialog apollo-dialog-id="'masterNoPermissionDialog'" apollo-title="'申请配置权限'"
apollo-detail="'您不是项目管理员, 只有项目管理员才有添加集群、namespace的权限。 <apolloconfirmdialog apollo-dialog-id="'emergencyPublishAlertDialog'"
如需管理员权限,请找项目管理员 ' + masterUsers + ' 分配管理员权限'" apollo-title="'Config.EmergencyPublishAlert.DialogTitle' | translate"
apollo-show-cancel-btn="false"></apolloconfirmdialog> apollo-detail="'Config.EmergencyPublishAlert.DialogContent' | translate" apollo-show-cancel-btn="true"
apollo-confirm="emergencyPublish">
<apolloconfirmdialog apollo-dialog-id="'namespaceLockedDialog'" apollo-title="'编辑受限'" </apolloconfirmdialog>
apollo-detail="'当前namespace正在被 ' + lockOwner + ' 编辑,一次发布只能被一个人修改.'"
apollo-show-cancel-btn="false"></apolloconfirmdialog> <apolloconfirmdialog apollo-dialog-id="'deleteBranchDialog'"
apollo-title="'Config.DeleteBranch.DialogTitle' | translate"
<apolloconfirmdialog apollo-dialog-id="'rollbackAlertDialog'" apollo-title="'回滚'" apollo-detail="'Config.DeleteBranch.DialogContent' | translate" apollo-show-cancel-btn="true"
apollo-detail="'确定要回滚吗?'" apollo-confirm="deleteBranch">
apollo-show-cancel-btn="true" apollo-confirm="rollback"></apolloconfirmdialog> </apolloconfirmdialog>
<apolloconfirmdialog apollo-dialog-id="'emergencyPublishAlertDialog'" apollo-title="'紧急发布'" <apolloconfirmdialog apollo-dialog-id="'updateRuleTips'"
apollo-detail="'确定要紧急发布吗?'" apollo-title="'Config.UpdateRuleTips.DialogTitle' | translate"
apollo-show-cancel-btn="true" apollo-confirm="emergencyPublish"></apolloconfirmdialog> apollo-detail="'Config.UpdateRuleTips.DialogContent' | translate"></apolloconfirmdialog>
<apolloconfirmdialog apollo-dialog-id="'deleteBranchDialog'" apollo-title="'删除灰度'" <apolloconfirmdialog apollo-dialog-id="'mergeAndReleaseDenyDialog'"
apollo-detail="'删除灰度会丢失灰度的配置,确定要删除吗?'" apollo-title="'Config.MergeAndReleaseDeny.DialogTitle' | translate"
apollo-show-cancel-btn="true" apollo-confirm="deleteBranch"></apolloconfirmdialog> apollo-detail="'Config.MergeAndReleaseDeny.DialogContent' | translate"></apolloconfirmdialog>
<apolloconfirmdialog apollo-dialog-id="'updateRuleTips'" apollo-title="'更新灰度规则提示'" <apolloconfirmdialog apollo-dialog-id="'grayReleaseWithoutRulesTips'"
apollo-detail="'灰度规则已生效,但发现灰度版本有未发布的配置,这些配置需要手动灰度发布才会生效'"></apolloconfirmdialog> apollo-title="'Config.GrayReleaseWithoutRulesTips.DialogTitle' | translate"
apollo-detail="'Config.GrayReleaseWithoutRulesTips.DialogContent' | translate">
<apolloconfirmdialog apollo-dialog-id="'mergeAndReleaseDenyDialog'" apollo-title="'全量发布'" </apolloconfirmdialog>
apollo-detail="'namespace主版本有未发布的配置,请先发布主版本配置'"></apolloconfirmdialog>
<apolloconfirmdialog apollo-dialog-id="'deleteNamespaceDenyForMasterInstanceDialog'"
<apolloconfirmdialog apollo-dialog-id="'grayReleaseWithoutRulesTips'" apollo-title="'缺失灰度规则提示'" apollo-title="'Config.DeleteNamespaceDenyForMasterInstance.DialogTitle' | translate"
apollo-detail="'灰度版本还没有配置任何灰度规则,请配置灰度规则'"> apollo-detail="'Config.DeleteNamespaceDenyForMasterInstance.DialogContent' | translate:this"
</apolloconfirmdialog> apollo-confirm="continueDeleteNamespace">
</apolloconfirmdialog>
<apolloconfirmdialog apollo-dialog-id="'deleteNamespaceDenyForMasterInstanceDialog'"
apollo-title="'删除Namespace警告信息'" <apolloconfirmdialog apollo-dialog-id="'deleteNamespaceDenyForBranchInstanceDialog'"
apollo-detail="'发现有 <b>' + deleteNamespaceContext.namespace.instancesCount + apollo-title="'Config.DeleteNamespaceDenyForBranchInstance.DialogTitle' | translate"
'</b> 个实例正在使用Namespace(' + deleteNamespaceContext.namespace.baseInfo.namespaceName + apollo-detail="'Config.DeleteNamespaceDenyForBranchInstance.DialogContent' | translate:this"
'),删除Namespace将导致实例获取不到配置。<br> apollo-confirm="continueDeleteNamespace">
请到 <ins>“实例列表”</ins> 确认实例信息,如确认相关实例都已经不再使用该Namespace配置,可以联系Apollo相关负责人删除实例信息(InstanceConfig)或等待实例24小时自动过期后再来删除。'" </apolloconfirmdialog>
apollo-confirm="continueDeleteNamespace">
</apolloconfirmdialog> <apolloconfirmdialog apollo-dialog-id="'deleteNamespaceDenyForPublicNamespaceDialog'"
apollo-title="'Config.DeleteNamespaceDenyForPublicNamespace.DialogTitle' | translate"
<apolloconfirmdialog apollo-dialog-id="'deleteNamespaceDenyForBranchInstanceDialog'" apollo-detail="deleteNamespaceContext.detailReason">
apollo-title="'删除Namespace警告信息'" </apolloconfirmdialog>
apollo-detail="'发现有 <b>' + deleteNamespaceContext.namespace.branch.latestReleaseInstances.total
+ '</b> 个实例正在使用Namespace(' + deleteNamespaceContext.namespace.baseInfo.namespaceName + <apolloconfirmdialog apollo-dialog-id="'syntaxCheckFailedDialog'"
')灰度版本的配置,删除Namespace将导致实例获取不到配置。<br> apollo-title="'Config.SyntaxCheckFailed.DialogTitle' | translate"
请到 <ins>“灰度版本” => “实例列表”</ins> 确认实例信息,如确认相关实例都已经不再使用该Namespace配置,可以联系Apollo相关负责人删除实例信息(InstanceConfig)或等待实例24小时自动过期后再来删除。'" apollo-detail="syntaxCheckContext.syntaxCheckMessage" apollo-extra-class="'pre'">
apollo-confirm="continueDeleteNamespace"> </apolloconfirmdialog>
</apolloconfirmdialog>
<apolloconfirmdialog apollo-dialog-id="'deleteNamespaceDenyForPublicNamespaceDialog'" <div class="modal fade" id="createBranchTips" tabindex="-1" role="dialog">
apollo-title="'删除Namespace失败提示'" <div class="modal-dialog" role="document">
apollo-detail="deleteNamespaceContext.detailReason"> <div class="modal-content">
</apolloconfirmdialog> <div class="modal-header panel-primary">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
<apolloconfirmdialog apollo-dialog-id="'syntaxCheckFailedDialog'" aria-hidden="true">&times;</span></button>
apollo-title="'语法检查错误'" <h4 class="modal-title">{{'Config.CreateBranchTips.DialogTitle' | translate}}</h4>
apollo-detail="syntaxCheckContext.syntaxCheckMessage" </div>
apollo-extra-class="'pre'"> <div class="modal-body" ng-bind-html="'Config.CreateBranchTips.DialogContent' | translate">
</apolloconfirmdialog> </div>
<div class="modal-footer">
<button type="button" class="btn btn-default"
<div class="modal fade" id="createBranchTips" tabindex="-1" role="dialog"> data-dismiss="modal">{{'Common.Cancel' | translate}}</button>
<div class="modal-dialog" role="document"> <button type="button" class="btn btn-primary" data-dismiss="modal"
<div class="modal-content"> ng-click="createBranch()">{{'Common.Ok' | translate}}</button>
<div class="modal-header panel-primary"> </div>
<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">
通过创建灰度版本,您可以对某些配置做灰度测试<br>
灰度流程为:<br>
&nbsp;&nbsp;1.创建灰度版本 <br>
&nbsp;&nbsp;2.配置灰度配置项<br>
&nbsp;&nbsp;3.配置灰度规则.如果是私有的namespace可以按照客户端的IP进行灰度,如果是公共的namespace则可以同时按AppId和客户端的IP进行灰度<br>
&nbsp;&nbsp;4.灰度发布<br>
灰度版本最终有两种结果:<b>全量发布和放弃灰度</b><br>
<b>全量发布</b>:灰度的配置合到主版本并发布,所有的客户端都会使用合并后的配置<br>
<b>放弃灰度</b>:删除灰度版本,所有的客户端都会使用回主版本的配置<br>
注意事项:<br>
&nbsp;&nbsp;1.如果灰度版本已经有灰度发布过,那么修改灰度规则后,无需再次灰度发布就立即生效<br>
</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="createBranch()">
确定
</button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div>
<div ng-include="'views/common/footer.html'"></div> <div ng-include="'views/common/footer.html'"></div>
<!-- jquery.js --> <!-- jquery.js -->
<script src="vendor/jquery.min.js" type="text/javascript"></script> <script src="vendor/jquery.min.js" type="text/javascript"></script>
<script src="vendor/select2/select2.min.js" type="text/javascript"></script> <script src="vendor/select2/select2.min.js" type="text/javascript"></script>
<script src="vendor/jquery-plugin/jquery.textareafullscreen.js" type="text/javascript"></script> <script src="vendor/jquery-plugin/jquery.textareafullscreen.js" type="text/javascript"></script>
<!--lodash.js--> <!--lodash.js-->
<script src="vendor/lodash.min.js" type="text/javascript"></script> <script src="vendor/lodash.min.js" type="text/javascript"></script>
<!--angular--> <!--angular-->
<script src="vendor/angular/angular.min.js"></script> <script src="vendor/angular/angular.min.js"></script>
<script src="vendor/angular/angular-resource.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/angular-toastr-1.4.1.tpls.min.js"></script>
<script src="vendor/angular/loading-bar.min.js"></script> <script src="vendor/angular/loading-bar.min.js"></script>
<script src="vendor/angular/angular-cookies.min.js"></script>
<script src="vendor/angular/angular-sanitize.min.js"></script>
<!-- bootstrap.js --> <script src="vendor/angular/angular-translate.2.18.1/angular-translate.min.js"></script>
<script src="vendor/bootstrap/js/bootstrap.min.js" type="text/javascript"></script> <script src="vendor/angular/angular-translate.2.18.1/angular-translate-loader-static-files.min.js"></script>
<script src="vendor/bootstrap/js/bootstrap-treeview.min.js" type="text/javascript"></script> <script src="vendor/angular/angular-translate.2.18.1/angular-translate-storage-cookie.min.js"></script>
<!-- bootstrap.js -->
<script src="vendor/bootstrap/js/bootstrap.min.js" type="text/javascript"></script>
<script src="vendor/bootstrap/js/bootstrap-treeview.min.js" type="text/javascript"></script>
<script src="vendor/diff.min.js" type="text/javascript"></script> <script src="vendor/diff.min.js" type="text/javascript"></script>
<script src="vendor/clipboard.min.js" type="text/javascript"></script> <script src="vendor/clipboard.min.js" type="text/javascript"></script>
<script src="vendor/ui-ace/ace.js" type="text/javascript"></script> <script src="vendor/ui-ace/ace.js" type="text/javascript"></script>
<script src="vendor/ui-ace/ui-ace.min.js" type="text/javascript"></script> <script src="vendor/ui-ace/ui-ace.min.js" type="text/javascript"></script>
<script src="vendor/ui-ace/mode-properties.js" type="text/javascript"></script> <script src="vendor/ui-ace/mode-properties.js" type="text/javascript"></script>
<script src="vendor/ui-ace/mode-xml.js" type="text/javascript"></script> <script src="vendor/ui-ace/mode-xml.js" type="text/javascript"></script>
<script src="vendor/ui-ace/mode-yaml.js" type="text/javascript"></script> <script src="vendor/ui-ace/mode-yaml.js" type="text/javascript"></script>
<script src="vendor/ui-ace/mode-json.js" type="text/javascript"></script> <script src="vendor/ui-ace/mode-json.js" type="text/javascript"></script>
<script src="vendor/ui-ace/worker-json.js" type="text/javascript"></script> <script src="vendor/ui-ace/worker-json.js" type="text/javascript"></script>
<script src="vendor/ui-ace/worker-xml.js" type="text/javascript"></script> <script src="vendor/ui-ace/worker-xml.js" type="text/javascript"></script>
<!--valdr--> <!--valdr-->
<script src="vendor/valdr/valdr.min.js" type="text/javascript"></script> <script src="vendor/valdr/valdr.min.js" type="text/javascript"></script>
<script src="vendor/valdr/valdr-message.min.js" type="text/javascript"></script> <script src="vendor/valdr/valdr-message.min.js" type="text/javascript"></script>
<!--biz script--> <!--biz script-->
<script type="application/javascript" src="scripts/app.js"></script> <script type="application/javascript" src="scripts/app.js"></script>
<!--service--> <!--service-->
<script type="application/javascript" src="scripts/services/AppService.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/services/EnvService.js"></script>
<script type="application/javascript" src="scripts/services/UserService.js"></script> <script type="application/javascript" src="scripts/services/UserService.js"></script>
<script type="application/javascript" src="scripts/services/ConfigService.js"></script> <script type="application/javascript" src="scripts/services/ConfigService.js"></script>
<script type="application/javascript" src="scripts/services/ReleaseService.js"></script> <script type="application/javascript" src="scripts/services/ReleaseService.js"></script>
<script type="application/javascript" src="scripts/services/PermissionService.js"></script> <script type="application/javascript" src="scripts/services/PermissionService.js"></script>
<script type="application/javascript" src="scripts/services/NamespaceService.js"></script> <script type="application/javascript" src="scripts/services/NamespaceService.js"></script>
<script type="application/javascript" src="scripts/services/CommitService.js"></script> <script type="application/javascript" src="scripts/services/CommitService.js"></script>
<script type="application/javascript" src="scripts/services/CommonService.js"></script> <script type="application/javascript" src="scripts/services/CommonService.js"></script>
<script type="application/javascript" src="scripts/services/NamespaceLockService.js"></script> <script type="application/javascript" src="scripts/services/NamespaceLockService.js"></script>
<script type="application/javascript" src="scripts/services/InstanceService.js"></script> <script type="application/javascript" src="scripts/services/InstanceService.js"></script>
<script type="application/javascript" src="scripts/services/FavoriteService.js"></script> <script type="application/javascript" src="scripts/services/FavoriteService.js"></script>
<script type="application/javascript" src="scripts/services/NamespaceBranchService.js"></script> <script type="application/javascript" src="scripts/services/NamespaceBranchService.js"></script>
<script type="application/javascript" src="scripts/services/EventManager.js"></script> <script type="application/javascript" src="scripts/services/EventManager.js"></script>
<script type="application/javascript" src="scripts/AppUtils.js"></script> <script type="application/javascript" src="scripts/AppUtils.js"></script>
<!--directive--> <!--directive-->
<script type="application/javascript" src="scripts/directive/directive.js"></script> <script type="application/javascript" src="scripts/directive/directive.js"></script>
<script type="application/javascript" src="scripts/directive/namespace-panel-directive.js"></script> <script type="application/javascript" src="scripts/directive/namespace-panel-directive.js"></script>
<script type="application/javascript" src="scripts/directive/diff-directive.js"></script> <script type="application/javascript" src="scripts/directive/diff-directive.js"></script>
<script type="application/javascript" src="scripts/directive/release-modal-directive.js"></script> <script type="application/javascript" src="scripts/directive/release-modal-directive.js"></script>
<script type="application/javascript" src="scripts/directive/item-modal-directive.js"></script> <script type="application/javascript" src="scripts/directive/item-modal-directive.js"></script>
<script type="application/javascript" src="scripts/directive/show-text-modal-directive.js"></script> <script type="application/javascript" src="scripts/directive/show-text-modal-directive.js"></script>
<script type="application/javascript" src="scripts/directive/rollback-modal-directive.js"></script> <script type="application/javascript" src="scripts/directive/rollback-modal-directive.js"></script>
<script type="application/javascript" src="scripts/directive/gray-release-rules-modal-directive.js"></script> <script type="application/javascript" src="scripts/directive/gray-release-rules-modal-directive.js"></script>
<script type="application/javascript" src="scripts/directive/merge-and-publish-modal-directive.js"></script> <script type="application/javascript" src="scripts/directive/merge-and-publish-modal-directive.js"></script>
<script type="application/javascript" src="scripts/directive/publish-deny-modal-directive.js"></script> <script type="application/javascript" src="scripts/directive/publish-deny-modal-directive.js"></script>
<script type="application/javascript" src="scripts/directive/delete-namespace-modal-directive.js"></script> <script type="application/javascript" src="scripts/directive/delete-namespace-modal-directive.js"></script>
<!--controller--> <!--controller-->
<script type="application/javascript" src="scripts/controller/config/ConfigNamespaceController.js"></script> <script type="application/javascript" src="scripts/controller/config/ConfigNamespaceController.js"></script>
<script type="application/javascript" src="scripts/controller/config/ConfigBaseInfoController.js"></script> <script type="application/javascript" src="scripts/controller/config/ConfigBaseInfoController.js"></script>
<script type="application/javascript" src="scripts/PageCommon.js"></script> <script type="application/javascript" src="scripts/PageCommon.js"></script>
<script src="scripts/valdr.js" type="text/javascript"></script> <script src="scripts/valdr.js" type="text/javascript"></script>
</body> </body>
</html>
</html>
\ No newline at end of file
<!doctype html> <!doctype html>
<html ng-app="diff_item"> <html ng-app="diff_item">
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="icon" href="../img/config.png"> <link rel="icon" href="../img/config.png">
...@@ -9,11 +10,12 @@ ...@@ -9,11 +10,12 @@
<link rel="stylesheet" type="text/css" media='all' href="../vendor/angular/loading-bar.min.css"> <link rel="stylesheet" type="text/css" media='all' href="../vendor/angular/loading-bar.min.css">
<link rel="stylesheet" type="text/css" href="../styles/common-style.css"> <link rel="stylesheet" type="text/css" href="../styles/common-style.css">
<link rel="stylesheet" type="text/css" href="../vendor/select2/select2.min.css"> <link rel="stylesheet" type="text/css" href="../vendor/select2/select2.min.css">
<title>比较配置</title> <title>{{'Config.Diff.Title' | translate }}</title>
<style> <style>
.comment-toggle { .comment-toggle {
margin-left: 8px !important; margin-left: 8px !important;
} }
.diff-content { .diff-content {
margin-top: 12px; margin-top: 12px;
} }
...@@ -22,134 +24,139 @@ ...@@ -22,134 +24,139 @@
<body> <body>
<apollonav></apollonav> <apollonav></apollonav>
<div class="container-fluid apollo-container" ng-controller="DiffItemController"> <div class="container-fluid apollo-container" ng-controller="DiffItemController">
<section class="panel col-md-offset-1 col-md-10"> <section class="panel col-md-offset-1 col-md-10">
<header class="panel-heading"> <header class="panel-heading">
<div class="row"> <div class="row">
<div class="col-md-7"> <div class="col-md-7">
<h4 class="modal-title">比较配置 <h4 class="modal-title">{{'Config.Diff.Title' | translate }}
<small ng-show="syncItemStep == 1">(第一步:选择比较信息)</small> <small ng-show="syncItemStep == 1">{{'Config.Diff.FirstStep' | translate }}</small>
<small ng-show="syncItemStep == 2">(第二步:查看差异配置)</small> <small ng-show="syncItemStep == 2">{{'Config.Diff.SecondStep' | translate }}</small>
</h4> </h4>
</div> </div>
<div class="col-md-5 text-right"> <div class="col-md-5 text-right">
<button type="button" class="btn btn-primary" ng-show="syncItemStep > 1 && syncItemStep < 3" <button type="button" class="btn btn-primary" ng-show="syncItemStep > 1 && syncItemStep < 3"
ng-click="syncItemNextStep(-1)">上一步 ng-click="syncItemNextStep(-1)">{{'Config.Diff.PreviousStep' | translate }}
</button> </button>
<button type="button" class="btn btn-primary" ng-show="syncItemStep < 2" <button type="button" class="btn btn-primary" ng-show="syncItemStep < 2"
ng-click="diff()">下一步 ng-click="diff()">{{'Config.Diff.NextStep' | translate }}
</button> </button>
<button type="button" class="btn btn-info" data-dismiss="modal" <button type="button" class="btn btn-info" data-dismiss="modal"
ng-click="backToAppHomePage()">返回到项目首页 ng-click="backToAppHomePage()">{{'Common.ReturnToIndex' | translate }}
</button> </button>
</div> </div>
</div>
</header>
<div class="panel-body">
<div class="row" ng-show="syncItemStep == 1">
<div class="alert-info alert no-radius">
<strong>Tips:</strong>
<ul>
<li>通过比较配置功能,可以查看多个环境、集群间的配置差异</li>
</ul>
</div> </div>
<div class="form-horizontal"> </header>
<div class="form-group"> <div class="panel-body">
<label class="col-sm-2 control-label">要比较的集群</label> <div class="row" ng-show="syncItemStep == 1">
<div class="col-sm-6"> <div class="alert-info alert no-radius">
<apolloclusterselector apollo-app-id="pageContext.appId" apollo-default-all-checked="false" <strong>{{'Config.Diff.TipsTitle' | translate }}:</strong>
apollo-select="collectSelectedClusters" <ul>
apollo-default-checked-env="pageContext.env" <li>{{'Config.Diff.Tips' | translate }}</li>
apollo-default-checked-cluster="pageContext.clusterName"></apolloclusterselector> </ul>
</div>
<div class="form-horizontal">
<div class="form-group">
<label class="col-sm-2 control-label">{{'Config.Diff.DiffCluster' | translate }}</label>
<div class="col-sm-6">
<apolloclusterselector apollo-app-id="pageContext.appId"
apollo-default-all-checked="false" apollo-select="collectSelectedClusters"
apollo-default-checked-env="pageContext.env"
apollo-default-checked-cluster="pageContext.clusterName"></apolloclusterselector>
</div>
</div> </div>
</div> </div>
<hr>
</div> </div>
<hr>
</div>
<!--step 2--> <!--step 2-->
<div class="row" ng-show="syncItemStep == 2"> <div class="row" ng-show="syncItemStep == 2">
<div class="row" style="margin-top: 10px;"> <div class="row" style="margin-top: 10px;">
<div class="form-horizontal"> <div class="form-horizontal">
<div class="col-sm-12"> <div class="col-sm-12">
<label class="control-label"> <label class="control-label">
<input type="checkbox" <input type="checkbox" class="comment-toggle" ng-checked="showCommentDiff"
class="comment-toggle" ng-click="showCommentDiff=!showCommentDiff">
ng-checked="showCommentDiff" {{'Config.Diff.HasDiffComment' | translate }}
ng-click="showCommentDiff=!showCommentDiff"> </label>
是否比较注释 </div>
</label> <div class="col-sm-12 diff-content">
</div> <table class="table table-bordered table-striped table-hover">
<div class="col-sm-12 diff-content"> <thead>
<table class="table table-bordered table-striped table-hover"> <tr>
<thead> <td>Key</td>
<tr> <td ng-repeat="cluster in syncData.syncToNamespaces"
<td>Key</td> ng-bind="cluster.env + ':' + cluster.clusterName + ':' + cluster.namespaceName + ':Value'">
<td ng-repeat="cluster in syncData.syncToNamespaces" </td>
ng-bind="cluster.env + ':' + cluster.clusterName + ':' + cluster.namespaceName + ':Value'" <td ng-show="showCommentDiff"
></td> ng-repeat="cluster in syncData.syncToNamespaces"
<td ng-show="showCommentDiff" ng-bind="cluster.env + ':' + cluster.clusterName + ':' + cluster.namespaceName + ':Comment'">
ng-repeat="cluster in syncData.syncToNamespaces" </td>
ng-bind="cluster.env + ':' + cluster.clusterName + ':' + cluster.namespaceName + ':Comment'" </tr>
></td> </thead>
</tr> <tbody>
</thead> <tr ng-repeat="(key, itemsKeyedByCluster) in itemsKeyedByKey">
<tbody> <td width="15%" ng-bind="key"></td>
<tr ng-repeat="(key, itemsKeyedByCluster) in itemsKeyedByKey"> <td ng-repeat="cluster in syncData.syncToNamespaces"
<td width="15%" ng-bind="key"></td> ng-bind="(itemsKeyedByCluster[cluster.env + ':' + cluster.clusterName + ':' + cluster.namespaceName] || {}).value">
<td ng-repeat="cluster in syncData.syncToNamespaces" </td>
ng-bind="(itemsKeyedByCluster[cluster.env + ':' + cluster.clusterName + ':' + cluster.namespaceName] || {}).value"></td> <td ng-show="showCommentDiff"
<td ng-show="showCommentDiff" ng-repeat="cluster in syncData.syncToNamespaces"
ng-repeat="cluster in syncData.syncToNamespaces" ng-bind="(itemsKeyedByCluster[cluster.env + ':' + cluster.clusterName + ':' + cluster.namespaceName] || {}).comment">
ng-bind="(itemsKeyedByCluster[cluster.env + ':' + cluster.clusterName + ':' + cluster.namespaceName] || {}).comment"></td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </section>
</section>
<showtextmodal text="text"/> <showtextmodal text="text" />
</div> </div>
<div ng-include="'../views/common/footer.html'"></div> <div ng-include="'../views/common/footer.html'"></div>
<!-- jquery.js --> <!-- jquery.js -->
<script src="../vendor/jquery.min.js" type="text/javascript"></script> <script src="../vendor/jquery.min.js" type="text/javascript"></script>
<script src="../vendor/select2/select2.min.js" type="text/javascript"></script> <script src="../vendor/select2/select2.min.js" type="text/javascript"></script>
<!--angular--> <!--angular-->
<script src="../vendor/angular/angular.min.js"></script> <script src="../vendor/angular/angular.min.js"></script>
<script src="../vendor/angular/angular-resource.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/angular-toastr-1.4.1.tpls.min.js"></script>
<script src="../vendor/angular/loading-bar.min.js"></script> <script src="../vendor/angular/loading-bar.min.js"></script>
<script src="../vendor/angular/angular-cookies.min.js"></script>
<script src="../vendor/angular/angular-translate.2.18.1/angular-translate.min.js"></script>
<script src="../vendor/angular/angular-translate.2.18.1/angular-translate-loader-static-files.min.js"></script>
<script src="../vendor/angular/angular-translate.2.18.1/angular-translate-storage-cookie.min.js"></script>
<!-- bootstrap.js --> <!-- bootstrap.js -->
<script src="../vendor/bootstrap/js/bootstrap.min.js" type="text/javascript"></script> <script src="../vendor/bootstrap/js/bootstrap.min.js" type="text/javascript"></script>
<script src="../vendor/clipboard.min.js" type="text/javascript"></script> <script src="../vendor/clipboard.min.js" type="text/javascript"></script>
<!--biz--> <!--biz-->
<script type="application/javascript" src="../scripts/app.js"></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/services/AppService.js"></script>
<script type="application/javascript" src="../scripts/services/EnvService.js"></script> <script type="application/javascript" src="../scripts/services/EnvService.js"></script>
<script type="application/javascript" src="../scripts/services/ConfigService.js"></script> <script type="application/javascript" src="../scripts/services/ConfigService.js"></script>
<script type="application/javascript" src="../scripts/services/UserService.js"></script> <script type="application/javascript" src="../scripts/services/UserService.js"></script>
<script type="application/javascript" src="../scripts/services/CommonService.js"></script> <script type="application/javascript" src="../scripts/services/CommonService.js"></script>
<script type="application/javascript" src="../scripts/services/PermissionService.js"></script> <script type="application/javascript" src="../scripts/services/PermissionService.js"></script>
<script type="application/javascript" src="../scripts/AppUtils.js"></script> <script type="application/javascript" src="../scripts/AppUtils.js"></script>
<script type="application/javascript" src="../scripts/controller/config/DiffConfigController.js"></script> <script type="application/javascript" src="../scripts/controller/config/DiffConfigController.js"></script>
<script type="application/javascript" src="../scripts/PageCommon.js"></script> <script type="application/javascript" src="../scripts/PageCommon.js"></script>
<script type="application/javascript" src="../scripts/directive/directive.js"></script> <script type="application/javascript" src="../scripts/directive/directive.js"></script>
<script type="application/javascript" src="../scripts/directive/show-text-modal-directive.js"></script> <script type="application/javascript" src="../scripts/directive/show-text-modal-directive.js"></script>
</body> </body>
</html>
</html>
\ No newline at end of file
<!doctype html > <!doctype html>
<html ng-app="release_history"> <html ng-app="release_history">
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="icon" href="../img/config.png"> <link rel="icon" href="../img/config.png">
...@@ -9,275 +10,295 @@ ...@@ -9,275 +10,295 @@
<link rel="stylesheet" type="text/css" media='all' href="../vendor/angular/loading-bar.min.css"> <link rel="stylesheet" type="text/css" media='all' href="../vendor/angular/loading-bar.min.css">
<link rel="stylesheet" type="text/css" href="../styles/common-style.css"> <link rel="stylesheet" type="text/css" href="../styles/common-style.css">
<link rel="stylesheet" type="text/css" href="../vendor/select2/select2.min.css"> <link rel="stylesheet" type="text/css" href="../vendor/select2/select2.min.css">
<title>发布历史</title> <title>{{'Config.History.Title' | translate }}</title>
</head> </head>
<body> <body>
<apollonav></apollonav> <apollonav></apollonav>
<div class="container-fluid apollo-container" ng-controller="ReleaseHistoryController"> <div class="container-fluid apollo-container" ng-controller="ReleaseHistoryController">
<section class="release-history panel col-md-12 no-radius hidden"> <section class="release-history panel col-md-12 no-radius hidden">
<div class="panel-heading row"> <div class="panel-heading row">
<div class="operation-caption-container col-md-3"> <div class="operation-caption-container col-md-3">
<div class="operation-caption release-operation-normal text-center" <div class="operation-caption release-operation-normal text-center" style="left:0;">
style="left:0;"> <small>{{'Config.History.MasterVersionPublish' | translate }}</small>
<small>主版本发布</small> </div>
</div> <div class="operation-caption release-operation-rollback text-center" style="left: 110px;">
<div class="operation-caption release-operation-rollback text-center" <small>{{'Config.History.MasterVersionRollback' | translate }}</small>
style="left: 80px;"> </div>
<small>主版本回滚</small> <div class="operation-caption release-operation-gray text-center" style="left: 220px;">
<small>{{'Config.History.GrayscaleOperator' | translate }}</small>
</div>
</div> </div>
<div class="operation-caption release-operation-gray text-center"
style="left: 160px;"> <div class="col-md-6 text-center">
<small>灰度操作</small> <h4>{{'Config.History.PublishHistory' | translate }}</h4>
<small>({{'Common.AppId' | translate }}:{{pageContext.appId}},
{{'Common.Environment' | translate }}:{{pageContext.env}},
{{'Common.Cluster' | translate }}:{{pageContext.clusterName}},
{{'Common.Namespace' | translate }}:{{pageContext.namespaceName}})
</small>
</div> </div>
</div>
<div class="col-md-6 text-center"> <div class="pull-right back-btn">
<h4>发布历史</h4> <a type="button" class="btn btn-info"
<small>(AppId:{{pageContext.appId}}, ENV:{{pageContext.env}}, Cluster:{{pageContext.clusterName}}, href="/config.html?#/appid={{pageContext.appId}}">{{'Common.ReturnToIndex' | translate }}
Namespace:{{pageContext.namespaceName}}) </a>
</small> </div>
</div>
<div class="pull-right back-btn">
<a type="button" class="btn btn-info" href="/config.html?#/appid={{pageContext.appId}}">返回到项目首页
</a>
</div> </div>
</div> <div class="release-history-container panel-body row"
ng-show="!isConfigHidden && releaseHistories && releaseHistories.length > 0">
<div class="release-history-list col-md-3">
<div class="release-history-container panel-body row" ng-show="!isConfigHidden && releaseHistories && releaseHistories.length > 0"> <div class="media hover" ng-class="{'active': releaseHistory.id == selectedReleaseHistory}"
<div class="release-history-list col-md-3"> ng-repeat="releaseHistory in releaseHistories"
ng-click="showReleaseHistoryDetail(releaseHistory)">
<div class="media hover" ng-class="{'active': releaseHistory.id == selectedReleaseHistory}" <div class="release-operation"
ng-repeat="releaseHistory in releaseHistories" ng-class="{'release-operation-normal': releaseHistory.operation == 0 || releaseHistory.operation == 5,
ng-click="showReleaseHistoryDetail(releaseHistory)">
<div class="release-operation"
ng-class="{'release-operation-normal': releaseHistory.operation == 0 || releaseHistory.operation == 5,
'release-operation-gray': releaseHistory.operation == 2 || releaseHistory.operation == 3 || 'release-operation-gray': releaseHistory.operation == 2 || releaseHistory.operation == 3 ||
releaseHistory.operation == 4 || releaseHistory.operation == 7 || releaseHistory.operation == 8, releaseHistory.operation == 4 || releaseHistory.operation == 7 || releaseHistory.operation == 8,
'release-operation-rollback': releaseHistory.operation == 1 || releaseHistory.operation == 6}"> 'release-operation-rollback': releaseHistory.operation == 1 || releaseHistory.operation == 6}">
</div>
<h4 class="media-left text-center" ng-bind="releaseHistory.operator">
</h4>
<div class="media-body">
<h5 class="col-md-7 word-break" ng-show="releaseHistory.operation == 0">
{{'Config.History.OperationType0' | translate }}</h5>
<h5 class="col-md-7 word-break" ng-show="releaseHistory.operation == 1">
{{'Config.History.OperationType1' | translate }}</h5>
<h5 class="col-md-7 word-break" ng-show="releaseHistory.operation == 2">
{{'Config.History.OperationType2' | translate }}</h5>
<h5 class="col-md-7 word-break" ng-show="releaseHistory.operation == 3">
{{'Config.History.OperationType3' | translate }}</h5>
<h5 class="col-md-7 word-break" ng-show="releaseHistory.operation == 4">
{{'Config.History.OperationType4' | translate }}</h5>
<h5 class="col-md-7 word-break" ng-show="releaseHistory.operation == 5">
{{'Config.History.OperationType5' | translate }}</h5>
<h5 class="col-md-7 word-break" ng-show="releaseHistory.operation == 6">
{{'Config.History.OperationType6' | translate }}</h5>
<h5 class="col-md-7 word-break" ng-show="releaseHistory.operation == 7">
{{'Config.History.OperationType7' | translate }}</h5>
<h5 class="col-md-7 word-break" ng-show="releaseHistory.operation == 8">
{{'Config.History.OperationType8' | translate }}</h5>
<h6 class="col-md-5 text-right" ng-bind="releaseHistory.releaseTimeFormatted"></h6>
<span class="label label-warning no-radius emergency-publish"
ng-if="releaseHistory.operationContext.isEmergencyPublish">{{'Config.History.UrgentPublish' | translate }}</span>
</div>
</div> </div>
<h4 class="media-left text-center" ng-bind="releaseHistory.operator">
</h4> <div class="load-more media panel-heading text-center hover" ng-show="!hasLoadAll"
<div class="media-body"> ng-click="findReleaseHistory()">
{{'Config.History.LoadMore' | translate }}
<h5 class="col-md-7 word-break" ng-show="releaseHistory.operation == 0">普通发布</h5>
<h5 class="col-md-7 word-break" ng-show="releaseHistory.operation == 1">回滚</h5>
<h5 class="col-md-7 word-break" ng-show="releaseHistory.operation == 2">灰度发布</h5>
<h5 class="col-md-7 word-break" ng-show="releaseHistory.operation == 3">更新灰度规则</h5>
<h5 class="col-md-7 word-break" ng-show="releaseHistory.operation == 4">灰度全量发布</h5>
<h5 class="col-md-7 word-break" ng-show="releaseHistory.operation == 5">灰度发布(主版本发布)</h5>
<h5 class="col-md-7 word-break" ng-show="releaseHistory.operation == 6">灰度发布(主版本回滚)</h5>
<h5 class="col-md-7 word-break" ng-show="releaseHistory.operation == 7">放弃灰度</h5>
<h5 class="col-md-7 word-break" ng-show="releaseHistory.operation == 8">删除灰度(全量发布)</h5>
<h6 class="col-md-5 text-right" ng-bind="releaseHistory.releaseTimeFormatted"></h6>
<span class="label label-warning no-radius emergency-publish"
ng-if="releaseHistory.operationContext.isEmergencyPublish">紧急发布</span>
</div> </div>
</div>
<div class="load-more media panel-heading text-center hover"
ng-show="!hasLoadAll"
ng-click="findReleaseHistory()">
加载更多
</div> </div>
</div> <!--properties mode info-->
<div class="release-info col-md-9 panel panel-default no-radius" ng-show="!isTextNamespace">
<div class="panel-heading">
<!--properties mode info--> <span ng-bind="history.releaseTitle"></span>
<div class="release-info col-md-9 panel panel-default no-radius" <span class="pull-right" ng-bind="history.releaseTime | date: 'yyyy-MM-dd HH:mm:ss'"></span>
ng-show="!isTextNamespace">
<div class="panel-heading">
<span ng-bind="history.releaseTitle"></span> <div class="row" style="padding-top: 10px;">
<span class="pull-right" ng-bind="history.releaseTime | date: 'yyyy-MM-dd HH:mm:ss'"></span> <div class="col-md-5">
<small ng-show="history.releaseComment" ng-bind="history.releaseComment"></small>
</div>
<div class="col-md-7 text-right">
<div class="btn-group">
<button type="button" class="btn btn-default btn-sm"
ng-class="{'active':history.viewType == 'diff'}" data-tooltip="tooltip"
data-placement="bottom" title="{{'Config.History.ChangedItemTips' | translate }}"
ng-click="switchConfigViewType(history, 'diff')">{{'Config.History.ChangedItem' | translate }}
</button>
<button type="button" class="btn btn-default btn-sm"
ng-class="{'active':history.viewType == 'all'}" data-tooltip="tooltip"
data-placement="bottom" title="{{'Config.History.AllItemTips' | translate }}"
ng-click="switchConfigViewType(history, 'all')">{{'Config.History.AllItem' | translate }}
</button>
</div>
</div>
<div class="row" style="padding-top: 10px;">
<div class="col-md-5">
<small ng-show="history.releaseComment" ng-bind="history.releaseComment"></small>
</div> </div>
<div class="col-md-7 text-right"> </div>
<div class="btn-group">
<button type="button" class="btn btn-default btn-sm" <div class="panel-body config">
ng-class="{'active':history.viewType == 'diff'}" <section ng-show="history.viewType=='diff'">
data-tooltip="tooltip" data-placement="bottom" title="查看此次发布与上次版本的变更" <h4 class="section-title">{{'Config.History.ChangedItem' | translate }}</h4>
ng-click="switchConfigViewType(history, 'diff')">变更的配置 <div ng-show="history.changes && history.changes.length > 0">
</button> <table class="no-margin table table-striped table-hover table-bordered">
<button type="button" class="btn btn-default btn-sm" <thead>
ng-class="{'active':history.viewType == 'all'}" <tr>
data-tooltip="tooltip" data-placement="bottom" title="查看此次发布的所有配置信息" <th>{{'Config.History.ChangeType' | translate }}</th>
ng-click="switchConfigViewType(history, 'all')">全部配置 <th>{{'Config.History.ChangeKey' | translate }}</th>
</button> <th>{{'Config.History.ChangeOldValue' | translate }}</th>
<th>{{'Config.History.ChangeNewValue' | translate }}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="change in history.changes">
<td width="10%">
<span
ng-show="change.type == 'ADDED'">{{'Config.History.ChangeTypeNew' | translate }}</span>
<span
ng-show="change.type == 'MODIFIED'">{{'Config.History.ChangeTypeModify' | translate }}</span>
<span
ng-show="change.type == 'DELETED'">{{'Config.History.ChangeTypeDelete' | translate }}</span>
</td>
<td class="cursor-pointer" width="20%"
ng-click="showText(change.entity.firstEntity.key)">
<span ng-bind="change.entity.firstEntity.key | limitTo: 250"></span>
<span
ng-bind="change.entity.firstEntity.key.length > 250 ? '...' :''"></span>
</td>
<td class="cursor-pointer" width="35%"
ng-click="showText(change.entity.firstEntity.value)">
<span ng-bind="change.entity.firstEntity.value | limitTo: 250"></span>
<span
ng-bind="change.entity.firstEntity.value.length > 250 ? '...' :''"></span>
</td>
<td class="cursor-pointer" width="35%"
ng-click="showText(change.entity.secondEntity.value)">
<span ng-bind="change.entity.secondEntity.value | limitTo: 250"></span>
<span
ng-bind="change.entity.secondEntity.value.length > 250 ? '...' :''"></span>
</td>
</tr>
</tbody>
</table>
</div> </div>
</div> <div class="text-center empty-container"
ng-show="!history.changes || history.changes.length == 0">
<h5>{{'Config.History.NoChange' | translate }}</h5>
</div>
</section>
</div>
</div>
<div class="panel-body config"> <section ng-show="history.viewType=='all'">
<section ng-show="history.viewType=='diff'"> <h4 class="section-title">{{'Config.History.AllItem' | translate }}</h4>
<h4 class="section-title">变更的配置</h4> <table class="no-margin table table-striped table-hover table-bordered"
<div ng-show="history.changes && history.changes.length > 0"> ng-show="history.configuration && history.configuration.length > 0">
<table class="no-margin table table-striped table-hover table-bordered">
<thead> <thead>
<tr> <tr>
<th>Type</th> <th>{{'Config.History.ChangeKey' | translate }}</th>
<th>Key</th> <th>{{'Config.History.ChangeValue' | translate }}</th>
<th>Old Value</th> </tr>
<th>New Value</th>
</tr>
</thead> </thead>
<tbody> <tbody>
<tr ng-repeat="change in history.changes"> <tr ng-repeat="item in history.configuration">
<td width="10%"> <td class="cursor-pointer" width="30%" ng-click="showText(item.firstEntity)">
<span ng-show="change.type == 'ADDED'">新增</span> <span ng-bind="item.firstEntity | limitTo: 250"></span>
<span ng-show="change.type == 'MODIFIED'">修改</span> <span ng-bind="item.firstEntity.length > 250 ? '...' :''"></span>
<span ng-show="change.type == 'DELETED'">删除</span> </td>
</td> <td class="cursor-pointer" width="70%" ng-click="showText(item.secondEntity)">
<td class="cursor-pointer" width="20%" <span ng-bind="item.secondEntity | limitTo: 250"></span>
ng-click="showText(change.entity.firstEntity.key)"> <span ng-bind="item.secondEntity.length > 250 ? '...' :''"></span>
<span ng-bind="change.entity.firstEntity.key | limitTo: 250"></span> </td>
<span ng-bind="change.entity.firstEntity.key.length > 250 ? '...' :''"></span> </tr>
</td>
<td class="cursor-pointer" width="35%"
ng-click="showText(change.entity.firstEntity.value)">
<span ng-bind="change.entity.firstEntity.value | limitTo: 250"></span>
<span ng-bind="change.entity.firstEntity.value.length > 250 ? '...' :''"></span>
</td>
<td class="cursor-pointer" width="35%"
ng-click="showText(change.entity.secondEntity.value)">
<span ng-bind="change.entity.secondEntity.value | limitTo: 250"></span>
<span ng-bind="change.entity.secondEntity.value.length > 250 ? '...' :''"></span>
</td>
</tr>
</tbody> </tbody>
</table> </table>
</div> <div class="text-center empty-container"
<div class="text-center empty-container" ng-show="history.viewType=='all' && (!history.configuration || history.configuration.length == 0)">
ng-show="!history.changes || history.changes.length == 0"> <h5>{{'Config.History.NoItem' | translate }}</h5>
<h5>无配置更改</h5> </div>
</div> </section>
</section>
<section
<section ng-show="history.viewType=='all'"> ng-show="history.branchName != history.clusterName && history.operation != 8 && history.operation != 7">
<h4 class="section-title">全部配置</h4> <hr>
<table class="no-margin table table-striped table-hover table-bordered" <h4 class="section-title">{{'Config.History.GrayscaleRule' | translate }}</h4>
ng-show="history.configuration && history.configuration.length > 0"> <table class="no-margin table table-striped table-hover table-bordered"
<thead> ng-show="history.operationContext.rules">
<tr> <thead>
<th>Key</th> <tr>
<th>Value</th> <th>{{'Config.History.GrayscaleAppId' | translate }}</th>
</tr> <th>{{'Config.History.GrayscaleIp' | translate }}</th>
</thead> </tr>
<tbody> </thead>
<tr ng-repeat="item in history.configuration"> <tbody>
<td class="cursor-pointer" width="30%" ng-click="showText(item.firstEntity)"> <tr ng-repeat="rule in history.operationContext.rules">
<span ng-bind="item.firstEntity | limitTo: 250"></span> <td width="20%" ng-bind="rule.clientAppId"></td>
<span ng-bind="item.firstEntity.length > 250 ? '...' :''"></span> <td width="80%" ng-bind="rule.clientIpList.join(', ')"></td>
</td> </tr>
<td class="cursor-pointer" width="70%" ng-click="showText(item.secondEntity)"> </tbody>
<span ng-bind="item.secondEntity | limitTo: 250"></span> </table>
<span ng-bind="item.secondEntity.length > 250 ? '...' :''"></span> <h5 class="text-center empty-container" ng-show="!history.operationContext.rules">
</td> {{'Config.History.NoGrayscaleRule' | translate }}
</tr> </h5>
</tbody> </section>
</table>
<div class="text-center empty-container"
ng-show="history.viewType=='all' && (!history.configuration || history.configuration.length == 0)">
<h5>无配置</h5>
</div>
</section>
<section ng-show="history.branchName != history.clusterName && history.operation != 8 && history.operation != 7">
<hr>
<h4 class="section-title">灰度规则</h4>
<table class="no-margin table table-striped table-hover table-bordered"
ng-show="history.operationContext.rules">
<thead>
<tr>
<th>灰度的AppId</th>
<th>灰度的IP</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="rule in history.operationContext.rules">
<td width="20%" ng-bind="rule.clientAppId"></td>
<td width="80%" ng-bind="rule.clientIpList.join(', ')"></td>
</tr>
</tbody>
</table>
<h5 class="text-center empty-container" ng-show="!history.operationContext.rules">
无灰度规则
</h5>
</section>
</div>
</div> </div>
</div>
<!--text mode--> <!--text mode-->
<div class="release-info col-md-9" <div class="release-info col-md-9"
ng-show="isTextNamespace && history.changes && history.changes.length > 0"> ng-show="isTextNamespace && history.changes && history.changes.length > 0">
<apollodiff ng-repeat="change in history.changes" <apollodiff ng-repeat="change in history.changes" old-str="change.entity.firstEntity.value"
old-str="change.entity.firstEntity.value" new-str="change.entity.secondEntity.value" apollo-id="'releaseStrDiff'">
new-str="change.entity.secondEntity.value" </apollodiff>
apollo-id="'releaseStrDiff'"> </div>
</apollodiff>
</div>
</div> </div>
<div class="panel-body" ng-show="isConfigHidden || !releaseHistories || releaseHistories.length == 0"> <div class="panel-body" ng-show="isConfigHidden || !releaseHistories || releaseHistories.length == 0">
<h4 class="text-center empty-container" ng-show="isConfigHidden">您不是该项目的管理员,也没有该Namespace的编辑或发布权限,无法查看发布历史</h4> <h4 class="text-center empty-container" ng-show="isConfigHidden">
<h4 class="text-center empty-container" ng-show="!isConfigHidden">无发布历史信息</h4> {{'Config.History.NoPermissionTips' | translate }}</h4>
</div> <h4 class="text-center empty-container" ng-show="!isConfigHidden">
</section> {{'Config.History.NoPublishHistory' | translate }}</h4>
</div>
</section>
<showtextmodal text="text"></showtextmodal> <showtextmodal text="text"></showtextmodal>
</div> </div>
<div ng-include="'../views/common/footer.html'"></div> <div ng-include="'../views/common/footer.html'"></div>
<!-- jquery.js --> <!-- jquery.js -->
<script src="../vendor/jquery.min.js" type="text/javascript"></script> <script src="../vendor/jquery.min.js" type="text/javascript"></script>
<script src="../vendor/select2/select2.min.js" type="text/javascript"></script> <script src="../vendor/select2/select2.min.js" type="text/javascript"></script>
<!--angular--> <!--angular-->
<script src="../vendor/angular/angular.min.js"></script> <script src="../vendor/angular/angular.min.js"></script>
<script src="../vendor/angular/angular-resource.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/angular-toastr-1.4.1.tpls.min.js"></script>
<script src="../vendor/angular/loading-bar.min.js"></script> <script src="../vendor/angular/loading-bar.min.js"></script>
<script src="../vendor/angular/angular-cookies.min.js"></script>
<script src="../vendor/angular/angular-translate.2.18.1/angular-translate.min.js"></script>
<script src="../vendor/angular/angular-translate.2.18.1/angular-translate-loader-static-files.min.js"></script>
<script src="../vendor/angular/angular-translate.2.18.1/angular-translate-storage-cookie.min.js"></script>
<!-- bootstrap.js --> <!-- bootstrap.js -->
<script src="../vendor/bootstrap/js/bootstrap.min.js" type="text/javascript"></script> <script src="../vendor/bootstrap/js/bootstrap.min.js" type="text/javascript"></script>
<script src="../vendor/diff.min.js" type="text/javascript"></script> <script src="../vendor/diff.min.js" type="text/javascript"></script>
<!--biz--> <!--biz-->
<script type="application/javascript" src="../scripts/app.js"></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/services/AppService.js"></script>
<script type="application/javascript" src="../scripts/services/EnvService.js"></script> <script type="application/javascript" src="../scripts/services/EnvService.js"></script>
<script type="application/javascript" src="../scripts/services/ReleaseService.js"></script> <script type="application/javascript" src="../scripts/services/ReleaseService.js"></script>
<script type="application/javascript" src="../scripts/services/UserService.js"></script> <script type="application/javascript" src="../scripts/services/UserService.js"></script>
<script type="application/javascript" src="../scripts/services/CommonService.js"></script> <script type="application/javascript" src="../scripts/services/CommonService.js"></script>
<script type="application/javascript" src="../scripts/services/ReleaseHistoryService.js"></script> <script type="application/javascript" src="../scripts/services/ReleaseHistoryService.js"></script>
<script type="application/javascript" src="../scripts/services/ConfigService.js"></script> <script type="application/javascript" src="../scripts/services/ConfigService.js"></script>
<script type="application/javascript" src="../scripts/services/PermissionService.js"></script> <script type="application/javascript" src="../scripts/services/PermissionService.js"></script>
<script type="application/javascript" src="../scripts/AppUtils.js"></script> <script type="application/javascript" src="../scripts/AppUtils.js"></script>
<script type="application/javascript" src="../scripts/controller/config/ReleaseHistoryController.js"></script> <script type="application/javascript" src="../scripts/controller/config/ReleaseHistoryController.js"></script>
<script type="application/javascript" src="../scripts/PageCommon.js"></script> <script type="application/javascript" src="../scripts/PageCommon.js"></script>
<script type="application/javascript" src="../scripts/directive/directive.js"></script> <script type="application/javascript" src="../scripts/directive/directive.js"></script>
<script type="application/javascript" src="../scripts/directive/show-text-modal-directive.js"></script> <script type="application/javascript" src="../scripts/directive/show-text-modal-directive.js"></script>
<script type="application/javascript" src="../scripts/directive/diff-directive.js"></script> <script type="application/javascript" src="../scripts/directive/diff-directive.js"></script>
</body> </body>
</html>
</html>
\ No newline at end of file
<!doctype html> <!doctype html>
<html ng-app="sync_item"> <html ng-app="sync_item">
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="icon" href="../img/config.png"> <link rel="icon" href="../img/config.png">
...@@ -9,238 +10,252 @@ ...@@ -9,238 +10,252 @@
<link rel="stylesheet" type="text/css" media='all' href="../vendor/angular/loading-bar.min.css"> <link rel="stylesheet" type="text/css" media='all' href="../vendor/angular/loading-bar.min.css">
<link rel="stylesheet" type="text/css" href="../styles/common-style.css"> <link rel="stylesheet" type="text/css" href="../styles/common-style.css">
<link rel="stylesheet" type="text/css" href="../vendor/select2/select2.min.css"> <link rel="stylesheet" type="text/css" href="../vendor/select2/select2.min.css">
<title>同步配置</title> <title>{{'Config.Sync.Title' | translate }}</title>
</head> </head>
<body> <body>
<apollonav></apollonav> <apollonav></apollonav>
<div class="container-fluid apollo-container hidden" ng-controller="SyncItemController"> <div class="container-fluid apollo-container hidden" ng-controller="SyncItemController">
<section class="panel col-md-offset-1 col-md-10"> <section class="panel col-md-offset-1 col-md-10">
<header class="panel-heading"> <header class="panel-heading">
<div class="row"> <div class="row">
<div class="col-md-7"> <div class="col-md-7">
<h4 class="modal-title">同步配置 <h4 class="modal-title">{{'Config.Sync.Title' | translate }}
<small ng-show="syncItemStep == 1">(第一步:选择同步信息)</small> <small ng-show="syncItemStep == 1">{{'Config.Sync.FistStep' | translate }}</small>
<small ng-show="syncItemStep == 2">(第二步:检查Diff)</small> <small ng-show="syncItemStep == 2">{{'Config.Sync.SecondStep' | translate }}</small>
</h4> </h4>
</div>
<div class="col-md-5 text-right">
<button type="button" class="btn btn-primary" ng-show="syncItemStep > 1 && syncItemStep < 3"
ng-click="syncItemNextStep(-1)">上一步
</button>
<button type="button" class="btn btn-primary" ng-show="syncItemStep < 2"
ng-click="diff()">下一步
</button>
<button type="button" class="btn btn-success" ng-show="syncItemStep == 2 && hasDiff"
ng-click="syncItems()" ng-disabled="syncBtnDisabled">同步
</button>
<button type="button" class="btn btn-info" data-dismiss="modal"
ng-click="backToAppHomePage()">返回到项目首页
</button>
</div>
</div>
</header>
<div class="panel-body">
<div class="row" ng-show="syncItemStep == 1">
<div class="alert-info alert no-radius">
<strong>Tips:</strong>
<ul>
<li>通过同步配置功能,可以使多个环境、集群间的配置保持一致</li>
<li>需要注意的是,同步完之后需要发布后才会对应用生效</li>
</ul>
</div>
<div class="form-horizontal">
<div class="form-group">
<label class="col-sm-2 control-label">同步的Namespace</label>
<div class="col-sm-6">
<h4 ng-bind="pageContext.namespaceName"></h4>
</div>
</div> </div>
</div> <div class="col-md-5 text-right">
<div class="form-horizontal"> <button type="button" class="btn btn-primary" ng-show="syncItemStep > 1 && syncItemStep < 3"
<div class="form-group"> ng-click="syncItemNextStep(-1)">{{'Config.Sync.PreviousStep' | translate }}
<label class="col-sm-2 control-label">同步到那个集群</label> </button>
<div class="col-sm-6"> <button type="button" class="btn btn-primary" ng-show="syncItemStep < 2"
<apolloclusterselector apollo-app-id="pageContext.appId" apollo-default-all-checked="true" ng-click="diff()">{{'Config.Sync.NextStep' | translate }}
apollo-select="collectSelectedClusters" </button>
apollo-not-checked-env="pageContext.env" <button type="button" class="btn btn-success" ng-show="syncItemStep == 2 && hasDiff"
apollo-not-checked-cluster="pageContext.clusterName"></apolloclusterselector> ng-click="syncItems()" ng-disabled="syncBtnDisabled">{{'Config.Sync.Sync' | translate }}
</div> </button>
<button type="button" class="btn btn-info" data-dismiss="modal"
ng-click="backToAppHomePage()">{{'Common.ReturnToIndex' | translate }}
</button>
</div> </div>
</div> </div>
<hr> </header>
</div> <div class="panel-body">
<div class="row" ng-show="syncItemStep == 1">
<div class="row" ng-show="syncItemStep == 1" style="margin-top: 10px;"> <div class="alert-info alert no-radius">
<div class="form-horizontal"> <strong>{{'Config.Sync.Tips' | translate }}:</strong>
<div class="col-sm-2 text-right"> <ul>
<label class="control-label">需要同步的配置</label> <li>{{'Config.Sync.Tips1' | translate }}</li>
<li>{{'Config.Sync.Tips2' | translate }}</li>
</ul>
</div> </div>
<div class="col-sm-10"> <div class="form-horizontal">
<div class="row text-right" style="margin-bottom: 5px; margin-right: 0px;"> <div class="form-group">
按最后更新时间过滤 <label class="col-sm-2 control-label">{{'Config.Sync.SyncNamespace' | translate }}</label>
开始时间:<input type="date" ng-model="filterBeginTime"> 结束时间: <input type="date" ng-model="filterEndTime"> <div class="col-sm-6">
<button class="btn btn-sm btn-primary" ng-click="filter()">过滤</button> <h4 ng-bind="pageContext.namespaceName"></h4>
<button class="btn btn-sm btn-default" ng-click="resetFilter()">重置</button> </div>
</div> </div>
<table class="table table-bordered table-striped table-hover">
<thead>
<tr>
<td><input type="checkbox" ng-click="toggleItemsCheckedStatus()"></td>
<td class="hover" ng-click="col='key';desc=!desc;">
Key
<span class="glyphicon glyphicon-sort"></span>
</td>
<td>Value</td>
<td class="hover" ng-click="col='dataChangeCreatedTime';desc=!desc;">
Create Time
<span class="glyphicon glyphicon-sort"></span>
</td>
<td class="hover" ng-click="col='dataChangeLastModifiedTime';desc=!desc;">
Update Time
<span class="glyphicon glyphicon-sort"></span>
</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in viewItems|orderBy:col:desc">
<td width="10%"><input type="checkbox" ng-checked="item.checked"
ng-click="switchSelect(item)"></td>
<td width="20%">
<span ng-bind="item.key | limitTo: 250"></span>
<span ng-bind="item.key.length > 250 ? '...' : ''"></span>
</td>
<td class="cursor-pointer" width="40%" ng-click="showText(item.value)">
<span ng-bind="item.value | limitTo: 250"></span>
<span ng-bind="item.value.length > 250 ? '...' : ''"></span>
</td>
<td width="15%">
<span ng-bind="item.dataChangeCreatedTime | date: 'yyyy-MM-dd HH:mm:ss'"></span>
</td>
<td width="15%">
<span ng-bind="item.dataChangeLastModifiedTime | date: 'yyyy-MM-dd HH:mm:ss'"></span>
</td>
</tr>
</tbody>
</table>
</div> </div>
<div class="form-horizontal">
<div class="form-group">
<label class="col-sm-2 control-label">{{'Config.Sync.SyncToCluster' | translate }}</label>
<div class="col-sm-6">
<apolloclusterselector apollo-app-id="pageContext.appId"
apollo-default-all-checked="true" apollo-select="collectSelectedClusters"
apollo-not-checked-env="pageContext.env"
apollo-not-checked-cluster="pageContext.clusterName"></apolloclusterselector>
</div>
</div>
</div>
<hr>
</div> </div>
</div> <div class="row" ng-show="syncItemStep == 1" style="margin-top: 10px;">
<!--step 2-->
<div class="row" ng-show="syncItemStep == 2" ng-repeat="clusterDiff in clusterDiffs">
<h4 class="text-center">
环境:<span ng-bind="clusterDiff.namespace.env"></span>
集群:<span ng-bind="clusterDiff.namespace.clusterName"></span>
<span ng-show="!clusterDiff.extInfo">Namespace:{{pageContext.namespaceName}}</span>
</h4>
<div class="text-center"
ng-show="clusterDiff.diffs.createItems.length + clusterDiff.diffs.updateItems.length == 0 || clusterDiff.extInfo">
<span ng-show="clusterDiff.diffs.createItems.length + clusterDiff.diffs.updateItems.length == 0 && !clusterDiff.extInfo">没有更新的配置</span>
<span ng-show="clusterDiff.extInfo" ng-bind="clusterDiff.extInfo"></span>
,忽略同步
</div>
<div class="row" style="margin-top: 10px;"
ng-show="clusterDiff.diffs.updateItems.length + clusterDiff.diffs.createItems.length > 0">
<div class="form-horizontal"> <div class="form-horizontal">
<div class="col-sm-12"> <div class="col-sm-2 text-right">
<label class="control-label">{{'Config.Sync.NeedToSyncItem' | translate }}</label>
</div>
<div class="col-sm-10">
<div class="row text-right" style="margin-bottom: 5px; margin-right: 0px;">
{{'Config.Sync.SortByLastModifyTime' | translate }}
{{'Config.Sync.BeginTime' | translate }}:<input type="date" ng-model="filterBeginTime">
{{'Config.Sync.EndTime' | translate }}: <input type="date" ng-model="filterEndTime">
<button class="btn btn-sm btn-primary"
ng-click="filter()">{{'Config.Sync.Filter' | translate }}</button>
<button class="btn btn-sm btn-default"
ng-click="resetFilter()">{{'Config.Sync.Rest' | translate }}</button>
</div>
<table class="table table-bordered table-striped table-hover"> <table class="table table-bordered table-striped table-hover">
<thead> <thead>
<tr> <tr>
<td>Type</td> <td><input type="checkbox" ng-click="toggleItemsCheckedStatus()"></td>
<td>Key</td> <td class="hover" ng-click="col='key';desc=!desc;">
<td>同步前</td> {{'Config.Sync.ItemKey' | translate }}
<td>同步后</td> <span class="glyphicon glyphicon-sort"></span>
<td>Comment</td> </td>
<td>操作</td> <td>{{'Config.Sync.ItemValue' | translate }}</td>
</tr> <td class="hover" ng-click="col='dataChangeCreatedTime';desc=!desc;">
{{'Config.Sync.ItemCreateTime' | translate }}
<span class="glyphicon glyphicon-sort"></span>
</td>
<td class="hover" ng-click="col='dataChangeLastModifiedTime';desc=!desc;">
{{'Config.Sync.ItemUpdateTime' | translate }}
<span class="glyphicon glyphicon-sort"></span>
</td>
</tr>
</thead> </thead>
<tbody> <tbody>
<tr ng-repeat="createItem in clusterDiff.diffs.createItems"> <tr ng-repeat="item in viewItems|orderBy:col:desc">
<td width="5%">新增</td> <td width="10%"><input type="checkbox" ng-checked="item.checked"
<td width="15%" ng-bind="createItem.key"></td> ng-click="switchSelect(item)"></td>
<td width="30%"></td> <td width="20%">
<td width="30%" ng-bind="createItem.value"></td> <span ng-bind="item.key | limitTo: 250"></span>
<td width="15%" ng-bind="createItem.comment"></td> <span ng-bind="item.key.length > 250 ? '...' : ''"></span>
<td width="5%"> </td>
<a data-tooltip="tooltip" data-placement="bottom" title="不同步该配置" <td class="cursor-pointer" width="40%" ng-click="showText(item.value)">
ng-click="removeItem(clusterDiff.diffs, 'create', createItem)">删除</a> <span ng-bind="item.value | limitTo: 250"></span>
</td> <span ng-bind="item.value.length > 250 ? '...' : ''"></span>
</tr> </td>
<tr ng-repeat="updateItem in clusterDiff.diffs.updateItems"> <td width="15%">
<td width="5%">更新</td> <span
<td width="15%" ng-bind="updateItem.key"></td> ng-bind="item.dataChangeCreatedTime | date: 'yyyy-MM-dd HH:mm:ss'"></span>
<td width="30%" ng-bind="updateItem.oldValue"></td> </td>
<td width="30%" ng-bind="updateItem.value"></td> <td width="15%">
<td width="15%" ng-bind="updateItem.comment"></td> <span
<td width="5%"> ng-bind="item.dataChangeLastModifiedTime | date: 'yyyy-MM-dd HH:mm:ss'"></span>
<a data-tooltip="tooltip" data-placement="bottom" title="不同步该配置" </td>
ng-click="removeItem(clusterDiff.diffs, 'update', updateItem)">删除</a> </tr>
</td>
</tr>
</tbody> </tbody>
</table> </table>
</div> </div>
</div> </div>
</div> </div>
</div>
<!--step 2-->
<div class="row" ng-show="syncItemStep == 2" ng-repeat="clusterDiff in clusterDiffs">
<h4 class="text-center">
{{'Common.Environment' | translate }}:<span ng-bind="clusterDiff.namespace.env"></span>
{{'Common.Cluster' | translate }}:<span ng-bind="clusterDiff.namespace.clusterName"></span>
<span
ng-show="!clusterDiff.extInfo">{{'Common.Namespace' | translate }}:{{pageContext.namespaceName}}</span>
</h4>
<div class="text-center"
ng-show="clusterDiff.diffs.createItems.length + clusterDiff.diffs.updateItems.length == 0 || clusterDiff.extInfo">
<span
ng-show="clusterDiff.diffs.createItems.length + clusterDiff.diffs.updateItems.length == 0 && !clusterDiff.extInfo">{{'Config.Sync.NoNeedSyncItem' | translate }}</span>
<span ng-show="clusterDiff.extInfo" ng-bind="clusterDiff.extInfo"></span>
,{{'Config.Sync.IgnoreSync' | translate }}
</div>
<!--step 3--> <div class="row" style="margin-top: 10px;"
<div class="row text-center" ng-show="syncItemStep == 3 && syncSuccess"> ng-show="clusterDiff.diffs.updateItems.length + clusterDiff.diffs.createItems.length > 0">
<img src="../img/sync-succ.png" style="height: 100px; width: 100px"> <div class="form-horizontal">
<h3>同步成功!</h3> <div class="col-sm-12">
</div> <table class="table table-bordered table-striped table-hover">
<div class="row text-center" ng-show="syncItemStep == 3 && !syncSuccess"> <thead>
<img src="../img/sync-error.png" style="height: 100px; width: 100px"> <tr>
<h3>同步失败!</h3> <td>{{'Config.Sync.Step2Type' | translate }}</td>
</div> <td>{{'Config.Sync.Step2Key' | translate }}</td>
<td>{{'Config.Sync.Step2SyncBefore' | translate }}</td>
<td>{{'Config.Sync.Step2SyncAfter' | translate }}</td>
<td>{{'Config.Sync.Step2Comment' | translate }}</td>
<td>{{'Config.Sync.Step2Operator' | translate }}</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="createItem in clusterDiff.diffs.createItems">
<td width="5%">{{'Config.Sync.NewAdd' | translate }}</td>
<td width="15%" ng-bind="createItem.key"></td>
<td width="30%"></td>
<td width="30%" ng-bind="createItem.value"></td>
<td width="15%" ng-bind="createItem.comment"></td>
<td width="5%">
<a data-tooltip="tooltip" data-placement="bottom"
title="{{'Config.Sync.NoSyncItem' | translate }}"
ng-click="removeItem(clusterDiff.diffs, 'create', createItem)">{{'Config.Sync.Delete' | translate }}</a>
</td>
</tr>
<tr ng-repeat="updateItem in clusterDiff.diffs.updateItems">
<td width="5%">{{'Config.Sync.Update' | translate }}</td>
<td width="15%" ng-bind="updateItem.key"></td>
<td width="30%" ng-bind="updateItem.oldValue"></td>
<td width="30%" ng-bind="updateItem.value"></td>
<td width="15%" ng-bind="updateItem.comment"></td>
<td width="5%">
<a data-tooltip="tooltip" data-placement="bottom"
title="{{'Config.Sync.NoSyncItem' | translate }}"
ng-click="removeItem(clusterDiff.diffs, 'update', updateItem)">{{'Config.Sync.Delete' | translate }}</a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</section>
<showtextmodal text="text"/> <!--step 3-->
</div> <div class="row text-center" ng-show="syncItemStep == 3 && syncSuccess">
<img src="../img/sync-succ.png" style="height: 100px; width: 100px">
<h3>{{'Config.Sync.SyncSuccessfully' | translate }}</h3>
</div>
<div class="row text-center" ng-show="syncItemStep == 3 && !syncSuccess">
<img src="../img/sync-error.png" style="height: 100px; width: 100px">
<h3>{{'Config.Sync.SyncFailed' | translate }}</h3>
</div>
</div>
</section>
<showtextmodal text="text" />
</div>
<div ng-include="'../views/common/footer.html'"></div>
<!-- jquery.js --> <div ng-include="'../views/common/footer.html'"></div>
<script src="../vendor/jquery.min.js" type="text/javascript"></script>
<script src="../vendor/select2/select2.min.js" type="text/javascript"></script>
<!--angular--> <!-- jquery.js -->
<script src="../vendor/angular/angular.min.js"></script> <script src="../vendor/jquery.min.js" type="text/javascript"></script>
<script src="../vendor/angular/angular-resource.min.js"></script> <script src="../vendor/select2/select2.min.js" type="text/javascript"></script>
<script src="../vendor/angular/angular-toastr-1.4.1.tpls.min.js"></script>
<script src="../vendor/angular/loading-bar.min.js"></script>
<!--angular-->
<script src="../vendor/angular/angular.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>
<script src="../vendor/angular/angular-cookies.min.js"></script>
<!-- bootstrap.js --> <script src="../vendor/angular/angular-translate.2.18.1/angular-translate.min.js"></script>
<script src="../vendor/bootstrap/js/bootstrap.min.js" type="text/javascript"></script> <script src="../vendor/angular/angular-translate.2.18.1/angular-translate-loader-static-files.min.js"></script>
<script src="../vendor/angular/angular-translate.2.18.1/angular-translate-storage-cookie.min.js"></script>
<script src="../vendor/clipboard.min.js" type="text/javascript"></script> <!-- bootstrap.js -->
<!--biz--> <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/services/EnvService.js"></script>
<script type="application/javascript" src="../scripts/services/ConfigService.js"></script>
<script type="application/javascript" src="../scripts/services/UserService.js"></script>
<script type="application/javascript" src="../scripts/services/CommonService.js"></script>
<script type="application/javascript" src="../scripts/services/PermissionService.js"></script>
<script type="application/javascript" src="../scripts/AppUtils.js"></script> <script src="../vendor/clipboard.min.js" type="text/javascript"></script>
<script type="application/javascript" src="../scripts/controller/config/SyncConfigController.js"></script> <!--biz-->
<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/services/ConfigService.js"></script>
<script type="application/javascript" src="../scripts/services/UserService.js"></script>
<script type="application/javascript" src="../scripts/services/CommonService.js"></script>
<script type="application/javascript" src="../scripts/services/PermissionService.js"></script>
<script type="application/javascript" src="../scripts/PageCommon.js"></script> <script type="application/javascript" src="../scripts/AppUtils.js"></script>
<script type="application/javascript" src="../scripts/directive/directive.js"></script> <script type="application/javascript" src="../scripts/controller/config/SyncConfigController.js"></script>
<script type="application/javascript" src="../scripts/directive/show-text-modal-directive.js"></script>
<script type="application/javascript" src="../scripts/PageCommon.js"></script>
<script type="application/javascript" src="../scripts/directive/directive.js"></script>
<script type="application/javascript" src="../scripts/directive/show-text-modal-directive.js"></script>
</body> </body>
</html>
</html>
\ No newline at end of file
<!doctype html> <!doctype html>
<html ng-app="delete_app_cluster_namespace"> <html ng-app="delete_app_cluster_namespace">
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="icon" href="../img/config.png"> <link rel="icon" href="../img/config.png">
...@@ -9,213 +10,223 @@ ...@@ -9,213 +10,223 @@
<link rel="stylesheet" type="text/css" media='all' href="../vendor/angular/loading-bar.min.css"> <link rel="stylesheet" type="text/css" media='all' href="../vendor/angular/loading-bar.min.css">
<link rel="stylesheet" type="text/css" href="../styles/common-style.css"> <link rel="stylesheet" type="text/css" href="../styles/common-style.css">
<link rel="stylesheet" type="text/css" href="../vendor/select2/select2.min.css"> <link rel="stylesheet" type="text/css" href="../vendor/select2/select2.min.css">
<title>删除应用、集群、AppNamespace</title> <title>{{'Delete.Title' | translate }}</title>
</head> </head>
<body> <body>
<apollonav></apollonav> <apollonav></apollonav>
<div class="container-fluid" ng-controller="DeleteAppClusterNamespaceController"> <div class="container-fluid" ng-controller="DeleteAppClusterNamespaceController">
<div class="col-md-10 col-md-offset-1 panel"> <div class="col-md-10 col-md-offset-1 panel">
<section class="panel-body" ng-show="isRootUser"> <section class="panel-body" ng-show="isRootUser">
<!-- delete app --> <!-- delete app -->
<section class="row"> <section class="row">
<h5>删除应用 <h5>{{'Delete.DeleteApp' | translate }}
<small> <small>
(由于删除应用影响面较大,所以现在暂时只允许系统管理员删除,请确保没有客户端读取该应用的配置后再做删除动作) {{'Delete.DeleteAppTips' | translate }}
</small> </small>
</h5> </h5>
<hr> <hr>
<form class="form-horizontal"> <form class="form-horizontal">
<div class="form-group" valdr-form-group> <div class="form-group" valdr-form-group>
<label class="col-sm-2 control-label"> <label class="col-sm-2 control-label">
<apollorequiredfield></apollorequiredfield> <apollorequiredfield></apollorequiredfield>
应用AppId</label> {{'Common.AppId' | translate }}
<div class="col-sm-5"> </label>
<input type="text" class="form-control" ng-model="app.appId"> <div class="col-sm-5">
<small>(删除前请先查询应用信息)</small> <input type="text" class="form-control" ng-model="app.appId">
<small> {{'Delete.AppIdTips' | translate }}</small>
</div>
<div class="col-sm-1">
<button class="btn btn-info" ng-click="getAppInfo()">{{'Common.Search' | translate }}</button>
</div>
</div> </div>
<div class="col-sm-1"> <div class="form-group" valdr-form-group>
<button class="btn btn-info" ng-click="getAppInfo()">查询</button> <label class="col-sm-2 control-label">
{{'Delete.AppInfo' | translate }}</label>
<div class="col-sm-5">
<h5 ng-show="app.info" ng-bind="app.info"></h5>
</div>
</div> </div>
</div>
<div class="form-group" valdr-form-group>
<label class="col-sm-2 control-label">
应用信息</label>
<div class="col-sm-5">
<h5 ng-show="app.info" ng-bind="app.info"></h5>
</div>
</div>
<div class="form-group"> <div class="form-group">
<div class="col-sm-offset-2 col-sm-9"> <div class="col-sm-offset-2 col-sm-9">
<button type="submit" class="btn btn-primary" <button type="submit" class="btn btn-primary" ng-disabled="deleteAppBtnDisabled"
ng-disabled="deleteAppBtnDisabled"
ng-click="deleteApp()"> ng-click="deleteApp()">
删除应用 {{'Delete.DeleteApp' | translate }}
</button> </button>
</div>
</div> </div>
</div> </form>
</form> </section>
</section>
<!-- delete cluster -->
<!-- delete cluster --> <section class="row">
<section class="row"> <h5>{{'Delete.DeleteCluster' | translate }}
<h5>删除集群 <small>
<small> {{'Delete.DeleteClusterTips' | translate }}
(由于删除集群影响面较大,所以现在暂时只允许系统管理员删除,请确保没有客户端读取该集群的配置后再做删除动作) </small>
</small> </h5>
</h5> <hr>
<hr> <form class="form-horizontal">
<form class="form-horizontal"> <div class="form-group" valdr-form-group>
<div class="form-group" valdr-form-group> <label class="col-sm-2 control-label">
<label class="col-sm-2 control-label"> <apollorequiredfield></apollorequiredfield>
<apollorequiredfield></apollorequiredfield> {{'Common.AppId' | translate }}
应用AppId</label> </label>
<div class="col-sm-5"> <div class="col-sm-5">
<input type="text" class="form-control" ng-model="cluster.appId"> <input type="text" class="form-control" ng-model="cluster.appId">
</div>
</div> </div>
</div> <div class="form-group" valdr-form-group>
<div class="form-group" valdr-form-group> <label class="col-sm-2 control-label">
<label class="col-sm-2 control-label"> <apollorequiredfield></apollorequiredfield>
<apollorequiredfield></apollorequiredfield> {{'Delete.EnvName' | translate }}
环境名称</label> </label>
<div class="col-sm-5"> <div class="col-sm-5">
<input type="text" class="form-control" ng-model="cluster.env"> <input type="text" class="form-control" ng-model="cluster.env">
</div>
</div> </div>
</div> <div class="form-group" valdr-form-group>
<div class="form-group" valdr-form-group> <label class="col-sm-2 control-label">
<label class="col-sm-2 control-label"> <apollorequiredfield></apollorequiredfield>
<apollorequiredfield></apollorequiredfield> {{'Common.ClusterName' | translate }}
集群名称</label> </label>
<div class="col-sm-5"> <div class="col-sm-5">
<input type="text" class="form-control" ng-model="cluster.name"> <input type="text" class="form-control" ng-model="cluster.name">
<small>(删除前请先查询应用集群信息)</small> <small>{{'Delete.ClusterNameTips' | translate }}</small>
</div>
<div class="col-sm-1">
<button class="btn btn-info"
ng-click="getClusterInfo()">{{'Common.Search' | translate }}</button>
</div>
</div> </div>
<div class="col-sm-1"> <div class="form-group" viv clform-group>
<button class="btn btn-info" ng-click="getClusterInfo()">查询</button> <label class="col-sm-2 control-label">
{{'Delete.ClusterInfo' | translate }}</label>
<div class="col-sm-5">
<h5 ng-show="cluster.info" ng-bind="cluster.info"></h5>
</div>
</div> </div>
</div>
<div class="form-group" viv clform-group>
<label class="col-sm-2 control-label">
集群信息</label>
<div class="col-sm-5">
<h5 ng-show="cluster.info" ng-bind="cluster.info"></h5>
</div>
</div>
<div class="form-group"> <div class="form-group">
<div class="col-sm-offset-2 col-sm-9"> <div class="col-sm-offset-2 col-sm-9">
<button type="submit" class="btn btn-primary" <button type="submit" class="btn btn-primary" ng-disabled="deleteClusterBtnDisabled"
ng-disabled="deleteClusterBtnDisabled"
ng-click="deleteCluster()"> ng-click="deleteCluster()">
删除集群 {{'Delete.DeleteCluster' | translate }}
</button> </button>
</div>
</div> </div>
</div> </form>
</form> </section>
</section>
<!-- delete app namespace -->
<!-- delete app namespace --> <section class="row">
<section class="row"> <h5>{{'Delete.DeleteNamespace' | translate }}
<h5>删除AppNamespace <small>{{'Delete.DeleteNamespaceTips' | translate }}</small>
<small>(注意,所有环境的Namespace和AppNamespace都会被删除!如果只是要删除某个环境的Namespace,让用户到项目页面中自行删除!)</small> </h5>
</h5> <small>
<small> {{'Delete.DeleteNamespaceTips2' | translate }}
目前用户可以自行删除关联的Namespace和私有的Namespace,不过无法删除AppNamespace元信息,因为删除AppNamespace影响面较大,所以现在暂时只允许系统管理员删除,对于公共Namespace需要确保没有应用关联了该AppNamespace。 </small>
</small> <hr>
<hr> <form class="form-horizontal">
<form class="form-horizontal"> <div class="form-group" valdr-form-group>
<div class="form-group" valdr-form-group> <label class="col-sm-2 control-label">
<label class="col-sm-2 control-label"> <apollorequiredfield></apollorequiredfield>
<apollorequiredfield></apollorequiredfield> {{'Common.AppId' | translate }}
应用AppId</label> </label>
<div class="col-sm-5"> <div class="col-sm-5">
<input type="text" class="form-control" ng-model="appNamespace.appId"> <input type="text" class="form-control" ng-model="appNamespace.appId">
</div> </div>
</div>
<div class="form-group" valdr-form-group>
<label class="col-sm-2 control-label">
<apollorequiredfield></apollorequiredfield>
AppNamespace名称</label>
<div class="col-sm-5">
<input type="text" class="form-control" ng-model="appNamespace.name">
<small>(非properties类型的namespace请加上类型后缀,例如apollo.xml)</small>
</div> </div>
<div class="col-sm-1"> <div class="form-group" valdr-form-group>
<button class="btn btn-info" ng-click="getAppNamespaceInfo()">查询</button> <label class="col-sm-2 control-label">
<apollorequiredfield></apollorequiredfield>
{{'Delete.AppNamespaceName' | translate }}
</label>
<div class="col-sm-5">
<input type="text" class="form-control" ng-model="appNamespace.name">
<small>{{'Delete.AppNamespaceNameTips' | translate }}</small>
</div>
<div class="col-sm-1">
<button class="btn btn-info" ng-click="getAppNamespaceInfo()">{{'Common.Search' | translate }}</button>
</div>
</div> </div>
</div> <div class="form-group" viv clform-group>
<div class="form-group" viv clform-group> <label class="col-sm-2 control-label">
<label class="col-sm-2 control-label"> {{'Delete.AppNamespaceInfo' | translate }}</label>
AppNamespace信息</label> <div class="col-sm-5">
<div class="col-sm-5"> <h5 ng-show="appNamespace.info" ng-bind="appNamespace.info"></h5>
<h5 ng-show="appNamespace.info" ng-bind="appNamespace.info"></h5> </div>
</div> </div>
</div>
<div class="form-group">
<div class="form-group"> <div class="col-sm-offset-2 col-sm-9">
<div class="col-sm-offset-2 col-sm-9"> <button type="submit" class="btn btn-primary"
<button type="submit" class="btn btn-primary" ng-disabled="deleteAppNamespaceBtnDisabled" ng-click="deleteAppNamespace()">
ng-disabled="deleteAppNamespaceBtnDisabled" {{'Delete.DeleteNamespace' | translate }}
ng-click="deleteAppNamespace()"> </button>
删除AppNamespace </div>
</button>
</div> </div>
</div> </form>
</form> </section>
</section> </section>
</section>
<section class="panel-body text-center" ng-if="!isRootUser"> <section class="panel-body text-center" ng-if="!isRootUser">
<h4>当前页面只对Apollo管理员开放</h4> <h4>{{'Common.IsRootUserTips' | translate }}</h4>
</section> </section>
</div>
</div> </div>
</div>
<div ng-include="'../views/common/footer.html'"></div> <div ng-include="'../views/common/footer.html'"></div>
<!-- jquery.js --> <!-- jquery.js -->
<script src="../vendor/jquery.min.js" type="text/javascript"></script> <script src="../vendor/jquery.min.js" type="text/javascript"></script>
<!--angular--> <!--angular-->
<script src="../vendor/angular/angular.min.js"></script> <script src="../vendor/angular/angular.min.js"></script>
<script src="../vendor/angular/angular-route.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-resource.min.js"></script>
<script src="../vendor/angular/angular-toastr-1.4.1.tpls.min.js"></script> <script src="../vendor/angular/angular-toastr-1.4.1.tpls.min.js"></script>
<script src="../vendor/angular/loading-bar.min.js"></script> <script src="../vendor/angular/loading-bar.min.js"></script>
<script src="vendor/angular/angular-cookies.min.js"></script>
<!--valdr--> <script src="vendor/angular/angular-translate.2.18.1/angular-translate.min.js"></script>
<script src="../vendor/valdr/valdr.min.js" type="text/javascript"></script> <script src="vendor/angular/angular-translate.2.18.1/angular-translate-loader-static-files.min.js"></script>
<script src="../vendor/valdr/valdr-message.min.js" type="text/javascript"></script> <script src="vendor/angular/angular-translate.2.18.1/angular-translate-storage-cookie.min.js"></script>
<!-- bootstrap.js --> <!--valdr-->
<script src="../vendor/bootstrap/js/bootstrap.min.js" type="text/javascript"></script> <script src="../vendor/valdr/valdr.min.js" type="text/javascript"></script>
<script src="../vendor/valdr/valdr-message.min.js" type="text/javascript"></script>
<script src="../vendor/lodash.min.js"></script> <!-- bootstrap.js -->
<script src="../vendor/bootstrap/js/bootstrap.min.js" type="text/javascript"></script>
<script src="../vendor/select2/select2.min.js" type="text/javascript"></script> <script src="../vendor/lodash.min.js"></script>
<!--biz-->
<!--must import-->
<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/services/UserService.js"></script>
<script type="application/javascript" src="../scripts/services/CommonService.js"></script>
<script type="application/javascript" src="../scripts/services/PermissionService.js"></script>
<script type="application/javascript" src="../scripts/services/ClusterService.js"></script>
<script type="application/javascript" src="../scripts/services/NamespaceService.js"></script>
<script type="application/javascript" src="../scripts/AppUtils.js"></script> <script src="../vendor/select2/select2.min.js" type="text/javascript"></script>
<!--biz-->
<!--must import-->
<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/services/UserService.js"></script>
<script type="application/javascript" src="../scripts/services/CommonService.js"></script>
<script type="application/javascript" src="../scripts/services/PermissionService.js"></script>
<script type="application/javascript" src="../scripts/services/ClusterService.js"></script>
<script type="application/javascript" src="../scripts/services/NamespaceService.js"></script>
<script type="application/javascript" src="../scripts/PageCommon.js"></script> <script type="application/javascript" src="../scripts/AppUtils.js"></script>
<script type="application/javascript" src="../scripts/directive/directive.js"></script>
<script type="application/javascript" src="../scripts/valdr.js"></script>
<script type="application/javascript" src="../scripts/controller/DeleteAppClusterNamespaceController.js"></script> <script type="application/javascript" src="../scripts/PageCommon.js"></script>
<script type="application/javascript" src="../scripts/directive/directive.js"></script>
<script type="application/javascript" src="../scripts/valdr.js"></script>
<script type="application/javascript" src="../scripts/controller/DeleteAppClusterNamespaceController.js"></script>
</body> </body>
</html>
</html>
\ No newline at end of file
{
"Common.Title": "Apollo Configuration Center",
"Common.Ctrip": "Ctrip",
"Common.CtripDepartment": "Framework R&D Department",
"Common.Nav.ShowNavBar": "Display navigation bar",
"Common.Nav.HideNavBar": "Hide navigation bar",
"Common.Nav.Help": "Help",
"Common.Nav.AdminTools": "Admin Tools",
"Common.Nav.UserManage": "User Management",
"Common.Nav.SystemRoleManage": "System Permission Management",
"Common.Nav.OpenMange": "Open Platform Authorization Management",
"Common.Nav.SystemConfig": "System Configuration",
"Common.Nav.DeleteApp-Cluster-Namespace": "Delete Apps, Clusters, AppNamespace",
"Common.Nav.SystemInfo": "System Information",
"Common.Nav.Logout": "Logout",
"Common.Department": "Department",
"Common.Cluster": "Cluster",
"Common.Environment": "Environment",
"Common.Email": "Email",
"Common.AppId": "App Id",
"Common.Namespace": "Namespace",
"Common.AppName": "App Name",
"Common.AppOwner": "App Owner",
"Common.AppOwnerLong": "App Owner",
"Common.AppAdmin": "App Administrators",
"Common.ClusterName": "Cluster Name",
"Common.Submit": "Submit",
"Common.Save": "Save",
"Common.Created": "Create Successfully",
"Common.CreateFailed": "Fail to Create",
"Common.Deleted": "Delete Successfully",
"Common.DeleteFailed": "Fail to Delete",
"Common.ReturnToIndex": "Return to project page",
"Common.Cancel": "Cancel",
"Common.Ok": "OK",
"Common.Search": "Query",
"Common.IsRootUser": "Current page is only accessible to Apollo administrator.",
"Common.PleaseChooseDepartment": "Please select department",
"Common.PleaseChooseOwner": "Please select app owner",
"Common.LoginExpiredTips": "Your login is expired. Please refresh the page and try again.",
"Component.DeleteNamespace.Title": "Delete Namespace",
"Component.DeleteNamespace.PublicContent": "Deleting namespace will cause the instances unable to get the configuration of this namespace. Are you sure to delete it?",
"Component.DeleteNamespace.PrivateContent": "Deleting a private Namespace will cause the instances unable to get the configuration of this namespace, and the page will prompt 'missing namespace' (unless the AppNamespace is deleted by admin tool). Are you sure to delete it?",
"Component.GrayscalePublishRule.Title": "Edit Grayscale Rule",
"Component.GrayscalePublishRule.AppId": "Grayscale AppId",
"Component.GrayscalePublishRule.AcceptRule": "Grayscale Application Rule",
"Component.GrayscalePublishRule.AcceptPartInstance": "Apply to some instances",
"Component.GrayscalePublishRule.AcceptAllInstance": "Apply to all instances",
"Component.GrayscalePublishRule.IP": "Grayscale IP",
"Component.GrayscalePublishRule.AppIdFilterTips": "(The list of instances are filtered by the typed AppId automatically)",
"Component.GrayscalePublishRule.IpTips": "Can't find the IP you want? You may ",
"Component.GrayscalePublishRule.EnterIp": "enter IP manually",
"Component.GrayscalePublishRule.EnterIpTips": "Enter the list of IP, using ',' as the separator, and then click the Add button.",
"Component.GrayscalePublishRule.Add": "Add",
"Component.ConfigItem.Title": "Add Configuration",
"Component.ConfigItem.TitleTips": "(Reminder: Configuration can be added in batch via text mode)",
"Component.ConfigItem.AddGrayscaleItem": "Add Grayscale Configuration",
"Component.ConfigItem.ModifyItem": "Modify Configuration",
"Component.ConfigItem.ItemKey": "Key",
"Component.ConfigItem.ItemValue": "Value",
"Component.ConfigItem.ItemValueTips": "Note: Hidden characters (Spaces, Newline, Tab) easily cause configuration errors. If you want to check hidden characters in Value, please click",
"Component.ConfigItem.ItemValueShowDetection": "Check Hidden Characters",
"Component.ConfigItem.ItemValueNotHiddenChars": "No Hidden Characters",
"Component.ConfigItem.ItemComment": "Comment",
"Component.ConfigItem.ChooseCluster": "Select Cluster",
"Component.MergePublish.Title": "Full Release",
"Component.MergePublish.Tips": "Full release will merge the configurations of grayscale version into the main version and release them.",
"Component.MergePublish.NextStep": "After full release, choose which behavior you want",
"Component.MergePublish.DeleteGrayscale": "Delete grayscale version",
"Component.MergePublish.ReservedGrayscale": "Keep grayscale version",
"Component.Namespace.Branch.IsChanged": "Modified",
"Component.Namespace.Branch.ChangeUser": "Current Modifier",
"Component.Namespace.Branch.ContinueGrayscalePublish": "Continue to Grayscale Release",
"Component.Namespace.Branch.GrayscalePublish": "Grayscale Release",
"Component.Namespace.Branch.MergeToMasterAndPublish": "Merge to the main version and release the main version's configurations ",
"Component.Namespace.Branch.AllPublish": "Full Release",
"Component.Namespace.Branch.DiscardGrayscaleVesion": "Abandon Grayscale Version",
"Component.Namespace.Branch.DiscardGrayscale": "Abandon Grayscale",
"Component.Namespace.Branch.NoPermissionTips": "You are not this project's administrator, nor you have edit or release permission for the namespace. Thus you cannot view the configuration.",
"Component.Namespace.Branch.Tab.Configuration": "Configuration",
"Component.Namespace.Branch.Tab.GrayscaleRule": "Grayscale Rule",
"Component.Namespace.Branch.Tab.GrayscaleInstance": "Grayscale Instance List",
"Component.Namespace.Branch.Tab.ChangeHistory": "Change History",
"Component.Namespace.Branch.Body.Item": "Grayscale Configuration",
"Component.Namespace.Branch.Body.AddedItem": "Add Grayscale Configuration",
"Component.Namespace.Branch.Body.PublishState": "Release Status",
"Component.Namespace.Branch.Body.ItemSort": "Sort",
"Component.Namespace.Branch.Body.ItemKey": "Key",
"Component.Namespace.Branch.Body.ItemMasterValue": "Value of Main Version",
"Component.Namespace.Branch.Body.ItemGrayscaleValue": "Grayscale value",
"Component.Namespace.Branch.Body.ItemComment": "Comment",
"Component.Namespace.Branch.Body.ItemLastModify": "Last Modifier",
"Component.Namespace.Branch.Body.ItemLastModifyTime": "Last Modified Time",
"Component.Namespace.Branch.Body.ItemOperator": "Operation",
"Component.Namespace.Branch.Body.ClickToSeeItemValue": "Click to view released values",
"Component.Namespace.Branch.Body.ItemNoPublish": "Unreleased",
"Component.Namespace.Branch.Body.ItemPublished": "Released",
"Component.Namespace.Branch.Body.ItemEffective": "Effective configuration",
"Component.Namespace.Branch.Body.ClickToSee": "Click to view",
"Component.Namespace.Branch.Body.DeletedItem": "Deleted configuration",
"Component.Namespace.Branch.Body.Delete": "Deleted",
"Component.Namespace.Branch.Body.ChangedFromMaster": "Configuration modified from the main version",
"Component.Namespace.Branch.Body.ModifiedItem": "Modified configuration",
"Component.Namespace.Branch.Body.Modify": "Modified",
"Component.Namespace.Branch.Body.AddedByGrayscale": "Specific configuration for grayscale version",
"Component.Namespace.Branch.Body.Added": "New",
"Component.Namespace.Branch.Body.Op.Modify": "Modify",
"Component.Namespace.Branch.Body.Op.Delete": "Delete",
"Component.Namespace.MasterBranch.Body.Title": "Configuration of the main version",
"Component.Namespace.MasterBranch.Body.PublishState": "Release Status",
"Component.Namespace.MasterBranch.Body.ItemKey": "Key",
"Component.Namespace.MasterBranch.Body.ItemValue": "Value",
"Component.Namespace.MasterBranch.Body.ItemComment": "Comment",
"Component.Namespace.MasterBranch.Body.ItemLastModify": "Last Modifier",
"Component.Namespace.MasterBranch.Body.ItemLastModifyTime": "Last Modified Time",
"Component.Namespace.MasterBranch.Body.ItemOperator": "Operation",
"Component.Namespace.MasterBranch.Body.ClickToSeeItemValue": "Click to check released values",
"Component.Namespace.MasterBranch.Body.ItemNoPublish": "Unreleased",
"Component.Namespace.MasterBranch.Body.ItemEffective": "Effective configuration",
"Component.Namespace.MasterBranch.Body.ItemPublished": "Released",
"Component.Namespace.MasterBranch.Body.AddedItem": "New configuration",
"Component.Namespace.MasterBranch.Body.ModifyItem": "Modify the grayscale configuration",
"Component.Namespace.Branch.GrayScaleRule.NoPermissionTips": "You do not have the permission to edit grayscale rule. Only those who have the permission to edit or release the namespace can edit grayscale rule. If you need to edit grayscale rule, please contact the project administrator to apply for the permission.",
"Component.Namespace.Branch.GrayScaleRule.AppId": "Grayscale AppId",
"Component.Namespace.Branch.GrayScaleRule.IpList": "Grayscale IP List",
"Component.Namespace.Branch.GrayScaleRule.Operator": "Operation",
"Component.Namespace.Branch.GrayScaleRule.ApplyToAllInstances": "ALL",
"Component.Namespace.Branch.GrayScaleRule.Modify": "Modify",
"Component.Namespace.Branch.GrayScaleRule.Delete": "Delete",
"Component.Namespace.Branch.GrayScaleRule.AddNewRule": "Create Rule",
"Component.Namespace.Branch.Instance.RefreshList": "Refresh List",
"Component.Namespace.Branch.Instance.ItemToSee": "View configuration",
"Component.Namespace.Branch.Instance.InstanceAppId": "App ID",
"Component.Namespace.Branch.Instance.InstanceClusterName": "Cluster Name",
"Component.Namespace.Branch.Instance.InstanceDataCenter": "Data Center",
"Component.Namespace.Branch.Instance.InstanceIp": "IP",
"Component.Namespace.Branch.Instance.InstanceGetItemTime": "Configuration Fetched Time",
"Component.Namespace.Branch.Instance.LoadMore": "Refresh list",
"Component.Namespace.Branch.Instance.NoInstance": "No instance information",
"Component.Namespace.Branch.History.ItemType": "Type",
"Component.Namespace.Branch.History.ItemKey": "Key",
"Component.Namespace.Branch.History.ItemOldValue": "Old Value",
"Component.Namespace.Branch.History.ItemNewValue": "New Value",
"Component.Namespace.Branch.History.ItemComment": "Comment",
"Component.Namespace.Branch.History.NewAdded": "Add",
"Component.Namespace.Branch.History.Modified": "Update",
"Component.Namespace.Branch.History.Deleted": "Delete",
"Component.Namespace.Branch.History.LoadMore": "Load more",
"Component.Namespace.Branch.History.NoHistory": "No Change History",
"Component.Namespace.Header.Title.Private": "Private",
"Component.Namespace.Header.Title.PrivateTips": "The configuration of private namespace ({{namespace.baseInfo.namespaceName}}) can be only fetched by clients whose AppId is {{appId}}",
"Component.Namespace.Header.Title.Public": "Public",
"Component.Namespace.Header.Title.PublicTips": "The configuration of namespace ({{namespace.baseInfo.namespaceName}}) can be fetched by any client.",
"Component.Namespace.Header.Title.Extend": "Association",
"Component.Namespace.Header.Title.ExtendTips": "The configuration of namespace ({{namespace.baseInfo.namespaceName}}) will override the configuration of the public namespace, and the combined configuration can only be fetched by clients whose AppId is {{appId}}.",
"Component.Namespace.Header.Title.ExpandAndCollapse": "[Expand/Collapse]",
"Component.Namespace.Header.Title.Master": "Main Version",
"Component.Namespace.Header.Title.Grayscale": "Grayscale Version",
"Component.Namespace.Master.LoadNamespace": "Load Namespace",
"Component.Namespace.Master.LoadNamespaceTips": "Load Namespace",
"Component.Namespace.Master.Items.Changed": "Modified",
"Component.Namespace.Master.Items.ChangedUser": "Current modifier",
"Component.Namespace.Master.Items.Publish": "Release",
"Component.Namespace.Master.Items.PublishTips": "Release configuration",
"Component.Namespace.Master.Items.Rollback": "Rollback",
"Component.Namespace.Master.Items.RollbackTips": "Rollback released configuration",
"Component.Namespace.Master.Items.PublishHistory": "Release History",
"Component.Namespace.Master.Items.PublishHistoryTips": "View the release history",
"Component.Namespace.Master.Items.Grant": "Authorize",
"Component.Namespace.Master.Items.GrantTips": "Manage the configuration edit and release permission",
"Component.Namespace.Master.Items.Grayscale": "Grayscale",
"Component.Namespace.Master.Items.GrayscaleTips": "Create a test version",
"Component.Namespace.Master.Items.RequestPermission": "Apply for configuration permission",
"Component.Namespace.Master.Items.RequestPermissionTips": "You do not have any configuration permission. Please apply.",
"Component.Namespace.Master.Items.DeleteNamespace": "Delete Namespace",
"Component.Namespace.Master.Items.NoPermissionTips": "You are not this project's administrator, nor you have edit or releas permission for the namespace. Thus you cannot view the configuration.",
"Component.Namespace.Master.Items.ItemList": "Table",
"Component.Namespace.Master.Items.ItemListByText": "Text",
"Component.Namespace.Master.Items.ItemHistory": "Change History",
"Component.Namespace.Master.Items.ItemInstance": "Instance List",
"Component.Namespace.Master.Items.CopyText": "Copy",
"Component.Namespace.Master.Items.GrammarCheck": "Syntax Check",
"Component.Namespace.Master.Items.CancelChanged": "Cancel",
"Component.Namespace.Master.Items.Change": "Modify",
"Component.Namespace.Master.Items.SummitChanged": "Submit",
"Component.Namespace.Master.Items.SortByKey": "Filter the configurations by key",
"Component.Namespace.Master.Items.FilterItem": "Filter",
"Component.Namespace.Master.Items.SyncItemTips": "Synchronize configurations among environments",
"Component.Namespace.Master.Items.SyncItem": "Synchronize",
"Component.Namespace.Master.Items.DiffItemTips": "Compare the configurations among environments",
"Component.Namespace.Master.Items.DiffItem": "Compare",
"Component.Namespace.Master.Items.AddItem": "Add Configuration",
"Component.Namespace.Master.Items.Body.ItemsNoPublishedTips": "Tips: This namespace has never been released. Apollo client will not be able to fetch the configuration and will record 404 log information. Please release it in time.",
"Component.Namespace.Master.Items.Body.FilterByKey": "Input key to filter",
"Component.Namespace.Master.Items.Body.PublishState": "Release Status",
"Component.Namespace.Master.Items.Body.Sort": "Sort",
"Component.Namespace.Master.Items.Body.ItemKey": "Key",
"Component.Namespace.Master.Items.Body.ItemValue": "Value",
"Component.Namespace.Master.Items.Body.ItemComment": "Comment",
"Component.Namespace.Master.Items.Body.ItemLastModify": "Last Modifier",
"Component.Namespace.Master.Items.Body.ItemLastModifyTime": "Last Modified Time",
"Component.Namespace.Master.Items.Body.ItemOperator": "Operation",
"Component.Namespace.Master.Items.Body.NoPublish": "Unreleased",
"Component.Namespace.Master.Items.Body.NoPublishTitle": "Click to view released values",
"Component.Namespace.Master.Items.Body.NoPublishTips": "New configuration, no released value",
"Component.Namespace.Master.Items.Body.Published": "Released",
"Component.Namespace.Master.Items.Body.PublishedTitle": "Effective configuration",
"Component.Namespace.Master.Items.Body.ClickToSee": "Click to view",
"Component.Namespace.Master.Items.Body.Grayscale": "Gray",
"Component.Namespace.Master.Items.Body.HaveGrayscale": "This configuration has grayscale configuration. Click to view the value of grayscale.",
"Component.Namespace.Master.Items.Body.NewAdded": "New",
"Component.Namespace.Master.Items.Body.NewAddedTips": "New Configuration",
"Component.Namespace.Master.Items.Body.Modified": "Modified",
"Component.Namespace.Master.Items.Body.ModifiedTips": "Modified Configuration",
"Component.Namespace.Master.Items.Body.Deleted": "Deleted",
"Component.Namespace.Master.Items.Body.DeletedTips": "Deleted Configuration",
"Component.Namespace.Master.Items.Body.ModifyTips": "Modify",
"Component.Namespace.Master.Items.Body.DeleteTips": "Delete",
"Component.Namespace.Master.Items.Body.Link.Title": "Overridden Configuration",
"Component.Namespace.Master.Items.Body.Link.NoCoverLinkItem": "No Overridden Configuration",
"Component.Namespace.Master.Items.Body.Public.Title": "Public Configuration",
"Component.Namespace.Master.Items.Body.Public.Published": "Released Configuration",
"Component.Namespace.Master.Items.Body.Public.NoPublish": "Unreleased Configuration",
"Component.Namespace.Master.Items.Body.Public.NoPublicNamespaceTips1": "Owner of the current public namespace",
"Component.Namespace.Master.Items.Body.Public.NoPublicNamespaceTips2": "hasn't associated this namespace, please contact the owner of {{namespace.parentAppId}} to associate this namespace in the {{namespace.parentAppId}} project.",
"Component.Namespace.Master.Items.Body.Public.NoPublished": "No Released Configuration",
"Component.Namespace.Master.Items.Body.Public.PublishedAndCover": "Override this configuration",
"Component.Namespace.Master.Items.Body.NoPublished.Title": "No public configuration",
"Component.Namespace.Master.Items.Body.NoPublished.PublishedValue": "Released Value",
"Component.Namespace.Master.Items.Body.NoPublished.NoPublishedValue": "Unreleased Value",
"Component.Namespace.Master.Items.Body.HistoryView.ItemType": "Type",
"Component.Namespace.Master.Items.Body.HistoryView.ItemKey": "Key",
"Component.Namespace.Master.Items.Body.HistoryView.ItemOldValue": "Old Value",
"Component.Namespace.Master.Items.Body.HistoryView.ItemNewValue": " New Value",
"Component.Namespace.Master.Items.Body.HistoryView.ItemComment": "Comment",
"Component.Namespace.Master.Items.Body.HistoryView.NewAdded": "Add",
"Component.Namespace.Master.Items.Body.HistoryView.Updated": "Update",
"Component.Namespace.Master.Items.Body.HistoryView.Deleted": "Delete",
"Component.Namespace.Master.Items.Body.HistoryView.LoadMore": "Load more",
"Component.Namespace.Master.Items.Body.HistoryView.NoHistory": "No Change History",
"Component.Namespace.Master.Items.Body.Instance.Tips": "Tips: Only show instances who have fetched configurations in the last 24 hrs ",
"Component.Namespace.Master.Items.Body.Instance.UsedNewItem": "Instances using the latest configuration",
"Component.Namespace.Master.Items.Body.Instance.NoUsedNewItem": "Instances using outdated configuration",
"Component.Namespace.Master.Items.Body.Instance.AllInstance": "All Instances",
"Component.Namespace.Master.Items.Body.Instance.RefreshList": "Refresh List",
"Component.Namespace.Master.Items.Body.Instance.ToSeeItem": "View Configuration",
"Component.Namespace.Master.Items.Body.Instance.LoadMore": "Load more",
"Component.Namespace.Master.Items.Body.Instance.ItemAppId": "App ID",
"Component.Namespace.Master.Items.Body.Instance.ItemCluster": "Cluster Name",
"Component.Namespace.Master.Items.Body.Instance.ItemDataCenter": "Data Center",
"Component.Namespace.Master.Items.Body.Instance.ItemIp": "IP",
"Component.Namespace.Master.Items.Body.Instance.ItemGetTime": "Configuration fetched time",
"Component.Namespace.Master.Items.Body.Instance.NoInstanceTips": "No Instance Information",
"Component.PublishDeny.Title": "Release Restriction",
"Component.PublishDeny.Tips1": "You can't release! The operators to edit and release the configurations in {{env}} environment must be different, please find someone else who has the release permission of this namespace to do the release operation.",
"Component.PublishDeny.Tips2": "(If it is non working time or a special situation, you may release by clicking the 'Emergency Release' button.)",
"Component.PublishDeny.EmergencyPublish": "Emergency Release",
"Component.PublishDeny.Close": "Close",
"Component.Publish.Title": "Release",
"Component.Publish.Tips": "(Only the released configurations can be fetched by clients, and this release will only be applied to the current environment: {{env}})",
"Component.Publish.Grayscale": "Grayscale Release",
"Component.Publish.GrayscaleTips": "(The grayscale configurations are only applied to the instances specified in grayscale rules)",
"Component.Publish.AllPublish": "Full Release",
"Component.Publish.AllPublishTips": "(Full release configurations are applied to all instances)",
"Component.Publish.ToSeeChange": "View changes",
"Component.Publish.PublishedValue": "Released values",
"Component.Publish.Changes": "Changes",
"Component.Publish.Key": "Key",
"Component.Publish.NoPublishedValue": "Unreleased values",
"Component.Publish.ModifyUser": "Modifier",
"Component.Publish.ModifyTime": "Modified Time",
"Component.Publish.NewAdded": "New",
"Component.Publish.NewAddedTips": "New Configuration",
"Component.Publish.Modified": "Modified",
"Component.Publish.ModifiedTips": "Modified Configuration",
"Component.Publish.Deleted": "Deleted",
"Component.Publish.DeletedTips": "Deleted Configuration",
"Component.Publish.MasterValue": "Main version value",
"Component.Publish.GrayValue": "Grayscale version value",
"Component.Publish.GrayPublishedValue": "Released grayscale version value",
"Component.Publish.GrayNoPublishedValue": "Unreleased grayscale version value",
"Component.Publish.ItemNoChange": "No configuration changes",
"Component.Publish.GrayItemNoChange": "No configuration changes",
"Component.Publish.NoGrayItems": "No grayscale changes",
"Component.Publish.Release": "Release Name",
"Component.Publish.ReleaseComment": "Comment",
"Component.Publish.OpPublish": "Release",
"Component.Rollback.To": "roll back to",
"Component.Rollback.Tips": "This operation will roll back to the last released version, and the current version is abandoned, but there is no impact to the currently editing configurations. You may view the currently effective version in the release history page",
"Component.Rollback.ClickToView": "Click to view",
"Component.Rollback.ItemType": "Type",
"Component.Rollback.ItemKey": "Key",
"Component.Rollback.RollbackBeforeValue": "Before Rollback",
"Component.Rollback.RollbackAfterValue": "After Rollback",
"Component.Rollback.Added": "Add",
"Component.Rollback.Modified": "Update",
"Component.Rollback.Deleted": "Delete",
"Component.Rollback.NoChange": "No configuration changes",
"Component.Rollback.OpRollback": "Rollback",
"Component.ShowText.Title": "View",
"Login.Login": "Login",
"Login.UserNameOrPasswordIncorrect": "Incorrect username or password",
"Login.LogoutSuccessfully": "Logout Successfully",
"Index.MyProject": "My projects",
"Index.CreateProject": "Create project",
"Index.LoadMore": "Load more",
"Index.FavoriteItems": "Favorite projects",
"Index.Topping": "Top",
"Index.FavoriteTip": "You haven't favorited any items yet. You can favorite items on the project homepage.",
"Index.RecentlyViewedItems": "Recent projects",
"Index.GetCreateAppRoleFailed": "Failed to get the information of create project permission",
"Index.Topped": "Top Successfully",
"Index.CancelledFavorite": "Remove favorite successfully",
"Cluster.CreateCluster": "Create Cluster",
"Cluster.Tips.1": "By adding clusters, the same program can use different configuration in different clusters (such as different data centers)",
"Cluster.Tips.2": "If the different clusters use the same configuration, there is no need to create clusters",
"Cluster.Tips.3": "By default, Apollo reads IDC attributes in /opt/settings/server.properties(Linux) or C:\\opt\\settings\\server.properties(Windows) files on the machine as cluster names, such as SHAJQ (Jinqiao Data Center), SHAOY (Ouyang Data Center)",
"Cluster.Tips.4": "The cluster name created here should be consistent with the IDC attribute in server.properties on the machine",
"Cluster.CreateNameTips": "(Cluster names such as SHAJQ, SHAOY or customized clusters such as SHAJQ-xx, SHAJQ-yy)",
"Cluster.ChooseEnvironment": "Environment",
"Cluster.LoadingEnvironmentError": "Error in loading environment information",
"Cluster.ClusterCreated": "Create cluster successfully",
"Cluster.ClusterCreateFailed": "Failed to create cluster",
"Cluster.PleaseChooseEnvironment": "Please select the environment",
"Config.Title": "Apollo Configuration Center",
"Config.AppIdNotFound": "doesn't exist, ",
"Config.ClickByCreate": "click to create",
"Config.EnvList": "Environments",
"Config.EnvListTips": "Manage the configuration of different environments and clusters by switching environments and clusters",
"Config.ProjectInfo": "Project Info",
"Config.ModifyBasicProjectInfo": "Modify project's basic information",
"Config.Favorite": "Favorite",
"Config.CancelFavorite": "Cancel Favorite",
"Config.MissEnv": "Missing environment",
"Config.MissNamespace": "Missing Namespace",
"Config.ProjectManage": "Manage Project",
"Config.CreateAppMissEnv": "Recover Environments",
"Config.CreateAppMissNamespace": "Recover Namespaces",
"Config.AddCluster": "Add Cluster",
"Config.AddNamespace": "Add Namespace",
"Config.CurrentlyOperatorEnv": "Current environment",
"Config.DoNotRemindAgain": "No longer prompt",
"Config.Note": "Note",
"Config.ClusterIsDefaultTipContent": "All instances that do not belong to the '{{name}}' cluster will fetch the default cluster (current page) configuration, and those that belong to the '{{name}}' cluster will use the corresponding cluster configuration!",
"Config.ClusterIsCustomTipContent": "Instances belonging to the '{{name}}' cluster will only fetch the configuration of the '{{name}}' cluster (the current page), and the default cluster configuration will only be fetched when the corresponding namespace has not been released in the current cluster.",
"Config.HasNotPublishNamespace": "The following environment/cluster has unreleased configurations, the client will not fetch the unreleased configurations, please release them in time.",
"Config.DeleteItem.DialogTitle": "Delete configuration",
"Config.DeleteItem.DialogContent": "You are deleting the configuration whose Key is <b>'{{config.key}}'</b> Value is <b>'{{config.value}}'</b>. <br> Are you sure to delete the configuration?",
"Config.PublishNoPermission.DialogTitle": "Release",
"Config.PublishNoPermission.DialogContent": "You do not have release permission. Please ask the project administrators '{{masterUsers}}' to authorize release permission.",
"Config.ModifyNoPermission.DialogTitle": "Apply for Configuration Permission",
"Config.ModifyNoPermission.DialogContent": "Please ask the project administrators '{{masterUsers}}' to authorize release or edit permission.",
"Config.MasterNoPermission.DialogTitle": "Apply for Configuration Permission",
"Config.MasterNoPermission.DialogContent": "You are not this project's administrator. Only project administrators have the permission to add clusters and namespaces. Please ask the project administrators '{{masterUsers}}' to assign administrator permission",
"Config.NamespaceLocked.DialogTitle": "Edit not allowed",
"Config.NamespaceLocked.DialogContent": "Current namespace is being edited by '{{lockOwner}}', and a release phase can only be edited by one person.",
"Config.RollbackAlert.DialogTitle": "Rollback",
"Config.RollbackAlert.DialogContent": "Are you sure to roll back?",
"Config.EmergencyPublishAlert.DialogTitle": "Emergency release",
"Config.EmergencyPublishAlert.DialogContent": "Are you sure to perform the emergency release?",
"Config.DeleteBranch.DialogTitle": "Delete grayscale",
"Config.DeleteBranch.DialogContent": "Deleting grayscale will lose the grayscale configurations. Are you sure to delete it?",
"Config.UpdateRuleTips.DialogTitle": "Update gray rule prompt",
"Config.UpdateRuleTips.DialogContent": "Grayscale rules are in effect. However there are unreleased configurations in grayscale version, they won't be effective until a manual grayscale release is performed.",
"Config.MergeAndReleaseDeny.DialogTitle": "Full release",
"Config.MergeAndReleaseDeny.DialogContent": "The main version has unreleased configuration. Please release the main version first.",
"Config.GrayReleaseWithoutRulesTips.DialogTitle": "Missing gray rule prompt",
"Config.GrayReleaseWithoutRulesTips.DialogContent": "The grayscale version has not configured any grayscale rule. Please configure the grayscale rules.",
"Config.DeleteNamespaceDenyForMasterInstance.DialogTitle": "Delete namespace warning",
"Config.DeleteNamespaceDenyForMasterInstance.DialogContent": "There are <b>'{{deleteNamespaceContext.namespace.instancesCount}}'</b> instances using namespace ('{{deleteNamespaceContext.namespace.baseInfo.namespaceName}}'), and deleting namespace would cause those instances failed to fetch configuration. <br> Please go to <ins> \"Instance List\"</ins> to confirm the instance information. If you confirm that the relevant instances are no longer using the namespace configuration, you can contact the Apollo administrators to delete the instance information (Instance Config) or wait for the instance to expire automatically 24 hours before deletion.",
"Config.DeleteNamespaceDenyForBranchInstance.DialogTitle": "Delete namespace warning information",
"Config.DeleteNamespaceDenyForBranchInstance.DialogContent": "There are <b>'{{deleteNamespaceContext.namespace.branch.latestReleaseInstances.total}}'</b> instances using the graysacle version of namespace ('{{deleteNamespaceContext.namespace.baseInfo.namespaceName}}') configuration, and deleting Namespace would cause those instances failed to fetch configuration. <br> Please go to <ins> \"Grayscale Version\"=> \"Instance List\"</ins> to confirm the instance information. If you confirm the relevant instances are no longer using the namespace configuration, you can contact the Apollo administrators to delete the instance information (Instance Config) or wait for the instance to expire automatically 24 hours before deletion.",
"Config.DeleteNamespaceDenyForPublicNamespace.DialogTitle": "Delete Namespace Failure Tip",
"Config.DeleteNamespaceDenyForPublicNamespace.DialogContent": "Delete Namespace Failure Tip",
"Config.DeleteNamespaceDenyForPublicNamespace.PleaseEnterAppId": "Please enter appId",
"Config.SyntaxCheckFailed.DialogTitle": "Syntax Check Error",
"Config.SyntaxCheckFailed.DialogContent": "Delete Namespace Failure Tip",
"Config.CreateBranchTips.DialogTitle": "Create Grayscale Notice",
"Config.CreateBranchTips.DialogContent": "By creating grayscale version, you can do grayscale test for some configurations. <br> Grayscale process is as follows: <br> &nbsp; &nbsp; 1. Create grayscale version <br> &nbsp; &nbsp; 2. Configure grayscale configuration items <br> &nbsp; &nbsp; 3. Configure grayscale rules. If it is a private namespace, it can be grayed according to the IP of client. If it is a public namespace, it can be grayed accodring to both appid and the IP. <br> &nbsp; &nbsp; 4. Grayscale release <br> Grayscale version has two final results: <b> Full release and Abandon grayscale</b> <br> <b>Full release</b>: grayscale configurations are merged with the main version and released, all clients will use the merged configurations <br> <b> Abandon grayscale</b>: Delete grayscale version. All clients will use the configurations of the main version<br> Notice: <br> &nbsp; &nbsp; 1. If the grayscale version has been released, then the grayscale rules will be effective immediately without the need to release grayscale configuration again.",
"Config.ProjectMissEnvInfos": "There are missing environments in the current project, please click \"Recover Environments\" on the left side of the page to do the recovery.",
"Config.ProjectMissNamespaceInfos": "There are missing namespaces in the current environment. Please click \"Recover Namespaces\" on the left side of the page to do the recovery.",
"Config.SystemError": "System error, please try again or contact the system administrator",
"Config.FavoriteSuccessfully": "Favorite Successfully",
"Config.FavoriteFailed": "Failed to favorite",
"Config.CancelledFavorite": "Cancel favorite successfully",
"Config.CancelFavoriteFailed": "Failed to cancel the favorite",
"Config.GetUserInfoFailed": "Failed to obtain user login information",
"Config.LoadingAllNamespaceError": "Failed to load configuration",
"Config.CancelFavoriteError": "Failure to Cancel Collection",
"Config.Deleted": "Delete Successfully",
"Config.DeleteFailed": "Failed to delete",
"Config.GrayscaleCreated": "Create Grayscale Successfully",
"Config.GrayscaleCreateFailed": "Failed to create grayscale",
"Config.BranchDeleted": "Delete branch successfully",
"Config.BranchDeleteFailed": "Failed to delete branch",
"Config.DeleteNamespaceFailedTips": "The following projects are associated with this public namespace and they must all be deleted deleting the public Namespace",
"Config.DeleteNamespaceNoPermissionFailedTitle": "Failed to delete",
"Config.DeleteNamespaceNoPermissionFailedTips": "You do not have Project Administrator permission. Only Administrators can delete namespace. Please ask Project Administrators [{{usres}}] to delete namespace.",
"Delete.Title": "Delete applications, clusters, AppNamespace",
"Delete.DeleteApp": "Delete application",
"Delete.DeleteAppTips": "(Because deleting applications has very large impacts, only system administrators are allowed to delete them for the time being. Make sure that no client fetches the configuration of the application before deleting it.)",
"Delete.AppIdTips": "(Please query application information before deleting)",
"Delete.AppInfo": "Application information",
"Delete.DeleteCluster": "Delete clusters",
"Delete.DeleteClusterTips": "(Because deleting clusters has very large impacts, only system administrators are allowed to delete them for the time being. Make sure that no client fetches the configuration of the cluster before deleting it.)",
"Delete.EnvName": "Environment Name",
"Delete.ClusterNameTips": "(Please query cluster information before deletion)",
"Delete.ClusterInfo": "Cluster information",
"Delete.DeleteNamespace": "Delete AppNamespace",
"Delete.DeleteNamespaceTips": "(Note that Namespace and AppNamespace in all environments will be deleted! If you just want to delete the namespace of some environment, let the user delete it on the project page!",
"Delete.DeleteNamespaceTips2": "Currently users can delete the associated namespace and private namespace by themselves, but they can not delete the AppNamespace. Because deleting AppNamespace has very large impacts, it is only allowed to be deleted by system administrators for the time being. For public Namespace, it is necessary to ensure that no application associates the AppNamespace",
"Delete.AppNamespaceName": "AppNamespace name",
"Delete.AppNamespaceNameTips": "(For non-properties namespaces, please add the suffix, such as apollo.xml)",
"Delete.AppNamespaceInfo": "AppNamespace Information",
"Delete.IsRootUserTips": "The current page is only accessible to Apollo administrators",
"Delete.PleaseEnterAppId": "Please enter appId",
"Delete.AppIdNotFound": "AppId: '{{appId}}' does not exist!",
"Delete.AppInfoContent": "Application name: '{{appName}}' department: '{{departmentName}}({{departmentId}})' owner: '{{ownerName}}'",
"Delete.ConfirmDeleteAppId": "Are you sure to delete AppId: '{{appId}}'?",
"Delete.Deleted": "Delete Successfully",
"Delete.PleaseEnterAppIdAndEnvAndCluster": "Please enter appId, environment, and cluster name",
"Delete.ClusterInfoContent": "AppId: '{{appId}}' environment: '{{env}}' cluster name: '{{clusterName}}'",
"Delete.ConfirmDeleteCluster": "Are you sure to delete the cluster? AppId: '{{appId}}' environment: '{{env}}' cluster name:'{{clusterName}}'",
"Delete.PleaseEnterAppIdAndNamespace": "Please enter appId and AppNamespace names",
"Delete.AppNamespaceInfoContent": "AppId: '{{appId}}' AppNamespace name: '{{namespace}}' isPublic: '{{isPublic}}'",
"Delete.ConfirmDeleteNamespace": "Are you sure to delete AppNamespace and Namespace for all environments? AppId: '{{appId}}' environment: 'All environments' AppNamespace name: '{{namespace}}'",
"Namespace.Title": "New Namespace",
"Namespace.UnderstandMore": "(Click to learn more about Namespace)",
"Namespace.Link.Tips1": "Applications can override the configuration of a public namespace by associating a public namespace",
"Namespace.Link.Tips2": "If the application does not need to override the configuration of the public namespace, then there is no need to associate the public namespace",
"Namespace.CreatePublic.Tips1": "The configuration of the public Namespace can be fetched by any application",
"Namespace.CreatePublic.Tips2": "Configuration of public components or the need for multiple applications to share the same configuration can be achieved by creating a public namespace.",
"Namespace.CreatePublic.Tips3": "If other applications need to override the configuration of the public namespace, you can associate the public namespace in other applications, and then configure the configuration that needs to be overridden in the associated namespace.",
"Namespace.CreatePublic.Tips4": "If other applications do not need to override the configuration of public namespace, then there is no need to associate public namespace in other applications.",
"Namespace.CreatePrivate.Tips1": "The configuration of a private Namespace can only be fetched by the application to which it belongs.",
"Namespace.CreatePrivate.Tips2": "Group management configuration can be achieved by creating a private namespace",
"Namespace.CreatePrivate.Tips3": "The format of private namespaces can be xml, yml, yaml, json, txt. You can get the content of namespace in non-property format through the ConfigFile interface in apollo-client.",
"Namespace.CreatePrivate.Tips4": "The 1.3.0 and above versions of apollo-client provide better support for yaml/yml. Config objects can be obtained directly through ConfigService.getConfig(\"someNamespace.yml\"), or through @EnableApolloConfig(\"someNamespace.yml\") or apollo.bootstrap.namespaces=someNamespace.yml to inject YML configuration into Spring/Spring Boot",
"Namespace.CreateNamespace": "Create Namespace",
"Namespace.AssociationPublicNamespace": "Associate Public Namespace",
"Namespace.ChooseCluster": "Select Cluster",
"Namespace.NamespaceName": "Name",
"Namespace.AutoAddDepartmentPrefix": "Add department prefix",
"Namespace.AutoAddDepartmentPrefixTips": "(The name of a public namespace needs to be globally unique, and adding a department prefix helps ensure global uniqueness)",
"Namespace.NamespaceType": "Type",
"Namespace.NamespaceType.Public": "Public",
"Namespace.NamespaceType.Private": "Private",
"Namespace.Remark": "Remarks",
"Namespace.Namespace": "Namespace",
"Namespace.PleaseChooseNamespace": "Please select namespace",
"Namespace.LoadingPublicNamespaceError": "Failed to load public namespace",
"Namespace.LoadingAppInfoError": "Failed to load App information",
"Namespace.PleaseChooseCluster": "Select Cluster",
"Namespace.CheckNamespaceNameLengthTip": "The namespace name should not be longer than 32 characters. Department prefix:'{{departmentLength}}' characters, name {{namespaceLength}} characters",
"ServiceConfig.Title": "System Configuration",
"ServiceConfig.Tips": "(Maintain Apollo PortalDB.ServerConfig table data, will override configuration items if they already exist, or create configuration items. Configuration updates take effect automatically in a minute)",
"ServiceConfig.Key": "Key",
"ServiceConfig.KeyTips": "(Please query the configuration information before modifying the configuration)",
"ServiceConfig.Value": "Value",
"ServiceConfig.Comment": "Comment",
"ServiceConfig.Saved": "Save Successfully",
"ServiceConfig.SaveFailed": "Failed to Save",
"ServiceConfig.PleaseEnterKey": "Please enter key",
"ServiceConfig.KeyNotExistsAndCreateTip": "Key: '{{key}}' does not exist. Click Save to create the configuration item.",
"ServiceConfig.KeyExistsAndSaveTip": "Key: '{{key}}' already exists. Click Save will override the configuration item.",
"SystemInfo.Title": "System Information",
"SystemInfo.SystemVersion": "System version",
"SystemInfo.Tips1": "The environment list comes from the <strong>apollo.portal.envs</strong> configuration in Apollo PortalDB.ServerConfig, and can be configured in <a href=\"{{serverConfigUrl}}\">System Configuration</a> page. For more information, please refer the <strong>apollo.portal.envs - supportable environment list</strong> section in <a href=\"{{wikiUrl}}\">Distributed Deployment Guide</a>.",
"SystemInfo.Tips2": "The meta server address shows the meta server information for this environment configuration. For more information, please refer the <strong>Configuring meta service information for apollo-portal</strong> section in <a href=\"{{wikiUrl}}\">Distributed Deployment Guide</a>.",
"SystemInfo.Active": "Active",
"SystemInfo.ActiveTips": "(Current environment status is abnormal, please diagnose with the system information below and Check Health results of AdminService)",
"SystemInfo.MetaServerAddress": "Meta server address",
"SystemInfo.ConfigServices": "Config Services",
"SystemInfo.ConfigServices.Name": "Name",
"SystemInfo.ConfigServices.InstanceId": "Instance Id",
"SystemInfo.ConfigServices.HomePageUrl": "Home Page Url",
"SystemInfo.ConfigServices.CheckHealth": "Check Health",
"SystemInfo.NoConfigServiceTips": "No config service found!",
"SystemInfo.Check": "Check",
"SystemInfo.AdminServices": "Admin Services",
"SystemInfo.AdminServices.Name": "Name",
"SystemInfo.AdminServices.InstanceId": "Instance Id",
"SystemInfo.AdminServices.HomePageUrl": "Home Page Url",
"SystemInfo.AdminServices.CheckHealth": "Check Health",
"SystemInfo.NoAdminServiceTips": "No admin service found!",
"SystemInfo.IsRootUser": "The current page is only accessible to Apollo administrators",
"SystemRole.Title": "System Permission Management",
"SystemRole.AddCreateAppRoleToUser": "Create application permission for users",
"SystemRole.AddCreateAppRoleToUserTips": "(When role.create-application.enabled=true is set in system configurations, only super admin and those accounts with Create application permission can create application)",
"SystemRole.ChooseUser": "Select User",
"SystemRole.Add": "Add",
"SystemRole.AuthorizedUser": "Users with permission",
"SystemRole.ModifyAppAdminUser": "Modify Application Administrator Allocation Permissions",
"SystemRole.ModifyAppAdminUserTips": "(When role.manage-app-master.enabled=true is set in system configurations, only super admin and those accounts with application administrator allocation permissions can modify the application's administrators)",
"SystemRole.AppIdTips": "(Please query the application information first)",
"SystemRole.AppInfo": "Application information",
"SystemRole.AllowAppMasterAssignRole": "Allow this user to add Master as an administrator",
"SystemRole.DeleteAppMasterAssignRole": "Disallow this user to add Master as an administrator",
"SystemRole.IsRootUser": "The current page is only accessible to Apollo administrators",
"SystemRole.PleaseChooseUser": "Please select a user",
"SystemRole.Added": "Add Successfully",
"SystemRole.AddFailed": "Failed to add",
"SystemRole.Deleted": "Delete Successfully",
"SystemRole.DeleteFailed": "Failed to Delete",
"SystemRole.GetCanCreateProjectUsersError": "Error getting user list with create project permission",
"SystemRole.PleaseEnterAppId": "Please enter appId",
"SystemRole.AppIdNotFound": "AppId: '{{appId}}' does not exist!",
"SystemRole.AppInfoContent": "Application name: '{{appName}}' department: '{{departmentName}}({{departmentId}})' owner: '{{ownerName}}'",
"SystemRole.DeleteMasterAssignRoleTips": "Are you sure to disallow the user '{{userId}}' to add Master as an administrator for AppId:'{{appId}}'?",
"SystemRole.DeletedMasterAssignRoleTips": "Disallow the user '{{userId}}' to add Master as an administrator for AppId:'{{appId}}' Successfully",
"SystemRole.AllowAppMasterAssignRoleTips": "Are you sure to allow the user '{{userId}}' to add Master as an administrator for AppId:'{{appId}}'?",
"SystemRole.AllowedAppMasterAssignRoleTips": "Allow the user '{{userId}}' to add Master as an administrator for AppId:'{{appId}}' Successfully",
"UserMange.Title": "User Management",
"UserMange.TitleTips": "(Only valid for the default Spring Security simple authentication method: - Dapollo_profile = github,auth)",
"UserMange.UserName": "User Name",
"UserMange.UserNameTips": "If the user name entered does not exist, will create a new one. If it already exists, then it will be updated.",
"UserMange.Pwd": "Password",
"UserMange.Email": "Email",
"UserMange.Created": "Create user successfully",
"UserMange.CreateFailed": "Failed to create user",
"Open.Manage.Title": "Open Platform",
"Open.Manage.CreateThirdApp": "Create third-party applications",
"Open.Manage.CreateThirdAppTips": "(Note: Third-party applications can manage configuration through Apollo Open Platform)",
"Open.Manage.ThirdAppId": "Third party appId",
"Open.Manage.ThirdAppIdTips": "(Please check if the third-party application has already exists first)",
"Open.Manage.ThirdAppName": "Third party application name",
"Open.Manage.ThirdAppNameTips": "(Suggested format xx-yy-zz e.g. apollo-server)",
"Open.Manage.ProjectOwner": "Owner",
"Open.Manage.Create": "Create",
"Open.Manage.GrantPermission": "Authorization",
"Open.Manage.GrantPermissionTips": "(Namespace level permissions include edit and release namespace. Application level permissions include creating namespace, edit or release any namespace in the application.)",
"Open.Manage.Token": "Token",
"Open.Manage.ManagedAppId": "Managed AppId",
"Open.Manage.ManagedNamespace": "Managed Namespace",
"Open.Manage.ManagedNamespaceTips": "(For non-properties namespaces, please add the suffix, such as apollo.xml)",
"Open.Manage.GrantType": "Authorization type",
"Open.Manage.GrantType.Namespace": "Namespace",
"Open.Manage.GrantType.App": "App",
"Open.Manage.GrantEnv": "Environments",
"Open.Manage.GrantEnvTips": "(If you don't select any environment, then will have permissions to all environments.)",
"Open.Manage.PleaseEnterAppId": "Please enter appId",
"Open.Manage.AppNotCreated": "App('{{appId}}') does not exist, please create it first",
"Open.Manage.GrantSuccessfully": "Authorize Successfully",
"Open.Manage.GrantFailed": "Failed to authorize",
"Namespace.Role.Title": "Permission Management",
"Namespace.Role.GrantModifyTo": "Permission to edit",
"Namespace.Role.GrantModifyTo2": "(Can edit the configuration)",
"Namespace.Role.AllEnv": "All environments",
"Namespace.Role.GrantPublishTo": "Permission to release",
"Namespace.Role.GrantPublishTo2": "(Can release the configuration)",
"Namespace.Role.Add": "Add",
"Namespace.Role.NoPermission": "You do not have permission!",
"Namespace.Role.InitNamespacePermissionError": "Error initializing authorization",
"Namespace.Role.GetEnvGrantUserError": "Failed to load authorized users for '{{env}}'",
"Namespace.Role.GetGrantUserError": "Failed to load authorized users",
"Namespace.Role.PleaseChooseUser": "Please select the user",
"Namespace.Role.Added": "Add Successfully",
"Namespace.Role.AddFailed": "Failed to add",
"Namespace.Role.Deleted": "Delete Successfully",
"Namespace.Role.DeleteFailed": "Failed to Delete",
"Config.Sync.Title": "Synchronize Configuration",
"Config.Sync.FistStep": "(Step 1: Select Synchronization Information)",
"Config.Sync.SecondStep": "(Step 2: Check Diff)",
"Config.Sync.PreviousStep": "Previous step",
"Config.Sync.NextStep": "Next step",
"Config.Sync.Sync": "Synchronize",
"Config.Sync.Tips": "Tips",
"Config.Sync.Tips1": "Configurations between multiple environments and clusters can be maintained by synchronize configuration",
"Config.Sync.Tips2": "It should be noted that the configurations will not take effect until they are released after synchronization.",
"Config.Sync.SyncNamespace": "Synchronized Namespace",
"Config.Sync.SyncToCluster": "Synchronize to which cluster",
"Config.Sync.NeedToSyncItem": "Configuration to synchronize",
"Config.Sync.SortByLastModifyTime": "Filter by last update time",
"Config.Sync.BeginTime": "Start time",
"Config.Sync.EndTime": "End time",
"Config.Sync.Filter": "Filter",
"Config.Sync.Rest": "Reset",
"Config.Sync.ItemKey": "Key",
"Config.Sync.ItemValue": "Value",
"Config.Sync.ItemCreateTime": "Create Time",
"Config.Sync.ItemUpdateTime": "Update Time",
"Config.Sync.NoNeedSyncItem": "No updated configuration",
"Config.Sync.IgnoreSync": "Ignore synchronization",
"Config.Sync.Step2Type": "Type",
"Config.Sync.Step2Key": "Key",
"Config.Sync.Step2SyncBefore": "Before Sync",
"Config.Sync.Step2SyncAfter": "After Sync",
"Config.Sync.Step2Comment": "Comment",
"Config.Sync.Step2Operator": "Operation",
"Config.Sync.NewAdd": "Add",
"Config.Sync.NoSyncItem": "Do not synchronize the configuration",
"Config.Sync.Delete": "Delete",
"Config.Sync.Update": "Update",
"Config.Sync.SyncSuccessfully": "Synchronize Successfully!",
"Config.Sync.SyncFailed": "Failed to Synchronize!",
"Config.Sync.LoadingItemsError": "Error loading configuration",
"Config.Sync.PleaseChooseNeedSyncItems": "Please select the configuration that needs synchronization",
"Config.Sync.PleaseChooseCluster": "Select Cluster",
"Config.History.Title": "Release History",
"Config.History.MasterVersionPublish": "Main version release",
"Config.History.MasterVersionRollback": "Main version rollback",
"Config.History.GrayscaleOperator": "Grayscale operation",
"Config.History.PublishHistory": "Release History",
"Config.History.OperationType0": "Normal release",
"Config.History.OperationType1": "Rollback",
"Config.History.OperationType2": "Grayscale Release",
"Config.History.OperationType3": "Update Gray Rules",
"Config.History.OperationType4": "Full Grayscale Release",
"Config.History.OperationType5": "Grayscale Release(Main Version Release)",
"Config.History.OperationType6": "Grayscale Release(Main Version Rollback)",
"Config.History.OperationType7": "Abandon Grayscale",
"Config.History.OperationType8": "Delete Grayscale(Full Release)",
"Config.History.UrgentPublish": "Emergency Release",
"Config.History.LoadMore": "Load more",
"Config.History.ChangedItem": "Changed Configuration",
"Config.History.ChangedItemTips": "View changes between this release and the previous release",
"Config.History.AllItem": "Full Configuration",
"Config.History.AllItemTips": "View all configurations for this release",
"Config.History.ChangeType": "Type",
"Config.History.ChangeKey": "Key",
"Config.History.ChangeValue": "Value",
"Config.History.ChangeOldValue": "Old Value",
"Config.History.ChangeNewValue": "New Value",
"Config.History.ChangeTypeNew": "Add",
"Config.History.ChangeTypeModify": "Update",
"Config.History.ChangeTypeDelete": "Delete",
"Config.History.NoChange": "No configuration changes",
"Config.History.NoItem": "No configuration",
"Config.History.GrayscaleRule": "Grayscale Rule",
"Config.History.GrayscaleAppId": "Grayscale AppId",
"Config.History.GrayscaleIp": "Grayscale IP",
"Config.History.NoGrayscaleRule": "No Grayscale Rule",
"Config.History.NoPermissionTips": "You are not this project's administrator, nor you have edit or release permission for the namespace. Thus you cannot view the release history.",
"Config.History.NoPublishHistory": "No release history",
"Config.History.LoadingHistoryError": "No release history",
"Config.Diff.Title": "Compare Configuration",
"Config.Diff.FirstStep": "(Step 1: Select what to compare)",
"Config.Diff.SecondStep": "(Step 2: View the differences)",
"Config.Diff.PreviousStep": "Previous step",
"Config.Diff.NextStep": "Next step",
"Config.Diff.TipsTitle": "Tips",
"Config.Diff.Tips": "By comparing configuration, you can see configuration differences between multiple environments and clusters",
"Config.Diff.DiffCluster": "Clusters to be compared",
"Config.Diff.HasDiffComment": "Whether to compare comments or not",
"Config.Diff.PleaseChooseTwoCluster": "Please select at least two clusters",
"App.CreateProject": "Create Project",
"App.AppIdTips": "(Application's unique identifiers)",
"App.AppNameTips": "(Suggested format xx-yy-zz e.g. apollo-server)",
"App.AppOwnerTips": "(After enabling the application administrator allocation restrictions, the application owner and project administrator are default to current account, not subject to change)",
"App.AppAdminTips1": "(The application owner has project administrator permission by default.",
"App.AppAdminTips2": "Project administrators can create namespace, cluster, and assign user permissions)",
"App.Setting.Title": "Manage Project",
"App.Setting.Admin": "Administrators",
"App.Setting.AdminTips": "(Project administrators have the following permissions: 1. Create namespace 2. Create clusters 3. Manage project and namespace permissions)",
"App.Setting.Add": "Add",
"App.Setting.BasicInfo": "Basic information",
"App.Setting.ProjectName": "App Name",
"App.Setting.ProjectNameTips": "(Suggested format xx-yy-zz e.g. apollo-server)",
"App.Setting.ProjectOwner": "Owner",
"App.Setting.Modify": "Modify project information",
"App.Setting.Cancel": "Cancel",
"App.Setting.NoPermissionTips": "You do not have permission to operate, please ask [{{users}}] to authorize",
"App.Setting.DeleteAdmin": "Delete Administrator",
"App.Setting.CanNotDeleteAllAdmin": "Cannot delete all administrators",
"App.Setting.PleaseChooseUser": "Please select a user",
"App.Setting.Added": "Add Successfully",
"App.Setting.AddFailed": "Failed to Add",
"App.Setting.Deleted": "Delete Successfully",
"App.Setting.DeleteFailed": "Failed to Delete",
"App.Setting.Modified": "Update Successfully",
"Valdr.App.AppId.Size": "AppId cannot be longer than 32 characters",
"Valdr.App.AppId.Required": "AppId cannot be empty",
"Valdr.App.appName.Size": "The app name cannot be longer than 128 characters",
"Valdr.App.appName.Required": "App name cannot be empty",
"Valdr.Cluster.ClusterName.Size": "Cluster names cannot be longer than 32 characters",
"Valdr.Cluster.ClusterName.Required": "Cluster name cannot be empty",
"Valdr.AppNamespace.NamespaceName.Size": "Namespace name cannot be longer than 32 characters",
"Valdr.AppNamespace.NamespaceName.Required": "Namespace name cannot be empty",
"Valdr.AppNamespace.Comment.Size": "Comment length should not exceed 64 characters",
"Valdr.Item.Key.Size": "Key cannot be longer than 128 characters",
"Valdr.Item.Key.Required": "Key can't be empty",
"Valdr.Item.Comment.Size": "Comment length should not exceed 64 characters",
"Valdr.Release.ReleaseName.Size": "Release Name cannot be longer than 64 characters",
"Valdr.Release.ReleaseName.Required": "Release Name cannot be empty",
"Valdr.Release.Comment.Size": "Comment length should not exceed 64 characters",
"ApolloConfirmDialog.DefaultConfirmBtnName": "OK",
"ApolloConfirmDialog.SearchPlaceHolder": "Search items (App Id, App Name)",
"RulesModal.ChooseInstances": "Select from the list of instances",
"RulesModal.InvalidIp": "Illegal IP Address: '{{ip}}'",
"RulesModal.GrayscaleAppIdCanNotBeNull": "Grayscale AppId cannot be empty",
"RulesModal.AppIdExistsRule": "Rules already exist for AppId='{{appId}}'",
"RulesModal.IpListCanNotBeNull": "IP list cannot be empty",
"ItemModal.KeyExists": "Key='{{key}}' already exists",
"ItemModal.AddedTips": "Add Successfully. need to release configuration to take effect",
"ItemModal.AddFailed": "Failed to Add",
"ItemModal.PleaseChooseCluster": "Please Select Cluster",
"ItemModal.ModifiedTips": "Update Successfully. need to release configuration to take effect",
"ItemModal.ModifyFailed": "Failed to Update",
"ItemModal.Tabs": "Tab character",
"ItemModal.NewLine": "Newline character",
"ItemModal.Space": "Blank space",
"ApolloNsPanel.LoadingHistoryError": "Failed to load change history",
"ApolloNsPanel.LoadingGrayscaleError": "Failed to load change history",
"ApolloNsPanel.Deleted": "Delete Successfully",
"ApolloNsPanel.GrayscaleModified": "Update grayscale rules successfully",
"ApolloNsPanel.GrayscaleModifyFailed": "Failed to update grayscale rules",
"ApolloNsPanel.ModifiedTips": "Update Successfully. need to release configuration to take effect",
"ApolloNsPanel.ModifyFailed": "Failed to Update",
"ApolloNsPanel.GrammarIsright": "Syntax is correct",
"ReleaseModal.Published": "Release Successfully",
"ReleaseModal.PublishFailed": "Failed to Release",
"ReleaseModal.GrayscalePublished": "Grayscale Release Successfully",
"ReleaseModal.GrayscalePublishFailed": "Failed to Grayscale Release",
"ReleaseModal.AllPublished": "Full Release Successfully",
"ReleaseModal.AllPublishFailed": "Failed to Full Release",
"Rollback.NoRollbackList": "No released history to rollback",
"Rollback.RollbackSuccessfully": "Rollback Successfully",
"Rollback.RollbackFailed": "Failed to Rollback"
}
\ No newline at end of file
{
"Common.Title": "Apollo配置中心",
"Common.Ctrip": "携程",
"Common.CtripDepartment": "框架研发部",
"Common.Nav.ShowNavBar": "显示导航栏",
"Common.Nav.HideNavBar": "隐藏导航栏",
"Common.Nav.Help": "帮助",
"Common.Nav.AdminTools": "管理员工具",
"Common.Nav.UserManage": "用户管理",
"Common.Nav.SystemRoleManage": "系统权限管理",
"Common.Nav.OpenMange": "开放平台授权管理",
"Common.Nav.SystemConfig": "系统参数",
"Common.Nav.DeleteApp-Cluster-Namespace": "删除应用、集群、AppNamespace",
"Common.Nav.SystemInfo": "系统信息",
"Common.Nav.Logout": "退出",
"Common.Department": "部门",
"Common.Cluster": "集群",
"Common.Environment": "环境",
"Common.Email": "邮箱",
"Common.AppId": "AppId",
"Common.Namespace": "Namespace",
"Common.AppName": "应用名称",
"Common.AppOwner": "负责人",
"Common.AppOwnerLong": "应用负责人",
"Common.AppAdmin": "项目管理员",
"Common.ClusterName": "集群名称",
"Common.Submit": "提交",
"Common.Save": "保存",
"Common.Created": "创建成功",
"Common.CreateFailed": "创建失败",
"Common.Deleted": "删除成功",
"Common.DeleteFailed": "删除失败",
"Common.ReturnToIndex": "返回到项目首页",
"Common.Cancel": "取消",
"Common.Ok": "确定",
"Common.Search": "查询",
"Common.IsRootUser": "当前页面只对Apollo管理员开放",
"Common.PleaseChooseDepartment": "请选择部门",
"Common.PleaseChooseOwner": "请选择应用负责人",
"Common.LoginExpiredTips": "您的登录信息已过期,请刷新页面后重试",
"Component.DeleteNamespace.Title": "删除Namespace",
"Component.DeleteNamespace.PublicContent": "删除Namespace将导致实例获取不到此Namespace的配置,确定要删除吗?",
"Component.DeleteNamespace.PrivateContent": "删除私有Namespace将导致实例获取不到此Namespace的配置,且页面会提示缺失Namespace(除非使用管理员工具删除AppNamespace),确定要删除吗?",
"Component.GrayscalePublishRule.Title": "编辑灰度规则",
"Component.GrayscalePublishRule.AppId": "灰度的AppId",
"Component.GrayscalePublishRule.AcceptRule": "灰度应用规则",
"Component.GrayscalePublishRule.AcceptPartInstance": "应用到部分实例",
"Component.GrayscalePublishRule.AcceptAllInstance": "应用到所有的实例",
"Component.GrayscalePublishRule.IP": "灰度的IP",
"Component.GrayscalePublishRule.AppIdFilterTips": "(实例列表会根据输入的AppId自动过滤)",
"Component.GrayscalePublishRule.IpTips": "没找到你想要的IP?可以",
"Component.GrayscalePublishRule.EnterIp": "手动输入IP",
"Component.GrayscalePublishRule.EnterIpTips": "输入IP列表,英文逗号隔开,输入完后点击添加按钮",
"Component.GrayscalePublishRule.Add": "添加",
"Component.ConfigItem.Title": "添加配置项",
"Component.ConfigItem.TitleTips": "(温馨提示: 可以通过文本模式批量添加配置)",
"Component.ConfigItem.AddGrayscaleItem": "添加灰度配置项",
"Component.ConfigItem.ModifyItem": "修改配置项",
"Component.ConfigItem.ItemKey": "Key",
"Component.ConfigItem.ItemValue": "Value",
"Component.ConfigItem.ItemValueTips": "注意: 隐藏字符(空格、换行符、制表符Tab)容易导致配置出错,如果需要检测Value中隐藏字符,请点击",
"Component.ConfigItem.ItemValueShowDetection": "检测隐藏字符",
"Component.ConfigItem.ItemValueNotHiddenChars": "无隐藏字符",
"Component.ConfigItem.ItemComment": "Comment",
"Component.ConfigItem.ChooseCluster": "选择集群",
"Component.MergePublish.Title": "全量发布",
"Component.MergePublish.Tips": "全量发布将会把灰度版本的配置合并到主分支,并发布。",
"Component.MergePublish.NextStep": "全量发布后,您希望",
"Component.MergePublish.DeleteGrayscale": "删除灰度版本",
"Component.MergePublish.ReservedGrayscale": "保留灰度版本",
"Component.Namespace.Branch.IsChanged": "有修改",
"Component.Namespace.Branch.ChangeUser": "当前修改者",
"Component.Namespace.Branch.ContinueGrayscalePublish": "继续灰度发布",
"Component.Namespace.Branch.GrayscalePublish": "灰度发布",
"Component.Namespace.Branch.MergeToMasterAndPublish": "合并到主版本并发布主版本配置",
"Component.Namespace.Branch.AllPublish": "全量发布",
"Component.Namespace.Branch.DiscardGrayscaleVesion": "废弃灰度版本",
"Component.Namespace.Branch.DiscardGrayscale": "放弃灰度",
"Component.Namespace.Branch.NoPermissionTips": "您不是该项目的管理员,也没有该Namespace的编辑或发布权限,无法查看配置信息。",
"Component.Namespace.Branch.Tab.Configuration": "配置",
"Component.Namespace.Branch.Tab.GrayscaleRule": "灰度规则",
"Component.Namespace.Branch.Tab.GrayscaleInstance": "灰度实例列表",
"Component.Namespace.Branch.Tab.ChangeHistory": "更改历史",
"Component.Namespace.Branch.Body.Item": "灰度的配置",
"Component.Namespace.Branch.Body.AddedItem": "新增灰度配置",
"Component.Namespace.Branch.Body.PublishState": "发布状态",
"Component.Namespace.Branch.Body.ItemSort": "排序",
"Component.Namespace.Branch.Body.ItemKey": "Key",
"Component.Namespace.Branch.Body.ItemMasterValue": "主版本的值",
"Component.Namespace.Branch.Body.ItemGrayscaleValue": "灰度的值",
"Component.Namespace.Branch.Body.ItemComment": "备注",
"Component.Namespace.Branch.Body.ItemLastModify": "最后修改人",
"Component.Namespace.Branch.Body.ItemLastModifyTime": "最后修改时间",
"Component.Namespace.Branch.Body.ItemOperator": "操作",
"Component.Namespace.Branch.Body.ClickToSeeItemValue": "点击查看已发布的值",
"Component.Namespace.Branch.Body.ItemNoPublish": "未发布",
"Component.Namespace.Branch.Body.ItemPublished": "已发布",
"Component.Namespace.Branch.Body.ItemEffective": "已生效的配置",
"Component.Namespace.Branch.Body.ClickToSee": "点击查看",
"Component.Namespace.Branch.Body.DeletedItem": "删除的配置",
"Component.Namespace.Branch.Body.Delete": "删",
"Component.Namespace.Branch.Body.ChangedFromMaster": "修改主版本的配置",
"Component.Namespace.Branch.Body.ModifiedItem": "修改的配置",
"Component.Namespace.Branch.Body.Modify": "改",
"Component.Namespace.Branch.Body.AddedByGrayscale": "灰度版本特有的配置",
"Component.Namespace.Branch.Body.Added": "新",
"Component.Namespace.Branch.Body.Op.Modify": "修改",
"Component.Namespace.Branch.Body.Op.Delete": "删除",
"Component.Namespace.MasterBranch.Body.Title": "主版本的配置",
"Component.Namespace.MasterBranch.Body.PublishState": "发布状态",
"Component.Namespace.MasterBranch.Body.ItemKey": "Key",
"Component.Namespace.MasterBranch.Body.ItemValue": "Value",
"Component.Namespace.MasterBranch.Body.ItemComment": "备注",
"Component.Namespace.MasterBranch.Body.ItemLastModify": "最后修改人",
"Component.Namespace.MasterBranch.Body.ItemLastModifyTime": "最后修改时间",
"Component.Namespace.MasterBranch.Body.ItemOperator": "操作",
"Component.Namespace.MasterBranch.Body.ClickToSeeItemValue": "点击查看已发布的值",
"Component.Namespace.MasterBranch.Body.ItemNoPublish": "未发布",
"Component.Namespace.MasterBranch.Body.ItemEffective": "已生效的配置",
"Component.Namespace.MasterBranch.Body.ItemPublished": "已发布",
"Component.Namespace.MasterBranch.Body.AddedItem": "新增的配置",
"Component.Namespace.MasterBranch.Body.ModifyItem": "修改此灰度配置",
"Component.Namespace.Branch.GrayScaleRule.NoPermissionTips": "您没有权限编辑灰度规则, 具有namespace修改权或者发布权的人员才可以编辑灰度规则. 如需要编辑灰度规则,请找项目管理员申请权限.",
"Component.Namespace.Branch.GrayScaleRule.AppId": "灰度的AppId",
"Component.Namespace.Branch.GrayScaleRule.IpList": "灰度的IP列表",
"Component.Namespace.Branch.GrayScaleRule.Operator": "操作",
"Component.Namespace.Branch.GrayScaleRule.ApplyToAllInstances": "ALL",
"Component.Namespace.Branch.GrayScaleRule.Modify": "修改",
"Component.Namespace.Branch.GrayScaleRule.Delete": "删除",
"Component.Namespace.Branch.GrayScaleRule.AddNewRule": "新增规则",
"Component.Namespace.Branch.Instance.RefreshList": "刷新列表",
"Component.Namespace.Branch.Instance.ItemToSee": "查看配置",
"Component.Namespace.Branch.Instance.InstanceAppId": "App ID",
"Component.Namespace.Branch.Instance.InstanceClusterName": "Cluster Name",
"Component.Namespace.Branch.Instance.InstanceDataCenter": "Data Center",
"Component.Namespace.Branch.Instance.InstanceIp": "IP",
"Component.Namespace.Branch.Instance.InstanceGetItemTime": "配置获取时间",
"Component.Namespace.Branch.Instance.LoadMore": "刷新列表",
"Component.Namespace.Branch.Instance.NoInstance": "无实例信息",
"Component.Namespace.Branch.History.ItemType": "Type",
"Component.Namespace.Branch.History.ItemKey": "Key",
"Component.Namespace.Branch.History.ItemOldValue": "Old Value",
"Component.Namespace.Branch.History.ItemNewValue": "New Value",
"Component.Namespace.Branch.History.ItemComment": "Comment",
"Component.Namespace.Branch.History.NewAdded": "新增",
"Component.Namespace.Branch.History.Modified": "更新",
"Component.Namespace.Branch.History.Deleted": "删除",
"Component.Namespace.Branch.History.LoadMore": "加载更多",
"Component.Namespace.Branch.History.NoHistory": "无更改历史",
"Component.Namespace.Header.Title.Private": "私有",
"Component.Namespace.Header.Title.PrivateTips": "私有namespace({{namespace.baseInfo.namespaceName}})的配置只能被AppId为{{appId}}的客户端读取到",
"Component.Namespace.Header.Title.Public": "公共",
"Component.Namespace.Header.Title.PublicTips": "namespace({{namespace.baseInfo.namespaceName}})的配置能被任何客户端读取到",
"Component.Namespace.Header.Title.Extend": "关联",
"Component.Namespace.Header.Title.ExtendTips": "namespace({{namespace.baseInfo.namespaceName}})的配置将会覆盖公共namespace的配置, 且合并之后的配置只能被AppId为{{appId}}的客户端读取到",
"Component.Namespace.Header.Title.ExpandAndCollapse": "[展开/收缩]",
"Component.Namespace.Header.Title.Master": "主版本",
"Component.Namespace.Header.Title.Grayscale": "灰度版本",
"Component.Namespace.Master.LoadNamespace": "加载Namespace",
"Component.Namespace.Master.LoadNamespaceTips": "加载Namespace",
"Component.Namespace.Master.Items.Changed": "有修改",
"Component.Namespace.Master.Items.ChangedUser": "当前修改者",
"Component.Namespace.Master.Items.Publish": "发布",
"Component.Namespace.Master.Items.PublishTips": "发布配置",
"Component.Namespace.Master.Items.Rollback": "回滚",
"Component.Namespace.Master.Items.RollbackTips": "回滚已发布配置",
"Component.Namespace.Master.Items.PublishHistory": "发布历史",
"Component.Namespace.Master.Items.PublishHistoryTips": "查看发布历史",
"Component.Namespace.Master.Items.Grant": "授权",
"Component.Namespace.Master.Items.GrantTips": "配置修改、发布权限",
"Component.Namespace.Master.Items.Grayscale": "灰度",
"Component.Namespace.Master.Items.GrayscaleTips": "创建测试版本",
"Component.Namespace.Master.Items.RequestPermission": "申请配置权限",
"Component.Namespace.Master.Items.RequestPermissionTips": "您没有任何配置权限,请申请",
"Component.Namespace.Master.Items.DeleteNamespace": "删除Namespace",
"Component.Namespace.Master.Items.NoPermissionTips": "您不是该项目的管理员,也没有该Namespace的编辑或发布权限,无法查看配置信息。",
"Component.Namespace.Master.Items.ItemList": "表格",
"Component.Namespace.Master.Items.ItemListByText": "文本",
"Component.Namespace.Master.Items.ItemHistory": "更改历史",
"Component.Namespace.Master.Items.ItemInstance": "实例列表",
"Component.Namespace.Master.Items.CopyText": "复制文本",
"Component.Namespace.Master.Items.GrammarCheck": "语法检查",
"Component.Namespace.Master.Items.CancelChanged": "取消修改",
"Component.Namespace.Master.Items.Change": "修改配置",
"Component.Namespace.Master.Items.SummitChanged": "提交修改",
"Component.Namespace.Master.Items.SortByKey": "按Key过滤配置",
"Component.Namespace.Master.Items.FilterItem": "过滤配置",
"Component.Namespace.Master.Items.SyncItemTips": "同步各环境间配置",
"Component.Namespace.Master.Items.SyncItem": "同步配置",
"Component.Namespace.Master.Items.DiffItemTips": "比较各环境间配置",
"Component.Namespace.Master.Items.DiffItem": "比较配置",
"Component.Namespace.Master.Items.AddItem": "新增配置",
"Component.Namespace.Master.Items.Body.ItemsNoPublishedTips": "Tips: 此namespace从来没有发布过,Apollo客户端将获取不到配置并记录404日志信息,请及时发布。",
"Component.Namespace.Master.Items.Body.FilterByKey": "输入key过滤",
"Component.Namespace.Master.Items.Body.PublishState": "发布状态",
"Component.Namespace.Master.Items.Body.Sort": "排序",
"Component.Namespace.Master.Items.Body.ItemKey": "Key",
"Component.Namespace.Master.Items.Body.ItemValue": "Value",
"Component.Namespace.Master.Items.Body.ItemComment": "备注",
"Component.Namespace.Master.Items.Body.ItemLastModify": "最后修改人",
"Component.Namespace.Master.Items.Body.ItemLastModifyTime": "最后修改时间",
"Component.Namespace.Master.Items.Body.ItemOperator": "操作",
"Component.Namespace.Master.Items.Body.NoPublish": "未发布",
"Component.Namespace.Master.Items.Body.NoPublishTitle": "点击查看已发布的值",
"Component.Namespace.Master.Items.Body.NoPublishTips": "新增的配置,无发布的值",
"Component.Namespace.Master.Items.Body.Published": "已发布",
"Component.Namespace.Master.Items.Body.PublishedTitle": "已生效的配置",
"Component.Namespace.Master.Items.Body.ClickToSee": "点击查看",
"Component.Namespace.Master.Items.Body.Grayscale": "灰",
"Component.Namespace.Master.Items.Body.HaveGrayscale": "该配置有灰度配置,点击查看灰度的值",
"Component.Namespace.Master.Items.Body.NewAdded": "新",
"Component.Namespace.Master.Items.Body.NewAddedTips": "新增的配置",
"Component.Namespace.Master.Items.Body.Modified": "改",
"Component.Namespace.Master.Items.Body.ModifiedTips": "修改的配置",
"Component.Namespace.Master.Items.Body.Deleted": "删",
"Component.Namespace.Master.Items.Body.DeletedTips": "删除的配置",
"Component.Namespace.Master.Items.Body.ModifyTips": "修改",
"Component.Namespace.Master.Items.Body.DeleteTips": "删除",
"Component.Namespace.Master.Items.Body.Link.Title": "覆盖的配置",
"Component.Namespace.Master.Items.Body.Link.NoCoverLinkItem": "无覆盖的配置",
"Component.Namespace.Master.Items.Body.Public.Title": "公共的配置",
"Component.Namespace.Master.Items.Body.Public.Published": "已发布的配置",
"Component.Namespace.Master.Items.Body.Public.NoPublish": "未发布的配置",
"Component.Namespace.Master.Items.Body.Public.NoPublicNamespaceTips1": "当前公共namespace的所有者",
"Component.Namespace.Master.Items.Body.Public.NoPublicNamespaceTips2": "没有关联此namespace,请联系{{namespace.parentAppId}}的所有者在{{namespace.parentAppId}}项目里关联此namespace",
"Component.Namespace.Master.Items.Body.Public.NoPublished": "无发布的配置",
"Component.Namespace.Master.Items.Body.Public.PublishedAndCover": "覆盖此配置",
"Component.Namespace.Master.Items.Body.NoPublished.Title": "无公共的配置",
"Component.Namespace.Master.Items.Body.NoPublished.PublishedValue": "已发布的值",
"Component.Namespace.Master.Items.Body.NoPublished.NoPublishedValue": "未发布的值",
"Component.Namespace.Master.Items.Body.HistoryView.ItemType": "Type",
"Component.Namespace.Master.Items.Body.HistoryView.ItemKey": "Key",
"Component.Namespace.Master.Items.Body.HistoryView.ItemOldValue": "Old Value",
"Component.Namespace.Master.Items.Body.HistoryView.ItemNewValue": " New Value",
"Component.Namespace.Master.Items.Body.HistoryView.ItemComment": "Comment",
"Component.Namespace.Master.Items.Body.HistoryView.NewAdded": "新增",
"Component.Namespace.Master.Items.Body.HistoryView.Updated": "更新",
"Component.Namespace.Master.Items.Body.HistoryView.Deleted": "删除",
"Component.Namespace.Master.Items.Body.HistoryView.LoadMore": "加载更多",
"Component.Namespace.Master.Items.Body.HistoryView.NoHistory": "无更改历史",
"Component.Namespace.Master.Items.Body.Instance.Tips": "实例说明:只展示最近一天访问过Apollo的实例",
"Component.Namespace.Master.Items.Body.Instance.UsedNewItem": "使用最新配置的实例",
"Component.Namespace.Master.Items.Body.Instance.NoUsedNewItem": "使用非最新配置的实例",
"Component.Namespace.Master.Items.Body.Instance.AllInstance": "所有实例",
"Component.Namespace.Master.Items.Body.Instance.RefreshList": "刷新列表",
"Component.Namespace.Master.Items.Body.Instance.ToSeeItem": "查看配置",
"Component.Namespace.Master.Items.Body.Instance.LoadMore": "加载更多",
"Component.Namespace.Master.Items.Body.Instance.ItemAppId": "App ID",
"Component.Namespace.Master.Items.Body.Instance.ItemCluster": "Cluster Name",
"Component.Namespace.Master.Items.Body.Instance.ItemDataCenter": "Data Center",
"Component.Namespace.Master.Items.Body.Instance.ItemIp": "IP",
"Component.Namespace.Master.Items.Body.Instance.ItemGetTime": "配置获取时间",
"Component.Namespace.Master.Items.Body.Instance.NoInstanceTips": "无实例信息",
"Component.PublishDeny.Title": "发布受限",
"Component.PublishDeny.Tips1": "您不能发布哟~{{env}}环境配置的编辑和发布必须为不同的人,请找另一个具有当前namespace发布权的人操作发布~",
"Component.PublishDeny.Tips2": "(如果是非工作时间或者特殊情况,您可以通过点击'紧急发布'按钮进行发布)",
"Component.PublishDeny.EmergencyPublish": "紧急发布",
"Component.PublishDeny.Close": "关闭",
"Component.Publish.Title": "发布",
"Component.Publish.Tips": "(只有发布过的配置才会被客户端获取到,此次发布只会作用于当前环境:{{env}})",
"Component.Publish.Grayscale": "灰度发布",
"Component.Publish.GrayscaleTips": "(灰度发布的配置只会作用于在灰度规则中配置的实例)",
"Component.Publish.AllPublish": "全量发布",
"Component.Publish.AllPublishTips": "(全量发布的配置会作用于全部的实例)",
"Component.Publish.ToSeeChange": "查看变更",
"Component.Publish.PublishedValue": "发布的值",
"Component.Publish.Changes": "Changes",
"Component.Publish.Key": "Key",
"Component.Publish.NoPublishedValue": "未发布的值",
"Component.Publish.ModifyUser": "修改人",
"Component.Publish.ModifyTime": "修改时间",
"Component.Publish.NewAdded": "新",
"Component.Publish.NewAddedTips": "新增的配置",
"Component.Publish.Modified": "改",
"Component.Publish.ModifiedTips": "修改的配置",
"Component.Publish.Deleted": "删",
"Component.Publish.DeletedTips": "删除的配置",
"Component.Publish.MasterValue": "主版本值",
"Component.Publish.GrayValue": "灰度版本的值",
"Component.Publish.GrayPublishedValue": "灰度版本发布的值",
"Component.Publish.GrayNoPublishedValue": "灰度版本未发布的值",
"Component.Publish.ItemNoChange": "配置没有变化",
"Component.Publish.GrayItemNoChange": "灰度配置没有变化",
"Component.Publish.NoGrayItems": "没有灰度的配置项",
"Component.Publish.Release": "Release Name",
"Component.Publish.ReleaseComment": "Comment",
"Component.Publish.OpPublish": "发布",
"Component.Rollback.To": "回滚到",
"Component.Rollback.Tips": "此操作将会回滚到上一个发布版本,且当前版本作废,但不影响正在修改的配置。可在发布历史页面查看当前生效的版本",
"Component.Rollback.ClickToView": "点击查看",
"Component.Rollback.ItemType": "Type",
"Component.Rollback.ItemKey": "Key",
"Component.Rollback.RollbackBeforeValue": "回滚前",
"Component.Rollback.RollbackAfterValue": "回滚后",
"Component.Rollback.Added": "新增",
"Component.Rollback.Modified": "更新",
"Component.Rollback.Deleted": "删除",
"Component.Rollback.NoChange": "配置没有变化",
"Component.Rollback.OpRollback": "回滚",
"Component.ShowText.Title": "查看",
"Login.Login": "登录",
"Login.UserNameOrPasswordIncorrect": "用户名或密码错误",
"Login.LogoutSuccessfully": "登出成功",
"Index.MyProject": "我的项目",
"Index.CreateProject": "创建项目",
"Index.LoadMore": "加载更多",
"Index.FavoriteItems": "收藏的项目",
"Index.Topping": "置顶",
"Index.FavoriteTip": "您还没有收藏过任何项目,在项目主页可以收藏项目哟~",
"Index.RecentlyViewedItems": "最近浏览的项目",
"Index.GetCreateAppRoleFailed": "获取创建应用权限信息失败",
"Index.Topped": "置顶成功",
"Index.CancelledFavorite": "取消收藏成功",
"Cluster.CreateCluster": "新建集群",
"Cluster.Tips.1": "通过添加集群,可以使同一份程序在不同的集群(如不同的数据中心)使用不同的配置",
"Cluster.Tips.2": "如果不同集群使用一样的配置,则没有必要创建集群",
"Cluster.Tips.3": "Apollo默认会读取机器上/opt/settings/server.properties(linux)或C:\\opt\\settings\\server.properties(windows)文件中的idc属性作为集群名字, 如SHAJQ(金桥数据中心)、SHAOY(欧阳数据中心)",
"Cluster.Tips.4": "在这里创建的集群名字需要和机器上server.properties中的idc属性一致",
"Cluster.CreateNameTips": "(部署集群如:SHAJQ,SHAOY 或自定义集群如:SHAJQ-xx,SHAJQ-yy)",
"Cluster.ChooseEnvironment": "选择环境",
"Cluster.LoadingEnvironmentError": "加载环境信息出错",
"Cluster.ClusterCreated": "集群创建成功",
"Cluster.ClusterCreateFailed": "集群创建失败",
"Cluster.PleaseChooseEnvironment": "请选择环境",
"Config.Title": "Apollo配置中心",
"Config.AppIdNotFound": "不存在,",
"Config.ClickByCreate": "点击创建",
"Config.EnvList": "环境列表",
"Config.EnvListTips": "通过切换环境、集群来管理不同环境、集群的配置",
"Config.ProjectInfo": "项目信息",
"Config.ModifyBasicProjectInfo": "修改项目基本信息",
"Config.Favorite": "收藏",
"Config.CancelFavorite": "取消收藏",
"Config.MissEnv": "缺失的环境",
"Config.MissNamespace": "缺失的Namespace",
"Config.ProjectManage": "管理项目",
"Config.CreateAppMissEnv": "补缺环境",
"Config.CreateAppMissNamespace": "补缺Namespace",
"Config.AddCluster": "添加集群",
"Config.AddNamespace": "添加Namespace",
"Config.CurrentlyOperatorEnv": "当前操作环境",
"Config.DoNotRemindAgain": "不再提示",
"Config.Note": "注意",
"Config.ClusterIsDefaultTipContent": "所有不属于 '{{name}}' 集群的实例会使用default集群(当前页面)的配置,属于 '{{name}}' 的实例会使用对应集群的配置!",
"Config.ClusterIsCustomTipContent": "属于 '{{name}}' 集群的实例只会使用 '{{name}}' 集群(当前页面)的配置,只有当对应namespace在当前集群没有发布过配置时,才会使用default集群的配置。",
"Config.HasNotPublishNamespace": "以下环境/集群有未发布的配置,客户端获取不到未发布的配置,请及时发布。",
"Config.DeleteItem.DialogTitle": "删除配置",
"Config.DeleteItem.DialogContent": "您正在删除 Key 为 <b> '{{config.key}}' </b> Value 为 <b> '{{config.value}}' </b> 的配置.<br>确定要删除配置吗?",
"Config.PublishNoPermission.DialogTitle": "发布",
"Config.PublishNoPermission.DialogContent": "您没有发布权限哦~ 请找项目管理员 '{{masterUsers}}' 分配发布权限",
"Config.ModifyNoPermission.DialogTitle": "申请配置权限",
"Config.ModifyNoPermission.DialogContent": "请找项目管理员 '{{masterUsers}}' 分配编辑或发布权限",
"Config.MasterNoPermission.DialogTitle": "申请配置权限",
"Config.MasterNoPermission.DialogContent": "您不是项目管理员, 只有项目管理员才有添加集群、namespace的权限。如需管理员权限,请找项目管理员 '{{masterUsers}}' 分配管理员权限",
"Config.NamespaceLocked.DialogTitle": "编辑受限",
"Config.NamespaceLocked.DialogContent": "当前namespace正在被 '{{lockOwner}}' 编辑,一次发布只能被一个人修改.",
"Config.RollbackAlert.DialogTitle": "回滚",
"Config.RollbackAlert.DialogContent": "确定要回滚吗?",
"Config.EmergencyPublishAlert.DialogTitle": "紧急发布",
"Config.EmergencyPublishAlert.DialogContent": "确定要紧急发布吗?",
"Config.DeleteBranch.DialogTitle": "删除灰度",
"Config.DeleteBranch.DialogContent": "删除灰度会丢失灰度的配置,确定要删除吗?",
"Config.UpdateRuleTips.DialogTitle": "更新灰度规则提示",
"Config.UpdateRuleTips.DialogContent": "灰度规则已生效,但发现灰度版本有未发布的配置,这些配置需要手动灰度发布才会生效",
"Config.MergeAndReleaseDeny.DialogTitle": "全量发布",
"Config.MergeAndReleaseDeny.DialogContent": "namespace主版本有未发布的配置,请先发布主版本配置",
"Config.GrayReleaseWithoutRulesTips.DialogTitle": "缺失灰度规则提示",
"Config.GrayReleaseWithoutRulesTips.DialogContent": "灰度版本还没有配置任何灰度规则,请配置灰度规则",
"Config.DeleteNamespaceDenyForMasterInstance.DialogTitle": "删除Namespace警告信息",
"Config.DeleteNamespaceDenyForMasterInstance.DialogContent": "发现有 <b>'{{deleteNamespaceContext.namespace.instancesCount}}'</b> 个实例正在使用Namespace('{{deleteNamespaceContext.namespace.baseInfo.namespaceName}}'),删除Namespace将导致实例获取不到配置。<br>请到 <ins>“实例列表”</ins> 确认实例信息,如确认相关实例都已经不再使用该Namespace配置,可以联系Apollo相关负责人删除实例信息(InstanceConfig)或等待实例24小时自动过期后再来删除。",
"Config.DeleteNamespaceDenyForBranchInstance.DialogTitle": "删除Namespace警告信息",
"Config.DeleteNamespaceDenyForBranchInstance.DialogContent": "发现有 <b>'{{deleteNamespaceContext.namespace.branch.latestReleaseInstances.total}}'</b> 个实例正在使用Namespace('{{deleteNamespaceContext.namespace.baseInfo.namespaceName}}')灰度版本的配置,删除Namespace将导致实例获取不到配置。<br> 请到 <ins>“灰度版本” => “实例列表”</ins> 确认实例信息,如确认相关实例都已经不再使用该Namespace配置,可以联系Apollo相关负责人删除实例信息(InstanceConfig)或等待实例24小时自动过期后再来删除。",
"Config.DeleteNamespaceDenyForPublicNamespace.DialogTitle": "删除Namespace失败提示",
"Config.DeleteNamespaceDenyForPublicNamespace.DialogContent": "删除Namespace失败提示",
"Config.DeleteNamespaceDenyForPublicNamespace.PleaseEnterAppId": "请输入appId",
"Config.SyntaxCheckFailed.DialogTitle": "语法检查错误",
"Config.SyntaxCheckFailed.DialogContent": "删除Namespace失败提示",
"Config.CreateBranchTips.DialogTitle": "创建灰度须知",
"Config.CreateBranchTips.DialogContent": "通过创建灰度版本,您可以对某些配置做灰度测试<br>灰度流程为:<br>&nbsp;&nbsp;1.创建灰度版本 <br>&nbsp;&nbsp;2.配置灰度配置项<br>&nbsp;&nbsp;3.配置灰度规则.如果是私有的namespace可以按照客户端的IP进行灰度,如果是公共的namespace则可以同时按AppId和客户端的IP进行灰度<br>&nbsp;&nbsp;4.灰度发布<br>灰度版本最终有两种结果:<b>全量发布和放弃灰度</b><br><b>全量发布</b>:灰度的配置合到主版本并发布,所有的客户端都会使用合并后的配置<br><b>放弃灰度</b>:删除灰度版本,所有的客户端都会使用回主版本的配置<br>注意事项:<br>&nbsp;&nbsp;1.如果灰度版本已经有灰度发布过,那么修改灰度规则后,无需再次灰度发布就立即生效",
"Config.ProjectMissEnvInfos": "当前项目有环境缺失,请点击页面左侧『补缺环境』补齐数据",
"Config.ProjectMissNamespaceInfos": "当前环境有Namespace缺失,请点击页面左侧『补缺Namespace』补齐数据",
"Config.SystemError": "系统出错,请重试或联系系统负责人",
"Config.FavoriteSuccessfully": "收藏成功",
"Config.FavoriteFailed": "收藏失败",
"Config.CancelledFavorite": "取消收藏成功",
"Config.CancelFavoriteFailed": "取消收藏失败",
"Config.GetUserInfoFailed": "获取用户登录信息失败",
"Config.LoadingAllNamespaceError": "加载配置信息出错",
"Config.CancelFavoriteError": "取消收藏失败",
"Config.Deleted": "删除成功",
"Config.DeleteFailed": "删除失败",
"Config.GrayscaleCreated": "创建灰度成功",
"Config.GrayscaleCreateFailed": "创建灰度失败",
"Config.BranchDeleted": "分支删除成功",
"Config.BranchDeleteFailed": "分支删除失败",
"Config.DeleteNamespaceFailedTips": "以下应用已关联此公共Namespace,必须先删除全部已关联的Namespace才能删除公共Namespace",
"Config.DeleteNamespaceNoPermissionFailedTitle": "删除失败",
"Config.DeleteNamespaceNoPermissionFailedTips": "您没有项目管理员权限,只有管理员才能删除Namespace,请找项目管理员 [{{usres}}] 删除Namespace",
"Delete.Title": "删除应用、集群、AppNamespace",
"Delete.DeleteApp": "删除应用",
"Delete.DeleteAppTips": "(由于删除应用影响面较大,所以现在暂时只允许系统管理员删除,请确保没有客户端读取该应用的配置后再做删除动作)",
"Delete.AppIdTips": "(删除前请先查询应用信息)",
"Delete.AppInfo": "应用信息",
"Delete.DeleteCluster": "删除集群",
"Delete.DeleteClusterTips": "(由于删除集群影响面较大,所以现在暂时只允许系统管理员删除,请确保没有客户端读取该集群的配置后再做删除动作)",
"Delete.EnvName": "环境名称",
"Delete.ClusterNameTips": "(删除前请先查询应用集群信息)",
"Delete.ClusterInfo": "集群信息",
"Delete.DeleteNamespace": "删除AppNamespace",
"Delete.DeleteNamespaceTips": "(注意,所有环境的Namespace和AppNamespace都会被删除!如果只是要删除某个环境的Namespace,让用户到项目页面中自行删除!)",
"Delete.DeleteNamespaceTips2": "目前用户可以自行删除关联的Namespace和私有的Namespace,不过无法删除AppNamespace元信息,因为删除AppNamespace影响面较大,所以现在暂时只允许系统管理员删除,对于公共Namespace需要确保没有应用关联了该AppNamespace。",
"Delete.AppNamespaceName": "AppNamespace名称",
"Delete.AppNamespaceNameTips": "(非properties类型的namespace请加上类型后缀,例如apollo.xml)",
"Delete.AppNamespaceInfo": "AppNamespace信息",
"Delete.IsRootUserTips": "当前页面只对Apollo管理员开放",
"Delete.PleaseEnterAppId": "请输入appId",
"Delete.AppIdNotFound": "AppId: '{{appId}}'不存在!",
"Delete.AppInfoContent": "应用名:'{{appName}}' 部门:'{{departmentName}}({{departmentId}})' 负责人:'{{ownerName}}'",
"Delete.ConfirmDeleteAppId": "确认删除AppId:'{{appId}}'?",
"Delete.Deleted": "删除成功",
"Delete.PleaseEnterAppIdAndEnvAndCluster": "请输入appId、环境和集群名称",
"Delete.ClusterInfoContent": "AppId:'{{appId}}' 环境:'{{env}}' 集群名称:'{{clusterName}}'",
"Delete.ConfirmDeleteCluster": "确认删除集群?AppId:'{{appId}}' 环境:'{{env}}' 集群名称:'{{clusterName}}'",
"Delete.PleaseEnterAppIdAndNamespace": "请输入appId和AppNamespace名称",
"Delete.AppNamespaceInfoContent": "AppId:'{{appId}}' AppNamespace名称:'{{namespace}}' isPublic:'{{isPublic}}'",
"Delete.ConfirmDeleteNamespace": "确认删除所有环境的AppNamespace和Namespace?appId: '{{appId}}' 环境:'所有环境' AppNamespace名称:'{{namespace}}'",
"Namespace.Title": "新建Namespace",
"Namespace.UnderstandMore": "(点击了解更多Namespace相关知识)",
"Namespace.Link.Tips1": "应用可以通过关联公共namespace来覆盖公共Namespace的配置",
"Namespace.Link.Tips2": "如果应用不需要覆盖公共Namespace的配置,那么无需关联公共Namespace",
"Namespace.CreatePublic.Tips1": "公共的Namespace的配置能被任何项目读取",
"Namespace.CreatePublic.Tips2": "通过创建公共Namespace可以实现公共组件的配置,或多个应用共享同一份配置的需求",
"Namespace.CreatePublic.Tips3": "如果其它应用需要覆盖公共部分的配置,可以在其它应用那里关联公共Namespace,然后在关联的Namespace里面配置需要覆盖的配置即可",
"Namespace.CreatePublic.Tips4": "如果其它应用不需要覆盖公共部分的配置,那么就不需要在其它应用那里关联公共Namespace",
"Namespace.CreatePrivate.Tips1": "私有Namespace的配置只能被所属的应用获取到",
"Namespace.CreatePrivate.Tips2": "通过创建一个私有的Namespace可以实现分组管理配置",
"Namespace.CreatePrivate.Tips3": "私有Namespace的格式可以是xml、yml、yaml、json、txt. 您可以通过apollo-client中ConfigFile接口来获取非properties格式Namespace的内容",
"Namespace.CreatePrivate.Tips4": "1.3.0及以上版本的apollo-client针对yaml/yml提供了更好的支持,可以通过ConfigService.getConfig(\"someNamespace.yml\")直接获取Config对象,也可以通过@EnableApolloConfig(\"someNamespace.yml\")或apollo.bootstrap.namespaces=someNamespace.yml注入yml配置到Spring/SpringBoot中去",
"Namespace.CreateNamespace": "创建Namespace",
"Namespace.AssociationPublicNamespace": "关联公共Namespace",
"Namespace.ChooseCluster": "选择集群",
"Namespace.NamespaceName": "名称",
"Namespace.AutoAddDepartmentPrefix": "自动添加部门前缀",
"Namespace.AutoAddDepartmentPrefixTips": "(公共Namespace的名称需要全局唯一,添加部门前缀有助于保证全局唯一性)",
"Namespace.NamespaceType": "类型",
"Namespace.NamespaceType.Public": "public",
"Namespace.NamespaceType.Private": "private",
"Namespace.Remark": "备注",
"Namespace.Namespace": "namespace",
"Namespace.PleaseChooseNamespace": "请选择Namespace",
"Namespace.LoadingPublicNamespaceError": "加载公共namespace错误",
"Namespace.LoadingAppInfoError": "加载App信息出错",
"Namespace.PleaseChooseCluster": "请选择集群",
"Namespace.CheckNamespaceNameLengthTip": "namespace名称不能大于32个字符. 部门前缀:'{{departmentLength}}'个字符, 名称{{namespaceLength}}个字符",
"ServiceConfig.Title": "应用配置",
"ServiceConfig.Tips": "(维护ApolloPortalDB.ServerConfig表数据,如果已存在配置项则会覆盖,否则会创建配置项。配置更新后,一分钟后自动生效)",
"ServiceConfig.Key": "key",
"ServiceConfig.KeyTips": "(修改配置前请先查询该配置信息)",
"ServiceConfig.Value": "value",
"ServiceConfig.Comment": "comment",
"ServiceConfig.Saved": "保存成功",
"ServiceConfig.SaveFailed": "保存失败",
"ServiceConfig.PleaseEnterKey": "请输入key",
"ServiceConfig.KeyNotExistsAndCreateTip": "Key: '{{key}}' 不存在,点击保存后会创建该配置项",
"ServiceConfig.KeyExistsAndSaveTip": "Key: '{{key}}' 已存在,点击保存后会覆盖该配置项",
"SystemInfo.Title": "系统信息",
"SystemInfo.SystemVersion": "系统版本",
"SystemInfo.Tips1": "环境列表来自于ApolloPortalDB.ServerConfig中的<strong>apollo.portal.envs</strong>配置,可以到<a href=\"{{serverConfigUrl}}\">系统参数</a>页面配置,更多信息可以参考<a href=\"{{wikiUrl}}\">分布式部署指南</a>中的<strong>apollo.portal.envs - 可支持的环境列表</strong>章节。",
"SystemInfo.Tips2": "Meta server地址展示了该环境配置的meta server信息,更多信息可以参考<a href=\"{{wikiUrl}}\">分布式部署指南</a>中的<strong>配置apollo-portal的meta service信息</strong>章节。",
"SystemInfo.Active": "Active",
"SystemInfo.ActiveTips": "(当前环境状态异常,请结合下方系统信息和AdminService的Check Health结果排查)",
"SystemInfo.MetaServerAddress": "Meta server地址",
"SystemInfo.ConfigServices": "Config Services",
"SystemInfo.ConfigServices.Name": "Name",
"SystemInfo.ConfigServices.InstanceId": "Instance Id",
"SystemInfo.ConfigServices.HomePageUrl": "Home Page Url",
"SystemInfo.ConfigServices.CheckHealth": "Check Health",
"SystemInfo.NoConfigServiceTips": "No config service found!",
"SystemInfo.Check": "check",
"SystemInfo.AdminServices": "Admin Services",
"SystemInfo.AdminServices.Name": "Name",
"SystemInfo.AdminServices.InstanceId": "Instance Id",
"SystemInfo.AdminServices.HomePageUrl": "Home Page Url",
"SystemInfo.AdminServices.CheckHealth": "Check Health",
"SystemInfo.NoAdminServiceTips": "No admin service found!",
"SystemInfo.IsRootUser": "当前页面只对Apollo管理员开放",
"SystemRole.Title": "系统权限管理",
"SystemRole.AddCreateAppRoleToUser": "为用户添加创建应用权限",
"SystemRole.AddCreateAppRoleToUserTips": "(系统参数中设置 role.create-application.enabled=true 会限制只有超级管理员和拥有创建应用权限的帐号可以创建项目)",
"SystemRole.ChooseUser": "用户选择",
"SystemRole.Add": "添加",
"SystemRole.AuthorizedUser": "已拥有权限用户",
"SystemRole.ModifyAppAdminUser": "修改应用管理员分配权限",
"SystemRole.ModifyAppAdminUserTips": "(系统参数中设置 role.manage-app-master.enabled=true 会限制只有超级管理员和拥有管理员分配权限的帐号可以修改项目管理员)",
"SystemRole.AppIdTips": "(请先查询应用信息)",
"SystemRole.AppInfo": "应用信息",
"SystemRole.AllowAppMasterAssignRole": "允许此用户作为管理员时添加Master",
"SystemRole.DeleteAppMasterAssignRole": "禁止此用户作为管理员时添加Master",
"SystemRole.IsRootUser": "当前页面只对Apollo管理员开放",
"SystemRole.PleaseChooseUser": "请选择用户名",
"SystemRole.Added": "添加成功",
"SystemRole.AddFailed": "添加失败",
"SystemRole.Deleted": "删除成功",
"SystemRole.DeleteFailed": "删除失败",
"SystemRole.GetCanCreateProjectUsersError": "获取拥有创建项目权限的用户列表出错",
"SystemRole.PleaseEnterAppId": "请输入appId",
"SystemRole.AppIdNotFound": "AppId: '{{appId}}' 不存在!",
"SystemRole.AppInfoContent": "应用名:'{{appName}}' 部门:'{{departmentName}}({{departmentId}})' 负责人:'{{ownerName}}",
"SystemRole.DeleteMasterAssignRoleTips": "确认删除AppId: '{{appId}}' 的用户: '{{userId}}' 分配应用管理员的权限?",
"SystemRole.DeletedMasterAssignRoleTips": "删除AppId: '{{appId}}' 的用户: '{{userId}}' 分配应用管理员的权限成功",
"SystemRole.AllowAppMasterAssignRoleTips": "确认添加AppId: '{{appId}}' 的用户: '{{userId}}' 分配应用管理员的权限?",
"SystemRole.AllowedAppMasterAssignRoleTips": "添加AppId: '{{appId}}' 的用户: '{{userId}}' 分配应用管理员的权限成功",
"UserMange.Title": "用户管理",
"UserMange.TitleTips": "(仅对默认的Spring Security简单认证方式有效: -Dapollo_profile=github,auth)",
"UserMange.UserName": "用户名",
"UserMange.UserNameTips": "输入的用户名如果不存在,则新建。若已存在,则更新。",
"UserMange.Pwd": "密码",
"UserMange.Email": "邮箱",
"UserMange.Created": "创建用户成功",
"UserMange.CreateFailed": "创建用户失败",
"Open.Manage.Title": "开放平台",
"Open.Manage.CreateThirdApp": "创建第三方应用",
"Open.Manage.CreateThirdAppTips": "(说明: 第三方应用可以通过Apollo开放平台来对配置进行管理)",
"Open.Manage.ThirdAppId": "第三方应用ID",
"Open.Manage.ThirdAppIdTips": "(创建前请先查询第三方应用是否已经申请过)",
"Open.Manage.ThirdAppName": "第三方应用名称",
"Open.Manage.ThirdAppNameTips": "(建议格式 xx-yy-zz 例:apollo-server)",
"Open.Manage.ProjectOwner": "项目负责人",
"Open.Manage.Create": "创建",
"Open.Manage.GrantPermission": "赋权",
"Open.Manage.GrantPermissionTips": "(Namespace级别权限包括: 修改、发布Namespace。应用级别权限包括: 创建Namespace、修改或发布应用下任何Namespace)",
"Open.Manage.Token": "Token",
"Open.Manage.ManagedAppId": "被管理的AppId",
"Open.Manage.ManagedNamespace": "被管理的Namespace",
"Open.Manage.ManagedNamespaceTips": "(非properties类型的namespace请加上类型后缀,例如apollo.xml)",
"Open.Manage.GrantType": "授权类型",
"Open.Manage.GrantType.Namespace": "Namespace",
"Open.Manage.GrantType.App": "App",
"Open.Manage.GrantEnv": "环境",
"Open.Manage.GrantEnvTips": "(不选择则所有环境都有权限,如果提示Namespace's role does not exist,请先打开该Namespace的授权页面触发一下权限的初始化动作)",
"Open.Manage.PleaseEnterAppId": "请输入appId",
"Open.Manage.AppNotCreated": "App('{{appId}}')未创建,请先创建",
"Open.Manage.GrantSuccessfully": "赋权成功",
"Open.Manage.GrantFailed": "赋权失败",
"Namespace.Role.Title": "权限管理",
"Namespace.Role.GrantModifyTo": "修改权",
"Namespace.Role.GrantModifyTo2": "(可以修改配置)",
"Namespace.Role.AllEnv": "所有环境",
"Namespace.Role.GrantPublishTo": "发布权",
"Namespace.Role.GrantPublishTo2": "(可以发布配置)",
"Namespace.Role.Add": "添加",
"Namespace.Role.NoPermission": "您没有权限哟!",
"Namespace.Role.InitNamespacePermissionError": "初始化授权出错",
"Namespace.Role.GetEnvGrantUserError": "加载 '{{env}}' 授权用户出错",
"Namespace.Role.GetGrantUserError": "加载授权用户出错",
"Namespace.Role.PleaseChooseUser": "请选择用户",
"Namespace.Role.Added": "添加成功",
"Namespace.Role.AddFailed": "添加失败",
"Namespace.Role.Deleted": "删除成功",
"Namespace.Role.DeleteFailed": "删除失败",
"Config.Sync.Title": "同步配置",
"Config.Sync.FistStep": "(第一步:选择同步信息)",
"Config.Sync.SecondStep": "(第二步:检查Diff)",
"Config.Sync.PreviousStep": "上一步",
"Config.Sync.NextStep": "下一步",
"Config.Sync.Sync": "同步",
"Config.Sync.Tips": "Tips",
"Config.Sync.Tips1": "通过同步配置功能,可以使多个环境、集群间的配置保持一致",
"Config.Sync.Tips2": "需要注意的是,同步完之后需要发布后才会对应用生效",
"Config.Sync.SyncNamespace": "同步的Namespace",
"Config.Sync.SyncToCluster": "同步到那个集群",
"Config.Sync.NeedToSyncItem": "需要同步的配置",
"Config.Sync.SortByLastModifyTime": "按最后更新时间过滤",
"Config.Sync.BeginTime": "开始时间",
"Config.Sync.EndTime": "结束时间",
"Config.Sync.Filter": "过滤",
"Config.Sync.Rest": "重置",
"Config.Sync.ItemKey": "Key",
"Config.Sync.ItemValue": "Value",
"Config.Sync.ItemCreateTime": "Create Time",
"Config.Sync.ItemUpdateTime": "Update Time",
"Config.Sync.NoNeedSyncItem": "没有更新的配置",
"Config.Sync.IgnoreSync": "忽略同步",
"Config.Sync.Step2Type": "Type",
"Config.Sync.Step2Key": "Key",
"Config.Sync.Step2SyncBefore": "同步前",
"Config.Sync.Step2SyncAfter": "同步后",
"Config.Sync.Step2Comment": "Comment",
"Config.Sync.Step2Operator": "操作",
"Config.Sync.NewAdd": "新增",
"Config.Sync.NoSyncItem": "不同步该配置",
"Config.Sync.Delete": "删除",
"Config.Sync.Update": "更新",
"Config.Sync.SyncSuccessfully": "同步成功!",
"Config.Sync.SyncFailed": "同步失败!",
"Config.Sync.LoadingItemsError": "加载配置出错",
"Config.Sync.PleaseChooseNeedSyncItems": "请选择需要同步的配置",
"Config.Sync.PleaseChooseCluster": "请选择集群",
"Config.History.Title": "发布历史",
"Config.History.MasterVersionPublish": "主版本发布",
"Config.History.MasterVersionRollback": "主版本回滚",
"Config.History.GrayscaleOperator": "灰度操作",
"Config.History.PublishHistory": "发布历史",
"Config.History.OperationType0": "普通发布",
"Config.History.OperationType1": "回滚",
"Config.History.OperationType2": "灰度发布",
"Config.History.OperationType3": "更新灰度规则",
"Config.History.OperationType4": "灰度全量发布",
"Config.History.OperationType5": "灰度发布(主版本发布)",
"Config.History.OperationType6": "灰度发布(主版本回滚)",
"Config.History.OperationType7": "放弃灰度",
"Config.History.OperationType8": "删除灰度(全量发布)",
"Config.History.UrgentPublish": "紧急发布",
"Config.History.LoadMore": "加载更多",
"Config.History.ChangedItem": "变更的配置",
"Config.History.ChangedItemTips": "查看此次发布与上次版本的变更",
"Config.History.AllItem": "全部配置",
"Config.History.AllItemTips": "查看此次发布的所有配置信息",
"Config.History.ChangeType": "Type",
"Config.History.ChangeKey": "Key",
"Config.History.ChangeValue": "Value",
"Config.History.ChangeOldValue": "Old Value",
"Config.History.ChangeNewValue": "New Value",
"Config.History.ChangeTypeNew": "新增",
"Config.History.ChangeTypeModify": "修改",
"Config.History.ChangeTypeDelete": "删除",
"Config.History.NoChange": "无配置更改",
"Config.History.NoItem": "无配置",
"Config.History.GrayscaleRule": "灰度规则",
"Config.History.GrayscaleAppId": "灰度的AppId",
"Config.History.GrayscaleIp": "灰度的IP",
"Config.History.NoGrayscaleRule": "无灰度规则",
"Config.History.NoPermissionTips": "您不是该项目的管理员,也没有该Namespace的编辑或发布权限,无法查看发布历史",
"Config.History.NoPublishHistory": "无发布历史信息",
"Config.History.LoadingHistoryError": "无发布历史信息",
"Config.Diff.Title": "比较配置",
"Config.Diff.FirstStep": "(第一步:选择比较信息)",
"Config.Diff.SecondStep": "(第二步:查看差异配置)",
"Config.Diff.PreviousStep": "上一步",
"Config.Diff.NextStep": "下一步",
"Config.Diff.TipsTitle": "Tips",
"Config.Diff.Tips": "通过比较配置功能,可以查看多个环境、集群间的配置差异",
"Config.Diff.DiffCluster": "要比较的集群",
"Config.Diff.HasDiffComment": "是否比较注释",
"Config.Diff.PleaseChooseTwoCluster": "请至少选择两个集群",
"App.CreateProject": "创建项目",
"App.AppIdTips": "(应用唯一标识)",
"App.AppNameTips": "(建议格式 xx-yy-zz 例:apollo-server)",
"App.AppOwnerTips": "(开启项目管理员分配权限控制后,应用负责人和项目管理员默认为本账号,不可选择)",
"App.AppAdminTips1": "(应用负责人默认具有项目管理员权限,",
"App.AppAdminTips2": "项目管理员可以创建Namespace和集群、分配用户权限)",
"App.Setting.Title": "项目管理",
"App.Setting.Admin": "管理员",
"App.Setting.AdminTips": "(项目管理员具有以下权限: 1. 创建Namespace 2. 创建集群 3. 管理项目、Namespace权限)",
"App.Setting.Add": "添加",
"App.Setting.BasicInfo": "基本信息",
"App.Setting.ProjectName": "项目名称",
"App.Setting.ProjectNameTips": "(建议格式 xx-yy-zz 例:apollo-server)",
"App.Setting.ProjectOwner": "项目负责人",
"App.Setting.Modify": "修改项目信息",
"App.Setting.Cancel": "取消修改",
"App.Setting.NoPermissionTips": "您没有权限操作,请找 [{{users}}] 开通权限",
"App.Setting.DeleteAdmin": "删除管理员",
"App.Setting.CanNotDeleteAllAdmin": "不能删除所有的管理员",
"App.Setting.PleaseChooseUser": "请选择用户",
"App.Setting.Added": "添加成功",
"App.Setting.AddFailed": "添加失败",
"App.Setting.Deleted": "删除成功",
"App.Setting.DeleteFailed": "删除失败",
"App.Setting.Modified": "修改成功",
"Valdr.App.AppId.Size": "AppId长度不能多于32个字符",
"Valdr.App.AppId.Required": "AppId不能为空",
"Valdr.App.appName.Size": "应用名称长度不能多于128个字符",
"Valdr.App.appName.Required": "应用名称不能为空",
"Valdr.Cluster.ClusterName.Size": "集群名称长度不能多于32个字符",
"Valdr.Cluster.ClusterName.Required": "集群名称不能为空",
"Valdr.AppNamespace.NamespaceName.Size": "Namespace名称长度不能多于32个字符",
"Valdr.AppNamespace.NamespaceName.Required": "Namespace名称不能为空",
"Valdr.AppNamespace.Comment.Size": "备注长度不能多于64个字符",
"Valdr.Item.Key.Size": "Key长度不能多于128个字符",
"Valdr.Item.Key.Required": "Key不能为空",
"Valdr.Item.Comment.Size": "备注长度不能多于64个字符",
"Valdr.Release.ReleaseName.Size": "Release Name长度不能多于64个字符",
"Valdr.Release.ReleaseName.Required": "Release Name不能为空",
"Valdr.Release.Comment.Size": "备注长度不能多于64个字符",
"ApolloConfirmDialog.DefaultConfirmBtnName": "确认",
"ApolloConfirmDialog.SearchPlaceHolder": "搜索项目(AppId、项目名)",
"RulesModal.ChooseInstances": "从实例列表中选择",
"RulesModal.InvalidIp": "不合法的IP地址: '{{ip}}'",
"RulesModal.GrayscaleAppIdCanNotBeNull": "灰度的AppId不能为空",
"RulesModal.AppIdExistsRule": "已经存在AppId='{{appId}}'的规则",
"RulesModal.IpListCanNotBeNull": "IP列表不能为空",
"ItemModal.KeyExists": "key='{{key}}' 已存在",
"ItemModal.AddedTips": "添加成功,如需生效请发布",
"ItemModal.AddFailed": "添加失败",
"ItemModal.PleaseChooseCluster": "请选择集群",
"ItemModal.ModifiedTips": "更新成功, 如需生效请发布",
"ItemModal.ModifyFailed": "更新失败",
"ItemModal.Tabs": "制表符",
"ItemModal.NewLine": "换行符",
"ItemModal.Space": "空格",
"ApolloNsPanel.LoadingHistoryError": "加载修改历史记录出错",
"ApolloNsPanel.LoadingGrayscaleError": "加载修改历史记录出错",
"ApolloNsPanel.Deleted": "删除成功",
"ApolloNsPanel.GrayscaleModified": "灰度规则更新成功",
"ApolloNsPanel.GrayscaleModifyFailed": "灰度规则更新失败",
"ApolloNsPanel.ModifiedTips": "更新成功, 如需生效请发布",
"ApolloNsPanel.ModifyFailed": "更新失败",
"ApolloNsPanel.GrammarIsright": "语法正确!",
"ReleaseModal.Published": "发布成功",
"ReleaseModal.PublishFailed": "发布失败",
"ReleaseModal.GrayscalePublished": "灰度发布成功",
"ReleaseModal.GrayscalePublishFailed": "灰度发布失败",
"ReleaseModal.AllPublished": "全量发布成功",
"ReleaseModal.AllPublishFailed": "全量发布失败",
"Rollback.NoRollbackList": "没有可以回滚的发布历史",
"Rollback.RollbackSuccessfully": "回滚成功",
"Rollback.RollbackFailed": "回滚失败"
}
\ No newline at end of file
<!doctype html> <!doctype html>
<html ng-app="index"> <html ng-app="index">
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="icon" href="./img/config.png"> <link rel="icon" href="./img/config.png">
...@@ -11,127 +12,130 @@ ...@@ -11,127 +12,130 @@
<link rel="stylesheet" type="text/css" media='all' href="vendor/font-awesome.min.css"> <link rel="stylesheet" type="text/css" media='all' href="vendor/font-awesome.min.css">
<link rel="stylesheet" type="text/css" href="styles/common-style.css"> <link rel="stylesheet" type="text/css" href="styles/common-style.css">
<title>Apollo配置中心</title> <title>{{'Common.Title' | translate }}</title>
</head> </head>
<body> <body>
<apollonav></apollonav> <apollonav></apollonav>
<div id="app-list" class="hidden" ng-controller="IndexController"> <div id="app-list" class="hidden" ng-controller="IndexController">
<section class="media create-app-list"> <section class="media create-app-list">
<aside class="media-left text-center"> <aside class="media-left text-center">
<h5>我的项目</h5> <h5>{{'Index.MyProject' | translate }}</h5>
</aside> </aside>
<aside class="media-body"> <aside class="media-body">
<div class="app-panel col-md-2 text-center" ng-click="goToCreateAppPage()" ng-if="hasCreateApplicationPermission"> <div class="app-panel col-md-2 text-center" ng-click="goToCreateAppPage()"
<div href="#" class="thumbnail create-btn hover cursor-pointer"> ng-if="hasCreateApplicationPermission">
<img src="img/plus-white.png"/> <div href="#" class="thumbnail create-btn hover cursor-pointer">
<h5>创建项目</h5> <img src="img/plus-white.png" />
<h5>{{'Index.CreateProject' | translate }}</h5>
</div>
</div> </div>
</div> <div class="app-panel col-md-2 text-center" ng-repeat="app in createdApps"
<div class="app-panel col-md-2 text-center" ng-repeat="app in createdApps" ng-click="goToAppHomePage(app.appId)">
ng-click="goToAppHomePage(app.appId)"> <div href="#" class="thumbnail hover cursor-pointer">
<div href="#" class="thumbnail hover cursor-pointer"> <h4 ng-bind="app.appId"></h4>
<h4 ng-bind="app.appId"></h4> <h5 ng-bind="app.name"></h5>
<h5 ng-bind="app.name"></h5> </div>
</div> </div>
</div> <div class="app-panel col-md-2 text-center" ng-show="hasMoreCreatedApps"
<div class="app-panel col-md-2 text-center" ng-show="hasMoreCreatedApps" ng-click="getUserCreatedApps()">
ng-click="getUserCreatedApps()"> <div href="#" class="thumbnail hover cursor-pointer">
<div href="#" class="thumbnail hover cursor-pointer"> <img class="more-img" src="img/more.png" />
<img class="more-img" src="img/more.png"/> <h5>{{'Index.LoadMore' | translate }}</h5>
<h5>加载更多</h5> </div>
</div> </div>
</div> </aside>
</aside> </section>
</section>
<section class="media favorites-app-list">
<section class="media favorites-app-list"> <aside class="media-left text-center">
<aside class="media-left text-center"> <h5>{{'Index.FavoriteItems' | translate }}</h5>
<h5>收藏的项目</h5> </aside>
</aside> <aside class="media-body">
<aside class="media-body"> <div class="app-panel col-md-2 text-center" ng-repeat="app in favorites"
<div class="app-panel col-md-2 text-center" ng-click="goToAppHomePage(app.appId)" ng-mouseover="toggleOperationBtn(app)"
ng-repeat="app in favorites" ng-mouseout="toggleOperationBtn(app)">
ng-click="goToAppHomePage(app.appId)" <div class="thumbnail hover">
ng-mouseover="toggleOperationBtn(app)" <h4 ng-bind="app.appId"></h4>
ng-mouseout="toggleOperationBtn(app)"> <h5 ng-bind="app.name"></h5>
<div class="thumbnail hover">
<h4 ng-bind="app.appId"></h4> <p class="operate-panel" ng-show="app.showOperationBtn">
<h5 ng-bind="app.name"></h5> <button class="btn btn-default btn-xs" title="{{'Index.Topping' | translate }}"
<p class="operate-panel" ng-show="app.showOperationBtn">
<button class="btn btn-default btn-xs" title="置顶"
ng-click="toTop(app.favoriteId);$event.stopPropagation();"> ng-click="toTop(app.favoriteId);$event.stopPropagation();">
<img src="img/top.png" class="i-15"> <img src="img/top.png" class="i-15">
</button> </button>
<button class="btn btn-default btn-xs" title="取消收藏" <button class="btn btn-default btn-xs" title="{{'Index.FavoriteCancel' | translate }}"
ng-click="deleteFavorite(app.favoriteId);$event.stopPropagation();"> ng-click="deleteFavorite(app.favoriteId);$event.stopPropagation();">
<img src="img/like.png" class="i-15"> <img src="img/like.png" class="i-15">
</button> </button>
</p> </p>
</div>
</div> </div>
</div> <div class="col-md-2 text-center" ng-show="hasMoreFavorites" ng-click="getUserFavorites()">
<div class="col-md-2 text-center" ng-show="hasMoreFavorites" <div href="#" class="thumbnail hover cursor-pointer">
ng-click="getUserFavorites()"> <img class="more-img" src="img/more.png" />
<div href="#" class="thumbnail hover cursor-pointer"> <h5>{{'Index.LoadMore' | translate }}</h5>
<img class="more-img" src="img/more.png"/> </div>
<h5>加载更多</h5>
</div> </div>
</div> <div class="no-favorites text-center" ng-show="!favorites || favorites.length == 0">
<div class="no-favorites text-center" ng-show="!favorites || favorites.length == 0"> <h4>{{'Index.FavoriteTip' | translate }}</h4>
<h4>您还没有收藏过任何项目,在项目主页可以收藏项目哟~</h4>
</div>
</aside>
</section>
<section class="media visit-app-list" ng-show="visitedApps && visitedApps.length">
<aside class="media-left text-center">
<h5>最近浏览的项目</h5>
</aside>
<aside class="media-body">
<div class="app-panel col-md-2 text-center"
ng-repeat="app in visitedApps"
ng-click="goToAppHomePage(app.appId)">
<div class="thumbnail hover">
<h4 ng-bind="app.appId"></h4>
<h5 ng-bind="app.name"></h5>
</div> </div>
</div>
</aside>
</section>
</div>
</aside>
</section>
<section class="media visit-app-list" ng-show="visitedApps && visitedApps.length">
<aside class="media-left text-center">
<h5>{{'Index.RecentlyViewedItems' | translate }}</h5>
</aside>
<aside class="media-body">
<div class="app-panel col-md-2 text-center" ng-repeat="app in visitedApps"
ng-click="goToAppHomePage(app.appId)">
<div class="thumbnail hover">
<h4 ng-bind="app.appId"></h4>
<h5 ng-bind="app.name"></h5>
</div>
</div>
</aside>
</section>
</div>
<div ng-include="'views/common/footer.html'"></div>
<!--angular--> <div ng-include="'views/common/footer.html'"></div>
<script src="vendor/angular/angular.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 --> <!--angular-->
<script src="vendor/jquery.min.js" type="text/javascript"></script> <script src="vendor/angular/angular.min.js"></script>
<script src="vendor/select2/select2.min.js" type="text/javascript"></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>
<script src="vendor/angular/angular-cookies.min.js"></script>
<!-- bootstrap.js --> <script src="vendor/angular/angular-translate.2.18.1/angular-translate.min.js"></script>
<script src="vendor/bootstrap/js/bootstrap.min.js" type="text/javascript"></script> <script src="vendor/angular/angular-translate.2.18.1/angular-translate-loader-static-files.min.js"></script>
<script src="vendor/angular/angular-translate.2.18.1/angular-translate-storage-cookie.min.js"></script>
<script type="application/javascript" src="scripts/app.js"></script> <!-- jquery.js -->
<script type="application/javascript" src="scripts/services/AppService.js"></script> <script src="vendor/jquery.min.js" type="text/javascript"></script>
<script type="application/javascript" src="scripts/services/EnvService.js"></script> <script src="vendor/select2/select2.min.js" type="text/javascript"></script>
<script type="application/javascript" src="scripts/services/UserService.js"></script>
<script type="application/javascript" src="scripts/services/CommonService.js"></script>
<script type="application/javascript" src="scripts/services/FavoriteService.js"></script>
<script type="application/javascript" src="scripts/services/PermissionService.js"></script>
<script type="application/javascript" src="scripts/AppUtils.js"></script>
<script type="application/javascript" src="scripts/directive/directive.js"></script>
<script type="application/javascript" src="scripts/controller/IndexController.js"></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/services/EnvService.js"></script>
<script type="application/javascript" src="scripts/services/UserService.js"></script>
<script type="application/javascript" src="scripts/services/CommonService.js"></script>
<script type="application/javascript" src="scripts/services/FavoriteService.js"></script>
<script type="application/javascript" src="scripts/services/PermissionService.js"></script>
<script type="application/javascript" src="scripts/AppUtils.js"></script>
<script type="application/javascript" src="scripts/directive/directive.js"></script>
<script type="application/javascript" src="scripts/controller/IndexController.js"></script>
</body> </body>
</html>
</html>
\ No newline at end of file
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<html lang="en" ng-app="login"> <html lang="en" ng-app="login">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Apollo配置中心</title> <title>{{ 'Common.Title' | translate }}</title>
<link rel="icon" href="./img/config.png"> <link rel="icon" href="./img/config.png">
<link rel="stylesheet" type="text/css" href="vendor/bootstrap/css/bootstrap.min.css"> <link rel="stylesheet" type="text/css" href="vendor/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="vendor/font-awesome.min.css"> <link rel="stylesheet" href="vendor/font-awesome.min.css">
...@@ -257,7 +257,7 @@ ...@@ -257,7 +257,7 @@
</div> </div>
<div class="col-xs-12 form-group pull-right"> <div class="col-xs-12 form-group pull-right">
<input type="submit" name="login-submit" id="login-submit" tabindex="4" <input type="submit" name="login-submit" id="login-submit" tabindex="4"
class="form-control btn btn-login" value="登录"> class="form-control btn btn-login" value="{{'Login.Login' | translate }}">
</div> </div>
</form> </form>
</div> </div>
...@@ -277,6 +277,11 @@ ...@@ -277,6 +277,11 @@
<script src="vendor/angular/angular-resource.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/angular-toastr-1.4.1.tpls.min.js"></script>
<script src="vendor/angular/loading-bar.min.js"></script> <script src="vendor/angular/loading-bar.min.js"></script>
<script src="vendor/angular/angular-cookies.min.js"></script>
<script src="vendor/angular/angular-translate.2.18.1/angular-translate.min.js"></script>
<script src="vendor/angular/angular-translate.2.18.1/angular-translate-loader-static-files.min.js"></script>
<script src="vendor/angular/angular-translate.2.18.1/angular-translate-storage-cookie.min.js"></script>
<script type="application/javascript" src="scripts/app.js"></script> <script type="application/javascript" src="scripts/app.js"></script>
<script type="application/javascript" src="scripts/AppUtils.js"></script> <script type="application/javascript" src="scripts/AppUtils.js"></script>
......
<!doctype html> <!doctype html>
<html ng-app="namespace"> <html ng-app="namespace">
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="icon" href="./img/config.png"> <link rel="icon" href="./img/config.png">
...@@ -9,223 +10,232 @@ ...@@ -9,223 +10,232 @@
<link rel="stylesheet" type="text/css" href="vendor/select2/select2.min.css"> <link rel="stylesheet" type="text/css" href="vendor/select2/select2.min.css">
<link rel="stylesheet" type="text/css" media='all' href="vendor/angular/loading-bar.min.css"> <link rel="stylesheet" type="text/css" media='all' href="vendor/angular/loading-bar.min.css">
<link rel="stylesheet" type="text/css" href="styles/common-style.css"> <link rel="stylesheet" type="text/css" href="styles/common-style.css">
<title>新建Namespace</title> <title>{{'Namespace.Title' | translate }}</title>
</head> </head>
<body> <body>
<apollonav></apollonav> <apollonav></apollonav>
<div class="container-fluid apollo-container hidden" ng-controller="LinkNamespaceController"> <div class="container-fluid apollo-container hidden" ng-controller="LinkNamespaceController">
<div class="row"> <div class="row">
<div class="col-md-8 col-md-offset-2"> <div class="col-md-8 col-md-offset-2">
<div class="panel"> <div class="panel">
<header class="panel-heading"> <header class="panel-heading">
<div class="row"> <div class="row">
<div class="col-md-6">新建Namespace <div class="col-md-6">{{'Namespace.Title' | translate }}
<small><a target="_blank" href="https://github.com/ctripcorp/apollo/wiki/Apollo%E6%A0%B8%E5%BF%83%E6%A6%82%E5%BF%B5%E4%B9%8B%E2%80%9CNamespace%E2%80%9D"> <small><a target="_blank"
(点击了解更多Namespace相关知识) href="https://github.com/ctripcorp/apollo/wiki/Apollo%E6%A0%B8%E5%BF%83%E6%A6%82%E5%BF%B5%E4%B9%8B%E2%80%9CNamespace%E2%80%9D">
</a> </small> {{'Namespace.UnderstandMore' | translate }}
</div> </a> </small>
<div class="col-md-6 text-right"> </div>
<button type="button" class="btn btn-info" ng-click="back()">返回到项目首页 <div class="col-md-6 text-right">
</button> <button type="button" class="btn btn-info"
ng-click="back()">{{'Common.ReturnToIndex' | translate }} </button>
</div>
</div> </div>
</div>
</header> </header>
<div class="panel-body"> <div class="panel-body">
<div class="alert alert-info no-radius"> <div class="alert alert-info no-radius">
<strong>Tips:</strong> <strong>Tips:</strong>
<ul ng-show="type == 'link'"> <ul ng-show="type == 'link'">
<li>应用可以通过关联公共namespace来覆盖公共Namespace的配置</li> <li>{{'Namespace.Link.Tips1' | translate }}</li>
<li>如果应用不需要覆盖公共Namespace的配置,那么无需关联公共Namespace</li> <li>{{'Namespace.Link.Tips2' | translate }}</li>
</ul> </ul>
<ul ng-show="type == 'create' && appNamespace.isPublic"> <ul ng-show="type == 'create' && appNamespace.isPublic">
<li>公共的Namespace的配置能被任何项目读取</li> <li>{{'Namespace.CreatePublic.Tips1' | translate }}</li>
<li> <li>{{'Namespace.CreatePublic.Tips2' | translate }}</li>
通过创建公共Namespace可以实现公共组件的配置,或多个应用共享同一份配置的需求 <li>{{'Namespace.CreatePublic.Tips3' | translate }}</li>
</li> <li>{{'Namespace.CreatePublic.Tips4' | translate }}</li>
<li>如果其它应用需要覆盖公共部分的配置,可以在其它应用那里关联公共Namespace,然后在关联的Namespace里面配置需要覆盖的配置即可</li> </ul>
<li>如果其它应用不需要覆盖公共部分的配置,那么就不需要在其它应用那里关联公共Namespace</li> <ul ng-show="type == 'create' && !appNamespace.isPublic">
</ul> <li>{{'Namespace.CreatePrivate.Tips1' | translate }}</li>
<ul ng-show="type == 'create' && !appNamespace.isPublic"> <li>{{'Namespace.CreatePrivate.Tips2' | translate }}</li>
<li>私有Namespace的配置只能被所属的应用获取到</li> <li>{{'Namespace.CreatePrivate.Tips3' | translate }}</li>
<li> <li>{{'Namespace.CreatePrivate.Tips4' | translate }}</li>
通过创建一个私有的Namespace可以实现分组管理配置 </ul>
</li>
<li>私有Namespace的格式可以是xml、yml、yaml、json、txt. 您可以通过apollo-client中ConfigFile接口来获取非properties格式Namespace的内容</li>
<li>1.3.0及以上版本的apollo-client针对yaml/yml提供了更好的支持,可以通过ConfigService.getConfig("someNamespace.yml")直接获取Config对象,也可以通过@EnableApolloConfig("someNamespace.yml")或apollo.bootstrap.namespaces=someNamespace.yml注入yml配置到Spring/Spring Boot中去</li>
</ul>
</div>
<div class="row text-right" style="padding-right: 20px;">
<div class="btn-group btn-group-sm" role="group" aria-label="...">
<button type="button" class="btn btn-default" ng-class="{active:type=='link'}"
ng-click="switchType('link')">关联公共Namespace
</button>
<button type="button" class="btn btn-default" ng-class="{active:type=='create'}"
ng-click="switchType('create')">创建Namespace
</button>
</div> </div>
</div> <div class="row text-right" style="padding-right: 20px;">
<div class="btn-group btn-group-sm" role="group" aria-label="...">
<button type="button" class="btn btn-default" ng-class="{active:type=='link'}"
<form class="form-horizontal" name="namespaceForm" valdr-type="AppNamespace" ng-click="switchType('link')">{{'Namespace.AssociationPublicNamespace' | translate }}
style="margin-top: 30px;" ng-show="step == 1" ng-submit="createNamespace()"> </button>
<div class="form-group"> <button type="button" class="btn btn-default" ng-class="{active:type=='create'}"
<label class="col-sm-3 control-label">AppId</label> ng-click="switchType('create')">{{'Namespace.CreateNamespace' | translate }}
<div class="col-sm-6" valdr-form-group> </button>
<label class="form-control-static" ng-bind="appId"></label>
</div> </div>
</div> </div>
<div class="form-horizontal" ng-show="type == 'link'">
<form class="form-horizontal" name="namespaceForm" valdr-type="AppNamespace"
style="margin-top: 30px;" ng-show="step == 1" ng-submit="createNamespace()">
<div class="form-group"> <div class="form-group">
<label class="col-sm-3 control-label"> <label class="col-sm-3 control-label">{{'Common.AppId' | translate }}</label>
<apollorequiredfield></apollorequiredfield>
选择集群</label>
<div class="col-sm-6" valdr-form-group> <div class="col-sm-6" valdr-form-group>
<apolloclusterselector apollo-app-id="appId" apollo-default-all-checked="true" <label class="form-control-static" ng-bind="appId"></label>
apollo-select="collectSelectedClusters"></apolloclusterselector>
</div> </div>
</div> </div>
</div> <div class="form-horizontal" ng-show="type == 'link'">
<div class="form-group" ng-show="type == 'create'"> <div class="form-group">
<label class="col-sm-3 control-label"> <label class="col-sm-3 control-label">
<apollorequiredfield></apollorequiredfield> <apollorequiredfield></apollorequiredfield>
名称</label> {{'Namespace.ChooseCluster' | translate }}
<div class="col-sm-5" valdr-form-group> </label>
<div ng-class="{'input-group':appNamespace.isPublic && appendNamespacePrefix}"> <div class="col-sm-6" valdr-form-group>
<span class="input-group-addon" ng-show="appNamespace.isPublic && appendNamespacePrefix" <apolloclusterselector apollo-app-id="appId" apollo-default-all-checked="true"
ng-bind="appBaseInfo.namespacePrefix"></span> apollo-select="collectSelectedClusters"></apolloclusterselector>
<input type="text" name="namespaceName" class="form-control" </div>
ng-model="appNamespace.name">
</div> </div>
</div> </div>
<div class="form-group" ng-show="type == 'create'">
<label class="col-sm-3 control-label">
<apollorequiredfield></apollorequiredfield>
{{'Namespace.NamespaceName' | translate }}
</label>
<div class="col-sm-5" valdr-form-group>
<div ng-class="{'input-group':appNamespace.isPublic && appendNamespacePrefix}">
<span class="input-group-addon"
ng-show="appNamespace.isPublic && appendNamespacePrefix"
ng-bind="appBaseInfo.namespacePrefix"></span>
<input type="text" name="namespaceName" class="form-control"
ng-model="appNamespace.name">
</div>
</div>
<!--public namespace can only be properties --> <!--public namespace can only be properties -->
<div class="col-sm-2" ng-show="!appNamespace.isPublic"> <div class="col-sm-2" ng-show="!appNamespace.isPublic">
<select class="form-control" name="format" ng-model="appNamespace.format"> <select class="form-control" name="format" ng-model="appNamespace.format">
<option value="properties">properties</option> <option value="properties">properties</option>
<option value="xml">xml</option> <option value="xml">xml</option>
<option value="json">json</option> <option value="json">json</option>
<option value="yml">yml</option> <option value="yml">yml</option>
<option value="yaml">yaml</option> <option value="yaml">yaml</option>
<option value="txt">txt</option> <option value="txt">txt</option>
</select> </select>
</div> </div>
&nbsp;&nbsp; &nbsp;&nbsp;
<span ng-show="appNamespace.isPublic && appendNamespacePrefix" ng-bind="concatNamespace()" <span ng-show="appNamespace.isPublic && appendNamespacePrefix"
style="line-height: 34px;"></span> ng-bind="concatNamespace()" style="line-height: 34px;"></span>
</div> </div>
<div class="form-group" ng-show="type == 'create' && appNamespace.isPublic"> <div class="form-group" ng-show="type == 'create' && appNamespace.isPublic">
<label class="col-sm-3 control-label"> <label class="col-sm-3 control-label">
自动添加部门前缀 {{'Namespace.AutoAddDepartmentPrefix' | translate }}
</label> </label>
<div class="col-sm-6" valdr-form-group> <div class="col-sm-6" valdr-form-group>
<div> <div>
<label class="checkbox-inline"> <label class="checkbox-inline">
<input type="checkbox" ng-model="appendNamespacePrefix" /> <input type="checkbox" ng-model="appendNamespacePrefix" />
{{appBaseInfo.namespacePrefix}} {{appBaseInfo.namespacePrefix}}
</label> </label>
</div>
<small>{{'Namespace.AutoAddDepartmentPrefixTips' | translate }}</small>
</div> </div>
<small>(公共Namespace的名称需要全局唯一,添加部门前缀有助于保证全局唯一性)</small>
</div> </div>
</div>
<div class="form-group" ng-show="type == 'create' && (pageSetting.canAppAdminCreatePrivateNamespace || hasRootPermission)"> <div class="form-group"
<label class="col-sm-3 control-label"> ng-show="type == 'create' && (pageSetting.canAppAdminCreatePrivateNamespace || hasRootPermission)">
<apollorequiredfield></apollorequiredfield> <label class="col-sm-3 control-label">
类型</label> <apollorequiredfield></apollorequiredfield>
<div class="col-sm-4" valdr-form-group> {{'Namespace.NamespaceType' | translate }}
<label class="radio-inline">
<input type="radio" name="namespaceType" value="true" ng-value="true"
ng-model="appNamespace.isPublic"> public
</label>
<label class="radio-inline">
<input type="radio" name="namespaceType" value="false" ng-value="false"
ng-model="appNamespace.isPublic"> private
</label> </label>
<div class="col-sm-4" valdr-form-group>
<label class="radio-inline">
<input type="radio" name="namespaceType" value="true" ng-value="true"
ng-model="appNamespace.isPublic"> {{'Namespace.NamespaceType.Public' | translate }}
</label>
<label class="radio-inline">
<input type="radio" name="namespaceType" value="false" ng-value="false"
ng-model="appNamespace.isPublic"> {{'Namespace.NamespaceType.Private' | translate }}
</label>
</div>
</div> </div>
</div> <div class="form-group" ng-show="type == 'create'" valdr-form-group>
<div class="form-group" ng-show="type == 'create'" valdr-form-group> <label class="col-sm-3 control-label">{{'Namespace.Remark' | translate }}</label>
<label class="col-sm-3 control-label">备注</label> <div class="col-sm-7" valdr-form-group>
<div class="col-sm-7" valdr-form-group> <textarea class="form-control" rows="3" name="comment"
<textarea class="form-control" rows="3" name="comment" ng-model="appNamespace.comment"></textarea>
ng-model="appNamespace.comment"></textarea> </div>
</div> </div>
</div> <div class="form-group" ng-show="type == 'link'">
<div class="form-group" ng-show="type == 'link'"> <label class="col-sm-3 control-label">
<label class="col-sm-3 control-label"> <apollorequiredfield></apollorequiredfield>
<apollorequiredfield></apollorequiredfield> {{'Namespace.Namespace' | translate }}
namespace</label> </label>
<div class="col-sm-4" valdr-form-group> <div class="col-sm-4" valdr-form-group>
<select id="namespaces"> <select id="namespaces">
<option></option> <option></option>
</select> </select>
</div>
</div> </div>
</div>
<div class="form-group"> <div class="form-group">
<div class="col-sm-offset-3 col-sm-10"> <div class="col-sm-offset-3 col-sm-10">
<button type="submit" class="btn btn-primary" <button type="submit" class="btn btn-primary"
ng-disabled="(type == 'create' && namespaceForm.$invalid) || submitBtnDisabled"> ng-disabled="(type == 'create' && namespaceForm.$invalid) || submitBtnDisabled">
提交 {{'Common.Submit' | translate }}
</button> </button>
</div>
</div> </div>
</div> </form>
</form>
<div class="row text-center" ng-show="step == 2"> <div class="row text-center" ng-show="step == 2">
<img src="img/sync-succ.png" style="height: 100px; width: 100px"> <img src="img/sync-succ.png" style="height: 100px; width: 100px">
<h3>创建成功!</h3> <h3>{{'Common.Created' | translate }}</h3>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div>
<div ng-include="'views/common/footer.html'"></div> <div ng-include="'views/common/footer.html'"></div>
<!--angular-->
<script src="vendor/angular/angular.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>
<script src="vendor/angular/angular-cookies.min.js"></script>
<!--angular--> <script src="vendor/angular/angular-translate.2.18.1/angular-translate.min.js"></script>
<script src="vendor/angular/angular.min.js"></script> <script src="vendor/angular/angular-translate.2.18.1/angular-translate-loader-static-files.min.js"></script>
<script src="vendor/angular/angular-resource.min.js"></script> <script src="vendor/angular/angular-translate.2.18.1/angular-translate-storage-cookie.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 --> <!-- jquery.js -->
<script src="vendor/jquery.min.js" type="text/javascript"></script> <script src="vendor/jquery.min.js" type="text/javascript"></script>
<script src="vendor/select2/select2.min.js" type="text/javascript"></script> <script src="vendor/select2/select2.min.js" type="text/javascript"></script>
<!-- bootstrap.js --> <!-- bootstrap.js -->
<script src="vendor/bootstrap/js/bootstrap.min.js" type="text/javascript"></script> <script src="vendor/bootstrap/js/bootstrap.min.js" type="text/javascript"></script>
<script src="vendor/valdr/valdr.min.js" type="text/javascript"></script> <script src="vendor/valdr/valdr.min.js" type="text/javascript"></script>
<script src="vendor/valdr/valdr-message.min.js" type="text/javascript"></script> <script src="vendor/valdr/valdr-message.min.js" type="text/javascript"></script>
<script type="application/javascript" src="scripts/app.js"></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/services/AppService.js"></script>
<script type="application/javascript" src="scripts/services/EnvService.js"></script> <script type="application/javascript" src="scripts/services/EnvService.js"></script>
<script type="application/javascript" src="scripts/services/UserService.js"></script> <script type="application/javascript" src="scripts/services/UserService.js"></script>
<script type="application/javascript" src="scripts/services/CommonService.js"></script> <script type="application/javascript" src="scripts/services/CommonService.js"></script>
<script type="application/javascript" src="scripts/services/NamespaceService.js"></script> <script type="application/javascript" src="scripts/services/NamespaceService.js"></script>
<script type="application/javascript" src="scripts/services/PermissionService.js"></script> <script type="application/javascript" src="scripts/services/PermissionService.js"></script>
<script type="application/javascript" src="scripts/AppUtils.js"></script> <script type="application/javascript" src="scripts/AppUtils.js"></script>
<!--directive--> <!--directive-->
<script type="application/javascript" src="scripts/directive/directive.js"></script> <script type="application/javascript" src="scripts/directive/directive.js"></script>
<script type="application/javascript" src="scripts/controller/NamespaceController.js"></script> <script type="application/javascript" src="scripts/controller/NamespaceController.js"></script>
<script src="scripts/valdr.js" type="text/javascript"></script> <script src="scripts/valdr.js" type="text/javascript"></script>
</body> </body>
</html>
</html>
\ No newline at end of file
<!doctype html> <!doctype html>
<html ng-app="role"> <html ng-app="role">
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="icon" href="../img/config.png"> <link rel="icon" href="../img/config.png">
...@@ -9,156 +10,176 @@ ...@@ -9,156 +10,176 @@
<link rel="stylesheet" type="text/css" media='all' href="../vendor/angular/loading-bar.min.css"> <link rel="stylesheet" type="text/css" media='all' href="../vendor/angular/loading-bar.min.css">
<link rel="stylesheet" type="text/css" href="../styles/common-style.css"> <link rel="stylesheet" type="text/css" href="../styles/common-style.css">
<link rel="stylesheet" type="text/css" href="../vendor/select2/select2.min.css"> <link rel="stylesheet" type="text/css" href="../vendor/select2/select2.min.css">
<title>权限管理</title> <title>{{'Namespace.Role.Title' | translate }}</title>
</head> </head>
<body> <body>
<apollonav></apollonav> <apollonav></apollonav>
<div class="container-fluid apollo-container"> <div class="container-fluid apollo-container">
<section class="panel col-md-offset-1 col-md-10" ng-controller="NamespaceRoleController"> <section class="panel col-md-offset-1 col-md-10" ng-controller="NamespaceRoleController">
<header class="panel-heading"> <header class="panel-heading">
<div class="row"> <div class="row">
<div class="col-md-7"> <div class="col-md-7">
<h4 class="modal-title">权限管理<small>(AppId:<label ng-bind="pageContext.appId"></label> Namespace:<label ng-bind="pageContext.namespaceName"></label>)</small> <h4 class="modal-title">
</h4> {{'Namespace.Role.Title' | translate }}<small>({{'Common.AppId' | translate }}:<label
</div> ng-bind="pageContext.appId"></label> {{'Common.Namespace' | translate }}:<label
<div class="col-md-5 text-right"> ng-bind="pageContext.namespaceName"></label>)</small>
<a type="button" class="btn btn-info" data-dismiss="modal" </h4>
href="/config.html?#appid={{pageContext.appId}}">返回到项目首页 </div>
</a> <div class="col-md-5 text-right">
<a type="button" class="btn btn-info" data-dismiss="modal"
href="/config.html?#appid={{pageContext.appId}}">{{'Common.ReturnToIndex' | translate }}
</a>
</div>
</div> </div>
</div> </header>
</header> <div class="panel-body" ng-show="hasAssignUserPermission">
<div class="panel-body" ng-show="hasAssignUserPermission"> <div class="row">
<div class="row"> <div class="form-horizontal">
<div class="form-horizontal"> <div class="form-group">
<div class="form-group"> <label
<label class="col-sm-2 control-label">修改权<br><small>(可以修改配置)</small></label> class="col-sm-2 control-label">{{'Namespace.Role.GrantModifyTo' | translate }}<br><small>{{'Namespace.Role.GrantModifyTo2' | translate }}</small></label>
<div class="col-sm-8"> <div class="col-sm-8">
<form class="form-inline" ng-submit="assignRoleToUser('ModifyNamespace')"> <form class="form-inline" ng-submit="assignRoleToUser('ModifyNamespace')">
<div class="form-group"> <div class="form-group">
<apollouserselector apollo-id="modifyRoleWidgetId"></apollouserselector> <apollouserselector apollo-id="modifyRoleWidgetId"></apollouserselector>
<select class="form-control input-sm" ng-model="modifyRoleSelectedEnv"> <select class="form-control input-sm" ng-model="modifyRoleSelectedEnv">
<option value="">所有环境</option> <option value="">{{'Namespace.Role.AllEnv' | translate }}</option>
<option ng-repeat="env in envs" ng-value="env">{{env}}</option> <option ng-repeat="env in envs" ng-value="env">{{env}}</option>
</select> </select>
</div> </div>
<button type="submit" class="btn btn-default" style="margin-left: 20px;" ng-disabled="modifyRoleSubmitBtnDisabled">添加</button> <button type="submit" class="btn btn-default" style="margin-left: 20px;"
</form> ng-disabled="modifyRoleSubmitBtnDisabled">{{'Namespace.Role.Add' | translate }}</button>
<!-- Split button --> </form>
<div class="item-container"> <!-- Split button -->
<h5>所有环境</h5> <div class="item-container">
<div class="btn-group item-info" ng-repeat="user in rolesAssignedUsers.modifyRoleUsers"> <h5>{{'Namespace.Role.AllEnv' | translate }}</h5>
<button type="button" class="btn btn-default" ng-bind="user.userId"></button> <div class="btn-group item-info"
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" ng-repeat="user in rolesAssignedUsers.modifyRoleUsers">
aria-haspopup="true" aria-expanded="false" ng-click="removeUserRole('ModifyNamespace', user.userId, null)"> <button type="button" class="btn btn-default" ng-bind="user.userId"></button>
<span class="glyphicon glyphicon-remove"></span> <button type="button" class="btn btn-default dropdown-toggle"
</button> data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"
ng-click="removeUserRole('ModifyNamespace', user.userId, null)">
<span class="glyphicon glyphicon-remove"></span>
</button>
</div>
</div> </div>
</div> <div class="item-container" ng-repeat="env in envs">
<div class="item-container" ng-repeat="env in envs"> <h5>{{env}}</h5>
<h5>{{env}}</h5> <div class="btn-group item-info"
<div class="btn-group item-info" ng-repeat="user in envRolesAssignedUsers[env].modifyRoleUsers"> ng-repeat="user in envRolesAssignedUsers[env].modifyRoleUsers">
<button type="button" class="btn btn-default" ng-bind="user.userId"></button> <button type="button" class="btn btn-default" ng-bind="user.userId"></button>
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" <button type="button" class="btn btn-default dropdown-toggle"
aria-haspopup="true" aria-expanded="false" ng-click="removeUserRole('ModifyNamespace', user.userId, env)"> data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"
<span class="glyphicon glyphicon-remove"></span> ng-click="removeUserRole('ModifyNamespace', user.userId, env)">
</button> <span class="glyphicon glyphicon-remove"></span>
</button>
</div>
</div> </div>
</div>
</div>
</div> </div>
</div> </div>
</div> <hr>
<hr>
<div class="row" style="margin-top: 10px;"> <div class="row" style="margin-top: 10px;">
<div class="form-horizontal"> <div class="form-horizontal">
<div class="col-sm-2 text-right"> <div class="col-sm-2 text-right">
<label class="control-label">发布权<br><small>(可以发布配置)</small></label> <label
</div> class="control-label">{{'Namespace.Role.GrantPublishTo' | translate }}<br><small>{{'Namespace.Role.GrantPublishTo2' | translate }}</small></label>
<div class="col-sm-8">
<form class="form-inline" ng-submit="assignRoleToUser('ReleaseNamespace')">
<div class="form-group">
<apollouserselector apollo-id="releaseRoleWidgetId"></apollouserselector>
<select class="form-control input-sm" ng-model="releaseRoleSelectedEnv">
<option value="">所有环境</option>
<option ng-repeat="env in envs" ng-value="env">{{env}}</option>
</select>
</div>
<button type="submit" class="btn btn-default" style="margin-left: 20px;" ng-disabled="ReleaseRoleSubmitBtnDisabled">添加</button>
</form>
<!-- Split button -->
<div class="item-container">
<h5>所有环境</h5>
<div class="btn-group item-info" ng-repeat="user in rolesAssignedUsers.releaseRoleUsers">
<button type="button" class="btn btn-default" ng-bind="user.userId"></button>
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false" ng-click="removeUserRole('ReleaseNamespace', user.userId, null)">
<span class="glyphicon glyphicon-remove"></span>
</button>
</div>
</div> </div>
<div class="col-sm-8">
<form class="form-inline" ng-submit="assignRoleToUser('ReleaseNamespace')">
<div class="form-group">
<apollouserselector apollo-id="releaseRoleWidgetId"></apollouserselector>
<select class="form-control input-sm" ng-model="releaseRoleSelectedEnv">
<option value="">{{'Namespace.Role.AllEnv' | translate }}</option>
<option ng-repeat="env in envs" ng-value="env">{{env}}</option>
</select>
</div>
<button type="submit" class="btn btn-default" style="margin-left: 20px;"
ng-disabled="ReleaseRoleSubmitBtnDisabled">{{'Namespace.Role.Add' | translate }}</button>
</form>
<!-- Split button -->
<div class="item-container">
<h5>{{'Namespace.Role.AllEnv' | translate }}</h5>
<div class="btn-group item-info"
ng-repeat="user in rolesAssignedUsers.releaseRoleUsers">
<button type="button" class="btn btn-default" ng-bind="user.userId"></button>
<button type="button" class="btn btn-default dropdown-toggle"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"
ng-click="removeUserRole('ReleaseNamespace', user.userId, null)">
<span class="glyphicon glyphicon-remove"></span>
</button>
</div>
</div>
<div class="item-container" ng-repeat="env in envs"> <div class="item-container" ng-repeat="env in envs">
<h5>{{env}}</h5> <h5>{{env}}</h5>
<div class="btn-group item-info" ng-repeat="user in envRolesAssignedUsers[env].releaseRoleUsers"> <div class="btn-group item-info"
<button type="button" class="btn btn-default" ng-bind="user.userId"></button> ng-repeat="user in envRolesAssignedUsers[env].releaseRoleUsers">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" <button type="button" class="btn btn-default" ng-bind="user.userId"></button>
aria-haspopup="true" aria-expanded="false" ng-click="removeUserRole('ReleaseNamespace', user.userId, env)"> <button type="button" class="btn btn-default dropdown-toggle"
<span class="glyphicon glyphicon-remove"></span> data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"
</button> ng-click="removeUserRole('ReleaseNamespace', user.userId, env)">
<span class="glyphicon glyphicon-remove"></span>
</button>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div>
</div> </div>
<div class="panel-body text-center" ng-show="!hasAssignUserPermission"> <div class="panel-body text-center" ng-show="!hasAssignUserPermission">
<h2>您没有权限哟!</h2> <h2>{{'Namespace.Role.NoPermission' | translate }}</h2>
</div> </div>
</section> </section>
</div> </div>
<div ng-include="'../views/common/footer.html'"></div> <div ng-include="'../views/common/footer.html'"></div>
<!-- jquery.js --> <!-- jquery.js -->
<script src="../vendor/jquery.min.js" type="text/javascript"></script> <script src="../vendor/jquery.min.js" type="text/javascript"></script>
<!--angular--> <!--angular-->
<script src="../vendor/angular/angular.min.js"></script> <script src="../vendor/angular/angular.min.js"></script>
<script src="../vendor/angular/angular-resource.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/angular-toastr-1.4.1.tpls.min.js"></script>
<script src="../vendor/angular/loading-bar.min.js"></script> <script src="../vendor/angular/loading-bar.min.js"></script>
<script src="../vendor/angular/angular-cookies.min.js"></script>
<script src="../vendor/angular/angular-translate.2.18.1/angular-translate.min.js"></script>
<script src="../vendor/angular/angular-translate.2.18.1/angular-translate-loader-static-files.min.js"></script>
<script src="../vendor/angular/angular-translate.2.18.1/angular-translate-storage-cookie.min.js"></script>
<!-- bootstrap.js --> <!-- bootstrap.js -->
<script src="../vendor/bootstrap/js/bootstrap.min.js" type="text/javascript"></script> <script src="../vendor/bootstrap/js/bootstrap.min.js" type="text/javascript"></script>
<script src="../vendor/select2/select2.min.js" type="text/javascript"></script> <script src="../vendor/select2/select2.min.js" type="text/javascript"></script>
<!--biz--> <!--biz-->
<!--must import--> <!--must import-->
<script type="application/javascript" src="../scripts/app.js"></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/services/AppService.js"></script>
<script type="application/javascript" src="../scripts/services/EnvService.js"></script> <script type="application/javascript" src="../scripts/services/EnvService.js"></script>
<script type="application/javascript" src="../scripts/services/UserService.js"></script> <script type="application/javascript" src="../scripts/services/UserService.js"></script>
<script type="application/javascript" src="../scripts/services/CommonService.js"></script> <script type="application/javascript" src="../scripts/services/CommonService.js"></script>
<script type="application/javascript" src="../scripts/services/PermissionService.js"></script> <script type="application/javascript" src="../scripts/services/PermissionService.js"></script>
<script type="application/javascript" src="../scripts/AppUtils.js"></script> <script type="application/javascript" src="../scripts/AppUtils.js"></script>
<script type="application/javascript" src="../scripts/PageCommon.js"></script> <script type="application/javascript" src="../scripts/PageCommon.js"></script>
<script type="application/javascript" src="../scripts/directive/directive.js"></script> <script type="application/javascript" src="../scripts/directive/directive.js"></script>
<script type="application/javascript" src="../scripts/controller/role/NamespaceRoleController.js"></script> <script type="application/javascript" src="../scripts/controller/role/NamespaceRoleController.js"></script>
</body> </body>
</html>
</html>
\ No newline at end of file
<!doctype html> <!doctype html>
<html ng-app="open_manage"> <html ng-app="open_manage">
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="icon" href="../img/config.png"> <link rel="icon" href="../img/config.png">
...@@ -9,206 +10,216 @@ ...@@ -9,206 +10,216 @@
<link rel="stylesheet" type="text/css" media='all' href="../vendor/angular/loading-bar.min.css"> <link rel="stylesheet" type="text/css" media='all' href="../vendor/angular/loading-bar.min.css">
<link rel="stylesheet" type="text/css" href="../styles/common-style.css"> <link rel="stylesheet" type="text/css" href="../styles/common-style.css">
<link rel="stylesheet" type="text/css" href="../vendor/select2/select2.min.css"> <link rel="stylesheet" type="text/css" href="../vendor/select2/select2.min.css">
<title>开放平台</title> <title>{{'Open.Manage.Title' | translate }}</title>
</head> </head>
<body> <body>
<apollonav></apollonav> <apollonav></apollonav>
<div class="container-fluid" ng-controller="OpenManageController"> <div class="container-fluid" ng-controller="OpenManageController">
<div class="col-md-10 col-md-offset-1 panel"> <div class="col-md-10 col-md-offset-1 panel">
<section class="panel-body" ng-show="isRootUser"> <section class="panel-body" ng-show="isRootUser">
<!--project admin--> <!--project admin-->
<section class="row"> <section class="row">
<h5>创建第三方应用 <h5>{{'Open.Manage.CreateThirdApp' | translate }}
<small> <small>
(说明: 第三方应用可以通过Apollo开放平台来对配置进行管理) {{'Open.Manage.CreateThirdAppTips' | translate }}
</small> </small>
</h5> </h5>
<hr> <hr>
<form class="form-horizontal"> <form class="form-horizontal">
<div class="form-group" valdr-form-group> <div class="form-group" valdr-form-group>
<label class="col-sm-2 control-label"> <label class="col-sm-2 control-label">
<apollorequiredfield></apollorequiredfield> <apollorequiredfield></apollorequiredfield>
第三方应用ID</label> {{'Open.Manage.ThirdAppId' | translate }}
<div class="col-sm-3"> </label>
<input type="text" class="form-control" ng-model="consumer.appId"> <div class="col-sm-3">
<small>(创建前请先查询第三方应用是否已经申请过)</small> <input type="text" class="form-control" ng-model="consumer.appId">
</div> <small>{{'Open.Manage.ThirdAppIdTips' | translate }}</small>
<div class="col-sm-1"> </div>
<button class="btn btn-info" ng-click="getTokenByAppId()">查询</button> <div class="col-sm-1">
</div> <button class="btn btn-info" ng-click="getTokenByAppId()">查询</button>
<div class="col-sm-6"> </div>
<h4 style="color: red" <div class="col-sm-6">
ng-show="consumerToken" <h4 style="color: red" ng-show="consumerToken"
ng-bind="'Token: ' + consumerToken.token"></h4> ng-bind="'Token: ' + consumerToken.token"></h4>
</div>
</div> </div>
</div> <div class="form-group">
<div class="form-group"> <label class="col-sm-2 control-label">
<label class="col-sm-2 control-label"> <apollorequiredfield></apollorequiredfield>
<apollorequiredfield></apollorequiredfield> {{'Common.Department' | translate }}
部门</label> </label>
<div class="col-sm-3"> <div class="col-sm-3">
<select id="organization"> <select id="organization">
<option></option> <option></option>
</select> </select>
</div>
</div> </div>
</div> <div class="form-group" valdr-form-group>
<div class="form-group" valdr-form-group> <label class="col-sm-2 control-label">
<label class="col-sm-2 control-label"> <apollorequiredfield></apollorequiredfield>
<apollorequiredfield></apollorequiredfield> {{'Open.Manage.ThirdAppName' | translate }}
第三方应用名称</label> </label>
<div class="col-sm-3"> <div class="col-sm-3">
<input type="text" class="form-control" ng-model="consumer.name"> <input type="text" class="form-control" ng-model="consumer.name">
<small>(建议格式 xx-yy-zz 例:apollo-server)</small> <small>{{'Open.Manage.ThirdAppNameTips' | translate }}</small>
</div>
</div> </div>
</div> <div class="form-group">
<div class="form-group"> <label class="col-sm-2 control-label">
<label class="col-sm-2 control-label"> <apollorequiredfield></apollorequiredfield>
<apollorequiredfield></apollorequiredfield> {{'Open.Manage.ProjectOwner' | translate }}
项目负责人</label> </label>
<div class="col-sm-6 J_ownerSelectorPanel"> <div class="col-sm-6 J_ownerSelectorPanel">
<apollouserselector apollo-id="'ownerSelector'"></apollouserselector> <apollouserselector apollo-id="'ownerSelector'"></apollouserselector>
</div>
</div> </div>
</div>
<div class="form-group"> <div class="form-group">
<div class="col-sm-offset-2 col-sm-9"> <div class="col-sm-offset-2 col-sm-9">
<button type="submit" class="btn btn-primary" <button type="submit" class="btn btn-primary" ng-disabled="submitBtnDisabled"
ng-disabled="submitBtnDisabled"
ng-click="createConsumer()"> ng-click="createConsumer()">
创建 {{'Open.Manage.Create' | translate }}
</button> </button>
</div>
</div> </div>
</div> </form>
</form> </section>
</section>
<section class="row">
<section class="row"> <h5>{{'Open.Manage.GrantPermission' | translate }}
<h5>赋权 <small>
<small> {{'Open.Manage.GrantPermissionTips' | translate }}
(Namespace级别权限包括: 修改、发布Namespace。应用级别权限包括: 创建Namespace、修改或发布应用下任何Namespace) </small>
</small> </h5>
</h5> <hr>
<hr> <form class="form-horizontal" ng-submit="assignRoleToConsumer()">
<form class="form-horizontal" ng-submit="assignRoleToConsumer()">
<div class="form-group" valdr-form-group>
<div class="form-group" valdr-form-group> <label class="col-sm-2 control-label">
<label class="col-sm-2 control-label"> <apollorequiredfield></apollorequiredfield>
<apollorequiredfield></apollorequiredfield> {{'Open.Manage.Token' | translate }}
token</label> </label>
<div class="col-sm-5"> <div class="col-sm-5">
<input type="text" class="form-control" ng-model="consumerRole.token" required> <input type="text" class="form-control" ng-model="consumerRole.token" required>
</div>
</div> </div>
</div> <div class="form-group" valdr-form-group>
<div class="form-group" valdr-form-group> <label class="col-sm-2 control-label">
<label class="col-sm-2 control-label"> <apollorequiredfield></apollorequiredfield>
<apollorequiredfield></apollorequiredfield> {{'Open.Manage.ManagedAppId' | translate }}
被管理的AppId</label> </label>
<div class="col-sm-3"> <div class="col-sm-3">
<input type="text" class="form-control" ng-model="consumerRole.appId" required> <input type="text" class="form-control" ng-model="consumerRole.appId" required>
</div>
</div> </div>
</div> <div class="form-group" valdr-form-group>
<div class="form-group" valdr-form-group> <label class="col-sm-2 control-label">
<label class="col-sm-2 control-label"> {{'Open.Manage.ManagedNamespace' | translate }}</label>
被管理的Namespace</label> <div class="col-sm-3">
<div class="col-sm-3"> <input type="text" class="form-control" ng-model="consumerRole.namespaceName">
<input type="text" class="form-control" ng-model="consumerRole.namespaceName"> <small>{{'Open.Manage.ManagedNamespaceTips' | translate }}</small>
<small>(非properties类型的namespace请加上类型后缀,例如apollo.xml)</small> </div>
</div> </div>
</div> <div class="form-group" valdr-form-group>
<div class="form-group" valdr-form-group> <label class="col-sm-2 control-label">
<label class="col-sm-2 control-label"> {{'Open.Manage.GrantType' | translate }}
授权类型
</label>
<div class="col-sm-3">
<label class="radio-inline">
<input type="radio" name="inlineRadioOptions" ng-value="'NamespaceRole'" ng-model="consumerRole.type">
Namespace
</label> </label>
<label class="radio-inline"> <div class="col-sm-3">
<input type="radio" name="inlineRadioOptions" ng-value="'AppRole'" ng-model="consumerRole.type"> <label class="radio-inline">
App <input type="radio" name="inlineRadioOptions" ng-value="'NamespaceRole'"
</label> ng-model="consumerRole.type">
</div> {{'Open.Manage.GrantType.Namespace' | translate }}
</div> </label>
<div class="form-group" valdr-form-group ng-show="consumerRole.type=='NamespaceRole'"> <label class="radio-inline">
<label class="col-sm-2 control-label"> <input type="radio" name="inlineRadioOptions" ng-value="'AppRole'"
环境 ng-model="consumerRole.type">
</label> {{'Open.Manage.GrantType.App' | translate }}
<div class="col-sm-10">
<div>
<label class="checkbox-inline" ng-repeat="env in envs">
<input type="checkbox" ng-checked="env.checked" ng-click="switchSelect(env)" />
{{env.env}}
</label> </label>
</div> </div>
<small>(不选择则所有环境都有权限,如果提示Namespace's role does not exist,请先打开该Namespace的授权页面触发一下权限的初始化动作)</small>
</div> </div>
</div> <div class="form-group" valdr-form-group ng-show="consumerRole.type=='NamespaceRole'">
<div class="form-group"> <label class="col-sm-2 control-label">
<div class="col-sm-offset-2 col-sm-9"> {{'Open.Manage.GrantEnv' | translate }}
<button type="submit" class="btn btn-primary" </label>
ng-disabled="submitBtnDisabled"> <div class="col-sm-10">
提交 <div>
</button> <label class="checkbox-inline" ng-repeat="env in envs">
<input type="checkbox" ng-checked="env.checked" ng-click="switchSelect(env)" />
{{env.env}}
</label>
</div>
<small>{{'Open.Manage.GrantEnvTips' | translate }}</small>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-9">
<button type="submit" class="btn btn-primary" ng-disabled="submitBtnDisabled">
{{'Common.Submit' | translate }}
</button>
</div>
</div> </div>
</div> </form>
</form>
</section> </section>
</section> </section>
<section class="panel-body text-center" ng-if="!isRootUser"> <section class="panel-body text-center" ng-if="!isRootUser">
<h4>当前页面只对Apollo管理员开放</h4> <h4>{{'Common.IsRootUser' | translate }}</h4>
</section> </section>
</div>
</div> </div>
</div>
<div ng-include="'../views/common/footer.html'"></div> <div ng-include="'../views/common/footer.html'"></div>
<!-- jquery.js --> <!-- jquery.js -->
<script src="../vendor/jquery.min.js" type="text/javascript"></script> <script src="../vendor/jquery.min.js" type="text/javascript"></script>
<!--angular--> <!--angular-->
<script src="../vendor/angular/angular.min.js"></script> <script src="../vendor/angular/angular.min.js"></script>
<script src="../vendor/angular/angular-route.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-resource.min.js"></script>
<script src="../vendor/angular/angular-toastr-1.4.1.tpls.min.js"></script> <script src="../vendor/angular/angular-toastr-1.4.1.tpls.min.js"></script>
<script src="../vendor/angular/loading-bar.min.js"></script> <script src="../vendor/angular/loading-bar.min.js"></script>
<script src="../vendor/angular/angular-cookies.min.js"></script>
<!--valdr-->
<script src="../vendor/valdr/valdr.min.js" type="text/javascript"></script> <script src="../vendor/angular/angular-translate.2.18.1/angular-translate.min.js"></script>
<script src="../vendor/valdr/valdr-message.min.js" type="text/javascript"></script> <script src="../vendor/angular/angular-translate.2.18.1/angular-translate-loader-static-files.min.js"></script>
<script src="../vendor/angular/angular-translate.2.18.1/angular-translate-storage-cookie.min.js"></script>
<!-- bootstrap.js --> <!--valdr-->
<script src="../vendor/bootstrap/js/bootstrap.min.js" type="text/javascript"></script> <script src="../vendor/valdr/valdr.min.js" type="text/javascript"></script>
<script src="../vendor/valdr/valdr-message.min.js" type="text/javascript"></script>
<script src="../vendor/lodash.min.js"></script>
<!-- bootstrap.js -->
<script src="../vendor/select2/select2.min.js" type="text/javascript"></script> <script src="../vendor/bootstrap/js/bootstrap.min.js" type="text/javascript"></script>
<!--biz-->
<!--must import--> <script src="../vendor/lodash.min.js"></script>
<script type="application/javascript" src="../scripts/app.js"></script>
<script type="application/javascript" src="../scripts/services/AppService.js"></script> <script src="../vendor/select2/select2.min.js" type="text/javascript"></script>
<script type="application/javascript" src="../scripts/services/EnvService.js"></script> <!--biz-->
<script type="application/javascript" src="../scripts/services/UserService.js"></script> <!--must import-->
<script type="application/javascript" src="../scripts/services/CommonService.js"></script> <script type="application/javascript" src="../scripts/app.js"></script>
<script type="application/javascript" src="../scripts/services/PermissionService.js"></script> <script type="application/javascript" src="../scripts/services/AppService.js"></script>
<script type="application/javascript" src="../scripts/services/OrganizationService.js"></script> <script type="application/javascript" src="../scripts/services/EnvService.js"></script>
<script type="application/javascript" src="../scripts/services/ConsumerService.js"></script> <script type="application/javascript" src="../scripts/services/UserService.js"></script>
<script type="application/javascript" src="../scripts/services/CommonService.js"></script>
<script type="application/javascript" src="../scripts/AppUtils.js"></script> <script type="application/javascript" src="../scripts/services/PermissionService.js"></script>
<script type="application/javascript" src="../scripts/services/OrganizationService.js"></script>
<script type="application/javascript" src="../scripts/PageCommon.js"></script> <script type="application/javascript" src="../scripts/services/ConsumerService.js"></script>
<script type="application/javascript" src="../scripts/directive/directive.js"></script>
<script type="application/javascript" src="../scripts/valdr.js"></script> <script type="application/javascript" src="../scripts/AppUtils.js"></script>
<script type="application/javascript" src="../scripts/controller/open/OpenManageController.js"></script> <script type="application/javascript" src="../scripts/PageCommon.js"></script>
<script type="application/javascript" src="../scripts/directive/directive.js"></script>
<script type="application/javascript" src="../scripts/valdr.js"></script>
<script type="application/javascript" src="../scripts/controller/open/OpenManageController.js"></script>
</body> </body>
</html>
</html>
\ No newline at end of file
appUtil.service('AppUtil', ['toastr', '$window', '$q', function (toastr, $window, $q) { appUtil.service('AppUtil', ['toastr', '$window', '$q', '$translate', function (toastr, $window, $q, $translate) {
function parseErrorMsg(response) { function parseErrorMsg(response) {
if (response.status == -1) { if (response.status == -1) {
return "您的登录信息已过期,请刷新页面后重试"; return $translate.instant('Common.LoginExpiredTips');
} }
var msg = "Code:" + response.status; var msg = "Code:" + response.status;
if (response.data.message != null) { if (response.data.message != null) {
...@@ -13,7 +13,7 @@ appUtil.service('AppUtil', ['toastr', '$window', '$q', function (toastr, $window ...@@ -13,7 +13,7 @@ appUtil.service('AppUtil', ['toastr', '$window', '$q', function (toastr, $window
function parsePureErrorMsg(response) { function parsePureErrorMsg(response) {
if (response.status == -1) { if (response.status == -1) {
return "您的登录信息已过期,请刷新页面后重试"; return $translate.instant('Common.LoginExpiredTips');
} }
if (response.data.message != null) { if (response.data.message != null) {
return response.data.message; return response.data.message;
...@@ -25,23 +25,23 @@ appUtil.service('AppUtil', ['toastr', '$window', '$q', function (toastr, $window ...@@ -25,23 +25,23 @@ appUtil.service('AppUtil', ['toastr', '$window', '$q', function (toastr, $window
var d = $q.defer(); var d = $q.defer();
if (requestBody) { if (requestBody) {
resource(requestParams, requestBody, function (result) { resource(requestParams, requestBody, function (result) {
d.resolve(result); d.resolve(result);
}, },
function (result) { function (result) {
d.reject(result); d.reject(result);
}); });
} else { } else {
resource(requestParams, function (result) { resource(requestParams, function (result) {
d.resolve(result); d.resolve(result);
}, },
function (result) { function (result) {
d.reject(result); d.reject(result);
}); });
} }
return d.promise; return d.promise;
} }
return { return {
errorMsg: parseErrorMsg, errorMsg: parseErrorMsg,
pureErrorMsg: parsePureErrorMsg, pureErrorMsg: parsePureErrorMsg,
...@@ -92,7 +92,7 @@ appUtil.service('AppUtil', ['toastr', '$window', '$q', function (toastr, $window ...@@ -92,7 +92,7 @@ appUtil.service('AppUtil', ['toastr', '$window', '$q', function (toastr, $window
hideModal: function (modal) { hideModal: function (modal) {
$(modal).modal("hide"); $(modal).modal("hide");
}, },
checkIPV4:function (ip) { checkIPV4: function (ip) {
return /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$|^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$|^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/.test(ip); return /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$|^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$|^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/.test(ip);
} }
} }
......
/**utils*/ /**utils*/
var appUtil = angular.module('app.util', ['toastr']); var appUtil = angular.module('app.util', ['toastr', 'ngCookies', 'pascalprecht.translate'])
.config(['$translateProvider', function ($translateProvider) {
$translateProvider.useSanitizeValueStrategy(null); // disable sanitization by default
$translateProvider.useCookieStorage();
$translateProvider.useStaticFilesLoader({
prefix: '/i18n/',
suffix: '.json'
});
$translateProvider.registerAvailableLanguageKeys(['en', 'zh-CN'], {
'zh-*': 'zh-CN',
'zh': 'zh-CN',
'en-*': 'en',
"*": "en"
})
$translateProvider.uniformLanguageTag('bcp47').determinePreferredLanguage();
}]);
/**service module 定义*/ /**service module 定义*/
var appService = angular.module('app.service', ['ngResource']); var appService = angular.module('app.service', ['ngResource', 'app.util'])
/** directive */ /** directive */
var directive_module = angular.module('apollo.directive', ['app.service', 'app.util', 'toastr']); var directive_module = angular.module('apollo.directive', ['app.service', 'app.util', 'toastr', 'pascalprecht.translate']);
/** page module 定义*/ /** page module 定义*/
// 首页 // 首页
var index_module = angular.module('index', ['toastr', 'app.service', 'apollo.directive', 'app.util', 'angular-loading-bar']); var index_module = angular.module('index', ['toastr', 'app.service', 'apollo.directive', 'app.util', 'angular-loading-bar', 'pascalprecht.translate']);
//项目主页 //项目主页
var application_module = angular.module('application', ['app.service', 'apollo.directive', 'app.util', 'toastr', 'angular-loading-bar', 'valdr', 'ui.ace']); var application_module = angular.module('application', ['app.service', 'apollo.directive', 'app.util', 'toastr', 'angular-loading-bar', 'valdr', 'ui.ace', 'ngSanitize']);
//创建项目页面 //创建项目页面
var app_module = angular.module('create_app', ['apollo.directive', 'toastr', 'app.service', 'app.util', 'angular-loading-bar', 'valdr']); var app_module = angular.module('create_app', ['apollo.directive', 'toastr', 'app.service', 'app.util', 'angular-loading-bar', 'valdr','pascalprecht.translate']);
//配置同步页面 //配置同步页面
var sync_item_module = angular.module('sync_item', ['app.service', 'apollo.directive', 'app.util', 'toastr', 'angular-loading-bar']); var sync_item_module = angular.module('sync_item', ['app.service', 'apollo.directive', 'app.util', 'toastr', 'angular-loading-bar']);
// 比较页面 // 比较页面
...@@ -27,7 +43,7 @@ var setting_module = angular.module('setting', ['app.service', 'apollo.directive ...@@ -27,7 +43,7 @@ var setting_module = angular.module('setting', ['app.service', 'apollo.directive
//role //role
var role_module = angular.module('role', ['app.service', 'apollo.directive', 'app.util', 'toastr', 'angular-loading-bar']); var role_module = angular.module('role', ['app.service', 'apollo.directive', 'app.util', 'toastr', 'angular-loading-bar']);
//cluster //cluster
var cluster_module = angular.module('cluster', ['app.service', 'apollo.directive', 'app.util', 'toastr', 'angular-loading-bar' , 'valdr']); var cluster_module = angular.module('cluster', ['app.service', 'apollo.directive', 'app.util', 'toastr', 'angular-loading-bar', 'valdr']);
//release history //release history
var release_history_module = angular.module('release_history', ['app.service', 'apollo.directive', 'app.util', 'toastr', 'angular-loading-bar']); var release_history_module = angular.module('release_history', ['app.service', 'apollo.directive', 'app.util', 'toastr', 'angular-loading-bar']);
//open manage //open manage
...@@ -35,7 +51,7 @@ var open_manage_module = angular.module('open_manage', ['app.service', 'apollo.d ...@@ -35,7 +51,7 @@ var open_manage_module = angular.module('open_manage', ['app.service', 'apollo.d
//user //user
var user_module = angular.module('user', ['apollo.directive', 'toastr', 'app.service', 'app.util', 'angular-loading-bar', 'valdr']); var user_module = angular.module('user', ['apollo.directive', 'toastr', 'app.service', 'app.util', 'angular-loading-bar', 'valdr']);
//login //login
var login_module = angular.module('login', ['toastr', 'app.util']); var login_module = angular.module('login', ['app.service', 'toastr', 'app.util', 'pascalprecht.translate']);
//delete app cluster namespace //delete app cluster namespace
var delete_app_cluster_namespace_module = angular.module('delete_app_cluster_namespace', ['app.service', 'apollo.directive', 'app.util', 'toastr', 'angular-loading-bar']); var delete_app_cluster_namespace_module = angular.module('delete_app_cluster_namespace', ['app.service', 'apollo.directive', 'app.util', 'toastr', 'angular-loading-bar']);
//system info //system info
......
app_module.controller('CreateAppController', app_module.controller('CreateAppController',
['$scope', '$window', 'toastr', 'AppService', 'AppUtil', 'OrganizationService','SystemRoleService','UserService', ['$scope', '$window', '$translate', 'toastr', 'AppService', 'AppUtil', 'OrganizationService', 'SystemRoleService', 'UserService',
createAppController]); createAppController]);
function createAppController($scope, $window, toastr, AppService, AppUtil, OrganizationService, SystemRoleService, UserService) { function createAppController($scope, $window, $translate, toastr, AppService, AppUtil, OrganizationService, SystemRoleService, UserService) {
$scope.app = {}; $scope.app = {};
$scope.submitBtnDisabled = false; $scope.submitBtnDisabled = false;
...@@ -27,10 +27,10 @@ function createAppController($scope, $window, toastr, AppService, AppUtil, Organ ...@@ -27,10 +27,10 @@ function createAppController($scope, $window, toastr, AppService, AppUtil, Organ
organizations.push(org); organizations.push(org);
}); });
$('#organization').select2({ $('#organization').select2({
placeholder: '请选择部门', placeholder: $translate.instant('Common.PleaseChooseDepartment'),
width: '100%', width: '100%',
data: organizations data: organizations
}); });
}, function (result) { }, function (result) {
toastr.error(AppUtil.errorMsg(result), "load organizations error"); toastr.error(AppUtil.errorMsg(result), "load organizations error");
}); });
...@@ -60,7 +60,7 @@ function createAppController($scope, $window, toastr, AppService, AppUtil, Organ ...@@ -60,7 +60,7 @@ function createAppController($scope, $window, toastr, AppService, AppUtil, Organ
var selectedOrg = $('#organization').select2('data')[0]; var selectedOrg = $('#organization').select2('data')[0];
if (!selectedOrg.id) { if (!selectedOrg.id) {
toastr.warning("请选择部门"); toastr.warning($translate.instant('Common.PleaseChooseDepartment'));
$scope.submitBtnDisabled = false; $scope.submitBtnDisabled = false;
return; return;
} }
...@@ -71,10 +71,10 @@ function createAppController($scope, $window, toastr, AppService, AppUtil, Organ ...@@ -71,10 +71,10 @@ function createAppController($scope, $window, toastr, AppService, AppUtil, Organ
// owner // owner
var owner = $('.ownerSelector').select2('data')[0]; var owner = $('.ownerSelector').select2('data')[0];
if ($scope.isOpenManageAppMasterRoleLimit) { if ($scope.isOpenManageAppMasterRoleLimit) {
owner = {id: $scope.currentUser.userId}; owner = { id: $scope.currentUser.userId };
} }
if (!owner) { if (!owner) {
toastr.warning("请选择应用负责人"); toastr.warning($translate.instant('Common.PleaseChooseOwner'));
$scope.submitBtnDisabled = false; $scope.submitBtnDisabled = false;
return; return;
} }
...@@ -84,7 +84,7 @@ function createAppController($scope, $window, toastr, AppService, AppUtil, Organ ...@@ -84,7 +84,7 @@ function createAppController($scope, $window, toastr, AppService, AppUtil, Organ
$scope.app.admins = []; $scope.app.admins = [];
var admins = $(".adminSelector").select2('data'); var admins = $(".adminSelector").select2('data');
if ($scope.isOpenManageAppMasterRoleLimit) { if ($scope.isOpenManageAppMasterRoleLimit) {
admins = [{id: $scope.currentUser.userId}]; admins = [{ id: $scope.currentUser.userId }];
} }
if (admins) { if (admins) {
admins.forEach(function (admin) { admins.forEach(function (admin) {
...@@ -93,14 +93,14 @@ function createAppController($scope, $window, toastr, AppService, AppUtil, Organ ...@@ -93,14 +93,14 @@ function createAppController($scope, $window, toastr, AppService, AppUtil, Organ
} }
AppService.create($scope.app).then(function (result) { AppService.create($scope.app).then(function (result) {
toastr.success('创建成功!'); toastr.success($translate.instant('Common.Created'));
setInterval(function () { setInterval(function () {
$scope.submitBtnDisabled = false; $scope.submitBtnDisabled = false;
$window.location.href = '/config.html?#appid=' + result.appId; $window.location.href = '/config.html?#appid=' + result.appId;
}, 1000); }, 1000);
}, function (result) { }, function (result) {
$scope.submitBtnDisabled = false; $scope.submitBtnDisabled = false;
toastr.error(AppUtil.errorMsg(result), '创建失败!'); toastr.error(AppUtil.errorMsg(result), $translate.instant('Common.CreateFailed'));
}); });
} }
......
cluster_module.controller('ClusterController', cluster_module.controller('ClusterController',
['$scope', '$location', '$window', 'toastr', 'AppService', 'EnvService', 'ClusterService', ['$scope', '$location', '$window', '$translate', 'toastr', 'AppService', 'EnvService', 'ClusterService',
'AppUtil', 'AppUtil',
function ($scope, $location, $window, toastr, AppService, EnvService, ClusterService, function ($scope, $location, $window, $translate, toastr, AppService, EnvService, ClusterService,
AppUtil) { AppUtil) {
var params = AppUtil.parseParams($location.$$url); var params = AppUtil.parseParams($location.$$url);
$scope.appId = params.appid; $scope.appId = params.appid;
$scope.step = 1; $scope.step = 1;
$scope.submitBtnDisabled = false;
EnvService.find_all_envs().then(function (result) {
$scope.envs = [];
result.forEach(function (env) {
$scope.envs.push({name: env, checked: false});
}); $scope.submitBtnDisabled = false;
$(".apollo-container").removeClass("hidden");
}, function (result) {
toastr.error(AppUtil.errorMsg(result), "加载环境信息出错");
});
$scope.clusterName = ''; EnvService.find_all_envs().then(function (result) {
$scope.envs = [];
result.forEach(function (env) {
$scope.envs.push({ name: env, checked: false });
$scope.switchChecked = function (env, $event) { });
env.checked = !env.checked; $(".apollo-container").removeClass("hidden");
$event.stopPropagation(); }, function (result) {
}; toastr.error(AppUtil.errorMsg(result), $translate.instant('Cluster.LoadingEnvironmentError'));
});
$scope.toggleEnvCheckedStatus = function (env) { $scope.clusterName = '';
env.checked = !env.checked;
};
$scope.create = function () { $scope.switchChecked = function (env, $event) {
env.checked = !env.checked;
$event.stopPropagation();
};
var noEnvChecked = true; $scope.toggleEnvCheckedStatus = function (env) {
$scope.envs.forEach(function (env) { env.checked = !env.checked;
if (env.checked) { };
noEnvChecked = false;
$scope.submitBtnDisabled = true;
ClusterService.create_cluster($scope.appId, env.name,
{
name: $scope.clusterName,
appId: $scope.appId
}).then(function (result) {
toastr.success(env.name, "集群创建成功");
$scope.step = 2;
$scope.submitBtnDisabled = false;
}, function (result) {
toastr.error(AppUtil.errorMsg(result), "集群创建失败");
$scope.submitBtnDisabled = false;
})
}
});
if (noEnvChecked){ $scope.create = function () {
toastr.warning("请选择环境");
}
}; var noEnvChecked = true;
$scope.envs.forEach(function (env) {
if (env.checked) {
noEnvChecked = false;
$scope.submitBtnDisabled = true;
ClusterService.create_cluster($scope.appId, env.name,
{
name: $scope.clusterName,
appId: $scope.appId
}).then(function (result) {
toastr.success(env.name, $translate.instant('Cluster.ClusterCreated'));
$scope.step = 2;
$scope.submitBtnDisabled = false;
}, function (result) {
toastr.error(AppUtil.errorMsg(result), $translate.instant('Cluster.ClusterCreateFailed'));
$scope.submitBtnDisabled = false;
})
}
});
}]); if (noEnvChecked) {
toastr.warning($translate.instant('Cluster.PleaseChooseEnvironment'));
}
};
}]);
delete_app_cluster_namespace_module.controller('DeleteAppClusterNamespaceController', delete_app_cluster_namespace_module.controller('DeleteAppClusterNamespaceController',
['$scope', 'toastr', 'AppUtil', 'AppService', 'ClusterService', 'NamespaceService', 'PermissionService', ['$scope', '$translate', 'toastr', 'AppUtil', 'AppService', 'ClusterService', 'NamespaceService', 'PermissionService',
DeleteAppClusterNamespaceController]); DeleteAppClusterNamespaceController]);
function DeleteAppClusterNamespaceController($scope, toastr, AppUtil, AppService, ClusterService, NamespaceService, PermissionService) { function DeleteAppClusterNamespaceController($scope, $translate, toastr, AppUtil, AppService, ClusterService, NamespaceService, PermissionService) {
$scope.app = {}; $scope.app = {};
$scope.deleteAppBtnDisabled = true; $scope.deleteAppBtnDisabled = true;
...@@ -24,13 +24,13 @@ function DeleteAppClusterNamespaceController($scope, toastr, AppUtil, AppService ...@@ -24,13 +24,13 @@ function DeleteAppClusterNamespaceController($scope, toastr, AppUtil, AppService
function initPermission() { function initPermission() {
PermissionService.has_root_permission() PermissionService.has_root_permission()
.then(function (result) { .then(function (result) {
$scope.isRootUser = result.hasPermission; $scope.isRootUser = result.hasPermission;
}) })
} }
function getAppInfo() { function getAppInfo() {
if (!$scope.app.appId) { if (!$scope.app.appId) {
toastr.warning("请输入appId"); toastr.warning($translate.instant('Delete.PleaseEnterAppId'));
return; return;
} }
...@@ -38,95 +38,119 @@ function DeleteAppClusterNamespaceController($scope, toastr, AppUtil, AppService ...@@ -38,95 +38,119 @@ function DeleteAppClusterNamespaceController($scope, toastr, AppUtil, AppService
AppService.load($scope.app.appId).then(function (result) { AppService.load($scope.app.appId).then(function (result) {
if (!result.appId) { if (!result.appId) {
toastr.warning("AppId: " + $scope.app.appId + " 不存在!"); toastr.warning($translate.instant('Delete.AppIdNotFound', { appId: $scope.app.appId }));
$scope.deleteAppBtnDisabled = true; $scope.deleteAppBtnDisabled = true;
return; return;
} }
$scope.app.info = "应用名:" + result.name + " 部门:" + result.orgName + '(' + result.orgId + ')' + " 负责人:" + result.ownerName; $scope.app.info = $translate.instant('Delete.AppInfoContent', {
appName: result.name,
departmentName: result.orgName,
departmentId: result.orgId,
ownerName: result.ownerName
});
$scope.deleteAppBtnDisabled = false; $scope.deleteAppBtnDisabled = false;
}, function (result) { }, function (result) {
AppUtil.showErrorMsg(result); AppUtil.showErrorMsg(result);
}); });
} }
function deleteApp() { function deleteApp() {
if (!$scope.app.appId) { if (!$scope.app.appId) {
toastr.warning("请输入appId"); toastr.warning($translate.instant('Delete.PleaseEnterAppId'));
return; return;
} }
if (confirm("确认删除AppId: " + $scope.app.appId + "")) { if (confirm($translate.instant('Delete.ConfirmDeleteAppId', { appId: $scope.app.appId }))) {
AppService.delete_app($scope.app.appId).then(function (result) { AppService.delete_app($scope.app.appId).then(function (result) {
toastr.success("删除成功"); toastr.success($translate.instant('Delete.Deleted'));
$scope.deleteAppBtnDisabled = true; $scope.deleteAppBtnDisabled = true;
}, function (result) { }, function (result) {
AppUtil.showErrorMsg(result); AppUtil.showErrorMsg(result);
}) })
} }
} }
function getClusterInfo() { function getClusterInfo() {
if (!$scope.cluster.appId || !$scope.cluster.env || !$scope.cluster.name) { if (!$scope.cluster.appId || !$scope.cluster.env || !$scope.cluster.name) {
toastr.warning("请输入appId、环境和集群名称"); toastr.warning($translate.instant('Delete.PleaseEnterAppIdAndEnvAndCluster'));
return; return;
} }
$scope.cluster.info = ""; $scope.cluster.info = "";
ClusterService.load_cluster($scope.cluster.appId, $scope.cluster.env, $scope.cluster.name).then(function (result) { ClusterService.load_cluster($scope.cluster.appId, $scope.cluster.env, $scope.cluster.name).then(function (result) {
$scope.cluster.info = "AppId:" + result.appId+ " 环境:" + $scope.cluster.env + " 集群名称:" + result.name; $scope.cluster.info = $translate.instant('Delete.ClusterInfoContent', {
appId: result.appId,
env: $scope.cluster.env,
clusterName: result.name
});
$scope.deleteClusterBtnDisabled = false; $scope.deleteClusterBtnDisabled = false;
}, function (result) { }, function (result) {
AppUtil.showErrorMsg(result); AppUtil.showErrorMsg(result);
}); });
} }
function deleteCluster() { function deleteCluster() {
if (!$scope.cluster.appId || !$scope.cluster.env || !$scope.cluster.name) { if (!$scope.cluster.appId || !$scope.cluster.env || !$scope.cluster.name) {
toastr.warning("请输入appId、环境和集群名称"); toastr.warning($translate.instant('Delete.PleaseEnterAppIdAndEnvAndCluster'));
return; return;
} }
if (confirm("确认删除集群?appId: " + $scope.cluster.appId + " 环境:" + $scope.cluster.env + " 集群名称:" + $scope.cluster.name)) { var confirmTip = $translate.instant('Delete.ConfirmDeleteCluster', {
ClusterService.delete_cluster($scope.cluster.appId, $scope.cluster.env, $scope.cluster.name).then(function (result) { appId: $scope.cluster.appId,
toastr.success("删除成功"); env: $scope.cluster.env,
$scope.deleteClusterBtnDisabled = true; clusterName: $scope.cluster.name
}, function (result) { });
AppUtil.showErrorMsg(result);
}) if (confirm(confirmTip)) {
} ClusterService.delete_cluster($scope.cluster.appId, $scope.cluster.env, $scope.cluster.name).then(function (result) {
toastr.success($translate.instant('Delete.Deleted'));
$scope.deleteClusterBtnDisabled = true;
}, function (result) {
AppUtil.showErrorMsg(result);
})
}
} }
function getAppNamespaceInfo() { function getAppNamespaceInfo() {
if (!$scope.appNamespace.appId || !$scope.appNamespace.name) { if (!$scope.appNamespace.appId || !$scope.appNamespace.name) {
toastr.warning("请输入appId和AppNamespace名称"); toastr.warning($translate.instant('Delete.PleaseEnterAppIdAndNamespace'));
return; return;
} }
$scope.appNamespace.info = ""; $scope.appNamespace.info = "";
NamespaceService.loadAppNamespace($scope.appNamespace.appId, $scope.appNamespace.name).then(function (result) { NamespaceService.loadAppNamespace($scope.appNamespace.appId, $scope.appNamespace.name).then(function (result) {
$scope.appNamespace.info = "AppId:" + result.appId+ " AppNamespace名称:" + result.name + " isPublic:" + result.isPublic; $scope.appNamespace.info = $translate.instant('Delete.AppNamespaceInfoContent', {
appId: result.appId,
namespace: result.name,
isPublic: result.isPublic
});
$scope.deleteAppNamespaceBtnDisabled = false; $scope.deleteAppNamespaceBtnDisabled = false;
}, function (result) { }, function (result) {
AppUtil.showErrorMsg(result); AppUtil.showErrorMsg(result);
}); });
} }
function deleteAppNamespace() { function deleteAppNamespace() {
if (!$scope.appNamespace.appId || !$scope.appNamespace.name) { if (!$scope.appNamespace.appId || !$scope.appNamespace.name) {
toastr.warning("请输入appId和AppNamespace名称"); toastr.warning($translate.instant('Delete.PleaseEnterAppIdAndNamespace'));
return; return;
} }
if (confirm("确认删除所有环境的AppNamespace和Namespace?appId: " + $scope.appNamespace.appId + " 环境:所有环境" + " AppNamespace名称:" + $scope.appNamespace.name)) { var confirmTip = $translate.instant('Delete.ConfirmDeleteNamespace', {
NamespaceService.deleteAppNamespace($scope.appNamespace.appId, $scope.appNamespace.name).then(function (result) { appId: $scope.appNamespace.appId,
toastr.success("删除成功"); namespace: $scope.appNamespace.name
$scope.deleteAppNamespaceBtnDisabled = true; });
}, function (result) { if (confirm(confirmTip)) {
AppUtil.showErrorMsg(result); NamespaceService.deleteAppNamespace($scope.appNamespace.appId, $scope.appNamespace.name).then(function (result) {
}) toastr.success($translate.instant('Delete.Deleted'));
} $scope.deleteAppNamespaceBtnDisabled = true;
}, function (result) {
AppUtil.showErrorMsg(result);
})
}
} }
} }
index_module.controller('IndexController', ['$scope', '$window', 'toastr', 'AppUtil', 'AppService', index_module.controller('IndexController', ['$scope', '$window', '$translate', 'toastr', 'AppUtil', 'AppService',
'UserService', 'FavoriteService', 'UserService', 'FavoriteService',
IndexController]); IndexController]);
function IndexController($scope, $window, toastr, AppUtil, AppService, UserService, FavoriteService) { function IndexController($scope, $window, $translate, toastr, AppUtil, AppService, UserService, FavoriteService) {
$scope.userId = ''; $scope.userId = '';
...@@ -15,13 +15,13 @@ function IndexController($scope, $window, toastr, AppUtil, AppService, UserServi ...@@ -15,13 +15,13 @@ function IndexController($scope, $window, toastr, AppUtil, AppService, UserServi
$scope.toTop = toTop; $scope.toTop = toTop;
$scope.deleteFavorite = deleteFavorite; $scope.deleteFavorite = deleteFavorite;
function initCreateApplicationPermission() { function initCreateApplicationPermission() {
AppService.has_create_application_role($scope.userId).then( AppService.has_create_application_role($scope.userId).then(
function (value) { function (value) {
$scope.hasCreateApplicationPermission = value.hasCreateApplicationPermission; $scope.hasCreateApplicationPermission = value.hasCreateApplicationPermission;
}, },
function (reason) { function (reason) {
toastr.warning(AppUtil.errorMsg(reason), "获取创建应用权限信息失败"); toastr.warning(AppUtil.errorMsg(reason), $translate.instant('Index.GetCreateAppRoleFailed'));
} }
) )
} }
...@@ -70,7 +70,7 @@ function IndexController($scope, $window, toastr, AppUtil, AppService, UserServi ...@@ -70,7 +70,7 @@ function IndexController($scope, $window, toastr, AppUtil, AppService, UserServi
$scope.favoritesPage += 1; $scope.favoritesPage += 1;
$scope.hasMoreFavorites = result.length == size; $scope.hasMoreFavorites = result.length == size;
if ($scope.favoritesPage == 1){ if ($scope.favoritesPage == 1) {
$("#app-list").removeClass("hidden"); $("#app-list").removeClass("hidden");
} }
...@@ -92,7 +92,7 @@ function IndexController($scope, $window, toastr, AppUtil, AppService, UserServi ...@@ -92,7 +92,7 @@ function IndexController($scope, $window, toastr, AppUtil, AppService, UserServi
}); });
result.forEach(function (favorite) { result.forEach(function (favorite) {
var app = appIdMapApp[favorite.appId]; var app = appIdMapApp[favorite.appId];
if (!app){ if (!app) {
return; return;
} }
app.favoriteId = favorite.id; app.favoriteId = favorite.id;
...@@ -122,7 +122,7 @@ function IndexController($scope, $window, toastr, AppUtil, AppService, UserServi ...@@ -122,7 +122,7 @@ function IndexController($scope, $window, toastr, AppUtil, AppService, UserServi
userVisitedApps.forEach(function (appId) { userVisitedApps.forEach(function (appId) {
var app = appIdMapApp[appId]; var app = appIdMapApp[appId];
if (app){ if (app) {
$scope.visitedApps.push(app); $scope.visitedApps.push(app);
} }
}); });
...@@ -145,7 +145,7 @@ function IndexController($scope, $window, toastr, AppUtil, AppService, UserServi ...@@ -145,7 +145,7 @@ function IndexController($scope, $window, toastr, AppUtil, AppService, UserServi
function toTop(favoriteId) { function toTop(favoriteId) {
FavoriteService.toTop(favoriteId).then(function () { FavoriteService.toTop(favoriteId).then(function () {
toastr.success("置顶成功"); toastr.success($translate.instant('Index.Topped'));
refreshFavorites(); refreshFavorites();
}) })
...@@ -153,7 +153,7 @@ function IndexController($scope, $window, toastr, AppUtil, AppService, UserServi ...@@ -153,7 +153,7 @@ function IndexController($scope, $window, toastr, AppUtil, AppService, UserServi
function deleteFavorite(favoriteId) { function deleteFavorite(favoriteId) {
FavoriteService.deleteFavorite(favoriteId).then(function () { FavoriteService.deleteFavorite(favoriteId).then(function () {
toastr.success("取消收藏成功"); toastr.success($translate.instant('Index.CancelledFavorite'));
refreshFavorites(); refreshFavorites();
}) })
} }
......
login_module.controller('LoginController', login_module.controller('LoginController',
['$scope', '$window', '$location', 'toastr', 'AppUtil', ['$scope', '$window', '$location', '$translate', 'toastr', 'AppUtil',
LoginController]); LoginController]);
function LoginController($scope, $window, $location, toastr, AppUtil) { function LoginController($scope, $window, $location, $translate, toastr, AppUtil) {
if ($location.$$url) { if ($location.$$url) {
var params = AppUtil.parseParams($location.$$url); var params = AppUtil.parseParams($location.$$url);
if (params.error) { if (params.error) {
$scope.info = "用户名或密码错误"; $translate('Login.UserNameOrPasswordIncorrect').then(function(result) {
$scope.info = result;
});
} }
if (params.logout) { if (params.logout) {
$scope.info = "登出成功"; $translate('Login.LogoutSuccessfully').then(function(result) {
$scope.info = result;
});
} }
} }
......
namespace_module.controller("LinkNamespaceController", namespace_module.controller("LinkNamespaceController",
['$scope', '$location', '$window', 'toastr', 'AppService', 'AppUtil', 'NamespaceService', ['$scope', '$location', '$window', '$translate', 'toastr', 'AppService', 'AppUtil', 'NamespaceService',
'PermissionService', 'CommonService', 'PermissionService', 'CommonService',
function ($scope, $location, $window, toastr, AppService, AppUtil, NamespaceService, function ($scope, $location, $window, $translate, toastr, AppService, AppUtil, NamespaceService,
PermissionService, CommonService) { PermissionService, CommonService) {
var params = AppUtil.parseParams($location.$$url); var params = AppUtil.parseParams($location.$$url);
$scope.appId = params.appid; $scope.appId = params.appid;
$scope.type = 'link'; $scope.type = 'link';
$scope.step = 1; $scope.step = 1;
$scope.submitBtnDisabled = false; $scope.submitBtnDisabled = false;
$scope.appendNamespacePrefix = true; $scope.appendNamespacePrefix = true;
PermissionService.has_root_permission().then(function (result) { PermissionService.has_root_permission().then(function (result) {
$scope.hasRootPermission = result.hasPermission; $scope.hasRootPermission = result.hasPermission;
}); });
CommonService.getPageSetting().then(function (setting) { CommonService.getPageSetting().then(function (setting) {
$scope.pageSetting = setting; $scope.pageSetting = setting;
}); });
NamespaceService.find_public_namespaces().then(function (result) { NamespaceService.find_public_namespaces().then(function (result) {
var publicNamespaces = []; var publicNamespaces = [];
result.forEach(function (item) { result.forEach(function (item) {
var namespace = {}; var namespace = {};
namespace.id = item.name; namespace.id = item.name;
namespace.text = item.name; namespace.text = item.name;
publicNamespaces.push(namespace); publicNamespaces.push(namespace);
}); });
$('#namespaces').select2({ $('#namespaces').select2({
placeholder: '请选择Namespace', placeholder: $translate.instant('Namespace.PleaseChooseNamespace'),
width: '100%', width: '100%',
data: publicNamespaces data: publicNamespaces
}); });
$(".apollo-container").removeClass("hidden"); $(".apollo-container").removeClass("hidden");
}, function (result) { }, function (result) {
toastr.error(AppUtil.errorMsg(result), "load public namespace error"); toastr.error(AppUtil.errorMsg(result), $translate.instant('Namespace.LoadingPublicNamespaceError'));
}); });
AppService.load($scope.appId).then(function (result) { AppService.load($scope.appId).then(function (result) {
$scope.appBaseInfo = result; $scope.appBaseInfo = result;
$scope.appBaseInfo.namespacePrefix = result.orgId + '.'; $scope.appBaseInfo.namespacePrefix = result.orgId + '.';
}, function (result) { }, function (result) {
toastr.error(AppUtil.errorMsg(result), "加载App信息出错"); toastr.error(AppUtil.errorMsg(result), $translate.instant('Namespace.LoadingAppInfoError'));
}); });
$scope.appNamespace = { $scope.appNamespace = {
appId: $scope.appId, appId: $scope.appId,
name: '', name: '',
comment: '', comment: '',
isPublic: true, isPublic: true,
format: 'properties' format: 'properties'
}; };
$scope.switchNSType = function (type) { $scope.switchNSType = function (type) {
$scope.appNamespace.isPublic = type; $scope.appNamespace.isPublic = type;
}; };
$scope.concatNamespace = function () { $scope.concatNamespace = function () {
if (!$scope.appBaseInfo) { if (!$scope.appBaseInfo) {
return ''; return '';
} }
return $scope.appBaseInfo.namespacePrefix + return $scope.appBaseInfo.namespacePrefix +
($scope.appNamespace.name ? $scope.appNamespace.name : ''); ($scope.appNamespace.name ? $scope.appNamespace.name : '');
}; };
var selectedClusters = []; var selectedClusters = [];
$scope.collectSelectedClusters = function (data) { $scope.collectSelectedClusters = function (data) {
selectedClusters = data; selectedClusters = data;
}; };
$scope.createNamespace = function () { $scope.createNamespace = function () {
if ($scope.type == 'link') { if ($scope.type == 'link') {
if (selectedClusters.length == 0) { if (selectedClusters.length == 0) {
toastr.warning("请选择集群"); toastr.warning($translate.instant('Namespace.PleaseChooseCluster'));
return; return;
} }
if ($scope.namespaceType == 1) { if ($scope.namespaceType == 1) {
var selectedNamespaceName = $('#namespaces').select2('data')[0].id; var selectedNamespaceName = $('#namespaces').select2('data')[0].id;
if (!selectedNamespaceName) { if (!selectedNamespaceName) {
toastr.warning("请选择Namespace"); toastr.warning($translate.instant('Namespace.PleaseChooseNamespace'));
return; return;
} }
$scope.namespaceName = selectedNamespaceName; $scope.namespaceName = selectedNamespaceName;
} }
var namespaceCreationModels = []; var namespaceCreationModels = [];
selectedClusters.forEach(function (cluster) { selectedClusters.forEach(function (cluster) {
namespaceCreationModels.push({ namespaceCreationModels.push({
env: cluster.env, env: cluster.env,
namespace: { namespace: {
appId: $scope.appId, appId: $scope.appId,
clusterName: cluster.clusterName, clusterName: cluster.clusterName,
namespaceName: $scope.namespaceName namespaceName: $scope.namespaceName
} }
}); });
}); });
$scope.submitBtnDisabled = true; $scope.submitBtnDisabled = true;
NamespaceService.createNamespace($scope.appId, namespaceCreationModels) NamespaceService.createNamespace($scope.appId, namespaceCreationModels)
.then(function (result) { .then(function (result) {
toastr.success("创建成功"); toastr.success($translate.instant('Common.Created'));
$scope.step = 2; $scope.step = 2;
setInterval(function () { setInterval(function () {
$scope.submitBtnDisabled = false; $scope.submitBtnDisabled = false;
$window.location.href = $window.location.href =
'/namespace/role.html?#appid=' + $scope.appId '/namespace/role.html?#appid=' + $scope.appId
+ "&namespaceName=" + $scope.namespaceName; + "&namespaceName=" + $scope.namespaceName;
}, 1000); }, 1000);
}, function (result) { }, function (result) {
$scope.submitBtnDisabled = false; $scope.submitBtnDisabled = false;
toastr.error(AppUtil.errorMsg(result)); toastr.error(AppUtil.errorMsg(result));
}); });
} else { } else {
var namespaceNameLength = $scope.concatNamespace().length; var namespaceNameLength = $scope.concatNamespace().length;
if (namespaceNameLength > 32) { if (namespaceNameLength > 32) {
toastr.error("namespace名称不能大于32个字符. 部门前缀" var errorTip = $translate.instant('Namespace.CheckNamespaceNameLengthTip', {
+ (namespaceNameLength - $scope.appNamespace.name.length) departmentLength: namespaceNameLength - $scope.appNamespace.name.length,
+ "个字符, 名称" + $scope.appNamespace.name.length + "个字符" namespaceLength: $scope.appNamespace.name.length
); });
return; toastr.error(errorTip);
} return;
}
$scope.submitBtnDisabled = true;
//only append namespace prefix for public app namespace $scope.submitBtnDisabled = true;
var appendNamespacePrefix = $scope.appNamespace.isPublic ? $scope.appendNamespacePrefix : false; //only append namespace prefix for public app namespace
NamespaceService.createAppNamespace($scope.appId, $scope.appNamespace, appendNamespacePrefix).then( var appendNamespacePrefix = $scope.appNamespace.isPublic ? $scope.appendNamespacePrefix : false;
function (result) { NamespaceService.createAppNamespace($scope.appId, $scope.appNamespace, appendNamespacePrefix).then(
$scope.step = 2; function (result) {
setTimeout(function () { $scope.step = 2;
$scope.submitBtnDisabled = false; setTimeout(function () {
$window.location.href = $scope.submitBtnDisabled = false;
"/namespace/role.html?#/appid=" + $scope.appId $window.location.href =
+ "&namespaceName=" + result.name; "/namespace/role.html?#/appid=" + $scope.appId
}, 1000); + "&namespaceName=" + result.name;
}, function (result) { }, 1000);
$scope.submitBtnDisabled = false; }, function (result) {
toastr.error(AppUtil.errorMsg(result), "创建失败"); $scope.submitBtnDisabled = false;
}); toastr.error(AppUtil.errorMsg(result), $translate.instant('Common.CreateFailed'));
} });
}
};
};
$scope.namespaceType = 1;
$scope.selectNamespaceType = function (type) { $scope.namespaceType = 1;
$scope.namespaceType = type; $scope.selectNamespaceType = function (type) {
}; $scope.namespaceType = type;
};
$scope.back = function () {
$window.location.href = '/config.html?#appid=' + $scope.appId; $scope.back = function () {
}; $window.location.href = '/config.html?#appid=' + $scope.appId;
};
$scope.switchType = function (type) {
$scope.type = type; $scope.switchType = function (type) {
}; $scope.type = type;
}]); };
}]);
server_config_module.controller('ServerConfigController', server_config_module.controller('ServerConfigController',
['$scope', '$window', 'toastr', 'ServerConfigService', 'AppUtil', ['$scope', '$window', '$translate', 'toastr', 'ServerConfigService', 'AppUtil',
function ($scope, $window, toastr, ServerConfigService, AppUtil) { function ($scope, $window, $translate, toastr, ServerConfigService, AppUtil) {
$scope.serverConfig = {}; $scope.serverConfig = {};
$scope.saveBtnDisabled = true; $scope.saveBtnDisabled = true;
$scope.create = function () { $scope.create = function () {
ServerConfigService.create($scope.serverConfig).then(function (result) { ServerConfigService.create($scope.serverConfig).then(function (result) {
toastr.success("保存成功"); toastr.success($translate.instant('ServiceConfig.Saved'));
$scope.saveBtnDisabled = true; $scope.saveBtnDisabled = true;
$scope.serverConfig = result; $scope.serverConfig = result;
}, function (result) { }, function (result) {
toastr.error(AppUtil.errorMsg(result), "保存失败"); toastr.error(AppUtil.errorMsg(result), $translate.instant('ServiceConfig.SaveFailed'));
}); });
}; };
$scope.getServerConfigInfo = function () { $scope.getServerConfigInfo = function () {
if (!$scope.serverConfig.key) { if (!$scope.serverConfig.key) {
toastr.warning("请输入key"); toastr.warning($translate.instant('ServiceConfig.PleaseEnterKey'));
return; return;
} }
ServerConfigService.getServerConfigInfo($scope.serverConfig.key).then(function (result) { ServerConfigService.getServerConfigInfo($scope.serverConfig.key).then(function (result) {
$scope.saveBtnDisabled = false; $scope.saveBtnDisabled = false;
if (!result.key) { if (!result.key) {
toastr.info("Key: " + $scope.serverConfig.key + " 不存在,点击保存后会创建该配置项"); toastr.info($translate.instant('ServiceConfig.KeyNotExistsAndCreateTip', { key: $scope.serverConfig.key }));
return; return;
} }
toastr.info("Key: " + $scope.serverConfig.key + " 已存在,点击保存后会覆盖该配置项"); toastr.info($translate.instant('ServiceConfig.KeyExistsAndSaveTip', { key: $scope.serverConfig.key }));
$scope.serverConfig = result; $scope.serverConfig = result;
}, function (result) { }, function (result) {
AppUtil.showErrorMsg(result); AppUtil.showErrorMsg(result);
}) })
} }
}]); }]);
setting_module.controller('SettingController', setting_module.controller('SettingController',
['$scope', '$location', 'toastr', ['$scope', '$location', '$translate', 'toastr',
'AppService', 'AppUtil', 'PermissionService', 'AppService', 'AppUtil', 'PermissionService',
'OrganizationService', 'OrganizationService',
SettingController]); SettingController]);
function SettingController($scope, $location, toastr, function SettingController($scope, $location, $translate, toastr,
AppService, AppUtil, PermissionService, AppService, AppUtil, PermissionService,
OrganizationService) { OrganizationService) {
var params = AppUtil.parseParams($location.$$url); var params = AppUtil.parseParams($location.$$url);
var $orgWidget = $('#organization'); var $orgWidget = $('#organization');
...@@ -49,10 +49,10 @@ function SettingController($scope, $location, toastr, ...@@ -49,10 +49,10 @@ function SettingController($scope, $location, toastr,
organizations.push(org); organizations.push(org);
}); });
$orgWidget.select2({ $orgWidget.select2({
placeholder: '请选择部门', placeholder: $translate.instant('Common.PleaseChooseDepartment'),
width: '100%', width: '100%',
data: organizations data: organizations
}); });
}, function (result) { }, function (result) {
toastr.error(AppUtil.errorMsg(result), "load organizations error"); toastr.error(AppUtil.errorMsg(result), "load organizations error");
}); });
...@@ -107,7 +107,7 @@ function SettingController($scope, $location, toastr, ...@@ -107,7 +107,7 @@ function SettingController($scope, $location, toastr,
var $ownerSelector = $('.ownerSelector'); var $ownerSelector = $('.ownerSelector');
var defaultSelectedDOM = '<option value="' + app.ownerName + '" selected="selected">' + app.ownerName var defaultSelectedDOM = '<option value="' + app.ownerName + '" selected="selected">' + app.ownerName
+ '</option>'; + '</option>';
$ownerSelector.append(defaultSelectedDOM); $ownerSelector.append(defaultSelectedDOM);
$ownerSelector.trigger('change'); $ownerSelector.trigger('change');
} }
...@@ -115,21 +115,21 @@ function SettingController($scope, $location, toastr, ...@@ -115,21 +115,21 @@ function SettingController($scope, $location, toastr,
function assignMasterRoleToUser() { function assignMasterRoleToUser() {
var user = $('.' + $scope.userSelectWidgetId).select2('data')[0]; var user = $('.' + $scope.userSelectWidgetId).select2('data')[0];
if (!user) { if (!user) {
toastr.warning("请选择用户"); toastr.warning($translate.instant('App.Setting.PleaseChooseUser'));
return; return;
} }
var toAssignMasterRoleUser = user.id; var toAssignMasterRoleUser = user.id;
$scope.submitBtnDisabled = true; $scope.submitBtnDisabled = true;
PermissionService.assign_master_role($scope.pageContext.appId, PermissionService.assign_master_role($scope.pageContext.appId,
toAssignMasterRoleUser) toAssignMasterRoleUser)
.then(function (result) { .then(function (result) {
$scope.submitBtnDisabled = false; $scope.submitBtnDisabled = false;
toastr.success("添加成功"); toastr.success($translate.instant('App.Setting.Added'));
$scope.appRoleUsers.masterUsers.push({userId: toAssignMasterRoleUser}); $scope.appRoleUsers.masterUsers.push({ userId: toAssignMasterRoleUser });
$('.' + $scope.userSelectWidgetId).select2("val", ""); $('.' + $scope.userSelectWidgetId).select2("val", "");
}, function (result) { }, function (result) {
$scope.submitBtnDisabled = false; $scope.submitBtnDisabled = false;
toastr.error(AppUtil.errorMsg(result), "添加失败"); toastr.error(AppUtil.errorMsg(result), $translate.instant('App.Setting.AddFailed'));
}); });
} }
...@@ -140,10 +140,10 @@ function SettingController($scope, $location, toastr, ...@@ -140,10 +140,10 @@ function SettingController($scope, $location, toastr,
} }
PermissionService.remove_master_role($scope.pageContext.appId, user) PermissionService.remove_master_role($scope.pageContext.appId, user)
.then(function (result) { .then(function (result) {
toastr.success("删除成功"); toastr.success($translate.instant('App.Setting.Deleted'));
removeUserFromList($scope.appRoleUsers.masterUsers, user); removeUserFromList($scope.appRoleUsers.masterUsers, user);
}, function (result) { }, function (result) {
toastr.error(AppUtil.errorMsg(result), "删除失败"); toastr.error(AppUtil.errorMsg(result), $translate.instant('App.Setting.DeleteFailed'));
}); });
} }
...@@ -177,7 +177,7 @@ function SettingController($scope, $location, toastr, ...@@ -177,7 +177,7 @@ function SettingController($scope, $location, toastr,
var selectedOrg = $orgWidget.select2('data')[0]; var selectedOrg = $orgWidget.select2('data')[0];
if (!selectedOrg.id) { if (!selectedOrg.id) {
toastr.warning("请选择部门"); toastr.warning($translate.instant('Common.PleaseChooseDepartment'));
return; return;
} }
...@@ -187,13 +187,13 @@ function SettingController($scope, $location, toastr, ...@@ -187,13 +187,13 @@ function SettingController($scope, $location, toastr,
// owner // owner
var owner = $('.ownerSelector').select2('data')[0]; var owner = $('.ownerSelector').select2('data')[0];
if (!owner) { if (!owner) {
toastr.warning("请选择应用负责人"); toastr.warning($translate.instant('Common.PleaseChooseOwner'));
return; return;
} }
app.ownerName = owner.id; app.ownerName = owner.id;
AppService.update(app).then(function (app) { AppService.update(app).then(function (app) {
toastr.success("修改成功"); toastr.success($translate.instant('App.Setting.Modified'));
initApplication(); initApplication();
$scope.display.app.edit = false; $scope.display.app.edit = false;
$scope.submitBtnDisabled = false; $scope.submitBtnDisabled = false;
......
user_module.controller('UserController', user_module.controller('UserController',
['$scope', '$window', 'toastr', 'AppUtil', 'UserService', ['$scope', '$window', '$translate', 'toastr', 'AppUtil', 'UserService',
UserController]); UserController]);
function UserController($scope, $window, toastr, AppUtil, UserService) { function UserController($scope, $window, $translate, toastr, AppUtil, UserService) {
$scope.user = {}; $scope.user = {};
$scope.createOrUpdateUser = function () { $scope.createOrUpdateUser = function () {
UserService.createOrUpdateUser($scope.user).then(function (result) { UserService.createOrUpdateUser($scope.user).then(function (result) {
toastr.success("创建用户成功"); toastr.success($translate.instant('UserMange.Created'));
}, function (result) { }, function (result) {
AppUtil.showErrorMsg(result, "创建用户失败"); AppUtil.showErrorMsg(result, $translate.instant('UserMange.CreateFailed'));
}) })
} }
......
application_module.controller("ConfigBaseInfoController", application_module.controller("ConfigBaseInfoController",
['$rootScope', '$scope', '$window', '$location', 'toastr', 'EventManager', 'UserService', ['$rootScope', '$scope', '$window', '$location', '$translate', 'toastr', 'EventManager', 'UserService',
'AppService', 'AppService',
'FavoriteService', 'FavoriteService',
'PermissionService', 'PermissionService',
'AppUtil', ConfigBaseInfoController]); 'AppUtil', ConfigBaseInfoController]);
function ConfigBaseInfoController($rootScope, $scope, $window, $location, toastr, EventManager, UserService, AppService, function ConfigBaseInfoController($rootScope, $scope, $window, $location, $translate, toastr, EventManager, UserService, AppService,
FavoriteService, FavoriteService,
PermissionService, PermissionService,
AppUtil) { AppUtil) {
var urlParams = AppUtil.parseParams($location.$$url); var urlParams = AppUtil.parseParams($location.$$url);
var appId = urlParams.appid; var appId = urlParams.appid;
...@@ -36,16 +36,16 @@ function ConfigBaseInfoController($rootScope, $scope, $window, $location, toastr ...@@ -36,16 +36,16 @@ function ConfigBaseInfoController($rootScope, $scope, $window, $location, toastr
sessionStorage.setItem( sessionStorage.setItem(
$rootScope.pageContext.appId, $rootScope.pageContext.appId,
JSON.stringify({ JSON.stringify({
env: $rootScope.pageContext.env, env: $rootScope.pageContext.env,
cluster: $rootScope.pageContext.clusterName cluster: $rootScope.pageContext.clusterName
})); }));
UserService.load_user().then(function (result) { UserService.load_user().then(function (result) {
$rootScope.pageContext.userId = result.userId; $rootScope.pageContext.userId = result.userId;
loadAppInfo(); loadAppInfo();
handleFavorite(); handleFavorite();
}, function (result) { }, function (result) {
toastr.error(AppUtil.errorMsg(result), "获取用户登录信息失败"); toastr.error(AppUtil.errorMsg(result), $translate.instant('Config.GetUserInfoFailed'));
}); });
handlePermission(); handlePermission();
...@@ -74,13 +74,13 @@ function ConfigBaseInfoController($rootScope, $scope, $window, $location, toastr ...@@ -74,13 +74,13 @@ function ConfigBaseInfoController($rootScope, $scope, $window, $location, toastr
var count = 0; var count = 0;
$scope.missEnvs.forEach(function (env) { $scope.missEnvs.forEach(function (env) {
AppService.create_remote(env, $scope.appBaseInfo).then(function (result) { AppService.create_remote(env, $scope.appBaseInfo).then(function (result) {
toastr.success(env, '创建成功'); toastr.success(env, $translate.instant('Common.Created'));
count++; count++;
if (count == $scope.missEnvs.length) { if (count == $scope.missEnvs.length) {
location.reload(true); location.reload(true);
} }
}, function (result) { }, function (result) {
toastr.error(AppUtil.errorMsg(result), '创建失败:' + env); toastr.error(AppUtil.errorMsg(result), `${$translate.instant('Common.CreateFailed')}:${env}`);
count++; count++;
if (count == $scope.missEnvs.length) { if (count == $scope.missEnvs.length) {
location.reload(true); location.reload(true);
...@@ -92,12 +92,12 @@ function ConfigBaseInfoController($rootScope, $scope, $window, $location, toastr ...@@ -92,12 +92,12 @@ function ConfigBaseInfoController($rootScope, $scope, $window, $location, toastr
$scope.createMissingNamespaces = function () { $scope.createMissingNamespaces = function () {
AppService.create_missing_namespaces($rootScope.pageContext.appId, $rootScope.pageContext.env, AppService.create_missing_namespaces($rootScope.pageContext.appId, $rootScope.pageContext.env,
$rootScope.pageContext.clusterName).then(function (result) { $rootScope.pageContext.clusterName).then(function (result) {
toastr.success("创建成功"); toastr.success($translate.instant('Common.Created'));
location.reload(true); location.reload(true);
}, function (result) { }, function (result) {
toastr.error(AppUtil.errorMsg(result), "创建失败"); toastr.error(AppUtil.errorMsg(result), $translate.instant('Common.CreateFailed'));
} }
); );
}; };
function findMissEnvs() { function findMissEnvs() {
...@@ -106,7 +106,7 @@ function ConfigBaseInfoController($rootScope, $scope, $window, $location, toastr ...@@ -106,7 +106,7 @@ function ConfigBaseInfoController($rootScope, $scope, $window, $location, toastr
$scope.missEnvs = AppUtil.collectData(result); $scope.missEnvs = AppUtil.collectData(result);
if ($scope.missEnvs.length > 0) { if ($scope.missEnvs.length > 0) {
toastr.warning("当前项目有环境缺失,请点击页面左侧『补缺环境』补齐数据"); toastr.warning($translate.instant('Config.ProjectMissEnvInfos'));
} }
$scope.findMissingNamespaces(); $scope.findMissingNamespaces();
...@@ -121,13 +121,13 @@ function ConfigBaseInfoController($rootScope, $scope, $window, $location, toastr ...@@ -121,13 +121,13 @@ function ConfigBaseInfoController($rootScope, $scope, $window, $location, toastr
$scope.missingNamespaces = []; $scope.missingNamespaces = [];
// only check missing private namespaces when app exists in current env // only check missing private namespaces when app exists in current env
if ($rootScope.pageContext.env && $scope.missEnvs.indexOf($rootScope.pageContext.env) === -1) { if ($rootScope.pageContext.env && $scope.missEnvs.indexOf($rootScope.pageContext.env) === -1) {
AppService.find_missing_namespaces($rootScope.pageContext.appId, $rootScope.pageContext.env, AppService.find_missing_namespaces($rootScope.pageContext.appId, $rootScope.pageContext.env,
$rootScope.pageContext.clusterName).then(function (result) { $rootScope.pageContext.clusterName).then(function (result) {
$scope.missingNamespaces = AppUtil.collectData(result); $scope.missingNamespaces = AppUtil.collectData(result);
if ($scope.missingNamespaces.length > 0) { if ($scope.missingNamespaces.length > 0) {
toastr.warning("当前环境有Namespace缺失,请点击页面左侧『补缺Namespace』补齐数据"); toastr.warning($translate.instant('Config.ProjectMissNamespaceInfos'));
} }
}); });
} }
}; };
...@@ -164,7 +164,7 @@ function ConfigBaseInfoController($rootScope, $scope, $window, $location, toastr ...@@ -164,7 +164,7 @@ function ConfigBaseInfoController($rootScope, $scope, $window, $location, toastr
currentUserVisitedApps.push($rootScope.pageContext.appId); currentUserVisitedApps.push($rootScope.pageContext.appId);
localStorage.setItem(VISITED_APPS_STORAGE_KEY, localStorage.setItem(VISITED_APPS_STORAGE_KEY,
JSON.stringify(visitedAppsObject)); JSON.stringify(visitedAppsObject));
} }
} }
...@@ -176,7 +176,7 @@ function ConfigBaseInfoController($rootScope, $scope, $window, $location, toastr ...@@ -176,7 +176,7 @@ function ConfigBaseInfoController($rootScope, $scope, $window, $location, toastr
var nodes = AppUtil.collectData(result); var nodes = AppUtil.collectData(result);
if (!nodes || nodes.length == 0) { if (!nodes || nodes.length == 0) {
toastr.error("系统出错,请重试或联系系统负责人"); toastr.error($translate.instant('Config.SystemError'));
return; return;
} }
//default first env if session storage is empty //default first env if session storage is empty
...@@ -197,7 +197,7 @@ function ConfigBaseInfoController($rootScope, $scope, $window, $location, toastr ...@@ -197,7 +197,7 @@ function ConfigBaseInfoController($rootScope, $scope, $window, $location, toastr
//如果env下面只有一个default集群则不显示集群列表 //如果env下面只有一个default集群则不显示集群列表
if (env.clusters && env.clusters.length == 1 && env.clusters[0].name if (env.clusters && env.clusters.length == 1 && env.clusters[0].name
== 'default') { == 'default') {
if ($rootScope.pageContext.env == env.env) { if ($rootScope.pageContext.env == env.env) {
node.state = {}; node.state = {};
node.state.selected = true; node.state.selected = true;
...@@ -213,14 +213,14 @@ function ConfigBaseInfoController($rootScope, $scope, $window, $location, toastr ...@@ -213,14 +213,14 @@ function ConfigBaseInfoController($rootScope, $scope, $window, $location, toastr
//default selection from session storage or first env & first cluster //default selection from session storage or first env & first cluster
if ($rootScope.pageContext.env == env.env && $rootScope.pageContext.clusterName if ($rootScope.pageContext.env == env.env && $rootScope.pageContext.clusterName
== cluster.name) { == cluster.name) {
clusterNode.state = {}; clusterNode.state = {};
clusterNode.state.selected = true; clusterNode.state.selected = true;
} }
clusterNode.text = cluster.name; clusterNode.text = cluster.name;
parentNode.push(node.text); parentNode.push(node.text);
clusterNode.tags = ['集群']; clusterNode.tags = [$translate.instant('Common.Cluster')];
clusterNode.parentNode = parentNode; clusterNode.parentNode = parentNode;
clusterNodes.push(clusterNode); clusterNodes.push(clusterNode);
...@@ -232,42 +232,42 @@ function ConfigBaseInfoController($rootScope, $scope, $window, $location, toastr ...@@ -232,42 +232,42 @@ function ConfigBaseInfoController($rootScope, $scope, $window, $location, toastr
//init treeview //init treeview
$('#treeview').treeview({ $('#treeview').treeview({
color: "#797979", color: "#797979",
showBorder: true, showBorder: true,
data: navTree, data: navTree,
levels: 99, levels: 99,
expandIcon: '', expandIcon: '',
collapseIcon: '', collapseIcon: '',
showTags: true, showTags: true,
onNodeSelected: function (event, data) { onNodeSelected: function (event, data) {
if (!data.parentNode) {//first nav node if (!data.parentNode) {//first nav node
$rootScope.pageContext.env = data.text; $rootScope.pageContext.env = data.text;
$rootScope.pageContext.clusterName = $rootScope.pageContext.clusterName =
'default'; 'default';
} else {//second cluster node } else {//second cluster node
$rootScope.pageContext.env = $rootScope.pageContext.env =
data.parentNode[0]; data.parentNode[0];
$rootScope.pageContext.clusterName = $rootScope.pageContext.clusterName =
data.text; data.text;
} }
//storage scene //storage scene
sessionStorage.setItem( sessionStorage.setItem(
$rootScope.pageContext.appId, $rootScope.pageContext.appId,
JSON.stringify({ JSON.stringify({
env: $rootScope.pageContext.env, env: $rootScope.pageContext.env,
cluster: $rootScope.pageContext.clusterName cluster: $rootScope.pageContext.clusterName
})); }));
$window.location.href = "/config.html#/appid=" $window.location.href = "/config.html#/appid="
+ $rootScope.pageContext.appId + $rootScope.pageContext.appId
+ "&env=" + $rootScope.pageContext.env + "&env=" + $rootScope.pageContext.env
+ "&cluster=" + $rootScope.pageContext.clusterName; + "&cluster=" + $rootScope.pageContext.clusterName;
EventManager.emit(EventManager.EventType.REFRESH_NAMESPACE); EventManager.emit(EventManager.EventType.REFRESH_NAMESPACE);
EventManager.emit(EventManager.EventType.CHANGE_ENV_CLUSTER); EventManager.emit(EventManager.EventType.CHANGE_ENV_CLUSTER);
$rootScope.showSideBar = false; $rootScope.showSideBar = false;
} }
}); });
var envMapClusters = {}; var envMapClusters = {};
navTree.forEach(function (node) { navTree.forEach(function (node) {
...@@ -289,7 +289,7 @@ function ConfigBaseInfoController($rootScope, $scope, $window, $location, toastr ...@@ -289,7 +289,7 @@ function ConfigBaseInfoController($rootScope, $scope, $window, $location, toastr
$rootScope.envMapClusters = envMapClusters; $rootScope.envMapClusters = envMapClusters;
}, function (result) { }, function (result) {
toastr.error(AppUtil.errorMsg(result), "系统出错,请重试或联系系统负责人"); toastr.error(AppUtil.errorMsg(result), $translate.instant('Config.SystemError'));
}); });
} }
...@@ -297,7 +297,7 @@ function ConfigBaseInfoController($rootScope, $scope, $window, $location, toastr ...@@ -297,7 +297,7 @@ function ConfigBaseInfoController($rootScope, $scope, $window, $location, toastr
function handleFavorite() { function handleFavorite() {
FavoriteService.findFavorites($rootScope.pageContext.userId, FavoriteService.findFavorites($rootScope.pageContext.userId,
$rootScope.pageContext.appId) $rootScope.pageContext.appId)
.then(function (result) { .then(function (result) {
if (result && result.length) { if (result && result.length) {
$scope.favoriteId = result[0].id; $scope.favoriteId = result[0].id;
...@@ -314,9 +314,9 @@ function ConfigBaseInfoController($rootScope, $scope, $window, $location, toastr ...@@ -314,9 +314,9 @@ function ConfigBaseInfoController($rootScope, $scope, $window, $location, toastr
FavoriteService.addFavorite(favorite) FavoriteService.addFavorite(favorite)
.then(function (result) { .then(function (result) {
$scope.favoriteId = result.id; $scope.favoriteId = result.id;
toastr.success("收藏成功"); toastr.success($translate.instant('Config.FavoriteSuccessfully'));
}, function (result) { }, function (result) {
toastr.error(AppUtil.errorMsg(result), "收藏失败"); toastr.error(AppUtil.errorMsg(result), $translate.instant('Config.FavoriteFailed'));
}) })
}; };
...@@ -324,9 +324,9 @@ function ConfigBaseInfoController($rootScope, $scope, $window, $location, toastr ...@@ -324,9 +324,9 @@ function ConfigBaseInfoController($rootScope, $scope, $window, $location, toastr
FavoriteService.deleteFavorite($scope.favoriteId) FavoriteService.deleteFavorite($scope.favoriteId)
.then(function (result) { .then(function (result) {
$scope.favoriteId = 0; $scope.favoriteId = 0;
toastr.success("取消收藏成功"); toastr.success($translate.instant('Config.CancelledFavorite'));
}, function (result) { }, function (result) {
toastr.error(AppUtil.errorMsg(result), "取消收藏失败"); toastr.error(AppUtil.errorMsg(result), $translate.instant('Config.CancelFavoriteFailed'));
}) })
}; };
} }
......
application_module.controller("ConfigNamespaceController", application_module.controller("ConfigNamespaceController",
['$rootScope', '$scope', 'toastr', 'AppUtil', 'EventManager', 'ConfigService', ['$rootScope', '$scope', '$translate', 'toastr', 'AppUtil', 'EventManager', 'ConfigService',
'PermissionService', 'UserService', 'NamespaceBranchService', 'NamespaceService', 'PermissionService', 'UserService', 'NamespaceBranchService', 'NamespaceService',
controller]); controller]);
function controller($rootScope, $scope, toastr, AppUtil, EventManager, ConfigService, function controller($rootScope, $scope, $translate, toastr, AppUtil, EventManager, ConfigService,
PermissionService, UserService, NamespaceBranchService, NamespaceService) { PermissionService, UserService, NamespaceBranchService, NamespaceService) {
$scope.rollback = rollback; $scope.rollback = rollback;
$scope.preDeleteItem = preDeleteItem; $scope.preDeleteItem = preDeleteItem;
...@@ -24,12 +24,10 @@ function controller($rootScope, $scope, toastr, AppUtil, EventManager, ConfigSer ...@@ -24,12 +24,10 @@ function controller($rootScope, $scope, toastr, AppUtil, EventManager, ConfigSer
init(); init();
function init() { function init() {
initRole(); initRole();
initUser(); initUser();
initPublishInfo(); initPublishInfo();
} }
function initRole() { function initRole() {
PermissionService.get_app_role_users($rootScope.pageContext.appId) PermissionService.get_app_role_users($rootScope.pageContext.appId)
.then(function (result) { .then(function (result) {
...@@ -87,14 +85,14 @@ function controller($rootScope, $scope, toastr, AppUtil, EventManager, ConfigSer ...@@ -87,14 +85,14 @@ function controller($rootScope, $scope, toastr, AppUtil, EventManager, ConfigSer
} }
EventManager.subscribe(EventManager.EventType.REFRESH_NAMESPACE, EventManager.subscribe(EventManager.EventType.REFRESH_NAMESPACE,
function (context) { function (context) {
if (context.namespace) { if (context.namespace) {
refreshSingleNamespace(context.namespace); refreshSingleNamespace(context.namespace);
} else { } else {
refreshAllNamespaces(); refreshAllNamespaces();
} }
}); });
function refreshAllNamespaces() { function refreshAllNamespaces() {
if ($rootScope.pageContext.env == '') { if ($rootScope.pageContext.env == '') {
...@@ -102,17 +100,17 @@ function controller($rootScope, $scope, toastr, AppUtil, EventManager, ConfigSer ...@@ -102,17 +100,17 @@ function controller($rootScope, $scope, toastr, AppUtil, EventManager, ConfigSer
} }
ConfigService.load_all_namespaces($rootScope.pageContext.appId, ConfigService.load_all_namespaces($rootScope.pageContext.appId,
$rootScope.pageContext.env, $rootScope.pageContext.env,
$rootScope.pageContext.clusterName).then( $rootScope.pageContext.clusterName).then(
function (result) { function (result) {
$scope.namespaces = result; $scope.namespaces = result;
$('.config-item-container').removeClass('hide'); $('.config-item-container').removeClass('hide');
initPublishInfo(); initPublishInfo();
}, function (result) { }, function (result) {
toastr.error(AppUtil.errorMsg(result), "加载配置信息出错"); toastr.error(AppUtil.errorMsg(result), $translate.instant('Config.LoadingAllNamespaceError'));
}); });
} }
function refreshSingleNamespace(namespace) { function refreshSingleNamespace(namespace) {
...@@ -121,25 +119,25 @@ function controller($rootScope, $scope, toastr, AppUtil, EventManager, ConfigSer ...@@ -121,25 +119,25 @@ function controller($rootScope, $scope, toastr, AppUtil, EventManager, ConfigSer
} }
ConfigService.load_namespace($rootScope.pageContext.appId, ConfigService.load_namespace($rootScope.pageContext.appId,
$rootScope.pageContext.env, $rootScope.pageContext.env,
$rootScope.pageContext.clusterName, $rootScope.pageContext.clusterName,
namespace.baseInfo.namespaceName).then( namespace.baseInfo.namespaceName).then(
function (result) { function (result) {
$scope.namespaces.forEach(function (namespace, index) { $scope.namespaces.forEach(function (namespace, index) {
if (namespace.baseInfo.namespaceName == result.baseInfo.namespaceName) { if (namespace.baseInfo.namespaceName == result.baseInfo.namespaceName) {
result.showNamespaceBody = true; result.showNamespaceBody = true;
result.initialized = true; result.initialized = true;
result.show = namespace.show; result.show = namespace.show;
$scope.namespaces[index] = result; $scope.namespaces[index] = result;
} }
}); });
initPublishInfo(); initPublishInfo();
}, function (result) { }, function (result) {
toastr.error(AppUtil.errorMsg(result), "加载配置信息出错"); toastr.error(AppUtil.errorMsg(result), $translate.instant('Config.LoadingAllNamespaceError'));
}); });
} }
function rollback() { function rollback() {
...@@ -165,19 +163,19 @@ function controller($rootScope, $scope, toastr, AppUtil, EventManager, ConfigSer ...@@ -165,19 +163,19 @@ function controller($rootScope, $scope, toastr, AppUtil, EventManager, ConfigSer
function deleteItem() { function deleteItem() {
ConfigService.delete_item($rootScope.pageContext.appId, ConfigService.delete_item($rootScope.pageContext.appId,
$rootScope.pageContext.env, $rootScope.pageContext.env,
$scope.toOperationNamespace.baseInfo.clusterName, $scope.toOperationNamespace.baseInfo.clusterName,
$scope.toOperationNamespace.baseInfo.namespaceName, $scope.toOperationNamespace.baseInfo.namespaceName,
toDeleteItemId).then( toDeleteItemId).then(
function (result) { function (result) {
toastr.success("删除成功!"); toastr.success($translate.instant('Config.Deleted'));
EventManager.emit(EventManager.EventType.REFRESH_NAMESPACE, EventManager.emit(EventManager.EventType.REFRESH_NAMESPACE,
{ {
namespace: $scope.toOperationNamespace namespace: $scope.toOperationNamespace
}); });
}, function (result) { }, function (result) {
toastr.error(AppUtil.errorMsg(result), "删除失败"); toastr.error(AppUtil.errorMsg(result), $translate.instant('Config.DeleteFailed'));
}); });
} }
//修改配置 //修改配置
...@@ -276,17 +274,17 @@ function controller($rootScope, $scope, toastr, AppUtil, EventManager, ConfigSer ...@@ -276,17 +274,17 @@ function controller($rootScope, $scope, toastr, AppUtil, EventManager, ConfigSer
function createBranch() { function createBranch() {
NamespaceBranchService.createBranch($rootScope.pageContext.appId, NamespaceBranchService.createBranch($rootScope.pageContext.appId,
$rootScope.pageContext.env, $rootScope.pageContext.env,
$rootScope.pageContext.clusterName, $rootScope.pageContext.clusterName,
toCreateBranchNamespace.baseInfo.namespaceName) toCreateBranchNamespace.baseInfo.namespaceName)
.then(function (result) { .then(function (result) {
toastr.success("创建灰度成功"); toastr.success($translate.instant('Config.GrayscaleCreated'));
EventManager.emit(EventManager.EventType.REFRESH_NAMESPACE, EventManager.emit(EventManager.EventType.REFRESH_NAMESPACE,
{ {
namespace: toCreateBranchNamespace namespace: toCreateBranchNamespace
}); });
}, function (result) { }, function (result) {
toastr.error(AppUtil.errorMsg(result), "创建灰度失败"); toastr.error(AppUtil.errorMsg(result), $translate.instant('Config.GrayscaleCreateFailed'));
}) })
} }
...@@ -300,43 +298,43 @@ function controller($rootScope, $scope, toastr, AppUtil, EventManager, ConfigSer ...@@ -300,43 +298,43 @@ function controller($rootScope, $scope, toastr, AppUtil, EventManager, ConfigSer
function deleteBranch() { function deleteBranch() {
NamespaceBranchService.deleteBranch($rootScope.pageContext.appId, NamespaceBranchService.deleteBranch($rootScope.pageContext.appId,
$rootScope.pageContext.env, $rootScope.pageContext.env,
$rootScope.pageContext.clusterName, $rootScope.pageContext.clusterName,
$scope.toDeleteBranch.baseInfo.namespaceName, $scope.toDeleteBranch.baseInfo.namespaceName,
$scope.toDeleteBranch.baseInfo.clusterName $scope.toDeleteBranch.baseInfo.clusterName
) )
.then(function (result) { .then(function (result) {
toastr.success("删除成功"); toastr.success($translate.instant('Config.BranchDeleted'));
EventManager.emit(EventManager.EventType.REFRESH_NAMESPACE, EventManager.emit(EventManager.EventType.REFRESH_NAMESPACE,
{ {
namespace: $scope.toDeleteBranch.parentNamespace namespace: $scope.toDeleteBranch.parentNamespace
}); });
}, function (result) { }, function (result) {
toastr.error(AppUtil.errorMsg(result), "删除分支失败"); toastr.error(AppUtil.errorMsg(result), $translate.instant('Config.BranchDeleteFailed'));
}) })
} }
EventManager.subscribe(EventManager.EventType.EMERGENCY_PUBLISH, EventManager.subscribe(EventManager.EventType.EMERGENCY_PUBLISH,
function (context) { function (context) {
AppUtil.showModal("#emergencyPublishAlertDialog"); AppUtil.showModal("#emergencyPublishAlertDialog");
$scope.emergencyPublishContext = context; $scope.emergencyPublishContext = context;
}); });
function emergencyPublish() { function emergencyPublish() {
if ($scope.emergencyPublishContext.mergeAndPublish) { if ($scope.emergencyPublishContext.mergeAndPublish) {
EventManager.emit(EventManager.EventType.MERGE_AND_PUBLISH_NAMESPACE, EventManager.emit(EventManager.EventType.MERGE_AND_PUBLISH_NAMESPACE,
{ {
branch: $scope.emergencyPublishContext.namespace, branch: $scope.emergencyPublishContext.namespace,
isEmergencyPublish: true isEmergencyPublish: true
}); });
} else { } else {
EventManager.emit(EventManager.EventType.PUBLISH_NAMESPACE, EventManager.emit(EventManager.EventType.PUBLISH_NAMESPACE,
{ {
namespace: $scope.emergencyPublishContext.namespace, namespace: $scope.emergencyPublishContext.namespace,
isEmergencyPublish: true isEmergencyPublish: true
}); });
} }
} }
...@@ -355,15 +353,13 @@ function controller($rootScope, $scope, toastr, AppUtil, EventManager, ConfigSer ...@@ -355,15 +353,13 @@ function controller($rootScope, $scope, toastr, AppUtil, EventManager, ConfigSer
var appId = namespace.appId; var appId = namespace.appId;
var clusterName = namespace.clusterName; var clusterName = namespace.clusterName;
var url = '/config.html?#/appid=' + appId + '&env=' + $scope.pageContext.env + '&cluster=' var url = '/config.html?#/appid=' + appId + '&env=' + $scope.pageContext.env + '&cluster='
+ clusterName; + clusterName;
namespaceTips.push("<a target='_blank' href=\'" + url + "\'>AppId = " + appId + ", 集群 = " + clusterName namespaceTips.push("<a target='_blank' href=\'" + url + "\'>AppId = " + appId + ", Cluster = " + clusterName
+ ", Namespace = " + namespace.namespaceName + "</a>"); + ", Namespace = " + namespace.namespaceName + "</a>");
}); });
$scope.deleteNamespaceContext.detailReason = $scope.deleteNamespaceContext.detailReason = $translate.instant('Config.DeleteNamespaceFailedTips') + "<br>" + namespaceTips.join("<br>");
"以下应用已关联此公共Namespace,必须先删除全部已关联的Namespace才能删除公共Namespace。<br>"
+ namespaceTips.join("<br>");
AppUtil.showModal('#deleteNamespaceDenyForPublicNamespaceDialog'); AppUtil.showModal('#deleteNamespaceDenyForPublicNamespaceDialog');
} }
......
diff_item_module.controller("DiffItemController", diff_item_module.controller("DiffItemController",
['$scope', '$location', '$window', 'toastr', 'AppService', 'AppUtil', 'ConfigService', ['$scope', '$location', '$window', '$translate', 'toastr', 'AppService', 'AppUtil', 'ConfigService',
function ($scope, $location, $window, toastr, AppService, AppUtil, ConfigService) { function ($scope, $location, $window, $translate, toastr, AppService, AppUtil, ConfigService) {
var params = AppUtil.parseParams($location.$$url); var params = AppUtil.parseParams($location.$$url);
$scope.pageContext = { $scope.pageContext = {
appId: params.appid, appId: params.appid,
env: params.env, env: params.env,
clusterName: params.clusterName, clusterName: params.clusterName,
namespaceName: params.namespaceName namespaceName: params.namespaceName
}; };
var sourceItems = []; var sourceItems = [];
$scope.diff = diff; $scope.diff = diff;
$scope.syncBtnDisabled = false; $scope.syncBtnDisabled = false;
$scope.showCommentDiff = false; $scope.showCommentDiff = false;
$scope.collectSelectedClusters = collectSelectedClusters; $scope.collectSelectedClusters = collectSelectedClusters;
$scope.syncItemNextStep = syncItemNextStep; $scope.syncItemNextStep = syncItemNextStep;
$scope.backToAppHomePage = backToAppHomePage; $scope.backToAppHomePage = backToAppHomePage;
$scope.switchSelect = switchSelect; $scope.switchSelect = switchSelect;
$scope.showText = showText; $scope.showText = showText;
$scope.itemsKeyedByKey = {}; $scope.itemsKeyedByKey = {};
$scope.syncData = { $scope.syncData = {
syncToNamespaces: [], syncToNamespaces: [],
syncItems: [] syncItems: []
}; };
function diff() { function diff() {
$scope.syncData = parseSyncSourceData(); $scope.syncData = parseSyncSourceData();
if ($scope.syncData.syncToNamespaces.length < 2) { if ($scope.syncData.syncToNamespaces.length < 2) {
toastr.warning("请至少选择两个集群"); toastr.warning($translate.instant('Config.Diff.PleaseChooseTwoCluster'));
return; return;
} }
$scope.syncData.syncToNamespaces.forEach(function (namespace) { $scope.syncData.syncToNamespaces.forEach(function (namespace) {
ConfigService.find_items(namespace.appId, ConfigService.find_items(namespace.appId,
namespace.env, namespace.env,
namespace.clusterName, namespace.clusterName,
namespace.namespaceName).then(function (result) { namespace.namespaceName).then(function (result) {
result.forEach(function (item) { result.forEach(function (item) {
var itemsKeyedByClusterName = $scope.itemsKeyedByKey[item.key] || {}; var itemsKeyedByClusterName = $scope.itemsKeyedByKey[item.key] || {};
itemsKeyedByClusterName[namespace.env + ':' + namespace.clusterName + ':' + namespace.namespaceName] = item; itemsKeyedByClusterName[namespace.env + ':' + namespace.clusterName + ':' + namespace.namespaceName] = item;
$scope.itemsKeyedByKey[item.key] = itemsKeyedByClusterName; $scope.itemsKeyedByKey[item.key] = itemsKeyedByClusterName;
}); });
}); });
}); });
$scope.syncItemNextStep(1); $scope.syncItemNextStep(1);
}
var selectedClusters = [];
function collectSelectedClusters(data) {
selectedClusters = data;
}
function parseSyncSourceData() {
var syncData = {
syncToNamespaces: [],
syncItems: []
};
var namespaceName = $scope.pageContext.namespaceName;
selectedClusters.forEach(function (cluster) {
if (cluster.checked) {
cluster.clusterName = cluster.name;
cluster.namespaceName = namespaceName;
syncData.syncToNamespaces.push(cluster);
} }
});
return syncData; var selectedClusters = [];
}
////// flow control /////// function collectSelectedClusters(data) {
selectedClusters = data;
}
function parseSyncSourceData() {
var syncData = {
syncToNamespaces: [],
syncItems: []
};
var namespaceName = $scope.pageContext.namespaceName;
selectedClusters.forEach(function (cluster) {
if (cluster.checked) {
cluster.clusterName = cluster.name;
cluster.namespaceName = namespaceName;
syncData.syncToNamespaces.push(cluster);
}
});
return syncData;
}
////// flow control ///////
$scope.syncItemStep = 1; $scope.syncItemStep = 1;
function syncItemNextStep(offset) { function syncItemNextStep(offset) {
$scope.syncItemStep += offset; $scope.syncItemStep += offset;
} }
function backToAppHomePage() { function backToAppHomePage() {
$window.location.href = '/config.html?#appid=' + $scope.pageContext.appId; $window.location.href = '/config.html?#appid=' + $scope.pageContext.appId;
} }
function switchSelect(o) { function switchSelect(o) {
o.checked = !o.checked; o.checked = !o.checked;
} }
function showText(text) { function showText(text) {
$scope.text = text; $scope.text = text;
AppUtil.showModal('#showTextModal'); AppUtil.showModal('#showTextModal');
} }
}]); }]);
release_history_module.controller("ReleaseHistoryController", release_history_module.controller("ReleaseHistoryController",
['$scope', '$location', 'AppUtil', ['$scope', '$location', '$translate', 'AppUtil',
'ReleaseService', 'ConfigService', 'ReleaseHistoryService', releaseHistoryController 'ReleaseService', 'ConfigService', 'ReleaseHistoryService', releaseHistoryController
]); ]);
function releaseHistoryController($scope, $location, AppUtil, function releaseHistoryController($scope, $location, $translate, AppUtil,
ReleaseService, ConfigService, ReleaseHistoryService) { ReleaseService, ConfigService, ReleaseHistoryService) {
var params = AppUtil.parseParams($location.$$url); var params = AppUtil.parseParams($location.$$url);
$scope.pageContext = { $scope.pageContext = {
...@@ -48,10 +48,10 @@ function releaseHistoryController($scope, $location, AppUtil, ...@@ -48,10 +48,10 @@ function releaseHistoryController($scope, $location, AppUtil,
return; return;
} }
ReleaseHistoryService.findReleaseHistoryByNamespace($scope.pageContext.appId, ReleaseHistoryService.findReleaseHistoryByNamespace($scope.pageContext.appId,
$scope.pageContext.env, $scope.pageContext.env,
$scope.pageContext.clusterName, $scope.pageContext.clusterName,
$scope.pageContext.namespaceName, $scope.pageContext.namespaceName,
$scope.page, PAGE_SIZE) $scope.page, PAGE_SIZE)
.then(function (result) { .then(function (result) {
if ($scope.page == 0) { if ($scope.page == 0) {
$(".release-history").removeClass('hidden'); $(".release-history").removeClass('hidden');
...@@ -75,7 +75,7 @@ function releaseHistoryController($scope, $location, AppUtil, ...@@ -75,7 +75,7 @@ function releaseHistoryController($scope, $location, AppUtil,
} else if ($scope.pageContext.releaseId == history.releaseId) { } else if ($scope.pageContext.releaseId == history.releaseId) {
// text namespace doesn't support ALL view // text namespace doesn't support ALL view
if (!$scope.isTextNamespace) { if (!$scope.isTextNamespace) {
history.viewType = CONFIG_VIEW_TYPE.ALL; history.viewType = CONFIG_VIEW_TYPE.ALL;
} }
defaultToShowReleaseHistory = history; defaultToShowReleaseHistory = history;
} }
...@@ -87,19 +87,19 @@ function releaseHistoryController($scope, $location, AppUtil, ...@@ -87,19 +87,19 @@ function releaseHistoryController($scope, $location, AppUtil,
$scope.page = $scope.page + 1; $scope.page = $scope.page + 1;
}, function (result) { }, function (result) {
AppUtil.showErrorMsg(result, "加载发布历史信息出错"); AppUtil.showErrorMsg(result, $translate.instant('Config.History.LoadingHistoryError'));
}); });
} }
function loadNamespace() { function loadNamespace() {
ConfigService.load_namespace($scope.pageContext.appId, ConfigService.load_namespace($scope.pageContext.appId,
$scope.pageContext.env, $scope.pageContext.env,
$scope.pageContext.clusterName, $scope.pageContext.clusterName,
$scope.pageContext.namespaceName) $scope.pageContext.namespaceName)
.then(function (result) { .then(function (result) {
$scope.isTextNamespace = result.format != "properties"; $scope.isTextNamespace = result.format != "properties";
if ($scope.isTextNamespace) { if ($scope.isTextNamespace) {
fixTextNamespaceViewType(); fixTextNamespaceViewType();
} }
$scope.isConfigHidden = result.isConfigHidden; $scope.isConfigHidden = result.isConfigHidden;
}) })
...@@ -117,12 +117,12 @@ function releaseHistoryController($scope, $location, AppUtil, ...@@ -117,12 +117,12 @@ function releaseHistoryController($scope, $location, AppUtil,
} }
function fixTextNamespaceViewType() { function fixTextNamespaceViewType() {
$scope.releaseHistories.forEach(function (history) { $scope.releaseHistories.forEach(function (history) {
// text namespace doesn't support ALL view // text namespace doesn't support ALL view
if (history.viewType == CONFIG_VIEW_TYPE.ALL) { if (history.viewType == CONFIG_VIEW_TYPE.ALL) {
switchConfigViewType(history, CONFIG_VIEW_TYPE.DIFF); switchConfigViewType(history, CONFIG_VIEW_TYPE.DIFF);
} }
}); });
} }
function switchConfigViewType(history, viewType) { function switchConfigViewType(history, viewType) {
...@@ -144,8 +144,8 @@ function releaseHistoryController($scope, $location, AppUtil, ...@@ -144,8 +144,8 @@ function releaseHistoryController($scope, $location, AppUtil,
} }
ReleaseService.compare($scope.pageContext.env, ReleaseService.compare($scope.pageContext.env,
history.previousReleaseId, history.previousReleaseId,
history.releaseId) history.releaseId)
.then(function (result) { .then(function (result) {
history.changes = result.changes; history.changes = result.changes;
}) })
......
sync_item_module.controller("SyncItemController", sync_item_module.controller("SyncItemController",
['$scope', '$location', '$window', 'toastr', 'AppService', 'AppUtil', 'ConfigService', ['$scope', '$location', '$window', '$translate', 'toastr', 'AppService', 'AppUtil', 'ConfigService',
function ($scope, $location, $window, toastr, AppService, AppUtil, ConfigService) { function ($scope, $location, $window, $translate, toastr, AppService, AppUtil, ConfigService) {
var params = AppUtil.parseParams($location.$$url); var params = AppUtil.parseParams($location.$$url);
$scope.pageContext = { $scope.pageContext = {
appId: params.appid, appId: params.appid,
env: params.env, env: params.env,
clusterName: params.clusterName, clusterName: params.clusterName,
namespaceName: params.namespaceName namespaceName: params.namespaceName
}; };
var sourceItems = []; var sourceItems = [];
$scope.syncBtnDisabled = false; $scope.syncBtnDisabled = false;
$scope.viewItems = []; $scope.viewItems = [];
$scope.toggleItemsCheckedStatus = toggleItemsCheckedStatus; $scope.toggleItemsCheckedStatus = toggleItemsCheckedStatus;
$scope.diff = diff; $scope.diff = diff;
$scope.removeItem = removeItem; $scope.removeItem = removeItem;
$scope.syncItems = syncItems; $scope.syncItems = syncItems;
$scope.collectSelectedClusters = collectSelectedClusters; $scope.collectSelectedClusters = collectSelectedClusters;
$scope.syncItemNextStep = syncItemNextStep; $scope.syncItemNextStep = syncItemNextStep;
$scope.backToAppHomePage = backToAppHomePage; $scope.backToAppHomePage = backToAppHomePage;
$scope.switchSelect = switchSelect; $scope.switchSelect = switchSelect;
$scope.filter = filter; $scope.filter = filter;
$scope.resetFilter = resetFilter; $scope.resetFilter = resetFilter;
$scope.showText = showText; $scope.showText = showText;
init(); init();
function init() { function init() {
////// load items ////// ////// load items //////
ConfigService.find_items($scope.pageContext.appId, $scope.pageContext.env, ConfigService.find_items($scope.pageContext.appId, $scope.pageContext.env,
$scope.pageContext.clusterName, $scope.pageContext.clusterName,
$scope.pageContext.namespaceName, $scope.pageContext.namespaceName,
"lastModifiedTime") "lastModifiedTime")
.then(function (result) { .then(function (result) {
sourceItems = []; sourceItems = [];
result.forEach(function (item) { result.forEach(function (item) {
if (item.key) { if (item.key) {
item.checked = false; item.checked = false;
sourceItems.push(item); sourceItems.push(item);
} }
}); });
$scope.viewItems = sourceItems; $scope.viewItems = sourceItems;
$(".apollo-container").removeClass("hidden"); $(".apollo-container").removeClass("hidden");
}, function (result) { }, function (result) {
toastr.error(AppUtil.errorMsg(result), "加载配置出错"); toastr.error(AppUtil.errorMsg(result), $translate.instant('Config.Sync.LoadingItemsError'));
}); });
} }
var itemAllSelected = false; var itemAllSelected = false;
function toggleItemsCheckedStatus() { function toggleItemsCheckedStatus() {
itemAllSelected = !itemAllSelected; itemAllSelected = !itemAllSelected;
$scope.viewItems.forEach(function (item) { $scope.viewItems.forEach(function (item) {
item.checked = itemAllSelected; item.checked = itemAllSelected;
}) })
} }
var syncData = { var syncData = {
syncToNamespaces: [], syncToNamespaces: [],
syncItems: [] syncItems: []
}; };
function diff() { function diff() {
parseSyncSourceData(); parseSyncSourceData();
if (syncData.syncItems.length == 0) { if (syncData.syncItems.length == 0) {
toastr.warning("请选择需要同步的配置"); toastr.warning($translate.instant('Config.Sync.PleaseChooseNeedSyncItems'));
return; return;
} }
if (syncData.syncToNamespaces.length == 0) { if (syncData.syncToNamespaces.length == 0) {
toastr.warning("请选择集群"); toastr.warning($translate.instant('Config.Sync.PleaseChooseCluster'));
return; return;
} }
$scope.hasDiff = false; $scope.hasDiff = false;
ConfigService.diff($scope.pageContext.namespaceName, syncData).then( ConfigService.diff($scope.pageContext.namespaceName, syncData).then(
function (result) { function (result) {
$scope.clusterDiffs = result; $scope.clusterDiffs = result;
$scope.clusterDiffs.forEach(function (clusterDiff) { $scope.clusterDiffs.forEach(function (clusterDiff) {
if (!$scope.hasDiff) { if (!$scope.hasDiff) {
$scope.hasDiff = $scope.hasDiff =
clusterDiff.diffs.createItems.length clusterDiff.diffs.createItems.length
+ clusterDiff.diffs.updateItems.length + clusterDiff.diffs.updateItems.length
> 0; > 0;
} }
if (clusterDiff.diffs.updateItems.length > 0) { if (clusterDiff.diffs.updateItems.length > 0) {
//赋予同步前的值 //赋予同步前的值
ConfigService.find_items(clusterDiff.namespace.appId, ConfigService.find_items(clusterDiff.namespace.appId,
clusterDiff.namespace.env, clusterDiff.namespace.env,
clusterDiff.namespace.clusterName, clusterDiff.namespace.clusterName,
clusterDiff.namespace.namespaceName) clusterDiff.namespace.namespaceName)
.then(function (result) { .then(function (result) {
var oldItemMap = {}; var oldItemMap = {};
result.forEach(function (item) { result.forEach(function (item) {
oldItemMap[item.key] = item.value; oldItemMap[item.key] = item.value;
}); });
clusterDiff.diffs.updateItems.forEach(function (item) { clusterDiff.diffs.updateItems.forEach(function (item) {
item.oldValue = oldItemMap[item.key]; item.oldValue = oldItemMap[item.key];
}) })
}); });
} }
}); });
$scope.syncItemNextStep(1); $scope.syncItemNextStep(1);
}, function (result) { }, function (result) {
toastr.error(AppUtil.errorMsg(result)); toastr.error(AppUtil.errorMsg(result));
}); });
} }
function removeItem(diff, type, toRemoveItem) { function removeItem(diff, type, toRemoveItem) {
var syncDataResult = [], var syncDataResult = [],
diffSetResult = [], diffSetResult = [],
diffSet; diffSet;
if (type == 'create') { if (type == 'create') {
diffSet = diff.createItems; diffSet = diff.createItems;
} else { } else {
diffSet = diff.updateItems; diffSet = diff.updateItems;
} }
diffSet.forEach(function (item) { diffSet.forEach(function (item) {
if (item.key != toRemoveItem.key) { if (item.key != toRemoveItem.key) {
diffSetResult.push(item); diffSetResult.push(item);
} }
}); });
if (type == 'create') { if (type == 'create') {
diff.createItems = diffSetResult; diff.createItems = diffSetResult;
} else { } else {
diff.updateItems = diffSetResult; diff.updateItems = diffSetResult;
} }
syncData.syncItems.forEach(function (item) { syncData.syncItems.forEach(function (item) {
if (item.key != toRemoveItem.key) { if (item.key != toRemoveItem.key) {
syncDataResult.push(item); syncDataResult.push(item);
} }
}); });
syncData.syncItems = syncDataResult; syncData.syncItems = syncDataResult;
} }
function syncItems() { function syncItems() {
$scope.syncBtnDisabled = true; $scope.syncBtnDisabled = true;
ConfigService.sync_items($scope.pageContext.appId, ConfigService.sync_items($scope.pageContext.appId,
$scope.pageContext.namespaceName, $scope.pageContext.namespaceName,
syncData).then(function (result) { syncData).then(function (result) {
$scope.syncItemStep += 1; $scope.syncItemStep += 1;
$scope.syncSuccess = true; $scope.syncSuccess = true;
$scope.syncBtnDisabled = false; $scope.syncBtnDisabled = false;
}, function (result) { }, function (result) {
$scope.syncSuccess = false; $scope.syncSuccess = false;
$scope.syncBtnDisabled = false; $scope.syncBtnDisabled = false;
toastr.error(AppUtil.errorMsg(result)); toastr.error(AppUtil.errorMsg(result));
}); });
} }
var selectedClusters = []; var selectedClusters = [];
function collectSelectedClusters(data) { function collectSelectedClusters(data) {
selectedClusters = data; selectedClusters = data;
} }
function parseSyncSourceData() { function parseSyncSourceData() {
syncData = { syncData = {
syncToNamespaces: [], syncToNamespaces: [],
syncItems: [] syncItems: []
}; };
var namespaceName = $scope.pageContext.namespaceName; var namespaceName = $scope.pageContext.namespaceName;
selectedClusters.forEach(function (cluster) { selectedClusters.forEach(function (cluster) {
if (cluster.checked) { if (cluster.checked) {
cluster.clusterName = cluster.name; cluster.clusterName = cluster.name;
cluster.namespaceName = namespaceName; cluster.namespaceName = namespaceName;
syncData.syncToNamespaces.push(cluster); syncData.syncToNamespaces.push(cluster);
} }
}); });
$scope.viewItems.forEach(function (item) { $scope.viewItems.forEach(function (item) {
if (item.checked) { if (item.checked) {
syncData.syncItems.push(item); syncData.syncItems.push(item);
} }
}); });
return syncData; return syncData;
} }
////// flow control /////// ////// flow control ///////
$scope.syncItemStep = 1; $scope.syncItemStep = 1;
function syncItemNextStep(offset) { function syncItemNextStep(offset) {
$scope.syncItemStep += offset; $scope.syncItemStep += offset;
} }
function backToAppHomePage() { function backToAppHomePage() {
$window.location.href = '/config.html?#appid=' + $scope.pageContext.appId; $window.location.href = '/config.html?#appid=' + $scope.pageContext.appId;
} }
function switchSelect(o) { function switchSelect(o) {
o.checked = !o.checked; o.checked = !o.checked;
} }
function filter() { function filter() {
var beginTime = $scope.filterBeginTime; var beginTime = $scope.filterBeginTime;
var endTime = $scope.filterEndTime; var endTime = $scope.filterEndTime;
var result = []; var result = [];
sourceItems.forEach(function (item) { sourceItems.forEach(function (item) {
var updateTime = new Date(item.dataChangeLastModifiedTime); var updateTime = new Date(item.dataChangeLastModifiedTime);
if ((!beginTime || updateTime > beginTime) if ((!beginTime || updateTime > beginTime)
&& (!endTime || updateTime < endTime)) { && (!endTime || updateTime < endTime)) {
result.push(item); result.push(item);
} }
}); });
$scope.viewItems = result; $scope.viewItems = result;
} }
function resetFilter() { function resetFilter() {
$scope.filterBeginTime = null; $scope.filterBeginTime = null;
$scope.filterEndTime = null; $scope.filterEndTime = null;
filter(); filter();
} }
function showText(text) { function showText(text) {
$scope.text = text; $scope.text = text;
AppUtil.showModal('#showTextModal'); AppUtil.showModal('#showTextModal');
} }
}]); }]);
open_manage_module.controller('OpenManageController', open_manage_module.controller('OpenManageController',
['$scope', 'toastr', 'AppUtil', 'OrganizationService', 'ConsumerService', 'PermissionService','EnvService', ['$scope', '$translate', 'toastr', 'AppUtil', 'OrganizationService', 'ConsumerService', 'PermissionService', 'EnvService',
OpenManageController]); OpenManageController]);
function OpenManageController($scope, toastr, AppUtil, OrganizationService, ConsumerService, PermissionService, EnvService) { function OpenManageController($scope, $translate, toastr, AppUtil, OrganizationService, ConsumerService, PermissionService, EnvService) {
var $orgWidget = $('#organization'); var $orgWidget = $('#organization');
...@@ -35,10 +35,10 @@ function OpenManageController($scope, toastr, AppUtil, OrganizationService, Cons ...@@ -35,10 +35,10 @@ function OpenManageController($scope, toastr, AppUtil, OrganizationService, Cons
organizations.push(org); organizations.push(org);
}); });
$orgWidget.select2({ $orgWidget.select2({
placeholder: '请选择部门', placeholder: $translate.instant('Common.PleaseChooseDepartment'),
width: '100%', width: '100%',
data: organizations data: organizations
}); });
}, function (result) { }, function (result) {
toastr.error(AppUtil.errorMsg(result), "load organizations error"); toastr.error(AppUtil.errorMsg(result), "load organizations error");
}); });
...@@ -47,16 +47,16 @@ function OpenManageController($scope, toastr, AppUtil, OrganizationService, Cons ...@@ -47,16 +47,16 @@ function OpenManageController($scope, toastr, AppUtil, OrganizationService, Cons
function initPermission() { function initPermission() {
PermissionService.has_root_permission() PermissionService.has_root_permission()
.then(function (result) { .then(function (result) {
$scope.isRootUser = result.hasPermission; $scope.isRootUser = result.hasPermission;
}); });
} }
function initEnv() { function initEnv() {
EnvService.find_all_envs() EnvService.find_all_envs()
.then(function (result){ .then(function (result) {
$scope.envs = new Array(); $scope.envs = new Array();
for (var iLoop = 0; iLoop < result.length; iLoop++) { for (var iLoop = 0; iLoop < result.length; iLoop++) {
$scope.envs.push({ checked : false, env : result[iLoop] }); $scope.envs.push({ checked: false, env: result[iLoop] });
$scope.envsChecked = new Array(); $scope.envsChecked = new Array();
} }
...@@ -75,7 +75,7 @@ function OpenManageController($scope, toastr, AppUtil, OrganizationService, Cons ...@@ -75,7 +75,7 @@ function OpenManageController($scope, toastr, AppUtil, OrganizationService, Cons
function getTokenByAppId() { function getTokenByAppId() {
if (!$scope.consumer.appId) { if (!$scope.consumer.appId) {
toastr.warning("请输入appId"); toastr.warning($translate.instant('Open.Manage.PleaseEnterAppId'));
return; return;
} }
...@@ -86,7 +86,9 @@ function OpenManageController($scope, toastr, AppUtil, OrganizationService, Cons ...@@ -86,7 +86,9 @@ function OpenManageController($scope, toastr, AppUtil, OrganizationService, Cons
$scope.consumerToken = consumerToken; $scope.consumerToken = consumerToken;
$scope.consumerRole.token = consumerToken.token; $scope.consumerRole.token = consumerToken.token;
} else { } else {
$scope.consumerToken = {token: 'App(' + $scope.consumer.appId + ')未创建,请先创建'}; $scope.consumerToken = {
token: $translate.instant('Open.Manage.AppNotCreated', { appId: $scope.consumer.appId })
};
} }
}); });
} }
...@@ -95,13 +97,13 @@ function OpenManageController($scope, toastr, AppUtil, OrganizationService, Cons ...@@ -95,13 +97,13 @@ function OpenManageController($scope, toastr, AppUtil, OrganizationService, Cons
$scope.submitBtnDisabled = true; $scope.submitBtnDisabled = true;
if (!$scope.consumer.appId) { if (!$scope.consumer.appId) {
toastr.warning("请输入appId"); toastr.warning($translate.instant('Open.Manage.PleaseEnterAppId'));
return; return;
} }
var selectedOrg = $orgWidget.select2('data')[0]; var selectedOrg = $orgWidget.select2('data')[0];
if (!selectedOrg.id) { if (!selectedOrg.id) {
toastr.warning("请选择部门"); toastr.warning($translate.instant('Common.PleaseChooseDepartment'));
return; return;
} }
...@@ -111,20 +113,20 @@ function OpenManageController($scope, toastr, AppUtil, OrganizationService, Cons ...@@ -111,20 +113,20 @@ function OpenManageController($scope, toastr, AppUtil, OrganizationService, Cons
// owner // owner
var owner = $('.ownerSelector').select2('data')[0]; var owner = $('.ownerSelector').select2('data')[0];
if (!owner) { if (!owner) {
toastr.warning("请选择应用负责人"); toastr.warning($translate.instant('Common.PleaseChooseOwner'));
return; return;
} }
$scope.consumer.ownerName = owner.id; $scope.consumer.ownerName = owner.id;
ConsumerService.createConsumer($scope.consumer) ConsumerService.createConsumer($scope.consumer)
.then(function (consumerToken) { .then(function (consumerToken) {
toastr.success("创建成功"); toastr.success($translate.instant('Common.Created'));
$scope.consumerToken = consumerToken; $scope.consumerToken = consumerToken;
$scope.consumerRole.token = consumerToken.token; $scope.consumerRole.token = consumerToken.token;
$scope.submitBtnDisabled = false; $scope.submitBtnDisabled = false;
$scope.consumer = {}; $scope.consumer = {};
}, function (response) { }, function (response) {
AppUtil.showErrorMsg(response, "创建失败"); AppUtil.showErrorMsg(response, $translate.instant('Common.CreateFailed'));
$scope.submitBtnDisabled = false; $scope.submitBtnDisabled = false;
}) })
...@@ -132,14 +134,14 @@ function OpenManageController($scope, toastr, AppUtil, OrganizationService, Cons ...@@ -132,14 +134,14 @@ function OpenManageController($scope, toastr, AppUtil, OrganizationService, Cons
function assignRoleToConsumer() { function assignRoleToConsumer() {
ConsumerService.assignRoleToConsumer($scope.consumerRole.token, ConsumerService.assignRoleToConsumer($scope.consumerRole.token,
$scope.consumerRole.type, $scope.consumerRole.type,
$scope.consumerRole.appId, $scope.consumerRole.appId,
$scope.consumerRole.namespaceName, $scope.consumerRole.namespaceName,
$scope.envsChecked) $scope.envsChecked)
.then(function (consumerRoles) { .then(function (consumerRoles) {
toastr.success("赋权成功"); toastr.success($translate.instant('Open.Manage.GrantSuccessfully'));
}, function (response) { }, function (response) {
AppUtil.showErrorMsg(response, "赋权失败"); AppUtil.showErrorMsg(response, $translate.instant('Open.Manage.GrantFailed'));
}) })
} }
......
role_module.controller('NamespaceRoleController', role_module.controller('NamespaceRoleController',
['$scope', '$location', '$window', 'toastr', 'AppService', 'UserService', 'AppUtil', 'EnvService', ['$scope', '$location', '$window', '$translate', 'toastr', 'AppService', 'UserService', 'AppUtil', 'EnvService',
'PermissionService', 'PermissionService',
function ($scope, $location, $window, toastr, AppService, UserService, AppUtil, EnvService, function ($scope, $location, $window, $translate, toastr, AppService, UserService, AppUtil, EnvService,
PermissionService) { PermissionService) {
var params = AppUtil.parseParams($location.$$url); var params = AppUtil.parseParams($location.$$url);
$scope.pageContext = { $scope.pageContext = {
...@@ -22,8 +22,8 @@ role_module.controller('NamespaceRoleController', ...@@ -22,8 +22,8 @@ role_module.controller('NamespaceRoleController',
PermissionService.init_app_namespace_permission($scope.pageContext.appId, $scope.pageContext.namespaceName) PermissionService.init_app_namespace_permission($scope.pageContext.appId, $scope.pageContext.namespaceName)
.then(function (result) { .then(function (result) {
}, function(result) { }, function (result) {
toastr.warn(AppUtil.errorMsg(result), "初始化授权出错"); toastr.warn(AppUtil.errorMsg(result), $translate.instant('Namespace.Role.InitNamespacePermissionError'));
}); });
PermissionService.has_assign_user_permission($scope.pageContext.appId) PermissionService.has_assign_user_permission($scope.pageContext.appId)
...@@ -34,7 +34,7 @@ role_module.controller('NamespaceRoleController', ...@@ -34,7 +34,7 @@ role_module.controller('NamespaceRoleController',
}); });
EnvService.find_all_envs() EnvService.find_all_envs()
.then(function (result){ .then(function (result) {
$scope.envs = result; $scope.envs = result;
$scope.envRolesAssignedUsers = {}; $scope.envRolesAssignedUsers = {};
for (var iLoop = 0; iLoop < result.length; iLoop++) { for (var iLoop = 0; iLoop < result.length; iLoop++) {
...@@ -42,8 +42,8 @@ role_module.controller('NamespaceRoleController', ...@@ -42,8 +42,8 @@ role_module.controller('NamespaceRoleController',
PermissionService.get_namespace_env_role_users($scope.pageContext.appId, env, $scope.pageContext.namespaceName) PermissionService.get_namespace_env_role_users($scope.pageContext.appId, env, $scope.pageContext.namespaceName)
.then(function (result) { .then(function (result) {
$scope.envRolesAssignedUsers[result.env] = result; $scope.envRolesAssignedUsers[result.env] = result;
}, function(result) { }, function (result) {
toastr.error(AppUtil.errorMsg(result), "加载" + env + "授权用户出错"); toastr.error(AppUtil.errorMsg(result), $translate.instant('Namespace.Role.GetEnvGrantUserError', { env }));
}); });
} }
}); });
...@@ -53,14 +53,14 @@ role_module.controller('NamespaceRoleController', ...@@ -53,14 +53,14 @@ role_module.controller('NamespaceRoleController',
.then(function (result) { .then(function (result) {
$scope.rolesAssignedUsers = result; $scope.rolesAssignedUsers = result;
}, function (result) { }, function (result) {
toastr.error(AppUtil.errorMsg(result), "加载授权用户出错"); toastr.error(AppUtil.errorMsg(result), $translate.instant('Namespace.Role.GetGrantUserError'));
}); });
$scope.assignRoleToUser = function (roleType) { $scope.assignRoleToUser = function (roleType) {
if ("ReleaseNamespace" === roleType) { if ("ReleaseNamespace" === roleType) {
var user = $('.' + $scope.releaseRoleWidgetId).select2('data')[0]; var user = $('.' + $scope.releaseRoleWidgetId).select2('data')[0];
if (!user) { if (!user) {
toastr.warning("请选择用户"); toastr.warning($translate.instant('Namespace.Role.PleaseChooseUser'));
return; return;
} }
$scope.ReleaseRoleSubmitBtnDisabled = true; $scope.ReleaseRoleSubmitBtnDisabled = true;
...@@ -76,26 +76,26 @@ role_module.controller('NamespaceRoleController', ...@@ -76,26 +76,26 @@ role_module.controller('NamespaceRoleController',
$scope.pageContext.namespaceName, $scope.pageContext.namespaceName,
toAssignReleaseNamespaceRoleUser) toAssignReleaseNamespaceRoleUser)
.then(function (result) { .then(function (result) {
toastr.success("添加成功"); toastr.success($translate.instant('Namespace.Role.Added'));
$scope.ReleaseRoleSubmitBtnDisabled = false; $scope.ReleaseRoleSubmitBtnDisabled = false;
if ($scope.releaseRoleSelectedEnv === "") { if ($scope.releaseRoleSelectedEnv === "") {
$scope.rolesAssignedUsers.releaseRoleUsers.push( $scope.rolesAssignedUsers.releaseRoleUsers.push(
{userId: toAssignReleaseNamespaceRoleUser}); { userId: toAssignReleaseNamespaceRoleUser });
} else { } else {
$scope.envRolesAssignedUsers[$scope.releaseRoleSelectedEnv].releaseRoleUsers.push( $scope.envRolesAssignedUsers[$scope.releaseRoleSelectedEnv].releaseRoleUsers.push(
{userId: toAssignReleaseNamespaceRoleUser}); { userId: toAssignReleaseNamespaceRoleUser });
} }
$('.' + $scope.releaseRoleWidgetId).select2("val", ""); $('.' + $scope.releaseRoleWidgetId).select2("val", "");
$scope.releaseRoleSelectedEnv = ""; $scope.releaseRoleSelectedEnv = "";
}, function (result) { }, function (result) {
$scope.ReleaseRoleSubmitBtnDisabled = false; $scope.ReleaseRoleSubmitBtnDisabled = false;
toastr.error(AppUtil.errorMsg(result), "添加失败"); toastr.error(AppUtil.errorMsg(result), $translate.instant('Namespace.Role.AddFailed'));
}); });
} else { } else {
var user = $('.' + $scope.modifyRoleWidgetId).select2('data')[0]; var user = $('.' + $scope.modifyRoleWidgetId).select2('data')[0];
if (!user) { if (!user) {
toastr.warning("请选择用户"); toastr.warning($translate.instant('Namespace.Role.PleaseChooseUser'));
return; return;
} }
$scope.modifyRoleSubmitBtnDisabled = true; $scope.modifyRoleSubmitBtnDisabled = true;
...@@ -111,20 +111,20 @@ role_module.controller('NamespaceRoleController', ...@@ -111,20 +111,20 @@ role_module.controller('NamespaceRoleController',
$scope.pageContext.namespaceName, $scope.pageContext.namespaceName,
toAssignModifyNamespaceRoleUser) toAssignModifyNamespaceRoleUser)
.then(function (result) { .then(function (result) {
toastr.success("添加成功"); toastr.success($translate.instant('Namespace.Role.Added'));
$scope.modifyRoleSubmitBtnDisabled = false; $scope.modifyRoleSubmitBtnDisabled = false;
if ($scope.modifyRoleSelectedEnv === "") { if ($scope.modifyRoleSelectedEnv === "") {
$scope.rolesAssignedUsers.modifyRoleUsers.push( $scope.rolesAssignedUsers.modifyRoleUsers.push(
{userId: toAssignModifyNamespaceRoleUser}); { userId: toAssignModifyNamespaceRoleUser });
} else { } else {
$scope.envRolesAssignedUsers[$scope.modifyRoleSelectedEnv].modifyRoleUsers.push( $scope.envRolesAssignedUsers[$scope.modifyRoleSelectedEnv].modifyRoleUsers.push(
{userId: toAssignModifyNamespaceRoleUser}); { userId: toAssignModifyNamespaceRoleUser });
} }
$('.' + $scope.modifyRoleWidgetId).select2("val", ""); $('.' + $scope.modifyRoleWidgetId).select2("val", "");
$scope.modifyRoleSelectedEnv = ""; $scope.modifyRoleSelectedEnv = "";
}, function (result) { }, function (result) {
$scope.modifyRoleSubmitBtnDisabled = false; $scope.modifyRoleSubmitBtnDisabled = false;
toastr.error(AppUtil.errorMsg(result), "添加失败"); toastr.error(AppUtil.errorMsg(result), $translate.instant('Namespace.Role.AddFailed'));
}); });
} }
}; };
...@@ -141,14 +141,14 @@ role_module.controller('NamespaceRoleController', ...@@ -141,14 +141,14 @@ role_module.controller('NamespaceRoleController',
$scope.pageContext.namespaceName, $scope.pageContext.namespaceName,
user) user)
.then(function (result) { .then(function (result) {
toastr.success("删除成功"); toastr.success($translate.instant('Namespace.Role.Deleted'));
if (!env) { if (!env) {
removeUserFromList($scope.rolesAssignedUsers.releaseRoleUsers, user); removeUserFromList($scope.rolesAssignedUsers.releaseRoleUsers, user);
} else { } else {
removeUserFromList($scope.envRolesAssignedUsers[env].releaseRoleUsers, user); removeUserFromList($scope.envRolesAssignedUsers[env].releaseRoleUsers, user);
} }
}, function (result) { }, function (result) {
toastr.error(AppUtil.errorMsg(result), "删除失败"); toastr.error(AppUtil.errorMsg(result), $translate.instant('Namespace.Role.DeleteFailed'));
}); });
} else { } else {
var removeModifyNamespaceRoleFunc = !env ? var removeModifyNamespaceRoleFunc = !env ?
...@@ -161,14 +161,14 @@ role_module.controller('NamespaceRoleController', ...@@ -161,14 +161,14 @@ role_module.controller('NamespaceRoleController',
$scope.pageContext.namespaceName, $scope.pageContext.namespaceName,
user) user)
.then(function (result) { .then(function (result) {
toastr.success("删除成功"); toastr.success($translate.instant('Namespace.Role.Deleted'));
if (!env) { if (!env) {
removeUserFromList($scope.rolesAssignedUsers.modifyRoleUsers, user); removeUserFromList($scope.rolesAssignedUsers.modifyRoleUsers, user);
} else { } else {
removeUserFromList($scope.envRolesAssignedUsers[env].modifyRoleUsers, user); removeUserFromList($scope.envRolesAssignedUsers[env].modifyRoleUsers, user);
} }
}, function (result) { }, function (result) {
toastr.error(AppUtil.errorMsg(result), "删除失败"); toastr.error(AppUtil.errorMsg(result), $translate.instant('Namespace.Role.DeleteFailed'));
}); });
} }
}; };
......
angular.module('systemRole', ['app.service', 'apollo.directive', 'app.util', 'toastr', 'angular-loading-bar']) angular.module('systemRole', ['app.service', 'apollo.directive', 'app.util', 'toastr', 'angular-loading-bar'])
.controller('SystemRoleController', .controller('SystemRoleController',
['$scope', '$location', '$window', 'toastr', 'AppService', 'UserService', 'AppUtil', 'EnvService', ['$scope', '$location', '$window', '$translate', 'toastr', 'AppService', 'UserService', 'AppUtil', 'EnvService',
'PermissionService', 'SystemRoleService', function SystemRoleController($scope, $location, $window, toastr, AppService, UserService, AppUtil, EnvService, 'PermissionService', 'SystemRoleService', function SystemRoleController($scope, $location, $window, $translate, toastr, AppService, UserService, AppUtil, EnvService,
PermissionService, SystemRoleService) { PermissionService, SystemRoleService) {
$scope.addCreateApplicationBtnDisabled = false; $scope.addCreateApplicationBtnDisabled = false;
$scope.deleteCreateApplicationBtnDisabled = false; $scope.deleteCreateApplicationBtnDisabled = false;
$scope.modifySystemRoleWidgetId = 'modifySystemRoleWidgetId'; $scope.modifySystemRoleWidgetId = 'modifySystemRoleWidgetId';
$scope.modifyManageAppMasterRoleWidgetId = 'modifyManageAppMasterRoleWidgetId'; $scope.modifyManageAppMasterRoleWidgetId = 'modifyManageAppMasterRoleWidgetId';
$scope.hasCreateApplicationPermissionUserList = []; $scope.hasCreateApplicationPermissionUserList = [];
$scope.operateManageAppMasterRoleBtn = true; $scope.operateManageAppMasterRoleBtn = true;
$scope.app = {
appId: "",
info: ""
};
initPermission();
$scope.addCreateApplicationRoleToUser = function() { $scope.app = {
var user = $('.' + $scope.modifySystemRoleWidgetId).select2('data')[0]; appId: "",
if (!user) { info: ""
toastr.warning("请选择用户名"); };
return;
} initPermission();
SystemRoleService.add_create_application_role(user.id)
.then( $scope.addCreateApplicationRoleToUser = function () {
function (value) { var user = $('.' + $scope.modifySystemRoleWidgetId).select2('data')[0];
toastr.info("添加成功"); if (!user) {
getCreateApplicationRoleUsers(); toastr.warning($translate.instant('SystemRole.PleaseChooseUser'));
}, return;
function (reason) { }
toastr.warning(AppUtil.errorMsg(reason), "添加失败"); SystemRoleService.add_create_application_role(user.id)
.then(
function (value) {
toastr.info($translate.instant('SystemRole.Added'));
getCreateApplicationRoleUsers();
},
function (reason) {
toastr.warning(AppUtil.errorMsg(reason), $translate.instant('SystemRole.AddFailed'));
}
);
};
$scope.deleteCreateApplicationRoleFromUser = function (userId) {
SystemRoleService.delete_create_application_role(userId)
.then(
function (value) {
toastr.info($translate.instant('SystemRole.Deleted'));
getCreateApplicationRoleUsers();
},
function (reason) {
toastr.warn(AppUtil.errorMsg(reason), $translate.instant('SystemRole.DeleteFailed'));
}
);
};
function getCreateApplicationRoleUsers() {
SystemRoleService.get_create_application_role_users()
.then(
function (result) {
$scope.hasCreateApplicationPermissionUserList = result;
},
function (reason) {
toastr.warning(AppUtil.errorMsg(reason), $translate.instant('SystemRole.GetCanCreateProjectUsersError'));
}
)
} }
);
}; function initPermission() {
PermissionService.has_root_permission()
$scope.deleteCreateApplicationRoleFromUser = function(userId) { .then(function (result) {
SystemRoleService.delete_create_application_role(userId) $scope.isRootUser = result.hasPermission;
.then( });
function (value) {
toastr.info("删除成功");
getCreateApplicationRoleUsers(); getCreateApplicationRoleUsers();
},
function (reason) {
toastr.warn(AppUtil.errorMsg(reason), "删除失败");
} }
);
}; $scope.getAppInfo = function () {
if (!$scope.app.appId) {
toastr.warning($translate.instant('SystemRole.PleaseEnterAppId'));
function getCreateApplicationRoleUsers() { $scope.operateManageAppMasterRoleBtn = true;
SystemRoleService.get_create_application_role_users() return;
.then( }
function (result) {
$scope.hasCreateApplicationPermissionUserList = result; $scope.app.info = "";
},
function (reason) { AppService.load($scope.app.appId).then(function (result) {
toastr.warning(AppUtil.errorMsg(reason), "获取拥有创建项目的用户列表出错"); if (!result.appId) {
} toastr.warning($translate.instant('SystemRole.AppIdNotFound', { appId: $scope.app.appId }));
) $scope.operateManageAppMasterRoleBtn = true;
} return;
}
function initPermission() {
PermissionService.has_root_permission() $scope.app.info = $translate.instant('SystemRole.AppInfoContent', {
.then(function (result) { appName: result.name,
$scope.isRootUser = result.hasPermission; departmentName: result.orgName,
}); departmentId: result.orgId,
getCreateApplicationRoleUsers(); ownerName: result.ownerName
} });
$scope.getAppInfo = function() { $scope.operateManageAppMasterRoleBtn = false;
if (!$scope.app.appId) { }, function (result) {
toastr.warning("请输入appId"); AppUtil.showErrorMsg(result);
$scope.operateManageAppMasterRoleBtn = true; $scope.operateManageAppMasterRoleBt = true;
return; });
} };
$scope.app.info = ""; $scope.deleteAppMasterAssignRole = function () {
if (!$scope.app.appId) {
AppService.load($scope.app.appId).then(function (result) { toastr.warning($translate.instant('SystemRole.PleaseEnterAppId'));
if (!result.appId) { return;
toastr.warning("AppId: " + $scope.app.appId + " 不存在!"); }
$scope.operateManageAppMasterRoleBtn = true; var user = $('.' + $scope.modifyManageAppMasterRoleWidgetId).select2('data')[0];
return; if (!user) {
} toastr.warning($translate.instant('SystemRole.PleaseChooseUser'));
return;
$scope.app.info = "应用名:" + result.name + " 部门:" + result.orgName + '(' + result.orgId + ')' + " 负责人:" + result.ownerName; }
var confirmTips = $translate.instant('SystemRole.DeleteMasterAssignRoleTips', {
$scope.operateManageAppMasterRoleBtn = false; appId: $scope.app.appId,
}, function (result) { userId: user.id
AppUtil.showErrorMsg(result); });
$scope.operateManageAppMasterRoleBt = true; if (confirm(confirmTips)) {
}); AppService.delete_app_master_assign_role($scope.app.appId, user.id).then(function (result) {
}; var deletedTips = $translate.instant('SystemRole.DeletedMasterAssignRoleTips', {
appId: $scope.app.appId,
$scope.deleteAppMasterAssignRole = function() { userId: user.id
if (!$scope.app.appId) { });
toastr.warning("请输入appId"); toastr.success(deletedTips);
return; $scope.operateManageAppMasterRoleBtn = true;
} }, function (result) {
var user = $('.' + $scope.modifyManageAppMasterRoleWidgetId).select2('data')[0]; AppUtil.showErrorMsg(result);
if (!user) { })
toastr.warning("请选择用户名"); }
return; };
}
if (confirm("确认删除AppId: " + $scope.app.appId + "的用户: " + user.id + " 分配应用管理员的权限?")) { $scope.allowAppMasterAssignRole = function () {
AppService.delete_app_master_assign_role($scope.app.appId, user.id).then(function (result) { if (!$scope.app.appId) {
toastr.success("删除AppId: " + $scope.app.appId + "的用户: " + user.id + " 分配应用管理员的权限成功"); toastr.warning($translate.instant('SystemRole.PleaseEnterAppId'));
$scope.operateManageAppMasterRoleBtn = true; return;
}, function (result) { }
AppUtil.showErrorMsg(result); var user = $('.' + $scope.modifyManageAppMasterRoleWidgetId).select2('data')[0];
}) if (!user) {
} toastr.warning($translate.instant('SystemRole.PleaseChooseUser'));
}; return;
}
$scope.allowAppMasterAssignRole = function () { var confirmTips = $translate.instant('SystemRole.AllowAppMasterAssignRoleTips', {
if (!$scope.app.appId) { appId: $scope.app.appId,
toastr.warning("请输入appId"); userId: user.id
return; });
} if (confirm(confirmTips)) {
var user = $('.' + $scope.modifyManageAppMasterRoleWidgetId).select2('data')[0]; AppService.allow_app_master_assign_role($scope.app.appId, user.id).then(function (result) {
if (!user) {
toastr.warning("请选择用户名"); var allowedTips = $translate.instant('SystemRole.AllowedAppMasterAssignRoleTips', {
return; appId: $scope.app.appId,
} userId: user.id
if (confirm("确认添加AppId: " + $scope.app.appId + "的用户: " + user.id + " 分配应用管理员的权限?")) { });
AppService.allow_app_master_assign_role($scope.app.appId, user.id).then(function (result) { toastr.success(allowedTips);
toastr.success("添加AppId: " + $scope.app.appId + "的用户: " + user.id + " 分配应用管理员的权限成功"); $scope.operateManageAppMasterRoleBtn = true;
$scope.operateManageAppMasterRoleBtn = true; }, function (result) {
}, function (result) { AppUtil.showErrorMsg(result);
AppUtil.showErrorMsg(result); })
}) }
} };
}; }]);
}]);
directive_module.directive('deletenamespacemodal', deleteNamespaceModalDirective); directive_module.directive('deletenamespacemodal', deleteNamespaceModalDirective);
function deleteNamespaceModalDirective($window, $q, toastr, AppUtil, EventManager, function deleteNamespaceModalDirective($window, $q, $translate, toastr, AppUtil, EventManager,
PermissionService, UserService, NamespaceService) { PermissionService, UserService, NamespaceService) {
return { return {
restrict: 'E', restrict: 'E',
templateUrl: '../../views/component/delete-namespace-modal.html', templateUrl: '../../views/component/delete-namespace-modal.html',
...@@ -12,6 +12,8 @@ function deleteNamespaceModalDirective($window, $q, toastr, AppUtil, EventManage ...@@ -12,6 +12,8 @@ function deleteNamespaceModalDirective($window, $q, toastr, AppUtil, EventManage
}, },
link: function (scope) { link: function (scope) {
scope.doDeleteNamespace = doDeleteNamespace; scope.doDeleteNamespace = doDeleteNamespace;
EventManager.subscribe(EventManager.EventType.PRE_DELETE_NAMESPACE, function (context) { EventManager.subscribe(EventManager.EventType.PRE_DELETE_NAMESPACE, function (context) {
...@@ -67,8 +69,9 @@ function deleteNamespaceModalDirective($window, $q, toastr, AppUtil, EventManage ...@@ -67,8 +69,9 @@ function deleteNamespaceModalDirective($window, $q, toastr, AppUtil, EventManage
scope.isAppMasterUser = isAppMasterUser; scope.isAppMasterUser = isAppMasterUser;
if (!isAppMasterUser) { if (!isAppMasterUser) {
toastr.error("您没有项目管理员权限,只有管理员才能删除Namespace,请找项目管理员 [" + scope.masterUsers.join("") toastr.error($translate.instant('Config.DeleteNamespaceNoPermissionFailedTitle', {
+ "] 删除Namespace", "删除失败"); usres: scope.masterUsers.join(", ")
}), $translate.instant('Config.DeleteNamespaceNoPermissionFailedTitle'));
d.reject(); d.reject();
} else { } else {
d.resolve(); d.resolve();
...@@ -110,8 +113,8 @@ function deleteNamespaceModalDirective($window, $q, toastr, AppUtil, EventManage ...@@ -110,8 +113,8 @@ function deleteNamespaceModalDirective($window, $q, toastr, AppUtil, EventManage
var publicAppId = namespace.baseInfo.appId; var publicAppId = namespace.baseInfo.appId;
NamespaceService.getPublicAppNamespaceAllNamespaces(scope.env, NamespaceService.getPublicAppNamespaceAllNamespaces(scope.env,
namespace.baseInfo.namespaceName, namespace.baseInfo.namespaceName,
0, 20) 0, 20)
.then(function (associatedNamespaces) { .then(function (associatedNamespaces) {
var otherAppAssociatedNamespaces = []; var otherAppAssociatedNamespaces = [];
associatedNamespaces.forEach(function (associatedNamespace) { associatedNamespaces.forEach(function (associatedNamespace) {
...@@ -144,17 +147,17 @@ function deleteNamespaceModalDirective($window, $q, toastr, AppUtil, EventManage ...@@ -144,17 +147,17 @@ function deleteNamespaceModalDirective($window, $q, toastr, AppUtil, EventManage
function doDeleteNamespace() { function doDeleteNamespace() {
var toDeleteNamespace = scope.toDeleteNamespace; var toDeleteNamespace = scope.toDeleteNamespace;
NamespaceService.deleteNamespace(toDeleteNamespace.baseInfo.appId, scope.env, NamespaceService.deleteNamespace(toDeleteNamespace.baseInfo.appId, scope.env,
toDeleteNamespace.baseInfo.clusterName, toDeleteNamespace.baseInfo.clusterName,
toDeleteNamespace.baseInfo.namespaceName) toDeleteNamespace.baseInfo.namespaceName)
.then(function () { .then(function () {
toastr.success("删除成功"); toastr.success($translate.instant('Common.Deleted'));
setTimeout(function () { setTimeout(function () {
$window.location.reload(); $window.location.reload();
}, 1000); }, 1000);
}, function (result) { }, function (result) {
AppUtil.showErrorMsg(result, "删除失败"); AppUtil.showErrorMsg(result, $translate.instant('Common.DeleteFailed'));
}) })
} }
......
directive_module.directive('apollodiff', directive_module.directive('apollodiff',
function ($compile, $window) { function ($compile, $window) {
return { return {
restrict: 'E', restrict: 'E',
templateUrl: '../../views/component/diff.html', templateUrl: '../../views/component/diff.html',
transclude: true, transclude: true,
replace: true, replace: true,
scope: { scope: {
oldStr: '=', oldStr: '=',
newStr: '=', newStr: '=',
apolloId: '=' apolloId: '='
}, },
link: function (scope, element, attrs) { link: function (scope, element, attrs) {
scope.$watch('oldStr', makeDiff); scope.$watch('oldStr', makeDiff);
scope.$watch('newStr', makeDiff); scope.$watch('newStr', makeDiff);
function makeDiff() { function makeDiff() {
var displayArea = document.getElementById(scope.apolloId); var displayArea = document.getElementById(scope.apolloId);
if (!displayArea){ if (!displayArea) {
return; return;
} }
//clear //clear
displayArea.innerHTML = ''; displayArea.innerHTML = '';
var color = '', var color = '',
span = null, span = null,
pre = ''; pre = '';
var oldStr = scope.oldStr == undefined ? '' : scope.oldStr; var oldStr = scope.oldStr == undefined ? '' : scope.oldStr;
var newStr = scope.newStr == undefined ? '' : scope.newStr; var newStr = scope.newStr == undefined ? '' : scope.newStr;
var diff = JsDiff.diffLines(oldStr, newStr), var diff = JsDiff.diffLines(oldStr, newStr),
fragment = document.createDocumentFragment(); fragment = document.createDocumentFragment();
diff.forEach(function (part) { diff.forEach(function (part) {
// green for additions, red for deletions // green for additions, red for deletions
// grey for common parts // grey for common parts
color = part.added ? 'green' : color = part.added ? 'green' :
part.removed ? 'red' : 'grey'; part.removed ? 'red' : 'grey';
span = document.createElement('span'); span = document.createElement('span');
span.style.color = color; span.style.color = color;
pre = part.added ? '+' : pre = part.added ? '+' :
part.removed ? '-' : ''; part.removed ? '-' : '';
span.appendChild(document.createTextNode(pre + part.value)); span.appendChild(document.createTextNode(pre + part.value));
fragment.appendChild(span); fragment.appendChild(span);
}); });
displayArea.appendChild(fragment); displayArea.appendChild(fragment);
} }
} }
} }
}); });
/** navbar */ /** navbar */
directive_module.directive('apollonav', directive_module.directive('apollonav',
function ($compile, $window, toastr, AppUtil, AppService, EnvService, function ($compile, $window, $translate, toastr, AppUtil, AppService, EnvService,
UserService, CommonService, PermissionService) { UserService, CommonService, PermissionService) {
return { return {
restrict: 'E', restrict: 'E',
templateUrl: '../../views/common/nav.html', templateUrl: '../../views/common/nav.html',
transclude: true, transclude: true,
replace: true, replace: true,
link: function (scope, element, attrs) { link: function (scope, element, attrs) {
CommonService.getPageSetting().then(function (setting) { CommonService.getPageSetting().then(function (setting) {
scope.pageSetting = setting; scope.pageSetting = setting;
}); });
// Looks like a trick to make xml/yml/json namespaces display right, but why? // Looks like a trick to make xml/yml/json namespaces display right, but why?
$(document).on('click', function () { $(document).on('click', function () {
scope.$apply(function () {}); scope.$apply(function () {});
}); });
$('#app-search-list').select2({ $translate('ApolloConfirmDialog.SearchPlaceHolder').then(function(placeholderLabel) {
placeholder: '搜索项目(AppId、项目名)', $('#app-search-list').select2({
ajax: { placeholder: placeholderLabel,
url: "/apps/search", ajax: {
dataType: 'json', url: "/apps/search",
delay: 400, dataType: 'json',
data: function (params) { delay: 400,
return { data: function (params) {
query: params.term || '', return {
page: params.page ? params.page - 1 : 0, query: params.term || '',
size: 20 page: params.page ? params.page - 1 : 0,
}; size: 20
}, };
processResults: function (data) { },
if (data && data.content) { processResults: function (data) {
var hasMore = data.content.length if (data && data.content) {
=== data.size; var hasMore = data.content.length
var result = []; === data.size;
data.content.forEach(function (app) { var result = [];
result.push({ data.content.forEach(function (app) {
id: app.appId, result.push({
text: app.appId + ' / ' + app.name id: app.appId,
}) text: app.appId + ' / ' + app.name
}); })
return { });
results: result, return {
pagination: { results: result,
more: hasMore pagination: {
} more: hasMore
}; }
} else { };
return { } else {
results: [], return {
pagination: { results: [],
more: false pagination: {
} more: false
}; }
} };
}
}
} }
}); }
});
$('#app-search-list').on('select2:select', function () {
var selected = $('#app-search-list').select2('data'); $('#app-search-list').on('select2:select', function () {
if (selected && selected.length) { var selected = $('#app-search-list').select2('data');
jumpToConfigPage(selected[0].id) if (selected && selected.length) {
} jumpToConfigPage(selected[0].id)
}); }
});
function jumpToConfigPage(selectedAppId) { });
if ($window.location.href.indexOf("config.html") > -1) {
$window.location.hash = "appid=" + selectedAppId; function jumpToConfigPage(selectedAppId) {
$window.location.reload(); if ($window.location.href.indexOf("config.html") > -1) {
} else { $window.location.hash = "appid=" + selectedAppId;
$window.location.href = '/config.html?#appid=' + selectedAppId; $window.location.reload();
} } else {
}; $window.location.href = '/config.html?#appid=' + selectedAppId;
}
UserService.load_user().then(function (result) { };
scope.userName = result.userId;
}, function (result) { UserService.load_user().then(function (result) {
scope.userName = result.userId;
}); }, function (result) {
PermissionService.has_root_permission().then(function(result) { });
scope.hasRootPermission = result.hasPermission;
}) PermissionService.has_root_permission().then(function (result) {
} scope.hasRootPermission = result.hasPermission;
} })
}); scope.changeLanguage = function (lang) {
$translate.use(lang)
}
}
}
});
/** env cluster selector*/ /** env cluster selector*/
directive_module.directive('apolloclusterselector', function ($compile, $window, AppService, AppUtil, toastr) { directive_module.directive('apolloclusterselector', function ($compile, $window, AppService, AppUtil, toastr) {
...@@ -124,8 +130,8 @@ directive_module.directive('apolloclusterselector', function ($compile, $window, ...@@ -124,8 +130,8 @@ directive_module.directive('apolloclusterselector', function ($compile, $window,
cluster.env = env; cluster.env = env;
//default checked //default checked
cluster.checked = scope.defaultAllChecked || cluster.checked = scope.defaultAllChecked ||
(cluster.env == scope.defaultCheckedEnv && cluster.name (cluster.env == scope.defaultCheckedEnv && cluster.name
== scope.defaultCheckedCluster); == scope.defaultCheckedCluster);
//not checked //not checked
if (cluster.env == scope.notCheckedEnv && cluster.name == scope.notCheckedCluster) { if (cluster.env == scope.notCheckedEnv && cluster.name == scope.notCheckedCluster) {
cluster.checked = false; cluster.checked = false;
...@@ -186,7 +192,7 @@ directive_module.directive('apollorequiredfield', function ($compile, $window) { ...@@ -186,7 +192,7 @@ directive_module.directive('apollorequiredfield', function ($compile, $window) {
}); });
/** 确认框 */ /** 确认框 */
directive_module.directive('apolloconfirmdialog', function ($compile, $window, $sce) { directive_module.directive('apolloconfirmdialog', function ($compile, $window, $sce,$translate) {
return { return {
restrict: 'E', restrict: 'E',
templateUrl: '../../views/component/confirm-dialog.html', templateUrl: '../../views/component/confirm-dialog.html',
...@@ -209,15 +215,15 @@ directive_module.directive('apolloconfirmdialog', function ($compile, $window, $ ...@@ -209,15 +215,15 @@ directive_module.directive('apolloconfirmdialog', function ($compile, $window, $
}); });
if (!scope.confirmBtnText) { if (!scope.confirmBtnText) {
scope.confirmBtnText = '确认'; scope.confirmBtnText = $translate.instant('ApolloConfirmDialog.DefaultConfirmBtnName');
} }
scope.confirm = function () { scope.confirm = function () {
if (scope.doConfirm) { if (scope.doConfirm) {
scope.doConfirm(); scope.doConfirm();
} }
}; };
} }
...@@ -271,9 +277,9 @@ directive_module.directive('apollouserselector', function ($compile, $window) { ...@@ -271,9 +277,9 @@ directive_module.directive('apollouserselector', function ($compile, $window) {
var users = []; var users = [];
data.forEach(function (user) { data.forEach(function (user) {
users.push({ users.push({
id: user.userId, id: user.userId,
text: user.userId + " | " + user.name text: user.userId + " | " + user.name
}) })
}); });
return { return {
results: users results: users
...@@ -288,7 +294,7 @@ directive_module.directive('apollouserselector', function ($compile, $window) { ...@@ -288,7 +294,7 @@ directive_module.directive('apollouserselector', function ($compile, $window) {
function initSelect2() { function initSelect2() {
$('.' + scope.id).select2(select2Options); $('.' + scope.id).select2(select2Options);
} }
} }
} }
...@@ -322,9 +328,9 @@ directive_module.directive('apollomultipleuserselector', function ($compile, $wi ...@@ -322,9 +328,9 @@ directive_module.directive('apollomultipleuserselector', function ($compile, $wi
var users = []; var users = [];
data.forEach(function (user) { data.forEach(function (user) {
users.push({ users.push({
id: user.userId, id: user.userId,
text: user.userId + " | " + user.name text: user.userId + " | " + user.name
}) })
}); });
return { return {
results: users results: users
......
directive_module.directive('rulesmodal', rulesModalDirective); directive_module.directive('rulesmodal', rulesModalDirective);
function rulesModalDirective(toastr, AppUtil, EventManager, InstanceService) { function rulesModalDirective($translate, toastr, AppUtil, EventManager, InstanceService) {
return { return {
restrict: 'E', restrict: 'E',
templateUrl: '../../views/component/gray-release-rules-modal.html', templateUrl: '../../views/component/gray-release-rules-modal.html',
...@@ -23,24 +23,24 @@ function rulesModalDirective(toastr, AppUtil, EventManager, InstanceService) { ...@@ -23,24 +23,24 @@ function rulesModalDirective(toastr, AppUtil, EventManager, InstanceService) {
scope.initSelectIps = initSelectIps; scope.initSelectIps = initSelectIps;
EventManager.subscribe(EventManager.EventType.EDIT_GRAY_RELEASE_RULES, EventManager.subscribe(EventManager.EventType.EDIT_GRAY_RELEASE_RULES,
function (context) { function (context) {
var branch = context.branch; var branch = context.branch;
scope.branch = branch; scope.branch = branch;
if (branch.editingRuleItem.clientIpList && branch.editingRuleItem.clientIpList[0] == '*'){ if (branch.editingRuleItem.clientIpList && branch.editingRuleItem.clientIpList[0] == '*') {
branch.editingRuleItem.ApplyToAllInstances = true; branch.editingRuleItem.ApplyToAllInstances = true;
}else { } else {
branch.editingRuleItem.ApplyToAllInstances = false; branch.editingRuleItem.ApplyToAllInstances = false;
} }
$('.rules-ip-selector').select2({ $('.rules-ip-selector').select2({
placeholder: "从实例列表中选择", placeholder: $translate.instant('RulesModal.ChooseInstances'),
allowClear: true allowClear: true
}); });
AppUtil.showModal('#rulesModal'); AppUtil.showModal('#rulesModal');
}); });
$('.rules-ip-selector').on('select2:select', function () { $('.rules-ip-selector').on('select2:select', function () {
addRules(scope.branch); addRules(scope.branch);
...@@ -73,7 +73,7 @@ function rulesModalDirective(toastr, AppUtil, EventManager, InstanceService) { ...@@ -73,7 +73,7 @@ function rulesModalDirective(toastr, AppUtil, EventManager, InstanceService) {
if (newIps && newIps.length > 0) { if (newIps && newIps.length > 0) {
newIps.forEach(function (IP) { newIps.forEach(function (IP) {
if (!AppUtil.checkIPV4(IP)) { if (!AppUtil.checkIPV4(IP)) {
toastr.error("不合法的IP地址:" + IP); toastr.error($translate.instant('RulesModal.ChooseInstances', { ip: IP }));
} else if (oldIPs.indexOf(IP) < 0) { } else if (oldIPs.indexOf(IP) < 0) {
oldIPs.push(IP); oldIPs.push(IP);
} }
...@@ -102,7 +102,7 @@ function rulesModalDirective(toastr, AppUtil, EventManager, InstanceService) { ...@@ -102,7 +102,7 @@ function rulesModalDirective(toastr, AppUtil, EventManager, InstanceService) {
scope.completeEditBtnDisable = true; scope.completeEditBtnDisable = true;
if (!branch.editingRuleItem.clientAppId) { if (!branch.editingRuleItem.clientAppId) {
toastr.error("灰度的AppId不能为空"); toastr.error($translate.instant('RulesModal.GrayscaleAppIdCanNotBeNull'));
scope.completeEditBtnDisable = false; scope.completeEditBtnDisable = false;
return; return;
} }
...@@ -111,7 +111,7 @@ function rulesModalDirective(toastr, AppUtil, EventManager, InstanceService) { ...@@ -111,7 +111,7 @@ function rulesModalDirective(toastr, AppUtil, EventManager, InstanceService) {
var errorRuleItem = false; var errorRuleItem = false;
branch.rules.ruleItems.forEach(function (ruleItem) { branch.rules.ruleItems.forEach(function (ruleItem) {
if (ruleItem.clientAppId == branch.editingRuleItem.clientAppId) { if (ruleItem.clientAppId == branch.editingRuleItem.clientAppId) {
toastr.error("已经存在AppId=" + branch.editingRuleItem.clientAppId + "的规则"); toastr.error($translate.instant('RulesModal.AppIdExistsRule', { appId: branch.editingRuleItem.clientAppId }));
errorRuleItem = true; errorRuleItem = true;
} }
}); });
...@@ -123,7 +123,7 @@ function rulesModalDirective(toastr, AppUtil, EventManager, InstanceService) { ...@@ -123,7 +123,7 @@ function rulesModalDirective(toastr, AppUtil, EventManager, InstanceService) {
if (!branch.editingRuleItem.ApplyToAllInstances) { if (!branch.editingRuleItem.ApplyToAllInstances) {
if (branch.editingRuleItem.draftIpList.length == 0) { if (branch.editingRuleItem.draftIpList.length == 0) {
toastr.error("IP列表不能为空"); toastr.error($translate.instant('RulesModal.IpListCanNotBeNull'));
scope.completeEditBtnDisable = false; scope.completeEditBtnDisable = false;
return; return;
} else { } else {
...@@ -156,9 +156,9 @@ function rulesModalDirective(toastr, AppUtil, EventManager, InstanceService) { ...@@ -156,9 +156,9 @@ function rulesModalDirective(toastr, AppUtil, EventManager, InstanceService) {
AppUtil.hideModal('#rulesModal'); AppUtil.hideModal('#rulesModal');
EventManager.emit(EventManager.EventType.UPDATE_GRAY_RELEASE_RULES, EventManager.emit(EventManager.EventType.UPDATE_GRAY_RELEASE_RULES,
{ {
branch: branch branch: branch
}, branch.baseInfo.namespaceName); }, branch.baseInfo.namespaceName);
scope.completeEditBtnDisable = false; scope.completeEditBtnDisable = false;
} }
...@@ -185,12 +185,12 @@ function rulesModalDirective(toastr, AppUtil, EventManager, InstanceService) { ...@@ -185,12 +185,12 @@ function rulesModalDirective(toastr, AppUtil, EventManager, InstanceService) {
return; return;
} }
InstanceService.findInstancesByNamespace(scope.appId, InstanceService.findInstancesByNamespace(scope.appId,
scope.env, scope.env,
scope.cluster, scope.cluster,
scope.branch.baseInfo.namespaceName, scope.branch.baseInfo.namespaceName,
scope.branch.editingRuleItem.clientAppId, scope.branch.editingRuleItem.clientAppId,
0, 0,
2000) 2000)
.then(function (result) { .then(function (result) {
scope.selectIps = result.content; scope.selectIps = result.content;
}); });
......
directive_module.directive('itemmodal', itemModalDirective); directive_module.directive('itemmodal', itemModalDirective);
function itemModalDirective(toastr, $sce, AppUtil, EventManager, ConfigService) { function itemModalDirective($translate, toastr, $sce, AppUtil, EventManager, ConfigService) {
return { return {
restrict: 'E', restrict: 'E',
templateUrl: '../../views/component/item-modal.html', templateUrl: '../../views/component/item-modal.html',
...@@ -31,7 +31,7 @@ function itemModalDirective(toastr, $sce, AppUtil, EventManager, ConfigService) ...@@ -31,7 +31,7 @@ function itemModalDirective(toastr, $sce, AppUtil, EventManager, ConfigService)
}); });
$("#valueEditor").textareafullscreen(); $("#valueEditor").textareafullscreen();
function doItem() { function doItem() {
if (!scope.item.value) { if (!scope.item.value) {
...@@ -44,7 +44,7 @@ function itemModalDirective(toastr, $sce, AppUtil, EventManager, ConfigService) ...@@ -44,7 +44,7 @@ function itemModalDirective(toastr, $sce, AppUtil, EventManager, ConfigService)
var hasRepeatKey = false; var hasRepeatKey = false;
scope.toOperationNamespace.items.forEach(function (item) { scope.toOperationNamespace.items.forEach(function (item) {
if (!item.isDeleted && scope.item.key == item.item.key) { if (!item.isDeleted && scope.item.key == item.item.key) {
toastr.error("key=" + scope.item.key + " 已存在"); toastr.error($translate.instant('ItemModal.KeyExists', { key: scope.item.key }));
hasRepeatKey = true; hasRepeatKey = true;
} }
}); });
...@@ -56,52 +56,52 @@ function itemModalDirective(toastr, $sce, AppUtil, EventManager, ConfigService) ...@@ -56,52 +56,52 @@ function itemModalDirective(toastr, $sce, AppUtil, EventManager, ConfigService)
if (scope.toOperationNamespace.isBranch) { if (scope.toOperationNamespace.isBranch) {
ConfigService.create_item(scope.appId, ConfigService.create_item(scope.appId,
scope.env, scope.env,
scope.toOperationNamespace.baseInfo.clusterName, scope.toOperationNamespace.baseInfo.clusterName,
scope.toOperationNamespace.baseInfo.namespaceName, scope.toOperationNamespace.baseInfo.namespaceName,
scope.item).then( scope.item).then(
function (result) { function (result) {
toastr.success("添加成功,如需生效请发布"); toastr.success($translate.instant('ItemModal.AddedTips'));
scope.item.addItemBtnDisabled = false; scope.item.addItemBtnDisabled = false;
AppUtil.hideModal('#itemModal'); AppUtil.hideModal('#itemModal');
EventManager.emit(EventManager.EventType.REFRESH_NAMESPACE, EventManager.emit(EventManager.EventType.REFRESH_NAMESPACE,
{ {
namespace: scope.toOperationNamespace namespace: scope.toOperationNamespace
}); });
}, function (result) { }, function (result) {
toastr.error(AppUtil.errorMsg(result), "添加失败"); toastr.error(AppUtil.errorMsg(result), $translate.instant('ItemModal.AddFailed'));
scope.item.addItemBtnDisabled = false; scope.item.addItemBtnDisabled = false;
}); });
} else { } else {
if (selectedClusters.length == 0) { if (selectedClusters.length == 0) {
toastr.error("请选择集群"); toastr.error($translate.instant('ItemModal.PleaseChooseCluster'));
scope.item.addItemBtnDisabled = false; scope.item.addItemBtnDisabled = false;
return; return;
} }
selectedClusters.forEach(function (cluster) { selectedClusters.forEach(function (cluster) {
ConfigService.create_item(scope.appId, ConfigService.create_item(scope.appId,
cluster.env, cluster.env,
cluster.name, cluster.name,
scope.toOperationNamespace.baseInfo.namespaceName, scope.toOperationNamespace.baseInfo.namespaceName,
scope.item).then( scope.item).then(
function (result) { function (result) {
scope.item.addItemBtnDisabled = false; scope.item.addItemBtnDisabled = false;
AppUtil.hideModal('#itemModal'); AppUtil.hideModal('#itemModal');
toastr.success(cluster.env + " , " + scope.item.key, "添加成功,如需生效请发布"); toastr.success(cluster.env + " , " + scope.item.key, $translate.instant('ItemModal.AddedTips'));
if (cluster.env == scope.env && if (cluster.env == scope.env &&
cluster.name == scope.cluster) { cluster.name == scope.cluster) {
EventManager.emit(EventManager.EventType.REFRESH_NAMESPACE, EventManager.emit(EventManager.EventType.REFRESH_NAMESPACE,
{ {
namespace: scope.toOperationNamespace namespace: scope.toOperationNamespace
}); });
} }
}, function (result) { }, function (result) {
toastr.error(AppUtil.errorMsg(result), "添加失败"); toastr.error(AppUtil.errorMsg(result), $translate.instant('ItemModal.AddFailed'));
scope.item.addItemBtnDisabled = false; scope.item.addItemBtnDisabled = false;
}); });
}); });
} }
...@@ -112,22 +112,22 @@ function itemModalDirective(toastr, $sce, AppUtil, EventManager, ConfigService) ...@@ -112,22 +112,22 @@ function itemModalDirective(toastr, $sce, AppUtil, EventManager, ConfigService)
} }
ConfigService.update_item(scope.appId, ConfigService.update_item(scope.appId,
scope.env, scope.env,
scope.toOperationNamespace.baseInfo.clusterName, scope.toOperationNamespace.baseInfo.clusterName,
scope.toOperationNamespace.baseInfo.namespaceName, scope.toOperationNamespace.baseInfo.namespaceName,
scope.item).then( scope.item).then(
function (result) { function (result) {
EventManager.emit(EventManager.EventType.REFRESH_NAMESPACE, EventManager.emit(EventManager.EventType.REFRESH_NAMESPACE,
{ {
namespace: scope.toOperationNamespace namespace: scope.toOperationNamespace
}); });
AppUtil.hideModal('#itemModal'); AppUtil.hideModal('#itemModal');
toastr.success("更新成功, 如需生效请发布"); toastr.success($translate.instant('ItemModal.ModifiedTips'));
}, function (result) { }, function (result) {
toastr.error(AppUtil.errorMsg(result), "更新失败"); toastr.error(AppUtil.errorMsg(result), $translate.instant('ItemModal.ModifyFailed'));
}); });
} }
} }
...@@ -167,11 +167,11 @@ function itemModalDirective(toastr, $sce, AppUtil, EventManager, ConfigService) ...@@ -167,11 +167,11 @@ function itemModalDirective(toastr, $sce, AppUtil, EventManager, ConfigService)
function viewHiddenChar(c) { function viewHiddenChar(c) {
if (c == '\t') { if (c == '\t') {
return '<mark>#制表符#</mark>'; return '<mark>#' + $translate.instant('ItemModal.Tabs') + '#</mark>';
} else if (c == '\n') { } else if (c == '\n') {
return '<mark>#换行符#</mark>'; return '<mark>#' + $translate.instant('ItemModal.NewLine') + '#</mark>';
} else if (c == ' ') { } else if (c == ' ') {
return '<mark>#空格#</mark>'; return '<mark>#' + $translate.instant('ItemModal.Space') + '#</mark>';
} }
} }
......
...@@ -16,26 +16,26 @@ function mergeAndPublishDirective(AppUtil, EventManager) { ...@@ -16,26 +16,26 @@ function mergeAndPublishDirective(AppUtil, EventManager) {
scope.showReleaseModal = showReleaseModal; scope.showReleaseModal = showReleaseModal;
EventManager.subscribe(EventManager.EventType.MERGE_AND_PUBLISH_NAMESPACE, EventManager.subscribe(EventManager.EventType.MERGE_AND_PUBLISH_NAMESPACE,
function (context) { function (context) {
var branch = context.branch; var branch = context.branch;
scope.toReleaseNamespace = branch; scope.toReleaseNamespace = branch;
scope.toDeleteBranch = branch; scope.toDeleteBranch = branch;
scope.isEmergencyPublish = scope.isEmergencyPublish =
context.isEmergencyPublish ? context.isEmergencyPublish : false; context.isEmergencyPublish ? context.isEmergencyPublish : false;
var branchStatusMerge = 2; var branchStatusMerge = 2;
branch.branchStatus = branchStatusMerge; branch.branchStatus = branchStatusMerge;
branch.mergeAndPublish = true; branch.mergeAndPublish = true;
AppUtil.showModal('#mergeAndPublishModal'); AppUtil.showModal('#mergeAndPublishModal');
}); });
function showReleaseModal() { function showReleaseModal() {
EventManager.emit(EventManager.EventType.PUBLISH_NAMESPACE, EventManager.emit(EventManager.EventType.PUBLISH_NAMESPACE,
{ {
namespace: scope.toReleaseNamespace, namespace: scope.toReleaseNamespace,
isEmergencyPublish: scope.isEmergencyPublish isEmergencyPublish: scope.isEmergencyPublish
}); });
} }
} }
......
directive_module.directive('apollonspanel', directive); directive_module.directive('apollonspanel', directive);
function directive($window, toastr, AppUtil, EventManager, PermissionService, NamespaceLockService, function directive($window, $translate, toastr, AppUtil, EventManager, PermissionService, NamespaceLockService,
UserService, CommitService, ReleaseService, InstanceService, NamespaceBranchService, ConfigService) { UserService, CommitService, ReleaseService, InstanceService, NamespaceBranchService, ConfigService) {
return { return {
restrict: 'E', restrict: 'E',
templateUrl: '../../views/component/namespace-panel.html', templateUrl: '../../views/component/namespace-panel.html',
...@@ -70,13 +70,13 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na ...@@ -70,13 +70,13 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
scope.deleteNamespace = deleteNamespace; scope.deleteNamespace = deleteNamespace;
var subscriberId = EventManager.subscribe(EventManager.EventType.UPDATE_GRAY_RELEASE_RULES, var subscriberId = EventManager.subscribe(EventManager.EventType.UPDATE_GRAY_RELEASE_RULES,
function (context) { function (context) {
useRules(context.branch); useRules(context.branch);
}, scope.namespace.baseInfo.namespaceName); }, scope.namespace.baseInfo.namespaceName);
scope.$on('$destroy', function () { scope.$on('$destroy', function () {
EventManager.unsubscribe(EventManager.EventType.UPDATE_GRAY_RELEASE_RULES, EventManager.unsubscribe(EventManager.EventType.UPDATE_GRAY_RELEASE_RULES,
subscriberId, scope.namespace.baseInfo.namespaceName); subscriberId, scope.namespace.baseInfo.namespaceName);
}); });
preInit(scope.namespace); preInit(scope.namespace);
...@@ -91,8 +91,8 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na ...@@ -91,8 +91,8 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
namespace.isPublic ? namespace.parentAppId != namespace.baseInfo.appId : false; namespace.isPublic ? namespace.parentAppId != namespace.baseInfo.appId : false;
//namespace view name hide suffix //namespace view name hide suffix
namespace.viewName = namespace.baseInfo.namespaceName.replace(".xml", "").replace( namespace.viewName = namespace.baseInfo.namespaceName.replace(".xml", "").replace(
".properties", "").replace(".json", "").replace(".yml", "") ".properties", "").replace(".json", "").replace(".yml", "")
.replace(".yaml", "").replace(".txt", ""); .replace(".yaml", "").replace(".txt", "");
} }
function init() { function init() {
...@@ -103,7 +103,7 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na ...@@ -103,7 +103,7 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
function refreshNamespace() { function refreshNamespace() {
EventManager.emit(EventManager.EventType.REFRESH_NAMESPACE, EventManager.emit(EventManager.EventType.REFRESH_NAMESPACE,
{namespace: scope.namespace}); { namespace: scope.namespace });
} }
function initNamespace(namespace, viewType) { function initNamespace(namespace, viewType) {
...@@ -136,8 +136,8 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na ...@@ -136,8 +136,8 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
function initNamespaceBranch(namespace) { function initNamespaceBranch(namespace) {
NamespaceBranchService.findNamespaceBranch(scope.appId, scope.env, NamespaceBranchService.findNamespaceBranch(scope.appId, scope.env,
namespace.baseInfo.clusterName, namespace.baseInfo.clusterName,
namespace.baseInfo.namespaceName) namespace.baseInfo.namespaceName)
.then(function (result) { .then(function (result) {
if (!result.baseInfo) { if (!result.baseInfo) {
...@@ -248,7 +248,7 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na ...@@ -248,7 +248,7 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
scope.appId, scope.appId,
scope.env, scope.env,
namespace.baseInfo.namespaceName namespace.baseInfo.namespaceName
) )
.then(function (result) { .then(function (result) {
//branch has same permission //branch has same permission
namespace.hasModifyPermission = result.hasPermission; namespace.hasModifyPermission = result.hasPermission;
...@@ -258,8 +258,8 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na ...@@ -258,8 +258,8 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
}); });
} }
else { else {
//branch has same permission //branch has same permission
namespace.hasModifyPermission = result.hasPermission; namespace.hasModifyPermission = result.hasPermission;
if (namespace.branch) { if (namespace.branch) {
namespace.branch.hasModifyPermission = result.hasPermission; namespace.branch.hasModifyPermission = result.hasPermission;
} }
...@@ -275,7 +275,7 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na ...@@ -275,7 +275,7 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
scope.appId, scope.appId,
scope.env, scope.env,
namespace.baseInfo.namespaceName namespace.baseInfo.namespaceName
) )
.then(function (result) { .then(function (result) {
//branch has same permission //branch has same permission
namespace.hasReleasePermission = result.hasPermission; namespace.hasReleasePermission = result.hasPermission;
...@@ -300,7 +300,7 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na ...@@ -300,7 +300,7 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
} }
//load public namespace //load public namespace
ConfigService.load_public_namespace_for_associated_namespace(scope.env, scope.appId, scope.cluster, ConfigService.load_public_namespace_for_associated_namespace(scope.env, scope.appId, scope.cluster,
namespace.baseInfo.namespaceName) namespace.baseInfo.namespaceName)
.then(function (result) { .then(function (result) {
var publicNamespace = result; var publicNamespace = result;
namespace.publicNamespace = publicNamespace; namespace.publicNamespace = publicNamespace;
...@@ -346,8 +346,8 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na ...@@ -346,8 +346,8 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
function initNamespaceLock(namespace) { function initNamespaceLock(namespace) {
NamespaceLockService.get_namespace_lock(scope.appId, scope.env, NamespaceLockService.get_namespace_lock(scope.appId, scope.env,
namespace.baseInfo.clusterName, namespace.baseInfo.clusterName,
namespace.baseInfo.namespaceName) namespace.baseInfo.namespaceName)
.then(function (result) { .then(function (result) {
namespace.lockOwner = result.lockOwner; namespace.lockOwner = result.lockOwner;
namespace.isEmergencyPublishAllowed = result.isEmergencyPublishAllowed; namespace.isEmergencyPublishAllowed = result.isEmergencyPublishAllowed;
...@@ -376,9 +376,9 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na ...@@ -376,9 +376,9 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
function initNamespaceInstancesCount(namespace) { function initNamespaceInstancesCount(namespace) {
InstanceService.getInstanceCountByNamespace(scope.appId, InstanceService.getInstanceCountByNamespace(scope.appId,
scope.env, scope.env,
scope.cluster, scope.cluster,
namespace.baseInfo.namespaceName) namespace.baseInfo.namespaceName)
.then(function (result) { .then(function (result) {
namespace.instancesCount = result.num; namespace.instancesCount = result.num;
}) })
...@@ -446,11 +446,11 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na ...@@ -446,11 +446,11 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
var size = 10; var size = 10;
CommitService.find_commits(scope.appId, CommitService.find_commits(scope.appId,
scope.env, scope.env,
namespace.baseInfo.clusterName, namespace.baseInfo.clusterName,
namespace.baseInfo.namespaceName, namespace.baseInfo.namespaceName,
namespace.commitPage, namespace.commitPage,
size) size)
.then(function (result) { .then(function (result) {
if (result.length < size) { if (result.length < size) {
namespace.hasLoadAllCommit = true; namespace.hasLoadAllCommit = true;
...@@ -463,7 +463,7 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na ...@@ -463,7 +463,7 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
} }
namespace.commitPage += 1; namespace.commitPage += 1;
}, function (result) { }, function (result) {
toastr.error(AppUtil.errorMsg(result), "加载修改历史记录出错"); toastr.error(AppUtil.errorMsg(result), $translate.instant('ApolloNsPanel.LoadingHistoryError'));
}); });
} }
...@@ -479,9 +479,9 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na ...@@ -479,9 +479,9 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
if (namespace_instance_view_type.LATEST_RELEASE == type) { if (namespace_instance_view_type.LATEST_RELEASE == type) {
if (!namespace.latestRelease) { if (!namespace.latestRelease) {
ReleaseService.findLatestActiveRelease(scope.appId, ReleaseService.findLatestActiveRelease(scope.appId,
scope.env, scope.env,
namespace.baseInfo.clusterName, namespace.baseInfo.clusterName,
namespace.baseInfo.namespaceName) namespace.baseInfo.namespaceName)
.then(function (result) { .then(function (result) {
namespace.isLatestReleaseLoaded = true; namespace.isLatestReleaseLoaded = true;
...@@ -492,9 +492,9 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na ...@@ -492,9 +492,9 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
} }
namespace.latestRelease = result; namespace.latestRelease = result;
InstanceService.findInstancesByRelease(scope.env, InstanceService.findInstancesByRelease(scope.env,
namespace.latestRelease.id, namespace.latestRelease.id,
namespace.latestReleaseInstancesPage, namespace.latestReleaseInstancesPage,
size) size)
.then(function (result) { .then(function (result) {
namespace.latestReleaseInstances = result; namespace.latestReleaseInstances = result;
namespace.latestReleaseInstancesPage++; namespace.latestReleaseInstancesPage++;
...@@ -502,9 +502,9 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na ...@@ -502,9 +502,9 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
}); });
} else { } else {
InstanceService.findInstancesByRelease(scope.env, InstanceService.findInstancesByRelease(scope.env,
namespace.latestRelease.id, namespace.latestRelease.id,
namespace.latestReleaseInstancesPage, namespace.latestReleaseInstancesPage,
size) size)
.then(function (result) { .then(function (result) {
if (result && result.content.length) { if (result && result.content.length) {
namespace.latestReleaseInstancesPage++; namespace.latestReleaseInstancesPage++;
...@@ -522,10 +522,10 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na ...@@ -522,10 +522,10 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
return; return;
} }
InstanceService.findByReleasesNotIn(scope.appId, InstanceService.findByReleasesNotIn(scope.appId,
scope.env, scope.env,
scope.cluster, scope.cluster,
namespace.baseInfo.namespaceName, namespace.baseInfo.namespaceName,
namespace.latestRelease.id) namespace.latestRelease.id)
.then(function (result) { .then(function (result) {
if (!result || result.length == 0) { if (!result || result.length == 0) {
return return
...@@ -558,11 +558,11 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na ...@@ -558,11 +558,11 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
} else { } else {
InstanceService.findInstancesByNamespace(scope.appId, InstanceService.findInstancesByNamespace(scope.appId,
scope.env, scope.env,
scope.cluster, scope.cluster,
namespace.baseInfo.namespaceName, namespace.baseInfo.namespaceName,
'', '',
namespace.allInstancesPage) namespace.allInstancesPage)
.then(function (result) { .then(function (result) {
if (result && result.content.length) { if (result && result.content.length) {
namespace.allInstancesPage++; namespace.allInstancesPage++;
...@@ -598,10 +598,10 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na ...@@ -598,10 +598,10 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
function initRules(branch) { function initRules(branch) {
NamespaceBranchService.findBranchGrayRules(scope.appId, NamespaceBranchService.findBranchGrayRules(scope.appId,
scope.env, scope.env,
scope.cluster, scope.cluster,
scope.namespace.baseInfo.namespaceName, scope.namespace.baseInfo.namespaceName,
branch.baseInfo.clusterName) branch.baseInfo.clusterName)
.then(function (result) { .then(function (result) {
if (result.appId) { if (result.appId) {
...@@ -609,7 +609,7 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na ...@@ -609,7 +609,7 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
} }
}, function (result) { }, function (result) {
toastr.error(AppUtil.errorMsg(result), "加载灰度规则出错"); toastr.error(AppUtil.errorMsg(result), $translate.instant('ApolloNsPanel.LoadingGrayscaleError'));
}); });
} }
...@@ -643,7 +643,7 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na ...@@ -643,7 +643,7 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
branch.rules.ruleItems.forEach(function (item, index) { branch.rules.ruleItems.forEach(function (item, index) {
if (item.clientAppId == ruleItem.clientAppId) { if (item.clientAppId == ruleItem.clientAppId) {
branch.rules.ruleItems.splice(index, 1); branch.rules.ruleItems.splice(index, 1);
toastr.success("删除成功"); toastr.success($translate.instant('ApolloNsPanel.Deleted'));
} }
}); });
...@@ -652,14 +652,14 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na ...@@ -652,14 +652,14 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
function useRules(branch) { function useRules(branch) {
NamespaceBranchService.updateBranchGrayRules(scope.appId, NamespaceBranchService.updateBranchGrayRules(scope.appId,
scope.env, scope.env,
scope.cluster, scope.cluster,
scope.namespace.baseInfo.namespaceName, scope.namespace.baseInfo.namespaceName,
branch.baseInfo.clusterName, branch.baseInfo.clusterName,
branch.rules branch.rules
) )
.then(function (result) { .then(function (result) {
toastr.success('灰度规则更新成功'); toastr.success($translate.instant('ApolloNsPanel.GrayscaleModified'));
//show tips if branch has not release configs //show tips if branch has not release configs
if (branch.itemModifiedCnt) { if (branch.itemModifiedCnt) {
...@@ -671,7 +671,7 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na ...@@ -671,7 +671,7 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
}, 1500); }, 1500);
}, function (result) { }, function (result) {
AppUtil.showErrorMsg(result, "灰度规则更新失败"); AppUtil.showErrorMsg(result, $translate.instant('ApolloNsPanel.GrayscaleModifyFailed'));
}) })
} }
...@@ -724,25 +724,25 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na ...@@ -724,25 +724,25 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
} }
namespace.commitChangeBtnDisabled = true; namespace.commitChangeBtnDisabled = true;
ConfigService.modify_items(scope.appId, ConfigService.modify_items(scope.appId,
scope.env, scope.env,
scope.cluster, scope.cluster,
namespace.baseInfo.namespaceName, namespace.baseInfo.namespaceName,
model).then( model).then(
function (result) { function (result) {
toastr.success("更新成功, 如需生效请发布"); toastr.success($translate.instant('ApolloNsPanel.ModifiedTips'));
//refresh all namespace items //refresh all namespace items
EventManager.emit(EventManager.EventType.REFRESH_NAMESPACE, EventManager.emit(EventManager.EventType.REFRESH_NAMESPACE,
{ {
namespace: namespace namespace: namespace
}); });
return true; return true;
}, function (result) { }, function (result) {
toastr.error(AppUtil.errorMsg(result), "更新失败"); toastr.error(AppUtil.errorMsg(result), $translate.instant('ApolloNsPanel.ModifyFailed'));
namespace.commitChangeBtnDisabled = false; namespace.commitChangeBtnDisabled = false;
return false; return false;
} }
); );
namespace.commited = true; namespace.commited = true;
toggleTextEditStatus(namespace); toggleTextEditStatus(namespace);
} }
...@@ -754,19 +754,19 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na ...@@ -754,19 +754,19 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
format: namespace.format format: namespace.format
}; };
ConfigService.syntax_check_text(scope.appId, ConfigService.syntax_check_text(scope.appId,
scope.env, scope.env,
scope.cluster, scope.cluster,
namespace.baseInfo.namespaceName, namespace.baseInfo.namespaceName,
model).then( model).then(
function (result) { function (result) {
toastr.success("语法正确!"); toastr.success($translate.instant('ApolloNsPanel.GrammarIsright'));
}, function (result) { }, function (result) {
EventManager.emit(EventManager.EventType.SYNTAX_CHECK_TEXT_FAILED, { EventManager.emit(EventManager.EventType.SYNTAX_CHECK_TEXT_FAILED, {
syntaxCheckMessage: AppUtil.pureErrorMsg(result) syntaxCheckMessage: AppUtil.pureErrorMsg(result)
}); });
} }
); );
} }
function goToParentAppConfigPage(namespace) { function goToParentAppConfigPage(namespace) {
...@@ -857,9 +857,9 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na ...@@ -857,9 +857,9 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
} }
EventManager.emit(EventManager.EventType.PUBLISH_NAMESPACE, EventManager.emit(EventManager.EventType.PUBLISH_NAMESPACE,
{ {
namespace: namespace namespace: namespace
}); });
} }
function mergeAndPublish(branch) { function mergeAndPublish(branch) {
...@@ -874,16 +874,16 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na ...@@ -874,16 +874,16 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
mergeAndPublish: true mergeAndPublish: true
}); });
} else { } else {
EventManager.emit(EventManager.EventType.MERGE_AND_PUBLISH_NAMESPACE, {branch: branch}); EventManager.emit(EventManager.EventType.MERGE_AND_PUBLISH_NAMESPACE, { branch: branch });
} }
} }
function rollback(namespace) { function rollback(namespace) {
EventManager.emit(EventManager.EventType.PRE_ROLLBACK_NAMESPACE, {namespace: namespace}); EventManager.emit(EventManager.EventType.PRE_ROLLBACK_NAMESPACE, { namespace: namespace });
} }
function deleteNamespace(namespace) { function deleteNamespace(namespace) {
EventManager.emit(EventManager.EventType.PRE_DELETE_NAMESPACE, {namespace: namespace}); EventManager.emit(EventManager.EventType.PRE_DELETE_NAMESPACE, { namespace: namespace });
} }
//theme: https://github.com/ajaxorg/ace-builds/tree/ba3b91e04a5aa559d56ac70964f9054baa0f4caf/src-min //theme: https://github.com/ajaxorg/ace-builds/tree/ba3b91e04a5aa559d56ac70964f9054baa0f4caf/src-min
...@@ -895,10 +895,10 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na ...@@ -895,10 +895,10 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
onLoad: function (_editor) { onLoad: function (_editor) {
_editor.$blockScrolling = Infinity; _editor.$blockScrolling = Infinity;
_editor.setOptions({ _editor.setOptions({
fontSize: 13, fontSize: 13,
minLines: 10, minLines: 10,
maxLines: 20 maxLines: 20
}) })
} }
}; };
......
...@@ -24,10 +24,10 @@ function publishDenyDirective(AppUtil, EventManager) { ...@@ -24,10 +24,10 @@ function publishDenyDirective(AppUtil, EventManager) {
AppUtil.hideModal(MODAL_ID); AppUtil.hideModal(MODAL_ID);
EventManager.emit(EventManager.EventType.EMERGENCY_PUBLISH, EventManager.emit(EventManager.EventType.EMERGENCY_PUBLISH,
{ {
mergeAndPublish: scope.mergeAndPublish, mergeAndPublish: scope.mergeAndPublish,
namespace: scope.toReleaseNamespace namespace: scope.toReleaseNamespace
}); });
} }
} }
......
directive_module.directive('releasemodal', releaseModalDirective); directive_module.directive('releasemodal', releaseModalDirective);
function releaseModalDirective(toastr, AppUtil, EventManager, ReleaseService, NamespaceBranchService) { function releaseModalDirective($translate, toastr, AppUtil, EventManager, ReleaseService, NamespaceBranchService) {
return { return {
restrict: 'E', restrict: 'E',
templateUrl: '../../views/component/release-modal.html', templateUrl: '../../views/component/release-modal.html',
...@@ -20,25 +20,25 @@ function releaseModalDirective(toastr, AppUtil, EventManager, ReleaseService, Na ...@@ -20,25 +20,25 @@ function releaseModalDirective(toastr, AppUtil, EventManager, ReleaseService, Na
scope.releaseChangeViewType = 'change'; scope.releaseChangeViewType = 'change';
scope.releaseComment = ''; scope.releaseComment = '';
scope.isEmergencyPublish = false; scope.isEmergencyPublish = false;
EventManager.subscribe(EventManager.EventType.PUBLISH_NAMESPACE,
function (context) {
var namespace = context.namespace;
scope.toReleaseNamespace = context.namespace;
scope.isEmergencyPublish = !!context.isEmergencyPublish;
var date = new Date().Format("yyyyMMddhhmmss"); EventManager.subscribe(EventManager.EventType.PUBLISH_NAMESPACE,
if (namespace.mergeAndPublish) { function (context) {
namespace.releaseTitle = date + "-gray-release-merge-to-master";
} else if (namespace.isBranch) { var namespace = context.namespace;
namespace.releaseTitle = date + "-gray"; scope.toReleaseNamespace = context.namespace;
} else { scope.isEmergencyPublish = !!context.isEmergencyPublish;
namespace.releaseTitle = date + "-release";
} var date = new Date().Format("yyyyMMddhhmmss");
if (namespace.mergeAndPublish) {
namespace.releaseTitle = date + "-gray-release-merge-to-master";
} else if (namespace.isBranch) {
namespace.releaseTitle = date + "-gray";
} else {
namespace.releaseTitle = date + "-release";
}
AppUtil.showModal('#releaseModal'); AppUtil.showModal('#releaseModal');
}); });
function release() { function release() {
if (scope.toReleaseNamespace.mergeAndPublish) { if (scope.toReleaseNamespace.mergeAndPublish) {
...@@ -54,96 +54,96 @@ function releaseModalDirective(toastr, AppUtil, EventManager, ReleaseService, Na ...@@ -54,96 +54,96 @@ function releaseModalDirective(toastr, AppUtil, EventManager, ReleaseService, Na
function publish() { function publish() {
scope.releaseBtnDisabled = true; scope.releaseBtnDisabled = true;
ReleaseService.publish(scope.appId, scope.env, ReleaseService.publish(scope.appId, scope.env,
scope.toReleaseNamespace.baseInfo.clusterName, scope.toReleaseNamespace.baseInfo.clusterName,
scope.toReleaseNamespace.baseInfo.namespaceName, scope.toReleaseNamespace.baseInfo.namespaceName,
scope.toReleaseNamespace.releaseTitle, scope.toReleaseNamespace.releaseTitle,
scope.releaseComment, scope.releaseComment,
scope.isEmergencyPublish).then( scope.isEmergencyPublish).then(
function (result) { function (result) {
AppUtil.hideModal('#releaseModal'); AppUtil.hideModal('#releaseModal');
toastr.success("发布成功"); toastr.success($translate.instant('ReleaseModal.Published'));
scope.releaseBtnDisabled = false; scope.releaseBtnDisabled = false;
EventManager.emit(EventManager.EventType.REFRESH_NAMESPACE, EventManager.emit(EventManager.EventType.REFRESH_NAMESPACE,
{ {
namespace: scope.toReleaseNamespace namespace: scope.toReleaseNamespace
}) })
}, function (result) { }, function (result) {
scope.releaseBtnDisabled = false; scope.releaseBtnDisabled = false;
toastr.error(AppUtil.errorMsg(result), "发布失败"); toastr.error(AppUtil.errorMsg(result), $translate.instant('ReleaseModal.PublishFailed'));
} }
); );
} }
function grayPublish() { function grayPublish() {
scope.releaseBtnDisabled = true; scope.releaseBtnDisabled = true;
ReleaseService.grayPublish(scope.appId, scope.env, ReleaseService.grayPublish(scope.appId, scope.env,
scope.toReleaseNamespace.parentNamespace.baseInfo.clusterName, scope.toReleaseNamespace.parentNamespace.baseInfo.clusterName,
scope.toReleaseNamespace.baseInfo.namespaceName, scope.toReleaseNamespace.baseInfo.namespaceName,
scope.toReleaseNamespace.baseInfo.clusterName, scope.toReleaseNamespace.baseInfo.clusterName,
scope.toReleaseNamespace.releaseTitle, scope.toReleaseNamespace.releaseTitle,
scope.releaseComment, scope.releaseComment,
scope.isEmergencyPublish).then( scope.isEmergencyPublish).then(
function (result) { function (result) {
AppUtil.hideModal('#releaseModal'); AppUtil.hideModal('#releaseModal');
toastr.success("灰度发布成功"); toastr.success($translate.instant('ReleaseModal.GrayscalePublished'));
scope.releaseBtnDisabled = false; scope.releaseBtnDisabled = false;
//refresh item status //refresh item status
scope.toReleaseNamespace.branchItems.forEach(function (item, index) { scope.toReleaseNamespace.branchItems.forEach(function (item, index) {
if (item.isDeleted) { if (item.isDeleted) {
scope.toReleaseNamespace.branchItems.splice(index, 1); scope.toReleaseNamespace.branchItems.splice(index, 1);
} else { } else {
item.isModified = false; item.isModified = false;
}
});
//reset namespace status
scope.toReleaseNamespace.itemModifiedCnt = 0;
scope.toReleaseNamespace.lockOwner = undefined;
//check rules
if (!scope.toReleaseNamespace.rules
|| !scope.toReleaseNamespace.rules.ruleItems
|| !scope.toReleaseNamespace.rules.ruleItems.length) {
scope.toReleaseNamespace.viewType = 'rule';
AppUtil.showModal('#grayReleaseWithoutRulesTips');
} }
});
//reset namespace status
scope.toReleaseNamespace.itemModifiedCnt = 0;
scope.toReleaseNamespace.lockOwner = undefined;
//check rules }, function (result) {
if (!scope.toReleaseNamespace.rules scope.releaseBtnDisabled = false;
|| !scope.toReleaseNamespace.rules.ruleItems toastr.error(AppUtil.errorMsg(result), $translate.instant('ReleaseModal.GrayscalePublishFailed'));
|| !scope.toReleaseNamespace.rules.ruleItems.length) {
scope.toReleaseNamespace.viewType = 'rule';
AppUtil.showModal('#grayReleaseWithoutRulesTips');
}
}, function (result) { });
scope.releaseBtnDisabled = false;
toastr.error(AppUtil.errorMsg(result), "灰度发布失败");
});
} }
function mergeAndPublish() { function mergeAndPublish() {
NamespaceBranchService.mergeAndReleaseBranch(scope.appId, NamespaceBranchService.mergeAndReleaseBranch(scope.appId,
scope.env, scope.env,
scope.cluster, scope.cluster,
scope.toReleaseNamespace.baseInfo.namespaceName, scope.toReleaseNamespace.baseInfo.namespaceName,
scope.toReleaseNamespace.baseInfo.clusterName, scope.toReleaseNamespace.baseInfo.clusterName,
scope.toReleaseNamespace.releaseTitle, scope.toReleaseNamespace.releaseTitle,
scope.releaseComment, scope.releaseComment,
scope.isEmergencyPublish, scope.isEmergencyPublish,
scope.toReleaseNamespace.mergeAfterDeleteBranch) scope.toReleaseNamespace.mergeAfterDeleteBranch)
.then(function (result) { .then(function (result) {
toastr.success("全量发布成功"); toastr.success($translate.instant('ReleaseModal.AllPublished'));
EventManager.emit(EventManager.EventType.REFRESH_NAMESPACE, EventManager.emit(EventManager.EventType.REFRESH_NAMESPACE,
{ {
namespace: scope.toReleaseNamespace namespace: scope.toReleaseNamespace
}) })
}, function (result) { }, function (result) {
toastr.error(AppUtil.errorMsg(result), "全量发布失败"); toastr.error(AppUtil.errorMsg(result), $translate.instant('ReleaseModal.AllPublishFailed'));
}); });
AppUtil.hideModal('#releaseModal'); AppUtil.hideModal('#releaseModal');
......
directive_module.directive('rollbackmodal', rollbackModalDirective); directive_module.directive('rollbackmodal', rollbackModalDirective);
function rollbackModalDirective(AppUtil, EventManager, ReleaseService, toastr) { function rollbackModalDirective($translate, AppUtil, EventManager, ReleaseService, toastr) {
return { return {
restrict: 'E', restrict: 'E',
templateUrl: '../../views/component/rollback-modal.html', templateUrl: '../../views/component/rollback-modal.html',
...@@ -16,34 +16,34 @@ function rollbackModalDirective(AppUtil, EventManager, ReleaseService, toastr) { ...@@ -16,34 +16,34 @@ function rollbackModalDirective(AppUtil, EventManager, ReleaseService, toastr) {
scope.showRollbackAlertDialog = showRollbackAlertDialog; scope.showRollbackAlertDialog = showRollbackAlertDialog;
EventManager.subscribe(EventManager.EventType.PRE_ROLLBACK_NAMESPACE, EventManager.subscribe(EventManager.EventType.PRE_ROLLBACK_NAMESPACE,
function (context) { function (context) {
preRollback(context.namespace); preRollback(context.namespace);
}); });
EventManager.subscribe(EventManager.EventType.ROLLBACK_NAMESPACE, EventManager.subscribe(EventManager.EventType.ROLLBACK_NAMESPACE,
function (context) { function (context) {
rollback(); rollback();
}); });
function preRollback(namespace) { function preRollback(namespace) {
scope.toRollbackNamespace = namespace; scope.toRollbackNamespace = namespace;
//load latest two active releases //load latest two active releases
ReleaseService.findActiveReleases(scope.appId, ReleaseService.findActiveReleases(scope.appId,
scope.env, scope.env,
scope.cluster, scope.cluster,
scope.toRollbackNamespace.baseInfo.namespaceName, scope.toRollbackNamespace.baseInfo.namespaceName,
0, 2) 0, 2)
.then(function (result) { .then(function (result) {
if (result.length <= 1) { if (result.length <= 1) {
toastr.error("没有可以回滚的发布历史"); toastr.error($translate.instant('Rollback.NoRollbackList'));
return; return;
} }
scope.toRollbackNamespace.firstRelease = result[0]; scope.toRollbackNamespace.firstRelease = result[0];
scope.toRollbackNamespace.secondRelease = result[1]; scope.toRollbackNamespace.secondRelease = result[1];
ReleaseService.compare(scope.env, ReleaseService.compare(scope.env,
scope.toRollbackNamespace.firstRelease.id, scope.toRollbackNamespace.firstRelease.id,
scope.toRollbackNamespace.secondRelease.id) scope.toRollbackNamespace.secondRelease.id)
.then(function (result) { .then(function (result) {
scope.toRollbackNamespace.releaseCompareResult = result.changes; scope.toRollbackNamespace.releaseCompareResult = result.changes;
...@@ -55,18 +55,18 @@ function rollbackModalDirective(AppUtil, EventManager, ReleaseService, toastr) { ...@@ -55,18 +55,18 @@ function rollbackModalDirective(AppUtil, EventManager, ReleaseService, toastr) {
function rollback() { function rollback() {
scope.toRollbackNamespace.rollbackBtnDisabled = true; scope.toRollbackNamespace.rollbackBtnDisabled = true;
ReleaseService.rollback(scope.env, ReleaseService.rollback(scope.env,
scope.toRollbackNamespace.firstRelease.id) scope.toRollbackNamespace.firstRelease.id)
.then(function (result) { .then(function (result) {
toastr.success("回滚成功"); toastr.success($translate.instant('Rollback.RollbackSuccessfully'));
scope.toRollbackNamespace.rollbackBtnDisabled = false; scope.toRollbackNamespace.rollbackBtnDisabled = false;
AppUtil.hideModal('#rollbackModal'); AppUtil.hideModal('#rollbackModal');
EventManager.emit(EventManager.EventType.REFRESH_NAMESPACE, EventManager.emit(EventManager.EventType.REFRESH_NAMESPACE,
{ {
namespace:scope.toRollbackNamespace namespace: scope.toRollbackNamespace
}); });
}, function (result) { }, function (result) {
scope.toRollbackNamespace.rollbackBtnDisabled = false; scope.toRollbackNamespace.rollbackBtnDisabled = false;
AppUtil.showErrorMsg(result, "回滚失败"); AppUtil.showErrorMsg(result, $translate.instant('Rollback.RollbackFailed'));
}) })
} }
......
...@@ -3,104 +3,104 @@ setting_module.config(appValdr); ...@@ -3,104 +3,104 @@ setting_module.config(appValdr);
function appValdr(valdrProvider) { function appValdr(valdrProvider) {
valdrProvider.addConstraints({ valdrProvider.addConstraints({
'App': { 'App': {
'appId': { 'appId': {
'size': { 'size': {
'max': 32, 'max': 32,
'message': 'AppId长度不能多于32个字符' 'message': 'Valdr.App.AppId.Size'
}, },
'required': { 'required': {
'message': 'AppId不能为空' 'message': 'Valdr.App.AppId.Required'
} }
}, },
'appName': { 'appName': {
'size': { 'size': {
'max': 128, 'max': 128,
'message': '应用名称长度不能多于128个字符' 'message': 'Valdr.App.appName.Size'
}, },
'required': { 'required': {
'message': '应用名称不能为空' 'message': 'Valdr.App.appName.Required'
} }
} }
} }
}) })
} }
cluster_module.config(function (valdrProvider) { cluster_module.config(function (valdrProvider) {
valdrProvider.addConstraints({ valdrProvider.addConstraints({
'Cluster': { 'Cluster': {
'clusterName': { 'clusterName': {
'size': { 'size': {
'max': 32, 'max': 32,
'message': '集群名称长度不能多于32个字符' 'message': 'Valdr.Cluster.ClusterName.Size'
}, },
'required': { 'required': {
'message': '集群名称不能为空' 'message': 'Valdr.Cluster.ClusterName.Required'
} }
} }
} }
}) })
}); });
namespace_module.config(function (valdrProvider) { namespace_module.config(function (valdrProvider) {
valdrProvider.addConstraints({ valdrProvider.addConstraints({
'AppNamespace': { 'AppNamespace': {
'namespaceName': { 'namespaceName': {
'size': { 'size': {
'max': 32, 'max': 32,
'message': 'Namespace名称长度不能多于32个字符' 'message': 'Valdr.AppNamespace.NamespaceName.Size'
}, },
'required': { 'required': {
'message': 'Namespace名称不能为空' 'message': 'Valdr.AppNamespace.NamespaceName.Required'
} }
}, },
'comment': { 'comment': {
'size': { 'size': {
'max': 64, 'max': 64,
'message': '备注长度不能多于64个字符' 'message': 'Valdr.AppNamespace.Comment.Size'
} }
} }
} }
}) })
}); });
application_module.config(function (valdrProvider) { application_module.config(function (valdrProvider) {
valdrProvider.addConstraints({ valdrProvider.addConstraints({
'Item': { 'Item': {
'key': { 'key': {
'size': { 'size': {
'max': 128, 'max': 128,
'message': 'Key长度不能多于128个字符' 'message': 'Valdr.Item.Key.Size'
}, },
'required': { 'required': {
'message': 'Key不能为空' 'message': 'Valdr.Item.Key.Required'
} }
}, },
'comment': { 'comment': {
'size': { 'size': {
'max': 64, 'max': 64,
'message': '备注长度不能多于64个字符' 'message': 'Valdr.Item.Comment.Size'
} }
} }
}, },
'Release': { 'Release': {
'releaseName': { 'releaseName': {
'size': { 'size': {
'max': 64, 'max': 64,
'message': 'Release Name长度不能多于64个字符' 'message': 'Valdr.Release.ReleaseName.Size'
}, },
'required': { 'required': {
'message': 'Release Name不能为空' 'message': 'Valdr.Release.ReleaseName.Size'
} }
}, },
'comment': { 'comment': {
'size': { 'size': {
'max': 64, 'max': 64,
'message': '备注长度不能多于64个字符' 'message': 'Valdr.Release.Comment.Size'
} }
} }
} }
}) })
}); });
<!doctype html> <!doctype html>
<html ng-app="server_config"> <html ng-app="server_config">
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="icon" href="./img/config.png"> <link rel="icon" href="./img/config.png">
...@@ -9,95 +10,105 @@ ...@@ -9,95 +10,105 @@
<link rel="stylesheet" type="text/css" href="vendor/select2/select2.min.css"> <link rel="stylesheet" type="text/css" href="vendor/select2/select2.min.css">
<link rel="stylesheet" type="text/css" media='all' href="vendor/angular/loading-bar.min.css"> <link rel="stylesheet" type="text/css" media='all' href="vendor/angular/loading-bar.min.css">
<link rel="stylesheet" type="text/css" href="styles/common-style.css"> <link rel="stylesheet" type="text/css" href="styles/common-style.css">
<title>应用配置</title> <title>{{'ServiceConfig.Title' | translate }}</title>
</head> </head>
<body> <body>
<apollonav></apollonav> <apollonav></apollonav>
<div class="container-fluid apollo-container"> <div class="container-fluid apollo-container">
<div class="row"> <div class="row">
<div class="col-md-8 col-md-offset-2"> <div class="col-md-8 col-md-offset-2">
<div class="panel"> <div class="panel">
<header class="panel-heading"> <header class="panel-heading">
应用配置 {{'ServiceConfig.Title' | translate }}
<small>(维护ApolloPortalDB.ServerConfig表数据,如果已存在配置项则会覆盖,否则会创建配置项。配置更新后,一分钟后自动生效)</small> <small>{{'ServiceConfig.Tips' | translate }}</small>
</header> </header>
<div class="panel-body"> <div class="panel-body">
<form class="form-horizontal" ng-controller="ServerConfigController"> <form class="form-horizontal" ng-controller="ServerConfigController">
<div class="form-group"> <div class="form-group">
<label class="col-sm-2 control-label"> <label class="col-sm-2 control-label">
<apollorequiredfield></apollorequiredfield> <apollorequiredfield></apollorequiredfield>
key</label> {{'ServiceConfig.Key' | translate }}
<div class="col-sm-8"> </label>
<input type="text" class="form-control" name="key" ng-model="serverConfig.key" <div class="col-sm-8">
required> <input type="text" class="form-control" name="key" ng-model="serverConfig.key"
<small>(修改配置前请先查询该配置信息)</small> required>
</div> <small>{{'ServiceConfig.KeyTips' | translate }}</small>
<div class="col-sm-1"> </div>
<button class="btn btn-info" ng-click="getServerConfigInfo()">查询</button> <div class="col-sm-1">
<button class="btn btn-info"
ng-click="getServerConfigInfo()">{{'Common.Search' | translate }}</button>
</div>
</div> </div>
</div> <div class="form-group">
<div class="form-group"> <label class="col-sm-2 control-label">
<label class="col-sm-2 control-label"> <apollorequiredfield></apollorequiredfield>
<apollorequiredfield></apollorequiredfield> {{'ServiceConfig.Value' | translate }}
value</label> </label>
<div class="col-sm-9"> <div class="col-sm-9">
<textarea class="form-control" rows="4" name="value" ng-model="serverConfig.value"></textarea> <textarea class="form-control" rows="4" name="value"
ng-model="serverConfig.value"></textarea>
</div>
</div> </div>
</div> <div class="form-group">
<div class="form-group"> <label class="col-sm-2 control-label">
<label class="col-sm-2 control-label"> {{'ServiceConfig.Comment' | translate }}</label>
comment</label> <div class="col-sm-9">
<div class="col-sm-9"> <textarea class="form-control" rows="4" name="comment"
<textarea class="form-control" rows="4" name="comment" ng-model="serverConfig.comment"></textarea> ng-model="serverConfig.comment"></textarea>
</div>
</div> </div>
</div>
<div class="form-group"> <div class="form-group">
<div class="col-sm-offset-2 col-sm-10"> <div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-primary" <button type="submit" class="btn btn-primary" ng-disabled="saveBtnDisabled"
ng-disabled="saveBtnDisabled"
ng-click="create()"> ng-click="create()">
保存 {{'Common.Save' | translate }}
</button> </button>
</div>
</div> </div>
</div> </form>
</form> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div>
<div ng-include="'views/common/footer.html'"></div> <div ng-include="'views/common/footer.html'"></div>
<!--angular--> <!--angular-->
<script src="vendor/angular/angular.min.js"></script> <script src="vendor/angular/angular.min.js"></script>
<script src="vendor/angular/angular-resource.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/angular-toastr-1.4.1.tpls.min.js"></script>
<script src="vendor/angular/loading-bar.min.js"></script> <script src="vendor/angular/loading-bar.min.js"></script>
<script src="vendor/angular/angular-cookies.min.js"></script>
<!-- jquery.js --> <script src="vendor/angular/angular-translate.2.18.1/angular-translate.min.js"></script>
<script src="vendor/jquery.min.js" type="text/javascript"></script> <script src="vendor/angular/angular-translate.2.18.1/angular-translate-loader-static-files.min.js"></script>
<script src="vendor/select2/select2.min.js" type="text/javascript"></script> <script src="vendor/angular/angular-translate.2.18.1/angular-translate-storage-cookie.min.js"></script>
<!-- bootstrap.js --> <!-- jquery.js -->
<script src="vendor/bootstrap/js/bootstrap.min.js" type="text/javascript"></script> <script src="vendor/jquery.min.js" type="text/javascript"></script>
<script src="vendor/select2/select2.min.js" type="text/javascript"></script>
<script type="application/javascript" src="scripts/app.js"></script> <!-- bootstrap.js -->
<script type="application/javascript" src="scripts/directive/directive.js"></script> <script src="vendor/bootstrap/js/bootstrap.min.js" type="text/javascript"></script>
<script type="application/javascript" src="scripts/AppUtils.js"></script>
<script type="application/javascript" src="scripts/services/AppService.js"></script> <script type="application/javascript" src="scripts/app.js"></script>
<script type="application/javascript" src="scripts/services/EnvService.js"></script> <script type="application/javascript" src="scripts/directive/directive.js"></script>
<script type="application/javascript" src="scripts/services/UserService.js"></script> <script type="application/javascript" src="scripts/AppUtils.js"></script>
<script type="application/javascript" src="scripts/services/CommonService.js"></script>
<script type="application/javascript" src="scripts/services/ServerConfigService.js"></script>
<script type="application/javascript" src="scripts/services/PermissionService.js"></script>
<script type="application/javascript" src="scripts/controller/ServerConfigController.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/services/UserService.js"></script>
<script type="application/javascript" src="scripts/services/CommonService.js"></script>
<script type="application/javascript" src="scripts/services/ServerConfigService.js"></script>
<script type="application/javascript" src="scripts/services/PermissionService.js"></script>
<script type="application/javascript" src="scripts/controller/ServerConfigController.js"></script>
</body> </body>
</html>
</html>
\ No newline at end of file
...@@ -297,7 +297,7 @@ table th { ...@@ -297,7 +297,7 @@ table th {
.project-info th { .project-info th {
text-align: right; text-align: right;
padding: 4px 6px; padding: 4px 2px;
width: 5em; width: 5em;
} }
...@@ -654,7 +654,7 @@ table th { ...@@ -654,7 +654,7 @@ table th {
.release-history .operation-caption { .release-history .operation-caption {
position: absolute; position: absolute;
top: 45px; top: 45px;
width: 75px; width: 100px;
height: 18px; height: 18px;
color: #fff; color: #fff;
font-size: 12px; font-size: 12px;
......
<!doctype html> <!doctype html>
<html ng-app="systemRole"> <html ng-app="systemRole">
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="icon" href="../img/config.png"> <link rel="icon" href="../img/config.png">
...@@ -9,161 +10,173 @@ ...@@ -9,161 +10,173 @@
<link rel="stylesheet" type="text/css" media='all' href="../vendor/angular/loading-bar.min.css"> <link rel="stylesheet" type="text/css" media='all' href="../vendor/angular/loading-bar.min.css">
<link rel="stylesheet" type="text/css" href="../styles/common-style.css"> <link rel="stylesheet" type="text/css" href="../styles/common-style.css">
<link rel="stylesheet" type="text/css" href="../vendor/select2/select2.min.css"> <link rel="stylesheet" type="text/css" href="../vendor/select2/select2.min.css">
<title>系统权限管理</title> <title>{{'SystemRole.Title' | translate }}</title>
</head> </head>
<body> <body>
<apollonav></apollonav> <apollonav></apollonav>
<div class="container-fluid" ng-controller="SystemRoleController"> <div class="container-fluid" ng-controller="SystemRoleController">
<div class="col-md-10 col-md-offset-1 panel"> <div class="col-md-10 col-md-offset-1 panel">
<section class="panel-body" ng-show="isRootUser"> <section class="panel-body" ng-show="isRootUser">
<section class="row"> <section class="row">
<h5>为用户添加创建应用权限 <h5>{{'SystemRole.AddCreateAppRoleToUser' | translate }}
<small> <small>
(系统参数中设置 role.create-application.enabled=true 会限制只有超级管理员和拥有创建应用权限的帐号可以创建项目) {{'SystemRole.AddCreateAppRoleToUserTips' | translate }}
</small> </small>
</h5> </h5>
<hr> <hr>
<div class="row"> <div class="row">
<div class="form-horizontal"> <div class="form-horizontal">
<div class="form-group"> <div class="form-group">
<label class="col-sm-2 control-label">用户选择<br></label> <label
<div class="col-sm-8"> class="col-sm-2 control-label">{{'SystemRole.ChooseUser' | translate }}<br></label>
<form class="form-inline" ng-submit="addCreateApplicationRoleToUser()"> <div class="col-sm-8">
<div class="form-group"> <form class="form-inline" ng-submit="addCreateApplicationRoleToUser()">
<apollouserselector apollo-id="modifySystemRoleWidgetId"></apollouserselector> <div class="form-group">
<apollouserselector apollo-id="modifySystemRoleWidgetId">
</apollouserselector>
</div>
<button type="submit" class="btn btn-default"
style="margin-left: 20px;">{{'SystemRole.Add' | translate }}</button>
</form>
<div class="item-container">
<h5>{{'SystemRole.AuthorizedUser' | translate }}</h5>
<div class="btn-group item-info"
ng-repeat="user in hasCreateApplicationPermissionUserList">
<button type="button" class="btn btn-default" ng-bind="user"></button>
<button type="button" class="btn btn-default dropdown-toggle"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"
ng-click="deleteCreateApplicationRoleFromUser(user)">
<span class="glyphicon glyphicon-remove"></span>
</button>
</div>
</div> </div>
<button type="submit" class="btn btn-default" style="margin-left: 20px;">添加</button>
</form>
<div class="item-container">
<h5>已拥有权限用户</h5>
<div class="btn-group item-info" ng-repeat="user in hasCreateApplicationPermissionUserList">
<button type="button" class="btn btn-default" ng-bind="user"></button>
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false" ng-click="deleteCreateApplicationRoleFromUser(user)">
<span class="glyphicon glyphicon-remove"></span>
</button>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </section>
</section>
<section class="row">
<section class="row"> <h5>{{'SystemRole.ModifyAppAdminUser' | translate }}
<h5>修改应用管理员分配权限 <small>
<small> {{'SystemRole.ModifyAppAdminUserTips' | translate }}
(系统参数中设置 role.manage-app-master.enabled=true 会限制只有超级管理员和拥有管理员分配权限的帐号可以修改项目管理员) </small>
</small> </h5>
</h5> <hr>
<hr> <form class="form-horizontal">
<form class="form-horizontal"> <div class="form-group" valdr-form-group>
<div class="form-group" valdr-form-group> <label class="col-sm-2 control-label">
<label class="col-sm-2 control-label"> <apollorequiredfield></apollorequiredfield>
<apollorequiredfield></apollorequiredfield> {{'SystemRole.AppIdTips' | translate }}
应用AppId</label> </label>
<div class="col-sm-5"> <div class="col-sm-5">
<input type="text" class="form-control" ng-model="app.appId"> <input type="text" class="form-control" ng-model="app.appId">
<small>(请先查询应用信息)</small> <small>{{'SystemRole.Title' | translate }}</small>
</div> </div>
<div class="col-sm-1"> <div class="col-sm-1">
<button class="btn btn-info" ng-click="getAppInfo()">查询</button> <button class="btn btn-info"
ng-click="getAppInfo()">{{'Common.Search' | translate }}</button>
</div>
</div> </div>
</div> <div class="form-group" valdr-form-group>
<div class="form-group" valdr-form-group> <label class="col-sm-2 control-label">
<label class="col-sm-2 control-label"> {{'SystemRole.AppInfo' | translate }}</label>
应用信息</label> <div class="col-sm-5">
<div class="col-sm-5"> <h5 ng-show="app.info" ng-bind="app.info"></h5>
<h5 ng-show="app.info" ng-bind="app.info"></h5> </div>
</div> </div>
</div>
<div class="form-group"> <div class="form-group">
<label class="col-sm-2 control-label">用户选择<br></label> <label class="col-sm-2 control-label">{{'SystemRole.ChooseUser' | translate }}<br></label>
<div class="col-sm-8"> <div class="col-sm-8">
<form class="form-inline"> <form class="form-inline">
<div class="form-group"> <div class="form-group">
<apollouserselector apollo-id="modifyManageAppMasterRoleWidgetId"></apollouserselector> <apollouserselector apollo-id="modifyManageAppMasterRoleWidgetId">
</div> </apollouserselector>
</form> </div>
</form>
</div>
</div> </div>
</div>
<div class="form-group"> <div class="form-group">
<div class="col-sm-offset-2 col-sm-9"> <div class="col-sm-offset-2 col-sm-9">
<button type="submit" class="btn btn-primary" <button type="submit" class="btn btn-primary"
ng-disabled="operateManageAppMasterRoleBtn" ng-disabled="operateManageAppMasterRoleBtn" ng-click="allowAppMasterAssignRole()">
ng-click="allowAppMasterAssignRole()"> {{'SystemRole.AllowAppMasterAssignRole' | translate }}
允许此用户作为管理员时添加Master </button>
</button> <button type="submit" class="btn btn-primary"
<button type="submit" class="btn btn-primary" ng-disabled="operateManageAppMasterRoleBtn" ng-click="deleteAppMasterAssignRole()">
ng-disabled="operateManageAppMasterRoleBtn" {{'SystemRole.DeleteAppMasterAssignRole' | translate }}
ng-click="deleteAppMasterAssignRole()"> </button>
禁止此用户作为管理员时添加Master </div>
</button>
</div> </div>
</div> </form>
</form> </section>
</section>
</section> </section>
<section class="panel-body text-center" ng-if="!isRootUser"> <section class="panel-body text-center" ng-if="!isRootUser">
<h4>当前页面只对Apollo管理员开放</h4> <h4>{{'Common.IsRootUser' | translate }}</h4>
</section> </section>
</div>
</div> </div>
</div>
<div ng-include="'../views/common/footer.html'"></div> <div ng-include="'../views/common/footer.html'"></div>
<!-- jquery.js --> <!-- jquery.js -->
<script src="../vendor/jquery.min.js" type="text/javascript"></script> <script src="../vendor/jquery.min.js" type="text/javascript"></script>
<!--angular--> <!--angular-->
<script src="../vendor/angular/angular.min.js"></script> <script src="../vendor/angular/angular.min.js"></script>
<script src="../vendor/angular/angular-route.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-resource.min.js"></script>
<script src="../vendor/angular/angular-toastr-1.4.1.tpls.min.js"></script> <script src="../vendor/angular/angular-toastr-1.4.1.tpls.min.js"></script>
<script src="../vendor/angular/loading-bar.min.js"></script> <script src="../vendor/angular/loading-bar.min.js"></script>
<script src="vendor/angular/angular-cookies.min.js"></script>
<!--valdr--> <script src="vendor/angular/angular-translate.2.18.1/angular-translate.min.js"></script>
<script src="../vendor/valdr/valdr.min.js" type="text/javascript"></script> <script src="vendor/angular/angular-translate.2.18.1/angular-translate-loader-static-files.min.js"></script>
<script src="../vendor/valdr/valdr-message.min.js" type="text/javascript"></script> <script src="vendor/angular/angular-translate.2.18.1/angular-translate-storage-cookie.min.js"></script>
<!-- bootstrap.js --> <!--valdr-->
<script src="../vendor/bootstrap/js/bootstrap.min.js" type="text/javascript"></script> <script src="../vendor/valdr/valdr.min.js" type="text/javascript"></script>
<script src="../vendor/valdr/valdr-message.min.js" type="text/javascript"></script>
<script src="../vendor/lodash.min.js"></script> <!-- bootstrap.js -->
<script src="../vendor/bootstrap/js/bootstrap.min.js" type="text/javascript"></script>
<script src="../vendor/select2/select2.min.js" type="text/javascript"></script> <script src="../vendor/lodash.min.js"></script>
<!--biz-->
<!--must import-->
<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/services/UserService.js"></script>
<script type="application/javascript" src="../scripts/services/CommonService.js"></script>
<script type="application/javascript" src="../scripts/services/PermissionService.js"></script>
<script type="application/javascript" src="../scripts/services/ClusterService.js"></script>
<script type="application/javascript" src="../scripts/services/NamespaceService.js"></script>
<script type="application/javascript" src="../scripts/services/SystemRoleService.js"></script>
<script type="application/javascript" src="../scripts/AppUtils.js"></script> <script src="../vendor/select2/select2.min.js" type="text/javascript"></script>
<!--biz-->
<!--must import-->
<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/services/UserService.js"></script>
<script type="application/javascript" src="../scripts/services/CommonService.js"></script>
<script type="application/javascript" src="../scripts/services/PermissionService.js"></script>
<script type="application/javascript" src="../scripts/services/ClusterService.js"></script>
<script type="application/javascript" src="../scripts/services/NamespaceService.js"></script>
<script type="application/javascript" src="../scripts/services/SystemRoleService.js"></script>
<script type="application/javascript" src="../scripts/PageCommon.js"></script> <script type="application/javascript" src="../scripts/AppUtils.js"></script>
<script type="application/javascript" src="../scripts/directive/directive.js"></script>
<script type="application/javascript" src="../scripts/valdr.js"></script>
<script type="application/javascript" src="../scripts/controller/role/SystemRoleController.js"></script> <script type="application/javascript" src="../scripts/PageCommon.js"></script>
<script type="application/javascript" src="../scripts/directive/directive.js"></script>
<script type="application/javascript" src="../scripts/valdr.js"></script>
<script type="application/javascript" src="../scripts/controller/role/SystemRoleController.js"></script>
</body> </body>
</html> </html>
<!doctype html> <!doctype html>
<html ng-app="system_info"> <html ng-app="system_info">
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="icon" href="../img/config.png"> <link rel="icon" href="../img/config.png">
...@@ -9,135 +10,150 @@ ...@@ -9,135 +10,150 @@
<link rel="stylesheet" type="text/css" media='all' href="../vendor/angular/loading-bar.min.css"> <link rel="stylesheet" type="text/css" media='all' href="../vendor/angular/loading-bar.min.css">
<link rel="stylesheet" type="text/css" href="../styles/common-style.css"> <link rel="stylesheet" type="text/css" href="../styles/common-style.css">
<link rel="stylesheet" type="text/css" href="../vendor/select2/select2.min.css"> <link rel="stylesheet" type="text/css" href="../vendor/select2/select2.min.css">
<title>系统信息</title> <title>{{'SystemInfo.Title' | translate }}</title>
</head> </head>
<body> <body>
<apollonav></apollonav> <apollonav></apollonav>
<div class="container-fluid" ng-controller="SystemInfoController"> <div class="container-fluid" ng-controller="SystemInfoController">
<div class="col-md-10 col-md-offset-1 panel"> <div class="col-md-10 col-md-offset-1 panel">
<section class="panel-body" ng-show="isRootUser"> <section class="panel-body" ng-show="isRootUser">
<section class="row"> <section class="row">
<h3>系统信息 <h3>{{'SystemInfo.Title' | translate }}
</h3> </h3>
<h6 ng-show="systemInfo.version">系统版本: {{systemInfo.version}}</h6> <h6 ng-show="systemInfo.version">{{'SystemInfo.SystemVersion' | translate }}: {{systemInfo.version}}
<h6>环境列表来自于ApolloPortalDB.ServerConfig中的<strong>apollo.portal.envs</strong>配置,可以到<a href="server_config.html">系统参数</a>页面配置, </h6>
更多信息可以参考<a href="https://github.com/ctripcorp/apollo/wiki/%E5%88%86%E5%B8%83%E5%BC%8F%E9%83%A8%E7%BD%B2%E6%8C%87%E5%8D%97">分布式部署指南</a>中的<strong>apollo.portal.envs - 可支持的环境列表</strong>章节。 <h6 translate="SystemInfo.Tips1" translate-value-server-config-url="server_config.html"
</h6> translate-value-wiki-url="https://github.com/ctripcorp/apollo/wiki/%E5%88%86%E5%B8%83%E5%BC%8F%E9%83%A8%E7%BD%B2%E6%8C%87%E5%8D%97">
<h6>Meta server地址展示了该环境配置的meta server信息,更多信息可以参考<a href="https://github.com/ctripcorp/apollo/wiki/%E5%88%86%E5%B8%83%E5%BC%8F%E9%83%A8%E7%BD%B2%E6%8C%87%E5%8D%97">分布式部署指南</a>中的<strong>配置apollo-portal的meta service信息</strong>章节。 </h6>
</h6>
<h6 translate="SystemInfo.Tips2"
<div ng-repeat="env in systemInfo.environments"> translate-value-wiki-url="https://github.com/ctripcorp/apollo/wiki/%E5%88%86%E5%B8%83%E5%BC%8F%E9%83%A8%E7%BD%B2%E6%8C%87%E5%8D%97">
<hr> </h6>
<h4>环境: {{env.env}}
</h4> <div ng-repeat="env in systemInfo.environments">
<h5>Active: {{env.active}} <hr>
<span ng-show="env.active == false" style="color: #a94442;">(当前环境状态异常,请结合下方系统信息和Admin Service的Check Health结果排查)</span> <h4>{{'Common.Environment' | translate }}: {{env.env}}
</h5> </h4>
<h5>Meta server地址: {{env.metaServerAddress}}</h5> <h5>{{'SystemInfo.Active' | translate }}: {{env.active}}
<div ng-show="env.errorMessage" ng-bind="env.errorMessage" class="alert alert-danger" role="alert"> <span ng-show="env.active == false"
style="color: #a94442;">{{'SystemInfo.ActiveTips' | translate }}</span>
</h5>
<h5>{{'SystemInfo.MetaServerAddress' | translate }}: {{env.metaServerAddress}}</h5>
<div ng-show="env.errorMessage" ng-bind="env.errorMessage" class="alert alert-danger"
role="alert">
</div>
<h4 class="text-center">{{'SystemInfo.ConfigServices' | translate }}</h4>
<table class="table table-striped table-hover table-bordered">
<thead>
<tr>
<th>{{'SystemInfo.ConfigServices.Name' | translate }}</th>
<th>{{'SystemInfo.ConfigServices.InstanceId' | translate }}</th>
<th>{{'SystemInfo.ConfigServices.HomePageUrl' | translate }}</th>
<th>{{'SystemInfo.ConfigServices.CheckHealth' | translate }}</th>
</tr>
</thead>
<tbody>
<tr ng-show="(!env.configServices || env.configServices.length < 1)">
<td colspan="4">{{'SystemInfo.NoConfigServiceTips' | translate }}</td>
</tr>
<tr ng-show="env.configServices && env.configServices.length > 0"
ng-repeat="service in env.configServices">
<td>{{service.appName}}</td>
<td>{{service.instanceId}}</td>
<td>{{service.homepageUrl}}</td>
<td><a href="javascript:;"
ng-click="check(service.instanceId, service.homepageUrl)">{{'SystemInfo.Check' | translate }}</a>
</td>
</tr>
</tbody>
</table>
<h4 class="text-center">{{'SystemInfo.AdminServices' | translate }}</h4>
<table class="table table-striped table-hover table-bordered">
<thead>
<tr>
<th>{{'SystemInfo.AdminServices.Name' | translate }}</th>
<th>{{'SystemInfo.AdminServices.InstanceId' | translate }}</th>
<th>{{'SystemInfo.AdminServices.HomePageUrl' | translate }}</th>
<th>{{'SystemInfo.AdminServices.CheckHealth' | translate }}</th>
</tr>
</thead>
<tbody>
<tr ng-show="(!env.adminServices || env.adminServices.length < 1)">
<td colspan="4">{{'SystemInfo.NoAdminServiceTips' | translate }}</td>
</tr>
<tr ng-show="env.adminServices && env.adminServices.length > 0"
ng-repeat="service in env.adminServices">
<td>{{service.appName}}</td>
<td>{{service.instanceId}}</td>
<td>{{service.homepageUrl}}</td>
<td><a href="javascript:;"
ng-click="check(service.instanceId, service.homepageUrl)">{{'SystemInfo.Check' | translate }}</a>
</tr>
</tbody>
</table>
</div> </div>
<h4 class="text-center">Config Services</h4>
<table class="table table-striped table-hover table-bordered">
<thead>
<tr>
<th>Name</th>
<th>Instance Id</th>
<th>Home Page Url</th>
<th>Check Health</th>
</tr>
</thead>
<tbody>
<tr ng-show="(!env.configServices || env.configServices.length < 1)">
<td colspan="4">No config service found!</td>
</tr>
<tr ng-show="env.configServices && env.configServices.length > 0" ng-repeat="service in env.configServices">
<td>{{service.appName}}</td>
<td>{{service.instanceId}}</td>
<td>{{service.homepageUrl}}</td>
<td><a href="javascript:;" ng-click="check(service.instanceId, service.homepageUrl)">check</a>
</td>
</tr>
</tbody>
</table>
<h4 class="text-center">Admin Services</h4>
<table class="table table-striped table-hover table-bordered">
<thead>
<tr>
<th>Name</th>
<th>Instance Id</th>
<th>Home Page Url</th>
<th>Check Health</th>
</tr>
</thead>
<tbody>
<tr ng-show="(!env.adminServices || env.adminServices.length < 1)">
<td colspan="4">No admin service found!</td>
</tr>
<tr ng-show="env.adminServices && env.adminServices.length > 0" ng-repeat="service in env.adminServices">
<td>{{service.appName}}</td>
<td>{{service.instanceId}}</td>
<td>{{service.homepageUrl}}</td>
<td><a href="javascript:;" ng-click="check(service.instanceId, service.homepageUrl)">check</a>
</tr>
</tbody>
</table>
</div>
</section>
</section> </section>
</section>
<section class="panel-body text-center" ng-if="!isRootUser"> <section class="panel-body text-center" ng-if="!isRootUser">
<h4>当前页面只对Apollo管理员开放</h4> <h4>{{'Common.IsRootUser' | translate }}</h4>
</section> </section>
</div>
</div> </div>
</div>
<div ng-include="'../views/common/footer.html'"></div> <div ng-include="'../views/common/footer.html'"></div>
<!-- jquery.js --> <!-- jquery.js -->
<script src="../vendor/jquery.min.js" type="text/javascript"></script> <script src="../vendor/jquery.min.js" type="text/javascript"></script>
<!--angular--> <!--angular-->
<script src="../vendor/angular/angular.min.js"></script> <script src="../vendor/angular/angular.min.js"></script>
<script src="../vendor/angular/angular-route.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-resource.min.js"></script>
<script src="../vendor/angular/angular-toastr-1.4.1.tpls.min.js"></script> <script src="../vendor/angular/angular-toastr-1.4.1.tpls.min.js"></script>
<script src="../vendor/angular/loading-bar.min.js"></script> <script src="../vendor/angular/loading-bar.min.js"></script>
<script src="vendor/angular/angular-cookies.min.js"></script>
<!--valdr--> <script src="vendor/angular/angular-translate.2.18.1/angular-translate.min.js"></script>
<script src="../vendor/valdr/valdr.min.js" type="text/javascript"></script> <script src="vendor/angular/angular-translate.2.18.1/angular-translate-loader-static-files.min.js"></script>
<script src="../vendor/valdr/valdr-message.min.js" type="text/javascript"></script> <script src="vendor/angular/angular-translate.2.18.1/angular-translate-storage-cookie.min.js"></script>
<!-- bootstrap.js --> <!--valdr-->
<script src="../vendor/bootstrap/js/bootstrap.min.js" type="text/javascript"></script> <script src="../vendor/valdr/valdr.min.js" type="text/javascript"></script>
<script src="../vendor/valdr/valdr-message.min.js" type="text/javascript"></script>
<script src="../vendor/lodash.min.js"></script> <!-- bootstrap.js -->
<script src="../vendor/bootstrap/js/bootstrap.min.js" type="text/javascript"></script>
<script src="../vendor/select2/select2.min.js" type="text/javascript"></script> <script src="../vendor/lodash.min.js"></script>
<!--biz-->
<!--must import-->
<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/services/UserService.js"></script>
<script type="application/javascript" src="../scripts/services/CommonService.js"></script>
<script type="application/javascript" src="../scripts/services/PermissionService.js"></script>
<script type="application/javascript" src="../scripts/services/ClusterService.js"></script>
<script type="application/javascript" src="../scripts/services/NamespaceService.js"></script>
<script type="application/javascript" src="../scripts/services/SystemInfoService.js"></script>
<script type="application/javascript" src="../scripts/AppUtils.js"></script> <script src="../vendor/select2/select2.min.js" type="text/javascript"></script>
<!--biz-->
<!--must import-->
<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/services/UserService.js"></script>
<script type="application/javascript" src="../scripts/services/CommonService.js"></script>
<script type="application/javascript" src="../scripts/services/PermissionService.js"></script>
<script type="application/javascript" src="../scripts/services/ClusterService.js"></script>
<script type="application/javascript" src="../scripts/services/NamespaceService.js"></script>
<script type="application/javascript" src="../scripts/services/SystemInfoService.js"></script>
<script type="application/javascript" src="../scripts/PageCommon.js"></script> <script type="application/javascript" src="../scripts/AppUtils.js"></script>
<script type="application/javascript" src="../scripts/directive/directive.js"></script>
<script type="application/javascript" src="../scripts/valdr.js"></script>
<script type="application/javascript" src="../scripts/controller/SystemInfoController.js"></script> <script type="application/javascript" src="../scripts/PageCommon.js"></script>
<script type="application/javascript" src="../scripts/directive/directive.js"></script>
<script type="application/javascript" src="../scripts/valdr.js"></script>
<script type="application/javascript" src="../scripts/controller/SystemInfoController.js"></script>
</body> </body>
</html>
</html>
\ No newline at end of file
<!doctype html> <!doctype html>
<html ng-app="user"> <html ng-app="user">
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="icon" href="./img/config.png"> <link rel="icon" href="./img/config.png">
...@@ -10,99 +11,107 @@ ...@@ -10,99 +11,107 @@
<link rel="stylesheet" type="text/css" media='all' href="vendor/angular/loading-bar.min.css"> <link rel="stylesheet" type="text/css" media='all' href="vendor/angular/loading-bar.min.css">
<link rel="stylesheet" type="text/css" href="styles/common-style.css"> <link rel="stylesheet" type="text/css" href="styles/common-style.css">
<title>用户管理</title> <title>{{'UserMange.Title' | translate }}</title>
</head> </head>
<body> <body>
<apollonav></apollonav> <apollonav></apollonav>
<div class="container-fluid apollo-container"> <div class="container-fluid apollo-container">
<div class="row"> <div class="row">
<div class="col-md-8 col-md-offset-2"> <div class="col-md-8 col-md-offset-2">
<div class="panel"> <div class="panel">
<header class="panel-heading"> <header class="panel-heading">
用户管理 {{'UserMange.Title' | translate }}
<small> <small>
(仅对默认的Spring Security简单认证方式有效: -Dapollo_profile=github,auth) {{'UserMange.TitleTips' | translate }}
</small> </small>
</header> </header>
<form class="form-horizontal panel-body" name="appForm" ng-controller="UserController" <form class="form-horizontal panel-body" name="appForm" ng-controller="UserController"
valdr-type="App" valdr-type="App" ng-submit="createOrUpdateUser()">
ng-submit="createOrUpdateUser()"> <div class="form-group" valdr-form-group>
<div class="form-group" valdr-form-group> <label class="col-sm-2 control-label">
<label class="col-sm-2 control-label"> <apollorequiredfield></apollorequiredfield>
<apollorequiredfield></apollorequiredfield> {{'UserMange.UserName' | translate }}
用户名</label> </label>
<div class="col-sm-5"> <div class="col-sm-5">
<input type="text" class="form-control" name="username" ng-model="user.username"> <input type="text" class="form-control" name="username" ng-model="user.username">
<small>输入的用户名如果不存在,则新建。若已存在,则更新。</small> <small>{{'UserMange.UserNameTips' | translate }}</small>
</div>
</div> </div>
</div> <div class="form-group" valdr-form-group>
<div class="form-group" valdr-form-group> <label class="col-sm-2 control-label">
<label class="col-sm-2 control-label"> <apollorequiredfield></apollorequiredfield>
<apollorequiredfield></apollorequiredfield> {{'UserMange.Pwd' | translate }}
密码</label> </label>
<div class="col-sm-5"> <div class="col-sm-5">
<input type="text" class="form-control" name="password" ng-model="user.password"> <input type="text" class="form-control" name="password" ng-model="user.password">
</div>
</div> </div>
</div> <div class="form-group" valdr-form-group>
<div class="form-group" valdr-form-group> <label class="col-sm-2 control-label">
<label class="col-sm-2 control-label"> <apollorequiredfield></apollorequiredfield>
<apollorequiredfield></apollorequiredfield> {{'UserMange.Email' | translate }}
邮箱</label> </label>
<div class="col-sm-5"> <div class="col-sm-5">
<input type="text" class="form-control" name="password" ng-model="user.email"> <input type="text" class="form-control" name="password" ng-model="user.email">
</div>
</div> </div>
</div>
<div class="form-group"> <div class="form-group">
<div class="col-sm-offset-2 col-sm-9"> <div class="col-sm-offset-2 col-sm-9">
<button type="submit" class="btn btn-primary" <button type="submit" class="btn btn-primary"
ng-disabled="appForm.$invalid || submitBtnDisabled">提交 ng-disabled="appForm.$invalid || submitBtnDisabled">{{'Common.Submit' | translate }}
</button> </button>
</div>
</div> </div>
</div> </form>
</form>
</div>
</div> </div>
</div> </div>
</div> </div>
</div>
<div ng-include="'views/common/footer.html'"></div> <div ng-include="'views/common/footer.html'"></div>
<!--angular-->
<script src="vendor/angular/angular.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>
<script src="vendor/angular/angular-cookies.min.js"></script>
<!--angular--> <script src="vendor/angular/angular-translate.2.18.1/angular-translate.min.js"></script>
<script src="vendor/angular/angular.min.js"></script> <script src="vendor/angular/angular-translate.2.18.1/angular-translate-loader-static-files.min.js"></script>
<script src="vendor/angular/angular-resource.min.js"></script> <script src="vendor/angular/angular-translate.2.18.1/angular-translate-storage-cookie.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 --> <!-- jquery.js -->
<script src="vendor/jquery.min.js" type="text/javascript"></script> <script src="vendor/jquery.min.js" type="text/javascript"></script>
<script src="vendor/select2/select2.min.js" type="text/javascript"></script> <script src="vendor/select2/select2.min.js" type="text/javascript"></script>
<!-- bootstrap.js --> <!-- bootstrap.js -->
<script src="vendor/bootstrap/js/bootstrap.min.js" type="text/javascript"></script> <script src="vendor/bootstrap/js/bootstrap.min.js" type="text/javascript"></script>
<!--valdr--> <!--valdr-->
<script src="vendor/valdr/valdr.min.js" type="text/javascript"></script> <script src="vendor/valdr/valdr.min.js" type="text/javascript"></script>
<script src="vendor/valdr/valdr-message.min.js" type="text/javascript"></script> <script src="vendor/valdr/valdr-message.min.js" type="text/javascript"></script>
<script type="application/javascript" src="scripts/app.js"></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/services/AppService.js"></script>
<script type="application/javascript" src="scripts/services/EnvService.js"></script> <script type="application/javascript" src="scripts/services/EnvService.js"></script>
<script type="application/javascript" src="scripts/services/UserService.js"></script> <script type="application/javascript" src="scripts/services/UserService.js"></script>
<script type="application/javascript" src="scripts/services/CommonService.js"></script> <script type="application/javascript" src="scripts/services/CommonService.js"></script>
<script type="application/javascript" src="scripts/AppUtils.js"></script> <script type="application/javascript" src="scripts/AppUtils.js"></script>
<script type="application/javascript" src="scripts/services/OrganizationService.js"></script> <script type="application/javascript" src="scripts/services/OrganizationService.js"></script>
<script type="application/javascript" src="scripts/directive/directive.js"></script> <script type="application/javascript" src="scripts/directive/directive.js"></script>
<script type="application/javascript" src="scripts/services/PermissionService.js"></script> <script type="application/javascript" src="scripts/services/PermissionService.js"></script>
<script type="application/javascript" src="scripts/controller/UserController.js"></script> <script type="application/javascript" src="scripts/controller/UserController.js"></script>
<script src="scripts/valdr.js" type="text/javascript"></script> <script src="scripts/valdr.js" type="text/javascript"></script>
</body> </body>
</html>
</html>
\ No newline at end of file
/*
AngularJS v1.4.1
(c) 2010-2015 Google, Inc. http://angularjs.org
License: MIT
*/
(function(n,h,p){'use strict';function E(a){var f=[];r(f,h.noop).chars(a);return f.join("")}function g(a,f){var d={},c=a.split(","),b;for(b=0;b<c.length;b++)d[f?h.lowercase(c[b]):c[b]]=!0;return d}function F(a,f){function d(a,b,d,l){b=h.lowercase(b);if(s[b])for(;e.last()&&t[e.last()];)c("",e.last());u[b]&&e.last()==b&&c("",b);(l=v[b]||!!l)||e.push(b);var m={};d.replace(G,function(b,a,f,c,d){m[a]=q(f||c||d||"")});f.start&&f.start(b,m,l)}function c(b,a){var c=0,d;if(a=h.lowercase(a))for(c=e.length-
1;0<=c&&e[c]!=a;c--);if(0<=c){for(d=e.length-1;d>=c;d--)f.end&&f.end(e[d]);e.length=c}}"string"!==typeof a&&(a=null===a||"undefined"===typeof a?"":""+a);var b,k,e=[],m=a,l;for(e.last=function(){return e[e.length-1]};a;){l="";k=!0;if(e.last()&&w[e.last()])a=a.replace(new RegExp("([\\W\\w]*)<\\s*\\/\\s*"+e.last()+"[^>]*>","i"),function(a,b){b=b.replace(H,"$1").replace(I,"$1");f.chars&&f.chars(q(b));return""}),c("",e.last());else{if(0===a.indexOf("\x3c!--"))b=a.indexOf("--",4),0<=b&&a.lastIndexOf("--\x3e",
b)===b&&(f.comment&&f.comment(a.substring(4,b)),a=a.substring(b+3),k=!1);else if(x.test(a)){if(b=a.match(x))a=a.replace(b[0],""),k=!1}else if(J.test(a)){if(b=a.match(y))a=a.substring(b[0].length),b[0].replace(y,c),k=!1}else K.test(a)&&((b=a.match(z))?(b[4]&&(a=a.substring(b[0].length),b[0].replace(z,d)),k=!1):(l+="<",a=a.substring(1)));k&&(b=a.indexOf("<"),l+=0>b?a:a.substring(0,b),a=0>b?"":a.substring(b),f.chars&&f.chars(q(l)))}if(a==m)throw L("badparse",a);m=a}c()}function q(a){if(!a)return"";A.innerHTML=
a.replace(/</g,"&lt;");return A.textContent}function B(a){return a.replace(/&/g,"&amp;").replace(M,function(a){var d=a.charCodeAt(0);a=a.charCodeAt(1);return"&#"+(1024*(d-55296)+(a-56320)+65536)+";"}).replace(N,function(a){return"&#"+a.charCodeAt(0)+";"}).replace(/</g,"&lt;").replace(/>/g,"&gt;")}function r(a,f){var d=!1,c=h.bind(a,a.push);return{start:function(a,k,e){a=h.lowercase(a);!d&&w[a]&&(d=a);d||!0!==C[a]||(c("<"),c(a),h.forEach(k,function(d,e){var k=h.lowercase(e),g="img"===a&&"src"===k||
"background"===k;!0!==O[k]||!0===D[k]&&!f(d,g)||(c(" "),c(e),c('="'),c(B(d)),c('"'))}),c(e?"/>":">"))},end:function(a){a=h.lowercase(a);d||!0!==C[a]||(c("</"),c(a),c(">"));a==d&&(d=!1)},chars:function(a){d||c(B(a))}}}var L=h.$$minErr("$sanitize"),z=/^<((?:[a-zA-Z])[\w:-]*)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*(>?)/,y=/^<\/\s*([\w:-]+)[^>]*>/,G=/([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g,K=/^</,J=/^<\//,H=/\x3c!--(.*?)--\x3e/g,x=/<!DOCTYPE([^>]*?)>/i,
I=/<!\[CDATA\[(.*?)]]\x3e/g,M=/[\uD800-\uDBFF][\uDC00-\uDFFF]/g,N=/([^\#-~| |!])/g,v=g("area,br,col,hr,img,wbr");n=g("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr");p=g("rp,rt");var u=h.extend({},p,n),s=h.extend({},n,g("address,article,aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,script,section,table,ul")),t=h.extend({},p,g("a,abbr,acronym,b,bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s,samp,small,span,strike,strong,sub,sup,time,tt,u,var"));
n=g("circle,defs,desc,ellipse,font-face,font-face-name,font-face-src,g,glyph,hkern,image,linearGradient,line,marker,metadata,missing-glyph,mpath,path,polygon,polyline,radialGradient,rect,stop,svg,switch,text,title,tspan,use");var w=g("script,style"),C=h.extend({},v,s,t,u,n),D=g("background,cite,href,longdesc,src,usemap,xlink:href");n=g("abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,scope,scrolling,shape,size,span,start,summary,tabindex,target,title,type,valign,value,vspace,width");
p=g("accent-height,accumulate,additive,alphabetic,arabic-form,ascent,baseProfile,bbox,begin,by,calcMode,cap-height,class,color,color-rendering,content,cx,cy,d,dx,dy,descent,display,dur,end,fill,fill-rule,font-family,font-size,font-stretch,font-style,font-variant,font-weight,from,fx,fy,g1,g2,glyph-name,gradientUnits,hanging,height,horiz-adv-x,horiz-origin-x,ideographic,k,keyPoints,keySplines,keyTimes,lang,marker-end,marker-mid,marker-start,markerHeight,markerUnits,markerWidth,mathematical,max,min,offset,opacity,orient,origin,overline-position,overline-thickness,panose-1,path,pathLength,points,preserveAspectRatio,r,refX,refY,repeatCount,repeatDur,requiredExtensions,requiredFeatures,restart,rotate,rx,ry,slope,stemh,stemv,stop-color,stop-opacity,strikethrough-position,strikethrough-thickness,stroke,stroke-dasharray,stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,stroke-opacity,stroke-width,systemLanguage,target,text-anchor,to,transform,type,u1,u2,underline-position,underline-thickness,unicode,unicode-range,units-per-em,values,version,viewBox,visibility,width,widths,x,x-height,x1,x2,xlink:actuate,xlink:arcrole,xlink:role,xlink:show,xlink:title,xlink:type,xml:base,xml:lang,xml:space,xmlns,xmlns:xlink,y,y1,y2,zoomAndPan",
!0);var O=h.extend({},D,p,n),A=document.createElement("pre");h.module("ngSanitize",[]).provider("$sanitize",function(){this.$get=["$$sanitizeUri",function(a){return function(f){var d=[];F(f,r(d,function(c,b){return!/^unsafe/.test(a(c,b))}));return d.join("")}}]});h.module("ngSanitize").filter("linky",["$sanitize",function(a){var f=/((ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"\u201d\u2019]/i,d=/^mailto:/i;return function(c,b){function k(a){a&&g.push(E(a))}function e(a,
c){g.push("<a ");h.isDefined(b)&&g.push('target="',b,'" ');g.push('href="',a.replace(/"/g,"&quot;"),'">');k(c);g.push("</a>")}if(!c)return c;for(var m,l=c,g=[],n,p;m=l.match(f);)n=m[0],m[2]||m[4]||(n=(m[3]?"http://":"mailto:")+n),p=m.index,k(l.substr(0,p)),e(n,m[0].replace(d,"")),l=l.substring(p+m[0].length);k(l);return a(g.join(""))}}])})(window,window.angular);
//# sourceMappingURL=angular-sanitize.min.js.map
\ No newline at end of file
/*!
* angular-translate - v2.18.1 - 2018-05-19
*
* Copyright (c) 2018 The angular-translate team, Pascal Precht; Licensed MIT
*/
!function(e,i){"function"==typeof define&&define.amd?define([],function(){return i()}):"object"==typeof module&&module.exports?module.exports=i():i()}(0,function(){function e(n,a){"use strict";return function(r){if(!(r&&(angular.isArray(r.files)||angular.isString(r.prefix)&&angular.isString(r.suffix))))throw new Error("Couldn't load static files, no files and prefix or suffix specified!");r.files||(r.files=[{prefix:r.prefix,suffix:r.suffix}]);for(var e=function(e){if(!e||!angular.isString(e.prefix)||!angular.isString(e.suffix))throw new Error("Couldn't load static file, no prefix or suffix specified!");var i=[e.prefix,r.key,e.suffix].join("");return angular.isObject(r.fileMap)&&r.fileMap[i]&&(i=r.fileMap[i]),a(angular.extend({url:i,method:"GET"},r.$http)).then(function(e){return e.data},function(){return n.reject(r.key)})},i=[],t=r.files.length,f=0;f<t;f++)i.push(e({prefix:r.files[f].prefix,key:r.key,suffix:r.files[f].suffix}));return n.all(i).then(function(e){for(var i=e.length,r={},t=0;t<i;t++)for(var f in e[t])r[f]=e[t][f];return r})}}return e.$inject=["$q","$http"],angular.module("pascalprecht.translate").factory("$translateStaticFilesLoader",e),e.displayName="$translateStaticFilesLoader","pascalprecht.translate"});
\ No newline at end of file
/*!
* angular-translate - v2.18.1 - 2018-05-19
*
* Copyright (c) 2018 The angular-translate team, Pascal Precht; Licensed MIT
*/
!function(t,e){"function"==typeof define&&define.amd?define([],function(){return e()}):"object"==typeof module&&module.exports?module.exports=e():e()}(0,function(){function t(t){"use strict";var n;if(1===angular.version.major&&4<=angular.version.minor){var o=t.get("$cookies");n={get:function(t){return o.get(t)},put:function(t,e){o.put(t,e)}}}else{var r=t.get("$cookieStore");n={get:function(t){return r.get(t)},put:function(t,e){r.put(t,e)}}}return{get:function(t){return n.get(t)},set:function(t,e){n.put(t,e)},put:function(t,e){n.put(t,e)}}}return t.$inject=["$injector"],angular.module("pascalprecht.translate").factory("$translateCookieStorage",t),t.displayName="$translateCookieStorage","pascalprecht.translate"});
\ No newline at end of file
/*!
* angular-translate - v2.18.1 - 2018-05-19
*
* Copyright (c) 2018 The angular-translate team, Pascal Precht; Licensed MIT
*/
!function(t,e){"function"==typeof define&&define.amd?define([],function(){return e()}):"object"==typeof module&&module.exports?module.exports=e():e()}(0,function(){function t(e){"use strict";var n=e.storageKey(),a=e.storage(),t=function(){var t=e.preferredLanguage();angular.isString(t)?e.use(t):a.put(n,e.use())};t.displayName="fallbackFromIncorrectStorageValue",a?a.get(n)?e.use(a.get(n)).catch(t):t():angular.isString(e.preferredLanguage())&&e.use(e.preferredLanguage())}function e(t,r,e,i){"use strict";var z,c,T,x,F,I,_,n,V,R,D,K,U,M,H,G,q={},Y=[],B=t,J=[],Q="translate-cloak",W=!1,X=!1,Z=".",tt=!1,et=!1,nt=0,at=!0,a="default",s={default:function(t){return(t||"").split("-").join("_")},java:function(t){var e=(t||"").split("-").join("_"),n=e.split("_");return 1<n.length?n[0].toLowerCase()+"_"+n[1].toUpperCase():e},bcp47:function(t){var e=(t||"").split("_").join("-"),n=e.split("-");switch(n.length){case 1:n[0]=n[0].toLowerCase();break;case 2:n[0]=n[0].toLowerCase(),4===n[1].length?n[1]=n[1].charAt(0).toUpperCase()+n[1].slice(1).toLowerCase():n[1]=n[1].toUpperCase();break;case 3:n[0]=n[0].toLowerCase(),n[1]=n[1].charAt(0).toUpperCase()+n[1].slice(1).toLowerCase(),n[2]=n[2].toUpperCase();break;default:return e}return n.join("-")},"iso639-1":function(t){return(t||"").split("_").join("-").split("-")[0].toLowerCase()}},o=function(){if(angular.isFunction(i.getLocale))return i.getLocale();var t,e,n=r.$get().navigator,a=["language","browserLanguage","systemLanguage","userLanguage"];if(angular.isArray(n.languages))for(t=0;t<n.languages.length;t++)if((e=n.languages[t])&&e.length)return e;for(t=0;t<a.length;t++)if((e=n[a[t]])&&e.length)return e;return null};o.displayName="angular-translate/service: getFirstBrowserLanguage";var rt=function(){var t=o()||"";return s[a]&&(t=s[a](t)),t};rt.displayName="angular-translate/service: getLocale";var it=function(t,e){for(var n=0,a=t.length;n<a;n++)if(t[n]===e)return n;return-1},st=function(){return this.toString().replace(/^\s+|\s+$/g,"")},f=function(t){return angular.isString(t)?t.toLowerCase():t},ot=function(t){if(t){for(var e,n=[],a=f(t),r=0,i=Y.length;r<i;r++)n.push(f(Y[r]));if(-1<(r=it(n,a)))return Y[r];if(c)for(var s in c)if(c.hasOwnProperty(s)){var o=!1,l=Object.prototype.hasOwnProperty.call(c,s)&&f(s)===f(t);if("*"===s.slice(-1)&&(o=f(s.slice(0,-1))===f(t.slice(0,s.length-1))),(l||o)&&(e=c[s],-1<it(n,f(e))))return e}var u=t.split("_");return 1<u.length&&-1<it(n,f(u[0]))?u[0]:void 0}},lt=function(t,e){if(!t&&!e)return q;if(t&&!e){if(angular.isString(t))return q[t]}else angular.isObject(q[t])||(q[t]={}),angular.extend(q[t],ut(e));return this};this.translations=lt,this.cloakClassName=function(t){return t?(Q=t,this):Q},this.nestedObjectDelimeter=function(t){return t?(Z=t,this):Z};var ut=function(t,e,n,a){var r,i,s;for(r in e||(e=[]),n||(n={}),t)Object.prototype.hasOwnProperty.call(t,r)&&(s=t[r],angular.isObject(s)?ut(s,e.concat(r),n,r):(i=e.length?""+e.join(Z)+Z+r:r,e.length&&r===a&&(n[""+e.join(Z)]="@:"+i),n[i]=s));return n};ut.displayName="flatObject",this.addInterpolation=function(t){return J.push(t),this},this.useMessageFormatInterpolation=function(){return this.useInterpolation("$translateMessageFormatInterpolation")},this.useInterpolation=function(t){return R=t,this},this.useSanitizeValueStrategy=function(t){return e.useStrategy(t),this},this.preferredLanguage=function(t){return t?(ct(t),this):z};var ct=function(t){return t&&(z=t),z};this.translationNotFoundIndicator=function(t){return this.translationNotFoundIndicatorLeft(t),this.translationNotFoundIndicatorRight(t),this},this.translationNotFoundIndicatorLeft=function(t){return t?(U=t,this):U},this.translationNotFoundIndicatorRight=function(t){return t?(M=t,this):M},this.fallbackLanguage=function(t){return ft(t),this};var ft=function(t){return t?(angular.isString(t)?(x=!0,T=[t]):angular.isArray(t)&&(x=!1,T=t),angular.isString(z)&&it(T,z)<0&&T.push(z),this):x?T[0]:T};this.use=function(t){if(t){if(!q[t]&&!D)throw new Error("$translateProvider couldn't find translationTable for langKey: '"+t+"'");return F=t,this}return F},this.resolveClientLocale=function(){return rt()};var gt=function(t){return t?(B=t,this):n?n+B:B};this.storageKey=gt,this.useUrlLoader=function(t,e){return this.useLoader("$translateUrlLoader",angular.extend({url:t},e))},this.useStaticFilesLoader=function(t){return this.useLoader("$translateStaticFilesLoader",t)},this.useLoader=function(t,e){return D=t,K=e||{},this},this.useLocalStorage=function(){return this.useStorage("$translateLocalStorage")},this.useCookieStorage=function(){return this.useStorage("$translateCookieStorage")},this.useStorage=function(t){return _=t,this},this.storagePrefix=function(t){return t?(n=t,this):t},this.useMissingTranslationHandlerLog=function(){return this.useMissingTranslationHandler("$translateMissingTranslationHandlerLog")},this.useMissingTranslationHandler=function(t){return V=t,this},this.usePostCompiling=function(t){return W=!!t,this},this.forceAsyncReload=function(t){return X=!!t,this},this.uniformLanguageTag=function(t){return t?angular.isString(t)&&(t={standard:t}):t={},a=t.standard,this},this.determinePreferredLanguage=function(t){var e=t&&angular.isFunction(t)?t():rt();return z=Y.length&&ot(e)||e,this},this.registerAvailableLanguageKeys=function(t,e){return t?(Y=t,e&&(c=e),this):Y},this.useLoaderCache=function(t){return!1===t?H=void 0:!0===t?H=!0:void 0===t?H="$translationCache":t&&(H=t),this},this.directivePriority=function(t){return void 0===t?nt:(nt=t,this)},this.statefulFilter=function(t){return void 0===t?at:(at=t,this)},this.postProcess=function(t){return G=t||void 0,this},this.keepContent=function(t){return et=!!t,this},this.$get=["$log","$injector","$rootScope","$q",function(t,o,s,m){var i,$,y,b=o.get(R||"$translateDefaultInterpolation"),S=!1,L={},f={},j=function(t,s,o,l,u,c){!F&&z&&(F=z);var a=u&&u!==F?ot(u)||u:F;if(u&&v(u),angular.isArray(t)){return function(t){for(var a={},e=[],n=function(e){var n=m.defer(),t=function(t){a[e]=t,n.resolve([e,t])};return j(e,s,o,l,u,c).then(t,t),n.promise},r=0,i=t.length;r<i;r++)e.push(n(t[r]));return m.all(e).then(function(){return a})}(t)}var e=m.defer();t&&(t=st.apply(t));var n=function(){var t=f[a]||f[z];if($=0,_&&!t){var e=i.get(B);if(t=f[e],T&&T.length){var n=it(T,e);$=0===n?1:0,it(T,z)<0&&T.push(z)}}return t}();if(n){var r=function(){u||(a=F),h(t,s,o,l,a,c).then(e.resolve,e.reject)};r.displayName="promiseResolved",n.finally(r).catch(angular.noop)}else h(t,s,o,l,a,c).then(e.resolve,e.reject);return e.promise},w=function(t){return U&&(t=[U,t].join(" ")),M&&(t=[t,M].join(" ")),t},l=function(t){F=t,_&&i.put(j.storageKey(),F),s.$emit("$translateChangeSuccess",{language:t}),b.setLocale(F);var e=function(t,e){L[e].setLocale(F)};e.displayName="eachInterpolatorLocaleSetter",angular.forEach(L,e),s.$emit("$translateChangeEnd",{language:t})},u=function(n){if(!n)throw"No language key specified for loading.";var a=m.defer();s.$emit("$translateLoadingStart",{language:n}),S=!0;var t=H;"string"==typeof t&&(t=o.get(t));var e=angular.extend({},K,{key:n,$http:angular.extend({},{cache:t},K.$http)}),r=function(t){var e={};s.$emit("$translateLoadingSuccess",{language:n}),angular.isArray(t)?angular.forEach(t,function(t){angular.extend(e,ut(t))}):angular.extend(e,ut(t)),S=!1,a.resolve({key:n,table:e}),s.$emit("$translateLoadingEnd",{language:n})};r.displayName="onLoaderSuccess";var i=function(t){s.$emit("$translateLoadingError",{language:t}),a.reject(t),s.$emit("$translateLoadingEnd",{language:t})};return i.displayName="onLoaderError",o.get(D)(e).then(r,i),a.promise};if(_&&(!(i=o.get(_)).get||!i.put))throw new Error("Couldn't use storage '"+_+"', missing get() or put() method!");if(J.length){var e=function(t){var e=o.get(t);e.setLocale(z||F),L[e.getInterpolationIdentifier()]=e};e.displayName="interpolationFactoryAdder",angular.forEach(J,e)}var c=function(a,r,i,s,o){var l=m.defer(),t=function(t){if(Object.prototype.hasOwnProperty.call(t,r)&&null!==t[r]){s.setLocale(a);var e=t[r];if("@:"===e.substr(0,2))c(a,e.substr(2),i,s,o).then(l.resolve,l.reject);else{var n=s.interpolate(t[r],i,"service",o,r);n=O(r,t[r],n,i,a),l.resolve(n)}s.setLocale(F)}else l.reject()};return t.displayName="fallbackTranslationResolver",function(t){var e=m.defer();if(Object.prototype.hasOwnProperty.call(q,t))e.resolve(q[t]);else if(f[t]){var n=function(t){lt(t.key,t.table),e.resolve(t.table)};n.displayName="translationTableResolver",f[t].then(n,e.reject)}else e.reject();return e.promise}(a).then(t,l.reject),l.promise},g=function(t,e,n,a,r){var i,s=q[t];if(s&&Object.prototype.hasOwnProperty.call(s,e)&&null!==s[e]){if(a.setLocale(t),i=a.interpolate(s[e],n,"filter",r,e),i=O(e,s[e],i,n,t,r),!angular.isString(i)&&angular.isFunction(i.$$unwrapTrustedValue)){var o=i.$$unwrapTrustedValue();if("@:"===o.substr(0,2))return g(t,o.substr(2),n,a,r)}else if("@:"===i.substr(0,2))return g(t,i.substr(2),n,a,r);a.setLocale(F)}return i},C=function(t,e,n,a){return V?o.get(V)(t,F,e,n,a):t},N=function(t,e,n,a,r,i){var s=m.defer();if(t<T.length){var o=T[t];c(o,e,n,a,i).then(function(t){s.resolve(t)},function(){return N(t+1,e,n,a,r,i).then(s.resolve,s.reject)})}else if(r)s.resolve(r);else{var l=C(e,n,r);V&&l?s.resolve(l):s.reject(w(e))}return s.promise},p=function(t,e,n,a,r){var i;if(t<T.length){var s=T[t];(i=g(s,e,n,a,r))||""===i||(i=p(t+1,e,n,a))}return i},h=function(t,e,n,a,r,i){var s,o,l,u,c,f=m.defer(),g=r?q[r]:q,p=n?L[n]:b;if(g&&Object.prototype.hasOwnProperty.call(g,t)&&null!==g[t]){var h=g[t];if("@:"===h.substr(0,2))j(h.substr(2),e,n,a,r,i).then(f.resolve,f.reject);else{var d=p.interpolate(h,e,"service",i,t);d=O(t,h,d,e,r),f.resolve(d)}}else{var v;V&&!S&&(v=C(t,e,a)),r&&T&&T.length?(s=t,o=e,l=p,u=a,c=i,N(0<y?y:$,s,o,l,u,c)).then(function(t){f.resolve(t)},function(t){f.reject(w(t))}):V&&!S&&v?a?f.resolve(a):f.resolve(v):a?f.resolve(a):f.reject(w(t))}return f.promise},d=function(t,e,n,a,r){var i,s=a?q[a]:q,o=b;if(L&&Object.prototype.hasOwnProperty.call(L,n)&&(o=L[n]),s&&Object.prototype.hasOwnProperty.call(s,t)&&null!==s[t]){var l=s[t];"@:"===l.substr(0,2)?i=d(l.substr(2),e,n,a,r):(i=o.interpolate(l,e,"filter",r,t),i=O(t,l,i,e,a,r))}else{var u;V&&!S&&(u=C(t,e,r)),i=a&&T&&T.length?p(($=0)<y?y:$,t,e,o,r):V&&!S&&u?u:w(t)}return i},O=function(t,e,n,a,r,i){var s=G;return s&&("string"==typeof s&&(s=o.get(s)),s)?s(t,e,n,a,r,i):n},v=function(t){q[t]||!D||f[t]||(f[t]=u(t).then(function(t){return lt(t.key,t.table),t}))};j.preferredLanguage=function(t){return t&&ct(t),z},j.cloakClassName=function(){return Q},j.nestedObjectDelimeter=function(){return Z},j.fallbackLanguage=function(t){if(null!=t){if(ft(t),D&&T&&T.length)for(var e=0,n=T.length;e<n;e++)f[T[e]]||(f[T[e]]=u(T[e]));j.use(j.use())}return x?T[0]:T},j.useFallbackLanguage=function(t){if(null!=t)if(t){var e=it(T,t);-1<e&&(y=e)}else y=0},j.proposedLanguage=function(){return I},j.storage=function(){return i},j.negotiateLocale=ot,j.use=function(e){if(!e)return F;var n=m.defer();n.promise.then(null,angular.noop),s.$emit("$translateChangeStart",{language:e});var t=ot(e);return 0<Y.length&&!t?m.reject(e):(t&&(e=t),I=e,!X&&q[e]||!D||f[e]?f[e]?f[e].then(function(t){return I===t.key&&l(t.key),n.resolve(t.key),t},function(t){return!F&&T&&0<T.length&&T[0]!==t?j.use(T[0]).then(n.resolve,n.reject):n.reject(t)}):(n.resolve(e),l(e)):(f[e]=u(e).then(function(t){return lt(t.key,t.table),n.resolve(t.key),I===e&&l(t.key),t},function(t){return s.$emit("$translateChangeError",{language:t}),n.reject(t),s.$emit("$translateChangeEnd",{language:t}),m.reject(t)}),f[e].finally(function(){var t;I===(t=e)&&(I=void 0),f[t]=void 0}).catch(angular.noop)),n.promise)},j.resolveClientLocale=function(){return rt()},j.storageKey=function(){return gt()},j.isPostCompilingEnabled=function(){return W},j.isForceAsyncReloadEnabled=function(){return X},j.isKeepContent=function(){return et},j.refresh=function(t){if(!D)throw new Error("Couldn't refresh translation table, no loader registered!");s.$emit("$translateRefreshStart",{language:t});var e=m.defer(),n={};function a(e){var t=u(e);return(f[e]=t).then(function(t){q[e]={},lt(e,t.table),n[e]=!0},angular.noop),t}if(e.promise.then(function(){for(var t in q)q.hasOwnProperty(t)&&(t in n||delete q[t]);F&&l(F)},angular.noop).finally(function(){s.$emit("$translateRefreshEnd",{language:t})}),t)q[t]?a(t).then(e.resolve,e.reject):e.reject();else{var r=T&&T.slice()||[];F&&-1===r.indexOf(F)&&r.push(F),m.all(r.map(a)).then(e.resolve,e.reject)}return e.promise},j.instant=function(t,e,n,a,r){var i=a&&a!==F?ot(a)||a:F;if(null===t||angular.isUndefined(t))return t;if(a&&v(a),angular.isArray(t)){for(var s={},o=0,l=t.length;o<l;o++)s[t[o]]=j.instant(t[o],e,n,a,r);return s}if(angular.isString(t)&&t.length<1)return t;t&&(t=st.apply(t));var u,c,f=[];z&&f.push(z),i&&f.push(i),T&&T.length&&(f=f.concat(T));for(var g=0,p=f.length;g<p;g++){var h=f[g];if(q[h]&&void 0!==q[h][t]&&(u=d(t,e,n,i,r)),void 0!==u)break}u||""===u||(U||M?u=w(t):(u=b.interpolate(t,e,"filter",r),V&&!S&&(c=C(t,e,r)),V&&!S&&c&&(u=c)));return u},j.versionInfo=function(){return"2.18.1"},j.loaderCache=function(){return H},j.directivePriority=function(){return nt},j.statefulFilter=function(){return at},j.isReady=function(){return tt};var n=m.defer();n.promise.then(function(){tt=!0}),j.onReady=function(t){var e=m.defer();return angular.isFunction(t)&&e.promise.then(t),tt?e.resolve():n.promise.then(e.resolve),e.promise},j.getAvailableLanguageKeys=function(){return 0<Y.length?Y:null},j.getTranslationTable=function(t){return(t=t||j.use())&&q[t]?angular.copy(q[t]):null};var a=s.$on("$translateReady",function(){n.resolve(),a(),a=null}),r=s.$on("$translateChangeEnd",function(){n.resolve(),r(),r=null});if(D){if(angular.equals(q,{})&&j.use()&&j.use(j.use()),T&&T.length)for(var E=function(t){return lt(t.key,t.table),s.$emit("$translateChangeEnd",{language:t.key}),t},k=0,P=T.length;k<P;k++){var A=T[k];!X&&q[A]||(f[A]=u(A).then(E))}}else s.$emit("$translateReady",{language:j.use()});return j}]}function n(s,o){"use strict";var t={};return t.setLocale=function(t){t},t.getInterpolationIdentifier=function(){return"default"},t.useSanitizeValueStrategy=function(t){return o.useStrategy(t),this},t.interpolate=function(t,e,n,a,r){var i;return e=e||{},e=o.sanitize(e,"params",a,n),angular.isNumber(t)?i=""+t:angular.isString(t)?(i=s(t)(e),i=o.sanitize(i,"text",a,n)):i="",i},t}function a(S,L,j,w,C){"use strict";var N=function(t){return angular.isString(t)?t.toLowerCase():t};return{restrict:"AE",scope:!0,priority:S.directivePriority(),compile:function(t,h){var d=h.translateValues?h.translateValues:void 0,v=h.translateInterpolation?h.translateInterpolation:void 0,m=h.translateSanitizeStrategy?h.translateSanitizeStrategy:void 0,$=t[0].outerHTML.match(/translate-value-+/i),y="^(.*)("+L.startSymbol()+".*"+L.endSymbol()+")(.*)",b="^(.*)"+L.startSymbol()+"(.*)"+L.endSymbol()+"(.*)";return function(r,l,u){r.interpolateParams={},r.preText="",r.postText="",r.translateNamespace=function t(e){if(e.translateNamespace)return e.translateNamespace;if(e.$parent)return t(e.$parent)}(r);var i={},s=function(t){if(angular.isFunction(s._unwatchOld)&&(s._unwatchOld(),s._unwatchOld=void 0),angular.equals(t,"")||!angular.isDefined(t)){var e=function(){return this.toString().replace(/^\s+|\s+$/g,"")}.apply(l.text()),n=e.match(y);if(angular.isArray(n)){r.preText=n[1],r.postText=n[3],i.translate=L(n[2])(r.$parent);var a=e.match(b);angular.isArray(a)&&a[2]&&a[2].length&&(s._unwatchOld=r.$watch(a[2],function(t){i.translate=t,c()}))}else i.translate=e||void 0}else i.translate=t;c()},t=function(e){u.$observe(e,function(t){i[e]=t,c()})};!function(t,e,n){if(e.translateValues&&angular.extend(t,w(e.translateValues)(r.$parent)),$)for(var a in n)Object.prototype.hasOwnProperty.call(e,a)&&"translateValue"===a.substr(0,14)&&"translateValues"!==a&&(t[N(a.substr(14,1))+a.substr(15)]=n[a])}(r.interpolateParams,u,h);var e=!0;for(var n in u.$observe("translate",function(t){void 0===t?s(""):""===t&&e||(i.translate=t,c()),e=!1}),u)u.hasOwnProperty(n)&&"translateAttr"===n.substr(0,13)&&13<n.length&&t(n);if(u.$observe("translateDefault",function(t){r.defaultText=t,c()}),m&&u.$observe("translateSanitizeStrategy",function(t){r.sanitizeStrategy=w(t)(r.$parent),c()}),d&&u.$observe("translateValues",function(t){t&&r.$parent.$watch(function(){angular.extend(r.interpolateParams,w(t)(r.$parent))})}),$){var a=function(n){u.$observe(n,function(t){var e=N(n.substr(14,1))+n.substr(15);r.interpolateParams[e]=t})};for(var o in u)Object.prototype.hasOwnProperty.call(u,o)&&"translateValue"===o.substr(0,14)&&"translateValues"!==o&&a(o)}var c=function(){for(var t in i)i.hasOwnProperty(t)&&void 0!==i[t]&&f(t,i[t],r,r.interpolateParams,r.defaultText,r.translateNamespace)},f=function(e,t,n,a,r,i){t?(i&&"."===t.charAt(0)&&(t=i+t),S(t,a,v,r,n.translateLanguage,n.sanitizeStrategy).then(function(t){g(t,n,!0,e)},function(t){g(t,n,!1,e)})):g(t,n,!1,e)},g=function(t,e,n,a){if(n||void 0!==e.defaultText&&(t=e.defaultText),"translate"===a){(n||!n&&!S.isKeepContent()&&void 0===u.translateKeepContent)&&l.empty().append(e.preText+t+e.postText);var r=S.isPostCompilingEnabled(),i=void 0!==h.translateCompile,s=i&&"false"!==h.translateCompile;(r&&!i||s)&&j(l.contents())(e)}else{var o=u.$attr[a];"data-"===o.substr(0,5)&&(o=o.substr(5)),o=o.substr(15),l.attr(o,t)}};(d||$||u.translateDefault)&&r.$watch("interpolateParams",c,!0),r.$on("translateLanguageChanged",c);var p=C.$on("$translateChangeSuccess",c);l.text().length?u.translate?s(u.translate):s(""):u.translate&&s(u.translate),c(),r.$on("$destroy",p)}}}}function r(u,c){"use strict";return{restrict:"A",priority:u.directivePriority(),link:function(n,a,r){var i,s,o,l={},t=function(){angular.forEach(i,function(t,e){t&&(l[e]=!0,n.translateNamespace&&"."===t.charAt(0)&&(t=n.translateNamespace+t),u(t,s,r.translateInterpolation,void 0,n.translateLanguage,o).then(function(t){a.attr(e,t)},function(t){a.attr(e,t)}))}),angular.forEach(l,function(t,e){i[e]||(a.removeAttr(e),delete l[e])})};f(n,r.translateAttr,function(t){i=t},t),f(n,r.translateValues,function(t){s=t},t),f(n,r.translateSanitizeStrategy,function(t){o=t},t),r.translateValues&&n.$watch(r.translateValues,t,!0),n.$on("translateLanguageChanged",t);var e=c.$on("$translateChangeSuccess",t);t(),n.$on("$destroy",e)}}}function f(t,e,n,a){"use strict";e&&("::"===e.substr(0,2)?e=e.substr(2):t.$watch(e,function(t){n(t),a()},!0),n(t.$eval(e)))}function i(s,o){"use strict";return{compile:function(t){var i=function(t){t.addClass(s.cloakClassName())};return i(t),function(t,e,n){var a=function(t){t.removeClass(s.cloakClassName())}.bind(this,e),r=i.bind(this,e);n.translateCloak&&n.translateCloak.length?(n.$observe("translateCloak",function(t){s(t).then(a,r)}),o.$on("$translateChangeSuccess",function(){s(n.translateCloak).then(a,r)})):s.onReady(a)}}}}function s(){"use strict";return{restrict:"A",scope:!0,compile:function(){return{pre:function(t,e,n){t.translateNamespace=function t(e){if(e.translateNamespace)return e.translateNamespace;if(e.$parent)return t(e.$parent)}(t),t.translateNamespace&&"."===n.translateNamespace.charAt(0)?t.translateNamespace+=n.translateNamespace:t.translateNamespace=n.translateNamespace}}}}}function o(){"use strict";return{restrict:"A",scope:!0,compile:function(){return function(e,t,n){n.$observe("translateLanguage",function(t){e.translateLanguage=t}),e.$watch("translateLanguage",function(){e.$broadcast("translateLanguageChanged")})}}}}function l(i,s){"use strict";var t=function(t,e,n,a){if(!angular.isObject(e)){var r=this||{__SCOPE_IS_NOT_AVAILABLE:"More info at https://github.com/angular/angular.js/commit/8863b9d04c722b278fa93c5d66ad1e578ad6eb1f"};e=i(e)(r)}return s.instant(t,e,n,a)};return s.statefulFilter()&&(t.$stateful=!0),t}function u(t){"use strict";return t("translations")}return t.$inject=["$translate"],e.$inject=["$STORAGE_KEY","$windowProvider","$translateSanitizationProvider","pascalprechtTranslateOverrider"],n.$inject=["$interpolate","$translateSanitization"],a.$inject=["$translate","$interpolate","$compile","$parse","$rootScope"],r.$inject=["$translate","$rootScope"],i.$inject=["$translate","$rootScope"],l.$inject=["$parse","$translate"],u.$inject=["$cacheFactory"],angular.module("pascalprecht.translate",["ng"]).run(t),t.displayName="runTranslate",angular.module("pascalprecht.translate").provider("$translateSanitization",function(){"use strict";var n,a,g,p=null,h=!1,d=!1;(g={sanitize:function(t,e){return"text"===e&&(t=i(t)),t},escape:function(t,e){return"text"===e&&(t=r(t)),t},sanitizeParameters:function(t,e){return"params"===e&&(t=o(t,i)),t},escapeParameters:function(t,e){return"params"===e&&(t=o(t,r)),t},sce:function(t,e,n){return"text"===e?t=s(t):"params"===e&&"filter"!==n&&(t=o(t,r)),t},sceParameters:function(t,e){return"params"===e&&(t=o(t,s)),t}}).escaped=g.escapeParameters,this.addStrategy=function(t,e){return g[t]=e,this},this.removeStrategy=function(t){return delete g[t],this},this.useStrategy=function(t){return h=!0,p=t,this},this.$get=["$injector","$log",function(u,c){var e,f={};return u.has("$sanitize")&&(n=u.get("$sanitize")),u.has("$sce")&&(a=u.get("$sce")),{useStrategy:(e=this,function(t){e.useStrategy(t)}),sanitize:function(t,e,n,a){if(p||h||d||(c.warn("pascalprecht.translate.$translateSanitization: No sanitization strategy has been configured. This can have serious security implications. See http://angular-translate.github.io/docs/#/guide/19_security for details."),d=!0),n||null===n||(n=p),!n)return t;a||(a="service");var r,i,s,o,l=angular.isArray(n)?n:[n];return r=t,i=e,s=a,o=l,angular.forEach(o,function(e){if(angular.isFunction(e))r=e(r,i,s);else if(angular.isFunction(g[e]))r=g[e](r,i,s);else{if(!angular.isString(g[e]))throw new Error("pascalprecht.translate.$translateSanitization: Unknown sanitization strategy: '"+e+"'");if(!f[g[e]])try{f[g[e]]=u.get(g[e])}catch(t){throw f[g[e]]=function(){},new Error("pascalprecht.translate.$translateSanitization: Unknown sanitization strategy: '"+e+"'")}r=f[g[e]](r,i,s)}}),r}}}];var r=function(t){var e=angular.element("<div></div>");return e.text(t),e.html()},i=function(t){if(!n)throw new Error("pascalprecht.translate.$translateSanitization: Error cannot find $sanitize service. Either include the ngSanitize module (https://docs.angularjs.org/api/ngSanitize) or use a sanitization strategy which does not depend on $sanitize, such as 'escape'.");return n(t)},s=function(t){if(!a)throw new Error("pascalprecht.translate.$translateSanitization: Error cannot find $sce service.");return a.trustAsHtml(t)},o=function(t,n,a){if(angular.isDate(t))return t;if(angular.isObject(t)){var r=angular.isArray(t)?[]:{};if(a){if(-1<a.indexOf(t))throw new Error("pascalprecht.translate.$translateSanitization: Error cannot interpolate parameter due recursive object")}else a=[];return a.push(t),angular.forEach(t,function(t,e){angular.isFunction(t)||(r[e]=o(t,n,a))}),a.splice(-1,1),r}return angular.isNumber(t)?t:!0===t||!1===t?t:angular.isUndefined(t)||null===t?t:n(t)}}),angular.module("pascalprecht.translate").constant("pascalprechtTranslateOverrider",{}).provider("$translate",e),e.displayName="displayName",angular.module("pascalprecht.translate").factory("$translateDefaultInterpolation",n),n.displayName="$translateDefaultInterpolation",angular.module("pascalprecht.translate").constant("$STORAGE_KEY","NG_TRANSLATE_LANG_KEY"),angular.module("pascalprecht.translate").directive("translate",a),a.displayName="translateDirective",angular.module("pascalprecht.translate").directive("translateAttr",r),r.displayName="translateAttrDirective",angular.module("pascalprecht.translate").directive("translateCloak",i),i.displayName="translateCloakDirective",angular.module("pascalprecht.translate").directive("translateNamespace",s),s.displayName="translateNamespaceDirective",angular.module("pascalprecht.translate").directive("translateLanguage",o),o.displayName="translateLanguageDirective",angular.module("pascalprecht.translate").filter("translate",l),l.displayName="translateFilterFactory",angular.module("pascalprecht.translate").factory("$translationCache",u),u.displayName="$translationCache","pascalprecht.translate"});
\ No newline at end of file
<div class="footer"> <div class="footer">
<hr> <hr>
<p class="text-center"> <p class="text-center">
<span class="glyphicon glyphicon-copyright-mark" aria-hidden="true"></span>携程 框架研发部 <span class="glyphicon glyphicon-copyright-mark" aria-hidden="true"></span>{{'Common.Ctrip' | translate }} {{'Common.CtripDepartment' | translate }}
<a href="https://github.com/ctripcorp/apollo" target="_blank"> <a href="https://github.com/ctripcorp/apollo" target="_blank">
<img src="../../img/github.png" style="width: 50px; height: 20px;"> <img src="../../img/github.png" style="width: 50px; height: 20px;">
</a> </a>
......
...@@ -4,13 +4,13 @@ ...@@ -4,13 +4,13 @@
<img class="navbar-brand side-bar-switch cursor-pointer" src="../../img/show_sidebar.png" <img class="navbar-brand side-bar-switch cursor-pointer" src="../../img/show_sidebar.png"
onMouseOver="this.style.background='#f1f2f7'" onMouseOver="this.style.background='#f1f2f7'"
onMouseOut="this.style.background='#fff'" onMouseOut="this.style.background='#fff'"
data-tooltip="tooltip" data-placement="bottom" title="显示导航栏" data-tooltip="tooltip" data-placement="bottom" title="{{'Common.Nav.ShowNavBar' | translate }}"
ng-show="viewMode == 2 && !showSideBar" ng-show="viewMode == 2 && !showSideBar"
ng-click="showSideBar = !showSideBar"> ng-click="showSideBar = !showSideBar">
<img class="navbar-brand side-bar-switch cursor-pointer" src="../../img/hide_sidebar.png" <img class="navbar-brand side-bar-switch cursor-pointer" src="../../img/hide_sidebar.png"
onMouseOver="this.style.background='#f1f2f7'" onMouseOver="this.style.background='#f1f2f7'"
onMouseOut="this.style.background='#fff'" onMouseOut="this.style.background='#fff'"
data-tooltip="tooltip" data-placement="bottom" title="隐藏导航栏" data-tooltip="tooltip" data-placement="bottom" title="{{'Common.Nav.HideNavBar' | translate }}"
ng-show="viewMode == 2 && showSideBar" ng-show="viewMode == 2 && showSideBar"
ng-click="showSideBar = !showSideBar"> ng-click="showSideBar = !showSideBar">
<a class="navbar-brand logo" href="/"> <a class="navbar-brand logo" href="/">
...@@ -22,20 +22,29 @@ ...@@ -22,20 +22,29 @@
<ul class="nav navbar-nav navbar-right"> <ul class="nav navbar-nav navbar-right">
<li> <li>
<a href="{{pageSetting.wikiAddress}}" target="_blank"> <a href="{{pageSetting.wikiAddress}}" target="_blank">
<span class="glyphicon glyphicon-question-sign"></span> 帮助 <span class="glyphicon glyphicon-question-sign"></span> {{'Common.Nav.Help' | translate }}
</a> </a>
</li> </li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
<span class="glyphicon .glyphicon-glyphicon-font"></span>&nbsp;Language<span class="caret"></span></a>
<ul class="dropdown-menu">
<li value="en"><a href="javascript:void(0)" ng-click="changeLanguage('en')">English</a></li>
<li value="zh-CN"><a href="javascript:void(0)" ng-click="changeLanguage('zh-CN')">简体中文</a></li>
</ul>
</li>
<li class="dropdown" ng-if="hasRootPermission"> <li class="dropdown" ng-if="hasRootPermission">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
<span class="glyphicon glyphicon-cog"></span>&nbsp;管理员工具 <span class="glyphicon glyphicon-cog"></span>&nbsp;{{'Common.Nav.AdminTools' | translate }}
<span class="caret"></span></a> <span class="caret"></span></a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><a href="/user-manage.html" target="_blank">用户管理</a></li> <li><a href="/user-manage.html" target="_blank">{{'Common.Nav.UserManage' | translate }}</a></li>
<li><a href="/system-role-manage.html" target="_blank">系统权限管理</a></li> <li><a href="/system-role-manage.html" target="_blank">{{'Common.Nav.SystemRoleManage' | translate }}</a></li>
<li><a href="/open/manage.html" target="_blank">开放平台授权管理</a></li> <li><a href="/open/manage.html" target="_blank">{{'Common.Nav.OpenMange' | translate }}</a></li>
<li><a href="/server_config.html" target="_blank">系统参数</a></li> <li><a href="/server_config.html" target="_blank">{{'Common.Nav.SystemConfig' | translate }}</a></li>
<li><a href="/delete_app_cluster_namespace.html" target="_blank">删除应用、集群、AppNamespace</a></li> <li><a href="/delete_app_cluster_namespace.html" target="_blank">{{'Common.Nav.DeleteApp-Cluster-Namespace' | translate }}</a></li>
<li><a href="/system_info.html" target="_blank">系统信息</a></li> <li><a href="/system_info.html" target="_blank">{{'Common.Nav.SystemInfo' | translate }}</a></li>
</ul> </ul>
</li> </li>
<li class="dropdown"> <li class="dropdown">
...@@ -43,7 +52,7 @@ ...@@ -43,7 +52,7 @@
<span class="glyphicon glyphicon-user"></span>&nbsp;{{userName}} <span class="glyphicon glyphicon-user"></span>&nbsp;{{userName}}
<span class="caret"></span></a> <span class="caret"></span></a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><a href="/user/logout">退出</a></li> <li><a href="/user/logout">{{'Common.Nav.Logout' | translate }}</a></li>
</ul> </ul>
</li> </li>
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal" <button type="button" class="btn btn-default" data-dismiss="modal"
ng-show="showCancelBtn" ng-click="cancel()">取消</button> ng-show="showCancelBtn" ng-click="cancel()">{{'Common.Cancel' | translate }}</button>
<button type="button" class="btn btn-danger" data-dismiss="modal" <button type="button" class="btn btn-danger" data-dismiss="modal"
ng-click="confirm()"> ng-click="confirm()">
{{confirmBtnText}} {{confirmBtnText}}
......
...@@ -5,22 +5,22 @@ ...@@ -5,22 +5,22 @@
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
aria-hidden="true">&times;</span></button> aria-hidden="true">&times;</span></button>
<h4 class="modal-title"> <h4 class="modal-title">
删除Namespace {{'Component.DeleteNamespace.Title' | translate }}
</h4> </h4>
</div> </div>
<div class="modal-body form-horizontal" ng-show="toDeleteNamespace.isPublic"> <div class="modal-body form-horizontal" ng-show="toDeleteNamespace.isPublic">
删除Namespace将导致实例获取不到此Namespace的配置,确定要删除吗? {{'Component.DeleteNamespace.PublicContent' | translate }}
</div> </div>
<div class="modal-body form-horizontal" ng-show="!toDeleteNamespace.isPublic"> <div class="modal-body form-horizontal" ng-show="!toDeleteNamespace.isPublic">
删除私有Namespace将导致实例获取不到此Namespace的配置,且页面会提示缺失Namespace(除非使用管理员工具删除AppNamespace),确定要删除吗? {{'Component.DeleteNamespace.PrivateContent' | translate }}
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal"> <button type="button" class="btn btn-default" data-dismiss="modal">
取消 {{'Common.Cancel' | translate }}
</button> </button>
<button type="button" class="btn btn-danger" data-dismiss="modal" <button type="button" class="btn btn-danger" data-dismiss="modal"
ng-click="doDeleteNamespace()"> ng-click="doDeleteNamespace()">
确认 {{'Common.Ok' | translate }}
</button> </button>
</div> </div>
</div> </div>
......
<table class="table table-hover" style="width: 250px"> <table class="table table-hover" style="width: 300px">
<thead> <thead>
<tr> <tr>
<td><input type="checkbox" ng-checked="envAllSelected" ng-click="toggleEnvsCheckedStatus()"></td> <td><input type="checkbox" ng-checked="envAllSelected" ng-click="toggleEnvsCheckedStatus()"></td>
</td> </td>
<td>环境</td> <td>{{'Common.Environment' | translate }}</td>
<td>集群</td> <td>{{'Common.Cluster' | translate }}</td>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
......
...@@ -6,69 +6,69 @@ ...@@ -6,69 +6,69 @@
aria-hidden="true">&times;</span> aria-hidden="true">&times;</span>
</button> </button>
<h4 class="modal-title"> <h4 class="modal-title">
编辑灰度规则 {{'Component.GrayscalePublishRule.Title' | translate }}
</h4> </h4>
</div> </div>
<div class="modal-body form-horizontal"> <div class="modal-body form-horizontal">
<div class="form-group" <div class="form-group"
ng-show="branch.parentNamespace.isPublic && !branch.parentNamespace.isLinkedNamespace"> ng-show="branch.parentNamespace.isPublic && !branch.parentNamespace.isLinkedNamespace">
<label class="control-label col-md-3 text-right"> <label class="control-label col-md-3 text-right">
<apollorequiredfield></apollorequiredfield> <apollorequiredfield></apollorequiredfield>
灰度的AppId</label> {{'Component.GrayscalePublishRule.AppId' | translate }}
</label>
<div class="col-md-4"> <div class="col-md-4">
<input type="text" class="form-control" <input type="text" class="form-control" ng-model="branch.editingRuleItem.clientAppId"
ng-model="branch.editingRuleItem.clientAppId" ng-model-options='{ debounce: 300 }' ng-change='initSelectIps()'>
ng-model-options='{ debounce: 300 }'
ng-change='initSelectIps()'
>
</div> </div>
</div> </div>
<div class="form-group" <div class="form-group"
ng-show="branch.parentNamespace.isPublic && !branch.parentNamespace.isLinkedNamespace"> ng-show="branch.parentNamespace.isPublic && !branch.parentNamespace.isLinkedNamespace">
<label class="control-label col-md-3 text-right">灰度应用规则</label> <label
class="control-label col-md-3 text-right">{{'Component.GrayscalePublishRule.AcceptRule' | translate }}</label>
<div class="col-md-9"> <div class="col-md-9">
<label class="form-control-static radio-inline"> <label class="form-control-static radio-inline">
<input type="radio" name="ApplyToAllInstances" value="false" <input type="radio" name="ApplyToAllInstances" value="false"
ng-checked="!branch.editingRuleItem.ApplyToAllInstances" ng-checked="!branch.editingRuleItem.ApplyToAllInstances"
ng-click="branch.editingRuleItem.ApplyToAllInstances = false"> ng-click="branch.editingRuleItem.ApplyToAllInstances = false">
应用到部分实例 {{'Component.GrayscalePublishRule.AcceptPartInstance' | translate }}
</label> </label>
<label class="form-control-static radio-inline"> <label class="form-control-static radio-inline">
<input type="radio" name="ApplyToAllInstances" value="true" <input type="radio" name="ApplyToAllInstances" value="true"
ng-checked="branch.editingRuleItem.ApplyToAllInstances" ng-checked="branch.editingRuleItem.ApplyToAllInstances"
ng-click="branch.editingRuleItem.ApplyToAllInstances = true"> ng-click="branch.editingRuleItem.ApplyToAllInstances = true">
应用到所有的实例 {{'Component.GrayscalePublishRule.AcceptAllInstance' | translate }}
</label> </label>
</div> </div>
</div> </div>
<div class="form-group" ng-show="!branch.editingRuleItem.ApplyToAllInstances"> <div class="form-group" ng-show="!branch.editingRuleItem.ApplyToAllInstances">
<label class="control-label col-md-3 text-right"> <label class="control-label col-md-3 text-right">
<apollorequiredfield></apollorequiredfield> <apollorequiredfield></apollorequiredfield>
灰度的IP</label> {{'Component.GrayscalePublishRule.IP' | translate }}
</label>
<div class="col-md-9"> <div class="col-md-9">
<div class="form-inline"> <div class="form-inline">
<div class="form-group"> <div class="form-group">
<select class="rules-ip-selector" multiple="multiple"> <select class="rules-ip-selector" multiple="multiple">
<option ng-repeat="instance in selectIps" <option ng-repeat="instance in selectIps" ng-bind="instance.ip">
ng-bind="instance.ip">
</option> </option>
</select> </select>
<div ng-show="branch.parentNamespace.isPublic && !branch.parentNamespace.isLinkedNamespace"> <div
<small>(实例列表会根据输入的AppId自动过滤)</small> ng-show="branch.parentNamespace.isPublic && !branch.parentNamespace.isLinkedNamespace">
<small>{{'Component.GrayscalePublishRule.AppIdFilterTips' | translate }}</small>
</div> </div>
<div style="margin-top: 5px"> <div style="margin-top: 5px">
<small>没找到你想要的IP?可以<a ng-click="manual =! manual">手动输入IP</a></small> <small>{{'Component.GrayscalePublishRule.IpTips' | translate }}<a
ng-click="manual =! manual">{{'Component.GrayscalePublishRule.EnterIp' | translate }}</a></small>
</div> </div>
</div> </div>
</div> </div>
<div class="form-inline" ng-show="manual"> <div class="form-inline" ng-show="manual">
<div class="form-group"> <div class="form-group">
<textarea class="form-control" ng-model="toAddIPs" rows="3" <textarea class="form-control" ng-model="toAddIPs" rows="3"
placeholder="输入IP列表,英文逗号隔开,输入完后点击添加按钮"></textarea> placeholder="{{'Component.GrayscalePublishRule.EnterIpTips' | translate }}"></textarea>
</div> </div>
<button class="btn-default btn add-rule" <button class="btn-default btn add-rule" ng-click="batchAddIPs(branch, toAddIPs)">
ng-click="batchAddIPs(branch, toAddIPs)"> {{'Component.GrayscalePublishRule.Add' | translate }}
添加
</button> </button>
</div> </div>
</div> </div>
...@@ -77,12 +77,10 @@ ...@@ -77,12 +77,10 @@
<div class="form-group" ng-show="!branch.editingRuleItem.ApplyToAllInstances"> <div class="form-group" ng-show="!branch.editingRuleItem.ApplyToAllInstances">
<div class="col-md-offset-1 col-md-10 item-container"> <div class="col-md-offset-1 col-md-10 item-container">
<section class="btn-group item-info" <section class="btn-group item-info" ng-repeat="ip in branch.editingRuleItem.draftIpList">
ng-repeat="ip in branch.editingRuleItem.draftIpList">
<button type="button" class="btn btn-default" ng-bind="ip"></button> <button type="button" class="btn btn-default" ng-bind="ip"></button>
<button type="button" class="btn btn-default dropdown-toggle" <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"
data-toggle="dropdown" ng-click="removeRule(branch.editingRuleItem, ip)">
ng-click="removeRule(branch.editingRuleItem, ip)">
<span class="glyphicon glyphicon-remove"></span> <span class="glyphicon glyphicon-remove"></span>
</button> </button>
</section> </section>
...@@ -91,13 +89,14 @@ ...@@ -91,13 +89,14 @@
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button class="btn btn-default" ng-click="cancelEditItem(branch)">取消</button> <button class="btn btn-default"
ng-click="cancelEditItem(branch)">{{'Common.Cancel' | translate }}</button>
<button class="btn btn-primary" ng-disabled="completeEditBtnDisable" <button class="btn btn-primary" ng-disabled="completeEditBtnDisable"
ng-click="completeEditItem(branch)">完成 ng-click="completeEditItem(branch)">{{'Common.Ok' | translate }}
</button> </button>
</div> </div>
</div> </div>
</div> </div>
</form> </form>
\ No newline at end of file
<form id="itemModal" class="modal fade" valdr-type="Item" name="itemForm" <form id="itemModal" class="modal fade" valdr-type="Item" name="itemForm" ng-submit="doItem()">
ng-submit="doItem()">
<div class="modal-dialog" role="document"> <div class="modal-dialog" role="document">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header panel-primary"> <div class="modal-header panel-primary">
...@@ -7,58 +6,59 @@ ...@@ -7,58 +6,59 @@
aria-hidden="true">&times;</span></button> aria-hidden="true">&times;</span></button>
<h4 class="modal-title"> <h4 class="modal-title">
<span ng-show="item.tableViewOperType == 'create' && !toOperationNamespace.isBranch"> <span ng-show="item.tableViewOperType == 'create' && !toOperationNamespace.isBranch">
添加配置项 <small class="text-info">(温馨提示: 可以通过文本模式批量添加配置)</small> {{'Component.ConfigItem.Title' | translate }} <small
class="text-info">{{'Component.ConfigItem.TitleTips' | translate }}</small>
</span> </span>
<span ng-show="item.tableViewOperType == 'create' && toOperationNamespace.isBranch"> 添加灰度配置项</span> <span ng-show="item.tableViewOperType == 'create' && toOperationNamespace.isBranch">
<span ng-show="item.tableViewOperType == 'update'"> 修改配置项</span> {{'Component.ConfigItem.AddGrayscaleItem' | translate }}</span>
<span ng-show="item.tableViewOperType == 'update'">
{{'Component.ConfigItem.ModifyItem' | translate }}</span>
</h4> </h4>
</div> </div>
<div class="modal-body form-horizontal"> <div class="modal-body form-horizontal">
<div class="form-group"> <div class="form-group">
<label class="col-sm-2 control-label"> <label class="col-sm-2 control-label">
<apollorequiredfield <apollorequiredfield ng-show="item.tableViewOperType == 'create'"></apollorequiredfield>
ng-show="item.tableViewOperType == 'create'"></apollorequiredfield> {{'Component.ConfigItem.ItemKey' | translate }}
Key
</label> </label>
<div class="col-sm-10" valdr-form-group> <div class="col-sm-10" valdr-form-group>
<input type="text" name="key" class="form-control" ng-model="item.key" tabindex="1" <input type="text" name="key" class="form-control" ng-model="item.key" tabindex="1"
ng-required="true" ng-disabled="item.tableViewOperType != 'create'"/> ng-required="true" ng-disabled="item.tableViewOperType != 'create'" />
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="col-sm-2 control-label">Value</label> <label class="col-sm-2 control-label">{{'Component.ConfigItem.ItemValue' | translate }}</label>
<div class="col-sm-10" valdr-form-group> <div class="col-sm-10" valdr-form-group>
<textarea id="valueEditor" name="value" class="form-control" rows="6" tabindex="2" <textarea id="valueEditor" name="value" class="form-control" rows="6" tabindex="2"
ng-required="false" ng-required="false" ng-model="item.value">
ng-model="item.value">
</textarea> </textarea>
注意: 隐藏字符(空格、换行符、制表符Tab)容易导致配置出错,如果需要检测Value中隐藏字符请点击 <a ng-click="showHiddenChars()">检测隐藏字符</a> {{'Component.ConfigItem.ItemValueTips' | translate }} <a
ng-click="showHiddenChars()">{{'Component.ConfigItem.ItemValueShowDetection' | translate }}</a>
<br> <br>
<div class="bg-info" ng-show="showHiddenCharsContext && hiddenCharCounter == 0">无隐藏字符</div> <div class="bg-info" ng-show="showHiddenCharsContext && hiddenCharCounter == 0">
<div class="bg-info" ng-bind-html="valueWithHiddenChars" ng-show="showHiddenCharsContext && hiddenCharCounter > 0"></div> {{'Component.ConfigItem.ItemValueNotHiddenChars' | translate }}</div>
<div class="bg-info" ng-bind-html="valueWithHiddenChars"
ng-show="showHiddenCharsContext && hiddenCharCounter > 0"></div>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="col-sm-2 control-label">Comment</label> <label class="col-sm-2 control-label">{{'Component.ConfigItem.ItemComment' | translate }}</label>
<div class="col-sm-10" valdr-form-group> <div class="col-sm-10" valdr-form-group>
<textarea class="form-control" name="comment" ng-model="item.comment" tabindex="3" <textarea class="form-control" name="comment" ng-model="item.comment" tabindex="3" rows="2">
rows="2">
</textarea> </textarea>
</div> </div>
</div> </div>
<div class="form-group" <div class="form-group" ng-show="item.tableViewOperType == 'create' && !toOperationNamespace.isBranch">
ng-show="item.tableViewOperType == 'create' && !toOperationNamespace.isBranch">
<label class="col-sm-2 control-label"> <label class="col-sm-2 control-label">
<apollorequiredfield></apollorequiredfield> <apollorequiredfield></apollorequiredfield>
选择集群</label> {{'Component.ConfigItem.ChooseCluster' | translate }}
</label>
<div class="col-sm-10"> <div class="col-sm-10">
<apolloclusterselector apollo-app-id="appId" <apolloclusterselector apollo-app-id="appId" apollo-default-all-checked="false"
apollo-default-all-checked="false" apollo-default-checked-env="env" apollo-default-checked-cluster="cluster"
apollo-default-checked-env="env" apollo-select="collectSelectedClusters">
apollo-default-checked-cluster="cluster"
apollo-select="collectSelectedClusters">
</apolloclusterselector> </apolloclusterselector>
</div> </div>
...@@ -66,13 +66,13 @@ ...@@ -66,13 +66,13 @@
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal"> <button type="button" class="btn btn-default" data-dismiss="modal">
取消 {{'Common.Cancel' | translate }}
</button> </button>
<button type="submit" class="btn btn-primary" <button type="submit" class="btn btn-primary"
ng-disabled="itemForm.$invalid || (item.addItemBtnDisabled && item.tableViewOperType == 'create')"> ng-disabled="itemForm.$invalid || (item.addItemBtnDisabled && item.tableViewOperType == 'create')">
提交 {{'Common.Submit' | translate }}
</button> </button>
</div> </div>
</div> </div>
</div> </div>
</form> </form>
\ No newline at end of file
...@@ -4,35 +4,34 @@ ...@@ -4,35 +4,34 @@
<div class="modal-header panel-primary"> <div class="modal-header panel-primary">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
aria-hidden="true">&times;</span></button> aria-hidden="true">&times;</span></button>
<h4 class="modal-title">全量发布</h4> <h4 class="modal-title">{{'Component.MergePublish.Title' | translate }}</h4>
</div> </div>
<div class="modal-body"> <div class="modal-body">
全量发布将会把灰度版本的配置合并到主分支,并发布。 {{'Component.MergePublish.Tips' | translate }}
<br> <br>
<h5>全量发布后,您希望</h5> <h5>{{'Component.MergePublish.NextStep' | translate }}</h5>
<div class="radio"> <div class="radio">
<label ng-click="toReleaseNamespace.mergeAfterDeleteBranch = 'true'"> <label ng-click="toReleaseNamespace.mergeAfterDeleteBranch = 'true'">
<input type="radio" name="deleteBranch" <input type="radio" name="deleteBranch" ng-checked="!toReleaseNamespace.mergeAfterDeleteBranch ||
ng-checked="!toReleaseNamespace.mergeAfterDeleteBranch ||
toReleaseNamespace.mergeAfterDeleteBranch == 'true'"> toReleaseNamespace.mergeAfterDeleteBranch == 'true'">
删除灰度版本 {{'Component.MergePublish.DeleteGrayscale' | translate }}
</label> </label>
</div> </div>
<div class="radio"> <div class="radio">
<label ng-click="toReleaseNamespace.mergeAfterDeleteBranch = 'false'"> <label ng-click="toReleaseNamespace.mergeAfterDeleteBranch = 'false'">
<input type="radio" name="deleteBranch" <input type="radio" name="deleteBranch"
ng-checked="toReleaseNamespace.mergeAfterDeleteBranch == 'false'"> ng-checked="toReleaseNamespace.mergeAfterDeleteBranch == 'false'">
保留灰度版本 {{'Component.MergePublish.ReservedGrayscale' | translate }}
</label> </label>
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button> <button type="button" class="btn btn-default"
<button type="button" class="btn btn-primary" data-dismiss="modal" data-dismiss="modal">{{'Common.Cancel' | translate }}</button>
ng-click="showReleaseModal()"> <button type="button" class="btn btn-primary" data-dismiss="modal" ng-click="showReleaseModal()">
确定 {{'Common.Ok' | translate }}
</button> </button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
\ No newline at end of file
<section class="branch-panel-body" <section class="branch-panel-body" ng-if="namespace.initialized &&
ng-if="namespace.initialized &&
(namespace.hasBranch && namespace.displayControl.currentOperateBranch != 'master')"> (namespace.hasBranch && namespace.displayControl.currentOperateBranch != 'master')">
<!--main header--> <!--main header-->
<header class="panel-heading"> <header class="panel-heading">
...@@ -8,45 +7,44 @@ ...@@ -8,45 +7,44 @@
<div class="col-md-6 col-sm-6 header-namespace"> <div class="col-md-6 col-sm-6 header-namespace">
<b class="namespace-name" ng-bind="namespace.viewName"></b> <b class="namespace-name" ng-bind="namespace.viewName"></b>
<span class="label label-warning no-radius namespace-label" <span class="label label-warning no-radius namespace-label"
ng-show="namespace.branch.itemModifiedCnt > 0">有修改 ng-show="namespace.branch.itemModifiedCnt > 0">{{'Component.Namespace.Branch.IsChanged' | translate }}
<span class="badge label badge-white namespace-label" <span class="badge label badge-white namespace-label"
ng-bind="namespace.branch.itemModifiedCnt"></span> ng-bind="namespace.branch.itemModifiedCnt"></span>
</span> </span>
<span class="label label-primary no-radius namespace-label" <span class="label label-primary no-radius namespace-label"
ng-show="namespace.branch.lockOwner">当前修改者: ng-show="namespace.branch.lockOwner">{{'Component.Namespace.Branch.ChangeUser' | translate }}:
<span ng-bind="namespace.branch.lockOwner"></span> <span ng-bind="namespace.branch.lockOwner"></span>
</span> </span>
</div> </div>
<div class="col-md-6 col-sm-6 text-right header-buttons"> <div class="col-md-6 col-sm-6 text-right header-buttons">
<a type="button" class="btn btn-success btn-sm" <a type="button" class="btn btn-success btn-sm" data-tooltip="tooltip" data-placement="bottom"
data-tooltip="tooltip" data-placement="bottom" title="继续灰度发布" title="{{'Component.Namespace.Branch.ContinueGrayscalePublish' | translate }}"
ng-show="(namespace.hasReleasePermission || namespace.hasModifyPermission)" ng-show="(namespace.hasReleasePermission || namespace.hasModifyPermission)"
ng-click="publish(namespace.branch)"> ng-click="publish(namespace.branch)">
灰度发布 {{'Component.Namespace.Branch.GrayscalePublish' | translate }}
</a> </a>
<a type="button" class="btn btn-primary btn-sm" <a type="button" class="btn btn-primary btn-sm" data-tooltip="tooltip" data-placement="bottom"
data-tooltip="tooltip" data-placement="bottom" title="合并到主版本并发布主版本配置" title="{{'Component.Namespace.Branch.MergeToMasterAndPublish' | translate }}"
ng-show="(namespace.hasReleasePermission || namespace.hasModifyPermission)" ng-show="(namespace.hasReleasePermission || namespace.hasModifyPermission)"
ng-click="mergeAndPublish(namespace.branch)"> ng-click="mergeAndPublish(namespace.branch)">
全量发布 {{'Component.Namespace.Branch.AllPublish' | translate }}
</a> </a>
<a type="button" class="btn btn-warning btn-sm" <a type="button" class="btn btn-warning btn-sm" data-tooltip="tooltip" data-placement="bottom"
data-tooltip="tooltip" data-placement="bottom" title="废弃灰度版本" title="{{'Component.Namespace.Branch.DiscardGrayscaleVesion' | translate }}" ng-show="(namespace.hasReleasePermission
ng-show="(namespace.hasReleasePermission
|| (!namespace.branch.latestRelease && namespace.hasModifyPermission))" || (!namespace.branch.latestRelease && namespace.hasModifyPermission))"
ng-click="preDeleteBranch(namespace.branch)"> ng-click="preDeleteBranch(namespace.branch)">
放弃灰度 {{'Component.Namespace.Branch.DiscardGrayscale' | translate }}
</a> </a>
</div> </div>
</div> </div>
</header> </header>
<div id="BODY{{namespace.branch.id}}" ng-class="{'collapse in': showNamespaceBody, 'collapse' : !showNamespaceBody}"> <div id="BODY{{namespace.branch.id}}"
<div class="J_namespace-release-tip well well-sm no-radius text-center" ng-class="{'collapse in': showNamespaceBody, 'collapse' : !showNamespaceBody}">
ng-show="namespace.isConfigHidden"> <div class="J_namespace-release-tip well well-sm no-radius text-center" ng-show="namespace.isConfigHidden">
<span style="color: red">您不是该项目的管理员,也没有该Namespace的编辑或发布权限,无法查看配置信息。</span> <span style="color: red">{{'Component.Namespace.Branch.NoPermissionTips' | translate }}</span>
</div> </div>
<!--second header--> <!--second header-->
...@@ -58,29 +56,29 @@ ...@@ -58,29 +56,29 @@
ng-show="namespace.isPropertiesFormat"> ng-show="namespace.isPropertiesFormat">
<a ng-class="{node_active:namespace.branch.viewType == 'table'}"> <a ng-class="{node_active:namespace.branch.viewType == 'table'}">
<img src="img/table.png"> <img src="img/table.png">
配置 {{'Component.Namespace.Branch.Tab.Configuration' | translate }}
</a> </a>
</li> </li>
<li role="presentation" ng-click="switchView(namespace.branch, 'rule')"> <li role="presentation" ng-click="switchView(namespace.branch, 'rule')">
<a ng-class="{node_active:namespace.branch.viewType == 'rule'}"> <a ng-class="{node_active:namespace.branch.viewType == 'rule'}">
<img src="img/rule.png"> <img src="img/rule.png">
灰度规则 {{'Component.Namespace.Branch.Tab.GrayscaleRule' | translate }}
<span class="badge badge-grey" <span class="badge badge-grey"
ng-bind="namespace.branch.grayIps.length + namespace.branch.grayApps.length"></span> ng-bind="namespace.branch.grayIps.length + namespace.branch.grayApps.length"></span>
</a> </a>
</li> </li>
<li role="presentation" ng-click="switchView(namespace.branch, 'instance')"> <li role="presentation" ng-click="switchView(namespace.branch, 'instance')">
<a ng-class="{node_active:namespace.branch.viewType == 'instance'}"> <a ng-class="{node_active:namespace.branch.viewType == 'instance'}">
<img src="img/machine.png"> <img src="img/machine.png">
灰度实例列表 {{'Component.Namespace.Branch.Tab.GrayscaleInstance' | translate }}
<span class="badge badge-grey" <span class="badge badge-grey"
ng-bind="namespace.branch.latestReleaseInstances.total"></span> ng-bind="namespace.branch.latestReleaseInstances.total"></span>
</a> </a>
</li> </li>
<li role="presentation" ng-click="switchView(namespace.branch, 'history')"> <li role="presentation" ng-click="switchView(namespace.branch, 'history')">
<a ng-class="{node_active:namespace.branch.viewType == 'history'}"> <a ng-class="{node_active:namespace.branch.viewType == 'history'}">
<img src="img/change.png"> <img src="img/change.png">
更改历史 {{'Component.Namespace.Branch.Tab.ChangeHistory' | translate }}
</a> </a>
</li> </li>
</ul> </ul>
...@@ -94,194 +92,211 @@ ...@@ -94,194 +92,211 @@
<div class="panel panel-default" ng-if="namespace.hasBranch"> <div class="panel panel-default" ng-if="namespace.hasBranch">
<div class="panel-heading"> <div class="panel-heading">
灰度的配置 {{'Component.Namespace.Branch.Body.Item' | translate }}
<button type="button" class="btn btn-primary btn-sm pull-right" style="margin-top: -4px;" <button type="button" class="btn btn-primary btn-sm pull-right" style="margin-top: -4px;"
ng-show="namespace.hasModifyPermission" ng-show="namespace.hasModifyPermission" ng-click="createItem(namespace.branch)">
ng-click="createItem(namespace.branch)">
<img src="img/plus.png"> <img src="img/plus.png">
新增灰度配置 {{'Component.Namespace.Branch.Body.AddedItem' | translate }}
</button> </button>
</div> </div>
<table class="table table-bordered table-striped table-hover"> <table class="table table-bordered table-striped table-hover">
<thead> <thead>
<tr> <tr>
<th>发布状态</th> <th>{{'Component.Namespace.Branch.Body.PublishState' | translate }}</th>
<th class="hover" title="排序" <th class="hover" title="{{'Component.Namespace.Branch.Body.ItemSort' | translate }}"
ng-click="col='item.key';desc=!desc;"> ng-click="col='item.key';desc=!desc;">
Key&nbsp; {{'Component.Namespace.Branch.Body.ItemKey' | translate }}&nbsp;
<span class="glyphicon glyphicon-sort"></span> <span class="glyphicon glyphicon-sort"></span>
</th> </th>
<th> <th>
主版本的值 {{'Component.Namespace.Branch.Body.ItemMasterValue' | translate }}
</th> </th>
<th> <th>
灰度的值 {{'Component.Namespace.Branch.Body.ItemGrayscaleValue' | translate }}
</th> </th>
<th> <th>
备注 {{'Component.Namespace.Branch.Body.ItemComment' | translate }}
</th> </th>
<th class="hover" title="排序" <th class="hover" title="{{'Component.Namespace.Branch.Body.ItemSort' | translate }}"
ng-click="col='item.dataChangeLastModifiedBy';desc=!desc;"> ng-click="col='item.dataChangeLastModifiedBy';desc=!desc;">
最后修改人 {{'Component.Namespace.Branch.Body.ItemLastModify' | translate }}
<span class="glyphicon glyphicon-sort"></span> <span class="glyphicon glyphicon-sort"></span>
</th> </th>
<th class="hover" title="排序" <th class="hover" title="{{'Component.Namespace.Branch.Body.ItemSort' | translate }}"
ng-click="col='item.dataChangeLastModifiedTime';desc=!desc;"> ng-click="col='item.dataChangeLastModifiedTime';desc=!desc;">
最后修改时间 {{'Component.Namespace.Branch.Body.ItemLastModifyTime' | translate }}
<span class="glyphicon glyphicon-sort"></span> <span class="glyphicon glyphicon-sort"></span>
</th> </th>
<th> <th>
操作 {{'Component.Namespace.Branch.Body.ItemOperator' | translate }}
</th> </th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr ng-repeat="config in namespace.branch.branchItems |orderBy:col:desc" <tr ng-repeat="config in namespace.branch.branchItems |orderBy:col:desc"
ng-if="config.item.key"> ng-if="config.item.key">
<td width="7%" class="text-center"> <td width="7%" class="text-center">
<span class="label label-warning no-radius cursor-pointer" <span class="label label-warning no-radius cursor-pointer" data-tooltip="tooltip"
data-tooltip="tooltip" data-placement="bottom" title="点击查看已发布的值" data-placement="bottom"
ng-if="config.isModified || config.isDeleted" title="{{'Component.Namespace.Branch.Body.ClickToSeeItemValue' | translate }}"
ng-click="showText(config.oldValue)">未发布</span> ng-if="config.isModified || config.isDeleted"
<span class="label label-default-light no-radius" ng-click="showText(config.oldValue)">{{'Component.Namespace.Branch.Body.ItemNoPublish' | translate }}</span>
data-tooltip="tooltip" data-placement="bottom" title="已生效的配置" <span class="label label-default-light no-radius" data-tooltip="tooltip"
ng-if="!config.isModified">已发布</span> data-placement="bottom"
</td> title="{{'Component.Namespace.Branch.Body.ItemEffective' | translate }}"
<td width="15%" class="cursor-pointer" title="点击查看" ng-click="showText(config.item.key)"> ng-if="!config.isModified">{{'Component.Namespace.Branch.Body.ItemPublished' | translate }}</span>
<span ng-bind="config.item.key | limitTo: 250"></span> </td>
<span ng-bind="config.item.key.length > 250 ? '...' :''"></span> <td width="15%" class="cursor-pointer"
<span class="label label-danger" ng-if="config.isDeleted" title="{{'Component.Namespace.Branch.Body.ClickToSee' | translate }}"
data-tooltip="tooltip" data-placement="bottom" title="删除的配置"></span> ng-click="showText(config.item.key)">
<span class="label label-info" ng-if="!config.isDeleted && config.masterItemExists" <span ng-bind="config.item.key | limitTo: 250"></span>
data-tooltip="tooltip" data-placement="bottom" title="修改主版本的配置"></span> <span ng-bind="config.item.key.length > 250 ? '...' :''"></span>
<span class="label label-success" <span class="label label-danger" ng-if="config.isDeleted" data-tooltip="tooltip"
ng-if="!config.isDeleted && !config.masterItemExists" data-placement="bottom"
data-tooltip="tooltip" data-placement="bottom" title="灰度版本特有的配置"></span> title="{{'Component.Namespace.Branch.Body.DeletedItem' | translate }}">{{'Component.Namespace.Branch.Body.Delete' | translate }}</span>
</td> <span class="label label-info" ng-if="!config.isDeleted && config.masterItemExists"
<td width="20%" class="cursor-pointer" title="点击查看" data-tooltip="tooltip" data-placement="bottom"
ng-click="showText(config.masterReleaseValue)"> title="{{'Component.Namespace.Branch.Body.ChangedFromMaster' | translate }}">{{'Component.Namespace.Branch.Body.Modify' | translate }}</span>
<span ng-bind="config.masterReleaseValue | limitTo: 250"></span> <span class="label label-success"
<span ng-bind="config.item.value.length > 250 ? '...': ''"></span> ng-if="!config.isDeleted && !config.masterItemExists" data-tooltip="tooltip"
</td> data-placement="bottom"
<td width="20%" class="cursor-pointer" title="点击查看" ng-click="showText(config.item.value)"> title="{{'Component.Namespace.Branch.Body.AddedByGrayscale' | translate }}">{{'Component.Namespace.Branch.Body.Added' | translate }}</span>
<span ng-bind="config.item.value | limitTo: 250"></span> </td>
<span ng-bind="config.item.value.length > 250 ? '...': ''"></span> <td width="20%" class="cursor-pointer"
</td> title="{{'Component.Namespace.Branch.Body.ClickToSee' | translate }}"
<td width="10%" title="{{config.item.comment}}"> ng-click="showText(config.masterReleaseValue)">
<span ng-bind="config.item.comment | limitTo: 250"></span> <span ng-bind="config.masterReleaseValue | limitTo: 250"></span>
<span ng-bind="config.item.comment.length > 250 ?'...' : ''"></span> <span ng-bind="config.item.value.length > 250 ? '...': ''"></span>
</td> </td>
<td width="10%" ng-bind="config.item.dataChangeLastModifiedBy"> <td width="20%" class="cursor-pointer"
</td> title="{{'Component.Namespace.Branch.Body.ClickToSee' | translate }}"
<td width="10%" ng-click="showText(config.item.value)">
ng-bind="config.item.dataChangeLastModifiedTime | date: 'yyyy-MM-dd HH:mm:ss'"> <span ng-bind="config.item.value | limitTo: 250"></span>
</td> <span ng-bind="config.item.value.length > 250 ? '...': ''"></span>
</td>
<td width="10%" title="{{config.item.comment}}">
<span ng-bind="config.item.comment | limitTo: 250"></span>
<span ng-bind="config.item.comment.length > 250 ?'...' : ''"></span>
</td>
<td width="10%" ng-bind="config.item.dataChangeLastModifiedBy">
</td>
<td width="10%"
ng-bind="config.item.dataChangeLastModifiedTime | date: 'yyyy-MM-dd HH:mm:ss'">
</td>
<td width="9%" class="text-center"> <td width="9%" class="text-center">
<img src="img/edit.png" <img src="img/edit.png" data-tooltip="tooltip" data-placement="bottom"
data-tooltip="tooltip" data-placement="bottom" title="修改" title="{{'Component.Namespace.Branch.Body.Op.Modify' | translate }}"
ng-if="!config.isDeleted" ng-if="!config.isDeleted" ng-click="editItem(namespace.branch, config.item)"
ng-click="editItem(namespace.branch, config.item)" ng-show="namespace.hasModifyPermission">
ng-show="namespace.hasModifyPermission"> <img style="margin-left: 5px;" src="img/cancel.png" data-tooltip="tooltip"
<img style="margin-left: 5px;" src="img/cancel.png" data-placement="bottom"
data-tooltip="tooltip" data-placement="bottom" title="删除" title="{{'Component.Namespace.Branch.Body.Op.Delete' | translate }}"
ng-if="!config.isDeleted" ng-if="!config.isDeleted"
ng-click="preDeleteItem(namespace.branch, config.item)" ng-click="preDeleteItem(namespace.branch, config.item)"
ng-show="namespace.hasModifyPermission"> ng-show="namespace.hasModifyPermission">
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>
<div class="panel panel-default" <div class="panel panel-default"
ng-if="namespace.branch.masterItems && namespace.branch.masterItems.length > 0"> ng-if="namespace.branch.masterItems && namespace.branch.masterItems.length > 0">
<div class="panel-heading"> <div class="panel-heading">
主版本的配置 {{'Component.Namespace.MasterBranch.Body.Title' | translate }}
</div> </div>
<table class="table table-bordered table-striped table-hover"> <table class="table table-bordered table-striped table-hover">
<thead> <thead>
<tr> <tr>
<th>发布状态</th> <th>{{'Component.Namespace.MasterBranch.Body.PublishState' | translate }}</th>
<th class="hover" title="排序" <th class="hover" title="{{'Component.Namespace.Branch.Body.ItemSort' | translate }}"
ng-click="col='item.key';desc=!desc;"> ng-click="col='item.key';desc=!desc;">
Key&nbsp; {{'Component.Namespace.MasterBranch.Body.ItemKey' | translate }}&nbsp;
<span class="glyphicon glyphicon-sort"></span> <span class="glyphicon glyphicon-sort"></span>
</th> </th>
<th> <th>
Value {{'Component.Namespace.MasterBranch.Body.ItemValue' | translate }}
</th> </th>
<th> <th>
备注 {{'Component.Namespace.MasterBranch.Body.ItemComment' | translate }}
</th> </th>
<th class="hover" title="排序" <th class="hover" title="{{'Component.Namespace.Branch.Body.ItemSort' | translate }}"
ng-click="col='item.dataChangeLastModifiedBy';desc=!desc;"> ng-click="col='item.dataChangeLastModifiedBy';desc=!desc;">
最后修改人 {{'Component.Namespace.MasterBranch.Body.ItemLastModify' | translate }}
<span class="glyphicon glyphicon-sort"></span> <span class="glyphicon glyphicon-sort"></span>
</th> </th>
<th class="hover" title="排序" <th class="hover" title="{{'Component.Namespace.Branch.Body.ItemSort' | translate }}"
ng-click="col='item.dataChangeLastModifiedTime';desc=!desc;"> ng-click="col='item.dataChangeLastModifiedTime';desc=!desc;">
最后修改时间 {{'Component.Namespace.MasterBranch.Body.ItemLastModifyTime' | translate }}
<span class="glyphicon glyphicon-sort"></span> <span class="glyphicon glyphicon-sort"></span>
</th> </th>
<th> <th>
操作 {{'Component.Namespace.MasterBranch.Body.ItemOperator' | translate }}
</th> </th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr ng-repeat="config in namespace.branch.masterItems |orderBy:col:desc" <tr ng-repeat="config in namespace.branch.masterItems |orderBy:col:desc"
ng-if="config.item.key"> ng-if="config.item.key">
<td width="8%" class="text-center"> <td width="8%" class="text-center">
<span class="label label-warning no-radius cursor-pointer" <span class="label label-warning no-radius cursor-pointer" data-tooltip="tooltip"
data-tooltip="tooltip" data-placement="bottom" title="点击查看已发布的值" data-placement="bottom"
ng-if="config.isModified || config.isDeleted" title="{{'Component.Namespace.MasterBranch.Body.ClickToSeeItemValue' | translate }}"
ng-click="showText(config.oldValue)">未发布</span> ng-if="config.isModified || config.isDeleted"
<span class="label label-default-light no-radius" ng-click="showText(config.oldValue)">{{'Component.Namespace.MasterBranch.Body.ItemNoPublish' | translate }}</span>
data-tooltip="tooltip" data-placement="bottom" title="已生效的配置" <span class="label label-default-light no-radius" data-tooltip="tooltip"
ng-if="!config.isModified">已发布</span> data-placement="bottom"
</td> title="{{'Component.Namespace.MasterBranch.Body.ItemEffective' | translate }}"
<td width="15%" class="cursor-pointer" title="点击查看" ng-click="showText(config.item.key)"> ng-if="!config.isModified">{{'Component.Namespace.MasterBranch.Body.ItemPublished' | translate }}</span>
<span ng-bind="config.item.key | limitTo: 250"></span> </td>
<span ng-bind="config.item.key.length > 250 ? '...' :''"></span> <td width="15%" class="cursor-pointer"
<span class="label label-success" ng-if="config.isModified && !config.oldValue" title="{{'Component.Namespace.Branch.Body.ClickToSee' | translate }}"
data-tooltip="tooltip" data-placement="bottom" title="新增的配置"></span> ng-click="showText(config.item.key)">
<span class="label label-info" <span ng-bind="config.item.key | limitTo: 250"></span>
ng-if="config.isModified && config.oldValue && !config.isDeleted" <span ng-bind="config.item.key.length > 250 ? '...' :''"></span>
data-tooltip="tooltip" data-placement="bottom" title="修改的配置"></span> <span class="label label-success" ng-if="config.isModified && !config.oldValue"
<span class="label label-danger" ng-if="config.isDeleted" data-tooltip="tooltip" data-placement="bottom"
data-tooltip="tooltip" data-placement="bottom" title="删除的配置"></span> title="{{'Component.Namespace.MasterBranch.Body.AddedItem' | translate }}">{{'Component.Namespace.Branch.Body.Added' | translate }}</span>
</td> <span class="label label-info"
<td width="35%" class="cursor-pointer" title="点击查看" ng-click="showText(config.item.value)"> ng-if="config.isModified && config.oldValue && !config.isDeleted"
<span ng-bind="config.item.value | limitTo: 250"></span> data-tooltip="tooltip" data-placement="bottom"
<span ng-bind="config.item.value.length > 250 ? '...': ''"></span> title="{{'Component.Namespace.Branch.Body.ModifiedItem' | translate }}">{{'Component.Namespace.Branch.Body.Modify' | translate }}</span>
</td> <span class="label label-danger" ng-if="config.isDeleted" data-tooltip="tooltip"
<td width="12%" title="{{config.item.comment}}"> data-placement="bottom"
<span ng-bind="config.item.comment | limitTo: 250"></span> title="{{'Component.Namespace.Branch.Body.DeletedItem' | translate }}">{{'Component.Namespace.Branch.Body.Delete' | translate }}</span>
<span ng-bind="config.item.comment.length > 250 ?'...' : ''"></span> </td>
</td> <td width="35%" class="cursor-pointer"
<td width="10%" ng-bind="config.item.dataChangeLastModifiedBy"> title="{{'Component.Namespace.Branch.Body.ClickToSee' | translate }}"
</td> ng-click="showText(config.item.value)">
<td width="15%" <span ng-bind="config.item.value | limitTo: 250"></span>
ng-bind="config.item.dataChangeLastModifiedTime | date: 'yyyy-MM-dd HH:mm:ss'"> <span ng-bind="config.item.value.length > 250 ? '...': ''"></span>
</td> </td>
<td width="12%" title="{{config.item.comment}}">
<span ng-bind="config.item.comment | limitTo: 250"></span>
<span ng-bind="config.item.comment.length > 250 ?'...' : ''"></span>
</td>
<td width="10%" ng-bind="config.item.dataChangeLastModifiedBy">
</td>
<td width="15%"
ng-bind="config.item.dataChangeLastModifiedTime | date: 'yyyy-MM-dd HH:mm:ss'">
</td>
<td width="5%" class="text-center"> <td width="5%" class="text-center">
<img src="img/gray.png" <img src="img/gray.png" data-tooltip="tooltip" data-placement="bottom"
data-tooltip="tooltip" data-placement="bottom" title="对此配置灰度" title="{{'Component.Namespace.MasterBranch.Body.ModifyItem' | translate }}"
ng-if="!config.isDeleted" ng-if="!config.isDeleted" ng-click="editItem(namespace.branch, config.item)"
ng-click="editItem(namespace.branch, config.item)" ng-show="namespace.hasModifyPermission">
ng-show="namespace.hasModifyPermission"> </td>
</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>
...@@ -290,47 +305,49 @@ ...@@ -290,47 +305,49 @@
<div class="rules-manage-view row" ng-show="namespace.branch.viewType == 'rule'"> <div class="rules-manage-view row" ng-show="namespace.branch.viewType == 'rule'">
<div class="alert alert-warning no-radius" <div class="alert alert-warning no-radius"
ng-show="!namespace.hasModifyPermission && !namespace.hasReleasePermission"> ng-show="!namespace.hasModifyPermission && !namespace.hasReleasePermission">
<strong>Tips:</strong> <strong>Tips:</strong>
您没有权限编辑灰度规则, 具有namespace修改权或者发布权的人员才可以编辑灰度规则. 如需要编辑灰度规则,请找项目管理员申请权限. {{'Component.Namespace.Branch.GrayScaleRule.NoPermissionTips' | translate }}
</div> </div>
<table class="table table-bordered table-hover"> <table class="table table-bordered table-hover">
<thead> <thead>
<tr> <tr>
<th>灰度的AppId</th> <th>{{'Component.Namespace.Branch.GrayScaleRule.AppId' | translate }}</th>
<th>灰度的IP列表</th> <th>{{'Component.Namespace.Branch.GrayScaleRule.IpList' | translate }}</th>
<th>操作</th> <th>{{'Component.Namespace.Branch.GrayScaleRule.Operator' | translate }}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr ng-repeat="ruleItem in namespace.branch.rules.ruleItems"> <tr ng-repeat="ruleItem in namespace.branch.rules.ruleItems">
<td width="20%" ng-bind="ruleItem.clientAppId"></td> <td width="20%" ng-bind="ruleItem.clientAppId"></td>
<td width="70%" ng-show="!ruleItem.ApplyToAllInstances" <td width="70%" ng-show="!ruleItem.ApplyToAllInstances"
ng-bind="ruleItem.clientIpList.join(', ')"></td> ng-bind="ruleItem.clientIpList.join(', ')"></td>
<td width="70%" ng-show="ruleItem.ApplyToAllInstances">ALL</td> <td width="70%" ng-show="ruleItem.ApplyToAllInstances">
<td class="text-center" width="10%"> {{'Component.Namespace.Branch.GrayScaleRule.ApplyToAllInstances' | translate }}</td>
<img src="img/edit.png" class="i-20 hover" <td class="text-center" width="10%">
data-tooltip="tooltip" data-placement="bottom" title="修改" <img src="img/edit.png" class="i-20 hover" data-tooltip="tooltip"
ng-show="namespace.hasModifyPermission || namespace.hasReleasePermission" data-placement="bottom"
ng-click="editRuleItem(namespace.branch, ruleItem)"> title="{{'Component.Namespace.Branch.GrayScaleRule.Modify' | translate }}"
<img src="img/cancel.png" class="i-20 hover" style="margin-left: 5px;" ng-show="namespace.hasModifyPermission || namespace.hasReleasePermission"
data-tooltip="tooltip" data-placement="bottom" title="删除" ng-click="editRuleItem(namespace.branch, ruleItem)">
ng-show="namespace.hasModifyPermission || namespace.hasReleasePermission" <img src="img/cancel.png" class="i-20 hover" style="margin-left: 5px;"
ng-click="deleteRuleItem(namespace.branch, ruleItem)"> data-tooltip="tooltip" data-placement="bottom"
</td> title="{{'Component.Namespace.Branch.GrayScaleRule.Delete' | translate }}"
</tr> ng-show="namespace.hasModifyPermission || namespace.hasReleasePermission"
ng-click="deleteRuleItem(namespace.branch, ruleItem)">
</td>
</tr>
</tbody> </tbody>
</table> </table>
<button class="btn btn-primary" <button class="btn btn-primary" ng-if="namespace.hasModifyPermission || namespace.hasReleasePermission"
ng-if="namespace.hasModifyPermission || namespace.hasReleasePermission" ng-show="(namespace.isPublic && !namespace.isLinkedNamespace) ||
ng-show="(namespace.isPublic && !namespace.isLinkedNamespace) ||
((!namespace.isPublic || namespace.isLinkedNamespace) ((!namespace.isPublic || namespace.isLinkedNamespace)
&& (!namespace.branch.rules && (!namespace.branch.rules
|| !namespace.branch.rules.ruleItems || !namespace.branch.rules.ruleItems
|| !namespace.branch.rules.ruleItems.length))" || !namespace.branch.rules.ruleItems.length))"
ng-click="addRuleItem(namespace.branch)">新增规则 ng-click="addRuleItem(namespace.branch)">{{'Component.Namespace.Branch.GrayScaleRule.AddNewRule' | translate }}
</button> </button>
...@@ -340,50 +357,52 @@ ...@@ -340,50 +357,52 @@
<!--instances --> <!--instances -->
<div class="panel panel-default" ng-show="namespace.branch.viewType == 'instance'"> <div class="panel panel-default" ng-show="namespace.branch.viewType == 'instance'">
<div class="panel-heading text-right"> <div class="panel-heading text-right">
<button class="btn btn-default btn-sm" <button class="btn btn-default btn-sm" data-tooltip="tooltip" data-placement="bottom"
data-tooltip="tooltip" data-placement="bottom" title="刷新列表" title="{{'Component.Namespace.Branch.Instance.RefreshList' | translate }}"
ng-click="refreshInstancesInfo(namespace.branch)"> ng-click="refreshInstancesInfo(namespace.branch)">
<img src="../../img/refresh.png"/> <img src="../../img/refresh.png" />
</button> </button>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<div class="panel-default" ng-if="namespace.branch.latestReleaseInstances.total > 0"> <div class="panel-default" ng-if="namespace.branch.latestReleaseInstances.total > 0">
<div class="panel-heading"> <div class="panel-heading">
<a target="_blank" data-tooltip="tooltip" data-placement="bottom" title="查看配置" <a target="_blank" data-tooltip="tooltip" data-placement="bottom"
href="/config/history.html?#/appid={{appId}}&env={{env}}&clusterName={{namespace.baseInfo.clusterName}}&namespaceName={{namespace.baseInfo.namespaceName}}&releaseId={{namespace.branch.latestRelease.id}}"> title="{{'Component.Namespace.Branch.Instance.ItemToSee' | translate }}"
href="/config/history.html?#/appid={{appId}}&env={{env}}&clusterName={{namespace.baseInfo.clusterName}}&namespaceName={{namespace.baseInfo.namespaceName}}&releaseId={{namespace.branch.latestRelease.id}}">
{{namespace.branch.latestRelease.name}} {{namespace.branch.latestRelease.name}}
</a> </a>
</div> </div>
<table class="table table-bordered table-striped"> <table class="table table-bordered table-striped">
<thead> <thead>
<tr> <tr>
<td>App ID</td> <td>{{'Component.Namespace.Branch.Instance.InstanceAppId' | translate }}</td>
<td>Cluster Name</td> <td>{{'Component.Namespace.Branch.Instance.InstanceClusterName' | translate }}</td>
<td>Data Center</td> <td>{{'Component.Namespace.Branch.Instance.InstanceDataCenter' | translate }}</td>
<td>IP</td> <td>{{'Component.Namespace.Branch.Instance.InstanceIp' | translate }}</td>
<td>配置获取时间</td> <td>{{'Component.Namespace.Branch.Instance.InstanceGetItemTime' | translate }}</td>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr ng-repeat="instance in namespace.branch.latestReleaseInstances.content"> <tr ng-repeat="instance in namespace.branch.latestReleaseInstances.content">
<td width="20%" ng-bind="instance.appId"></td> <td width="20%" ng-bind="instance.appId"></td>
<td width="20%" ng-bind="instance.clusterName"></td> <td width="20%" ng-bind="instance.clusterName"></td>
<td width="20%" ng-bind="instance.dataCenter"></td> <td width="20%" ng-bind="instance.dataCenter"></td>
<td width="20%" ng-bind="instance.ip"></td> <td width="20%" ng-bind="instance.ip"></td>
<td width="20%">{{instance.configs && instance.configs.length ? <td width="20%">{{instance.configs && instance.configs.length ?
(instance.configs[0].releaseDeliveryTime | date: 'yyyy-MM-dd HH:mm:ss') : ''}} (instance.configs[0].releaseDeliveryTime | date: 'yyyy-MM-dd HH:mm:ss') : ''}}
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
<div class="row text-center" <div class="row text-center"
ng-show="namespace.branch.latestReleaseInstances.content.length < namespace.branch.latestReleaseInstances.total"> ng-show="namespace.branch.latestReleaseInstances.content.length < namespace.branch.latestReleaseInstances.total">
<button class="btn btn-default" ng-click="loadInstanceInfo(namespace.branch)">加载更多</button> <button class="btn btn-default"
ng-click="loadInstanceInfo(namespace.branch)">{{'Component.Namespace.Branch.Instance.LoadMore' | translate }}</button>
</div> </div>
</div> </div>
<div class="text-center" ng-if="namespace.branch.latestReleaseInstances.total == 0"> <div class="text-center" ng-if="namespace.branch.latestReleaseInstances.total == 0">
无实例信息 {{'Component.Namespace.Branch.Instance.NoInstance' | translate }}
</div> </div>
</div> </div>
...@@ -391,13 +410,12 @@ ...@@ -391,13 +410,12 @@
</div> </div>
<!--history view--> <!--history view-->
<div class="J_historyview history-view" ng-show="namespace.branch.viewType == 'history'"> <div class="J_historyview history-view" ng-show="namespace.branch.viewType == 'history'">
<div class="media" <div class="media" ng-show="namespace.branch.commits && namespace.branch.commits.length"
ng-show="namespace.branch.commits && namespace.branch.commits.length" ng-repeat="commits in namespace.branch.commits">
ng-repeat="commits in namespace.branch.commits">
<div class="media-body"> <div class="media-body">
<div class="row"> <div class="row">
<div class="col-md-6 col-sm-6 "><h3 class="media-heading" <div class="col-md-6 col-sm-6 ">
ng-bind="commits.dataChangeCreatedBy"></h3> <h3 class="media-heading" ng-bind="commits.dataChangeCreatedBy"></h3>
</div> </div>
<div class="col-md-6 col-sm-6 text-right"> <div class="col-md-6 col-sm-6 text-right">
<h5 class="media-heading" <h5 class="media-heading"
...@@ -408,108 +426,107 @@ ...@@ -408,108 +426,107 @@
<!--properties format--> <!--properties format-->
<table class="table table-bordered table-striped text-center table-hover" <table class="table table-bordered table-striped text-center table-hover"
style="margin-top: 5px;" style="margin-top: 5px;" ng-if="namespace.isPropertiesFormat">
ng-if="namespace.isPropertiesFormat">
<thead> <thead>
<tr> <tr>
<th> <th>
Type {{'Component.Namespace.Branch.History.ItemType' | translate }}
</th> </th>
<th> <th>
Key {{'Component.Namespace.Branch.History.ItemKey' | translate }}
</th> </th>
<th> <th>
Old Value {{'Component.Namespace.Branch.History.ItemOldValue' | translate }}
</th> </th>
<th> <th>
New Value {{'Component.Namespace.Branch.History.ItemNewValue' | translate }}
</th> </th>
<th> <th>
Comment {{'Component.Namespace.Branch.History.ItemComment' | translate }}
</th> </th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<!--兼容老数据,不显示item类型为空行和注释的item--> <!--兼容老数据,不显示item类型为空行和注释的item-->
<tr ng-repeat="item in commits.changeSets.createItems" ng-show="item.key"> <tr ng-repeat="item in commits.changeSets.createItems" ng-show="item.key">
<td width="2%"> <td width="6%">
新增 {{'Component.Namespace.Branch.History.NewAdded' | translate }}
</td> </td>
<td width="20%" title="{{item.key}}"> <td width="20%" title="{{item.key}}">
<span ng-bind="item.key | limitTo: 250"></span> <span ng-bind="item.key | limitTo: 250"></span>
<span ng-bind="item.key.length > 250 ? '...' :''"></span> <span ng-bind="item.key.length > 250 ? '...' :''"></span>
</td> </td>
<td width="30%"> <td width="28%">
</td> </td>
<td width="30%" class="cursor-pointer" title="{{item.value}}" <td width="28%" class="cursor-pointer" title="{{item.value}}"
ng-click="showText(item.value)"> ng-click="showText(item.value)">
<span ng-bind="item.value | limitTo: 250"></span> <span ng-bind="item.value | limitTo: 250"></span>
<span ng-bind="item.value.length > 250 ? '...': ''"></span> <span ng-bind="item.value.length > 250 ? '...': ''"></span>
</td> </td>
<td width="18%" title="{{item.comment}}"> <td width="18%" title="{{item.comment}}">
<span ng-bind="item.comment | limitTo: 250"></span> <span ng-bind="item.comment | limitTo: 250"></span>
<span ng-bind="item.comment.length > 250 ?'...' : ''"></span> <span ng-bind="item.comment.length > 250 ?'...' : ''"></span>
</td> </td>
</tr> </tr>
<tr ng-repeat="item in commits.changeSets.updateItems"> <tr ng-repeat="item in commits.changeSets.updateItems">
<td width="2%"> <td width="6%">
更新 {{'Component.Namespace.Branch.History.Modified' | translate }}
</td> </td>
<td width="20%" title="{{item.newItem.key}}"> <td width="20%" title="{{item.newItem.key}}">
<span ng-bind="item.newItem.key | limitTo: 250"></span> <span ng-bind="item.newItem.key | limitTo: 250"></span>
<span ng-bind="item.newItem.key.length > 250 ? '...' :''"></span> <span ng-bind="item.newItem.key.length > 250 ? '...' :''"></span>
</td> </td>
<td width="30%" class="cursor-pointer" title="{{item.oldItem.value}}" <td width="28%" class="cursor-pointer" title="{{item.oldItem.value}}"
ng-click="showText(item.oldItem.value)"> ng-click="showText(item.oldItem.value)">
<span ng-bind="item.oldItem.value | limitTo: 250"></span> <span ng-bind="item.oldItem.value | limitTo: 250"></span>
<span ng-bind="item.oldItem.value.length > 250 ? '...': ''"></span> <span ng-bind="item.oldItem.value.length > 250 ? '...': ''"></span>
</td> </td>
<td width="30%" class="cursor-pointer" title="{{item.newItem.value}}" <td width="28%" class="cursor-pointer" title="{{item.newItem.value}}"
ng-click="showText(item.newItem.value)"> ng-click="showText(item.newItem.value)">
<span ng-bind="item.newItem.value | limitTo: 250"></span> <span ng-bind="item.newItem.value | limitTo: 250"></span>
<span ng-bind="item.newItem.value.length > 250 ? '...': ''"></span> <span ng-bind="item.newItem.value.length > 250 ? '...': ''"></span>
</td> </td>
<td width="18%" title="{{item.newItem.comment}}"> <td width="18%" title="{{item.newItem.comment}}">
<span ng-bind="item.newItem.comment | limitTo: 250"></span> <span ng-bind="item.newItem.comment | limitTo: 250"></span>
<span ng-bind="item.newItem.comment.length > 250 ?'...' : ''"></span> <span ng-bind="item.newItem.comment.length > 250 ?'...' : ''"></span>
</td> </td>
</tr> </tr>
<tr ng-repeat="item in commits.changeSets.deleteItems" <tr ng-repeat="item in commits.changeSets.deleteItems"
ng-show="item.key || item.comment"> ng-show="item.key || item.comment">
<td width="2%"> <td width="6%">
删除 {{'Component.Namespace.Branch.History.Deleted' | translate }}
</td> </td>
<td width="20%" title="{{item.key}}"> <td width="20%" title="{{item.key}}">
<span ng-bind="item.key | limitTo: 250"></span> <span ng-bind="item.key | limitTo: 250"></span>
<span ng-bind="item.key.length > 250 ? '...' :''"></span> <span ng-bind="item.key.length > 250 ? '...' :''"></span>
</td> </td>
<td width="30%" title="{{item.value}}"> <td width="28%" title="{{item.value}}">
<span ng-bind="item.value | limitTo: 250"></span> <span ng-bind="item.value | limitTo: 250"></span>
<span ng-bind="item.value.length > 250 ? '...': ''"></span> <span ng-bind="item.value.length > 250 ? '...': ''"></span>
</td> </td>
<td width="30%"> <td width="28%">
</td> </td>
<td width="18%" title="{{item.comment}}"> <td width="18%" title="{{item.comment}}">
<span ng-bind="item.comment | limitTo: 250"></span> <span ng-bind="item.comment | limitTo: 250"></span>
<span ng-bind="item.comment.length > 250 ?'...' : ''"></span> <span ng-bind="item.comment.length > 250 ?'...' : ''"></span>
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
<!--not properties format--> <!--not properties format-->
<div ng-if="!namespace.isPropertiesFormat"> <div ng-if="!namespace.isPropertiesFormat">
<div ng-repeat="item in commits.changeSets.createItems"> <div ng-repeat="item in commits.changeSets.createItems">
<textarea class="form-control no-radius" rows="20" <textarea class="form-control no-radius" rows="20" ng-disabled="true"
ng-disabled="true" ng-bind="item.value"> ng-bind="item.value">
</textarea> </textarea>
</div> </div>
<div ng-repeat="item in commits.changeSets.updateItems"> <div ng-repeat="item in commits.changeSets.updateItems">
<textarea class="form-control no-radius" rows="20" <textarea class="form-control no-radius" rows="20" ng-disabled="true"
ng-disabled="true" ng-bind="item.newItem.value"> ng-bind="item.newItem.value">
</textarea> </textarea>
</div> </div>
</div> </div>
...@@ -520,14 +537,14 @@ ...@@ -520,14 +537,14 @@
</div> </div>
<div class="text-center"> <div class="text-center">
<button type="button" class="btn btn-default" ng-show="!namespace.branch.hasLoadAllCommit" <button type="button" class="btn btn-default" ng-show="!namespace.branch.hasLoadAllCommit"
ng-click="loadCommitHistory(namespace.branch)">加载更多 ng-click="loadCommitHistory(namespace.branch)">{{'Component.Namespace.Branch.History.LoadMore' | translate }}
<span class="glyphicon glyphicon-menu-down"></span></button> <span class="glyphicon glyphicon-menu-down"></span></button>
</div> </div>
<div class="empty-container text-center" <div class="empty-container text-center"
ng-show="!namespace.branch.commits || !namespace.branch.commits.length"> ng-show="!namespace.branch.commits || !namespace.branch.commits.length">
无更改历史 {{'Component.Namespace.Branch.History.NoHistory' | translate }}
</div> </div>
</div> </div>
</section> </section>
</div> </div>
</section> </section>
\ No newline at end of file
...@@ -3,17 +3,17 @@ ...@@ -3,17 +3,17 @@
<div class="col-md-6" style="padding-bottom:5px;"> <div class="col-md-6" style="padding-bottom:5px;">
<span class="text-center namespace-attribute-public label label-primary no-radius"> <span class="text-center namespace-attribute-public label label-primary no-radius">
<span data-tooltip="tooltip" data-placement="bottom" <span data-tooltip="tooltip" data-placement="bottom"
title="私有namespace({{namespace.baseInfo.namespaceName}})的配置只能被AppId为{{appId}}的客户端读取到" title="{{'Component.Namespace.Header.Title.PrivateTips' | translate:this }}"
ng-show="!namespace.isPublic">私有</span> ng-show="!namespace.isPublic">{{'Component.Namespace.Header.Title.Private' | translate }}</span>
<span data-tooltip="tooltip" data-placement="top" <span data-tooltip="tooltip" data-placement="top"
title="namespace({{namespace.baseInfo.namespaceName}})的配置能被任何客户端读取到" title="{{'Component.Namespace.Header.Title.PublicTips' | translate:this }}"
ng-show="namespace.isPublic && namespace.parentAppId == namespace.baseInfo.appId">公共</span> ng-show="namespace.isPublic && namespace.parentAppId == namespace.baseInfo.appId">{{'Component.Namespace.Header.Title.Public' | translate }}</span>
<span data-tooltip="tooltip" data-placement="top" <span data-tooltip="tooltip" data-placement="top"
title="namespace({{namespace.baseInfo.namespaceName}})的配置将会覆盖公共namespace的配置, 且合并之后的配置只能被AppId为{{appId}}的客户端读取到" title="{{'Component.Namespace.Header.Title.ExtendTips' | translate:this }}"
ng-show="namespace.isPublic && namespace.isLinkedNamespace" ng-show="namespace.isPublic && namespace.isLinkedNamespace"
ng-click="goToParentAppConfigPage(namespace)">关联</span> ng-click="goToParentAppConfigPage(namespace)">{{'Component.Namespace.Header.Title.Extend' | translate }}</span>
</span> </span>
<span class="text-center namespace-attribute-public label label-info no-radius"> <span class="text-center namespace-attribute-public label label-info no-radius">
<span ng-bind="namespace.format" style="width:30px;"></span> <span ng-bind="namespace.format" style="width:30px;"></span>
...@@ -21,11 +21,10 @@ ...@@ -21,11 +21,10 @@
</div> </div>
<div class="col-md-6 text-right" style="padding-right:23px;"> <div class="col-md-6 text-right" style="padding-right:23px;">
<span data-toggle="collapse" data-target="#BODY{{namespace.branch.id}}" aria-expanded="false"> <span data-toggle="collapse" data-target="#BODY{{namespace.branch.id}}" aria-expanded="false">
<span class="label no-radius cursor-pointer" <span class="label no-radius cursor-pointer" data-toggle="collapse" data-target="#BODY{{namespace.id}}"
data-toggle="collapse" data-target="#BODY{{namespace.id}}" aria-expanded="false" aria-expanded="false" ng-click="showNamespaceBody = !showNamespaceBody"
ng-click="showNamespaceBody = !showNamespaceBody" ng-show="namespace.initialized">
ng-show="namespace.initialized"> <a>{{'Component.Namespace.Header.Title.ExpandAndCollapse' | translate }}</a>
<a>[展开/收缩]</a>
</span> </span>
</span> </span>
</div> </div>
...@@ -39,20 +38,20 @@ ...@@ -39,20 +38,20 @@
<ul class="nav nav-tabs"> <ul class="nav nav-tabs">
<li role="presentation"> <li role="presentation">
<a ng-class="{'node_active': namespace.displayControl.currentOperateBranch == 'master'}" <a ng-class="{'node_active': namespace.displayControl.currentOperateBranch == 'master'}"
ng-click="switchBranch('master', true)"> ng-click="switchBranch('master', true)">
<img src="img/branch.png"> <img src="img/branch.png">
主版本 {{'Component.Namespace.Header.Title.Master' | translate }}
</a> </a>
</li> </li>
<li role="presentation"> <li role="presentation">
<a ng-class="{'node_active': namespace.displayControl.currentOperateBranch != 'master'}" <a ng-class="{'node_active': namespace.displayControl.currentOperateBranch != 'master'}"
ng-click="switchBranch(namespace.branchName, true)"> ng-click="switchBranch(namespace.branchName, true)">
<img src="img/branch.png"> <img src="img/branch.png">
灰度版本 {{'Component.Namespace.Header.Title.Grayscale' | translate }}
</a> </a>
</li> </li>
</ul> </ul>
</div> </div>
</div> </div>
</header> </header>
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -4,25 +4,23 @@ ...@@ -4,25 +4,23 @@
<div class="modal-header panel-primary"> <div class="modal-header panel-primary">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"> <button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span></button> <span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">发布受限</h4> <h4 class="modal-title">{{'Component.PublishDeny.Title' | translate }}</h4>
</div> </div>
<div class="modal-body"> <div class="modal-body">{{'Component.PublishDeny.Tips1' | translate:this }}
您不能发布哟~{{env}}环境配置的编辑和发布必须为不同的人,请找另一个具有当前namespace发布权的人操作发布~
<span ng-if="toReleaseNamespace.isEmergencyPublishAllowed"> <span ng-if="toReleaseNamespace.isEmergencyPublishAllowed">
<br><br><small>(如果是非工作时间或者特殊情况,您可以通过点击<mark>紧急发布</mark>按钮进行发布)</small> <br><br><small>{{'Component.PublishDeny.Tips2' | translate }}</small>
</span> </span>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-danger" data-dismiss="modal" <button type="button" class="btn btn-danger" data-dismiss="modal"
ng-if="toReleaseNamespace.isEmergencyPublishAllowed" ng-if="toReleaseNamespace.isEmergencyPublishAllowed" ng-click="emergencyPublish()">
ng-click="emergencyPublish()"> {{'Component.PublishDeny.EmergencyPublish' | translate }}
紧急发布
</button> </button>
<button type="button" class="btn btn-primary" data-dismiss="modal"> <button type="button" class="btn btn-primary" data-dismiss="modal">
关闭 {{'Component.PublishDeny.Close' | translate }}
</button> </button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
\ No newline at end of file
<form id="releaseModal" class="modal fade form-horizontal" name="releaseForm" valdr-type="Release" <form id="releaseModal" class="modal fade form-horizontal" name="releaseForm" valdr-type="Release"
ng-submit="release()"> ng-submit="release()">
<div class="modal-dialog" role="document"> <div class="modal-dialog" role="document">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header panel-primary"> <div class="modal-header panel-primary">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
aria-hidden="true">&times;</span></button> aria-hidden="true">&times;</span></button>
<h4 class="modal-title" ng-show="!toReleaseNamespace.isBranch">发布 <h4 class="modal-title" ng-show="!toReleaseNamespace.isBranch">
<small>(只有发布过的配置才会被客户端获取到,此次发布只会作用于当前环境:{{env}})</small> {{'Component.Publish.Title' | translate }}
<small>{{'Component.Publish.Tips' | translate:this }}</small>
</h4> </h4>
<h4 class="modal-title" ng-show="toReleaseNamespace.isBranch && !toReleaseNamespace.mergeAndPublish"> <h4 class="modal-title" ng-show="toReleaseNamespace.isBranch && !toReleaseNamespace.mergeAndPublish">
灰度发布 {{'Component.Publish.Grayscale' | translate }}
<small>(灰度发布的配置只会作用于在灰度规则中配置的实例)</small> <small>{{'Component.Publish.GrayscaleTips' | translate }}</small>
</h4> </h4>
<h4 class="modal-title" ng-show="toReleaseNamespace.isBranch && toReleaseNamespace.mergeAndPublish"> <h4 class="modal-title" ng-show="toReleaseNamespace.isBranch && toReleaseNamespace.mergeAndPublish">
全量发布 {{'Component.Publish.AllPublish' | translate }}
<small>(全量发布的配置会作用于全部的实例)</small> <small>{{'Component.Publish.AllPublishTips' | translate }}</small>
</h4> </h4>
</div> </div>
...@@ -26,212 +27,211 @@ ...@@ -26,212 +27,211 @@
<div class="row"> <div class="row">
<div class="btn-group btn-group-xs" style="padding-right: 10px" role="group"> <div class="btn-group btn-group-xs" style="padding-right: 10px" role="group">
<button type="button" class="btn btn-default" <button type="button" class="btn btn-default"
ng-class="{active:releaseChangeViewType=='change'}" ng-class="{active:releaseChangeViewType=='change'}"
ng-click="switchReleaseChangeViewType('change')">查看变更 ng-click="switchReleaseChangeViewType('change')">{{'Component.Publish.ToSeeChange' | translate }}
</button> </button>
<button type="button" class="btn btn-default" <button type="button" class="btn btn-default"
ng-class="{active:releaseChangeViewType=='release'}" ng-class="{active:releaseChangeViewType=='release'}"
ng-click="switchReleaseChangeViewType('release')">发布的值 ng-click="switchReleaseChangeViewType('release')">{{'Component.Publish.PublishedValue' | translate }}
</button> </button>
</div> </div>
</div> </div>
</div> </div>
<label class="col-sm-2 control-label" ng-if="toReleaseNamespace.isPropertiesFormat">Changes</label> <label class="col-sm-2 control-label"
ng-if="toReleaseNamespace.isPropertiesFormat">{{'Component.Publish.Changes' | translate }}</label>
<div class="col-sm-10" <div class="col-sm-10"
ng-if="(!toReleaseNamespace.isBranch && toReleaseNamespace.itemModifiedCnt) ng-if="(!toReleaseNamespace.isBranch && toReleaseNamespace.itemModifiedCnt)
|| (toReleaseNamespace.isBranch && toReleaseNamespace.itemModifiedCnt) || (toReleaseNamespace.isBranch && toReleaseNamespace.itemModifiedCnt)
|| (toReleaseNamespace.isBranch && toReleaseNamespace.mergeAndPublish && toReleaseNamespace.branchItems.length)" || (toReleaseNamespace.isBranch && toReleaseNamespace.mergeAndPublish && toReleaseNamespace.branchItems.length)"
valdr-form-group> valdr-form-group>
<!--properties format--> <!--properties format-->
<!--normal release--> <!--normal release-->
<table class="table table-bordered table-striped text-center table-hover" <table class="table table-bordered table-striped text-center table-hover"
ng-if="toReleaseNamespace.isPropertiesFormat && !toReleaseNamespace.isBranch"> ng-if="toReleaseNamespace.isPropertiesFormat && !toReleaseNamespace.isBranch">
<thead> <thead>
<tr> <tr>
<th> <th>
Key {{'Component.Publish.Key' | translate }}
</th> </th>
<th> <th>
发布的值 {{'Component.Publish.PublishedValue' | translate }}
</th> </th>
<th> <th>
未发布的值 {{'Component.Publish.NoPublishedValue' | translate }}
</th> </th>
<th> <th>
修改人 {{'Component.Publish.ModifyUser' | translate }}
</th> </th>
<th> <th>
修改时间 {{'Component.Publish.ModifyTime' | translate }}
</th> </th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr ng-repeat="config in toReleaseNamespace.items" <tr ng-repeat="config in toReleaseNamespace.items"
ng-if="config.item.key && config.isModified"> ng-if="config.item.key && config.isModified">
<td width="20%" title="{{config.item.key}}"> <td width="20%" title="{{config.item.key}}">
<span ng-bind="config.item.key"></span> <span ng-bind="config.item.key"></span>
<span class="label label-success" ng-if="config.isModified && !config.oldValue" <span class="label label-success" ng-if="config.isModified && !config.oldValue"
data-tooltip="tooltip" data-placement="bottom" title="新增的配置"></span> data-tooltip="tooltip" data-placement="bottom"
<span class="label label-info" title="{{'Component.Publish.NewAddedTips' | translate }}">{{'Component.Publish.NewAdded' | translate }}</span>
ng-if="config.isModified && config.oldValue && !config.isDeleted" <span class="label label-info"
data-tooltip="tooltip" data-placement="bottom" title="修改的配置"></span> ng-if="config.isModified && config.oldValue && !config.isDeleted"
<span class="label label-danger" ng-if="config.isDeleted" data-tooltip="tooltip" data-placement="bottom"
data-tooltip="tooltip" data-placement="bottom" title="删除的配置"></span> title="{{'Component.Publish.ModifiedTips' | translate }}">{{'Component.Publish.Modified' | translate }}</span>
</td> <span class="label label-danger" ng-if="config.isDeleted" data-tooltip="tooltip"
<td width="25%" title="{{config.oldValue}}"> data-placement="bottom"
<span ng-bind="config.oldValue"></span> title="{{'Component.Publish.DeletedTips' | translate }}">{{'Component.Publish.Deleted' | translate }}</span>
</td> </td>
<td width="25%" title="{{config.newValue}}"> <td width="25%" title="{{config.oldValue}}">
<span ng-bind="config.newValue"></span> <span ng-bind="config.oldValue"></span>
</td> </td>
<td width="15%" ng-bind="config.item.dataChangeLastModifiedBy"> <td width="25%" title="{{config.newValue}}">
</td> <span ng-bind="config.newValue"></span>
<td width="15%" </td>
ng-bind="config.item.dataChangeLastModifiedTime | date: 'yyyy-MM-dd HH:mm:ss'"> <td width="15%" ng-bind="config.item.dataChangeLastModifiedBy">
</td> </td>
</tr> <td width="15%"
ng-bind="config.item.dataChangeLastModifiedTime | date: 'yyyy-MM-dd HH:mm:ss'">
</td>
</tr>
</tbody> </tbody>
</table> </table>
<!--branch gray release--> <!--branch gray release-->
<table class="table table-bordered table-striped text-center table-hover" <table class="table table-bordered table-striped text-center table-hover" ng-if="toReleaseNamespace.isPropertiesFormat &&
ng-if="toReleaseNamespace.isPropertiesFormat &&
toReleaseNamespace.isBranch && !toReleaseNamespace.mergeAndPublish"> toReleaseNamespace.isBranch && !toReleaseNamespace.mergeAndPublish">
<thead> <thead>
<tr> <tr>
<th> <th>
Key {{'Component.Publish.Key' | translate }}
</th> </th>
<th> <th>
主版本值 {{'Component.Publish.MasterValue' | translate }}
</th> </th>
<th> <th>
灰度版本发布的值 {{'Component.Publish.GrayPublishedValue' | translate }}
</th> </th>
<th> <th>
灰度版本未发布的值 {{'Component.Publish.GrayNoPublishedValue' | translate }}
</th> </th>
<th> <th>
修改人 {{'Component.Publish.ModifyUser' | translate }}
</th> </th>
<th> <th>
修改时间 {{'Component.Publish.ModifyTime' | translate }}
</th> </th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr ng-repeat="config in toReleaseNamespace.branchItems" <tr ng-repeat="config in toReleaseNamespace.branchItems"
ng-if="config.isModified || config.isDeleted"> ng-if="config.isModified || config.isDeleted">
<td width="15%" title="{{config.item.key}}"> <td width="15%" title="{{config.item.key}}">
<span ng-bind="config.item.key"></span> <span ng-bind="config.item.key"></span>
<span class="label label-danger" <span class="label label-danger"
ng-show="config.isDeleted"></span> ng-show="config.isDeleted">{{'Component.Publish.Deleted' | translate }}</span>
</td> </td>
<td width="20%" title="{{config.masterReleaseValue}}"> <td width="20%" title="{{config.masterReleaseValue}}">
<span ng-bind="config.masterReleaseValue"></span> <span ng-bind="config.masterReleaseValue"></span>
</td> </td>
<td width="20%" title="{{config.oldValue}}"> <td width="20%" title="{{config.oldValue}}">
<span ng-bind="config.oldValue"></span> <span ng-bind="config.oldValue"></span>
</td> </td>
<td width="20%" title="{{config.newValue}}"> <td width="20%" title="{{config.newValue}}">
<span ng-bind="config.newValue"></span> <span ng-bind="config.newValue"></span>
</td> </td>
<td width="10%" ng-bind="config.item.dataChangeLastModifiedBy"> <td width="10%" ng-bind="config.item.dataChangeLastModifiedBy">
</td> </td>
<td width="15%" <td width="15%"
ng-bind="config.item.dataChangeLastModifiedTime | date: 'yyyy-MM-dd HH:mm:ss'"> ng-bind="config.item.dataChangeLastModifiedTime | date: 'yyyy-MM-dd HH:mm:ss'">
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
<!--branch updateAndPublish and publish--> <!--branch updateAndPublish and publish-->
<table class="table table-bordered table-striped text-center table-hover" <table class="table table-bordered table-striped text-center table-hover" ng-if="toReleaseNamespace.isPropertiesFormat &&
ng-if="toReleaseNamespace.isPropertiesFormat &&
toReleaseNamespace.isBranch && toReleaseNamespace.mergeAndPublish"> toReleaseNamespace.isBranch && toReleaseNamespace.mergeAndPublish">
<thead> <thead>
<tr> <tr>
<th> <th>
Key {{'Component.Publish.Key' | translate }}
</th> </th>
<th ng-if="toReleaseNamespace.isBranch"> <th ng-if="toReleaseNamespace.isBranch">
主版本值 {{'Component.Publish.MasterValue' | translate }}
</th> </th>
<th ng-if="toReleaseNamespace.isBranch && toReleaseNamespace.mergeAndPublish"> <th ng-if="toReleaseNamespace.isBranch && toReleaseNamespace.mergeAndPublish">
灰度版本的值 {{'Component.Publish.GrayValue' | translate }}
</th> </th>
<th ng-if="!toReleaseNamespace.isBranch || !toReleaseNamespace.mergeAndPublish"> <th ng-if="!toReleaseNamespace.isBranch || !toReleaseNamespace.mergeAndPublish">
发布的值 {{'Component.Publish.PublishedValue' | translate }}
</th> </th>
<th ng-if="!toReleaseNamespace.isBranch || !toReleaseNamespace.mergeAndPublish"> <th ng-if="!toReleaseNamespace.isBranch || !toReleaseNamespace.mergeAndPublish">
未发布的值 {{'Component.Publish.NoPublishedValue' | translate }}
</th> </th>
<th> <th>
修改人 {{'Component.Publish.ModifyUser' | translate }}
</th> </th>
<th> <th>
修改时间 {{'Component.Publish.ModifyTime' | translate }}
</th> </th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr ng-repeat="config in toReleaseNamespace.branchItems" <tr ng-repeat="config in toReleaseNamespace.branchItems" ng-if="!config.isDeleted">
ng-if="!config.isDeleted"> <td width="20%" title="{{config.item.key}}">
<td width="20%" title="{{config.item.key}}"> <span ng-bind="config.item.key"></span>
<span ng-bind="config.item.key"></span> </td>
</td> <td width="25%" title="{{config.masterReleaseValue}}">
<td width="25%" title="{{config.masterReleaseValue}}"> <span ng-bind="config.masterReleaseValue"></span>
<span ng-bind="config.masterReleaseValue"></span> </td>
</td> <td width="25%" title="{{config.item.value}}">
<td width="25%" title="{{config.item.value}}"> <span ng-bind="config.item.value"></span>
<span ng-bind="config.item.value"></span> </td>
</td> <td width="15%" ng-bind="config.item.dataChangeLastModifiedBy">
<td width="15%" ng-bind="config.item.dataChangeLastModifiedBy"> </td>
</td> <td width="15%"
<td width="15%" ng-bind="config.item.dataChangeLastModifiedTime | date: 'yyyy-MM-dd HH:mm:ss'">
ng-bind="config.item.dataChangeLastModifiedTime | date: 'yyyy-MM-dd HH:mm:ss'"> </td>
</td> </tr>
</tr>
</tbody> </tbody>
</table> </table>
<!--file format --> <!--file format -->
<div ng-repeat="item in toReleaseNamespace.items" <div ng-repeat="item in toReleaseNamespace.items" ng-if="!toReleaseNamespace.isPropertiesFormat"
ng-if="!toReleaseNamespace.isPropertiesFormat" ng-show="releaseChangeViewType=='change'">
ng-show="releaseChangeViewType=='change'"> <apollodiff old-str="item.oldValue" new-str="item.newValue" apollo-id="'releaseStrDiff'">
<apollodiff old-str="item.oldValue" new-str="item.newValue" </apollodiff>
apollo-id="'releaseStrDiff'"></apollodiff>
</div> </div>
<div ng-repeat="item in toReleaseNamespace.items" <div ng-repeat="item in toReleaseNamespace.items" ng-if="!toReleaseNamespace.isPropertiesFormat"
ng-if="!toReleaseNamespace.isPropertiesFormat" ng-show="releaseChangeViewType=='release'">
ng-show="releaseChangeViewType=='release'"> <textarea class="form-control no-radius" rows="20" ng-disabled="true"
<textarea class="form-control no-radius" rows="20" ng-show="item.newValue" ng-bind="item.newValue">
ng-disabled="true" ng-show="item.newValue" ng-bind="item.newValue">
</textarea> </textarea>
</div> </div>
</div> </div>
<div class="col-sm-5" <div class="col-sm-5"
ng-show="(!toReleaseNamespace.isBranch && !toReleaseNamespace.itemModifiedCnt)" ng-show="(!toReleaseNamespace.isBranch && !toReleaseNamespace.itemModifiedCnt)"
valdr-form-group> valdr-form-group>
<label class="form-control-static"> <label class="form-control-static">
配置没有变化 {{'Component.Publish.ItemNoChange' | translate }}
</label> </label>
</div> </div>
<div class="col-sm-5" <div class="col-sm-5"
ng-show="(toReleaseNamespace.isBranch && !toReleaseNamespace.mergeAndPublish && !toReleaseNamespace.itemModifiedCnt)" ng-show="(toReleaseNamespace.isBranch && !toReleaseNamespace.mergeAndPublish && !toReleaseNamespace.itemModifiedCnt)"
valdr-form-group> valdr-form-group>
<label class="form-control-static"> <label class="form-control-static">
灰度配置没有变化 {{'Component.Publish.GrayItemNoChange' | translate }}
</label> </label>
</div> </div>
<div class="col-sm-5" <div class="col-sm-5"
ng-show="(toReleaseNamespace.isBranch && toReleaseNamespace.mergeAndPublish && toReleaseNamespace.branchItems.length == 0)" ng-show="(toReleaseNamespace.isBranch && toReleaseNamespace.mergeAndPublish && toReleaseNamespace.branchItems.length == 0)"
valdr-form-group> valdr-form-group>
<label class="form-control-static"> <label class="form-control-static">
没有灰度的配置项 {{'Component.Publish.NoGrayItems' | translate }}
</label> </label>
</div> </div>
...@@ -239,20 +239,18 @@ ...@@ -239,20 +239,18 @@
<div class="form-group"> <div class="form-group">
<label class="col-sm-2 control-label"> <label class="col-sm-2 control-label">
<apollorequiredfield></apollorequiredfield> <apollorequiredfield></apollorequiredfield>
Release Name</label> {{'Component.Publish.Release' | translate }}
</label>
<div class="col-sm-5" valdr-form-group> <div class="col-sm-5" valdr-form-group>
<input type="text" name="releaseName" class="form-control" <input type="text" name="releaseName" class="form-control" placeholder="input release name"
placeholder="input release name" ng-model="toReleaseNamespace.releaseTitle" ng-required="true">
ng-model="toReleaseNamespace.releaseTitle" ng-required="true">
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="col-sm-2 control-label">Comment</label> <label class="col-sm-2 control-label">{{'Component.Publish.ReleaseComment' | translate }}</label>
<div class="col-sm-10" valdr-form-group> <div class="col-sm-10" valdr-form-group>
<textarea rows="4" name="comment" class="form-control" <textarea rows="4" name="comment" class="form-control" style="margin-top: 15px;"
style="margin-top: 15px;" ng-model="releaseComment" placeholder="Add an optional extended description..."></textarea>
ng-model="releaseComment"
placeholder="Add an optional extended description..."></textarea>
</div> </div>
</div> </div>
...@@ -260,16 +258,14 @@ ...@@ -260,16 +258,14 @@
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button> <button type="button" class="btn btn-default"
data-dismiss="modal">{{'Common.Cancel' | translate }}</button>
<button type="submit" class="btn btn-primary" <button type="submit" class="btn btn-primary"
ng-disabled="releaseForm.$invalid || releaseBtnDisabled ng-disabled="releaseForm.$invalid || releaseBtnDisabled
|| (toReleaseNamespace.isBranch && toReleaseNamespace.mergeAndPublish && toReleaseNamespace.branchItems.length == 0)"> || (toReleaseNamespace.isBranch && toReleaseNamespace.mergeAndPublish && toReleaseNamespace.branchItems.length == 0)">
发布 {{'Component.Publish.OpPublish' | translate }}
</button> </button>
</div> </div>
</div> </div>
</div> </div>
</form> </form>
\ No newline at end of file
<form id="rollbackModal" class="modal fade form-horizontal" <form id="rollbackModal" class="modal fade form-horizontal" ng-submit="showRollbackAlertDialog()">
ng-submit="showRollbackAlertDialog()">
<div class="modal-dialog" role="document"> <div class="modal-dialog" role="document">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header panel-primary"> <div class="modal-header panel-primary">
...@@ -7,79 +6,82 @@ ...@@ -7,79 +6,82 @@
aria-hidden="true">&times;</span></button> aria-hidden="true">&times;</span></button>
<div class="modal-title text-center"> <div class="modal-title text-center">
<span style="font-size: 18px;" ng-bind="toRollbackNamespace.firstRelease.name"></span> <span style="font-size: 18px;" ng-bind="toRollbackNamespace.firstRelease.name"></span>
<span style="font-size: 18px;"> &nbsp;回滚到&nbsp;</span> <span style="font-size: 18px;"> &nbsp;{{'Component.Rollback.To' | translate }}&nbsp;</span>
<span style="font-size: 18px;" ng-bind="toRollbackNamespace.secondRelease.name"></span> <span style="font-size: 18px;" ng-bind="toRollbackNamespace.secondRelease.name"></span>
</div> </div>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div class="alert alert-warning" role="alert"> <div class="alert alert-warning" role="alert">
此操作将会回滚到上一个发布版本,且当前版本作废,但不影响正在修改的配置。可在发布历史页面查看当前生效的版本 {{'Component.Rollback.Tips' | translate }}
<a target="_blank" <a target="_blank"
href="/config/history.html?#/appid={{appId}}&env={{env}}&clusterName={{toRollbackNamespace.baseInfo.clusterName}}&namespaceName={{toRollbackNamespace.baseInfo.namespaceName}}">点击查看</a> href="/config/history.html?#/appid={{appId}}&env={{env}}&clusterName={{toRollbackNamespace.baseInfo.clusterName}}&namespaceName={{toRollbackNamespace.baseInfo.namespaceName}}">{{'Component.Rollback.ClickToView' | translate }}</a>
</div> </div>
<div class="form-group" style="margin-top: 15px;"> <div class="form-group" style="margin-top: 15px;">
<!--properties format--> <!--properties format-->
<div class="col-sm-12" <div class="col-sm-12"
ng-if="toRollbackNamespace.releaseCompareResult.length > 0 && toRollbackNamespace.isPropertiesFormat"> ng-if="toRollbackNamespace.releaseCompareResult.length > 0 && toRollbackNamespace.isPropertiesFormat">
<table class="table table-bordered table-striped text-center table-hover" <table class="table table-bordered table-striped text-center table-hover"
ng-if="toRollbackNamespace.isPropertiesFormat"> ng-if="toRollbackNamespace.isPropertiesFormat">
<thead> <thead>
<tr> <tr>
<th> <th>
Type {{'Component.Rollback.ItemType' | translate }}
</th> </th>
<th> <th>
Key {{'Component.Rollback.ItemKey' | translate }}
</th> </th>
<th> <th>
回滚前 {{'Component.Rollback.RollbackBeforeValue' | translate }}
</th> </th>
<th> <th>
回滚后 {{'Component.Rollback.RollbackAfterValue' | translate }}
</th> </th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr ng-repeat="change in toRollbackNamespace.releaseCompareResult"> <tr ng-repeat="change in toRollbackNamespace.releaseCompareResult">
<td width="10%"> <td width="10%">
<span ng-show="change.type == 'ADDED'">新增</span> <span
<span ng-show="change.type == 'MODIFIED'">更新</span> ng-show="change.type == 'ADDED'">{{'Component.Rollback.Added' | translate }}</span>
<span ng-show="change.type == 'DELETED'">删除</span> <span
</td> ng-show="change.type == 'MODIFIED'">{{'Component.Rollback.Modified' | translate }}</span>
<td width="20%" ng-bind="change.entity.firstEntity.key"> <span
ng-show="change.type == 'DELETED'">{{'Component.Rollback.Deleted' | translate }}</span>
</td>
<td width="20%" ng-bind="change.entity.firstEntity.key">
</td> </td>
<td width="35%" ng-bind="change.entity.firstEntity.value"> <td width="35%" ng-bind="change.entity.firstEntity.value">
</td> </td>
<td width="35%" ng-bind="change.entity.secondEntity.value"> <td width="35%" ng-bind="change.entity.secondEntity.value">
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>
<!--file format --> <!--file format -->
<div class="col-sm-12" <div class="col-sm-12"
ng-if="toRollbackNamespace.releaseCompareResult.length > 0 && !toRollbackNamespace.isPropertiesFormat"> ng-if="toRollbackNamespace.releaseCompareResult.length > 0 && !toRollbackNamespace.isPropertiesFormat">
<div ng-repeat="change in toRollbackNamespace.releaseCompareResult" <div ng-repeat="change in toRollbackNamespace.releaseCompareResult"
ng-if="!toRollbackNamespace.isPropertiesFormat"> ng-if="!toRollbackNamespace.isPropertiesFormat">
<h5>回滚前</h5> <h5>{{'Component.Rollback.RollbackBeforeValue' | translate }}</h5>
<textarea class="form-control no-radius" rows="20" <textarea class="form-control no-radius" rows="20" ng-disabled="true"
ng-disabled="true" ng-bind="change.entity.firstEntity.value"> ng-bind="change.entity.firstEntity.value">
</textarea> </textarea>
<hr> <hr>
<h5>回滚后</h5> <h5>{{'Component.Rollback.RollbackAfterValue' | translate }}</h5>
<textarea class="form-control no-radius" rows="20" <textarea class="form-control no-radius" rows="20" ng-disabled="true"
ng-disabled="true" ng-bind="change.entity.secondEntity.value"> ng-bind="change.entity.secondEntity.value">
</textarea> </textarea>
</div> </div>
</div> </div>
<div class="col-sm-12 text-center" ng-if="toRollbackNamespace.releaseCompareResult.length == 0"> <div class="col-sm-12 text-center" ng-if="toRollbackNamespace.releaseCompareResult.length == 0">
<h4> <h4>
配置没有变化 {{'Component.Rollback.NoChange' | translate }}
</h4> </h4>
</div> </div>
</div> </div>
...@@ -87,12 +89,13 @@ ...@@ -87,12 +89,13 @@
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button> <button type="button" class="btn btn-default"
data-dismiss="modal">{{'Common.Cancel' | translate }}</button>
<button type="submit" class="btn btn-danger" <button type="submit" class="btn btn-danger"
ng-disabled="toRollbackNamespace.rollbackBtnDisabled">回滚 ng-disabled="toRollbackNamespace.rollbackBtnDisabled">{{'Component.Rollback.OpRollback' | translate }}
</button> </button>
</div> </div>
</div> </div>
</div> </div>
</form> </form>
\ No newline at end of file
...@@ -5,14 +5,13 @@ ...@@ -5,14 +5,13 @@
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
aria-hidden="true">&times;</span></button> aria-hidden="true">&times;</span></button>
<h4 class="modal-title">查看</h4> <h4 class="modal-title">{{'Component.ShowText.Title' | translate }}</h4>
</div> </div>
<pre class="modal-body no-radius" style="margin-bottom: 0" <pre class="modal-body no-radius" style="margin-bottom: 0" ng-show="!jsonObject" ng-bind="text">
ng-show="!jsonObject" ng-bind="text">
</pre> </pre>
<pre class="modal-body no-radius" style="margin-bottom: 0" <pre class="modal-body no-radius" style="margin-bottom: 0" ng-show="jsonObject"
ng-show="jsonObject" ng-bind="jsonObject | json:4"> ng-bind="jsonObject | json:4">
</pre> </pre>
</div> </div>
</div> </div>
</div> </div>
\ No newline at end of file
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