Commit 670aaf5a by lepdou

sync item

parent 47c4cd25
...@@ -20,6 +20,7 @@ INSERT INTO AppNamespace (AppId, Name) VALUES ('100003173', 'fx.apollo.portal'); ...@@ -20,6 +20,7 @@ INSERT INTO AppNamespace (AppId, Name) VALUES ('100003173', 'fx.apollo.portal');
INSERT INTO AppNamespace (AppID, Name) VALUES ('fxhermesproducer', 'fx.hermes.producer'); INSERT INTO AppNamespace (AppID, Name) VALUES ('fxhermesproducer', 'fx.hermes.producer');
INSERT INTO Namespace (Id, AppId, ClusterName, NamespaceName) VALUES (1, '100003171', 'default', 'application'); INSERT INTO Namespace (Id, AppId, ClusterName, NamespaceName) VALUES (1, '100003171', 'default', 'application');
INSERT INTO Namespace (Id, AppId, ClusterName, NamespaceName) VALUES (5, '100003171', 'cluster1', 'application');
INSERT INTO Namespace (Id, AppId, ClusterName, NamespaceName) VALUES (2, 'fxhermesproducer', 'default', 'fx.hermes.producer'); INSERT INTO Namespace (Id, AppId, ClusterName, NamespaceName) VALUES (2, 'fxhermesproducer', 'default', 'fx.hermes.producer');
INSERT INTO Namespace (Id, AppId, ClusterName, NamespaceName) VALUES (3, '100003172', 'default', 'application'); INSERT INTO Namespace (Id, AppId, ClusterName, NamespaceName) VALUES (3, '100003172', 'default', 'application');
INSERT INTO Namespace (Id, AppId, ClusterName, NamespaceName) VALUES (4, '100003173', 'default', 'application'); INSERT INTO Namespace (Id, AppId, ClusterName, NamespaceName) VALUES (4, '100003173', 'default', 'application');
...@@ -27,7 +28,7 @@ INSERT INTO Namespace (Id, AppId, ClusterName, NamespaceName) VALUES (4, '100003 ...@@ -27,7 +28,7 @@ INSERT INTO Namespace (Id, AppId, ClusterName, NamespaceName) VALUES (4, '100003
INSERT INTO Item (NamespaceId, `Key`, Value, Comment) VALUES (1, 'k1', 'v1', 'comment1'); INSERT INTO Item (NamespaceId, `Key`, Value, Comment) VALUES (1, 'k1', 'v1', 'comment1');
INSERT INTO Item (NamespaceId, `Key`, Value, Comment) VALUES (1, 'k2', 'v2', 'comment2'); INSERT INTO Item (NamespaceId, `Key`, Value, Comment) VALUES (1, 'k2', 'v2', 'comment2');
INSERT INTO Item (NamespaceId, `Key`, Value, Comment) VALUES (2, 'k3', 'v3', 'comment3'); INSERT INTO Item (NamespaceId, `Key`, Value, Comment) VALUES (2, 'k3', 'v3', 'comment3');
INSERT INTO Item (NamespaceId, `Key`, Value, Comment) VALUES (5, 'k3', 'v4', 'comment4'); INSERT INTO Item (NamespaceId, `Key`, Value, Comment, LineNum) VALUES (5, 'k1', 'v4', 'comment4',1);
INSERT INTO RELEASE (ReleaseKey, Name, Comment, AppId, ClusterName, NamespaceName, Configurations) VALUES ('TEST-RELEASE-KEY', 'REV1','First Release','100003171', 'default', 'application', '{"k1":"v1"}'); INSERT INTO RELEASE (ReleaseKey, Name, Comment, AppId, ClusterName, NamespaceName, Configurations) VALUES ('TEST-RELEASE-KEY', 'REV1','First Release','100003171', 'default', 'application', '{"k1":"v1"}');
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>
<build> <build>
<plugins> <plugins>
<plugin> <plugin>
......
...@@ -14,6 +14,8 @@ import com.ctrip.apollo.portal.entity.form.NamespaceReleaseModel; ...@@ -14,6 +14,8 @@ import com.ctrip.apollo.portal.entity.form.NamespaceReleaseModel;
import com.ctrip.apollo.portal.service.ConfigService; import com.ctrip.apollo.portal.service.ConfigService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
...@@ -102,7 +104,20 @@ public class ConfigController { ...@@ -102,7 +104,20 @@ public class ConfigController {
throw new BadRequestException("request model is invalid"); throw new BadRequestException("request model is invalid");
} }
return configService.compare(model.getSyncItems(), model.getSyncToNamespaces()); return configService.compare(model.getSyncToNamespaces(), model.getSyncItems());
}
@RequestMapping(value = "/namespaces/{namespaceName}/items", method = RequestMethod.PUT, consumes = {
"application/json"})
public ResponseEntity<Void> update(@RequestBody NamespaceSyncModel model){
if (model == null){
throw new BadRequestException("request payload shoud not be null");
}
if (model.isInvalid()) {
throw new BadRequestException("request model is invalid");
}
configService.syncItems(model.getSyncToNamespaces(), model.getSyncItems());
return ResponseEntity.status(HttpStatus.OK).build();
} }
} }
...@@ -47,4 +47,14 @@ public class NamespaceIdentifer implements Verifiable{ ...@@ -47,4 +47,14 @@ public class NamespaceIdentifer implements Verifiable{
public boolean isInvalid() { public boolean isInvalid() {
return StringUtils.isContainEmpty(env, clusterName, namespaceName); return StringUtils.isContainEmpty(env, clusterName, namespaceName);
} }
@Override
public String toString() {
return "NamespaceIdentifer{" +
"appId='" + appId + '\'' +
", env='" + env + '\'' +
", clusterName='" + clusterName + '\'' +
", namespaceName='" + namespaceName + '\'' +
'}';
}
} }
...@@ -54,11 +54,6 @@ public class ConfigService { ...@@ -54,11 +54,6 @@ public class ConfigService {
/** /**
* load cluster all namespace info with items * load cluster all namespace info with items
*
* @param appId
* @param env
* @param clusterName
* @return
*/ */
public List<NamespaceVO> findNampspaces(String appId, Env env, String clusterName) { public List<NamespaceVO> findNampspaces(String appId, Env env, String clusterName) {
...@@ -76,7 +71,7 @@ public class ConfigService { ...@@ -76,7 +71,7 @@ public class ConfigService {
namespaceVOs.add(namespaceVO); namespaceVOs.add(namespaceVO);
} catch (Exception e) { } catch (Exception e) {
logger.error("parse namespace error. app id:{}, env:{}, clusterName:{}, namespace:{}", logger.error("parse namespace error. app id:{}, env:{}, clusterName:{}, namespace:{}",
appId, env, clusterName, namespace.getNamespaceName(), e); appId, env, clusterName, namespace.getNamespaceName(), e);
throw e; throw e;
} }
} }
...@@ -85,7 +80,7 @@ public class ConfigService { ...@@ -85,7 +80,7 @@ public class ConfigService {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private NamespaceVO parseNamespace(String appId, Env env, String clusterName, NamespaceDTO namespace) { private NamespaceVO parseNamespace(String appId, Env env, String clusterName, NamespaceDTO namespace) {
NamespaceVO namespaceVO = new NamespaceVO(); NamespaceVO namespaceVO = new NamespaceVO();
namespaceVO.setNamespace(namespace); namespaceVO.setNamespace(namespace);
...@@ -100,10 +95,10 @@ public class ConfigService { ...@@ -100,10 +95,10 @@ public class ConfigService {
try { try {
release = releaseAPI.loadLatestRelease(appId, env, clusterName, namespaceName); release = releaseAPI.loadLatestRelease(appId, env, clusterName, namespaceName);
releaseItems = gson.fromJson(release.getConfigurations(), Map.class); releaseItems = gson.fromJson(release.getConfigurations(), Map.class);
}catch (HttpClientErrorException e){ } catch (HttpClientErrorException e) {
if (e.getStatusCode() == HttpStatus.NOT_FOUND){ if (e.getStatusCode() == HttpStatus.NOT_FOUND) {
logger.warn(ExceptionUtils.toString(e)); logger.warn(ExceptionUtils.toString(e));
}else { } else {
throw e; throw e;
} }
} }
...@@ -142,7 +137,7 @@ public class ConfigService { ...@@ -142,7 +137,7 @@ public class ConfigService {
/** /**
* parse config text and update config items * parse config text and update config items
* *
* @return parse result * @return parse result
*/ */
public void updateConfigItemByText(NamespaceTextModel model) { public void updateConfigItemByText(NamespaceTextModel model) {
...@@ -154,8 +149,8 @@ public class ConfigService { ...@@ -154,8 +149,8 @@ public class ConfigService {
String configText = model.getConfigText(); String configText = model.getConfigText();
ItemChangeSets changeSets = resolver.resolve(namespaceId, configText, ItemChangeSets changeSets = resolver.resolve(namespaceId, configText,
itemAPI.findItems(appId, env, clusterName, namespaceName)); itemAPI.findItems(appId, env, clusterName, namespaceName));
if (changeSets.isEmpty()){ if (changeSets.isEmpty()) {
return; return;
} }
try { try {
...@@ -171,85 +166,107 @@ public class ConfigService { ...@@ -171,85 +166,107 @@ public class ConfigService {
/** /**
* createRelease config items * createRelease config items
*
* @return
*/ */
public ReleaseDTO createRelease(NamespaceReleaseModel model) { public ReleaseDTO createRelease(NamespaceReleaseModel model) {
return releaseAPI.release(model.getAppId(), model.getEnv(), model.getClusterName(), return releaseAPI.release(model.getAppId(), model.getEnv(), model.getClusterName(),
model.getNamespaceName(), model.getReleaseBy(), model.getReleaseComment()); model.getNamespaceName(), model.getReleaseBy(), model.getReleaseComment());
} }
public List<ItemDTO> findItems(String appId, Env env, String clusterName, String namespaceName){ public List<ItemDTO> findItems(String appId, Env env, String clusterName, String namespaceName) {
return itemAPI.findItems(appId, env, clusterName, namespaceName); return itemAPI.findItems(appId, env, clusterName, namespaceName);
} }
public List<ItemDiffs> compare(List<ItemDTO> sourceItems, List<NamespaceIdentifer> comparedNamespaces){ public void syncItems(List<NamespaceIdentifer> comparedNamespaces, List<ItemDTO> sourceItems){
List<ItemDiffs> itemDiffs = compare(comparedNamespaces, sourceItems);
for (ItemDiffs itemDiff: itemDiffs){
NamespaceIdentifer namespaceIdentifer = itemDiff.getNamespace();
try {
itemAPI
.updateItems(namespaceIdentifer.getAppId(), namespaceIdentifer.getEnv(),
namespaceIdentifer.getClusterName(),
namespaceIdentifer.getNamespaceName(), itemDiff.getDiffs());
} catch (HttpClientErrorException e) {
logger.error("sync items error. namespace:{}", namespaceIdentifer);
throw new ServiceException(String.format("sync item error. env:%s, clusterName:%s", namespaceIdentifer.getEnv(),
namespaceIdentifer.getClusterName()), e);
}
}
}
public List<ItemDiffs> compare(List<NamespaceIdentifer> comparedNamespaces, List<ItemDTO> sourceItems) {
List<ItemDiffs> result = new LinkedList<>(); List<ItemDiffs> result = new LinkedList<>();
String appId, clusterName, namespaceName; for (NamespaceIdentifer namespace : comparedNamespaces) {
Env env;
for (NamespaceIdentifer namespace: comparedNamespaces){
appId = namespace.getAppId();
clusterName = namespace.getClusterName();
namespaceName = namespace.getNamespaceName();
env = namespace.getEnv();
NamespaceDTO namespaceDTO = null;
try {
namespaceDTO = namespaceAPI.loadNamespace(appId, env, clusterName, namespaceName);
} catch (NotFoundException e){
logger.warn("namespace not exist. appId:{}, env:{}, clusterName:{}, namespaceName:{}", appId, env, clusterName,
namespaceName);
throw new BadRequestException(String.format(
"namespace not exist. appId:%s, env:%s, clusterName:%s, namespaceName:%s", appId, env, clusterName,
namespaceName));
}
ItemDiffs itemDiffs = new ItemDiffs(namespace); ItemDiffs itemDiffs = new ItemDiffs(namespace);
ItemChangeSets changeSets = new ItemChangeSets(); itemDiffs.setDiffs(parseChangeSets(namespace, sourceItems));
itemDiffs.setDiffs(changeSets);
List<ItemDTO>
targetItems =
itemAPI.findItems(namespace.getAppId(), namespace.getEnv(),
namespace.getClusterName(), namespace.getNamespaceName());
long namespaceId = namespaceDTO.getId();
if (CollectionUtils.isEmpty(targetItems)){//all source items is added
int lineNum = 1;
for (ItemDTO sourceItem: sourceItems){
changeSets.addCreateItem(buildItem(namespaceId, lineNum++, sourceItem));
}
}else {
Map<String, ItemDTO> keyMapItem = BeanUtils.mapByKey("key", targetItems);
String key,sourceValue,sourceComment;
ItemDTO targetItem = null;
int maxLineNum = targetItems.size();//append to last
for (ItemDTO sourceItem: sourceItems){
key = sourceItem.getKey();
sourceValue = sourceItem.getValue();
sourceComment = sourceItem.getComment();
targetItem = keyMapItem.get(key);
if (targetItem == null) {//added items
changeSets.addCreateItem(buildItem(namespaceId, ++maxLineNum, sourceItem));
}else if (!sourceValue.equals(targetItem.getValue()) || !sourceComment.equals(targetItem.getComment())){//modified items
targetItem.setValue(sourceValue);
targetItem.setComment(sourceComment);
changeSets.addUpdateItem(targetItem);
}
}
}
result.add(itemDiffs); result.add(itemDiffs);
} }
return result; return result;
} }
private ItemDTO buildItem(long namespaceId, int lineNum, ItemDTO sourceItem){ private long getNamespaceId(NamespaceIdentifer namespaceIdentifer) {
String appId = namespaceIdentifer.getAppId();
String clusterName = namespaceIdentifer.getClusterName();
String namespaceName = namespaceIdentifer.getNamespaceName();
Env env = namespaceIdentifer.getEnv();
NamespaceDTO namespaceDTO = null;
try {
namespaceDTO = namespaceAPI.loadNamespace(appId, env, clusterName, namespaceName);
} catch (NotFoundException e) {
logger.warn("namespace not exist. appId:{}, env:{}, clusterName:{}, namespaceName:{}", appId, env, clusterName,
namespaceName);
throw new BadRequestException(String.format(
"namespace not exist. appId:%s, env:%s, clusterName:%s, namespaceName:%s", appId, env, clusterName,
namespaceName));
}
return namespaceDTO.getId();
}
private ItemChangeSets parseChangeSets(NamespaceIdentifer namespace, List<ItemDTO> sourceItems){
ItemChangeSets changeSets = new ItemChangeSets();
List<ItemDTO>
targetItems =
itemAPI.findItems(namespace.getAppId(), namespace.getEnv(),
namespace.getClusterName(), namespace.getNamespaceName());
long namespaceId = getNamespaceId(namespace);
if (CollectionUtils.isEmpty(targetItems)) {//all source items is added
int lineNum = 1;
for (ItemDTO sourceItem : sourceItems) {
changeSets.addCreateItem(buildItem(namespaceId, lineNum++, sourceItem));
}
} else {
Map<String, ItemDTO> keyMapItem = BeanUtils.mapByKey("key", targetItems);
String key, sourceValue, sourceComment;
ItemDTO targetItem = null;
int maxLineNum = targetItems.size();//append to last
for (ItemDTO sourceItem : sourceItems) {
key = sourceItem.getKey();
sourceValue = sourceItem.getValue();
sourceComment = sourceItem.getComment();
targetItem = keyMapItem.get(key);
if (targetItem == null) {//added items
changeSets.addCreateItem(buildItem(namespaceId, ++maxLineNum, sourceItem));
} else if (!sourceValue.equals(targetItem.getValue()) || !sourceComment
.equals(targetItem.getComment())) {//modified items
targetItem.setValue(sourceValue);
targetItem.setComment(sourceComment);
changeSets.addUpdateItem(targetItem);
}
}
}
return changeSets;
}
private ItemDTO buildItem(long namespaceId, int lineNum, ItemDTO sourceItem) {
ItemDTO createdItem = new ItemDTO(); ItemDTO createdItem = new ItemDTO();
BeanUtils.copyEntityProperties(sourceItem, createdItem); BeanUtils.copyEntityProperties(sourceItem, createdItem);
createdItem.setLineNum(lineNum++); createdItem.setLineNum(lineNum++);
......
...@@ -12,7 +12,7 @@ appUtil.service('AppUtil', [function () { ...@@ -12,7 +12,7 @@ appUtil.service('AppUtil', [function () {
if (!path) { if (!path) {
return {}; return {};
} }
if (path.startsWith("/")) { if (path.indexOf('/') == 0) {
path = path.substring(1, path.length); path = path.substring(1, path.length);
} }
var params = path.split("&"); var params = path.split("&");
......
sync_item_module.controller("SyncItemController", sync_item_module.controller("SyncItemController",
['$scope', '$location', 'toastr', 'AppService', 'AppUtil', 'ConfigService', ['$scope', '$location', '$window', 'toastr', 'AppService', 'AppUtil', 'ConfigService',
function ($scope, $location, toastr, AppService, AppUtil, ConfigService) { function ($scope, $location, $window, toastr, AppService, AppUtil, ConfigService) {
var params = AppUtil.parseParams($location.$$url); var params = AppUtil.parseParams($location.$$url);
var currentUser = 'test_user'; var currentUser = 'test_user';
...@@ -13,15 +13,16 @@ sync_item_module.controller("SyncItemController", ...@@ -13,15 +13,16 @@ sync_item_module.controller("SyncItemController",
////// load env ////// ////// load env //////
AppService.load_nav_tree($scope.pageContext.appId).then(function (result) { AppService.load_nav_tree($scope.pageContext.appId).then(function (result) {
$scope.clusters = result.nodes; $scope.namespaceIdentifers = [];
$scope.clusters = [];
result.nodes.forEach(function (node) { result.nodes.forEach(function (node) {
var env = node.env; var env = node.env;
node.clusters.forEach(function (cluster) { node.clusters.forEach(function (cluster) {
cluster.env = env; cluster.env = env;
cluster.checked = false; cluster.checked = false;
$scope.clusters.push(cluster); if (env != $scope.pageContext.env || cluster.name != $scope.pageContext.clusterName){
}) $scope.namespaceIdentifers.push(cluster);
}
})
}); });
}, function (result) { }, function (result) {
toastr.error(AppUtil.errorMsg(result), "加载环境出错"); toastr.error(AppUtil.errorMsg(result), "加载环境出错");
...@@ -30,8 +31,8 @@ sync_item_module.controller("SyncItemController", ...@@ -30,8 +31,8 @@ sync_item_module.controller("SyncItemController",
var envAllSelected = false; var envAllSelected = false;
$scope.toggleEnvsCheckedStatus = function () { $scope.toggleEnvsCheckedStatus = function () {
envAllSelected = !envAllSelected; envAllSelected = !envAllSelected;
$scope.clusters.forEach(function (cluster) { $scope.namespaceIdentifers.forEach(function (namespaceIdentifer) {
cluster.checked = envAllSelected; namespaceIdentifer.checked = envAllSelected;
}) })
}; };
...@@ -39,9 +40,12 @@ sync_item_module.controller("SyncItemController", ...@@ -39,9 +40,12 @@ sync_item_module.controller("SyncItemController",
ConfigService.find_items($scope.pageContext.appId, $scope.pageContext.env, ConfigService.find_items($scope.pageContext.appId, $scope.pageContext.env,
$scope.pageContext.clusterName, $scope.pageContext.namespaceName).then(function (result) { $scope.pageContext.clusterName, $scope.pageContext.namespaceName).then(function (result) {
$scope.sourceItems = result; $scope.sourceItems = [];
$scope.sourceItems.forEach(function (item) { result.forEach(function (item) {
item.checked = false; if (item.key){
item.checked = false;
$scope.sourceItems.push(item);
}
}) })
}, function (result) { }, function (result) {
...@@ -56,6 +60,44 @@ sync_item_module.controller("SyncItemController", ...@@ -56,6 +60,44 @@ sync_item_module.controller("SyncItemController",
}) })
}; };
$scope.diff = function () {
ConfigService.diff($scope.pageContext.namespaceName, parseSyncSourceData()).then(function (result) {
$scope.diffs = result;
$scope.syncItemNextStep(1);
}, function (result) {
toastr.error(AppUtil.errorMsg(result));
});
};
$scope.syncItems = function () {
ConfigService.sync_items($scope.pageContext.namespaceName, parseSyncSourceData()).then(function (result) {
$scope.syncItemStep += 1;
}, function (result) {
toastr.error(AppUtil.errorMsg(result));
});
};
function parseSyncSourceData() {
var sourceData = {
syncToNamespaces: [],
syncItems: []
};
var namespaceName = $scope.pageContext.namespaceName;
$scope.namespaceIdentifers.forEach(function (namespaceIdentifer) {
if (namespaceIdentifer.checked){
namespaceIdentifer.clusterName = namespaceIdentifer.name;
namespaceIdentifer.namespaceName = namespaceName;
sourceData.syncToNamespaces.push(namespaceIdentifer);
}
});
$scope.sourceItems.forEach(function (item) {
if (item.checked) {
sourceData.syncItems.push(item);
}
});
return sourceData;
}
////// flow control /////// ////// flow control ///////
$scope.syncItemStep = 1; $scope.syncItemStep = 1;
...@@ -63,14 +105,12 @@ sync_item_module.controller("SyncItemController", ...@@ -63,14 +105,12 @@ sync_item_module.controller("SyncItemController",
$scope.syncItemStep += offset; $scope.syncItemStep += offset;
}; };
$scope.syncItems = function () { $scope.return = function () {
$scope.syncItemStep += 1; $window.location.href = '/views/app.html?#appid=' + $scope.pageContext.appId;
}; };
$scope.destorySync = function () { $scope.switchSelect = function (o) {
$scope.syncItemStep = 1; o.checked = !o.checked;
} }
}]); }]);
...@@ -17,6 +17,16 @@ appService.service("ConfigService", ['$resource', '$q', function ($resource, $q) ...@@ -17,6 +17,16 @@ appService.service("ConfigService", ['$resource', '$q', function ($resource, $q)
release: { release: {
method: 'POST', method: 'POST',
url:'/apps/:appId/env/:env/clusters/:clusterName/namespaces/:namespaceName/release' url:'/apps/:appId/env/:env/clusters/:clusterName/namespaces/:namespaceName/release'
},
diff: {
method: 'POST',
url: '/namespaces/:namespaceName/diff',
isArray: true
},
sync_item: {
method: 'PUT',
url: '/namespaces/:namespaceName/items',
isArray: false
} }
}); });
...@@ -87,6 +97,30 @@ appService.service("ConfigService", ['$resource', '$q', function ($resource, $q) ...@@ -87,6 +97,30 @@ appService.service("ConfigService", ['$resource', '$q', function ($resource, $q)
d.reject(result); d.reject(result);
}); });
return d.promise; return d.promise;
},
diff: function (namespaceName, sourceData) {
var d = $q.defer();
config_source.diff({
namespaceName: namespaceName
}, sourceData, function (result) {
d.resolve(result);
}, function (result) {
d.reject(result);
});
return d.promise;
},
sync_items: function (namespaceName, sourceData) {
var d = $q.defer();
config_source.sync_item({
namespaceName: namespaceName
}, sourceData, function (result) {
d.resolve(result);
}, function (result) {
d.reject(result);
});
return d.promise;
} }
} }
......
...@@ -65,14 +65,6 @@ ...@@ -65,14 +65,6 @@
</div> </div>
</section> </section>
<a class="list-group-item" data-toggle="modal" data-target="#syncItems">
<div class="row">
<div class="col-md-2"><img src="../img/sync.png" class="i-20"></div>
<div class="col-md-7 hidden-xs">
<p class="apps-description">配置同步</p>
</div>
</div>
</a>
<a class="list-group-item" data-toggle="modal" data-target="#createEnvModal" <a class="list-group-item" data-toggle="modal" data-target="#createEnvModal"
ng-show="missEnvs.length > 0"> ng-show="missEnvs.length > 0">
<div class="row"> <div class="row">
......
...@@ -29,12 +29,12 @@ ...@@ -29,12 +29,12 @@
ng-click="syncItemNextStep(-1)">上一步 ng-click="syncItemNextStep(-1)">上一步
</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="syncItemNextStep(1)">下一步 ng-click="diff()">下一步
</button> </button>
<button type="button" class="btn btn-success" ng-show="syncItemStep == 2" ng-click="syncItems()">同步 <button type="button" class="btn btn-success" ng-show="syncItemStep == 2" ng-click="syncItems()">同步
</button> </button>
<button type="button" class="btn btn-primary" data-dismiss="modal" ng-show="syncItemStep == 3" <button type="button" class="btn btn-primary" data-dismiss="modal" ng-show="syncItemStep == 3"
ng-click="destorySync()">返回 ng-click="return()">返回
</button> </button>
</div> </div>
</div> </div>
...@@ -55,10 +55,11 @@ ...@@ -55,10 +55,11 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr ng-repeat="cluster in clusters"> <tr ng-repeat="namespaceIdentifer in namespaceIdentifers">
<td width="10%"><input type="checkbox" ng-checked="cluster.checked"></td> <td width="10%"><input type="checkbox" ng-checked="namespaceIdentifer.checked"
<td width="30%">{{cluster.env}}</td> ng-click="switchSelect(namespaceIdentifer)"></td>
<td width="60%">{{cluster.name}}</td> <td width="30%">{{namespaceIdentifer.env}}</td>
<td width="60%">{{namespaceIdentifer.name}}</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
...@@ -85,10 +86,14 @@ ...@@ -85,10 +86,14 @@
</thead> </thead>
<tbody> <tbody>
<tr ng-repeat="item in sourceItems"> <tr ng-repeat="item in sourceItems">
<td width="10%"><input type="checkbox" ng-checked="item.checked"></td> <td width="10%"><input type="checkbox" ng-checked="item.checked"
ng-click="switchSelect(item)"></td>
<td width="20%">{{item.key}}</td> <td width="20%">{{item.key}}</td>
<td width="50%">{{item.value | limitTo: 36}} {{item.value.length > 36 ? '...' : ''}}</td> <td width="50%">{{item.value | limitTo: 36}} {{item.value.length > 36 ? '...' : ''}}
<td width="20%">{{item.comment | limitTo: 15}}{{item.comment.length > 15 ? '...' : ''}}</td> </td>
<td width="20%">{{item.comment | limitTo: 15}}{{item.comment.length > 15 ? '...' :
''}}
</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
...@@ -99,28 +104,29 @@ ...@@ -99,28 +104,29 @@
</div> </div>
<!--step 2--> <!--step 2-->
<div class="row" ng-show="syncItemStep == 2"> <div class="row" ng-show="syncItemStep == 2" ng-repeat="diff in diffs">
<h4 class="text-center">环境:fat 集群:default</h4> <h4 class="text-center">环境:{{diff.namespace.env}} 集群:{{diff.namespace.clusterName}}</h4>
<hr> <hr>
<div class="row" style="margin-top: 10px;"> <div class="row text-center" style="margin-top: 10px;" ng-show="diff.diffs.createItems.length == 0 && diff.diffs.updateItems.length == 0">
<h5>无更新的配置</h5>
</div>
<div class="row" style="margin-top: 10px;" ng-show="diff.diffs.createItems.length > 0">
<div class="form-horizontal"> <div class="form-horizontal">
<label class="col-sm-2 control-label">新增的配置</label> <label class="col-sm-2 control-label">新增的配置</label>
<div class="col-sm-9"> <div class="col-sm-9">
<table class="table table-bordered table-hover"> <table class="table table-bordered table-striped table-hover">
<thead> <thead>
<tr> <tr>
<td>key</td> <td>key</td>
<td>value</td> <td>value</td>
<td>comment</td>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr> <tr ng-repeat="createItem in diff.diffs.createItems">
<td width="30%">k1</td> <td width="30%">{{createItem.key}}</td>
<td width="60%">v1</td> <td width="40%">{{createItem.value}}</td>
</tr> <td width="30%">{{createItem.comment}}</td>
<tr>
<td width="30%">k1</td>
<td width="60%">v1</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
...@@ -128,33 +134,28 @@ ...@@ -128,33 +134,28 @@
</div> </div>
</div> </div>
</div> </div>
<div class="row" ng-show="syncItemStep == 2"> <div class="row" style="margin-top: 10px;" ng-show="diff.diffs.updateItems.length > 0">
<div class="row" style="margin-top: 10px;"> <div class="form-horizontal">
<div class="form-horizontal"> <label class="col-sm-2 control-label">更新的配置</label>
<label class="col-sm-2 control-label">更新的配置</label> <div class="col-sm-9">
<div class="col-sm-9"> <table class="table table-bordered table-striped table-hover">
<table class="table table-bordered table-striped table-hover"> <thead>
<thead> <tr>
<tr> <td>key</td>
<td>key</td> <td>value</td>
<td>value</td> <td>comment</td>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr> <tr ng-repeat="updateItem in diff.diffs.updateItems">
<td width="30%">k1</td> <td width="30%">{{updateItem.key}}</td>
<td width="60%">v1</td> <td width="40%">{{updateItem.value}}</td>
</tr> <td width="30%">{{updateItem.comment}}</td>
<tr> </tr>
<td width="30%">k1</td> </tbody>
<td width="60%">v1</td> </table>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -143,7 +143,7 @@ public class ConfigServiceTest { ...@@ -143,7 +143,7 @@ public class ConfigServiceTest {
when(namespaceAPI.loadNamespace(appId, Env.valueOf(env), clusterName, namespaceName)).thenReturn(namespaceDTO); when(namespaceAPI.loadNamespace(appId, Env.valueOf(env), clusterName, namespaceName)).thenReturn(namespaceDTO);
when(itemAPI.findItems(appId, Env.valueOf(env), clusterName, namespaceName)).thenReturn(null); when(itemAPI.findItems(appId, Env.valueOf(env), clusterName, namespaceName)).thenReturn(null);
List<ItemDiffs> itemDiffses = configService.compare(sourceItems, namespaceIdentifers); List<ItemDiffs> itemDiffses = configService.compare(namespaceIdentifers, sourceItems);
assertEquals(1,itemDiffses.size()); assertEquals(1,itemDiffses.size());
ItemDiffs itemDiffs = itemDiffses.get(0); ItemDiffs itemDiffs = itemDiffses.get(0);
...@@ -180,7 +180,7 @@ public class ConfigServiceTest { ...@@ -180,7 +180,7 @@ public class ConfigServiceTest {
when(namespaceAPI.loadNamespace(appId, Env.valueOf(env), clusterName, namespaceName)).thenReturn(namespaceDTO); when(namespaceAPI.loadNamespace(appId, Env.valueOf(env), clusterName, namespaceName)).thenReturn(namespaceDTO);
when(itemAPI.findItems(appId, Env.valueOf(env), clusterName, namespaceName)).thenReturn(targetItems); when(itemAPI.findItems(appId, Env.valueOf(env), clusterName, namespaceName)).thenReturn(targetItems);
List<ItemDiffs> itemDiffses = configService.compare(sourceItems, namespaceIdentifers); List<ItemDiffs> itemDiffses = configService.compare(namespaceIdentifers, sourceItems);
assertEquals(1, itemDiffses.size()); assertEquals(1, itemDiffses.size());
ItemDiffs itemDiffs = itemDiffses.get(0); ItemDiffs itemDiffs = itemDiffses.get(0);
......
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