Ability to customize order of visualization package display

This commit is contained in:
Lee moon soo 2017-01-08 13:06:00 -08:00
parent cd7439618e
commit e18d9a4d81
8 changed files with 295 additions and 19 deletions

View file

@ -310,3 +310,69 @@ zeppelin-examples/zeppelin-example-clock/target/zeppelin-example-clock-0.7.0-SNA
</td>
</tr>
</table>
<br />
### Get visualization display order
<table class="table-configuration">
<col width="200">
<tr>
<td>Description</td>
<td>This ```GET``` method returns display order of enabled visualization packages.</td>
</tr>
<tr>
<td>URL</td>
<td>```http://[zeppelin-server]:[zeppelin-port]/api/helium/visualizationOrder```</td>
</tr>
<tr>
<td>Success code</td>
<td>200</td>
</tr>
<tr>
<td> Fail code</td>
<td> 500 </td>
</tr>
<tr>
<td>Sample JSON response</td>
<td>
<code>{"status":"OK","body":["zeppelin_horizontalbar","zeppelin-bubblechart"]}</code>
</td>
</tr>
</table>
<br />
### Set visualization display order
<table class="table-configuration">
<col width="200">
<tr>
<td>Description</td>
<td>This ```POST``` method set visualization packages display order.</td>
</tr>
<tr>
<td>URL</td>
<td>```http://[zeppelin-server]:[zeppelin-port]/api/helium/visualizationOrder```</td>
</tr>
<tr>
<td>Success code</td>
<td>200</td>
</tr>
<tr>
<td> Fail code</td>
<td> 500 </td>
</tr>
<tr>
<td>Sample JSON input</td>
<td>
<code>["zeppelin-bubblechart", "zeppelin_horizontalbar"]</code>
</td>
</tr>
<tr>
<td>Sample JSON response</td>
<td>
<code>{"status":"OK"}</code>
</td>
</tr>
</table>

View file

@ -19,6 +19,7 @@ package org.apache.zeppelin.rest;
import com.github.eirslett.maven.plugins.frontend.lib.TaskRunnerException;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.apache.commons.io.FileUtils;
import org.apache.zeppelin.helium.Helium;
import org.apache.zeppelin.helium.HeliumPackage;
@ -163,4 +164,26 @@ public class HeliumRestApi {
return new JsonResponse(Response.Status.INTERNAL_SERVER_ERROR, e.getMessage()).build();
}
}
@GET
@Path("visualizationOrder")
public Response getVisualizationPackageOrder() {
List<String> order = helium.getVisualizationPackageOrder();
return new JsonResponse(Response.Status.OK, order).build();
}
@POST
@Path("visualizationOrder")
public Response setVisualizationPackageOrder(String orderedPackageNameList) {
List<String> orderedList = gson.fromJson(
orderedPackageNameList, new TypeToken<List<String>>(){}.getType());
try {
helium.setVisualizationPackageOrder(orderedList);
} catch (IOException | TaskRunnerException e) {
logger.error(e.getMessage(), e);
return new JsonResponse(Response.Status.INTERNAL_SERVER_ERROR, e.getMessage()).build();
}
return new JsonResponse(Response.Status.OK).build();
}
}

View file

