Commit dcc68fb9 authored by 张乐's avatar 张乐 Committed by GitHub

Merge pull request #2321 from nobodyiam/search-app

search app from backend instead of loading all app and filter in frontend
parents 6aa339cc b4e0a622
package com.ctrip.framework.apollo.portal.controller; package com.ctrip.framework.apollo.portal.controller;
import com.ctrip.framework.apollo.common.dto.PageDTO;
import com.ctrip.framework.apollo.common.entity.App; import com.ctrip.framework.apollo.common.entity.App;
import com.ctrip.framework.apollo.common.exception.BadRequestException; import com.ctrip.framework.apollo.common.exception.BadRequestException;
import com.ctrip.framework.apollo.common.http.MultiResponseEntity; import com.ctrip.framework.apollo.common.http.MultiResponseEntity;
...@@ -77,7 +78,16 @@ public class AppController { ...@@ -77,7 +78,16 @@ public class AppController {
} else { } else {
return appService.findByAppIds(Sets.newHashSet(appIds.split(","))); return appService.findByAppIds(Sets.newHashSet(appIds.split(",")));
} }
}
@GetMapping("/search")
public PageDTO<App> searchByAppIdOrAppName(@RequestParam(value = "query", required = false) String query,
Pageable pageable) {
if (StringUtils.isEmpty(query)) {
return appService.findAll(pageable);
} else {
return appService.searchByAppIdOrAppName(query, pageable);
}
} }
@GetMapping("/by-owner") @GetMapping("/by-owner")
......
...@@ -2,6 +2,7 @@ package com.ctrip.framework.apollo.portal.repository; ...@@ -2,6 +2,7 @@ package com.ctrip.framework.apollo.portal.repository;
import com.ctrip.framework.apollo.common.entity.App; import com.ctrip.framework.apollo.common.entity.App;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;
...@@ -21,6 +22,8 @@ public interface AppRepository extends PagingAndSortingRepository<App, Long> { ...@@ -21,6 +22,8 @@ public interface AppRepository extends PagingAndSortingRepository<App, Long> {
List<App> findByAppIdIn(Set<String> appIds, Pageable pageable); List<App> findByAppIdIn(Set<String> appIds, Pageable pageable);
Page<App> findByAppIdContainingOrNameContaining(String appId, String name, Pageable pageable);
@Modifying @Modifying
@Query("UPDATE App SET IsDeleted=1,DataChange_LastModifiedBy = ?2 WHERE AppId=?1") @Query("UPDATE App SET IsDeleted=1,DataChange_LastModifiedBy = ?2 WHERE AppId=?1")
int deleteApp(String appId, String operator); int deleteApp(String appId, String operator);
......
package com.ctrip.framework.apollo.portal.service; package com.ctrip.framework.apollo.portal.service;
import com.ctrip.framework.apollo.common.dto.AppDTO; import com.ctrip.framework.apollo.common.dto.AppDTO;
import com.ctrip.framework.apollo.common.dto.PageDTO;
import com.ctrip.framework.apollo.common.entity.App; import com.ctrip.framework.apollo.common.entity.App;
import com.ctrip.framework.apollo.common.exception.BadRequestException; import com.ctrip.framework.apollo.common.exception.BadRequestException;
import com.ctrip.framework.apollo.common.utils.BeanUtils; import com.ctrip.framework.apollo.common.utils.BeanUtils;
...@@ -14,6 +15,7 @@ import com.ctrip.framework.apollo.portal.spi.UserInfoHolder; ...@@ -14,6 +15,7 @@ import com.ctrip.framework.apollo.portal.spi.UserInfoHolder;
import com.ctrip.framework.apollo.portal.spi.UserService; import com.ctrip.framework.apollo.portal.spi.UserService;
import com.ctrip.framework.apollo.tracer.Tracer; import com.ctrip.framework.apollo.tracer.Tracer;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
...@@ -65,6 +67,18 @@ public class AppService { ...@@ -65,6 +67,18 @@ public class AppService {
return Lists.newArrayList((apps)); return Lists.newArrayList((apps));
} }
public PageDTO<App> findAll(Pageable pageable) {
Page<App> apps = appRepository.findAll(pageable);
return new PageDTO<>(apps.getContent(), pageable, apps.getTotalElements());
}
public PageDTO<App> searchByAppIdOrAppName(String query, Pageable pageable) {
Page<App> apps = appRepository.findByAppIdContainingOrNameContaining(query, query, pageable);
return new PageDTO<>(apps.getContent(), pageable, apps.getTotalElements());
}
public List<App> findByAppIds(Set<String> appIds) { public List<App> findByAppIds(Set<String> appIds) {
return appRepository.findByAppIdIn(appIds); return appRepository.findByAppIdIn(appIds);
} }
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
<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">
<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">
<title>比较配置</title> <title>比较配置</title>
<style> <style>
.comment-toggle { .comment-toggle {
...@@ -122,6 +123,7 @@ ...@@ -122,6 +123,7 @@
<!-- 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>
<!--angular--> <!--angular-->
<script src="../vendor/angular/angular.min.js"></script> <script src="../vendor/angular/angular.min.js"></script>
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
<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">
<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">
<title>发布历史</title> <title>发布历史</title>
</head> </head>
...@@ -246,6 +247,7 @@ ...@@ -246,6 +247,7 @@
<!-- 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>
<!--angular--> <!--angular-->
<script src="../vendor/angular/angular.min.js"></script> <script src="../vendor/angular/angular.min.js"></script>
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
<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">
<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">
<title>同步配置</title> <title>同步配置</title>
</head> </head>
...@@ -213,6 +214,7 @@ ...@@ -213,6 +214,7 @@
<!-- 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>
<!--angular--> <!--angular-->
<script src="../vendor/angular/angular.min.js"></script> <script src="../vendor/angular/angular.min.js"></script>
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
<!-- styles --> <!-- styles -->
<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">
<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" media='all' href="vendor/font-awesome.min.css"> <link rel="stylesheet" type="text/css" media='all' href="vendor/font-awesome.min.css">
...@@ -115,6 +116,7 @@ ...@@ -115,6 +116,7 @@
<!-- 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>
<!-- 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>
......
...@@ -13,105 +13,64 @@ directive_module.directive('apollonav', ...@@ -13,105 +13,64 @@ directive_module.directive('apollonav',
scope.pageSetting = setting; scope.pageSetting = setting;
}); });
scope.sourceApps = []; $('#app-search-list').select2({
scope.copiedApps = []; placeholder: '搜索项目(AppId、项目名)',
ajax: {
AppService.find_apps().then(function (result) { url: "/apps/search",
result.forEach(function (app) { dataType: 'json',
app.selected = false; delay: 400,
scope.sourceApps.push(app); data: function (params) {
}); return {
scope.copiedApps = angular.copy(scope.sourceApps); query: params.term || '',
}, function (result) { page: params.page ? params.page - 1 : 0,
toastr.error(AppUtil.errorMsg(result), "load apps error"); size: 20
});
scope.searchKey = '';
scope.shouldShowAppList = false;
var selectedApp = {};
scope.selectApp = function (app) {
select(app);
scope.jumpToConfigPage();
}; };
},
scope.changeSearchKey = function () { processResults: function (data) {
scope.copiedApps = []; if (data && data.content) {
var searchKey = scope.searchKey.toLocaleLowerCase(); var hasMore = data.content.length
scope.sourceApps.forEach(function (app) { === data.size;
if (app.name.toLocaleLowerCase().indexOf(searchKey) > -1 var result = [];
|| app.appId.toLocaleLowerCase().indexOf(searchKey) > -1) { data.content.forEach(function (app) {
scope.copiedApps.push(app); result.push({
} id: app.appId,
text: app.appId + ' / ' + app.name
})
}); });
scope.shouldShowAppList = true; return {
results: result,
pagination: {
more: hasMore
}
}; };
scope.jumpToConfigPage = function () {
if (selectedApp.appId) {
if ($window.location.href.indexOf("config.html") > -1) {
$window.location.hash = "appid=" + selectedApp.appId;
$window.location.reload();
} else { } else {
$window.location.href = '/config.html?#appid=' + selectedApp.appId; return {
} results: [],
pagination: {
more: false
} }
}; };
//up:38 down:40 enter:13
var selectedAppIdx = -1;
element.bind("keydown keypress", function (event) {
if (event.keyCode == 40) {
if (selectedAppIdx < scope.copiedApps.length - 1) {
clearAppsSelectedStatus();
scope.copiedApps[++selectedAppIdx].selected = true;
}
} else if (event.keyCode == 38) {
if (selectedAppIdx >= 1) {
clearAppsSelectedStatus();
scope.copiedApps[--selectedAppIdx].selected = true;
}
} else if (event.keyCode == 13) {
if (scope.shouldShowAppList && selectedAppIdx > -1) {
select(scope.copiedApps[selectedAppIdx]);
event.preventDefault();
} else {
scope.jumpToConfigPage();
} }
} }
//强制刷新 }
scope.$apply(function () {
scope.copiedApps = scope.copiedApps;
});
});
$(".search-input").on("click", function (event) {
event.stopPropagation();
});
$(document).on('click', function () {
scope.$apply(function () {
scope.shouldShowAppList = false;
});
}); });
function clearAppsSelectedStatus() { $('#app-search-list').on('select2:select', function () {
scope.copiedApps.forEach(function (app) { var selected = $('#app-search-list').select2('data');
app.selected = false; if (selected && selected.length) {
}) jumpToConfigPage(selected[0].id)
} }
});
function select(app) { function jumpToConfigPage(selectedAppId) {
selectedApp = app; if ($window.location.href.indexOf("config.html") > -1) {
scope.searchKey = app.name; $window.location.hash = "appid=" + selectedAppId;
scope.shouldShowAppList = false; $window.location.reload();
clearAppsSelectedStatus(); } else {
selectedAppIdx = -1; $window.location.href = '/config.html?#appid=' + selectedAppId;
} }
};
UserService.load_user().then(function (result) { UserService.load_user().then(function (result) {
scope.userName = result.userId; scope.userName = result.userId;
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
<!-- styles --> <!-- styles -->
<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">
<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>应用配置</title>
...@@ -81,6 +82,7 @@ ...@@ -81,6 +82,7 @@
<!-- 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>
<!-- 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>
......
...@@ -805,3 +805,11 @@ table th { ...@@ -805,3 +805,11 @@ table th {
padding-left: 30px; padding-left: 30px;
} }
.app-search-list .select2-container, .app-search-list .select2-container .select2-selection {
height: 34px;
}
.app-search-list .select2-container .select2-selection .select2-selection__rendered {
line-height: 34px;
font-size: 14px;
}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -49,19 +49,10 @@ ...@@ -49,19 +49,10 @@
</ul> </ul>
<div class="navbar-form navbar-right form-inline" role="search"> <div class="navbar-form navbar-right form-inline" role="search">
<div class="form-group"> <div class="form-group app-search-list">
<input type="text" class="form-control search-input" placeholder="搜索项目(AppId、项目名)" <select id="app-search-list" style="width: 350px"></select>
style="width: 350px"
ng-model="searchKey" ng-change="changeSearchKey()" ng-focus="changeSearchKey()">
<div class="row app-list" ng-show="shouldShowAppList">
<div ng-repeat="app in copiedApps" class="app-item" ng-class="{'app-selected':app.selected}"
ng-click="selectApp(app)">{{app.appId}} / {{app.name}}
</div>
</div> </div>
</div> </div>
</div> </div>
</div>
</div> </div>
</nav> </nav>
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