Commit 26cb8582 by lepdou

portal v2

parent 11e8b799
...@@ -8,10 +8,12 @@ import org.springframework.web.bind.annotation.RequestMapping; ...@@ -8,10 +8,12 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import com.ctrip.apollo.biz.entity.Release; import com.ctrip.apollo.biz.entity.Release;
import com.ctrip.apollo.biz.service.ConfigService;
import com.ctrip.apollo.biz.service.ReleaseService; import com.ctrip.apollo.biz.service.ReleaseService;
import com.ctrip.apollo.biz.service.ViewService; import com.ctrip.apollo.biz.service.ViewService;
import com.ctrip.apollo.biz.utils.BeanUtils; import com.ctrip.apollo.biz.utils.BeanUtils;
import com.ctrip.apollo.core.dto.ReleaseDTO; import com.ctrip.apollo.core.dto.ReleaseDTO;
import com.ctrip.apollo.core.utils.StringUtils;
@RestController @RestController
public class ReleaseController { public class ReleaseController {
...@@ -22,6 +24,9 @@ public class ReleaseController { ...@@ -22,6 +24,9 @@ public class ReleaseController {
@Autowired @Autowired
private ReleaseService releaseService; private ReleaseService releaseService;
@Autowired
private ConfigService configService;
@RequestMapping("/release/{releaseId}") @RequestMapping("/release/{releaseId}")
public ReleaseDTO findOne(@PathVariable("releaseId") long releaseId) { public ReleaseDTO findOne(@PathVariable("releaseId") long releaseId) {
Release release = releaseService.findOne(releaseId); Release release = releaseService.findOne(releaseId);
...@@ -35,4 +40,16 @@ public class ReleaseController { ...@@ -35,4 +40,16 @@ public class ReleaseController {
List<Release> releases = viewSerivce.findReleases(appId, clusterName, namespaceName); List<Release> releases = viewSerivce.findReleases(appId, clusterName, namespaceName);
return BeanUtils.batchTransform(ReleaseDTO.class, releases); return BeanUtils.batchTransform(ReleaseDTO.class, releases);
} }
@RequestMapping("/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/releases/latest")
public ReleaseDTO findLatestRelease(@PathVariable("appId") String appId,
@PathVariable("clusterName") String clusterName,
@PathVariable("namespaceName") String namespaceName){
if (StringUtils.isContainEmpty(appId, clusterName, namespaceName)){
return null;
}
Release release = configService.findRelease(appId, clusterName, namespaceName);
return BeanUtils.transfrom(ReleaseDTO.class, release);
}
} }
...@@ -43,7 +43,10 @@ public class BeanUtils { ...@@ -43,7 +43,10 @@ public class BeanUtils {
* return BeanUtil.transform(UserDTO.class, userBean); * return BeanUtil.transform(UserDTO.class, userBean);
* </pre> * </pre>
*/ */
public static <T> T transfrom(Class<T> clazz, Object src) { public static <T> T transfrom(Class<T> clazz, Object src) {
if (src == null){
return null;
}
T instance = null; T instance = null;
try { try {
instance = clazz.newInstance(); instance = clazz.newInstance();
......
...@@ -2,3 +2,4 @@ spring.datasource.url = jdbc:h2:mem:~/fxapolloconfigdb;mode=mysql ...@@ -2,3 +2,4 @@ spring.datasource.url = jdbc:h2:mem:~/fxapolloconfigdb;mode=mysql
spring.jpa.hibernate.naming_strategy=org.hibernate.cfg.EJB3NamingStrategy spring.jpa.hibernate.naming_strategy=org.hibernate.cfg.EJB3NamingStrategy
spring.h2.console.enabled = true spring.h2.console.enabled = true
spring.h2.console.settings.web-allow-others=true spring.h2.console.settings.web-allow-others=true
...@@ -31,6 +31,20 @@ public class StringUtils { ...@@ -31,6 +31,20 @@ public class StringUtils {
return str == null || str.length() == 0; return str == null || str.length() == 0;
} }
public static boolean isContainEmpty(String... args){
if (args == null){
return false;
}
for (String arg: args){
if (arg == null || "".equals(arg)){
return true;
}
}
return false;
}
/** /**
* <p> * <p>
* Checks if a String is whitespace, empty ("") or null. * Checks if a String is whitespace, empty ("") or null.
......
package com.ctrip.apollo.portal.api; package com.ctrip.apollo.portal.api;
import com.google.common.base.Strings;
import com.ctrip.apollo.Apollo; import com.ctrip.apollo.Apollo;
import com.ctrip.apollo.core.dto.AppDTO; import com.ctrip.apollo.core.dto.AppDTO;
import com.ctrip.apollo.core.dto.ClusterDTO; import com.ctrip.apollo.core.dto.ClusterDTO;
import com.ctrip.apollo.core.dto.ItemDTO; import com.ctrip.apollo.core.dto.ItemDTO;
import com.ctrip.apollo.core.dto.NamespaceDTO;
import com.ctrip.apollo.core.dto.ReleaseDTO; import com.ctrip.apollo.core.dto.ReleaseDTO;
import com.ctrip.apollo.core.utils.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.List;
@Service @Service
public class AdminServiceAPI { public class AdminServiceAPI {
...@@ -24,45 +24,61 @@ public class AdminServiceAPI { ...@@ -24,45 +24,61 @@ public class AdminServiceAPI {
} }
} }
@Service @Service
public static class ConfigAPI extends API { public static class NamespaceAPI extends API {
public static String CONFIG_RELEASE_API = "/configs/release/";
public ReleaseDTO[] getConfigByReleaseId(Apollo.Env env, long releaseId) { public NamespaceDTO[] findGroupsByAppAndCluster(String appId, Apollo.Env env,
if (releaseId <= 0) { String clusterName) {
if (StringUtils.isContainEmpty(appId, clusterName)) {
return null; return null;
} }
return restTemplate.getForObject(getAdminServiceHost(env) + CONFIG_RELEASE_API + releaseId, return restTemplate.getForObject(
ReleaseDTO[].class); getAdminServiceHost(env) + String.format("apps/%s/clusters/%s/namespaces", appId, clusterName),
NamespaceDTO[].class);
} }
}
@Service
public static class ItemAPI extends API {
public ItemDTO[] getLatestConfigItemsByClusters(Apollo.Env env, List<Long> clusterIds) { public ItemDTO[] findItems(String appId, Apollo.Env env, String clusterName, String namespace) {
if (clusterIds == null || clusterIds.size() == 0) { if (StringUtils.isContainEmpty(appId, clusterName, namespace)) {
return null; return null;
} }
StringBuilder sb = new StringBuilder();
for (long clusterId : clusterIds) {
sb.append(clusterId).append(",");
}
return restTemplate.getForObject(getAdminServiceHost(env) + "/configs/latest?clusterIds=" return restTemplate.getForObject(getAdminServiceHost(env) + String
+ sb.substring(0, sb.length() - 1), ItemDTO[].class); .format("apps/%s/clusters/%s/namespaces/%s/items", appId,
clusterName, namespace),
ItemDTO[].class);
} }
} }
@Service @Service
public static class ClusterAPI extends API { public static class ClusterAPI extends API {
public static String CLUSTER_APP_API = "/cluster/app/"; public ClusterDTO[] findClustersByApp(String appId, Apollo.Env env) {
if (StringUtils.isContainEmpty(appId)) {
public ClusterDTO[] getClustersByApp(Apollo.Env env, String appId) {
if (Strings.isNullOrEmpty(appId)) {
return null; return null;
} }
return restTemplate.getForObject(getAdminServiceHost(env) + CLUSTER_APP_API + appId, return restTemplate.getForObject(getAdminServiceHost(env) + String.format("apps/%s/clusters", appId),
ClusterDTO[].class); ClusterDTO[].class);
}
}
@Service
public static class ReleaseAPI extends API{
public ReleaseDTO loadLatestRelease(String appId, Apollo.Env env, String clusterName, String namespace){
if (StringUtils.isContainEmpty(appId, clusterName, namespace)){
return null;
}
return restTemplate.getForObject(getAdminServiceHost(env) + String
.format("apps/%s/clusters/%s/namespaces/%s/releases/latest", appId,
clusterName, namespace), ReleaseDTO.class);
} }
} }
......
package com.ctrip.apollo.portal.controller;
import com.google.common.base.Strings;
import com.ctrip.apollo.portal.entity.ClusterNavTree;
import com.ctrip.apollo.portal.service.AppService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/apps")
public class AppController {
@Autowired
private AppService appService;
@RequestMapping("/{appId}/navtree")
public ClusterNavTree nav(@PathVariable String appId) {
if (Strings.isNullOrEmpty(appId)) {
throw new IllegalArgumentException("app id can not be empty.");
}
return appService.buildClusterNavTree(appId);
}
}
package com.ctrip.apollo.portal.controller; package com.ctrip.apollo.portal.controller;
import com.google.common.base.Strings;
import com.ctrip.apollo.Apollo; import com.ctrip.apollo.Apollo;
import com.ctrip.apollo.core.dto.AppConfigVO; import com.ctrip.apollo.core.utils.StringUtils;
import com.ctrip.apollo.portal.constants.PortalConstants; import com.ctrip.apollo.portal.entity.NamespaceVO;
import com.ctrip.apollo.portal.exception.NotFoundException;
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;
...@@ -13,35 +11,21 @@ import org.springframework.web.bind.annotation.PathVariable; ...@@ -13,35 +11,21 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController @RestController
@RequestMapping("/configs") @RequestMapping("")
public class ConfigController { public class ConfigController {
@Autowired @Autowired
private ConfigService configService; private ConfigService configService;
@RequestMapping("/{appId}/{env}/{versionId}") @RequestMapping("/apps/{appId}/env/{env}/clusters/{clusterName}/namespaces")
public AppConfigVO detail(@PathVariable String appId, @PathVariable String env, public List<NamespaceVO> findNamespaces(@PathVariable String appId, @PathVariable String env, @PathVariable String clusterName){
@PathVariable long versionId) { if (StringUtils.isContainEmpty(appId, env, clusterName)){
throw new IllegalArgumentException("app id and cluster name can not be empty");
if (Strings.isNullOrEmpty(appId) || Strings.isNullOrEmpty(env)) {
throw new IllegalArgumentException(
String.format("app id and env can not be empty. app id:%s , env:%s", appId, env));
} }
Apollo.Env e = Apollo.Env.valueOf(env); return configService.findNampspaces(appId, Apollo.Env.valueOf(env), clusterName);
if (versionId == PortalConstants.LASTEST_VERSION_ID) {
return configService.loadLatestConfig(e, appId);
// } else if (versionId > 0) {
//
// return configService.loadReleaseConfig(e, appId, versionId);
//
}
else {
throw new NotFoundException();
}
} }
} }
package com.ctrip.apollo.portal.controller;
import com.ctrip.apollo.Apollo;
import com.ctrip.apollo.portal.PortalSettings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/envs")
public class EnvController {
@Autowired
private PortalSettings portalSettings;
@RequestMapping("")
public List<Apollo.Env> envs(){
return portalSettings.getEnvs();
}
}
package com.ctrip.apollo.portal.entity;
import com.ctrip.apollo.Apollo;
import com.ctrip.apollo.core.dto.ClusterDTO;
import java.util.LinkedList;
import java.util.List;
public class ClusterNavTree {
private List<Node> nodes;
public void addNode(Node node){
if (nodes == null){
nodes = new LinkedList<>();
}
nodes.add(node);
}
public static class Node{
private Apollo.Env env;
private List<ClusterDTO> clusters;
public Node(Apollo.Env env){
this.env = env;
}
public Apollo.Env getEnv() {
return env;
}
public void setEnv(Apollo.Env env) {
this.env = env;
}
public List<ClusterDTO> getClusters() {
return clusters;
}
public void setClusters(List<ClusterDTO> clusters) {
this.clusters = clusters;
}
}
public List<Node> getNodes() {
return nodes;
}
public void setNodes(List<Node> nodes) {
this.nodes = nodes;
}
}
package com.ctrip.apollo.portal.entity;
import com.ctrip.apollo.core.dto.ItemDTO;
import com.ctrip.apollo.core.dto.NamespaceDTO;
import java.util.List;
public class NamespaceVO {
private NamespaceDTO namespace;
private int itemModifiedCnt;
private List<ItemVO> items;
public NamespaceDTO getNamespace() {
return namespace;
}
public void setNamespace(NamespaceDTO namespace) {
this.namespace = namespace;
}
public int getItemModifiedCnt() {
return itemModifiedCnt;
}
public void setItemModifiedCnt(int itemModifiedCnt) {
this.itemModifiedCnt = itemModifiedCnt;
}
public List<ItemVO> getItems() {
return items;
}
public void setItems(List<ItemVO> items) {
this.items = items;
}
public static class ItemVO{
private ItemDTO item;
private boolean isModified;
private String oldValue;
private String newValue;
public ItemDTO getItem() {
return item;
}
public void setItem(ItemDTO item) {
this.item = item;
}
public boolean isModified() {
return isModified;
}
public void setModified(boolean isModified) {
this.isModified = isModified;
}
public String getOldValue() {
return oldValue;
}
public void setOldValue(String oldValue) {
this.oldValue = oldValue;
}
public String getNewValue() {
return newValue;
}
public void setNewValue(String newValue) {
this.newValue = newValue;
}
}
}
package com.ctrip.apollo.portal.service;
import com.ctrip.apollo.Apollo;
import com.ctrip.apollo.portal.entity.ClusterNavTree;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class AppService {
@Autowired
private ClusterService clusterService;
public ClusterNavTree buildClusterNavTree(String appId){
ClusterNavTree tree = new ClusterNavTree();
ClusterNavTree.Node localNode = new ClusterNavTree.Node(Apollo.Env.LOCAL);
localNode.setClusters(clusterService.findClusters(Apollo.Env.LOCAL, appId));
tree.addNode(localNode);
// ClusterNavTree.Node uatNode = new ClusterNavTree.Node(Apollo.Env.UAT);
// List<ClusterDTO> uatClusters = new LinkedList<>();
// uatClusters.add(defaultCluster);
// uatNode.setClusters(uatClusters);
// tree.addNode(uatNode);
return tree;
}
}
package com.ctrip.apollo.portal.service;
import com.ctrip.apollo.Apollo;
import com.ctrip.apollo.core.dto.ClusterDTO;
import com.ctrip.apollo.portal.api.AdminServiceAPI;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.List;
@Service
public class ClusterService {
@Autowired
private AdminServiceAPI.ClusterAPI clusterAPI;
public List<ClusterDTO> findClusters(Apollo.Env env, String appId){
return Arrays.asList(clusterAPI.findClustersByApp(appId, env));
}
}
...@@ -3,27 +3,11 @@ var appService = angular.module('app.service', ['ngResource']); ...@@ -3,27 +3,11 @@ var appService = angular.module('app.service', ['ngResource']);
/** page module 定义*/ /** page module 定义*/
//项目主页 //项目主页
var application_module = angular.module('application', ['ngResource', 'ui.router', 'app.service', 'toastr', 'angular-loading-bar']); var application_module = angular.module('application', ['ngResource','ui.router', 'app.service', 'toastr', 'angular-loading-bar', 'ngTable']);
//创建项目页面 //创建项目页面
var create_app_module = angular.module('create_app', ['ngResource', 'toastr', 'app.service', 'angular-loading-bar']); var create_app_module = angular.module('create_app', ['ngResource', 'toastr', 'app.service', 'angular-loading-bar']);
/**router*/
application_module.config(['$stateProvider',
function ($stateProvider) {
$stateProvider
.state('config', {
templateUrl: '../../views/app/config.html',
controller: 'AppConfigController'
}).state('info', {
templateUrl: '../../views/app/info.html',
controller: 'AppInfoController'
}).state('setting', {
templateUrl: '../../views/app/setting.html'
});
}]).run(function ($state) {
$state.go('config');
});
......
appService.service('AppService', ['$resource', '$q', function ($resource, $q) { appService.service('AppService', ['$resource', '$q', function ($resource, $q) {
var app_resource = $resource('/apps/:appId', {}, { var app_resource = $resource('/apps/:appId', {}, {
load_navtree:{
methode: 'GET',
isArray:false,
url:'/apps/:appId/navtree'
},
load_app: { load_app: {
method: 'GET', method: 'GET',
isArray: false isArray: false
...@@ -10,6 +15,17 @@ appService.service('AppService', ['$resource', '$q', function ($resource, $q) { ...@@ -10,6 +15,17 @@ appService.service('AppService', ['$resource', '$q', function ($resource, $q) {
} }
}); });
return { return {
load_nav_tree: function loadNavTree(appId){
var d = $q.defer();
app_resource.load_navtree({
appId: appId
}, function(result){
d.resolve(result);
}, function(result){
d.reject(result);
});
return d.promise;
},
add: function add(app) { add: function add(app) {
var d = $q.defer(); var d = $q.defer();
app_resource.add_app({}, app, function (result) { app_resource.add_app({}, app, function (result) {
......
appService.service("ConfigService", ['$resource', '$q', function ($resource, $q) { appService.service("ConfigService", ['$resource', '$q', function ($resource, $q) {
var config_source = $resource("/configs/:appId/:env/:versionId", {}, { var config_source = $resource("", {}, {
load_config: { load_all_groups: {
method: 'GET', method:'GET',
isArray: false isArray: true,
url:'/apps/:appId/env/:env/clusters/:clusterName/namespaces'
} }
}); });
return { return {
load: function (appId, env, versionId) { load_all_namespaces: function (appId, env, clusterName) {
var d = $q.defer(); var d = $q.defer();
config_source.load_config({ config_source.load_all_groups({
appId: appId, appId: appId,
env: env, env: env,
versionId: versionId clusterName: clusterName
}, function (result) { }, function (result) {
d.resolve(result); d.resolve(result);
}, function (result) { }, function (result) {
de.reject(result); d.reject(result);
}); });
return d.promise; return d.promise;
} }
......
body { body {
color: #797979; color: #797979;
background: #f1f2f7; background: #fff;
padding: 0px !important; padding: 0px !important;
margin: 0px !important; margin: 0px !important;
font-size: 13px; font-size: 13px;
padding-bottom: 50px; min-height: 650px;
} }
a{ a{
cursor: pointer; cursor: pointer;
} }
.container {
width: 100%;
min-height: 550px;
}
.footer { .footer {
height: 50px; height: 100px;
width: 100%; width: 100%;
background: #F6F6F6; background: #F6F6F6;
padding-top: 10px; padding-top: 40px;
} }
/*panel*/ /*panel*/
.panel-heading { .panel-heading {
font-size: 16px; height: 45px;
font-size: 14px;
background-color: #f5f5f5; background-color: #f5f5f5;
padding: 5px 20px; padding: 5px 20px;
}
/*sec-panel*/
.sec-panel {
/*padding-left: 5%;*/
}
.sec-panel .panel-heading {
font-size: 14px;
height: 28px;
padding: 5px 20px;
} }
table th { table th {
...@@ -49,22 +35,93 @@ table th { ...@@ -49,22 +35,93 @@ table th {
background-color: #f5f5f5; background-color: #f5f5f5;
} }
.app .tab-content {
background-color: #ffffff;
}
#config-info { #config-info {
padding: 20px 0px; min-height: 500px;
background-color: #ffffff;
} }
#config-info .nav { #config-info .nav {
background-color: #f5f5f5; background-color: #f5f5f5;
} }
#config-info .config-info-container { #config-edit {
padding: 20px 20px; border: 1px solid #ddd;
border-radius: 3px;
}
#config-edit .panel-heading {
border-bottom: 1px solid #ddd;
}
.tocify-header {
font-size: 14px;
}
.tocify-subheader {
font-size: 13px;
}
.Hide {
display: none;
}
.config-item-container .config-items {
height: 500px;
overflow: scroll;
}
.historyview {
padding: 50px 20px;
}
.historyview .commit {
padding: 5px 15px;
border: 1px solid #ddd;
}
.historyview img {
position: absolute;
left: -28px;
}
.historyview .media .row {
padding-left: 35px;
}
.historyview .list {
position: relative;
border-left: 3px solid #ddd;
} }
#config-info nav { .line {
margin-top: -20px; width: 20px;
border: 1px solid #ddd;
} }
.editable-table > tbody > tr > td {
padding: 4px
}
.editable-text {
padding-left: 4px;
padding-top: 4px;
padding-bottom: 4px;
display: inline-block;
}
.editable-table tbody > tr > td > .controls {
/ / width: 100 %
}
.editable-input {
padding-left: 3px;
}
.editable-input.input-sm {
height: 30px;
font-size: 14px;
padding-top: 4px;
padding-bottom: 4px;
}
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -40,23 +40,23 @@ public class ConfigServiceTest { ...@@ -40,23 +40,23 @@ public class ConfigServiceTest {
private ServiceLocator serviceLocator; private ServiceLocator serviceLocator;
@Spy @Spy
private AdminServiceAPI.ClusterAPI clusterAPI; private AdminServiceAPI.ClusterAPI clusterAPI;
@Spy // @Spy
private AdminServiceAPI.ConfigAPI configAPI; // private AdminServiceAPI.ConfigAPI configAPI;
@Before @Before
public void setUp() throws ServiceException { public void setUp() throws ServiceException {
ReflectionTestUtils.setField(clusterAPI, "restTemplate", restTemplate); // ReflectionTestUtils.setField(clusterAPI, "restTemplate", restTemplate);
ReflectionTestUtils.setField(configAPI, "restTemplate", restTemplate); // ReflectionTestUtils.setField(configAPI, "restTemplate", restTemplate);
//
ReflectionTestUtils.setField(clusterAPI, "serviceLocator", serviceLocator); // ReflectionTestUtils.setField(clusterAPI, "serviceLocator", serviceLocator);
ReflectionTestUtils.setField(configAPI, "serviceLocator", serviceLocator); // ReflectionTestUtils.setField(configAPI, "serviceLocator", serviceLocator);
//
String defaultAdminService = "http://localhost:8090"; // String defaultAdminService = "http://localhost:8090";
ServiceDTO service = new ServiceDTO(); // ServiceDTO service = new ServiceDTO();
service.setHomepageUrl(defaultAdminService); // service.setHomepageUrl(defaultAdminService);
Mockito.doReturn(service).when(serviceLocator).getAdminService(Env.DEV); // Mockito.doReturn(service).when(serviceLocator).getAdminService(Env.DEV);
} }
// @Test // @Test
......
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