@ -16,12 +16,14 @@
angular.module('zeppelinWebApp').controller('HeliumCtrl', HeliumCtrl);
HeliumCtrl.$inject = ['$scope', '$rootScope', '$http', '$sce', 'baseUrlSrv', 'ngToast'];
HeliumCtrl.$inject = ['$scope', '$rootScope', '$sce', 'baseUrlSrv', 'ngToast', 'heliumService'];
function HeliumCtrl($scope, $rootScope, $http, $sce, baseUrlSrv, ngToast) {
function HeliumCtrl($scope, $rootScope, $sce, baseUrlSrv, ngToast, heliumService) {
$scope.packageInfos = {};
$scope.defaultVersions = {};
$scope.showVersions = {};
$scope.visualizationOrder = [];
$scope.visualizationOrderChanged = false;
var buildDefaultVersionListToDisplay = function(packageInfos) {
var defaultVersions = {};
@ -48,7 +50,7 @@
};
var getAllPackageInfo = function() {
$http.get(baseUrlSrv.getRestApiBase() + '/helium/all').
heliumService.getAllPackageInfo().
success(function(data, status) {
$scope.packageInfos = data.body;
buildDefaultVersionListToDisplay($scope.packageInfos);
@ -58,12 +60,63 @@
});
};
var getVisualizationOrder = function() {
heliumService.getVisualizationOrder().
success(function(data, status) {
$scope.visualizationOrder = data.body;
}).
error(function(data, status) {
console.log('Can not get visualization order %o %o', status, data);
});
};
$scope.visualizationOrderListeners = {
accept: function(sourceItemHandleScope, destSortableScope) {return true;},
itemMoved: function(event) {},
orderChanged: function(event) {
$scope.visualizationOrderChanged = true;
}
};
var init = function() {
getAllPackageInfo();
getVisualizationOrder();
$scope.visualizationOrderChanged = false;
};
init();
$scope.saveVisualizationOrder = function() {
var confirm = BootstrapDialog.confirm({
closable: false,
closeByBackdrop: false,
closeByKeyboard: false,
title: '',
message: 'Save changes?',
callback: function(result) {
if (result) {
confirm.$modalFooter.find('button').addClass('disabled');
confirm.$modalFooter.find('button:contains("OK")')
.html('<i class="fa fa-circle-o-notch fa-spin"></i> Enabling');
heliumService.setVisualizationOrder($scope.visualizationOrder).
success(function(data, status) {
init();
confirm.close();
}).
error(function(data, status) {
confirm.close();
console.log('Failed to save order');
BootstrapDialog.show({
title: 'Error on saving order ',
message: data.message
});
});
return false;
}
}
});
}
$scope.enable = function(name, artifact) {
var confirm = BootstrapDialog.confirm({
closable: false,
@ -76,9 +129,9 @@
confirm.$modalFooter.find('button').addClass('disabled');
confirm.$modalFooter.find('button:contains("OK")')
.html('<i class="fa fa-circle-o-notch fa-spin"></i> Enabling');
$http.post(baseUrlSrv.getRestApiBase() + '/helium/enable/' + name, artifact).
heliumService.enable(name, artifact).
success(function(data, status) {
getAllPackageInfo();
init();
confirm.close();
}).
error(function(data, status) {
@ -107,9 +160,9 @@
confirm.$modalFooter.find('button').addClass('disabled');
confirm.$modalFooter.find('button:contains("OK")')
.html('<i class="fa fa-circle-o-notch fa-spin"></i> Disabling');
$http.post(baseUrlSrv.getRestApiBase() + '/helium/disable/' + name).
heliumService.disable(name).
success(function(data, status) {
getAllPackageInfo();
init();
confirm.close();
}).
error(function(data, status) {

View file

@ -37,6 +37,12 @@
float: left;
}
.heliumPackageList .heliumPackageName span {
font-size: 10px;
color: #AAAAAA;
}
.heliumPackageList .heliumPackageDisabledArtifact {
color:gray;
}
@ -45,9 +51,50 @@
color:#444444;
}
.heliumPackageList .heliumPackageVersions {
.heliumPackageList .heliumPackageEnabledArtifact span,
.heliumPackageList .heliumPackageDisabledArtifact span {
margin-left:3px;
cursor:pointer;
text-decoration:
underline;color:#3071a9
}
.heliumPackageList .heliumPackageDescription {
margin-top: 10px;
}
}
.heliumVisualizationOrder {
display: inline-block;
}
.heliumVisualizationOrder .as-sortable-item,
.heliumVisualizationOrder .as-sortable-placeholder {
display: inline-block;
float: left;
}
.heliumVisualizationOrder .as-sortable-item-handle {
width: 35px;
height: 30px;
}
.heliumVisualizationOrder .sortable-row:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
.heliumVisualizationOrder .as-sortable-item svg {
width: 100%;
height: 100%;
}
.heliumVisualizationOrder .saveLink {
margin-left:10px;
margin-top:5px;
cursor:pointer;
text-decoration:
underline;color:#3071a9
}

View file

@ -20,6 +20,26 @@ limitations under the License.
</h3>
</div>
</div>
<div ng-show="visualizationOrder.length > 1"
class="row heliumVisualizationOrder">
<div class="col-md-12 sortable-row btn-group"
as-sortable="visualizationOrderListeners"
data-ng-model="visualizationOrder">
<div style="margin-bottom:5px">Visualization package display order (drag and drop to reorder)</div>
<div class="btn-group" data-ng-repeat="pkgName in visualizationOrder"
as-sortable-item>
<div class="btn btn-default btn-sm"
ng-bind-html='defaultVersions[pkgName].pkg.icon'
as-sortable-item-handle>
</div>
</div>
<a class="saveLink"
ng-show="visualizationOrderChanged"
ng-click="saveVisualizationOrder()">
save
</a>
</div>
</div>
</div>
</div>
@ -30,7 +50,7 @@ limitations under the License.
<div class="heliumPackageHead">
<div class="heliumPackageIcon"
ng-bind-html=pkgInfo.pkg.icon></div>
<div class="heliumPackageName">{{pkgName}}</div>
<div class="heliumPackageName">{{pkgName}} <span>{{pkgInfo.pkg.type}}</span></div>
<div ng-show="!pkgInfo.enabled"
ng-click="enable(pkgName, pkgInfo.pkg.artifact)"
class="btn btn-success btn-xs"
@ -43,8 +63,7 @@ limitations under the License.
<div ng-class="{heliumPackageDisabledArtifact: !pkgInfo.enabled, heliumPackageEnabledArtifact: pkgInfo.enabled}">
{{pkgInfo.pkg.artifact}}
<span ng-show="packageInfos[pkgName].length > 0"
ng-click="toggleVersions(pkgName)"
style="margin-left:3px;cursor:pointer;text-decoration: underline;color:#3071a9">
ng-click="toggleVersions(pkgName)">
Versions
</span>
</div>

View file

@ -38,5 +38,25 @@
this.get = function() {
return visualizations;
};
this.getVisualizationOrder = function() {
return $http.get(baseUrlSrv.getRestApiBase() + '/helium/visualizationOrder');
};
this.setVisualizationOrder = function(list) {
return $http.post(baseUrlSrv.getRestApiBase() + '/helium/visualizationOrder', list);
};
this.getAllPackageInfo = function() {
return $http.get(baseUrlSrv.getRestApiBase() + '/helium/all');
};
this.enable = function(name, artifact) {
return $http.post(baseUrlSrv.getRestApiBase() + '/helium/enable/' + name, artifact);
};
this.disable = function(name) {
return $http.post(baseUrlSrv.getRestApiBase() + '/helium/disable/' + name);
};
};
})();

View file

@ -119,6 +119,7 @@ public class Helium {
public synchronized void save() throws IOException {
String jsonString;
synchronized (registry) {
clearNotExistsPackages();
heliumConf.setRegistry(registry);
jsonString = gson.toJson(heliumConf);
}
@ -131,6 +132,28 @@ public class Helium {
FileUtils.writeStringToFile(heliumConfFile, jsonString);
}
private void clearNotExistsPackages() {
Map<String, List<HeliumPackageSearchResult>> all = getAllPackageInfo();
// clear visualization display order
List<String> packageOrder = heliumConf.getVisualizationDisplayOrder();
List<String> clearedOrder = new LinkedList<>();
for (String pkgName : packageOrder) {
if (all.containsKey(pkgName)) {
clearedOrder.add(pkgName);
}
}
heliumConf.setVisualizationDisplayOrder(clearedOrder);
// clear enabled package
Map<String, String> enabledPackages = heliumConf.getEnabledPackages();
for (String pkgName : enabledPackages.keySet()) {
if (!all.containsKey(pkgName)) {
heliumConf.disablePackage(pkgName);
}
}
}
public Map<String, List<HeliumPackageSearchResult>> getAllPackageInfo() {
Map<String, String> enabledPackageInfo = heliumConf.getEnabledPackages();
@ -301,4 +324,29 @@ public class Helium {
return orderedVisualizationPackages;
}
/**
* Get enabled package list in order
* @return
*/
public List<String> getVisualizationPackageOrder() {
List orderedPackageList = new LinkedList<>();
List<HeliumPackage> packages = getVisualizationPackagesToBundle();
for (HeliumPackage pkg : packages) {
orderedPackageList.add(pkg.getName());
}
return orderedPackageList;
}
public void setVisualizationPackageOrder(List<String> orderedPackageList)
throws IOException, TaskRunnerException {
heliumConf.setVisualizationDisplayOrder(orderedPackageList);
// if package is visualization, rebuild bundle
visualizationFactory.bundle(getVisualizationPackagesToBundle());
save();
}
}

View file

@ -60,14 +60,14 @@ public class HeliumConf {
}
public List<String> getVisualizationDisplayOrder() {
return visualizationDisplayOrder;
if (visualizationDisplayOrder == null) {
return new LinkedList<String>();
} else {
return visualizationDisplayOrder;
}
}
public void setVisualizationDisplayOrder(List<HeliumPackage> orderedPackageList) {
List<String> order = new LinkedList<>();
for (HeliumPackage pkg : orderedPackageList) {
order.add(pkg.getName());
}
visualizationDisplayOrder = order;
public void setVisualizationDisplayOrder(List<String> orderedPackageList) {
visualizationDisplayOrder = orderedPackageList;
}
}